From 7127b17406698e77d009aca21398ad5f661e4fab Mon Sep 17 00:00:00 2001 From: blablalf Date: Tue, 14 Nov 2023 11:14:55 +0100 Subject: [PATCH] V0 --- .github/workflows/smartContractTest.yml | 41 + .gitignore | 25 + .gitmodules | 24 + README.md | 125 + audits/Bailsec_final_report.pdf | Bin 0 -> 565057 bytes audits/Salus_final_report.pdf | Bin 0 -> 1265032 bytes .../DeployZapper.s.sol/1/run-1699554225.json | 238 + .../DeployZapper.s.sol/1/run-1699554508.json | 204 + .../DeployZapper.s.sol/1/run-1699554522.json | 616 + .../DeployZapper.s.sol/1/run-latest.json | 616 + .../5/run-1696517528.json | 38 + .../5/run-1696517534.json | 69 + .../5/run-1696517628.json | 38 + .../5/run-1696517662.json | 109 + .../5/run-1696517669.json | 276 + .../5/run-1696517944.json | 132 + .../5/run-1696517958.json | 330 + .../5/run-1696517987.json | 330 + .../5/run-1696518085.json | 132 + .../5/run-1696518099.json | 330 + .../5/run-1696518128.json | 330 + .../5/run-1696518454.json | 132 + .../5/run-1696518486.json | 330 + .../5/run-1696518515.json | 330 + .../5/run-1696518532.json | 132 + .../5/run-1696518545.json | 330 + .../5/run-1696518546.json | 330 + .../5/run-1696519178.json | 132 + .../5/run-1696519191.json | 330 + .../5/run-1696519236.json | 132 + .../5/run-1696519261.json | 330 + .../5/run-1696519262.json | 330 + .../5/run-1696604696.json | 132 + .../5/run-1696604718.json | 330 + .../5/run-1696605676.json | 132 + .../5/run-1696605690.json | 330 + .../5/run-1696610570.json | 120 + .../5/run-1696610582.json | 318 + .../5/run-1696612484.json | 132 + .../5/run-1696612514.json | 330 + .../5/run-1696612747.json | 132 + .../5/run-1696612753.json | 330 + .../5/run-1696612935.json | 132 + .../5/run-1696612948.json | 330 + .../5/run-1696613263.json | 120 + .../5/run-1696613269.json | 318 + .../5/run-1696614074.json | 120 + .../5/run-1696614087.json | 318 + .../5/run-1696614621.json | 132 + .../5/run-1696614633.json | 330 + .../5/run-1696614670.json | 330 + .../5/run-1696845420.json | 132 + .../5/run-1696845427.json | 330 + .../5/run-1696845459.json | 330 + .../5/run-latest.json | 330 + .../1/run-1696689350.json | 132 + .../1/run-1696689363.json | 315 + .../1/run-latest.json | 315 + .../1/run-1699551295.json | 131 + .../1/run-latest.json | 131 + config.yaml | 64 + example.env | 79 + foundry.toml | 43 + .../.github/ISSUE_TEMPLATE/bug_report.yaml | 54 + .../ISSUE_TEMPLATE/feature_request.yaml | 18 + lib/crytic/.github/workflows/examples.yaml | 115 + lib/crytic/.gitignore | 43 + lib/crytic/.gitmodules | 20 + lib/crytic/.solhint.json | 10 + lib/crytic/CODEOWNERS | 7 + lib/crytic/CONTRIBUTING.md | 69 + lib/crytic/LICENSE | 661 + lib/crytic/PROPERTIES.md | 221 + lib/crytic/README.md | 427 + lib/crytic/Trophies.md | 10 + .../external/ERC20ExternalPropertyTests.sol | 19 + .../contracts/ERC20/external/ExampleToken.sol | 61 + .../contracts/ERC20/external/TokenMock.sol | 20 + .../ERC20/external/echidna.config.yaml | 7 + .../ERC20ExternalBasicProperties.sol | 193 + .../ERC20ExternalBurnableProperties.sol | 54 + ...C20ExternalIncreaseAllowanceProperties.sol | 36 + .../ERC20ExternalMintableProperties.sol | 23 + .../ERC20ExternalPausableProperties.sol | 54 + .../external/util/ERC20ExternalTestBase.sol | 14 + .../ERC20/external/util/ITokenMock.sol | 18 + .../ERC20/internal/echidna.config.yaml | 6 + .../properties/ERC20BasicProperties.sol | 194 + .../properties/ERC20BurnableProperties.sol | 55 + .../ERC20IncreaseAllowanceProperties.sol | 37 + .../properties/ERC20MintableProperties.sol | 26 + .../properties/ERC20PausableProperties.sol | 68 + .../ERC20/internal/util/ERC20TestBase.sol | 18 + .../ERC4626/ERC4626PropertyTests.sol | 21 + lib/crytic/contracts/ERC4626/README.md | 163 + .../properties/FunctionalAccountingProps.sol | 111 + .../ERC4626/properties/MustNotRevertProps.sol | 109 + .../properties/RedeemUsingApprovalProps.sol | 86 + .../ERC4626/properties/RoundingProps.sol | 102 + .../ERC4626/properties/SecurityProps.sol | 54 + .../properties/SenderIndependentProps.sol | 77 + .../ERC4626/properties/VaultProxy.sol | 57 + .../contracts/ERC4626/test/Solmate4626.sol | 34 + .../ERC4626/test/echidna.config.yaml | 7 + .../rounding/BadConvertToAssetsRounding.sol | 59 + .../rounding/BadConvertToSharesRounding.sol | 58 + .../test/rounding/BadPreviewMintRounding.sol | 58 + .../rounding/BadPreviewWithdrawRounding.sol | 57 + .../test/security/BadShareInflation.sol | 32 + .../test/usingApproval/BadAllowanceUpdate.sol | 85 + lib/crytic/contracts/ERC4626/util/Actor.sol | 81 + .../ERC4626/util/ERC4626PropertyTestBase.sol | 155 + .../ERC4626/util/IERC4626Internal.sol | 10 + .../ERC4626/util/RedemptionProxy.sol | 19 + .../contracts/ERC4626/util/TestERC20Token.sol | 76 + .../ABDKMath64x64PropertyTests.sol | 1829 + .../contracts/Math/ABDKMath64x64/README.md | 38 + .../abdk-libraries-solidity/ABDKMath64x64.md | 172 + .../abdk-libraries-solidity/ABDKMath64x64.sol | 750 + .../abdk-libraries-solidity/ABDKMathQuad.md | 196 + .../abdk-libraries-solidity/ABDKMathQuad.sol | 1215 + .../abdk-libraries-solidity/LICENSE.md | 28 + .../abdk-libraries-solidity/README.md | 22 + lib/crytic/contracts/util/Hevm.sol | 30 + lib/crytic/contracts/util/IERC20.sol | 78 + lib/crytic/contracts/util/IERC4626.sol | 56 + .../contracts/util/PropertiesConstants.sol | 9 + .../contracts/util/PropertiesHelper.sol | 373 + lib/crytic/foundry.toml | 6 + lib/crytic/hardhat.config.js | 45 + lib/crytic/lib/ERC4626/.gitattributes | 1 + .../lib/ERC4626/.github/workflows/test.yaml | 12 + lib/crytic/lib/ERC4626/.gitignore | 132 + lib/crytic/lib/ERC4626/README.md | 3 + lib/crytic/lib/ERC4626/ape-config.yaml | 18 + lib/crytic/lib/ERC4626/contracts/ERC4626.json | 249 + lib/crytic/lib/ERC4626/contracts/ERC4626.sol | 20 + .../lib/ERC4626/contracts/SolidityVault.sol | 158 + .../lib/ERC4626/contracts/VyperVault.vy | 258 + .../lib/ERC4626/contracts/test/Token.vy | 70 + lib/crytic/lib/ERC4626/requirements.txt | 3 + .../lib/ERC4626/scripts/make_interfaces.py | 70 + .../lib/forge-std/.github/workflows/ci.yml | 92 + lib/crytic/lib/forge-std/.gitignore | 4 + lib/crytic/lib/forge-std/.gitmodules | 3 + lib/crytic/lib/forge-std/LICENSE-APACHE | 203 + lib/crytic/lib/forge-std/LICENSE-MIT | 25 + lib/crytic/lib/forge-std/README.md | 250 + lib/crytic/lib/forge-std/foundry.toml | 21 + .../lib/forge-std/lib/ds-test/.gitignore | 3 + lib/crytic/lib/forge-std/lib/ds-test/LICENSE | 674 + lib/crytic/lib/forge-std/lib/ds-test/Makefile | 14 + .../lib/forge-std/lib/ds-test/default.nix | 4 + .../lib/forge-std/lib/ds-test/demo/demo.sol | 222 + .../lib/forge-std/lib/ds-test/package.json | 15 + .../lib/forge-std/lib/ds-test/src/test.sol | 469 + lib/crytic/lib/forge-std/package.json | 16 + lib/crytic/lib/forge-std/src/Base.sol | 33 + lib/crytic/lib/forge-std/src/Script.sol | 26 + .../lib/forge-std/src/StdAssertions.sol | 325 + lib/crytic/lib/forge-std/src/StdChains.sol | 233 + lib/crytic/lib/forge-std/src/StdCheats.sol | 572 + lib/crytic/lib/forge-std/src/StdError.sol | 15 + lib/crytic/lib/forge-std/src/StdInvariant.sol | 92 + lib/crytic/lib/forge-std/src/StdJson.sol | 179 + lib/crytic/lib/forge-std/src/StdMath.sol | 43 + lib/crytic/lib/forge-std/src/StdStorage.sol | 327 + lib/crytic/lib/forge-std/src/StdUtils.sol | 189 + lib/crytic/lib/forge-std/src/Test.sol | 31 + lib/crytic/lib/forge-std/src/Vm.sol | 405 + lib/crytic/lib/forge-std/src/console.sol | 1533 + lib/crytic/lib/forge-std/src/console2.sol | 1546 + .../lib/forge-std/src/interfaces/IERC1155.sol | 105 + .../lib/forge-std/src/interfaces/IERC165.sol | 12 + .../lib/forge-std/src/interfaces/IERC20.sol | 43 + .../lib/forge-std/src/interfaces/IERC4626.sol | 190 + .../lib/forge-std/src/interfaces/IERC721.sol | 164 + .../forge-std/src/interfaces/IMulticall3.sol | 73 + .../lib/forge-std/test/StdAssertions.t.sol | 823 + lib/crytic/lib/forge-std/test/StdChains.t.sol | 160 + lib/crytic/lib/forge-std/test/StdCheats.t.sol | 329 + lib/crytic/lib/forge-std/test/StdError.t.sol | 118 + lib/crytic/lib/forge-std/test/StdMath.t.sol | 197 + .../lib/forge-std/test/StdStorage.t.sol | 283 + lib/crytic/lib/forge-std/test/StdUtils.t.sol | 297 + .../test/compilation/CompilationScript.sol | 10 + .../compilation/CompilationScriptBase.sol | 10 + .../test/compilation/CompilationTest.sol | 10 + .../test/compilation/CompilationTestBase.sol | 10 + .../.changeset/beige-buses-drop.md | 5 + .../.changeset/config.json | 12 + .../.changeset/curvy-shrimps-enjoy.md | 5 + .../.changeset/curvy-suns-sort.md | 5 + .../.changeset/early-oranges-raise.md | 5 + .../.changeset/famous-rules-burn.md | 5 + .../.changeset/five-ducks-develop.md | 5 + .../.changeset/five-poets-mix.md | 5 + .../.changeset/flat-deers-end.md | 5 + .../.changeset/four-bats-sniff.md | 5 + .../.changeset/funny-rockets-compete.md | 5 + .../.changeset/gold-chicken-clean.md | 5 + .../.changeset/happy-socks-travel.md | 5 + .../.changeset/healthy-squids-stare.md | 5 + .../.changeset/lemon-dogs-kiss.md | 5 + .../.changeset/little-kiwis-ring.md | 5 + .../.changeset/lovely-dragons-appear.md | 5 + .../.changeset/many-panthers-hide.md | 5 + .../.changeset/modern-games-exist.md | 5 + .../.changeset/new-ways-own.md | 5 + .../.changeset/ninety-hornets-kick.md | 5 + .../.changeset/perfect-insects-listen.md | 5 + .../.changeset/pretty-hornets-play.md | 5 + .../.changeset/proud-comics-deliver.md | 5 + .../.changeset/short-roses-judge.md | 5 + .../.changeset/slimy-knives-hug.md | 5 + .../.changeset/small-cars-appear.md | 5 + .../.changeset/strong-bulldogs-buy.md | 5 + .../.changeset/tame-ladybugs-sit.md | 5 + .../.changeset/thin-dragons-report.md | 5 + .../.changeset/thirty-swans-exercise.md | 5 + .../.changeset/violet-frogs-hide.md | 5 + .../.changeset/yellow-swans-cover.md | 5 + .../lib/openzeppelin-contracts/.codecov.yml | 12 + .../lib/openzeppelin-contracts/.editorconfig | 21 + .../lib/openzeppelin-contracts/.eslintrc | 20 + .../.github/ISSUE_TEMPLATE/bug_report.md | 21 + .../.github/ISSUE_TEMPLATE/config.yml | 4 + .../.github/ISSUE_TEMPLATE/feature_request.md | 14 + .../.github/PULL_REQUEST_TEMPLATE.md | 20 + .../.github/actions/gas-compare/action.yml | 49 + .../.github/actions/setup/action.yml | 19 + .../.github/actions/storage-layout/action.yml | 55 + .../.github/workflows/actionlint.yml | 18 + .../.github/workflows/changeset.yml | 28 + .../.github/workflows/checks.yml | 96 + .../.github/workflows/docs.yml | 19 + .../.github/workflows/release-cycle.yml | 214 + .../.github/workflows/upgradeable.yml | 23 + .../lib/openzeppelin-contracts/.gitignore | 70 + .../lib/openzeppelin-contracts/.gitmodules | 6 + .../lib/openzeppelin-contracts/.mocharc.js | 4 + .../lib/openzeppelin-contracts/.prettierrc | 14 + .../lib/openzeppelin-contracts/.solcover.js | 13 + .../lib/openzeppelin-contracts/.solhint.json | 14 + .../lib/openzeppelin-contracts/CHANGELOG.md | 663 + .../openzeppelin-contracts/CODE_OF_CONDUCT.md | 73 + .../openzeppelin-contracts/CONTRIBUTING.md | 36 + .../lib/openzeppelin-contracts/GUIDELINES.md | 117 + lib/crytic/lib/openzeppelin-contracts/LICENSE | 22 + .../lib/openzeppelin-contracts/README.md | 90 + .../lib/openzeppelin-contracts/RELEASING.md | 47 + .../lib/openzeppelin-contracts/SECURITY.md | 42 + .../openzeppelin-contracts/audits/2017-03.md | 292 + .../openzeppelin-contracts/audits/2018-10.pdf | Bin 0 -> 1000527 bytes .../audits/2022-10-Checkpoints.pdf | Bin 0 -> 155606 bytes .../audits/2022-10-ERC4626.pdf | Bin 0 -> 204184 bytes .../openzeppelin-contracts/audits/README.md | 15 + .../openzeppelin-contracts/certora/Makefile | 24 + .../openzeppelin-contracts/certora/README.md | 56 + .../certora/applyHarness.patch | 101 + .../certora/harnesses/ERC20VotesHarness.sol | 28 + .../harnesses/WizardControlFirstPriority.sol | 150 + .../certora/harnesses/WizardFirstTry.sol | 141 + .../certora/munged/.gitignore | 2 + .../certora/reports/2021-10.pdf | Bin 0 -> 92882 bytes .../certora/reports/2022-03.pdf | Bin 0 -> 199401 bytes .../certora/reports/2022-05.pdf | Bin 0 -> 132223 bytes .../certora/scripts/Governor.sh | 10 + .../GovernorCountingSimple-counting.sh | 10 + .../scripts/WizardControlFirstPriority.sh | 12 + .../certora/scripts/WizardFirstTry.sh | 10 + .../certora/scripts/sanity.sh | 14 + .../certora/scripts/verifyAll.sh | 39 + .../certora/specs/GovernorBase.spec | 333 + .../certora/specs/GovernorCountingSimple.spec | 221 + .../certora/specs/RulesInProgress.spec | 139 + .../certora/specs/sanity.spec | 14 + .../contracts/access/AccessControl.sol | 247 + .../access/AccessControlCrossChain.sol | 45 + .../access/AccessControlEnumerable.sol | 64 + .../contracts/access/IAccessControl.sol | 88 + .../access/IAccessControlEnumerable.sol | 31 + .../contracts/access/Ownable.sol | 83 + .../contracts/access/Ownable2Step.sol | 57 + .../contracts/access/README.adoc | 25 + .../crosschain/CrossChainEnabled.sol | 54 + .../contracts/crosschain/README.adoc | 34 + .../crosschain/amb/CrossChainEnabledAMB.sol | 49 + .../contracts/crosschain/amb/LibAMB.sol | 35 + .../arbitrum/CrossChainEnabledArbitrumL1.sol | 44 + .../arbitrum/CrossChainEnabledArbitrumL2.sol | 40 + .../crosschain/arbitrum/LibArbitrumL1.sol | 42 + .../crosschain/arbitrum/LibArbitrumL2.sol | 45 + .../contracts/crosschain/errors.sol | 7 + .../optimism/CrossChainEnabledOptimism.sol | 41 + .../crosschain/optimism/LibOptimism.sol | 36 + .../polygon/CrossChainEnabledPolygonChild.sol | 72 + .../contracts/finance/PaymentSplitter.sol | 214 + .../contracts/finance/README.adoc | 20 + .../contracts/finance/VestingWallet.sol | 145 + .../contracts/governance/Governor.sol | 627 + .../contracts/governance/IGovernor.sol | 307 + .../contracts/governance/README.adoc | 176 + .../governance/TimelockController.sol | 423 + .../GovernorCompatibilityBravo.sol | 328 + .../IGovernorCompatibilityBravo.sol | 113 + .../extensions/GovernorCountingSimple.sol | 100 + .../extensions/GovernorPreventLateQuorum.sol | 107 + .../extensions/GovernorProposalThreshold.sol | 23 + .../extensions/GovernorSettings.sol | 110 + .../extensions/GovernorTimelockCompound.sol | 192 + .../extensions/GovernorTimelockControl.sol | 166 + .../governance/extensions/GovernorVotes.sol | 55 + .../extensions/GovernorVotesComp.sol | 55 + .../GovernorVotesQuorumFraction.sol | 122 + .../extensions/IGovernorTimelock.sol | 26 + .../contracts/governance/utils/IVotes.sol | 56 + .../contracts/governance/utils/Votes.sol | 244 + .../contracts/interfaces/IERC1155.sol | 6 + .../interfaces/IERC1155MetadataURI.sol | 6 + .../contracts/interfaces/IERC1155Receiver.sol | 6 + .../contracts/interfaces/IERC1271.sol | 19 + .../contracts/interfaces/IERC1363.sol | 78 + .../contracts/interfaces/IERC1363Receiver.sol | 32 + .../contracts/interfaces/IERC1363Spender.sol | 26 + .../contracts/interfaces/IERC165.sol | 6 + .../interfaces/IERC1820Implementer.sol | 6 + .../contracts/interfaces/IERC1820Registry.sol | 6 + .../contracts/interfaces/IERC20.sol | 6 + .../contracts/interfaces/IERC20Metadata.sol | 6 + .../contracts/interfaces/IERC2309.sol | 21 + .../contracts/interfaces/IERC2612.sol | 8 + .../contracts/interfaces/IERC2981.sol | 25 + .../contracts/interfaces/IERC3156.sol | 7 + .../interfaces/IERC3156FlashBorrower.sol | 29 + .../interfaces/IERC3156FlashLender.sol | 43 + .../contracts/interfaces/IERC4626.sol | 232 + .../contracts/interfaces/IERC4906.sol | 19 + .../contracts/interfaces/IERC5267.sol | 27 + .../contracts/interfaces/IERC5313.sol | 17 + .../contracts/interfaces/IERC5805.sol | 9 + .../contracts/interfaces/IERC6372.sol | 17 + .../contracts/interfaces/IERC721.sol | 6 + .../interfaces/IERC721Enumerable.sol | 6 + .../contracts/interfaces/IERC721Metadata.sol | 6 + .../contracts/interfaces/IERC721Receiver.sol | 6 + .../contracts/interfaces/IERC777.sol | 6 + .../contracts/interfaces/IERC777Recipient.sol | 6 + .../contracts/interfaces/IERC777Sender.sol | 6 + .../contracts/interfaces/README.adoc | 56 + .../contracts/interfaces/draft-IERC1822.sol | 20 + .../contracts/interfaces/draft-IERC2612.sol | 7 + .../contracts/metatx/ERC2771Context.sol | 43 + .../contracts/metatx/MinimalForwarder.sol | 72 + .../contracts/metatx/README.adoc | 12 + .../mocks/AccessControlCrossChainMock.sol | 8 + .../contracts/mocks/ArraysMock.sol | 51 + .../contracts/mocks/CallReceiverMock.sol | 57 + .../contracts/mocks/ConditionalEscrowMock.sol | 18 + .../contracts/mocks/ContextMock.sol | 29 + .../contracts/mocks/DummyImplementation.sol | 57 + .../contracts/mocks/EIP712Verifier.sol | 16 + .../contracts/mocks/ERC1271WalletMock.sol | 26 + .../mocks/ERC165/ERC165MaliciousData.sol | 12 + .../mocks/ERC165/ERC165MissingData.sol | 7 + .../mocks/ERC165/ERC165NotSupported.sol | 5 + .../mocks/ERC165/ERC165ReturnBomb.sol | 18 + .../contracts/mocks/ERC20Mock.sol | 16 + .../contracts/mocks/ERC2771ContextMock.sol | 22 + .../mocks/ERC3156FlashBorrowerMock.sol | 53 + .../contracts/mocks/ERC4626Mock.sol | 16 + .../contracts/mocks/EtherReceiverMock.sol | 17 + .../contracts/mocks/InitializableMock.sol | 130 + .../contracts/mocks/MulticallTest.sol | 23 + .../MultipleInheritanceInitializableMocks.sol | 131 + .../contracts/mocks/PausableMock.sol | 31 + .../contracts/mocks/PullPaymentMock.sol | 15 + .../contracts/mocks/ReentrancyAttack.sol | 12 + .../contracts/mocks/ReentrancyMock.sol | 51 + .../mocks/RegressionImplementation.sol | 61 + .../contracts/mocks/SafeMathMemoryCheck.sol | 72 + .../SingleInheritanceInitializableMocks.sol | 49 + .../contracts/mocks/StorageSlotMock.sol | 77 + .../contracts/mocks/TimersBlockNumberImpl.sol | 39 + .../contracts/mocks/TimersTimestampImpl.sol | 39 + .../contracts/mocks/VotesMock.sol | 45 + .../contracts/mocks/compound/CompTimelock.sol | 174 + .../contracts/mocks/crosschain/bridges.sol | 94 + .../contracts/mocks/crosschain/receivers.sol | 54 + .../mocks/governance/GovernorCompMock.sol | 20 + .../GovernorCompatibilityBravoMock.sol | 100 + .../mocks/governance/GovernorMock.sol | 28 + .../GovernorPreventLateQuorumMock.sol | 45 + .../GovernorTimelockCompoundMock.sol | 60 + .../GovernorTimelockControlMock.sol | 60 + .../mocks/governance/GovernorVoteMock.sol | 20 + .../governance/GovernorWithParamsMock.sol | 50 + .../contracts/mocks/proxy/BadBeacon.sol | 11 + .../mocks/proxy/ClashingImplementation.sol | 17 + .../contracts/mocks/proxy/UUPSLegacy.sol | 54 + .../mocks/proxy/UUPSUpgradeableMock.sol | 33 + .../mocks/token/ERC1155ReceiverMock.sol | 47 + .../mocks/token/ERC20DecimalsMock.sol | 17 + .../mocks/token/ERC20FlashMintMock.sol | 26 + .../mocks/token/ERC20MulticallMock.sol | 8 + .../mocks/token/ERC20NoReturnMock.sol | 21 + .../mocks/token/ERC20PermitNoRevertMock.sol | 38 + .../mocks/token/ERC20ReturnFalseMock.sol | 27 + .../mocks/token/ERC20ReturnTrueMock.sol | 27 + .../mocks/token/ERC20VotesLegacyMock.sol | 262 + .../mocks/token/ERC4626OffsetMock.sol | 17 + .../token/ERC721ConsecutiveEnumerableMock.sol | 51 + .../mocks/token/ERC721ConsecutiveMock.sol | 61 + .../mocks/token/ERC721ReceiverMock.sol | 42 + .../mocks/token/ERC721URIStorageMock.sol | 17 + .../contracts/mocks/token/ERC777Mock.sol | 13 + .../mocks/token/ERC777SenderRecipientMock.sol | 152 + .../contracts/mocks/token/VotesTimestamp.sol | 40 + .../contracts/mocks/wizard/MyGovernor1.sol | 79 + .../contracts/mocks/wizard/MyGovernor2.sol | 85 + .../contracts/mocks/wizard/MyGovernor3.sol | 94 + .../contracts/package.json | 32 + .../contracts/proxy/Clones.sol | 88 + .../contracts/proxy/ERC1967/ERC1967Proxy.sol | 32 + .../proxy/ERC1967/ERC1967Upgrade.sol | 171 + .../contracts/proxy/Proxy.sol | 86 + .../contracts/proxy/README.adoc | 85 + .../contracts/proxy/beacon/BeaconProxy.sol | 61 + .../contracts/proxy/beacon/IBeacon.sol | 16 + .../proxy/beacon/UpgradeableBeacon.sol | 65 + .../proxy/transparent/ProxyAdmin.sol | 81 + .../TransparentUpgradeableProxy.sol | 132 + .../contracts/proxy/utils/Initializable.sol | 166 + .../contracts/proxy/utils/UUPSUpgradeable.sol | 99 + .../contracts/security/Pausable.sol | 105 + .../contracts/security/PullPayment.sol | 74 + .../contracts/security/README.adoc | 20 + .../contracts/security/ReentrancyGuard.sol | 77 + .../contracts/token/ERC1155/ERC1155.sol | 497 + .../contracts/token/ERC1155/IERC1155.sol | 119 + .../token/ERC1155/IERC1155Receiver.sol | 58 + .../contracts/token/ERC1155/README.adoc | 49 + .../ERC1155/extensions/ERC1155Burnable.sol | 32 + .../ERC1155/extensions/ERC1155Pausable.sol | 44 + .../ERC1155/extensions/ERC1155Supply.sol | 64 + .../ERC1155/extensions/ERC1155URIStorage.sol | 63 + .../extensions/IERC1155MetadataURI.sol | 22 + .../presets/ERC1155PresetMinterPauser.sol | 114 + .../contracts/token/ERC1155/presets/README.md | 1 + .../token/ERC1155/utils/ERC1155Holder.sol | 36 + .../token/ERC1155/utils/ERC1155Receiver.sol | 19 + .../contracts/token/ERC20/ERC20.sol | 365 + .../contracts/token/ERC20/IERC20.sol | 78 + .../contracts/token/ERC20/README.adoc | 78 + .../token/ERC20/extensions/ERC20Burnable.sol | 39 + .../token/ERC20/extensions/ERC20Capped.sol | 37 + .../token/ERC20/extensions/ERC20FlashMint.sol | 109 + .../token/ERC20/extensions/ERC20Pausable.sol | 35 + .../token/ERC20/extensions/ERC20Permit.sol | 95 + .../token/ERC20/extensions/ERC20Snapshot.sol | 191 + .../token/ERC20/extensions/ERC20Votes.sol | 290 + .../token/ERC20/extensions/ERC20VotesComp.sol | 46 + .../token/ERC20/extensions/ERC20Wrapper.sol | 70 + .../token/ERC20/extensions/ERC4626.sol | 256 + .../token/ERC20/extensions/IERC20Metadata.sol | 28 + .../token/ERC20/extensions/IERC20Permit.sol | 60 + .../ERC20/extensions/draft-ERC20Permit.sol | 8 + .../ERC20/extensions/draft-IERC20Permit.sol | 7 + .../ERC20/presets/ERC20PresetFixedSupply.sol | 30 + .../ERC20/presets/ERC20PresetMinterPauser.sol | 94 + .../contracts/token/ERC20/presets/README.md | 1 + .../contracts/token/ERC20/utils/SafeERC20.sol | 95 + .../token/ERC20/utils/TokenTimelock.sol | 72 + .../contracts/token/ERC721/ERC721.sol | 468 + .../contracts/token/ERC721/IERC721.sol | 132 + .../token/ERC721/IERC721Receiver.sol | 27 + .../contracts/token/ERC721/README.adoc | 73 + .../ERC721/extensions/ERC721Burnable.sol | 26 + .../ERC721/extensions/ERC721Consecutive.sol | 143 + .../ERC721/extensions/ERC721Enumerable.sol | 159 + .../ERC721/extensions/ERC721Pausable.sol | 40 + .../token/ERC721/extensions/ERC721Royalty.sol | 38 + .../ERC721/extensions/ERC721URIStorage.sol | 74 + .../token/ERC721/extensions/ERC721Votes.sol | 41 + .../token/ERC721/extensions/ERC721Wrapper.sol | 96 + .../ERC721/extensions/IERC721Enumerable.sol | 29 + .../ERC721/extensions/IERC721Metadata.sol | 27 + .../ERC721/extensions/draft-ERC721Votes.sol | 9 + .../ERC721PresetMinterPauserAutoId.sol | 132 + .../contracts/token/ERC721/presets/README.md | 1 + .../token/ERC721/utils/ERC721Holder.sol | 23 + .../contracts/token/ERC777/ERC777.sol | 512 + .../contracts/token/ERC777/IERC777.sol | 200 + .../token/ERC777/IERC777Recipient.sol | 35 + .../contracts/token/ERC777/IERC777Sender.sol | 35 + .../contracts/token/ERC777/README.adoc | 30 + .../presets/ERC777PresetFixedSupply.sol | 30 + .../contracts/token/common/ERC2981.sol | 107 + .../contracts/token/common/README.adoc | 10 + .../contracts/utils/Address.sol | 244 + .../contracts/utils/Arrays.sol | 105 + .../contracts/utils/Base64.sol | 92 + .../contracts/utils/Checkpoints.sol | 560 + .../contracts/utils/Context.sol | 24 + .../contracts/utils/Counters.sol | 43 + .../contracts/utils/Create2.sol | 75 + .../contracts/utils/Multicall.sol | 25 + .../contracts/utils/README.adoc | 113 + .../contracts/utils/ShortStrings.sol | 94 + .../contracts/utils/StorageSlot.sol | 138 + .../contracts/utils/Strings.sol | 85 + .../contracts/utils/Timers.sol | 75 + .../contracts/utils/cryptography/ECDSA.sol | 217 + .../contracts/utils/cryptography/EIP712.sol | 143 + .../utils/cryptography/MerkleProof.sol | 223 + .../utils/cryptography/SignatureChecker.sol | 50 + .../utils/cryptography/draft-EIP712.sol | 8 + .../utils/escrow/ConditionalEscrow.sol | 25 + .../contracts/utils/escrow/Escrow.sol | 67 + .../contracts/utils/escrow/RefundEscrow.sol | 100 + .../contracts/utils/introspection/ERC165.sol | 29 + .../utils/introspection/ERC165Checker.sol | 126 + .../utils/introspection/ERC165Storage.sol | 42 + .../introspection/ERC1820Implementer.sol | 41 + .../contracts/utils/introspection/IERC165.sol | 25 + .../introspection/IERC1820Implementer.sol | 20 + .../utils/introspection/IERC1820Registry.sol | 112 + .../contracts/utils/math/Math.sol | 336 + .../contracts/utils/math/SafeCast.sol | 1136 + .../contracts/utils/math/SafeMath.sol | 215 + .../contracts/utils/math/SignedMath.sol | 43 + .../contracts/utils/math/SignedSafeMath.sol | 68 + .../contracts/utils/structs/BitMaps.sol | 51 + .../utils/structs/DoubleEndedQueue.sol | 170 + .../contracts/utils/structs/EnumerableMap.sol | 598 + .../contracts/utils/structs/EnumerableSet.sol | 378 + .../contracts/vendor/amb/IAMB.sol | 41 + .../contracts/vendor/arbitrum/IArbSys.sol | 134 + .../contracts/vendor/arbitrum/IBridge.sol | 102 + .../arbitrum/IDelayedMessageProvider.sol | 16 + .../contracts/vendor/arbitrum/IInbox.sol | 152 + .../contracts/vendor/arbitrum/IOutbox.sol | 117 + .../vendor/compound/ICompoundTimelock.sol | 86 + .../contracts/vendor/compound/LICENSE | 11 + .../vendor/optimism/ICrossDomainMessenger.sol | 34 + .../contracts/vendor/optimism/LICENSE | 22 + .../vendor/polygon/IFxMessageProcessor.sol | 7 + .../lib/openzeppelin-contracts/foundry.toml | 3 + .../openzeppelin-contracts/hardhat.config.js | 114 + .../hardhat/env-contract.js | 10 + .../hardhat/ignore-unreachable-warnings.js | 45 + .../hardhat/skip-foundry-tests.js | 6 + .../lib/erc4626-tests/ERC4626.prop.sol | 404 + .../lib/erc4626-tests/ERC4626.test.sol | 349 + .../lib/erc4626-tests/LICENSE | 661 + .../lib/erc4626-tests/README.md | 116 + .../lib/forge-std/.github/workflows/ci.yml | 92 + .../lib/forge-std/.gitignore | 4 + .../lib/forge-std/.gitmodules | 3 + .../lib/forge-std/LICENSE-APACHE | 203 + .../lib/forge-std/LICENSE-MIT | 25 + .../lib/forge-std/README.md | 250 + .../lib/forge-std/foundry.toml | 21 + .../lib/forge-std/lib/ds-test/.gitignore | 3 + .../lib/forge-std/lib/ds-test/LICENSE | 674 + .../lib/forge-std/lib/ds-test/Makefile | 14 + .../lib/forge-std/lib/ds-test/default.nix | 4 + .../lib/forge-std/lib/ds-test/demo/demo.sol | 222 + .../lib/forge-std/lib/ds-test/package.json | 15 + .../lib/forge-std/lib/ds-test/src/test.sol | 469 + .../lib/forge-std/package.json | 16 + .../lib/forge-std/src/Base.sol | 31 + .../lib/forge-std/src/Script.sol | 26 + .../lib/forge-std/src/StdAssertions.sol | 209 + .../lib/forge-std/src/StdChains.sol | 189 + .../lib/forge-std/src/StdCheats.sol | 565 + .../lib/forge-std/src/StdError.sol | 15 + .../lib/forge-std/src/StdJson.sol | 179 + .../lib/forge-std/src/StdMath.sol | 43 + .../lib/forge-std/src/StdStorage.sol | 327 + .../lib/forge-std/src/StdUtils.sol | 123 + .../lib/forge-std/src/Test.sol | 28 + .../lib/forge-std/src/Vm.sol | 385 + .../lib/forge-std/src/console.sol | 1533 + .../lib/forge-std/src/console2.sol | 1546 + .../lib/forge-std/src/interfaces/IERC1155.sol | 105 + .../lib/forge-std/src/interfaces/IERC165.sol | 12 + .../lib/forge-std/src/interfaces/IERC20.sol | 43 + .../lib/forge-std/src/interfaces/IERC4626.sol | 190 + .../lib/forge-std/src/interfaces/IERC721.sol | 164 + .../lib/forge-std/test/StdAssertions.t.sol | 587 + .../lib/forge-std/test/StdChains.t.sol | 123 + .../lib/forge-std/test/StdCheats.t.sol | 305 + .../lib/forge-std/test/StdError.t.sol | 118 + .../lib/forge-std/test/StdMath.t.sol | 197 + .../lib/forge-std/test/StdStorage.t.sol | 283 + .../lib/forge-std/test/StdUtils.t.sol | 191 + .../test/compilation/CompilationScript.sol | 10 + .../compilation/CompilationScriptBase.sol | 10 + .../test/compilation/CompilationTest.sol | 10 + .../test/compilation/CompilationTestBase.sol | 10 + .../lib/openzeppelin-contracts/logo.svg | 15 + .../lib/openzeppelin-contracts/netlify.toml | 3 + .../openzeppelin-contracts/package-lock.json | 29066 ++++++++++++++++ .../lib/openzeppelin-contracts/package.json | 94 + .../lib/openzeppelin-contracts/renovate.json | 4 + .../scripts/checks/compare-layout.js | 19 + .../scripts/checks/compareGasReports.js | 243 + .../scripts/checks/extract-layout.js | 40 + .../scripts/checks/generation.sh | 6 + .../scripts/checks/inheritance-ordering.js | 54 + .../openzeppelin-contracts/scripts/gen-nav.js | 41 + .../scripts/generate/format-lines.js | 16 + .../scripts/generate/run.js | 37 + .../scripts/generate/templates/Checkpoints.js | 325 + .../generate/templates/EnumerableMap.js | 310 + .../generate/templates/EnumerableSet.js | 250 + .../scripts/generate/templates/SafeCast.js | 163 + .../scripts/generate/templates/StorageSlot.js | 87 + .../scripts/generate/templates/conversion.js | 30 + .../scripts/git-user-config.sh | 6 + .../openzeppelin-contracts/scripts/helpers.js | 37 + .../scripts/migrate-imports.js | 180 + .../openzeppelin-contracts/scripts/prepack.sh | 12 + .../scripts/prepare-contracts-package.sh | 15 + .../scripts/prepare-docs.sh | 15 + .../openzeppelin-contracts/scripts/prepare.sh | 10 + .../scripts/release/format-changelog.js | 33 + .../scripts/release/synchronize-versions.js | 15 + .../scripts/release/update-comment.js | 34 + .../scripts/release/version.sh | 11 + .../release/workflow/exit-prerelease.sh | 8 + .../release/workflow/github-release.js | 47 + .../release/workflow/integrity-check.sh | 20 + .../scripts/release/workflow/pack.sh | 26 + .../release/workflow/prepare-release-merge.sh | 24 + .../scripts/release/workflow/publish.sh | 20 + .../scripts/release/workflow/rerun.js | 7 + .../workflow/set-changesets-pr-title.js | 17 + .../scripts/release/workflow/start.sh | 35 + .../scripts/release/workflow/state.js | 104 + .../scripts/remove-ignored-artifacts.js | 45 + .../scripts/update-docs-branch.js | 63 + .../slither.config.json | 5 + .../openzeppelin-contracts/test/TESTING.md | 3 + .../test/access/AccessControl.behavior.js | 217 + .../test/access/AccessControl.test.js | 12 + .../access/AccessControlCrossChain.test.js | 49 + .../access/AccessControlEnumerable.test.js | 17 + .../test/access/Ownable.test.js | 51 + .../test/access/Ownable2Step.test.js | 57 + .../test/crosschain/CrossChainEnabled.test.js | 78 + .../test/finance/PaymentSplitter.test.js | 217 + .../test/finance/VestingWallet.behavior.js | 59 + .../test/finance/VestingWallet.test.js | 67 + .../test/governance/Governor.test.js | 699 + .../governance/TimelockController.test.js | 1099 + .../GovernorCompatibilityBravo.test.js | 268 + .../extensions/GovernorComp.test.js | 88 + .../extensions/GovernorERC721.test.js | 115 + .../GovernorPreventLateQuorum.test.js | 189 + .../GovernorTimelockCompound.test.js | 352 + .../GovernorTimelockControl.test.js | 445 + .../GovernorVotesQuorumFraction.test.js | 154 + .../extensions/GovernorWithParams.test.js | 173 + .../test/governance/utils/EIP6372.behavior.js | 23 + .../test/governance/utils/Votes.behavior.js | 361 + .../test/governance/utils/Votes.test.js | 71 + .../test/helpers/chainid.js | 10 + .../test/helpers/create2.js | 11 + .../test/helpers/crosschain.js | 61 + .../test/helpers/customError.js | 24 + .../test/helpers/eip712.js | 67 + .../test/helpers/enums.js | 12 + .../test/helpers/erc1967.js | 24 + .../test/helpers/governance.js | 201 + .../test/helpers/map-values.js | 7 + .../test/helpers/sign.js | 63 + .../test/helpers/time.js | 17 + .../test/helpers/txpool.js | 38 + .../test/metatx/ERC2771Context.test.js | 101 + .../test/metatx/MinimalForwarder.test.js | 169 + .../test/migrate-imports.test.js | 32 + .../test/proxy/Clones.behaviour.js | 136 + .../test/proxy/Clones.test.js | 61 + .../test/proxy/ERC1967/ERC1967Proxy.test.js | 13 + .../test/proxy/Proxy.behaviour.js | 225 + .../test/proxy/beacon/BeaconProxy.test.js | 139 + .../proxy/beacon/UpgradeableBeacon.test.js | 44 + .../test/proxy/transparent/ProxyAdmin.test.js | 125 + .../TransparentUpgradeableProxy.behaviour.js | 435 + .../TransparentUpgradeableProxy.test.js | 15 + .../test/proxy/utils/Initializable.test.js | 218 + .../test/proxy/utils/UUPSUpgradeable.test.js | 85 + .../test/security/Pausable.test.js | 85 + .../test/security/PullPayment.test.js | 51 + .../test/security/ReentrancyGuard.test.js | 43 + .../test/token/ERC1155/ERC1155.behavior.js | 767 + .../test/token/ERC1155/ERC1155.test.js | 235 + .../extensions/ERC1155Burnable.test.js | 67 + .../extensions/ERC1155Pausable.test.js | 108 + .../ERC1155/extensions/ERC1155Supply.test.js | 107 + .../extensions/ERC1155URIStorage.test.js | 66 + .../presets/ERC1155PresetMinterPauser.test.js | 156 + .../token/ERC1155/utils/ERC1155Holder.test.js | 64 + .../test/token/ERC20/ERC20.behavior.js | 322 + .../test/token/ERC20/ERC20.test.js | 305 + .../extensions/ERC20Burnable.behavior.js | 106 + .../ERC20/extensions/ERC20Burnable.test.js | 20 + .../ERC20/extensions/ERC20Capped.behavior.js | 32 + .../ERC20/extensions/ERC20Capped.test.js | 23 + .../ERC20/extensions/ERC20FlashMint.test.js | 204 + .../ERC20/extensions/ERC20Pausable.test.js | 133 + .../ERC20/extensions/ERC20Snapshot.test.js | 207 + .../token/ERC20/extensions/ERC20Votes.test.js | 578 + .../ERC20/extensions/ERC20VotesComp.test.js | 543 + .../ERC20/extensions/ERC20Wrapper.test.js | 190 + .../test/token/ERC20/extensions/ERC4626.t.sol | 18 + .../token/ERC20/extensions/ERC4626.test.js | 610 + .../extensions/draft-ERC20Permit.test.js | 103 + .../presets/ERC20PresetFixedSupply.test.js | 42 + .../presets/ERC20PresetMinterPauser.test.js | 110 + .../test/token/ERC20/utils/SafeERC20.test.js | 264 + .../token/ERC20/utils/TokenTimelock.test.js | 71 + .../test/token/ERC721/ERC721.behavior.js | 893 + .../test/token/ERC721/ERC721.test.js | 15 + .../token/ERC721/ERC721Enumerable.test.js | 20 + .../ERC721/extensions/ERC721Burnable.test.js | 70 + .../extensions/ERC721Consecutive.test.js | 205 + .../ERC721/extensions/ERC721Pausable.test.js | 92 + .../ERC721/extensions/ERC721Royalty.test.js | 41 + .../extensions/ERC721URIStorage.test.js | 100 + .../ERC721/extensions/ERC721Votes.test.js | 184 + .../ERC721/extensions/ERC721Wrapper.test.js | 283 + .../ERC721PresetMinterPauserAutoId.test.js | 122 + .../token/ERC721/utils/ERC721Holder.test.js | 22 + .../test/token/ERC777/ERC777.behavior.js | 597 + .../test/token/ERC777/ERC777.test.js | 556 + .../presets/ERC777PresetFixedSupply.test.js | 49 + .../test/token/common/ERC2981.behavior.js | 157 + .../test/utils/Address.test.js | 321 + .../test/utils/Arrays.test.js | 123 + .../test/utils/Base64.test.js | 33 + .../test/utils/Checkpoints.test.js | 228 + .../test/utils/Context.behavior.js | 42 + .../test/utils/Context.test.js | 17 + .../test/utils/Counters.test.js | 84 + .../test/utils/Create2.test.js | 89 + .../test/utils/Multicall.test.js | 68 + .../test/utils/ShortStrings.test.js | 44 + .../test/utils/StorageSlot.test.js | 210 + .../test/utils/Strings.test.js | 150 + .../test/utils/TimersBlockNumberImpl.test.js | 55 + .../test/utils/TimersTimestamp.test.js | 55 + .../test/utils/cryptography/ECDSA.test.js | 260 + .../test/utils/cryptography/EIP712.test.js | 70 + .../utils/cryptography/MerkleProof.test.js | 180 + .../cryptography/SignatureChecker.test.js | 87 + .../utils/escrow/ConditionalEscrow.test.js | 37 + .../test/utils/escrow/Escrow.behavior.js | 90 + .../test/utils/escrow/Escrow.test.js | 14 + .../test/utils/escrow/RefundEscrow.test.js | 143 + .../test/utils/introspection/ERC165.test.js | 11 + .../utils/introspection/ERC165Checker.test.js | 302 + .../utils/introspection/ERC165Storage.test.js | 23 + .../introspection/ERC1820Implementer.test.js | 71 + .../SupportsInterface.behavior.js | 130 + .../test/utils/math/Math.t.sol | 217 + .../test/utils/math/Math.test.js | 289 + .../test/utils/math/SafeCast.test.js | 152 + .../test/utils/math/SafeMath.test.js | 433 + .../test/utils/math/SignedMath.test.js | 95 + .../test/utils/math/SignedSafeMath.test.js | 152 + .../test/utils/structs/BitMap.test.js | 145 + .../utils/structs/DoubleEndedQueue.test.js | 99 + .../utils/structs/EnumerableMap.behavior.js | 185 + .../test/utils/structs/EnumerableMap.test.js | 151 + .../utils/structs/EnumerableSet.behavior.js | 129 + .../test/utils/structs/EnumerableSet.test.js | 76 + lib/crytic/lib/solmate/.gas-snapshot | 459 + lib/crytic/lib/solmate/.gitattributes | 1 + .../solmate/.github/pull_request_template.md | 13 + .../lib/solmate/.github/workflows/tests.yml | 29 + lib/crytic/lib/solmate/.gitignore | 3 + lib/crytic/lib/solmate/.gitmodules | 3 + lib/crytic/lib/solmate/.prettierignore | 1 + lib/crytic/lib/solmate/.prettierrc | 14 + lib/crytic/lib/solmate/LICENSE | 661 + lib/crytic/lib/solmate/README.md | 69 + .../audits/v6-Fixed-Point-Solutions.pdf | Bin 0 -> 170456 bytes lib/crytic/lib/solmate/foundry.toml | 7 + lib/crytic/lib/solmate/lib/ds-test/.gitignore | 3 + lib/crytic/lib/solmate/lib/ds-test/LICENSE | 674 + lib/crytic/lib/solmate/lib/ds-test/Makefile | 14 + .../lib/solmate/lib/ds-test/default.nix | 4 + .../lib/solmate/lib/ds-test/demo/demo.sol | 222 + .../lib/solmate/lib/ds-test/package.json | 15 + .../lib/solmate/lib/ds-test/src/test.sol | 469 + lib/crytic/lib/solmate/package-lock.json | 125 + lib/crytic/lib/solmate/package.json | 20 + lib/crytic/lib/solmate/src/auth/Auth.sol | 64 + lib/crytic/lib/solmate/src/auth/Owned.sol | 44 + .../auth/authorities/MultiRolesAuthority.sol | 123 + .../src/auth/authorities/RolesAuthority.sol | 108 + lib/crytic/lib/solmate/src/mixins/ERC4626.sol | 183 + lib/crytic/lib/solmate/src/test/Auth.t.sol | 192 + .../solmate/src/test/Bytes32AddressLib.t.sol | 22 + lib/crytic/lib/solmate/src/test/CREATE3.t.sol | 74 + .../lib/solmate/src/test/DSTestPlus.t.sol | 72 + lib/crytic/lib/solmate/src/test/ERC1155.t.sol | 1777 + lib/crytic/lib/solmate/src/test/ERC20.t.sol | 531 + lib/crytic/lib/solmate/src/test/ERC4626.t.sol | 446 + lib/crytic/lib/solmate/src/test/ERC721.t.sol | 727 + .../solmate/src/test/FixedPointMathLib.t.sol | 360 + .../lib/solmate/src/test/LibString.t.sol | 148 + .../lib/solmate/src/test/MerkleProofLib.t.sol | 50 + .../src/test/MultiRolesAuthority.t.sol | 321 + lib/crytic/lib/solmate/src/test/Owned.t.sol | 40 + .../solmate/src/test/ReentrancyGuard.t.sol | 56 + .../lib/solmate/src/test/RolesAuthority.t.sol | 148 + lib/crytic/lib/solmate/src/test/SSTORE2.t.sol | 152 + .../lib/solmate/src/test/SafeCastLib.t.sol | 229 + .../solmate/src/test/SafeTransferLib.t.sol | 610 + .../lib/solmate/src/test/SignedWadMath.t.sol | 60 + lib/crytic/lib/solmate/src/test/WETH.t.sol | 146 + .../src/test/utils/DSInvariantTest.sol | 16 + .../lib/solmate/src/test/utils/DSTestPlus.sol | 179 + .../lib/solmate/src/test/utils/Hevm.sol | 107 + .../src/test/utils/mocks/MockAuthChild.sol | 12 + .../src/test/utils/mocks/MockAuthority.sol | 20 + .../src/test/utils/mocks/MockERC1155.sol | 42 + .../src/test/utils/mocks/MockERC20.sol | 20 + .../src/test/utils/mocks/MockERC4626.sol | 28 + .../src/test/utils/mocks/MockERC721.sol | 30 + .../src/test/utils/mocks/MockOwned.sol | 12 + .../utils/weird-tokens/MissingReturnToken.sol | 83 + .../utils/weird-tokens/ReturnsFalseToken.sol | 61 + .../weird-tokens/ReturnsGarbageToken.sol | 115 + .../weird-tokens/ReturnsTooLittleToken.sol | 70 + .../weird-tokens/ReturnsTooMuchToken.sol | 98 + .../utils/weird-tokens/ReturnsTwoToken.sol | 61 + .../utils/weird-tokens/RevertingToken.sol | 61 + lib/crytic/lib/solmate/src/tokens/ERC1155.sol | 257 + lib/crytic/lib/solmate/src/tokens/ERC20.sol | 206 + lib/crytic/lib/solmate/src/tokens/ERC721.sol | 231 + lib/crytic/lib/solmate/src/tokens/WETH.sol | 35 + .../solmate/src/utils/Bytes32AddressLib.sol | 14 + lib/crytic/lib/solmate/src/utils/CREATE3.sol | 83 + .../solmate/src/utils/FixedPointMathLib.sol | 255 + .../lib/solmate/src/utils/LibString.sol | 77 + .../lib/solmate/src/utils/MerkleProofLib.sol | 48 + .../lib/solmate/src/utils/ReentrancyGuard.sol | 19 + lib/crytic/lib/solmate/src/utils/SSTORE2.sol | 101 + .../lib/solmate/src/utils/SafeCastLib.sol | 73 + .../lib/solmate/src/utils/SafeTransferLib.sol | 128 + .../lib/solmate/src/utils/SignedWadMath.sol | 235 + lib/crytic/package-lock.json | 6844 ++++ lib/crytic/package.json | 27 + lib/erc4626-tests/ERC4626.prop.sol | 404 + lib/erc4626-tests/ERC4626.test.sol | 349 + lib/erc4626-tests/LICENSE | 661 + lib/erc4626-tests/README.md | 116 + lib/forge-std/.github/workflows/ci.yml | 134 + lib/forge-std/.github/workflows/sync.yml | 29 + lib/forge-std/.gitignore | 4 + lib/forge-std/.gitmodules | 3 + lib/forge-std/LICENSE-APACHE | 203 + lib/forge-std/LICENSE-MIT | 25 + lib/forge-std/README.md | 250 + lib/forge-std/foundry.toml | 21 + .../lib/ds-test/.github/workflows/build.yml | 41 + lib/forge-std/lib/ds-test/.gitignore | 4 + lib/forge-std/lib/ds-test/LICENSE | 674 + lib/forge-std/lib/ds-test/Makefile | 14 + lib/forge-std/lib/ds-test/default.nix | 4 + lib/forge-std/lib/ds-test/demo/demo.sol | 222 + lib/forge-std/lib/ds-test/package.json | 15 + lib/forge-std/lib/ds-test/src/test.sol | 592 + lib/forge-std/lib/ds-test/src/test.t.sol | 417 + lib/forge-std/package.json | 16 + lib/forge-std/src/Base.sol | 35 + lib/forge-std/src/Script.sol | 27 + lib/forge-std/src/StdAssertions.sol | 376 + lib/forge-std/src/StdChains.sol | 236 + lib/forge-std/src/StdCheats.sol | 817 + lib/forge-std/src/StdError.sol | 15 + lib/forge-std/src/StdInvariant.sol | 107 + lib/forge-std/src/StdJson.sol | 183 + lib/forge-std/src/StdMath.sol | 43 + lib/forge-std/src/StdStorage.sol | 378 + lib/forge-std/src/StdStyle.sol | 333 + lib/forge-std/src/StdUtils.sol | 198 + lib/forge-std/src/Test.sol | 33 + lib/forge-std/src/Vm.sol | 743 + lib/forge-std/src/console.sol | 1533 + lib/forge-std/src/console2.sol | 1558 + lib/forge-std/src/interfaces/IERC1155.sol | 105 + lib/forge-std/src/interfaces/IERC165.sol | 12 + lib/forge-std/src/interfaces/IERC20.sol | 43 + lib/forge-std/src/interfaces/IERC4626.sol | 190 + lib/forge-std/src/interfaces/IERC721.sol | 164 + lib/forge-std/src/interfaces/IMulticall3.sol | 73 + lib/forge-std/src/safeconsole.sol | 13248 +++++++ lib/forge-std/test/StdAssertions.t.sol | 1015 + lib/forge-std/test/StdChains.t.sol | 220 + lib/forge-std/test/StdCheats.t.sol | 610 + lib/forge-std/test/StdError.t.sol | 118 + lib/forge-std/test/StdMath.t.sol | 212 + lib/forge-std/test/StdStorage.t.sol | 315 + lib/forge-std/test/StdStyle.t.sol | 110 + lib/forge-std/test/StdUtils.t.sol | 342 + lib/forge-std/test/Vm.t.sol | 15 + .../test/compilation/CompilationScript.sol | 10 + .../compilation/CompilationScriptBase.sol | 10 + .../test/compilation/CompilationTest.sol | 10 + .../test/compilation/CompilationTestBase.sol | 10 + .../test/fixtures/broadcast.log.json | 187 + .../.changeset/config.json | 12 + .../.codecov.yml | 12 + .../.editorconfig | 21 + lib/openzeppelin-contracts-v4.9.3/.eslintrc | 20 + .../.github/ISSUE_TEMPLATE/bug_report.md | 21 + .../.github/ISSUE_TEMPLATE/config.yml | 4 + .../.github/ISSUE_TEMPLATE/feature_request.md | 14 + .../.github/PULL_REQUEST_TEMPLATE.md | 20 + .../.github/actions/gas-compare/action.yml | 49 + .../.github/actions/setup/action.yml | 19 + .../.github/actions/storage-layout/action.yml | 55 + .../.github/workflows/actionlint.yml | 18 + .../.github/workflows/changeset.yml | 28 + .../.github/workflows/checks.yml | 111 + .../.github/workflows/docs.yml | 19 + .../.github/workflows/formal-verification.yml | 68 + .../.github/workflows/release-cycle.yml | 218 + .../.github/workflows/upgradeable.yml | 30 + lib/openzeppelin-contracts-v4.9.3/.gitignore | 71 + lib/openzeppelin-contracts-v4.9.3/.gitmodules | 7 + lib/openzeppelin-contracts-v4.9.3/.mocharc.js | 4 + lib/openzeppelin-contracts-v4.9.3/.prettierrc | 14 + .../.solcover.js | 13 + .../.solhint.json | 14 + .../CHANGELOG.md | 730 + .../CODE_OF_CONDUCT.md | 73 + .../CONTRIBUTING.md | 36 + .../GUIDELINES.md | 117 + lib/openzeppelin-contracts-v4.9.3/LICENSE | 22 + lib/openzeppelin-contracts-v4.9.3/README.md | 90 + .../RELEASING.md | 47 + lib/openzeppelin-contracts-v4.9.3/SECURITY.md | 42 + .../audits/2017-03.md | 292 + .../audits/2018-10.pdf | Bin 0 -> 1000527 bytes .../audits/2022-10-Checkpoints.pdf | Bin 0 -> 155606 bytes .../audits/2022-10-ERC4626.pdf | Bin 0 -> 204184 bytes .../audits/2023-05-v4.9.pdf | Bin 0 -> 483005 bytes .../audits/README.md | 16 + .../certora/.gitignore | 1 + .../certora/Makefile | 54 + .../certora/README.md | 60 + .../diff/token_ERC721_ERC721.sol.patch | 14 + .../AccessControlDefaultAdminRulesHarness.sol | 47 + .../harnesses/AccessControlHarness.sol | 7 + .../harnesses/DoubleEndedQueueHarness.sol | 59 + .../harnesses/ERC20FlashMintHarness.sol | 36 + .../certora/harnesses/ERC20PermitHarness.sol | 17 + .../certora/harnesses/ERC20WrapperHarness.sol | 25 + .../harnesses/ERC3156FlashBorrowerHarness.sol | 13 + .../certora/harnesses/ERC721Harness.sol | 37 + .../harnesses/ERC721ReceiverHarness.sol | 11 + .../harnesses/EnumerableMapHarness.sol | 55 + .../harnesses/EnumerableSetHarness.sol | 35 + .../harnesses/InitializableHarness.sol | 23 + .../certora/harnesses/Ownable2StepHarness.sol | 9 + .../certora/harnesses/OwnableHarness.sol | 9 + .../certora/harnesses/PausableHarness.sol | 19 + .../harnesses/TimelockControllerHarness.sol | 12 + .../certora/reports/2021-10.pdf | Bin 0 -> 92882 bytes .../certora/reports/2022-03.pdf | Bin 0 -> 199401 bytes .../certora/reports/2022-05.pdf | Bin 0 -> 132223 bytes .../certora/run.js | 146 + .../certora/specs.json | 86 + .../certora/specs/AccessControl.spec | 126 + .../specs/AccessControlDefaultAdminRules.spec | 500 + .../certora/specs/DoubleEndedQueue.spec | 366 + .../certora/specs/ERC20.spec | 414 + .../certora/specs/ERC20FlashMint.spec | 48 + .../certora/specs/ERC20Wrapper.spec | 198 + .../certora/specs/ERC721.spec | 589 + .../certora/specs/EnumerableMap.spec | 334 + .../certora/specs/EnumerableSet.spec | 247 + .../certora/specs/Initializable.spec | 165 + .../certora/specs/Ownable.spec | 78 + .../certora/specs/Ownable2Step.spec | 108 + .../certora/specs/Pausable.spec | 96 + .../certora/specs/TimelockController.spec | 275 + .../certora/specs/helpers/helpers.spec | 1 + .../certora/specs/methods/IAccessControl.spec | 7 + .../IAccessControlDefaultAdminRules.spec | 36 + .../certora/specs/methods/IERC20.spec | 11 + .../certora/specs/methods/IERC2612.spec | 5 + .../certora/specs/methods/IERC3156.spec | 5 + .../certora/specs/methods/IERC5313.spec | 3 + .../certora/specs/methods/IERC721.spec | 20 + .../certora/specs/methods/IOwnable.spec | 5 + .../certora/specs/methods/IOwnable2Step.spec | 7 + .../contracts/access/AccessControl.sol | 248 + .../access/AccessControlCrossChain.sol | 45 + .../access/AccessControlDefaultAdminRules.sol | 383 + .../access/AccessControlEnumerable.sol | 64 + .../contracts/access/IAccessControl.sol | 88 + .../IAccessControlDefaultAdminRules.sol | 172 + .../access/IAccessControlEnumerable.sol | 31 + .../contracts/access/Ownable.sol | 83 + .../contracts/access/Ownable2Step.sol | 57 + .../contracts/access/README.adoc | 27 + .../crosschain/CrossChainEnabled.sol | 54 + .../contracts/crosschain/README.adoc | 34 + .../crosschain/amb/CrossChainEnabledAMB.sol | 49 + .../contracts/crosschain/amb/LibAMB.sol | 35 + .../arbitrum/CrossChainEnabledArbitrumL1.sol | 44 + .../arbitrum/CrossChainEnabledArbitrumL2.sol | 40 + .../crosschain/arbitrum/LibArbitrumL1.sol | 42 + .../crosschain/arbitrum/LibArbitrumL2.sol | 45 + .../contracts/crosschain/errors.sol | 7 + .../optimism/CrossChainEnabledOptimism.sol | 41 + .../crosschain/optimism/LibOptimism.sol | 36 + .../polygon/CrossChainEnabledPolygonChild.sol | 72 + .../contracts/finance/PaymentSplitter.sol | 214 + .../contracts/finance/README.adoc | 20 + .../contracts/finance/VestingWallet.sol | 145 + .../contracts/governance/Governor.sol | 723 + .../contracts/governance/IGovernor.sol | 313 + .../contracts/governance/README.adoc | 176 + .../governance/TimelockController.sol | 422 + .../GovernorCompatibilityBravo.sol | 333 + .../IGovernorCompatibilityBravo.sol | 118 + .../extensions/GovernorCountingSimple.sol | 100 + .../extensions/GovernorPreventLateQuorum.sol | 105 + .../extensions/GovernorProposalThreshold.sol | 23 + .../extensions/GovernorSettings.sol | 110 + .../extensions/GovernorTimelockCompound.sol | 190 + .../extensions/GovernorTimelockControl.sol | 166 + .../governance/extensions/GovernorVotes.sol | 55 + .../extensions/GovernorVotesComp.sol | 55 + .../GovernorVotesQuorumFraction.sol | 121 + .../extensions/IGovernorTimelock.sol | 26 + .../contracts/governance/utils/IVotes.sol | 56 + .../contracts/governance/utils/Votes.sol | 244 + .../contracts/interfaces/IERC1155.sol | 6 + .../interfaces/IERC1155MetadataURI.sol | 6 + .../contracts/interfaces/IERC1155Receiver.sol | 6 + .../contracts/interfaces/IERC1271.sol | 19 + .../contracts/interfaces/IERC1363.sol | 80 + .../contracts/interfaces/IERC1363Receiver.sol | 35 + .../contracts/interfaces/IERC1363Spender.sol | 29 + .../contracts/interfaces/IERC165.sol | 6 + .../interfaces/IERC1820Implementer.sol | 6 + .../contracts/interfaces/IERC1820Registry.sol | 6 + .../contracts/interfaces/IERC1967.sol | 26 + .../contracts/interfaces/IERC20.sol | 6 + .../contracts/interfaces/IERC20Metadata.sol | 6 + .../contracts/interfaces/IERC2309.sol | 21 + .../contracts/interfaces/IERC2612.sol | 8 + .../contracts/interfaces/IERC2981.sol | 25 + .../contracts/interfaces/IERC3156.sol | 7 + .../interfaces/IERC3156FlashBorrower.sol | 29 + .../interfaces/IERC3156FlashLender.sol | 43 + .../contracts/interfaces/IERC4626.sol | 232 + .../contracts/interfaces/IERC4906.sol | 20 + .../contracts/interfaces/IERC5267.sol | 28 + .../contracts/interfaces/IERC5313.sol | 18 + .../contracts/interfaces/IERC5805.sol | 9 + .../contracts/interfaces/IERC6372.sol | 17 + .../contracts/interfaces/IERC721.sol | 6 + .../interfaces/IERC721Enumerable.sol | 6 + .../contracts/interfaces/IERC721Metadata.sol | 6 + .../contracts/interfaces/IERC721Receiver.sol | 6 + .../contracts/interfaces/IERC777.sol | 6 + .../contracts/interfaces/IERC777Recipient.sol | 6 + .../contracts/interfaces/IERC777Sender.sol | 6 + .../contracts/interfaces/README.adoc | 73 + .../contracts/interfaces/draft-IERC1822.sol | 20 + .../contracts/interfaces/draft-IERC2612.sol | 8 + .../contracts/metatx/ERC2771Context.sol | 43 + .../contracts/metatx/MinimalForwarder.sol | 72 + .../contracts/metatx/README.adoc | 12 + .../mocks/AccessControlCrossChainMock.sol | 8 + .../contracts/mocks/ArraysMock.sol | 51 + .../contracts/mocks/CallReceiverMock.sol | 61 + .../contracts/mocks/ConditionalEscrowMock.sol | 18 + .../contracts/mocks/ContextMock.sol | 35 + .../contracts/mocks/DummyImplementation.sol | 57 + .../contracts/mocks/EIP712Verifier.sol | 16 + .../contracts/mocks/ERC1271WalletMock.sol | 26 + .../mocks/ERC165/ERC165MaliciousData.sol | 12 + .../mocks/ERC165/ERC165MissingData.sol | 7 + .../mocks/ERC165/ERC165NotSupported.sol | 5 + .../mocks/ERC165/ERC165ReturnBomb.sol | 18 + .../contracts/mocks/ERC20Mock.sol | 16 + .../contracts/mocks/ERC20Reentrant.sol | 43 + .../contracts/mocks/ERC2771ContextMock.sol | 22 + .../mocks/ERC3156FlashBorrowerMock.sol | 53 + .../contracts/mocks/ERC4626Mock.sol | 16 + .../contracts/mocks/EtherReceiverMock.sol | 17 + .../contracts/mocks/InitializableMock.sol | 130 + .../contracts/mocks/MulticallTest.sol | 23 + .../MultipleInheritanceInitializableMocks.sol | 131 + .../contracts/mocks/PausableMock.sol | 31 + .../contracts/mocks/PullPaymentMock.sol | 15 + .../contracts/mocks/ReentrancyAttack.sol | 12 + .../contracts/mocks/ReentrancyMock.sol | 51 + .../mocks/RegressionImplementation.sol | 61 + .../contracts/mocks/SafeMathMemoryCheck.sol | 72 + .../SingleInheritanceInitializableMocks.sol | 49 + .../contracts/mocks/StorageSlotMock.sol | 77 + .../contracts/mocks/TimelockReentrant.sol | 26 + .../contracts/mocks/TimersBlockNumberImpl.sol | 39 + .../contracts/mocks/TimersTimestampImpl.sol | 39 + .../contracts/mocks/VotesMock.sol | 45 + .../contracts/mocks/compound/CompTimelock.sol | 174 + .../contracts/mocks/crosschain/bridges.sol | 94 + .../contracts/mocks/crosschain/receivers.sol | 54 + .../mocks/governance/GovernorCompMock.sol | 20 + .../GovernorCompatibilityBravoMock.sol | 100 + .../mocks/governance/GovernorMock.sol | 28 + .../GovernorPreventLateQuorumMock.sol | 45 + .../GovernorTimelockCompoundMock.sol | 60 + .../GovernorTimelockControlMock.sol | 60 + .../mocks/governance/GovernorVoteMock.sol | 20 + .../governance/GovernorWithParamsMock.sol | 50 + .../contracts/mocks/proxy/BadBeacon.sol | 11 + .../mocks/proxy/ClashingImplementation.sol | 17 + .../contracts/mocks/proxy/UUPSLegacy.sol | 54 + .../mocks/proxy/UUPSUpgradeableMock.sol | 33 + .../mocks/token/ERC1155ReceiverMock.sol | 47 + .../mocks/token/ERC20DecimalsMock.sol | 17 + .../mocks/token/ERC20ExcessDecimalsMock.sol | 9 + .../mocks/token/ERC20FlashMintMock.sol | 26 + .../mocks/token/ERC20ForceApproveMock.sol | 13 + .../mocks/token/ERC20MulticallMock.sol | 8 + .../mocks/token/ERC20NoReturnMock.sol | 28 + .../mocks/token/ERC20PermitNoRevertMock.sol | 36 + .../mocks/token/ERC20ReturnFalseMock.sol | 19 + .../mocks/token/ERC20VotesLegacyMock.sol | 262 + .../mocks/token/ERC4626OffsetMock.sol | 17 + .../contracts/mocks/token/ERC4646FeesMock.sol | 40 + .../token/ERC721ConsecutiveEnumerableMock.sol | 51 + .../mocks/token/ERC721ConsecutiveMock.sol | 61 + .../mocks/token/ERC721ReceiverMock.sol | 42 + .../mocks/token/ERC721URIStorageMock.sol | 17 + .../contracts/mocks/token/ERC777Mock.sol | 13 + .../mocks/token/ERC777SenderRecipientMock.sol | 152 + .../contracts/mocks/token/VotesTimestamp.sol | 40 + .../contracts/mocks/wizard/MyGovernor1.sol | 79 + .../contracts/mocks/wizard/MyGovernor2.sol | 85 + .../contracts/mocks/wizard/MyGovernor3.sol | 94 + .../contracts/package.json | 32 + .../contracts/proxy/Clones.sol | 88 + .../contracts/proxy/ERC1967/ERC1967Proxy.sol | 32 + .../proxy/ERC1967/ERC1967Upgrade.sol | 157 + .../contracts/proxy/Proxy.sol | 86 + .../contracts/proxy/README.adoc | 87 + .../contracts/proxy/beacon/BeaconProxy.sol | 61 + .../contracts/proxy/beacon/IBeacon.sol | 16 + .../proxy/beacon/UpgradeableBeacon.sol | 65 + .../proxy/transparent/ProxyAdmin.sol | 81 + .../TransparentUpgradeableProxy.sol | 191 + .../contracts/proxy/utils/Initializable.sol | 166 + .../contracts/proxy/utils/UUPSUpgradeable.sol | 99 + .../contracts/security/Pausable.sol | 105 + .../contracts/security/PullPayment.sol | 74 + .../contracts/security/README.adoc | 20 + .../contracts/security/ReentrancyGuard.sol | 77 + .../contracts/token/ERC1155/ERC1155.sol | 497 + .../contracts/token/ERC1155/IERC1155.sol | 119 + .../token/ERC1155/IERC1155Receiver.sol | 58 + .../contracts/token/ERC1155/README.adoc | 49 + .../ERC1155/extensions/ERC1155Burnable.sol | 32 + .../ERC1155/extensions/ERC1155Pausable.sol | 44 + .../ERC1155/extensions/ERC1155Supply.sol | 64 + .../ERC1155/extensions/ERC1155URIStorage.sol | 63 + .../extensions/IERC1155MetadataURI.sol | 22 + .../presets/ERC1155PresetMinterPauser.sol | 114 + .../contracts/token/ERC1155/presets/README.md | 1 + .../token/ERC1155/utils/ERC1155Holder.sol | 36 + .../token/ERC1155/utils/ERC1155Receiver.sol | 19 + .../contracts/token/ERC20/ERC20.sol | 365 + .../contracts/token/ERC20/IERC20.sol | 78 + .../contracts/token/ERC20/README.adoc | 78 + .../token/ERC20/extensions/ERC20Burnable.sol | 39 + .../token/ERC20/extensions/ERC20Capped.sol | 37 + .../token/ERC20/extensions/ERC20FlashMint.sol | 109 + .../token/ERC20/extensions/ERC20Pausable.sol | 35 + .../token/ERC20/extensions/ERC20Permit.sol | 95 + .../token/ERC20/extensions/ERC20Snapshot.sol | 191 + .../token/ERC20/extensions/ERC20Votes.sol | 290 + .../token/ERC20/extensions/ERC20VotesComp.sol | 46 + .../token/ERC20/extensions/ERC20Wrapper.sol | 73 + .../token/ERC20/extensions/ERC4626.sol | 256 + .../token/ERC20/extensions/IERC20Metadata.sol | 28 + .../token/ERC20/extensions/IERC20Permit.sol | 60 + .../ERC20/extensions/draft-ERC20Permit.sol | 8 + .../ERC20/extensions/draft-IERC20Permit.sol | 8 + .../ERC20/presets/ERC20PresetFixedSupply.sol | 30 + .../ERC20/presets/ERC20PresetMinterPauser.sol | 94 + .../contracts/token/ERC20/presets/README.md | 1 + .../contracts/token/ERC20/utils/SafeERC20.sol | 143 + .../token/ERC20/utils/TokenTimelock.sol | 72 + .../contracts/token/ERC721/ERC721.sol | 466 + .../contracts/token/ERC721/IERC721.sol | 132 + .../token/ERC721/IERC721Receiver.sol | 27 + .../contracts/token/ERC721/README.adoc | 73 + .../ERC721/extensions/ERC721Burnable.sol | 26 + .../ERC721/extensions/ERC721Consecutive.sol | 148 + .../ERC721/extensions/ERC721Enumerable.sol | 159 + .../ERC721/extensions/ERC721Pausable.sol | 40 + .../token/ERC721/extensions/ERC721Royalty.sol | 38 + .../ERC721/extensions/ERC721URIStorage.sol | 74 + .../token/ERC721/extensions/ERC721Votes.sol | 43 + .../token/ERC721/extensions/ERC721Wrapper.sol | 97 + .../ERC721/extensions/IERC721Enumerable.sol | 29 + .../ERC721/extensions/IERC721Metadata.sol | 27 + .../ERC721/extensions/draft-ERC721Votes.sol | 9 + .../ERC721PresetMinterPauserAutoId.sol | 132 + .../contracts/token/ERC721/presets/README.md | 1 + .../token/ERC721/utils/ERC721Holder.sol | 23 + .../contracts/token/ERC777/ERC777.sol | 514 + .../contracts/token/ERC777/IERC777.sol | 200 + .../token/ERC777/IERC777Recipient.sol | 35 + .../contracts/token/ERC777/IERC777Sender.sol | 35 + .../contracts/token/ERC777/README.adoc | 32 + .../presets/ERC777PresetFixedSupply.sol | 30 + .../contracts/token/common/ERC2981.sol | 107 + .../contracts/token/common/README.adoc | 10 + .../contracts/utils/Address.sol | 244 + .../contracts/utils/Arrays.sol | 105 + .../contracts/utils/Base64.sol | 92 + .../contracts/utils/Checkpoints.sol | 560 + .../contracts/utils/Context.sol | 24 + .../contracts/utils/Counters.sol | 43 + .../contracts/utils/Create2.sol | 75 + .../contracts/utils/Multicall.sol | 25 + .../contracts/utils/README.adoc | 113 + .../contracts/utils/ShortStrings.sol | 122 + .../contracts/utils/StorageSlot.sol | 138 + .../contracts/utils/Strings.sol | 85 + .../contracts/utils/Timers.sol | 75 + .../contracts/utils/cryptography/ECDSA.sol | 217 + .../contracts/utils/cryptography/EIP712.sol | 142 + .../utils/cryptography/MerkleProof.sol | 227 + .../utils/cryptography/SignatureChecker.sol | 50 + .../utils/cryptography/draft-EIP712.sol | 8 + .../utils/escrow/ConditionalEscrow.sol | 25 + .../contracts/utils/escrow/Escrow.sol | 67 + .../contracts/utils/escrow/RefundEscrow.sol | 100 + .../contracts/utils/introspection/ERC165.sol | 29 + .../utils/introspection/ERC165Checker.sol | 126 + .../utils/introspection/ERC165Storage.sol | 42 + .../introspection/ERC1820Implementer.sol | 43 + .../contracts/utils/introspection/IERC165.sol | 25 + .../introspection/IERC1820Implementer.sol | 20 + .../utils/introspection/IERC1820Registry.sol | 112 + .../contracts/utils/math/Math.sol | 339 + .../contracts/utils/math/SafeCast.sol | 1136 + .../contracts/utils/math/SafeMath.sol | 215 + .../contracts/utils/math/SignedMath.sol | 43 + .../contracts/utils/math/SignedSafeMath.sol | 68 + .../contracts/utils/structs/BitMaps.sol | 51 + .../utils/structs/DoubleEndedQueue.sol | 170 + .../contracts/utils/structs/EnumerableMap.sol | 598 + .../contracts/utils/structs/EnumerableSet.sol | 378 + .../contracts/vendor/amb/IAMB.sol | 41 + .../contracts/vendor/arbitrum/IArbSys.sol | 134 + .../contracts/vendor/arbitrum/IBridge.sol | 102 + .../arbitrum/IDelayedMessageProvider.sol | 16 + .../contracts/vendor/arbitrum/IInbox.sol | 152 + .../contracts/vendor/arbitrum/IOutbox.sol | 117 + .../vendor/compound/ICompoundTimelock.sol | 86 + .../contracts/vendor/compound/LICENSE | 11 + .../vendor/optimism/ICrossDomainMessenger.sol | 34 + .../contracts/vendor/optimism/LICENSE | 22 + .../vendor/polygon/IFxMessageProcessor.sol | 7 + .../foundry.toml | 3 + .../hardhat.config.js | 118 + .../hardhat/env-artifacts.js | 24 + .../hardhat/env-contract.js | 10 + .../hardhat/ignore-unreachable-warnings.js | 45 + .../hardhat/skip-foundry-tests.js | 6 + .../hardhat/task-test-get-files.js | 25 + .../lib/erc4626-tests/ERC4626.prop.sol | 404 + .../lib/erc4626-tests/ERC4626.test.sol | 349 + .../lib/erc4626-tests/LICENSE | 661 + .../lib/erc4626-tests/README.md | 116 + .../lib/forge-std/.github/workflows/ci.yml | 92 + .../lib/forge-std/.gitignore | 4 + .../lib/forge-std/.gitmodules | 3 + .../lib/forge-std/LICENSE-APACHE | 203 + .../lib/forge-std/LICENSE-MIT | 25 + .../lib/forge-std/README.md | 250 + .../lib/forge-std/foundry.toml | 21 + .../lib/ds-test/.github/workflows/build.yml | 41 + .../lib/forge-std/lib/ds-test/.gitignore | 4 + .../lib/forge-std/lib/ds-test/LICENSE | 674 + .../lib/forge-std/lib/ds-test/Makefile | 14 + .../lib/forge-std/lib/ds-test/default.nix | 4 + .../lib/forge-std/lib/ds-test/demo/demo.sol | 222 + .../lib/forge-std/lib/ds-test/package.json | 15 + .../lib/forge-std/lib/ds-test/src/test.sol | 469 + .../lib/forge-std/lib/ds-test/src/test.t.sol | 313 + .../lib/forge-std/package.json | 16 + .../lib/forge-std/src/Base.sol | 33 + .../lib/forge-std/src/Script.sol | 26 + .../lib/forge-std/src/StdAssertions.sol | 376 + .../lib/forge-std/src/StdChains.sol | 233 + .../lib/forge-std/src/StdCheats.sol | 624 + .../lib/forge-std/src/StdError.sol | 15 + .../lib/forge-std/src/StdInvariant.sol | 92 + .../lib/forge-std/src/StdJson.sol | 179 + .../lib/forge-std/src/StdMath.sol | 43 + .../lib/forge-std/src/StdStorage.sol | 327 + .../lib/forge-std/src/StdStyle.sol | 333 + .../lib/forge-std/src/StdUtils.sol | 189 + .../lib/forge-std/src/Test.sol | 32 + .../lib/forge-std/src/Vm.sol | 409 + .../lib/forge-std/src/console.sol | 1533 + .../lib/forge-std/src/console2.sol | 1546 + .../lib/forge-std/src/interfaces/IERC1155.sol | 105 + .../lib/forge-std/src/interfaces/IERC165.sol | 12 + .../lib/forge-std/src/interfaces/IERC20.sol | 43 + .../lib/forge-std/src/interfaces/IERC4626.sol | 190 + .../lib/forge-std/src/interfaces/IERC721.sol | 164 + .../forge-std/src/interfaces/IMulticall3.sol | 73 + .../lib/forge-std/test/StdAssertions.t.sol | 954 + .../lib/forge-std/test/StdChains.t.sol | 160 + .../lib/forge-std/test/StdCheats.t.sol | 401 + .../lib/forge-std/test/StdError.t.sol | 118 + .../lib/forge-std/test/StdMath.t.sol | 197 + .../lib/forge-std/test/StdStorage.t.sol | 283 + .../lib/forge-std/test/StdStyle.t.sol | 110 + .../lib/forge-std/test/StdUtils.t.sol | 297 + .../test/compilation/CompilationScript.sol | 10 + .../compilation/CompilationScriptBase.sol | 10 + .../test/compilation/CompilationTest.sol | 10 + .../test/compilation/CompilationTestBase.sol | 10 + .../test/fixtures/broadcast.log.json | 187 + lib/openzeppelin-contracts-v4.9.3/logo.svg | 15 + .../netlify.toml | 3 + .../package-lock.json | 28833 +++++++++++++++ .../package.json | 96 + .../remappings.txt | 1 + .../renovate.json | 4 + .../requirements.txt | 1 + .../scripts/checks/compare-layout.js | 19 + .../scripts/checks/compareGasReports.js | 243 + .../scripts/checks/extract-layout.js | 40 + .../scripts/checks/generation.sh | 6 + .../scripts/checks/inheritance-ordering.js | 54 + .../scripts/gen-nav.js | 41 + .../scripts/generate/format-lines.js | 16 + .../scripts/generate/run.js | 49 + .../scripts/generate/templates/Checkpoints.js | 304 + .../generate/templates/Checkpoints.opts.js | 22 + .../generate/templates/Checkpoints.t.js | 256 + .../generate/templates/EnumerableMap.js | 310 + .../generate/templates/EnumerableSet.js | 250 + .../scripts/generate/templates/SafeCast.js | 163 + .../scripts/generate/templates/StorageSlot.js | 87 + .../scripts/generate/templates/conversion.js | 30 + .../scripts/git-user-config.sh | 6 + .../scripts/helpers.js | 37 + .../scripts/migrate-imports.js | 180 + .../scripts/prepack.sh | 12 + .../scripts/prepare-contracts-package.sh | 15 + .../scripts/prepare-docs.sh | 26 + .../scripts/prepare.sh | 10 + .../scripts/release/format-changelog.js | 33 + .../scripts/release/synchronize-versions.js | 15 + .../scripts/release/update-comment.js | 34 + .../scripts/release/version.sh | 11 + .../release/workflow/exit-prerelease.sh | 8 + .../release/workflow/github-release.js | 47 + .../release/workflow/integrity-check.sh | 20 + .../scripts/release/workflow/pack.sh | 26 + .../scripts/release/workflow/publish.sh | 20 + .../scripts/release/workflow/rerun.js | 7 + .../workflow/set-changesets-pr-title.js | 17 + .../scripts/release/workflow/start.sh | 35 + .../scripts/release/workflow/state.js | 112 + .../scripts/remove-ignored-artifacts.js | 45 + .../scripts/update-docs-branch.js | 63 + .../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 + .../slither.config.json | 5 + .../test/TESTING.md | 3 + .../test/access/AccessControl.behavior.js | 867 + .../test/access/AccessControl.test.js | 12 + .../access/AccessControlCrossChain.test.js | 49 + .../AccessControlDefaultAdminRules.test.js | 25 + .../access/AccessControlEnumerable.test.js | 17 + .../test/access/Ownable.test.js | 59 + .../test/access/Ownable2Step.test.js | 67 + .../test/crosschain/CrossChainEnabled.test.js | 78 + .../test/finance/PaymentSplitter.test.js | 217 + .../test/finance/VestingWallet.behavior.js | 59 + .../test/finance/VestingWallet.test.js | 67 + .../test/governance/Governor.t.sol | 55 + .../test/governance/Governor.test.js | 782 + .../governance/TimelockController.test.js | 1254 + .../GovernorCompatibilityBravo.test.js | 283 + .../extensions/GovernorComp.test.js | 88 + .../extensions/GovernorERC721.test.js | 115 + .../GovernorPreventLateQuorum.test.js | 189 + .../GovernorTimelockCompound.test.js | 352 + .../GovernorTimelockControl.test.js | 445 + .../GovernorVotesQuorumFraction.test.js | 154 + .../extensions/GovernorWithParams.test.js | 173 + .../test/governance/utils/EIP6372.behavior.js | 23 + .../test/governance/utils/Votes.behavior.js | 361 + .../test/governance/utils/Votes.test.js | 71 + .../test/helpers/chainid.js | 10 + .../test/helpers/create2.js | 11 + .../test/helpers/crosschain.js | 61 + .../test/helpers/customError.js | 24 + .../test/helpers/eip712.js | 67 + .../test/helpers/enums.js | 12 + .../test/helpers/erc1967.js | 24 + .../test/helpers/governance.js | 201 + .../test/helpers/map-values.js | 7 + .../test/helpers/sign.js | 63 + .../test/helpers/time.js | 17 + .../test/helpers/txpool.js | 38 + .../test/metatx/ERC2771Context.test.js | 122 + .../test/metatx/MinimalForwarder.test.js | 169 + .../test/migrate-imports.test.js | 33 + .../test/proxy/Clones.behaviour.js | 136 + .../test/proxy/Clones.test.js | 61 + .../test/proxy/ERC1967/ERC1967Proxy.test.js | 13 + .../test/proxy/Proxy.behaviour.js | 225 + .../test/proxy/beacon/BeaconProxy.test.js | 139 + .../proxy/beacon/UpgradeableBeacon.test.js | 44 + .../test/proxy/transparent/ProxyAdmin.test.js | 127 + .../TransparentUpgradeableProxy.behaviour.js | 433 + .../TransparentUpgradeableProxy.test.js | 17 + .../test/proxy/utils/Initializable.test.js | 218 + .../test/proxy/utils/UUPSUpgradeable.test.js | 85 + .../test/security/Pausable.test.js | 85 + .../test/security/PullPayment.test.js | 51 + .../test/security/ReentrancyGuard.test.js | 43 + .../test/token/ERC1155/ERC1155.behavior.js | 767 + .../test/token/ERC1155/ERC1155.test.js | 235 + .../extensions/ERC1155Burnable.test.js | 67 + .../extensions/ERC1155Pausable.test.js | 108 + .../ERC1155/extensions/ERC1155Supply.test.js | 107 + .../extensions/ERC1155URIStorage.test.js | 66 + .../presets/ERC1155PresetMinterPauser.test.js | 156 + .../token/ERC1155/utils/ERC1155Holder.test.js | 64 + .../test/token/ERC20/ERC20.behavior.js | 322 + .../test/token/ERC20/ERC20.test.js | 305 + .../extensions/ERC20Burnable.behavior.js | 106 + .../ERC20/extensions/ERC20Burnable.test.js | 20 + .../ERC20/extensions/ERC20Capped.behavior.js | 32 + .../ERC20/extensions/ERC20Capped.test.js | 23 + .../ERC20/extensions/ERC20FlashMint.test.js | 204 + .../ERC20/extensions/ERC20Pausable.test.js | 133 + .../ERC20/extensions/ERC20Snapshot.test.js | 207 + .../token/ERC20/extensions/ERC20Votes.test.js | 578 + .../ERC20/extensions/ERC20VotesComp.test.js | 543 + .../ERC20/extensions/ERC20Wrapper.test.js | 190 + .../test/token/ERC20/extensions/ERC4626.t.sol | 42 + .../token/ERC20/extensions/ERC4626.test.js | 1031 + .../extensions/draft-ERC20Permit.test.js | 103 + .../presets/ERC20PresetFixedSupply.test.js | 42 + .../presets/ERC20PresetMinterPauser.test.js | 110 + .../test/token/ERC20/utils/SafeERC20.test.js | 350 + .../token/ERC20/utils/TokenTimelock.test.js | 71 + .../test/token/ERC721/ERC721.behavior.js | 893 + .../test/token/ERC721/ERC721.test.js | 15 + .../token/ERC721/ERC721Enumerable.test.js | 20 + .../ERC721/extensions/ERC721Burnable.test.js | 70 + .../ERC721/extensions/ERC721Consecutive.t.sol | 122 + .../extensions/ERC721Consecutive.test.js | 206 + .../ERC721/extensions/ERC721Pausable.test.js | 92 + .../ERC721/extensions/ERC721Royalty.test.js | 41 + .../extensions/ERC721URIStorage.test.js | 100 + .../ERC721/extensions/ERC721Votes.test.js | 184 + .../ERC721/extensions/ERC721Wrapper.test.js | 283 + .../ERC721PresetMinterPauserAutoId.test.js | 122 + .../token/ERC721/utils/ERC721Holder.test.js | 22 + .../test/token/ERC777/ERC777.behavior.js | 597 + .../test/token/ERC777/ERC777.test.js | 556 + .../presets/ERC777PresetFixedSupply.test.js | 49 + .../test/token/common/ERC2981.behavior.js | 157 + .../test/utils/Address.test.js | 361 + .../test/utils/Arrays.test.js | 123 + .../test/utils/Base64.test.js | 33 + .../test/utils/Checkpoints.t.sol | 347 + .../test/utils/Checkpoints.test.js | 255 + .../test/utils/Context.behavior.js | 42 + .../test/utils/Context.test.js | 17 + .../test/utils/Counters.test.js | 84 + .../test/utils/Create2.test.js | 89 + .../test/utils/Multicall.test.js | 68 + .../test/utils/ShortStrings.t.sol | 55 + .../test/utils/ShortStrings.test.js | 55 + .../test/utils/StorageSlot.test.js | 210 + .../test/utils/Strings.test.js | 150 + .../test/utils/TimersBlockNumberImpl.test.js | 55 + .../test/utils/TimersTimestamp.test.js | 55 + .../test/utils/cryptography/ECDSA.test.js | 260 + .../test/utils/cryptography/EIP712.test.js | 103 + .../utils/cryptography/MerkleProof.test.js | 200 + .../cryptography/SignatureChecker.test.js | 87 + .../utils/escrow/ConditionalEscrow.test.js | 37 + .../test/utils/escrow/Escrow.behavior.js | 90 + .../test/utils/escrow/Escrow.test.js | 14 + .../test/utils/escrow/RefundEscrow.test.js | 143 + .../test/utils/introspection/ERC165.test.js | 11 + .../utils/introspection/ERC165Checker.test.js | 302 + .../utils/introspection/ERC165Storage.test.js | 23 + .../introspection/ERC1820Implementer.test.js | 71 + .../SupportsInterface.behavior.js | 146 + .../test/utils/math/Math.t.sol | 217 + .../test/utils/math/Math.test.js | 289 + .../test/utils/math/SafeCast.test.js | 152 + .../test/utils/math/SafeMath.test.js | 433 + .../test/utils/math/SignedMath.test.js | 95 + .../test/utils/math/SignedSafeMath.test.js | 152 + .../test/utils/structs/BitMap.test.js | 145 + .../utils/structs/DoubleEndedQueue.test.js | 99 + .../utils/structs/EnumerableMap.behavior.js | 185 + .../test/utils/structs/EnumerableMap.test.js | 154 + .../utils/structs/EnumerableSet.behavior.js | 129 + .../test/utils/structs/EnumerableSet.test.js | 79 + .../.changeset/config.json | 12 + .../.codecov.yml | 12 + .../.editorconfig | 21 + lib/openzeppelin-contracts-v5.0.0/.eslintrc | 20 + .../.github/ISSUE_TEMPLATE/bug_report.md | 21 + .../.github/ISSUE_TEMPLATE/config.yml | 4 + .../.github/ISSUE_TEMPLATE/feature_request.md | 14 + .../.github/PULL_REQUEST_TEMPLATE.md | 20 + .../.github/actions/gas-compare/action.yml | 49 + .../.github/actions/setup/action.yml | 21 + .../.github/actions/storage-layout/action.yml | 55 + .../.github/workflows/actionlint.yml | 18 + .../.github/workflows/changeset.yml | 28 + .../.github/workflows/checks.yml | 118 + .../.github/workflows/docs.yml | 19 + .../.github/workflows/formal-verification.yml | 68 + .../.github/workflows/release-cycle.yml | 214 + .../.github/workflows/upgradeable.yml | 34 + lib/openzeppelin-contracts-v5.0.0/.gitignore | 72 + lib/openzeppelin-contracts-v5.0.0/.gitmodules | 7 + lib/openzeppelin-contracts-v5.0.0/.mocharc.js | 4 + lib/openzeppelin-contracts-v5.0.0/.prettierrc | 15 + .../.solcover.js | 13 + .../CHANGELOG.md | 972 + .../CODE_OF_CONDUCT.md | 73 + .../CONTRIBUTING.md | 36 + .../GUIDELINES.md | 148 + lib/openzeppelin-contracts-v5.0.0/LICENSE | 22 + lib/openzeppelin-contracts-v5.0.0/README.md | 107 + .../RELEASING.md | 45 + lib/openzeppelin-contracts-v5.0.0/SECURITY.md | 42 + .../audits/2017-03.md | 292 + .../audits/2018-10.pdf | Bin 0 -> 1000527 bytes .../audits/2022-10-Checkpoints.pdf | Bin 0 -> 155606 bytes .../audits/2022-10-ERC4626.pdf | Bin 0 -> 204184 bytes .../audits/2023-05-v4.9.pdf | Bin 0 -> 485395 bytes .../audits/2023-10-v5.0.pdf | Bin 0 -> 910284 bytes .../audits/README.md | 17 + .../certora/.gitignore | 1 + .../certora/Makefile | 54 + .../certora/README.md | 60 + .../access_manager_AccessManager.sol.patch | 97 + .../AccessControlDefaultAdminRulesHarness.sol | 46 + .../harnesses/AccessControlHarness.sol | 6 + .../harnesses/DoubleEndedQueueHarness.sol | 58 + .../harnesses/ERC20FlashMintHarness.sol | 36 + .../certora/harnesses/ERC20PermitHarness.sol | 16 + .../certora/harnesses/ERC20WrapperHarness.sol | 34 + .../harnesses/ERC3156FlashBorrowerHarness.sol | 13 + .../certora/harnesses/ERC721Harness.sol | 33 + .../harnesses/ERC721ReceiverHarness.sol | 11 + .../harnesses/EnumerableMapHarness.sol | 55 + .../harnesses/EnumerableSetHarness.sol | 35 + .../harnesses/InitializableHarness.sol | 23 + .../certora/harnesses/Ownable2StepHarness.sol | 10 + .../certora/harnesses/OwnableHarness.sol | 10 + .../certora/harnesses/PausableHarness.sol | 18 + .../harnesses/TimelockControllerHarness.sol | 13 + .../certora/reports/2021-10.pdf | Bin 0 -> 92882 bytes .../certora/reports/2022-03.pdf | Bin 0 -> 199401 bytes .../certora/reports/2022-05.pdf | Bin 0 -> 132223 bytes .../certora/run.js | 160 + .../certora/specs.json | 86 + .../certora/specs/AccessControl.spec | 119 + .../specs/AccessControlDefaultAdminRules.spec | 464 + .../certora/specs/DoubleEndedQueue.spec | 300 + .../certora/specs/ERC20.spec | 352 + .../certora/specs/ERC20FlashMint.spec | 55 + .../certora/specs/ERC20Wrapper.spec | 198 + .../certora/specs/ERC721.spec | 679 + .../certora/specs/EnumerableMap.spec | 333 + .../certora/specs/EnumerableSet.spec | 246 + .../certora/specs/Initializable.spec | 165 + .../certora/specs/Ownable.spec | 77 + .../certora/specs/Ownable2Step.spec | 108 + .../certora/specs/Pausable.spec | 96 + .../certora/specs/TimelockController.spec | 274 + .../certora/specs/helpers/helpers.spec | 7 + .../certora/specs/methods/IAccessControl.spec | 8 + .../IAccessControlDefaultAdminRules.spec | 36 + .../certora/specs/methods/IERC20.spec | 11 + .../certora/specs/methods/IERC2612.spec | 5 + .../specs/methods/IERC3156FlashBorrower.spec | 3 + .../specs/methods/IERC3156FlashLender.spec | 5 + .../certora/specs/methods/IERC5313.spec | 3 + .../certora/specs/methods/IERC721.spec | 17 + .../specs/methods/IERC721Receiver.spec | 3 + .../certora/specs/methods/IOwnable.spec | 5 + .../certora/specs/methods/IOwnable2Step.spec | 7 + .../contracts/access/AccessControl.sol | 209 + .../contracts/access/IAccessControl.sol | 98 + .../contracts/access/Ownable.sol | 100 + .../contracts/access/Ownable2Step.sol | 59 + .../contracts/access/README.adoc | 43 + .../AccessControlDefaultAdminRules.sol | 396 + .../extensions/AccessControlEnumerable.sol | 70 + .../IAccessControlDefaultAdminRules.sol | 192 + .../extensions/IAccessControlEnumerable.sol | 31 + .../access/manager/AccessManaged.sol | 113 + .../access/manager/AccessManager.sol | 730 + .../access/manager/AuthorityUtils.sol | 32 + .../access/manager/IAccessManaged.sol | 32 + .../access/manager/IAccessManager.sol | 392 + .../contracts/access/manager/IAuthority.sol | 14 + .../contracts/finance/README.adoc | 14 + .../contracts/finance/VestingWallet.sol | 154 + .../contracts/governance/Governor.sol | 850 + .../contracts/governance/IGovernor.sol | 427 + .../contracts/governance/README.adoc | 167 + .../governance/TimelockController.sol | 472 + .../extensions/GovernorCountingSimple.sol | 100 + .../extensions/GovernorPreventLateQuorum.sol | 102 + .../extensions/GovernorSettings.sol | 112 + .../governance/extensions/GovernorStorage.sol | 115 + .../extensions/GovernorTimelockAccess.sol | 346 + .../extensions/GovernorTimelockCompound.sol | 167 + .../extensions/GovernorTimelockControl.sol | 173 + .../governance/extensions/GovernorVotes.sol | 64 + .../GovernorVotesQuorumFraction.sol | 110 + .../contracts/governance/utils/IVotes.sol | 59 + .../contracts/governance/utils/Votes.sol | 251 + .../contracts/interfaces/IERC1155.sol | 6 + .../interfaces/IERC1155MetadataURI.sol | 6 + .../contracts/interfaces/IERC1155Receiver.sol | 6 + .../contracts/interfaces/IERC1271.sol | 17 + .../contracts/interfaces/IERC1363.sol | 80 + .../contracts/interfaces/IERC1363Receiver.sol | 35 + .../contracts/interfaces/IERC1363Spender.sol | 29 + .../contracts/interfaces/IERC165.sol | 6 + .../interfaces/IERC1820Implementer.sol | 20 + .../contracts/interfaces/IERC1820Registry.sol | 112 + .../contracts/interfaces/IERC1967.sol | 24 + .../contracts/interfaces/IERC20.sol | 6 + .../contracts/interfaces/IERC20Metadata.sol | 6 + .../contracts/interfaces/IERC2309.sol | 19 + .../contracts/interfaces/IERC2612.sol | 8 + .../contracts/interfaces/IERC2981.sol | 23 + .../contracts/interfaces/IERC3156.sol | 7 + .../interfaces/IERC3156FlashBorrower.sol | 27 + .../interfaces/IERC3156FlashLender.sol | 41 + .../contracts/interfaces/IERC4626.sol | 230 + .../contracts/interfaces/IERC4906.sol | 20 + .../contracts/interfaces/IERC5267.sol | 28 + .../contracts/interfaces/IERC5313.sol | 16 + .../contracts/interfaces/IERC5805.sol | 9 + .../contracts/interfaces/IERC6372.sol | 17 + .../contracts/interfaces/IERC721.sol | 6 + .../interfaces/IERC721Enumerable.sol | 6 + .../contracts/interfaces/IERC721Metadata.sol | 6 + .../contracts/interfaces/IERC721Receiver.sol | 6 + .../contracts/interfaces/IERC777.sol | 200 + .../contracts/interfaces/IERC777Recipient.sol | 35 + .../contracts/interfaces/IERC777Sender.sol | 35 + .../contracts/interfaces/README.adoc | 82 + .../contracts/interfaces/draft-IERC1822.sol | 20 + .../contracts/interfaces/draft-IERC6093.sol | 161 + .../contracts/metatx/ERC2771Context.sol | 75 + .../contracts/metatx/ERC2771Forwarder.sol | 370 + .../contracts/metatx/README.adoc | 12 + .../contracts/mocks/AccessManagedTarget.sol | 34 + .../contracts/mocks/ArraysMock.sol | 51 + .../contracts/mocks/AuthorityMock.sol | 69 + .../contracts/mocks/CallReceiverMock.sol | 73 + .../contracts/mocks/ContextMock.sol | 35 + .../contracts/mocks/DummyImplementation.sol | 65 + .../contracts/mocks/EIP712Verifier.sol | 16 + .../contracts/mocks/ERC1271WalletMock.sol | 24 + .../ERC165/ERC165InterfacesSupported.sol | 58 + .../mocks/ERC165/ERC165MaliciousData.sol | 12 + .../mocks/ERC165/ERC165MissingData.sol | 7 + .../mocks/ERC165/ERC165NotSupported.sol | 5 + .../mocks/ERC165/ERC165ReturnBomb.sol | 18 + .../contracts/mocks/ERC2771ContextMock.sol | 23 + .../mocks/ERC3156FlashBorrowerMock.sol | 53 + .../contracts/mocks/EtherReceiverMock.sol | 17 + .../contracts/mocks/InitializableMock.sol | 130 + .../contracts/mocks/MulticallTest.sol | 23 + .../MultipleInheritanceInitializableMocks.sol | 131 + .../contracts/mocks/PausableMock.sol | 31 + .../contracts/mocks/ReentrancyAttack.sol | 12 + .../contracts/mocks/ReentrancyMock.sol | 50 + .../mocks/RegressionImplementation.sol | 61 + .../SingleInheritanceInitializableMocks.sol | 49 + .../contracts/mocks/Stateless.sol | 36 + .../contracts/mocks/StorageSlotMock.sol | 77 + .../contracts/mocks/TimelockReentrant.sol | 26 + .../contracts/mocks/UpgradeableBeaconMock.sol | 27 + .../contracts/mocks/VotesMock.sol | 42 + .../contracts/mocks/compound/CompTimelock.sol | 174 + .../mocks/governance/GovernorMock.sol | 14 + .../GovernorPreventLateQuorumMock.sol | 46 + .../mocks/governance/GovernorStorageMock.sol | 79 + .../governance/GovernorTimelockAccessMock.sol | 70 + .../GovernorTimelockCompoundMock.sol | 69 + .../GovernorTimelockControlMock.sol | 69 + .../mocks/governance/GovernorVoteMock.sol | 20 + .../governance/GovernorWithParamsMock.sol | 51 + .../contracts/mocks/proxy/BadBeacon.sol | 11 + .../mocks/proxy/ClashingImplementation.sol | 19 + .../mocks/proxy/UUPSUpgradeableMock.sol | 35 + .../mocks/token/ERC1155ReceiverMock.sol | 74 + .../mocks/token/ERC20ApprovalMock.sol | 10 + .../mocks/token/ERC20DecimalsMock.sol | 17 + .../mocks/token/ERC20ExcessDecimalsMock.sol | 9 + .../mocks/token/ERC20FlashMintMock.sol | 26 + .../mocks/token/ERC20ForceApproveMock.sol | 13 + .../contracts/mocks/token/ERC20Mock.sol | 16 + .../mocks/token/ERC20MulticallMock.sol | 8 + .../mocks/token/ERC20NoReturnMock.sol | 28 + .../contracts/mocks/token/ERC20Reentrant.sol | 39 + .../mocks/token/ERC20ReturnFalseMock.sol | 19 + .../mocks/token/ERC20VotesLegacyMock.sol | 253 + .../mocks/token/ERC4626LimitsMock.sol | 23 + .../contracts/mocks/token/ERC4626Mock.sol | 17 + .../mocks/token/ERC4626OffsetMock.sol | 17 + .../contracts/mocks/token/ERC4646FeesMock.sol | 40 + .../token/ERC721ConsecutiveEnumerableMock.sol | 42 + .../mocks/token/ERC721ConsecutiveMock.sol | 61 + .../mocks/token/ERC721ReceiverMock.sol | 47 + .../mocks/token/ERC721URIStorageMock.sol | 17 + .../contracts/mocks/token/VotesTimestamp.sol | 29 + .../contracts/package.json | 32 + .../contracts/proxy/Clones.sol | 95 + .../contracts/proxy/ERC1967/ERC1967Proxy.sol | 40 + .../contracts/proxy/ERC1967/ERC1967Utils.sol | 193 + .../contracts/proxy/Proxy.sol | 69 + .../contracts/proxy/README.adoc | 87 + .../contracts/proxy/beacon/BeaconProxy.sol | 57 + .../contracts/proxy/beacon/IBeacon.sol | 16 + .../proxy/beacon/UpgradeableBeacon.sol | 70 + .../proxy/transparent/ProxyAdmin.sol | 45 + .../TransparentUpgradeableProxy.sol | 116 + .../contracts/proxy/utils/Initializable.sol | 228 + .../contracts/proxy/utils/UUPSUpgradeable.sol | 147 + .../contracts/token/ERC1155/ERC1155.sol | 468 + .../contracts/token/ERC1155/IERC1155.sol | 128 + .../token/ERC1155/IERC1155Receiver.sol | 59 + .../contracts/token/ERC1155/README.adoc | 41 + .../ERC1155/extensions/ERC1155Burnable.sol | 28 + .../ERC1155/extensions/ERC1155Pausable.sol | 38 + .../ERC1155/extensions/ERC1155Supply.sol | 87 + .../ERC1155/extensions/ERC1155URIStorage.sol | 61 + .../extensions/IERC1155MetadataURI.sol | 20 + .../token/ERC1155/utils/ERC1155Holder.sol | 42 + .../contracts/token/ERC20/ERC20.sol | 316 + .../contracts/token/ERC20/IERC20.sol | 79 + .../contracts/token/ERC20/README.adoc | 67 + .../token/ERC20/extensions/ERC20Burnable.sol | 39 + .../token/ERC20/extensions/ERC20Capped.sol | 56 + .../token/ERC20/extensions/ERC20FlashMint.sol | 134 + .../token/ERC20/extensions/ERC20Pausable.sol | 33 + .../token/ERC20/extensions/ERC20Permit.sol | 83 + .../token/ERC20/extensions/ERC20Votes.sol | 83 + .../token/ERC20/extensions/ERC20Wrapper.sol | 86 + .../token/ERC20/extensions/ERC4626.sol | 286 + .../token/ERC20/extensions/IERC20Metadata.sol | 26 + .../token/ERC20/extensions/IERC20Permit.sol | 90 + .../contracts/token/ERC20/utils/SafeERC20.sol | 118 + .../contracts/token/ERC721/ERC721.sol | 483 + .../contracts/token/ERC721/IERC721.sol | 135 + .../token/ERC721/IERC721Receiver.sol | 28 + .../contracts/token/ERC721/README.adoc | 67 + .../ERC721/extensions/ERC721Burnable.sol | 26 + .../ERC721/extensions/ERC721Consecutive.sol | 176 + .../ERC721/extensions/ERC721Enumerable.sol | 172 + .../ERC721/extensions/ERC721Pausable.sol | 37 + .../token/ERC721/extensions/ERC721Royalty.sol | 27 + .../ERC721/extensions/ERC721URIStorage.sol | 61 + .../token/ERC721/extensions/ERC721Votes.sol | 47 + .../token/ERC721/extensions/ERC721Wrapper.sol | 102 + .../ERC721/extensions/IERC721Enumerable.sol | 29 + .../ERC721/extensions/IERC721Metadata.sol | 27 + .../token/ERC721/utils/ERC721Holder.sol | 24 + .../contracts/token/common/ERC2981.sol | 137 + .../contracts/token/common/README.adoc | 10 + .../contracts/utils/Address.sol | 159 + .../contracts/utils/Arrays.sol | 127 + .../contracts/utils/Base64.sol | 90 + .../contracts/utils/Context.sol | 24 + .../contracts/utils/Create2.sol | 96 + .../contracts/utils/Multicall.sol | 23 + .../contracts/utils/Nonces.sol | 46 + .../contracts/utils/Pausable.sol | 119 + .../contracts/utils/README.adoc | 88 + .../contracts/utils/ReentrancyGuard.sol | 84 + .../contracts/utils/ShortStrings.sol | 123 + .../contracts/utils/StorageSlot.sol | 135 + .../contracts/utils/Strings.sol | 94 + .../contracts/utils/cryptography/ECDSA.sol | 174 + .../contracts/utils/cryptography/EIP712.sol | 160 + .../utils/cryptography/MerkleProof.sol | 232 + .../utils/cryptography/MessageHashUtils.sol | 86 + .../utils/cryptography/SignatureChecker.sol | 48 + .../contracts/utils/introspection/ERC165.sol | 27 + .../utils/introspection/ERC165Checker.sol | 124 + .../contracts/utils/introspection/IERC165.sol | 25 + .../contracts/utils/math/Math.sol | 415 + .../contracts/utils/math/SafeCast.sol | 1153 + .../contracts/utils/math/SignedMath.sol | 43 + .../contracts/utils/structs/BitMaps.sol | 60 + .../contracts/utils/structs/Checkpoints.sol | 603 + .../utils/structs/DoubleEndedQueue.sol | 169 + .../contracts/utils/structs/EnumerableMap.sol | 533 + .../contracts/utils/structs/EnumerableSet.sol | 378 + .../contracts/utils/types/Time.sol | 130 + .../vendor/compound/ICompoundTimelock.sol | 86 + .../contracts/vendor/compound/LICENSE | 11 + .../foundry.toml | 10 + .../hardhat.config.js | 131 + .../hardhat/env-artifacts.js | 24 + .../hardhat/env-contract.js | 25 + .../hardhat/ignore-unreachable-warnings.js | 45 + .../hardhat/skip-foundry-tests.js | 6 + .../hardhat/task-test-get-files.js | 25 + .../lib/erc4626-tests/ERC4626.prop.sol | 404 + .../lib/erc4626-tests/ERC4626.test.sol | 349 + .../lib/erc4626-tests/LICENSE | 661 + .../lib/erc4626-tests/README.md | 116 + .../lib/forge-std/.github/workflows/ci.yml | 92 + .../lib/forge-std/.gitignore | 4 + .../lib/forge-std/.gitmodules | 3 + .../lib/forge-std/LICENSE-APACHE | 203 + .../lib/forge-std/LICENSE-MIT | 25 + .../lib/forge-std/README.md | 250 + .../lib/forge-std/foundry.toml | 21 + .../lib/forge-std/lib/ds-test/.gitignore | 3 + .../lib/forge-std/lib/ds-test/LICENSE | 674 + .../lib/forge-std/lib/ds-test/Makefile | 14 + .../lib/forge-std/lib/ds-test/default.nix | 4 + .../lib/forge-std/lib/ds-test/demo/demo.sol | 222 + .../lib/forge-std/lib/ds-test/package.json | 15 + .../lib/forge-std/lib/ds-test/src/test.sol | 469 + .../lib/forge-std/package.json | 16 + .../lib/forge-std/src/Base.sol | 31 + .../lib/forge-std/src/Script.sol | 26 + .../lib/forge-std/src/StdAssertions.sol | 209 + .../lib/forge-std/src/StdChains.sol | 189 + .../lib/forge-std/src/StdCheats.sol | 565 + .../lib/forge-std/src/StdError.sol | 15 + .../lib/forge-std/src/StdJson.sol | 179 + .../lib/forge-std/src/StdMath.sol | 43 + .../lib/forge-std/src/StdStorage.sol | 327 + .../lib/forge-std/src/StdUtils.sol | 123 + .../lib/forge-std/src/Test.sol | 28 + .../lib/forge-std/src/Vm.sol | 385 + .../lib/forge-std/src/console.sol | 1533 + .../lib/forge-std/src/console2.sol | 1546 + .../lib/forge-std/src/interfaces/IERC1155.sol | 105 + .../lib/forge-std/src/interfaces/IERC165.sol | 12 + .../lib/forge-std/src/interfaces/IERC20.sol | 43 + .../lib/forge-std/src/interfaces/IERC4626.sol | 190 + .../lib/forge-std/src/interfaces/IERC721.sol | 164 + .../lib/forge-std/test/StdAssertions.t.sol | 587 + .../lib/forge-std/test/StdChains.t.sol | 123 + .../lib/forge-std/test/StdCheats.t.sol | 305 + .../lib/forge-std/test/StdError.t.sol | 118 + .../lib/forge-std/test/StdMath.t.sol | 197 + .../lib/forge-std/test/StdStorage.t.sol | 283 + .../lib/forge-std/test/StdUtils.t.sol | 191 + .../test/compilation/CompilationScript.sol | 10 + .../compilation/CompilationScriptBase.sol | 10 + .../test/compilation/CompilationTest.sol | 10 + .../test/compilation/CompilationTestBase.sol | 10 + .../test/fixtures/broadcast.log.json | 187 + lib/openzeppelin-contracts-v5.0.0/logo.svg | 15 + .../netlify.toml | 3 + .../package-lock.json | 16544 +++++++++ .../package.json | 96 + .../remappings.txt | 1 + .../renovate.json | 4 + .../requirements.txt | 1 + .../scripts/checks/compare-layout.js | 20 + .../scripts/checks/compareGasReports.js | 243 + .../scripts/checks/extract-layout.js | 38 + .../scripts/checks/generation.sh | 6 + .../scripts/checks/inheritance-ordering.js | 54 + .../scripts/gen-nav.js | 41 + .../scripts/generate/format-lines.js | 16 + .../scripts/generate/run.js | 49 + .../scripts/generate/templates/Checkpoints.js | 247 + .../generate/templates/Checkpoints.opts.js | 17 + .../generate/templates/Checkpoints.t.js | 146 + .../generate/templates/EnumerableMap.js | 283 + .../generate/templates/EnumerableSet.js | 250 + .../scripts/generate/templates/SafeCast.js | 126 + .../scripts/generate/templates/StorageSlot.js | 78 + .../scripts/generate/templates/conversion.js | 30 + .../scripts/git-user-config.sh | 6 + .../scripts/helpers.js | 37 + .../scripts/prepack.sh | 23 + .../scripts/prepare-docs.sh | 26 + .../scripts/release/format-changelog.js | 33 + .../scripts/release/synchronize-versions.js | 15 + .../scripts/release/update-comment.js | 34 + .../scripts/release/version.sh | 11 + .../release/workflow/exit-prerelease.sh | 8 + .../release/workflow/github-release.js | 48 + .../release/workflow/integrity-check.sh | 20 + .../scripts/release/workflow/pack.sh | 26 + .../scripts/release/workflow/publish.sh | 26 + .../scripts/release/workflow/rerun.js | 7 + .../workflow/set-changesets-pr-title.js | 17 + .../scripts/release/workflow/start.sh | 35 + .../scripts/release/workflow/state.js | 112 + .../scripts/remove-ignored-artifacts.js | 45 + .../scripts/solhint-custom/index.js | 84 + .../scripts/solhint-custom/package.json | 5 + .../scripts/update-docs-branch.js | 65 + .../scripts/upgradeable/README.md | 21 + .../scripts/upgradeable/patch-apply.sh | 19 + .../scripts/upgradeable/patch-save.sh | 18 + .../scripts/upgradeable/transpile-onto.sh | 54 + .../scripts/upgradeable/transpile.sh | 47 + .../scripts/upgradeable/upgradeable.patch | 360 + .../slither.config.json | 5 + .../solhint.config.js | 20 + .../test/TESTING.md | 3 + .../test/access/AccessControl.behavior.js | 909 + .../test/access/AccessControl.test.js | 12 + .../test/access/Ownable.test.js | 72 + .../test/access/Ownable2Step.test.js | 70 + .../AccessControlDefaultAdminRules.test.js | 26 + .../AccessControlEnumerable.test.js | 17 + .../test/access/manager/AccessManaged.test.js | 142 + .../access/manager/AccessManager.behavior.js | 711 + .../test/access/manager/AccessManager.test.js | 2683 ++ .../access/manager/AuthorityUtils.test.js | 91 + .../test/finance/VestingWallet.behavior.js | 59 + .../test/finance/VestingWallet.test.js | 69 + .../test/governance/Governor.t.sol | 55 + .../test/governance/Governor.test.js | 1024 + .../governance/TimelockController.test.js | 1286 + .../extensions/GovernorERC721.test.js | 116 + .../GovernorPreventLateQuorum.test.js | 195 + .../extensions/GovernorStorage.test.js | 150 + .../extensions/GovernorTimelockAccess.test.js | 777 + .../GovernorTimelockCompound.test.js | 441 + .../GovernorTimelockControl.test.js | 515 + .../GovernorVotesQuorumFraction.test.js | 167 + .../extensions/GovernorWithParams.test.js | 277 + .../test/governance/utils/EIP6372.behavior.js | 23 + .../test/governance/utils/Votes.behavior.js | 360 + .../test/governance/utils/Votes.test.js | 92 + .../test/helpers/access-manager.js | 69 + .../test/helpers/account.js | 14 + .../test/helpers/chainid.js | 10 + .../test/helpers/constants.js | 7 + .../test/helpers/create.js | 22 + .../test/helpers/customError.js | 43 + .../test/helpers/eip712.js | 67 + .../test/helpers/enums.js | 11 + .../test/helpers/erc1967.js | 43 + .../test/helpers/governance.js | 253 + .../test/helpers/iterate.js | 16 + .../test/helpers/math.js | 11 + .../test/helpers/methods.js | 5 + .../test/helpers/sign.js | 63 + .../test/helpers/time.js | 17 + .../test/helpers/txpool.js | 38 + .../test/metatx/ERC2771Context.test.js | 134 + .../test/metatx/ERC2771Forwarder.t.sol | 165 + .../test/metatx/ERC2771Forwarder.test.js | 541 + .../test/proxy/Clones.behaviour.js | 136 + .../test/proxy/Clones.test.js | 62 + .../test/proxy/ERC1967/ERC1967Proxy.test.js | 12 + .../test/proxy/ERC1967/ERC1967Utils.test.js | 172 + .../test/proxy/Proxy.behaviour.js | 182 + .../test/proxy/beacon/BeaconProxy.test.js | 152 + .../proxy/beacon/UpgradeableBeacon.test.js | 54 + .../test/proxy/transparent/ProxyAdmin.test.js | 103 + .../TransparentUpgradeableProxy.behaviour.js | 413 + .../TransparentUpgradeableProxy.test.js | 24 + .../test/proxy/utils/Initializable.test.js | 220 + .../test/proxy/utils/UUPSUpgradeable.test.js | 131 + .../test/token/ERC1155/ERC1155.behavior.js | 905 + .../test/token/ERC1155/ERC1155.test.js | 252 + .../extensions/ERC1155Burnable.test.js | 71 + .../extensions/ERC1155Pausable.test.js | 113 + .../ERC1155/extensions/ERC1155Supply.test.js | 116 + .../extensions/ERC1155URIStorage.test.js | 66 + .../token/ERC1155/utils/ERC1155Holder.test.js | 64 + .../test/token/ERC20/ERC20.behavior.js | 340 + .../test/token/ERC20/ERC20.test.js | 202 + .../extensions/ERC20Burnable.behavior.js | 116 + .../ERC20/extensions/ERC20Burnable.test.js | 20 + .../ERC20/extensions/ERC20Capped.behavior.js | 31 + .../ERC20/extensions/ERC20Capped.test.js | 24 + .../ERC20/extensions/ERC20FlashMint.test.js | 210 + .../ERC20/extensions/ERC20Pausable.test.js | 136 + .../ERC20/extensions/ERC20Permit.test.js | 118 + .../token/ERC20/extensions/ERC20Votes.test.js | 593 + .../ERC20/extensions/ERC20Wrapper.test.js | 211 + .../test/token/ERC20/extensions/ERC4626.t.sol | 41 + .../token/ERC20/extensions/ERC4626.test.js | 1109 + .../test/token/ERC20/utils/SafeERC20.test.js | 240 + .../test/token/ERC721/ERC721.behavior.js | 978 + .../test/token/ERC721/ERC721.test.js | 15 + .../token/ERC721/ERC721Enumerable.test.js | 20 + .../ERC721/extensions/ERC721Burnable.test.js | 82 + .../ERC721/extensions/ERC721Consecutive.t.sol | 181 + .../extensions/ERC721Consecutive.test.js | 221 + .../ERC721/extensions/ERC721Pausable.test.js | 90 + .../ERC721/extensions/ERC721Royalty.test.js | 47 + .../extensions/ERC721URIStorage.test.js | 114 + .../ERC721/extensions/ERC721Votes.test.js | 183 + .../ERC721/extensions/ERC721Wrapper.test.js | 289 + .../token/ERC721/utils/ERC721Holder.test.js | 22 + .../test/token/common/ERC2981.behavior.js | 169 + .../test/utils/Address.test.js | 340 + .../test/utils/Arrays.test.js | 123 + .../test/utils/Base64.test.js | 33 + .../test/utils/Context.behavior.js | 42 + .../test/utils/Context.test.js | 17 + .../test/utils/Create2.test.js | 102 + .../test/utils/Multicall.test.js | 69 + .../test/utils/Nonces.test.js | 71 + .../test/utils/Pausable.test.js | 86 + .../test/utils/ReentrancyGuard.test.js | 44 + .../test/utils/ShortStrings.t.sol | 55 + .../test/utils/ShortStrings.test.js | 55 + .../test/utils/StorageSlot.test.js | 210 + .../test/utils/Strings.test.js | 153 + .../test/utils/cryptography/ECDSA.test.js | 245 + .../test/utils/cryptography/EIP712.test.js | 111 + .../utils/cryptography/MerkleProof.test.js | 207 + .../cryptography/MessageHashUtils.test.js | 55 + .../cryptography/SignatureChecker.test.js | 87 + .../test/utils/introspection/ERC165.test.js | 11 + .../utils/introspection/ERC165Checker.test.js | 300 + .../SupportsInterface.behavior.js | 144 + .../test/utils/math/Math.t.sol | 216 + .../test/utils/math/Math.test.js | 469 + .../test/utils/math/SafeCast.test.js | 161 + .../test/utils/math/SignedMath.test.js | 95 + .../test/utils/structs/BitMap.test.js | 145 + .../test/utils/structs/Checkpoints.t.sol | 332 + .../test/utils/structs/Checkpoints.test.js | 158 + .../utils/structs/DoubleEndedQueue.test.js | 99 + .../utils/structs/EnumerableMap.behavior.js | 178 + .../test/utils/structs/EnumerableMap.test.js | 149 + .../utils/structs/EnumerableSet.behavior.js | 129 + .../test/utils/structs/EnumerableSet.test.js | 79 + .../test/utils/types/Time.test.js | 140 + .../.changeset/config.json | 12 + lib/openzeppelin-contracts/.codecov.yml | 12 + lib/openzeppelin-contracts/.editorconfig | 21 + lib/openzeppelin-contracts/.eslintrc | 20 + .../.github/ISSUE_TEMPLATE/bug_report.md | 21 + .../.github/ISSUE_TEMPLATE/config.yml | 4 + .../.github/ISSUE_TEMPLATE/feature_request.md | 14 + .../.github/PULL_REQUEST_TEMPLATE.md | 20 + .../.github/actions/gas-compare/action.yml | 49 + .../.github/actions/setup/action.yml | 21 + .../.github/actions/storage-layout/action.yml | 55 + .../.github/workflows/actionlint.yml | 18 + .../.github/workflows/changeset.yml | 28 + .../.github/workflows/checks.yml | 118 + .../.github/workflows/docs.yml | 19 + .../.github/workflows/formal-verification.yml | 68 + .../.github/workflows/release-cycle.yml | 214 + .../.github/workflows/upgradeable.yml | 34 + lib/openzeppelin-contracts/.gitignore | 72 + lib/openzeppelin-contracts/.gitmodules | 7 + lib/openzeppelin-contracts/.mocharc.js | 4 + lib/openzeppelin-contracts/.prettierrc | 15 + lib/openzeppelin-contracts/.solcover.js | 13 + lib/openzeppelin-contracts/CHANGELOG.md | 972 + lib/openzeppelin-contracts/CODE_OF_CONDUCT.md | 73 + lib/openzeppelin-contracts/CONTRIBUTING.md | 36 + lib/openzeppelin-contracts/GUIDELINES.md | 148 + lib/openzeppelin-contracts/LICENSE | 22 + lib/openzeppelin-contracts/README.md | 107 + lib/openzeppelin-contracts/RELEASING.md | 45 + lib/openzeppelin-contracts/SECURITY.md | 42 + lib/openzeppelin-contracts/audits/2017-03.md | 292 + lib/openzeppelin-contracts/audits/2018-10.pdf | Bin 0 -> 1000527 bytes .../audits/2022-10-Checkpoints.pdf | Bin 0 -> 155606 bytes .../audits/2022-10-ERC4626.pdf | Bin 0 -> 204184 bytes .../audits/2023-05-v4.9.pdf | Bin 0 -> 485395 bytes .../audits/2023-10-v5.0.pdf | Bin 0 -> 910284 bytes lib/openzeppelin-contracts/audits/README.md | 17 + lib/openzeppelin-contracts/certora/.gitignore | 1 + lib/openzeppelin-contracts/certora/Makefile | 54 + lib/openzeppelin-contracts/certora/README.md | 60 + .../access_manager_AccessManager.sol.patch | 97 + .../AccessControlDefaultAdminRulesHarness.sol | 46 + .../harnesses/AccessControlHarness.sol | 6 + .../harnesses/DoubleEndedQueueHarness.sol | 58 + .../harnesses/ERC20FlashMintHarness.sol | 36 + .../certora/harnesses/ERC20PermitHarness.sol | 16 + .../certora/harnesses/ERC20WrapperHarness.sol | 34 + .../harnesses/ERC3156FlashBorrowerHarness.sol | 13 + .../certora/harnesses/ERC721Harness.sol | 33 + .../harnesses/ERC721ReceiverHarness.sol | 11 + .../harnesses/EnumerableMapHarness.sol | 55 + .../harnesses/EnumerableSetHarness.sol | 35 + .../harnesses/InitializableHarness.sol | 23 + .../certora/harnesses/Ownable2StepHarness.sol | 10 + .../certora/harnesses/OwnableHarness.sol | 10 + .../certora/harnesses/PausableHarness.sol | 18 + .../harnesses/TimelockControllerHarness.sol | 13 + .../certora/reports/2021-10.pdf | Bin 0 -> 92882 bytes .../certora/reports/2022-03.pdf | Bin 0 -> 199401 bytes .../certora/reports/2022-05.pdf | Bin 0 -> 132223 bytes lib/openzeppelin-contracts/certora/run.js | 160 + lib/openzeppelin-contracts/certora/specs.json | 86 + .../certora/specs/AccessControl.spec | 119 + .../specs/AccessControlDefaultAdminRules.spec | 464 + .../certora/specs/DoubleEndedQueue.spec | 300 + .../certora/specs/ERC20.spec | 352 + .../certora/specs/ERC20FlashMint.spec | 55 + .../certora/specs/ERC20Wrapper.spec | 198 + .../certora/specs/ERC721.spec | 679 + .../certora/specs/EnumerableMap.spec | 333 + .../certora/specs/EnumerableSet.spec | 246 + .../certora/specs/Initializable.spec | 165 + .../certora/specs/Ownable.spec | 77 + .../certora/specs/Ownable2Step.spec | 108 + .../certora/specs/Pausable.spec | 96 + .../certora/specs/TimelockController.spec | 274 + .../certora/specs/helpers/helpers.spec | 7 + .../certora/specs/methods/IAccessControl.spec | 8 + .../IAccessControlDefaultAdminRules.spec | 36 + .../certora/specs/methods/IERC20.spec | 11 + .../certora/specs/methods/IERC2612.spec | 5 + .../specs/methods/IERC3156FlashBorrower.spec | 3 + .../specs/methods/IERC3156FlashLender.spec | 5 + .../certora/specs/methods/IERC5313.spec | 3 + .../certora/specs/methods/IERC721.spec | 17 + .../specs/methods/IERC721Receiver.spec | 3 + .../certora/specs/methods/IOwnable.spec | 5 + .../certora/specs/methods/IOwnable2Step.spec | 7 + .../contracts/access/AccessControl.sol | 209 + .../contracts/access/IAccessControl.sol | 98 + .../contracts/access/Ownable.sol | 100 + .../contracts/access/Ownable2Step.sol | 59 + .../contracts/access/README.adoc | 43 + .../AccessControlDefaultAdminRules.sol | 396 + .../extensions/AccessControlEnumerable.sol | 70 + .../IAccessControlDefaultAdminRules.sol | 192 + .../extensions/IAccessControlEnumerable.sol | 31 + .../access/manager/AccessManaged.sol | 113 + .../access/manager/AccessManager.sol | 730 + .../access/manager/AuthorityUtils.sol | 32 + .../access/manager/IAccessManaged.sol | 32 + .../access/manager/IAccessManager.sol | 392 + .../contracts/access/manager/IAuthority.sol | 14 + .../contracts/finance/README.adoc | 14 + .../contracts/finance/VestingWallet.sol | 154 + .../contracts/governance/Governor.sol | 850 + .../contracts/governance/IGovernor.sol | 427 + .../contracts/governance/README.adoc | 167 + .../governance/TimelockController.sol | 472 + .../extensions/GovernorCountingSimple.sol | 100 + .../extensions/GovernorPreventLateQuorum.sol | 102 + .../extensions/GovernorSettings.sol | 112 + .../governance/extensions/GovernorStorage.sol | 115 + .../extensions/GovernorTimelockAccess.sol | 346 + .../extensions/GovernorTimelockCompound.sol | 167 + .../extensions/GovernorTimelockControl.sol | 173 + .../governance/extensions/GovernorVotes.sol | 64 + .../GovernorVotesQuorumFraction.sol | 110 + .../contracts/governance/utils/IVotes.sol | 59 + .../contracts/governance/utils/Votes.sol | 251 + .../contracts/interfaces/IERC1155.sol | 6 + .../interfaces/IERC1155MetadataURI.sol | 6 + .../contracts/interfaces/IERC1155Receiver.sol | 6 + .../contracts/interfaces/IERC1271.sol | 17 + .../contracts/interfaces/IERC1363.sol | 80 + .../contracts/interfaces/IERC1363Receiver.sol | 35 + .../contracts/interfaces/IERC1363Spender.sol | 29 + .../contracts/interfaces/IERC165.sol | 6 + .../interfaces/IERC1820Implementer.sol | 20 + .../contracts/interfaces/IERC1820Registry.sol | 112 + .../contracts/interfaces/IERC1967.sol | 24 + .../contracts/interfaces/IERC20.sol | 6 + .../contracts/interfaces/IERC20Metadata.sol | 6 + .../contracts/interfaces/IERC2309.sol | 19 + .../contracts/interfaces/IERC2612.sol | 8 + .../contracts/interfaces/IERC2981.sol | 23 + .../contracts/interfaces/IERC3156.sol | 7 + .../interfaces/IERC3156FlashBorrower.sol | 27 + .../interfaces/IERC3156FlashLender.sol | 41 + .../contracts/interfaces/IERC4626.sol | 230 + .../contracts/interfaces/IERC4906.sol | 20 + .../contracts/interfaces/IERC5267.sol | 28 + .../contracts/interfaces/IERC5313.sol | 16 + .../contracts/interfaces/IERC5805.sol | 9 + .../contracts/interfaces/IERC6372.sol | 17 + .../contracts/interfaces/IERC721.sol | 6 + .../interfaces/IERC721Enumerable.sol | 6 + .../contracts/interfaces/IERC721Metadata.sol | 6 + .../contracts/interfaces/IERC721Receiver.sol | 6 + .../contracts/interfaces/IERC777.sol | 200 + .../contracts/interfaces/IERC777Recipient.sol | 35 + .../contracts/interfaces/IERC777Sender.sol | 35 + .../contracts/interfaces/README.adoc | 82 + .../contracts/interfaces/draft-IERC1822.sol | 20 + .../contracts/interfaces/draft-IERC6093.sol | 161 + .../contracts/metatx/ERC2771Context.sol | 75 + .../contracts/metatx/ERC2771Forwarder.sol | 370 + .../contracts/metatx/README.adoc | 12 + .../contracts/mocks/AccessManagedTarget.sol | 34 + .../contracts/mocks/ArraysMock.sol | 51 + .../contracts/mocks/AuthorityMock.sol | 69 + .../contracts/mocks/CallReceiverMock.sol | 73 + .../contracts/mocks/ContextMock.sol | 35 + .../contracts/mocks/DummyImplementation.sol | 65 + .../contracts/mocks/EIP712Verifier.sol | 16 + .../contracts/mocks/ERC1271WalletMock.sol | 24 + .../ERC165/ERC165InterfacesSupported.sol | 58 + .../mocks/ERC165/ERC165MaliciousData.sol | 12 + .../mocks/ERC165/ERC165MissingData.sol | 7 + .../mocks/ERC165/ERC165NotSupported.sol | 5 + .../mocks/ERC165/ERC165ReturnBomb.sol | 18 + .../contracts/mocks/ERC2771ContextMock.sol | 23 + .../mocks/ERC3156FlashBorrowerMock.sol | 53 + .../contracts/mocks/EtherReceiverMock.sol | 17 + .../contracts/mocks/InitializableMock.sol | 130 + .../contracts/mocks/MulticallTest.sol | 23 + .../MultipleInheritanceInitializableMocks.sol | 131 + .../contracts/mocks/PausableMock.sol | 31 + .../contracts/mocks/ReentrancyAttack.sol | 12 + .../contracts/mocks/ReentrancyMock.sol | 50 + .../mocks/RegressionImplementation.sol | 61 + .../SingleInheritanceInitializableMocks.sol | 49 + .../contracts/mocks/Stateless.sol | 36 + .../contracts/mocks/StorageSlotMock.sol | 77 + .../contracts/mocks/TimelockReentrant.sol | 26 + .../contracts/mocks/UpgradeableBeaconMock.sol | 27 + .../contracts/mocks/VotesMock.sol | 42 + .../contracts/mocks/compound/CompTimelock.sol | 174 + .../mocks/governance/GovernorMock.sol | 14 + .../GovernorPreventLateQuorumMock.sol | 46 + .../mocks/governance/GovernorStorageMock.sol | 79 + .../governance/GovernorTimelockAccessMock.sol | 70 + .../GovernorTimelockCompoundMock.sol | 69 + .../GovernorTimelockControlMock.sol | 69 + .../mocks/governance/GovernorVoteMock.sol | 20 + .../governance/GovernorWithParamsMock.sol | 51 + .../contracts/mocks/proxy/BadBeacon.sol | 11 + .../mocks/proxy/ClashingImplementation.sol | 19 + .../mocks/proxy/UUPSUpgradeableMock.sol | 35 + .../mocks/token/ERC1155ReceiverMock.sol | 74 + .../mocks/token/ERC20ApprovalMock.sol | 10 + .../mocks/token/ERC20DecimalsMock.sol | 17 + .../mocks/token/ERC20ExcessDecimalsMock.sol | 9 + .../mocks/token/ERC20FlashMintMock.sol | 26 + .../mocks/token/ERC20ForceApproveMock.sol | 13 + .../contracts/mocks/token/ERC20Mock.sol | 16 + .../mocks/token/ERC20MulticallMock.sol | 8 + .../mocks/token/ERC20NoReturnMock.sol | 28 + .../contracts/mocks/token/ERC20Reentrant.sol | 39 + .../mocks/token/ERC20ReturnFalseMock.sol | 19 + .../mocks/token/ERC20VotesLegacyMock.sol | 253 + .../mocks/token/ERC4626LimitsMock.sol | 23 + .../contracts/mocks/token/ERC4626Mock.sol | 17 + .../mocks/token/ERC4626OffsetMock.sol | 17 + .../contracts/mocks/token/ERC4646FeesMock.sol | 40 + .../token/ERC721ConsecutiveEnumerableMock.sol | 42 + .../mocks/token/ERC721ConsecutiveMock.sol | 61 + .../mocks/token/ERC721ReceiverMock.sol | 47 + .../mocks/token/ERC721URIStorageMock.sol | 17 + .../contracts/mocks/token/VotesTimestamp.sol | 29 + .../contracts/package.json | 32 + .../contracts/proxy/Clones.sol | 95 + .../contracts/proxy/ERC1967/ERC1967Proxy.sol | 40 + .../contracts/proxy/ERC1967/ERC1967Utils.sol | 193 + .../contracts/proxy/Proxy.sol | 69 + .../contracts/proxy/README.adoc | 87 + .../contracts/proxy/beacon/BeaconProxy.sol | 57 + .../contracts/proxy/beacon/IBeacon.sol | 16 + .../proxy/beacon/UpgradeableBeacon.sol | 70 + .../proxy/transparent/ProxyAdmin.sol | 45 + .../TransparentUpgradeableProxy.sol | 116 + .../contracts/proxy/utils/Initializable.sol | 228 + .../contracts/proxy/utils/UUPSUpgradeable.sol | 147 + .../contracts/token/ERC1155/ERC1155.sol | 468 + .../contracts/token/ERC1155/IERC1155.sol | 128 + .../token/ERC1155/IERC1155Receiver.sol | 59 + .../contracts/token/ERC1155/README.adoc | 41 + .../ERC1155/extensions/ERC1155Burnable.sol | 28 + .../ERC1155/extensions/ERC1155Pausable.sol | 38 + .../ERC1155/extensions/ERC1155Supply.sol | 87 + .../ERC1155/extensions/ERC1155URIStorage.sol | 61 + .../extensions/IERC1155MetadataURI.sol | 20 + .../token/ERC1155/utils/ERC1155Holder.sol | 42 + .../contracts/token/ERC20/ERC20.sol | 316 + .../contracts/token/ERC20/IERC20.sol | 79 + .../contracts/token/ERC20/README.adoc | 67 + .../token/ERC20/extensions/ERC20Burnable.sol | 39 + .../token/ERC20/extensions/ERC20Capped.sol | 56 + .../token/ERC20/extensions/ERC20FlashMint.sol | 134 + .../token/ERC20/extensions/ERC20Pausable.sol | 33 + .../token/ERC20/extensions/ERC20Permit.sol | 83 + .../token/ERC20/extensions/ERC20Votes.sol | 83 + .../token/ERC20/extensions/ERC20Wrapper.sol | 86 + .../token/ERC20/extensions/ERC4626.sol | 286 + .../token/ERC20/extensions/IERC20Metadata.sol | 26 + .../token/ERC20/extensions/IERC20Permit.sol | 90 + .../contracts/token/ERC20/utils/SafeERC20.sol | 118 + .../contracts/token/ERC721/ERC721.sol | 483 + .../contracts/token/ERC721/IERC721.sol | 135 + .../token/ERC721/IERC721Receiver.sol | 28 + .../contracts/token/ERC721/README.adoc | 67 + .../ERC721/extensions/ERC721Burnable.sol | 26 + .../ERC721/extensions/ERC721Consecutive.sol | 176 + .../ERC721/extensions/ERC721Enumerable.sol | 172 + .../ERC721/extensions/ERC721Pausable.sol | 37 + .../token/ERC721/extensions/ERC721Royalty.sol | 27 + .../ERC721/extensions/ERC721URIStorage.sol | 61 + .../token/ERC721/extensions/ERC721Votes.sol | 47 + .../token/ERC721/extensions/ERC721Wrapper.sol | 102 + .../ERC721/extensions/IERC721Enumerable.sol | 29 + .../ERC721/extensions/IERC721Metadata.sol | 27 + .../token/ERC721/utils/ERC721Holder.sol | 24 + .../contracts/token/common/ERC2981.sol | 137 + .../contracts/token/common/README.adoc | 10 + .../contracts/utils/Address.sol | 159 + .../contracts/utils/Arrays.sol | 127 + .../contracts/utils/Base64.sol | 90 + .../contracts/utils/Context.sol | 24 + .../contracts/utils/Create2.sol | 96 + .../contracts/utils/Multicall.sol | 23 + .../contracts/utils/Nonces.sol | 46 + .../contracts/utils/Pausable.sol | 119 + .../contracts/utils/README.adoc | 88 + .../contracts/utils/ReentrancyGuard.sol | 84 + .../contracts/utils/ShortStrings.sol | 123 + .../contracts/utils/StorageSlot.sol | 135 + .../contracts/utils/Strings.sol | 94 + .../contracts/utils/cryptography/ECDSA.sol | 174 + .../contracts/utils/cryptography/EIP712.sol | 160 + .../utils/cryptography/MerkleProof.sol | 232 + .../utils/cryptography/MessageHashUtils.sol | 86 + .../utils/cryptography/SignatureChecker.sol | 48 + .../contracts/utils/introspection/ERC165.sol | 27 + .../utils/introspection/ERC165Checker.sol | 124 + .../contracts/utils/introspection/IERC165.sol | 25 + .../contracts/utils/math/Math.sol | 415 + .../contracts/utils/math/SafeCast.sol | 1153 + .../contracts/utils/math/SignedMath.sol | 43 + .../contracts/utils/structs/BitMaps.sol | 60 + .../contracts/utils/structs/Checkpoints.sol | 603 + .../utils/structs/DoubleEndedQueue.sol | 169 + .../contracts/utils/structs/EnumerableMap.sol | 533 + .../contracts/utils/structs/EnumerableSet.sol | 378 + .../contracts/utils/types/Time.sol | 130 + .../vendor/compound/ICompoundTimelock.sol | 86 + .../contracts/vendor/compound/LICENSE | 11 + lib/openzeppelin-contracts/foundry.toml | 10 + lib/openzeppelin-contracts/hardhat.config.js | 131 + .../hardhat/env-artifacts.js | 24 + .../hardhat/env-contract.js | 25 + .../hardhat/ignore-unreachable-warnings.js | 45 + .../hardhat/skip-foundry-tests.js | 6 + .../hardhat/task-test-get-files.js | 25 + .../lib/erc4626-tests/ERC4626.prop.sol | 404 + .../lib/erc4626-tests/ERC4626.test.sol | 349 + .../lib/erc4626-tests/LICENSE | 661 + .../lib/erc4626-tests/README.md | 116 + .../lib/forge-std/.github/workflows/ci.yml | 92 + .../lib/forge-std/.gitignore | 4 + .../lib/forge-std/.gitmodules | 3 + .../lib/forge-std/LICENSE-APACHE | 203 + .../lib/forge-std/LICENSE-MIT | 25 + .../lib/forge-std/README.md | 250 + .../lib/forge-std/foundry.toml | 21 + .../lib/forge-std/lib/ds-test/.gitignore | 3 + .../lib/forge-std/lib/ds-test/LICENSE | 674 + .../lib/forge-std/lib/ds-test/Makefile | 14 + .../lib/forge-std/lib/ds-test/default.nix | 4 + .../lib/forge-std/lib/ds-test/demo/demo.sol | 222 + .../lib/forge-std/lib/ds-test/package.json | 15 + .../lib/forge-std/lib/ds-test/src/test.sol | 469 + .../lib/forge-std/package.json | 16 + .../lib/forge-std/src/Base.sol | 31 + .../lib/forge-std/src/Script.sol | 26 + .../lib/forge-std/src/StdAssertions.sol | 209 + .../lib/forge-std/src/StdChains.sol | 189 + .../lib/forge-std/src/StdCheats.sol | 565 + .../lib/forge-std/src/StdError.sol | 15 + .../lib/forge-std/src/StdJson.sol | 179 + .../lib/forge-std/src/StdMath.sol | 43 + .../lib/forge-std/src/StdStorage.sol | 327 + .../lib/forge-std/src/StdUtils.sol | 123 + .../lib/forge-std/src/Test.sol | 28 + .../lib/forge-std/src/Vm.sol | 385 + .../lib/forge-std/src/console.sol | 1533 + .../lib/forge-std/src/console2.sol | 1546 + .../lib/forge-std/src/interfaces/IERC1155.sol | 105 + .../lib/forge-std/src/interfaces/IERC165.sol | 12 + .../lib/forge-std/src/interfaces/IERC20.sol | 43 + .../lib/forge-std/src/interfaces/IERC4626.sol | 190 + .../lib/forge-std/src/interfaces/IERC721.sol | 164 + .../lib/forge-std/test/StdAssertions.t.sol | 587 + .../lib/forge-std/test/StdChains.t.sol | 123 + .../lib/forge-std/test/StdCheats.t.sol | 305 + .../lib/forge-std/test/StdError.t.sol | 118 + .../lib/forge-std/test/StdMath.t.sol | 197 + .../lib/forge-std/test/StdStorage.t.sol | 283 + .../lib/forge-std/test/StdUtils.t.sol | 191 + .../test/compilation/CompilationScript.sol | 10 + .../compilation/CompilationScriptBase.sol | 10 + .../test/compilation/CompilationTest.sol | 10 + .../test/compilation/CompilationTestBase.sol | 10 + .../test/fixtures/broadcast.log.json | 187 + lib/openzeppelin-contracts/logo.svg | 15 + lib/openzeppelin-contracts/netlify.toml | 3 + lib/openzeppelin-contracts/package-lock.json | 16544 +++++++++ lib/openzeppelin-contracts/package.json | 96 + lib/openzeppelin-contracts/remappings.txt | 1 + lib/openzeppelin-contracts/renovate.json | 4 + lib/openzeppelin-contracts/requirements.txt | 1 + .../scripts/checks/compare-layout.js | 20 + .../scripts/checks/compareGasReports.js | 243 + .../scripts/checks/extract-layout.js | 38 + .../scripts/checks/generation.sh | 6 + .../scripts/checks/inheritance-ordering.js | 54 + lib/openzeppelin-contracts/scripts/gen-nav.js | 41 + .../scripts/generate/format-lines.js | 16 + .../scripts/generate/run.js | 49 + .../scripts/generate/templates/Checkpoints.js | 247 + .../generate/templates/Checkpoints.opts.js | 17 + .../generate/templates/Checkpoints.t.js | 146 + .../generate/templates/EnumerableMap.js | 283 + .../generate/templates/EnumerableSet.js | 250 + .../scripts/generate/templates/SafeCast.js | 126 + .../scripts/generate/templates/StorageSlot.js | 78 + .../scripts/generate/templates/conversion.js | 30 + .../scripts/git-user-config.sh | 6 + lib/openzeppelin-contracts/scripts/helpers.js | 37 + lib/openzeppelin-contracts/scripts/prepack.sh | 23 + .../scripts/prepare-docs.sh | 26 + .../scripts/release/format-changelog.js | 33 + .../scripts/release/synchronize-versions.js | 15 + .../scripts/release/update-comment.js | 34 + .../scripts/release/version.sh | 11 + .../release/workflow/exit-prerelease.sh | 8 + .../release/workflow/github-release.js | 48 + .../release/workflow/integrity-check.sh | 20 + .../scripts/release/workflow/pack.sh | 26 + .../scripts/release/workflow/publish.sh | 26 + .../scripts/release/workflow/rerun.js | 7 + .../workflow/set-changesets-pr-title.js | 17 + .../scripts/release/workflow/start.sh | 35 + .../scripts/release/workflow/state.js | 112 + .../scripts/remove-ignored-artifacts.js | 45 + .../scripts/solhint-custom/index.js | 84 + .../scripts/solhint-custom/package.json | 5 + .../scripts/update-docs-branch.js | 65 + .../scripts/upgradeable/README.md | 21 + .../scripts/upgradeable/patch-apply.sh | 19 + .../scripts/upgradeable/patch-save.sh | 18 + .../scripts/upgradeable/transpile-onto.sh | 54 + .../scripts/upgradeable/transpile.sh | 47 + .../scripts/upgradeable/upgradeable.patch | 360 + .../slither.config.json | 5 + lib/openzeppelin-contracts/solhint.config.js | 20 + lib/openzeppelin-contracts/test/TESTING.md | 3 + .../test/access/AccessControl.behavior.js | 909 + .../test/access/AccessControl.test.js | 12 + .../test/access/Ownable.test.js | 72 + .../test/access/Ownable2Step.test.js | 70 + .../AccessControlDefaultAdminRules.test.js | 26 + .../AccessControlEnumerable.test.js | 17 + .../test/access/manager/AccessManaged.test.js | 142 + .../access/manager/AccessManager.behavior.js | 711 + .../test/access/manager/AccessManager.test.js | 2683 ++ .../access/manager/AuthorityUtils.test.js | 91 + .../test/finance/VestingWallet.behavior.js | 59 + .../test/finance/VestingWallet.test.js | 69 + .../test/governance/Governor.t.sol | 55 + .../test/governance/Governor.test.js | 1024 + .../governance/TimelockController.test.js | 1286 + .../extensions/GovernorERC721.test.js | 116 + .../GovernorPreventLateQuorum.test.js | 195 + .../extensions/GovernorStorage.test.js | 150 + .../extensions/GovernorTimelockAccess.test.js | 777 + .../GovernorTimelockCompound.test.js | 441 + .../GovernorTimelockControl.test.js | 515 + .../GovernorVotesQuorumFraction.test.js | 167 + .../extensions/GovernorWithParams.test.js | 277 + .../test/governance/utils/EIP6372.behavior.js | 23 + .../test/governance/utils/Votes.behavior.js | 360 + .../test/governance/utils/Votes.test.js | 92 + .../test/helpers/access-manager.js | 69 + .../test/helpers/account.js | 14 + .../test/helpers/chainid.js | 10 + .../test/helpers/constants.js | 7 + .../test/helpers/create.js | 22 + .../test/helpers/customError.js | 43 + .../test/helpers/eip712.js | 67 + .../test/helpers/enums.js | 11 + .../test/helpers/erc1967.js | 43 + .../test/helpers/governance.js | 253 + .../test/helpers/iterate.js | 16 + .../test/helpers/math.js | 11 + .../test/helpers/methods.js | 5 + .../test/helpers/sign.js | 63 + .../test/helpers/time.js | 17 + .../test/helpers/txpool.js | 38 + .../test/metatx/ERC2771Context.test.js | 134 + .../test/metatx/ERC2771Forwarder.t.sol | 165 + .../test/metatx/ERC2771Forwarder.test.js | 541 + .../test/proxy/Clones.behaviour.js | 136 + .../test/proxy/Clones.test.js | 62 + .../test/proxy/ERC1967/ERC1967Proxy.test.js | 12 + .../test/proxy/ERC1967/ERC1967Utils.test.js | 172 + .../test/proxy/Proxy.behaviour.js | 182 + .../test/proxy/beacon/BeaconProxy.test.js | 152 + .../proxy/beacon/UpgradeableBeacon.test.js | 54 + .../test/proxy/transparent/ProxyAdmin.test.js | 103 + .../TransparentUpgradeableProxy.behaviour.js | 413 + .../TransparentUpgradeableProxy.test.js | 24 + .../test/proxy/utils/Initializable.test.js | 220 + .../test/proxy/utils/UUPSUpgradeable.test.js | 131 + .../test/token/ERC1155/ERC1155.behavior.js | 905 + .../test/token/ERC1155/ERC1155.test.js | 252 + .../extensions/ERC1155Burnable.test.js | 71 + .../extensions/ERC1155Pausable.test.js | 113 + .../ERC1155/extensions/ERC1155Supply.test.js | 116 + .../extensions/ERC1155URIStorage.test.js | 66 + .../token/ERC1155/utils/ERC1155Holder.test.js | 64 + .../test/token/ERC20/ERC20.behavior.js | 340 + .../test/token/ERC20/ERC20.test.js | 202 + .../extensions/ERC20Burnable.behavior.js | 116 + .../ERC20/extensions/ERC20Burnable.test.js | 20 + .../ERC20/extensions/ERC20Capped.behavior.js | 31 + .../ERC20/extensions/ERC20Capped.test.js | 24 + .../ERC20/extensions/ERC20FlashMint.test.js | 210 + .../ERC20/extensions/ERC20Pausable.test.js | 136 + .../ERC20/extensions/ERC20Permit.test.js | 118 + .../token/ERC20/extensions/ERC20Votes.test.js | 593 + .../ERC20/extensions/ERC20Wrapper.test.js | 211 + .../test/token/ERC20/extensions/ERC4626.t.sol | 41 + .../token/ERC20/extensions/ERC4626.test.js | 1109 + .../test/token/ERC20/utils/SafeERC20.test.js | 240 + .../test/token/ERC721/ERC721.behavior.js | 978 + .../test/token/ERC721/ERC721.test.js | 15 + .../token/ERC721/ERC721Enumerable.test.js | 20 + .../ERC721/extensions/ERC721Burnable.test.js | 82 + .../ERC721/extensions/ERC721Consecutive.t.sol | 181 + .../extensions/ERC721Consecutive.test.js | 221 + .../ERC721/extensions/ERC721Pausable.test.js | 90 + .../ERC721/extensions/ERC721Royalty.test.js | 47 + .../extensions/ERC721URIStorage.test.js | 114 + .../ERC721/extensions/ERC721Votes.test.js | 183 + .../ERC721/extensions/ERC721Wrapper.test.js | 289 + .../token/ERC721/utils/ERC721Holder.test.js | 22 + .../test/token/common/ERC2981.behavior.js | 169 + .../test/utils/Address.test.js | 340 + .../test/utils/Arrays.test.js | 123 + .../test/utils/Base64.test.js | 33 + .../test/utils/Context.behavior.js | 42 + .../test/utils/Context.test.js | 17 + .../test/utils/Create2.test.js | 102 + .../test/utils/Multicall.test.js | 69 + .../test/utils/Nonces.test.js | 71 + .../test/utils/Pausable.test.js | 86 + .../test/utils/ReentrancyGuard.test.js | 44 + .../test/utils/ShortStrings.t.sol | 55 + .../test/utils/ShortStrings.test.js | 55 + .../test/utils/StorageSlot.test.js | 210 + .../test/utils/Strings.test.js | 153 + .../test/utils/cryptography/ECDSA.test.js | 245 + .../test/utils/cryptography/EIP712.test.js | 111 + .../utils/cryptography/MerkleProof.test.js | 207 + .../cryptography/MessageHashUtils.test.js | 55 + .../cryptography/SignatureChecker.test.js | 87 + .../test/utils/introspection/ERC165.test.js | 11 + .../utils/introspection/ERC165Checker.test.js | 300 + .../SupportsInterface.behavior.js | 144 + .../test/utils/math/Math.t.sol | 216 + .../test/utils/math/Math.test.js | 469 + .../test/utils/math/SafeCast.test.js | 161 + .../test/utils/math/SignedMath.test.js | 95 + .../test/utils/structs/BitMap.test.js | 145 + .../test/utils/structs/Checkpoints.t.sol | 332 + .../test/utils/structs/Checkpoints.test.js | 158 + .../utils/structs/DoubleEndedQueue.test.js | 99 + .../utils/structs/EnumerableMap.behavior.js | 178 + .../test/utils/structs/EnumerableMap.test.js | 149 + .../utils/structs/EnumerableSet.behavior.js | 129 + .../test/utils/structs/EnumerableSet.test.js | 79 + .../test/utils/types/Time.test.js | 140 + lib/solmate/.gas-snapshot | 563 + lib/solmate/.gitattributes | 1 + lib/solmate/.github/pull_request_template.md | 13 + lib/solmate/.github/workflows/tests.yml | 29 + lib/solmate/.gitignore | 3 + lib/solmate/.gitmodules | 3 + lib/solmate/.prettierignore | 1 + lib/solmate/.prettierrc | 14 + lib/solmate/LICENSE | 661 + lib/solmate/README.md | 70 + .../audits/v6-Fixed-Point-Solutions.pdf | Bin 0 -> 170456 bytes lib/solmate/foundry.toml | 7 + lib/solmate/lib/ds-test/.gitignore | 3 + lib/solmate/lib/ds-test/LICENSE | 674 + lib/solmate/lib/ds-test/Makefile | 14 + lib/solmate/lib/ds-test/default.nix | 4 + lib/solmate/lib/ds-test/demo/demo.sol | 222 + lib/solmate/lib/ds-test/package.json | 15 + lib/solmate/lib/ds-test/src/test.sol | 469 + lib/solmate/package-lock.json | 125 + lib/solmate/package.json | 20 + lib/solmate/src/auth/Auth.sol | 64 + lib/solmate/src/auth/Owned.sol | 44 + .../auth/authorities/MultiRolesAuthority.sol | 123 + .../src/auth/authorities/RolesAuthority.sol | 108 + lib/solmate/src/mixins/ERC4626.sol | 183 + lib/solmate/src/test/Auth.t.sol | 192 + lib/solmate/src/test/Bytes32AddressLib.t.sol | 22 + lib/solmate/src/test/CREATE3.t.sol | 74 + lib/solmate/src/test/DSTestPlus.t.sol | 72 + lib/solmate/src/test/ERC1155.t.sol | 1777 + lib/solmate/src/test/ERC20.t.sol | 531 + lib/solmate/src/test/ERC4626.t.sol | 446 + lib/solmate/src/test/ERC6909.t.sol | 312 + lib/solmate/src/test/ERC721.t.sol | 727 + lib/solmate/src/test/FixedPointMathLib.t.sol | 360 + lib/solmate/src/test/LibString.t.sol | 148 + lib/solmate/src/test/MerkleProofLib.t.sol | 50 + .../src/test/MultiRolesAuthority.t.sol | 321 + lib/solmate/src/test/Owned.t.sol | 40 + lib/solmate/src/test/ReentrancyGuard.t.sol | 56 + lib/solmate/src/test/RolesAuthority.t.sol | 148 + lib/solmate/src/test/SSTORE2.t.sol | 152 + lib/solmate/src/test/SafeCastLib.t.sol | 644 + lib/solmate/src/test/SafeTransferLib.t.sol | 610 + lib/solmate/src/test/SignedWadMath.t.sol | 74 + lib/solmate/src/test/WETH.t.sol | 146 + .../src/test/utils/DSInvariantTest.sol | 16 + lib/solmate/src/test/utils/DSTestPlus.sol | 179 + lib/solmate/src/test/utils/Hevm.sol | 107 + .../src/test/utils/mocks/MockAuthChild.sol | 12 + .../src/test/utils/mocks/MockAuthority.sol | 20 + .../src/test/utils/mocks/MockERC1155.sol | 42 + .../src/test/utils/mocks/MockERC20.sol | 20 + .../src/test/utils/mocks/MockERC4626.sol | 28 + .../src/test/utils/mocks/MockERC6909.sol | 22 + .../src/test/utils/mocks/MockERC721.sol | 30 + .../src/test/utils/mocks/MockOwned.sol | 12 + .../utils/weird-tokens/MissingReturnToken.sol | 83 + .../utils/weird-tokens/ReturnsFalseToken.sol | 61 + .../weird-tokens/ReturnsGarbageToken.sol | 115 + .../weird-tokens/ReturnsTooLittleToken.sol | 70 + .../weird-tokens/ReturnsTooMuchToken.sol | 98 + .../utils/weird-tokens/ReturnsTwoToken.sol | 61 + .../utils/weird-tokens/RevertingToken.sol | 61 + lib/solmate/src/tokens/ERC1155.sol | 257 + lib/solmate/src/tokens/ERC20.sol | 206 + lib/solmate/src/tokens/ERC6909.sol | 140 + lib/solmate/src/tokens/ERC721.sol | 231 + lib/solmate/src/tokens/WETH.sol | 35 + lib/solmate/src/utils/Bytes32AddressLib.sol | 14 + lib/solmate/src/utils/CREATE3.sol | 83 + lib/solmate/src/utils/FixedPointMathLib.sol | 255 + lib/solmate/src/utils/LibString.sol | 77 + lib/solmate/src/utils/MerkleProofLib.sol | 48 + lib/solmate/src/utils/ReentrancyGuard.sol | 19 + lib/solmate/src/utils/SSTORE2.sol | 101 + lib/solmate/src/utils/SafeCastLib.sol | 193 + lib/solmate/src/utils/SafeTransferLib.sol | 128 + lib/solmate/src/utils/SignedWadMath.sol | 245 + remappings.txt | 12 + ...DeployAmphorSyntheticVaultWithPermit.s.sol | 51 + ...DeployAmphorSyntheticVaultWithPermit.s.sol | 51 + ...DeployAmphorSyntheticVaultWithPermit.s.sol | 49 + .../WBTC_DeployAmphorSyntheticVault.s.sol | 47 + .../WSTETH_DeployAmphorSyntheticVault.s.sol | 50 + script/L1/DeployZapper.s.sol | 45 + src/AmphorSyntheticVault.sol | 802 + src/AmphorSyntheticVaultWithPermit.sol | 160 + src/VaultZapper.sol | 311 + src/utils/Constants.sol | 115 + src/utils/ConstantsBSC.sol | 11 + src/utils/MockERC20.sol.bak | 8 + src/utils/PermitERC20.sol | 16 + test.txt | 1 + test/Zapper/OffChainCalls.t.sol | 63 + test/Zapper/ZapperDeposit.t.sol | 249 + test/Zapper/ZapperDepositPermit.t.sol | 141 + test/Zapper/ZapperManagement.t.sol | 142 + test/Zapper/ZapperOnlyAllowedRouter.t.sol | 97 + test/Zapper/ZapperOnlyAllowedVault.t.sol | 97 + test/Zapper/ZapperWithdraw.t.sol | 200 + test/Zapper/ZapperWithdrawPermit.sol | 209 + test/echidna.config.yaml | 5 + test/scripts/getOneInchQuote.js | 68 + test/testsRules.md | 11 + test/utils/SigUtils.sol | 53 + test/v0/BaseVault/BaseVault.t.sol | 10 + test/v0/Core/BaseProperties.t.sol | 290 + test/v0/Core/Global.t.sol | 59 + test/v0/SyntheticVault/SyntheticBase.t.sol | 97 + test/v0/SyntheticVault/SyntheticBasic.t.sol | 171 + .../SyntheticDepositAndWithdraw.t.sol | 448 + .../SyntheticVault/SyntheticEndAndStart.t.sol | 585 + .../SyntheticVault/SyntheticInflation.t.sol | 303 + .../v0/SyntheticVault/SyntheticPausable.t.sol | 172 + test/v0/SyntheticVault/SyntheticPermit.t.sol | 423 + test/v0/SyntheticVault/a16zCompliance.t.sol | 21 + test/v0/SyntheticVault/cryticCompliance.t.sol | 26 + 2741 files changed, 460949 insertions(+) create mode 100644 .github/workflows/smartContractTest.yml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 README.md create mode 100644 audits/Bailsec_final_report.pdf create mode 100644 audits/Salus_final_report.pdf create mode 100644 broadcast/DeployZapper.s.sol/1/run-1699554225.json create mode 100644 broadcast/DeployZapper.s.sol/1/run-1699554508.json create mode 100644 broadcast/DeployZapper.s.sol/1/run-1699554522.json create mode 100644 broadcast/DeployZapper.s.sol/1/run-latest.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517528.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517534.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517628.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517662.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517669.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517944.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517958.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517987.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518085.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518099.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518128.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518454.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518486.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518515.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518532.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518545.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518546.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519178.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519191.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519236.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519261.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519262.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696604696.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696604718.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696605676.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696605690.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696610570.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696610582.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612484.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612514.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612747.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612753.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612935.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612948.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696613263.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696613269.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614074.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614087.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614621.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614633.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614670.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845420.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845427.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845459.json create mode 100644 broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-latest.json create mode 100644 broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-1696689350.json create mode 100644 broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-1696689363.json create mode 100644 broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-latest.json create mode 100644 broadcast/WSTETH_DeployAmphorSyntheticVault.s.sol/1/run-1699551295.json create mode 100644 broadcast/WSTETH_DeployAmphorSyntheticVault.s.sol/1/run-latest.json create mode 100644 config.yaml create mode 100644 example.env create mode 100644 foundry.toml create mode 100644 lib/crytic/.github/ISSUE_TEMPLATE/bug_report.yaml create mode 100644 lib/crytic/.github/ISSUE_TEMPLATE/feature_request.yaml create mode 100644 lib/crytic/.github/workflows/examples.yaml create mode 100644 lib/crytic/.gitignore create mode 100644 lib/crytic/.gitmodules create mode 100644 lib/crytic/.solhint.json create mode 100644 lib/crytic/CODEOWNERS create mode 100644 lib/crytic/CONTRIBUTING.md create mode 100644 lib/crytic/LICENSE create mode 100644 lib/crytic/PROPERTIES.md create mode 100644 lib/crytic/README.md create mode 100644 lib/crytic/Trophies.md create mode 100644 lib/crytic/contracts/ERC20/external/ERC20ExternalPropertyTests.sol create mode 100644 lib/crytic/contracts/ERC20/external/ExampleToken.sol create mode 100644 lib/crytic/contracts/ERC20/external/TokenMock.sol create mode 100644 lib/crytic/contracts/ERC20/external/echidna.config.yaml create mode 100644 lib/crytic/contracts/ERC20/external/properties/ERC20ExternalBasicProperties.sol create mode 100644 lib/crytic/contracts/ERC20/external/properties/ERC20ExternalBurnableProperties.sol create mode 100644 lib/crytic/contracts/ERC20/external/properties/ERC20ExternalIncreaseAllowanceProperties.sol create mode 100644 lib/crytic/contracts/ERC20/external/properties/ERC20ExternalMintableProperties.sol create mode 100644 lib/crytic/contracts/ERC20/external/properties/ERC20ExternalPausableProperties.sol create mode 100644 lib/crytic/contracts/ERC20/external/util/ERC20ExternalTestBase.sol create mode 100644 lib/crytic/contracts/ERC20/external/util/ITokenMock.sol create mode 100644 lib/crytic/contracts/ERC20/internal/echidna.config.yaml create mode 100644 lib/crytic/contracts/ERC20/internal/properties/ERC20BasicProperties.sol create mode 100644 lib/crytic/contracts/ERC20/internal/properties/ERC20BurnableProperties.sol create mode 100644 lib/crytic/contracts/ERC20/internal/properties/ERC20IncreaseAllowanceProperties.sol create mode 100644 lib/crytic/contracts/ERC20/internal/properties/ERC20MintableProperties.sol create mode 100644 lib/crytic/contracts/ERC20/internal/properties/ERC20PausableProperties.sol create mode 100644 lib/crytic/contracts/ERC20/internal/util/ERC20TestBase.sol create mode 100644 lib/crytic/contracts/ERC4626/ERC4626PropertyTests.sol create mode 100644 lib/crytic/contracts/ERC4626/README.md create mode 100644 lib/crytic/contracts/ERC4626/properties/FunctionalAccountingProps.sol create mode 100644 lib/crytic/contracts/ERC4626/properties/MustNotRevertProps.sol create mode 100644 lib/crytic/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol create mode 100644 lib/crytic/contracts/ERC4626/properties/RoundingProps.sol create mode 100644 lib/crytic/contracts/ERC4626/properties/SecurityProps.sol create mode 100644 lib/crytic/contracts/ERC4626/properties/SenderIndependentProps.sol create mode 100644 lib/crytic/contracts/ERC4626/properties/VaultProxy.sol create mode 100644 lib/crytic/contracts/ERC4626/test/Solmate4626.sol create mode 100644 lib/crytic/contracts/ERC4626/test/echidna.config.yaml create mode 100644 lib/crytic/contracts/ERC4626/test/rounding/BadConvertToAssetsRounding.sol create mode 100644 lib/crytic/contracts/ERC4626/test/rounding/BadConvertToSharesRounding.sol create mode 100644 lib/crytic/contracts/ERC4626/test/rounding/BadPreviewMintRounding.sol create mode 100644 lib/crytic/contracts/ERC4626/test/rounding/BadPreviewWithdrawRounding.sol create mode 100644 lib/crytic/contracts/ERC4626/test/security/BadShareInflation.sol create mode 100644 lib/crytic/contracts/ERC4626/test/usingApproval/BadAllowanceUpdate.sol create mode 100644 lib/crytic/contracts/ERC4626/util/Actor.sol create mode 100644 lib/crytic/contracts/ERC4626/util/ERC4626PropertyTestBase.sol create mode 100644 lib/crytic/contracts/ERC4626/util/IERC4626Internal.sol create mode 100644 lib/crytic/contracts/ERC4626/util/RedemptionProxy.sol create mode 100644 lib/crytic/contracts/ERC4626/util/TestERC20Token.sol create mode 100644 lib/crytic/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol create mode 100644 lib/crytic/contracts/Math/ABDKMath64x64/README.md create mode 100644 lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMath64x64.md create mode 100644 lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMath64x64.sol create mode 100644 lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMathQuad.md create mode 100644 lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMathQuad.sol create mode 100644 lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/LICENSE.md create mode 100644 lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/README.md create mode 100644 lib/crytic/contracts/util/Hevm.sol create mode 100644 lib/crytic/contracts/util/IERC20.sol create mode 100644 lib/crytic/contracts/util/IERC4626.sol create mode 100644 lib/crytic/contracts/util/PropertiesConstants.sol create mode 100644 lib/crytic/contracts/util/PropertiesHelper.sol create mode 100644 lib/crytic/foundry.toml create mode 100644 lib/crytic/hardhat.config.js create mode 100644 lib/crytic/lib/ERC4626/.gitattributes create mode 100644 lib/crytic/lib/ERC4626/.github/workflows/test.yaml create mode 100644 lib/crytic/lib/ERC4626/.gitignore create mode 100644 lib/crytic/lib/ERC4626/README.md create mode 100644 lib/crytic/lib/ERC4626/ape-config.yaml create mode 100644 lib/crytic/lib/ERC4626/contracts/ERC4626.json create mode 100644 lib/crytic/lib/ERC4626/contracts/ERC4626.sol create mode 100644 lib/crytic/lib/ERC4626/contracts/SolidityVault.sol create mode 100644 lib/crytic/lib/ERC4626/contracts/VyperVault.vy create mode 100644 lib/crytic/lib/ERC4626/contracts/test/Token.vy create mode 100644 lib/crytic/lib/ERC4626/requirements.txt create mode 100644 lib/crytic/lib/ERC4626/scripts/make_interfaces.py create mode 100644 lib/crytic/lib/forge-std/.github/workflows/ci.yml create mode 100644 lib/crytic/lib/forge-std/.gitignore create mode 100644 lib/crytic/lib/forge-std/.gitmodules create mode 100644 lib/crytic/lib/forge-std/LICENSE-APACHE create mode 100644 lib/crytic/lib/forge-std/LICENSE-MIT create mode 100644 lib/crytic/lib/forge-std/README.md create mode 100644 lib/crytic/lib/forge-std/foundry.toml create mode 100644 lib/crytic/lib/forge-std/lib/ds-test/.gitignore create mode 100644 lib/crytic/lib/forge-std/lib/ds-test/LICENSE create mode 100644 lib/crytic/lib/forge-std/lib/ds-test/Makefile create mode 100644 lib/crytic/lib/forge-std/lib/ds-test/default.nix create mode 100644 lib/crytic/lib/forge-std/lib/ds-test/demo/demo.sol create mode 100644 lib/crytic/lib/forge-std/lib/ds-test/package.json create mode 100644 lib/crytic/lib/forge-std/lib/ds-test/src/test.sol create mode 100644 lib/crytic/lib/forge-std/package.json create mode 100644 lib/crytic/lib/forge-std/src/Base.sol create mode 100644 lib/crytic/lib/forge-std/src/Script.sol create mode 100644 lib/crytic/lib/forge-std/src/StdAssertions.sol create mode 100644 lib/crytic/lib/forge-std/src/StdChains.sol create mode 100644 lib/crytic/lib/forge-std/src/StdCheats.sol create mode 100644 lib/crytic/lib/forge-std/src/StdError.sol create mode 100644 lib/crytic/lib/forge-std/src/StdInvariant.sol create mode 100644 lib/crytic/lib/forge-std/src/StdJson.sol create mode 100644 lib/crytic/lib/forge-std/src/StdMath.sol create mode 100644 lib/crytic/lib/forge-std/src/StdStorage.sol create mode 100644 lib/crytic/lib/forge-std/src/StdUtils.sol create mode 100644 lib/crytic/lib/forge-std/src/Test.sol create mode 100644 lib/crytic/lib/forge-std/src/Vm.sol create mode 100644 lib/crytic/lib/forge-std/src/console.sol create mode 100644 lib/crytic/lib/forge-std/src/console2.sol create mode 100644 lib/crytic/lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 lib/crytic/lib/forge-std/src/interfaces/IERC165.sol create mode 100644 lib/crytic/lib/forge-std/src/interfaces/IERC20.sol create mode 100644 lib/crytic/lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 lib/crytic/lib/forge-std/src/interfaces/IERC721.sol create mode 100644 lib/crytic/lib/forge-std/src/interfaces/IMulticall3.sol create mode 100644 lib/crytic/lib/forge-std/test/StdAssertions.t.sol create mode 100644 lib/crytic/lib/forge-std/test/StdChains.t.sol create mode 100644 lib/crytic/lib/forge-std/test/StdCheats.t.sol create mode 100644 lib/crytic/lib/forge-std/test/StdError.t.sol create mode 100644 lib/crytic/lib/forge-std/test/StdMath.t.sol create mode 100644 lib/crytic/lib/forge-std/test/StdStorage.t.sol create mode 100644 lib/crytic/lib/forge-std/test/StdUtils.t.sol create mode 100644 lib/crytic/lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 lib/crytic/lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 lib/crytic/lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 lib/crytic/lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/beige-buses-drop.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/config.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/curvy-shrimps-enjoy.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/curvy-suns-sort.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/early-oranges-raise.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/famous-rules-burn.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/five-ducks-develop.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/five-poets-mix.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/flat-deers-end.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/four-bats-sniff.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/funny-rockets-compete.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/gold-chicken-clean.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/happy-socks-travel.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/healthy-squids-stare.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/lemon-dogs-kiss.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/little-kiwis-ring.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/lovely-dragons-appear.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/many-panthers-hide.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/modern-games-exist.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/new-ways-own.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/ninety-hornets-kick.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/perfect-insects-listen.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/pretty-hornets-play.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/proud-comics-deliver.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/short-roses-judge.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/slimy-knives-hug.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/small-cars-appear.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/strong-bulldogs-buy.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/tame-ladybugs-sit.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/thin-dragons-report.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/thirty-swans-exercise.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/violet-frogs-hide.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.changeset/yellow-swans-cover.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.codecov.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.editorconfig create mode 100644 lib/crytic/lib/openzeppelin-contracts/.eslintrc create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/actions/setup/action.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/workflows/actionlint.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/workflows/changeset.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/workflows/checks.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/workflows/docs.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/.gitignore create mode 100644 lib/crytic/lib/openzeppelin-contracts/.gitmodules create mode 100644 lib/crytic/lib/openzeppelin-contracts/.mocharc.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/.prettierrc create mode 100644 lib/crytic/lib/openzeppelin-contracts/.solcover.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/.solhint.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/CHANGELOG.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/CONTRIBUTING.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/GUIDELINES.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/LICENSE create mode 100644 lib/crytic/lib/openzeppelin-contracts/README.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/RELEASING.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/SECURITY.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/audits/2017-03.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/audits/2018-10.pdf create mode 100644 lib/crytic/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf create mode 100644 lib/crytic/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf create mode 100644 lib/crytic/lib/openzeppelin-contracts/audits/README.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/Makefile create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/README.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/applyHarness.patch create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/harnesses/ERC20VotesHarness.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/harnesses/WizardControlFirstPriority.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/harnesses/WizardFirstTry.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/munged/.gitignore create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/reports/2021-10.pdf create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/reports/2022-03.pdf create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/reports/2022-05.pdf create mode 100755 lib/crytic/lib/openzeppelin-contracts/certora/scripts/Governor.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/scripts/GovernorCountingSimple-counting.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/scripts/WizardControlFirstPriority.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/scripts/WizardFirstTry.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/scripts/sanity.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/scripts/verifyAll.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/specs/GovernorBase.spec create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/specs/GovernorCountingSimple.spec create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/specs/RulesInProgress.spec create mode 100644 lib/crytic/lib/openzeppelin-contracts/certora/specs/sanity.spec create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControl.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControlCrossChain.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControlEnumerable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/access/IAccessControlEnumerable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/access/Ownable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/access/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/CrossChainEnabled.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/amb/CrossChainEnabledAMB.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/amb/LibAMB.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/LibArbitrumL1.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/LibArbitrumL2.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/errors.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/optimism/LibOptimism.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/finance/PaymentSplitter.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/finance/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/Governor.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/compatibility/GovernorCompatibilityBravo.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalThreshold.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesComp.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/IGovernorTimelock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC2612.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/metatx/MinimalForwarder.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/metatx/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/AccessControlCrossChainMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ConditionalEscrowMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC20Mock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC4626Mock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/MulticallTest.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/PullPaymentMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/SafeMathMemoryCheck.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/TimersBlockNumberImpl.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/TimersTimestampImpl.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/crosschain/bridges.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/crosschain/receivers.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCompMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSLegacy.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20PermitNoRevertMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnTrueMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC777Mock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC777SenderRecipientMock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/VotesTimestamp.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor1.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor2.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor3.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/package.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/Clones.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/security/Pausable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/security/PullPayment.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/security/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/presets/README.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Receiver.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Snapshot.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20VotesComp.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Permit.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-IERC20Permit.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/README.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/utils/TokenTimelock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/draft-ERC721Votes.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/presets/README.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/ERC777.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777Recipient.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777Sender.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/token/common/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Address.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Arrays.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Base64.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Checkpoints.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Context.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Counters.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Create2.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Multicall.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/README.adoc create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Strings.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/Timers.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-EIP712.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/ConditionalEscrow.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/Escrow.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/RefundEscrow.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Storage.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC1820Implementer.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC1820Implementer.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC1820Registry.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/Math.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SignedSafeMath.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/amb/IAMB.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IArbSys.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IBridge.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IDelayedMessageProvider.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IInbox.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IOutbox.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/optimism/ICrossDomainMessenger.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/optimism/LICENSE create mode 100644 lib/crytic/lib/openzeppelin-contracts/contracts/vendor/polygon/IFxMessageProcessor.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/foundry.toml create mode 100644 lib/crytic/lib/openzeppelin-contracts/hardhat.config.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/hardhat/env-contract.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/README.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.gitignore create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.gitmodules create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/README.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/foundry.toml create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/.gitignore create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/LICENSE create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/Makefile create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/default.nix create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/demo/demo.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/package.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/test.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/package.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/console.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/logo.svg create mode 100644 lib/crytic/lib/openzeppelin-contracts/netlify.toml create mode 100644 lib/crytic/lib/openzeppelin-contracts/package-lock.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/package.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/renovate.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/checks/compare-layout.js create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/checks/extract-layout.js create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/checks/generation.sh create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/gen-nav.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/generate/format-lines.js create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/generate/run.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/git-user-config.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/helpers.js create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/migrate-imports.js create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/prepack.sh create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/prepare-contracts-package.sh create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/prepare-docs.sh create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/prepare.sh create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/release/format-changelog.js create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/release/update-comment.js create mode 100755 lib/crytic/lib/openzeppelin-contracts/scripts/release/version.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/prepare-release-merge.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/start.sh create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/state.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/scripts/update-docs-branch.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/slither.config.json create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/TESTING.md create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/access/AccessControl.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/access/AccessControlCrossChain.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/access/AccessControlEnumerable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/access/Ownable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/crosschain/CrossChainEnabled.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/finance/PaymentSplitter.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/Governor.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/TimelockController.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/compatibility/GovernorCompatibilityBravo.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorComp.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/utils/EIP6372.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/chainid.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/create2.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/crosschain.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/customError.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/eip712.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/enums.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/erc1967.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/governance.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/map-values.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/sign.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/time.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/helpers/txpool.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/metatx/MinimalForwarder.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/migrate-imports.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/Clones.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/security/Pausable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/security/PullPayment.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/security/ReentrancyGuard.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Snapshot.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20VotesComp.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Permit.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/utils/TokenTimelock.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/ERC777.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/ERC777.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Address.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Arrays.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Base64.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Checkpoints.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Context.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Context.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Counters.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Create2.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Multicall.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/Strings.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/TimersBlockNumberImpl.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/TimersTimestamp.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/ConditionalEscrow.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/Escrow.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/Escrow.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/RefundEscrow.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165Storage.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC1820Implementer.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/math/Math.t.sol create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/math/Math.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/math/SafeMath.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/math/SignedSafeMath.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js create mode 100644 lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js create mode 100644 lib/crytic/lib/solmate/.gas-snapshot create mode 100644 lib/crytic/lib/solmate/.gitattributes create mode 100644 lib/crytic/lib/solmate/.github/pull_request_template.md create mode 100644 lib/crytic/lib/solmate/.github/workflows/tests.yml create mode 100644 lib/crytic/lib/solmate/.gitignore create mode 100644 lib/crytic/lib/solmate/.gitmodules create mode 100644 lib/crytic/lib/solmate/.prettierignore create mode 100644 lib/crytic/lib/solmate/.prettierrc create mode 100644 lib/crytic/lib/solmate/LICENSE create mode 100644 lib/crytic/lib/solmate/README.md create mode 100644 lib/crytic/lib/solmate/audits/v6-Fixed-Point-Solutions.pdf create mode 100644 lib/crytic/lib/solmate/foundry.toml create mode 100644 lib/crytic/lib/solmate/lib/ds-test/.gitignore create mode 100644 lib/crytic/lib/solmate/lib/ds-test/LICENSE create mode 100644 lib/crytic/lib/solmate/lib/ds-test/Makefile create mode 100644 lib/crytic/lib/solmate/lib/ds-test/default.nix create mode 100644 lib/crytic/lib/solmate/lib/ds-test/demo/demo.sol create mode 100644 lib/crytic/lib/solmate/lib/ds-test/package.json create mode 100644 lib/crytic/lib/solmate/lib/ds-test/src/test.sol create mode 100644 lib/crytic/lib/solmate/package-lock.json create mode 100644 lib/crytic/lib/solmate/package.json create mode 100644 lib/crytic/lib/solmate/src/auth/Auth.sol create mode 100644 lib/crytic/lib/solmate/src/auth/Owned.sol create mode 100644 lib/crytic/lib/solmate/src/auth/authorities/MultiRolesAuthority.sol create mode 100644 lib/crytic/lib/solmate/src/auth/authorities/RolesAuthority.sol create mode 100644 lib/crytic/lib/solmate/src/mixins/ERC4626.sol create mode 100644 lib/crytic/lib/solmate/src/test/Auth.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/Bytes32AddressLib.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/CREATE3.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/DSTestPlus.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/ERC1155.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/ERC20.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/ERC4626.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/ERC721.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/FixedPointMathLib.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/LibString.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/MerkleProofLib.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/MultiRolesAuthority.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/Owned.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/ReentrancyGuard.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/RolesAuthority.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/SSTORE2.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/SafeCastLib.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/SafeTransferLib.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/SignedWadMath.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/WETH.t.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/DSInvariantTest.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/DSTestPlus.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/Hevm.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/mocks/MockAuthChild.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/mocks/MockAuthority.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/mocks/MockERC1155.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/mocks/MockERC20.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/mocks/MockERC4626.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/mocks/MockERC721.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/mocks/MockOwned.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sol create mode 100644 lib/crytic/lib/solmate/src/test/utils/weird-tokens/RevertingToken.sol create mode 100644 lib/crytic/lib/solmate/src/tokens/ERC1155.sol create mode 100644 lib/crytic/lib/solmate/src/tokens/ERC20.sol create mode 100644 lib/crytic/lib/solmate/src/tokens/ERC721.sol create mode 100644 lib/crytic/lib/solmate/src/tokens/WETH.sol create mode 100644 lib/crytic/lib/solmate/src/utils/Bytes32AddressLib.sol create mode 100644 lib/crytic/lib/solmate/src/utils/CREATE3.sol create mode 100644 lib/crytic/lib/solmate/src/utils/FixedPointMathLib.sol create mode 100644 lib/crytic/lib/solmate/src/utils/LibString.sol create mode 100644 lib/crytic/lib/solmate/src/utils/MerkleProofLib.sol create mode 100644 lib/crytic/lib/solmate/src/utils/ReentrancyGuard.sol create mode 100644 lib/crytic/lib/solmate/src/utils/SSTORE2.sol create mode 100644 lib/crytic/lib/solmate/src/utils/SafeCastLib.sol create mode 100644 lib/crytic/lib/solmate/src/utils/SafeTransferLib.sol create mode 100644 lib/crytic/lib/solmate/src/utils/SignedWadMath.sol create mode 100644 lib/crytic/package-lock.json create mode 100644 lib/crytic/package.json create mode 100644 lib/erc4626-tests/ERC4626.prop.sol create mode 100644 lib/erc4626-tests/ERC4626.test.sol create mode 100644 lib/erc4626-tests/LICENSE create mode 100644 lib/erc4626-tests/README.md create mode 100644 lib/forge-std/.github/workflows/ci.yml create mode 100644 lib/forge-std/.github/workflows/sync.yml create mode 100644 lib/forge-std/.gitignore create mode 100644 lib/forge-std/.gitmodules create mode 100644 lib/forge-std/LICENSE-APACHE create mode 100644 lib/forge-std/LICENSE-MIT create mode 100644 lib/forge-std/README.md create mode 100644 lib/forge-std/foundry.toml create mode 100644 lib/forge-std/lib/ds-test/.github/workflows/build.yml create mode 100644 lib/forge-std/lib/ds-test/.gitignore create mode 100644 lib/forge-std/lib/ds-test/LICENSE create mode 100644 lib/forge-std/lib/ds-test/Makefile create mode 100644 lib/forge-std/lib/ds-test/default.nix create mode 100644 lib/forge-std/lib/ds-test/demo/demo.sol create mode 100644 lib/forge-std/lib/ds-test/package.json create mode 100644 lib/forge-std/lib/ds-test/src/test.sol create mode 100644 lib/forge-std/lib/ds-test/src/test.t.sol create mode 100644 lib/forge-std/package.json create mode 100644 lib/forge-std/src/Base.sol create mode 100644 lib/forge-std/src/Script.sol create mode 100644 lib/forge-std/src/StdAssertions.sol create mode 100644 lib/forge-std/src/StdChains.sol create mode 100644 lib/forge-std/src/StdCheats.sol create mode 100644 lib/forge-std/src/StdError.sol create mode 100644 lib/forge-std/src/StdInvariant.sol create mode 100644 lib/forge-std/src/StdJson.sol create mode 100644 lib/forge-std/src/StdMath.sol create mode 100644 lib/forge-std/src/StdStorage.sol create mode 100644 lib/forge-std/src/StdStyle.sol create mode 100644 lib/forge-std/src/StdUtils.sol create mode 100644 lib/forge-std/src/Test.sol create mode 100644 lib/forge-std/src/Vm.sol create mode 100644 lib/forge-std/src/console.sol create mode 100644 lib/forge-std/src/console2.sol create mode 100644 lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 lib/forge-std/src/interfaces/IERC165.sol create mode 100644 lib/forge-std/src/interfaces/IERC20.sol create mode 100644 lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 lib/forge-std/src/interfaces/IERC721.sol create mode 100644 lib/forge-std/src/interfaces/IMulticall3.sol create mode 100644 lib/forge-std/src/safeconsole.sol create mode 100644 lib/forge-std/test/StdAssertions.t.sol create mode 100644 lib/forge-std/test/StdChains.t.sol create mode 100644 lib/forge-std/test/StdCheats.t.sol create mode 100644 lib/forge-std/test/StdError.t.sol create mode 100644 lib/forge-std/test/StdMath.t.sol create mode 100644 lib/forge-std/test/StdStorage.t.sol create mode 100644 lib/forge-std/test/StdStyle.t.sol create mode 100644 lib/forge-std/test/StdUtils.t.sol create mode 100644 lib/forge-std/test/Vm.t.sol create mode 100644 lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 lib/forge-std/test/fixtures/broadcast.log.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/.changeset/config.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/.codecov.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.editorconfig create mode 100644 lib/openzeppelin-contracts-v4.9.3/.eslintrc create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/config.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/actions/gas-compare/action.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/actions/setup/action.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/actions/storage-layout/action.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/workflows/actionlint.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/workflows/changeset.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/workflows/checks.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/workflows/docs.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/workflows/formal-verification.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/workflows/release-cycle.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.github/workflows/upgradeable.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/.gitignore create mode 100644 lib/openzeppelin-contracts-v4.9.3/.gitmodules create mode 100644 lib/openzeppelin-contracts-v4.9.3/.mocharc.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/.prettierrc create mode 100644 lib/openzeppelin-contracts-v4.9.3/.solcover.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/.solhint.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/CHANGELOG.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/CODE_OF_CONDUCT.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/CONTRIBUTING.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/GUIDELINES.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/LICENSE create mode 100644 lib/openzeppelin-contracts-v4.9.3/README.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/RELEASING.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/SECURITY.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/audits/2017-03.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/audits/2018-10.pdf create mode 100644 lib/openzeppelin-contracts-v4.9.3/audits/2022-10-Checkpoints.pdf create mode 100644 lib/openzeppelin-contracts-v4.9.3/audits/2022-10-ERC4626.pdf create mode 100644 lib/openzeppelin-contracts-v4.9.3/audits/2023-05-v4.9.pdf create mode 100644 lib/openzeppelin-contracts-v4.9.3/audits/README.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/.gitignore create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/Makefile create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/README.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/diff/token_ERC721_ERC721.sol.patch create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/AccessControlHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/DoubleEndedQueueHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20FlashMintHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20PermitHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20WrapperHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC3156FlashBorrowerHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC721Harness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC721ReceiverHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/EnumerableMapHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/EnumerableSetHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/InitializableHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/Ownable2StepHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/OwnableHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/PausableHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/harnesses/TimelockControllerHarness.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/reports/2021-10.pdf create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/reports/2022-03.pdf create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/reports/2022-05.pdf create mode 100755 lib/openzeppelin-contracts-v4.9.3/certora/run.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/AccessControl.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/AccessControlDefaultAdminRules.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/DoubleEndedQueue.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20FlashMint.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20Wrapper.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC721.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/EnumerableMap.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/EnumerableSet.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/Initializable.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/Ownable.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/Ownable2Step.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/Pausable.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/TimelockController.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/helpers/helpers.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IAccessControl.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IAccessControlDefaultAdminRules.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC20.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC2612.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC3156.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC5313.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC721.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IOwnable.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IOwnable2Step.spec create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControl.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlCrossChain.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlDefaultAdminRules.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlEnumerable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControl.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControlDefaultAdminRules.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControlEnumerable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/Ownable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/Ownable2Step.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/access/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/CrossChainEnabled.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/amb/CrossChainEnabledAMB.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/amb/LibAMB.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/LibArbitrumL1.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/LibArbitrumL2.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/errors.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/optimism/LibOptimism.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/finance/PaymentSplitter.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/finance/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/finance/VestingWallet.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/Governor.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/IGovernor.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/TimelockController.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/compatibility/GovernorCompatibilityBravo.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorCountingSimple.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorPreventLateQuorum.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorProposalThreshold.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorSettings.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorTimelockCompound.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorTimelockControl.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotes.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotesComp.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotesQuorumFraction.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/IGovernorTimelock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/utils/IVotes.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/governance/utils/Votes.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155MetadataURI.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155Receiver.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1271.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363Receiver.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363Spender.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC165.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1820Implementer.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1820Registry.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1967.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC20.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC20Metadata.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2309.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2612.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2981.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156FlashBorrower.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156FlashLender.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC4626.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC4906.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5267.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5313.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5805.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC6372.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Metadata.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Receiver.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777Recipient.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777Sender.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/draft-IERC1822.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/draft-IERC2612.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/metatx/ERC2771Context.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/metatx/MinimalForwarder.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/metatx/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/AccessControlCrossChainMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ArraysMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/CallReceiverMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ConditionalEscrowMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ContextMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/DummyImplementation.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/EIP712Verifier.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC1271WalletMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165MaliciousData.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165MissingData.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165NotSupported.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165ReturnBomb.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC20Mock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC20Reentrant.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC2771ContextMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC3156FlashBorrowerMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC4626Mock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/EtherReceiverMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/InitializableMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/MulticallTest.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/MultipleInheritanceInitializableMocks.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/PausableMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/PullPaymentMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ReentrancyAttack.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ReentrancyMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/RegressionImplementation.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/SafeMathMemoryCheck.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/SingleInheritanceInitializableMocks.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/StorageSlotMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimelockReentrant.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimersBlockNumberImpl.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimersTimestampImpl.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/VotesMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/compound/CompTimelock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/crosschain/bridges.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/crosschain/receivers.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorCompMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorTimelockCompoundMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorTimelockControlMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorVoteMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorWithParamsMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/BadBeacon.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/ClashingImplementation.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/UUPSLegacy.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/UUPSUpgradeableMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC1155ReceiverMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20DecimalsMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ExcessDecimalsMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20FlashMintMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ForceApproveMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20MulticallMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20NoReturnMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20PermitNoRevertMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ReturnFalseMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20VotesLegacyMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC4626OffsetMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC4646FeesMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ConsecutiveMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ReceiverMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721URIStorageMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC777Mock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC777SenderRecipientMock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/VotesTimestamp.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor1.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor2.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor3.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/package.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/Clones.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/ERC1967/ERC1967Proxy.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/ERC1967/ERC1967Upgrade.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/Proxy.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/BeaconProxy.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/IBeacon.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/UpgradeableBeacon.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/transparent/ProxyAdmin.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/transparent/TransparentUpgradeableProxy.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/utils/Initializable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/proxy/utils/UUPSUpgradeable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/security/Pausable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/security/PullPayment.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/security/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/security/ReentrancyGuard.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/ERC1155.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/IERC1155.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/IERC1155Receiver.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Burnable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Pausable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Supply.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/presets/README.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/utils/ERC1155Holder.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/utils/ERC1155Receiver.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/ERC20.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/IERC20.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Burnable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Capped.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20FlashMint.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Pausable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Permit.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Snapshot.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Votes.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20VotesComp.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Wrapper.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC4626.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/IERC20Metadata.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/IERC20Permit.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/draft-ERC20Permit.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/draft-IERC20Permit.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/README.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/utils/SafeERC20.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/utils/TokenTimelock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/ERC721.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/IERC721.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/IERC721Receiver.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Burnable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Consecutive.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Pausable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Royalty.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721URIStorage.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Votes.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Wrapper.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/IERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/IERC721Metadata.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/draft-ERC721Votes.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/presets/README.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/utils/ERC721Holder.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/ERC777.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777Recipient.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777Sender.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/common/ERC2981.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/token/common/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Address.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Arrays.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Base64.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Checkpoints.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Context.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Counters.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Create2.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Multicall.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/README.adoc create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/ShortStrings.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/StorageSlot.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Strings.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/Timers.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/ECDSA.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/EIP712.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/MerkleProof.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/SignatureChecker.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/draft-EIP712.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/ConditionalEscrow.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/Escrow.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/RefundEscrow.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165Checker.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165Storage.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC1820Implementer.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC165.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC1820Implementer.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC1820Registry.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/Math.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SafeCast.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SafeMath.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SignedMath.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SignedSafeMath.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/BitMaps.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/DoubleEndedQueue.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/EnumerableMap.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/EnumerableSet.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/amb/IAMB.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IArbSys.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IBridge.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IDelayedMessageProvider.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IInbox.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IOutbox.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/compound/ICompoundTimelock.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/compound/LICENSE create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/optimism/ICrossDomainMessenger.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/optimism/LICENSE create mode 100644 lib/openzeppelin-contracts-v4.9.3/contracts/vendor/polygon/IFxMessageProcessor.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/foundry.toml create mode 100644 lib/openzeppelin-contracts-v4.9.3/hardhat.config.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/hardhat/env-artifacts.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/hardhat/env-contract.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/hardhat/ignore-unreachable-warnings.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/hardhat/skip-foundry-tests.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/hardhat/task-test-get-files.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/ERC4626.prop.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/ERC4626.test.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/LICENSE create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/README.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.github/workflows/ci.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.gitignore create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.gitmodules create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/LICENSE-APACHE create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/LICENSE-MIT create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/README.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/foundry.toml create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/.github/workflows/build.yml create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/.gitignore create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/LICENSE create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/Makefile create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/default.nix create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/demo/demo.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/package.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/src/test.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/src/test.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/package.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Base.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Script.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdAssertions.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdChains.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdCheats.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdError.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdInvariant.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdJson.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdMath.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdStorage.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdStyle.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdUtils.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Test.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Vm.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/console.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/console2.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC165.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC20.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC721.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IMulticall3.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdAssertions.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdChains.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdCheats.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdError.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdMath.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdStorage.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdStyle.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdUtils.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/fixtures/broadcast.log.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/logo.svg create mode 100644 lib/openzeppelin-contracts-v4.9.3/netlify.toml create mode 100644 lib/openzeppelin-contracts-v4.9.3/package-lock.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/package.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/remappings.txt create mode 100644 lib/openzeppelin-contracts-v4.9.3/renovate.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/requirements.txt create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/checks/compare-layout.js create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/checks/compareGasReports.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/checks/extract-layout.js create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/checks/generation.sh create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/checks/inheritance-ordering.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/gen-nav.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/format-lines.js create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/generate/run.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.opts.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.t.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/EnumerableMap.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/EnumerableSet.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/SafeCast.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/StorageSlot.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/conversion.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/git-user-config.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/helpers.js create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/migrate-imports.js create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/prepack.sh create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/prepare-contracts-package.sh create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/prepare-docs.sh create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/prepare.sh create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/release/format-changelog.js create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/release/synchronize-versions.js create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/release/update-comment.js create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/release/version.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/exit-prerelease.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/github-release.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/integrity-check.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/pack.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/publish.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/rerun.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/set-changesets-pr-title.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/start.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/state.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/remove-ignored-artifacts.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/update-docs-branch.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/README.md create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/patch-apply.sh create mode 100755 lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/patch-save.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/transpile-onto.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/transpile.sh create mode 100644 lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/upgradeable.patch create mode 100644 lib/openzeppelin-contracts-v4.9.3/slither.config.json create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/TESTING.md create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/access/AccessControl.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/access/AccessControl.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlCrossChain.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlDefaultAdminRules.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlEnumerable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/access/Ownable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/access/Ownable2Step.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/crosschain/CrossChainEnabled.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/finance/PaymentSplitter.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/finance/VestingWallet.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/finance/VestingWallet.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/Governor.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/Governor.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/TimelockController.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/compatibility/GovernorCompatibilityBravo.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorComp.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorERC721.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorPreventLateQuorum.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorTimelockCompound.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorTimelockControl.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorVotesQuorumFraction.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorWithParams.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/utils/EIP6372.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/utils/Votes.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/governance/utils/Votes.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/chainid.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/create2.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/crosschain.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/customError.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/eip712.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/enums.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/erc1967.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/governance.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/map-values.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/sign.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/time.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/helpers/txpool.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/metatx/ERC2771Context.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/metatx/MinimalForwarder.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/migrate-imports.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/Clones.behaviour.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/Clones.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/ERC1967/ERC1967Proxy.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/Proxy.behaviour.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/beacon/BeaconProxy.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/beacon/UpgradeableBeacon.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/ProxyAdmin.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/TransparentUpgradeableProxy.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/utils/Initializable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/proxy/utils/UUPSUpgradeable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/security/Pausable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/security/PullPayment.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/security/ReentrancyGuard.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/ERC1155.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/ERC1155.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Burnable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Pausable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Supply.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155URIStorage.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/utils/ERC1155Holder.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/ERC20.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/ERC20.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Burnable.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Burnable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Capped.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Capped.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20FlashMint.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Pausable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Snapshot.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Votes.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20VotesComp.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Wrapper.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC4626.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC4626.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/draft-ERC20Permit.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/utils/SafeERC20.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/utils/TokenTimelock.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721Enumerable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Burnable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Consecutive.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Consecutive.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Pausable.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Royalty.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721URIStorage.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Votes.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Wrapper.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/utils/ERC721Holder.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/ERC777.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/ERC777.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/token/common/ERC2981.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Address.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Arrays.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Base64.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Checkpoints.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Checkpoints.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Context.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Context.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Counters.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Create2.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Multicall.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/ShortStrings.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/ShortStrings.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/StorageSlot.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/Strings.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/TimersBlockNumberImpl.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/TimersTimestamp.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/ECDSA.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/EIP712.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/MerkleProof.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/SignatureChecker.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/ConditionalEscrow.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/Escrow.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/Escrow.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/RefundEscrow.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165Checker.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165Storage.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC1820Implementer.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/SupportsInterface.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/math/Math.t.sol create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/math/Math.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/math/SafeCast.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/math/SafeMath.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/math/SignedMath.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/math/SignedSafeMath.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/structs/BitMap.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/structs/DoubleEndedQueue.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableMap.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableMap.test.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableSet.behavior.js create mode 100644 lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableSet.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/.changeset/config.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/.codecov.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.editorconfig create mode 100644 lib/openzeppelin-contracts-v5.0.0/.eslintrc create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/config.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/actions/gas-compare/action.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/actions/setup/action.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/actions/storage-layout/action.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/workflows/actionlint.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/workflows/changeset.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/workflows/checks.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/workflows/docs.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/workflows/formal-verification.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/workflows/release-cycle.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.github/workflows/upgradeable.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/.gitignore create mode 100644 lib/openzeppelin-contracts-v5.0.0/.gitmodules create mode 100644 lib/openzeppelin-contracts-v5.0.0/.mocharc.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/.prettierrc create mode 100644 lib/openzeppelin-contracts-v5.0.0/.solcover.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/CHANGELOG.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/CODE_OF_CONDUCT.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/CONTRIBUTING.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/GUIDELINES.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/LICENSE create mode 100644 lib/openzeppelin-contracts-v5.0.0/README.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/RELEASING.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/SECURITY.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/audits/2017-03.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/audits/2018-10.pdf create mode 100644 lib/openzeppelin-contracts-v5.0.0/audits/2022-10-Checkpoints.pdf create mode 100644 lib/openzeppelin-contracts-v5.0.0/audits/2022-10-ERC4626.pdf create mode 100644 lib/openzeppelin-contracts-v5.0.0/audits/2023-05-v4.9.pdf create mode 100644 lib/openzeppelin-contracts-v5.0.0/audits/2023-10-v5.0.pdf create mode 100644 lib/openzeppelin-contracts-v5.0.0/audits/README.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/.gitignore create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/Makefile create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/README.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/diff/access_manager_AccessManager.sol.patch create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/AccessControlHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/DoubleEndedQueueHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20FlashMintHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20PermitHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20WrapperHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC3156FlashBorrowerHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC721Harness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC721ReceiverHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/EnumerableMapHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/EnumerableSetHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/InitializableHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/Ownable2StepHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/OwnableHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/PausableHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/harnesses/TimelockControllerHarness.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/reports/2021-10.pdf create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/reports/2022-03.pdf create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/reports/2022-05.pdf create mode 100755 lib/openzeppelin-contracts-v5.0.0/certora/run.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/AccessControl.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/AccessControlDefaultAdminRules.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/DoubleEndedQueue.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20FlashMint.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20Wrapper.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC721.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/EnumerableMap.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/EnumerableSet.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/Initializable.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/Ownable.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/Ownable2Step.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/Pausable.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/TimelockController.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/helpers/helpers.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IAccessControl.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IAccessControlDefaultAdminRules.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC20.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC2612.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC3156FlashBorrower.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC3156FlashLender.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC5313.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC721.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC721Receiver.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IOwnable.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IOwnable2Step.spec create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/AccessControl.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/IAccessControl.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/Ownable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/Ownable2Step.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/AccessControlDefaultAdminRules.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/AccessControlEnumerable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/IAccessControlDefaultAdminRules.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/IAccessControlEnumerable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AccessManaged.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AccessManager.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AuthorityUtils.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAccessManaged.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAccessManager.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAuthority.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/finance/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/finance/VestingWallet.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/Governor.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/IGovernor.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/TimelockController.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorCountingSimple.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorPreventLateQuorum.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorSettings.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorStorage.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockAccess.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockCompound.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockControl.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorVotes.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorVotesQuorumFraction.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/utils/IVotes.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/governance/utils/Votes.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155MetadataURI.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155Receiver.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1271.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363Receiver.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363Spender.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC165.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1820Implementer.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1820Registry.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1967.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC20.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC20Metadata.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2309.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2612.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2981.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156FlashBorrower.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156FlashLender.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC4626.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC4906.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5267.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5313.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5805.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC6372.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Metadata.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Receiver.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777Recipient.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777Sender.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/draft-IERC1822.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/draft-IERC6093.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/metatx/ERC2771Context.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/metatx/ERC2771Forwarder.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/metatx/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/AccessManagedTarget.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ArraysMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/AuthorityMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/CallReceiverMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ContextMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/DummyImplementation.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/EIP712Verifier.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC1271WalletMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165InterfacesSupported.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165MaliciousData.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165MissingData.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165NotSupported.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165ReturnBomb.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC2771ContextMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC3156FlashBorrowerMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/EtherReceiverMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/InitializableMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/MulticallTest.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/MultipleInheritanceInitializableMocks.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/PausableMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ReentrancyAttack.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ReentrancyMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/RegressionImplementation.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/SingleInheritanceInitializableMocks.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/Stateless.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/StorageSlotMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/TimelockReentrant.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/UpgradeableBeaconMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/VotesMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/compound/CompTimelock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorStorageMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockAccessMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockCompoundMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockControlMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorVoteMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorWithParamsMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/BadBeacon.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/ClashingImplementation.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/UUPSUpgradeableMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC1155ReceiverMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ApprovalMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20DecimalsMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ExcessDecimalsMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20FlashMintMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ForceApproveMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20Mock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20MulticallMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20NoReturnMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20Reentrant.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ReturnFalseMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20VotesLegacyMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626LimitsMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626Mock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626OffsetMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4646FeesMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ConsecutiveMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ReceiverMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721URIStorageMock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/VotesTimestamp.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/package.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/Clones.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/ERC1967/ERC1967Proxy.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/ERC1967/ERC1967Utils.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/Proxy.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/BeaconProxy.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/IBeacon.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/UpgradeableBeacon.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/transparent/ProxyAdmin.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/utils/Initializable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/proxy/utils/UUPSUpgradeable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/ERC1155.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/IERC1155.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/IERC1155Receiver.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Burnable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Pausable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Supply.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/utils/ERC1155Holder.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/ERC20.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/IERC20.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Burnable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Capped.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20FlashMint.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Pausable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Permit.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Votes.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Wrapper.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC4626.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/IERC20Metadata.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/IERC20Permit.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/utils/SafeERC20.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/ERC721.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/IERC721.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/IERC721Receiver.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Burnable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Consecutive.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Pausable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Royalty.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721URIStorage.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Votes.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Wrapper.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/IERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/IERC721Metadata.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/utils/ERC721Holder.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/common/ERC2981.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/token/common/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Address.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Arrays.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Base64.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Context.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Create2.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Multicall.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Nonces.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Pausable.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/README.adoc create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/ReentrancyGuard.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/ShortStrings.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/StorageSlot.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/Strings.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/ECDSA.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/EIP712.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/MerkleProof.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/MessageHashUtils.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/SignatureChecker.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/ERC165.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/ERC165Checker.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/IERC165.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/Math.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/SafeCast.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/SignedMath.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/BitMaps.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/Checkpoints.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/DoubleEndedQueue.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/EnumerableMap.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/EnumerableSet.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/utils/types/Time.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/vendor/compound/ICompoundTimelock.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/contracts/vendor/compound/LICENSE create mode 100644 lib/openzeppelin-contracts-v5.0.0/foundry.toml create mode 100644 lib/openzeppelin-contracts-v5.0.0/hardhat.config.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/hardhat/env-artifacts.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/hardhat/env-contract.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/hardhat/ignore-unreachable-warnings.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/hardhat/skip-foundry-tests.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/hardhat/task-test-get-files.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/ERC4626.prop.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/ERC4626.test.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/LICENSE create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/README.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.github/workflows/ci.yml create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.gitignore create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.gitmodules create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/LICENSE-APACHE create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/LICENSE-MIT create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/README.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/foundry.toml create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/.gitignore create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/LICENSE create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/Makefile create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/default.nix create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/demo/demo.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/package.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/src/test.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/package.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Base.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Script.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdAssertions.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdChains.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdCheats.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdError.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdJson.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdMath.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdStorage.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdUtils.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Test.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Vm.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/console.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/console2.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC165.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC20.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC721.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdAssertions.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdChains.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdCheats.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdError.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdMath.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdStorage.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdUtils.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/fixtures/broadcast.log.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/logo.svg create mode 100644 lib/openzeppelin-contracts-v5.0.0/netlify.toml create mode 100644 lib/openzeppelin-contracts-v5.0.0/package-lock.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/package.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/remappings.txt create mode 100644 lib/openzeppelin-contracts-v5.0.0/renovate.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/requirements.txt create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/checks/compare-layout.js create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/checks/compareGasReports.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/checks/extract-layout.js create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/checks/generation.sh create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/checks/inheritance-ordering.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/gen-nav.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/format-lines.js create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/generate/run.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.opts.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.t.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/EnumerableMap.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/EnumerableSet.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/SafeCast.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/StorageSlot.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/conversion.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/git-user-config.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/helpers.js create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/prepack.sh create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/prepare-docs.sh create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/release/format-changelog.js create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/release/synchronize-versions.js create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/release/update-comment.js create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/release/version.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/exit-prerelease.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/github-release.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/integrity-check.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/pack.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/publish.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/rerun.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/set-changesets-pr-title.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/start.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/state.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/remove-ignored-artifacts.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/solhint-custom/index.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/solhint-custom/package.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/update-docs-branch.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/README.md create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/patch-apply.sh create mode 100755 lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/patch-save.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/transpile-onto.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/transpile.sh create mode 100644 lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/upgradeable.patch create mode 100644 lib/openzeppelin-contracts-v5.0.0/slither.config.json create mode 100644 lib/openzeppelin-contracts-v5.0.0/solhint.config.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/TESTING.md create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/AccessControl.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/AccessControl.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/Ownable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/Ownable2Step.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/extensions/AccessControlDefaultAdminRules.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/extensions/AccessControlEnumerable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManaged.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManager.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManager.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/access/manager/AuthorityUtils.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/finance/VestingWallet.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/finance/VestingWallet.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/Governor.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/Governor.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/TimelockController.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorERC721.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorPreventLateQuorum.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorStorage.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockAccess.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockCompound.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockControl.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorVotesQuorumFraction.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorWithParams.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/utils/EIP6372.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/utils/Votes.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/governance/utils/Votes.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/access-manager.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/account.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/chainid.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/constants.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/create.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/customError.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/eip712.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/enums.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/erc1967.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/governance.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/iterate.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/math.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/methods.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/sign.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/time.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/helpers/txpool.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Context.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Forwarder.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Forwarder.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/Clones.behaviour.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/Clones.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/ERC1967/ERC1967Proxy.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/ERC1967/ERC1967Utils.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/Proxy.behaviour.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/beacon/BeaconProxy.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/beacon/UpgradeableBeacon.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/ProxyAdmin.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/TransparentUpgradeableProxy.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/utils/Initializable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/proxy/utils/UUPSUpgradeable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/ERC1155.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/ERC1155.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Burnable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Pausable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Supply.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155URIStorage.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/utils/ERC1155Holder.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/ERC20.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/ERC20.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Burnable.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Burnable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Capped.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Capped.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20FlashMint.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Pausable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Permit.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Votes.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Wrapper.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC4626.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC4626.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/utils/SafeERC20.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721Enumerable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Burnable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Consecutive.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Consecutive.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Pausable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Royalty.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721URIStorage.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Votes.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Wrapper.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/utils/ERC721Holder.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/token/common/ERC2981.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Address.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Arrays.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Base64.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Context.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Context.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Create2.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Multicall.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Nonces.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Pausable.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/ReentrancyGuard.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/ShortStrings.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/ShortStrings.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/StorageSlot.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/Strings.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/ECDSA.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/EIP712.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/MerkleProof.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/MessageHashUtils.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/SignatureChecker.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/ERC165.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/ERC165Checker.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/SupportsInterface.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/math/Math.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/math/Math.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/math/SafeCast.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/math/SignedMath.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/structs/BitMap.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/structs/Checkpoints.t.sol create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/structs/Checkpoints.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/structs/DoubleEndedQueue.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableMap.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableMap.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableSet.behavior.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableSet.test.js create mode 100644 lib/openzeppelin-contracts-v5.0.0/test/utils/types/Time.test.js create mode 100644 lib/openzeppelin-contracts/.changeset/config.json create mode 100644 lib/openzeppelin-contracts/.codecov.yml create mode 100644 lib/openzeppelin-contracts/.editorconfig create mode 100644 lib/openzeppelin-contracts/.eslintrc create mode 100644 lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml create mode 100644 lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml create mode 100644 lib/openzeppelin-contracts/.github/actions/setup/action.yml create mode 100644 lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml create mode 100644 lib/openzeppelin-contracts/.github/workflows/actionlint.yml create mode 100644 lib/openzeppelin-contracts/.github/workflows/changeset.yml create mode 100644 lib/openzeppelin-contracts/.github/workflows/checks.yml create mode 100644 lib/openzeppelin-contracts/.github/workflows/docs.yml create mode 100644 lib/openzeppelin-contracts/.github/workflows/formal-verification.yml create mode 100644 lib/openzeppelin-contracts/.github/workflows/release-cycle.yml create mode 100644 lib/openzeppelin-contracts/.github/workflows/upgradeable.yml create mode 100644 lib/openzeppelin-contracts/.gitignore create mode 100644 lib/openzeppelin-contracts/.gitmodules create mode 100644 lib/openzeppelin-contracts/.mocharc.js create mode 100644 lib/openzeppelin-contracts/.prettierrc create mode 100644 lib/openzeppelin-contracts/.solcover.js create mode 100644 lib/openzeppelin-contracts/CHANGELOG.md create mode 100644 lib/openzeppelin-contracts/CODE_OF_CONDUCT.md create mode 100644 lib/openzeppelin-contracts/CONTRIBUTING.md create mode 100644 lib/openzeppelin-contracts/GUIDELINES.md create mode 100644 lib/openzeppelin-contracts/LICENSE create mode 100644 lib/openzeppelin-contracts/README.md create mode 100644 lib/openzeppelin-contracts/RELEASING.md create mode 100644 lib/openzeppelin-contracts/SECURITY.md create mode 100644 lib/openzeppelin-contracts/audits/2017-03.md create mode 100644 lib/openzeppelin-contracts/audits/2018-10.pdf create mode 100644 lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf create mode 100644 lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf create mode 100644 lib/openzeppelin-contracts/audits/2023-05-v4.9.pdf create mode 100644 lib/openzeppelin-contracts/audits/2023-10-v5.0.pdf create mode 100644 lib/openzeppelin-contracts/audits/README.md create mode 100644 lib/openzeppelin-contracts/certora/.gitignore create mode 100644 lib/openzeppelin-contracts/certora/Makefile create mode 100644 lib/openzeppelin-contracts/certora/README.md create mode 100644 lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch create mode 100644 lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol create mode 100644 lib/openzeppelin-contracts/certora/reports/2021-10.pdf create mode 100644 lib/openzeppelin-contracts/certora/reports/2022-03.pdf create mode 100644 lib/openzeppelin-contracts/certora/reports/2022-05.pdf create mode 100755 lib/openzeppelin-contracts/certora/run.js create mode 100644 lib/openzeppelin-contracts/certora/specs.json create mode 100644 lib/openzeppelin-contracts/certora/specs/AccessControl.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/ERC20.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/ERC721.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/Initializable.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/Ownable.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/Pausable.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/TimelockController.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec create mode 100644 lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec create mode 100644 lib/openzeppelin-contracts/contracts/access/AccessControl.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/IAccessControl.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/Ownable.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol create mode 100644 lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol create mode 100644 lib/openzeppelin-contracts/contracts/finance/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/Governor.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/IGovernor.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/governance/TimelockController.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol create mode 100644 lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol create mode 100644 lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol create mode 100644 lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol create mode 100644 lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol create mode 100644 lib/openzeppelin-contracts/contracts/metatx/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/MulticallTest.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/Stateless.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol create mode 100644 lib/openzeppelin-contracts/contracts/mocks/token/VotesTimestamp.sol create mode 100644 lib/openzeppelin-contracts/contracts/package.json create mode 100644 lib/openzeppelin-contracts/contracts/proxy/Clones.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/Proxy.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol create mode 100644 lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol create mode 100644 lib/openzeppelin-contracts/contracts/token/common/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/utils/Address.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/Arrays.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/Base64.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/Context.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/Create2.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/Multicall.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/Nonces.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/Pausable.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/README.adoc create mode 100644 lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/Strings.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/math/Math.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol create mode 100644 lib/openzeppelin-contracts/contracts/utils/types/Time.sol create mode 100644 lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol create mode 100644 lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE create mode 100644 lib/openzeppelin-contracts/foundry.toml create mode 100644 lib/openzeppelin-contracts/hardhat.config.js create mode 100644 lib/openzeppelin-contracts/hardhat/env-artifacts.js create mode 100644 lib/openzeppelin-contracts/hardhat/env-contract.js create mode 100644 lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js create mode 100644 lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js create mode 100644 lib/openzeppelin-contracts/hardhat/task-test-get-files.js create mode 100644 lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol create mode 100644 lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol create mode 100644 lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE create mode 100644 lib/openzeppelin-contracts/lib/erc4626-tests/README.md create mode 100644 lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml create mode 100644 lib/openzeppelin-contracts/lib/forge-std/.gitignore create mode 100644 lib/openzeppelin-contracts/lib/forge-std/.gitmodules create mode 100644 lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE create mode 100644 lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT create mode 100644 lib/openzeppelin-contracts/lib/forge-std/README.md create mode 100644 lib/openzeppelin-contracts/lib/forge-std/foundry.toml create mode 100644 lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/.gitignore create mode 100644 lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/LICENSE create mode 100644 lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/Makefile create mode 100644 lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/default.nix create mode 100644 lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/demo/demo.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/package.json create mode 100644 lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/test.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/package.json create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/Base.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/Script.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/Test.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/console.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/console2.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol create mode 100644 lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json create mode 100644 lib/openzeppelin-contracts/logo.svg create mode 100644 lib/openzeppelin-contracts/netlify.toml create mode 100644 lib/openzeppelin-contracts/package-lock.json create mode 100644 lib/openzeppelin-contracts/package.json create mode 100644 lib/openzeppelin-contracts/remappings.txt create mode 100644 lib/openzeppelin-contracts/renovate.json create mode 100644 lib/openzeppelin-contracts/requirements.txt create mode 100644 lib/openzeppelin-contracts/scripts/checks/compare-layout.js create mode 100755 lib/openzeppelin-contracts/scripts/checks/compareGasReports.js create mode 100644 lib/openzeppelin-contracts/scripts/checks/extract-layout.js create mode 100755 lib/openzeppelin-contracts/scripts/checks/generation.sh create mode 100755 lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js create mode 100644 lib/openzeppelin-contracts/scripts/gen-nav.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/format-lines.js create mode 100755 lib/openzeppelin-contracts/scripts/generate/run.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js create mode 100644 lib/openzeppelin-contracts/scripts/generate/templates/conversion.js create mode 100644 lib/openzeppelin-contracts/scripts/git-user-config.sh create mode 100644 lib/openzeppelin-contracts/scripts/helpers.js create mode 100755 lib/openzeppelin-contracts/scripts/prepack.sh create mode 100755 lib/openzeppelin-contracts/scripts/prepare-docs.sh create mode 100755 lib/openzeppelin-contracts/scripts/release/format-changelog.js create mode 100755 lib/openzeppelin-contracts/scripts/release/synchronize-versions.js create mode 100755 lib/openzeppelin-contracts/scripts/release/update-comment.js create mode 100755 lib/openzeppelin-contracts/scripts/release/version.sh create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/github-release.js create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/pack.sh create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/publish.sh create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/rerun.js create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/start.sh create mode 100644 lib/openzeppelin-contracts/scripts/release/workflow/state.js create mode 100644 lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js create mode 100644 lib/openzeppelin-contracts/scripts/solhint-custom/index.js create mode 100644 lib/openzeppelin-contracts/scripts/solhint-custom/package.json create mode 100644 lib/openzeppelin-contracts/scripts/update-docs-branch.js create mode 100644 lib/openzeppelin-contracts/scripts/upgradeable/README.md create mode 100755 lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh create mode 100755 lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh create mode 100644 lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh create mode 100644 lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh create mode 100644 lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch create mode 100644 lib/openzeppelin-contracts/slither.config.json create mode 100644 lib/openzeppelin-contracts/solhint.config.js create mode 100644 lib/openzeppelin-contracts/test/TESTING.md create mode 100644 lib/openzeppelin-contracts/test/access/AccessControl.behavior.js create mode 100644 lib/openzeppelin-contracts/test/access/AccessControl.test.js create mode 100644 lib/openzeppelin-contracts/test/access/Ownable.test.js create mode 100644 lib/openzeppelin-contracts/test/access/Ownable2Step.test.js create mode 100644 lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js create mode 100644 lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js create mode 100644 lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js create mode 100644 lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js create mode 100644 lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js create mode 100644 lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js create mode 100644 lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js create mode 100644 lib/openzeppelin-contracts/test/finance/VestingWallet.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/Governor.t.sol create mode 100644 lib/openzeppelin-contracts/test/governance/Governor.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/TimelockController.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js create mode 100644 lib/openzeppelin-contracts/test/governance/utils/EIP6372.behavior.js create mode 100644 lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js create mode 100644 lib/openzeppelin-contracts/test/governance/utils/Votes.test.js create mode 100644 lib/openzeppelin-contracts/test/helpers/access-manager.js create mode 100644 lib/openzeppelin-contracts/test/helpers/account.js create mode 100644 lib/openzeppelin-contracts/test/helpers/chainid.js create mode 100644 lib/openzeppelin-contracts/test/helpers/constants.js create mode 100644 lib/openzeppelin-contracts/test/helpers/create.js create mode 100644 lib/openzeppelin-contracts/test/helpers/customError.js create mode 100644 lib/openzeppelin-contracts/test/helpers/eip712.js create mode 100644 lib/openzeppelin-contracts/test/helpers/enums.js create mode 100644 lib/openzeppelin-contracts/test/helpers/erc1967.js create mode 100644 lib/openzeppelin-contracts/test/helpers/governance.js create mode 100644 lib/openzeppelin-contracts/test/helpers/iterate.js create mode 100644 lib/openzeppelin-contracts/test/helpers/math.js create mode 100644 lib/openzeppelin-contracts/test/helpers/methods.js create mode 100644 lib/openzeppelin-contracts/test/helpers/sign.js create mode 100644 lib/openzeppelin-contracts/test/helpers/time.js create mode 100644 lib/openzeppelin-contracts/test/helpers/txpool.js create mode 100644 lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js create mode 100644 lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol create mode 100644 lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js create mode 100644 lib/openzeppelin-contracts/test/proxy/Clones.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js create mode 100644 lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js create mode 100644 lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js create mode 100644 lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.behavior.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.behavior.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js create mode 100644 lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js create mode 100644 lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js create mode 100644 lib/openzeppelin-contracts/test/utils/Address.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/Arrays.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/Base64.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/Context.behavior.js create mode 100644 lib/openzeppelin-contracts/test/utils/Context.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/Create2.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/Multicall.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/Nonces.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/Pausable.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol create mode 100644 lib/openzeppelin-contracts/test/utils/ShortStrings.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/StorageSlot.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/Strings.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js create mode 100644 lib/openzeppelin-contracts/test/utils/math/Math.t.sol create mode 100644 lib/openzeppelin-contracts/test/utils/math/Math.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol create mode 100644 lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js create mode 100644 lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js create mode 100644 lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js create mode 100644 lib/openzeppelin-contracts/test/utils/types/Time.test.js create mode 100644 lib/solmate/.gas-snapshot create mode 100644 lib/solmate/.gitattributes create mode 100644 lib/solmate/.github/pull_request_template.md create mode 100644 lib/solmate/.github/workflows/tests.yml create mode 100644 lib/solmate/.gitignore create mode 100644 lib/solmate/.gitmodules create mode 100644 lib/solmate/.prettierignore create mode 100644 lib/solmate/.prettierrc create mode 100644 lib/solmate/LICENSE create mode 100644 lib/solmate/README.md create mode 100644 lib/solmate/audits/v6-Fixed-Point-Solutions.pdf create mode 100644 lib/solmate/foundry.toml create mode 100644 lib/solmate/lib/ds-test/.gitignore create mode 100644 lib/solmate/lib/ds-test/LICENSE create mode 100644 lib/solmate/lib/ds-test/Makefile create mode 100644 lib/solmate/lib/ds-test/default.nix create mode 100644 lib/solmate/lib/ds-test/demo/demo.sol create mode 100644 lib/solmate/lib/ds-test/package.json create mode 100644 lib/solmate/lib/ds-test/src/test.sol create mode 100644 lib/solmate/package-lock.json create mode 100644 lib/solmate/package.json create mode 100644 lib/solmate/src/auth/Auth.sol create mode 100644 lib/solmate/src/auth/Owned.sol create mode 100644 lib/solmate/src/auth/authorities/MultiRolesAuthority.sol create mode 100644 lib/solmate/src/auth/authorities/RolesAuthority.sol create mode 100644 lib/solmate/src/mixins/ERC4626.sol create mode 100644 lib/solmate/src/test/Auth.t.sol create mode 100644 lib/solmate/src/test/Bytes32AddressLib.t.sol create mode 100644 lib/solmate/src/test/CREATE3.t.sol create mode 100644 lib/solmate/src/test/DSTestPlus.t.sol create mode 100644 lib/solmate/src/test/ERC1155.t.sol create mode 100644 lib/solmate/src/test/ERC20.t.sol create mode 100644 lib/solmate/src/test/ERC4626.t.sol create mode 100644 lib/solmate/src/test/ERC6909.t.sol create mode 100644 lib/solmate/src/test/ERC721.t.sol create mode 100644 lib/solmate/src/test/FixedPointMathLib.t.sol create mode 100644 lib/solmate/src/test/LibString.t.sol create mode 100644 lib/solmate/src/test/MerkleProofLib.t.sol create mode 100644 lib/solmate/src/test/MultiRolesAuthority.t.sol create mode 100644 lib/solmate/src/test/Owned.t.sol create mode 100644 lib/solmate/src/test/ReentrancyGuard.t.sol create mode 100644 lib/solmate/src/test/RolesAuthority.t.sol create mode 100644 lib/solmate/src/test/SSTORE2.t.sol create mode 100644 lib/solmate/src/test/SafeCastLib.t.sol create mode 100644 lib/solmate/src/test/SafeTransferLib.t.sol create mode 100644 lib/solmate/src/test/SignedWadMath.t.sol create mode 100644 lib/solmate/src/test/WETH.t.sol create mode 100644 lib/solmate/src/test/utils/DSInvariantTest.sol create mode 100644 lib/solmate/src/test/utils/DSTestPlus.sol create mode 100644 lib/solmate/src/test/utils/Hevm.sol create mode 100644 lib/solmate/src/test/utils/mocks/MockAuthChild.sol create mode 100644 lib/solmate/src/test/utils/mocks/MockAuthority.sol create mode 100644 lib/solmate/src/test/utils/mocks/MockERC1155.sol create mode 100644 lib/solmate/src/test/utils/mocks/MockERC20.sol create mode 100644 lib/solmate/src/test/utils/mocks/MockERC4626.sol create mode 100644 lib/solmate/src/test/utils/mocks/MockERC6909.sol create mode 100644 lib/solmate/src/test/utils/mocks/MockERC721.sol create mode 100644 lib/solmate/src/test/utils/mocks/MockOwned.sol create mode 100644 lib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sol create mode 100644 lib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sol create mode 100644 lib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sol create mode 100644 lib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sol create mode 100644 lib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sol create mode 100644 lib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sol create mode 100644 lib/solmate/src/test/utils/weird-tokens/RevertingToken.sol create mode 100644 lib/solmate/src/tokens/ERC1155.sol create mode 100644 lib/solmate/src/tokens/ERC20.sol create mode 100644 lib/solmate/src/tokens/ERC6909.sol create mode 100644 lib/solmate/src/tokens/ERC721.sol create mode 100644 lib/solmate/src/tokens/WETH.sol create mode 100644 lib/solmate/src/utils/Bytes32AddressLib.sol create mode 100644 lib/solmate/src/utils/CREATE3.sol create mode 100644 lib/solmate/src/utils/FixedPointMathLib.sol create mode 100644 lib/solmate/src/utils/LibString.sol create mode 100644 lib/solmate/src/utils/MerkleProofLib.sol create mode 100644 lib/solmate/src/utils/ReentrancyGuard.sol create mode 100644 lib/solmate/src/utils/SSTORE2.sol create mode 100644 lib/solmate/src/utils/SafeCastLib.sol create mode 100644 lib/solmate/src/utils/SafeTransferLib.sol create mode 100644 lib/solmate/src/utils/SignedWadMath.sol create mode 100644 remappings.txt create mode 100644 script/GOERLI/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol create mode 100644 script/GOERLI/GOERLI_customUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol create mode 100644 script/L1/AmphorSyntheticVault/USDC_DeployAmphorSyntheticVaultWithPermit.s.sol create mode 100644 script/L1/AmphorSyntheticVault/WBTC_DeployAmphorSyntheticVault.s.sol create mode 100644 script/L1/AmphorSyntheticVault/WSTETH_DeployAmphorSyntheticVault.s.sol create mode 100644 script/L1/DeployZapper.s.sol create mode 100644 src/AmphorSyntheticVault.sol create mode 100644 src/AmphorSyntheticVaultWithPermit.sol create mode 100644 src/VaultZapper.sol create mode 100644 src/utils/Constants.sol create mode 100644 src/utils/ConstantsBSC.sol create mode 100644 src/utils/MockERC20.sol.bak create mode 100644 src/utils/PermitERC20.sol create mode 100644 test.txt create mode 100644 test/Zapper/OffChainCalls.t.sol create mode 100644 test/Zapper/ZapperDeposit.t.sol create mode 100644 test/Zapper/ZapperDepositPermit.t.sol create mode 100644 test/Zapper/ZapperManagement.t.sol create mode 100644 test/Zapper/ZapperOnlyAllowedRouter.t.sol create mode 100644 test/Zapper/ZapperOnlyAllowedVault.t.sol create mode 100644 test/Zapper/ZapperWithdraw.t.sol create mode 100644 test/Zapper/ZapperWithdrawPermit.sol create mode 100644 test/echidna.config.yaml create mode 100644 test/scripts/getOneInchQuote.js create mode 100644 test/testsRules.md create mode 100644 test/utils/SigUtils.sol create mode 100644 test/v0/BaseVault/BaseVault.t.sol create mode 100644 test/v0/Core/BaseProperties.t.sol create mode 100644 test/v0/Core/Global.t.sol create mode 100644 test/v0/SyntheticVault/SyntheticBase.t.sol create mode 100644 test/v0/SyntheticVault/SyntheticBasic.t.sol create mode 100644 test/v0/SyntheticVault/SyntheticDepositAndWithdraw.t.sol create mode 100644 test/v0/SyntheticVault/SyntheticEndAndStart.t.sol create mode 100644 test/v0/SyntheticVault/SyntheticInflation.t.sol create mode 100644 test/v0/SyntheticVault/SyntheticPausable.t.sol create mode 100644 test/v0/SyntheticVault/SyntheticPermit.t.sol create mode 100644 test/v0/SyntheticVault/a16zCompliance.t.sol create mode 100644 test/v0/SyntheticVault/cryticCompliance.t.sol diff --git a/.github/workflows/smartContractTest.yml b/.github/workflows/smartContractTest.yml new file mode 100644 index 0000000..a1ba4eb --- /dev/null +++ b/.github/workflows/smartContractTest.yml @@ -0,0 +1,41 @@ +name: smartContractTest + +on: [push, workflow_dispatch] + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + strategy: + fail-fast: true + + name: Foundry project + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3.5.3 + with: + submodules: recursive + + - name: Set up env variables + run: | + cp -n example.env .env + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.0.10 + with: + version: nightly + + - name: Run Forge tests + env: + FOUNDRY_ETH_RPC_URL: ${{ secrets.RPC_URL_MAINNET }} + run: | + cp example.env .env + forge test + id: test + + - name: Run Forge coverage + env: + FOUNDRY_ETH_RPC_URL: ${{ secrets.RPC_URL_MAINNET }} + run: | + forge coverage diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc1c3ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +**/.env + +# Mac files +**/.DS_Store + +# VS Code files +.vscode + +# Tests reports +report +tests +crytic-export \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..acaba4f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,24 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std + tag = v1.7.1 +[submodule "lib/solmate"] + path = lib/solmate + url = https://github.com/transmissions11/solmate +[submodule "lib/erc4626-tests"] + path = lib/erc4626-tests + url = https://github.com/a16z/erc4626-tests +[submodule "lib/openzeppelin-contracts-v5.0.0"] + path = lib/openzeppelin-contracts-v5.0.0 + url = https://github.com/OpenZeppelin/openzeppelin-contracts + tag = v5.0.0 +[submodule "lib/openzeppelin-contracts-v4.9.3"] + path = lib/openzeppelin-contracts-v4.9.3 + url = https://github.com/OpenZeppelin/openzeppelin-contracts + tag = v4.9.3 +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts +[submodule "lib/crytic"] + path = lib/crytic + url = https://github.com/crytic/properties diff --git a/README.md b/README.md new file mode 100644 index 0000000..d1b5e45 --- /dev/null +++ b/README.md @@ -0,0 +1,125 @@ +## Context +`Amphor` protocol is a `L1 DeFi` protocol proposing `ERC-4626` based strategies. +The first startegy to come out is a timelocked strategy that require the funds +to exit the vault during the product duration (which varies from `2` to +`6` weeks). + +## AmphorSyntheticVault +This vault is the most basic strategy on the code side because the funds are +deposited by the users, then the vault is locked during the product period. Once +it has been locked, the funds go to a market maker wallet that is keeping the +assets in garantee. +At the end of the period (which varies from `2` to `6` weeks), `Amphor` +get back the funds into the vault and users can `deposit` and/or `withdraw` +again. + +## Underlying supported +For the first iteration of the protocol, the only underlying supported will be +`USDC` from `Circle`. +In the future, we might support `WBTC` and `WETH` as underlying assets. +Since `USDC` token supports `Permit` operations but not `WBTC` and `WETH`, we +have separated this feature into another contract (`AmphorSyntheticVaultWithPermit`). + +## Process flow on the vault manager side +`NOTE:` Management of the vault is handled by a multisig wallet. +1. The vault contract is deployed (`constructor`) and some funds are directly +deposited into it in order to bootstrap it and prevent as much as possible from +inflation attacks (event if there are others protections from it). +A performance fee of `20.00%` for `Amphor` protocol is set. +2. The vault is open for `deposit` and `withdraw` during a little period (approx +2 days). +3. The vault is locked (`deposit`/`withdraw` shouldn't be possible) with the +`start` function (callable only by `owner`/manager of the vault). During this +transaction the funds are withdrawn from the contract. +4. After the product period end, the vault is unlocked (`deposit`/`withdraw` +are now be possible) using +the `end` function (callable only by the `owner` of the vault). +In case of a positive performance, some fees are taken fees by the protocol +(that cannot exceed `30.00%` and can only be changed by `owner` of the vault). + +## Main contracts +### Protocol contracts files +- `AmphorSyntheticVault.sol`: Vanilla `AmphorSyntheticVault`. +- `AmphorSyntheticVaultWithPermit.sol`: `AmphorSyntheticVault` with `Permit` feature. +___ +### Deployment contracts files +- `L1_USDC_DeployAmphorSyntheticVault.sol`: Deployment script for `AmphorSyntheticVaultWithPermit` +with `USDC` as underlying. Should bootstrap the vault with `100 USDC` (based on +the `env` file). Should set the perf fees to `20.00%`. +- `L1_WBTC_DeployAmphorSyntheticVault.sol`: Deployment script for `AmphorSyntheticVault` +with `WBTC` as underlying. Should bootstrap the vault with `0.01 WBTC` (based on +the `env` file). Should set the perf fees to `20.00%`. +- `L1_WETH_DeployAmphorSyntheticVault.sol`: Deployment script for `AmphorSyntheticVault` +with `WETH` as underlying. Should bootstrap the vault with `0.1 WETH` (based on +the `env` file). Should set the perf fees to `20.00%`. +___ +### Test contracts files +- `a16zCompliance.t.sol`: Implements the tests of `a16z`. Unfortunaly we didn't +manage to make them work. +- `cryticCompliance.t.sol`: Implements the tests of `crytic` (from +[Trail of a bits](https://www.trailofbits.com/)). These one pass, you can launch +them with the following command: +``` +$ echidna . --contract CryticERC4626PropertyTestsSynth --config test/echidna.config.yaml +``` +- `SyntheticBase.t.sol`: Should define a part of the main state variables. Should +define some functions that will be directly used into the actual tests. +- `SyntheticBasic.t.sol`: Should implement some basics tests that test the vault +state variables and some basic properties of the vault. +- `SyntheticDepositAndWithdraw.t.sol`: Should implement some tests on the deposit +and the withdraw function. +- `SyntheticEndAndStart.t.sol`: Should implement some tests on the start and the +end function. +- `SyntheticInflation.t.sol`: Should implement some tests demonstrating vault +resilience in the face of inflationary attacks. +- `SyntheticPausable.t.sol`: Should implement some tests demonstrating the good +working of the `Pausable` feature. +- `SyntheticPermit.t.sol`: Should implement some tests demonstrating the good +working of the `Permit` feature. +- `SigUtils.sol`: Should implement utils functions used by `SyntheticPermit` +contract test (`SyntheticPermit.t.sol`). +## Useful commands +### Foundry +The protocol is a [Foundry](https://book.getfoundry.sh) project. +[Foundry](https://book.getfoundry.sh) a blazing fast, portable and modular +toolkit for Ethereum application development written in Rust. +#### Foundry commands +##### Build +```shell +$ forge build +``` +##### Test +```shell +$ forge test +``` +##### Format +```shell +$ forge fmt +``` +##### Coverage +```shell +$ forge coverage +``` +##### Gas Snapshots +```shell +$ forge snapshot +``` +##### Anvil +```shell +$ anvil +``` +##### Deploy +```shell +$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key +``` +##### Cast +```shell +$ cast +``` +##### Help +```shell +$ forge --help +$ anvil --help +$ cast --help +``` +___ diff --git a/audits/Bailsec_final_report.pdf b/audits/Bailsec_final_report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..21ed112d8815f52e6c730c9ae5bde50b693f1375 GIT binary patch literal 565057 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 a6(_wfW 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�J2I_!PRT9>EAU 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ℜ%u4=LRI+ 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ãK0i?db_-+P&IjdS%tC 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

j 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 literal 0 HcmV?d00001 diff --git a/audits/Salus_final_report.pdf b/audits/Salus_final_report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..47da676acb4af168778bffb97fccce6e957c0f49 GIT binary patch literal 1265032 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

>xpNpX$zXgMS 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 z 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ⅇ%|X5X2OGz6%?|$be*#5-t|O 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


QcPAl#h1o9eGt87qTmfsukp5_vZ^!oZ&wpw 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%0AQ&mD7}9DN zJ0LQMTLwa()wV%~kTsRcsOC>!B3I{1eGSX>i?lhCrobeTF~nm|5qJK{F+aHMzj*yO z*$SyDFKwgy_QgRu#UJW%klimDV!5oh8{Jlv+%;&r0QZDWbxIhF4i;dN47nuJ4|3XK z-t@blcDaM)8y(s`q@%NsdH}D69-!{azw#^FJQ|5u z(Q8N_Nt$Wmuklmj?P7cbX_}|xsCfz>u%o4WM2hvR$7U1xWDjn|P|8*+XDI#z_N8|M z=RY%_DD>$XQhAIlc8wi8IaNJX@rpQM@Ua|h2CmK&MP%{HnuRto`Wb|}=+9qhVJN+8 zQb!sES9jrHTxHzTHofPqg9Ej}yrrS02Fx}-=mKS-41ikprO zo~~VGz0ID z1Jr*MlFWQ-&&a1ut+>Za+Q&(n)lwZX{XHv|r5>=2w>ytg5;<8`d734$ZW5$eNfIN* zfvh-6zU{~E(gUYqW{N~DeV?7}+}9^?{q&s~rz)on=sb(@)3*qTki}Q+(O3OBr4d#A zF3gkg{Ej%~pVPRHS#U=eK>5^u&=v53$lW0Oi(#AXvYiHqJmnn!Eue8}I3j}2waG0A zWqfOSRbO{{Bk4_0sI+|A*y-Wo`t=Ln1%iN!t8d<{sbY=a`6796c(In^z*XE0w7XJg zMXv(Kgbm>i3_;`>C74-zv}ys5hX0Yf>?oYsAYZ86ctZ-R{+nLNnV>vFxoD3ql?J%( zp9{dpNz^aN@l?7OBO5fcii5ajWtG*fMVu|NusaOd@QL%tJ)Z{kX7KI8olaEd *0 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

<3;kldS;9YNzdkd)S&F^k0C_l`Fdgi7iHg!N~R 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

9O`DsWnOR(u{3f_Y zlsd{U`_zD^td76(T=V_yl@@EtLGE8=&a&>c^lATbL^k%8R<#_oDJH|qgm|O4SXi7^ zF)shs=5?ioaM{Ms7!JjASYv7?pHcd1>92Sk8*@*8|GJ7v81+ilCl3ujXo)vWgm3V8 zr`3C{j5qUsI3@8H?AJH*1yot!KNb{{&8ok#6orV5`5fO_$n?C(h`~?cVl(~2&%GjP zg-(=IYeJTfJXxw1F6+Fc%&lE$8ItCSt0~+#QdOkOc+Wd`&d$8RL_=K%)is#st9hL9 zO`faTRPoOX{27Bd_<=;26?dxPa9__`X5eRwA#8nC`OT=T3BvdKVwizby#ELKqC#z( zq0vdW5R5EvVhbYMQZ69kUr;e=v?S6tGt72IW(r5M<0M#lY z;-ZFAZ)McP)}BIUcrIvR4h6|VjU-Oi(J=V_T`jlee19>k-I7PVf%|L3_D=I=$11vG zP5loo!uOL0e#)eno+y-hvEd#V;6*8%D#@MN80OKWsM9iWthsrhN54*KE9vqs`&I5- z_+5N7!23$I^V3-0Vr7}AW=#`)l8CTij-$pg#P71KX}T42Pl6YbGqM-GbJoy&g@LB> zeX*Yk`@{L^DO$3U?cyWIiZ!SexpuWJdJkdM&o-FT*y1zs^gO;ryy^&$=*J*>dv%b( zcB$uAckmyr?c>+SpOvn=4bOXcOq@CfemrN0Bz1DJ9!i^dXY;IoNu+L8z|f>%;aa-& zBqk@5%G{5QJ9Uj!ci&^)q_XnP)c$FPxZq>&plpwzvVXU2skZr=nP&g-YPpFoAO~Re zz#dsYRb}|-3(NnFaahnxfk6KB@P>4O-W14Se)q7WhFgRRDWbkGU$Jzz&ZAj(jy{#> zS6cSV=BL9y$VS=}X|nhfX0x^y`?s|lRvd7>5+)VhuIw>19RD1Ko%g;3=*5#n@l5oR zbc=(SWNKVB;#XfS*sNmax2?UYwUX-;Ce)wYBa7o-`u!h&oMI32WSj>_9<# z`|hvDCL$pq6aJAdN{jA+(mxSm3Fro~9JB1g5W4h7d~Gd#2nGg$zh0>PDuh<@zxKmN zKD43HHm%_*iHgn!%fD(1Y1)|p~R?ydxIlaPZ^xIkMH#Av9hpZmZ>UnxVKX#^Djy@YbTG1^L zRtjj;zn2J(g~x-c{@jLSQt7a?R>#=}Vwt>wy+*dgOfUGwYvrje-|YUS&1!r(`c48u z)6{iO{%3okKzziu8PMPT4gByvW8%De4zv|m5vjU=`WpYMO9dR~6^)Qcoz<_Qc{gHf$=*Vk0v3@AB4f{to&h{`(WBxi1ZC`BjOA!Yhy!yrkaJ zGEYFV;otV7^bS~wQ*K$toYIlS0hXCdT%zj(W&bk9_VibJT&6Fy)CQ^a3S_eW7U26& zW!eJ0DN*@2$THMwZp$EH3@+7%4Q>8Xjjo8Y@&qf+Efn*f=-9C2b=r(k0hV!gh1~Q*2J>!`%6=z_MQ0yx<<_FKhzh|0 z`khiN*L-HMoAgiNmj6w<_wKVitw5&1avU%^^`|o^)t2bBZDEDnSGRzsKg;}r3N`{O z^-aG!I0MlyYl^vw?IYn&=}ykiC$>E`UBu%$tjV5`VCouVFO&UiOackUg<*l9o`a@w zz+TIyCCS@YU8zkA43+Fv*D!j+2rr+8Ba>g)2v2dR&D8+?;+sAnev#wL%7ycEP9Th; zkOp3uuMa+Nh_#2{+6o|QA$%u)^G8_I5D-kRqmex<@vv304F=I&^hmM2wL%v`M3@dL zXYr)*r&AAMiWv6*FgH9qOBvmtuZJid9oV%bD0q-exVDd=W3}MRKEVhrw%<-uqP^GB zAbJsjqG1{UsjW1uh}g%(e1Aa^z*$x+X1u`d7@&rRigFOJGrwQy_0%ChFLEq0-Vz3Xq| zJBD!$I*tb8#X9!->uOCc6#$;I`&}O9@o-*k4-0zmR~vR>b+_i z`$j)A3+7YCZWNfgqtyxyy8mz;lR^t~>p;LhcO%oAV&<6YM=WtnQK(yS;ztkX2je1s zE=H)A_ZablD^VP*4y+(cWQXxZo9NGyYRnQ)P0RM_2lLjB729pQ*c!z;Js@HiEq-GCz5Z|YcacWmx!jCCOPIlMkBdt79-{U zTqs^Dn2*`);mGIXf%s`nCeo(ZUQEqQTK55*h4p(ZF1xtnoS~a5J6_8YpPaR7tFSaQ{~#NGkrf1|>q#CP=T`vG$5ae0DTEma3H%B}sKI~iC)O?Mro^l+ zH9L37@ANABSDX_z#fklun<|x-t$DrTWE#k}1z+JYyZ-69yX$wcH*i)x^T~RB zglidf_#{hn&>X@H@K{H?t`nb${CcO$j)xm@{}9cM>vOY@qk2}W-L8$?a(}hKDXn|`a z&whH<^uQJ@)}U6xtXMT!&=}ngy}p0=DIz1z7|6c8jPTE%b2dl2l|(S7KPl&-(E04) zsVdqoAZK6cB+sWsJ=MHdal6@G-s!c%eC#R3srxaF(qu(RRk5=57N%#4J!8~0n6meN znnU|`rJ&Bp0ao5D0N#L5#%!oo&Za z(h|}WZ$|>dN1no2uI$h5Shha+w=}a~n-AL5vBB`vi#G&;B!sxl3~;l!9O}5vF7CiA zfn+dvnT%>S(W+?mRN?+Pg(&;*h>y}&7eUHY#iEWw)jL}g4A53A87s9Q3qG{Ly^yBi z;yc!A*i_v^{+b1+73GEHsY|exd5AG*v_$)5S16yJSg|`8dNV0Jr}52-!kcLK+xuw{ zyEfm^4g}oUI1sk&JtC&1)MYua3XS>!E8sN+QGUzvy?> zLk1Yw9SIb2sIK#KJkcK0a+~L4nXOqH1I_v)MGKlq#v)M#mv>C_@0J9`U)b;`dGsao zHU`wZE9oH4VII@Tuy7^Y)oT#Dw6;T$P@4YrP7~-%pUJ9?E^1`gv)HkuA?kOE@%G}% z66_@3?#lYhF4k*_-U$N9(5oUxy#5)(1v}DDD^p%lmG(z-yJw#_G)G{W_oJe%^yyio z8-DH6PVMdO_b}a<)6#;R@F3djfG%9qyHmSP%dBGif|00Efq=RoxvTXJ1!-53@Pogw z2voQDLb&yoSKIm*UOjmV&1xax{!vO3z7LPHn%&sd-O$fXnsS+U z?D|Q(|Mn}-JnERSzN<`ijQ39cHX4 zLD!cF`=!AV7Q-25YjWhvY0;Cj&^mJ+?^AFYSQ?CriH*obW}ynXV@2_$nDN#aV%}Rp z9|RlV;l^cHRael_x!+>*NBkp1Ij(Nwxq!gN!lc!FM9*>@u5ax@ z>}hBRIKBF}U)M?ZsOBEe3lqusWuqE9CB?TF0R+g0zv1RY%f<2GioL85Uyh4?9t)s9 zHw@!knC_8N8AZFoeLBr?T2Fu~`LymK7fbn^KA%@{@lD{`I|JaG7kuL5eu$Gi>==MZ zEZFyvR1gu?Qx*YN)7XHJ6*kQO&gHvj0pvRFB1fD)o^D7WvVeY|%@}_j7r_;0?EZbB zqy@TfJ+<=#c7IR#S|^8a_e^EzrGNV9^{X_*NYZKW!$t7JX7K&y(=>@wju8Rb#a9)> z2XiN1NvH)x$Io)kxZQe ziaz|a4bx&&ZGqpa{z7$6YhEqw{RZiwvI3!?J$&)5-#y4WN~w>0raJ%mfaf0jqW}WY zWuu0>AV5H2%?r|C44D&0zF*Q!+J`6e>NP=-irbpHDZKHM@+T<-sT;?=~tTy zi)?2w6sMbqloE)Va#K`e+ zNm}TYEn-%Hy5*9@N zQqgqO)l>-gKOJ$)?p(zG5L%XgO}SsdY>Q4SPUy3gr0JLqR1zm|6C9!u-Vy=W z&z_zRSY!e_nWt->O`Yg-kdnd%2PgY@Ekgs&-YHyPZ)@^j+nWu0*Kg z&7_pfuzcPOjh!S@zdMB#G2mCo@>@f`1x2SoxYNYgrrRmXOp3qzN zul!i$mQiX}5`U=TTH=abuwuiK&AuDKUjMmZJb>eVl-k>PWbDG zzIj8Y{Fy7zHQ6e|a}Sc$z}ebr;*(rGmVmZR)ggRCJ`wzBLOgzTxHeUcw0=sLDExT- z9nbc~4bjn5m9l+G?Ul)eklN_Jnbz29qORa+Zy}ewS!%l=N2Bss;REfR&vwWCp)iSm z7>2<4Vb0Nu>Y-V!wx6eRF4r7)cH-{V2r;W<+y+-WP#L7|g3@QdXOt@XK&d{lWLfhBf-%v{^Ie1+Ws5(Wji_2vCa5ub%{MVPE3!;VN^Hw|SmE9;J|5R!y}&|DhpV z%=Em?eNVwtl$wdPJ_EVgqu1}bpC=^B!HO>F&|x|V)Weo*p> zyQlKE9PI$nnL_aeTyM={+Fu45#JK9OJ?f;YCNy&L#O9c1c{xm;eIV~?mY*(h@n2iZ z^un{a`7v; z)GaZB=;cU3DhcFN!c%Z@<*NBwas9+1CHHesL;p@0lM?R+TB& zk^ApZk9>%$b~&y(ONIQ8!g!gi_mNb^Ld}L{kUzu=JkEJzu;A*`nk`Zfsap8h+|k}D5g@R~tN!bYlrz3RdX%|k9ERsHulMQBcF zyyMUJdc^P|i>7$eCqF&$h~&Pw8X$ftS591|Q3hYc33)4U`Q7a!Ft*C#+#vBLr{e!k zGemqK!7A&!ln@s(MN{tgK24U9lk<=}9}ArP*fRH5nUz)dC2DxQ<4Ksd@@z_rZLU#5 ze%-P41KTVV=^|)mK1liRd)*okmCp&ne7)(u>bj}I5Q4&KaM6n|8#@G($)ut>Ys&L( zdg<8#w!4xd*?gPH{#yDpX#qx{z@WY|Qk zaH)DK5xp7qb6lpf08>k9oHAfN;8jG(9J&nL{ClmRq;oyXz)_9{C&TbO2l7s!z{+{UbOlCF2yh{@N;+U%VaB2oV5xSh|41nVzg_q- zXBErwy)n$_+jSqdkpaKRmzO_qpAi24xb(Mzqi?HL)2)p}$0v^GUZKm48k@*hrv5y$ zwyUHk?~AOAZhvUOzB(g0pIKQs}6cMz&cvO>YH1{&%eE=ei;@9a-pSt|QkRjd&Ba zq>Z)7TOKnHE=A~>x8PU0f&V`YPO%HC)|#&NDO2ZjGWG{sI7dAN&>VZ01$>)lK@)}; z&C#r}h{8jjPR993>Gr>6FmAG6DKoao2$}<=sMFgnUD#_6nMOBBSgh>W6l7$8;NO=t z$3qupa1)8wsQI&U{H-B%F>zyRd}T8*+Kdd=UYqIFuk=6i-UA%YZv7h-A`uZJh-k@( z5+w#>%;>!YA$oLC2BVwNYlxEQ5xsXo5Taz1AR$@?QKLogy_W>vgZJIv-uvDAfBnxn z-*@);uH#yl8ISec&sx8A*R}4o9_xPnV1v?UvwTtS_JdS0)iKi|CFb&IAo})TPZrEe zKUWCR<6fuVIeE?~Ht?XPly}Agi;e-YFM^sI3=kkhv2tyZes#tjiiuVaa~*jxNJG7c zj=YQEeu~u!%F!Wy4T)$}U0Xff%ts!)F|Xd_BX{S-!ivw6e6S+f`fq1sah|ZbM?6*G zL&fbfb|dom8F;W7s?-?|!)a4So}fdJNol)Mwhyn@7B5xK;)`6NN+x&vDeHtNVkMVP zP+7zD=&k*R0*5%2nmsciJ|j0lplQc%|1ByfTIsg#Paq87cUE-&?8z2VhKy$)kzPdv z@)5lNoRs2Xazcd2Q@-1?#DU~OT-aBfa=INKdi3h(6zAlkzg#_|g){MXL-@8=o@G9h zrkz{ocg&Z{Sb0s|j#aU$n7M<++#gXnnA`f>Gt`9F#h*R}TXK>#mD&x>IWj+8uDS6< zY5rr-dUs0NToko}hHNz689}~Rx3L{u@ovsznmj$pI{`8*qe=|XE6~B;kI>V^aJr4{ zd`9J59%T!1Lz9--vi-R|ys=|8j_sv3Fw3mFvX!*o&YD|< zciTB5c?W{RvEA!}X8o$+c^G!{m)9SJaGd5~W)j0jJ~;SrC$;%mFU++&3k{O^v7Df5 zoE&I_ikB^qP@PO~8sE@9)vBGP1o&i43yE1nY6}4>rpTV}RouWY!-(~>#^X>DOvmqQ zro@~K5lAZ)l|Qr^89|%pVY=iy>Y#(83g}U#M1|tTw>)$=D0!4_J9X^*uCGA6ffnz0 zSv9g3DWRmoi>p2(kZT9u`EOUO-CCX*to641srQ49Q3c%a(f;fa&#yPFuNSiDxfWLE z#Kw6b!B%!kKLi9^7_kn3CIG@+r*s;X#H>O=8j_ET{_}it(a`4d*y8!)wXF_UFR9Mk zj9y$(G#nXP+Klw!`flE6{X4UFU2VgAk`vf5&EKGul^)+ET=(&ku- z0-+<|pXS|c=S3E$rpyrsbI2x%4W@<)yfJbSp#Js%{W{Lc38@>teB^uYxOgp2h4eCe zOTQBu_M~!#Fh{!hJ+LLPceG7xABt3R!|EQE#U;+QSETp6%+-TDTcfOtIqMtFKKa*D zx+`@tDnklrVD_PawK-N0SzO7J{mgr2bae7NrVdDXnl_3%e^nA1w`6I!-63sc^_Kci{A;V+z49FJl#?28HN-zmyHK@h2$gCDj&dr#8o$J_5>AjSb_Er%A z7a3gz*5!p!Pb)iH505oJ=pYrzLgr(5a`=N$>rT$ga_Z0+B(kIL5HIPZ-p4ZZ-J5Z|uZonNgEEA2|?knP@4&Ge4PXgIMWFlpw)o-2!y5lrkf8T2~k zpm}%x@CZaeE(E$k}g#i_?y*l>JlWg}loEovB{M*vY zXOB7nll#VIi0UNl=AeEIlqK_Ki(&Y%h`T8Ya_Fpgb^P+cj0DZj!V-!53nL$)yV%?} z_;AXDfQPRV3*rMy%WS&PSuHj{fIxD*lC_D0vQ~teJ*8O7YNHwD9^UaI)g)-{llh}Y zeKwB%D!&-cbywAcP|P%YhgU+Xn?Qfbp^e#ps2*Hy-PAd52rz2koURHVRk`p|kA(#tRR>sUFj z*{P6UraykVAZo5%Z1f|_x|6?1G;6H24bKOS*nXXD+`RbhyE2DeEJ6EeJMxUU=OpxHhoAS37D%m*zEm}WF#rV|a z<0qNAwU2`-#K0RFrKb2a$Q3mz6npiHSO%KMT^&QB^hlLoq7{2@F?k8ajOb_RD6p}G z%rdr=vczR$?z=docNoI*CekU}^+PxeQ5~Mh`XodJRk(RP_*^^NGc3QJy0kvLnxoTp zS5;Y#O4Z)f!`6I8uYGTH2wD6lWzJm}3BKky)>YVh*LgV0);wkLXnQh}ChVY1D_$w* zP%qcBWxJX&p{!P2L!tMfe$@>VL}DjuQ76`XWCg`h{V?uC_6@j~n<(f+QM!T=*>-&{ zx%YvZ4OH{0WX@omZc27?nO@H2mf4VBgBl)a%6lmu%F%#dv!(D89DO_%hMD=896pUY zA452Kb16*#kNJ=u8x>LsnD@YTJwhX8=aq6W*zW+tF5B95?N;>wUfUO#K1a0-M|EPB z87eFZD_0}D?u_wHyGI=G{Sj?MPMdlvw(n4Hn$N4Tq$HrzVK}+h3~eLO%dF-kq#|pA z5se(C%lJOS&ReWC$5KNP+~yQN(HV+r=^2ed6RsuCWyjU-Y5rjS@DBDxNi+dW=^t_8 zc&-Y6qc%OP15QS@ftDavu!zbEAp>hSGlu9;DEuQM)~TmwR4H8nLRUkLMP@Y?Q|UW7 z_nTK7CF}R=pj4a-)!!8AP0GhGwxm$aYURw%%Fc`A1^KLX>$^IxrJgCp^%(8I6!BZL zLXINm*6L#rC_JozrsP{7>-q{d=Ns$6Cn#L>F*@Id`wSL7+!9Z@CMv7*XmCRGjmP1TCx;l7;ttd-xk)b=~&0H~&&HT{W_(NJP{8909!&Jy(hx=GXII?&rVNM>2Tez)C=EHw!7qDwuf~p0qpf-=fcY?9?PM38IZ+^ zv2&FXohcf~LvrMrE}lLleuB5&_{BB0-E`4l)7|fBdKWl=y(5nK5=&w^)I?ORwMW=1 zzdc5$so2)vls{_4?BRQ$1pyOIuIrtRiI!nWg1QvkY*)&e-P;>otc)G4n4fdb?esbx z9rdZ_=~jt8b83|{SmxowuY=vrH8IW;dT$@YD-q8XW#_@eNh5Ts z-NXC>@KK~c%2~IgjvoKT@wq|bz|uh_n6JZKg6;npCF(xswr?_Lr&Yq7NH=$Ma!hrMV zKK^>HCy<;LD#0rH5W8t^+cn0GEz;GFjiT<*geS<7N-ubx2MZhOpZT0KpBdBK&>zk( ze=ICeC7S)LrfAl>@CSqe3mm;57f8OcjwN%39&XX!9yYS|DDm)_BXN4g!~ zpm4qi=j0X8yKihbT*5o`YvC@NIGbIom?9PY2qpBCLK%0}!{|Cq_*C-`hxhE~I(4Hw zlMm+Q^06ER9I^9{0)oe2U>mBExI1MuXAb6A zYk!xzW3V=sU0_$Ub#vYOIm-pL89%-PDvW7%Y)5 zSOQkhnRH?4VYhzY0P0f>+{M)q%!J+T=^cGVk8fz@uX^;b^0AFS3Kg_wnuBmo7j#(~ zRiw$Note@5ZtaX49E^Je^ zdi#0u=jdh@8ViUOC7>;35`U>OM7w__+63ZjZwEVDt4ED-AsqF07r>)2Z?>4~#`LeL zz9jyG5G^}~_Ky5EL$_DXO?jQf5vat_6LdaL(-T0K$ahQ{Fht8Zm(FS?CZ+Tf@(HD;XGkC3GAS ztLt&Dd`DceI?G~8>YL=4?LYauLphyC*u{c{L;8n2x&@HE9L(I$NWU*sQ-J@^gR-sp zQPv9>p|ttAK-u0=K0#~_ZHfY*GVZq*dFb3FaimgNV~>d)%*G7XMsp&Ih@~-i-VmG* zh&QlyDE#t%$9}F^nPi;1V=;ZQAgZ_`X-+_}Io3QEbDV`<1k3~87@+LNhY4nPex7-r zRYByQv!kPKzDi)t9i{Q!omN?2rZajCCCyhtXi|9$m*}J|9))aEXFRS9?+oJ^*14;I zW(`w5qRhkajOcU%A<-0mOl)3Fx~GC}$C#Ll3gCil%jcL8w*bdYTxg2l_$ss`%XHPn z^1il$SZp|40%-r9f{nG!eml@+-*u>izy>}hFpx6Lane#iErpJJ29 z#tBjRmf_5)Mj}Ue_~(7yC;M7TcBK}vr(Wu?voMN4+HP@TS1EOED=J38m9(_E7$up+ z4iN#kaO_+eO-Ax)Mh(gi?4w;by9te>UNAse)*-Q&hO%ic&z-#Uumxw0&D*ES>q$A* zm#reZxqcP%1zPn;RA4ZdT^O4KINLT>Lt~a!n6x=!nv4}n-Md!)C>h<3k~~Z(J^pVE z@>U9;ejg7R~0%cYJe0*C5wi(*^Ucw+}FGn!eSmTYQ9CsE#;UIq!G_L$kw* zY({liOLY%92AHRr&&4dZ0jltk_;9k{_6V@fKsv5)He*<0u{6pb6KiPakAif2t+dbP zNDR@2M(xF?pdtzfj510b!%0gd7o>}%ozd8)(4OYJO zQ9YgXk#Hx~4C|es@OS>jL8%YUA&X=RHi2)jb}K?L3@B{hxuBKD&2`eM+FJ)6z;iG~ z#vL8QI;p%)Ypyx7ZK<*Of{tymdMf$6*zZmKJFUBSkH4Q2dVcRYBxUUf5SNb%3%D30 z)~qb(ovuJ#OdmDQR6|{$-6=|F*}R|!r@$=fNRoi83fNG!;D%LaKsZ@e^||MV(|KF! z^(@9OpTu<1BC+P#Bk^@E?Cuj@38a2E!E95cUo;?^P%$BfUVSdqnp0kbYViPe@<;zp zx08zg1)IhNPyN^v9)dh5=%e^JU|ds#&|!#fGfx+MjL!N39Ta58>h}z6fv_4+Dk_8+ zuqkNUwL&Dgr6+kqGcuT>Xsp64+5C>foy_?Qa(WyuGjo<7YhbD<766xS?OqB^so3E7 zaH`q&719Le97hOdO=B* ztlg#1DzxL;LZly{!+}hox|{7(l7yALdVAk7J+<~HM4O+r@tQbE93_fDx7jTVKiq2S zZqzzAEjS;GSi(me;B+1ttdhP~U4Xj-t-0CWZ^N-4(Fu6mGQ+JH9_kG1Jj`#m=GZ}~ zL|YySsi9pPGQ~hu2MLxWF=;&43=>M9S<3WeVY>+ri4WY&MTX?jhWAwMfi-LIL||pg z&EBzCJ>kJqozmH{9=$CR{CqtPT{<+>!Ia6K*7{<$t>IWD_k+GmM!Q`4NOG#l+3F_o zh>rJuq@M#IbEyJ=mni=W2=G#pOqyeXLw6t6AjoxX!SsgYAry6@*|d~b<3-N-8i(Y| zuzvL?bKn$pR)*AN)m%Yg$=`q@xH<+*stqO4m=m$`CDW&Vg1gvKMzhb6zn4VIg{vjn zpoN^sc^7pS4_{t{m>WcXT;=+*+)hfbzX}Z|DGEd{7Av90UI3Kpfc>fE(5f2YIG|B3 z@@UWS;!O2?)}nB3+M(Ko1O=kY=L+fh{LE3RF*TX*a@W_f2(hZPxoTZxaa_t=58yn+ z&OrbvRY4wVTe~SGP7kUmu|zkiYTOH@l@9a6p}*k2RBduugNc#itc0%;u`;9YWD{(8 zB!vLKf)nwm@pT<0I_qpgzaS_~83F`c)C}J4&kxKKr?;6(_0($WW<${$*s7J*ZSETv z8p-=IA*VN~7Q62EiU39>%I!((Q5q6pMl;m7qjBJDx~xjnX>A#~W*>M!*+Xl{qR?O6 zW4(Nw!Ji~pHZ=m9yJ%EH*X-e^QYgR59V~O*_jLI1c#Z>q0(nc%y*&myC|C-NH2#kgKZT0c@4;!w~=YaW9GSnABtuz zM9-{KA>G}SBpb7rac9QP!PeHt4s1wX$eT09`;|(Rbdi>QCc)L#Rsd#^(3VwDTAFjyYbW?OsVwnb5c(+-0U| zRG?jMHy1{$?YF=Y=WvJqLJS)2k;`PP|0-S{uCz(aEnxF&KyNRaLaBE>0M{rP?Fa^B zO9&88??hel4v7kI)v%@Av(P++aKpA>tN2fdpyH5M=aUCGIE=yfySA-6AddPm2)PN? zL5B~Eo{-eAz~07ZJ?@KQkM4{$ZMV&sH` z!qyb+h(Z|IoPD!1wj|`^262JTz6c3%s=L`EK%81nj4cr+j)a_QPR5SsSLAGr%n^i~ zPm!jM79ehJIB+z@BLvdi!V$#72PNc`w6nHDso5Ku05?k^oRKC7S(K3*A*Te=5v`0s zN!r=i+u0&)9YMf-GDvGj1Pa6{V{PP!kV2T)nF53#BW%q9%1{_YL)(;F2qb69|pZFI`QfK?>hO#zb6MbY~FiFs|+y_@fSs%)WD7jzbaAHqrdT-^h)D&WTEiqlan~!u_9tVH;r9V2_2P|cdu37R2L`(7w)Wo zYq9nUhhdtQ?8>TN!LmztNCZuus9VK69`=95SjJC9w|3bw+hbRC`g62-^|%r)C+-qg z=TZa3ti-S>_(e#op)AwgxY5K4C&vODsbYeZ)j*q(XOtlUQg5uE3(I`|b?@mEe{RBS z!PTQn(zbI#1bs>FY(GZ_pDf70y@s3Gn^m><(S#{qXEf}FV3B#YQW+wZp@lZDobgzm zecZike~Hk3&Nf_){#P_S=7vAROjm$gcm_Wa8y2{#n?4hw#S9heQeN`6)8Xma#Fd?6(5 zbQMp`E|zTgW0zTh!O{?=z&tv9$VUcV@`=kBhL``9mhNeH`8Hd&R^eVsXggR+=p{YI|lPf zI*4pV-)h-DLBk-G5g~I)tWQFjw(Hb`35?$n=QHj7D)+Wj>oKhzd=ru_w;3?9{_Mg0 zP{>2Mt6o#`n|CbPI`kKRED9^D4&P^6xV$Na*cNzeHm|+r(qQn@&4G;1ETI+dsyW#l z8q4}w{#|F-HmMzcn z&dOnyuDtm+UqOF3(Bjo|95P}idx&?>wK!g0$Ilg+Q9r#53f?Z*+6|QA1YD1!&rZH{ ziGoo~ie5c6`gJ<}r7haw=cSoRW4PqE0=yd*K6`??N^iU*jJm``IP#oIYBb>0=Tu3J zNc-+9J9w((w}`2Nb~7U2S`SRdXu8P0R!5hZ94~8~)`vSK+^w?zHV_&%c>Lp@)Xhk7 zT79W2kDHHO(>!vtcisrIV>_VaLT@HCFIjn=W{-}~>~{@}c~6M@g-&zW?Pu}|Yt^c1 z{E7?8V&nLv$*Dj+e6YUdtI;@n2|TDwp$7*|P6T7d`Les#!tRVb9}VzM7S@+E>^|vU2Bca`=-|DW{Z(MiX z?zh=Uwo`e7Vy_@>S>F0AB9(ut-+ygE4Xw&szm}-Vf?`WEjM!58nd9j_Hk&egitEn> zar&z+{ySBC;Q}b1+j~_6+Rh1OfxXum$jfE=-Fl9A}@&dqQY4fMT9BR zNW#t)q{{_d`xB| zsQwQQ&i|g?5pv3MLqS0K7d_<%@&9>Q2I$3E?`62T0axmxCo!6UpEoW^^>X}lMl#(R$a-!l&HA58v_jKlkH;p07n`#%gHFAM~fzrgo@ zU(NGgNEhz~a2G`iKWDRlMuh+0 zBXWk&e;N^95d55-&uq;9v_t<&g#iDD!$Ckf$M3&oli=t2?S`ESr=7aH{MP28WdE9N?&=!9s2Zg}FybvC40EzQ@?hr1to2!wVDZi8LUx;$^ z!N6Q_$eHw=SGMGJvvjeuGBV@lH3cePK>XK+I=We!xBvn2KUestCh{TdtWXyAFf$m! z=`WR`e0*Ry41Q+q&mV2#0JCs{I&(Q&SVBO$e=y5mA8qXdi?X*4Ai8cMCHMTPQCO#{a>Me{Hra#M%z-!tLZ{VG8@FYJZUB1w;AH zl=pcn>`d(4ZTL-$U0^Oqp!x-K|3j;xV18iW{;Y56Vr9(*%wIqu*8f}|;6^An7|PFm z#-r!NZ4nkOR;Je6FmodS!V8i40}=>;%AefG?+)WbqM%%k+)e-z|6C0M1M|ZnXZZZR zbe!qse^42cMvg|-cIIc&ZVt?@@SO`gA+UCW1|oXCb9DbsxXzTwAGcpDlmJE%&IbWh z^?x;Q4hID7ALh+HuQ{q~R4(wl6mZMsKqQz(busz!#t33Y|58ZQt8dpd=>65rK=c_= zcl@3cL9|}J1%>fE`7Sd#M4=K|iA8%3k44P=syQxNbwQ52=$f>8Qa|z_dubKDhQ(3b z->TmYsyLZW7EJ!I&+oDRArEbP8~-x_J&zC{V-Xvem7s{?$H`1?g+)s5GrRk+M1rrVpUN??oJ1=#Sj+tS%d3?mbe85Q%K)1Y0M3TY6_~o~HLz4Ti77yZ2 zJ6j$Ei2Ca$2CK_^j@o|LyYNmB4fA`KKv3y<|C1NpPgZE|3>|&9`%=Xa-HqQ{cl;tH zHIXN*LBWTJezojU*8n}1mF#s1#aD$SVZ1Tqy=qNR(<#va=*A7=h|BlHhn|lsZAkuH z%kWaG@(hlgd-B}pvQg80j-D*i>}yw4?%c2L&Ek9e@nd-I}b2MJP*0oF?Um`5zL>*82$+~tc=Y(sPFVEhA{B!1Kbmu11 z@|W1-C#K!1-#kvYmJC~ez2Np3LrnLv9vg8aa6BjPE$41kV0@X~rQQ_k6t-iO4j&kS z<8sy-HT6bJKa;_IC-z*0$k_gOxoI@+XWZ?mVe<{ozMPlMV>guV?j(NE_dhvqPr|$` zOYk^x5Bq@7P{gu%-pa{xK#UFJpa}wnBwodC&cD(SYl&~qj#k!)$W2IU_X}mY$tL3* zeYuPL?VW*m!Y-n>cc7_wUD7O+sfWtkY%(`CtR*-$tOJ6F@K)$G42k;7GT9%G(+=aW z^G&qimN=$s;*iU$@E1r_h~-n=$l!)5dC}8-q)5L{q5ER#(z3XL-;I+cyM8MhFQ=RL zUtij}sc2h#cSgLiYvRPO7Vmo_PD57uF+Y)TSgJ%zhKTQ;m@r-u$HGm=%fiFwFF_Urq7h~D^JnVGTx z5+D=;GJ6{7@Z85K3=mbD?&MT@--Nz-KMkuvq#LDvP3hxbTa{HUsq!F;I;s||eYCV6 zYMuMZ&q4^**L&wZ#bAY-Jx6Jn3%2POLJ6SoNfru(qX9Cuo>pLrI_zC#=Vbq-XaLOM)tmZ^9RgYgmK2h8LlC zr0GCD5BiyWi6vI?535y3`actVYfVQvsTmNqkel0&lx^lZ>|;Z$n!Y!SJD6@#Iq>ag zE?{p2>!P||O1gq`1Z`VUW6I*5Yn5)4Woe2`k{ zBn;NqrflwfM_tO0rMP2yxp{Ag+QI9Hs+2>RrC6bhLbum%YPb(p%EZf3t>z&em!$~o z5@CZ0`Wg2sikEWdC|W<_XBf!4++01QZ)}57e&_4rq^hiELlUe}nXZK#Vbc7OZ0u&N z{P4|-sRDlA>+Hu+M2OqZxGs{=$tI`U4LJl@7Qwy~f+j8uI<(YFuFNrIqOcRnme|W5D zR@FuqWn(?{0mGb?gbs43LK!+(YjKsgMHbohm|j?l=VPWLrtlUG z<*OEB(#tLuUUA%F`prU*mXihxt%*jOMOshT<31P7i_CF&UJ~tmvQcvVwM71V*@J`) zp0IRe_h>OD{ZOige5vxZ`AB%Re(WuLDa<|VC-AXb7(N)VJmrL}o;{Vb$}gVN)rjky ze)n;`$tC>WkNWk>IuGadYNz?|)hcV6aRKM;h1T~j9o-Xiz9)(_@SWW~M;9k&*Wtmc zA}jroDd!@jt)=zb!lHZweGP3DgUSM^HgwS`-}Q4kXH-b_E;8Rj!tQx4JqN|Ffcy1< zxW~N2*TQwdR*1U7>>tJz)f{F0>pSSmTPTle&y-#Qc;s_!F3Lyhu+|tS4sd?cpwep` zWNks-1ZCGmUu+tyrQ@LjU3XHiq4Y1Fu`;Xf*T1YenkQ+|M)z{P~gXcdtl>Z6+v2KvP<)c(UIeF8AQIfK#PyEU$Aj&%~8oHwCFOY zwAP0h^An~YD{0{eu)Z*`|NIm+&zRNln2T}xEo3?Q<|VHq|C<5X**UR~x%!FS28x#T zp4CNN(_6K;I>@X)pn2a{_gBgdFr;z}SA^uJesZjQtpciT?DmlGO{zs2wgj$(U^Xx5 ziPj0LzD8ytzq+wWHN9}YL~9*f+xFph!Py??JNG4jG-wc~cbesojelQzo@>gs8*{5< zBl0_oyPuH_S^S4d3Jd%NMXsY=luO1qh_dsUW@Zeb4Cqdn-a^aw-~ol1TddA6O4QbH zNE`>M-8qD9NxJt05fN!`u5*ylviZBdYJQ&`bxnQsd4+}_$pD|_phV;?#3K>IQt0H& zN~#jcBBd_Ueifl92y`Iqf zV`_`4W(G_JU2!}TdT$-lw^(^Fnxa0r18&zAv_X-kZ@;=yj9O+kOumNop{&Zd@M|&ErO!{1Yqp4ug>vzp#sz-x6(sdHyCvzYn^T^AvoF=c_ zoL=E~d+B&_UE>~3Rd%_$@@vlBI@MF`-knN9U5H(~@`GPv;R*D2Pm77$9wf{#LEO6A z3R}n4<}*qQdnKdZhTz6VWj{WMAYbU5tt*N$L_a`5?RWFXJlEzsEDSwD= z)r1onS*ypT^R?cloB6(oXSY-G!eZKHQsl#v_I+{SXo72TA6#HnUn)Tf*{ZJ+hw)M$ zM=LA2+k&!*`i5G?;-7HV_%v{rDw!k&bX#?25DlmnfVAs63#NE3jNe1UUKq#s@-bc)&;Fr-|jw~H7!64KWm3R?=DxUlwK~cy&`Q8kT1r` zQ0EA%AGi{@hX%dy8;G3!CUB`-+yX(Y(5!JA$L1MR{+;Sb=ZY^w)r*PItIGEm$%qN> zCXB|mO>|U5GK?UAgPQ#7Vj=f=SdeKF@oyDCt;_imv)OuAP%*ts-|&|gb21=g$z_Zu zmd%C3c=_sB?S2W*z;|2EsbefhopgVD*~-R26qI>BUZ$dexR}!k+q?^~h%BORHF@v( zlC5og;<=)K@#^!;enKWe(vqee2pj%ART>uR!`FI&ZFu4qZ3yox)jS-BR9B3OYU67i zx2CRLu>y^}F*PORmdM<9s&rwc;kBURsC>vE%iv3`BWvTqBc~V!{`nb`-|^$vgt$K> zW*!?(_502%Iczy|#pU@V@vZ35_$eCaUAGUC9%I@ft5qhs8bynPDzt4f&a30*&1_eI zv-C6?S)$pag;d0ihvymcZH)C<}5lhOq z70E=2hpA5UY8x_@{7`q{RZXRrfw{W{-d|LF#*pmGf1QMOHR@Vlh5u47ai+w0l_{>( z$`Vd0(KBlWPmwQv3hNPEJ$1o|{)6UH!G@Dv9Oa;p3L&CYO?M07GLJ40uv*U7_nm=j{$iO6sI|+$jHE zftN0&W*3>#6fub%DVnJy?N_mFYPm|cB<^yxbnULZZG>bLtbxCf;0y9Pto?>*VN|O{ zQ3^BvJz7_os}Pjrdsn;`pF;neUT)7zt<2XrB|D-c=(UeKp9??#fQi-K8r#t4ruq%- zEXroP0(1LF;}vB}cs2S7x*R`$L>^MUmu2g=tcS)1xBytn)<@ zJQaCsq92G)$wgDic3z!%$ipKdLj0+J4mZ@HX;bJ;Bag$(7i8@E8r3J0hPZOi-p~gs z>rO+r;=Wi>w7du@M%-$&eaP--?;KNA(m#ls7V=zA>__2Nq_;(KlIkVj@LRqgLl$D} z_GORj_2VH>fvPS#>He9Mi0-NV{B<{r&{JGRRd@aNq%C*jO6+Qq&2<|t1LY%6s>GQi z6E(+7W>@TKDU?yO;I-Xw(hwMhe_PM@E4!u3&JdF*kGW z)=vTxf=QyiOqM3ouL}%V+%%B zDl5o`z+bWO+>;1e7w-y%&R{ol>0`H97t)vGE%pA;*3gHYk)#9PxE^-7^1h3emj__0{}&rRZhrj!@2^KO6xxrLQ@N-_W#`|-lQd}~j zUv158)xLmluAlY>f?xQfCQYqA@+R?Yt1nN2@I;SZ zG#o$0r8{V;Z{Fp+0)FQ+IWhgqd-u}zq9JaVSDfgn)((`!CA0~oFi(B5lz z&vF|}<|VUJC?{ij5pJ{?yw*5!XUgXHgD`X4@nk{DgSp4kb$t7UoDQ9JapT%vmR&Y^ zY+av9_c!~$U43#z#K)>Px5|D;t^TtU=chZaM}zxbT(G@HulnZUQj*9_r#05dxZk!o zP_o=!Dv7YrL9VAf__ru2sM??R6io{C3vIg0kybvlZTo4MJW6?R(|gsvD^Wj3_i)?C zGw;~rs#WeM=HNo5b*-^_@d}PZCY3wE(wm*iMMKumz`!7G1FyHvwr?+$SS!7<+L+Sz z_SbJoiXYRis3Q`kSG0WMC3~>FT5@+;;HP=YaEGa){(VnbkD4RBCTg3B z4(^E#Dwa+pB%`%&#tk>_PM3RFa)B8-l=>&>K(B)$o*-+AetD!6kCRQN?bIRn^*dm* z`SmW%u{t~LaoME8fid;c8nC&QPul>=6IV`~#U+uU_t_`8vsLB9z(Ll)`Fj{n2jZ1vu!9~hQj`>e>y%)Wp^LN&@8qUpb{1a@7z5s*ocr_|zK78<8w zEmq+tr_TAzSd+^wzU!JlekyUiy-0ZXBTe9ZjT_wV<9TQrl%Cu_#>TI%g5lSV>=ex zOkIFyOl&sI>9gOdYGXE->XbrK;kk`1EZTJ<(R8U1Z77A`qbcTG;cE!{bTXj+?G-}f zl?F+e=ytYJE2=-QL$s|mr8;R^z)~SD+#2^#$p0UBz3=z1wu4khWW2y&Nm3 zmW2{QgjU!P=N=DKHqz5W>^*1q{BJ#(p!797ReNSx!oGf+9%ZREX)`v^aJh(rg5G;#y=<^@da{y`)#a286&h zi$pbb+zn@3C(<~Loplorq-%?|4q_WUG-tD~g7cVP^Ii5Hz1=Mpn)%AUZqUE>N*xO! zwVjly^}EmB#mw@z;_crgth@l0V@R6_dG+qT%=kg%Zydkwb28geF*2HIK+rOj#&P47 z;RmOaaD&R_XH_nIw?^z~Z#$@3N>`U>k?#K

)Z6ntQVObGp}Ed1eVmxT(RLs|#69 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

a{AO0hOn?i6fs z%X)#k&gv5W2;R*fqWUtpxEt=ElVRX8un z?HuwRW@j%ld6iiS0^xCD5lPC7uiSti9kWqxHKqbZWwn3y8_qHAuBp#w(QL+d@QSl? ziNiT0!T9 zGYT6@MQ2t?ojEhrsMvZ)=*Sw&z`)9!IchyIA8s6|LS=S`?T|$j(l?5iGZlCkbH#Hh zyymt&vGgdd+jUql5bss}X1M-#aX?~=+x`6ajX~?Plyiu;#9iGXx8{ra+s16>F5`D4 zz!Ie|9Vye_;w#4a^$dJUtC4cXZ&ka(R4m>TQxc$woC3 z|9Ioyd#;6;dBV2@!>3hBU99kmH4zy!it7yka?TUMy zMcbRFy7W@`vZWe!HIuGY``?d*2aOIooJk33!H2q^Dv|2SrQ+$bH-{DCkeka6+zzk%aCOuAVVtnD(}P=2qj<`kM3#@3op5qzo(>Z^Cw_dyJ+I-2^sx_a5J;AePUi zfr%iN1jL4>+7C}hmDKc{sJX2B!$LEwJ)NaZ1!62*za1@;9e)GLkq!EH?+fFm{cuUB zWRE~FE`OP%_Wia`nKDdDJTt`~{%M)9Pp{D`(xxM2+EDZ04AhY>Eh(R;msNLiT}Tu( zC0UK8lZc|-%~zJ5f-(%qPV@7s)b6YDb{agbbB)2`23u8qhHTJh=g}u6@+PuStjur- zdXZSQhMP)rV^r1aGYdza5a}fAVRzbj|Oha-|#Xe19f&Am@^H%X;Um z+^l~HuiCldb$a2+EtZmXI9NDVVIEv{c@C&307q9AWJoELl42{!)65<~jJX0|%@=P& z(i+}fDg^gHlMUzG3LzYd=Bg z?=Sjr@Cx*L^Lp}{{TlmFFJzap%6A|YEzbNMRepcYCnj2s>cOE3{1dxPap8&aJ}F{= zI=-A3>8ioFUD@Luk{)Cg2D%y5+D@Rna7*=CF5s5e310u^kBkJ5t~Rbz&$qvt`wlqp zqu1Fm={@8gJPQJ4r{fuvsj{@%p0g#hY(d)yf4>YKVFZiuxbwzna{O+xdczxe5zSca zuH&U$?S2~Xs%)HFfS2F*J+J*{o^RgCY@gwQZdx;|VazGoPG{+1cTu561Iq&30M;q& zKBd#J|0f9BNOhMp;e9BPvz^sfP5}QviXdM&wiaeV9iK7g{%luA1o)x4F>%Xm#U8qe zF~LZkP4hk~4a_Xsrbu%@?$)~IVgVt<*%_hmRrJ|{ZDD4MtMDnB@<(mKg|(QH@4Y(@ zyvBzDCAViIe)2OUysF9vQqpoG#~}N(V>%+Q+2SwEY9X2WNy zmmemjTCy6F@=#D9Sf#ELY7^I|+I!0;Vvxl&Iv3z(mbvR}zlkr}q<{3bL{e;M#djHr zFbY(xKMz*mOI!2Ys{kT6wg_9^1I`18 zbnKR+oYIi1D~29hy=QwDl>m{40|c0kpOr0Yw!|u#(=}hRZ%HobzPeZO1C5_Z2_NfE z$Sggt5`e9$Nwp~-w?Tls-P`w_Zkq!APxteCGX@HQ_r0)CPAY8IWz6StC#TWmP&baQ z_$S4>!v1L?Unz!Z#vuCSwplZad{Z&T`L>zsi(=5oq0Q4tHfD6%TCAknD-)ZvIUB6l zp~wyEK?9`0Nw@ds%w5~yV9S+9y8ji_$wMbz3^$8i?mTlz`0AhQj|4ld`GF^I`uxgG z?n_gLR7rq(Au0_^Q-d?y7`8#+ZRdUEp`W7+lX($0b54x1DON^u56+kEYlj8}wpgM$ zI;>|lX@q#9Mn${{$(&}i0{M^gaJu*3e$+U4>Y`x&2V5FCc@g3ex1kx8U!&|lEf ztK%|_skaS1?y8aiUQ9az2vRlE6}WuRIptCWQch%ERvt-R4UxO$-Yysju}W97G}Njz z5C|Cv_}X+uhK=wd8E{4+tPm2il{RQ}0jgVxyhFMdEEPHu=nUmwVtNpRc_G+xQa{TT2J zo{($ze0<)lFC^r{4_Y6P+nK&7-C1&obj;A-LMaw@j`_88ntc=p9xFNyOW4|_D9@#kcu9SHtG~x*Q6F4J z4wYt2fz-aUg~i*<**mt76mxcIKGp}oDa5R0ZgQTVIc5AyRtY70c#6MGcnlBhbMRBv zpylvN^lXou+Jzj5W0tJ>Kw-n%q%{|S!#q^hJ zi$^*m(+F8Yb4M)@&T>^4|hiiH$vW+VNi=(#a^JkSSi>Li1_tFs9*;n zf}6||3swOQk6&+OQsd~b(#dJ5t)M(5&%U%o`#Z#qFbv`p7N09LQso=%z zSHGg1E}B7;K10A^A~<|GT?wigEY}z=9(xI+nuPW5b~iw}d@T9a>m*9y*Ss%Lw$}y2 z@7I*7T$zlo)g}aQ8H?rb03R{>*SiwqjmLflbldKi&jAjO3t8_rSAxu*E3r2|q=#`} zjRBmNGNL)X%sGe()vfPv3w}Qx$jMrv&Eyq1YFp1ztI68+Be?ApcgeNA32aXTKyqL#DY8~clJ(hE z)8Tliz+1K7$Cc<)fsN7Ed<&4~o?JBQf~5%-XgplEE(WWgs_C3+;mX*4U7x;6O-AXK z8L|s2Tbsl8|3;ao9s^wGcD-8UA>E@A6K1~3e&&!rJ}WmQ0(G!Dkq*DIcAZ=GCb(Q` z5P2R#?4ujawEmpl1Xc}V$ z<^_C{2IO-jx2@(F_~+vnx-qpp-tX?Lk+uXLsBCNrMstdenjf(yJ|`sJ8gMS;>9O#i zUhsS3Y(71> zv#!~)qg)fq5UK}?IivjRzxo}8cs%l)glTeJV3qoxbf@x7m^TpKKz4#Nm<3YREZ7m2 zPJ`y8%SL0+f#ZeF~5HfzndzvS1=|`>E*h++^vVpR`HCCJh3A=I^Bm~2X~-XdcG#u z$1VnKIUm&VH=a7o`M5jm**gARw@VmWO1Ei2XRyX*Kg~e0V#ky5-exVzQpaK-5Uog^ zWR1mKm97DCNZr&RhZf5AY4}v(Ta-@1USSY6Q7@jXl^Itr-YeElHi7ff82}SjC8EwU8lTtuVQ!vG0y6vsCP!mR9koQ&D5unt!1Q~bp`PHVTAn8tRFWgCF^W+ zIggSM2d|1b zg~NUX1rL5$^Xu9gw8TQyzv`Tye*As7D%X_rAcVh;TElHG=<%=!a^4W6PRrIE_aewZ z>I81V35_cjgDg?pasydFnM*noz;tH8-!(Vyl*9rf^mw7fJJ3@R7pAbdK1Pd6TJU2a zO6h+Qch6C>EDeId+qP}nwvF5NZQI?qZQHhO+kM-%ZCkf{`^~rW-ZwLQ_UwOqDo>rL zjK~aCMrCDX#jhUi*yL%al2z_T>}l@yCvZ@7OvYS89N7TE7ELYf)5>lB{swzld8G`m z%pc6T_&0uyk6Tm$T21gr%b}uS%P610JQg@6xO#|JgX*$|HdPKiZHxAW&b2~T1xYRa zGaEd?5Qs$wZSIMM>B^pfElR6Ic8eB>m=P@OrqszHBxebvMJ(B31IdWOC5|29*2#Oug| zICt#=Rh7G#4(1YgwQ8%X_BW_*<)Knb#!TJ#Pq@g@1d1YCAldFwwL;%HN_Ypcp!;p;f zp%>CVUxE2gLvo*90fdI1O?U+nJsbuZrxNCrYfKvFvBtDXpn?_1l#8R9iaTJ58W9tn zgAR7O1{&pJ#Ktt~3yk!Vl#7FI#CV5qiZxiF78vGc3^Xh(m?Qzs1CLA&%MsI(WETrP zM*(5{S;<_UwahZ6m3*qBY1%y}FZ|QOp7K@s22CTJnLq5FWbby#qn4Pe!hLy4&ow7L zAP)2^*!XgRa^8EZ0a4dnCBtdTVjH?XppSHPNu+;}j7JrATe68z88rY0WEI6+*Au5D z5jDg*G2OjiPO*G3=cqay%7h6}>LZiXZT-m>y3#o^o%CP7yj5bQw!ziM-;I8^DAL>nG0t?Z z_saLEH|@0b|8jrMQoaQP?L%WZ$;8wfOxtZsFvrTF$W% z>8lcP636s-9R!%ihY|(@kq|)9O!ogR+8^nNgJ~A z0&fZVbKla_TG~WywVgm))H<(LEnp6*K2AYrp--hD+}u9RQ~o%rT`lXp_K;X{OSn4O*Ev);#U)+psJ#ED05 zBwzhl#^?X#iHD5O^si<9>uT(n%^GMpB#nl5xHGI=zQ|cI&fMV5utAscC-j3B)3S zT}rP2hC2`0jlg^T;G~%1(S0my0RchSig5>mlPDdiYz8;tDV}PRw?Mck?@Dmi-CVnn ztzDp9MxCw-c}cRRPp3cNCiMoabN3B}&)Mhf7PJrpMWTzOPPcuvf$>dDdBPc0WLz6{ zRxn%8FI_>_NW!VJd5LR^^Lu_6OHVU@E<%rHmH|$7ca4YP-l*AU9-lCGSUmswFZYNZ z|34_Mohy2T?l{>%WhEp(`W7W)xkY*DAX)VLt`aDueG`#kG(pNIA;-A%f-k#a*1d4G zJiALb2U3lvOQU(40!G3NwVf|87xhIt*$p$j7#_<&WkDMWCX5OHwcv;fTkeD#-qfDM zYTLtXeaweDYT5=DrIcef?RE&BE~a(>RThoikKI3>UJ|NL6c>v|I4b#kISfOEQ=%XJ zlDAAsDpPl3k^lI8HiY`Tb>EAhEq&pUpSHj=&2pLlG~GPm1A}^zHTZk*D@7w=D#u&i z%gTAk_!yrcVaqE-X8m4yFVDq=jIT4V^wZ|Y_sqL3BwJEH4+qEHx;kZauLjzzvClHW z>&>TKS4e@; zuDThkCQpq~E6vrB;u^lLbJypWIaJmZ8mi*q2Z~g?+5N2L8fKtm;ICD8DRWCRPV$aA z{57vCopA_#e~bp|CAer|uU>^#F;v>{YQAzjXK8gY?l@X7-?qVLJ2UB?x%J+^$h)7v z4!dh*BgR9)U}DWctZeE%7^_PKR&dn8n${ySYcv6%N1S}Sm>+zNwp_sp?U?Qmm}v#i zyFU*~Cz|cEm~ZB7j~D&0cIW6pXl{7PyC->_$tX{4t!}{h)Lfe%>LZx_=Bs`7vYyQh zCqW;+=Wf06LtoKd)0%fRP!i2vZ#?q8dRj|=C~Y;k4+mbEVigXC5C&JtdJ}Vf%qC?W z53yZ=MHkU#wO8|MJM91W39jmGi-L5m(uVlq9qE!r1%tmNqQ&{v#pfWceHW^9W00PbYx*^ypN z+iMEZM+F$YIKH^j5vV_-Fb0zdf$$B#%9+<2u<}@(T_%+bDs~WQerm?DY$?P8I@qXi zgN4u{C-B`cg!5ftC1h50Lk6*oD@KeXlZZ`l==aYrFo?Ss@+xwOZJ0#qgmIyu&f4{?%6|dTa4O|q!Ebmo|NckH!z;4OC>qza;HUFFzrJye*4fJWp=ilsWMV-9NpTE=81&^WOa_c#A~;mNm`lO zypKa{y4VBe>!OPcu{&c|Pu%w_-1*S%t|%mO!r?1SvUqX5E(dwh7@p)+^^a8%3zV2tZEyaxBZtiv}cpT}L^Cr`(^ z0O>%pfhfs$g#gt>w7^yI4?Q1B=m&t+pfkvt{KM*g)Z zNJ3}6u5pQ4>;3y=3%y5)Xx5=iRhz_{#5GHAjRWcFi^XOzze|z!!Fxv4mEuIY>kEK0 z?+)g}X-rA^Xe4=voThK|gLjP`DyHk9;tx2HvIisp?ATCBBwX7XHHnTfI=J@PQ0NVB zfG4nm^-oZ_$K`j^2tC<*(y#a7?|FKn+B_20{zQULKg=u$zhSp@9&8!yDQrmJJQ{+U zmHLAB1eQ!?)*+?^%6)niT>Ny8?MESaFd(Evnitq&gNempnPJawK)&d^9yCm`Z>HKf z)2FRUj`MJVXeypNJ!BqtScW60UntXlsx+p@P7QOz2ZB zQ;}%78@n%(U+0>sE_<2biZVS{aJ2GpG8HM|fOZR$Fcj!A`zM{Wj0p)|oXB20;czTe zxIMZm&19*5AlaC^o@|J?(_AYsEKYoHwbeMio<j@F@YRu{iX|>C#aD+Ep;U)^7)w@`OmFn!Exl9lL9nsEPuK0TNAGTN@Ca{ z$4(iz5MKq1xUZgc9L6Exe-^@gGs=LgD>(x%;niH{`yz_)rIB<8(b0z4ngb!^+D>mL!q^uyyy zGwSZ-)LMXSgGPCCG%jv058YQ0?H}Ub$fRHztOUUJXNp;3`Pz#hAFR+5aowpYY7_DI@lzLJk=hWnq{{_y+2V|K!Clb$If`!F zYAWsMa|6tUoweckqVvgmmu918EIx5>V zr4Lp^lx02980AXZ5p}vXNYa{}Vh4Q}4C2rK7Ip^cfILC1J&#=0wr*ZA@&)l56*CrW0`0@-K`wBC$HbBA6V1a<{D6TO}*xpH4;>qD= z#_2Y9oCUuZ;aw+9k${+Jv1MxE`N}odHfOgswY>}hUJgOW0m?{7DgEm5J zLwt}dVqdzYEJYBfuKHqz!WA{6B{ciEWGlPl`I=}!3L_fy8XG{%0#FfoXqw05HMJle zpaeuN5HW}VHk2nMRl#L80DWH&WJ0(ZAd+kdUuGzb5+7<3%z%lO@!nkt3s z!-uR%-#nx!k^WhASzPK+uzgV51opbi2EFu_tE4*iNXv|#XNwK4x2tvAYIXb`n`d4Z ze)gew!^Q9Oe6@>K@1+^bW8HgKogv)$-#k9cg{TSr!P%9Ql*?JaR88eOkGCMN4v%xX zA8u|trm*~;SqrOz!)W*0>A!D~kac3MBB=;-H=oi%qv;Hv4z8c{TJwf@Q^05`}WA~e8G8_YEcc6?V4pxf9y7U&nCltIL zB#PI`QDCE~L&d7Bdaa61jgx*!DhRb;*vsW?7J&19N0OC7Ie#va&lii*Shm2ihHjV* zc!l&Dk7GIxI9RcwlsoZ(Ar`OLhp5Qf)iRL}FIqSj21II4)D;63q>f$}VbUdWVv# zKouVE(sxIM9ie|* z2YhHZ;a(fny3PU4SQXg0hWJlY$(i>WQ76GWZ6n+C=xCMBA84d4wB|| zaAR%luPe8K0kB_Authx!b{N!_90`2%PP$f_W}21U3%Ku`_l{4dZwX5YlCpEiV>~8w z+%Y|hTBY>MIdg2|T8WeCXp5>A_{^1xUTJP!ZXKiPsdrQDgb3)fvUrxPnh{S01A}w^ zQHx+XjIwyV1QL!~xh|v7v$`wbl{M|^y>At*sjAfw%0bG@y6 z04fyH4c6I}Js&f=ioQBd8a#AArYG75FPX2suSU6#H)F2Dtv7?HYwv(eR4YAbSbh4= zuf1;8;31|lh0RWh>C-WL&ghgdjz~D1b=MbXNi?~|I4`(Bi3E>So^=v>*m7~s@u4(C~IkIAQ9Vin~fES5vsN7_0 zwpzYwPFWA6R~&n6O}JF}{&zV?vF8{XMb>(6l@$Qv3C|i>mN+*=Zf$@7(sfH`S5N65-!G3lDpT&Mcm?Ef?dVE)pqfiu{`#E2hsKw6Fy$adHZ7dC zCnKAdly^2ErIXRS($47Q=~7n5`o0blr9}}g%ZrwQROE|@Et^qM)r4lKp-oj4YQ}w! zqeBX4dhMuRPE((Y4~5u_0L^qLPe}`EAv>`c<_)3{kC#|CQ)VD8u3Mr7_~zE zVM4CxsrNFZVrux$7~lh}Jih|o!yQ!E)4PPZwRexTKPYtkZ&?;>5kSp5uhjzvs5_di zQ1PRnPaf+TU!QZPMKyLW{M*05`0N!{U6+%dAFqvzEr{v5O;;OU_EwO)IE0N#gR!OX zle?Sh&ztoE@HO4GSmhPdkckdzGkxHP>wtbN1=_n3fEZ#paPpJjf-x7nQIUnH9|^+L;blx= z0IEi2$eTh{Aj-8mJ(6i>RqCREX*U7dEn2i^D>lTGdSAY0^>=TdIwIU7tbu~ogl5CL zeVv54?xA+#s^k@@6SB#Fn!WlLcvD!Q^p|rd@-K+`E&nS0sodB_u~2IaT~8q)a@}M^ z9%R)gqi+z*UZw7LZ^TPy(PX)%xehfz2_W~vVmyzi>14E@&YE|CD@~W0gvI#Kuh{Xc zj=!VE)LVaobc#NSaZ_!>Wsj=F$BK+)wupi9VAfwOF^a#Hqii}$ z&+>=c_L5Z8*nY9o+iq$3)Sg|leluWor3kCTRwvdHAtDGvs%Wr)f}J>zd7Gi?OcPbr zLnZUYOzm7%l(Q0+)lHo|3(JDRi|jVM0ts!do-Qz2jO#VZo{+pLvu1?f?@nBs7*u2~hEhtTFW>9)&;d#9)lzS=85*WQsUZJ;e!Zc=0|nw1H^_MGvG)5e>(^zW^8n z@c7w#k&1%JO{!bn`gjn~dYJtYrvynbqIPEm5DpKN!vG>Yf$5*z-!8%dk}t6dl~|&3 zr^!1{fEBgE$|lo=P^b2|wbXLJj_hum$$uz*ISBXi)>lpLGwXwSzf!JMyy;{4H6F;l zAxqYhHOxbd$bU(OaY&+YQ9?-7?Q$*xz?KOC1@DFnM?)fz+_fh<12q#q6A%9kUhd=* z%dm=1BJ<=i`UrzzLDLA-NYuEZReKBu*!Y=c4t~Xh#FII2awDItHg0+N=#cXf=c$es zml=mXHh#$ZS@h@5x6;Tczb67`U<_zSqohyAc0ghWR1R?vC#IEkL(_(L`S;~SW-fH2V;&eN zlI#D>W~>yf@L1*@z|e%%#MO+RzBP5I`jEsIwz!|tD40KM?AHXubFNYA;M29J( z3N>HXmL+kf5o^uOR!Ur?nkvOTGfFDzo4c~(3iQ5V!C0dD$z?&R{*Hw!sshA~?^>1) z5u{g%^{zuFWqtZ2i6*-2q3~P8g6o)Y$k0yUa%o8=`JhM!Gv0VfGC97#p0GH!CA1s) zK~NmSqiCnpFy@G%=7Ls7iI;}iQ{DEQ6F%mc&*OR1*4AwSh^7^bPAG^}u(AMJUZw@ayhv|6t?8D|4iG;8LY z7Bu{X*3#`gvdEWuUnLRnDp#YV4dKau3SA)9CktVmJ>!}&>Yo|OcboI>d(*2J)>V;H5RmV#7Zb*EkDiMKGx!1TZWG#sLj40JM>UoBH%DSN z3Z$RpB~4?uk5CT5exxV)_=tU$*bCD9dWG0Am4lscKJuT zBSQ9Oz@1wt3li8Ho2nqm%`gS8XX`8#)E3|r3x}0Lz>ST?!MqmdI|ofr!GX=L9XAV$ zjHO|w_scje<@IIjx30@34`$$s*vD4opdBFEZ*}9ClXSGJ#!tihi@WE~AhoNPx#X7> z+5I1+swYoy4S)ec7nA&o6zMo6l8_vFB{FikI9Of3A_qx3sOM*%Rh}F7kr+(A{_zCL zMz`ODrmo^OSROeU#8Tm-rZ21?;ymnWEFo@e1M~+e_rN^jh3);d*|{a#AVB;=jTfvC z&v^rZiDQMI?Bqq>qG=1yBV!HlB-BmyS|#;&{bunxd@Xda)t=n)|C1L;}z(rzUy%D$}^yz>d>{7HaQ^tTW{nYo{7AZ6Ru?xX$W51s%Le1u} z3kAew0GCqoC!i7+6UA(kptR{I-9x|z8<%>QmjN0o08P{q209Rnd&v?66A$Zp@2Eb* z4*f_(74?XD5m&0kHyBEb@g%YE&?_gc2c+4()auCbDgH7Thr5CTPV8{4bMsUa(IWdhA_a2b6a13%bSiNe;e z7_!2w9(o3~Y0XWbNvv)kjISf^-eg~^zxQ*x^ylbbOF(iYl$A(Tu*=J%KxjH}a-`J$ zh%blo(6bwkv*53?pEPBuA8O=7lQ_`TbC;S+p3GR#egQ3@ioBAyA40Fx!2qVyG2(J@$IfhDtO=E#{xC*x5&C zc)INFyMuWxPusnfomXp)c%CKrJhX{fS2KtVN;D2uj)aq2x@O-Z?y5fEF8_#)e}E-G zpXOlT5za$12Lm0>MS}oRgOdVw27o!ehu=wtI8!G|*@$K$0|WFuO_>X!VmpZ>0j2sw z^mdr|^YNe~G=0&T$_u286(ufsB-H$aoCHDp9$Y(rIx6YoDv0HF z3Z$Q99qJ8o4O8`G>e}MJypl(au$$7u^WySQk5y?Vs;8ug4T+VGe^1FfOQl#e7&QF2 zFMM6oK3`k;P}Y0uy6JxDKJZ8a?+2%PHU+Pr#iFx4B(~m=u!M2xW}SZ%`IDb-RMy-l zHou@qB{Clz9w{P#5avsOy(^yX79EJR3_L@tOu-Bi#)6U;y z7%paCsWUe~Zic67!}+c}=M(sqaLD1=lp+@V`*z&${Ka*v)yNumhl7CSjV_O^DEv*P zd%yY1l4KgM&(k4xD~icOpYLy_O4rz~2Vrx!9`qQiKABz)$I&g@KJQihiZ%?@EGe7v zN1HG%!Z9=6WT}9YkGV5;{4K{>0EuOsq+J)jZ|1d9FuXQ z(U?^fsn-tj1@In3XMs$0#_c98Z5szvfKQcynCyU0Ea3X`$UpyD95c{~C8kfUQgwr4 zcDlNtIW`P@rX%ij7%aXnyLU zHdAkU?a@WvC1#t0`A0+UcJ#+nm+upXbB+fhyuUS@_FY&)k0L622e@ z?!+MZ^DE_&&4pAeX=G9^9`j<(F zi%dn#04?0k1896Kz$!BB&6QN7k;pBPZ76gyBzkwkdTQC%6jiVSb^wyrKO}_F{80vC zNCt6*KdmsjYGFM5dx zlvhyMRzAU7V^2KAX!oRGPHb1RRNP>e_1$XN+F{leb$HVjpv8Q%(#Y+%s)C#w3N&SJ z;B(|YS_1r@cLKcI2UKc5Z4n<7Kw%GN8(XSX!R?ivDDXZ6O%}?(_wE(%44IbM2yQks zjAxUl2wbSQlvmDC?L@!UPG(|WY4dHK%JRj|G0U1$b;KaZf;U6RAt1H?!@RHzCSjhc zfGnuo(n;1r`A2J>u4*7piV$XnzeS^N8-`ggh{afqdL2-by-YZuOID}dm@4X{^J59K zb&&qR7bR)%M}bED4&>R2*_PvYeUWurPUr2(fuk79AJ?_2o-Fg4Wt-FvD_xeg`1bq7 z5c=%*;i`_$$Z4r*Jr>gi4c6O@nOkbIsIE4`1bmnA#an1o9ga>i9mF3NTGJYAmPhH* zy1AWAzjiE(!+cPN?1Hbf6rsv1;7q6!{nI~m#UZ$$P&mt|d+}W7B~0Cbh$~N_OcWR5 z?~8?;2vu3DER>@jl@^ePl;l}>2&4)QXE*nR?Auy34-gbBmc!47`0QIK1b(#U;Ch3E zq9TzJV2m~_d_?Ead&8K;l#eS1<_=aG7B+t zrB5>ZWl61!1&gw(JrPlmd!^;Uae)k|K@^$PnfoUkbkb$3&HVmIp*!!cj&*6(5zn-` z6Fvf3iod<)iyS#40Y!zl)16;U9B(f=MIjyxQ^Ww23_E;|WM;so9}@kJP@6g^9}7-Y zg{aqx$-9&lYo%ybU^EnNt!P%8M+|m^M7@NuR@xA*RSw)x#E_uVAOOvr=7L+%Yg-d$ zCpyg3`IV01vzMBl;M!OMYQl$4j<|JeUV8&*>e52etlrMj|H zYm45|fk5I=Q1Hy-9p&bBmfQa$u@5V$uZc`vDif&k^|Qf;jhiNNh+4Lm(v6@fR%b1o*ltOmG504AA;17aoG_}b?>Y&3bTVr^MA z%l#{@tLFsQm9I#i?zS_Jw&X`uuV8d!p(MV^qDbT^MU_z$P%=35Mvb%B zp%;T6wf&R3ru#FW zbYgP>Jv7c2p(jZpeLzplk=Us^*X{VB+^!4A9`o} zxm0ZBfyyi>Y}cC4?#~^wdv?{@hOO~#kT(W99-r3J1El*t=;QE7gF-}69B48^Oq~Fr^7JT7xm~Lv@eE!Kqj^}! zUz+$AjZXrM6#To85(EgZl>OKJtznkRsrQ%Cm+#g~Q|=xVuN_%-f+1J;dt+(k{z=t0 z+CEoHGS+^`ESw~T2Y~~Qp~%V_tR%mM2-#?gixM^U7xFV#NDiZbERe;eOtA`9>intY z63I%B(+n@~v!o}XvtIYCPA!g2cHj35PD%AU+J;_3?6hqZF2NRZm$6|@y5^Da{DQgJ zC8>+VS3;UfZkZ>T&y?0o8bw!ZKK$MVUK%`Oxy?Q&If-z-2k1o5ncOB2dd&X$BLL_7 zl?$h@q3^Lf9F%CuuE5@y&0U603k8a!M}az9`uzgr?F)#>0sa9aL#Df@9=X z28lx`s`fW4Q07OvZ6bcCHsX>`N9bpx!!k{CZbF>56Cx7x)=22z*{6pdH6RcEoZTgv zUxLBKn3Os5c!(RJ}!C{%L zT|2#|;*T=#f17B;{FXMxnQCAz$eX9UjbJXWM1?14G=9H>yTqJi)^;<%T2xs?RV!U6 zn_|H4izkXNR86p5!k=jkb1&&WdA;iVpcR2xJ?Sk;91ilmpWI+ z;@P}nIaCcrg<@DmaiQE$H2GuhK1xLt+F^lMR9iic%!2h4e2>FsD-2b=TT_@yuWmyf9*=t*xX zMP(P;kffw(uY=jq9)8xkM}RB9GwGSv?!0@=uCe?ax_OJ8F0OLE^`!*z)-GUSiqz!8 zP^4D%R2g!q(Ya8B%Zv@>6~m2O9O=Gj2<(*f?PG>}Talm=`e9&L?0eqc&)0 zW^J2$@ISo|=>CK}c};ocdGyCnOqbTE)32`&INw|G-)DSGm6T}hc$~7 z+o~%IA}eFS?JB!q>K_^1d7S5Z4%9S-tyad%5Hfc` zMWEW91KW+Z@5j|6Ykn6jgu@v;>}2G**-hRREpm6A%@zG15?!Y^oR^fP6hTqSksDu_ z_blCt5XXh%?C*A$a#5)&>*n<|aeQx0)%jgfWU05FQZseHe??2nQSxh~J_5R^BBu$< zLg{`Isygp$7F&%*tAB$3GsOA$ms~;PhCu5cp3peh=O!ADy4nmhl6^CytyE+{2p1#P zjrA*&kUuE>e<=%xWWu#woW9SXhv5pwN5GK@*beDpPlyT2w=l% z8IkAWy9WBI%JOMMl}r_N91SZ^R5HWR(imQ4#pIbdu%s4(gRtoB-PA2r3jN&ff-#Fm zFD^c}b$sr5K86A+NqAh9zMgI3eB?~M0pBtCB7Bg`%<8nBvtQ~)tPu3j(`raRkWU%I z+63SH24zx?5G-Z-%AXN;!#Kh!~6=* z8{IQrUoBt{Tk0we`Pji*At9r2=N_ba*CF#UzprIWem~mOtKo69*k3s@7RbV$<<*Au zfH^%dGFwGc8%TX!zSQ_ZWxc9NMY}qHr`2eRc&cx54tq^2^aXD`zPs{2;aASTVBY@$ zzy8BMe`~AXWb41wYoULs*Mbh_`c|^a-!cEqyXO4nhMB%~>WajuU z&^6~@gzS%R9r{0!VV3_>UH?_Xe`-wdA5HRKpzHr$@xN8v{}049J1c_@0V{zP^EbuJ z$-%(F{!Lvo5->7-o7BwTbo93@{Y`*>M}Ldf|5BqF2$^Uu1!L*F~% zBw*qoU}a_drmDY5Y67Oekm!Hk{5#*j_-8uC@BipC5wNkb(Q$sOHaRscQ<`&(SH|%;6gi zPwcd#k$#e+5 zy=ASx+vK~SIhg(}104bu29|%L$N#s^&C2i>tp1;e4(mUM&i|cXX8U)1StoAXCV&A! z^!YPfqc{S>FxP@4FfmrlU^YbR9`Gl8S&;#aA=-!6pAq45QUTMWsYix{g~>X_IiWjq zvaS3eK`MQ_Y_tJH_f84XA7DZb9z{1th9#1F;p@)L9BdY;5*k1xdUV`c4gDtc#dtXq zclsb$WpuTi%T@coX5Y}omC-25s1P_fN?PQ4T!@8`#+sw-+{~A&D%>c#)uMWVO6sur zATynR&pMs?7ZzSAD`an!K~UY&=lm}B-r>)JJnJu`G_Jf$#05ru7YH#Gk1XbvKc#zC zUYLD8Q`q>xTgLYXjgq?{<(O5EZ>VqKt@~rwtIU0_dyL;lsWxfje~!xEhx7koRQ^l7H*orfxC!Y02gm*2 zhp7Koi2JW0@xMXbe|7c0kD7lS68{b2W@cn%XZjvE&8?h_9SHvVAaF7kG5*W(hN71- zwlQ@w`yNX;m^l9Zy>QXx=82;6#O`@jRbE}b^-L@6Qj#zwCLzHUC_sP;p&uroE;}Q! z(ic@55siQfDhP`E9MzhaPb}-7N&us1>a<`#XpGXr$edqF49o??CDp#|XiJVTvwi)_ zJALo=<+?qs?AFtAwjK@^xo?&S!K^D6aOn^Lqv; zd;~b?XH+VQS@=@zhRiWk*JUxc(7#O&!&R#NL`}6xSLDs}4qoVlBlz+ES@c>b__3qzb4N5)U$4T%5Nn*! zan_i+`sK#L1I-t1d=xc>E{*#=2tUUQLZB68+{a_}f;v5kagU0I8-BiT+*FTkyQ9sB zmB|p`Xwpo#-cytae(SfXD*sBSmG^ziKEKQUg8f8u3!^*$D8-2%3DV1is~e&xIBG4Z zQ>tx{P---DRW7}MpgG`6(uj%mXMfPcUFeGlhH((S&&RD4^)%;sd+70rKEc-9g>l2N zfZbKPaf*=LZvAVDfZgl|=Qx4u=>=+v@Qq9c0cTD7+aN#NWWDl-^erXN`|dQ=ocf3R zW-TxOr)&9dC@Hcf75V281H)@(P$k=J)a4LgTF}gU%wry7Zxj{*e z4xpE)2RTnB$~f^@wkTQwpk-R3OJizKB7Eogxz!FPxe4n&4pdXZoei)(j0!ueeLEv( z23V6`1G8Z2UG_>+D<6d9Xn!mm4_ukPxm7zz8pEQn>CXs{tLdfl4a=LaJ)1ziTMzzK zDe9Ao{-z$!h$L4Z8rflw44c9$^G*9-pLaD!{TkZxeP$F-Cf?QF{TOy;+`{)*a--ck_XPdar;JOSR?0crPthmaFAnuU zp$lGj&w-RW7~V1s=gu#B*6__6={aZ!{h+_{O74w8O7vU;oM%-TSsfbLm5#e6)`uLv z{|Tg*@Ty*qGoB2PaQZ{Li3r1=by@-BU9nbE`X^{*Us7fa>HZE=WdnkxZuCeY*-J#C z*KJxod0ivMJ650zf_Qys%kw>+n7#!jA9H5Z>u4O@!5{6h_f&s3=s0iCseqy*!wHin zD0{r6z%5>0Bsvhk>m$I?&57r_gmI=^8Ki^DG}F0j%)^iP*YR2#p9|}hMMFy=*O47% zu@`V0e||yq3qK4gPu$4gUJO9MeN5z6=h_?Nq@M68`_b0DDm@6}R$-es==K}_hRsB4 zNQ<#yZi_EGXajCxF+ZV-OZFXke`tsHEod=UwHy(Z_A#Idf2}byRR3l`9ti48aiA&s z8S&M73PK@Fb6nJ+!Dnj=J*K4R4SX~$k`DbUkrhVU{&krAaZTS2oILOF;;g5s4F_*X z(Z>KN3^D-v#eFGRlNoJl*qYVyin&ol9m1K~jr`tz>ZF&`2i%TpM}4$CX>QVs+tui@ zckfDrA3Jf3b?)P|>-w8;6D+dCkOy|3DzhMk-v_MaaT4|3)@a%Rt8(Z=i&3VpHZ2L# zJhL0(6e!h&nGf6UgKAg|#ssAfrph8+mD9j=s5b9VcucB*bSNMk3LFh)WO{sZG}_2G zm|3V#z+KZKeEayZRYxvl)1)a?RxChQ#VCseDzVphb~nBFC(RrRGVyMmA+$Od4>q&O z^SD_!C}YLZ1y|iq7@m^Ws;?zpvovP5YcephPKKf0k}p-2kxHT zZCo1&k+_G`$S?P*pH}_H3J{R~1zi#40gQ7fIJgxWO=j~a#THgJDT4e|JQm&EKLIZ0 zuy1C4*yy;v;U-})m z3R?-U#rLFzd#~-b;z9Q9t%@(&p6I0$Sz%r3;24d{X0U-6>Li@MrvziLvHZlAkZ!O@ zXIuQa%ua}GSprta?(QY*6{#Jg1GXx&QW<}rfsZ%okWL3Tyl^velP`{QJ5xgMF za6_EF`65tYRp*($T@ym#mtR3)O4uLkwa=-G(i;n4RU%IqAPnk=m9ES?5F z4tFIbdRxnqtfc?N(l-Zp(tKaXwr$(V#x^!~vaxM%Y}?K!wz;uw+qRQ8&+q+Kb)CNb z$5eIq^vv|!zV{sI6vSV;OYdk-QRSFQ=GUll$nMlIhrs~a2GK5N3e#ObZia<>Ll7A9 zX`xZPrv!5tghi*VsBpXIUum8bdf;=7vxAGczPOAL-2{46l!pG$!TXxx&Sa zsbFY><2(9{_YZV&R=HeEeJDM_d!y&i)~WIfGsHPA#s=!&rilIyIh~&Bq`=gpEuf%1 zaFpK^B+0|)1*b;v1_F*OK){efKec;3#ZtC+L&=?mV3|t>}TTS*V6%q5y~xZBbgJLl?|;)!cJV zP@GUBiSg-6oN;!L-EoGK6xs*skc9nqJXLi!5!})C1|)HV73Y92 zEb!K=3$_J1e-SOiBjkMtO$DT;rT_3?leF&qIAY&NV3q2eWv1D~Ls6#lvN43low=sGASV3Jcfj4zyMwP! z+6TC?B6F53U-+a*g;0cIdL(?De?;gz1D8zE->_2uNw0*Y=;K}l9~%hV9g&`dOot~H z#oZbsv?Y5>L^~7sD7PxC(09_J+)5p|Vb#Y;(C#od;(SBd{mT^Xdy16AZ%d;ic8iCU z0ywK2 zFBhM|xL}^=%zVl%jRqcazly)=zUE4^N|AeT-Tm>iN_?|NESbk&pspsBU?zdzv8@glGEl22D0`lJJ4$M2|&KG<`o`HCLm)bE2j$A#F zr5<6c*!G791`$0xv`kWkB?b=?4_JqEDlqcPi#8*vfA~iALui)l3+7Q7awDAfjm=v+ zCx|dS=>?)G^Y5BDhh=)^@2wihl1Che+^YW16A^gFvMae2Ip>q#si)#$>U|C`oZjS@ zV&OR984r@)buW1@ngw)k)*T=IOrP68A5l)GzugDA4tsoZ2dr~X?76Z?fel(OgBP}z5u@ctLokaZ!!9) zjH4ujt%Nbs6-8BZ2o^05+NbcFLTem?C>P`9Ed+K5Rj#LxeD7>dIByN zNOH{#E-zaHmg8L~(nGa)5WiyXITDGT!JhyIGHwM+XMM~*aQZ|osNOoDzZq2$u~(L! z?fEDA2_Qu9SATM`AV0Ulf75>;zh+BSG9?(tNyJw}yOm|ad{l-GdO~Vq#gnhq_ zlKSIIo1;g~ltnkFs9{gQw?mSc$Hosne1m{IfaQ@HyGOt+P$#5;--D(XO6efS=8&v2 zi9Nm*%!Um&_Ui)!d;|I7EEVvVBv3xSPI77dZwsA>fH1zTf@V^k4hCGMY+sUmY%~`9 z8Dk@3!}-M%y0!l9B`vRq+I#2M^m?ibccP-7?fc&Jy1J06&}@Z9(av8DC4XPg{wp-G zfp0;KXqXtWx$p?<-^QzkELrp212_iDnwPk6c{uPIMI`oqE{wL zoYt15zE$5#zCGUS%VnCcYt#MmeLy?j4%7cxLlh1MiHT=ICsHIrzrj!Z8PGOkll~KD zEshr%Kpi;vXQl&h$!RTBktzCT8q9zr!DZE0o9+65(}6$Vzb|C7b&M2{4MNW7@u(NK|1ucb7K z*!GZrr}E&^QahbE1OlL1Gf-j>2jFM9@;uHcFAxX>3Z<#lYq{# z#G}@vW*z*K!q#oi#-3ZXw!%XGfV}zI`Q-vZTaD^5>nXj@zOF)F52mQ-FC{(r`ZJi) z&4%Qy$InQ02s)z)VhMEK;vkPLhmvR~4;zn7z^5&8ZOjpWCcaq6llw*FRO0{04_!7Rc8IaTGLdu^kX_YNp=P2^1t8mw`R-r0gJ=23JI! z)BREAuC1gTy~BA_R8mrarlI6x&@-*fOXMj3ZY=_+|LGSN3oCJ4cDOF2BkL^gC>%Jl zf_@orr;WceYf%Pd5hTctWK%J~7*O&8fq9fO-;ED0kgfZ9S5L%)E9|kVfkrbT9!tl= z8s`2cjks%r7)%#uOAWWHqnjo@uAm@;je~D5|1N6)_Ol8ZG4Jk(bmBtAc7;6R;5}9i z2Ike7qFPAtnuTX@;6wX&dR6j>(sDS;3tqCGHe2oLR~8v-fFdG@IJJVr+789&G~)u@ zO?}(kJDi;G;|@zlCMUrKO6sK>SXeA2;C}&pHgdVNI^PbH`*wPn>`(sC;b{EAvZ?JI z1kK<6cL%X|iOV$u?oq7>3W*TJCVQxMAV#7*9LojxR6(2Y|5>-{2+Ij@$%p2sDQj7#D*T0AvUOhAOZ#1V_<5 zoSopG25v9_WlUn~G~rJ-pc6(^us|s<%zuy<%KO&{_<$H8$a_E->u*>>Bv+UbGa7}w zAT%1W_>VhKrsUlL!FZTL%6l?TxP*Iy zOqjPQX`$}a!{dMW_YP};9H8lB@q~Jek@u7|qFUh?cu?wstvr))_kB5{9Q-M{TGPW z(p!V9z3ciT^eaCQy31gFj2si&x0!a2wGr5geJ8IO z%pd)N`~jhboa-NoiL zNZ(X<+^yhk(yw&Vr@t@!odNDpdSV|ydLkc4xAZSidJ-R4UturMo$*{ye!DN!o#89+ zkjURKcEn%sTk@UIxemN=*F?Su*Cf8c*Te+7FXWxMFR0$&p-4R;h$wb>fDht5&Ku-C z#TTqw!W-y4<`>vKhZnS4?E!&4x0&b{g%_(m7cSsj;;+bkDXyp&KJS8SYQ8@S7t`R~`C8h`n8 z+u{FLj@e)IKdt{&U$OwgWA0C^<HQ58vCT57S?T^WXnh+~lmvSfCa9<>AmO!-U|fu)t=50P7~obxZzr zo1^<2ZoUp?1+au6DK{Sh>yg?|&}Zp zi!~0$qSElpr7&0tFu)A~#d7A#1MDcnLBj>y1l`zc%K>S-!{OGe{0biayF*17$jMB` z1jY3>Y|jweTepRWEb%DWVQIW6&{w7uBoQ|jU_Lk#U_cqd$t+n5=71Xl1_7K)FjODv z4}%Dc*rW-%MALOcRM{^W?A0p_MZm4ww|S{HmFcxcA7fZGMzaCzf<-kD1U(b%Z`ja6 zvRWlr=V_zeOElHD=GxV^67k5npU1f`$YGRP6&3_whpYTLat+O7_tVWB9Qp~pqK%*+ zT&vpJ<38v^7YussJ9NJR4{E~tamZorvqc?4-QWB+-CtOvU)saCs6nYvhhg9a1r<)- z8B(SvQi1j5HPdWLwmC8upj~&oi*Oh!1Y@i*M3!|w0S6O{TaN(kJqC|v^)u?Q{IkEl zV(Nl^jaiLp%)16E47+p(M)wZRS6!JiZLHN{NwcM8@)P#R1|Zf3;Svwf>CWPG_Q2&( zF+mlFEi*>~3z7+9V?zWHj*gq!9}W(^A%cTKY?M#})t!dzIZ|n<6R&$mmYT(xwPnF{ zQ!VR*qKk%Z*#X(;`){DX@*Q^*K1t+*q=HRAk z*@Kg{HO8P3crKMsPIpj=!e3uWo)xMS$VOE76d=B!Qx7aRL!E%zt>zg*5d6kMd{Vr3 z9~%nJOgf)3`kvZn;<&~49jQ~F+K$MI`jf~9@WwNc2cIZbW?z5Td~nP>NTw&l4Kek+ zX2cn@A1c=0!0jEJU-+BDqFMYB&v{Mgd6zb(96=hH69w5e+!%cG5Th!(27d^BLimG+ zjQ@U>(C-azP_B`t1CQUY5ah?sqT5&idnM=ai=K@_S1!PWYQVX^*=u848C$J)|H(_V zE!JkYOHV0AH(w7fs4NI5xD;lh)j*MK@tB8JPFl!-s{b8@9sq*D&c! zI;s892sdE2Of)Sr7mxUXBeY4$*{J_uf;z+FnwFUJ|6Q zxPoxy1!6ILrT+j>DiXn6^dHD8hN8JhDh^Y#70tv6i@-!Hn@i>s2Zx~H0RGoTBNjte z`VRn9!Vx4z|AD+>5So~z;sAAkB(i7(krLQ1F{J<504S3G?5w^BG_|5ylHg=zjrjj> zJHpWF=O$xeiE%19ll})z5w=Aq;{U-B+NR`eG}@-~Bg5{W#q0P3q69qAgutx-)sl{J ziT|}F9c$grXt`LaA||!q&Y2qj{AtvcTo3*a1}!>T-Kz%vnHxzWi$q{44RDFUQ5*iB z4G1It&(119r`C%94}OW!Dm9Y)2aXYH46Xmo*|$&r$F?4hCw!UuO=U4XS?cil4lY4W zun2EAj_d7t0C84 zp(6!5!xuD>fD}vY0!LNQdJs!5z*??fZyT{ zJ4Je|;^JTk22_#8v4WG%<2iP`{>>vhf{?4JQI1XCQ9Zr2u>G!Z%Z5K1U{U!%A{Ze+ z)8qYbk6Pk(iSJCtMoAauv{8V6#7ou znlFC&(ifj^tqd9?=WF}Q(*ILVz?6&Qm%n0M&Yd2LmD~@X+Pom)1am! z0LRD6pGO1sIyHHV>6t()3k}E)LR6W%Qr$cqS9HIuNA)3uLv04$=Ni@Acp1~j>Y^hIvGrgPQJx6y&Hvent zMR-d(f@%bd0HK9JfJ}iLf;5FJ0mErv>Y=y)c>~~5u*G@4E#wH|b8sP;#V=xDB`)@c zYM^SM&Va1?-|g@Z>0>2Ww^aTi+y_FV^dkKGF*$zrhlRhZGH|7l_qDZCwOf#Y8Zoio zF(iutFe*P-t%2TPsPYg|aDt|o4?{H-BifQO{nb8Ew(nO`j{2ILacf2k{xxj*fjC2@ zNEH>DCQ@45q%4uJrm?J3nvEKjorQBn^ftcw@-g3i}14CU;qIhPb+$5^E&R8PA}pB{pC1 zVdUf@yv8L{O~{<}kY(H?No7e?5K%?Qn=x5Mh*eT0rjTPLrXljud?r!fx!41Ro&s6r zR<%g)>|#fNkRB!M4pNO173|xhP`J?AnQlB(4LU-Cr&{DfXrT9>w$6M(pb9iFck}>P zd^;*ZceA=aR@HjXilm%srLlLEk#ufQ7&bzl$uUHpJ+1_yn3+czd{;Idt$h*iVY}seHrH5n#4BJ|BG1K8E3-^wfBg7;|DbVlFG z4SiJWx@nrEx0X)^Wv|Z9+^CuA4Hkk&TeEQHX0rQ*x0C@*UVzK3`^ga(;jFD@_SLDAJniwz{A)o{C@&OIQ7WasnLWwBXo8cS+} zpoDUng=lUlY^<{H0HVE1eP#wBRA(bt9y{EGUSts21n)ZD}?Fr?!FFA{9Rg%R8 zXG$jxq$CrWtaElF!QjAFdXKv;P|Xq{ZlD#&Q!@(nhMJpNKG=s0geDxB(fz)PlGc-k zLQ6qK_N45uw0CokFqR5heXzAA)J1HJ0(fw>at4@y(C-UF2_f`VLCnHsGQm0w8WNoR zA~>&R7@>Sgq+rWY7@-Gp@SE^h-LuJDbG{9(-ZwE)Gy)qum4kmN73K)5g5I~Jl}-Aj zymHqR zPv|ZfU1t9XbBw0xgs=r6Mo)P~au9L!90_olS#_%gS(GqfW~w1k#fQ`9gkdRKGM=)u ze=q(~rIlQ>?v38Rk=a6oIkI)Qxf&`(!vrJ)d8Al=V>cZwVd<9`GM%3zfu+W27^8I}|$mJ47~e%1=IoMrM;=ha(C*3%v_J zq)RyGQ%^BBkR3u=XTAK!KFgi~my(XPmU zH@$=V9Q(Z!(eu$_bad28iTrv>zf%LW;E$nVbPlgyb;$>u_4L3N;nf`4zi>q|gC#On zwHRoY9Hr_EtZ5abjr$q!@!6~NSWBt9(K7akF0KV@i9c%U41Ob9RA%e+5GtW;#zhd* z&+-|M#6i?I*44$Y2nSx81dc z#-n`CNhGBTyckRbCA^F>+ma0WwP%+SUY7Ivy@}m3cGEnLFL(Qz+P-I%qq-nBOQWJl z44~;0>%0ikZtZw3iq%MOW=XfeDoDrjJVSXE^GzXk<-VY`ByL=EuZoDcCq)kI+lPWs zR48r>v9Rxxq0Y)`%Pts`TpKg7T^;HAXiWigql&ggA+se8+~K3B%A#H=-hI{!mTP%9lvk$1{ucE*R5m0N<;Qv!lMyEG z9I0s-V^MhuGQVGPEX$aw5>NtAG)o}w>Lm-DHD_^&Gh^!^;s#eCTA<1RLq&fivMOPi z7n0>wa9k0X5q7;c@C*3E2ExtKQB3byUh+*7QoKRhu^fvKBO=wKFy%?IR zrNANouWORSmAt$?X9#9U*z4DEewTM38gZlQxDyjg%wp6_WOl(&B$@>c=TlNR7tzdWu5P7xAT8w9J z`610wUfl%$8vm4A?5WVb?i1o<`Q}k=sI|fSqpOOH)icK@ZT6x>{yh7l z=8lbIA-<~AXd0#FxYfBhEehYc#1!TP_EBXTOtEKkG-!IqSt4+X1aO3wg?~UjY0&^) z8LXydUezdH52L2GIQHhKL1#K^DCWR>LYxum{sHU+32oszZ&`m$gaqH*D_=4;zkNz( z-bGMUVC_Nh?h2qBtY%I4{Nv_>&yJ9aD_J#KS+ylEmEa3i> zf+=ud3nK|x)a4FxCZ$R_5-yUVrADxLNHh{fYbkG`0wDf#7N>?eHpCL7GlF_wgy)m* z0F@+_JQTTW$gQtIM6ZN#)`Ld3??P2ggZxlVGe$!!6qkL$NUov?C(R8YJ4Nd{QozkW zj(P@&J!+~TIg{LHvp2|>B!t-(8a}vxlxCY1s!P1&YBwYKJI~01YLaQw z(r|oSxk*`URf(%Aqur%rEf2w&=M)!uEI|vCY?Xw)b%k>|o-HtBkMz8oWN?)Yix30b zp*TVXI1_!Xr{wTi?J>?96!Bg+rH%%xAayxC(7AK#I^z_lv`3EPw1!)tSG+dOGo1WtoMWsrKnP}~eumU-rGZXuFttmWLbi5YRU~Or z+Nm)}l1T-vfH;#6O2{fcd5>Xxg8+}MY5L!3uSmDU>8N)WC+7=ITNh-sj8q|M&~VWD zR5Ni$KQZrnOlz8ts-EQJo|@obKp

EO4K7bb!QNaMX-@J} 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 literal 0 HcmV?d00001 diff --git a/broadcast/DeployZapper.s.sol/1/run-1699554225.json b/broadcast/DeployZapper.s.sol/1/run-1699554225.json new file mode 100644 index 0000000..d9de3ce --- /dev/null +++ b/broadcast/DeployZapper.s.sol/1/run-1699554225.json @@ -0,0 +1,238 @@ +{ + "transactions": [ + { + "hash": "0xa843be8d7a03913ae8f70f5f51b90e11adcd06a5f55e32540e77cc007271ef40", + "transactionType": "CREATE", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "gas": "0x277ba0", + "value": "0x0", + "data": "0x608060405234801561001057600080fd5b5061001a3361002c565b6001805460ff60a01b19169055610098565b600180546001600160a01b031916905561004581610048565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6122a380620000a86000396000f3fe60806040526004361061016a5760003560e01c8063715018a6116100cb5780639c264df31161007f578063ba72467e11610059578063ba72467e146103b4578063e30c3978146103d4578063f2fde38b146103f257600080fd5b80639c264df3146103505780639e6f1f6614610371578063a1039de5146103a157600080fd5b80638456cb59116100b05780638456cb59146102e957806389476069146102fe5780638da5cb5b1461031e57600080fd5b8063715018a6146102bf57806379ba5097146102d457600080fd5b80633f4ba83a116101225780634a1534f4116101075780634a1534f41461026b5780635a18664c1461028b5780635c975abb146102a057600080fd5b80633f4ba83a14610236578063423513f11461024b57600080fd5b806306b829a91161015357806306b829a9146101b1578063393b8516146101d15780633c1502f81461021657600080fd5b806301fa5d561461016f578063063e5eb714610191575b600080fd5b34801561017b57600080fd5b5061018f61018a366004611e60565b610412565b005b34801561019d57600080fd5b5061018f6101ac366004611e60565b610480565b3480156101bd57600080fd5b5061018f6101cc366004611ecd565b610589565b3480156101dd57600080fd5b506102016101ec366004611e60565b60026020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b34801561022257600080fd5b5061018f610231366004611ecd565b610929565b34801561024257600080fd5b5061018f610cb1565b34801561025757600080fd5b5061018f610266366004611f58565b610cc3565b34801561027757600080fd5b5061018f610286366004611f58565b610ce5565b34801561029757600080fd5b5061018f610cfc565b3480156102ac57600080fd5b50600154600160a01b900460ff16610201565b3480156102cb57600080fd5b5061018f610d33565b3480156102e057600080fd5b5061018f610d45565b3480156102f557600080fd5b5061018f610dd0565b34801561030a57600080fd5b5061018f610319366004611e60565b610de0565b34801561032a57600080fd5b506000546001600160a01b03165b6040516001600160a01b03909116815260200161020d565b61036361035e366004611fdc565b610e65565b60405190815260200161020d565b34801561037d57600080fd5b5061020161038c366004611e60565b60036020526000908152604090205460ff1681565b6103636103af36600461206b565b61115b565b3480156103c057600080fd5b5061018f6103cf36600461210c565b611185565b3480156103e057600080fd5b506001546001600160a01b0316610338565b3480156103fe57600080fd5b5061018f61040d366004611e60565b6111e7565b61041a611265565b6001600160a01b038116600081815260036020908152604091829020805460ff81161560ff19909116811790915591518281529192917fd166590f22562bbdf8cfae03171c96fab89b02f3a8705085704575bb3b795cbd91015b60405180910390a25050565b610488611265565b6001600160a01b03811660009081526002602052604090205460ff161580156104b9576104b4826112bf565b610531565b610531826000846001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105219190612145565b6001600160a01b031691906113a8565b6001600160a01b038216600081815260026020908152604091829020805460ff191685151590811790915591519182527f67e1d668ec79170f9b4759aa0b1bb6d92edfad37be780bb42a72f572637644b19101610474565b6001600160a01b038416600090815260036020526040902054849060ff166105d457604051632462ed0960e01b81526001600160a01b03821660048201526024015b60405180910390fd5b6001600160a01b038616600090815260026020526040902054869060ff1661061a5760405163e9d6016160e01b81526001600160a01b03821660048201526024016105cb565b6106226114e4565b6000876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610662573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612145565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156106cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f09190612162565b90506001600160a01b03881663ba0876528730336040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815260048101939093526001600160a01b0391821660248401521660448201526064016020604051808303816000875af1158015610770573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107949190612162565b506107d58786868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061153e92505050565b506000886001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610816573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061083a9190612145565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015610880573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108a49190612162565b9050818111156108d157604051632db0390560e11b815260048101839052602481018290526044016105cb565b876001600160a01b0316896001600160a01b03167f623dc4ca876faa5fccd52d0d3e187f16d8d6457498edbd2492d7a6aabf0cb7448960405161091691815260200190565b60405180910390a3505050505050505050565b6001600160a01b038416600090815260036020526040902054849060ff1661096f57604051632462ed0960e01b81526001600160a01b03821660048201526024016105cb565b6001600160a01b038616600090815260026020526040902054869060ff166109b55760405163e9d6016160e01b81526001600160a01b03821660048201526024016105cb565b6109bd6114e4565b6000876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109fd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a219190612145565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015610a67573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a8b9190612162565b90506001600160a01b03881663b460af948730336040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b16815260048101939093526001600160a01b0391821660248401521660448201526064016020604051808303816000875af1158015610b0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2f9190612162565b50610b708786868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061153e92505050565b506000886001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bb1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bd59190612145565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015610c1b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c3f9190612162565b905081811115610c6c57604051632db0390560e11b815260048101839052602481018290526044016105cb565b876001600160a01b0316896001600160a01b03167fc3d5d1f4fa1c9b76d38aa7356792d8957236ee4c3073cde42dab63aefe16fe0f8960405161091691815260200190565b610cb9611265565b610cc161164f565b565b610cd086335b30846116bf565b610cdd8686868686610929565b505050505050565b610cef8633610cc9565b610cdd8686868686610589565b610d04611265565b60405133904780156108fc02916000818181858888f19350505050158015610d30573d6000803e3d6000fd5b50565b610d3b611265565b610cc16000611790565b60015433906001600160a01b03168114610dc75760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e6572000000000000000000000000000000000000000000000060648201526084016105cb565b610d3081611790565b610dd8611265565b610cc16117b6565b610de8611265565b610d30336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610e30573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e549190612162565b6001600160a01b0384169190611814565b6001600160a01b038516600090815260036020526040812054869060ff16610eab57604051632462ed0960e01b81526001600160a01b03821660048201526024016105cb565b6001600160a01b038816600090815260026020526040902054889060ff16610ef15760405163e9d6016160e01b81526001600160a01b03821660048201526024016105cb565b610ef96114e4565b85600003610f33576040517f01a01cca00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600034600003610fb7576040516370a0823160e01b81523060048201526001600160a01b038c16906370a0823190602401602060405180830381865afa158015610f81573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fa59190612162565b9050610fb2898c8a611862565b610fc4565b610fc1344761217b565b90505b6110048987878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061153e92505050565b5060003415611013574761107b565b6040516370a0823160e01b81523060048201526001600160a01b038d16906370a0823190602401602060405180830381865afa158015611057573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107b9190612162565b9050818111156110a857604051632db0390560e11b815260048101839052602481018290526044016105cb565b60006110b38c61192a565b9050888110156110f9576040517f6f7d15f100000000000000000000000000000000000000000000000000000000815260048101829052602481018a90526044016105cb565b604080516001600160a01b038f81168252602082018d9052918101839052818d16918e16907f3bbaafe3a26613ab5c4fd7390bafb0450ba2b86c6e7196b8200e6ae93489f5a59060600160405180910390a39c9b505050505050505050505050565b6000611169893330856116bf565b61117889898989898989610e65565b9998505050505050505050565b61118d611265565b6111a36001600160a01b038316826000196113a8565b816001600160a01b0316816001600160a01b03167fd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef060405160405180910390a35050565b6111ef611265565b600180546001600160a01b03831673ffffffffffffffffffffffffffffffffffffffff19909116811790915561122d6000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6000546001600160a01b03163314610cc15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105cb565b61130481600019836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104fd573d6000803e3d6000fd5b806001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611342573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113669190612145565b6001600160a01b0316816001600160a01b03167fe46f222dc28076f4f19a6286c1310e5ca995851a198499c3d185311b4e87ab6860405160405180910390a350565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b3000000000000000000000000000000000000000000000000000000001790526114278482611a92565b6114de576040516001600160a01b0384166024820152600060448201526114d49085907f095ea7b300000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152611b39565b6114de8482611b39565b50505050565b600154600160a01b900460ff1615610cc15760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a207061757365640000000000000000000000000000000060448201526064016105cb565b6060600080846001600160a01b0316348560405161155c91906121d9565b60006040518083038185875af1925050503d8060008114611599576040519150601f19603f3d011682016040523d82523d6000602084013e61159e565b606091505b509150915081611645578351156115e357806040517f4ecb9b6d0000000000000000000000000000000000000000000000000000000081526004016105cb91906121f5565b6040517f4ecb9b6d00000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f556e6b6e6f776e20726561736f6e00000000000000000000000000000000000060448201526064016105cb565b9150505b92915050565b611657611c21565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6001600160a01b03841663d505accf8484843560208601356116e76060880160408901612228565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561177257600080fd5b505af1158015611786573d6000803e3d6000fd5b5050505050505050565b6001805473ffffffffffffffffffffffffffffffffffffffff19169055610d3081611c7a565b6117be6114e4565b600180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586116a23390565b6040516001600160a01b03831660248201526044810182905261185d9084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401611470565b505050565b6118776001600160a01b038316333084611cd7565b806001600160a01b03831663dd62ed3e336040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b0391821660048201529087166024820152604401602060405180830381865afa1580156118ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119109190612162565b101561185d5761185d6001600160a01b03831684836113a8565b600080826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561196b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061198f9190612145565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa1580156119d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119fd9190612162565b6040517f6e553f65000000000000000000000000000000000000000000000000000000008152600481018290523360248201529091506001600160a01b03851690636e553f65906044016020604051808303816000875af1158015611a66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a8a9190612162565b949350505050565b6000806000846001600160a01b031684604051611aaf91906121d9565b6000604051808303816000865af19150503d8060008114611aec576040519150601f19603f3d011682016040523d82523d6000602084013e611af1565b606091505b5091509150818015611b1b575080511580611b1b575080806020019051810190611b1b919061224b565b8015611b3057506001600160a01b0385163b15155b95945050505050565b6000611b8e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d289092919063ffffffff16565b9050805160001480611baf575080806020019051810190611baf919061224b565b61185d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084016105cb565b600154600160a01b900460ff16610cc15760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f742070617573656400000000000000000000000060448201526064016105cb565b600080546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b03808516602483015283166044820152606481018290526114de9085907f23b872dd0000000000000000000000000000000000000000000000000000000090608401611470565b6060611a8a848460008585600080866001600160a01b03168587604051611d4f91906121d9565b60006040518083038185875af1925050503d8060008114611d8c576040519150601f19603f3d011682016040523d82523d6000602084013e611d91565b606091505b5091509150611da287838387611dad565b979650505050505050565b60608315611e1c578251600003611e15576001600160a01b0385163b611e155760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105cb565b5081611a8a565b611a8a8383815115611e315781518083602001fd5b8060405162461bcd60e51b81526004016105cb91906121f5565b6001600160a01b0381168114610d3057600080fd5b600060208284031215611e7257600080fd5b8135611e7d81611e4b565b9392505050565b60008083601f840112611e9657600080fd5b50813567ffffffffffffffff811115611eae57600080fd5b602083019150836020828501011115611ec657600080fd5b9250929050565b600080600080600060808688031215611ee557600080fd5b8535611ef081611e4b565b94506020860135611f0081611e4b565b935060408601359250606086013567ffffffffffffffff811115611f2357600080fd5b611f2f88828901611e84565b969995985093965092949392505050565b600060a08284031215611f5257600080fd5b50919050565b6000806000806000806101208789031215611f7257600080fd5b8635611f7d81611e4b565b95506020870135611f8d81611e4b565b945060408701359350606087013567ffffffffffffffff811115611fb057600080fd5b611fbc89828a01611e84565b9094509250611fd090508860808901611f40565b90509295509295509295565b600080600080600080600060c0888a031215611ff757600080fd5b873561200281611e4b565b9650602088013561201281611e4b565b9550604088013561202281611e4b565b9450606088013593506080880135925060a088013567ffffffffffffffff81111561204c57600080fd5b6120588a828b01611e84565b989b979a50959850939692959293505050565b600080600080600080600080610160898b03121561208857600080fd5b883561209381611e4b565b975060208901356120a381611e4b565b965060408901356120b381611e4b565b9550606089013594506080890135935060a089013567ffffffffffffffff8111156120dd57600080fd5b6120e98b828c01611e84565b90945092506120fd90508a60c08b01611f40565b90509295985092959890939650565b6000806040838503121561211f57600080fd5b823561212a81611e4b565b9150602083013561213a81611e4b565b809150509250929050565b60006020828403121561215757600080fd5b8151611e7d81611e4b565b60006020828403121561217457600080fd5b5051919050565b81810381811115611649577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60005b838110156121d05781810151838201526020016121b8565b50506000910152565b600082516121eb8184602087016121b5565b9190910192915050565b60208152600082518060208401526122148160408501602087016121b5565b601f01601f19169190910160400192915050565b60006020828403121561223a57600080fd5b813560ff81168114611e7d57600080fd5b60006020828403121561225d57600080fd5b81518015158114611e7d57600080fdfea264697066735822122088090587719944bcc8e893a1e27d26860f34e1c8d1724c40a5ec7850cc06ab4564736f6c63430008130033", + "nonce": "0x6", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x18129d5bd910d4c6ea4c48c13defe29a02e7a01f5f863b31287e8a4492c4a20c", + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "toggleRouterAuthorization(address)", + "arguments": [ + "0x1111111254EEB25477B68fb85Ed929f73A960582" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x11014", + "value": "0x0", + "data": "0x01fa5d560000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x7", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "approveTokenForRouter(address,address)", + "arguments": [ + "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "0x1111111254EEB25477B68fb85Ed929f73A960582" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x13602", + "value": "0x0", + "data": "0xba72467e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x8", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "approveTokenForRouter(address,address)", + "arguments": [ + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "0x1111111254EEB25477B68fb85Ed929f73A960582" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x16f87", + "value": "0x0", + "data": "0xba72467e000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x9", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "approveTokenForRouter(address,address)", + "arguments": [ + "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "0x1111111254EEB25477B68fb85Ed929f73A960582" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x130cf", + "value": "0x0", + "data": "0xba72467e000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xa", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "approveTokenForRouter(address,address)", + "arguments": [ + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "0x1111111254EEB25477B68fb85Ed929f73A960582" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x13578", + "value": "0x0", + "data": "0xba72467e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xb", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "approveTokenForRouter(address,address)", + "arguments": [ + "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "0x1111111254EEB25477B68fb85Ed929f73A960582" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1a349", + "value": "0x0", + "data": "0xba72467e000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xc", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "approveTokenForRouter(address,address)", + "arguments": [ + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "0x1111111254EEB25477B68fb85Ed929f73A960582" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x142a2", + "value": "0x0", + "data": "0xba72467e0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xd", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "toggleVaultAuthorization(address)", + "arguments": [ + "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1b8db", + "value": "0x0", + "data": "0x063e5eb70000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744", + "nonce": "0xe", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "VaultZapper", + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1112c", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0xf", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xa843be8d7a03913ae8f70f5f51b90e11adcd06a5f55e32540e77cc007271ef40", + "0x18129d5bd910d4c6ea4c48c13defe29a02e7a01f5f863b31287e8a4492c4a20c" + ], + "returns": {}, + "timestamp": 1699554225, + "chain": 1, + "multi": false, + "commit": "00f26c1" +} \ No newline at end of file diff --git a/broadcast/DeployZapper.s.sol/1/run-1699554508.json b/broadcast/DeployZapper.s.sol/1/run-1699554508.json new file mode 100644 index 0000000..5dcf48f --- /dev/null +++ b/broadcast/DeployZapper.s.sol/1/run-1699554508.json @@ -0,0 +1,204 @@ +{ + "transactions": [ + { + "hash": "0xf38e5e8197aa1283686ce1ee81883cad2ff3202e8b80e86eecf3a45072f7fa61", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x8acc", + "value": "0x0", + "data": "0x01fa5d560000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xc", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xb969", + "value": "0x0", + "data": "0xba72467e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xd", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x11376", + "value": "0x0", + "data": "0xba72467e000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xe", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xfb3d", + "value": "0x0", + "data": "0xba72467e000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xf", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xb8e7", + "value": "0x0", + "data": "0xba72467e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x10", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1a349", + "value": "0x0", + "data": "0xba72467e000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x11", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x142a2", + "value": "0x0", + "data": "0xba72467e0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x12", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1b8db", + "value": "0x0", + "data": "0x063e5eb70000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744", + "nonce": "0x13", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x978ccbb1cd9d3310a3a5dbc411e6672a0168660712fd190d6c5424d16a974405", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1112c", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x14", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xf38e5e8197aa1283686ce1ee81883cad2ff3202e8b80e86eecf3a45072f7fa61", + "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "0x978ccbb1cd9d3310a3a5dbc411e6672a0168660712fd190d6c5424d16a974405" + ], + "returns": {}, + "timestamp": 1699554508, + "chain": 1, + "multi": false, + "commit": "00f26c1" +} \ No newline at end of file diff --git a/broadcast/DeployZapper.s.sol/1/run-1699554522.json b/broadcast/DeployZapper.s.sol/1/run-1699554522.json new file mode 100644 index 0000000..abc3b4d --- /dev/null +++ b/broadcast/DeployZapper.s.sol/1/run-1699554522.json @@ -0,0 +1,616 @@ +{ + "transactions": [ + { + "hash": "0xf38e5e8197aa1283686ce1ee81883cad2ff3202e8b80e86eecf3a45072f7fa61", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x8acc", + "value": "0x0", + "data": "0x01fa5d560000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xc", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xb969", + "value": "0x0", + "data": "0xba72467e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xd", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x11376", + "value": "0x0", + "data": "0xba72467e000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xe", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xfb3d", + "value": "0x0", + "data": "0xba72467e000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xf", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xb8e7", + "value": "0x0", + "data": "0xba72467e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x10", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1a349", + "value": "0x0", + "data": "0xba72467e000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x11", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x142a2", + "value": "0x0", + "data": "0xba72467e0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x12", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1b8db", + "value": "0x0", + "data": "0x063e5eb70000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744", + "nonce": "0x13", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x978ccbb1cd9d3310a3a5dbc411e6672a0168660712fd190d6c5424d16a974405", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1112c", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x14", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xf38e5e8197aa1283686ce1ee81883cad2ff3202e8b80e86eecf3a45072f7fa61", + "transactionIndex": "0x2e", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x440869", + "gasUsed": "0x647e", + "contractAddress": null, + "logs": [ + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd166590f22562bbdf8cfae03171c96fab89b02f3a8705085704575bb3b795cbd", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xf38e5e8197aa1283686ce1ee81883cad2ff3202e8b80e86eecf3a45072f7fa61", + "transactionIndex": "0x2e", + "logIndex": "0x8a", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000100000000000000000000000000000000000000000000000000001000000000000000000000010000000000000000002000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000800000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionIndex": "0x2f", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x448ea6", + "gasUsed": "0x863d", + "contractAddress": null, + "logs": [ + { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionIndex": "0x2f", + "logIndex": "0x8b", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionIndex": "0x2f", + "logIndex": "0x8c", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000200000000000000000080000000008000000000000000000000000000002000000000010000000000000000000000000000000000000000000000001000000000000200000000000000000000000000000000000080000000000000000000400000000020000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000002000000000000000000000000000010000000000000000400000000000000000000000000100800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionIndex": "0x30", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x454b00", + "gasUsed": "0xbc5a", + "contractAddress": null, + "logs": [ + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionIndex": "0x30", + "logIndex": "0x8d", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionIndex": "0x30", + "logIndex": "0x8e", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000000100000000000000000000000000000000000000000000000000000000002000000000000000010000000000000000000200000000000000000080008000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200080000010000000000000000000000020000000000200000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000010000000000000000400000000000004000000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionIndex": "0x31", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x4600e5", + "gasUsed": "0xb5e5", + "contractAddress": null, + "logs": [ + { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionIndex": "0x31", + "logIndex": "0x8f", + "removed": false + }, + { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionIndex": "0x31", + "logIndex": "0x90", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionIndex": "0x31", + "logIndex": "0x91", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000000100000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000200000000000000000080000000000000000000000000000000000000002000000000000000000000000000000000000000000000000200000000001000000000000000000000000000000000000000000000000080000000000000000000000100000020000000000000000000080000004000000000000000000000000000000004000000000000000002000000000000000000000020000000000000000000000000010000000000000000400000000000000000000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionIndex": "0x32", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x4686c4", + "gasUsed": "0x85df", + "contractAddress": null, + "logs": [ + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionIndex": "0x32", + "logIndex": "0x92", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionIndex": "0x32", + "logIndex": "0x93", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000000100000000000000000000000000000000000000000000000000000000000000000000002000010080000000000000000200000000000000000080000000000000000800000000000000000000002000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000400000000000080000000000000000000000000000020000000000000000000000000004000000000000000000000000000000000000000000000000002000000000080000000000000000000000000000000000000010200000000000000400000000000000000000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionIndex": "0x33", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x47a575", + "gasUsed": "0x11eb1", + "contractAddress": null, + "logs": [ + { + "address": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionIndex": "0x33", + "logIndex": "0x94", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionIndex": "0x33", + "logIndex": "0x95", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000100000000000040000000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000200000000000000000080000000000000000100000000000000000000002000000000000000000000000000000000000200000000000000000000001000000000000000000000000000000000000000000000000080000000000000000000000000000020000000000000000000000800204000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000010000000000000000400000000000000800000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionIndex": "0x34", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x488210", + "gasUsed": "0xdc9b", + "contractAddress": null, + "logs": [ + { + "address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionIndex": "0x34", + "logIndex": "0x96", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionIndex": "0x34", + "logIndex": "0x97", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000020100000000000000000000000000000000000008000000000000000000000000000000000000010000000000000000000200000000000000000080000000000000000000000000000000000000002000000000000000000000000000000000000000000020000000000000001000000000000000000000000000000000000000000000000080000000000000000000000000000030000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000004000000000000000000000010000000000000000400000000000000200000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionIndex": "0x35", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x49c13d", + "gasUsed": "0x13f2d", + "contractAddress": null, + "logs": [ + { + "address": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionIndex": "0x35", + "logIndex": "0x98", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xe46f222dc28076f4f19a6286c1310e5ca995851a198499c3d185311b4e87ab68", + "0x0000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744", + "0x0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionIndex": "0x35", + "logIndex": "0x99", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0x67e1d668ec79170f9b4759aa0b1bb6d92edfad37be780bb42a72f572637644b1", + "0x0000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionIndex": "0x35", + "logIndex": "0x9a", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000001010000000000000000000208000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000010000000080000000000000080008000000000000000000002000020000000000000000000000000000000000000000000000000000000000000001000000000000100000000000000084000000000000000000000000080000000010000000000000001000008000000000000000004000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0x978ccbb1cd9d3310a3a5dbc411e6672a0168660712fd190d6c5424d16a974405", + "transactionIndex": "0x36", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x4a7c06", + "gasUsed": "0xbac9", + "contractAddress": null, + "logs": [ + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000255e26065387de09436db52acc4ae2a3cd11e854", + "0x00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x978ccbb1cd9d3310a3a5dbc411e6672a0168660712fd190d6c5424d16a974405", + "transactionIndex": "0x36", + "logIndex": "0x9b", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000020000000080000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000080000000000000080000000000000000000000000000000000000000020000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1699554522, + "chain": 1, + "multi": false, + "commit": "00f26c1" +} \ No newline at end of file diff --git a/broadcast/DeployZapper.s.sol/1/run-latest.json b/broadcast/DeployZapper.s.sol/1/run-latest.json new file mode 100644 index 0000000..abc3b4d --- /dev/null +++ b/broadcast/DeployZapper.s.sol/1/run-latest.json @@ -0,0 +1,616 @@ +{ + "transactions": [ + { + "hash": "0xf38e5e8197aa1283686ce1ee81883cad2ff3202e8b80e86eecf3a45072f7fa61", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x8acc", + "value": "0x0", + "data": "0x01fa5d560000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xc", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xb969", + "value": "0x0", + "data": "0xba72467e0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xd", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x11376", + "value": "0x0", + "data": "0xba72467e000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xe", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xfb3d", + "value": "0x0", + "data": "0xba72467e000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0xf", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0xb8e7", + "value": "0x0", + "data": "0xba72467e000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x10", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1a349", + "value": "0x0", + "data": "0xba72467e000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x11", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x142a2", + "value": "0x0", + "data": "0xba72467e0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c5990000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "nonce": "0x12", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1b8db", + "value": "0x0", + "data": "0x063e5eb70000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744", + "nonce": "0x13", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x978ccbb1cd9d3310a3a5dbc411e6672a0168660712fd190d6c5424d16a974405", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0xd697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "gas": "0x1112c", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x14", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xf38e5e8197aa1283686ce1ee81883cad2ff3202e8b80e86eecf3a45072f7fa61", + "transactionIndex": "0x2e", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x440869", + "gasUsed": "0x647e", + "contractAddress": null, + "logs": [ + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd166590f22562bbdf8cfae03171c96fab89b02f3a8705085704575bb3b795cbd", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xf38e5e8197aa1283686ce1ee81883cad2ff3202e8b80e86eecf3a45072f7fa61", + "transactionIndex": "0x2e", + "logIndex": "0x8a", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000100000000000000000000000000000000000000000000000000001000000000000000000000010000000000000000002000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000800000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionIndex": "0x2f", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x448ea6", + "gasUsed": "0x863d", + "contractAddress": null, + "logs": [ + { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionIndex": "0x2f", + "logIndex": "0x8b", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xd4ec45aa15eb9f2f36bdf48107c898fcd3e618816c0112f2830d08382cbc6007", + "transactionIndex": "0x2f", + "logIndex": "0x8c", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000200000000000000000080000000008000000000000000000000000000002000000000010000000000000000000000000000000000000000000000001000000000000200000000000000000000000000000000000080000000000000000000400000000020000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000002000000000000000000000000000010000000000000000400000000000000000000000000100800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionIndex": "0x30", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x454b00", + "gasUsed": "0xbc5a", + "contractAddress": null, + "logs": [ + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionIndex": "0x30", + "logIndex": "0x8d", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x5f1d3522720fd4ffe1dcf992074c0d990cc2666dd1e88ddc27dc2356e7a1ad5e", + "transactionIndex": "0x30", + "logIndex": "0x8e", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000000100000000000000000000000000000000000000000000000000000000002000000000000000010000000000000000000200000000000000000080008000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000200080000010000000000000000000000020000000000200000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000010000000000000000400000000000004000000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionIndex": "0x31", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x4600e5", + "gasUsed": "0xb5e5", + "contractAddress": null, + "logs": [ + { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionIndex": "0x31", + "logIndex": "0x8f", + "removed": false + }, + { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionIndex": "0x31", + "logIndex": "0x90", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x97d59903e4cdc1dd02a21090785a88831aee73fb3aa8a2cf83f109238cccdb42", + "transactionIndex": "0x31", + "logIndex": "0x91", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000000100000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000200000000000000000080000000000000000000000000000000000000002000000000000000000000000000000000000000000000000200000000001000000000000000000000000000000000000000000000000080000000000000000000000100000020000000000000000000080000004000000000000000000000000000000004000000000000000002000000000000000000000020000000000000000000000000010000000000000000400000000000000000000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionIndex": "0x32", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x4686c4", + "gasUsed": "0x85df", + "contractAddress": null, + "logs": [ + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionIndex": "0x32", + "logIndex": "0x92", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xf5e5ee25454d7f186c3dbe47ab15ec3e315c1b633c14c0671a3310bdbdcfdc99", + "transactionIndex": "0x32", + "logIndex": "0x93", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000000100000000000000000000000000000000000000000000000000000000000000000000002000010080000000000000000200000000000000000080000000000000000800000000000000000000002000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000400000000000080000000000000000000000000000020000000000000000000000000004000000000000000000000000000000000000000000000000002000000000080000000000000000000000000000000000000010200000000000000400000000000000000000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionIndex": "0x33", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x47a575", + "gasUsed": "0x11eb1", + "contractAddress": null, + "logs": [ + { + "address": "0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionIndex": "0x33", + "logIndex": "0x94", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe84" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x81154bd6e1f1448313ecedf0d4dd15ad37898857a0d63813ae174ae8d5036380", + "transactionIndex": "0x33", + "logIndex": "0x95", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000100000000000040000000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000200000000000000000080000000000000000100000000000000000000002000000000000000000000000000000000000200000000000000000000001000000000000000000000000000000000000000000000000080000000000000000000000000000020000000000000000000000800204000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000010000000000000000400000000000000800000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionIndex": "0x34", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x488210", + "gasUsed": "0xdc9b", + "contractAddress": null, + "logs": [ + { + "address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionIndex": "0x34", + "logIndex": "0x96", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xd6e8a8fc052939c88e845bbe596b2de2a07139e2fdeeed39548f594b82caaef0", + "0x0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582", + "0x0000000000000000000000002260fac5e5542a773aa44fbcfedf7c193bc2c599" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xbe7426c89d3aa63563cf985749a913156ea7f21544dfdb7cf6749f3b43d2242c", + "transactionIndex": "0x34", + "logIndex": "0x97", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000040000020100000000000000000000000000000000000008000000000000000000000000000000000000010000000000000000000200000000000000000080000000000000000000000000000000000000002000000000000000000000000000000000000000000020000000000000001000000000000000000000000000000000000000000000000080000000000000000000000000000030000000000000000000000000004000000000000000000000000000000000000000000000000002000000000000000000000000004000000000000000000000010000000000000000400000000000000200000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionIndex": "0x35", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x49c13d", + "gasUsed": "0x13f2d", + "contractAddress": null, + "logs": [ + { + "address": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000d697d2af3ddfe4ed24e92a230c4b93606b5d05fb", + "0x0000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionIndex": "0x35", + "logIndex": "0x98", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0xe46f222dc28076f4f19a6286c1310e5ca995851a198499c3d185311b4e87ab68", + "0x0000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744", + "0x0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionIndex": "0x35", + "logIndex": "0x99", + "removed": false + }, + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0x67e1d668ec79170f9b4759aa0b1bb6d92edfad37be780bb42a72f572637644b1", + "0x0000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000001", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0xcda6adb63784462ae65e7d0bc46ab8696721008fb99842830869dd16dbb60929", + "transactionIndex": "0x35", + "logIndex": "0x9a", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000001010000000000000000000208000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000010000000080000000000000080008000000000000000000002000020000000000000000000000000000000000000000000000000000000000000001000000000000100000000000000084000000000000000000000000080000000010000000000000001000008000000000000000004000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + }, + { + "transactionHash": "0x978ccbb1cd9d3310a3a5dbc411e6672a0168660712fd190d6c5424d16a974405", + "transactionIndex": "0x36", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "from": "0x255e26065387de09436DB52AcC4aE2a3CD11E854", + "to": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "cumulativeGasUsed": "0x4a7c06", + "gasUsed": "0xbac9", + "contractAddress": null, + "logs": [ + { + "address": "0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000255e26065387de09436db52acc4ae2a3cd11e854", + "0x00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca" + ], + "data": "0x", + "blockHash": "0x640d180255a923e820c277574f7cd541ea8ce0b86f6bc5310860ddf59790d602", + "blockNumber": "0x11ad6f4", + "transactionHash": "0x978ccbb1cd9d3310a3a5dbc411e6672a0168660712fd190d6c5424d16a974405", + "transactionIndex": "0x36", + "logIndex": "0x9b", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000020000000080000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000080000000000000080000000000000000000000000000000000000000020000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xc7bc9f3d7" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1699554522, + "chain": 1, + "multi": false, + "commit": "00f26c1" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517528.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517528.json new file mode 100644 index 0000000..24dfe7d --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517528.json @@ -0,0 +1,38 @@ +{ + "transactions": [ + { + "hash": "0x3b667395a3f3d7308d9e0e3baf4fec6804133e0ff70016494b68f9ea1c76ff68", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVault", + "contractAddress": "0x642eC60A61d26b472f1E4E0e79A83818eF90768d", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "test", + "test", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2734a3", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200259f3803806200259f83398101604081905262000034916200026b565b8282600362000044838262000397565b50600462000053828262000397565b505050620000706200006a6200011b60201b60201c565b6200011f565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000f7919062000463565b60ff91011660805250506008805462ff000019166201000017905550620004889050565b3390565b600680546001600160a01b03191690556200013a816200013d565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001b757600080fd5b81516001600160401b0380821115620001d457620001d46200018f565b604051601f8301601f19908116603f01168101908282118183101715620001ff57620001ff6200018f565b816040528381526020925086838588010111156200021c57600080fd5b600091505b8382101562000240578582018301518183018401529082019062000221565b600093810190920192909252949350505050565b805160ff811681146200026657600080fd5b919050565b600080600080608085870312156200028257600080fd5b84516001600160a01b03811681146200029a57600080fd5b60208601519094506001600160401b0380821115620002b857600080fd5b620002c688838901620001a5565b94506040870151915080821115620002dd57600080fd5b50620002ec87828801620001a5565b925050620002fd6060860162000254565b905092959194509250565b600181811c908216806200031d57607f821691505b6020821081036200033e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039257600081815260208120601f850160051c810160208610156200036d5750805b601f850160051c820191505b818110156200038e5782815560010162000379565b5050505b505050565b81516001600160401b03811115620003b357620003b36200018f565b620003cb81620003c4845462000308565b8462000344565b602080601f831160018114620004035760008415620003ea5750858301515b600019600386901b1c1916600185901b1785556200038e565b600085815260208120601f198616915b82811015620004345788860151825594840194600190910190840162000413565b5085821015620004535787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047657600080fd5b620004818262000254565b9392505050565b60805160a05160c0516120af620004f0600039600081816104c301528181610f8e01526110f80152600081816103a0015281816107580152818161082601528181610c9d01528181610efe0152818161150b015261161e0152600061035901526120af6000f3fe608060405234801561001057600080fd5b506004361061027f5760003560e01c8063715018a61161015c578063ba087652116100ce578063d905777e11610087578063d905777e14610585578063dd62ed3e14610598578063e30c3978146105ab578063eea29132146105bc578063ef8b30f71461054c578063f2fde38b146105cf57600080fd5b8063ba08765214610531578063be9a655514610544578063c63d75b614610406578063c6e6f5921461054c578063ca1123c21461055f578063ce96cb771461057257600080fd5b806395d89b411161012057806395d89b41146104b657806396b298c5146104be578063a457c2d7146104e5578063a9059cbb146104f8578063b3d7f6b91461050b578063b460af941461051e57600080fd5b8063715018a61461047a57806379ba5097146104825780638456cb591461048a5780638da5cb5b1461049257806394bf804d146104a357600080fd5b806332f289cf116101f5578063402d267d116101b9578063402d267d146104065780634375d8cd146104195780634cdad506146102bd5780635c975abb1461042c5780636e553f651461043e57806370a082311461045157600080fd5b806332f289cf1461038b57806338d52e0f1461039e57806339509351146103d85780633ee3d6bc146103eb5780633f4ba83a146103fe57600080fd5b80630a28a477116102475780630a28a477146102f35780630ad245281461030657806318160ddd1461031b57806323b872dd146103235780633035106b14610336578063313ce5671461035757600080fd5b806301e1d114146102845780630217631e1461029f57806306fdde03146102a857806307a2d13a146102bd578063095ea7b3146102d0575b600080fd5b61028c6105e2565b6040519081526020015b60405180910390f35b61028c60075481565b6102b0610618565b6040516102969190611c96565b61028c6102cb366004611cc9565b6106aa565b6102e36102de366004611cf7565b6106bd565b6040519015158152602001610296565b61028c610301366004611cc9565b6106d5565b610319610314366004611cc9565b6106e2565b005b60025461028c565b6102e3610331366004611d23565b6107f6565b6008546103449061ffff1681565b60405161ffff9091168152602001610296565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff9091168152602001610296565b610319610399366004611d64565b61081c565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610296565b6102e36103e6366004611cf7565b6108f6565b61028c6103f9366004611d81565b610918565b61031961095f565b61028c610414366004611d64565b610971565b6008546102e39062010000900460ff1681565b600654600160a01b900460ff166102e3565b61028c61044c366004611da8565b6109a9565b61028c61045f366004611d64565b6001600160a01b031660009081526020819052604090205490565b6103196109f7565b610319610a09565b610319610a80565b6005546001600160a01b03166103c0565b61028c6104b1366004611da8565b610a90565b6102b0610ade565b6103797f000000000000000000000000000000000000000000000000000000000000000081565b6102e36104f3366004611cf7565b610aed565b6102e3610506366004611cf7565b610b73565b61028c610519366004611cc9565b610b81565b61028c61052c366004611dd8565b610b8e565b61028c61053f366004611dd8565b610be5565b610319610c33565b61028c61055a366004611cc9565b610d0c565b61031961056d366004611e1a565b610d19565b61028c610580366004611d64565b610d99565b61028c610593366004611d64565b610ddc565b61028c6105a6366004611e3e565b610e14565b6006546001600160a01b03166103c0565b61028c6105ca366004611d81565b610e3f565b6103196105dd366004611d64565b610e75565b60085460009062010000900460ff1615610603576105fe610ee6565b905090565b60075461060e610ee6565b6105fe9190611e82565b60606003805461062790611e95565b80601f016020809104026020016040519081016040528092919081815260200182805461065390611e95565b80156106a05780601f10610675576101008083540402835291602001916106a0565b820191906000526020600020905b81548152906001019060200180831161068357829003601f168201915b5050505050905090565b60006106b7826000610f71565b92915050565b6000336106cb818585610fca565b5060019392505050565b60006106b78260016110ee565b6106ea61113e565b60085462010000900460ff16156107145760405163cf9c0f0960e01b815260040160405180910390fd5b60006007548211801561072c575060085461ffff1615155b15610753576007546008549083039061074f90829061ffff166127106001611198565b9150505b6107887f000000000000000000000000000000000000000000000000000000000000000033306107838587611ecf565b6111f3565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb9084846107cf60025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b600033610804858285611264565b61080f8585856112d8565b60019150505b9392505050565b61082461113e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03160361087657604051634b51153360e11b815260040160405180910390fd5b6108f3336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156108be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e29190611ee2565b6001600160a01b038416919061147c565b50565b6000336106cb8185856109098383610e14565b6109139190611e82565b610fca565b6000806109258585610a90565b90508281111561095757838184604051632e18fdcb60e01b815260040161094e93929190611efb565b60405180910390fd5b949350505050565b61096761113e565b61096f6114b1565b565b60085460009062010000900460ff1615806109955750600654600160a01b900460ff165b6109a1576000196106b7565b600092915050565b6000806109b583610971565b9050808411156109de57828482604051633c8097d960e11b815260040161094e93929190611efb565b60006109e985610d0c565b905061095733858784611506565b6109ff61113e565b61096f6000611598565b60065433906001600160a01b03168114610a775760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840161094e565b6108f381611598565b610a8861113e565b61096f6115b1565b600080610a9c83610971565b905080841115610ac55782848260405163284ff66760e01b815260040161094e93929190611efb565b6000610ad085610b81565b905061095733858388611506565b60606004805461062790611e95565b60003381610afb8286610e14565b905083811015610b5b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161094e565b610b688286868403610fca565b506001949350505050565b6000336106cb8185856112d8565b60006106b7826001610f71565b600080610b9a83610d99565b905080851115610bc357828582604051633fa733bb60e21b815260040161094e93929190611efb565b6000610bce866106d5565b9050610bdc858588846115f4565b95945050505050565b600080610bf183610ddc565b905080851115610c1a57828582604051632e52afbb60e21b815260040161094e93929190611efb565b6000610c25866106aa565b9050610bdc858583896115f4565b610c3b61113e565b60085462010000900460ff16610c6457604051635adc30c160e11b815260040160405180910390fd5b610c6c610ee6565b6007556008805462ff000019169055610cc4610c906005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061147c565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610cf260025490565b6040805192835260208301919091520160405180910390a2565b60006106b78260006110ee565b610d2161113e565b610bb88161ffff161115610d485760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610db35760006106b7565b6106b7610dd5836001600160a01b031660009081526020819052604090205490565b6000610f71565b60085460009062010000900460ff16610df65760006106b7565b6001600160a01b0382166000908152602081905260409020546106b7565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610e4c85856109a9565b9050828110156109575783818460405163d032c98360e01b815260040161094e93929190611efb565b610e7d61113e565b600680546001600160a01b0383166001600160a01b03199091168117909155610eae6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fe9190611ee2565b6000610815610f7e6105e2565b610f89906001611e82565b610fb47f0000000000000000000000000000000000000000000000000000000000000000600a612000565b600254610fc19190611e82565b85919085611198565b6001600160a01b03831661102c5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161094e565b6001600160a01b03821661108d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161094e565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061081561111e7f0000000000000000000000000000000000000000000000000000000000000000600a612000565b60025461112b9190611e82565b6111336105e2565b610fc1906001611e82565b6005546001600160a01b0316331461096f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161094e565b6000806111a68686866116b0565b905060018360028111156111bc576111bc61200f565b1480156111d95750600084806111d4576111d4612025565b868809115b15610bdc576111e9600182611e82565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261125e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261179a565b50505050565b60006112708484610e14565b9050600019811461125e57818110156112cb5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161094e565b61125e8484848403610fca565b6001600160a01b03831661133c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161094e565b6001600160a01b03821661139e5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161094e565b6001600160a01b038316600090815260208190526040902054818110156114165760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161094e565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361125e565b6040516001600160a01b0383166024820152604481018290526114ac90849063a9059cbb60e01b90606401611227565b505050565b6114b961186f565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6115327f00000000000000000000000000000000000000000000000000000000000000008530856111f3565b61153c83826118bf565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161158a929190918252602082015260400190565b60405180910390a350505050565b600680546001600160a01b03191690556108f38161197e565b6115b96119d0565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114e93390565b336001600160a01b0384161461160f5761160f833383611264565b6116198382611a1d565b6116447f0000000000000000000000000000000000000000000000000000000000000000858461147c565b826001600160a01b0316846001600160a01b031661165f3390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db85856040516116a2929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036116ea578382816116e0576116e0612025565b0492505050610815565b8084116117315760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b604482015260640161094e565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006117ef826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b4f9092919063ffffffff16565b9050805160001480611810575080806020019051810190611810919061203b565b6114ac5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161094e565b600654600160a01b900460ff1661096f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161094e565b6001600160a01b0382166119155760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161094e565b80600260008282546119279190611e82565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff161561096f5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161094e565b6001600160a01b038216611a7d5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161094e565b6001600160a01b03821660009081526020819052604090205481811015611af15760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161094e565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6060610957848460008585600080866001600160a01b03168587604051611b76919061205d565b60006040518083038185875af1925050503d8060008114611bb3576040519150601f19603f3d011682016040523d82523d6000602084013e611bb8565b606091505b5091509150611bc987838387611bd4565b979650505050505050565b60608315611c43578251600003611c3c576001600160a01b0385163b611c3c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161094e565b5081610957565b6109578383815115611c585781518083602001fd5b8060405162461bcd60e51b815260040161094e9190611c96565b60005b83811015611c8d578181015183820152602001611c75565b50506000910152565b6020815260008251806020840152611cb5816040850160208701611c72565b601f01601f19169190910160400192915050565b600060208284031215611cdb57600080fd5b5035919050565b6001600160a01b03811681146108f357600080fd5b60008060408385031215611d0a57600080fd5b8235611d1581611ce2565b946020939093013593505050565b600080600060608486031215611d3857600080fd5b8335611d4381611ce2565b92506020840135611d5381611ce2565b929592945050506040919091013590565b600060208284031215611d7657600080fd5b813561081581611ce2565b600080600060608486031215611d9657600080fd5b833592506020840135611d5381611ce2565b60008060408385031215611dbb57600080fd5b823591506020830135611dcd81611ce2565b809150509250929050565b600080600060608486031215611ded57600080fd5b833592506020840135611dff81611ce2565b91506040840135611e0f81611ce2565b809150509250925092565b600060208284031215611e2c57600080fd5b813561ffff8116811461081557600080fd5b60008060408385031215611e5157600080fd5b8235611e5c81611ce2565b91506020830135611dcd81611ce2565b634e487b7160e01b600052601160045260246000fd5b808201808211156106b7576106b7611e6c565b600181811c90821680611ea957607f821691505b602082108103611ec957634e487b7160e01b600052602260045260246000fd5b50919050565b818103818111156106b7576106b7611e6c565b600060208284031215611ef457600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b80851115611f57578160001904821115611f3d57611f3d611e6c565b80851615611f4a57918102915b93841c9390800290611f21565b509250929050565b600082611f6e575060016106b7565b81611f7b575060006106b7565b8160018114611f915760028114611f9b57611fb7565b60019150506106b7565b60ff841115611fac57611fac611e6c565b50506001821b6106b7565b5060208310610133831016604e8410600b8410161715611fda575081810a6106b7565b611fe48383611f1c565b8060001904821115611ff857611ff8611e6c565b029392505050565b600061081560ff841683611f5f565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60006020828403121561204d57600080fd5b8151801515811461081557600080fd5b6000825161206f818460208701611c72565b919091019291505056fea26469706673582212206194a91bc0127a6aea3903abaa84084327ddb1752fc3b73e1f57e74da641ed2a64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004746573740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000", + "nonce": "0x46", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x3b667395a3f3d7308d9e0e3baf4fec6804133e0ff70016494b68f9ea1c76ff68" + ], + "returns": {}, + "timestamp": 1696517528, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517534.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517534.json new file mode 100644 index 0000000..ee82069 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517534.json @@ -0,0 +1,69 @@ +{ + "transactions": [ + { + "hash": "0x3b667395a3f3d7308d9e0e3baf4fec6804133e0ff70016494b68f9ea1c76ff68", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVault", + "contractAddress": "0x642eC60A61d26b472f1E4E0e79A83818eF90768d", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "test", + "test", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2734a3", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200259f3803806200259f83398101604081905262000034916200026b565b8282600362000044838262000397565b50600462000053828262000397565b505050620000706200006a6200011b60201b60201c565b6200011f565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000f7919062000463565b60ff91011660805250506008805462ff000019166201000017905550620004889050565b3390565b600680546001600160a01b03191690556200013a816200013d565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001b757600080fd5b81516001600160401b0380821115620001d457620001d46200018f565b604051601f8301601f19908116603f01168101908282118183101715620001ff57620001ff6200018f565b816040528381526020925086838588010111156200021c57600080fd5b600091505b8382101562000240578582018301518183018401529082019062000221565b600093810190920192909252949350505050565b805160ff811681146200026657600080fd5b919050565b600080600080608085870312156200028257600080fd5b84516001600160a01b03811681146200029a57600080fd5b60208601519094506001600160401b0380821115620002b857600080fd5b620002c688838901620001a5565b94506040870151915080821115620002dd57600080fd5b50620002ec87828801620001a5565b925050620002fd6060860162000254565b905092959194509250565b600181811c908216806200031d57607f821691505b6020821081036200033e57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039257600081815260208120601f850160051c810160208610156200036d5750805b601f850160051c820191505b818110156200038e5782815560010162000379565b5050505b505050565b81516001600160401b03811115620003b357620003b36200018f565b620003cb81620003c4845462000308565b8462000344565b602080601f831160018114620004035760008415620003ea5750858301515b600019600386901b1c1916600185901b1785556200038e565b600085815260208120601f198616915b82811015620004345788860151825594840194600190910190840162000413565b5085821015620004535787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047657600080fd5b620004818262000254565b9392505050565b60805160a05160c0516120af620004f0600039600081816104c301528181610f8e01526110f80152600081816103a0015281816107580152818161082601528181610c9d01528181610efe0152818161150b015261161e0152600061035901526120af6000f3fe608060405234801561001057600080fd5b506004361061027f5760003560e01c8063715018a61161015c578063ba087652116100ce578063d905777e11610087578063d905777e14610585578063dd62ed3e14610598578063e30c3978146105ab578063eea29132146105bc578063ef8b30f71461054c578063f2fde38b146105cf57600080fd5b8063ba08765214610531578063be9a655514610544578063c63d75b614610406578063c6e6f5921461054c578063ca1123c21461055f578063ce96cb771461057257600080fd5b806395d89b411161012057806395d89b41146104b657806396b298c5146104be578063a457c2d7146104e5578063a9059cbb146104f8578063b3d7f6b91461050b578063b460af941461051e57600080fd5b8063715018a61461047a57806379ba5097146104825780638456cb591461048a5780638da5cb5b1461049257806394bf804d146104a357600080fd5b806332f289cf116101f5578063402d267d116101b9578063402d267d146104065780634375d8cd146104195780634cdad506146102bd5780635c975abb1461042c5780636e553f651461043e57806370a082311461045157600080fd5b806332f289cf1461038b57806338d52e0f1461039e57806339509351146103d85780633ee3d6bc146103eb5780633f4ba83a146103fe57600080fd5b80630a28a477116102475780630a28a477146102f35780630ad245281461030657806318160ddd1461031b57806323b872dd146103235780633035106b14610336578063313ce5671461035757600080fd5b806301e1d114146102845780630217631e1461029f57806306fdde03146102a857806307a2d13a146102bd578063095ea7b3146102d0575b600080fd5b61028c6105e2565b6040519081526020015b60405180910390f35b61028c60075481565b6102b0610618565b6040516102969190611c96565b61028c6102cb366004611cc9565b6106aa565b6102e36102de366004611cf7565b6106bd565b6040519015158152602001610296565b61028c610301366004611cc9565b6106d5565b610319610314366004611cc9565b6106e2565b005b60025461028c565b6102e3610331366004611d23565b6107f6565b6008546103449061ffff1681565b60405161ffff9091168152602001610296565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff9091168152602001610296565b610319610399366004611d64565b61081c565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610296565b6102e36103e6366004611cf7565b6108f6565b61028c6103f9366004611d81565b610918565b61031961095f565b61028c610414366004611d64565b610971565b6008546102e39062010000900460ff1681565b600654600160a01b900460ff166102e3565b61028c61044c366004611da8565b6109a9565b61028c61045f366004611d64565b6001600160a01b031660009081526020819052604090205490565b6103196109f7565b610319610a09565b610319610a80565b6005546001600160a01b03166103c0565b61028c6104b1366004611da8565b610a90565b6102b0610ade565b6103797f000000000000000000000000000000000000000000000000000000000000000081565b6102e36104f3366004611cf7565b610aed565b6102e3610506366004611cf7565b610b73565b61028c610519366004611cc9565b610b81565b61028c61052c366004611dd8565b610b8e565b61028c61053f366004611dd8565b610be5565b610319610c33565b61028c61055a366004611cc9565b610d0c565b61031961056d366004611e1a565b610d19565b61028c610580366004611d64565b610d99565b61028c610593366004611d64565b610ddc565b61028c6105a6366004611e3e565b610e14565b6006546001600160a01b03166103c0565b61028c6105ca366004611d81565b610e3f565b6103196105dd366004611d64565b610e75565b60085460009062010000900460ff1615610603576105fe610ee6565b905090565b60075461060e610ee6565b6105fe9190611e82565b60606003805461062790611e95565b80601f016020809104026020016040519081016040528092919081815260200182805461065390611e95565b80156106a05780601f10610675576101008083540402835291602001916106a0565b820191906000526020600020905b81548152906001019060200180831161068357829003601f168201915b5050505050905090565b60006106b7826000610f71565b92915050565b6000336106cb818585610fca565b5060019392505050565b60006106b78260016110ee565b6106ea61113e565b60085462010000900460ff16156107145760405163cf9c0f0960e01b815260040160405180910390fd5b60006007548211801561072c575060085461ffff1615155b15610753576007546008549083039061074f90829061ffff166127106001611198565b9150505b6107887f000000000000000000000000000000000000000000000000000000000000000033306107838587611ecf565b6111f3565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb9084846107cf60025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b600033610804858285611264565b61080f8585856112d8565b60019150505b9392505050565b61082461113e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b03160361087657604051634b51153360e11b815260040160405180910390fd5b6108f3336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa1580156108be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108e29190611ee2565b6001600160a01b038416919061147c565b50565b6000336106cb8185856109098383610e14565b6109139190611e82565b610fca565b6000806109258585610a90565b90508281111561095757838184604051632e18fdcb60e01b815260040161094e93929190611efb565b60405180910390fd5b949350505050565b61096761113e565b61096f6114b1565b565b60085460009062010000900460ff1615806109955750600654600160a01b900460ff165b6109a1576000196106b7565b600092915050565b6000806109b583610971565b9050808411156109de57828482604051633c8097d960e11b815260040161094e93929190611efb565b60006109e985610d0c565b905061095733858784611506565b6109ff61113e565b61096f6000611598565b60065433906001600160a01b03168114610a775760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b606482015260840161094e565b6108f381611598565b610a8861113e565b61096f6115b1565b600080610a9c83610971565b905080841115610ac55782848260405163284ff66760e01b815260040161094e93929190611efb565b6000610ad085610b81565b905061095733858388611506565b60606004805461062790611e95565b60003381610afb8286610e14565b905083811015610b5b5760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b606482015260840161094e565b610b688286868403610fca565b506001949350505050565b6000336106cb8185856112d8565b60006106b7826001610f71565b600080610b9a83610d99565b905080851115610bc357828582604051633fa733bb60e21b815260040161094e93929190611efb565b6000610bce866106d5565b9050610bdc858588846115f4565b95945050505050565b600080610bf183610ddc565b905080851115610c1a57828582604051632e52afbb60e21b815260040161094e93929190611efb565b6000610c25866106aa565b9050610bdc858583896115f4565b610c3b61113e565b60085462010000900460ff16610c6457604051635adc30c160e11b815260040160405180910390fd5b610c6c610ee6565b6007556008805462ff000019169055610cc4610c906005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061147c565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610cf260025490565b6040805192835260208301919091520160405180910390a2565b60006106b78260006110ee565b610d2161113e565b610bb88161ffff161115610d485760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610db35760006106b7565b6106b7610dd5836001600160a01b031660009081526020819052604090205490565b6000610f71565b60085460009062010000900460ff16610df65760006106b7565b6001600160a01b0382166000908152602081905260409020546106b7565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610e4c85856109a9565b9050828110156109575783818460405163d032c98360e01b815260040161094e93929190611efb565b610e7d61113e565b600680546001600160a01b0383166001600160a01b03199091168117909155610eae6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fe9190611ee2565b6000610815610f7e6105e2565b610f89906001611e82565b610fb47f0000000000000000000000000000000000000000000000000000000000000000600a612000565b600254610fc19190611e82565b85919085611198565b6001600160a01b03831661102c5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b606482015260840161094e565b6001600160a01b03821661108d5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b606482015260840161094e565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061081561111e7f0000000000000000000000000000000000000000000000000000000000000000600a612000565b60025461112b9190611e82565b6111336105e2565b610fc1906001611e82565b6005546001600160a01b0316331461096f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640161094e565b6000806111a68686866116b0565b905060018360028111156111bc576111bc61200f565b1480156111d95750600084806111d4576111d4612025565b868809115b15610bdc576111e9600182611e82565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261125e9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261179a565b50505050565b60006112708484610e14565b9050600019811461125e57818110156112cb5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e6365000000604482015260640161094e565b61125e8484848403610fca565b6001600160a01b03831661133c5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b606482015260840161094e565b6001600160a01b03821661139e5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b606482015260840161094e565b6001600160a01b038316600090815260208190526040902054818110156114165760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b606482015260840161094e565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361125e565b6040516001600160a01b0383166024820152604481018290526114ac90849063a9059cbb60e01b90606401611227565b505050565b6114b961186f565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6115327f00000000000000000000000000000000000000000000000000000000000000008530856111f3565b61153c83826118bf565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161158a929190918252602082015260400190565b60405180910390a350505050565b600680546001600160a01b03191690556108f38161197e565b6115b96119d0565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586114e93390565b336001600160a01b0384161461160f5761160f833383611264565b6116198382611a1d565b6116447f0000000000000000000000000000000000000000000000000000000000000000858461147c565b826001600160a01b0316846001600160a01b031661165f3390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db85856040516116a2929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036116ea578382816116e0576116e0612025565b0492505050610815565b8084116117315760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b604482015260640161094e565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006117ef826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611b4f9092919063ffffffff16565b9050805160001480611810575080806020019051810190611810919061203b565b6114ac5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161094e565b600654600160a01b900460ff1661096f5760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b604482015260640161094e565b6001600160a01b0382166119155760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015260640161094e565b80600260008282546119279190611e82565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff161561096f5760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b604482015260640161094e565b6001600160a01b038216611a7d5760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b606482015260840161094e565b6001600160a01b03821660009081526020819052604090205481811015611af15760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b606482015260840161094e565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6060610957848460008585600080866001600160a01b03168587604051611b76919061205d565b60006040518083038185875af1925050503d8060008114611bb3576040519150601f19603f3d011682016040523d82523d6000602084013e611bb8565b606091505b5091509150611bc987838387611bd4565b979650505050505050565b60608315611c43578251600003611c3c576001600160a01b0385163b611c3c5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161094e565b5081610957565b6109578383815115611c585781518083602001fd5b8060405162461bcd60e51b815260040161094e9190611c96565b60005b83811015611c8d578181015183820152602001611c75565b50506000910152565b6020815260008251806020840152611cb5816040850160208701611c72565b601f01601f19169190910160400192915050565b600060208284031215611cdb57600080fd5b5035919050565b6001600160a01b03811681146108f357600080fd5b60008060408385031215611d0a57600080fd5b8235611d1581611ce2565b946020939093013593505050565b600080600060608486031215611d3857600080fd5b8335611d4381611ce2565b92506020840135611d5381611ce2565b929592945050506040919091013590565b600060208284031215611d7657600080fd5b813561081581611ce2565b600080600060608486031215611d9657600080fd5b833592506020840135611d5381611ce2565b60008060408385031215611dbb57600080fd5b823591506020830135611dcd81611ce2565b809150509250929050565b600080600060608486031215611ded57600080fd5b833592506020840135611dff81611ce2565b91506040840135611e0f81611ce2565b809150509250925092565b600060208284031215611e2c57600080fd5b813561ffff8116811461081557600080fd5b60008060408385031215611e5157600080fd5b8235611e5c81611ce2565b91506020830135611dcd81611ce2565b634e487b7160e01b600052601160045260246000fd5b808201808211156106b7576106b7611e6c565b600181811c90821680611ea957607f821691505b602082108103611ec957634e487b7160e01b600052602260045260246000fd5b50919050565b818103818111156106b7576106b7611e6c565b600060208284031215611ef457600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b80851115611f57578160001904821115611f3d57611f3d611e6c565b80851615611f4a57918102915b93841c9390800290611f21565b509250929050565b600082611f6e575060016106b7565b81611f7b575060006106b7565b8160018114611f915760028114611f9b57611fb7565b60019150506106b7565b60ff841115611fac57611fac611e6c565b50506001821b6106b7565b5060208310610133831016604e8410600b8410161715611fda575081810a6106b7565b611fe48383611f1c565b8060001904821115611ff857611ff8611e6c565b029392505050565b600061081560ff841683611f5f565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60006020828403121561204d57600080fd5b8151801515811461081557600080fd5b6000825161206f818460208701611c72565b919091019291505056fea26469706673582212206194a91bc0127a6aea3903abaa84084327ddb1752fc3b73e1f57e74da641ed2a64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000004746573740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000", + "nonce": "0x46", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x3b667395a3f3d7308d9e0e3baf4fec6804133e0ff70016494b68f9ea1c76ff68", + "transactionIndex": "0x0", + "blockHash": "0x84ad226745b7be905ea3b5d29060179846e6b380a3e3c32af3e422af19abbf26", + "blockNumber": "0x95c023", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x1e2ae8", + "gasUsed": "0x1e2ae8", + "contractAddress": "0x642eC60A61d26b472f1E4E0e79A83818eF90768d", + "logs": [ + { + "address": "0x642eC60A61d26b472f1E4E0e79A83818eF90768d", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x84ad226745b7be905ea3b5d29060179846e6b380a3e3c32af3e422af19abbf26", + "blockNumber": "0x95c023", + "transactionHash": "0x3b667395a3f3d7308d9e0e3baf4fec6804133e0ff70016494b68f9ea1c76ff68", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000100000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000020000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696517534, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517628.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517628.json new file mode 100644 index 0000000..fdbed97 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517628.json @@ -0,0 +1,38 @@ +{ + "transactions": [ + { + "hash": "0x680b2673ea858c56073d29f8dc85a1e61ff112f5c92f8864ed7b9c8b48463c2c", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x04E2a52Cf2352e64B83D30ba33ED9f1605cA58F5", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x47", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x680b2673ea858c56073d29f8dc85a1e61ff112f5c92f8864ed7b9c8b48463c2c" + ], + "returns": {}, + "timestamp": 1696517628, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517662.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517662.json new file mode 100644 index 0000000..8c8cd38 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517662.json @@ -0,0 +1,109 @@ +{ + "transactions": [ + { + "hash": "0x33b7ddca1489db0f9f282ae3b8cc4f53681874237d084b3653b0efd065b8c9c0", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x48", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xacb402c5d68f7847ec631fe198bd1af95d74bbd28f20338b04656ce01dfbc50e", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x4c93d5b8ae971df35abc7b666cc0e550a6f0d547", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x49", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xefd0fac30a0868feea6aae67167a7cda08dd5c13521fe21bceb1b6212b735862", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000004c93d5b8ae971df35abc7b666cc0e550a6f0d5470000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x4a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x594bd891a334436c2f3d0c13842ed1e7fbb617b692ca026206e98643ac8d7431", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x4c93d5b8ae971df35abc7b666cc0e550a6f0d547", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x4b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x33b7ddca1489db0f9f282ae3b8cc4f53681874237d084b3653b0efd065b8c9c0", + "0xacb402c5d68f7847ec631fe198bd1af95d74bbd28f20338b04656ce01dfbc50e", + "0xefd0fac30a0868feea6aae67167a7cda08dd5c13521fe21bceb1b6212b735862", + "0x594bd891a334436c2f3d0c13842ed1e7fbb617b692ca026206e98643ac8d7431" + ], + "returns": {}, + "timestamp": 1696517662, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517669.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517669.json new file mode 100644 index 0000000..9f33071 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517669.json @@ -0,0 +1,276 @@ +{ + "transactions": [ + { + "hash": "0x33b7ddca1489db0f9f282ae3b8cc4f53681874237d084b3653b0efd065b8c9c0", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x48", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xacb402c5d68f7847ec631fe198bd1af95d74bbd28f20338b04656ce01dfbc50e", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x4c93d5b8ae971df35abc7b666cc0e550a6f0d547", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x49", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xefd0fac30a0868feea6aae67167a7cda08dd5c13521fe21bceb1b6212b735862", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000004c93d5b8ae971df35abc7b666cc0e550a6f0d5470000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x4a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x594bd891a334436c2f3d0c13842ed1e7fbb617b692ca026206e98643ac8d7431", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x4c93d5b8ae971df35abc7b666cc0e550a6f0d547", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x4b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x33b7ddca1489db0f9f282ae3b8cc4f53681874237d084b3653b0efd065b8c9c0", + "transactionIndex": "0x1", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21408d", + "gasUsed": "0x20ee85", + "contractAddress": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "logs": [ + { + "address": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "transactionHash": "0x33b7ddca1489db0f9f282ae3b8cc4f53681874237d084b3653b0efd065b8c9c0", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000101000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0xacb402c5d68f7847ec631fe198bd1af95d74bbd28f20338b04656ce01dfbc50e", + "transactionIndex": "0x2", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "cumulativeGasUsed": "0x21b685", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "transactionHash": "0xacb402c5d68f7847ec631fe198bd1af95d74bbd28f20338b04656ce01dfbc50e", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0xefd0fac30a0868feea6aae67167a7cda08dd5c13521fe21bceb1b6212b735862", + "transactionIndex": "0x3", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x226abc", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000004c93d5b8ae971df35abc7b666cc0e550a6f0d547" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "transactionHash": "0xefd0fac30a0868feea6aae67167a7cda08dd5c13521fe21bceb1b6212b735862", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000004000000020000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0x594bd891a334436c2f3d0c13842ed1e7fbb617b692ca026206e98643ac8d7431", + "transactionIndex": "0x5", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "cumulativeGasUsed": "0x3e5119", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000004c93d5b8ae971df35abc7b666cc0e550a6f0d547" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "transactionHash": "0x594bd891a334436c2f3d0c13842ed1e7fbb617b692ca026206e98643ac8d7431", + "transactionIndex": "0x5", + "logIndex": "0x6", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000004c93d5b8ae971df35abc7b666cc0e550a6f0d547" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "transactionHash": "0x594bd891a334436c2f3d0c13842ed1e7fbb617b692ca026206e98643ac8d7431", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + }, + { + "address": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "transactionHash": "0x594bd891a334436c2f3d0c13842ed1e7fbb617b692ca026206e98643ac8d7431", + "transactionIndex": "0x5", + "logIndex": "0x8", + "removed": false + }, + { + "address": "0x4c93d5b8aE971DF35abC7b666CC0E550A6F0d547", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xc0abe7931007c94e8597a61d11251af3e9c4bd867f8435cb1db7332eb2b87231", + "blockNumber": "0x95c02d", + "transactionHash": "0x594bd891a334436c2f3d0c13842ed1e7fbb617b692ca026206e98643ac8d7431", + "transactionIndex": "0x5", + "logIndex": "0x9", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000004000000020000000000000000000000000000000000000101000000000000000000000000000000000000000000000000000000200000000000400000000000000008000000080000000000000000000000000001000000000000020000080000000000000800008000000004000000000010000000000000000000000000000000000000000000000000000000000000000000000000220000000000000000000002000000000000000001000000000000000000000000000002000000000000000000000000000200000008000000000000000020000010000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696517669, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517944.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517944.json new file mode 100644 index 0000000..617e906 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517944.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0xf253ad2723325a77585fbe6789ba3c652e42d93c689fcd60436f7eeacef14e80", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x4c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaa94f35b72eeea4afd36069aa046a219e271b85145bf2155b97527027af7ea43", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x4d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xac56a11ad62251fa374e454aea61e85e5ebcff3e32a9fb8edfeec423b2065e92", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a60000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x4e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x4f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa67884a59ea8177c5f6950128488247e6430575b727c5e6417aa925499921da0", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x50", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xf253ad2723325a77585fbe6789ba3c652e42d93c689fcd60436f7eeacef14e80", + "0xaa94f35b72eeea4afd36069aa046a219e271b85145bf2155b97527027af7ea43", + "0xac56a11ad62251fa374e454aea61e85e5ebcff3e32a9fb8edfeec423b2065e92", + "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "0xa67884a59ea8177c5f6950128488247e6430575b727c5e6417aa925499921da0" + ], + "returns": {}, + "timestamp": 1696517944, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517958.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517958.json new file mode 100644 index 0000000..54a76ce --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517958.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0xf253ad2723325a77585fbe6789ba3c652e42d93c689fcd60436f7eeacef14e80", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x4c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaa94f35b72eeea4afd36069aa046a219e271b85145bf2155b97527027af7ea43", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x4d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xac56a11ad62251fa374e454aea61e85e5ebcff3e32a9fb8edfeec423b2065e92", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a60000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x4e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x4f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa67884a59ea8177c5f6950128488247e6430575b727c5e6417aa925499921da0", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x50", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xf253ad2723325a77585fbe6789ba3c652e42d93c689fcd60436f7eeacef14e80", + "transactionIndex": "0x2", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x231b05", + "gasUsed": "0x20ee85", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "logs": [ + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0xf253ad2723325a77585fbe6789ba3c652e42d93c689fcd60436f7eeacef14e80", + "transactionIndex": "0x2", + "logIndex": "0x5", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000200020000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0xaa94f35b72eeea4afd36069aa046a219e271b85145bf2155b97527027af7ea43", + "transactionIndex": "0x3", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "cumulativeGasUsed": "0x2390fd", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0xaa94f35b72eeea4afd36069aa046a219e271b85145bf2155b97527027af7ea43", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000200020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0xac56a11ad62251fa374e454aea61e85e5ebcff3e32a9fb8edfeec423b2065e92", + "transactionIndex": "0x4", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x244534", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a6" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0xac56a11ad62251fa374e454aea61e85e5ebcff3e32a9fb8edfeec423b2065e92", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000400000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000002000008000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "cumulativeGasUsed": "0x260149", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a6" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "logIndex": "0x8", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a6" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "logIndex": "0x9", + "removed": false + }, + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "logIndex": "0xa", + "removed": false + }, + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "logIndex": "0xb", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x0000000000000000000000000000000000000000020002000000000000000000010000000000000000000000000000000000000000000040000000000020000000000040000000000000000800000000000000000000000000000000000100000000000002000008000000000000080000800000000400000000001000000004000000000000000000000000000000000000000000000000000000000000000002000000000000000200000a000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000000000000020000010000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0xa67884a59ea8177c5f6950128488247e6430575b727c5e6417aa925499921da0", + "transactionIndex": "0x6", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "cumulativeGasUsed": "0x26bc4a", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0xa67884a59ea8177c5f6950128488247e6430575b727c5e6417aa925499921da0", + "transactionIndex": "0x6", + "logIndex": "0xc", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000200020000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000040000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696517958, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517987.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517987.json new file mode 100644 index 0000000..3ff47b5 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696517987.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0xf253ad2723325a77585fbe6789ba3c652e42d93c689fcd60436f7eeacef14e80", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x4c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaa94f35b72eeea4afd36069aa046a219e271b85145bf2155b97527027af7ea43", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x4d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xac56a11ad62251fa374e454aea61e85e5ebcff3e32a9fb8edfeec423b2065e92", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a60000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x4e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x4f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa67884a59ea8177c5f6950128488247e6430575b727c5e6417aa925499921da0", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xbc62f79a9b5fcde9e3b7a1d7564124405148a3a6", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x50", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xf253ad2723325a77585fbe6789ba3c652e42d93c689fcd60436f7eeacef14e80", + "transactionIndex": "0x2", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x231b05", + "gasUsed": "0x20ee85", + "contractAddress": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "logs": [ + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0xf253ad2723325a77585fbe6789ba3c652e42d93c689fcd60436f7eeacef14e80", + "transactionIndex": "0x2", + "logIndex": "0x5", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000200020000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000440000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0xaa94f35b72eeea4afd36069aa046a219e271b85145bf2155b97527027af7ea43", + "transactionIndex": "0x3", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "cumulativeGasUsed": "0x2390fd", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0xaa94f35b72eeea4afd36069aa046a219e271b85145bf2155b97527027af7ea43", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000200020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0xac56a11ad62251fa374e454aea61e85e5ebcff3e32a9fb8edfeec423b2065e92", + "transactionIndex": "0x4", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x244534", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a6" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0xac56a11ad62251fa374e454aea61e85e5ebcff3e32a9fb8edfeec423b2065e92", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000400000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000002000008000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "cumulativeGasUsed": "0x260149", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a6" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "logIndex": "0x8", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000bc62f79a9b5fcde9e3b7a1d7564124405148a3a6" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "logIndex": "0x9", + "removed": false + }, + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "logIndex": "0xa", + "removed": false + }, + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0x06c28acb0f2ecb539419a769c68fddcd69378d52e1a0fd8810a503cb5c17309c", + "transactionIndex": "0x5", + "logIndex": "0xb", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x0000000000000000000000000000000000000000020002000000000000000000010000000000000000000000000000000000000000000040000000000020000000000040000000000000000800000000000000000000000000000000000100000000000002000008000000000000080000800000000400000000001000000004000000000000000000000000000000000000000000000000000000000000000002000000000000000200000a000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000000000000020000010000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0xa67884a59ea8177c5f6950128488247e6430575b727c5e6417aa925499921da0", + "transactionIndex": "0x6", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "cumulativeGasUsed": "0x26bc4a", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xbC62F79a9b5fcDe9E3B7a1d7564124405148A3a6", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x16bc028ce9df18dc207e46648bf34359406c921c2cc81463718bfa1c1289673d", + "blockNumber": "0x95c042", + "transactionHash": "0xa67884a59ea8177c5f6950128488247e6430575b727c5e6417aa925499921da0", + "transactionIndex": "0x6", + "logIndex": "0xc", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000200020000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000040000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696517987, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518085.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518085.json new file mode 100644 index 0000000..932c85c --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518085.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0xb199bec73a4e799eb2ce644902995d2adbfdf32316ac639c189a693026dfe7ab", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x51", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6494b31c5c465fd20c1c6bd67f373ff9ab91dbdd056d4592b54e4980bb0a7de1", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x52", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x51e20dbee1a07e6fa95d7c263de5ae2e0b6d9b419926fca7738cbb5199bc0faf", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x149785F5A2813524EEEAd7f4B349654659B05124", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000149785f5a2813524eeead7f4b349654659b051240000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x53", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x54", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6bdf33b079c6a657836816d223421b85ab31d0b7b9ddbe594d241f1d828c189a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x55", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xb199bec73a4e799eb2ce644902995d2adbfdf32316ac639c189a693026dfe7ab", + "0x6494b31c5c465fd20c1c6bd67f373ff9ab91dbdd056d4592b54e4980bb0a7de1", + "0x51e20dbee1a07e6fa95d7c263de5ae2e0b6d9b419926fca7738cbb5199bc0faf", + "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "0x6bdf33b079c6a657836816d223421b85ab31d0b7b9ddbe594d241f1d828c189a" + ], + "returns": {}, + "timestamp": 1696518085, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518099.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518099.json new file mode 100644 index 0000000..a0a461f --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518099.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0xb199bec73a4e799eb2ce644902995d2adbfdf32316ac639c189a693026dfe7ab", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x51", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6494b31c5c465fd20c1c6bd67f373ff9ab91dbdd056d4592b54e4980bb0a7de1", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x52", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x51e20dbee1a07e6fa95d7c263de5ae2e0b6d9b419926fca7738cbb5199bc0faf", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x149785F5A2813524EEEAd7f4B349654659B05124", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000149785f5a2813524eeead7f4b349654659b051240000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x53", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x54", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6bdf33b079c6a657836816d223421b85ab31d0b7b9ddbe594d241f1d828c189a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x55", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xb199bec73a4e799eb2ce644902995d2adbfdf32316ac639c189a693026dfe7ab", + "transactionIndex": "0x1", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21408d", + "gasUsed": "0x20ee85", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "logs": [ + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xb199bec73a4e799eb2ce644902995d2adbfdf32316ac639c189a693026dfe7ab", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000020000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000001000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0x6494b31c5c465fd20c1c6bd67f373ff9ab91dbdd056d4592b54e4980bb0a7de1", + "transactionIndex": "0x2", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "cumulativeGasUsed": "0x21b685", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0x6494b31c5c465fd20c1c6bd67f373ff9ab91dbdd056d4592b54e4980bb0a7de1", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0x51e20dbee1a07e6fa95d7c263de5ae2e0b6d9b419926fca7738cbb5199bc0faf", + "transactionIndex": "0x3", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x226abc", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000149785f5a2813524eeead7f4b349654659b05124" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0x51e20dbee1a07e6fa95d7c263de5ae2e0b6d9b419926fca7738cbb5199bc0faf", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000a00000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "cumulativeGasUsed": "0x2426d1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000149785f5a2813524eeead7f4b349654659b05124" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000149785f5a2813524eeead7f4b349654659b05124" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000020000000000000000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000000200000000000400000000000000008000000000000000000000000000000000001000000000000020000080000000000000800008000000004000000000010000000000000000000000000000000000000000000000000000000000000000000000080020000000000000000000002000000000000000000100000000000000000000000000002000000000000000000000000000a00000008000000001000000020000010000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0x6bdf33b079c6a657836816d223421b85ab31d0b7b9ddbe594d241f1d828c189a", + "transactionIndex": "0x5", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "cumulativeGasUsed": "0x24e1d2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0x6bdf33b079c6a657836816d223421b85ab31d0b7b9ddbe594d241f1d828c189a", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000020000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000080000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000001000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696518099, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518128.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518128.json new file mode 100644 index 0000000..c05c9a8 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518128.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0xb199bec73a4e799eb2ce644902995d2adbfdf32316ac639c189a693026dfe7ab", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x51", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6494b31c5c465fd20c1c6bd67f373ff9ab91dbdd056d4592b54e4980bb0a7de1", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x52", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x51e20dbee1a07e6fa95d7c263de5ae2e0b6d9b419926fca7738cbb5199bc0faf", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x149785F5A2813524EEEAd7f4B349654659B05124", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000149785f5a2813524eeead7f4b349654659b051240000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x53", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x54", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6bdf33b079c6a657836816d223421b85ab31d0b7b9ddbe594d241f1d828c189a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x149785f5a2813524eeead7f4b349654659b05124", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x55", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xb199bec73a4e799eb2ce644902995d2adbfdf32316ac639c189a693026dfe7ab", + "transactionIndex": "0x1", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21408d", + "gasUsed": "0x20ee85", + "contractAddress": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "logs": [ + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xb199bec73a4e799eb2ce644902995d2adbfdf32316ac639c189a693026dfe7ab", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000020000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000001000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0x6494b31c5c465fd20c1c6bd67f373ff9ab91dbdd056d4592b54e4980bb0a7de1", + "transactionIndex": "0x2", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "cumulativeGasUsed": "0x21b685", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0x6494b31c5c465fd20c1c6bd67f373ff9ab91dbdd056d4592b54e4980bb0a7de1", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0x51e20dbee1a07e6fa95d7c263de5ae2e0b6d9b419926fca7738cbb5199bc0faf", + "transactionIndex": "0x3", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x226abc", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000149785f5a2813524eeead7f4b349654659b05124" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0x51e20dbee1a07e6fa95d7c263de5ae2e0b6d9b419926fca7738cbb5199bc0faf", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000a00000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "cumulativeGasUsed": "0x2426d1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000149785f5a2813524eeead7f4b349654659b05124" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000149785f5a2813524eeead7f4b349654659b05124" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0xd5a7df5d73e380ebe0ebc8e53ad6ad0ecc7bb85b8dd5a13039accf73695566ed", + "transactionIndex": "0x4", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000020000000000000000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000000200000000000400000000000000008000000000000000000000000000000000001000000000000020000080000000000000800008000000004000000000010000000000000000000000000000000000000000000000000000000000000000000000080020000000000000000000002000000000000000000100000000000000000000000000002000000000000000000000000000a00000008000000001000000020000010000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + }, + { + "transactionHash": "0x6bdf33b079c6a657836816d223421b85ab31d0b7b9ddbe594d241f1d828c189a", + "transactionIndex": "0x5", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "cumulativeGasUsed": "0x24e1d2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x149785F5A2813524EEEAd7f4B349654659B05124", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xba55afc604cc29e86672776f5f3464f65ea830808b42245fbcfb8b63ea0dc74b", + "blockNumber": "0x95c04e", + "transactionHash": "0x6bdf33b079c6a657836816d223421b85ab31d0b7b9ddbe594d241f1d828c189a", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000020000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000080000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000001000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0b" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696518128, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518454.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518454.json new file mode 100644 index 0000000..33e607e --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518454.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x39d9e4d309d3fb465826b17166971f0bdf7e5e53aee8122ed67197fc98c17c5a", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x56", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x86d56aa729c2fabaac4f760f623abc91ec26f67d9fc5e06ee07b8f5c1bb91136", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x57", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6262f800478233ec3d35d28c85761c682df42d29a2f5368117e24fcd79cea95d", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d70000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x58", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x59", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7a6593c819a908fa324af53c014b9f2836b42e3973263d3c34132195d6640c07", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x5a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x39d9e4d309d3fb465826b17166971f0bdf7e5e53aee8122ed67197fc98c17c5a", + "0x86d56aa729c2fabaac4f760f623abc91ec26f67d9fc5e06ee07b8f5c1bb91136", + "0x6262f800478233ec3d35d28c85761c682df42d29a2f5368117e24fcd79cea95d", + "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "0x7a6593c819a908fa324af53c014b9f2836b42e3973263d3c34132195d6640c07" + ], + "returns": {}, + "timestamp": 1696518454, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518486.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518486.json new file mode 100644 index 0000000..269e878 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518486.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x39d9e4d309d3fb465826b17166971f0bdf7e5e53aee8122ed67197fc98c17c5a", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x56", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x86d56aa729c2fabaac4f760f623abc91ec26f67d9fc5e06ee07b8f5c1bb91136", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x57", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6262f800478233ec3d35d28c85761c682df42d29a2f5368117e24fcd79cea95d", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d70000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x58", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x59", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7a6593c819a908fa324af53c014b9f2836b42e3973263d3c34132195d6640c07", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x5a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x39d9e4d309d3fb465826b17166971f0bdf7e5e53aee8122ed67197fc98c17c5a", + "transactionIndex": "0x3", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21e49d", + "gasUsed": "0x20ee85", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "logs": [ + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0x39d9e4d309d3fb465826b17166971f0bdf7e5e53aee8122ed67197fc98c17c5a", + "transactionIndex": "0x3", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x86d56aa729c2fabaac4f760f623abc91ec26f67d9fc5e06ee07b8f5c1bb91136", + "transactionIndex": "0x4", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "cumulativeGasUsed": "0x225a95", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0x86d56aa729c2fabaac4f760f623abc91ec26f67d9fc5e06ee07b8f5c1bb91136", + "transactionIndex": "0x4", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x6262f800478233ec3d35d28c85761c682df42d29a2f5368117e24fcd79cea95d", + "transactionIndex": "0x5", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x230ecc", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d7" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0x6262f800478233ec3d35d28c85761c682df42d29a2f5368117e24fcd79cea95d", + "transactionIndex": "0x5", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000004000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "cumulativeGasUsed": "0x24cae1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d7" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d7" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000001000000000000000000000220000000000400000000000000008000000000000000000000000000000000001000000000000020000080000000000000800008000000004000000000010000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000040002000000000001000000000000000000000000000000000002000000000000000000000000000200000008004000000000000020000010000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x7a6593c819a908fa324af53c014b9f2836b42e3973263d3c34132195d6640c07", + "transactionIndex": "0x7", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "cumulativeGasUsed": "0x2585e2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0x7a6593c819a908fa324af53c014b9f2836b42e3973263d3c34132195d6640c07", + "transactionIndex": "0x7", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000001000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000040000000000000001000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696518486, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518515.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518515.json new file mode 100644 index 0000000..81693ea --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518515.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x39d9e4d309d3fb465826b17166971f0bdf7e5e53aee8122ed67197fc98c17c5a", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x56", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x86d56aa729c2fabaac4f760f623abc91ec26f67d9fc5e06ee07b8f5c1bb91136", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x57", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x6262f800478233ec3d35d28c85761c682df42d29a2f5368117e24fcd79cea95d", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d70000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x58", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x59", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7a6593c819a908fa324af53c014b9f2836b42e3973263d3c34132195d6640c07", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xba1d47bf11a10b5674c1429d865a01d1158743d7", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x5a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x39d9e4d309d3fb465826b17166971f0bdf7e5e53aee8122ed67197fc98c17c5a", + "transactionIndex": "0x3", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21e49d", + "gasUsed": "0x20ee85", + "contractAddress": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "logs": [ + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0x39d9e4d309d3fb465826b17166971f0bdf7e5e53aee8122ed67197fc98c17c5a", + "transactionIndex": "0x3", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x86d56aa729c2fabaac4f760f623abc91ec26f67d9fc5e06ee07b8f5c1bb91136", + "transactionIndex": "0x4", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "cumulativeGasUsed": "0x225a95", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0x86d56aa729c2fabaac4f760f623abc91ec26f67d9fc5e06ee07b8f5c1bb91136", + "transactionIndex": "0x4", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000001000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x6262f800478233ec3d35d28c85761c682df42d29a2f5368117e24fcd79cea95d", + "transactionIndex": "0x5", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x230ecc", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d7" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0x6262f800478233ec3d35d28c85761c682df42d29a2f5368117e24fcd79cea95d", + "transactionIndex": "0x5", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000004000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "cumulativeGasUsed": "0x24cae1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d7" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ba1d47bf11a10b5674c1429d865a01d1158743d7" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0xdd81fc313f05a70a9ee49bafafdbe076b702e701dca79011487012cec6d6188b", + "transactionIndex": "0x6", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000001000000000000000000000220000000000400000000000000008000000000000000000000000000000000001000000000000020000080000000000000800008000000004000000000010000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000040002000000000001000000000000000000000000000000000002000000000000000000000000000200000008004000000000000020000010000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x7a6593c819a908fa324af53c014b9f2836b42e3973263d3c34132195d6640c07", + "transactionIndex": "0x7", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "cumulativeGasUsed": "0x2585e2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xba1d47bf11A10B5674c1429d865a01D1158743D7", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x7cba894bb6dfa67fad03417d50604f37e758c5f58f4a6188e1ba57d3ca270cb2", + "blockNumber": "0x95c067", + "transactionHash": "0x7a6593c819a908fa324af53c014b9f2836b42e3973263d3c34132195d6640c07", + "transactionIndex": "0x7", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000001000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000040000000000000001000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696518515, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518532.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518532.json new file mode 100644 index 0000000..ad52781 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518532.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x05612de5fcf7afcb3a916bc9fbb7abe5a24bc2ae6c6af72435b79976270e6aed", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x5b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaea77f50911c87bee82bda7de711949d65d4b9e82f761b12d8b08fce4c79edb1", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x5c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7f3a74846b38d42a4cb0cd074d78874047c5c1f11d9a79d77087ddb5dd0fdc60", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac30000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x5d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x5e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9f669a47177efc158193ef32184016b588dd67a7668396e46f23a6ec6f54788b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x5f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x05612de5fcf7afcb3a916bc9fbb7abe5a24bc2ae6c6af72435b79976270e6aed", + "0xaea77f50911c87bee82bda7de711949d65d4b9e82f761b12d8b08fce4c79edb1", + "0x7f3a74846b38d42a4cb0cd074d78874047c5c1f11d9a79d77087ddb5dd0fdc60", + "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "0x9f669a47177efc158193ef32184016b588dd67a7668396e46f23a6ec6f54788b" + ], + "returns": {}, + "timestamp": 1696518532, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518545.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518545.json new file mode 100644 index 0000000..b458503 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518545.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x05612de5fcf7afcb3a916bc9fbb7abe5a24bc2ae6c6af72435b79976270e6aed", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x5b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaea77f50911c87bee82bda7de711949d65d4b9e82f761b12d8b08fce4c79edb1", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x5c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7f3a74846b38d42a4cb0cd074d78874047c5c1f11d9a79d77087ddb5dd0fdc60", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac30000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x5d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x5e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9f669a47177efc158193ef32184016b588dd67a7668396e46f23a6ec6f54788b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x5f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x05612de5fcf7afcb3a916bc9fbb7abe5a24bc2ae6c6af72435b79976270e6aed", + "transactionIndex": "0x4", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x22740c", + "gasUsed": "0x20ee85", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "logs": [ + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x05612de5fcf7afcb3a916bc9fbb7abe5a24bc2ae6c6af72435b79976270e6aed", + "transactionIndex": "0x4", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000002000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xaea77f50911c87bee82bda7de711949d65d4b9e82f761b12d8b08fce4c79edb1", + "transactionIndex": "0x5", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "cumulativeGasUsed": "0x22ea04", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0xaea77f50911c87bee82bda7de711949d65d4b9e82f761b12d8b08fce4c79edb1", + "transactionIndex": "0x5", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x7f3a74846b38d42a4cb0cd074d78874047c5c1f11d9a79d77087ddb5dd0fdc60", + "transactionIndex": "0x6", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x239e3b", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac3" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x7f3a74846b38d42a4cb0cd074d78874047c5c1f11d9a79d77087ddb5dd0fdc60", + "transactionIndex": "0x6", + "logIndex": "0x3", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000100000000000080000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000110000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "cumulativeGasUsed": "0x255a50", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac3" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac3" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "logIndex": "0x6", + "removed": false + }, + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000002000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000400000000000000008000000000000000000000000000000000001000000100000020000080000000000000800008000000004000000000010000010000000000000000000000000000000000000000000000000000000000000000000020000000000000000000002000000000000004000000000000040000000000000000002000000000000000000000000000200000008000000000000000020000110000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x9f669a47177efc158193ef32184016b588dd67a7668396e46f23a6ec6f54788b", + "transactionIndex": "0x8", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "cumulativeGasUsed": "0x261551", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x9f669a47177efc158193ef32184016b588dd67a7668396e46f23a6ec6f54788b", + "transactionIndex": "0x8", + "logIndex": "0x8", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000002000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000004000000000000040000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696518545, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518546.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518546.json new file mode 100644 index 0000000..89ac985 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696518546.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x05612de5fcf7afcb3a916bc9fbb7abe5a24bc2ae6c6af72435b79976270e6aed", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x5b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaea77f50911c87bee82bda7de711949d65d4b9e82f761b12d8b08fce4c79edb1", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x5c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7f3a74846b38d42a4cb0cd074d78874047c5c1f11d9a79d77087ddb5dd0fdc60", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac30000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x5d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5b73C5498c1E3b4dbA84de0F1833c4a029d90519" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519", + "nonce": "0x5e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9f669a47177efc158193ef32184016b588dd67a7668396e46f23a6ec6f54788b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x8d925f32489a775a11b18dfb39fb97adb3f88ac3", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x5f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x05612de5fcf7afcb3a916bc9fbb7abe5a24bc2ae6c6af72435b79976270e6aed", + "transactionIndex": "0x4", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x22740c", + "gasUsed": "0x20ee85", + "contractAddress": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "logs": [ + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x05612de5fcf7afcb3a916bc9fbb7abe5a24bc2ae6c6af72435b79976270e6aed", + "transactionIndex": "0x4", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000002000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xaea77f50911c87bee82bda7de711949d65d4b9e82f761b12d8b08fce4c79edb1", + "transactionIndex": "0x5", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "cumulativeGasUsed": "0x22ea04", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0xaea77f50911c87bee82bda7de711949d65d4b9e82f761b12d8b08fce4c79edb1", + "transactionIndex": "0x5", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000040000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x7f3a74846b38d42a4cb0cd074d78874047c5c1f11d9a79d77087ddb5dd0fdc60", + "transactionIndex": "0x6", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x239e3b", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac3" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x7f3a74846b38d42a4cb0cd074d78874047c5c1f11d9a79d77087ddb5dd0fdc60", + "transactionIndex": "0x6", + "logIndex": "0x3", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000100000000000080000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000110000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "cumulativeGasUsed": "0x255a50", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac3" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000008d925f32489a775a11b18dfb39fb97adb3f88ac3" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "logIndex": "0x6", + "removed": false + }, + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b73c5498c1e3b4dba84de0f1833c4a029d90519" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x630853ded7ceab92d6c0809b458cf981b31ed3579f667159d924af98c8d24a50", + "transactionIndex": "0x7", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000002000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000400000000000000008000000000000000000000000000000000001000000100000020000080000000000000800008000000004000000000010000010000000000000000000000000000000000000000000000000000000000000000000020000000000000000000002000000000000004000000000000040000000000000000002000000000000000000000000000200000008000000000000000020000110000000000000000000000000000800000100000000000000000000000200", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x9f669a47177efc158193ef32184016b588dd67a7668396e46f23a6ec6f54788b", + "transactionIndex": "0x8", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "cumulativeGasUsed": "0x261551", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x8d925f32489A775a11B18dfB39Fb97aDB3f88Ac3", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x4ba96bef0f1e565308055d34ba9ef522368f6dcfabb22d0c064954e147788221", + "blockNumber": "0x95c06b", + "transactionHash": "0x9f669a47177efc158193ef32184016b588dd67a7668396e46f23a6ec6f54788b", + "transactionIndex": "0x8", + "logIndex": "0x8", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000002000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000004000000000000040000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696518546, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519178.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519178.json new file mode 100644 index 0000000..0707609 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519178.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x683b88599d5f6ed8a97946fae78ab66705af997d1c7b9d00250746a13db1dfa2", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x60", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa4ef1506f5cc915c24ec567ea6646f3de083ba5204406d666e475a7e94743ace", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x0abce8f8265f6ce91fa574afe2990caaeb122ff0", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x61", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x5dbaa208996d094a8f442dd4f49522c9f4b43613821470b64ec9f348e2e49924", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000000abce8f8265f6ce91fa574afe2990caaeb122ff00000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x62", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf611c81fa3091dd5885800f0253635e94b8518961355a0a9ab1e85b9ce62a495", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x0abce8f8265f6ce91fa574afe2990caaeb122ff0", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x63", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x0f8a0da2b6c9711f5b73c295dc52c3ca005a39e35c97031784edd186adec612e", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x0abce8f8265f6ce91fa574afe2990caaeb122ff0", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x64", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x683b88599d5f6ed8a97946fae78ab66705af997d1c7b9d00250746a13db1dfa2", + "0xa4ef1506f5cc915c24ec567ea6646f3de083ba5204406d666e475a7e94743ace", + "0x5dbaa208996d094a8f442dd4f49522c9f4b43613821470b64ec9f348e2e49924", + "0xf611c81fa3091dd5885800f0253635e94b8518961355a0a9ab1e85b9ce62a495", + "0x0f8a0da2b6c9711f5b73c295dc52c3ca005a39e35c97031784edd186adec612e" + ], + "returns": {}, + "timestamp": 1696519178, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519191.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519191.json new file mode 100644 index 0000000..51c15e9 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519191.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x683b88599d5f6ed8a97946fae78ab66705af997d1c7b9d00250746a13db1dfa2", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x60", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa4ef1506f5cc915c24ec567ea6646f3de083ba5204406d666e475a7e94743ace", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x0abce8f8265f6ce91fa574afe2990caaeb122ff0", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x61", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x5dbaa208996d094a8f442dd4f49522c9f4b43613821470b64ec9f348e2e49924", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000000abce8f8265f6ce91fa574afe2990caaeb122ff00000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x62", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf611c81fa3091dd5885800f0253635e94b8518961355a0a9ab1e85b9ce62a495", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x0abce8f8265f6ce91fa574afe2990caaeb122ff0", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x63", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x0f8a0da2b6c9711f5b73c295dc52c3ca005a39e35c97031784edd186adec612e", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x0abce8f8265f6ce91fa574afe2990caaeb122ff0", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x64", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x683b88599d5f6ed8a97946fae78ab66705af997d1c7b9d00250746a13db1dfa2", + "transactionIndex": "0x1", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21408d", + "gasUsed": "0x20ee85", + "contractAddress": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "logs": [ + { + "address": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "transactionHash": "0x683b88599d5f6ed8a97946fae78ab66705af997d1c7b9d00250746a13db1dfa2", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000010000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000001000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xa4ef1506f5cc915c24ec567ea6646f3de083ba5204406d666e475a7e94743ace", + "transactionIndex": "0x2", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "cumulativeGasUsed": "0x21b685", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "transactionHash": "0xa4ef1506f5cc915c24ec567ea6646f3de083ba5204406d666e475a7e94743ace", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x5dbaa208996d094a8f442dd4f49522c9f4b43613821470b64ec9f348e2e49924", + "transactionIndex": "0x3", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x226abc", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000000abce8f8265f6ce91fa574afe2990caaeb122ff0" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "transactionHash": "0x5dbaa208996d094a8f442dd4f49522c9f4b43613821470b64ec9f348e2e49924", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000800000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xf611c81fa3091dd5885800f0253635e94b8518961355a0a9ab1e85b9ce62a495", + "transactionIndex": "0x4", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "cumulativeGasUsed": "0x2426d1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000000abce8f8265f6ce91fa574afe2990caaeb122ff0" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "transactionHash": "0xf611c81fa3091dd5885800f0253635e94b8518961355a0a9ab1e85b9ce62a495", + "transactionIndex": "0x4", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000000abce8f8265f6ce91fa574afe2990caaeb122ff0" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "transactionHash": "0xf611c81fa3091dd5885800f0253635e94b8518961355a0a9ab1e85b9ce62a495", + "transactionIndex": "0x4", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "transactionHash": "0xf611c81fa3091dd5885800f0253635e94b8518961355a0a9ab1e85b9ce62a495", + "transactionIndex": "0x4", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "transactionHash": "0xf611c81fa3091dd5885800f0253635e94b8518961355a0a9ab1e85b9ce62a495", + "transactionIndex": "0x4", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000010000000000000000000000000000000000000000000000002000100000000000000000000800000000000000000000000000000800000200000000000400000000000000008000000000000000000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004004000000000000000000200000000000000000020000000000000000000000000000000000000000000000000000000000000000000002000400000000000000000000000200000008000000000001000020000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x0f8a0da2b6c9711f5b73c295dc52c3ca005a39e35c97031784edd186adec612e", + "transactionIndex": "0x5", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "cumulativeGasUsed": "0x24e1d2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x0AbCe8F8265f6ce91fa574Afe2990CAAEB122fF0", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x0f1bd6a1028ea1ad095d7619a9b3fb36173c33038c2b90610c42b3675bceeb4c", + "blockNumber": "0x95c099", + "transactionHash": "0x0f8a0da2b6c9711f5b73c295dc52c3ca005a39e35c97031784edd186adec612e", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000010000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000200000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000001000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696519191, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519236.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519236.json new file mode 100644 index 0000000..c766ba9 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519236.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x3cdc6db9c8c3732ceb80438e7f54ee0ea9cf97c842d9fbb2949c62e41426a0e4", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x65", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x33d6a97f64a26600b98cd1f6d3156ec65e5571d704366f3ae1be6674b032389b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x66", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xb1dcd2321b1ea1285ff585fc22ea569dbf22b48fcfd6d8c080bbe06727c1728e", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d8040000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x67", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x68", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa332c27ea332c5f126f253c9913f9a9377671b32e71767d43e1ec50ddad2014a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x69", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x3cdc6db9c8c3732ceb80438e7f54ee0ea9cf97c842d9fbb2949c62e41426a0e4", + "0x33d6a97f64a26600b98cd1f6d3156ec65e5571d704366f3ae1be6674b032389b", + "0xb1dcd2321b1ea1285ff585fc22ea569dbf22b48fcfd6d8c080bbe06727c1728e", + "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "0xa332c27ea332c5f126f253c9913f9a9377671b32e71767d43e1ec50ddad2014a" + ], + "returns": {}, + "timestamp": 1696519236, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519261.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519261.json new file mode 100644 index 0000000..583ffee --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519261.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x3cdc6db9c8c3732ceb80438e7f54ee0ea9cf97c842d9fbb2949c62e41426a0e4", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x65", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x33d6a97f64a26600b98cd1f6d3156ec65e5571d704366f3ae1be6674b032389b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x66", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xb1dcd2321b1ea1285ff585fc22ea569dbf22b48fcfd6d8c080bbe06727c1728e", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d8040000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x67", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x68", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa332c27ea332c5f126f253c9913f9a9377671b32e71767d43e1ec50ddad2014a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x69", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x3cdc6db9c8c3732ceb80438e7f54ee0ea9cf97c842d9fbb2949c62e41426a0e4", + "transactionIndex": "0x1", + "blockHash": "0xf55ab88d59a1e298da584cbd27f73d2eacad6dce70c16d7607f3c57a7a56b5dc", + "blockNumber": "0x95c09c", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21408d", + "gasUsed": "0x20ee85", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "logs": [ + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xf55ab88d59a1e298da584cbd27f73d2eacad6dce70c16d7607f3c57a7a56b5dc", + "blockNumber": "0x95c09c", + "transactionHash": "0x3cdc6db9c8c3732ceb80438e7f54ee0ea9cf97c842d9fbb2949c62e41426a0e4", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000200000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000020000000010000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x33d6a97f64a26600b98cd1f6d3156ec65e5571d704366f3ae1be6674b032389b", + "transactionIndex": "0x2", + "blockHash": "0xf55ab88d59a1e298da584cbd27f73d2eacad6dce70c16d7607f3c57a7a56b5dc", + "blockNumber": "0x95c09c", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "cumulativeGasUsed": "0x21b685", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xf55ab88d59a1e298da584cbd27f73d2eacad6dce70c16d7607f3c57a7a56b5dc", + "blockNumber": "0x95c09c", + "transactionHash": "0x33d6a97f64a26600b98cd1f6d3156ec65e5571d704366f3ae1be6674b032389b", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000020000000010000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xb1dcd2321b1ea1285ff585fc22ea569dbf22b48fcfd6d8c080bbe06727c1728e", + "transactionIndex": "0x1", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x1063f", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d804" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0xb1dcd2321b1ea1285ff585fc22ea569dbf22b48fcfd6d8c080bbe06727c1728e", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000100000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000800040000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "cumulativeGasUsed": "0x2c254", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d804" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d804" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + }, + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "logIndex": "0x4", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000200000000100400000000000000008000000000000000000000000000200000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000000000000020000010020000000010000000000000000800000100000800040000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xa332c27ea332c5f126f253c9913f9a9377671b32e71767d43e1ec50ddad2014a", + "transactionIndex": "0x3", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "cumulativeGasUsed": "0x37d55", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0xa332c27ea332c5f126f253c9913f9a9377671b32e71767d43e1ec50ddad2014a", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000020000000010000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696519261, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519262.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519262.json new file mode 100644 index 0000000..c949c4c --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696519262.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x3cdc6db9c8c3732ceb80438e7f54ee0ea9cf97c842d9fbb2949c62e41426a0e4", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea26469706673582212207f78f055fc91bd0297393b5fb91d28b7c7ec48751239be099a4ae4c93c26dd9c64736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x65", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x33d6a97f64a26600b98cd1f6d3156ec65e5571d704366f3ae1be6674b032389b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x66", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xb1dcd2321b1ea1285ff585fc22ea569dbf22b48fcfd6d8c080bbe06727c1728e", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d8040000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x67", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x68", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa332c27ea332c5f126f253c9913f9a9377671b32e71767d43e1ec50ddad2014a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xab454cbf946777ba1ddbe3d014c9bd290793d804", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x69", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x3cdc6db9c8c3732ceb80438e7f54ee0ea9cf97c842d9fbb2949c62e41426a0e4", + "transactionIndex": "0x1", + "blockHash": "0xf55ab88d59a1e298da584cbd27f73d2eacad6dce70c16d7607f3c57a7a56b5dc", + "blockNumber": "0x95c09c", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21408d", + "gasUsed": "0x20ee85", + "contractAddress": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "logs": [ + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xf55ab88d59a1e298da584cbd27f73d2eacad6dce70c16d7607f3c57a7a56b5dc", + "blockNumber": "0x95c09c", + "transactionHash": "0x3cdc6db9c8c3732ceb80438e7f54ee0ea9cf97c842d9fbb2949c62e41426a0e4", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000200000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000020000000010000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x33d6a97f64a26600b98cd1f6d3156ec65e5571d704366f3ae1be6674b032389b", + "transactionIndex": "0x2", + "blockHash": "0xf55ab88d59a1e298da584cbd27f73d2eacad6dce70c16d7607f3c57a7a56b5dc", + "blockNumber": "0x95c09c", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "cumulativeGasUsed": "0x21b685", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xf55ab88d59a1e298da584cbd27f73d2eacad6dce70c16d7607f3c57a7a56b5dc", + "blockNumber": "0x95c09c", + "transactionHash": "0x33d6a97f64a26600b98cd1f6d3156ec65e5571d704366f3ae1be6674b032389b", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000020000000010000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xb1dcd2321b1ea1285ff585fc22ea569dbf22b48fcfd6d8c080bbe06727c1728e", + "transactionIndex": "0x1", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x1063f", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d804" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0xb1dcd2321b1ea1285ff585fc22ea569dbf22b48fcfd6d8c080bbe06727c1728e", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000100000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000800040000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "cumulativeGasUsed": "0x2c254", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d804" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ab454cbf946777ba1ddbe3d014c9bd290793d804" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + }, + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0x00178c6ea25de0bfeeaf91ef2dec6e7d2ecf4074fe2ba6aa5b9d4317b1de5c96", + "transactionIndex": "0x2", + "logIndex": "0x4", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000200000000100400000000000000008000000000000000000000000000200000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000000000000020000010020000000010000000000000000800000100000800040000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + }, + { + "transactionHash": "0xa332c27ea332c5f126f253c9913f9a9377671b32e71767d43e1ec50ddad2014a", + "transactionIndex": "0x3", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "cumulativeGasUsed": "0x37d55", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xaB454cBF946777Ba1DDBE3d014C9bd290793d804", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xe154879175d1061ae6da651f96c5f5cc87eb5590416a0fb4ec2e11eee71895b5", + "blockNumber": "0x95c09d", + "transactionHash": "0xa332c27ea332c5f126f253c9913f9a9377671b32e71767d43e1ec50ddad2014a", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000020000000010000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0a" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696519262, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696604696.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696604696.json new file mode 100644 index 0000000..0df7aaf --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696604696.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x233c972eefdecef59cd97f38ae4bb7f199116a945a38314834f16278b82f3bf7", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220d32c94df33079f9b0f5e3ded9e4141985ce7f60645911a39aab3910ed3873ca064736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x7a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xb67f94946908d63d9cc93549b6d8c5810af79cbaa50d9d6f0eccf2ef3df79361", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x3622de84ea703164bb1a66ba69bb7310dfc8f7f5", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x7b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3caccd4024dc74bb90d146d1b36d31e8d104b005e9f83df4d8fc705a47630935", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000003622de84ea703164bb1a66ba69bb7310dfc8f7f50000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x7c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf683a12bbc50e983a245db34199698e7d0d3e1da9fe9d7308580f5e878403db7", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x3622de84ea703164bb1a66ba69bb7310dfc8f7f5", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x7d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x65397bea59cf68138bb28d052b208ed4cd1a949aa2931367f81a540dea6e40ed", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x3622de84ea703164bb1a66ba69bb7310dfc8f7f5", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x7e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x233c972eefdecef59cd97f38ae4bb7f199116a945a38314834f16278b82f3bf7", + "0xb67f94946908d63d9cc93549b6d8c5810af79cbaa50d9d6f0eccf2ef3df79361", + "0x3caccd4024dc74bb90d146d1b36d31e8d104b005e9f83df4d8fc705a47630935", + "0xf683a12bbc50e983a245db34199698e7d0d3e1da9fe9d7308580f5e878403db7", + "0x65397bea59cf68138bb28d052b208ed4cd1a949aa2931367f81a540dea6e40ed" + ], + "returns": {}, + "timestamp": 1696604696, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696604718.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696604718.json new file mode 100644 index 0000000..907f034 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696604718.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x233c972eefdecef59cd97f38ae4bb7f199116a945a38314834f16278b82f3bf7", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220d32c94df33079f9b0f5e3ded9e4141985ce7f60645911a39aab3910ed3873ca064736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x7a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xb67f94946908d63d9cc93549b6d8c5810af79cbaa50d9d6f0eccf2ef3df79361", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x3622de84ea703164bb1a66ba69bb7310dfc8f7f5", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x7b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3caccd4024dc74bb90d146d1b36d31e8d104b005e9f83df4d8fc705a47630935", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000003622de84ea703164bb1a66ba69bb7310dfc8f7f50000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x7c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf683a12bbc50e983a245db34199698e7d0d3e1da9fe9d7308580f5e878403db7", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x3622de84ea703164bb1a66ba69bb7310dfc8f7f5", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x7d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x65397bea59cf68138bb28d052b208ed4cd1a949aa2931367f81a540dea6e40ed", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x3622de84ea703164bb1a66ba69bb7310dfc8f7f5", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x7e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x233c972eefdecef59cd97f38ae4bb7f199116a945a38314834f16278b82f3bf7", + "transactionIndex": "0x1", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21408d", + "gasUsed": "0x20ee85", + "contractAddress": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "logs": [ + { + "address": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "transactionHash": "0x233c972eefdecef59cd97f38ae4bb7f199116a945a38314834f16278b82f3bf7", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000001004000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0xb67f94946908d63d9cc93549b6d8c5810af79cbaa50d9d6f0eccf2ef3df79361", + "transactionIndex": "0x2", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "cumulativeGasUsed": "0x21b685", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "transactionHash": "0xb67f94946908d63d9cc93549b6d8c5810af79cbaa50d9d6f0eccf2ef3df79361", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001004000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x3caccd4024dc74bb90d146d1b36d31e8d104b005e9f83df4d8fc705a47630935", + "transactionIndex": "0x3", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x226abc", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000003622de84ea703164bb1a66ba69bb7310dfc8f7f5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "transactionHash": "0x3caccd4024dc74bb90d146d1b36d31e8d104b005e9f83df4d8fc705a47630935", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000200000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000020010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0xf683a12bbc50e983a245db34199698e7d0d3e1da9fe9d7308580f5e878403db7", + "transactionIndex": "0x4", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "cumulativeGasUsed": "0x2426d1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000003622de84ea703164bb1a66ba69bb7310dfc8f7f5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "transactionHash": "0xf683a12bbc50e983a245db34199698e7d0d3e1da9fe9d7308580f5e878403db7", + "transactionIndex": "0x4", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000003622de84ea703164bb1a66ba69bb7310dfc8f7f5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "transactionHash": "0xf683a12bbc50e983a245db34199698e7d0d3e1da9fe9d7308580f5e878403db7", + "transactionIndex": "0x4", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "transactionHash": "0xf683a12bbc50e983a245db34199698e7d0d3e1da9fe9d7308580f5e878403db7", + "transactionIndex": "0x4", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "transactionHash": "0xf683a12bbc50e983a245db34199698e7d0d3e1da9fe9d7308580f5e878403db7", + "transactionIndex": "0x4", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000200000000002000100000000000000000000000000000000000000000000000000801004200000000000400000000000000008000000000000000000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004000000000000000000000000000000000000000020000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000000000000020020010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x65397bea59cf68138bb28d052b208ed4cd1a949aa2931367f81a540dea6e40ed", + "transactionIndex": "0x5", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "cumulativeGasUsed": "0x24e1d2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x3622de84Ea703164bb1A66BA69bb7310dFC8f7F5", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xc80f00bbc64e665b9090518ae9c989fca9bd0e737427a3dccba4ce545b1fd0a5", + "blockNumber": "0x95d701", + "transactionHash": "0x65397bea59cf68138bb28d052b208ed4cd1a949aa2931367f81a540dea6e40ed", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000801004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696604718, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696605676.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696605676.json new file mode 100644 index 0000000..32a9d2b --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696605676.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0xf69b02f30f4eeaac7067fd82db02e6f612badf15ea3ea2b937291166cd02eeeb", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220d32c94df33079f9b0f5e3ded9e4141985ce7f60645911a39aab3910ed3873ca064736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x7f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x703b551758d6fa905aa0caa9f3a9ec7eff126f8cc2bc384bf3a246c849c434f9", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x80", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x1cdc5fb5f1a36955ecccdc31225f95d08a5046d42c266139cd78228a91667e51", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x81", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x60ff683dce0458fefb2ceb89a3d54d762048bffda861760dbded05cb66cb969b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x82", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdec335444a08dcd0d60861338c9e60e87c4a99c90e21bb60e3b927643e2f86e8", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x83", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xf69b02f30f4eeaac7067fd82db02e6f612badf15ea3ea2b937291166cd02eeeb", + "0x703b551758d6fa905aa0caa9f3a9ec7eff126f8cc2bc384bf3a246c849c434f9", + "0x1cdc5fb5f1a36955ecccdc31225f95d08a5046d42c266139cd78228a91667e51", + "0x60ff683dce0458fefb2ceb89a3d54d762048bffda861760dbded05cb66cb969b", + "0xdec335444a08dcd0d60861338c9e60e87c4a99c90e21bb60e3b927643e2f86e8" + ], + "returns": {}, + "timestamp": 1696605676, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696605690.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696605690.json new file mode 100644 index 0000000..1f56c7b --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696605690.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0xf69b02f30f4eeaac7067fd82db02e6f612badf15ea3ea2b937291166cd02eeeb", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220d32c94df33079f9b0f5e3ded9e4141985ce7f60645911a39aab3910ed3873ca064736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x7f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x703b551758d6fa905aa0caa9f3a9ec7eff126f8cc2bc384bf3a246c849c434f9", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x80", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x1cdc5fb5f1a36955ecccdc31225f95d08a5046d42c266139cd78228a91667e51", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x81", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x60ff683dce0458fefb2ceb89a3d54d762048bffda861760dbded05cb66cb969b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x82", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdec335444a08dcd0d60861338c9e60e87c4a99c90e21bb60e3b927643e2f86e8", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x83", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xf69b02f30f4eeaac7067fd82db02e6f612badf15ea3ea2b937291166cd02eeeb", + "transactionIndex": "0x1", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21408d", + "gasUsed": "0x20ee85", + "contractAddress": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "logs": [ + { + "address": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "transactionHash": "0xf69b02f30f4eeaac7067fd82db02e6f612badf15ea3ea2b937291166cd02eeeb", + "transactionIndex": "0x1", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0x703b551758d6fa905aa0caa9f3a9ec7eff126f8cc2bc384bf3a246c849c434f9", + "transactionIndex": "0x2", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "cumulativeGasUsed": "0x21b685", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "transactionHash": "0x703b551758d6fa905aa0caa9f3a9ec7eff126f8cc2bc384bf3a246c849c434f9", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0x1cdc5fb5f1a36955ecccdc31225f95d08a5046d42c266139cd78228a91667e51", + "transactionIndex": "0x3", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x226abc", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "transactionHash": "0x1cdc5fb5f1a36955ecccdc31225f95d08a5046d42c266139cd78228a91667e51", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000001000000000000000000000000000000000000200000000000000000000000000000002000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0x60ff683dce0458fefb2ceb89a3d54d762048bffda861760dbded05cb66cb969b", + "transactionIndex": "0x4", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "cumulativeGasUsed": "0x2426d1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "transactionHash": "0x60ff683dce0458fefb2ceb89a3d54d762048bffda861760dbded05cb66cb969b", + "transactionIndex": "0x4", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000718da86d2aa507f9a1daef0a3e0bb7c0f6e1d07d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "transactionHash": "0x60ff683dce0458fefb2ceb89a3d54d762048bffda861760dbded05cb66cb969b", + "transactionIndex": "0x4", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "transactionHash": "0x60ff683dce0458fefb2ceb89a3d54d762048bffda861760dbded05cb66cb969b", + "transactionIndex": "0x4", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "transactionHash": "0x60ff683dce0458fefb2ceb89a3d54d762048bffda861760dbded05cb66cb969b", + "transactionIndex": "0x4", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000001000000000000000000000000000000800000200000000000400000200000000008002000000000000000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000008000000000000004000000000000000000000000000000800000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000a00000008000000000000000020000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + }, + { + "transactionHash": "0xdec335444a08dcd0d60861338c9e60e87c4a99c90e21bb60e3b927643e2f86e8", + "transactionIndex": "0x5", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "cumulativeGasUsed": "0x24e1d2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x718da86D2aa507f9A1daEF0A3E0Bb7C0f6E1D07D", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x3cfac449ecb8ec0893bdafa1e2598f63a3b45544320146c2a1ff76e57009cb28", + "blockNumber": "0x95d744", + "transactionHash": "0xdec335444a08dcd0d60861338c9e60e87c4a99c90e21bb60e3b927643e2f86e8", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000008000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e0c" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696605690, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696610570.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696610570.json new file mode 100644 index 0000000..9c3602a --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696610570.json @@ -0,0 +1,120 @@ +{ + "transactions": [ + { + "hash": "0x7b6c022e34d399f697df09d41921c5ce181e9081b2a2a1759bea88f2b27ccdcd", + "transactionType": "CREATE", + "contractName": null, + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd78", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122078cb3e5258db6f6122e37106c14d5667037a019773dc08b4c6404fd857c36fb264736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x84", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x16c8e970413e874520e401e523e258649ca356ec2951f2c817b84abb34d825a4", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x13ebfd96dc5990e4d72c48812ee7f8a7e57f753f", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x85", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x41570a55e9fc67ce03f5be709f36af6672b4a93dba24b9c9c981c890298a7448", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b300000000000000000000000013ebfd96dc5990e4d72c48812ee7f8a7e57f753f0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x86", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x526fed0a38bf98011fcadcab985fa787f4ff8d0db04663d8cca5138ea992e282", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x13ebfd96dc5990e4d72c48812ee7f8a7e57f753f", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x87", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x76b134aff30dc4cf11a8f117723db3c4e7a8be988879cccd04d25c9d19f3985a", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x13ebfd96dc5990e4d72c48812ee7f8a7e57f753f", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x88", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x7b6c022e34d399f697df09d41921c5ce181e9081b2a2a1759bea88f2b27ccdcd", + "0x16c8e970413e874520e401e523e258649ca356ec2951f2c817b84abb34d825a4", + "0x41570a55e9fc67ce03f5be709f36af6672b4a93dba24b9c9c981c890298a7448", + "0x526fed0a38bf98011fcadcab985fa787f4ff8d0db04663d8cca5138ea992e282", + "0x76b134aff30dc4cf11a8f117723db3c4e7a8be988879cccd04d25c9d19f3985a" + ], + "returns": {}, + "timestamp": 1696610570, + "chain": 5, + "multi": false, + "commit": "7f53ce1" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696610582.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696610582.json new file mode 100644 index 0000000..9411e42 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696610582.json @@ -0,0 +1,318 @@ +{ + "transactions": [ + { + "hash": "0x7b6c022e34d399f697df09d41921c5ce181e9081b2a2a1759bea88f2b27ccdcd", + "transactionType": "CREATE", + "contractName": null, + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd78", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122078cb3e5258db6f6122e37106c14d5667037a019773dc08b4c6404fd857c36fb264736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x84", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x16c8e970413e874520e401e523e258649ca356ec2951f2c817b84abb34d825a4", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x13ebfd96dc5990e4d72c48812ee7f8a7e57f753f", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x85", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x41570a55e9fc67ce03f5be709f36af6672b4a93dba24b9c9c981c890298a7448", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b300000000000000000000000013ebfd96dc5990e4d72c48812ee7f8a7e57f753f0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x86", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x526fed0a38bf98011fcadcab985fa787f4ff8d0db04663d8cca5138ea992e282", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x13ebfd96dc5990e4d72c48812ee7f8a7e57f753f", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x87", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x76b134aff30dc4cf11a8f117723db3c4e7a8be988879cccd04d25c9d19f3985a", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x13ebfd96dc5990e4d72c48812ee7f8a7e57f753f", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x88", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x7b6c022e34d399f697df09d41921c5ce181e9081b2a2a1759bea88f2b27ccdcd", + "transactionIndex": "0x5", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x278d77", + "gasUsed": "0x20ef69", + "contractAddress": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "logs": [ + { + "address": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "transactionHash": "0x7b6c022e34d399f697df09d41921c5ce181e9081b2a2a1759bea88f2b27ccdcd", + "transactionIndex": "0x5", + "logIndex": "0xe", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000002000000000800000001000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000001000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x16c8e970413e874520e401e523e258649ca356ec2951f2c817b84abb34d825a4", + "transactionIndex": "0x6", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "cumulativeGasUsed": "0x28036f", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "transactionHash": "0x16c8e970413e874520e401e523e258649ca356ec2951f2c817b84abb34d825a4", + "transactionIndex": "0x6", + "logIndex": "0xf", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000002000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x41570a55e9fc67ce03f5be709f36af6672b4a93dba24b9c9c981c890298a7448", + "transactionIndex": "0x7", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x28b7a6", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000013ebfd96dc5990e4d72c48812ee7f8a7e57f753f" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "transactionHash": "0x41570a55e9fc67ce03f5be709f36af6672b4a93dba24b9c9c981c890298a7448", + "transactionIndex": "0x7", + "logIndex": "0x10", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x526fed0a38bf98011fcadcab985fa787f4ff8d0db04663d8cca5138ea992e282", + "transactionIndex": "0x8", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "cumulativeGasUsed": "0x2a73bb", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000013ebfd96dc5990e4d72c48812ee7f8a7e57f753f" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "transactionHash": "0x526fed0a38bf98011fcadcab985fa787f4ff8d0db04663d8cca5138ea992e282", + "transactionIndex": "0x8", + "logIndex": "0x11", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000013ebfd96dc5990e4d72c48812ee7f8a7e57f753f" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "transactionHash": "0x526fed0a38bf98011fcadcab985fa787f4ff8d0db04663d8cca5138ea992e282", + "transactionIndex": "0x8", + "logIndex": "0x12", + "removed": false + }, + { + "address": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "transactionHash": "0x526fed0a38bf98011fcadcab985fa787f4ff8d0db04663d8cca5138ea992e282", + "transactionIndex": "0x8", + "logIndex": "0x13", + "removed": false + }, + { + "address": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "transactionHash": "0x526fed0a38bf98011fcadcab985fa787f4ff8d0db04663d8cca5138ea992e282", + "transactionIndex": "0x8", + "logIndex": "0x14", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000200000000000400000000000000008000000000000000000000000000000000001000000000000020000080002000000040800000001000004000000000010000000000000000000000000000000004000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000050000000002000000000000000000000000000200000008000000000000000020000010000000000000000000001000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x76b134aff30dc4cf11a8f117723db3c4e7a8be988879cccd04d25c9d19f3985a", + "transactionIndex": "0x9", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "cumulativeGasUsed": "0x2b2ebc", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x13ebFd96Dc5990E4D72C48812eE7F8a7e57f753F", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x21e67b1d6b011c5887d7a9ea9ca144430cc25ee89227cdf34694f8ab247219f8", + "blockNumber": "0x95d889", + "transactionHash": "0x76b134aff30dc4cf11a8f117723db3c4e7a8be988879cccd04d25c9d19f3985a", + "transactionIndex": "0x9", + "logIndex": "0x15", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000801000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000001000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696610582, + "chain": 5, + "multi": false, + "commit": "7f53ce1" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612484.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612484.json new file mode 100644 index 0000000..221c28b --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612484.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0xa799400e2d4962308023c212dea41b9ded88ec8ce85b3f0a2a7f2a0026615952", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220e425012f7fc78508ec6165b0f4067d70f9165432e02d9723f84ae5534557b72564736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x89", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaf7b866b80ffa6f53019ee817335505cbf16b96ee44089a8427314038fd1b847", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x5b3a8bc032d792493cc0a2338bb76829a690ea89", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x8a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x73ddd5e20a024f8349b232e1fc21dbc326671ebb89d9cfda3888ca83735769a9", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000005b3a8bc032d792493cc0a2338bb76829a690ea890000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x8b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x85aabcf82916310e9c16fa51870aeddb6387cd6845b35d034a62d7311ee645cd", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x5b3a8bc032d792493cc0a2338bb76829a690ea89", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x8c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x855ef85d4b186cbc5d85bf5887e950313d674e5a08effd10818c9b955f7ebebd", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x5b3a8bc032d792493cc0a2338bb76829a690ea89", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x8d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xa799400e2d4962308023c212dea41b9ded88ec8ce85b3f0a2a7f2a0026615952", + "0xaf7b866b80ffa6f53019ee817335505cbf16b96ee44089a8427314038fd1b847", + "0x73ddd5e20a024f8349b232e1fc21dbc326671ebb89d9cfda3888ca83735769a9", + "0x85aabcf82916310e9c16fa51870aeddb6387cd6845b35d034a62d7311ee645cd", + "0x855ef85d4b186cbc5d85bf5887e950313d674e5a08effd10818c9b955f7ebebd" + ], + "returns": {}, + "timestamp": 1696612484, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612514.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612514.json new file mode 100644 index 0000000..490d47f --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612514.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0xa799400e2d4962308023c212dea41b9ded88ec8ce85b3f0a2a7f2a0026615952", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220e425012f7fc78508ec6165b0f4067d70f9165432e02d9723f84ae5534557b72564736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x89", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xaf7b866b80ffa6f53019ee817335505cbf16b96ee44089a8427314038fd1b847", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x5b3a8bc032d792493cc0a2338bb76829a690ea89", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x8a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x73ddd5e20a024f8349b232e1fc21dbc326671ebb89d9cfda3888ca83735769a9", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000005b3a8bc032d792493cc0a2338bb76829a690ea890000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x8b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x85aabcf82916310e9c16fa51870aeddb6387cd6845b35d034a62d7311ee645cd", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x5b3a8bc032d792493cc0a2338bb76829a690ea89", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x8c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x855ef85d4b186cbc5d85bf5887e950313d674e5a08effd10818c9b955f7ebebd", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x5b3a8bc032d792493cc0a2338bb76829a690ea89", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x8d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xa799400e2d4962308023c212dea41b9ded88ec8ce85b3f0a2a7f2a0026615952", + "transactionIndex": "0x0", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x20ee85", + "gasUsed": "0x20ee85", + "contractAddress": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "logs": [ + { + "address": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "transactionHash": "0xa799400e2d4962308023c212dea41b9ded88ec8ce85b3f0a2a7f2a0026615952", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x10000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0xaf7b866b80ffa6f53019ee817335505cbf16b96ee44089a8427314038fd1b847", + "transactionIndex": "0x1", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "cumulativeGasUsed": "0x21647d", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "transactionHash": "0xaf7b866b80ffa6f53019ee817335505cbf16b96ee44089a8427314038fd1b847", + "transactionIndex": "0x1", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000002000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x73ddd5e20a024f8349b232e1fc21dbc326671ebb89d9cfda3888ca83735769a9", + "transactionIndex": "0x2", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x2218b4", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b3a8bc032d792493cc0a2338bb76829a690ea89" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "transactionHash": "0x73ddd5e20a024f8349b232e1fc21dbc326671ebb89d9cfda3888ca83735769a9", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000200000200000000000000000000000000000000000000000000000000000000000000001000000000000002000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000004000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x85aabcf82916310e9c16fa51870aeddb6387cd6845b35d034a62d7311ee645cd", + "transactionIndex": "0x3", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "cumulativeGasUsed": "0x23d4c9", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b3a8bc032d792493cc0a2338bb76829a690ea89" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "transactionHash": "0x85aabcf82916310e9c16fa51870aeddb6387cd6845b35d034a62d7311ee645cd", + "transactionIndex": "0x3", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005b3a8bc032d792493cc0a2338bb76829a690ea89" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "transactionHash": "0x85aabcf82916310e9c16fa51870aeddb6387cd6845b35d034a62d7311ee645cd", + "transactionIndex": "0x3", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "transactionHash": "0x85aabcf82916310e9c16fa51870aeddb6387cd6845b35d034a62d7311ee645cd", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "transactionHash": "0x85aabcf82916310e9c16fa51870aeddb6387cd6845b35d034a62d7311ee645cd", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x10000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000a00000200000000000400000000000000008000000000000000000000000000000000001000000000000022000080000000000000800000000000004000000000010000000000000000000000000000000004020000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000002000000000000200000008000000000000000020000010000000000000000000000004000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x855ef85d4b186cbc5d85bf5887e950313d674e5a08effd10818c9b955f7ebebd", + "transactionIndex": "0x4", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "cumulativeGasUsed": "0x248fca", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x5B3a8bC032d792493Cc0a2338BB76829A690eA89", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x2dd8723e8b2208f0f4949e8bb7ebe34d732f81b2375acd06a44b850d2a433b30", + "blockNumber": "0x95d900", + "transactionHash": "0x855ef85d4b186cbc5d85bf5887e950313d674e5a08effd10818c9b955f7ebebd", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x10000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000002000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696612514, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612747.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612747.json new file mode 100644 index 0000000..572729a --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612747.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0xa8fb81a8c553295a42b72ee1a6208fa424812b7340d92f61f2e57842748b2389", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220e425012f7fc78508ec6165b0f4067d70f9165432e02d9723f84ae5534557b72564736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x8e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd4f087f7873023c4c2deb222747814662282a18f888be8c4ec4755c971e6ffd2", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5a500f8", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x8f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7c362f4a9d0e55de3801bf9102534d276fc341da82a539385d18e087f7a8756b", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0x1077e", + "value": "0x0", + "data": "0x095ea7b300000000000000000000000017c216247119a539f5bd92a26e9b759ea5a500f80000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x90", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x25932b261deb66de8ee2ea3be16493871ec1527d1def12e121b8cb91a324a402", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5a500f8", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x91", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x85b31f0977056f90c568fba110478308136bfaa927cd9799bacd23ecc29f1681", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5a500f8", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x92", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xa8fb81a8c553295a42b72ee1a6208fa424812b7340d92f61f2e57842748b2389", + "0xd4f087f7873023c4c2deb222747814662282a18f888be8c4ec4755c971e6ffd2", + "0x7c362f4a9d0e55de3801bf9102534d276fc341da82a539385d18e087f7a8756b", + "0x25932b261deb66de8ee2ea3be16493871ec1527d1def12e121b8cb91a324a402", + "0x85b31f0977056f90c568fba110478308136bfaa927cd9799bacd23ecc29f1681" + ], + "returns": {}, + "timestamp": 1696612747, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612753.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612753.json new file mode 100644 index 0000000..8c6a0ad --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612753.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0xa8fb81a8c553295a42b72ee1a6208fa424812b7340d92f61f2e57842748b2389", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220e425012f7fc78508ec6165b0f4067d70f9165432e02d9723f84ae5534557b72564736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x8e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd4f087f7873023c4c2deb222747814662282a18f888be8c4ec4755c971e6ffd2", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5a500f8", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x8f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x7c362f4a9d0e55de3801bf9102534d276fc341da82a539385d18e087f7a8756b", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0x1077e", + "value": "0x0", + "data": "0x095ea7b300000000000000000000000017c216247119a539f5bd92a26e9b759ea5a500f80000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x90", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x25932b261deb66de8ee2ea3be16493871ec1527d1def12e121b8cb91a324a402", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5a500f8", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x91", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x85b31f0977056f90c568fba110478308136bfaa927cd9799bacd23ecc29f1681", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5a500f8", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x92", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0xa8fb81a8c553295a42b72ee1a6208fa424812b7340d92f61f2e57842748b2389", + "transactionIndex": "0x0", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x20ee85", + "gasUsed": "0x20ee85", + "contractAddress": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "logs": [ + { + "address": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "transactionHash": "0xa8fb81a8c553295a42b72ee1a6208fa424812b7340d92f61f2e57842748b2389", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000010000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000200000000800000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0xd4f087f7873023c4c2deb222747814662282a18f888be8c4ec4755c971e6ffd2", + "transactionIndex": "0x1", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "cumulativeGasUsed": "0x21647d", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "transactionHash": "0xd4f087f7873023c4c2deb222747814662282a18f888be8c4ec4755c971e6ffd2", + "transactionIndex": "0x1", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000100000000000000000000010000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x7c362f4a9d0e55de3801bf9102534d276fc341da82a539385d18e087f7a8756b", + "transactionIndex": "0x2", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x2218a8", + "gasUsed": "0xb42b", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000017c216247119a539f5bd92a26e9b759ea5a500f8" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "transactionHash": "0x7c362f4a9d0e55de3801bf9102534d276fc341da82a539385d18e087f7a8756b", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x25932b261deb66de8ee2ea3be16493871ec1527d1def12e121b8cb91a324a402", + "transactionIndex": "0x3", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "cumulativeGasUsed": "0x23d4bd", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000017c216247119a539f5bd92a26e9b759ea5a500f8" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "transactionHash": "0x25932b261deb66de8ee2ea3be16493871ec1527d1def12e121b8cb91a324a402", + "transactionIndex": "0x3", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000017c216247119a539f5bd92a26e9b759ea5a500f8" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "transactionHash": "0x25932b261deb66de8ee2ea3be16493871ec1527d1def12e121b8cb91a324a402", + "transactionIndex": "0x3", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "transactionHash": "0x25932b261deb66de8ee2ea3be16493871ec1527d1def12e121b8cb91a324a402", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "transactionHash": "0x25932b261deb66de8ee2ea3be16493871ec1527d1def12e121b8cb91a324a402", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000010000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000200000000000400000000000000008000000000000000000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000088000000004000000000000000000000000000000000000000020000000000000000000000000000000000000000000000002000000000000000000002200000000000000000000000000200000008800000000000000020000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x85b31f0977056f90c568fba110478308136bfaa927cd9799bacd23ecc29f1681", + "transactionIndex": "0x4", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "cumulativeGasUsed": "0x248fbe", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x17c216247119a539f5bd92a26e9b759ea5A500f8", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xe383ef782afb2884e658dd08fbd628810d2b851180267e901397f0a3126d0bea", + "blockNumber": "0x95d90f", + "transactionHash": "0x85b31f0977056f90c568fba110478308136bfaa927cd9799bacd23ecc29f1681", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000010000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000002000000000000000002000000000000000000000000000000200000000800000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696612753, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612935.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612935.json new file mode 100644 index 0000000..f678562 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612935.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x59c541f474434fa213e43eb1e0d42c0b66ab6ab9ec701ef551811abc150510dc", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220e425012f7fc78508ec6165b0f4067d70f9165432e02d9723f84ae5534557b72564736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x93", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa946e2ce334a2beeda835fdd21ed97a41e304f29b05a1787d3698467f07aefef", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xc0486b4c3a3e6c8ce4224ad36babe590893d955d", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x94", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x4ee6f914786229295268999447cfffb3d5106be85e4da1fa5e46651a00d3cb61", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000c0486b4c3a3e6c8ce4224ad36babe590893d955d0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x95", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xe4b4f0c22cbeb711e543ea0242e2b84922432280f86743298df69e1980863874", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xc0486b4c3a3e6c8ce4224ad36babe590893d955d", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x96", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa3c89b12af5c1cbd3d84b0d4575cfb976c0ffde29389fdeea85b38cccd77c2e1", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xc0486b4c3a3e6c8ce4224ad36babe590893d955d", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x97", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x59c541f474434fa213e43eb1e0d42c0b66ab6ab9ec701ef551811abc150510dc", + "0xa946e2ce334a2beeda835fdd21ed97a41e304f29b05a1787d3698467f07aefef", + "0x4ee6f914786229295268999447cfffb3d5106be85e4da1fa5e46651a00d3cb61", + "0xe4b4f0c22cbeb711e543ea0242e2b84922432280f86743298df69e1980863874", + "0xa3c89b12af5c1cbd3d84b0d4575cfb976c0ffde29389fdeea85b38cccd77c2e1" + ], + "returns": {}, + "timestamp": 1696612935, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612948.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612948.json new file mode 100644 index 0000000..4bbeb90 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696612948.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x59c541f474434fa213e43eb1e0d42c0b66ab6ab9ec701ef551811abc150510dc", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acc50", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282538038062002825833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612326620004ff600039600081816105250152818161106f01526111d90152600081816103dc015281816107e0015281816108ae01528181610d7e01528181610fdf015281816115ec0152818161168301526117d70152600061039501526123266000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e4f565b6102c8610307366004611e82565b610732565b61031f61031a366004611eb0565b610745565b60405190151581526020016102d2565b6102c861033d366004611e82565b61075d565b610355610350366004611e82565b61076a565b005b6002546102c8565b61031f61036d366004611edc565b61087e565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1d565b6108a4565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb0565b61097e565b6102c8610435366004611f3a565b6109a0565b6103556109e7565b6102c8610450366004611f1d565b6109f9565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f61565b610a31565b6102c861049b366004611f1d565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611fa9565b610a7f565b610355610aa1565b610355610ab3565b610355610b2a565b6005546001600160a01b03166103fc565b6102c8610500366004611ff3565b610b3a565b6102c8610513366004611f61565b610b4f565b6102ec610b9d565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611fa9565b610bac565b61031f610568366004611eb0565b610bc2565b6102c861057b366004611ff3565b610c48565b61031f61058e366004611eb0565b610c5d565b6102c86105a1366004611e82565b610c6b565b6102c86105b4366004612032565b610c78565b6102c86105c7366004612032565b610cc6565b610355610d14565b6102c86105e2366004611e82565b610ded565b6103556105f5366004612074565b610dfa565b6102c8610608366004611f1d565b610e7a565b6102c861061b366004611f1d565b610ebd565b6102c861062e366004612098565b610ef5565b6006546001600160a01b03166103fc565b6102c8610652366004611f3a565b610f20565b610355610665366004611f1d565b610f56565b60085460009062010000900460ff161561068b57610686610fc7565b905090565b600754610696610fc7565b61068691906120dc565b6060600380546106af906120ef565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120ef565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611052565b92915050565b6000336107538185856110ab565b5060019392505050565b600061073f8260016111cf565b61077261121f565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff166127106001611279565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612123565b6112d4565b6008805462ff00001916620100001790556000600781905542907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085760025490565b60408051948552602085019390935291830152606082015260800160405180910390a25050565b60003361088c858285611345565b6108978585856113b9565b60019150505b9392505050565b6108ac61121f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108fe57604051634b51153360e11b815260040160405180910390fd5b61097b336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610946573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096a9190612136565b6001600160a01b038416919061155d565b50565b6000336107538185856109918383610ef5565b61099b91906120dc565b6110ab565b6000806109ad8585610b4f565b9050828111156109df57838184604051632e18fdcb60e01b81526004016109d69392919061214f565b60405180910390fd5b949350505050565b6109ef61121f565b6109f7611592565b565b60085460009062010000900460ff161580610a1d5750600654600160a01b900460ff165b610a295760001961073f565b600092915050565b600080610a3d836109f9565b905080841115610a6657828482604051633c8097d960e11b81526004016109d69392919061214f565b6000610a7185610ded565b90506109df338587846115e7565b6000610a8d335b3084611679565b610a98858585610f20565b95945050505050565b610aa961121f565b6109f76000611751565b60065433906001600160a01b03168114610b215760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d6565b61097b81611751565b610b3261121f565b6109f761176a565b6000610b4533610a86565b6109df8484610a31565b600080610b5b836109f9565b905080841115610b845782848260405163284ff66760e01b81526004016109d69392919061214f565b6000610b8f85610c6b565b90506109df338583886115e7565b6060600480546106af906120ef565b6000610bb733610a86565b610a988585856109a0565b60003381610bd08286610ef5565b905083811015610c305760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d6565b610c3d82868684036110ab565b506001949350505050565b6000610c5333610a86565b6109df8484610b4f565b6000336107538185856113b9565b600061073f826001611052565b600080610c8483610e7a565b905080851115610cad57828582604051633fa733bb60e21b81526004016109d69392919061214f565b6000610cb88661075d565b9050610a98858588846117ad565b600080610cd283610ebd565b905080851115610cfb57828582604051632e52afbb60e21b81526004016109d69392919061214f565b6000610d0686610732565b9050610a98858583896117ad565b610d1c61121f565b60085462010000900460ff16610d4557604051635adc30c160e11b815260040160405180910390fd5b610d4d610fc7565b6007556008805462ff000019169055610da5610d716005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155d565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd360025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111cf565b610e0261121f565b610bb88161ffff161115610e295760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9457600061073f565b61073f610eb6836001600160a01b031660009081526020819052604090205490565b6000611052565b60085460009062010000900460ff16610ed757600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2d8585610a31565b9050828110156109df5783818460405163d032c98360e01b81526004016109d69392919061214f565b610f5e61121f565b600680546001600160a01b0383166001600160a01b03199091168117909155610f8f6005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612136565b600061089d61105f61066a565b61106a9060016120dc565b6110957f0000000000000000000000000000000000000000000000000000000000000000600a612254565b6002546110a291906120dc565b85919085611279565b6001600160a01b03831661110d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d6565b6001600160a01b03821661116e5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d6565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089d6111ff7f0000000000000000000000000000000000000000000000000000000000000000600a612254565b60025461120c91906120dc565b61121461066a565b6110a29060016120dc565b6005546001600160a01b031633146109f75760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d6565b600080611287868686611869565b9050600183600281111561129d5761129d612263565b1480156112ba5750600084806112b5576112b5612279565b868809115b15610a98576112ca6001826120dc565b9695505050505050565b6040516001600160a01b038085166024830152831660448201526064810182905261133f9085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611953565b50505050565b60006113518484610ef5565b9050600019811461133f57818110156113ac5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d6565b61133f84848484036110ab565b6001600160a01b03831661141d5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d6565b6001600160a01b03821661147f5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d6565b6001600160a01b038316600090815260208190526040902054818110156114f75760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d6565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a361133f565b6040516001600160a01b03831660248201526044810182905261158d90849063a9059cbb60e01b90606401611308565b505050565b61159a611a28565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116137f00000000000000000000000000000000000000000000000000000000000000008530856112d4565b61161d8382611a78565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166b929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c1606088016040890161228f565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173457600080fd5b505af1158015611748573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097b81611b37565b611772611b89565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115ca3390565b336001600160a01b038416146117c8576117c8833383611345565b6117d28382611bd6565b6117fd7f0000000000000000000000000000000000000000000000000000000000000000858461155d565b826001600160a01b0316846001600160a01b03166118183390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185b929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a35783828161189957611899612279565b049250505061089d565b8084116118ea5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d6565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a8826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d089092919063ffffffff16565b90508051600014806119c95750808060200190518101906119c991906122b2565b61158d5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d6565b600654600160a01b900460ff166109f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d6565b6001600160a01b038216611ace5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d6565b8060026000828254611ae091906120dc565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f75760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d6565b6001600160a01b038216611c365760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d6565b6001600160a01b03821660009081526020819052604090205481811015611caa5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d6565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109df848460008585600080866001600160a01b03168587604051611d2f91906122d4565b60006040518083038185875af1925050503d8060008114611d6c576040519150601f19603f3d011682016040523d82523d6000602084013e611d71565b606091505b5091509150611d8287838387611d8d565b979650505050505050565b60608315611dfc578251600003611df5576001600160a01b0385163b611df55760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d6565b50816109df565b6109df8383815115611e115781518083602001fd5b8060405162461bcd60e51b81526004016109d69190611e4f565b60005b83811015611e46578181015183820152602001611e2e565b50506000910152565b6020815260008251806020840152611e6e816040850160208701611e2b565b601f01601f19169190910160400192915050565b600060208284031215611e9457600080fd5b5035919050565b6001600160a01b038116811461097b57600080fd5b60008060408385031215611ec357600080fd5b8235611ece81611e9b565b946020939093013593505050565b600080600060608486031215611ef157600080fd5b8335611efc81611e9b565b92506020840135611f0c81611e9b565b929592945050506040919091013590565b600060208284031215611f2f57600080fd5b813561089d81611e9b565b600080600060608486031215611f4f57600080fd5b833592506020840135611f0c81611e9b565b60008060408385031215611f7457600080fd5b823591506020830135611f8681611e9b565b809150509250929050565b600060a08284031215611fa357600080fd5b50919050565b6000806000806101008587031215611fc057600080fd5b843593506020850135611fd281611e9b565b925060408501359150611fe88660608701611f91565b905092959194509250565b600080600060e0848603121561200857600080fd5b83359250602084013561201a81611e9b565b91506120298560408601611f91565b90509250925092565b60008060006060848603121561204757600080fd5b83359250602084013561205981611e9b565b9150604084013561206981611e9b565b809150509250925092565b60006020828403121561208657600080fd5b813561ffff8116811461089d57600080fd5b600080604083850312156120ab57600080fd5b82356120b681611e9b565b91506020830135611f8681611e9b565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c6565b600181811c9082168061210357607f821691505b602082108103611fa357634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c6565b60006020828403121561214857600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ab578160001904821115612191576121916120c6565b8085161561219e57918102915b93841c9390800290612175565b509250929050565b6000826121c25750600161073f565b816121cf5750600061073f565b81600181146121e557600281146121ef5761220b565b600191505061073f565b60ff841115612200576122006120c6565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222e575081810a61073f565b6122388383612170565b806000190482111561224c5761224c6120c6565b029392505050565b600061089d60ff8416836121b3565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a157600080fd5b813560ff8116811461089d57600080fd5b6000602082840312156122c457600080fd5b8151801515811461089d57600080fd5b600082516122e6818460208701611e2b565b919091019291505056fea2646970667358221220e425012f7fc78508ec6165b0f4067d70f9165432e02d9723f84ae5534557b72564736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x93", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa946e2ce334a2beeda835fdd21ed97a41e304f29b05a1787d3698467f07aefef", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xc0486b4c3a3e6c8ce4224ad36babe590893d955d", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x94", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x4ee6f914786229295268999447cfffb3d5106be85e4da1fa5e46651a00d3cb61", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000c0486b4c3a3e6c8ce4224ad36babe590893d955d0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x95", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xe4b4f0c22cbeb711e543ea0242e2b84922432280f86743298df69e1980863874", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xc0486b4c3a3e6c8ce4224ad36babe590893d955d", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x96", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa3c89b12af5c1cbd3d84b0d4575cfb976c0ffde29389fdeea85b38cccd77c2e1", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xc0486b4c3a3e6c8ce4224ad36babe590893d955d", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x97", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x59c541f474434fa213e43eb1e0d42c0b66ab6ab9ec701ef551811abc150510dc", + "transactionIndex": "0x0", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x20ee85", + "gasUsed": "0x20ee85", + "contractAddress": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "logs": [ + { + "address": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "transactionHash": "0x59c541f474434fa213e43eb1e0d42c0b66ab6ab9ec701ef551811abc150510dc", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000001000000000000000000000000000002000000020000000000000000000800000000000000000000000000000000408000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0xa946e2ce334a2beeda835fdd21ed97a41e304f29b05a1787d3698467f07aefef", + "transactionIndex": "0x1", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "cumulativeGasUsed": "0x21647d", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "transactionHash": "0xa946e2ce334a2beeda835fdd21ed97a41e304f29b05a1787d3698467f07aefef", + "transactionIndex": "0x1", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000002000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x4ee6f914786229295268999447cfffb3d5106be85e4da1fa5e46651a00d3cb61", + "transactionIndex": "0x2", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x2218b4", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000c0486b4c3a3e6c8ce4224ad36babe590893d955d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "transactionHash": "0x4ee6f914786229295268999447cfffb3d5106be85e4da1fa5e46651a00d3cb61", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000001000000020000000000080000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000020000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0xe4b4f0c22cbeb711e543ea0242e2b84922432280f86743298df69e1980863874", + "transactionIndex": "0x3", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "cumulativeGasUsed": "0x23d4c9", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000c0486b4c3a3e6c8ce4224ad36babe590893d955d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "transactionHash": "0xe4b4f0c22cbeb711e543ea0242e2b84922432280f86743298df69e1980863874", + "transactionIndex": "0x3", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000c0486b4c3a3e6c8ce4224ad36babe590893d955d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "transactionHash": "0xe4b4f0c22cbeb711e543ea0242e2b84922432280f86743298df69e1980863874", + "transactionIndex": "0x3", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "transactionHash": "0xe4b4f0c22cbeb711e543ea0242e2b84922432280f86743298df69e1980863874", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "transactionHash": "0xe4b4f0c22cbeb711e543ea0242e2b84922432280f86743298df69e1980863874", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000200000000000400000000000000008000000000000000000000000000000000001000002020000020000080000000000000800000000000004000000000010000000009000000000000000000000004000000000000000000000000000000000000000020000000000000000000000004000000000000000000000000000000000000000000002000000000000000000000000000200000008000000000000000020000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0xa3c89b12af5c1cbd3d84b0d4575cfb976c0ffde29389fdeea85b38cccd77c2e1", + "transactionIndex": "0x4", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "cumulativeGasUsed": "0x248fca", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xc0486b4c3A3E6C8Ce4224ad36BABe590893d955d", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xb6c3cf10a80756951f8349ba5e6bee1e3a2a4d1ebb54af123dc7cd76bb7c6744", + "blockNumber": "0x95d91b", + "transactionHash": "0xa3c89b12af5c1cbd3d84b0d4575cfb976c0ffde29389fdeea85b38cccd77c2e1", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000400000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000800000000000000000000000000008000000000000000000000004000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696612948, + "chain": 5, + "multi": false, + "commit": "918a14b" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696613263.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696613263.json new file mode 100644 index 0000000..702e81f --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696613263.json @@ -0,0 +1,120 @@ +{ + "transactions": [ + { + "hash": "0x67b0c576e0370d0dbb92c24c1806a05f0d6156e51ed3746f436baa050536e007", + "transactionType": "CREATE", + "contractName": null, + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd69", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122027ddea86359ef600e5cb7cf891c9fc33618fc1d2c2dd95c341c7f0c3507f22e464736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x98", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x0cfb419b385c7c7fed87a1cb1ad0d8b876d38bb3831169f3ce1eac79ed61c2a3", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9e4561b1c560177bb5c129177ec2192f9391dc1c", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x99", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x94030e509cdfbb81081788029ad74830cec0868bd0e8a36c99a797fd409a7afe", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000009e4561b1c560177bb5c129177ec2192f9391dc1c0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x9a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3ec72855de7ecbe8912577f4fcbffc0ba7b3796b5ea17e80b829075912335342", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9e4561b1c560177bb5c129177ec2192f9391dc1c", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x9b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf7521706078f90a47b5a1a1699dd2be6a0f6101d95b2166ce38442a79448c46d", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9e4561b1c560177bb5c129177ec2192f9391dc1c", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x9c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x67b0c576e0370d0dbb92c24c1806a05f0d6156e51ed3746f436baa050536e007", + "0x0cfb419b385c7c7fed87a1cb1ad0d8b876d38bb3831169f3ce1eac79ed61c2a3", + "0x94030e509cdfbb81081788029ad74830cec0868bd0e8a36c99a797fd409a7afe", + "0x3ec72855de7ecbe8912577f4fcbffc0ba7b3796b5ea17e80b829075912335342", + "0xf7521706078f90a47b5a1a1699dd2be6a0f6101d95b2166ce38442a79448c46d" + ], + "returns": {}, + "timestamp": 1696613263, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696613269.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696613269.json new file mode 100644 index 0000000..1526afe --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696613269.json @@ -0,0 +1,318 @@ +{ + "transactions": [ + { + "hash": "0x67b0c576e0370d0dbb92c24c1806a05f0d6156e51ed3746f436baa050536e007", + "transactionType": "CREATE", + "contractName": null, + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd69", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122027ddea86359ef600e5cb7cf891c9fc33618fc1d2c2dd95c341c7f0c3507f22e464736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x98", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x0cfb419b385c7c7fed87a1cb1ad0d8b876d38bb3831169f3ce1eac79ed61c2a3", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9e4561b1c560177bb5c129177ec2192f9391dc1c", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x99", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x94030e509cdfbb81081788029ad74830cec0868bd0e8a36c99a797fd409a7afe", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000009e4561b1c560177bb5c129177ec2192f9391dc1c0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x9a", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3ec72855de7ecbe8912577f4fcbffc0ba7b3796b5ea17e80b829075912335342", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9e4561b1c560177bb5c129177ec2192f9391dc1c", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x9b", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xf7521706078f90a47b5a1a1699dd2be6a0f6101d95b2166ce38442a79448c46d", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9e4561b1c560177bb5c129177ec2192f9391dc1c", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0x9c", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x67b0c576e0370d0dbb92c24c1806a05f0d6156e51ed3746f436baa050536e007", + "transactionIndex": "0x0", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x20ef5d", + "gasUsed": "0x20ef5d", + "contractAddress": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "logs": [ + { + "address": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "transactionHash": "0x67b0c576e0370d0dbb92c24c1806a05f0d6156e51ed3746f436baa050536e007", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x0cfb419b385c7c7fed87a1cb1ad0d8b876d38bb3831169f3ce1eac79ed61c2a3", + "transactionIndex": "0x1", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "cumulativeGasUsed": "0x216555", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "transactionHash": "0x0cfb419b385c7c7fed87a1cb1ad0d8b876d38bb3831169f3ce1eac79ed61c2a3", + "transactionIndex": "0x1", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x94030e509cdfbb81081788029ad74830cec0868bd0e8a36c99a797fd409a7afe", + "transactionIndex": "0x2", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x22198c", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000009e4561b1c560177bb5c129177ec2192f9391dc1c" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "transactionHash": "0x94030e509cdfbb81081788029ad74830cec0868bd0e8a36c99a797fd409a7afe", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100800000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000800000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000030000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0x3ec72855de7ecbe8912577f4fcbffc0ba7b3796b5ea17e80b829075912335342", + "transactionIndex": "0x3", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "cumulativeGasUsed": "0x23d5a1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000009e4561b1c560177bb5c129177ec2192f9391dc1c" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "transactionHash": "0x3ec72855de7ecbe8912577f4fcbffc0ba7b3796b5ea17e80b829075912335342", + "transactionIndex": "0x3", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000009e4561b1c560177bb5c129177ec2192f9391dc1c" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "transactionHash": "0x3ec72855de7ecbe8912577f4fcbffc0ba7b3796b5ea17e80b829075912335342", + "transactionIndex": "0x3", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "transactionHash": "0x3ec72855de7ecbe8912577f4fcbffc0ba7b3796b5ea17e80b829075912335342", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "transactionHash": "0x3ec72855de7ecbe8912577f4fcbffc0ba7b3796b5ea17e80b829075912335342", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100800000000000000000040000000000000000000000000000800000200000000000400000000000000008000000000000000000000000000800000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004800000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000000000000020000030000000000000000000000000000800000100000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + }, + { + "transactionHash": "0xf7521706078f90a47b5a1a1699dd2be6a0f6101d95b2166ce38442a79448c46d", + "transactionIndex": "0x4", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "cumulativeGasUsed": "0x2490a2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x9e4561B1C560177Bb5c129177EC2192f9391Dc1c", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x29b1d08d262267ff9423b9c2ad98691f7e66d246046156b5f5a7eaadcb99daaa", + "blockNumber": "0x95d92f", + "transactionHash": "0xf7521706078f90a47b5a1a1699dd2be6a0f6101d95b2166ce38442a79448c46d", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000800000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e09" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696613269, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614074.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614074.json new file mode 100644 index 0000000..dc41df3 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614074.json @@ -0,0 +1,120 @@ +{ + "transactions": [ + { + "hash": "0x532a66973d79c323266877f508c8c4282f2dae5a4c5cfeaed35b3fd950ef6fa8", + "transactionType": "CREATE", + "contractName": null, + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd69", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122027ddea86359ef600e5cb7cf891c9fc33618fc1d2c2dd95c341c7f0c3507f22e464736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x9d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa5e5b98ebc7cb0febf90e0ab484ed93bbb851297eeb634828eca388fcdc0c0ad", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x24c30e70512f108e6747a71a435e6c410c57dd0d", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x9e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x907c291153cef2a328f24cec1ad67a811c9e9974f2c5e12a8e1fd1e61e5d8a2f", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b300000000000000000000000024c30e70512f108e6747a71a435e6c410c57dd0d0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x9f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd958e8b210c6d0b0a7d36fe6369ca0d6946fcbb67386632e25dd402aa3d2dd71", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x24c30e70512f108e6747a71a435e6c410c57dd0d", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa0", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdf05193b9e4c95a007b2da2bbaef502eeebb525dd38d2b05747444fc51866dbb", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x24c30e70512f108e6747a71a435e6c410c57dd0d", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa1", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x532a66973d79c323266877f508c8c4282f2dae5a4c5cfeaed35b3fd950ef6fa8", + "0xa5e5b98ebc7cb0febf90e0ab484ed93bbb851297eeb634828eca388fcdc0c0ad", + "0x907c291153cef2a328f24cec1ad67a811c9e9974f2c5e12a8e1fd1e61e5d8a2f", + "0xd958e8b210c6d0b0a7d36fe6369ca0d6946fcbb67386632e25dd402aa3d2dd71", + "0xdf05193b9e4c95a007b2da2bbaef502eeebb525dd38d2b05747444fc51866dbb" + ], + "returns": {}, + "timestamp": 1696614074, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614087.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614087.json new file mode 100644 index 0000000..0c84a5e --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614087.json @@ -0,0 +1,318 @@ +{ + "transactions": [ + { + "hash": "0x532a66973d79c323266877f508c8c4282f2dae5a4c5cfeaed35b3fd950ef6fa8", + "transactionType": "CREATE", + "contractName": null, + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd69", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122027ddea86359ef600e5cb7cf891c9fc33618fc1d2c2dd95c341c7f0c3507f22e464736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x9d", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xa5e5b98ebc7cb0febf90e0ab484ed93bbb851297eeb634828eca388fcdc0c0ad", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x24c30e70512f108e6747a71a435e6c410c57dd0d", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x9e", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x907c291153cef2a328f24cec1ad67a811c9e9974f2c5e12a8e1fd1e61e5d8a2f", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b300000000000000000000000024c30e70512f108e6747a71a435e6c410c57dd0d0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x9f", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd958e8b210c6d0b0a7d36fe6369ca0d6946fcbb67386632e25dd402aa3d2dd71", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x24c30e70512f108e6747a71a435e6c410c57dd0d", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa0", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdf05193b9e4c95a007b2da2bbaef502eeebb525dd38d2b05747444fc51866dbb", + "transactionType": "CALL", + "contractName": null, + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "function": null, + "arguments": null, + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x24c30e70512f108e6747a71a435e6c410c57dd0d", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa1", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x532a66973d79c323266877f508c8c4282f2dae5a4c5cfeaed35b3fd950ef6fa8", + "transactionIndex": "0x0", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x20ef5d", + "gasUsed": "0x20ef5d", + "contractAddress": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "logs": [ + { + "address": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "transactionHash": "0x532a66973d79c323266877f508c8c4282f2dae5a4c5cfeaed35b3fd950ef6fa8", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000080100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000201000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0xa5e5b98ebc7cb0febf90e0ab484ed93bbb851297eeb634828eca388fcdc0c0ad", + "transactionIndex": "0x1", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "cumulativeGasUsed": "0x216555", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "transactionHash": "0xa5e5b98ebc7cb0febf90e0ab484ed93bbb851297eeb634828eca388fcdc0c0ad", + "transactionIndex": "0x1", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x907c291153cef2a328f24cec1ad67a811c9e9974f2c5e12a8e1fd1e61e5d8a2f", + "transactionIndex": "0x2", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x22198c", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000024c30e70512f108e6747a71a435e6c410c57dd0d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "transactionHash": "0x907c291153cef2a328f24cec1ad67a811c9e9974f2c5e12a8e1fd1e61e5d8a2f", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000400000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000400000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0xd958e8b210c6d0b0a7d36fe6369ca0d6946fcbb67386632e25dd402aa3d2dd71", + "transactionIndex": "0x3", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "cumulativeGasUsed": "0x23d5a1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000024c30e70512f108e6747a71a435e6c410c57dd0d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "transactionHash": "0xd958e8b210c6d0b0a7d36fe6369ca0d6946fcbb67386632e25dd402aa3d2dd71", + "transactionIndex": "0x3", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x00000000000000000000000024c30e70512f108e6747a71a435e6c410c57dd0d" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "transactionHash": "0xd958e8b210c6d0b0a7d36fe6369ca0d6946fcbb67386632e25dd402aa3d2dd71", + "transactionIndex": "0x3", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "transactionHash": "0xd958e8b210c6d0b0a7d36fe6369ca0d6946fcbb67386632e25dd402aa3d2dd71", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "transactionHash": "0xd958e8b210c6d0b0a7d36fe6369ca0d6946fcbb67386632e25dd402aa3d2dd71", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002080100000400000000000000000000000000000000000000000000800000200000000000400000000000000008000000000200000000400000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004000000000000000000000000000000000000804020000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000000000000020000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0xdf05193b9e4c95a007b2da2bbaef502eeebb525dd38d2b05747444fc51866dbb", + "transactionIndex": "0x4", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "cumulativeGasUsed": "0x2490a2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x24C30e70512F108e6747A71A435E6c410c57dd0D", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x26425f890de8a5e3eddaa130c6243e6d13f8a0af5a4319061b0febba96ff856d", + "blockNumber": "0x95d963", + "transactionHash": "0xdf05193b9e4c95a007b2da2bbaef502eeebb525dd38d2b05747444fc51866dbb", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002080100000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000000000800000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696614087, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614621.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614621.json new file mode 100644 index 0000000..a8f613e --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614621.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x5bd2171846324117030b1761fd1136b5bc9446a7c2043334398f7ff76606dbaa", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd69", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea2646970667358221220b77b8e521b60b6eee308b5639832beaa00cca8467b74185bd0cdb1b37ff42dc964736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0xa2", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x8b514089cf33d1e0d50cb3bd3f474559665143d607e704a809c6ead28853e02b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0xa3", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x41584685a6b23acd7289828930579026040da940bedd56823046e3c469b71523", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a50000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0xa4", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa5", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x80c7a845b9a4fca7ac191742cc7cc42cc14ec76a6663d729c4cd60d105cf2ba3", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa6", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x5bd2171846324117030b1761fd1136b5bc9446a7c2043334398f7ff76606dbaa", + "0x8b514089cf33d1e0d50cb3bd3f474559665143d607e704a809c6ead28853e02b", + "0x41584685a6b23acd7289828930579026040da940bedd56823046e3c469b71523", + "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "0x80c7a845b9a4fca7ac191742cc7cc42cc14ec76a6663d729c4cd60d105cf2ba3" + ], + "returns": {}, + "timestamp": 1696614621, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614633.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614633.json new file mode 100644 index 0000000..882a45e --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614633.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x5bd2171846324117030b1761fd1136b5bc9446a7c2043334398f7ff76606dbaa", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd69", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea2646970667358221220b77b8e521b60b6eee308b5639832beaa00cca8467b74185bd0cdb1b37ff42dc964736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0xa2", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x8b514089cf33d1e0d50cb3bd3f474559665143d607e704a809c6ead28853e02b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0xa3", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x41584685a6b23acd7289828930579026040da940bedd56823046e3c469b71523", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a50000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0xa4", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa5", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x80c7a845b9a4fca7ac191742cc7cc42cc14ec76a6663d729c4cd60d105cf2ba3", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa6", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x5bd2171846324117030b1761fd1136b5bc9446a7c2043334398f7ff76606dbaa", + "transactionIndex": "0x0", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x20ef5d", + "gasUsed": "0x20ef5d", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "logs": [ + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x5bd2171846324117030b1761fd1136b5bc9446a7c2043334398f7ff76606dbaa", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000004000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x8b514089cf33d1e0d50cb3bd3f474559665143d607e704a809c6ead28853e02b", + "transactionIndex": "0x1", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "cumulativeGasUsed": "0x216555", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x8b514089cf33d1e0d50cb3bd3f474559665143d607e704a809c6ead28853e02b", + "transactionIndex": "0x1", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x41584685a6b23acd7289828930579026040da940bedd56823046e3c469b71523", + "transactionIndex": "0x2", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x22198c", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x41584685a6b23acd7289828930579026040da940bedd56823046e3c469b71523", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000001000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000080000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "cumulativeGasUsed": "0x23d5a1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000001800000200000000000400000010000000008000000000000000000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004200000000000000000000000000100000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000004000000020000010000000000000000000080000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x80c7a845b9a4fca7ac191742cc7cc42cc14ec76a6663d729c4cd60d105cf2ba3", + "transactionIndex": "0x4", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "cumulativeGasUsed": "0x2490a2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x80c7a845b9a4fca7ac191742cc7cc42cc14ec76a6663d729c4cd60d105cf2ba3", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000004000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696614633, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614670.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614670.json new file mode 100644 index 0000000..4dfa207 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696614670.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x5bd2171846324117030b1761fd1136b5bc9446a7c2043334398f7ff76606dbaa", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd69", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea2646970667358221220b77b8e521b60b6eee308b5639832beaa00cca8467b74185bd0cdb1b37ff42dc964736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0xa2", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x8b514089cf33d1e0d50cb3bd3f474559665143d607e704a809c6ead28853e02b", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0xa3", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x41584685a6b23acd7289828930579026040da940bedd56823046e3c469b71523", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a50000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0xa4", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa5", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x80c7a845b9a4fca7ac191742cc7cc42cc14ec76a6663d729c4cd60d105cf2ba3", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xff3820bd8196c6fdb5568d7cb1814ecc305787a5", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xa6", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x5bd2171846324117030b1761fd1136b5bc9446a7c2043334398f7ff76606dbaa", + "transactionIndex": "0x0", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x20ef5d", + "gasUsed": "0x20ef5d", + "contractAddress": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "logs": [ + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x5bd2171846324117030b1761fd1136b5bc9446a7c2043334398f7ff76606dbaa", + "transactionIndex": "0x0", + "logIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000004000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x8b514089cf33d1e0d50cb3bd3f474559665143d607e704a809c6ead28853e02b", + "transactionIndex": "0x1", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "cumulativeGasUsed": "0x216555", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x8b514089cf33d1e0d50cb3bd3f474559665143d607e704a809c6ead28853e02b", + "transactionIndex": "0x1", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x41584685a6b23acd7289828930579026040da940bedd56823046e3c469b71523", + "transactionIndex": "0x2", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x22198c", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x41584685a6b23acd7289828930579026040da940bedd56823046e3c469b71523", + "transactionIndex": "0x2", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000001000000200000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000080000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "cumulativeGasUsed": "0x23d5a1", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "logIndex": "0x3", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000ff3820bd8196c6fdb5568d7cb1814ecc305787a5" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x3b4bd86b273a2e65adf3e5166f227c155073ee2a195ba7004091b9d50d7c432a", + "transactionIndex": "0x3", + "logIndex": "0x6", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000001800000200000000000400000010000000008000000000000000000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004200000000000000000000000000100000000000020000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000200000008000000004000000020000010000000000000000000080000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + }, + { + "transactionHash": "0x80c7a845b9a4fca7ac191742cc7cc42cc14ec76a6663d729c4cd60d105cf2ba3", + "transactionIndex": "0x4", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "cumulativeGasUsed": "0x2490a2", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xFf3820bd8196C6Fdb5568d7CB1814ecC305787a5", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0xbbd4952dcb884517d5289e9f2f070f3ef68b689f250ab7bf2bb95ce7326f116d", + "blockNumber": "0x95d988", + "transactionHash": "0x80c7a845b9a4fca7ac191742cc7cc42cc14ec76a6663d729c4cd60d105cf2ba3", + "transactionIndex": "0x4", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000000000000000000000000000000000000000000000000800000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004200000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000004000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e08" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696614670, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845420.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845420.json new file mode 100644 index 0000000..9d94903 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845420.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionType": "CREATE", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd78", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122017793c8a7bc05c2038109aabb313bdc155ed8cc05f48aeac25e878dc3835b77364736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0xa9", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0xaa", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a340000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0xab", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xac", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xad", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7" + ], + "returns": {}, + "timestamp": 1696845420, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845427.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845427.json new file mode 100644 index 0000000..c59ab56 --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845427.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionType": "CREATE", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd78", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122017793c8a7bc05c2038109aabb313bdc155ed8cc05f48aeac25e878dc3835b77364736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0xa9", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0xaa", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a340000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0xab", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xac", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xad", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionIndex": "0x2", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21a8f4", + "gasUsed": "0x20ef69", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionIndex": "0x3", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x221eec", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionIndex": "0x4", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x22d323", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionIndex": "0x4", + "logIndex": "0x3", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000020000000000800000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x248f38", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x6", + "removed": false + }, + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000004000000000000000000000000000000000000000000800000200000000000400000000000000008020000000000800000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004000000000000000000000000000000020000000022000000000000000000000000000000000000000000000000000800000000000000002000000000000000000000000000200000008000000000000000020000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionIndex": "0x6", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x254a39", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionIndex": "0x6", + "logIndex": "0x8", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000004000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000020000000002000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696845427, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845459.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845459.json new file mode 100644 index 0000000..0b1b6ef --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-1696845459.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionType": "CREATE", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd78", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122017793c8a7bc05c2038109aabb313bdc155ed8cc05f48aeac25e878dc3835b77364736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0xa9", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0xaa", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a340000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0xab", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xac", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xad", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionIndex": "0x2", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21a8f4", + "gasUsed": "0x20ef69", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionIndex": "0x3", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x221eec", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionIndex": "0x4", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x22d323", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionIndex": "0x4", + "logIndex": "0x3", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000020000000000800000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x248f38", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x6", + "removed": false + }, + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000004000000000000000000000000000000000000000000800000200000000000400000000000000008020000000000800000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004000000000000000000000000000000020000000022000000000000000000000000000000000000000000000000000800000000000000002000000000000000000000000000200000008000000000000000020000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionIndex": "0x6", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x254a39", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionIndex": "0x6", + "logIndex": "0x8", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000004000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000020000000002000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696845459, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-latest.json b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-latest.json new file mode 100644 index 0000000..0b1b6ef --- /dev/null +++ b/broadcast/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol/5/run-latest.json @@ -0,0 +1,330 @@ +{ + "transactions": [ + { + "hash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionType": "CREATE", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": null, + "arguments": [ + "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "gas": "0x2acd78", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea264697066735822122017793c8a7bc05c2038109aabb313bdc155ed8cc05f48aeac25e878dc3835b77364736f6c634300081500330000000000000000000000009fd21be27a2b059a288229361e2fa632d8d2d074000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0xa9", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0xaa", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionType": "CALL", + "contractName": "MintableERC20", + "contractAddress": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0x9fd21be27a2b059a288229361e2fa632d8d2d074", + "gas": "0xf8eb", + "value": "0x0", + "data": "0x095ea7b3000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a340000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0xab", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0x26563", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xac", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionType": "CALL", + "contractName": "TestPermit", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "function": "transferOwnership(address)", + "arguments": [ + "0x5A0Fb32360aead818D5486fe311A88bc681A1de1" + ], + "transaction": { + "type": "0x02", + "from": "0xb91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "to": "0xf6513770645a858569cea1a87210f16f7a9c9a34", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1", + "nonce": "0xad", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionIndex": "0x2", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": null, + "cumulativeGasUsed": "0x21a8f4", + "gasUsed": "0x20ef69", + "contractAddress": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8" + ], + "data": "0x", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0x744ea791336c268af24bb38fd45dad1cdad5081861ca16f686fa530ef5912e63", + "transactionIndex": "0x2", + "logIndex": "0x1", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000100000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000020000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionIndex": "0x3", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x221eec", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xd379b161db77ecf231287a2fb9c21f8f45a408130b9f81c7d41fab7987bf7738", + "transactionIndex": "0x3", + "logIndex": "0x2", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionIndex": "0x4", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "cumulativeGasUsed": "0x22d323", + "gasUsed": "0xb437", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xde8e09d90aa8334c192ad5518fe107a2fa9316eb57e20f89968959cf8dfbec1d", + "transactionIndex": "0x4", + "logIndex": "0x3", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000200000000000000000000000000000020000000000800000000000000000000001000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000200000000000000000000000000000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x248f38", + "gasUsed": "0x1bc15", + "contractAddress": null, + "logs": [ + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x4", + "removed": false + }, + { + "address": "0x9FD21bE27A2B059a288229361E2fA632D8D2d074", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x000000000000000000000000f6513770645a858569cea1a87210f16f7a9c9a34" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x5", + "removed": false + }, + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x6", + "removed": false + }, + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0xc468d0aabd9f9d76e3372083448705ae3c4e265ca81407ef181c644871c87337", + "transactionIndex": "0x5", + "logIndex": "0x7", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000004000000000000000000000000000000000000000000800000200000000000400000000000000008020000000000800000000000000000000001000000000000020000080000000000000800000000000004000000000010000000000000000000000000000000004000000000000000000000000000000020000000022000000000000000000000000000000000000000000000000000800000000000000002000000000000000000000000000200000008000000000000000020000010000000000000000000000000000800000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + }, + { + "transactionHash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionIndex": "0x6", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "from": "0xb91212aaf24Db4E2d21137B9Ea2a6A18e75412e8", + "to": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "cumulativeGasUsed": "0x254a39", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0xF6513770645a858569CEA1A87210F16F7A9c9A34", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x000000000000000000000000b91212aaf24db4e2d21137b9ea2a6a18e75412e8", + "0x0000000000000000000000005a0fb32360aead818d5486fe311a88bc681a1de1" + ], + "data": "0x", + "blockHash": "0x9fb601b7ae4058696a1bd75a3236bde50b99ab6cd0cf785b6e612dc487dcfc13", + "blockNumber": "0x961565", + "transactionHash": "0x72df8e14c70d3a546236e6782ee455f1f2e5b99deeb367ce2918274d89cfebe7", + "transactionIndex": "0x6", + "logIndex": "0x8", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000002000100000004000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000004000000000000000000000000000000020000000002000000000020000000000000000000000000000000000000000000000000000002000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0xb2d05e18" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696845459, + "chain": 5, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-1696689350.json b/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-1696689350.json new file mode 100644 index 0000000..a48c524 --- /dev/null +++ b/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-1696689350.json @@ -0,0 +1,132 @@ +{ + "transactions": [ + { + "hash": "0x5514e398ace083197b20c735700fb1f232427b2e76806f352752c690fe11a45d", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": null, + "arguments": [ + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "gas": "0x2af249", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea2646970667358221220b77b8e521b60b6eee308b5639832beaa00cca8467b74185bd0cdb1b37ff42dc964736f6c63430008150033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x0", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9945811378a7f96d39cf772fd1b447ff9abe9aa9baefe2897d40bd0764d058f0", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x1", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9627703ce5807a788409235da16a2407212d35b6bc7e8c5b788b23aa6409a4c3", + "transactionType": "CALL", + "contractName": "FiatTokenProxy", + "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "gas": "0x1568f", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000003b022edecd65b63288704a6fa33a8b9185b5096b0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x2", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0x29365", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x3", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xda4a85f013f860c64f5a6c5551280c0032fad78b7b5005625176af9bf9541254", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x4", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0x5514e398ace083197b20c735700fb1f232427b2e76806f352752c690fe11a45d", + "0x9945811378a7f96d39cf772fd1b447ff9abe9aa9baefe2897d40bd0764d058f0", + "0x9627703ce5807a788409235da16a2407212d35b6bc7e8c5b788b23aa6409a4c3", + "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "0xda4a85f013f860c64f5a6c5551280c0032fad78b7b5005625176af9bf9541254" + ], + "returns": {}, + "timestamp": 1696689350, + "chain": 1, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-1696689363.json b/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-1696689363.json new file mode 100644 index 0000000..5d6bfc3 --- /dev/null +++ b/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-1696689363.json @@ -0,0 +1,315 @@ +{ + "transactions": [ + { + "hash": "0x5514e398ace083197b20c735700fb1f232427b2e76806f352752c690fe11a45d", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": null, + "arguments": [ + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "gas": "0x2af249", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea2646970667358221220b77b8e521b60b6eee308b5639832beaa00cca8467b74185bd0cdb1b37ff42dc964736f6c63430008150033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x0", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9945811378a7f96d39cf772fd1b447ff9abe9aa9baefe2897d40bd0764d058f0", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x1", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9627703ce5807a788409235da16a2407212d35b6bc7e8c5b788b23aa6409a4c3", + "transactionType": "CALL", + "contractName": "FiatTokenProxy", + "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "gas": "0x1568f", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000003b022edecd65b63288704a6fa33a8b9185b5096b0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x2", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0x29365", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x3", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xda4a85f013f860c64f5a6c5551280c0032fad78b7b5005625176af9bf9541254", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x4", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x5514e398ace083197b20c735700fb1f232427b2e76806f352752c690fe11a45d", + "transactionIndex": "0x9", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": null, + "cumulativeGasUsed": "0x332c7e", + "gasUsed": "0x210bbb", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "logs": [ + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472" + ], + "data": "0x", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x5514e398ace083197b20c735700fb1f232427b2e76806f352752c690fe11a45d", + "transactionIndex": "0x9", + "logIndex": "0x29", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000800002000000800000000000000000000000000000000400000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000004000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + }, + { + "transactionHash": "0x9945811378a7f96d39cf772fd1b447ff9abe9aa9baefe2897d40bd0764d058f0", + "transactionIndex": "0xa", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "cumulativeGasUsed": "0x33a276", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x9945811378a7f96d39cf772fd1b447ff9abe9aa9baefe2897d40bd0764d058f0", + "transactionIndex": "0xa", + "logIndex": "0x2a", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000800002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + }, + { + "transactionHash": "0x9627703ce5807a788409235da16a2407212d35b6bc7e8c5b788b23aa6409a4c3", + "transactionIndex": "0xb", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "cumulativeGasUsed": "0x348cb1", + "gasUsed": "0xea3b", + "contractAddress": null, + "logs": [ + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "0x0000000000000000000000003b022edecd65b63288704a6fa33a8b9185b5096b" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x9627703ce5807a788409235da16a2407212d35b6bc7e8c5b788b23aa6409a4c3", + "transactionIndex": "0xb", + "logIndex": "0x2b", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000200000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000080000000010000000000000000000000020000000000200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000010000004000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + }, + { + "transactionHash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionIndex": "0xc", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "cumulativeGasUsed": "0x366a15", + "gasUsed": "0x1dd64", + "contractAddress": null, + "logs": [ + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "0x0000000000000000000000003b022edecd65b63288704a6fa33a8b9185b5096b" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionIndex": "0xc", + "logIndex": "0x2c", + "removed": false + }, + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionIndex": "0xc", + "logIndex": "0x2d", + "removed": false + }, + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "0x00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionIndex": "0xc", + "logIndex": "0x2e", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000008000008000000004000000000000000000000000000000000000000020000000800002000000800000000000004000001000010000000000000000000000000000000000000000080000000010000000000000000000000000000000000200000000000000880000000000000000000000000000020000000000002000000000000000000000000000000000008020000000000000020000000000004000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + }, + { + "transactionHash": "0xda4a85f013f860c64f5a6c5551280c0032fad78b7b5005625176af9bf9541254", + "transactionIndex": "0xd", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "cumulativeGasUsed": "0x372516", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "0x00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca" + ], + "data": "0x", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0xda4a85f013f860c64f5a6c5551280c0032fad78b7b5005625176af9bf9541254", + "transactionIndex": "0xd", + "logIndex": "0x2f", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000800002000000000000800000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000020000000000000880000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696689363, + "chain": 1, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-latest.json b/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-latest.json new file mode 100644 index 0000000..5d6bfc3 --- /dev/null +++ b/broadcast/L1_USDC_DeployAmphorSyntheticVaultWithPermit.s.sol/1/run-latest.json @@ -0,0 +1,315 @@ +{ + "transactions": [ + { + "hash": "0x5514e398ace083197b20c735700fb1f232427b2e76806f352752c690fe11a45d", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": null, + "arguments": [ + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "Amphor Synthetic LP-IL Hedged (USDC)", + "ampr-LP-USD", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "gas": "0x2af249", + "value": "0x0", + "data": "0x60e06040523480156200001157600080fd5b506040516200282638038062002826833981016040819052620000349162000273565b83838383828260036200004883826200039f565b5060046200005782826200039f565b505050620000746200006e6200012360201b60201c565b62000127565b6006805460ff60a01b191690556001600160a01b03841660a081905260ff821660c0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620000d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000fb91906200046b565b60ff91011660805250506008805462ff00001916620100001790555062000490945050505050565b3390565b600680546001600160a01b0319169055620001428162000145565b50565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001bf57600080fd5b81516001600160401b0380821115620001dc57620001dc62000197565b604051601f8301601f19908116603f0116810190828211818310171562000207576200020762000197565b816040528381526020925086838588010111156200022457600080fd5b600091505b8382101562000248578582018301518183018401529082019062000229565b600093810190920192909252949350505050565b805160ff811681146200026e57600080fd5b919050565b600080600080608085870312156200028a57600080fd5b84516001600160a01b0381168114620002a257600080fd5b60208601519094506001600160401b0380821115620002c057600080fd5b620002ce88838901620001ad565b94506040870151915080821115620002e557600080fd5b50620002f487828801620001ad565b92505062000305606086016200025c565b905092959194509250565b600181811c908216806200032557607f821691505b6020821081036200034657634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039a57600081815260208120601f850160051c81016020861015620003755750805b601f850160051c820191505b81811015620003965782815560010162000381565b5050505b505050565b81516001600160401b03811115620003bb57620003bb62000197565b620003d381620003cc845462000310565b846200034c565b602080601f8311600181146200040b5760008415620003f25750858301515b600019600386901b1c1916600185901b17855562000396565b600085815260208120601f198616915b828110156200043c578886015182559484019460019091019084016200041b565b50858210156200045b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200047e57600080fd5b62000489826200025c565b9392505050565b60805160a05160c051612327620004ff600039600081816105250152818161107001526111da0152600081816103dc015281816107e0015281816108af01528181610d7f01528181610fe0015281816115ed0152818161168401526117d80152600061039501526123276000f3fe608060405234801561001057600080fd5b50600436106102bb5760003560e01c806379ba509711610182578063b460af94116100e9578063ce96cb77116100a2578063e30c39781161007c578063e30c397814610633578063eea2913214610644578063ef8b30f7146105d4578063f2fde38b1461065757600080fd5b8063ce96cb77146105fa578063d905777e1461060d578063dd62ed3e1461062057600080fd5b8063b460af94146105a6578063ba087652146105b9578063be9a6555146105cc578063c63d75b614610442578063c6e6f592146105d4578063ca1123c2146105e757600080fd5b806396b298c51161013b57806396b298c514610520578063a0bb22b414610547578063a457c2d71461055a578063a716cf4a1461056d578063a9059cbb14610580578063b3d7f6b91461059357600080fd5b806379ba5097146104d15780638456cb59146104d95780638da5cb5b146104e15780638e06aafc146104f257806394bf804d1461050557806395d89b411461051857600080fd5b806338d52e0f116102265780634cdad506116101df5780634cdad506146102f95780635c975abb146104685780636e553f651461047a57806370a082311461048d57806370a428a4146104b6578063715018a6146104c957600080fd5b806338d52e0f146103da57806339509351146104145780633ee3d6bc146104275780633f4ba83a1461043a578063402d267d146104425780634375d8cd1461045557600080fd5b80630ad24528116102785780630ad245281461034257806318160ddd1461035757806323b872dd1461035f5780633035106b14610372578063313ce5671461039357806332f289cf146103c757600080fd5b806301e1d114146102c05780630217631e146102db57806306fdde03146102e457806307a2d13a146102f9578063095ea7b31461030c5780630a28a4771461032f575b600080fd5b6102c861066a565b6040519081526020015b60405180910390f35b6102c860075481565b6102ec6106a0565b6040516102d29190611e50565b6102c8610307366004611e83565b610732565b61031f61031a366004611eb1565b610745565b60405190151581526020016102d2565b6102c861033d366004611e83565b61075d565b610355610350366004611e83565b61076a565b005b6002546102c8565b61031f61036d366004611edd565b61087f565b6008546103809061ffff1681565b60405161ffff90911681526020016102d2565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff90911681526020016102d2565b6103556103d5366004611f1e565b6108a5565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020016102d2565b61031f610422366004611eb1565b61097f565b6102c8610435366004611f3b565b6109a1565b6103556109e8565b6102c8610450366004611f1e565b6109fa565b60085461031f9062010000900460ff1681565b600654600160a01b900460ff1661031f565b6102c8610488366004611f62565b610a32565b6102c861049b366004611f1e565b6001600160a01b031660009081526020819052604090205490565b6102c86104c4366004611faa565b610a80565b610355610aa2565b610355610ab4565b610355610b2b565b6005546001600160a01b03166103fc565b6102c8610500366004611ff4565b610b3b565b6102c8610513366004611f62565b610b50565b6102ec610b9e565b6103b57f000000000000000000000000000000000000000000000000000000000000000081565b6102c8610555366004611faa565b610bad565b61031f610568366004611eb1565b610bc3565b6102c861057b366004611ff4565b610c49565b61031f61058e366004611eb1565b610c5e565b6102c86105a1366004611e83565b610c6c565b6102c86105b4366004612033565b610c79565b6102c86105c7366004612033565b610cc7565b610355610d15565b6102c86105e2366004611e83565b610dee565b6103556105f5366004612075565b610dfb565b6102c8610608366004611f1e565b610e7b565b6102c861061b366004611f1e565b610ebe565b6102c861062e366004612099565b610ef6565b6006546001600160a01b03166103fc565b6102c8610652366004611f3b565b610f21565b610355610665366004611f1e565b610f57565b60085460009062010000900460ff161561068b57610686610fc8565b905090565b600754610696610fc8565b61068691906120dd565b6060600380546106af906120f0565b80601f01602080910402602001604051908101604052809291908181526020018280546106db906120f0565b80156107285780601f106106fd57610100808354040283529160200191610728565b820191906000526020600020905b81548152906001019060200180831161070b57829003601f168201915b5050505050905090565b600061073f826000611053565b92915050565b6000336107538185856110ac565b5060019392505050565b600061073f8260016111d0565b610772611220565b60085462010000900460ff161561079c5760405163cf9c0f0960e01b815260040160405180910390fd5b6000600754821180156107b4575060085461ffff1615155b156107db57600754600854908303906107d790829061ffff16612710600161127a565b9150505b6108107f0000000000000000000000000000000000000000000000000000000000000000333061080b8587612124565b6112d5565b6008805462ff000019166201000017905560075442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461085360025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600755565b60003361088d858285611346565b6108988585856113ba565b60019150505b9392505050565b6108ad611220565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b0316036108ff57604051634b51153360e11b815260040160405180910390fd5b61097c336040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610947573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096b9190612137565b6001600160a01b038416919061155e565b50565b6000336107538185856109928383610ef6565b61099c91906120dd565b6110ac565b6000806109ae8585610b50565b9050828111156109e057838184604051632e18fdcb60e01b81526004016109d793929190612150565b60405180910390fd5b949350505050565b6109f0611220565b6109f8611593565b565b60085460009062010000900460ff161580610a1e5750600654600160a01b900460ff165b610a2a5760001961073f565b600092915050565b600080610a3e836109fa565b905080841115610a6757828482604051633c8097d960e11b81526004016109d793929190612150565b6000610a7285610dee565b90506109e0338587846115e8565b6000610a8e335b308461167a565b610a99858585610f21565b95945050505050565b610aaa611220565b6109f86000611752565b60065433906001600160a01b03168114610b225760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016109d7565b61097c81611752565b610b33611220565b6109f861176b565b6000610b4633610a87565b6109e08484610a32565b600080610b5c836109fa565b905080841115610b855782848260405163284ff66760e01b81526004016109d793929190612150565b6000610b9085610c6c565b90506109e0338583886115e8565b6060600480546106af906120f0565b6000610bb833610a87565b610a998585856109a1565b60003381610bd18286610ef6565b905083811015610c315760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b60648201526084016109d7565b610c3e82868684036110ac565b506001949350505050565b6000610c5433610a87565b6109e08484610b50565b6000336107538185856113ba565b600061073f826001611053565b600080610c8583610e7b565b905080851115610cae57828582604051633fa733bb60e21b81526004016109d793929190612150565b6000610cb98661075d565b9050610a99858588846117ae565b600080610cd383610ebe565b905080851115610cfc57828582604051632e52afbb60e21b81526004016109d793929190612150565b6000610d0786610732565b9050610a99858583896117ae565b610d1d611220565b60085462010000900460ff16610d4657604051635adc30c160e11b815260040160405180910390fd5b610d4e610fc8565b6007556008805462ff000019169055610da6610d726005546001600160a01b031690565b6007546001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919061155e565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600754610dd460025490565b6040805192835260208301919091520160405180910390a2565b600061073f8260006111d0565b610e03611220565b610bb88161ffff161115610e2a5760405163192069c360e31b815260040160405180910390fd5b6008805461ffff191661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b60085460009062010000900460ff16610e9557600061073f565b61073f610eb7836001600160a01b031660009081526020819052604090205490565b6000611053565b60085460009062010000900460ff16610ed857600061073f565b6001600160a01b03821660009081526020819052604090205461073f565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600080610f2e8585610a32565b9050828110156109e05783818460405163d032c98360e01b81526004016109d793929190612150565b610f5f611220565b600680546001600160a01b0383166001600160a01b03199091168117909155610f906005546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa15801561102f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106869190612137565b600061089e61106061066a565b61106b9060016120dd565b6110967f0000000000000000000000000000000000000000000000000000000000000000600a612255565b6002546110a391906120dd565b8591908561127a565b6001600160a01b03831661110e5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b60648201526084016109d7565b6001600160a01b03821661116f5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b60648201526084016109d7565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b600061089e6112007f0000000000000000000000000000000000000000000000000000000000000000600a612255565b60025461120d91906120dd565b61121561066a565b6110a39060016120dd565b6005546001600160a01b031633146109f85760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016109d7565b60008061128886868661186a565b9050600183600281111561129e5761129e612264565b1480156112bb5750600084806112b6576112b661227a565b868809115b15610a99576112cb6001826120dd565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526113409085906323b872dd60e01b906084015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611954565b50505050565b60006113528484610ef6565b9050600019811461134057818110156113ad5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e636500000060448201526064016109d7565b61134084848484036110ac565b6001600160a01b03831661141e5760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b60648201526084016109d7565b6001600160a01b0382166114805760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b60648201526084016109d7565b6001600160a01b038316600090815260208190526040902054818110156114f85760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b60648201526084016109d7565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3611340565b6040516001600160a01b03831660248201526044810182905261158e90849063a9059cbb60e01b90606401611309565b505050565b61159b611a29565b6006805460ff60a01b191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b6116147f00000000000000000000000000000000000000000000000000000000000000008530856112d5565b61161e8382611a79565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7848460405161166c929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf8484843560208601356116c26060880160408901612290565b6040516001600160e01b031960e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b15801561173557600080fd5b505af1158015611749573d6000803e3d6000fd5b50505050505050565b600680546001600160a01b031916905561097c81611b38565b611773611b8a565b6006805460ff60a01b1916600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586115cb3390565b336001600160a01b038416146117c9576117c9833383611346565b6117d38382611bd7565b6117fe7f0000000000000000000000000000000000000000000000000000000000000000858461155e565b826001600160a01b0316846001600160a01b03166118193390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db858560405161185c929190918252602082015260400190565b60405180910390a450505050565b60008080600019858709858702925082811083820303915050806000036118a45783828161189a5761189a61227a565b049250505061089e565b8084116118eb5760405162461bcd60e51b81526020600482015260156024820152744d6174683a206d756c446976206f766572666c6f7760581b60448201526064016109d7565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006119a9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d099092919063ffffffff16565b90508051600014806119ca5750808060200190518101906119ca91906122b3565b61158e5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016109d7565b600654600160a01b900460ff166109f85760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016109d7565b6001600160a01b038216611acf5760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f20616464726573730060448201526064016109d7565b8060026000828254611ae191906120dd565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600580546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600654600160a01b900460ff16156109f85760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b60448201526064016109d7565b6001600160a01b038216611c375760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b60648201526084016109d7565b6001600160a01b03821660009081526020819052604090205481811015611cab5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b60648201526084016109d7565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60606109e0848460008585600080866001600160a01b03168587604051611d3091906122d5565b60006040518083038185875af1925050503d8060008114611d6d576040519150601f19603f3d011682016040523d82523d6000602084013e611d72565b606091505b5091509150611d8387838387611d8e565b979650505050505050565b60608315611dfd578251600003611df6576001600160a01b0385163b611df65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016109d7565b50816109e0565b6109e08383815115611e125781518083602001fd5b8060405162461bcd60e51b81526004016109d79190611e50565b60005b83811015611e47578181015183820152602001611e2f565b50506000910152565b6020815260008251806020840152611e6f816040850160208701611e2c565b601f01601f19169190910160400192915050565b600060208284031215611e9557600080fd5b5035919050565b6001600160a01b038116811461097c57600080fd5b60008060408385031215611ec457600080fd5b8235611ecf81611e9c565b946020939093013593505050565b600080600060608486031215611ef257600080fd5b8335611efd81611e9c565b92506020840135611f0d81611e9c565b929592945050506040919091013590565b600060208284031215611f3057600080fd5b813561089e81611e9c565b600080600060608486031215611f5057600080fd5b833592506020840135611f0d81611e9c565b60008060408385031215611f7557600080fd5b823591506020830135611f8781611e9c565b809150509250929050565b600060a08284031215611fa457600080fd5b50919050565b6000806000806101008587031215611fc157600080fd5b843593506020850135611fd381611e9c565b925060408501359150611fe98660608701611f92565b905092959194509250565b600080600060e0848603121561200957600080fd5b83359250602084013561201b81611e9c565b915061202a8560408601611f92565b90509250925092565b60008060006060848603121561204857600080fd5b83359250602084013561205a81611e9c565b9150604084013561206a81611e9c565b809150509250925092565b60006020828403121561208757600080fd5b813561ffff8116811461089e57600080fd5b600080604083850312156120ac57600080fd5b82356120b781611e9c565b91506020830135611f8781611e9c565b634e487b7160e01b600052601160045260246000fd5b8082018082111561073f5761073f6120c7565b600181811c9082168061210457607f821691505b602082108103611fa457634e487b7160e01b600052602260045260246000fd5b8181038181111561073f5761073f6120c7565b60006020828403121561214957600080fd5b5051919050565b6001600160a01b039390931683526020830191909152604082015260600190565b600181815b808511156121ac578160001904821115612192576121926120c7565b8085161561219f57918102915b93841c9390800290612176565b509250929050565b6000826121c35750600161073f565b816121d05750600061073f565b81600181146121e657600281146121f05761220c565b600191505061073f565b60ff841115612201576122016120c7565b50506001821b61073f565b5060208310610133831016604e8410600b841016171561222f575081810a61073f565b6122398383612171565b806000190482111561224d5761224d6120c7565b029392505050565b600061089e60ff8416836121b4565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6000602082840312156122a257600080fd5b813560ff8116811461089e57600080fd5b6000602082840312156122c557600080fd5b8151801515811461089e57600080fd5b600082516122e7818460208701611e2c565b919091019291505056fea2646970667358221220b77b8e521b60b6eee308b5639832beaa00cca8467b74185bd0cdb1b37ff42dc964736f6c63430008150033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000024416d70686f722053796e746865746963204c502d494c204865646765642028555344432900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d555344000000000000000000000000000000000000000000", + "nonce": "0x0", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9945811378a7f96d39cf772fd1b447ff9abe9aa9baefe2897d40bd0764d058f0", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0xa2f1", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x1", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x9627703ce5807a788409235da16a2407212d35b6bc7e8c5b788b23aa6409a4c3", + "transactionType": "CALL", + "contractName": "FiatTokenProxy", + "contractAddress": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "function": "approve(address,uint256):(bool)", + "arguments": [ + "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "100000000" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "gas": "0x1568f", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000003b022edecd65b63288704a6fa33a8b9185b5096b0000000000000000000000000000000000000000000000000000000005f5e100", + "nonce": "0x2", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "deposit(uint256,address):(uint256)", + "arguments": [ + "100000000", + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0x29365", + "value": "0x0", + "data": "0x6e553f650000000000000000000000000000000000000000000000000000000005f5e10000000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x3", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xda4a85f013f860c64f5a6c5551280c0032fad78b7b5005625176af9bf9541254", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x6cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "to": "0x3b022edecd65b63288704a6fa33a8b9185b5096b", + "gas": "0x1117e", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x4", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "transactionHash": "0x5514e398ace083197b20c735700fb1f232427b2e76806f352752c690fe11a45d", + "transactionIndex": "0x9", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": null, + "cumulativeGasUsed": "0x332c7e", + "gasUsed": "0x210bbb", + "contractAddress": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "logs": [ + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472" + ], + "data": "0x", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x5514e398ace083197b20c735700fb1f232427b2e76806f352752c690fe11a45d", + "transactionIndex": "0x9", + "logIndex": "0x29", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000800002000000800000000000000000000000000000000400000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000004000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + }, + { + "transactionHash": "0x9945811378a7f96d39cf772fd1b447ff9abe9aa9baefe2897d40bd0764d058f0", + "transactionIndex": "0xa", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "cumulativeGasUsed": "0x33a276", + "gasUsed": "0x75f8", + "contractAddress": null, + "logs": [ + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0x650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220" + ], + "data": "0x00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000007d0", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x9945811378a7f96d39cf772fd1b447ff9abe9aa9baefe2897d40bd0764d058f0", + "transactionIndex": "0xa", + "logIndex": "0x2a", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000800002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + }, + { + "transactionHash": "0x9627703ce5807a788409235da16a2407212d35b6bc7e8c5b788b23aa6409a4c3", + "transactionIndex": "0xb", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "cumulativeGasUsed": "0x348cb1", + "gasUsed": "0xea3b", + "contractAddress": null, + "logs": [ + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "0x0000000000000000000000003b022edecd65b63288704a6fa33a8b9185b5096b" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x9627703ce5807a788409235da16a2407212d35b6bc7e8c5b788b23aa6409a4c3", + "transactionIndex": "0xb", + "logIndex": "0x2b", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000200000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000080000000010000000000000000000000020000000000200000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000010000004000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + }, + { + "transactionHash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionIndex": "0xc", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "cumulativeGasUsed": "0x366a15", + "gasUsed": "0x1dd64", + "contractAddress": null, + "logs": [ + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "0x0000000000000000000000003b022edecd65b63288704a6fa33a8b9185b5096b" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e100", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionIndex": "0xc", + "logIndex": "0x2c", + "removed": false + }, + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca" + ], + "data": "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionIndex": "0xc", + "logIndex": "0x2d", + "removed": false + }, + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0xdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d7", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "0x00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000005f5e1000000000000000000000000000000000000000000000000056bc75e2d63100000", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0x3a37eefebd58ed738cdf589952ae0187d779a4ff9f36435934a808a5626b1f3e", + "transactionIndex": "0xc", + "logIndex": "0x2e", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000008000008000000004000000000000000000000000000000000000000020000000800002000000800000000000004000001000010000000000000000000000000000000000000000080000000010000000000000000000000000000000000200000000000000880000000000000000000000000000020000000000002000000000000000000000000000000000008020000000000000020000000000004000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + }, + { + "transactionHash": "0xda4a85f013f860c64f5a6c5551280c0032fad78b7b5005625176af9bf9541254", + "transactionIndex": "0xd", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "from": "0x6cAb4513C2459cfCf75Bb247F6cC4C86B6d9b472", + "to": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "cumulativeGasUsed": "0x372516", + "gasUsed": "0xbb01", + "contractAddress": null, + "logs": [ + { + "address": "0x3b022EdECD65b63288704a6fa33A8B9185b5096b", + "topics": [ + "0x38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e22700", + "0x0000000000000000000000006cab4513c2459cfcf75bb247f6cc4c86b6d9b472", + "0x00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca" + ], + "data": "0x", + "blockHash": "0x042b24c8496545dc73627572b71acd7dfc69eb9dfba00b0627713eda940533fc", + "blockNumber": "0x117396a", + "transactionHash": "0xda4a85f013f860c64f5a6c5551280c0032fad78b7b5005625176af9bf9541254", + "transactionIndex": "0xd", + "logIndex": "0x2f", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000800002000000000000800000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000020000000000000880000000000000000000000000000020000000002000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "effectiveGasPrice": "0x26e9c7bc7" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1696689363, + "chain": 1, + "multi": false, + "commit": "f67f0e3" +} \ No newline at end of file diff --git a/broadcast/WSTETH_DeployAmphorSyntheticVault.s.sol/1/run-1699551295.json b/broadcast/WSTETH_DeployAmphorSyntheticVault.s.sol/1/run-1699551295.json new file mode 100644 index 0000000..3a351fd --- /dev/null +++ b/broadcast/WSTETH_DeployAmphorSyntheticVault.s.sol/1/run-1699551295.json @@ -0,0 +1,131 @@ +{ + "transactions": [ + { + "hash": "0xbc6423ddb863dae808015392d62a431785281b1479739d313c80cc365ceed594", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "function": null, + "arguments": [ + "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "Amphor Synthetic LP-IL Hedged (WSTETH)", + "ampr-LP-ETH", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "gas": "0x3bcd88", + "value": "0x0", + "data": "0x6101c06040523480156200001257600080fd5b5060405162003883380380620038838339810160408190526200003591620003c8565b838383838280604051806040016040528060018152602001603160f81b81525085858160039081620000689190620004f4565b506004620000778282620004f4565b506200008991508390506005620001ef565b610120526200009a816006620001ef565b61014052815160208084019190912060e052815190820120610100524660a0526200012860e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506200013d3362000228565b600a805460ff60a01b191690556001600160a01b03841661018081905260ff82166101a0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620001a0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c69190620005c0565b60ff910116610160525050600c805462ff0000191662010000179055506200063f945050505050565b60006020835110156200020f57620002078362000246565b905062000222565b816200021c8482620004f4565b5060ff90505b92915050565b600a80546001600160a01b0319169055620002438162000292565b50565b600080829050601f815111156200027d578260405163305a27a960e01b8152600401620002749190620005e5565b60405180910390fd5b80516200028a826200061a565b179392505050565b600980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000317578181015183820152602001620002fd565b50506000910152565b600082601f8301126200033257600080fd5b81516001600160401b03808211156200034f576200034f620002e4565b604051601f8301601f19908116603f011681019082821181831017156200037a576200037a620002e4565b816040528381528660208588010111156200039457600080fd5b620003a7846020830160208901620002fa565b9695505050505050565b805160ff81168114620003c357600080fd5b919050565b60008060008060808587031215620003df57600080fd5b84516001600160a01b0381168114620003f757600080fd5b60208601519094506001600160401b03808211156200041557600080fd5b620004238883890162000320565b945060408701519150808211156200043a57600080fd5b50620004498782880162000320565b9250506200045a60608601620003b1565b905092959194509250565b600181811c908216806200047a57607f821691505b6020821081036200049b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004ef57600081815260208120601f850160051c81016020861015620004ca5750805b601f850160051c820191505b81811015620004eb57828155600101620004d6565b5050505b505050565b81516001600160401b03811115620005105762000510620002e4565b620005288162000521845462000465565b84620004a1565b602080601f831160018114620005605760008415620005475750858301515b600019600386901b1c1916600185901b178555620004eb565b600085815260208120601f198616915b82811015620005915788860151825594840194600190910190840162000570565b5085821015620005b05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215620005d357600080fd5b620005de82620003b1565b9392505050565b602081526000825180602084015262000606816040850160208701620002fa565b601f01601f19169190910160400192915050565b805160208083015191908110156200049b5760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051613189620006fa6000396000818161060201528181611668015261180601526000818161048b01528181610922015281816109f101528181611111015281816115d801528181611e1f01528181611eb601526120f50152600061043c01526000610d9501526000610d6a01526000611d5901526000611d3101526000611c8c01526000611cb601526000611ce001526131896000f3fe608060405234801561001057600080fd5b50600436106103625760003560e01c80638456cb59116101c8578063ba08765211610104578063d505accf116100a2578063e30c39781161007c578063e30c39781461075c578063eea291321461076d578063ef8b30f7146106c4578063f2fde38b1461078057600080fd5b8063d505accf146106fd578063d905777e14610710578063dd62ed3e1461072357600080fd5b8063c63d75b6116100de578063c63d75b6146104f1578063c6e6f592146106c4578063ca1123c2146106d7578063ce96cb77146106ea57600080fd5b8063ba08765214610696578063be9a6555146106a9578063c06e6732146106b157600080fd5b806396b298c511610171578063a716cf4a1161014b578063a716cf4a1461064a578063a9059cbb1461065d578063b3d7f6b914610670578063b460af941461068357600080fd5b806396b298c5146105fd578063a0bb22b414610624578063a457c2d71461063757600080fd5b80638e06aafc116101a25780638e06aafc146105cf57806394bf804d146105e257806395d89b41146105f557600080fd5b80638456cb591461059b57806384b0196e146105a35780638da5cb5b146105be57600080fd5b806338d52e0f116102a25780635c975abb1161024057806370a428a41161021a57806370a428a414610565578063715018a61461057857806379ba5097146105805780637ecebe001461058857600080fd5b80635c975abb146105175780636e553f651461052957806370a082311461053c57600080fd5b80633f4ba83a1161027c5780633f4ba83a146104e9578063402d267d146104f15780634375d8cd146105045780634cdad506146103a057600080fd5b806338d52e0f1461048957806339509351146104c35780633ee3d6bc146104d657600080fd5b80630ad245281161030f5780633035106b116102e95780633035106b14610419578063313ce5671461043a57806332f289cf1461046e5780633644e5151461048157600080fd5b80630ad24528146103e957806318160ddd146103fe57806323b872dd1461040657600080fd5b806307a2d13a1161034057806307a2d13a146103a0578063095ea7b3146103b35780630a28a477146103d657600080fd5b806301e1d114146103675780630217631e1461038257806306fdde031461038b575b600080fd5b61036f610793565b6040519081526020015b60405180910390f35b61036f600b5481565b6103936107c9565b6040516103799190612bcb565b61036f6103ae366004612bde565b61085b565b6103c66103c1366004612c0c565b61086e565b6040519015158152602001610379565b61036f6103e4366004612bde565b610886565b6103fc6103f7366004612bde565b610893565b005b60025461036f565b6103c6610414366004612c38565b6109c1565b600c546104279061ffff1681565b60405161ffff9091168152602001610379565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff9091168152602001610379565b6103fc61047c366004612c79565b6109e7565b61036f610af3565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610379565b6103c66104d1366004612c0c565b610afd565b61036f6104e4366004612c96565b610b3c565b6103fc610bab565b61036f6104ff366004612c79565b610bbd565b600c546103c69062010000900460ff1681565b600a54600160a01b900460ff166103c6565b61036f610537366004612cbd565b610bf5565b61036f61054a366004612c79565b6001600160a01b031660009081526020819052604090205490565b61036f610573366004612cff565b610c6f565b6103fc610c91565b6103fc610ca3565b61036f610596366004612c79565b610d2e565b6103fc610d4c565b6105ab610d5c565b6040516103799796959493929190612d49565b6009546001600160a01b03166104ab565b61036f6105dd366004612dfb565b610e01565b61036f6105f0366004612cbd565b610e16565b610393610e90565b61045c7f000000000000000000000000000000000000000000000000000000000000000081565b61036f610632366004612cff565b610e9f565b6103c6610645366004612c0c565b610eb5565b61036f610658366004612dfb565b610f6a565b6103c661066b366004612c0c565b610f7f565b61036f61067e366004612bde565b610f8d565b61036f610691366004612e3a565b610f9a565b61036f6106a4366004612e3a565b611014565b6103fc61108e565b6103fc6106bf366004612bde565b611180565b61036f6106d2366004612bde565b611225565b6103fc6106e5366004612e7c565b611232565b61036f6106f8366004612c79565b6112e8565b6103fc61070b366004612eb6565b61132b565b61036f61071e366004612c79565b61148f565b61036f610731366004612f24565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600a546001600160a01b03166104ab565b61036f61077b366004612c96565b6114c7565b6103fc61078e366004612c79565b611529565b600c5460009062010000900460ff16156107b4576107af6115a7565b905090565b600b546107bf6115a7565b6107af9190612f68565b6060600380546107d890612f7b565b80601f016020809104026020016040519081016040528092919081815260200182805461080490612f7b565b80156108515780601f1061082657610100808354040283529160200191610851565b820191906000526020600020905b81548152906001019060200180831161083457829003601f168201915b5050505050905090565b600061086882600061164b565b92915050565b60003361087c8185856116a4565b5060019392505050565b60006108688260016117fc565b61089b61184c565b600c5462010000900460ff16156108de576040517fcf9c0f0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600b54821180156108f65750600c5461ffff1615155b1561091d57600b54600c549083039061091990829061ffff1661271060016118a6565b9150505b6109527f0000000000000000000000000000000000000000000000000000000000000000333061094d8587612faf565b611901565b600c805462ff0000191662010000179055600b5442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461099560025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600b55565b6000336109cf8582856119b8565b6109da858585611a44565b60019150505b9392505050565b6109ef61184c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031603610a5a576040517f96a22a6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610af0336040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610abb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610adf9190612fc2565b6001600160a01b0384169190611c31565b50565b60006107af611c7f565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919061087c9082908690610b37908790612f68565b6116a4565b600080610b498585610e16565b905082811115610ba3576040517f2e18fdcb0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101829052604481018490526064015b60405180910390fd5b949350505050565b610bb361184c565b610bbb611daa565b565b600c5460009062010000900460ff161580610be15750600a54600160a01b900460ff165b610bed57600019610868565b600092915050565b600080610c0183610bbd565b905080841115610c56576040517f79012fb20000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810185905260448101829052606401610b9a565b6000610c6185611225565b9050610ba333858784611e1a565b6000610c7d335b3084611eac565b610c888585856114c7565b95945050505050565b610c9961184c565b610bbb6000611f9c565b600a5433906001600160a01b03168114610d255760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152608401610b9a565b610af081611f9c565b6001600160a01b038116600090815260076020526040812054610868565b610d5461184c565b610bbb611fc2565b600060608082808083610d907f00000000000000000000000000000000000000000000000000000000000000006005612020565b610dbb7f00000000000000000000000000000000000000000000000000000000000000006006612020565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b6000610e0c33610c76565b610ba38484610bf5565b600080610e2283610bbd565b905080841115610e77576040517f284ff6670000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810185905260448101829052606401610b9a565b6000610e8285610f8d565b9050610ba333858388611e1a565b6060600480546107d890612f7b565b6000610eaa33610c76565b610c88858585610b3c565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015610f525760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610b9a565b610f5f82868684036116a4565b506001949350505050565b6000610f7533610c76565b610ba38484610e16565b60003361087c818585611a44565b600061086882600161164b565b600080610fa6836112e8565b905080851115610ffb576040517ffe9cceec0000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810186905260448101829052606401610b9a565b600061100686610886565b9050610c88858588846120cb565b6000806110208361148f565b905080851115611075576040517fb94abeec0000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810186905260448101829052606401610b9a565b60006110808661085b565b9050610c88858583896120cb565b61109661184c565b600c5462010000900460ff166110d8576040517fb5b8618200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110e06115a7565b600b55600c805462ff0000191690556111386111046009546001600160a01b031690565b600b546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190611c31565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600b5461116660025490565b6040805192835260208301919091520160405180910390a2565b61118861184c565b427f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb600b548360006111b960025490565b60408051948552602085019390935291830152606082015260800160405180910390a2427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600b5461120a60025490565b6040805192835260208301919091520160405180910390a250565b60006108688260006117fc565b61123a61184c565b610bb88161ffff16111561127a576040517fc9034e1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b600c5460009062010000900460ff16611302576000610868565b610868611324836001600160a01b031660009081526020819052604090205490565b600061164b565b8342111561137b5760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610b9a565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886113aa8c612187565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000611405826121af565b90506000611415828787876121f7565b9050896001600160a01b0316816001600160a01b0316146114785760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610b9a565b6114838a8a8a6116a4565b50505050505050505050565b600c5460009062010000900460ff166114a9576000610868565b6001600160a01b038216600090815260208190526040902054610868565b6000806114d48585610bf5565b905082811015610ba3576040517fd032c9830000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024810182905260448101849052606401610b9a565b61153161184c565b600a80546001600160a01b03831673ffffffffffffffffffffffffffffffffffffffff19909116811790915561156f6009546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611627573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107af9190612fc2565b60006109e0611658610793565b611663906001612f68565b61168e7f0000000000000000000000000000000000000000000000000000000000000000600a6130bf565b60025461169b9190612f68565b859190856118a6565b6001600160a01b03831661171f5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b03821661179b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006109e061182c7f0000000000000000000000000000000000000000000000000000000000000000600a6130bf565b6002546118399190612f68565b611841610793565b61169b906001612f68565b6009546001600160a01b03163314610bbb5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b9a565b6000806118b486868661221f565b905060018360028111156118ca576118ca6130ce565b1480156118e75750600084806118e2576118e26130e4565b868809115b15610c88576118f7600182612f68565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526119b29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612311565b50505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146119b25781811015611a375760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610b9a565b6119b284848484036116a4565b6001600160a01b038316611ac05760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b038216611b3c5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b03831660009081526020819052604090205481811015611bcb5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36119b2565b6040516001600160a01b038316602482015260448101829052611c7a9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161194e565b505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015611cd857507f000000000000000000000000000000000000000000000000000000000000000046145b15611d0257507f000000000000000000000000000000000000000000000000000000000000000090565b6107af604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b611db26123f9565b600a80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b611e467f0000000000000000000000000000000000000000000000000000000000000000853085611901565b611e508382612452565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78484604051611e9e929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf848484356020860135611ef460608801604089016130fa565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b158015611f7f57600080fd5b505af1158015611f93573d6000803e3d6000fd5b50505050505050565b600a805473ffffffffffffffffffffffffffffffffffffffff19169055610af081612511565b611fca612570565b600a80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611dfd3390565b606060ff831461203a57612033836125ca565b9050610868565b81805461204690612f7b565b80601f016020809104026020016040519081016040528092919081815260200182805461207290612f7b565b80156120bf5780601f10612094576101008083540402835291602001916120bf565b820191906000526020600020905b8154815290600101906020018083116120a257829003601f168201915b50505050509050610868565b336001600160a01b038416146120e6576120e68333836119b8565b6120f08382612609565b61211b7f00000000000000000000000000000000000000000000000000000000000000008584611c31565b826001600160a01b0316846001600160a01b03166121363390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051612179929190918252602082015260400190565b60405180910390a450505050565b6001600160a01b03811660009081526007602052604090208054600181018255905b50919050565b60006108686121bc611c7f565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600080600061220887878787612772565b9150915061221581612836565b5095945050505050565b60008080600019858709858702925082811083820303915050806000036122595783828161224f5761224f6130e4565b04925050506109e0565b8084116122a85760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152606401610b9a565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000612366826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661299b9092919063ffffffff16565b90508051600014806123875750808060200190518101906123879190613115565b611c7a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b9a565b600a54600160a01b900460ff16610bbb5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b9a565b6001600160a01b0382166124a85760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610b9a565b80600260008282546124ba9190612f68565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600980546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600a54600160a01b900460ff1615610bbb5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b9a565b606060006125d7836129aa565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6001600160a01b0382166126855760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b038216600090815260208190526040902054818110156127145760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156127a9575060009050600361282d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156127fd573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166128265760006001925092505061282d565b9150600090505b94509492505050565b600081600481111561284a5761284a6130ce565b036128525750565b6001816004811115612866576128666130ce565b036128b35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b9a565b60028160048111156128c7576128c76130ce565b036129145760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b9a565b6003816004811115612928576129286130ce565b03610af05760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6060610ba384846000856129eb565b600060ff8216601f811115610868576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082471015612a635760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b9a565b600080866001600160a01b03168587604051612a7f9190613137565b60006040518083038185875af1925050503d8060008114612abc576040519150601f19603f3d011682016040523d82523d6000602084013e612ac1565b606091505b5091509150612ad287838387612add565b979650505050505050565b60608315612b4c578251600003612b45576001600160a01b0385163b612b455760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b9a565b5081610ba3565b610ba38383815115612b615781518083602001fd5b8060405162461bcd60e51b8152600401610b9a9190612bcb565b60005b83811015612b96578181015183820152602001612b7e565b50506000910152565b60008151808452612bb7816020860160208601612b7b565b601f01601f19169290920160200192915050565b6020815260006109e06020830184612b9f565b600060208284031215612bf057600080fd5b5035919050565b6001600160a01b0381168114610af057600080fd5b60008060408385031215612c1f57600080fd5b8235612c2a81612bf7565b946020939093013593505050565b600080600060608486031215612c4d57600080fd5b8335612c5881612bf7565b92506020840135612c6881612bf7565b929592945050506040919091013590565b600060208284031215612c8b57600080fd5b81356109e081612bf7565b600080600060608486031215612cab57600080fd5b833592506020840135612c6881612bf7565b60008060408385031215612cd057600080fd5b823591506020830135612ce281612bf7565b809150509250929050565b600060a082840312156121a957600080fd5b6000806000806101008587031215612d1657600080fd5b843593506020850135612d2881612bf7565b925060408501359150612d3e8660608701612ced565b905092959194509250565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e081840152612d8560e084018a612b9f565b8381036040850152612d97818a612b9f565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015612de957835183529284019291840191600101612dcd565b50909c9b505050505050505050505050565b600080600060e08486031215612e1057600080fd5b833592506020840135612e2281612bf7565b9150612e318560408601612ced565b90509250925092565b600080600060608486031215612e4f57600080fd5b833592506020840135612e6181612bf7565b91506040840135612e7181612bf7565b809150509250925092565b600060208284031215612e8e57600080fd5b813561ffff811681146109e057600080fd5b803560ff81168114612eb157600080fd5b919050565b600080600080600080600060e0888a031215612ed157600080fd5b8735612edc81612bf7565b96506020880135612eec81612bf7565b95506040880135945060608801359350612f0860808901612ea0565b925060a0880135915060c0880135905092959891949750929550565b60008060408385031215612f3757600080fd5b8235612f4281612bf7565b91506020830135612ce281612bf7565b634e487b7160e01b600052601160045260246000fd5b8082018082111561086857610868612f52565b600181811c90821680612f8f57607f821691505b6020821081036121a957634e487b7160e01b600052602260045260246000fd5b8181038181111561086857610868612f52565b600060208284031215612fd457600080fd5b5051919050565b600181815b80851115613016578160001904821115612ffc57612ffc612f52565b8085161561300957918102915b93841c9390800290612fe0565b509250929050565b60008261302d57506001610868565b8161303a57506000610868565b8160018114613050576002811461305a57613076565b6001915050610868565b60ff84111561306b5761306b612f52565b50506001821b610868565b5060208310610133831016604e8410600b8410161715613099575081810a610868565b6130a38383612fdb565b80600019048211156130b7576130b7612f52565b029392505050565b60006109e060ff84168361301e565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60006020828403121561310c57600080fd5b6109e082612ea0565b60006020828403121561312757600080fd5b815180151581146109e057600080fd5b60008251613149818460208701612b7b565b919091019291505056fea2646970667358221220a6e02a37c989ba80fd1f4c202e2e69bbcc2d75b94341e52daad9bc5d5e954af664736f6c634300081300330000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000026416d70686f722053796e746865746963204c502d494c204865646765642028575354455448290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d455448000000000000000000000000000000000000000000", + "nonce": "0x1", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdd8b0945300f1b8ea0b2ab6d6d729f9ccdbf09e365f0b5c16559d07dc8b20878", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0x2791eb5807d69fe10c02eed6b4dc12bac0701744", + "gas": "0xac42", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x2", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x393086158f0bc8a43e3c1b7542c8ae66e246c1c9c6ecc9509d762c22a37be2dc", + "transactionType": "CALL", + "contractName": "WstETH", + "contractAddress": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "function": "approve(address,uint256)", + "arguments": [ + "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "100000000000000000" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", + "gas": "0xf95b", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744000000000000000000000000000000000000000000000000016345785d8a0000", + "nonce": "0x3", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x76a7672acaa2bf55ea36bf9130a0eb866196f296c9e2911cb6736898eaf0bf56", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "function": "deposit(uint256,address)", + "arguments": [ + "100000000000000000", + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0x2791eb5807d69fe10c02eed6b4dc12bac0701744", + "gas": "0x28a73", + "value": "0x0", + "data": "0x6e553f65000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x4", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0x2791eb5807d69fe10c02eed6b4dc12bac0701744", + "gas": "0x1023b", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x5", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xbc6423ddb863dae808015392d62a431785281b1479739d313c80cc365ceed594", + "0xdd8b0945300f1b8ea0b2ab6d6d729f9ccdbf09e365f0b5c16559d07dc8b20878", + "0x393086158f0bc8a43e3c1b7542c8ae66e246c1c9c6ecc9509d762c22a37be2dc", + "0x76a7672acaa2bf55ea36bf9130a0eb866196f296c9e2911cb6736898eaf0bf56" + ], + "returns": {}, + "timestamp": 1699551295, + "chain": 1, + "multi": false, + "commit": "4e2ce73" +} \ No newline at end of file diff --git a/broadcast/WSTETH_DeployAmphorSyntheticVault.s.sol/1/run-latest.json b/broadcast/WSTETH_DeployAmphorSyntheticVault.s.sol/1/run-latest.json new file mode 100644 index 0000000..3a351fd --- /dev/null +++ b/broadcast/WSTETH_DeployAmphorSyntheticVault.s.sol/1/run-latest.json @@ -0,0 +1,131 @@ +{ + "transactions": [ + { + "hash": "0xbc6423ddb863dae808015392d62a431785281b1479739d313c80cc365ceed594", + "transactionType": "CREATE", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "function": null, + "arguments": [ + "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "Amphor Synthetic LP-IL Hedged (WSTETH)", + "ampr-LP-ETH", + "12" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "gas": "0x3bcd88", + "value": "0x0", + "data": "0x6101c06040523480156200001257600080fd5b5060405162003883380380620038838339810160408190526200003591620003c8565b838383838280604051806040016040528060018152602001603160f81b81525085858160039081620000689190620004f4565b506004620000778282620004f4565b506200008991508390506005620001ef565b610120526200009a816006620001ef565b61014052815160208084019190912060e052815190820120610100524660a0526200012860e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c052506200013d3362000228565b600a805460ff60a01b191690556001600160a01b03841661018081905260ff82166101a0526040805163313ce56760e01b8152905183929163313ce5679160048083019260209291908290030181865afa158015620001a0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001c69190620005c0565b60ff910116610160525050600c805462ff0000191662010000179055506200063f945050505050565b60006020835110156200020f57620002078362000246565b905062000222565b816200021c8482620004f4565b5060ff90505b92915050565b600a80546001600160a01b0319169055620002438162000292565b50565b600080829050601f815111156200027d578260405163305a27a960e01b8152600401620002749190620005e5565b60405180910390fd5b80516200028a826200061a565b179392505050565b600980546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b634e487b7160e01b600052604160045260246000fd5b60005b8381101562000317578181015183820152602001620002fd565b50506000910152565b600082601f8301126200033257600080fd5b81516001600160401b03808211156200034f576200034f620002e4565b604051601f8301601f19908116603f011681019082821181831017156200037a576200037a620002e4565b816040528381528660208588010111156200039457600080fd5b620003a7846020830160208901620002fa565b9695505050505050565b805160ff81168114620003c357600080fd5b919050565b60008060008060808587031215620003df57600080fd5b84516001600160a01b0381168114620003f757600080fd5b60208601519094506001600160401b03808211156200041557600080fd5b620004238883890162000320565b945060408701519150808211156200043a57600080fd5b50620004498782880162000320565b9250506200045a60608601620003b1565b905092959194509250565b600181811c908216806200047a57607f821691505b6020821081036200049b57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620004ef57600081815260208120601f850160051c81016020861015620004ca5750805b601f850160051c820191505b81811015620004eb57828155600101620004d6565b5050505b505050565b81516001600160401b03811115620005105762000510620002e4565b620005288162000521845462000465565b84620004a1565b602080601f831160018114620005605760008415620005475750858301515b600019600386901b1c1916600185901b178555620004eb565b600085815260208120601f198616915b82811015620005915788860151825594840194600190910190840162000570565b5085821015620005b05787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215620005d357600080fd5b620005de82620003b1565b9392505050565b602081526000825180602084015262000606816040850160208701620002fa565b601f01601f19169190910160400192915050565b805160208083015191908110156200049b5760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a051613189620006fa6000396000818161060201528181611668015261180601526000818161048b01528181610922015281816109f101528181611111015281816115d801528181611e1f01528181611eb601526120f50152600061043c01526000610d9501526000610d6a01526000611d5901526000611d3101526000611c8c01526000611cb601526000611ce001526131896000f3fe608060405234801561001057600080fd5b50600436106103625760003560e01c80638456cb59116101c8578063ba08765211610104578063d505accf116100a2578063e30c39781161007c578063e30c39781461075c578063eea291321461076d578063ef8b30f7146106c4578063f2fde38b1461078057600080fd5b8063d505accf146106fd578063d905777e14610710578063dd62ed3e1461072357600080fd5b8063c63d75b6116100de578063c63d75b6146104f1578063c6e6f592146106c4578063ca1123c2146106d7578063ce96cb77146106ea57600080fd5b8063ba08765214610696578063be9a6555146106a9578063c06e6732146106b157600080fd5b806396b298c511610171578063a716cf4a1161014b578063a716cf4a1461064a578063a9059cbb1461065d578063b3d7f6b914610670578063b460af941461068357600080fd5b806396b298c5146105fd578063a0bb22b414610624578063a457c2d71461063757600080fd5b80638e06aafc116101a25780638e06aafc146105cf57806394bf804d146105e257806395d89b41146105f557600080fd5b80638456cb591461059b57806384b0196e146105a35780638da5cb5b146105be57600080fd5b806338d52e0f116102a25780635c975abb1161024057806370a428a41161021a57806370a428a414610565578063715018a61461057857806379ba5097146105805780637ecebe001461058857600080fd5b80635c975abb146105175780636e553f651461052957806370a082311461053c57600080fd5b80633f4ba83a1161027c5780633f4ba83a146104e9578063402d267d146104f15780634375d8cd146105045780634cdad506146103a057600080fd5b806338d52e0f1461048957806339509351146104c35780633ee3d6bc146104d657600080fd5b80630ad245281161030f5780633035106b116102e95780633035106b14610419578063313ce5671461043a57806332f289cf1461046e5780633644e5151461048157600080fd5b80630ad24528146103e957806318160ddd146103fe57806323b872dd1461040657600080fd5b806307a2d13a1161034057806307a2d13a146103a0578063095ea7b3146103b35780630a28a477146103d657600080fd5b806301e1d114146103675780630217631e1461038257806306fdde031461038b575b600080fd5b61036f610793565b6040519081526020015b60405180910390f35b61036f600b5481565b6103936107c9565b6040516103799190612bcb565b61036f6103ae366004612bde565b61085b565b6103c66103c1366004612c0c565b61086e565b6040519015158152602001610379565b61036f6103e4366004612bde565b610886565b6103fc6103f7366004612bde565b610893565b005b60025461036f565b6103c6610414366004612c38565b6109c1565b600c546104279061ffff1681565b60405161ffff9091168152602001610379565b7f00000000000000000000000000000000000000000000000000000000000000005b60405160ff9091168152602001610379565b6103fc61047c366004612c79565b6109e7565b61036f610af3565b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b039091168152602001610379565b6103c66104d1366004612c0c565b610afd565b61036f6104e4366004612c96565b610b3c565b6103fc610bab565b61036f6104ff366004612c79565b610bbd565b600c546103c69062010000900460ff1681565b600a54600160a01b900460ff166103c6565b61036f610537366004612cbd565b610bf5565b61036f61054a366004612c79565b6001600160a01b031660009081526020819052604090205490565b61036f610573366004612cff565b610c6f565b6103fc610c91565b6103fc610ca3565b61036f610596366004612c79565b610d2e565b6103fc610d4c565b6105ab610d5c565b6040516103799796959493929190612d49565b6009546001600160a01b03166104ab565b61036f6105dd366004612dfb565b610e01565b61036f6105f0366004612cbd565b610e16565b610393610e90565b61045c7f000000000000000000000000000000000000000000000000000000000000000081565b61036f610632366004612cff565b610e9f565b6103c6610645366004612c0c565b610eb5565b61036f610658366004612dfb565b610f6a565b6103c661066b366004612c0c565b610f7f565b61036f61067e366004612bde565b610f8d565b61036f610691366004612e3a565b610f9a565b61036f6106a4366004612e3a565b611014565b6103fc61108e565b6103fc6106bf366004612bde565b611180565b61036f6106d2366004612bde565b611225565b6103fc6106e5366004612e7c565b611232565b61036f6106f8366004612c79565b6112e8565b6103fc61070b366004612eb6565b61132b565b61036f61071e366004612c79565b61148f565b61036f610731366004612f24565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600a546001600160a01b03166104ab565b61036f61077b366004612c96565b6114c7565b6103fc61078e366004612c79565b611529565b600c5460009062010000900460ff16156107b4576107af6115a7565b905090565b600b546107bf6115a7565b6107af9190612f68565b6060600380546107d890612f7b565b80601f016020809104026020016040519081016040528092919081815260200182805461080490612f7b565b80156108515780601f1061082657610100808354040283529160200191610851565b820191906000526020600020905b81548152906001019060200180831161083457829003601f168201915b5050505050905090565b600061086882600061164b565b92915050565b60003361087c8185856116a4565b5060019392505050565b60006108688260016117fc565b61089b61184c565b600c5462010000900460ff16156108de576040517fcf9c0f0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600b54821180156108f65750600c5461ffff1615155b1561091d57600b54600c549083039061091990829061ffff1661271060016118a6565b9150505b6109527f0000000000000000000000000000000000000000000000000000000000000000333061094d8587612faf565b611901565b600c805462ff0000191662010000179055600b5442907f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb90848461099560025490565b60408051948552602085019390935291830152606082015260800160405180910390a250506000600b55565b6000336109cf8582856119b8565b6109da858585611a44565b60019150505b9392505050565b6109ef61184c565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031603610a5a576040517f96a22a6600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610af0336040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015610abb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610adf9190612fc2565b6001600160a01b0384169190611c31565b50565b60006107af611c7f565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919061087c9082908690610b37908790612f68565b6116a4565b600080610b498585610e16565b905082811115610ba3576040517f2e18fdcb0000000000000000000000000000000000000000000000000000000081526001600160a01b038516600482015260248101829052604481018490526064015b60405180910390fd5b949350505050565b610bb361184c565b610bbb611daa565b565b600c5460009062010000900460ff161580610be15750600a54600160a01b900460ff165b610bed57600019610868565b600092915050565b600080610c0183610bbd565b905080841115610c56576040517f79012fb20000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810185905260448101829052606401610b9a565b6000610c6185611225565b9050610ba333858784611e1a565b6000610c7d335b3084611eac565b610c888585856114c7565b95945050505050565b610c9961184c565b610bbb6000611f9c565b600a5433906001600160a01b03168114610d255760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f74207468652060448201527f6e6577206f776e657200000000000000000000000000000000000000000000006064820152608401610b9a565b610af081611f9c565b6001600160a01b038116600090815260076020526040812054610868565b610d5461184c565b610bbb611fc2565b600060608082808083610d907f00000000000000000000000000000000000000000000000000000000000000006005612020565b610dbb7f00000000000000000000000000000000000000000000000000000000000000006006612020565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b6000610e0c33610c76565b610ba38484610bf5565b600080610e2283610bbd565b905080841115610e77576040517f284ff6670000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810185905260448101829052606401610b9a565b6000610e8285610f8d565b9050610ba333858388611e1a565b6060600480546107d890612f7b565b6000610eaa33610c76565b610c88858585610b3c565b3360008181526001602090815260408083206001600160a01b038716845290915281205490919083811015610f525760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610b9a565b610f5f82868684036116a4565b506001949350505050565b6000610f7533610c76565b610ba38484610e16565b60003361087c818585611a44565b600061086882600161164b565b600080610fa6836112e8565b905080851115610ffb576040517ffe9cceec0000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810186905260448101829052606401610b9a565b600061100686610886565b9050610c88858588846120cb565b6000806110208361148f565b905080851115611075576040517fb94abeec0000000000000000000000000000000000000000000000000000000081526001600160a01b03841660048201526024810186905260448101829052606401610b9a565b60006110808661085b565b9050610c88858583896120cb565b61109661184c565b600c5462010000900460ff166110d8576040517fb5b8618200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6110e06115a7565b600b55600c805462ff0000191690556111386111046009546001600160a01b031690565b600b546001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169190611c31565b427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600b5461116660025490565b6040805192835260208301919091520160405180910390a2565b61118861184c565b427f2ba91c5af725b7eb47a99fc37633a131c737733dfb297706e7b11c724250efdb600b548360006111b960025490565b60408051948552602085019390935291830152606082015260800160405180910390a2427fc33272939f066c227e913a4b3434d860794f185c551685c29451a3a38b9b259c600b5461120a60025490565b6040805192835260208301919091520160405180910390a250565b60006108688260006117fc565b61123a61184c565b610bb88161ffff16111561127a576040517fc9034e1800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600c80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00001661ffff83169081179091556040805182815260208101929092527f650c33539188595d37a71b1a08a2fb3ee0728c0a1068d89f573c3fa4b28da220910160405180910390a150565b600c5460009062010000900460ff16611302576000610868565b610868611324836001600160a01b031660009081526020819052604090205490565b600061164b565b8342111561137b5760405162461bcd60e51b815260206004820152601d60248201527f45524332305065726d69743a206578706972656420646561646c696e650000006044820152606401610b9a565b60007f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98888886113aa8c612187565b6040805160208101969096526001600160a01b0394851690860152929091166060840152608083015260a082015260c0810186905260e0016040516020818303038152906040528051906020012090506000611405826121af565b90506000611415828787876121f7565b9050896001600160a01b0316816001600160a01b0316146114785760405162461bcd60e51b815260206004820152601e60248201527f45524332305065726d69743a20696e76616c6964207369676e617475726500006044820152606401610b9a565b6114838a8a8a6116a4565b50505050505050505050565b600c5460009062010000900460ff166114a9576000610868565b6001600160a01b038216600090815260208190526040902054610868565b6000806114d48585610bf5565b905082811015610ba3576040517fd032c9830000000000000000000000000000000000000000000000000000000081526001600160a01b03851660048201526024810182905260448101849052606401610b9a565b61153161184c565b600a80546001600160a01b03831673ffffffffffffffffffffffffffffffffffffffff19909116811790915561156f6009546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611627573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107af9190612fc2565b60006109e0611658610793565b611663906001612f68565b61168e7f0000000000000000000000000000000000000000000000000000000000000000600a6130bf565b60025461169b9190612f68565b859190856118a6565b6001600160a01b03831661171f5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b03821661179b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b0383811660008181526001602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60006109e061182c7f0000000000000000000000000000000000000000000000000000000000000000600a6130bf565b6002546118399190612f68565b611841610793565b61169b906001612f68565b6009546001600160a01b03163314610bbb5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610b9a565b6000806118b486868661221f565b905060018360028111156118ca576118ca6130ce565b1480156118e75750600084806118e2576118e26130e4565b868809115b15610c88576118f7600182612f68565b9695505050505050565b6040516001600160a01b03808516602483015283166044820152606481018290526119b29085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090931692909217909152612311565b50505050565b6001600160a01b0383811660009081526001602090815260408083209386168352929052205460001981146119b25781811015611a375760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610b9a565b6119b284848484036116a4565b6001600160a01b038316611ac05760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b038216611b3c5760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b03831660009081526020819052604090205481811015611bcb5760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b03848116600081815260208181526040808320878703905593871680835291849020805487019055925185815290927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a36119b2565b6040516001600160a01b038316602482015260448101829052611c7a9084907fa9059cbb000000000000000000000000000000000000000000000000000000009060640161194e565b505050565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016148015611cd857507f000000000000000000000000000000000000000000000000000000000000000046145b15611d0257507f000000000000000000000000000000000000000000000000000000000000000090565b6107af604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b611db26123f9565b600a80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b611e467f0000000000000000000000000000000000000000000000000000000000000000853085611901565b611e508382612452565b826001600160a01b0316846001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78484604051611e9e929190918252602082015260400190565b60405180910390a350505050565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663d505accf848484356020860135611ef460608801604089016130fa565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b1681526001600160a01b0395861660048201529490931660248501526044840191909152606483015260ff166084820152606084013560a4820152608084013560c482015260e401600060405180830381600087803b158015611f7f57600080fd5b505af1158015611f93573d6000803e3d6000fd5b50505050505050565b600a805473ffffffffffffffffffffffffffffffffffffffff19169055610af081612511565b611fca612570565b600a80547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b1790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611dfd3390565b606060ff831461203a57612033836125ca565b9050610868565b81805461204690612f7b565b80601f016020809104026020016040519081016040528092919081815260200182805461207290612f7b565b80156120bf5780601f10612094576101008083540402835291602001916120bf565b820191906000526020600020905b8154815290600101906020018083116120a257829003601f168201915b50505050509050610868565b336001600160a01b038416146120e6576120e68333836119b8565b6120f08382612609565b61211b7f00000000000000000000000000000000000000000000000000000000000000008584611c31565b826001600160a01b0316846001600160a01b03166121363390565b6001600160a01b03167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051612179929190918252602082015260400190565b60405180910390a450505050565b6001600160a01b03811660009081526007602052604090208054600181018255905b50919050565b60006108686121bc611c7f565b836040517f19010000000000000000000000000000000000000000000000000000000000008152600281019290925260228201526042902090565b600080600061220887878787612772565b9150915061221581612836565b5095945050505050565b60008080600019858709858702925082811083820303915050806000036122595783828161224f5761224f6130e4565b04925050506109e0565b8084116122a85760405162461bcd60e51b815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152606401610b9a565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000612366826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b031661299b9092919063ffffffff16565b90508051600014806123875750808060200190518101906123879190613115565b611c7a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610b9a565b600a54600160a01b900460ff16610bbb5760405162461bcd60e51b815260206004820152601460248201527f5061757361626c653a206e6f74207061757365640000000000000000000000006044820152606401610b9a565b6001600160a01b0382166124a85760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610b9a565b80600260008282546124ba9190612f68565b90915550506001600160a01b038216600081815260208181526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b600980546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600a54600160a01b900460ff1615610bbb5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610b9a565b606060006125d7836129aa565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b6001600160a01b0382166126855760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b038216600090815260208190526040902054818110156127145760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6001600160a01b0383166000818152602081815260408083208686039055600280548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156127a9575060009050600361282d565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa1580156127fd573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166128265760006001925092505061282d565b9150600090505b94509492505050565b600081600481111561284a5761284a6130ce565b036128525750565b6001816004811115612866576128666130ce565b036128b35760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610b9a565b60028160048111156128c7576128c76130ce565b036129145760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610b9a565b6003816004811115612928576129286130ce565b03610af05760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c60448201527f75650000000000000000000000000000000000000000000000000000000000006064820152608401610b9a565b6060610ba384846000856129eb565b600060ff8216601f811115610868576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606082471015612a635760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c00000000000000000000000000000000000000000000000000006064820152608401610b9a565b600080866001600160a01b03168587604051612a7f9190613137565b60006040518083038185875af1925050503d8060008114612abc576040519150601f19603f3d011682016040523d82523d6000602084013e612ac1565b606091505b5091509150612ad287838387612add565b979650505050505050565b60608315612b4c578251600003612b45576001600160a01b0385163b612b455760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610b9a565b5081610ba3565b610ba38383815115612b615781518083602001fd5b8060405162461bcd60e51b8152600401610b9a9190612bcb565b60005b83811015612b96578181015183820152602001612b7e565b50506000910152565b60008151808452612bb7816020860160208601612b7b565b601f01601f19169290920160200192915050565b6020815260006109e06020830184612b9f565b600060208284031215612bf057600080fd5b5035919050565b6001600160a01b0381168114610af057600080fd5b60008060408385031215612c1f57600080fd5b8235612c2a81612bf7565b946020939093013593505050565b600080600060608486031215612c4d57600080fd5b8335612c5881612bf7565b92506020840135612c6881612bf7565b929592945050506040919091013590565b600060208284031215612c8b57600080fd5b81356109e081612bf7565b600080600060608486031215612cab57600080fd5b833592506020840135612c6881612bf7565b60008060408385031215612cd057600080fd5b823591506020830135612ce281612bf7565b809150509250929050565b600060a082840312156121a957600080fd5b6000806000806101008587031215612d1657600080fd5b843593506020850135612d2881612bf7565b925060408501359150612d3e8660608701612ced565b905092959194509250565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e081840152612d8560e084018a612b9f565b8381036040850152612d97818a612b9f565b606085018990526001600160a01b038816608086015260a0850187905284810360c0860152855180825283870192509083019060005b81811015612de957835183529284019291840191600101612dcd565b50909c9b505050505050505050505050565b600080600060e08486031215612e1057600080fd5b833592506020840135612e2281612bf7565b9150612e318560408601612ced565b90509250925092565b600080600060608486031215612e4f57600080fd5b833592506020840135612e6181612bf7565b91506040840135612e7181612bf7565b809150509250925092565b600060208284031215612e8e57600080fd5b813561ffff811681146109e057600080fd5b803560ff81168114612eb157600080fd5b919050565b600080600080600080600060e0888a031215612ed157600080fd5b8735612edc81612bf7565b96506020880135612eec81612bf7565b95506040880135945060608801359350612f0860808901612ea0565b925060a0880135915060c0880135905092959891949750929550565b60008060408385031215612f3757600080fd5b8235612f4281612bf7565b91506020830135612ce281612bf7565b634e487b7160e01b600052601160045260246000fd5b8082018082111561086857610868612f52565b600181811c90821680612f8f57607f821691505b6020821081036121a957634e487b7160e01b600052602260045260246000fd5b8181038181111561086857610868612f52565b600060208284031215612fd457600080fd5b5051919050565b600181815b80851115613016578160001904821115612ffc57612ffc612f52565b8085161561300957918102915b93841c9390800290612fe0565b509250929050565b60008261302d57506001610868565b8161303a57506000610868565b8160018114613050576002811461305a57613076565b6001915050610868565b60ff84111561306b5761306b612f52565b50506001821b610868565b5060208310610133831016604e8410600b8410161715613099575081810a610868565b6130a38383612fdb565b80600019048211156130b7576130b7612f52565b029392505050565b60006109e060ff84168361301e565b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b60006020828403121561310c57600080fd5b6109e082612ea0565b60006020828403121561312757600080fd5b815180151581146109e057600080fd5b60008251613149818460208701612b7b565b919091019291505056fea2646970667358221220a6e02a37c989ba80fd1f4c202e2e69bbcc2d75b94341e52daad9bc5d5e954af664736f6c634300081300330000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000026416d70686f722053796e746865746963204c502d494c204865646765642028575354455448290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b616d70722d4c502d455448000000000000000000000000000000000000000000", + "nonce": "0x1", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0xdd8b0945300f1b8ea0b2ab6d6d729f9ccdbf09e365f0b5c16559d07dc8b20878", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "function": "setFees(uint16)", + "arguments": [ + "2000" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0x2791eb5807d69fe10c02eed6b4dc12bac0701744", + "gas": "0xac42", + "value": "0x0", + "data": "0xca1123c200000000000000000000000000000000000000000000000000000000000007d0", + "nonce": "0x2", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x393086158f0bc8a43e3c1b7542c8ae66e246c1c9c6ecc9509d762c22a37be2dc", + "transactionType": "CALL", + "contractName": "WstETH", + "contractAddress": "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", + "function": "approve(address,uint256)", + "arguments": [ + "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "100000000000000000" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0", + "gas": "0xf95b", + "value": "0x0", + "data": "0x095ea7b30000000000000000000000002791eb5807d69fe10c02eed6b4dc12bac0701744000000000000000000000000000000000000000000000000016345785d8a0000", + "nonce": "0x3", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": "0x76a7672acaa2bf55ea36bf9130a0eb866196f296c9e2911cb6736898eaf0bf56", + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "function": "deposit(uint256,address)", + "arguments": [ + "100000000000000000", + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0x2791eb5807d69fe10c02eed6b4dc12bac0701744", + "gas": "0x28a73", + "value": "0x0", + "data": "0x6e553f65000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x4", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + }, + { + "hash": null, + "transactionType": "CALL", + "contractName": "AmphorSyntheticVaultWithPermit", + "contractAddress": "0x2791EB5807D69Fe10C02eED6B4DC12baC0701744", + "function": "transferOwnership(address)", + "arguments": [ + "0x32B0aCfBb18C270491CDD124EB104A8d25A182ca" + ], + "transaction": { + "type": "0x02", + "from": "0x255e26065387de09436db52acc4ae2a3cd11e854", + "to": "0x2791eb5807d69fe10c02eed6b4dc12bac0701744", + "gas": "0x1023b", + "value": "0x0", + "data": "0xf2fde38b00000000000000000000000032b0acfbb18c270491cdd124eb104a8d25a182ca", + "nonce": "0x5", + "accessList": [] + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [], + "libraries": [], + "pending": [ + "0xbc6423ddb863dae808015392d62a431785281b1479739d313c80cc365ceed594", + "0xdd8b0945300f1b8ea0b2ab6d6d729f9ccdbf09e365f0b5c16559d07dc8b20878", + "0x393086158f0bc8a43e3c1b7542c8ae66e246c1c9c6ecc9509d762c22a37be2dc", + "0x76a7672acaa2bf55ea36bf9130a0eb866196f296c9e2911cb6736898eaf0bf56" + ], + "returns": {}, + "timestamp": 1699551295, + "chain": 1, + "multi": false, + "commit": "4e2ce73" +} \ No newline at end of file diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..9fdb43d --- /dev/null +++ b/config.yaml @@ -0,0 +1,64 @@ +# Learn how to configure DevNet templates using YAML here: https://docs.tenderly.co/devnets/yaml-template + +version: v0 +template: + name: zapper + block-number: latest + visibility: TEAM + network-id: 1 + execution: + chain-config: + chain-id: 1 + block-gas-limit: 10000000 + base-fee-per-gas: 1000000000 + + # contracts: + # - address: 0x395eD9ffd32b255dBD128092ABa40200159d664b + # bytecode: 0x123412341234123124123143 + # balance: 100 + # slots: + # - 0x3459054d09ae8631455b798b2b5d106e17bb4e68a39d2d2a935f5f1b7253988c: 0x0000000000000000000000000000000000000000000000000000000000000000 + # - 0x3459054d09ae8631455b798b2b5d106e17bb4e68a39d2d2a935f5f1b7253988d: 0x0000000000000000000000000000000000000000000000000000000000000001 + wallets: + - address: 0x86AE120DFf0967Fdb20ADa7629976A759A6FdEdf + balance: 100 + - private-key: 0x3459054d09ae8631455b798b2b5d106e17bb4e68a39d2d2a935f5f1b7253988c + balance: 100 + # storage: + # - address: 0x395eD9ffd32b255dBD128092ABa40200159d664b + # slots: + # - 0x1459054d09ae8631455b798b2b5d106e17bb4e68a39d2d2a935f5f1b7253988c: 0x0000000000000000000000000000000000000000000000000000000000000001 + # - 0x2459054d09ae8631455b798b2b5d106e17bb4e68a39d2d2a935f5f1b7253988c: 0x0000000000000000000000000000000000000000000000000000000000000002 + # - address: 0xabcde9ffd32b255dBD128092ABa40200159d665a + # slots: + # - 0x3459054d09ae8631455b798b2b5d106e17bb4e68a39d2d2a935f5f1b7253988c: 0x0000000000000000000000000000000000000000000000000000000000000003 + # balances: + # - address: 0x395eD9ffd32b255dBD128092ABa40200159d664b + # amount: 1000 + # - address: 0x395eD9ffd32b255dBD128092ABa40200159d664b + # amount: 1000 + erc20: + - contract: 0x6B175474E89094C44Da98b954EedeAC495271d0F # DAI + balances: + - address: 0x86AE120DFf0967Fdb20ADa7629976A759A6FdEdf + amount: 100 + - contract: 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 # WBTC + balances: + - address: 0x86AE120DFf0967Fdb20ADa7629976A759A6FdEdf + amount: 100 + - contract: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 # weth + balances: + - address: 0x86AE120DFf0967Fdb20ADa7629976A759A6FdEdf + amount: 100 + - contract: 0xdAC17F958D2ee523a2206206994597C13D831ec7 # USDT + balances: + - address: 0x86AE120DFf0967Fdb20ADa7629976A759A6FdEdf + amount: 100 + - contract: 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 # USDC + balances: + - address: 0x86AE120DFf0967Fdb20ADa7629976A759A6FdEdf + amount: 100 + - contract: 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84 # steth + balances: + - address: 0x86AE120DFf0967Fdb20ADa7629976A759A6FdEdf + amount: 100 diff --git a/example.env b/example.env new file mode 100644 index 0000000..15b5b60 --- /dev/null +++ b/example.env @@ -0,0 +1,79 @@ +SEED= +# OR +PRIVATE_KEY=0x +AMPHORLABS_ADDRESS_GOERLI=0x5A0Fb32360aead818D5486fe311A88bc681A1de1 # TEST USED ONLY +AMPHORLABS_ADDRESS=0x32B0aCfBb18C270491CDD124EB104A8d25A182ca # MAINNET +WSTETH_AMPHOR_VAULT_MAINNET=0x2791eb5807d69fe10c02eed6b4dc12bac0701744 +FOUNDRY_FUZZ_MAX_TEST_REJECTS=4294967295 +FOUNDRY_FFI=true +FOUNDRY_ETH_RPC_URL="https://eth-mainnet.g.alchemy.com/v2/API_KEY" +############################################## +############## SYNTHETIC VAULT ############# +############################################## +BOOTSTRAP_AMOUNT_SYNTHETIC_USDC=100000000 +BOOTSTRAP_AMOUNT_SYNTHETIC_WETH=10000000000000000000 +BOOTSTRAP_AMOUNT_SYNTHETIC_WBTC=1000000 +DECIMALS_OFFSET_USDC=12 +DECIMALS_OFFSET_WETH=12 +DECIMALS_OFFSET_WBTC=12 +SYNTHETIC_USDC_V0_NAME="Amphor Synthetic LP-IL Hedged (USDC)" +SYNTHETIC_USDC_V0_SYMBOL=ampr-LP-USD +SYNTHETIC_WETH_V0_NAME="Amphor Synthetic LP-IL Hedged (WETH)" +SYNTHETIC_WETH_V0_SYMBOL=ampr-LP-ETH +SYNTHETIC_WBTC_V0_NAME="Amphor Synthetic LP-IL Hedged (WBTC)" +SYNTHETIC_WBTC_V0_SYMBOL=ampr-LP-BTC +INITIAL_FEES_AMOUNT=2000 #2000 = 20.00% +############################################## +################# POLYGON ################# +############################################## +POLYGON_ETHERSCAN_API_KEY= +POLYGON_ZK_TESTNET_ETHERSCAN_API_KEY= +############################################## +# MUMBAI +USDC_MUMBAI=0xe9DcE89B076BA6107Bb64EF30678efec11939234 +USDT_MUMBAI=0xAcDe43b9E5f72a4F554D4346e69e8e7AC8F352f0 +DAI_MUMBAI=0xF14f9596430931E177469715c591513308244e8F +WETH_MUMBAI=0xD087ff96281dcf722AEa82aCA57E8545EA9e6C96 +WBTC_MUMBAI=0x97e8dE167322a3bCA28E8A49BC46F6Ce128FEC68 +VERIFIER_URL_MUMBAI=https://api-testnet.polygonscan.com/api/ +RPC_URL_MUMBAI=https://polygon-mumbai-bor.publicnode.com +############################################## +# POLYGON MAINNET +USDC_POLYGON=0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 +USDT_POLYGON=0xc2132D05D31c914a87C6611C10748AEb04B58e8F +DAI_POLYGON=0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063 +WETH_POLYGON=0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619 +WBTC_POLYGON=0x1BFD67037B42Cf73acF2047067bd4F2C47D9BfD6 +VERIFIER_URL_POLYGON=https://api.polygonscan.com/api/ +RPC_URL_POLYGON=https://polygon.meowrpc.com +############################################## +################# ETHEREUM ################# +############################################## +ETHERSCAN_API_KEY= +VERIFIER_URL_GOERLI=https://api-goerli.etherscan.io/api +VERIFIER_URL=https://api.etherscan.io/api +############################################## +# GOERLI +USDC_GOERLI=0x65afadd39029741b3b8f0756952c74678c9cec93 +AAVE_USDC_GOERLI=0x9FD21bE27A2B059a288229361E2fA632D8D2d074 +CUSTOM_USDC_GOERLI=0x782609433dDCb91c64635F65B92aa09Dc6EFd01D +USDT_GOERLI=0x2e8d98fd126a32362f2bd8aa427e59a1ec63f780 +DAI_GOERLI=0xba8dced3512925e52fe67b1b5329187589072a55 +WETH_GOERLI=0xccb14936c2e000ed8393a571d15a2672537838ad +WBTC_GOERLI=0x45AC379F019E48ca5dAC02E54F406F99F5088099 +RPC_URL_GOERLI=https://ethereum-goerli.publicnode.com +############################################## +# SEPOLIA +RPC_URL_SEPOLIA=https://endpoints.omniatech.io/v1/eth/sepolia/public +############################################## +# MAINNET +USDC_MAINNET=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 +USDT_MAINNET=0xdAC17F958D2ee523a2206206994597C13D831ec7 +DAI_MAINNET=0x6B175474E89094C44Da98b954EedeAC495271d0F +ETH_MAINNET=0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE +WETH_MAINNET=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 +STETH_MAINNET=0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84 +WSTETH_MAINNET=0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0 +WBTC_MAINNET=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599 +RPC_URL_MAINNET=https://ethereum.publicnode.com +############################################## diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 0000000..beec5df --- /dev/null +++ b/foundry.toml @@ -0,0 +1,43 @@ +[profile.default] +src = 'src' +out = 'out' +libs = ['lib'] +solc = "0.8.19" +optimizer-runs = 2_000 + +[profile.production] +src = 'src' +out = 'out' +libs = ['lib'] +solc = "0.8.19" +# eth-rpc-url = "https://eth-mainnet.g.alchemy.com/v2/" +optimizer-runs = 10_000_000 + +[profile.ci] +src = 'src' +out = 'out' +libs = ['lib'] +solc = "0.8.19" +# ffi = true +optimizer-runs = 10_000_000 + +remappings = [ + "ds-test/=lib/forge-std/lib/ds-test/src/", + "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", + "@forge-std/=lib/forge-std/src/", + "@solmate/=lib/solmate/src/", + "@openzeppelin/=lib/openzeppelin-contracts/", + "@openzeppelin-v4.9.3/=lib/openzeppelin-contracts-v4.9.3/", + "@openzeppelin-v5.0.0/=lib/openzeppelin-contracts-v5.0.0/", + "@uniswap/v3-core/=lib/v3-core/", + "@uniswap/v3-periphery/=lib/v3-periphery/", + "@maverick-v1-interfaces/=lib/maverick-v1-interfaces/contracts/interfaces/", + "lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/", + "@crytic/=lib/crytic/contracts" +] + +[rpc_endpoints] +goerli = "https://ethereum-goerli.publicnode.com" + +[fmt] +line_length = 80 diff --git a/lib/crytic/.github/ISSUE_TEMPLATE/bug_report.yaml b/lib/crytic/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 0000000..8d41b62 --- /dev/null +++ b/lib/crytic/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,54 @@ +--- +description: "File a bug report" +labels: + - bug-candidate +name: "Bug Report" +title: "[Bug-Candidate]: " +body: + - + attributes: + value: | + Before submitting, please check the issues tab to avoid duplicates. + Thanks for taking the time to fill out this bug report! + type: markdown + - + attributes: + label: "Describe the issue:" + id: what-happened + type: textarea + validations: + required: true + - + attributes: + label: "Steps to reproduce the issue:" + description: "Please be as detailed as you can. It's easier for us to fix the bug if we can reproduce it." + placeholder: "First, clone the `crytic/properties` repository..." + id: reproduce + type: textarea + validations: + required: true + - + attributes: + label: "If additional code is needed for reproducing, please copy it here, or drop us a link to the repository:" + description: "It can be a github repo, code snippet, or empty if no additional code is needed." + placeholder: "`contract A {}`\n" + id: additional-code + type: textarea + - + attributes: + label: "Echidna version:" + description: "Run `echidna-test --version`" + id: version + type: textarea + validations: + required: true + - + attributes: + label: "Additional information:" + description: | + Please add any additional information you might consider important, or copy and paste any relevant log output. + This will be automatically formatted into code, so no need for backticks or other formatting. + render: shell + id: additional-information + type: textarea + diff --git a/lib/crytic/.github/ISSUE_TEMPLATE/feature_request.yaml b/lib/crytic/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 0000000..fe04776 --- /dev/null +++ b/lib/crytic/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,18 @@ +--- +name: Feature request +description: Suggest new features or improvements to existing features +labels: + - "feature-request" +title: "[Feature-request]: " +body: + - type: markdown + attributes: + value: | + Before submitting, please check the issues tab to avoid duplicates. + Thanks for providing feedback! + - type: textarea + attributes: + label: Describe the desired feature or improvement + description: Please be as specific as you can, explain why is that needed or what problem it solves. + validations: + required: true \ No newline at end of file diff --git a/lib/crytic/.github/workflows/examples.yaml b/lib/crytic/.github/workflows/examples.yaml new file mode 100644 index 0000000..a579d4d --- /dev/null +++ b/lib/crytic/.github/workflows/examples.yaml @@ -0,0 +1,115 @@ +name: Test examples + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + +env: + FOUNDRY_PROFILE: ci + +jobs: + foundry: + name: Test Foundry examples + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Compile ERC20 Foundry example + working-directory: tests/ERC20/foundry + run: forge build --build-info + + - name: Run Echidna against ERC20 Internal Foundry example + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC20/foundry + files: . + config: ./echidna-config.yaml + crytic-args: --ignore-compile + contract: CryticERC20InternalHarness + + - name: Run Echidna against ERC20 External Foundry example + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC20/foundry + files: . + config: ./echidna-config-ext.yaml + crytic-args: --ignore-compile + contract: CryticERC20ExternalHarness + + - name: Compile ERC4646 Foundry example + working-directory: tests/ERC4626/foundry + run: forge build --build-info + + - name: Run Echidna against ERC4626 Foundry example + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC4626/foundry + files: . + config: ./echidna.yaml + crytic-args: --ignore-compile + contract: CryticERC4626InternalHarness + + hardhat: + name: Test Hardhat examples + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Set up Nodejs + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Install dependencies and compile ERC20 example + working-directory: tests/ERC20/hardhat + run: | + npm ci + npx hardhat compile --force + + - name: Run Echidna for Internal tests + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC20/hardhat + files: . + config: ./tests/echidna-config.yaml + crytic-args: --ignore-compile + contract: CryticERC20InternalHarness + + - name: Run Echidna for External tests + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC20/hardhat + files: . + config: ./tests/echidna-config-ext.yaml + crytic-args: --ignore-compile + contract: CryticERC20ExternalHarness + + - name: Install dependencies and compile ERC4626 example + working-directory: tests/ERC4626/hardhat + run: | + npm ci + npx hardhat compile --force + + - name: Run Echidna + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC4626/hardhat + files: . + config: tests/echidna-config.yaml + crytic-args: --ignore-compile + contract: CryticERC4626Harness diff --git a/lib/crytic/.gitignore b/lib/crytic/.gitignore new file mode 100644 index 0000000..fdfddc2 --- /dev/null +++ b/lib/crytic/.gitignore @@ -0,0 +1,43 @@ +# Cache +**/.cache +**/cache +**/.config +**/.git +**/.node-gyp +**/.npm +**/crytic-compile +**/crytic-export +**/corpus + +# Local storage +**/*.local +.env + +# Compiled output +.flags +artifacts/ +build/ +dist/ +node_modules/ +corpus/ +**/out +*corpus* + +# IDEs and editors +*.launch +*.sublime-workspace +*.sw[opq] +.c9/ +.classpath +.idea +.project +.pki +.settings/ +.vscode + +# Logs +*.log* + +# OS +.bash_history +.DS_Store diff --git a/lib/crytic/.gitmodules b/lib/crytic/.gitmodules new file mode 100644 index 0000000..e600796 --- /dev/null +++ b/lib/crytic/.gitmodules @@ -0,0 +1,20 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std + branch = v1.1.1 +[submodule "lib/solmate"] + path = lib/solmate + url = https://github.com/transmissions11/solmate + tag = v6 +[submodule "lib/ERC4626"] + path = lib/ERC4626 + url = https://github.com/fubuloubu/ERC4626 + branch = main +[submodule "contracts/Math/ABDKMath64x64/abdk-libraries-solidity"] + path = contracts/Math/ABDKMath64x64/abdk-libraries-solidity + url = https://github.com/abdk-consulting/abdk-libraries-solidity.git + tag = v3.2 +[submodule "lib/openzeppelin-contracts"] + path = lib/openzeppelin-contracts + url = https://github.com/openzeppelin/openzeppelin-contracts + branch = v4.8.0 diff --git a/lib/crytic/.solhint.json b/lib/crytic/.solhint.json new file mode 100644 index 0000000..dcb7836 --- /dev/null +++ b/lib/crytic/.solhint.json @@ -0,0 +1,10 @@ +{ + "extends": "solhint:recommended", + "rules": { + "compiler-version": ["off"], + "func-name-mixedcase": ["off"], + "func-visibility": ["warn",{ "ignoreConstructors":true }], + "no-empty-blocks": ["off"], + "var-name-mixedcase": ["off"] + } +} diff --git a/lib/crytic/CODEOWNERS b/lib/crytic/CODEOWNERS new file mode 100644 index 0000000..1a48e32 --- /dev/null +++ b/lib/crytic/CODEOWNERS @@ -0,0 +1,7 @@ +* @montyly @ggrieco-tob +/contracts/ERC20/ @glarregay-tob +/contracts/ERC4626/ @bsamuels453 +/contracts/Math/ @glarregay-tob +/contracts/util/ @glarregay-tob @bsamuels453 +/tests/ @glarregay-tob @bsamuels453 +/.github/workflows/ @elopez \ No newline at end of file diff --git a/lib/crytic/CONTRIBUTING.md b/lib/crytic/CONTRIBUTING.md new file mode 100644 index 0000000..58a7c33 --- /dev/null +++ b/lib/crytic/CONTRIBUTING.md @@ -0,0 +1,69 @@ +# Contributing to Properties + +First, thanks for your interest in contributing to this repository! We welcome and appreciate all contributions, including bug reports, feature suggestions, tutorials/blog posts, and code improvements. + +If you're unsure where to start, we recommend taking a look at our [issue tracker](https://github.com/crytic/properties/issues). If you find an issue or proposal that you feel you can do, assign yourself to it or contact the relevant [CODEOWNERS](CODEOWNERS) + +## Bug reports and feature suggestions + +Bug reports and feature suggestions can be submitted to our issue tracker. For bug reports, adding as much information as you can will help us in debugging and resolving the issue quickly. If you find a security vulnerability, do not open an issue, email opensource@trailofbits.com instead. + +## Questions + +Questions can be submitted to the issue tracker, but you may get a faster response if you ask in our [chat room](https://empireslacking.herokuapp.com/) (in the #ethereum channel). + +## Code + +This repository uses the pull request contribution model. Please create an account on Github if you don't have one already, fork this repository, and submit your contributions via pull requests. For more documentation, look [here](https://guides.github.com/activities/forking/). + +Some pull request guidelines: + +- Create a new branch from the [`main`](https://github.com/crytic/properties/tree/main) branch. If you are submitting a new feature, prefix the new branch name with `dev` (for example, `dev-add-properties-for-erc20-transfers`). If your submission is a bug fix, prefix the new branch name with `fix` (for example, `fix-typo-in-readme`). Please be descriptive in the branch name, avoid confusing or unclear names such as `mypatch2` or `bugfix`. +- Minimize irrelevant changes (formatting, whitespace, etc) to code that would otherwise not be touched by this patch. Save formatting or style corrections for a separate pull request that does not make any semantic changes. +- When possible, large changes should be split up into smaller focused pull requests. +- Fill out the pull request description with a summary of what your patch does, key changes that have been made, and any further points of discussion, if applicable. If your pull request solves an open issue, add "Fixes #xxx" at the end. +- Title your pull request with a brief description of what it's changing. "Fixes #123" is a good comment to add to the description, but makes for an unclear title on its own. +- If your are unsure about something, don't hesitate to ask! + +## Directory Structure + +Below is a rough outline of the directory structure: +```text +. +├── contracts # Parent folder for contracts +│ ├── ERC20 # Properties for ERC-20 contracts +│ │ ├── external # External testing +│ │ │ ├── properties +│ │ │ └── util +│ │ └── internal # Internal testing +│ │ ├── properties +│ │ └── util +│ ├── ERC4626 # Properties for ERC-4626 tokenized vaults +│ │ ├── properties +│ │ ├── test +│ │ │ ├── rounding +│ │ │ ├── security +│ │ │ └── usingApproval +│ │ └── util +│ ├── Math # Properties for mathematical libraries +│ │ └── ABDKMath64x64 +│ ├── util # Helpers for new or existing properties +│ └── ... +├── lib # External libraries needed for the repository +└── tests # Tests for properties + ├── ERC20 + │ ├── foundry + │ └── hardhat + ├── ERC4626 + │ ├── foundry + │ └── hardhat + └── ... + ├── foundry + └── hardhat +``` + +Please follow this structure in your collaborations. + +## Running tests on your computer + +Please read [README.md](README.md) for instructions on how to set up your environment and run the tests. diff --git a/lib/crytic/LICENSE b/lib/crytic/LICENSE new file mode 100644 index 0000000..bae94e1 --- /dev/null +++ b/lib/crytic/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/lib/crytic/PROPERTIES.md b/lib/crytic/PROPERTIES.md new file mode 100644 index 0000000..9575ec0 --- /dev/null +++ b/lib/crytic/PROPERTIES.md @@ -0,0 +1,221 @@ +# Introduction + +This file lists all the currently implemented Echidna property tests for ERC20, ERC4626 and ABDKMath64x64. For each property, there is a permalink to the file implementing it in the repository and a small description of the invariant tested. + +## Table of contents + +- [Introduction](#introduction) + - [Table of contents](#table-of-contents) + - [ERC20](#erc20) + - [Basic properties for standard functions](#basic-properties-for-standard-functions) + - [Tests for burnable tokens](#tests-for-burnable-tokens) + - [Tests for mintable tokens](#tests-for-mintable-tokens) + - [Tests for pausable tokens](#tests-for-pausable-tokens) + - [Tests for tokens implementing `increaseAllowance` and `decreaseAllowance`](#tests-for-tokens-implementing-increaseallowance-and-decreaseallowance) + - [ERC4626](#erc4626) + - [ABDKMath64x64](#abdkmath64x64) + +## ERC20 + +### Basic properties for standard functions + +| ID | Name | Invariant tested | +|---|---|---| +| ERC20-BASE-001 | [test_ERC20_constantSupply](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L16) | Total supply should be constant for non-mintable and non-burnable tokens. | +| ERC20-BASE-002 | [test_ERC20_userBalanceNotHigherThanSupply](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L22) | No user balance should be greater than the token's total supply. | +| ERC20-BASE-003 | [test_ERC20_usersBalancesNotHigherThanSupply](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L27) | The sum of users balances should not be greater than the token's total supply. | +| ERC20-BASE-004 | [test_ERC20_zeroAddressBalance](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L33) | Token balance for address zero should be zero. | +| ERC20-BASE-005 | [test_ERC20_transferToZeroAddress](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L38) | `transfer`s to zero address should not be allowed. | +| ERC20-BASE-006 | [test_ERC20_transferFromToZeroAddress](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L47) | `transferFrom`s to zero address should not be allowed. | +| ERC20-BASE-007 | [test_ERC20_selfTransfer](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L70) | Self `transfer`s should not break accounting. | +| ERC20-BASE-008 | [test_ERC20_selfTransferFrom](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L58) | Self `transferFrom`s should not break accounting. | +| ERC20-BASE-009 | [test_ERC20_transferMoreThanBalance](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L93) | `transfer`s for more than account balance should not be allowed. | +| ERC20-BASE-010 | [test_ERC20_transferFromMoreThanBalance](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L80) | `transferFrom`s for more than account balance should not be allowed. | +| ERC20-BASE-011 | [test_ERC20_transferZeroAmount](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L105) | `transfer`s for zero amount should not break accounting. | +| ERC20-BASE-012 | [test_ERC20_transferFromZeroAmount](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L117) | `transferFrom`s for zero amount should not break accounting. | +| ERC20-BASE-013 | [test_ERC20_transfer](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L130) | Valid `transfer`s should update accounting correctly. | +| ERC20-BASE-014 | [test_ERC20_transferFrom](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L144) | Valid `transferFrom`s should update accounting correctly. | +| ERC20-BASE-015 | [test_ERC20_setAllowance](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L160) | Allowances should be set correctly when `approve` is called. | +| ERC20-BASE-016 | [test_ERC20_setAllowanceTwice](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L167) | Allowances should be updated correctly when `approve` is called twice. | +| ERC20-BASE-017 | [test_ERC20_spendAllowanceAfterTransfer](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BasicProperties.sol#L178) | After `transferFrom`, allowances should be updated correctly. | + +### Tests for burnable tokens + +| ID | Name | Invariant tested | +|---|---|---| +| ERC20-BURNABLE-001 | [test_ERC20_burn](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BurnableProperties.sol#L17) | User balance and total supply should be updated correctly when `burn` is called. | +| ERC20-BURNABLE-002 | [test_ERC20_burnFrom](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BurnableProperties.sol#L29) | User balance and total supply should be updated correctly when `burnFrom` is called. | +| ERC20-BURNABLE-003 | [test_ERC20_burnFromUpdateAllowance](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20BurnableProperties.sol#L42) | Allowances should be updated correctly when `burnFrom` is called. | + +### Tests for mintable tokens + +| ID | Name | Invariant tested | +|---|---|---| +| ERC20-MINTABLE-001 | [test_ERC20_mintTokens](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20MintableProperties.sol#L19) | User balance and total supply should be updated correctly after minting. | + +### Tests for pausable tokens + +| ID | Name | Invariant tested | +|---|---|---| +| ERC20-PAUSABLE-001 | [test_ERC20_pausedTransfer](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20PausableProperties.sol#L35) | Token `transfer`s should not be possible when paused state is enabled. | +| ERC20-PAUSABLE-002 | [test_ERC20_pausedTransferFrom](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20PausableProperties.sol#L52) | Token `transferFrom`s should not be possible when paused state is enabled. | + +### Tests for tokens implementing `increaseAllowance` and `decreaseAllowance` + +| ID | Name | Invariant tested | +|---|---|---| +| ERC20-ALLOWANCE-001 | [test_ERC20_setAndIncreaseAllowance](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20IncreaseAllowanceProperties.sol#L17) | Allowance should be updated correctly when `increaseAllowance` is called. | +| ERC20-ALLOWANCE-002 | [test_ERC20_setAndDecreaseAllowance](https://github.com/crytic/properties/blob/main/contracts/ERC20/internal/properties/ERC20IncreaseAllowanceProperties.sol#L28) | Allowance should be updated correctly when `decreaseAllowance` is called. | + +## ERC4626 + +| ID | Name | Invariant tested | +|---|---|---| +| ERC4626-001 | [verify_assetMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L10) | `asset` must not revert. | +| ERC4626-002 | [verify_totalAssetsMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L20) | `totalAssets` must not revert. | +| ERC4626-003 | [verify_convertToAssetsMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L30) | `convertToAssets` must not revert for reasonable values. | +| ERC4626-004 | [verify_convertToSharesMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L54) | `convertToShares` must not revert for reasonable values. | +| ERC4626-005 | [verify_maxDepositMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L71) | `maxDeposit` must not revert. | +| ERC4626-006 | [verify_maxMintMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L79) | `maxMint` must not revert. | +| ERC4626-007 | [verify_maxRedeemMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L87) | `maxRedeem` must not revert. | +| ERC4626-008 | [verify_maxWithdrawMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L99) | `maxWithdraw` must not revert. | +| ERC4626-009 | [verify_redeemViaApprovalProxy](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol#L10) | Redeem via approval proxy. | +| ERC4626-010 | [verify_withdrawViaApprovalProxy](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol#L31) | Withdraw via approval proxy. | +| ERC4626-011 | [verify_withdrawRequiresTokenApproval](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol#L56) | Withdraw requires approval for third parties. | +| ERC4626-012 | [verify_redeemRequiresTokenApproval](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol#L73) | Redeem requires approval for third parties. | +| ERC4626-013 | [verify_previewDepositRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L9) | checks `previewDeposit` rounding direction | +| ERC4626-014 | [verify_previewMintRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L15) | checks `previewMint` rounding direction | +| ERC4626-015 | [verify_convertToSharesRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L22) | checks `convertToShares` rounding direction | +| ERC4626-016 | [verify_previewRedeemRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L29) | checks `previewRedeem` rounding direction | +| ERC4626-017 | [verify_previewWithdrawRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L35) | checks `previewWithdraw` rounding direction | +| ERC4626-018 | [verify_convertToAssetsRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L42) | checks `convertToAssets` rounding direction | +| ERC4626-019 | [verify_depositRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L48) | checks `deposit` rounding direction | +| ERC4626-020 | [verify_mintRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L54) | checks `mint` rounding direction | +| ERC4626-021 | [verify_withdrawRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L62) | checks `withdraw` rounding direction | +| ERC4626-022 | [verify_redeemRoundingDirection](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RoundingProps.sol#L70) | checks `redeem` rounding direction | +| ERC4626-023 | [verify_maxDepositIgnoresSenderAssets](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/SenderIndependentProps.sol#L10) | `maxDeposit` must assume the agent has infinite assets. | +| ERC4626-024 | [verify_maxMintIgnoresSenderAssets](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/SenderIndependentProps.sol#L19) | `maxMint` must assume the agent has infinite assets. | +| ERC4626-025 | [verify_previewMintIgnoresSender](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/SenderIndependentProps.sol#L28) | `previewMint` must not be dependent on `msg.sender`. | +| ERC4626-026 | [verify_previewDepositIgnoresSender](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/SenderIndependentProps.sol#L38) | `previewDeposit` must not be dependent on `msg.sender`. | +| ERC4626-027 | [verify_previewWithdrawIgnoresSender](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/SenderIndependentProps.sol#L48) | `previewWithdraw` must not be dependent on `msg.sender`. | +| ERC4626-028 | [verify_previewRedeemIgnoresSender](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/SenderIndependentProps.sol#L63) | `previewRedeem` must not be dependent on `msg.sender`. | +| ERC4626-029 | [verify_depositProperties](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/FunctionalAccountingProps.sol#L11) | `deposit` assets and shares handling. | +| ERC4626-030 | [verify_mintProperties](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/FunctionalAccountingProps.sol#L39) | `mint` assets and shares handling. | +| ERC4626-031 | [verify_redeemProperties](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/FunctionalAccountingProps.sol#L65) | `redeem` assets and shares handling. | +| ERC4626-032 | [verify_withdrawProperties](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/FunctionalAccountingProps.sol#L92) | `withdraw` assets and shares handling. | +| ERC4626-033 | [verify_sharePriceInflationAttack](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/SecurityProps.sol#L12) | Checks for share inflation attacks. | +| ERC4626-034 | [verify_assetDecimalsLessThanVault](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/SecurityProps.sol#L7) | Compares vault decimals with asset decimals. | +| ERC4626-035 | [verify_withdrawRequiresTokenApproval](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol#L56) | Verifies that `withdraw` requires token approval. | +| ERC4626-036 | [verify_redeemRequiresTokenApproval](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol#L73) | Verifies that `redeem` requires token approval. | +| ERC4626-037 | [verify_convertToSharesMustNotRevert](https://github.com/crytic/properties/blob/main/contracts/ERC4626/properties/MustNotRevertProps.sol#L54) | `convertToShares` must not revert for reasonable values. | + +## ABDKMath64x64 + +| ID | Name | Invariant tested | +|---|---|---| +| ABDKMATH-001 | [add_test_commutative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L274) | Commutative property for addition. | +| ABDKMATH-002 | [add_test_associative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L283) | Associative property for addition. | +| ABDKMATH-003 | [add_test_identity](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L294) | Identity operation for addition. | +| ABDKMATH-004 | [add_test_values](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L303) | Addition result should increase or decrease depending on operands signs. | +| ABDKMATH-005 | [add_test_range](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L322) | Addition result should be in the valid 64x64-arithmetic range. | +| ABDKMATH-006 | [add_test_maximum_value](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L334) | Addition edge case: maximum value plus zero should be maximum value. | +| ABDKMATH-007 | [add_test_maximum_value_plus_one](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L346) | Addition edge case: maximum value plus one should revert (out of range). | +| ABDKMATH-008 | [add_test_minimum_value](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L356) | Addition edge case: minimum value plus zero should be minimum value. | +| ABDKMATH-009 | [add_test_minimum_value_plus_negative_one](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L368) | Addition edge case: minimum value plus minus one should revert (out of range). | +| ABDKMATH-010 | [sub_test_equivalence_to_addition](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L392) | Subtraction should be equal to addition with opposite sign. | +| ABDKMATH-011 | [sub_test_non_commutative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L402) | Anti-commutative property for subtraction. | +| ABDKMATH-012 | [sub_test_identity](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L411) | Identity operation for subtraction. | +| ABDKMATH-013 | [sub_test_neutrality](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L420) | Adding and subtracting the same value should not affect original value. | +| ABDKMATH-014 | [sub_test_values](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L433) | Subtraction result should increase or decrease depending on operands signs. | +| ABDKMATH-015 | [sub_test_range](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L451) | Subtraction result should be in the valid 64x64-arithmetic range. | +| ABDKMATH-016 | [sub_test_maximum_value](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L463) | Subtraction edge case: maximum value minus zero should be maximum value. | +| ABDKMATH-017 | [sub_test_maximum_value_minus_neg_one](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L476) | Subtraction edge case: maximum value minus negative one should revert (out of range). | +| ABDKMATH-018 | [sub_test_minimum_value](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L486) | Subtraction edge case: minimum value minus zero should be minimum value. | +| ABDKMATH-019 | [sub_test_minimum_value_minus_one](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L498) | Subtraction edge case: minimum value minus one should revert (out of range). | +| ABDKMATH-020 | [mul_test_commutative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L522) | Commutative property for multiplication. | +| ABDKMATH-021 | [mul_test_associative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L531) | Associative property for multiplication. | +| ABDKMATH-022 | [mul_test_distributive](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L548) | Distributive property for multiplication. | +| ABDKMATH-023 | [mul_test_identity](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L565) | Identity operation for multiplication. | +| ABDKMATH-024 | [mul_test_values](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L575) | Multiplication result should increase or decrease depending on operands signs. | +| ABDKMATH-025 | [mul_test_range](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L606) | Multiplication result should be in the valid 64x64-arithmetic range. | +| ABDKMATH-026 | [mul_test_maximum_value](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L618) | Multiplication edge case: maximum value times one should be maximum value | +| ABDKMATH-027 | [mul_test_minimum_value](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L631) | Multiplication edge case: minimum value times one should be minimum value | +| ABDKMATH-028 | [div_test_division_identity](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L659) | Identity operation for division. | +| ABDKMATH-029 | [div_test_negative_divisor](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L678) | Division result sign should change according to divisor sign. | +| ABDKMATH-030 | [div_test_division_num_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L689) | Division with zero numerator should be zero. | +| ABDKMATH-031 | [div_test_values](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L699) | Division result should increase or decrease (in absolute value) depending on divisor's absolute value. | +| ABDKMATH-032 | [div_test_div_by_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L718) | Division edge case: Divisor zero should revert. | +| ABDKMATH-033 | [div_test_maximum_denominator](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L728) | Division edge case: Division result by a large number should be less than one. | +| ABDKMATH-034 | [div_test_maximum_numerator](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L736) | Division edge case: Division result of maximum value should revert if divisor is less than one. | +| ABDKMATH-035 | [div_test_range](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L750) | Division result should be in the valid 64x64-arithmetic range. | +| ABDKMATH-036 | [neg_test_double_negation](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L778) | Double sign negation should be equal to the original operand. | +| ABDKMATH-037 | [neg_test_identity](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L786) | Identity operation for sign negation. | +| ABDKMATH-038 | [neg_test_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L801) | Negation edge case: Negation of zero should be zero. | +| ABDKMATH-039 | [neg_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L809) | Negation edge case: Negation of maximum value minus epsilon should not revert. | +| ABDKMATH-040 | [neg_test_minimum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L819) | Negation edge case: Negation of minimum value plus epsilon should not revert. | +| ABDKMATH-041 | [abs_test_positive](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L842) | Absolute value should be always positive. | +| ABDKMATH-042 | [abs_test_negative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L850) | Absolute value of a number and its negation should be equal. | +| ABDKMATH-043 | [abs_test_multiplicativeness](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L859) | Multiplicativeness property for absolute value. | +| ABDKMATH-044 | [abs_test_subadditivity](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L874) | Subadditivity property for absolute value. | +| ABDKMATH-045 | [abs_test_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L889) | Absolute value edge case: absolute value of zero is zero. | +| ABDKMATH-046 | [abs_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L903) | Absolute value edge case: absolute value of maximum value is maximum value. | +| ABDKMATH-047 | [abs_test_minimum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L916) | Absolute value edge case: absolute value of minimum value is the negation of minimum value. | +| ABDKMATH-048 | [inv_test_double_inverse](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L945) | Result of double inverse should be _close enough_ to the original operand. | +| ABDKMATH-049 | [inv_test_division](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L957) | Inverse should be equivalent to division. | +| ABDKMATH-050 | [inv_test_division_noncommutativity](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L968) | Anticommutative property for inverse operation. | +| ABDKMATH-051 | [inv_test_multiplication](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L981) | Multiplication of inverses should be equal to inverse of multiplication. | +| ABDKMATH-052 | [inv_test_identity](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1003) | Identity property for inverse. | +| ABDKMATH-053 | [inv_test_values](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1018) | Inverse result should be in range (0, 1) if operand is greater than one. | +| ABDKMATH-054 | [inv_test_sign](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1031) | Inverse result should keep operand's sign. | +| ABDKMATH-055 | [inv_test_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1050) | Inverse edge case: Inverse of zero should revert. | +| ABDKMATH-056 | [inv_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1060) | Inverse edge case: Inverse of maximum value should be close to zero. | +| ABDKMATH-057 | [inv_test_minimum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1073) | Inverse edge case: Inverse of minimum value should be close to zero. | +| ABDKMATH-058 | [avg_test_values_in_range](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1102) | Average result should be between operands. | +| ABDKMATH-059 | [avg_test_one_value](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1114) | Average of the same number twice is the number itself. | +| ABDKMATH-060 | [avg_test_operand_order](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1122) | Average result does not depend on the order of operands. | +| ABDKMATH-061 | [avg_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1137) | Average edge case: Average of maximum value twice is the maximum value. | +| ABDKMATH-062 | [avg_test_minimum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1151) | Average edge case: Average of minimum value twice is the minimum value. | +| ABDKMATH-063 | [gavg_test_values_in_range](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1181) | Geometric average result should be between operands. | +| ABDKMATH-064 | [gavg_test_one_value](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1197) | Geometric average of the same number twice is the number itself. | +| ABDKMATH-065 | [gavg_test_operand_order](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1205) | Geometric average result does not depend on the order of operands. | +| ABDKMATH-066 | [gavg_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1220) | Geometric average edge case: Average of maximum value twice is the maximum value. | +| ABDKMATH-067 | [gavg_test_minimum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1234) | Geometric average edge case: Average of minimum value twice is the minimum value. | +| ABDKMATH-068 | [pow_test_zero_exponent](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1264) | Power of zero should be one. | +| ABDKMATH-069 | [pow_test_zero_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1272) | Zero to the power of any number should be zero. | +| ABDKMATH-070 | [pow_test_one_exponent](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1282) | Power of one should be equal to the operand. | +| ABDKMATH-071 | [pow_test_base_one](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1290) | One to the power of any number should be one. | +| ABDKMATH-072 | [pow_test_product_same_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1298) | Product of powers of the same base property | +| ABDKMATH-073 | [pow_test_power_of_an_exponentiation](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1310) | Power of an exponentiation property | +| ABDKMATH-074 | [pow_test_product_same_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1322) | Distributive property for power of a product | +| ABDKMATH-075 | [pow_test_values](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1336) | Power result should increase or decrease (in absolute value) depending on exponent's absolute value. | +| ABDKMATH-076 | [pow_test_sign](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1352) | Power result sign should change according to the exponent sign. | +| ABDKMATH-077 | [pow_test_maximum_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1382) | Power edge case: Power of the maximum value should revert if exponent > 1. | +| ABDKMATH-078 | [pow_test_high_exponent](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1394) | Power edge case: Result should be zero if base is small and exponent is large. | +| ABDKMATH-079 | [sqrt_test_inverse_mul](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1418) | Square root inverse as multiplication. | +| ABDKMATH-080 | [sqrt_test_inverse_pow](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1430) | Square root inverse as power. | +| ABDKMATH-081 | [sqrt_test_distributive](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1442) | Square root distributive property respect to multiplication. | +| ABDKMATH-082 | [sqrt_test_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1465) | Square root edge case: square root of zero should be zero. | +| ABDKMATH-083 | [sqrt_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1470) | Square root edge case: square root of maximum value should not revert. | +| ABDKMATH-084 | [sqrt_test_minimum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1481) | Square root edge case: square root of minimum value should revert (negative). | +| ABDKMATH-085 | [sqrt_test_negative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1491) | Square root edge case: square root of a negative value should revert. | +| ABDKMATH-086 | [log2_test_distributive_mul](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1518) | Base-2 logarithm distributive property respect to multiplication. | +| ABDKMATH-087 | [log2_test_power](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1538) | Base-2 logarithm of a power property. | +| ABDKMATH-088 | [log2_test_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1555) | Base-2 logarithm edge case: Logarithm of zero should revert. | +| ABDKMATH-089 | [log2_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1565) | Base-2 logarithm edge case: Logarithm of maximum value should not revert. | +| ABDKMATH-090 | [log2_test_negative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1579) | Base-2 logarithm edge case: Logarithm of a negative value should revert. | +| ABDKMATH-091 | [ln_test_distributive_mul](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1606) | Natural logarithm distributive property respect to multiplication. | +| ABDKMATH-092 | [ln_test_power](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1627) | Natural logarithm of a power property. | +| ABDKMATH-093 | [ln_test_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1644) | Natural logarithm edge case: Logarithm of zero should revert. | +| ABDKMATH-094 | [ln_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1654) | Natural logarithm edge case: Logarithm of maximum value should not revert. | +| ABDKMATH-095 | [ln_test_negative](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1668) | Natural logarithm edge case: Logarithm of a negative value should revert. | +| ABDKMATH-096 | [exp2_test_equivalence_pow](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1695) | Base-2 exponentiation should be equal to power. | +| ABDKMATH-097 | [exp2_test_inverse](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1704) | Base-2 exponentiation inverse function. | +| ABDKMATH-098 | [exp2_test_negative_exponent](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1719) | Base-2 exponentiation with negative exponent should equal the inverse. | +| ABDKMATH-099 | [exp2_test_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1737) | Base-2 exponentiation edge case: exponent zero result should be one. | +| ABDKMATH-100 | [exp2_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1744) | Base-2 exponentiation edge case: exponent maximum value should revert. | +| ABDKMATH-101 | [exp2_test_minimum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1755) | Base-2 exponentiation edge case: exponent minimum value result should be zero. | +| ABDKMATH-102 | [exp_test_inverse](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1784) | Natural exponentiation inverse function. | +| ABDKMATH-103 | [exp_test_negative_exponent](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1800) | Natural exponentiation with negative exponent should equal the inverse. | +| ABDKMATH-104 | [exp_test_zero](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1818) | Natural exponentiation edge case: exponent zero result should be one. | +| ABDKMATH-105 | [exp_test_maximum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1825) | Natural exponentiation edge case: exponent maximum value should revert. | +| ABDKMATH-106 | [exp_test_minimum](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1836) | Natural exponentiation edge case: exponent minimum value result should be zero. | diff --git a/lib/crytic/README.md b/lib/crytic/README.md new file mode 100644 index 0000000..a7c7f83 --- /dev/null +++ b/lib/crytic/README.md @@ -0,0 +1,427 @@ +# Table of contents + +- [Table of contents](#table-of-contents) +- [Properties](#properties) + - [Testing the properties with fuzzing](#testing-the-properties-with-fuzzing) + - [ERC20 tests](#erc20-tests) + - [ERC4626 Tests](#erc4626-tests) + - [ABDKMath64x64 tests](#abdkmath64x64-tests) + - [Additional resources](#additional-resources) +- [Helper functions](#helper-functions) + - [Usage examples](#usage-examples) + - [Logging](#logging) + - [Assertions](#assertions) + - [Clamping](#clamping) +- [HEVM cheat codes support](#hevm-cheat-codes-support) + - [Usage example](#usage-example) +- [Trophies](#trophies) +- [How to contribute to this repo?](#how-to-contribute-to-this-repo) + + +# Properties + +This repository contains 168 code properties for: + +- [ERC20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) token: mintable, burnable, pausable and transferable invariants ([25 properties](PROPERTIES.md#erc20)). +- [ERC4626](https://ethereum.org/en/developers/docs/standards/tokens/erc-4626/) vaults: strict specification and additional security invariants ([37 properties](PROPERTIES.md#erc4626)). +- [ABDKMath64x64](https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.md) fixed-point library invariants ([106 properties](PROPERTIES.md#abdkmath64x64)). + +The goals of these properties are to: +- Detect vulnerabilities +- Ensure adherence to relevant standards +- Provide educational guidance for writing invariants + +The properties can be used through unit tests or through fuzzing with [Echidna](https://github.com/crytic/echidna). + +## Testing the properties with fuzzing + +1. Install [Echidna](https://github.com/crytic/echidna#installation). +2. Import the properties into to your project: + - In case of using Hardhat, use: `npm install https://github.com/crytic/properties.git` or `yarn add https://github.com/crytic/properties.git` + - In case of using Foundry, use: `forge install crytic/properties` + +3. According to tests required, go the the specific sections: + - [ERC20 tests](#erc20-tests) + - [ERC4626 test](#erc4626-tests) + - [ABDKMath64x64 tests](#abdkmath64x64-tests) + +### ERC20 tests + +To test an ERC20 token, follow these steps: +1. [Integration](#integration) +2. [Configuration](#configuration) +3. [Run](#run) + +You can see the output for a [compliant token](#example-output-for-a-compliant-token), and [non compliant token](#example-output-for-a-non-compliant-token). + +#### Integration +Decide if you want to do internal or external testing. Both approaches have advantanges and disadvantages, you can check more information about them [here](https://secure-contracts.com/program-analysis/echidna/basic/common-testing-approaches.html). + +For internal testing, create a new Solidity file containing the `CryticERC20InternalHarness` contract. `USER1`, `USER2` and `USER3` constants are initialized by default in `PropertiesConstants` contract to be the addresses from where echidna sends transactions, and `INITIAL_BALANCE` is by default `1000e18`: +```Solidity +pragma solidity ^0.8.0; +import "@crytic/properties/contracts/ERC20/internal/properties/ERC20BasicProperties.sol"; +import "./MyToken.sol"; +contract CryticERC20InternalHarness is MyToken, CryticERC20BasicProperties { + + constructor() { + // Setup balances for USER1, USER2 and USER3: + _mint(USER1, INITIAL_BALANCE); + _mint(USER2, INITIAL_BALANCE); + _mint(USER3, INITIAL_BALANCE); + // Setup total supply: + initialSupply = totalSupply(); + } +} +``` + +For external testing, create two contracts: the `CryticERC20ExternalHarness` and the `TokenMock` as shown below. +In the `CryticERC20ExternalHarness` contract you can specify which properties to test, via inheritance. In the `TokenMock` contract, you will need to modify the `isMintableOrBurnable` variable if your contract is able to mint or burn tokens. + +```Solidity +pragma solidity ^0.8.0; +import "./MyToken.sol"; +import {ITokenMock} from "@crytic/properties/contracts/ERC20/external/util/ITokenMock.sol"; +import {CryticERC20ExternalBasicProperties} from "@crytic/properties/contracts/ERC20/external/properties/ERC20ExternalBasicProperties.sol"; +import {PropertiesConstants} from "@crytic/properties/contracts/util/PropertiesConstants.sol"; + + +contract CryticERC20ExternalHarness is CryticERC20ExternalBasicProperties { + constructor() { + // Deploy ERC20 + token = ITokenMock(address(new CryticTokenMock())); + } +} + +contract CryticTokenMock is MyToken, PropertiesConstants { + + bool public isMintableOrBurnable; + uint256 public initialSupply; + constructor () { + _mint(USER1, INITIAL_BALANCE); + _mint(USER2, INITIAL_BALANCE); + _mint(USER3, INITIAL_BALANCE); + _mint(msg.sender, INITIAL_BALANCE); + + initialSupply = totalSupply(); + isMintableOrBurnable = true; + } +} +``` + +#### Configuration +Create the following Echidna config file + +```yaml +corpusDir: "tests/crytic/erc20/echidna-corpus-internal" +testMode: assertion +testLimit: 100000 +deployer: "0x10000" +sender: ["0x10000", "0x20000", "0x30000"] +``` + +If you're using external testing, you will also need to specify: + +```yaml +multi-abi: true +``` + +To perform more than one test, save the files with a descriptive path, to identify what test each file or corpus belongs to. For these examples, we use `tests/crytic/erc20/echidna-internal.yaml` and `tests/crytic/erc20/echidna-external.yaml` for the Echidna tests for ERC20. We recommended to modify the `corpusDir` for external tests accordingly. + +The above configuration will start Echidna in assertion mode. Contract will be deployed from address `0x10000`, and transactions will be sent from the owner and two different users (`0x20000` and `0x30000`). There is an initial limit of `100000` tests, but depending on the token code complexity, this can be increased. Finally, once Echidna finishes the fuzzing campaign, corpus and coverage results will be available in the `tests/crytic/erc20/echidna-corpus-internal` directory. + + +#### Run +Run Echidna: +- For internal testing: `echidna-test . --contract CryticERC20InternalHarness --config tests/crytic/erc20/echidna-internal.yaml` +- For external testing: `echidna-test . --contract CryticERC20ExternalHarness --config tests/crytic/erc20/echidna-external.yaml` + +Finally, inspect the coverage report in `tests/crytic/erc20/echidna-corpus-internal` or `tests/crytic/erc20/echidna-corpus-external` when it finishes. + +#### Example: Output for a compliant token + +If the token under test is compliant and no properties will fail during fuzzing, the Echidna output should be similar to the screen below: +``` +$ echidna-test . --contract CryticERC20InternalHarness --config tests/echidna.config.yaml +Loaded total of 23 transactions from corpus/coverage +Analyzing contract: contracts/ERC20/CryticERC20InternalHarness.sol:CryticERC20InternalHarness +name(): passed! 🎉 +test_ERC20_transferFromAndBurn(): passed! 🎉 +approve(address,uint256): passed! 🎉 +test_ERC20_userBalanceNotHigherThanSupply(): passed! 🎉 +totalSupply(): passed! 🎉 +... +``` + +#### Example: Output for a non-compliant token + +For this example, the ExampleToken's approval function was modified to perform no action: +``` +function approve(address spender, uint256 amount) public virtual override(ERC20) returns (bool) { + // do nothing + return true; +} +``` + +In this case, the Echidna output should be similar to the screen below, notice that all functions that rely on `approve()` to work correctly will have their assertions broken, and will report the situation. +``` +$ echidna-test . --contract CryticERC20ExternalHarness --config tests/echidna.config.yaml +Loaded total of 25 transactions from corpus/coverage +Analyzing contract: contracts/ERC20/CryticERC20ExternalHarness.sol:CryticERC20ExternalHarness +name(): passed! 🎉 +test_ERC20_transferFromAndBurn(): passed! 🎉 +approve(address,uint256): passed! 🎉 +... +test_ERC20_setAllowance(): failed!💥 + Call sequence: + test_ERC20_setAllowance() + +Event sequence: Panic(1), AssertEqFail("Equal assertion failed. Message: Failed to set allowance") from: ERC20PropertyTests@0x00a329c0648769A73afAc7F9381E08FB43dBEA72 +... +``` + +### ERC4626 Tests + +To test an ERC4626 token, follow these steps: +1. [Integration](#integration-1) +2. [Configuration](#configuration-1) +3. [Run](#run-1) + + +#### Integration + +Create a new Solidity file containing the `CryticERC4626Harness` contract. Make sure it properly initializes your ERC4626 vault with a test token (`TestERC20Token`): + +If you are using Hardhat: + +```Solidity + import {CryticERC4626PropertyTests} from "@crytic/properties/contracts/ERC4626/ERC4626PropertyTests.sol"; + // this token _must_ be the vault's underlying asset + import {TestERC20Token} from "@crytic/properties/contracts/ERC4626/util/TestERC20Token.sol"; + // change to your vault implementation + import "./Basic4626Impl.sol"; + + contract CryticERC4626Harness is CryticERC4626PropertyTests { + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + Basic4626Impl _vault = new Basic4626Impl(_asset); + initialize(address(_vault), address(_asset), false); + } + } +``` + +If you are using Foundry: + +```Solidity + import {CryticERC4626PropertyTests} from "properties/ERC4626/ERC4626PropertyTests.sol"; + // this token _must_ be the vault's underlying asset + import {TestERC20Token} from "properties/ERC4626/util/TestERC20Token.sol"; + // change to your vault implementation + import "../src/Basic4626Impl.sol"; + + contract CryticERC4626Harness is CryticERC4626PropertyTests { + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + Basic4626Impl _vault = new Basic4626Impl(_asset); + initialize(address(_vault), address(_asset), false); + } + } +``` + +#### Configuration +Create a minimal Echidna config file (e.g. `tests/echidna.config.yaml`) + +```yaml +corpusDir: "tests/echidna-corpus" +testMode: assertion +testLimit: 100000 +deployer: "0x10000" +sender: ["0x10000"] +``` + +#### Run +Run the test suite using `echidna-test . --contract CryticERC4626Harness --config tests/echidna.config.yaml` and inspect the coverage report in `tests/echidna-corpus` when it finishes. + +Example repositories are available for [Hardhat](tests/ERC4626/hardhat) and [Foundry](tests/ERC4626/foundry). + +Once things are up and running, consider adding internal testing methods to your Vault ABI to allow testing special edge case properties like rounding. For more info, see the [ERC4626 readme](contracts/ERC4626/README.md#adding-internal-test-methods). + +### ABDKMath64x64 tests + +The Solidity smart contract programming language does not have any inbuilt feature for working with decimal numbers, so for contracts dealing with non-integer values, a third party solution is needed. [ABDKMath64x64](https://github.com/abdk-consulting/abdk-libraries-solidity) is a fixed-point arithmetic Solidity library that operates on 64.64-bit numbers. + +A 64.64-bit fixed-point number is a data type that consists of a sign bit, a 63-bit integer part, and a 64bit decimal part. Since there is no direct support for fractional numbers in the EVM, the underlying data type that stores the values is a 128-bit signed integer. + +ABDKMath64x64 library implements [19 arithmetic operations](https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.md#simple-arithmetic "19 arithmetic operations") using fixed-point numbers and [6 conversion functions](https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.md#conversions "6 conversion functions") between integer types and fixed-point types. + +We provide a number of tests related with fundamental mathematical properties of the floating point numbers. To include these tests into your repository, follow these steps: +1. [Integration](#integration-2) +2. [Run](#run-2) + +#### Integration + +Create a new Solidity file containing the `ABDKMath64x64Harness` contract: + +```Solidity +pragma solidity ^0.8.0; +import "@crytic/properties/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol; + +contract CryticABDKMath64x64Harness is CryticABDKMath64x64PropertyTests { + /* Any additional test can be added here */ +} +``` + +#### Run +Run the test suite using `echidna-test . --contract CryticABDKMath64x64Harness --seq-len 1 --test-mode assertion --corpus-dir tests/echidna-corpus` and inspect the coverage report in `tests/echidna-corpus` when it finishes. + + +## Additional resources + +- [Building secure contracts](https://secure-contracts.com/program-analysis/index.html) +- Our [EmpireSlacking](https://empireslacking.herokuapp.com/) slack server, channel #ethereum +- Watch our [fuzzing workshop](https://www.youtube.com/watch?v=QofNQxW_K08&list=PLciHOL_J7Iwqdja9UH4ZzE8dP1IxtsBXI) + + +# Helper functions + +The repository provides a collection of functions and events meant to simplify the debugging and testing of assertions in Echidna. Commonly used functions, such as integer clamping or logging for different types are available in [contracts/util/PropertiesHelper.sol](contracts/util/PropertiesHelper.sol). + +Available helpers: +- `LogXxx`: Events that can be used to log values in fuzzing tests. `string`, `uint256` and `address` loggers are provided. In Echidna's assertion mode, when an assertion violation is detected, all events emitted in the call sequence are printed. +- `assertXxx`: Asserts that a condition is met, logging violations. Assertions for equality, non-equality, greater-than, greater-than-or-equal, less-than and less-than-or-equal comparisons are provided, and user-provided messages are supported for logging. +- `clampXxx`: Limits an `int256` or `uint256` to a certain range. Clamps for less-than, less-than-or-equal, greater-than, greater-than-or-equal, and range are provided. + +## Usage examples + +### Logging + +Log a value for debugging. When the assertion is violated, the value of `someValue` will be printed: + +```solidity +pragma solidity ^0.8.0; + +import "@crytic/properties/contracts/util/PropertiesHelper.sol"; + +contract TestProperties is PropertiesAsserts { + + // ... + + function test_some_invariant(uint256 someValue) public { + // ... + + LogUint256("someValue is: ", someValue); + + // ... + + assert(fail); + + // ... + } + + // ... + +} + +``` + +### Assertions + +Assert equality, and log violations: + +```solidity +pragma solidity ^0.8.0; + +import "@crytic/properties/contracts/util/PropertiesHelper.sol"; + +contract TestProperties is PropertiesAsserts { + + // ... + + function test_some_invariant(uint256 someValue) public { + // ... + + assertEq(someValue, 25, "someValue doesn't have the correct value"); + + // ... + } + + // ... + +} + +``` + +In case this assertion fails, for example if `someValue` is 30, the following will be printed in Echidna: + +`Invalid: 30!=25, reason: someValue doesn't have the correct value` + + +### Clamping + +Assure that a function's fuzzed parameter is in a certain range: + +```solidity +pragma solidity ^0.8.0; + +import "@crytic/properties/contracts/util/PropertiesHelper.sol"; + +contract TestProperties is PropertiesAsserts { + + int256 constant MAX_VALUE = 2**160; + int256 constant MIN_VALUE = -2**24; + + // ... + + function test_some_invariant(int256 someValue) public { + someValue = clampBetween(someValue, MIN_VALUE, MAX_VALUE); + + // ... + } + + // ... + +} + +``` + +# HEVM cheat codes support + +Since version 2.0.5, Echidna supports [HEVM cheat codes](https://hevm.dev/controlling-the-unit-testing-environment.html#cheat-codes). This repository contains a [`Hevm.sol`](contracts/util/Hevm.sol) contract that exposes cheat codes for easy integration into contracts under test. + +Cheat codes should be used with care, since they can alter the execution environment in ways that are not expected, and may introduce false positives or false negatives. + +## Usage example + +Use `prank` to simulate a call from a different `msg.sender`: + +```solidity +pragma solidity ^0.8.0; + +import "@crytic/properties/contracts/util/Hevm.sol"; + +contract TestProperties { + + // ... + + function test_some_invariant(uint256 someValue) public { + // ... + + hevm.prank(newSender); + otherContract.someFunction(someValue); // This call's msg.sender will be newSender + otherContract.someFunction(someValue); // This call's msg.sender will be address(this) + + // ... + } + + // ... + +} + +``` + +# Trophies + +A list of security vulnerabilities that were found using the properties can be found on the [trophies page](Trophies.md#properties-trophies). + +# How to contribute to this repo? +Contributions are welcome! You can read more about the contribution guidelines and directory structure in the [CONTRIBUTING.md](CONTRIBUTING.md) file. diff --git a/lib/crytic/Trophies.md b/lib/crytic/Trophies.md new file mode 100644 index 0000000..3699696 --- /dev/null +++ b/lib/crytic/Trophies.md @@ -0,0 +1,10 @@ +# Properties Trophies + +The following lists security vulnerabilities that were found using the properties. +If you found a security vulnerability using crytic/properties, +please submit a PR with the relevant information. + +| Project | Vulnerability | Date | +|--|--|--| +[Pods Finance](https://github.com/pods-finance/yield-contracts/blob/main/audits/2022-11-15_OpenZeppelin_Pods.pdf) | C-03 The vault can be drained one share at a time | March 2023 +[Pods Finance](https://github.com/pods-finance/yield-contracts/blob/main/audits/2022-11-15_OpenZeppelin_Pods.pdf) | H-03 Rounding up in minting shares | March 2023 \ No newline at end of file diff --git a/lib/crytic/contracts/ERC20/external/ERC20ExternalPropertyTests.sol b/lib/crytic/contracts/ERC20/external/ERC20ExternalPropertyTests.sol new file mode 100644 index 0000000..1570cb6 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/ERC20ExternalPropertyTests.sol @@ -0,0 +1,19 @@ +pragma solidity ^0.8.0; + +import "./TokenMock.sol"; +import {ITokenMock} from "./util/ITokenMock.sol"; +import {CryticERC20ExternalBasicProperties} from "./properties/ERC20ExternalBasicProperties.sol"; +import {CryticERC20ExternalBurnableProperties} from "./properties/ERC20ExternalBurnableProperties.sol"; +import {CryticERC20ExternalMintableProperties} from "./properties/ERC20ExternalMintableProperties.sol"; +import {CryticERC20ExternalPausableProperties} from "./properties/ERC20ExternalPausableProperties.sol"; +import {CryticERC20ExternalIncreaseAllowanceProperties} from "./properties/ERC20ExternalIncreaseAllowanceProperties.sol"; + +contract CryticERC20ExternalPropertyTests is CryticERC20ExternalBasicProperties, CryticERC20ExternalIncreaseAllowanceProperties, CryticERC20ExternalBurnableProperties, CryticERC20ExternalMintableProperties, CryticERC20ExternalPausableProperties { + + constructor() { + // Deploy ERC20, mint initial balance to users (deployer is address(this)) + // If the token is mintable or burnable, the argument must be true. False otherwise. + token = ITokenMock(address(new TokenMock(true))); + } + +} diff --git a/lib/crytic/contracts/ERC20/external/ExampleToken.sol b/lib/crytic/contracts/ERC20/external/ExampleToken.sol new file mode 100644 index 0000000..6458891 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/ExampleToken.sol @@ -0,0 +1,61 @@ +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; +import "@openzeppelin/contracts/security/Pausable.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract ExampleToken is ERC20, ERC20Burnable, Pausable, Ownable { + constructor() ERC20("Example token", "EXT") {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function mint(address to, uint256 amount) public virtual onlyOwner { + _mint(to, amount); + } + + function _beforeTokenTransfer(address from, address to, uint256 amount) + internal + virtual + whenNotPaused + override + { + super._beforeTokenTransfer(from, to, amount); + } +} + +contract ExampleTokenNonCompliant is ERC20, ERC20Burnable, Pausable, Ownable { + constructor() ERC20("Example token", "EXT") {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function approve(address, uint256) public virtual override(ERC20) returns (bool) { + // do nothing + return true; + } + + function mint(address to, uint256 amount) public virtual onlyOwner { + _mint(to, amount); + } + + function _beforeTokenTransfer(address from, address to, uint256 amount) + internal + virtual + whenNotPaused + override + { + super._beforeTokenTransfer(from, to, amount); + } +} \ No newline at end of file diff --git a/lib/crytic/contracts/ERC20/external/TokenMock.sol b/lib/crytic/contracts/ERC20/external/TokenMock.sol new file mode 100644 index 0000000..4920ab6 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/TokenMock.sol @@ -0,0 +1,20 @@ +pragma solidity ^0.8.0; + +import "../../util/PropertiesConstants.sol"; +import "./ExampleToken.sol"; + +contract TokenMock is ExampleToken, PropertiesConstants { + + bool public isMintableOrBurnable; + uint256 public initialSupply; + constructor (bool _isMintableOrBurnable) { + _mint(USER1, INITIAL_BALANCE); + _mint(USER2, INITIAL_BALANCE); + _mint(USER3, INITIAL_BALANCE); + _mint(msg.sender, INITIAL_BALANCE); + + initialSupply = totalSupply(); + isMintableOrBurnable = _isMintableOrBurnable; + } + +} diff --git a/lib/crytic/contracts/ERC20/external/echidna.config.yaml b/lib/crytic/contracts/ERC20/external/echidna.config.yaml new file mode 100644 index 0000000..4603034 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/echidna.config.yaml @@ -0,0 +1,7 @@ +coverage: true +multi-abi: true +corpusDir: "corpus" +testMode: assertion +testLimit: 100000 +deployer: "0x10000" +sender: ["0x10000", "0x20000", "0x30000"] \ No newline at end of file diff --git a/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalBasicProperties.sol b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalBasicProperties.sol new file mode 100644 index 0000000..e6c634d --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalBasicProperties.sol @@ -0,0 +1,193 @@ +pragma solidity ^0.8.0; + +import {CryticERC20ExternalTestBase} from "../util/ERC20ExternalTestBase.sol"; + +abstract contract CryticERC20ExternalBasicProperties is CryticERC20ExternalTestBase { + constructor() { + + } + + //////////////////////////////////////// + // Properties + + // Total supply should change only by means of mint or burn + function test_ERC20external_constantSupply() public virtual { + require(!token.isMintableOrBurnable()); + assertEq(token.initialSupply(), token.totalSupply(), "Token supply was modified"); + } + + // User balance must not exceed total supply + function test_ERC20external_userBalanceNotHigherThanSupply() public { + assertLte(token.balanceOf(msg.sender), token.totalSupply(), "User balance higher than total supply"); + } + + // Sum of users balance must not exceed total supply + function test_ERC20external_userBalancesLessThanTotalSupply() public { + uint256 sumBalances = token.balanceOf(address(this)) + token.balanceOf(USER1) + token.balanceOf(USER2) + token.balanceOf(USER3); + assertLte(sumBalances, token.totalSupply(), "Sum of user balances are greater than total supply"); + } + + // Address zero should have zero balance + function test_ERC20external_zeroAddressBalance() public { + assertEq(token.balanceOf(address(0)), 0, "Address zero balance not equal to zero"); + } + + // Transfers to zero address should not be allowed + function test_ERC20external_transferToZeroAddress() public { + uint256 balance = token.balanceOf(address(this)); + require(balance > 0); + + bool r = token.transfer(address(0), balance); + assertWithMsg(r == false, "Successful transfer to address zero"); + } + + // Transfers to zero address should not be allowed + function test_ERC20external_transferFromToZeroAddress(uint256 value) public { + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 0 && allowance > 0); + uint256 maxValue = balance_sender >= allowance ? allowance : balance_sender; + + bool r = token.transferFrom(msg.sender, address(0), value % (maxValue + 1)); + assertWithMsg(r == false, "Successful transferFrom to address zero"); + } + + // Self transfers should not break accounting + function test_ERC20external_selfTransferFrom(uint256 value) public { + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 0 && allowance > 0); + uint256 maxValue = balance_sender >= allowance ? allowance : balance_sender; + + bool r = token.transferFrom(msg.sender, msg.sender, value % (maxValue + 1)); + assertWithMsg(r == true, "Failed self transferFrom"); + assertEq(balance_sender, token.balanceOf(msg.sender), "Self transferFrom breaks accounting"); + } + + // Self transfers should not break accounting + function test_ERC20external_selfTransfer(uint256 value) public { + uint256 balance_sender = token.balanceOf(address(this)); + require(balance_sender > 0); + + bool r = token.transfer(address(this), value % (balance_sender + 1)); + assertWithMsg(r == true, "Failed self transfer"); + assertEq(balance_sender, token.balanceOf(address(this)), "Self transfer breaks accounting"); + } + + // Transfers for more than available balance should not be allowed + function test_ERC20external_transferFromMoreThanBalance(address target) public { + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 balance_receiver = token.balanceOf(target); + uint256 allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 0 && allowance > balance_sender); + + bool r = token.transferFrom(msg.sender, target, balance_sender+1); + assertWithMsg(r == false, "Successful transferFrom for more than account balance"); + assertEq(token.balanceOf(msg.sender), balance_sender, "TransferFrom for more than balance modified source balance"); + assertEq(token.balanceOf(target), balance_receiver, "TransferFrom for more than balance modified target balance"); + } + + // Transfers for more than available balance should not be allowed + function test_ERC20external_transferMoreThanBalance(address target) public { + uint256 balance_sender = token.balanceOf(address(this)); + uint256 balance_receiver = token.balanceOf(target); + require(balance_sender > 0); + + bool r = token.transfer(target, balance_sender+1); + assertWithMsg(r == false, "Successful transfer for more than account balance"); + assertEq(token.balanceOf(address(this)), balance_sender, "Transfer for more than balance modified source balance"); + assertEq(token.balanceOf(target), balance_receiver, "Transfer for more than balance modified target balance"); + } + + // Zero amount transfers should not break accounting + function test_ERC20external_transferZeroAmount(address target) public { + uint256 balance_sender = token.balanceOf(address(this)); + uint256 balance_receiver = token.balanceOf(target); + require(balance_sender > 0); + + bool r = token.transfer(target, 0); + assertWithMsg(r == true, "Zero amount transfer failed"); + assertEq(token.balanceOf(address(this)), balance_sender, "Zero amount transfer modified source balance"); + assertEq(token.balanceOf(target), balance_receiver, "Zero amount transfer modified target balance"); + } + + // Zero amount transfers should not break accounting + function test_ERC20external_transferFromZeroAmount(address target) public { + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 balance_receiver = token.balanceOf(target); + uint256 allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 0 && allowance > 0); + + bool r = token.transferFrom(msg.sender, target, 0); + assertWithMsg(r == true, "Zero amount transferFrom failed"); + assertEq(token.balanceOf(msg.sender), balance_sender, "Zero amount transferFrom modified source balance"); + assertEq(token.balanceOf(target), balance_receiver, "Zero amount transferFrom modified target balance"); + } + + // Transfers should update accounting correctly + function test_ERC20external_transfer(address target, uint256 amount) public { + require(target != address(this)); + uint256 balance_sender = token.balanceOf(address(this)); + uint256 balance_receiver = token.balanceOf(target); + require(balance_sender > 2); + uint256 transfer_value = (amount % balance_sender) + 1; + + bool r = token.transfer(target, transfer_value); + assertWithMsg(r == true, "transfer failed"); + assertEq(token.balanceOf(address(this)), balance_sender-transfer_value, "Wrong source balance after transfer"); + assertEq(token.balanceOf(target), balance_receiver+transfer_value, "Wrong target balance after transfer"); + } + + // Transfers should update accounting correctly + function test_ERC20external_transferFrom(address target, uint256 amount) public { + require(target != address(this)); + require(target != msg.sender); + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 balance_receiver = token.balanceOf(target); + uint256 allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 2 && allowance > balance_sender); + uint256 transfer_value = (amount % balance_sender) + 1; + + bool r = token.transferFrom(msg.sender, target, transfer_value); + assertWithMsg(r == true, "transfer failed"); + assertEq(token.balanceOf(msg.sender), balance_sender - transfer_value, "Wrong source balance after transferFrom"); + assertEq(token.balanceOf(target), balance_receiver + transfer_value, "Wrong target balance after transferFrom"); + } + + // Approve should set correct allowances + function test_ERC20external_setAllowance(address target, uint256 amount) public { + bool r = token.approve(target, amount); + assertWithMsg(r == true, "Failed to set allowance via approve"); + assertEq(token.allowance(address(this), target), amount, "Allowance not set correctly"); + } + + // Approve should set correct allowances + function test_ERC20external_setAllowanceTwice(address target, uint256 amount) public { + bool r = token.approve(target, amount); + assertWithMsg(r == true, "Failed to set allowance via approve"); + assertEq(token.allowance(address(this), target), amount, "Allowance not set correctly"); + + r = token.approve(target, amount/2); + assertWithMsg(r == true, "Failed to set allowance via approve"); + assertEq(token.allowance(address(this), target), amount/2, "Allowance not set correctly"); + } + + // TransferFrom should decrease allowance + function test_ERC20external_spendAllowanceAfterTransfer(address target, uint256 amount) public { + require(target != address(this) && target != address(0)); + require(target != msg.sender); + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 current_allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 0 && current_allowance > balance_sender); + uint256 transfer_value = (amount % balance_sender) + 1; + + bool r = token.transferFrom(msg.sender, target, transfer_value); + assertWithMsg(r == true, "transferFrom failed"); + + // Some implementations take an allowance of 2**256-1 as infinite, and therefore don't update + if (current_allowance != type(uint256).max) { + assertEq(token.allowance(msg.sender, address(this)), current_allowance - transfer_value, "Allowance not updated correctly"); + } + } + +} diff --git a/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalBurnableProperties.sol b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalBurnableProperties.sol new file mode 100644 index 0000000..6baf269 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalBurnableProperties.sol @@ -0,0 +1,54 @@ +pragma solidity ^0.8.0; + +import "../util/ERC20ExternalTestBase.sol"; + +abstract contract CryticERC20ExternalBurnableProperties is CryticERC20ExternalTestBase { + + constructor() { + + } + + //////////////////////////////////////// + // Properties + + // Burn should update user balance and total supply + function test_ERC20external_burn(uint256 amount) public { + uint256 balance_sender = token.balanceOf(address(this)); + uint256 supply = token.totalSupply(); + require(balance_sender > 0); + uint256 burn_amount = amount % (balance_sender+1); + + token.burn(burn_amount); + assertEq(token.balanceOf(address(this)), balance_sender - burn_amount, "Source balance incorrect after burn"); + assertEq(token.totalSupply(), supply-burn_amount, "Total supply incorrect after burn"); + } + + // Burn should update user balance and total supply + function test_ERC20external_burnFrom(uint256 amount) public { + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 0 && allowance > balance_sender); + uint256 supply = token.totalSupply(); + uint256 burn_amount = amount % (balance_sender+1); + + token.burnFrom(msg.sender, burn_amount); + assertEq(token.balanceOf(msg.sender), balance_sender - burn_amount, "Source balance incorrect after burnFrom"); + assertEq(token.totalSupply(), supply-burn_amount, "Total supply incorrect after burnFrom"); + } + + // burnFrom should update allowance + function test_ERC20external_burnFromUpdateAllowance(uint256 amount) public { + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 current_allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 0 && current_allowance > balance_sender); + uint256 burn_amount = amount % (balance_sender+1); + + token.burnFrom(msg.sender, burn_amount); + + // Some implementations take an allowance of 2**256-1 as infinite, and therefore don't update + if (current_allowance != type(uint256).max) { + assertEq(token.allowance(msg.sender, address(this)), current_allowance - burn_amount, "Allowance not updated correctly"); + } + } + +} diff --git a/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalIncreaseAllowanceProperties.sol b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalIncreaseAllowanceProperties.sol new file mode 100644 index 0000000..abeae99 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalIncreaseAllowanceProperties.sol @@ -0,0 +1,36 @@ +pragma solidity ^0.8.0; + +import "../util/ERC20ExternalTestBase.sol"; + +abstract contract CryticERC20ExternalIncreaseAllowanceProperties is CryticERC20ExternalTestBase { + + constructor() { + + } + + //////////////////////////////////////// + // Properties + + // Allowance should be modified correctly via increase/decrease + function test_ERC20external_setAndIncreaseAllowance(address target, uint256 initialAmount, uint256 increaseAmount) public { + bool r = token.approve(target, initialAmount); + assertWithMsg(r == true, "Failed to set initial allowance via approve"); + assertEq(token.allowance(address(this), target), initialAmount, "Allowance not set correctly"); + + r = token.increaseAllowance(target, increaseAmount); + assertWithMsg(r == true, "Failed to increase allowance"); + assertEq(token.allowance(address(this), target), initialAmount+increaseAmount, "Allowance not increased correctly"); + } + + // Allowance should be modified correctly via increase/decrease + function test_ERC20external_setAndDecreaseAllowance(address target, uint256 initialAmount, uint256 decreaseAmount) public { + bool r = token.approve(target, initialAmount); + assertWithMsg(r == true, "Failed to set initial allowance via approve"); + assertEq(token.allowance(address(this), target), initialAmount, "Allowance not set correctly"); + + r = token.decreaseAllowance(target, decreaseAmount); + assertWithMsg(r == true, "Failed to decrease allowance"); + assertEq(token.allowance(address(this), target), initialAmount-decreaseAmount, "Allowance not decreased correctly"); + } + +} diff --git a/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalMintableProperties.sol b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalMintableProperties.sol new file mode 100644 index 0000000..548b7a5 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalMintableProperties.sol @@ -0,0 +1,23 @@ +pragma solidity ^0.8.0; + +import "../util/ERC20ExternalTestBase.sol"; + +abstract contract CryticERC20ExternalMintableProperties is CryticERC20ExternalTestBase { + + constructor() { + + } + + //////////////////////////////////////// + // Properties + + // Minting tokens should update user balance and total supply + function test_ERC20external_mintTokens(address target, uint256 amount) public { + uint256 balance_receiver = token.balanceOf(target); + uint256 supply = token.totalSupply(); + + token.mint(target, amount); + assertEq(token.balanceOf(target), balance_receiver+amount, "Mint failed to update target balance"); + assertEq(token.totalSupply(), supply+amount, "Mint failed to update total supply"); + } +} diff --git a/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalPausableProperties.sol b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalPausableProperties.sol new file mode 100644 index 0000000..86ecc72 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/properties/ERC20ExternalPausableProperties.sol @@ -0,0 +1,54 @@ +pragma solidity ^0.8.0; + +import "../util/ERC20ExternalTestBase.sol"; +import "../../../util/Hevm.sol"; + +abstract contract CryticERC20ExternalPausableProperties is CryticERC20ExternalTestBase { + + constructor() { + + } + + //////////////////////////////////////// + // Properties + + // Transfers should not be possible during paused state + function test_ERC20external_pausedTransfer(address target, uint256 amount) public { + uint256 balance_sender = token.balanceOf(address(this)); + uint256 balance_receiver = token.balanceOf(target); + require(balance_sender > 0); + uint256 transfer_amount = amount % (balance_sender+1); + + hevm.prank(token.owner()); + token.pause(); + + bool r = token.transfer(target, transfer_amount); + assertWithMsg(r == false, "Tokens transferred while paused"); + assertEq(token.balanceOf(address(this)), balance_sender, "Transfer while paused altered source balance"); + assertEq(token.balanceOf(target), balance_receiver, "Transfer while paused altered target balance"); + + hevm.prank(token.owner()); + token.unpause(); + } + + // Transfers should not be possible during paused state + function test_ERC20external_pausedTransferFrom(address target, uint256 amount) public { + uint256 balance_sender = token.balanceOf(msg.sender); + uint256 balance_receiver = token.balanceOf(target); + uint256 allowance = token.allowance(msg.sender, address(this)); + require(balance_sender > 0 && allowance > balance_sender); + uint256 transfer_amount = amount % (balance_sender+1); + + hevm.prank(token.owner()); + token.pause(); + + bool r = token.transferFrom(msg.sender, target, transfer_amount); + assertWithMsg(r == false, "Tokens transferred while paused"); + assertEq(token.balanceOf(msg.sender), balance_sender, "Transfer while paused altered source balance"); + assertEq(token.balanceOf(target), balance_receiver, "Transfer while paused altered target balance"); + + hevm.prank(token.owner()); + token.unpause(); + } + +} diff --git a/lib/crytic/contracts/ERC20/external/util/ERC20ExternalTestBase.sol b/lib/crytic/contracts/ERC20/external/util/ERC20ExternalTestBase.sol new file mode 100644 index 0000000..86781fc --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/util/ERC20ExternalTestBase.sol @@ -0,0 +1,14 @@ +pragma solidity ^0.8.0; + +import "../../../util/PropertiesHelper.sol"; +import "./ITokenMock.sol"; +import "../../../util/PropertiesConstants.sol"; + +abstract contract CryticERC20ExternalTestBase is PropertiesAsserts, PropertiesConstants { + + ITokenMock token; + + constructor() { + } + +} diff --git a/lib/crytic/contracts/ERC20/external/util/ITokenMock.sol b/lib/crytic/contracts/ERC20/external/util/ITokenMock.sol new file mode 100644 index 0000000..39a24b0 --- /dev/null +++ b/lib/crytic/contracts/ERC20/external/util/ITokenMock.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.8.0; + +import "../../../util/IERC20.sol"; + +interface ITokenMock is IERC20 { + function isMintableOrBurnable() external returns (bool); + function initialSupply() external returns (uint256); + + function burn(uint256) external; + function burnFrom(address, uint256) external; + function mint(address, uint256) external; + function pause() external; + function unpause() external; + function paused() external returns (bool); + function owner() external returns (address); + function increaseAllowance(address, uint256) external returns (bool); + function decreaseAllowance(address, uint256) external returns (bool); +} \ No newline at end of file diff --git a/lib/crytic/contracts/ERC20/internal/echidna.config.yaml b/lib/crytic/contracts/ERC20/internal/echidna.config.yaml new file mode 100644 index 0000000..b5ab450 --- /dev/null +++ b/lib/crytic/contracts/ERC20/internal/echidna.config.yaml @@ -0,0 +1,6 @@ +coverage: true +corpusDir: "corpus" +testMode: assertion +testLimit: 100000 +deployer: "0x10000" +sender: ["0x10000", "0x20000", "0x30000"] \ No newline at end of file diff --git a/lib/crytic/contracts/ERC20/internal/properties/ERC20BasicProperties.sol b/lib/crytic/contracts/ERC20/internal/properties/ERC20BasicProperties.sol new file mode 100644 index 0000000..ca85933 --- /dev/null +++ b/lib/crytic/contracts/ERC20/internal/properties/ERC20BasicProperties.sol @@ -0,0 +1,194 @@ +pragma solidity ^0.8.13; + +import "../util/ERC20TestBase.sol"; + +abstract contract CryticERC20BasicProperties is CryticERC20Base { + + constructor() { + + } + + //////////////////////////////////////// + // Properties + + // Total supply should change only by means of mint or burn + function test_ERC20_constantSupply() public virtual { + require(!isMintableOrBurnable); + assertEq(initialSupply, totalSupply(), "Token supply was modified"); + } + + // User balance must not exceed total supply + function test_ERC20_userBalanceNotHigherThanSupply() public { + assertLte(balanceOf(msg.sender), totalSupply(), "User balance higher than total supply"); + } + + // Sum of users balance must not exceed total supply + function test_ERC20_usersBalancesNotHigherThanSupply() public { + uint256 balance = balanceOf(USER1) + balanceOf(USER2) + balanceOf(USER3); + assertLte(balance, totalSupply(), "Sum of user balances higher than total supply"); + } + + // Address zero should have zero balance + function test_ERC20_zeroAddressBalance() public { + assertEq(balanceOf(address(0)), 0, "Address zero balance not equal to zero"); + } + + // Transfers to zero address should not be allowed + function test_ERC20_transferToZeroAddress() public { + uint256 balance = balanceOf(address(this)); + require(balance > 0); + + bool r = transfer(address(0), balance); + assertWithMsg(r == false, "Successful transfer to address zero"); + } + + // Transfers to zero address should not be allowed + function test_ERC20_transferFromToZeroAddress(uint256 value) public { + uint256 balance_sender = balanceOf(msg.sender); + uint256 current_allowance = allowance(msg.sender, address(this)); + require(balance_sender > 0 && current_allowance > 0); + uint256 maxValue = balance_sender >= current_allowance ? current_allowance : balance_sender; + + bool r = transferFrom(msg.sender, address(0), value % (maxValue + 1)); + assertWithMsg(r == false, "Successful transferFrom to address zero"); + } + + // Self transfers should not break accounting + function test_ERC20_selfTransferFrom(uint256 value) public { + uint256 balance_sender = balanceOf(msg.sender); + uint256 current_allowance = allowance(msg.sender, address(this)); + require(balance_sender > 0 && current_allowance > 0); + uint256 maxValue = balance_sender >= current_allowance ? current_allowance : balance_sender; + + bool r = transferFrom(msg.sender, msg.sender, value % (maxValue + 1)); + assertWithMsg(r == true, "Failed self transferFrom"); + assertEq(balance_sender, balanceOf(msg.sender), "Self transferFrom breaks accounting"); + } + + // Self transfers should not break accounting + function test_ERC20_selfTransfer(uint256 value) public { + uint256 balance_sender = balanceOf(address(this)); + require(balance_sender > 0); + + bool r = this.transfer(address(this), value % (balance_sender + 1)); + assertWithMsg(r == true, "Failed self transfer"); + assertEq(balance_sender, balanceOf(address(this)), "Self transfer breaks accounting"); + } + + // Transfers for more than available balance should not be allowed + function test_ERC20_transferFromMoreThanBalance(address target) public { + uint256 balance_sender = balanceOf(msg.sender); + uint256 balance_receiver = balanceOf(target); + uint256 current_allowance = allowance(msg.sender, address(this)); + require(balance_sender > 0 && current_allowance > balance_sender); + + bool r = transferFrom(msg.sender, target, balance_sender+1); + assertWithMsg(r == false, "Successful transferFrom for more than account balance"); + assertEq(balanceOf(msg.sender), balance_sender, "TransferFrom for more than balance modified source balance"); + assertEq(balanceOf(target), balance_receiver, "TransferFrom for more than balance modified target balance"); + } + + // Transfers for more than available balance should not be allowed + function test_ERC20_transferMoreThanBalance(address target) public { + uint256 balance_sender = balanceOf(address(this)); + uint256 balance_receiver = balanceOf(target); + require(balance_sender > 0); + + bool r = this.transfer(target, balance_sender+1); + assertWithMsg(r == false, "Successful transfer for more than account balance"); + assertEq(balanceOf(address(this)), balance_sender, "Transfer for more than balance modified source balance"); + assertEq(balanceOf(target), balance_receiver, "Transfer for more than balance modified target balance"); + } + + // Zero amount transfers should not break accounting + function test_ERC20_transferZeroAmount(address target) public { + uint256 balance_sender = balanceOf(address(this)); + uint256 balance_receiver = balanceOf(target); + require(balance_sender > 0); + + bool r = transfer(target, 0); + assertWithMsg(r == true, "Zero amount transfer failed"); + assertEq(balanceOf(address(this)), balance_sender, "Zero amount transfer modified source balance"); + assertEq(balanceOf(target), balance_receiver, "Zero amount transfer modified target balance"); + } + + // Zero amount transfers should not break accounting + function test_ERC20_transferFromZeroAmount(address target) public { + uint256 balance_sender = balanceOf(msg.sender); + uint256 balance_receiver = balanceOf(target); + uint256 current_allowance = allowance(msg.sender, address(this)); + require(balance_sender > 0 && current_allowance > 0); + + bool r = transferFrom(msg.sender, target, 0); + assertWithMsg(r == true, "Zero amount transferFrom failed"); + assertEq(balanceOf(msg.sender), balance_sender, "Zero amount transferFrom modified source balance"); + assertEq(balanceOf(target), balance_receiver, "Zero amount transferFrom modified target balance"); + } + + // Transfers should update accounting correctly + function test_ERC20_transfer(address target, uint256 amount) public { + require(target != address(this)); + uint256 balance_sender = balanceOf(address(this)); + uint256 balance_receiver = balanceOf(target); + require(balance_sender > 2); + uint256 transfer_value = (amount % balance_sender) + 1; + + bool r = this.transfer(target, transfer_value); + assertWithMsg(r == true, "transfer failed"); + assertEq(balanceOf(address(this)), balance_sender-transfer_value, "Wrong source balance after transfer"); + assertEq(balanceOf(target), balance_receiver+transfer_value, "Wrong target balance after transfer"); + } + + // Transfers should update accounting correctly + function test_ERC20_transferFrom(address target, uint256 amount) public { + require(target != address(this)); + require(target != msg.sender); + uint256 balance_sender = balanceOf(msg.sender); + uint256 balance_receiver = balanceOf(target); + uint256 current_allowance = allowance(msg.sender, address(this)); + require(balance_sender > 2 && current_allowance > balance_sender); + uint256 transfer_value = (amount % balance_sender) + 1; + + bool r = transferFrom(msg.sender, target, transfer_value); + assertWithMsg(r == true, "transferFrom failed"); + assertEq(balanceOf(msg.sender), balance_sender - transfer_value, "Wrong source balance after transferFrom"); + assertEq(balanceOf(target), balance_receiver + transfer_value, "Wrong target balance after transferFrom"); + } + + // Approve should set correct allowances + function test_ERC20_setAllowance(address target, uint256 amount) public { + bool r = this.approve(target, amount); + assertWithMsg(r == true, "Failed to set allowance via approve"); + assertEq(allowance(address(this), target), amount, "Allowance not set correctly"); + } + + // Approve should set correct allowances + function test_ERC20_setAllowanceTwice(address target, uint256 amount) public { + bool r = this.approve(target, amount); + assertWithMsg(r == true, "Failed to set allowance via approve"); + assertEq(allowance(address(this), target), amount, "Allowance not set correctly"); + + r = this.approve(target, amount/2); + assertWithMsg(r == true, "Failed to set allowance via approve"); + assertEq(allowance(address(this), target), amount/2, "Allowance not set correctly"); + } + + // TransferFrom should decrease allowance + function test_ERC20_spendAllowanceAfterTransfer(address target, uint256 amount) public { + require(target != address(this) && target != address(0)); + require(target != msg.sender); + uint256 balance_sender = balanceOf(msg.sender); + uint256 current_allowance = allowance(msg.sender, address(this)); + require(balance_sender > 0 && current_allowance > balance_sender); + uint256 transfer_value = (amount % balance_sender) + 1; + + bool r = this.transferFrom(msg.sender, target, transfer_value); + assertWithMsg(r == true, "transferFrom failed"); + + // Some implementations take an allowance of 2**256-1 as infinite, and therefore don't update + if (current_allowance != type(uint256).max) { + assertEq(allowance(msg.sender, address(this)), current_allowance - transfer_value, "Allowance not updated correctly"); + } + } + +} diff --git a/lib/crytic/contracts/ERC20/internal/properties/ERC20BurnableProperties.sol b/lib/crytic/contracts/ERC20/internal/properties/ERC20BurnableProperties.sol new file mode 100644 index 0000000..9b74eea --- /dev/null +++ b/lib/crytic/contracts/ERC20/internal/properties/ERC20BurnableProperties.sol @@ -0,0 +1,55 @@ +pragma solidity ^0.8.13; + +import "../util/ERC20TestBase.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; + +abstract contract CryticERC20BurnableProperties is CryticERC20Base, ERC20Burnable { + + constructor() { + isMintableOrBurnable = true; + } + + //////////////////////////////////////// + // Properties + + // Burn should update user balance and total supply + function test_ERC20_burn(uint256 amount) public { + uint256 balance_sender = balanceOf(address(this)); + uint256 supply = totalSupply(); + require(balance_sender > 0); + uint256 burn_amount = amount % (balance_sender+1); + + this.burn(burn_amount); + assertEq(balanceOf(address(this)), balance_sender - burn_amount, "Source balance incorrect after burn"); + assertEq(totalSupply(), supply-burn_amount, "Total supply incorrect after burn"); + } + + // Burn should update user balance and total supply + function test_ERC20_burnFrom(uint256 amount) public { + uint256 balance_sender = balanceOf(msg.sender); + uint256 allowance = allowance(msg.sender, address(this)); + require(balance_sender > 0 && allowance > balance_sender); + uint256 supply = totalSupply(); + uint256 burn_amount = amount % (balance_sender+1); + + this.burnFrom(msg.sender, burn_amount); + assertEq(balanceOf(msg.sender), balance_sender - burn_amount, "Source balance incorrect after burnFrom"); + assertEq(totalSupply(), supply-burn_amount, "Total supply incorrect after burnFrom"); + } + + // burnFrom should update allowance + function test_ERC20_burnFromUpdateAllowance(uint256 amount) public { + uint256 balance_sender = balanceOf(msg.sender); + uint256 current_allowance = allowance(msg.sender, address(this)); + require(balance_sender > 0 && current_allowance > balance_sender); + uint256 burn_amount = amount % (balance_sender+1); + + this.burnFrom(msg.sender, burn_amount); + + // Some implementations take an allowance of 2**256-1 as infinite, and therefore don't update + if (current_allowance != type(uint256).max) { + assertEq(allowance(msg.sender, address(this)), current_allowance - burn_amount, "Allowance not updated correctly"); + } + } + +} diff --git a/lib/crytic/contracts/ERC20/internal/properties/ERC20IncreaseAllowanceProperties.sol b/lib/crytic/contracts/ERC20/internal/properties/ERC20IncreaseAllowanceProperties.sol new file mode 100644 index 0000000..910d769 --- /dev/null +++ b/lib/crytic/contracts/ERC20/internal/properties/ERC20IncreaseAllowanceProperties.sol @@ -0,0 +1,37 @@ +pragma solidity ^0.8.13; + +import "../util/ERC20TestBase.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; + +abstract contract CryticERC20IncreaseAllowanceProperties is CryticERC20Base { + + constructor() { + + } + + //////////////////////////////////////// + // Properties + + // Allowance should be modified correctly via increase/decrease + function test_ERC20_setAndIncreaseAllowance(address target, uint256 initialAmount, uint256 increaseAmount) public { + bool r = this.approve(target, initialAmount); + assertWithMsg(r == true, "Failed to set initial allowance via approve"); + assertEq(allowance(address(this), target), initialAmount, "Allowance not set correctly"); + + r = this.increaseAllowance(target, increaseAmount); + assertWithMsg(r == true, "Failed to increase allowance"); + assertEq(allowance(address(this), target), initialAmount+increaseAmount, "Allowance not increased correctly"); + } + + // Allowance should be modified correctly via increase/decrease + function test_ERC20_setAndDecreaseAllowance(address target, uint256 initialAmount, uint256 decreaseAmount) public { + bool r = this.approve(target, initialAmount); + assertWithMsg(r == true, "Failed to set initial allowance via approve"); + assertEq(allowance(address(this), target), initialAmount, "Allowance not set correctly"); + + r = this.decreaseAllowance(target, decreaseAmount); + assertWithMsg(r == true, "Failed to decrease allowance"); + assertEq(allowance(address(this), target), initialAmount-decreaseAmount, "Allowance not decreased correctly"); + } + +} diff --git a/lib/crytic/contracts/ERC20/internal/properties/ERC20MintableProperties.sol b/lib/crytic/contracts/ERC20/internal/properties/ERC20MintableProperties.sol new file mode 100644 index 0000000..cac5f77 --- /dev/null +++ b/lib/crytic/contracts/ERC20/internal/properties/ERC20MintableProperties.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.8.13; + +import "../util/ERC20TestBase.sol"; + +abstract contract CryticERC20MintableProperties is CryticERC20Base { + + constructor() { + isMintableOrBurnable = true; + } + + // Should be modified if target contract's function name is not mint + function mint(address to, uint256 amount) public virtual; + + //////////////////////////////////////// + // Properties + + // Minting tokens should update user balance and total supply + function test_ERC20_mintTokens(address target, uint256 amount) public { + uint256 balance_receiver = balanceOf(target); + uint256 supply = totalSupply(); + + this.mint(target, amount); + assertEq(balanceOf(target), balance_receiver+amount, "Mint failed to update target balance"); + assertEq(totalSupply(), supply+amount, "Mint failed to update total supply"); + } +} diff --git a/lib/crytic/contracts/ERC20/internal/properties/ERC20PausableProperties.sol b/lib/crytic/contracts/ERC20/internal/properties/ERC20PausableProperties.sol new file mode 100644 index 0000000..a2a560b --- /dev/null +++ b/lib/crytic/contracts/ERC20/internal/properties/ERC20PausableProperties.sol @@ -0,0 +1,68 @@ +pragma solidity ^0.8.13; + +import "../util/ERC20TestBase.sol"; +import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol"; + +abstract contract CryticERC20PausableProperties is CryticERC20Base, ERC20Pausable { + + constructor() {} + + //////////////////////////////////////// + // Helper functions - May need tweaking for non-OZ tokens + + function _overridePause(bool paused) internal { + if(paused) { + _pause(); + } else { + _unpause(); + } + } + + // Override for pausable tokens + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual override(ERC20, ERC20Pausable) { + ERC20Pausable._beforeTokenTransfer(from, to, amount); + } + + //////////////////////////////////////// + // Properties + + // Transfers should not be possible during paused state + function test_ERC20_pausedTransfer(address target, uint256 amount) public { + uint256 balance_sender = balanceOf(address(this)); + uint256 balance_receiver = balanceOf(target); + require(balance_sender > 0); + uint256 transfer_amount = amount % (balance_sender+1); + + _pause(); + + bool r = this.transfer(target, transfer_amount); + assertWithMsg(r == false, "Tokens transferred while paused"); + assertEq(balanceOf(address(this)), balance_sender, "Transfer while paused altered source balance"); + assertEq(balanceOf(target), balance_receiver, "Transfer while paused altered target balance"); + + _unpause(); + } + + // Transfers should not be possible during paused state + function test_ERC20_pausedTransferFrom(address target, uint256 amount) public { + uint256 balance_sender = balanceOf(msg.sender); + uint256 balance_receiver = balanceOf(target); + uint256 allowance = allowance(msg.sender, address(this)); + require(balance_sender > 0 && allowance > balance_sender); + uint256 transfer_amount = amount % (balance_sender+1); + + _pause(); + + bool r = this.transferFrom(msg.sender, target, transfer_amount); + assertWithMsg(r == false, "Tokens transferred while paused"); + assertEq(balanceOf(msg.sender), balance_sender, "Transfer while paused altered source balance"); + assertEq(balanceOf(target), balance_receiver, "Transfer while paused altered target balance"); + + _unpause(); + } + +} diff --git a/lib/crytic/contracts/ERC20/internal/util/ERC20TestBase.sol b/lib/crytic/contracts/ERC20/internal/util/ERC20TestBase.sol new file mode 100644 index 0000000..5b7de94 --- /dev/null +++ b/lib/crytic/contracts/ERC20/internal/util/ERC20TestBase.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.8.0; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "../../../util/PropertiesConstants.sol"; +import "../../../util/PropertiesHelper.sol"; + +abstract contract CryticERC20Base is ERC20, PropertiesAsserts, PropertiesConstants { + + // Initial supply after deploying + uint256 initialSupply; + + // Is the contract allowed to change its total supply? + bool isMintableOrBurnable; + + constructor() { + } + +} diff --git a/lib/crytic/contracts/ERC4626/ERC4626PropertyTests.sol b/lib/crytic/contracts/ERC4626/ERC4626PropertyTests.sol new file mode 100644 index 0000000..5540f4f --- /dev/null +++ b/lib/crytic/contracts/ERC4626/ERC4626PropertyTests.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.8.0; + +import {TestERC20Token} from "./util/TestERC20Token.sol"; +import {CryticERC4626RedeemUsingApproval} from "./properties/RedeemUsingApprovalProps.sol"; +import {CryticERC4626SenderIndependent} from "./properties/SenderIndependentProps.sol"; +import {CryticERC4626PropertyBase} from "./util/ERC4626PropertyTestBase.sol"; +import {CryticERC4626MustNotRevert} from "./properties/MustNotRevertProps.sol"; +import {CryticERC4626FunctionalAccounting} from "./properties/FunctionalAccountingProps.sol"; +import {CryticERC4626Rounding} from "./properties/RoundingProps.sol"; +import {CryticERC4626VaultProxy} from "./properties/VaultProxy.sol"; +import {CryticERC4626SecurityProps} from "./properties/SecurityProps.sol"; + +/// @notice Aggregator contract for various 4626 property tests. Inherit from this & echidna will test all properties at the same time. +contract CryticERC4626PropertyTests is + CryticERC4626RedeemUsingApproval, + CryticERC4626MustNotRevert, + CryticERC4626SenderIndependent, + CryticERC4626FunctionalAccounting, + CryticERC4626Rounding, + CryticERC4626SecurityProps{ +} \ No newline at end of file diff --git a/lib/crytic/contracts/ERC4626/README.md b/lib/crytic/contracts/ERC4626/README.md new file mode 100644 index 0000000..3410a99 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/README.md @@ -0,0 +1,163 @@ + +# ERC4626 Echidna Property Tests + +- [ERC4626 Echidna Property Tests](#erc4626-echidna-property-tests) + - [Consuming](#consuming) + - [Initial setup](#initial-setup) + - [Adding internal test methods to a vault](#adding-internal-test-methods-to-a-vault) + - [Developing](#developing) + - [Properties Tested](#properties-tested) + - [MustNotRevertProps](#mustnotrevertprops) + - [FunctionalAccountingProps](#functionalaccountingprops) + - [RedeemUsingApprovalProps](#redeemusingapprovalprops) + - [SenderIndependentProps](#senderindependentprops) + - [RoundingProps](#roundingprops) + - [SecurityProps](#securityprops) + - [Properties to consider adding](#properties-to-consider-adding) + - [Properties that may not be testable](#properties-that-may-not-be-testable) + +## Consuming + +### Initial setup +To use these properties to test a given vault implementation, see the readme in the project root. + +### Adding internal test methods to a vault +Some properties of the ERC4626 spec cannot be tested externally because testing them requires interactions between the test suite & functionality that is not defined in the spec. + +To compensate for this limitation, a vault under test may optionally implement a set of methods that allow such properties to be tested. See [IERC4626Internal](util/IERC4626Internal.sol) for the list of methods. + +These methods should be added to the Vault by a derived, test-environment-only contract to minimize changes to the production contract. When a vault under test implements IERC4626Internal, pass `true` to the test harness's `initialize()` function to enable the properties that require the internal interface: + +``` +contract Vault is IERC4626 { ... } + +contract VaultTestable is Vault, IERC4626Internal { ... } + +contract TestHarness is CryticERC4626PropertyTests{ + constructor(...) { + [...] + initialize(address(_vault), address(_asset), true); + } +} +``` + +Check out the [rounding property verification contracts](test/rounding/BadConvertToAssetsRounding.sol) if you'd like to see how such an implementation would look. + +## Developing + +Before doing any development, run `forge install` to get dependencies sorted out. `forge build` will not work without the [Echidna remappings](test/echidna.config.yaml). + +Running tests(used to validate the properties are working correctly): + +`echidna-test ./contracts/ERC4626/test/rounding/BadConvertToAssetsRounding.sol --contract TestHarness --config ./contracts/ERC4626/test/echidna.config.yaml` +Should cause these properties to fail: +- verify_previewRedeemRoundingDirection +- verify_redeemRoundingDirection +- verify_convertToAssetsRoundingDirection + +`echidna-test ./contracts/ERC4626/test/rounding/BadConvertToSharesRounding.sol --contract TestHarness --config ./contracts/ERC4626/test/echidna.config.yaml` +Should cause these properties to fail: +- verify_convertToSharesRoundingDirection +- verify_previewDepositRoundingDirection +- verify_depositRoundingDirection + +`echidna-test ./contracts/ERC4626/test/rounding/BadPreviewMintRounding.sol --contract TestHarness --config ./contracts/ERC4626/test/echidna.config.yaml` +Should cause these properties to fail: +- verify_previewMintRoundingDirection +- verify_mintRoundingDirection + +`echidna-test ./contracts/ERC4626/test/rounding/BadPreviewWithdrawRounding.sol --contract TestHarness --config ./contracts/ERC4626/test/echidna.config.yaml` +Should cause these properties to fail: +- verify_previewWithdrawRoundingDirection +- verify_withdrawRoundingDirection + +`echidna-test ./contracts/ERC4626/test/security/BadShareInflation.sol --contract TestHarness --config ./contracts/ERC4626/test/echidna.config.yaml` +Should cause these properties to fail: +- verify_sharePriceInflationAttack + +`echidna-test ./contracts/ERC4626/test/usingApproval/BadAllowanceUpdate.sol --contract TestHarness --config ./contracts/ERC4626/test/echidna.config.yaml` +Should cause these properties to fail: +- verify_redeemViaApprovalProxy +- verify_withdrawViaApprovalProxy +- verify_redeemRequiresTokenApproval +- verify_withdrawRequiresTokenApproval + +Run property tests against vanilla solmate: + +`echidna-test ./contracts/ERC4626/test/Solmate4626.sol --contract TestHarness --config ./contracts/ERC4626/test/echidna.config.yaml` + +[EIP-4626 Spec](https://eips.ethereum.org/EIPS/eip-4626) + +## Properties Tested + +### MustNotRevertProps +- `convertToAssets()` must not revert for reasonable values +- `convertToShares()` must not revert for reasonable values +- `asset()` must not revert +- `totalAssets()` must not revert +- `maxDeposit()` must not revert +- `maxMint()` must not revert +- `maxRedeem()` must not revert +- `maxWithdraw()` must not revert + +### FunctionalAccountingProps +- `deposit()` must deduct assets from the owner +- `deposit()` must credit shares to the receiver +- `deposit()` must mint greater than or equal to the number of shares predicted by `previewDeposit()` +- `mint()` must deduct assets from the owner +- `mint()` must credit shares to the receiver +- `mint()` must consume less than or equal to the number of assets predicted by `previewMint()` +- `withdraw()` must deduct shares from the owner +- `withdraw()` must credit assets to the receiver +- `withdraw()` must deduct less than or equal to the number of shares predicted by `previewWithdraw()` +- `redeem()` must deduct shares from the owner +- `redeem()` must credit assets to the receiver +- `redeem()` must credit greater than or equal to the number of assets predicted by `previewRedeem()` + +### RedeemUsingApprovalProps +- `withdraw()` must allow proxies to withdraw tokens on behalf of the owner using share token approvals +- `redeem()` must allow proxies to redeem shares on behalf of the owner using share token approvals +- Third party `withdraw()` calls must update the msg.sender's allowance +- Third party `redeem()` calls must update the msg.sender's allowance +- Third parties must not be able to `withdraw()` tokens on an owner's behalf without a token approval +- Third parties must not be able to `redeem()` shares on an owner's behalf without a token approval + +### SenderIndependentProps +- `maxDeposit()` must assume the receiver/sender has infinite assets +- `maxMint()` must assume the receiver/sender has infinite assets +- `previewMint()` must not account for msg.sender asset balance +- `previewDeposit()` must not account for msg.sender asset balance +- `previewWithdraw()` must not account for msg.sender share balance +- `previewRedeem()` must not account for msg.sender share balance + +### RoundingProps +- Shares may never be minted for free using: + - `previewDeposit()` + - `previewMint()` + - `convertToShares()` +- Tokens may never be withdrawn for free using: + - `previewWithdraw()` + - `previewRedeem()` + - `convertToAssets()` +- Shares may never be minted for free using: + - `deposit()` + - `mint()` +- Tokens may never be withdrawn for free using: + - `withdraw()` + - `redeem()` + +### SecurityProps +- `decimals()` should be larger than or equal to `asset.decimals()` +- Accounting system must not be vulnerable to share price inflation attacks + +## Properties to consider adding +- deposit/mint must increase totalSupply/totalAssets +- withdraw/redeem must decrease totalSupply/totalAssets +- `previewDeposit()` must not account for vault specific/user/global limits +- `previewMint()` must not account for vault specific/user/global limits +- `previewWithdraw()` must not account for vault specific/user/global limits +- `previewRedeem()` must not account for vault specific/user/global limits + +## Properties that may not be testable +- Note that any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in share price or some other type of condition, meaning the depositor will lose assets by depositing. +- Whether a given method is inclusive of withdraw/deposit fees \ No newline at end of file diff --git a/lib/crytic/contracts/ERC4626/properties/FunctionalAccountingProps.sol b/lib/crytic/contracts/ERC4626/properties/FunctionalAccountingProps.sol new file mode 100644 index 0000000..40a7c50 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/properties/FunctionalAccountingProps.sol @@ -0,0 +1,111 @@ +pragma solidity ^0.8.0; + +import {CryticERC4626PropertyBase} from "../util/ERC4626PropertyTestBase.sol"; + +contract CryticERC4626FunctionalAccounting is CryticERC4626PropertyBase { + /// @notice Validates the following properties: + /// - deposit() must deduct assets from the owner + /// - deposit() must credit shares to the receiver + /// - deposit() must mint greater than or equal to the number of shares predicted by previewDeposit() + function verify_depositProperties(uint256 receiverId, uint256 tokens) public { + address sender = address(this); + address receiver = restrictAddressToThirdParties(receiverId); + tokens = requireValidDepositAmount(sender, receiver, tokens); + + (uint256 senderAssetsBeforeDeposit,) = measureAddressHoldings(sender, "sender", "before deposit"); + (, uint256 receiverSharesBeforeDeposit) = measureAddressHoldings(receiver, "receiver", "before deposit"); + + uint256 sharesExpected = vault.previewDeposit(tokens); + uint256 sharesMinted = vault.deposit(tokens, receiver); + assertGte(sharesMinted, sharesExpected, "deposit() must always mint greater than or equal to the shares predicted by previewDeposit()"); + + (uint256 senderAssetsAfterDeposit,) = measureAddressHoldings(sender, "sender", "after deposit"); + (, uint256 receiverSharesAfterDeposit) = measureAddressHoldings(receiver, "receiver", "after deposit"); + + uint256 senderAssetsDelta = senderAssetsBeforeDeposit - senderAssetsAfterDeposit; + assertEq(senderAssetsDelta, tokens, "deposit() must consume exactly the number of tokens requested"); + + uint256 receiverSharesDelta = receiverSharesAfterDeposit - receiverSharesBeforeDeposit; + assertEq(receiverSharesDelta, sharesMinted, "deposit() must credit the correct number of shares to the receiver"); + } + + /// @notice Validates the following properties: + /// - mint() must deduct assets from the owner + /// - mint() must credit shares to the receiver + /// - mint() must consume less than or equal to the number of assets predicted by previewMint() + function verify_mintProperties(uint256 receiverId, uint256 shares) public { + address sender = address(this); + address receiver = restrictAddressToThirdParties(receiverId); + uint256 tokensExpected = vault.previewMint(shares); + shares = requireValidMintAmount(sender, receiver, shares); + + (uint256 senderAssetsBeforeMint,) = measureAddressHoldings(sender, "sender", "before mint"); + (, uint256 receiverSharesBeforeMint) = measureAddressHoldings(receiver, "receiver", "before mint"); + + uint256 tokensConsumed = vault.mint(shares, receiver); + assertLte(tokensConsumed, tokensExpected, "mint() must always consume less than or equal to the tokens predicted by previewMint()"); + + (uint256 senderAssetsAfterMint,) = measureAddressHoldings(sender, "sender", "after mint"); + (, uint256 receiverSharesAfterMint) = measureAddressHoldings(receiver, "receiver", "after mint"); + + uint256 senderAssetsDelta = senderAssetsBeforeMint - senderAssetsAfterMint; + assertEq(senderAssetsDelta, tokensConsumed, "mint() must consume exactly the number of tokens requested"); + + uint256 receiverSharesDelta = receiverSharesAfterMint - receiverSharesBeforeMint; + assertEq(receiverSharesDelta, shares, "mint() must credit the correct number of shares to the receiver"); + } + + /// @notice Validates the following properties: + /// - redeem() must deduct shares from the owner + /// - redeem() must credit assets to the receiver + /// - redeem() must credit greater than or equal to the number of assets predicted by previewRedeem() + function verify_redeemProperties(uint256 receiverId, uint256 shares) public { + // we can only redeem on behalf of address(this) until we get cheatcodes + address owner = address(this); + address receiver = restrictAddressToThirdParties(receiverId); + shares = requireValidRedeemAmount(owner, shares); + + (, uint256 ownerSharesBefore) = measureAddressHoldings(owner, "owner", "before redeem"); + (uint256 receiverAssetsBefore,) = measureAddressHoldings(receiver, "receiver", "before redeem"); + + uint256 tokensExpected = vault.previewRedeem(shares); + uint256 tokensWithdrawn = vault.redeem(shares, receiver, owner); + assertGte(tokensWithdrawn, tokensExpected, "redeem() must withdraw greater than or equal to the number of assets predicted by previewRedeem()"); + + (, uint256 ownerSharesAfter) = measureAddressHoldings(owner, "owner", "after redeem"); + (uint256 receiverAssetsAfter,) = measureAddressHoldings(receiver, "receiver", "after redeem"); + + uint256 receiverAssetsDelta = receiverAssetsAfter - receiverAssetsBefore; + assertEq(receiverAssetsDelta, tokensWithdrawn, "redeem() must credit the correct number of assets to the receiver"); + + uint256 ownerSharesDelta = ownerSharesBefore - ownerSharesAfter; + assertEq(ownerSharesDelta, shares, "redeem() must deduct the correct number of shares from the owner"); + } + + /// @notice Validates the following properties: + /// - withdraw() must deduct shares from the owner + /// - withdraw() must credit assets to the receiver + /// - withdraw() must deduct less than or equal to the number of shares predicted by previewWithdraw() + function verify_withdrawProperties(uint256 receiverId, uint256 tokens) public { + // we can only withdraw on behalf of address(this) until we get cheatcodes + address owner = address(this); + address receiver = restrictAddressToThirdParties(receiverId); + tokens = requireValidWithdrawAmount(owner, tokens); + uint256 sharesExpected = vault.previewWithdraw(tokens); + + (, uint256 ownerSharesBefore) = measureAddressHoldings(owner, "owner", "before withdraw"); + (uint256 receiverAssetsBefore,) = measureAddressHoldings(receiver, "receiver", "before withdraw"); + + uint256 sharesRedeemed = vault.withdraw(tokens, receiver, owner); + assertLte(sharesRedeemed, sharesExpected, "withdraw() must redeem less than or equal to the number of shares predicted by previewWithdraw()"); + + (, uint256 ownerSharesAfter) = measureAddressHoldings(owner, "owner", "after withdraw"); + (uint256 receiverAssetsAfter,) = measureAddressHoldings(receiver, "receiver", "after withdraw"); + + uint256 receiverAssetsDelta = receiverAssetsAfter - receiverAssetsBefore; + assertEq(receiverAssetsDelta, tokens, "withdraw() must credit the correct number of assets to the receiver"); + + uint256 ownerSharesDelta = ownerSharesBefore - ownerSharesAfter; + assertEq(ownerSharesDelta, sharesRedeemed, "withdraw() must deduct the correct number of shares from the owner"); + } +} diff --git a/lib/crytic/contracts/ERC4626/properties/MustNotRevertProps.sol b/lib/crytic/contracts/ERC4626/properties/MustNotRevertProps.sol new file mode 100644 index 0000000..59087e5 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/properties/MustNotRevertProps.sol @@ -0,0 +1,109 @@ +pragma solidity ^0.8.0; + +import {CryticERC4626PropertyBase} from "../util/ERC4626PropertyTestBase.sol"; +import {CryticERC4626VaultProxy} from "./VaultProxy.sol"; +contract CryticERC4626MustNotRevert is CryticERC4626PropertyBase, CryticERC4626VaultProxy { + + /// @notice Validates the following properties: + /// - vault.asset() must not revert + function verify_assetMustNotRevert() public { + try vault.asset() { + return; + } catch { + assertWithMsg(false, "vault.asset() must not revert"); + } + } + + /// @notice Validates the following properties: + /// - vault.totalAssets() must not revert + function verify_totalAssetsMustNotRevert() public { + try vault.totalAssets() { + return; + } catch { + assertWithMsg(false, "vault.totalAssets() must not revert"); + } + } + + /// @notice Validates the following properties: + /// - vault.convertToAssets() must not revert for reasonable values + function verify_convertToAssetsMustNotRevert(uint256 shares) public { + // arbitrarily define "reasonable values" to be 10**(token.decimals+20) + uint256 reasonably_largest_value = 10**(vault.decimals()+20); + + // prevent scenarios where there is enough totalSupply to trigger overflows + require(vault.totalSupply() <= reasonably_largest_value); + shares = clampLte(shares, reasonably_largest_value); + + // exclude the possibility of idiosyncratic reverts. Might have to add more in future. + shares = clampLte(shares, vault.totalSupply()); + + emit LogUint256("totalSupply", vault.totalSupply()); + emit LogUint256("totalAssets", vault.totalAssets()); + + + try vault.convertToAssets(shares) { + return; + } catch { + assertWithMsg(false, "vault.convertToAssets() must not revert"); + } + } + + /// @notice Validates the following properties: + /// - vault.convertToShares() must not revert for reasonable values + function verify_convertToSharesMustNotRevert(uint256 tokens) public { + // arbitrarily define "reasonable values" to be 10**(token.decimals+20) + uint256 reasonably_largest_value = 10**(asset.decimals()+20); + + // prevent scenarios where there is enough totalSupply to trigger overflows + require(asset.totalSupply() <= reasonably_largest_value); + + // exclude the possibility of idiosyncratic reverts. Might have to add more in future. + tokens = clampLte(tokens, asset.totalSupply()); + + try vault.convertToShares(tokens) { + return; + } catch { + assertWithMsg(false, "vault.convertToShares() must not revert"); + } + } + + function verify_maxDepositMustNotRevert(address owner) public { + try vault.maxDeposit(owner) { + return; + } catch { + assertWithMsg(false, "vault.maxDeposit() must not revert"); + } + } + + function verify_maxMintMustNotRevert(address owner) public { + try vault.maxMint(owner) { + return; + } catch { + assertWithMsg(false, "vault.maxMint() must not revert"); + } + } + + function verify_maxRedeemMustNotRevert(address owner) public { + // if the following reverts from overflow, bail out. + // additional criterion might be required in the future + vault.convertToAssets(vault.balanceOf(owner)); + + try vault.maxRedeem(owner) { + return; + } catch { + assertWithMsg(false, "vault.maxRedeem() must not revert"); + } + } + + function verify_maxWithdrawMustNotRevert(address owner) public { + // if the following reverts from overflow, bail out. + // additional criterion might be required in the future + vault.convertToAssets(vault.balanceOf(owner)); + + try vault.maxWithdraw(owner) { + return; + } catch { + assertWithMsg(false, "vault.maxWithdraw() must not revert"); + } + } +} diff --git a/lib/crytic/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol b/lib/crytic/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol new file mode 100644 index 0000000..e81826e --- /dev/null +++ b/lib/crytic/contracts/ERC4626/properties/RedeemUsingApprovalProps.sol @@ -0,0 +1,86 @@ +pragma solidity ^0.8.0; +import {CryticERC4626PropertyBase} from "../util/ERC4626PropertyTestBase.sol"; +import {CryticERC4626VaultProxy} from "./VaultProxy.sol"; + +contract CryticERC4626RedeemUsingApproval is CryticERC4626PropertyBase, CryticERC4626VaultProxy { + + /// @notice verifies `redeem()` must allow proxies to redeem shares on behalf of the owner using share token approvals + /// verifies third party `redeem()` calls must update the msg.sender's allowance + function verify_redeemViaApprovalProxy(uint256 receiverId, uint256 shares) public returns (uint256 tokensWithdrawn){ + address owner = address(this); + address receiver = restrictAddressToThirdParties(receiverId); + shares = requireValidRedeemAmount(owner, shares); + + vault.approve(address(redemptionProxy), shares); + measureAddressHoldings(address(this), "vault", "before redeemption"); + + try redemptionProxy.redeemOnBehalf(shares, receiver, owner) returns (uint256 _tokensWithdrawn){ + tokensWithdrawn = _tokensWithdrawn; + } catch { + assertWithMsg(false, "vault.redeem() reverted during redeem via approval"); + } + + // verify allowance is updated + uint256 newAllowance = vault.allowance(owner,address(redemptionProxy)); + assertEq(newAllowance, 0, "The vault failed to update the redemption proxy's share allowance"); + } + + /// @notice verifies `withdraw()` must allow proxies to withdraw shares on behalf of the owner using share token approvals + /// verifies third party `withdraw()` calls must update the msg.sender's allowance + function verify_withdrawViaApprovalProxy(uint256 receiverId, uint256 tokens) public returns (uint256 sharesBurned){ + address owner = address(this); + address receiver = restrictAddressToThirdParties(receiverId); + tokens = requireValidWithdrawAmount(owner, tokens); + + uint256 expectedSharesConsumed = vault.previewWithdraw(tokens); + vault.approve(address(redemptionProxy), expectedSharesConsumed); + measureAddressHoldings(address(this), "vault", "before withdraw"); + + try redemptionProxy.withdrawOnBehalf(tokens, receiver, owner) returns (uint256 _sharesBurned) { + sharesBurned = _sharesBurned; + } catch { + assertWithMsg(false, "vault.withdraw() reverted during withdraw via approval"); + } + + emit LogUint256("withdraw consumed this many shares:", sharesBurned); + + // verify allowance is updated + uint256 newAllowance = vault.allowance(owner, address(redemptionProxy)); + uint256 expectedAllowance = expectedSharesConsumed - sharesBurned; + emit LogUint256("Expecting allowance to now be:", expectedAllowance); + assertEq(expectedAllowance, newAllowance, "The vault failed to update the redemption proxy's share allowance"); + } + + /// @notice verifies third parties must not be able to `withdraw()` tokens on an owner's behalf without a token approval + function verify_withdrawRequiresTokenApproval(uint256 receiverId, uint256 tokens, uint256 sharesApproved) public { + address owner = address(this); + address receiver = restrictAddressToThirdParties(receiverId); + tokens = requireValidWithdrawAmount(owner, tokens); + uint256 expectedSharesConsumed = vault.previewWithdraw(tokens); + emit LogUint256("Will attempt to proxy withdraw this many shares:", expectedSharesConsumed); + + require(sharesApproved < expectedSharesConsumed); + emit LogUint256("Approving spend of this many shares:", sharesApproved); + vault.approve(address(redemptionProxy), sharesApproved); + + try redemptionProxy.withdrawOnBehalf(tokens, receiver, owner) returns (uint256 _sharesBurned) { + assertLte(_sharesBurned, sharesApproved, "Redemption proxy must not be able to withdraw more shares than it was approved"); + } catch { } + } + + /// @notice verifies third parties must not be able to `redeem()` shares on an owner's behalf without a token approval + function verify_redeemRequiresTokenApproval(uint256 receiverId, uint256 shares, uint256 sharesApproved) public { + address owner = address(this); + address receiver = restrictAddressToThirdParties(receiverId); + shares = requireValidRedeemAmount(owner, shares); + emit LogUint256("Will attempt to proxy redeem this many shares:", shares); + + require(sharesApproved < shares); + emit LogUint256("Approving spend of this many shares:", sharesApproved); + vault.approve(address(redemptionProxy), sharesApproved); + + try redemptionProxy.redeemOnBehalf(shares, receiver, owner) returns (uint256 _sharesBurned) { + assertLte(_sharesBurned, sharesApproved, "Redemption proxy must not be able to redeem more shares than it was approved"); + } catch { } + } +} diff --git a/lib/crytic/contracts/ERC4626/properties/RoundingProps.sol b/lib/crytic/contracts/ERC4626/properties/RoundingProps.sol new file mode 100644 index 0000000..8f79710 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/properties/RoundingProps.sol @@ -0,0 +1,102 @@ +pragma solidity ^0.8.0; +import {CryticERC4626PropertyBase} from "../util/ERC4626PropertyTestBase.sol"; +import {CryticERC4626VaultProxy} from "./VaultProxy.sol"; + +contract CryticERC4626Rounding is CryticERC4626PropertyBase, CryticERC4626VaultProxy { + + /// @notice verifies shares may never be minted for free using previewDeposit() + function verify_previewDepositRoundingDirection() public { + require(supportsInternalTestingIface); + uint256 sharesMinted = vault.previewDeposit(0); + assertEq(sharesMinted, 0, "previewDeposit() must not mint shares at no cost"); + } + + /// @notice verifies shares may never be minted for free using previewMint() + function verify_previewMintRoundingDirection(uint256 shares) public { + require(supportsInternalTestingIface); + require(shares > 0); + uint256 tokensConsumed = vault.previewMint(shares); + assertGt(tokensConsumed, 0, "previewMint() must never mint shares at no cost"); + } + + /// @notice verifies shares may never be minted for free using convertToShares() + function verify_convertToSharesRoundingDirection() public { + require(supportsInternalTestingIface); + // note: the correctness of this property can't be tested using solmate as a reference impl. 0/n=0. best case scenario, some other property gets set off. + uint256 tokensWithdrawn = vault.convertToShares(0); + assertEq(tokensWithdrawn, 0, "convertToShares() must not allow shares to be minted at no cost"); + } + + /// @notice verifies tokens may never be withdrawn for free using previewRedeem() + function verify_previewRedeemRoundingDirection() public { + require(supportsInternalTestingIface); + uint256 tokensWithdrawn = vault.previewRedeem(0); + assertEq(tokensWithdrawn, 0, "previewRedeem() must not allow assets to be withdrawn at no cost"); + } + + /// @notice verifies tokens may never be withdrawn for free using previewWithdraw() + function verify_previewWithdrawRoundingDirection(uint256 tokens) public { + require(supportsInternalTestingIface); + require(tokens > 0); + uint256 sharesRedeemed = vault.previewWithdraw(tokens); + assertGt(sharesRedeemed, 0, "previewWithdraw() must not allow assets to be withdrawn at no cost"); + } + + /// @notice verifies tokens may never be withdrawn for free using convertToAssets() + function verify_convertToAssetsRoundingDirection() public { + require(supportsInternalTestingIface); + // note: the correctness of this property can't be tested using solmate as a reference impl. 0/n=0. best case scenario, some other property gets set off. + uint256 tokensWithdrawn = vault.convertToAssets(0); + assertEq(tokensWithdrawn, 0, "convertToAssets() must not allow assets to be withdrawn at no cost"); + } + + /// @notice Indirectly verifies the rounding direction of convertToShares/convertToAssets is correct by attempting to + /// create an arbitrage by depositing, then withdrawing + function verify_convertRoundTrip(uint256 amount) public { + require(supportsInternalTestingIface); + uint256 sharesMinted = vault.convertToShares(amount); + uint256 tokensWithdrawn = vault.convertToAssets(sharesMinted); + assertGte(amount, tokensWithdrawn, "A profit was extractable from a convertTo round trip (deposit, then withdraw)"); + } + + /// @notice Indirectly verifies the rounding direction of convertToShares/convertToAssets is correct by attempting to + /// create an arbitrage by withdrawing, then depositing + function verify_convertRoundTrip2(uint256 amount) public { + require(supportsInternalTestingIface); + uint256 tokensWithdrawn = vault.convertToAssets(amount); + uint256 sharesMinted = vault.convertToShares(tokensWithdrawn); + assertGte(amount, sharesMinted, "A profit was extractable from a convertTo round trip (withdraw, then deposit)"); + } + + /// @notice verifies Shares may never be minted for free using deposit() + function verify_depositRoundingDirection() public { + require(supportsInternalTestingIface); + uint256 shares = vault.deposit(0, address(this)); + assertEq(shares, 0, "Shares must not be minted for free"); + } + + /// @notice verifies Shares may never be minted for free using mint() + function verify_mintRoundingDirection(uint256 shares) public { + require(supportsInternalTestingIface); + require(shares > 0); + uint256 tokensDeposited = vault.mint(shares, address(this)); + + assertGt(tokensDeposited, 0, "Shares must not be minted for free"); + } + + /// @notice verifies tokens may never be withdrawn for free using withdraw() + function verify_withdrawRoundingDirection(uint256 tokens) public { + require(supportsInternalTestingIface); + require(tokens > 0); + uint256 sharesRedeemed = vault.withdraw(tokens, address(this), address(this)); + + assertGt(sharesRedeemed, 0, "Token must not be withdrawn for free"); + } + + /// @notice verifies tokens may never be withdrawn for free using redeem() + function verify_redeemRoundingDirection() public { + require(supportsInternalTestingIface); + uint256 tokensWithdrawn = vault.redeem(0, address(this), address(this)); + assertEq(tokensWithdrawn, 0, "Tokens must not be withdrawn for free"); + } +} diff --git a/lib/crytic/contracts/ERC4626/properties/SecurityProps.sol b/lib/crytic/contracts/ERC4626/properties/SecurityProps.sol new file mode 100644 index 0000000..0cd659c --- /dev/null +++ b/lib/crytic/contracts/ERC4626/properties/SecurityProps.sol @@ -0,0 +1,54 @@ +pragma solidity ^0.8.0; +import {CryticERC4626PropertyBase} from "../util/ERC4626PropertyTestBase.sol"; + +contract CryticERC4626SecurityProps is CryticERC4626PropertyBase { + /// @notice verify `decimals()` should be larger than or equal to `asset.decimals()` + function verify_assetDecimalsLessThanVault() public { + assertGte(vault.decimals(), asset.decimals(), "The vault's share token should have greater than or equal to the number of decimals as the vault's asset token."); + } + + /// @notice verify Accounting system must not be vulnerable to share price inflation attacks + function verify_sharePriceInflationAttack(uint256 inflateAmount, uint256 delta) public { + // this has to be changed if there's deposit/withdraw fees + uint256 lossThreshold = 0.999 ether; + // vault is fresh + require(vault.totalAssets() == 0); + require(vault.totalSupply() == 0); + + // these minimums are to prevent 1-wei rounding errors from triggering the property + require(inflateAmount > 10000); + uint256 victimDeposit = inflateAmount + delta; + address attacker = address(this); + // fund account + prepareAddressForDeposit(attacker, inflateAmount); + + uint256 shares = vault.deposit(1, attacker); + // attack only works when pps=1:1 + new vault + require(shares == 1); + require(vault.totalAssets() == 1); + + // inflate pps + asset.transfer(address(vault), inflateAmount-1); + + // fund victim + alice.fund(victimDeposit); + alice.approveFunds(); + + emit LogUint256("Amount of alice's deposit:", victimDeposit); + uint256 aliceShares = alice.depositFunds(victimDeposit); + emit LogUint256("Alice Shares:", aliceShares); + uint256 aliceWithdrawnFunds = alice.redeemShares(aliceShares); + emit LogUint256("Amount of tokens alice withdrew:", aliceWithdrawnFunds); + + uint256 victimLoss = victimDeposit - aliceWithdrawnFunds; + emit LogUint256("Alice Loss:", victimLoss); + + uint256 minRedeemedAmountNorm = (victimDeposit * lossThreshold) / 1 ether; + + emit LogUint256("lossThreshold", lossThreshold); + emit LogUint256("minRedeemedAmountNorm", minRedeemedAmountNorm); + assertGt(aliceWithdrawnFunds, minRedeemedAmountNorm, "Share inflation attack possible, victim lost an amount over lossThreshold%"); + } + + +} diff --git a/lib/crytic/contracts/ERC4626/properties/SenderIndependentProps.sol b/lib/crytic/contracts/ERC4626/properties/SenderIndependentProps.sol new file mode 100644 index 0000000..6feb7d3 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/properties/SenderIndependentProps.sol @@ -0,0 +1,77 @@ +pragma solidity ^0.8.0; +import {CryticERC4626PropertyBase} from "../util/ERC4626PropertyTestBase.sol"; + +contract CryticERC4626SenderIndependent is CryticERC4626PropertyBase { + // todo: these properties may have issues in vaults that have super weird redemption curves. + // If that happens, use a proxy contract to compare results instead of msg.sender's state + + /// @notice verify `maxDeposit()` assumes the receiver/sender has infinite assets + function verify_maxDepositIgnoresSenderAssets(uint256 tokens) public { + address receiver = address(this); + uint256 maxDepositBefore = vault.maxDeposit(receiver); + asset.mint(receiver, tokens); + uint256 maxDepositAfter = vault.maxDeposit(receiver); + assertEq(maxDepositBefore, maxDepositAfter, "maxDeposit must assume the agent has infinite assets"); + } + + /// @notice verify `maxMint()` assumes the receiver/sender has infinite assets + function verify_maxMintIgnoresSenderAssets(uint256 tokens) public { + address receiver = address(this); + uint256 maxMintBefore = vault.maxMint(receiver); + asset.mint(receiver, tokens); + uint256 maxMintAfter = vault.maxMint(receiver); + assertEq(maxMintBefore, maxMintAfter, "maxMint must assume the agent has infinite assets"); + } + + /// @notice verify `previewMint()` does not account for msg.sender asset balance + function verify_previewMintIgnoresSender(uint256 tokens, uint256 shares) public { + address receiver = address(this); + uint256 assetsExpectedBefore = vault.previewMint(shares); + prepareAddressForDeposit(receiver, tokens); + + uint256 assetsExpectedAfter = vault.previewMint(shares); + assertEq(assetsExpectedBefore, assetsExpectedAfter, "previewMint must not be dependent on msg.sender"); + } + + /// @notice verify `previewDeposit()` does not account for msg.sender asset balance + function verify_previewDepositIgnoresSender(uint256 tokens) public { + address receiver = address(this); + uint256 sharesExpectedBefore = vault.previewDeposit(tokens); + prepareAddressForDeposit(receiver, tokens); + + uint256 sharesExpectedAfter = vault.previewDeposit(tokens); + assertEq(sharesExpectedBefore, sharesExpectedAfter, "previewDeposit must not be dependent on msg.sender"); + } + + /// @notice verify `previewWithdraw()` does not account for msg.sender asset balance + function verify_previewWithdrawIgnoresSender(uint256 tokens) public { + address receiver = address(this); + uint256 sharesExpectedBefore = vault.previewWithdraw(tokens); + prepareAddressForDeposit(receiver, tokens); + + vault.deposit(tokens, receiver); + + uint256 sharesExpectedAfter = vault.previewWithdraw(tokens); + assertEq(sharesExpectedBefore, sharesExpectedAfter, "previewWithdraw must not be dependent on msg.sender"); + + // keep this property relatively stateless + vault.redeem(vault.balanceOf(receiver), receiver, receiver); + } + + /// @notice verify `previewRedeem()` does not account for msg.sender asset balance + function verify_previewRedeemIgnoresSender(uint256 shares) public { + address receiver = address(this); + uint256 tokensExpectedBefore = vault.previewRedeem(shares); + + uint256 assetsToDeposit = vault.previewMint(shares); + prepareAddressForDeposit(receiver, assetsToDeposit); + + vault.deposit(assetsToDeposit, receiver); + + uint256 tokensExpectedAfter = vault.previewRedeem(shares); + assertEq(tokensExpectedBefore, tokensExpectedAfter, "previewRedeem must not be dependent on msg.sender"); + + // keep this property relatively stateless + vault.redeem(vault.balanceOf(receiver), receiver, receiver); + } +} diff --git a/lib/crytic/contracts/ERC4626/properties/VaultProxy.sol b/lib/crytic/contracts/ERC4626/properties/VaultProxy.sol new file mode 100644 index 0000000..c8c7984 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/properties/VaultProxy.sol @@ -0,0 +1,57 @@ +pragma solidity ^0.8.0; +import {CryticERC4626PropertyBase} from "../util/ERC4626PropertyTestBase.sol"; +import {CryticIERC4626Internal} from "../util/IERC4626Internal.sol"; + +contract CryticERC4626VaultProxy is CryticERC4626PropertyBase { + function recognizeProfitProxy(uint256 profit) public { + require(supportsInternalTestingIface); + require(vault.totalSupply() > 0); + CryticIERC4626Internal(address(vault)).recognizeProfit(profit); + } + + function recognizeLossProxy(uint256 loss) public { + require(supportsInternalTestingIface); + require(vault.totalSupply() > 0); + CryticIERC4626Internal(address(vault)).recognizeLoss(loss); + } + + /// @dev intended to be used when property violations are being shrunk + function depositForSelfSimple(uint256 assets) public { + asset.mint(address(this), assets); + asset.approve(address(vault), assets); + vault.deposit(assets, address(this)); + } + + function redeemForSelfSimple(uint256 shares) public { + shares = clampLte(shares, vault.balanceOf(address(this))); + vault.redeem(shares, address(this), address(this)); + } + + // consider removing/refactoring the following since they're so unlikely to be useful during testing + function deposit(uint256 assets, uint256 receiverId) public { + address receiver = restrictAddressToThirdParties(receiverId); + vault.deposit(assets, receiver); + } + + function withdraw(uint256 assets, uint256 ownerId, uint256 receiverId) public { + address receiver = restrictAddressToThirdParties(receiverId); + address owner = restrictAddressToThirdParties(ownerId); + vault.withdraw(assets, receiver, owner); + } + + function mint(uint256 shares, uint256 receiverId) public { + address receiver = restrictAddressToThirdParties(receiverId); + vault.mint(shares, receiver); + } + + function redeem(uint256 shares, uint256 ownerId, uint256 receiverId) public { + address receiver = restrictAddressToThirdParties(receiverId); + address owner = restrictAddressToThirdParties(ownerId); + vault.redeem(shares, receiver, owner); + } + + function mintAsset(uint256 assets, uint256 receiverId) public { + address receiver = restrictAddressToThirdParties(receiverId); + asset.mint(receiver, assets); + } +} diff --git a/lib/crytic/contracts/ERC4626/test/Solmate4626.sol b/lib/crytic/contracts/ERC4626/test/Solmate4626.sol new file mode 100644 index 0000000..ffb94e6 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/test/Solmate4626.sol @@ -0,0 +1,34 @@ +pragma solidity ^0.8.0; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import {ERC4626} from "solmate/src/mixins/ERC4626.sol"; +import {CryticERC4626PropertyTests} from "../ERC4626PropertyTests.sol"; +import {TestERC20Token} from "../util/TestERC20Token.sol"; +import {CryticERC4626SecurityProps} from "../properties/SecurityProps.sol"; + +/// @notice Basic solmate 4626 impl for property validation/testing. +contract Solmate4626 is ERC4626 { + uint256 private _totalAssets; + + constructor(ERC20 _asset) ERC4626(_asset, "Test Vault",_asset.symbol()) {} + + function totalAssets() public view virtual override returns (uint256) { + return _totalAssets; + } + + function beforeWithdraw(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets - assets; + } + + function afterDeposit(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets + assets; + } +} + +contract TestHarness is CryticERC4626PropertyTests{ + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + ERC4626 _vault = new Solmate4626(ERC20(address(_asset))); + initialize(address(_vault), address(_asset)); + } +} diff --git a/lib/crytic/contracts/ERC4626/test/echidna.config.yaml b/lib/crytic/contracts/ERC4626/test/echidna.config.yaml new file mode 100644 index 0000000..5984852 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/test/echidna.config.yaml @@ -0,0 +1,7 @@ +coverage: true +corpusDir: "corpus" +testMode: assertion +testLimit: 100000 +cryticArgs: + - --solc-remaps + - ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ solmate/=lib/solmate/ \ No newline at end of file diff --git a/lib/crytic/contracts/ERC4626/test/rounding/BadConvertToAssetsRounding.sol b/lib/crytic/contracts/ERC4626/test/rounding/BadConvertToAssetsRounding.sol new file mode 100644 index 0000000..6020a1e --- /dev/null +++ b/lib/crytic/contracts/ERC4626/test/rounding/BadConvertToAssetsRounding.sol @@ -0,0 +1,59 @@ +pragma solidity ^0.8.0; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import {ERC4626} from "solmate/src/mixins/ERC4626.sol"; +import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; + +import {CryticERC4626PropertyTests} from "../../ERC4626PropertyTests.sol"; +import {TestERC20Token} from "../../util/TestERC20Token.sol"; +import {CryticERC4626RedeemUsingApproval} from "../../properties/RedeemUsingApprovalProps.sol"; +import {CryticERC4626SenderIndependent} from "../../properties/SenderIndependentProps.sol"; +import {CryticERC4626MustNotRevert} from "../../properties/MustNotRevertProps.sol"; +import {CryticERC4626FunctionalAccounting} from "../../properties/FunctionalAccountingProps.sol"; +import {CryticERC4626Rounding} from "../../properties/RoundingProps.sol"; +import {CryticERC4626VaultProxy} from "../../properties/VaultProxy.sol"; + +contract BadConvertToAssetsRounding is ERC4626 { + using FixedPointMathLib for uint256; + + uint256 private _totalAssets; + + constructor(ERC20 _asset) ERC4626(_asset,"Test Vault", _asset.symbol()) { + } + + function totalAssets() public view virtual override returns (uint256) { + return _totalAssets; + } + + function beforeWithdraw(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets - assets; + } + + function afterDeposit(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets + assets; + } + + function convertToAssets(uint256 shares) public view override returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); + } + + function recognizeProfit(uint256 profit) public { + TestERC20Token(address(asset)).mint(address(this), profit); + _totalAssets += profit; + } + + function recognizeLoss(uint256 loss) public { + TestERC20Token(address(asset)).burn(address(this), loss); + _totalAssets -= loss; + } + +} + +contract TestHarness is CryticERC4626Rounding{ + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + ERC4626 _vault = new BadConvertToAssetsRounding(ERC20(address(_asset))); + initialize(address(_vault), address(_asset), true); + } +} diff --git a/lib/crytic/contracts/ERC4626/test/rounding/BadConvertToSharesRounding.sol b/lib/crytic/contracts/ERC4626/test/rounding/BadConvertToSharesRounding.sol new file mode 100644 index 0000000..3e21439 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/test/rounding/BadConvertToSharesRounding.sol @@ -0,0 +1,58 @@ +pragma solidity ^0.8.0; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import {ERC4626} from "solmate/src/mixins/ERC4626.sol"; +import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; + +import {TestERC20Token} from "../../util/TestERC20Token.sol"; +import {CryticERC4626PropertyTests} from "../../ERC4626PropertyTests.sol"; +import {CryticERC4626Rounding} from "../../properties/RoundingProps.sol"; + +contract BadConvertToSharesRounding is ERC4626 { + using FixedPointMathLib for uint256; + + uint256 private _totalAssets; + + constructor(ERC20 _asset) ERC4626(_asset, "Test Vault", _asset.symbol()) { + } + + function totalAssets() public view virtual override returns (uint256) { + return _totalAssets; + } + + function beforeWithdraw(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets - assets; + } + + function afterDeposit(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets + assets; + } + + function convertToShares(uint256 assets) public view override returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + if(supply == 0){ + return assets; + } else { + return assets.mulDivUp(supply, totalAssets()); + } + } + + function recognizeProfit(uint256 profit) public { + TestERC20Token(address(asset)).mint(address(this), profit); + _totalAssets += profit; + } + + function recognizeLoss(uint256 loss) public { + TestERC20Token(address(asset)).burn(address(this), loss); + _totalAssets -= loss; + } +} + +contract TestHarness is CryticERC4626Rounding{ + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + ERC4626 _vault = new BadConvertToSharesRounding(ERC20(address(_asset))); + initialize(address(_vault), address(_asset), true); + } +} diff --git a/lib/crytic/contracts/ERC4626/test/rounding/BadPreviewMintRounding.sol b/lib/crytic/contracts/ERC4626/test/rounding/BadPreviewMintRounding.sol new file mode 100644 index 0000000..c93a221 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/test/rounding/BadPreviewMintRounding.sol @@ -0,0 +1,58 @@ +pragma solidity ^0.8.0; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import {ERC4626} from "solmate/src/mixins/ERC4626.sol"; +import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; + +import {CryticERC4626PropertyTests} from "../../ERC4626PropertyTests.sol"; +import {TestERC20Token} from "../../util/TestERC20Token.sol"; +import {CryticERC4626Rounding} from "../../properties/RoundingProps.sol"; + +contract BadPreviewMintRounding is ERC4626 { + using FixedPointMathLib for uint256; + + uint256 private _totalAssets; + + constructor(ERC20 _asset) ERC4626(_asset,"Test Vault", _asset.symbol()) { + // initialize the vault such that price per share != 1:1 + _totalAssets = 0.001 ether; + totalSupply = 1 ether; + } + + function totalAssets() public view virtual override returns (uint256) { + return _totalAssets; + } + + function beforeWithdraw(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets - assets; + } + + function afterDeposit(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets + assets; + } + + function previewMint(uint256 shares) public view override returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply); + } + + function recognizeProfit(uint256 profit) public { + TestERC20Token(address(asset)).mint(address(this), profit); + _totalAssets += profit; + } + + function recognizeLoss(uint256 loss) public { + TestERC20Token(address(asset)).burn(address(this), loss); + _totalAssets -= loss; + } + +} + +contract TestHarness is CryticERC4626Rounding{ + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + ERC4626 _vault = new BadPreviewMintRounding(ERC20(address(_asset))); + initialize(address(_vault), address(_asset), true); + } +} diff --git a/lib/crytic/contracts/ERC4626/test/rounding/BadPreviewWithdrawRounding.sol b/lib/crytic/contracts/ERC4626/test/rounding/BadPreviewWithdrawRounding.sol new file mode 100644 index 0000000..d3ac907 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/test/rounding/BadPreviewWithdrawRounding.sol @@ -0,0 +1,57 @@ +pragma solidity ^0.8.0; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import {ERC4626} from "solmate/src/mixins/ERC4626.sol"; +import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; + +import {CryticERC4626PropertyTests} from "../../ERC4626PropertyTests.sol"; +import {TestERC20Token} from "../../util/TestERC20Token.sol"; +import {CryticERC4626Rounding} from "../../properties/RoundingProps.sol"; + +contract BadPreviewWithdrawRounding is ERC4626 { + using FixedPointMathLib for uint256; + + uint256 private _totalAssets; + + constructor(ERC20 _asset) ERC4626(_asset, "Test Vault", _asset.symbol()) { + // initialize the vault such that price per share != 1:1 + _totalAssets = 1 ether; + totalSupply = 0.001 ether; + } + + function totalAssets() public view virtual override returns (uint256) { + return _totalAssets; + } + + function beforeWithdraw(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets - assets; + } + + function afterDeposit(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets + assets; + } + + function previewWithdraw(uint256 assets) public view override returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); + } + + function recognizeProfit(uint256 profit) public { + TestERC20Token(address(asset)).mint(address(this), profit); + _totalAssets += profit; + } + + function recognizeLoss(uint256 loss) public { + TestERC20Token(address(asset)).burn(address(this), loss); + _totalAssets -= loss; + } +} + +contract TestHarness is CryticERC4626Rounding{ + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + ERC4626 _vault = new BadPreviewWithdrawRounding(ERC20(address(_asset))); + initialize(address(_vault),address(_asset), true); + } +} diff --git a/lib/crytic/contracts/ERC4626/test/security/BadShareInflation.sol b/lib/crytic/contracts/ERC4626/test/security/BadShareInflation.sol new file mode 100644 index 0000000..a34294f --- /dev/null +++ b/lib/crytic/contracts/ERC4626/test/security/BadShareInflation.sol @@ -0,0 +1,32 @@ +pragma solidity ^0.8.0; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import {ERC4626} from "solmate/src/mixins/ERC4626.sol"; +import {CryticERC4626PropertyTests} from "../../ERC4626PropertyTests.sol"; +import {TestERC20Token} from "../../util/TestERC20Token.sol"; +import {CryticERC4626SecurityProps} from "../../properties/SecurityProps.sol"; + +/// @notice Basic solmate 4626 impl for property validation/testing. +contract BadShareInflation is ERC4626 { + uint256 private _totalAssets; + + constructor(ERC20 _asset) ERC4626(_asset, "Test Vault", _asset.symbol()) {} + + function totalAssets() public view virtual override returns (uint256) { + return asset.balanceOf(address(this)); + } + + function beforeWithdraw(uint256 assets, uint256) internal override { + } + + function afterDeposit(uint256 assets, uint256) internal override { + } +} + +contract TestHarness is CryticERC4626SecurityProps { + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + ERC4626 _vault = new BadShareInflation(ERC20(address(_asset))); + initialize(address(_vault), address(_asset), false); + } +} diff --git a/lib/crytic/contracts/ERC4626/test/usingApproval/BadAllowanceUpdate.sol b/lib/crytic/contracts/ERC4626/test/usingApproval/BadAllowanceUpdate.sol new file mode 100644 index 0000000..5884c7b --- /dev/null +++ b/lib/crytic/contracts/ERC4626/test/usingApproval/BadAllowanceUpdate.sol @@ -0,0 +1,85 @@ +pragma solidity ^0.8.0; + +import {ERC20} from "solmate/src/tokens/ERC20.sol"; +import {ERC4626} from "solmate/src/mixins/ERC4626.sol"; +import {FixedPointMathLib} from "solmate/src/utils/FixedPointMathLib.sol"; +import {SafeTransferLib} from "solmate/src/utils/SafeTransferLib.sol"; + +import {CryticERC4626PropertyTests} from "../../ERC4626PropertyTests.sol"; +import {TestERC20Token} from "../../util/TestERC20Token.sol"; +import {CryticERC4626RedeemUsingApproval} from "../../properties/RedeemUsingApprovalProps.sol"; + +contract BadAllowanceUpdate is ERC4626 { + using FixedPointMathLib for uint256; + using SafeTransferLib for ERC20; + + uint256 private _totalAssets; + + constructor(ERC20 _asset) ERC4626(_asset, "Test Vault", _asset.symbol()) { + } + + function totalAssets() public view virtual override returns (uint256) { + return _totalAssets; + } + + function beforeWithdraw(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets - assets; + } + + function afterDeposit(uint256 assets, uint256) internal override { + _totalAssets = _totalAssets + assets; + } + + function withdraw( + uint256 assets, + address receiver, + address owner + ) public override returns (uint256 shares) { + shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up. + + if (msg.sender != owner) { + uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. + + // if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; + } + + beforeWithdraw(assets, shares); + + _burn(owner, shares); + + emit Withdraw(msg.sender, receiver, owner, assets, shares); + + asset.safeTransfer(receiver, assets); + } + + function redeem( + uint256 shares, + address receiver, + address owner + ) public override returns (uint256 assets) { + if (msg.sender != owner) { + uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. + + // if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; + } + + // Check for rounding error since we round down in previewRedeem. + require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS"); + + beforeWithdraw(assets, shares); + + _burn(owner, shares); + + emit Withdraw(msg.sender, receiver, owner, assets, shares); + + asset.safeTransfer(receiver, assets); + } +} + +contract TestHarness is CryticERC4626RedeemUsingApproval{ + constructor () { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 18); + ERC4626 _vault = new BadAllowanceUpdate(ERC20(address(_asset))); + initialize(address(_vault), address(_asset), false); + } +} diff --git a/lib/crytic/contracts/ERC4626/util/Actor.sol b/lib/crytic/contracts/ERC4626/util/Actor.sol new file mode 100644 index 0000000..9d61a15 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/util/Actor.sol @@ -0,0 +1,81 @@ +pragma solidity ^0.8.0; + +import {IERC4626} from "../../util/IERC4626.sol"; +import {TestERC20Token} from "../util/TestERC20Token.sol"; +import {PropertiesAsserts} from "../../util/PropertiesHelper.sol"; + +/// @notice This contract has two purposes: +/// 1. Act as a proxy for performing vault deposits/withdraws (since we don't have vm.prank) +/// 2. Keep track of how much the account has deposited/withdrawn & raise an error if the account can withdraw/redeem more than it deposited/minted. +/// @dev It's important that other property tests never send tokens/shares to the Actor contract address, or else the accounting will break. This restriction is enforced in restrictAddressToThirdParties() +/// If support is added for "harvesting" a vault during property tests, the accounting logic here needs to be updated to reflect cases where an actor can withdraw more than they deposited. +contract Actor is PropertiesAsserts { + TestERC20Token token; + IERC4626 vault; + + uint256 tokensDeposited; //tracks how many aggregate tokens this actor has deposited on its own behalf + uint256 sharesMinted; //tracks how many aggregate shares this actor has minted on its own behalf + + constructor(IERC4626 _vault) { + vault = _vault; + token = TestERC20Token(address(_vault.asset())); + } + + function accountForOpenedPosition(uint256 _tokensDeposited, uint256 _sharesMinted) internal { + tokensDeposited += _tokensDeposited; + sharesMinted += _sharesMinted; + } + + function accountForClosedPosition(uint256 _tokensReceived, uint256 _sharesBurned) internal { + assertLte(_sharesBurned, sharesMinted, "Actor has burned more shares than they ever minted. Implies a rounding or accounting error"); + assertLte(_tokensReceived, tokensDeposited, "Actor has withdrawn more tokens than they ever deposited. Implies a rounding or accounting error"); + tokensDeposited -= _tokensReceived; + sharesMinted -= _sharesBurned; + } + + function fund(uint256 amount) public { + token.mint(address(this), amount); + } + + function approveFunds() public { + token.approve(address(vault), type(uint256).max); + } + + function depositFunds(uint256 assets) public returns (uint256 _sharesMinted) { + _sharesMinted = vault.deposit(assets, address(this)); + accountForOpenedPosition(assets, _sharesMinted); + } + + function mintShares(uint256 shares) public returns (uint256 _tokensDeposited) { + _tokensDeposited = vault.mint(shares, address(this)); + accountForOpenedPosition(_tokensDeposited, shares); + } + + function withdrawTokens(uint256 assets) public returns (uint256 _sharesBurned) { + _sharesBurned = vault.withdraw(assets, address(this), address(this)); + accountForClosedPosition(assets, _sharesBurned); + } + + function redeemShares(uint256 shares) public returns (uint256 _tokensWithdrawn) { + _tokensWithdrawn = vault.redeem(shares, address(this), address(this)); + accountForClosedPosition(_tokensWithdrawn, shares); + } + + function depositFundsOnBehalf(uint256 assets, address receiver) public returns (uint256 _sharesMinted) { + _sharesMinted = vault.deposit(assets, receiver); + } + + function mintSharesOnBehalf(uint256 shares, address receiver) public returns (uint256 _tokensDeposited) { + _tokensDeposited = vault.mint(shares, receiver); + } + + function withdrawTokensOnBehalf(uint256 assets, address receiver) public returns (uint256 _sharesBurned) { + _sharesBurned = vault.withdraw(assets, receiver, address(this)); + accountForClosedPosition(assets, _sharesBurned); + } + + function redeemSharesOnBehalf(uint256 shares, address receiver) public returns (uint256 _tokensWithdrawn) { + _tokensWithdrawn = vault.redeem(shares, receiver, address(this)); + accountForClosedPosition(_tokensWithdrawn, shares); + } +} diff --git a/lib/crytic/contracts/ERC4626/util/ERC4626PropertyTestBase.sol b/lib/crytic/contracts/ERC4626/util/ERC4626PropertyTestBase.sol new file mode 100644 index 0000000..3253913 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/util/ERC4626PropertyTestBase.sol @@ -0,0 +1,155 @@ +pragma solidity ^0.8.0; + +import {IERC20} from "../../util/IERC20.sol"; +import {IERC4626} from "../../util/IERC4626.sol"; +import {TestERC20Token} from "./TestERC20Token.sol"; +import {Actor} from "../util/Actor.sol"; +import {PropertiesAsserts} from "../../util/PropertiesHelper.sol"; +import {RedemptionProxy} from "./RedemptionProxy.sol"; + +/// @notice This contract is used as a base contract for all 4626 property tests. +contract CryticERC4626PropertyBase is PropertiesAsserts { + TestERC20Token asset; + IERC4626 vault; + + Actor alice; + Actor bob; //remove? + + RedemptionProxy redemptionProxy; + + // feature flags + bool supportsInternalTestingIface; + + function initialize(address _vault, address _asset, bool _supportsInternalTestingIface) internal { + vault = IERC4626(_vault); + asset = TestERC20Token(_asset); + alice = new Actor(vault); + bob = new Actor(vault); + redemptionProxy = new RedemptionProxy(vault); + supportsInternalTestingIface = _supportsInternalTestingIface; + } + + /// @notice Funds the `owner` address with `tokens` & forces a token approval for the vault to spend owner's tokens. + function prepareAddressForDeposit(address owner, uint256 tokens) internal { + asset.mint(owner, tokens); + asset.forceApproval(owner, address(vault), tokens); + } + + /// @notice Measures the `target`'s assets and shares, and emits events to assist in debugging property failures. + /// @param target A address to target + /// @param name A name for the target address (alice, bob, vault, etc.) + /// @param annotation An additional piece of metadata for debugging ie: "before deposit", "after mint", etc. + function measureAddressHoldings(address target, string memory name, string memory annotation) internal + returns (uint256 assetBalance, uint256 shareBalance) { + + assetBalance = asset.balanceOf(target); + shareBalance = vault.balanceOf(target); + + string memory assetMsg = string(abi.encodePacked("asset.balanceOf(", name, ") (", annotation, ")")); + emit LogUint256(assetMsg, assetBalance); + string memory shareMsg = string(abi.encodePacked("vault.balanceOf(", name, ") (", annotation, ")")); + emit LogUint256(shareMsg, shareBalance); + } + + /// @notice Prevents `party` from resolving to addresses which have special accounting rules. + function restrictAddressToThirdParties(uint256 partyIndex) internal view returns (address) { + // set up 3 static third parties + partyIndex = partyIndex % 3; + if(partyIndex == 0){ + return address(this); + } + if(partyIndex == 1){ + return 0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa; + } + return 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB; + } + + + /// @notice Performs all the checks required to ensure a successful vault deposit. This includes funding the owner account and clamping token amounts as needed. + /// It is assumed that successful calls to requireValidDepositAmount imply that vault.deposit() will not revert. This implied property might not hold for certain + /// vault implementations, and should be modified if exceptions are discovered. + function requireValidDepositAmount(address owner, address receiver, uint256 tokens) internal returns (uint256) { + tokens = clampLte(tokens, vault.maxDeposit(receiver)); + tokens = clampGt(tokens, 0); + prepareAddressForDeposit(owner, tokens); + + + // The following logic is intended to revert when an unreasonably large deposit is being made. + uint256 sharesMinted = vault.convertToShares(tokens); + uint256 currentShares = vault.balanceOf(receiver); + vault.convertToAssets(sharesMinted + currentShares); + //uint256 sharesRedeemed = vault.previewWithdraw(tokensWithdrawn); + emit LogUint256("Tokens to use in deposit:", tokens); + + // configure with setting? + require(vault.previewDeposit(tokens) > 0); + return tokens; + } + + /// @notice Performs all the checks required to ensure a successful vault mint. This includes funding the owner account and clamping token amounts as needed. + /// It is assumed that successful calls to requireValidDepositAmount imply that vault.mint() will not revert. This implied property might not hold for certain + /// vault implementations, and should be modified if exceptions are discovered. + function requireValidMintAmount(address owner, address receiver, uint256 shares) internal returns (uint256) { + shares = clampLte(shares, vault.maxMint(receiver)); + uint256 tokensDeposited = vault.previewMint(shares); + prepareAddressForDeposit(owner, tokensDeposited); + + // The following logic is intended to revert when an unreasonably large mint is being made. + uint256 currentShares = vault.balanceOf(receiver); + vault.previewRedeem(currentShares + shares ); + emit LogUint256("Shares to use in mint:", shares); + + // configure with setting? + // require(vault.previewMint(shares) > 0); + return shares; + } + + /// @notice Performs all the checks required to ensure a successful vault redeem. This includes funding the owner account and clamping token amounts as needed. + /// It is assumed that successful calls to requireValidDepositAmount imply that vault.redeem() will not revert. This implied property might not hold for certain + /// vault implementations, and should be modified if exceptions are discovered. + function requireValidRedeemAmount(address owner, uint256 shares) internal returns (uint256) { + // should this be a configured setting? + require(shares > 0); + + uint256 maxRedeem = vault.maxRedeem(owner); + require(maxRedeem > 0); + uint256 ownerShares = vault.balanceOf(owner); + require(ownerShares > 0); + + shares = clampLte(shares, maxRedeem); + shares = clampLte(shares, ownerShares); + + // The following logic is intended to revert when an unreasonably large redemption is being made. + uint256 tokensWithdrawn = vault.convertToAssets(shares); + vault.previewRedeem(shares); + // should this be a configured setting? + require(tokensWithdrawn > 0); + emit LogUint256("Shares to use in redemption:", shares); + return shares; + } + + /// @notice Performs all the checks required to ensure a successful vault withdraw. This includes funding the owner account and clamping token amounts as needed. + /// It is assumed that successful calls to requireValidDepositAmount imply that vault.withdraw() will not revert. This implied property might not hold for certain + /// vault implementations, and should be modified if exceptions are discovered. + function requireValidWithdrawAmount(address owner, uint256 tokens) internal returns (uint256) { + uint256 maxWithdraw = vault.maxWithdraw(owner); + require(maxWithdraw > 0); + + uint256 ownerBalance = vault.balanceOf(owner); + require(ownerBalance > 0); + + uint256 sharesToRedeem = vault.previewWithdraw(tokens); + sharesToRedeem = clampLte(sharesToRedeem, vault.balanceOf(owner)); + require(sharesToRedeem <= ownerBalance); + + // not easy to clamp these without making this code a lot more complex. + uint256 clampedTokens = vault.previewRedeem(sharesToRedeem); + require(clampedTokens <= maxWithdraw); + // should this be a configured setting? + require(sharesToRedeem > 0); + + // we don't need to check for unreasonably large withdraws because previewWithdraw would have reverted. + emit LogUint256("Tokens to use in withdraw:", clampedTokens); + return clampedTokens; + } +} diff --git a/lib/crytic/contracts/ERC4626/util/IERC4626Internal.sol b/lib/crytic/contracts/ERC4626/util/IERC4626Internal.sol new file mode 100644 index 0000000..3e4a989 --- /dev/null +++ b/lib/crytic/contracts/ERC4626/util/IERC4626Internal.sol @@ -0,0 +1,10 @@ +pragma solidity ^0.8.0; + +/// @notice Developers may optionally implement these interfaces on their Vault contract to increase coverage/enable rounding tests. +interface CryticIERC4626Internal { + /// @notice Called by the fuzzer. The vault implementation should use TestERC20Token.mint() to credit itself with the amount of profit. + function recognizeProfit(uint256 profit) external; + + /// @notice Called by the fuzzer. The vault implementation should use TestERC20Token.burn()/.transfer() to account for the amount of loss. + function recognizeLoss(uint256 loss) external; +} \ No newline at end of file diff --git a/lib/crytic/contracts/ERC4626/util/RedemptionProxy.sol b/lib/crytic/contracts/ERC4626/util/RedemptionProxy.sol new file mode 100644 index 0000000..007c28d --- /dev/null +++ b/lib/crytic/contracts/ERC4626/util/RedemptionProxy.sol @@ -0,0 +1,19 @@ +pragma solidity ^0.8.0; + +import {IERC4626} from "../../util/IERC4626.sol"; + +contract RedemptionProxy { + IERC4626 vault; + + constructor(IERC4626 _vault) { + vault = _vault; + } + + function redeemOnBehalf(uint256 shares, address receiver, address owner) public returns (uint256 tokensWithdrawn) { + tokensWithdrawn = vault.redeem(shares, receiver, owner ); + } + + function withdrawOnBehalf(uint256 tokens, address receiver, address owner) public returns (uint256 sharesRedeemed) { + sharesRedeemed = vault.withdraw(tokens, receiver, owner ); + } +} \ No newline at end of file diff --git a/lib/crytic/contracts/ERC4626/util/TestERC20Token.sol b/lib/crytic/contracts/ERC4626/util/TestERC20Token.sol new file mode 100644 index 0000000..c410d9e --- /dev/null +++ b/lib/crytic/contracts/ERC4626/util/TestERC20Token.sol @@ -0,0 +1,76 @@ +pragma solidity ^0.8.0; + +contract TestERC20Token { + + event Transfer(address indexed from, address indexed to, uint256 amount); + event Approval(address indexed owner, address indexed spender, uint256 amount); + + string public name; + string public symbol; + uint256 public decimals; + uint256 public totalSupply; + mapping(address => uint256) public balanceOf; + mapping(address => mapping(address => uint256)) public allowance; + + constructor( + string memory _name, + string memory _symbol, + uint256 _decimals + ) { + name = _name; + symbol = _symbol; + decimals = _decimals; + } + + function approve(address spender, uint256 amount) public returns (bool) { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + return true; + } + + function transfer(address to, uint256 amount) public returns (bool) { + balanceOf[msg.sender] -= amount; + balanceOf[to] += amount; + + emit Transfer(msg.sender, to, amount); + return true; + } + + function transferFrom( + address from, + address to, + uint256 amount) + public returns (bool) { + + uint256 spenderAllowance = allowance[from][msg.sender]; + if (spenderAllowance != type(uint256).max) { + allowance[from][msg.sender] = spenderAllowance - amount; + } + + balanceOf[from] -= amount; + balanceOf[to] += amount; + + emit Transfer(from, to, amount); + return true; + } + + function mint(address to, uint256 amount) public { + totalSupply += amount; + balanceOf[to] += amount; + + emit Transfer(address(0), to, amount); + } + + function burn(address from, uint256 amount) public { + totalSupply -= amount; + balanceOf[from] -= amount; + + emit Transfer(from, address(0), amount); + } + + function forceApproval(address account, address spender, uint256 amount) public { + allowance[account][spender] = amount; + emit Approval(account, spender, amount); + } +} \ No newline at end of file diff --git a/lib/crytic/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol b/lib/crytic/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol new file mode 100644 index 0000000..ffca89a --- /dev/null +++ b/lib/crytic/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol @@ -0,0 +1,1829 @@ +pragma solidity ^0.8.0; + +import "./abdk-libraries-solidity/ABDKMath64x64.sol"; + +contract CryticABDKMath64x64Properties { + + /* ================================================================ + 64x64 fixed-point constants used for testing specific values. + This assumes that ABDK library's fromInt(x) works as expected. + ================================================================ */ + int128 internal ZERO_FP = ABDKMath64x64.fromInt(0); + int128 internal ONE_FP = ABDKMath64x64.fromInt(1); + int128 internal MINUS_ONE_FP = ABDKMath64x64.fromInt(-1); + int128 internal TWO_FP = ABDKMath64x64.fromInt(2); + int128 internal THREE_FP = ABDKMath64x64.fromInt(3); + int128 internal EIGHT_FP = ABDKMath64x64.fromInt(8); + int128 internal THOUSAND_FP = ABDKMath64x64.fromInt(1000); + int128 internal MINUS_SIXTY_FOUR_FP = ABDKMath64x64.fromInt(-64); + int128 internal EPSILON = 1; + int128 internal ONE_TENTH_FP = ABDKMath64x64.div(ABDKMath64x64.fromInt(1), ABDKMath64x64.fromInt(10)); + + /* ================================================================ + Constants used for precision loss calculations + ================================================================ */ + uint256 internal REQUIRED_SIGNIFICANT_BITS = 10; + + /* ================================================================ + Integer representations maximum values. + These constants are used for testing edge cases or limits for + possible values. + ================================================================ */ + int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; + int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + int256 private constant MAX_256 = + 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + int256 private constant MIN_256 = + -0x8000000000000000000000000000000000000000000000000000000000000000; + uint256 private constant MAX_U256 = + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + /* ================================================================ + Events used for debugging or showing information. + ================================================================ */ + event Value(string reason, int128 val); + event LogErr(bytes error); + + /* ================================================================ + Helper functions. + ================================================================ */ + + // These functions allows to compare a and b for equality, discarding + // the last precision_bits bits. + // An absolute value function is implemented inline in order to not use + // the implementation from the library under test. + function equal_within_precision(int128 a, int128 b, uint256 precision_bits) public pure returns(bool) { + int128 max = (a > b) ? a : b; + int128 min = (a > b) ? b : a; + int128 r = (max - min) >> precision_bits; + + return (r == 0); + } + + function equal_within_precision_u(uint256 a, uint256 b, uint256 precision_bits) public pure returns(bool) { + uint256 max = (a > b) ? a : b; + uint256 min = (a > b) ? b : a; + uint256 r = (max - min) >> precision_bits; + + return (r == 0); + } + + // This function determines if the relative error between a and b is less + // than error_percent % (expressed as a 64x64 value) + // Uses functions from the library under test! + function equal_within_tolerance(int128 a, int128 b, int128 error_percent) public pure returns(bool) { + int128 tol_value = abs(mul(a, div(error_percent, fromUInt(100)))); + + return (abs(sub(b, a)) <= tol_value); + } + + // Check that there are remaining significant digits after a multiplication + // Uses functions from the library under test! + function significant_digits_lost_in_mult(int128 a, int128 b) public pure returns (bool) { + int128 x = a >= 0 ? a : -a; + int128 y = b >= 0 ? b : -b; + + int128 lx = toInt(log_2(x)); + int128 ly = toInt(log_2(y)); + + return(lx + ly - 1 <= -64); + } + + // Return how many significant bits will remain after multiplying a and b + // Uses functions from the library under test! + function significant_bits_after_mult(int128 a, int128 b) public pure returns (uint256) { + int128 x = a >= 0 ? a : -a; + int128 y = b >= 0 ? b : -b; + + int128 lx = toInt(log_2(x)); + int128 ly = toInt(log_2(y)); + int256 prec = lx + ly - 1; + + if (prec < -64) return 0; + else return(64 + uint256(prec)); + } + + // Return the i most significant bits from |n|. If n has less than i significant bits, return |n| + // Uses functions from the library under test! + function most_significant_bits(int128 n, uint256 i) public pure returns (uint256) { + // Create a mask consisting of i bits set to 1 + uint256 mask = (2**i) - 1; + + // Get the position of the MSB set to 1 of n + uint256 pos = uint64(toInt(log_2(n)) + 64 + 1); + + // Get the positive value of n + uint256 value = (n>0) ? uint128(n) : uint128(-n); + + // Shift the mask to match the rightmost 1-set bit + if(pos > i) { mask <<= (pos - i); } + + return (value & mask); + } + + // Returns true if the n most significant bits of a and b are almost equal + // Uses functions from the library under test! + function equal_most_significant_bits_within_precision(int128 a, int128 b, uint256 bits) public pure returns (bool) { + // Get the number of bits in a and b + // Since log(x) returns in the interval [-64, 63), add 64 to be in the interval [0, 127) + uint256 a_bits = uint256(int256(toInt(log_2(a)) + 64)); + uint256 b_bits = uint256(int256(toInt(log_2(b)) + 64)); + + // a and b lengths may differ in 1 bit, so the shift should take into account the longest + uint256 shift_bits = (a_bits > b_bits) ? (a_bits - bits) : (b_bits - bits); + + // Get the _bits_ most significant bits of a and b + uint256 a_msb = most_significant_bits(a, bits) >> shift_bits; + uint256 b_msb = most_significant_bits(b, bits) >> shift_bits; + + // See if they are equal within 1 bit precision + // This could be modified to get the precision as a parameter to the function + return equal_within_precision_u(a_msb, b_msb, 1); + } + + /* ================================================================ + Library wrappers. + These functions allow calling the ABDKMath64x64 library. + ================================================================ */ + function debug(string calldata x, int128 y) public { + emit Value(x, ABDKMath64x64.toInt(y)); + } + + function fromInt(int256 x) public pure returns (int128) { + return ABDKMath64x64.fromInt(x); + } + + function toInt(int128 x) public pure returns (int64) { + return ABDKMath64x64.toInt(x); + } + + function fromUInt(uint256 x) public pure returns (int128) { + return ABDKMath64x64.fromUInt(x); + } + + function toUInt(int128 x) public pure returns (uint64) { + return ABDKMath64x64.toUInt(x); + } + + function add(int128 x, int128 y) public pure returns (int128) { + return ABDKMath64x64.add(x, y); + } + + function sub(int128 x, int128 y) public pure returns (int128) { + return ABDKMath64x64.sub(x, y); + } + + function mul(int128 x, int128 y) public pure returns (int128) { + return ABDKMath64x64.mul(x, y); + } + + function mulu(int128 x, uint256 y) public pure returns (uint256) { + return ABDKMath64x64.mulu(x, y); + } + + function div(int128 x, int128 y) public pure returns (int128) { + return ABDKMath64x64.div(x, y); + } + + function neg(int128 x) public pure returns (int128) { + return ABDKMath64x64.neg(x); + } + + function abs(int128 x) public pure returns (int128) { + return ABDKMath64x64.abs(x); + } + + function inv(int128 x) public pure returns (int128) { + return ABDKMath64x64.inv(x); + } + + function avg(int128 x, int128 y) public pure returns (int128) { + return ABDKMath64x64.avg(x, y); + } + + function gavg(int128 x, int128 y) public pure returns (int128) { + return ABDKMath64x64.gavg(x, y); + } + + function pow(int128 x, uint256 y) public pure returns (int128) { + return ABDKMath64x64.pow(x, y); + } + + function sqrt(int128 x) public pure returns (int128) { + return ABDKMath64x64.sqrt(x); + } + + function log_2(int128 x) public pure returns (int128) { + return ABDKMath64x64.log_2(x); + } + + function ln(int128 x) public pure returns (int128) { + return ABDKMath64x64.ln(x); + } + + function exp_2(int128 x) public pure returns (int128) { + return ABDKMath64x64.exp_2(x); + } + + function exp(int128 x) public pure returns (int128) { + return ABDKMath64x64.exp(x); + } + + + /* ================================================================ + Start of tests + ================================================================ */ + + + + /* ================================================================ + + TESTS FOR FUNCTION add() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for commutative property + // x + y == y + x + function add_test_commutative(int128 x, int128 y) public pure { + int128 x_y = add(x, y); + int128 y_x = add(y, x); + + assert(x_y == y_x); + } + + // Test for associative property + // (x + y) + z == x + (y + z) + function add_test_associative(int128 x, int128 y, int128 z) public pure { + int128 x_y = add(x, y); + int128 y_z = add(y, z); + int128 xy_z = add(x_y, z); + int128 x_yz = add(x, y_z); + + assert(xy_z == x_yz); + } + + // Test for identity operation + // x + 0 == x (equivalent to x + (-x) == 0) + function add_test_identity(int128 x) public view { + int128 x_0 = add(x, ZERO_FP); + + assert(x_0 == x); + assert(add(x, neg(x)) == ZERO_FP); + } + + // Test that the result increases or decreases depending + // on the value to be added + function add_test_values(int128 x, int128 y) public view { + int128 x_y = add(x, y); + + if (y >= ZERO_FP) { + assert(x_y >= x); + } else { + assert(x_y < x); + } + } + + + /* ================================================================ + Tests for overflow and edge cases. + These should make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // The result of the addition must be between the maximum + // and minimum allowed values for 64x64 + function add_test_range(int128 x, int128 y) public view { + int128 result; + try this.add(x, y) { + result = this.add(x, y); + assert(result <= MAX_64x64 && result >= MIN_64x64); + } catch { + // If it reverts, just ignore + } + } + + // Adding zero to the maximum value shouldn't revert, as it is valid + // Moreover, the result must be MAX_64x64 + function add_test_maximum_value() public view { + int128 result; + try this.add(MAX_64x64, ZERO_FP) { + // Expected behaviour, does not revert + result = this.add(MAX_64x64, ZERO_FP); + assert(result == MAX_64x64); + } catch { + assert(false); + } + } + + // Adding one to the maximum value should revert, as it is out of range + function add_test_maximum_value_plus_one() public view { + try this.add(MAX_64x64, ONE_FP) { + assert(false); + } catch { + // Expected behaviour, reverts + } + } + + // Adding zero to the minimum value shouldn't revert, as it is valid + // Moreover, the result must be MIN_64x64 + function add_test_minimum_value() public view { + int128 result; + try this.add(MIN_64x64, ZERO_FP) { + // Expected behaviour, does not revert + result = this.add(MIN_64x64, ZERO_FP); + assert(result == MIN_64x64); + } catch { + assert(false); + } + } + + // Adding minus one to the maximum value should revert, as it is out of range + function add_test_minimum_value_plus_negative_one() public view { + try this.add(MIN_64x64, MINUS_ONE_FP) { + assert(false); + } catch { + // Expected behaviour, reverts + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION sub() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test equivalence to addition + // x - y == x + (-y) + function sub_test_equivalence_to_addition(int128 x, int128 y) public pure { + int128 minus_y = neg(y); + int128 addition = add(x, minus_y); + int128 subtraction = sub(x, y); + + assert(addition == subtraction); + } + + // Test for non-commutative property + // x - y == -(y - x) + function sub_test_non_commutative(int128 x, int128 y) public pure { + int128 x_y = sub(x, y); + int128 y_x = sub(y, x); + + assert(x_y == neg(y_x)); + } + + // Test for identity operation + // x - 0 == x (equivalent to x - x == 0) + function sub_test_identity(int128 x) public view { + int128 x_0 = sub(x, ZERO_FP); + + assert(x_0 == x); + assert(sub(x, x) == ZERO_FP); + } + + // Test for neutrality over addition and subtraction + // (x - y) + y == (x + y) - y == x + function sub_test_neutrality(int128 x, int128 y) public pure { + int128 x_minus_y = sub(x, y); + int128 x_plus_y = add(x, y); + + int128 x_minus_y_plus_y = add(x_minus_y, y); + int128 x_plus_y_minus_y = sub(x_plus_y, y); + + assert(x_minus_y_plus_y == x_plus_y_minus_y); + assert(x_minus_y_plus_y == x); + } + + // Test that the result increases or decreases depending + // on the value to be subtracted + function sub_test_values(int128 x, int128 y) public view { + int128 x_y = sub(x, y); + + if (y >= ZERO_FP) { + assert(x_y <= x); + } else { + assert(x_y > x); + } + } + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // The result of the subtraction must be between the maximum + // and minimum allowed values for 64x64 + function sub_test_range(int128 x, int128 y) public view { + int128 result; + try this.sub(x, y) { + result = this.sub(x, y); + assert(result <= MAX_64x64 && result >= MIN_64x64); + } catch { + // If it reverts, just ignore + } + } + + // Subtracting zero from the maximum value shouldn't revert, as it is valid + // Moreover, the result must be MAX_64x64 + function sub_test_maximum_value() public view { + int128 result; + try this.sub(MAX_64x64, ZERO_FP) { + // Expected behaviour, does not revert + result = this.sub(MAX_64x64, ZERO_FP); + assert(result == MAX_64x64); + } catch { + assert(false); + } + } + + // Subtracting minus one from the maximum value should revert, + // as it is out of range + function sub_test_maximum_value_minus_neg_one() public view { + try this.sub(MAX_64x64, MINUS_ONE_FP) { + assert(false); + } catch { + // Expected behaviour, reverts + } + } + + // Subtracting zero from the minimum value shouldn't revert, as it is valid + // Moreover, the result must be MIN_64x64 + function sub_test_minimum_value() public view { + int128 result; + try this.sub(MIN_64x64, ZERO_FP) { + // Expected behaviour, does not revert + result = this.sub(MIN_64x64, ZERO_FP); + assert(result == MIN_64x64); + } catch { + assert(false); + } + } + + // Subtracting one from the minimum value should revert, as it is out of range + function sub_test_minimum_value_minus_one() public view { + try this.sub(MIN_64x64, ONE_FP) { + assert(false); + } catch { + // Expected behaviour, reverts + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION mul() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for commutative property + // x * y == y * x + function mul_test_commutative(int128 x, int128 y) public pure { + int128 x_y = mul(x, y); + int128 y_x = mul(y, x); + + assert(x_y == y_x); + } + + // Test for associative property + // (x * y) * z == x * (y * z) + function mul_test_associative(int128 x, int128 y, int128 z) public view { + int128 x_y = mul(x, y); + int128 y_z = mul(y, z); + int128 xy_z = mul(x_y, z); + int128 x_yz = mul(x, y_z); + + // Failure if all significant digits are lost + require(significant_bits_after_mult(x, y) > REQUIRED_SIGNIFICANT_BITS); + require(significant_bits_after_mult(y, z) > REQUIRED_SIGNIFICANT_BITS); + require(significant_bits_after_mult(x_y, z) > REQUIRED_SIGNIFICANT_BITS); + require(significant_bits_after_mult(x, y_z) > REQUIRED_SIGNIFICANT_BITS); + + assert(equal_within_tolerance(xy_z, x_yz, ONE_TENTH_FP)); + } + + // Test for distributive property + // x * (y + z) == x * y + x * z + function mul_test_distributive(int128 x, int128 y, int128 z) public view { + int128 y_plus_z = add(y, z); + int128 x_times_y_plus_z = mul(x, y_plus_z); + + int128 x_times_y = mul(x, y); + int128 x_times_z = mul(x, z); + + // Failure if all significant digits are lost + require(significant_bits_after_mult(x, y) > REQUIRED_SIGNIFICANT_BITS); + require(significant_bits_after_mult(x, z) > REQUIRED_SIGNIFICANT_BITS); + require(significant_bits_after_mult(x, y_plus_z) > REQUIRED_SIGNIFICANT_BITS); + + assert(equal_within_tolerance(add(x_times_y, x_times_z), x_times_y_plus_z, ONE_TENTH_FP)); + } + + // Test for identity operation + // x * 1 == x (also check that x * 0 == 0) + function mul_test_identity(int128 x) public view { + int128 x_1 = mul(x, ONE_FP); + int128 x_0 = mul(x, ZERO_FP); + + assert(x_0 == ZERO_FP); + assert(x_1 == x); + } + + // Test that the result increases or decreases depending + // on the value to be added + function mul_test_values(int128 x, int128 y) public view { + require(x != ZERO_FP && y != ZERO_FP); + + int128 x_y = mul(x, y); + + require(significant_digits_lost_in_mult(x, y) == false); + + if (x >= ZERO_FP) { + if (y >= ONE_FP) { + assert(x_y >= x); + } else { + assert(x_y <= x); + } + } else { + if (y >= ONE_FP) { + assert(x_y <= x); + } else { + assert(x_y >= x); + } + } + } + + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // The result of the multiplication must be between the maximum + // and minimum allowed values for 64x64 + function mul_test_range(int128 x, int128 y) public view { + int128 result; + try this.mul(x, y) { + result = this.mul(x, y); + assert(result <= MAX_64x64 && result >= MIN_64x64); + } catch { + // If it reverts, just ignore + } + } + + // Multiplying the maximum value times one shouldn't revert, as it is valid + // Moreover, the result must be MAX_64x64 + function mul_test_maximum_value() public view { + int128 result; + try this.mul(MAX_64x64, ONE_FP) { + // Expected behaviour, does not revert + result = this.mul(MAX_64x64, ONE_FP); + assert(result == MAX_64x64); + } catch { + assert(false); + } + } + + // Multiplying the minimum value times one shouldn't revert, as it is valid + // Moreover, the result must be MIN_64x64 + function mul_test_minimum_value() public view { + int128 result; + try this.mul(MIN_64x64, ONE_FP) { + // Expected behaviour, does not revert + result = this.mul(MIN_64x64, ONE_FP); + assert(result == MIN_64x64); + } catch { + assert(false); + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION div() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for identity property + // x / 1 == x (equivalent to x / x == 1) + // Moreover, x/x should not revert unless x == 0 + function div_test_division_identity(int128 x) public view { + int128 div_1 = div(x, ONE_FP); + assert(x == div_1); + + int128 div_x; + + try this.div(x, x) { + // This should always equal one + div_x = div(x, x); + assert(div_x == ONE_FP); + } catch { + // The only allowed case to revert is if x == 0 + assert(x == ZERO_FP); + } + + } + + // Test for negative divisor + // x / -y == -(x / y) + function div_test_negative_divisor(int128 x, int128 y) public view { + require(y < ZERO_FP); + + int128 x_y = div(x, y); + int128 x_minus_y = div(x, neg(y)); + + assert(x_y == neg(x_minus_y)); + } + + // Test for division with 0 as numerator + // 0 / x = 0 + function div_test_division_num_zero(int128 x) public view { + require(x != ZERO_FP); + + int128 div_0 = div(ZERO_FP, x); + + assert(ZERO_FP == div_0); + } + + // Test that the absolute value of the result increases or + // decreases depending on the denominator's absolute value + function div_test_values(int128 x, int128 y) public view { + require(y != ZERO_FP); + + int128 x_y = abs(div(x, y)); + + if (abs(y) >= ONE_FP) { + assert(x_y <= abs(x)); + } else { + assert(x_y >= abs(x)); + } + } + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for division by zero + function div_test_div_by_zero(int128 x) public view { + try this.div(x, ZERO_FP) { + // Unexpected, this should revert + assert(false); + } catch { + // Expected revert + } + } + + // Test for division by a large value, the result should be less than one + function div_test_maximum_denominator(int128 x) public view { + int128 div_large = div(x, MAX_64x64); + + assert(abs(div_large) <= ONE_FP); + } + + // Test for division of a large value + // This should revert if |x| < 1 as it would return a value higher than max + function div_test_maximum_numerator(int128 x) public view { + int128 div_large; + + try this.div(MAX_64x64, x) { + // If it didn't revert, then |x| >= 1 + div_large = div(MAX_64x64, x); + + assert(abs(x) >= ONE_FP); + } catch { + // Expected revert as result is higher than max + } + } + + // Test for values in range + function div_test_range(int128 x, int128 y) public view { + int128 result; + + try this.div(x, y) { + // If it returns a value, it must be in range + result = div(x, y); + assert(result <= MAX_64x64 && result >= MIN_64x64); + } catch { + // Otherwise, it should revert + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION neg() + + ================================================================ */ + + /* ================================================================ + Tests for mathematical properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for the double negation + // -(-x) == x + function neg_test_double_negation(int128 x) public pure { + int128 double_neg = neg(neg(x)); + + assert(x == double_neg); + } + + // Test for the identity operation + // x + (-x) == 0 + function neg_test_identity(int128 x) public view { + int128 neg_x = neg(x); + + assert(add(x, neg_x) == ZERO_FP); + } + + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for the zero-case + // -0 == 0 + function neg_test_zero() public view { + int128 neg_x = neg(ZERO_FP); + + assert(neg_x == ZERO_FP); + } + + // Test for the maximum value case + // Since this is implementation-dependant, we will actually test with MAX_64x64-EPS + function neg_test_maximum() public view { + try this.neg(sub(MAX_64x64, EPSILON)) { + // Expected behaviour, does not revert + } catch { + assert(false); + } + } + + // Test for the minimum value case + // Since this is implementation-dependant, we will actually test with MIN_64x64+EPS + function neg_test_minimum() public view { + try this.neg(add(MIN_64x64, EPSILON)) { + // Expected behaviour, does not revert + } catch { + assert(false); + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION abs() + + ================================================================ */ + + /* ================================================================ + Tests for mathematical properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test that the absolute value is always positive + function abs_test_positive(int128 x) public view { + int128 abs_x = abs(x); + + assert(abs_x >= ZERO_FP); + } + + // Test that the absolute value of a number equals the + // absolute value of the negative of the same number + function abs_test_negative(int128 x) public pure { + int128 abs_x = abs(x); + int128 abs_minus_x = abs(neg(x)); + + assert(abs_x == abs_minus_x); + } + + // Test the multiplicativeness property + // | x * y | == |x| * |y| + function abs_test_multiplicativeness(int128 x, int128 y) public pure { + int128 abs_x = abs(x); + int128 abs_y = abs(y); + int128 abs_xy = abs(mul(x, y)); + int128 abs_x_abs_y = mul(abs_x, abs_y); + + // Failure if all significant digits are lost + require(significant_digits_lost_in_mult(abs_x, abs_y) == false); + + // Assume a tolerance of two bits of precision + assert(equal_within_precision(abs_xy, abs_x_abs_y, 2)); + } + + // Test the subadditivity property + // | x + y | <= |x| + |y| + function abs_test_subadditivity(int128 x, int128 y) public pure { + int128 abs_x = abs(x); + int128 abs_y = abs(y); + int128 abs_xy = abs(add(x, y)); + + assert(abs_xy <= add(abs_x, abs_y)); + } + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test the zero-case | 0 | = 0 + function abs_test_zero() public view { + int128 abs_zero; + + try this.abs(ZERO_FP) { + // If it doesn't revert, the value must be zero + abs_zero = this.abs(ZERO_FP); + assert(abs_zero == ZERO_FP); + } catch { + // Unexpected, the function must not revert here + assert(false); + } + } + + // Test the maximum value + function abs_test_maximum() public view { + int128 abs_max; + + try this.abs(MAX_64x64) { + // If it doesn't revert, the value must be MAX_64x64 + abs_max = this.abs(MAX_64x64); + assert(abs_max == MAX_64x64); + } catch { + + } + } + + // Test the minimum value + function abs_test_minimum() public view { + int128 abs_min; + + try this.abs(MIN_64x64) { + // If it doesn't revert, the value must be the negative of MIN_64x64 + abs_min = this.abs(MIN_64x64); + assert(abs_min == neg(MIN_64x64)); + } catch { + + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION inv() + + ================================================================ */ + + + /* ================================================================ + Tests for mathematical properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test that the inverse of the inverse is close enough to the + // original number + function inv_test_double_inverse(int128 x) public view { + require(x != ZERO_FP); + + int128 double_inv_x = inv(inv(x)); + + // The maximum loss of precision will be 2 * log2(x) bits rounded up + uint256 loss = 2 * toUInt(log_2(x)) + 2; + + assert(equal_within_precision(x, double_inv_x, loss)); + } + + // Test equivalence with division + function inv_test_division(int128 x) public view { + require(x != ZERO_FP); + + int128 inv_x = inv(x); + int128 div_1_x = div(ONE_FP, x); + + assert(inv_x == div_1_x); + } + + // Test the anticommutativity of the division + // x / y == 1 / (y / x) + function inv_test_division_noncommutativity(int128 x, int128 y) public view { + require(x != ZERO_FP && y != ZERO_FP); + + int128 x_y = div(x, y); + int128 y_x = div(y, x); + + require(significant_bits_after_mult(x, inv(y)) > REQUIRED_SIGNIFICANT_BITS); + require(significant_bits_after_mult(y, inv(x)) > REQUIRED_SIGNIFICANT_BITS); + assert(equal_within_tolerance(x_y, inv(y_x), ONE_TENTH_FP)); + } + + // Test the multiplication of inverses + // 1/(x * y) == 1/x * 1/y + function inv_test_multiplication(int128 x, int128 y) public view { + require(x != ZERO_FP && y != ZERO_FP); + + int128 inv_x = inv(x); + int128 inv_y = inv(y); + int128 inv_x_times_inv_y = mul(inv_x, inv_y); + + int128 x_y = mul(x, y); + int128 inv_x_y = inv(x_y); + + require(significant_bits_after_mult(x, y) > REQUIRED_SIGNIFICANT_BITS); + require(significant_bits_after_mult(inv_x, inv_y) > REQUIRED_SIGNIFICANT_BITS); + + // The maximum loss of precision is given by the formula: + // 2 * | log_2(x) - log_2(y) | + 1 + uint256 loss = 2 * toUInt(abs(log_2(x) - log_2(y))) + 1; + + assert(equal_within_precision(inv_x_y, inv_x_times_inv_y, loss)); + } + + // Test identity property + // Intermediate result should have at least REQUIRED_SIGNIFICANT_BITS + function inv_test_identity(int128 x) public view { + require(x != ZERO_FP); + + int128 inv_x = inv(x); + int128 identity = mul(inv_x, x); + + require(significant_bits_after_mult(x, inv_x) > REQUIRED_SIGNIFICANT_BITS); + + // They should agree with a tolerance of one tenth of a percent + assert(equal_within_tolerance(identity, ONE_FP, ONE_TENTH_FP)); + } + + // Test that the absolute value of the result is in range zero-one + // if x is greater than one, else, the absolute value of the result + // must be greater than one + function inv_test_values(int128 x) public view { + require(x != ZERO_FP); + + int128 abs_inv_x = abs(inv(x)); + + if(abs(x) >= ONE_FP) { + assert(abs_inv_x <= ONE_FP); + } else { + assert(abs_inv_x > ONE_FP); + } + } + + // Test that the result has the same sign as the argument + function inv_test_sign(int128 x) public view { + require(x != ZERO_FP); + + int128 inv_x = inv(x); + + if(x > ZERO_FP) { + assert(inv_x > ZERO_FP); + } else { + assert(inv_x < ZERO_FP); + } + } + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test the zero-case, should revert + function inv_test_zero() public view { + try this.inv(ZERO_FP) { + // Unexpected, the function must revert + assert(false); + } catch { + + } + } + + // Test the maximum value case, should not revert, and be close to zero + function inv_test_maximum() public view { + int128 inv_maximum; + + try this.inv(MAX_64x64) { + inv_maximum = this.inv(MAX_64x64); + assert(equal_within_precision(inv_maximum, ZERO_FP, 10)); + } catch { + // Unexpected, the function must not revert + assert(false); + } + } + + // Test the minimum value case, should not revert, and be close to zero + function inv_test_minimum() public view { + int128 inv_minimum; + + try this.inv(MAX_64x64) { + inv_minimum = this.inv(MAX_64x64); + assert(equal_within_precision(abs(inv_minimum), ZERO_FP, 10)); + } catch { + // Unexpected, the function must not revert + assert(false); + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION avg() + + ================================================================ */ + + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test that the result is between the two operands + // avg(x, y) >= min(x, y) && avg(x, y) <= max(x, y) + function avg_test_values_in_range(int128 x, int128 y) public pure { + int128 avg_xy = avg(x, y); + + if(x >= y) { + assert(avg_xy >= y && avg_xy <= x); + } else { + assert(avg_xy >= x && avg_xy <= y); + } + } + + // Test that the average of the same number is itself + // avg(x, x) == x + function avg_test_one_value(int128 x) public pure { + int128 avg_x = avg(x, x); + + assert(avg_x == x); + } + + // Test that the order of operands is irrelevant + // avg(x, y) == avg(y, x) + function avg_test_operand_order(int128 x, int128 y) public pure { + int128 avg_xy = avg(x, y); + int128 avg_yx = avg(y, x); + + assert(avg_xy == avg_yx); + } + + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for the maximum value + function avg_test_maximum() public view { + int128 result; + + // This may revert due to overflow depending on implementation + // If it doesn't revert, the result must be MAX_64x64 + try this.avg(MAX_64x64, MAX_64x64) { + result = this.avg(MAX_64x64, MAX_64x64); + assert(result == MAX_64x64); + } catch { + + } + } + + // Test for the minimum value + function avg_test_minimum() public view { + int128 result; + + // This may revert due to overflow depending on implementation + // If it doesn't revert, the result must be MIN_64x64 + try this.avg(MIN_64x64, MIN_64x64) { + result = this.avg(MIN_64x64, MIN_64x64); + assert(result == MIN_64x64); + } catch { + + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION gavg() + + ================================================================ */ + + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test that the result is between the two operands + // gavg(x, y) >= min(x, y) && gavg(x, y) <= max(x, y) + function gavg_test_values_in_range(int128 x, int128 y) public view { + int128 gavg_xy = gavg(x, y); + + if(x == ZERO_FP || y == ZERO_FP) { + assert(gavg_xy == ZERO_FP); + } else { + if(abs(x) >= abs(y)) { + assert(gavg_xy >= abs(y) && gavg_xy <= abs(x)); + } else { + assert(gavg_xy >= abs(x) && gavg_xy <= abs(y)); + } + } + } + + // Test that the average of the same number is itself + // gavg(x, x) == | x | + function gavg_test_one_value(int128 x) public pure { + int128 gavg_x = gavg(x, x); + + assert(gavg_x == abs(x)); + } + + // Test that the order of operands is irrelevant + // gavg(x, y) == gavg(y, x) + function gavg_test_operand_order(int128 x, int128 y) public pure { + int128 gavg_xy = gavg(x, y); + int128 gavg_yx = gavg(y, x); + + assert(gavg_xy == gavg_yx); + } + + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for the maximum value + function gavg_test_maximum() public view { + int128 result; + + // This may revert due to overflow depending on implementation + // If it doesn't revert, the result must be MAX_64x64 + try this.gavg(MAX_64x64, MAX_64x64) { + result = this.gavg(MAX_64x64, MAX_64x64); + assert(result == MAX_64x64); + } catch { + + } + } + + // Test for the minimum value + function gavg_test_minimum() public view { + int128 result; + + // This may revert due to overflow depending on implementation + // If it doesn't revert, the result must be MIN_64x64 + try this.gavg(MIN_64x64, MIN_64x64) { + result = this.gavg(MIN_64x64, MIN_64x64); + assert(result == MIN_64x64); + } catch { + + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION pow() + + ================================================================ */ + + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for zero exponent + // x ** 0 == 1 + function pow_test_zero_exponent(int128 x) public view { + int128 x_pow_0 = pow(x, 0); + + assert(x_pow_0 == ONE_FP); + } + + // Test for zero base + // 0 ** x == 0 (for positive x) + function pow_test_zero_base(uint256 x) public view { + require(x != 0); + + int128 zero_pow_x = pow(ZERO_FP, x); + + assert(zero_pow_x == ZERO_FP); + } + + // Test for exponent one + // x ** 1 == x + function pow_test_one_exponent(int128 x) public pure { + int128 x_pow_1 = pow(x, 1); + + assert(x_pow_1 == x); + } + + // Test for base one + // 1 ** x == 1 + function pow_test_base_one(uint256 x) public view { + int128 one_pow_x = pow(ONE_FP, x); + + assert(one_pow_x == ONE_FP); + } + + // Test for product of powers of the same base + // x ** a * x ** b == x ** (a + b) + function pow_test_product_same_base(int128 x, uint256 a, uint256 b) public view { + require(x != ZERO_FP); + + int128 x_a = pow(x, a); + int128 x_b = pow(x, b); + int128 x_ab = pow(x, a + b); + + assert(equal_within_precision(mul(x_a, x_b), x_ab, 2)); + } + + // Test for power of an exponentiation + // (x ** a) ** b == x ** (a * b) + function pow_test_power_of_an_exponentiation(int128 x, uint256 a, uint256 b) public view { + require(x != ZERO_FP); + + int128 x_a = pow(x, a); + int128 x_a_b = pow(x_a, b); + int128 x_ab = pow(x, a * b); + + assert(equal_within_precision(x_a_b, x_ab, 2)); + } + + // Test for power of a product + // (x * y) ** a == x ** a * y ** a + function pow_test_product_same_base(int128 x, int128 y, uint256 a) public view { + require(x != ZERO_FP && y != ZERO_FP); + require(a > 2**32); // to avoid massive loss of precision + + int128 x_y = mul(x, y); + int128 xy_a = pow(x_y, a); + + int128 x_a = pow(x, a); + int128 y_a = pow(y, a); + + assert(equal_within_precision(mul(x_a, y_a), xy_a, 2)); + } + + // Test for result being greater than or lower than the argument, depending on + // its absolute value and the value of the exponent + function pow_test_values(int128 x, uint256 a) public view { + require(x != ZERO_FP); + + int128 x_a = pow(x, a); + + if(abs(x) >= ONE_FP) { + assert(abs(x_a) >= ONE_FP); + } + + if(abs(x) <= ONE_FP) { + assert(abs(x_a) <= ONE_FP); + } + } + + // Test for result sign: if the exponent is even, sign is positive + // if the exponent is odd, preserves the sign of the base + function pow_test_sign(int128 x, uint256 a) public view { + require(x != ZERO_FP && a != 0); + + int128 x_a = pow(x, a); + + // This prevents the case where a small negative number gets + // rounded down to zero and thus changes sign + require(x_a != ZERO_FP); + + // If the exponent is even + if(a % 2 == 0) { + assert(x_a == abs(x_a)); + } else { + // x_a preserves x sign + if (x < ZERO_FP) { + assert(x_a < ZERO_FP); + } else { + assert(x_a > ZERO_FP); + } + } + } + + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for maximum base and exponent > 1 + function pow_test_maximum_base(uint256 a) public view { + require(a > 1); + + try this.pow(MAX_64x64, a) { + // Unexpected, should revert because of overflow + assert(false); + } catch { + // Expected revert + } + } + + // Test for abs(base) < 1 and high exponent + function pow_test_high_exponent(int128 x, uint256 a) public view { + require(abs(x) < ONE_FP && a > 2**64); + + int128 result = pow(x, a); + + assert(result == ZERO_FP); + } + + + + /* ================================================================ + + TESTS FOR FUNCTION sqrt() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for the inverse operation + // sqrt(x) * sqrt(x) == x + function sqrt_test_inverse_mul(int128 x) public view { + require(x >= ZERO_FP); + + int128 sqrt_x = sqrt(x); + int128 sqrt_x_squared = mul(sqrt_x, sqrt_x); + + // Precision loss is at most half the bits of the operand + assert(equal_within_precision(sqrt_x_squared, x, (toUInt(log_2(x)) >> 1) + 2)); + } + + // Test for the inverse operation + // sqrt(x) ** 2 == x + function sqrt_test_inverse_pow(int128 x) public view { + require(x >= ZERO_FP); + + int128 sqrt_x = sqrt(x); + int128 sqrt_x_squared = pow(sqrt_x, 2); + + // Precision loss is at most half the bits of the operand + assert(equal_within_precision(sqrt_x_squared, x, (toUInt(log_2(x)) >> 1) + 2)); + } + + // Test for distributive property respect to the multiplication + // sqrt(x) * sqrt(y) == sqrt(x * y) + function sqrt_test_distributive(int128 x, int128 y) public view { + require(x >= ZERO_FP && y >= ZERO_FP); + + int128 sqrt_x = sqrt(x); + int128 sqrt_y = sqrt(y); + int128 sqrt_x_sqrt_y = mul(sqrt_x, sqrt_y); + int128 sqrt_xy = sqrt(mul(x, y)); + + // Ensure we have enough significant digits for the result to be meaningful + require(significant_bits_after_mult(x, y) > REQUIRED_SIGNIFICANT_BITS); + require(significant_bits_after_mult(sqrt_x, sqrt_y) > REQUIRED_SIGNIFICANT_BITS); + + // Allow an error of up to one tenth of a percent + assert(equal_within_tolerance(sqrt_x_sqrt_y, sqrt_xy, ONE_TENTH_FP)); + } + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for zero case + function sqrt_test_zero() public view { + assert(sqrt(ZERO_FP) == ZERO_FP); + } + + // Test for maximum value + function sqrt_test_maximum() public view { + try this.sqrt(MAX_64x64) { + // Expected behaviour, MAX_64x64 is positive, and operation + // should not revert as the result is in range + } catch { + // Unexpected, should not revert + assert(false); + } + } + + // Test for minimum value + function sqrt_test_minimum() public view { + try this.sqrt(MIN_64x64) { + // Unexpected, should revert. MIN_64x64 is negative. + assert(false); + } catch { + // Expected behaviour, revert + } + } + + // Test for negative operands + function sqrt_test_negative(int128 x) public view { + require(x < ZERO_FP); + + try this.sqrt(x) { + // Unexpected, should revert + assert(false); + } catch { + // Expected behaviour, revert + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION log2() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for distributive property respect to multiplication + // log2(x * y) = log2(x) + log2(y) + function log2_test_distributive_mul(int128 x, int128 y) public view { + int128 log2_x = log_2(x); + int128 log2_y = log_2(y); + int128 log2_x_log2_y = add(log2_x, log2_y); + + int128 xy = mul(x, y); + int128 log2_xy = log_2(xy); + + // Ensure we have enough significant digits for the result to be meaningful + require(significant_bits_after_mult(x, y) > REQUIRED_SIGNIFICANT_BITS); + + // The maximum loss of precision is given by the formula: + // | log_2(x) + log_2(y) | + uint256 loss = toUInt(abs(log_2(x) + log_2(y))); + + assert(equal_within_precision(log2_x_log2_y, log2_xy, loss)); + } + + // Test for logarithm of a power + // log2(x ** y) = y * log2(x) + function log2_test_power(int128 x, uint256 y) public pure { + int128 x_y = pow(x, y); + int128 log2_x_y = log_2(x_y); + + uint256 y_log2_x = mulu(log_2(x), y); + + assert(y_log2_x == toUInt(log2_x_y)); + } + + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for zero case, should revert + function log2_test_zero() public view { + try this.log_2(ZERO_FP) { + // Unexpected, should revert + assert(false); + } catch { + // Expected revert, log(0) is not defined + } + } + + // Test for maximum value case, should return a positive number + function log2_test_maximum() public view { + int128 result; + + try this.log_2(MAX_64x64) { + // Expected, should not revert and the result must be > 0 + result = this.log_2(MAX_64x64); + assert(result > ZERO_FP); + } catch { + // Unexpected + assert(false); + } + } + + // Test for negative values, should revert as log2 is not defined + function log2_test_negative(int128 x) public view { + require(x < ZERO_FP); + + try this.log_2(x) { + // Unexpected, should revert + assert(false); + } catch { + // Expected + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION ln() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for distributive property respect to multiplication + // ln(x * y) = ln(x) + ln(y) + function ln_test_distributive_mul(int128 x, int128 y) public view { + require(x > ZERO_FP && y > ZERO_FP); + + int128 ln_x = ln(x); + int128 ln_y = ln(y); + int128 ln_x_ln_y = add(ln_x, ln_y); + + int128 xy = mul(x, y); + int128 ln_xy = ln(xy); + + require(significant_bits_after_mult(x, y) > REQUIRED_SIGNIFICANT_BITS); + + // The maximum loss of precision is given by the formula: + // | log_2(x) + log_2(y) | + uint256 loss = toUInt(abs(log_2(x) + log_2(y))); + + assert(equal_within_precision(ln_x_ln_y, ln_xy, loss)); + } + + // Test for logarithm of a power + // ln(x ** y) = y * ln(x) + function ln_test_power(int128 x, uint256 y) public pure { + int128 x_y = pow(x, y); + int128 ln_x_y = ln(x_y); + + uint256 y_ln_x = mulu(ln(x), y); + + assert(y_ln_x == toUInt(ln_x_y)); + } + + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for zero case, should revert + function ln_test_zero() public view { + try this.ln(ZERO_FP) { + // Unexpected, should revert + assert(false); + } catch { + // Expected revert, log(0) is not defined + } + } + + // Test for maximum value case, should return a positive number + function ln_test_maximum() public view { + int128 result; + + try this.ln(MAX_64x64) { + // Expected, should not revert and the result must be > 0 + result = this.ln(MAX_64x64); + assert(result > ZERO_FP); + } catch { + // Unexpected + assert(false); + } + } + + // Test for negative values, should revert as ln is not defined + function ln_test_negative(int128 x) public view { + require(x < ZERO_FP); + + try this.ln(x) { + // Unexpected, should revert + assert(false); + } catch { + // Expected + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION exp2() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for equality with pow(2, x) for integer x + // pow(2, x) == exp_2(x) + function exp2_test_equivalence_pow(uint256 x) public view { + int128 exp2_x = exp_2(fromUInt(x)); + int128 pow_2_x = pow(TWO_FP, x); + + assert(exp2_x == pow_2_x); + } + + // Test for inverse function + // If y = log_2(x) then exp_2(y) == x + function exp2_test_inverse(int128 x) public view { + int128 log2_x = log_2(x); + int128 exp2_x = exp_2(log2_x); + + uint256 bits = 50; + + if(log2_x < ZERO_FP) { + bits = uint256(int256(bits) + int256(log2_x)); + } + + assert(equal_most_significant_bits_within_precision(x, exp2_x, bits)); + } + + // Test for negative exponent + // exp_2(-x) == inv( exp_2(x) ) + function exp2_test_negative_exponent(int128 x) public view { + require(x < ZERO_FP && x != MIN_64x64); + + int128 exp2_x = exp_2(x); + int128 exp2_minus_x = exp_2(-x); + + // Result should be within 4 bits precision for the worst case + assert(equal_within_precision(exp2_x, inv(exp2_minus_x), 4)); + } + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for zero case + // exp_2(0) == 1 + function exp2_test_zero() public view { + int128 exp_zero = exp_2(ZERO_FP); + assert(exp_zero == ONE_FP); + } + + // Test for maximum value. This should overflow as it won't fit + // in the data type + function exp2_test_maximum() public view { + try this.exp_2(MAX_64x64) { + // Unexpected, should revert + assert(false); + } catch { + // Expected revert + } + } + + // Test for minimum value. This should return zero since + // 2 ** -x == 1 / 2 ** x that tends to zero as x increases + function exp2_test_minimum() public view { + int128 result; + + try this.exp_2(MIN_64x64) { + // Expected, should not revert, check that value is zero + result = exp_2(MIN_64x64); + assert(result == ZERO_FP); + } catch { + // Unexpected revert + assert(false); + } + } + + + + /* ================================================================ + + TESTS FOR FUNCTION exp() + + ================================================================ */ + + /* ================================================================ + Tests for arithmetic properties. + These should make sure that the implemented function complies + with math rules and expected behaviour. + ================================================================ */ + + // Test for inverse function + // If y = ln(x) then exp(y) == x + function exp_test_inverse(int128 x) public view { + int128 ln_x = ln(x); + int128 exp_x = exp(ln_x); + int128 log2_x = log_2(x); + + uint256 bits = 48; + + if(log2_x < ZERO_FP) { + bits = uint256(int256(bits) + int256(log2_x)); + } + + assert(equal_most_significant_bits_within_precision(x, exp_x, bits)); + } + + // Test for negative exponent + // exp(-x) == inv( exp(x) ) + function exp_test_negative_exponent(int128 x) public view { + require(x < ZERO_FP && x != MIN_64x64); + + int128 exp_x = exp(x); + int128 exp_minus_x = exp(-x); + + // Result should be within 4 bits precision for the worst case + assert(equal_within_precision(exp_x, inv(exp_minus_x), 4)); + } + + /* ================================================================ + Tests for overflow and edge cases. + These will make sure that the function reverts on overflow and + behaves correctly on edge cases + ================================================================ */ + + // Test for zero case + // exp(0) == 1 + function exp_test_zero() public view { + int128 exp_zero = exp(ZERO_FP); + assert(exp_zero == ONE_FP); + } + + // Test for maximum value. This should overflow as it won't fit + // in the data type + function exp_test_maximum() public view { + try this.exp(MAX_64x64) { + // Unexpected, should revert + assert(false); + } catch { + // Expected revert + } + } + + // Test for minimum value. This should return zero since + // e ** -x == 1 / e ** x that tends to zero as x increases + function exp_test_minimum() public view { + int128 result; + + try this.exp(MIN_64x64) { + // Expected, should not revert, check that value is zero + result = exp(MIN_64x64); + assert(result == ZERO_FP); + } catch { + // Unexpected revert + assert(false); + } + } + +} diff --git a/lib/crytic/contracts/Math/ABDKMath64x64/README.md b/lib/crytic/contracts/Math/ABDKMath64x64/README.md new file mode 100644 index 0000000..f23ccad --- /dev/null +++ b/lib/crytic/contracts/Math/ABDKMath64x64/README.md @@ -0,0 +1,38 @@ +# ABDKMath64x64 test suite for Echidna + +## What is ABDKMath64x64? +The Solidity smart contract programming language does not have any inbuilt feature for working with decimal numbers, so for contracts dealing with non-integer values, a third party solution is needed. ABDKMath64x64 is a fixed-point arithmetic Solidity library that operates on 64.64-bit numbers. This library was developed by [ABDK Consulting](https://abdk.consulting/ "ABDK Consulting") and is [open source](https://github.com/abdk-consulting/abdk-libraries-solidity "open source") under the BSD License. + +A 64.64-bit fixed-point number is a data type that consists of a sign bit, a 63-bit integer part, and a 64bit decimal part. Since there is no direct support for fractional numbers in the EVM, the underlying data type that stores the values is a 128-bit signed integer. + +ABDKMath64x64 library implements [19 arithmetic operations](https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.md#simple-arithmetic "19 arithmetic operations") using fixed-point numbers and [6 conversion functions](https://github.com/abdk-consulting/abdk-libraries-solidity/blob/master/ABDKMath64x64.md#conversions "6 conversion functions") between integer types and fixed-point types. + +## Why are tests needed? + +Solidity libraries are used in smart contracts that at some point in time can hold important value in tokens or other assets. The security of those assets is directly related to the robustness and reliability of the smart contract source code. + +While testing does not guarantee the absence of errors, it helps the developers in assessing what the risky operations are, how they work, and ultimately how can they fail. Furthermore, having a working test suite with common and edge cases is useful to ensure that code does not behave unexpectedly, and that future versions of the library do not break compatibility. + +Echidna testing can be integrated into CI/CD pipelines, so bugs are caught early and the developers are notified about security risks in their contracts. + +## Who are these tests designed for? + +In principle, these tests are meant to be an entry level practice to learn how to use Echidna for assertion-based fuzz tests, targeting a stand-alone library. It is a self contained exercise that shows how to determine the contract invariants, create proper tests, and configure the relevant Echidna parameters for the campaign. + +Determining the invariants is a process that involves an intermediate-level comprehension of the library and the math properties behind the operations implemented. For example, the addition function has the `x+y == y+x` commutative property. This statement should always be true, no matter the values of `x` and `y`, therefore it should be a good invariant for the system. More complex operations can demand more complex invariants. + +The next step, creating the tests, means to implement Solidity functions that verify the previously defined invariants. Echidna is a fuzz tester, so it can quickly test different values for the arguments of a function. For example, the commutative property can be tested using a function that takes two parameters and performs the additions, as shown below: +```solidity + // Test for commutative property + // x + y == y + x + function add_test_commutative(int128 x, int128 y) public { + int128 x_y = add(x, y); + int128 y_x = add(y, x); + + assert(x_y == y_x); + } +``` + +Finally, the fuzzer has to be instructed to perform the correct type of test, the number of test runs to be made, among other configuration parameters. Since the invariant is checked using an assertion, Echidna must be configured to try to find assertion violations. In this mode, different argument values are passed to `add_test_commutative()`, and the result of the `assert(x_y == y_x)` expression is evaluated for each call: if the assertion is false, the invariant was broken, and it is a sign that there can be an issue with the library implementation. + +However, even if this particular test suite is meant as an exercise, it can be used as a template to create tests for other fixed-point arithmetic libraries implementations. \ No newline at end of file diff --git a/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMath64x64.md b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMath64x64.md new file mode 100644 index 0000000..98b27ad --- /dev/null +++ b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMath64x64.md @@ -0,0 +1,172 @@ +ABDK Math 64.64 +=============== + +Library of mathematical functions operating with signed 64.64-bit fixed point +numbers. + +Copyright (c) 2019, [ABDK Consulting](https://abdk.consulting/) + +All rights reserved. + +Signed 64.64 Fixed Point Numbers +-------------------------------- + +Signed 64.64-bit fixed point number is basically a simple fraction whose +numerator is a signed 128-bit integer and denominator is 2^64. As long as +denominator is always the same, there is no need to store it, thus in Solidity +signed 64.64-bit fixed point numbers are represented by int128 type holding only +the numerator. + +Signed 64.64-bit fixed point numbers combine wide range and decent precision +with good performance, and should be a good fit for most applications that need +to deal with real numbers. + +Simple Arithmetic +----------------- + +Here is the list of simple arithmetic functions provided by the library. + + function add (int128 x, int128 y) internal pure returns (int128) + +Add one signed 64.64 fixed point number to another and return the result as a +signed 64.64 fixed point number. + + function sub (int128 x, int128 y) internal pure returns (int128) + +Subtract one signed 64.64 fixed point number from another and return the result +as a signed 64.64 fixed point number. + + function mul (int128 x, int128 y) internal pure returns (int128) + +Multiply one signed 64.64 fixed point number by another and return the result as +a signed 64.64 fixed point number. + + function muli (int128 x, int256 y) internal pure returns (int256) + +Multiply a signed 64.64 fixed point number by a signed 256-bit integer number +and return the result as a signed 256-bit integer number. + + function mulu (int128 x, uint256 y) internal pure returns (uint256) + +Multiply a signed 64.64 fixed point number by an unsigned 256-bit integer number +and return the result as an unsigned 256-bit integer number. + + function div (int128 x, int128 y) internal pure returns (int128) + +Divide one signed 64.64 fixed point number by another and return the result as +a signed 64.64 fixed point number. + + function divi (int256 x, int256 y) internal pure returns (int128) + +Divide one signed 256-bit integer number by another and return the result as a +signed 64.64 fixed point number. + + function divu (uint256 x, uint256 y) internal pure returns (int128) + +Divide one unsigned 256-bit integer number by another and return the result as +a signed 64.64 fixed point number. + + function neg (int128 x) internal pure returns (int128) + +Calculate the opposite for a signed 64.64 fixed point number, i.e. `-x`, and +return the result as a signed 64.64 fixed point number. + + function abs (int128 x) internal pure returns (int128) + +Calculate absolute value of a signed 64.64 fixed point number and return the +result as a signed 64.64 fixed point number. + + function inv (int128 x) internal pure returns (int128) + +Calculate the reciprocal for a signed 64.64 fixed point number, i.e. `1/x`, and +return the result as a signed 64.64 fixed point number. + +Average Values +-------------- + +Here are average value functions. + + function avg (int128 x, int128 y) internal pure returns (int128) + +Calculate the arithmetic average of two signed 64.64 fixed point numbers and +return the result as a signed 64.64 fixed point number. + + function gavg (int128 x, int128 y) internal pure returns (int128) + +Calculate the geometric average of two signed 64.64 fixed point numbers and +return the result as a signed 64.64 fixed point number. + +Power and Root +-------------- + +Here are power and root functions. + + function pow (int128 x, uint256 y) internal pure returns (int128) + +Raise a signed 64.64 fixed point number to a non-negative integer power and +return the result as a signed 64.64 fixed point number. + + function sqrt (int128 x) internal pure returns (int128) + +Calculate the square root of a signed 64.64 fixed point number and return the +result as a signed 64.64 fixed point number. + +Exponentiation and Logarithm +---------------------------- + +Here are exponential and logarithm functions. + + function log_2 (int128 x) internal pure returns (int128) + +Calculate the binary logarithm of a signed 64.64 fixed point number and return +the result as a signed 64.64 fixed point number. + + function ln (int128 x) internal pure returns (int128) + +Calculate the natural logarithm of a signed 64.64 fixed point number and return +the result as a signed 64.64 fixed point number. + + function exp_2 (int128 x) internal pure returns (int128) + +Raise 2 to the power of a signed 64.64 fixed point number, i.e. calculate +`2^x`, and return the result as a signed 64.64 fixed point number. + + function exp (int128 x) internal pure returns (int128) + +Exponentiate a signed 64.64 fixed point number, i.e. calculate `e^x`, and +return the result as a signed 64.64 fixed point number. + +Conversions +----------- + +Here are conversion functions. + + function fromInt (int256 x) internal pure returns (int128) + +Convert a signed 256 bit integer number into a signed 64.64 bit fixed point +number. + + function toInt (int128 x) internal pure returns (int64) + +Convert a signed 64.64 bit fixed point number into a signed 64 bit integer +number. + + function fromUInt (uint256 x) internal pure returns (int128) + +Convert an unsigned 256 bit integer number into a signed 64.64 bit fixed point +number. + + function toUInt (int128 x) internal pure returns (uint64) + +Convert a signed 64.64 bit fixed point number into a unsigned 64 bit integer +number. + + function from128x128 (int256 x) internal pure returns (int128) + +Convert a signed 128.128 bit fixed point number into a signed 64.64 bit fixed +point number. + + function to128x128 (int128 x) internal pure returns (int256) + +Convert a signed 64.64 bit fixed point number into a signed 128.128 bit fixed +point number. diff --git a/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMath64x64.sol b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMath64x64.sol new file mode 100644 index 0000000..2cbe46a --- /dev/null +++ b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMath64x64.sol @@ -0,0 +1,750 @@ +// SPDX-License-Identifier: BSD-4-Clause +/* + * ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting. + * Author: Mikhail Vladimirov + */ +pragma solidity ^0.8.0; + +/** + * Smart contract library of mathematical functions operating with signed + * 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is + * basically a simple fraction whose numerator is signed 128-bit integer and + * denominator is 2^64. As long as denominator is always the same, there is no + * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are + * represented by int128 type holding only the numerator. + */ +library ABDKMath64x64 { + /* + * Minimum value signed 64.64-bit fixed point number may have. + */ + int128 private constant MIN_64x64 = -0x80000000000000000000000000000000; + + /* + * Maximum value signed 64.64-bit fixed point number may have. + */ + int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + /** + * Convert signed 256-bit integer number into signed 64.64-bit fixed point + * number. Revert on overflow. + * + * @param x signed 256-bit integer number + * @return signed 64.64-bit fixed point number + */ + function fromInt (int256 x) internal pure returns (int128) { + unchecked { + require (x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF); + return int128 (x << 64); + } + } + + /** + * Convert signed 64.64 fixed point number into signed 64-bit integer number + * rounding down. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64-bit integer number + */ + function toInt (int128 x) internal pure returns (int64) { + unchecked { + return int64 (x >> 64); + } + } + + /** + * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point + * number. Revert on overflow. + * + * @param x unsigned 256-bit integer number + * @return signed 64.64-bit fixed point number + */ + function fromUInt (uint256 x) internal pure returns (int128) { + unchecked { + require (x <= 0x7FFFFFFFFFFFFFFF); + return int128 (int256 (x << 64)); + } + } + + /** + * Convert signed 64.64 fixed point number into unsigned 64-bit integer + * number rounding down. Revert on underflow. + * + * @param x signed 64.64-bit fixed point number + * @return unsigned 64-bit integer number + */ + function toUInt (int128 x) internal pure returns (uint64) { + unchecked { + require (x >= 0); + return uint64 (uint128 (x >> 64)); + } + } + + /** + * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point + * number rounding down. Revert on overflow. + * + * @param x signed 128.128-bin fixed point number + * @return signed 64.64-bit fixed point number + */ + function from128x128 (int256 x) internal pure returns (int128) { + unchecked { + int256 result = x >> 64; + require (result >= MIN_64x64 && result <= MAX_64x64); + return int128 (result); + } + } + + /** + * Convert signed 64.64 fixed point number into signed 128.128 fixed point + * number. + * + * @param x signed 64.64-bit fixed point number + * @return signed 128.128 fixed point number + */ + function to128x128 (int128 x) internal pure returns (int256) { + unchecked { + return int256 (x) << 64; + } + } + + /** + * Calculate x + y. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function add (int128 x, int128 y) internal pure returns (int128) { + unchecked { + int256 result = int256(x) + y; + require (result >= MIN_64x64 && result <= MAX_64x64); + return int128 (result); + } + } + + /** + * Calculate x - y. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function sub (int128 x, int128 y) internal pure returns (int128) { + unchecked { + int256 result = int256(x) - y; + require (result >= MIN_64x64 && result <= MAX_64x64); + return int128 (result); + } + } + + /** + * Calculate x * y rounding down. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function mul (int128 x, int128 y) internal pure returns (int128) { + unchecked { + int256 result = int256(x) * y >> 64; + require (result >= MIN_64x64 && result <= MAX_64x64); + return int128 (result); + } + } + + /** + * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point + * number and y is signed 256-bit integer number. Revert on overflow. + * + * @param x signed 64.64 fixed point number + * @param y signed 256-bit integer number + * @return signed 256-bit integer number + */ + function muli (int128 x, int256 y) internal pure returns (int256) { + unchecked { + if (x == MIN_64x64) { + require (y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF && + y <= 0x1000000000000000000000000000000000000000000000000); + return -y << 63; + } else { + bool negativeResult = false; + if (x < 0) { + x = -x; + negativeResult = true; + } + if (y < 0) { + y = -y; // We rely on overflow behavior here + negativeResult = !negativeResult; + } + uint256 absoluteResult = mulu (x, uint256 (y)); + if (negativeResult) { + require (absoluteResult <= + 0x8000000000000000000000000000000000000000000000000000000000000000); + return -int256 (absoluteResult); // We rely on overflow behavior here + } else { + require (absoluteResult <= + 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return int256 (absoluteResult); + } + } + } + } + + /** + * Calculate x * y rounding down, where x is signed 64.64 fixed point number + * and y is unsigned 256-bit integer number. Revert on overflow. + * + * @param x signed 64.64 fixed point number + * @param y unsigned 256-bit integer number + * @return unsigned 256-bit integer number + */ + function mulu (int128 x, uint256 y) internal pure returns (uint256) { + unchecked { + if (y == 0) return 0; + + require (x >= 0); + + uint256 lo = (uint256 (int256 (x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64; + uint256 hi = uint256 (int256 (x)) * (y >> 128); + + require (hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + hi <<= 64; + + require (hi <= + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo); + return hi + lo; + } + } + + /** + * Calculate x / y rounding towards zero. Revert on overflow or when y is + * zero. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function div (int128 x, int128 y) internal pure returns (int128) { + unchecked { + require (y != 0); + int256 result = (int256 (x) << 64) / y; + require (result >= MIN_64x64 && result <= MAX_64x64); + return int128 (result); + } + } + + /** + * Calculate x / y rounding towards zero, where x and y are signed 256-bit + * integer numbers. Revert on overflow or when y is zero. + * + * @param x signed 256-bit integer number + * @param y signed 256-bit integer number + * @return signed 64.64-bit fixed point number + */ + function divi (int256 x, int256 y) internal pure returns (int128) { + unchecked { + require (y != 0); + + bool negativeResult = false; + if (x < 0) { + x = -x; // We rely on overflow behavior here + negativeResult = true; + } + if (y < 0) { + y = -y; // We rely on overflow behavior here + negativeResult = !negativeResult; + } + uint128 absoluteResult = divuu (uint256 (x), uint256 (y)); + if (negativeResult) { + require (absoluteResult <= 0x80000000000000000000000000000000); + return -int128 (absoluteResult); // We rely on overflow behavior here + } else { + require (absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return int128 (absoluteResult); // We rely on overflow behavior here + } + } + } + + /** + * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit + * integer numbers. Revert on overflow or when y is zero. + * + * @param x unsigned 256-bit integer number + * @param y unsigned 256-bit integer number + * @return signed 64.64-bit fixed point number + */ + function divu (uint256 x, uint256 y) internal pure returns (int128) { + unchecked { + require (y != 0); + uint128 result = divuu (x, y); + require (result <= uint128 (MAX_64x64)); + return int128 (result); + } + } + + /** + * Calculate -x. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function neg (int128 x) internal pure returns (int128) { + unchecked { + require (x != MIN_64x64); + return -x; + } + } + + /** + * Calculate |x|. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function abs (int128 x) internal pure returns (int128) { + unchecked { + require (x != MIN_64x64); + return x < 0 ? -x : x; + } + } + + /** + * Calculate 1 / x rounding towards zero. Revert on overflow or when x is + * zero. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function inv (int128 x) internal pure returns (int128) { + unchecked { + require (x != 0); + int256 result = int256 (0x100000000000000000000000000000000) / x; + require (result >= MIN_64x64 && result <= MAX_64x64); + return int128 (result); + } + } + + /** + * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function avg (int128 x, int128 y) internal pure returns (int128) { + unchecked { + return int128 ((int256 (x) + int256 (y)) >> 1); + } + } + + /** + * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down. + * Revert on overflow or in case x * y is negative. + * + * @param x signed 64.64-bit fixed point number + * @param y signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function gavg (int128 x, int128 y) internal pure returns (int128) { + unchecked { + int256 m = int256 (x) * int256 (y); + require (m >= 0); + require (m < + 0x4000000000000000000000000000000000000000000000000000000000000000); + return int128 (sqrtu (uint256 (m))); + } + } + + /** + * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number + * and y is unsigned 256-bit integer number. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @param y uint256 value + * @return signed 64.64-bit fixed point number + */ + function pow (int128 x, uint256 y) internal pure returns (int128) { + unchecked { + bool negative = x < 0 && y & 1 == 1; + + uint256 absX = uint128 (x < 0 ? -x : x); + uint256 absResult; + absResult = 0x100000000000000000000000000000000; + + if (absX <= 0x10000000000000000) { + absX <<= 63; + while (y != 0) { + if (y & 0x1 != 0) { + absResult = absResult * absX >> 127; + } + absX = absX * absX >> 127; + + if (y & 0x2 != 0) { + absResult = absResult * absX >> 127; + } + absX = absX * absX >> 127; + + if (y & 0x4 != 0) { + absResult = absResult * absX >> 127; + } + absX = absX * absX >> 127; + + if (y & 0x8 != 0) { + absResult = absResult * absX >> 127; + } + absX = absX * absX >> 127; + + y >>= 4; + } + + absResult >>= 64; + } else { + uint256 absXShift = 63; + if (absX < 0x1000000000000000000000000) { absX <<= 32; absXShift -= 32; } + if (absX < 0x10000000000000000000000000000) { absX <<= 16; absXShift -= 16; } + if (absX < 0x1000000000000000000000000000000) { absX <<= 8; absXShift -= 8; } + if (absX < 0x10000000000000000000000000000000) { absX <<= 4; absXShift -= 4; } + if (absX < 0x40000000000000000000000000000000) { absX <<= 2; absXShift -= 2; } + if (absX < 0x80000000000000000000000000000000) { absX <<= 1; absXShift -= 1; } + + uint256 resultShift = 0; + while (y != 0) { + require (absXShift < 64); + + if (y & 0x1 != 0) { + absResult = absResult * absX >> 127; + resultShift += absXShift; + if (absResult > 0x100000000000000000000000000000000) { + absResult >>= 1; + resultShift += 1; + } + } + absX = absX * absX >> 127; + absXShift <<= 1; + if (absX >= 0x100000000000000000000000000000000) { + absX >>= 1; + absXShift += 1; + } + + y >>= 1; + } + + require (resultShift < 64); + absResult >>= 64 - resultShift; + } + int256 result = negative ? -int256 (absResult) : int256 (absResult); + require (result >= MIN_64x64 && result <= MAX_64x64); + return int128 (result); + } + } + + /** + * Calculate sqrt (x) rounding down. Revert if x < 0. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function sqrt (int128 x) internal pure returns (int128) { + unchecked { + require (x >= 0); + return int128 (sqrtu (uint256 (int256 (x)) << 64)); + } + } + + /** + * Calculate binary logarithm of x. Revert if x <= 0. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function log_2 (int128 x) internal pure returns (int128) { + unchecked { + require (x > 0); + + int256 msb = 0; + int256 xc = x; + if (xc >= 0x10000000000000000) { xc >>= 64; msb += 64; } + if (xc >= 0x100000000) { xc >>= 32; msb += 32; } + if (xc >= 0x10000) { xc >>= 16; msb += 16; } + if (xc >= 0x100) { xc >>= 8; msb += 8; } + if (xc >= 0x10) { xc >>= 4; msb += 4; } + if (xc >= 0x4) { xc >>= 2; msb += 2; } + if (xc >= 0x2) msb += 1; // No need to shift xc anymore + + int256 result = msb - 64 << 64; + uint256 ux = uint256 (int256 (x)) << uint256 (127 - msb); + for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) { + ux *= ux; + uint256 b = ux >> 255; + ux >>= 127 + b; + result += bit * int256 (b); + } + + return int128 (result); + } + } + + /** + * Calculate natural logarithm of x. Revert if x <= 0. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function ln (int128 x) internal pure returns (int128) { + unchecked { + require (x > 0); + + return int128 (int256 ( + uint256 (int256 (log_2 (x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128)); + } + } + + /** + * Calculate binary exponent of x. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function exp_2 (int128 x) internal pure returns (int128) { + unchecked { + require (x < 0x400000000000000000); // Overflow + + if (x < -0x400000000000000000) return 0; // Underflow + + uint256 result = 0x80000000000000000000000000000000; + + if (x & 0x8000000000000000 > 0) + result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128; + if (x & 0x4000000000000000 > 0) + result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128; + if (x & 0x2000000000000000 > 0) + result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128; + if (x & 0x1000000000000000 > 0) + result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128; + if (x & 0x800000000000000 > 0) + result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128; + if (x & 0x400000000000000 > 0) + result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128; + if (x & 0x200000000000000 > 0) + result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128; + if (x & 0x100000000000000 > 0) + result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128; + if (x & 0x80000000000000 > 0) + result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128; + if (x & 0x40000000000000 > 0) + result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128; + if (x & 0x20000000000000 > 0) + result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128; + if (x & 0x10000000000000 > 0) + result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128; + if (x & 0x8000000000000 > 0) + result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128; + if (x & 0x4000000000000 > 0) + result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128; + if (x & 0x2000000000000 > 0) + result = result * 0x1000162E525EE054754457D5995292026 >> 128; + if (x & 0x1000000000000 > 0) + result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128; + if (x & 0x800000000000 > 0) + result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128; + if (x & 0x400000000000 > 0) + result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128; + if (x & 0x200000000000 > 0) + result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128; + if (x & 0x100000000000 > 0) + result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128; + if (x & 0x80000000000 > 0) + result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128; + if (x & 0x40000000000 > 0) + result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128; + if (x & 0x20000000000 > 0) + result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128; + if (x & 0x10000000000 > 0) + result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128; + if (x & 0x8000000000 > 0) + result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128; + if (x & 0x4000000000 > 0) + result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128; + if (x & 0x2000000000 > 0) + result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128; + if (x & 0x1000000000 > 0) + result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128; + if (x & 0x800000000 > 0) + result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128; + if (x & 0x400000000 > 0) + result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128; + if (x & 0x200000000 > 0) + result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128; + if (x & 0x100000000 > 0) + result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128; + if (x & 0x80000000 > 0) + result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128; + if (x & 0x40000000 > 0) + result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128; + if (x & 0x20000000 > 0) + result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128; + if (x & 0x10000000 > 0) + result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128; + if (x & 0x8000000 > 0) + result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128; + if (x & 0x4000000 > 0) + result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128; + if (x & 0x2000000 > 0) + result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128; + if (x & 0x1000000 > 0) + result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128; + if (x & 0x800000 > 0) + result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128; + if (x & 0x400000 > 0) + result = result * 0x100000000002C5C85FDF477B662B26945 >> 128; + if (x & 0x200000 > 0) + result = result * 0x10000000000162E42FEFA3AE53369388C >> 128; + if (x & 0x100000 > 0) + result = result * 0x100000000000B17217F7D1D351A389D40 >> 128; + if (x & 0x80000 > 0) + result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128; + if (x & 0x40000 > 0) + result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128; + if (x & 0x20000 > 0) + result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128; + if (x & 0x10000 > 0) + result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128; + if (x & 0x8000 > 0) + result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128; + if (x & 0x4000 > 0) + result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128; + if (x & 0x2000 > 0) + result = result * 0x1000000000000162E42FEFA39F02B772C >> 128; + if (x & 0x1000 > 0) + result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128; + if (x & 0x800 > 0) + result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128; + if (x & 0x400 > 0) + result = result * 0x100000000000002C5C85FDF473DEA871F >> 128; + if (x & 0x200 > 0) + result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128; + if (x & 0x100 > 0) + result = result * 0x100000000000000B17217F7D1CF79E949 >> 128; + if (x & 0x80 > 0) + result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128; + if (x & 0x40 > 0) + result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128; + if (x & 0x20 > 0) + result = result * 0x100000000000000162E42FEFA39EF366F >> 128; + if (x & 0x10 > 0) + result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128; + if (x & 0x8 > 0) + result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128; + if (x & 0x4 > 0) + result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128; + if (x & 0x2 > 0) + result = result * 0x1000000000000000162E42FEFA39EF358 >> 128; + if (x & 0x1 > 0) + result = result * 0x10000000000000000B17217F7D1CF79AB >> 128; + + result >>= uint256 (int256 (63 - (x >> 64))); + require (result <= uint256 (int256 (MAX_64x64))); + + return int128 (int256 (result)); + } + } + + /** + * Calculate natural exponent of x. Revert on overflow. + * + * @param x signed 64.64-bit fixed point number + * @return signed 64.64-bit fixed point number + */ + function exp (int128 x) internal pure returns (int128) { + unchecked { + require (x < 0x400000000000000000); // Overflow + + if (x < -0x400000000000000000) return 0; // Underflow + + return exp_2 ( + int128 (int256 (x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128)); + } + } + + /** + * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit + * integer numbers. Revert on overflow or when y is zero. + * + * @param x unsigned 256-bit integer number + * @param y unsigned 256-bit integer number + * @return unsigned 64.64-bit fixed point number + */ + function divuu (uint256 x, uint256 y) private pure returns (uint128) { + unchecked { + require (y != 0); + + uint256 result; + + if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + result = (x << 64) / y; + else { + uint256 msb = 192; + uint256 xc = x >> 192; + if (xc >= 0x100000000) { xc >>= 32; msb += 32; } + if (xc >= 0x10000) { xc >>= 16; msb += 16; } + if (xc >= 0x100) { xc >>= 8; msb += 8; } + if (xc >= 0x10) { xc >>= 4; msb += 4; } + if (xc >= 0x4) { xc >>= 2; msb += 2; } + if (xc >= 0x2) msb += 1; // No need to shift xc anymore + + result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1); + require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + uint256 hi = result * (y >> 128); + uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + + uint256 xh = x >> 192; + uint256 xl = x << 64; + + if (xl < lo) xh -= 1; + xl -= lo; // We rely on overflow behavior here + lo = hi << 128; + if (xl < lo) xh -= 1; + xl -= lo; // We rely on overflow behavior here + + result += xh == hi >> 128 ? xl / y : 1; + } + + require (result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return uint128 (result); + } + } + + /** + * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer + * number. + * + * @param x unsigned 256-bit integer number + * @return unsigned 128-bit integer number + */ + function sqrtu (uint256 x) private pure returns (uint128) { + unchecked { + if (x == 0) return 0; + else { + uint256 xx = x; + uint256 r = 1; + if (xx >= 0x100000000000000000000000000000000) { xx >>= 128; r <<= 64; } + if (xx >= 0x10000000000000000) { xx >>= 64; r <<= 32; } + if (xx >= 0x100000000) { xx >>= 32; r <<= 16; } + if (xx >= 0x10000) { xx >>= 16; r <<= 8; } + if (xx >= 0x100) { xx >>= 8; r <<= 4; } + if (xx >= 0x10) { xx >>= 4; r <<= 2; } + if (xx >= 0x4) { r <<= 1; } + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; // Seven iterations should be enough + uint256 r1 = x / r; + return uint128 (r < r1 ? r : r1); + } + } + } +} diff --git a/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMathQuad.md b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMathQuad.md new file mode 100644 index 0000000..5585e2d --- /dev/null +++ b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMathQuad.md @@ -0,0 +1,196 @@ +ABDK Math Quad +============== + +Library of mathematical functions operating with IEEE 754 quadruple precision +(128 bit) floating point numbers. + +Copyright (c) 2019, [ABDK Consulting](https://abdk.consulting/) + +All rights reserved. + +IEEE 754 Quadruple Precision Floating Point Numbers +--------------------------------------------------- + +IEEE 754 standard specifies quadruple precision floating point numbers to have: + +* sign bit: 1 bit, +* exponent: 15 bits, +* significand precision: 113 bits (112 explicitly stored). + +This gives from 33 to 36 significant decimal digits precision. + +The minimum strictly positive (subnormal) value is `2^−16494 ≈ 10^−4965` +and has a precision of only one bit. The minimum positive normal value is +`2^−16382 ≈ 3.3621 × 10^−4932` and has a precision of 113 bits, i.e. +`±2^−16494` as well. The maximum representable value is +`2^16384 − 2^16271 ≈ 1.1897 × 10^4932`. + +The following special values are supported: + +* `NaN` (not a number), +* `+Infinity`, +* `-Infinity`. + +The format has two zero values: `0` (positive zero) and `-0` (negative zero). + +Comparison +---------- + +Here is the list of comparison functions provided by the library. + + function isNaN (bytes16 x) internal pure returns (bool) + +Test whether given quadruple precision floating point number is NaN (not a +number). + + function isInfinity (bytes16 x) internal pure returns (bool) + +Test whether given quadruple precision floating point number is infinity, either +positive or negative. + + function sign (bytes16 x) internal pure returns (int8) + +Get the sign of a quadruple precision floating point number, i.e. `-1` if +argument is negative, `0` if argument is zero, i.e. `0` or `-0`, and `1` if +argument is positive. + + function cmp (bytes16 x, bytes16 y) internal pure returns (int8) + +Compare two quadruple precision floating point numbers, and return `-1` if +`x < y`, `0` if `x = y`, and `1` is `x > y`. Basically, this function +returns `sign (x - y)`. + + function eq (bytes16 x, bytes16 y) internal pure returns (bool) + +Test whether two quadruple precision floating point numbers are equal. + +Simple Arithmetic +----------------- + +Simple arithmetic functions. + + function add (bytes16 x, bytes16 y) internal pure returns (bytes16) + +Add one quadruple precision floating point number to another and return the +result as a quadruple precision floating point number. + + function sub (bytes16 x, bytes16 y) internal pure returns (bytes16) + +Subtract one quadruple precision floating point number from another and +return the result as a quadruple precision floating point number. + + function mul (bytes16 x, bytes16 y) internal pure returns (bytes16) + +Multiply one quadruple precision floating point number by another and return the +result as a quadruple precision floating point number. + + function div (bytes16 x, bytes16 y) internal pure returns (bytes16) + +Divide one quadruple precision floating point number by another and return the +result as a quadruple precision floating point number. + + function neg (bytes16 x) internal pure returns (bytes16) + +Calculate the opposite for a quadruple precision floating point number, i.e. +`-x`, and return the result as a quadruple precision floating point number. + + function abs (bytes16 x) internal pure returns (bytes16) + +Calculate absolute value of a quadruple precision floating point number and +return the result as a quadruple precision floating point number. + +Root, Logarithm, and Exponentiation +----------------------------------- + +Root, logarithm, and exponentiation functions. + + function sqrt (bytes16 x) internal pure returns (bytes16) + +Calculate the square root of a quadruple precision floating point number and +return the result as a quadruple precision floating point number. + + function log_2 (bytes16 x) internal pure returns (bytes16) + +Calculate the binary logarithm of a quadruple precision floating point number +and return the result as a quadruple precision floating point number. + + function ln (bytes16 x) internal pure returns (bytes16) + +Calculate the natural logarithm of a quadruple precision floating point number +and return the result as a quadruple precision floating point number. + + function pow_2 (bytes16 x) internal pure returns (bytes16) + +Raise 2 to the power of a quadruple precision floating point number, i.e. +calculate `2^x`, and return the result as a quadruple precision floating +point number. + + function exp (bytes16 x) internal pure returns (bytes16) + +Exponentiate a quadruple precision floating point number, i.e. calculate +`e^x`, and return the result as a quadruple precision floating point number. + +Conversions +----------- + +Here are conversion functions. + + function fromInt (int256 x) internal pure returns (bytes16) + +Convert a signed 256 bit integer number into a quadruple precision floating +point number. + + function toInt (bytes16 x) internal pure returns (int256) + +Convert a quadruple precision floating point number into a signed 256 bit +integer number. + + function fromUInt (uint256 x) internal pure returns (bytes16) + +Convert an unsigned 256 bit integer number into a quadruple precision floating +point number. + + function toUInt (bytes16 x) internal pure returns (uint256) + +Convert a quadruple precision floating point number into an unsigned 256 bit +integer number. + + function from128x128 (int256 x) internal pure returns (bytes16) + +Convert a signed 128.128 bit fixed point number into a quadruple precision +floating point number. + + function to128x128 (bytes16 x) internal pure returns (int256) + +Convert a quadruple precision floating point number into a signed 128.128 bit +fixed point number. + + function from64x64 (int128 x) internal pure returns (bytes16) + +Convert a signed 64.64 bit fixed point number into a quadruple precision +floating point number. + + function to64x64 (bytes16 x) internal pure returns (int128) + +Convert a quadruple precision floating point number into a signed 64.64 bit +fixed point number. + + function fromOctuple (bytes32 x) internal pure returns (bytes16) + +Convert an octuple precision floating point number into a quadruple precision +floating point number. + + function toOctuple (bytes16 x) internal pure returns (bytes32) + +Convert a quadruple precision floating point number into an octuple precision +floating point number. + + function fromDouble (bytes8 x) internal pure returns (bytes16) + +Convert a double precision floating point number into a quadruple precision +floating point number. + + function toDouble (bytes16 x) internal pure returns (bytes8) + +Convert a quadruple precision floating point number into a double precision +floating point number. \ No newline at end of file diff --git a/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMathQuad.sol b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMathQuad.sol new file mode 100644 index 0000000..dcc3fc8 --- /dev/null +++ b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/ABDKMathQuad.sol @@ -0,0 +1,1215 @@ +// SPDX-License-Identifier: BSD-4-Clause +/* + * ABDK Math Quad Smart Contract Library. Copyright © 2019 by ABDK Consulting. + * Author: Mikhail Vladimirov + */ +pragma solidity ^0.8.0; + +/** + * Smart contract library of mathematical functions operating with IEEE 754 + * quadruple-precision binary floating-point numbers (quadruple precision + * numbers). As long as quadruple precision numbers are 16-bytes long, they are + * represented by bytes16 type. + */ +library ABDKMathQuad { + /* + * 0. + */ + bytes16 private constant POSITIVE_ZERO = 0x00000000000000000000000000000000; + + /* + * -0. + */ + bytes16 private constant NEGATIVE_ZERO = 0x80000000000000000000000000000000; + + /* + * +Infinity. + */ + bytes16 private constant POSITIVE_INFINITY = 0x7FFF0000000000000000000000000000; + + /* + * -Infinity. + */ + bytes16 private constant NEGATIVE_INFINITY = 0xFFFF0000000000000000000000000000; + + /* + * Canonical NaN value. + */ + bytes16 private constant NaN = 0x7FFF8000000000000000000000000000; + + /** + * Convert signed 256-bit integer number into quadruple precision number. + * + * @param x signed 256-bit integer number + * @return quadruple precision number + */ + function fromInt (int256 x) internal pure returns (bytes16) { + unchecked { + if (x == 0) return bytes16 (0); + else { + // We rely on overflow behavior here + uint256 result = uint256 (x > 0 ? x : -x); + + uint256 msb = mostSignificantBit (result); + if (msb < 112) result <<= 112 - msb; + else if (msb > 112) result >>= msb - 112; + + result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112; + if (x < 0) result |= 0x80000000000000000000000000000000; + + return bytes16 (uint128 (result)); + } + } + } + + /** + * Convert quadruple precision number into signed 256-bit integer number + * rounding towards zero. Revert on overflow. + * + * @param x quadruple precision number + * @return signed 256-bit integer number + */ + function toInt (bytes16 x) internal pure returns (int256) { + unchecked { + uint256 exponent = uint128 (x) >> 112 & 0x7FFF; + + require (exponent <= 16638); // Overflow + if (exponent < 16383) return 0; // Underflow + + uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | + 0x10000000000000000000000000000; + + if (exponent < 16495) result >>= 16495 - exponent; + else if (exponent > 16495) result <<= exponent - 16495; + + if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative + require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000); + return -int256 (result); // We rely on overflow behavior here + } else { + require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return int256 (result); + } + } + } + + /** + * Convert unsigned 256-bit integer number into quadruple precision number. + * + * @param x unsigned 256-bit integer number + * @return quadruple precision number + */ + function fromUInt (uint256 x) internal pure returns (bytes16) { + unchecked { + if (x == 0) return bytes16 (0); + else { + uint256 result = x; + + uint256 msb = mostSignificantBit (result); + if (msb < 112) result <<= 112 - msb; + else if (msb > 112) result >>= msb - 112; + + result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16383 + msb << 112; + + return bytes16 (uint128 (result)); + } + } + } + + /** + * Convert quadruple precision number into unsigned 256-bit integer number + * rounding towards zero. Revert on underflow. Note, that negative floating + * point numbers in range (-1.0 .. 0.0) may be converted to unsigned integer + * without error, because they are rounded to zero. + * + * @param x quadruple precision number + * @return unsigned 256-bit integer number + */ + function toUInt (bytes16 x) internal pure returns (uint256) { + unchecked { + uint256 exponent = uint128 (x) >> 112 & 0x7FFF; + + if (exponent < 16383) return 0; // Underflow + + require (uint128 (x) < 0x80000000000000000000000000000000); // Negative + + require (exponent <= 16638); // Overflow + uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | + 0x10000000000000000000000000000; + + if (exponent < 16495) result >>= 16495 - exponent; + else if (exponent > 16495) result <<= exponent - 16495; + + return result; + } + } + + /** + * Convert signed 128.128 bit fixed point number into quadruple precision + * number. + * + * @param x signed 128.128 bit fixed point number + * @return quadruple precision number + */ + function from128x128 (int256 x) internal pure returns (bytes16) { + unchecked { + if (x == 0) return bytes16 (0); + else { + // We rely on overflow behavior here + uint256 result = uint256 (x > 0 ? x : -x); + + uint256 msb = mostSignificantBit (result); + if (msb < 112) result <<= 112 - msb; + else if (msb > 112) result >>= msb - 112; + + result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16255 + msb << 112; + if (x < 0) result |= 0x80000000000000000000000000000000; + + return bytes16 (uint128 (result)); + } + } + } + + /** + * Convert quadruple precision number into signed 128.128 bit fixed point + * number. Revert on overflow. + * + * @param x quadruple precision number + * @return signed 128.128 bit fixed point number + */ + function to128x128 (bytes16 x) internal pure returns (int256) { + unchecked { + uint256 exponent = uint128 (x) >> 112 & 0x7FFF; + + require (exponent <= 16510); // Overflow + if (exponent < 16255) return 0; // Underflow + + uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | + 0x10000000000000000000000000000; + + if (exponent < 16367) result >>= 16367 - exponent; + else if (exponent > 16367) result <<= exponent - 16367; + + if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative + require (result <= 0x8000000000000000000000000000000000000000000000000000000000000000); + return -int256 (result); // We rely on overflow behavior here + } else { + require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return int256 (result); + } + } + } + + /** + * Convert signed 64.64 bit fixed point number into quadruple precision + * number. + * + * @param x signed 64.64 bit fixed point number + * @return quadruple precision number + */ + function from64x64 (int128 x) internal pure returns (bytes16) { + unchecked { + if (x == 0) return bytes16 (0); + else { + // We rely on overflow behavior here + uint256 result = uint128 (x > 0 ? x : -x); + + uint256 msb = mostSignificantBit (result); + if (msb < 112) result <<= 112 - msb; + else if (msb > 112) result >>= msb - 112; + + result = result & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | 16319 + msb << 112; + if (x < 0) result |= 0x80000000000000000000000000000000; + + return bytes16 (uint128 (result)); + } + } + } + + /** + * Convert quadruple precision number into signed 64.64 bit fixed point + * number. Revert on overflow. + * + * @param x quadruple precision number + * @return signed 64.64 bit fixed point number + */ + function to64x64 (bytes16 x) internal pure returns (int128) { + unchecked { + uint256 exponent = uint128 (x) >> 112 & 0x7FFF; + + require (exponent <= 16446); // Overflow + if (exponent < 16319) return 0; // Underflow + + uint256 result = uint256 (uint128 (x)) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF | + 0x10000000000000000000000000000; + + if (exponent < 16431) result >>= 16431 - exponent; + else if (exponent > 16431) result <<= exponent - 16431; + + if (uint128 (x) >= 0x80000000000000000000000000000000) { // Negative + require (result <= 0x80000000000000000000000000000000); + return -int128 (int256 (result)); // We rely on overflow behavior here + } else { + require (result <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF); + return int128 (int256 (result)); + } + } + } + + /** + * Convert octuple precision number into quadruple precision number. + * + * @param x octuple precision number + * @return quadruple precision number + */ + function fromOctuple (bytes32 x) internal pure returns (bytes16) { + unchecked { + bool negative = x & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0; + + uint256 exponent = uint256 (x) >> 236 & 0x7FFFF; + uint256 significand = uint256 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + if (exponent == 0x7FFFF) { + if (significand > 0) return NaN; + else return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY; + } + + if (exponent > 278526) + return negative ? NEGATIVE_INFINITY : POSITIVE_INFINITY; + else if (exponent < 245649) + return negative ? NEGATIVE_ZERO : POSITIVE_ZERO; + else if (exponent < 245761) { + significand = (significand | 0x100000000000000000000000000000000000000000000000000000000000) >> 245885 - exponent; + exponent = 0; + } else { + significand >>= 124; + exponent -= 245760; + } + + uint128 result = uint128 (significand | exponent << 112); + if (negative) result |= 0x80000000000000000000000000000000; + + return bytes16 (result); + } + } + + /** + * Convert quadruple precision number into octuple precision number. + * + * @param x quadruple precision number + * @return octuple precision number + */ + function toOctuple (bytes16 x) internal pure returns (bytes32) { + unchecked { + uint256 exponent = uint128 (x) >> 112 & 0x7FFF; + + uint256 result = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + if (exponent == 0x7FFF) exponent = 0x7FFFF; // Infinity or NaN + else if (exponent == 0) { + if (result > 0) { + uint256 msb = mostSignificantBit (result); + result = result << 236 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + exponent = 245649 + msb; + } + } else { + result <<= 124; + exponent += 245760; + } + + result |= exponent << 236; + if (uint128 (x) >= 0x80000000000000000000000000000000) + result |= 0x8000000000000000000000000000000000000000000000000000000000000000; + + return bytes32 (result); + } + } + + /** + * Convert double precision number into quadruple precision number. + * + * @param x double precision number + * @return quadruple precision number + */ + function fromDouble (bytes8 x) internal pure returns (bytes16) { + unchecked { + uint256 exponent = uint64 (x) >> 52 & 0x7FF; + + uint256 result = uint64 (x) & 0xFFFFFFFFFFFFF; + + if (exponent == 0x7FF) exponent = 0x7FFF; // Infinity or NaN + else if (exponent == 0) { + if (result > 0) { + uint256 msb = mostSignificantBit (result); + result = result << 112 - msb & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + exponent = 15309 + msb; + } + } else { + result <<= 60; + exponent += 15360; + } + + result |= exponent << 112; + if (x & 0x8000000000000000 > 0) + result |= 0x80000000000000000000000000000000; + + return bytes16 (uint128 (result)); + } + } + + /** + * Convert quadruple precision number into double precision number. + * + * @param x quadruple precision number + * @return double precision number + */ + function toDouble (bytes16 x) internal pure returns (bytes8) { + unchecked { + bool negative = uint128 (x) >= 0x80000000000000000000000000000000; + + uint256 exponent = uint128 (x) >> 112 & 0x7FFF; + uint256 significand = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + if (exponent == 0x7FFF) { + if (significand > 0) return 0x7FF8000000000000; // NaN + else return negative ? + bytes8 (0xFFF0000000000000) : // -Infinity + bytes8 (0x7FF0000000000000); // Infinity + } + + if (exponent > 17406) + return negative ? + bytes8 (0xFFF0000000000000) : // -Infinity + bytes8 (0x7FF0000000000000); // Infinity + else if (exponent < 15309) + return negative ? + bytes8 (0x8000000000000000) : // -0 + bytes8 (0x0000000000000000); // 0 + else if (exponent < 15361) { + significand = (significand | 0x10000000000000000000000000000) >> 15421 - exponent; + exponent = 0; + } else { + significand >>= 60; + exponent -= 15360; + } + + uint64 result = uint64 (significand | exponent << 52); + if (negative) result |= 0x8000000000000000; + + return bytes8 (result); + } + } + + /** + * Test whether given quadruple precision number is NaN. + * + * @param x quadruple precision number + * @return true if x is NaN, false otherwise + */ + function isNaN (bytes16 x) internal pure returns (bool) { + unchecked { + return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF > + 0x7FFF0000000000000000000000000000; + } + } + + /** + * Test whether given quadruple precision number is positive or negative + * infinity. + * + * @param x quadruple precision number + * @return true if x is positive or negative infinity, false otherwise + */ + function isInfinity (bytes16 x) internal pure returns (bool) { + unchecked { + return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == + 0x7FFF0000000000000000000000000000; + } + } + + /** + * Calculate sign of x, i.e. -1 if x is negative, 0 if x if zero, and 1 if x + * is positive. Note that sign (-0) is zero. Revert if x is NaN. + * + * @param x quadruple precision number + * @return sign of x + */ + function sign (bytes16 x) internal pure returns (int8) { + unchecked { + uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN + + if (absoluteX == 0) return 0; + else if (uint128 (x) >= 0x80000000000000000000000000000000) return -1; + else return 1; + } + } + + /** + * Calculate sign (x - y). Revert if either argument is NaN, or both + * arguments are infinities of the same sign. + * + * @param x quadruple precision number + * @param y quadruple precision number + * @return sign (x - y) + */ + function cmp (bytes16 x, bytes16 y) internal pure returns (int8) { + unchecked { + uint128 absoluteX = uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + require (absoluteX <= 0x7FFF0000000000000000000000000000); // Not NaN + + uint128 absoluteY = uint128 (y) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + require (absoluteY <= 0x7FFF0000000000000000000000000000); // Not NaN + + // Not infinities of the same sign + require (x != y || absoluteX < 0x7FFF0000000000000000000000000000); + + if (x == y) return 0; + else { + bool negativeX = uint128 (x) >= 0x80000000000000000000000000000000; + bool negativeY = uint128 (y) >= 0x80000000000000000000000000000000; + + if (negativeX) { + if (negativeY) return absoluteX > absoluteY ? -1 : int8 (1); + else return -1; + } else { + if (negativeY) return 1; + else return absoluteX > absoluteY ? int8 (1) : -1; + } + } + } + } + + /** + * Test whether x equals y. NaN, infinity, and -infinity are not equal to + * anything. + * + * @param x quadruple precision number + * @param y quadruple precision number + * @return true if x equals to y, false otherwise + */ + function eq (bytes16 x, bytes16 y) internal pure returns (bool) { + unchecked { + if (x == y) { + return uint128 (x) & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF < + 0x7FFF0000000000000000000000000000; + } else return false; + } + } + + /** + * Calculate x + y. Special values behave in the following way: + * + * NaN + x = NaN for any x. + * Infinity + x = Infinity for any finite x. + * -Infinity + x = -Infinity for any finite x. + * Infinity + Infinity = Infinity. + * -Infinity + -Infinity = -Infinity. + * Infinity + -Infinity = -Infinity + Infinity = NaN. + * + * @param x quadruple precision number + * @param y quadruple precision number + * @return quadruple precision number + */ + function add (bytes16 x, bytes16 y) internal pure returns (bytes16) { + unchecked { + uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; + uint256 yExponent = uint128 (y) >> 112 & 0x7FFF; + + if (xExponent == 0x7FFF) { + if (yExponent == 0x7FFF) { + if (x == y) return x; + else return NaN; + } else return x; + } else if (yExponent == 0x7FFF) return y; + else { + bool xSign = uint128 (x) >= 0x80000000000000000000000000000000; + uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (xExponent == 0) xExponent = 1; + else xSignifier |= 0x10000000000000000000000000000; + + bool ySign = uint128 (y) >= 0x80000000000000000000000000000000; + uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (yExponent == 0) yExponent = 1; + else ySignifier |= 0x10000000000000000000000000000; + + if (xSignifier == 0) return y == NEGATIVE_ZERO ? POSITIVE_ZERO : y; + else if (ySignifier == 0) return x == NEGATIVE_ZERO ? POSITIVE_ZERO : x; + else { + int256 delta = int256 (xExponent) - int256 (yExponent); + + if (xSign == ySign) { + if (delta > 112) return x; + else if (delta > 0) ySignifier >>= uint256 (delta); + else if (delta < -112) return y; + else if (delta < 0) { + xSignifier >>= uint256 (-delta); + xExponent = yExponent; + } + + xSignifier += ySignifier; + + if (xSignifier >= 0x20000000000000000000000000000) { + xSignifier >>= 1; + xExponent += 1; + } + + if (xExponent == 0x7FFF) + return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY; + else { + if (xSignifier < 0x10000000000000000000000000000) xExponent = 0; + else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + return bytes16 (uint128 ( + (xSign ? 0x80000000000000000000000000000000 : 0) | + (xExponent << 112) | + xSignifier)); + } + } else { + if (delta > 0) { + xSignifier <<= 1; + xExponent -= 1; + } else if (delta < 0) { + ySignifier <<= 1; + xExponent = yExponent - 1; + } + + if (delta > 112) ySignifier = 1; + else if (delta > 1) ySignifier = (ySignifier - 1 >> uint256 (delta - 1)) + 1; + else if (delta < -112) xSignifier = 1; + else if (delta < -1) xSignifier = (xSignifier - 1 >> uint256 (-delta - 1)) + 1; + + if (xSignifier >= ySignifier) xSignifier -= ySignifier; + else { + xSignifier = ySignifier - xSignifier; + xSign = ySign; + } + + if (xSignifier == 0) + return POSITIVE_ZERO; + + uint256 msb = mostSignificantBit (xSignifier); + + if (msb == 113) { + xSignifier = xSignifier >> 1 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + xExponent += 1; + } else if (msb < 112) { + uint256 shift = 112 - msb; + if (xExponent > shift) { + xSignifier = xSignifier << shift & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + xExponent -= shift; + } else { + xSignifier <<= xExponent - 1; + xExponent = 0; + } + } else xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + if (xExponent == 0x7FFF) + return xSign ? NEGATIVE_INFINITY : POSITIVE_INFINITY; + else return bytes16 (uint128 ( + (xSign ? 0x80000000000000000000000000000000 : 0) | + (xExponent << 112) | + xSignifier)); + } + } + } + } + } + + /** + * Calculate x - y. Special values behave in the following way: + * + * NaN - x = NaN for any x. + * Infinity - x = Infinity for any finite x. + * -Infinity - x = -Infinity for any finite x. + * Infinity - -Infinity = Infinity. + * -Infinity - Infinity = -Infinity. + * Infinity - Infinity = -Infinity - -Infinity = NaN. + * + * @param x quadruple precision number + * @param y quadruple precision number + * @return quadruple precision number + */ + function sub (bytes16 x, bytes16 y) internal pure returns (bytes16) { + unchecked { + return add (x, y ^ 0x80000000000000000000000000000000); + } + } + + /** + * Calculate x * y. Special values behave in the following way: + * + * NaN * x = NaN for any x. + * Infinity * x = Infinity for any finite positive x. + * Infinity * x = -Infinity for any finite negative x. + * -Infinity * x = -Infinity for any finite positive x. + * -Infinity * x = Infinity for any finite negative x. + * Infinity * 0 = NaN. + * -Infinity * 0 = NaN. + * Infinity * Infinity = Infinity. + * Infinity * -Infinity = -Infinity. + * -Infinity * Infinity = -Infinity. + * -Infinity * -Infinity = Infinity. + * + * @param x quadruple precision number + * @param y quadruple precision number + * @return quadruple precision number + */ + function mul (bytes16 x, bytes16 y) internal pure returns (bytes16) { + unchecked { + uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; + uint256 yExponent = uint128 (y) >> 112 & 0x7FFF; + + if (xExponent == 0x7FFF) { + if (yExponent == 0x7FFF) { + if (x == y) return x ^ y & 0x80000000000000000000000000000000; + else if (x ^ y == 0x80000000000000000000000000000000) return x | y; + else return NaN; + } else { + if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; + else return x ^ y & 0x80000000000000000000000000000000; + } + } else if (yExponent == 0x7FFF) { + if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; + else return y ^ x & 0x80000000000000000000000000000000; + } else { + uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (xExponent == 0) xExponent = 1; + else xSignifier |= 0x10000000000000000000000000000; + + uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (yExponent == 0) yExponent = 1; + else ySignifier |= 0x10000000000000000000000000000; + + xSignifier *= ySignifier; + if (xSignifier == 0) + return (x ^ y) & 0x80000000000000000000000000000000 > 0 ? + NEGATIVE_ZERO : POSITIVE_ZERO; + + xExponent += yExponent; + + uint256 msb = + xSignifier >= 0x200000000000000000000000000000000000000000000000000000000 ? 225 : + xSignifier >= 0x100000000000000000000000000000000000000000000000000000000 ? 224 : + mostSignificantBit (xSignifier); + + if (xExponent + msb < 16496) { // Underflow + xExponent = 0; + xSignifier = 0; + } else if (xExponent + msb < 16608) { // Subnormal + if (xExponent < 16496) + xSignifier >>= 16496 - xExponent; + else if (xExponent > 16496) + xSignifier <<= xExponent - 16496; + xExponent = 0; + } else if (xExponent + msb > 49373) { + xExponent = 0x7FFF; + xSignifier = 0; + } else { + if (msb > 112) + xSignifier >>= msb - 112; + else if (msb < 112) + xSignifier <<= 112 - msb; + + xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + xExponent = xExponent + msb - 16607; + } + + return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) | + xExponent << 112 | xSignifier)); + } + } + } + + /** + * Calculate x / y. Special values behave in the following way: + * + * NaN / x = NaN for any x. + * x / NaN = NaN for any x. + * Infinity / x = Infinity for any finite non-negative x. + * Infinity / x = -Infinity for any finite negative x including -0. + * -Infinity / x = -Infinity for any finite non-negative x. + * -Infinity / x = Infinity for any finite negative x including -0. + * x / Infinity = 0 for any finite non-negative x. + * x / -Infinity = -0 for any finite non-negative x. + * x / Infinity = -0 for any finite non-negative x including -0. + * x / -Infinity = 0 for any finite non-negative x including -0. + * + * Infinity / Infinity = NaN. + * Infinity / -Infinity = -NaN. + * -Infinity / Infinity = -NaN. + * -Infinity / -Infinity = NaN. + * + * Division by zero behaves in the following way: + * + * x / 0 = Infinity for any finite positive x. + * x / -0 = -Infinity for any finite positive x. + * x / 0 = -Infinity for any finite negative x. + * x / -0 = Infinity for any finite negative x. + * 0 / 0 = NaN. + * 0 / -0 = NaN. + * -0 / 0 = NaN. + * -0 / -0 = NaN. + * + * @param x quadruple precision number + * @param y quadruple precision number + * @return quadruple precision number + */ + function div (bytes16 x, bytes16 y) internal pure returns (bytes16) { + unchecked { + uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; + uint256 yExponent = uint128 (y) >> 112 & 0x7FFF; + + if (xExponent == 0x7FFF) { + if (yExponent == 0x7FFF) return NaN; + else return x ^ y & 0x80000000000000000000000000000000; + } else if (yExponent == 0x7FFF) { + if (y & 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFF != 0) return NaN; + else return POSITIVE_ZERO | (x ^ y) & 0x80000000000000000000000000000000; + } else if (y & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) { + if (x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0) return NaN; + else return POSITIVE_INFINITY | (x ^ y) & 0x80000000000000000000000000000000; + } else { + uint256 ySignifier = uint128 (y) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (yExponent == 0) yExponent = 1; + else ySignifier |= 0x10000000000000000000000000000; + + uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (xExponent == 0) { + if (xSignifier != 0) { + uint shift = 226 - mostSignificantBit (xSignifier); + + xSignifier <<= shift; + + xExponent = 1; + yExponent += shift - 114; + } + } + else { + xSignifier = (xSignifier | 0x10000000000000000000000000000) << 114; + } + + xSignifier = xSignifier / ySignifier; + if (xSignifier == 0) + return (x ^ y) & 0x80000000000000000000000000000000 > 0 ? + NEGATIVE_ZERO : POSITIVE_ZERO; + + assert (xSignifier >= 0x1000000000000000000000000000); + + uint256 msb = + xSignifier >= 0x80000000000000000000000000000 ? mostSignificantBit (xSignifier) : + xSignifier >= 0x40000000000000000000000000000 ? 114 : + xSignifier >= 0x20000000000000000000000000000 ? 113 : 112; + + if (xExponent + msb > yExponent + 16497) { // Overflow + xExponent = 0x7FFF; + xSignifier = 0; + } else if (xExponent + msb + 16380 < yExponent) { // Underflow + xExponent = 0; + xSignifier = 0; + } else if (xExponent + msb + 16268 < yExponent) { // Subnormal + if (xExponent + 16380 > yExponent) + xSignifier <<= xExponent + 16380 - yExponent; + else if (xExponent + 16380 < yExponent) + xSignifier >>= yExponent - xExponent - 16380; + + xExponent = 0; + } else { // Normal + if (msb > 112) + xSignifier >>= msb - 112; + + xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + xExponent = xExponent + msb + 16269 - yExponent; + } + + return bytes16 (uint128 (uint128 ((x ^ y) & 0x80000000000000000000000000000000) | + xExponent << 112 | xSignifier)); + } + } + } + + /** + * Calculate -x. + * + * @param x quadruple precision number + * @return quadruple precision number + */ + function neg (bytes16 x) internal pure returns (bytes16) { + unchecked { + return x ^ 0x80000000000000000000000000000000; + } + } + + /** + * Calculate |x|. + * + * @param x quadruple precision number + * @return quadruple precision number + */ + function abs (bytes16 x) internal pure returns (bytes16) { + unchecked { + return x & 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + } + } + + /** + * Calculate square root of x. Return NaN on negative x excluding -0. + * + * @param x quadruple precision number + * @return quadruple precision number + */ + function sqrt (bytes16 x) internal pure returns (bytes16) { + unchecked { + if (uint128 (x) > 0x80000000000000000000000000000000) return NaN; + else { + uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; + if (xExponent == 0x7FFF) return x; + else { + uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (xExponent == 0) xExponent = 1; + else xSignifier |= 0x10000000000000000000000000000; + + if (xSignifier == 0) return POSITIVE_ZERO; + + bool oddExponent = xExponent & 0x1 == 0; + xExponent = xExponent + 16383 >> 1; + + if (oddExponent) { + if (xSignifier >= 0x10000000000000000000000000000) + xSignifier <<= 113; + else { + uint256 msb = mostSignificantBit (xSignifier); + uint256 shift = (226 - msb) & 0xFE; + xSignifier <<= shift; + xExponent -= shift - 112 >> 1; + } + } else { + if (xSignifier >= 0x10000000000000000000000000000) + xSignifier <<= 112; + else { + uint256 msb = mostSignificantBit (xSignifier); + uint256 shift = (225 - msb) & 0xFE; + xSignifier <<= shift; + xExponent -= shift - 112 >> 1; + } + } + + uint256 r = 0x10000000000000000000000000000; + r = (r + xSignifier / r) >> 1; + r = (r + xSignifier / r) >> 1; + r = (r + xSignifier / r) >> 1; + r = (r + xSignifier / r) >> 1; + r = (r + xSignifier / r) >> 1; + r = (r + xSignifier / r) >> 1; + r = (r + xSignifier / r) >> 1; // Seven iterations should be enough + uint256 r1 = xSignifier / r; + if (r1 < r) r = r1; + + return bytes16 (uint128 (xExponent << 112 | r & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); + } + } + } + } + + /** + * Calculate binary logarithm of x. Return NaN on negative x excluding -0. + * + * @param x quadruple precision number + * @return quadruple precision number + */ + function log_2 (bytes16 x) internal pure returns (bytes16) { + unchecked { + if (uint128 (x) > 0x80000000000000000000000000000000) return NaN; + else if (x == 0x3FFF0000000000000000000000000000) return POSITIVE_ZERO; + else { + uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; + if (xExponent == 0x7FFF) return x; + else { + uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (xExponent == 0) xExponent = 1; + else xSignifier |= 0x10000000000000000000000000000; + + if (xSignifier == 0) return NEGATIVE_INFINITY; + + bool resultNegative; + uint256 resultExponent = 16495; + uint256 resultSignifier; + + if (xExponent >= 0x3FFF) { + resultNegative = false; + resultSignifier = xExponent - 0x3FFF; + xSignifier <<= 15; + } else { + resultNegative = true; + if (xSignifier >= 0x10000000000000000000000000000) { + resultSignifier = 0x3FFE - xExponent; + xSignifier <<= 15; + } else { + uint256 msb = mostSignificantBit (xSignifier); + resultSignifier = 16493 - msb; + xSignifier <<= 127 - msb; + } + } + + if (xSignifier == 0x80000000000000000000000000000000) { + if (resultNegative) resultSignifier += 1; + uint256 shift = 112 - mostSignificantBit (resultSignifier); + resultSignifier <<= shift; + resultExponent -= shift; + } else { + uint256 bb = resultNegative ? 1 : 0; + while (resultSignifier < 0x10000000000000000000000000000) { + resultSignifier <<= 1; + resultExponent -= 1; + + xSignifier *= xSignifier; + uint256 b = xSignifier >> 255; + resultSignifier += b ^ bb; + xSignifier >>= 127 + b; + } + } + + return bytes16 (uint128 ((resultNegative ? 0x80000000000000000000000000000000 : 0) | + resultExponent << 112 | resultSignifier & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF)); + } + } + } + } + + /** + * Calculate natural logarithm of x. Return NaN on negative x excluding -0. + * + * @param x quadruple precision number + * @return quadruple precision number + */ + function ln (bytes16 x) internal pure returns (bytes16) { + unchecked { + return mul (log_2 (x), 0x3FFE62E42FEFA39EF35793C7673007E5); + } + } + + /** + * Calculate 2^x. + * + * @param x quadruple precision number + * @return quadruple precision number + */ + function pow_2 (bytes16 x) internal pure returns (bytes16) { + unchecked { + bool xNegative = uint128 (x) > 0x80000000000000000000000000000000; + uint256 xExponent = uint128 (x) >> 112 & 0x7FFF; + uint256 xSignifier = uint128 (x) & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + + if (xExponent == 0x7FFF && xSignifier != 0) return NaN; + else if (xExponent > 16397) + return xNegative ? POSITIVE_ZERO : POSITIVE_INFINITY; + else if (xExponent < 16255) + return 0x3FFF0000000000000000000000000000; + else { + if (xExponent == 0) xExponent = 1; + else xSignifier |= 0x10000000000000000000000000000; + + if (xExponent > 16367) + xSignifier <<= xExponent - 16367; + else if (xExponent < 16367) + xSignifier >>= 16367 - xExponent; + + if (xNegative && xSignifier > 0x406E00000000000000000000000000000000) + return POSITIVE_ZERO; + + if (!xNegative && xSignifier > 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) + return POSITIVE_INFINITY; + + uint256 resultExponent = xSignifier >> 128; + xSignifier &= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + if (xNegative && xSignifier != 0) { + xSignifier = ~xSignifier; + resultExponent += 1; + } + + uint256 resultSignifier = 0x80000000000000000000000000000000; + if (xSignifier & 0x80000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128; + if (xSignifier & 0x40000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128; + if (xSignifier & 0x20000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128; + if (xSignifier & 0x10000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10B5586CF9890F6298B92B71842A98363 >> 128; + if (xSignifier & 0x8000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1059B0D31585743AE7C548EB68CA417FD >> 128; + if (xSignifier & 0x4000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128; + if (xSignifier & 0x2000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128; + if (xSignifier & 0x1000000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128; + if (xSignifier & 0x800000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128; + if (xSignifier & 0x400000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128; + if (xSignifier & 0x200000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100162F3904051FA128BCA9C55C31E5DF >> 128; + if (xSignifier & 0x100000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000B175EFFDC76BA38E31671CA939725 >> 128; + if (xSignifier & 0x80000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128; + if (xSignifier & 0x40000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128; + if (xSignifier & 0x20000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000162E525EE054754457D5995292026 >> 128; + if (xSignifier & 0x10000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000B17255775C040618BF4A4ADE83FC >> 128; + if (xSignifier & 0x8000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128; + if (xSignifier & 0x4000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128; + if (xSignifier & 0x2000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000162E43F4F831060E02D839A9D16D >> 128; + if (xSignifier & 0x1000000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000B1721BCFC99D9F890EA06911763 >> 128; + if (xSignifier & 0x800000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128; + if (xSignifier & 0x400000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128; + if (xSignifier & 0x200000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000162E430E5A18F6119E3C02282A5 >> 128; + if (xSignifier & 0x100000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000B1721835514B86E6D96EFD1BFE >> 128; + if (xSignifier & 0x80000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128; + if (xSignifier & 0x40000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000002C5C8601CC6B9E94213C72737A >> 128; + if (xSignifier & 0x20000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000162E42FFF037DF38AA2B219F06 >> 128; + if (xSignifier & 0x10000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000B17217FBA9C739AA5819F44F9 >> 128; + if (xSignifier & 0x8000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128; + if (xSignifier & 0x4000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128; + if (xSignifier & 0x2000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000162E42FF0999CE3541B9FFFCF >> 128; + if (xSignifier & 0x1000000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000B17217F80F4EF5AADDA45554 >> 128; + if (xSignifier & 0x800000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000058B90BFBF8479BD5A81B51AD >> 128; + if (xSignifier & 0x400000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128; + if (xSignifier & 0x200000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000162E42FEFB2FED257559BDAA >> 128; + if (xSignifier & 0x100000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128; + if (xSignifier & 0x80000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128; + if (xSignifier & 0x40000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128; + if (xSignifier & 0x20000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000162E42FEFA494F1478FDE05 >> 128; + if (xSignifier & 0x10000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000B17217F7D20CF927C8E94C >> 128; + if (xSignifier & 0x8000000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128; + if (xSignifier & 0x4000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000002C5C85FDF477B662B26945 >> 128; + if (xSignifier & 0x2000000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000162E42FEFA3AE53369388C >> 128; + if (xSignifier & 0x1000000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000B17217F7D1D351A389D40 >> 128; + if (xSignifier & 0x800000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128; + if (xSignifier & 0x400000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000002C5C85FDF4741BEA6E77E >> 128; + if (xSignifier & 0x200000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000162E42FEFA39FE95583C2 >> 128; + if (xSignifier & 0x100000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000B17217F7D1CFB72B45E1 >> 128; + if (xSignifier & 0x80000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128; + if (xSignifier & 0x40000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000002C5C85FDF473E242EA38 >> 128; + if (xSignifier & 0x20000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000162E42FEFA39F02B772C >> 128; + if (xSignifier & 0x10000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000B17217F7D1CF7D83C1A >> 128; + if (xSignifier & 0x8000000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128; + if (xSignifier & 0x4000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000002C5C85FDF473DEA871F >> 128; + if (xSignifier & 0x2000000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000162E42FEFA39EF44D91 >> 128; + if (xSignifier & 0x1000000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000B17217F7D1CF79E949 >> 128; + if (xSignifier & 0x800000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000058B90BFBE8E7BCE544 >> 128; + if (xSignifier & 0x400000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000002C5C85FDF473DE6ECA >> 128; + if (xSignifier & 0x200000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000162E42FEFA39EF366F >> 128; + if (xSignifier & 0x100000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000B17217F7D1CF79AFA >> 128; + if (xSignifier & 0x80000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000058B90BFBE8E7BCD6D >> 128; + if (xSignifier & 0x40000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000002C5C85FDF473DE6B2 >> 128; + if (xSignifier & 0x20000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000162E42FEFA39EF358 >> 128; + if (xSignifier & 0x10000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000B17217F7D1CF79AB >> 128; + if (xSignifier & 0x8000000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000058B90BFBE8E7BCD5 >> 128; + if (xSignifier & 0x4000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000002C5C85FDF473DE6A >> 128; + if (xSignifier & 0x2000000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000162E42FEFA39EF34 >> 128; + if (xSignifier & 0x1000000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000B17217F7D1CF799 >> 128; + if (xSignifier & 0x800000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000058B90BFBE8E7BCC >> 128; + if (xSignifier & 0x400000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000002C5C85FDF473DE5 >> 128; + if (xSignifier & 0x200000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000162E42FEFA39EF2 >> 128; + if (xSignifier & 0x100000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000B17217F7D1CF78 >> 128; + if (xSignifier & 0x80000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000058B90BFBE8E7BB >> 128; + if (xSignifier & 0x40000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000002C5C85FDF473DD >> 128; + if (xSignifier & 0x20000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000162E42FEFA39EE >> 128; + if (xSignifier & 0x10000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000B17217F7D1CF6 >> 128; + if (xSignifier & 0x8000000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000058B90BFBE8E7A >> 128; + if (xSignifier & 0x4000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000002C5C85FDF473C >> 128; + if (xSignifier & 0x2000000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000162E42FEFA39D >> 128; + if (xSignifier & 0x1000000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000B17217F7D1CE >> 128; + if (xSignifier & 0x800000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000058B90BFBE8E6 >> 128; + if (xSignifier & 0x400000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000002C5C85FDF472 >> 128; + if (xSignifier & 0x200000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000162E42FEFA38 >> 128; + if (xSignifier & 0x100000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000B17217F7D1B >> 128; + if (xSignifier & 0x80000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000058B90BFBE8D >> 128; + if (xSignifier & 0x40000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000002C5C85FDF46 >> 128; + if (xSignifier & 0x20000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000162E42FEFA2 >> 128; + if (xSignifier & 0x10000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000B17217F7D0 >> 128; + if (xSignifier & 0x8000000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000058B90BFBE7 >> 128; + if (xSignifier & 0x4000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000002C5C85FDF3 >> 128; + if (xSignifier & 0x2000000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000162E42FEF9 >> 128; + if (xSignifier & 0x1000000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000B17217F7C >> 128; + if (xSignifier & 0x800000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000058B90BFBD >> 128; + if (xSignifier & 0x400000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000002C5C85FDE >> 128; + if (xSignifier & 0x200000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000162E42FEE >> 128; + if (xSignifier & 0x100000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000B17217F6 >> 128; + if (xSignifier & 0x80000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000058B90BFA >> 128; + if (xSignifier & 0x40000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000002C5C85FC >> 128; + if (xSignifier & 0x20000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000162E42FD >> 128; + if (xSignifier & 0x10000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000B17217E >> 128; + if (xSignifier & 0x8000000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000058B90BE >> 128; + if (xSignifier & 0x4000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000002C5C85E >> 128; + if (xSignifier & 0x2000000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000162E42E >> 128; + if (xSignifier & 0x1000000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000B17216 >> 128; + if (xSignifier & 0x800000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000058B90A >> 128; + if (xSignifier & 0x400000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000002C5C84 >> 128; + if (xSignifier & 0x200000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000162E41 >> 128; + if (xSignifier & 0x100000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000B1720 >> 128; + if (xSignifier & 0x80000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000058B8F >> 128; + if (xSignifier & 0x40000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000002C5C7 >> 128; + if (xSignifier & 0x20000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000162E3 >> 128; + if (xSignifier & 0x10000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000B171 >> 128; + if (xSignifier & 0x8000 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000058B8 >> 128; + if (xSignifier & 0x4000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000002C5B >> 128; + if (xSignifier & 0x2000 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000162D >> 128; + if (xSignifier & 0x1000 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000B16 >> 128; + if (xSignifier & 0x800 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000058A >> 128; + if (xSignifier & 0x400 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000002C4 >> 128; + if (xSignifier & 0x200 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000161 >> 128; + if (xSignifier & 0x100 > 0) resultSignifier = resultSignifier * 0x1000000000000000000000000000000B0 >> 128; + if (xSignifier & 0x80 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000057 >> 128; + if (xSignifier & 0x40 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000002B >> 128; + if (xSignifier & 0x20 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000015 >> 128; + if (xSignifier & 0x10 > 0) resultSignifier = resultSignifier * 0x10000000000000000000000000000000A >> 128; + if (xSignifier & 0x8 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000004 >> 128; + if (xSignifier & 0x4 > 0) resultSignifier = resultSignifier * 0x100000000000000000000000000000001 >> 128; + + if (!xNegative) { + resultSignifier = resultSignifier >> 15 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + resultExponent += 0x3FFF; + } else if (resultExponent <= 0x3FFE) { + resultSignifier = resultSignifier >> 15 & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF; + resultExponent = 0x3FFF - resultExponent; + } else { + resultSignifier = resultSignifier >> resultExponent - 16367; + resultExponent = 0; + } + + return bytes16 (uint128 (resultExponent << 112 | resultSignifier)); + } + } + } + + /** + * Calculate e^x. + * + * @param x quadruple precision number + * @return quadruple precision number + */ + function exp (bytes16 x) internal pure returns (bytes16) { + unchecked { + return pow_2 (mul (x, 0x3FFF71547652B82FE1777D0FFDA0D23A)); + } + } + + /** + * Get index of the most significant non-zero bit in binary representation of + * x. Reverts if x is zero. + * + * @return index of the most significant non-zero bit in binary representation + * of x + */ + function mostSignificantBit (uint256 x) private pure returns (uint256) { + unchecked { + require (x > 0); + + uint256 result = 0; + + if (x >= 0x100000000000000000000000000000000) { x >>= 128; result += 128; } + if (x >= 0x10000000000000000) { x >>= 64; result += 64; } + if (x >= 0x100000000) { x >>= 32; result += 32; } + if (x >= 0x10000) { x >>= 16; result += 16; } + if (x >= 0x100) { x >>= 8; result += 8; } + if (x >= 0x10) { x >>= 4; result += 4; } + if (x >= 0x4) { x >>= 2; result += 2; } + if (x >= 0x2) result += 1; // No need to shift x anymore + + return result; + } + } +} diff --git a/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/LICENSE.md b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/LICENSE.md new file mode 100644 index 0000000..838d74e --- /dev/null +++ b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/LICENSE.md @@ -0,0 +1,28 @@ +Copyright (c) 2019, [ABDK Consulting](https://abdk.consulting/) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software must + display the following acknowledgement: This product includes software + developed by ABDK Consulting. +4. Neither the name of ABDK Consulting nor the names of its contributors may be + used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ABDK CONSULTING ''AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL ABDK CONSULTING BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +OF SUCH DAMAGE. diff --git a/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/README.md b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/README.md new file mode 100644 index 0000000..d81e6cc --- /dev/null +++ b/lib/crytic/contracts/Math/ABDKMath64x64/abdk-libraries-solidity/README.md @@ -0,0 +1,22 @@ +ABDK Libraries for Solidity +=========================== + +Copyright (c) 2019, [ABDK Consulting](https://abdk.consulting/) + +All rights reserved. + +Math 64.64 +---------- + +Library of mathematical functions operating with signed 64.64-bit fixed point +numbers. + +\[ [documentation](ABDKMath64x64.md) | [source](ABDKMath64x64.sol) \] + +Math Quad +--------- + +Library of mathematical functions operating with IEEE 754 quadruple precision +(128 bit) floating point numbers. + +\[ [documentation](ABDKMathQuad.md) | [source](ABDKMathQuad.sol) \] diff --git a/lib/crytic/contracts/util/Hevm.sol b/lib/crytic/contracts/util/Hevm.sol new file mode 100644 index 0000000..c5f493c --- /dev/null +++ b/lib/crytic/contracts/util/Hevm.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.0; + +interface IHevm { + // Set block.timestamp to newTimestamp + function warp(uint256 newTimestamp) external; + + // Set block.number to newNumber + function roll(uint256 newNumber) external; + + // Loads a storage slot from an address + function load(address where, bytes32 slot) external returns (bytes32); + + // Stores a value to an address' storage slot + function store(address where, bytes32 slot, bytes32 value) external; + + // Signs data (privateKey, digest) => (r, v, s) + function sign(uint256 privateKey, bytes32 digest) external returns (uint8 r, bytes32 v, bytes32 s); + + // Gets address for a given private key + function addr(uint256 privateKey) external returns (address addr); + + // Performs a foreign function call via terminal + function ffi(string[] calldata inputs) external returns (bytes memory result); + + // Performs the next smart contract call with specified `msg.sender` + function prank(address newSender) external; +} + +IHevm constant hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); \ No newline at end of file diff --git a/lib/crytic/contracts/util/IERC20.sol b/lib/crytic/contracts/util/IERC20.sol new file mode 100644 index 0000000..bd0837a --- /dev/null +++ b/lib/crytic/contracts/util/IERC20.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom( + address from, + address to, + uint256 amount + ) external returns (bool); + + function decimals() external returns (uint8); +} diff --git a/lib/crytic/contracts/util/IERC4626.sol b/lib/crytic/contracts/util/IERC4626.sol new file mode 100644 index 0000000..a870049 --- /dev/null +++ b/lib/crytic/contracts/util/IERC4626.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IERC20.sol"; + +interface IERC4626 is IERC20 { + event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed caller, + address indexed receiver, + address indexed owner, + uint256 assets, + uint256 shares + ); + + function asset() external view returns (IERC20); + + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + function withdraw( + uint256 assets, + address receiver, + address owner + ) external returns (uint256 shares); + + function redeem( + uint256 shares, + address receiver, + address owner + ) external returns (uint256 assets); + + function totalAssets() external view returns (uint256); + + function convertToShares(uint256 assets) external view returns (uint256); + + function convertToAssets(uint256 shares) external view returns (uint256); + + function previewDeposit(uint256 assets) external view returns (uint256); + + function previewMint(uint256 shares) external view returns (uint256); + + function previewWithdraw(uint256 assets) external view returns (uint256); + + function previewRedeem(uint256 shares) external view returns (uint256); + + function maxDeposit(address) external view returns (uint256); + + function maxMint(address) external view returns (uint256); + + function maxWithdraw(address owner) external view returns (uint256); + + function maxRedeem(address owner) external view returns (uint256); +} \ No newline at end of file diff --git a/lib/crytic/contracts/util/PropertiesConstants.sol b/lib/crytic/contracts/util/PropertiesConstants.sol new file mode 100644 index 0000000..d16c509 --- /dev/null +++ b/lib/crytic/contracts/util/PropertiesConstants.sol @@ -0,0 +1,9 @@ +pragma solidity ^0.8.0; + +abstract contract PropertiesConstants { + // Constant echidna addresses + address constant USER1 = address(0x10000); + address constant USER2 = address(0x20000); + address constant USER3 = address(0x30000); + uint256 constant INITIAL_BALANCE = 1000e18; +} diff --git a/lib/crytic/contracts/util/PropertiesHelper.sol b/lib/crytic/contracts/util/PropertiesHelper.sol new file mode 100644 index 0000000..a9519fb --- /dev/null +++ b/lib/crytic/contracts/util/PropertiesHelper.sol @@ -0,0 +1,373 @@ +pragma solidity ^0.8.0; + +abstract contract PropertiesAsserts { + event LogUint256(string,uint256); + event LogAddress(string, address); + event LogString(string); + + event AssertFail(string); + event AssertEqFail(string); + event AssertNeqFail(string); + event AssertGteFail(string); + event AssertGtFail(string); + event AssertLteFail(string); + event AssertLtFail(string); + + function assertWithMsg(bool b, string memory reason) internal { + if(!b){ + emit AssertFail(reason); + assert(false); + } + } + + /// @notice asserts that a is equal to b. Violations are logged using reason. + function assertEq(uint256 a, uint256 b, string memory reason) internal { + if(a != b){ + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,"!=",bStr,", reason: ", reason); + emit AssertEqFail(string(assertMsg)); + assert(false); + } + } + + /// @notice int256 version of assertEq + function assertEq(int256 a, int256 b, string memory reason) internal { + if(a != b){ + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,"!=",bStr,", reason: ", reason); + emit AssertEqFail(string(assertMsg)); + assert(false); + } + } + + /// @notice asserts that a is not equal to b. Violations are logged using reason. + function assertNeq(uint256 a, uint256 b, string memory reason) internal { + if(a == b){ + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,"==",bStr,", reason: ", reason); + emit AssertNeqFail(string(assertMsg)); + assert(false); + } + } + + /// @notice int256 version of assertNeq + function assertNeq(int256 a, int256 b, string memory reason) internal { + if(a == b){ + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,"==",bStr,", reason: ", reason); + emit AssertNeqFail(string(assertMsg)); + assert(false); + } + } + + /// @notice asserts that a is greater than or equal to b. Violations are logged using reason. + function assertGte(uint256 a, uint256 b, string memory reason) internal { + if(!(a >= b)) { + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,"<",bStr," failed, reason: ", reason); + emit AssertGteFail(string(assertMsg)); + assert(false); + } + } + + /// @notice int256 version of assertGte + function assertGte(int256 a, int256 b, string memory reason) internal { + if(!(a >= b)) { + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,"<",bStr," failed, reason: ", reason); + emit AssertGteFail(string(assertMsg)); + assert(false); + } + } + + /// @notice asserts that a is greater than b. Violations are logged using reason. + function assertGt(uint256 a, uint256 b, string memory reason) internal { + if(!(a > b)) { + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,"<=", bStr," failed, reason: ", reason); + emit AssertGtFail(string(assertMsg)); + assert(false); + } + } + + /// @notice int256 version of assertGt + function assertGt(int256 a, int256 b, string memory reason) internal { + if(!(a > b)) { + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,"<=", bStr," failed, reason: ", reason); + emit AssertGtFail(string(assertMsg)); + assert(false); + } + } + + /// @notice asserts that a is less than or equal to b. Violations are logged using reason. + function assertLte(uint256 a, uint256 b, string memory reason) internal { + if(!(a <= b)) { + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,">", bStr," failed, reason: ", reason); + emit AssertLteFail(string(assertMsg)); + assert(false); + } + } + + /// @notice int256 version of assertLte + function assertLte(int256 a, int256 b, string memory reason) internal { + if(!(a <= b)) { + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,">", bStr," failed, reason: ", reason); + emit AssertLteFail(string(assertMsg)); + assert(false); + } + } + + /// @notice asserts that a is less than b. Violations are logged using reason. + function assertLt(uint256 a, uint256 b, string memory reason) internal { + if(!(a < b)) { + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,">=",bStr," failed, reason: ", reason); + emit AssertLtFail(string(assertMsg)); + assert(false); + } + } + + /// @notice int256 version of assertLt + function assertLt(int256 a, int256 b, string memory reason) internal { + if(!(a < b)) { + string memory aStr = PropertiesLibString.toString(a); + string memory bStr = PropertiesLibString.toString(b); + bytes memory assertMsg = abi.encodePacked("Invalid: ", aStr,">=",bStr," failed, reason: ", reason); + emit AssertLtFail(string(assertMsg)); + assert(false); + } + } + + /// @notice Clamps value to be between low and high, both inclusive + function clampBetween(uint256 value, uint256 low, uint256 high) internal returns (uint256) { + if(value < low || value > high) { + uint ans = low + (value % (high - low + 1)); + string memory valueStr = PropertiesLibString.toString(value); + string memory ansStr = PropertiesLibString.toString(ans); + bytes memory message = abi.encodePacked("Clamping value ", valueStr, " to ", ansStr); + emit LogString(string(message)); + return ans; + } + return value; + } + + /// @notice int256 version of clampBetween + function clampBetween(int256 value, int256 low, int256 high) internal returns (int256) { + if(value < low || value > high) { + int range = high - low + 1; + int clamped = (value - low) % (range); + if (clamped < 0) clamped += range; + int ans = low + clamped; + string memory valueStr = PropertiesLibString.toString(value); + string memory ansStr = PropertiesLibString.toString(ans); + bytes memory message = abi.encodePacked("Clamping value ", valueStr, " to ", ansStr); + emit LogString(string(message)); + return ans; + } + return value; + } + + /// @notice clamps a to be less than b + function clampLt(uint256 a, uint256 b) internal returns (uint256){ + if ( !(a < b)) { + assertNeq(b, 0, "clampLt cannot clamp value a to be less than zero. Check your inputs/assumptions."); + uint256 value = a % b; + string memory aStr = PropertiesLibString.toString(a); + string memory valueStr = PropertiesLibString.toString(value); + bytes memory message = abi.encodePacked("Clamping value ", aStr, " to ", valueStr); + emit LogString(string(message)); + return value; + } + return a; + } + + /// @notice int256 version of clampLt + function clampLt(int256 a, int256 b) internal returns (int256){ + if ( !(a < b)) { + int256 value = b-1; + string memory aStr = PropertiesLibString.toString(a); + string memory valueStr = PropertiesLibString.toString(value); + bytes memory message = abi.encodePacked("Clamping value ", aStr, " to ", valueStr); + emit LogString(string(message)); + return value; + } + return a; + } + + /// @notice clamps a to be less than or equal to b + function clampLte(uint256 a, uint256 b) internal returns (uint256) { + if(!(a <= b)) { + uint256 value = a % (b+1); + string memory aStr = PropertiesLibString.toString(a); + string memory valueStr = PropertiesLibString.toString(value); + bytes memory message = abi.encodePacked("Clamping value ", aStr, " to ", valueStr); + emit LogString(string(message)); + return value; + } + return a; + } + + /// @notice int256 version of clampLte + function clampLte(int256 a, int256 b) internal returns (int256) { + if(!(a <= b)) { + int256 value = b; + string memory aStr = PropertiesLibString.toString(a); + string memory valueStr = PropertiesLibString.toString(value); + bytes memory message = abi.encodePacked("Clamping value ", aStr, " to ", valueStr); + emit LogString(string(message)); + return value; + } + return a; + } + + /// @notice clamps a to be greater than b + function clampGt(uint256 a, uint256 b) internal returns (uint256) { + if(!(a > b)){ + assertNeq(b, type(uint256).max, "clampGt cannot clamp value a to be larger than uint256.max. Check your inputs/assumptions."); + uint256 value = b+1; + string memory aStr = PropertiesLibString.toString(a); + string memory valueStr = PropertiesLibString.toString(value); + bytes memory message = abi.encodePacked("Clamping value ", aStr, " to ", valueStr); + emit LogString(string(message)); + return value; + } else { + return a; + } + } + + /// @notice int256 version of clampGt + function clampGt(int256 a, int256 b) internal returns (int256) { + if(!(a > b)){ + int256 value = b+1; + string memory aStr = PropertiesLibString.toString(a); + string memory valueStr = PropertiesLibString.toString(value); + bytes memory message = abi.encodePacked("Clamping value ", aStr, " to ", valueStr); + emit LogString(string(message)); + return value; + } else { + return a; + } + } + + /// @notice clamps a to be greater than or equal to b + function clampGte(uint256 a, uint256 b) internal returns (uint256) { + if(!(a > b)){ + uint256 value = b; + string memory aStr = PropertiesLibString.toString(a); + string memory valueStr = PropertiesLibString.toString(value); + bytes memory message = abi.encodePacked("Clamping value ", aStr, " to ", valueStr); + emit LogString(string(message)); + return value; + } + return a; + } + + /// @notice int256 version of clampGte + function clampGte(int256 a, int256 b) internal returns (int256) { + if(!(a > b)){ + int256 value = b; + string memory aStr = PropertiesLibString.toString(a); + string memory valueStr = PropertiesLibString.toString(value); + bytes memory message = abi.encodePacked("Clamping value ", aStr, " to ", valueStr); + emit LogString(string(message)); + return value; + } + return a; + } +} + +/// @notice Efficient library for creating string representations of integers. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) +/// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibString.sol) +/// @dev Name of the library is modified to prevent collisions with contract-under-test uses of LibString +library PropertiesLibString { + + function toString(int256 value) internal pure returns (string memory str) { + uint256 absValue = value >= 0 ? uint256(value) : uint256(-value); + str = toString(absValue); + + if(value < 0) { + str = string(abi.encodePacked("-", str)); + } + } + + function toString(uint256 value) internal pure returns (string memory str) { + /// @solidity memory-safe-assembly + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), but we allocate 160 bytes + // to keep the free memory pointer word aligned. We'll need 1 word for the length, 1 word for the + // trailing zeros padding, and 3 other words for a max of 78 digits. In total: 5 * 32 = 160 bytes. + let newFreeMemoryPointer := add(mload(0x40), 160) + + // Update the free memory pointer to avoid overriding our string. + mstore(0x40, newFreeMemoryPointer) + + // Assign str to the end of the zone of newly allocated memory. + str := sub(newFreeMemoryPointer, 32) + + // Clean the last word of memory it may not be overwritten. + mstore(str, 0) + + // Cache the end of the memory to calculate the length later. + let end := str + + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // prettier-ignore + for { let temp := value } 1 {} { + // Move the pointer 1 byte to the left. + str := sub(str, 1) + + // Write the character to the pointer. + // The ASCII index of the '0' character is 48. + mstore8(str, add(48, mod(temp, 10))) + + // Keep dividing temp until zero. + temp := div(temp, 10) + + // prettier-ignore + if iszero(temp) { break } + } + + // Compute and cache the final total length of the string. + let length := sub(end, str) + + // Move the pointer 32 bytes leftwards to make room for the length. + str := sub(str, 32) + + // Store the string's length at the start of memory allocated for our string. + mstore(str, length) + } + } + + function toString(address value) internal pure returns (string memory str){ + bytes memory s = new bytes(40); + for (uint i = 0; i < 20; i++) { + bytes1 b = bytes1(uint8(uint(uint160(value)) / (2**(8*(19 - i))))); + bytes1 hi = bytes1(uint8(b) / 16); + bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi)); + s[2*i] = char(hi); + s[2*i+1] = char(lo); + } + return string(s); + } + + function char(bytes1 b) internal pure returns (bytes1 c) { + if (uint8(b) < 10) return bytes1(uint8(b) + 0x30); + else return bytes1(uint8(b) + 0x57); + } +} diff --git a/lib/crytic/foundry.toml b/lib/crytic/foundry.toml new file mode 100644 index 0000000..0b6dcff --- /dev/null +++ b/lib/crytic/foundry.toml @@ -0,0 +1,6 @@ +[profile.default] +src = 'contracts' +out = 'out' +libs = ['lib'] + +# See more config options https://github.com/foundry-rs/foundry/tree/master/config \ No newline at end of file diff --git a/lib/crytic/hardhat.config.js b/lib/crytic/hardhat.config.js new file mode 100644 index 0000000..ea07066 --- /dev/null +++ b/lib/crytic/hardhat.config.js @@ -0,0 +1,45 @@ +const urlOverride = process.env.ETH_PROVIDER_URL; +const chainId = parseInt(process.env.CHAIN_ID ?? "31337", 10); + +module.exports = { + paths: { + artifacts: "./artifacts", + sources: "./contracts", + tests: "./tests", + }, + solidity: { + compilers: [ + { + version: "0.8.1", + settings: { + optimizer: { + enabled: true, + runs: 200 + } + } + }, + { + version: "0.8.17", + settings: { + optimizer: { + enabled: true, + runs: 200 + } + } + }, + + ], + }, + defaultNetwork: "hardhat", + networks: { + hardhat: { + chainId, + loggingEnabled: false, + saveDeployments: false, + }, + localhost: { + chainId, + url: urlOverride || "http://localhost:8545", + }, + }, +}; diff --git a/lib/crytic/lib/ERC4626/.gitattributes b/lib/crytic/lib/ERC4626/.gitattributes new file mode 100644 index 0000000..c2b17bf --- /dev/null +++ b/lib/crytic/lib/ERC4626/.gitattributes @@ -0,0 +1 @@ +*.vy linguist-language=Python diff --git a/lib/crytic/lib/ERC4626/.github/workflows/test.yaml b/lib/crytic/lib/ERC4626/.github/workflows/test.yaml new file mode 100644 index 0000000..886b243 --- /dev/null +++ b/lib/crytic/lib/ERC4626/.github/workflows/test.yaml @@ -0,0 +1,12 @@ +on: ["push", "pull_request"] + +name: Test + +jobs: + functional: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: ApeWorX/github-action@v1 + - run: ape compile --size + - run: ape test -s diff --git a/lib/crytic/lib/ERC4626/.gitignore b/lib/crytic/lib/ERC4626/.gitignore new file mode 100644 index 0000000..7253877 --- /dev/null +++ b/lib/crytic/lib/ERC4626/.gitignore @@ -0,0 +1,132 @@ +# Auto-generated +hardhat.config.js + +.build/ +contracts/.cache/ +*.swp +**/.DS_Store + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# setuptools-scm +version.py + +# Ape stuff +.build/ + +# IDEs stuff +.vscode diff --git a/lib/crytic/lib/ERC4626/README.md b/lib/crytic/lib/ERC4626/README.md new file mode 100644 index 0000000..43a7d92 --- /dev/null +++ b/lib/crytic/lib/ERC4626/README.md @@ -0,0 +1,3 @@ +# EIP-4626 Demo Implementation in Vyper + +See [EIP-4626](https://eips.ethereum.org/EIPS/eip-4626) for more details. diff --git a/lib/crytic/lib/ERC4626/ape-config.yaml b/lib/crytic/lib/ERC4626/ape-config.yaml new file mode 100644 index 0000000..00426e8 --- /dev/null +++ b/lib/crytic/lib/ERC4626/ape-config.yaml @@ -0,0 +1,18 @@ +plugins: +- name: vyper +- name: solidity + +dependencies: + - name: OpenZeppelin + github: OpenZeppelin/openzeppelin-contracts + version: 4.7.3 + +solidity: + import_remapping: + - "@OpenZeppelin=OpenZeppelin/4.7.3" + +test: + gas: + exclude: + - contract_name: Token + - method_name: DEBUG_* diff --git a/lib/crytic/lib/ERC4626/contracts/ERC4626.json b/lib/crytic/lib/ERC4626/contracts/ERC4626.json new file mode 100644 index 0000000..6cee256 --- /dev/null +++ b/lib/crytic/lib/ERC4626/contracts/ERC4626.json @@ -0,0 +1,249 @@ +[{ + "name": "asset", + "type": "function", + "stateMutability": "view", + "inputs": [], + "outputs": [{ + "name": "assetTokenAddress", + "type": "address" + }] +}, { + "name": "totalAssets", + "type": "function", + "stateMutability": "view", + "inputs": [], + "outputs": [{ + "name": "totalManagedAssets", + "type": "uint256" + }] +}, { + "name": "convertToShares", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "assets", + "type": "uint256" + }], + "outputs": [{ + "name": "shares", + "type": "uint256" + }] +}, { + "name": "convertToAssets", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "shares", + "type": "uint256" + }], + "outputs": [{ + "name": "assets", + "type": "uint256" + }] +}, { + "name": "maxDeposit", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "receiver", + "type": "address" + }], + "outputs": [{ + "name": "maxAssets", + "type": "uint256" + }] +}, { + "name": "previewDeposit", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "assets", + "type": "uint256" + }], + "outputs": [{ + "name": "shares", + "type": "uint256" + }] +}, { + "name": "deposit", + "type": "function", + "stateMutability": "nonpayable", + "inputs": [{ + "name": "assets", + "type": "uint256" + }, { + "name": "receiver", + "type": "address" + }], + "outputs": [{ + "name": "shares", + "type": "uint256" + }] +}, { + "name": "maxMint", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "receiver", + "type": "address" + }], + "outputs": [{ + "name": "maxShares", + "type": "uint256" + }] +}, { + "name": "previewMint", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "shares", + "type": "uint256" + }], + "outputs": [{ + "name": "assets", + "type": "uint256" + }] +}, { + "name": "mint", + "type": "function", + "stateMutability": "nonpayable", + "inputs": [{ + "name": "shares", + "type": "uint256" + }, { + "name": "receiver", + "type": "address" + }], + "outputs": [{ + "name": "assets", + "type": "uint256" + }] +}, { + "name": "maxWithdraw", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "owner", + "type": "address" + }], + "outputs": [{ + "name": "maxAssets", + "type": "uint256" + }] +}, { + "name": "previewWithdraw", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "assets", + "type": "uint256" + }], + "outputs": [{ + "name": "shares", + "type": "uint256" + }] +}, { + "name": "withdraw", + "type": "function", + "stateMutability": "nonpayable", + "inputs": [{ + "name": "assets", + "type": "uint256" + }, { + "name": "receiver", + "type": "address" + }, { + "name": "owner", + "type": "address" + }], + "outputs": [{ + "name": "shares", + "type": "uint256" + }] +}, { + "name": "maxRedeem", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "owner", + "type": "address" + }], + "outputs": [{ + "name": "maxShares", + "type": "uint256" + }] +}, { + "name": "previewRedeem", + "type": "function", + "stateMutability": "view", + "inputs": [{ + "name": "shares", + "type": "uint256" + }], + "outputs": [{ + "name": "assets", + "type": "uint256" + }] +}, { + "name": "redeem", + "type": "function", + "stateMutability": "nonpayable", + "inputs": [{ + "name": "shares", + "type": "uint256" + }, { + "name": "receiver", + "type": "address" + }, { + "name": "owner", + "type": "address" + }], + "outputs": [{ + "name": "assets", + "type": "uint256" + }] +}, { + "name": "Deposit", + "type": "event", + "inputs": [{ + "name": "_caller", + "indexed": true, + "type": "address" + }, { + "name": "owner", + "indexed": true, + "type": "address" + }, { + "name": "assets", + "indexed": false, + "type": "uint256" + }, { + "name": "shares", + "indexed": false, + "type": "uint256" + }] +}, { + "name": "Withdraw", + "type": "event", + "inputs": [{ + "name": "_caller", + "indexed": true, + "type": "address" + }, { + "name": "receiver", + "indexed": true, + "type": "address" + }, { + "name": "owner", + "indexed": true, + "type": "address" + }, { + "name": "assets", + "indexed": false, + "type": "uint256" + }, { + "name": "shares", + "indexed": false, + "type": "uint256" + }] +}] \ No newline at end of file diff --git a/lib/crytic/lib/ERC4626/contracts/ERC4626.sol b/lib/crytic/lib/ERC4626/contracts/ERC4626.sol new file mode 100644 index 0000000..cf99027 --- /dev/null +++ b/lib/crytic/lib/ERC4626/contracts/ERC4626.sol @@ -0,0 +1,20 @@ +interface IERC4626 { + function asset() external view returns (address assetTokenAddress); + function totalAssets() external view returns (uint256 totalManagedAssets); + function convertToShares(uint256 assets) external view returns (uint256 shares); + function convertToAssets(uint256 shares) external view returns (uint256 assets); + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + function previewDeposit(uint256 assets) external view returns (uint256 shares); + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + function maxMint(address receiver) external view returns (uint256 maxShares); + function previewMint(uint256 shares) external view returns (uint256 assets); + function mint(uint256 shares, address receiver) external returns (uint256 assets); + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + function maxRedeem(address owner) external view returns (uint256 maxShares); + function previewRedeem(uint256 shares) external view returns (uint256 assets); + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); + event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); + event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares); +} diff --git a/lib/crytic/lib/ERC4626/contracts/SolidityVault.sol b/lib/crytic/lib/ERC4626/contracts/SolidityVault.sol new file mode 100644 index 0000000..e03a464 --- /dev/null +++ b/lib/crytic/lib/ERC4626/contracts/SolidityVault.sol @@ -0,0 +1,158 @@ +pragma solidity ^0.8; + +import { IERC4626 } from "ERC4626.sol"; +import { ERC20 } from "@OpenZeppelin/token/ERC20/ERC20.sol"; + +contract SolidityVault is IERC4626, ERC20 { + address public asset; + + constructor(address _asset) ERC20("Test Vault", "vTEST") { + asset = _asset; + } + + function totalAssets() public view returns (uint256) { + return ERC20(asset).balanceOf(address(this)); + } + + function convertToAssets(uint256 shares) public view returns (uint256) { + uint256 _totalSupply = totalSupply(); + if (_totalSupply == 0) return 0; + return shares * totalAssets() / _totalSupply; + } + + function convertToShares(uint256 assets) public view returns (uint256) { + uint256 _totalSupply = totalSupply(); + uint256 _totalAssets = totalAssets(); + if (_totalAssets == 0 || _totalSupply == 0) return assets; + return assets * _totalSupply / _totalAssets; + } + + function maxDeposit(address receiver) external view returns (uint256) { + return type(uint256).max; + } + + function previewDeposit(uint256 assets) external view returns (uint256) { + return convertToShares(assets); + } + + function deposit(uint256 assets, address receiver) public returns (uint256) { + uint256 shares = convertToShares(assets); + ERC20(asset).transferFrom(msg.sender, address(this), assets); + + _mint(receiver, shares); + emit Deposit(msg.sender, receiver, assets, shares); + + return shares; + } + + function deposit(uint256 assets) external returns (uint256) { + return deposit(assets, msg.sender); + } + + function maxMint(address receiver) external view returns (uint256) { + return type(uint256).max; + } + + function previewMint(uint256 shares) external view returns (uint256) { + uint256 assets = convertToAssets(shares); + if (assets == 0 && totalAssets() == 0) return shares; + return assets; + } + + function mint(uint256 shares, address receiver) public returns (uint256) { + uint256 assets = convertToAssets(shares); + + if (totalAssets() == 0) assets = shares; + + ERC20(asset).transferFrom(msg.sender, address(this), assets); + + _mint(receiver, shares); + emit Deposit(msg.sender, receiver, assets, shares); + + return assets; + } + + function mint(uint256 shares) external returns (uint256) { + return mint(shares, msg.sender); + } + + function maxWithdraw(address owner) external view returns (uint256) { + return type(uint256).max; + } + + function previewWithdraw(uint256 assets) external view returns (uint256) { + uint256 shares = convertToShares(assets); + if (totalSupply() == 0) return 0; + return shares; + } + + function withdraw( + uint256 assets, + address receiver, + address owner + ) + public + returns (uint256) + { + uint256 shares = convertToShares(assets); + + if (owner != msg.sender) { + _spendAllowance(owner, msg.sender, shares); + } + _burn(owner, shares); + + ERC20(asset).transfer(receiver, assets); + emit Withdraw(msg.sender, receiver, owner, assets, shares); + + return shares; + } + + function withdraw(uint256 assets, address receiver) external returns (uint256) { + return withdraw(assets, receiver, msg.sender); + } + + function withdraw(uint256 assets) external returns (uint256) { + return withdraw(assets, msg.sender, msg.sender); + } + + function maxRedeem(address owner) external view returns (uint256) { + return type(uint256).max; + } + + function previewRedeem(uint256 shares) external view returns (uint256) { + return convertToAssets(shares); + } + + function redeem( + uint256 shares, + address receiver, + address owner + ) + public + returns (uint256) + { + uint256 assets = convertToAssets(shares); + + if (owner != msg.sender) { + _spendAllowance(owner, msg.sender, shares); + } + _burn(owner, shares); + + ERC20(asset).transfer(receiver, assets); + emit Withdraw(msg.sender, receiver, owner, assets, shares); + + return assets; + } + + function redeem(uint256 shares, address receiver) external returns (uint256) { + return redeem(shares, receiver, msg.sender); + } + + function redeem(uint256 shares) external returns (uint256) { + return redeem(shares, msg.sender, msg.sender); + } + + function DEBUG_steal_tokens(uint256 amount) external { + ERC20(asset).transfer(msg.sender, amount); + } +} diff --git a/lib/crytic/lib/ERC4626/contracts/VyperVault.vy b/lib/crytic/lib/ERC4626/contracts/VyperVault.vy new file mode 100644 index 0000000..d6ab773 --- /dev/null +++ b/lib/crytic/lib/ERC4626/contracts/VyperVault.vy @@ -0,0 +1,258 @@ +# @version 0.3.2 +from vyper.interfaces import ERC20 + +import ERC4626 as ERC4626 + +implements: ERC20 +implements: ERC4626 + +##### ERC20 ##### + +totalSupply: public(uint256) +balanceOf: public(HashMap[address, uint256]) +allowance: public(HashMap[address, HashMap[address, uint256]]) + +NAME: constant(String[10]) = "Test Vault" +SYMBOL: constant(String[5]) = "vTEST" +DECIMALS: constant(uint8) = 18 + +event Transfer: + sender: indexed(address) + receiver: indexed(address) + amount: uint256 + +event Approval: + owner: indexed(address) + spender: indexed(address) + allowance: uint256 + +##### ERC4626 ##### + +asset: public(ERC20) + +event Deposit: + depositor: indexed(address) + receiver: indexed(address) + assets: uint256 + shares: uint256 + +event Withdraw: + withdrawer: indexed(address) + receiver: indexed(address) + owner: indexed(address) + assets: uint256 + shares: uint256 + + +@external +def __init__(asset: ERC20): + self.asset = asset + + +@view +@external +def name() -> String[10]: + return NAME + + +@view +@external +def symbol() -> String[5]: + return SYMBOL + + +@view +@external +def decimals() -> uint8: + return DECIMALS + + +@external +def transfer(receiver: address, amount: uint256) -> bool: + self.balanceOf[msg.sender] -= amount + self.balanceOf[receiver] += amount + log Transfer(msg.sender, receiver, amount) + return True + + +@external +def approve(spender: address, amount: uint256) -> bool: + self.allowance[msg.sender][spender] = amount + log Approval(msg.sender, spender, amount) + return True + + +@external +def transferFrom(sender: address, receiver: address, amount: uint256) -> bool: + self.allowance[sender][msg.sender] -= amount + self.balanceOf[sender] -= amount + self.balanceOf[receiver] += amount + log Transfer(sender, receiver, amount) + return True + + +@view +@external +def totalAssets() -> uint256: + return self.asset.balanceOf(self) + + +@view +@internal +def _convertToAssets(shareAmount: uint256) -> uint256: + totalSupply: uint256 = self.totalSupply + if totalSupply == 0: + return 0 + + # NOTE: `shareAmount = 0` is extremely rare case, not optimizing for it + # NOTE: `totalAssets = 0` is extremely rare case, not optimizing for it + return shareAmount * self.asset.balanceOf(self) / totalSupply + + +@view +@external +def convertToAssets(shareAmount: uint256) -> uint256: + return self._convertToAssets(shareAmount) + + +@view +@internal +def _convertToShares(assetAmount: uint256) -> uint256: + totalSupply: uint256 = self.totalSupply + totalAssets: uint256 = self.asset.balanceOf(self) + if totalAssets == 0 or totalSupply == 0: + return assetAmount # 1:1 price + + # NOTE: `assetAmount = 0` is extremely rare case, not optimizing for it + return assetAmount * totalSupply / totalAssets + + +@view +@external +def convertToShares(assetAmount: uint256) -> uint256: + return self._convertToShares(assetAmount) + + +@view +@external +def maxDeposit(owner: address) -> uint256: + return MAX_UINT256 + + +@view +@external +def previewDeposit(assets: uint256) -> uint256: + return self._convertToShares(assets) + + +@external +def deposit(assets: uint256, receiver: address=msg.sender) -> uint256: + shares: uint256 = self._convertToShares(assets) + self.asset.transferFrom(msg.sender, self, assets) + + self.totalSupply += shares + self.balanceOf[receiver] += shares + log Deposit(msg.sender, receiver, assets, shares) + return shares + + +@view +@external +def maxMint(owner: address) -> uint256: + return MAX_UINT256 + + +@view +@external +def previewMint(shares: uint256) -> uint256: + assets: uint256 = self._convertToAssets(shares) + + # NOTE: Vyper does lazy eval on if, so this avoids SLOADs most of the time + if assets == 0 and self.asset.balanceOf(self) == 0: + return shares # NOTE: Assume 1:1 price if nothing deposited yet + + return assets + + +@external +def mint(shares: uint256, receiver: address=msg.sender) -> uint256: + assets: uint256 = self._convertToAssets(shares) + + if assets == 0 and self.asset.balanceOf(self) == 0: + assets = shares # NOTE: Assume 1:1 price if nothing deposited yet + + self.asset.transferFrom(msg.sender, self, assets) + + self.totalSupply += shares + self.balanceOf[receiver] += shares + log Deposit(msg.sender, receiver, assets, shares) + return assets + + +@view +@external +def maxWithdraw(owner: address) -> uint256: + return MAX_UINT256 # real max is `self.asset.balanceOf(self)` + + +@view +@external +def previewWithdraw(assets: uint256) -> uint256: + shares: uint256 = self._convertToShares(assets) + + # NOTE: Vyper does lazy eval on if, so this avoids SLOADs most of the time + if shares == assets and self.totalSupply == 0: + return 0 # NOTE: Nothing to redeem + + return shares + + +@external +def withdraw(assets: uint256, receiver: address=msg.sender, owner: address=msg.sender) -> uint256: + shares: uint256 = self._convertToShares(assets) + + # NOTE: Vyper does lazy eval on if, so this avoids SLOADs most of the time + if shares == assets and self.totalSupply == 0: + raise # Nothing to redeem + + if owner != msg.sender: + self.allowance[owner][msg.sender] -= shares + + self.totalSupply -= shares + self.balanceOf[owner] -= shares + + self.asset.transfer(receiver, assets) + log Withdraw(msg.sender, receiver, owner, assets, shares) + return shares + + +@view +@external +def maxRedeem(owner: address) -> uint256: + return MAX_UINT256 # real max is `self.totalSupply` + + +@view +@external +def previewRedeem(shares: uint256) -> uint256: + return self._convertToAssets(shares) + + +@external +def redeem(shares: uint256, receiver: address=msg.sender, owner: address=msg.sender) -> uint256: + if owner != msg.sender: + self.allowance[owner][msg.sender] -= shares + + assets: uint256 = self._convertToAssets(shares) + self.totalSupply -= shares + self.balanceOf[owner] -= shares + + self.asset.transfer(receiver, assets) + log Withdraw(msg.sender, receiver, owner, assets, shares) + return assets + + +@external +def DEBUG_steal_tokens(amount: uint256): + # NOTE: This is the primary method of mocking share price changes + self.asset.transfer(msg.sender, amount) diff --git a/lib/crytic/lib/ERC4626/contracts/test/Token.vy b/lib/crytic/lib/ERC4626/contracts/test/Token.vy new file mode 100644 index 0000000..7d76cfd --- /dev/null +++ b/lib/crytic/lib/ERC4626/contracts/test/Token.vy @@ -0,0 +1,70 @@ +# @version 0.3.1 +from vyper.interfaces import ERC20 + +implements: ERC20 + +totalSupply: public(uint256) +balanceOf: public(HashMap[address, uint256]) +allowance: public(HashMap[address, HashMap[address, uint256]]) + +NAME: constant(String[10]) = "Test Token" +SYMBOL: constant(String[4]) = "TEST" +DECIMALS: constant(uint8) = 18 + +event Transfer: + sender: indexed(address) + receiver: indexed(address) + amount: uint256 + +event Approval: + owner: indexed(address) + spender: indexed(address) + allowance: uint256 + + +@view +@external +def name() -> String[10]: + return NAME + + +@view +@external +def symbol() -> String[4]: + return SYMBOL + + +@view +@external +def decimals() -> uint8: + return DECIMALS + + +@external +def transfer(receiver: address, amount: uint256) -> bool: + self.balanceOf[msg.sender] -= amount + self.balanceOf[receiver] += amount + log Transfer(msg.sender, receiver, amount) + return True + + +@external +def approve(spender: address, amount: uint256) -> bool: + self.allowance[msg.sender][spender] = amount + log Approval(msg.sender, spender, amount) + return True + + +@external +def transferFrom(sender: address, receiver: address, amount: uint256) -> bool: + self.allowance[sender][msg.sender] -= amount + self.balanceOf[sender] -= amount + self.balanceOf[receiver] += amount + log Transfer(sender, receiver, amount) + return True + + +@external +def DEBUG_mint(receiver: address, amount: uint256): + self.balanceOf[receiver] += amount + self.totalSupply += amount diff --git a/lib/crytic/lib/ERC4626/requirements.txt b/lib/crytic/lib/ERC4626/requirements.txt new file mode 100644 index 0000000..adca816 --- /dev/null +++ b/lib/crytic/lib/ERC4626/requirements.txt @@ -0,0 +1,3 @@ +eth-ape>=0.5.4 +black +jsbeautifier diff --git a/lib/crytic/lib/ERC4626/scripts/make_interfaces.py b/lib/crytic/lib/ERC4626/scripts/make_interfaces.py new file mode 100644 index 0000000..0a8eae3 --- /dev/null +++ b/lib/crytic/lib/ERC4626/scripts/make_interfaces.py @@ -0,0 +1,70 @@ +import re +import yaml +import json +import requests +from pathlib import Path + +import jsbeautifier + + +ERC4626_URL = "https://raw.githubusercontent.com/ethereum/EIPs/master/EIPS/eip-4626.md" + + +def make_solidity_interface(spec): + interfaces = [] + for abi in spec: + if abi["type"] == "function": + inputs = ", ".join(f"{i['type']} {i['name']}" for i in abi["inputs"]) + interface = f"function {abi['name']}({inputs}) external" + if abi["stateMutability"] != "nonpayable": + interface += " " + abi["stateMutability"] + if "outputs" in abi: + outputs = ", ".join(f"{i['type']} {i['name']}" for i in abi["outputs"]) + interface += f" returns ({outputs})" + interfaces.append(interface) + + elif abi["type"] == "event": + inputs = ", ".join( + f"{i['type']} indexed {i['name']}" + if i["indexed"] + else f"{i['type']} {i['name']}" + for i in abi["inputs"] + ) + interface = f"event {abi['name']}({inputs})" + interfaces.append(interface) + + else: + raise Exception(f"Can't handle '{abi['type']}'") + return interfaces + + +def main(): + yaml_string = requests.get(ERC4626_URL).content.decode("utf-8") + yaml_sections = [ + s.split("```")[0] + for s in yaml_string.split("```yaml") + if "```" in s # Skip first section + ] + spec = yaml.safe_load("".join(yaml_sections)) + interface_file = Path("contracts") / "ERC4626.json" + print(f"Writing {interface_file}") + + opts = jsbeautifier.default_options() + opts.indent_size = 2 + interface_text = jsbeautifier.beautify(json.dumps(spec), opts) + # HACK: "caller" is illegal keyword in Vyper + interface_text = interface_text.replace("caller", "_caller") + interface_file.write_text(interface_text) + + # Write Solidity interface + interface_file = Path("contracts") / "ERC4626.sol" + print(f"Writing {interface_file}") + interface_file.write_text( + """interface IERC4626 {open} + {interfaces}; +{close}""".format( + open="{", + interfaces=";\n ".join(make_solidity_interface(spec)), + close="}", + ) + ) diff --git a/lib/crytic/lib/forge-std/.github/workflows/ci.yml b/lib/crytic/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..96b2336 --- /dev/null +++ b/lib/crytic/lib/forge-std/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + # Backwards compatibility checks. + - name: Check compatibility with 0.8.0 + if: always() + run: forge build --skip test --use solc:0.8.0 + + - name: Check compatibility with 0.7.6 + if: always() + run: forge build --skip test --use solc:0.7.6 + + - name: Check compatibility with 0.7.0 + if: always() + run: forge build --skip test --use solc:0.7.0 + + - name: Check compatibility with 0.6.12 + if: always() + run: forge build --skip test --use solc:0.6.12 + + - name: Check compatibility with 0.6.2 + if: always() + run: forge build --skip test --use solc:0.6.2 + + # via-ir compilation time checks. + - name: Measure compilation time of Test with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTest.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of TestBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTestBase.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of Script with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScript.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of ScriptBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScriptBase.sol --use solc:0.8.17 --via-ir + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Run tests + run: forge test -vvv + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Check formatting + run: forge fmt --check diff --git a/lib/crytic/lib/forge-std/.gitignore b/lib/crytic/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/lib/crytic/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/lib/crytic/lib/forge-std/.gitmodules b/lib/crytic/lib/forge-std/.gitmodules new file mode 100644 index 0000000..e124719 --- /dev/null +++ b/lib/crytic/lib/forge-std/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ds-test"] + path = lib/ds-test + url = https://github.com/dapphub/ds-test diff --git a/lib/crytic/lib/forge-std/LICENSE-APACHE b/lib/crytic/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/lib/crytic/lib/forge-std/LICENSE-APACHE @@ -0,0 +1,203 @@ +Copyright Contributors to Forge Standard Library + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/crytic/lib/forge-std/LICENSE-MIT b/lib/crytic/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/lib/crytic/lib/forge-std/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright Contributors to Forge Standard Library + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER +DEALINGS IN THE SOFTWARE.R diff --git a/lib/crytic/lib/forge-std/README.md b/lib/crytic/lib/forge-std/README.md new file mode 100644 index 0000000..8494a7d --- /dev/null +++ b/lib/crytic/lib/forge-std/README.md @@ -0,0 +1,250 @@ +# Forge Standard Library • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml) + +Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes. + +**Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).** + +## Install + +```bash +forge install foundry-rs/forge-std +``` + +## Contracts +### stdError + +This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors. + +See the contract itself for all error codes. + +#### Example usage + +```solidity + +import "forge-std/Test.sol"; + +contract TestContract is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } +} + +contract ErrorsTest { + function arithmeticError(uint256 a) public { + uint256 a = a - 100; + } +} +``` + +### stdStorage + +This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`). + +This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth. + +I.e.: +```solidity +struct T { + // depth 0 + uint256 a; + // depth 1 + uint256 b; +} +``` + +#### Example usage + +```solidity +import "forge-std/Test.sol"; + +contract TestContract is Test { + using stdStorage for StdStorage; + + Storage test; + + function setUp() public { + test = new Storage(); + } + + function testFindExists() public { + // Lets say we want to find the slot for the public + // variable `exists`. We just pass in the function selector + // to the `find` command + uint256 slot = stdstore.target(address(test)).sig("exists()").find(); + assertEq(slot, 0); + } + + function testWriteExists() public { + // Lets say we want to write to the slot for the public + // variable `exists`. We just pass in the function selector + // to the `checked_write` command + stdstore.target(address(test)).sig("exists()").checked_write(100); + assertEq(test.exists(), 100); + } + + // It supports arbitrary storage layouts, like assembly based storage locations + function testFindHidden() public { + // `hidden` is a random hash of a bytes, iteration through slots would + // not find it. Our mechanism does + // Also, you can use the selector instead of a string + uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find(); + assertEq(slot, uint256(keccak256("my.random.var"))); + } + + // If targeting a mapping, you have to pass in the keys necessary to perform the find + // i.e.: + function testFindMapping() public { + uint256 slot = stdstore + .target(address(test)) + .sig(test.map_addr.selector) + .with_key(address(this)) + .find(); + // in the `Storage` constructor, we wrote that this address' value was 1 in the map + // so when we load the slot, we expect it to be 1 + assertEq(uint(vm.load(address(test), bytes32(slot))), 1); + } + + // If the target is a struct, you can specify the field depth: + function testFindStruct() public { + // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc. + uint256 slot_for_a_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(0) + .find(); + + uint256 slot_for_b_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(1) + .find(); + + assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1); + assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2); + } +} + +// A complex storage contract +contract Storage { + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + constructor() { + map_addr[msg.sender] = 1; + } + + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + // mapping(address => Packed) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basicStruct = UnpackedStruct({ + a: 1, + b: 2 + }); + + function hidden() public view returns (bytes32 t) { + // an extremely hidden storage slot + bytes32 slot = keccak256("my.random.var"); + assembly { + t := sload(slot) + } + } +} +``` + +### stdCheats + +This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you. + + +#### Example usage: +```solidity + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +// Inherit the stdCheats +contract StdCheatsTest is Test { + Bar test; + function setUp() public { + test = new Bar(); + } + + function testHoax() public { + // we call `hoax`, which gives the target address + // eth and then calls `prank` + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + + // overloaded to allow you to specify how much eth to + // initialize the address with + hoax(address(1337), 1); + test.bar{value: 1}(address(1337)); + } + + function testStartHoax() public { + // we call `startHoax`, which gives the target address + // eth and then calls `startPrank` + // + // it is also overloaded so that you can specify an eth amount + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } +} + +contract Bar { + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } +} +``` + +### Std Assertions + +Expand upon the assertion functions from the `DSTest` library. + +### `console.log` + +Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log). +It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console2.sol"; +... +console2.log(someValue); +``` + +If you need compatibility with Hardhat, you must use the standard `console.sol` instead. +Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console.sol"; +... +console.log(someValue); +``` + +## License + +Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/lib/crytic/lib/forge-std/foundry.toml b/lib/crytic/lib/forge-std/foundry.toml new file mode 100644 index 0000000..36e4e63 --- /dev/null +++ b/lib/crytic/lib/forge-std/foundry.toml @@ -0,0 +1,21 @@ +[profile.default] +fs_permissions = [{ access = "read-write", path = "./"}] + +[rpc_endpoints] +# The RPC URLs are modified versions of the default for testing initialization. +mainnet = "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5" # Different API key. +optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash. +arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash. +needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}" + +[fmt] +# These are all the `forge fmt` defaults. +line_length = 120 +tab_width = 4 +bracket_spacing = false +int_types = 'long' +multiline_func_header = 'attributes_first' +quote_style = 'double' +number_underscore = 'preserve' +single_line_statement_blocks = 'preserve' +ignore = ["src/console.sol", "src/console2.sol"] \ No newline at end of file diff --git a/lib/crytic/lib/forge-std/lib/ds-test/.gitignore b/lib/crytic/lib/forge-std/lib/ds-test/.gitignore new file mode 100644 index 0000000..63f0b2c --- /dev/null +++ b/lib/crytic/lib/forge-std/lib/ds-test/.gitignore @@ -0,0 +1,3 @@ +/.dapple +/build +/out diff --git a/lib/crytic/lib/forge-std/lib/ds-test/LICENSE b/lib/crytic/lib/forge-std/lib/ds-test/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib/crytic/lib/forge-std/lib/ds-test/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/crytic/lib/forge-std/lib/ds-test/Makefile b/lib/crytic/lib/forge-std/lib/ds-test/Makefile new file mode 100644 index 0000000..661dac4 --- /dev/null +++ b/lib/crytic/lib/forge-std/lib/ds-test/Makefile @@ -0,0 +1,14 @@ +all:; dapp build + +test: + -dapp --use solc:0.4.23 build + -dapp --use solc:0.4.26 build + -dapp --use solc:0.5.17 build + -dapp --use solc:0.6.12 build + -dapp --use solc:0.7.5 build + +demo: + DAPP_SRC=demo dapp --use solc:0.7.5 build + -hevm dapp-test --verbose 3 + +.PHONY: test demo diff --git a/lib/crytic/lib/forge-std/lib/ds-test/default.nix b/lib/crytic/lib/forge-std/lib/ds-test/default.nix new file mode 100644 index 0000000..cf65419 --- /dev/null +++ b/lib/crytic/lib/forge-std/lib/ds-test/default.nix @@ -0,0 +1,4 @@ +{ solidityPackage, dappsys }: solidityPackage { + name = "ds-test"; + src = ./src; +} diff --git a/lib/crytic/lib/forge-std/lib/ds-test/demo/demo.sol b/lib/crytic/lib/forge-std/lib/ds-test/demo/demo.sol new file mode 100644 index 0000000..f3bb48e --- /dev/null +++ b/lib/crytic/lib/forge-std/lib/ds-test/demo/demo.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import "../src/test.sol"; + +contract DemoTest is DSTest { + function test_this() public pure { + require(true); + } + function test_logs() public { + emit log("-- log(string)"); + emit log("a string"); + + emit log("-- log_named_uint(string, uint)"); + emit log_named_uint("uint", 512); + + emit log("-- log_named_int(string, int)"); + emit log_named_int("int", -512); + + emit log("-- log_named_address(string, address)"); + emit log_named_address("address", address(this)); + + emit log("-- log_named_bytes32(string, bytes32)"); + emit log_named_bytes32("bytes32", "a string"); + + emit log("-- log_named_bytes(string, bytes)"); + emit log_named_bytes("bytes", hex"cafefe"); + + emit log("-- log_named_string(string, string)"); + emit log_named_string("string", "a string"); + + emit log("-- log_named_decimal_uint(string, uint, uint)"); + emit log_named_decimal_uint("decimal uint", 1.0e18, 18); + + emit log("-- log_named_decimal_int(string, int, uint)"); + emit log_named_decimal_int("decimal int", -1.0e18, 18); + } + event log_old_named_uint(bytes32,uint); + function test_old_logs() public { + emit log_old_named_uint("key", 500); + emit log_named_bytes32("bkey", "val"); + } + function test_trace() public view { + this.echo("string 1", "string 2"); + } + function test_multiline() public { + emit log("a multiline\\nstring"); + emit log("a multiline string"); + emit log_bytes("a string"); + emit log_bytes("a multiline\nstring"); + emit log_bytes("a multiline\\nstring"); + emit logs(hex"0000"); + emit log_named_bytes("0x0000", hex"0000"); + emit logs(hex"ff"); + } + function echo(string memory s1, string memory s2) public pure + returns (string memory, string memory) + { + return (s1, s2); + } + + function prove_this(uint x) public { + emit log_named_uint("sym x", x); + assertGt(x + 1, 0); + } + + function test_logn() public { + assembly { + log0(0x01, 0x02) + log1(0x01, 0x02, 0x03) + log2(0x01, 0x02, 0x03, 0x04) + log3(0x01, 0x02, 0x03, 0x04, 0x05) + } + } + + event MyEvent(uint, uint indexed, uint, uint indexed); + function test_events() public { + emit MyEvent(1, 2, 3, 4); + } + + function test_asserts() public { + string memory err = "this test has failed!"; + emit log("## assertTrue(bool)\n"); + assertTrue(false); + emit log("\n"); + assertTrue(false, err); + + emit log("\n## assertEq(address,address)\n"); + assertEq(address(this), msg.sender); + emit log("\n"); + assertEq(address(this), msg.sender, err); + + emit log("\n## assertEq32(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(uint,uint)\n"); + assertEq(uint(0), 1); + emit log("\n"); + assertEq(uint(0), 1, err); + + emit log("\n## assertEq(int,int)\n"); + assertEq(-1, -2); + emit log("\n"); + assertEq(-1, -2, err); + + emit log("\n## assertEqDecimal(int,int,uint)\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertEqDecimal(uint,uint,uint)\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGt(uint,uint)\n"); + assertGt(uint(0), 0); + emit log("\n"); + assertGt(uint(0), 0, err); + + emit log("\n## assertGt(int,int)\n"); + assertGt(-1, -1); + emit log("\n"); + assertGt(-1, -1, err); + + emit log("\n## assertGtDecimal(int,int,uint)\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGtDecimal(uint,uint,uint)\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGe(uint,uint)\n"); + assertGe(uint(0), 1); + emit log("\n"); + assertGe(uint(0), 1, err); + + emit log("\n## assertGe(int,int)\n"); + assertGe(-1, 0); + emit log("\n"); + assertGe(-1, 0, err); + + emit log("\n## assertGeDecimal(int,int,uint)\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGeDecimal(uint,uint,uint)\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertLt(uint,uint)\n"); + assertLt(uint(0), 0); + emit log("\n"); + assertLt(uint(0), 0, err); + + emit log("\n## assertLt(int,int)\n"); + assertLt(-1, -1); + emit log("\n"); + assertLt(-1, -1, err); + + emit log("\n## assertLtDecimal(int,int,uint)\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLtDecimal(uint,uint,uint)\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertLe(uint,uint)\n"); + assertLe(uint(1), 0); + emit log("\n"); + assertLe(uint(1), 0, err); + + emit log("\n## assertLe(int,int)\n"); + assertLe(0, -1); + emit log("\n"); + assertLe(0, -1, err); + + emit log("\n## assertLeDecimal(int,int,uint)\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLeDecimal(uint,uint,uint)\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertEq(string,string)\n"); + string memory s1 = "string 1"; + string memory s2 = "string 2"; + assertEq(s1, s2); + emit log("\n"); + assertEq(s1, s2, err); + + emit log("\n## assertEq0(bytes,bytes)\n"); + assertEq0(hex"abcdef01", hex"abcdef02"); + emit log("\n"); + assertEq0(hex"abcdef01", hex"abcdef02", err); + } +} + +contract DemoTestWithSetUp { + function setUp() public { + } + function test_pass() public pure { + } +} diff --git a/lib/crytic/lib/forge-std/lib/ds-test/package.json b/lib/crytic/lib/forge-std/lib/ds-test/package.json new file mode 100644 index 0000000..4802ada --- /dev/null +++ b/lib/crytic/lib/forge-std/lib/ds-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "ds-test", + "version": "1.0.0", + "description": "Assertions, equality checks and other test helpers ", + "bugs": "https://github.com/dapphub/ds-test/issues", + "license": "GPL-3.0", + "author": "Contributors to ds-test", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/dapphub/ds-test.git" + } +} diff --git a/lib/crytic/lib/forge-std/lib/ds-test/src/test.sol b/lib/crytic/lib/forge-std/lib/ds-test/src/test.sol new file mode 100644 index 0000000..515a3bd --- /dev/null +++ b/lib/crytic/lib/forge-std/lib/ds-test/src/test.sol @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.5.0; + +contract DSTest { + event log (string); + event logs (bytes); + + event log_address (address); + event log_bytes32 (bytes32); + event log_int (int); + event log_uint (uint); + event log_bytes (bytes); + event log_string (string); + + event log_named_address (string key, address val); + event log_named_bytes32 (string key, bytes32 val); + event log_named_decimal_int (string key, int val, uint decimals); + event log_named_decimal_uint (string key, uint val, uint decimals); + event log_named_int (string key, int val); + event log_named_uint (string key, uint val); + event log_named_bytes (string key, bytes val); + event log_named_string (string key, string val); + + bool public IS_TEST = true; + bool private _failed; + + address constant HEVM_ADDRESS = + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); + + modifier mayRevert() { _; } + modifier testopts(string memory) { _; } + + function failed() public returns (bool) { + if (_failed) { + return _failed; + } else { + bool globalFailed = false; + if (hasHEVMContext()) { + (, bytes memory retdata) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("load(address,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed")) + ) + ); + globalFailed = abi.decode(retdata, (bool)); + } + return globalFailed; + } + } + + function fail() internal { + if (hasHEVMContext()) { + (bool status, ) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("store(address,bytes32,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) + ) + ); + status; // Silence compiler warnings + } + _failed = true; + } + + function hasHEVMContext() internal view returns (bool) { + uint256 hevmCodeSize = 0; + assembly { + hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) + } + return hevmCodeSize > 0; + } + + modifier logs_gas() { + uint startGas = gasleft(); + _; + uint endGas = gasleft(); + emit log_named_uint("gas", startGas - endGas); + } + + function assertTrue(bool condition) internal { + if (!condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertTrue(bool condition, string memory err) internal { + if (!condition) { + emit log_named_string("Error", err); + assertTrue(condition); + } + } + + function assertEq(address a, address b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [address]"); + emit log_named_address(" Expected", b); + emit log_named_address(" Actual", a); + fail(); + } + } + function assertEq(address a, address b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes32 a, bytes32 b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [bytes32]"); + emit log_named_bytes32(" Expected", b); + emit log_named_bytes32(" Actual", a); + fail(); + } + } + function assertEq(bytes32 a, bytes32 b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + function assertEq32(bytes32 a, bytes32 b) internal { + assertEq(a, b); + } + function assertEq32(bytes32 a, bytes32 b, string memory err) internal { + assertEq(a, b, err); + } + + function assertEq(int a, int b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + function assertEq(int a, int b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEq(uint a, uint b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + function assertEq(uint a, uint b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEqDecimal(int a, int b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal int]"); + emit log_named_decimal_int(" Expected", b, decimals); + emit log_named_decimal_int(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + function assertEqDecimal(uint a, uint b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Expected", b, decimals); + emit log_named_decimal_uint(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + + function assertGt(uint a, uint b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGt(uint a, uint b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGt(int a, int b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGt(int a, int b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGtDecimal(int a, int b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + function assertGtDecimal(uint a, uint b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + + function assertGe(uint a, uint b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGe(uint a, uint b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGe(int a, int b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGe(int a, int b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGeDecimal(int a, int b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + function assertGeDecimal(uint a, uint b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertLt(uint a, uint b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLt(uint a, uint b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLt(int a, int b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLt(int a, int b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLtDecimal(int a, int b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + function assertLtDecimal(uint a, uint b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + + function assertLe(uint a, uint b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLe(uint a, uint b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLe(int a, int b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLe(int a, int b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLeDecimal(int a, int b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + function assertLeDecimal(uint a, uint b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log("Error: a == b not satisfied [string]"); + emit log_named_string(" Expected", b); + emit log_named_string(" Actual", a); + fail(); + } + } + function assertEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { + ok = true; + if (a.length == b.length) { + for (uint i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + ok = false; + } + } + } else { + ok = false; + } + } + function assertEq0(bytes memory a, bytes memory b) internal { + if (!checkEq0(a, b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + function assertEq0(bytes memory a, bytes memory b, string memory err) internal { + if (!checkEq0(a, b)) { + emit log_named_string("Error", err); + assertEq0(a, b); + } + } +} diff --git a/lib/crytic/lib/forge-std/package.json b/lib/crytic/lib/forge-std/package.json new file mode 100644 index 0000000..ccd8ad3 --- /dev/null +++ b/lib/crytic/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.4.0", + "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", + "homepage": "https://book.getfoundry.sh/forge/forge-std", + "bugs": "https://github.com/foundry-rs/forge-std/issues", + "license": "(Apache-2.0 OR MIT)", + "author": "Contributors to Forge Standard Library", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/foundry-rs/forge-std.git" + } +} diff --git a/lib/crytic/lib/forge-std/src/Base.sol b/lib/crytic/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..83c5c1c --- /dev/null +++ b/lib/crytic/lib/forge-std/src/Base.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {StdStorage} from "./StdStorage.sol"; +import {Vm, VmSafe} from "./Vm.sol"; + +abstract contract CommonBase { + // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. + address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + // console.sol and console2.sol work by executing a staticcall to this address. + address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; + // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38. + address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))); + // Address of the test contract, deployed by the DEFAULT_SENDER. + address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; + // Deterministic deployment address of the Multicall3 contract. + address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11; + + uint256 internal constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + Vm internal constant vm = Vm(VM_ADDRESS); + StdStorage internal stdstore; +} + +abstract contract TestBase is CommonBase {} + +abstract contract ScriptBase is CommonBase { + // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); +} diff --git a/lib/crytic/lib/forge-std/src/Script.sol b/lib/crytic/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..bffccad --- /dev/null +++ b/lib/crytic/lib/forge-std/src/Script.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Standard Library's default Script. + +// 🧩 MODULES +import {ScriptBase} from "./Base.sol"; +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheatsSafe} from "./StdCheats.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorageSafe} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {VmSafe} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {ScriptBase} from "./Base.sol"; + +// ⭐️ SCRIPT +abstract contract Script is StdChains, StdCheatsSafe, StdUtils, ScriptBase { + // Note: IS_SCRIPT() must return true. + bool public IS_SCRIPT = true; +} diff --git a/lib/crytic/lib/forge-std/src/StdAssertions.sol b/lib/crytic/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..af144a4 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {DSTest} from "ds-test/test.sol"; +import {stdMath} from "./StdMath.sol"; + +abstract contract StdAssertions is DSTest { + event log_array(uint256[] val); + event log_array(int256[] val); + event log_array(address[] val); + event log_named_array(string key, uint256[] val); + event log_named_array(string key, int256[] val); + event log_named_array(string key, address[] val); + + function fail(string memory err) internal virtual { + emit log_named_string("Error", err); + fail(); + } + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); + } + + function assertEq(bool a, bool b) internal virtual { + if (a != b) { + emit log("Error: a == b not satisfied [bool]"); + emit log_named_string(" Left", a ? "true" : "false"); + emit log_named_string(" Right", b ? "true" : "false"); + fail(); + } + } + + function assertEq(bool a, bool b, string memory err) internal virtual { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes memory a, bytes memory b) internal virtual { + assertEq0(a, b); + } + + function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { + assertEq0(a, b, err); + } + + function assertEq(uint256[] memory a, uint256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [uint[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(int256[] memory a, int256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [int[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(address[] memory a, address[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [address[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + // Legacy helper + function assertEqUint(uint256 a, uint256 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_decimal_uint(" Expected", b, decimals); + emit log_named_decimal_uint(" Actual", a, decimals); + emit log_named_decimal_uint(" Max Delta", maxDelta, decimals); + emit log_named_decimal_uint(" Delta", delta, decimals); + fail(); + } + } + + function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, string memory err) + internal + virtual + { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_decimal_int(" Expected", b, decimals); + emit log_named_decimal_int(" Actual", a, decimals); + emit log_named_decimal_uint(" Max Delta", maxDelta, decimals); + emit log_named_decimal_uint(" Delta", delta, decimals); + fail(); + } + } + + function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, string memory err) + internal + virtual + { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_decimal_uint(" Expected", b, decimals); + emit log_named_decimal_uint(" Actual", a, decimals); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_decimal_int(" Expected", b, decimals); + emit log_named_decimal_int(" Actual", a, decimals); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, string memory err) + internal + virtual + { + if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + } +} diff --git a/lib/crytic/lib/forge-std/src/StdChains.sol b/lib/crytic/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..b1f0e6d --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdChains.sol @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +/** + * StdChains provides information about EVM compatible chains that can be used in scripts/tests. + * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are + * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of + * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the + * alias used in this contract, which can be found as the first argument to the + * `setChainWithDefaultRpcUrl` call in the `initialize` function. + * + * There are two main ways to use this contract: + * 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or + * `setChain(string memory chainAlias, Chain memory chain)` + * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. + * + * The first time either of those are used, chains are initialized with the default set of RPC URLs. + * This is done in `initialize`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in + * `defaultRpcUrls`. + * + * The `setChain` function is straightforward, and it simply saves off the given chain data. + * + * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say + * we want to retrieve `mainnet`'s RPC URL: + * - If you haven't set any mainnet chain info with `setChain`, you haven't specified that + * chain in `foundry.toml` and no env var is set, the default data and RPC URL will be returned. + * - If you have set a mainnet RPC URL in `foundry.toml` it will return that, if valid (e.g. if + * a URL is given or if an environment variable is given and that environment variable exists). + * Otherwise, the default data is returned. + * - If you specified data with `setChain` it will return that. + * + * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults. + */ +abstract contract StdChains { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private initialized; + + struct ChainData { + string name; + uint256 chainId; + string rpcUrl; + } + + struct Chain { + // The chain name. + string name; + // The chain's Chain ID. + uint256 chainId; + // The chain's alias. (i.e. what gets specified in `foundry.toml`). + string chainAlias; + // A default RPC endpoint for this chain. + // NOTE: This default RPC URL is included for convenience to facilitate quick tests and + // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy + // usage as you will be throttled and this is a disservice to others who need this endpoint. + string rpcUrl; + } + + // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data. + mapping(string => Chain) private chains; + // Maps from the chain's alias to it's default RPC URL. + mapping(string => string) private defaultRpcUrls; + // Maps from a chain ID to it's alias. + mapping(uint256 => string) private idToAlias; + + bool private fallbackToDefaultRpcUrls = true; + + // The RPC URL will be fetched from config or defaultRpcUrls if possible. + function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) { + require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string."); + + initialize(); + chain = chains[chainAlias]; + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + function getChain(uint256 chainId) internal virtual returns (Chain memory chain) { + require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0."); + initialize(); + string memory chainAlias = idToAlias[chainId]; + + chain = chains[chainAlias]; + + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, ChainData memory chain) internal virtual { + require( + bytes(chainAlias).length != 0, + "StdChains setChain(string,ChainData): Chain alias cannot be the empty string." + ); + + require(chain.chainId != 0, "StdChains setChain(string,ChainData): Chain ID cannot be 0."); + + initialize(); + string memory foundAlias = idToAlias[chain.chainId]; + + require( + bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)), + string( + abi.encodePacked( + "StdChains setChain(string,ChainData): Chain ID ", + vm.toString(chain.chainId), + " already used by \"", + foundAlias, + "\"." + ) + ) + ); + + uint256 oldChainId = chains[chainAlias].chainId; + delete idToAlias[oldChainId]; + + chains[chainAlias] = + Chain({name: chain.name, chainId: chain.chainId, chainAlias: chainAlias, rpcUrl: chain.rpcUrl}); + idToAlias[chain.chainId] = chainAlias; + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, Chain memory chain) internal virtual { + setChain(chainAlias, ChainData({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl})); + } + + function _toUpper(string memory str) private pure returns (string memory) { + bytes memory strb = bytes(str); + bytes memory copy = new bytes(strb.length); + for (uint256 i = 0; i < strb.length; i++) { + bytes1 b = strb[i]; + if (b >= 0x61 && b <= 0x7A) { + copy[i] = bytes1(uint8(b) - 32); + } else { + copy[i] = b; + } + } + return string(copy); + } + + // lookup rpcUrl, in descending order of priority: + // current -> config (foundry.toml) -> environment variable -> default + function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) private returns (Chain memory) { + if (bytes(chain.rpcUrl).length == 0) { + try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) { + chain.rpcUrl = configRpcUrl; + } catch (bytes memory err) { + string memory envName = string(abi.encodePacked(_toUpper(chainAlias), "_RPC_URL")); + if (fallbackToDefaultRpcUrls) { + chain.rpcUrl = vm.envOr(envName, defaultRpcUrls[chainAlias]); + } else { + chain.rpcUrl = vm.envString(envName); + } + // distinguish 'not found' from 'cannot read' + bytes memory notFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + if (keccak256(notFoundError) != keccak256(err) || bytes(chain.rpcUrl).length == 0) { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, err), mload(err)) + } + } + } + } + return chain; + } + + function setFallbackToDefaultRpcUrls(bool useDefault) internal { + fallbackToDefaultRpcUrls = useDefault; + } + + function initialize() private { + if (initialized) return; + + initialized = true; + + // If adding an RPC here, make sure to test the default RPC URL in `testRpcs` + setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545")); + setChainWithDefaultRpcUrl( + "mainnet", ChainData("Mainnet", 1, "https://mainnet.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b") + ); + setChainWithDefaultRpcUrl( + "goerli", ChainData("Goerli", 5, "https://goerli.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b") + ); + setChainWithDefaultRpcUrl( + "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b") + ); + setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io")); + setChainWithDefaultRpcUrl("optimism_goerli", ChainData("Optimism Goerli", 420, "https://goerli.optimism.io")); + setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl( + "arbitrum_one_goerli", ChainData("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc") + ); + setChainWithDefaultRpcUrl("arbitrum_nova", ChainData("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl("polygon", ChainData("Polygon", 137, "https://polygon-rpc.com")); + setChainWithDefaultRpcUrl( + "polygon_mumbai", ChainData("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com") + ); + setChainWithDefaultRpcUrl("avalanche", ChainData("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc")); + setChainWithDefaultRpcUrl( + "avalanche_fuji", ChainData("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc") + ); + setChainWithDefaultRpcUrl( + "bnb_smart_chain", ChainData("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org") + ); + setChainWithDefaultRpcUrl( + "bnb_smart_chain_testnet", + ChainData("BNB Smart Chain Testnet", 97, "https://rpc.ankr.com/bsc_testnet_chapel") + ); + setChainWithDefaultRpcUrl("gnosis_chain", ChainData("Gnosis Chain", 100, "https://rpc.gnosischain.com")); + } + + // set chain info, with priority to chainAlias' rpc url in foundry.toml + function setChainWithDefaultRpcUrl(string memory chainAlias, ChainData memory chain) private { + string memory rpcUrl = chain.rpcUrl; + defaultRpcUrls[chainAlias] = rpcUrl; + chain.rpcUrl = ""; + setChain(chainAlias, chain); + chain.rpcUrl = rpcUrl; // restore argument + } +} diff --git a/lib/crytic/lib/forge-std/src/StdCheats.sol b/lib/crytic/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..356b9ee --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdCheats.sol @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {Vm} from "./Vm.sol"; + +abstract contract StdCheatsSafe { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private gasMeteringOff; + + // Data structures to parse Transaction objects from the broadcast artifact + // that conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawTx1559 { + string[] arguments; + address contractAddress; + string contractName; + // json value name = function + string functionSig; + bytes32 hash; + // json value name = tx + RawTx1559Detail txDetail; + // json value name = type + string opcode; + } + + struct RawTx1559Detail { + AccessList[] accessList; + bytes data; + address from; + bytes gas; + bytes nonce; + address to; + bytes txType; + bytes value; + } + + struct Tx1559 { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + bytes32 hash; + Tx1559Detail txDetail; + string opcode; + } + + struct Tx1559Detail { + AccessList[] accessList; + bytes data; + address from; + uint256 gas; + uint256 nonce; + address to; + uint256 txType; + uint256 value; + } + + // Data structures to parse Transaction objects from the broadcast artifact + // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct TxLegacy { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + string hash; + string opcode; + TxDetailLegacy transaction; + } + + struct TxDetailLegacy { + AccessList[] accessList; + uint256 chainId; + bytes data; + address from; + uint256 gas; + uint256 gasPrice; + bytes32 hash; + uint256 nonce; + bytes1 opcode; + bytes32 r; + bytes32 s; + uint256 txType; + address to; + uint8 v; + uint256 value; + } + + struct AccessList { + address accessAddress; + bytes32[] storageKeys; + } + + // Data structures to parse Receipt objects from the broadcast artifact. + // The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawReceipt { + bytes32 blockHash; + bytes blockNumber; + address contractAddress; + bytes cumulativeGasUsed; + bytes effectiveGasPrice; + address from; + bytes gasUsed; + RawReceiptLog[] logs; + bytes logsBloom; + bytes status; + address to; + bytes32 transactionHash; + bytes transactionIndex; + } + + struct Receipt { + bytes32 blockHash; + uint256 blockNumber; + address contractAddress; + uint256 cumulativeGasUsed; + uint256 effectiveGasPrice; + address from; + uint256 gasUsed; + ReceiptLog[] logs; + bytes logsBloom; + uint256 status; + address to; + bytes32 transactionHash; + uint256 transactionIndex; + } + + // Data structures to parse the entire broadcast artifact, assuming the + // transactions conform to EIP1559. + + struct EIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + Receipt[] receipts; + uint256 timestamp; + Tx1559[] transactions; + TxReturn[] txReturns; + } + + struct RawEIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + RawReceipt[] receipts; + TxReturn[] txReturns; + uint256 timestamp; + RawTx1559[] transactions; + } + + struct RawReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + bytes blockNumber; + bytes data; + bytes logIndex; + bool removed; + bytes32[] topics; + bytes32 transactionHash; + bytes transactionIndex; + bytes transactionLogIndex; + } + + struct ReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + uint256 blockNumber; + bytes data; + uint256 logIndex; + bytes32[] topics; + uint256 transactionIndex; + uint256 transactionLogIndex; + bool removed; + } + + struct TxReturn { + string internalType; + string value; + } + + function assumeNoPrecompiles(address addr) internal virtual { + // Assembly required since `block.chainid` was introduced in 0.8.0. + uint256 chainId; + assembly { + chainId := chainid() + } + assumeNoPrecompiles(addr, chainId); + } + + function assumeNoPrecompiles(address addr, uint256 chainId) internal pure virtual { + // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific + // address), but the same rationale for excluding them applies so we include those too. + + // These should be present on all EVM-compatible chains. + vm.assume(addr < address(0x1) || addr > address(0x9)); + + // forgefmt: disable-start + if (chainId == 10 || chainId == 420) { + // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21 + vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800)); + } else if (chainId == 42161 || chainId == 421613) { + // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains + vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068)); + } else if (chainId == 43114 || chainId == 43113) { + // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59 + vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff)); + vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF)); + vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff)); + } + // forgefmt: disable-end + } + + function readEIP1559ScriptArtifact(string memory path) + internal + view + virtual + returns (EIP1559ScriptArtifact memory) + { + string memory data = vm.readFile(path); + bytes memory parsedData = vm.parseJson(data); + RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact)); + EIP1559ScriptArtifact memory artifact; + artifact.libraries = rawArtifact.libraries; + artifact.path = rawArtifact.path; + artifact.timestamp = rawArtifact.timestamp; + artifact.pending = rawArtifact.pending; + artifact.txReturns = rawArtifact.txReturns; + artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts); + artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions); + return artifact; + } + + function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) { + Tx1559[] memory txs = new Tx1559[](rawTxs.length); + for (uint256 i; i < rawTxs.length; i++) { + txs[i] = rawToConvertedEIPTx1559(rawTxs[i]); + } + return txs; + } + + function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) { + Tx1559 memory transaction; + transaction.arguments = rawTx.arguments; + transaction.contractName = rawTx.contractName; + transaction.functionSig = rawTx.functionSig; + transaction.hash = rawTx.hash; + transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail); + transaction.opcode = rawTx.opcode; + return transaction; + } + + function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail) + internal + pure + virtual + returns (Tx1559Detail memory) + { + Tx1559Detail memory txDetail; + txDetail.data = rawDetail.data; + txDetail.from = rawDetail.from; + txDetail.to = rawDetail.to; + txDetail.nonce = _bytesToUint(rawDetail.nonce); + txDetail.txType = _bytesToUint(rawDetail.txType); + txDetail.value = _bytesToUint(rawDetail.value); + txDetail.gas = _bytesToUint(rawDetail.gas); + txDetail.accessList = rawDetail.accessList; + return txDetail; + } + + function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions"); + RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[])); + return rawToConvertedEIPTx1559s(rawTxs); + } + + function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559)); + return rawToConvertedEIPTx1559(rawTx); + } + + // Analogous to readTransactions, but for receipts. + function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts"); + RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[])); + return rawToConvertedReceipts(rawReceipts); + } + + function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt)); + return rawToConvertedReceipt(rawReceipt); + } + + function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) { + Receipt[] memory receipts = new Receipt[](rawReceipts.length); + for (uint256 i; i < rawReceipts.length; i++) { + receipts[i] = rawToConvertedReceipt(rawReceipts[i]); + } + return receipts; + } + + function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) { + Receipt memory receipt; + receipt.blockHash = rawReceipt.blockHash; + receipt.to = rawReceipt.to; + receipt.from = rawReceipt.from; + receipt.contractAddress = rawReceipt.contractAddress; + receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice); + receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed); + receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed); + receipt.status = _bytesToUint(rawReceipt.status); + receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex); + receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber); + receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs); + receipt.logsBloom = rawReceipt.logsBloom; + receipt.transactionHash = rawReceipt.transactionHash; + return receipt; + } + + function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs) + internal + pure + virtual + returns (ReceiptLog[] memory) + { + ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length); + for (uint256 i; i < rawLogs.length; i++) { + logs[i].logAddress = rawLogs[i].logAddress; + logs[i].blockHash = rawLogs[i].blockHash; + logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber); + logs[i].data = rawLogs[i].data; + logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex); + logs[i].topics = rawLogs[i].topics; + logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex); + logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex); + logs[i].removed = rawLogs[i].removed; + } + return logs; + } + + // Deploy a contract by fetching the contract bytecode from + // the artifacts directory + // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))` + function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed."); + } + + function deployCode(string memory what) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string): Deployment failed."); + } + + /// @dev deploy contract with value on construction + function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed."); + } + + function deployCode(string memory what, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed."); + } + + // creates a labeled address and the corresponding private key + function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) { + privateKey = uint256(keccak256(abi.encodePacked(name))); + addr = vm.addr(privateKey); + vm.label(addr, name); + } + + // creates a labeled address + function makeAddr(string memory name) internal virtual returns (address addr) { + (addr,) = makeAddrAndKey(name); + } + + function deriveRememberKey(string memory mnemonic, uint32 index) + internal + virtual + returns (address who, uint256 privateKey) + { + privateKey = vm.deriveKey(mnemonic, index); + who = vm.rememberKey(privateKey); + } + + function _bytesToUint(bytes memory b) private pure returns (uint256) { + require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function isFork() internal view virtual returns (bool status) { + try vm.activeFork() { + status = true; + } catch (bytes memory) {} + } + + modifier skipWhenForking() { + if (!isFork()) { + _; + } + } + + modifier skipWhenNotForking() { + if (isFork()) { + _; + } + } + + modifier noGasMetering() { + vm.pauseGasMetering(); + // To prevent turning gas monitoring back on with nested functions that use this modifier, + // we check if gasMetering started in the off position. If it did, we don't want to turn + // it back on until we exit the top level function that used the modifier + // + // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well. + // funcA will have `gasStartedOff` as false, funcB will have it as true, + // so we only turn metering back on at the end of the funcA + bool gasStartedOff = gasMeteringOff; + gasMeteringOff = true; + + _; + + // if gas metering was on when this modifier was called, turn it back on at the end + if (!gasStartedOff) { + gasMeteringOff = false; + vm.resumeGasMetering(); + } + } + + // a cheat for fuzzing addresses that are payable only + // see https://github.com/foundry-rs/foundry/issues/3631 + function assumePayable(address addr) internal virtual { + (bool success,) = payable(addr).call{value: 0}(""); + vm.assume(success); + } +} + +// Wrappers around cheatcodes to avoid footguns +abstract contract StdCheats is StdCheatsSafe { + using stdStorage for StdStorage; + + StdStorage private stdstore; + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + // Skip forward or rewind time by the specified number of seconds + function skip(uint256 time) internal virtual { + vm.warp(block.timestamp + time); + } + + function rewind(uint256 time) internal virtual { + vm.warp(block.timestamp - time); + } + + // Setup a prank from an address that has some ether + function hoax(address msgSender) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.prank(msgSender); + } + + function hoax(address msgSender, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.prank(msgSender); + } + + function hoax(address msgSender, address origin) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.prank(msgSender, origin); + } + + function hoax(address msgSender, address origin, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.prank(msgSender, origin); + } + + // Start perpetual prank from an address that has some ether + function startHoax(address msgSender) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.startPrank(msgSender); + } + + function startHoax(address msgSender, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.startPrank(msgSender); + } + + // Start perpetual prank from an address that has some ether + // tx.origin is set to the origin parameter + function startHoax(address msgSender, address origin) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.startPrank(msgSender, origin); + } + + function startHoax(address msgSender, address origin, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.startPrank(msgSender, origin); + } + + function changePrank(address msgSender) internal virtual { + vm.stopPrank(); + vm.startPrank(msgSender); + } + + // The same as Vm's `deal` + // Use the alternative signature for ERC20 tokens + function deal(address to, uint256 give) internal virtual { + vm.deal(to, give); + } + + // Set the balance of an account for any ERC20 token + // Use the alternative signature to update `totalSupply` + function deal(address token, address to, uint256 give) internal virtual { + deal(token, to, give, false); + } + + function deal(address token, address to, uint256 give, bool adjust) internal virtual { + // get current balance + (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to)); + uint256 prevBal = abi.decode(balData, (uint256)); + + // update balance + stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give); + + // update total supply + if (adjust) { + (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd)); + uint256 totSup = abi.decode(totSupData, (uint256)); + if (give < prevBal) { + totSup -= (prevBal - give); + } else { + totSup += (give - prevBal); + } + stdstore.target(token).sig(0x18160ddd).checked_write(totSup); + } + } +} diff --git a/lib/crytic/lib/forge-std/src/StdError.sol b/lib/crytic/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdError.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test +pragma solidity >=0.6.2 <0.9.0; + +library stdError { + bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); + bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); + bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); + bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); + bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); + bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); + bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); + bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); + bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); +} diff --git a/lib/crytic/lib/forge-std/src/StdInvariant.sol b/lib/crytic/lib/forge-std/src/StdInvariant.sol new file mode 100644 index 0000000..efa1129 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdInvariant.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +contract StdInvariant { + struct FuzzSelector { + address addr; + bytes4[] selectors; + } + + address[] private _excludedContracts; + address[] private _excludedSenders; + address[] private _targetedContracts; + address[] private _targetedSenders; + + string[] private _excludedArtifacts; + string[] private _targetedArtifacts; + + FuzzSelector[] private _targetedArtifactSelectors; + FuzzSelector[] private _targetedSelectors; + + // Functions for users: + // These are intended to be called in tests. + + function excludeContract(address newExcludedContract_) internal { + _excludedContracts.push(newExcludedContract_); + } + + function excludeSender(address newExcludedSender_) internal { + _excludedSenders.push(newExcludedSender_); + } + + function excludeArtifact(string memory newExcludedArtifact_) internal { + _excludedArtifacts.push(newExcludedArtifact_); + } + + function targetArtifact(string memory newTargetedArtifact_) internal { + _targetedArtifacts.push(newTargetedArtifact_); + } + + function targetArtifactSelector(FuzzSelector memory newTargetedArtifactSelector_) internal { + _targetedArtifactSelectors.push(newTargetedArtifactSelector_); + } + + function targetContract(address newTargetedContract_) internal { + _targetedContracts.push(newTargetedContract_); + } + + function targetSelector(FuzzSelector memory newTargetedSelector_) internal { + _targetedSelectors.push(newTargetedSelector_); + } + + function targetSender(address newTargetedSender_) internal { + _targetedSenders.push(newTargetedSender_); + } + + // Functions for forge: + // These are called by forge to run invariant tests and don't need to be called in tests. + + function excludeArtifacts() public view returns (string[] memory excludedArtifacts_) { + excludedArtifacts_ = _excludedArtifacts; + } + + function excludeContracts() public view returns (address[] memory excludedContracts_) { + excludedContracts_ = _excludedContracts; + } + + function excludeSenders() public view returns (address[] memory excludedSenders_) { + excludedSenders_ = _excludedSenders; + } + + function targetArtifacts() public view returns (string[] memory targetedArtifacts_) { + targetedArtifacts_ = _targetedArtifacts; + } + + function targetArtifactSelectors() public view returns (FuzzSelector[] memory targetedArtifactSelectors_) { + targetedArtifactSelectors_ = _targetedArtifactSelectors; + } + + function targetContracts() public view returns (address[] memory targetedContracts_) { + targetedContracts_ = _targetedContracts; + } + + function targetSelectors() public view returns (FuzzSelector[] memory targetedSelectors_) { + targetedSelectors_ = _targetedSelectors; + } + + function targetSenders() public view returns (address[] memory targetedSenders_) { + targetedSenders_ = _targetedSenders; + } +} diff --git a/lib/crytic/lib/forge-std/src/StdJson.sol b/lib/crytic/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..014e6b1 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdJson.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +// Helpers for parsing and writing JSON files +// To parse: +// ``` +// using stdJson for string; +// string memory json = vm.readFile("some_peth"); +// json.parseUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "deploymentArtifact"; +// Contract contract = new Contract(); +// json.serialize("contractAddress", address(contract)); +// json = json.serialize("deploymentTimes", uint(1)); +// // store the stringified JSON to the 'json' variable we have been using as a key +// // as we won't need it any longer +// string memory json2 = "finalArtifact"; +// string memory final = json2.serialize("depArtifact", json); +// final.write(""); +// ``` + +library stdJson { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) { + return vm.parseJson(json, key); + } + + function readUint(string memory json, string memory key) internal returns (uint256) { + return vm.parseJsonUint(json, key); + } + + function readUintArray(string memory json, string memory key) internal returns (uint256[] memory) { + return vm.parseJsonUintArray(json, key); + } + + function readInt(string memory json, string memory key) internal returns (int256) { + return vm.parseJsonInt(json, key); + } + + function readIntArray(string memory json, string memory key) internal returns (int256[] memory) { + return vm.parseJsonIntArray(json, key); + } + + function readBytes32(string memory json, string memory key) internal returns (bytes32) { + return vm.parseJsonBytes32(json, key); + } + + function readBytes32Array(string memory json, string memory key) internal returns (bytes32[] memory) { + return vm.parseJsonBytes32Array(json, key); + } + + function readString(string memory json, string memory key) internal returns (string memory) { + return vm.parseJsonString(json, key); + } + + function readStringArray(string memory json, string memory key) internal returns (string[] memory) { + return vm.parseJsonStringArray(json, key); + } + + function readAddress(string memory json, string memory key) internal returns (address) { + return vm.parseJsonAddress(json, key); + } + + function readAddressArray(string memory json, string memory key) internal returns (address[] memory) { + return vm.parseJsonAddressArray(json, key); + } + + function readBool(string memory json, string memory key) internal returns (bool) { + return vm.parseJsonBool(json, key); + } + + function readBoolArray(string memory json, string memory key) internal returns (bool[] memory) { + return vm.parseJsonBoolArray(json, key); + } + + function readBytes(string memory json, string memory key) internal returns (bytes memory) { + return vm.parseJsonBytes(json, key); + } + + function readBytesArray(string memory json, string memory key) internal returns (bytes[] memory) { + return vm.parseJsonBytesArray(json, key); + } + + function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bool[] memory value) + internal + returns (string memory) + { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256[] memory value) + internal + returns (string memory) + { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256[] memory value) + internal + returns (string memory) + { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address[] memory value) + internal + returns (string memory) + { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string[] memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function write(string memory jsonKey, string memory path) internal { + vm.writeJson(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeJson(jsonKey, path, valueKey); + } +} diff --git a/lib/crytic/lib/forge-std/src/StdMath.sol b/lib/crytic/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +library stdMath { + int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; + + function abs(int256 a) internal pure returns (uint256) { + // Required or it will fail when `a = type(int256).min` + if (a == INT256_MIN) { + return 57896044618658097711785492504343953926634992332820282019728792003956564819968; + } + + return uint256(a > 0 ? a : -a); + } + + function delta(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a - b : b - a; + } + + function delta(int256 a, int256 b) internal pure returns (uint256) { + // a and b are of the same sign + // this works thanks to two's complement, the left-most bit is the sign bit + if ((a ^ b) > -1) { + return delta(abs(a), abs(b)); + } + + // a and b are of opposite signs + return abs(a) + abs(b); + } + + function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + + return absDelta * 1e18 / b; + } + + function percentDelta(int256 a, int256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + uint256 absB = abs(b); + + return absDelta * 1e18 / absB; + } +} diff --git a/lib/crytic/lib/forge-std/src/StdStorage.sol b/lib/crytic/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..73a5ceb --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; + mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; +} + +library stdStorageSafe { + event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot); + event WARNING_UninitedSlot(address who, uint256 slot); + + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against + // slot complexity: + // if flat, will be bytes32(uint256(uint)); + // if map, will be keccak256(abi.encode(key, uint(slot))); + // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot))))); + // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); + function find(StdStorage storage self) internal returns (uint256) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + vm.record(); + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + (bytes32[] memory reads,) = vm.accesses(address(who)); + if (reads.length == 1) { + bytes32 curr = vm.load(who, reads[0]); + if (curr == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[0])); + } + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + } else if (reads.length > 1) { + for (uint256 i = 0; i < reads.length; i++) { + bytes32 prev = vm.load(who, reads[i]); + if (prev == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[i])); + } + // store + vm.store(who, reads[i], bytes32(hex"1337")); + bool success; + bytes memory rdat; + { + (success, rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + if (success && fdat == bytes32(hex"1337")) { + // we found which of the slots is the actual one + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + vm.store(who, reads[i], prev); + break; + } + vm.store(who, reads[i], prev); + } + } else { + revert("stdStorage find(StdStorage): No storage use detected for target."); + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], + "stdStorage find(StdStorage): Slot(s) not found." + ); + + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + self._target = _target; + return self; + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + self._sig = _sig; + return self; + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + self._sig = sigs(_sig); + return self; + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + self._keys.push(bytes32(uint256(uint160(who)))); + return self; + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + self._keys.push(bytes32(amt)); + return self; + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + self._keys.push(key); + return self; + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + self._depth = _depth; + return self; + } + + function read(StdStorage storage self) private returns (bytes memory) { + address t = self._target; + uint256 s = find(self); + return abi.encode(vm.load(t, bytes32(s))); + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return abi.decode(read(self), (bytes32)); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + int256 v = read_int(self); + if (v == 0) return false; + if (v == 1) return true; + revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + } + + function read_address(StdStorage storage self) internal returns (address) { + return abi.decode(read(self), (address)); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return abi.decode(read(self), (uint256)); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return abi.decode(read(self), (int256)); + } + + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} + +library stdStorage { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return stdStorageSafe.sigs(sigStr); + } + + function find(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.find(self); + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + return stdStorageSafe.target(self, _target); + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, who); + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, amt); + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, key); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function checked_write(StdStorage storage self, address who) internal { + checked_write(self, bytes32(uint256(uint160(who)))); + } + + function checked_write(StdStorage storage self, uint256 amt) internal { + checked_write(self, bytes32(amt)); + } + + function checked_write(StdStorage storage self, bool write) internal { + bytes32 t; + /// @solidity memory-safe-assembly + assembly { + t := write + } + checked_write(self, t); + } + + function checked_write(StdStorage storage self, bytes32 set) internal { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + find(self); + } + bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]); + + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + bytes32 curr = vm.load(who, slot); + + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + vm.store(who, slot, set); + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return stdStorageSafe.read_bytes32(self); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + return stdStorageSafe.read_bool(self); + } + + function read_address(StdStorage storage self) internal returns (address) { + return stdStorageSafe.read_address(self); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.read_uint(self); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return stdStorageSafe.read_int(self); + } + + // Private function so needs to be copied over + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + // Private function so needs to be copied over + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} diff --git a/lib/crytic/lib/forge-std/src/StdUtils.sol b/lib/crytic/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..f68d11f --- /dev/null +++ b/lib/crytic/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {IMulticall3} from "./interfaces/IMulticall3.sol"; +// TODO Remove import. +import {VmSafe} from "./Vm.sol"; + +abstract contract StdUtils { + /*////////////////////////////////////////////////////////////////////////// + CONSTANTS + //////////////////////////////////////////////////////////////////////////*/ + + IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11); + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; + uint256 private constant INT256_MIN_ABS = + 57896044618658097711785492504343953926634992332820282019728792003956564819968; + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + // Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address private constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { + require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); + // If x is between min and max, return x directly. This is to ensure that dictionary values + // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 + if (x >= min && x <= max) return x; + + uint256 size = max - min + 1; + + // If the value is 0, 1, 2, 3, warp that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. + // This helps ensure coverage of the min/max values. + if (x <= 3 && size > x) return min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); + + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. + if (x > max) { + uint256 diff = x - max; + uint256 rem = diff % size; + if (rem == 0) return max; + result = min + rem - 1; + } else if (x < min) { + uint256 diff = min - x; + uint256 rem = diff % size; + if (rem == 0) return min; + result = max - rem + 1; + } + } + + function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log("Bound Result", result); + } + + function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) { + require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min."); + + // Shifting all int256 values to uint256 to use _bound function. The range of two types are: + // int256 : -(2**255) ~ (2**255 - 1) + // uint256: 0 ~ (2**256 - 1) + // So, add 2**255, INT256_MIN_ABS to the integer values. + // + // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow. + // So, use `~uint256(x) + 1` instead. + uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS); + uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS); + uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS); + + uint256 y = _bound(_x, _min, _max); + + // To move it back to int256 value, subtract INT256_MIN_ABS at here. + result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS); + console2_log("Bound result", vm.toString(result)); + } + + function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { + require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce + /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) + function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { + // forgefmt: disable-start + // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0. + // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it. + if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80)))); + if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce)))); + + // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length. + if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce)))); + if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce)))); + if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce)))); + // forgefmt: disable-end + + // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp + // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) + // We assume nobody can have a nonce large enough to require more than 32 bytes. + return addressFromLast20Bytes( + keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))) + ); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash))); + } + + /// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) { + return computeCreate2Address(salt, initCodeHash, CREATE2_FACTORY); + } + + /// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments + /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode + function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) { + return hashInitCode(creationCode, ""); + } + + /// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2 + /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode + /// @param args the ABI-encoded arguments to the constructor of C + function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(creationCode, args)); + } + + // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses. + function getTokenBalances(address token, address[] memory addresses) + internal + virtual + returns (uint256[] memory balances) + { + uint256 tokenCodeSize; + assembly { + tokenCodeSize := extcodesize(token) + } + require(tokenCodeSize > 0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract."); + + // ABI encode the aggregate call to Multicall3. + uint256 length = addresses.length; + IMulticall3.Call[] memory calls = new IMulticall3.Call[](length); + for (uint256 i = 0; i < length; ++i) { + // 0x70a08231 = bytes4("balanceOf(address)")) + calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))}); + } + + // Make the aggregate call. + (, bytes[] memory returnData) = multicall.aggregate(calls); + + // ABI decode the return data and return the balances. + balances = new uint256[](length); + for (uint256 i = 0; i < length; ++i) { + balances[i] = abi.decode(returnData[i], (uint256)); + } + } + + /*////////////////////////////////////////////////////////////////////////// + PRIVATE FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { + return address(uint160(uint256(bytesValue))); + } + + // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere. + + function console2_log(string memory p0, uint256 p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + status; + } + + function console2_log(string memory p0, string memory p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1)); + status; + } +} diff --git a/lib/crytic/lib/forge-std/src/Test.sol b/lib/crytic/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..98fa7be --- /dev/null +++ b/lib/crytic/lib/forge-std/src/Test.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// 💬 ABOUT +// Standard Library's default Test + +// 🧩 MODULES +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdAssertions} from "./StdAssertions.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheats} from "./StdCheats.sol"; +import {stdError} from "./StdError.sol"; +import {StdInvariant} from "./StdInvariant.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; +import {DSTest} from "ds-test/test.sol"; + +// ⭐️ TEST +abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils, TestBase { +// Note: IS_TEST() must return true. +// Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76. +} diff --git a/lib/crytic/lib/forge-std/src/Vm.sol b/lib/crytic/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..31ebd41 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/Vm.sol @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// Cheatcodes are marked as view/pure/none using the following rules: +// 0. A call's observable behaviour includes its return value, logs, reverts and state writes, +// 1. If you can influence a later call's observable behaviour, you're neither `view` nor `pure (you are modifying some state be it the EVM, interpreter, filesystem, etc), +// 2. Otherwise if you can be influenced by an earlier call, or if reading some state, you're `view`, +// 3. Otherwise you're `pure`. + +interface VmSafe { + struct Log { + bytes32[] topics; + bytes data; + address emitter; + } + + struct Rpc { + string key; + string url; + } + + struct FsMetadata { + bool isDir; + bool isSymlink; + uint256 length; + bool readOnly; + uint256 modified; + uint256 accessed; + uint256 created; + } + + // Loads a storage slot from an address + function load(address target, bytes32 slot) external view returns (bytes32 data); + // Signs data + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + // Gets the address for a given private key + function addr(uint256 privateKey) external pure returns (address keyAddr); + // Gets the nonce of an account + function getNonce(address account) external view returns (uint64 nonce); + // Performs a foreign function call via the terminal + function ffi(string[] calldata commandInput) external returns (bytes memory result); + // Sets environment variables + function setEnv(string calldata name, string calldata value) external; + // Reads environment variables, (name) => (value) + function envBool(string calldata name) external view returns (bool value); + function envUint(string calldata name) external view returns (uint256 value); + function envInt(string calldata name) external view returns (int256 value); + function envAddress(string calldata name) external view returns (address value); + function envBytes32(string calldata name) external view returns (bytes32 value); + function envString(string calldata name) external view returns (string memory value); + function envBytes(string calldata name) external view returns (bytes memory value); + // Reads environment variables as arrays + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + // Read environment variables with default value + function envOr(string calldata name, bool defaultValue) external returns (bool value); + function envOr(string calldata name, uint256 defaultValue) external returns (uint256 value); + function envOr(string calldata name, int256 defaultValue) external returns (int256 value); + function envOr(string calldata name, address defaultValue) external returns (address value); + function envOr(string calldata name, bytes32 defaultValue) external returns (bytes32 value); + function envOr(string calldata name, string calldata defaultValue) external returns (string memory value); + function envOr(string calldata name, bytes calldata defaultValue) external returns (bytes memory value); + // Read environment variables as arrays with default value + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + returns (bool[] memory value); + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + returns (uint256[] memory value); + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + returns (int256[] memory value); + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + returns (address[] memory value); + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + returns (bytes32[] memory value); + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + returns (string[] memory value); + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + returns (bytes[] memory value); + // Records all storage reads and writes + function record() external; + // Gets all accessed reads and write slot from a recording session, for a given address + function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots); + // Gets the _creation_ bytecode from an artifact file. Takes in the relative path to the json file + function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode); + // Gets the _deployed_ bytecode from an artifact file. Takes in the relative path to the json file + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + // Labels an address in call traces + function label(address account, string calldata newLabel) external; + // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain + function broadcast() external; + // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain + function broadcast(address signer) external; + // Has the next call (at this call depth only) create a transaction with the private key provided as the sender that can later be signed and sent onchain + function broadcast(uint256 privateKey) external; + // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain + function startBroadcast() external; + // Has all subsequent calls (at this call depth only) create transactions with the address provided that can later be signed and sent onchain + function startBroadcast(address signer) external; + // Has all subsequent calls (at this call depth only) create transactions with the private key provided that can later be signed and sent onchain + function startBroadcast(uint256 privateKey) external; + // Stops collecting onchain transactions + function stopBroadcast() external; + // Reads the entire content of file to string + function readFile(string calldata path) external view returns (string memory data); + // Reads the entire content of file as binary. Path is relative to the project root. + function readFileBinary(string calldata path) external view returns (bytes memory data); + // Get the path of the current project root + function projectRoot() external view returns (string memory path); + // Get the metadata for a file/directory + function fsMetadata(string calldata fileOrDir) external returns (FsMetadata memory metadata); + // Reads next line of file to string + function readLine(string calldata path) external view returns (string memory line); + // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does. + function writeFile(string calldata path, string calldata data) external; + // Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does. + // Path is relative to the project root. + function writeFileBinary(string calldata path, bytes calldata data) external; + // Writes line to file, creating a file if it does not exist. + function writeLine(string calldata path, string calldata data) external; + // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine. + function closeFile(string calldata path) external; + // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases: + // - Path points to a directory. + // - The file doesn't exist. + // - The user lacks permissions to remove the file. + function removeFile(string calldata path) external; + // Convert values to a string + function toString(address value) external pure returns (string memory stringifiedValue); + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + function toString(bool value) external pure returns (string memory stringifiedValue); + function toString(uint256 value) external pure returns (string memory stringifiedValue); + function toString(int256 value) external pure returns (string memory stringifiedValue); + // Convert values from a string + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + // Record all the transaction logs + function recordLogs() external; + // Gets all the recorded logs + function getRecordedLogs() external returns (Log[] memory logs); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index} + function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at {derivationPath}{index} + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index) + external + pure + returns (uint256 privateKey); + // Adds a private key to the local forge wallet and returns the address + function rememberKey(uint256 privateKey) external returns (address keyAddr); + // + // parseJson + // + // ---- + // In case the returned value is a JSON object, it's encoded as a ABI-encoded tuple. As JSON objects + // don't have the notion of ordered, but tuples do, they JSON object is encoded with it's fields ordered in + // ALPHABETICAL order. That means that in order to successfully decode the tuple, we need to define a tuple that + // encodes the fields in the same order, which is alphabetical. In the case of Solidity structs, they are encoded + // as tuples, with the attributes in the order in which they are defined. + // For example: json = { 'a': 1, 'b': 0xa4tb......3xs} + // a: uint256 + // b: address + // To decode that json, we need to define a struct or a tuple as follows: + // struct json = { uint256 a; address b; } + // If we defined a json struct with the opposite order, meaning placing the address b first, it would try to + // decode the tuple in that order, and thus fail. + // ---- + // Given a string of JSON, return it as ABI-encoded + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + // The following parseJson cheatcodes will do type coercion, for the type that they indicate. + // For example, parseJsonUint will coerce all values to a uint256. That includes stringified numbers '12' + // and hex numbers '0xEF'. + // Type coercion works ONLY for discrete values or arrays. That means that the key must return a value or array, not + // a JSON object. + function parseJsonUint(string calldata, string calldata) external returns (uint256); + function parseJsonUintArray(string calldata, string calldata) external returns (uint256[] memory); + function parseJsonInt(string calldata, string calldata) external returns (int256); + function parseJsonIntArray(string calldata, string calldata) external returns (int256[] memory); + function parseJsonBool(string calldata, string calldata) external returns (bool); + function parseJsonBoolArray(string calldata, string calldata) external returns (bool[] memory); + function parseJsonAddress(string calldata, string calldata) external returns (address); + function parseJsonAddressArray(string calldata, string calldata) external returns (address[] memory); + function parseJsonString(string calldata, string calldata) external returns (string memory); + function parseJsonStringArray(string calldata, string calldata) external returns (string[] memory); + function parseJsonBytes(string calldata, string calldata) external returns (bytes memory); + function parseJsonBytesArray(string calldata, string calldata) external returns (bytes[] memory); + function parseJsonBytes32(string calldata, string calldata) external returns (bytes32); + function parseJsonBytes32Array(string calldata, string calldata) external returns (bytes32[] memory); + + // Serialize a key and value to a JSON object stored in-memory that can be later written to a file + // It returns the stringified version of the specific JSON file up to that moment. + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + // + // writeJson + // + // ---- + // Write a serialized JSON object to a file. If the file exists, it will be overwritten. + // Let's assume we want to write the following JSON to a file: + // + // { "boolean": true, "number": 342, "object": { "title": "finally json serialization" } } + // + // ``` + // string memory json1 = "some key"; + // vm.serializeBool(json1, "boolean", true); + // vm.serializeBool(json1, "number", uint256(342)); + // json2 = "some other key"; + // string memory output = vm.serializeString(json2, "title", "finally json serialization"); + // string memory finalJson = vm.serialize(json1, "object", output); + // vm.writeJson(finalJson, "./output/example.json"); + // ``` + // The critical insight is that every invocation of serialization will return the stringified version of the JSON + // up to that point. That means we can construct arbitrary JSON objects and then use the return stringified version + // to serialize them as values to another JSON object. + // + // json1 and json2 are simply keys used by the backend to keep track of the objects. So vm.serializeJson(json1,..) + // will find the object in-memory that is keyed by "some key". + function writeJson(string calldata json, string calldata path) external; + // Write a serialized JSON object to an **existing** JSON file, replacing a value with key = + // This is useful to replace a specific value of a JSON file, without having to parse the entire thing + function writeJson(string calldata json, string calldata path, string calldata valueKey) external; + // Returns the RPC url for the given alias + function rpcUrl(string calldata rpcAlias) external view returns (string memory json); + // Returns all rpc urls and their aliases `[alias, url][]` + function rpcUrls() external view returns (string[2][] memory urls); + // Returns all rpc urls and their aliases as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + // If the condition is false, discard this run's fuzz inputs and generate new ones. + function assume(bool condition) external pure; + // Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + // Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; +} + +interface Vm is VmSafe { + // Sets block.timestamp + function warp(uint256 newTimestamp) external; + // Sets block.height + function roll(uint256 newHeight) external; + // Sets block.basefee + function fee(uint256 newBasefee) external; + // Sets block.difficulty + function difficulty(uint256 newDifficulty) external; + // Sets block.chainid + function chainId(uint256 newChainId) external; + // Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) external; + // Sets the nonce of an account; must be higher than the current nonce of the account + function setNonce(address account, uint64 newNonce) external; + // Sets the *next* call's msg.sender to be the input address + function prank(address msgSender) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called + function startPrank(address msgSender) external; + // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input + function prank(address msgSender, address txOrigin) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input + function startPrank(address msgSender, address txOrigin) external; + // Resets subsequent calls' msg.sender to be `address(this)` + function stopPrank() external; + // Sets an address' balance + function deal(address account, uint256 newBalance) external; + // Sets an address' code + function etch(address target, bytes calldata newRuntimeBytecode) external; + // Expects an error on next call + function expectRevert(bytes calldata revertData) external; + function expectRevert(bytes4 revertData) external; + function expectRevert() external; + // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + // Call this function, then emit an event, then call a function. Internally after the call, we check if + // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external; + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) + external; + // Mocks a call to an address, returning specified data. + // Calldata can either be strict or a partial match, e.g. if you only + // pass a Solidity selector to the expected calldata, then the entire Solidity + // function will be mocked. + function mockCall(address callee, bytes calldata data, bytes calldata returnData) external; + // Mocks a call to an address with a specific msg.value, returning specified data. + // Calldata match takes precedence over msg.value in case of ambiguity. + function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external; + // Clears all mocked calls + function clearMockedCalls() external; + // Expects a call to an address with the specified calldata. + // Calldata can either be a strict or a partial match + function expectCall(address callee, bytes calldata data) external; + // Expects a call to an address with the specified msg.value and calldata + function expectCall(address callee, uint256 msgValue, bytes calldata data) external; + // Sets block.coinbase + function coinbase(address newCoinbase) external; + // Snapshot the current state of the evm. + // Returns the id of the snapshot that was created. + // To revert a snapshot use `revertTo` + function snapshot() external returns (uint256 snapshotId); + // Revert the state of the EVM to a previous snapshot + // Takes the snapshot id to revert to. + // This deletes the snapshot and all snapshots taken after the given snapshot id. + function revertTo(uint256 snapshotId) external returns (bool success); + // Creates a new fork with the given endpoint and block and returns the identifier of the fork + function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork + function createFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before the transaction, + // and returns the identifier of the fork + function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates _and_ also selects new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before + // the transaction, returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active. + function selectFork(uint256 forkId) external; + /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + // Updates the currently active fork to given block number + // This is similar to `roll` but for the currently active fork + function rollFork(uint256 blockNumber) external; + // Updates the currently active fork to given transaction + // this will `rollFork` with the number of the block the transaction was mined in and replays all transaction mined before it in the block + function rollFork(bytes32 txHash) external; + // Updates the given fork to given block number + function rollFork(uint256 forkId, uint256 blockNumber) external; + // Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block + function rollFork(uint256 forkId, bytes32 txHash) external; + // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup + // Meaning, changes made to the state of this account will be kept when switching forks + function makePersistent(address account) external; + function makePersistent(address account0, address account1) external; + function makePersistent(address account0, address account1, address account2) external; + function makePersistent(address[] calldata accounts) external; + // Revokes persistent status from the address, previously added via `makePersistent` + function revokePersistent(address account) external; + function revokePersistent(address[] calldata accounts) external; + // Returns true if the account is marked as persistent + function isPersistent(address account) external view returns (bool persistent); + // In forking mode, explicitly grant the given address cheatcode access + function allowCheatcodes(address account) external; + // Fetches the given transaction from the active fork and executes it on the current state + function transact(bytes32 txHash) external; + // Fetches the given transaction from the given fork and executes it on the current state + function transact(uint256 forkId, bytes32 txHash) external; +} diff --git a/lib/crytic/lib/forge-std/src/console.sol b/lib/crytic/lib/forge-std/src/console.sol new file mode 100644 index 0000000..ad57e53 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/console.sol @@ -0,0 +1,1533 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/crytic/lib/forge-std/src/console2.sol b/lib/crytic/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..8596233 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/console2.sol @@ -0,0 +1,1546 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +/// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should +/// use `int256` and `uint256`. This modified version fixes that. This version is recommended +/// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in +/// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`. +/// Reference: https://github.com/NomicFoundation/hardhat/issues/2178 +library console2 { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function logUint(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function log(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint256 p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); + } + + function log(uint256 p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); + } + + function log(uint256 p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); + } + + function log(uint256 p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); + } + + function log(string memory p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function log(string memory p0, int256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint256 p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/crytic/lib/forge-std/src/interfaces/IERC1155.sol b/lib/crytic/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..f7dd2b4 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/interfaces/IERC1155.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-1155 Multi Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-1155 +/// Note: The ERC-165 identifier for this interface is 0xd9b67a26. +interface IERC1155 is IERC165 { + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_id` argument MUST be the token type being transferred. + /// - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferSingle( + address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value + ); + + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_ids` argument MUST be the list of tokens being transferred. + /// - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferBatch( + address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values + ); + + /// @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled). + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. + /// The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". + event URI(string _value, uint256 indexed _id); + + /// @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + /// - MUST revert on any other error. + /// - MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + /// - After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _id ID of the token type + /// @param _value Transfer amount + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; + + /// @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if length of `_ids` is not the same as length of `_values`. + /// - MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + /// - MUST revert on any other error. + /// - MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + /// - Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + /// - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _ids IDs of each token type (order and length must match _values array) + /// @param _values Transfer amounts per token type (order and length must match _ids array) + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + function safeBatchTransferFrom( + address _from, + address _to, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data + ) external; + + /// @notice Get the balance of an account's tokens. + /// @param _owner The address of the token holder + /// @param _id ID of the token + /// @return The _owner's balance of the token type requested + function balanceOf(address _owner, uint256 _id) external view returns (uint256); + + /// @notice Get the balance of multiple account/token pairs + /// @param _owners The addresses of the token holders + /// @param _ids ID of the tokens + /// @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair) + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) + external + view + returns (uint256[] memory); + + /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + /// @dev MUST emit the ApprovalForAll event on success. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Queries the approval status of an operator for a given owner. + /// @param _owner The owner of the tokens + /// @param _operator Address of authorized operator + /// @return True if the operator is approved, false if not + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} diff --git a/lib/crytic/lib/forge-std/src/interfaces/IERC165.sol b/lib/crytic/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/interfaces/IERC165.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +interface IERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} diff --git a/lib/crytic/lib/forge-std/src/interfaces/IERC20.sol b/lib/crytic/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/interfaces/IERC20.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +/// @dev Interface of the ERC20 standard as defined in the EIP. +/// @dev This includes the optional name, symbol, and decimals metadata. +interface IERC20 { + /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` + /// is the new allowance. + event Approval(address indexed owner, address indexed spender, uint256 value); + + /// @notice Returns the amount of tokens in existence. + function totalSupply() external view returns (uint256); + + /// @notice Returns the amount of tokens owned by `account`. + function balanceOf(address account) external view returns (uint256); + + /// @notice Moves `amount` tokens from the caller's account to `to`. + function transfer(address to, uint256 amount) external returns (bool); + + /// @notice Returns the remaining number of tokens that `spender` is allowed + /// to spend on behalf of `owner` + function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. + /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. + /// `amount` is then deducted from the caller's allowance. + function transferFrom(address from, address to, uint256 amount) external returns (bool); + + /// @notice Returns the name of the token. + function name() external view returns (string memory); + + /// @notice Returns the symbol of the token. + function symbol() external view returns (string memory); + + /// @notice Returns the decimals places of the token. + function decimals() external view returns (uint8); +} diff --git a/lib/crytic/lib/forge-std/src/interfaces/IERC4626.sol b/lib/crytic/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..bfe3a11 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/interfaces/IERC4626.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC20.sol"; + +/// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in +/// https://eips.ethereum.org/EIPS/eip-4626 +interface IERC4626 is IERC20 { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares + ); + + /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + /// @dev + /// - MUST be an ERC-20 token contract. + /// - MUST NOT revert. + function asset() external view returns (address assetTokenAddress); + + /// @notice Returns the total amount of the underlying asset that is “managed” by Vault. + /// @dev + /// - SHOULD include any compounding that occurs from yield. + /// - MUST be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT revert. + function totalAssets() external view returns (uint256 totalManagedAssets); + + /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + /// through a deposit call. + /// @dev + /// - MUST return a limited value if receiver is subject to some deposit limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + /// - MUST NOT revert. + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + /// call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + /// in the same transaction. + /// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + /// deposit would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// deposit execution, and are accounted for during deposit. + /// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + /// @dev + /// - MUST return a limited value if receiver is subject to some mint limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + /// - MUST NOT revert. + function maxMint(address receiver) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + /// in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + /// same transaction. + /// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + /// would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by minting. + function previewMint(uint256 shares) external view returns (uint256 assets); + + /// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + /// execution, and are accounted for during mint. + /// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + /// Vault, through a withdraw call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST NOT revert. + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + /// call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + /// called + /// in the same transaction. + /// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + /// the withdrawal would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// withdraw execution, and are accounted for during withdraw. + /// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + /// through a redeem call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + /// - MUST NOT revert. + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + /// in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + /// same transaction. + /// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + /// redemption would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by redeeming. + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// redeem execution, and are accounted for during redeem. + /// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/crytic/lib/forge-std/src/interfaces/IERC721.sol b/lib/crytic/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..0a16f45 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/interfaces/IERC721.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-721 Non-Fungible Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. +interface IERC721 is IERC165 { + /// @dev This emits when ownership of any NFT changes by any mechanism. + /// This event emits when NFTs are created (`from` == 0) and destroyed + /// (`to` == 0). Exception: during contract creation, any number of NFTs + /// may be created and assigned without emitting Transfer. At the time of + /// any transfer, the approved address for that NFT (if any) is reset to none. + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + + /// @dev This emits when the approved address for an NFT is changed or + /// reaffirmed. The zero address indicates there is no approved address. + /// When a Transfer event emits, this also indicates that the approved + /// address for that NFT (if any) is reset to none. + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + /// @dev This emits when an operator is enabled or disabled for an owner. + /// The operator can manage all NFTs of the owner. + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @notice Count all NFTs assigned to an owner + /// @dev NFTs assigned to the zero address are considered invalid, and this + /// function throws for queries about the zero address. + /// @param _owner An address for whom to query the balance + /// @return The number of NFTs owned by `_owner`, possibly zero + function balanceOf(address _owner) external view returns (uint256); + + /// @notice Find the owner of an NFT + /// @dev NFTs assigned to zero address are considered invalid, and queries + /// about them do throw. + /// @param _tokenId The identifier for an NFT + /// @return The address of the owner of the NFT + function ownerOf(uint256 _tokenId) external view returns (address); + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. When transfer is complete, this function + /// checks if `_to` is a smart contract (code size > 0). If so, it calls + /// `onERC721Received` on `_to` and throws if the return value is not + /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + /// @param data Additional data with no specified format, sent in call to `_to` + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev This works identically to the other function with an extra data parameter, + /// except this function just sets data to "". + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE + /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE + /// THEY MAY BE PERMANENTLY LOST + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Change or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param _approved The new approved NFT controller + /// @param _tokenId The NFT to approve + function approve(address _approved, uint256 _tokenId) external payable; + + /// @notice Enable or disable approval for a third party ("operator") to manage + /// all of `msg.sender`'s assets + /// @dev Emits the ApprovalForAll event. The contract MUST allow + /// multiple operators per owner. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Get the approved address for a single NFT + /// @dev Throws if `_tokenId` is not a valid NFT. + /// @param _tokenId The NFT to find the approved address for + /// @return The approved address for this NFT, or the zero address if there is none + function getApproved(uint256 _tokenId) external view returns (address); + + /// @notice Query if an address is an authorized operator for another address + /// @param _owner The address that owns the NFTs + /// @param _operator The address that acts on behalf of the owner + /// @return True if `_operator` is an approved operator for `_owner`, false otherwise + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} + +/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02. +interface IERC721TokenReceiver { + /// @notice Handle the receipt of an NFT + /// @dev The ERC721 smart contract calls this function on the recipient + /// after a `transfer`. This function MAY throw to revert and reject the + /// transfer. Return of other than the magic value MUST result in the + /// transaction being reverted. + /// Note: the contract address is always the message sender. + /// @param _operator The address which called `safeTransferFrom` function + /// @param _from The address which previously owned the token + /// @param _tokenId The NFT identifier which is being transferred + /// @param _data Additional data with no specified format + /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + /// unless throwing + function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) + external + returns (bytes4); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x5b5e139f. +interface IERC721Metadata is IERC721 { + /// @notice A descriptive name for a collection of NFTs in this contract + function name() external view returns (string memory _name); + + /// @notice An abbreviated name for NFTs in this contract + function symbol() external view returns (string memory _symbol); + + /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. + /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC + /// 3986. The URI may point to a JSON file that conforms to the "ERC721 + /// Metadata JSON Schema". + function tokenURI(uint256 _tokenId) external view returns (string memory); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x780e9d63. +interface IERC721Enumerable is IERC721 { + /// @notice Count NFTs tracked by this contract + /// @return A count of valid NFTs tracked by this contract, where each one of + /// them has an assigned and queryable owner not equal to the zero address + function totalSupply() external view returns (uint256); + + /// @notice Enumerate valid NFTs + /// @dev Throws if `_index` >= `totalSupply()`. + /// @param _index A counter less than `totalSupply()` + /// @return The token identifier for the `_index`th NFT, + /// (sort order not specified) + function tokenByIndex(uint256 _index) external view returns (uint256); + + /// @notice Enumerate NFTs assigned to an owner + /// @dev Throws if `_index` >= `balanceOf(_owner)` or if + /// `_owner` is the zero address, representing invalid NFTs. + /// @param _owner An address where we are interested in NFTs owned by them + /// @param _index A counter less than `balanceOf(_owner)` + /// @return The token identifier for the `_index`th NFT assigned to `_owner`, + /// (sort order not specified) + function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); +} diff --git a/lib/crytic/lib/forge-std/src/interfaces/IMulticall3.sol b/lib/crytic/lib/forge-std/src/interfaces/IMulticall3.sol new file mode 100644 index 0000000..0d031b7 --- /dev/null +++ b/lib/crytic/lib/forge-std/src/interfaces/IMulticall3.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +interface IMulticall3 { + struct Call { + address target; + bytes callData; + } + + struct Call3 { + address target; + bool allowFailure; + bytes callData; + } + + struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; + } + + struct Result { + bool success; + bytes returnData; + } + + function aggregate(Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes[] memory returnData); + + function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData); + + function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData); + + function blockAndAggregate(Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); + + function getBasefee() external view returns (uint256 basefee); + + function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash); + + function getBlockNumber() external view returns (uint256 blockNumber); + + function getChainId() external view returns (uint256 chainid); + + function getCurrentBlockCoinbase() external view returns (address coinbase); + + function getCurrentBlockDifficulty() external view returns (uint256 difficulty); + + function getCurrentBlockGasLimit() external view returns (uint256 gaslimit); + + function getCurrentBlockTimestamp() external view returns (uint256 timestamp); + + function getEthBalance(address addr) external view returns (uint256 balance); + + function getLastBlockHash() external view returns (bytes32 blockHash); + + function tryAggregate(bool requireSuccess, Call[] calldata calls) + external + payable + returns (Result[] memory returnData); + + function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); +} diff --git a/lib/crytic/lib/forge-std/test/StdAssertions.t.sol b/lib/crytic/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..6222654 --- /dev/null +++ b/lib/crytic/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,823 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdAssertionsTest is Test { + string constant CUSTOM_ERROR = "guh!"; + + bool constant EXPECT_PASS = false; + bool constant EXPECT_FAIL = true; + + TestTest t = new TestTest(); + + /*////////////////////////////////////////////////////////////////////////// + FAIL(STRING) + //////////////////////////////////////////////////////////////////////////*/ + + function testShouldFail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._fail(CUSTOM_ERROR); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_FALSE + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertFalse_Pass() external { + t._assertFalse(false, EXPECT_PASS); + } + + function testAssertFalse_Fail() external { + vm.expectEmit(false, false, false, true); + emit log("Error: Assertion Failed"); + t._assertFalse(true, EXPECT_FAIL); + } + + function testAssertFalse_Err_Pass() external { + t._assertFalse(false, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertFalse_Err_Fail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertFalse(true, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BOOL) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bool_Pass(bool a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bool_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bool]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BoolErr_Pass(bool a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BoolErr_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BYTES) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bytes_Pass(bytes calldata a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bytes_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bytes]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BytesErr_Pass(bytes calldata a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BytesErr_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(ARRAY) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_UintArr_Pass(uint256 e0, uint256 e1, uint256 e2) public { + uint256[] memory a = new uint256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + uint256[] memory b = new uint256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_IntArr_Pass(int256 e0, int256 e1, int256 e2) public { + int256[] memory a = new int256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + int256[] memory b = new int256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_AddressArr_Pass(address e0, address e1, address e2) public { + address[] memory a = new address[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + address[] memory b = new address[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_UintArr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_UintArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEqUint() public { + assertEqUint(uint8(1), uint128(1)); + assertEqUint(uint64(2), uint64(2)); + } + + function testFailAssertEqUint() public { + assertEqUint(uint64(1), uint96(2)); + assertEqUint(uint160(3), uint160(4)); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS_DECIMAL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbsDecimal_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqAbsDecimal_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqAbsDecimal_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbsDecimal_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Int_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Int_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_IntErr_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_IntErr_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS_DECIMAL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbsDecimal_Int_Pass(int256 a, int256 b, uint256 maxDelta, uint256 decimals) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqAbsDecimal_Int_Fail(int256 a, int256 b, uint256 maxDelta, uint256 decimals) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqAbsDecimal_IntErr_Pass(int256 a, int256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbsDecimal_IntErr_Fail(int256 a, int256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL_DECIMAL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRelDecimal_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals) + external + { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals) + external + { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqRelDecimal_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals) + external + { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals) + external + { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL_DECIMAL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRelDecimal_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqRelDecimal_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } +} + +contract TestTest is Test { + modifier expectFailure(bool expectFail) { + bool preState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + _; + bool postState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + + if (preState == true) { + return; + } + + if (expectFail) { + require(postState == true, "expected failure not triggered"); + + // unwind the expected failure + vm.store(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x00))); + } else { + require(postState == false, "unexpected failure was triggered"); + } + } + + function _fail(string memory err) external expectFailure(true) { + fail(err); + } + + function _assertFalse(bool data, bool expectFail) external expectFailure(expectFail) { + assertFalse(data); + } + + function _assertFalse(bool data, string memory err, bool expectFail) external expectFailure(expectFail) { + assertFalse(data, err); + } + + function _assertEq(bool a, bool b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bool a, bool b, string memory err, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b, err); + } + + function _assertEq(bytes memory a, bytes memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bytes memory a, bytes memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(int256[] memory a, int256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(address[] memory a, address[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(int256[] memory a, int256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(address[] memory a, address[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + + function _assertApproxEqAbsDecimal( + uint256 a, + uint256 b, + uint256 maxDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals, err); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + + function _assertApproxEqAbsDecimal( + int256 a, + int256 b, + uint256 maxDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals, err); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRelDecimal(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + + function _assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, err); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + + function _assertApproxEqRelDecimal( + int256 a, + int256 b, + uint256 maxPercentDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, err); + } +} diff --git a/lib/crytic/lib/forge-std/test/StdChains.t.sol b/lib/crytic/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..c2b215d --- /dev/null +++ b/lib/crytic/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdChainsTest is Test { + function testChainRpcInitialization() public { + // RPCs specified in `foundry.toml` should be updated. + assertEq(getChain(1).rpcUrl, "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5"); + assertEq(getChain("optimism_goerli").rpcUrl, "https://goerli.optimism.io/"); + assertEq(getChain("arbitrum_one_goerli").rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/"); + + // Environment variables should be the next fallback + assertEq(getChain("arbitrum_nova").rpcUrl, "https://nova.arbitrum.io/rpc"); + vm.setEnv("ARBITRUM_NOVA_RPC_URL", "myoverride"); + assertEq(getChain("arbitrum_nova").rpcUrl, "myoverride"); + vm.setEnv("ARBITRUM_NOVA_RPC_URL", "https://nova.arbitrum.io/rpc"); + + // Cannot override RPCs defined in `foundry.toml` + vm.setEnv("MAINNET_RPC_URL", "myoverride2"); + assertEq(getChain("mainnet").rpcUrl, "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5"); + + // Other RPCs should remain unchanged. + assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545"); + assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b"); + } + + function testRpc(string memory rpcAlias) internal { + string memory rpcUrl = getChain(rpcAlias).rpcUrl; + vm.createSelectFork(rpcUrl); + } + + // Ensure we can connect to the default RPC URL for each chain. + function testRpcs() public { + testRpc("mainnet"); + testRpc("goerli"); + testRpc("sepolia"); + testRpc("optimism"); + testRpc("optimism_goerli"); + testRpc("arbitrum_one"); + testRpc("arbitrum_one_goerli"); + testRpc("arbitrum_nova"); + testRpc("polygon"); + testRpc("polygon_mumbai"); + testRpc("avalanche"); + testRpc("avalanche_fuji"); + testRpc("bnb_smart_chain"); + testRpc("bnb_smart_chain_testnet"); + testRpc("gnosis_chain"); + } + + function testChainNoDefault() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found."); + getChain("does_not_exist"); + } + + function testSetChainFirstFails() public { + vm.expectRevert("StdChains setChain(string,ChainData): Chain ID 31337 already used by \"anvil\"."); + setChain("anvil2", ChainData("Anvil", 31337, "URL")); + } + + function testChainBubbleUp() public { + setChain("needs_undefined_env_var", ChainData("", 123456789, "")); + vm.expectRevert( + "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found" + ); + getChain("needs_undefined_env_var"); + } + + function testCannotSetChain_ChainIdExists() public { + setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + + vm.expectRevert('StdChains setChain(string,ChainData): Chain ID 123456789 already used by "custom_chain".'); + + setChain("another_custom_chain", ChainData("", 123456789, "")); + } + + function testSetChain() public { + setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + Chain memory customChain = getChain("custom_chain"); + assertEq(customChain.name, "Custom Chain"); + assertEq(customChain.chainId, 123456789); + assertEq(customChain.chainAlias, "custom_chain"); + assertEq(customChain.rpcUrl, "https://custom.chain/"); + Chain memory chainById = getChain(123456789); + assertEq(chainById.name, customChain.name); + assertEq(chainById.chainId, customChain.chainId); + assertEq(chainById.chainAlias, customChain.chainAlias); + assertEq(chainById.rpcUrl, customChain.rpcUrl); + customChain.name = "Another Custom Chain"; + customChain.chainId = 987654321; + setChain("another_custom_chain", customChain); + Chain memory anotherCustomChain = getChain("another_custom_chain"); + assertEq(anotherCustomChain.name, "Another Custom Chain"); + assertEq(anotherCustomChain.chainId, 987654321); + assertEq(anotherCustomChain.chainAlias, "another_custom_chain"); + assertEq(anotherCustomChain.rpcUrl, "https://custom.chain/"); + // Verify the first chain data was not overwritten + chainById = getChain(123456789); + assertEq(chainById.name, "Custom Chain"); + assertEq(chainById.chainId, 123456789); + } + + function testSetNoEmptyAlias() public { + vm.expectRevert("StdChains setChain(string,ChainData): Chain alias cannot be the empty string."); + setChain("", ChainData("", 123456789, "")); + } + + function testSetNoChainId0() public { + vm.expectRevert("StdChains setChain(string,ChainData): Chain ID cannot be 0."); + setChain("alias", ChainData("", 0, "")); + } + + function testGetNoChainId0() public { + vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0."); + getChain(0); + } + + function testGetNoEmptyAlias() public { + vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string."); + getChain(""); + } + + function testChainIdNotFound() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found."); + getChain("no_such_alias"); + } + + function testChainAliasNotFound() public { + vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found."); + getChain(321); + } + + function testSetChain_ExistingOne() public { + setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + assertEq(getChain(123456789).chainId, 123456789); + + setChain("custom_chain", ChainData("Modified Chain", 999999999, "https://modified.chain/")); + vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); + getChain(123456789); + + Chain memory modifiedChain = getChain(999999999); + assertEq(modifiedChain.name, "Modified Chain"); + assertEq(modifiedChain.chainId, 999999999); + assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); + } + + function testDontUseDefaultRpcUrl() public { + // Should error if default RPCs flag is set to false. + setFallbackToDefaultRpcUrls(false); + vm.expectRevert( + "Failed to get environment variable `ANVIL_RPC_URL` as type `string`: environment variable not found" + ); + getChain(31337); + vm.expectRevert( + "Failed to get environment variable `SEPOLIA_RPC_URL` as type `string`: environment variable not found" + ); + getChain("sepolia"); + } +} diff --git a/lib/crytic/lib/forge-std/test/StdCheats.t.sol b/lib/crytic/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..82bfb23 --- /dev/null +++ b/lib/crytic/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdCheats.sol"; +import "../src/Test.sol"; +import "../src/StdJson.sol"; + +contract StdCheatsTest is Test { + Bar test; + + using stdJson for string; + + function setUp() public { + test = new Bar(); + } + + function testSkip() public { + vm.warp(100); + skip(25); + assertEq(block.timestamp, 125); + } + + function testRewind() public { + vm.warp(100); + rewind(25); + assertEq(block.timestamp, 75); + } + + function testHoax() public { + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + } + + function testHoaxOrigin() public { + hoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + } + + function testHoaxDifferentAddresses() public { + hoax(address(1337), address(7331)); + test.origin{value: 100}(address(1337), address(7331)); + } + + function testStartHoax() public { + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testStartHoaxOrigin() public { + startHoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + test.origin{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testChangePrank() public { + vm.startPrank(address(1337)); + test.bar(address(1337)); + changePrank(address(0xdead)); + test.bar(address(0xdead)); + changePrank(address(1337)); + test.bar(address(1337)); + vm.stopPrank(); + } + + function testMakeAddrEquivalence() public { + (address addr,) = makeAddrAndKey("1337"); + assertEq(makeAddr("1337"), addr); + } + + function testMakeAddrSigning() public { + (address addr, uint256 key) = makeAddrAndKey("1337"); + bytes32 hash = keccak256("some_message"); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash); + assertEq(ecrecover(hash, v, r, s), addr); + } + + function testDeal() public { + deal(address(this), 1 ether); + assertEq(address(this).balance, 1 ether); + } + + function testDealToken() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18); + assertEq(barToken.balanceOf(address(this)), 10000e18); + } + + function testDealTokenAdjustTS() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18, true); + assertEq(barToken.balanceOf(address(this)), 10000e18); + assertEq(barToken.totalSupply(), 20000e18); + deal(bar, address(this), 0, true); + assertEq(barToken.balanceOf(address(this)), 0); + assertEq(barToken.totalSupply(), 10000e18); + } + + function testDeployCode() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes("")); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar"); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeVal() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes(""), 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + function testDeployCodeValNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar", 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + // We need this so we can call "this.deployCode" rather than "deployCode" directly + function deployCodeHelper(string memory what) external { + deployCode(what); + } + + function testDeployCodeFail() public { + vm.expectRevert(bytes("StdCheats deployCode(string): Deployment failed.")); + this.deployCodeHelper("StdCheats.t.sol:RevertingContract"); + } + + function getCode(address who) internal view returns (bytes memory o_code) { + /// @solidity memory-safe-assembly + assembly { + // retrieve the size of the code, this needs assembly + let size := extcodesize(who) + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + o_code := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(o_code, size) + // actually retrieve the code, this needs assembly + extcodecopy(who, add(o_code, 0x20), 0, size) + } + } + + function testDeriveRememberKey() public { + string memory mnemonic = "test test test test test test test test test test test junk"; + + (address deployer, uint256 privateKey) = deriveRememberKey(mnemonic, 0); + assertEq(deployer, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); + } + + function testBytesToUint() public { + assertEq(3, bytesToUint_test(hex"03")); + assertEq(2, bytesToUint_test(hex"02")); + assertEq(255, bytesToUint_test(hex"ff")); + assertEq(29625, bytesToUint_test(hex"73b9")); + } + + function testParseJsonTxDetail() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + string memory json = vm.readFile(path); + bytes memory transactionDetails = json.parseRaw(".transactions[0].tx"); + RawTx1559Detail memory rawTxDetail = abi.decode(transactionDetails, (RawTx1559Detail)); + Tx1559Detail memory txDetail = rawToConvertedEIP1559Detail(rawTxDetail); + assertEq(txDetail.from, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(txDetail.to, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512); + assertEq( + txDetail.data, + hex"23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004" + ); + assertEq(txDetail.nonce, 3); + assertEq(txDetail.txType, 2); + assertEq(txDetail.gas, 29625); + assertEq(txDetail.value, 0); + } + + function testReadEIP1559Transaction() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 0; + Tx1559 memory transaction = readTx1559(path, index); + transaction; + } + + function testReadEIP1559Transactions() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Tx1559[] memory transactions = readTx1559s(path); + transactions; + } + + function testReadReceipt() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 5; + Receipt memory receipt = readReceipt(path, index); + assertEq( + receipt.logsBloom, + hex"00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100" + ); + } + + function testReadReceipts() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Receipt[] memory receipts = readReceipts(path); + receipts; + } + + function testGasMeteringModifier() public { + uint256 gas_start_normal = gasleft(); + addInLoop(); + uint256 gas_used_normal = gas_start_normal - gasleft(); + + uint256 gas_start_single = gasleft(); + addInLoopNoGas(); + uint256 gas_used_single = gas_start_single - gasleft(); + + uint256 gas_start_double = gasleft(); + addInLoopNoGasNoGas(); + uint256 gas_used_double = gas_start_double - gasleft(); + + emit log_named_uint("Normal gas", gas_used_normal); + emit log_named_uint("Single modifier gas", gas_used_single); + emit log_named_uint("Double modifier gas", gas_used_double); + assertTrue(gas_used_double + gas_used_single < gas_used_normal); + } + + function addInLoop() internal pure returns (uint256) { + uint256 b; + for (uint256 i; i < 10000; i++) { + b += i; + } + return b; + } + + function addInLoopNoGas() internal noGasMetering returns (uint256) { + return addInLoop(); + } + + function addInLoopNoGasNoGas() internal noGasMetering returns (uint256) { + return addInLoopNoGas(); + } + + function bytesToUint_test(bytes memory b) private pure returns (uint256) { + uint256 number; + for (uint256 i = 0; i < b.length; i++) { + number = number + uint256(uint8(b[i])) * (2 ** (8 * (b.length - (i + 1)))); + } + return number; + } + + function testAssumeNoPrecompiles(address addr) external { + assumeNoPrecompiles(addr, getChain("optimism_goerli").chainId); + assertTrue( + addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) + || addr > address(0x4200000000000000000000000000000000000800) + ); + } + + function testAssumePayable() external { + // all should revert since these addresses are not payable + + // VM address + vm.expectRevert(); + assumePayable(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + // Console address + vm.expectRevert(); + assumePayable(0x000000000000000000636F6e736F6c652e6c6f67); + + // Create2Deployer + vm.expectRevert(); + assumePayable(0x4e59b44847b379578588920cA78FbF26c0B4956C); + } + + function testAssumePayable(address addr) external { + assumePayable(addr); + assertTrue( + addr != 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D && addr != 0x000000000000000000636F6e736F6c652e6c6f67 + && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C + ); + } +} + +contract Bar { + constructor() payable { + /// `DEAL` STDCHEAT + totalSupply = 10000e18; + balanceOf[address(this)] = totalSupply; + } + + /// `HOAX` STDCHEATS + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } + + function origin(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedSender, "!prank"); + } + + function origin(address expectedSender, address expectedOrigin) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedOrigin, "!prank"); + } + + /// `DEAL` STDCHEAT + mapping(address => uint256) public balanceOf; + uint256 public totalSupply; +} + +contract RevertingContract { + constructor() { + revert(); + } +} diff --git a/lib/crytic/lib/forge-std/test/StdError.t.sol b/lib/crytic/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..ccd3efa --- /dev/null +++ b/lib/crytic/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdError.sol"; +import "../src/Test.sol"; + +contract StdErrorsTest is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectAssertion() public { + vm.expectRevert(stdError.assertionError); + test.assertionError(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } + + function testExpectDiv() public { + vm.expectRevert(stdError.divisionError); + test.divError(0); + } + + function testExpectMod() public { + vm.expectRevert(stdError.divisionError); + test.modError(0); + } + + function testExpectEnum() public { + vm.expectRevert(stdError.enumConversionError); + test.enumConversion(1); + } + + function testExpectEncodeStg() public { + vm.expectRevert(stdError.encodeStorageError); + test.encodeStgError(); + } + + function testExpectPop() public { + vm.expectRevert(stdError.popError); + test.pop(); + } + + function testExpectOOB() public { + vm.expectRevert(stdError.indexOOBError); + test.indexOOBError(1); + } + + function testExpectMem() public { + vm.expectRevert(stdError.memOverflowError); + test.mem(); + } + + function testExpectIntern() public { + vm.expectRevert(stdError.zeroVarError); + test.intern(); + } +} + +contract ErrorsTest { + enum T {T1} + + uint256[] public someArr; + bytes someBytes; + + function assertionError() public pure { + assert(false); + } + + function arithmeticError(uint256 a) public pure { + a -= 100; + } + + function divError(uint256 a) public pure { + 100 / a; + } + + function modError(uint256 a) public pure { + 100 % a; + } + + function enumConversion(uint256 a) public pure { + T(a); + } + + function encodeStgError() public { + /// @solidity memory-safe-assembly + assembly { + sstore(someBytes.slot, 1) + } + keccak256(someBytes); + } + + function pop() public { + someArr.pop(); + } + + function indexOOBError(uint256 a) public pure { + uint256[] memory t = new uint256[](0); + t[a]; + } + + function mem() public pure { + uint256 l = 2 ** 256 / 32; + new uint256[](l); + } + + function intern() public returns (uint256) { + function(uint256) internal returns (uint256) x; + x(2); + return 7; + } +} diff --git a/lib/crytic/lib/forge-std/test/StdMath.t.sol b/lib/crytic/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..95037ea --- /dev/null +++ b/lib/crytic/lib/forge-std/test/StdMath.t.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdMath.sol"; +import "../src/Test.sol"; + +contract StdMathTest is Test { + function testGetAbs() external { + assertEq(stdMath.abs(-50), 50); + assertEq(stdMath.abs(50), 50); + assertEq(stdMath.abs(-1337), 1337); + assertEq(stdMath.abs(0), 0); + + assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1); + assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1)); + } + + function testGetAbs_Fuzz(int256 a) external { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function testGetDelta_Uint() external { + assertEq(stdMath.delta(uint256(0), uint256(0)), 0); + assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337); + assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max); + assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max); + assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max); + + assertEq(stdMath.delta(0, uint256(0)), 0); + assertEq(stdMath.delta(1337, uint256(0)), 1337); + assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max); + assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max); + assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max); + + assertEq(stdMath.delta(1337, uint256(1337)), 0); + assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0); + assertEq(stdMath.delta(5000, uint256(1250)), 3750); + } + + function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external { + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetDelta_Int() external { + assertEq(stdMath.delta(int256(0), int256(0)), 0); + assertEq(stdMath.delta(int256(0), int256(1337)), 1337); + assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1); + assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1); + assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1); + + assertEq(stdMath.delta(0, int256(0)), 0); + assertEq(stdMath.delta(1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1); + assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1); + assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1); + + assertEq(stdMath.delta(-0, int256(0)), 0); + assertEq(stdMath.delta(-1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(int256(0), -0), 0); + assertEq(stdMath.delta(int256(0), -1337), 1337); + assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(1337, int256(1337)), 0); + assertEq(stdMath.delta(type(int256).max, type(int256).max), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).min), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max); + assertEq(stdMath.delta(5000, int256(1250)), 3750); + } + + function testGetDelta_Int_Fuzz(int256 a, int256 b) external { + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetPercentDelta_Uint() external { + assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); + assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); + assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); + assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(uint256(1), 0); + } + + function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external { + vm.assume(b != 0); + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / b; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + function testGetPercentDelta_Int() external { + assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); + assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, int256(1337)), 0); + assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); + assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); + + assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, int256(2500)), 0); + assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(int256(1), 0); + } + + function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external { + vm.assume(b != 0); + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / absB; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function getAbs(int256 a) private pure returns (uint256) { + if (a < 0) { + return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); + } + + return uint256(a); + } +} diff --git a/lib/crytic/lib/forge-std/test/StdStorage.t.sol b/lib/crytic/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..d4c563a --- /dev/null +++ b/lib/crytic/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdStorage.sol"; +import "../src/Test.sol"; + +contract StdStorageTest is Test { + using stdStorage for StdStorage; + + StorageTest internal test; + + function setUp() public { + test = new StorageTest(); + } + + function testStorageHidden() public { + assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find()); + } + + function testStorageObvious() public { + assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find()); + } + + function testStorageCheckedWriteHidden() public { + stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100); + assertEq(uint256(test.hidden()), 100); + } + + function testStorageCheckedWriteObvious() public { + stdstore.target(address(test)).sig(test.exists.selector).checked_write(100); + assertEq(test.exists(), 100); + } + + function testStorageMapStructA() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot); + } + + function testStorageMapStructB() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot); + } + + function testStorageDeepMap() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key( + address(this) + ).find(); + assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(5)))))), slot); + } + + function testStorageCheckedWriteDeepMap() public { + stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(address(this)) + .checked_write(100); + assertEq(100, test.deep_map(address(this), address(this))); + } + + function testStorageDeepMapStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(0).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 0), + bytes32(slot) + ); + } + + function testStorageDeepMapStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(1).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 1), + bytes32(slot) + ); + } + + function testStorageCheckedWriteDeepMapStructA() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(100, a); + assertEq(0, b); + } + + function testStorageCheckedWriteDeepMapStructB() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(0, a); + assertEq(100, b); + } + + function testStorageCheckedWriteMapStructA() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 100); + assertEq(b, 0); + } + + function testStorageCheckedWriteMapStructB() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 0); + assertEq(b, 100); + } + + function testStorageStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find(); + assertEq(uint256(7), slot); + } + + function testStorageStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find(); + assertEq(uint256(7) + 1, slot); + } + + function testStorageCheckedWriteStructA() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 100); + assertEq(b, 1337); + } + + function testStorageCheckedWriteStructB() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 1337); + assertEq(b, 100); + } + + function testStorageMapAddrFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find(); + assertEq(uint256(keccak256(abi.encode(address(this), uint256(1)))), slot); + } + + function testStorageMapUintFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find(); + assertEq(uint256(keccak256(abi.encode(100, uint256(2)))), slot); + } + + function testStorageCheckedWriteMapUint() public { + stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100); + assertEq(100, test.map_uint(100)); + } + + function testStorageCheckedWriteMapAddr() public { + stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100); + assertEq(100, test.map_addr(address(this))); + } + + function testStorageCheckedWriteMapBool() public { + stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true); + assertTrue(test.map_bool(address(this))); + } + + function testFailStorageCheckedWriteMapPacked() public { + // expect PackedSlot error but not external call so cant expectRevert + stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))) + .checked_write(100); + } + + function testStorageCheckedWriteMapPackedSuccess() public { + uint256 full = test.map_packed(address(1337)); + // keep upper 128, set lower 128 to 1337 + full = (full & (uint256((1 << 128) - 1) << 128)) | 1337; + stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write( + full + ); + assertEq(1337, test.read_struct_lower(address(1337))); + } + + function testFailStorageConst() public { + // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()")))); + stdstore.target(address(test)).sig("const()").find(); + } + + function testFailStorageNativePack() public { + stdstore.target(address(test)).sig(test.tA.selector).find(); + stdstore.target(address(test)).sig(test.tB.selector).find(); + + // these both would fail + stdstore.target(address(test)).sig(test.tC.selector).find(); + stdstore.target(address(test)).sig(test.tD.selector).find(); + } + + function testStorageReadBytes32() public { + bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32(); + assertEq(val, hex"1337"); + } + + function testStorageReadBool_False() public { + bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool(); + assertEq(val, false); + } + + function testStorageReadBool_True() public { + bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool(); + assertEq(val, true); + } + + function testStorageReadBool_Revert() public { + vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + this.readNonBoolValue(); + } + + function readNonBoolValue() public { + stdstore.target(address(test)).sig(test.tE.selector).read_bool(); + } + + function testStorageReadAddress() public { + address val = stdstore.target(address(test)).sig(test.tF.selector).read_address(); + assertEq(val, address(1337)); + } + + function testStorageReadUint() public { + uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint(); + assertEq(val, 1); + } + + function testStorageReadInt() public { + int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int(); + assertEq(val, type(int256).min); + } +} + +contract StorageTest { + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + mapping(uint256 => uint256) public map_uint; + mapping(address => uint256) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basic; + + uint248 public tA; + bool public tB; + + bool public tC = false; + uint248 public tD = 1; + + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + mapping(address => bool) public map_bool; + + bytes32 public tE = hex"1337"; + address public tF = address(1337); + int256 public tG = type(int256).min; + bool public tH = true; + + constructor() { + basic = UnpackedStruct({a: 1337, b: 1337}); + + uint256 two = (1 << 128) | 1; + map_packed[msg.sender] = two; + map_packed[address(uint160(1337))] = 1 << 128; + } + + function read_struct_upper(address who) public view returns (uint256) { + return map_packed[who] >> 128; + } + + function read_struct_lower(address who) public view returns (uint256) { + return map_packed[who] & ((1 << 128) - 1); + } + + function hidden() public view returns (bytes32 t) { + bytes32 slot = keccak256("my.random.var"); + /// @solidity memory-safe-assembly + assembly { + t := sload(slot) + } + } + + function const() public pure returns (bytes32 t) { + t = bytes32(hex"1337"); + } +} diff --git a/lib/crytic/lib/forge-std/test/StdUtils.t.sol b/lib/crytic/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..a085b19 --- /dev/null +++ b/lib/crytic/lib/forge-std/test/StdUtils.t.sol @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdUtilsMock is StdUtils { + // We deploy a mock version so we can properly test expected reverts. + function getTokenBalances_(address token, address[] memory addresses) + external + returns (uint256[] memory balances) + { + return getTokenBalances(token, addresses); + } +} + +contract StdUtilsTest is Test { + /*////////////////////////////////////////////////////////////////////////// + BOUND UINT + //////////////////////////////////////////////////////////////////////////*/ + + function testBound() public { + assertEq(bound(uint256(5), 0, 4), 0); + assertEq(bound(uint256(0), 69, 69), 69); + assertEq(bound(uint256(0), 68, 69), 68); + assertEq(bound(uint256(10), 150, 190), 174); + assertEq(bound(uint256(300), 2800, 3200), 3107); + assertEq(bound(uint256(9999), 1337, 6666), 4669); + } + + function testBound_WithinRange() public { + assertEq(bound(uint256(51), 50, 150), 51); + assertEq(bound(uint256(51), 50, 150), bound(bound(uint256(51), 50, 150), 50, 150)); + assertEq(bound(uint256(149), 50, 150), 149); + assertEq(bound(uint256(149), 50, 150), bound(bound(uint256(149), 50, 150), 50, 150)); + } + + function testBound_EdgeCoverage() public { + assertEq(bound(uint256(0), 50, 150), 50); + assertEq(bound(uint256(1), 50, 150), 51); + assertEq(bound(uint256(2), 50, 150), 52); + assertEq(bound(uint256(3), 50, 150), 53); + assertEq(bound(type(uint256).max, 50, 150), 150); + assertEq(bound(type(uint256).max - 1, 50, 150), 149); + assertEq(bound(type(uint256).max - 2, 50, 150), 148); + assertEq(bound(type(uint256).max - 3, 50, 150), 147); + } + + function testBound_DistributionIsEven(uint256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, UINT256_MAX / 2, UINT256_MAX / 2 + size); + uint256 max = min + size - 1; + uint256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + i, min, max); + assertEq(result, min + (i - 1) % size); + // x < min + result = bound(min - i, min, max); + assertEq(result, max - (i - 1) % size); + } + } + + function testBound(uint256 num, uint256 min, uint256 max) public { + if (min > max) (min, max) = (max, min); + + uint256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundUint256Max() public { + assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1); + assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max); + } + + function testCannotBoundMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(uint256(5), 100, 10); + } + + function testCannotBoundMaxLessThanMin(uint256 num, uint256 min, uint256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(num, min, max); + } + + /*////////////////////////////////////////////////////////////////////////// + BOUND INT + //////////////////////////////////////////////////////////////////////////*/ + + function testBoundInt() public { + assertEq(bound(-3, 0, 4), 2); + assertEq(bound(0, -69, -69), -69); + assertEq(bound(0, -69, -68), -68); + assertEq(bound(-10, 150, 190), 154); + assertEq(bound(-300, 2800, 3200), 2908); + assertEq(bound(9999, -1337, 6666), 1995); + } + + function testBoundInt_WithinRange() public { + assertEq(bound(51, -50, 150), 51); + assertEq(bound(51, -50, 150), bound(bound(51, -50, 150), -50, 150)); + assertEq(bound(149, -50, 150), 149); + assertEq(bound(149, -50, 150), bound(bound(149, -50, 150), -50, 150)); + } + + function testBoundInt_EdgeCoverage() public { + assertEq(bound(type(int256).min, -50, 150), -50); + assertEq(bound(type(int256).min + 1, -50, 150), -49); + assertEq(bound(type(int256).min + 2, -50, 150), -48); + assertEq(bound(type(int256).min + 3, -50, 150), -47); + assertEq(bound(type(int256).min, 10, 150), 10); + assertEq(bound(type(int256).min + 1, 10, 150), 11); + assertEq(bound(type(int256).min + 2, 10, 150), 12); + assertEq(bound(type(int256).min + 3, 10, 150), 13); + + assertEq(bound(type(int256).max, -50, 150), 150); + assertEq(bound(type(int256).max - 1, -50, 150), 149); + assertEq(bound(type(int256).max - 2, -50, 150), 148); + assertEq(bound(type(int256).max - 3, -50, 150), 147); + assertEq(bound(type(int256).max, -50, -10), -10); + assertEq(bound(type(int256).max - 1, -50, -10), -11); + assertEq(bound(type(int256).max - 2, -50, -10), -12); + assertEq(bound(type(int256).max - 3, -50, -10), -13); + } + + function testBoundInt_DistributionIsEven(int256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, -int256(size / 2), int256(size - size / 2)); + int256 max = min + int256(size) - 1; + int256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + int256(i), min, max); + assertEq(result, min + int256((i - 1) % size)); + // x < min + result = bound(min - int256(i), min, max); + assertEq(result, max - int256((i - 1) % size)); + } + } + + function testBoundInt(int256 num, int256 min, int256 max) public { + if (min > max) (min, max) = (max, min); + + int256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundIntInt256Max() public { + assertEq(bound(0, type(int256).max - 1, type(int256).max), type(int256).max - 1); + assertEq(bound(1, type(int256).max - 1, type(int256).max), type(int256).max); + } + + function testBoundIntInt256Min() public { + assertEq(bound(0, type(int256).min, type(int256).min + 1), type(int256).min); + assertEq(bound(1, type(int256).min, type(int256).min + 1), type(int256).min + 1); + } + + function testCannotBoundIntMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(-5, 100, 10); + } + + function testCannotBoundIntMaxLessThanMin(int256 num, int256 min, int256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(num, min, max); + } + + /*////////////////////////////////////////////////////////////////////////// + BYTES TO UINT + //////////////////////////////////////////////////////////////////////////*/ + + function testBytesToUint() external { + bytes memory maxUint = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + bytes memory two = hex"02"; + bytes memory millionEther = hex"d3c21bcecceda1000000"; + + assertEq(bytesToUint(maxUint), type(uint256).max); + assertEq(bytesToUint(two), 2); + assertEq(bytesToUint(millionEther), 1_000_000 ether); + } + + function testCannotConvertGT32Bytes() external { + bytes memory thirty3Bytes = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + vm.expectRevert("StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + bytesToUint(thirty3Bytes); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function testComputeCreateAddress() external { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE2 ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function testComputeCreate2Address() external { + bytes32 salt = bytes32(uint256(31415)); + bytes32 initcodeHash = keccak256(abi.encode(0x6080)); + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + address create2Address = computeCreate2Address(salt, initcodeHash, deployer); + assertEq(create2Address, 0xB147a5d25748fda14b463EB04B111027C290f4d3); + } + + function testComputeCreate2AddressWithDefaultDeployer() external { + bytes32 salt = 0xc290c670fde54e5ef686f9132cbc8711e76a98f0333a438a92daa442c71403c0; + bytes32 initcodeHash = hashInitCode(hex"6080", ""); + assertEq(initcodeHash, 0x1a578b7a4b0b5755db6d121b4118d4bc68fe170dca840c59bc922f14175a76b0); + address create2Address = computeCreate2Address(salt, initcodeHash); + assertEq(create2Address, 0xc0ffEe2198a06235aAbFffe5Db0CacF1717f5Ac6); + } +} + +contract StdUtilsForkTest is Test { + /*////////////////////////////////////////////////////////////////////////// + GET TOKEN BALANCES + //////////////////////////////////////////////////////////////////////////*/ + + address internal SHIB = 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE; + address internal SHIB_HOLDER_0 = 0x855F5981e831D83e6A4b4EBFCAdAa68D92333170; + address internal SHIB_HOLDER_1 = 0x8F509A90c2e47779cA408Fe00d7A72e359229AdA; + address internal SHIB_HOLDER_2 = 0x0e3bbc0D04fF62211F71f3e4C45d82ad76224385; + + address internal USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address internal USDC_HOLDER_0 = 0xDa9CE944a37d218c3302F6B82a094844C6ECEb17; + address internal USDC_HOLDER_1 = 0x3e67F4721E6d1c41a015f645eFa37BEd854fcf52; + + function setUp() public { + // All tests of the `getTokenBalances` method are fork tests using live contracts. + vm.createSelectFork({urlOrAlias: "mainnet", blockNumber: 16_428_900}); + } + + function testCannotGetTokenBalances_NonTokenContract() external { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + // The UniswapV2Factory contract has neither a `balanceOf` function nor a fallback function, + // so the `balanceOf` call should revert. + address token = address(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); + address[] memory addresses = new address[](1); + addresses[0] = USDC_HOLDER_0; + + vm.expectRevert("Multicall3: call failed"); + stdUtils.getTokenBalances_(token, addresses); + } + + function testCannotGetTokenBalances_EOA() external { + address eoa = vm.addr({privateKey: 1}); + address[] memory addresses = new address[](1); + addresses[0] = USDC_HOLDER_0; + vm.expectRevert("StdUtils getTokenBalances(address,address[]): Token address is not a contract."); + getTokenBalances(eoa, addresses); + } + + function testGetTokenBalances_Empty() external { + address[] memory addresses = new address[](0); + uint256[] memory balances = getTokenBalances(USDC, addresses); + assertEq(balances.length, 0); + } + + function testGetTokenBalances_USDC() external { + address[] memory addresses = new address[](2); + addresses[0] = USDC_HOLDER_0; + addresses[1] = USDC_HOLDER_1; + uint256[] memory balances = getTokenBalances(USDC, addresses); + assertEq(balances[0], 159_000_000_000_000); + assertEq(balances[1], 131_350_000_000_000); + } + + function testGetTokenBalances_SHIB() external { + address[] memory addresses = new address[](3); + addresses[0] = SHIB_HOLDER_0; + addresses[1] = SHIB_HOLDER_1; + addresses[2] = SHIB_HOLDER_2; + uint256[] memory balances = getTokenBalances(SHIB, addresses); + assertEq(balances[0], 3_323_256_285_484.42e18); + assertEq(balances[1], 1_271_702_771_149.99999928e18); + assertEq(balances[2], 606_357_106_247e18); + } +} diff --git a/lib/crytic/lib/forge-std/test/compilation/CompilationScript.sol b/lib/crytic/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..e205cff --- /dev/null +++ b/lib/crytic/lib/forge-std/test/compilation/CompilationScript.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScript is Script {} diff --git a/lib/crytic/lib/forge-std/test/compilation/CompilationScriptBase.sol b/lib/crytic/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..ce8e0e9 --- /dev/null +++ b/lib/crytic/lib/forge-std/test/compilation/CompilationScriptBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScriptBase is ScriptBase {} diff --git a/lib/crytic/lib/forge-std/test/compilation/CompilationTest.sol b/lib/crytic/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..9beeafe --- /dev/null +++ b/lib/crytic/lib/forge-std/test/compilation/CompilationTest.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTest is Test {} diff --git a/lib/crytic/lib/forge-std/test/compilation/CompilationTestBase.sol b/lib/crytic/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..e993535 --- /dev/null +++ b/lib/crytic/lib/forge-std/test/compilation/CompilationTestBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTestBase is TestBase {} diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/beige-buses-drop.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/beige-buses-drop.md new file mode 100644 index 0000000..4566ecc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/beige-buses-drop.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. ([#3787](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3787)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/config.json b/lib/crytic/lib/openzeppelin-contracts/.changeset/config.json new file mode 100644 index 0000000..66794fa --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/config.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", + "changelog": [ + "@changesets/changelog-github", + { + "repo": "OpenZeppelin/openzeppelin-contracts" + } + ], + "commit": false, + "access": "public", + "baseBranch": "master" +} diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/curvy-shrimps-enjoy.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/curvy-shrimps-enjoy.md new file mode 100644 index 0000000..4bc410a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/curvy-shrimps-enjoy.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/curvy-suns-sort.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/curvy-suns-sort.md new file mode 100644 index 0000000..97b51fe --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/curvy-suns-sort.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. ([#3960](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3960)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/early-oranges-raise.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/early-oranges-raise.md new file mode 100644 index 0000000..af60a44 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/famous-rules-burn.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/famous-rules-burn.md new file mode 100644 index 0000000..a746dc2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/famous-rules-burn.md @@ -0,0 +1,5 @@ +--- +'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)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/five-ducks-develop.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/five-ducks-develop.md new file mode 100644 index 0000000..fe25db0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/five-poets-mix.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/five-poets-mix.md new file mode 100644 index 0000000..f5050b2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/flat-deers-end.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/flat-deers-end.md new file mode 100644 index 0000000..61895f2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/flat-deers-end.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`Governor`: add a public `cancel(uint256)` function. diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/four-bats-sniff.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/four-bats-sniff.md new file mode 100644 index 0000000..137b5e5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/funny-rockets-compete.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/funny-rockets-compete.md new file mode 100644 index 0000000..a8c77c6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/funny-rockets-compete.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +Reformatted codebase with latest version of Prettier Solidity. ([#3898](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3898)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/gold-chicken-clean.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/gold-chicken-clean.md new file mode 100644 index 0000000..0d64fde --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/gold-chicken-clean.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`Strings`: add `equal` method. ([#3774](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3774)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/happy-socks-travel.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/happy-socks-travel.md new file mode 100644 index 0000000..b29d6ba --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/healthy-squids-stare.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/healthy-squids-stare.md new file mode 100644 index 0000000..fad0872 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/healthy-squids-stare.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/lemon-dogs-kiss.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/lemon-dogs-kiss.md new file mode 100644 index 0000000..976949d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/lemon-dogs-kiss.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/little-kiwis-ring.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/little-kiwis-ring.md new file mode 100644 index 0000000..a1cb7bb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/little-kiwis-ring.md @@ -0,0 +1,5 @@ +--- +'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)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/lovely-dragons-appear.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/lovely-dragons-appear.md new file mode 100644 index 0000000..fe53863 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/many-panthers-hide.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/many-panthers-hide.md new file mode 100644 index 0000000..5f04c99 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/many-panthers-hide.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`TransparentUpgradeableProxy`: support value passthrough for all ifAdmin function. diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/modern-games-exist.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/modern-games-exist.md new file mode 100644 index 0000000..bd89b4f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/modern-games-exist.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`StorageSlot`: Add support for `string` and `bytes`. diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/new-ways-own.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/new-ways-own.md new file mode 100644 index 0000000..f940bfe --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/ninety-hornets-kick.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/ninety-hornets-kick.md new file mode 100644 index 0000000..16886c5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/ninety-hornets-kick.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`Votes`, `ERC20Votes`, `ERC721Votes`: support timestamp checkpointing using EIP-6372. diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/perfect-insects-listen.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/perfect-insects-listen.md new file mode 100644 index 0000000..9e60120 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/pretty-hornets-play.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/pretty-hornets-play.md new file mode 100644 index 0000000..230a53b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/pretty-hornets-play.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`Strings`: add `toString` method for signed integers. ([#3773](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3773)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/proud-comics-deliver.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/proud-comics-deliver.md new file mode 100644 index 0000000..e9c1015 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/short-roses-judge.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/short-roses-judge.md new file mode 100644 index 0000000..002aebb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/short-roses-judge.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`EIP712`: add EIP-5267 support for better domain discovery. diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/slimy-knives-hug.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/slimy-knives-hug.md new file mode 100644 index 0000000..94099ee --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/small-cars-appear.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/small-cars-appear.md new file mode 100644 index 0000000..0263bcd --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/strong-bulldogs-buy.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/strong-bulldogs-buy.md new file mode 100644 index 0000000..001b0f8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/tame-ladybugs-sit.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/tame-ladybugs-sit.md new file mode 100644 index 0000000..8a1e416 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/tame-ladybugs-sit.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': patch +--- + +`MerkleProof`: optimize by using unchecked arithmetic. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/thin-dragons-report.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/thin-dragons-report.md new file mode 100644 index 0000000..b73730f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/thirty-swans-exercise.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/thirty-swans-exercise.md new file mode 100644 index 0000000..a460271 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.changeset/thirty-swans-exercise.md @@ -0,0 +1,5 @@ +--- +'openzeppelin-solidity': minor +--- + +`ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`. diff --git a/lib/crytic/lib/openzeppelin-contracts/.changeset/violet-frogs-hide.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/violet-frogs-hide.md new file mode 100644 index 0000000..21d2bf9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.changeset/yellow-swans-cover.md b/lib/crytic/lib/openzeppelin-contracts/.changeset/yellow-swans-cover.md new file mode 100644 index 0000000..ee16801 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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/lib/crytic/lib/openzeppelin-contracts/.codecov.yml b/lib/crytic/lib/openzeppelin-contracts/.codecov.yml new file mode 100644 index 0000000..9455306 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.codecov.yml @@ -0,0 +1,12 @@ +comment: off +github_checks: + annotations: false +coverage: + status: + patch: + default: + target: 95% + only_pulls: true + project: + default: + threshold: 1% diff --git a/lib/crytic/lib/openzeppelin-contracts/.editorconfig b/lib/crytic/lib/openzeppelin-contracts/.editorconfig new file mode 100644 index 0000000..f162e8d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = false +max_line_length = 120 + +[*.sol] +indent_size = 4 + +[*.js] +indent_size = 2 + +[*.{adoc,md}] +max_line_length = 0 diff --git a/lib/crytic/lib/openzeppelin-contracts/.eslintrc b/lib/crytic/lib/openzeppelin-contracts/.eslintrc new file mode 100644 index 0000000..a5418c5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.eslintrc @@ -0,0 +1,20 @@ +{ + "root": true, + "extends" : [ + "eslint:recommended", + "prettier", + ], + "env": { + "es2022": true, + "browser": true, + "node": true, + "mocha": true, + }, + "globals" : { + "artifacts": "readonly", + "contract": "readonly", + "web3": "readonly", + "extendEnvironment": "readonly", + "expect": "readonly", + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md b/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..2797a08 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,21 @@ +--- +name: Bug report +about: Report a bug in OpenZeppelin Contracts + +--- + + + + + +**💻 Environment** + + + +**📝 Details** + + + +**🔢 Code to reproduce bug** + + diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml b/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..4018cef --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: + - name: Questions & Support Requests + url: https://forum.openzeppelin.com/c/support/contracts/18 + about: Ask in the OpenZeppelin Forum diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md b/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..ff596b0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,14 @@ +--- +name: Feature request +about: Suggest an idea for OpenZeppelin Contracts + +--- + +**🧐 Motivation** + + +**📝 Details** + + + + diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md b/lib/crytic/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2394518 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,20 @@ + + + + + +Fixes #???? + + + + + +#### PR Checklist + + + + + +- [ ] Tests +- [ ] Documentation +- [ ] Changeset entry (run `npx changeset add`) diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml b/lib/crytic/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml new file mode 100644 index 0000000..e38c48e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml @@ -0,0 +1,49 @@ +name: Compare gas costs +inputs: + token: + description: github token + required: true + report: + description: report to read from + required: false + default: gasReporterOutput.json + out_report: + description: report to read + required: false + default: ${{ github.ref_name }}.gasreport.json + ref_report: + description: report to read from + required: false + default: ${{ github.base_ref }}.gasreport.json + +runs: + using: composite + steps: + - name: Download reference report + 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 gasreport + env: + GITHUB_TOKEN: ${{ inputs.token }} + shell: bash + continue-on-error: true + id: reference + - name: Compare reports + if: steps.reference.outcome == 'success' && github.event_name == 'pull_request' + run: | + node scripts/checks/compareGasReports.js ${{ inputs.report }} ${{ inputs.ref_report }} >> $GITHUB_STEP_SUMMARY + env: + STYLE: markdown + shell: bash + - name: Rename report for upload + if: github.event_name != 'pull_request' + run: | + mv ${{ inputs.report }} ${{ inputs.out_report }} + shell: bash + - name: Save report + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: gasreport + path: ${{ inputs.out_report }} diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/actions/setup/action.yml b/lib/crytic/lib/openzeppelin-contracts/.github/actions/setup/action.yml new file mode 100644 index 0000000..680fba0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/actions/setup/action.yml @@ -0,0 +1,19 @@ +name: Setup + +runs: + using: composite + steps: + - uses: actions/setup-node@v3 + with: + node-version: 14.x + - uses: actions/cache@v3 + id: cache + with: + path: '**/node_modules' + key: npm-v3-${{ hashFiles('**/package-lock.json') }} + - name: Install dependencies + run: npm ci + shell: bash + if: steps.cache.outputs.cache-hit != 'true' + env: + SKIP_COMPILE: true diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml b/lib/crytic/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml new file mode 100644 index 0000000..fdfd5a2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.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 }} + 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/lib/crytic/lib/openzeppelin-contracts/.github/workflows/actionlint.yml b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/actionlint.yml new file mode 100644 index 0000000..8193109 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/actionlint.yml @@ -0,0 +1,18 @@ +name: lint workflows + +on: + pull_request: + paths: + - '.github/**/*.ya?ml' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Add problem matchers + run: | + # https://github.com/rhysd/actionlint/blob/3a2f2c7/docs/usage.md#problem-matchers + curl -LO https://raw.githubusercontent.com/rhysd/actionlint/main/.github/actionlint-matcher.json + echo "::add-matcher::actionlint-matcher.json" + - uses: docker://rhysd/actionlint:latest diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/workflows/changeset.yml b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/changeset.yml new file mode 100644 index 0000000..5fe70cf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/changeset.yml @@ -0,0 +1,28 @@ +name: changeset + +on: + pull_request: + branches: + - master + types: + - opened + - synchronize + - labeled + - unlabeled + +concurrency: + group: changeset-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + if: ${{ !contains(github.event.pull_request.labels.*.name, 'ignore-changeset') }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # Include history so Changesets finds merge-base + - name: Set up environment + uses: ./.github/actions/setup + - name: Check changeset + run: npx changeset status --since=origin/${{ github.base_ref }} diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/workflows/checks.yml b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/checks.yml new file mode 100644 index 0000000..c37bf93 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/checks.yml @@ -0,0 +1,96 @@ +name: checks + +on: + push: + branches: + - master + - release-v* + pull_request: {} + workflow_dispatch: {} + +concurrency: + group: checks-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: npm run lint + + tests: + runs-on: ubuntu-latest + env: + FORCE_COLOR: 1 + NODE_OPTIONS: --max_old_space_size=4096 + GAS: true + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - name: Run tests and generate gas report + run: npm run test + - 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 }} + - name: Check storage layout + uses: ./.github/actions/storage-layout + with: + token: ${{ github.token }} + + foundry-tests: + if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + - name: Run tests + run: forge test -vv + + coverage: + if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: npm run coverage + env: + NODE_OPTIONS: --max_old_space_size=4096 + - uses: codecov/codecov-action@v3 + + slither: + if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: rm foundry.toml + - uses: crytic/slither-action@v0.3.0 + + codespell: + if: github.repository != 'OpenZeppelin/openzeppelin-contracts-upgradeable' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Run CodeSpell + uses: codespell-project/actions-codespell@v1.0 + with: + check_filenames: true + skip: package-lock.json,*.pdf diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/workflows/docs.yml b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/docs.yml new file mode 100644 index 0000000..4b54ea6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/docs.yml @@ -0,0 +1,19 @@ +name: Build Docs + +on: + push: + branches: [release-v*] + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - run: node scripts/update-docs-branch.js + - run: git push --all origin diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml new file mode 100644 index 0000000..2fd6645 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml @@ -0,0 +1,214 @@ +# 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: + push: + branches: + - release-v* + workflow_dispatch: {} + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + state: + name: Check state + permissions: + pull-requests: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - id: state + name: Get state + uses: actions/github-script@v6 + env: + TRIGGERING_ACTOR: ${{ github.triggering_actor }} + with: + result-encoding: string + script: await require('./scripts/release/workflow/state.js')({ github, context, core }) + outputs: + # Job Flags + start: ${{ steps.state.outputs.start }} + changesets: ${{ steps.state.outputs.changesets }} + promote: ${{ steps.state.outputs.promote }} + publish: ${{ steps.state.outputs.publish }} + merge: ${{ steps.state.outputs.merge }} + + # Global variables + is_prerelease: ${{ steps.state.outputs.is_prerelease }} + + start: + needs: state + name: Start new release candidate + permissions: + contents: write + actions: write + if: needs.state.outputs.start == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - id: start + name: Create branch with release candidate + run: bash scripts/release/workflow/start.sh + - name: Re-run workflow + uses: actions/github-script@v6 + env: + REF: ${{ steps.start.outputs.branch }} + with: + script: await require('./scripts/release/workflow/rerun.js')({ github, context }) + + promote: + needs: state + name: Promote to final release + permissions: + contents: write + actions: write + if: needs.state.outputs.promote == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Exit prerelease state + if: needs.state.outputs.is_prerelease == 'true' + run: bash scripts/release/workflow/exit-prerelease.sh + - name: Re-run workflow + uses: actions/github-script@v6 + with: + script: await require('./scripts/release/workflow/rerun.js')({ github, context }) + + changesets: + needs: state + name: Update PR to release + permissions: + contents: write + pull-requests: write + if: needs.state.outputs.changesets == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # To get all tags + - name: Set up environment + uses: ./.github/actions/setup + - name: Set release title + uses: actions/github-script@v6 + with: + result-encoding: string + script: await require('./scripts/release/workflow/set-changesets-pr-title.js')({ core }) + - name: Create PR + uses: changesets/action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRERELEASE: ${{ needs.state.outputs.is_prerelease }} + with: + version: npm run version + title: ${{ env.TITLE }} + commit: ${{ env.TITLE }} + body: | # Wait for support on this https://github.com/changesets/action/pull/250 + This is an automated PR for releasing ${{ github.repository }} + Check [CHANGELOG.md](${{ github.repository }}/CHANGELOG.md) + + publish: + needs: state + name: Publish to npm + environment: npm + permissions: + contents: write + if: needs.state.outputs.publish == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - id: pack + name: Pack + 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 + run: bash scripts/release/workflow/publish.sh + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + TARBALL: ${{ steps.pack.outputs.tarball }} + TAG: ${{ steps.pack.outputs.tag }} + - name: Push tags + run: git push --tags + - name: Create Github Release + uses: actions/github-script@v6 + env: + 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 + name: Create PR back to master + permissions: + contents: write + pull-requests: write + if: needs.state.outputs.merge == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # All branches + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Create branch to merge + run: bash scripts/release/workflow/prepare-release-merge.sh + - name: Create PR back to master + uses: actions/github-script@v6 + with: + script: | + await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head: 'merge/${{ github.ref_name }}', + base: 'master', + title: '${{ format('Merge {0} branch', github.ref_name) }}' + }); diff --git a/lib/crytic/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml new file mode 100644 index 0000000..a7ed8da --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml @@ -0,0 +1,23 @@ +name: Upgradeable Trigger + +on: + push: + branches: + - master + - release-v* + +jobs: + trigger: + runs-on: ubuntu-latest + steps: + - id: app + uses: getsentry/action-github-app-token@v2 + 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 }}" } }' diff --git a/lib/crytic/lib/openzeppelin-contracts/.gitignore b/lib/crytic/lib/openzeppelin-contracts/.gitignore new file mode 100644 index 0000000..9350b26 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.gitignore @@ -0,0 +1,70 @@ +*.swp +*.swo + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +allFiredEvents +scTopics + +# Coverage directory used by tools like istanbul +coverage +coverage.json +coverageEnv + +# node-waf configuration +.lock-wscript + +# Dependency directory +node_modules + +# Debug log from npm +npm-debug.log + +# local env variables +.env + +# truffle build directory +build/ + +# macOS +.DS_Store + +# truffle +.node-xmlhttprequest-* + +# IntelliJ IDE +.idea + +# docs artifacts +docs/modules/api + +# only used to package @openzeppelin/contracts +contracts/build/ +contracts/README.md + +# temporary artifact from solidity-coverage +allFiredEvents +.coverage_artifacts +.coverage_cache +.coverage_contracts + +# hardat-exposed +contracts-exposed + +# Hardhat +/cache +/artifacts + +# Foundry +/out + +# Certora +.certora* +.last_confs +certora_* diff --git a/lib/crytic/lib/openzeppelin-contracts/.gitmodules b/lib/crytic/lib/openzeppelin-contracts/.gitmodules new file mode 100644 index 0000000..aaa229f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.gitmodules @@ -0,0 +1,6 @@ +[submodule "lib/forge-std"] + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "lib/erc4626-tests"] + path = lib/erc4626-tests + url = https://github.com/a16z/erc4626-tests.git diff --git a/lib/crytic/lib/openzeppelin-contracts/.mocharc.js b/lib/crytic/lib/openzeppelin-contracts/.mocharc.js new file mode 100644 index 0000000..920662d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.mocharc.js @@ -0,0 +1,4 @@ +module.exports = { + require: 'hardhat/register', + timeout: 4000, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/.prettierrc b/lib/crytic/lib/openzeppelin-contracts/.prettierrc new file mode 100644 index 0000000..e08e242 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.prettierrc @@ -0,0 +1,14 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all", + "arrowParens": "avoid", + "overrides": [ + { + "files": "*.sol", + "options": { + "singleQuote": false + } + } + ] +} diff --git a/lib/crytic/lib/openzeppelin-contracts/.solcover.js b/lib/crytic/lib/openzeppelin-contracts/.solcover.js new file mode 100644 index 0000000..e0dea5e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.solcover.js @@ -0,0 +1,13 @@ +module.exports = { + norpc: true, + testCommand: 'npm test', + compileCommand: 'npm run compile', + skipFiles: ['mocks'], + providerOptions: { + default_balance_ether: '10000000000000000000000000', + }, + mocha: { + fgrep: '[skip-on-coverage]', + invert: true, + }, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/.solhint.json b/lib/crytic/lib/openzeppelin-contracts/.solhint.json new file mode 100644 index 0000000..7729288 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/.solhint.json @@ -0,0 +1,14 @@ +{ + "rules": { + "no-unused-vars": "error", + "const-name-snakecase": "error", + "contract-name-camelcase": "error", + "event-name-camelcase": "error", + "func-name-mixedcase": "error", + "func-param-name-mixedcase": "error", + "modifier-name-mixedcase": "error", + "private-vars-leading-underscore": "error", + "var-name-mixedcase": "error", + "imports-on-top": "error" + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/CHANGELOG.md b/lib/crytic/lib/openzeppelin-contracts/CHANGELOG.md new file mode 100644 index 0000000..8ad77fe --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/CHANGELOG.md @@ -0,0 +1,663 @@ +# 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)) +- `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) + +- `ERC4626`: Use staticcall instead of call when fetching underlying ERC-20 decimals. ([#3943](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3943)) + +## 4.8.0 (2022-11-08) + +- `TimelockController`: Added a new `admin` constructor parameter that is assigned the admin role instead of the deployer account. ([#3722](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3722)) +- `Initializable`: add internal functions `_getInitializedVersion` and `_isInitializing` ([#3598](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3598)) +- `ERC165Checker`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339)) +- `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468)) +- `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469)) +- `Governor`: make the `relay` function payable, and add support for EOA payments. ([#3730](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3730)) +- `GovernorCompatibilityBravo`: remove unused `using` statements. ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506)) +- `ERC20`: optimize `_transfer`, `_mint` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) +- `ERC20Votes`, `ERC721Votes`: optimize `getPastVotes` for looking up recent checkpoints. ([#3673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3673)) +- `ERC20FlashMint`: add an internal `_flashFee` function for overriding. ([#3551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3551)) +- `ERC4626`: use the same `decimals()` as the underlying asset by default (if available). ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639)) +- `ERC4626`: add internal `_initialConvertToShares` and `_initialConvertToAssets` functions to customize empty vaults behavior. ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639)) +- `ERC721`: optimize transfers by making approval clearing implicit instead of emitting an event. ([#3481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3481)) +- `ERC721`: optimize burn by making approval clearing implicit instead of emitting an event. ([#3538](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3538)) +- `ERC721`: Fix balance accounting when a custom `_beforeTokenTransfer` hook results in a transfer of the token under consideration. ([#3611](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3611)) +- `ERC721`: use unchecked arithmetic for balance updates. ([#3524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3524)) +- `ERC721Consecutive`: Implementation of EIP-2309 that allows batch minting of ERC721 tokens during construction. ([#3311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3311)) +- `ReentrancyGuard`: Reduce code size impact of the modifier by using internal functions. ([#3515](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3515)) +- `SafeCast`: optimize downcasting of signed integers. ([#3565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3565)) +- `ECDSA`: Remove redundant check on the `v` value. ([#3591](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3591)) +- `VestingWallet`: add `releasable` getters. ([#3580](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3580)) +- `VestingWallet`: remove unused library `Math.sol`. ([#3605](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3605)) +- `VestingWallet`: make constructor payable. ([#3665](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3665)) +- `Create2`: optimize address computation by using assembly instead of `abi.encodePacked`. ([#3600](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3600)) +- `Clones`: optimized the assembly to use only the scratch space during deployments, and optimized `predictDeterministicAddress` to use fewer operations. ([#3640](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3640)) +- `Checkpoints`: Use procedural generation to support multiple key/value lengths. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Checkpoints`: Add new lookup mechanisms. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Arrays`: Add `unsafeAccess` functions that allow reading and writing to an element in a storage array bypassing Solidity's "out-of-bounds" check. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Strings`: optimize `toString`. ([#3573](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3573)) +- `Ownable2Step`: extension of `Ownable` that makes the ownership transfers a two step process. ([#3620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620)) +- `Math` and `SignedMath`: optimize function `max` by using `>` instead of `>=`. ([#3679](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3679)) +- `Math`: Add `log2`, `log10` and `log256`. ([#3670](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3670)) +- Arbitrum: Update the vendored arbitrum contracts to match the nitro upgrade. ([#3692](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3692)) + +### Breaking changes + +- `ERC721`: In order to add support for batch minting via `ERC721Consecutive` it was necessary to make a minor breaking change in the internal interface of `ERC721`. Namely, the hooks `_beforeTokenTransfer` and `_afterTokenTransfer` have one additional argument that may need to be added to overrides: + +```diff + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId, ++ uint256 batchSize + ) internal virtual override +``` + +- `ERC4626`: Conversion from shares to assets (and vice-versa) in an empty vault used to consider the possible mismatch between the underlying asset's and the vault's decimals. This initial conversion rate is now set to 1-to-1 irrespective of decimals, which are meant for usability purposes only. The vault now uses the assets decimals by default, so off-chain the numbers should appear the same. Developers overriding the vault decimals to a value that does not match the underlying asset may want to override the `_initialConvertToShares` and `_initialConvertToAssets` to replicate the previous behavior. + +- `TimelockController`: During deployment, the TimelockController used to grant the `TIMELOCK_ADMIN_ROLE` to the deployer and to the timelock itself. The deployer was then expected to renounce this role once configuration of the timelock is over. Failing to renounce that role allows the deployer to change the timelock permissions (but not to bypass the delay for any time-locked actions). The role is no longer given to the deployer by default. A new parameter `admin` can be set to a non-zero address to grant the admin role during construction (to the deployer or any other address). Just like previously, this admin role should be renounced after configuration. If this param is given `address(0)`, the role is not allocated and doesn't need to be revoked. In any case, the timelock itself continues to have this role. + +### Deprecations + +- `EIP712`: Added the file `EIP712.sol` and deprecated `draft-EIP712.sol` since the EIP is no longer a Draft. Developers are encouraged to update their imports. ([#3621](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3621)) + +```diff +-import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; ++import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +``` + +- `ERC721Votes`: Added the file `ERC721Votes.sol` and deprecated `draft-ERC721Votes.sol` since it no longer depends on a Draft EIP (EIP-712). Developers are encouraged to update their imports. ([#3699](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3699)) + +```diff +-import "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol"; ++import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol"; +``` + +### ERC-721 Compatibility Note + +ERC-721 integrators that interpret contract state from events should make sure that they implement the clearing of approval that is implicit in every transfer according to the EIP. Previous versions of OpenZeppelin Contracts emitted an explicit `Approval` event even though it was not required by the specification, and this is no longer the case. + +With the new `ERC721Consecutive` extension, the internal workings of `ERC721` are slightly changed. Custom extensions to ERC721 should be reviewed to ensure they remain correct. The internal functions that should be considered are `_ownerOf` (new), `_beforeTokenTransfer`, and `_afterTokenTransfer`. + +### ERC-4626 Upgrade Note + +Existing `ERC4626` contracts that are upgraded to 4.8 must initialize a new variable that holds the vault token decimals. The recommended way to do this is to use a [reinitializer]: + +[reinitializer]: https://docs.openzeppelin.com/contracts/4.x/api/proxy#Initializable-reinitializer-uint8- + +```solidity +function migrateToV48() public reinitializer(2) { + __ERC4626_init(IERC20Upgradeable(asset())); +} +``` + +## 4.7.3 (2022-08-10) + +### Breaking changes + +- `ECDSA`: `recover(bytes32,bytes)` and `tryRecover(bytes32,bytes)` no longer accept compact signatures to prevent malleability. Compact signature support remains available using `recover(bytes32,bytes32,bytes32)` and `tryRecover(bytes32,bytes32,bytes32)`. + +## 4.7.2 (2022-07-25) + +- `LibArbitrumL2`, `CrossChainEnabledArbitrumL2`: Fixed detection of cross-chain calls for EOAs. Previously, calls from EOAs would be classified as cross-chain calls. ([#3578](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3578)) +- `GovernorVotesQuorumFraction`: Fixed quorum updates so they do not affect past proposals that failed due to lack of quorum. ([#3561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3561)) +- `ERC165Checker`: Added protection against large returndata. ([#3587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3587)) + +## 4.7.1 (2022-07-18) + +- `SignatureChecker`: Fix an issue that causes `isValidSignatureNow` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552)) +- `ERC165Checker`: Fix an issue that causes `supportsInterface` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552)) + +## 4.7.0 (2022-06-29) + +- `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317)) +- `CrossChainEnabledPolygonChild`: replace the `require` statement with the custom error `NotCrossChainCall`. ([#3380](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3380)) +- `ERC20FlashMint`: Add customizable flash fee receiver. ([#3327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3327)) +- `ERC4626`: add an extension of `ERC20` that implements the ERC4626 Tokenized Vault Standard. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171)) +- `SafeERC20`: add `safePermit` as mitigation against phantom permit functions. ([#3280](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3280)) +- `Math`: add a `mulDiv` function that can round the result either up or down. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171)) +- `Math`: Add a `sqrt` function to compute square roots of integers, rounding either up or down. ([#3242](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3242)) +- `Strings`: add a new overloaded function `toHexString` that converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. ([#3403](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3403)) +- `EnumerableMap`: add new `UintToUintMap` map type. ([#3338](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3338)) +- `EnumerableMap`: add new `Bytes32ToUintMap` map type. ([#3416](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3416)) +- `SafeCast`: add support for many more types, using procedural code generation. ([#3245](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3245)) +- `MerkleProof`: add `multiProofVerify` to prove multiple values are part of a Merkle tree. ([#3276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3276)) +- `MerkleProof`: add calldata versions of the functions to avoid copying input arrays to memory and save gas. ([#3200](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3200)) +- `ERC721`, `ERC1155`: simplified revert reasons. ([#3254](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3254), ([#3438](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3438))) +- `ERC721`: removed redundant require statement. ([#3434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3434)) +- `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350)) +- `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450)) +- `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) + +### Breaking changes + +- `Initializable`: functions decorated with the modifier `reinitializer(1)` may no longer invoke each other. + +## 4.6.0 (2022-04-26) + +- `crosschain`: Add a new set of contracts for cross-chain applications. `CrossChainEnabled` is a base contract with instantiations for several chains and bridges, and `AccessControlCrossChain` is an extension of access control that allows cross-chain operation. ([#3183](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3183)) +- `AccessControl`: add a virtual `_checkRole(bytes32)` function that can be overridden to alter the `onlyRole` modifier behavior. ([#3137](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3137)) +- `EnumerableMap`: add new `AddressToUintMap` map type. ([#3150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3150)) +- `EnumerableMap`: add new `Bytes32ToBytes32Map` map type. ([#3192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3192)) +- `ERC20FlashMint`: support infinite allowance when paying back a flash loan. ([#3226](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3226)) +- `ERC20Wrapper`: the `decimals()` function now tries to fetch the value from the underlying token instance. If that calls revert, then the default value is used. ([#3259](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3259)) +- `draft-ERC20Permit`: replace `immutable` with `constant` for `_PERMIT_TYPEHASH` since the `keccak256` of string literals is treated specially and the hash is evaluated at compile time. ([#3196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3196)) +- `ERC1155`: Add a `_afterTokenTransfer` hook for improved extensibility. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166)) +- `ERC1155URIStorage`: add a new extension that implements a `_setURI` behavior similar to ERC721's `_setTokenURI`. ([#3210](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3210)) +- `DoubleEndedQueue`: a new data structure that supports efficient push and pop to both front and back, useful for FIFO and LIFO queues. ([#3153](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3153)) +- `Governor`: improved security of `onlyGovernance` modifier when using an external executor contract (e.g. a timelock) that can operate without necessarily going through the governance protocol. ([#3147](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3147)) +- `Governor`: Add a way to parameterize votes. This can be used to implement voting systems such as fractionalized voting, ERC721 based voting, or any number of other systems. The `params` argument added to `_countVote` method, and included in the newly added `_getVotes` method, can be used by counting and voting modules respectively for such purposes. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: rewording of revert reason for consistency. ([#3275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3275)) +- `Governor`: fix an inconsistency in data locations that could lead to invalid bytecode being produced. ([#3295](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3295)) +- `Governor`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by governors. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230)) +- `TimelockController`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by timelocks. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230)) +- `TimelockController`: Add a separate canceller role for the ability to cancel. ([#3165](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3165)) +- `Initializable`: add a reinitializer modifier that enables the initialization of new modules, added to already initialized contracts through upgradeability. ([#3232](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3232)) +- `Initializable`: add an Initialized event that tracks initialized version numbers. ([#3294](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3294)) +- `ERC2981`: make `royaltyInfo` public to allow super call in overrides. ([#3305](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3305)) + +### Upgradeability notice + +- `TimelockController`: **(Action needed)** The upgrade from <4.6 to >=4.6 introduces a new `CANCELLER_ROLE` that requires set up to be assignable. After the upgrade, only addresses with this role will have the ability to cancel. Proposers will no longer be able to cancel. Assigning cancellers can be done by an admin (including the timelock itself) once the role admin is set up. To do this, we recommend upgrading to the `TimelockControllerWith46MigrationUpgradeable` contract and then calling the `migrateTo46` function. + +### Breaking changes + +- `Governor`: Adds internal virtual `_getVotes` method that must be implemented; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing voting module extension, rename `getVotes` to `_getVotes` and add a `bytes memory` argument. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: Adds `params` parameter to internal virtual `_countVote` method; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing counting module extension, add a `bytes memory` argument to `_countVote`. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: Does not emit `VoteCast` event when params data is non-empty; instead emits `VoteCastWithParams` event. To fix this on an integration that consumes the `VoteCast` event, also fetch/monitor `VoteCastWithParams` events. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Votes`: The internal virtual function `_getVotingUnits` was made `view` (which was accidentally missing). Any overrides should now be updated so they are `view` as well. + +## 4.5.0 (2022-02-09) + +- `ERC2981`: add implementation of the royalty standard, and the respective extensions for `ERC721` and `ERC1155`. ([#3012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3012)) +- `GovernorTimelockControl`: improve the `state()` function to have it reflect cases where a proposal has been canceled directly on the timelock. ([#2977](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2977)) +- Preset contracts are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com). ([#2986](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2986)) +- `Governor`: add a relay function to help recover assets sent to a governor that is not its own executor (e.g. when using a timelock). ([#2926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2926)) +- `GovernorPreventLateQuorum`: add new module to ensure a minimum voting duration is available after the quorum is reached. ([#2973](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2973)) +- `ERC721`: improved revert reason when transferring from wrong owner. ([#2975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2975)) +- `Votes`: Added a base contract for vote tracking with delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944)) +- `ERC721Votes`: Added an extension of ERC721 enabled with vote tracking and delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944)) +- `ERC2771Context`: use immutable storage to store the forwarder address, no longer an issue since Solidity >=0.8.8 allows reading immutable variables in the constructor. ([#2917](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2917)) +- `Base64`: add a library to parse bytes into base64 strings using `encode(bytes memory)` function, and provide examples to show how to use to build URL-safe `tokenURIs`. ([#2884](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2884)) +- `ERC20`: reduce allowance before triggering transfer. ([#3056](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3056)) +- `ERC20`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085)) +- `ERC20`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `ERC20Burnable`: do not update allowance on `burnFrom` when allowance is `type(uint256).max`. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `ERC777`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085)) +- `ERC777`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `SignedMath`: a new signed version of the Math library with `max`, `min`, and `average`. ([#2686](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2686)) +- `SignedMath`: add an `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984)) +- `ERC1967Upgrade`: Refactor the secure upgrade to use `ERC1822` instead of the previous rollback mechanism. This reduces code complexity and attack surface with similar security guarantees. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021)) +- `UUPSUpgradeable`: Add `ERC1822` compliance to support the updated secure upgrade mechanism. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021)) +- Some more functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. + +### Breaking changes + +- `ERC1967Upgrade`: The function `_upgradeToAndCallSecure` was renamed to `_upgradeToAndCallUUPS`, along with the change in security mechanism described above. +- `Address`: The Solidity pragma is increased from `^0.8.0` to `^0.8.1`. This is required by the `account.code.length` syntax that replaces inline assembly. This may require users to bump their compiler version from `0.8.0` to `0.8.1` or later. Note that other parts of the code already include stricter requirements. + +## 4.4.2 (2022-01-11) + +### Bugfixes + +- `GovernorCompatibilityBravo`: Fix error in the encoding of calldata for proposals submitted through the compatibility interface with explicit signatures. ([#3100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3100)) + +## 4.4.1 (2021-12-14) + +- `Initializable`: change the existing `initializer` modifier and add a new `onlyInitializing` modifier to prevent reentrancy risk. ([#3006](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3006)) + +### Breaking change + +It is no longer possible to call an `initializer`-protected function from within another `initializer` function outside the context of a constructor. Projects using OpenZeppelin upgradeable proxies should continue to work as is, since in the common case the initializer is invoked in the constructor directly. If this is not the case for you, the suggested change is to use the new `onlyInitializing` modifier in the following way: + +```diff + contract A { +- function initialize() public initializer { ... } ++ function initialize() internal onlyInitializing { ... } + } + contract B is A { + function initialize() public initializer { + A.initialize(); + } + } +``` + +## 4.4.0 (2021-11-25) + +- `Ownable`: add an internal `_transferOwnership(address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControl`: add internal `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControl`: mark `_setupRole(bytes32,address)` as deprecated in favor of `_grantRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControlEnumerable`: hook into `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2946](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2946)) +- `EIP712`: cache `address(this)` to immutable storage to avoid potential issues if a vanilla contract is used in a delegatecall context. ([#2852](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2852)) +- Add internal `_setApprovalForAll` to `ERC721` and `ERC1155`. ([#2834](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2834)) +- `Governor`: shift vote start and end by one block to better match Compound's GovernorBravo and prevent voting at the Governor level if the voting snapshot is not ready. ([#2892](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2892)) +- `GovernorCompatibilityBravo`: consider quorum an inclusive rather than exclusive minimum to match Compound's GovernorBravo. ([#2974](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2974)) +- `GovernorSettings`: a new governor module that manages voting settings updatable through governance actions. ([#2904](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2904)) +- `PaymentSplitter`: now supports ERC20 assets in addition to Ether. ([#2858](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2858)) +- `ECDSA`: add a variant of `toEthSignedMessageHash` for arbitrary length message hashing. ([#2865](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2865)) +- `MerkleProof`: add a `processProof` function that returns the rebuilt root hash given a leaf and a proof. ([#2841](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2841)) +- `VestingWallet`: new contract that handles the vesting of Ether and ERC20 tokens following a customizable vesting schedule. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2748)) +- `Governor`: enable receiving Ether when a Timelock contract is not used. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849)) +- `GovernorTimelockCompound`: fix ability to use Ether stored in the Timelock contract. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849)) + +## 4.3.3 (2021-11-08) + +- `ERC1155Supply`: Handle `totalSupply` changes by hooking into `_beforeTokenTransfer` to ensure consistency of balances and supply during `IERC1155Receiver.onERC1155Received` calls. + +## 4.3.2 (2021-09-14) + +- `UUPSUpgradeable`: Add modifiers to prevent `upgradeTo` and `upgradeToAndCall` being executed on any contract that is not the active ERC1967 proxy. This prevents these functions being called on implementation contracts or minimal ERC1167 clones, in particular. + +## 4.3.1 (2021-08-26) + +- `TimelockController`: Add additional isOperationReady check. + +## 4.3.0 (2021-08-17) + +- `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754)) +- `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768)) +- `Governor`: added a modular system of `Governor` contracts based on `GovernorAlpha` and `GovernorBravo`. ([#2672](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2672)) +- Add an `interfaces` folder containing solidity interfaces to final ERCs. ([#2517](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2517)) +- `ECDSA`: add `tryRecover` functions that will not throw if the signature is invalid, and will return an error flag instead. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661)) +- `SignatureChecker`: Reduce gas usage of the `isValidSignatureNow` function for the "signature by EOA" case. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661)) + +## 4.2.0 (2021-06-30) + +- `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632)) +- `ERC20VotesComp`: Variant of `ERC20Votes` that is compatible with Compound's `Comp` token interface but restricts supply to `uint96`. ([#2706](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2706)) +- `ERC20Wrapper`: add a new extension of the `ERC20` token which wraps an underlying token. Deposit and withdraw guarantee that the total supply is backed by a corresponding amount of underlying token. ([#2633](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2633)) +- Enumerables: Improve gas cost of removal in `EnumerableSet` and `EnumerableMap`. +- Enumerables: Improve gas cost of lookup in `EnumerableSet` and `EnumerableMap`. +- `Counter`: add a reset method. ([#2678](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2678)) +- Tokens: Wrap definitely safe subtractions in `unchecked` blocks. +- `Math`: Add a `ceilDiv` method for performing ceiling division. +- `ERC1155Supply`: add a new `ERC1155` extension that keeps track of the totalSupply of each tokenId. ([#2593](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2593)) +- `BitMaps`: add a new `BitMaps` library that provides a storage efficient datastructure for `uint256` to `bool` mapping with contiguous keys. ([#2710](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2710)) + +### Breaking Changes + +- `ERC20FlashMint` is no longer a Draft ERC. ([#2673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2673))) + +**How to update:** Change your import paths by removing the `draft-` prefix from `@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20FlashMint.sol`. + +> See [Releases and Stability: Drafts](https://docs.openzeppelin.com/contracts/4.x/releases-stability#drafts). + +## 4.1.0 (2021-04-29) + +- `IERC20Metadata`: add a new extended interface that includes the optional `name()`, `symbol()` and `decimals()` functions. ([#2561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2561)) +- `ERC777`: make reception acquirement optional in `_mint`. ([#2552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2552)) +- `ERC20Permit`: add a `_useNonce` to enable further usage of ERC712 signatures. ([#2565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2565)) +- `ERC20FlashMint`: add an implementation of the ERC3156 extension for flash-minting ERC20 tokens. ([#2543](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2543)) +- `SignatureChecker`: add a signature verification library that supports both EOA and ERC1271 compliant contracts as signers. ([#2532](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2532)) +- `Multicall`: add abstract contract with `multicall(bytes[] calldata data)` function to bundle multiple calls together ([#2608](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2608)) +- `ECDSA`: add support for ERC2098 short-signatures. ([#2582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2582)) +- `AccessControl`: add an `onlyRole` modifier to restrict specific function to callers bearing a specific role. ([#2609](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2609)) +- `StorageSlot`: add a library for reading and writing primitive types to specific storage slots. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542)) +- UUPS Proxies: add `UUPSUpgradeable` to implement the UUPS proxy pattern together with `EIP1967Proxy`. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542)) + +### Breaking changes + +This release includes two small breaking changes in `TimelockController`. + +1. The `onlyRole` modifier in this contract was designed to let anyone through if the role was granted to `address(0)`, + allowing the possibility to to make a role "open", which can be used for `EXECUTOR_ROLE`. This modifier is now + replaced by `AccessControl.onlyRole`, which does not have this ability. The previous behavior was moved to the + modifier `TimelockController.onlyRoleOrOpenRole`. +2. It was possible to make `PROPOSER_ROLE` an open role (as described in the previous item) if it was granted to + `address(0)`. This would affect the `schedule`, `scheduleBatch`, and `cancel` operations in `TimelockController`. + This ability was removed as it does not make sense to open up the `PROPOSER_ROLE` in the same way that it does for + `EXECUTOR_ROLE`. + +## 4.0.0 (2021-03-23) + +- Now targeting the 0.8.x line of Solidity compilers. For 0.6.x (resp 0.7.x) support, use version 3.4.0 (resp 3.4.0-solc-0.7) of OpenZeppelin. +- `Context`: making `_msgData` return `bytes calldata` instead of `bytes memory` ([#2492](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2492)) +- `ERC20`: removed the `_setDecimals` function and the storage slot associated to decimals. ([#2502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2502)) +- `Strings`: addition of a `toHexString` function. ([#2504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2504)) +- `EnumerableMap`: change implementation to optimize for `key → value` lookups instead of enumeration. ([#2518](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2518)) +- `GSN`: deprecate GSNv1 support in favor of upcoming support for GSNv2. ([#2521](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2521)) +- `ERC165`: remove uses of storage in the base ERC165 implementation. ERC165 based contracts now use storage-less virtual functions. Old behavior remains available in the `ERC165Storage` extension. ([#2505](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2505)) +- `Initializable`: make initializer check stricter during construction. ([#2531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2531)) +- `ERC721`: remove enumerability of tokens from the base implementation. This feature is now provided separately through the `ERC721Enumerable` extension. ([#2511](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2511)) +- `AccessControl`: removed enumerability by default for a more lightweight contract. It is now opt-in through `AccessControlEnumerable`. ([#2512](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2512)) +- Meta Transactions: add `ERC2771Context` and a `MinimalForwarder` for meta-transactions. ([#2508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2508)) +- Overall reorganization of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503)) +- `ERC20Capped`: optimize gas usage by enforcing the check directly in `_mint`. ([#2524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2524)) +- Rename `UpgradeableProxy` to `ERC1967Proxy`. ([#2547](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2547)) +- `ERC777`: optimize the gas costs of the constructor. ([#2551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2551)) +- `ERC721URIStorage`: add a new extension that implements the `_setTokenURI` behavior as it was available in 3.4.0. ([#2555](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2555)) +- `AccessControl`: added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562)) +- `ERC1155`: make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576)) + +### Bug fixes for beta releases + +- `AccessControlEnumerable`: Fixed `renounceRole` not updating enumerable set of addresses for a role. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572)) + +### How to upgrade from 3.x + +Since this version has moved a few contracts to different directories, users upgrading from a previous version will need to adjust their import statements. To make this easier, the package includes a script that will migrate import statements automatically. After upgrading to the latest version of the package, run: + +``` +npx openzeppelin-contracts-migrate-imports +``` + +Make sure you're using git or another version control system to be able to recover from any potential error in our script. + +### How to upgrade from 4.0-beta.x + +Some further changes have been done between the different beta iterations. Transitions made during this period are configured in the `migrate-imports` script. Consequently, you can upgrade from any previous 4.0-beta.x version using the same script as described in the _How to upgrade from 3.x_ section. + +## 3.4.2 (2021-07-24) + +- `TimelockController`: Add additional isOperationReady check. + +## 3.4.1 (2021-03-03) + +- `ERC721`: made `_approve` an internal function (was private). + +## 3.4.0 (2021-02-02) + +- `BeaconProxy`: added new kind of proxy that allows simultaneous atomic upgrades. ([#2411](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2411)) +- `EIP712`: added helpers to verify EIP712 typed data signatures on chain. ([#2418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2418)) +- `ERC20Permit`: added an implementation of the ERC20 permit extension for gasless token approvals. ([#2237](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237)) +- Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399)) +- `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) +- `Clones`: added a library for deploying EIP 1167 minimal proxies. ([#2449](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2449)) +- `Context`: moved from `contracts/GSN` to `contracts/utils`. ([#2453](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2453)) +- `PaymentSplitter`: replace usage of `.transfer()` with `Address.sendValue` for improved compatibility with smart wallets. ([#2455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2455)) +- `UpgradeableProxy`: bubble revert reasons from initialization calls. ([#2454](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2454)) +- `SafeMath`: fix a memory allocation issue by adding new `SafeMath.tryOp(uint,uint)→(bool,uint)` functions. `SafeMath.op(uint,uint,string)→uint` are now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462)) +- `EnumerableMap`: fix a memory allocation issue by adding new `EnumerableMap.tryGet(uint)→(bool,address)` functions. `EnumerableMap.get(uint)→string` is now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462)) +- `ERC165Checker`: added batch `getSupportedInterfaces`. ([#2469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2469)) +- `RefundEscrow`: `beneficiaryWithdraw` will forward all available gas to the beneficiary. ([#2480](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2480)) +- Many view and pure functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. + +### Security Fixes + +- `ERC777`: fix potential reentrancy issues for custom extensions to `ERC777`. ([#2483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483)) + +If you're using our implementation of ERC777 from version 3.3.0 or earlier, and you define a custom `_beforeTokenTransfer` function that writes to a storage variable, you may be vulnerable to a reentrancy attack. If you're affected and would like assistance please write to security@openzeppelin.com. [Read more in the pull request.](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483) + +## 3.3.0 (2020-11-26) + +- Now supports both Solidity 0.6 and 0.7. Compiling with solc 0.7 will result in warnings. Install the `solc-0.7` tag to compile without warnings. +- `Address`: added `functionStaticCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) +- `TimelockController`: added a contract to augment access control schemes with a delay. ([#2354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2354)) +- `EnumerableSet`: added `Bytes32Set`, for sets of `bytes32`. ([#2395](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2395)) + +## 3.2.2-solc-0.7 (2020-10-28) + +- Resolve warnings introduced by Solidity 0.7.4. ([#2396](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2396)) + +## 3.2.1-solc-0.7 (2020-09-15) + +- `ERC777`: Remove a warning about function state visibility in Solidity 0.7. ([#2327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2327)) + +## 3.2.0 (2020-09-10) + +### New features + +- Proxies: added the proxy contracts from OpenZeppelin SDK. ([#2335](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2335)) + +#### Proxy changes with respect to OpenZeppelin SDK + +Aside from upgrading them from Solidity 0.5 to 0.6, we've changed a few minor things from the proxy contracts as they were found in OpenZeppelin SDK. + +- `UpgradeabilityProxy` was renamed to `UpgradeableProxy`. +- `AdminUpgradeabilityProxy` was renamed to `TransparentUpgradeableProxy`. +- `Proxy._willFallback` was renamed to `Proxy._beforeFallback`. +- `UpgradeabilityProxy._setImplementation` and `AdminUpgradeabilityProxy._setAdmin` were made private. + +### Improvements + +- `Address.isContract`: switched from `extcodehash` to `extcodesize` for less gas usage. ([#2311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2311)) + +### Breaking changes + +- `ERC20Snapshot`: switched to using `_beforeTokenTransfer` hook instead of overriding ERC20 operations. ([#2312](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2312)) + +This small change in the way we implemented `ERC20Snapshot` may affect users who are combining this contract with +other ERC20 flavors, since it no longer overrides `_transfer`, `_mint`, and `_burn`. This can result in having to remove Solidity `override(...)` specifiers in derived contracts for these functions, and to instead have to add it for `_beforeTokenTransfer`. See [Using Hooks](https://docs.openzeppelin.com/contracts/3.x/extending-contracts#using-hooks) in the documentation. + +## 3.1.0 (2020-06-23) + +### New features + +- `SafeCast`: added functions to downcast signed integers (e.g. `toInt32`), improving usability of `SignedSafeMath`. ([#2243](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2243)) +- `functionCall`: new helpers that replicate Solidity's function call semantics, reducing the need to rely on `call`. ([#2264](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2264)) +- `ERC1155`: added support for a base implementation, non-standard extensions and a preset contract. ([#2014](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2014), [#2230](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2230)) + +### Improvements + +- `ReentrancyGuard`: reduced overhead of using the `nonReentrant` modifier. ([#2171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2171)) +- `AccessControl`: added a `RoleAdminChanged` event to `_setAdminRole`. ([#2214](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2214)) +- Made all `public` functions in the token preset contracts `virtual`. ([#2257](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2257)) + +### Deprecations + +- `SafeERC20`: deprecated `safeApprove`. ([#2268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2268)) + +## 3.0.2 (2020-06-08) + +### Improvements + +- Added SPX license identifier to all contracts. ([#2235](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2235)) + +## 3.0.1 (2020-04-27) + +### Bugfixes + +- `ERC777`: fixed the `_approve` internal function not validating some of their arguments for non-zero addresses. ([#2213](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2213)) + +## 3.0.0 (2020-04-20) + +### New features + +- `AccessControl`: new contract for managing permissions in a system, replacement for `Ownable` and `Roles`. ([#2112](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2112)) +- `SafeCast`: new functions to convert to and from signed and unsigned values: `toUint256` and `toInt256`. ([#2123](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2123)) +- `EnumerableMap`: a new data structure for key-value pairs (like `mapping`) that can be iterated over. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) + +### Breaking changes + +- `ERC721`: `burn(owner, tokenId)` was removed, use `burn(tokenId)` instead. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `ERC721`: `_checkOnERC721Received` was removed. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `ERC721`: `_transferFrom` and `_safeTransferFrom` were renamed to `_transfer` and `_safeTransfer`. ([#2162](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2162)) +- `Ownable`: removed `_transferOwnership`. ([#2162](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2162)) +- `PullPayment`, `Escrow`: `withdrawWithGas` was removed. The old `withdraw` function now forwards all gas. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `Roles` was removed, use `AccessControl` as a replacement. ([#2112](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2112)) +- `ECDSA`: when receiving an invalid signature, `recover` now reverts instead of returning the zero address. ([#2114](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2114)) +- `Create2`: added an `amount` argument to `deploy` for contracts with `payable` constructors. ([#2117](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2117)) +- `Pausable`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Strings`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Counters`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `SignedSafeMath`: moved to the `math` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `ERC20Snapshot`: moved to the `token/ERC20` directory. `snapshot` was changed into an `internal` function. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Ownable`: moved to the `access` directory. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Ownable`: removed `isOwner`. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Secondary`: removed from the library, use `Ownable` instead. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Escrow`, `ConditionalEscrow`, `RefundEscrow`: these now use `Ownable` instead of `Secondary`, their external API changed accordingly. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `ERC20`: removed `_burnFrom`. ([#2119](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2119)) +- `Address`: removed `toPayable`, use `payable(address)` instead. ([#2133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2133)) +- `ERC777`: `_send`, `_mint` and `_burn` now use the caller as the operator. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134)) +- `ERC777`: removed `_callsTokensToSend` and `_callTokensReceived`. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134)) +- `EnumerableSet`: renamed `get` to `at`. ([#2151](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2151)) +- `ERC165Checker`: functions no longer have a leading underscore. ([#2150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2150)) +- `ERC721Metadata`, `ERC721Enumerable`: these contracts were removed, and their functionality merged into `ERC721`. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) +- `ERC721`: added a constructor for `name` and `symbol`. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) +- `ERC20Detailed`: this contract was removed and its functionality merged into `ERC20`. ([#2161](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2161)) +- `ERC20`: added a constructor for `name` and `symbol`. `decimals` now defaults to 18. ([#2161](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2161)) +- `Strings`: renamed `fromUint256` to `toString` ([#2188](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2188)) + +## 2.5.1 (2020-04-24) + +### Bugfixes + +- `ERC777`: fixed the `_send` and `_approve` internal functions not validating some of their arguments for non-zero addresses. ([#2212](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2212)) + +## 2.5.0 (2020-02-04) + +### New features + +- `SafeCast.toUintXX`: new library for integer downcasting, which allows for safe operation on smaller types (e.g. `uint32`) when combined with `SafeMath`. ([#1926](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1926)) +- `ERC721Metadata`: added `baseURI`, which can be used for dramatic gas savings when all token URIs share a prefix (e.g. `http://api.myapp.com/tokens/`). ([#1970](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1970)) +- `EnumerableSet`: new library for storing enumerable sets of values. Only `AddressSet` is supported in this release. ([#2061](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/2061)) +- `Create2`: simple library to make usage of the `CREATE2` opcode easier. ([#1744](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1744)) + +### Improvements + +- `ERC777`: `_burn` is now internal, providing more flexibility and making it easier to create tokens that deflate. ([#1908](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1908)) +- `ReentrancyGuard`: greatly improved gas efficiency by using the net gas metering mechanism introduced in the Istanbul hardfork. ([#1992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1992), [#1996](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1996)) +- `ERC777`: improve extensibility by making `_send` and related functions `internal`. ([#2027](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2027)) +- `ERC721`: improved revert reason when transferring tokens to a non-recipient contract. ([#2018](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018)) + +### Breaking changes + +- `ERC165Checker` now requires a minimum Solidity compiler version of 0.5.10. ([#1829](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1829)) + +## 2.4.0 (2019-10-29) + +### New features + +- `Address.toPayable`: added a helper to convert between address types without having to resort to low-level casting. ([#1773](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1773)) +- Facilities to make metatransaction-enabled contracts through the Gas Station Network. ([#1844](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1844)) +- `Address.sendValue`: added a replacement to Solidity's `transfer`, removing the fixed gas stipend. ([#1962](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1962)) +- Added replacement for functions that don't forward all gas (which have been deprecated): ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976)) + - `PullPayment.withdrawPaymentsWithGas(address payable payee)` + - `Escrow.withdrawWithGas(address payable payee)` +- `SafeMath`: added support for custom error messages to `sub`, `div` and `mod` functions. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828)) + +### Improvements + +- `Address.isContract`: switched from `extcodesize` to `extcodehash` for less gas usage. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) +- `ERC20` and `ERC777` updated to throw custom errors on subtraction overflows. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828)) + +### Deprecations + +- Deprecated functions that don't forward all gas: ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976)) + - `PullPayment.withdrawPayments(address payable payee)` + - `Escrow.withdraw(address payable payee)` + +### Breaking changes + +- `Address` now requires a minimum Solidity compiler version of 0.5.5. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) +- `SignatureBouncer` has been removed from drafts, both to avoid confusions with the GSN and `GSNRecipientSignature` (previously called `GSNBouncerSignature`) and because the API was not very clear. ([#1879](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1879)) + +### How to upgrade from 2.4.0-beta + +The final 2.4.0 release includes a refactor of the GSN contracts that will be a breaking change for 2.4.0-beta users. + +- The default empty implementations of `_preRelayedCall` and `_postRelayedCall` were removed and must now be explicitly implemented always in custom recipients. If your custom recipient didn't include an implementation, you can provide an empty one. +- `GSNRecipient`, `GSNBouncerBase`, and `GSNContext` were all merged into `GSNRecipient`. +- `GSNBouncerSignature` and `GSNBouncerERC20Fee` were renamed to `GSNRecipientSignature` and `GSNRecipientERC20Fee`. +- It is no longer necessary to inherit from `GSNRecipient` when using `GSNRecipientSignature` and `GSNRecipientERC20Fee`. + +For example, a contract using `GSNBouncerSignature` would have to be changed in the following way. + +```diff +-contract MyDapp is GSNRecipient, GSNBouncerSignature { ++contract MyDapp is GSNRecipientSignature { +``` + +Refer to the table below to adjust your inheritance list. + +| 2.4.0-beta | 2.4.0 | +| ----------------------------------- | ----------------------- | +| `GSNRecipient, GSNBouncerSignature` | `GSNRecipientSignature` | +| `GSNRecipient, GSNBouncerERC20Fee` | `GSNRecipientERC20Fee` | +| `GSNBouncerBase` | `GSNRecipient` | + +## 2.3.0 (2019-05-27) + +### New features + +- `ERC1820`: added support for interacting with the [ERC1820](https://eips.ethereum.org/EIPS/eip-1820) registry contract (`IERC1820Registry`), as well as base contracts that can be registered as implementers there. ([#1677](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1677)) +- `ERC777`: support for the [ERC777 token](https://eips.ethereum.org/EIPS/eip-777), which has multiple improvements over `ERC20` (but is backwards compatible with it) such as built-in burning, a more straightforward permission system, and optional sender and receiver hooks on transfer (mandatory for contracts!). ([#1684](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1684)) +- All contracts now have revert reason strings, which give insight into error conditions, and help debug failing transactions. ([#1704](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1704)) + +### Improvements + +- Reverted the Solidity version bump done in v2.2.0, setting the minimum compiler version to v0.5.0, to prevent unexpected build breakage. Users are encouraged however to stay on top of new compiler releases, which usually include bugfixes. ([#1729](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1729)) + +### Bugfixes + +- `PostDeliveryCrowdsale`: some validations where skipped when paired with other crowdsale flavors, such as `AllowanceCrowdsale`, or `MintableCrowdsale` and `ERC20Capped`, which could cause buyers to not be able to claim their purchased tokens. ([#1721](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1721)) +- `ERC20._transfer`: the `from` argument was allowed to be the zero address, so it was possible to internally trigger a transfer of 0 tokens from the zero address. This address is not a valid destinatary of transfers, nor can it give or receive allowance, so this behavior was inconsistent. It now reverts. ([#1752](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1752)) + +## 2.2.0 (2019-03-14) + +### New features + +- `ERC20Snapshot`: create snapshots on demand of the token balances and total supply, to later retrieve and e.g. calculate dividends at a past time. ([#1617](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1617)) +- `SafeERC20`: `ERC20` contracts with no return value (i.e. that revert on failure) are now supported. ([#1655](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1655)) +- `ERC20`: added internal `_approve(address owner, address spender, uint256 value)`, allowing derived contracts to set the allowance of arbitrary accounts. ([#1609](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1609)) +- `ERC20Metadata`: added internal `_setTokenURI(string memory tokenURI)`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618)) +- `TimedCrowdsale`: added internal `_extendTime(uint256 newClosingTime)` as well as `TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime)` event allowing to extend the crowdsale, as long as it hasn't already closed. + +### Improvements + +- Upgraded the minimum compiler version to v0.5.2: this removes many Solidity warnings that were false positives. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606)) +- `ECDSA`: `recover` no longer accepts malleable signatures (those using upper-range values for `s`, or 0/1 for `v`). ([#1622](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1622)) +- `ERC721`'s transfers are now more gas efficient due to removal of unnecessary `SafeMath` calls. ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610)) +- Fixed variable shadowing issues. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606)) + +### Bugfixes + +- (minor) `SafeERC20`: `safeApprove` wasn't properly checking for a zero allowance when attempting to set a non-zero allowance. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647)) + +### Breaking changes in drafts + +- `TokenMetadata` has been renamed to `ERC20Metadata`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618)) +- The library `Counter` has been renamed to `Counters` and its API has been improved. See an example in `ERC721`, lines [17](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L17) and [204](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L204). ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610)) + +## 2.1.3 (2019-02-26) + +- Backported `SafeERC20.safeApprove` bugfix. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647)) + +## 2.1.2 (2019-01-17) + +- Removed most of the test suite from the npm package, except `PublicRole.behavior.js`, which may be useful to users testing their own `Roles`. + +## 2.1.1 (2019-01-04) + +- Version bump to avoid conflict in the npm registry. + +## 2.1.0 (2019-01-04) + +### New features + +- Now targeting the 0.5.x line of Solidity compilers. For 0.4.24 support, use version 2.0 of OpenZeppelin. +- `WhitelistCrowdsale`: a crowdsale where only whitelisted accounts (`WhitelistedRole`) can purchase tokens. Adding or removing accounts from the whitelist is done by whitelist admins (`WhitelistAdminRole`). Similar to the pre-2.0 `WhitelistedCrowdsale`. ([#1525](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1525), [#1589](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1589)) +- `RefundablePostDeliveryCrowdsale`: replacement for `RefundableCrowdsale` (deprecated, see below) where tokens are only granted once the crowdsale ends (if it meets its goal). ([#1543](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1543)) +- `PausableCrowdsale`: allows for pausers (`PauserRole`) to pause token purchases. Other crowdsale operations (e.g. withdrawals and refunds, if applicable) are not affected. ([#832](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/832)) +- `ERC20`: `transferFrom` and `_burnFrom ` now emit `Approval` events, to represent the token's state comprehensively through events. ([#1524](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1524)) +- `ERC721`: added `_burn(uint256 tokenId)`, replacing the similar deprecated function (see below). ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) +- `ERC721`: added `_tokensOfOwner(address owner)`, allowing to internally retrieve the array of an account's owned tokens. ([#1522](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1522)) +- Crowdsales: all constructors are now `public`, meaning it is not necessary to extend these contracts in order to deploy them. The exception is `FinalizableCrowdsale`, since it is meaningless unless extended. ([#1564](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1564)) +- `SignedSafeMath`: added overflow-safe operations for signed integers (`int256`). ([#1559](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1559), [#1588](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1588)) + +### Improvements + +- The compiler version required by `Array` was behind the rest of the library so it was updated to `v0.4.24`. ([#1553](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1553)) +- Now conforming to a 4-space indentation code style. ([1508](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1508)) +- `ERC20`: more gas efficient due to removed redundant `require`s. ([#1409](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1409)) +- `ERC721`: fixed a bug that prevented internal data structures from being properly cleaned, missing potential gas refunds. ([#1539](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1539) and [#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549)) +- `ERC721`: general gas savings on `transferFrom`, `_mint` and `_burn`, due to redundant `require`s and `SSTORE`s. ([#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549)) + +### Bugfixes + +### Breaking changes + +### Deprecations + +- `ERC721._burn(address owner, uint256 tokenId)`: due to the `owner` parameter being unnecessary. ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) +- `RefundableCrowdsale`: due to trading abuse potential on crowdsales that miss their goal. ([#1543](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1543)) diff --git a/lib/crytic/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md b/lib/crytic/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..cd7770d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at contact@openzeppelin.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/lib/crytic/lib/openzeppelin-contracts/CONTRIBUTING.md b/lib/crytic/lib/openzeppelin-contracts/CONTRIBUTING.md new file mode 100644 index 0000000..1a44cc2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing Guidelines + +There are many ways to contribute to OpenZeppelin Contracts. + +## Troubleshooting + +You can help other users in the community to solve their smart contract issues in the [OpenZeppelin Forum]. + +[OpenZeppelin Forum]: https://forum.openzeppelin.com/ + +## Opening an issue + +You can [open an issue] to suggest a feature or report a minor bug. For serious bugs please do not open an issue, instead refer to our [security policy] for appropriate steps. + +If you believe your issue may be due to user error and not a problem in the library, consider instead posting a question on the [OpenZeppelin Forum]. + +Before opening an issue, be sure to search through the existing open and closed issues, and consider posting a comment in one of those instead. + +When requesting a new feature, include as many details as you can, especially around the use cases that motivate it. Features are prioritized according to the impact they may have on the ecosystem, so we appreciate information showing that the impact could be high. + +[security policy]: https://github.com/OpenZeppelin/openzeppelin-contracts/security +[open an issue]: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/new/choose + +## Submitting a pull request + +If you would like to contribute code or documentation you may do so by forking the repository and submitting a pull request. + +Any non-trivial code contribution must be first discussed with the maintainers in an issue (see [Opening an issue](#opening-an-issue)). Only very minor changes are accepted without prior discussion. + +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/lib/crytic/lib/openzeppelin-contracts/GUIDELINES.md b/lib/crytic/lib/openzeppelin-contracts/GUIDELINES.md new file mode 100644 index 0000000..0f4c982 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/GUIDELINES.md @@ -0,0 +1,117 @@ +# Engineering Guidelines + +## Testing + +Code must be thoroughly tested with quality unit tests. + +We defer to the [Moloch Testing Guide](https://github.com/MolochVentures/moloch/tree/master/test#readme) for specific recommendations, though not all of it is relevant here. Note the introduction: + +> Tests should be written, not only to verify correctness of the target code, but to be comprehensively reviewed by other programmers. Therefore, for mission critical Solidity code, the quality of the tests are just as important (if not more so) than the code itself, and should be written with the highest standards of clarity and elegance. + +Every addition or change to the code must come with relevant and comprehensive tests. + +Refactors should avoid simultaneous changes to tests. + +Flaky tests are not acceptable. + +The test suite should run automatically for every change in the repository, and in pull requests tests must pass before merging. + +The test suite coverage must be kept as close to 100% as possible, enforced in pull requests. + +In some cases unit tests may be insufficient and complementary techniques should be used: + +1. Property-based tests (aka. fuzzing) for math-heavy code. +2. Formal verification for state machines. + +## Code style + +Solidity code should be written in a consistent format enforced by a linter, following the official [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html). See below for further [Solidity Conventions](#solidity-conventions). + +The code should be simple and straightforward, prioritizing readability and understandability. Consistency and predictability should be maintained across the codebase. In particular, this applies to naming, which should be systematic, clear, and concise. + +Sometimes these guidelines may be broken if doing so brings significant efficiency gains, but explanatory comments should be added. + +Modularity should be pursued, but not at the cost of the above priorities. + +## Documentation + +For contributors, project guidelines and processes must be documented publicly. + +For users, features must be abundantly documented. Documentation should include answers to common questions, solutions to common problems, and recommendations for critical decisions that the user may face. + +All changes to the core codebase (excluding tests, auxiliary scripts, etc.) must be documented in a changelog, except for purely cosmetic or documentation changes. + +## Peer review + +All changes must be submitted through pull requests and go through peer code review. + +The review must be approached by the reviewer in a similar way as if it was an audit of the code in question (but importantly it is not a substitute for and should not be considered an audit). + +Reviewers should enforce code and project guidelines. + +External contributions must be reviewed separately by multiple maintainers. + +## Automation + +Automation should be used as much as possible to reduce the possibility of human error and forgetfulness. + +Automations that make use of sensitive credentials must use secure secret management, and must be strengthened against attacks such as [those on GitHub Actions worklows](https://github.com/nikitastupin/pwnhub). + +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. + +* All state variables should be private. + + Changes to state should be accompanied by events, and in some cases it is not correct to arbitrarily set state. Encapsulating variables as private and only allowing modification via setters enables us to ensure that events and other rules are followed reliably and prevents this kind of user error. + +* Internal or private state variables or functions should have an underscore prefix. + + ```solidity + contract TestContract { + uint256 private _privateVar; + uint256 internal _internalVar; + function _testInternal() internal { ... } + function _testPrivate() private { ... } + } + ``` + +* 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); + } + ``` + + Some standards (e.g. ERC20) use present tense, and in those cases the + standard specification is used. + +* Interface names should have a capital I prefix. + + ```solidity + interface IERC777 { + ``` + +* Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted. diff --git a/lib/crytic/lib/openzeppelin-contracts/LICENSE b/lib/crytic/lib/openzeppelin-contracts/LICENSE new file mode 100644 index 0000000..817249a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016-2023 zOS Global Limited and contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/crytic/lib/openzeppelin-contracts/README.md b/lib/crytic/lib/openzeppelin-contracts/README.md new file mode 100644 index 0000000..094637e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/README.md @@ -0,0 +1,90 @@ +# OpenZeppelin + +[![NPM Package](https://img.shields.io/npm/v/@openzeppelin/contracts.svg)](https://www.npmjs.org/package/@openzeppelin/contracts) +[![Coverage Status](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts/graph/badge.svg)](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts) +[![GitPOAPs](https://public-api.gitpoap.io/v1/repo/OpenZeppelin/openzeppelin-contracts/badge)](https://www.gitpoap.io/gh/OpenZeppelin/openzeppelin-contracts) +[![Docs](https://img.shields.io/badge/docs-%F0%9F%93%84-yellow)](https://docs.openzeppelin.com/contracts) +[![Forum](https://img.shields.io/badge/forum-%F0%9F%92%AC-yellow)](https://docs.openzeppelin.com/contracts) + +**A library for secure smart contract development.** Build on a solid foundation of community-vetted code. + + * Implementations of standards like [ERC20](https://docs.openzeppelin.com/contracts/erc20) and [ERC721](https://docs.openzeppelin.com/contracts/erc721). + * Flexible [role-based permissioning](https://docs.openzeppelin.com/contracts/access-control) scheme. + * Reusable [Solidity components](https://docs.openzeppelin.com/contracts/utilities) to build custom contracts and complex decentralized systems. + +:mage: **Not sure how to get started?** Check out [Contracts Wizard](https://wizard.openzeppelin.com/) — an interactive smart contract generator. + +:building_construction: **Want to scale your decentralized application?** Check out [OpenZeppelin Defender](https://openzeppelin.com/defender) — a secure platform for automating and monitoring your operations. + +## Overview + +### Installation + +``` +$ npm install @openzeppelin/contracts +``` + +OpenZeppelin Contracts features a [stable API](https://docs.openzeppelin.com/contracts/releases-stability#api-stability), which means that your contracts won't break unexpectedly when upgrading to a newer minor version. + +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. + +### Usage + +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"; + +contract MyCollectible is ERC721 { + constructor() ERC721("MyCollectible", "MCO") { + } +} +``` + +_If you're new to smart contract development, head to [Developing Smart Contracts](https://docs.openzeppelin.com/learn/developing-smart-contracts) to learn about creating a new project and compiling your contracts._ + +To keep your system secure, you should **always** use the installed code as-is, and neither copy-paste it from online sources nor modify it yourself. The library is designed so that only the contracts and functions you use are deployed, so you don't need to worry about it needlessly increasing gas costs. + +## Learn More + +The guides in the [documentation site](https://docs.openzeppelin.com/contracts) will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides: + +* [Access Control](https://docs.openzeppelin.com/contracts/access-control): decide who can perform each of the actions on your system. +* [Tokens](https://docs.openzeppelin.com/contracts/tokens): create tradeable assets or collectives, and distribute them via [Crowdsales](https://docs.openzeppelin.com/contracts/crowdsales). +* [Utilities](https://docs.openzeppelin.com/contracts/utilities): generic useful tools including non-overflowing math, signature verification, and trustless paying systems. + +The [full API](https://docs.openzeppelin.com/contracts/api/token/ERC20) is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts's development in the [community forum](https://forum.openzeppelin.com). + +Finally, you may want to take a look at the [guides on our blog](https://blog.openzeppelin.com/guides), which cover several common use cases and good practices. The following articles provide great background reading, though please note that some of the referenced tools have changed, as the tooling in the ecosystem continues to rapidly evolve. + +* [The Hitchhiker’s Guide to Smart Contracts in Ethereum](https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05) will help you get an overview of the various tools available for smart contract development, and help you set up your environment. +* [A Gentle Introduction to Ethereum Programming, Part 1](https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094) provides very useful information on an introductory level, including many basic concepts from the Ethereum platform. +* For a more in-depth dive, you may read the guide [Designing the Architecture for Your Ethereum Application](https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317), which discusses how to better structure your application and its relationship to the real world. + +## Security + +This project is maintained by [OpenZeppelin](https://openzeppelin.com) with the goal of providing a secure and reliable library of smart contract components for the ecosystem. We address security through risk management in various areas such as engineering and open source best practices, scoping and API design, multi-layered review processes, and incident response preparedness. + +The security policy is detailed in [`SECURITY.md`](./SECURITY.md), and specifies how you can report security vulnerabilities, which versions will receive security patches, and how to stay informed about them. We run a [bug bounty program on Immunefi](https://immunefi.com/bounty/openzeppelin) to reward the responsible disclosure of vulnerabilities. + +The engineering guidelines we follow to promote project quality can be found in [`GUIDELINES.md`](./GUIDELINES.md). + +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. + +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. + +## Contribute + +OpenZeppelin Contracts exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the [contribution guide](CONTRIBUTING.md)! + +## License + +OpenZeppelin Contracts is released under the [MIT License](LICENSE). + +## Legal + +Your use of this Project is governed by the terms found at www.openzeppelin.com/tos (the "Terms"). diff --git a/lib/crytic/lib/openzeppelin-contracts/RELEASING.md b/lib/crytic/lib/openzeppelin-contracts/RELEASING.md new file mode 100644 index 0000000..0318f63 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/RELEASING.md @@ -0,0 +1,47 @@ +# Releasing + +> Visit the documentation for [details about release schedule](https://docs.openzeppelin.com/contracts/releases-stability). + +OpenZeppelin Contracts uses a fully automated release process that takes care of compiling, packaging, and publishing the library, all of which is carried out in a clean CI environment (GitHub Actions), implemented in the ([`release-cycle`](.github/workflows/release-cycle.yml)) workflow. This helps to reduce the potential for human error and inconsistencies, and ensures that the release process is ongoing and reliable. + +## Changesets + +[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. + +## Branching model + +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. + +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" + + checkout master + commit id: "Feature C" + commit id: "Fix A" + + checkout release-vX.Y + cherry-pick id: "Fix A" tag: "" + commit id: "Release vX.Y.0-rc.1" + commit id: "Release vX.Y.0" + + 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" +``` diff --git a/lib/crytic/lib/openzeppelin-contracts/SECURITY.md b/lib/crytic/lib/openzeppelin-contracts/SECURITY.md new file mode 100644 index 0000000..4d6ff96 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/SECURITY.md @@ -0,0 +1,42 @@ +# Security Policy + +Security vulnerabilities should be disclosed to the project maintainers through [Immunefi], or alternatively by email to security@openzeppelin.com. + +[Immunefi]: https://immunefi.com/bounty/openzeppelin + +## Bug Bounty + +Responsible disclosure of security vulnerabilities is rewarded through a bug bounty program on [Immunefi]. + +There is a bonus reward for issues introduced in release candidates that are reported before making it into a stable release. + +## Security Patches + +Security vulnerabilities will be patched as soon as responsibly possible, and published as an advisory on this repository (see [advisories]) and on the affected npm packages. + +[advisories]: https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories + +Projects that build on OpenZeppelin Contracts are encouraged to clearly state, in their source code and websites, how to be contacted about security issues in the event that a direct notification is considered necessary. We recommend including it in the NatSpec for the contract as `/// @custom:security-contact security@example.com`. + +Additionally, we recommend installing the library through npm and setting up vulnerability alerts such as [Dependabot]. + +[Dependabot]: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-supply-chain-security#what-is-dependabot + +### Supported Versions + +Security patches will be released for the latest minor of a given major release. For example, if an issue is found in versions >=4.6.0 and the latest is 4.8.0, the patch will be released only in version 4.8.1. + +Only critical severity bug fixes will be backported to past major releases. + +| Version | Critical security fixes | Other security fixes | +| ------- | ----------------------- | -------------------- | +| 4.x | :white_check_mark: | :white_check_mark: | +| 3.4 | :white_check_mark: | :x: | +| 2.5 | :white_check_mark: | :x: | +| < 2.0 | :x: | :x: | + +Note as well that the Solidity language itself only guarantees security updates for the latest release. + +## Legal + +Smart contracts are a nascent techology and carry a high level of technical risk and uncertainty. OpenZeppelin Contracts is made available under the MIT License, which disclaims all warranties in relation to the project and which limits the liability of those that contribute and maintain the project, including OpenZeppelin. Your use of the project is also governed by the terms found at www.openzeppelin.com/tos (the "Terms"). As set out in the Terms, you are solely responsible for any use of OpenZeppelin Contracts and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an on-going duty by any contributor, including OpenZeppelin, to correct any flaws or alert you to all or any of the potential risks of utilizing the project. diff --git a/lib/crytic/lib/openzeppelin-contracts/audits/2017-03.md b/lib/crytic/lib/openzeppelin-contracts/audits/2017-03.md new file mode 100644 index 0000000..4cd6dbf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/audits/2017-03.md @@ -0,0 +1,292 @@ +# OpenZeppelin Audit + +NOTE ON 2021-07-19: This report makes reference to Zeppelin, OpenZeppelin, OpenZeppelin Contracts, the OpenZeppelin team, and OpenZeppelin library. Many of these things have since been renamed and know that this audit applies to what is currently called the OpenZeppelin Contracts which are maintained by the OpenZeppelin Contracts Community. + +March, 2017 +Authored by Dennis Peterson and Peter Vessenes + +# Introduction + +Zeppelin requested that New Alchemy perform an audit of the contracts in their OpenZeppelin library. The OpenZeppelin contracts are a set of contracts intended to be a safe building block for a variety of uses by parties that may not be as sophisticated as the OpenZeppelin team. It is a design goal that the contracts be deployable safely and "as-is". + +The contracts are hosted at: + +https://github.com/OpenZeppelin/zeppelin-solidity + +All the contracts in the "contracts" folder are in scope. + +The git commit hash we evaluated is: +9c5975a706b076b7000e8179f8101e0c61024c87 + +# Disclaimer + +The audit makes no statements or warrantees about utility of the code, safety of the code, suitability of the business model, regulatory regime for the business model, or any other statements about fitness of the contracts to purpose, or their bugfree status. The audit documentation is for discussion purposes only. + +# Executive Summary + +Overall the OpenZeppelin codebase is of reasonably high quality -- it is clean, modular and follows best practices throughout. + +It is still in flux as a codebase, and needs better documentation per file as to expected behavior and future plans. It probably needs more comprehensive and aggressive tests written by people less nice than the current OpenZeppelin team. + +We identified two critical errors and one moderate issue, and would not recommend this commit hash for public use until these bugs are remedied. + +The repository includes a set of Truffle unit tests, a requirement and best practice for smart contracts like these; we recommend these be bulked up. + +# Discussion + +## Big Picture: Is This A Worthwhile Project? + +As soon as a developer touches OpenZeppelin contracts, they will modify something, leaving them in an un-audited state. We do not recommend developers deploy any unaudited code to the Blockchain if it will handle money, information or other things of value. + +> "In accordance with Unix philosophy, Perl gives you enough rope to hang yourself" +> --Larry Wall + +We think this is an incredibly worthwhile project -- aided by the high code quality. Creating a framework that can be easily extended helps increase the average code quality on the Blockchain by charting a course for developers and encouraging containment of modifications to certain sections. + +> "Rust: The language that makes you take the safety off before shooting yourself in the foot" +> -- (@mbrubeck) + +We think much more could be done here, and recommend the OpenZeppelin team keep at this and keep focusing on the design goal of removing rope and adding safety. + +## Solidity Version Updates Recommended + +Most of the code uses Solidity 0.4.11, but some files under `Ownership` are marked 0.4.0. These should be updated. + +Solidity 0.4.10 will add several features which could be useful in these contracts: + +- `assert(condition)`, which throws if the condition is false + +- `revert()`, which rolls back without consuming all remaining gas. + +- `address.transfer(value)`, which is like `send` but automatically propagates exceptions, and supports `.gas()`. See https://github.com/ethereum/solidity/issues/610 for more on this. + +## Error Handling: Throw vs Return False +Solidity standards allow two ways to handle an error -- either calling `throw` or returning `false`. Both have benefits. In particular, a `throw` guarantees a complete wipe of the call stack (up to the preceding external call), whereas `false` allows a function to continue. + +In general we prefer `throw` in our code audits, because it is simpler -- it's less for an engineer to keep track of. Returning `false` and using logic to check results can quickly become a poorly-tracked state machine, and this sort of complexity can cause errors. + +In the OpenZeppelin contracts, both styles are used in different parts of the codebase. `SimpleToken` transfers throw upon failure, while the full ERC20 token returns `false`. Some modifiers `throw`, others just wrap the function body in a conditional, effectively allowing the function to return false if the condition is not met. + +We don't love this, and would usually recommend you stick with one style or the other throughout the codebase. + +In at least one case, these different techniques are combined cleverly (see the Multisig comments, line 65). As a set of contracts intended for general use, we recommend you either strive for more consistency or document explicit design criteria that govern which techniques are used where. + +Note that it may be impossible to use either one in all situations. For example, SafeMath functions pretty much have to throw upon failure, but ERC20 specifies returning booleans. Therefore we make no particular recommendations, but simply point out inconsistencies to consider. + +# Critical Issues + +## Stuck Ether in Crowdsale contract +CrowdsaleToken.sol has no provision for withdrawing the raised ether. We *strongly* recommend a standard `withdraw` function be added. There is no scenario in which someone should deploy this contract as is, whether for testing or live. + +## Recursive Call in MultisigWallet +Line 45 of `MultisigWallet.sol` checks if the amount being sent by `execute` is under a daily limit. + +This function can only be called by the "Owner". As a first angle of attack, it's worth asking what will happen if the multisig wallet owners reset the daily limit by approving a call to `resetSpentToday`. + +If a chain of calls can be constructed in which the owner confirms the `resetSpentToday` function and then withdraws through `execute` in a recursive call, the contract can be drained. In fact, this could be done without a recursive call, just through repeated `execute` calls alternating with the `confirm` calls. + +We are still working through the confirmation protocol in `Shareable.sol`, but we are not convinced that this is impossible, in fact it looks possible. The flexibility any shared owner has in being able to revoke confirmation later is another worrisome angle of approach even if some simple patches are included. + +This bug has a number of causes that need to be addressed: + +1. `resetSpentToday` and `confirm` together do not limit the days on which the function can be called or (it appears) the number of times it can be called. +1. Once a call has been confirmed and `execute`d it appears that it can be re-executed. This is not good. +3. `confirmandCheck` doesn't seem to have logic about whether or not the function in question has been called. +4. Even if it did, `revoke` would need updates and logic to deal with revocation requests after a function call had been completed. + +We do not recommend using the MultisigWallet until these issues are fixed. + +# Moderate to Minor Issues + +## PullPayment +PullPayment.sol needs some work. It has no explicit provision for cancelling a payment. This would be desirable in a number of scenarios; consider a payee losing their wallet, or giving a griefing address, or just an address that requires more than the default gas offered by `send`. + +`asyncSend` has no overflow checking. This is a bad plan. We recommend overflow and underflow checking at the layer closest to the data manipulation. + +`asyncSend` allows more balance to be queued up for sending than the contract holds. This is probably a bad idea, or at the very least should be called something different. If the intent is to allow this, it should have provisions for dealing with race conditions between competing `withdrawPayments` calls. + +It would be nice to see how many payments are pending. This would imply a bit of a rewrite; we recommend this contract get some design time, and that developers don't rely on it in its current state. + +## Shareable Contract + +We do not believe the `Shareable.sol` contract is ready for primetime. It is missing functions, and as written may be vulnerable to a reordering attack -- an attack in which a miner or other party "racing" with a smart contract participant inserts their own information into a list or mapping. + +The confirmation and revocation code needs to be looked over with a very careful eye imagining extraordinarily bad behavior by shared owners before this contract can be called safe. + +No sanity checks on the initial constructor's `required` argument are worrisome as well. + +# Line by Line Comments + +## Lifecycle + +### Killable + +Very simple, allows owner to call selfdestruct, sending funds to owner. No issues. However, note that `selfdestruct` should typically not be used; it is common that a developer may want to access data in a former contract, and they may not understand that `selfdestruct` limits access to the contract. We recommend better documentation about this dynamic, and an alternate function name for `kill` like `completelyDestroy` while `kill` would perhaps merely send funds to the owner. + +Also note that a killable function allows the owner to take funds regardless of other logic. This may be desirable or undesirable depending on the circumstances. Perhaps `Killable` should have a different name as well. + +### Migrations + +I presume that the goal of this contract is to allow and annotate a migration to a new smart contract address. We are not clear here how this would be accomplished by the code; we'd like to review with the OpenZeppelin team. + +### Pausable + +We like these pauses! Note that these allow significant griefing potential by owners, and that this might not be obvious to participants in smart contracts using the OpenZeppelin framework. We would recommend that additional sample logic be added to for instance the TokenContract showing safer use of the pause and resume functions. In particular, we would recommend a timelock after which anyone could unpause the contract. + +The modifiers use the pattern `if(bool){_;}`. This is fine for functions that return false upon failure, but could be problematic for functions expected to throw upon failure. See our comments above on standardizing on `throw` or `return(false)`. + +## Ownership + +### Ownable + +Line 19: Modifier throws if doesn't meet condition, in contrast to some other inheritable modifiers (e.g. in Pausable) that use `if(bool){_;}`. + +### Claimable + +Inherits from Ownable but the existing owner sets a pendingOwner who has to claim ownership. + +Line 17: Another modifier that throws. + +### DelayedClaimable + +Is there any reason to descend from Ownable directly, instead of just Claimable, which descends from Ownable? If not, descending from both just adds confusion. + +### Contactable + +Allows owner to set a public string of contract information. No issues. + +### Shareable + +This needs some work. Doesn't check if `_required <= len(_owners)` for instance, that would be a bummer. What if _required were like `MAX - 1`? + +I have a general concern about the difference between `owners`, `_owners`, and `owner` in `Ownable.sol`. I recommend "Owners" be renamed. In general we do not recomment single character differences in variable names, although a preceding underscore is not uncommon in Solidity code. + +Line 34: "this contract only has six types of events"...actually only two. + +Line 61: Why is `ownerIndex` keyed by addresses hashed to `uint`s? Why not use the addresses directly, so `ownerIndex` is less obscure, and so there's stronger typing? + +Line 62: Do not love `++i) ... owners[2+ i]`. Makes me do math, which is not what I want to do. I want to not have to do math. + +There should probably be a function for adding a new operation, so the developer doesn't have to work directly with the internal data. (This would make the multisig contract even shorter.) + +There's a `revoke` function but not a `propose` function that we can see. + +Beware reordering. If `propose` allows the user to choose a bytes string for their proposal, bad things(TM) will happen as currently written. + + +### Multisig + +Just an interface. Note it allows changing an owner address, but not changing the number of owners. This is somewhat limiting but also simplifies implementation. + +## Payment + +### PullPayment + +Safe from reentrance attack since ether send is at the end, plus it uses `.send()` rather than `.call.value()`. + +There's an argument to be made that `.call.value()` is a better option *if* you're sure that it will be done after all state updates, since `.send` will fail if the recipient has an expensive fallback function. However, in the context of a function meant to be embedded in other contracts, it's probably better to use `.send`. One possible compromise is to add a function which allows only the owner to send ether via `.call.value`. + +If you don't use `call.value` you should implement a `cancel` function in case some value is pending here. + +Line 14: +Doesn't use safeAdd. Although it appears that payout amounts can only be increased, in fact the payer could lower the payout as much as desired via overflow. Also, the payer could add a large non-overflowing amount, causing the payment to exceed the contract balance and therefore fail when withdraw is attempted. + +Recommendation: track the sum of non-withdrawn asyncSends, and don't allow a new one which exceeds the leftover balance. If it's ever desirable to make payments revocable, it should be done explicitly. + +## Tokens + +### ERC20 + +Standard ERC20 interface only. + +There's a security hole in the standard, reported at Edcon: `approve` does not protect against race conditions and simply replaces the current value. An approved spender could wait for the owner to call `approve` again, then attempt to spend the old limit before the new limit is applied. If successful, this attacker could successfully spend the sum of both limits. + +This could be fixed by either (1) including the old limit as a parameter, so the update will fail if some gets spent, or (2) using the value parameter as a delta instead of replacement value. + +This is not fixable while adhering to the current full ERC20 standard, though it would be possible to add a "secureApprove" function. The impact isn't extreme since at least you can only be attacked by addresses you approved. Also, users could mitigate this by always setting spending limits to zero and checking for spends, before setting the new limit. + +Edcon slides: +https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view + +### ERC20Basic + +Simpler interface skipping the Approve function. Note this departs from ERC20 in another way: transfer throws instead of returning false. + +### BasicToken + +Uses `SafeSub` and `SafeMath`, so transfer `throw`s instead of returning false. This complies with ERC20Basic but not the actual ERC20 standard. + +### StandardToken + +Implementation of full ERC20 token. + +Transfer() and transferFrom() use SafeMath functions, which will cause them to throw instead of returning false. Not a security issue but departs from standard. + +### SimpleToken + +Sample instantiation of StandardToken. Note that in this sample, decimals is 18 and supply only 10,000, so the supply is a small fraction of a single nominal token. + +### CrowdsaleToken + +StandardToken which mints tokens at a fixed price when sent ether. + +There's no provision for owner withdrawing the ether. As a sample for crowdsales it should be Ownable and allow the owner to withdraw ether, rather than stranding the ether in the contract. + +Note: an alternative pattern is a mint() function which is only callable from a separate crowdsale contract, so any sort of rules can be added without modifying the token itself. + +### VestedToken + +Lines 23, 27: +Functions `transfer()` and `transferFrom()` have a modifier canTransfer which throws if not enough tokens are available. However, transfer() returns a boolean success. Inconsistent treatment of failure conditions may cause problems for other contracts using the token. (Note that transferableTokens() relies on safeSub(), so will also throw if there's insufficient balance.) + +Line 64: +Delete not actually necessary since the value is overwritten in the next line anyway. + +## Root level + +### Bounty + +Avoids potential race condition by having each researcher deploy a separate contract for attack; if a research manages to break his associated contract, other researchers can't immediately claim the reward, they have to reproduce the attack in their own contracts. + +A developer could subvert this intent by implementing `deployContract()` to always return the same address. However, this would break the `researchers` mapping, updating the researcher address associated with the contract. This could be prevented by blocking rewrites in `researchers`. + +### DayLimit + +The modifier `limitedDaily` calls `underLimit`, which both checks that the spend is below the daily limit, and adds the input value to the daily spend. This is fine if all functions throw upon failure. However, not all OpenZeppelin functions do this; there are functions that returns false, and modifiers that wrap the function body in `if (bool) {_;}`. In these cases, `_value` will be added to `spentToday`, but ether may not actually be sent because other preconditions were not met. (However in the OpenZeppelin multisig this is not a problem.) + +Lines 4, 11: +Comment claims that `DayLimit` is multiowned, and Shareable is imported, but DayLimit does not actually inherit from Shareable. The intent may be for child contracts to inherit from Shareable (as Multisig does); in this case the import should be removed and the comment altered. + +Line 46: +Manual overflow check instead of using safeAdd. Since this is called from a function that throws upon failure anyway, there's no real downside to using safeAdd. + +### LimitBalance + +No issues. + +### MultisigWallet + +Lines 28, 76, 80: +`kill`, `setDailyLimit`, and `resetSpentToday` only happen with multisig approval, and hashes for these actions are logged by Shareable. However, they should probably post their own events for easy reading. + +Line 45: +This call to underLimit will reduce the daily limit, and then either throw or return 0. So in this case there's no danger that the limit will be reduced without the operation going through. + +Line 65: +Shareable's onlyManyOwners will take the user's confirmation, and execute the function body if and only if enough users have confirmed. Whole thing throws if the send fails, which will roll back the confirmation. Confirm returns false if not enough have confirmed yet, true if the whole thing succeeds, and throws only in the exceptional circumstance that the designated transaction unexpectedly fails. Elegant design. + +Line 68: +Throw here is good but note this function can fail either by returning false or by throwing. + +Line 92: +A bit odd to split `clearPending()` between this contract and Shareable. However this does allow contracts inheriting from Shareable to use custom structs for pending transactions. + + +### SafeMath + +Another interesting comment from the same Edcon presentation was that the overflow behavior of Solidity is undocumented, so in theory, source code that relies on it could break with a future revision. + +However, compiled code should be fine, and in the unlikely event that the compiler is revised in this way, there should be plenty of warning. (But this is an argument for keeping overflow checks isolated in SafeMath.) + +Aside from that small caveat, these are fine. + diff --git a/lib/crytic/lib/openzeppelin-contracts/audits/2018-10.pdf b/lib/crytic/lib/openzeppelin-contracts/audits/2018-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d5bf12741c8a6d44ed597de7204fde72d91dec35 GIT binary patch literal 1000527 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%0AXGSxD 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%0Ds@WxhHVsCq?&%C$272odl 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

%X-{jq)zF)pGEGKPHkt7x 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

@!c9KnY4NvNgEvnPA? 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

QsKH{N_IQtXo9hrt1|lnPuADU$b1Mf#WXL540@w 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%0DQ_tNgAAku*dN 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

fwy2<7q zDUf=Nh}CM0fE@!qOXtsLFjQ>$FZ2yw)|OeY5B{dg9ZVSOX9Cpw#z`7!j7aa6(6{a$4FhsBu72G5Gt3ar2e+Aijb6l&EFnK zgbkye>R;w7rO=AxuAv~#+b(Q)j+Y#7Nn#15O)!WjhFJ*}vDBRwPW>2EYH(nfeo!Zs zP>e)wKb@f2;oB4uV%v|fqUSmpTAMbtW&7L?cX91cn|dOtrX8qUXNP$Ynz=hWo;#yF zeTFVdpOqs}-XfM|7RKBO^#dvUB!<69j0Pv*DFGL^*?2Xg4WcIZ81Ze(rMDXv=B5gr z<9w|<*ww7#S7KM{6vkIj!s}wu^RAU+} z_+K98!d36qresKVe%TT&ENQq3Sg+fC`0q?GZUKkR?AYGfa}DTY*=Qf_l#vck<3kiw z)H!4f1H7PuBOsy~O!MjSBzK9$Qk%vRJ3`)gI9gz7WnCOjxn86hH5G zgD2-V=1O-9F}V6$>;W)YiiN_{+hFUvN-Wr1Z;}-~3CYu48b8G4sV%T5_<6e;?41i< zjxjYG61gXMT!-zH)h1a@ zzc@*6>iAi^b8nC5UC}~_MsyT}^^(~wsL=@x7|M-zzxr9lm%+QP@EdH+{C$fX`+;Q( z6QV%O;N3e8@LmWGzhK^LA0Q5QC4-Bno^1V-xPGwh2!?h-RL=3UU`*a$N(Myz9YXbe zGV-Jy;QRF*wM$$KEGL|k|4~5yvx}Jma+ZO|rC!)gkGV|_;9cFr$DKk)>BWN~(;Eu9o zomyAR7ZTY?Mw9i78#mq71J%i>vEvcO@L4c;SS7$}G0MR95G$TbzhB=wK7TeZ^v?q7 ziLHMk4zvAQPw@rFW*L67mPFv?af}v=)9%L|y^|wk-!-aR|Llg~K39@`R9^xSxPBM= z%b2T` zPo$0~?@P|iQG+?;Gs3Zeo zXbX#;hntIv%fKX0ES1%mVtNWu);V)bS{0CYn#r{ph#h?w# z6aK&5lWm|BG){A;kL3ay6mvhXy9Cy3k{vbYCUbt;C6TYg5`sON*TKz6$DWUL*^*E{x;lj@bJ z`4&lWklridPA3CY5l%c%$^n1Pm&%PAQplvCa{3Hib?3gz27P1s91=R+^1+6H6s zX}R-IsHye2ggRzPgJVhe%bq-+OzFo;e9%7PGPj1Aleg=h9i%k;OnTRh-aB0J;p<7I zw8+$Jd~qD@_#kGO7hC21FO8qv#;DYxlStWbP@_fqy&$j#>utVouc?l14i?Wu0^zp8s}gvot|7hnFNC zNiTi`YloFI@S9Z0z=e9|Zi9c5kfAEH;n^;ShS75#=|_e?dpF__yh8mH z@lHAhs3jbuCqTWS2G)ou-vDLCDK&o^B(jY&xUPFgnaQZU-r>t&d!_}x_}*z9Py%dJ zo~*7^s3fb$Hh);$S4u^*)^*L&3AJx#kqJWrpA%fu8vwaoV>(@ZVbbi9->7^y3+t`j zOdyK|8R>PHS>NTy{V24#@~TB{Ai*l~%)=y%p0F5LwJi!m{hd_H>zP%|P&@OPnn{(p z)I&0*F`{<3ibJlFcSRyTh*HXKypRwbS9wdOry13AL+CQ-QzNa5dJR*(3EzXU-09Q2 z$F+?M%r#y(sagSlaDIZ#Eb7m`f~_?_>%~Z)9B&#@`Qs7Z=aw|SF4b$MV9zTjxm^UQ&3@=GE<<&7(JLN9}mZ)$p_t0B4G1_N`E7X0ysF_!kS!O6?rx z)DQcdDb-YS_Km5JRCsx{yrWTQgN%2B{gCK!8Y`28OY9u+Ko1@@IW}nN?#MruYBeF; vmz$7%8{kQOm<9x(L!%4$|Fbnt&IXRo?v5s=upAsL9Bk~cBqSnoqOku9foUHh literal 0 HcmV?d00001 diff --git a/lib/crytic/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf b/lib/crytic/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7e0d08387ad3be0a3e74201566eca3167aead1c2 GIT binary patch literal 155606 zcmcFr2V4}%(iagF6c8myMiCTn7j~CjSjiwDIp-`nrzJ-NK@m8KN|Y=a$r%wzB1!Th zK{ApgXZ!~6PVS!Gd%W-7@8>$rbamCgs=8~sr>lov=8iB30%pgh{~8ybgbSf%rM0?e zip#}?%c9_HZ9vN+qibYfhsz>vqHjm5PKyBQRDOpncLf$SXtUJ0;cJ4M27%U6g?Z z!0*>g*dXj+7=i!A4$yw@;eRm{ z9LWYovi{J~(h6l@2h!CCx-y`pt~ubaBYS_>`R54!irxws7cSq&1xU}>K+nwD3b39X z$lT(@(#TE^;CN{Aqapkk zCH^Yj&fdZTkaF1IXz2f&1}NQo<^~`uLlDr-4*J+(r#^}u|E8tArM(?sY-?K+2cSQJ z4DBuT{^%Y@0p>3ZU`Pa@8WM^;7^<4Ing^r%=->A+bD-hxV_e7yB_e;&Q4dG1E(FYa zSkTj@g&Z_u;s5=PApg;wgPSVS_e_DFen@Eof&-%$!O9AUK_O5!Bn*aN<)DSI9mRnp=^wFZON+bt`1d4;!PZ#keEsozv=+hj z(EIrK<7sT`*kLL}NfZg)7_`m~>>06;Wy9R4i>)VY zH(4oeIP}!Dj4X@Gzp?txb4)&KtBtD#N>J(HH1 zMJb~O&;1_Tp4Tg!W0*J8y;GE*=wQt772`w8^S1dCX&p~3YI>N?Q=>mizv5o?MW7?2fpRQ_nRMMuN+Uc>+eV4mg>VCb_LU3q!TI zlnM=?j9EJ!Et>h(vln(Bf7#uTD4WKJh8y2ho2{F!jbnO?c%RstfH80G5~*Qd%dc@M zc%3$Oufwc^gm{lk?4p&ed}q!F{sjNB>iAHB`#EQBTD*mKu+tK)RY=rkZ-xIxbJ~p! zl~f6x^?le*$ajz6Om=pDhIDgK1nI-R37Ydl&h)|}j}c#3aKf)^E9;^gg?fn#@n5Lr zbkA>>*B523F?)WRRUTW##qt)?8`!4!Agd={q?unoZsCgPZZh9+v$J=1T++)mGVU=S zEtusAwDeG4eDVJBEctR|2dwm45BEFr_mve6^E6+CAzlaL;d|%)J~9r%@$Vz!#}wsY z$k_rh=J#i{q=CMPu7H&j5TXx;790r&L)qbQAU<%gLBJdwNOlAp5GH^L$x&#cJ)EiF zvd9_OS=rm_0Z;YAmXN~RgVyibCnlq8^d*LPGeuZQ0uSM_Vi5RfLD_Dw<;PK%t>3x(0%+x2b;@n ze=^@1KU%W!3HQuR%DFa{#67Ffl7QD6O0m^$uG<6heJ*(G!!v#vG*a5%I`(6~Jp%P0 z)I1z$HfFJHX>GBp!lsHnn`&yyz-`-LcX4Xb;~P

2ojH?x0tMLX1p#1!i~6c>Ik8Oj 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 literal 0 HcmV?d00001 diff --git a/lib/crytic/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf b/lib/crytic/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf new file mode 100644 index 0000000000000000000000000000000000000000..154fe75212e317a87cfa249b9101a04e789281bd GIT binary patch literal 204184 zcmc$H2Ut_f);3r`LBNV4AXrckDG4MbR0RPQDbhRAdk?*;2r5maN$(LqDm*#DszVM$sj+wK*|EP>h*$(ntxOQKAa){NULtK1Ees=!%y(w`2qSG; zdT}#t6Gd$^Gi@V%6WSYATKWiDNo_Mz3j_lZ%MB}po~gwjWq@J<3vG48Ps$}MOtq{u zwSfk5+Uk~e5*GS^eh51=hyjNJhW2*~SmOw&Bh-ydb%}PZM2j^D5sSDL0$`+VNehBt zdrHJ2rfv-U#2EFawk2ZsXtzv>mR{4;MAOL1Qs30Xk^wL=h;7#lEbdF=Fentn z4yNT`XJ>|j*`QdXsnF7E>zgs@n*ePs^(_(FCYpBGwqH&Ar?yZw4rVa)M_V0z6D@rc zU97sV4*OFJHV_9h3`d)uzOEjVrM9)Ug+2nSiDTELe`@w;k~jnrOgg3(#_9+Jp!jd7 zvav&%;ZPU|iWw_FHvvCjU4sD3gJ}lc9bdoEYh-Hk2ez<(#MW5f(h^|Dq-CmUi2z2x zu7SP{(?6@^05P-TSm;}0Z3_!i3nswbmcYaTJj7(7ZEmG+q0MB8P)BGRYnvdjz5hD) z{{+eghckoNSlL0CAprE=#MFdI+t$oTUsE5!q;HHF+m=k~0GO4fw$|U^fZ5rYS=rd( zP}Xla2yLLD7BEEsJE|K2ymr0u)vDj7$qrz_} zSXvnyt6N});Me%`n+6DV4I^zPQynH?ssQr@fgSX_f#^3at$=B%t!}}j0~~xCem@^b zP!0$)9QI>=S(#X>>u58nYv?lpGt(3^*DyW&8vp*RmX)0u#sLAdV#X-o^Ia=y0fEd? zAMm!Ox(SnpHj|D8K%dFN%7jVXL<{47EH5ofU|5+NX=A6x&!^;{xT#>`+3vruffX~< zzC|@bTZFI_W}ISUl{zrOu?L#!v>;3)mK)zn1a9n>U<&2MH4L;h5m-rmFb5P4V`T&4 z2NZ-E$1pgU76ixmS`v#O0Ym_83lprc87okQjs4gvDLr+Jr7%?(SRtUpw4hysV+y{~ z#mxV2bcOVd05Dn>AtQkDO>Mx^+C(gOwM}#pdO*Bn!?Xe>vbMT0k!^T{Y?nzF>k+3F zxiP}n=f~;pT_5m>5on98 z=JMw{kgepf06O3SDd~_tJNmM>{7J1du`T$tW)e?6=y^0{OEt<^2lJH1;CDXMgk}{i zpL|>EdhvXgeQ9IsK?8{u7KI2WfAnXFbduQ|y=tE_(QPKU=tXH_z8|ki@_Ot5< z$(}5T$oA~2T$NoFF;4H5!Ml)>HckB8!pE6+G^bYdrQbV~b5h3SS~;|jx(n@!$STJ1 zAOq}Trx#$SN1=6^SNUf~EX*bfl#+ET3+At^YVt7(NY!`Q1urVAJ`Bt2>UbP}3SK{) zn#wCJd>T@zPmOO`e&xR6$3_hvq2eeGlC`w!0-lysqHBQ)#4cTLdGMp|XVrCB2~o;{2h?BU zx!)C-x5*2(QFA$Rk|n{oM)wA<_+V#tK^`6*M?4$zrPgjWSo_5mC$+fv{Uk|q4}t~q z0wX@#6;EB(ZK^%I{6N&JhR9p!>2Z1Zr~45r%aI2d4_x6d2{xOP4WG22jpbws9(xQJ$Cg&q-KA_Wz@f;vW<5bzdRHMKdh zFw(VlplI`6EPcj(M1XwUbagFbiGOd07;|B|p4G=3`;r;fbk45A7E|=#y|R!*xij?P zR=Hcw{*VcyYBX;fPI@TKNfVD1&aj`48N^dM76c_)%i_rfgpvM zst`DY8O#BJz(KSyb`UcR2IqjX(_+_UyD^j&dln{Qk<_*{wX)Cz);8ER3$SLi&^P`E zIQ&N1+FHMt`!VY|aJun#vmOMTS6Kfr?~xJpJ{PO~(pJ_^7LZ3vthyXPy{^1}V1Nk4 zpHEV!!Rje#l}GR>8DA(nKf|T|wmY@vi@Iyh6Epl)+MI))W&}OuJ-*bIui9F+H+egD zazlfRyM!|`)JjV>8*2-_aywlTFQz-gOE%>;9JaHWla|wh+vWt$ArqFDXQyPHrLK~xcD0Jb`D~{bN5u>HzVPyK>(=n`mG<_1 z7;HnoZz$NVNMFfYT1B$VD$ho&_%yC*Z!B#r(PZ##uhF$6H12#zIJll+KwMxXqMs1# zXh6KPKDx6QT(+Ik$)DNCm4+6mN9VQoMNOIJQ3j^QwDVboyEH5>Y_OnBxo9jmyC)J? zQvBPT#*IZ7N|G8=-*cLlTW^$aBu+V~O*z5?xe`++2~SOQ<$7ffBSD-@E$bt^M|mc| zjLwS#jx;?*Eso+!LWr)k5gzZFF(U{|lFiMwLN8-cV*vz(?4n<1jh;jLtI(@OhH$0& z>4@xBjfnhKChb>0;F{#3nnQRXqtLWBGq06YWbn4|y*))&NH+>R@`c`O^aoTHS4%k6YiP4a$!(Ok} zP(6*V@mygB#d2nl4%xJ!hK(`uT<0?qOSkl*WeG|ixzCCdybgMOHo&*6PW=kWawg|` z>Kd;EO^Op5l}Ywl(dcMaXj@5Kt44ea_cRHToDx56q)YXlVUjjl!T}n~E9<$83SW7z zC=$to=wmZv(nq68ue2(@SVk!ukvcRE33{u5}qTl3QNP zZhfIk)3_No}0Ro3@FBsqs^)KcK9=%N@Pq0*~>PnfDO3-8^-n-^kTjbv>B*!Vt%`H zv?77}v%rvUXzi=kaY*{SalApwqQ!>zx>Wl5N7;)7H9^m6^ZimLDzh~ilaXlO-Z*bg zrEL7{Zg>|TlT=US0!0W>6SLGYMewN@I_y`h%Bu@GT37i+Uh(JDO1lN!71XQ7d_C3+ zPQs(cR$%IH7JaM0)IYHfd4_tCbchKT4WIKPP6ej^==66rfVT6U+88xBXs)E#dYp=% z(l`{M{H@i&G1_nBf7=Qmhr03SUX8UFL;}W41ZGTY$2wO_hk%mqqdXmTy5B@>EdWng z@35IG={~CHM|gx|v~Q0o{_GH+^N^Wa5Z($m^+DKmLVQxx4cCh~2fiKdM;z@x#Dp#V z(_v&{+}|kpii%N-bI2nu{2K*$)CXYvBCh)pFTPRkUPPSi#}otPd{D=~9sZi9L!{3> zsu((~USL|>SvNVRbLTcqN6Nzhb~K%e$nC*vCq&^%xpRwXY6r#+4VT;H!Y zF8P)El%O%WTNY`mKW{|r^w>%4loo!YetGZ zniSc&n%ptX5OuHq=yWngOhV`}MeNu4P8l|S5y-_HX||h1210sCI&MMOuP4?mM^HDg z6+pc}PRh3mpx#|iuKo~Hix)}~7cKe`ZUs<(q$&NI8jQABl|P{oj74MXe^mUGh8L0Yj3=>TUjn8Gampjd_)t@pg1DiS;SoMZG-d@@mPlbz$CaacGWT=$# zWVA%zZm9(=*NJ(wjjv>_bIjD6b`{;ZTzu(FL!LvYQ7Pe!g^zs!+A)nfRQ~YjBV zyvMH9ALC@n{$hFKz!(E@uKii}L&gIAs$!m|{G)WI9bnOoMO}D>D{gnBG9we) z+!~m#?kk)X=`=8&TAVTNu;e9)c56TziC*czLm8{-u=RC}I)%c#KCG_D%nSLSw4 z=vF%$RaqF*=4d%Sde*>FOY{Ctx_(EM>!1xIR9K9}r!S42O#Wym`8KrY(H2)1RR@7t zdzoc+!54z6*&t&dZZ3+AV*h%-QDe<08-rS^JNI|Qpu(kYig+cRR0SCTC&N6fY;Gr2 zM=x};&#EsNI<{Uk1Ars8j8i^p8zZ(<@_HWKbjyWXyqcV)cpiR&thH=X$8snzy-XKo zDP6do&L)xFv}{9-ZKG0D??_PERDJY9*Rc(0s; zb0=BCjG<~2Yc`r8plkn|9unH2DCTz$rrTJv#6plc&E*RdS+j!od-=54vwFi97%no# zXlorrux9P!Jfnb5?Um{ly z9X$$ci*F)0K!=&WORaNLd*gy)bRAdx4*F*x{#vYRr%0b&5ggDzvHK2mWtRp(eA$lk z>~~6Ek-qf}hZ0WTT1UtAu>EXoZu+?11Fi}1B6S+^>pv-dp7N?^+UJxg8=@O!5Bwkz z8itD}iVMG_`7N`$x8C1ZPgWP_TU!4m21Q;M%VE07kWC+>O%Bl3xyN67?T%iEAU<_n ztXq&m01E86kMpJAVJ55uK*#gAB31~XK~9&06*`G}hi!uqihhJ`^G}7EfFAq?<~ku( zHAa^!=`O#qA)R|aDgGz40f*NAq+__~{{-guz5mW{>*e@*m(J63W|wm6{p1R_bE}uZ zl*E&LY_IzWRa}CTE?z0zW>$&}L%p9b@-ptQ27Z-~d<;o1tNrMXTDA${T)5NLm(Ycs zI^%Zwz`O<8=mJvpBOkrf%S39=4IM-v;TAEIvyvM}s^85!I2W~t0`v7`*hP-Q?MU+H zg-y$OTPm2ypikSug>9b!M2rRY9$+?BCmN>>tg5{72_IYUYSr-UVTU;f=P*Mf-_ARn z)%AJH8B?1@0>I>kMFIlnhM{utle5Kb+C5|IT(eN&5A(Cd-U$P%Hj$iQAD2;p6Kp%8 zYHo>)zl(~Zs%-HM94PM6RPQj~+g3tNR63r*pvu9#BR(>20Qw!ucR2`k} z1@YH%x$EuLxCPl9X_~>-9AcV16WfEWIi}bPx>@v_nu|HbSS3Ikg0cSp0DOGT2S*VO zoRFR!mM1{L3x(60A3eBE_#boqJ@`+|gWxRIbS3?6ls$3%2^`=D9BX5|^>aVqbK3sK z5WfZgW?_`NZi14%34b87E{wuqqPl9akQps&Sc5KaZFO?cU|CAa&lp@)Y*$ihVhJum z`Lc+WINnHN`qWn5Ww|g**g^%)1@TsA53iE7Q2B+6kW%8h9 z#OT8HV6MAp>9*35yhKMGHA{ZO-OtU9(h;}T-Om%WQ~lwzAD?5>8=?C-rwqmPrm-I% zy}q_^ROj~(Ra0pOJO;V@iFNt`dfmgR9@F@Q;*Zb8&K1a&9Q5~(aL(*sfT>XG0Ej7o zii?J!ic1qi7fUt55s=ORq(i0^SjM~PZMxRt5*jik>u6FT) zJt3~m@24l8)#hwFCyxG#^qn@`p@i#Sm1s!I{xw> zcW`g!2*l$4qU+q^Rljq?FTC^9;!;9T43ZEO>qMq;bK_ivTkE+BSDy|J4#bkQlN`D} zF6BU9OM9>}S1xgBnA0Mq(FEg(R>EMH_Xvm!nk7Na)ZgK3&(KQpv%b^vq$Ah(Yr_Tg zLbCCw>lECA;GQV3E_beJx5X<7+tPk`Hc;YT>DA!KcT%0td)M!FW(j zeQSu*-(NENHErOA%3sX(OPHUy6rg9^wXL?o~880bWhG4EKi zj(pb34UvJ*q8z~U(jhitmm|!SQ)qfEC@j;H7oBcY-mg2K;{|sM0uiF#y%f-+usp=1 zNgDkKG)fx4r+)?+V8VaC82jo9%l;oc{ij(JyH?0E720 zX8R?~&)hm4dSL90;qe&c?kBoD{kB_c`fb2|N2~;*>Li98-PNj(w2Yn>57KmqU#XW6 zUEV>~NzkZlUu2W!3yV_3+&=Ei99!yaTu)v+5!Tp!%~MT~!-aRXdEPQH&bh#Zo{!pQ zDkuN|=Bw)Q=iRjJv9;Q2Eo0FuE}AE5GAZWIq0BhMGNV{2lxvCaR!hQAgIjA;Y-bMN30q=Tn$6yd!JOxt zY@2^9)YuIA4U8)(Ry9T!9yM0AFREI=?q|jSfcC5%r~6Mj_6PKT0Q39af8#ec6jMAp ze&(N>?OQ`kf75tQ9-Vfer|n#kpv^%`T+f+}an%Jfi&$8Aro}3 z4v+CVjL8!kFs0QWvQ^=l(1ec5zcNn&9GyS6P)T_ z`-)DxD1R|@RTa;Sgv7K;8ZYyC6rDl_6*ivhT%kq=C27#yyL#Q1*RYiAbCp39&*xUH z*T~NW!OtORA4N|;*~LZW6DZ8H`3#^K?C_e0@*YhJ8~Ej-s=Q%!%f-vCk<6{FD;0{K zX-tyL8#RixoNcp{rLnwFNS6ImEJXB33MfPN4 zIy{I*B>|_@oDPANwAfZjF>{a7Q=b)InShwj!lJX6CBk69I|d6=G0;9h>h3|OjIJ6$ z(_1pS5LC8D=S2!+P;uiqgNP%@AZ}!TWYu-2I+MJX&D5&n_GlC@rvX!e5?Mr8d`#;L z@tJlj>CcKI4Hh2Bx5o--)Tn`%3XHOOldv!r>W04Q7 z`%Kul{ZV>x=f2FkJY>hG?JiI02>I=0;{xC{(c8wurs6{^n_aW2+Z*`War4qsg*7TyS6wD3+cgo8r}~U3^%LiggXrRIo9+27k=%P1P7VbHZ&|$Lkf*EM)PIElYB*@NBDV(-2o4@Lo zXT3w}Xt&lFEWt&|=fh#Va;=SPIN?Z{VA4j1jJ?c_Q@-_+iHqp7v))@eHdc#D>Sd#T zWOZT^z7A85<)S>E>DDuITn=X`^(>lQLvXxeSX-!R_sw?k94>5V3(i^z>zjVc?Q*7y zY$J7J7%E*fXCAto?*LhQEWJ9cZLeBWpPAcVTnus09e%}{R%CMf8jEVJU2pCA7>3W> z5n84q(^M%oZtdadtyNHmWjs}aK%Ny<+FWfhqfJejYG7AAv#RsfdD}IY($7OHrloNR zNABh;Y$i2^O-&sRhS!iq!!*wHeMKu85w--ke8^IJ$QzVoeAJ}5<-DpCJWM`sU9DJ9 z_GvUxyt9cOukR^2l}(Z-LnGkW*^<`7km2N;m);%Ju$)^a9BA5GJ@VAoWP%Cu`9ki5 z>?dRMlxI+%+%`$A~~MxMpxl)zDU>VU*ii_rtd)c`wz9fI?ebM)1qtfa%wEPw2a?h8UNAVFAXS?Rxv(NR+ z0J2q$%}Zo8gCzwnx+6T4Y*FL3blf?@wKg@zG3ldzd6n{KX*y$+$)@eT3>t0Ik|Ljw zO=p_sRVpo{zw)rAFSggKT39tZ2Nk5SsfEan+i}|8+rKcwii}K2TyCEzDMz2AY1S-T zfki@82G30SjvI$c`uLm7U(0Kb+n^b7JkqdY6;8*SR;8Lj)4W&_thV&>+}U@_2O>{T zni5Z6er@Td8P;gDgep}_ROqTFm>f(xsaqby%^Q&yLbqiyuYac)xm-Wn0g7TUoo6U`Fo1?I5KSE||M9FMIZ zLf?-esFbW^qk7%mPhNGisP`VVD}OYXU(urkQd)}4n|#GhtfARsSjItfxH1u1)HXk2 zL!;B;zS62$G&MmTLo&NzzhM;N@M2Y2z%yRLzU5hlssvkPVySW7MqP0M1M*ppxs|-0 ztHFmwCmQkGcCXQ`0;U~%nR8*2^KdtG(aIZXvS}Ol#{%!p$u1e>XR_ypN~F7UHNKYB zYb!BGc32d)huu2v9cn;dT&hPeC)JZ7H>jH8Fl!HO8869SoOjATZIocY@sOto>DCtC zpA2gt`a&E^9xmp5@m@t?#fLCi2ZHW^u6oq-oX5S6bW$fHE)^fWf-ifTsj9a)y4iiW zHCgp6fpf~HwJt9!OLtYzpvMSVD671A+t8beuxRx$gPQv+uT%6J%sBmQ(x!WPoY@Rv zC4COf1Y9loksN>?HuE<&g*^>aUrr5vem66iAHgM0w<*w7E;(S*B8H4io3kc2LW=3P zZPM2%7-tUViJTag58p^tqfbiFX=12*M-zCZ+SgRAon3%QuGz`-VM0|$>BAzd3jIos7w2H3Df?BdesdJ-(J31~*O?7^vBwC;h@ea(d=mVAcP!B|W96>3w%zU8^uv&_=m!BWnMzV}CDiCf;}sv4Wfw0zJlteMvl&gY3C zxVp0*tuq=XmCFWZkltVXu3s`IQ^|{u6Od9QSJufAzd zd{LG9URA2Ibf;!9>=+Bv)d=#@?f&V|`hvS>N9cL4C81_im&Ze&m6a|n&r~H+2wW>k zZVIF9UV%(+J*C`qs-JD+o>*lQ$kQ~aA3YK_>ALmk);5>lT3%uyX$RliiSFjq9K{-| zy6tzv8Dxn!HfFi)P5eSKoK9>{))Ay^yz~(b%Wt7uk^EE*GtU+tnTlo_PZ_J}W8Tnu zCE+|3Xt&l`WTc%?=N2qpCf;nKF7CswgRWcav%9MwHD$eHR&Bo)OB@bX-?laivV+?? z8Z3L%j)VpipQE%GaV))6L`B0fxmjFV&^}(fUX$>lY9>5;U$7!I1T7t&>&`OJ%p6tq zwA?zW7retKpg@59>&wQNw2J@1%f^_Oee0b_F&Xu-QEU(&x3V0U<$Z5f7 z2k)YQcTw1OQP_4-z9zV_?V^0m?_%3UVcSJv+eKm9MPb`TVc$hz-$enEz%Yu~cTw1P zxv=k|u zAQk5igup;b9}ENr(x(1v3t`649ti!&VuZ580XJcNgX=Li(6{`lUwQ0X-WRT)FcV=9 zEI>d`Bb*(=4g-eBzexi#h4w-N3}%L~fj}_84>&Y%yz`$~12cv9Km*4oU^ZsZUwy&~ z`R1u#`UIQ0hwBkc{MZ8r5G$A&%FYg?5z+#wt^XDYO!V3l31IrNv4VgYh)V*;AODFZ zFtKwFBz|}U0*5kl{KXp(4j?h~?_=5@GG%d{vd8cW0>hc%5H<*Kg8A3EU{9`lFbj|i z4a^ld7&trPa{1w#|H3ZVGyER7;J64l{Ca}H31Sck_?zQ?HDSKzUE{b1yTaH54G;*J zGi*S@F5sSjmB)V&O~D{22e9tJ<$>dx|Ii+L45v750g|4-X5r$x1q}V>tY5k1kIC)0 zzS(0;1+hVal>i4ASd>BjeKLCuuI#|x0c>D6u$IIngX5t8#xi>hvT!hvg1jGgd7S;bBN$)Xw|B5slGZfCs3J1o*|AD2k zS3i4*X*hG3m5mv)I}UJ02RjVNumAhe@rNBBaGZ|40^0)>%ozs^ECztoSAfUA%w>eIM`@$l;XMw*bd|Ch9SQSvwzu70oP4? zjQYT84Oq)_z=6x{{|%qLM*d&$`9AH~|4aMqG5F)S>xW`ocLCR|zzzwR-DH04uD@<# zf$On7o&i7{z)}v_F9ot0W|e%xau2SLHi?7;aA zxUcs=BDB|7{&PY&)9}Bw&>n+1j>mpz#`PF*GXCww`1hT;{;=^CuHW_;(gBUkz;YfN zm;RTu_8QlJP7B9-|Bkix7~64t_(MOA57}VA4VAxNQhwXf3uikpT=(rUvICdOzZ6oX>hdnU*;WQl8xK0E1+4{QY+OI<8H>drBZP;*} ziG3)t2clpgWI@>B9KbW2|7)gujP}1^isR(}nN9b28o+V>4@$Vshq8WK5dF&ef4^NG zuD|zqMgTTvV`k-m02?vVvibR$J4`)1uYwJKM?en1uYxq4)5PD zXmR()#P#7G&j=u32?*f;gWyowf1S!+&jrAJLg1+(4A>VBm&%Xj>VIw(?2eD$BH7>V zlm!MB#u#gU-ypAEQPh``<9NwR2CBoA>zeZk){!^2`n`|Qcu~`ORGyofhY3Y1&~}t> zZ>1Udr3yn5K7L3&LA>yqCMj7%CUfro)^0@m;IqM{=FE|}`HMxw+*#|>FjPdEvjtH5Y#<=qAUDJ=jPJv@dv7&z4qpgC5 zJ9=NF;2|1!M43Mo^M%Bfk|c?V;7=UAbS!W7=t*y=_oPJLZ0XLvj>dZk)|+i9KFi3F z62j)KGYq#g>xT?3qfHsC{TbkCnc}IU8+jieOd?GfFEJ60HG2AAtZLr;BAu1+K`8mI zU2i@tto44_gz2f%!uk-okyl%u6?FM6cDf98gA1>dIr@ZEn4_3@L213v6Qv4{{K_J< z7dF}=IV#i8>jouhylX)(9g7011M^2}Q|y(zp|hQQjYZ+shJ`P-qV5}K=osrHPTW?~ zC3yZ~IwNUQUrE~}>TquYWLD?>Wd<1$Wo;B%xoh!5qh&opPDgmNX4Q#O=e*HeA?5SK z;HOvn$(*Dc?mlhR$gbD1teSKwE_K;Z>^U~(vzfw0lmheR2PMjl)43RkKwpjsHve=xA$nY#)u0zNi4`p~|-ktN7Q zZIv9P3x*3Vcqq%BQxMyp+Za69qiOoU=tVEbhxKMpPOX5M0?<>`evn`i*lwCRXc^|W z&88%-WP(!PuAg=t$m>mtgrCVpR)orymyZ`~Y&=0X4U~D64yaP2h8~m&fz5vqG8@rSLcn*~!a1 zv$i4Sz1HyfGReC8=T!A1bHdnz`-CAJpBvJ{@C3pf`qkHpU9E~!kvFm%Q=|HQL>w)T zRWhqIy}SNcY6hLuJ=VlwarA@#o1%wN##z&b*WPl_*qA->c(0*gb>w6Dy}MP#c8~Hd zF8fL9e~LOP$5Zv#?)^+i8)EHwr^kg{ISyOd?uwTqJmM;T56OsU7eoC}9IH_Fb0J+1 zw4N0nFmFpcS%4&t-^Zeq(h+m5eCes{xb&TkTgt-90{(>%n-5=KToJ3as`B;nM0u&1_ORbse0e8FyS<)$ztn{>A_7=Swo`vX`GZ1V3$?(T ziF}0cgYh}zpDL9f4iBN(*>pr|#;g=38XWnli1qJ-p-Fjo#7a`_4eDvR^GCH96{GH2 znzNG#Qf*wQ=7)7Cb_`Nb>*TX_s#R3*y=~&KY<$uvxlm%S-X!);Y;Gv}+_Lh` zlb+Ci#T-F1|5jp<`~yL*z+w-(o#x;o)f{}PXV5S5;U}a5*ek8lKG}!HHXoR1K7ZJ= z${->u%8JoVn=?=WPA)={{;uS%Zo0dQo)CkBJv-T}fEyHY{tsI?Pw@rmA5*5uxqC(B z9de&%mMv-4353P>8=E|vn7kTMDqm_>hl!YJ5qoP>lbCE{9jDsRI}M9{@?_ZJ^($Gi@jTx;kU ztil&2btFID{{fCRC+U8vp#U{7+# zYdV?gw`-)5`z}9G|MV8Als9*Whyd7R1xnAM^IPXV>yTJ_ zG)_xUm+@)S3id4S~t=5{Sqi41Do6Ie>?boIxN2^d*#*tKbupN1^p`2ar9fL2< z@#cmv$C(xq{)aUN5BLq36}qws98y-6p6qWL@Y2*f!*>6yPPHqg3o>krd0D$m^{}`> z`Bgzrm(Roe>K$Usy`cS%TD-4LrIA=NX22WLr||FgpL=tCe(+$eSc5rS>GY87{+-On zd>>UtZ?<`CY4Fa7hBQiu*jspuM^$;Af_Ji)@!QE*#zx-DF>Y`e@U9tI2QiohlwM=_ z*t-~!&fusV8{#fbu|M{apf0ITrNmRU{{F5{vv3Dw@FpT`C^cj#_Cp65`m}R(*+T7R z!Rz@e8^mgh#m@*&7h4XRqECPJ?I}YGZ**l?nvn{w1y3voZI4}Gk+e7nI%K|>;@xmB zvX2uw{c3xB-Frh~Hu7k{*#oDdBNZ<#Eryq7=&GqhX!9y3PtDk?>*a%{Xr$j+`;P8c z*70i?XI_q5S)lxLOpexeTG zB|GDBwZqm-2_q-PMyrPNDpTQS*A02x!&)~Vlx|6tpS_cr5LwJ-NCM@wxzmtQ4L`9^ zO;D!O=#to1c8!l^XIr3=byE2-`w>cUX-PL{Zm?&0#zgv@F54;GoU2YBS(=ZzI67P6tDH|23lSLQ zb5iD4oV+X;rc@#m*k#l<@r-d~Y2JKoU|Oxu*>MN0B~C*Vl9Fy66SUp2{87u^iDDGE>u?D2c=v{YSmdBb;hdttlW z_i7P~4XDZVmR5R@Gqtxz`u+~n)thbRhJy|!rYp#mGDFGDwTtyop1jab#L&lU-buZI z&4b596DZ!eU#6O?A@NNZ^r>FbX+sz=-Am4%dre5qulES;ik`Y7pd zr(D^eluMvFJ`Zu`=$m976}?t@&tLp}*v-?AyL*ESgNyWYVXvD^T-MiS`L?D{zfsDS z61SFb-x=Fpbe=v%Mz+LbIvup3#&aUd;e(NNZ{*;%UEa={LC2^H!bnoMI0@zSvc8Qm z^VqCWuS)JyL9-(h>C=%OONW)$;VX0whtmc1gpaWf$s1mprOQh^azZlu{yP>of4>c7 zPeJaR7Ekiy?CO`Fv_cRfg4~Z==#AeFhTfUP%+3`O1{ZYn1 z>W3G)C_b?s83w-vo7{hOHFRRl@zw%rOjAWPxu9@IDp62HN_5C8MSCJU$m{b+Js#8A z%aX*&;?c9~omuMLzD}t<{xO|}DtX*Fn%?exZ(18?5es5*n%aXMs}V6S_zEBI8Euj} zbIZ>}KMSE*Jlerj9=uhwkztqbU~Z8S_$pVJ`0^C5F(?)8AaR+B-rmQzh#B;p>QVWt z+ROc;(_Lc$qA2n!wJq1rq49?DqMPUPtJP<3l!=E>O}3#6%_#G``H$Ugv3V0X5u21y z!fsIJCRN9tI5e$N32~5mddP)gcIrS6uLl#dINbKtzS4>>l2^nYt6nU0F)XABxo5y0 zDKyyb)1kXr8xmMZ-qhjNvApuO*n7sAGV@YX&Xv0Kncx)YnPew|7T$}f?0ux2)eb{X zHfEWP!je6LiN|3agC|wkw1f4|!e^Q1NY3`R92KipcO%qfD^dfMZv?YFlNO6jCi9A9 zpQlls77&^^8F^PHHo)I0QJ*dC!c*UP)2_>P zkt5={PLKNHn@a<)AGAo)kD46N>2lW#rjO#;3P#y1ZM7X2n^o%F+1|=+%#(0ZrYA{N z)}%bEO0QfoH$3>o;^y0X!*VMo%xS}}7Wi2zOllwm1qi7}+6A@C^d*-&u;W4it&Zt;#fi4^^^f^d1BA^~*BzFXbxn}9k@v|&L7FbXCK4FZi z{bI=3eY%a=qU`mxjdTLBn-N~)opB4XY?9AqncgAJ$FMwZbJAl6yWpiIB_FRSxmAr= zVZKi!EtEFmdYt5Tc;%M&(Uo?Duns>BQ!qUrlbHxn~%_*)JIGb=ZdEl*mB_RB~LNFpPjg{TLtN^T46U z`}$>L&!&yYjLX^j9lfre<)JKTMW)4zXx5FX#UI`(W1keYywptBd?xU)c&rb%ElJx$ zwL`kG2We(|5J4lBHQDv$GqDtAPhV3UG1C~;>X+%)6BHKAI=*^Jn1-y}gAZE!du}8Bc-K!?|_p4UUyf}8^o>Nt_6g{m1wM^&?N^V)uXOahGCFqeNT;hIO6Pq<=mCxA z`yN@R48PlzbdE3CYBYhmp_6G5zCV}IO)&iv`fL~pgGBttNa;h6~fkqWt_WXX)Q zcZE8WA3oI`tqSB#W^PJObGnV&cP^v#Wp4+ML1dI7SmMqRBSDO#Pt*vg4Es|U9(3kk zqG*$#Y_@lieot>-U2Ozs02blfxNI#6B;e8QXHe!X<3b8npuA0}|No7NwE zK*VSdQNGz^fG1b3{mkHTg$--VSvuf?r6=~D)Il>XqWn+;YPrD+Ek>V>l3U+ylLj4- zru}exf2E1ad&7IIZ{<(je-w1kdsW?YpZ1MGq`Ssj{43gecdqu=mqQ=RT|l`C;#J4i zW~LC(5!W)ssS-Vna%1tgccn<=o{mB~qaHr!kFSgorqern_6~u8gj{oI%(3HbSJ|l5 zWJrvQv$G!D8qPG)s~~&4-#dqjk#Oiq!v1j(jUnN2{>y3aCDpGg`iG{?$shFp+$x*q z8?BR2>GN8ISldlSV-4@HP>LQgWRNS4j2DKV)IO`w+SJY^azUu(nU4h? zsU)K|)xcevFekzGlN3`Tl&nur?C;1gdaNee98eAwE$lASNGI8UB9YQM&#b$cmb>Sz z6^TEL@L7fqtB!YgeulbA#lgr@9+W}(yFw9(?#}Cu?d5N#uT@);! zqqvar=(wcuQ{M<`YnX&XVdaCdH&q~ZFLKrhom|(`rO2?7;Pu=*Ipr(M>MhCd`1A`U zUIt5j;yU&EzEup7p`id$MuPH+Ow9ou39?(!tHbVEVHS=I4Z^(UH~37rmc#gS#mP2W z9J{?0=#Pq2x0?KA>;kFm}74@uV@t889A z`r0|CBfY+}Q>JfdigucU(JXv)Vo-Lf4=5MFF*`=q)O8nv?S@ zW>2yQqm~^{MWuc5zZNN;>sHi;u6GWlGu7={4c=I_6`pX;rXhthKC+ITa^`+Jy{K}; zv_E=9mxp?y`@_&W9xQKO{S$hV`Qy}mh1vZc;}svb36mPasef{@^4F(sn7@nmU;h~m z?6t%H>BS1}L%F}ZSb?xZ|M>TFT2#7BF2OCFGBQw$cwzM$2hSXu)9`jDeCZKl>~NoQ zBf3?aP^kKCI?d(=sm^7JD=$-1uiY-u^NqgOa{DsH5uxxW_p_3hBVwcY^w!lZ?C&sC z_0ODB6L;ZCVz3w7sb{JPTU%gRD%yN~d*k`Tl1Ha6b7r*k^zGQMFGXLmT4~#XZ_U?M zKW6A!=mTFZt2eP=7!R05e3pV%U$R;mUS1ksjN)@yTU(4M-B_?#Z=?wX&#M;E%p#+V zScNuHgQ9M>l}*0*Wwqa^6!>C@Ve3Lur5H%Q)a`m zv^}{{c%Q^2w$EeOzMu+L_$p{6Qq^{%f@0lj(jhO0F=KS27CCy5F{9RMC0}*Xu#0v! z%o|z!%IXPUI=E8CXMywGnMubQa3r&gSFpnoo1p&pA4-x9uyr)uA8pOv#UfTA}_ruW>-NetxL?CALdX=?=3$ zjlR9lxVGas> zefD-0w>D}mEBaJt$k-Gcq)fbWP0@G3^&y1uU#@~=`0dpBudOspQ*&)PmThZIFbd}Zk9_ABs^ysP9S(KNcH88zCpcev-&q|Gu` zCm0q>#E)8W`?m-RZd?zw?mg3@zur8`vV*Q-d5%~!7}O%>?MtMYUDVP$x;-x#EqsS< zq*ac9^y=N)4u+b1b9Axjlw%F+whyh0Cmp+A-}ywLvJi7NkgPvO9g>`A)yle<;<FzR>3o5L)e~U(kidpjPtyWXV#7uAVI-&VD$)2CTl$~S6&saQ3_0(`Bu(ciSF~Ixq?OQjq{IhnLm5@2}W=7IA!LE?B(vFPjV`CEfc&J zO*gHE*6iaTb2pC>KG*4^G)<`zq?0Uj<~us<@+jCg?aD>HNyXxEhPMK&rzxn!@~?H8 z1NZp^MC9v)r%Fq8gC*r}%Jt_h8pAz zr#4GYFUv|x!Dj>RCK9Y651A<%r=Dr%mxJ5;3Q;*2Eo#s&D7q$h+>m|0F|rZGWop}> zdwSC2H1uJ)s^|aX?wx}xefKr*I33%zI<}LJZFFqgW~XD@ww-j?v2EM7Gpm1lpE>(r z=AB*doT{nwPgXrotyI>!o?H1|_w~6m__exs!;Q4nbh<)U_-tl5Vmx29%Q;_!#Yyin zJ#F%S1${8~ES4cchpAebHC_l&ruIQLjWr3v&7YF@W7%7?FGkL{=Nn|c3gI_}IcnFR z>>RVvjOZ(_?&M45(m{kseY23S(8j2ceVGxp-g_YSE1Cy(A3JaEt@7=5L7rY}p9 zHHY-I%$*gYwW#}xq<0+5sx8Q(LH_zx(y5f=>JU+(yKyg2jM;7&y_ zRhN?Vr%4v{cY2HMXl!zlsQ8*ATsb^uvoGfl+Fn5AVhA1c^@}@ZwvV%L5egBTDp%pa zxVjC9FCAyRFK%)lorc%Ctq7^yHS?6*YHK9spS|e%;FKI#4-@JOncrFGRIX(F3f~a zd<9oSK&)>PJ8|G|Ii=di@kPO8BJbbbUe50}Z!PTPyb{m!XULcLj`#PH4efn>vo5KA z;?!pjH5m~1&i{;4$^>mJL|5LJDob||rC+Saa-vO9pD=09@JXGtJ;PJubn+3R#9QB= zt?qgstp0qtyb`v%zu1{(t7gkw;+O2$x74bXkkBfzYtnDtDU2>o4BNCj5D`BsHZmZM zgsO*Z&v1vDaMwse;Jzh}&_1$qJJ^@ZYcjedumhtia3ChfbVDxaUXw~Q!vN8vYX5+Q1G0d;Z@U;BLnjBA>S=Z42G9y) zNZk9nhHJm#nyc}*t=6!@^njqALe1e=&9o-dDKAT-2@=i{_D-2Vb7E&o5N)JMm>Xt_ zyh*o^G2IhE^zoLmwxKyY?V{f+l{7@OkbygF`khjpw(>@a)2qFRK4W^L-s-lT3Hm zQf!eX9g!PAX(W*i%WBY^Hemq)PZq@07Tp^6vlnJ_NkGtsI1HrQ6)Nh?Ulirg2_Xxh zr{t!}+hPjIAN`U61u6>WfOXRLE8^(*GkSEZz{V9z>2$Es?!l6rxh>*FAo;i3G3yzg zb$+W#GJ9;6(X>k~L;2&wqqAo5AbyiUf|OAgXRLXw`%ev{_AJ~EqF>_^M6&(CWcedM z>4;>V#q4vyBMXvg(T_pP4U3op#6Z_V2DY`5SUHa|y4Re#u5vC%Q)UOG8q5f;mXm@77u!&$+ktU^FYZ-r6=jmNkQRk} zYNkuiTjkDKO+v|z=()k85O=;$8P}95$1GBol8X;@U|~!ZeOvX~0T*4F-#(&5wxPC_ zjgNW|f=ej7|9!N@DC;|?x9l{q-jiWA!dd$5ru9HvIbb>+cRr(^QOAMe2AFt)bj6ct zy8@jBm3%EvI4v;*DH_RV zS;(!|1hQ@YAkudwL+|GGZ%3ikig8$yOHP~Sc0HUDvzuVWzphQuvh}ENe6LBUzp`X| zBjED*oMiXIb&w?p4=X(67Bv4b8!lLIf@mj;!DXz{$5~*OH>uCDq6Y!D6~yfj*&27T z7jAM)K3Op)IsPPcg7Z(1li6~}^#4-72n1H+2?f~}$L70t~P4M!m z?#Gxg-_$fg_SFjgAmI^C8Oz0FT|wqc5Z#;OcRrKrJL9GBl~0x{#`St2&oh1;QuE3w z7hN8QsQwD0dHlum{vJ!)b7nbHd2>i7`*YDzW0D4(4-|5qqAJO_mDQ1}?%VRw$1Kwh zCQJ>!{c8c>n92*qT#uVm2_?M|WtP}LARlrbr9KxT%06dOS4A30x|k-jEG=3lB=)FO ziLI;>n`L`{B$*0hl99oq{1k-Ux#sA2cE(dek6ev~6106JBGdFj31z4}ziD^`&x zu-~lzP`x*u%4>s*H(QzrZik&s-sr%9WG!!4FScgHT-uQ5QRfq`nDyNo*&c)Q7R4=VERJS7L`P*)p&tl^+NQ96NZ2y{p3q9ZIJ62}^5}aJa~dpU=JJhkc^% z=hWc%XXTHJ5ol3kO_0Eg4KBU8eU_T329~HP?Tq|h4EHm|L5~Qu8#&H(GS5UpYmvyc z1wMrB2W{&}L(N$?nsqbZg=M~-44XT2$ahto9jP9En5P^GyFDAfQ*HX2#ARJ7KgiNZ z6*}ujIK+W=F2i0qMtd5NR>G{h;5EW@y$k%{=#-+6lu`Q9Cy&Z*QsopxIA}P!08ahm z*~@A0c0bs8WQkj4i8@I(G~fDMNvX>E+j5`IaeLL|(}a7j8`2_uT0TQ8B`WPECdI~A zT}AdT;pdTSTIWZU_m9Ql^>>~@|7hE0pWAh~j?OGfWSRXpzr5pCN8)Ito)JDJhdx*7@0EH#0$8Mp)|)Tf4&=x}Jee%0K!RESLN!1^q$8 zPZtN8LV=WUEVr)jUZDzR6R-=)a4gq=n%UUUj;B0KmA?$xNz3qEuyf4GJU<9I^b|pR z*p8U`Yd}_=wD=qFV$#J`hWUTkq4#o5u7uQf&ND7<=pr53AAs_wKbrFzE9>qNzm`F$ z$?{gMmz41quL{8OWsN|-oEKHPI$N+Xw*fbfR3P_R$JgDpu>mU)T4c{b6!IxMg0U25 zoJvuXmgDZ{C@EQ1sJ7rHuk4um$Jbf+?h~`TJ)-PmoI{U`FYZ%8%I-qACTXT0REESg zt?Yni3Edi8qztuL#1t&~iKsMn>ZjBVELa+eM2ZNkE&Xzl^{2Sm`&mZGc7{d|T8AgH z2z>EPbbgt(4DAu#%|cd{tIB5OD_Vg-`Gcyh{^bg+(yb#kN9`ttk!zzML2$xssklSJ5TF@au%K0 zx)tLU6&7&1ZO#B-+1^yP>ovVH*wfLuJVmV8dp-9X^zDxHX8KccLw%Ec*r;Abr30EB z@q(xZvFxDK|iLvob0L zIdJip;2FY-pgintG`hR0fdaG5lkGp?NXuymoR%7ly<>4o;7U^M@fBKY91dYEzS0XWr`xoFjuJkB>HrOqS;|K_@ zgphEGNh<6h9;)|yVFwz6T3jGXp+{Tc#pAG!Vw?Xuv#~yI5ietaU{90n`&l{rqr+-8 z|Jnc@`|E942cc&2r4Jg5HkZyOgN#_z)>yZ3%~W6kmNxaP#Ys%noF zrk&BD@B*I8HYb^^j`O8VTcz>HKG6+1mFzThoAhn-m~&*E1LRSw$p+CuYb}(f;o0C(oOaEmF*wCj2V@S0Wsi`@hLUS(j)uaF zjNloLhDRw%)x`Y}1@K-!j+9rqE*cBjfh3WD4%b@lV1(6!G0XDQo!BJO9Dt|P>tXV} zz_yl6Mn5{dHhaFV+C2cDGt~f!&xaLFYZ?!m8dbjm#pj-|esH$knfnDBX1MxwLP9|= z)bVbhk>)BB9iDcZ~u6qaLFwOQbmYg-Bkmey=w}Nl`J#%$*g0yc!h9tDhckrYtQ8NIjKd~2Yw_5 zCjuT3t84y0%)*m$l`+HEq_ivS(gD?H4bzEeLeoNn;?i&w;~(Q*RiKE)9N`Nwfx11c zw)_tm$fhN#1+U{^*4gFy*${aN?E8-fU(88Q{4uhvI1{a#^~;;JVJ}i+w+kcJy^?g1 z<5mvaJ{*p8%hiII{Dzu7Li5Q+r^xMFs*>#+`vJd_m=YzsA<09#z<}t~O|hmP$cNf9 zR;4mMp~vozp7^&+id%2Bo7nfD)e$kOj{6CX=dq8TtGZ`Rf|bpyTyhdQsfOkzVR?gB z_d4NSa`p1T&!|bw&Ysv$=fr)_EzwV&==;Zli{IOQ&s#%k?kocXo|h;72_AFC9VTNh z^hp)x*PfH3R2i+~p!j_LfnV<_r;frkwtVo|4n=&P`B8qVfBR1=&Hpi(@PDV${HO5y zpH-UwCq#|yPwYSuK#cm^%b(r#fU7?{+Z6%Gt-rneiDd$={_J=Gy!p`6e`o9b#|VkwU!1VN?L-nZbTYTK0RYGd=~WaZ zp#S_Jq%?DKvUB93rw61l9qEjn%#0n3ovrC?9Zcy(B;=L;+@=MPjM%9D?5h9QldJ#I z^WW}s`rp#c7}@{O!~j8Q02Aq7L1s(BMg|6~9E|#`%xtWN#>^%R zhO7(*MjWgR#w?tihODeCChSb~|N47QwwA^=^dgEvObqnKZcfHFjsRU9|J?W^6`iB4 z)xVePpGTh@dyK45=i1tr(OIASS7SPU^0ST~w zXlJa<0Hz)@2P2?c{xyblCqM&Fnu)_K$l*|30<+ftLQS(3XHmDIEg`8xsIQ`48f-0@8<*SJ|QC~ zU|{?2BpD;ezn?JwT2}lMJ@X%$**~cBhgJa~!>|JyEh7gYIQrjQv;SjTpPBLB+WO;K zn$d>r4nB+3Q}w_Ew?4oSprlLPA;A0*t{@~(H&d!|)ktO_X9q;S{37^uCnN}kHp_;F zJZ7$^+^F9xJkh9*>+^g!E&f>gQUFVTB6+g7D|-&TBk%JhWLw1h&EMz2*J75hKyUIY zICR3&`D1WXc9Zv5CiC;5tJwF$ZN>&>ziUZ#KY8WXcwvDOpJipUo^{Q^+x6{nTi4rF zHNVf(==W^?&Ww-SOvR)jyHp<#h5XIW#phjwV&7+R7WI84riKPMx-tRZg0lwMpr370 zkZn}f-ip<<=jIZR-}rrWH#A?~rMt3^9+fI|~knw@%Vd~9AaZWUk3ZN4j^^wem!wIVi398OXck0lX9$&vWbO6paP zAHVq)cf}2L`IQ7GUfi_ZoSGl%ulpkUaMAOWg_YtEaNA~HmEMej0_fJVSwP2^S8@Ko*&93QHSo@?V9hbJ56h6<~Jb5Kbk*cT8(I9fh1x|2fS2&mK zFN?bqqn>l4ANaRmX)tjmD;t}uM`ex;tR2}L)Uj%Y5AXa{03GYteb>W8>_rJmQb7`XV6aGa@uv-4vaKCg8EpQKb+mQ_+(yVUDtUeLM zhYM&4c(m?e^>dqTcGMR~O=G)9gq$vwU5kwA9-SiCrJ@T=+J0HH-@c4u&Kj=l<-)Jb zkOjE}Z?suDMJIYk!_e+}vkpi3YypS5*SAiOvcenom1ijDZ@f&rHwC`%M77;VmX{y3 z-5hs~hp$E9on_*=wHN8P(cV38h`qwIT)t;`~sum`&BV(WBFH^iIB_m5vk=?pnwsPwjJZc66_#bjYVdp&Zx z$igVYwcb65co@i#aY$z(2NT*4k1`3Dr8q_ELcU--?SO}}mkEHb&Go6j2>D6tnO)DX zE9<8z0vU-$xRc1@ogi^mQE@DW$Iz3>ea~R`= zmD?m8z+Si<<7qE384z07;+1=I+e_p8f#V5RSDay zyJ%ParL&EtWU1w@?7`ddeffPG=QjRA#^apl>4j777(drDjbnm$j!13`_y9K76itx! zv_NH|VXQyR^(>V|bScbmu5-A)`PE4ZI}JWIxzruKOS{w?|9urVHQ8NdQi{-nIT&Le zc@Xxla^2OnRF7`%h|(GH)dCXxmXr^pRqHTN+W$0;Tj7_~QopEXw5O7HAQrn?DU1vv zjhlc0T}*U0WkjoB?u&~k+rdI$!&#p_1@d5)zq)jfnL;be^68Wo5dw3b9krfe5>b(B zV0*)P^qVNrMowqp$Ud?@ssr#WoNM71g~8o0s>h+wJ17sV2NI6{SplTYg(T{&DYGCn z$b{oIJx%lnM?Cut-YUurja$Gm7h|MyLIrN9kuJKH6{1=B2Y3dJ5^dDjib66hmWmSR zqnGrE&5-w4L+S(Pp7$go|FFIW@ywpx=m(EcPP5Og_jT)xT zFAQVhsZz;Lvmv7!M(`7P8%t{ZdvFK?+NP|e4UTKZ-bctMb7$ptO*Lm=v;{SFwJNat z_k^I^7nGd{a$H4P4myrx!|s`&?8VTZHo>Qfyl2=ien#!-4(jE7F9_N>S(}1I(QS_} zAq00H@q6|(2z|fUr4U+1GCF5pW9Z=8`DNWh@+HfEfI~Y>m>5Wo3YifbNL>k%_>iqx zP3#NzGi_z znl4yoA1@INl0_2m-m^olopw(x1&+o8*GVBea`%_UL!y@A-)SFfJVx@_{t>~qG5ybE zj|eq7(UR2d8-j0lewU%3e;^id$7y#MiYM9aDnhDC>R!J}#2VOtP@npBA#rTk$1BY!y4I2A;a_@P*@TAu4=MbFaKCyovfzWHIBl~?D}votc-_?FaFGz@fdbB5I&f)cVjVm#iN?ClBa$gBGAhd;xd$2bIAM(3( zaBz}hS5h5jcWNS>cvznOF6e@XbY(xypsruWX+AK4f%N(pnrdq^-()v zd6VJ<8sHa@m3dlBxnr!yzr#k*P)uD>&kz;<)+n^RKq|g`7!F_BpmD_Wyst1@tE- zduk`NkL6O6^I?~MD>2-PvGIPI(W}(wvw}E3rOUs@5pv?j<#5!f-|S~$j}oWQue6l4 z?8E1-7*!!YNCFsTsn#$@Y|wT#`e&wB6x3{l@umcREu5j-SCc9c*wqbpxD29o7{5Zi zfOWvWBE4y}5%?S7GVSaUv037b(7>0(L4(@=nG@X~Tk`BI#%(Xqx1`_hETgXgy*}*Y z?MpN@OWck8kH_Jps>nu*hA;sG1U5woMh%e~^L%OLRlzdl@x-Wws5%{3N_FrZGc?c% zt}vP~J`!&;v=)K}Xk9)lq2J8GznkJ#^2|$?i1PH%Lh@B$Tb{twk=_R5HrJ_trf%`- zy8amC?Jz*|RsJD1@4k-xR4;zTiLl5g^sV+xGgFemvtSub3e=@V0Eo=VwmRrJ(54); z%I8Ode$@8P@oU9)Aee0@y2EAK;GKT^YOv{v9hghY!8DHB?BLu1449Yo?$pm8;bHV7 znWG37&U}>jQ~kKvyk0)dl3$@*8Lm^S`8L`DShP$#=e^Fk2NAGjFvK=JoS$tRP3KXw z`1P(y*Obq9gfdS-Byd>*JeZ4T7FsvRdRAV;P?=!-!5HpC260j?&Op48S<_P4)&zUu zCT{OF#eFiQZqDehYTrC&ic}nYR9RRn*_TTLLm~Vmp<_h6ahYd9emN{@ z9M+CnBrFC6wNFW>%KH3Kz3KaQ?a2_G{J7GUPoU^k7CyqM{jS#I__5#7#Gdt@XUi|O z{ZPNjW$MzLt&O~oGG$sdHdR34;g}Y|e@9Q|e(D;LVs{zB5G8vi^j;Oe8t$`v$?v`& za2?QuaNedaJ(JKC3$a|Uy2s7pj-<;KnMV_%YnpKqSm1o#6p3;jnBA4@(Kp|d_YQy}^u@4H)$|j@l>l0i1MpOmAdev|4 zV@=^85veHc5FNa6tWv?2R?MYyic0^q@*aZzR|ZXtr( zsW!WnSC7+l(;e1>DC{x^Vc~BOTjUooL2tL|l02){LTbC_7$2AUN$5_sQg%9dbKre<#*&u|=M&(O^id!RpBFkCgI8+*jGsf-g`59P}RKK3b*k2i8IYXq2o= zbHIh1s5l^HN)zvL+VIj`*g=)GmfMAP#{RmH87bCS1VPM)>q7u}DarqiMf3vkupb@yrj~ z%U)qg%T#ppWNX(M)RZ5|Um!SWP2F}=^{Z3GLh}{B&yMT0(h_Vp=4%BUNW9O7rIaP? zhv{tsG2b%p9EtOi8N&F&*bOg$v019OTXVcxxs%O*$4vka#^vhBZID7RBvU43Lj`g~ zPKLBwwmBgMx9)r1=nf@q>}EdImaic0vCS6w0h=`8c%l4TeH$aypUY2!X97GGCa!HG z#_W3Lx3L79z(R;78MVa9n%Wng9?%}ytu0n&1GqNIIblimHEj;Nm;#9rc2ySW;k2z>>+9#3)5#ecbP&(N*=`~YBF<9lC*(gpt{W4#U zwc1$-JG+&Te8;GSygo9zTFEzaSXI=JaUxNEk5lpfJp=WHqoUE}!D&1UNwfhym)X#E zBDplXBtwq|bQAkPV_k3by9LI!X_@5ERT%qO1>zRBtvdA-L4yEH$cX!l<&asOS>+NL z)QUE>KkoV6MClr38_Z$?hdXNr+Z)?NLcA_%Kh=sLJqjb$WMG{E|5t!_E)*8gQZQ61 zE(9hvO81S4mOwSt=|=TiBf2|Pt@=3D5qpt`Z!BOa%O_(O zMMY8SCS(5@N_J1Jj4P1VEfyl{T@nACvjf!Dr)4!JqS^W1F-z} zdYE#6d0tk(+<(j({C#@+4D`ep@e~Me;ya$V<#D1z715vI7CHigaOCKmSjV^mEjE~N zNOUiQynw=P-Q~ryd?bwTpO2)V-G(dR>*%M5cgH^XL*Qqa4l0Ji9Co*e{b)p9P{Tz| z*>b&9u;5G{k_xz;7OI`XJdf(G^t{EQh)QF?2YeA&0^v(P=*_xfkCY-qcM94Ts07T( zUNAcNOu$Gv+Or?1>{v`pLU&p)TTr6J7BD%maCm~@ENCkF2rZc^w10MpT)0=xSKJ*3 zuY@;2WQc%3(qQydLVYuFtRw%Fv^`j7Vz$bLo$CbFx%a9Wh&1XbccIL;7>+5~Sw_ch zG)8Aaz5&Av0pXe{rUYoI8R~fvnCR~e3YE@DZ(kf#sa;aE<0wh2zU3ky7L)$5&Nq7+ z8wd^|C76`C3tlS%*z}qvAF5y)2O$@)fe&8U)g3FfV9uC85vZkaE5ZU$MqIY_LH#VK zAdp<~MQ_J;j$`2kM{#3M&2aHJ5qHM|qMU%>l}E=~deQh@-fyN*vF@bs^$-{L(~ow% zy^v=eg0!U-FXX~U1ND(e;Mz1f*yz6?u-ldDe+%`uDo0BA&O`CQ+HkGDHGJ%EgadIx zCtBO+|1{N0IE$?2bqnmme&yf5{v{EFD8Q68=35vYRIB!6~~4)|nNc5hlk3Aq*Kt4iQ}81dqV*WPS2TCbsSG{k6kH63r?F z{>(OGZ<8}MyBItA%(i`80rhc#+j5Zk6=yWM*Y`B{9kiKj%uO>uS7XLsIWK`KRI^pa zrcy_DpAsT$)7IKImL@5JzkJ)l;Q0hyvnsgdaWly>@BUPCWS^<+bE6CEjJLMUmjU@A zyQ=UL;p;L9B|?gzyN3DU?l|9!~cb#$qYDr2LPdC0~{U3 z&dN;pm*xDQ(ZK(YeewT?JW_U+fA3xWlh{HgX22;c0G}Ih$_g{!=$*fd!^HkaCnf-t zk`Mqg|6lX&|EnZ(axgajKX&2&y#oJetpD$lf9wowZ2txfIIk@gP1Gak!CJ>~O_N+Oc+{>y)O7Zk@O&gAOd; z2p{IlV`kxJqF%D1h3xkB^XRcHMg5-HQCH)Smm0p0&=0!LF-3=vB$(E%%E`L{^xbmL zr&nFsF7LW<_ova%jF0C-C2^_yx6MM8XZ2oW0M>+W$tw8|RAl>*zIfB;bMVslASnf-Tv0{ z=&d2c;3jv)?K3ua0{^F-gE^E5?4|3C!a#pe&0IoxG!LCMC3T~C z;04p0Vb$_tzSuz`SA2Aqx6fBd))|h5&X3VaQaiSyxHr&tdkiE}e-cjag5WUv4Tnse z0GEKI9YaRQ_p$4e?1O#+J`WEM*o!SJxM{SJXp67MPt&v8`KF#vM@oDjs+?ZJb*@j9 zyAuRzZiz;ol;71v_h*TQ)mE8we{Wc#Ef{VSuDe`+C~%TTe7{5hdrI?B6zlxf)D`tx zm(@V6;6p=GjmuZ0p}JI|WzgfG2C+krR{}li=T`ZX*EptEW|_ABC|V=AK5xUN5pZTl z_N=heZUdau&Zk4T#(>y%L$gcmUWUc@@s~^Ar$qwamyQ%?IR)vGyJR!J60Mxvusc4F zkKHQWtf0v|&L$?gyT_4_EFImITQzOEmIq1WXUm9N*Tu)y4mE3j7u$#Cc-JU{EKFP| z$w*Z5evRGU;MwfVX3MCU8H#u9}d4nC6<-Bd=J?Q?J( zoYGx`rVTBKe0zC106J~Kq2yCzwKvN~qBWp3lF_iA>cmWgaJGg^W~z{w4m$v+$6jHz z$!uCuwOt%3Y9(soT6x@2Di6*^d)`>Fv8CthTt(0iu zml&CpmL6=w(m3@jGCgmlH*mS)&O{1i*kpi_9!_prc&uhZOuh_+B3V|qVlb*z8+V>4 z+#C8KB4vO@WmO)M4Q09jhQqrPdq7pFC9hgvBZenoq@>p8tr0c{=k`57choSv)1`6X z1L~#X2~XB0Xb*Nd1lDBWEKD__YVdXSQ%k1NVg*5TP`n;z6j z1xFY1i2k^H$NQD4(l4Q2V}x;P9(Tc)a$WDm3ncT@P*Ih}&YhA>5I#i~N?)c|gFkuS z?F(PiO1)6lC3Vo&xznGS!b#Isy4Y0Kh3Tn5pw2yI#khMrzja(6pS#c{^~Z#GE}mM=8fV01 zmr?rScEk2;;K-3=yRj9RrIkU{(-(9X)JkiRtJx(MkA6pzYxL)8&7hCX-J<^`o|TBl z#Uf+>^sj^jT5xM!St?Hhj}ju139h7J4u!2L=d*Ncm@k&KQatcd8$8kxYOza50fbVv zC7Sg71@BNJma~ zg38Q7Tsp#$nx_i?jtgal{xl||#mpMV#lCfB!F71hEP?w;3~Q1~W>J~%9=>}?#FzV! z?wxFLOx;R?+o3ka@R9wcxh^=p#pjFKTmXAQaZt0in^-E&$ZsVIG2`|i_fYV~2d7d` zZ#YMA9doXo;h%IFi#7V#k_SQj7#|(WrjUd7CljW&scq-#=+?TanPUS?0kGVo09#k| zXRv^hn`3I3FX#2w%>v;Lk&NOi`|Te*;5mMdML7#U6(7g(Wx|iI>325tJb>)PMjDd_ z(Ro{m7v+z$b0)*^e^34x?B~`L?+0?#3O7G8Q^*yaVGM!cHH}0#sTJ9t%h>dm&9T6i ztIVZrHc8X-nvwuUE);fQr_x*2q5y5BS~u0nw{To@QaEUo_K4I5wf)PMb@`Mb1@`E_k5c75%DKPL-+u&Sv@ye;Kh%OJ$`TzQndRb;2f zw<0lUUg|XG3U5&eyyfytC4WL!j1tdU|5M8(zB6)V?j4*Bt5Qk64l~nc1Ef5BCwbe{ z3cR8ugd;vXHp3lEQV93aEn^)e)!|BXWL+kAfg>80h28@`!=Q{8B83uOvEeG~0z1>0 zQ_7JeY&)p&@h|tTX`z+V*n%to z2=|E7QmZ5xJyuD{Cpv;`fhCJ;vUGCi4H8Z^hP+UvZL2Tt%Zl73qFavHF?q4S7y|iA zK>;KIJx1k`Hdof>vp##C979(+T@gOkNb2v7o#T7zK%UbFLCy%<2C6n5X;*o@Rnazq zV(8F~nMqJh_p{+k%v7T$$5tVBN3qI+U@k7lcKwRrh+rRJtBOi@sL(vuI*Edwj+r>9F62SSIW}u8j6tk$~r~%E%)JMV-u@bSj%h)!A~%6 z)w?f%{88L}-f*Hw#=%#k25c@3WwW^XuYEyT^*uozRtg-fhpx@FWkuI4aY#hm2fL7s zwPA;pv9C~i>4{no4h?Q+&v;f<$awQXrQ<3J2nRyqELP5Yf{kny=`AUtjdzkn zE>$6(W&Qm>;oSvL8-eZTAc7E<`_M(AYJE%K#1Sk4^EC{r+OvYVL>gO`-=VBK%Gh4&?LV155SM#`Br?`Z6+`t}M(g2s;*fy&Ttdry&ziE(ObI zb}J%S(mbbm^L^yVeu8%IC%m8_>O7deGD;9aZa=z6H{kD)izAdt)Ud?;Og>hjO-iHs zGy8$F3gQCZmV>VWCM)yI3*uNIG4}(alRPd0p^Pl-P_41==i`?V1!)^8-_ecx=hu0a zUCr>V)p3FJDW@jrNcS|&+?MCJ2S3Kt_Tev_OOC9R?`s~g%Ms-$;A2k>R*IXqL0IXr zp{=5kE6x(ks&YaDg7`9J(wlXC8gY^1tVFV0jTdAQ3o3o)bnSLdb$O`dKX|dl=h`}< zv!oNr!1^k+wN?d4X~|E2c1nH%d5d}gnX1X%zA9U>gxoT@eSyQHC8mDg{RIjC*YpyM z?hlw=qP3INzedr->ZGV$Z)IA4S>3sSIW6lr*agE->TbU% zEw?;&Ml7%Vw%%zI!VuB&nN*0xUGH!nUl8?Z9giAlJWKOzH!NU+e8yyv@k|L~#;7X! zs`=f4mM9)gqRRBJD+9Oj8+GDx!53LaGsUN~OlNd^v7*3(aEycm?z3siK?X#6hzA-% zn`OaDW_z>R7Ms2r-vB-u4>11fW%kiqXa2FxMj+5;VB1S6IFKnnf5zd zi8;^v(E+NtBJ%TSx)LhZ`W;J5YtzX)ye04>xS;K#W7yL0ykV42^RXqeK`5H?YZ>Lu zD4lX0eo%8%bE1?ONM@d9Ao_0!3KVc~()j`63pX}hY)SAjd|C$+;43RV73J+%Ky_I4Jf5_$A^FXu>nw?Y({_L75g6&v;Yb97#c48|>cY;@1wRD(9uC2W!NI4u@s4PjIkFuOt`=zm!>8d^lNMivwB z29>z^s0eM41(o#eHL=~D%e+U(q`7~UF1vl39kj|{2pMve3H#wNg^lEHl4i+jG4>>l z3NDS|H1y+}APJBfcJ38X_7w3D)190-*i=3Xu{tuuArBnymcJzOY4t|>VP_B~T%02UqYSM$7O zK8(pOxPhiF05>;I4URo zt%tie#$n(sDn<&eZ72UOjuQ8xnq`E}r^mA8)kVP=2Na2Ql#+m2)JWvvrG41LfZ*bE zc48EFQB3Yv)ytO7!;p$}88RxCdKNkT*<)(#*F-Gdj$cFFiT$=B#RjP{wrhiR zru!4eG$sp{eZM8`$s>Gz`^yD&kl#3*L^$+4asUbb_D_PKe_3ty(gGwp7F!hTcTCvR zrS$z_ke8P3QEOR@WI~gbp6~1(o?203P(@|;%DEW%aK*E}kDRf%fF!d+MQ6*5fZhixkGlp1~BANH#l46nxiCiktmsCO-&JO=YLVOn@K6|O5%16(`dD&BBn&W9?XH`p!~AQ z48rHBomsr@JZHcbyU4$xCUJ7jTf6+KPw7S&t(Td zIE3rXS!3L|4z9G>9ne+ZKJ8>KISPUAif{-$?Z3X?vfGo$V(tkh+>a#mahuT%bn&NsE>M}`H3nX4mwFH6MuxX&x51n(JL56_?+^7^UVFb@c~RD* zbEY2n<~g;gJI{v4=(IM*#!Z{?caH+sa$JJV%i4*%Rzr$G_1ByZhvEv)w7g2_hKsmQ zsSe7Q)BT=OubfTk`dLCWp(jEvF<7FlO+!>A3JLMILb`f(mp~wCZ|JQX0L(*v!E7|% zfb7NcKC8PRVv&k|cQzG_KVxGRxq#MR%f&wvGGMtVjzgf@9TFXMU{TcluM zU~ALR);Pl0y5pEZ2NGWw{!^!s8P5`R^)!r~&-OH;IX$p=dgd%GTjuE31D3b!W1_bQ z44**a>dRKatJ9*ljq6hqD*N_jOLYk?#4(N>d1k9Ay2EMbiCzQqU_JpQrY7)H5=@Pb zam-cTRkMznaT;REMf!#Vg^LozdGZFIS)o<$23;m*>z%)J&y(=Cni7yqz=?HZqpJ0OGWvmC=bNjhw2$s6S zs6=v#zcHD1z(m10s5Dk2Kd}Oom)_N-yBl4?m+MJ=j4?di~;J5o)ZC26y zOTRoQy_U)kVqBVr^}GkNZqO$koW?GKZx8YV^V?pFLrkvR!xL&xyImD;#&l%*jwVS* z(U9TbKUJZz_4}V+wp(kb5j71~+Zyj5ZnDJHx;P+_I~MMNcva6H6mnUZx`p#a+}c*{ zQW;v)30XZ|q|Es!t9Z9We7>N+4t8l9;QQoseR2f_6R5G@e(bMA_iiZA*w(14mBD^0 zo2tK~b`_>dM}4`fv~EOmJbiz_Nw|b>&RA$a(_ourdAVUL*dT4bXeP|=4DDc} z#Bsco*%@+&F+h0x6~O%qM^m5w7f``C=atvXDU^rl^OE~vq^o{_XP6RKxD|FIOc@uY z9bLY!qAm0g&WHcj{mWNwzP7WM#gc$2cOC&&d=SS;Y{MMB0t3n05x6kURWT_+bIdhF ztrgB}FPXMUW8MR0M_;AZ%SbqX?2Gx73Eob3GOOQ*&IEp&iDa9L;=8A_E;+0!>H#eT z9eW;{NQmH_D??}Ue2q+~!2P8Q9}97K*LdSS3u}c}sjW=EC!r}!Uj0u6F`sl7BYWPV z6pUW4z}Q&;NYcUvoRu(2drMfpt-0!|enm!Ih(*Y+7lI~-$GG%3c@OGJ?F4X@vfK>B4{owxJc1F{1x#!)_WOYp+~12 zfl?)W=73u8RL`aNj2VHT>3hM3qDvqQoY?_X(&rF zo2`B=1OTh$yW`Q-y^ge~IbRXainPmR8gOFB&TpXNgEhi-c#f6d`AqG|%~(x@n{1ie zj$2*{r?lhT_0Y!9J4q1CU4&6TSri%AYMX&{eQZm6ZQ#QjWlp`>I>=_fXGA~-W_b9b zOg6h3_p2o2QUWaylOyPnH{a1+2k~x0$Z9j8w8OVbnS_K~ajRnW0N>!Bt$2bP2k907 zj#1F4<(M4O!fd_$9a5Jln=4rZY#7%%-Vub_&r664COZu;I<_5C$j);NrMAtI zK}wOg#^C97xdZzsI^xKB3=!3y>iE+=$q{n_CX&roZF6@ykQciygc94jyWh;QzoSV% zBp1W1!I9Q8<$%9;9WEa(hY8?t+fOitWGl2hQP&o8x+CS}!nX&ieLvOesZeh;E8=u- zVjo;n3gmMGfIS!Nlr?ISyxmv`q}c+c)vCcOSwF2(m}a%?UkOdP!XYtW#v%)8#ibGV z{ptW<8H0vH@0|^FhlO=&eHK^_jYH&6oU4{I>W}LKGF;j zTH`gn$i$!}-;Dam0B}-lCOfj%P^qGW*{^YQUS|dQssp1T1K+I1#+G+YgA8HYv5-R| zrLdh!mr@R167E5rPf6T&#VPKy)9cxxJ+jTW`DG6=laOrBB}__m;h zSi+Ex@mmD75W)^gt4g6DW<@1WW0&DrUR;rdxD4n-6c|IH(u0l9gEc=*WFC9yQcqj} z*dT*viza0dRVM%h+)&vMf%L07&1NBG4LxQ1!qvLj>x_z)BCxfpIW&D@Hz+Jf2|W|u zDo>1s{x4%;so&R1hohwUTR)Yuk|vS)#k&RU;}5Hur%376;uy$XSO_n7$}we4?Q5M@ zJLZzCi}f~>G+-k%3mt+oi7c{<7za81S6k$? zU8Z1(Gtl5F6GW5RjFiP1x*ae%RRq!%JBCYa$|5#IHBMMXTE_lh1co+$1kw({5@|#x zbyY~Bf}uD^A&Z&@J2^$%kTTq0j~p^RuCcGcwpxwpl~U`?9{u);6y>Un9};Up-8`At zg-ZTkRLRR2n%TT|RE#pzIUyK8J#!!fvJpI7^rPtepNBjpkNQ4=d`W zKmyGx6T^Whwy=_M1(@ACk6DFwzxf=iQon&`v%x$-{txcnIx4P4OW#C-2e;r5LXhBI zXo9=DySqDt1lQp1uEE`dySqDuyEB#K-u``8rl-H2zCCO1U(`B_#i91ub*gH=`+46F zcgjjTb&C6B4`0fmMwJVGthH!W@tSC1zbptoa5{;zx2WrRT)(M&da4ySv+@ zMlsk~J{#XZ_V?kWhu=U-J{j}DT{M@z*YFApLvCLfGJZu{4t#%qD{^?;G`v3Y;@G=E z-qNwK+xy1L_*!_jo?+JOoTlIC;5qb0rrhu#cW9yiEhnufaIKVIsD)77=|RZro_Baw zI^~~e-~R}L{*S=pY`{YjjYk)Dl~i3vatB4Gc} zQ7rTZe&Y5rr${z!BF7pUPsl83UGOOI0x(YdJeF45+E0}As^dV z*Lz07nQ&C5Ock6Xav+*JE-c8KZhlV(XvvAux9PnAuE&2-%Tm59uYE&%aD;r>^jsha za2gse?)b#}IW8sRMFnjbTGX};IwIrfbnTS>$8UgGFE$V+|EHy*f>$F2PO{IbM7 zQ@d?|GQFk+WQ6M0#xqNwOZ4pO;o*I|Ns43bs3t)_Gp~;nB08Vs;K8kejvX7ugu8~& zVHz|bd;(UhL^DvLqv5;o*_EN^t4{bXWV_lTqn0H7hSyn9ZNPCgk~kycQ6spUkUSXq zyaQ@5=>@T0V?|!(1ZkFL+uNp1y%9s7Zijv36y}SIyVI`qT@Ki{d8^dpv5?*C;|1M| z=O?$o-g|+d)&!b6p>7OOd3~&Mdy&>^8S%UoNx1u=Gl?7DAhI-VigR8WJn@Qeua_%3 z1Tpu-2c&=w&O^w@guc%YM9M6XSMM}IRu5l9fQ z&%EURnUxy3vu)6T{GvUH)g*srm5Ci6LVvF}B&EoEt>FD+*d8N76k+`*h;=jGlK9oW zwa<&t9#>b(Uj&P2ImRT`A9Ox(>llLHkJfQG&+yY@G-^6nYmy%3^ob(`IXboEujQ4lLTj%g zBnhP#sga8gK0d4L&R;eqUN`JrsrnfgKjh0qU!nyRSxkOGKFRrVG!WL%GZSbY{w%5J z#>(`D9w`3L0wuGa@Zqvv~7mGWDJ9W|m zu0+1_^??4VQp?cNF^3M4Z#OKN%9o92@ZtwBPQG9uM=5kCtK%zQeJxkG)kg2N=J}|}VZGW9J_2Fc zD1-2kEyW*#B%@ey;*(S zU$pi+o*N6MpY+EHzu!maHc@u!h$4k=+}CTPxuTSfp`N+RxKf&$jqrXtKLdVytF(Gr z*=+Js0mZNC#apvwvg+9Hfnb@w;OHfCLU_){wJ;b#x5C5gq4hpNj@(^^=Zip_*mr4~ z%aNlb@VHrSxz<(e$q!b%~S*7Oo+uHQ_{$g3B7nyf<^k2OM^qr4${aq zWV0yv)M@RH2O@^Ln0DrhAOoa$CH)oh^2?s+CXwB_`>)`YN^O}_H`+w4xBTiwnb1-+ z;|HKG-}|NnO$7$>tby7CgYVR2(Ozyx*GC;c-SW0EcBWZ9WFTj0!)VXjQf(|1$F}YXjxyC^j?HuF6)=Z45Z|HJ?;Cejd2)>vg|a z+paQV6mxc9!pgjoRF5v~clW>FPiAX`j^r6hFR`}s-Va+C)D&zq(xX2brqd{)^9L$V zNz1DhZ@S+<&2|v96*uv;c{g3x-XY3qBO4YLA&e@=n*O)~0y_jEd`J!=)tS)as`>3T zmhO){z}R!TYikAWhwi7Ljw>&%>U3O#fU3CFSKn$#3Uy(!prMem%B;gImBA%Ik+&YV z`(O*QIC|NGP3CMJmXbr5)0yJf4l*)p35{NF+1M{70k$7S=QKafzQ^?neZ_ul3lngL zQg1SY4|zToTsS<9$8eq-o|xPAmi9@*1mblQP(j;tw@=${yrrQ-wwGF{;wI&o0M3Oc zCUNq3!L2v%o1qg7+9GB=u~k!?pp`j9=0^ulSwr(GvSDKL09{NfhJpX$Y>fP=W9GDKMl4xE^9PxT)JAb4BMZfsXwyQ@3rt(;oV32VoD~R-xukX@B=H(V zVd)UeW6_F`FO@QpkU+cvV7aDxB9)vph((Hug0W#>s}TEyN7<@uBPS|(y0l4KK=^jU zI^7VKQ$#kN(HzRMTRR5Y492XG-PnOPbZL7aFpi2q1FQ1qq*f6v3S)SQ|CEuN`0y2y zmb37XF1BE@h(p)%SN`;OqOeeS@!SI@yj`VH*Mbtaufkgs-Scj#g=UMfv5xkJUqxUY z$VLbXRG2{03O2zSnYN&O!BVN#mvT>-;q`0;3gWeAnvjNf1JDG6lR+Usp#5>PF*l92;vcudkrWW8jWy0ki?vH!Wi{nr`RbZ6N7(VgD?7ywo z6iEzc{2~rTo9ag+A{DviQ`^dfN4a318eALn-n>k#&mX+^Acdl_OR`>WV{3Y6;j))Q zUdoFvSiYKH7!n4KZDwC#sQ+txN6y5k!UuZ&iGKCOqMFe7C{X6D zMoLvL9b`DZ3)8#yF!?@Rt5FzA#^k(9`%J^zqk^BMA-}Y>juuFMADi$v= zgL>c;feR$Q??)_JuKbD(Vv+jbPyNSysXXcgKR4=}nhCP#1Vl3#h>1o143WYlv4Io? z+kZP)F^q@`3XvjHg-7S5On>i@;efwU?TPVB{Ppu1@zz)tx&baO1>|z10{Vyy)YX(2 z6OpwFe+?-0Rzv~cl^?T}6v@DJfeGdiwGi@-;kW^kavX-HOHQ{)ZMsnalzJOIqh`D= z+^%X`F}X}8fTN2Z?B&BwMy&=3)8=nJ@3pid(kXNF@x~o?!N;O)w~2P)*jl3pukWV3 zen+ka%dP))i>z(ZNhSq*CN~||8?b`7-zJ{4s#M$uBqrZbAAXv6@}OoLd=lmcgDDkc zRAayB#nmQc74*N2!ebAThwlg!Bp_>>~a5;{ysSOJbfwT^Tb`%2qc>XSP#+3u_cAgs-r%(_nrv zDvWu;h_zTJ{a7$rU4*?h`k_Ai^zpFu7p2RGEmMmtT9|1+jJBz}dHWnlY*eMLW=O!l z#QIT{lq%jK0D^4o42jxdkHHaNwP}o7IEG91t7wlPjs^5@bFtHiX17{i8{0RT8`FNG z+3#S{dSWKjEPxry&mXeB#&?XM(8S(tIfd4>_e{oM7fT1>NGAixtsqOj(W%TBhonlLrsUPkNc1JzF_&&kV34N)1M*P7wBQx}Fu7FxY`mn1|{ z?}y?@6|J}vWM5R?mKn=CaAH_KK{h16IGj)uoB~j|8Z0)yID7OZAiu72@2Q?7D&;29 zroI`Fjk=n;UVx4eQEHIvID5y2|CuYyZjFw|jrbW`P{sx99|yJU|7dLaKQgHO^*#7M zb@^ofm(xkV&hRG&K8yesS_W2jb`aIX!uWH{1G3Wt4HiM(a4f8h00sat3q3n6{qLjy zdxJ$&dwWMidpaf%4MX~OBn|t2m84-|rU(2DNiz&0X?_O&j)DSz!RtVQzdaCeXzUCd zU+|%X(6+uOEr+3oLc9ab8uEiD4LlExZmvb_zN?9FUa%xz=_pndB{5AH3-W54-;)El zb3xOF-ND|;HYu}Ut?_imEO&X@w(Pb#qDEJE(5q$7&rub}@%d&|dX?)yH1*{(gKK}0qW%O}-V)ZQ$H?CJDJEO=y0R9o zoG=_y5+ft;hqObfhe(LT;AZ-9SIv^(P*Zv0qiKN>^K>k<(vp5{R>9khx;cd)3q9b% z=H{1i^&4(0DV(PrvdTaLPs`=lqn+IRBk>15>%xP|uATr(HQR`=d8F!Oh?gLH4>Riy zljuYRnfLjXKick|Z+M#@5MR9xR>la4K`_9*&s4+q`>>gR$TxFs!I$v%PV#y;g4{fi zOz_$Wr43EWc3j5cB2ZnQ{K$w|Qozb@hqB&6l0#c6kep355zj_%Fy>5zp}W5x2lM$= zi^Dmr7g-9dDv&Y*qAVzDf@y)m$z(HP7fWNS;o2pdkTN*0=e{+?i{q)P1bS$y3|DZ( zI!f}@+Dmp4e*`=8&Mm=&BHoGeQmnFY!Rj+@*FEw@bGl{LvftJM-ZnM-n+Gl~v~ z@7;8*zcNlnWKN&u?hC5>?(D)ToIRgB@aCF=&0VIx#R%C>tGVdivs<{xI;(K9d0NvF zI$`+nay4-@IRXOBy2HggFDGDU-{z1H`e*#F1B_+xdd0xWlU>&o&}V^8A#AF5Lowf* zF^Z@Svzc7cucTz3zdX=LP$&V9@x)NK7~%lp){I!~l^Rtx_4DS) z+nq+2%8!!!?YyJ%w{vPDkkBkqSKIZzl#lx(ctd?^vJK^`o0FeD4}WY|fWlsIM{pZj z@JWlNpLD(Hq%RUyF7G|9-Un9{mVQc^mYKPXphL6nO~pR+D;YT`;xksZhTxF7)U!QE z5tmkVL-l7>5^_iMh+&{(dNP)!p46nY8`Uv#BhwFS*`0+lv3t*uGB8+1>%abZy1@=% z$VN>9kCjUsnoMJlV+P-m+PzeHZg|TFbhvsh5+FxdGv{au1Zp0xRy__Y#G{L*N81^c ziOOl7a2c)y7g_u$|0)l?W0?^HYjZ-;6#_+;#WD|+p(&)@;1DTVT(5Ya_VF9l=cF76 zZyzlg!uImIsbyQ*fO_%Ei6N8hxlC|5&33^w^N0_kmw19>Kf`FIV-sbXOvPyBx*wF} zHK!UD#T`SEhhj_CUD`3tTH6?pDBKDqIEzm?WA}{*m*$He-p1|=r2zHJVr1mlvfM9c zY$X*HYZ*8v)ccmWf|P`Rs9Jvu4SV&Vhv_M7s%UJb;+z1n;0snu={-M7E2%x@v;yWH^OO4NTnW>6M|KjrO?d!E1UV^)uN6AhN1Ag5l6xu&JnggDM#K4bqV%%4^gfrE;IpI*oEk$To_)wH2XN5#l+g^8|9M zQM0HW$S2_UHcmNb`{x1}YecRKuj6v2pHnACv?42R8~^o$NofvGy-T zt3k!GeMSzp6anYY#Ea^fZv#kovSY)SQ) z80wAMM!WpU+&yJ~W)T+6;Om9r?Wb{!H4(3H``PIodj^l0470q%^+UR_cBS?uQ1ENz zzHBzMp7NPE*{uJLQ-)>JB0nz%azuF=@?fe{Z<@3FASbvC#0j)vJ8L!mzN*OKbI4G4kZuZpU);}p*(cEPIV5n!7<<84eEt%r5^+08*pQSoS8O{mK zM05un(UVxXj@ed;xiKz4rv?nMl4{jf6HN<+diya>=PNWCnGZ!>etYeFM_i#<-oHYe z$XV_2J|M{G;_;1#Hffv4iuIiW*puvjq|!ki;c@WGx8Mtjyd3pc40tubiWuYw`)y{N z33f}GZ|PLM7K%LHTsY?B*3Ff0XCKzRCRpbSP{~)`?;0~>FsWvlo-1Gg>|0Y%cKK-- z+19Lr8$yMH{qaRd3r@-Ra-)S$KdkGXD-cE@LzGpeOQehoRq*3^bJeZA9j)n2z7&yV zW|?v39PwkSDGom$z_1&#uHIeV$ER_eyP)+vuB`Crq@>Oo!u_iH7TYq5SGh8-;VQ>Ls>3$3fwmJ zGpyn0RZI6-AxK<5W;%Fa>eyQ{=qJ(dNgLcj_nf1u0Gk&}SMS)+__8`@LhA`q!Ew-i>$V1O z&2Koq?;?zR3*zP4V(f+MFtw$W8Y)PQ(#-a z*(Om^DTGR_D2%a9>6!bftrI)t8Hgc+y^hpD8F^WX(R4O-SC#IoY_u-&IPkXEa2nAv zo3zEfnTXoa8g=mkhBRc3bqjJd8yQciX6?zCA^@A(UvPNJ51nh^`_Dy@yUjgA{vElTtXBx26kenMJUVwB@jq2n22{OQ0xu7h3hW4 zz}V%^GzU#*}k zL{n%O#+MEPhg?;Y@ocF&trfZD97>}@9|4DSU$~I&H%zL0vuogf_U09G0cd zW7_=UX!w?b6ix-*DoCt|o*hWm6V5AdrQQ7R3Fm2-_;YQ)i(d39tu`M)FA&s;OCCaD zs}sywR{%dF&T{3y^8>f6Kg|vz%__yjEWTQ_C(-O(Fbh?h4*Wg~78)>1+z{<&M^cn>`glGb|kAd`$(xw3wy&8Ni@$W}wu? zV`Jzh=b+nw+UV*{PM|WpY2AtS!OGH1TeHCPZBQSl{jWrWNna5Qnvl z2EjKMTHD9X_!tLUFzj}lRBq(WnN|4V3a=9sGDQd&G27jWap|4wDE{*!O!+$TNGI0d zJ1dr%-T}m6TqR<=b{iC@C$2eGtdG?d(6ssK((S3WMexJgXdBS=+iw`NHMB~`!asf1 zH+$@F?#Q&d74PeVOQzc6##U^VTq_F4n=1`yADSbIGIYUWR!MEO0R?|*ZkeKYk0C-)g;fNJF^Jx1-D{=AT0uOFd*2yNQU4okWlbkO*$h3>5 z>RSf)PEdnnwd!oa*LnK2H>v2V&U1d^VkymP&1^@tag^k|BA`Kes^)t+IW44tqHbN$ zZ{UY=poL~Zsb<_t8_I=_IEk$;ifE~o0i{yImKYc6t)7w;7Ox|lq0iXjKV7>d%V>YP zc18Y!YnK>F`6rNT*Iep>3VBuSC3Jfl6v)qO$CU&{35{RzyP)y&jy$s=^q5LREJvR( z7%l5y%i^==qEWYh6|zbEr)EeCcH^4x(#IcF+qiP?z!y|)oj(mFG~acWmnt+rSg3h9~}aR%8fxoVB8E0yK5V#8$QU&xM;pE z66s5hAZZ@Fjx>f1!}OB!W?1pJDT^YtPu?){5Mn4#YY^R5lZQkncnx!!;8ky&)x;eVk%=CPj0*h@d~e@i8jTamNP(Q;%uA+w`sR_J%QAtGWaQLIuDm|wnK@z_xY1-0Tg$#4rk z^IjLu!%Jm!8V?8wC)Nc!YSmb3eXlK1J`A(TV`!L*u5iJErsaAlw!69x$*OO;&q*jo zQPl~;vh^1OZH+#;^MJvW85+faBCnD?T}^@=uF0@%(8(c6ZR`B#;!H)>YeB|cbb*6@ z;ep@$m$AZs4$GlwStQoDzu%d?(vRy4@8Q*PGVXGj?INCyl4*7Y zZ^Co=w1D?j>@x~UC9VibcU-8c(wA((pT=F)KwAfFH-tB|OzQ0&`A*rpayQ&98(f9K zu~n~Lh!_3ZHKc0(#<+`Bs>lN2%_r{m&ug=YBUS?ylsLdU53nc3L}c{SSyP~AMH}v* zW?;jsiX0r}m*d^%Kt4bVJy+IualnC*Y$L`l%_(&Mj#@H?T}&+voXCPbjVAi78@yS) zM-&6`f^D^o%|nDsIMr>!ooB!7Z99)$d7>N?9v1Q;TiVtMSE9DmG;if<{qQ*LajEmn z_2?m6-%S_qRpt{xKAD8KT2@QVmg|7oGp?-I(vpF1joT(KpX^hImpX4#4!Cy|ddIfC zibs^c74z}B`7>7BIpTFSr5vBUS3G*_^XDnVbO_VlL>TR6ebAKrYBMW@|F&l-@Ya>f zD<^t%Jf7hw8lkSDjlcxX?+%Oxp^?u*YpBDBWI2FPv+$RqJ`#PBi#RV zP7e6J&)?EfLvkJP}>#@gQ0;qSD-U+)2bq5&9~S!tO;+w9CBUqJ?D&{YTR zw1YD080mjL#h>f#jDVlN@ayQmNdqwbJ$dr$4fDTSGtgD1XJG^ZMxa0^S|(;DHV~V{ z2mt)`=)Y~v{^(!%pSd?Ov$6f1=Bxp7Z>;+Ua&IiC0?WPi0{a4O;lfa>L-4MKX0C_O z&CHFO+6?Q>iSEm@5WQ$muY{4~a6uRWi<-eGSF|{*y7s5YU>cmyffTHGA@3LDM0@%kI z(!B0=E>~gL?n>fxLha7*r#BRI&$UNkPqUENn@Jq3ZJ;eOCs(&th^Z#7>exBu( z1|>xaroPF9AJl6Ju_{-UCXXnyHg{YUUe~D}UXPU+ExtSm@UJ5}D+CwuVPDfUrWxcKZy8II_ zWo6HVX<99FOd3~TM~JgQF%i@PKhE;BtqAZc9ST zi_3iP{It|dUU(WRcYLJH)y9_OGv7;)#2k-@`N|ZFSKW%z%)P0m_W8UO%&}|tIIBlX zzRu;mr%L{-rdx+|W_yXxIh?!SBhf^qb4=0?`5F~TAU(+DXuiFY$I?mfb^&2T^15ET`NO6zM`>3SpCG3-NRPv452{5739rr|#oUeC`as3>cHvHc zfdJdK43au)&?6%!F^w)?o8qlEZr^1{jIaYdV5dqpr0$WZSEcofC5us$K(3yiX&8xi zAITjHyz#kU*Zg}nV7_^WK`uTIAs$w+LcifohF~XJ2^~t#{3{0c=Bs<7`6nd_AOu@S5ZN_n$_S@ zlZQed4ao;P$~fz*JjJ&6)o%Giq}tuYp>M}rlk8J>cIzT|b=>NZSDIbN-US7nMz2tm zrW2h%M!9+IR5P|*ej?DE*h!QdSw?cENXc7>$hkNW+<)Ab@pZnJ@fGK2#&}xKwIC|t zsgFyu+TRMy;xLlcM50T)C9@~6cM+EtB?8_=BF1)Bpsjks;mxx&HInk-3g;%}Mi{Aa zB3 z&AKn7O>m~H2_#`Z@1RS{H?=quDym0NdeIi@qZqp*CzU&IXr02y*cj#!6Ozepged|@ z8-UTs>BSM0xA&~mGtHPP$Bivm$dnrP%-x>Ixa=VEy5BzGecHAj6KPl|w1dnwm&{Ub zy0jRy?LL&JVc1ZUvWZt03(4nLDV_Bws!i9*zT|so+MnspojUOS!YP}3ID-hgS?GeW z<&YWk>XJ-#lNpo;a-?T>s(=P5RXUI6AlN@NNk|rN68FVr?Y?Cai)$jPXF5)&$E48@ z+}l@62LE$;zJ!~c`7Qbzy(|fsj8h>8C@k4B$fa%negQ#wZZ>v-dm1T zSOIuj-RQEKrQ&;;D6Ndp2q5=LoA1l(IQBsLD8sNVm%%B6@K*M~^gUH%sA2C)#-ujy#D7DpbB%SYIf z4fO>rNTp9yud7AVdXm4|#?6|2&wh>R^5J60rP$#x zj_4u7mAAiUrjmB6WapsrO+At&mA1LvX|wvB^8ASwm-@Ae8a!qAg9e;pmf>6EV213E zMSvPie40fds`Uz!rU@z}LU3rlE)V;M|80IEq_76Uk~vuzm*lc|0Q zLGm~yMnZs>8^4EmlA&T1IU5{yZkusQSi*{A3$p*COIk4D4Q2bh(5W$A9U02WERMvN z5|xa(;Nw0(X|Cpr<7t6|c87k+*hk7fzO!XiW!vSFI?2~^7<`QbQ+?qKAOUrautrV* z&L??!&$?zVnFD1?`L81Btuq@=V*s@ST88B6q%t^1eadpqJ&raZJHZQ_xdgJ=j;B>| z>cg{J;`O+%&M|#S#dWu>aEeNzuXk;)HFHbBz1!9yyTVp)s=1kKAE+^49`E)^7QSpX zA>{JAwD58XBA0#??X*${_c>RCuvH9{d^{GjW=>fkPt8skP=xhlbMl<&Oh%}u*G#lz z%CNj|WEk13IokQikYHNb4fBDDI*r!dZYx7)(x*Dk1Q&>!-@_AqBo~7KXDf|qU5z>I zISD3-7ipv?C#|U$$u9P0S1CDft8c(r_1 ztU7C-@uUf`S`{T~q83!IjPMM}2bGoEm)cA|Go7PwM1O6m=?)MRO0JfXEN$WCH1k(j z{ho`KOl8Gy0G2N_xae0|Or8w3B;%ZGFZiT4Nr)(Zj92R;y!2XVNp3`~&Pcas?ndle z8*Fk1h4j}{MJi4#!~Pf;s)bv!gP$#l!K#dk?OH~wHX;L1Gz?Edc0)1f zL$X-DbFhr9jvPftTen1{K31D8_PM>D6zf(Ne;l3h_E(j1DH))-nSM8k>HZx!SFZf*l)5QEyX2%*9MXgdq;Vx`@N#;o%`Q)-^cozW zMJzl*#h*Nn{Cu#7Q`F!*tpYS2meSX?;8eUi#~J$4RrAEWYok+nz)<9sH)uLdgzxBK zpEg)mrDf@zS?1P(u95FOEH1Vca7SwjJZb@+C5MODnweo?-OafLQ%dGn?RUVGXjOdo zWzBm~Kx9?fl2ng1Rj(+|bGFU2oYi%o+_4aTQTyI9y-)+c3MMT>cH*Xbd4l(788Sx5 zrh_-JI?1<=cJ|q$>-|c0G5TQ+T?KCxhk#dgVk^(}>$!Oix!Lp;D06Gn zUa?d43_-GQ+}^Cdb@~tnOdJ?S>T1MUP;#C$M>-dwW1|61KRhT??A3p@s2=Zvw+#Lo z&u_ZLNRw;v9s^T$yzIF6qC@iL4u&-V?tBB$@2Ic4bw<2;pvUKSt9{4XJI;qGGw|Uf zx#DWXl^|~PD#=7N|5xKBy-fz@kcNB^5R#viwy>iN0D_2 z5QgJ|M>1KNjiecX?Ij+wVA9%5P%KF@rk2VF^hb`h9E-&>TU3r`VE=v@Z=6Wowr!p} z?AlK$u;r%|sQpt4-09{^@O7Rfwyl6vRjl0i;F-f~bc#bmrsOeco-XN@H-*cMigD#H`WissFT8VLK@)vh!nQku3pqs5k)2E{F9i8 zgrN^f#ufjB2iFS2UXkZfem%MZnW|%!PYFD{U&@*aBCmp6w(x$Ep35@N&~PX z*e(W%R=fh-97N3MMHviR`md4wg_scp5i@?tBHR8=Z~!YhIj;A-?QA}oyn-Ho)tP75G(dOE;N3& z{aYXs+qxVYc{%H2!BNG3dW__jFzG2t=k_A7VVubu$bd-X zh9Y8OYrl}0w>ID*U>kx96~j;@2uE>fbbddihw??a+tCBq35asNB7H%~On0UrnFubf z7<40X*?Sg#k}1s(!w$`bxWUa;m7hhrE37DfIQv10CSAuujs)gH?lT;l!{}wvsrf7E z4ydgsmD*@Sq0g!r7e-_lOjNNIXgqJe8K|qE8E6T+YSaN-{Oevlt%=5|+ zx8i1;o#R>{GzN;`4h+8@Yk*>1f~eTjbq)jPP@Gl=Eg$Z_XBo9sHE;hlkWsX$Em4E^ zb@ZG0@0^{s7rv)9KH|t-z3mb=)380%-_Swt;;t1gyc{Amx)~>bMP?$+MJafieSXS- zwV?bSXc9gH78$-^8l1^eXyK4+gAmAZ-3a}9dbM_k#CeEg4>LA*+ACM-@_H#Vy>03a zUXezWgvCN0j&}t*xw3vMYO~;~?q51!i^eY< zu+c+~ftbUlTGr;JO7Mp2mgmBKSoSD@Xjy2*JWsB}e;D%N3;7*e+K{zqSi~W+m3>Ti z%hkxjS>jX2<>o1!r^ySB_sl?O{=0i+uP5gGk~_M0RPaBE8Du0A%B%Sk{PT4+aW>pK z!uSv6COuc}sb%DIrQXDjU8~N(UHt_dHg;4)kosq>z>6A0mw`v>jg6|^zHaUzQW?7M zov1_5)Y@F-wbEi-@A^4^oPrLtVKF3fcgLGiKnVAb>L1{bpv7+=jQ{9k_lmH|Q2#eY?%&#yE7iJ>Ut&*?E6JsW6b{D({*Mi!9d!p2C?LjV6w zrjNe0rKPC@ogM=_z>rl}&xlE%jrr&Q!(_y6phvIE%ED&EZm0{=1lXAAS#|$@F#NmR zf1(Hs?93o^h>4zo4fJ$DqUUc&h>?+*_NR*z3o|hr6Z2nzqW`_g@L!6+uBXpL&t_y` zU}VUq2QV@;1n3(YfQ}jIGXZ`(vl!4DvNId~oua@%|FhTrOc5B_X&D&+46FcRCIAC1 zGaG=7g@u@bg`F1khz&F;X9A@bvHw2$zgL96@>8q;rhj;Xe-s-3vspGsC;3~mmLm;y zYlDU`uX1hKQOK>(V{9EAoiEfJI0l496HQ+XDv)azM~DlwbSjY_ZsNJff`~?k4W;q+ z0;<=YrpXCFel5XhiiV^9US7ugZD@xIV#AavM7-%<+=-OJ{4YC%2g6H`q)*pG<_8A) z6bz}+Owq**@7$k5U0yp?=8_HIe_--+5k_ZBm5OflmKHs9%CjbCZ@a5 z{M1Z+#OM!Xiy7|8{mCl9qySI&`FC!zX5VX5UhZxt>u#JFciUc0_V1EaEiyFCNb)qU zwL;W25<4-K^^P|9jA>}O9KO^S-B@GCr`ZDpDkBRy4!V$IP0SdIPEL5!_>zity_J)r z>V61PbjP{X&ZA*&jHU2;@pwM0(-HAJpRQYs5~WMOT%|HRKacpI99z7r#qZY|zRH(b zX<2Yf=2?IRb1J9!t^iLY zWLP;7cgO%3Y3}0?4JXVi-#(s0oQM-Fy{?#BZ7a9|mk%=%B>Hc=3MogTUjj~EF1sSU zeY(G*#mVfm4S%j%B%oQPl`>$OzOSk?JnzWea=D{TtW1%3Ld`d9oa#4@E_lXsf--AWQ9lqO_iY+*dkAM*5(aU%(0qJthE`6Xq-O(Z7k;7)y z#xgyfY3wFwX2S7g;qq!hfRv~Drqp|A)>yA`g22IQjn}E%*#~ORo9@YY z;igmHClHmJ&i1G#>gjmr7K3RxU)rmr)&epd`chzsi-l7s`E<7J%Qs`$o)Y2&pE2_H zg9cYT7prB&$1fh9J<}hgq?|A*oJo>(asxy&d0!K^n=2H2>rYE}H`@%jZj=P$<&DAB zX?9O2c^{C}F2q*5+v9E@>q&UguwRU)+3aZtZ=EB;lq)?VcUGakXBIgVj)jJo-Rw0C z5Qxtk-lLx;FV*a^&GRrBWgZ?)+Girb4U=AWIH@$AeXh<0sGLIhsUT4UQappX1HJPE zxa8jr(NaG0xnyc41?Awi2Zi5T`L^=RcYhVh0o?bw3-(fb8zb6)!vPWdB!k*BD~+t{;$ zC+dkH4bCR^9$5ZJxNX%SHILR`uoPBsyC7rBCNRDXrhM$r{t6EVb;(kGwQD(Y!lb50 zvSw#*V)nqg;F8~avzx22wjcmFv8lw$eGifjkiT7Rr2$A8WLq5VJRSASNq*MZPS-z~b;GnXh9SMOaz> zmfizjHs#eFzcRn;*t8sR>4Z~L(Q}ZrvKW7N11gj}7cr{Y=_- z--0LZZ2c1#i*^vf~eqtO||^L(gYq z=@FWqAL=$%f{#^!&l#ar`=dEs+2na)UKbi0A&to0%##gxF+KQuZYk6)|AHxJUrq zo-PmdNx)Y68nK713~jd`n*~o~a-VR;EP_UVqDKX~*AQ|fDL`2jX9i+Q`WEW@tAiiZ zCajG@U!iKkaK|d<5A+Dinw7iZt&<%q^QL48Os~pT<@kZIn2Iikiix@5?P7c%bevi) z`w8`9b7`&8f5>4Ac6VsJ8l0CIp;qD6gNT_#aMjg)7HRsB^{{*t_olzMnQdCD9Ng>i zS=#&YB7J>Fh^SE7GkS=pncf$%I$etFbfG*z1?F44h@dc>gv1Q3sORl%dfUtGC+u5e zPXH{kv}I?*#M4+xX3LIV`Ptb2#ob$nRk?NR!yqCJ8$>`_kdj<9Qqmz^N=bJ&(jg%! zA&oRhcXxMphje!ed=KE>TerUNdH1=_IoI#of9U0!uJx?3#vF6Z`8?wu_kEI3o$H|G zDMb;i=tN*}733z`*{l&r6z8H|CAEuWq>Vdy@n+r8@OhE;;y%PlHyf6JIoh>tall(S zN34?sH6+@c3lz8nqAlw}!MC)bT2Xn9329T!hd3DPlyAm!Q7m^fz8vvWCU-Wg^TK!s zV5IO@4#M?#V~X!P;i41HS3e#;IV&IFX4~aBC{Y^XFk)qt+g{m=9<-jJiK5hRr5@uH zfm>QGiX?pjZqyWttGyZka)0 z_){jUqm>mMg^y%1Z)+<8Ei&ycv^!Wjbiopim081n8QzY@~<|IH$?9vQKMh5nyBQa zx90UOSIh)-8(2VDG~@2AgpbPYeF+JkpGw=fa((h`;j_a) zrY}z4@vp4wJ1<7h3GMm#7`UQyeZxo0VNvZj6KG-Nrl3_%A2_&zQK!U&U=Ba4X*;f!<}l?TQ!}k zJOen0#G2piNA-}%0_ZZQA8-XwMU6J>W0DC|`p=8Q3qyO5l>40L?ZPl0Pf5tPR#qew zjE7JEmg5{~e^{2Fyb0IRQlY%_W{XIboPh(Puhi9Oc$zKf{63akX-{vf=jhH3$?kT| zuHylj45C`1tXBSeg*RVc*~^SUS6i7>)}Ay)L=cX@Um7$O_Dl`dKXL_h$LPyxXNAFH z7UbH#BJ1?@fS)9YDH&)Dg}8oX&`%q<#52PrhBm6})a+m=Xz(6N5Kx;F?-L*joI@=& zkI{C;hk*`nPd5H3duSKIy z8&N#YS5Y=Ha8REW;|P^lu=f3BA+ku>sApDiyx4^))Ue@sn-01KW{TFuTD(x$JX^by zmR2B3!h?^mE<=1@OP9|#@G)tgwS5k=9dQ|Et?{* znwv9Kvt6y;@=S{zn`%8n#xZZTiWyGm6T4D#IET$soby0bNGC%TbKb|4TkrMool9CS z+U>-VqXx`Q)v@ZRU$RN57C0Db3+d8#&7KxsqQiW4=6q&+L z-ErVTcUs@5^!M=3$q>(;ODXK+Q0t)&c`o)}q9jws2F79@`j=bq$PB{rB4UU&7#qf3 zs)F-Qj?{fw3kM1wYl7%emMsEJ8?9# zRDqpBOmx#Co~}dat;{> z21A$$h_;W#THaMgBLe(WeHlrm2F#vM)E+w_;*+-{!MaQ$4^usT69yK)OUvyd(+iPa z0Y!^fu|_wjU!i0!|IIf#+KyTc}kTlH?kRRvln5fX1_S~IL3dRgj5+!kEVof`0ai1TQ1*VNwm8Q^X`GP1xXEbLWPu^NiHB<*(S;+1}Vp|nv zKOT|qQRAhCpJ1s#V6*oYXhcJ9jz=iFZ$vzm?*9T_Nwu%1I7@Bf+HcADz7d#gA3wIc zMJg(h$wGmg5L^eK^?2d;|+a*@HkDWl~JUM9B24!KAJB zMVdBqt7jP576{LQg2yp`gJswwB?20xurPcwt{8~(mY{LLz8RqRiE<|3Tk8{?yv_4> zE1_k)g|<5_8idkRW`tx^~mZ%{^Hg{w0Sv`QtHF1C29tHYKpw!C;PMZK&J ziQ*ceX0`6Uj1+w(DyV_cZQgHKNP>k|AEhRfk$}qi~5L1s_w~v-@w9gf>apy!Eu?Fy07H-p@cA?#e%WzWZWot zo@vEDxaoV+=58$R2n#@$Z=~3fn|P62(1WGDklEz=lyajBT%c*l^)OI(CXI3#iw>D<%Ydy1w#JP8fwchw(@p6pr-d@nvP+IQ~+q~jM z2m>AIk9#zp@OQZB-}F6s&HEaP6{(ygZrSC+3|DjRO6eB^VG zOeL3%@->74{oaAK{-GEo?d$Q+4KouG#*c0)9vb)PZYv%IjpMQ`HK;3uvzPIlIr|LH zCxW%@DUO*Y&3oNF?&WJ@ggc%1);Q75PEJ)dk^K=K)wDK;L8?rB8ehFrTClT3q)PAr z(M4?Qz3hel*177O@g4Zw%GzSxYoE+TF_jq%6L!#ok-3AP7O7w5V)gVD6|HsO9^Y{9 z7USzmAtuwZ4}+Y%-FVSf^LCAf8ymfjRfJZJCuF#el2yGnAO{i~_TA2fScB0q1?Q^y zMs)RMj^6A*S9|;|V*mE29ubJuEKd1pYrc90%{X+*HG6hIe0%8LjVB$PtS$_N2(zpn%m~4e^(9x0YV9P^^m)kClJkD&l8B| zj!g_ib5p6gsh51Kn*h}Ix358WbrTTiu73(ZxPKe}c0JIy>w&&q4|tG&_qlJ^1K7WA zU(?=Q?|-rWa`zMe#$$In&<$-F6C?1foq-WhK489WK%fK45RA+;^z_WPMD>h!qyKl0 z-TyaRh8TaY*L+XA{vQz4|KKwQDxi3Et0D2d&**<2{m1(3XX?LO6%|-&X)AThx29V7 z)FOJu1~&5K<4@`&Vbq>P)(*~0%RlrZHa$WJ_G&KnRK^* z{db-AXP|xWw0~Hj{laOtoBiK$8WRf;X$&kt@7#BhcGLODLJPF@0i*x8Nc%~B3Fut> zo6GZir~MIWKRE557HPk5+V{wT|6m{ZQ5ff2@&aU?0Qn_G#vA!103Jf~PdcK3=zlt+ z-5$CB#_IgeXY|ZKSL*E%?FXMR{XY87IHLW^XMeLr83deQS!kG8Zkpcz%v~TBCg6-l z2MB=u0|Skb_OGy>+k3gc5oq5#?Yl_(-f91|Nc)A;{_foXGcy$(aDNFv7{7}&dLZan zfSh&{fBz#X?Z0YcD3pYk+i{bvyV*<9@oG;#ZBL~h3VmOMOLb@ewM1?UIvUD%iLt1GNGObX&RObU%> zoohQJ41Bq(;(8zlvT*0b+2bVHPenHEUQj#f=?CwloVcdsS=S5`rIErzMzn?b?KP~; z;w@M%&zRD#XUf}k7$7x5eUTJe+wC*m>`q%Z#AZ1v+mlg?73p7v$Z`1u>oS(*C^?LPk#$27z!K6D1)^pT(5m+Jb3o_yedd={!VBM!Rbm0F)aZ;d+2+ZklbwM|2)n2I99S#L%bZGBU1|)tTd8%<>i(3Mf@&;Q_gwR2_RgmdpxCdw%iz9V=11<%iu3Ei zDzymsATo-x*q;a93xToTuh;+bTkUV#B%;WDNL!-#lRb38Tm$P2`phV=LvVWlw5JC~ z0)p))zh_(d0{d7dw=M9vi^ws$h>NxVTM%V+S1^4nrVqaG3lUg2`4~(;dC|Xj9$o~$EeJs{rSC)C~-Rb^`)(a%(MYiDhy*ZNi!76b&`q zA~YK3XRu~QtX4@7k%m}I@Rq)HR))m_a*1T7q()>W3Wp^H!I^00g)L8JaA~d%PSR$t zq^(L_JL#KsHLS72$RaK1^Z5f$J)|XlV4t>Kf4Y*1Id6M!Y@xroCLwPBY3_{<`)LN& zkWl$djSYF$i3}3yiQFYRQhl$xybLB6yvbYVg976i+#0-M=jaR4+Ba9*jx!7Fx^n@= zKHG)C?^p`p3=|Zm5yI9$*01BQ=?%)862hPL8(dZnY)F+b@7=eYj!;9zbeaw{Av`YP zdWEM+sto~$W$x|-izlY3ouw#JrD55&Ayrf#wbc*KIZ`hYMG;A?@I|VVq>W29qD@i> z+q8#sA+)_ymOln1pnc3|nXLTL`qAROZo||?Mz=wwG!MqPAT*B@_G66wWNtnHF4_xp zdrKQPwg;yyW9|i0toa<{0$uL{Md0XfsUWBZGy)UTjT}#^V91U#i(V{KG`5=1n_yZ7 zgxSO}nbl}=5~y$&KCZYXI+J?ullN?XOv)iYM?{$IGbp(^33rqkSJV3ugH*WgS96uG zWR62snXN2HAX5|Kaw3i#?a!?0B0e9YW|@{$2s9DXr`TFiGHF`PL5@iEvh+Q3IJ_54F^VeHmxMmHm>QwS^4u>(G#N^{-xvx4 z_Kgd(9r%KJ$XL=C^}g2|m;HG3zH5>=-8!h;d}1-wabV5eN38}kJ9Gm_UrP|^8%nK- zMu!hQmlcN-M%T+e@V5i+uxy62J%9d+dhUg>rv5443{AvPKGPKFp?o&l%d^;KMxDw} zp*RK0ueTH*2srVUM@havcu?1_?Y0~XO^m?2gdVyhLoWi#?x!C&4s=sAA|k{w4JPji zBViBru(n6N0%K2NbFnCSsn!~%#Wa_P;e`t|q)trv(k2LyvQ)NP1(09aJD;`)Qk;s1 zutW>i6s?lE)^zR21)lAFWn&HPw$c}3;PJ7*+*Ir`A-`hQ;Uc28c%*|#O*b>*dLpal zqCqD)Cwy?|sy%F$({O*KY8da8$74UozVT%?+Z5P=gDtt~GP#8G=f~o~_N7NwDoL5; zvx=E&uLwhjFexdQTJ+=Vo0PfQ(^Fd<=L4IO1XsPbP$*(5qBgPA%KB_4sIcC?jwy0_ zb<}%YPBsU*#=(C9BXz;2mQZ<}Rg}as&#|v=|G?7|OD3X7Vk0PT z4_l9Hi&!m{OlENuHoK$AXXB+NFTGdzpm&dIlqTh#PYmNv)5c~LnD1D`e*P3cOR-K7 zB2<_&N%ZRfFUBzIhtx2K)kJ<^+0P3@nwV$nW(EacoILSTJg(7K-dbt7-6ZAr zOLR6wo1}A}*WX#4eyt*(ESyqS5Xjd`HO(PY3<+AoEqV}DyWWp>4pZB7A$ROI|VAX(Eb7ECfdKQsk)>XZEd@N<}{?;<(KzrC`3?rL}L}77h z&Q7#Oekb#^rDI1yK`t$~W)fzwPk5&@9sct1m!r3-)2aM1Gp5_RBLzN`xds)T5rsZg zFxvtf_Q-gO9q#fSTO9PuR5pGgNfb@YcszJ%_s z4QcEV#ppzLmz3jJLFsjMD3}~qKhXd~n(RQG_^eAbt|a6TAhs}L4aU@`s*5t~p|S>+ zb9N48dbCJEbajXa7ieUNXvHWfr zdr6`Sb?^dW0Qn#o~{)*l);q0Aa&@ zCH|_Hf$To1B}daXrXQqgF&h_U>8turjg05wd!Ry;jOR>`hnTdO$Em`86Rrk!>}V_^e%l);FPA$e2JeQW6H<+bx_^Wh;jQHi1~nP8_LrmSbL z#n8Zd9)*RH3xi8%OTtp|OJcs1MA^$COIj-eFAb3d4g`WctD?Uj2vo$VQmxsrP0=-2 z!4Q8nUD^SzfLF46u}KH#@Cquol-jzVkm}Pl@iZ9T7K-JiI*yxIIFNaD{*bi*OPO` zImN-RAD&WwaxhfO_mYEBE9We?ya1EpemR&gww8$_C2zU+5;2`ZF#9;(K z`jgeN5_)T;5}ZnfPlHT4Bs4MT*=rTck{S-Vs*hd}t*!M(vRiE#zxiCa9AD}P$cpt> zB`w(Pa{DDc-`f6AQ)*bPg2%pt&K1Z6f5NK;|Z9N&~Hr0;evw(MDdWLKvrAkFOHPuZI zI)e3-)h>C=W3)3-&&ZT?uzQi&9`4?Q0?aqM@e_21shtf{`=y)yQ4$IiaJN4k{fO1bx45xTWy@AT_5_>;$0 zTOTgE&B*o$gh@z{nyFNV`ho|S2y3Yc=`x#vNy(v=*orLeSc33FQP=@ zHCju_yGe~A_E&ECwd_3mu%mG!?qynA0v6rH;QN)8X;|+45B6kfCT$Homxk?*X3jlj zOYX(`IZksh6N~4!!Z@G@ZnC?Y`kw3`7VuDRE!?ll>_UI+&5F0&?%F$@L^OW53W35& zF26yIr^#YVF38e5p0$_#sWB(>IDqH!ipp32L|*R;rJvy!qcpjG0S9>`pdGTfGEA=; z+OeqaiT(4ohUE{o7phtabQ1Yl+3Eu`i^10F#fswif=C%?)Qbr{~*x;&N!2Iz={G;0RAqAhO zq05a1?O?SOX5wqALRR7L&OP?ehqfv$eI8O4+-uGbO$+|~yhp6`0#}i)X?%SnJA;B+ zTq`K3BFQ)Cy_B0FmMBh|;pezdFH6;?Y6|_*{Hz=WvI*W;#5*`Rxl%erw$?fT0ue7f z>`q;st~VBOohXD(TT7#zw-e5ncspH$Mx&79_#!x+SoSVD!Dwbg${Fd@gvpE8j3hYr z?75y}qfq+^Pp-bTf6qDaEW^6JdXmVNO1!dMRuK=2iI*Yk#iGkR{^t3_m^C00VT2GP z?#v2qGm$||zvlNUfqW_qic~waK}ab9!u{R>mAnzTr902`u5Us^}( za#?vOs_rkOyP^Eh|7jul2bIYwS+}w+rHcKq^2d*)Kt3g}XH-#2AUv_|j>Nn-T=g1Sde<29 zDU}?4W=9G2y-5n0BvSoo$R>XyjTKbeMCj6V*b=o|O$?fe@4)F(iH25F0o(81#h8(jk0Gb3s#YWtJX;)ffv}!2@X?!ki<-U zw^qcRE-n^3lC9@=ZhEA4n8)=8JIq^X;;7x@5fOepdy%(A@|!JD_riB+-GO_mNGjWH z8lroP25B7cCS`S5{tw@nFw^T7Z;4B8Dnj7~>Y zcfK$n72$p>6#-}}x86uaVBbkauwl}g4sErBicEWDi#&fzE?pe9C-pmCTB{BO^#&eh zv4zaC-1A0M84Ktx8Bj3S;01vomCONxm~?<3<{m&0L&I8JBKG+hkctTU9WSkjeuJ0p z`C6iSD-}@)r+5Zk*Q{OW>$~F^^$4qnBVPHz9%9~n%<%IP^Xj}6%mTrCmU#>FZV{l6 zTcwDk7ccxyndu=QQ0cVG6*YP2v@f&vI$e^=OU%G7y1~QN0iGD*`?OiB&8EnFnczzB z;bcCKq-x#MwP$&r(+8vYM?7=UNOSQ`Up8ZyDW3?A5|t(YyrU}o0w!^`>_xs}*lsW? zJdHM_E!Th>w}Wiri#L6?#fcbs4MLA;iHLTW6GYTJpq1*Ly4VISjV-u+@L0N`h3io*)}?BYY{dE-cu+ z-<2ZR)z@Fx`E5+OMy$Grsio(&-*Uvn-g3mW2jc5cQU_+N2Lr;&(zx~ao5~jah4zthOzvFeL{1)gblQR+T;dEX`HXNQMJ6z*r<@u4xEWBkM?-;w z4HsYlBr&>wlEmaDg18s%%d)M31P17$xd5kJynlj zw2$x-3cK*_S!(EeALKTT8_*2bJ!v&rmZf&D*LC_8Ax0suSQfy?>a=gQ0f44mtzHS_ z7rCBF+^I#_gJ%LXF&$V@*EpfFj_$m)AHEUADEb~JH@U7#e8HgdL(607G6ZMZo-o>a zIbCYs{8s8Axem+~S1O$ATb5x(ultX)C}h-(vPnzL)xRWnaJV23L105Wjn5m(-AF6< zl5DS1hn(5s0@BJHXcqu%I=n~8?e&1a!Pn!`y*?Edq_VfGJ9#UgEBV$6n0H*61Q|y= zlRqRK>IuDY!r~GKw3TDrCa^i$F@D2gRv=~G#ad{@fvxHO%2DvhcuXLNK{`XVQN7Vg zhvZsS$4N+ks$jOfyPsm4GHwm~WYeYsFS^!d@G4*sMVpPXzg9uLXE_lSd-EsGcFwxy2-7P$aOA`^iy@e{h@wr`+gb#6*44VL z$I@^LK>Rbqo;nMsn0TL_8O`Wp5qa59Bw#-hc<%9_ul_`#R|jchEtP%gLF0R5y`seq zO|+3YRuPl8p0D0hMMF=JejT-~!260vJo(z=7szSapJ5~aGstP$TX^%oMNZRxLp;-d zLp;-dLp;-dLp;-dLp;-dLp;-dLp;;{?<1aXP5V1VBicW8C4h<~0Bv9dJWC4@{xj16 z)mlb;fYpTxz@*-c{=Z*_v@|i$GNuL!wX`(UTDF#2#uj=e#uhgN-&Jlwlp?eYf34o$ zPUU~oZ?pi0@|)k7{?y~30boe~B)|PEE&;lY`~RlXK!E-?%bg;}_f7-QHFu-`j9~kf z)BYwpgciVo(0zlpG5)a@X#uGOW@Z*TIsjP-$PY08Uq{+EJ|qyWwi-ayM5j%wNl&K< z=)E&(F==Tt+~f`okQxiKx*9-~#KiLRa{HU05}=a1)BNBd zAdJ3^{xcl(H(?}n0EUX58N>jzTznTnH~(a0VxqeNm;C=cf(S*JenLjv9ytC+g8q(x zjuxODW4K#THw1LF41j@TlmZYx)Ix?11gVWn=?FIkL%Il~-~W4~5*zBWzUc-^=x+|JmQ-MuVI(cI7M2pjpF zK{364!u;|wypzdfOFO6b>&pJuM+lQ2reuO^x$BpH%Z{9Iy0Fbxd-*lIGH5BN2s&j< zDtBap@@-sIC5Ka$!@=|h-u3=+Wo9)8hsxDnN8e{ZwMws(i}22Ti8D&axV4vB8Zb#d z5^K@tbk6KWaQ2aV#N;?L7WR?(BPFGJWzKnL!&hCj0@10jWaLGiR<&j)TW4Bd?$mJ3 z^;X8DUd&HN#3Q!Mb|f2|_8kReJk;pM)efg?X*X97AGBP|m&>s~T{+r2(&_#b7>!Wx z(Wkw0(OTFo^BBu#6s@;C zdWpVu=$quIhwCMqLYRDekY;gAxdq_4(fQdx9iQ|!Kx2ZFFD`YD)Twf)f+$2J4|$c)FEy#u-E|gxnc_OBs6h_`^sFmtuaCSq9j_lsv^*@c zL)s9mz;a5JFvU*ny(sjRNX?tqU8I%fw(s34!1&_k+aBNBoqtq>r_@syCY57OvOXsn>h00I1N zk1nocl7>niLvE+uIC1rH6DO5d<&gMTc40G22f|+o626!z1E{U9*P^p^`hh$_bdsgo2%*74zHh}FHf<5zjIl$F~+(z zD(~GHe!9#TW%jnrqtJYnr-_~7y& z+OtQB4!a^SeDHR*az=_sJ4h4fjnK+A1&<(?c-}k+t9hw6y|5L1-i328KF`7)*BHsN zT+O`#JbYa>F6SU;{*)JgQo4?8gk60-77o+4ICB^qNN(*LiMm(BY+ozC^O7R854`Z6 z6YD}yL(u7_HOkXRMx%vJoncjx!6;iAuuIZ05%+ueM;v>zA1`b!Hm+=IPULub`3>k5 z>e9lcylX>>WHcF;_iO{Yq2NfPoW#-1;5kU-k6sb8-N)~CIkGnz~{ zg4fWcr**z}R>mjdR)$U~Z)|ce=S60{wiszU4GQ$CSkZhZL@^H%W>FLa619VRCdKaL zyO8|qxr3+BR~tmH^YH@P0@h%}2=4FB6&Hu-@`Yv*g&;AnF(kf*eE1d#E*OpEgXmJL zdqYjeP?o1crc2p@#a&q5k5!tUMWHGiIE$&xTc0_sR) z=nfJI7tt6JvqiC5tS487b0UoKKyz@UACy<d2)kWGy?7&Jjt}EFVkg$6B%exvEk2|~j;BE?h5s0AC0t`;D%DQ0`^+iaugrUbRW6nr zynRC$M}bSR7~R8_#Z~U{3XDG-olPZOQr7^Pj3}dO4)O`Va&Xn#!w-p6NYGFo(nadt z4A=$wA!O6g)D1#tLMYrljJkmY&vQ&oir9UH;_CVt4Lb9>%@G^k2m*{6ke}FhgH8z& z1t(m{^$O>nhiLr-ZtuFD6MN{ezDcNJdKf)Y)Id6spw)#lHN!plnc<(nJ*1SQs+;6rj@xLJi*} zsin|NwlkFR-_1*H0}~^oU5Fw;|AY|Byl$QURQg2kqfq#&ReH&D6@EfAa}CCx$F-u& z%XMC4u2W@CACHD&4LUgoafBsiGcfU^K9sIwV0us=WtR`c*Zn5=%t2i&nT%v6u%2gN zIpv^ENCIqS3ekF8W#vfaNN~#$%znV2(=kZUf zG@er>t}?h}ektHR;$F8gAI9_;NC?91|D1V`*#@?(LO<5#OX9Hp(B_|P8hnsurN;9N zWD$Uha31%d8}V05Ue}8F0|g#z(}s48il>jfm)9a1GJpFFJR7#`-x^EcZf>yd)D3ND z5bp@*NSlaP?g!t?NHf~*`PhbDqiRc4VZ?-GlN zZiD!H2>+rOI;c%#X{Z7Xjuph@cOnWN*$q;~sSNh>EO5lxXXw|q8F>zcf?X-^X&b2W zom}oG$rpKGf5kOEI^BCMNzZd6T|rH?`cV4esGREr~?-o|@A>XZI34a)k&l&uP%ZMxnHDZ~~b^mX@KS4WI( zj+$~4!lx^{_!};b@OWF`v9P5lS3-)6L+L$$OM^R*33?cT`+>IA2ks1N7Lqsa*~4~r zz(Zln7LaTgZeEP`u}kmQVdJC9q3}z)=C=bFa@oRHLg8>8Z&``5rCs6Wm@@K88ABBz zkIZOOL{uLfxIFNg-PSF^Y7Jj-Sj0j)jLUSu@hwRnuVLHF9rv2zspof9;^0`Wd z?n!M}c-5Ot7R5c%NyZiKDxpFa7Ge) zbG;U|oCU+DyW*vhy-{ScyKB4dm$54QDyLdkr21FwS3L%R68CLv!mD0t|%gHINRI$v_}=ZfrF`B+0`%;G)#dg(Cjwu56=dUo>-dPr1`u^7`oyZ(3h* zDMYW#w5-NPn#DCQ%8P}7o9|lpJC&x+PL=CSEi!`$d`pxfry43z*2^lsv@oER{l-A` z9H+AJ$?J?#wTglPj%x@laW$@AJS+wXwg1{T{Xg@t`1ao7SDM5BTa@A;y6+i7{vFtz zmYMNKqUCJGmp6AaH8*!NV8v%nU=7&!ptu1M15I!|H*Ee&1+02QFjlXxm#E{K!>z{0 z+gTcvErXZ&6|b|HSd1Ly4o@Tpor4Eo3bQ=0adKd}w3d2#=yN6OGoOlh%^PRnnwUR6EHZ~($3+;WrP86*f{G78Y#_9Cy zNiUKLXWY@*{Mlik_|v*UzDjZQEp#luevZr|>i)4(+x}x+5xhVmN05NV=*FIf__6IK z2q$pKB)9DhYV^f{AQVu#?Jlh)v>Xn*Cy@^vaOs>XOp9GPN+DFQib-Z z;_+~zaUv?7HMtwrN%jJxRN14C=(Zl$&Rmq*I;gb5I?gXO`V8w#KVR0kDDn5yb#%U} z7#J4Uwaj6UJGVf`;d~EIm18bz_o2As>OL*W+~9Jv)rbj6Rn?ogodX$;{C^-b%1Ukrql&g!$nw$&}Ydlk5 z%#O@qlNROn3ZkMzjIQKFf1be1>WUMXiFuNvp_yH^&FC%rzC*6pf?c>mz^Y|+dOA~5 zl}E#qMsWb6Uq7*bk!T`k)+_xU0rbj&BX(loAQ?XjMuLFps|eq27CYg>B+%Fs?I4Sf z2Ss@MbOjz&i;q~L0lL(tZiOkdUh3xK!#A=GZ`s-D* z6640cj@0I2Ri7ZwoY`=yv&ehW8@E^Th}ryOG0>*D-cojtP_0!&G8H3b9dxIvhE&+} z3@vT)PY*cnJlJTdm=qLiHQHkm1&>yrnOxY8om8szO*B^Z62|t(bpY;)tE#@d?`ZhE z#)p-c5bHRcB*1eV+A4Nm>_nf()Z}uF%sTVS1)*>11UCAk2F-I1=kSGO+8A-nh^&zV`*qKFI#!ZLQR8Ocm;9WT5QKU7up~rw5EF390 zNS^EQT+a8n=zUt9BbL&8K(YbeZXz<&BZAr<#l!j)!+7K%%2?9|!D zTDi}K&R{W5jE$)yi~Lgf03x}x`29v`VNu8!WdRhW3`@w9{iOQ-({Omca>S=bbwcA|d;QRU*LLPn zN3Z0PE8oVi zW2Jw4Ur?6*%m>MyNW0E(B{*)5N>e6wI!OV>rtTq>yxLS_DEp)27rDoBJ8C<&9`Cl^VR(a z9iC1CY zMm@`=d+~+Z=-QXib;CM^zR~tng$s@2P=}rP{oouig%c|y=DaP{H&lK&Rkj$vF;Qim zI7RD4U4nzdEPQ$K0Fl&KX=IuXtHP|m7q=FHxx%0n;?x8&PZsLB8}#IZngDfxFR2~E z+(Ma0lI@dj)-wI$m;qP80No~8aBLDtB_)QyO0zKilJ$iQh59qZlKVsW=j~ui#^Vhy zrD^KM9?iKFL4G{j_P(dZwKD8uUUws2BqaP>cO%H-5iyO6C|EneWPZ0xp2t>LFsVm_ zcte^Hrvx#gnJ`|8^9N5ryr}y|yy!8e!UN0?5+R=wXczi~>2ORcJS%48CtqYOj4{b9 zSGKsyMIFZi;zijv;zjmQC~p2?YMC^TvW1naOlKiOh7@$x0^@a3x)C#9Vglktr2F6t zp_cuacDsa1oqJ!b@rAtfy{zMu`yOl_v&>ipS#z3VLFLVIN_1!IQ<`?bi^zm7k3WJW z3H{R0cn^T3+-MiYYxe}NNg{H=1-4!2CI={a2NlLAVY|2wH9UUBJlMLff{V!a;5rzb zVu2nUZwhA~i%wMMb@$WB%kD*58WHuyx^3vzM!1GXa4P!<34Q!l{rfs$UGG;gCv2zY z+H;`>j4;M*Kt2Lk-bgwas0zV8NKm_$5KxP@?h@npylq(z6a@E(G{y`*C=`(hV0$C# zU^mvSf=kn(Bb6PzsvO^u+POH&I23Y}XL-4gBt>6R&_}~M z=yh2(Z%o<+X{dj6q%ZxQrn(kleKw;9`J%d$z#l610W5d<} z$GwCTXtIwYN)&*;bMDI*ZNuj$PqOEaJ4;Tn)0t(m&xlF1<0FH+i}I{?c&SCFv+`mB zX~$=%_8Od%b7KEj_YpsHNc<1oN8BPxegQi9-@A|af#yxm(ohSZRNPd{SV7CwRLfA$ z82=k+0$=6^Q=w<4rHL=6W@TuJ&t;{lXGsQ7Z)#cGP?_C9UZ`KoE8qi6fB=sH12X`B z0UG>)CVxiIEsYRRZ{#ttGPVTd-C?Qu^~{0Kf#_~O2TLuYcJqqimP!zoT0+fS>*jq7 zckbZexS4~S`qkb0|EOf$nJc5F4p?oXjn88OwCNjL0@MY+TXhG#xwYy~?h__@pomO+ z3uU3X0khm0Mf2y^0>yNInGlv*48V>6Cf=fWZVEzw81X~Z`pyVxD(C+ZgVXlr~mGb-yQH5OKyM850?B;9{y&DhKZ@xcXr%?l>Vk2cfa|MiTH~hw>YLB z?D(MyduNA`v8B0*rj>>zfW7(7oI8xv-!$j$hyM$6=x^av-6g)QH$!*7{a=}K2O9e>Rsdpx?;bhac}7rAM;BjO%Ua7^&+@y7VYY#8B(I`Tq5fVq{{VV!0z{`t=gLb(_== zb9!U#Uu+XGvH67`ng50#Y5(x!-OT;r$6H9>?|F&-TSE93e!RWAtAfCTnZ~AaU@yxP|bwj5SPd7Q~-R^H!2i z>ZkYvAUDi_0^2S9>krxTF8;nb>UY=tBB*`H|09R-M>^K_VE#iM+F~HzLMa%ea_8j_e8{yra15nJ~>_Fd}@rz6^^rs1y_;=p3 z{9#7_g)sn(jEaTvmXPN!tM6_~|C0RwV%l8-{NA*ik-r3*D4-Dsn1ZiqqG4fa{$t(+ z-C}lso>V3f70tg+yx&~%N8@@Uvg~@XkyB%G#f{35H*66JjRDlv=i?hI$%$ zmiT%`rY7b<{sm4(H|bXMzci5chH8n9o&|t^{mQ^^4*RQt-%ac7QuvDlffJU7q17## z_B#XUZgap-iQ|`x^yZj#7iHf9{x9qBdjr1D_}@;B%zvI7zvbk+RsC%hfB)(4bMPPZ zyEjMM8*;&$%NPQjPWaUPhQO5bY5~a*7!=Vm*0I#ZX97;1H;WGlT`e^uSlgKF=TNq& z!y_v_n_Y&C?O^gK@7j#LpB&2YtlkqMbqkf?_WD2}gb&Hh4TgLO?iLSykHbfb_l4a~ z!mBe$jCwmX;CQzkmbEGttM;rcsQrB`#*KH>#7 zOfq2CeH`16L`x;M4pT>Gy%E=k(gS)N+!*o!L!rtuZn&VG z->TlXJXw=}+t_MY!0bK450+vrx4&DTB?_gWKD?HyO`^l{raSPXF5B=ae9z;kl?hnM zrd(IN`(0p=5#?KrZ8ch$m*52svD$MY31$Z?t4KyggQZYPK<;B>Djoy zPy@RpPt(MO2=9sfE)rbt1LE7FS=w`6uKT>)?CVEq!}x-!AK~4)Txl>F+(q=ca9{H@ zw{eL>v3vEif5d0)wWrD~qI$7BtZNAbzRo=J)h7bU!9Hx-NuJUw|FJav{81 z0o%c&M+8;y{u7BdR0A}MWAC`7TbDa3IA_*qm*sN?b;oR9+3JJn*wDf5*?0 zz-TrAj}rf=i0J(xjjdUEL{D3*YPi?`N7*|y>B2=#f@Rk!+qP}nwr!oVZR?b6+qP}n zHlC_}XKto@;=AdH`~iDktXPpNGcp5J@9Q&w9xA}P4Vb zgDuMu;KwU>L)!95q?$2unDed=_&f;66YXXKv=}kclE|tfvmLGnzE7=vTv^^{i%nt z3RGIs$&DpMimtdrssQyz#Bva;hdu0!P{D{6W+3I;B+k;EJfhS3MG^z3xPPiQh5X!~z4 z4nG+o76Bd-VrJ?}Gib%CpNWndWoBoU$0i6kMeZD?o|L?p`swVH{|=yb%-iEw_NGqv=j(xURiti;+O|{TCUC5Ayi< z3_Cu?Xw=ej)bU6jWUjP~goKVSK6e8PWMQAZ(9`#gWD*b&CnGyfL3Vn2ih7Jt%EfJ7 zjd_ASejDj!Ow3kBxW!k?Fq#nuJaXlFDBGr(me zG{ejiJp4FM$lXHX{*Q!BHe{X;ALbhs^7KfWOisdSWWi|hpa>!fWD zTtkdqS^aDT)sks(h2GHuc231fYZpjEOldr|Xi%di^@=V(BCtcfi{QTEU)=!uZD z1ZpCcma?ryI8Ypm8z$vs6A7F)vzuxm?PRY}%90^=zf`0zq$BpalQ?x@U(!L0QvQHehMuXolq){vi;{Q<0}wLSmsZehe=U$1uUqPXY~^TxUNV*1 zkXQzQUIf{s&Fp-ZlBn@ZP%2R=bR7kArBx#k0L+LL5MnSJ&G%Tq9PCU@My&~^2tkP> zLRd68L5cc_MV04_mCB%M6Tp#LDrg2`#&d6+k`o&g$LxucZz~B7;RBS?O_ZlJ00b^* z7No@g2dr|(5Rv84xzmUo*)@r(AxLz&oc9(%+~^Rr9&Dc`;6pWmCEs)lV;{aU8CX21 z*fPbM>Z*}l{53T)n7nyCrPWeCRhsvr0NiXpRo0l9g(JW?EU3+NB;i#mFM50+3Tv*xeacV|KOf)f#ALnze4;8p?bF?UtnK5|v|aQ4CZO zx~yzX)>68?DW1tdmw+y9AQ@fEP%@IDlrC)`#ZkOhlI2{j8_#S3`a$EF(XFdbRF|SL zu{XXqxi>L(awlgdYbJLh>qlNy(LJ$;YFKG#ZEbCCZ6C!ll7%cwCrc++BU>Zqkh%F! zJZtpdE?bWUw-LA1=fK~|zngzY|E@k4T~I7>EqRs{Fe`lsW)#b+^Q+oZ{VLkixG%F? z>%7pl+$4r&E^Uu>&wqz{CVt2~89yOE@jdxIfj)^m5u8exv+~Tu&nR?v zdXahBy>{NZ4qds|Wu@h&>8I_c@u&5s`K6hqour|qrKYK+g{KM7#?x9lY2)kUYPOe* zceT3rzA@f`+#T$abaQwLJc>J%y_wum@U!_?e=a{(+^CFEOj~r%!5Bn4WZq$PmX=-q z@eRl=ExW?{6!cBVt+2S*@QUNtBq%()6nWw0Gax9%I3IdJ`uyt~#;@|L`rE}XlUFmh zaCVt@k$3g<{P79mTksRwEBUKzP|dL5e%bZB^NH_U*Q>BsM=+0Y8U8%Z2P zG68r1?LR$!!U7e)`FV>9R~FArpYfjxpIm@$KcT*IgGK*U{{@CCjpwS*x=%I$2cXkW zvv|&y^%i%`vbua;YeBa!lYh|DONyxiIY~-KmvX z1Q0r>{=8^2YFZs3r!=y8e&>#BbD)DcTV+ggHFN~rE+Td_U@lylRe9pL<=+w@JWbXvS)?&dlRb+KRo{sbfm`R^yK5`rP3G@9Pg>uNdLwVOL|K zjZT+v$i*CQ@|44$_H({~Q(O@2_T4h+;p1Kn_nNs5Q$^xm)PP9Uc+B+L_p zy<)5{@6irg3?*$#U^JFyWQ-y=M}C&gd=3z&38W{vprvLcbOIOeDo8(o>4hsIaNl3> zK{5!8_DBgFh^NPVZ5I)OR@07G<~y!w`xm2@{gns8dDH-7aJX#%5@M5kxaQ_I$PE#@ zIU8X`y-F9QIA3X8&LWwijvC?`;mncBK{=^3TGd^|B5@#98JC({xHcfn;e}_RBb;Zj ztUll|SfR3}@%!(X1DVFip{=|DXS5xh6B#X4wckFOY(2=q zxhsc3nJLQPWo);t88i#`W|QnqftAvZ6uAhxS%)c-Uvo{)_!&Oc)`S&L_Jr-;L#khfIugC;YkEXyh78LH++egHDOFN#EF4t@7&b# z6gc&>^t9D}-TkOHl3icsgeVz*d6+!Vp2(-(@ZS@oy7@nu)8GzZOt~R@%??YRx)>>Y zHeIY(wrmNQ^)=Gh3W#+)<74ZZoXU$jx`Y1GD(+$(+L*(X0HcTl$b)C`FA^?K}l`iWTe-B?6 zSKsl$%~++3#PhZ`LjvU5zG+qWfZZR>m0s-N@2t0V_XD4UpJWO**I2vlDiIch@_Qjm=Hzi|` z$KU3qqOLcO9W+_A5^yy+4E6Ij-C$M}{+9nYFWQ6-gII4TNW8dYwI(PWYg4&LYYF3= zaBb*b5h3j)6}&$<2xnDe)^iaf_H?vqF*gikBH~xEn}97#qS~qhNKE1*;KT2hEDA+^ z(=(yVekDNDCOG?D!_n5;&1{s8S~Ys$iKh$x5LxZRCoeWztq~qh+kV|om%v5?Agljq z>(ez;o!VnJV7eLobGQG|&(!sx8-2BYSBwm3$f^_MvvT#S`w-a`Fjx}W8m##PpZc{N ze`M|*X5J&C{~KLdS7NF2M~*b?!;&l!3|cE@jPZ(&ca-AYWNeDEXy!J1Y>4gZx!>u~O7X{+Mpi-N;4qrrBF69+-PrcJm^zdZN_q>R&7 zO0-K-)LT+?M@lqjhnP9L8YV0O#bJm=Ex|*{Ch!|^0&e^ zO|OR6CgYZ-?!*wBJK;40tlyxxU)O`&ZbY+$en1@;!^fRgoAI0dSX8YZUT{*19V~?DSv+tzy#5gRzw&!|>XJJ3Ne>H31PU7XG3v`V0p;~^ zCZEVUCf@r<9QeII>%nz@G+cIby9RH0Cx@bEZHU4*f0V9|JS1_OKN+GybM=P^}KtX=Zz2++ZB15t(R(hqVe$Td>CRAw?RwDE!tN*z4haPTb(Xfg`{M( z!N{NG73SLF)oRWV?iJ+-ez(b;ng_HRgbF(SXI6W>)l;OGI?+lvMRIpSdDX5qf+3)t zYF-`LvhCZq5KNop6pN~n0+CD;dW&B<#$n;gq6kr5Mn>J>nAz?cf4@6=ApJO7I2w$G z=p%CvjJmQ)x4Lt~!kYH(6N{0zdG%&~Y<2bwK$zaqN8}%CYS#0)K@cKuw_MIC2X=|{ zC5A@C)Bs0acOB15ufb*iO+m$4z61pf{HM0Up#tEYHdH70^GM2+dbI{`)H+)HW#_?* zuueNC7-{uqKn$NN2 zVaufa(~iWvsGhvy@1Mw)(@>SSYtBpp=#P@cMYE^YJMAO^%Sw2f3d-1M{_z(<{gc?y zL^u6_F8t-%lvF<633I#^I+xu|Xg7Va7IX+Xt_5Tpj51n%cjmM*=dtjw{5paX_d_%U zaNfa3x|Q9J=+!MI6uV+RoZitYtJNd6mTaXV7uy}REA87Smbs<&4-cBW456@526i~vSxn0&Oh31b77E{rv;-W$+7cQ ztP>{+qpiHF_iTL~v%*(~*Ej)mYPM(J$_EV)pvZk@$K22kRJ>u8g`vp}BxbEY$*|wO z9^ZU;r0hUh2_bg}R%V%A>3Qmw5ke4tF`51TB*)h8S;C&(nV6)Q!I*7z7SI$HF4L`^GUN7cdUx;t!dsnTcL8z@v`}r~o{EWEuf;aNF9a0G~|T zOK-H3AxQh029w;U+QBQNx$mffPOLi0?%Jrh!WI81wZ%QG%yiuK*%`s1iFX+Ke9Rtr zZ zNf~07KjcPm;&l?>a8K}+AHbMWV&-aW{A96^o9!5*)}Qwinj2W*YJfjRl)h~d#V|aR zUayV;ERZx$C`&6NO{aDGmP7fllOs7ie|D-v((d;>>2S!hxZ&Gn$+St{9tnHh*TejuQjkxgxBMb`I>w)Jz`61z8Xctwg_^KL@$*wf5D`4jY1F7^N0wqM9~FV^e9W zvV)>v#Fk#mFYr{SOkZ5lp zl;^*1quQSS#qKrz4}m=~GdXG1t zl+SyOg2GkiW^bg4_^JJ!;dsJjUEY@X?ilS`Ngd$;cSubiDq9A)8H8r|#hEDXY3wCM zW%U<2Y0vjT{r2k9vRYDToWbMY6E1|JVy)JHIcTs3E`dqTqu?keugN%~{PviJH^eyp(6G9_JD zrrc^g|AbupK<2>M%l|0Nk9)8|xbM?%hlhiC&bfl#cI7JG^M@_1QJJai1*mQ6VYJX1Z@MZu5Fwn2vScvoJQT!CgQ~2Kk&=6_~^icHj7M^f( z?E7q3a&AyxehzJ$ozK9VEcE)&>-aqfF4dBRD{#{~|9nFSxw+_hY(8ZJVCjFHPdx1l zU?S!ZwPo`B=g*=zAO0+!sp$O9x;}|nP!~8ofV;RyRB|TT=sZmG1=AGjNG^l9EBNNC zo{~boJ-NS~?e&do=k>*CK0dmCh>VL&BBv-g;i`$@ra}$Lvl9r*VKA+b8dnlio{JVy z3H3_Jp**b69#*AC)S)98^hCA>m;Wg^m3a;lYhD{v}HZq+3>fyz5!s zQ;`UI(4V?>UuF@;0? zw}t5=RN}*Bl&nUpXsbZFb-w8>zEx1+j_(y*viShVOjTS-VM_-s4oe0eV;r9hi zc_CEQCscJ3bYIGTA^z7MSQGta0P zw#4Nc{OUJJe*|M_iiA+8^Ap3Sfk7ZTf2R-CAoHGQGh(yo{hNymhZRBbFzd!EBh%RX4}ymEN8u4SM}O1+LcdXihLQ$>`p3WU z%twWi#Fa8uo9u~u<(8o^876ka$&$DwFihD!BKZfRLD}1q96rE{;pm{RL$d?pH}9dZ z^sV-RBjXpe_u2X1@0`pgFwrlp(WE%o|6uw1uL}166S@B{<;4G|XY2ov6K^yGk%jgOQPjL5d_0F_Bldw;$Al&2tC+q$0E)?!M06t_L^D=-)>HDxKC*)%*_d+h=4X zg-bYiijq0I6=?gFA^aq+jc1_kr7fwvrl4t08~%{ih;5o}ApbVH#F^@7o4l#U{5c)X z!R;G2&_;uf8@TKnSMbGDQ$w-D&n$OSF~CR6)i|=PO)eDEMV8q;a9M3#_GrroVaY*552ft`Y3 z3|H63@k!eacY*H5Tg|*I%5CAB@0Kvc@`k>edRS@AS=D5WY1-E$f(g8B7!}=K=lcVD z04>4t`ZpdAle{P~RD0Qo?)yF;S#3EXApAo{2stTnK#5BOW&b!TJiA5mm=;A}ADT${ z<#l>yccwS-4aOPWWhdHNnu4$|ye*7xqISRrm^mVazr?#AfQNpLW(F!V}0|A zt1dL2Tf_`QiF^P*T)Ao-D`4u>;W|;W*aAzprr^i=ve`pD@v`L9`7<{{^=FY0{Gwa= z7sKY7bfW_(Ok1hti&2xu5Rt*oVonTz@70CA=H?oz_$?GAO7tgP`wOk=!E5~Xd})VZ zl<6BsesgoZGq=^VZw<@{h8S7v`azwC;>4S}3S`yCc1-Z^bwb>i+E{&kkGag)!z|<= z!)aEt?SAq#L^j@__pnW{6U#`)Od(>hX3Q{H7&RUXQ~ZD5Nrj6}zvzRwa)NC;W9N;K zc;I|J(rRAlPk*4^9f5oYvsj3vk4&J9OoS!V7oQ@{AkRpmNSA5QrAt*NnOUU%C2X5y zFpb`3=rWDJP6u_?)K6GD=6LM&q0Eyh^BKZ0tjDfBT(L~8W>#(0&PT6cb}ezPls-|h zQLWOhW3QCEv~Q8SQT?sP*Z3{`Q%-WJ_LAnM04V#^1PHlaIPys%EMZ(McqQdlmtD%{ zl)<`I^h$TNXslhK`v&WmIV`qa^1Qh9sNAi5Jq!7&x`&0DrG4$h-cDneO&MHGRo7I% zbW}BE*MR03BhO<=Fo}2ZT6GS3nc73(Lp_Z|~c#?sCZUB}rKTx6`x#pzshWbN5n z*p;2E<(;gSe=GKms%V>B(_S_W)DN7#c3yHn8>Rc27J8c9%_`(H&0%S;phK4aWV4iS zU@c!adg``v)#A^>c_BkOOTLdliqaX$)Qj7$VD2T8_k49`4FvjhRGUBh79oz4x zC(I10sJ8};XtxHHh~2L6>LpS(iX36pD;{WQfT2Am7&|3N1c)R^ zpvk0MFVJdw$WNhQUl4z>mcqmdmY-1`YZ!K*97ej0_kp+!i0J$Q8cW4R?WW9c(ITFM zwu$9MI0ixplwfuq7}ARap%C31Fwu{LK8@_oXC!z`G6b%N=Bzk2+lL>AHiA#r2z5;= z0WhOK9ZUO06iG62Q_hVXYZ_z)qTqQ%^@>jwoY*a0F`*L0~# z>RF^7qBW--RL8q>0BsgB><}>+aK4l%=#Bm8cte6mKAE6}c< z)HSn183{~IMT^>m`ZpznD2fXow58YYMkwEJEknzjHI8N(2orBuW41w7P6Pss@<~{q z;fU5AwZ2$6kvSTg%ol`k6YbZ`o-`}EP$q;KLli-N9zitT1vKPDBwp`jFkCiFl*=D? zyxS9U|Dt?5&4f86$C>MGPyD7$Oy5+X3`6chQQ~}8jDjpT!g`yG1vgB)$r+wIOC~yf z>NZY>JZ>_H!PxU5YXc0EF*yR}G9s%@<)SLS-;~1mA`Nj*E$#?DbZv^L8xxc@tCc@7 zRIY|1wTu|2)$bAue+CjF5esL_va~eVtQ&nbA9eKs>(snn7HVM1GM(q!P(gIt7XiU>Ow=O7SB2Ky|WQ^&9dE-D@UY^+xt?F!Ab zgw`p`upslo>|3HQ59ZpUU!ZY0npxiGwza#tnz%+D9%pmZvWiJE-49K2n0E+^%YtJ; zCl${IS^P7LX$r>)h(vnXtsrA@A0}|eL~#|;k}J?OE>Y-x>&S1T=Pd#P22M-hh^wUPk(mp)QrB z+4-96Y#)h}YU^w4$3)z+o5_w1=Pt!XG?DFM{{zqCXW2kfclwZi7>f~01vyPM8bZuM ze%Oh#rbobGH(_xq6Q?9m_pX;s*HO_@vk`0J91 zhWeBmaSoX9+(<8B;C%JVcIuq}j)zj|%QY4q0a&S4&ZM=@hRQXz9f<>4H;|v2k9Nv( zxf@t^+lyQ*J#vSpKfJ`=y}~oL8i;**hsu9GCo(q|-%S{@9pAXyLoOZ)XxqEW2j$wA!fe(RK{nY*On<+foOg|e$O-0PkPSXh| zui)M_^{@Mw-^pn9erk;3wE&eneguUpci6gnM1|CwidH_?gtHjCGxsCo3Cb*< z?kt{hjF>4)^riWBxVuO(Nfj*gzu(?pI`-CV11ks*DZh+!2<)I@zYci*2jn=kvfEqB z;H%-|c?aIZpU)rmDpNPVD?f8`B}fpzJvkc5iT-x5URlM3FYy^yi{AeeQ~KZi-v5_O ziH)6|`Tt-_BV1O3s1mCyOMhL1IVIzRCn|SPz(v8pRr^_Bf+C_Q#UCP~0wjV213XUV z*+%ngBArl*#7DMp$?>blMoFxV3&laLapNB_i;Bjnu}vN`mwgEKt{_mFHUO_%1_p24 zwHj)7l^S*WYHx7Z+kD4h=P}}Nd@FpVq5v{h#PR>j=#5~8cI)k?^FOpyoOwhkZb!X{UfU>XDd{U{NSG`Ycwc#- zEE13#?Um5+aOMFNgHLMf!haxUzM_@%cOIY1T-jW2KFHA1iQ+XS0inF#xt)$awWB}S zevwoc4>oi}7pKXZwCcA+NQhd7S^+O5FJ!GF2{!Rf)9fcn`oDw|3(~E)byw2L?|j3N z*!THKQ@opiF%nMe z;5pg0P^5sVNLeJ2GGxh8~_LKAHl(WfjILx+#>76ROfl;RKYkgnvM6a0B6#CSnV zP)YphGlEKjpGiI_%Yeu*GUsTU7{Z&!_=8yx93ZhCt9Ff>(xT1il@;vr&>cBdIvXmNP=%pVrj{$@g7=lutc9wF<;S9 zk~187L^b3FCzySX)L-Q3B!#tLAi;G}5T{u-Db=tUMj*LFNy{&lP5^3z(YGTlh_w|Zq z8yQSv`uMikmsq_K(8s-NLXA1esW?BCo~Fsp&Pq@DGI2Od4y0836!qlnW}nk>_LPWe zcmSaD(%L`uZFqy_-pQI<1p{J%^9-YX1K|uHkqP3G)$Mi&(9m}Hxv9w;@*Tw&jw6$$ zag8?Y@D}tAk4Ww}$R>T<{yxuAVdhls?$VVGkY z-lubeo1mMe%Z#e&!#@9~dp+))f@*ehEI&c*wX4K9z+~v`Co~Z=xGhOK>GFJgH9k3a zp{RKLF9sya0M~$*%feZG;duLSEadO)H6!GQPBfF_5YaYIaZJKXNcCv7@Hk|MEvYFQ zkqwmAK%(3^Q1k)&bA1RtJ+nF?#xR*qM? z8NP(E#AjsM7fn7V-;kRHV~3H2&Bpc+Y#pz7oO+~rta_yNZ2h+IjQh^y)$r5HrRXC{ zpS(JLd4%vR>XzE2^(XYF^e6SFbx0IQq&ZP}wEBqo&hb%qn>;&ydIbL{yiQ`6NI#)@ zRNJ64NbXCoo8mBy_fhF3)0k*GvHrMw#QUh#CD}{9n-UmDI3_p=e^hv!V;=9+rTHah z(INaAj}oXt8`Ti>0Dp`8Vg40SBm)4A!p?`BHa!UYp77To7M){5VcZg<2is{0Grw9u zS5F+F<-Vf%=c{P7?+af42}K@n!%-t;X;)g=(3%Cd+3#EHr!DIqVcCO!xHWH`d;WuH zp2zC*?oyGNlHGV0Q`ynC{d40s!Hzb$p~rKdQZcXfe*eCRkfxj3x%kmhchbu(W$YG# zPVJt}S=mv-x#uAsH-SN_T*D66AJ~thXoKO1MgZ zzy9QQe7o!>m3OCWP>cI+x#*#W^DKM&jzRhy!SD48r8()be?rsG(X`W7xYy(_mgmdn z62mOa+gEZ}2-6)=)Y1sBJA3Z*r!tX-i%XGldWYD5G}ctWvKS+ihJxo_B$ z1=-^k!j~%V{?~^{H~BM)F~AEW+TMC4`x8Unz72=HNayAg)4Rg^YzAA-8Gq`!!rE?W zl=*j8IV-RsSYN2^d}Eo)3tG>!$9gVSWbtK4Bi;s)asb6{uAUqQcFh=1MzcQTC?FP% zaf!mUWt^&AG0@g z??2;Gs^(Tr%^DceoX${A&W=+fS5BOdy(u|Q=Fobg?_rI#h0($q4|kktZYeo`f;Jo# zG(|V~78t)9QMfrf6n5@A!q@Vu@GLD5ECuS~?{{zp(;oS<{#Yr$M5ailLQjZvQ8#FR z9(e8*yf`$LzIh1&Y44rDNbc7O+uoCr(-buuF`URHoiZS|4simzVY$;|i>wzwZr**<6%=8oXUq#({Z3b0UB=ESXwbCsF=B15|H2s$N}X0o*~)U`jE7ZK z-%!|6$|@$b+#y;12!@*L*=WL+l(Cl+@~q6iqB~yYql8!{(Ov7Ebq5 zp1!m>>Fzc(XO+vOw3so;nu0SlbSSg^w@WO4nJwXKF3%RYPDCi(CQouz5xNhsB3|_a z2r=#Yd>-f3MqHg86#*rO?FkZmBYeV&HJcqHOf`~x?pJ4piKR8`6`bj zX;e-rj;X;=9r|ZFUry8ul8u%8coS38=UuVdtBh!(2XXu{xG`@z!jFn;h&6y-snt?-Pjy_r;OfxH&FNm z_-prlLSwwm7*x&q&+MxhDt3bnNR~v6;hJthpB4RwFq^7InL3Wp0*r#45=9M=rOV6cu2t>a4L-xtmRJ4=!CAcv}!-VnI+DisU#W@(|umAv1UxZ9!DKf($87)$va zAwlGqg@IA1rIB7Vpa7PZT44>}7aUhM@N}s3m}$?6;wP4K@*?__9h76bQ zP=%!hVY^TG04W6j-F<=3@6Ninl>4FqB)Oim;g993x;zx&L_b}Cs%_osnd;M4!Rl;S z;JC73CdiWD@HD?{s1Y0zyPVOIV`^!=k+mx#m_Ot}LcZXjJ8d?26)h+56j&%3siAkh zwfKP-Mm3{uG_cxTJs?R*WqdE+amADi(z;myup%R_Px!I&(coD8{ zOKF@PgO<7IQ9>d9vwZo+O_Oxc*30DUp0wp5; z!K>q})aQaCv*)e`wk|K}G&j?e^~aY)U#7NZ&riFH960tj4j^U3QT~#40p*!h=D_B` zI||ZXY%q_pVGwRPs?n$j*GXu8Hz%wb%Le+ul`ocL2g)BfySynqfE1d8Ccfztm%)+Q z2xhqp%1!mJY!g2eN(~gU=p@EI#Wq8Bd;FaFrc?Fgv%h3}g?f}8J~2jd*@lT@w&v8R z7Kuq6=@b)5IgksP$z@@go%(22{YuVhr@0)@BtCz4fjIe#jKx26A~Kb*>eI5J*A>dK zfl)B<7;+_{@UW9{$T;u^wr-8s2Gi`Q$92$Wa`eJgm@#zZmrWcfOL7mJU9swiwv%~SuE0HJMjxB zy?u>ekO59{9%C45)MfB9D2Q=YEPOuSOQ|;kl=POV!#+}@v;z#)>%ts46M@-#c_V}B&HHX6!)|J?&s$cg&Z#m-hNU&uS|B9fusA_SYD4JZ|o)w#t{gSGQxhiC3YqjGQRe zQyTERxz3vGg*b=z>-v<24v)4*DV-jV5uPMhoLsB;BDVPw*`HN-w08No3zP$2Z%cX1 zWYp8I>l=b)o~}C(wf;r{X5E$&kKm0jH;$H@s^OA$zMJjl;C6yx-2fmcHKJyo@#>;Q zi7O3NM$t@#0@;`nc#_lBLukQZf}18n!pHiK-%)oH^;IFWn>uFLVZ#6`jGQW=H135B zKJmEAAXL-s8|#;YS02Rt?8Vn(dKo~^j1HgT0lTe!crv!khV?W=heRGdPFOV)pC%Bj zn%21(xroF`vzznKDFd0TfN#=$vH8{^d>Gm57mu}|a{rq{B9Zm`dTR{zH1pvr-by`| z7dO!|BhG8li5}tZkMrdCgcPOrJhPsI7ikZc9$X;SJ?m9`tU@SbRIt{xF+F1p?sHVJ z9)Ihf@?-b_!>=t21V3-kcN`5Rf=|7;-@v_1^}WHGJmzW} zDrZ_ImUY?l)cl)1xI3&`ri<(LF&efUEX}(%dz@iojU%!^dD%Ri&FxQX`CXpG^33Ex zU!(9cJKr3faMRIhUo-@i6q92JiW{JR*;Eh0a$SKDR6$!pFkm3Cof;M*U|;zjG1Alk z<7%BB(nH`=4IA(zj?_9hWmd0zI2YAq@Tl|p26245$%pkDEadwee_PpY5>p6kDfJo* zx$qm_QumZ?*4|m~@f`>q|BVjAR_H817sIm)dNUdXC)D<5$RzQz%M|GQfACm zzYHK=no8+x)2EquM)0;OZ)wg}W2BWf=oW09@V>tr zoz2Y5e?QUr1i!gFHR=}?WW4Pc6|F8G25|0G7bI|a$=n&ez{FeyDBOxx$5Lp;s^)%q z@?OQEQND`6be7G6{a1=cAmkDH(9$-wy6&_{A~Xnpye+|QR3pwqBuYF&N8F8LHA60; zK|ZD{a3*6}q-52#42_jzkdr-NK-8|-eddDc!+2TCi3GMk44#5H*0Vx4fY$(h3V&KD zHc0bMl^BfZc*5Dy}HV=d|}jP3&~7wrq3Wd=Dl zFUiU%7Vs)b&3;!hb4J1*czbxB6z-6qd@ZfXi8I_0cuoxlW!H_E4;L|4lhCpVTz}WE z$#_&bY54oK>mNWuHW)jumAbDNEV6PEMBDa}R_)g?l-G&hPlp^vOm%DV^BWVm{+;HRpAvzb6 zn^NZ^n^=!Z|DG}y8xUE5eLWtk(v$WiqsuZVl{#xy zXuD}=(8^=);eU_lR#&hxuNv0l0|!jjDyr&NaG=>j#z*WbW<#utY(P7h41B(u`8WlZ zaK?nA&Dh?Ce_DEjhn5%{d~zy5#1*FTfVS`k@m(9YVV8`aR4UnY>cOcDcDf^|)cg*# z;J{F~_k0TbF`%x$gfguaY@h46@%oNww{t%>}xkSgXFW&z~$A6?|4xz_|WTvPm$%Z8nGiT9~ z;f()r4p(XC*Tv=t&zhYPqNZ7FCAO0+{>bTOi6nU_W|$xxk}CZ$h)``ygR9vR%dMzl z>h&XD?XU-ptm2V7ys8{`w4D*fjODBIXtE0=9}Lik&LPieLpzG{;!w zCNaPj<_$vo+9hA@)LQ>#w~CvG;X$`*$?1Oea-Fl+7>PX`V zj`whiTYL0YXIFjKI`Ru3Y$KSnRj{H~R89{2&zw+q!snIm4{1+Ii zC(rGFx;_8zVIBXMw`Ufv|9|ZVrsf8LudsFjaU*8Us-vE zfi6hlrN+h6{urSkrDCF>C18Ou38`=75fbj_Lj~?rQX`{>GLrM7=RtAjW@!L=rZ2K$ zj$&rNcH`Y0G;&lds#Mgm3so9o9j@L=#lpz!K*lG2VQ(|0wvk%{&CUti(cX!Ps^j93o8>P5{62M8tY z5FPp#`AEtvr4IE^z=%rKEJ*~$T1fLqc@oLqjY>{Cowq@m$9ngVkcele=V)lH`Q?ch z@@$WJBKA?lW}9g4rX2*X>+nb~=#|G4?J+Wa?_YZpAv3cwAtj9t2b+*I-lZnV%4r-By(qpfusecgh$;_zOFRRD@T0VCk4+7jV9_gCx@p!y=;~|ElT+xf3P+^xF%HeJ?oUWZA0x)-dLsL zMKkI+pcR;6YdaA>Pkh!B@7Q1}BJQ^~z7;{V|;^r?cy|2CxKcJUF$rN!l`L6+s5{m@Efbejm>kia1EQLtJ7$n#{@MDqzv4dF9C86O1@o6cKDn)4g>}FD2tN^P1i*T;93N0{!eA)0fS^ zPz(G9TIq_|3h#tIM73|#9^RcT$8J((a?3z8=yM!Q2M|dLh4Y4slap?sozTHpG`_%7 z6Hh|yHJ*T2T{QIK6+pty$FOqqPhDH{c$VsK%#_>|&G;ORBU;DO7Y}a3#ztHP|BmpO zs(V3KfAF#au8S!;w{Bb^h(;&Rm|FdKVq5=z5po=L<*a*nQNkN>>tNwD9DKBO{fUtf zFwrWoEK4kU;2F1r23V2U$Cg;z0+PK*U$Z0&95^1T?}_Xlyex}pwqy=T)XH+LiEaOj zvUiU0CF=G*PoK7J+qQk$JZ;;yZFm3Lwr$(CZQGplymKeHGr997Z?gYbSyh!(?Y*m# zTKIfNUFribNjgSt>O(tap7-rLa&QR1#|Rx#GfDB|9S?cR2+>DH9g-FyuY%zMdi0Pc z`^EJ$8FW$!NFbN`1^2@2l-yJ~$h;^&l~F_`67NzKMSbT;(uaP{5rIYE4%smZWs=z- zx<-T+>6y1CQg9YgDkeCIv{NjN1<;H$-s89jb_#bFI>~>chR(@zBY`-#dzBU+yC9SX z@R~aub zr}jo*tun{b?>6bijw%GVS5lL1ve8RS|6?&hGm*#7&VDOM|Mpaj0Da}xKe}?cS?c0x za*sgAE9%Pwz|b~cq2(>T?^PzSD-~(|{cXpaqys79hFbklvAe?(`|%+B$%V83UCx*R z<-AKD{p21m3*2-h;MVZGIubB-gfJY)vo3+b1Mq>ArUo~W{boX_1E7|>f& z10&1aKR_(9d4KI0SxlDSo5lJ=)G{Siui$C+9(coii&FvZca>wIEA0JUv=T4k)hw=w zOK&#U&7g<>`LGIEFoROhP2YjeJFY`6<17bfU2ze0`Q)I&u~WQ~d7Vy>b{7X`7eI09 zej)`?UOSnmTuhaK=aI>S@3d(1eEpu;@k;Go3QPRv^_cl7?kfhhtUgM#rToi3j`6kZ zMy=Y4GKK8E3cC#l=KFc~{NQ=X!ES#i05klm)>U!6I7(kt%+C(>0=B=}T7kFD)*tIk zj4ktq;*tl@?c4h!C4Qdu&JBM3b^FCV7Z1Ft&wF)zeOt~p&y5w^J7-iWsr)Ml#at@ygVGMx_Yd*ea&hHcrHK%^Yw)7zZ_Pdng5e2 zPefC=Yd=qeB>{M_GQJ(wvY0F)m@IC}b*a=ANRelSJuwBVa-LuBHAY$HlbREQ4@Qyq zCf$X6C`$)Lu~_8B&*brKTgNp$cpBxhe4XfisbTG8VqG8RA9Mi#Nh8ZT?2Q#xrrB(~ z5uHqjFP|nxt))FTm2sRtmd6`zY(9Ti1nFY8AY? z$mjJ|<6bgzvRnBg6AqUzvyOY0KTxzNU(ROI#q&Q+E_T;+TPDNMsqRmPg=crOwPk8V z`q>5NUgp(0>3Ruei$+meUTvl=wchAjT!xqdWhqOJG)cIYLW285qwH0>%?Ze1fQWrL z6KboKSdAWe$IMe{C1VN88U!+ES0mt~O%A^poHA%~Q{o})reBr{5Gf)r#8cFzRKy~J z1tb)KDs~^nXQz}GZOwzv!=5!iMlX_3GbPbFn6^c3Dqj=6#0wumaH_q=1dWi7>aufKYCx?;usBgtu^z5TAhc`z#hd&A^MbYzc z3!-uJGG`?s6bc%lFzXp`d4XkJp)h$Vtx2wX+GGR}S5jA2m!&?B*TK}9vA8XywyQ0d zLCzO_&NVi5I}C}uUF}}cOAnjF+Ad%%O|~>i=QEvu_S&d)$Klm`^L>8*Md7IQ=|==9 z^HN>l33gS%%&cyBOm%Ik+k4#-i;a1SjY?hV3FQ?EN&Ud^114YsQNkNA6k-SNkfoKFz%_+U`x#PwuDEX+ zhqtg%tI5LRe>djl?%Eqbhqrndz>7jdXvaGXUrut`epA=<_0UgRnC1&!q4E0N2pP)Z zwc!PgY_+a+eS>Ru`ht_Q zix@YwTLv{T&SLx>k>t)?Ra8W;n!Nsjsk2&FU{!*;I=$fvzouX9qO=DCye-PB=+RcSQ+|zS19|T53AeC5KrwN;7kN?`?fd18eV~r>u}^6Q$NMpU zhnrGKzB(%k5GJEteW`-wJD`fxor56EN%GM1BF64?zI|^H9HFn=aeaTi$E;cNE7Mb( zyHQiMq+mC(BYnNd+$eh1l(MNRlYVqm;cMd>8b6m^TJ)}GCob*}c~byo@YB_TO+n7Y zwCekV=We82v~www)*%b-ZC`Z0nH8C)U$fq;8_c))19me&+qs~&P5Z1zgVA6$DZy@L z|Mv{jnaew&o;VdyvKfkHrmNH67`;v=O=QYIqv-Z4YL~-P-4CL$)*MCHU!7=vpgnl1 z^P4!Vq?)JIm5K>PEEW^Ap<$eFFsc-^blZPBB@u6ZB^5~wV-n6fw^@gg-+kvJ#vga6 z5lB<{8~-zpNy)Q3URMZ+0~B6ix7anzUv$1Kt+^g5m=!~ZQd_HT7K^($)wRAv1QSD6 z|5W*Oew2VBhN(6%X+ydBG2Z16u|l%&(oy%jrdnyQy+y-cHuWLR6+7F2z0n%#rm$Y& zJ#->fY5e@RW;dHsV;N*L4EihcX&BlEY#^K$!v=T-El)QR7i?&s3Pi}R6vOR=JG-#G z?GldX!J-HD1~em@P35Z%6o`gz2;4~CS3#d=h*eX=&-jnq(HW^vhw2q&HXaMHGZ?z( zP$zVLw0rt-5`#P`T8G8;r~UHwwe5|-U{%Y^O7>`GYu_}@(>8~EQ|rz72h)O1=BaCo zt(WJH?gQ9<-t=ujMA`thk$kAa5=RA2*mEmMaJ{1LIdh#rVs+nqqN)Cb zYGp15e`pR*=3(1fs7*L0sr7%HY_9H3aY$SDsXCUKa1C?LAO(o=lYrJ2LYjL zX1;#lyH<#pySx9o7<^`P!L@u)~yVw9LiKCI3k^hYULoxIdB_(maqQ@*ZV+M$TAV%~*L_Dp=QOfntu+Ch zKGHM4(8z{(V&lRU)~)0xGUO+=kZw5k|MX}6-}#mQH)fCVpNuFg)Bhs+{r{u*{_zX{ zKfN>FkWNaX%XZ3JEv_XCTk2dNlH^u|goHr^ab%VH=ok4V5jV>haFIJ4KfcpHIS*M6S=Ia9s>(In zRhlg}TSaaxK}bTGZt>z;H`@c?bY5M1okQ<+@n1Hv_9y2ZusJ62u1 z#uG&CRVS3G39lX?_01R1q;t4Krv4qQAg}$|J_Df95m1>hT_9F!mdvQL(YlMAD+_th z6OrimMU?@dv@RN^iL0AmI}c#2YF%33hCP6mH78R$PUGRWG-Cxe)tq~{O}`T*05vfZ z1SE#IviBKn06cZQj|iWLuNBDmlmArCm**YeL!{Y*ZlKYo_Snr`Es0FB>+ z?Qq0AHeL&bVM&10tiGNDwvMwh5mt}5!k5CtPx$d3;q7}`*-wHuo-)OCODpQmy(y5o zOQw(JMh_iZE^Jq%bW>BWCEkhV0#;aln*bBLC=xP^5|<4`3Ui6&5HK|xjiRbW-)-*+ zGevXWfkx&Bk};CGk92Uq#+i3Pg@q2b6(s86NxPOho*jh;>2!K4@FY#gV@~nbecB=` z$_F!`eOw8SzBHi{Xbruy1Q7*cLu?=}f2>P-UkyQ6BB*S|0uI>^?w7W@J?r2{$~?2f z-_LYA`TJdUz2q`58eX$Kp1T|e?x%nFTDV;WFD@X+5mjDy4|!jJyM3M@k{}$tuL7E} zZnCEPJ+o}P_tpJ-V;KZ)vG*o>P8#{&0RPA1OOE`mDdlCl|NCe6S zt-wT^=;LlXVNhRUz!Ez_rak_;5PggocubEeDvG3F41@_l}?qJ?2lm@ z0PlcEMmQ;gup>16M=gdSEH$SAa`w)f{ULx4>ZVU;wyuVI9QwUqRY^42Php;Ix;v-s z0qWTkZ!*@?QOQekLs#kG(qhwx$;h|2zV&>gCG=1#{=W3fVbRCV@`KcMzev~9jk3u4 zhw#mQX>qBd1m3zPoVU(ijSo!}HlwafRqi1T!@1{jnBN`wWkeEeR4V8P0^@@sdQQn{%phhdV3@_pJr<1Q2-l6|t-9!moNH zOO-=pd1xm5QvLmfDIKi3J!RI3h&3^`iG(#c6KH15Qd1Q0={$2%7KhfMJrk}^FAyIM zNd9e#c;Ca@1N*b#Cx!cHq*etAZCmk#n%IB~yfQ+_?>FJ{&zX!{VX9B^&>PNAV%%!b z0as)BSdwMO(wc7XX-CcXW_T~hCV}r_m}<1%6`byOCdKcFft2`L&`|1zJ*Lnee1EB& z(1{eA{*yhsI+*X_J!ZHZA0#5*@jU=St2`LKFA9+d69?VFk{KGn8TgZT=*vME7uKx;DQGwXz{hYnsA~CN0Km`t5ilDQ( z>l-Ru=&j2sS!Yx$oP%50FF2ImNVe6RAa5L<-E6W~=Fl#jY*!)F(39+@v6-TQ1~xa7 zSYe-H(o6f^oNU?npGKr?S$}?q)u}y7xTKE$qw(LXPv9M$)HvUIp*z^MfB^uM9p!gq}XI-dgOC32sBaxf$2rI(UAWeDi+UzIKV&dhZq=ht1IY0nx1= zwrDhJ{<;>@w1X0ZO(PcsTM{Z4BTeNp1Qt$hMjtn{2?vkfVKml}!lCzuqjK*yl~~os z3ZwE^{uQFq!>OnoHV=A<@p00}Mhc*>e`1{=&#vmXbpVL=})H0_MxfJ~bI_X3CXk$kWI_#uWn zROr|som`B+1P+-)YOnsMStQRk*a4K@Wd;KnwPApMBdC1-L!drMC?bvzGA7**8E%Lp z#;`s`D7b1r0$gCAK0>HJizwcxelOzb4$}Kk@Yq*9K~3o2Y3RW2uKvSroOit{IiSa3 zjT_=wY8Vd#;Tf9K_=`ACjyy5e2RA3m7SG(w3%^Z^KefwShJX%mp%)7e9LsE+ipx6x zl5{i!+L7`JPLV~HYSdaUtCSGaokU#G;p|o1CC;F zm_CF<8zI_+eMfsW!9txbQ>XKI`E2lk%n{=viWV8nNAjG8pi$o5l)Y?XnW(VRchVc(fvB183=y4yUN#} z>!H>sk*afGa3BW;;z6b3D#1bJt8k3={o>$k{l~`@HOcZP0%8FT!!={2rC1l=_`H!g z^iB8s89|W|XXP{$LfwjbF&Am9G_HW?091@gcui0GEIq<#%jpi? zOR>J%bfd&p6&aPhnNWI(q75iGWM`7)=$%og!@kn-%I%+t4mN*ZQ^*H40o=5KSmWdj z&$RAYyn+5jBN$Hr$}l%p6b3#cpTECx>(L(2?pe}ejRn`R3V)a#;!q0ko3pebN)R^S>I16@osIHDW)mG9B&rRq5iSHDCO*cDO0>vr z(LZ}Vvp#wG2uU=`R05VnGJ|(F@H`TmO#?^Wy?jA2;SBc(|6zzF!siuRB_%Qa!;R25 zsaGib3YBC?ipE*mrPIxhQ4M^o%2?u6;w!=&nLdM_+zPEq{!I^DecnBRd)zBJ)N1oW zXR=34L{=v-d;CoXW{G#vc3hyGia7AU04?^8^q*-2CVVFQ$2X(k&bbT;)MFHP;zU9p z05(gYGb#5Pi$>Jqwt&raXf_G-NLX@BJdp>&8QHmHy?iw>$?J;uZZk>FXL#noC#rd2 z-lHK|UEL+b2j+XPjhpIta`WrG;2CkeG5j%6+n;Y0BT}Wa>j^piZ!M#y77a_2YHJ3^ ztE|tu=Q=)d`UQFn$YG=dQK?#Ezaj+YmgeT`79Z3&3 zN>;e*8#a(V4ZX3H)x>KTl2QkmxH%g1?B~*1MU##+Tau}#sXzVcdv>#WI{(P|_{1+S z6K~grvA1E?P~Da<=EpOPnG1GCKb^VWnFMhO2c)I1&ZVvS&()DlOAc0ZT)3x1rnsfN z*PQ9n>E`(&_LS6zJ^|K8caXs`56vy%YZ1oEE06#zuU(h5-`ly(OeH3)0;)Iy{_(d0 zWBH-r6tW*5+UE=WqISmInRJXUfo5f>uxfGz^_A_o;c%R5SJMf&m~btNAvd`T^>5$7 zUcPKu!>&dPgwSUQXZzs*z|3uv(^}dXxtuhoaLQeiXcgqMAFrnfvU=(#GJIN~B;a4-`&y z0s4Ne=8#|ZI7CU(`6Bf_y41A0qT$4xCCI-e0s5F8GMX2sbmNRo={mBf=2kCaH2WtJ45l!%uSgdNP_Cj4|{YQeoM^ zG|A#1oqlKNN!MNyb)3>QL%T?H9BPl#Ij1yB?HFIyUlMIyF!;NXgJ zJ57qi!$PVcAtwYNr4C$Aio0@M(yVoorPDs%_r_#}z)W8+_Lv#k-wn$Q4P|`Wf4%d6 z&&~E$8^dBIESb;#Y6kR7$UU^YcCbXd6sogSCGhvFK8(B)JK=gKR_9;X9oZldJq;%@ zizkp{jFYO+)%=xct0tvl^t&+VBdxS%LFerPLMNQUy@_Mq!W3F9jdnSvpCz=Ni;1>X zk%$CWdg)MCC4F9U8B7ne#1_SSY$Q^!QI8+!C+G0Pkwq>J4 z*V}skPV^t?;;~vxeNxCnGl5UsR^B~Kq4EZjLe(Jh;8`SzJed-eaHa_gmIwg{4`3AQ zAGE5++l)FN3DTo`!+S$O{fD!NJ6{jV9|4S`J>4fH{v52a^zzjB!8Ry~^XjtL?VifzyHpXZxL|TM6TV zc{czJ2RV~kbh>DFb*`|2Tu`xqcwAYm&ik*O`!8zpi{Dg>ix0YUdjJcNXOhd#}OEz|WO#p`Uu8$L2upZBp+ajuBv!;9r4&xSY%O+0_R9etG5os&6_qn^m7LF5>)WC4XUlk z2I7hW0p%idxoR!)EYYgxT^?X#AN?_rXT3`>5|T*RatIWYQU*9SLP$AylE{g1diZ&E zjHU~{2fh*&=`VAxusL_b_+~_~*DXoD%^nxaOR+VY9 zQ%;;)7#l1nOC>ozPec4YwfLMGQ5BRM0j^JxK?{2mMSHKOA^t4@6QK!hMW)}nS-5=+~lF_Tt>U*F}7dJ8$pzr<2 z3B?JI@@6)GBdRhkk02%8mDGiTxy6C7GIB@M0R2Nqx@9BEHf*F6zAICxHe?8VoI@7mBz1cgEmnO+TAmV>k7Y`A^FN>1Nj|$dceW4B_4UWbRvNKVG6&{v zeO4AMpX5t#V0<|>N6?0#Q*TcBjW8|;9;GDnhDlVYDiSPdk|M%}IvF+^hDuGx*#e^} z`?lIBy_KHoHc4l=Rw6fgl;h%^BW0tfX`}Pdk2B@{8j>WK!39!XXMn{5YNSL7VKXw; z_+ELpF9iIa&{*GK7g5Pg3QJF!DgC&s?CZhkYd;#s7Me1M2+d^DE!dC{fh{nMeQNe! zz^suPvM&V&@y;^Jlkgi(oJ+N<{8i}f3{4YB!|x_d`DqSi9zUCZ=jB!4O9jq2NB+r35;Z>O}om;8G zr*F8v>b`a0^{qXPuH}uY!+K97XCoA8>57d5qau}7#MxNa46iO^ivKCN4V$u#N-S(! z;O4rNxC@UVpr^fq^SFK1EU^WIgF1m+jm6$m`Pj_R{*w*uakebW9B;W7YCPGn!=dt# zgMV?sy$({zmKRlXsF$Tq(P1gAY*AH!G*uhwoHGfZn+)HHX85IMU$Je`2w4FHIr zhN6|Iu_li~xg;;H;pfWOIUgCrlk8>j)VRXLra1!a4@P>xLu)iOtIY!Q?_JIo(G*Nr zmb?*f$SYWuXaOxxg%vQRqrjV@boi}YPizn3Aq|7-wu|Uf5TNUes-9n$W78ZD!0rjm z&A>0%r1=Ahw{eN;8Sr>7Kmkt)T?s*awj3kb&dfYX(x~oTG-ncvfT}XfYpmAeA~v+% zgvz~~{Zm(VHXIv$x~N;^&Jy4|rn|TFDTO8b@amuwmc7f>o{V-cbO##ox{lF?9+bU7 zBS*fusYhWGC*UH5bV!8+2}D__CHBxgO*9rGuMGr@LoyEb$F2R)4Bu){Z6UwQfvojx zl#M>1tl!hgB+_d|XD!Gu6i>{ol$rw3ZX=B^^bB1gbjGAM2W$%4m#%0_ay9VC>K}yBbKv zq@mT&z>p=YEQFhljclcMa8Q!vuxQt`e;oIb^gc@In$A(FF^Z9{~Z#?!X__uqrb7gKsK(?6n1`%{kFypq6lF{SaYJr4pY`Ju&=;xLv! z+Y`Gemu2Ma;rFu zEg<9iY|WAigAWAY@inN)$0*5&awf3K7~ANn7!=tUOtBh)VNtY_vsMhvvfhNwqa_t~ zUu{K4YhPaue?azkv{5S8iLutP4>lM<>(LNg-KAPb*or z6)pd9)l8^Nt7JBk%sK*Zob~{h61%Wt%8W62V^G8*j8zye6>f_6=r+!DZf6^4he;Nn zcqC00(UKPXBOmt)9R4f3M6zP~hL+d)ZZ)lip}A`b83~I&$-<`DzbIM=&Xq`)jab)d zege73{fqNZq?+ur%>lCsF-b8z!6dc2?jVM-b*79v*PMe{pKb*5N48WD%lDToJKL@q z+Oy%`O0AZI<X8ptB5=njgfFa-PnJ_4b`{v0oSkjQtt{5T?H#jygox9!7W`sHk&_&zpadRY zM&<3+A2<-bNT+M@c39Wc)#d#wKUdwJUgTr92WWrc@9M?FOpncb<$rDYTpZQM9wIkL z%oOq19DTD(I1jHy1IK9r?B5>bk?PUUSq3%iHzF0e26g2%uc`iv$nI5rLz@<*#U^y@ z+=Sl$`G$1&jcAmQ3sl0hT4qvPSQ$}U&{wqQdF}WsdoGEMl{*k=AhGoEO~SHr0?YH+z}DL ztlHylc@BryT3uS&+FELcn`y}FQ@z7sMdJO7_b>Pq))+0m*6ZU}yBrEK>oLUIw3U);vN%Rrz z=0HxI`NR%Lxh78HEjlH(E6&&JdJ^=WpL#LjKp6EHbZ zEVwAi`)OO^!r$UsqQ<|uGB(;mFb~vbQlfGdCnPlrU^@!x3s7vW@=J>2e1O^w&Twg-^V(oLa=ApH2?}ZF_DE5oF-=(Ts6_FypJvbZ&(EJ{ z=)Ar;T}sRFxs|%ll1?&~srqE(>@M6*q02DRy!%#nRlak-nO$p#jxaIik#1 zd&SgobEzDioj=~Z`rsQ zMGmsF4#x zm;q*Pl@@Cw`!(M z-XM7#zemDArhj{3!l}3@Y+dr8pv+;oU56x&|GI#2oT1+CKS+Q-Vi(dC?AMEC=*!Lx z1|QiELwKuq=R)Z)U2&joHm%Eg$FD!wgtL+COU ztLHc9VI3^?1}T}_uFtUd`zasCgFV~qs^3T5kZ=5#*yj5U1{(|yN{uyTmXm5Cl>a{W z6}O;Hrh0OAAx_ZDOV?X!huICep70fGQ3>SP6l<@8$k;XCZU-3^>^8ka(D;kq_Yzy+ z=q~p!uR99)(+enAQif*Sb()s15at{))HI4A<#o!l06QYADh2!nx-G*Bg_r3lFpxIgh!Ux4cW`Z>o8(_mg)FE^JXEuQ+tGX>jT&JFoeRV z2px~Lxdv(k~oUt9bf}hX11-Y9Ex>EWs-J6HOV@L z&bqC}Co91x2To}*N4$ipj=$a_cO~1{TP2OBP7-dXcgOXqRinI%cHX0(ZeY1tEZ^t$ zCh&WzpVpu7(YLX>#K!qntG5CN-e05|MK875PQ(oiWK50|6@stQXk8}COP+@gq*n-b zSl{4Vfj2z+t?JPrLc;>HXW=l@MNKIZT}rNeGIV!liJnWZ+#}-WUv)3vp#rmOBXD=%Te{mWx=Kh@=e;}l zAY=+vudg}GCCDpG>D{ab_6DwUJk4(Y?Txytp<>esn=2m|#Xi!yWKfQQwt0~#+!7Cs zysbFW<9ul}_TG4ub0U#3V*%OG{loZiMZB}3bkpeL(;g&lJaLo#%|WsN16US`gtQDs zd!Ya@uz~Ra!$$Ng?+H-1@zhKuKGcH5{#N&O6Gw(*)Aw!Fe+@AO*!%oFXwS#AG!~B#Hbg zwS-Mc^CB_}>#DWNg3KzT3QP@jOL|(l8|yPu+`OX;V%mbrg;nWPvZ+MVv%j=bs}BD< z&RgCGk`o1pGsAOPwPIKeqS-2=H=~^a9T?ux3d1yPf3x)~^(yqz8YMO8ewNjYg9vxh z4dtl}W`)VAeS1C*34I)Yq`;qvfm7-?i?P&vD-vWZ*9ldee>v1caGDd&xWDJa=Tn{f ziGi;%*qX1+<%$o&nrg47}aZX=u^l$SvubDM+JG`mVQ4#K(1cf|C%>hdF| z_ByA`9mc5LI4kpbtl3D{z%*UhF+_6!IKfK7KMTh_hUcX8mvAN|CDmVh-E?2ZRMO*c zJeLl>zewxW7#+^nf&coU`^e9Jt)Gx&)xBc;ls)7Mau2Ua24c1J<1j8Tw-&pYGkG+< zWm6z<3pz6HDdQ25&pyoiiL=B~biw2)Ecjj-!B8r0{}5vabe_>2s4NxvpduC^i{_Yx3P zs;bfCL^4PFsW|6UchrpekZt#v*FI?YKyvC)*rZ&x)|*#8s^7G%eeiA=JXx~PIcjIB zn3UkCFll{21?TIu48MK+DE=aavi{?hMSo7IhIpPFj}4R#h@q#mXZq8`OtthXZ(X57BU3^(!H7sntibOm(P zlxaUJ{A>UA>y6`@N0AjI+b#o7QKd7VMl=}EQ(kOzbtm} zg2Ed`$MmA%u3cW&EQY?fx6T0KYR$9Pu27Td#AQP)<;9(SpD^N$$9#SOKn7@}oWRQ# zo-gL-ab}aqU^e&3Y^6&NRoeP#PWy&tX;y*ypX$5*y9n_AQ{VMZOP!hRe=oJl$i&FV z`Ts(GU3o)#X)dMRw5d)cIT>GdSkWevy2sOM)|1-aC9KMJ4%#Da)HP%b#t0+fB*euv zQ_4f36sN&8T3J&j&Rdf$gh*otZO+3#XE_hH^dgl1%;BYML5|Qou`)3Jt}*I-uQ$jFUVbNHZ)ube_lzW@PWG) zNvMLv7Js0Rswh&Vuh(6_mSJ{4G$^R7xQAb~3f}9{f?dWP4Nex5>(FgHo(^_xdB=0M zSzW$tzHL#V4*7$@e|Ho=Yx&+^o+=3a`3A(r-KW=SA7lt~_s;A)B9!>PEN*+J%_M-l z-V}Vf-eB%@Wt@fx+Ws3$w04Eefzb1`*|01T*ll109R=qmh z1BTWVB}2qp@TyZBfI>w!>yu-Eo$VPs*_Ex|m_z6-(l3?%D5BSV}{yRtBB;rntZTozFajom0-ph^SMnU`(aWjRR@gYZ5lj#}{!w2zV| zH^Z0n2I~ra=NA(XiAZeIJMyY_jLXONfpahF$LI%~JNle+v)>cvo?S#AFJ4_84B_a8 zaQv()EpGfxi?qj2dh(+st114_X=pXp=`wZ~JgNCPKFPT)bNMN0@TdGhG8|w#_W9c( zi`W-D*XvVjoEmHn{Rv|t>O^+IwDl;>(d>u5Ivj+sCjNty65QAL-jTm`an-k#Zxh<5 z`Jn6l_P0HeJy15Xvjx$N*jav_NS+cxlZKx#WUoVo->$&nG*`YtL1{AfYSACvCLvnA z6SUH?I_E8pq{UWJBJoIz zKon@Y7iXdpTvLJ>3)XGbl39bpX)iBoFdB4Nsh|QiG)4Hpy9FylQNBRIl7(`BByrdq z;T_ai9wFHP>ESP8B{(gI3h_ryP8g9I;s2aIA?RMR#X9~wd8M=w%X?W%RSm8IadI*% zLJ7_c3F$P~SAqIm$?Lik1YYgO_FaQsqR7 za8be`f+(Wbg=iN=3tBJKVw2gNG>iv|=yGn#y0ZsvKn_KJq9ijO+7g91ta?jFzQbwQ z7EwZHS*egW6dDX7Big|xb( zb~yD&i@25x?^s5J1q+mhKg#a!hkq*rsgg^U2fqPQQZA(zp^4aEdGB{`` zQ}uqAO#eVP4H7ai7A<2|Y!^_CWP!qL>q$ui;=hB*64+7K%JWu`py?RkX+X0hVPKdB%*3=xs6ZiOzP8)q)(+Oo8D=2Dq-EgO3D zcI&_YYn1|(lDH&v#Puseiu~N{5JQes_#v6H&jyM}l)|85X$U&BbXr!dZ{3^*^CCTX zbZX}GZ#jexf$+dIGPy?Z90h55t!noYS2nP`lOHTE> zynpTFtEnqRuuM=>P&<4`(=HZL6=7RPZFBJQ6sNi-btfG13z)MZ;nUhhRI{NaR2XLV z=8zqa*wgY+7jQuZi~KE0)*~m!^WHjx52MCol2bx+;i9@fey1&tg)B-!Ux+bh=8!J_ z3teB$Ci~(`mW8Bp8IqklsO^tlpW{iR zheTp>=8ga0G<#H%L`5>tw5TLl2<>#t4%NhyOehd`1ycgng^NgwNSnn$EEDP&ktk`M zL9X@$km{}?v^l$l3tM=F4qqu-^5%4m$d6hf1{^E{3L(nk@NCFomq;X}TFVQc%_><` z&Pyqn0Z5LP>Y_BqboNOpEVJs)Mb$Vv3iTf9?lz!$DZtUwegLI^Iq!gx@^Pv*RvBGA zWn?tp$@`1Vv9#8Dp8Ej`ndONm^~?C05p81vzDN>dl+~+z0jOyFb;xjjJ6- zpN#}BvHv@EOhm{=TLcYRk-WG>Mg4wpN1Bw<*P`-bOR04+x zwcLwRqRl1?5*DmhVmq;yW$xeF{$q7jVoCbR`TCzRb8fp7>b&*1ZgwPYjn<196EU$d zYymL|^9oE{u2BK~OH9EPn4kz8v9jfAw!5W7Obqo7ho{lF+XdFR1>1TIv+j>){_zEJ zu5N(^1*b*R_7RV>E-8}@zp|H(M$Jg5Dg=Q^{@k<*)7{1I&XwG>4tRo-=(FbSLdJ}u z#w9*01aZsRSp!#=(V{%gN60gvfZ!M4=2k^NRpXt3kPD87UvDW>O)Hn-U4}~+f#N4f z!rq7#4ZjpAE__n42AU!(ml^vcg=~xFwM8_$vv?I0?qQ$I)jG$7r0twj$TuqXZ$w`)GBZGVNF!#+WD*y_EQ9({;DMfS_? ziSCI`!EJ_~Y>pgnuY)_uZfWOJY}0m^>sI*+{y=}xLwSLQ2lOyCVt!9^Sa|il#++3Y zvriQq2Oi(-elPt*whVd9@dl3~kF(fwzpm6mt};Xun2|uKNt#={AhAZk34p}?b^;0k zLiYRe(*%0?)eXi0=Y}Rzjl<(OI~7Zr7mR)#2^kkP6Ox5UH{z}@0nn7jAXhmp^5kdcwmH*!60>Gbyn z^Nf?cKR_;oq8S2GE=C@7#u8BHnYg63PCMO3#THym>Fox2CatCS_dZkmFGFJaKQ4J* zia?7o^`N?jNiwk2!MLVyAU4L{|CqlrF!YdttqlBRU~2!nQvgqK&0ey=q&cIw4i-g? z&mthPiFVwmzeIk3V_e>z1d3jgOe4{`DPF!#uub)ZBBn*;vxrWi&%ElpJlV|hO2bmw z)_Y++#!bIZ8GGK68wu!O-#RgFVDY1 ziDX8zXG8g$g4qJR5)_)kdgHTDjYMLg&G1p^$#FsIO)e4=MRU-THrG1JwR#e>Qq1b@ z3I2nMdu;B;{kN5}mQLWRGl7N#E$(RV#^iXa_)m4{E%S!<1tC|BQ`vuJ9yhI1N$_>! zY!=#oIi*e|ouLH2IDOFG9R&juE1_|c`^H&x!M@b@cE&&)t^0BV3_K zUNbFOV^Wp)1}4C+hf<4chhWFO>(k2)6bmdnC)bD2h4jdodH^CZh&csfMpn;)oSXLR zKb8P9P&(wSw4cfE|K{pr!Q$bLo+?NK!QApF*G2q?B-3J1Kvo$io1FgR79P&mKlZRg zMdHP?8l3@L?7cO@aF$Z*H?5 zI_%V9g@!ByHKIuhX2WyQgsjpjQpZ*kf{|PuXnWj^K41|82MX<1s-@Yj)o`fFFT$1K z+T7>RZ=_ikm(>cQ=SZ!a=ZD2Fkh=AzRtHOc)pzdY9SWOB)|)7CFRUR@LJNp_m(J3} zgs&ua1S};io%QjbG8i#RqJ44B>xh;itUwhQuH7fK=x|X2EVAk3y{df3tdFa^&OXi< zU3ZSRKC_Fua?&}Uu299gedx38db@vLVh8E6*{LxPIQ)VYCN#0?HQT1Cy4FAC|G&t4 z?|7`+{(oGALR1PNl#pyrdzFxp$lm+3SN0w$Qf5MS%Bbv7*_6sAdyle5_Q?Ld-{<>% zUKiKhbzk@Q^ZVR?eXhr)^VrAhSg+Uf`8p0Kg1x|$1NJrQfc=_pK4jZOHxCXaw#=gP zeJl+89ypNX2naTdU}e1|Nf%K*M*X&KTLIhiH6|+TOQcdAcy09N`K1)RUq_PJsozRi zn9z30IFyngEDI5qHwuBzzx}5#!8tMQN$_>;U>oA~6hpVm=WfbLqy|hp36~#BxV36N zsg-sm)X|gWDhP)jNKRRkrI+jS^%pbl3$2FDo zWA4{fYlf~@l#jOw)(6AMyB3pDlXCkzy==Jka&{)C-_?C=Gkn?Nb^n|puKJ^6@7f6! zo{+tG_^{~FG0o2yEQY=$9M^#a34(8zam>zOLCMxUV0hZ(;mpV64u9f1lB;*7FHtIH z&b*A_R^&95$ns;{cZg5u2~Jh*bpIr*RI#VU6XjxSuICD@OOAI9}+i5O#GEK2AL!PdTVp?xBR+ zW0b^CHAVRRO?z<~)&b)B6^n7o*KK=_&S4C~Th+qx3n@BnSJ#!SZgxw}N_89d6`m5l zp}-);%>=VWm&fR1bkeb z5^a@NNPe}kYw5gyvZKQDxWB}he~sBo2dy}^8x|Ck#Dx^EUN>`;9jExE z^;-Ul`*(^V!5BsAzO_-)TcU+&IaXWB4C`ldo|Q@#JMpz`EN8QHsx0g`w9i%X6}yfo zoYH=15xQOfGw(Ser8aK}OZ@m19&;Dk>pYj3;xYP;*U?|+IaY8oT+Y`D)0mj%P!e-x z$xPo}>WrNmtRJYa6dVv=d!_PJ;i96#oNVLG>9QH6oE2ZE7YEH{yzk1(4LveVdw6W9 zGrB#P{H>Wv4ERi?k+qLUqcaN>J3cDGHjrnm zsrr(cxNh&|YffOfC7mUc3<) zvMsFraW97V?j*6R$~|ijX&to^x5@ku?{ZdNyi5OdYs!*q&H4Ek4Yr7vb5;-16@6Db z+AANoNbSFhUX_m@DR=6~-o1r`(}LAe*l+pb9>o)cV$qcSU7HO8bsgd~T*mh|3S+mP zxuqwuA(DL>zYbLye!V zUMoGIlTcUun|~(5yiPX|?(~gy%Fkc&8QXLZ!vy_T5Xh%>~O zHpRTxO`;<3MioEHTxurhv(98*s|i8pIkl|COkgUHlM=bQA*H3(=I}Zt-)bK1#n)fHqqF}0PSV4wJk@Vtfso(H;#KX!a_sSkiquw?SLFhOBhFUxUB0U2 z7WL7Pk^AC%hKp^f^0rL2iCba%z3D1Xu<0&JT%^mJ<)1GoUm_x9%s3NJ`7_*Et?8wW zdS~Lh*YQJ0-`@bKW3MHQOoP^1J~C8YUCO_xEIxcAza;vra=eFYkY=_65v$04j)!}8 zdBN*~660l8wIIPZHLZ$*NAd?1nWdR;-;G33zTW)uIN0&N^?M1=?#{X-i6E7bj|J?l zZ%pWGY8u}Pl0;=M$_vOUJwN8`x?=mi-rIihB(*4o8gylX$v2{dzLqQ-*qK zDbzU`7&^WN)yMTkM^&qZeRGe6VkKeMc~9LRDM?KXP#I3s>a!`AN(ys4DSk!LLLgqa z2kCNQW>@&c=C^Re0ja6bg{9EU9WAZuX?fqdXmVijLKzjknVIA-AF8^3Jg4m#lnUj&;AQj#9bkPa-<^q)hbz z;zdhlot~KKl(|qs=Y8&Z%IXz6UZDtUyZihPYcaMv9Jd5->^}9{`*xq2^H&PCXwhgO z$u1DlT)K(xZT69f1xjqS0E2z|{t4*|gn}O9a+!f&`pp)+wDRYzzN}g6hvNj+W${dB zPGsfR++eKM{xb9_^TXmBin*LTx`6(M9Zkd1OS1C*83I2><4knBw+-dKD>y~`$~6qK z?pg1mrT)pdpnJ|qxkyc!p?SZ!m47mm$*Ht)c69oV>zc?u-E(GEt)~0mn5=U$`WPzP zTX@SVrQEvA-Q;e|E}l;?uNQq7Zl}NcEj>Gc<$ky3d{4i)f63>kRwtf2(MsC5r$32b za8h}gi02(EbH-viXrn!9oHUkC53fx5scO6Q`LhidwLt-w9uY?>5_8HqUyY-gx-UW-uu`>QBz12q0O;VSoFF-bF-K%hWal!tGTH4 z5Rj}0n3`LLWL_H|$1PFta+w+3e___~FlGFLjM-N`+4? z@8kGL^Ha}QGoQ)2A^+v&BjmlR4?6>NH;00fB-*%zyIQ2~=X{x(wzX%++8Ymh{dT?J ztww4WZToCtgeuYM^cnN@M@8=9n!=Z}sUlRvq%v=zGJ)g=l~(-NFCtV$O&4#5kO&D* zS(yYWg>_B}wa0wO%%Dh6-gtM7i7PiX;#ZCbPCPeNMkd#}H!4@727jce-Y6^*bW-uv z`|OMm@$qj~qQt{@&d}jnJxjWt)|6-+6(wYvK8G(f>r+@5R6UG0v1pj;K!0($$f(y~ zh@&{N%EI2hX3ND+47vToO(-)kqbW(Pj;@9AhjviAxus$R;Ty7pwxDG>-hEGtNlH-} zevy2e$&r$r4DS|)usYQU{_>?Y$EhLz!VHFf`S1Qc>2-;Srt|d%p&Gd-x|td@!G8_e zaDL-?z<$xq^wM;oW38MCyK#HIrR(?!u}ShicW!#dm+p6Dw;p$p_A9W&va?h%s+qD} zW65c!s4;Wj$@wT5(mXd$@bHsn3i9=hygmuNd%cREB(d z({k(Da^W*dZ5d-^Ica9;#U(oSS--GjG=Ems%TPho;l3TG{%(;wHF|F>x zI@Uxi&wKRdmlwZJrL2v&$ZnSeNqaMjF2?kzvKS+1J@?K9;t^1X$_C<_3%^)oorzV( z%Oo*>m!G#dFNwi;om8KU{a7zi@p(II*|idSI# z&RXY#r(ft@n%iA_3X(soA&x7~ZG5m9iP9{qN^?vt>%Snkb-8A!YtNCJFVXx5eu`iz z8^0r+^NR`7i6|TA9)1^IfihkLChh$@h-a!36=KQ7rcUIUy2y4$YdLpfE6Y!@tMBQr zJ&>T_VThA_&;MpKW}JrsX*o0b!2LF{UX4)tv-y{|luA{$?S}nM*KZCLunaXtr)X&D z<`J}~ah#1jmfY`|2LlD^Uf&+?sc_2RoViBD(_ND ztZw>bXCj0h@DFz1mKJnQCr!?(G=FSgY8vS4J2*3pH;31Rr|4+18h+=CF{akZcd0Yh zf;g6)JcXxl$>ODRRr(P)ayvNGi|HMU>o4hSd~Ros7dr`!sPIadACPXiF!Tnk-Q7-+ z@(r2}ES^{i44imM)c5`7Mixd_rAd zC;d4Nw?KUG%6F-UaW6aCHL1=%eLR2bq=Wp&UV(jU{i}Iji_-no)b}P>U$vTbmf=}> zCs_^zobWimEr)N~o$Fmh( zHLQH}obB@DlSf;Ze-nJ32b|PY1puA;zMtH(8G$irh2>A{T@$+6S5AH zI-lak|2Qi_7on;9W_*=2B-V$3`7vq1`I<|1DqNzkm?SL;m~d`Yi8t-xoo(xJCS9;j zy=m$s_q0Ys`bW>YQUe#YNvz#Os81oJfaxE-5@n)xzDs`#8xZ{CMK-VKyZ-u!6^`}*fHD2D4= zL?qN_q8r>-_3Us~8f^W`7u~6zDvqSJN*K5q?XXV0s!H(~PP{2NC4AM3wv4D{f0Ft+ zlW7T`8@ag!Eq09C2;Wb+ zr$w`41!vr@Ibh`_PWThV-1jEd__`uYu*o6Rv~<-{r*UOY!<)9z7Dx9^wEv3z%5g_Q zyzMZIfoiP#ERCBloSv<54%XWFOeXsUsvj7ra$%MqYo)?{k7X;q4>;yrxiUwZW|J|9 z&gI@bV4&HFiH&wGO+9-@+9zJ7YMy1n?d2`=ld+e}&Ma-xEZNdV8dLAE&XY8~#rUC% z^#(U|VkL-wYdpad%id_5yg((#JX~w%`Z{@V9ue(4{g{2T3Yj&5-RX%mW73Ak@OUvf zjO?8{T}f-qP3Hn)_JGoRk~?DVQLgrsUd}JA@n>C9qF3@SzVnbiZ!s{@t+BOHaMqgo zR%!CxoKJ3=w{Y6-xD7UJE8YQqgXmf7J%uz{t0?}yhwoXY<+m=xFovce3EJn4xjouE zFcF088s^Opn8$4NWo85vUbNcY91?MxzoAiZQqm{ko~%>e!+UvZR9@6cL@%b!nJFZ; z=_<3~PAWW=>}yUPtTleId;Iy=_gwtW_tpAKL%w6oV5AHE)NlWpNISxPJ5qK^o!>H} zr2Ov824|V6$6WzjxElX{p4t_JTWX?=6J zmO(Auy7N5wZVUbM2Oi_ySiw8e=@niM2%bARrk;1R7m<4#c}Y9Qr-D;det3wk1{2+U z^%VG$J?5;|W}a=!M}3}8+xi|)(GBI`L{$Wj>D&&m>9gJR-9Oh+E7CV+I`#E!c}f24 z%aS&h*5elD8&f!(2Pc31m>*HDFXI!l_aTNZd#9Ul1x)q*(4b6i}Rm|2DmSbO|=f)CRFFSe9*cQres_GZLjEF^wrd=H*G@VZ_;8Eljo^Y*MrWK z(DwU?-diY~EXohEv#q+fz~hj)yxJ?%UTXC9*h|-)z$u%;=L)y-W=)1-)vk)3IGsWx z@2HzLsd8T|jigwHPQ_od+kcn$I>L=tTR-<%V|q+!(4g!E)#SGF9Je8HM;=YZ02Lxj z(cHmI8-)dxQ|;0Cwrl;FdqNf5xpR8otULGa2r)aG$y##n)d*{Pl3Q{6VdGZ!B`O7|MjR>yQxF%gCv|Q+*dU|~;l_$qd=N_5U-s2i?FPm#i7ea^;=iIT6z-{WOC{G%Q!pY0qEBe94n4d4N@k{hGYc_$lK<8f zw>360J!FOag%;n*D;DzKC5gVDx>xW*%t%Q$tvj=3JL$fjqQGs!es7r_BLl_fh#MKt zn7m^7ZPc^;7~ZzNZj}-s9)3Z&dTUzgn-Y;ty4?DOM#;CNc*=t9*=#j?C!(GVKX$VX zq2xFi(9KhO{;Xou<*M)-Pem`T)%)?^v281f*nTDUUaF+8#5qa$5nop+>03Er871c+ zb7lHSrr^sFCaP{7Y{823!V49pw8gw{aa3$&R38wIb^2U=F`2p%&Us??9`c(VmeA;x zimp>}JEO6Ih)lfBJd3JyYF)dGdF-m1Uu5y2bd@}o6D7P?3j}4uh5}PPLP@W_tLjWj z)x{80q)6nX!fH++H6vTQe^9^HG5(U-?b^Xw}P#O}-`X|_H-VYkq zsq(KcUvm8z`HAD&t9vUy)O|I6<>+FRRaJZXe!Wj?&+Pj2%Y9c}=3YJq606kw>qG3k zB-J7a5}|~yV_jzx&D-a(N%yWbDarZxg_?%~qh}KDrF>N~;CaE&>n46BA8IY{sc{k9`lUH#7C-)YFlNCE~iu6o?ulLS9h!^(B?gg+G4qW?r_x(5MdBv>c;YSoEP+Yor(7?X?Zin zc7$F3)XFQaQ(m}SkzUhWrv<6WUt<=vCTMU!=dZLN%fn%hi=_;1Mi8hb`8ed^nbW>F z`Ax)OV3e$##rIzIIentpjms5;GsjYKP00g{rbZ}pntlalhVz&R1jJ+f^yTOb!Fq2R zN+f@2C^D9^k`N=Q=d(#m)*DR3<&ooNt)Ax1>L&Khu3t+`@bYk-dXS-EUt5wXvlGn8 zvc>xO90tsYF?Pd3FJa5S8sLh2HEQX|JDVdhRs^@G2e$Ptjj}MBap-Irp(tE*#u=M)Y!brICx;3%S@7tG0m* zty*blx|J_>@R8&|$?7BcVPuu^%b#Vxw)gT5VL+s6nBn#i;rYyUnf3XL{%Qi|w1WPW zUiVGc6CBAUHaz#u%hjpFuXYG*Z&FXoGgjVsH0SW(oZQ(T9--kc@F~I+ZBFjkJWkp_ z_po9orOJ6?JbvF!p+N(Khu@YVRGY}XgZf=@pRIXX0dJ3@)Z=l=y^T=47TjJUy?r~M zB`t~0d97~~sSo)2TCv_firVLB+4L-MO)5QIV{rX}xHMx*RbWo|fMJPlls$P&$E>#O zshX45pLRYK5UY9<7d^p?WNYr$b=y!Mu(@w^xS(&dhQ#6v>{Em zSiap4*-Bg6v>#fMVB49al~@wmR*Qe#+Lrq>DsN<1x;^@4KiQkzDn8Dra+z)$?zPx( z?h^LlXHPpEb*=YsQ|yGF@rah%PByQiaJ&{1;7Jn=wO$E@!-ona{s- zr^maFHrLb@t51q2qItfs3ut{+mH%REW}>=p#0QSsq73EaGlbPG*iYR^YkKlpFZ0{~ z#0-&H6t*uV&9gmLJ5lFEu*iU0w?0m@Rfie6dzXK&m(GK-RE*Xq;X6fL$T)p!vikK{ z+vpB?PR~ZnP|wVSVdr|P4~;V!BI6N@bxeD0m<_u#z$_KYw{!tnlqJ= z-^<3^r&ynSHD#N7Q?@FzsY?>#!8-S5XGLZcDBD;j+PXwK-W~&#z;am8^Bj>EzM4VA z@}j7HZ=$@t2A^+5ZAC_}jG0_7G15o;PSt*rycccmS~K>uE%{X$pZC7B)b&hWa|LF* zTS(z`YkuKU-*%bJR|M3NvLhwTdxQ-y%Md;v;v}8K7l1!H)ocSy0Lnz-LV>+fDnRsG9E4~ zgWiU`5Cg#)!hl4AGBRhbd4t|YyGu0^1UqCKT$K8Jb#@#zmjYzT2)QT?_!{gOYmfvn zT-qP)g1^fIOnhi1s?f`-Tc1K^HFaHO3sNZ&nRUw(=y@BFAD-E!bJo({YmKve(t==B zUni&QiV=sJQGLy}cEwMx@AtKR0)tPLkoVB#bM(}55%ElD;v=nEx_+?+v6P4$yP)O3 z{bf~OE9af~*9~pCD@20!>uG&eE@7S}!8#>zWcQ|4RNQ(aGjpT!dDSB8_M0~Xd#SCf zPLNJ$Dk-b->m~1vP!YBHG~00yj%&sj9tdM?k!-}!rFzB(-zv@ZcaB8;9 zn6kc$`PD(u&6dq3e_4lYuf78cKTlD{)(PCnkLOFeRr*AC!glpH3Tej!wYV;PQHpJv zlaiD22`M@;BPi9UeJf6!-@k|odCZ(b5vyG!)j8E)YDlVw_SB_Bam~;*fz)?WqJBlE zW|C=sin~*{6Q&Z;{JgoXlA0MI^4O83y*9!|d^<*pAwuNIGPT6EP`l{O?X&Ho65Efp z54ciCZfujcFJ9g=O&z(pEz7@0nkrAT=TfpuQL;-dMSW|Vq@7rbON!dRPN;p6R)uy? zHkCYe?chmVMEk+3*=Qxf_Nj39@d9~P-0*fieA15P6MM|@t$Vm%wXc+oS4ltHZ=mFz zQmW`X5O`yJ=2}%VjVQ9jEOl$&S)kTLO$2)pTX@%vZsteqfu79Mt%EPPwY!UoPnC5$ zqr;PBbP$Sr<(;HD;wkI*sbnXkQX{`@(RVpvZR&n|!r*1^jlI;sZ#}O^Z^SBHbxtpG zPTq26bH68Y-erql%ts<`>vDsUebPSLWYCkVwpi&0I!>lk6FSvBm>U=yKM2+_oi%Hh z)_4|h2gB;FxJ6jidQayTo7T(Mo7)GJe-^%#L!bLJrk;t9<>zP;gKb3BB_BC&oYDh{ zq#xd&_RhP-Yu9-HbY$84a%S`9!Ucu&D%E~@LOX`~8}`CmC$_G-JoXIsOrX5X8y;U5 zG8k6BSl>KOJRUhtvO>5evWdBQnZMSpgv~+kdqP6Uj)3VD)%bq!jst6*SA6C;)dc3C zo?Y0zFN0%)#Dkl~8O4Dmw~DO?RTn4*`8H3xJlG*|VR3n;)pBvn*%-=G!R%b>OlS}P;iK6t(O=~^Xaw#<7`B@Q9M!WGdAt=>ity>}k` z&>%`Gdlhdg>fdXp9C}JacK?Kj(~1vHTH5b zsb{yusAx`~9o8qfgeU%)jH~#9F_}2d#elm_oUbcz&YV-b=orp@AqJ`aHR59J*5$b- zPH%5dX=H1K`TZB(V+$VyKiI#W?HucTQ*|ft?JNcs27?5rYx-@*5|5!+OFazn7zOjD z&QE3OQZZ>nLAErNRYdW5*oN*NtGA!IC1n%WL~{a%=nOF^eh>jfqkmb_L&Q z^Uqo_+5L(GJ8RLI&xCKRwXeiA%svV!$yFS2v@V}e*1s4g@mY;HxxCzFZ?Zim>O98T ze5;+e+ix3w$U3lKki-!uWM>Wz(u5h<-W{rm+s|a0vv?{>{Q;}G;&Fqn`D?uo-gdNu zvSVT2W+}S65y2M+y9lcBrE4=^7|^j0_UbO3V$BcRVfsvQV@IS|J*z&ju~klpr}wgq zTjh_-=Yvbh`)}1@UGlSJ`h|hUb)>yx z)zUFm`&Y&b_*gEMwe>i?Pf13J}SHd`a>MqlII$b90PsuVO% zw&659(T{)faV=yq`lKJl9^*%vFQ;RJl4wF_$_e5bLoRz)1TSG`{wz?WX#eZk!jtD@pXb z)lUwdJ|q=b_VSy;-tP}sJn5-6%I{Zo_E&VZkIg4u?4f#TqUI2?9&%io4HJl?ObuXx$Jo5>5$svB2{OTiGMw@5!!a(6?MPpv+$KR z@fR0^2-8w*jlu2(zrdQMj6~Pz8Fp`}(T)j{eMd4Xt4|qtOBfuucuNeJn+Ls3oA|r= z7dB6NDvk~-;*L=Gi{jPZ@jLhyB!6PCBS_Tq$^(}Zp4$2z)+cO9e?70}@e9Knl;bYL z7CC#rtbu-6r)SxK={@VxO1H&e$*cIqbHzqGmn&aUxL8Gg5FMWwApP!K1$+%P^*O*> zIq+JkusZvh)%o5lOMVtsSzmXoi@%8WK8VM*0ls~86vuC_r|;J`v$ko?yF1z)qobCR z`uj}`$*2{U*GRlpa$(8pwAanL} z+JjH+>{(gUlTnyV(ab;252@$N>DuSUuxUJy-CZ&Cdvcuhinjsp@Z1-V*R{f|%pdeG zH0N8LWu+-5an0}aTg8q(k-*#Yaq48kTs1$YDSiT7UN1*1X=_axcFSO}1XrAEMD+zZ zzM+5)fqQSO#r$0G5)vLp?nZ8~@$?eA z2i3}bwMv2<5-)ltCx@ADlRUq|eper}>q@YsywKO$K37lfuYK%1Uz>~y*}n#Jc=HQ1 ze0gQW-tf>yw|Xd%?85hn2u#}G??RuRe8;RgUaCxx*011qC$3WIh5u&(`d9ry&g9=% zzXe?TP{JYpLgmH7eocWk=5OMPw=qM$n}zSyi`bm5d&9(bJyxJjMErajnX&#P^V9Nc z1sIvbZC@q#FN*&1Al&fTYGVnY%fGVn@tD9Kmff?f7}<(k35I38Ov)R~YfAOFOC(>A z_LxOA-alTSUvEr}Tz)kC;Y?hbq>B9J62}EHh6P} zX^CF?tp2O`Hh!L0=4>9OYPH)i z{?C9bW@;9FBqd@*A*E~1bT5iiVQftq9ep3zu;otq<_Uv(-@2UVZwqPV!yG;s>u+ zH!65?*euUET$wo*AEv|i)dSZ(ErPslXe!~CdcQnL{iWK)^v2^c%7h7Tu7|#)Qe_J6 zKx*FgXwl`D`?S3y+16(}noOa*UqXAiN+<$Jp{{sUus4~0e|Ox0d9~ckpqb{Bb9**x zoMYs4<@+{KjUNe-5;8Oneb+T4#^flQB`<$%HtW82rWxBe;M#lasprM@W(sR_A@!e{ zNfiBXC{M+XYp(Td4+=_>QWxJf5dXbt)V}JS= z?hB4|ye{1NkQ9|}nXKi{nffkeKOYC`FF1@(MYdo2o@Kr_(REi>LR#jT{a3zK`^dt= zPqYM#jM71mZ$y03{+?=070)#%B=r7kx5ycI+|*<^Wcphbv!se|^udG47c`DrcvOrN+Q)i|q9`bB0z^>ycM zMjwBgng3Dn`9j|rx~m%1pQih*8S}{Mub+v#{rF+i!^n4J*#&)XH_9oBqARl=84Lzm z(V8JXEKdZb^rbMz=U=%(x)<}orxr7rP^cDfiK%pir_<+^ zRsU$;AeoVQA;{g!m213CJgf0}P}!rmv|fRLd@bNOR;-hmn68+vjm`VrySqEG*R&0? z=wuL8Bz$!4MjCN(_UT&pg!yyR-&TkcvlWphy9GGY-U#(dEj%fvUm_az?471qahD7q zXV8V>EBTmnVjF?zK|H26kW`wdLqZQlvJ4dGV&aerfakb^N505 zT`_U^TC?m4IU1LU&lY`w8R|M#2eay`n?=8bEs1_%+DrJDcnIE!Uf2z`y07cMA|jw7 zDHc{m&qFWJ&^&h8P2E-fc*f6Bg`e+FFBI8FYB-!SQR3XBcaL;6eEEUq5@&EXwc=B` zNj_6c@`c+rvIM*g4DCbL22<5pl%vAQexAbr5PwNJh}T0W=(H`Ne9wI4)MIyU|Maoc zFE2{?5qMwY=t6dCV#abz_=}?K#XTMFb!s`Ug*!0M7DPX*z?<>UFvm|^|#s?#YmNU#}+zWkJtz#D;nA(qxU#cVB0U zoPR=spq4iy(8hCptgBw?ku2eEt{<>gV3ianVEU2i7LMk`W7;TLL8>)oddrdPx{FkC znb?MxJ}xR~*1YH{<;tROG0uNQ$9bn~a4kHOb^sal^rnN^o!aNml&x>qzu>PtH?%w< z<5v?yPW~u5!OM0bSfgsBV=uErqL6hAc~9B1tNoKqY3(XZCh5DK^~NVW$Pu?UythmhEH^3@|Cle3>)cFll)_888^jrxH8Pn- zPtRF6eSS~wB4E*L)EoUt@#$;H#|7%_JQ8%pT!^rron9N~y{?7YRttO14%+WOV{qpP zI%PzeU`ti9W+1D4&VHpyi(0?(deg6|w?r3{xznbHb}|R{`Ajox0VmVDRhJNQ;rA)l zqZhvnihP*gTX0@3>!Mg>i&Yiz`JQ1J7r)5JR95i*UZ69M&Xq*#~q}u8bdRmKB zg}T-Ou`II>3SXP#=#BiufD4GMf}e-!$*0Q^x!M^Y1+^FOUHo3GG>HhR>Lg!xVF zwVBh}e>HafF%)s;``aOlcEU^NpL(U7j(oL|kluQsvx8c1v|f7so{3ChrlLjh(}=I1 zK1e#JTFd>^*D}x`96G)O{O36JI`P;IpEu17K7nmC5mtHuM93h*`CtNSw=)_3ftf0iFqa7 z+gARUlp-|Dk@x0{7Lv&cMCfB0*J$x-+b4u zuSQ_z(K=ab;vOpv?)E>$B4uVLLCJ4UtGGyZ=2domAAyS2xu4Iv*hU1#&+rna8+@)Z zxj7=$KzxrZ6Y>1Rvb5IC`_iWuWZRKhQ{4n2@jyyCpc`*@|9JU&Q|IhDr$4#oD&Y_6y{pL_*PVWEoY(1Z!~;`UOEN z8EYeo@5(pkcHijhzT{n~!d*S_>IK{Ln5yWh)Afe;-LTvH$ciI%15f2)cYpHABZ#hX zf69mXmL{Z~d6plqfbqjKO;>%+cN+4!AJ;oeajvC=5}Fd-4(#d_@wboEKaWk+bTRtf zohgf}*(o9vj5+DiCRbAj@t!K+QM{Ho|1SFqW8+#hRfFY<@D(KYms6c4jP(^^{cf*) zghRC6^bE0@Cb3FH+VQ^AltVD}I-Kh2*=_Dl8t9Li)y$=>)a|+Q#IZGfbGc_?Fx>uT zz#`9u?c8C1AG&@SrV}IEjV1fk$scd*ZQiTcA6gD&gb%eA2IO=NR;#yZurgEH=oA3SB;m^#C%Do z=-{~De)6#s7RKo%VaGIb!`}86IG?|g`!;LSY2x0G%v%iUs9GPklcfYK!mtj(?5Xs)7? z7=bh^15*bY1e7TzX6s6$1+>q?$;D2?&BH+h{3Rh89XvK^M*}N!qZ>A+R!ADalXb(v z2x;R;!_N(b!H&TQ3nv)6X<#RXG&ePK1Z(24DLEpoRcZKu3@{{x3W3rAt}rAQ4F@*@ z=t~jEbTV{AjYQrKX#7 zT7!dR2L)qO1LlYW_~B*eq0yn?-~@s^90*`=96*#4jDl0AL&F6Y;^yWAgFIk)E>w^o z2y*gs1F77o0ze)R{9xfVgJ|3VAcA!5{F5nZGC7=usSf7&@949AG z0vH1y*e(}4*bXPKPCyut2Jq&q;fdvB21+blf z9f&lr29A!jxU`Kqux%CWZH<(Wjx;9bHpccy2U{n5BP5L>uvcyHfW2mHZsZ8ZP-#Zi z26m{*e{OET_e}F|H@C`7rGMSmG{#61pdmQ}J4kn+&IAkk9Iya&{w#sgJAf=e4Gu^c zBU@vngPnm9(%!(v6p1Iq4*VxVBV+>nhdRoC$p=n8N_s;RBQpbgus8xN4txN`fe#}N zRE(D$72`8N#dx?;F+(Vi2Z@UDLNRUwRLlS_X@rXL8$$K?Q85l4s0XMOgfS|{&56om zhhhjWRLq1EmB)pEVhAY41H~XYxuAO7yihApNkb^c1C7A|jv1orA^A`xc_BIZAX#`& z^*A_@s60++w7@XInc#-{@|xu8~{F&IJhc%k0ep_xEHCApxPKtQu(Yy{PV z+BAg5z+;SRlMjwTBQkp-sd;!&BjSW&2uLyx zcy^)DazQ;HAUTbpb?1fZaYM7j4ULZ-iXl)l!GVCs2lWTXxS{cxKym_2gL{{YA2nyd z21D&+ctp?)BB7nd3rGgoH+c60A=D}U+bMTM@iJ-DOs{XitE6|@h6VjoO-ceJKR+CrxpI{bFew3}?1}wt=6tloc<=L~73ot=|*#ZCnU}|CWjxxuP2}j`y4t|u$Lz!^2`9+yk z$oxWP^oaRInS375yuv1u4>XHhTwppE``?*JXciB{Jl;c72AfC(590r)Le)Ep6P$4xsD!~|6Fr{C-h%5 z7q|zHYOcdy!1t#>zt>#iGSYH)#hIj#R?bLAb0dR0NGBwu+0d-(k1QH6?{DZA3xGpe zIQV%1&30MS0P_D}PX11r{eD9J zmz5fzW;g+2q(cL87j8h60Xzv*bAYk~(>b~MP(Pr`gNt$j8Vbzf0;mC4;XnC-x`6l* zz=n7LPQc5FB6%p91e{iGUXVTjTmoQSKn~b15CsVh*ghXHi(oP@H%OvDaZ%)thmRW- z1uKKuJU~PIC?yM&19de>eNbc&fnrW5a>5NTMs9%W9sUFfCD;hq7bn;~@Wagkj1&0e zfOP=F2tE`!V+SV{8aoFEXc-_eIDls^z_?H% z{f+>Er{>5x;yvuOKocM?_W!%;9oPcJ!jhQ&}xfKh;X0HXkbDK`vEVIl+d4pRw$O`%Fc{Q(FV)g}aC0Y-s} zLGTvfYp57RGq_=B55s8)7Q-YC0TUT`d{FN^Q19$eD*z7yC4;FM4+PNxjE(96B2@^O zR6#Ht4fLV$!4#4kD#-!$024KU%Ym%`g9dxxfMPIU=YS-G=^iIcoM4&(%^6I2&=dqF z0WblAM#}+7#sy0TlK>P2VTWlVFOO4R8-|e1H(B(LyWD3AF+fLr!R3AX>xD3DYQO=GmbhIN>ostpE#$Y7>$SraUlZ zg-H&;qQU+EE)JIDhQ-ZPvw%tdFA_Y!IrR?~`Cka$?@jT443|(C;ID8A zrPPnA`NMv$e}YTOGSX7FZ~y;?OFRHt;-NtR1|2kBe+!m)IRGy=2;5NKY7Tw?Ivw&> zbMXE%Sc1^uzxP%HKFEJqn!f`}zn_l(7Fa?-Boq$e1cQg+4dBED_#0^KA%ycMq=8@- z3eo^jgAagFXh;LV8I(&HXc0sgP(=vB05}YQFko{a&H#cSU;=|6xB)*=5CnuJK%1N> zpD@r5AQBJ+Q4<=qKv)RnIpzYe69{fl01gB_K$sUL9N@+U8V8~fPWcTs0gC?>n;iB| zz}SQjxV`wl>YD|Y{;$yFhzdvZP{>661#ldJ14otpQL}y&(i{ape}NxI0LM|Y_ZMga zDQ(yb_!qbXDP~?63PB@+J+*+t4`sfN_)%d%brcR91sq2q6awmj2kPM{;5Z5ZIFEpX zqfqatVLb|(j>4;dYr2n^{G*`hC^$H31P>YA{~pT+ZiD_oNB)cX`n_`e&&?O=qVX?& zO5lp~#zD^3#`Y-Phw^B^Od2rv55mt4m4okF zS@=Qn4rn?Kkc$Ge@oz6&!8_GIOc*B@(99td#{CZ$uAIQV9q3;LaBus6){+7@A%C@`uwI5p z2HJkWmK3&LFg=Ip7JSRe1(6zP1>cMsuO{}3jG$lUj(tt@YMD}39inc-!g+tpbxE|~{fTM&-d+1SY!B*kK0%>y)gLVPz3W0AVVaEa5{=>aP>%a@`9!}W(0J#IuXa`zNUcoJkJA9iCKqnL>hU7%kbErQ60)csGhYGyUp!I{@B%Dw^=oXh9zR!lKI~qMg zy#rhyHJ?zMX!jT(^?wh;0PfNMR}Awv2J=4$F(~8xR}k|ru2$e>(C;Ms{guTnWmPfd zTmJ(N&I5oA@ERBmVLe2!PGQ8l6oxcS!+`zrWpCE<<02P0N7@+3A=iwlT`PU); zqd(;DK+NyQ|G$r6U>7>-snnkr5~!D80B=QKNPy-Tu*@JSKKuhDgC!3qfnlgkfF%RA z9N^agC;Kjn>4)zgfc!u19)K_?3h;gnb;STg0bqxE)&|cT zDjlTtzkP27l>ZB=1-t}*o&huxVgEnO=>d@X7bJq#-;fnRBMR95!bk+R@UT{ftv{q| z;kQ_5zIfE;LG{o&8n!c#MFNZ@%6h;y9lkbzu?LKbARCK*lLOgb_%Zi=? z4qIvn6&PR1G!B9h8tejx>>B!F;)vCO-&CP}9Z-Mp zyCV4F1?^FQ<^_Il#RI%Vgs*paAUg|NWVG#uXCGP%_}T=0kpRs%2jqK!o#JR~4N1oV zjUN~sIQy_~0(Rb`uMQx2(3lNIP0$R(R~2Y<0F56=1g$Q7A%J$tLvo_MH1K@GPH_l1 zppgnBnIUN9|8Sq9@eVX1^tBL-jG%b|k;8w{uK%O|_FsGxzqcX(u~`SyC7`|jV%AX# z>J7@}r(>qq;>|NT`Y5aCOw?IXbh4U0tw+M0nfMis5tx6_pDIHb%eFfsIW*EHY!SXTZ&dA2MO3Q#NKRjGnpBP=J>18%l0OPcr7O87Kpr~Bb1G1`ip`~=aX3BP$n>Uepl zW2o{k&E_x4)p8 zPAS21+Vz*_A<#m59v0d_2VM8-jl)7SH=rj%#cb}=<26TU1bA)T(86GVT{SMFXNBcR zn=F5{c}t6w^7 zmsnsGT^9?e8;!0@bfhi=x^7X*;kx91tS|#mHw0Z5*ribW;0mXlN7r3@b-3>KA2Q1V zbswPX0^hZJs4f<|F5<`{HT)s7ZGWjkJi4yOk-F^Yx>?r`FOu>EdVwX(=ES7k;qK6oJMb8_MSSM%of%^Me!6U69Se#2z^=|%nQy=jPzk)cz1L>{1_^n zpz#S5?pt+M(n3#9j7#t!AY1jduL(5^`;09HU|zMPKpB{-p=`mYTGyJoOCAt~8d1I2 zFw-Y_V4fW#ea71-uzl~Wv{DKEAj84HI0tB>8|6yALo!u&_NdA)gY95+(3M-Q2{!El zZ84rR>%H{d*NJ8iIII*<$U=nq( zsx1ILQui{YEW*bbwM+Cb9=MYdTt9JY$jh@FRq@*}N@>SDNm{5qej0531&6f`2K~xNTRPXLzt7MAOD?0L0Inklg^827ycbVepudyk;P z0gS(HBwAU10_?XjGejuED42wC3K$Igqx~Pur8B5_7qEla@4x@yn2w6Rm-@9n_JAWC z*s{J3Tgr&QAXM^I86ZwPLz~`)1hBeAB-=lmYq6sF$>o2%BN6)YQWTOI@^ z?>esD!N|Pd1I0%g4=yXj&45efTlTelyhmn~PH(OtnF?b`?uJ=45hs{at@B~iWU2yt zT{o1)GrN(hvU%tZiwQQK7)AP7ARB{dX0HS1zj+BUfa-arc?I{5>;iQ`FKX{mLtuo1oY+n_Ib`)NC`$`ST4C*kE;mxAQUG zO6D%kQHTCgp;QAbp%n48Nq^Kf>}_d8;QTV(z>r#7Ur#ewy>vcd_}QcL&yiqFU&{W{ z-AQ2)3|{BssQ78`2eAjPUOwlNXWO;LG?(jt{3Iu-`bvPo*2nZ=&fOT8O0w%(F^ylk zwiSkFzG)TO-y6NZx1KzE?rI{cJKvciC-W{3j5}Sgw1a09_IH)YKg$8)|I+SHsapn4 z(Q64U7jyHNS)6iGUv=V`sZHu^01`CH2%ab@1Ll3gY%YiCr{bvxOqz(7y1h{gi`)97 z7`-e%m&TNV$yH9xE_+!-;Y6W(>YI8=>6uC@+ZrZP6}WGW{a9fPNv0l&*J7FeUoE;q z=GHZl!X)IgA2jPRFs?`miarzc1v(l0rRl8cy+ICFrF^nWx!SCmUIe_tL zduEqCE1Gj;0K154Z_~e^>h|Co<1vieG0s-6?FWG(#f?3svQlNTSSrt6Qzh!Qp5NmI zPWZlzV7sFL0?4;qd1vEe?lR+De$iLs+WtV1*0^X)B1%8&vs({Mmb-~+xz1sWoYB4B zpIftkK1hGojq8zI*G36Lpe{7ZNHxx8Cf`;kJLzbJozWEnD^6BErjB!guE^ zdz1}_t7_p{$xC=&$w%DShN8Ck!KGW2^dpM>MWs~^Qj%1Z@0$`NkV1vjJw_H8e?WCX z`*%%ksF}`zp+_oc)z|~m6fk@C3L5(#x1HE)ndt=Za@&q$_G+UBCYhp@rf9tWaG2@T zs93!3UhP}PUt%6ppToLd|LK30;x!R|Li4@c3~LDwxzN+|nCx4khFuPOWPWi+cFZ$- z(EuuiW3lPekSKFw{ZG?$yXka#*)iHy)PZylB{7+qeaWZWpC|D!_W=&3fy3uTH{N`gff6z7uMKphe)Ekx4s$s-K-&Vj} zqat**5{!22WZnk*7b~+h?7xiAcW#GxXV5!FEY>67X>eWZ|K6K}$t zUiEtb6GfPizwsjk^2=N^1&%`X+mkCdkE-qUx9H^AG3@B(FR(K+Um#5|Dgu$k9ntn1 z@iwC@AIU+IX{+>v(knmCSBXYhZN>fJ9}Q!5?~y*LMJ7#F56A7c zW z9K(y>hC7O5?D5YGV;f(NPn+@Mnl))SHwoAGxZE>Bamd_gm%BAq52vT!eW0RW96{{F z8|N;iyX-VjV@iDvKGrZE57~f$0Z+IR?m6?B&V@}Iykn9R5jA`O@0*Z9A&X{E^|ZIP zxgK@6@#{@WmBWa|M}&|KIu1h*JVipm2x5d8IK`79H4Fj8-3d2{B82nSYW>o+>GP@GceHB))8opi?@IO8UL$qxKa1 zf(S%AIc>bZ1}z70u_aGkOH_vB35MR#|9v`RIZ}LjYxrm3Z)cb_}e2)*YNkSwWX8CZ0bI3y1 zE!twQP=9b7ViZNbwD4Lz8NDu9P?y;9#xU_~?n$aJ#@orx&yIl0MI^Qv1d<7Tx2Z+j zs^@LM?O9p(Wz8b*b{BDYdEv4+3TGP=#uOMQE-_F3*)0z}96RXW>U5=|{a0=4u3YF+!)La*4JGW9Oyq z-w%0i;AoNI6Kkne1hio})wY`>k@$Fzk1acoF9$!UPb}KFDcbeu(x_u#7;=5|SY)yvhnFd>X zL<$ffgh+<0TU9s8D0r9j6(`iIA=iJe)Ydp;#FN!k1+q~r~{ zba@EnDOnEMo0tK>`$rtYNjXipG#RCqNlYUD<^UaBn+t?ou$jl6hOAI15{zHoGbV+T zg06;*&Q4eQM2DAW-9xMpezcN0y^#yf0A(&aj*S5ki#t#49J^;`u{Sp!34Nzib*+## zhnFC9|L;%;!VZZ@F2)?8Wyz2I~8S3P(Wy6f+7+OpN5Ll0P2_5r?z$b}RKizzhgl{!O*zl%v z>PXkx*AjfZH24Jlh$vRd!3HA!MiVU(stNd5MyRBr$|0rjk3l=AQDPqV(0A6oX&5IF zi0=|JAGlw$x!3ID__%chd(uZ7H&xd&y4S2LzU)D{+}YX55wz^&{k8X8_t;vY3q?Pa z6kd!LR^JZTtY^tX*##p7#qzh=>}a)BrmGiSpa!SToDv<(E$M%SPbz_u3yPB;yeB(g zq$11D@so*%`S12xVtmZWQPT+cUl;i{GP|xUKcm|`I1*4}3zdWgDF;sI9dJ^sFFZ^o zU}eoNa^Ufka-^Nj;Pp^i&_Z=CZ5}h=61yh@zP+W@`!JzNI-NJPs8lrDUUqew@DU?# z-MT-@9{IQqM=47kZJF{VRzzBahr=a@iqLn+$Gj zS7}E_Rd+wutPm#|Ouws(rH=_|%1u7bKf%VGYy zqaRyuo!kB%k*|3Ep<9C#aVXyTtEfZA5^Tq}a$#oDtBMe!nlwqv6-Q*mvsMI36Y>O| zCb#Y3bn8mk5-LUhQ+3D-yi1ve=Ld|_)ww-zU2%S9N~3H1#Vy?cI_>5+f^=^vz;}$M zS~v>SguCJI^GM6`b3zWK+%$+BhBJ3+$&6KPm$@0hCBjF%n6Gg#v2ckqzY0T9UsrgP z+Iqg|#&;*=m)Zz1>21KbvD~I2&vxkVOKyzTA}7Esr7;&F9Xa(5SLCi^U^Ja{Ji{!s zBeJBpO7KT(NX?@LFfC`cVb&Yp(mj9ZB}7{IJd#GMMppPjh;iY}iI79m^P#drkkD@( zmBKELS-4HhAXUah^*BHCv$L#ne+1slkKbbA_x$bVQ126?)FJgkk-xWalYh8fV--Dn z#_(Lrp$y0s>Bl+f(OIf$C|-{CzS11+DX_@sm(_Od4y;J^re*q#x+-)<)}^~ru=T)X z9aqY)>fw)O?=2nZkEX|Y(;TlJS87W}HR4HLAPR~KD_jv~50oOnj1pm$jDL!}p6JfiNR0OGqCrtez(-J$*i*5q)AJ1^~Md^K*S ztLZ51SfL9eGNa`=$d=@cIFV3n30=oRHuyD(-Hem@OQ6jhts*i7{a*Ew7o@cNWsCd+ zhV6v^aPT4EcIEx>c;Wyxy7Gs0280rreBaCp`e^rO!>zbS^7pfI?Pv~8W^dxdc-O*k zM1BXfA|=E%k{+oqMpRvTA(I&4lv^Bq+rnu$be(`Po$LCv(PV`~3d9og0bw2G9w|qR zoV%{KIX<-!c6SjRlvyv854xYVQOJ!pz8SWb4L=hY`!xfk+5;i)`y1(JlyzFZsK z!$BlH-O0YU7J?UiXzk0Zwv4ztI5o%A)L)V9g_DfYr%!Ip$iOq zw{RsA1^6TIhvDV>65Gexvc_oIgy%Kp3U(=2`Y;Gw^;3sScYFDn-fx< zwBdt!O*K}jLPY@a7t>(9V3xv7=I6J9i^444=l^awH2#Hvm@xP)U!UcmO((||ib%{Z_ zzn9wzmSfPCgdm9h!?ADP9g=?0%eOjWWLw0JiQrdyb$6m8GZMBRt~V3dOln9q$UKN^1eT97f$%Y*`nn&4uE=?rcYEkW+MI8{D1G%d0? z)URTP#bWi?BM+OU6=9OYg+L?JZ9w8GDBP~bY+xB)`}GVuZTLe5re=~zjjfoHn1~uX znMx`|3g<}u02y#B_$W*@oQgA`8;dCR^XRq8Idech;yF>qIMt;pphXP^FbGSbN>G9z zqkNyl?lFX4q*9o7+#A1#$}q-Tib8`05)o?lFg$Zj1j|q{IXhCLXH{kdlYY#WMNUcq ze1^s!pg}pJIW4+2dFL9*JNkX#m}SRv}%H1M7E2f2jc&> zVt9m9c6(;y_jM+)mEw*t?(ZruK_Oc}j_zx}6tZBIX2JGwu>{X*A%DO?oK~1<0i!ol2S2KIWkM)AO9U?W>w<1wjs7^DN)# z5#3AD_O{N!(;{l>AreRM?kbO#5Blj|S{^=e4U8Z&+##adil z{togNr}Zp%08N)nK>>NM3lYPK-E)FGZTRQ#pq~WMk|1R-Nn&@(KgitKF5^99BHEsV zWa7&Ab#8^So79Cs?~4VX_zVrzs%l=!czlL!NKK>yO#<0|cT06rcRn$!5W2jNKx762 z0S6||0j2SF&YI-Fuf4Q67L8Wmf?{}_hi_W4hNl2?Q2=L1Zrw~S38n2q_?Dz*A;+F#-Qf3L!t)vX5KPlgI9&`)C1xkLgK_>=cgi}dHzll^a>A%vE@&<2B;lJ0Q-hz5uC zE-B=EIZRhln&~?96Q8-EFqs0bsu(S6qsV)Eceqm93kw9I-dG?<^p$QeXbTAr6kUt* z3RG&lpwC6z`yBSGgb>eO0VZ*bJ9?6Uc$u^aR@7_Lj>Tuo9iweA477#6x=16~&)OZ&eP} zRlj+|PGy7o7merG*fCJ`4}737apJb8CHUo_`07i^LI`gKphd6^+cL0hK_K?{@_j|A zI!_Ly7P-+$0R%GL&Qdf)5(`-*5J^(swE#4N1sovoO_J66RmL?h2^dgq8!8~y5NS1g ztb(ubCsI%!kyI>c=$T|i$YF3o?RI6KebXQAHWBwwkB}t(`KT?qN}PQP8{~JiQ?)Lj zX_1*S?8%g2%pa<&Xtk@$&w!O?Zi2uL-Wu}l$Z9+>tVTd;&*|#f>L+c?8ZL(uLUSKT z+cPs+LVh%P2G9?6RAWo})lZnnnGAc{zw^&SqLd;=n7viOFLnw)JUa|4-xomj@Z_j$ z1Of*cLRWr^g4$Yjy@Xe*tQI z`Or_qN05Q;zH|0U8QEMw^(0Vl(PlQ6gD~fZWCKxseSLNQ@6gy0*6$Hfirn;Aey_?S zfDkhf?TxOlCYqtM{ky=O0Dm;5m;&1epF3wJHH^c2*ym>+!Lt%ucyv6ME(B8U1N6$= zu{p-wKzJ#U_FKd0Ffk&@ci3~GqYeHi6<{*^BH)Dr>$&dR4x0vYO3}DgN8}3rxH5@g zU}v$-lMx^Bp;=8^dteFN3w%x3u*}y@9e@>Fqjp$E;?XXcoIZ&Z-Rj?AIM;9~Xq(JmAaqxkqCKDy8u}sI}zu4=2Iad=aIu6+Oh%=DH0JmQQ{GIs+2=H*TMF+#8M= zGw(Qmk`qz#zP*$YA!3L$Bz+4H4lNIf&QAGOOZ(8eXi%i=N)sXC{k=MlUmlBjG%Z_3 zq!(&?c)U*CgtCR+Rv8Lzb7(g2_=V9WrI>`}j}J+bNeAmf+&yyKqJv~;&fG$V`GM*YY3LSs7m!`_x z>X&%YE8DlMaa$vXMg)$CdN|){OCw)ZYe$=Ra(weH^fTJ~B@EEov$rho4ZU z8sDw7pxb@xcwBpkm$Zy7i-s{tOu2h#I5FhE=TTw2Hl0#^rG7kY^*g1-jBc+VlQqWQ zsYYeGH7(GfS|wK9=CwLRN`Zw|yKro#ng+HJM@Ty4&$-7frG*GScHcJ((pdDEaQ_Xp zX`9+lW{nmKV=Dy$c=2U8PPR(ACCS zvpAYc8I%#nGH`hG9Y8+=fQ0^?&6)MB!Gc5sIy1#=CD%J)zG zkYy%LJ;Aw)jnQ9lOrCKRtfXNzf)Rx`6DHP11T4EI74Vf$I%yn(%JgxLeEp?^yna8o znD8^zIQv@YmH3i9s$}lZ>i#u0oYK(P~abil4h*hp&CKOnCe?ZbT&=(#_Y zl76EcW)Rb^()tl_P3`F?#uXCbt>?Ylt>z^x*~j9KnoAh+mQfr!FwSZhnonSUhR8oS zjyAZ7p{gM=DLG(U9U)>QQ8o(pl-c5Soj==4BfQ}7+D5U5Rjf^3;V@cD=UI`?#*)!k zRJ7vAXu!XWIph$=z`>|gtGWb1)N=CT)pMczkhu3x5ToJKLmZN4E(${L?uel+vR7M9 zkko#V!Pkfq0ht_dMY9?9>#IR%TD8o)95|Hq7-*TG;l3B%m<5An<=yNRv=Nk`0fi|^ zF=Wi2A^h;uG-_jMD`pB*((crcXG)-M>*d`h?q(dt?ibCdjT?Z!O5q5khm!dxzeOt= z?wsEkb1m)i6~^tH87)QYU&jdTLlu(DEI52d?M*|H4XyR&%PF98pF=;mYkwg%BeiWAU z)(_yFh=Iudlwr>Tq0DcA*A=#BHt;3Sptkw2T{-c=I#)R3EfOKHsB(%TGem_}xqk3YtOoqXdhCXo$i}?<7*fr|yGMnqW*oc$PEBb5i z%mplRbOmi{zj-{tGYsKzdaq3ml~SPw^fTuam=vVi9P2+^AtuOJS2_oic1qizNKI_S z32}derFQASlm?T!y~oU?tcJ_jvF?+jN&=RKy)x6C?Jd;w;%CxS7>K>iA}KCP2Zg7u z)uDoz%2Ch`FG6SeBZx3!D-b3$>RN_xwm#C}c3D09o`+=COM(VHV&|dO`v`}rJJYU)tz61>lpBi_?FmvGbE^i)Ipl#AA zatgeKEHW>d(*b7D|4c0#Wa0x~m-Uf)RsJY``Mz%zo6JFPMy-E5^ch(y?>VCB7=tcF z6=sD8&oL_SEib(`=W=m;#*!}3QOYm3SA5`rfl!?rFC5C@l)Q<0o8vH)PqOT>7~E?j zIw}xw0b@wUYGEZST$eu>r%*Q~g7MoPA3w|5*Y;yCjIUo2g?ZoCJyLX8QgC}Y^8>RH z%WoCue0Cs@pd~W-&Vp9h>c~Lr>Zk&Xe35DnaBD`Fp)Kf|dP~=9bFW4l5Sp!*0VitY z*xJMTC#+}HB3ZI&Ur7F+9xVEbV^?Vy?^2_k>reJfYxwMbPRCVI7hY0PafDNs;WD%2 zqM-Q{{rfMp94&IB8rwR;sx*a2L(=?~N-Kq(ZZT=nYD&`fObYnyQ7emP{7P-FM@l<& z>)T%6iL!vsWx3rj15fBMXM~8XqlB7k9(!aTGK5l!n&0uqJs$Rh?yb2{uj4uKIe4N+ zz%6U5SbGL;&+(uS5!Jfd6q#GkoJd+S7 zlW269crZWbv-%-zNWUQ^Wmakup@+~YtC*kJ1HN?75STlw`do(W(Bs3|Qv6NTI$rZ6 zO9w}52Rfu@;pn#KLzRz|TfBl)y>VGLg#f63aEq?Udrq%bpAv_fMLgp(x&QoFZb0oD z0nR*ok?~)7Im*cT{?Kr0dlVMY(=*b+tx>TxXCm$!sql?i^*yttiKYsSN&+Z5G>q$;JaxJ&Y@w9s6rC{AMDzM^d?QOzx~YMZDJOBqlRVnOXnURjBK*f2bA**S28G{&+8g-*LCc;uUx zn$lR}Czwr@C()I11RREv4X;qylf@>3(9S-%|k@h=AeRSc9jz3B0uxNB0K`#4dV0Q62H~ zZ;2mhqYGGaU!a!X$ZNcNVgQuUZMq}p@wcuGlt6#FFg`{{VA7FMz5bVtk6jQiLm zFh(D5N&GFf1c@OS?O=-k^NT{vaL0%Mwfs(AL;i_%kagPQ{`wC9(vPn@+l2bej8E7? zv|ZJd4lD`-legpkN&?|+!#@RpjacEp&WA|Y`%kHyOi+O>?mtD3AnZPq9V22mX6nDV z^i|cAZvNnUk~7Hg7UA8)knvMptUDi2f-~*oX?pc(BK2tmABEP=`Nl@{lXd(o1?r8o zy#Ip_-Pq<49}{oGpOPyOXzU6@|7oE6SAm)8dZhmnHt1epJ2U;abPfbM4m94mreO&Y zeZuSx@%%IO)zz1$@n2hlnf{7L5PxX=Okq>|pSn(WDM;Q--#-PGAeqjse-S0qS!JrR z*V1%*%lw4ubVWGkX%+DMx{Cx(*xQZXUW0JLiLL#8K zV_&NN)hEfc&Lan?>wgO>LCUQ_ksH85`9GDf?nFUbs75=F5SW)ce{EZr;IJ(Jd`a8s zZ{=lSL<{h7i6@>x{fCDCCQtE1_K&U}BK{f!U1u3Jfvk?g;+ zvdj3lthkSA{uf!y09o$;A#2y|-**34llS-86uc?;H!hPSw||=jh{4s1BlaI$7FA{c zCd;mVoUrd7(*>DdbtwIMOoaW<#)tBNhGt+A^!Ogf|N1NNKZW@J{1y2B?+0j~UM2fK zzH{*Z@FoEG@zWUp*RLoDTj@Cd-@c>p_x&W`BNPAYE4h1fj_#6c`0$7J?b_dUa)rj3 zi{Ge~(+y>xiofQk-V;ip5)(@MB*#xfE>0auB`R9{DXMe|$unfPM?2_09#G2bJk*>Vh`wjOsfk^+J5 z4E%KCi};S z0Ro~Q(NdDpH=L6EHX2Qn_+~ts{ zlRrL^C!B@N!CVSp19xzC}75Tx@H474V_;2!zm~Om}qhh(e|1&KgC>8RG;E9(*Y~WgZ;gR!0+*HW%UvN0;WcI(r zeCVb$!+fGQL3Aeb&6^!I{*Awn0U{32r%MlD|d7~icj?mJ2dN!)fA??4<@5NiI|SwC|9qlgWJkP)3ri;n0R1 z9nE?6`fh`G{XXgoGr8B}W=J#kF)LIvpf!yR9Q-%W0nJ8C1 z!y(5-c|?YPR+zz+#PM>WZa0lqPrg>tHQk*be}p!)RaArEy)7|BaOv%~ABu6=KL& z>Gy3%(kS|(sVpBx(Z@e%-c7g>!2#|L-w{MdwJN$Hs8-lj&no<1pNuV4{JRs_-mscZi|=V% zuO#rkcFQsH75f1zA#4$~`w4i$1gknaL(*ur6D!SeGUg}4L>HCo1VS0gpL~IfQM?ZHz&YTKCj;XO!?L9kj+sf1- z`8wn?A)QaFMGq{;c`wH$T7BcCyd#29t=Xig2VK^BqvE!McCI^iX<5gBMG{?=T2bj^ zYZ}B7US84%ojOQ+za3HZ;sPvf{A@z~=Iv4#;Rv@e}E{OLGv zN%?(5pa6yPbUe_{PA0EwNZjbDp}kdoPAxqySG9PT7FhQckkevn;w$kRkQ`V$^I=4< z--bfz6$8=0&S#*@Vx>`5$}kmzUMCi;G2Yv<{<*qfCw`&j9N5f)b-w_c7>R1znP}C- zO0f8ll2Yk;xzOWId#@YOH=j?BEE#ePCAorKKecy_D_5fI<_?y9V&s3{r+2%x1xv?*Oj1LX9{GH+%Q z^?{AkoqMUw#HdS$vt{rZHSuKTRgXZrfQk{Fn#=4f2xWPYxF~=PU}Qe`0$FiTuqx3*o=Lx9_qP$pd&_Zdq6uoArb5~nO~-RXgA79A zH78^Y^{AMNO199UUnI!crT*ceTBRb|*hoqL!q&MCK}gjm74kOl-d@1;he2i2Y4_l# zq62cthFKc~j@EkF`i3u@!1n2DglFoONm$={UyfgkD5U%%72;h`^{cPyI{Sg{7)R}e z+WC*TRdgg4)!;8ffcO>M{t#o$f=DL}bS@y%=en_>>O@pZd zkTFpFjjxr92dGPScO|YM1NP2mcL4u_ci)of^K14s|Em2OTWN*i+0O5^oH{>y6PVKl z5b~!+sa^&Elhl`=4f#nQaPK^%H>jI zuVMY$y_go@v2fZWKIY%+Q7faf+ddmgJ6Wgyv711`FJGS$%)Q!GULe1TPbVDd75jc9 zQli?_oOpy3SQ$r4q8N!W8I^YrbBLl~8W#$WTadZc(3K4*0@J_yJ}Y6VW1iIxuREs ze2v?dT-x%hQj@XXvAAwna8|`Y-wo95FM^!Y@);IyDA3|NrQ8Z`o5_slBZi7BZGECM z$5tB4njKdR&dvq#QTm(H@_3D069$&xQ(;C{LPmFUi0D=SDH9<%yTW0ai9y#lfjUXz zLcC;7UfrAaa=kSjShHKYIY;9=n?xv3!J7jEm-T~pz&JOOHGd;pMUJlL32NaBrx^G{ zBS(m8v-O~cs#JJ_i&_1Yj%TmcmyO1S?@dRJpf3^R>Zx#M9x{K|HdfI}5*K5fy(37< zpUNXBk16Ou@{u$<*SGu#(nv1`ANmu{%0mg#r$UBuE-QkhNS6!>n z@3(ApcIRx@NG(?+VJLbovlWR3oSGos58b$BM&=d~n3Wd3Y@rOQhfai2S3_s}CTu1) zqfFmVKETujvDyC4+H!z`z*1|KZbK$z`4`&-(u1dbrKF_B`ng~@XE2lOj~BruQ8!Ug zy^W(NAi(<;%9zwa4TFkS{5bC9&5v1eJn(5ezD@5{!yy;ETZT8Y=`)A?L$Pt;JB>#^ zk>%<$KOI`bXSu88Nf4J|6dX&BzGCydwAylVUvOosT8FAV#oO@=%EAW$uC)J0(UVI@ zcjJ{u(6XQ+>CsieE>PHmHhdwOD3H-9;BLB3Fz*;eaaRXCr^O5Sm@oBtD=xo%l8);o zi5r#Yj>qjrAGdi~>vHx|}& zN&*hZ>*Z%1l0K~pg%VTN&pSGBJJ})Zdlu6Tp%qv2WdiJJ!M2m>v>|*)IObOeE}LDM^DtK@6GTkg&N)CzBkEIxl; zYP}?ToZW|~I(4-R8~?L-G_^b(7!2MyTq*1|E5U1VD?jXrCOsM zA|RH*>n+e(>DI*6>)Hap@F2jB5M;eQRuHZJ>r?(i4G%fczPMC}hBW(9M<+Zsb@mHh zJyS7JpiM=5c}nlja|q4nlcG{jGqM6&Rf(&> zMMmnMwr#2@QNIn0%l`zP__!;~mJZy`y+NM9P|(#2DDPKuj0XBu)SpynfNB~D2U`!6+G3pUHi!`I(Vf$I)Mpm% z_&4U?Q}3=FOfLV*6Y?3Z#9TPu;xK$qoba2r!-iW}4d&f0xFQOh70ph3_H65VkgH$+ zmZemZCBQP9;G9w+9w$9`##gqt<2 z#hCR;S3F*UV~sW52o${1&Q!y0%K}GsY=hf)q}*&4zBtmh-^#5sg=xx1%gy-vK$rOQ zw$fKM{#NMD8E5%Moa5*;=MSD%q8#N8n`7$-#z^I^OTx#+syPe0%Btco9QEn6e$+IS z5r0j-Qc&u?b5CXrUc*(_PMNYlS%p@{rQgsHrkKym>8bCv$1UkTkd#_ulRF~g|Mg1? z{^0@EY-`@{UfpaU0?m~aHwt&A*w|;e_u}@dNtmk?M&2adC6>}NzgGUbsh`z1&?J_5 z$^4@P9P-O<>bl=eZmKC%*5c9ay%hurV8f)O48yzWsb~%>Nnbbihi?qno09Z*i{U({ z!+K*>;rB^bq?ZrD2g7x+cNGpB9mKa%40MbO*cvm|$y&FZhTUdIeEPF|RHN1b;n@bV zsE0u)0k5=-_0;s{N1E=<>x1SB-pm^l#&S67ucD~) z!1iNYZo@ov{`~t@+H#FYec7n|jKh)2_;iLOvZ#Vs7F+=bKE5SHaRUZrDdIKD97E?# zH>yEid(vH6fqi!6_p+Uj`qqSR-^{UYuv7Ytl-DY22y>fb#DQPl=JoMz5Q(lwv-Q{~ zX!09Y$q!Z}-Oy$EGY@V<1-w!E6dpQD%15c^I`!c?)p&R9`8(HDo3vt4hYk+hq_|3ZIWxRG^h zY!|*IvR;N6*!`i~evMa3m-oDy@xU&l5Oo=M%SWe(Fp7ic*SB*t8j4p@zatneD@%Mv zC<*aor4A7i(ja@YlCr1A;Ns)2!f5PP@pBS%DOA!|-4Yov7^Bi~QSa=s3RXOAJBDNi zIy&(?SY?1y`luH~g9KG0{;T089~oaC1z6_MbmlfJ~|TBF_G9yeDL zZkqHyH6Uz4?MfA-PUG|o43Tn);-aM@prl?nd#L959`MVGOffMP@4kql{BfC8jl{^z^f;U4rjcU9r}RS) z*)fC$E}I*V0dp&_f4>A70YtaBx}(WdCrje+g5d6S|7mPThT&*%LE1FypPp#kJ;-FQvlbznHuOBP}Nr zeNT$DW$5EnRPKl18GAgpR9|q+M)sV?+XlRqv09px5{T;*S{w0dXqHBAGy6f_Dsr|aL$0nXIkPyU8!7>*JNULl{?7P`P;%nhX$*XSmcq4*Qn60f2j)+7$ z+%3Zs*r?W^`G|rn!G{9Y>D%`p!P>3gR>f7c;U9l!23Vg48d!hpwgR6`yrVTphm76p zw0<^@Z|C4=tHuLiP7gJ`&f&4dG3?@%r8v#4A%7jMW3m0QXp1@HUB$xo53df1t84%H z2?*WWX^+@rja?IFeT4WgO1xc5QP09clcMguc2wMD6=d(OV6;-ejT9`R|x*O`#*)DouVuMI}+96aS88?7uq3uhP4~ z@KtZs&8@VL!ZoR0;*|qP=)ECd)=h)FCG!f_@os!(q}gpBdoq^fAr`%r&8_w!t7E`G zZS&kx7%q;V_LZjlorWCN5~Y1fRY zi|0jAu}WuM71Zg7Ht}X)6-Pg(LRMe|+}d4MF&*UDfZ0D4A4}cCK>TV;xyDzamOt z970PL_gT=;|DvOCnU&K%O{Oq605ef%dhD|A3Vuj~pmmv_2$qVI zDv0|dqjP*Y)wXfxWkmLa|K&P5BSe9}x|;y0mQD5M)ojM>eePFV&odY9P9&G6>k|nA z`f;ni1y0{F>`y0Jtf=H%J)QfnXaZgKpB*x<6h=?J6JeO}$3gc?HPkr`3tE?|Afs0KA$C^I1HejyN3G$6C$~7t&dkn}!Li z`g4tLHbvoRq_#{g6jqa0b>ZfBB7r(EW0di#%-@e3RH=oe4*Vf$JHHgVs-h9b6&JA> z$0JP6@+dj9X4$vKV3Axy>D0-Tw8p1HYi0~YSRq&HXzf%TZo3No_9M@$jrLjE;#uka zjCTSV-!(*On<9=(^(1myN2NZAe?w<iB2%HBMzd~ zT8{wFA8BQMH@|IyAIA1$1ZT8Dau4=b5*%~!V0Ew)`!ue)V`+~? z`h{<16-StMF9QkuJ+A21xGrqv=`W@XvcI(ClV3nVcm)gynouNuN99tNfR!08$|huY zMBCOy0@dij!X^t;_wg-^IFU+?rpNjM{(u)H0Xu6tUedIdrAKk=Ce} zNZf#*;b>7zWSCcUEXOON0Vh6yHNVT4N^2n4xox>0;&k@Zy6K)Oh&bzxH%ONUrEijWxfha&t{jQ!N~Ld)THbTRgv*3ulMKrFzE)0OgW;=R7KOwz#XoW1tJC*XrZbjw?12Pbyq`F z#G}4WN-$+~5E4TfYSi0`+iik9c;BoGyrCN+)JI)lkFUU&-8r^=kB*HyShAa=Szq}! zU6ts_Co4+QSnQqF z`)(^8x;H&YR{FW)jug5tDpw(7L30#ID%Z~(wY&7K_R0NS-!2A(9`$)}PZWJWgFmaC z@b90at#J3v*l!q=sEKZ9rgo_v!TDuJ+kfhC<(Z-tqxw-xVs|wzUBF^T|3W~=$N4Y- z>;swuE4Ez48zw8Z`HnGdz8bpA=_9l=a$pyYJ$n`* zLO?*)S75avm=J4LFP2<DWWyEF}buP6%o9(u_MuemKBJr2~2WvEBD=x?DB`~H= zVL+sM5mNv0Oe)6|1Y+loSypjvo{G@YClQ-|Z6=H!i&Wg_z zRXhFlLygsVM5Z2P0%&+fZ&;XC)yL@M4fyVdE*Ojyr6B#tvRUq?7i z?9DCP6eq>icWh(&S~mWp=-h@!PXGG0GRXwmx}WR zb9N8)?zC9d;`HBJ0&G-noJVi)@Vhc1x-0x&t}-|!rrKU{pX7{i75HbmHOLpcLTXh) z42sk8T^zAX(y^u9zhSLrNdBTS{x+D)f@WXeo3bMCPI&fRiS;i12iLTf?OC?OTB{Aw zAco8c+pAjZ3{NtWyq=9%Z>e_yaIw8nK?4UfZ#u;iH#8r%U+GJVSJ_hoCsMx)eq;R_ zK$fR$-kEXLG8E(y|7g$>=7zfIta3@aR+406_Zf+9gSBL{iTM|8&TPC=eE0@ayF9pO z#&lxYO&9j!mvW1SqXD_CP0t{21#AJHTa5ga6s5f8UF7keJrhrt7IpGjp(n40T=t-< z=DX+nDDU=C#1_VKyNOVMV<3?$_V2#S@@~P6>srujO4t;RUQ5&r+ zKdM*Y}Nt%gIQShn>Pu)Gd>4yOgsYG%byZ0l}3Z~#F9iEt6{H| zCqF5>nTzRJ8>h{0VidCjp|-8z^Xi5kZ`^20O?4t0m>8lK{Z1LS-3$O4*Am7(2d4g1 zmq^o~>rX>&OILR=%92lOGI!-A70<4`8zL9Be2+F4X1cNZDdz97(9(2_?ApOVxt=-$ zSowwd5q^UVs_wi3p309(&pFVop6i;zevl}=CER+Go}Ed^as(^XFyY9w&$DN36uFMp zt>wGE|7Jp&{*r1zK#1(fG({JCj7gVZG%hAf;GZxv{HF|8Qi4jTOHm~oY zMkWYG<$6i}^*+z}pZj*3wWE%;_lQAnrlG2zI8cP<74xkPKX(k#G)-VPxzcsw+!piA zt1C5T)+`Mlv3lb^z{9Chk%+?_Z zX&PPAOeF@P^_tGoY*CAq^tN&TgHygtm@*j@?$GBh=uy!;W=3j!%hqy(KIf);BoR$z zz#Q4czSubFX8Xgi72ZwXb6lCV8^NxQ9}936tI~BYGKc8?N^bpp&#m9?`*H5K+cQXr zN%y57xr--}txsPwsfN^)zX95;z@92P%3Pg9bOQ;u#(dQ8pWE9^AyLd=%qXx{z>vHD z^j6u(B>`!>`Rc?{nX1i^!098+sa|!W$GjMX8j!O%a*(>7?;U(x-OA0z6|J$s)%Z}u zsf*0BJ27Jp(ui$vM&6FR;OT|R7o|6EB%-%FVG}dQ%KGG|>q$8%w57*dK<|aid`I!! z(`EdKKhsTd@w;i`0UsHR2~CI~Xqyis+&)j>$5ryt(T;vdv3GzEdq543&rV*ew6N+B zB6jnF;f3HY-K-q6;A7&fXUEAKTrVJt zN!ss@g&#tpuH_ZAsL2+TMggF;sZ#3yjBL-|F?2qJx#rksGEjg6)03>$ctt zFzJ41dztmtXQTwJar=HL_KgcBuDC3JK2Vo?T7Saq@*4@MaEfMT;lD6Pnu!R=prWcL zV;W|)aVkXjYHs&LNE}T>a~MoRPVCQb(6%ACatpU@MWpI3jgnGe18xiVyX}IF=J>?StY#BDOCq(KW}v!G3F~8V=JwqYwIMz&AO4*69kCgZu^iIsb zH8AE(5s`rjJuT_FQ$wmckpSaXnsofdjJUD_8(RcX=+{J(WCklx`yN}lVs9(oyHKgF z@}QTD>v!i4Z1@Tf((9~6xZDhc=Hc{DfB6opPZTDsyp!@Q?Mpu*dJD+FuPEur!&?$w zkHw}w(t7>*-8#pOnN{Ecn4`2Xr~R=nS-nSlFRaccGHz+@sj#%gI-O=@3)tRHxYexp z$7K#Zqxlg2P&W8LTKa9qF@gvE6c)cG3P|6zTd6-MA4= zp~Ld2Q%ko1er%olhcNi8aR>z| zDIDkc)w)%Y<F231;Z=6PdN+DQ^$k>$kf3-CCpi3an< z$SrkWyK`*?#3WRHzg1Il5LoN}eJo8|lo-vka$}}6d^NV;8t+EzT(EBA$NZ0n_X-XK z%q%6W5mBn|lEq&9rS-xby(w3*KL{+!_-!T`BM5e1nm!a8*CAU9DWXGpl@{2K?PiBx=N%rIxpZ-(ZZ*+9bjw^I z^^UClb-z2N^VRErjUQ9%vvuN$dStE?D59j0zo?YU-2VVG4n^N|${gJ&0?qj6)|eMm zv{Y8|cwUabri?hwa_>e3O@Txu*vTcR+2{N@rI?yo8b`Uo7aa46jkC6NS;7PG$FFYr z8&lcwjae0M(t61+AF;~$hNQ?~=?5em`t@hmqHtQs$7OYUYp?!Yz37$CG%1SVy<~OUYru+E-)xJwS!^fFdm%h@H>DP22c-&E}hdd zrkbDpUdio>D&qVkAWNtFS9~Ln)A`ro&7RdEBV@S zYJxIMt@Ro&w2q)W0^i&i&;!nBxLN*|HMr(pz^d4Yl3w`Yt$iUuI`v|=Paj@*=yR4- zB~%7pwMU+2Y7m9hoK}Iqt@qfVG)~9(M^TEtChG4O4|Hy7)rk%J7Kry^2crvOo^(mb zXj^sW)=6OUb3;n>DtP3GR>-H}jZt4nDXnsBbepjry`h7A45eAy z+R?q5SWd!SW}c!fcN3+{#e@H5>e#b&nxBrcWINZEo_|i^w&4!-d{OM-Vry-|O)fT; zT>#LuVV>?$x?Pc}Sk{)b=nf($NL++oiDcp=KBBYZPR5sAp=AcYY*fggq?Y3Cpzqu7 zhhemA2rx3rpRZNsuGlKA7<5#9m$t4vl3)v^G8#WOI;x6PV?3^7%ic{CTAKfH_XO{d zfmpac2A=neqH5Xnc{P)Y{DdI$S#32(b#kMh9%k~TRu^N5=@Z&#D5kyv?=t%kp%Y`2DuTozGV#7j$wJg8zzeAG`5HEq}Xs zS?b)VeyI~?U`E(CYBUSJ$mxY1K_b=5_V16IRaO=@iU_uv{OQ{_Ac$=;)?Fy3yGxCzkA2# zEfMiBLBY4!`>$7oG60&jo4dyT3JM6giss6>(Yt(J+Z>OEWbDNgt9^vmZ=QSCN5u&` z#)SnjjXFjdp3CU_qaa=1Mht9cUL9pZ>>1`QXl3<~&U=*s?Y+3CFb0O8ia#T7vbJBy z%^$nF<5;^(s?V?5h*TVKSRh`eDxiYYIj2r~XK{EA_@)Y1%M#CBqHkD+)0UJtwXmBA3-+0+wX zjvGt3=cte3QPK>zi4l(D@8Jr9uCXkA4V8-m_NA%_W>^y>pmE_pzwKMYw;8{rhVT$u ziaN}7AfJ~e4H!cAz_m2B?%D^g44tZHbTkJ&HmnG}kJ7m*%Ci$N)w0n5AA-lF zmSSDv-VwKQ`8n|ISULPHe*W*v>Y6Lv;%kKza)3@^!w(WC@jy8rQ@!krpwh#PIFGHj z$(&q1^)k6Bq1|?(Fa!Fv*s4nsU8iTkhgw-?rM6^bA(MP*cKDUQXHe;*UtxR;>MMul zBW}Qu5BOlDst|dPnrPNPm&D&+>5ds86C1W!asl{L26(B$-iSZ5bxDF(1h0{Gy*7w;h8ghh#+SjRMeyzPHGqa@Kl z>l6Q+1E%+qMlk8Pb!U$d=RI7?ULX{Xh4-#T#&1!j>%kwRxvoxriAI6mm5tDo2y=G( z*fKH(jh2Qw-SpNL{!-;^9q=Tr)%Dy90*1YAx4Qi@-e1B{_hpkNJc_U>xiTc2bYPpB zVhc;-V-$Zuj00vsvrKY66%%PgZjv;G*-^{>$^+c}S0R{Vd~PwaBUPdHKxm2!i9a>S zbU)-P>>`aJbQ>b^`=HzBSFG zgIgxOI6lRz4+R~SU;%j|^M_N|+%nYt^IJHkpSDHvI>w(!zgHcu>*opuFy*sWD{2<+ z%nM9D7Qiji4mpek)Br0gr}hNno{22=(u8|2FwhN2WQLbqK(#dpEqV^hM{y1?WJ*^g ztRprX?tQ;^wjHzyfmq$+^xp_8dZ_U=H5r8Sk$%1^--$cssblC?gX+L@trkw%O4H8Y z^)r-C$%ozh`!imOs1(!Nt47V?NlbCs_Oj~c9SbAilC0+M5zRaQa33;H%bOjd3dEOU z!#PPM`K&OfOfNzcV2VZhGVq}#UjX-K&I7Oi6dtN)>K*j-|D(Q3j;LRN3Qh;D-r}R!$&Fe%kX54AJ5)s=~an9s-Bq( z_$l6U%7N~laR8((a{e9cg~z|u2Yx%IJ#1UM_yP|nWp5%aNEGERoHYnoYOCd+SW)SM zI^TU&1qyTuI;0?q6vLnZgHYgPD%l?9c^7rf`tqDLPN16PC06>$Xm&Vwbj)=u z2XjE(oDhhR#3M-ua*JwIl=;W!?^Zq;ZnEzQFFAK;02?I5Get{F|DCJ z4KYR^e~-^RXs@=bdrF%}$N7tQ zRfvDxiii;iT`2J~mc<)5?jsrx@yYliw~y0B&4Zx3!W(yN1QkwW&6v6QTyEespKvsX z=U3}yBrUw}N^Lrg*tGa5E=ua?MLdrul{e{P<)7_Cb2d;WUZYUMs}H2b*qzuk`}*>9 z!JHQ1r8XHPUB?){Z2aXPtDtW!snO)^j8=g)x4L3^-oAH6SIRJR@t>nQ*h-3is#2M;R~zD6r}dgomM+@>$UJxFMcoj7{!iPhq;pXO zg=^HdV#di8sRYg~i3?AJnQl&n8<(wFC9vx0h5;)v!4Ufd^QtWGLvuR}HQ`YO{oW1E%b}bwpWXI?5@kv01;@{)M6S&NpXWyym@JWDnD5us3@q)?; z^ZJ!h78gV{sQ4>H{cPf=FHh03Fti7!um#Tp(91nCh3<<1Oxm;az0e000FZ+Q2*pIc zu$d!++x%{E@HFO`v9QR?H1eP2quJUbrkIs$|TV; zvU3DA)fm#*>b=?5Em@cgzngouTTPWo2S zp5CO9s6p@42ET`mx*KY}W%}~SB+-%>t^N)uN{3u$=poG5`YJ-(^{{%|ASo@?m0eECYDB&rUudSWqRwkqFMO=v&D9s5AyL?<)BtBYpbCigS%%P0)3*`!C72 ztIO#k{1Ci4p#qlQYT1u*?=qhMW`1*+6es#@p_P~&;E<9CSh3DdJ?1PSMWZ1e>C9!f zG7dBw1GL9(bQ(-|;UHa~H9zBk*}{_~P!MPH><*ifWif@zbA@dguV%@Qr$_IBf!S0} zzAd?uj~IO^@Z-h?eWj)2o`J5R_m$EbK2$K3_0 zLh^0zwJBz`_4Y}goiLw-)?4%3UHeW>Za}652Ms&GBLP(AvkdXBG*N&w9?M-lNX8r- z7c$)Ly`qcAz5>dRB-oM9nq#s*nomJ!|DF;NJ--un9>1Y|owPyM5+M&>&oNgGU{?-4 zqbV@J1waBvI^ekAIh;JD{kyWN)qp)&ZLFPGZuw|vE>H$_cg!=huxV|7wvH=yBSto{ z()VjQ8u53W(x~)--fu@m=Ga8~ixV98Ia=2})ZgWMS4Qu=qRVYqo{F_ho2STKS^W_4 z5@2y#8Pq09)7MXN)+E*q@R50(!hs+^n@65s#nkmjS-{LUUsrwTdf-NTZf-VWG}DE7 zOas~dTFeX9`YYmFWap_ETzc_g!$gG)=95|ox@AWVWA*o%nWo&Io|0H>kXO_pE1OEk ziDYocA3NUbD%6QCK)!rLa68IYCja==+%Mcy3@*1Mi6(~)@5R^_ATYTCbt_bq(~SZq zqVT;U?9n+6_-bf24%*@zK7J!-wBnC2KD&p{#5hc z`l|SSGXdl1Ia3YnQ#$prs%LBE(TN7L;Z#>%Y1bt~VM&Eq*_#uc$aEI?t&mlR z>;jV)j@AIzo9&j%Hr9@1mEFZF)M{+f5d(^a49#t*<`MB6y;rRZTB) zfv&ULI9l_Xm1jOc`Cn09OMe9Fuhzk$Q%dJ_Z$@5xP9B}H#-mGw#Kup@l_>0C4*=;5 zo!ML#@aGsxDcEaE*FiXmvnMAXB?#?-P(GRHnvd5mzp{ep`t$8o#GX~!*Nl-5=)lC3 z*qcJ@uW1YS8S*;xH6gqKWuuoGlpe8D1pE#ILTM8-RDSy}H(BA6hi)S&YbcKT_wynP z;hJX!4J(G7S*AW<)eWdv_ymr49f36 zTVc&5sqsNCowk&Vx%RC$_F)!@dQ+`eDKZ~DS8eJftXh>xwgkr{#`kHi(nB_@uTRtSTZj{ zgg96axbGL8<=+yTY}A{!?!pT)dLh1c#gdeqRD% zS_Xb^bZd!9SV9wgu&$6AMQqw+hp~>%`HDXe10WdRWxuoF9YVQaQzm(kICLj0myN+x zYxCv3{t^3Ld(T9;Fdw?R$I3?cZ4*106q>+yIzK1(q7mS_qicDsw;lMRq$J~>DL(rI z3mJj*vlAH_v2IMX1TDGU2J+08iMCar8g$wjdP-Z)zFr}57g90Vn}b0}tF~K|wCDV1 zni$PT=khHFskQMGS1zI!QNBMo>Gd=|a-^AI`_;G*G!)J-4ee_1+P9X2Kv}PUxZc?A zcX7Bj(OO9rrXf)G4INQ++t)i|5EeVY4#hw*o`FQrlr{&dNO`n|=x>t4-s>IX*cv@! zz6rgLCCsN9CsM;{6dks!F}`f$6r0yFwpu$YAie^4G@C=vHsrIP-Cmd*I{Q}9pUW?e zd5A2fnO$ufwZoY{e)S3KBxufkP2A9l?u_u{;FY`L5?esUtq%JA{$u~}?TzoBwldCt zH#2*a&$ts>S9vcI_I>Sovgluzk6zYq2JAacJJ$66Fq%W8P3$*&wu!!3GyCE4O4OOi zHj25UG*Grja{;&JYZyKSPP(N22YE)snR9871z5`y1;ZIz6qkuU;+uAS<{7HyzEj%N z$2`W3&CoFr3OVAoSpCP9HnnC z=rj+gBeY}AoeUsH103qAd<#VoG8WtLlIlzXV(YeDJjrKEfEA1J9&R#XZp~Ex!nDXF zcT^G`$6_x)B&JQ4zBaMdoy2vzLqweAlFz7v^0T>8?qk)hvdA)0a!JcNjE?d%OiQ2> zO=!{l5;is2z+Rem2P-qRBPa?=Amz}9a;U-dufUByooiZ_bNU(mN>LGr4byn=npSbjTTrt|E1-WyqH zgjEWA@lWA&Z+fBLSVJ<$76^i&DzTcK3FaNc zWnwQ|Uxb#Bj)m}l=QZ$*B!;M0^Agl{3oEnA$f7XuaA5|YZ18@a$^B_ zGP$Q5a$(+)8h2?PrRUvQV4!kK*NwVv8Vc>iLSIMT^Z+#OIL0*9gtL_vft%vysDHmQ zxnH*BX)kDf_Dmrd3|3jozwX7|nPHdNlEKPM>v6=^xLITN0bjbl%ZB3W zszJjHhYnxu;oHx)M*nMns+r7jV=E-`y&!3g1G#*X5kztNgk%{3jq>Jrja`=ItZhb^ zL0;GKLiSgaC>k}@kY1Q)x^9`_B z)1r+tbDku0|C0^=!L(1b#+_2@)mtMQI^p?4>fN?Q2u5=m?V7FCK)FFZ(a>0SSuv^m zyUJCqTwvw`iEKmk-`cv>idF1>>+!{H^ZOoO=lRLQq1#~ZVR&r06OC=PrfP}=NZ&^6-KR6nQ)~@i?p)b2X zeXWDV*RdGMa(pWR1AX%FKfo(8}wO=FG-N8YsdirG0Alp+D zVik%7<(8*jaVoQuN54cjTyN_HRri^{2;#8MtTn^{#q5dApvSVGGLfYN$&sej2TvDS zYPUUnZ?RkMV;%BadiZAfFXFB=+4firhm4|`~aBS%eX_#K`8ROVv z<_G)ey!-51FmtA{}h4p}eUbvp1^bke^n9GzYl3%W|^t5ma_3U_bc#%J=z9 z_HzBk?(feJEZ8Sv(DJTt+CjID~_F2MbcW?v7x+U5+JvUb|fTI=TBmRLsfS+J@$po=NHoP{udaA_X<*RABtO$K1t_eAdIx5I@GkM6f{NrRj*NQVBLB z`o00|vHL+000|49enWK*@wQKbm2Fc{$`g)HcvY_uaIemqeJ<^De%u$lOs&Hsuo7u` zL70ZuU4Z%r)hb;uyM3UH8Q4^xT}PorYZNLVVzPLjg=@dpYj7@|tg9em2FhF2qgA|M zx7OSI0srKd72#T`bs|4C-z29vJ!=BLquM?$m3~yn0}8Ej=M%gXnG0ETAZ4Jg=b&>h zUrhva?DZj+Bt0rhx+=pJXgoJlc2~X4m4&skcLl|SP$ohd+8yMB<~qbK@$uE_%aZn+ zK8~dtm?m{4wKb6&T@+s|LK<*>0E<5E3SV2G-KG3w@H4ZWXh>7=-W$Cv5z39lo2!@D zbrKHcP8h8!Y2``ly~oTUnjsG=sq{`Tt#l=Q>Ac44Nk=zOYp76Y*Vygqwt5M0InW~q{ybM%(XOy{z{KRUEV(STDpg3`lTVzB z;8DkGg&YF9jp~%K{dB3qV>)v#j6FGvph_{PT*Z}sJ~ZblpxVF>U%yy7^sM3*hY*{M zsisTYFDe}D@TA+PiIvNpVFTaR7i(WK^68$}L;-Xy(;a>wv9clVkgjoN3? z%^mqraPk9OM;rJJI%GT;5MbNFt-{4fJ0-+&T|b@`H>N#iDXyz`|L z+9Q@nbd!EdycU;GmrSOd1HGFV<+>}+uil-#-^P&31(cC&=bSShnMWM1<$2FgOM8im z4q2|-X-*%YJ67}M4aSBq10?~CGQ{BSDz@2&qV>>km`xzXtIW)T(y+h4mAEs zbzLMl-^T>6Pl8V#Z~nMsSV5{>+wKlLN=`Fs2N7V2H)XJpmo@K4K$E`A;*$#)Mj09f zK)maJcZz)ZbF9$*C{yWs=(wPvEJv4CS~U;IjE8~P->zUPJ;iW;N_UM0;hFhfzSEb5 zeNoySDG)FtLSq2-W@6rf7Zoh%{TpuXEhc1FBYQ=#05p@c;2D=|!&!U;J{C(_1}gn& zxPWEFL;;y?k%UD&+M=g>aNnkX-`MYp5gw9IshJUo7 z$7Al7@yzdE>FZYOh8Pn}&D1$kzA$rBkuFMnP;7nYI;r6yE>P4Of5TN408yuzd6J|) z^KX#b3P%C2O#0$U!cu-Bmsr&c*c6- z^VQ@0K%wQHSDjw6p?$|`%v8DF2^T#3eJu>f$ClHk>4egN%-T3nA8mj}>__**i1CuA z?`6CgE8#tN{Z%#8fyE)yIJxOTmbkQ$%aEj6nbim#5{9}&m1Tqj{|Z*&F-Vbmn#Awy z72nW6Vw zSnwbz-!mB+eodXP(F{Lr($}z%y?U`n6JNpg+f*lEI+%vp6QymKS5w+W9BK+c3g&mA zlol>_C2DQks=i0kWO|Hga7$A(2+9NlGF|?V*j^6@W;$8tvDT8jx8o^YHn~EMMxixL zOQ7asPMRDY0AXU-bI0kj@oY~KzV1Y+k$KFcdjZ$U@k)oFhtkOacu`r84o0^K_Ao?y z$jv}+E%+2kDig=Z`-Fe}>b4t;fF}`UPJP8F^+kS$C#sEhzjjUJ1&T%$Nds*69dZ&j z222Pvn;wJ?Qpd|RP_I|2=3rW47wKpDefbS(5qlpI)g^4L2Y#?3-*!VM#&8k(pS)co zRVAvpO-@Lhx0mfl-*8C6{#1HvO+-C@+~$%G*ZKU)BQ7o`gJhig$|-n3P!UyfKo)7s z5`8GQUy0jo_-f7)X0AhVT>scTo7Q=dTT?OwL*I3Ym);Ozcm;3LNK!7eBOnNx4zhUv4*WU_ycz-X39ZrEQb!d=tlwV-i&@e z3~0o0yhb@kY~ZNjs~c^$bJ5tnQhN*97qVX$+e~cpC8FV$8X7mJ@g2!6GiM^aNlCwty;HTS)wuW; zIj_>oKXiiMJHbV8Z+Lg$^cgP$R(fT(+wO-_h5-VH+a9VoT5IjyRJsp z9`)(~(W-b)p+KHh0DPCcXr-#`Sxxhh#%+I=p^mm>MiCy3((cHa8k);h6?TndE7Ev^ zE!LrgO4XxFxM_~dXnm7l%C@H}>fZW25!y-F<@T@JTqICVLrkjdzK1p~4EvG^uWGS} zLJt2Eo~z{fL}em$=M%5Xzb^soK)Tdm+782ge3Bg&d! z2ix!(rpSSYKWkq8y8RqMII?o*B0ZR3=3xGm1+o`oK1oH@y|=9F9@OI5(H0^4vsOvz z)ouq@p8XgRW7I#feA->(n~J46#o_M9UbD9k4GJjqi+A!sMY7$pm+qyrQl5^h;#}i8 zMR9)Pc1eG=&2(u(UmAT%8}$dH*==0;SN?kd=y`9a^yDtx%aox%V)~06FwDg~v^q3p zbw5gZDR5(k)N0$kKpgaCF*z`)0qOyNvD!^;_Qml|Q!?|K(SG~q4_?o1F~Pu%or^~| zJQTEfhcF^Ho_l|r?!mHB0pdM=`}J!6<+{d%&E+67R*b!CeY8Fs95T;w7?pzisSumJ zK}`of^O%_6dTp`RP5Xt}Kzqu=bT=w5MGPJ&3_ngA_mNT%lzgw9J=+!0cVoTsCsBhr zn>tZarNA6@h3MFWgM@o zw!b-YlE>00Ud|~g-LKDwKun3*W3_7>H8i)qm4Yb`g#{~~dbo_8Eg#aLyd`i}M|3!B$*mDAIt!;o4yl-Dh| z#|YNeaCEy8=g73qP1iY7+tyC2xaMu%KI6f77$`c$kOTkJze0vCXa!NUNpfTsP~Xw1 z$Q81eNL}KU8>xYe`=WKQQ_SJYy;x&mM2G0l_Cz$!&itbv9vK-olyk~KoxF>>^&ojz z>zIe?SIr8Q?P~GVtC`oR>{iX(SJvc63eZ8FrI%=1WbK!WZvv5V!Pg(`@=mhFH5pv*X3uy&um+WrxkEOAa37OiRU{Vjyg-r3>~hp)gzKJlT+ zNIB}!pg=Qy!NscD^Wo%&X^qsR<_MD zU%JU2f+yXmcbfv5w-nbAi7fH0K9iSS(zxbt*i*n@uzJvAY8jevXGQ5qh_+y#_19+{ zGyT-d#d>{rBRLEeF46DkwK@_TS6WcTrA9{`G8|Q9oHd z5%F@SkM)*)Yjn~dUNZfqZHWKQU(tBwYlupYi9@3PYbMTjPA>g!u`aY-suYo%D} zbjQvrO0UjTHb>2qytM3(HvY+3`VEh90a+czUvo0}{0lFFqSS;NFKib?X2o9=d9Yb6 z>Df!v2Xz(;Dv>)Kay`1 z%G*r-sDAY@i~T9(W{_$2M?)aGY0vq}AEb|0zToaZi*3mQnfg6|yA0+s6pnh&l#FcM z`FbyhPk{!q@!#Apb#tT(^x3)9q_vD5whi3(xO~CjqjO6`k>2m&uVyr6@Oj8s_{Ia` zq>|A-Lk3if$BO6jB*({PD_#rZa6{8lajaOtN>5&IRDq%BoF9v>t^H}tUydj_TZ<80 zI`!_ghP#zL+jq_3-J9*l$3z7IrXy6oWXai)e$@9uZY8a=Per)lk7bpYiR*i23yF>! zZo|qDw_c*L#qjrMUp<4ii>pQ)l0*+k-;oE2`ZoT-%=0$Ux3S!TP1(QVNn@gHy1=E0 zn0%~Q=6InyEa+x{YnFqLnd42hAdv$%XAv->5uD59GQpg78~wn%Rhg{{*)A}1al0`$rPLO zrCJG;Yp)!b=G4EJ-xnmCW7&9GC~xr^Z&2~)bxo<;)3Uba4;(|WXM>83@))|K$dc0Y zRMD|zshPvVg}sMuM`gygHXaGR=@}76zn`IeUVMgogVqKLpS+~cc2eKdB_La!qtq1@ z_N7Rz`0)gISNCjt$w#Rd^nH1}Z}4sm!n-NNc4NkW#ScRTH7e>HL|gxPnnx$&DHO@a zCO~N+GU=~5W0_h~gFyQ6OsC0f8EjCM-ZE^L`;PY(OS2FPHh5|1sqEf(H<+Z%s!7eB^b7duvf6B2}a8WPc3fFOiUkKieMlI5&!#SG2 zg*rrjqTHPsJ#@3x^^1`?|GQGq$e=4=vgaJ`J|#Bx&%7D;-m~X|`Lo_~qiT{PY_kjd zxFPjzIn$D-g7qL&_R%0rOwsffzn$=yS9W}R_Qx*nrY|t%>H?3BQhJ`e=#VPEiy4+&Mczz5k!e~xxSZ10k49@nG z)%HUbuC*@PH2QcC1?JpWLyn3V{rWW$9zvk(fu*GxQy1qxGhgToK(%*{`SPznWyQ8k zYtJ^6+`EC+mN*;YGTI~@W|of?q2S_(iyFWx{4`)w<>=f2-U3U9WYa%p&x69*nVCEQlE?aw7(Yb^e(z$*O|H5 za`3`~WT5mjWVpjzy}tBO1L)g=iSFp&to#(=LPBa8$;!N_lQT|?4-tA0Qkir%idyNQ zTq`i%dJE5N3lmwN?V2o{4w$CCcP=H@a}e!4)?xUx0=df<2;?rDAr{t+sck4W6oD zU9nR{sYA$qz)-yw1Uhm)EAYYl7}Kf)chEC1p-4M!EX%*OESILXg-X384qmo+%W1e- z94@?Lnr>)Puya%2*T;B82*NN@hU2dDH9Mkj{Rw4ILGjL@V7g)kH;yL>&mW5~pb0z` zB+Cvl8DUF$aGM{4D@lk$=auNp-={Y5YsTtL4GR>UL2V{@P=r(5c+xpJ9rTf$L_CC}}R zD-$kyDJaJ_cP3{932uG@KpvW!CvqnA(jL!%=?UETj(pB_C5gq&I*_gMs0(2V zMrbJr@`={}9bTK$cP9V)w{M41mUozw@yFU$;)Q2Uh}<_csPrRPM#w>jzLVD8R9%nSU6<-v z5$P|~D@SOV4|}STZeXpb6)N6`vw?fFMK$225h`cCL!jq0(g!yXH~YpXLC7!Bn5{APZ2mnj-o{kWO(*BqPD;IwDp~`(H6lCz;=UJ4RD1<$8RP2`tsE(&n zMe2?XWQOz?VQ^U|%8*PhM_9MfV3P$VgQL%@@&5sUc74FE&N~P}*Vn-P`RBXr53xFf z(zQ`%{NG5>6_G@WwhOk`J{>tbU;US1iHC1+fCkZy!PnH^@;USmm?Omtg+9gbc$x&~ zJn^OY%}Vt7$u_#!bHTHlfe-oh(+;iQV~_xiZK?^pOUvThFs7w%3`d~Vf;jh;>wRo@ zQnNcq>&mU2Z3RtU%hKTXC9f}#FOi79wn|hAiIVvlG_3cLrPmL%WsmK5C!irn?lt|$ z_(m{|bPq%ztQ7JHP5$#;`c>GOV7)EnsE2>8V~3kl4Qre359heY^s{#t+fz($ z1RFwB3cT6+K3UW%+0AcwYb`sPGRz2FKJq`xiwv^2T|CJe3x6tcKlr8IrR1~qd+T{~ z8Y>;e2Lf1n_sEB=2gnXvx-LH9xSzSwbs#C2k*H~LEF>OkTAn24RTkqzC`STNFHjj7 zT(RoJRGL8Cn~%)A!+EaaA=tzep@nbry*jMR7@Eut{U zRKKH54qza}&T6u%LGiiQ_HcS?XNX*C0ApgUO{_S;!yEMrC6;G}i&3y>YJ+-c(0-3w zc3MI`mfK4*TcRW3N-wCTKb4Or!-dFAm#9{oO*^iYw>CeZ_RHHI7Hk~s%5Kq(C2~4N zL|SWM`xX>h&z7ZJHIEa$bsSjvqjOQDArbwfwys3C*6Ly279k*nF8t^X;m3c;IhBSgDgo&H~Ac#rQKpl)8}afqUkmNJ^@1!=MfPRbVBv^D|J3_zax^m zzuFeS0nLX9g8)t zhn|PCl>f`okup7)$l_)=9uR=$Nc^u2LN!i@3$?m+gM`1ec^a*H;u68vIb>vHyJXU? zcIf(V>mHpCuW*9WQsu}v3%dMko@}twKu6R=8k3VMv9i>2?gqLwxnKOKSX5X!!O)uI zdm_AUwKZX#M;-sbm7ww-dZ;){JV}Lx=1LWR<`9Rh-C-tv5j{Qm@Xm5lNRVif=D!qr zhZtl}D+9?3w6&f0x!lsMfx9I-1nH9>m|L`neWw_GQr25rO}f$t8NP{4bPQB9U1+BV z%x#(bmr=#5IjSR2`Hok5VeP+YcGV|$10Jxerpu)miR;5w&d0g)o`j6&f7$q7zoX>P zo-K;|M*2!KdTbv)laAv4Ao^F>V%jAdT|r0wqD$yqJqasc2{-kBAtBO+Ejd6dq{dHP|Ee~G7B652e~MpX*;$M{}UxJa>LZ{3wM@xKYQp>c-LFkXs`-ATX4`N#5$5C1D* zBp{2DA|}A|Hyh}#eq8yX)6ncUQW%t3U1kos>fLOw2HG}}JrGraQB5pfz`vUqSY z;*LQVcp^z|#sRw9_w20TbNn(g8)^3LKS6(t^1Poa9@^BIIE>6*n2~T1{2e^;XX_Ae zjT_6CT{AftPAx4v&BkWyf2D+ow}6i$-4%`IbgsWgC7PPWe|Ym>JD(Xty!i~uSzb}} zd2P8TbLM1ciT^D?i_e6RcUROSDVSDmIh3>0Yg1*lI7&Gw?7!ZA-~vKbpPvWf&){XgfHtifNErPmgxM1|TUp!7 z*(q>|&i-#EJ=y>A17pyhM_n#K_#-E6PeHAV?dp_&^T&jxA#sZSa7S=HP!U}3`T4v; z^Vp)7N@D>4bRjC3gSj2k^$$l_BoEQwpbFxfXc%|SnKcewjX)*_)U&oE3(Z}P?h+{% zV&4(6%=sC1KyGf+$^Yo_pQKgGqYU|H<2Xm^xcaE=|37D%B24S*ANx*zz4D0v z>+H(osY?5}ikKVP6k>9ln4u~6oO91=vwK!4H_L2{nh4qw8hC6URLOP>%QD7rKIi&I?rr0@>FWoI)CuWP46@O zag&+^&y6lwC1rYg^LM{f?i*qtmpc|b#%NuAr=%?PL1nNy^{(YjhHkpI z?pb@W?TG=7dolZlpqMM8rbbMS15kRrXuz0Jcfo7z)Qy#=Mm+hf;s^c%oy-y*JD2vX zp4KMP2)SQ4`8}^+x`(_2-PGm!3T*hy1kKLl{yJ9uV2sHf^JVsC^XQXa$zA2|LbAYX z|DT@g^#VV5sryq-E;Zp`PQ1m&-`--YY8K_CXy2baa*o}xaru)y{U?=by4?FR%I{v= zcvDeXR7L+7k5>CBmW6-2MFnWxaEU9J)Ooz~V0U=Q?-2=LCZ1gMclf@S6Rb2F*Lcbo z`v2(PmsaI`Lf>^eez=exA87m6D8J=FW@<65rUF_1)EIv;QE=pZo|cZn`oNmL86$J% z-c88b;23v;eQZ%wY38=JZFy0rd#8nMjvqTraNOlZcuANnIx&4aL1RW5 zQD}2w#G3xu55dv=g1{LQ{dG#en=!&6_H>>WuRxYd*WRry2=q#uC|aS@T1Mgh49jW_ z8vj(+QUbq9QZ=6V{`Ay-2P$#TuX@x{W=p_NoBaK(i=*_D@{e_{m8C^xql`q)-1KPA zp8dtP%jP@uW%jj8U#u=%@hWs;)g9L^pW+PHpLrUQrdqGN0nUT*Jb&;8zNCD73f5wE z;)G#elEZ$oz4_o|+5yb^S@0m9`T9@78ob@csa&rVN_5vW7yYckGo5N&BO3zc{bE0_}N z(s$4EL$VG>-j0^Jxj0!^5O}7DQZw1SM?5U+xX+7llYW0nFDGU->03>?qP4$kz!kYw z28~WODrV=Nlz&z7MRi!i&Fy*`kxhrafGd5!y7H;Dpiv9BGWDfmVgE1{xvf71^qf87 za_Uoic#-0j%M$VH*g^F898VN%OG$s*sQTCY{y3TwG2Wmtc$6|#6tK1_L-m11f6$%2 z4rWFuWVEPI+n?+RR^NGl?yCi}28_CHucd1W@MYz-LGg~7MO!{A6)01OeapLpZ7Yqp zm>x@%>8%`TGflK3y|hvJE5AKJ*x!|Y^0@H;2+oSq8NU;%M)&JSG@{8iaF|+Ev zHLr=_WBkE+P5q;pEJRYN*xQ3A82F=)ii6QfCZ2wL2e2ID69jF@FgQ(-e2z3ESr%tG zz9UayXC)O&_&CKfh9rhl48;@J_mK#Kqzo}3CuA_5z}jV#i^qn+V=Y839@4>!B_gS} zOCJ|QhQh$7kKGJx@CwI;hC-HN35L&Nv>{2+G$)jCwiNq#`g%KwefT&>flZb?!8fN* z4NP{zNgkLUH88u%FS#lUvyhZ4$|=MR%lMX&gy6)XMndOT&GYnjA7Z5cG6OK!SN&mW z$$n|)dwcpy_{PS-JX144E%2$@A~4SpgU1}SoXDOi=ykrq0jf&H{4db z)bJ{P?Yt2-%eS>jjkHyJgSd~^%NuWO_tc5V|4?UY@Z^_*9ou3G(($H8&kT=z-p77X`VjT8_tk>LHF2|J8$U;Ejw_ly?oG=s!!-p}v(=B(WzU*CJJv!t zVoHSDc6!v~x``JbxcM75sD>`iFWpdoFsr$1|IMeC0dZMP9lP+jjn(vn_?WpfMwMym zuln6%8y&lExQhFlkovBkqwRrGr@NLHey9DS?=5PLGE+3tQ_7_)Mtd#(r>-o?I@{i$ zb!IiT&3t&ua;Fg|d*m_?%p7If<)>DUAGvqR_X@9T{_D}Dm3KbvDwzKAk2$Z8#YUXX zn_cmHO3T>Nm}h#P-w(U;y+K~QZuTt~ga)b)H*HMR$zX;8zPVr+I%HD{&f zUf0^z@rGMtY@&X>{H9wuO%q?uyj__kSxT3zf1W&NhUG=29RXI^`N~-)az9=< zAiv98wS2GT=qXVy7Hjr+jG7h{d3@8#3hi2HEeXCi+p{bFq*5OJ(J*(U`^T0On(JL= zpERmBYL7p7LNES&*jU2`1uZ{@4aiu2!Es@)dDc;jIjJfRw$CS>jJf1U{A94WB**#s z$F<2jNv5dEA@uQYP3Izx(lT&!|@Nt13} z^aa-TyuNRgQ&#BV`{RD)JE+X-TJ!DY$Ekv*-7g zTWeN(#pq|=&pv6NMs>bYARNz!nTBLv=;kdNdyYNjPHz}d`RGYXEnS-#G3~t8kIDD) zzRRz$ZLS)3seSdMuuuEB$NQMH+ey@D%* zzxjLmM2q3Ai}I^BCXKn*t`g$I+wrHC+p2LTmDh9BZa$q{XD(LQpE+~yA)P7jTQ@Cx z^SB|$UXuHy@+D?k`<=L?%m>?_VRjE~y)x9=|=nU0G^W8I~JOxG5=mQ9sz}e_CqYQLB4sQgh@; zYdy(}1c^oVos(V_u8eEy=`GTtKlja1UiT<)Oh@V1$!TjtYbSIn)`SY*dz)R&!?qTT zSFw{AjLb=ym$CJ7+Abv%of`QChHPv>;2b+64=&TP?!8`5PS=P!uk`x26Fv_M|Fvnj zk4BzSP56%$e4TUEO`5mo8SUAcd!Gz%5wYKqAzLWy9=(@buZXWow1UhHe9{>zFFF^G0(g-oQ=h< z?(xT7Co5XSEbq|1btc38nzrWCWX0wL>W5cKTi*C}{#=z>c1;l2v}Bdhxv2at?<+|6 z06+8bvAu#rEq_)oEZ*7hOR_*9FYuHkiy~iyPQNv=&LI2O`v|?DW7P9-IusokG9p0Ub;oQD&oMfdY2U= z%T^p*{BxJd=woT^MV|uFb$UDYen`PHA5HnJP_M9d=2H9Tf0teT=jfshZa+Pm7Sdw5 zD5-eS<73Lfjg8K4^_Om%acw$P`DLf!Xvf%;d)tF*W_R2O+PrU)%Wv^++kOey_i43x zo^e^`j?)IOTZ4K(AI@Or^}LdJlsGi~+kP;?IMRKwT&jP0`=qAc z+HSw=9-;7g)`w3KXFe;On0Djhw+gbXXbu)+Ge7BkE2&5-?yH_6+z{*g!%4))WhGBm z8V9Pij4rzzXlw>Atu~6BK|?ZlInUEW%9k}XvMvHF2SYAptor+kZ!(2g2>dY6g~)n_ zzWx6nJ3nvndY!ti-CMZkW;Y0%yx>sTDom*yzM zrofdbO^74%F(fJrLkrP$41>}*^gI@$5Zkjjhv>lyNyG*$DGR%yc4lcIf(@2o(Y+jk zXPm=0kST_q#}O1_KTi0Kb(9d1g`-*YJfH}|gJWSE5Ezc=L0|+6`-s3uB(?~QVqkp< zj6pC-V5mO`97AwQ-~?hT0t7H3Gfq*k&k2xTVEYj`i(r=knG246f}}Y(76{;SWF5ny zy0JKd7om`5VOfO0m9XE0Bu>J*2}zQK`3gxi4+$xZhW#s~gbeIAAw@IDc_2r?*cH+Q zf;AEcgN7jtkpR5#c_cv~`JN<51REqrBYB(zqQE>T46PLuMl!IED2zeyOyL*@V}k-1 zf@P*CkUb&YKoLW1MNu@8cWHoK*nU7W#BVfs5&`>{2Ka;JqX`1Z_cTb)uzWOu<`-HB zf(z1v24I7+Mzf$`!s|d@LwK+Zst1Q*$ax%r5#x6iOlG_=I zBjGq=Xb_o@9tGl+aZT|^d!K`_LC@`lL5l89XxmcbGESPs>fBM9U? zP%aUfITnc-7Q>NR%L2Q=xtImD8}>O%qjdp@jP7Mf1TQRjwubOvF%01W(k_fi7Caq; z?aZ<)lK(iIL+rxI3IpVG?i=}!qX-(t0Y{NY&gKAIU>tB1sv8GHhH=kP9D)s5T7&iF zKw!f9ax_W9KIdo@_Z$rn4eJZa8^QxTJ%eq}F(8@1dl?~8YdKjEBI_6o#vcb#EMj{G z?J+qPBO!fp4784r%(Bc0=X)F{NgR?H$5|5Y$8pe=VDLH;6C!&_3WISE3N1lHdH@;+ z*GrsafY?Lr0%%BY252Or8>moloxw>~2-ikHLvR3S42*jmbii=V!2#^yx&>$~Vk=Mw z;T|0aB@f0VPJxyS)|VoXdoZvLWI)I+6lipy_`oR=G!pPS5~*9DgTn|2Yk&qm@Lmuf zu+KqD1NVC1p+0gC253T5W`^SszAP{d%$Fq)yMX9`dqK`bDc_x%i9wZn6cIo}N-ZK(6eogM}XJJ^3JN`)}ZVq#|!=-~Bi^ P3ADOAJw3B!^LYOO&o2YP literal 0 HcmV?d00001 diff --git a/lib/crytic/lib/openzeppelin-contracts/audits/README.md b/lib/crytic/lib/openzeppelin-contracts/audits/README.md new file mode 100644 index 0000000..40098a4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/audits/README.md @@ -0,0 +1,15 @@ +# Audits + +| Date | Version | Commit | Auditor | Scope | Links | +| ------------ | ------- | --------- | ------------ | -------------------- | ----------------------------------------------------------- | +| 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) | + +# Formal Verification + +| Date | Version | Commit | Tool | Scope | Links | +| ------------ | ------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | +| May 2022 | v4.7.0 | `109778c` | Certora | Initializable, GovernorPreventLateQuorum, ERC1155Burnable, ERC1155Pausable, ERC1155Supply, ERC1155Holder, ERC1155Receiver | [🔗](../certora/reports/2022-05.pdf) | +| March 2022 | v4.4.0 | `4088540` | Certora | ERC20Votes, ERC20FlashMint, ERC20Wrapper, TimelockController, ERC721Votes, Votes, AccessControl, ERC1155 | [🔗](../certora/reports/2022-03.pdf) | +| October 2021 | v4.4.0 | `4088540` | Certora | Governor, GovernorCountingSimple, GovernorProposalThreshold, GovernorTimelockControl, GovernorVotes, GovernorVotesQuorumFraction | [🔗](../certora/reports/2021-10.pdf) | diff --git a/lib/crytic/lib/openzeppelin-contracts/certora/Makefile b/lib/crytic/lib/openzeppelin-contracts/certora/Makefile new file mode 100644 index 0000000..bbbddbc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/Makefile @@ -0,0 +1,24 @@ +default: help + +PATCH = applyHarness.patch +CONTRACTS_DIR = ../contracts +MUNGED_DIR = munged + +help: + @echo "usage:" + @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) + diff --git a/lib/crytic/lib/openzeppelin-contracts/certora/README.md b/lib/crytic/lib/openzeppelin-contracts/certora/README.md new file mode 100644 index 0000000..55f84d4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/README.md @@ -0,0 +1,56 @@ +# Running the certora verification tool + +These instructions detail the process for running CVT on the OpenZeppelin (Wizard/Governor) contracts. + +Documentation for CVT and the specification language are available +[here](https://certora.atlassian.net/wiki/spaces/CPD/overview) + +## 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/). + +These scripts should be run from the root directory; for example by running + +``` +sh certora/scripts/verifyAll.sh +``` + +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`). + +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. + +For example, to verify the `WizardFirstPriority` contract against the +`GovernorCountingSimple` specification, you could change the `--verify` line of +the `WizardControlFirstPriortity.sh` script to: + +``` +--verify WizardFirstPriority:certora/specs/GovernorCountingSimple.spec \ +``` + +## 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. + +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. + +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. + +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. diff --git a/lib/crytic/lib/openzeppelin-contracts/certora/applyHarness.patch b/lib/crytic/lib/openzeppelin-contracts/certora/applyHarness.patch new file mode 100644 index 0000000..0fbe9ac --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/applyHarness.patch @@ -0,0 +1,101 @@ +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/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/ERC20VotesHarness.sol b/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/ERC20VotesHarness.sol new file mode 100644 index 0000000..5067ecf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/ERC20VotesHarness.sol @@ -0,0 +1,28 @@ +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/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/WizardControlFirstPriority.sol b/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/WizardControlFirstPriority.sol new file mode 100644 index 0000000..5ae7fe0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/WizardControlFirstPriority.sol @@ -0,0 +1,150 @@ +// 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/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/WizardFirstTry.sol b/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/WizardFirstTry.sol new file mode 100644 index 0000000..83fece0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/harnesses/WizardFirstTry.sol @@ -0,0 +1,141 @@ +// 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/lib/crytic/lib/openzeppelin-contracts/certora/munged/.gitignore b/lib/crytic/lib/openzeppelin-contracts/certora/munged/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/munged/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/lib/crytic/lib/openzeppelin-contracts/certora/reports/2021-10.pdf b/lib/crytic/lib/openzeppelin-contracts/certora/reports/2021-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..22df9c61e6a9f74b29f90b6e36bd3d04f99756f5 GIT binary patch literal 92882 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 aXJ@ZxYwu)>@+&A9#pUoWT@sTO$NL{da>MEX literal 0 HcmV?d00001 diff --git a/lib/crytic/lib/openzeppelin-contracts/certora/reports/2022-03.pdf b/lib/crytic/lib/openzeppelin-contracts/certora/reports/2022-03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b6ff81d1812c808e2f683c1e5fe10abf71ba5438 GIT binary patch literal 199401 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

E02esqZ$^2gTs{2 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 literal 0 HcmV?d00001 diff --git a/lib/crytic/lib/openzeppelin-contracts/certora/reports/2022-05.pdf b/lib/crytic/lib/openzeppelin-contracts/certora/reports/2022-05.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f24a44910c4fba449300987456b5f440e7f99511 GIT binary patch literal 132223 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%0D7|ieYKPVYBX59b!U}f9eB5UvK%HwkWL{dR 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 UVZ$VVhf9Eu51oMlq$-2{KaJIBBLDyZ literal 0 HcmV?d00001 diff --git a/lib/crytic/lib/openzeppelin-contracts/certora/scripts/Governor.sh b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/Governor.sh new file mode 100755 index 0000000..53ade50 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/Governor.sh @@ -0,0 +1,10 @@ +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/lib/crytic/lib/openzeppelin-contracts/certora/scripts/GovernorCountingSimple-counting.sh b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/GovernorCountingSimple-counting.sh new file mode 100644 index 0000000..9ed8fe3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/GovernorCountingSimple-counting.sh @@ -0,0 +1,10 @@ +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/lib/crytic/lib/openzeppelin-contracts/certora/scripts/WizardControlFirstPriority.sh b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/WizardControlFirstPriority.sh new file mode 100644 index 0000000..b815986 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/WizardControlFirstPriority.sh @@ -0,0 +1,12 @@ +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/lib/crytic/lib/openzeppelin-contracts/certora/scripts/WizardFirstTry.sh b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/WizardFirstTry.sh new file mode 100644 index 0000000..fd5a32a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/WizardFirstTry.sh @@ -0,0 +1,10 @@ +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/lib/crytic/lib/openzeppelin-contracts/certora/scripts/sanity.sh b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/sanity.sh new file mode 100644 index 0000000..1c42bf6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/sanity.sh @@ -0,0 +1,14 @@ +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/lib/crytic/lib/openzeppelin-contracts/certora/scripts/verifyAll.sh b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/verifyAll.sh new file mode 100644 index 0000000..9b2f11c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/scripts/verifyAll.sh @@ -0,0 +1,39 @@ +#!/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/lib/crytic/lib/openzeppelin-contracts/certora/specs/GovernorBase.spec b/lib/crytic/lib/openzeppelin-contracts/certora/specs/GovernorBase.spec new file mode 100644 index 0000000..de728dd --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/specs/GovernorBase.spec @@ -0,0 +1,333 @@ +////////////////////////////////////////////////////////////////////////////// +///////////////////// 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/lib/crytic/lib/openzeppelin-contracts/certora/specs/GovernorCountingSimple.spec b/lib/crytic/lib/openzeppelin-contracts/certora/specs/GovernorCountingSimple.spec new file mode 100644 index 0000000..7af73be --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/specs/GovernorCountingSimple.spec @@ -0,0 +1,221 @@ +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/lib/crytic/lib/openzeppelin-contracts/certora/specs/RulesInProgress.spec b/lib/crytic/lib/openzeppelin-contracts/certora/specs/RulesInProgress.spec new file mode 100644 index 0000000..cbad333 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/specs/RulesInProgress.spec @@ -0,0 +1,139 @@ +////////////////////////////////////////////////////////////////////////////// +////////////// 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/lib/crytic/lib/openzeppelin-contracts/certora/specs/sanity.spec b/lib/crytic/lib/openzeppelin-contracts/certora/specs/sanity.spec new file mode 100644 index 0000000..e08f688 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/certora/specs/sanity.spec @@ -0,0 +1,14 @@ +/* +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/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControl.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControl.sol new file mode 100644 index 0000000..5f2829e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControl.sol @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (access/AccessControl.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; +import "../utils/Context.sol"; +import "../utils/Strings.sol"; +import "../utils/introspection/ERC165.sol"; + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * 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)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * 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. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `_msgSender()` is missing `role`. + * Overriding this function changes the behavior of the {onlyRole} modifier. + * + * Format of the revert message is described in {_checkRole}. + * + * _Available since v4.6._ + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(account), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * May emit a {RoleGranted} event. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControlCrossChain.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControlCrossChain.sol new file mode 100644 index 0000000..95be509 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControlCrossChain.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControlCrossChain.sol) + +pragma solidity ^0.8.4; + +import "./AccessControl.sol"; +import "../crosschain/CrossChainEnabled.sol"; + +/** + * @dev An extension to {AccessControl} with support for cross-chain access management. + * For each role, is extension implements an equivalent "aliased" role that is used for + * restricting calls originating from other chains. + * + * For example, if a function `myFunction` is protected by `onlyRole(SOME_ROLE)`, and + * if an address `x` has role `SOME_ROLE`, it would be able to call `myFunction` directly. + * A wallet or contract at the same address on another chain would however not be able + * to call this function. In order to do so, it would require to have the role + * `_crossChainRoleAlias(SOME_ROLE)`. + * + * This aliasing is required to protect against multiple contracts living at the same + * address on different chains but controlled by conflicting entities. + * + * _Available since v4.6._ + */ +abstract contract AccessControlCrossChain is AccessControl, CrossChainEnabled { + bytes32 public constant CROSSCHAIN_ALIAS = keccak256("CROSSCHAIN_ALIAS"); + + /** + * @dev See {AccessControl-_checkRole}. + */ + function _checkRole(bytes32 role) internal view virtual override { + if (_isCrossChain()) { + _checkRole(_crossChainRoleAlias(role), _crossChainSender()); + } else { + super._checkRole(role); + } + } + + /** + * @dev Returns the aliased role corresponding to `role`. + */ + function _crossChainRoleAlias(bytes32 role) internal pure virtual returns (bytes32) { + return role ^ CROSSCHAIN_ALIAS; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControlEnumerable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControlEnumerable.sol new file mode 100644 index 0000000..354e1be --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/access/AccessControlEnumerable.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControlEnumerable.sol"; +import "./AccessControl.sol"; +import "../utils/structs/EnumerableSet.sol"; + +/** + * @dev Extension of {AccessControl} that allows enumerating the members of each role. + */ +abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { + using EnumerableSet for EnumerableSet.AddressSet; + + mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) { + return _roleMembers[role].at(index); + } + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) { + return _roleMembers[role].length(); + } + + /** + * @dev Overload {_grantRole} to track enumerable memberships + */ + function _grantRole(bytes32 role, address account) internal virtual override { + super._grantRole(role, account); + _roleMembers[role].add(account); + } + + /** + * @dev Overload {_revokeRole} to track enumerable memberships + */ + function _revokeRole(bytes32 role, address account) internal virtual override { + super._revokeRole(role, account); + _roleMembers[role].remove(account); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol new file mode 100644 index 0000000..f773ecc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + +pragma solidity ^0.8.0; + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/access/IAccessControlEnumerable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/access/IAccessControlEnumerable.sol new file mode 100644 index 0000000..61aaf57 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/access/IAccessControlEnumerable.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; + +/** + * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. + */ +interface IAccessControlEnumerable is IAccessControl { + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) external view returns (address); + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) external view returns (uint256); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/access/Ownable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/access/Ownable.sol new file mode 100644 index 0000000..6d4e866 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/access/Ownable.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions anymore. 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. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol new file mode 100644 index 0000000..f5a3d80 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol) + +pragma solidity ^0.8.0; + +import "./Ownable.sol"; + +/** + * @dev Contract module which provides access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership} and {acceptOwnership}. + * + * This module is used through inheritance. It will make available all functions + * from parent (Ownable). + */ +abstract contract Ownable2Step is Ownable { + address private _pendingOwner; + + event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Returns the address of the pending owner. + */ + function pendingOwner() public view virtual returns (address) { + return _pendingOwner; + } + + /** + * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual override onlyOwner { + _pendingOwner = newOwner; + emit OwnershipTransferStarted(owner(), newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual override { + delete _pendingOwner; + super._transferOwnership(newOwner); + } + + /** + * @dev The new owner accepts the ownership transfer. + */ + function acceptOwnership() public virtual { + address sender = _msgSender(); + require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner"); + _transferOwnership(sender); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/access/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/access/README.adoc new file mode 100644 index 0000000..888d0e9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/access/README.adoc @@ -0,0 +1,25 @@ += Access Control + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access + +This directory provides ways to restrict who can access the functions of a contract or when they can do it. + +- {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. +- {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. + +== Authorization + +{{Ownable}} + +{{Ownable2Step}} + +{{IAccessControl}} + +{{AccessControl}} + +{{AccessControlCrossChain}} + +{{IAccessControlEnumerable}} + +{{AccessControlEnumerable}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/CrossChainEnabled.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/CrossChainEnabled.sol new file mode 100644 index 0000000..4c9b9e5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/CrossChainEnabled.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (crosschain/CrossChainEnabled.sol) + +pragma solidity ^0.8.4; + +import "./errors.sol"; + +/** + * @dev Provides information for building cross-chain aware contracts. This + * abstract contract provides accessors and modifiers to control the execution + * flow when receiving cross-chain messages. + * + * Actual implementations of cross-chain aware contracts, which are based on + * this abstraction, will have to inherit from a bridge-specific + * specialization. Such specializations are provided under + * `crosschain//CrossChainEnabled.sol`. + * + * _Available since v4.6._ + */ +abstract contract CrossChainEnabled { + /** + * @dev Throws if the current function call is not the result of a + * cross-chain execution. + */ + modifier onlyCrossChain() { + if (!_isCrossChain()) revert NotCrossChainCall(); + _; + } + + /** + * @dev Throws if the current function call is not the result of a + * cross-chain execution initiated by `account`. + */ + modifier onlyCrossChainSender(address expected) { + address actual = _crossChainSender(); + if (expected != actual) revert InvalidCrossChainSender(actual, expected); + _; + } + + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message. + */ + function _isCrossChain() internal view virtual returns (bool); + + /** + * @dev Returns the address of the sender of the cross-chain message that + * triggered the current function call. + * + * IMPORTANT: Should revert with `NotCrossChainCall` if the current function + * call is not the result of a cross-chain message. + */ + function _crossChainSender() internal view virtual returns (address); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/README.adoc new file mode 100644 index 0000000..266b153 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/README.adoc @@ -0,0 +1,34 @@ += Cross Chain Awareness + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/crosschain + +This directory provides building blocks to improve cross-chain awareness of smart contracts. + +- {CrossChainEnabled} is an abstraction that contains accessors and modifiers to control the execution flow when receiving cross-chain messages. + +== CrossChainEnabled specializations + +The following specializations of {CrossChainEnabled} provide implementations of the {CrossChainEnabled} abstraction for specific bridges. This can be used to complex cross-chain aware components such as {AccessControlCrossChain}. + +{{CrossChainEnabledAMB}} + +{{CrossChainEnabledArbitrumL1}} + +{{CrossChainEnabledArbitrumL2}} + +{{CrossChainEnabledOptimism}} + +{{CrossChainEnabledPolygonChild}} + +== Libraries for cross-chain + +In addition to the {CrossChainEnabled} abstraction, cross-chain awareness is also available through libraries. These libraries can be used to build complex designs such as contracts with the ability to interact with multiple bridges. + +{{LibAMB}} + +{{LibArbitrumL1}} + +{{LibArbitrumL2}} + +{{LibOptimism}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/amb/CrossChainEnabledAMB.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/amb/CrossChainEnabledAMB.sol new file mode 100644 index 0000000..e69355d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/amb/CrossChainEnabledAMB.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/amb/CrossChainEnabledAMB.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "./LibAMB.sol"; + +/** + * @dev https://docs.tokenbridge.net/amb-bridge/about-amb-bridge[AMB] + * specialization or the {CrossChainEnabled} abstraction. + * + * As of february 2020, AMB bridges are available between the following chains: + * + * - https://docs.tokenbridge.net/eth-xdai-amb-bridge/about-the-eth-xdai-amb[ETH ⇌ xDai] + * - https://docs.tokenbridge.net/eth-qdai-bridge/about-the-eth-qdai-amb[ETH ⇌ qDai] + * - https://docs.tokenbridge.net/eth-etc-amb-bridge/about-the-eth-etc-amb[ETH ⇌ ETC] + * - https://docs.tokenbridge.net/eth-bsc-amb/about-the-eth-bsc-amb[ETH ⇌ BSC] + * - https://docs.tokenbridge.net/eth-poa-amb-bridge/about-the-eth-poa-amb[ETH ⇌ POA] + * - https://docs.tokenbridge.net/bsc-xdai-amb/about-the-bsc-xdai-amb[BSC ⇌ xDai] + * - https://docs.tokenbridge.net/poa-xdai-amb/about-the-poa-xdai-amb[POA ⇌ xDai] + * - https://docs.tokenbridge.net/rinkeby-xdai-amb-bridge/about-the-rinkeby-xdai-amb[Rinkeby ⇌ xDai] + * - https://docs.tokenbridge.net/kovan-sokol-amb-bridge/about-the-kovan-sokol-amb[Kovan ⇌ Sokol] + * + * _Available since v4.6._ + */ +contract CrossChainEnabledAMB is CrossChainEnabled { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _bridge; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) { + _bridge = bridge; + } + + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return LibAMB.isCrossChain(_bridge); + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return LibAMB.crossChainSender(_bridge); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/amb/LibAMB.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/amb/LibAMB.sol new file mode 100644 index 0000000..aef9c43 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/amb/LibAMB.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/amb/LibAMB.sol) + +pragma solidity ^0.8.4; + +import {IAMB as AMB_Bridge} from "../../vendor/amb/IAMB.sol"; +import "../errors.sol"; + +/** + * @dev Primitives for cross-chain aware contracts using the + * https://docs.tokenbridge.net/amb-bridge/about-amb-bridge[AMB] + * family of bridges. + */ +library LibAMB { + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message relayed by `bridge`. + */ + function isCrossChain(address bridge) internal view returns (bool) { + return msg.sender == bridge; + } + + /** + * @dev Returns the address of the sender that triggered the current + * cross-chain message through `bridge`. + * + * NOTE: {isCrossChain} should be checked before trying to recover the + * sender, as it will revert with `NotCrossChainCall` if the current + * function call is not the result of a cross-chain message. + */ + function crossChainSender(address bridge) internal view returns (address) { + if (!isCrossChain(bridge)) revert NotCrossChainCall(); + return AMB_Bridge(bridge).messageSender(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol new file mode 100644 index 0000000..5068da3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "./LibArbitrumL1.sol"; + +/** + * @dev https://arbitrum.io/[Arbitrum] specialization or the + * {CrossChainEnabled} abstraction the L1 side (mainnet). + * + * This version should only be deployed on L1 to process cross-chain messages + * originating from L2. For the other side, use {CrossChainEnabledArbitrumL2}. + * + * The bridge contract is provided and maintained by the arbitrum team. You can + * find the address of this contract on the rinkeby testnet in + * https://developer.offchainlabs.com/docs/useful_addresses[Arbitrum's developer documentation]. + * + * _Available since v4.6._ + */ +abstract contract CrossChainEnabledArbitrumL1 is CrossChainEnabled { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _bridge; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) { + _bridge = bridge; + } + + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return LibArbitrumL1.isCrossChain(_bridge); + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return LibArbitrumL1.crossChainSender(_bridge); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol new file mode 100644 index 0000000..e85993d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "./LibArbitrumL2.sol"; + +/** + * @dev https://arbitrum.io/[Arbitrum] specialization or the + * {CrossChainEnabled} abstraction the L2 side (arbitrum). + * + * This version should only be deployed on L2 to process cross-chain messages + * originating from L1. For the other side, use {CrossChainEnabledArbitrumL1}. + * + * Arbitrum L2 includes the `ArbSys` contract at a fixed address. Therefore, + * this specialization of {CrossChainEnabled} does not include a constructor. + * + * _Available since v4.6._ + * + * WARNING: There is currently a bug in Arbitrum that causes this contract to + * fail to detect cross-chain calls when deployed behind a proxy. This will be + * fixed when the network is upgraded to Arbitrum Nitro, currently scheduled for + * August 31st 2022. + */ +abstract contract CrossChainEnabledArbitrumL2 is CrossChainEnabled { + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return LibArbitrumL2.isCrossChain(LibArbitrumL2.ARBSYS); + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return LibArbitrumL2.crossChainSender(LibArbitrumL2.ARBSYS); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/LibArbitrumL1.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/LibArbitrumL1.sol new file mode 100644 index 0000000..be7236b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/LibArbitrumL1.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (crosschain/arbitrum/LibArbitrumL1.sol) + +pragma solidity ^0.8.4; + +import {IBridge as ArbitrumL1_Bridge} from "../../vendor/arbitrum/IBridge.sol"; +import {IOutbox as ArbitrumL1_Outbox} from "../../vendor/arbitrum/IOutbox.sol"; +import "../errors.sol"; + +/** + * @dev Primitives for cross-chain aware contracts for + * https://arbitrum.io/[Arbitrum]. + * + * This version should only be used on L1 to process cross-chain messages + * originating from L2. For the other side, use {LibArbitrumL2}. + */ +library LibArbitrumL1 { + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message relayed by the `bridge`. + */ + function isCrossChain(address bridge) internal view returns (bool) { + return msg.sender == bridge; + } + + /** + * @dev Returns the address of the sender that triggered the current + * cross-chain message through the `bridge`. + * + * NOTE: {isCrossChain} should be checked before trying to recover the + * sender, as it will revert with `NotCrossChainCall` if the current + * function call is not the result of a cross-chain message. + */ + function crossChainSender(address bridge) internal view returns (address) { + if (!isCrossChain(bridge)) revert NotCrossChainCall(); + + address sender = ArbitrumL1_Outbox(ArbitrumL1_Bridge(bridge).activeOutbox()).l2ToL1Sender(); + require(sender != address(0), "LibArbitrumL1: system messages without sender"); + + return sender; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/LibArbitrumL2.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/LibArbitrumL2.sol new file mode 100644 index 0000000..715a387 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/arbitrum/LibArbitrumL2.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (crosschain/arbitrum/LibArbitrumL2.sol) + +pragma solidity ^0.8.4; + +import {IArbSys as ArbitrumL2_Bridge} from "../../vendor/arbitrum/IArbSys.sol"; +import "../errors.sol"; + +/** + * @dev Primitives for cross-chain aware contracts for + * https://arbitrum.io/[Arbitrum]. + * + * This version should only be used on L2 to process cross-chain messages + * originating from L1. For the other side, use {LibArbitrumL1}. + * + * WARNING: There is currently a bug in Arbitrum that causes this contract to + * fail to detect cross-chain calls when deployed behind a proxy. This will be + * fixed when the network is upgraded to Arbitrum Nitro, currently scheduled for + * August 31st 2022. + */ +library LibArbitrumL2 { + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message relayed by `arbsys`. + */ + address public constant ARBSYS = 0x0000000000000000000000000000000000000064; + + function isCrossChain(address arbsys) internal view returns (bool) { + return ArbitrumL2_Bridge(arbsys).wasMyCallersAddressAliased(); + } + + /** + * @dev Returns the address of the sender that triggered the current + * cross-chain message through `arbsys`. + * + * NOTE: {isCrossChain} should be checked before trying to recover the + * sender, as it will revert with `NotCrossChainCall` if the current + * function call is not the result of a cross-chain message. + */ + function crossChainSender(address arbsys) internal view returns (address) { + if (!isCrossChain(arbsys)) revert NotCrossChainCall(); + + return ArbitrumL2_Bridge(arbsys).myCallersAddressWithoutAliasing(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/errors.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/errors.sol new file mode 100644 index 0000000..004460e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/errors.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (crosschain/errors.sol) + +pragma solidity ^0.8.4; + +error NotCrossChainCall(); +error InvalidCrossChainSender(address actual, address expected); diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol new file mode 100644 index 0000000..1005864 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/optimism/CrossChainEnabledOptimism.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "./LibOptimism.sol"; + +/** + * @dev https://www.optimism.io/[Optimism] specialization or the + * {CrossChainEnabled} abstraction. + * + * The messenger (`CrossDomainMessenger`) contract is provided and maintained by + * the optimism team. You can find the address of this contract on mainnet and + * kovan in the https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts/deployments[deployments section of Optimism monorepo]. + * + * _Available since v4.6._ + */ +abstract contract CrossChainEnabledOptimism is CrossChainEnabled { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _messenger; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address messenger) { + _messenger = messenger; + } + + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return LibOptimism.isCrossChain(_messenger); + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return LibOptimism.crossChainSender(_messenger); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/optimism/LibOptimism.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/optimism/LibOptimism.sol new file mode 100644 index 0000000..d963ade --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/optimism/LibOptimism.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/optimism/LibOptimism.sol) + +pragma solidity ^0.8.4; + +import {ICrossDomainMessenger as Optimism_Bridge} from "../../vendor/optimism/ICrossDomainMessenger.sol"; +import "../errors.sol"; + +/** + * @dev Primitives for cross-chain aware contracts for https://www.optimism.io/[Optimism]. + * See the https://community.optimism.io/docs/developers/bridge/messaging/#accessing-msg-sender[documentation] + * for the functionality used here. + */ +library LibOptimism { + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message relayed by `messenger`. + */ + function isCrossChain(address messenger) internal view returns (bool) { + return msg.sender == messenger; + } + + /** + * @dev Returns the address of the sender that triggered the current + * cross-chain message through `messenger`. + * + * NOTE: {isCrossChain} should be checked before trying to recover the + * sender, as it will revert with `NotCrossChainCall` if the current + * function call is not the result of a cross-chain message. + */ + function crossChainSender(address messenger) internal view returns (address) { + if (!isCrossChain(messenger)) revert NotCrossChainCall(); + + return Optimism_Bridge(messenger).xDomainMessageSender(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol new file mode 100644 index 0000000..fa09948 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/polygon/CrossChainEnabledPolygonChild.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "../../security/ReentrancyGuard.sol"; +import "../../utils/Address.sol"; +import "../../vendor/polygon/IFxMessageProcessor.sol"; + +address constant DEFAULT_SENDER = 0x000000000000000000000000000000000000dEaD; + +/** + * @dev https://polygon.technology/[Polygon] specialization or the + * {CrossChainEnabled} abstraction the child side (polygon/mumbai). + * + * This version should only be deployed on child chain to process cross-chain + * messages originating from the parent chain. + * + * The fxChild contract is provided and maintained by the polygon team. You can + * find the address of this contract polygon and mumbai in + * https://docs.polygon.technology/docs/develop/l1-l2-communication/fx-portal/#contract-addresses[Polygon's Fx-Portal documentation]. + * + * _Available since v4.6._ + */ +abstract contract CrossChainEnabledPolygonChild is IFxMessageProcessor, CrossChainEnabled, ReentrancyGuard { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _fxChild; + address private _sender = DEFAULT_SENDER; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address fxChild) { + _fxChild = fxChild; + } + + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return msg.sender == _fxChild; + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return _sender; + } + + /** + * @dev External entry point to receive and relay messages originating + * from the fxChild. + * + * Non-reentrancy is crucial to avoid a cross-chain call being able + * to impersonate anyone by just looping through this with user-defined + * arguments. + * + * Note: if _fxChild calls any other function that does a delegate-call, + * then security could be compromised. + */ + function processMessageFromRoot( + uint256 /* stateId */, + address rootMessageSender, + bytes calldata data + ) external override nonReentrant { + if (!_isCrossChain()) revert NotCrossChainCall(); + + _sender = rootMessageSender; + Address.functionDelegateCall(address(this), data, "cross-chain execution failed"); + _sender = DEFAULT_SENDER; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/finance/PaymentSplitter.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/finance/PaymentSplitter.sol new file mode 100644 index 0000000..daa9090 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/finance/PaymentSplitter.sol @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (finance/PaymentSplitter.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/utils/SafeERC20.sol"; +import "../utils/Address.sol"; +import "../utils/Context.sol"; + +/** + * @title PaymentSplitter + * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware + * that the Ether will be split in this way, since it is handled transparently by the contract. + * + * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each + * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim + * an amount proportional to the percentage of total shares they were assigned. The distribution of shares is set at the + * time of contract deployment and can't be updated thereafter. + * + * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the + * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release} + * function. + * + * NOTE: This contract assumes that ERC20 tokens will behave similarly to native tokens (Ether). Rebasing tokens, and + * tokens that apply fees during transfers, are likely to not be supported as expected. If in doubt, we encourage you + * to run tests before sending real value to this contract. + */ +contract PaymentSplitter is Context { + event PayeeAdded(address account, uint256 shares); + event PaymentReleased(address to, uint256 amount); + event ERC20PaymentReleased(IERC20 indexed token, address to, uint256 amount); + event PaymentReceived(address from, uint256 amount); + + uint256 private _totalShares; + uint256 private _totalReleased; + + mapping(address => uint256) private _shares; + mapping(address => uint256) private _released; + address[] private _payees; + + mapping(IERC20 => uint256) private _erc20TotalReleased; + mapping(IERC20 => mapping(address => uint256)) private _erc20Released; + + /** + * @dev Creates an instance of `PaymentSplitter` where each account in `payees` is assigned the number of shares at + * the matching position in the `shares` array. + * + * All addresses in `payees` must be non-zero. Both arrays must have the same non-zero length, and there must be no + * duplicates in `payees`. + */ + constructor(address[] memory payees, uint256[] memory shares_) payable { + require(payees.length == shares_.length, "PaymentSplitter: payees and shares length mismatch"); + require(payees.length > 0, "PaymentSplitter: no payees"); + + for (uint256 i = 0; i < payees.length; i++) { + _addPayee(payees[i], shares_[i]); + } + } + + /** + * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully + * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the + * reliability of the events, and not the actual splitting of Ether. + * + * To learn more about this see the Solidity documentation for + * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback + * functions]. + */ + receive() external payable virtual { + emit PaymentReceived(_msgSender(), msg.value); + } + + /** + * @dev Getter for the total shares held by payees. + */ + function totalShares() public view returns (uint256) { + return _totalShares; + } + + /** + * @dev Getter for the total amount of Ether already released. + */ + function totalReleased() public view returns (uint256) { + return _totalReleased; + } + + /** + * @dev Getter for the total amount of `token` already released. `token` should be the address of an IERC20 + * contract. + */ + function totalReleased(IERC20 token) public view returns (uint256) { + return _erc20TotalReleased[token]; + } + + /** + * @dev Getter for the amount of shares held by an account. + */ + function shares(address account) public view returns (uint256) { + return _shares[account]; + } + + /** + * @dev Getter for the amount of Ether already released to a payee. + */ + function released(address account) public view returns (uint256) { + return _released[account]; + } + + /** + * @dev Getter for the amount of `token` tokens already released to a payee. `token` should be the address of an + * IERC20 contract. + */ + function released(IERC20 token, address account) public view returns (uint256) { + return _erc20Released[token][account]; + } + + /** + * @dev Getter for the address of the payee number `index`. + */ + function payee(uint256 index) public view returns (address) { + return _payees[index]; + } + + /** + * @dev Getter for the amount of payee's releasable Ether. + */ + function releasable(address account) public view returns (uint256) { + uint256 totalReceived = address(this).balance + totalReleased(); + return _pendingPayment(account, totalReceived, released(account)); + } + + /** + * @dev Getter for the amount of payee's releasable `token` tokens. `token` should be the address of an + * IERC20 contract. + */ + function releasable(IERC20 token, address account) public view returns (uint256) { + uint256 totalReceived = token.balanceOf(address(this)) + totalReleased(token); + return _pendingPayment(account, totalReceived, released(token, account)); + } + + /** + * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the + * total shares and their previous withdrawals. + */ + function release(address payable account) public virtual { + require(_shares[account] > 0, "PaymentSplitter: account has no shares"); + + uint256 payment = releasable(account); + + require(payment != 0, "PaymentSplitter: account is not due payment"); + + // _totalReleased is the sum of all values in _released. + // If "_totalReleased += payment" does not overflow, then "_released[account] += payment" cannot overflow. + _totalReleased += payment; + unchecked { + _released[account] += payment; + } + + Address.sendValue(account, payment); + emit PaymentReleased(account, payment); + } + + /** + * @dev Triggers a transfer to `account` of the amount of `token` tokens they are owed, according to their + * percentage of the total shares and their previous withdrawals. `token` must be the address of an IERC20 + * contract. + */ + function release(IERC20 token, address account) public virtual { + require(_shares[account] > 0, "PaymentSplitter: account has no shares"); + + uint256 payment = releasable(token, account); + + require(payment != 0, "PaymentSplitter: account is not due payment"); + + // _erc20TotalReleased[token] is the sum of all values in _erc20Released[token]. + // If "_erc20TotalReleased[token] += payment" does not overflow, then "_erc20Released[token][account] += payment" + // cannot overflow. + _erc20TotalReleased[token] += payment; + unchecked { + _erc20Released[token][account] += payment; + } + + SafeERC20.safeTransfer(token, account, payment); + emit ERC20PaymentReleased(token, account, payment); + } + + /** + * @dev internal logic for computing the pending payment of an `account` given the token historical balances and + * already released amounts. + */ + function _pendingPayment( + address account, + uint256 totalReceived, + uint256 alreadyReleased + ) private view returns (uint256) { + return (totalReceived * _shares[account]) / _totalShares - alreadyReleased; + } + + /** + * @dev Add a new payee to the contract. + * @param account The address of the payee to add. + * @param shares_ The number of shares owned by the payee. + */ + function _addPayee(address account, uint256 shares_) private { + require(account != address(0), "PaymentSplitter: account is the zero address"); + require(shares_ > 0, "PaymentSplitter: shares are 0"); + require(_shares[account] == 0, "PaymentSplitter: account already has shares"); + + _payees.push(account); + _shares[account] = shares_; + _totalShares = _totalShares + shares_; + emit PayeeAdded(account, shares_); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/finance/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/finance/README.adoc new file mode 100644 index 0000000..b64af31 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/finance/README.adoc @@ -0,0 +1,20 @@ += Finance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/finance + +This directory includes primitives for financial systems: + +- {PaymentSplitter} allows to split Ether and ERC20 payments among a group of accounts. The sender does not need to be + aware that the assets will be split in this way, since it is handled transparently by the contract. The split can be + in equal parts or in any other arbitrary proportion. + +- {VestingWallet} handles the vesting of Ether and ERC20 tokens for a given beneficiary. Custody of multiple tokens can + be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting + schedule. + +== Contracts + +{{PaymentSplitter}} + +{{VestingWallet}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol new file mode 100644 index 0000000..fe67eb5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (finance/VestingWallet.sol) +pragma solidity ^0.8.0; + +import "../token/ERC20/utils/SafeERC20.sol"; +import "../utils/Address.sol"; +import "../utils/Context.sol"; + +/** + * @title VestingWallet + * @dev This contract handles the vesting of Eth and ERC20 tokens for a given beneficiary. Custody of multiple tokens + * can be given to this contract, which will release the token to the beneficiary following a given vesting schedule. + * The vesting schedule is customizable through the {vestedAmount} function. + * + * 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. + */ +contract VestingWallet is Context { + event EtherReleased(uint256 amount); + event ERC20Released(address indexed token, uint256 amount); + + uint256 private _released; + mapping(address => uint256) private _erc20Released; + address private immutable _beneficiary; + uint64 private immutable _start; + uint64 private immutable _duration; + + /** + * @dev Set the beneficiary, start timestamp and vesting duration of the vesting wallet. + */ + constructor(address beneficiaryAddress, uint64 startTimestamp, uint64 durationSeconds) payable { + require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address"); + _beneficiary = beneficiaryAddress; + _start = startTimestamp; + _duration = durationSeconds; + } + + /** + * @dev The contract should be able to receive Eth. + */ + receive() external payable virtual {} + + /** + * @dev Getter for the beneficiary address. + */ + function beneficiary() public view virtual returns (address) { + return _beneficiary; + } + + /** + * @dev Getter for the start timestamp. + */ + function start() public view virtual returns (uint256) { + return _start; + } + + /** + * @dev Getter for the vesting duration. + */ + function duration() public view virtual returns (uint256) { + return _duration; + } + + /** + * @dev Amount of eth already released + */ + function released() public view virtual returns (uint256) { + return _released; + } + + /** + * @dev Amount of token already released + */ + function released(address token) public view virtual returns (uint256) { + return _erc20Released[token]; + } + + /** + * @dev Getter for the amount of releasable eth. + */ + function releasable() public view virtual returns (uint256) { + return vestedAmount(uint64(block.timestamp)) - released(); + } + + /** + * @dev Getter for the amount of releasable `token` tokens. `token` should be the address of an + * IERC20 contract. + */ + function releasable(address token) public view virtual returns (uint256) { + return vestedAmount(token, uint64(block.timestamp)) - released(token); + } + + /** + * @dev Release the native token (ether) that have already vested. + * + * Emits a {EtherReleased} event. + */ + function release() public virtual { + uint256 amount = releasable(); + _released += amount; + emit EtherReleased(amount); + Address.sendValue(payable(beneficiary()), amount); + } + + /** + * @dev Release the tokens that have already vested. + * + * Emits a {ERC20Released} event. + */ + function release(address token) public virtual { + uint256 amount = releasable(token); + _erc20Released[token] += amount; + emit ERC20Released(token, amount); + SafeERC20.safeTransfer(IERC20(token), beneficiary(), amount); + } + + /** + * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve. + */ + function vestedAmount(uint64 timestamp) public view virtual returns (uint256) { + return _vestingSchedule(address(this).balance + released(), timestamp); + } + + /** + * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve. + */ + function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) { + return _vestingSchedule(IERC20(token).balanceOf(address(this)) + released(token), timestamp); + } + + /** + * @dev Virtual implementation of the vesting formula. This returns the amount vested, as a function of time, for + * an asset given its total historical allocation. + */ + function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) { + if (timestamp < start()) { + return 0; + } else if (timestamp > start() + duration()) { + return totalAllocation; + } else { + return (totalAllocation * (timestamp - start())) / duration(); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/Governor.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/Governor.sol new file mode 100644 index 0000000..1483da6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/Governor.sol @@ -0,0 +1,627 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (governance/Governor.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/IERC721Receiver.sol"; +import "../token/ERC1155/IERC1155Receiver.sol"; +import "../utils/cryptography/ECDSA.sol"; +import "../utils/cryptography/EIP712.sol"; +import "../utils/introspection/ERC165.sol"; +import "../utils/math/SafeCast.sol"; +import "../utils/structs/DoubleEndedQueue.sol"; +import "../utils/Address.sol"; +import "../utils/Context.sol"; +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: + * + * - A counting module must implement {quorum}, {_quorumReached}, {_voteSucceeded} and {_countVote} + * - A voting module must implement {_getVotes} + * - Additionally, the {votingPeriod} must also be implemented + * + * _Available since v4.3._ + */ +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 = + keccak256("ExtendedBallot(uint256 proposalId,uint8 support,string reason,bytes params)"); + + // solhint-disable var-name-mixedcase + struct ProposalCore { + // --- 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; + } + // 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 + // {onlyGovernance} modifier needs to be whitelisted in this queue. Whitelisting is set in {_beforeExecute}, + // consumed by the {onlyGovernance} modifier and eventually reset in {_afterExecute}. This ensures that the + // execution of {onlyGovernance} protected calls can only be achieved through successful proposals. + DoubleEndedQueue.Bytes32Deque private _governanceCall; + + /** + * @dev Restricts a function so it can only be executed through governance proposals. For example, governance + * parameter setters in {GovernorSettings} are protected using this modifier. + * + * The governance executing address may be different from the Governor's own address, for example it could be a + * timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these + * functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus, + * for example, additional timelock proposers are not able to change governance parameters without going through the + * governance protocol (since v4.6). + */ + modifier onlyGovernance() { + require(_msgSender() == _executor(), "Governor: onlyGovernance"); + if (_executor() != address(this)) { + bytes32 msgDataHash = keccak256(_msgData()); + // loop until popping the expected operation - throw if deque is empty (operation not authorized) + while (_governanceCall.popFront() != msgDataHash) {} + } + _; + } + + /** + * @dev Sets the value for {name} and {version} + */ + constructor(string memory name_) EIP712(name_, version()) { + _name = name_; + } + + /** + * @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)); + } + + /** + * @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 + 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 == type(IERC1155Receiver).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IGovernor-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IGovernor-version}. + */ + function version() public view virtual override returns (string memory) { + return "1"; + } + + /** + * @dev See {IGovernor-hashProposal}. + * + * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array + * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id + * can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in + * advance, before the proposal is submitted. + * + * Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the + * same proposal (with same operation and same description) will have the same id if submitted on multiple governors + * across multiple networks. This also means that in order to execute the same operation twice (on the same + * governor) the proposer will have to change the description in order to avoid proposal id conflicts. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public pure virtual override returns (uint256) { + return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash))); + } + + /** + * @dev See {IGovernor-state}. + */ + function state(uint256 proposalId) public view virtual override returns (ProposalState) { + ProposalCore storage proposal = _proposals[proposalId]; + + if (proposal.executed) { + return ProposalState.Executed; + } + + if (proposal.canceled) { + return ProposalState.Canceled; + } + + uint256 snapshot = proposalSnapshot(proposalId); + + if (snapshot == 0) { + revert("Governor: unknown proposal id"); + } + + uint256 currentTimepoint = clock(); + + if (snapshot >= currentTimepoint) { + return ProposalState.Pending; + } + + uint256 deadline = proposalDeadline(proposalId); + + if (deadline >= currentTimepoint) { + return ProposalState.Active; + } + + if (_quorumReached(proposalId) && _voteSucceeded(proposalId)) { + return ProposalState.Succeeded; + } else { + return ProposalState.Defeated; + } + } + + /** + * @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; + } + + /** + * @dev See {IGovernor-proposalDeadline}. + */ + function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) { + return _proposals[proposalId].voteEnd; + } + + /** + * @dev Address of the proposer + */ + function _proposalProposer(uint256 proposalId) internal view virtual returns (address) { + return _proposals[proposalId].proposer; + } + + /** + * @dev Amount of votes already cast passes the threshold limit. + */ + function _quorumReached(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Is the proposal successful or not. + */ + function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`. + */ + 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`. + * + * Note: Support is generic and can represent various things depending on the voting system used. + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal virtual; + + /** + * @dev Default additional encoded parameters used by castVote methods that don't include them + * + * Note: Should be overridden by specific implementations to use an appropriate value, the + * meaning of the additional params, in the context of that implementation + */ + function _defaultParams() internal view virtual returns (bytes memory) { + return ""; + } + + /** + * @dev See {IGovernor-propose}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual override returns (uint256) { + address proposer = _msgSender(); + uint256 currentTimepoint = clock(); + + require( + getVotes(proposer, currentTimepoint - 1) >= proposalThreshold(), + "Governor: proposer votes below proposal threshold" + ); + + uint256 proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description))); + + 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"); + + uint256 snapshot = currentTimepoint + votingDelay(); + uint256 deadline = snapshot + votingPeriod(); + + _proposals[proposalId] = ProposalCore({ + proposer: proposer, + voteStart: snapshot.toUint64(), + voteEnd: deadline.toUint64(), + executed: false, + canceled: false, + __gap_unused0: 0, + __gap_unused1: 0 + }); + + emit ProposalCreated( + proposalId, + proposer, + targets, + values, + new string[](targets.length), + calldatas, + snapshot, + deadline, + description + ); + + return proposalId; + } + + /** + * @dev See {IGovernor-execute}. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual override returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + ProposalState status = state(proposalId); + require( + status == ProposalState.Succeeded || status == ProposalState.Queued, + "Governor: proposal not successful" + ); + _proposals[proposalId].executed = true; + + emit ProposalExecuted(proposalId); + + _beforeExecute(proposalId, targets, values, calldatas, descriptionHash); + _execute(proposalId, targets, values, calldatas, descriptionHash); + _afterExecute(proposalId, targets, values, calldatas, descriptionHash); + + return proposalId; + } + + /** + * @dev See {IGovernor-cancel}. + */ + 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"); + return _cancel(targets, values, calldatas, descriptionHash); + } + + /** + * @dev Internal execution mechanism. Can be overridden to implement different execution mechanism + */ + function _execute( + uint256 /* proposalId */, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual { + string memory errorMessage = "Governor: call reverted without message"; + for (uint256 i = 0; i < targets.length; ++i) { + (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); + Address.verifyCallResult(success, returndata, errorMessage); + } + } + + /** + * @dev Hook before execution is triggered. + */ + function _beforeExecute( + uint256 /* proposalId */, + address[] memory targets, + uint256[] memory /* values */, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual { + if (_executor() != address(this)) { + for (uint256 i = 0; i < targets.length; ++i) { + if (targets[i] == address(this)) { + _governanceCall.pushBack(keccak256(calldatas[i])); + } + } + } + } + + /** + * @dev Hook after execution is triggered. + */ + function _afterExecute( + uint256 /* proposalId */, + address[] memory /* targets */, + uint256[] memory /* values */, + bytes[] memory /* calldatas */, + bytes32 /*descriptionHash*/ + ) internal virtual { + if (_executor() != address(this)) { + if (!_governanceCall.empty()) { + _governanceCall.clear(); + } + } + } + + /** + * @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( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + ProposalState status = state(proposalId); + + require( + status != ProposalState.Canceled && status != ProposalState.Expired && status != ProposalState.Executed, + "Governor: proposal not active" + ); + _proposals[proposalId].canceled = true; + + emit ProposalCanceled(proposalId); + + return proposalId; + } + + /** + * @dev See {IGovernor-getVotes}. + */ + function getVotes(address account, uint256 timepoint) public view virtual override returns (uint256) { + return _getVotes(account, timepoint, _defaultParams()); + } + + /** + * @dev See {IGovernor-getVotesWithParams}. + */ + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) public view virtual override returns (uint256) { + return _getVotes(account, timepoint, params); + } + + /** + * @dev See {IGovernor-castVote}. + */ + function castVote(uint256 proposalId, uint8 support) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, ""); + } + + /** + * @dev See {IGovernor-castVoteWithReason}. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParams}. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev See {IGovernor-castVoteBySig}. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override returns (uint256) { + address voter = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support))), + v, + r, + s + ); + return _castVote(proposalId, voter, support, ""); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override returns (uint256) { + address voter = ECDSA.recover( + _hashTypedDataV4( + keccak256( + abi.encode( + EXTENDED_BALLOT_TYPEHASH, + proposalId, + support, + keccak256(bytes(reason)), + keccak256(params) + ) + ) + ), + v, + r, + s + ); + + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams(). + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason + ) internal virtual returns (uint256) { + return _castVote(proposalId, account, support, reason, _defaultParams()); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual returns (uint256) { + ProposalCore storage proposal = _proposals[proposalId]; + require(state(proposalId) == ProposalState.Active, "Governor: vote not currently active"); + + uint256 weight = _getVotes(account, proposal.voteStart, params); + _countVote(proposalId, account, support, weight, params); + + if (params.length == 0) { + emit VoteCast(account, proposalId, support, weight, reason); + } else { + emit VoteCastWithParams(account, proposalId, support, weight, reason, params); + } + + return weight; + } + + /** + * @dev Relays a transaction or function call to an arbitrary target. In cases where the governance executor + * is some contract other than the governor itself, like when using a timelock, this function can be invoked + * in a governance proposal to recover tokens or Ether that was sent to the governor contract by mistake. + * Note that if the executor is simply the governor itself, use of `relay` is redundant. + */ + function relay(address target, uint256 value, bytes calldata data) external payable virtual onlyGovernance { + (bool success, bytes memory returndata) = target.call{value: value}(data); + Address.verifyCallResult(success, returndata, "Governor: relay reverted without message"); + } + + /** + * @dev Address through which the governor executes action. Will be overloaded by module that execute actions + * through another contract such as a timelock. + */ + function _executor() internal view virtual returns (address) { + return address(this); + } + + /** + * @dev See {IERC721Receiver-onERC721Received}. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { + return this.onERC721Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155Received}. + */ + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155BatchReceived}. + */ + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol new file mode 100644 index 0000000..70f81ef --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (governance/IGovernor.sol) + +pragma solidity ^0.8.0; + +import "../interfaces/IERC165.sol"; +import "../interfaces/IERC6372.sol"; + +/** + * @dev Interface of the {Governor} core. + * + * _Available since v4.3._ + */ +abstract contract IGovernor is IERC165, IERC6372 { + enum ProposalState { + Pending, + Active, + Canceled, + Defeated, + Succeeded, + Queued, + Expired, + Executed + } + + /** + * @dev Emitted when a proposal is created. + */ + event ProposalCreated( + uint256 proposalId, + address proposer, + address[] targets, + uint256[] values, + string[] signatures, + bytes[] calldatas, + uint256 voteStart, + uint256 voteEnd, + string description + ); + + /** + * @dev Emitted when a proposal is canceled. + */ + event ProposalCanceled(uint256 proposalId); + + /** + * @dev Emitted when a proposal is executed. + */ + event ProposalExecuted(uint256 proposalId); + + /** + * @dev Emitted when a vote is cast without params. + * + * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. + */ + event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason); + + /** + * @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 interpepretation also depends on the voting module used. + */ + event VoteCastWithParams( + address indexed voter, + uint256 proposalId, + uint8 support, + uint256 weight, + string reason, + bytes params + ); + + /** + * @notice module:core + * @dev Name of the governor instance (used in building the ERC712 domain separator). + */ + function name() public view virtual returns (string memory); + + /** + * @notice module:core + * @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1" + */ + 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 + * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of + * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`. + * + * There are 2 standard keys: `support` and `quorum`. + * + * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`. + * - `quorum=bravo` means that only For votes are counted towards quorum. + * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum. + * + * If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique + * name that describes the behavior. For example: + * + * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain. + * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote. + * + * NOTE: The string can be decoded by the standard + * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`] + * JavaScript class. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public view virtual returns (string memory); + + /** + * @notice module:core + * @dev Hashing function used to (re)build the proposal id from the proposal details.. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public pure virtual returns (uint256); + + /** + * @notice module:core + * @dev Current state of a proposal, following Compound's convention + */ + function state(uint256 proposalId) public view virtual returns (ProposalState); + + /** + * @notice module:core + * @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 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, 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, 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. + */ + function votingPeriod() public view virtual returns (uint256); + + /** + * @notice module:user-config + * @dev Minimum number of cast voted required for a proposal to be successful. + * + * 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 timepoint) public view virtual returns (uint256); + + /** + * @notice module:reputation + * @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 timepoint) public view virtual returns (uint256); + + /** + * @notice module:reputation + * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters. + */ + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) public view virtual returns (uint256); + + /** + * @notice module:voting + * @dev Returns whether `account` has cast a vote on `proposalId`. + */ + function hasVoted(uint256 proposalId, address account) public view virtual returns (bool); + + /** + * @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. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual returns (uint256 proposalId); + + /** + * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the + * deadline to be reached. + * + * Emits a {ProposalExecuted} event. + * + * Note: some module can modify the requirements for execution, for example by adding an additional timelock. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual returns (uint256 proposalId); + + /** + * @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( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256 proposalId); + + /** + * @dev Cast a vote + * + * Emits a {VoteCast} event. + */ + function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason + * + * Emits a {VoteCast} event. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote using the user's cryptographic signature. + * + * Emits a {VoteCast} event. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters using the user's cryptographic signature. + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual returns (uint256 balance); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/README.adoc new file mode 100644 index 0000000..6d53e97 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/README.adoc @@ -0,0 +1,176 @@ += Governance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/governance + +This directory includes primitives for on-chain governance. + +== Governor + +This modular system of Governor contracts allows the deployment on-chain voting protocols similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo] and beyond, through the ability to easily customize multiple aspects of the protocol. + +[TIP] +==== +For a guided experience, set up your Governor contract using https://wizard.openzeppelin.com/#governor[Contracts Wizard]. + +For a written walkthrough, check out our guide on xref:ROOT:governance.adoc[How to set up on-chain governance]. +==== + +* {Governor}: The core contract that contains all the logic and primitives. It is abstract and requires choosing one of each of the modules below, or custom ones. + +Votes modules determine the source of voting power, and sometimes quorum number. + +* {GovernorVotes}: Extracts voting weight from an {ERC20Votes}, or since v4.5 an {ERC721Votes} token. + +* {GovernorVotesComp}: Extracts voting weight from a COMP-like or {ERC20VotesComp} token. + +* {GovernorVotesQuorumFraction}: Combines with `GovernorVotes` to set the quorum as a fraction of the total token supply. + +Counting modules determine valid voting options. + +* {GovernorCountingSimple}: Simple voting mechanism with 3 voting options: Against, For and Abstain. + +Timelock extensions add a delay for governance decisions to be executed. The workflow is extended to require a `queue` step before execution. With these modules, proposals are executed by the external timelock contract, thus it is the timelock that has to hold the assets that are being governed. + +* {GovernorTimelockControl}: Connects with an instance of {TimelockController}. Allows multiple proposers and executors, in addition to the Governor itself. + +* {GovernorTimelockCompound}: Connects with an instance of Compound's https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[`Timelock`] contract. + +Other extensions can customize the behavior or interface in multiple ways. + +* {GovernorCompatibilityBravo}: Extends the interface to be fully `GovernorBravo`-compatible. Note that events are compatible regardless of whether this extension is included or not. + +* {GovernorSettings}: Manages some of the settings (voting delay, voting period duration, and proposal threshold) in a way that can be updated through a governance proposal, without requiring an upgrade. + +* {GovernorPreventLateQuorum}: Ensures there is a minimum voting period after quorum is reached as a security protection against large voters. + +In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications: + +* <>: 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. + +=== Core + +{{IGovernor}} + +{{Governor}} + +=== Modules + +{{GovernorCountingSimple}} + +{{GovernorVotes}} + +{{GovernorVotesQuorumFraction}} + +{{GovernorVotesComp}} + +=== Extensions + +{{GovernorTimelockControl}} + +{{GovernorTimelockCompound}} + +{{GovernorSettings}} + +{{GovernorPreventLateQuorum}} + +{{GovernorCompatibilityBravo}} + +=== Deprecated + +{{GovernorProposalThreshold}} + +== Utils + +{{Votes}} + +== Timelock + +In a governance system, the {TimelockController} contract is in charge of introducing a delay between a proposal and its execution. It can be used with or without a {Governor}. + +{{TimelockController}} + +[[timelock-terminology]] +==== Terminology + +* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content. +* *Operation status:* +** *Unset:* An operation that is not part of the timelock mechanism. +** *Pending:* An operation that has been scheduled, before the timer expires. +** *Ready:* An operation that has been scheduled, after the timer expires. +** *Done:* An operation that has been executed. +* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations. +* *Role*: +** *Admin:* An address (smart contract or EOA) that is in charge of granting the roles of Proposer and Executor. +** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations. +** *Executor:* An address (smart contract or EOA) that is in charge of executing operations once the timelock has expired. This role can be given to the zero address to allow anyone to execute operations. + +[[timelock-operation]] +==== Operation structure + +Operation executed by the xref:api:governance.adoc#TimelockController[`TimelockController`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations. + +Both operations contain: + +* *Target*, the address of the smart contract that the timelock should operate on. +* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction. +* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encoded using web3js as follows: + +```javascript +const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI() +``` + +* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency. +* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value. + +In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length. + +[[timelock-operation-lifecycle]] +==== Operation lifecycle + +Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle: + +`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done` + +* By calling xref:api:governance.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:governance.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:governance.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method. +* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed. +* By calling xref:api:governance.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:governance.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed. +* xref:api:governance.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled. + +Operations status can be queried using the functions: + +* xref:api:governance.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`] +* xref:api:governance.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`] +* xref:api:governance.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`] + +[[timelock-roles]] +==== Roles + +[[timelock-admin]] +===== Admin + +The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, the admin role can be granted to any address (in addition to the timelock itself). After further configuration and testing, this optional admin should renounce its role such that all further maintenance operations have to go through the timelock process. + +This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5` + +[[timelock-proposer]] +===== Proposer + +The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO. + +WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers. + +This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1` + +[[timelock-executor]] +===== Executor + +The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executors can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers. Alternatively, it is possible to allow _any_ address to execute a proposal once the timelock has expired by granting the executor role to the zero address. + +This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63` + +WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management. diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol new file mode 100644 index 0000000..615b4c0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (governance/TimelockController.sol) + +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 + * owner of an `Ownable` smart contract, it enforces a timelock on all + * `onlyOwner` maintenance operations. This gives time for users of the + * controlled contract to exit before a potentially dangerous maintenance + * operation is applied. + * + * By default, this contract is self administered, meaning administration tasks + * have to go through the timelock process. The proposer (resp executor) role + * is in charge of proposing (resp executing) operations. A common use case is + * to position this {TimelockController} as the owner of a smart contract, with + * a multisig or a DAO as the sole proposer. + * + * _Available since v3.3._ + */ +contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver { + bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE"); + bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); + bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); + bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); + uint256 internal constant _DONE_TIMESTAMP = uint256(1); + + mapping(bytes32 => uint256) private _timestamps; + uint256 private _minDelay; + + /** + * @dev Emitted when a call is scheduled as part of operation `id`. + */ + event CallScheduled( + bytes32 indexed id, + uint256 indexed index, + address target, + uint256 value, + bytes data, + bytes32 predecessor, + uint256 delay + ); + + /** + * @dev Emitted when a call is performed as part of operation `id`. + */ + 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. + */ + event Cancelled(bytes32 indexed id); + + /** + * @dev Emitted when the minimum delay for future operations is modified. + */ + event MinDelayChange(uint256 oldDuration, uint256 newDuration); + + /** + * @dev Initializes the contract with the following parameters: + * + * - `minDelay`: initial minimum delay for operations + * - `proposers`: accounts to be granted proposer and canceller roles + * - `executors`: accounts to be granted executor role + * - `admin`: optional account to be granted admin role; disable with zero address + * + * IMPORTANT: The optional admin can aid with initial configuration of roles after deployment + * without being subject to delay, but this role should be subsequently renounced in favor of + * administration through timelocked proposals. Previous versions of this contract would assign + * this admin to the deployer automatically and should be renounced as well. + */ + constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) { + _setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE); + _setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE); + _setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE); + _setRoleAdmin(CANCELLER_ROLE, TIMELOCK_ADMIN_ROLE); + + // self administration + _setupRole(TIMELOCK_ADMIN_ROLE, address(this)); + + // optional admin + if (admin != address(0)) { + _setupRole(TIMELOCK_ADMIN_ROLE, admin); + } + + // register proposers and cancellers + for (uint256 i = 0; i < proposers.length; ++i) { + _setupRole(PROPOSER_ROLE, proposers[i]); + _setupRole(CANCELLER_ROLE, proposers[i]); + } + + // register executors + for (uint256 i = 0; i < executors.length; ++i) { + _setupRole(EXECUTOR_ROLE, executors[i]); + } + + _minDelay = minDelay; + emit MinDelayChange(0, minDelay); + } + + /** + * @dev Modifier to make a function callable only by a certain role. In + * addition to checking the sender's role, `address(0)` 's role is also + * considered. Granting a role to `address(0)` is equivalent to enabling + * this role for everyone. + */ + modifier onlyRoleOrOpenRole(bytes32 role) { + if (!hasRole(role, address(0))) { + _checkRole(role, _msgSender()); + } + _; + } + + /** + * @dev Contract might receive/hold ETH as part of the maintenance process. + */ + receive() external payable {} + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, AccessControl) returns (bool) { + return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @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) { + return getTimestamp(id) > 0; + } + + /** + * @dev Returns whether an operation is pending or not. + */ + function isOperationPending(bytes32 id) public view virtual returns (bool pending) { + return getTimestamp(id) > _DONE_TIMESTAMP; + } + + /** + * @dev Returns whether an operation is ready or not. + */ + function isOperationReady(bytes32 id) public view virtual returns (bool ready) { + uint256 timestamp = getTimestamp(id); + return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp; + } + + /** + * @dev Returns whether an operation is done or not. + */ + function isOperationDone(bytes32 id) public view virtual returns (bool done) { + return getTimestamp(id) == _DONE_TIMESTAMP; + } + + /** + * @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) { + return _timestamps[id]; + } + + /** + * @dev Returns the minimum delay for an operation to become valid. + * + * This value can be changed by executing an operation that calls `updateDelay`. + */ + function getMinDelay() public view virtual returns (uint256 duration) { + return _minDelay; + } + + /** + * @dev Returns the identifier of an operation containing a single + * transaction. + */ + function hashOperation( + address target, + uint256 value, + bytes calldata data, + bytes32 predecessor, + bytes32 salt + ) public pure virtual returns (bytes32 hash) { + return keccak256(abi.encode(target, value, data, predecessor, salt)); + } + + /** + * @dev Returns the identifier of an operation containing a batch of + * transactions. + */ + function hashOperationBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt + ) public pure virtual returns (bytes32 hash) { + return keccak256(abi.encode(targets, values, payloads, predecessor, salt)); + } + + /** + * @dev Schedule an operation containing a single transaction. + * + * Emits events {CallScheduled} and {CallSalt}. + * + * Requirements: + * + * - the caller must have the 'proposer' role. + */ + function schedule( + address target, + uint256 value, + bytes calldata data, + bytes32 predecessor, + bytes32 salt, + uint256 delay + ) public virtual onlyRole(PROPOSER_ROLE) { + 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 a {CallSalt} event and one {CallScheduled} event per transaction in the batch. + * + * Requirements: + * + * - the caller must have the 'proposer' role. + */ + function scheduleBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt, + uint256 delay + ) public virtual onlyRole(PROPOSER_ROLE) { + require(targets.length == values.length, "TimelockController: length mismatch"); + require(targets.length == payloads.length, "TimelockController: length mismatch"); + + bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + _schedule(id, delay); + 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); + } + } + + /** + * @dev Schedule an operation that is to become valid after a given delay. + */ + function _schedule(bytes32 id, uint256 delay) private { + require(!isOperation(id), "TimelockController: operation already scheduled"); + require(delay >= getMinDelay(), "TimelockController: insufficient delay"); + _timestamps[id] = block.timestamp + delay; + } + + /** + * @dev Cancel an operation. + * + * Requirements: + * + * - the caller must have the 'canceller' role. + */ + function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) { + require(isOperationPending(id), "TimelockController: operation cannot be cancelled"); + delete _timestamps[id]; + + emit Cancelled(id); + } + + /** + * @dev Execute an (ready) operation containing a single transaction. + * + * Emits a {CallExecuted} event. + * + * Requirements: + * + * - the caller must have the 'executor' role. + */ + // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, + // thus any modifications to the operation during reentrancy should be caught. + // slither-disable-next-line reentrancy-eth + function execute( + address target, + uint256 value, + bytes calldata payload, + bytes32 predecessor, + bytes32 salt + ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { + bytes32 id = hashOperation(target, value, payload, predecessor, salt); + + _beforeCall(id, predecessor); + _execute(target, value, payload); + emit CallExecuted(id, 0, target, value, payload); + _afterCall(id); + } + + /** + * @dev Execute an (ready) operation containing a batch of transactions. + * + * Emits one {CallExecuted} event per transaction in the batch. + * + * Requirements: + * + * - the caller must have the 'executor' role. + */ + // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, + // thus any modifications to the operation during reentrancy should be caught. + // slither-disable-next-line reentrancy-eth + function executeBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt + ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { + require(targets.length == values.length, "TimelockController: length mismatch"); + require(targets.length == payloads.length, "TimelockController: length mismatch"); + + bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + + _beforeCall(id, predecessor); + for (uint256 i = 0; i < targets.length; ++i) { + address target = targets[i]; + uint256 value = values[i]; + bytes calldata payload = payloads[i]; + _execute(target, value, payload); + emit CallExecuted(id, i, target, value, payload); + } + _afterCall(id); + } + + /** + * @dev Execute an operation's call. + */ + function _execute(address target, uint256 value, bytes calldata data) internal virtual { + (bool success, ) = target.call{value: value}(data); + require(success, "TimelockController: underlying transaction reverted"); + } + + /** + * @dev Checks before execution of an operation's calls. + */ + function _beforeCall(bytes32 id, bytes32 predecessor) private view { + require(isOperationReady(id), "TimelockController: operation is not ready"); + require(predecessor == bytes32(0) || isOperationDone(predecessor), "TimelockController: missing dependency"); + } + + /** + * @dev Checks after execution of an operation's calls. + */ + function _afterCall(bytes32 id) private { + require(isOperationReady(id), "TimelockController: operation is not ready"); + _timestamps[id] = _DONE_TIMESTAMP; + } + + /** + * @dev Changes the minimum timelock duration for future operations. + * + * Emits a {MinDelayChange} event. + * + * Requirements: + * + * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing + * an operation where the timelock is the target and the data is the ABI-encoded call to this function. + */ + function updateDelay(uint256 newDelay) external virtual { + require(msg.sender == address(this), "TimelockController: caller must be timelock"); + emit MinDelayChange(_minDelay, newDelay); + _minDelay = newDelay; + } + + /** + * @dev See {IERC721Receiver-onERC721Received}. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { + return this.onERC721Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155Received}. + */ + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155BatchReceived}. + */ + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/compatibility/GovernorCompatibilityBravo.sol new file mode 100644 index 0000000..39c895b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (governance/compatibility/GovernorCompatibilityBravo.sol) + +pragma solidity ^0.8.0; + +import "../../utils/math/SafeCast.sol"; +import "../extensions/IGovernorTimelock.sol"; +import "../Governor.sol"; +import "./IGovernorCompatibilityBravo.sol"; + +/** + * @dev Compatibility layer that implements GovernorBravo compatibility on top of {Governor}. + * + * This compatibility layer includes a voting system and requires a {IGovernorTimelock} compatible module to be added + * through inheritance. It does not include token bindings, nor does it include any variable upgrade patterns. + * + * NOTE: When using this module, you may need to enable the Solidity optimizer to avoid hitting the contract size limit. + * + * _Available since v4.3._ + */ +abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorCompatibilityBravo, Governor { + enum VoteType { + Against, + For, + Abstain + } + + struct ProposalDetails { + address proposer; + address[] targets; + uint256[] values; + string[] signatures; + bytes[] calldatas; + uint256 forVotes; + uint256 againstVotes; + uint256 abstainVotes; + mapping(address => Receipt) receipts; + bytes32 descriptionHash; + } + + mapping(uint256 => ProposalDetails) private _proposalDetails; + + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo&quorum=bravo"; + } + + // ============================================== Proposal lifecycle ============================================== + /** + * @dev See {IGovernor-propose}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual override(IGovernor, Governor) returns (uint256) { + _storeProposal(_msgSender(), targets, values, new string[](calldatas.length), calldatas, description); + return super.propose(targets, values, calldatas, description); + } + + /** + * @dev See {IGovernorCompatibilityBravo-propose}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) public virtual override returns (uint256) { + _storeProposal(_msgSender(), targets, values, signatures, calldatas, description); + return propose(targets, values, _encodeCalldata(signatures, calldatas), description); + } + + /** + * @dev See {IGovernorCompatibilityBravo-queue}. + */ + function queue(uint256 proposalId) public virtual override { + ( + 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 { + ( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) = _getProposalParameters(proposalId); + + execute(targets, values, calldatas, descriptionHash); + } + + /** + * @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( + _msgSender() == proposer || getVotes(proposer, clock() - 1) < proposalThreshold(), + "GovernorBravo: proposer above threshold" + ); + + return _cancel(targets, values, calldatas, descriptionHash); + } + + /** + * @dev Encodes calldatas with optional function signature. + */ + function _encodeCalldata( + string[] memory signatures, + bytes[] memory calldatas + ) private pure returns (bytes[] memory) { + bytes[] memory fullcalldatas = new bytes[](calldatas.length); + + for (uint256 i = 0; i < signatures.length; ++i) { + fullcalldatas[i] = bytes(signatures[i]).length == 0 + ? calldatas[i] + : abi.encodePacked(bytes4(keccak256(bytes(signatures[i]))), calldatas[i]); + } + + 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 + */ + function _storeProposal( + address proposer, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) private { + bytes32 descriptionHash = keccak256(bytes(description)); + uint256 proposalId = hashProposal(targets, values, _encodeCalldata(signatures, calldatas), descriptionHash); + + ProposalDetails storage details = _proposalDetails[proposalId]; + if (details.descriptionHash == bytes32(0)) { + details.proposer = proposer; + details.targets = targets; + details.values = values; + details.signatures = signatures; + details.calldatas = calldatas; + details.descriptionHash = descriptionHash; + } + } + + // ==================================================== Views ===================================================== + /** + * @dev See {IGovernorCompatibilityBravo-proposals}. + */ + function proposals( + uint256 proposalId + ) + public + view + virtual + override + returns ( + uint256 id, + address proposer, + uint256 eta, + uint256 startBlock, + uint256 endBlock, + uint256 forVotes, + uint256 againstVotes, + uint256 abstainVotes, + bool canceled, + bool executed + ) + { + id = proposalId; + eta = proposalEta(proposalId); + startBlock = proposalSnapshot(proposalId); + endBlock = proposalDeadline(proposalId); + + ProposalDetails storage details = _proposalDetails[proposalId]; + proposer = details.proposer; + forVotes = details.forVotes; + againstVotes = details.againstVotes; + abstainVotes = details.abstainVotes; + + ProposalState status = state(proposalId); + canceled = status == ProposalState.Canceled; + executed = status == ProposalState.Executed; + } + + /** + * @dev See {IGovernorCompatibilityBravo-getActions}. + */ + function getActions( + uint256 proposalId + ) + public + view + virtual + override + returns ( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas + ) + { + ProposalDetails storage details = _proposalDetails[proposalId]; + return (details.targets, details.values, details.signatures, details.calldatas); + } + + /** + * @dev See {IGovernorCompatibilityBravo-getReceipt}. + */ + function getReceipt(uint256 proposalId, address voter) public view virtual override returns (Receipt memory) { + return _proposalDetails[proposalId].receipts[voter]; + } + + /** + * @dev See {IGovernorCompatibilityBravo-quorumVotes}. + */ + function quorumVotes() public view virtual override returns (uint256) { + return quorum(clock() - 1); + } + + // ==================================================== Voting ==================================================== + /** + * @dev See {IGovernor-hasVoted}. + */ + function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { + return _proposalDetails[proposalId].receipts[account].hasVoted; + } + + /** + * @dev See {Governor-_quorumReached}. In this module, only forVotes count toward the quorum. + */ + function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { + ProposalDetails storage details = _proposalDetails[proposalId]; + return quorum(proposalSnapshot(proposalId)) <= details.forVotes; + } + + /** + * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes. + */ + function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) { + ProposalDetails storage details = _proposalDetails[proposalId]; + return details.forVotes > details.againstVotes; + } + + /** + * @dev See {Governor-_countVote}. In this module, the support follows Governor Bravo. + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory // params + ) internal virtual override { + ProposalDetails storage details = _proposalDetails[proposalId]; + Receipt storage receipt = details.receipts[account]; + + require(!receipt.hasVoted, "GovernorCompatibilityBravo: vote already cast"); + receipt.hasVoted = true; + receipt.support = support; + receipt.votes = SafeCast.toUint96(weight); + + if (support == uint8(VoteType.Against)) { + details.againstVotes += weight; + } else if (support == uint8(VoteType.For)) { + details.forVotes += weight; + } else if (support == uint8(VoteType.Abstain)) { + details.abstainVotes += weight; + } else { + revert("GovernorCompatibilityBravo: invalid vote type"); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol new file mode 100644 index 0000000..159c551 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (governance/compatibility/IGovernorCompatibilityBravo.sol) + +pragma solidity ^0.8.0; + +import "../IGovernor.sol"; + +/** + * @dev Interface extension that adds missing functions to the {Governor} core to provide `GovernorBravo` compatibility. + * + * _Available since v4.3._ + */ +abstract contract IGovernorCompatibilityBravo is IGovernor { + /** + * @dev Proposal structure from Compound Governor Bravo. Not actually used by the compatibility layer, as + * {{proposal}} returns a very different structure. + */ + struct Proposal { + uint256 id; + address proposer; + uint256 eta; + address[] targets; + uint256[] values; + string[] signatures; + bytes[] calldatas; + uint256 startBlock; + uint256 endBlock; + uint256 forVotes; + uint256 againstVotes; + uint256 abstainVotes; + bool canceled; + bool executed; + mapping(address => Receipt) receipts; + } + + /** + * @dev Receipt structure from Compound Governor Bravo + */ + struct Receipt { + bool hasVoted; + uint8 support; + uint96 votes; + } + + /** + * @dev Part of the Governor Bravo's interface. + */ + function quorumVotes() public view virtual returns (uint256); + + /** + * @dev Part of the Governor Bravo's interface: _"The official record of all proposals ever proposed"_. + */ + function proposals( + uint256 + ) + public + view + virtual + returns ( + uint256 id, + address proposer, + uint256 eta, + uint256 startBlock, + uint256 endBlock, + uint256 forVotes, + uint256 againstVotes, + uint256 abstainVotes, + bool canceled, + bool executed + ); + + /** + * @dev Part of the Governor Bravo's interface: _"Function used to propose a new proposal"_. + */ + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) public virtual returns (uint256); + + /** + * @dev Part of the Governor Bravo's interface: _"Queues a proposal of state succeeded"_. + */ + function queue(uint256 proposalId) public virtual; + + /** + * @dev Part of the Governor Bravo's interface: _"Executes a queued proposal if eta has passed"_. + */ + function execute(uint256 proposalId) public payable virtual; + + /** + * @dev Part of the Governor Bravo's interface: _"Gets actions of a proposal"_. + */ + function getActions( + uint256 proposalId + ) + public + view + virtual + returns ( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas + ); + + /** + * @dev Part of the Governor Bravo's interface: _"Gets the receipt for a voter on a given proposal"_. + */ + function getReceipt(uint256 proposalId, address voter) public view virtual returns (Receipt memory); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol new file mode 100644 index 0000000..f3eea9d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (governance/extensions/GovernorCountingSimple.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; + +/** + * @dev Extension of {Governor} for simple, 3 options, vote counting. + * + * _Available since v4.3._ + */ +abstract contract GovernorCountingSimple is Governor { + /** + * @dev Supported vote types. Matches Governor Bravo ordering. + */ + enum VoteType { + Against, + For, + Abstain + } + + struct ProposalVote { + uint256 againstVotes; + uint256 forVotes; + uint256 abstainVotes; + mapping(address => bool) hasVoted; + } + + mapping(uint256 => ProposalVote) private _proposalVotes; + + /** + * @dev See {IGovernor-COUNTING_MODE}. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo&quorum=for,abstain"; + } + + /** + * @dev See {IGovernor-hasVoted}. + */ + function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { + return _proposalVotes[proposalId].hasVoted[account]; + } + + /** + * @dev Accessor to the internal vote counts. + */ + function proposalVotes( + uint256 proposalId + ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + return (proposalVote.againstVotes, proposalVote.forVotes, proposalVote.abstainVotes); + } + + /** + * @dev See {Governor-_quorumReached}. + */ + function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + return quorum(proposalSnapshot(proposalId)) <= proposalVote.forVotes + proposalVote.abstainVotes; + } + + /** + * @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) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + return proposalVote.forVotes > proposalVote.againstVotes; + } + + /** + * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo). + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory // params + ) internal virtual override { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + require(!proposalVote.hasVoted[account], "GovernorVotingSimple: vote already cast"); + proposalVote.hasVoted[account] = true; + + if (support == uint8(VoteType.Against)) { + proposalVote.againstVotes += weight; + } else if (support == uint8(VoteType.For)) { + proposalVote.forVotes += weight; + } else if (support == uint8(VoteType.Abstain)) { + proposalVote.abstainVotes += weight; + } else { + revert("GovernorVotingSimple: invalid value for enum VoteType"); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol new file mode 100644 index 0000000..676d2b1 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (governance/extensions/GovernorPreventLateQuorum.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; +import "../../utils/math/Math.sol"; + +/** + * @dev A module that ensures there is a minimum voting period after quorum is reached. This prevents a large voter from + * swaying a vote and triggering quorum at the last minute, by ensuring there is always time for other voters to react + * 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). + * + * _Available since v4.5._ + */ +abstract contract GovernorPreventLateQuorum is Governor { + using SafeCast for uint256; + + uint64 private _voteExtension; + + /// @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); + + /// @dev Emitted when the {lateQuorumVoteExtension} parameter is changed. + 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. + */ + constructor(uint64 initialVoteExtension) { + _setLateQuorumVoteExtension(initialVoteExtension); + } + + /** + * @dev Returns the proposal deadline, which may have been extended beyond that set at proposal creation, if the + * 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]); + } + + /** + * @dev Casts a vote and detects if it caused quorum to be reached, potentially extending the voting period. See + * {Governor-_castVote}. + * + * May emit a {ProposalExtended} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual override returns (uint256) { + uint256 result = super._castVote(proposalId, account, support, reason, params); + + if (_extendedDeadlines[proposalId] == 0 && _quorumReached(proposalId)) { + uint64 extendedDeadline = clock() + lateQuorumVoteExtension(); + + if (extendedDeadline > proposalDeadline(proposalId)) { + emit ProposalExtended(proposalId, extendedDeadline); + } + + _extendedDeadlines[proposalId] = extendedDeadline; + } + + return result; + } + + /** + * @dev Returns the current value of the vote extension parameter: the number of blocks that are required to pass + * from the time a proposal reaches quorum until its voting period ends. + */ + function lateQuorumVoteExtension() public view virtual returns (uint64) { + return _voteExtension; + } + + /** + * @dev Changes the {lateQuorumVoteExtension}. This operation can only be performed by the governance executor, + * generally through a governance proposal. + * + * Emits a {LateQuorumVoteExtensionSet} event. + */ + function setLateQuorumVoteExtension(uint64 newVoteExtension) public virtual onlyGovernance { + _setLateQuorumVoteExtension(newVoteExtension); + } + + /** + * @dev Changes the {lateQuorumVoteExtension}. This is an internal function that can be exposed in a public function + * like {setLateQuorumVoteExtension} if another access control mechanism is needed. + * + * Emits a {LateQuorumVoteExtensionSet} event. + */ + function _setLateQuorumVoteExtension(uint64 newVoteExtension) internal virtual { + emit LateQuorumVoteExtensionSet(_voteExtension, newVoteExtension); + _voteExtension = newVoteExtension; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalThreshold.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalThreshold.sol new file mode 100644 index 0000000..3feebac --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalThreshold.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (governance/extensions/GovernorProposalThreshold.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; + +/** + * @dev Extension of {Governor} for proposal restriction to token holders with a minimum balance. + * + * _Available since v4.3._ + * _Deprecated since v4.4._ + */ +abstract contract GovernorProposalThreshold is Governor { + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual override returns (uint256) { + return super.propose(targets, values, calldatas, description); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol new file mode 100644 index 0000000..527f41c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (governance/extensions/GovernorSettings.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; + +/** + * @dev Extension of {Governor} for settings updatable through governance. + * + * _Available since v4.4._ + */ +abstract contract GovernorSettings is Governor { + uint256 private _votingDelay; + uint256 private _votingPeriod; + uint256 private _proposalThreshold; + + event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay); + event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod); + event ProposalThresholdSet(uint256 oldProposalThreshold, uint256 newProposalThreshold); + + /** + * @dev Initialize the governance parameters. + */ + constructor(uint256 initialVotingDelay, uint256 initialVotingPeriod, uint256 initialProposalThreshold) { + _setVotingDelay(initialVotingDelay); + _setVotingPeriod(initialVotingPeriod); + _setProposalThreshold(initialProposalThreshold); + } + + /** + * @dev See {IGovernor-votingDelay}. + */ + function votingDelay() public view virtual override returns (uint256) { + return _votingDelay; + } + + /** + * @dev See {IGovernor-votingPeriod}. + */ + function votingPeriod() public view virtual override returns (uint256) { + return _votingPeriod; + } + + /** + * @dev See {Governor-proposalThreshold}. + */ + function proposalThreshold() public view virtual override returns (uint256) { + return _proposalThreshold; + } + + /** + * @dev Update the voting delay. This operation can only be performed through a governance proposal. + * + * Emits a {VotingDelaySet} event. + */ + function setVotingDelay(uint256 newVotingDelay) public virtual onlyGovernance { + _setVotingDelay(newVotingDelay); + } + + /** + * @dev Update the voting period. This operation can only be performed through a governance proposal. + * + * Emits a {VotingPeriodSet} event. + */ + function setVotingPeriod(uint256 newVotingPeriod) public virtual onlyGovernance { + _setVotingPeriod(newVotingPeriod); + } + + /** + * @dev Update the proposal threshold. This operation can only be performed through a governance proposal. + * + * Emits a {ProposalThresholdSet} event. + */ + function setProposalThreshold(uint256 newProposalThreshold) public virtual onlyGovernance { + _setProposalThreshold(newProposalThreshold); + } + + /** + * @dev Internal setter for the voting delay. + * + * Emits a {VotingDelaySet} event. + */ + function _setVotingDelay(uint256 newVotingDelay) internal virtual { + emit VotingDelaySet(_votingDelay, newVotingDelay); + _votingDelay = newVotingDelay; + } + + /** + * @dev Internal setter for the voting period. + * + * Emits a {VotingPeriodSet} event. + */ + function _setVotingPeriod(uint256 newVotingPeriod) internal virtual { + // voting period must be at least one block long + require(newVotingPeriod > 0, "GovernorSettings: voting period too low"); + emit VotingPeriodSet(_votingPeriod, newVotingPeriod); + _votingPeriod = newVotingPeriod; + } + + /** + * @dev Internal setter for the proposal threshold. + * + * Emits a {ProposalThresholdSet} event. + */ + function _setProposalThreshold(uint256 newProposalThreshold) internal virtual { + emit ProposalThresholdSet(_proposalThreshold, newProposalThreshold); + _proposalThreshold = newProposalThreshold; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol new file mode 100644 index 0000000..629f8f8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (governance/extensions/GovernorTimelockCompound.sol) + +pragma solidity ^0.8.0; + +import "./IGovernorTimelock.sol"; +import "../Governor.sol"; +import "../../utils/math/SafeCast.sol"; +import "../../vendor/compound/ICompoundTimelock.sol"; + +/** + * @dev Extension of {Governor} that binds the execution process to a Compound Timelock. This adds a delay, enforced by + * the external timelock to all successful proposal (in addition to the voting duration). The {Governor} needs to be + * the admin of the timelock for any operation to be performed. A public, unrestricted, + * {GovernorTimelockCompound-__acceptAdmin} is available to accept ownership of the timelock. + * + * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * inaccessible. + * + * _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) + mapping(uint256 => uint64) private _proposalTimelocks; + + /** + * @dev Emitted when the timelock controller used for proposal execution is modified. + */ + event TimelockChange(address oldTimelock, address newTimelock); + + /** + * @dev Set the timelock. + */ + constructor(ICompoundTimelock timelockAddress) { + _updateTimelock(timelockAddress); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, Governor) returns (bool) { + return interfaceId == type(IGovernorTimelock).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Overridden version of the {Governor-state} function with added support for the `Queued` and `Expired` status. + */ + function state(uint256 proposalId) public view virtual override(IGovernor, Governor) returns (ProposalState) { + ProposalState status = super.state(proposalId); + + if (status != ProposalState.Succeeded) { + return status; + } + + uint256 eta = proposalEta(proposalId); + if (eta == 0) { + return status; + } else if (block.timestamp >= eta + _timelock.GRACE_PERIOD()) { + return ProposalState.Expired; + } else { + return ProposalState.Queued; + } + } + + /** + * @dev Public accessor to check the address of the timelock + */ + function timelock() public view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Public accessor to check the eta of a queued proposal + */ + function proposalEta(uint256 proposalId) public view virtual override returns (uint256) { + return _proposalTimelocks[proposalId]; + } + + /** + * @dev Function to queue a proposal to the timelock. + */ + function queue( + 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.Succeeded, "Governor: proposal not successful"); + + uint256 eta = block.timestamp + _timelock.delay(); + _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))), + "GovernorTimelockCompound: identical proposal action already queued" + ); + _timelock.queueTransaction(targets[i], values[i], "", calldatas[i], eta); + } + + emit ProposalQueued(proposalId, eta); + + return proposalId; + } + + /** + * @dev Overridden execute function that run the already queued proposal through the timelock. + */ + function _execute( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual override { + uint256 eta = proposalEta(proposalId); + require(eta > 0, "GovernorTimelockCompound: proposal not yet queued"); + Address.sendValue(payable(_timelock), msg.value); + for (uint256 i = 0; i < targets.length; ++i) { + _timelock.executeTransaction(targets[i], values[i], "", calldatas[i], eta); + } + } + + /** + * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it as already + * been queued. + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + 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); + } + } + + return proposalId; + } + + /** + * @dev Address through which the governor executes action. In this case, the timelock. + */ + function _executor() internal view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Accept admin right over the timelock. + */ + // solhint-disable-next-line private-vars-leading-underscore + function __acceptAdmin() public { + _timelock.acceptAdmin(); + } + + /** + * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates + * must be proposed, scheduled, and executed through governance proposals. + * + * For security reasons, the timelock must be handed over to another admin before setting up a new one. The two + * operations (hand over the timelock) and do the update can be batched in a single proposal. + * + * Note that if the timelock admin has been handed over in a previous operation, we refuse updates made through the + * timelock if admin of the timelock has already been accepted and the operation is executed outside the scope of + * governance. + + * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. + */ + function updateTimelock(ICompoundTimelock newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(ICompoundTimelock newTimelock) private { + emit TimelockChange(address(_timelock), address(newTimelock)); + _timelock = newTimelock; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol new file mode 100644 index 0000000..6aa2556 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (governance/extensions/GovernorTimelockControl.sol) + +pragma solidity ^0.8.0; + +import "./IGovernorTimelock.sol"; +import "../Governor.sol"; +import "../TimelockController.sol"; + +/** + * @dev Extension of {Governor} that binds the execution process to an instance of {TimelockController}. This adds a + * delay, enforced by the {TimelockController} to all successful proposal (in addition to the voting duration). The + * {Governor} needs the proposer (and ideally the executor) roles for the {Governor} to work properly. + * + * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * inaccessible. + * + * WARNING: Setting up the TimelockController to have additional proposers besides the governor is very risky, as it + * grants them powers that they must be trusted or known not to use: 1) {onlyGovernance} functions like {relay} are + * available to them through the timelock, and 2) approved governance proposals can be blocked by them, effectively + * executing a Denial of Service attack. This risk will be mitigated in a future release. + * + * _Available since v4.3._ + */ +abstract contract GovernorTimelockControl is IGovernorTimelock, Governor { + TimelockController private _timelock; + mapping(uint256 => bytes32) private _timelockIds; + + /** + * @dev Emitted when the timelock controller used for proposal execution is modified. + */ + event TimelockChange(address oldTimelock, address newTimelock); + + /** + * @dev Set the timelock. + */ + constructor(TimelockController timelockAddress) { + _updateTimelock(timelockAddress); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, Governor) returns (bool) { + return interfaceId == type(IGovernorTimelock).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Overridden version of the {Governor-state} function with added support for the `Queued` status. + */ + function state(uint256 proposalId) public view virtual override(IGovernor, Governor) returns (ProposalState) { + ProposalState status = super.state(proposalId); + + if (status != ProposalState.Succeeded) { + return status; + } + + // 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; + } else if (_timelock.isOperationDone(queueid)) { + return ProposalState.Executed; + } else if (_timelock.isOperationPending(queueid)) { + return ProposalState.Queued; + } else { + return ProposalState.Canceled; + } + } + + /** + * @dev Public accessor to check the address of the timelock + */ + function timelock() public view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Public accessor to check the eta of a queued proposal + */ + function proposalEta(uint256 proposalId) public view virtual override returns (uint256) { + uint256 eta = _timelock.getTimestamp(_timelockIds[proposalId]); + return eta == 1 ? 0 : eta; // _DONE_TIMESTAMP (1) should be replaced with a 0 value + } + + /** + * @dev Function to queue a proposal to the timelock. + */ + function queue( + 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.Succeeded, "Governor: proposal not successful"); + + uint256 delay = _timelock.getMinDelay(); + _timelockIds[proposalId] = _timelock.hashOperationBatch(targets, values, calldatas, 0, descriptionHash); + _timelock.scheduleBatch(targets, values, calldatas, 0, descriptionHash, delay); + + emit ProposalQueued(proposalId, block.timestamp + delay); + + return proposalId; + } + + /** + * @dev Overridden execute function that run the already queued proposal through the timelock. + */ + function _execute( + uint256 /* proposalId */, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override { + _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash); + } + + /** + * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it as already + * been queued. + */ + // This function can reenter through the external call to the timelock, but we assume the timelock is trusted and + // well behaved (according to TimelockController) and this will not happen. + // slither-disable-next-line reentrancy-no-eth + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + if (_timelockIds[proposalId] != 0) { + _timelock.cancel(_timelockIds[proposalId]); + delete _timelockIds[proposalId]; + } + + return proposalId; + } + + /** + * @dev Address through which the governor executes action. In this case, the timelock. + */ + function _executor() internal view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates + * must be proposed, scheduled, and executed through governance proposals. + * + * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. + */ + function updateTimelock(TimelockController newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(TimelockController newTimelock) private { + emit TimelockChange(address(_timelock), address(newTimelock)); + _timelock = newTimelock; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol new file mode 100644 index 0000000..6443171 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (governance/extensions/GovernorVotes.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; +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._ + */ +abstract contract GovernorVotes is Governor { + IERC5805 public immutable token; + + constructor(IVotes 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"; + } + } + + /** + * Read the voting weight from the token's built in snapshot mechanism (see {Governor-_getVotes}). + */ + function _getVotes( + address account, + uint256 timepoint, + bytes memory /*params*/ + ) internal view virtual override returns (uint256) { + return token.getPastVotes(account, timepoint); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesComp.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesComp.sol new file mode 100644 index 0000000..17250ad --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesComp.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (governance/extensions/GovernorVotesComp.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; +import "../../token/ERC20/extensions/ERC20VotesComp.sol"; + +/** + * @dev Extension of {Governor} for voting weight extraction from a Comp token. + * + * _Available since v4.3._ + */ +abstract contract GovernorVotesComp is Governor { + ERC20VotesComp public immutable token; + + constructor(ERC20VotesComp token_) { + token = token_; + } + + /** + * @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 timepoint, + bytes memory /*params*/ + ) internal view virtual override returns (uint256) { + return token.getPriorVotes(account, timepoint); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol new file mode 100644 index 0000000..19c5b19 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (governance/extensions/GovernorVotesQuorumFraction.sol) + +pragma solidity ^0.8.0; + +import "./GovernorVotes.sol"; +import "../../utils/Checkpoints.sol"; +import "../../utils/math/SafeCast.sol"; + +/** + * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a + * fraction of the total supply. + * + * _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 + + /// @custom:oz-retyped-from Checkpoints.History + Checkpoints.Trace224 private _quorumNumeratorHistory; + + event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator); + + /** + * @dev Initialize quorum as a fraction of the token's total supply. + * + * The fraction is specified as `numerator / denominator`. By default the denominator is 100, so quorum is + * specified as a percent: a numerator of 10 corresponds to quorum being 10% of total supply. The denominator can be + * customized by overriding {quorumDenominator}. + */ + constructor(uint256 quorumNumeratorValue) { + _updateQuorumNumerator(quorumNumeratorValue); + } + + /** + * @dev Returns the current quorum numerator. See {quorumDenominator}. + */ + function quorumNumerator() public view virtual returns (uint256) { + return _quorumNumeratorHistory._checkpoints.length == 0 ? _quorumNumerator : _quorumNumeratorHistory.latest(); + } + + /** + * @dev Returns the quorum numerator at a specific timepoint. See {quorumDenominator}. + */ + 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) { + return _quorumNumerator; + } + + // Optimistic search, check the latest checkpoint + Checkpoints.Checkpoint224 memory latest = _quorumNumeratorHistory._checkpoints[length - 1]; + if (latest._key <= timepoint) { + return latest._value; + } + + // Otherwise, do the binary search + return _quorumNumeratorHistory.upperLookupRecent(timepoint.toUint32()); + } + + /** + * @dev Returns the quorum denominator. Defaults to 100, but may be overridden. + */ + function quorumDenominator() public view virtual returns (uint256) { + return 100; + } + + /** + * @dev Returns the quorum for a timepoint, in terms of number of votes: `supply * numerator / denominator`. + */ + function quorum(uint256 timepoint) public view virtual override returns (uint256) { + return (token.getPastTotalSupply(timepoint) * quorumNumerator(timepoint)) / quorumDenominator(); + } + + /** + * @dev Changes the quorum numerator. + * + * Emits a {QuorumNumeratorUpdated} event. + * + * Requirements: + * + * - Must be called through a governance proposal. + * - New numerator must be smaller or equal to the denominator. + */ + function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance { + _updateQuorumNumerator(newQuorumNumerator); + } + + /** + * @dev Changes the quorum numerator. + * + * Emits a {QuorumNumeratorUpdated} event. + * + * Requirements: + * + * - New numerator must be smaller or equal to the denominator. + */ + function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual { + require( + newQuorumNumerator <= quorumDenominator(), + "GovernorVotesQuorumFraction: quorumNumerator over quorumDenominator" + ); + + uint256 oldQuorumNumerator = quorumNumerator(); + + // 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()}) + ); + } + + // Set new quorum for future proposals + _quorumNumeratorHistory.push(clock().toUint32(), newQuorumNumerator.toUint224()); + + emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/IGovernorTimelock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/IGovernorTimelock.sol new file mode 100644 index 0000000..40402f6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/extensions/IGovernorTimelock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (governance/extensions/IGovernorTimelock.sol) + +pragma solidity ^0.8.0; + +import "../IGovernor.sol"; + +/** + * @dev Extension of the {IGovernor} for timelock supporting modules. + * + * _Available since v4.3._ + */ +abstract contract IGovernorTimelock is IGovernor { + event ProposalQueued(uint256 proposalId, uint256 eta); + + function timelock() public view virtual returns (address); + + function proposalEta(uint256 proposalId) public view virtual returns (uint256); + + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256 proposalId); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol new file mode 100644 index 0000000..c73d073 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol) +pragma solidity ^0.8.0; + +/** + * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. + * + * _Available since v4.5._ + */ +interface IVotes { + /** + * @dev Emitted when an account changes their delegate. + */ + event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); + + /** + * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes. + */ + event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance); + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) external view returns (uint256); + + /** + * @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 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. + * + * 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 timepoint) external view returns (uint256); + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) external view returns (address); + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) external; + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol new file mode 100644 index 0000000..f70cf38 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: MIT +// 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"; + +/** + * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be + * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of + * "representative" that will pool delegated voting units from different accounts and can then use it to vote in + * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to + * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative. + * + * This contract is often combined with a token contract such that voting units correspond to token units. For an + * example, see {ERC721Votes}. + * + * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed + * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the + * cost of this history tracking optional. + * + * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return + * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the + * previous example, it would be included in {ERC721-_beforeTokenTransfer}). + * + * _Available since v4.5._ + */ +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; + + /// @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. + */ + function getVotes(address account) public view virtual override returns (uint256) { + return _delegateCheckpoints[account].latest(); + } + + /** + * @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: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + 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 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. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastTotalSupply(uint256 timepoint) public view virtual override returns (uint256) { + require(timepoint < clock(), "Votes: future lookup"); + return _totalCheckpoints.upperLookupRecent(SafeCast.toUint32(timepoint)); + } + + /** + * @dev Returns the current total supply of votes. + */ + function _getTotalSupply() internal view virtual returns (uint256) { + return _totalCheckpoints.latest(); + } + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) public view virtual override returns (address) { + return _delegation[account]; + } + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) public virtual override { + address account = _msgSender(); + _delegate(account, 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, "Votes: signature expired"); + address signer = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))), + v, + r, + s + ); + require(nonce == _useNonce(signer), "Votes: invalid nonce"); + _delegate(signer, delegatee); + } + + /** + * @dev Delegate all of `account`'s voting units to `delegatee`. + * + * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. + */ + function _delegate(address account, address delegatee) internal virtual { + address oldDelegate = delegates(account); + _delegation[account] = delegatee; + + emit DelegateChanged(account, oldDelegate, delegatee); + _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account)); + } + + /** + * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to` + * should be zero. Total supply of voting units will be adjusted with mints and burns. + */ + function _transferVotingUnits(address from, address to, uint256 amount) internal virtual { + if (from == address(0)) { + _push(_totalCheckpoints, _add, SafeCast.toUint224(amount)); + } + if (to == address(0)) { + _push(_totalCheckpoints, _subtract, SafeCast.toUint224(amount)); + } + _moveDelegateVotes(delegates(from), delegates(to), amount); + } + + /** + * @dev Moves delegated votes from one delegate to another. + */ + function _moveDelegateVotes(address from, address to, uint256 amount) private { + if (from != to && amount > 0) { + if (from != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[from], + _subtract, + SafeCast.toUint224(amount) + ); + emit DelegateVotesChanged(from, oldValue, newValue); + } + if (to != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[to], + _add, + SafeCast.toUint224(amount) + ); + emit DelegateVotesChanged(to, oldValue, newValue); + } + } + } + + 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(uint224 a, uint224 b) private pure returns (uint224) { + return a - b; + } + + /** + * @dev Consumes a nonce. + * + * Returns the current value and increments nonce. + */ + function _useNonce(address owner) internal virtual returns (uint256 current) { + Counters.Counter storage nonce = _nonces[owner]; + current = nonce.current(); + nonce.increment(); + } + + /** + * @dev Returns an address nonce. + */ + function nonces(address owner) public view virtual returns (uint256) { + return _nonces[owner].current(); + } + + /** + * @dev Returns the contract's {EIP712} domain separator. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view returns (bytes32) { + return _domainSeparatorV4(); + } + + /** + * @dev Must return the voting units held by an account. + */ + function _getVotingUnits(address) internal view virtual returns (uint256); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol new file mode 100644 index 0000000..f891132 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC1155/IERC1155.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol new file mode 100644 index 0000000..2aa885f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155MetadataURI.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC1155/extensions/IERC1155MetadataURI.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol new file mode 100644 index 0000000..a6d4ead --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155Receiver.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC1155/IERC1155Receiver.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol new file mode 100644 index 0000000..5ec44c7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC1271 standard signature validation method for + * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. + * + * _Available since v4.1._ + */ +interface IERC1271 { + /** + * @dev Should return whether the signature provided is valid for the provided data + * @param hash Hash of the data to be signed + * @param signature Signature byte array associated with _data + */ + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol new file mode 100644 index 0000000..1a8dc79 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1363.sol) + +pragma solidity ^0.8.0; + +import "./IERC20.sol"; +import "./IERC165.sol"; + +interface IERC1363 is IERC165, IERC20 { + /* + * Note: the ERC-165 identifier for this interface is 0x4bbee2df. + * 0x4bbee2df === + * 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('approveAndCall(address,uint256)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) + */ + + /** + * @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 + * @return true unless throwing + */ + function transferAndCall(address to, uint256 value) 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 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); + + /** + * @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 + * @return true unless throwing + */ + function transferFromAndCall(address from, address to, uint256 value) 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 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); + + /** + * @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 + */ + function approveAndCall(address spender, uint256 value) 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 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); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol new file mode 100644 index 0000000..bc5eadd --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1363Receiver.sol) + +pragma solidity ^0.8.0; + +interface IERC1363Receiver { + /* + * Note: the ERC-165 identifier for this interface is 0x88a7ca5c. + * 0x88a7ca5c === bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)")) + */ + + /** + * @notice Handle the receipt of ERC1363 tokens + * @dev Any ERC1363 smart contract calls this function on the recipient + * after a `transfer` or a `transferFrom`. This function MAY throw to revert and reject the + * transfer. Return of other than the magic value MUST result in the + * transaction being reverted. + * 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 data bytes Additional data with no specified format + * @return `bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)"))` + * unless throwing + */ + function onTransferReceived( + address operator, + address from, + uint256 value, + bytes memory data + ) external returns (bytes4); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol new file mode 100644 index 0000000..28775e1 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1363Spender.sol) + +pragma solidity ^0.8.0; + +interface IERC1363Spender { + /* + * Note: the ERC-165 identifier for this interface is 0x7b04a2d0. + * 0x7b04a2d0 === bytes4(keccak256("onApprovalReceived(address,uint256,bytes)")) + */ + + /** + * @notice Handle the approval of ERC1363 tokens + * @dev Any ERC1363 smart contract calls this function on the recipient + * after an `approve`. This function MAY throw to revert and reject the + * approval. Return of other than the magic value MUST result in the + * 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 data bytes Additional data with no specified format + * @return `bytes4(keccak256("onApprovalReceived(address,uint256,bytes)"))` + * unless throwing + */ + function onApprovalReceived(address owner, uint256 value, bytes memory data) external returns (bytes4); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol new file mode 100644 index 0000000..b97c4da --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC165.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol new file mode 100644 index 0000000..a83a7a3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1820Implementer.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC1820Implementer.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol new file mode 100644 index 0000000..1b1ba9f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1820Registry.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC1820Registry.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol new file mode 100644 index 0000000..a819316 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/IERC20.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol new file mode 100644 index 0000000..aa5c639 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol new file mode 100644 index 0000000..b3fec44 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC2309.sol) + +pragma solidity ^0.8.0; + +/** + * @dev ERC-2309: ERC-721 Consecutive Transfer Extension. + * + * _Available since v4.8._ + */ +interface IERC2309 { + /** + * @dev Emitted when the tokens from `fromTokenId` to `toTokenId` are transferred from `fromAddress` to `toAddress`. + */ + event ConsecutiveTransfer( + uint256 indexed fromTokenId, + uint256 toTokenId, + address indexed fromAddress, + address indexed toAddress + ); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol new file mode 100644 index 0000000..6dfdf6f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC2612.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/extensions/IERC20Permit.sol"; + +interface IERC2612 is IERC20Permit {} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol new file mode 100644 index 0000000..1c9448a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC165.sol"; + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol new file mode 100644 index 0000000..1238190 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156.sol) + +pragma solidity ^0.8.0; + +import "./IERC3156FlashBorrower.sol"; +import "./IERC3156FlashLender.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol new file mode 100644 index 0000000..c3b4f1e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC3156FlashBorrower.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC3156 FlashBorrower, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + * + * _Available since v4.1._ + */ +interface IERC3156FlashBorrower { + /** + * @dev Receive a flash loan. + * @param initiator The initiator of the loan. + * @param token The loan currency. + * @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" + */ + function onFlashLoan( + address initiator, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) external returns (bytes32); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol new file mode 100644 index 0000000..3101283 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashLender.sol) + +pragma solidity ^0.8.0; + +import "./IERC3156FlashBorrower.sol"; + +/** + * @dev Interface of the ERC3156 FlashLender, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + * + * _Available since v4.1._ + */ +interface IERC3156FlashLender { + /** + * @dev The amount of currency available to be lended. + * @param token The loan currency. + * @return The amount of `token` that can be borrowed. + */ + function maxFlashLoan(address token) external view returns (uint256); + + /** + * @dev The fee to be charged for a given loan. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @return The amount of `token` to be charged for the loan, on top of the returned principal. + */ + function flashFee(address token, uint256 amount) external view returns (uint256); + + /** + * @dev Initiate a flash loan. + * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @param data Arbitrary data structure, intended to contain user-defined parameters. + */ + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 amount, + bytes calldata data + ) external returns (bool); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol new file mode 100644 index 0000000..08e5de7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC4626.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/IERC20.sol"; +import "../token/ERC20/extensions/IERC20Metadata.sol"; + +/** + * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in + * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. + * + * _Available since v4.7._ + */ +interface IERC4626 is IERC20, IERC20Metadata { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, + address indexed receiver, + address indexed owner, + uint256 assets, + uint256 shares + ); + + /** + * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + * + * - MUST be an ERC-20 token contract. + * - MUST NOT revert. + */ + function asset() external view returns (address assetTokenAddress); + + /** + * @dev Returns the total amount of the underlying asset that is “managed” by Vault. + * + * - SHOULD include any compounding that occurs from yield. + * - MUST be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT revert. + */ + function totalAssets() external view returns (uint256 totalManagedAssets); + + /** + * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + * scenario where all the conditions are met. + * + * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + * - MUST NOT revert. + * + * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + * from. + */ + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + * scenario where all the conditions are met. + * + * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + * - MUST NOT revert. + * + * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + * from. + */ + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + * through a deposit call. + * + * - MUST return a limited value if receiver is subject to some deposit limit. + * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + * - MUST NOT revert. + */ + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + * current on-chain conditions. + * + * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + * in the same transaction. + * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + * deposit would be accepted, regardless if the user has enough tokens approved, etc. + * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by depositing. + */ + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + * + * - MUST emit the Deposit event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * deposit execution, and are accounted for during deposit. + * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + * approving enough underlying tokens to the Vault contract, etc). + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + */ + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /** + * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + * - MUST return a limited value if receiver is subject to some mint limit. + * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + * - MUST NOT revert. + */ + function maxMint(address receiver) external view returns (uint256 maxShares); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + * current on-chain conditions. + * + * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + * same transaction. + * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + * would be accepted, regardless if the user has enough tokens approved, etc. + * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by minting. + */ + function previewMint(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + * + * - MUST emit the Deposit event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + * execution, and are accounted for during mint. + * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + * approving enough underlying tokens to the Vault contract, etc). + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + */ + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /** + * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + * Vault, through a withdraw call. + * + * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + * - MUST NOT revert. + */ + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + * given current on-chain conditions. + * + * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + * called + * in the same transaction. + * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + * the withdrawal would be accepted, regardless if the user has enough shares, etc. + * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by depositing. + */ + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. + * + * - MUST emit the Withdraw event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * withdraw execution, and are accounted for during withdraw. + * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + * not having enough shares, etc). + * + * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + * Those methods should be performed separately. + */ + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /** + * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + * through a redeem call. + * + * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + * - MUST NOT revert. + */ + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + * given current on-chain conditions. + * + * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + * same transaction. + * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + * redemption would be accepted, regardless if the user has enough shares, etc. + * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by redeeming. + */ + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. + * + * - MUST emit the Withdraw event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * redeem execution, and are accounted for during redeem. + * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + * not having enough shares, etc). + * + * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + * Those methods should be performed separately. + */ + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol new file mode 100644 index 0000000..c9eaa12 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol new file mode 100644 index 0000000..3adc4a7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol new file mode 100644 index 0000000..2c9a47d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol new file mode 100644 index 0000000..2c2e5e3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol new file mode 100644 index 0000000..e1a0bf8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol new file mode 100644 index 0000000..822b311 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/IERC721.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol new file mode 100644 index 0000000..e39a5a0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Enumerable.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/extensions/IERC721Enumerable.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol new file mode 100644 index 0000000..afe2707 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol new file mode 100644 index 0000000..c9c153a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Receiver.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/IERC721Receiver.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol new file mode 100644 index 0000000..b97ba7b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC777/IERC777.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol new file mode 100644 index 0000000..0ce2704 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777Recipient.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC777/IERC777Recipient.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol new file mode 100644 index 0000000..f1f17a2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777Sender.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC777/IERC777Sender.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/README.adoc new file mode 100644 index 0000000..5b4cedf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/README.adoc @@ -0,0 +1,56 @@ += Interfaces + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/interfaces + +== List of standardized interfaces +These interfaces are available as `.sol` files, and also as compiler `.json` ABI files (through the npm package). These +are useful to interact with third party contracts that implement them. + +- {IERC20} +- {IERC20Metadata} +- {IERC165} +- {IERC721} +- {IERC721Receiver} +- {IERC721Enumerable} +- {IERC721Metadata} +- {IERC777} +- {IERC777Recipient} +- {IERC777Sender} +- {IERC1155} +- {IERC1155Receiver} +- {IERC1155MetadataURI} +- {IERC1271} +- {IERC1363} +- {IERC1820Implementer} +- {IERC1820Registry} +- {IERC1822Proxiable} +- {IERC2612} +- {IERC2981} +- {IERC3156FlashLender} +- {IERC3156FlashBorrower} +- {IERC4626} + +== Detailed ABI + +{{IERC1271}} + +{{IERC1363}} + +{{IERC1363Receiver}} + +{{IERC1820Implementer}} + +{{IERC1820Registry}} + +{{IERC1822Proxiable}} + +{{IERC2612}} + +{{IERC2981}} + +{{IERC3156FlashLender}} + +{{IERC3156FlashBorrower}} + +{{IERC4626}} \ No newline at end of file diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol new file mode 100644 index 0000000..3b73d74 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) + +pragma solidity ^0.8.0; + +/** + * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified + * proxy whose upgrades are fully controlled by the current implementation. + */ +interface IERC1822Proxiable { + /** + * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation + * address. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. + */ + function proxiableUUID() external view returns (bytes32); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC2612.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC2612.sol new file mode 100644 index 0000000..1ea7bf1 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC2612.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +// EIP-2612 is Final as of 2022-11-01. This file is deprecated. + +import "./IERC2612.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol new file mode 100644 index 0000000..8cc14b9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol) + +pragma solidity ^0.8.9; + +import "../utils/Context.sol"; + +/** + * @dev Context variant with ERC2771 support. + */ +abstract contract ERC2771Context is Context { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _trustedForwarder; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address trustedForwarder) { + _trustedForwarder = trustedForwarder; + } + + function isTrustedForwarder(address forwarder) public view virtual returns (bool) { + return forwarder == _trustedForwarder; + } + + function _msgSender() internal view virtual override returns (address sender) { + if (isTrustedForwarder(msg.sender)) { + // The assembly code is more direct than the Solidity version using `abi.decode`. + /// @solidity memory-safe-assembly + assembly { + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + } else { + return super._msgSender(); + } + } + + function _msgData() internal view virtual override returns (bytes calldata) { + if (isTrustedForwarder(msg.sender)) { + return msg.data[:msg.data.length - 20]; + } else { + return super._msgData(); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/MinimalForwarder.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/MinimalForwarder.sol new file mode 100644 index 0000000..9298ae6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/MinimalForwarder.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (metatx/MinimalForwarder.sol) + +pragma solidity ^0.8.0; + +import "../utils/cryptography/ECDSA.sol"; +import "../utils/cryptography/EIP712.sol"; + +/** + * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}. + * + * MinimalForwarder is mainly meant for testing, as it is missing features to be a good production-ready forwarder. This + * contract does not intend to have all the properties that are needed for a sound forwarding system. A fully + * functioning forwarding system with good properties requires more complexity. We suggest you look at other projects + * such as the GSN which do have the goal of building a system like that. + */ +contract MinimalForwarder is EIP712 { + using ECDSA for bytes32; + + struct ForwardRequest { + address from; + address to; + uint256 value; + uint256 gas; + uint256 nonce; + bytes data; + } + + bytes32 private constant _TYPEHASH = + keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)"); + + mapping(address => uint256) private _nonces; + + constructor() EIP712("MinimalForwarder", "0.0.1") {} + + function getNonce(address from) public view returns (uint256) { + return _nonces[from]; + } + + function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) { + address signer = _hashTypedDataV4( + keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data))) + ).recover(signature); + return _nonces[req.from] == req.nonce && signer == req.from; + } + + function execute( + ForwardRequest calldata req, + bytes calldata signature + ) public payable returns (bool, bytes memory) { + require(verify(req, signature), "MinimalForwarder: signature does not match request"); + _nonces[req.from] = req.nonce + 1; + + (bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}( + abi.encodePacked(req.data, req.from) + ); + + // Validate that the relayer has sent enough gas for the call. + // See https://ronan.eth.limo/blog/ethereum-gas-dangers/ + if (gasleft() <= req.gas / 63) { + // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since + // neither revert or assert consume all gas since Solidity 0.8.0 + // https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require + /// @solidity memory-safe-assembly + assembly { + invalid() + } + } + + return (success, returndata); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/README.adoc new file mode 100644 index 0000000..eccdeaf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/metatx/README.adoc @@ -0,0 +1,12 @@ += Meta Transactions + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx + +== Core + +{{ERC2771Context}} + +== Utils + +{{MinimalForwarder}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/AccessControlCrossChainMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/AccessControlCrossChainMock.sol new file mode 100644 index 0000000..cd4c3a5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/AccessControlCrossChainMock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +import "../access/AccessControlCrossChain.sol"; +import "../crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol"; + +contract AccessControlCrossChainMock is AccessControlCrossChain, CrossChainEnabledArbitrumL2 {} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol new file mode 100644 index 0000000..2ea17a0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Arrays.sol"; + +contract Uint256ArraysMock { + using Arrays for uint256[]; + + uint256[] private _array; + + constructor(uint256[] memory array) { + _array = array; + } + + function findUpperBound(uint256 element) external view returns (uint256) { + return _array.findUpperBound(element); + } + + function unsafeAccess(uint256 pos) external view returns (uint256) { + return _array.unsafeAccess(pos).value; + } +} + +contract AddressArraysMock { + using Arrays for address[]; + + address[] private _array; + + constructor(address[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (address) { + return _array.unsafeAccess(pos).value; + } +} + +contract Bytes32ArraysMock { + using Arrays for bytes32[]; + + bytes32[] private _array; + + constructor(bytes32[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (bytes32) { + return _array.unsafeAccess(pos).value; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol new file mode 100644 index 0000000..344a105 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract CallReceiverMock { + event MockFunctionCalled(); + event MockFunctionCalledWithArgs(uint256 a, uint256 b); + + uint256[] private _array; + + function mockFunction() public payable returns (string memory) { + emit MockFunctionCalled(); + + return "0x1234"; + } + + function mockFunctionWithArgs(uint256 a, uint256 b) public payable returns (string memory) { + emit MockFunctionCalledWithArgs(a, b); + + return "0x1234"; + } + + function mockFunctionNonPayable() public returns (string memory) { + emit MockFunctionCalled(); + + return "0x1234"; + } + + function mockStaticFunction() public pure returns (string memory) { + return "0x1234"; + } + + function mockFunctionRevertsNoReason() public payable { + revert(); + } + + function mockFunctionRevertsReason() public payable { + revert("CallReceiverMock: reverting"); + } + + function mockFunctionThrows() public payable { + assert(false); + } + + function mockFunctionOutOfGas() public payable { + for (uint256 i = 0; ; ++i) { + _array.push(i); + } + } + + function mockFunctionWritesStorage(bytes32 slot, bytes32 value) public returns (string memory) { + assembly { + sstore(slot, value) + } + return "0x1234"; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ConditionalEscrowMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ConditionalEscrowMock.sol new file mode 100644 index 0000000..ececf05 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ConditionalEscrowMock.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/escrow/ConditionalEscrow.sol"; + +// mock class using ConditionalEscrow +contract ConditionalEscrowMock is ConditionalEscrow { + mapping(address => bool) private _allowed; + + function setAllowed(address payee, bool allowed) public { + _allowed[payee] = allowed; + } + + function withdrawalAllowed(address payee) public view override returns (bool) { + return _allowed[payee]; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol new file mode 100644 index 0000000..7759f35 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +contract ContextMock is Context { + event Sender(address sender); + + function msgSender() public { + emit Sender(_msgSender()); + } + + event Data(bytes data, uint256 integerValue, string stringValue); + + function msgData(uint256 integerValue, string memory stringValue) public { + emit Data(_msgData(), integerValue, stringValue); + } +} + +contract ContextMockCaller { + function callSender(ContextMock context) public { + context.msgSender(); + } + + function callData(ContextMock context, uint256 integerValue, string memory stringValue) public { + context.msgData(integerValue, stringValue); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol new file mode 100644 index 0000000..ddcca66 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +abstract contract Impl { + function version() public pure virtual returns (string memory); +} + +contract DummyImplementation { + uint256 public value; + string public text; + uint256[] public values; + + function initializeNonPayable() public { + value = 10; + } + + function initializePayable() public payable { + value = 100; + } + + function initializeNonPayableWithValue(uint256 _value) public { + value = _value; + } + + function initializePayableWithValue(uint256 _value) public payable { + value = _value; + } + + function initialize(uint256 _value, string memory _text, uint256[] memory _values) public { + value = _value; + text = _text; + values = _values; + } + + function get() public pure returns (bool) { + return true; + } + + function version() public pure virtual returns (string memory) { + return "V1"; + } + + function reverts() public pure { + require(false, "DummyImplementation reverted"); + } +} + +contract DummyImplementationV2 is DummyImplementation { + function migrate(uint256 newVal) public payable { + value = newVal; + } + + function version() public pure override returns (string memory) { + return "V2"; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol new file mode 100644 index 0000000..dcef9ef --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/cryptography/ECDSA.sol"; +import "../utils/cryptography/EIP712.sol"; + +abstract contract EIP712Verifier is EIP712 { + function verify(bytes memory signature, address signer, address mailTo, string memory mailContents) external view { + bytes32 digest = _hashTypedDataV4( + keccak256(abi.encode(keccak256("Mail(address to,string contents)"), mailTo, keccak256(bytes(mailContents)))) + ); + address recoveredSigner = ECDSA.recover(digest, signature); + require(recoveredSigner == signer); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol new file mode 100644 index 0000000..0152889 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../access/Ownable.sol"; +import "../interfaces/IERC1271.sol"; +import "../utils/cryptography/ECDSA.sol"; + +contract ERC1271WalletMock is Ownable, IERC1271 { + constructor(address originalOwner) { + transferOwnership(originalOwner); + } + + function isValidSignature(bytes32 hash, bytes memory signature) public view override returns (bytes4 magicValue) { + return ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0); + } +} + +contract ERC1271MaliciousMock is IERC1271 { + function isValidSignature(bytes32, bytes memory) public pure override returns (bytes4) { + assembly { + mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0, 32) + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol new file mode 100644 index 0000000..2446f3d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC165MaliciousData { + function supportsInterface(bytes4) public pure returns (bool) { + assembly { + mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0, 32) + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol new file mode 100644 index 0000000..59cd51a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC165MissingData { + function supportsInterface(bytes4 interfaceId) public view {} // missing return +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol new file mode 100644 index 0000000..486c7f0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC165NotSupported {} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol new file mode 100644 index 0000000..e53235d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +contract ERC165ReturnBombMock is IERC165 { + function supportsInterface(bytes4 interfaceId) public pure override returns (bool) { + if (interfaceId == type(IERC165).interfaceId) { + assembly { + mstore(0, 1) + } + } + assembly { + return(0, 101500) + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC20Mock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC20Mock.sol new file mode 100644 index 0000000..cc75923 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC20Mock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ERC20} from "../token/ERC20/ERC20.sol"; + +contract ERC20Mock is ERC20 { + constructor() ERC20("ERC20Mock", "E20M") {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol new file mode 100644 index 0000000..387df78 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.9; + +import "./ContextMock.sol"; +import "../metatx/ERC2771Context.sol"; + +// By inheriting from ERC2771Context, Context's internal functions are overridden automatically +contract ERC2771ContextMock is ContextMock, ERC2771Context { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address trustedForwarder) ERC2771Context(trustedForwarder) { + emit Sender(_msgSender()); // _msgSender() should be accessible during construction + } + + function _msgSender() internal view override(Context, ERC2771Context) returns (address) { + return ERC2771Context._msgSender(); + } + + function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) { + return ERC2771Context._msgData(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol new file mode 100644 index 0000000..6a4410f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../token/ERC20/IERC20.sol"; +import "../interfaces/IERC3156.sol"; +import "../utils/Address.sol"; + +/** + * @dev WARNING: this IERC3156FlashBorrower mock implementation is for testing purposes ONLY. + * Writing a secure flash lock borrower is not an easy task, and should be done with the utmost care. + * This is not an example of how it should be done, and no pattern present in this mock should be considered secure. + * Following best practices, always have your contract properly audited before using them to manipulate important funds on + * live networks. + */ +contract ERC3156FlashBorrowerMock is IERC3156FlashBorrower { + bytes32 internal constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + bool immutable _enableApprove; + bool immutable _enableReturn; + + event BalanceOf(address token, address account, uint256 value); + event TotalSupply(address token, uint256 value); + + constructor(bool enableReturn, bool enableApprove) { + _enableApprove = enableApprove; + _enableReturn = enableReturn; + } + + function onFlashLoan( + address /*initiator*/, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) public override returns (bytes32) { + require(msg.sender == token); + + emit BalanceOf(token, address(this), IERC20(token).balanceOf(address(this))); + emit TotalSupply(token, IERC20(token).totalSupply()); + + if (data.length > 0) { + // WARNING: This code is for testing purposes only! Do not use. + Address.functionCall(token, data); + } + + if (_enableApprove) { + IERC20(token).approve(token, amount + fee); + } + + return _enableReturn ? _RETURN_VALUE : bytes32(0); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC4626Mock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC4626Mock.sol new file mode 100644 index 0000000..ef2d1a4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ERC4626Mock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../token/ERC20/extensions/ERC4626.sol"; + +contract ERC4626Mock is ERC4626 { + constructor(address underlying) ERC20("ERC4626Mock", "E4626M") ERC4626(IERC20(underlying)) {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol new file mode 100644 index 0000000..a11e646 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract EtherReceiverMock { + bool private _acceptEther; + + function setAcceptEther(bool acceptEther) public { + _acceptEther = acceptEther; + } + + receive() external payable { + if (!_acceptEther) { + revert(); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol new file mode 100644 index 0000000..34040b6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../proxy/utils/Initializable.sol"; + +/** + * @title InitializableMock + * @dev This contract is a mock to test initializable functionality + */ +contract InitializableMock is Initializable { + bool public initializerRan; + bool public onlyInitializingRan; + uint256 public x; + + function isInitializing() public view returns (bool) { + return _isInitializing(); + } + + function initialize() public initializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyInitializing { + onlyInitializingRan = true; + } + + function initializerNested() public initializer { + initialize(); + } + + function onlyInitializingNested() public initializer { + initializeOnlyInitializing(); + } + + function initializeWithX(uint256 _x) public payable initializer { + x = _x; + } + + function nonInitializable(uint256 _x) public payable { + x = _x; + } + + function fail() public pure { + require(false, "InitializableMock forced failure"); + } +} + +contract ConstructorInitializableMock is Initializable { + bool public initializerRan; + bool public onlyInitializingRan; + + constructor() initializer { + initialize(); + initializeOnlyInitializing(); + } + + function initialize() public initializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyInitializing { + onlyInitializingRan = true; + } +} + +contract ChildConstructorInitializableMock is ConstructorInitializableMock { + bool public childInitializerRan; + + constructor() initializer { + childInitialize(); + } + + function childInitialize() public initializer { + childInitializerRan = true; + } +} + +contract ReinitializerMock is Initializable { + uint256 public counter; + + function getInitializedVersion() public view returns (uint8) { + return _getInitializedVersion(); + } + + function initialize() public initializer { + doStuff(); + } + + function reinitialize(uint8 i) public reinitializer(i) { + doStuff(); + } + + function nestedReinitialize(uint8 i, uint8 j) public reinitializer(i) { + reinitialize(j); + } + + function chainReinitialize(uint8 i, uint8 j) public { + reinitialize(i); + reinitialize(j); + } + + function disableInitializers() public { + _disableInitializers(); + } + + function doStuff() public onlyInitializing { + counter++; + } +} + +contract DisableNew is Initializable { + constructor() { + _disableInitializers(); + } +} + +contract DisableOld is Initializable { + constructor() initializer {} +} + +contract DisableBad1 is DisableNew, DisableOld {} + +contract DisableBad2 is Initializable { + constructor() initializer { + _disableInitializers(); + } +} + +contract DisableOk is DisableOld, DisableNew {} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/MulticallTest.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/MulticallTest.sol new file mode 100644 index 0000000..fcbec6a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/MulticallTest.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./token/ERC20MulticallMock.sol"; + +contract MulticallTest { + function checkReturnValues( + ERC20MulticallMock multicallToken, + address[] calldata recipients, + uint256[] calldata amounts + ) external { + bytes[] memory calls = new bytes[](recipients.length); + for (uint256 i = 0; i < recipients.length; i++) { + calls[i] = abi.encodeWithSignature("transfer(address,uint256)", recipients[i], amounts[i]); + } + + bytes[] memory results = multicallToken.multicall(calls); + for (uint256 i = 0; i < results.length; i++) { + require(abi.decode(results[i], (bool))); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..e79cd92 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../proxy/utils/Initializable.sol"; + +// Sample contracts showing upgradeability with multiple inheritance. +// Child contract inherits from Father and Mother contracts, and Father extends from Gramps. +// +// Human +// / \ +// | Gramps +// | | +// Mother Father +// | | +// -- Child -- + +/** + * Sample base initializable contract that is a human + */ +contract SampleHuman is Initializable { + bool public isHuman; + + function initialize() public initializer { + __SampleHuman_init(); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleHuman_init() internal onlyInitializing { + __SampleHuman_init_unchained(); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleHuman_init_unchained() internal onlyInitializing { + isHuman = true; + } +} + +/** + * Sample base initializable contract that defines a field mother + */ +contract SampleMother is Initializable, SampleHuman { + uint256 public mother; + + function initialize(uint256 value) public initializer { + __SampleMother_init(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleMother_init(uint256 value) internal onlyInitializing { + __SampleHuman_init(); + __SampleMother_init_unchained(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleMother_init_unchained(uint256 value) internal onlyInitializing { + mother = value; + } +} + +/** + * Sample base initializable contract that defines a field gramps + */ +contract SampleGramps is Initializable, SampleHuman { + string public gramps; + + function initialize(string memory value) public initializer { + __SampleGramps_init(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleGramps_init(string memory value) internal onlyInitializing { + __SampleHuman_init(); + __SampleGramps_init_unchained(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleGramps_init_unchained(string memory value) internal onlyInitializing { + gramps = value; + } +} + +/** + * Sample base initializable contract that defines a field father and extends from gramps + */ +contract SampleFather is Initializable, SampleGramps { + uint256 public father; + + function initialize(string memory _gramps, uint256 _father) public initializer { + __SampleFather_init(_gramps, _father); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleFather_init(string memory _gramps, uint256 _father) internal onlyInitializing { + __SampleGramps_init(_gramps); + __SampleFather_init_unchained(_father); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleFather_init_unchained(uint256 _father) internal onlyInitializing { + father = _father; + } +} + +/** + * Child extends from mother, father (gramps) + */ +contract SampleChild is Initializable, SampleMother, SampleFather { + uint256 public child; + + function initialize(uint256 _mother, string memory _gramps, uint256 _father, uint256 _child) public initializer { + __SampleChild_init(_mother, _gramps, _father, _child); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleChild_init( + uint256 _mother, + string memory _gramps, + uint256 _father, + uint256 _child + ) internal onlyInitializing { + __SampleMother_init(_mother); + __SampleFather_init(_gramps, _father); + __SampleChild_init_unchained(_child); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleChild_init_unchained(uint256 _child) internal onlyInitializing { + child = _child; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol new file mode 100644 index 0000000..98bcfd5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../security/Pausable.sol"; + +contract PausableMock is Pausable { + bool public drasticMeasureTaken; + uint256 public count; + + constructor() { + drasticMeasureTaken = false; + count = 0; + } + + function normalProcess() external whenNotPaused { + count++; + } + + function drasticMeasure() external whenPaused { + drasticMeasureTaken = true; + } + + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/PullPaymentMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/PullPaymentMock.sol new file mode 100644 index 0000000..8a708e3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/PullPaymentMock.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../security/PullPayment.sol"; + +// mock class using PullPayment +contract PullPaymentMock is PullPayment { + constructor() payable {} + + // test helper function to call asyncTransfer + function callTransfer(address dest, uint256 amount) public { + _asyncTransfer(dest, amount); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol new file mode 100644 index 0000000..4de1812 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +contract ReentrancyAttack is Context { + function callSender(bytes4 data) public { + (bool success, ) = _msgSender().call(abi.encodeWithSelector(data)); + require(success, "ReentrancyAttack: failed call"); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol new file mode 100644 index 0000000..161e1d3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../security/ReentrancyGuard.sol"; +import "./ReentrancyAttack.sol"; + +contract ReentrancyMock is ReentrancyGuard { + uint256 public counter; + + constructor() { + counter = 0; + } + + function callback() external nonReentrant { + _count(); + } + + function countLocalRecursive(uint256 n) public nonReentrant { + if (n > 0) { + _count(); + countLocalRecursive(n - 1); + } + } + + function countThisRecursive(uint256 n) public nonReentrant { + if (n > 0) { + _count(); + (bool success, ) = address(this).call(abi.encodeWithSignature("countThisRecursive(uint256)", n - 1)); + require(success, "ReentrancyMock: failed call"); + } + } + + function countAndCall(ReentrancyAttack attacker) public nonReentrant { + _count(); + bytes4 func = bytes4(keccak256("callback()")); + attacker.callSender(func); + } + + function _count() private { + counter += 1; + } + + function guardedCheckEntered() public nonReentrant { + require(_reentrancyGuardEntered()); + } + + function unguardedCheckNotEntered() public view { + require(!_reentrancyGuardEntered()); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol new file mode 100644 index 0000000..be6b501 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../proxy/utils/Initializable.sol"; + +contract Implementation1 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } +} + +contract Implementation2 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } +} + +contract Implementation3 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue(uint256 _number) public view returns (uint256) { + return _value + _number; + } +} + +contract Implementation4 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } + + fallback() external { + _value = 1; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/SafeMathMemoryCheck.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/SafeMathMemoryCheck.sol new file mode 100644 index 0000000..9694688 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/SafeMathMemoryCheck.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/math/SafeMath.sol"; + +library SafeMathMemoryCheck { + function addMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.add(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } + + function subMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.sub(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } + + function mulMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.mul(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } + + function divMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.div(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } + + function modMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.mod(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..6c82dd2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../proxy/utils/Initializable.sol"; + +/** + * @title MigratableMockV1 + * @dev This contract is a mock to test initializable functionality through migrations + */ +contract MigratableMockV1 is Initializable { + uint256 public x; + + function initialize(uint256 value) public payable initializer { + x = value; + } +} + +/** + * @title MigratableMockV2 + * @dev This contract is a mock to test migratable functionality with params + */ +contract MigratableMockV2 is MigratableMockV1 { + bool internal _migratedV2; + uint256 public y; + + function migrate(uint256 value, uint256 anotherValue) public payable { + require(!_migratedV2); + x = value; + y = anotherValue; + _migratedV2 = true; + } +} + +/** + * @title MigratableMockV3 + * @dev This contract is a mock to test migratable functionality without params + */ +contract MigratableMockV3 is MigratableMockV2 { + bool internal _migratedV3; + + function migrate() public payable { + require(!_migratedV3); + uint256 oldX = x; + x = y; + y = oldX; + _migratedV3 = true; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol new file mode 100644 index 0000000..1da577c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/StorageSlot.sol"; + +contract StorageSlotMock { + using StorageSlot for *; + + function setBoolean(bytes32 slot, bool value) public { + slot.getBooleanSlot().value = value; + } + + function setAddress(bytes32 slot, address value) public { + slot.getAddressSlot().value = value; + } + + function setBytes32(bytes32 slot, bytes32 value) public { + slot.getBytes32Slot().value = value; + } + + function setUint256(bytes32 slot, uint256 value) public { + slot.getUint256Slot().value = value; + } + + function getBoolean(bytes32 slot) public view returns (bool) { + return slot.getBooleanSlot().value; + } + + function getAddress(bytes32 slot) public view returns (address) { + return slot.getAddressSlot().value; + } + + function getBytes32(bytes32 slot) public view returns (bytes32) { + return slot.getBytes32Slot().value; + } + + 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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/TimersBlockNumberImpl.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/TimersBlockNumberImpl.sol new file mode 100644 index 0000000..84633e6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/TimersBlockNumberImpl.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Timers.sol"; + +contract TimersBlockNumberImpl { + using Timers for Timers.BlockNumber; + + Timers.BlockNumber private _timer; + + function getDeadline() public view returns (uint64) { + return _timer.getDeadline(); + } + + function setDeadline(uint64 timestamp) public { + _timer.setDeadline(timestamp); + } + + function reset() public { + _timer.reset(); + } + + function isUnset() public view returns (bool) { + return _timer.isUnset(); + } + + function isStarted() public view returns (bool) { + return _timer.isStarted(); + } + + function isPending() public view returns (bool) { + return _timer.isPending(); + } + + function isExpired() public view returns (bool) { + return _timer.isExpired(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/TimersTimestampImpl.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/TimersTimestampImpl.sol new file mode 100644 index 0000000..07f9a1b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/TimersTimestampImpl.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Timers.sol"; + +contract TimersTimestampImpl { + using Timers for Timers.Timestamp; + + Timers.Timestamp private _timer; + + function getDeadline() public view returns (uint64) { + return _timer.getDeadline(); + } + + function setDeadline(uint64 timestamp) public { + _timer.setDeadline(timestamp); + } + + function reset() public { + _timer.reset(); + } + + function isUnset() public view returns (bool) { + return _timer.isUnset(); + } + + function isStarted() public view returns (bool) { + return _timer.isStarted(); + } + + function isPending() public view returns (bool) { + return _timer.isPending(); + } + + function isExpired() public view returns (bool) { + return _timer.isExpired(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol new file mode 100644 index 0000000..829504e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../governance/utils/Votes.sol"; + +abstract contract VotesMock is Votes { + mapping(address => uint256) private _balances; + mapping(uint256 => address) private _owners; + + function getTotalSupply() public view returns (uint256) { + return _getTotalSupply(); + } + + function delegate(address account, address newDelegation) public { + return _delegate(account, newDelegation); + } + + function _getVotingUnits(address account) internal view override returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 voteId) internal { + _balances[account] += 1; + _owners[voteId] = account; + _transferVotingUnits(address(0), account, 1); + } + + function _burn(uint256 voteId) internal { + address owner = _owners[voteId]; + _balances[owner] -= 1; + _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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol new file mode 100644 index 0000000..49ffa4b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: BSD-3-Clause +// solhint-disable private-vars-leading-underscore +/** + * Copyright 2020 Compound Labs, Inc. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +pragma solidity ^0.8.0; + +contract CompTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + + uint256 public constant GRACE_PERIOD = 14 days; + uint256 public constant MINIMUM_DELAY = 2 days; + uint256 public constant MAXIMUM_DELAY = 30 days; + + address public admin; + address public pendingAdmin; + uint256 public delay; + + mapping(bytes32 => bool) public queuedTransactions; + + constructor(address admin_, uint256 delay_) { + require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay."); + require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); + + admin = admin_; + delay = delay_; + } + + receive() external payable {} + + function setDelay(uint256 delay_) public { + require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock."); + require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay."); + require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); + delay = delay_; + + emit NewDelay(delay); + } + + function acceptAdmin() public { + require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin."); + admin = msg.sender; + pendingAdmin = address(0); + + emit NewAdmin(admin); + } + + function setPendingAdmin(address pendingAdmin_) public { + require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock."); + pendingAdmin = pendingAdmin_; + + emit NewPendingAdmin(pendingAdmin); + } + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public returns (bytes32) { + require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin."); + require( + eta >= getBlockTimestamp() + delay, + "Timelock::queueTransaction: Estimated execution block must satisfy delay." + ); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + queuedTransactions[txHash] = true; + + emit QueueTransaction(txHash, target, value, signature, data, eta); + return txHash; + } + + function cancelTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public { + require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin."); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + queuedTransactions[txHash] = false; + + emit CancelTransaction(txHash, target, value, signature, data, eta); + } + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public payable returns (bytes memory) { + require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin."); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued."); + require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock."); + require(getBlockTimestamp() <= eta + GRACE_PERIOD, "Timelock::executeTransaction: Transaction is stale."); + + queuedTransactions[txHash] = false; + + bytes memory callData; + + if (bytes(signature).length == 0) { + callData = data; + } else { + callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data); + } + + // solium-disable-next-line security/no-call-value + (bool success, bytes memory returnData) = target.call{value: value}(callData); + require(success, "Timelock::executeTransaction: Transaction execution reverted."); + + emit ExecuteTransaction(txHash, target, value, signature, data, eta); + + return returnData; + } + + function getBlockTimestamp() internal view returns (uint256) { + // solium-disable-next-line security/no-block-members + return block.timestamp; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/crosschain/bridges.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/crosschain/bridges.sol new file mode 100644 index 0000000..41baffe --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/crosschain/bridges.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/Address.sol"; +import "../../vendor/polygon/IFxMessageProcessor.sol"; + +abstract contract BaseRelayMock { + // needed to parse custom errors + error NotCrossChainCall(); + error InvalidCrossChainSender(address sender, address expected); + + address internal _currentSender; + + function relayAs(address target, bytes calldata data, address sender) external virtual { + address previousSender = _currentSender; + + _currentSender = sender; + + (bool success, bytes memory returndata) = target.call(data); + Address.verifyCallResultFromTarget(target, success, returndata, "low-level call reverted"); + + _currentSender = previousSender; + } +} + +/** + * AMB + */ +contract BridgeAMBMock is BaseRelayMock { + function messageSender() public view returns (address) { + return _currentSender; + } +} + +/** + * Arbitrum + */ +contract BridgeArbitrumL1Mock is BaseRelayMock { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable inbox = address(new BridgeArbitrumL1Inbox()); + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable outbox = address(new BridgeArbitrumL1Outbox()); + + function activeOutbox() public view returns (address) { + return outbox; + } + + function currentSender() public view returns (address) { + return _currentSender; + } +} + +contract BridgeArbitrumL1Inbox { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable bridge = msg.sender; +} + +contract BridgeArbitrumL1Outbox { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable bridge = msg.sender; + + function l2ToL1Sender() public view returns (address) { + return BridgeArbitrumL1Mock(bridge).currentSender(); + } +} + +contract BridgeArbitrumL2Mock is BaseRelayMock { + function wasMyCallersAddressAliased() public view returns (bool) { + return _currentSender != address(0); + } + + function myCallersAddressWithoutAliasing() public view returns (address) { + return _currentSender; + } +} + +/** + * Optimism + */ +contract BridgeOptimismMock is BaseRelayMock { + function xDomainMessageSender() public view returns (address) { + return _currentSender; + } +} + +/** + * Polygon + */ +contract BridgePolygonChildMock is BaseRelayMock { + function relayAs(address target, bytes calldata data, address sender) external override { + IFxMessageProcessor(target).processMessageFromRoot(0, sender, data); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/crosschain/receivers.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/crosschain/receivers.sol new file mode 100644 index 0000000..601a2ac --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/crosschain/receivers.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +import "../../access/Ownable.sol"; +import "../../crosschain/amb/CrossChainEnabledAMB.sol"; +import "../../crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol"; +import "../../crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol"; +import "../../crosschain/optimism/CrossChainEnabledOptimism.sol"; +import "../../crosschain/polygon/CrossChainEnabledPolygonChild.sol"; + +abstract contract Receiver is CrossChainEnabled { + // we don't use Ownable because it messes up testing for the upgradeable contracts + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable owner = msg.sender; + + function crossChainRestricted() external onlyCrossChain {} + + function crossChainOwnerRestricted() external onlyCrossChainSender(owner) {} +} + +/** + * AMB + */ +contract CrossChainEnabledAMBMock is Receiver, CrossChainEnabledAMB { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) CrossChainEnabledAMB(bridge) {} +} + +/** + * Arbitrum + */ +contract CrossChainEnabledArbitrumL1Mock is Receiver, CrossChainEnabledArbitrumL1 { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) CrossChainEnabledArbitrumL1(bridge) {} +} + +contract CrossChainEnabledArbitrumL2Mock is Receiver, CrossChainEnabledArbitrumL2 {} + +/** + * Optimism + */ +contract CrossChainEnabledOptimismMock is Receiver, CrossChainEnabledOptimism { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) CrossChainEnabledOptimism(bridge) {} +} + +/** + * Polygon + */ +contract CrossChainEnabledPolygonChildMock is Receiver, CrossChainEnabledPolygonChild { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) CrossChainEnabledPolygonChild(bridge) {} +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCompMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCompMock.sol new file mode 100644 index 0000000..cc368c4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCompMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotesComp.sol"; + +abstract contract GovernorCompMock is GovernorVotesComp, GovernorCountingSimple { + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol new file mode 100644 index 0000000..1b87d14 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/compatibility/GovernorCompatibilityBravo.sol"; +import "../../governance/extensions/GovernorTimelockCompound.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorVotesComp.sol"; + +abstract contract GovernorCompatibilityBravoMock is + GovernorCompatibilityBravo, + GovernorSettings, + GovernorTimelockCompound, + GovernorVotesComp +{ + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function supportsInterface( + bytes4 interfaceId + ) public view override(IERC165, Governor, GovernorTimelockCompound) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function state( + uint256 proposalId + ) public view override(IGovernor, Governor, GovernorTimelockCompound) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalEta( + uint256 proposalId + ) public view override(IGovernorTimelock, GovernorTimelockCompound) returns (uint256) { + return super.proposalEta(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public override(IGovernor, Governor, GovernorCompatibilityBravo) returns (uint256) { + return super.propose(targets, values, calldatas, description); + } + + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 salt + ) public override(IGovernorTimelock, GovernorTimelockCompound) returns (uint256) { + return super.queue(targets, values, calldatas, salt); + } + + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 salt + ) public payable override(IGovernor, Governor) returns (uint256) { + return super.execute(targets, values, calldatas, salt); + } + + 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( + 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 salt + ) internal override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) { + return super._cancel(targets, values, calldatas, salt); + } + + function _executor() internal view override(Governor, GovernorTimelockCompound) returns (address) { + return super._executor(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol new file mode 100644 index 0000000..8a1db47 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorProposalThreshold.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorMock is + GovernorProposalThreshold, + GovernorSettings, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public override(Governor, GovernorProposalThreshold) returns (uint256) { + return super.propose(targets, values, calldatas, description); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol new file mode 100644 index 0000000..79d8948 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorPreventLateQuorum.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorPreventLateQuorumMock is + GovernorSettings, + GovernorVotes, + GovernorCountingSimple, + GovernorPreventLateQuorum +{ + uint256 private _quorum; + + constructor(uint256 quorum_) { + _quorum = quorum_; + } + + function quorum(uint256) public view override returns (uint256) { + return _quorum; + } + + function proposalDeadline( + uint256 proposalId + ) public view override(Governor, GovernorPreventLateQuorum) returns (uint256) { + return super.proposalDeadline(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal override(Governor, GovernorPreventLateQuorum) returns (uint256) { + return super._castVote(proposalId, account, support, reason, params); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol new file mode 100644 index 0000000..b374628 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorTimelockCompound.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockCompoundMock is + GovernorSettings, + GovernorTimelockCompound, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function supportsInterface( + bytes4 interfaceId + ) public view override(Governor, GovernorTimelockCompound) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state( + uint256 proposalId + ) public view override(Governor, GovernorTimelockCompound) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + 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 salt + ) internal override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) { + return super._cancel(targets, values, calldatas, salt); + } + + function _executor() internal view override(Governor, GovernorTimelockCompound) returns (address) { + return super._executor(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol new file mode 100644 index 0000000..0630914 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorTimelockControl.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockControlMock is + GovernorSettings, + GovernorTimelockControl, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function supportsInterface( + bytes4 interfaceId + ) public view override(Governor, GovernorTimelockControl) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + 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 proposalId) { + return super._cancel(targets, values, calldatas, descriptionHash); + } + + function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { + return super._executor(); + } + + function nonGovernanceFunction() external {} +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol new file mode 100644 index 0000000..9b533bd --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorVoteMocks is GovernorVotes, GovernorCountingSimple { + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol new file mode 100644 index 0000000..361c287 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorWithParamsMock is GovernorVotes, GovernorCountingSimple { + event CountParams(uint256 uintParam, string strParam); + + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } + + function _getVotes( + address account, + uint256 blockNumber, + bytes memory params + ) internal view override(Governor, GovernorVotes) returns (uint256) { + uint256 reduction = 0; + // If the user provides parameters, we reduce the voting weight by the amount of the integer param + if (params.length > 0) { + (reduction, ) = abi.decode(params, (uint256, string)); + } + // reverts on overflow + return super._getVotes(account, blockNumber, params) - reduction; + } + + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal override(Governor, GovernorCountingSimple) { + if (params.length > 0) { + (uint256 _uintParam, string memory _strParam) = abi.decode(params, (uint256, string)); + emit CountParams(_uintParam, _strParam); + } + return super._countVote(proposalId, account, support, weight, params); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol new file mode 100644 index 0000000..bedcfed --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract BadBeaconNoImpl {} + +contract BadBeaconNotContract { + function implementation() external pure returns (address) { + return address(0x1); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol new file mode 100644 index 0000000..5c272a8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @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 payable returns (address) { + return 0x0000000000000000000000000000000011111142; + } + + function delegatedFunction() external pure returns (bool) { + return true; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSLegacy.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSLegacy.sol new file mode 100644 index 0000000..6956f56 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSLegacy.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./UUPSUpgradeableMock.sol"; + +// This contract implements the pre-4.5 UUPS upgrade function with a rollback test. +// It's used to test that newer UUPS contracts are considered valid upgrades by older UUPS contracts. +contract UUPSUpgradeableLegacyMock is UUPSUpgradeableMock { + // Inlined from ERC1967Upgrade + bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; + + // ERC1967Upgrade._setImplementation is private so we reproduce it here. + // An extra underscore prevents a name clash error. + function __setImplementation(address newImplementation) private { + require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + } + + function _upgradeToAndCallSecureLegacyV1(address newImplementation, bytes memory data, bool forceCall) internal { + address oldImplementation = _getImplementation(); + + // Initial upgrade and setup call + __setImplementation(newImplementation); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(newImplementation, data); + } + + // Perform rollback test if not already in progress + StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT); + if (!rollbackTesting.value) { + // Trigger rollback using upgradeTo from the new implementation + rollbackTesting.value = true; + Address.functionDelegateCall( + newImplementation, + abi.encodeWithSignature("upgradeTo(address)", oldImplementation) + ); + rollbackTesting.value = false; + // Check rollback was effective + require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades"); + // Finally reset to the new implementation and log the upgrade + _upgradeTo(newImplementation); + } + } + + // hooking into the old mechanism + function upgradeTo(address newImplementation) public override { + _upgradeToAndCallSecureLegacyV1(newImplementation, bytes(""), false); + } + + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { + _upgradeToAndCallSecureLegacyV1(newImplementation, data, false); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol new file mode 100644 index 0000000..f02271c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../proxy/utils/UUPSUpgradeable.sol"; +import "../../utils/Counters.sol"; + +contract NonUpgradeableMock { + Counters.Counter internal _counter; + + function current() external view returns (uint256) { + return Counters.current(_counter); + } + + function increment() external { + return Counters.increment(_counter); + } +} + +contract UUPSUpgradeableMock is NonUpgradeableMock, UUPSUpgradeable { + // Not having any checks in this function is dangerous! Do not do this outside tests! + function _authorizeUpgrade(address) internal override {} +} + +contract UUPSUpgradeableUnsafeMock is UUPSUpgradeableMock { + function upgradeTo(address newImplementation) public override { + ERC1967Upgrade._upgradeToAndCall(newImplementation, bytes(""), false); + } + + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { + ERC1967Upgrade._upgradeToAndCall(newImplementation, data, false); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol new file mode 100644 index 0000000..317d724 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC1155/IERC1155Receiver.sol"; +import "../../utils/introspection/ERC165.sol"; + +contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { + bytes4 private _recRetval; + bool private _recReverts; + bytes4 private _batRetval; + bool private _batReverts; + + event Received(address operator, address from, uint256 id, uint256 value, bytes data, uint256 gas); + event BatchReceived(address operator, address from, uint256[] ids, uint256[] values, bytes data, uint256 gas); + + constructor(bytes4 recRetval, bool recReverts, bytes4 batRetval, bool batReverts) { + _recRetval = recRetval; + _recReverts = recReverts; + _batRetval = batRetval; + _batReverts = batReverts; + } + + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external override returns (bytes4) { + require(!_recReverts, "ERC1155ReceiverMock: reverting on receive"); + emit Received(operator, from, id, value, data, gasleft()); + return _recRetval; + } + + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external override returns (bytes4) { + require(!_batReverts, "ERC1155ReceiverMock: reverting on batch receive"); + emit BatchReceived(operator, from, ids, values, data, gasleft()); + return _batRetval; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol new file mode 100644 index 0000000..32f2874 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20DecimalsMock is ERC20 { + uint8 private immutable _decimals; + + constructor(uint8 decimals_) { + _decimals = decimals_; + } + + function decimals() public view override returns (uint8) { + return _decimals; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol new file mode 100644 index 0000000..b4de7b7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/extensions/ERC20FlashMint.sol"; + +abstract contract ERC20FlashMintMock is ERC20FlashMint { + uint256 _flashFeeAmount; + address _flashFeeReceiverAddress; + + function setFlashFee(uint256 amount) public { + _flashFeeAmount = amount; + } + + function _flashFee(address, uint256) internal view override returns (uint256) { + return _flashFeeAmount; + } + + function setFlashFeeReceiver(address receiver) public { + _flashFeeReceiverAddress = receiver; + } + + function _flashFeeReceiver() internal view override returns (address) { + return _flashFeeReceiverAddress; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol new file mode 100644 index 0000000..145e97a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/ERC20.sol"; +import "../../utils/Multicall.sol"; + +abstract contract ERC20MulticallMock is ERC20, Multicall {} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol new file mode 100644 index 0000000..023dab2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC20NoReturnMock { + mapping(address => uint256) private _allowances; + + 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_; + } + + function allowance(address owner, address) public view returns (uint256) { + return _allowances[owner]; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20PermitNoRevertMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20PermitNoRevertMock.sol new file mode 100644 index 0000000..2b6e250 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20PermitNoRevertMock.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT + +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") {} + + function permitThatMayRevert( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + super.permit(owner, spender, value, deadline, v, r, s); + } + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override { + try this.permitThatMayRevert(owner, spender, value, deadline, v, r, s) { + // do nothing + } catch { + // do nothing + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol new file mode 100644 index 0000000..3f8f640 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC20ReturnFalseMock { + mapping(address => uint256) private _allowances; + + function transfer(address, uint256) public pure returns (bool) { + return false; + } + + function transferFrom(address, address, uint256) public pure returns (bool) { + return false; + } + + function approve(address, uint256) public pure 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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnTrueMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnTrueMock.sol new file mode 100644 index 0000000..8953aad --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnTrueMock.sol @@ -0,0 +1,27 @@ +// 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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol new file mode 100644 index 0000000..09a2675 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol new file mode 100644 index 0000000..6e270ca --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol new file mode 100644 index 0000000..55c40ac --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import "../../token/ERC721/extensions/ERC721Enumerable.sol"; + +contract ERC721ConsecutiveEnumerableMock is ERC721Consecutive, ERC721Enumerable { + constructor( + string memory name, + string memory symbol, + address[] memory receivers, + uint96[] memory amounts + ) ERC721(name, symbol) { + for (uint256 i = 0; i < receivers.length; ++i) { + _mintConsecutive(receivers[i], amounts[i]); + } + } + + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC721, ERC721Enumerable) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) { + return super._ownerOf(tokenId); + } + + function _mint(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Consecutive) { + super._mint(to, tokenId); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Enumerable) { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + } + + function _afterTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Consecutive) { + super._afterTokenTransfer(from, to, firstTokenId, batchSize); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol new file mode 100644 index 0000000..427f44a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import "../../token/ERC721/extensions/ERC721Enumerable.sol"; +import "../../token/ERC721/extensions/ERC721Pausable.sol"; +import "../../token/ERC721/extensions/draft-ERC721Votes.sol"; + +/** + * @title ERC721ConsecutiveMock + */ +contract ERC721ConsecutiveMock is ERC721Consecutive, ERC721Pausable, ERC721Votes { + constructor( + string memory name, + string memory symbol, + address[] memory delegates, + address[] memory receivers, + uint96[] memory amounts + ) ERC721(name, symbol) EIP712(name, "1") { + for (uint256 i = 0; i < delegates.length; ++i) { + _delegate(delegates[i], delegates[i]); + } + + for (uint256 i = 0; i < receivers.length; ++i) { + _mintConsecutive(receivers[i], amounts[i]); + } + } + + function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) { + return super._ownerOf(tokenId); + } + + function _mint(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Consecutive) { + super._mint(to, tokenId); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Pausable) { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + } + + function _afterTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Votes, ERC721Consecutive) { + super._afterTokenTransfer(from, to, firstTokenId, batchSize); + } +} + +contract ERC721ConsecutiveNoConstructorMintMock is ERC721Consecutive { + constructor(string memory name, string memory symbol) ERC721(name, symbol) { + _mint(msg.sender, 0); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol new file mode 100644 index 0000000..dd25788 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC721/IERC721Receiver.sol"; + +contract ERC721ReceiverMock is IERC721Receiver { + enum Error { + None, + RevertWithMessage, + RevertWithoutMessage, + Panic + } + + bytes4 private immutable _retval; + Error private immutable _error; + + event Received(address operator, address from, uint256 tokenId, bytes data, uint256 gas); + + constructor(bytes4 retval, Error error) { + _retval = retval; + _error = error; + } + + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes memory data + ) public override returns (bytes4) { + if (_error == Error.RevertWithMessage) { + revert("ERC721ReceiverMock: reverting"); + } else if (_error == Error.RevertWithoutMessage) { + revert(); + } else if (_error == Error.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + emit Received(operator, from, tokenId, data, gasleft()); + return _retval; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol new file mode 100644 index 0000000..455c933 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC721/extensions/ERC721URIStorage.sol"; + +abstract contract ERC721URIStorageMock is ERC721URIStorage { + string private _baseTokenURI; + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + function setBaseURI(string calldata newBaseTokenURI) public { + _baseTokenURI = newBaseTokenURI; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC777Mock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC777Mock.sol new file mode 100644 index 0000000..685277e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC777Mock.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC777/ERC777.sol"; + +abstract contract ERC777Mock is ERC777 { + event BeforeTokenTransfer(); + + function _beforeTokenTransfer(address, address, address, uint256) internal override { + emit BeforeTokenTransfer(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC777SenderRecipientMock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC777SenderRecipientMock.sol new file mode 100644 index 0000000..3bec6d9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/ERC777SenderRecipientMock.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC777/IERC777.sol"; +import "../../token/ERC777/IERC777Sender.sol"; +import "../../token/ERC777/IERC777Recipient.sol"; +import "../../utils/Context.sol"; +import "../../utils/introspection/IERC1820Registry.sol"; +import "../../utils/introspection/ERC1820Implementer.sol"; + +contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer { + event TokensToSendCalled( + address operator, + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData, + address token, + uint256 fromBalance, + uint256 toBalance + ); + + event TokensReceivedCalled( + address operator, + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData, + address token, + uint256 fromBalance, + uint256 toBalance + ); + + // Emitted in ERC777Mock. Here for easier decoding + event BeforeTokenTransfer(); + + bool private _shouldRevertSend; + bool private _shouldRevertReceive; + + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); + + bytes32 private constant _TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); + bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); + + function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external override { + if (_shouldRevertSend) { + revert(); + } + + IERC777 token = IERC777(_msgSender()); + + uint256 fromBalance = token.balanceOf(from); + // when called due to burn, to will be the zero address, which will have a balance of 0 + uint256 toBalance = token.balanceOf(to); + + emit TokensToSendCalled( + operator, + from, + to, + amount, + userData, + operatorData, + address(token), + fromBalance, + toBalance + ); + } + + function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external override { + if (_shouldRevertReceive) { + revert(); + } + + IERC777 token = IERC777(_msgSender()); + + uint256 fromBalance = token.balanceOf(from); + // when called due to burn, to will be the zero address, which will have a balance of 0 + uint256 toBalance = token.balanceOf(to); + + emit TokensReceivedCalled( + operator, + from, + to, + amount, + userData, + operatorData, + address(token), + fromBalance, + toBalance + ); + } + + function senderFor(address account) public { + _registerInterfaceForAddress(_TOKENS_SENDER_INTERFACE_HASH, account); + + address self = address(this); + if (account == self) { + registerSender(self); + } + } + + function registerSender(address sender) public { + _erc1820.setInterfaceImplementer(address(this), _TOKENS_SENDER_INTERFACE_HASH, sender); + } + + function recipientFor(address account) public { + _registerInterfaceForAddress(_TOKENS_RECIPIENT_INTERFACE_HASH, account); + + address self = address(this); + if (account == self) { + registerRecipient(self); + } + } + + function registerRecipient(address recipient) public { + _erc1820.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, recipient); + } + + function setShouldRevertSend(bool shouldRevert) public { + _shouldRevertSend = shouldRevert; + } + + function setShouldRevertReceive(bool shouldRevert) public { + _shouldRevertReceive = shouldRevert; + } + + function send(IERC777 token, address to, uint256 amount, bytes memory data) public { + // This is 777's send function, not the Solidity send function + token.send(to, amount, data); // solhint-disable-line check-send-result + } + + function burn(IERC777 token, uint256 amount, bytes memory data) public { + token.burn(amount, data); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/VotesTimestamp.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/token/VotesTimestamp.sol new file mode 100644 index 0000000..179c500 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor1.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor1.sol new file mode 100644 index 0000000..37ecfd5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor1.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "../../governance/Governor.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import "../../governance/extensions/GovernorTimelockControl.sol"; + +contract MyGovernor1 is + Governor, + GovernorTimelockControl, + GovernorVotes, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + constructor( + IVotes _token, + TimelockController _timelock + ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} + + function votingDelay() public pure override returns (uint256) { + return 1; // 1 block + } + + function votingPeriod() public pure override returns (uint256) { + return 45818; // 1 week + } + + // The following functions are overrides required by Solidity. + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(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, 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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor2.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor2.sol new file mode 100644 index 0000000..1472b67 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor2.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "../../governance/Governor.sol"; +import "../../governance/extensions/GovernorProposalThreshold.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import "../../governance/extensions/GovernorTimelockControl.sol"; + +contract MyGovernor2 is + Governor, + GovernorTimelockControl, + GovernorProposalThreshold, + GovernorVotes, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + constructor( + IVotes _token, + TimelockController _timelock + ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} + + function votingDelay() public pure override returns (uint256) { + return 1; // 1 block + } + + function votingPeriod() public pure override returns (uint256) { + return 45818; // 1 week + } + + function proposalThreshold() public pure override returns (uint256) { + return 1000e18; + } + + // The following functions are overrides required by Solidity. + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(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/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor3.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor3.sol new file mode 100644 index 0000000..f4d2951 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/mocks/wizard/MyGovernor3.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "../../governance/Governor.sol"; +import "../../governance/compatibility/GovernorCompatibilityBravo.sol"; +import "../../governance/extensions/GovernorVotes.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import "../../governance/extensions/GovernorTimelockControl.sol"; + +contract MyGovernor is + Governor, + GovernorTimelockControl, + GovernorCompatibilityBravo, + GovernorVotes, + GovernorVotesQuorumFraction +{ + constructor( + IVotes _token, + TimelockController _timelock + ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} + + function votingDelay() public pure override returns (uint256) { + return 1; // 1 block + } + + function votingPeriod() public pure override returns (uint256) { + return 45818; // 1 week + } + + function proposalThreshold() public pure override returns (uint256) { + return 1000e18; + } + + // The following functions are overrides required by Solidity. + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state( + uint256 proposalId + ) public view override(Governor, IGovernor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public override(Governor, GovernorCompatibilityBravo, IGovernor) returns (uint256) { + return super.propose(targets, values, calldatas, description); + } + + 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( + 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, IERC165, GovernorTimelockControl) returns (bool) { + return super.supportsInterface(interfaceId); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/package.json b/lib/crytic/lib/openzeppelin-contracts/contracts/package.json new file mode 100644 index 0000000..e3e6083 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/package.json @@ -0,0 +1,32 @@ +{ + "name": "@openzeppelin/contracts", + "description": "Secure Smart Contract library for Solidity", + "version": "4.8.0", + "files": [ + "**/*.sol", + "/build/contracts/*.json", + "!/mocks/**/*" + ], + "scripts": { + "prepare": "bash ../scripts/prepare-contracts-package.sh", + "prepare-docs": "cd ..; npm run prepare-docs" + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "security", + "zeppelin" + ], + "author": "OpenZeppelin Community ", + "license": "MIT", + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, + "homepage": "https://openzeppelin.com/contracts/" +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/Clones.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/Clones.sol new file mode 100644 index 0000000..7125198 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/Clones.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (proxy/Clones.sol) + +pragma solidity ^0.8.0; + +/** + * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for + * deploying minimal proxy contracts, also known as "clones". + * + * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies + * > a minimal bytecode implementation that delegates all calls to a known, fixed address. + * + * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` + * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the + * deterministic method. + * + * _Available since v3.4._ + */ +library Clones { + /** + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. + * + * This function uses the create opcode, which should never revert. + */ + function clone(address implementation) internal returns (address instance) { + /// @solidity memory-safe-assembly + assembly { + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create(0, 0x09, 0x37) + } + require(instance != address(0), "ERC1167: create failed"); + } + + /** + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. + * + * This function uses the create2 opcode and a `salt` to deterministically deploy + * the clone. Using the same `implementation` and `salt` multiple time will revert, since + * the clones cannot be deployed twice at the same address. + */ + function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { + /// @solidity memory-safe-assembly + assembly { + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create2(0, 0x09, 0x37, salt) + } + require(instance != address(0), "ERC1167: create2 failed"); + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt, + address deployer + ) internal pure returns (address predicted) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(add(ptr, 0x38), deployer) + mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) + mstore(add(ptr, 0x14), implementation) + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) + mstore(add(ptr, 0x58), salt) + mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) + predicted := keccak256(add(ptr, 0x43), 0x55) + } + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt + ) internal view returns (address predicted) { + return predictDeterministicAddress(implementation, salt, address(this)); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol new file mode 100644 index 0000000..a04d701 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol) + +pragma solidity ^0.8.0; + +import "../Proxy.sol"; +import "./ERC1967Upgrade.sol"; + +/** + * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an + * implementation address that can be changed. This address is stored in storage in the location specified by + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the + * implementation behind the proxy. + */ +contract ERC1967Proxy is Proxy, ERC1967Upgrade { + /** + * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. + * + * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded + * function call, and allows initializing the storage of the proxy like a Solidity constructor. + */ + constructor(address _logic, bytes memory _data) payable { + _upgradeToAndCall(_logic, _data, false); + } + + /** + * @dev Returns the current implementation address. + */ + function _implementation() internal view virtual override returns (address impl) { + return ERC1967Upgrade._getImplementation(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol new file mode 100644 index 0000000..0680f35 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol) + +pragma solidity ^0.8.2; + +import "../beacon/IBeacon.sol"; +import "../../interfaces/draft-IERC1822.sol"; +import "../../utils/Address.sol"; +import "../../utils/StorageSlot.sol"; + +/** + * @dev This abstract contract provides getters and event emitting update functions for + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. + * + * _Available since v4.1._ + */ +abstract contract ERC1967Upgrade { + // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 + bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; + + /** + * @dev Storage slot with the address of the current implementation. + * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is + * validated in the constructor. + */ + bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + /** + * @dev Emitted when the implementation is upgraded. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Returns the current implementation address. + */ + function _getImplementation() internal view returns (address) { + return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 implementation slot. + */ + function _setImplementation(address newImplementation) private { + require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + } + + /** + * @dev Perform implementation upgrade + * + * Emits an {Upgraded} event. + */ + function _upgradeTo(address newImplementation) internal { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + } + + /** + * @dev Perform implementation upgrade with additional setup call. + * + * Emits an {Upgraded} event. + */ + function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { + _upgradeTo(newImplementation); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(newImplementation, data); + } + } + + /** + * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. + * + * Emits an {Upgraded} event. + */ + function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { + // Upgrades from old implementations will perform a rollback test. This test requires the new + // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing + // this special case will break upgrade paths from old UUPS implementation to new ones. + if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { + _setImplementation(newImplementation); + } else { + try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { + require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); + } catch { + revert("ERC1967Upgrade: new implementation is not UUPS"); + } + _upgradeToAndCall(newImplementation, data, forceCall); + } + } + + /** + * @dev Storage slot with the admin of the contract. + * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is + * validated in the constructor. + */ + 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. + */ + function _getAdmin() internal view returns (address) { + return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 admin slot. + */ + function _setAdmin(address newAdmin) private { + require(newAdmin != address(0), "ERC1967: new admin is the zero address"); + StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; + } + + /** + * @dev Changes the admin of the proxy. + * + * Emits an {AdminChanged} event. + */ + function _changeAdmin(address newAdmin) internal { + emit AdminChanged(_getAdmin(), newAdmin); + _setAdmin(newAdmin); + } + + /** + * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. + * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. + */ + bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + + /** + * @dev Emitted when the beacon is upgraded. + */ + event BeaconUpgraded(address indexed beacon); + + /** + * @dev Returns the current beacon. + */ + function _getBeacon() internal view returns (address) { + return StorageSlot.getAddressSlot(_BEACON_SLOT).value; + } + + /** + * @dev Stores a new beacon in the EIP1967 beacon slot. + */ + function _setBeacon(address newBeacon) private { + require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); + require( + Address.isContract(IBeacon(newBeacon).implementation()), + "ERC1967: beacon implementation is not a contract" + ); + StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; + } + + /** + * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does + * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). + * + * Emits a {BeaconUpgraded} event. + */ + function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { + _setBeacon(newBeacon); + emit BeaconUpgraded(newBeacon); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol new file mode 100644 index 0000000..988cf72 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) + +pragma solidity ^0.8.0; + +/** + * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM + * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to + * be specified by overriding the virtual {_implementation} function. + * + * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a + * different contract through the {_delegate} function. + * + * The success and return data of the delegated call will be returned back to the caller of the proxy. + */ +abstract contract Proxy { + /** + * @dev Delegates the current call to `implementation`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _delegate(address implementation) internal virtual { + assembly { + // Copy msg.data. We take full control of memory in this inline assembly + // block because it will not return to Solidity code. We overwrite the + // Solidity scratch pad at memory position 0. + calldatacopy(0, 0, calldatasize()) + + // Call the implementation. + // out and outsize are 0 because we don't know the size yet. + let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) + + // Copy the returned data. + returndatacopy(0, 0, returndatasize()) + + switch result + // delegatecall returns 0 on error. + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + + /** + * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function + * and {_fallback} should delegate. + */ + function _implementation() internal view virtual returns (address); + + /** + * @dev Delegates the current call to the address returned by `_implementation()`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _fallback() internal virtual { + _beforeFallback(); + _delegate(_implementation()); + } + + /** + * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other + * function in the contract matches the call data. + */ + fallback() external payable virtual { + _fallback(); + } + + /** + * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data + * is empty. + */ + receive() external payable virtual { + _fallback(); + } + + /** + * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` + * call, or as part of the Solidity `fallback` or `receive` functions. + * + * If overridden should call `super._beforeFallback()`. + */ + function _beforeFallback() internal virtual {} +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/README.adoc new file mode 100644 index 0000000..5ada16e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/README.adoc @@ -0,0 +1,85 @@ += Proxies + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/proxy + +This is a low-level set of contracts implementing different proxy patterns with and without upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page. + +Most of the proxies below are built on an abstract base contract. + +- {Proxy}: Abstract contract implementing the core delegation functionality. + +In order to avoid clashes with the storage variables of the implementation contract behind a proxy, we use https://eips.ethereum.org/EIPS/eip-1967[EIP1967] storage slots. + +- {ERC1967Upgrade}: Internal functions to get and set the storage slots defined in EIP1967. +- {ERC1967Proxy}: A proxy using EIP1967 storage slots. Not upgradeable by default. + +There are two alternative ways to add upgradeability to an ERC1967 proxy. Their differences are explained below in <>. + +- {TransparentUpgradeableProxy}: A proxy with a built in admin and upgrade interface. +- {UUPSUpgradeable}: An upgradeability mechanism to be included in the implementation contract. + +CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Truffle and Hardhat. + +A different family of proxies are beacon proxies. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. + +- {BeaconProxy}: A proxy that retrieves its implementation from a beacon contract. +- {UpgradeableBeacon}: A beacon contract with a built in admin that can upgrade the {BeaconProxy} pointing to it. + +In this pattern, the proxy contract doesn't hold the implementation address in storage like an ERC1967 proxy. Instead, the address is stored in a separate beacon contract. The `upgrade` operations are sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded. + +Outside the realm of upgradeability, proxies can also be useful to make cheap contract clones, such as those created by an on-chain factory contract that creates many instances of the same contract. These instances are designed to be both cheap to deploy, and cheap to call. + +- {Clones}: A library that can deploy cheap minimal non-upgradeable proxies. + +[[transparent-vs-uups]] +== Transparent vs UUPS Proxies + +The original proxies included in OpenZeppelin followed the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[Transparent Proxy Pattern]. While this pattern is still provided, our recommendation is now shifting towards UUPS proxies, which are both lightweight and versatile. The name UUPS comes from https://eips.ethereum.org/EIPS/eip-1822[EIP1822], which first documented the pattern. + +While both of these share the same interface for upgrades, in UUPS proxies the upgrade is handled by the implementation, and can eventually be removed. Transparent proxies, on the other hand, include the upgrade and admin logic in the proxy itself. This means {TransparentUpgradeableProxy} is more expensive to deploy than what is possible with UUPS proxies. + +UUPS proxies are implemented using an {ERC1967Proxy}. Note that this proxy is not by itself upgradeable. It is the role of the implementation to include, alongside the contract's logic, all the code necessary to update the implementation's address that is stored at a specific slot in the proxy's storage space. This is where the {UUPSUpgradeable} contract comes in. Inheriting from it (and overriding the {xref-UUPSUpgradeable-_authorizeUpgrade-address-}[`_authorizeUpgrade`] function with the relevant access control mechanism) will turn your contract into a UUPS compliant implementation. + +Note that since both proxies use the same storage slot for the implementation address, using a UUPS compliant implementation with a {TransparentUpgradeableProxy} might allow non-admins to perform upgrade operations. + +By default, the upgrade functionality included in {UUPSUpgradeable} contains a security mechanism that will prevent any upgrades to a non UUPS compliant implementation. This prevents upgrades to an implementation contract that wouldn't contain the necessary upgrade mechanism, as it would lock the upgradeability of the proxy forever. This security mechanism can be bypassed by either of: + +- Adding a flag mechanism in the implementation that will disable the upgrade function when triggered. +- Upgrading to an implementation that features an upgrade mechanism without the additional security check, and then upgrading again to another implementation without the upgrade mechanism. + +The current implementation of this security mechanism uses https://eips.ethereum.org/EIPS/eip-1822[EIP1822] to detect the storage slot used by the implementation. A previous implementation, now deprecated, relied on a rollback check. It is possible to upgrade from a contract using the old mechanism to a new one. The inverse is however not possible, as old implementations (before version 4.5) did not include the `ERC1822` interface. + +== Core + +{{Proxy}} + +== ERC1967 + +{{ERC1967Proxy}} + +{{ERC1967Upgrade}} + +== Transparent Proxy + +{{TransparentUpgradeableProxy}} + +{{ProxyAdmin}} + +== Beacon + +{{BeaconProxy}} + +{{IBeacon}} + +{{UpgradeableBeacon}} + +== Minimal Clones + +{{Clones}} + +== Utils + +{{Initializable}} + +{{UUPSUpgradeable}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol new file mode 100644 index 0000000..d217b15 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol) + +pragma solidity ^0.8.0; + +import "./IBeacon.sol"; +import "../Proxy.sol"; +import "../ERC1967/ERC1967Upgrade.sol"; + +/** + * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. + * + * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't + * conflict with the storage layout of the implementation behind the proxy. + * + * _Available since v3.4._ + */ +contract BeaconProxy is Proxy, ERC1967Upgrade { + /** + * @dev Initializes the proxy with `beacon`. + * + * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This + * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity + * constructor. + * + * Requirements: + * + * - `beacon` must be a contract with the interface {IBeacon}. + */ + constructor(address beacon, bytes memory data) payable { + _upgradeBeaconToAndCall(beacon, data, false); + } + + /** + * @dev Returns the current beacon address. + */ + function _beacon() internal view virtual returns (address) { + return _getBeacon(); + } + + /** + * @dev Returns the current implementation address of the associated beacon. + */ + function _implementation() internal view virtual override returns (address) { + return IBeacon(_getBeacon()).implementation(); + } + + /** + * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}. + * + * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. + * + * Requirements: + * + * - `beacon` must be a contract. + * - The implementation returned by `beacon` must be a contract. + */ + function _setBeacon(address beacon, bytes memory data) internal virtual { + _upgradeBeaconToAndCall(beacon, data, false); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol new file mode 100644 index 0000000..fba3ee2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) + +pragma solidity ^0.8.0; + +/** + * @dev This is the interface that {BeaconProxy} expects of its beacon. + */ +interface IBeacon { + /** + * @dev Must return an address that can be used as a delegate call target. + * + * {BeaconProxy} will check that this address is a contract. + */ + function implementation() external view returns (address); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol new file mode 100644 index 0000000..5d83ceb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol) + +pragma solidity ^0.8.0; + +import "./IBeacon.sol"; +import "../../access/Ownable.sol"; +import "../../utils/Address.sol"; + +/** + * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their + * implementation contract, which is where they will delegate all function calls. + * + * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. + */ +contract UpgradeableBeacon is IBeacon, Ownable { + address private _implementation; + + /** + * @dev Emitted when the implementation returned by the beacon is changed. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the + * beacon. + */ + constructor(address implementation_) { + _setImplementation(implementation_); + } + + /** + * @dev Returns the current implementation address. + */ + function implementation() public view virtual override returns (address) { + return _implementation; + } + + /** + * @dev Upgrades the beacon to a new implementation. + * + * Emits an {Upgraded} event. + * + * Requirements: + * + * - msg.sender must be the owner of the contract. + * - `newImplementation` must be a contract. + */ + function upgradeTo(address newImplementation) public virtual onlyOwner { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + } + + /** + * @dev Sets the implementation contract address for this beacon + * + * Requirements: + * + * - `newImplementation` must be a contract. + */ + function _setImplementation(address newImplementation) private { + require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract"); + _implementation = newImplementation; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol new file mode 100644 index 0000000..8395342 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (proxy/transparent/ProxyAdmin.sol) + +pragma solidity ^0.8.0; + +import "./TransparentUpgradeableProxy.sol"; +import "../../access/Ownable.sol"; + +/** + * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an + * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. + */ +contract ProxyAdmin is Ownable { + /** + * @dev Returns the current implementation of `proxy`. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function getProxyImplementation(TransparentUpgradeableProxy 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"); + require(success); + return abi.decode(returndata, (address)); + } + + /** + * @dev Returns the current admin of `proxy`. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function getProxyAdmin(TransparentUpgradeableProxy 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"); + require(success); + return abi.decode(returndata, (address)); + } + + /** + * @dev Changes the admin of `proxy` to `newAdmin`. + * + * Requirements: + * + * - This contract must be the current admin of `proxy`. + */ + function changeProxyAdmin(TransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { + proxy.changeAdmin(newAdmin); + } + + /** + * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function upgrade(TransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { + proxy.upgradeTo(implementation); + } + + /** + * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See + * {TransparentUpgradeableProxy-upgradeToAndCall}. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function upgradeAndCall( + TransparentUpgradeableProxy proxy, + address implementation, + bytes memory data + ) public payable virtual onlyOwner { + proxy.upgradeToAndCall{value: msg.value}(implementation, data); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol new file mode 100644 index 0000000..155a22e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (proxy/transparent/TransparentUpgradeableProxy.sol) + +pragma solidity ^0.8.0; + +import "../ERC1967/ERC1967Proxy.sol"; + +/** + * @dev This contract implements a proxy that is upgradeable by an admin. + * + * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector + * clashing], which can potentially be used in an attack, this contract uses the + * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two + * things that go hand in hand: + * + * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if + * that call matches one of the admin functions exposed by the proxy itself. + * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the + * implementation. If the admin tries to call a function on the implementation it will fail with an error that says + * "admin cannot fallback to proxy target". + * + * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing + * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due + * to sudden errors when trying to call a function from the proxy implementation. + * + * 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. + */ +contract TransparentUpgradeableProxy is ERC1967Proxy { + /** + * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and + * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. + */ + constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) { + _changeAdmin(admin_); + } + + /** + * @dev Modifier used internally that will delegate the call to the implementation unless the sender is the admin. + */ + modifier ifAdmin() { + if (msg.sender == _getAdmin()) { + _; + } else { + _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_) { + _requireZeroValue(); + admin_ = _getAdmin(); + } + + /** + * @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_) { + _requireZeroValue(); + implementation_ = _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 { + _requireZeroValue(); + _changeAdmin(newAdmin); + } + + /** + * @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 { + _requireZeroValue(); + _upgradeToAndCall(newImplementation, bytes(""), false); + } + + /** + * @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 { + _upgradeToAndCall(newImplementation, data, true); + } + + /** + * @dev Returns the current admin. + */ + function _admin() internal view virtual returns (address) { + 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. + */ + function _requireZeroValue() private { + require(msg.value == 0); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol new file mode 100644 index 0000000..638dbe3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol) + +pragma solidity ^0.8.2; + +import "../../utils/Address.sol"; + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * 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"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a + * constructor. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: setting the version to 255 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint8 version) { + require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized != type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint8) { + return _initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _initializing; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol new file mode 100644 index 0000000..4ff0266 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol) + +pragma solidity ^0.8.0; + +import "../../interfaces/draft-IERC1822.sol"; +import "../ERC1967/ERC1967Upgrade.sol"; + +/** + * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an + * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. + * + * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is + * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing + * `UUPSUpgradeable` with a custom implementation of upgrades. + * + * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. + * + * _Available since v4.1._ + */ +abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address private immutable __self = address(this); + + /** + * @dev Check that the execution is being performed through a delegatecall call and that the execution context is + * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case + * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a + * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to + * fail. + */ + modifier onlyProxy() { + require(address(this) != __self, "Function must be called through delegatecall"); + require(_getImplementation() == __self, "Function must be called through active proxy"); + _; + } + + /** + * @dev Check that the execution is not being performed through a delegate call. This allows a function to be + * callable on the implementing contract but not through proxies. + */ + modifier notDelegated() { + require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); + _; + } + + /** + * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the + * implementation. It is used to validate the implementation's compatibility when performing an upgrade. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. + */ + function proxiableUUID() external view virtual override notDelegated returns (bytes32) { + return _IMPLEMENTATION_SLOT; + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeTo(address newImplementation) public virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call + * encoded in `data`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, data, true); + } + + /** + * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by + * {upgradeTo} and {upgradeToAndCall}. + * + * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. + * + * ```solidity + * function _authorizeUpgrade(address) internal override onlyOwner {} + * ``` + */ + function _authorizeUpgrade(address newImplementation) internal virtual; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/security/Pausable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/security/Pausable.sol new file mode 100644 index 0000000..bdd1184 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/security/Pausable.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which allows children to implement an emergency stop + * mechanism that can be triggered by an authorized account. + * + * This module is used through inheritance. It will make available the + * modifiers `whenNotPaused` and `whenPaused`, which can be applied to + * the functions of your contract. Note that they will not be pausable by + * simply including this module, only once the modifiers are put in place. + */ +abstract contract Pausable is Context { + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); + + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); + + bool private _paused; + + /** + * @dev Initializes the contract in unpaused state. + */ + constructor() { + _paused = false; + } + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + _requireNotPaused(); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + * + * Requirements: + * + * - The contract must be paused. + */ + modifier whenPaused() { + _requirePaused(); + _; + } + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** + * @dev Throws if the contract is paused. + */ + function _requireNotPaused() internal view virtual { + require(!paused(), "Pausable: paused"); + } + + /** + * @dev Throws if the contract is not paused. + */ + function _requirePaused() internal view virtual { + require(paused(), "Pausable: not paused"); + } + + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(_msgSender()); + } + + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(_msgSender()); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/security/PullPayment.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/security/PullPayment.sol new file mode 100644 index 0000000..65b4980 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/security/PullPayment.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (security/PullPayment.sol) + +pragma solidity ^0.8.0; + +import "../utils/escrow/Escrow.sol"; + +/** + * @dev Simple implementation of a + * https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/external-calls/#favor-pull-over-push-for-external-calls[pull-payment] + * strategy, where the paying contract doesn't interact directly with the + * receiver account, which must withdraw its payments itself. + * + * Pull-payments are often considered the best practice when it comes to sending + * Ether, security-wise. It prevents recipients from blocking execution, and + * eliminates reentrancy concerns. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + * + * 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}. + */ +abstract contract PullPayment { + Escrow private immutable _escrow; + + constructor() { + _escrow = new Escrow(); + } + + /** + * @dev Withdraw accumulated payments, forwarding all gas to the recipient. + * + * Note that _any_ account can call this function, not just the `payee`. + * This means that contracts unaware of the `PullPayment` protocol can still + * receive funds this way, by having a separate account call + * {withdrawPayments}. + * + * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. + * Make sure you trust the recipient, or are either following the + * checks-effects-interactions pattern or using {ReentrancyGuard}. + * + * @param payee Whose payments will be withdrawn. + * + * Causes the `escrow` to emit a {Withdrawn} event. + */ + function withdrawPayments(address payable payee) public virtual { + _escrow.withdraw(payee); + } + + /** + * @dev Returns the payments owed to an address. + * @param dest The creditor's address. + */ + function payments(address dest) public view returns (uint256) { + return _escrow.depositsOf(dest); + } + + /** + * @dev Called by the payer to store the sent amount as credit to be pulled. + * Funds sent in this way are stored in an intermediate {Escrow} contract, so + * there is no danger of them being spent before withdrawal. + * + * @param dest The destination address of the funds. + * @param amount The amount to transfer. + * + * Causes the `escrow` to emit a {Deposited} event. + */ + function _asyncTransfer(address dest, uint256 amount) internal virtual { + _escrow.deposit{value: amount}(dest); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/security/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/security/README.adoc new file mode 100644 index 0000000..66f398f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/security/README.adoc @@ -0,0 +1,20 @@ += Security + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/security + +These contracts aim to cover common security practices. + +* {PullPayment}: A pattern that can be used to avoid reentrancy attacks. +* {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions. +* {Pausable}: A common emergency response mechanism that can pause functionality while a remediation is pending. + +TIP: For an overview on reentrancy and the possible mechanisms to prevent it, read our article https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + +== Contracts + +{{PullPayment}} + +{{ReentrancyGuard}} + +{{Pausable}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol new file mode 100644 index 0000000..f9281ec --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/security/ReentrancyGuard.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + _nonReentrantBefore(); + _; + _nonReentrantAfter(); + } + + function _nonReentrantBefore() private { + // On the first call to nonReentrant, _status will be _NOT_ENTERED + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + } + + function _nonReentrantAfter() private { + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } + + /** + * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a + * `nonReentrant` function in the call stack. + */ + function _reentrancyGuardEntered() internal view returns (bool) { + return _status == _ENTERED; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol new file mode 100644 index 0000000..b20b711 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol) + +pragma solidity ^0.8.0; + +import "./IERC1155.sol"; +import "./IERC1155Receiver.sol"; +import "./extensions/IERC1155MetadataURI.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of the basic standard multi-token. + * See https://eips.ethereum.org/EIPS/eip-1155 + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + * + * _Available since v3.1._ + */ +contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { + using Address for address; + + // Mapping from token ID to account balances + mapping(uint256 => mapping(address => uint256)) private _balances; + + // Mapping from account to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json + string private _uri; + + /** + * @dev See {_setURI}. + */ + constructor(string memory uri_) { + _setURI(uri_); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC1155).interfaceId || + interfaceId == type(IERC1155MetadataURI).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function uri(uint256) public view virtual override returns (string memory) { + return _uri; + } + + /** + * @dev See {IERC1155-balanceOf}. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { + require(account != address(0), "ERC1155: address zero is not a valid owner"); + return _balances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] memory accounts, + uint256[] memory ids + ) public view virtual override returns (uint256[] memory) { + require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts[i], ids[i]); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { + return _operatorApprovals[account][operator]; + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: caller is not token owner or approved" + ); + _safeTransferFrom(from, to, id, amount, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: caller is not token owner or approved" + ); + _safeBatchTransferFrom(from, to, ids, amounts, data); + } + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: transfer to the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + _balances[id][to] += amount; + + emit TransferSingle(operator, from, to, id, amount); + + _afterTokenTransfer(operator, from, to, ids, amounts, data); + + _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require(to != address(0), "ERC1155: transfer to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + _balances[id][to] += amount; + } + + emit TransferBatch(operator, from, to, ids, amounts); + + _afterTokenTransfer(operator, from, to, ids, amounts, data); + + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the amounts in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setURI(string memory newuri) internal virtual { + _uri = newuri; + } + + /** + * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + _balances[id][to] += amount; + emit TransferSingle(operator, address(0), to, id, amount); + + _afterTokenTransfer(operator, address(0), to, ids, amounts, data); + + _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; i++) { + _balances[ids[i]][to] += amounts[i]; + } + + emit TransferBatch(operator, address(0), to, ids, amounts); + + _afterTokenTransfer(operator, address(0), to, ids, amounts, data); + + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + + /** + * @dev Destroys `amount` tokens of token type `id` from `from` + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `amount` tokens of token type `id`. + */ + function _burn(address from, uint256 id, uint256 amount) internal virtual { + require(from != address(0), "ERC1155: burn from the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + + emit TransferSingle(operator, from, address(0), id, amount); + + _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + */ + function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { + require(from != address(0), "ERC1155: burn from the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); + + for (uint256 i = 0; i < ids.length; i++) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + } + + emit TransferBatch(operator, from, address(0), ids, amounts); + + _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + require(owner != operator, "ERC1155: setting approval status for self"); + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `ids` and `amounts` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + /** + * @dev Hook that is called after any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) private { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non-ERC1155Receiver implementer"); + } + } + } + + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) private { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( + bytes4 response + ) { + if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non-ERC1155Receiver implementer"); + } + } + } + + function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { + uint256[] memory array = new uint256[](1); + array[0] = element; + + return array; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol new file mode 100644 index 0000000..eae0b70 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol) + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC1155 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-1155[EIP]. + * + * _Available since v3.1._ + */ +interface IERC1155 is IERC165 { + /** + * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. + */ + event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); + + /** + * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all + * transfers. + */ + event TransferBatch( + address indexed operator, + address indexed from, + address indexed to, + uint256[] ids, + uint256[] values + ); + + /** + * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to + * `approved`. + */ + event ApprovalForAll(address indexed account, address indexed operator, bool approved); + + /** + * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. + * + * If an {URI} event was emitted for `id`, the standard + * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value + * returned by {IERC1155MetadataURI-uri}. + */ + event URI(string value, uint256 indexed id); + + /** + * @dev Returns the amount of tokens of token type `id` owned by `account`. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) external view returns (uint256); + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] calldata accounts, + uint256[] calldata ids + ) external view returns (uint256[] memory); + + /** + * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the caller. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address account, address operator) external view returns (bool); + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] calldata ids, + uint256[] calldata amounts, + bytes calldata data + ) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol new file mode 100644 index 0000000..0dd271d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev _Available since v3.1._ + */ +interface IERC1155Receiver is IERC165 { + /** + * @dev Handles the receipt of a single ERC1155 token type. This function is + * called at the end of a `safeTransferFrom` after the balance has been updated. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + * (i.e. 0xf23a6e61, or its own function selector). + * + * @param operator The address which initiated the transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param id The ID of the token being transferred + * @param value The amount of tokens being transferred + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4); + + /** + * @dev Handles the receipt of a multiple ERC1155 token types. This function + * is called at the end of a `safeBatchTransferFrom` after the balances have + * been updated. + * + * NOTE: To accept the transfer(s), this must return + * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + * (i.e. 0xbc197c81, or its own function selector). + * + * @param operator The address which initiated the batch transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param ids An array containing ids of each token being transferred (order and length must match values array) + * @param values An array containing amounts of each token being transferred (order and length must match ids array) + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc new file mode 100644 index 0000000..13ffbdb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc @@ -0,0 +1,49 @@ += ERC 1155 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc1155 + +This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-1155[ERC1155 Multi Token Standard]. + +The EIP consists of three interfaces which fulfill different roles, found here as {IERC1155}, {IERC1155MetadataURI} and {IERC1155Receiver}. + +{ERC1155} implements the mandatory {IERC1155} interface, as well as the optional extension {IERC1155MetadataURI}, by relying on the substitution mechanism to use the same URI for all token types, dramatically reducing gas costs. + +Additionally there are multiple custom extensions, including: + +* designation of addresses that can pause token transfers for all users ({ERC1155Pausable}). +* destruction of own tokens ({ERC1155Burnable}). + +NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC1155 (such as <>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc1155.adoc#Presets[ERC1155 Presets] (such as {ERC1155PresetMinterPauser}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts. + +== Core + +{{IERC1155}} + +{{IERC1155MetadataURI}} + +{{ERC1155}} + +{{IERC1155Receiver}} + +{{ERC1155Receiver}} + +== Extensions + +{{ERC1155Pausable}} + +{{ERC1155Burnable}} + +{{ERC1155Supply}} + +{{ERC1155URIStorage}} + +== 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. + +{{ERC1155PresetMinterPauser}} + +== Utilities + +{{ERC1155Holder}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol new file mode 100644 index 0000000..cc81957 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/extensions/ERC1155Burnable.sol) + +pragma solidity ^0.8.0; + +import "../ERC1155.sol"; + +/** + * @dev Extension of {ERC1155} that allows token holders to destroy both their + * own tokens and those that they have been approved to use. + * + * _Available since v3.1._ + */ +abstract contract ERC1155Burnable is ERC1155 { + function burn(address account, uint256 id, uint256 value) public virtual { + require( + account == _msgSender() || isApprovedForAll(account, _msgSender()), + "ERC1155: caller is not token owner or approved" + ); + + _burn(account, id, value); + } + + function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual { + require( + account == _msgSender() || isApprovedForAll(account, _msgSender()), + "ERC1155: caller is not token owner or approved" + ); + + _burnBatch(account, ids, values); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol new file mode 100644 index 0000000..66ad55e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/ERC1155Pausable.sol) + +pragma solidity ^0.8.0; + +import "../ERC1155.sol"; +import "../../../security/Pausable.sol"; + +/** + * @dev ERC1155 token with pausable token transfers, minting and burning. + * + * 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. + * + * _Available since v3.1._ + */ +abstract contract ERC1155Pausable is ERC1155, Pausable { + /** + * @dev See {ERC1155-_beforeTokenTransfer}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override { + super._beforeTokenTransfer(operator, from, to, ids, amounts, data); + + require(!paused(), "ERC1155Pausable: token transfer while paused"); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol new file mode 100644 index 0000000..ec24389 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155Supply.sol) + +pragma solidity ^0.8.0; + +import "../ERC1155.sol"; + +/** + * @dev Extension of ERC1155 that adds tracking of total supply per id. + * + * Useful for scenarios where Fungible and Non-fungible tokens have to be + * clearly identified. Note: While a totalSupply of 1 might mean the + * corresponding is an NFT, there is no guarantees that no other token with the + * same id are not going to be minted. + */ +abstract contract ERC1155Supply is ERC1155 { + mapping(uint256 => uint256) private _totalSupply; + + /** + * @dev Total amount of tokens in with a given id. + */ + function totalSupply(uint256 id) public view virtual returns (uint256) { + return _totalSupply[id]; + } + + /** + * @dev Indicates whether any token exist with a given id, or not. + */ + function exists(uint256 id) public view virtual returns (bool) { + return ERC1155Supply.totalSupply(id) > 0; + } + + /** + * @dev See {ERC1155-_beforeTokenTransfer}. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override { + super._beforeTokenTransfer(operator, from, to, ids, amounts, data); + + if (from == address(0)) { + for (uint256 i = 0; i < ids.length; ++i) { + _totalSupply[ids[i]] += amounts[i]; + } + } + + if (to == address(0)) { + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + uint256 supply = _totalSupply[id]; + require(supply >= amount, "ERC1155: burn amount exceeds totalSupply"); + unchecked { + _totalSupply[id] = supply - amount; + } + } + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol new file mode 100644 index 0000000..623504f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155URIStorage.sol) + +pragma solidity ^0.8.0; + +import "../../../utils/Strings.sol"; +import "../ERC1155.sol"; + +/** + * @dev ERC1155 token with storage based token URI management. + * Inspired by the ERC721URIStorage extension + * + * _Available since v4.6._ + */ +abstract contract ERC1155URIStorage is ERC1155 { + using Strings for uint256; + + // Optional base URI + string private _baseURI = ""; + + // Optional mapping for token URIs + mapping(uint256 => string) private _tokenURIs; + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the concatenation of the `_baseURI` + * and the token-specific uri if the latter is set + * + * This enables the following behaviors: + * + * - if `_tokenURIs[tokenId]` is set, then the result is the concatenation + * of `_baseURI` and `_tokenURIs[tokenId]` (keep in mind that `_baseURI` + * is empty per default); + * + * - if `_tokenURIs[tokenId]` is NOT set then we fallback to `super.uri()` + * which in most cases will contain `ERC1155._uri`; + * + * - if `_tokenURIs[tokenId]` is NOT set, and if the parents do not have a + * uri value set, then the result is empty. + */ + function uri(uint256 tokenId) public view virtual override returns (string memory) { + string memory tokenURI = _tokenURIs[tokenId]; + + // If token URI is set, concatenate base URI and tokenURI (via abi.encodePacked). + return bytes(tokenURI).length > 0 ? string(abi.encodePacked(_baseURI, tokenURI)) : super.uri(tokenId); + } + + /** + * @dev Sets `tokenURI` as the tokenURI of `tokenId`. + */ + function _setURI(uint256 tokenId, string memory tokenURI) internal virtual { + _tokenURIs[tokenId] = tokenURI; + emit URI(uri(tokenId), tokenId); + } + + /** + * @dev Sets `baseURI` as the `_baseURI` for all tokens + */ + function _setBaseURI(string memory baseURI) internal virtual { + _baseURI = baseURI; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol new file mode 100644 index 0000000..520a297 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol) + +pragma solidity ^0.8.0; + +import "../IERC1155.sol"; + +/** + * @dev Interface of the optional ERC1155MetadataExtension interface, as defined + * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. + * + * _Available since v3.1._ + */ +interface IERC1155MetadataURI is IERC1155 { + /** + * @dev Returns the URI for token type `id`. + * + * If the `\{id\}` substring is present in the URI, it must be replaced by + * clients with the actual token type ID. + */ + function uri(uint256 id) external view returns (string memory); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol new file mode 100644 index 0000000..fd7729a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/presets/ERC1155PresetMinterPauser.sol) + +pragma solidity ^0.8.0; + +import "../ERC1155.sol"; +import "../extensions/ERC1155Burnable.sol"; +import "../extensions/ERC1155Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; + +/** + * @dev {ERC1155} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC1155PresetMinterPauser is Context, AccessControlEnumerable, ERC1155Burnable, ERC1155Pausable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE`, and `PAUSER_ROLE` to the account that + * deploys the contract. + */ + constructor(string memory uri) ERC1155(uri) { + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _setupRole(MINTER_ROLE, _msgSender()); + _setupRole(PAUSER_ROLE, _msgSender()); + } + + /** + * @dev Creates `amount` new tokens for `to`, of token type `id`. + * + * See {ERC1155-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 id, uint256 amount, bytes memory data) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have minter role to mint"); + + _mint(to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] variant of {mint}. + */ + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have minter role to mint"); + + _mintBatch(to, ids, amounts, data); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC1155Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC1155Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have pauser role to unpause"); + _unpause(); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(AccessControlEnumerable, ERC1155) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override(ERC1155, ERC1155Pausable) { + super._beforeTokenTransfer(operator, from, to, ids, amounts, data); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/presets/README.md b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/presets/README.md new file mode 100644 index 0000000..468200b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/presets/README.md @@ -0,0 +1 @@ +Contract presets are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com/) as a more powerful alternative. diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol new file mode 100644 index 0000000..7249de8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol) + +pragma solidity ^0.8.0; + +import "./ERC1155Receiver.sol"; + +/** + * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. + * + * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be + * stuck. + * + * @dev _Available since v3.1._ + */ +contract ERC1155Holder is ERC1155Receiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Receiver.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Receiver.sol new file mode 100644 index 0000000..2e6804a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Receiver.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol) + +pragma solidity ^0.8.0; + +import "../IERC1155Receiver.sol"; +import "../../../utils/introspection/ERC165.sol"; + +/** + * @dev _Available since v3.1._ + */ +abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol new file mode 100644 index 0000000..7c53c69 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) + +pragma solidity ^0.8.0; + +import "./IERC20.sol"; +import "./extensions/IERC20Metadata.sol"; +import "../../utils/Context.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ERC20 is Context, IERC20, IERC20Metadata { + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual override returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual override returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address to, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + * - the caller must have allowance for ``from``'s tokens of at least + * `amount`. + */ + function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue); + } + + return true; + } + + /** + * @dev Moves `amount` of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + */ + function _transfer(address from, address to, uint256 amount) internal virtual { + require(from != address(0), "ERC20: transfer from the zero address"); + require(to != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(from, to, amount); + + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by + // decrementing then incrementing. + _balances[to] += amount; + } + + emit Transfer(from, to, amount); + + _afterTokenTransfer(from, to, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply += amount; + unchecked { + // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. + _balances[account] += amount; + } + emit Transfer(address(0), account, amount); + + _afterTokenTransfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + uint256 accountBalance = _balances[account]; + require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); + unchecked { + _balances[account] = accountBalance - amount; + // Overflow not possible: amount <= accountBalance <= totalSupply. + _totalSupply -= amount; + } + + emit Transfer(account, address(0), amount); + + _afterTokenTransfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address owner, address spender, uint256 amount) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * + * Does not update the allowance amount in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Might emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC20: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount); + } + } + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} + + /** + * @dev Hook that is called after any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * has been transferred to `to`. + * - when `from` is zero, `amount` tokens have been minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens have been burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol new file mode 100644 index 0000000..66c4e4d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc new file mode 100644 index 0000000..b3f68e5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc @@ -0,0 +1,78 @@ += ERC 20 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc20 + +This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-20[ERC20 Token Standard]. + +TIP: For an overview of ERC20 tokens and a walk through on how to create a token contract read our xref:ROOT:erc20.adoc[ERC20 guide]. + +There are a few core contracts that implement the behavior specified in the EIP: + +* {IERC20}: the interface all ERC20 implementations should conform to. +* {IERC20Metadata}: the extended ERC20 interface including the <>, <> and <> functions. +* {ERC20}: the implementation of the ERC20 interface, including the <>, <> and <> optional standard extension to the base interface. + +Additionally there are multiple custom extensions, including: + +* {ERC20Burnable}: destruction of own tokens. +* {ERC20Capped}: enforcement of a cap to the total supply when minting tokens. +* {ERC20Pausable}: ability to pause token transfers. +* {ERC20Snapshot}: efficient storage of past token balances to be later queried at any point in time. +* {ERC20Permit}: gasless approval of tokens (standardized as ERC2612). +* {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC3156). +* {ERC20Votes}: support for voting and vote delegation. +* {ERC20VotesComp}: support for voting and vote delegation (compatible with Compound's token, with uint96 restrictions). +* {ERC20Wrapper}: wrapper to create an ERC20 backed by another ERC20, with deposit and withdraw methods. Useful in conjunction with {ERC20Votes}. +* {ERC4626}: tokenized vault that manages shares (represented as ERC20) that are backed by assets (another ERC20). + +Finally, there are some utilities to interact with ERC20 contracts in various ways. + +* {SafeERC20}: a wrapper around the interface that eliminates the need to handle boolean return values. +* {TokenTimelock}: hold tokens for a beneficiary until a specified time. + +NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC20 (such as <>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc20.adoc#Presets[ERC20 Presets] (such as {ERC20PresetMinterPauser}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts. + +== Core + +{{IERC20}} + +{{IERC20Metadata}} + +{{ERC20}} + +== Extensions + +{{ERC20Burnable}} + +{{ERC20Capped}} + +{{ERC20Pausable}} + +{{ERC20Permit}} + +{{ERC20Snapshot}} + +{{ERC20Votes}} + +{{ERC20VotesComp}} + +{{ERC20Wrapper}} + +{{ERC20FlashMint}} + +{{ERC4626}} + +== 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. + +{{ERC20PresetMinterPauser}} + +{{ERC20PresetFixedSupply}} + +== Utilities + +{{SafeERC20}} + +{{TokenTimelock}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol new file mode 100644 index 0000000..1cd08ee --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../../../utils/Context.sol"; + +/** + * @dev Extension of {ERC20} that allows token holders to destroy both their own + * tokens and those that they have an allowance for, in a way that can be + * recognized off-chain (via event analysis). + */ +abstract contract ERC20Burnable is Context, ERC20 { + /** + * @dev Destroys `amount` tokens from the caller. + * + * See {ERC20-_burn}. + */ + function burn(uint256 amount) public virtual { + _burn(_msgSender(), amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, deducting from the caller's + * allowance. + * + * See {ERC20-_burn} and {ERC20-allowance}. + * + * Requirements: + * + * - the caller must have allowance for ``accounts``'s tokens of at least + * `amount`. + */ + function burnFrom(address account, uint256 amount) public virtual { + _spendAllowance(account, _msgSender(), amount); + _burn(account, amount); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol new file mode 100644 index 0000000..16f830d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Capped.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; + +/** + * @dev Extension of {ERC20} that adds a cap to the supply of tokens. + */ +abstract contract ERC20Capped is ERC20 { + uint256 private immutable _cap; + + /** + * @dev Sets the value of the `cap`. This value is immutable, it can only be + * set once during construction. + */ + constructor(uint256 cap_) { + require(cap_ > 0, "ERC20Capped: cap is 0"); + _cap = cap_; + } + + /** + * @dev Returns the cap on the token's total supply. + */ + function cap() public view virtual returns (uint256) { + return _cap; + } + + /** + * @dev See {ERC20-_mint}. + */ + function _mint(address account, uint256 amount) internal virtual override { + require(ERC20.totalSupply() + amount <= cap(), "ERC20Capped: cap exceeded"); + super._mint(account, amount); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol new file mode 100644 index 0000000..063fe99 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20FlashMint.sol) + +pragma solidity ^0.8.0; + +import "../../../interfaces/IERC3156FlashBorrower.sol"; +import "../../../interfaces/IERC3156FlashLender.sol"; +import "../ERC20.sol"; + +/** + * @dev Implementation of the ERC3156 Flash loans extension, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + * + * Adds the {flashLoan} method, which provides flash loan support at the token + * level. By default there is no fee, but this can be changed by overriding {flashFee}. + * + * _Available since v4.1._ + */ +abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { + bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + /** + * @dev Returns the maximum amount of tokens available for loan. + * @param token The address of the token that is requested. + * @return The amount of token that can be loaned. + */ + function maxFlashLoan(address token) public view virtual override returns (uint256) { + return token == address(this) ? type(uint256).max - ERC20.totalSupply() : 0; + } + + /** + * @dev Returns the fee applied when doing flash loans. This function calls + * the {_flashFee} function which returns the fee applied when doing flash + * loans. + * @param token The token to be flash loaned. + * @param amount The amount of tokens to be loaned. + * @return The fees applied to the corresponding flash loan. + */ + function flashFee(address token, uint256 amount) public view virtual override returns (uint256) { + require(token == address(this), "ERC20FlashMint: wrong token"); + return _flashFee(token, amount); + } + + /** + * @dev Returns the fee applied when doing flash loans. By default this + * implementation has 0 fees. This function can be overloaded to make + * the flash loan mechanism deflationary. + * @param token The token to be flash loaned. + * @param amount The amount of tokens to be loaned. + * @return The fees applied to the corresponding flash loan. + */ + function _flashFee(address token, uint256 amount) internal view virtual returns (uint256) { + // silence warning about unused variable without the addition of bytecode. + token; + amount; + return 0; + } + + /** + * @dev Returns the receiver address of the flash fee. By default this + * implementation returns the address(0) which means the fee amount will be burnt. + * This function can be overloaded to change the fee receiver. + * @return The address for which the flash fee will be sent to. + */ + function _flashFeeReceiver() internal view virtual returns (address) { + return address(0); + } + + /** + * @dev Performs a flash loan. New tokens are minted and sent to the + * `receiver`, who is required to implement the {IERC3156FlashBorrower} + * interface. By the end of the flash loan, the receiver is expected to own + * amount + fee tokens and have them approved back to the token contract itself so + * they can be burned. + * @param receiver The receiver of the flash loan. Should implement the + * {IERC3156FlashBorrower-onFlashLoan} interface. + * @param token The token to be flash loaned. Only `address(this)` is + * supported. + * @param amount The amount of tokens to be loaned. + * @param data An arbitrary datafield that is passed to the receiver. + * @return `true` if the flash loan was successful. + */ + // This function can reenter, but it doesn't pose a risk because it always preserves the property that the amount + // minted at the beginning is always recovered and burned at the end, or else the entire function will revert. + // slither-disable-next-line reentrancy-no-eth + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 amount, + bytes calldata data + ) public virtual override returns (bool) { + require(amount <= maxFlashLoan(token), "ERC20FlashMint: amount exceeds maxFlashLoan"); + uint256 fee = flashFee(token, amount); + _mint(address(receiver), amount); + require( + receiver.onFlashLoan(msg.sender, token, amount, fee, data) == _RETURN_VALUE, + "ERC20FlashMint: invalid return value" + ); + address flashFeeReceiver = _flashFeeReceiver(); + _spendAllowance(address(receiver), address(this), amount + fee); + if (fee == 0 || flashFeeReceiver == address(0)) { + _burn(address(receiver), amount + fee); + } else { + _burn(address(receiver), amount); + _transfer(address(receiver), flashFeeReceiver, fee); + } + return true; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol new file mode 100644 index 0000000..e011f08 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Pausable.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../../../security/Pausable.sol"; + +/** + * @dev ERC20 token with pausable token transfers, minting and burning. + * + * 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 { + /** + * @dev See {ERC20-_beforeTokenTransfer}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { + super._beforeTokenTransfer(from, to, amount); + + require(!paused(), "ERC20Pausable: token transfer while paused"); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol new file mode 100644 index 0000000..a357199 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/extensions/ERC20Permit.sol) + +pragma solidity ^0.8.0; + +import "./IERC20Permit.sol"; +import "../ERC20.sol"; +import "../../../utils/cryptography/ECDSA.sol"; +import "../../../utils/cryptography/EIP712.sol"; +import "../../../utils/Counters.sol"; + +/** + * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + * + * _Available since v3.4._ + */ +abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { + using Counters for Counters.Counter; + + mapping(address => Counters.Counter) private _nonces; + + // solhint-disable-next-line var-name-mixedcase + bytes32 private constant _PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + /** + * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. + * However, to ensure consistency with the upgradeable transpiler, we will continue + * to reserve a slot. + * @custom:oz-renamed-from _PERMIT_TYPEHASH + */ + // solhint-disable-next-line var-name-mixedcase + bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; + + /** + * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. + * + * It's a good idea to use the same `name` that is defined as the ERC20 token name. + */ + constructor(string memory name) EIP712(name, "1") {} + + /** + * @dev See {IERC20Permit-permit}. + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override { + require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); + + bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); + + bytes32 hash = _hashTypedDataV4(structHash); + + address signer = ECDSA.recover(hash, v, r, s); + require(signer == owner, "ERC20Permit: invalid signature"); + + _approve(owner, spender, value); + } + + /** + * @dev See {IERC20Permit-nonces}. + */ + function nonces(address owner) public view virtual override returns (uint256) { + return _nonces[owner].current(); + } + + /** + * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view override returns (bytes32) { + return _domainSeparatorV4(); + } + + /** + * @dev "Consume a nonce": return the current value and increment. + * + * _Available since v4.1._ + */ + function _useNonce(address owner) internal virtual returns (uint256 current) { + Counters.Counter storage nonce = _nonces[owner]; + current = nonce.current(); + nonce.increment(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Snapshot.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Snapshot.sol new file mode 100644 index 0000000..ee104b0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Snapshot.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/extensions/ERC20Snapshot.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../../../utils/Arrays.sol"; +import "../../../utils/Counters.sol"; + +/** + * @dev This contract extends an ERC20 token with a snapshot mechanism. When a snapshot is created, the balances and + * total supply at the time are recorded for later access. + * + * This can be used to safely create mechanisms based on token balances such as trustless dividends or weighted voting. + * In naive implementations it's possible to perform a "double spend" attack by reusing the same balance from different + * accounts. By using snapshots to calculate dividends or voting power, those attacks no longer apply. It can also be + * used to create an efficient ERC20 forking mechanism. + * + * Snapshots are created by the internal {_snapshot} function, which will emit the {Snapshot} event and return a + * snapshot id. To get the total supply at the time of a snapshot, call the function {totalSupplyAt} with the snapshot + * id. To get the balance of an account at the time of a snapshot, call the {balanceOfAt} function with the snapshot id + * and the account address. + * + * NOTE: Snapshot policy can be customized by overriding the {_getCurrentSnapshotId} method. For example, having it + * return `block.number` will trigger the creation of snapshot at the beginning of each new block. When overriding this + * function, be careful about the monotonicity of its result. Non-monotonic snapshot ids will break the contract. + * + * Implementing snapshots for every block using this method will incur significant gas costs. For a gas-efficient + * alternative consider {ERC20Votes}. + * + * ==== Gas Costs + * + * Snapshots are efficient. Snapshot creation is _O(1)_. Retrieval of balances or total supply from a snapshot is _O(log + * n)_ in the number of snapshots that have been created, although _n_ for a specific account will generally be much + * smaller since identical balances in subsequent snapshots are stored as a single entry. + * + * There is a constant overhead for normal ERC20 transfers due to the additional snapshot bookkeeping. This overhead is + * only significant for the first transfer that immediately follows a snapshot for a particular account. Subsequent + * transfers will have normal cost until the next snapshot, and so on. + */ + +abstract contract ERC20Snapshot is ERC20 { + // Inspired by Jordi Baylina's MiniMeToken to record historical balances: + // https://github.com/Giveth/minime/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol + + using Arrays for uint256[]; + using Counters for Counters.Counter; + + // Snapshotted values have arrays of ids and the value corresponding to that id. These could be an array of a + // Snapshot struct, but that would impede usage of functions that work on an array. + struct Snapshots { + uint256[] ids; + uint256[] values; + } + + mapping(address => Snapshots) private _accountBalanceSnapshots; + Snapshots private _totalSupplySnapshots; + + // Snapshot ids increase monotonically, with the first value being 1. An id of 0 is invalid. + Counters.Counter private _currentSnapshotId; + + /** + * @dev Emitted by {_snapshot} when a snapshot identified by `id` is created. + */ + event Snapshot(uint256 id); + + /** + * @dev Creates a new snapshot and returns its snapshot id. + * + * Emits a {Snapshot} event that contains the same id. + * + * {_snapshot} is `internal` and you have to decide how to expose it externally. Its usage may be restricted to a + * set of accounts, for example using {AccessControl}, or it may be open to the public. + * + * [WARNING] + * ==== + * While an open way of calling {_snapshot} is required for certain trust minimization mechanisms such as forking, + * you must consider that it can potentially be used by attackers in two ways. + * + * First, it can be used to increase the cost of retrieval of values from snapshots, although it will grow + * logarithmically thus rendering this attack ineffective in the long term. Second, it can be used to target + * specific accounts and increase the cost of ERC20 transfers for them, in the ways specified in the Gas Costs + * section above. + * + * We haven't measured the actual numbers; if this is something you're interested in please reach out to us. + * ==== + */ + function _snapshot() internal virtual returns (uint256) { + _currentSnapshotId.increment(); + + uint256 currentId = _getCurrentSnapshotId(); + emit Snapshot(currentId); + return currentId; + } + + /** + * @dev Get the current snapshotId + */ + function _getCurrentSnapshotId() internal view virtual returns (uint256) { + return _currentSnapshotId.current(); + } + + /** + * @dev Retrieves the balance of `account` at the time `snapshotId` was created. + */ + function balanceOfAt(address account, uint256 snapshotId) public view virtual returns (uint256) { + (bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]); + + return snapshotted ? value : balanceOf(account); + } + + /** + * @dev Retrieves the total supply at the time `snapshotId` was created. + */ + function totalSupplyAt(uint256 snapshotId) public view virtual returns (uint256) { + (bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnapshots); + + return snapshotted ? value : totalSupply(); + } + + // Update balance and/or total supply snapshots before the values are modified. This is implemented + // in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations. + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { + super._beforeTokenTransfer(from, to, amount); + + if (from == address(0)) { + // mint + _updateAccountSnapshot(to); + _updateTotalSupplySnapshot(); + } else if (to == address(0)) { + // burn + _updateAccountSnapshot(from); + _updateTotalSupplySnapshot(); + } else { + // transfer + _updateAccountSnapshot(from); + _updateAccountSnapshot(to); + } + } + + function _valueAt(uint256 snapshotId, Snapshots storage snapshots) private view returns (bool, uint256) { + require(snapshotId > 0, "ERC20Snapshot: id is 0"); + require(snapshotId <= _getCurrentSnapshotId(), "ERC20Snapshot: nonexistent id"); + + // When a valid snapshot is queried, there are three possibilities: + // a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never + // created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds + // to this id is the current one. + // b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the + // requested id, and its value is the one to return. + // c) More snapshots were created after the requested one, and the queried value was later modified. There will be + // no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is + // larger than the requested one. + // + // In summary, we need to find an element in an array, returning the index of the smallest value that is larger if + // it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does + // exactly this. + + uint256 index = snapshots.ids.findUpperBound(snapshotId); + + if (index == snapshots.ids.length) { + return (false, 0); + } else { + return (true, snapshots.values[index]); + } + } + + function _updateAccountSnapshot(address account) private { + _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account)); + } + + function _updateTotalSupplySnapshot() private { + _updateSnapshot(_totalSupplySnapshots, totalSupply()); + } + + function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue) private { + uint256 currentId = _getCurrentSnapshotId(); + if (_lastSnapshotId(snapshots.ids) < currentId) { + snapshots.ids.push(currentId); + snapshots.values.push(currentValue); + } + } + + function _lastSnapshotId(uint256[] storage ids) private view returns (uint256) { + if (ids.length == 0) { + return 0; + } else { + return ids[ids.length - 1]; + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol new file mode 100644 index 0000000..273bb8c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20Votes.sol) + +pragma solidity ^0.8.0; + +import "./ERC20Permit.sol"; +import "../../../interfaces/IERC5805.sol"; +import "../../../utils/math/Math.sol"; +import "../../../utils/math/SafeCast.sol"; +import "../../../utils/cryptography/ECDSA.sol"; + +/** + * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's, + * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1. + * + * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module. + * + * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either + * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting + * power can be queried through the public accessors {getVotes} and {getPastVotes}. + * + * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it + * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. + * + * _Available since v4.2._ + */ +abstract contract ERC20Votes is ERC20Permit, IERC5805 { + 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 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`. + */ + 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 `timepoint`. + * + * Requirements: + * + * - `timepoint` must be in the past + */ + 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 `timepoint`. Note, this value is the sum of all balances. + * It is NOT the sum of all the delegated votes! + * + * Requirements: + * + * - `timepoint` must be in the past + */ + 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 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 `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 `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; + + uint256 low = 0; + uint256 high = length; + + if (length > 5) { + uint256 mid = length - Math.sqrt(length); + if (_unsafeAccess(ckpts, mid).fromBlock > timepoint) { + high = mid; + } else { + low = mid + 1; + } + } + + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(ckpts, mid).fromBlock > timepoint) { + 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 == clock()) { + _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight); + } else { + ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(clock()), 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/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20VotesComp.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20VotesComp.sol new file mode 100644 index 0000000..0461310 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20VotesComp.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20VotesComp.sol) + +pragma solidity ^0.8.0; + +import "./ERC20Votes.sol"; + +/** + * @dev Extension of ERC20 to support Compound's voting and delegation. This version exactly matches Compound's + * interface, with the drawback of only supporting supply up to (2^96^ - 1). + * + * NOTE: You should use this contract if you need exact compatibility with COMP (for example in order to use your token + * with Governor Alpha or Bravo) and if you are sure the supply cap of 2^96^ is enough for you. Otherwise, use the + * {ERC20Votes} variant of this module. + * + * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either + * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting + * power can be queried through the public accessors {getCurrentVotes} and {getPriorVotes}. + * + * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it + * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. + * + * _Available since v4.2._ + */ +abstract contract ERC20VotesComp is ERC20Votes { + /** + * @dev Comp version of the {getVotes} accessor, with `uint96` return type. + */ + function getCurrentVotes(address account) external view virtual returns (uint96) { + return SafeCast.toUint96(getVotes(account)); + } + + /** + * @dev Comp version of the {getPastVotes} accessor, with `uint96` return type. + */ + function getPriorVotes(address account, uint256 blockNumber) external view virtual returns (uint96) { + return SafeCast.toUint96(getPastVotes(account, blockNumber)); + } + + /** + * @dev Maximum token supply. Reduced to `type(uint96).max` (2^96^ - 1) to fit COMP interface. + */ + function _maxSupply() internal view virtual override returns (uint224) { + return type(uint96).max; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol new file mode 100644 index 0000000..ce51569 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/extensions/ERC20Wrapper.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../utils/SafeERC20.sol"; + +/** + * @dev Extension of the ERC20 token contract to support token wrapping. + * + * Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful + * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC20Votes} will allow the + * wrapping of an existing "basic" ERC20 into a governance token. + * + * _Available since v4.2._ + */ +abstract contract ERC20Wrapper is ERC20 { + IERC20 private immutable _underlying; + + constructor(IERC20 underlyingToken) { + _underlying = underlyingToken; + } + + /** + * @dev See {ERC20-decimals}. + */ + function decimals() public view virtual override returns (uint8) { + 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); + _mint(account, amount); + return true; + } + + /** + * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens. + */ + function withdrawTo(address account, uint256 amount) public virtual returns (bool) { + _burn(_msgSender(), amount); + SafeERC20.safeTransfer(_underlying, account, amount); + return true; + } + + /** + * @dev Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake. Internal + * 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(); + _mint(account, value); + return value; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol new file mode 100644 index 0000000..3846cbb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC4626.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../utils/SafeERC20.sol"; +import "../../../interfaces/IERC4626.sol"; +import "../../../utils/math/Math.sol"; + +/** + * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in + * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626]. + * + * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for + * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends + * 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] + * ==== + * 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 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 _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_); + _underlyingDecimals = success ? assetDecimals : 18; + _asset = asset_; + } + + /** + * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way. + */ + function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool, uint8) { + (bool success, bytes memory encodedDecimals) = address(asset_).staticcall( + abi.encodeWithSelector(IERC20Metadata.decimals.selector) + ); + if (success && encodedDecimals.length >= 32) { + uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256)); + if (returnedDecimals <= type(uint8).max) { + return (true, uint8(returnedDecimals)); + } + } + return (false, 0); + } + + /** + * @dev Decimals are 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) { + return _underlyingDecimals + _decimalsOffset(); + } + + /** @dev See {IERC4626-asset}. */ + function asset() public view virtual override returns (address) { + return address(_asset); + } + + /** @dev See {IERC4626-totalAssets}. */ + function totalAssets() public view virtual override returns (uint256) { + return _asset.balanceOf(address(this)); + } + + /** @dev See {IERC4626-convertToShares}. */ + function convertToShares(uint256 assets) public view virtual override returns (uint256) { + return _convertToShares(assets, Math.Rounding.Down); + } + + /** @dev See {IERC4626-convertToAssets}. */ + function convertToAssets(uint256 shares) public view virtual override returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Down); + } + + /** @dev See {IERC4626-maxDeposit}. */ + function maxDeposit(address) public view virtual override returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4626-maxMint}. */ + function maxMint(address) public view virtual override returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4626-maxWithdraw}. */ + function maxWithdraw(address owner) public view virtual override returns (uint256) { + return _convertToAssets(balanceOf(owner), Math.Rounding.Down); + } + + /** @dev See {IERC4626-maxRedeem}. */ + function maxRedeem(address owner) public view virtual override returns (uint256) { + return balanceOf(owner); + } + + /** @dev See {IERC4626-previewDeposit}. */ + function previewDeposit(uint256 assets) public view virtual override returns (uint256) { + return _convertToShares(assets, Math.Rounding.Down); + } + + /** @dev See {IERC4626-previewMint}. */ + function previewMint(uint256 shares) public view virtual override returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Up); + } + + /** @dev See {IERC4626-previewWithdraw}. */ + function previewWithdraw(uint256 assets) public view virtual override returns (uint256) { + return _convertToShares(assets, Math.Rounding.Up); + } + + /** @dev See {IERC4626-previewRedeem}. */ + function previewRedeem(uint256 shares) public view virtual override returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Down); + } + + /** @dev See {IERC4626-deposit}. */ + function deposit(uint256 assets, address receiver) public virtual override returns (uint256) { + require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max"); + + uint256 shares = previewDeposit(assets); + _deposit(_msgSender(), receiver, assets, shares); + + return shares; + } + + /** @dev See {IERC4626-mint}. + * + * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero. + * In this case, the shares will be minted without requiring any assets to be deposited. + */ + function mint(uint256 shares, address receiver) public virtual override returns (uint256) { + require(shares <= maxMint(receiver), "ERC4626: mint more than max"); + + uint256 assets = previewMint(shares); + _deposit(_msgSender(), receiver, assets, shares); + + return assets; + } + + /** @dev See {IERC4626-withdraw}. */ + function withdraw(uint256 assets, address receiver, address owner) public virtual override returns (uint256) { + require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max"); + + uint256 shares = previewWithdraw(assets); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return shares; + } + + /** @dev See {IERC4626-redeem}. */ + function redeem(uint256 shares, address receiver, address owner) public virtual override returns (uint256) { + require(shares <= maxRedeem(owner), "ERC4626: redeem more than max"); + + uint256 assets = previewRedeem(shares); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return assets; + } + + /** + * @dev Internal conversion function (from assets to shares) with support for rounding direction. + */ + function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) { + 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) { + return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding); + } + + /** + * @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 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. + // + // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the + // assets are transferred and before the shares are minted, which is a valid state. + // slither-disable-next-line reentrancy-no-eth + SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); + _mint(receiver, shares); + + emit Deposit(caller, receiver, assets, shares); + } + + /** + * @dev Withdraw/redeem common workflow. + */ + function _withdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) internal virtual { + if (caller != owner) { + _spendAllowance(owner, caller, shares); + } + + // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the + // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, + // calls the vault, which is assumed not malicious. + // + // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the + // shares are burned and after the assets are transferred, which is a valid state. + _burn(owner, shares); + SafeERC20.safeTransfer(_asset, receiver, assets); + + emit Withdraw(caller, receiver, owner, assets, shares); + } + + function _decimalsOffset() internal view virtual returns (uint8) { + return 0; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol new file mode 100644 index 0000000..83ba6ac --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) + +pragma solidity ^0.8.0; + +import "../IERC20.sol"; + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + * + * _Available since v4.1._ + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol new file mode 100644 index 0000000..bb43e53 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Permit.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + */ +interface IERC20Permit { + /** + * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, + * given ``owner``'s signed approval. + * + * IMPORTANT: The same issues {IERC20-approve} has related to transaction + * ordering also apply here. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `deadline` must be a timestamp in the future. + * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` + * over the EIP712-formatted function arguments. + * - the signature must use ``owner``'s current nonce (see {nonces}). + * + * For more information on the signature format, see the + * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP + * section]. + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @dev Returns the current nonce for `owner`. This value must be + * included whenever a signature is generated for {permit}. + * + * Every successful call to {permit} increases ``owner``'s nonce by one. This + * prevents a signature from being used multiple times. + */ + function nonces(address owner) external view returns (uint256); + + /** + * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view returns (bytes32); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Permit.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Permit.sol new file mode 100644 index 0000000..6579ef3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Permit.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/draft-ERC20Permit.sol) + +pragma solidity ^0.8.0; + +// EIP-2612 is Final as of 2022-11-01. This file is deprecated. + +import "./ERC20Permit.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-IERC20Permit.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-IERC20Permit.sol new file mode 100644 index 0000000..1df6c53 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-IERC20Permit.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +// EIP-2612 is Final as of 2022-11-01. This file is deprecated. + +import "./IERC20Permit.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol new file mode 100644 index 0000000..e826814 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/presets/ERC20PresetFixedSupply.sol) +pragma solidity ^0.8.0; + +import "../extensions/ERC20Burnable.sol"; + +/** + * @dev {ERC20} token, including: + * + * - Preminted initial supply + * - Ability for holders to burn (destroy) their tokens + * - No access control mechanism (for minting/pausing) and hence no governance + * + * This contract uses {ERC20Burnable} to include burn capabilities - head to + * its documentation for details. + * + * _Available since v3.4._ + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC20PresetFixedSupply is ERC20Burnable { + /** + * @dev Mints `initialSupply` amount of token and transfers them to `owner`. + * + * See {ERC20-constructor}. + */ + constructor(string memory name, string memory symbol, uint256 initialSupply, address owner) ERC20(name, symbol) { + _mint(owner, initialSupply); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol new file mode 100644 index 0000000..e711a89 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/presets/ERC20PresetMinterPauser.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../extensions/ERC20Burnable.sol"; +import "../extensions/ERC20Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; + +/** + * @dev {ERC20} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC20PresetMinterPauser is Context, AccessControlEnumerable, ERC20Burnable, ERC20Pausable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the + * account that deploys the contract. + * + * See {ERC20-constructor}. + */ + constructor(string memory name, string memory symbol) ERC20(name, symbol) { + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _setupRole(MINTER_ROLE, _msgSender()); + _setupRole(PAUSER_ROLE, _msgSender()); + } + + /** + * @dev Creates `amount` new tokens for `to`. + * + * See {ERC20-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 amount) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have minter role to mint"); + _mint(to, amount); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to unpause"); + _unpause(); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual override(ERC20, ERC20Pausable) { + super._beforeTokenTransfer(from, to, amount); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/README.md b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/README.md new file mode 100644 index 0000000..468200b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/presets/README.md @@ -0,0 +1 @@ +Contract presets are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com/) as a more powerful alternative. diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol new file mode 100644 index 0000000..028711d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) + +pragma solidity ^0.8.0; + +import "../IERC20.sol"; +import "../extensions/IERC20Permit.sol"; +import "../../../utils/Address.sol"; + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using Address for address; + + function safeTransfer(IERC20 token, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); + } + + function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { + _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + require( + (value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); + } + + 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)); + } + + 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)); + } + } + + function safePermit( + IERC20Permit token, + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) internal { + uint256 nonceBefore = token.nonces(owner); + token.permit(owner, spender, value, deadline, v, r, s); + uint256 nonceAfter = token.nonces(owner); + require(nonceAfter == nonceBefore + 1, "SafeERC20: permit 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). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that + // 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"); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/utils/TokenTimelock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/utils/TokenTimelock.sol new file mode 100644 index 0000000..ed855b7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC20/utils/TokenTimelock.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/utils/TokenTimelock.sol) + +pragma solidity ^0.8.0; + +import "./SafeERC20.sol"; + +/** + * @dev A token holder contract that will allow a beneficiary to extract the + * tokens after a given release time. + * + * Useful for simple vesting schedules like "advisors get all of their tokens + * after 1 year". + */ +contract TokenTimelock { + using SafeERC20 for IERC20; + + // ERC20 basic token contract being held + IERC20 private immutable _token; + + // beneficiary of tokens after they are released + address private immutable _beneficiary; + + // timestamp when token release is enabled + uint256 private immutable _releaseTime; + + /** + * @dev Deploys a timelock instance that is able to hold the token specified, and will only release it to + * `beneficiary_` when {release} is invoked after `releaseTime_`. The release time is specified as a Unix timestamp + * (in seconds). + */ + constructor(IERC20 token_, address beneficiary_, uint256 releaseTime_) { + require(releaseTime_ > block.timestamp, "TokenTimelock: release time is before current time"); + _token = token_; + _beneficiary = beneficiary_; + _releaseTime = releaseTime_; + } + + /** + * @dev Returns the token being held. + */ + function token() public view virtual returns (IERC20) { + return _token; + } + + /** + * @dev Returns the beneficiary that will receive the tokens. + */ + function beneficiary() public view virtual returns (address) { + return _beneficiary; + } + + /** + * @dev Returns the time when the tokens are released in seconds since Unix epoch (i.e. Unix timestamp). + */ + function releaseTime() public view virtual returns (uint256) { + return _releaseTime; + } + + /** + * @dev Transfers tokens held by the timelock to the beneficiary. Will only succeed if invoked after the release + * time. + */ + function release() public virtual { + require(block.timestamp >= releaseTime(), "TokenTimelock: current time is before release time"); + + uint256 amount = token().balanceOf(address(this)); + require(amount > 0, "TokenTimelock: no tokens to release"); + + token().safeTransfer(beneficiary(), amount); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol new file mode 100644 index 0000000..6bf620b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/ERC721.sol) + +pragma solidity ^0.8.0; + +import "./IERC721.sol"; +import "./IERC721Receiver.sol"; +import "./extensions/IERC721Metadata.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/Strings.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping(uint256 => address) private _owners; + + // Mapping owner address to token count + mapping(address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: address zero is not a valid owner"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _ownerOf(tokenId); + require(owner != address(0), "ERC721: invalid token ID"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + _requireMinted(tokenId); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require( + _msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not token owner or approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + _requireMinted(tokenId); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); + _safeTransfer(from, to, tokenId, data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + */ + function _ownerOf(uint256 tokenId) internal view virtual returns (address) { + return _owners[tokenId]; + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _ownerOf(tokenId) != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { + _mint(to, tokenId); + require( + _checkOnERC721Received(address(0), to, tokenId, data), + "ERC721: transfer to non ERC721Receiver implementer" + ); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId, 1); + + // Check that tokenId was not minted by `_beforeTokenTransfer` hook + require(!_exists(tokenId), "ERC721: token already minted"); + + unchecked { + // Will not overflow unless all 2**256 token ids are minted to the same owner. + // Given that tokens are minted one by one, it is impossible in practice that + // this ever happens. Might change if we allow batch minting. + // The ERC fails to describe this case. + _balances[to] += 1; + } + + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + + _afterTokenTransfer(address(0), to, tokenId, 1); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This is an internal function that does not check if the sender is authorized to operate on the token. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId, 1); + + // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook + owner = ERC721.ownerOf(tokenId); + + // Clear approvals + delete _tokenApprovals[tokenId]; + + unchecked { + // Cannot overflow, as that would require more tokens to be burned/transferred + // out than the owner initially received through minting and transferring in. + _balances[owner] -= 1; + } + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + + _afterTokenTransfer(owner, address(0), tokenId, 1); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId, 1); + + // Check that tokenId was not transferred by `_beforeTokenTransfer` hook + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); + + // Clear approvals from the previous owner + delete _tokenApprovals[tokenId]; + + unchecked { + // `_balances[from]` cannot overflow for the same reason as described in `_burn`: + // `from`'s balance is the number of token held, which is at least one before the current + // transfer. + // `_balances[to]` could overflow in the conditions described in `_mint`. That would require + // all 2**256 token ids to be minted, which in practice is impossible. + _balances[from] -= 1; + _balances[to] += 1; + } + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + + _afterTokenTransfer(from, to, tokenId, 1); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits an {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + require(owner != operator, "ERC721: approve to caller"); + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Reverts if the `tokenId` has not been minted yet. + */ + function _requireMinted(uint256 tokenId) internal view virtual { + require(_exists(tokenId), "ERC721: invalid token ID"); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory data + ) private returns (bool) { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { + return retval == IERC721Receiver.onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is + * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. + * - When `from` is zero, the tokens will be minted for `to`. + * - When `to` is zero, ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * - `batchSize` is non-zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 /* firstTokenId */, + uint256 batchSize + ) internal virtual { + if (batchSize > 1) { + if (from != address(0)) { + _balances[from] -= batchSize; + } + if (to != address(0)) { + _balances[to] += batchSize; + } + } + } + + /** + * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is + * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. + * - When `from` is zero, the tokens were minted for `to`. + * - When `to` is zero, ``from``'s tokens were burned. + * - `from` and `to` are never both zero. + * - `batchSize` is non-zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol new file mode 100644 index 0000000..7b60a9f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/IERC721.sol) + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol new file mode 100644 index 0000000..de67209 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc new file mode 100644 index 0000000..f571f5c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc @@ -0,0 +1,73 @@ += ERC 721 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc721 + +This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-721[ERC721 Non-Fungible Token Standard]. + +TIP: For a walk through on how to create an ERC721 token read our xref:ROOT:erc721.adoc[ERC721 guide]. + +The EIP specifies four interfaces: + +* {IERC721}: Core functionality required in all compliant implementation. +* {IERC721Metadata}: Optional extension that adds name, symbol, and token URI, almost always included. +* {IERC721Enumerable}: Optional extension that allows enumerating the tokens on chain, often not included since it requires large gas overhead. +* {IERC721Receiver}: An interface that must be implemented by contracts if they want to accept tokens through `safeTransferFrom`. + +OpenZeppelin Contracts provides implementations of all four interfaces: + +* {ERC721}: The core and metadata extensions, with a base URI mechanism. +* {ERC721Enumerable}: The enumerable extension. +* {ERC721Holder}: A bare bones implementation of the receiver interface. + +Additionally there are a few of other extensions: + +* {ERC721Consecutive}: An implementation of https://eips.ethereum.org/EIPS/eip-2309[ERC2309] for minting batchs of tokens during construction, in accordance with ERC721. +* {ERC721URIStorage}: A more flexible but more expensive way of storing metadata. +* {ERC721Votes}: Support for voting and vote delegation. +* {ERC721Royalty}: A way to signal royalty information following ERC2981. +* {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. + +== Core + +{{IERC721}} + +{{IERC721Metadata}} + +{{IERC721Enumerable}} + +{{ERC721}} + +{{ERC721Enumerable}} + +{{IERC721Receiver}} + +== Extensions + +{{ERC721Pausable}} + +{{ERC721Burnable}} + +{{ERC721Consecutive}} + +{{ERC721URIStorage}} + +{{ERC721Votes}} + +{{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. + +{{ERC721PresetMinterPauserAutoId}} + +== Utilities + +{{ERC721Holder}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol new file mode 100644 index 0000000..0dc7dae --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Burnable.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../utils/Context.sol"; + +/** + * @title ERC721 Burnable Token + * @dev ERC721 Token that can be burned (destroyed). + */ +abstract contract ERC721Burnable is Context, ERC721 { + /** + * @dev Burns `tokenId`. See {ERC721-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) public virtual { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); + _burn(tokenId); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol new file mode 100644 index 0000000..e6843f1 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Consecutive.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../interfaces/IERC2309.sol"; +import "../../../utils/Checkpoints.sol"; +import "../../../utils/structs/BitMaps.sol"; + +/** + * @dev Implementation of the ERC2309 "Consecutive Transfer Extension" as defined in + * https://eips.ethereum.org/EIPS/eip-2309[EIP-2309]. + * + * This extension allows the minting of large batches of tokens, during contract construction only. For upgradeable + * contracts this implies that batch minting is only available during proxy deployment, and not in subsequent upgrades. + * These batches are limited to 5000 tokens at a time by default to accommodate off-chain indexers. + * + * Using this extension removes the ability to mint single tokens during contract construction. This ability is + * regained after construction. During construction, only batch minting is allowed. + * + * IMPORTANT: This extension bypasses the hooks {_beforeTokenTransfer} and {_afterTokenTransfer} for tokens minted in + * batch. When using this extension, you should consider the {_beforeConsecutiveTokenTransfer} and + * {_afterConsecutiveTokenTransfer} hooks in addition to {_beforeTokenTransfer} and {_afterTokenTransfer}. + * + * IMPORTANT: When overriding {_afterTokenTransfer}, be careful about call ordering. {ownerOf} may return invalid + * values during the {_afterTokenTransfer} execution if the super call is not called first. To be safe, execute the + * super call before your custom logic. + * + * _Available since v4.8._ + */ +abstract contract ERC721Consecutive is IERC2309, ERC721 { + using BitMaps for BitMaps.BitMap; + using Checkpoints for Checkpoints.Trace160; + + Checkpoints.Trace160 private _sequentialOwnership; + BitMaps.BitMap private _sequentialBurn; + + /** + * @dev Maximum size of a batch of consecutive tokens. This is designed to limit stress on off-chain indexing + * services that have to record one entry per token, and have protections against "unreasonably large" batches of + * tokens. + * + * NOTE: Overriding the default value of 5000 will not cause on-chain issues, but may result in the asset not being + * correctly supported by off-chain indexing services (including marketplaces). + */ + function _maxBatchSize() internal view virtual returns (uint96) { + return 5000; + } + + /** + * @dev See {ERC721-_ownerOf}. Override that checks the sequential ownership structure for tokens that have + * been minted as part of a batch, and not yet transferred. + */ + function _ownerOf(uint256 tokenId) internal view virtual override returns (address) { + address owner = super._ownerOf(tokenId); + + // If token is owned by the core, or beyond consecutive range, return base value + if (owner != address(0) || tokenId > type(uint96).max) { + return owner; + } + + // Otherwise, check the token was not burned, and fetch ownership from the anchors + // Note: no need for safe cast, we know that tokenId <= type(uint96).max + return _sequentialBurn.get(tokenId) ? address(0) : address(_sequentialOwnership.lowerLookup(uint96(tokenId))); + } + + /** + * @dev Mint a batch of tokens of length `batchSize` for `to`. Returns the token id of the first token minted in the + * batch; if `batchSize` is 0, returns the number of consecutive ids minted so far. + * + * Requirements: + * + * - `batchSize` must not be greater than {_maxBatchSize}. + * - The function is called in the constructor of the contract (directly or indirectly). + * + * CAUTION: Does not emit a `Transfer` event. This is ERC721 compliant as long as it is done inside of the + * constructor, which is enforced by this function. + * + * CAUTION: Does not invoke `onERC721Received` on the receiver. + * + * Emits a {IERC2309-ConsecutiveTransfer} event. + */ + function _mintConsecutive(address to, uint96 batchSize) internal virtual returns (uint96) { + uint96 first = _totalConsecutiveSupply(); + + // minting a batch of size 0 is a no-op + if (batchSize > 0) { + require(!Address.isContract(address(this)), "ERC721Consecutive: batch minting restricted to constructor"); + require(to != address(0), "ERC721Consecutive: mint to the zero address"); + require(batchSize <= _maxBatchSize(), "ERC721Consecutive: batch too large"); + + // hook before + _beforeTokenTransfer(address(0), to, first, batchSize); + + // push an ownership checkpoint & emit event + uint96 last = first + batchSize - 1; + _sequentialOwnership.push(last, uint160(to)); + emit ConsecutiveTransfer(first, last, address(0), to); + + // hook after + _afterTokenTransfer(address(0), to, first, batchSize); + } + + return first; + } + + /** + * @dev See {ERC721-_mint}. Override version that restricts normal minting to after construction. + * + * Warning: Using {ERC721Consecutive} prevents using {_mint} during construction in favor of {_mintConsecutive}. + * After construction, {_mintConsecutive} is no longer available and {_mint} becomes available. + */ + function _mint(address to, uint256 tokenId) internal virtual override { + require(Address.isContract(address(this)), "ERC721Consecutive: can't mint during construction"); + super._mint(to, tokenId); + } + + /** + * @dev See {ERC721-_afterTokenTransfer}. Burning of tokens that have been sequentially minted must be explicit. + */ + function _afterTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override { + if ( + to == address(0) && // if we burn + firstTokenId < _totalConsecutiveSupply() && // and the tokenId was minted in a batch + !_sequentialBurn.get(firstTokenId) // and the token was never marked as burnt + ) { + require(batchSize == 1, "ERC721Consecutive: batch burn not supported"); + _sequentialBurn.set(firstTokenId); + } + super._afterTokenTransfer(from, to, firstTokenId, batchSize); + } + + function _totalConsecutiveSupply() private view returns (uint96) { + (bool exists, uint96 latestId, ) = _sequentialOwnership.latestCheckpoint(); + return exists ? latestId + 1 : 0; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol new file mode 100644 index 0000000..aab81a9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "./IERC721Enumerable.sol"; + +/** + * @dev This implements an optional extension of {ERC721} defined in the EIP that adds + * enumerability of all the token ids in the contract as well as all token ids owned by each + * account. + */ +abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { + // Mapping from owner to list of owned token IDs + mapping(address => mapping(uint256 => uint256)) private _ownedTokens; + + // Mapping from token ID to index of the owner tokens list + mapping(uint256 => uint256) private _ownedTokensIndex; + + // Array with all token ids, used for enumeration + uint256[] private _allTokens; + + // Mapping from token id to position in the allTokens array + mapping(uint256 => uint256) private _allTokensIndex; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { + require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); + return _ownedTokens[owner][index]; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _allTokens.length; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual override returns (uint256) { + require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); + return _allTokens[index]; + } + + /** + * @dev See {ERC721-_beforeTokenTransfer}. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + + if (batchSize > 1) { + // Will only trigger during construction. Batch transferring (minting) is not available afterwards. + revert("ERC721Enumerable: consecutive transfers not supported"); + } + + uint256 tokenId = firstTokenId; + + if (from == address(0)) { + _addTokenToAllTokensEnumeration(tokenId); + } else if (from != to) { + _removeTokenFromOwnerEnumeration(from, tokenId); + } + if (to == address(0)) { + _removeTokenFromAllTokensEnumeration(tokenId); + } else if (to != from) { + _addTokenToOwnerEnumeration(to, tokenId); + } + } + + /** + * @dev Private function to add a token to this extension's ownership-tracking data structures. + * @param to address representing the new owner of the given token ID + * @param tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + uint256 length = ERC721.balanceOf(to); + _ownedTokens[to][length] = tokenId; + _ownedTokensIndex[tokenId] = length; + } + + /** + * @dev Private function to add a token to this extension's token tracking data structures. + * @param tokenId uint256 ID of the token to be added to the tokens list + */ + function _addTokenToAllTokensEnumeration(uint256 tokenId) private { + _allTokensIndex[tokenId] = _allTokens.length; + _allTokens.push(tokenId); + } + + /** + * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that + * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for + * gas optimizations e.g. when performing a transfer operation (avoiding double writes). + * This has O(1) time complexity, but alters the order of the _ownedTokens array. + * @param from address representing the previous owner of the given token ID + * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { + // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; + uint256 tokenIndex = _ownedTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + + _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + } + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[tokenId]; + delete _ownedTokens[from][lastTokenIndex]; + } + + /** + * @dev Private function to remove a token from this extension's token tracking data structures. + * This has O(1) time complexity, but alters the order of the _allTokens array. + * @param tokenId uint256 ID of the token to be removed from the tokens list + */ + function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { + // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = _allTokens.length - 1; + uint256 tokenIndex = _allTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so + // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding + // an 'if' statement (like in _removeTokenFromOwnerEnumeration) + uint256 lastTokenId = _allTokens[lastTokenIndex]; + + _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + + // This also deletes the contents at the last position of the array + delete _allTokensIndex[tokenId]; + _allTokens.pop(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol new file mode 100644 index 0000000..cdd729b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Pausable.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../security/Pausable.sol"; + +/** + * @dev ERC721 token with pausable token transfers, minting and burning. + * + * 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 { + /** + * @dev See {ERC721-_beforeTokenTransfer}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + + require(!paused(), "ERC721Pausable: token transfer while paused"); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol new file mode 100644 index 0000000..298e342 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Royalty.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../common/ERC2981.sol"; +import "../../../utils/introspection/ERC165.sol"; + +/** + * @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment + * information. + * + * Royalty information can be specified globally for all token ids via {ERC2981-_setDefaultRoyalty}, and/or individually for + * specific token ids via {ERC2981-_setTokenRoyalty}. The latter takes precedence over the first. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + * + * _Available since v4.5._ + */ +abstract contract ERC721Royalty is ERC2981, ERC721 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) { + return super.supportsInterface(interfaceId); + } + + /** + * @dev See {ERC721-_burn}. This override additionally clears the royalty information for the token. + */ + function _burn(uint256 tokenId) internal virtual override { + super._burn(tokenId); + _resetTokenRoyalty(tokenId); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol new file mode 100644 index 0000000..201b05a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721URIStorage.sol) + +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 IERC4906, ERC721 { + using Strings for uint256; + + // 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}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + _requireMinted(tokenId); + + string memory _tokenURI = _tokenURIs[tokenId]; + string memory base = _baseURI(); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). + if (bytes(_tokenURI).length > 0) { + return string(abi.encodePacked(base, _tokenURI)); + } + + return super.tokenURI(tokenId); + } + + /** + * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. + * + * Emits {MetadataUpdate}. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { + require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token"); + _tokenURIs[tokenId] = _tokenURI; + + emit MetadataUpdate(tokenId); + } + + /** + * @dev See {ERC721-_burn}. This override additionally checks to see if a + * token-specific URI was set for the token, and if so, it deletes the token URI from + * the storage mapping. + */ + function _burn(uint256 tokenId) internal virtual override { + super._burn(tokenId); + + if (bytes(_tokenURIs[tokenId]).length != 0) { + delete _tokenURIs[tokenId]; + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol new file mode 100644 index 0000000..8e6500e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Votes.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../governance/utils/Votes.sol"; + +/** + * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts + * as 1 vote unit. + * + * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost + * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of + * the votes in governance decisions, or they can delegate to themselves to be their own representative. + * + * _Available since v4.5._ + */ +abstract contract ERC721Votes is ERC721, Votes { + /** + * @dev See {ERC721-_afterTokenTransfer}. Adjusts votes when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _afterTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override { + _transferVotingUnits(from, to, batchSize); + super._afterTokenTransfer(from, to, firstTokenId, batchSize); + } + + /** + * @dev Returns the balance of `account`. + */ + function _getVotingUnits(address account) internal view virtual override returns (uint256) { + return balanceOf(account); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol new file mode 100644 index 0000000..83e59ce --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC721.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, IERC721Receiver { + IERC721 private immutable _underlying; + + 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) { + uint256 length = tokenIds.length; + for (uint256 i = 0; i < length; ++i) { + 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; + } + + /** + * @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 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 from, + uint256 tokenId, + bytes memory + ) public virtual override returns (bytes4) { + require(address(underlying()) == _msgSender(), "ERC721Wrapper: caller is not underlying"); + _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/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol new file mode 100644 index 0000000..dfea427 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol new file mode 100644 index 0000000..dca77ba --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/draft-ERC721Votes.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/draft-ERC721Votes.sol new file mode 100644 index 0000000..c6aa7c5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/draft-ERC721Votes.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/draft-ERC721Votes.sol) + +pragma solidity ^0.8.0; + +// ERC721Votes was marked as draft due to the EIP-712 dependency. +// EIP-712 is Final as of 2022-08-11. This file is deprecated. + +import "./ERC721Votes.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol new file mode 100644 index 0000000..478e580 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../extensions/ERC721Enumerable.sol"; +import "../extensions/ERC721Burnable.sol"; +import "../extensions/ERC721Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; +import "../../../utils/Counters.sol"; + +/** + * @dev {ERC721} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * - token ID and URI autogeneration + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC721PresetMinterPauserAutoId is + Context, + AccessControlEnumerable, + ERC721Enumerable, + ERC721Burnable, + ERC721Pausable +{ + using Counters for Counters.Counter; + + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + Counters.Counter private _tokenIdTracker; + + string private _baseTokenURI; + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the + * account that deploys the contract. + * + * Token URIs will be autogenerated based on `baseURI` and their token IDs. + * See {ERC721-tokenURI}. + */ + constructor(string memory name, string memory symbol, string memory baseTokenURI) ERC721(name, symbol) { + _baseTokenURI = baseTokenURI; + + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _setupRole(MINTER_ROLE, _msgSender()); + _setupRole(PAUSER_ROLE, _msgSender()); + } + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + /** + * @dev Creates a new token for `to`. Its token ID will be automatically + * assigned (and available on the emitted {IERC721-Transfer} event), and the token + * URI autogenerated based on the base URI passed at construction. + * + * See {ERC721-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have minter role to mint"); + + // We cannot just use balanceOf to create the new tokenId because tokens + // can be burned (destroyed), so we need a separate counter. + _mint(to, _tokenIdTracker.current()); + _tokenIdTracker.increment(); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC721Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC721Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to unpause"); + _unpause(); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Enumerable, ERC721Pausable) { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(AccessControlEnumerable, ERC721, ERC721Enumerable) returns (bool) { + return super.supportsInterface(interfaceId); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/presets/README.md b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/presets/README.md new file mode 100644 index 0000000..468200b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/presets/README.md @@ -0,0 +1 @@ +Contract presets are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com/) as a more powerful alternative. diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol new file mode 100644 index 0000000..cfa533a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/utils/ERC721Holder.sol) + +pragma solidity ^0.8.0; + +import "../IERC721Receiver.sol"; + +/** + * @dev Implementation of the {IERC721Receiver} interface. + * + * Accepts all token transfers. + * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. + */ +contract ERC721Holder is IERC721Receiver { + /** + * @dev See {IERC721Receiver-onERC721Received}. + * + * Always returns `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { + return this.onERC721Received.selector; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/ERC777.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/ERC777.sol new file mode 100644 index 0000000..c1503c4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/ERC777.sol @@ -0,0 +1,512 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC777/ERC777.sol) + +pragma solidity ^0.8.0; + +import "./IERC777.sol"; +import "./IERC777Recipient.sol"; +import "./IERC777Sender.sol"; +import "../ERC20/IERC20.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/introspection/IERC1820Registry.sol"; + +/** + * @dev Implementation of the {IERC777} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * + * Support for ERC20 is included in this contract, as specified by the EIP: both + * the ERC777 and ERC20 interfaces can be safely used when interacting with it. + * Both {IERC777-Sent} and {IERC20-Transfer} events are emitted on token + * movements. + * + * 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. + */ +contract ERC777 is Context, IERC777, IERC20 { + using Address for address; + + IERC1820Registry internal constant _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); + + mapping(address => uint256) private _balances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + bytes32 private constant _TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); + bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); + + // This isn't ever read from - it's only used to respond to the defaultOperators query. + address[] private _defaultOperatorsArray; + + // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators). + mapping(address => bool) private _defaultOperators; + + // For each account, a mapping of its operators and revoked default operators. + mapping(address => mapping(address => bool)) private _operators; + mapping(address => mapping(address => bool)) private _revokedDefaultOperators; + + // ERC20-allowances + mapping(address => mapping(address => uint256)) private _allowances; + + /** + * @dev `defaultOperators` may be an empty array. + */ + constructor(string memory name_, string memory symbol_, address[] memory defaultOperators_) { + _name = name_; + _symbol = symbol_; + + _defaultOperatorsArray = defaultOperators_; + for (uint256 i = 0; i < defaultOperators_.length; i++) { + _defaultOperators[defaultOperators_[i]] = true; + } + + // register interfaces + _ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); + _ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC20Token"), address(this)); + } + + /** + * @dev See {IERC777-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC777-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {ERC20-decimals}. + * + * Always returns 18, as per the + * [ERC777 EIP](https://eips.ethereum.org/EIPS/eip-777#backward-compatibility). + */ + function decimals() public pure virtual returns (uint8) { + return 18; + } + + /** + * @dev See {IERC777-granularity}. + * + * This implementation always returns `1`. + */ + function granularity() public view virtual override returns (uint256) { + return 1; + } + + /** + * @dev See {IERC777-totalSupply}. + */ + function totalSupply() public view virtual override(IERC20, IERC777) returns (uint256) { + return _totalSupply; + } + + /** + * @dev Returns the amount of tokens owned by an account (`tokenHolder`). + */ + function balanceOf(address tokenHolder) public view virtual override(IERC20, IERC777) returns (uint256) { + return _balances[tokenHolder]; + } + + /** + * @dev See {IERC777-send}. + * + * Also emits a {IERC20-Transfer} event for ERC20 compatibility. + */ + function send(address recipient, uint256 amount, bytes memory data) public virtual override { + _send(_msgSender(), recipient, amount, data, "", true); + } + + /** + * @dev See {IERC20-transfer}. + * + * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient} + * interface if it is a contract. + * + * Also emits a {Sent} event. + */ + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { + _send(_msgSender(), recipient, amount, "", "", false); + return true; + } + + /** + * @dev See {IERC777-burn}. + * + * Also emits a {IERC20-Transfer} event for ERC20 compatibility. + */ + function burn(uint256 amount, bytes memory data) public virtual override { + _burn(_msgSender(), amount, data, ""); + } + + /** + * @dev See {IERC777-isOperatorFor}. + */ + function isOperatorFor(address operator, address tokenHolder) public view virtual override returns (bool) { + return + operator == tokenHolder || + (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) || + _operators[tokenHolder][operator]; + } + + /** + * @dev See {IERC777-authorizeOperator}. + */ + function authorizeOperator(address operator) public virtual override { + require(_msgSender() != operator, "ERC777: authorizing self as operator"); + + if (_defaultOperators[operator]) { + delete _revokedDefaultOperators[_msgSender()][operator]; + } else { + _operators[_msgSender()][operator] = true; + } + + emit AuthorizedOperator(operator, _msgSender()); + } + + /** + * @dev See {IERC777-revokeOperator}. + */ + function revokeOperator(address operator) public virtual override { + require(operator != _msgSender(), "ERC777: revoking self as operator"); + + if (_defaultOperators[operator]) { + _revokedDefaultOperators[_msgSender()][operator] = true; + } else { + delete _operators[_msgSender()][operator]; + } + + emit RevokedOperator(operator, _msgSender()); + } + + /** + * @dev See {IERC777-defaultOperators}. + */ + function defaultOperators() public view virtual override returns (address[] memory) { + return _defaultOperatorsArray; + } + + /** + * @dev See {IERC777-operatorSend}. + * + * Emits {Sent} and {IERC20-Transfer} events. + */ + function operatorSend( + address sender, + address recipient, + uint256 amount, + bytes memory data, + bytes memory operatorData + ) public virtual override { + require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder"); + _send(sender, recipient, amount, data, operatorData, true); + } + + /** + * @dev See {IERC777-operatorBurn}. + * + * Emits {Burned} and {IERC20-Transfer} events. + */ + function operatorBurn( + address account, + uint256 amount, + bytes memory data, + bytes memory operatorData + ) public virtual override { + require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder"); + _burn(account, amount, data, operatorData); + } + + /** + * @dev See {IERC20-allowance}. + * + * Note that operator and allowance concepts are orthogonal: operators may + * not have allowance, and accounts with allowance may not be operators + * themselves. + */ + function allowance(address holder, address spender) public view virtual override returns (uint256) { + return _allowances[holder][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Note that accounts cannot have allowance issued by their operators. + */ + function approve(address spender, uint256 value) public virtual override returns (bool) { + address holder = _msgSender(); + _approve(holder, spender, value); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Note that operator and allowance concepts are orthogonal: operators cannot + * call `transferFrom` (unless they have allowance), and accounts with + * allowance cannot call `operatorSend` (unless they are operators). + * + * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events. + */ + function transferFrom(address holder, address recipient, uint256 amount) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(holder, spender, amount); + _send(holder, recipient, amount, "", "", false); + return true; + } + + /** + * @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * If a send hook is registered for `account`, the corresponding function + * will be called with the caller address as the `operator` and with + * `userData` and `operatorData`. + * + * See {IERC777Sender} and {IERC777Recipient}. + * + * Emits {Minted} and {IERC20-Transfer} events. + * + * Requirements + * + * - `account` cannot be the zero address. + * - if `account` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function _mint(address account, uint256 amount, bytes memory userData, bytes memory operatorData) internal virtual { + _mint(account, amount, userData, operatorData, true); + } + + /** + * @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * If `requireReceptionAck` is set to true, and if a send hook is + * registered for `account`, the corresponding function will be called with + * `operator`, `data` and `operatorData`. + * + * See {IERC777Sender} and {IERC777Recipient}. + * + * Emits {Minted} and {IERC20-Transfer} events. + * + * Requirements + * + * - `account` cannot be the zero address. + * - if `account` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function _mint( + address account, + uint256 amount, + bytes memory userData, + bytes memory operatorData, + bool requireReceptionAck + ) internal virtual { + require(account != address(0), "ERC777: mint to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), account, amount); + + // Update state variables + _totalSupply += amount; + _balances[account] += amount; + + _callTokensReceived(operator, address(0), account, amount, userData, operatorData, requireReceptionAck); + + emit Minted(operator, account, amount, userData, operatorData); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Send tokens + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient + */ + function _send( + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData, + bool requireReceptionAck + ) internal virtual { + require(from != address(0), "ERC777: transfer from the zero address"); + require(to != address(0), "ERC777: transfer to the zero address"); + + address operator = _msgSender(); + + _callTokensToSend(operator, from, to, amount, userData, operatorData); + + _move(operator, from, to, amount, userData, operatorData); + + _callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck); + } + + /** + * @dev Burn tokens + * @param from address token holder address + * @param amount uint256 amount of tokens to burn + * @param data bytes extra information provided by the token holder + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _burn(address from, uint256 amount, bytes memory data, bytes memory operatorData) internal virtual { + require(from != address(0), "ERC777: burn from the zero address"); + + address operator = _msgSender(); + + _callTokensToSend(operator, from, address(0), amount, data, operatorData); + + _beforeTokenTransfer(operator, from, address(0), amount); + + // Update state variables + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC777: burn amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + } + _totalSupply -= amount; + + emit Burned(operator, from, amount, data, operatorData); + emit Transfer(from, address(0), amount); + } + + function _move( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) private { + _beforeTokenTransfer(operator, from, to, amount); + + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC777: transfer amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + } + _balances[to] += amount; + + emit Sent(operator, from, to, amount, userData, operatorData); + emit Transfer(from, to, amount); + } + + /** + * @dev See {ERC20-_approve}. + * + * Note that accounts cannot have allowance issued by their operators. + */ + function _approve(address holder, address spender, uint256 value) internal virtual { + require(holder != address(0), "ERC777: approve from the zero address"); + require(spender != address(0), "ERC777: approve to the zero address"); + + _allowances[holder][spender] = value; + emit Approval(holder, spender, value); + } + + /** + * @dev Call from.tokensToSend() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _callTokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) private { + address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(from, _TOKENS_SENDER_INTERFACE_HASH); + if (implementer != address(0)) { + IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); + } + } + + /** + * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but + * tokensReceived() was not registered for the recipient + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient + */ + function _callTokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData, + bool requireReceptionAck + ) private { + address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(to, _TOKENS_RECIPIENT_INTERFACE_HASH); + if (implementer != address(0)) { + IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); + } else if (requireReceptionAck) { + require(!to.isContract(), "ERC777: token recipient contract has no implementer for ERC777TokensRecipient"); + } + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * + * Does not update the allowance amount in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Might emit an {IERC20-Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC777: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount); + } + } + } + + /** + * @dev Hook that is called before any token transfer. This includes + * calls to {send}, {transfer}, {operatorSend}, minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address operator, address from, address to, uint256 amount) internal virtual {} +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777.sol new file mode 100644 index 0000000..d3bede6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC777/IERC777.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC777Token standard as defined in the EIP. + * + * This contract uses the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let + * token holders and recipients react to token movements by using setting implementers + * for the associated interfaces in said registry. See {IERC1820Registry} and + * {ERC1820Implementer}. + */ +interface IERC777 { + /** + * @dev Emitted when `amount` tokens are created by `operator` and assigned to `to`. + * + * Note that some additional user `data` and `operatorData` can be logged in the event. + */ + event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); + + /** + * @dev Emitted when `operator` destroys `amount` tokens from `account`. + * + * Note that some additional user `data` and `operatorData` can be logged in the event. + */ + event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); + + /** + * @dev Emitted when `operator` is made operator for `tokenHolder`. + */ + event AuthorizedOperator(address indexed operator, address indexed tokenHolder); + + /** + * @dev Emitted when `operator` is revoked its operator status for `tokenHolder`. + */ + event RevokedOperator(address indexed operator, address indexed tokenHolder); + + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the smallest part of the token that is not divisible. This + * means all token operations (creation, movement and destruction) must have + * amounts that are a multiple of this number. + * + * For most token contracts, this value will equal 1. + */ + function granularity() external view returns (uint256); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by an account (`owner`). + */ + function balanceOf(address owner) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * If send or receive hooks are registered for the caller and `recipient`, + * the corresponding functions will be called with `data` and empty + * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. + * + * Emits a {Sent} event. + * + * Requirements + * + * - the caller must have at least `amount` tokens. + * - `recipient` cannot be the zero address. + * - if `recipient` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function send(address recipient, uint256 amount, bytes calldata data) external; + + /** + * @dev Destroys `amount` tokens from the caller's account, reducing the + * total supply. + * + * If a send hook is registered for the caller, the corresponding function + * will be called with `data` and empty `operatorData`. See {IERC777Sender}. + * + * Emits a {Burned} event. + * + * Requirements + * + * - the caller must have at least `amount` tokens. + */ + function burn(uint256 amount, bytes calldata data) external; + + /** + * @dev Returns true if an account is an operator of `tokenHolder`. + * Operators can send and burn tokens on behalf of their owners. All + * accounts are their own operator. + * + * See {operatorSend} and {operatorBurn}. + */ + function isOperatorFor(address operator, address tokenHolder) external view returns (bool); + + /** + * @dev Make an account an operator of the caller. + * + * See {isOperatorFor}. + * + * Emits an {AuthorizedOperator} event. + * + * Requirements + * + * - `operator` cannot be calling address. + */ + function authorizeOperator(address operator) external; + + /** + * @dev Revoke an account's operator status for the caller. + * + * See {isOperatorFor} and {defaultOperators}. + * + * Emits a {RevokedOperator} event. + * + * Requirements + * + * - `operator` cannot be calling address. + */ + function revokeOperator(address operator) external; + + /** + * @dev Returns the list of default operators. These accounts are operators + * for all token holders, even if {authorizeOperator} was never called on + * them. + * + * This list is immutable, but individual holders may revoke these via + * {revokeOperator}, in which case {isOperatorFor} will return false. + */ + function defaultOperators() external view returns (address[] memory); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must + * be an operator of `sender`. + * + * If send or receive hooks are registered for `sender` and `recipient`, + * the corresponding functions will be called with `data` and + * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. + * + * Emits a {Sent} event. + * + * Requirements + * + * - `sender` cannot be the zero address. + * - `sender` must have at least `amount` tokens. + * - the caller must be an operator for `sender`. + * - `recipient` cannot be the zero address. + * - if `recipient` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function operatorSend( + address sender, + address recipient, + uint256 amount, + bytes calldata data, + bytes calldata operatorData + ) external; + + /** + * @dev Destroys `amount` tokens from `account`, reducing the total supply. + * The caller must be an operator of `account`. + * + * If a send hook is registered for `account`, the corresponding function + * will be called with `data` and `operatorData`. See {IERC777Sender}. + * + * Emits a {Burned} event. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + * - the caller must be an operator for `account`. + */ + function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external; + + event Sent( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777Recipient.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777Recipient.sol new file mode 100644 index 0000000..717dd8f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777Recipient.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Recipient.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. + * + * Accounts can be notified of {IERC777} tokens being sent to them by having a + * contract implement this interface (contract holders can be their own + * implementer) and registering it on the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. + * + * See {IERC1820Registry} and {ERC1820Implementer}. + */ +interface IERC777Recipient { + /** + * @dev Called by an {IERC777} token contract whenever tokens are being + * moved or created into a registered account (`to`). The type of operation + * is conveyed by `from` being the zero address or not. + * + * This call occurs _after_ the token contract's state is updated, so + * {IERC777-balanceOf}, etc., can be used to query the post-operation state. + * + * This function may revert to prevent the operation from being executed. + */ + function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777Sender.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777Sender.sol new file mode 100644 index 0000000..969e3e3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/IERC777Sender.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Sender.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC777TokensSender standard as defined in the EIP. + * + * {IERC777} Token holders can be notified of operations performed on their + * tokens by having a contract implement this interface (contract holders can be + * their own implementer) and registering it on the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. + * + * See {IERC1820Registry} and {ERC1820Implementer}. + */ +interface IERC777Sender { + /** + * @dev Called by an {IERC777} token contract whenever a registered holder's + * (`from`) tokens are about to be moved or destroyed. The type of operation + * is conveyed by `to` being the zero address or not. + * + * This call occurs _before_ the token contract's state is updated, so + * {IERC777-balanceOf}, etc., can be used to query the pre-operation state. + * + * This function may revert to prevent the operation from being executed. + */ + function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/README.adoc new file mode 100644 index 0000000..5012a31 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/README.adoc @@ -0,0 +1,30 @@ += ERC 777 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc777 + +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]. + +The token behavior itself is implemented in the core contracts: {IERC777}, {ERC777}. + +Additionally there are interfaces used to develop contracts that react to token movements: {IERC777Sender}, {IERC777Recipient}. + +== Core + +{{IERC777}} + +{{ERC777}} + +== Hooks + +{{IERC777Sender}} + +{{IERC777Recipient}} + +== Presets + +These contracts are preconfigured combinations of features. They can be used through inheritance or as models to copy and paste their source code. + +{{ERC777PresetFixedSupply}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol new file mode 100644 index 0000000..8bd4b79 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC777/presets/ERC777PresetFixedSupply.sol) +pragma solidity ^0.8.0; + +import "../ERC777.sol"; + +/** + * @dev {ERC777} token, including: + * + * - Preminted initial supply + * - No access control mechanism (for minting/pausing) and hence no governance + * + * _Available since v3.4._ + */ +contract ERC777PresetFixedSupply is ERC777 { + /** + * @dev Mints `initialSupply` amount of token and transfers them to `owner`. + * + * See {ERC777-constructor}. + */ + constructor( + string memory name, + string memory symbol, + address[] memory defaultOperators, + uint256 initialSupply, + address owner + ) ERC777(name, symbol, defaultOperators) { + _mint(owner, initialSupply, "", ""); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol new file mode 100644 index 0000000..f49cc8d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol) + +pragma solidity ^0.8.0; + +import "../../interfaces/IERC2981.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. + * + * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for + * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. + * + * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the + * fee is specified in basis points by default. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + * + * _Available since v4.5._ + */ +abstract contract ERC2981 is IERC2981, ERC165 { + struct RoyaltyInfo { + address receiver; + uint96 royaltyFraction; + } + + RoyaltyInfo private _defaultRoyaltyInfo; + mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @inheritdoc IERC2981 + */ + function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual override returns (address, uint256) { + RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId]; + + if (royalty.receiver == address(0)) { + royalty = _defaultRoyaltyInfo; + } + + uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator(); + + return (royalty.receiver, royaltyAmount); + } + + /** + * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a + * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an + * override. + */ + function _feeDenominator() internal pure virtual returns (uint96) { + return 10000; + } + + /** + * @dev Sets the royalty information that all ids in this contract will default to. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: invalid receiver"); + + _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Removes default royalty information. + */ + function _deleteDefaultRoyalty() internal virtual { + delete _defaultRoyaltyInfo; + } + + /** + * @dev Sets the royalty information for a specific token id, overriding the global default. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: Invalid parameters"); + + _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Resets royalty information for the token id back to the global default. + */ + function _resetTokenRoyalty(uint256 tokenId) internal virtual { + delete _tokenRoyaltyInfo[tokenId]; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/token/common/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/token/common/README.adoc new file mode 100644 index 0000000..af61674 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/token/common/README.adoc @@ -0,0 +1,10 @@ += Common (Tokens) + +Functionality that is common to multiple token standards. + +* {ERC2981}: NFT Royalties compatible with both ERC721 and ERC1155. +** For ERC721 consider {ERC721Royalty} which clears the royalty information from storage on burn. + +== Contracts + +{{ERC2981}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Address.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Address.sol new file mode 100644 index 0000000..433a866 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Address.sol @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * + * Furthermore, `isContract` will also return true if the target contract within + * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, + * which only has an effect at the end of a transaction. + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/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"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling + * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. + * + * _Available since v4.8._ + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + // only check isContract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + /** + * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason or using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert(bytes memory returndata, string memory errorMessage) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Arrays.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Arrays.sol new file mode 100644 index 0000000..2496475 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Arrays.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/Arrays.sol) + +pragma solidity ^0.8.0; + +import "./StorageSlot.sol"; +import "./math/Math.sol"; + +/** + * @dev Collection of functions related to array types. + */ +library Arrays { + using StorageSlot for bytes32; + + /** + * @dev Searches a sorted `array` and returns the first index that contains + * a value greater or equal to `element`. If no such index exists (i.e. all + * values in the array are strictly less than `element`), the array length is + * returned. Time complexity O(log n). + * + * `array` is expected to be sorted in ascending order, and to contain no + * repeated elements. + */ + function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { + if (array.length == 0) { + return 0; + } + + uint256 low = 0; + uint256 high = array.length; + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds down (it does integer division with truncation). + if (unsafeAccess(array, mid).value > element) { + high = mid; + } else { + low = mid + 1; + } + } + + // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. + if (low > 0 && unsafeAccess(array, low - 1).value == element) { + return low - 1; + } else { + return low; + } + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getAddressSlot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getBytes32Slot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getUint256Slot(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Base64.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Base64.sol new file mode 100644 index 0000000..4e08cd5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Base64.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + /// @solidity memory-safe-assembly + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Checkpoints.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Checkpoints.sol new file mode 100644 index 0000000..025b13d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Checkpoints.sol @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/Checkpoints.sol) +// This file was procedurally generated from scripts/generate/templates/Checkpoints.js. + +pragma solidity ^0.8.0; + +import "./math/Math.sol"; +import "./math/SafeCast.sol"; + +/** + * @dev This library defines the `History` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + * + * _Available since v4.5._ + */ +library Checkpoints { + struct History { + Checkpoint[] _checkpoints; + } + + struct Checkpoint { + uint32 _blockNumber; + uint224 _value; + } + + /** + * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one + * before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the + * block, the requested block number must be in the past, excluding the current block. + */ + function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) { + require(blockNumber < block.number, "Checkpoints: block not yet mined"); + uint32 key = SafeCast.toUint32(blockNumber); + + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one + * before it is returned, or zero otherwise. Similar to {upperLookup} but optimized for the case when the searched + * checkpoint is probably "recent", defined as being among the last sqrt(N) checkpoints where N is the number of + * checkpoints. + */ + function getAtProbablyRecentBlock(History storage self, uint256 blockNumber) internal view returns (uint256) { + require(blockNumber < block.number, "Checkpoints: block not yet mined"); + uint32 key = SafeCast.toUint32(blockNumber); + + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._blockNumber) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block. + * + * Returns previous value and new value. + */ + function push(History storage self, uint256 value) internal returns (uint256, uint256) { + return _insert(self._checkpoints, SafeCast.toUint32(block.number), SafeCast.toUint224(value)); + } + + /** + * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will + * be set to `op(latest, delta)`. + * + * Returns previous value and new value. + */ + function push( + History storage self, + function(uint256, uint256) view returns (uint256) op, + uint256 delta + ) internal returns (uint256, uint256) { + return push(self, op(latest(self), delta)); + } + + /** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ + function latest(History storage self) internal view returns (uint224) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint( + History storage self + ) internal view returns (bool exists, uint32 _blockNumber, uint224 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._blockNumber, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(History storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + require(last._blockNumber <= key, "Checkpoint: decreasing keys"); + + // Update or push new checkpoint + if (last._blockNumber == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint({_blockNumber: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint({_blockNumber: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none. + * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._blockNumber > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none. + * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._blockNumber < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace224 { + Checkpoint224[] _checkpoints; + } + + struct Checkpoint224 { + uint32 _key; + uint224 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + */ + function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none. + */ + function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + */ + function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint 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. + */ + function latest(Trace224 storage self) internal view returns (uint224) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace224 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint224 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + require(last._key <= key, "Checkpoint: decreasing keys"); + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint224({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint224({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none. + * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none. + * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint224[] storage self, + uint256 pos + ) private pure returns (Checkpoint224 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace160 { + Checkpoint160[] _checkpoints; + } + + struct Checkpoint160 { + uint96 _key; + uint160 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + */ + function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none. + */ + function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint with key lower or equal than the search key. + */ + function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the most recent checkpoint 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. + */ + function latest(Trace160 storage self) internal view returns (uint160) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace160 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint160 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + require(last._key <= key, "Checkpoint: decreasing keys"); + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint160({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint160({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or `high` if there is none. + * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _upperBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or `high` if there is none. + * `low` and `high` define a section where to do the search, with inclusive `low` and exclusive `high`. + * + * WARNING: `high` should not be greater than the array's length. + */ + function _lowerBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint160[] storage self, + uint256 pos + ) private pure returns (Checkpoint160 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Context.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Context.sol new file mode 100644 index 0000000..f304065 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Context.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Counters.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Counters.sol new file mode 100644 index 0000000..8a4f2a2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Counters.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) + +pragma solidity ^0.8.0; + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + */ +library Counters { + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + unchecked { + counter._value += 1; + } + } + + function decrement(Counter storage counter) internal { + uint256 value = counter._value; + require(value > 0, "Counter: decrement overflow"); + unchecked { + counter._value = value - 1; + } + } + + function reset(Counter storage counter) internal { + counter._value = 0; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Create2.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Create2.sol new file mode 100644 index 0000000..2255a4d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Create2.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/Create2.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. + * `CREATE2` can be used to compute in advance the address where a smart + * contract will be deployed, which allows for interesting new mechanisms known + * as 'counterfactual interactions'. + * + * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more + * information. + */ +library Create2 { + /** + * @dev Deploys a contract using `CREATE2`. The address where the contract + * will be deployed can be known in advance via {computeAddress}. + * + * The bytecode for a contract can be obtained from Solidity with + * `type(contractName).creationCode`. + * + * Requirements: + * + * - `bytecode` must not be empty. + * - `salt` must have not been used for `bytecode` already. + * - the factory must have a balance of at least `amount`. + * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. + */ + function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { + require(address(this).balance >= amount, "Create2: insufficient balance"); + require(bytecode.length != 0, "Create2: bytecode length is zero"); + /// @solidity memory-safe-assembly + assembly { + addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) + } + require(addr != address(0), "Create2: Failed on deploy"); + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the + * `bytecodeHash` or `salt` will result in a new destination address. + */ + function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { + return computeAddress(salt, bytecodeHash, address(this)); + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at + * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. + */ + function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) // Get free memory pointer + + // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | + // |-------------------|---------------------------------------------------------------------------| + // | bytecodeHash | CCCCCCCCCCCCC...CC | + // | salt | BBBBBBBBBBBBB...BB | + // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | + // | 0xFF | FF | + // |-------------------|---------------------------------------------------------------------------| + // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | + // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | + + mstore(add(ptr, 0x40), bytecodeHash) + mstore(add(ptr, 0x20), salt) + mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes + let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff + mstore8(start, 0xff) + addr := keccak256(start, 85) + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Multicall.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Multicall.sol new file mode 100644 index 0000000..7470c55 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Multicall.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (utils/Multicall.sol) + +pragma solidity ^0.8.0; + +import "./Address.sol"; + +/** + * @dev Provides a function to batch together multiple calls in a single external call. + * + * _Available since v4.1._ + */ +abstract contract Multicall { + /** + * @dev Receives and executes a batch of function calls on this contract. + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { + results = new bytes[](data.length); + for (uint256 i = 0; i < data.length; i++) { + results[i] = Address.functionDelegateCall(address(this), data[i]); + } + return results; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/README.adoc b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/README.adoc new file mode 100644 index 0000000..5e8af93 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/README.adoc @@ -0,0 +1,113 @@ += Utilities + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils + +Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives. + +The {Address}, {Arrays}, {Base64} and {Strings} libraries provide more operations related to these native data types, while {SafeCast} adds ways to safely convert between the different signed and unsigned numeric types. +{Multicall} provides a function to batch together multiple calls in a single external call. + +For new data types: + + * {Counters}: a simple way to get a counter that can only be incremented, decremented or reset. Very useful for ID generation, counting contract activity, among others. + * {EnumerableMap}: like Solidity's https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] type, but with key-value _enumeration_: this will let you know how many entries a mapping has, and iterate over them (which is not possible with `mapping`). + * {EnumerableSet}: like {EnumerableMap}, but for https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets]. Can be used to store privileged accounts, issued IDs, etc. + +[NOTE] +==== +Because Solidity does not support generic types, {EnumerableMap} and {EnumerableSet} are specialized to a limited number of key-value types. + +As of v3.0, {EnumerableMap} supports `uint256 -> address` (`UintToAddressMap`), and {EnumerableSet} supports `address` and `uint256` (`AddressSet` and `UintSet`). +==== + +Finally, {Create2} contains all necessary utilities to safely use the https://blog.openzeppelin.com/getting-the-most-out-of-create2/[`CREATE2` EVM opcode], without having to deal with low-level assembly. + +== Math + +{{Math}} + +{{SignedMath}} + +{{SafeCast}} + +{{SafeMath}} + +{{SignedSafeMath}} + +== Cryptography + +{{ECDSA}} + +{{SignatureChecker}} + +{{MerkleProof}} + +{{EIP712}} + +== Escrow + +{{ConditionalEscrow}} + +{{Escrow}} + +{{RefundEscrow}} + +== Introspection + +This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[type introspection] of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_. + +Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors. + +There are two main ways to approach this. + +* Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`. +* Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts. + +Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security. + +{{IERC165}} + +{{ERC165}} + +{{ERC165Storage}} + +{{ERC165Checker}} + +{{IERC1820Registry}} + +{{IERC1820Implementer}} + +{{ERC1820Implementer}} + +== Data Structures + +{{BitMaps}} + +{{EnumerableMap}} + +{{EnumerableSet}} + +{{DoubleEndedQueue}} + +{{Checkpoints}} + +== Libraries + +{{Create2}} + +{{Address}} + +{{Arrays}} + +{{Base64}} + +{{Counters}} + +{{Strings}} + +{{ShortStrings}} + +{{StorageSlot}} + +{{Multicall}} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol new file mode 100644 index 0000000..9f253df --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol new file mode 100644 index 0000000..44285c9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol @@ -0,0 +1,138 @@ +// 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; + +/** + * @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; + * } + * } + * ``` + * + * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ + * _Available since v4.9 for `string`, `bytes`._ + */ +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + struct StringSlot { + string value; + } + + struct BytesSlot { + bytes value; + } + + /** + * @dev Returns an `AddressSlot` with member `value` located at `slot`. + */ + function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + 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/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Strings.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Strings.sol new file mode 100644 index 0000000..3a037f4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Strings.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) + +pragma solidity ^0.8.0; + +import "./math/Math.sol"; +import "./math/SignedMath.sol"; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Timers.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Timers.sol new file mode 100644 index 0000000..1c92b02 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/Timers.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Timers.sol) + +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 { + uint64 _deadline; + } + + function getDeadline(Timestamp memory timer) internal pure returns (uint64) { + return timer._deadline; + } + + function setDeadline(Timestamp storage timer, uint64 timestamp) internal { + timer._deadline = timestamp; + } + + function reset(Timestamp storage timer) internal { + timer._deadline = 0; + } + + function isUnset(Timestamp memory timer) internal pure returns (bool) { + return timer._deadline == 0; + } + + function isStarted(Timestamp memory timer) internal pure returns (bool) { + return timer._deadline > 0; + } + + function isPending(Timestamp memory timer) internal view returns (bool) { + return timer._deadline > block.timestamp; + } + + function isExpired(Timestamp memory timer) internal view returns (bool) { + return isStarted(timer) && timer._deadline <= block.timestamp; + } + + struct BlockNumber { + uint64 _deadline; + } + + function getDeadline(BlockNumber memory timer) internal pure returns (uint64) { + return timer._deadline; + } + + function setDeadline(BlockNumber storage timer, uint64 timestamp) internal { + timer._deadline = timestamp; + } + + function reset(BlockNumber storage timer) internal { + timer._deadline = 0; + } + + function isUnset(BlockNumber memory timer) internal pure returns (bool) { + return timer._deadline == 0; + } + + function isStarted(BlockNumber memory timer) internal pure returns (bool) { + return timer._deadline > 0; + } + + function isPending(BlockNumber memory timer) internal view returns (bool) { + return timer._deadline > block.number; + } + + function isExpired(BlockNumber memory timer) internal view returns (bool) { + return isStarted(timer) && timer._deadline <= block.number; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol new file mode 100644 index 0000000..77279eb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol) + +pragma solidity ^0.8.0; + +import "../Strings.sol"; + +/** + * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. + * + * These functions can be used to verify that a message was signed by the holder + * of the private keys of a given address. + */ +library ECDSA { + enum RecoverError { + NoError, + InvalidSignature, + InvalidSignatureLength, + InvalidSignatureS, + InvalidSignatureV // Deprecated in v4.8 + } + + function _throwError(RecoverError error) private pure { + if (error == RecoverError.NoError) { + return; // no error: do nothing + } else if (error == RecoverError.InvalidSignature) { + revert("ECDSA: invalid signature"); + } else if (error == RecoverError.InvalidSignatureLength) { + revert("ECDSA: invalid signature length"); + } else if (error == RecoverError.InvalidSignatureS) { + revert("ECDSA: invalid signature 's' value"); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature` or error string. This address can then be used for verification purposes. + * + * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {toEthSignedMessageHash} on it. + * + * Documentation for signature generation: + * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] + * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] + * + * _Available since v4.3._ + */ + function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { + if (signature.length == 65) { + bytes32 r; + bytes32 s; + uint8 v; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + /// @solidity memory-safe-assembly + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + return tryRecover(hash, v, r, s); + } else { + return (address(0), RecoverError.InvalidSignatureLength); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature`. This address can then be used for verification purposes. + * + * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {toEthSignedMessageHash} on it. + */ + function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, signature); + _throwError(error); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. + * + * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] + * + * _Available since v4.3._ + */ + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { + bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + uint8 v = uint8((uint256(vs) >> 255) + 27); + return tryRecover(hash, v, r, s); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. + * + * _Available since v4.2._ + */ + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, r, vs); + _throwError(error); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `v`, + * `r` and `s` signature fields separately. + * + * _Available since v4.3._ + */ + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { + // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature + // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines + // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most + // signatures from current libraries generate a unique signature with an s-value in the lower half order. + // + // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value + // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or + // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept + // these malleable signatures as well. + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + return (address(0), RecoverError.InvalidSignatureS); + } + + // If the signature is valid (and not malleable), return the signer address + address signer = ecrecover(hash, v, r, s); + if (signer == address(0)) { + return (address(0), RecoverError.InvalidSignature); + } + + return (signer, RecoverError.NoError); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, v, r, s); + _throwError(error); + return recovered; + } + + /** + * @dev Returns an Ethereum Signed Message, created from a `hash`. This + * produces hash corresponding to the one signed with the + * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] + * JSON-RPC method as part of EIP-191. + * + * See {recover}. + */ + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { + // 32 is the length in bytes of hash, + // enforced by the type signature above + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, "\x19Ethereum Signed Message:\n32") + mstore(0x1c, hash) + message := keccak256(0x00, 0x3c) + } + } + + /** + * @dev Returns an Ethereum Signed Message, created from `s`. This + * produces hash corresponding to the one signed with the + * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] + * JSON-RPC method as part of EIP-191. + * + * See {recover}. + */ + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { + return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); + } + + /** + * @dev Returns an Ethereum Signed Typed Data, created from a + * `domainSeparator` and a `structHash`. This produces hash corresponding + * to the one signed with the + * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] + * JSON-RPC method as part of EIP-712. + * + * See {recover}. + */ + 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) + } + } + + /** + * @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/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol new file mode 100644 index 0000000..d0e52c3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol) + +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. + * + * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, + * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding + * they need in their contracts using a combination of `abi.encode` and `keccak256`. + * + * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding + * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA + * ({_hashTypedDataV4}). + * + * The implementation of the domain separator was designed to be as efficient as possible while still properly updating + * the chain id to protect against replay attacks on an eventual fork of the chain. + * + * 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 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 _cachedDomainSeparator; + uint256 private immutable _cachedChainId; + address private immutable _cachedThis; + + 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 */ + + /** + * @dev Initializes the domain separator and parameter caches. + * + * The meaning of `name` and `version` is specified in + * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: + * + * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. + * - `version`: the current major version of the signing domain. + * + * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart + * 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); + } + + /** + * @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(); + } + } + + function _buildDomainSeparator() private view returns (bytes32) { + return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); + } + + /** + * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this + * function returns the hash of the fully encoded EIP712 message for this domain. + * + * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: + * + * ```solidity + * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( + * keccak256("Mail(address to,string contents)"), + * mailTo, + * keccak256(bytes(mailContents)) + * ))); + * address signer = ECDSA.recover(digest, signature); + * ``` + */ + 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/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol new file mode 100644 index 0000000..3862fdb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.0; + +/** + * @dev These functions deal with verification of Merkle Tree proofs. + * + * The tree and the proofs can be generated using our + * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. + * You will find a quickstart guide in the readme. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + * OpenZeppelin's JavaScript library generates merkle trees that are safe + * against this attack out of the box. + */ +library MerkleProof { + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Calldata version of {verify} + * + * _Available since v4.7._ + */ + function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProofCalldata(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = _hashPair(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @dev Calldata version of {processProof} + * + * _Available since v4.7._ + */ + function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = _hashPair(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by + * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. + * + * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. + * + * _Available since v4.7._ + */ + function multiProofVerify( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProof(proof, proofFlags, leaves) == root; + } + + /** + * @dev Calldata version of {multiProofVerify} + * + * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. + * + * _Available since v4.7._ + */ + function multiProofVerifyCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProofCalldata(proof, proofFlags, leaves) == root; + } + + /** + * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction + * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another + * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false + * respectively. + * + * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree + * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the + * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). + * + * _Available since v4.7._ + */ + function processMultiProof( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32[] memory leaves + ) internal pure returns (bytes32 merkleRoot) { + // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by + // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the + // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of + // the merkle tree. + uint256 leavesLen = leaves.length; + uint256 totalHashes = proofFlags.length; + + // Check proof validity. + require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); + + // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using + // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". + bytes32[] memory hashes = new bytes32[](totalHashes); + uint256 leafPos = 0; + uint256 hashPos = 0; + uint256 proofPos = 0; + // At each step, we compute the next hash using two values: + // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we + // get the next hash. + // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the + // `proof` array. + for (uint256 i = 0; i < totalHashes; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = _hashPair(a, b); + } + + if (totalHashes > 0) { + unchecked { + return hashes[totalHashes - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @dev Calldata version of {processMultiProof}. + * + * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. + * + * _Available since v4.7._ + */ + function processMultiProofCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32[] memory leaves + ) internal pure returns (bytes32 merkleRoot) { + // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by + // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the + // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of + // the merkle tree. + uint256 leavesLen = leaves.length; + uint256 totalHashes = proofFlags.length; + + // Check proof validity. + require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof"); + + // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using + // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". + bytes32[] memory hashes = new bytes32[](totalHashes); + uint256 leafPos = 0; + uint256 hashPos = 0; + uint256 proofPos = 0; + // At each step, we compute the next hash using two values: + // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we + // get the next hash. + // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the + // `proof` array. + for (uint256 i = 0; i < totalHashes; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = _hashPair(a, b); + } + + if (totalHashes > 0) { + unchecked { + return hashes[totalHashes - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { + return a < b ? _efficientHash(a, b) : _efficientHash(b, a); + } + + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol new file mode 100644 index 0000000..c3a724d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/SignatureChecker.sol) + +pragma solidity ^0.8.0; + +import "./ECDSA.sol"; +import "../../interfaces/IERC1271.sol"; + +/** + * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA + * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like + * Argent and Gnosis Safe. + * + * _Available since v4.1._ + */ +library SignatureChecker { + /** + * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the + * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. + * + * 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 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature); + 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) + ); + return (success && + result.length == 32 && + abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-EIP712.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-EIP712.sol new file mode 100644 index 0000000..fdae3ba --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/cryptography/draft-EIP712.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/draft-EIP712.sol) + +pragma solidity ^0.8.0; + +// EIP-712 is Final as of 2022-08-11. This file is deprecated. + +import "./EIP712.sol"; diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/ConditionalEscrow.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/ConditionalEscrow.sol new file mode 100644 index 0000000..87f5381 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/ConditionalEscrow.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/escrow/ConditionalEscrow.sol) + +pragma solidity ^0.8.0; + +import "./Escrow.sol"; + +/** + * @title ConditionalEscrow + * @dev Base abstract escrow to only allow withdrawal if a condition is met. + * @dev Intended usage: See {Escrow}. Same usage guidelines apply here. + */ +abstract contract ConditionalEscrow is Escrow { + /** + * @dev Returns whether an address is allowed to withdraw their funds. To be + * implemented by derived contracts. + * @param payee The destination address of the funds. + */ + function withdrawalAllowed(address payee) public view virtual returns (bool); + + function withdraw(address payable payee) public virtual override { + require(withdrawalAllowed(payee), "ConditionalEscrow: payee is not allowed to withdraw"); + super.withdraw(payee); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/Escrow.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/Escrow.sol new file mode 100644 index 0000000..48dd51a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/Escrow.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (utils/escrow/Escrow.sol) + +pragma solidity ^0.8.0; + +import "../../access/Ownable.sol"; +import "../Address.sol"; + +/** + * @title Escrow + * @dev Base escrow contract, holds funds designated for a payee until they + * withdraw them. + * + * Intended usage: This contract (and derived escrow contracts) should be a + * standalone contract, that only interacts with the contract that instantiated + * it. That way, it is guaranteed that all Ether will be handled according to + * the `Escrow` rules, and there is no need to check for payable functions or + * transfers in the inheritance tree. The contract that uses the escrow as its + * payment method should be its owner, and provide public methods redirecting + * to the escrow's deposit and withdraw. + */ +contract Escrow is Ownable { + using Address for address payable; + + event Deposited(address indexed payee, uint256 weiAmount); + event Withdrawn(address indexed payee, uint256 weiAmount); + + mapping(address => uint256) private _deposits; + + function depositsOf(address payee) public view returns (uint256) { + return _deposits[payee]; + } + + /** + * @dev Stores the sent amount as credit to be withdrawn. + * @param payee The destination address of the funds. + * + * Emits a {Deposited} event. + */ + function deposit(address payee) public payable virtual onlyOwner { + uint256 amount = msg.value; + _deposits[payee] += amount; + emit Deposited(payee, amount); + } + + /** + * @dev Withdraw accumulated balance for a payee, forwarding all gas to the + * recipient. + * + * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. + * Make sure you trust the recipient, or are either following the + * checks-effects-interactions pattern or using {ReentrancyGuard}. + * + * @param payee The address whose funds will be withdrawn and transferred to. + * + * Emits a {Withdrawn} event. + */ + function withdraw(address payable payee) public virtual onlyOwner { + uint256 payment = _deposits[payee]; + + _deposits[payee] = 0; + + payee.sendValue(payment); + + emit Withdrawn(payee, payment); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/RefundEscrow.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/RefundEscrow.sol new file mode 100644 index 0000000..0e9621f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/escrow/RefundEscrow.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/escrow/RefundEscrow.sol) + +pragma solidity ^0.8.0; + +import "./ConditionalEscrow.sol"; + +/** + * @title RefundEscrow + * @dev Escrow that holds funds for a beneficiary, deposited from multiple + * parties. + * @dev Intended usage: See {Escrow}. Same usage guidelines apply here. + * @dev The owner account (that is, the contract that instantiates this + * contract) may deposit, close the deposit period, and allow for either + * withdrawal by the beneficiary, or refunds to the depositors. All interactions + * with `RefundEscrow` will be made through the owner contract. + */ +contract RefundEscrow is ConditionalEscrow { + using Address for address payable; + + enum State { + Active, + Refunding, + Closed + } + + event RefundsClosed(); + event RefundsEnabled(); + + State private _state; + address payable private immutable _beneficiary; + + /** + * @dev Constructor. + * @param beneficiary_ The beneficiary of the deposits. + */ + constructor(address payable beneficiary_) { + require(beneficiary_ != address(0), "RefundEscrow: beneficiary is the zero address"); + _beneficiary = beneficiary_; + _state = State.Active; + } + + /** + * @return The current state of the escrow. + */ + function state() public view virtual returns (State) { + return _state; + } + + /** + * @return The beneficiary of the escrow. + */ + function beneficiary() public view virtual returns (address payable) { + return _beneficiary; + } + + /** + * @dev Stores funds that may later be refunded. + * @param refundee The address funds will be sent to if a refund occurs. + */ + function deposit(address refundee) public payable virtual override { + require(state() == State.Active, "RefundEscrow: can only deposit while active"); + super.deposit(refundee); + } + + /** + * @dev Allows for the beneficiary to withdraw their funds, rejecting + * further deposits. + */ + function close() public virtual onlyOwner { + require(state() == State.Active, "RefundEscrow: can only close while active"); + _state = State.Closed; + emit RefundsClosed(); + } + + /** + * @dev Allows for refunds to take place, rejecting further deposits. + */ + function enableRefunds() public virtual onlyOwner { + require(state() == State.Active, "RefundEscrow: can only enable refunds while active"); + _state = State.Refunding; + emit RefundsEnabled(); + } + + /** + * @dev Withdraws the beneficiary's funds. + */ + function beneficiaryWithdraw() public virtual { + require(state() == State.Closed, "RefundEscrow: beneficiary can only withdraw while closed"); + beneficiary().sendValue(address(this).balance); + } + + /** + * @dev Returns whether refundees can withdraw their deposits (be refunded). The overridden function receives a + * 'payee' argument, but we ignore it here since the condition is global, not per-payee. + */ + function withdrawalAllowed(address) public view override returns (bool) { + return state() == State.Refunding; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol new file mode 100644 index 0000000..3bf5613 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol new file mode 100644 index 0000000..db6939d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/ERC165Checker.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Library used to query support of an interface declared via {IERC165}. + * + * Note that these functions return the actual result of the query: they do not + * `revert` if an interface is not supported. It is up to the caller to decide + * what to do in these cases. + */ +library ERC165Checker { + // As per the EIP-165 spec, no interface should ever match 0xffffffff + bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; + + /** + * @dev Returns true if `account` supports the {IERC165} interface. + */ + function supportsERC165(address account) internal view returns (bool) { + // Any contract that implements ERC165 must explicitly indicate support of + // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid + return + supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && + !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID); + } + + /** + * @dev Returns true if `account` supports the interface defined by + * `interfaceId`. Support for {IERC165} itself is queried automatically. + * + * See {IERC165-supportsInterface}. + */ + function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { + // query support of both ERC165 as per the spec and support of _interfaceId + return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); + } + + /** + * @dev Returns a boolean array where each value corresponds to the + * interfaces passed in and whether they're supported or not. This allows + * you to batch check interfaces for a contract where your expectation + * is that some interfaces may not be supported. + * + * See {IERC165-supportsInterface}. + * + * _Available since v3.4._ + */ + function getSupportedInterfaces( + address account, + bytes4[] memory interfaceIds + ) internal view returns (bool[] memory) { + // an array of booleans corresponding to interfaceIds and whether they're supported or not + bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); + + // query support of ERC165 itself + if (supportsERC165(account)) { + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); + } + } + + return interfaceIdsSupported; + } + + /** + * @dev Returns true if `account` supports all the interfaces defined in + * `interfaceIds`. Support for {IERC165} itself is queried automatically. + * + * Batch-querying can lead to gas savings by skipping repeated checks for + * {IERC165} support. + * + * See {IERC165-supportsInterface}. + */ + function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { + // query support of ERC165 itself + if (!supportsERC165(account)) { + return false; + } + + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { + return false; + } + } + + // all interfaces supported + return true; + } + + /** + * @notice Query if a contract implements an interface, does not check ERC165 support + * @param account The address of the contract to query for support of an interface + * @param interfaceId The interface identifier, as specified in ERC-165 + * @return true if the contract at account indicates support of the interface with + * identifier interfaceId, false otherwise + * @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) { + // prepare call + bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); + + // perform static call + bool success; + uint256 returnSize; + uint256 returnValue; + assembly { + success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) + returnSize := returndatasize() + returnValue := mload(0x00) + } + + return success && returnSize >= 0x20 && returnValue > 0; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Storage.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Storage.sol new file mode 100644 index 0000000..c99d9f3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Storage.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Storage.sol) + +pragma solidity ^0.8.0; + +import "./ERC165.sol"; + +/** + * @dev Storage based implementation of the {IERC165} interface. + * + * Contracts may inherit from this and call {_registerInterface} to declare + * their support of an interface. + */ +abstract contract ERC165Storage is ERC165 { + /** + * @dev Mapping of interface ids to whether or not it's supported. + */ + mapping(bytes4 => bool) private _supportedInterfaces; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId]; + } + + /** + * @dev Registers the contract as an implementer of the interface defined by + * `interfaceId`. Support of the actual ERC165 interface is automatic and + * registering its interface id is not required. + * + * See {IERC165-supportsInterface}. + * + * Requirements: + * + * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). + */ + function _registerInterface(bytes4 interfaceId) internal virtual { + require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); + _supportedInterfaces[interfaceId] = true; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC1820Implementer.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC1820Implementer.sol new file mode 100644 index 0000000..ac5a884 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/ERC1820Implementer.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC1820Implementer.sol) + +pragma solidity ^0.8.0; + +import "./IERC1820Implementer.sol"; + +/** + * @dev Implementation of the {IERC1820Implementer} interface. + * + * Contracts may inherit from this and call {_registerInterfaceForAddress} to + * declare their willingness to be implementers. + * {IERC1820Registry-setInterfaceImplementer} should then be called for the + * registration to be complete. + */ +contract ERC1820Implementer is IERC1820Implementer { + bytes32 private constant _ERC1820_ACCEPT_MAGIC = keccak256("ERC1820_ACCEPT_MAGIC"); + + mapping(bytes32 => mapping(address => bool)) private _supportedInterfaces; + + /** + * @dev See {IERC1820Implementer-canImplementInterfaceForAddress}. + */ + function canImplementInterfaceForAddress( + bytes32 interfaceHash, + address account + ) public view virtual override returns (bytes32) { + return _supportedInterfaces[interfaceHash][account] ? _ERC1820_ACCEPT_MAGIC : bytes32(0x00); + } + + /** + * @dev Declares the contract as willing to be an implementer of + * `interfaceHash` for `account`. + * + * See {IERC1820Registry-setInterfaceImplementer} and + * {IERC1820Registry-interfaceHash}. + */ + function _registerInterfaceForAddress(bytes32 interfaceHash, address account) internal virtual { + _supportedInterfaces[interfaceHash][account] = true; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol new file mode 100644 index 0000000..e8cdbdb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC1820Implementer.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC1820Implementer.sol new file mode 100644 index 0000000..c4d0b30 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC1820Implementer.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC1820Implementer.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface for an ERC1820 implementer, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[EIP]. + * Used by contracts that will be registered as implementers in the + * {IERC1820Registry}. + */ +interface IERC1820Implementer { + /** + * @dev Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract + * implements `interfaceHash` for `account`. + * + * See {IERC1820Registry-setInterfaceImplementer}. + */ + function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC1820Registry.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC1820Registry.sol new file mode 100644 index 0000000..a146bc2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/introspection/IERC1820Registry.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/IERC1820Registry.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the global ERC1820 Registry, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register + * implementers for interfaces in this registry, as well as query support. + * + * Implementers may be shared by multiple accounts, and can also implement more + * than a single interface for each account. Contracts can implement interfaces + * for themselves, but externally-owned accounts (EOA) must delegate this to a + * contract. + * + * {IERC165} interfaces can also be queried via the registry. + * + * For an in-depth explanation and source code analysis, see the EIP text. + */ +interface IERC1820Registry { + event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer); + + event ManagerChanged(address indexed account, address indexed newManager); + + /** + * @dev Sets `newManager` as the manager for `account`. A manager of an + * account is able to set interface implementers for it. + * + * By default, each account is its own manager. Passing a value of `0x0` in + * `newManager` will reset the manager to this initial state. + * + * Emits a {ManagerChanged} event. + * + * Requirements: + * + * - the caller must be the current manager for `account`. + */ + function setManager(address account, address newManager) external; + + /** + * @dev Returns the manager for `account`. + * + * See {setManager}. + */ + function getManager(address account) external view returns (address); + + /** + * @dev Sets the `implementer` contract as ``account``'s implementer for + * `interfaceHash`. + * + * `account` being the zero address is an alias for the caller's address. + * The zero address can also be used in `implementer` to remove an old one. + * + * See {interfaceHash} to learn how these are created. + * + * Emits an {InterfaceImplementerSet} event. + * + * Requirements: + * + * - the caller must be the current manager for `account`. + * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not + * end in 28 zeroes). + * - `implementer` must implement {IERC1820Implementer} and return true when + * queried for support, unless `implementer` is the caller. See + * {IERC1820Implementer-canImplementInterfaceForAddress}. + */ + function setInterfaceImplementer(address account, bytes32 _interfaceHash, address implementer) external; + + /** + * @dev Returns the implementer of `interfaceHash` for `account`. If no such + * implementer is registered, returns the zero address. + * + * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28 + * zeroes), `account` will be queried for support of it. + * + * `account` being the zero address is an alias for the caller's address. + */ + function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address); + + /** + * @dev Returns the interface hash for an `interfaceName`, as defined in the + * corresponding + * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP]. + */ + function interfaceHash(string calldata interfaceName) external pure returns (bytes32); + + /** + * @notice Updates the cache with whether the contract implements an ERC165 interface or not. + * @param account Address of the contract for which to update the cache. + * @param interfaceId ERC165 interface for which to update the cache. + */ + function updateERC165Cache(address account, bytes4 interfaceId) external; + + /** + * @notice Checks whether a contract implements an ERC165 interface or not. + * If the result is not cached a direct lookup on the contract address is performed. + * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling + * {updateERC165Cache} with the contract address. + * @param account Address of the contract to check. + * @param interfaceId ERC165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); + + /** + * @notice Checks whether a contract implements an ERC165 interface or not without using or updating the cache. + * @param account Address of the contract to check. + * @param interfaceId ERC165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/Math.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/Math.sol new file mode 100644 index 0000000..8400d06 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/Math.sol @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Down, // Toward negative infinity + Up, // Toward infinity + Zero // Toward zero + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds up instead + * of rounding down. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) + * with further edits by Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod0 := mul(x, y) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. + // See https://cs.stackexchange.com/q/138556/92363. + + // Does not overflow because the denominator cannot be zero at this stage in the function. + uint256 twos = denominator & (~denominator + 1); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works + // in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol new file mode 100644 index 0000000..435a5f9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol @@ -0,0 +1,1136 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) +// This file was procedurally generated from scripts/generate/templates/SafeCast.js. + +pragma solidity ^0.8.0; + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. `SafeCast` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + * + * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing + * all math on `uint256` and `int256` and then downcasting. + */ +library SafeCast { + /** + * @dev Returns the downcasted uint248 from uint256, reverting on + * overflow (when the input is greater than largest uint248). + * + * Counterpart to Solidity's `uint248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + * + * _Available since v4.7._ + */ + function toUint248(uint256 value) internal pure returns (uint248) { + require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); + return uint248(value); + } + + /** + * @dev Returns the downcasted uint240 from uint256, reverting on + * overflow (when the input is greater than largest uint240). + * + * Counterpart to Solidity's `uint240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + * + * _Available since v4.7._ + */ + function toUint240(uint256 value) internal pure returns (uint240) { + require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); + return uint240(value); + } + + /** + * @dev Returns the downcasted uint232 from uint256, reverting on + * overflow (when the input is greater than largest uint232). + * + * Counterpart to Solidity's `uint232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + * + * _Available since v4.7._ + */ + function toUint232(uint256 value) internal pure returns (uint232) { + require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); + return uint232(value); + } + + /** + * @dev Returns the downcasted uint224 from uint256, reverting on + * overflow (when the input is greater than largest uint224). + * + * Counterpart to Solidity's `uint224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + * + * _Available since v4.2._ + */ + function toUint224(uint256 value) internal pure returns (uint224) { + require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); + return uint224(value); + } + + /** + * @dev Returns the downcasted uint216 from uint256, reverting on + * overflow (when the input is greater than largest uint216). + * + * Counterpart to Solidity's `uint216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + * + * _Available since v4.7._ + */ + function toUint216(uint256 value) internal pure returns (uint216) { + require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); + return uint216(value); + } + + /** + * @dev Returns the downcasted uint208 from uint256, reverting on + * overflow (when the input is greater than largest uint208). + * + * Counterpart to Solidity's `uint208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + * + * _Available since v4.7._ + */ + function toUint208(uint256 value) internal pure returns (uint208) { + require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); + return uint208(value); + } + + /** + * @dev Returns the downcasted uint200 from uint256, reverting on + * overflow (when the input is greater than largest uint200). + * + * Counterpart to Solidity's `uint200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + * + * _Available since v4.7._ + */ + function toUint200(uint256 value) internal pure returns (uint200) { + require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); + return uint200(value); + } + + /** + * @dev Returns the downcasted uint192 from uint256, reverting on + * overflow (when the input is greater than largest uint192). + * + * Counterpart to Solidity's `uint192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + * + * _Available since v4.7._ + */ + function toUint192(uint256 value) internal pure returns (uint192) { + require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); + return uint192(value); + } + + /** + * @dev Returns the downcasted uint184 from uint256, reverting on + * overflow (when the input is greater than largest uint184). + * + * Counterpart to Solidity's `uint184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + * + * _Available since v4.7._ + */ + function toUint184(uint256 value) internal pure returns (uint184) { + require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); + return uint184(value); + } + + /** + * @dev Returns the downcasted uint176 from uint256, reverting on + * overflow (when the input is greater than largest uint176). + * + * Counterpart to Solidity's `uint176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + * + * _Available since v4.7._ + */ + function toUint176(uint256 value) internal pure returns (uint176) { + require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); + return uint176(value); + } + + /** + * @dev Returns the downcasted uint168 from uint256, reverting on + * overflow (when the input is greater than largest uint168). + * + * Counterpart to Solidity's `uint168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + * + * _Available since v4.7._ + */ + function toUint168(uint256 value) internal pure returns (uint168) { + require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); + return uint168(value); + } + + /** + * @dev Returns the downcasted uint160 from uint256, reverting on + * overflow (when the input is greater than largest uint160). + * + * Counterpart to Solidity's `uint160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + * + * _Available since v4.7._ + */ + function toUint160(uint256 value) internal pure returns (uint160) { + require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); + return uint160(value); + } + + /** + * @dev Returns the downcasted uint152 from uint256, reverting on + * overflow (when the input is greater than largest uint152). + * + * Counterpart to Solidity's `uint152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + * + * _Available since v4.7._ + */ + function toUint152(uint256 value) internal pure returns (uint152) { + require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); + return uint152(value); + } + + /** + * @dev Returns the downcasted uint144 from uint256, reverting on + * overflow (when the input is greater than largest uint144). + * + * Counterpart to Solidity's `uint144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + * + * _Available since v4.7._ + */ + function toUint144(uint256 value) internal pure returns (uint144) { + require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); + return uint144(value); + } + + /** + * @dev Returns the downcasted uint136 from uint256, reverting on + * overflow (when the input is greater than largest uint136). + * + * Counterpart to Solidity's `uint136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + * + * _Available since v4.7._ + */ + function toUint136(uint256 value) internal pure returns (uint136) { + require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); + return uint136(value); + } + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + * + * _Available since v2.5._ + */ + function toUint128(uint256 value) internal pure returns (uint128) { + require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); + return uint128(value); + } + + /** + * @dev Returns the downcasted uint120 from uint256, reverting on + * overflow (when the input is greater than largest uint120). + * + * Counterpart to Solidity's `uint120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + * + * _Available since v4.7._ + */ + function toUint120(uint256 value) internal pure returns (uint120) { + require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); + return uint120(value); + } + + /** + * @dev Returns the downcasted uint112 from uint256, reverting on + * overflow (when the input is greater than largest uint112). + * + * Counterpart to Solidity's `uint112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + * + * _Available since v4.7._ + */ + function toUint112(uint256 value) internal pure returns (uint112) { + require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); + return uint112(value); + } + + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + * + * _Available since v4.7._ + */ + function toUint104(uint256 value) internal pure returns (uint104) { + require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); + return uint104(value); + } + + /** + * @dev Returns the downcasted uint96 from uint256, reverting on + * overflow (when the input is greater than largest uint96). + * + * Counterpart to Solidity's `uint96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + * + * _Available since v4.2._ + */ + function toUint96(uint256 value) internal pure returns (uint96) { + require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); + return uint96(value); + } + + /** + * @dev Returns the downcasted uint88 from uint256, reverting on + * overflow (when the input is greater than largest uint88). + * + * Counterpart to Solidity's `uint88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + * + * _Available since v4.7._ + */ + function toUint88(uint256 value) internal pure returns (uint88) { + require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); + return uint88(value); + } + + /** + * @dev Returns the downcasted uint80 from uint256, reverting on + * overflow (when the input is greater than largest uint80). + * + * Counterpart to Solidity's `uint80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + * + * _Available since v4.7._ + */ + function toUint80(uint256 value) internal pure returns (uint80) { + require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); + return uint80(value); + } + + /** + * @dev Returns the downcasted uint72 from uint256, reverting on + * overflow (when the input is greater than largest uint72). + * + * Counterpart to Solidity's `uint72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + * + * _Available since v4.7._ + */ + function toUint72(uint256 value) internal pure returns (uint72) { + require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); + return uint72(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + * + * _Available since v2.5._ + */ + function toUint64(uint256 value) internal pure returns (uint64) { + require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); + return uint64(value); + } + + /** + * @dev Returns the downcasted uint56 from uint256, reverting on + * overflow (when the input is greater than largest uint56). + * + * Counterpart to Solidity's `uint56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + * + * _Available since v4.7._ + */ + function toUint56(uint256 value) internal pure returns (uint56) { + require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); + return uint56(value); + } + + /** + * @dev Returns the downcasted uint48 from uint256, reverting on + * overflow (when the input is greater than largest uint48). + * + * Counterpart to Solidity's `uint48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + * + * _Available since v4.7._ + */ + function toUint48(uint256 value) internal pure returns (uint48) { + require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); + return uint48(value); + } + + /** + * @dev Returns the downcasted uint40 from uint256, reverting on + * overflow (when the input is greater than largest uint40). + * + * Counterpart to Solidity's `uint40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + * + * _Available since v4.7._ + */ + function toUint40(uint256 value) internal pure returns (uint40) { + require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); + return uint40(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + * + * _Available since v2.5._ + */ + function toUint32(uint256 value) internal pure returns (uint32) { + require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); + return uint32(value); + } + + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + * + * _Available since v4.7._ + */ + function toUint24(uint256 value) internal pure returns (uint24) { + require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); + return uint24(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + * + * _Available since v2.5._ + */ + function toUint16(uint256 value) internal pure returns (uint16) { + require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + * + * _Available since v2.5._ + */ + function toUint8(uint256 value) internal pure returns (uint8) { + require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); + return uint8(value); + } + + /** + * @dev Converts a signed int256 into an unsigned uint256. + * + * Requirements: + * + * - input must be greater than or equal to 0. + * + * _Available since v3.0._ + */ + function toUint256(int256 value) internal pure returns (uint256) { + require(value >= 0, "SafeCast: value must be positive"); + return uint256(value); + } + + /** + * @dev Returns the downcasted int248 from int256, reverting on + * overflow (when the input is less than smallest int248 or + * greater than largest int248). + * + * Counterpart to Solidity's `int248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + * + * _Available since v4.7._ + */ + function toInt248(int256 value) internal pure returns (int248 downcasted) { + downcasted = int248(value); + require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); + } + + /** + * @dev Returns the downcasted int240 from int256, reverting on + * overflow (when the input is less than smallest int240 or + * greater than largest int240). + * + * Counterpart to Solidity's `int240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + * + * _Available since v4.7._ + */ + function toInt240(int256 value) internal pure returns (int240 downcasted) { + downcasted = int240(value); + require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); + } + + /** + * @dev Returns the downcasted int232 from int256, reverting on + * overflow (when the input is less than smallest int232 or + * greater than largest int232). + * + * Counterpart to Solidity's `int232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + * + * _Available since v4.7._ + */ + function toInt232(int256 value) internal pure returns (int232 downcasted) { + downcasted = int232(value); + require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); + } + + /** + * @dev Returns the downcasted int224 from int256, reverting on + * overflow (when the input is less than smallest int224 or + * greater than largest int224). + * + * Counterpart to Solidity's `int224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + * + * _Available since v4.7._ + */ + function toInt224(int256 value) internal pure returns (int224 downcasted) { + downcasted = int224(value); + require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); + } + + /** + * @dev Returns the downcasted int216 from int256, reverting on + * overflow (when the input is less than smallest int216 or + * greater than largest int216). + * + * Counterpart to Solidity's `int216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + * + * _Available since v4.7._ + */ + function toInt216(int256 value) internal pure returns (int216 downcasted) { + downcasted = int216(value); + require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); + } + + /** + * @dev Returns the downcasted int208 from int256, reverting on + * overflow (when the input is less than smallest int208 or + * greater than largest int208). + * + * Counterpart to Solidity's `int208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + * + * _Available since v4.7._ + */ + function toInt208(int256 value) internal pure returns (int208 downcasted) { + downcasted = int208(value); + require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); + } + + /** + * @dev Returns the downcasted int200 from int256, reverting on + * overflow (when the input is less than smallest int200 or + * greater than largest int200). + * + * Counterpart to Solidity's `int200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + * + * _Available since v4.7._ + */ + function toInt200(int256 value) internal pure returns (int200 downcasted) { + downcasted = int200(value); + require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); + } + + /** + * @dev Returns the downcasted int192 from int256, reverting on + * overflow (when the input is less than smallest int192 or + * greater than largest int192). + * + * Counterpart to Solidity's `int192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + * + * _Available since v4.7._ + */ + function toInt192(int256 value) internal pure returns (int192 downcasted) { + downcasted = int192(value); + require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); + } + + /** + * @dev Returns the downcasted int184 from int256, reverting on + * overflow (when the input is less than smallest int184 or + * greater than largest int184). + * + * Counterpart to Solidity's `int184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + * + * _Available since v4.7._ + */ + function toInt184(int256 value) internal pure returns (int184 downcasted) { + downcasted = int184(value); + require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); + } + + /** + * @dev Returns the downcasted int176 from int256, reverting on + * overflow (when the input is less than smallest int176 or + * greater than largest int176). + * + * Counterpart to Solidity's `int176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + * + * _Available since v4.7._ + */ + function toInt176(int256 value) internal pure returns (int176 downcasted) { + downcasted = int176(value); + require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); + } + + /** + * @dev Returns the downcasted int168 from int256, reverting on + * overflow (when the input is less than smallest int168 or + * greater than largest int168). + * + * Counterpart to Solidity's `int168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + * + * _Available since v4.7._ + */ + function toInt168(int256 value) internal pure returns (int168 downcasted) { + downcasted = int168(value); + require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); + } + + /** + * @dev Returns the downcasted int160 from int256, reverting on + * overflow (when the input is less than smallest int160 or + * greater than largest int160). + * + * Counterpart to Solidity's `int160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + * + * _Available since v4.7._ + */ + function toInt160(int256 value) internal pure returns (int160 downcasted) { + downcasted = int160(value); + require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); + } + + /** + * @dev Returns the downcasted int152 from int256, reverting on + * overflow (when the input is less than smallest int152 or + * greater than largest int152). + * + * Counterpart to Solidity's `int152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + * + * _Available since v4.7._ + */ + function toInt152(int256 value) internal pure returns (int152 downcasted) { + downcasted = int152(value); + require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); + } + + /** + * @dev Returns the downcasted int144 from int256, reverting on + * overflow (when the input is less than smallest int144 or + * greater than largest int144). + * + * Counterpart to Solidity's `int144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + * + * _Available since v4.7._ + */ + function toInt144(int256 value) internal pure returns (int144 downcasted) { + downcasted = int144(value); + require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); + } + + /** + * @dev Returns the downcasted int136 from int256, reverting on + * overflow (when the input is less than smallest int136 or + * greater than largest int136). + * + * Counterpart to Solidity's `int136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + * + * _Available since v4.7._ + */ + function toInt136(int256 value) internal pure returns (int136 downcasted) { + downcasted = int136(value); + require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); + } + + /** + * @dev Returns the downcasted int128 from int256, reverting on + * overflow (when the input is less than smallest int128 or + * greater than largest int128). + * + * Counterpart to Solidity's `int128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + * + * _Available since v3.1._ + */ + function toInt128(int256 value) internal pure returns (int128 downcasted) { + downcasted = int128(value); + require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); + } + + /** + * @dev Returns the downcasted int120 from int256, reverting on + * overflow (when the input is less than smallest int120 or + * greater than largest int120). + * + * Counterpart to Solidity's `int120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + * + * _Available since v4.7._ + */ + function toInt120(int256 value) internal pure returns (int120 downcasted) { + downcasted = int120(value); + require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); + } + + /** + * @dev Returns the downcasted int112 from int256, reverting on + * overflow (when the input is less than smallest int112 or + * greater than largest int112). + * + * Counterpart to Solidity's `int112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + * + * _Available since v4.7._ + */ + function toInt112(int256 value) internal pure returns (int112 downcasted) { + downcasted = int112(value); + require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); + } + + /** + * @dev Returns the downcasted int104 from int256, reverting on + * overflow (when the input is less than smallest int104 or + * greater than largest int104). + * + * Counterpart to Solidity's `int104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + * + * _Available since v4.7._ + */ + function toInt104(int256 value) internal pure returns (int104 downcasted) { + downcasted = int104(value); + require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); + } + + /** + * @dev Returns the downcasted int96 from int256, reverting on + * overflow (when the input is less than smallest int96 or + * greater than largest int96). + * + * Counterpart to Solidity's `int96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + * + * _Available since v4.7._ + */ + function toInt96(int256 value) internal pure returns (int96 downcasted) { + downcasted = int96(value); + require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); + } + + /** + * @dev Returns the downcasted int88 from int256, reverting on + * overflow (when the input is less than smallest int88 or + * greater than largest int88). + * + * Counterpart to Solidity's `int88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + * + * _Available since v4.7._ + */ + function toInt88(int256 value) internal pure returns (int88 downcasted) { + downcasted = int88(value); + require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); + } + + /** + * @dev Returns the downcasted int80 from int256, reverting on + * overflow (when the input is less than smallest int80 or + * greater than largest int80). + * + * Counterpart to Solidity's `int80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + * + * _Available since v4.7._ + */ + function toInt80(int256 value) internal pure returns (int80 downcasted) { + downcasted = int80(value); + require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); + } + + /** + * @dev Returns the downcasted int72 from int256, reverting on + * overflow (when the input is less than smallest int72 or + * greater than largest int72). + * + * Counterpart to Solidity's `int72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + * + * _Available since v4.7._ + */ + function toInt72(int256 value) internal pure returns (int72 downcasted) { + downcasted = int72(value); + require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); + } + + /** + * @dev Returns the downcasted int64 from int256, reverting on + * overflow (when the input is less than smallest int64 or + * greater than largest int64). + * + * Counterpart to Solidity's `int64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + * + * _Available since v3.1._ + */ + function toInt64(int256 value) internal pure returns (int64 downcasted) { + downcasted = int64(value); + require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); + } + + /** + * @dev Returns the downcasted int56 from int256, reverting on + * overflow (when the input is less than smallest int56 or + * greater than largest int56). + * + * Counterpart to Solidity's `int56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + * + * _Available since v4.7._ + */ + function toInt56(int256 value) internal pure returns (int56 downcasted) { + downcasted = int56(value); + require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); + } + + /** + * @dev Returns the downcasted int48 from int256, reverting on + * overflow (when the input is less than smallest int48 or + * greater than largest int48). + * + * Counterpart to Solidity's `int48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + * + * _Available since v4.7._ + */ + function toInt48(int256 value) internal pure returns (int48 downcasted) { + downcasted = int48(value); + require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); + } + + /** + * @dev Returns the downcasted int40 from int256, reverting on + * overflow (when the input is less than smallest int40 or + * greater than largest int40). + * + * Counterpart to Solidity's `int40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + * + * _Available since v4.7._ + */ + function toInt40(int256 value) internal pure returns (int40 downcasted) { + downcasted = int40(value); + require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); + } + + /** + * @dev Returns the downcasted int32 from int256, reverting on + * overflow (when the input is less than smallest int32 or + * greater than largest int32). + * + * Counterpart to Solidity's `int32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + * + * _Available since v3.1._ + */ + function toInt32(int256 value) internal pure returns (int32 downcasted) { + downcasted = int32(value); + require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); + } + + /** + * @dev Returns the downcasted int24 from int256, reverting on + * overflow (when the input is less than smallest int24 or + * greater than largest int24). + * + * Counterpart to Solidity's `int24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + * + * _Available since v4.7._ + */ + function toInt24(int256 value) internal pure returns (int24 downcasted) { + downcasted = int24(value); + require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); + } + + /** + * @dev Returns the downcasted int16 from int256, reverting on + * overflow (when the input is less than smallest int16 or + * greater than largest int16). + * + * Counterpart to Solidity's `int16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + * + * _Available since v3.1._ + */ + function toInt16(int256 value) internal pure returns (int16 downcasted) { + downcasted = int16(value); + require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); + } + + /** + * @dev Returns the downcasted int8 from int256, reverting on + * overflow (when the input is less than smallest int8 or + * greater than largest int8). + * + * Counterpart to Solidity's `int8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + * + * _Available since v3.1._ + */ + function toInt8(int256 value) internal pure returns (int8 downcasted) { + downcasted = int8(value); + require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); + } + + /** + * @dev Converts an unsigned uint256 into a signed int256. + * + * Requirements: + * + * - input must be less than or equal to maxInt256. + * + * _Available since v3.0._ + */ + function toInt256(uint256 value) internal pure returns (int256) { + // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive + require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); + return int256(value); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol new file mode 100644 index 0000000..2f48fb7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (utils/math/SafeMath.sol) + +pragma solidity ^0.8.0; + +// CAUTION +// This version of SafeMath should only be used with Solidity 0.8 or later, +// because it relies on the compiler's built in overflow checks. + +/** + * @dev Wrappers over Solidity's arithmetic operations. + * + * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler + * now has built in overflow checking. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + return a + b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + return a * b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + unchecked { + require(b <= a, errorMessage); + return a - b; + } + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + unchecked { + require(b > 0, errorMessage); + return a / b; + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + unchecked { + require(b > 0, errorMessage); + return a % b; + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol new file mode 100644 index 0000000..3ea9f8b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SignedSafeMath.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SignedSafeMath.sol new file mode 100644 index 0000000..6704d4c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/math/SignedSafeMath.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations. + * + * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler + * now has built in overflow checking. + */ +library SignedSafeMath { + /** + * @dev Returns the multiplication of two signed integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(int256 a, int256 b) internal pure returns (int256) { + return a * b; + } + + /** + * @dev Returns the integer division of two signed integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(int256 a, int256 b) internal pure returns (int256) { + return a / b; + } + + /** + * @dev Returns the subtraction of two signed integers, reverting on + * overflow. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(int256 a, int256 b) internal pure returns (int256) { + return a - b; + } + + /** + * @dev Returns the addition of two signed integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(int256 a, int256 b) internal pure returns (int256) { + return a + b; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol new file mode 100644 index 0000000..eb67bfa --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/BitMaps.sol) +pragma solidity ^0.8.0; + +/** + * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. + * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. + */ +library BitMaps { + struct BitMap { + mapping(uint256 => uint256) _data; + } + + /** + * @dev Returns whether the bit at `index` is set. + */ + function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + return bitmap._data[bucket] & mask != 0; + } + + /** + * @dev Sets the bit at `index` to the boolean `value`. + */ + function setTo(BitMap storage bitmap, uint256 index, bool value) internal { + if (value) { + set(bitmap, index); + } else { + unset(bitmap, index); + } + } + + /** + * @dev Sets the bit at `index`. + */ + function set(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] |= mask; + } + + /** + * @dev Unsets the bit at `index`. + */ + function unset(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] &= ~mask; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol new file mode 100644 index 0000000..6b3ea70 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/DoubleEndedQueue.sol) +pragma solidity ^0.8.4; + +import "../math/SafeCast.sol"; + +/** + * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of + * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and + * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that + * the existing queue contents are left in storage. + * + * 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; + * ``` + * + * _Available since v4.6._ + */ +library DoubleEndedQueue { + /** + * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty. + */ + error Empty(); + + /** + * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds. + */ + error OutOfBounds(); + + /** + * @dev Indices are signed integers because the queue can grow in any direction. They are 128 bits so begin and end + * are packed in a single storage slot for efficient access. Since the items are added one at a time we can safely + * assume that these 128-bit indices will not overflow, and use unchecked arithmetic. + * + * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to + * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and + * lead to unexpected behavior. + * + * Indices are in the range [begin, end) which means the first item is at data[begin] and the last item is at + * data[end - 1]. + */ + struct Bytes32Deque { + int128 _begin; + int128 _end; + mapping(int128 => bytes32) _data; + } + + /** + * @dev Inserts an item at the end of the queue. + */ + function pushBack(Bytes32Deque storage deque, bytes32 value) internal { + int128 backIndex = deque._end; + deque._data[backIndex] = value; + unchecked { + deque._end = backIndex + 1; + } + } + + /** + * @dev Removes the item at the end of the queue and returns it. + * + * Reverts with `Empty` if the queue is empty. + */ + function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) { + if (empty(deque)) revert Empty(); + int128 backIndex; + unchecked { + backIndex = deque._end - 1; + } + value = deque._data[backIndex]; + delete deque._data[backIndex]; + deque._end = backIndex; + } + + /** + * @dev Inserts an item at the beginning of the queue. + */ + function pushFront(Bytes32Deque storage deque, bytes32 value) internal { + int128 frontIndex; + unchecked { + frontIndex = deque._begin - 1; + } + deque._data[frontIndex] = value; + deque._begin = frontIndex; + } + + /** + * @dev Removes the item at the beginning of the queue and returns it. + * + * Reverts with `Empty` if the queue is empty. + */ + function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) { + if (empty(deque)) revert Empty(); + int128 frontIndex = deque._begin; + value = deque._data[frontIndex]; + delete deque._data[frontIndex]; + unchecked { + deque._begin = frontIndex + 1; + } + } + + /** + * @dev Returns the item at the beginning of the queue. + * + * Reverts with `Empty` if the queue is empty. + */ + function front(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) revert Empty(); + int128 frontIndex = deque._begin; + return deque._data[frontIndex]; + } + + /** + * @dev Returns the item at the end of the queue. + * + * Reverts with `Empty` if the queue is empty. + */ + function back(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) revert Empty(); + int128 backIndex; + unchecked { + backIndex = deque._end - 1; + } + return deque._data[backIndex]; + } + + /** + * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at + * `length(deque) - 1`. + * + * Reverts with `OutOfBounds` if the index is out of bounds. + */ + function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) { + // int256(deque._begin) is a safe upcast + int128 idx = SafeCast.toInt128(int256(deque._begin) + SafeCast.toInt256(index)); + if (idx >= deque._end) revert OutOfBounds(); + return deque._data[idx]; + } + + /** + * @dev Resets the queue back to being empty. + * + * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses + * out on potential gas refunds. + */ + function clear(Bytes32Deque storage deque) internal { + deque._begin = 0; + deque._end = 0; + } + + /** + * @dev Returns the number of items in the queue. + */ + function length(Bytes32Deque storage deque) internal view returns (uint256) { + // The interface preserves the invariant that begin <= end so we assume this will not overflow. + // We also assume there are at most int256.max items in the queue. + unchecked { + return uint256(int256(deque._end) - int256(deque._begin)); + } + } + + /** + * @dev Returns true if the queue is empty. + */ + function empty(Bytes32Deque storage deque) internal view returns (bool) { + return deque._end <= deque._begin; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol new file mode 100644 index 0000000..fb21f02 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableMap.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. + +pragma solidity ^0.8.0; + +import "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * ``` + * + * The following map types are supported: + * + * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 + * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 + * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 + * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 + * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +library EnumerableMap { + using EnumerableSet for EnumerableSet.Bytes32Set; + + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Map type with + // bytes32 keys and values. + // The Map implementation uses private functions, and user-facing + // implementations (such as Uint256ToAddressMap) are just wrappers around + // the underlying Map. + // This means that we can only create new EnumerableMaps for types that fit + // in bytes32. + + struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 => bytes32) _values; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key"); + return value; + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + Bytes32ToBytes32Map storage map, + bytes32 key, + string memory errorMessage + ) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), errorMessage); + return value; + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { + return map._keys.values(); + } + + // UintToUintMap + + struct UintToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(key))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(key), errorMessage)); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintToAddressMap + + struct UintToAddressMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToAddressMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), address(uint160(uint256(value)))); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, address(uint160(uint256(value)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(key))))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + UintToAddressMap storage map, + uint256 key, + string memory errorMessage + ) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage)))); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressToUintMap + + struct AddressToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { + return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(AddressToUintMap storage map, address key) internal returns (bool) { + return remove(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(AddressToUintMap storage map, address key) internal view returns (bool) { + return contains(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(AddressToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (address(uint160(uint256(key))), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(AddressToUintMap storage map, address key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(uint256(uint160(key))))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + AddressToUintMap storage map, + address key, + string memory errorMessage + ) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage)); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(AddressToUintMap storage map) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // Bytes32ToUintMap + + struct Bytes32ToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { + return set(map._inner, key, bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { + return remove(map._inner, key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { + return contains(map._inner, key); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(Bytes32ToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (key, uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, key); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { + return uint256(get(map._inner, key)); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + Bytes32ToUintMap storage map, + bytes32 key, + string memory errorMessage + ) internal view returns (uint256) { + return uint256(get(map._inner, key, errorMessage)); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { + bytes32[] memory store = keys(map._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol new file mode 100644 index 0000000..a01f82d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. + +pragma solidity ^0.8.0; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + // Position of the value in the `values` array, plus 1 because index 0 + // means a value is not in the set. + mapping(bytes32 => uint256) _indexes; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastValue; + // Update the index for the moved value + set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { + bytes32[] memory store = _values(set._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(AddressSet storage set) internal view returns (address[] memory) { + bytes32[] memory store = _values(set._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(UintSet storage set) internal view returns (uint256[] memory) { + bytes32[] memory store = _values(set._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/amb/IAMB.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/amb/IAMB.sol new file mode 100644 index 0000000..73a2bd2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/amb/IAMB.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (vendor/amb/IAMB.sol) +pragma solidity ^0.8.0; + +interface IAMB { + event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData); + event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData); + event AffirmationCompleted( + address indexed sender, + address indexed executor, + bytes32 indexed messageId, + bool status + ); + event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status); + + function messageSender() external view returns (address); + + function maxGasPerTx() external view returns (uint256); + + function transactionHash() external view returns (bytes32); + + function messageId() external view returns (bytes32); + + function messageSourceChainId() external view returns (bytes32); + + function messageCallStatus(bytes32 _messageId) external view returns (bool); + + function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32); + + function failedMessageReceiver(bytes32 _messageId) external view returns (address); + + function failedMessageSender(bytes32 _messageId) external view returns (address); + + function requireToPassMessage(address _contract, bytes calldata _data, uint256 _gas) external returns (bytes32); + + function requireToConfirmMessage(address _contract, bytes calldata _data, uint256 _gas) external returns (bytes32); + + function sourceChainId() external view returns (uint256); + + function destinationChainId() external view returns (uint256); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IArbSys.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IArbSys.sol new file mode 100644 index 0000000..9b79d5c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IArbSys.sol @@ -0,0 +1,134 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.8.0) (vendor/arbitrum/IArbSys.sol) + +pragma solidity >=0.4.21 <0.9.0; + +/** + * @title System level functionality + * @notice For use by contracts to interact with core L2-specific functionality. + * Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064. + */ +interface IArbSys { + /** + * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0) + * @return block number as int + */ + function arbBlockNumber() external view returns (uint256); + + /** + * @notice Get Arbitrum block hash (reverts unless currentBlockNum-256 <= arbBlockNum < currentBlockNum) + * @return block hash + */ + function arbBlockHash(uint256 arbBlockNum) external view returns (bytes32); + + /** + * @notice Gets the rollup's unique chain identifier + * @return Chain identifier as int + */ + function arbChainID() external view returns (uint256); + + /** + * @notice Get internal version number identifying an ArbOS build + * @return version number as int + */ + function arbOSVersion() external view returns (uint256); + + /** + * @notice Returns 0 since Nitro has no concept of storage gas + * @return uint 0 + */ + function getStorageGasAvailable() external view returns (uint256); + + /** + * @notice (deprecated) check if current call is top level (meaning it was triggered by an EoA or a L1 contract) + * @dev this call has been deprecated and may be removed in a future release + * @return true if current execution frame is not a call by another L2 contract + */ + function isTopLevelCall() external view returns (bool); + + /** + * @notice map L1 sender contract address to its L2 alias + * @param sender sender address + * @param unused argument no longer used + * @return aliased sender address + */ + function mapL1SenderContractAddressToL2Alias(address sender, address unused) external pure returns (address); + + /** + * @notice check if the caller (of this caller of this) is an aliased L1 contract address + * @return true iff the caller's address is an alias for an L1 contract address + */ + function wasMyCallersAddressAliased() external view returns (bool); + + /** + * @notice return the address of the caller (of this caller of this), without applying L1 contract address aliasing + * @return address of the caller's caller, without applying L1 contract address aliasing + */ + function myCallersAddressWithoutAliasing() external view returns (address); + + /** + * @notice Send given amount of Eth to dest from sender. + * This is a convenience function, which is equivalent to calling sendTxToL1 with empty data. + * @param destination recipient address on L1 + * @return unique identifier for this L2-to-L1 transaction. + */ + function withdrawEth(address destination) external payable returns (uint256); + + /** + * @notice Send a transaction to L1 + * @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data + * to a contract address without any code (as enforced by the Bridge contract). + * @param destination recipient address on L1 + * @param data (optional) calldata for L1 contract call + * @return a unique identifier for this L2-to-L1 transaction. + */ + function sendTxToL1(address destination, bytes calldata data) external payable returns (uint256); + + /** + * @notice Get send Merkle tree state + * @return size number of sends in the history + * @return root root hash of the send history + * @return partials hashes of partial subtrees in the send history tree + */ + function sendMerkleTreeState() external view returns (uint256 size, bytes32 root, bytes32[] memory partials); + + /** + * @notice creates a send txn from L2 to L1 + * @param position = (level << 192) + leaf = (0 << 192) + leaf = leaf + */ + event L2ToL1Tx( + address caller, + address indexed destination, + uint256 indexed hash, + uint256 indexed position, + uint256 arbBlockNum, + uint256 ethBlockNum, + uint256 timestamp, + uint256 callvalue, + bytes data + ); + + /// @dev DEPRECATED in favour of the new L2ToL1Tx event above after the nitro upgrade + event L2ToL1Transaction( + address caller, + address indexed destination, + uint256 indexed uniqueId, + uint256 indexed batchNumber, + uint256 indexInBatch, + uint256 arbBlockNum, + uint256 ethBlockNum, + uint256 timestamp, + uint256 callvalue, + bytes data + ); + + /** + * @notice logs a merkle branch for proof synthesis + * @param reserved an index meant only to align the 4th index with L2ToL1Transaction's 4th event + * @param hash the merkle hash + * @param position = (level << 192) + leaf + */ + event SendMerkleUpdate(uint256 indexed reserved, bytes32 indexed hash, uint256 indexed position); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IBridge.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IBridge.sol new file mode 100644 index 0000000..e71bedc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IBridge.sol @@ -0,0 +1,102 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.8.0) (vendor/arbitrum/IBridge.sol) + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +interface IBridge { + event MessageDelivered( + uint256 indexed messageIndex, + bytes32 indexed beforeInboxAcc, + address inbox, + uint8 kind, + address sender, + bytes32 messageDataHash, + uint256 baseFeeL1, + uint64 timestamp + ); + + event BridgeCallTriggered(address indexed outbox, address indexed to, uint256 value, bytes data); + + event InboxToggle(address indexed inbox, bool enabled); + + event OutboxToggle(address indexed outbox, bool enabled); + + event SequencerInboxUpdated(address newSequencerInbox); + + function allowedDelayedInboxList(uint256) external returns (address); + + function allowedOutboxList(uint256) external returns (address); + + /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message. + function delayedInboxAccs(uint256) external view returns (bytes32); + + /// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message. + function sequencerInboxAccs(uint256) external view returns (bytes32); + + // OpenZeppelin: changed return type from IOwnable + function rollup() external view returns (address); + + function sequencerInbox() external view returns (address); + + function activeOutbox() external view returns (address); + + function allowedDelayedInboxes(address inbox) external view returns (bool); + + function allowedOutboxes(address outbox) external view returns (bool); + + function sequencerReportedSubMessageCount() external view returns (uint256); + + /** + * @dev Enqueue a message in the delayed inbox accumulator. + * These messages are later sequenced in the SequencerInbox, either + * by the sequencer as part of a normal batch, or by force inclusion. + */ + function enqueueDelayedMessage( + uint8 kind, + address sender, + bytes32 messageDataHash + ) external payable returns (uint256); + + function executeCall( + address to, + uint256 value, + bytes calldata data + ) external returns (bool success, bytes memory returnData); + + function delayedMessageCount() external view returns (uint256); + + function sequencerMessageCount() external view returns (uint256); + + // ---------- onlySequencerInbox functions ---------- + + function enqueueSequencerMessage( + bytes32 dataHash, + uint256 afterDelayedMessagesRead, + uint256 prevMessageCount, + uint256 newMessageCount + ) external returns (uint256 seqMessageIndex, bytes32 beforeAcc, bytes32 delayedAcc, bytes32 acc); + + /** + * @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type + * This is done through a separate function entrypoint instead of allowing the sequencer inbox + * to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either + * every delayed inbox or every sequencer inbox call. + */ + function submitBatchSpendingReport(address batchPoster, bytes32 dataHash) external returns (uint256 msgNum); + + // ---------- onlyRollupOrOwner functions ---------- + + function setSequencerInbox(address _sequencerInbox) external; + + function setDelayedInbox(address inbox, bool enabled) external; + + function setOutbox(address inbox, bool enabled) external; + + // ---------- initializer ---------- + + // OpenZeppelin: changed rollup_ type from IOwnable + function initialize(address rollup_) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IDelayedMessageProvider.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IDelayedMessageProvider.sol new file mode 100644 index 0000000..914c25f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IDelayedMessageProvider.sol @@ -0,0 +1,16 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.8.0) (vendor/arbitrum/IDelayedMessageProvider.sol) + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +interface IDelayedMessageProvider { + /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator + event InboxMessageDelivered(uint256 indexed messageNum, bytes data); + + /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator + /// same as InboxMessageDelivered but the batch data is available in tx.input + event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IInbox.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IInbox.sol new file mode 100644 index 0000000..a8b6751 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IInbox.sol @@ -0,0 +1,152 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.8.0) (vendor/arbitrum/IInbox.sol) + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +import "./IBridge.sol"; +import "./IDelayedMessageProvider.sol"; + +interface IInbox is IDelayedMessageProvider { + function bridge() external view returns (IBridge); + + // OpenZeppelin: changed return type from ISequencerInbox + function sequencerInbox() external view returns (address); + + /** + * @notice Send a generic L2 message to the chain + * @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input + * @param messageData Data of the message being sent + */ + function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256); + + /** + * @notice Send a generic L2 message to the chain + * @dev This method can be used to send any type of message that doesn't require L1 validation + * @param messageData Data of the message being sent + */ + function sendL2Message(bytes calldata messageData) external returns (uint256); + + function sendL1FundedUnsignedTransaction( + uint256 gasLimit, + uint256 maxFeePerGas, + uint256 nonce, + address to, + bytes calldata data + ) external payable returns (uint256); + + function sendL1FundedContractTransaction( + uint256 gasLimit, + uint256 maxFeePerGas, + address to, + bytes calldata data + ) external payable returns (uint256); + + function sendUnsignedTransaction( + uint256 gasLimit, + uint256 maxFeePerGas, + uint256 nonce, + address to, + uint256 value, + bytes calldata data + ) external returns (uint256); + + function sendContractTransaction( + uint256 gasLimit, + uint256 maxFeePerGas, + address to, + uint256 value, + bytes calldata data + ) external returns (uint256); + + /** + * @notice Get the L1 fee for submitting a retryable + * @dev This fee can be paid by funds already in the L2 aliased address or by the current message value + * @dev This formula may change in the future, to future proof your code query this method instead of inlining!! + * @param dataLength The length of the retryable's calldata, in bytes + * @param baseFee The block basefee when the retryable is included in the chain, if 0 current block.basefee will be used + */ + function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee) external view returns (uint256); + + /** + * @notice Deposit eth from L1 to L2 to address of the sender if sender is an EOA, and to its aliased address if the sender is a contract + * @dev This does not trigger the fallback function when receiving in the L2 side. + * Look into retryable tickets if you are interested in this functionality. + * @dev This function should not be called inside contract constructors + */ + function depositEth() external payable returns (uint256); + + /** + * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts + * @dev all msg.value will deposited to callValueRefundAddress on L2 + * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error + * @param to destination L2 contract address + * @param l2CallValue call value for retryable L2 message + * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee + * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance + * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled + * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) + * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) + * @param data ABI encoded data of L2 message + * @return unique message number of the retryable transaction + */ + function createRetryableTicket( + address to, + uint256 l2CallValue, + uint256 maxSubmissionCost, + address excessFeeRefundAddress, + address callValueRefundAddress, + uint256 gasLimit, + uint256 maxFeePerGas, + bytes calldata data + ) external payable returns (uint256); + + /** + * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts + * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds + * come from the deposit alone, rather than falling back on the user's L2 balance + * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress). + * createRetryableTicket method is the recommended standard. + * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error + * @param to destination L2 contract address + * @param l2CallValue call value for retryable L2 message + * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee + * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance + * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled + * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) + * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) + * @param data ABI encoded data of L2 message + * @return unique message number of the retryable transaction + */ + function unsafeCreateRetryableTicket( + address to, + uint256 l2CallValue, + uint256 maxSubmissionCost, + address excessFeeRefundAddress, + address callValueRefundAddress, + uint256 gasLimit, + uint256 maxFeePerGas, + bytes calldata data + ) external payable returns (uint256); + + // ---------- onlyRollupOrOwner functions ---------- + + /// @notice pauses all inbox functionality + function pause() external; + + /// @notice unpauses all inbox functionality + function unpause() external; + + // ---------- initializer ---------- + + /** + * @dev function to be called one time during the inbox upgrade process + * this is used to fix the storage slots + */ + function postUpgradeInit(IBridge _bridge) external; + + // OpenZeppelin: changed _sequencerInbox type from ISequencerInbox + function initialize(IBridge _bridge, address _sequencerInbox) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IOutbox.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IOutbox.sol new file mode 100644 index 0000000..22fa58f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/arbitrum/IOutbox.sol @@ -0,0 +1,117 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.8.0) (vendor/arbitrum/IOutbox.sol) + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +import "./IBridge.sol"; + +interface IOutbox { + event SendRootUpdated(bytes32 indexed blockHash, bytes32 indexed outputRoot); + event OutBoxTransactionExecuted( + address indexed to, + address indexed l2Sender, + uint256 indexed zero, + uint256 transactionIndex + ); + + function rollup() external view returns (address); // the rollup contract + + function bridge() external view returns (IBridge); // the bridge contract + + function spent(uint256) external view returns (bytes32); // packed spent bitmap + + function roots(bytes32) external view returns (bytes32); // maps root hashes => L2 block hash + + // solhint-disable-next-line func-name-mixedcase + function OUTBOX_VERSION() external view returns (uint128); // the outbox version + + function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external; + + /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account + /// When the return value is zero, that means this is a system message + /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies + function l2ToL1Sender() external view returns (address); + + /// @return l2Block return L2 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active + function l2ToL1Block() external view returns (uint256); + + /// @return l1Block return L1 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active + function l2ToL1EthBlock() external view returns (uint256); + + /// @return timestamp return L2 timestamp when the L2 tx was initiated or 0 if no L2 to L1 transaction is active + function l2ToL1Timestamp() external view returns (uint256); + + /// @return outputId returns the unique output identifier of the L2 to L1 tx or 0 if no L2 to L1 transaction is active + function l2ToL1OutputId() external view returns (bytes32); + + /** + * @notice Executes a messages in an Outbox entry. + * @dev Reverts if dispute period hasn't expired, since the outbox entry + * is only created once the rollup confirms the respective assertion. + * @dev it is not possible to execute any L2-to-L1 transaction which contains data + * to a contract address without any code (as enforced by the Bridge contract). + * @param proof Merkle proof of message inclusion in send root + * @param index Merkle path to message + * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1) + * @param to destination address for L1 contract call + * @param l2Block l2 block number at which sendTxToL1 call was made + * @param l1Block l1 block number at which sendTxToL1 call was made + * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made + * @param value wei in L1 message + * @param data abi-encoded L1 message data + */ + function executeTransaction( + bytes32[] calldata proof, + uint256 index, + address l2Sender, + address to, + uint256 l2Block, + uint256 l1Block, + uint256 l2Timestamp, + uint256 value, + bytes calldata data + ) external; + + /** + * @dev function used to simulate the result of a particular function call from the outbox + * it is useful for things such as gas estimates. This function includes all costs except for + * proof validation (which can be considered offchain as a somewhat of a fixed cost - it's + * not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation). + * We can't include the cost of proof validation since this is intended to be used to simulate txs + * that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend + * to confirm a pending merkle root, but that would be less practical for integrating with tooling. + * It is only possible to trigger it when the msg sender is address zero, which should be impossible + * unless under simulation in an eth_call or eth_estimateGas + */ + function executeTransactionSimulation( + uint256 index, + address l2Sender, + address to, + uint256 l2Block, + uint256 l1Block, + uint256 l2Timestamp, + uint256 value, + bytes calldata data + ) external; + + /** + * @param index Merkle path to message + * @return true if the message has been spent + */ + function isSpent(uint256 index) external view returns (bool); + + function calculateItemHash( + address l2Sender, + address to, + uint256 l2Block, + uint256 l1Block, + uint256 l2Timestamp, + uint256 value, + bytes calldata data + ) external pure returns (bytes32); + + function calculateMerkleRoot(bytes32[] memory proof, uint256 path, bytes32 item) external pure returns (bytes32); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol new file mode 100644 index 0000000..fb33a68 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (vendor/compound/ICompoundTimelock.sol) + +pragma solidity ^0.8.0; + +/** + * https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[Compound's timelock] interface + */ +interface ICompoundTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + + receive() external payable; + + // solhint-disable-next-line func-name-mixedcase + function GRACE_PERIOD() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function MINIMUM_DELAY() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function MAXIMUM_DELAY() external view returns (uint256); + + function admin() external view returns (address); + + function pendingAdmin() external view returns (address); + + function delay() external view returns (uint256); + + function queuedTransactions(bytes32) external view returns (bool); + + function setDelay(uint256) external; + + function acceptAdmin() external; + + function setPendingAdmin(address) external; + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external returns (bytes32); + + function cancelTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external; + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external payable returns (bytes memory); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE new file mode 100644 index 0000000..7da2324 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE @@ -0,0 +1,11 @@ +Copyright 2020 Compound Labs, Inc. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/optimism/ICrossDomainMessenger.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/optimism/ICrossDomainMessenger.sol new file mode 100644 index 0000000..cc01a48 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/optimism/ICrossDomainMessenger.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (vendor/optimism/ICrossDomainMessenger.sol) +pragma solidity >0.5.0 <0.9.0; + +/** + * @title ICrossDomainMessenger + */ +interface ICrossDomainMessenger { + /********** + * Events * + **********/ + + event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit); + event RelayedMessage(bytes32 indexed msgHash); + event FailedRelayedMessage(bytes32 indexed msgHash); + + /************* + * Variables * + *************/ + + function xDomainMessageSender() external view returns (address); + + /******************** + * Public Functions * + ********************/ + + /** + * Sends a cross domain message to the target messenger. + * @param _target Target contract address. + * @param _message Message to send to the target. + * @param _gasLimit Gas limit for the provided message. + */ + function sendMessage(address _target, bytes calldata _message, uint32 _gasLimit) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/optimism/LICENSE b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/optimism/LICENSE new file mode 100644 index 0000000..6a7da52 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/optimism/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright 2020-2021 Optimism + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/polygon/IFxMessageProcessor.sol b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/polygon/IFxMessageProcessor.sol new file mode 100644 index 0000000..be73e6f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/contracts/vendor/polygon/IFxMessageProcessor.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (vendor/polygon/IFxMessageProcessor.sol) +pragma solidity ^0.8.0; + +interface IFxMessageProcessor { + function processMessageFromRoot(uint256 stateId, address rootMessageSender, bytes calldata data) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/foundry.toml b/lib/crytic/lib/openzeppelin-contracts/foundry.toml new file mode 100644 index 0000000..c0da487 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/foundry.toml @@ -0,0 +1,3 @@ +[fuzz] +runs = 10000 +max_test_rejects = 100000 diff --git a/lib/crytic/lib/openzeppelin-contracts/hardhat.config.js b/lib/crytic/lib/openzeppelin-contracts/hardhat.config.js new file mode 100644 index 0000000..32f721b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/hardhat.config.js @@ -0,0 +1,114 @@ +/// ENVVAR +// - CI: output gas report to file instead of stdout +// - COVERAGE: enable coverage report +// - ENABLE_GAS_REPORT: enable gas report +// - COMPILE_MODE: production modes enables optimizations (default: development) +// - COMPILE_VERSION: compiler version (default: 0.8.9) +// - COINMARKETCAP: coinmarkercat api key for USD value in gas report + +const fs = require('fs'); +const path = require('path'); +const argv = require('yargs/yargs')() + .env('') + .options({ + coverage: { + type: 'boolean', + default: false, + }, + gas: { + alias: 'enableGasReport', + type: 'boolean', + default: false, + }, + gasReport: { + alias: 'enableGasReportPath', + type: 'string', + implies: 'gas', + default: undefined, + }, + mode: { + alias: 'compileMode', + type: 'string', + choices: ['production', 'development'], + default: 'development', + }, + ir: { + alias: 'enableIR', + type: 'boolean', + default: false, + }, + compiler: { + alias: 'compileVersion', + type: 'string', + default: '0.8.13', + }, + coinmarketcap: { + alias: 'coinmarketcapApiKey', + type: 'string', + }, + }).argv; + +require('@nomiclabs/hardhat-truffle5'); +require('hardhat-ignore-warnings'); +require('hardhat-exposed'); + +require('solidity-docgen'); + +for (const f of fs.readdirSync(path.join(__dirname, 'hardhat'))) { + require(path.join(__dirname, 'hardhat', f)); +} + +const withOptimizations = argv.gas || argv.compileMode === 'production'; + +/** + * @type import('hardhat/config').HardhatUserConfig + */ +module.exports = { + solidity: { + version: argv.compiler, + settings: { + optimizer: { + enabled: withOptimizations, + runs: 200, + }, + viaIR: withOptimizations && argv.ir, + outputSelection: { '*': { '*': ['storageLayout'] } }, + }, + }, + warnings: { + '*': { + 'code-size': withOptimizations, + 'unused-param': !argv.coverage, // coverage causes unused-param warnings + default: 'error', + }, + }, + networks: { + hardhat: { + blockGasLimit: 10000000, + allowUnlimitedContractSize: !withOptimizations, + }, + }, + exposed: { + exclude: [ + 'vendor/**/*', + // overflow clash + 'utils/Timers.sol', + ], + }, + docgen: require('./docs/config'), +}; + +if (argv.gas) { + require('hardhat-gas-reporter'); + module.exports.gasReporter = { + showMethodSig: true, + currency: 'USD', + outputFile: argv.gasReport, + coinmarketcap: argv.coinmarketcap, + }; +} + +if (argv.coverage) { + require('solidity-coverage'); + module.exports.networks.hardhat.initialBaseFeePerGas = 0; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/hardhat/env-contract.js b/lib/crytic/lib/openzeppelin-contracts/hardhat/env-contract.js new file mode 100644 index 0000000..74d54cf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/hardhat/env-contract.js @@ -0,0 +1,10 @@ +extendEnvironment(env => { + const { contract } = env; + + env.contract = function (name, body) { + // remove the default account from the accounts list used in tests, in order + // to protect tests against accidentally passing due to the contract + // deployer being used subsequently as function caller + contract(name, accounts => body(accounts.slice(1))); + }; +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js b/lib/crytic/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js new file mode 100644 index 0000000..8e3e343 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js @@ -0,0 +1,45 @@ +// Warnings about unreachable code are emitted with a source location that corresponds to the unreachable code. +// We have some testing contracts that purposely cause unreachable code, but said code is in the library contracts, and +// with hardhat-ignore-warnings we are not able to selectively ignore them without potentially ignoring relevant +// warnings that we don't want to miss. +// Thus, we need to handle these warnings separately. We force Hardhat to compile them in a separate compilation job and +// then ignore the warnings about unreachable code that come from that compilation job. + +const { task } = require('hardhat/config'); +const { + TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, + TASK_COMPILE_SOLIDITY_COMPILE, +} = require('hardhat/builtin-tasks/task-names'); + +const marker = Symbol('unreachable'); +const markedCache = new WeakMap(); + +task(TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, async (params, _, runSuper) => { + const job = await runSuper(params); + // If the file is in the unreachable directory, we make a copy of the config and mark it, which will cause it to get + // compiled separately (along with the other marked files). + if (params.file.sourceName.startsWith('contracts/mocks/') && /\bunreachable\b/.test(params.file.sourceName)) { + const originalConfig = job.solidityConfig; + let markedConfig = markedCache.get(originalConfig); + if (markedConfig === undefined) { + markedConfig = { ...originalConfig, [marker]: true }; + markedCache.set(originalConfig, markedConfig); + } + job.solidityConfig = markedConfig; + } + return job; +}); + +const W_UNREACHABLE_CODE = '5740'; + +task(TASK_COMPILE_SOLIDITY_COMPILE, async (params, _, runSuper) => { + const marked = params.compilationJob.solidityConfig[marker]; + const result = await runSuper(params); + if (marked) { + result.output = { + ...result.output, + errors: result.output.errors?.filter(e => e.severity !== 'warning' || e.errorCode !== W_UNREACHABLE_CODE), + }; + } + return result; +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js b/lib/crytic/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js new file mode 100644 index 0000000..965ba37 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js @@ -0,0 +1,6 @@ +const { subtask } = require('hardhat/config'); +const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require('hardhat/builtin-tasks/task-names'); + +subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, __, runSuper) => + (await runSuper()).filter(path => !path.endsWith('.t.sol')), +); diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol b/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol new file mode 100644 index 0000000..c34512b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "forge-std/Test.sol"; + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC20} from "forge-std/interfaces/IERC20.sol"; +interface IERC20 { + event Transfer(address indexed from, address indexed to, uint value); + event Approval(address indexed owner, address indexed spender, uint value); + function totalSupply() external view returns (uint); + function balanceOf(address account) external view returns (uint); + function transfer(address to, uint amount) external returns (bool); + function allowance(address owner, address spender) external view returns (uint); + function approve(address spender, uint amount) external returns (bool); + function transferFrom(address from, address to, uint amount) external returns (bool); +} + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC4626} from "forge-std/interfaces/IERC4626.sol"; +interface IERC4626 is IERC20 { + event Deposit(address indexed caller, address indexed owner, uint assets, uint shares); + event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint assets, uint shares); + function asset() external view returns (address assetTokenAddress); + function totalAssets() external view returns (uint totalManagedAssets); + function convertToShares(uint assets) external view returns (uint shares); + function convertToAssets(uint shares) external view returns (uint assets); + function maxDeposit(address receiver) external view returns (uint maxAssets); + function previewDeposit(uint assets) external view returns (uint shares); + function deposit(uint assets, address receiver) external returns (uint shares); + function maxMint(address receiver) external view returns (uint maxShares); + function previewMint(uint shares) external view returns (uint assets); + function mint(uint shares, address receiver) external returns (uint assets); + function maxWithdraw(address owner) external view returns (uint maxAssets); + function previewWithdraw(uint assets) external view returns (uint shares); + function withdraw(uint assets, address receiver, address owner) external returns (uint shares); + function maxRedeem(address owner) external view returns (uint maxShares); + function previewRedeem(uint shares) external view returns (uint assets); + function redeem(uint shares, address receiver, address owner) external returns (uint assets); +} + +abstract contract ERC4626Prop is Test { + uint internal _delta_; + + address internal _underlying_; + address internal _vault_; + + bool internal _vaultMayBeEmpty; + bool internal _unlimitedAmount; + + // + // asset + // + + // asset + // "MUST NOT revert." + function prop_asset(address caller) public { + vm.prank(caller); IERC4626(_vault_).asset(); + } + + // totalAssets + // "MUST NOT revert." + function prop_totalAssets(address caller) public { + vm.prank(caller); IERC4626(_vault_).totalAssets(); + } + + // + // convert + // + + // convertToShares + // "MUST NOT show any variations depending on the caller." + function prop_convertToShares(address caller1, address caller2, uint assets) public { + vm.prank(caller1); uint res1 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // convertToAssets + // "MUST NOT show any variations depending on the caller." + function prop_convertToAssets(address caller1, address caller2, uint shares) public { + vm.prank(caller1); uint res1 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // + // deposit + // + + // maxDeposit + // "MUST NOT revert." + function prop_maxDeposit(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxDeposit(receiver); + } + + // previewDeposit + // "MUST return as close to and no more than the exact amount of Vault + // shares that would be minted in a deposit call in the same transaction. + // I.e. deposit should return the same or more shares as previewDeposit if + // called in the same transaction." + function prop_previewDeposit(address caller, address receiver, address other, uint assets) public { + vm.prank(other); uint sharesPreview = vault_previewDeposit(assets); // "MAY revert due to other conditions that would also cause deposit to revert." + vm.prank(caller); uint sharesActual = vault_deposit(assets, receiver); + assertApproxGeAbs(sharesActual, sharesPreview, _delta_); + } + + // deposit + function prop_deposit(address caller, address receiver, uint assets) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint shares = vault_deposit(assets, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // mint + // + + // maxMint + // "MUST NOT revert." + function prop_maxMint(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxMint(receiver); + } + + // previewMint + // "MUST return as close to and no fewer than the exact amount of assets + // that would be deposited in a mint call in the same transaction. I.e. mint + // should return the same or fewer assets as previewMint if called in the + // same transaction." + function prop_previewMint(address caller, address receiver, address other, uint shares) public { + vm.prank(other); uint assetsPreview = vault_previewMint(shares); + vm.prank(caller); uint assetsActual = vault_mint(shares, receiver); + assertApproxLeAbs(assetsActual, assetsPreview, _delta_); + } + + // mint + function prop_mint(address caller, address receiver, uint shares) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint assets = vault_mint(shares, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // withdraw + // + + // maxWithdraw + // "MUST NOT revert." + // NOTE: some implementations failed due to arithmetic overflow + function prop_maxWithdraw(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxWithdraw(owner); + } + + // previewWithdraw + // "MUST return as close to and no fewer than the exact amount of Vault + // shares that would be burned in a withdraw call in the same transaction. + // I.e. withdraw should return the same or fewer shares as previewWithdraw + // if called in the same transaction." + function prop_previewWithdraw(address caller, address receiver, address owner, address other, uint assets) public { + vm.prank(other); uint preview = vault_previewWithdraw(assets); + vm.prank(caller); uint actual = vault_withdraw(assets, receiver, owner); + assertApproxLeAbs(actual, preview, _delta_); + } + + // withdraw + function prop_withdraw(address caller, address receiver, address owner, uint assets) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint shares = vault_withdraw(assets, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // redeem + // + + // maxRedeem + // "MUST NOT revert." + function prop_maxRedeem(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxRedeem(owner); + } + + // previewRedeem + // "MUST return as close to and no more than the exact amount of assets that + // would be withdrawn in a redeem call in the same transaction. I.e. redeem + // should return the same or more assets as previewRedeem if called in the + // same transaction." + function prop_previewRedeem(address caller, address receiver, address owner, address other, uint shares) public { + vm.prank(other); uint preview = vault_previewRedeem(shares); + vm.prank(caller); uint actual = vault_redeem(shares, receiver, owner); + assertApproxGeAbs(actual, preview, _delta_); + } + + // redeem + function prop_redeem(address caller, address receiver, address owner, uint shares) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint assets = vault_redeem(shares, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // round trip properties + // + + // redeem(deposit(a)) <= a + function prop_RT_deposit_redeem(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares = vault_deposit(assets, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets, _delta_); + } + + // s = deposit(a) + // s' = withdraw(a) + // s' >= s + function prop_RT_deposit_withdraw(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares1 = vault_deposit(assets, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares1, _delta_); + } + + // deposit(redeem(s)) <= s + function prop_RT_redeem_deposit(address caller, uint shares) public { + vm.prank(caller); uint assets = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares, _delta_); + } + + // a = redeem(s) + // a' = mint(s) + // a' >= a + function prop_RT_redeem_mint(address caller, uint shares) public { + vm.prank(caller); uint assets1 = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets1, _delta_); + } + + // withdraw(mint(s)) >= s + function prop_RT_mint_withdraw(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets = vault_mint(shares, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares, _delta_); + } + + // a = mint(s) + // a' = redeem(s) + // a' <= a + function prop_RT_mint_redeem(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets1 = vault_mint(shares, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets1, _delta_); + } + + // mint(withdraw(a)) >= a + function prop_RT_withdraw_mint(address caller, uint assets) public { + vm.prank(caller); uint shares = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets, _delta_); + } + + // s = withdraw(a) + // s' = deposit(a) + // s' <= s + function prop_RT_withdraw_deposit(address caller, uint assets) public { + vm.prank(caller); uint shares1 = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares1, _delta_); + } + + // + // utils + // + + function vault_convertToShares(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToShares.selector, assets)); + } + function vault_convertToAssets(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToAssets.selector, shares)); + } + + function vault_maxDeposit(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxDeposit.selector, receiver)); + } + function vault_maxMint(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxMint.selector, receiver)); + } + function vault_maxWithdraw(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxWithdraw.selector, owner)); + } + function vault_maxRedeem(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxRedeem.selector, owner)); + } + + function vault_previewDeposit(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewDeposit.selector, assets)); + } + function vault_previewMint(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewMint.selector, shares)); + } + function vault_previewWithdraw(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewWithdraw.selector, assets)); + } + function vault_previewRedeem(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewRedeem.selector, shares)); + } + + function vault_deposit(uint assets, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.deposit.selector, assets, receiver)); + } + function vault_mint(uint shares, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.mint.selector, shares, receiver)); + } + function vault_withdraw(uint assets, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.withdraw.selector, assets, receiver, owner)); + } + function vault_redeem(uint shares, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.redeem.selector, shares, receiver, owner)); + } + + function _call_vault(bytes memory data) internal returns (uint) { + (bool success, bytes memory retdata) = _vault_.call(data); + if (success) return abi.decode(retdata, (uint)); + vm.assume(false); // if reverted, discard the current fuzz inputs, and let the fuzzer to start a new fuzz run + return 0; // silence warning + } + + function assertApproxGeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a >= b)) { + uint dt = b - a; + if (dt > maxDelta) { + emit log ("Error: a >=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } + + function assertApproxLeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a <= b)) { + uint dt = a - b; + if (dt > maxDelta) { + emit log ("Error: a <=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol b/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol new file mode 100644 index 0000000..6254a05 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "./ERC4626.prop.sol"; + +interface IMockERC20 is IERC20 { + function mint(address to, uint value) external; + function burn(address from, uint value) external; +} + +abstract contract ERC4626Test is ERC4626Prop { + function setUp() public virtual; + + uint constant N = 4; + + struct Init { + address[N] user; + uint[N] share; + uint[N] asset; + int yield; + } + + // setup initial vault state as follows: + // + // totalAssets == sum(init.share) + init.yield + // totalShares == sum(init.share) + // + // init.user[i]'s assets == init.asset[i] + // init.user[i]'s shares == init.share[i] + function setUpVault(Init memory init) public virtual { + // setup initial shares and assets for individual users + for (uint i = 0; i < N; i++) { + address user = init.user[i]; + vm.assume(_isEOA(user)); + // shares + uint shares = init.share[i]; + try IMockERC20(_underlying_).mint(user, shares) {} catch { vm.assume(false); } + _approve(_underlying_, user, _vault_, shares); + vm.prank(user); try IERC4626(_vault_).deposit(shares, user) {} catch { vm.assume(false); } + // assets + uint assets = init.asset[i]; + try IMockERC20(_underlying_).mint(user, assets) {} catch { vm.assume(false); } + } + + // setup initial yield for vault + setUpYield(init); + } + + // setup initial yield + function setUpYield(Init memory init) public virtual { + if (init.yield >= 0) { // gain + uint gain = uint(init.yield); + try IMockERC20(_underlying_).mint(_vault_, gain) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } else { // loss + vm.assume(init.yield > type(int).min); // avoid overflow in conversion + uint loss = uint(-1 * init.yield); + try IMockERC20(_underlying_).burn(_vault_, loss) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } + } + + // + // asset + // + + function test_asset(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_asset(caller); + } + + function test_totalAssets(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_totalAssets(caller); + } + + // + // convert + // + + function test_convertToShares(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToShares(caller1, caller2, assets); + } + + function test_convertToAssets(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToAssets(caller1, caller2, shares); + } + + // + // deposit + // + + function test_maxDeposit(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxDeposit(caller, receiver); + } + + function test_previewDeposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewDeposit(caller, receiver, other, assets); + } + + function test_deposit(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_deposit(caller, receiver, assets); + } + + // + // mint + // + + function test_maxMint(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxMint(caller, receiver); + } + + function test_previewMint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewMint(caller, receiver, other, shares); + } + + function test_mint(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_mint(caller, receiver, shares); + } + + // + // withdraw + // + + function test_maxWithdraw(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxWithdraw(caller, owner); + } + + function test_previewWithdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewWithdraw(caller, receiver, owner, other, assets); + } + + function test_withdraw(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, allowance); + prop_withdraw(caller, receiver, owner, assets); + } + + function testFail_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + vm.assume(caller != owner); + vm.assume(assets > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); uint shares = IERC4626(_vault_).withdraw(assets, receiver, owner); + assertGt(shares, 0); // this assert is expected to fail + } + + // + // redeem + // + + function test_maxRedeem(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxRedeem(caller, owner); + } + + function test_previewRedeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewRedeem(caller, receiver, owner, other, shares); + } + + function test_redeem(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, allowance); + prop_redeem(caller, receiver, owner, shares); + } + + function testFail_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + vm.assume(caller != owner); + vm.assume(shares > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); IERC4626(_vault_).redeem(shares, receiver, owner); + } + + // + // round trip tests + // + + function test_RT_deposit_redeem(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_redeem(caller, assets); + } + + function test_RT_deposit_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_withdraw(caller, assets); + } + + function test_RT_redeem_deposit(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_deposit(caller, shares); + } + + function test_RT_redeem_mint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_mint(caller, shares); + } + + function test_RT_mint_withdraw(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_withdraw(caller, shares); + } + + function test_RT_mint_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_redeem(caller, shares); + } + + function test_RT_withdraw_mint(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_mint(caller, assets); + } + + function test_RT_withdraw_deposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_deposit(caller, assets); + } + + // + // utils + // + + function _isContract(address account) internal view returns (bool) { return account.code.length > 0; } + function _isEOA (address account) internal view returns (bool) { return account.code.length == 0; } + + function _approve(address token, address owner, address spender, uint amount) internal { + vm.prank(owner); _safeApprove(token, spender, 0); + vm.prank(owner); _safeApprove(token, spender, amount); + } + + function _safeApprove(address token, address spender, uint amount) internal { + (bool success, bytes memory retdata) = token.call(abi.encodeWithSelector(IERC20.approve.selector, spender, amount)); + vm.assume(success); + if (retdata.length > 0) vm.assume(abi.decode(retdata, (bool))); + } + + function _max_deposit(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_underlying_).balanceOf(from); + } + + function _max_mint(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToShares(IERC20(_underlying_).balanceOf(from)); + } + + function _max_withdraw(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToAssets(IERC20(_vault_).balanceOf(from)); // may be different from maxWithdraw(from) + } + + function _max_redeem(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_vault_).balanceOf(from); // may be different from maxRedeem(from) + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE b/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/README.md b/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/README.md new file mode 100644 index 0000000..651e443 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/erc4626-tests/README.md @@ -0,0 +1,116 @@ +# ERC4626 Property Tests + +Foundry (dapptools-style) property-based tests for [ERC4626] standard conformance. + +[ERC4626]: + +You can read our post on "_[Generalized property tests for ERC4626 vaults][post]_." + +[post]: + +## Overview + +#### What is it? +- Test suites for checking if the given ERC4626 implementation satisfies the **standard requirements**. +- Dapptools-style **property-based tests** for fuzzing or symbolic execution testing. +- Tests that are **independent** from implementation details, thus applicable for any ERC4626 vaults. + +#### What isn’t it? +- It does NOT test implementation-specific details, e.g., how to generate and distribute yields, how to compute the share price, etc. + +#### Testing properties: + +- **Round-trip properties**: no one can make a free profit by depositing and immediately withdrawing back and forth. + +- **Functional correctness**: the `deposit()`, `mint()`, `withdraw()`, and `redeem()` functions update the balance and allowance properly. + +- The `preview{Deposit,Redeem}()` functions **MUST NOT over-estimate** the exact amount.[^1] + +[^1]: That is, the `deposit()` and `redeem()` functions “MUST return the same or more amounts as their preview function if called in the same transaction.” + +- The `preview{Mint,Withdraw}()` functions **MUST NOT under-estimate** the exact amount.[^2] + +[^2]: That is, the `mint()` and `withdraw()` functions “MUST return the same or fewer amounts as their preview function if called in the same transaction.” + +- The `convertTo{Shares,Assets}` functions “**MUST NOT show any variations** depending on the caller.” + +- The `asset()`, `totalAssets()`, and `max{Deposit,Mint,Withdraw,Redeem}()` functions “**MUST NOT revert**.” + +## Usage + +**Step 0**: Install [foundry] and add [forge-std] in your vault repo: +```bash +$ curl -L https://foundry.paradigm.xyz | bash + +$ cd /path/to/your-erc4626-vault +$ forge install foundry-rs/forge-std +``` + +[foundry]: +[forge-std]: + +**Step 1**: Add this [erc4626-tests] as a dependency to your vault: +```bash +$ cd /path/to/your-erc4626-vault +$ forge install a16z/erc4626-tests +``` + +[erc4626-tests]: + +**Step 2**: Extend the abstract test contract [`ERC4626Test`](ERC4626.test.sol) with your own custom vault setup method, for example: + +```solidity +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "erc4626-tests/ERC4626.test.sol"; + +import { ERC20Mock } from "/path/to/mocks/ERC20Mock.sol"; +import { ERC4626Mock } from "/path/to/mocks/ERC4626Mock.sol"; + +contract ERC4626StdTest is ERC4626Test { + function setUp() public override { + _underlying_ = address(new ERC20Mock("Mock ERC20", "MERC20", 18)); + _vault_ = address(new ERC4626Mock(ERC20Mock(__underlying__), "Mock ERC4626", "MERC4626")); + _delta_ = 0; + _vaultMayBeEmpty = false; + _unlimitedAmount = false; + } +} +``` + +Specifically, set the state variables as follows: +- `_vault_`: the address of your ERC4626 vault. +- `_underlying_`: the address of the underlying asset of your vault. Note that the default `setupVault()` and `setupYield()` methods of `ERC4626Test` assume that it implements `mint(address to, uint value)` and `burn(address from, uint value)`. You can override the setup methods with your own if such `mint()` and `burn()` are not implemented. +- `_delta_`: the maximum approximation error size to be passed to [`assertApproxEqAbs()`]. It must be given as an absolute value (not a percentage) in the smallest unit (e.g., Wei or Satoshi). Note that all the tests are expected to pass with `__delta__ == 0` as long as your vault follows the [preferred rounding direction] as specified in the standard. If your vault doesn't follow the preferred rounding direction, you can set `__delta__` to a reasonable size of rounding errors where the adversarial profit of exploiting such rounding errors stays sufficiently small compared to the gas cost. (You can read our [post] for more about the adversarial profit.) +- `_vaultMayBeEmpty`: when set to false, fuzz inputs that empties the vault are ignored. +- `_unlimitedAmount`: when set to false, fuzz inputs are restricted to the currently available amount from the caller. Limiting the amount can speed up fuzzing, but may miss some edge cases. + +[`assertApproxEqAbs()`]: + +[preferred rounding direction]: + +**Step 3**: Run `forge test` + +``` +$ forge test +``` + +## Examples + +Below are examples of adding these property tests to existing ERC4626 vaults: +- [OpenZeppelin ERC4626] [[diff](https://github.com/daejunpark/openzeppelin-contracts/pull/1/files)] +- [Solmate ERC4626] [[diff](https://github.com/daejunpark/solmate/pull/1/files)] +- [Revenue Distribution Token] [[diff](https://github.com/daejunpark/revenue-distribution-token/pull/1/files)] +- [Yield Daddy ERC4626 wrappers] [[diff](https://github.com/daejunpark/yield-daddy/pull/1/files)][^bug] + +[OpenZeppelin ERC4626]: +[Solmate ERC4626]: +[Revenue Distribution Token]: +[Yield Daddy ERC4626 wrappers]: + +[^bug]: Our property tests indeed revealed an [issue](https://github.com/timeless-fi/yield-daddy/issues/7) in their eToken testing mock contract. The tests passed after it is [fixed](https://github.com/daejunpark/yield-daddy/commit/721cf4bd766805fd409455434aa5fd1a9b2df25c). + +## Disclaimer + +_These smart contracts are being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the user interface or the smart contracts. They have not been audited and as such there can be no assurance they will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. THE SMART CONTRACTS CONTAINED HEREIN ARE FURNISHED AS IS, WHERE IS, WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY, NON-INFRINGEMENT OR FITNESS FOR ANY PARTICULAR PURPOSE. Further, use of any of these smart contracts may be restricted or prohibited under applicable law, including securities laws, and it is therefore strongly advised for you to contact a reputable attorney in any jurisdiction where these smart contracts may be accessible for any questions or concerns with respect thereto. Further, no information provided in this repo should be construed as investment advice or legal advice for any particular facts or circumstances, and is not meant to replace competent counsel. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See a16z.com/disclosures for more info._ diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..96b2336 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + # Backwards compatibility checks. + - name: Check compatibility with 0.8.0 + if: always() + run: forge build --skip test --use solc:0.8.0 + + - name: Check compatibility with 0.7.6 + if: always() + run: forge build --skip test --use solc:0.7.6 + + - name: Check compatibility with 0.7.0 + if: always() + run: forge build --skip test --use solc:0.7.0 + + - name: Check compatibility with 0.6.12 + if: always() + run: forge build --skip test --use solc:0.6.12 + + - name: Check compatibility with 0.6.2 + if: always() + run: forge build --skip test --use solc:0.6.2 + + # via-ir compilation time checks. + - name: Measure compilation time of Test with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTest.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of TestBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTestBase.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of Script with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScript.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of ScriptBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScriptBase.sol --use solc:0.8.17 --via-ir + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Run tests + run: forge test -vvv + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Check formatting + run: forge fmt --check diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.gitignore b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.gitmodules b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.gitmodules new file mode 100644 index 0000000..e124719 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ds-test"] + path = lib/ds-test + url = https://github.com/dapphub/ds-test diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE @@ -0,0 +1,203 @@ +Copyright Contributors to Forge Standard Library + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright Contributors to Forge Standard Library + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER +DEALINGS IN THE SOFTWARE.R diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/README.md b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/README.md new file mode 100644 index 0000000..8494a7d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/README.md @@ -0,0 +1,250 @@ +# Forge Standard Library • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml) + +Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes. + +**Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).** + +## Install + +```bash +forge install foundry-rs/forge-std +``` + +## Contracts +### stdError + +This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors. + +See the contract itself for all error codes. + +#### Example usage + +```solidity + +import "forge-std/Test.sol"; + +contract TestContract is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } +} + +contract ErrorsTest { + function arithmeticError(uint256 a) public { + uint256 a = a - 100; + } +} +``` + +### stdStorage + +This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`). + +This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth. + +I.e.: +```solidity +struct T { + // depth 0 + uint256 a; + // depth 1 + uint256 b; +} +``` + +#### Example usage + +```solidity +import "forge-std/Test.sol"; + +contract TestContract is Test { + using stdStorage for StdStorage; + + Storage test; + + function setUp() public { + test = new Storage(); + } + + function testFindExists() public { + // Lets say we want to find the slot for the public + // variable `exists`. We just pass in the function selector + // to the `find` command + uint256 slot = stdstore.target(address(test)).sig("exists()").find(); + assertEq(slot, 0); + } + + function testWriteExists() public { + // Lets say we want to write to the slot for the public + // variable `exists`. We just pass in the function selector + // to the `checked_write` command + stdstore.target(address(test)).sig("exists()").checked_write(100); + assertEq(test.exists(), 100); + } + + // It supports arbitrary storage layouts, like assembly based storage locations + function testFindHidden() public { + // `hidden` is a random hash of a bytes, iteration through slots would + // not find it. Our mechanism does + // Also, you can use the selector instead of a string + uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find(); + assertEq(slot, uint256(keccak256("my.random.var"))); + } + + // If targeting a mapping, you have to pass in the keys necessary to perform the find + // i.e.: + function testFindMapping() public { + uint256 slot = stdstore + .target(address(test)) + .sig(test.map_addr.selector) + .with_key(address(this)) + .find(); + // in the `Storage` constructor, we wrote that this address' value was 1 in the map + // so when we load the slot, we expect it to be 1 + assertEq(uint(vm.load(address(test), bytes32(slot))), 1); + } + + // If the target is a struct, you can specify the field depth: + function testFindStruct() public { + // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc. + uint256 slot_for_a_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(0) + .find(); + + uint256 slot_for_b_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(1) + .find(); + + assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1); + assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2); + } +} + +// A complex storage contract +contract Storage { + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + constructor() { + map_addr[msg.sender] = 1; + } + + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + // mapping(address => Packed) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basicStruct = UnpackedStruct({ + a: 1, + b: 2 + }); + + function hidden() public view returns (bytes32 t) { + // an extremely hidden storage slot + bytes32 slot = keccak256("my.random.var"); + assembly { + t := sload(slot) + } + } +} +``` + +### stdCheats + +This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you. + + +#### Example usage: +```solidity + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +// Inherit the stdCheats +contract StdCheatsTest is Test { + Bar test; + function setUp() public { + test = new Bar(); + } + + function testHoax() public { + // we call `hoax`, which gives the target address + // eth and then calls `prank` + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + + // overloaded to allow you to specify how much eth to + // initialize the address with + hoax(address(1337), 1); + test.bar{value: 1}(address(1337)); + } + + function testStartHoax() public { + // we call `startHoax`, which gives the target address + // eth and then calls `startPrank` + // + // it is also overloaded so that you can specify an eth amount + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } +} + +contract Bar { + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } +} +``` + +### Std Assertions + +Expand upon the assertion functions from the `DSTest` library. + +### `console.log` + +Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log). +It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console2.sol"; +... +console2.log(someValue); +``` + +If you need compatibility with Hardhat, you must use the standard `console.sol` instead. +Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console.sol"; +... +console.log(someValue); +``` + +## License + +Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/foundry.toml b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/foundry.toml new file mode 100644 index 0000000..cca8301 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/foundry.toml @@ -0,0 +1,21 @@ +[profile.default] +fs_permissions = [{ access = "read-write", path = "./"}] + +[rpc_endpoints] +# The RPC URLs are modified versions of the default for testing initialization. +mainnet = "https://mainnet.infura.io/v3/7a8769b798b642f6933f2ed52042bd70" # Different API key. +optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash. +arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash. +needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}" + +[fmt] +# These are all the `forge fmt` defaults. +line_length = 120 +tab_width = 4 +bracket_spacing = false +int_types = 'long' +multiline_func_header = 'attributes_first' +quote_style = 'double' +number_underscore = 'preserve' +single_line_statement_blocks = 'preserve' +ignore = ["src/console.sol", "src/console2.sol"] \ No newline at end of file diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/.gitignore b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/.gitignore new file mode 100644 index 0000000..63f0b2c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/.gitignore @@ -0,0 +1,3 @@ +/.dapple +/build +/out diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/LICENSE b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/Makefile b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/Makefile new file mode 100644 index 0000000..661dac4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/Makefile @@ -0,0 +1,14 @@ +all:; dapp build + +test: + -dapp --use solc:0.4.23 build + -dapp --use solc:0.4.26 build + -dapp --use solc:0.5.17 build + -dapp --use solc:0.6.12 build + -dapp --use solc:0.7.5 build + +demo: + DAPP_SRC=demo dapp --use solc:0.7.5 build + -hevm dapp-test --verbose 3 + +.PHONY: test demo diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/default.nix b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/default.nix new file mode 100644 index 0000000..cf65419 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/default.nix @@ -0,0 +1,4 @@ +{ solidityPackage, dappsys }: solidityPackage { + name = "ds-test"; + src = ./src; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/demo/demo.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/demo/demo.sol new file mode 100644 index 0000000..f3bb48e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/demo/demo.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import "../src/test.sol"; + +contract DemoTest is DSTest { + function test_this() public pure { + require(true); + } + function test_logs() public { + emit log("-- log(string)"); + emit log("a string"); + + emit log("-- log_named_uint(string, uint)"); + emit log_named_uint("uint", 512); + + emit log("-- log_named_int(string, int)"); + emit log_named_int("int", -512); + + emit log("-- log_named_address(string, address)"); + emit log_named_address("address", address(this)); + + emit log("-- log_named_bytes32(string, bytes32)"); + emit log_named_bytes32("bytes32", "a string"); + + emit log("-- log_named_bytes(string, bytes)"); + emit log_named_bytes("bytes", hex"cafefe"); + + emit log("-- log_named_string(string, string)"); + emit log_named_string("string", "a string"); + + emit log("-- log_named_decimal_uint(string, uint, uint)"); + emit log_named_decimal_uint("decimal uint", 1.0e18, 18); + + emit log("-- log_named_decimal_int(string, int, uint)"); + emit log_named_decimal_int("decimal int", -1.0e18, 18); + } + event log_old_named_uint(bytes32,uint); + function test_old_logs() public { + emit log_old_named_uint("key", 500); + emit log_named_bytes32("bkey", "val"); + } + function test_trace() public view { + this.echo("string 1", "string 2"); + } + function test_multiline() public { + emit log("a multiline\\nstring"); + emit log("a multiline string"); + emit log_bytes("a string"); + emit log_bytes("a multiline\nstring"); + emit log_bytes("a multiline\\nstring"); + emit logs(hex"0000"); + emit log_named_bytes("0x0000", hex"0000"); + emit logs(hex"ff"); + } + function echo(string memory s1, string memory s2) public pure + returns (string memory, string memory) + { + return (s1, s2); + } + + function prove_this(uint x) public { + emit log_named_uint("sym x", x); + assertGt(x + 1, 0); + } + + function test_logn() public { + assembly { + log0(0x01, 0x02) + log1(0x01, 0x02, 0x03) + log2(0x01, 0x02, 0x03, 0x04) + log3(0x01, 0x02, 0x03, 0x04, 0x05) + } + } + + event MyEvent(uint, uint indexed, uint, uint indexed); + function test_events() public { + emit MyEvent(1, 2, 3, 4); + } + + function test_asserts() public { + string memory err = "this test has failed!"; + emit log("## assertTrue(bool)\n"); + assertTrue(false); + emit log("\n"); + assertTrue(false, err); + + emit log("\n## assertEq(address,address)\n"); + assertEq(address(this), msg.sender); + emit log("\n"); + assertEq(address(this), msg.sender, err); + + emit log("\n## assertEq32(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(uint,uint)\n"); + assertEq(uint(0), 1); + emit log("\n"); + assertEq(uint(0), 1, err); + + emit log("\n## assertEq(int,int)\n"); + assertEq(-1, -2); + emit log("\n"); + assertEq(-1, -2, err); + + emit log("\n## assertEqDecimal(int,int,uint)\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertEqDecimal(uint,uint,uint)\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGt(uint,uint)\n"); + assertGt(uint(0), 0); + emit log("\n"); + assertGt(uint(0), 0, err); + + emit log("\n## assertGt(int,int)\n"); + assertGt(-1, -1); + emit log("\n"); + assertGt(-1, -1, err); + + emit log("\n## assertGtDecimal(int,int,uint)\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGtDecimal(uint,uint,uint)\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGe(uint,uint)\n"); + assertGe(uint(0), 1); + emit log("\n"); + assertGe(uint(0), 1, err); + + emit log("\n## assertGe(int,int)\n"); + assertGe(-1, 0); + emit log("\n"); + assertGe(-1, 0, err); + + emit log("\n## assertGeDecimal(int,int,uint)\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGeDecimal(uint,uint,uint)\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertLt(uint,uint)\n"); + assertLt(uint(0), 0); + emit log("\n"); + assertLt(uint(0), 0, err); + + emit log("\n## assertLt(int,int)\n"); + assertLt(-1, -1); + emit log("\n"); + assertLt(-1, -1, err); + + emit log("\n## assertLtDecimal(int,int,uint)\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLtDecimal(uint,uint,uint)\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertLe(uint,uint)\n"); + assertLe(uint(1), 0); + emit log("\n"); + assertLe(uint(1), 0, err); + + emit log("\n## assertLe(int,int)\n"); + assertLe(0, -1); + emit log("\n"); + assertLe(0, -1, err); + + emit log("\n## assertLeDecimal(int,int,uint)\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLeDecimal(uint,uint,uint)\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertEq(string,string)\n"); + string memory s1 = "string 1"; + string memory s2 = "string 2"; + assertEq(s1, s2); + emit log("\n"); + assertEq(s1, s2, err); + + emit log("\n## assertEq0(bytes,bytes)\n"); + assertEq0(hex"abcdef01", hex"abcdef02"); + emit log("\n"); + assertEq0(hex"abcdef01", hex"abcdef02", err); + } +} + +contract DemoTestWithSetUp { + function setUp() public { + } + function test_pass() public pure { + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/package.json b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/package.json new file mode 100644 index 0000000..4802ada --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "ds-test", + "version": "1.0.0", + "description": "Assertions, equality checks and other test helpers ", + "bugs": "https://github.com/dapphub/ds-test/issues", + "license": "GPL-3.0", + "author": "Contributors to ds-test", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/dapphub/ds-test.git" + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/test.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/test.sol new file mode 100644 index 0000000..515a3bd --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/test.sol @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.5.0; + +contract DSTest { + event log (string); + event logs (bytes); + + event log_address (address); + event log_bytes32 (bytes32); + event log_int (int); + event log_uint (uint); + event log_bytes (bytes); + event log_string (string); + + event log_named_address (string key, address val); + event log_named_bytes32 (string key, bytes32 val); + event log_named_decimal_int (string key, int val, uint decimals); + event log_named_decimal_uint (string key, uint val, uint decimals); + event log_named_int (string key, int val); + event log_named_uint (string key, uint val); + event log_named_bytes (string key, bytes val); + event log_named_string (string key, string val); + + bool public IS_TEST = true; + bool private _failed; + + address constant HEVM_ADDRESS = + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); + + modifier mayRevert() { _; } + modifier testopts(string memory) { _; } + + function failed() public returns (bool) { + if (_failed) { + return _failed; + } else { + bool globalFailed = false; + if (hasHEVMContext()) { + (, bytes memory retdata) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("load(address,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed")) + ) + ); + globalFailed = abi.decode(retdata, (bool)); + } + return globalFailed; + } + } + + function fail() internal { + if (hasHEVMContext()) { + (bool status, ) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("store(address,bytes32,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) + ) + ); + status; // Silence compiler warnings + } + _failed = true; + } + + function hasHEVMContext() internal view returns (bool) { + uint256 hevmCodeSize = 0; + assembly { + hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) + } + return hevmCodeSize > 0; + } + + modifier logs_gas() { + uint startGas = gasleft(); + _; + uint endGas = gasleft(); + emit log_named_uint("gas", startGas - endGas); + } + + function assertTrue(bool condition) internal { + if (!condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertTrue(bool condition, string memory err) internal { + if (!condition) { + emit log_named_string("Error", err); + assertTrue(condition); + } + } + + function assertEq(address a, address b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [address]"); + emit log_named_address(" Expected", b); + emit log_named_address(" Actual", a); + fail(); + } + } + function assertEq(address a, address b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes32 a, bytes32 b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [bytes32]"); + emit log_named_bytes32(" Expected", b); + emit log_named_bytes32(" Actual", a); + fail(); + } + } + function assertEq(bytes32 a, bytes32 b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + function assertEq32(bytes32 a, bytes32 b) internal { + assertEq(a, b); + } + function assertEq32(bytes32 a, bytes32 b, string memory err) internal { + assertEq(a, b, err); + } + + function assertEq(int a, int b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + function assertEq(int a, int b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEq(uint a, uint b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + function assertEq(uint a, uint b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEqDecimal(int a, int b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal int]"); + emit log_named_decimal_int(" Expected", b, decimals); + emit log_named_decimal_int(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + function assertEqDecimal(uint a, uint b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Expected", b, decimals); + emit log_named_decimal_uint(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + + function assertGt(uint a, uint b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGt(uint a, uint b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGt(int a, int b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGt(int a, int b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGtDecimal(int a, int b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + function assertGtDecimal(uint a, uint b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + + function assertGe(uint a, uint b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGe(uint a, uint b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGe(int a, int b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGe(int a, int b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGeDecimal(int a, int b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + function assertGeDecimal(uint a, uint b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertLt(uint a, uint b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLt(uint a, uint b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLt(int a, int b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLt(int a, int b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLtDecimal(int a, int b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + function assertLtDecimal(uint a, uint b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + + function assertLe(uint a, uint b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLe(uint a, uint b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLe(int a, int b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLe(int a, int b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLeDecimal(int a, int b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + function assertLeDecimal(uint a, uint b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log("Error: a == b not satisfied [string]"); + emit log_named_string(" Expected", b); + emit log_named_string(" Actual", a); + fail(); + } + } + function assertEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { + ok = true; + if (a.length == b.length) { + for (uint i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + ok = false; + } + } + } else { + ok = false; + } + } + function assertEq0(bytes memory a, bytes memory b) internal { + if (!checkEq0(a, b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + function assertEq0(bytes memory a, bytes memory b, string memory err) internal { + if (!checkEq0(a, b)) { + emit log_named_string("Error", err); + assertEq0(a, b); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/package.json b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/package.json new file mode 100644 index 0000000..a000ac8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.2.0", + "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", + "homepage": "https://book.getfoundry.sh/forge/forge-std", + "bugs": "https://github.com/foundry-rs/forge-std/issues", + "license": "(Apache-2.0 OR MIT)", + "author": "Contributors to Forge Standard Library", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/foundry-rs/forge-std.git" + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..e0d8b05 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {StdStorage} from "./StdStorage.sol"; +import {Vm, VmSafe} from "./Vm.sol"; + +abstract contract CommonBase { + // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. + address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + // console.sol and console2.sol work by executing a staticcall to this address. + address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; + // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38. + address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))); + // Address of the test contract, deployed by the DEFAULT_SENDER. + address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; + + uint256 internal constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + Vm internal constant vm = Vm(VM_ADDRESS); + StdStorage internal stdstore; +} + +abstract contract TestBase is CommonBase {} + +abstract contract ScriptBase is CommonBase { + // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..bffccad --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Standard Library's default Script. + +// 🧩 MODULES +import {ScriptBase} from "./Base.sol"; +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheatsSafe} from "./StdCheats.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorageSafe} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {VmSafe} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {ScriptBase} from "./Base.sol"; + +// ⭐️ SCRIPT +abstract contract Script is StdChains, StdCheatsSafe, StdUtils, ScriptBase { + // Note: IS_SCRIPT() must return true. + bool public IS_SCRIPT = true; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..733dbba --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {DSTest} from "ds-test/test.sol"; +import {stdMath} from "./StdMath.sol"; + +abstract contract StdAssertions is DSTest { + event log_array(uint256[] val); + event log_array(int256[] val); + event log_array(address[] val); + event log_named_array(string key, uint256[] val); + event log_named_array(string key, int256[] val); + event log_named_array(string key, address[] val); + + function fail(string memory err) internal virtual { + emit log_named_string("Error", err); + fail(); + } + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); + } + + function assertEq(bool a, bool b) internal virtual { + if (a != b) { + emit log("Error: a == b not satisfied [bool]"); + emit log_named_string(" Expected", b ? "true" : "false"); + emit log_named_string(" Actual", a ? "true" : "false"); + fail(); + } + } + + function assertEq(bool a, bool b, string memory err) internal virtual { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes memory a, bytes memory b) internal virtual { + assertEq0(a, b); + } + + function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { + assertEq0(a, b, err); + } + + function assertEq(uint256[] memory a, uint256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [uint[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(int256[] memory a, int256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [int[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(address[] memory a, address[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [address[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + // Legacy helper + function assertEqUint(uint256 a, uint256 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..68755bf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +/** + * StdChains provides information about EVM compatible chains that can be used in scripts/tests. + * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are + * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of + * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the + * alias used in this contract, which can be found as the first argument to the + * `setChainWithDefaultRpcUrl` call in the `initialize` function. + * + * There are two main ways to use this contract: + * 1. Set a chain with `setChain(string memory chainAlias, Chain memory chain)` + * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. + * + * The first time either of those are used, chains are initialized with the default set of RPC URLs. + * This is done in `initialize`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in + * `defaultRpcUrls`. + * + * The `setChain` function is straightforward, and it simply saves off the given chain data. + * + * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say + * we want to retrieve `mainnet`'s RPC URL: + * - If you haven't set any mainnet chain info with `setChain` and you haven't specified that + * chain in `foundry.toml`, the default data and RPC URL will be returned. + * - If you have set a mainnet RPC URL in `foundry.toml` it will return that, if valid (e.g. if + * a URL is given or if an environment variable is given and that environment variable exists). + * Otherwise, the default data is returned. + * - If you specified data with `setChain` it will return that. + * + * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> defaults. + */ +abstract contract StdChains { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private initialized; + + struct Chain { + // The chain name. + string name; + // The chain's Chain ID. + uint256 chainId; + // A default RPC endpoint for this chain. + // NOTE: This default RPC URL is included for convenience to facilitate quick tests and + // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy + // usage as you will be throttled and this is a disservice to others who need this endpoint. + string rpcUrl; + } + + // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data. + mapping(string => Chain) private chains; + // Maps from the chain's alias to it's default RPC URL. + mapping(string => string) private defaultRpcUrls; + // Maps from a chain ID to it's alias. + mapping(uint256 => string) private idToAlias; + + // The RPC URL will be fetched from config or defaultRpcUrls if possible. + function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) { + require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string."); + + initialize(); + chain = chains[chainAlias]; + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + function getChain(uint256 chainId) internal virtual returns (Chain memory chain) { + require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0."); + initialize(); + string memory chainAlias = idToAlias[chainId]; + + chain = chains[chainAlias]; + + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, Chain memory chain) internal virtual { + require( + bytes(chainAlias).length != 0, "StdChains setChain(string,Chain): Chain alias cannot be the empty string." + ); + + require(chain.chainId != 0, "StdChains setChain(string,Chain): Chain ID cannot be 0."); + + initialize(); + string memory foundAlias = idToAlias[chain.chainId]; + + require( + bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)), + string( + abi.encodePacked( + "StdChains setChain(string,Chain): Chain ID ", + vm.toString(chain.chainId), + " already used by \"", + foundAlias, + "\"." + ) + ) + ); + + uint256 oldChainId = chains[chainAlias].chainId; + delete idToAlias[oldChainId]; + + chains[chainAlias] = chain; + idToAlias[chain.chainId] = chainAlias; + } + + // lookup rpcUrl, in descending order of priority: + // current -> config (foundry.toml) -> default + function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) + private + view + returns (Chain memory) + { + if (bytes(chain.rpcUrl).length == 0) { + try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) { + chain.rpcUrl = configRpcUrl; + } catch (bytes memory err) { + chain.rpcUrl = defaultRpcUrls[chainAlias]; + // distinguish 'not found' from 'cannot read' + bytes memory notFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + if (keccak256(notFoundError) != keccak256(err) || bytes(chain.rpcUrl).length == 0) { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, err), mload(err)) + } + } + } + } + return chain; + } + + function initialize() private { + if (initialized) return; + + initialized = true; + + // If adding an RPC here, make sure to test the default RPC URL in `testRpcs` + setChainWithDefaultRpcUrl("anvil", Chain("Anvil", 31337, "http://127.0.0.1:8545")); + setChainWithDefaultRpcUrl( + "mainnet", Chain("Mainnet", 1, "https://mainnet.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl( + "goerli", Chain("Goerli", 5, "https://goerli.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl( + "sepolia", Chain("Sepolia", 11155111, "https://sepolia.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl("optimism", Chain("Optimism", 10, "https://mainnet.optimism.io")); + setChainWithDefaultRpcUrl("optimism_goerli", Chain("Optimism Goerli", 420, "https://goerli.optimism.io")); + setChainWithDefaultRpcUrl("arbitrum_one", Chain("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl( + "arbitrum_one_goerli", Chain("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc") + ); + setChainWithDefaultRpcUrl("arbitrum_nova", Chain("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl("polygon", Chain("Polygon", 137, "https://polygon-rpc.com")); + setChainWithDefaultRpcUrl("polygon_mumbai", Chain("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com")); + setChainWithDefaultRpcUrl("avalanche", Chain("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc")); + setChainWithDefaultRpcUrl( + "avalanche_fuji", Chain("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc") + ); + setChainWithDefaultRpcUrl("bnb_smart_chain", Chain("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org")); + setChainWithDefaultRpcUrl("bnb_smart_chain_testnet", Chain("BNB Smart Chain Testnet", 97, "https://data-seed-prebsc-1-s1.binance.org:8545"));// forgefmt: disable-line + setChainWithDefaultRpcUrl("gnosis_chain", Chain("Gnosis Chain", 100, "https://rpc.gnosischain.com")); + } + + // set chain info, with priority to chainAlias' rpc url in foundry.toml + function setChainWithDefaultRpcUrl(string memory chainAlias, Chain memory chain) private { + string memory rpcUrl = chain.rpcUrl; + defaultRpcUrls[chainAlias] = rpcUrl; + chain.rpcUrl = ""; + setChain(chainAlias, chain); + chain.rpcUrl = rpcUrl; // restore argument + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..f7204a5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {Vm} from "./Vm.sol"; + +abstract contract StdCheatsSafe { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private gasMeteringOff; + + // Data structures to parse Transaction objects from the broadcast artifact + // that conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawTx1559 { + string[] arguments; + address contractAddress; + string contractName; + // json value name = function + string functionSig; + bytes32 hash; + // json value name = tx + RawTx1559Detail txDetail; + // json value name = type + string opcode; + } + + struct RawTx1559Detail { + AccessList[] accessList; + bytes data; + address from; + bytes gas; + bytes nonce; + address to; + bytes txType; + bytes value; + } + + struct Tx1559 { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + bytes32 hash; + Tx1559Detail txDetail; + string opcode; + } + + struct Tx1559Detail { + AccessList[] accessList; + bytes data; + address from; + uint256 gas; + uint256 nonce; + address to; + uint256 txType; + uint256 value; + } + + // Data structures to parse Transaction objects from the broadcast artifact + // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct TxLegacy { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + string hash; + string opcode; + TxDetailLegacy transaction; + } + + struct TxDetailLegacy { + AccessList[] accessList; + uint256 chainId; + bytes data; + address from; + uint256 gas; + uint256 gasPrice; + bytes32 hash; + uint256 nonce; + bytes1 opcode; + bytes32 r; + bytes32 s; + uint256 txType; + address to; + uint8 v; + uint256 value; + } + + struct AccessList { + address accessAddress; + bytes32[] storageKeys; + } + + // Data structures to parse Receipt objects from the broadcast artifact. + // The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawReceipt { + bytes32 blockHash; + bytes blockNumber; + address contractAddress; + bytes cumulativeGasUsed; + bytes effectiveGasPrice; + address from; + bytes gasUsed; + RawReceiptLog[] logs; + bytes logsBloom; + bytes status; + address to; + bytes32 transactionHash; + bytes transactionIndex; + } + + struct Receipt { + bytes32 blockHash; + uint256 blockNumber; + address contractAddress; + uint256 cumulativeGasUsed; + uint256 effectiveGasPrice; + address from; + uint256 gasUsed; + ReceiptLog[] logs; + bytes logsBloom; + uint256 status; + address to; + bytes32 transactionHash; + uint256 transactionIndex; + } + + // Data structures to parse the entire broadcast artifact, assuming the + // transactions conform to EIP1559. + + struct EIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + Receipt[] receipts; + uint256 timestamp; + Tx1559[] transactions; + TxReturn[] txReturns; + } + + struct RawEIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + RawReceipt[] receipts; + TxReturn[] txReturns; + uint256 timestamp; + RawTx1559[] transactions; + } + + struct RawReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + bytes blockNumber; + bytes data; + bytes logIndex; + bool removed; + bytes32[] topics; + bytes32 transactionHash; + bytes transactionIndex; + bytes transactionLogIndex; + } + + struct ReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + uint256 blockNumber; + bytes data; + uint256 logIndex; + bytes32[] topics; + uint256 transactionIndex; + uint256 transactionLogIndex; + bool removed; + } + + struct TxReturn { + string internalType; + string value; + } + + function assumeNoPrecompiles(address addr) internal virtual { + // Assembly required since `block.chainid` was introduced in 0.8.0. + uint256 chainId; + assembly { + chainId := chainid() + } + assumeNoPrecompiles(addr, chainId); + } + + function assumeNoPrecompiles(address addr, uint256 chainId) internal virtual { + // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific + // address), but the same rationale for excluding them applies so we include those too. + + // These should be present on all EVM-compatible chains. + vm.assume(addr < address(0x1) || addr > address(0x9)); + + // forgefmt: disable-start + if (chainId == 10 || chainId == 420) { + // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21 + vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800)); + } else if (chainId == 42161 || chainId == 421613) { + // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains + vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068)); + } else if (chainId == 43114 || chainId == 43113) { + // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59 + vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff)); + vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF)); + vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff)); + } + // forgefmt: disable-end + } + + function readEIP1559ScriptArtifact(string memory path) + internal + view + virtual + returns (EIP1559ScriptArtifact memory) + { + string memory data = vm.readFile(path); + bytes memory parsedData = vm.parseJson(data); + RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact)); + EIP1559ScriptArtifact memory artifact; + artifact.libraries = rawArtifact.libraries; + artifact.path = rawArtifact.path; + artifact.timestamp = rawArtifact.timestamp; + artifact.pending = rawArtifact.pending; + artifact.txReturns = rawArtifact.txReturns; + artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts); + artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions); + return artifact; + } + + function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) { + Tx1559[] memory txs = new Tx1559[](rawTxs.length); + for (uint256 i; i < rawTxs.length; i++) { + txs[i] = rawToConvertedEIPTx1559(rawTxs[i]); + } + return txs; + } + + function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) { + Tx1559 memory transaction; + transaction.arguments = rawTx.arguments; + transaction.contractName = rawTx.contractName; + transaction.functionSig = rawTx.functionSig; + transaction.hash = rawTx.hash; + transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail); + transaction.opcode = rawTx.opcode; + return transaction; + } + + function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail) + internal + pure + virtual + returns (Tx1559Detail memory) + { + Tx1559Detail memory txDetail; + txDetail.data = rawDetail.data; + txDetail.from = rawDetail.from; + txDetail.to = rawDetail.to; + txDetail.nonce = _bytesToUint(rawDetail.nonce); + txDetail.txType = _bytesToUint(rawDetail.txType); + txDetail.value = _bytesToUint(rawDetail.value); + txDetail.gas = _bytesToUint(rawDetail.gas); + txDetail.accessList = rawDetail.accessList; + return txDetail; + } + + function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions"); + RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[])); + return rawToConvertedEIPTx1559s(rawTxs); + } + + function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559)); + return rawToConvertedEIPTx1559(rawTx); + } + + // Analogous to readTransactions, but for receipts. + function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts"); + RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[])); + return rawToConvertedReceipts(rawReceipts); + } + + function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt)); + return rawToConvertedReceipt(rawReceipt); + } + + function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) { + Receipt[] memory receipts = new Receipt[](rawReceipts.length); + for (uint256 i; i < rawReceipts.length; i++) { + receipts[i] = rawToConvertedReceipt(rawReceipts[i]); + } + return receipts; + } + + function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) { + Receipt memory receipt; + receipt.blockHash = rawReceipt.blockHash; + receipt.to = rawReceipt.to; + receipt.from = rawReceipt.from; + receipt.contractAddress = rawReceipt.contractAddress; + receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice); + receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed); + receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed); + receipt.status = _bytesToUint(rawReceipt.status); + receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex); + receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber); + receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs); + receipt.logsBloom = rawReceipt.logsBloom; + receipt.transactionHash = rawReceipt.transactionHash; + return receipt; + } + + function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs) + internal + pure + virtual + returns (ReceiptLog[] memory) + { + ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length); + for (uint256 i; i < rawLogs.length; i++) { + logs[i].logAddress = rawLogs[i].logAddress; + logs[i].blockHash = rawLogs[i].blockHash; + logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber); + logs[i].data = rawLogs[i].data; + logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex); + logs[i].topics = rawLogs[i].topics; + logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex); + logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex); + logs[i].removed = rawLogs[i].removed; + } + return logs; + } + + // Deploy a contract by fetching the contract bytecode from + // the artifacts directory + // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))` + function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed."); + } + + function deployCode(string memory what) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string): Deployment failed."); + } + + /// @dev deploy contract with value on construction + function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed."); + } + + function deployCode(string memory what, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed."); + } + + // creates a labeled address and the corresponding private key + function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) { + privateKey = uint256(keccak256(abi.encodePacked(name))); + addr = vm.addr(privateKey); + vm.label(addr, name); + } + + // creates a labeled address + function makeAddr(string memory name) internal virtual returns (address addr) { + (addr,) = makeAddrAndKey(name); + } + + function deriveRememberKey(string memory mnemonic, uint32 index) + internal + virtual + returns (address who, uint256 privateKey) + { + privateKey = vm.deriveKey(mnemonic, index); + who = vm.rememberKey(privateKey); + } + + function _bytesToUint(bytes memory b) private pure returns (uint256) { + require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function isFork() internal virtual returns (bool status) { + try vm.activeFork() { + status = true; + } catch (bytes memory) {} + } + + modifier skipWhenForking() { + if (!isFork()) { + _; + } + } + + modifier skipWhenNotForking() { + if (isFork()) { + _; + } + } + + modifier noGasMetering() { + vm.pauseGasMetering(); + // To prevent turning gas monitoring back on with nested functions that use this modifier, + // we check if gasMetering started in the off position. If it did, we don't want to turn + // it back on until we exit the top level function that used the modifier + // + // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well. + // funcA will have `gasStartedOff` as false, funcB will have it as true, + // so we only turn metering back on at the end of the funcA + bool gasStartedOff = gasMeteringOff; + gasMeteringOff = true; + + _; + + // if gas metering was on when this modifier was called, turn it back on at the end + if (!gasStartedOff) { + gasMeteringOff = false; + vm.resumeGasMetering(); + } + } +} + +// Wrappers around cheatcodes to avoid footguns +abstract contract StdCheats is StdCheatsSafe { + using stdStorage for StdStorage; + + StdStorage private stdstore; + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + // Skip forward or rewind time by the specified number of seconds + function skip(uint256 time) internal virtual { + vm.warp(block.timestamp + time); + } + + function rewind(uint256 time) internal virtual { + vm.warp(block.timestamp - time); + } + + // Setup a prank from an address that has some ether + function hoax(address who) internal virtual { + vm.deal(who, 1 << 128); + vm.prank(who); + } + + function hoax(address who, uint256 give) internal virtual { + vm.deal(who, give); + vm.prank(who); + } + + function hoax(address who, address origin) internal virtual { + vm.deal(who, 1 << 128); + vm.prank(who, origin); + } + + function hoax(address who, address origin, uint256 give) internal virtual { + vm.deal(who, give); + vm.prank(who, origin); + } + + // Start perpetual prank from an address that has some ether + function startHoax(address who) internal virtual { + vm.deal(who, 1 << 128); + vm.startPrank(who); + } + + function startHoax(address who, uint256 give) internal virtual { + vm.deal(who, give); + vm.startPrank(who); + } + + // Start perpetual prank from an address that has some ether + // tx.origin is set to the origin parameter + function startHoax(address who, address origin) internal virtual { + vm.deal(who, 1 << 128); + vm.startPrank(who, origin); + } + + function startHoax(address who, address origin, uint256 give) internal virtual { + vm.deal(who, give); + vm.startPrank(who, origin); + } + + function changePrank(address who) internal virtual { + vm.stopPrank(); + vm.startPrank(who); + } + + // The same as Vm's `deal` + // Use the alternative signature for ERC20 tokens + function deal(address to, uint256 give) internal virtual { + vm.deal(to, give); + } + + // Set the balance of an account for any ERC20 token + // Use the alternative signature to update `totalSupply` + function deal(address token, address to, uint256 give) internal virtual { + deal(token, to, give, false); + } + + function deal(address token, address to, uint256 give, bool adjust) internal virtual { + // get current balance + (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to)); + uint256 prevBal = abi.decode(balData, (uint256)); + + // update balance + stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give); + + // update total supply + if (adjust) { + (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd)); + uint256 totSup = abi.decode(totSupData, (uint256)); + if (give < prevBal) { + totSup -= (prevBal - give); + } else { + totSup += (give - prevBal); + } + stdstore.target(token).sig(0x18160ddd).checked_write(totSup); + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test +pragma solidity >=0.6.2 <0.9.0; + +library stdError { + bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); + bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); + bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); + bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); + bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); + bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); + bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); + bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); + bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..2dee471 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +// Helpers for parsing and writing JSON files +// To parse: +// ``` +// using stdJson for string; +// string memory json = vm.readFile("some_peth"); +// json.parseUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "deploymentArtifact"; +// Contract contract = new Contract(); +// json.serialize("contractAddress", address(contract)); +// json = json.serialize("deploymentTimes", uint(1)); +// // store the stringified JSON to the 'json' variable we have been using as a key +// // as we won't need it any longer +// string memory json2 = "finalArtifact"; +// string memory final = json2.serialize("depArtifact", json); +// final.write(""); +// ``` + +library stdJson { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) { + return vm.parseJson(json, key); + } + + function readUint(string memory json, string memory key) internal pure returns (uint256) { + return abi.decode(vm.parseJson(json, key), (uint256)); + } + + function readUintArray(string memory json, string memory key) internal pure returns (uint256[] memory) { + return abi.decode(vm.parseJson(json, key), (uint256[])); + } + + function readInt(string memory json, string memory key) internal pure returns (int256) { + return abi.decode(vm.parseJson(json, key), (int256)); + } + + function readIntArray(string memory json, string memory key) internal pure returns (int256[] memory) { + return abi.decode(vm.parseJson(json, key), (int256[])); + } + + function readBytes32(string memory json, string memory key) internal pure returns (bytes32) { + return abi.decode(vm.parseJson(json, key), (bytes32)); + } + + function readBytes32Array(string memory json, string memory key) internal pure returns (bytes32[] memory) { + return abi.decode(vm.parseJson(json, key), (bytes32[])); + } + + function readString(string memory json, string memory key) internal pure returns (string memory) { + return abi.decode(vm.parseJson(json, key), (string)); + } + + function readStringArray(string memory json, string memory key) internal pure returns (string[] memory) { + return abi.decode(vm.parseJson(json, key), (string[])); + } + + function readAddress(string memory json, string memory key) internal pure returns (address) { + return abi.decode(vm.parseJson(json, key), (address)); + } + + function readAddressArray(string memory json, string memory key) internal pure returns (address[] memory) { + return abi.decode(vm.parseJson(json, key), (address[])); + } + + function readBool(string memory json, string memory key) internal pure returns (bool) { + return abi.decode(vm.parseJson(json, key), (bool)); + } + + function readBoolArray(string memory json, string memory key) internal pure returns (bool[] memory) { + return abi.decode(vm.parseJson(json, key), (bool[])); + } + + function readBytes(string memory json, string memory key) internal pure returns (bytes memory) { + return abi.decode(vm.parseJson(json, key), (bytes)); + } + + function readBytesArray(string memory json, string memory key) internal pure returns (bytes[] memory) { + return abi.decode(vm.parseJson(json, key), (bytes[])); + } + + function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bool[] memory value) + internal + returns (string memory) + { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256[] memory value) + internal + returns (string memory) + { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256[] memory value) + internal + returns (string memory) + { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address[] memory value) + internal + returns (string memory) + { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string[] memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function write(string memory jsonKey, string memory path) internal { + vm.writeJson(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeJson(jsonKey, path, valueKey); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +library stdMath { + int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; + + function abs(int256 a) internal pure returns (uint256) { + // Required or it will fail when `a = type(int256).min` + if (a == INT256_MIN) { + return 57896044618658097711785492504343953926634992332820282019728792003956564819968; + } + + return uint256(a > 0 ? a : -a); + } + + function delta(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a - b : b - a; + } + + function delta(int256 a, int256 b) internal pure returns (uint256) { + // a and b are of the same sign + // this works thanks to two's complement, the left-most bit is the sign bit + if ((a ^ b) > -1) { + return delta(abs(a), abs(b)); + } + + // a and b are of opposite signs + return abs(a) + abs(b); + } + + function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + + return absDelta * 1e18 / b; + } + + function percentDelta(int256 a, int256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + uint256 absB = abs(b); + + return absDelta * 1e18 / absB; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..b0bfc00 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; + mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; +} + +library stdStorageSafe { + event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot); + event WARNING_UninitedSlot(address who, uint256 slot); + + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against + // slot complexity: + // if flat, will be bytes32(uint256(uint)); + // if map, will be keccak256(abi.encode(key, uint(slot))); + // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot))))); + // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); + function find(StdStorage storage self) internal returns (uint256) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + vm.record(); + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + (bytes32[] memory reads,) = vm.accesses(address(who)); + if (reads.length == 1) { + bytes32 curr = vm.load(who, reads[0]); + if (curr == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[0])); + } + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + } else if (reads.length > 1) { + for (uint256 i = 0; i < reads.length; i++) { + bytes32 prev = vm.load(who, reads[i]); + if (prev == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[i])); + } + // store + vm.store(who, reads[i], bytes32(hex"1337")); + bool success; + bytes memory rdat; + { + (success, rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + if (success && fdat == bytes32(hex"1337")) { + // we found which of the slots is the actual one + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + vm.store(who, reads[i], prev); + break; + } + vm.store(who, reads[i], prev); + } + } else { + require(false, "stdStorage find(StdStorage): No storage use detected for target."); + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], + "stdStorage find(StdStorage): Slot(s) not found." + ); + + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + self._target = _target; + return self; + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + self._sig = _sig; + return self; + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + self._sig = sigs(_sig); + return self; + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + self._keys.push(bytes32(uint256(uint160(who)))); + return self; + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + self._keys.push(bytes32(amt)); + return self; + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + self._keys.push(key); + return self; + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + self._depth = _depth; + return self; + } + + function read(StdStorage storage self) private returns (bytes memory) { + address t = self._target; + uint256 s = find(self); + return abi.encode(vm.load(t, bytes32(s))); + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return abi.decode(read(self), (bytes32)); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + int256 v = read_int(self); + if (v == 0) return false; + if (v == 1) return true; + revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + } + + function read_address(StdStorage storage self) internal returns (address) { + return abi.decode(read(self), (address)); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return abi.decode(read(self), (uint256)); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return abi.decode(read(self), (int256)); + } + + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} + +library stdStorage { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return stdStorageSafe.sigs(sigStr); + } + + function find(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.find(self); + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + return stdStorageSafe.target(self, _target); + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, who); + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, amt); + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, key); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function checked_write(StdStorage storage self, address who) internal { + checked_write(self, bytes32(uint256(uint160(who)))); + } + + function checked_write(StdStorage storage self, uint256 amt) internal { + checked_write(self, bytes32(amt)); + } + + function checked_write(StdStorage storage self, bool write) internal { + bytes32 t; + /// @solidity memory-safe-assembly + assembly { + t := write + } + checked_write(self, t); + } + + function checked_write(StdStorage storage self, bytes32 set) internal { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + find(self); + } + bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]); + + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + bytes32 curr = vm.load(who, slot); + + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + vm.store(who, slot, set); + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return stdStorageSafe.read_bytes32(self); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + return stdStorageSafe.read_bool(self); + } + + function read_address(StdStorage storage self) internal returns (address) { + return stdStorageSafe.read_address(self); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.read_uint(self); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return stdStorageSafe.read_int(self); + } + + // Private function so needs to be copied over + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + // Private function so needs to be copied over + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..a283e75 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// TODO Remove import. +import {VmSafe} from "./Vm.sol"; + +abstract contract StdUtils { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; + + uint256 private constant INT256_MIN_ABS = + 57896044618658097711785492504343953926634992332820282019728792003956564819968; + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { + require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); + // If x is between min and max, return x directly. This is to ensure that dictionary values + // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 + if (x >= min && x <= max) return x; + + uint256 size = max - min + 1; + + // If the value is 0, 1, 2, 3, warp that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. + // This helps ensure coverage of the min/max values. + if (x <= 3 && size > x) return min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); + + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. + if (x > max) { + uint256 diff = x - max; + uint256 rem = diff % size; + if (rem == 0) return max; + result = min + rem - 1; + } else if (x < min) { + uint256 diff = min - x; + uint256 rem = diff % size; + if (rem == 0) return min; + result = max - rem + 1; + } + } + + function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log("Bound Result", result); + } + + function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) { + require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min."); + + // Shifting all int256 values to uint256 to use _bound function. The range of two types are: + // int256 : -(2**255) ~ (2**255 - 1) + // uint256: 0 ~ (2**256 - 1) + // So, add 2**255, INT256_MIN_ABS to the integer values. + // + // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow. + // So, use `~uint256(x) + 1` instead. + uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS); + uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS); + uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS); + + uint256 y = _bound(_x, _min, _max); + + // To move it back to int256 value, subtract INT256_MIN_ABS at here. + result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS); + console2_log("Bound result", vm.toString(result)); + } + + /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce + /// @notice adapated from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) + function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { + // forgefmt: disable-start + // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0. + // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it. + if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80)))); + if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce)))); + + // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length. + if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce)))); + if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce)))); + if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce)))); + // forgefmt: disable-end + + // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp + // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) + // We assume nobody can have a nonce large enough to require more than 32 bytes. + return addressFromLast20Bytes( + keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))) + ); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash))); + } + + function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { + require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { + return address(uint160(uint256(bytesValue))); + } + + // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere. + + function console2_log(string memory p0, uint256 p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + status; + } + + function console2_log(string memory p0, string memory p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1)); + status; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..6c26230 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Standard Library's default Test + +// 🧩 MODULES +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdAssertions} from "./StdAssertions.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheats} from "./StdCheats.sol"; +import {stdError} from "./StdError.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; +import {DSTest} from "ds-test/test.sol"; + +// ⭐️ TEST +abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdUtils, TestBase { +// Note: IS_TEST() must return true. +// Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76. +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..6ebde70 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// Cheatcodes are marked as view/pure/none using the following rules: +// 0. A call's observable behaviour includes its return value, logs, reverts and state writes, +// 1. If you can influence a later call's observable behaviour, you're neither `view` nor `pure (you are modifying some state be it the EVM, interpreter, filesystem, etc), +// 2. Otherwise if you can be influenced by an earlier call, or if reading some state, you're `view`, +// 3. Otherwise you're `pure`. + +interface VmSafe { + struct Log { + bytes32[] topics; + bytes data; + address emitter; + } + + struct Rpc { + string key; + string url; + } + + struct FsMetadata { + bool isDir; + bool isSymlink; + uint256 length; + bool readOnly; + uint256 modified; + uint256 accessed; + uint256 created; + } + + // Loads a storage slot from an address + function load(address target, bytes32 slot) external view returns (bytes32 data); + // Signs data + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + // Gets the address for a given private key + function addr(uint256 privateKey) external pure returns (address addr); + // Gets the nonce of an account + function getNonce(address account) external view returns (uint64 nonce); + // Performs a foreign function call via the terminal + function ffi(string[] calldata commandInput) external returns (bytes memory result); + // Sets environment variables + function setEnv(string calldata name, string calldata value) external; + // Reads environment variables, (name) => (value) + function envBool(string calldata name) external view returns (bool value); + function envUint(string calldata name) external view returns (uint256 value); + function envInt(string calldata name) external view returns (int256 value); + function envAddress(string calldata name) external view returns (address value); + function envBytes32(string calldata name) external view returns (bytes32 value); + function envString(string calldata name) external view returns (string memory value); + function envBytes(string calldata name) external view returns (bytes memory value); + // Reads environment variables as arrays + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + // Read environment variables with default value + function envOr(string calldata name, bool defaultValue) external returns (bool value); + function envOr(string calldata name, uint256 defaultValue) external returns (uint256 value); + function envOr(string calldata name, int256 defaultValue) external returns (int256 value); + function envOr(string calldata name, address defaultValue) external returns (address value); + function envOr(string calldata name, bytes32 defaultValue) external returns (bytes32 value); + function envOr(string calldata name, string calldata defaultValue) external returns (string memory value); + function envOr(string calldata name, bytes calldata defaultValue) external returns (bytes memory value); + // Read environment variables as arrays with default value + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + returns (bool[] memory value); + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + returns (uint256[] memory value); + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + returns (int256[] memory value); + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + returns (address[] memory value); + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + returns (bytes32[] memory value); + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + returns (string[] memory value); + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + returns (bytes[] memory value); + // Records all storage reads and writes + function record() external; + // Gets all accessed reads and write slot from a recording session, for a given address + function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots); + // Gets the _creation_ bytecode from an artifact file. Takes in the relative path to the json file + function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode); + // Gets the _deployed_ bytecode from an artifact file. Takes in the relative path to the json file + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + // Labels an address in call traces + function label(address account, string calldata newLabel) external; + // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain + function broadcast() external; + // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain + function broadcast(address signer) external; + // Has the next call (at this call depth only) create a transaction with the private key provided as the sender that can later be signed and sent onchain + function broadcast(uint256 privateKey) external; + // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain + function startBroadcast() external; + // Has all subsequent calls (at this call depth only) create transactions with the address provided that can later be signed and sent onchain + function startBroadcast(address signer) external; + // Has all subsequent calls (at this call depth only) create transactions with the private key provided that can later be signed and sent onchain + function startBroadcast(uint256 privateKey) external; + // Stops collecting onchain transactions + function stopBroadcast() external; + // Reads the entire content of file to string + function readFile(string calldata path) external view returns (string memory data); + // Reads the entire content of file as binary. Path is relative to the project root. + function readFileBinary(string calldata path) external view returns (bytes memory data); + // Get the path of the current project root + function projectRoot() external view returns (string memory path); + // Get the metadata for a file/directory + function fsMetadata(string calldata fileOrDir) external returns (FsMetadata memory metadata); + // Reads next line of file to string + function readLine(string calldata path) external view returns (string memory line); + // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does. + function writeFile(string calldata path, string calldata data) external; + // Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does. + // Path is relative to the project root. + function writeFileBinary(string calldata path, bytes calldata data) external; + // Writes line to file, creating a file if it does not exist. + function writeLine(string calldata path, string calldata data) external; + // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine. + function closeFile(string calldata path) external; + // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases: + // - Path points to a directory. + // - The file doesn't exist. + // - The user lacks permissions to remove the file. + function removeFile(string calldata path) external; + // Convert values to a string + function toString(address value) external pure returns (string memory stringifiedValue); + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + function toString(bool value) external pure returns (string memory stringifiedValue); + function toString(uint256 value) external pure returns (string memory stringifiedValue); + function toString(int256 value) external pure returns (string memory stringifiedValue); + // Convert values from a string + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + // Record all the transaction logs + function recordLogs() external; + // Gets all the recorded logs + function getRecordedLogs() external returns (Log[] memory logs); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index} + function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at {derivationPath}{index} + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index) + external + pure + returns (uint256 privateKey); + // Adds a private key to the local forge wallet and returns the address + function rememberKey(uint256 privateKey) external returns (address addr); + // + // parseJson + // + // ---- + // In case the returned value is a JSON object, it's encoded as a ABI-encoded tuple. As JSON objects + // don't have the notion of ordered, but tuples do, they JSON object is encoded with it's fields ordered in + // ALPHABETICAL order. That means that in order to successfully decode the tuple, we need to define a tuple that + // encodes the fields in the same order, which is alphabetical. In the case of Solidity structs, they are encoded + // as tuples, with the attributes in the order in which they are defined. + // For example: json = { 'a': 1, 'b': 0xa4tb......3xs} + // a: uint256 + // b: address + // To decode that json, we need to define a struct or a tuple as follows: + // struct json = { uint256 a; address b; } + // If we defined a json struct with the opposite order, meaning placing the address b first, it would try to + // decode the tuple in that order, and thus fail. + // ---- + // Given a string of JSON, return it as ABI-encoded + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + // Serialize a key and value to a JSON object stored in-memory that can be later written to a file + // It returns the stringified version of the specific JSON file up to that moment. + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + // + // writeJson + // + // ---- + // Write a serialized JSON object to a file. If the file exists, it will be overwritten. + // Let's assume we want to write the following JSON to a file: + // + // { "boolean": true, "number": 342, "object": { "title": "finally json serialization" } } + // + // ``` + // string memory json1 = "some key"; + // vm.serializeBool(json1, "boolean", true); + // vm.serializeBool(json1, "number", uint256(342)); + // json2 = "some other key"; + // string memory output = vm.serializeString(json2, "title", "finally json serialization"); + // string memory finalJson = vm.serialize(json1, "object", output); + // vm.writeJson(finalJson, "./output/example.json"); + // ``` + // The critical insight is that every invocation of serialization will return the stringified version of the JSON + // up to that point. That means we can construct arbitrary JSON objects and then use the return stringified version + // to serialize them as values to another JSON object. + // + // json1 and json2 are simply keys used by the backend to keep track of the objects. So vm.serializeJson(json1,..) + // will find the object in-memory that is keyed by "some key". + function writeJson(string calldata json, string calldata path) external; + // Write a serialized JSON object to an **existing** JSON file, replacing a value with key = + // This is useful to replace a specific value of a JSON file, without having to parse the entire thing + function writeJson(string calldata json, string calldata path, string calldata valueKey) external; + // Returns the RPC url for the given alias + function rpcUrl(string calldata rpcAlias) external view returns (string memory json); + // Returns all rpc urls and their aliases `[alias, url][]` + function rpcUrls() external view returns (string[2][] memory urls); + // Returns all rpc urls and their aliases as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + // If the condition is false, discard this run's fuzz inputs and generate new ones. + function assume(bool condition) external pure; + // Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + // Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; +} + +interface Vm is VmSafe { + // Sets block.timestamp + function warp(uint256 newTimestamp) external; + // Sets block.height + function roll(uint256 newHeight) external; + // Sets block.basefee + function fee(uint256 newBasefee) external; + // Sets block.difficulty + function difficulty(uint256 newDifficulty) external; + // Sets block.chainid + function chainId(uint256 newChainId) external; + // Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) external; + // Sets the nonce of an account; must be higher than the current nonce of the account + function setNonce(address account, uint64 newNonce) external; + // Sets the *next* call's msg.sender to be the input address + function prank(address msgSender) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called + function startPrank(address msgSender) external; + // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input + function prank(address msgSender, address txOrigin) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input + function startPrank(address msgSender, address txOrigin) external; + // Resets subsequent calls' msg.sender to be `address(this)` + function stopPrank() external; + // Sets an address' balance + function deal(address account, uint256 newBalance) external; + // Sets an address' code + function etch(address target, bytes calldata newRuntimeBytecode) external; + // Expects an error on next call + function expectRevert(bytes calldata revertData) external; + function expectRevert(bytes4 revertData) external; + function expectRevert() external; + // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + // Call this function, then emit an event, then call a function. Internally after the call, we check if + // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external; + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) + external; + // Mocks a call to an address, returning specified data. + // Calldata can either be strict or a partial match, e.g. if you only + // pass a Solidity selector to the expected calldata, then the entire Solidity + // function will be mocked. + function mockCall(address callee, bytes calldata data, bytes calldata returnData) external; + // Mocks a call to an address with a specific msg.value, returning specified data. + // Calldata match takes precedence over msg.value in case of ambiguity. + function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external; + // Clears all mocked calls + function clearMockedCalls() external; + // Expects a call to an address with the specified calldata. + // Calldata can either be a strict or a partial match + function expectCall(address callee, bytes calldata data) external; + // Expects a call to an address with the specified msg.value and calldata + function expectCall(address callee, uint256 msgValue, bytes calldata data) external; + // Sets block.coinbase + function coinbase(address newCoinbase) external; + // Snapshot the current state of the evm. + // Returns the id of the snapshot that was created. + // To revert a snapshot use `revertTo` + function snapshot() external returns (uint256 snapshotId); + // Revert the state of the EVM to a previous snapshot + // Takes the snapshot id to revert to. + // This deletes the snapshot and all snapshots taken after the given snapshot id. + function revertTo(uint256 snapshotId) external returns (bool success); + // Creates a new fork with the given endpoint and block and returns the identifier of the fork + function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork + function createFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before the transaction, + // and returns the identifier of the fork + function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates _and_ also selects new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before + // the transaction, returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active. + function selectFork(uint256 forkId) external; + /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + // Updates the currently active fork to given block number + // This is similar to `roll` but for the currently active fork + function rollFork(uint256 blockNumber) external; + // Updates the currently active fork to given transaction + // this will `rollFork` with the number of the block the transaction was mined in and replays all transaction mined before it in the block + function rollFork(bytes32 txHash) external; + // Updates the given fork to given block number + function rollFork(uint256 forkId, uint256 blockNumber) external; + // Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block + function rollFork(uint256 forkId, bytes32 txHash) external; + // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup + // Meaning, changes made to the state of this account will be kept when switching forks + function makePersistent(address account) external; + function makePersistent(address account0, address account1) external; + function makePersistent(address account0, address account1, address account2) external; + function makePersistent(address[] calldata accounts) external; + // Revokes persistent status from the address, previously added via `makePersistent` + function revokePersistent(address account) external; + function revokePersistent(address[] calldata accounts) external; + // Returns true if the account is marked as persistent + function isPersistent(address account) external view returns (bool persistent); + // In forking mode, explicitly grant the given address cheatcode access + function allowCheatcodes(address account) external; + // Fetches the given transaction from the active fork and executes it on the current state + function transact(bytes32 txHash) external; + // Fetches the given transaction from the given fork and executes it on the current state + function transact(uint256 forkId, bytes32 txHash) external; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/console.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/console.sol new file mode 100644 index 0000000..ad57e53 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/console.sol @@ -0,0 +1,1533 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..8596233 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol @@ -0,0 +1,1546 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +/// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should +/// use `int256` and `uint256`. This modified version fixes that. This version is recommended +/// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in +/// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`. +/// Reference: https://github.com/NomicFoundation/hardhat/issues/2178 +library console2 { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function logUint(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function log(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint256 p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); + } + + function log(uint256 p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); + } + + function log(uint256 p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); + } + + function log(uint256 p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); + } + + function log(string memory p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function log(string memory p0, int256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint256 p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..f7dd2b4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-1155 Multi Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-1155 +/// Note: The ERC-165 identifier for this interface is 0xd9b67a26. +interface IERC1155 is IERC165 { + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_id` argument MUST be the token type being transferred. + /// - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferSingle( + address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value + ); + + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_ids` argument MUST be the list of tokens being transferred. + /// - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferBatch( + address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values + ); + + /// @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled). + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. + /// The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". + event URI(string _value, uint256 indexed _id); + + /// @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + /// - MUST revert on any other error. + /// - MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + /// - After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _id ID of the token type + /// @param _value Transfer amount + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; + + /// @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if length of `_ids` is not the same as length of `_values`. + /// - MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + /// - MUST revert on any other error. + /// - MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + /// - Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + /// - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _ids IDs of each token type (order and length must match _values array) + /// @param _values Transfer amounts per token type (order and length must match _ids array) + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + function safeBatchTransferFrom( + address _from, + address _to, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data + ) external; + + /// @notice Get the balance of an account's tokens. + /// @param _owner The address of the token holder + /// @param _id ID of the token + /// @return The _owner's balance of the token type requested + function balanceOf(address _owner, uint256 _id) external view returns (uint256); + + /// @notice Get the balance of multiple account/token pairs + /// @param _owners The addresses of the token holders + /// @param _ids ID of the tokens + /// @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair) + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) + external + view + returns (uint256[] memory); + + /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + /// @dev MUST emit the ApprovalForAll event on success. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Queries the approval status of an operator for a given owner. + /// @param _owner The owner of the tokens + /// @param _operator Address of authorized operator + /// @return True if the operator is approved, false if not + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +interface IERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +/// @dev Interface of the ERC20 standard as defined in the EIP. +/// @dev This includes the optional name, symbol, and decimals metadata. +interface IERC20 { + /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` + /// is the new allowance. + event Approval(address indexed owner, address indexed spender, uint256 value); + + /// @notice Returns the amount of tokens in existence. + function totalSupply() external view returns (uint256); + + /// @notice Returns the amount of tokens owned by `account`. + function balanceOf(address account) external view returns (uint256); + + /// @notice Moves `amount` tokens from the caller's account to `to`. + function transfer(address to, uint256 amount) external returns (bool); + + /// @notice Returns the remaining number of tokens that `spender` is allowed + /// to spend on behalf of `owner` + function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. + /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. + /// `amount` is then deducted from the caller's allowance. + function transferFrom(address from, address to, uint256 amount) external returns (bool); + + /// @notice Returns the name of the token. + function name() external view returns (string memory); + + /// @notice Returns the symbol of the token. + function symbol() external view returns (string memory); + + /// @notice Returns the decimals places of the token. + function decimals() external view returns (uint8); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..bfe3a11 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC20.sol"; + +/// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in +/// https://eips.ethereum.org/EIPS/eip-4626 +interface IERC4626 is IERC20 { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares + ); + + /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + /// @dev + /// - MUST be an ERC-20 token contract. + /// - MUST NOT revert. + function asset() external view returns (address assetTokenAddress); + + /// @notice Returns the total amount of the underlying asset that is “managed” by Vault. + /// @dev + /// - SHOULD include any compounding that occurs from yield. + /// - MUST be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT revert. + function totalAssets() external view returns (uint256 totalManagedAssets); + + /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + /// through a deposit call. + /// @dev + /// - MUST return a limited value if receiver is subject to some deposit limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + /// - MUST NOT revert. + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + /// call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + /// in the same transaction. + /// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + /// deposit would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// deposit execution, and are accounted for during deposit. + /// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + /// @dev + /// - MUST return a limited value if receiver is subject to some mint limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + /// - MUST NOT revert. + function maxMint(address receiver) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + /// in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + /// same transaction. + /// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + /// would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by minting. + function previewMint(uint256 shares) external view returns (uint256 assets); + + /// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + /// execution, and are accounted for during mint. + /// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + /// Vault, through a withdraw call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST NOT revert. + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + /// call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + /// called + /// in the same transaction. + /// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + /// the withdrawal would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// withdraw execution, and are accounted for during withdraw. + /// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + /// through a redeem call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + /// - MUST NOT revert. + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + /// in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + /// same transaction. + /// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + /// redemption would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by redeeming. + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// redeem execution, and are accounted for during redeem. + /// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..0a16f45 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-721 Non-Fungible Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. +interface IERC721 is IERC165 { + /// @dev This emits when ownership of any NFT changes by any mechanism. + /// This event emits when NFTs are created (`from` == 0) and destroyed + /// (`to` == 0). Exception: during contract creation, any number of NFTs + /// may be created and assigned without emitting Transfer. At the time of + /// any transfer, the approved address for that NFT (if any) is reset to none. + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + + /// @dev This emits when the approved address for an NFT is changed or + /// reaffirmed. The zero address indicates there is no approved address. + /// When a Transfer event emits, this also indicates that the approved + /// address for that NFT (if any) is reset to none. + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + /// @dev This emits when an operator is enabled or disabled for an owner. + /// The operator can manage all NFTs of the owner. + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @notice Count all NFTs assigned to an owner + /// @dev NFTs assigned to the zero address are considered invalid, and this + /// function throws for queries about the zero address. + /// @param _owner An address for whom to query the balance + /// @return The number of NFTs owned by `_owner`, possibly zero + function balanceOf(address _owner) external view returns (uint256); + + /// @notice Find the owner of an NFT + /// @dev NFTs assigned to zero address are considered invalid, and queries + /// about them do throw. + /// @param _tokenId The identifier for an NFT + /// @return The address of the owner of the NFT + function ownerOf(uint256 _tokenId) external view returns (address); + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. When transfer is complete, this function + /// checks if `_to` is a smart contract (code size > 0). If so, it calls + /// `onERC721Received` on `_to` and throws if the return value is not + /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + /// @param data Additional data with no specified format, sent in call to `_to` + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev This works identically to the other function with an extra data parameter, + /// except this function just sets data to "". + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE + /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE + /// THEY MAY BE PERMANENTLY LOST + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Change or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param _approved The new approved NFT controller + /// @param _tokenId The NFT to approve + function approve(address _approved, uint256 _tokenId) external payable; + + /// @notice Enable or disable approval for a third party ("operator") to manage + /// all of `msg.sender`'s assets + /// @dev Emits the ApprovalForAll event. The contract MUST allow + /// multiple operators per owner. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Get the approved address for a single NFT + /// @dev Throws if `_tokenId` is not a valid NFT. + /// @param _tokenId The NFT to find the approved address for + /// @return The approved address for this NFT, or the zero address if there is none + function getApproved(uint256 _tokenId) external view returns (address); + + /// @notice Query if an address is an authorized operator for another address + /// @param _owner The address that owns the NFTs + /// @param _operator The address that acts on behalf of the owner + /// @return True if `_operator` is an approved operator for `_owner`, false otherwise + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} + +/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02. +interface IERC721TokenReceiver { + /// @notice Handle the receipt of an NFT + /// @dev The ERC721 smart contract calls this function on the recipient + /// after a `transfer`. This function MAY throw to revert and reject the + /// transfer. Return of other than the magic value MUST result in the + /// transaction being reverted. + /// Note: the contract address is always the message sender. + /// @param _operator The address which called `safeTransferFrom` function + /// @param _from The address which previously owned the token + /// @param _tokenId The NFT identifier which is being transferred + /// @param _data Additional data with no specified format + /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + /// unless throwing + function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) + external + returns (bytes4); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x5b5e139f. +interface IERC721Metadata is IERC721 { + /// @notice A descriptive name for a collection of NFTs in this contract + function name() external view returns (string memory _name); + + /// @notice An abbreviated name for NFTs in this contract + function symbol() external view returns (string memory _symbol); + + /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. + /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC + /// 3986. The URI may point to a JSON file that conforms to the "ERC721 + /// Metadata JSON Schema". + function tokenURI(uint256 _tokenId) external view returns (string memory); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x780e9d63. +interface IERC721Enumerable is IERC721 { + /// @notice Count NFTs tracked by this contract + /// @return A count of valid NFTs tracked by this contract, where each one of + /// them has an assigned and queryable owner not equal to the zero address + function totalSupply() external view returns (uint256); + + /// @notice Enumerate valid NFTs + /// @dev Throws if `_index` >= `totalSupply()`. + /// @param _index A counter less than `totalSupply()` + /// @return The token identifier for the `_index`th NFT, + /// (sort order not specified) + function tokenByIndex(uint256 _index) external view returns (uint256); + + /// @notice Enumerate NFTs assigned to an owner + /// @dev Throws if `_index` >= `balanceOf(_owner)` or if + /// `_owner` is the zero address, representing invalid NFTs. + /// @param _owner An address where we are interested in NFTs owned by them + /// @param _index A counter less than `balanceOf(_owner)` + /// @return The token identifier for the `_index`th NFT assigned to `_owner`, + /// (sort order not specified) + function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..4d5827d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdAssertionsTest is Test { + string constant CUSTOM_ERROR = "guh!"; + + bool constant EXPECT_PASS = false; + bool constant EXPECT_FAIL = true; + + TestTest t = new TestTest(); + + /*////////////////////////////////////////////////////////////////////////// + FAIL(STRING) + //////////////////////////////////////////////////////////////////////////*/ + + function testShouldFail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._fail(CUSTOM_ERROR); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_FALSE + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertFalse_Pass() external { + t._assertFalse(false, EXPECT_PASS); + } + + function testAssertFalse_Fail() external { + vm.expectEmit(false, false, false, true); + emit log("Error: Assertion Failed"); + t._assertFalse(true, EXPECT_FAIL); + } + + function testAssertFalse_Err_Pass() external { + t._assertFalse(false, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertFalse_Err_Fail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertFalse(true, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BOOL) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bool_Pass(bool a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bool_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bool]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BoolErr_Pass(bool a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BoolErr_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BYTES) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bytes_Pass(bytes calldata a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bytes_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bytes]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BytesErr_Pass(bytes calldata a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BytesErr_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(ARRAY) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_UintArr_Pass(uint256 e0, uint256 e1, uint256 e2) public { + uint256[] memory a = new uint256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + uint256[] memory b = new uint256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_IntArr_Pass(int256 e0, int256 e1, int256 e2) public { + int256[] memory a = new int256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + int256[] memory b = new int256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_AddressArr_Pass(address e0, address e1, address e2) public { + address[] memory a = new address[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + address[] memory b = new address[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_UintArr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_UintArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEqUint() public { + assertEqUint(uint8(1), uint128(1)); + assertEqUint(uint64(2), uint64(2)); + } + + function testFailAssertEqUint() public { + assertEqUint(uint64(1), uint96(2)); + assertEqUint(uint160(3), uint160(4)); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Int_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Int_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_IntErr_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_IntErr_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } +} + +contract TestTest is Test { + modifier expectFailure(bool expectFail) { + bool preState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + _; + bool postState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + + if (preState == true) { + return; + } + + if (expectFail) { + require(postState == true, "expected failure not triggered"); + + // unwind the expected failure + vm.store(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x00))); + } else { + require(postState == false, "unexpected failure was triggered"); + } + } + + function _fail(string memory err) external expectFailure(true) { + fail(err); + } + + function _assertFalse(bool data, bool expectFail) external expectFailure(expectFail) { + assertFalse(data); + } + + function _assertFalse(bool data, string memory err, bool expectFail) external expectFailure(expectFail) { + assertFalse(data, err); + } + + function _assertEq(bool a, bool b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bool a, bool b, string memory err, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b, err); + } + + function _assertEq(bytes memory a, bytes memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bytes memory a, bytes memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(int256[] memory a, int256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(address[] memory a, address[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(int256[] memory a, int256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(address[] memory a, address[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..3657510 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdChainsTest is Test { + function testChainRpcInitialization() public { + // RPCs specified in `foundry.toml` should be updated. + assertEq(getChain(1).rpcUrl, "https://mainnet.infura.io/v3/7a8769b798b642f6933f2ed52042bd70"); + assertEq(getChain("optimism_goerli").rpcUrl, "https://goerli.optimism.io/"); + assertEq(getChain("arbitrum_one_goerli").rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/"); + + // Other RPCs should remain unchanged. + assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545"); + assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/6770454bc6ea42c58aac12978531b93f"); + } + + function testRpc(string memory rpcAlias) internal { + string memory rpcUrl = getChain(rpcAlias).rpcUrl; + vm.createSelectFork(rpcUrl); + } + + // Ensure we can connect to the default RPC URL for each chain. + function testRpcs() public { + testRpc("mainnet"); + testRpc("goerli"); + testRpc("sepolia"); + testRpc("optimism"); + testRpc("optimism_goerli"); + testRpc("arbitrum_one"); + testRpc("arbitrum_one_goerli"); + testRpc("arbitrum_nova"); + testRpc("polygon"); + testRpc("polygon_mumbai"); + testRpc("avalanche"); + testRpc("avalanche_fuji"); + testRpc("bnb_smart_chain"); + testRpc("bnb_smart_chain_testnet"); + testRpc("gnosis_chain"); + } + + function testChainNoDefault() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found."); + getChain("does_not_exist"); + } + + function testSetChainFirstFails() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain ID 31337 already used by \"anvil\"."); + setChain("anvil2", Chain("Anvil", 31337, "URL")); + } + + function testChainBubbleUp() public { + setChain("needs_undefined_env_var", Chain("", 123456789, "")); + vm.expectRevert( + "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found" + ); + getChain("needs_undefined_env_var"); + } + + function testCannotSetChain_ChainIdExists() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + + vm.expectRevert('StdChains setChain(string,Chain): Chain ID 123456789 already used by "custom_chain".'); + + setChain("another_custom_chain", Chain("", 123456789, "")); + } + + function testSetChain() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + Chain memory customChain = getChain("custom_chain"); + assertEq(customChain.name, "Custom Chain"); + assertEq(customChain.chainId, 123456789); + assertEq(customChain.rpcUrl, "https://custom.chain/"); + Chain memory chainById = getChain(123456789); + assertEq(chainById.name, customChain.name); + assertEq(chainById.chainId, customChain.chainId); + assertEq(chainById.rpcUrl, customChain.rpcUrl); + } + + function testSetNoEmptyAlias() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain alias cannot be the empty string."); + setChain("", Chain("", 123456789, "")); + } + + function testSetNoChainId0() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain ID cannot be 0."); + setChain("alias", Chain("", 0, "")); + } + + function testGetNoChainId0() public { + vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0."); + getChain(0); + } + + function testGetNoEmptyAlias() public { + vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string."); + getChain(""); + } + + function testChainIdNotFound() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found."); + getChain("no_such_alias"); + } + + function testChainAliasNotFound() public { + vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found."); + getChain(321); + } + + function testSetChain_ExistingOne() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + assertEq(getChain(123456789).chainId, 123456789); + + setChain("custom_chain", Chain("Modified Chain", 999999999, "https://modified.chain/")); + vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); + getChain(123456789); + + Chain memory modifiedChain = getChain(999999999); + assertEq(modifiedChain.name, "Modified Chain"); + assertEq(modifiedChain.chainId, 999999999); + assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..2eab3c3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdCheats.sol"; +import "../src/Test.sol"; +import "../src/StdJson.sol"; + +contract StdCheatsTest is Test { + Bar test; + + using stdJson for string; + + function setUp() public { + test = new Bar(); + } + + function testSkip() public { + vm.warp(100); + skip(25); + assertEq(block.timestamp, 125); + } + + function testRewind() public { + vm.warp(100); + rewind(25); + assertEq(block.timestamp, 75); + } + + function testHoax() public { + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + } + + function testHoaxOrigin() public { + hoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + } + + function testHoaxDifferentAddresses() public { + hoax(address(1337), address(7331)); + test.origin{value: 100}(address(1337), address(7331)); + } + + function testStartHoax() public { + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testStartHoaxOrigin() public { + startHoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + test.origin{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testChangePrank() public { + vm.startPrank(address(1337)); + test.bar(address(1337)); + changePrank(address(0xdead)); + test.bar(address(0xdead)); + changePrank(address(1337)); + test.bar(address(1337)); + vm.stopPrank(); + } + + function testMakeAddrEquivalence() public { + (address addr,) = makeAddrAndKey("1337"); + assertEq(makeAddr("1337"), addr); + } + + function testMakeAddrSigning() public { + (address addr, uint256 key) = makeAddrAndKey("1337"); + bytes32 hash = keccak256("some_message"); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash); + assertEq(ecrecover(hash, v, r, s), addr); + } + + function testDeal() public { + deal(address(this), 1 ether); + assertEq(address(this).balance, 1 ether); + } + + function testDealToken() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18); + assertEq(barToken.balanceOf(address(this)), 10000e18); + } + + function testDealTokenAdjustTS() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18, true); + assertEq(barToken.balanceOf(address(this)), 10000e18); + assertEq(barToken.totalSupply(), 20000e18); + deal(bar, address(this), 0, true); + assertEq(barToken.balanceOf(address(this)), 0); + assertEq(barToken.totalSupply(), 10000e18); + } + + function testDeployCode() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes("")); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar"); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeVal() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes(""), 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + function testDeployCodeValNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar", 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + // We need this so we can call "this.deployCode" rather than "deployCode" directly + function deployCodeHelper(string memory what) external { + deployCode(what); + } + + function testDeployCodeFail() public { + vm.expectRevert(bytes("StdCheats deployCode(string): Deployment failed.")); + this.deployCodeHelper("StdCheats.t.sol:RevertingContract"); + } + + function getCode(address who) internal view returns (bytes memory o_code) { + /// @solidity memory-safe-assembly + assembly { + // retrieve the size of the code, this needs assembly + let size := extcodesize(who) + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + o_code := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(o_code, size) + // actually retrieve the code, this needs assembly + extcodecopy(who, add(o_code, 0x20), 0, size) + } + } + + function testDeriveRememberKey() public { + string memory mnemonic = "test test test test test test test test test test test junk"; + + (address deployer, uint256 privateKey) = deriveRememberKey(mnemonic, 0); + assertEq(deployer, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); + } + + function testBytesToUint() public { + assertEq(3, bytesToUint_test(hex"03")); + assertEq(2, bytesToUint_test(hex"02")); + assertEq(255, bytesToUint_test(hex"ff")); + assertEq(29625, bytesToUint_test(hex"73b9")); + } + + function testParseJsonTxDetail() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + string memory json = vm.readFile(path); + bytes memory transactionDetails = json.parseRaw(".transactions[0].tx"); + RawTx1559Detail memory rawTxDetail = abi.decode(transactionDetails, (RawTx1559Detail)); + Tx1559Detail memory txDetail = rawToConvertedEIP1559Detail(rawTxDetail); + assertEq(txDetail.from, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(txDetail.to, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512); + assertEq( + txDetail.data, + hex"23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004" + ); + assertEq(txDetail.nonce, 3); + assertEq(txDetail.txType, 2); + assertEq(txDetail.gas, 29625); + assertEq(txDetail.value, 0); + } + + function testReadEIP1559Transaction() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 0; + Tx1559 memory transaction = readTx1559(path, index); + transaction; + } + + function testReadEIP1559Transactions() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Tx1559[] memory transactions = readTx1559s(path); + transactions; + } + + function testReadReceipt() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 5; + Receipt memory receipt = readReceipt(path, index); + assertEq( + receipt.logsBloom, + hex"00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100" + ); + } + + function testReadReceipts() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Receipt[] memory receipts = readReceipts(path); + receipts; + } + + function testGasMeteringModifier() public { + uint256 gas_start_normal = gasleft(); + addInLoop(); + uint256 gas_used_normal = gas_start_normal - gasleft(); + + uint256 gas_start_single = gasleft(); + addInLoopNoGas(); + uint256 gas_used_single = gas_start_single - gasleft(); + + uint256 gas_start_double = gasleft(); + addInLoopNoGasNoGas(); + uint256 gas_used_double = gas_start_double - gasleft(); + + emit log_named_uint("Normal gas", gas_used_normal); + emit log_named_uint("Single modifier gas", gas_used_single); + emit log_named_uint("Double modifier gas", gas_used_double); + assertTrue(gas_used_double + gas_used_single < gas_used_normal); + } + + function addInLoop() internal pure returns (uint256) { + uint256 b; + for (uint256 i; i < 10000; i++) { + b += i; + } + return b; + } + + function addInLoopNoGas() internal noGasMetering returns (uint256) { + return addInLoop(); + } + + function addInLoopNoGasNoGas() internal noGasMetering returns (uint256) { + return addInLoopNoGas(); + } + + function bytesToUint_test(bytes memory b) private pure returns (uint256) { + uint256 number; + for (uint256 i = 0; i < b.length; i++) { + number = number + uint256(uint8(b[i])) * (2 ** (8 * (b.length - (i + 1)))); + } + return number; + } + + function testAssumeNoPrecompiles(address addr) external { + assumeNoPrecompiles(addr, getChain("optimism_goerli").chainId); + assertTrue( + addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) + || addr > address(0x4200000000000000000000000000000000000800) + ); + } +} + +contract Bar { + constructor() payable { + /// `DEAL` STDCHEAT + totalSupply = 10000e18; + balanceOf[address(this)] = totalSupply; + } + + /// `HOAX` STDCHEATS + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } + + function origin(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedSender, "!prank"); + } + + function origin(address expectedSender, address expectedOrigin) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedOrigin, "!prank"); + } + + /// `DEAL` STDCHEAT + mapping(address => uint256) public balanceOf; + uint256 public totalSupply; +} + +contract RevertingContract { + constructor() { + revert(); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..ccd3efa --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdError.sol"; +import "../src/Test.sol"; + +contract StdErrorsTest is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectAssertion() public { + vm.expectRevert(stdError.assertionError); + test.assertionError(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } + + function testExpectDiv() public { + vm.expectRevert(stdError.divisionError); + test.divError(0); + } + + function testExpectMod() public { + vm.expectRevert(stdError.divisionError); + test.modError(0); + } + + function testExpectEnum() public { + vm.expectRevert(stdError.enumConversionError); + test.enumConversion(1); + } + + function testExpectEncodeStg() public { + vm.expectRevert(stdError.encodeStorageError); + test.encodeStgError(); + } + + function testExpectPop() public { + vm.expectRevert(stdError.popError); + test.pop(); + } + + function testExpectOOB() public { + vm.expectRevert(stdError.indexOOBError); + test.indexOOBError(1); + } + + function testExpectMem() public { + vm.expectRevert(stdError.memOverflowError); + test.mem(); + } + + function testExpectIntern() public { + vm.expectRevert(stdError.zeroVarError); + test.intern(); + } +} + +contract ErrorsTest { + enum T {T1} + + uint256[] public someArr; + bytes someBytes; + + function assertionError() public pure { + assert(false); + } + + function arithmeticError(uint256 a) public pure { + a -= 100; + } + + function divError(uint256 a) public pure { + 100 / a; + } + + function modError(uint256 a) public pure { + 100 % a; + } + + function enumConversion(uint256 a) public pure { + T(a); + } + + function encodeStgError() public { + /// @solidity memory-safe-assembly + assembly { + sstore(someBytes.slot, 1) + } + keccak256(someBytes); + } + + function pop() public { + someArr.pop(); + } + + function indexOOBError(uint256 a) public pure { + uint256[] memory t = new uint256[](0); + t[a]; + } + + function mem() public pure { + uint256 l = 2 ** 256 / 32; + new uint256[](l); + } + + function intern() public returns (uint256) { + function(uint256) internal returns (uint256) x; + x(2); + return 7; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..95037ea --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdMath.sol"; +import "../src/Test.sol"; + +contract StdMathTest is Test { + function testGetAbs() external { + assertEq(stdMath.abs(-50), 50); + assertEq(stdMath.abs(50), 50); + assertEq(stdMath.abs(-1337), 1337); + assertEq(stdMath.abs(0), 0); + + assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1); + assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1)); + } + + function testGetAbs_Fuzz(int256 a) external { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function testGetDelta_Uint() external { + assertEq(stdMath.delta(uint256(0), uint256(0)), 0); + assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337); + assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max); + assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max); + assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max); + + assertEq(stdMath.delta(0, uint256(0)), 0); + assertEq(stdMath.delta(1337, uint256(0)), 1337); + assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max); + assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max); + assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max); + + assertEq(stdMath.delta(1337, uint256(1337)), 0); + assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0); + assertEq(stdMath.delta(5000, uint256(1250)), 3750); + } + + function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external { + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetDelta_Int() external { + assertEq(stdMath.delta(int256(0), int256(0)), 0); + assertEq(stdMath.delta(int256(0), int256(1337)), 1337); + assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1); + assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1); + assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1); + + assertEq(stdMath.delta(0, int256(0)), 0); + assertEq(stdMath.delta(1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1); + assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1); + assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1); + + assertEq(stdMath.delta(-0, int256(0)), 0); + assertEq(stdMath.delta(-1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(int256(0), -0), 0); + assertEq(stdMath.delta(int256(0), -1337), 1337); + assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(1337, int256(1337)), 0); + assertEq(stdMath.delta(type(int256).max, type(int256).max), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).min), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max); + assertEq(stdMath.delta(5000, int256(1250)), 3750); + } + + function testGetDelta_Int_Fuzz(int256 a, int256 b) external { + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetPercentDelta_Uint() external { + assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); + assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); + assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); + assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(uint256(1), 0); + } + + function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external { + vm.assume(b != 0); + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / b; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + function testGetPercentDelta_Int() external { + assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); + assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, int256(1337)), 0); + assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); + assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); + + assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, int256(2500)), 0); + assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(int256(1), 0); + } + + function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external { + vm.assume(b != 0); + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / absB; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function getAbs(int256 a) private pure returns (uint256) { + if (a < 0) { + return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); + } + + return uint256(a); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..d4c563a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdStorage.sol"; +import "../src/Test.sol"; + +contract StdStorageTest is Test { + using stdStorage for StdStorage; + + StorageTest internal test; + + function setUp() public { + test = new StorageTest(); + } + + function testStorageHidden() public { + assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find()); + } + + function testStorageObvious() public { + assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find()); + } + + function testStorageCheckedWriteHidden() public { + stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100); + assertEq(uint256(test.hidden()), 100); + } + + function testStorageCheckedWriteObvious() public { + stdstore.target(address(test)).sig(test.exists.selector).checked_write(100); + assertEq(test.exists(), 100); + } + + function testStorageMapStructA() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot); + } + + function testStorageMapStructB() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot); + } + + function testStorageDeepMap() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key( + address(this) + ).find(); + assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(5)))))), slot); + } + + function testStorageCheckedWriteDeepMap() public { + stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(address(this)) + .checked_write(100); + assertEq(100, test.deep_map(address(this), address(this))); + } + + function testStorageDeepMapStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(0).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 0), + bytes32(slot) + ); + } + + function testStorageDeepMapStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(1).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 1), + bytes32(slot) + ); + } + + function testStorageCheckedWriteDeepMapStructA() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(100, a); + assertEq(0, b); + } + + function testStorageCheckedWriteDeepMapStructB() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(0, a); + assertEq(100, b); + } + + function testStorageCheckedWriteMapStructA() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 100); + assertEq(b, 0); + } + + function testStorageCheckedWriteMapStructB() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 0); + assertEq(b, 100); + } + + function testStorageStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find(); + assertEq(uint256(7), slot); + } + + function testStorageStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find(); + assertEq(uint256(7) + 1, slot); + } + + function testStorageCheckedWriteStructA() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 100); + assertEq(b, 1337); + } + + function testStorageCheckedWriteStructB() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 1337); + assertEq(b, 100); + } + + function testStorageMapAddrFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find(); + assertEq(uint256(keccak256(abi.encode(address(this), uint256(1)))), slot); + } + + function testStorageMapUintFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find(); + assertEq(uint256(keccak256(abi.encode(100, uint256(2)))), slot); + } + + function testStorageCheckedWriteMapUint() public { + stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100); + assertEq(100, test.map_uint(100)); + } + + function testStorageCheckedWriteMapAddr() public { + stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100); + assertEq(100, test.map_addr(address(this))); + } + + function testStorageCheckedWriteMapBool() public { + stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true); + assertTrue(test.map_bool(address(this))); + } + + function testFailStorageCheckedWriteMapPacked() public { + // expect PackedSlot error but not external call so cant expectRevert + stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))) + .checked_write(100); + } + + function testStorageCheckedWriteMapPackedSuccess() public { + uint256 full = test.map_packed(address(1337)); + // keep upper 128, set lower 128 to 1337 + full = (full & (uint256((1 << 128) - 1) << 128)) | 1337; + stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write( + full + ); + assertEq(1337, test.read_struct_lower(address(1337))); + } + + function testFailStorageConst() public { + // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()")))); + stdstore.target(address(test)).sig("const()").find(); + } + + function testFailStorageNativePack() public { + stdstore.target(address(test)).sig(test.tA.selector).find(); + stdstore.target(address(test)).sig(test.tB.selector).find(); + + // these both would fail + stdstore.target(address(test)).sig(test.tC.selector).find(); + stdstore.target(address(test)).sig(test.tD.selector).find(); + } + + function testStorageReadBytes32() public { + bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32(); + assertEq(val, hex"1337"); + } + + function testStorageReadBool_False() public { + bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool(); + assertEq(val, false); + } + + function testStorageReadBool_True() public { + bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool(); + assertEq(val, true); + } + + function testStorageReadBool_Revert() public { + vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + this.readNonBoolValue(); + } + + function readNonBoolValue() public { + stdstore.target(address(test)).sig(test.tE.selector).read_bool(); + } + + function testStorageReadAddress() public { + address val = stdstore.target(address(test)).sig(test.tF.selector).read_address(); + assertEq(val, address(1337)); + } + + function testStorageReadUint() public { + uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint(); + assertEq(val, 1); + } + + function testStorageReadInt() public { + int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int(); + assertEq(val, type(int256).min); + } +} + +contract StorageTest { + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + mapping(uint256 => uint256) public map_uint; + mapping(address => uint256) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basic; + + uint248 public tA; + bool public tB; + + bool public tC = false; + uint248 public tD = 1; + + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + mapping(address => bool) public map_bool; + + bytes32 public tE = hex"1337"; + address public tF = address(1337); + int256 public tG = type(int256).min; + bool public tH = true; + + constructor() { + basic = UnpackedStruct({a: 1337, b: 1337}); + + uint256 two = (1 << 128) | 1; + map_packed[msg.sender] = two; + map_packed[address(uint160(1337))] = 1 << 128; + } + + function read_struct_upper(address who) public view returns (uint256) { + return map_packed[who] >> 128; + } + + function read_struct_lower(address who) public view returns (uint256) { + return map_packed[who] & ((1 << 128) - 1); + } + + function hidden() public view returns (bytes32 t) { + bytes32 slot = keccak256("my.random.var"); + /// @solidity memory-safe-assembly + assembly { + t := sload(slot) + } + } + + function const() public pure returns (bytes32 t) { + t = bytes32(hex"1337"); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..f53a71b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdUtilsTest is Test { + function testBound() public { + assertEq(bound(uint256(5), 0, 4), 0); + assertEq(bound(uint256(0), 69, 69), 69); + assertEq(bound(uint256(0), 68, 69), 68); + assertEq(bound(uint256(10), 150, 190), 174); + assertEq(bound(uint256(300), 2800, 3200), 3107); + assertEq(bound(uint256(9999), 1337, 6666), 4669); + } + + function testBound_WithinRange() public { + assertEq(bound(uint256(51), 50, 150), 51); + assertEq(bound(uint256(51), 50, 150), bound(bound(uint256(51), 50, 150), 50, 150)); + assertEq(bound(uint256(149), 50, 150), 149); + assertEq(bound(uint256(149), 50, 150), bound(bound(uint256(149), 50, 150), 50, 150)); + } + + function testBound_EdgeCoverage() public { + assertEq(bound(uint256(0), 50, 150), 50); + assertEq(bound(uint256(1), 50, 150), 51); + assertEq(bound(uint256(2), 50, 150), 52); + assertEq(bound(uint256(3), 50, 150), 53); + assertEq(bound(type(uint256).max, 50, 150), 150); + assertEq(bound(type(uint256).max - 1, 50, 150), 149); + assertEq(bound(type(uint256).max - 2, 50, 150), 148); + assertEq(bound(type(uint256).max - 3, 50, 150), 147); + } + + function testBound_DistributionIsEven(uint256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, UINT256_MAX / 2, UINT256_MAX / 2 + size); + uint256 max = min + size - 1; + uint256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + i, min, max); + assertEq(result, min + (i - 1) % size); + // x < min + result = bound(min - i, min, max); + assertEq(result, max - (i - 1) % size); + } + } + + function testBound(uint256 num, uint256 min, uint256 max) public { + if (min > max) (min, max) = (max, min); + + uint256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundUint256Max() public { + assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1); + assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max); + } + + function testCannotBoundMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(uint256(5), 100, 10); + } + + function testCannotBoundMaxLessThanMin(uint256 num, uint256 min, uint256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(num, min, max); + } + + function testBoundInt() public { + assertEq(bound(-3, 0, 4), 2); + assertEq(bound(0, -69, -69), -69); + assertEq(bound(0, -69, -68), -68); + assertEq(bound(-10, 150, 190), 154); + assertEq(bound(-300, 2800, 3200), 2908); + assertEq(bound(9999, -1337, 6666), 1995); + } + + function testBoundInt_WithinRange() public { + assertEq(bound(51, -50, 150), 51); + assertEq(bound(51, -50, 150), bound(bound(51, -50, 150), -50, 150)); + assertEq(bound(149, -50, 150), 149); + assertEq(bound(149, -50, 150), bound(bound(149, -50, 150), -50, 150)); + } + + function testBoundInt_EdgeCoverage() public { + assertEq(bound(type(int256).min, -50, 150), -50); + assertEq(bound(type(int256).min + 1, -50, 150), -49); + assertEq(bound(type(int256).min + 2, -50, 150), -48); + assertEq(bound(type(int256).min + 3, -50, 150), -47); + assertEq(bound(type(int256).min, 10, 150), 10); + assertEq(bound(type(int256).min + 1, 10, 150), 11); + assertEq(bound(type(int256).min + 2, 10, 150), 12); + assertEq(bound(type(int256).min + 3, 10, 150), 13); + + assertEq(bound(type(int256).max, -50, 150), 150); + assertEq(bound(type(int256).max - 1, -50, 150), 149); + assertEq(bound(type(int256).max - 2, -50, 150), 148); + assertEq(bound(type(int256).max - 3, -50, 150), 147); + assertEq(bound(type(int256).max, -50, -10), -10); + assertEq(bound(type(int256).max - 1, -50, -10), -11); + assertEq(bound(type(int256).max - 2, -50, -10), -12); + assertEq(bound(type(int256).max - 3, -50, -10), -13); + } + + function testBoundInt_DistributionIsEven(int256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, -int256(size / 2), int256(size - size / 2)); + int256 max = min + int256(size) - 1; + int256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + int256(i), min, max); + assertEq(result, min + int256((i - 1) % size)); + // x < min + result = bound(min - int256(i), min, max); + assertEq(result, max - int256((i - 1) % size)); + } + } + + function testBoundInt(int256 num, int256 min, int256 max) public { + if (min > max) (min, max) = (max, min); + + int256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundIntInt256Max() public { + assertEq(bound(0, type(int256).max - 1, type(int256).max), type(int256).max - 1); + assertEq(bound(1, type(int256).max - 1, type(int256).max), type(int256).max); + } + + function testBoundIntInt256Min() public { + assertEq(bound(0, type(int256).min, type(int256).min + 1), type(int256).min); + assertEq(bound(1, type(int256).min, type(int256).min + 1), type(int256).min + 1); + } + + function testCannotBoundIntMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(-5, 100, 10); + } + + function testCannotBoundIntMaxLessThanMin(int256 num, int256 min, int256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(num, min, max); + } + + function testGenerateCreateAddress() external { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + function testGenerateCreate2Address() external { + bytes32 salt = bytes32(uint256(31415)); + bytes32 initcodeHash = keccak256(abi.encode(0x6080)); + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + address create2Address = computeCreate2Address(salt, initcodeHash, deployer); + assertEq(create2Address, 0xB147a5d25748fda14b463EB04B111027C290f4d3); + } + + function testBytesToUint() external { + bytes memory maxUint = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + bytes memory two = hex"02"; + bytes memory millionEther = hex"d3c21bcecceda1000000"; + + assertEq(bytesToUint(maxUint), type(uint256).max); + assertEq(bytesToUint(two), 2); + assertEq(bytesToUint(millionEther), 1_000_000 ether); + } + + function testCannotConvertGT32Bytes() external { + bytes memory thirty3Bytes = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + vm.expectRevert("StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + bytesToUint(thirty3Bytes); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..e205cff --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScript is Script {} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..ce8e0e9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScriptBase is ScriptBase {} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..9beeafe --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTest is Test {} diff --git a/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..e993535 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTestBase is TestBase {} diff --git a/lib/crytic/lib/openzeppelin-contracts/logo.svg b/lib/crytic/lib/openzeppelin-contracts/logo.svg new file mode 100644 index 0000000..f1e14c2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/lib/crytic/lib/openzeppelin-contracts/netlify.toml b/lib/crytic/lib/openzeppelin-contracts/netlify.toml new file mode 100644 index 0000000..0447f41 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/netlify.toml @@ -0,0 +1,3 @@ +[build] +command = "npm run docs" +publish = "build/site" diff --git a/lib/crytic/lib/openzeppelin-contracts/package-lock.json b/lib/crytic/lib/openzeppelin-contracts/package-lock.json new file mode 100644 index 0000000..4f808cf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/package-lock.json @@ -0,0 +1,29066 @@ +{ + "name": "openzeppelin-solidity", + "version": "4.8.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "openzeppelin-solidity", + "version": "4.8.0", + "license": "MIT", + "bin": { + "openzeppelin-contracts-migrate-imports": "scripts/migrate-imports.js" + }, + "devDependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-truffle5": "^2.0.5", + "@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", + "eth-sig-util": "^3.0.0", + "ethereumjs-util": "^7.0.7", + "ethereumjs-wallet": "^1.0.1", + "glob": "^8.0.3", + "graphlib": "^2.1.8", + "hardhat": "^2.9.1", + "hardhat-exposed": "^0.3.1", + "hardhat-gas-reporter": "^1.0.4", + "hardhat-ignore-warnings": "^0.2.0", + "keccak256": "^1.0.2", + "lodash.startcase": "^4.4.0", + "lodash.zip": "^4.2.0", + "merkletreejs": "^0.2.13", + "micromatch": "^4.0.2", + "prettier": "^2.8.1", + "prettier-plugin-solidity": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "solhint": "^3.3.6", + "solidity-ast": "^0.4.25", + "solidity-coverage": "^0.8.0", + "solidity-docgen": "^0.6.0-beta.29", + "web3": "^1.3.0", + "yargs": "^17.0.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "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==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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", + "integrity": "sha512-ECDNeoc3nfeAe1jqJb5aFQX7CqzQhD2klXRez2JDb/aVpGUbX673HgKrnrgJRuQR/9f2TtLoYIzrGB9qwD77mg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/config": "^2.3.0", + "@changesets/get-version-range-type": "^0.3.2", + "@changesets/git": "^2.0.0", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "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", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@changesets/assemble-release-plan": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.3.tgz", + "integrity": "sha512-g7EVZCmnWz3zMBAdrcKhid4hkHT+Ft1n0mLussFMcB1dE2zCuwcvGoy9ec3yOgPGF4hoMtgHaMIk3T3TBdvU9g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "semver": "^5.4.1" + } + }, + "node_modules/@changesets/assemble-release-plan/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/@changesets/changelog-git": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.1.14.tgz", + "integrity": "sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1" + } + }, + "node_modules/@changesets/changelog-github": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.4.8.tgz", + "integrity": "sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw==", + "dev": true, + "dependencies": { + "@changesets/get-github-info": "^0.5.2", + "@changesets/types": "^5.2.1", + "dotenv": "^8.1.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/apply-release-plan": "^6.1.3", + "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/changelog-git": "^0.1.14", + "@changesets/config": "^2.3.0", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/get-release-plan": "^3.0.16", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@changesets/write": "^0.2.3", + "@manypkg/get-packages": "^1.1.3", + "@types/is-ci": "^3.0.0", + "@types/semver": "^6.0.0", + "ansi-colors": "^4.1.3", + "chalk": "^2.1.0", + "enquirer": "^2.3.0", + "external-editor": "^3.1.0", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "is-ci": "^3.0.1", + "meow": "^6.0.0", + "outdent": "^0.5.0", + "p-limit": "^2.2.0", + "preferred-pm": "^3.0.0", + "resolve-from": "^5.0.0", + "semver": "^5.4.1", + "spawndamnit": "^2.0.0", + "term-size": "^2.1.0", + "tty-table": "^4.1.5" + }, + "bin": { + "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", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "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", + "integrity": "sha512-EgP/px6mhCx8QeaMAvWtRrgyxW08k/Bx2tpGT+M84jEdX37v3VKfh4Cz1BkwrYKuMV2HZKeHOh8sHvja/HcXfQ==", + "dev": true, + "dependencies": { + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/logger": "^0.0.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.2" + } + }, + "node_modules/@changesets/errors": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.1.4.tgz", + "integrity": "sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==", + "dev": true, + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.5.tgz", + "integrity": "sha512-w1eEvnWlbVDIY8mWXqWuYE9oKhvIaBhzqzo4ITSJY9hgoqQ3RoBqwlcAzg11qHxv/b8ReDWnMrpjpKrW6m1ZTA==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "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", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "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", + "integrity": "sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==", + "dev": true, + "dependencies": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.16.tgz", + "integrity": "sha512-OpP9QILpBp1bY2YNIKFzwigKh7Qe9KizRsZomzLe6pK8IUo8onkAAVUD8+JRKSr8R7d4+JRuQrfSSNlEwKyPYg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/config": "^2.3.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz", + "integrity": "sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==", + "dev": true + }, + "node_modules/@changesets/git": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-2.0.0.tgz", + "integrity": "sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.2", + "spawndamnit": "^2.0.0" + } + }, + "node_modules/@changesets/logger": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.0.5.tgz", + "integrity": "sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1", + "js-yaml": "^3.13.1" + } + }, + "node_modules/@changesets/pre": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-1.0.14.tgz", + "integrity": "sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.5.9.tgz", + "integrity": "sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/parse": "^0.3.16", + "@changesets/types": "^5.2.1", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "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", + "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==", + "dev": true + }, + "node_modules/@changesets/write": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.2.3.tgz", + "integrity": "sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/types": "^5.2.1", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "prettier": "^2.7.1" + } + }, + "node_modules/@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dev": true, + "dependencies": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + } + }, + "node_modules/@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true, + "dependencies": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + } + }, + "node_modules/@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + } + }, + "node_modules/@ensdomains/ensjs/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/@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "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/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "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/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bignumber/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/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "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/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "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/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "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" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "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/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "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/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/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key/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/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "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/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "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/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^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/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "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/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "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/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@frangio/servbot": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@frangio/servbot/-/servbot-0.2.5.tgz", + "integrity": "sha512-ogja4iAPZ1VwM5MU3C1ZhB88358F0PGbmSTGOkIZwOyLaDoMHIqOVCnavHjR7DV5h+oAI4Z4KDqlam3myQUrmg==", + "dev": true, + "engines": { + "node": ">=12.x", + "pnpm": "7.5.1" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "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", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "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", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "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==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "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==", + "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" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "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", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "^4.0.0", + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "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", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "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", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "functional-red-black-tree": "^1.0.1" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "^3.0.0", + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "^4.0.0-beta.2", + "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==", + "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", + "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" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "dev": true, + "dependencies": { + "ethereumjs-util": "^7.1.4" + }, + "peerDependencies": { + "hardhat": "^2.9.5" + } + }, + "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==", + "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" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomiclabs/hardhat-truffle5": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-truffle5/-/hardhat-truffle5-2.0.7.tgz", + "integrity": "sha512-Pw8451IUZp1bTp0QqCHCYfCHs66sCnyxPcaorapu9mfOV9xnZsVaFdtutnhNEiXdiZwbed7LFKpRsde4BjFwig==", + "dev": true, + "dependencies": { + "@nomiclabs/truffle-contract": "^4.2.23", + "@types/chai": "^4.2.0", + "chai": "^4.2.0", + "ethereumjs-util": "^7.1.4", + "fs-extra": "^7.0.1" + }, + "peerDependencies": { + "@nomiclabs/hardhat-web3": "^2.0.0", + "hardhat": "^2.6.4", + "web3": "^1.0.0-beta.36" + } + }, + "node_modules/@nomiclabs/hardhat-web3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-web3/-/hardhat-web3-2.0.0.tgz", + "integrity": "sha512-zt4xN+D+fKl3wW2YlTX3k9APR3XZgPkxJYf36AcliJn3oujnKEVRZaHu0PhgLjO+gR+F/kiYayo9fgd2L8970Q==", + "dev": true, + "dependencies": { + "@types/bignumber.js": "^5.0.0" + }, + "peerDependencies": { + "hardhat": "^2.0.0", + "web3": "^1.0.0-beta.36" + } + }, + "node_modules/@nomiclabs/truffle-contract": { + "version": "4.5.10", + "resolved": "https://registry.npmjs.org/@nomiclabs/truffle-contract/-/truffle-contract-4.5.10.tgz", + "integrity": "sha512-nF/6InFV+0hUvutyFgsdOMCoYlr//2fJbRER4itxYtQtc4/O1biTwZIKRu+5l2J5Sq6LU2WX7vZHtDgQdhWxIQ==", + "dev": true, + "dependencies": { + "@ensdomains/ensjs": "^2.0.1", + "@truffle/blockchain-utils": "^0.1.3", + "@truffle/contract-schema": "^3.4.7", + "@truffle/debug-utils": "^6.0.22", + "@truffle/error": "^0.1.0", + "@truffle/interface-adapter": "^0.5.16", + "bignumber.js": "^7.2.1", + "ethereum-ens": "^0.8.0", + "ethers": "^4.0.0-beta.1", + "source-map-support": "^0.5.19" + }, + "peerDependencies": { + "web3": "^1.2.1", + "web3-core-helpers": "^1.2.1", + "web3-core-promievent": "^1.2.1", + "web3-eth-abi": "^1.2.1", + "web3-utils": "^1.2.1" + } + }, + "node_modules/@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@openzeppelin/docs-utils": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/docs-utils/-/docs-utils-0.1.3.tgz", + "integrity": "sha512-O/iJ4jEi5ryNc/T74G9gbnFwQ8QaQ2bpAVoYXLPknZJyK52GEAvxC12UMP33KodTNV3rMzeeQrSBIdI8skjDJg==", + "dev": true, + "dependencies": { + "@frangio/servbot": "^0.2.5", + "chalk": "^3.0.0", + "chokidar": "^3.5.3", + "env-paths": "^2.2.0", + "find-up": "^4.1.0", + "is-port-reachable": "^3.0.0", + "js-yaml": "^3.13.1", + "lodash.startcase": "^4.4.0", + "minimist": "^1.2.0" + }, + "bin": { + "oz-docs": "oz-docs.js" + } + }, + "node_modules/@openzeppelin/test-helpers": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.16.tgz", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dev": true, + "dependencies": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "web3-utils": "^1.2.5" + } + }, + "node_modules/@openzeppelin/test-helpers/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/@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", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/bip32": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", + "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.1.1", + "@noble/secp256k1": "~1.6.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==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "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==", + "dev": true, + "dependencies": { + "change-case": "3.0.2", + "fast-check": "3.1.1", + "web3-utils": "1.8.1" + } + }, + "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==", + "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==", + "dev": true, + "dependencies": { + "@truffle/abi-utils": "^0.3.6", + "@truffle/compile-common": "^0.9.1", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "7.3.7", + "utf8": "^3.0.0", + "web3-utils": "1.8.1" + } + }, + "node_modules/@truffle/codec/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/codec/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@truffle/codec/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@truffle/codec/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/@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==", + "dev": true, + "dependencies": { + "@truffle/error": "^0.1.1", + "colors": "1.4.0" + } + }, + "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==", + "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", + "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" + } + }, + "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==", + "dev": true, + "dependencies": { + "ajv": "^6.10.0", + "debug": "^4.3.1" + } + }, + "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==", + "dev": true, + "dependencies": { + "@truffle/codec": "^0.14.11", + "@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" + } + }, + "node_modules/@truffle/debug-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/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", + "integrity": "sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA==", + "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==", + "dev": true, + "dependencies": { + "bn.js": "^5.1.3", + "ethers": "^4.0.32", + "web3": "1.8.1" + } + }, + "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/@trufflesuite/chromafi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@trufflesuite/chromafi/-/chromafi-3.0.0.tgz", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dev": true, + "dependencies": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "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==", + "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" + } + }, + "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", + "integrity": "sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==", + "deprecated": "This is a stub types definition for bignumber.js (https://github.com/MikeMcl/bignumber.js/). bignumber.js provides its own type definitions, so you don't need @types/bignumber.js installed!", + "dev": true, + "dependencies": { + "bignumber.js": "*" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "node_modules/@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "node_modules/@types/is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "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==", + "dev": true + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz", + "integrity": "sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true + }, + "node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/abstract-level/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", + "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "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/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/antlr4": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", + "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", + "dev": true + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "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==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "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/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/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/breakword": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/breakword/-/breakword-1.0.5.tgz", + "integrity": "sha512-ex5W9DoOQ/LUEU3PMdLs9ua/CYZl1678NUkKOdUSi8Aw5F1idieaiRURCBFJCwVcrD1J8Iy3vfWSloaMwO2qFg==", + "dev": true, + "dependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "node_modules/browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "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", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-reverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==", + "dev": true + }, + "node_modules/buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "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", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/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/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", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/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_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "dev": true, + "peerDependencies": { + "bn.js": "^4.11.0", + "chai": "^4.0.0" + } + }, + "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/change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "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 + }, + "node_modules/cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/cids/node_modules/multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "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==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "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", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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/cliui/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "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 + }, + "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", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "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==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-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/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, + "dependencies": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "dependencies": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "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" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "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", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "dependencies": { + "node-fetch": "2.6.7" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-addr-codec": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.7.tgz", + "integrity": "sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "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", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", + "dev": true + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "dev": true, + "dependencies": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + }, + "engines": { + "node": ">= 0.1.90" + } + }, + "node_modules/csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "dev": true + }, + "node_modules/csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "node_modules/csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", + "dev": true + }, + "node_modules/death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "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", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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, + "engines": { + "node": ">=4" + } + }, + "node_modules/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "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", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "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==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "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", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "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-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "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==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/escodegen/node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/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/escodegen/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/escodegen/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/eslint": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "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", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "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" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "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==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "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", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/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/eslint/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/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dev": true, + "dependencies": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "node_modules/eth-ens-namehash/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/eth-gas-reporter": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz", + "integrity": "sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.0.0-beta.146", + "@solidity-parser/parser": "^0.14.0", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^4.0.40", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^7.1.1", + "req-cwd": "^2.0.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "peerDependencies": { + "@codechecks/client": "^0.1.0" + }, + "peerDependenciesMeta": { + "@codechecks/client": { + "optional": true + } + } + }, + "node_modules/eth-gas-reporter/node_modules/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/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/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", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.1" + } + }, + "node_modules/eth-gas-reporter/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "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", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eth-gas-reporter/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==", + "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==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.1.2", + "@noble/secp256k1": "1.6.3", + "@scure/bip32": "1.1.0", + "@scure/bip39": "1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/eth-gas-reporter/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": { + "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": "*" + } + }, + "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", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eth-gas-reporter/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/eth-gas-reporter/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/eth-gas-reporter/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "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", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eth-gas-reporter/node_modules/readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eth-gas-reporter/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/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/eth-gas-reporter/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_modules/eth-gas-reporter/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==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/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_modules/eth-gas-reporter/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/eth-gas-reporter/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/eth-gas-reporter/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/eth-lib/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/eth-lib/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/eth-sig-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-3.0.1.tgz", + "integrity": "sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==", + "deprecated": "Deprecated in favor of '@metamask/eth-sig-util'", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^5.1.1", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.0" + } + }, + "node_modules/eth-sig-util/node_modules/ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "dependencies": { + "js-sha3": "^0.8.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereum-ens": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ethereum-ens/-/ethereum-ens-0.8.0.tgz", + "integrity": "sha512-a8cBTF4AWw1Q1Y37V1LSCS9pRY4Mh3f8vCg5cbXCCEJ3eno1hbI/+Ccv9SZLISYpqQhaglP3Bxb/34lS4Qf7Bg==", + "dev": true, + "dependencies": { + "bluebird": "^3.4.7", + "eth-ens-namehash": "^2.0.0", + "js-sha3": "^0.5.7", + "pako": "^1.0.4", + "underscore": "^1.8.3", + "web3": "^1.0.0-beta.34" + } + }, + "node_modules/ethereum-ens/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethereumjs-util/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/ethereumjs-wallet": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz", + "integrity": "sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==", + "dev": true, + "dependencies": { + "aes-js": "^3.1.2", + "bs58check": "^2.1.2", + "ethereum-cryptography": "^0.1.3", + "ethereumjs-util": "^7.1.2", + "randombytes": "^2.1.0", + "scrypt-js": "^3.0.1", + "utf8": "^3.0.0", + "uuid": "^8.3.2" + } + }, + "node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/ethers/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/ethers/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/ethers/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/ethers/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "node_modules/ethers/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "node_modules/ethers/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true + }, + "node_modules/ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-abi/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-abi/node_modules/js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==", + "dev": true + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dev": true, + "dependencies": { + "pure-rand": "^5.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "dev": true + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + }, + "bin": { + "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==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/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_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "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==", + "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": ">=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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "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==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "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/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.4.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/cli.js" + }, + "engines": { + "node": "^14.0.0 || ^16.0.0 || ^18.0.0" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "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==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.4", + "solidity-ast": "^0.4.25" + }, + "peerDependencies": { + "hardhat": "^2.3.0" + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "dependencies": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + }, + "peerDependencies": { + "hardhat": "^2.0.2" + } + }, + "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==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + } + }, + "node_modules/hardhat-ignore-warnings/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "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==", + "dev": true + }, + "node_modules/hardhat/node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "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==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.1.2", + "@noble/secp256k1": "1.6.3", + "@scure/bip32": "1.1.0", + "@scure/bip39": "1.1.0" + } + }, + "node_modules/hardhat/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "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", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/hardhat/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/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/hardhat/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/hardhat/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/hardhat/node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/hardhat/node_modules/solc/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/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", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "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", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-solidity": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.5.tgz", + "integrity": "sha512-ReXxQSGQkODMUgHcWzVSnfDCDrL2HshOYgw3OlIYmfHeRzUPkfJTUIp95pK4CmbiNG2eMTOmNLpfCz9Zq7Cwmg==", + "dev": true + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-cache-semantics": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "dev": true + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-id": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz", + "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "dependencies": { + "punycode": "2.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.1.tgz", + "integrity": "sha512-7WYV7Q5BTs0nlQm7tl92rDYYoyELLKHoDMBKhrxEoiV4mrfVdRz8hzPiYOzH7yWjzoVEamxRuAqhxL2PLRwZYQ==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "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==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "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", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "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", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/is-port-reachable": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-3.1.0.tgz", + "integrity": "sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "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==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "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", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keccak": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", + "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keccak256": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz", + "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0", + "buffer": "^6.0.3", + "keccak": "^3.0.2" + } + }, + "node_modules/keccak256/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/keccak256/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "dependencies": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/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/load-yaml-file": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "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", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true + }, + "node_modules/lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, + "node_modules/lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.2" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/meow": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", + "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "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", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/merkletreejs": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.2.32.tgz", + "integrity": "sha512-TostQBiwYRIwSE5++jGmacu3ODcKAgqb0Y/pnIohXS7sWxh1gCkSptbmF1a43faehRDpcHf7J/kv0Ml2D/zblQ==", + "dev": true, + "dependencies": { + "bignumber.js": "^9.0.1", + "buffer-reverse": "^1.0.1", + "crypto-js": "^3.1.9-1", + "treeify": "^1.1.0", + "web3-utils": "^1.3.4" + }, + "engines": { + "node": ">= 7.6.0" + } + }, + "node_modules/merkletreejs/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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "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", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "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", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "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", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mixme": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.4.tgz", + "integrity": "sha512-3KYa4m4Vlqx98GPdOHghxSdNtTvcP8E0kkaJ5Dlh+h2DRzF7zpuVVcA8B0QpKd11YJeP9QQ7ASkKzOeu195Wzw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", + "dev": true, + "dependencies": { + "mkdirp": "*" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mock-fs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "dev": true + }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "varint": "^5.0.0" + } + }, + "node_modules/multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "node_modules/multihashes/node_modules/multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "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", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==", + "dev": true + }, + "node_modules/nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "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", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "node_modules/node-environment-flags/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/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/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==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-interval-tree": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-2.1.2.tgz", + "integrity": "sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==", + "dev": true, + "dependencies": { + "shallowequal": "^1.1.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "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/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/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/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "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/object.getownpropertydescriptors": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz", + "integrity": "sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw==", + "dev": true, + "dependencies": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "node_modules/oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dev": true, + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-filter/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "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", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "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==", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/preferred-pm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.0.3.tgz", + "integrity": "sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0", + "find-yarn-workspace-root2": "1.2.16", + "path-exists": "^4.0.0", + "which-pm": "2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/preferred-pm/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/preferred-pm/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", + "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "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==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.14.5", + "semver": "^7.3.8", + "solidity-comments-extractor": "^0.0.7" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "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", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "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", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "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/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "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/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/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/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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "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==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "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==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "dependencies": { + "req-from": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from/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" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.12.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "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==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/responselike/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "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", + "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", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/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/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/rlp/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/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", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "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", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "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", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "node_modules/sc-istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sc-istanbul/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_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "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/semver/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "dependencies": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dev": true, + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/sha3/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/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/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dev": true, + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "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==", + "dev": true + }, + "node_modules/smartwrap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/smartwrap/-/smartwrap-2.0.2.tgz", + "integrity": "sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==", + "dev": true, + "dependencies": { + "array.prototype.flat": "^1.2.3", + "breakword": "^1.0.5", + "grapheme-splitter": "^1.0.4", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^15.1.0" + }, + "bin": { + "smartwrap": "src/terminal-adapter.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/smartwrap/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, + "engines": { + "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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/smartwrap/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/smartwrap/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "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", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dev": true, + "dependencies": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + }, + "bin": { + "solcjs": "solcjs" + } + }, + "node_modules/solc/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/solc/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/solc/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "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", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "node_modules/solc/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/solc/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/solc/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "node_modules/solc/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/solc/node_modules/yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "dependencies": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "node_modules/solc/node_modules/yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + }, + "node_modules/solhint": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", + "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "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" + }, + "bin": { + "solhint": "solhint.js" + }, + "optionalDependencies": { + "prettier": "^1.14.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==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "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==", + "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==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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==", + "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" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/solhint/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "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==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "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_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==", + "dev": true, + "dependencies": { + "has-flag": "^3.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_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==", + "dev": true + }, + "node_modules/solidity-comments": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments/-/solidity-comments-0.0.2.tgz", + "integrity": "sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "solidity-comments-darwin-arm64": "0.0.2", + "solidity-comments-darwin-x64": "0.0.2", + "solidity-comments-freebsd-x64": "0.0.2", + "solidity-comments-linux-arm64-gnu": "0.0.2", + "solidity-comments-linux-arm64-musl": "0.0.2", + "solidity-comments-linux-x64-gnu": "0.0.2", + "solidity-comments-linux-x64-musl": "0.0.2", + "solidity-comments-win32-arm64-msvc": "0.0.2", + "solidity-comments-win32-ia32-msvc": "0.0.2", + "solidity-comments-win32-x64-msvc": "0.0.2" + } + }, + "node_modules/solidity-comments-darwin-arm64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-arm64/-/solidity-comments-darwin-arm64-0.0.2.tgz", + "integrity": "sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-darwin-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-x64/-/solidity-comments-darwin-x64-0.0.2.tgz", + "integrity": "sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "node_modules/solidity-comments-freebsd-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-freebsd-x64/-/solidity-comments-freebsd-x64-0.0.2.tgz", + "integrity": "sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-gnu/-/solidity-comments-linux-arm64-gnu-0.0.2.tgz", + "integrity": "sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-musl/-/solidity-comments-linux-arm64-musl-0.0.2.tgz", + "integrity": "sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-gnu/-/solidity-comments-linux-x64-gnu-0.0.2.tgz", + "integrity": "sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-musl/-/solidity-comments-linux-x64-musl-0.0.2.tgz", + "integrity": "sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-arm64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-arm64-msvc/-/solidity-comments-win32-arm64-msvc-0.0.2.tgz", + "integrity": "sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-ia32-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-ia32-msvc/-/solidity-comments-win32-ia32-msvc-0.0.2.tgz", + "integrity": "sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-x64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-x64-msvc/-/solidity-comments-win32-x64-msvc-0.0.2.tgz", + "integrity": "sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-coverage": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.2.tgz", + "integrity": "sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.14.1", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "7.1.2", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "bin": { + "solidity-coverage": "plugins/bin.js" + }, + "peerDependencies": { + "hardhat": "^2.11.0" + } + }, + "node_modules/solidity-coverage/node_modules/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/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/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", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.1" + } + }, + "node_modules/solidity-coverage/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "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", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/solidity-coverage/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==", + "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", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/solidity-coverage/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/solidity-coverage/node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "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": "*" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/solidity-coverage/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "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", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/solidity-coverage/node_modules/mocha": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", + "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", + "dev": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "type": "opencollective", + "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==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "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", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/solidity-coverage/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/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/solidity-coverage/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_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==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/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_modules/solidity-coverage/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/solidity-coverage/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/solidity-coverage/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/solidity-coverage/node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "dependencies": { + "handlebars": "^4.7.7", + "solidity-ast": "^0.4.38" + }, + "peerDependencies": { + "hardhat": "^2.8.0" + } + }, + "node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz", + "integrity": "sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/spawndamnit/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/spawndamnit/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/spawndamnit/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==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit/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/spawndamnit/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_modules/spawndamnit/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "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==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "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==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "dev": true, + "dependencies": { + "mixme": "^0.5.1" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "node_modules/swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + } + }, + "node_modules/swarm-js/node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swarm-js/node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/swarm-js/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/swarm-js/node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/swarm-js/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "dependencies": { + "get-port": "^3.1.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "deprecated": "testrpc has been renamed to ganache-cli, please use this package from now on.", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "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", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "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==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "csv": "^5.5.0", + "kleur": "^4.1.4", + "smartwrap": "^2.0.2", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^17.1.1" + }, + "bin": { + "tty-table": "adapters/terminal-adapter.js" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/tty-table/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/tty-table/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/tty-table/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/undici": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=12.18" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, + "node_modules/upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "dev": true + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web3": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.1.tgz", + "integrity": "sha512-tAqFsQhGv340C9OgRJIuoScN7f7wa1tUvsnnDUMt9YE6J4gcm7TV2Uwv+KERnzvV+xgdeuULYpsioRRNKrUvoQ==", + "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" + }, + "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==", + "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/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==", + "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" + }, + "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==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.8.1", + "web3-utils": "1.8.1" + }, + "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==", + "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" + }, + "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==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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==", + "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" + }, + "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==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.1" + }, + "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", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "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==", + "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" + }, + "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==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.8.1" + }, + "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==", + "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", + "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" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/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/web3-eth-accounts/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/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==", + "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" + }, + "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==", + "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" + }, + "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==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.8.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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/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==", + "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" + }, + "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==", + "dev": true, + "dependencies": { + "web3-core": "1.8.1", + "web3-core-method": "1.8.1", + "web3-utils": "1.8.1" + }, + "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==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.8.1" + }, + "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==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.8.1" + }, + "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==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.1", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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==", + "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" + }, + "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==", + "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/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/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dev": true, + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true + }, + "node_modules/which-pm": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", + "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", + "dev": true, + "dependencies": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8.15" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true, + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/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, + "engines": { + "node": ">=8" + } + }, + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "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", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "dependencies": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "node_modules/xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "dependencies": { + "xhr-request": "^1.1.0" + } + }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "dev": true, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "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==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "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/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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/yargs/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "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==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@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==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.11" + } + }, + "@changesets/apply-release-plan": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.3.tgz", + "integrity": "sha512-ECDNeoc3nfeAe1jqJb5aFQX7CqzQhD2klXRez2JDb/aVpGUbX673HgKrnrgJRuQR/9f2TtLoYIzrGB9qwD77mg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/config": "^2.3.0", + "@changesets/get-version-range-type": "^0.3.2", + "@changesets/git": "^2.0.0", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "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", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@changesets/assemble-release-plan": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.3.tgz", + "integrity": "sha512-g7EVZCmnWz3zMBAdrcKhid4hkHT+Ft1n0mLussFMcB1dE2zCuwcvGoy9ec3yOgPGF4hoMtgHaMIk3T3TBdvU9g==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@changesets/changelog-git": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.1.14.tgz", + "integrity": "sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==", + "dev": true, + "requires": { + "@changesets/types": "^5.2.1" + } + }, + "@changesets/changelog-github": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.4.8.tgz", + "integrity": "sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw==", + "dev": true, + "requires": { + "@changesets/get-github-info": "^0.5.2", + "@changesets/types": "^5.2.1", + "dotenv": "^8.1.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/apply-release-plan": "^6.1.3", + "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/changelog-git": "^0.1.14", + "@changesets/config": "^2.3.0", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/get-release-plan": "^3.0.16", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@changesets/write": "^0.2.3", + "@manypkg/get-packages": "^1.1.3", + "@types/is-ci": "^3.0.0", + "@types/semver": "^6.0.0", + "ansi-colors": "^4.1.3", + "chalk": "^2.1.0", + "enquirer": "^2.3.0", + "external-editor": "^3.1.0", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "is-ci": "^3.0.1", + "meow": "^6.0.0", + "outdent": "^0.5.0", + "p-limit": "^2.2.0", + "preferred-pm": "^3.0.0", + "resolve-from": "^5.0.0", + "semver": "^5.4.1", + "spawndamnit": "^2.0.0", + "term-size": "^2.1.0", + "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" + } + } + } + }, + "@changesets/config": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.0.tgz", + "integrity": "sha512-EgP/px6mhCx8QeaMAvWtRrgyxW08k/Bx2tpGT+M84jEdX37v3VKfh4Cz1BkwrYKuMV2HZKeHOh8sHvja/HcXfQ==", + "dev": true, + "requires": { + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/logger": "^0.0.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.2" + } + }, + "@changesets/errors": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.1.4.tgz", + "integrity": "sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==", + "dev": true, + "requires": { + "extendable-error": "^0.1.5" + } + }, + "@changesets/get-dependents-graph": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.5.tgz", + "integrity": "sha512-w1eEvnWlbVDIY8mWXqWuYE9oKhvIaBhzqzo4ITSJY9hgoqQ3RoBqwlcAzg11qHxv/b8ReDWnMrpjpKrW6m1ZTA==", + "dev": true, + "requires": { + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "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" + } + } + } + }, + "@changesets/get-github-info": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.5.2.tgz", + "integrity": "sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==", + "dev": true, + "requires": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "@changesets/get-release-plan": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.16.tgz", + "integrity": "sha512-OpP9QILpBp1bY2YNIKFzwigKh7Qe9KizRsZomzLe6pK8IUo8onkAAVUD8+JRKSr8R7d4+JRuQrfSSNlEwKyPYg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/config": "^2.3.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3" + } + }, + "@changesets/get-version-range-type": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz", + "integrity": "sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==", + "dev": true + }, + "@changesets/git": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-2.0.0.tgz", + "integrity": "sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.2", + "spawndamnit": "^2.0.0" + } + }, + "@changesets/logger": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.0.5.tgz", + "integrity": "sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==", + "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": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.16.tgz", + "integrity": "sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==", + "dev": true, + "requires": { + "@changesets/types": "^5.2.1", + "js-yaml": "^3.13.1" + } + }, + "@changesets/pre": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-1.0.14.tgz", + "integrity": "sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "@changesets/read": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.5.9.tgz", + "integrity": "sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/parse": "^0.3.16", + "@changesets/types": "^5.2.1", + "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": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz", + "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==", + "dev": true + }, + "@changesets/write": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.2.3.tgz", + "integrity": "sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/types": "^5.2.1", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "prettier": "^2.7.1" + } + }, + "@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dev": true, + "requires": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + } + }, + "@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "dev": true, + "requires": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + } + }, + "@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + }, + "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" + } + } + } + }, + "@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "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==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "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": { + "argparse": "^2.0.1" + } + } + } + }, + "@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "requires": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.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 + } + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + }, + "dependencies": { + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + } + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true + }, + "@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "requires": { + "@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/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + }, + "dependencies": { + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "requires": {} + } + } + }, + "@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + }, + "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 + } + } + }, + "@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^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/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@frangio/servbot": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@frangio/servbot/-/servbot-0.2.5.tgz", + "integrity": "sha512-ogja4iAPZ1VwM5MU3C1ZhB88358F0PGbmSTGOkIZwOyLaDoMHIqOVCnavHjR7DV5h+oAI4Z4KDqlam3myQUrmg==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "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", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + }, + "dependencies": { + "@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "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" + } + } + } + }, + "@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "requires": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "dependencies": { + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + } + } + }, + "@noble/hashes": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", + "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", + "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==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@nomicfoundation/ethereumjs-block": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.0.0.tgz", + "integrity": "sha512-bk8uP8VuexLgyIZAHExH1QEovqx0Lzhc9Ntm63nCRKLHXIZkobaFaeCVwTESV7YkPKUk7NiK11s8ryed4CS9yA==", + "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-blockchain": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-6.0.0.tgz", + "integrity": "sha512-pLFEoea6MWd81QQYSReLlLfH7N9v7lH66JC/NMPN848ySPPQA5renWnE7wPByfQFzNrPBuDDRFFULMDmj1C0xw==", + "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", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-block": "^4.0.0", + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "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==", + "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", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + } + }, + "@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==", + "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==", + "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", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "functional-red-black-tree": "^1.0.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-common": "^3.0.0", + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-rlp": "^4.0.0-beta.2", + "ethereum-cryptography": "0.1.3" + } + }, + "@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==", + "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", + "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" + } + }, + "@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==", + "dev": true, + "requires": { + "ethereumjs-util": "^7.1.4" + } + }, + "@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==", + "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": { + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "dev": true, + "optional": true + }, + "@nomiclabs/hardhat-truffle5": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-truffle5/-/hardhat-truffle5-2.0.7.tgz", + "integrity": "sha512-Pw8451IUZp1bTp0QqCHCYfCHs66sCnyxPcaorapu9mfOV9xnZsVaFdtutnhNEiXdiZwbed7LFKpRsde4BjFwig==", + "dev": true, + "requires": { + "@nomiclabs/truffle-contract": "^4.2.23", + "@types/chai": "^4.2.0", + "chai": "^4.2.0", + "ethereumjs-util": "^7.1.4", + "fs-extra": "^7.0.1" + } + }, + "@nomiclabs/hardhat-web3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-web3/-/hardhat-web3-2.0.0.tgz", + "integrity": "sha512-zt4xN+D+fKl3wW2YlTX3k9APR3XZgPkxJYf36AcliJn3oujnKEVRZaHu0PhgLjO+gR+F/kiYayo9fgd2L8970Q==", + "dev": true, + "requires": { + "@types/bignumber.js": "^5.0.0" + } + }, + "@nomiclabs/truffle-contract": { + "version": "4.5.10", + "resolved": "https://registry.npmjs.org/@nomiclabs/truffle-contract/-/truffle-contract-4.5.10.tgz", + "integrity": "sha512-nF/6InFV+0hUvutyFgsdOMCoYlr//2fJbRER4itxYtQtc4/O1biTwZIKRu+5l2J5Sq6LU2WX7vZHtDgQdhWxIQ==", + "dev": true, + "requires": { + "@ensdomains/ensjs": "^2.0.1", + "@truffle/blockchain-utils": "^0.1.3", + "@truffle/contract-schema": "^3.4.7", + "@truffle/debug-utils": "^6.0.22", + "@truffle/error": "^0.1.0", + "@truffle/interface-adapter": "^0.5.16", + "bignumber.js": "^7.2.1", + "ethereum-ens": "^0.8.0", + "ethers": "^4.0.0-beta.1", + "source-map-support": "^0.5.19" + } + }, + "@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "@openzeppelin/docs-utils": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/docs-utils/-/docs-utils-0.1.3.tgz", + "integrity": "sha512-O/iJ4jEi5ryNc/T74G9gbnFwQ8QaQ2bpAVoYXLPknZJyK52GEAvxC12UMP33KodTNV3rMzeeQrSBIdI8skjDJg==", + "dev": true, + "requires": { + "@frangio/servbot": "^0.2.5", + "chalk": "^3.0.0", + "chokidar": "^3.5.3", + "env-paths": "^2.2.0", + "find-up": "^4.1.0", + "is-port-reachable": "^3.0.0", + "js-yaml": "^3.13.1", + "lodash.startcase": "^4.4.0", + "minimist": "^1.2.0" + } + }, + "@openzeppelin/test-helpers": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.16.tgz", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dev": true, + "requires": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "web3-utils": "^1.2.5" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@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", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "dev": true + }, + "@scure/bip32": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", + "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", + "dev": true, + "requires": { + "@noble/hashes": "~1.1.1", + "@noble/secp256k1": "~1.6.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==", + "dev": true, + "requires": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "requires": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + } + }, + "@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true + }, + "@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true + }, + "@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "@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==", + "dev": true, + "requires": { + "change-case": "3.0.2", + "fast-check": "3.1.1", + "web3-utils": "1.8.1" + } + }, + "@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==", + "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==", + "dev": true, + "requires": { + "@truffle/abi-utils": "^0.3.6", + "@truffle/compile-common": "^0.9.1", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "7.3.7", + "utf8": "^3.0.0", + "web3-utils": "1.8.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 + }, + "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==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "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 + } + } + }, + "@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==", + "dev": true, + "requires": { + "@truffle/error": "^0.1.1", + "colors": "1.4.0" + } + }, + "@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==", + "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", + "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" + } + }, + "@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==", + "dev": true, + "requires": { + "ajv": "^6.10.0", + "debug": "^4.3.1" + } + }, + "@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==", + "dev": true, + "requires": { + "@truffle/codec": "^0.14.11", + "@trufflesuite/chromafi": "^3.0.0", + "bn.js": "^5.1.3", + "chalk": "^2.4.2", + "debug": "^4.3.1", + "highlightjs-solidity": "^2.0.5" + }, + "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" + } + } + } + }, + "@truffle/error": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.1.1.tgz", + "integrity": "sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA==", + "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==", + "dev": true, + "requires": { + "bn.js": "^5.1.3", + "ethers": "^4.0.32", + "web3": "1.8.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 + } + } + }, + "@trufflesuite/chromafi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@trufflesuite/chromafi/-/chromafi-3.0.0.tgz", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "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==", + "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" + } + } + } + }, + "@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", + "integrity": "sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==", + "dev": true, + "requires": { + "bignumber.js": "*" + } + }, + "@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "@types/chai": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.4.tgz", + "integrity": "sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw==", + "dev": true + }, + "@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "@types/is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==", + "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": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "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==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/semver": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz", + "integrity": "sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==", + "dev": true + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true + }, + "abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "aes-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", + "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "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==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "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" + } + }, + "antlr4": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", + "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", + "dev": true + }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "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==", + "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" + } + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + } + } + }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "requires": { + "is-windows": "^1.0.0" + } + }, + "big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "dev": true + }, + "big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "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==", + "dev": true + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "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 + }, + "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" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "breakword": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/breakword/-/breakword-1.0.5.tgz", + "integrity": "sha512-ex5W9DoOQ/LUEU3PMdLs9ua/CYZl1678NUkKOdUSi8Aw5F1idieaiRURCBFJCwVcrD1J8Iy3vfWSloaMwO2qFg==", + "dev": true, + "requires": { + "wcwidth": "^1.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "requires": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "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", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-reverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==", + "dev": true + }, + "buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "dev": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "dev": true + }, + "cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "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", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "dev": true + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "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 + } + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "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" + }, + "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 + } + } + }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "dev": true, + "requires": {} + }, + "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" + } + }, + "change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dev": true, + "requires": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "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==", + "dev": true + }, + "cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "dependencies": { + "multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + } + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "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==", + "dev": true, + "requires": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "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", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "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", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "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==", + "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 + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "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==", + "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", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "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==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "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 + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, + "requires": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "requires": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "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==", + "dev": true + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^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==", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "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 + } + } + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "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", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "requires": { + "node-fetch": "2.6.7" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true + }, + "crypto-addr-codec": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.7.tgz", + "integrity": "sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "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", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", + "dev": true + }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "dev": true, + "requires": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + } + }, + "csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "dev": true + }, + "csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "dev": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", + "dev": true + }, + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + }, + "decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "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", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true + } + } + }, + "decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } + } + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "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==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "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", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "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==", + "dev": true + }, + "detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "requires": { + "address": "^1.0.1", + "debug": "4" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "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", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "requires": { + "heap": ">= 0.2.0" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", + "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "dev": true, + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.1" + } + }, + "dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "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": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", + "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "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==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "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", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "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-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "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" + } + } + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "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 + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "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" + } + }, + "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 + }, + "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" + } + } + } + }, + "eslint": { + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "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", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "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" + }, + "dependencies": { + "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 + }, + "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": "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" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "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": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "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==", + "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==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "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", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dev": true, + "requires": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + } + } + }, + "eth-gas-reporter": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz", + "integrity": "sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.0.0-beta.146", + "@solidity-parser/parser": "^0.14.0", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^4.0.40", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^7.1.1", + "req-cwd": "^2.0.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "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" + } + }, + "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", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "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", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "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==", + "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==", + "dev": true, + "requires": { + "@noble/hashes": "1.1.2", + "@noble/secp256k1": "1.6.3", + "@scure/bip32": "1.1.0", + "@scure/bip39": "1.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "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" + } + }, + "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", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "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==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + }, + "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": "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" + } + }, + "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" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } + }, + "eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + }, + "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 + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "eth-sig-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-3.0.1.tgz", + "integrity": "sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==", + "dev": true, + "requires": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^5.1.1", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + } + } + }, + "ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "requires": { + "js-sha3": "^0.8.0" + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereum-ens": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ethereum-ens/-/ethereum-ens-0.8.0.tgz", + "integrity": "sha512-a8cBTF4AWw1Q1Y37V1LSCS9pRY4Mh3f8vCg5cbXCCEJ3eno1hbI/+Ccv9SZLISYpqQhaglP3Bxb/34lS4Qf7Bg==", + "dev": true, + "requires": { + "bluebird": "^3.4.7", + "eth-ens-namehash": "^2.0.0", + "js-sha3": "^0.5.7", + "pako": "^1.0.4", + "underscore": "^1.8.3", + "web3": "^1.0.0-beta.34" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + } + } + }, + "ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + } + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "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 + } + } + }, + "ethereumjs-wallet": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz", + "integrity": "sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==", + "dev": true, + "requires": { + "aes-js": "^3.1.2", + "bs58check": "^2.1.2", + "ethereum-cryptography": "^0.1.3", + "ethereumjs-util": "^7.1.2", + "randombytes": "^2.1.0", + "scrypt-js": "^3.0.1", + "utf8": "^3.0.0", + "uuid": "^8.3.2" + } + }, + "ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "dev": true + } + } + }, + "ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==", + "dev": true + } + } + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "requires": { + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true + }, + "fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dev": true, + "requires": { + "pure-rand": "^5.0.1" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "dev": true, + "requires": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "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==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "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" + } + } + } + }, + "globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "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==", + "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" + }, + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "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==", + "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/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.4.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==", + "dev": true + }, + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "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==", + "dev": true, + "requires": { + "@noble/hashes": "1.1.2", + "@noble/secp256k1": "1.6.3", + "@scure/bip32": "1.1.0", + "@scure/bip39": "1.1.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "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" + } + }, + "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", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "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 + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "requires": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "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" + } + } + } + }, + "hardhat-exposed": { + "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", + "solidity-ast": "^0.4.25" + } + }, + "hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "requires": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + } + }, + "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==", + "dev": true, + "requires": { + "minimatch": "^5.1.0", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "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 + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true + }, + "highlightjs-solidity": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-2.0.5.tgz", + "integrity": "sha512-ReXxQSGQkODMUgHcWzVSnfDCDrL2HshOYgw3OlIYmfHeRzUPkfJTUIp95pK4CmbiNG2eMTOmNLpfCz9Zq7Cwmg==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "htmlparser2": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", + "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "entities": "^4.3.0" + } + }, + "http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "requires": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + } + }, + "http-cache-semantics": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "dev": true + }, + "http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "requires": { + "@types/node": "^10.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-id": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz", + "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "requires": { + "punycode": "2.1.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "immutable": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.1.tgz", + "integrity": "sha512-7WYV7Q5BTs0nlQm7tl92rDYYoyELLKHoDMBKhrxEoiV4mrfVdRz8hzPiYOzH7yWjzoVEamxRuAqhxL2PLRwZYQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "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==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true + }, + "io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "requires": { + "fp-ts": "^1.0.0" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "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": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true + }, + "is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, + "requires": { + "lower-case": "^1.1.0" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "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 + }, + "is-port-reachable": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-3.1.0.tgz", + "integrity": "sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "requires": { + "better-path-resolve": "1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, + "requires": { + "upper-case": "^1.1.0" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "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==", + "dev": true + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "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", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "keccak": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", + "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==", + "dev": true, + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + } + }, + "keccak256": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz", + "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==", + "dev": true, + "requires": { + "bn.js": "^5.2.0", + "buffer": "^6.0.3", + "keccak": "^3.0.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 + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "requires": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + } + }, + "level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true + }, + "level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "requires": { + "error-ex": "^1.2.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 + } + } + }, + "load-yaml-file": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.5", + "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": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", + "dev": true + }, + "lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "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" + } + } + } + }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, + "lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, + "requires": { + "lower-case": "^1.1.2" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true + }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "requires": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true + }, + "meow": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", + "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "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" + } + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "merkletreejs": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.2.32.tgz", + "integrity": "sha512-TostQBiwYRIwSE5++jGmacu3ODcKAgqb0Y/pnIohXS7sWxh1gCkSptbmF1a43faehRDpcHf7J/kv0Ml2D/zblQ==", + "dev": true, + "requires": { + "bignumber.js": "^9.0.1", + "buffer-reverse": "^1.0.1", + "crypto-js": "^3.1.9-1", + "treeify": "^1.1.0", + "web3-utils": "^1.3.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 + } + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "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", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "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": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mixme": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.4.tgz", + "integrity": "sha512-3KYa4m4Vlqx98GPdOHghxSdNtTvcP8E0kkaJ5Dlh+h2DRzF7zpuVVcA8B0QpKd11YJeP9QQ7ASkKzOeu195Wzw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "dev": true, + "requires": { + "mkdirp": "*" + } + }, + "mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "requires": { + "obliterator": "^2.0.0" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "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 + }, + "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 + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "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 + }, + "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": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, + "mock-fs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "dev": true + }, + "module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "dev": true, + "requires": { + "varint": "^5.0.0" + } + }, + "multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, + "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", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==", + "dev": true + }, + "nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "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==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "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", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "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" + } + }, + "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==", + "dev": true + }, + "node-interval-tree": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-2.1.2.tgz", + "integrity": "sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==", + "dev": true, + "requires": { + "shallowequal": "^1.1.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 + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true + }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "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==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "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" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz", + "integrity": "sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw==", + "dev": true, + "requires": { + "array.prototype.reduce": "^1.0.5", + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dev": true, + "requires": { + "http-https": "^1.0.0" + } + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "requires": { + "p-map": "^2.0.0" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } + } + }, + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "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==", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, + "requires": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "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", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "preferred-pm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.0.3.tgz", + "integrity": "sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==", + "dev": true, + "requires": { + "find-up": "^5.0.0", + "find-yarn-workspace-root2": "1.2.16", + "path-exists": "^4.0.0", + "which-pm": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + } + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", + "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "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==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.14.5", + "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==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "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 + } + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "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", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "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", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "dev": true + }, + "pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "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" + } + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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 + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "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" + } + }, + "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" + }, + "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==", + "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==", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "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" + } + } + } + }, + "read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.5", + "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==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "requires": { + "minimatch": "^3.0.5" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "dependencies": { + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + } + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "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==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "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", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "requires": { + "req-from": "^2.0.0" + } + }, + "req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "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 + } + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "dev": true, + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "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==", + "dev": true + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + }, + "dependencies": { + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "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", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "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" + } + } + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "dev": true + }, + "rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "requires": { + "bn.js": "^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 + } + } + }, + "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", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "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", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "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", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + }, + "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" + } + } + } + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "requires": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "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" + }, + "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==", + "dev": true, + "requires": { + "yallist": "^4.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 + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "requires": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "requires": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + } + }, + "sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dev": true, + "requires": { + "buffer": "6.0.3" + }, + "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "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" + } + } + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dev": true, + "requires": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + }, + "dependencies": { + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + } + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "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==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^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" + } + }, + "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 + } + } + }, + "smartwrap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/smartwrap/-/smartwrap-2.0.2.tgz", + "integrity": "sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==", + "dev": true, + "requires": { + "array.prototype.flat": "^1.2.3", + "breakword": "^1.0.5", + "grapheme-splitter": "^1.0.4", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^15.1.0" + }, + "dependencies": { + "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 + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "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==", + "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 + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "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" + } + } + } + }, + "snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dev": true, + "requires": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "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 + }, + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "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" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + } + } + }, + "solhint": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", + "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "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" + }, + "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "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 + }, + "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==", + "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 + }, + "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==", + "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" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "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==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "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==", + "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" + } + } + } + }, + "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==", + "dev": true + }, + "solidity-comments": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments/-/solidity-comments-0.0.2.tgz", + "integrity": "sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==", + "dev": true, + "requires": { + "solidity-comments-darwin-arm64": "0.0.2", + "solidity-comments-darwin-x64": "0.0.2", + "solidity-comments-freebsd-x64": "0.0.2", + "solidity-comments-linux-arm64-gnu": "0.0.2", + "solidity-comments-linux-arm64-musl": "0.0.2", + "solidity-comments-linux-x64-gnu": "0.0.2", + "solidity-comments-linux-x64-musl": "0.0.2", + "solidity-comments-win32-arm64-msvc": "0.0.2", + "solidity-comments-win32-ia32-msvc": "0.0.2", + "solidity-comments-win32-x64-msvc": "0.0.2" + } + }, + "solidity-comments-darwin-arm64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-arm64/-/solidity-comments-darwin-arm64-0.0.2.tgz", + "integrity": "sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==", + "dev": true, + "optional": true + }, + "solidity-comments-darwin-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-x64/-/solidity-comments-darwin-x64-0.0.2.tgz", + "integrity": "sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==", + "dev": true, + "optional": true + }, + "solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "solidity-comments-freebsd-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-freebsd-x64/-/solidity-comments-freebsd-x64-0.0.2.tgz", + "integrity": "sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-arm64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-gnu/-/solidity-comments-linux-arm64-gnu-0.0.2.tgz", + "integrity": "sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-arm64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-musl/-/solidity-comments-linux-arm64-musl-0.0.2.tgz", + "integrity": "sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-x64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-gnu/-/solidity-comments-linux-x64-gnu-0.0.2.tgz", + "integrity": "sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-x64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-musl/-/solidity-comments-linux-x64-musl-0.0.2.tgz", + "integrity": "sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-arm64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-arm64-msvc/-/solidity-comments-win32-arm64-msvc-0.0.2.tgz", + "integrity": "sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-ia32-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-ia32-msvc/-/solidity-comments-win32-ia32-msvc-0.0.2.tgz", + "integrity": "sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-x64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-x64-msvc/-/solidity-comments-win32-x64-msvc-0.0.2.tgz", + "integrity": "sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==", + "dev": true, + "optional": true + }, + "solidity-coverage": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.2.tgz", + "integrity": "sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.14.1", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "7.1.2", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "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" + } + }, + "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", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "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", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "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==", + "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", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "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" + } + }, + "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", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", + "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "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==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "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==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + }, + "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==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "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" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } + }, + "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==", + "dev": true, + "requires": { + "handlebars": "^4.7.7", + "solidity-ast": "^0.4.38" + } + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "spawndamnit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz", + "integrity": "sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==", + "dev": true, + "requires": { + "cross-spawn": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "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==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "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 + }, + "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" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "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==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + } + } + }, + "stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "requires": { + "type-fest": "^0.7.1" + }, + "dependencies": { + "type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", + "dev": true + }, + "stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "dev": true, + "requires": { + "mixme": "^0.5.1" + } + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "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" + } + }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "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" + } + }, + "swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + }, + "dependencies": { + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true + } + } + }, + "sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "requires": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + } + }, + "sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "requires": { + "get-port": "^3.1.0" + } + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "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 + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "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==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + } + } + }, + "tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "requires": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "requires": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + } + } + }, + "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", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true + }, + "title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "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==", + "dev": true + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "dev": true + }, + "trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "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==", + "dev": true, + "requires": { + "chalk": "^4.1.2", + "csv": "^5.5.0", + "kleur": "^4.1.4", + "smartwrap": "^2.0.2", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^17.1.1" + }, + "dependencies": { + "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 + }, + "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" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "undici": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "dev": true, + "requires": { + "busboy": "^1.6.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, + "upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, + "requires": { + "upper-case": "^1.1.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "dev": true + }, + "utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "web3": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.8.1.tgz", + "integrity": "sha512-tAqFsQhGv340C9OgRJIuoScN7f7wa1tUvsnnDUMt9YE6J4gcm7TV2Uwv+KERnzvV+xgdeuULYpsioRRNKrUvoQ==", + "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": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.8.1.tgz", + "integrity": "sha512-dJJHS84nvpoxv6ijTMkdUSlRr5beCXNtx4UZcrFLHBva8dT63QEtKdLyDt2AyMJJdVzTCk78uir/6XtVWrdS6w==", + "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==", + "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" + }, + "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", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "dev": true + } + } + }, + "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==", + "dev": true, + "requires": { + "web3-eth-iban": "1.8.1", + "web3-utils": "1.8.1" + } + }, + "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==", + "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-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==", + "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==", + "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" + } + }, + "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==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.1" + } + }, + "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==", + "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-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==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.8.1" + } + }, + "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==", + "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", + "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" + }, + "dependencies": { + "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-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==", + "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-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==", + "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-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==", + "dev": true, + "requires": { + "bn.js": "^5.2.1", + "web3-utils": "1.8.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 + } + } + }, + "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==", + "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-net": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.8.1.tgz", + "integrity": "sha512-LyEJAwogdFo0UAXZqoSJGFjopdt+kLw0P00FSZn2yszbgcoI7EwC+nXiOsEe12xz4LqpYLOtbR7+gxgiTVjjHQ==", + "dev": true, + "requires": { + "web3-core": "1.8.1", + "web3-core-method": "1.8.1", + "web3-utils": "1.8.1" + } + }, + "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==", + "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-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==", + "dev": true, + "requires": { + "oboe": "2.1.5", + "web3-core-helpers": "1.8.1" + } + }, + "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==", + "dev": true, + "requires": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.8.1", + "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==", + "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-utils": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.8.1.tgz", + "integrity": "sha512-LgnM9p6V7rHHUGfpMZod+NST8cRfGzJ1BTXAyNo7A9cJX9LczBfSRxJp+U/GInYe9mby40t3v22AJdlELibnsQ==", + "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 + } + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dev": true, + "requires": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "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==", + "dev": true + }, + "which-pm": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", + "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", + "dev": true, + "requires": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "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", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + }, + "xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "requires": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "requires": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "requires": { + "xhr-request": "^1.1.0" + } + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "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==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "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 + }, + "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 + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } + }, + "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 + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/package.json b/lib/crytic/lib/openzeppelin-contracts/package.json new file mode 100644 index 0000000..66d4488 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/package.json @@ -0,0 +1,94 @@ +{ + "name": "openzeppelin-solidity", + "description": "Secure Smart Contract library for Solidity", + "version": "4.8.0", + "files": [ + "/contracts/**/*.sol", + "/build/contracts/*.json", + "!/contracts/mocks/**/*" + ], + "bin": { + "openzeppelin-contracts-migrate-imports": "scripts/migrate-imports.js" + }, + "scripts": { + "compile": "hardhat compile", + "coverage": "env COVERAGE=true hardhat coverage", + "docs": "npm run prepare-docs && oz-docs", + "docs:watch": "oz-docs watch contracts docs/templates docs/config.js", + "prepare-docs": "scripts/prepare-docs.sh", + "lint": "npm run lint:js && npm run lint:sol", + "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' --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", + "prepack": "scripts/prepack.sh", + "generate": "scripts/generate/run.js", + "release": "scripts/release/release.sh", + "version": "scripts/release/version.sh", + "test": "hardhat test", + "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" + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "security", + "zeppelin" + ], + "author": "OpenZeppelin Community ", + "license": "MIT", + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, + "homepage": "https://openzeppelin.com/contracts/", + "devDependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-truffle5": "^2.0.5", + "@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", + "eth-sig-util": "^3.0.0", + "ethereumjs-util": "^7.0.7", + "ethereumjs-wallet": "^1.0.1", + "glob": "^8.0.3", + "graphlib": "^2.1.8", + "hardhat": "^2.9.1", + "hardhat-exposed": "^0.3.1", + "hardhat-gas-reporter": "^1.0.4", + "hardhat-ignore-warnings": "^0.2.0", + "keccak256": "^1.0.2", + "lodash.startcase": "^4.4.0", + "lodash.zip": "^4.2.0", + "merkletreejs": "^0.2.13", + "micromatch": "^4.0.2", + "prettier": "^2.8.1", + "prettier-plugin-solidity": "^1.1.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "solhint": "^3.3.6", + "solidity-ast": "^0.4.25", + "solidity-coverage": "^0.8.0", + "solidity-docgen": "^0.6.0-beta.29", + "web3": "^1.3.0", + "yargs": "^17.0.0" + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/renovate.json b/lib/crytic/lib/openzeppelin-contracts/renovate.json new file mode 100644 index 0000000..c0b97d8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/renovate.json @@ -0,0 +1,4 @@ +{ + "extends": ["github>OpenZeppelin/configs"], + "labels": ["ignore-changeset"] +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/checks/compare-layout.js b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/compare-layout.js new file mode 100644 index 0000000..7b7df99 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/compare-layout.js @@ -0,0 +1,19 @@ +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(report.explain()); + process.exitCode = 1; + } + } else { + console.log(`WARNING: ${name} is missing from the current branch`); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js new file mode 100755 index 0000000..160c8cc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js @@ -0,0 +1,243 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const chalk = require('chalk'); +const { argv } = require('yargs') + .env() + .options({ + style: { + type: 'string', + choices: ['shell', 'markdown'], + default: 'shell', + }, + hideEqual: { + type: 'boolean', + default: true, + }, + strictTesting: { + type: 'boolean', + default: false, + }, + }); + +// Deduce base tx cost from the percentage denominator +const BASE_TX_COST = 21000; + +// Utilities +function sum(...args) { + return args.reduce((a, b) => a + b, 0); +} + +function average(...args) { + return sum(...args) / args.length; +} + +function variation(current, previous, offset = 0) { + return { + value: current, + delta: current - previous, + prcnt: (100 * (current - previous)) / (previous - offset), + }; +} + +// Report class +class Report { + // Read report file + static load(filepath) { + return JSON.parse(fs.readFileSync(filepath, 'utf8')); + } + + // Compare two reports + 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'); + } + + const deployments = update.info.deployments + .map(contract => + Object.assign(contract, { previousVersion: ref.info.deployments.find(({ name }) => name === contract.name) }), + ) + .filter(contract => contract.gasData?.length && contract.previousVersion?.gasData?.length) + .flatMap(contract => [ + { + contract: contract.name, + method: '[bytecode length]', + avg: variation(contract.bytecode.length / 2 - 1, contract.previousVersion.bytecode.length / 2 - 1), + }, + { + contract: contract.name, + method: '[construction cost]', + avg: variation( + ...[contract.gasData, contract.previousVersion.gasData].map(x => Math.round(average(...x))), + BASE_TX_COST, + ), + }, + ]) + .sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`)); + + const methods = Object.keys(update.info.methods) + .filter(key => ref.info.methods[key]) + .filter(key => update.info.methods[key].numberOfCalls > 0) + .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, + min: variation(...[update, ref].map(x => Math.min(...x.info.methods[key].gasData)), BASE_TX_COST), + max: variation(...[update, ref].map(x => Math.max(...x.info.methods[key].gasData)), BASE_TX_COST), + avg: variation(...[update, ref].map(x => Math.round(average(...x.info.methods[key].gasData))), BASE_TX_COST), + })) + .sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`)); + + return [] + .concat(deployments, methods) + .filter(row => !opts.hideEqual || row.min?.delta || row.max?.delta || row.avg?.delta); + } +} + +// Display +function center(text, length) { + return text.padStart((text.length + length) / 2).padEnd(length); +} + +function plusSign(num) { + return num > 0 ? '+' : ''; +} + +function formatCellShell(cell) { + const format = chalk[cell?.delta > 0 ? 'red' : cell?.delta < 0 ? 'green' : 'reset']; + return [ + format((!isFinite(cell?.value) ? '-' : cell.value.toString()).padStart(8)), + format((!isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString()).padStart(8)), + format((!isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%').padStart(8)), + ]; +} + +function formatCmpShell(rows) { + const contractLength = Math.max(8, ...rows.map(({ contract }) => contract.length)); + const methodLength = Math.max(7, ...rows.map(({ method }) => method.length)); + + const COLS = [ + { txt: '', length: 0 }, + { txt: 'Contract', length: contractLength }, + { txt: 'Method', length: methodLength }, + { txt: 'Min', length: 30 }, + { txt: 'Max', length: 30 }, + { txt: 'Avg', length: 30 }, + { txt: '', length: 0 }, + ]; + const HEADER = COLS.map(entry => chalk.bold(center(entry.txt, entry.length || 0))) + .join(' | ') + .trim(); + const SEPARATOR = COLS.map(({ length }) => (length > 0 ? '-'.repeat(length + 2) : '')) + .join('|') + .trim(); + + return [ + '', + HEADER, + ...rows.map(entry => + [ + '', + chalk.grey(entry.contract.padEnd(contractLength)), + entry.method.padEnd(methodLength), + ...formatCellShell(entry.min), + ...formatCellShell(entry.max), + ...formatCellShell(entry.avg), + '', + ] + .join(' | ') + .trim(), + ), + '', + ] + .join(`\n${SEPARATOR}\n`) + .trim(); +} + +function alignPattern(align) { + switch (align) { + case 'left': + case undefined: + return ':-'; + case 'right': + return '-:'; + case 'center': + return ':-:'; + } +} + +function trend(value) { + return value > 0 ? ':x:' : value < 0 ? ':heavy_check_mark:' : ':heavy_minus_sign:'; +} + +function formatCellMarkdown(cell) { + return [ + !isFinite(cell?.value) ? '-' : cell.value.toString(), + !isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString(), + !isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%' + trend(cell.delta), + ]; +} + +function formatCmpMarkdown(rows) { + const COLS = [ + { txt: '' }, + { txt: 'Contract', align: 'left' }, + { txt: 'Method', align: 'left' }, + { txt: 'Min', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: 'Max', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: 'Avg', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: '' }, + ]; + const HEADER = COLS.map(entry => entry.txt) + .join(' | ') + .trim(); + const SEPARATOR = COLS.map(entry => (entry.txt ? alignPattern(entry.align) : '')) + .join('|') + .trim(); + + return [ + '# Changes to gas costs', + '', + HEADER, + SEPARATOR, + rows + .map(entry => + [ + '', + entry.contract, + entry.method, + ...formatCellMarkdown(entry.min), + ...formatCellMarkdown(entry.max), + ...formatCellMarkdown(entry.avg), + '', + ] + .join(' | ') + .trim(), + ) + .join('\n'), + '', + ] + .join('\n') + .trim(); +} + +// MAIN +const report = Report.compare(Report.load(argv._[0]), Report.load(argv._[1]), argv); + +switch (argv.style) { + case 'markdown': + console.log(formatCmpMarkdown(report)); + break; + case 'shell': + default: + console.log(formatCmpShell(report)); + break; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/checks/extract-layout.js b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/extract-layout.js new file mode 100644 index 0000000..d0c9cf3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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)))); diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/checks/generation.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/generation.sh new file mode 100755 index 0000000..00d609f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/generation.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +npm run generate +git diff -R --exit-code diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js new file mode 100755 index 0000000..45c707e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js @@ -0,0 +1,54 @@ +#!/usr/bin/env node + +const path = require('path'); +const graphlib = require('graphlib'); +const { findAll } = require('solidity-ast/utils'); +const { _: artifacts } = require('yargs').argv; + +for (const artifact of artifacts) { + const { output: solcOutput } = require(path.resolve(__dirname, '../..', artifact)); + + const graph = new graphlib.Graph({ directed: true }); + const names = {}; + const linearized = []; + + for (const source in solcOutput.contracts) { + if (source.includes('/mocks/')) { + continue; + } + + for (const contractDef of findAll('ContractDefinition', solcOutput.sources[source].ast)) { + names[contractDef.id] = contractDef.name; + linearized.push(contractDef.linearizedBaseContracts); + + contractDef.linearizedBaseContracts.forEach((c1, i, contracts) => + contracts.slice(i + 1).forEach(c2 => { + graph.setEdge(c1, c2); + }), + ); + } + } + + /// graphlib.alg.findCycles will not find minimal cycles. + /// We are only interested int cycles of lengths 2 (needs proof) + graph.nodes().forEach((x, i, nodes) => + nodes + .slice(i + 1) + .filter(y => graph.hasEdge(x, y) && graph.hasEdge(y, x)) + .forEach(y => { + console.log(`Conflict between ${names[x]} and ${names[y]} detected in the following dependency chains:`); + linearized + .filter(chain => chain.includes(parseInt(x)) && chain.includes(parseInt(y))) + .forEach(chain => { + const comp = chain.indexOf(parseInt(x)) < chain.indexOf(parseInt(y)) ? '>' : '<'; + console.log(`- ${names[x]} ${comp} ${names[y]} in ${names[chain.find(Boolean)]}`); + // console.log(`- ${names[x]} ${comp} ${names[y]}: ${chain.reverse().map(id => names[id]).join(', ')}`); + }); + process.exitCode = 1; + }), + ); +} + +if (!process.exitCode) { + console.log('Contract ordering is consistent.'); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/gen-nav.js b/lib/crytic/lib/openzeppelin-contracts/scripts/gen-nav.js new file mode 100644 index 0000000..de3d0da --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/gen-nav.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node + +const path = require('path'); +const glob = require('glob'); +const startCase = require('lodash.startcase'); + +const baseDir = process.argv[2]; + +const files = glob.sync(baseDir + '/**/*.adoc').map(f => path.relative(baseDir, f)); + +console.log('.API'); + +function getPageTitle(directory) { + switch (directory) { + case 'metatx': + return 'Meta Transactions'; + case 'common': + return 'Common (Tokens)'; + default: + return startCase(directory); + } +} + +const links = files.map(file => { + const doc = file.replace(baseDir, ''); + const title = path.parse(file).name; + + return { + xref: `* xref:${doc}[${getPageTitle(title)}]`, + title, + }; +}); + +// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20') +const sortedLinks = links.sort(function (a, b) { + return a.title.toLowerCase().localeCompare(b.title.toLowerCase(), undefined, { numeric: true }); +}); + +for (const link of sortedLinks) { + console.log(link.xref); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/generate/format-lines.js b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/format-lines.js new file mode 100644 index 0000000..fa3d6b1 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/format-lines.js @@ -0,0 +1,16 @@ +function formatLines(...lines) { + return [...indentEach(0, lines)].join('\n') + '\n'; +} + +function* indentEach(indent, lines) { + for (const line of lines) { + if (Array.isArray(line)) { + yield* indentEach(indent + 1, line); + } else { + const padding = ' '.repeat(indent); + yield* line.split('\n').map(subline => (subline === '' ? '' : padding + subline)); + } + } +} + +module.exports = formatLines; diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/generate/run.js b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/run.js new file mode 100755 index 0000000..e68681e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/run.js @@ -0,0 +1,37 @@ +#!/usr/bin/env node + +const cp = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const format = require('./format-lines'); + +function getVersion(path) { + try { + return fs.readFileSync(path, 'utf8').match(/\/\/ OpenZeppelin Contracts \(last updated v[^)]+\)/)[0]; + } catch (err) { + return null; + } +} + +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', +})) { + const script = path.relative(path.join(__dirname, '../..'), __filename); + const input = path.join(path.dirname(script), template); + const output = `./contracts/${file}`; + const version = getVersion(output); + const content = format( + '// SPDX-License-Identifier: MIT', + ...(version ? [version + ` (${file})`] : []), + `// This file was procedurally generated from ${input}.`, + '', + require(template), + ); + + fs.writeFileSync(output, content); + cp.execFileSync('prettier', ['--write', output]); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js new file mode 100644 index 0000000..e51e8b8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js @@ -0,0 +1,325 @@ +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; + +import "./math/Math.sol"; +import "./math/SafeCast.sol"; + +/** + * @dev This library defines the \`History\` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type \`Checkpoints.History\` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + * + * _Available since v4.5._ + */ +`; + +const types = opts => `\ +struct ${opts.historyTypeName} { + ${opts.checkpointTypeName}[] ${opts.checkpointFieldName}; +} + +struct ${opts.checkpointTypeName} { + ${opts.keyTypeName} ${opts.keyFieldName}; + ${opts.valueTypeName} ${opts.valueFieldName}; +} +`; + +/* eslint-disable max-len */ +const operations = opts => `\ +/** + * @dev Pushes a (\`key\`, \`value\`) pair into a ${opts.historyTypeName} so that it is stored as the checkpoint. + * + * Returns previous value and new value. + */ +function push( + ${opts.historyTypeName} storage self, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) internal returns (${opts.valueTypeName}, ${opts.valueTypeName}) { + return _insert(self.${opts.checkpointFieldName}, key, value); +} + +/** + * @dev Returns the value in the oldest checkpoint with key greater or equal than the search key, or zero if there is none. + */ +function lowerLookup(${opts.historyTypeName} storage self, ${opts.keyTypeName} key) internal view returns (${opts.valueTypeName}) { + uint256 len = self.${opts.checkpointFieldName}.length; + uint256 pos = _lowerBinaryLookup(self.${opts.checkpointFieldName}, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos).${opts.valueFieldName}; +} + +/** + * @dev Returns the value in the 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; + 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 => `\ +/** + * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one + * before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the + * block, the requested block number must be in the past, excluding the current block. + */ +function getAtBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) { + require(blockNumber < block.number, "Checkpoints: block not yet mined"); + uint32 key = SafeCast.toUint32(blockNumber); + + uint256 len = self.${opts.checkpointFieldName}.length; + 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 at a given block number. If a checkpoint is not available at that block, the closest one + * before it is returned, or zero otherwise. Similar to {upperLookup} but optimized for the case when the searched + * checkpoint is probably "recent", defined as being among the last sqrt(N) checkpoints where N is the number of + * checkpoints. + */ +function getAtProbablyRecentBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) { + require(blockNumber < block.number, "Checkpoints: block not yet mined"); + uint32 key = SafeCast.toUint32(blockNumber); + + uint256 len = self.${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)._blockNumber) { + 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}; +} + +/** + * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block. + * + * Returns previous value and new value. + */ +function push(${opts.historyTypeName} storage self, uint256 value) internal returns (uint256, uint256) { + return _insert(self.${opts.checkpointFieldName}, SafeCast.toUint32(block.number), SafeCast.toUint224(value)); +} + +/** + * @dev Pushes a value onto a History, by updating the latest value using binary operation \`op\`. The new value will + * be set to \`op(latest, delta)\`. + * + * Returns previous value and new value. + */ +function push( + ${opts.historyTypeName} storage self, + function(uint256, uint256) view returns (uint256) op, + uint256 delta +) internal returns (uint256, uint256) { + return push(self, op(latest(self), delta)); +} +`; + +const common = opts => `\ +/** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ +function latest(${opts.historyTypeName} storage self) internal view returns (${opts.valueTypeName}) { + uint256 pos = self.${opts.checkpointFieldName}.length; + return pos == 0 ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1).${opts.valueFieldName}; +} + +/** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ +function latestCheckpoint(${opts.historyTypeName} storage self) + internal + view + returns ( + bool exists, + ${opts.keyTypeName} ${opts.keyFieldName}, + ${opts.valueTypeName} ${opts.valueFieldName} + ) +{ + uint256 pos = self.${opts.checkpointFieldName}.length; + if (pos == 0) { + return (false, 0, 0); + } else { + ${opts.checkpointTypeName} memory ckpt = _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1); + return (true, ckpt.${opts.keyFieldName}, ckpt.${opts.valueFieldName}); + } +} + +/** + * @dev Returns the number of checkpoint. + */ +function length(${opts.historyTypeName} storage self) internal view returns (uint256) { + return self.${opts.checkpointFieldName}.length; +} + +/** + * @dev Pushes a (\`key\`, \`value\`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ +function _insert( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) private returns (${opts.valueTypeName}, ${opts.valueTypeName}) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + ${opts.checkpointTypeName} memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + require(last.${opts.keyFieldName} <= key, "Checkpoint: decreasing keys"); + + // Update or push new checkpoint + if (last.${opts.keyFieldName} == key) { + _unsafeAccess(self, pos - 1).${opts.valueFieldName} = value; + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + } + return (last.${opts.valueFieldName}, value); + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + return (0, value); + } +} + +/** + * @dev Return the index of the oldest checkpoint whose key is greater than the search key, or \`high\` if there is none. + * \`low\` and \`high\` define a section where to do the search, with inclusive \`low\` and exclusive \`high\`. + * + * WARNING: \`high\` should not be greater than the array's length. + */ +function _upperBinaryLookup( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + uint256 low, + uint256 high +) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid).${opts.keyFieldName} > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; +} + +/** + * @dev Return the index of the oldest checkpoint whose key is greater or equal than the search key, or \`high\` if there is none. + * \`low\` and \`high\` define a section where to do the search, with inclusive \`low\` and exclusive \`high\`. + * + * WARNING: \`high\` should not be greater than the array's length. + */ +function _lowerBinaryLookup( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + uint256 low, + uint256 high +) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid).${opts.keyFieldName} < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; +} + +/** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ +function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos) + private + pure + returns (${opts.checkpointTypeName} storage result) +{ + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } +} +`; +/* eslint-enable max-len */ + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library Checkpoints {', + [ + // Legacy types & functions + types(LEGACY_OPTS), + legacyOperations(LEGACY_OPTS), + common(LEGACY_OPTS), + // New flavors + ...OPTS.flatMap(opts => [types(opts), operations(opts), common(opts)]), + ], + '}', +); diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js new file mode 100644 index 0000000..2bbb69e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js @@ -0,0 +1,310 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); + +const TYPES = [ + { name: 'UintToUintMap', keyType: 'uint256', valueType: 'uint256' }, + { name: 'UintToAddressMap', keyType: 'uint256', valueType: 'address' }, + { name: 'AddressToUintMap', keyType: 'address', valueType: 'uint256' }, + { name: 'Bytes32ToUintMap', keyType: 'bytes32', valueType: 'uint256' }, +]; + +/* eslint-disable max-len */ +const header = `\ +pragma solidity ^0.8.0; + +import "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[\`mapping\`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * \`\`\` + * + * The following map types are supported: + * + * - \`uint256 -> address\` (\`UintToAddressMap\`) since v3.0.0 + * - \`address -> uint256\` (\`AddressToUintMap\`) since v4.6.0 + * - \`bytes32 -> bytes32\` (\`Bytes32ToBytes32Map\`) since v4.6.0 + * - \`uint256 -> uint256\` (\`UintToUintMap\`) since v4.7.0 + * - \`bytes32 -> uint256\` (\`Bytes32ToUintMap\`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +`; +/* eslint-enable max-len */ + +const defaultMap = () => `\ +// To implement this library for multiple types with as little code +// repetition as possible, we write it in terms of a generic Map type with +// bytes32 keys and values. +// The Map implementation uses private functions, and user-facing +// implementations (such as Uint256ToAddressMap) are just wrappers around +// the underlying Map. +// This means that we can only create new EnumerableMaps for types that fit +// in bytes32. + +struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 => bytes32) _values; +} + +/** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ +function set( + Bytes32ToBytes32Map storage map, + bytes32 key, + bytes32 value +) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); +} + +/** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ +function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); +} + +/** + * @dev Returns the number of key-value pairs in the map. O(1). + */ +function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); +} + +/** + * @dev Returns the key-value pair stored at position \`index\` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); +} + +/** + * @dev Tries to returns the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key"); + return value; +} + +/** + * @dev Same as {get}, with a custom error message when \`key\` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ +function get( + Bytes32ToBytes32Map storage map, + bytes32 key, + string memory errorMessage +) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), errorMessage); + return value; +} + +/** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { + return map._keys.values(); +} +`; + +const customMap = ({ name, keyType, valueType }) => `\ +// ${name} + +struct ${name} { + Bytes32ToBytes32Map _inner; +} + +/** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ +function set( + ${name} storage map, + ${keyType} key, + ${valueType} value +) internal returns (bool) { + return set(map._inner, ${toBytes32(keyType, 'key')}, ${toBytes32(valueType, 'value')}); +} + +/** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ +function remove(${name} storage map, ${keyType} key) internal returns (bool) { + return remove(map._inner, ${toBytes32(keyType, 'key')}); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(${name} storage map, ${keyType} key) internal view returns (bool) { + return contains(map._inner, ${toBytes32(keyType, 'key')}); +} + +/** + * @dev Returns the number of elements in the map. O(1). + */ +function length(${name} storage map) internal view returns (uint256) { + return length(map._inner); +} + +/** + * @dev Returns the element stored at position \`index\` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(${name} storage map, uint256 index) internal view returns (${keyType}, ${valueType}) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (${fromBytes32(keyType, 'key')}, ${fromBytes32(valueType, 'value')}); +} + +/** + * @dev Tries to returns the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(${name} storage map, ${keyType} key) internal view returns (bool, ${valueType}) { + (bool success, bytes32 value) = tryGet(map._inner, ${toBytes32(keyType, 'key')}); + return (success, ${fromBytes32(valueType, 'value')}); +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(${name} storage map, ${keyType} key) internal view returns (${valueType}) { + return ${fromBytes32(valueType, `get(map._inner, ${toBytes32(keyType, 'key')})`)}; +} + +/** + * @dev Same as {get}, with a custom error message when \`key\` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ +function get( + ${name} storage map, + ${keyType} key, + string memory errorMessage +) internal view returns (${valueType}) { + return ${fromBytes32(valueType, `get(map._inner, ${toBytes32(keyType, 'key')}, errorMessage)`)}; +} + +/** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function keys(${name} storage map) internal view returns (${keyType}[] memory) { + bytes32[] memory store = keys(map._inner); + ${keyType}[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableMap {', + [ + 'using EnumerableSet for EnumerableSet.Bytes32Set;', + '', + defaultMap(), + TYPES.map(details => customMap(details).trimEnd()).join('\n\n'), + ], + '}', +); diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js new file mode 100644 index 0000000..2b6a9c6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js @@ -0,0 +1,250 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); + +const TYPES = [ + { name: 'Bytes32Set', type: 'bytes32' }, + { name: 'AddressSet', type: 'address' }, + { name: 'UintSet', type: 'uint256' }, +]; + +/* eslint-disable max-len */ +const header = `\ +pragma solidity ^0.8.0; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * \`\`\` + * + * As of v3.3.0, sets of type \`bytes32\` (\`Bytes32Set\`), \`address\` (\`AddressSet\`) + * and \`uint256\` (\`UintSet\`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +`; +/* eslint-enable max-len */ + +const defaultSet = () => `\ +// To implement this library for multiple types with as little code +// repetition as possible, we write it in terms of a generic Set type with +// bytes32 values. +// The Set implementation uses private functions, and user-facing +// implementations (such as AddressSet) are just wrappers around the +// underlying Set. +// This means that we can only create new EnumerableSets for types that fit +// in bytes32. + +struct Set { + // Storage of set values + bytes32[] _values; + // Position of the value in the \`values\` array, plus 1 because index 0 + // means a value is not in the set. + mapping(bytes32 => uint256) _indexes; +} + +/** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ +function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } +} + +/** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ +function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastValue; + // Update the index for the moved value + set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; +} + +/** + * @dev Returns the number of values on the set. O(1). + */ +function _length(Set storage set) private view returns (uint256) { + return set._values.length; +} + +/** + * @dev Returns the value stored at position \`index\` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; +} + +/** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; +} +`; + +const customSet = ({ name, type }) => `\ +// ${name} + +struct ${name} { + Set _inner; +} + +/** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ +function add(${name} storage set, ${type} value) internal returns (bool) { + return _add(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ +function remove(${name} storage set, ${type} value) internal returns (bool) { + return _remove(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function contains(${name} storage set, ${type} value) internal view returns (bool) { + return _contains(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Returns the number of values in the set. O(1). + */ +function length(${name} storage set) internal view returns (uint256) { + return _length(set._inner); +} + +/** + * @dev Returns the value stored at position \`index\` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(${name} storage set, uint256 index) internal view returns (${type}) { + return ${fromBytes32(type, '_at(set._inner, index)')}; +} + +/** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function values(${name} storage set) internal view returns (${type}[] memory) { + bytes32[] memory store = _values(set._inner); + ${type}[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableSet {', + [defaultSet(), TYPES.map(details => customSet(details).trimEnd()).join('\n\n')], + '}', +); diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js new file mode 100644 index 0000000..3e2b148 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js @@ -0,0 +1,163 @@ +const assert = require('assert'); +const format = require('../format-lines'); +const { range } = require('../../helpers'); + +const LENGTHS = range(8, 256, 8).reverse(); // 248 → 8 (in steps of 8) + +// Returns the version of OpenZeppelin Contracts in which a particular function was introduced. +// This is used in the docs for each function. +const version = (selector, length) => { + switch (selector) { + case 'toUint(uint)': { + switch (length) { + case 8: + case 16: + case 32: + case 64: + case 128: + return '2.5'; + case 96: + case 224: + return '4.2'; + default: + assert(LENGTHS.includes(length)); + return '4.7'; + } + } + case 'toInt(int)': { + switch (length) { + case 8: + case 16: + case 32: + case 64: + case 128: + return '3.1'; + default: + assert(LENGTHS.includes(length)); + return '4.7'; + } + } + case 'toUint(int)': { + switch (length) { + case 256: + return '3.0'; + default: + assert(false); + return; + } + } + case 'toInt(uint)': { + switch (length) { + case 256: + return '3.0'; + default: + assert(false); + return; + } + } + default: + assert(false); + } +}; + +const header = `\ +pragma solidity ^0.8.0; + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. \`SafeCast\` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + * + * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing + * all math on \`uint256\` and \`int256\` and then downcasting. + */ +`; + +const toUintDownCast = length => `\ +/** + * @dev Returns the downcasted uint${length} from uint256, reverting on + * overflow (when the input is greater than largest uint${length}). + * + * Counterpart to Solidity's \`uint${length}\` operator. + * + * Requirements: + * + * - input must fit into ${length} bits + * + * _Available since v${version('toUint(uint)', length)}._ + */ +function toUint${length}(uint256 value) internal pure returns (uint${length}) { + require(value <= type(uint${length}).max, "SafeCast: value doesn't fit in ${length} bits"); + return uint${length}(value); +} +`; + +/* eslint-disable max-len */ +const toIntDownCast = length => `\ +/** + * @dev Returns the downcasted int${length} from int256, reverting on + * overflow (when the input is less than smallest int${length} or + * greater than largest int${length}). + * + * Counterpart to Solidity's \`int${length}\` operator. + * + * Requirements: + * + * - input must fit into ${length} bits + * + * _Available since v${version('toInt(int)', length)}._ + */ +function toInt${length}(int256 value) internal pure returns (int${length} downcasted) { + downcasted = int${length}(value); + require(downcasted == value, "SafeCast: value doesn't fit in ${length} bits"); +} +`; +/* eslint-enable max-len */ + +const toInt = length => `\ +/** + * @dev Converts an unsigned uint${length} into a signed int${length}. + * + * Requirements: + * + * - input must be less than or equal to maxInt${length}. + * + * _Available since v${version('toInt(uint)', length)}._ + */ +function toInt${length}(uint${length} value) internal pure returns (int${length}) { + // Note: Unsafe cast below is okay because \`type(int${length}).max\` is guaranteed to be positive + require(value <= uint${length}(type(int${length}).max), "SafeCast: value doesn't fit in an int${length}"); + return int${length}(value); +} +`; + +const toUint = length => `\ +/** + * @dev Converts a signed int${length} into an unsigned uint${length}. + * + * Requirements: + * + * - input must be greater than or equal to 0. + * + * _Available since v${version('toUint(int)', length)}._ + */ +function toUint${length}(int${length} value) internal pure returns (uint${length}) { + require(value >= 0, "SafeCast: value must be positive"); + return uint${length}(value); +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library SafeCast {', + [...LENGTHS.map(toUintDownCast), toUint(256), ...LENGTHS.map(toIntDownCast), toInt(256)], + '}', +); diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js new file mode 100644 index 0000000..69fa7cc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js new file mode 100644 index 0000000..9221f7c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js @@ -0,0 +1,30 @@ +function toBytes32(type, value) { + switch (type) { + case 'bytes32': + return value; + case 'uint256': + return `bytes32(${value})`; + case 'address': + return `bytes32(uint256(uint160(${value})))`; + default: + throw new Error(`Conversion from ${type} to bytes32 not supported`); + } +} + +function fromBytes32(type, value) { + switch (type) { + case 'bytes32': + return value; + case 'uint256': + return `uint256(${value})`; + case 'address': + return `address(uint160(uint256(${value})))`; + default: + throw new Error(`Conversion from bytes32 to ${type} not supported`); + } +} + +module.exports = { + toBytes32, + fromBytes32, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/git-user-config.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/git-user-config.sh new file mode 100644 index 0000000..e7b81c3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/git-user-config.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail -x + +git config user.name 'github-actions' +git config user.email '41898282+github-actions[bot]@users.noreply.github.com' diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/helpers.js b/lib/crytic/lib/openzeppelin-contracts/scripts/helpers.js new file mode 100644 index 0000000..fb9aad4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/helpers.js @@ -0,0 +1,37 @@ +function chunk(array, size = 1) { + return Array.range(Math.ceil(array.length / size)).map(i => array.slice(i * size, i * size + size)); +} + +function range(start, stop = undefined, step = 1) { + if (!stop) { + stop = start; + start = 0; + } + return start < stop + ? Array(Math.ceil((stop - start) / step)) + .fill() + .map((_, i) => start + i * step) + : []; +} + +function unique(array, op = x => x) { + return array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i); +} + +function zip(...args) { + return Array(Math.max(...args.map(arg => arg.length))) + .fill(null) + .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/lib/crytic/lib/openzeppelin-contracts/scripts/migrate-imports.js b/lib/crytic/lib/openzeppelin-contracts/scripts/migrate-imports.js new file mode 100755 index 0000000..f604419 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/migrate-imports.js @@ -0,0 +1,180 @@ +#!/usr/bin/env node + +const { promises: fs } = require('fs'); +const path = require('path'); + +const pathUpdates = { + // 'access/AccessControl.sol': undefined, + // 'access/Ownable.sol': undefined, + 'access/TimelockController.sol': 'governance/TimelockController.sol', + 'cryptography/ECDSA.sol': 'utils/cryptography/ECDSA.sol', + 'cryptography/MerkleProof.sol': 'utils/cryptography/MerkleProof.sol', + 'drafts/EIP712.sol': 'utils/cryptography/EIP712.sol', + 'drafts/ERC20Permit.sol': 'token/ERC20/extensions/ERC20Permit.sol', + 'drafts/IERC20Permit.sol': 'token/ERC20/extensions/IERC20Permit.sol', + 'GSN/Context.sol': 'utils/Context.sol', + // 'GSN/GSNRecipientERC20Fee.sol': undefined, + // 'GSN/GSNRecipientSignature.sol': undefined, + // 'GSN/GSNRecipient.sol': undefined, + // 'GSN/IRelayHub.sol': undefined, + // 'GSN/IRelayRecipient.sol': undefined, + 'introspection/ERC165Checker.sol': 'utils/introspection/ERC165Checker.sol', + 'introspection/ERC165.sol': 'utils/introspection/ERC165.sol', + 'introspection/ERC1820Implementer.sol': 'utils/introspection/ERC1820Implementer.sol', + 'introspection/IERC165.sol': 'utils/introspection/IERC165.sol', + 'introspection/IERC1820Implementer.sol': 'utils/introspection/IERC1820Implementer.sol', + 'introspection/IERC1820Registry.sol': 'utils/introspection/IERC1820Registry.sol', + 'math/Math.sol': 'utils/math/Math.sol', + 'math/SafeMath.sol': 'utils/math/SafeMath.sol', + 'math/SignedSafeMath.sol': 'utils/math/SignedSafeMath.sol', + 'payment/escrow/ConditionalEscrow.sol': 'utils/escrow/ConditionalEscrow.sol', + 'payment/escrow/Escrow.sol': 'utils/escrow/Escrow.sol', + 'payment/escrow/RefundEscrow.sol': 'utils/escrow/RefundEscrow.sol', + 'payment/PaymentSplitter.sol': 'finance/PaymentSplitter.sol', + 'utils/PaymentSplitter.sol': 'finance/PaymentSplitter.sol', + 'payment/PullPayment.sol': 'security/PullPayment.sol', + 'presets/ERC1155PresetMinterPauser.sol': 'token/ERC1155/presets/ERC1155PresetMinterPauser.sol', + 'presets/ERC20PresetFixedSupply.sol': 'token/ERC20/presets/ERC20PresetFixedSupply.sol', + 'presets/ERC20PresetMinterPauser.sol': 'token/ERC20/presets/ERC20PresetMinterPauser.sol', + 'presets/ERC721PresetMinterPauserAutoId.sol': 'token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol', + 'presets/ERC777PresetFixedSupply.sol': 'token/ERC777/presets/ERC777PresetFixedSupply.sol', + 'proxy/BeaconProxy.sol': 'proxy/beacon/BeaconProxy.sol', + // 'proxy/Clones.sol': undefined, + 'proxy/IBeacon.sol': 'proxy/beacon/IBeacon.sol', + 'proxy/Initializable.sol': 'proxy/utils/Initializable.sol', + 'utils/Initializable.sol': 'proxy/utils/Initializable.sol', + 'proxy/ProxyAdmin.sol': 'proxy/transparent/ProxyAdmin.sol', + // 'proxy/Proxy.sol': undefined, + 'proxy/TransparentUpgradeableProxy.sol': 'proxy/transparent/TransparentUpgradeableProxy.sol', + 'proxy/UpgradeableBeacon.sol': 'proxy/beacon/UpgradeableBeacon.sol', + 'proxy/UpgradeableProxy.sol': 'proxy/ERC1967/ERC1967Proxy.sol', + 'token/ERC1155/ERC1155Burnable.sol': 'token/ERC1155/extensions/ERC1155Burnable.sol', + 'token/ERC1155/ERC1155Holder.sol': 'token/ERC1155/utils/ERC1155Holder.sol', + 'token/ERC1155/ERC1155Pausable.sol': 'token/ERC1155/extensions/ERC1155Pausable.sol', + 'token/ERC1155/ERC1155Receiver.sol': 'token/ERC1155/utils/ERC1155Receiver.sol', + // 'token/ERC1155/ERC1155.sol': undefined, + 'token/ERC1155/IERC1155MetadataURI.sol': 'token/ERC1155/extensions/IERC1155MetadataURI.sol', + // 'token/ERC1155/IERC1155Receiver.sol': undefined, + // 'token/ERC1155/IERC1155.sol': undefined, + 'token/ERC20/ERC20Burnable.sol': 'token/ERC20/extensions/ERC20Burnable.sol', + 'token/ERC20/ERC20Capped.sol': 'token/ERC20/extensions/ERC20Capped.sol', + 'token/ERC20/ERC20Pausable.sol': 'token/ERC20/extensions/ERC20Pausable.sol', + 'token/ERC20/ERC20Snapshot.sol': 'token/ERC20/extensions/ERC20Snapshot.sol', + // 'token/ERC20/ERC20.sol': undefined, + // 'token/ERC20/IERC20.sol': undefined, + 'token/ERC20/SafeERC20.sol': 'token/ERC20/utils/SafeERC20.sol', + 'token/ERC20/TokenTimelock.sol': 'token/ERC20/utils/TokenTimelock.sol', + 'token/ERC721/ERC721Burnable.sol': 'token/ERC721/extensions/ERC721Burnable.sol', + 'token/ERC721/ERC721Holder.sol': 'token/ERC721/utils/ERC721Holder.sol', + 'token/ERC721/ERC721Pausable.sol': 'token/ERC721/extensions/ERC721Pausable.sol', + // 'token/ERC721/ERC721.sol': undefined, + 'token/ERC721/IERC721Enumerable.sol': 'token/ERC721/extensions/IERC721Enumerable.sol', + 'token/ERC721/IERC721Metadata.sol': 'token/ERC721/extensions/IERC721Metadata.sol', + // 'token/ERC721/IERC721Receiver.sol': undefined, + // 'token/ERC721/IERC721.sol': undefined, + // 'token/ERC777/ERC777.sol': undefined, + // 'token/ERC777/IERC777Recipient.sol': undefined, + // 'token/ERC777/IERC777Sender.sol': undefined, + // 'token/ERC777/IERC777.sol': undefined, + // 'utils/Address.sol': undefined, + // 'utils/Arrays.sol': undefined, + // 'utils/Context.sol': undefined, + // 'utils/Counters.sol': undefined, + // 'utils/Create2.sol': undefined, + 'utils/EnumerableMap.sol': 'utils/structs/EnumerableMap.sol', + 'utils/EnumerableSet.sol': 'utils/structs/EnumerableSet.sol', + 'utils/Pausable.sol': 'security/Pausable.sol', + 'utils/ReentrancyGuard.sol': 'security/ReentrancyGuard.sol', + 'utils/SafeCast.sol': 'utils/math/SafeCast.sol', + // 'utils/Strings.sol': undefined, + 'utils/cryptography/draft-EIP712.sol': 'utils/cryptography/EIP712.sol', + 'token/ERC20/extensions/draft-ERC20Permit.sol': 'token/ERC20/extensions/ERC20Permit.sol', + 'token/ERC20/extensions/draft-IERC20Permit.sol': 'token/ERC20/extensions/IERC20Permit.sol', +}; + +async function main(paths = ['contracts']) { + const files = await listFilesRecursively(paths, /\.sol$/); + + const updatedFiles = []; + for (const file of files) { + if (await updateFile(file, updateImportPaths)) { + updatedFiles.push(file); + } + } + + if (updatedFiles.length > 0) { + console.log(`${updatedFiles.length} file(s) were updated`); + for (const c of updatedFiles) { + console.log('-', c); + } + } else { + console.log('No files were updated'); + } +} + +async function listFilesRecursively(paths, filter) { + const queue = paths; + const files = []; + + while (queue.length > 0) { + const top = queue.shift(); + const stat = await fs.stat(top); + if (stat.isFile()) { + if (top.match(filter)) { + files.push(top); + } + } else if (stat.isDirectory()) { + for (const name of await fs.readdir(top)) { + queue.push(path.join(top, name)); + } + } + } + + return files; +} + +async function updateFile(file, update) { + const content = await fs.readFile(file, 'utf8'); + const updatedContent = update(content); + if (updatedContent !== content) { + await fs.writeFile(file, updatedContent); + return true; + } else { + return false; + } +} + +function updateImportPaths(source) { + for (const [oldPath, newPath] of Object.entries(pathUpdates)) { + source = source.replace( + path.join('@openzeppelin/contracts', oldPath), + path.join('@openzeppelin/contracts', newPath), + ); + source = source.replace( + path.join('@openzeppelin/contracts-upgradeable', getUpgradeablePath(oldPath)), + path.join('@openzeppelin/contracts-upgradeable', getUpgradeablePath(newPath)), + ); + } + + return source; +} + +function getUpgradeablePath(file) { + const { dir, name, ext } = path.parse(file); + const upgradeableName = name + 'Upgradeable'; + return path.format({ dir, ext, name: upgradeableName }); +} + +module.exports = { + pathUpdates, + updateImportPaths, + getUpgradeablePath, +}; + +if (require.main === module) { + const args = process.argv.length > 2 ? process.argv.slice(2) : undefined; + main(args).catch(e => { + console.error(e); + process.exit(1); + }); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/prepack.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/prepack.sh new file mode 100755 index 0000000..6f1bd4c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/prepack.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -euo pipefail +shopt -s globstar + +# cross platform `mkdir -p` +node -e 'fs.mkdirSync("build/contracts", { recursive: true })' + +cp artifacts/contracts/**/*.json build/contracts +rm build/contracts/*.dbg.json + +node scripts/remove-ignored-artifacts.js diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/prepare-contracts-package.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/prepare-contracts-package.sh new file mode 100755 index 0000000..3f62fd4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/prepare-contracts-package.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# cd to the root of the repo +cd "$(git rev-parse --show-toplevel)" + +# avoids re-compilation during publishing of both packages +if [[ ! -v ALREADY_COMPILED ]]; then + npm run clean + npm run prepare + npm run prepack +fi + +cp README.md contracts/ +mkdir contracts/build contracts/build/contracts +cp -r build/contracts/*.json contracts/build/contracts diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/prepare-docs.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/prepare-docs.sh new file mode 100755 index 0000000..4fc0c95 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/prepare-docs.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -euo pipefail + +OUTDIR="$(node -p 'require("./docs/config.js").outputDir')" + +if [ ! -d node_modules ]; then + npm ci +fi + +rm -rf "$OUTDIR" + +hardhat docgen + +node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc" diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/prepare.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/prepare.sh new file mode 100755 index 0000000..7014a70 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/prepare.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [ "${SKIP_COMPILE:-}" == true ]; then + exit +fi + +npm run clean +env COMPILE_MODE=production npm run compile diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/format-changelog.js b/lib/crytic/lib/openzeppelin-contracts/scripts/release/format-changelog.js new file mode 100755 index 0000000..b8bcc8c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/format-changelog.js @@ -0,0 +1,33 @@ +#!/usr/bin/env node + +// Adjusts the format of the changelog that changesets generates. +// This is run automatically when npm version is run. + +const fs = require('fs'); +const changelog = fs.readFileSync('CHANGELOG.md', 'utf8'); + +// Groups: +// - 1: Pull Request Number and URL +// - 2: Changeset entry +const RELEASE_LINE_REGEX = /^- (\[#.*?\]\(.*?\))?.*?! - (.*)$/gm; + +// Captures vX.Y.Z or vX.Y.Z-rc.W +const VERSION_TITLE_REGEX = /^## (\d+\.\d+\.\d+(-rc\.\d+)?)$/gm; + +const isPrerelease = process.env.PRERELEASE === 'true'; + +const formatted = changelog + // Remove titles + .replace(/^### Major Changes\n\n/gm, '') + .replace(/^### Minor Changes\n\n/gm, '') + .replace(/^### Patch Changes\n\n/gm, '') + // Remove extra whitespace between items + .replace(/^(- \[.*\n)\n(?=-)/gm, '$1') + // Format each release line + .replace(RELEASE_LINE_REGEX, (_, pr, entry) => (pr ? `- ${entry} (${pr})` : `- ${entry}`)) + // Add date to new version + .replace(VERSION_TITLE_REGEX, `\n## $1 (${new Date().toISOString().split('T')[0]})`) + // Conditionally allow vX.Y.Z.rc-.W sections only in prerelease + .replace(/^## \d\.\d\.\d-rc\S+[^]+?(?=^#)/gm, section => (isPrerelease ? section : '')); + +fs.writeFileSync('CHANGELOG.md', formatted); diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js b/lib/crytic/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js new file mode 100755 index 0000000..15aa259 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js @@ -0,0 +1,15 @@ +#!/usr/bin/env node + +// Synchronizes the version in contracts/package.json with the one in package.json. +// This is run automatically when npm version is run. + +const fs = require('fs'); + +setVersion('package.json', 'contracts/package.json'); + +function setVersion(from, to) { + const fromJson = JSON.parse(fs.readFileSync(from)); + const toJson = JSON.parse(fs.readFileSync(to)); + toJson.version = fromJson.version; + fs.writeFileSync(to, JSON.stringify(toJson, null, 2) + '\n'); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/update-comment.js b/lib/crytic/lib/openzeppelin-contracts/scripts/release/update-comment.js new file mode 100755 index 0000000..eb9f937 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/update-comment.js @@ -0,0 +1,34 @@ +#!/usr/bin/env node +const fs = require('fs'); +const proc = require('child_process'); +const semver = require('semver'); +const run = (cmd, ...args) => proc.execFileSync(cmd, args, { encoding: 'utf8' }).trim(); + +const gitStatus = run('git', 'status', '--porcelain', '-uno', 'contracts/**/*.sol'); +if (gitStatus.length > 0) { + console.error('Contracts directory is not clean'); + process.exit(1); +} + +const { version } = require('../../package.json'); + +// Get latest tag according to semver. +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 + .sort(semver.rcompare); + +// Ordering tag → HEAD is important here. +const files = run('git', 'diff', tag, 'HEAD', '--name-only', 'contracts/**/*.sol') + .split(/\r?\n/) + .filter(file => file && !file.match(/mock/i) && fs.existsSync(file)); + +for (const file of files) { + const current = fs.readFileSync(file, 'utf8'); + const updated = current.replace( + /(\/\/ SPDX-License-Identifier:.*)$(\n\/\/ OpenZeppelin Contracts .*$)?/m, + `$1\n// OpenZeppelin Contracts (last updated v${version}) (${file.replace('contracts/', '')})`, + ); + fs.writeFileSync(file, updated); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/version.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/release/version.sh new file mode 100755 index 0000000..7b0ddea --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/version.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euo pipefail + +changeset version + +scripts/release/format-changelog.js +scripts/release/synchronize-versions.js +scripts/release/update-comment.js + +oz-docs update-version diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh new file mode 100644 index 0000000..bcf9b9a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +npx changeset pre exit rc +git add . +git commit -m "Exit release candidate" +git push origin diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js new file mode 100644 index 0000000..92a47d9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js @@ -0,0 +1,47 @@ +const { readFileSync } = require('fs'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ github, context }) => { + const changelog = readFileSync('CHANGELOG.md', 'utf8'); + + await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `v${version}`, + body: extractSection(changelog, version), + prerelease: process.env.PRERELEASE === 'true', + }); +}; + +// From https://github.com/frangio/extract-changelog/blob/master/src/utils/word-regexp.ts +function makeWordRegExp(word) { + const start = word.length > 0 && /\b/.test(word[0]) ? '\\b' : ''; + const end = word.length > 0 && /\b/.test(word[word.length - 1]) ? '\\b' : ''; + return new RegExp(start + [...word].map(c => (/[a-z0-9]/i.test(c) ? c : '\\' + c)).join('') + end); +} + +// From https://github.com/frangio/extract-changelog/blob/master/src/core.ts +function extractSection(document, wantedHeading) { + // ATX Headings as defined in GitHub Flavored Markdown (https://github.github.com/gfm/#atx-headings) + const heading = /^ {0,3}(?#{1,6})(?: [ \t\v\f]*(?.*?)[ \t\v\f]*)?(?:[\n\r]+|$)/gm; + + const wantedHeadingRe = makeWordRegExp(wantedHeading); + + let start, end; + + for (const m of document.matchAll(heading)) { + if (!start) { + if (m.groups.text.search(wantedHeadingRe) === 0) { + start = m; + } + } else if (m.groups.lead.length <= start.groups.lead.length) { + end = m; + break; + } + } + + if (start) { + return document.slice(start.index + start[0].length, end?.index); + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh new file mode 100644 index 0000000..86e99f9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh new file mode 100644 index 0000000..ce30712 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +dist_tag() { + PACKAGE_JSON_NAME="$(jq -r .name ./package.json)" + LATEST_NPM_VERSION="$(npm info "$PACKAGE_JSON_NAME" version)" + PACKAGE_JSON_VERSION="$(jq -r .version ./package.json)" + + if [ "$PRERELEASE" = "true" ]; then + echo "next" + elif npx semver -r ">$LATEST_NPM_VERSION" "$PACKAGE_JSON_VERSION" > /dev/null; then + echo "latest" + else + # This is a patch for an older version + # npm can't publish without a tag + echo "tmp" + fi +} + +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/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/prepare-release-merge.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/prepare-release-merge.sh new file mode 100644 index 0000000..8be9692 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/prepare-release-merge.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Define merge branch name +MERGE_BRANCH=merge/$GITHUB_REF_NAME + +# Create the branch and force to start from ref +git checkout -B "$MERGE_BRANCH" "$GITHUB_REF_NAME" + +# Get deleted changesets in this branch that might conflict with master +readarray -t DELETED_CHANGESETS < <(git diff origin/master --name-only -- '.changeset/*.md') + +# Merge master, which will take those files cherry-picked. Auto-resolve conflicts favoring master. +git merge origin/master -m "Merge master to $GITHUB_REF_NAME" -X theirs + +# Remove the originally deleted changesets to correctly sync with master +rm -f "${DELETED_CHANGESETS[@]}" + +git add .changeset/ + +# Allow empty here since there may be no changes if `rm -f` failed for all changesets +git commit --allow-empty -m "Sync changesets with master" +git push -f origin "$MERGE_BRANCH" diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh new file mode 100644 index 0000000..41a9975 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Intentionally escape $ to avoid interpolation and writing the token to disk +echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > .npmrc + +# Actual publish +npm publish "$TARBALL" --tag "$TAG" + +delete_tag() { + PACKAGE_JSON_NAME="$(tar xfO "$TARBALL" package/package.json | jq -r .name)" + npm dist-tag rm "$PACKAGE_JSON_NAME" "$1" +} + +if [ "$TAG" = tmp ]; then + delete_tag "$TAG" +elif [ "$TAG" = latest ]; then + delete_tag next +fi diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js new file mode 100644 index 0000000..f48ce6e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js @@ -0,0 +1,7 @@ +module.exports = ({ github, context }) => + github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release-cycle.yml', + ref: process.env.REF || process.env.GITHUB_REF_NAME, + }); diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js new file mode 100644 index 0000000..59b03b2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js @@ -0,0 +1,17 @@ +const { coerce, inc, rsort } = require('semver'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ core }) => { + // Variables not in the context + const refName = process.env.GITHUB_REF_NAME; + + // Compare package.json version's next patch vs. first version patch + // A recently opened branch will give the next patch for the previous minor + // So, we get the max against the patch 0 of the release branch's version + const branchPatch0 = coerce(refName.replace('release-v', '')).version; + const packageJsonNextPatch = inc(version, 'patch'); + const [nextVersion] = rsort([branchPatch0, packageJsonNextPatch], false); + + core.exportVariable('TITLE', `Release v${nextVersion}`); +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/start.sh b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/start.sh new file mode 100644 index 0000000..7683ec5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/start.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Set changeset status location +# This is needed because `changeset status --output` only works with relative routes +CHANGESETS_STATUS_JSON="$(realpath --relative-to=. "$RUNNER_TEMP/status.json")" + +# Save changeset status to temp file +npx changeset status --output="$CHANGESETS_STATUS_JSON" + +# Defensive assertion. SHOULD NOT BE REACHED +if [ "$(jq '.releases | length' "$CHANGESETS_STATUS_JSON")" != 1 ]; then + echo "::error file=$CHANGESETS_STATUS_JSON::The status doesn't contain only 1 release" + exit 1; +fi; + +# Create branch +BRANCH_SUFFIX="$(jq -r '.releases[0].newVersion | gsub("\\.\\d+$"; "")' $CHANGESETS_STATUS_JSON)" +RELEASE_BRANCH="release-v$BRANCH_SUFFIX" +git checkout -b "$RELEASE_BRANCH" + +# Output branch +echo "branch=$RELEASE_BRANCH" >> $GITHUB_OUTPUT + +# Enter in prerelease state +npx changeset pre enter rc +git add . +git commit -m "Start release candidate" + +# Push 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 diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/state.js b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/state.js new file mode 100644 index 0000000..4d905e2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/release/workflow/state.js @@ -0,0 +1,104 @@ +const { readPreState } = require('@changesets/pre'); +const { default: readChangesets } = require('@changesets/read'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ github, context, core }) => { + const state = await getState({ github, context, core }); + + function setOutput(key, value) { + core.info(`State ${key} = ${value}`); + core.setOutput(key, value); + } + + // Jobs to trigger + setOutput('start', shouldRunStart(state)); + setOutput('promote', shouldRunPromote(state)); + setOutput('changesets', shouldRunChangesets(state)); + setOutput('publish', shouldRunPublish(state)); + setOutput('merge', shouldRunMerge(state)); + + // Global Variables + setOutput('is_prerelease', state.prerelease); +}; + +function shouldRunStart({ isMaster, isWorkflowDispatch, botRun }) { + return isMaster && isWorkflowDispatch && !botRun; +} + +function shouldRunPromote({ isReleaseBranch, isWorkflowDispatch, botRun }) { + return isReleaseBranch && isWorkflowDispatch && !botRun; +} + +function shouldRunChangesets({ isReleaseBranch, isPush, isWorkflowDispatch, botRun }) { + return (isReleaseBranch && isPush) || (isReleaseBranch && isWorkflowDispatch && botRun); +} + +function shouldRunPublish({ isReleaseBranch, isPush, hasPendingChangesets }) { + return isReleaseBranch && isPush && !hasPendingChangesets; +} + +function shouldRunMerge({ + isReleaseBranch, + isPush, + prerelease, + isCurrentFinalVersion, + hasPendingChangesets, + prBackExists, +}) { + return isReleaseBranch && isPush && !prerelease && isCurrentFinalVersion && !hasPendingChangesets && prBackExists; +} + +async function getState({ github, context, core }) { + // Variables not in the context + const refName = process.env.GITHUB_REF_NAME; + const botRun = process.env.TRIGGERING_ACTOR === 'github-actions[bot]'; + + const { changesets, preState } = await readChangesetState(); + + // Static vars + const state = { + refName, + hasPendingChangesets: changesets.length > 0, + prerelease: preState?.mode === 'pre', + isMaster: refName === 'master', + isReleaseBranch: refName.startsWith('release-v'), + isWorkflowDispatch: context.eventName === 'workflow_dispatch', + isPush: context.eventName === 'push', + isCurrentFinalVersion: !version.includes('-rc.'), + botRun, + }; + + // Async vars + const { data: prs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: `${context.repo.owner}:merge/${state.refName}`, + base: 'master', + state: 'open', + }); + + state.prBackExists = prs.length === 0; + + // Log every state value in debug mode + if (core.isDebug()) for (const [key, value] of Object.entries(state)) core.debug(`${key}: ${value}`); + + return state; +} + +// From https://github.com/changesets/action/blob/v1.4.1/src/readChangesetState.ts +async function readChangesetState(cwd = process.cwd()) { + const preState = await readPreState(cwd); + const isInPreMode = preState !== undefined && preState.mode === 'pre'; + + let changesets = await readChangesets(cwd); + + if (isInPreMode) { + changesets = changesets.filter(x => !preState.changesets.includes(x.id)); + } + + return { + preState: isInPreMode ? preState : undefined, + changesets, + }; +} diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js b/lib/crytic/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js new file mode 100644 index 0000000..f3e45b8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node + +// This script removes the build artifacts of ignored contracts. + +const fs = require('fs'); +const path = require('path'); +const match = require('micromatch'); + +function readJSON(path) { + return JSON.parse(fs.readFileSync(path)); +} + +const pkgFiles = readJSON('package.json').files; + +// Get only negated patterns. +const ignorePatterns = pkgFiles + .filter(pat => pat.startsWith('!')) + // Remove the negation part. Makes micromatch usage more intuitive. + .map(pat => pat.slice(1)); + +const ignorePatternsSubtrees = ignorePatterns + // Add **/* to ignore all files contained in the directories. + .concat(ignorePatterns.map(pat => path.join(pat, '**/*'))) + .map(p => p.replace(/^\//, '')); + +const artifactsDir = 'build/contracts'; +const buildinfo = 'artifacts/build-info'; +const filenames = fs.readdirSync(buildinfo); + +let n = 0; + +for (const filename of filenames) { + const solcOutput = readJSON(path.join(buildinfo, filename)).output; + for (const sourcePath in solcOutput.contracts) { + const ignore = match.any(sourcePath, ignorePatternsSubtrees); + if (ignore) { + for (const contract in solcOutput.contracts[sourcePath]) { + fs.unlinkSync(path.join(artifactsDir, contract + '.json')); + n += 1; + } + } + } +} + +console.error(`Removed ${n} mock artifacts`); diff --git a/lib/crytic/lib/openzeppelin-contracts/scripts/update-docs-branch.js b/lib/crytic/lib/openzeppelin-contracts/scripts/update-docs-branch.js new file mode 100644 index 0000000..4e94ba6 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/scripts/update-docs-branch.js @@ -0,0 +1,63 @@ +const proc = require('child_process'); +const read = cmd => proc.execSync(cmd, { encoding: 'utf8' }).trim(); +const run = cmd => { + proc.execSync(cmd, { stdio: 'inherit' }); +}; +const tryRead = cmd => { + try { + return read(cmd); + } catch (e) { + return undefined; + } +}; + +const releaseBranchRegex = /^release-v(?(?\d+)\.(?\d+)(?:\.(?\d+))?)$/; + +const currentBranch = read('git rev-parse --abbrev-ref HEAD'); +const match = currentBranch.match(releaseBranchRegex); + +if (!match) { + console.error('Not currently on a release branch'); + process.exit(1); +} + +if (/-.*$/.test(require('../package.json').version)) { + console.error('Refusing to update docs: prerelease detected'); + process.exit(0); +} + +const current = match.groups; +const docsBranch = `docs-v${current.major}.x`; + +// Fetch remotes and find the docs branch if it exists +run('git fetch --all --no-tags'); +const matchingDocsBranches = tryRead(`git rev-parse --glob='*/${docsBranch}'`); + +if (!matchingDocsBranches) { + // Create the branch + run(`git checkout --orphan ${docsBranch}`); +} else { + const [publishedRef, ...others] = new Set(matchingDocsBranches.split('\n')); + if (others.length > 0) { + console.error( + `Found conflicting ${docsBranch} branches.\n` + + 'Either local branch is outdated or there are multiple matching remote branches.', + ); + process.exit(1); + } + const publishedVersion = JSON.parse(read(`git show ${publishedRef}:package.json`)).version; + const publishedMinor = publishedVersion.match(/\d+\.(?\d+)\.\d+/).groups.minor; + if (current.minor < publishedMinor) { + console.error('Refusing to update docs: newer version is published'); + process.exit(0); + } + + run('git checkout --quiet --detach'); + run(`git reset --soft ${publishedRef}`); + run(`git checkout ${docsBranch}`); +} + +run('npm run prepare-docs'); +run('git add -f docs'); // --force needed because generated docs files are gitignored +run('git commit -m "Update docs"'); +run(`git checkout ${currentBranch}`); diff --git a/lib/crytic/lib/openzeppelin-contracts/slither.config.json b/lib/crytic/lib/openzeppelin-contracts/slither.config.json new file mode 100644 index 0000000..2b61879 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/slither.config.json @@ -0,0 +1,5 @@ +{ + "detectors_to_run": "reentrancy-eth,reentrancy-no-eth,reentrancy-unlimited-gas", + "filter_paths": "contracts/mocks", + "compile_force_framework": "hardhat" +} \ No newline at end of file diff --git a/lib/crytic/lib/openzeppelin-contracts/test/TESTING.md b/lib/crytic/lib/openzeppelin-contracts/test/TESTING.md new file mode 100644 index 0000000..a5ee932 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/TESTING.md @@ -0,0 +1,3 @@ +## Testing + +Unit test are critical to OpenZeppelin Contracts. They help ensure code quality and mitigate against security vulnerabilities. The directory structure within the `/test` directory corresponds to the `/contracts` directory. diff --git a/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js new file mode 100644 index 0000000..a935609 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js @@ -0,0 +1,217 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); + +const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; +const ROLE = web3.utils.soliditySha3('ROLE'); +const OTHER_ROLE = web3.utils.soliditySha3('OTHER_ROLE'); + +function shouldBehaveLikeAccessControl(errorPrefix, admin, authorized, other, otherAdmin) { + shouldSupportInterfaces(['AccessControl']); + + describe('default admin', function () { + it('deployer has default admin role', async function () { + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin)).to.equal(true); + }); + + it("other roles's admin is the default admin role", async function () { + expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + it("default admin role's admin is itself", async function () { + expect(await this.accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + }); + + describe('granting', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('non-admin cannot grant role to other accounts', async function () { + await expectRevert( + this.accessControl.grantRole(ROLE, authorized, { from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, + ); + }); + + it('accounts can be granted a role multiple times', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleGranted'); + }); + }); + + describe('revoking', function () { + it('roles that are not had can be revoked', async function () { + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + + context('with granted role', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('admin can revoke role', async function () { + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: admin }); + + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + }); + + it('non-admin cannot revoke role', async function () { + await expectRevert( + this.accessControl.revokeRole(ROLE, authorized, { from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, + ); + }); + + it('a role can be revoked multiple times', async function () { + await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + }); + }); + + describe('renouncing', function () { + it('roles that are not had can be renounced', async function () { + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + + context('with granted role', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('bearer can renounce role', async function () { + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: authorized }); + + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + }); + + it('only the sender can renounce their roles', async function () { + await expectRevert( + this.accessControl.renounceRole(ROLE, authorized, { from: admin }), + `${errorPrefix}: can only renounce roles for self`, + ); + }); + + it('a role can be renounced multiple times', async function () { + await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + }); + }); + + describe('setting role admin', function () { + beforeEach(async function () { + const receipt = await this.accessControl.$_setRoleAdmin(ROLE, OTHER_ROLE); + expectEvent(receipt, 'RoleAdminChanged', { + role: ROLE, + previousAdminRole: DEFAULT_ADMIN_ROLE, + newAdminRole: OTHER_ROLE, + }); + + await this.accessControl.grantRole(OTHER_ROLE, otherAdmin, { from: admin }); + }); + + it("a role's admin role can be changed", async function () { + expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(OTHER_ROLE); + }); + + it('the new admin can grant roles', async function () { + const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin }); + expectEvent(receipt, 'RoleGranted', { account: authorized, role: ROLE, sender: otherAdmin }); + }); + + it('the new admin can revoke roles', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin }); + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: otherAdmin }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: otherAdmin }); + }); + + it("a role's previous admins no longer grant roles", async function () { + await expectRevert( + this.accessControl.grantRole(ROLE, authorized, { from: admin }), + `${errorPrefix}: account ${admin.toLowerCase()} is missing role ${OTHER_ROLE}`, + ); + }); + + it("a role's previous admins no longer revoke roles", async function () { + await expectRevert( + this.accessControl.revokeRole(ROLE, authorized, { from: admin }), + `${errorPrefix}: account ${admin.toLowerCase()} is missing role ${OTHER_ROLE}`, + ); + }); + }); + + describe('onlyRole modifier', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('do not revert if sender has role', async function () { + await this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: authorized }); + }); + + it("revert if sender doesn't have role #1", async function () { + await expectRevert( + this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${ROLE}`, + ); + }); + + it("revert if sender doesn't have role #2", async function () { + await expectRevert( + this.accessControl.methods['$_checkRole(bytes32)'](OTHER_ROLE, { from: authorized }), + `${errorPrefix}: account ${authorized.toLowerCase()} is missing role ${OTHER_ROLE}`, + ); + }); + }); +} + +function shouldBehaveLikeAccessControlEnumerable(errorPrefix, admin, authorized, other, otherAdmin, otherAuthorized) { + shouldSupportInterfaces(['AccessControlEnumerable']); + + describe('enumerating', function () { + it('role bearers can be enumerated', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + await this.accessControl.grantRole(ROLE, other, { from: admin }); + await this.accessControl.grantRole(ROLE, otherAuthorized, { from: admin }); + await this.accessControl.revokeRole(ROLE, other, { from: admin }); + + const memberCount = await this.accessControl.getRoleMemberCount(ROLE); + expect(memberCount).to.bignumber.equal('2'); + + const bearers = []; + for (let i = 0; i < memberCount; ++i) { + bearers.push(await this.accessControl.getRoleMember(ROLE, i)); + } + + expect(bearers).to.have.members([authorized, otherAuthorized]); + }); + it('role enumeration should be in sync after renounceRole call', async function () { + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('0'); + await this.accessControl.grantRole(ROLE, admin, { from: admin }); + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('1'); + await this.accessControl.renounceRole(ROLE, admin, { from: admin }); + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('0'); + }); + }); +} + +module.exports = { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControl.test.js b/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControl.test.js new file mode 100644 index 0000000..90efad3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControl.test.js @@ -0,0 +1,12 @@ +const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js'); + +const AccessControl = artifacts.require('$AccessControl'); + +contract('AccessControl', function (accounts) { + beforeEach(async function () { + this.accessControl = await AccessControl.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl('AccessControl', ...accounts); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControlCrossChain.test.js b/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControlCrossChain.test.js new file mode 100644 index 0000000..d5a4107 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControlCrossChain.test.js @@ -0,0 +1,49 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { BridgeHelper } = require('../helpers/crosschain'); + +const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js'); + +const crossChainRoleAlias = role => + web3.utils.leftPad( + web3.utils.toHex(web3.utils.toBN(role).xor(web3.utils.toBN(web3.utils.soliditySha3('CROSSCHAIN_ALIAS')))), + 64, + ); + +const AccessControlCrossChainMock = artifacts.require('$AccessControlCrossChainMock'); + +const ROLE = web3.utils.soliditySha3('ROLE'); + +contract('AccessControl', function (accounts) { + before(async function () { + this.bridge = await BridgeHelper.deploy(); + }); + + beforeEach(async function () { + this.accessControl = await AccessControlCrossChainMock.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl('AccessControl', ...accounts); + + describe('CrossChain enabled', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, accounts[0], { from: accounts[0] }); + await this.accessControl.grantRole(crossChainRoleAlias(ROLE), accounts[1], { from: accounts[0] }); + }); + + it('check alliassing', async function () { + expect(await this.accessControl.$_crossChainRoleAlias(ROLE)).to.be.bignumber.equal(crossChainRoleAlias(ROLE)); + }); + + it('Crosschain calls not authorized to non-aliased addresses', async function () { + await expectRevert( + this.bridge.call(accounts[0], this.accessControl, '$_checkRole(bytes32)', [ROLE]), + `AccessControl: account ${accounts[0].toLowerCase()} is missing role ${crossChainRoleAlias(ROLE)}`, + ); + }); + + it('Crosschain calls not authorized to non-aliased addresses', async function () { + await this.bridge.call(accounts[1], this.accessControl, '$_checkRole(bytes32)', [ROLE]); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControlEnumerable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControlEnumerable.test.js new file mode 100644 index 0000000..2aa59f4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/access/AccessControlEnumerable.test.js @@ -0,0 +1,17 @@ +const { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, +} = require('./AccessControl.behavior.js'); + +const AccessControlEnumerable = artifacts.require('$AccessControlEnumerable'); + +contract('AccessControl', function (accounts) { + beforeEach(async function () { + this.accessControl = await AccessControlEnumerable.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl('AccessControl', ...accounts); + shouldBehaveLikeAccessControlEnumerable('AccessControl', ...accounts); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/access/Ownable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/access/Ownable.test.js new file mode 100644 index 0000000..dc308f9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/access/Ownable.test.js @@ -0,0 +1,51 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const Ownable = artifacts.require('$Ownable'); + +contract('Ownable', function (accounts) { + const [owner, other] = accounts; + + beforeEach(async function () { + this.ownable = await Ownable.new({ from: owner }); + }); + + it('has an owner', async function () { + expect(await this.ownable.owner()).to.equal(owner); + }); + + describe('transfer ownership', function () { + it('changes owner after transfer', async function () { + const receipt = await this.ownable.transferOwnership(other, { from: owner }); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(other); + }); + + it('prevents non-owners from transferring', async function () { + await expectRevert(this.ownable.transferOwnership(other, { from: other }), 'Ownable: caller is not the owner'); + }); + + it('guards ownership against stuck state', async function () { + await expectRevert( + this.ownable.transferOwnership(ZERO_ADDRESS, { from: owner }), + 'Ownable: new owner is the zero address', + ); + }); + }); + + describe('renounce ownership', function () { + it('loses owner after renouncement', async function () { + const receipt = await this.ownable.renounceOwnership({ from: owner }); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(ZERO_ADDRESS); + }); + + it('prevents non-owners from renouncement', async function () { + await expectRevert(this.ownable.renounceOwnership({ from: other }), 'Ownable: caller is not the owner'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js b/lib/crytic/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js new file mode 100644 index 0000000..64d4327 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js @@ -0,0 +1,57 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { expect } = require('chai'); + +const Ownable2Step = artifacts.require('$Ownable2Step'); + +contract('Ownable2Step', function (accounts) { + const [owner, accountA, accountB] = accounts; + + beforeEach(async function () { + this.ownable2Step = await Ownable2Step.new({ from: owner }); + }); + + describe('transfer ownership', function () { + it('starting a transfer does not change owner', async function () { + const receipt = await this.ownable2Step.transferOwnership(accountA, { from: owner }); + expectEvent(receipt, 'OwnershipTransferStarted', { previousOwner: owner, newOwner: accountA }); + expect(await this.ownable2Step.owner()).to.equal(owner); + expect(await this.ownable2Step.pendingOwner()).to.equal(accountA); + }); + + it('changes owner after transfer', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + const receipt = await this.ownable2Step.acceptOwnership({ from: accountA }); + expectEvent(receipt, 'OwnershipTransferred', { previousOwner: owner, newOwner: accountA }); + expect(await this.ownable2Step.owner()).to.equal(accountA); + expect(await this.ownable2Step.pendingOwner()).to.not.equal(accountA); + }); + + it('changes owner after renouncing ownership', async function () { + await this.ownable2Step.renounceOwnership({ from: owner }); + // If renounceOwnership is removed from parent an alternative is needed ... + // without it is difficult to cleanly renounce with the two step process + // see: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620#discussion_r957930388 + expect(await this.ownable2Step.owner()).to.equal(ZERO_ADDRESS); + }); + + it('pending owner resets after renouncing ownership', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + expect(await this.ownable2Step.pendingOwner()).to.equal(accountA); + await this.ownable2Step.renounceOwnership({ from: owner }); + expect(await this.ownable2Step.pendingOwner()).to.equal(ZERO_ADDRESS); + await expectRevert( + this.ownable2Step.acceptOwnership({ from: accountA }), + 'Ownable2Step: caller is not the new owner', + ); + }); + + 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', + ); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/crosschain/CrossChainEnabled.test.js b/lib/crytic/lib/openzeppelin-contracts/test/crosschain/CrossChainEnabled.test.js new file mode 100644 index 0000000..9e7d263 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/crosschain/CrossChainEnabled.test.js @@ -0,0 +1,78 @@ +const { BridgeHelper } = require('../helpers/crosschain'); +const { expectRevertCustomError } = require('../helpers/customError'); + +function randomAddress() { + return web3.utils.toChecksumAddress(web3.utils.randomHex(20)); +} + +const CrossChainEnabledAMBMock = artifacts.require('CrossChainEnabledAMBMock'); +const CrossChainEnabledArbitrumL1Mock = artifacts.require('CrossChainEnabledArbitrumL1Mock'); +const CrossChainEnabledArbitrumL2Mock = artifacts.require('CrossChainEnabledArbitrumL2Mock'); +const CrossChainEnabledOptimismMock = artifacts.require('CrossChainEnabledOptimismMock'); +const CrossChainEnabledPolygonChildMock = artifacts.require('CrossChainEnabledPolygonChildMock'); + +function shouldBehaveLikeReceiver(sender = randomAddress()) { + it('should reject same-chain calls', async function () { + await expectRevertCustomError(this.receiver.crossChainRestricted(), 'NotCrossChainCall()'); + + await expectRevertCustomError(this.receiver.crossChainOwnerRestricted(), 'NotCrossChainCall()'); + }); + + it('should restrict to cross-chain call from a invalid sender', async function () { + await expectRevertCustomError( + this.bridge.call(sender, this.receiver, 'crossChainOwnerRestricted()'), + `InvalidCrossChainSender("${sender}", "${await this.receiver.owner()}")`, + ); + }); + + it('should grant access to cross-chain call from the owner', async function () { + await this.bridge.call(await this.receiver.owner(), this.receiver, 'crossChainOwnerRestricted()'); + }); +} + +contract('CrossChainEnabled', function () { + describe('AMB', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('AMB'); + this.receiver = await CrossChainEnabledAMBMock.new(this.bridge.address); + }); + + shouldBehaveLikeReceiver(); + }); + + describe('Arbitrum-L1', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('Arbitrum-L1'); + this.receiver = await CrossChainEnabledArbitrumL1Mock.new(this.bridge.address); + }); + + shouldBehaveLikeReceiver(); + }); + + describe('Arbitrum-L2', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('Arbitrum-L2'); + this.receiver = await CrossChainEnabledArbitrumL2Mock.new(); + }); + + shouldBehaveLikeReceiver(); + }); + + describe('Optimism', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('Optimism'); + this.receiver = await CrossChainEnabledOptimismMock.new(this.bridge.address); + }); + + shouldBehaveLikeReceiver(); + }); + + describe('Polygon-Child', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('Polygon-Child'); + this.receiver = await CrossChainEnabledPolygonChildMock.new(this.bridge.address); + }); + + shouldBehaveLikeReceiver(); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/finance/PaymentSplitter.test.js b/lib/crytic/lib/openzeppelin-contracts/test/finance/PaymentSplitter.test.js new file mode 100644 index 0000000..1408c9f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/finance/PaymentSplitter.test.js @@ -0,0 +1,217 @@ +const { balance, constants, ether, expectEvent, send, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const PaymentSplitter = artifacts.require('PaymentSplitter'); +const ERC20 = artifacts.require('$ERC20'); + +contract('PaymentSplitter', function (accounts) { + const [owner, payee1, payee2, payee3, nonpayee1, payer1] = accounts; + + const amount = ether('1'); + + it('rejects an empty set of payees', async function () { + await expectRevert(PaymentSplitter.new([], []), 'PaymentSplitter: no payees'); + }); + + it('rejects more payees than shares', async function () { + await expectRevert( + PaymentSplitter.new([payee1, payee2, payee3], [20, 30]), + 'PaymentSplitter: payees and shares length mismatch', + ); + }); + + it('rejects more shares than payees', async function () { + await expectRevert( + PaymentSplitter.new([payee1, payee2], [20, 30, 40]), + 'PaymentSplitter: payees and shares length mismatch', + ); + }); + + it('rejects null payees', async function () { + await expectRevert( + PaymentSplitter.new([payee1, ZERO_ADDRESS], [20, 30]), + 'PaymentSplitter: account is the zero address', + ); + }); + + it('rejects zero-valued shares', async function () { + await expectRevert(PaymentSplitter.new([payee1, payee2], [20, 0]), 'PaymentSplitter: shares are 0'); + }); + + it('rejects repeated payees', async function () { + await expectRevert(PaymentSplitter.new([payee1, payee1], [20, 30]), 'PaymentSplitter: account already has shares'); + }); + + context('once deployed', function () { + beforeEach(async function () { + this.payees = [payee1, payee2, payee3]; + this.shares = [20, 10, 70]; + + this.contract = await PaymentSplitter.new(this.payees, this.shares); + this.token = await ERC20.new('MyToken', 'MT'); + await this.token.$_mint(owner, ether('1000')); + }); + + it('has total shares', async function () { + expect(await this.contract.totalShares()).to.be.bignumber.equal('100'); + }); + + it('has payees', async function () { + await Promise.all( + this.payees.map(async (payee, index) => { + expect(await this.contract.payee(index)).to.equal(payee); + expect(await this.contract.released(payee)).to.be.bignumber.equal('0'); + expect(await this.contract.releasable(payee)).to.be.bignumber.equal('0'); + }), + ); + }); + + describe('accepts payments', function () { + it('Ether', async function () { + await send.ether(owner, this.contract.address, amount); + + expect(await balance.current(this.contract.address)).to.be.bignumber.equal(amount); + }); + + it('Token', async function () { + await this.token.transfer(this.contract.address, amount, { from: owner }); + + expect(await this.token.balanceOf(this.contract.address)).to.be.bignumber.equal(amount); + }); + }); + + describe('shares', function () { + it('stores shares if address is payee', async function () { + expect(await this.contract.shares(payee1)).to.be.bignumber.not.equal('0'); + }); + + it('does not store shares if address is not payee', async function () { + expect(await this.contract.shares(nonpayee1)).to.be.bignumber.equal('0'); + }); + }); + + describe('release', function () { + describe('Ether', function () { + it('reverts if no funds to claim', async function () { + await expectRevert(this.contract.release(payee1), 'PaymentSplitter: account is not due payment'); + }); + it('reverts if non-payee want to claim', async function () { + await send.ether(payer1, this.contract.address, amount); + await expectRevert(this.contract.release(nonpayee1), 'PaymentSplitter: account has no shares'); + }); + }); + + describe('Token', function () { + it('reverts if no funds to claim', async function () { + await expectRevert( + this.contract.release(this.token.address, payee1), + 'PaymentSplitter: account is not due payment', + ); + }); + it('reverts if non-payee want to claim', async function () { + await this.token.transfer(this.contract.address, amount, { from: owner }); + await expectRevert( + this.contract.release(this.token.address, nonpayee1), + 'PaymentSplitter: account has no shares', + ); + }); + }); + }); + + describe('tracks releasable and released', function () { + it('Ether', async function () { + await send.ether(payer1, this.contract.address, amount); + const payment = amount.divn(10); + expect(await this.contract.releasable(payee2)).to.be.bignumber.equal(payment); + await this.contract.release(payee2); + expect(await this.contract.releasable(payee2)).to.be.bignumber.equal('0'); + expect(await this.contract.released(payee2)).to.be.bignumber.equal(payment); + }); + + it('Token', async function () { + await this.token.transfer(this.contract.address, amount, { from: owner }); + const payment = amount.divn(10); + expect(await this.contract.releasable(this.token.address, payee2, {})).to.be.bignumber.equal(payment); + await this.contract.release(this.token.address, payee2); + expect(await this.contract.releasable(this.token.address, payee2, {})).to.be.bignumber.equal('0'); + expect(await this.contract.released(this.token.address, payee2)).to.be.bignumber.equal(payment); + }); + }); + + describe('distributes funds to payees', function () { + it('Ether', async function () { + await send.ether(payer1, this.contract.address, amount); + + // receive funds + const initBalance = await balance.current(this.contract.address); + expect(initBalance).to.be.bignumber.equal(amount); + + // distribute to payees + + const tracker1 = await balance.tracker(payee1); + const receipt1 = await this.contract.release(payee1); + const profit1 = await tracker1.delta(); + expect(profit1).to.be.bignumber.equal(ether('0.20')); + expectEvent(receipt1, 'PaymentReleased', { to: payee1, amount: profit1 }); + + const tracker2 = await balance.tracker(payee2); + const receipt2 = await this.contract.release(payee2); + const profit2 = await tracker2.delta(); + expect(profit2).to.be.bignumber.equal(ether('0.10')); + expectEvent(receipt2, 'PaymentReleased', { to: payee2, amount: profit2 }); + + const tracker3 = await balance.tracker(payee3); + const receipt3 = await this.contract.release(payee3); + const profit3 = await tracker3.delta(); + expect(profit3).to.be.bignumber.equal(ether('0.70')); + expectEvent(receipt3, 'PaymentReleased', { to: payee3, amount: profit3 }); + + // end balance should be zero + expect(await balance.current(this.contract.address)).to.be.bignumber.equal('0'); + + // check correct funds released accounting + expect(await this.contract.totalReleased()).to.be.bignumber.equal(initBalance); + }); + + it('Token', async function () { + expect(await this.token.balanceOf(payee1)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(payee2)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(payee3)).to.be.bignumber.equal('0'); + + await this.token.transfer(this.contract.address, amount, { from: owner }); + + expectEvent(await this.contract.release(this.token.address, payee1), 'ERC20PaymentReleased', { + token: this.token.address, + to: payee1, + amount: ether('0.20'), + }); + + await this.token.transfer(this.contract.address, amount, { from: owner }); + + expectEvent(await this.contract.release(this.token.address, payee1), 'ERC20PaymentReleased', { + token: this.token.address, + to: payee1, + amount: ether('0.20'), + }); + + expectEvent(await this.contract.release(this.token.address, payee2), 'ERC20PaymentReleased', { + token: this.token.address, + to: payee2, + amount: ether('0.20'), + }); + + expectEvent(await this.contract.release(this.token.address, payee3), 'ERC20PaymentReleased', { + token: this.token.address, + to: payee3, + amount: ether('1.40'), + }); + + expect(await this.token.balanceOf(payee1)).to.be.bignumber.equal(ether('0.40')); + expect(await this.token.balanceOf(payee2)).to.be.bignumber.equal(ether('0.20')); + expect(await this.token.balanceOf(payee3)).to.be.bignumber.equal(ether('1.40')); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js new file mode 100644 index 0000000..afd4c04 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js @@ -0,0 +1,59 @@ +const { time } = require('@nomicfoundation/hardhat-network-helpers'); +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +function releasedEvent(token, amount) { + return token ? ['ERC20Released', { token: token.address, amount }] : ['EtherReleased', { amount }]; +} + +function shouldBehaveLikeVesting(beneficiary) { + it('check vesting schedule', async function () { + const [vestedAmount, releasable, ...args] = this.token + ? ['vestedAmount(address,uint64)', 'releasable(address)', this.token.address] + : ['vestedAmount(uint64)', 'releasable()']; + + for (const timestamp of this.schedule) { + await time.increaseTo(timestamp); + const vesting = this.vestingFn(timestamp); + + expect(await this.mock.methods[vestedAmount](...args, timestamp)).to.be.bignumber.equal(vesting); + + expect(await this.mock.methods[releasable](...args)).to.be.bignumber.equal(vesting); + } + }); + + it('execute vesting schedule', async function () { + const [release, ...args] = this.token ? ['release(address)', this.token.address] : ['release()']; + + let released = web3.utils.toBN(0); + const before = await this.getBalance(beneficiary); + + { + const receipt = await this.mock.methods[release](...args); + + await expectEvent.inTransaction(receipt.tx, this.mock, ...releasedEvent(this.token, '0')); + + await this.checkRelease(receipt, beneficiary, '0'); + + expect(await this.getBalance(beneficiary)).to.be.bignumber.equal(before); + } + + for (const timestamp of this.schedule) { + await time.setNextBlockTimestamp(timestamp); + const vested = this.vestingFn(timestamp); + + const receipt = await this.mock.methods[release](...args); + await expectEvent.inTransaction(receipt.tx, this.mock, ...releasedEvent(this.token, vested.sub(released))); + + await this.checkRelease(receipt, beneficiary, vested.sub(released)); + + expect(await this.getBalance(beneficiary)).to.be.bignumber.equal(before.add(vested)); + + released = vested; + } + }); +} + +module.exports = { + shouldBehaveLikeVesting, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js b/lib/crytic/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js new file mode 100644 index 0000000..5b90a69 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js @@ -0,0 +1,67 @@ +const { constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { web3 } = require('@openzeppelin/test-helpers/src/setup'); +const { expect } = require('chai'); + +const VestingWallet = artifacts.require('VestingWallet'); +const ERC20 = artifacts.require('$ERC20'); + +const { shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); + +const min = (...args) => args.slice(1).reduce((x, y) => (x.lt(y) ? x : y), args[0]); + +contract('VestingWallet', function (accounts) { + const [sender, beneficiary] = accounts; + + const amount = web3.utils.toBN(web3.utils.toWei('100')); + const duration = web3.utils.toBN(4 * 365 * 86400); // 4 years + + beforeEach(async function () { + this.start = (await time.latest()).addn(3600); // in 1 hour + this.mock = await VestingWallet.new(beneficiary, this.start, duration); + }); + + it('rejects zero address for beneficiary', async function () { + await expectRevert( + VestingWallet.new(constants.ZERO_ADDRESS, this.start, duration), + 'VestingWallet: beneficiary is zero address', + ); + }); + + it('check vesting contract', async function () { + expect(await this.mock.beneficiary()).to.be.equal(beneficiary); + expect(await this.mock.start()).to.be.bignumber.equal(this.start); + expect(await this.mock.duration()).to.be.bignumber.equal(duration); + }); + + describe('vesting schedule', function () { + beforeEach(async function () { + this.schedule = Array(64) + .fill() + .map((_, i) => web3.utils.toBN(i).mul(duration).divn(60).add(this.start)); + this.vestingFn = timestamp => min(amount, amount.mul(timestamp.sub(this.start)).div(duration)); + }); + + describe('Eth vesting', function () { + beforeEach(async function () { + await web3.eth.sendTransaction({ from: sender, to: this.mock.address, value: amount }); + this.getBalance = account => web3.eth.getBalance(account).then(web3.utils.toBN); + this.checkRelease = () => {}; + }); + + shouldBehaveLikeVesting(beneficiary); + }); + + describe('ERC20 vesting', function () { + beforeEach(async function () { + this.token = await ERC20.new('Name', 'Symbol'); + this.getBalance = account => this.token.balanceOf(account); + this.checkRelease = (receipt, to, value) => + expectEvent.inTransaction(receipt.tx, this.token, 'Transfer', { from: this.mock.address, to, value }); + + await this.token.$_mint(this.mock.address, amount); + }); + + shouldBehaveLikeVesting(beneficiary); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/governance/Governor.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/Governor.test.js new file mode 100644 index 0000000..1eabacc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/Governor.test.js @@ -0,0 +1,699 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +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 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 name = 'OZ-Governor'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, mode); + + 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 }); + + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + '', + ); + }); + + 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('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 }); + + 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(); + + 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.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'), + }); + + await this.helper.waitForDeadline(); + + const txExecute = await this.helper.execute(); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + + 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.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()); + + 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(), + }, + ], + '', + ); + + 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 = 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 }, + ); + }); + }); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/governance/TimelockController.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/TimelockController.test.js new file mode 100644 index 0000000..dde9235 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/TimelockController.test.js @@ -0,0 +1,1099 @@ +const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS, ZERO_BYTES32 } = constants; + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); + +const TimelockController = artifacts.require('TimelockController'); +const CallReceiverMock = artifacts.require('CallReceiverMock'); +const Implementation2 = artifacts.require('Implementation2'); +const ERC721 = artifacts.require('$ERC721'); +const ERC1155 = artifacts.require('$ERC1155'); + +const MINDELAY = time.duration.days(1); + +const salt = '0x025e7b0be353a74631ad648c667493c0e1cd31caa4cc2d3520fdc171ea0cc726'; // a random value + +function genOperation(target, value, data, predecessor, salt) { + const id = web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address', 'uint256', 'bytes', 'uint256', 'bytes32'], + [target, value, data, predecessor, salt], + ), + ); + return { id, target, value, data, predecessor, salt }; +} + +function genOperationBatch(targets, values, payloads, predecessor, salt) { + const id = web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address[]', 'uint256[]', 'bytes[]', 'uint256', 'bytes32'], + [targets, values, payloads, predecessor, salt], + ), + ); + return { id, targets, values, payloads, predecessor, salt }; +} + +contract('TimelockController', function (accounts) { + const [, admin, proposer, canceller, executor, other] = accounts; + + const TIMELOCK_ADMIN_ROLE = web3.utils.soliditySha3('TIMELOCK_ADMIN_ROLE'); + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + beforeEach(async function () { + // Deploy new timelock + this.mock = await TimelockController.new(MINDELAY, [proposer], [executor], admin); + + expect(await this.mock.hasRole(CANCELLER_ROLE, proposer)).to.be.equal(true); + await this.mock.revokeRole(CANCELLER_ROLE, proposer, { from: admin }); + await this.mock.grantRole(CANCELLER_ROLE, canceller, { from: admin }); + + // Mocks + this.callreceivermock = await CallReceiverMock.new({ from: admin }); + this.implementation2 = await Implementation2.new({ from: admin }); + }); + + shouldSupportInterfaces(['ERC1155Receiver']); + + it('initial state', async function () { + expect(await this.mock.getMinDelay()).to.be.bignumber.equal(MINDELAY); + + expect(await this.mock.TIMELOCK_ADMIN_ROLE()).to.be.equal(TIMELOCK_ADMIN_ROLE); + expect(await this.mock.PROPOSER_ROLE()).to.be.equal(PROPOSER_ROLE); + expect(await this.mock.EXECUTOR_ROLE()).to.be.equal(EXECUTOR_ROLE); + expect(await this.mock.CANCELLER_ROLE()).to.be.equal(CANCELLER_ROLE); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, proposer))), + ).to.be.deep.equal([true, false, false]); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, canceller))), + ).to.be.deep.equal([false, true, false]); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, executor))), + ).to.be.deep.equal([false, false, true]); + }); + + it('optional admin', async function () { + const mock = await TimelockController.new(MINDELAY, [proposer], [executor], ZERO_ADDRESS, { from: other }); + + expect(await mock.hasRole(TIMELOCK_ADMIN_ROLE, admin)).to.be.equal(false); + expect(await mock.hasRole(TIMELOCK_ADMIN_ROLE, other)).to.be.equal(false); + }); + + describe('methods', function () { + describe('operation hashing', function () { + it('hashOperation', async function () { + this.operation = genOperation( + '0x29cebefe301c6ce1bb36b58654fea275e1cacc83', + '0xf94fdd6e21da21d2', + '0xa3bc5104', + '0xba41db3be0a9929145cfe480bd0f1f003689104d275ae912099f925df424ef94', + '0x60d9109846ab510ed75c15f979ae366a8a2ace11d34ba9788c13ac296db50e6e', + ); + expect( + await this.mock.hashOperation( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ).to.be.equal(this.operation.id); + }); + + it('hashOperationBatch', async function () { + this.operation = genOperationBatch( + Array(8).fill('0x2d5f21620e56531c1d59c2df9b8e95d129571f71'), + Array(8).fill('0x2b993cfce932ccee'), + Array(8).fill('0xcf51966b'), + '0xce8f45069cc71d25f71ba05062de1a3974f9849b004de64a70998bca9d29c2e7', + '0x8952d74c110f72bfe5accdf828c74d53a7dfb71235dfa8a1e8c75d8576b372ff', + ); + expect( + await this.mock.hashOperationBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ).to.be.equal(this.operation.id); + }); + }); + describe('simple', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperation( + '0x31754f590B97fD975Eb86938f18Cc304E264D2F2', + 0, + '0x3bf92ccc', + ZERO_BYTES32, + salt, + ); + }); + + it('proposer can schedule', async function () { + const receipt = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + expectEvent(receipt, 'CallScheduled', { + id: this.operation.id, + index: web3.utils.toBN(0), + target: this.operation.target, + value: web3.utils.toBN(this.operation.value), + data: this.operation.data, + 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); + + expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( + web3.utils.toBN(block.timestamp).add(MINDELAY), + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + + await expectRevert( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockController: operation already scheduled', + ); + }); + + it('prevent non-proposer from committing', async function () { + await expectRevert( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: other }, + ), + `AccessControl: account ${other.toLowerCase()} is missing role ${PROPOSER_ROLE}`, + ); + }); + + it('enforce minimum delay', async function () { + await expectRevert( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1, + { from: proposer }, + ), + '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 () { + beforeEach(async function () { + this.operation = genOperation( + '0xAe22104DCD970750610E6FE15E623468A98b15f7', + 0, + '0x13e414de', + ZERO_BYTES32, + '0xc1059ed2dc130227aa1d1d539ac94c641306905c020436c636e19e3fab56fc7f', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expectRevert( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + ({ receipt: this.receipt, logs: this.logs } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('revert if execution comes too early 1/2', async function () { + await expectRevert( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + it('revert if execution comes too early 2/2', async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp - 5); // -1 is too tight, test sometime fails + + await expectRevert( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + describe('on time', function () { + beforeEach(async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp); + }); + + it('executor can reveal', async function () { + const receipt = await this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ); + expectEvent(receipt, 'CallExecuted', { + id: this.operation.id, + index: web3.utils.toBN(0), + target: this.operation.target, + value: web3.utils.toBN(this.operation.value), + data: this.operation.data, + }); + }); + + it('prevent non-executor from revealing', async function () { + await expectRevert( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: other }, + ), + `AccessControl: account ${other.toLowerCase()} is missing role ${EXECUTOR_ROLE}`, + ); + }); + }); + }); + }); + }); + + describe('batch', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0xEd912250835c812D4516BBD80BdaEA1bB63a293C'), + Array(8).fill(0), + Array(8).fill('0x2fcb7a88'), + ZERO_BYTES32, + '0x6cf9d042ade5de78bed9ffd075eb4b2a4f6b1736932c2dc8af517d6e066f51f5', + ); + }); + + it('proposer can schedule', async function () { + const receipt = await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + for (const i in this.operation.targets) { + expectEvent(receipt, 'CallScheduled', { + id: this.operation.id, + index: web3.utils.toBN(i), + target: this.operation.targets[i], + value: web3.utils.toBN(this.operation.values[i]), + data: this.operation.payloads[i], + 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); + + expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( + web3.utils.toBN(block.timestamp).add(MINDELAY), + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockController: operation already scheduled', + ); + }); + + it('length of batch parameter must match #1', async function () { + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockController: length mismatch', + ); + }); + + it('length of batch parameter must match #1', async function () { + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockController: length mismatch', + ); + }); + + it('prevent non-proposer from committing', async function () { + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: other }, + ), + `AccessControl: account ${other.toLowerCase()} is missing role ${PROPOSER_ROLE}`, + ); + }); + + it('enforce minimum delay', async function () { + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1, + { from: proposer }, + ), + 'TimelockController: insufficient delay', + ); + }); + }); + + describe('execute', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0x76E53CcEb05131Ef5248553bEBDb8F70536830b1'), + Array(8).fill(0), + Array(8).fill('0x58a60f63'), + ZERO_BYTES32, + '0x9545eeabc7a7586689191f78a5532443698538e54211b5bd4d7dc0fc0102b5c7', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + ({ receipt: this.receipt, logs: this.logs } = await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('revert if execution comes too early 1/2', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + it('revert if execution comes too early 2/2', async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp - 5); // -1 is to tight, test sometime fails + + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + describe('on time', function () { + beforeEach(async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp); + }); + + it('executor can reveal', async function () { + const receipt = await this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ); + for (const i in this.operation.targets) { + expectEvent(receipt, 'CallExecuted', { + id: this.operation.id, + index: web3.utils.toBN(i), + target: this.operation.targets[i], + value: web3.utils.toBN(this.operation.values[i]), + data: this.operation.payloads[i], + }); + } + }); + + it('prevent non-executor from revealing', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: other }, + ), + `AccessControl: account ${other.toLowerCase()} is missing role ${EXECUTOR_ROLE}`, + ); + }); + + it('length mismatch #1', async function () { + await expectRevert( + this.mock.executeBatch( + [], + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: length mismatch', + ); + }); + + it('length mismatch #2', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: length mismatch', + ); + }); + + it('length mismatch #3', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: length mismatch', + ); + }); + }); + }); + + it('partial execution', async function () { + const operation = genOperationBatch( + [this.callreceivermock.address, this.callreceivermock.address, this.callreceivermock.address], + [0, 0, 0], + [ + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(), + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + ], + ZERO_BYTES32, + '0x8ac04aa0d6d66b8812fb41d39638d37af0a9ab11da507afd65c509f8ed079d3e', + ); + + await this.mock.scheduleBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevert( + this.mock.executeBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + { from: executor }, + ), + 'TimelockController: underlying transaction reverted', + ); + }); + }); + }); + + describe('cancel', function () { + beforeEach(async function () { + this.operation = genOperation( + '0xC6837c44AA376dbe1d2709F13879E040CAb653ca', + 0, + '0x296e58dd', + ZERO_BYTES32, + '0xa2485763600634800df9fc9646fb2c112cf98649c55f63dd1d9c7d13a64399d9', + ); + ({ receipt: this.receipt, logs: this.logs } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('canceller can cancel', async function () { + const receipt = await this.mock.cancel(this.operation.id, { from: canceller }); + expectEvent(receipt, 'Cancelled', { id: this.operation.id }); + }); + + it('cannot cancel invalid operation', async function () { + await expectRevert( + this.mock.cancel(constants.ZERO_BYTES32, { from: canceller }), + 'TimelockController: operation cannot be cancelled', + ); + }); + + it('prevent non-canceller from canceling', async function () { + await expectRevert( + this.mock.cancel(this.operation.id, { from: other }), + `AccessControl: account ${other.toLowerCase()} is missing role ${CANCELLER_ROLE}`, + ); + }); + }); + }); + + describe('maintenance', function () { + it('prevent unauthorized maintenance', async function () { + await expectRevert(this.mock.updateDelay(0, { from: other }), 'TimelockController: caller must be timelock'); + }); + + it('timelock scheduled maintenance', async function () { + const newDelay = time.duration.hours(6); + const operation = genOperation( + this.mock.address, + 0, + this.mock.contract.methods.updateDelay(newDelay.toString()).encodeABI(), + ZERO_BYTES32, + '0xf8e775b2c5f4d66fb5c7fa800f35ef518c262b6014b3c0aee6ea21bff157f108', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + const receipt = await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor }, + ); + expectEvent(receipt, 'MinDelayChange', { newDuration: newDelay.toString(), oldDuration: MINDELAY }); + + expect(await this.mock.getMinDelay()).to.be.bignumber.equal(newDelay); + }); + }); + + describe('dependency', function () { + beforeEach(async function () { + this.operation1 = genOperation( + '0xdE66bD4c97304200A95aE0AadA32d6d01A867E39', + 0, + '0x01dc731a', + ZERO_BYTES32, + '0x64e932133c7677402ead2926f86205e2ca4686aebecf5a8077627092b9bb2feb', + ); + this.operation2 = genOperation( + '0x3c7944a3F1ee7fc8c5A5134ba7c79D11c3A1FCa3', + 0, + '0x8f531849', + this.operation1.id, + '0x036e1311cac523f9548e6461e29fb1f8f9196b91910a41711ea22f5de48df07d', + ); + await this.mock.schedule( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + MINDELAY, + { from: proposer }, + ); + await this.mock.schedule( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + }); + + it('cannot execute before dependency', async function () { + await expectRevert( + this.mock.execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + { from: executor }, + ), + 'TimelockController: missing dependency', + ); + }); + + it('can execute after dependency', async function () { + await this.mock.execute( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + { from: executor }, + ); + await this.mock.execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + { from: executor }, + ); + }); + }); + + describe('usage scenario', function () { + this.timeout(10000); + + it('call', async function () { + const operation = genOperation( + this.implementation2.address, + 0, + this.implementation2.contract.methods.setValue(42).encodeABI(), + ZERO_BYTES32, + '0x8043596363daefc89977b25f9d9b4d06c3910959ef0c4d213557a903e1b555e2', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor }, + ); + + expect(await this.implementation2.getValue()).to.be.bignumber.equal(web3.utils.toBN(42)); + }); + + it('call reverting', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + ZERO_BYTES32, + '0xb1b1b276fdf1a28d1e00537ea73b04d56639128b08063c1a2f70a52e38cba693', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'TimelockController: underlying transaction reverted', + ); + }); + + it('call throw', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(), + ZERO_BYTES32, + '0xe5ca79f295fc8327ee8a765fe19afb58f4a0cbc5053642bfdd7e73bc68e0fc67', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'TimelockController: underlying transaction reverted', + ); + }); + + it('call out of gas', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionOutOfGas().encodeABI(), + ZERO_BYTES32, + '0xf3274ce7c394c5b629d5215723563a744b817e1730cca5587c567099a14578fd', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + gas: '70000', + }), + 'TimelockController: underlying transaction reverted', + ); + }); + + it('call payable with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + ZERO_BYTES32, + '0x5ab73cd33477dcd36c1e05e28362719d0ed59a7b9ff14939de63a43073dc1f44', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor, value: 1 }, + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(1)); + }); + + it('call nonpayable with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunctionNonPayable().encodeABI(), + ZERO_BYTES32, + '0xb78edbd920c7867f187e5aa6294ae5a656cfbf0dea1ccdca3751b740d0f2bdf8', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'TimelockController: underlying transaction reverted', + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + it('call reverting with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + ZERO_BYTES32, + '0xdedb4563ef0095db01d81d3f2decf57cf83e4a72aa792af14c43a792b56f4de6', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'TimelockController: underlying transaction reverted', + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + }); + + 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(other, tokenId); + }); + + it('can receive an ERC721 safeTransfer', async function () { + await this.token.safeTransferFrom(other, this.mock.address, tokenId, { from: other }); + }); + }); + + 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(other, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it('can receive ERC1155 safeTransfer', async function () { + await this.token.safeTransferFrom( + other, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: other }, + ); + }); + + it('can receive ERC1155 safeBatchTransfer', async function () { + await this.token.safeBatchTransferFrom( + other, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: other }, + ); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/governance/compatibility/GovernorCompatibilityBravo.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/compatibility/GovernorCompatibilityBravo.test.js new file mode 100644 index 0000000..9e55194 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/compatibility/GovernorCompatibilityBravo.test.js @@ -0,0 +1,268 @@ +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 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 + .sha3(RLP.encode([creator, nonce])) + .slice(12) + .substring(14), + ); +} + +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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const proposalThreshold = web3.utils.toWei('10'); + const value = web3.utils.toWei('1'); + + 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); + + // 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.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: 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()', + }, + ], + '', + ); + }); + + 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.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, + 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/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorComp.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorComp.test.js new file mode 100644 index 0000000..bfcd0af --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorComp.test.js @@ -0,0 +1,88 @@ +const { expect } = require('chai'); +const Enums = require('../../helpers/enums'); +const { GovernorHelper } = require('../../helpers/governance'); + +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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, mode); + + 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 }); + + // 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('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); + + 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/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js new file mode 100644 index 0000000..c1f424c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js @@ -0,0 +1,115 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const Enums = require('../../helpers/enums'); +const { GovernorHelper } = require('../../helpers/governance'); + +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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockNFToken'; + const tokenSymbol = 'MTKN'; + 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'); + + 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, mode); + + 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 }); + + // 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('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: 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/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js new file mode 100644 index 0000000..f81bd52 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js @@ -0,0 +1,189 @@ +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 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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + 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'); + + 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, mode); + + 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 }); + + // 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 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/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js new file mode 100644 index 0000000..23d0adb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js @@ -0,0 +1,352 @@ +const { constants, 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 { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +const Timelock = artifacts.require('CompTimelock'); +const Governor = artifacts.require('$GovernorTimelockCompoundMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); + +function makeContractAddress(creator, nonce) { + return web3.utils.toChecksumAddress( + web3.utils + .sha3(RLP.encode([creator, nonce])) + .slice(12) + .substring(14), + ); +} + +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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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); + + // 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, 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.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 () { + 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); + }); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js new file mode 100644 index 0000000..ef50dc7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js @@ -0,0 +1,445 @@ +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 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; + + const TIMELOCK_ADMIN_ROLE = web3.utils.soliditySha3('TIMELOCK_ADMIN_ROLE'); + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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.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(); + + 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); + + 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.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. + }); + }); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js new file mode 100644 index 0000000..ca91580 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js @@ -0,0 +1,154 @@ +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 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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + 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'); + + 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, mode); + + 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 }); + + // 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 clock[mode]().then(timepoint => this.mock.quorum(timepoint - 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, + }); + + 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', + ); + }); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js new file mode 100644 index 0000000..4e14694 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js @@ -0,0 +1,173 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { fromRpcSig } = require('ethereumjs-util'); +const Enums = require('../../helpers/enums'); +const { getDomain, domainType } = require('../../helpers/eip712'); +const { GovernorHelper } = require('../../helpers/governance'); + +const Governor = artifacts.require('$GovernorWithParamsMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); + +const rawParams = { + 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; + + const name = 'OZ-Governor'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, mode); + + 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 }); + + // 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('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); + }); + + it('Voting with params is properly supported', async function () { + await this.helper.propose({ from: proposer }); + 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, + }, + { 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' }, + ], + }, + 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); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/governance/utils/EIP6372.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/utils/EIP6372.behavior.js new file mode 100644 index 0000000..022ec35 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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/lib/crytic/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js new file mode 100644 index 0000000..864a2f9 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js @@ -0,0 +1,361 @@ +const { constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); + +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +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' }, + { name: 'nonce', type: 'uint256' }, + { name: 'expiry', type: 'uint256' }, +]; + +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'); + }); + + it('domain separator', async function () { + expect(await this.votes.DOMAIN_SEPARATOR()).to.equal(domainSeparator(await getDomain(this.votes))); + }); + + describe('delegation with signature', function () { + const delegator = Wallet.generate(); + const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); + const nonce = 0; + + const buildAndSignData = async (contract, message, pk) => { + const data = await getDomain(contract).then(domain => ({ + primaryType: 'Delegation', + 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 } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + 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, + toDelegate: delegatorAddress, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: delegatorAddress, + previousBalance: '0', + newBalance: '1', + }); + + 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, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(delegatorAddress, timepoint)).to.be.bignumber.equal('1'); + }); + + it('rejects reused signature', async function () { + 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); + + await expectRevert( + this.votes.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s), + 'Votes: invalid nonce', + ); + }); + + it('rejects bad delegatee', async function () { + 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); + 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(this.account1Delegatee); + }); + + it('rejects bad nonce', async function () { + 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', + ); + }); + + it('rejects expired permit', async function () { + const expiry = (await time.latest()) - time.duration.weeks(1); + + const { v, r, s } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry, + }, + delegator.getPrivateKey(), + ); + + await expectRevert( + this.votes.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), + 'Votes: signature expired', + ); + }); + }); + + describe('set delegation', function () { + describe('call', function () { + it('delegation with tokens', async function () { + await this.votes.$_mint(this.account1, this.NFT0); + 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, + toDelegate: this.account1, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: this.account1, + previousBalance: '0', + newBalance: '1', + }); + + 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, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(this.account1, timepoint)).to.be.bignumber.equal('1'); + }); + + it('delegation without tokens', async function () { + expect(await this.votes.delegates(this.account1)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.votes.delegate(this.account1, { from: this.account1 }); + expectEvent(receipt, 'DelegateChanged', { + delegator: this.account1, + fromDelegate: ZERO_ADDRESS, + toDelegate: this.account1, + }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + expect(await this.votes.delegates(this.account1)).to.be.equal(this.account1); + }); + }); + }); + + describe('change delegation', function () { + beforeEach(async function () { + await this.votes.$_mint(this.account1, this.NFT0); + await this.votes.delegate(this.account1, { from: this.account1 }); + }); + + it('call', async function () { + 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, + toDelegate: this.account1Delegatee, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: this.account1, + previousBalance: '1', + newBalance: '0', + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: this.account1Delegatee, + previousBalance: '0', + newBalance: '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, 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, timepoint)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(this.account1Delegatee, timepoint)).to.be.bignumber.equal('1'); + }); + }); + + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.votes.delegate(this.account1, { from: this.account1 }); + }); + + it('reverts if block number >= current block', async function () { + await expectRevert(this.votes.getPastTotalSupply(5e10), 'future lookup'); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastTotalSupply(0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + 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(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 { 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(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 () { + const t1 = await this.votes.$_mint(this.account1, this.NFT1); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.votes.$_burn(this.NFT1); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.votes.$_mint(this.account1, this.NFT2); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.votes.$_burn(this.NFT2); + await time.advanceBlock(); + await time.advanceBlock(); + const t5 = await this.votes.$_mint(this.account1, this.NFT3); + 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); + 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'); + }); + }); + + // 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.votes.$_mint(this.account1, this.NFT0); + await this.votes.$_mint(this.account1, this.NFT1); + await this.votes.$_mint(this.account1, this.NFT2); + await this.votes.$_mint(this.account1, this.NFT3); + }); + + describe('getPastVotes', function () { + it('reverts if block number >= current block', async function () { + await expectRevert(this.votes.getPastVotes(this.account2, 5e10), 'future lookup'); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastVotes(this.account2, 0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + 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); + 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 { 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, timepoint - 1)).to.be.bignumber.equal('0'); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeVotes, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js b/lib/crytic/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js new file mode 100644 index 0000000..62b1ab2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js @@ -0,0 +1,71 @@ +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 MODES = { + blocknumber: artifacts.require('$VotesMock'), + timestamp: artifacts.require('$VotesTimestampMock'), +}; + +contract('Votes', function (accounts) { + const [account1, account2, account3] = accounts; + + 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'); + }); + + 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); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/chainid.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/chainid.js new file mode 100644 index 0000000..58757eb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/chainid.js @@ -0,0 +1,10 @@ +const hre = require('hardhat'); + +async function getChainId() { + const chainIdHex = await hre.network.provider.send('eth_chainId', []); + return new hre.web3.utils.BN(chainIdHex, 'hex'); +} + +module.exports = { + getChainId, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/create2.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/create2.js new file mode 100644 index 0000000..afe07da --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/create2.js @@ -0,0 +1,11 @@ +function computeCreate2Address(saltHex, bytecode, deployer) { + return web3.utils.toChecksumAddress( + `0x${web3.utils + .sha3(`0x${['ff', deployer, saltHex, web3.utils.soliditySha3(bytecode)].map(x => x.replace(/0x/, '')).join('')}`) + .slice(-40)}`, + ); +} + +module.exports = { + computeCreate2Address, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/crosschain.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/crosschain.js new file mode 100644 index 0000000..9e6ff96 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/crosschain.js @@ -0,0 +1,61 @@ +const { promisify } = require('util'); + +const BridgeAMBMock = artifacts.require('BridgeAMBMock'); +const BridgeArbitrumL1Mock = artifacts.require('BridgeArbitrumL1Mock'); +const BridgeArbitrumL2Mock = artifacts.require('BridgeArbitrumL2Mock'); +const BridgeOptimismMock = artifacts.require('BridgeOptimismMock'); +const BridgePolygonChildMock = artifacts.require('BridgePolygonChildMock'); + +class BridgeHelper { + static async deploy(type) { + return new BridgeHelper(await deployBridge(type)); + } + + constructor(bridge) { + this.bridge = bridge; + this.address = bridge.address; + } + + call(from, target, selector = undefined, args = []) { + return this.bridge.relayAs( + target.address || target, + selector ? target.contract.methods[selector](...args).encodeABI() : '0x', + from, + ); + } +} + +async function deployBridge(type = 'Arbitrum-L2') { + switch (type) { + case 'AMB': + return BridgeAMBMock.new(); + + case 'Arbitrum-L1': + return BridgeArbitrumL1Mock.new(); + + case 'Arbitrum-L2': { + const instance = await BridgeArbitrumL2Mock.new(); + const code = await web3.eth.getCode(instance.address); + await promisify(web3.currentProvider.send.bind(web3.currentProvider))({ + jsonrpc: '2.0', + method: 'hardhat_setCode', + params: ['0x0000000000000000000000000000000000000064', code], + id: new Date().getTime(), + }); + return BridgeArbitrumL2Mock.at('0x0000000000000000000000000000000000000064'); + } + + case 'Optimism': + return BridgeOptimismMock.new(); + + case 'Polygon-Child': + return BridgePolygonChildMock.new(); + + default: + throw new Error(`CrossChain: ${type} is not supported`); + } +} + +module.exports = { + BridgeHelper, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/customError.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/customError.js new file mode 100644 index 0000000..3cfcd72 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/customError.js @@ -0,0 +1,24 @@ +const { config } = require('hardhat'); + +const optimizationsEnabled = config.solidity.compilers.some(c => c.settings.optimizer.enabled); + +/** Revert handler that supports custom errors. */ +async function expectRevertCustomError(promise, reason) { + try { + await promise; + expect.fail("Expected promise to throw but it didn't"); + } catch (revert) { + if (reason) { + if (optimizationsEnabled) { + // Optimizations currently mess with Hardhat's decoding of custom errors + expect(revert.message).to.include.oneOf([reason, 'unrecognized return data or custom error']); + } else { + expect(revert.message).to.include(reason); + } + } + } +} + +module.exports = { + expectRevertCustomError, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/eip712.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/eip712.js new file mode 100644 index 0000000..b12a623 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/eip712.js @@ -0,0 +1,67 @@ +const ethSigUtil = require('eth-sig-util'); +const keccak256 = require('keccak256'); + +const EIP712Domain = [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + { name: 'salt', type: 'bytes32' }, +]; + +const Permit = [ + { name: 'owner', type: 'address' }, + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint256' }, +]; + +function bufferToHexString(buffer) { + return '0x' + buffer.toString('hex'); +} + +function hexStringToBuffer(hexstr) { + return Buffer.from(hexstr.replace(/^0x/, ''), 'hex'); +} + +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', domain, { EIP712Domain: domainType(domain) }), + ); +} + +function hashTypedData(domain, structHash) { + return bufferToHexString( + keccak256(Buffer.concat(['0x1901', domainSeparator(domain), structHash].map(str => hexStringToBuffer(str)))), + ); +} + +module.exports = { + Permit, + getDomain, + domainType, + domainSeparator, + hashTypedData, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/enums.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/enums.js new file mode 100644 index 0000000..ced6c38 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/enums.js @@ -0,0 +1,12 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +function Enum(...options) { + return Object.fromEntries(options.map((key, i) => [key, new BN(i)])); +} + +module.exports = { + Enum, + ProposalState: Enum('Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'), + VoteType: Enum('Against', 'For', 'Abstain'), + Rounding: Enum('Down', 'Up', 'Zero'), +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/erc1967.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/erc1967.js new file mode 100644 index 0000000..9abbcc8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/erc1967.js @@ -0,0 +1,24 @@ +const ImplementationLabel = 'eip1967.proxy.implementation'; +const AdminLabel = 'eip1967.proxy.admin'; +const BeaconLabel = 'eip1967.proxy.beacon'; + +function labelToSlot(label) { + return '0x' + web3.utils.toBN(web3.utils.keccak256(label)).subn(1).toString(16); +} + +function getSlot(address, slot) { + return web3.eth.getStorageAt( + web3.utils.isAddress(address) ? address : address.address, + web3.utils.isHex(slot) ? slot : labelToSlot(slot), + ); +} + +module.exports = { + ImplementationLabel, + AdminLabel, + BeaconLabel, + ImplementationSlot: labelToSlot(ImplementationLabel), + AdminSlot: labelToSlot(AdminLabel), + BeaconSlot: labelToSlot(BeaconLabel), + getSlot, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/governance.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/governance.js new file mode 100644 index 0000000..4b38b75 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/governance.js @@ -0,0 +1,201 @@ +const { forward } = require('../helpers/time'); + +function zip(...args) { + return Array(Math.max(...args.map(array => array.length))) + .fill() + .map((_, i) => args.map(array => array[i])); +} + +function concatHex(...args) { + return web3.utils.bytesToHex([].concat(...args.map(h => web3.utils.hexToBytes(h || '0x')))); +} + +function concatOpts(args, opts = null) { + return opts ? args.concat(opts) : args; +} + +class GovernorHelper { + constructor(governor, mode = 'blocknumber') { + this.governor = governor; + this.mode = mode; + } + + delegate(delegation = {}, opts = null) { + return Promise.all([ + delegation.token.delegate(delegation.to, { from: delegation.to }), + delegation.value && delegation.token.transfer(...concatOpts([delegation.to, delegation.value]), opts), + delegation.tokenId && + delegation.token + .ownerOf(delegation.tokenId) + .then(owner => + delegation.token.transferFrom(...concatOpts([owner, delegation.to, delegation.tokenId], opts)), + ), + ]); + } + + propose(opts = null) { + const proposal = this.currentProposal; + + return this.governor.methods[ + proposal.useCompatibilityInterface + ? 'propose(address[],uint256[],string[],bytes[],string)' + : 'propose(address[],uint256[],bytes[],string)' + ](...concatOpts(proposal.fullProposal, opts)); + } + + queue(opts = null) { + const proposal = this.currentProposal; + + return proposal.useCompatibilityInterface + ? this.governor.methods['queue(uint256)'](...concatOpts([proposal.id], opts)) + : this.governor.methods['queue(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } + + execute(opts = null) { + const proposal = this.currentProposal; + + return proposal.useCompatibilityInterface + ? this.governor.methods['execute(uint256)'](...concatOpts([proposal.id], opts)) + : this.governor.methods['execute(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } + + cancel(visibility = 'external', opts = null) { + const proposal = this.currentProposal; + + switch (visibility) { + case 'external': + 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), + ); + default: + throw new Error(`unsuported visibility "${visibility}"`); + } + } + + vote(vote = {}, opts = null) { + const proposal = this.currentProposal; + + return vote.signature + ? // if signature, and either params or reason → + vote.params || vote.reason + ? vote + .signature(this.governor, { + proposalId: proposal.id, + support: vote.support, + reason: vote.reason || '', + params: vote.params || '', + }) + .then(({ v, r, s }) => + this.governor.castVoteWithReasonAndParamsBySig( + ...concatOpts([proposal.id, vote.support, vote.reason || '', vote.params || '', v, r, s], opts), + ), + ) + : vote + .signature(this.governor, { + proposalId: proposal.id, + support: vote.support, + }) + .then(({ v, r, s }) => + this.governor.castVoteBySig(...concatOpts([proposal.id, vote.support, v, r, s], opts)), + ) + : vote.params + ? // otherwise if params + this.governor.castVoteWithReasonAndParams( + ...concatOpts([proposal.id, vote.support, vote.reason || '', vote.params], opts), + ) + : vote.reason + ? // otherwise if reason + this.governor.castVoteWithReason(...concatOpts([proposal.id, vote.support, vote.reason], opts)) + : this.governor.castVote(...concatOpts([proposal.id, vote.support], opts)); + } + + async waitForSnapshot(offset = 0) { + const proposal = this.currentProposal; + const timepoint = await this.governor.proposalSnapshot(proposal.id); + return forward[this.mode](timepoint.addn(offset)); + } + + async waitForDeadline(offset = 0) { + const proposal = this.currentProposal; + const timepoint = await this.governor.proposalDeadline(proposal.id); + return forward[this.mode](timepoint.addn(offset)); + } + + async waitForEta(offset = 0) { + const proposal = this.currentProposal; + const timestamp = await this.governor.proposalEta(proposal.id); + return forward.timestamp(timestamp.addn(offset)); + } + + /** + * Specify a proposal either as + * 1) an array of objects [{ target, value, data, signature? }] + * 2) an object of arrays { targets: [], values: [], data: [], signatures?: [] } + */ + setProposal(actions, description) { + let targets, values, signatures, data, useCompatibilityInterface; + + if (Array.isArray(actions)) { + useCompatibilityInterface = actions.some(a => 'signature' in a); + targets = actions.map(a => a.target); + values = actions.map(a => a.value || '0'); + signatures = actions.map(a => a.signature || ''); + data = actions.map(a => a.data || '0x'); + } else { + useCompatibilityInterface = Array.isArray(actions.signatures); + ({ targets, values, signatures = [], data } = actions); + } + + const fulldata = zip( + signatures.map(s => s && web3.eth.abi.encodeFunctionSignature(s)), + data, + ).map(hexs => concatHex(...hexs)); + + const descriptionHash = web3.utils.keccak256(description); + + // condensed version for queueing end executing + const shortProposal = [targets, values, fulldata, descriptionHash]; + + // full version for proposing + const fullProposal = [targets, values, ...(useCompatibilityInterface ? [signatures] : []), data, description]; + + // proposal id + const id = web3.utils.toBN( + web3.utils.keccak256( + web3.eth.abi.encodeParameters(['address[]', 'uint256[]', 'bytes[]', 'bytes32'], shortProposal), + ), + ); + + this.currentProposal = { + id, + targets, + values, + signatures, + data, + fulldata, + description, + descriptionHash, + shortProposal, + fullProposal, + useCompatibilityInterface, + }; + + return this.currentProposal; + } +} + +module.exports = { + GovernorHelper, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/map-values.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/map-values.js new file mode 100644 index 0000000..d2f7b2a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/map-values.js @@ -0,0 +1,7 @@ +function mapValues(obj, fn) { + return Object.fromEntries([...Object.entries(obj)].map(([k, v]) => [k, fn(v)])); +} + +module.exports = { + mapValues, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/sign.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/sign.js new file mode 100644 index 0000000..d537116 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/sign.js @@ -0,0 +1,63 @@ +function toEthSignedMessageHash(messageHex) { + const messageBuffer = Buffer.from(messageHex.substring(2), 'hex'); + const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`); + 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 + * @param contract TruffleContract + * @param signer address + * @param redeemer address + * @param methodName string + * @param methodArgs any[] + */ +const getSignFor = + (contract, signer) => + (redeemer, methodName, methodArgs = []) => { + const parts = [contract.address, redeemer]; + + const REAL_SIGNATURE_SIZE = 2 * 65; // 65 bytes in hexadecimal string length + const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length + const DUMMY_SIGNATURE = `0x${web3.utils.padLeft('', REAL_SIGNATURE_SIZE)}`; + + // if we have a method, add it to the parts that we're signing + if (methodName) { + if (methodArgs.length > 0) { + parts.push( + contract.contract.methods[methodName](...methodArgs.concat([DUMMY_SIGNATURE])) + .encodeABI() + .slice(0, -1 * PADDED_SIGNATURE_SIZE), + ); + } else { + const abi = contract.abi.find(abi => abi.name === methodName); + parts.push(abi.signature); + } + } + + // return the signature of the "Ethereum Signed Message" hash of the hash of `parts` + const messageHex = web3.utils.soliditySha3(...parts); + return web3.eth.sign(messageHex, signer); + }; + +module.exports = { + toEthSignedMessageHash, + toDataWithIntendedValidatorHash, + getSignFor, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/time.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/time.js new file mode 100644 index 0000000..30df8dc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/time.js @@ -0,0 +1,17 @@ +const ozHelpers = require('@openzeppelin/test-helpers'); +const helpers = require('@nomicfoundation/hardhat-network-helpers'); + +module.exports = { + clock: { + 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: ozHelpers.time.advanceBlockTo, + timestamp: helpers.time.increaseTo, + }, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/helpers/txpool.js b/lib/crytic/lib/openzeppelin-contracts/test/helpers/txpool.js new file mode 100644 index 0000000..ecdba54 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/helpers/txpool.js @@ -0,0 +1,38 @@ +const { network } = require('hardhat'); +const { promisify } = require('util'); + +const queue = promisify(setImmediate); + +async function countPendingTransactions() { + return parseInt(await network.provider.send('eth_getBlockTransactionCountByNumber', ['pending'])); +} + +async function batchInBlock(txs) { + try { + // disable auto-mining + await network.provider.send('evm_setAutomine', [false]); + // send all transactions + const promises = txs.map(fn => fn()); + // wait for node to have all pending transactions + while (txs.length > (await countPendingTransactions())) { + await queue(); + } + // mine one block + await network.provider.send('evm_mine'); + // fetch receipts + const receipts = await Promise.all(promises); + // Sanity check, all tx should be in the same block + const minedBlocks = new Set(receipts.map(({ receipt }) => receipt.blockNumber)); + expect(minedBlocks.size).to.equal(1); + + return receipts; + } finally { + // enable auto-mining + await network.provider.send('evm_setAutomine', [true]); + } +} + +module.exports = { + countPendingTransactions, + batchInBlock, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js b/lib/crytic/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js new file mode 100644 index 0000000..6c298d3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js @@ -0,0 +1,101 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); + +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC2771ContextMock = artifacts.require('ERC2771ContextMock'); +const MinimalForwarder = artifacts.require('MinimalForwarder'); +const ContextMockCaller = artifacts.require('ContextMockCaller'); + +const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior'); + +contract('ERC2771Context', function (accounts) { + beforeEach(async function () { + this.forwarder = await MinimalForwarder.new(); + this.recipient = await ERC2771ContextMock.new(this.forwarder.address); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }; + }); + + it('recognize trusted forwarder', async function () { + expect(await this.recipient.isTrustedForwarder(this.forwarder.address)); + }); + + context('when called directly', function () { + beforeEach(async function () { + this.context = this.recipient; // The Context behavior expects the contract in this.context + this.caller = await ContextMockCaller.new(); + }); + + shouldBehaveLikeRegularContext(...accounts); + }); + + context('when receiving a relayed call', function () { + beforeEach(async function () { + this.wallet = Wallet.generate(); + this.sender = web3.utils.toChecksumAddress(this.wallet.getAddressString()); + this.data = { + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + }; + }); + + describe('msgSender', function () { + it('returns the relayed transaction original sender', async function () { + const data = this.recipient.contract.methods.msgSender().encodeABI(); + + const req = { + from: this.sender, + to: this.recipient.address, + value: '0', + gas: '100000', + nonce: (await this.forwarder.getNonce(this.sender)).toString(), + data, + }; + + const sign = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { data: { ...this.data, message: req } }); + expect(await this.forwarder.verify(req, sign)).to.equal(true); + + const { tx } = await this.forwarder.execute(req, sign); + await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Sender', { sender: this.sender }); + }); + }); + + describe('msgData', function () { + it('returns the relayed transaction original data', async function () { + const integerValue = '42'; + const stringValue = 'OpenZeppelin'; + const data = this.recipient.contract.methods.msgData(integerValue, stringValue).encodeABI(); + + const req = { + from: this.sender, + to: this.recipient.address, + value: '0', + gas: '100000', + nonce: (await this.forwarder.getNonce(this.sender)).toString(), + data, + }; + + const sign = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { data: { ...this.data, message: req } }); + expect(await this.forwarder.verify(req, sign)).to.equal(true); + + const { tx } = await this.forwarder.execute(req, sign); + await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Data', { data, integerValue, stringValue }); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/metatx/MinimalForwarder.test.js b/lib/crytic/lib/openzeppelin-contracts/test/metatx/MinimalForwarder.test.js new file mode 100644 index 0000000..4884cc7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/metatx/MinimalForwarder.test.js @@ -0,0 +1,169 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); + +const { expectRevert, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const MinimalForwarder = artifacts.require('MinimalForwarder'); +const CallReceiverMock = artifacts.require('CallReceiverMock'); + +contract('MinimalForwarder', function (accounts) { + beforeEach(async function () { + this.forwarder = await MinimalForwarder.new(); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }; + }); + + context('with message', function () { + beforeEach(async function () { + this.wallet = Wallet.generate(); + this.sender = web3.utils.toChecksumAddress(this.wallet.getAddressString()); + this.req = { + from: this.sender, + to: constants.ZERO_ADDRESS, + value: '0', + gas: '100000', + nonce: Number(await this.forwarder.getNonce(this.sender)), + data: '0x', + }; + this.sign = () => + ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { + data: { + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + message: this.req, + }, + }); + }); + + context('verify', function () { + context('valid signature', function () { + beforeEach(async function () { + expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); + }); + + it('success', async function () { + expect(await this.forwarder.verify(this.req, this.sign())).to.be.equal(true); + }); + + afterEach(async function () { + expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); + }); + }); + + context('invalid signature', function () { + it('tampered from', async function () { + expect(await this.forwarder.verify({ ...this.req, from: accounts[0] }, this.sign())).to.be.equal(false); + }); + it('tampered to', async function () { + expect(await this.forwarder.verify({ ...this.req, to: accounts[0] }, this.sign())).to.be.equal(false); + }); + it('tampered value', async function () { + expect(await this.forwarder.verify({ ...this.req, value: web3.utils.toWei('1') }, this.sign())).to.be.equal( + false, + ); + }); + it('tampered nonce', async function () { + expect(await this.forwarder.verify({ ...this.req, nonce: this.req.nonce + 1 }, this.sign())).to.be.equal( + false, + ); + }); + it('tampered data', async function () { + expect(await this.forwarder.verify({ ...this.req, data: '0x1742' }, this.sign())).to.be.equal(false); + }); + it('tampered signature', async function () { + const tamperedsign = web3.utils.hexToBytes(this.sign()); + tamperedsign[42] ^= 0xff; + expect(await this.forwarder.verify(this.req, web3.utils.bytesToHex(tamperedsign))).to.be.equal(false); + }); + }); + }); + + context('execute', function () { + context('valid signature', function () { + beforeEach(async function () { + expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); + }); + + it('success', async function () { + await this.forwarder.execute(this.req, this.sign()); // expect to not revert + }); + + afterEach(async function () { + expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal( + web3.utils.toBN(this.req.nonce + 1), + ); + }); + }); + + context('invalid signature', function () { + it('tampered from', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, from: accounts[0] }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered to', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, to: accounts[0] }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered value', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, value: web3.utils.toWei('1') }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered nonce', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, nonce: this.req.nonce + 1 }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered data', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, data: '0x1742' }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered signature', async function () { + const tamperedsign = web3.utils.hexToBytes(this.sign()); + tamperedsign[42] ^= 0xff; + await expectRevert( + this.forwarder.execute(this.req, web3.utils.bytesToHex(tamperedsign)), + 'MinimalForwarder: signature does not match request', + ); + }); + }); + + it('bubble out of gas', async function () { + const receiver = await CallReceiverMock.new(); + const gasAvailable = 100000; + this.req.to = receiver.address; + this.req.data = receiver.contract.methods.mockFunctionOutOfGas().encodeABI(); + this.req.gas = 1000000; + + await expectRevert.assertion(this.forwarder.execute(this.req, this.sign(), { gas: gasAvailable })); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + expect(gasUsed).to.be.equal(gasAvailable); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/migrate-imports.test.js b/lib/crytic/lib/openzeppelin-contracts/test/migrate-imports.test.js new file mode 100644 index 0000000..7ec9a97 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/migrate-imports.test.js @@ -0,0 +1,32 @@ +const path = require('path'); +const { + promises: fs, + constants: { F_OK }, +} = require('fs'); +const { expect } = require('chai'); + +const { pathUpdates, updateImportPaths, getUpgradeablePath } = require('../scripts/migrate-imports.js'); + +describe('migrate-imports.js', function () { + it('every new path exists', async function () { + for (const p of Object.values(pathUpdates)) { + try { + await fs.access(path.join('contracts', p), F_OK); + } catch (e) { + await fs.access(path.join('contracts', getUpgradeablePath(p)), F_OK); + } + } + }); + + it('replaces import paths in a file', async function () { + const source = ` +import '@openzeppelin/contracts/math/Math.sol'; +import '@openzeppelin/contracts-upgradeable/math/MathUpgradeable.sol'; + `; + const expected = ` +import '@openzeppelin/contracts/utils/math/Math.sol'; +import '@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol'; + `; + expect(updateImportPaths(source)).to.equal(expected); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js new file mode 100644 index 0000000..b5fd3c5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js @@ -0,0 +1,136 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const DummyImplementation = artifacts.require('DummyImplementation'); + +module.exports = function shouldBehaveLikeClone(createClone) { + before('deploy implementation', async function () { + this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('initializes the proxy', async function () { + const dummy = new DummyImplementation(this.proxy); + expect(await dummy.value()).to.be.bignumber.equal(value.toString()); + }); + + it('has expected balance', async function () { + expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString()); + }); + }; + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createClone(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100; + const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods + .initializeNonPayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createClone(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42; + const initializeData = new DummyImplementation('').contract.methods + .initializePayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/Clones.test.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/Clones.test.js new file mode 100644 index 0000000..947b2ed --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/Clones.test.js @@ -0,0 +1,61 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { computeCreate2Address } = require('../helpers/create2'); +const { expect } = require('chai'); + +const shouldBehaveLikeClone = require('./Clones.behaviour'); + +const Clones = artifacts.require('$Clones'); + +contract('Clones', function (accounts) { + const [deployer] = accounts; + + describe('clone', function () { + shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { + const factory = await Clones.new(); + const receipt = await factory.$clone(implementation); + const address = receipt.logs.find(({ event }) => event === 'return$clone').args.instance; + await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); + return { address }; + }); + }); + + describe('cloneDeterministic', function () { + shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + const receipt = await factory.$cloneDeterministic(implementation, salt); + const address = receipt.logs.find(({ event }) => event === 'return$cloneDeterministic').args.instance; + await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); + return { address }; + }); + + it('address already used', async function () { + const implementation = web3.utils.randomHex(20); + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + // deploy once + expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic'); + // deploy twice + await expectRevert(factory.$cloneDeterministic(implementation, salt), 'ERC1167: create2 failed'); + }); + + it('address prediction', async function () { + const implementation = web3.utils.randomHex(20); + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + const predicted = await factory.$predictDeterministicAddress(implementation, salt); + + const creationCode = [ + '0x3d602d80600a3d3981f3363d3d373d3d3d363d73', + implementation.replace(/0x/, '').toLowerCase(), + '5af43d82803e903d91602b57fd5bf3', + ].join(''); + + expect(computeCreate2Address(salt, creationCode, factory.address)).to.be.equal(predicted); + + expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic', { + instance: predicted, + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js new file mode 100644 index 0000000..22df960 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js @@ -0,0 +1,13 @@ +const shouldBehaveLikeProxy = require('../Proxy.behaviour'); + +const ERC1967Proxy = artifacts.require('ERC1967Proxy'); + +contract('ERC1967Proxy', function (accounts) { + const [proxyAdminOwner] = accounts; + + const createProxy = async function (implementation, _admin, initData, opts) { + return ERC1967Proxy.new(implementation, initData, opts); + }; + + shouldBehaveLikeProxy(createProxy, undefined, proxyAdminOwner); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js new file mode 100644 index 0000000..0867b93 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js @@ -0,0 +1,225 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { getSlot, ImplementationSlot } = require('../helpers/erc1967'); + +const { expect } = require('chai'); + +const DummyImplementation = artifacts.require('DummyImplementation'); + +module.exports = function shouldBehaveLikeProxy(createProxy, proxyAdminAddress, proxyCreator) { + it('cannot be initialized with a non-contract address', async function () { + const nonContractAddress = proxyCreator; + const initializeData = Buffer.from(''); + await expectRevert.unspecified( + createProxy(nonContractAddress, proxyAdminAddress, initializeData, { + from: proxyCreator, + }), + ); + }); + + before('deploy implementation', async function () { + this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('sets the implementation address', async function () { + const implementationSlot = await getSlot(this.proxy, ImplementationSlot); + const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40)); + expect(implementationAddress).to.be.equal(this.implementation); + }); + + it('initializes the proxy', async function () { + const dummy = new DummyImplementation(this.proxy); + expect(await dummy.value()).to.be.bignumber.equal(value.toString()); + }); + + it('has expected balance', async function () { + expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString()); + }); + }; + + describe('without initialization', function () { + const initializeData = Buffer.from(''); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ value: 0, balance: 0 }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + value, + }) + ).address; + }); + + assertProxyInitialization({ value: 0, balance: value }); + }); + }); + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified( + createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator, value }), + ); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100; + const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + value, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods + .initializeNonPayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified( + createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator, value }), + ); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42; + const initializeData = new DummyImplementation('').contract.methods + .initializePayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + value, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + + describe('reverting initialization', function () { + const initializeData = new DummyImplementation('').contract.methods.reverts().encodeABI(); + + it('reverts', async function () { + await expectRevert( + createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator }), + 'DummyImplementation reverted', + ); + }); + }); + }); +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js new file mode 100644 index 0000000..968f00b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js @@ -0,0 +1,139 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { getSlot, BeaconSlot } = require('../../helpers/erc1967'); + +const { expect } = require('chai'); + +const UpgradeableBeacon = artifacts.require('UpgradeableBeacon'); +const BeaconProxy = artifacts.require('BeaconProxy'); +const DummyImplementation = artifacts.require('DummyImplementation'); +const DummyImplementationV2 = artifacts.require('DummyImplementationV2'); +const BadBeaconNoImpl = artifacts.require('BadBeaconNoImpl'); +const BadBeaconNotContract = artifacts.require('BadBeaconNotContract'); + +contract('BeaconProxy', function (accounts) { + const [anotherAccount] = accounts; + + describe('bad beacon is not accepted', async function () { + it('non-contract beacon', async function () { + await expectRevert(BeaconProxy.new(anotherAccount, '0x'), 'ERC1967: new beacon is not a contract'); + }); + + it('non-compliant beacon', async function () { + const beacon = await BadBeaconNoImpl.new(); + await expectRevert.unspecified(BeaconProxy.new(beacon.address, '0x')); + }); + + it('non-contract implementation', async function () { + const beacon = await BadBeaconNotContract.new(); + await expectRevert(BeaconProxy.new(beacon.address, '0x'), 'ERC1967: beacon implementation is not a contract'); + }); + }); + + before('deploy implementation', async function () { + this.implementationV0 = await DummyImplementation.new(); + this.implementationV1 = await DummyImplementationV2.new(); + }); + + describe('initialization', function () { + before(function () { + this.assertInitialized = async ({ value, balance }) => { + const beaconSlot = await getSlot(this.proxy, BeaconSlot); + const beaconAddress = web3.utils.toChecksumAddress(beaconSlot.substr(-40)); + expect(beaconAddress).to.equal(this.beacon.address); + + const dummy = new DummyImplementation(this.proxy.address); + expect(await dummy.value()).to.bignumber.eq(value); + + expect(await web3.eth.getBalance(this.proxy.address)).to.bignumber.eq(balance); + }; + }); + + beforeEach('deploy beacon', async function () { + this.beacon = await UpgradeableBeacon.new(this.implementationV0.address); + }); + + it('no initialization', async function () { + const data = Buffer.from(''); + const balance = '10'; + this.proxy = await BeaconProxy.new(this.beacon.address, data, { value: balance }); + await this.assertInitialized({ value: '0', balance }); + }); + + it('non-payable initialization', async function () { + const value = '55'; + const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); + this.proxy = await BeaconProxy.new(this.beacon.address, data); + await this.assertInitialized({ value, balance: '0' }); + }); + + it('payable initialization', async function () { + const value = '55'; + const data = this.implementationV0.contract.methods.initializePayableWithValue(value).encodeABI(); + const balance = '100'; + this.proxy = await BeaconProxy.new(this.beacon.address, data, { value: balance }); + await this.assertInitialized({ value, balance }); + }); + + it('reverting initialization', async function () { + const data = this.implementationV0.contract.methods.reverts().encodeABI(); + await expectRevert(BeaconProxy.new(this.beacon.address, data), 'DummyImplementation reverted'); + }); + }); + + it('upgrade a proxy by upgrading its beacon', async function () { + const beacon = await UpgradeableBeacon.new(this.implementationV0.address); + + const value = '10'; + const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); + const proxy = await BeaconProxy.new(beacon.address, data); + + const dummy = new DummyImplementation(proxy.address); + + // test initial values + expect(await dummy.value()).to.bignumber.eq(value); + + // test initial version + expect(await dummy.version()).to.eq('V1'); + + // upgrade beacon + await beacon.upgradeTo(this.implementationV1.address); + + // test upgraded version + expect(await dummy.version()).to.eq('V2'); + }); + + it('upgrade 2 proxies by upgrading shared beacon', async function () { + const value1 = '10'; + const value2 = '42'; + + const beacon = await UpgradeableBeacon.new(this.implementationV0.address); + + const proxy1InitializeData = this.implementationV0.contract.methods + .initializeNonPayableWithValue(value1) + .encodeABI(); + const proxy1 = await BeaconProxy.new(beacon.address, proxy1InitializeData); + + const proxy2InitializeData = this.implementationV0.contract.methods + .initializeNonPayableWithValue(value2) + .encodeABI(); + const proxy2 = await BeaconProxy.new(beacon.address, proxy2InitializeData); + + const dummy1 = new DummyImplementation(proxy1.address); + const dummy2 = new DummyImplementation(proxy2.address); + + // test initial values + expect(await dummy1.value()).to.bignumber.eq(value1); + expect(await dummy2.value()).to.bignumber.eq(value2); + + // test initial version + expect(await dummy1.version()).to.eq('V1'); + expect(await dummy2.version()).to.eq('V1'); + + // upgrade beacon + await beacon.upgradeTo(this.implementationV1.address); + + // test upgraded version + expect(await dummy1.version()).to.eq('V2'); + expect(await dummy2.version()).to.eq('V2'); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js new file mode 100644 index 0000000..d65f3e0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js @@ -0,0 +1,44 @@ +const { expectRevert, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const UpgradeableBeacon = artifacts.require('UpgradeableBeacon'); +const Implementation1 = artifacts.require('Implementation1'); +const Implementation2 = artifacts.require('Implementation2'); + +contract('UpgradeableBeacon', function (accounts) { + const [owner, other] = accounts; + + it('cannot be created with non-contract implementation', async function () { + await expectRevert(UpgradeableBeacon.new(accounts[0]), 'UpgradeableBeacon: implementation is not a contract'); + }); + + context('once deployed', async function () { + beforeEach('deploying beacon', async function () { + this.v1 = await Implementation1.new(); + this.beacon = await UpgradeableBeacon.new(this.v1.address, { from: owner }); + }); + + it('returns implementation', async function () { + expect(await this.beacon.implementation()).to.equal(this.v1.address); + }); + + it('can be upgraded by the owner', async function () { + const v2 = await Implementation2.new(); + const receipt = await this.beacon.upgradeTo(v2.address, { from: owner }); + expectEvent(receipt, 'Upgraded', { implementation: v2.address }); + expect(await this.beacon.implementation()).to.equal(v2.address); + }); + + it('cannot be upgraded to a non-contract', async function () { + await expectRevert( + this.beacon.upgradeTo(other, { from: owner }), + 'UpgradeableBeacon: implementation is not a contract', + ); + }); + + it('cannot be upgraded by other account', async function () { + const v2 = await Implementation2.new(); + await expectRevert(this.beacon.upgradeTo(v2.address, { from: other }), 'Ownable: caller is not the owner'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js new file mode 100644 index 0000000..811dc56 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js @@ -0,0 +1,125 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ImplV1 = artifacts.require('DummyImplementation'); +const ImplV2 = artifacts.require('DummyImplementationV2'); +const ProxyAdmin = artifacts.require('ProxyAdmin'); +const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy'); + +contract('ProxyAdmin', function (accounts) { + const [proxyAdminOwner, newAdmin, anotherAccount] = accounts; + + before('set implementations', async function () { + this.implementationV1 = await ImplV1.new(); + this.implementationV2 = await ImplV2.new(); + }); + + beforeEach(async function () { + const initializeData = Buffer.from(''); + this.proxyAdmin = await ProxyAdmin.new({ from: proxyAdminOwner }); + this.proxy = await TransparentUpgradeableProxy.new( + this.implementationV1.address, + this.proxyAdmin.address, + initializeData, + { from: proxyAdminOwner }, + ); + }); + + it('has an owner', async function () { + expect(await this.proxyAdmin.owner()).to.equal(proxyAdminOwner); + }); + + describe('#getProxyAdmin', function () { + it('returns proxyAdmin as admin of the proxy', async function () { + const admin = await this.proxyAdmin.getProxyAdmin(this.proxy.address); + expect(admin).to.be.equal(this.proxyAdmin.address); + }); + + it('call to invalid proxy', async function () { + await expectRevert.unspecified(this.proxyAdmin.getProxyAdmin(this.implementationV1.address)); + }); + }); + + describe('#changeProxyAdmin', function () { + it('fails to change proxy admin if its not the proxy owner', async function () { + await expectRevert( + this.proxyAdmin.changeProxyAdmin(this.proxy.address, newAdmin, { from: anotherAccount }), + 'caller is not the owner', + ); + }); + + it('changes proxy admin', async function () { + await this.proxyAdmin.changeProxyAdmin(this.proxy.address, newAdmin, { from: proxyAdminOwner }); + expect(await this.proxy.admin.call({ from: newAdmin })).to.eq(newAdmin); + }); + }); + + describe('#getProxyImplementation', function () { + it('returns proxy implementation address', async function () { + const implementationAddress = await this.proxyAdmin.getProxyImplementation(this.proxy.address); + expect(implementationAddress).to.be.equal(this.implementationV1.address); + }); + + it('call to invalid proxy', async function () { + await expectRevert.unspecified(this.proxyAdmin.getProxyImplementation(this.implementationV1.address)); + }); + }); + + describe('#upgrade', function () { + context('with unauthorized account', function () { + it('fails to upgrade', async function () { + await expectRevert( + this.proxyAdmin.upgrade(this.proxy.address, this.implementationV2.address, { from: anotherAccount }), + 'caller is not the owner', + ); + }); + }); + + context('with authorized account', function () { + it('upgrades implementation', async function () { + await this.proxyAdmin.upgrade(this.proxy.address, this.implementationV2.address, { from: proxyAdminOwner }); + const implementationAddress = await this.proxyAdmin.getProxyImplementation(this.proxy.address); + expect(implementationAddress).to.be.equal(this.implementationV2.address); + }); + }); + }); + + describe('#upgradeAndCall', function () { + context('with unauthorized account', function () { + it('fails to upgrade', async function () { + const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI(); + await expectRevert( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: anotherAccount, + }), + 'caller is not the owner', + ); + }); + }); + + context('with authorized account', function () { + context('with invalid callData', function () { + it('fails to upgrade', async function () { + const callData = '0x12345678'; + await expectRevert.unspecified( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: proxyAdminOwner, + }), + ); + }); + }); + + context('with valid callData', function () { + it('upgrades implementation', async function () { + const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI(); + await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: proxyAdminOwner, + }); + const implementationAddress = await this.proxyAdmin.getProxyImplementation(this.proxy.address); + expect(implementationAddress).to.be.equal(this.implementationV2.address); + }); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js new file mode 100644 index 0000000..3a10357 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -0,0 +1,435 @@ +const { BN, expectRevert, expectEvent, constants } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { getSlot, ImplementationSlot, AdminSlot } = require('../../helpers/erc1967'); + +const { expect } = require('chai'); + +const Proxy = artifacts.require('Proxy'); +const Implementation1 = artifacts.require('Implementation1'); +const Implementation2 = artifacts.require('Implementation2'); +const Implementation3 = artifacts.require('Implementation3'); +const Implementation4 = artifacts.require('Implementation4'); +const MigratableMockV1 = artifacts.require('MigratableMockV1'); +const MigratableMockV2 = artifacts.require('MigratableMockV2'); +const MigratableMockV3 = artifacts.require('MigratableMockV3'); +const InitializableMock = artifacts.require('InitializableMock'); +const DummyImplementation = artifacts.require('DummyImplementation'); +const ClashingImplementation = artifacts.require('ClashingImplementation'); + +module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProxy, accounts) { + const [proxyAdminAddress, proxyAdminOwner, anotherAccount] = accounts; + + before(async function () { + this.implementationV0 = (await DummyImplementation.new()).address; + this.implementationV1 = (await DummyImplementation.new()).address; + }); + + beforeEach(async function () { + const initializeData = Buffer.from(''); + this.proxy = await createProxy(this.implementationV0, proxyAdminAddress, initializeData, { + from: proxyAdminOwner, + }); + this.proxyAddress = this.proxy.address; + }); + + describe('implementation', function () { + it('returns the current implementation address', async function () { + const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + + expect(implementation).to.be.equal(this.implementationV0); + }); + + it('delegates to the implementation', async function () { + const dummy = new DummyImplementation(this.proxyAddress); + const value = await dummy.get(); + + expect(value).to.equal(true); + }); + }); + + describe('upgradeTo', function () { + describe('when the sender is the admin', function () { + const from = proxyAdminAddress; + + describe('when the given implementation is different from the current one', function () { + it('upgrades to the requested implementation', async function () { + await this.proxy.upgradeTo(this.implementationV1, { from }); + + const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.implementationV1); + }); + + it('emits an event', async function () { + expectEvent(await this.proxy.upgradeTo(this.implementationV1, { from }), 'Upgraded', { + implementation: this.implementationV1, + }); + }); + }); + + describe('when the given implementation is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.proxy.upgradeTo(ZERO_ADDRESS, { from }), + 'ERC1967: new implementation is not a contract', + ); + }); + }); + }); + + describe('when the sender is not the admin', function () { + const from = anotherAccount; + + it('reverts', async function () { + await expectRevert.unspecified(this.proxy.upgradeTo(this.implementationV1, { from })); + }); + }); + }); + + describe('upgradeToAndCall', function () { + describe('without migrations', function () { + beforeEach(async function () { + this.behavior = await InitializableMock.new(); + }); + + describe('when the call does not fail', function () { + const initializeData = new InitializableMock('').contract.methods['initializeWithX(uint256)'](42).encodeABI(); + + describe('when the sender is the admin', function () { + const from = proxyAdminAddress; + const value = 1e5; + + beforeEach(async function () { + this.receipt = await this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from, value }); + }); + + it('upgrades to the requested implementation', async function () { + const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.behavior.address); + }); + + it('emits an event', function () { + expectEvent(this.receipt, 'Upgraded', { implementation: this.behavior.address }); + }); + + it('calls the initializer function', async function () { + const migratable = new InitializableMock(this.proxyAddress); + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + }); + + it('sends given value to the proxy', async function () { + const balance = await web3.eth.getBalance(this.proxyAddress); + expect(balance.toString()).to.be.bignumber.equal(value.toString()); + }); + + it.skip('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); + expect(parseInt(storedValue)).to.eq(42); + }); + }); + + describe('when the sender is not the admin', function () { + it('reverts', async function () { + await expectRevert.unspecified( + this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from: anotherAccount }), + ); + }); + }); + }); + + describe('when the call does fail', function () { + const initializeData = new InitializableMock('').contract.methods.fail().encodeABI(); + + it('reverts', async function () { + await expectRevert.unspecified( + this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from: proxyAdminAddress }), + ); + }); + }); + }); + + describe('with migrations', function () { + describe('when the sender is the admin', function () { + const from = proxyAdminAddress; + const value = 1e5; + + describe('when upgrading to V1', function () { + const v1MigrationData = new MigratableMockV1('').contract.methods.initialize(42).encodeABI(); + + beforeEach(async function () { + this.behaviorV1 = await MigratableMockV1.new(); + this.balancePreviousV1 = new BN(await web3.eth.getBalance(this.proxyAddress)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV1.address, v1MigrationData, { from, value }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.behaviorV1.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV1.address }); + }); + + it("calls the 'initialize' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV1(this.proxyAddress); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + + const balance = await web3.eth.getBalance(this.proxyAddress); + expect(new BN(balance)).to.be.bignumber.equal(this.balancePreviousV1.addn(value)); + }); + + describe('when upgrading to V2', function () { + const v2MigrationData = new MigratableMockV2('').contract.methods.migrate(10, 42).encodeABI(); + + beforeEach(async function () { + this.behaviorV2 = await MigratableMockV2.new(); + this.balancePreviousV2 = new BN(await web3.eth.getBalance(this.proxyAddress)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV2.address, v2MigrationData, { + from, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.behaviorV2.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV2.address }); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV2(this.proxyAddress); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('10'); + + const y = await migratable.y(); + expect(y).to.be.bignumber.equal('42'); + + const balance = new BN(await web3.eth.getBalance(this.proxyAddress)); + expect(balance).to.be.bignumber.equal(this.balancePreviousV2.addn(value)); + }); + + describe('when upgrading to V3', function () { + const v3MigrationData = new MigratableMockV3('').contract.methods['migrate()']().encodeABI(); + + beforeEach(async function () { + this.behaviorV3 = await MigratableMockV3.new(); + this.balancePreviousV3 = new BN(await web3.eth.getBalance(this.proxyAddress)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV3.address, v3MigrationData, { + from, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await this.proxy.implementation.call({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.behaviorV3.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV3.address }); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV3(this.proxyAddress); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + + const y = await migratable.y(); + expect(y).to.be.bignumber.equal('10'); + + const balance = new BN(await web3.eth.getBalance(this.proxyAddress)); + expect(balance).to.be.bignumber.equal(this.balancePreviousV3.addn(value)); + }); + }); + }); + }); + }); + + describe('when the sender is not the admin', function () { + const from = anotherAccount; + + it('reverts', async function () { + const behaviorV1 = await MigratableMockV1.new(); + const v1MigrationData = new MigratableMockV1('').contract.methods.initialize(42).encodeABI(); + await expectRevert.unspecified(this.proxy.upgradeToAndCall(behaviorV1.address, v1MigrationData, { from })); + }); + }); + }); + }); + + describe('changeAdmin', function () { + describe('when the new proposed admin is not the zero address', function () { + const newAdmin = anotherAccount; + + describe('when the sender is the admin', function () { + beforeEach('transferring', async function () { + this.receipt = await this.proxy.changeAdmin(newAdmin, { from: proxyAdminAddress }); + }); + + it('assigns new proxy admin', async function () { + const newProxyAdmin = await this.proxy.admin.call({ from: newAdmin }); + expect(newProxyAdmin).to.be.equal(anotherAccount); + }); + + it('emits an event', function () { + expectEvent(this.receipt, 'AdminChanged', { + previousAdmin: proxyAdminAddress, + newAdmin: newAdmin, + }); + }); + }); + + describe('when the sender is not the admin', function () { + it('reverts', async function () { + await expectRevert.unspecified(this.proxy.changeAdmin(newAdmin, { from: anotherAccount })); + }); + }); + }); + + describe('when the new proposed admin is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.proxy.changeAdmin(ZERO_ADDRESS, { from: proxyAdminAddress }), + 'ERC1967: new admin is the zero address', + ); + }); + }); + }); + + describe('storage', function () { + it('should store the implementation address in specified location', async function () { + const implementationSlot = await getSlot(this.proxy, ImplementationSlot); + const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40)); + expect(implementationAddress).to.be.equal(this.implementationV0); + }); + + it('should store the admin proxy in specified location', async function () { + const proxyAdminSlot = await getSlot(this.proxy, AdminSlot); + const proxyAdminAddress = web3.utils.toChecksumAddress(proxyAdminSlot.substr(-40)); + expect(proxyAdminAddress).to.be.equal(proxyAdminAddress); + }); + }); + + describe('transparent proxy', function () { + beforeEach('creating proxy', async function () { + const initializeData = Buffer.from(''); + this.impl = await ClashingImplementation.new(); + this.proxy = await createProxy(this.impl.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + this.clashing = new ClashingImplementation(this.proxy.address); + }); + + it('proxy admin cannot call delegated functions', async function () { + await expectRevert( + this.clashing.delegatedFunction({ from: proxyAdminAddress }), + 'TransparentUpgradeableProxy: admin cannot fallback to proxy target', + ); + }); + + 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 }); + 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 }); + 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'); + }); + }); + }); + + describe('regression', () => { + const initializeData = Buffer.from(''); + + it('should add new function', async () => { + const instance1 = await Implementation1.new(); + const proxy = await createProxy(instance1.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const proxyInstance1 = new Implementation1(proxy.address); + await proxyInstance1.setValue(42); + + const instance2 = await Implementation2.new(); + await proxy.upgradeTo(instance2.address, { from: proxyAdminAddress }); + + const proxyInstance2 = new Implementation2(proxy.address); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('42'); + }); + + it('should remove function', async () => { + const instance2 = await Implementation2.new(); + const proxy = await createProxy(instance2.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const proxyInstance2 = new Implementation2(proxy.address); + await proxyInstance2.setValue(42); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('42'); + + const instance1 = await Implementation1.new(); + await proxy.upgradeTo(instance1.address, { from: proxyAdminAddress }); + + const proxyInstance1 = new Implementation2(proxy.address); + await expectRevert.unspecified(proxyInstance1.getValue()); + }); + + it('should change function signature', async () => { + const instance1 = await Implementation1.new(); + const proxy = await createProxy(instance1.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const proxyInstance1 = new Implementation1(proxy.address); + await proxyInstance1.setValue(42); + + const instance3 = await Implementation3.new(); + await proxy.upgradeTo(instance3.address, { from: proxyAdminAddress }); + const proxyInstance3 = new Implementation3(proxy.address); + + const res = await proxyInstance3.getValue(8); + expect(res.toString()).to.eq('50'); + }); + + it('should add fallback function', async () => { + const initializeData = Buffer.from(''); + const instance1 = await Implementation1.new(); + const proxy = await createProxy(instance1.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const instance4 = await Implementation4.new(); + await proxy.upgradeTo(instance4.address, { from: proxyAdminAddress }); + const proxyInstance4 = new Implementation4(proxy.address); + + const data = '0x'; + await web3.eth.sendTransaction({ to: proxy.address, from: anotherAccount, data }); + + const res = await proxyInstance4.getValue(); + expect(res.toString()).to.eq('1'); + }); + + it('should remove fallback function', async () => { + const instance4 = await Implementation4.new(); + const proxy = await createProxy(instance4.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const instance2 = await Implementation2.new(); + await proxy.upgradeTo(instance2.address, { from: proxyAdminAddress }); + + const data = '0x'; + await expectRevert.unspecified(web3.eth.sendTransaction({ to: proxy.address, from: anotherAccount, data })); + + const proxyInstance2 = new Implementation2(proxy.address); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('0'); + }); + }); +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js new file mode 100644 index 0000000..86dd55d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js @@ -0,0 +1,15 @@ +const shouldBehaveLikeProxy = require('../Proxy.behaviour'); +const shouldBehaveLikeTransparentUpgradeableProxy = require('./TransparentUpgradeableProxy.behaviour'); + +const TransparentUpgradeableProxy = artifacts.require('TransparentUpgradeableProxy'); + +contract('TransparentUpgradeableProxy', function (accounts) { + const [proxyAdminAddress, proxyAdminOwner] = accounts; + + const createProxy = async function (logic, admin, initData, opts) { + return TransparentUpgradeableProxy.new(logic, admin, initData, opts); + }; + + shouldBehaveLikeProxy(createProxy, proxyAdminAddress, proxyAdminOwner); + shouldBehaveLikeTransparentUpgradeableProxy(createProxy, accounts); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js new file mode 100644 index 0000000..39c820b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js @@ -0,0 +1,218 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const InitializableMock = artifacts.require('InitializableMock'); +const ConstructorInitializableMock = artifacts.require('ConstructorInitializableMock'); +const ChildConstructorInitializableMock = artifacts.require('ChildConstructorInitializableMock'); +const ReinitializerMock = artifacts.require('ReinitializerMock'); +const SampleChild = artifacts.require('SampleChild'); +const DisableBad1 = artifacts.require('DisableBad1'); +const DisableBad2 = artifacts.require('DisableBad2'); +const DisableOk = artifacts.require('DisableOk'); + +contract('Initializable', function () { + describe('basic testing without inheritance', function () { + beforeEach('deploying', async function () { + this.contract = await InitializableMock.new(); + }); + + describe('before initialize', function () { + it('initializer has not run', async function () { + expect(await this.contract.initializerRan()).to.equal(false); + }); + + it('_initializing returns false before initialization', async function () { + expect(await this.contract.isInitializing()).to.equal(false); + }); + }); + + describe('after initialize', function () { + beforeEach('initializing', async function () { + await this.contract.initialize(); + }); + + it('initializer has run', async function () { + expect(await this.contract.initializerRan()).to.equal(true); + }); + + it('_initializing returns false after initialization', async function () { + expect(await this.contract.isInitializing()).to.equal(false); + }); + + it('initializer does not run again', async function () { + await expectRevert(this.contract.initialize(), 'Initializable: contract is already initialized'); + }); + }); + + describe('nested under an initializer', function () { + it('initializer modifier reverts', async function () { + await expectRevert(this.contract.initializerNested(), 'Initializable: contract is already initialized'); + }); + + it('onlyInitializing modifier succeeds', async function () { + await this.contract.onlyInitializingNested(); + expect(await this.contract.onlyInitializingRan()).to.equal(true); + }); + }); + + it('cannot call onlyInitializable function outside the scope of an initializable function', async function () { + await expectRevert(this.contract.initializeOnlyInitializing(), 'Initializable: contract is not initializing'); + }); + }); + + it('nested initializer can run during construction', async function () { + const contract2 = await ConstructorInitializableMock.new(); + expect(await contract2.initializerRan()).to.equal(true); + expect(await contract2.onlyInitializingRan()).to.equal(true); + }); + + it('multiple constructor levels can be initializers', async function () { + const contract2 = await ChildConstructorInitializableMock.new(); + expect(await contract2.initializerRan()).to.equal(true); + expect(await contract2.childInitializerRan()).to.equal(true); + expect(await contract2.onlyInitializingRan()).to.equal(true); + }); + + describe('reinitialization', function () { + beforeEach('deploying', async function () { + this.contract = await ReinitializerMock.new(); + }); + + it('can reinitialize', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.initialize(); + expect(await this.contract.counter()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(2); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + await this.contract.reinitialize(3); + expect(await this.contract.counter()).to.be.bignumber.equal('3'); + }); + + it('can jump multiple steps', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.initialize(); + expect(await this.contract.counter()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(128); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + }); + + it('cannot nest reinitializers', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await expectRevert(this.contract.nestedReinitialize(2, 2), 'Initializable: contract is already initialized'); + await expectRevert(this.contract.nestedReinitialize(2, 3), 'Initializable: contract is already initialized'); + await expectRevert(this.contract.nestedReinitialize(3, 2), 'Initializable: contract is already initialized'); + }); + + it('can chain reinitializers', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.chainReinitialize(2, 3); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + }); + + it('_getInitializedVersion returns right version', async function () { + await this.contract.initialize(); + expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(12); + expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('12'); + }); + + describe('contract locking', function () { + it('prevents initialization', async function () { + await this.contract.disableInitializers(); + await expectRevert(this.contract.initialize(), 'Initializable: contract is already initialized'); + }); + + it('prevents re-initialization', async function () { + await this.contract.disableInitializers(); + await expectRevert(this.contract.reinitialize(255), 'Initializable: contract is already initialized'); + }); + + it('can lock contract after initialization', async function () { + await this.contract.initialize(); + await this.contract.disableInitializers(); + await expectRevert(this.contract.reinitialize(255), 'Initializable: contract is already initialized'); + }); + }); + }); + + describe('events', function () { + it('constructor initialization emits event', async function () { + const contract = await ConstructorInitializableMock.new(); + + await expectEvent.inTransaction(contract.transactionHash, contract, 'Initialized', { version: '1' }); + }); + + it('initialization emits event', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.initialize(); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1); + expectEvent(receipt, 'Initialized', { version: '1' }); + }); + + it('reinitialization emits event', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.reinitialize(128); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1); + expectEvent(receipt, 'Initialized', { version: '128' }); + }); + + it('chained reinitialization emits multiple events', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.chainReinitialize(2, 3); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(2); + expectEvent(receipt, 'Initialized', { version: '2' }); + expectEvent(receipt, 'Initialized', { version: '3' }); + }); + }); + + describe('complex testing with inheritance', function () { + const mother = '12'; + const gramps = '56'; + const father = '34'; + const child = '78'; + + beforeEach('deploying', async function () { + this.contract = await SampleChild.new(); + }); + + beforeEach('initializing', async function () { + await this.contract.initialize(mother, gramps, father, child); + }); + + it('initializes human', async function () { + expect(await this.contract.isHuman()).to.be.equal(true); + }); + + it('initializes mother', async function () { + expect(await this.contract.mother()).to.be.bignumber.equal(mother); + }); + + it('initializes gramps', async function () { + expect(await this.contract.gramps()).to.be.bignumber.equal(gramps); + }); + + it('initializes father', async function () { + expect(await this.contract.father()).to.be.bignumber.equal(father); + }); + + it('initializes child', async function () { + expect(await this.contract.child()).to.be.bignumber.equal(child); + }); + }); + + describe('disabling initialization', function () { + it('old and new patterns in bad sequence', async function () { + await expectRevert(DisableBad1.new(), 'Initializable: contract is already initialized'); + await expectRevert(DisableBad2.new(), 'Initializable: contract is initializing'); + }); + + it('old and new patterns in good sequence', async function () { + const ok = await DisableOk.new(); + await expectEvent.inConstruction(ok, 'Initialized', { version: '1' }); + await expectEvent.inConstruction(ok, 'Initialized', { version: '255' }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js new file mode 100644 index 0000000..b0c1b3f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js @@ -0,0 +1,85 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { web3 } = require('@openzeppelin/test-helpers/src/setup'); +const { getSlot, ImplementationSlot } = require('../../helpers/erc1967'); + +const ERC1967Proxy = artifacts.require('ERC1967Proxy'); +const UUPSUpgradeableMock = artifacts.require('UUPSUpgradeableMock'); +const UUPSUpgradeableUnsafeMock = artifacts.require('UUPSUpgradeableUnsafeMock'); +const UUPSUpgradeableLegacyMock = artifacts.require('UUPSUpgradeableLegacyMock'); +const NonUpgradeableMock = artifacts.require('NonUpgradeableMock'); + +contract('UUPSUpgradeable', function () { + before(async function () { + this.implInitial = await UUPSUpgradeableMock.new(); + this.implUpgradeOk = await UUPSUpgradeableMock.new(); + this.implUpgradeUnsafe = await UUPSUpgradeableUnsafeMock.new(); + this.implUpgradeNonUUPS = await NonUpgradeableMock.new(); + }); + + beforeEach(async function () { + const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x'); + this.instance = await UUPSUpgradeableMock.at(address); + }); + + it('upgrade to upgradeable implementation', async function () { + const { receipt } = await this.instance.upgradeTo(this.implUpgradeOk.address); + expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address }); + }); + + it('upgrade to upgradeable implementation with call', async function () { + expect(await this.instance.current()).to.be.bignumber.equal('0'); + + const { receipt } = await this.instance.upgradeToAndCall( + this.implUpgradeOk.address, + this.implUpgradeOk.contract.methods.increment().encodeABI(), + ); + expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address }); + + expect(await this.instance.current()).to.be.bignumber.equal('1'); + }); + + it('upgrade to and unsafe upgradeable implementation', async function () { + const { receipt } = await this.instance.upgradeTo(this.implUpgradeUnsafe.address); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeUnsafe.address }); + }); + + // delegate to a non existing upgradeTo function causes a low level revert + it('reject upgrade to non uups implementation', async function () { + await expectRevert( + this.instance.upgradeTo(this.implUpgradeNonUUPS.address), + 'ERC1967Upgrade: new implementation is not UUPS', + ); + }); + + it('reject proxy address as implementation', async function () { + const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x'); + const otherInstance = await UUPSUpgradeableMock.at(address); + + await expectRevert( + this.instance.upgradeTo(otherInstance.address), + 'ERC1967Upgrade: new implementation is not UUPS', + ); + }); + + it('can upgrade from legacy implementations', async function () { + const legacyImpl = await UUPSUpgradeableLegacyMock.new(); + const legacyInstance = await ERC1967Proxy.new(legacyImpl.address, '0x').then(({ address }) => + UUPSUpgradeableLegacyMock.at(address), + ); + + const receipt = await legacyInstance.upgradeTo(this.implInitial.address); + + const UpgradedEvents = receipt.logs.filter( + ({ address, event }) => address === legacyInstance.address && event === 'Upgraded', + ); + expect(UpgradedEvents.length).to.be.equal(1); + + expectEvent(receipt, 'Upgraded', { implementation: this.implInitial.address }); + + const implementationSlot = await getSlot(legacyInstance, ImplementationSlot); + const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40)); + expect(implementationAddress).to.be.equal(this.implInitial.address); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/security/Pausable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/security/Pausable.test.js new file mode 100644 index 0000000..5cca11e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/security/Pausable.test.js @@ -0,0 +1,85 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const PausableMock = artifacts.require('PausableMock'); + +contract('Pausable', function (accounts) { + const [pauser] = accounts; + + beforeEach(async function () { + this.pausable = await PausableMock.new(); + }); + + context('when unpaused', function () { + beforeEach(async function () { + expect(await this.pausable.paused()).to.equal(false); + }); + + it('can perform normal process in non-pause', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('cannot take drastic measure in non-pause', async function () { + await expectRevert(this.pausable.drasticMeasure(), 'Pausable: not paused'); + expect(await this.pausable.drasticMeasureTaken()).to.equal(false); + }); + + context('when paused', function () { + beforeEach(async function () { + this.receipt = await this.pausable.pause({ from: pauser }); + }); + + it('emits a Paused event', function () { + expectEvent(this.receipt, 'Paused', { account: pauser }); + }); + + it('cannot perform normal process in pause', async function () { + await expectRevert(this.pausable.normalProcess(), 'Pausable: paused'); + }); + + it('can take a drastic measure in a pause', async function () { + await this.pausable.drasticMeasure(); + expect(await this.pausable.drasticMeasureTaken()).to.equal(true); + }); + + it('reverts when re-pausing', async function () { + await expectRevert(this.pausable.pause(), 'Pausable: paused'); + }); + + describe('unpausing', function () { + it('is unpausable by the pauser', async function () { + await this.pausable.unpause(); + expect(await this.pausable.paused()).to.equal(false); + }); + + context('when unpaused', function () { + beforeEach(async function () { + this.receipt = await this.pausable.unpause({ from: pauser }); + }); + + it('emits an Unpaused event', function () { + expectEvent(this.receipt, 'Unpaused', { account: pauser }); + }); + + it('should resume allowing normal process', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('should prevent drastic measure', async function () { + await expectRevert(this.pausable.drasticMeasure(), 'Pausable: not paused'); + }); + + it('reverts when re-unpausing', async function () { + await expectRevert(this.pausable.unpause(), 'Pausable: not paused'); + }); + }); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/security/PullPayment.test.js b/lib/crytic/lib/openzeppelin-contracts/test/security/PullPayment.test.js new file mode 100644 index 0000000..5bf72bb --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/security/PullPayment.test.js @@ -0,0 +1,51 @@ +const { balance, ether } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const PullPaymentMock = artifacts.require('PullPaymentMock'); + +contract('PullPayment', function (accounts) { + const [payer, payee1, payee2] = accounts; + + const amount = ether('17'); + + beforeEach(async function () { + this.contract = await PullPaymentMock.new({ value: amount }); + }); + + describe('payments', function () { + it('can record an async payment correctly', async function () { + await this.contract.callTransfer(payee1, 100, { from: payer }); + expect(await this.contract.payments(payee1)).to.be.bignumber.equal('100'); + }); + + it('can add multiple balances on one account', async function () { + await this.contract.callTransfer(payee1, 200, { from: payer }); + await this.contract.callTransfer(payee1, 300, { from: payer }); + expect(await this.contract.payments(payee1)).to.be.bignumber.equal('500'); + }); + + it('can add balances on multiple accounts', async function () { + await this.contract.callTransfer(payee1, 200, { from: payer }); + await this.contract.callTransfer(payee2, 300, { from: payer }); + + expect(await this.contract.payments(payee1)).to.be.bignumber.equal('200'); + + expect(await this.contract.payments(payee2)).to.be.bignumber.equal('300'); + }); + }); + + describe('withdrawPayments', function () { + it('can withdraw payment', async function () { + const balanceTracker = await balance.tracker(payee1); + + await this.contract.callTransfer(payee1, amount, { from: payer }); + expect(await this.contract.payments(payee1)).to.be.bignumber.equal(amount); + + await this.contract.withdrawPayments(payee1); + + expect(await balanceTracker.delta()).to.be.bignumber.equal(amount); + expect(await this.contract.payments(payee1)).to.be.bignumber.equal('0'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/security/ReentrancyGuard.test.js b/lib/crytic/lib/openzeppelin-contracts/test/security/ReentrancyGuard.test.js new file mode 100644 index 0000000..1a80bc8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/security/ReentrancyGuard.test.js @@ -0,0 +1,43 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ReentrancyMock = artifacts.require('ReentrancyMock'); +const ReentrancyAttack = artifacts.require('ReentrancyAttack'); + +contract('ReentrancyGuard', function () { + beforeEach(async function () { + this.reentrancyMock = await ReentrancyMock.new(); + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('0'); + }); + + it('nonReentrant function can be called', async function () { + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('0'); + await this.reentrancyMock.callback(); + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('1'); + }); + + it('does not allow remote callback', async function () { + const attacker = await ReentrancyAttack.new(); + await expectRevert(this.reentrancyMock.countAndCall(attacker.address), 'ReentrancyAttack: failed call'); + }); + + it('_reentrancyGuardEntered should be true when guarded', async function () { + await this.reentrancyMock.guardedCheckEntered(); + }); + + it('_reentrancyGuardEntered should be false when unguarded', async function () { + await this.reentrancyMock.unguardedCheckNotEntered(); + }); + + // The following are more side-effects than intended behavior: + // I put them here as documentation, and to monitor any changes + // in the side-effects. + it('does not allow local recursion', async function () { + await expectRevert(this.reentrancyMock.countLocalRecursive(10), 'ReentrancyGuard: reentrant call'); + }); + + it('does not allow indirect local recursion', async function () { + await expectRevert(this.reentrancyMock.countThisRecursive(10), 'ReentrancyMock: failed call'); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js new file mode 100644 index 0000000..96d448a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js @@ -0,0 +1,767 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +const ERC1155ReceiverMock = artifacts.require('ERC1155ReceiverMock'); + +function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, multiTokenHolder, recipient, proxy]) { + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); + + const firstAmount = new BN(1000); + const secondAmount = new BN(2000); + + const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; + const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; + + describe('like an ERC1155', function () { + describe('balanceOf', function () { + it('reverts when queried about the zero address', async function () { + await expectRevert( + this.token.balanceOf(ZERO_ADDRESS, firstTokenId), + 'ERC1155: address zero is not a valid owner', + ); + }); + + context("when accounts don't own tokens", function () { + it('returns zero for given addresses', async function () { + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + }); + }); + + context('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstAmount, '0x', { + from: minter, + }); + await this.token.$_mint(secondTokenHolder, secondTokenId, secondAmount, '0x', { + from: minter, + }); + }); + + it('returns the amount of tokens owned by the given addresses', async function () { + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal(firstAmount); + + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal(secondAmount); + + expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('balanceOfBatch', function () { + it("reverts when input arrays don't match up", async function () { + await expectRevert( + this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder, secondTokenHolder], + [firstTokenId, secondTokenId, unknownTokenId], + ), + 'ERC1155: accounts and ids length mismatch', + ); + + await expectRevert( + this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder], + [firstTokenId, secondTokenId, unknownTokenId], + ), + 'ERC1155: accounts and ids length mismatch', + ); + }); + + it('reverts when one of the addresses is the zero address', async function () { + await expectRevert( + this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, ZERO_ADDRESS], + [firstTokenId, secondTokenId, unknownTokenId], + ), + 'ERC1155: address zero is not a valid owner', + ); + }); + + context("when accounts don't own tokens", function () { + it('returns zeros for each account', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [firstTokenId, secondTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal('0'); + expect(result[1]).to.be.a.bignumber.equal('0'); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + }); + + context('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstAmount, '0x', { + from: minter, + }); + await this.token.$_mint(secondTokenHolder, secondTokenId, secondAmount, '0x', { + from: minter, + }); + }); + + it('returns amounts owned by each account in order passed', async function () { + const result = await this.token.balanceOfBatch( + [secondTokenHolder, firstTokenHolder, firstTokenHolder], + [secondTokenId, firstTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal(secondAmount); + expect(result[1]).to.be.a.bignumber.equal(firstAmount); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + + it('returns multiple times the balance of the same address when asked', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [firstTokenId, secondTokenId, firstTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal(result[2]); + expect(result[0]).to.be.a.bignumber.equal(firstAmount); + expect(result[1]).to.be.a.bignumber.equal(secondAmount); + expect(result[2]).to.be.a.bignumber.equal(firstAmount); + }); + }); + }); + + describe('setApprovalForAll', function () { + let receipt; + beforeEach(async function () { + receipt = await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + }); + + it('sets approval status which can be queried via isApprovedForAll', async function () { + expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(true); + }); + + it('emits an ApprovalForAll log', function () { + expectEvent(receipt, 'ApprovalForAll', { account: multiTokenHolder, operator: proxy, approved: true }); + }); + + it('can unset approval for an operator', async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(false); + }); + + it('reverts if attempting to approve self as an operator', async function () { + await expectRevert( + this.token.setApprovalForAll(multiTokenHolder, true, { from: multiTokenHolder }), + 'ERC1155: setting approval status for self', + ); + }); + }); + + describe('safeTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstAmount, '0x', { + from: minter, + }); + await this.token.$_mint(multiTokenHolder, secondTokenId, secondAmount, '0x', { + from: minter, + }); + }); + + it('reverts when transferring more than balance', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount.addn(1), '0x', { + from: multiTokenHolder, + }), + 'ERC1155: insufficient balance for transfer', + ); + }); + + it('reverts when transferring to zero address', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, ZERO_ADDRESS, firstTokenId, firstAmount, '0x', { + from: multiTokenHolder, + }), + 'ERC1155: transfer to the zero address', + ); + }); + + function transferWasSuccessful({ operator, from, id, value }) { + it('debits transferred balance from sender', async function () { + const newBalance = await this.token.balanceOf(from, id); + expect(newBalance).to.be.a.bignumber.equal('0'); + }); + + it('credits transferred balance to receiver', async function () { + const newBalance = await this.token.balanceOf(this.toWhom, id); + expect(newBalance).to.be.a.bignumber.equal(value); + }); + + it('emits a TransferSingle log', function () { + expectEvent(this.transferLogs, 'TransferSingle', { + operator, + from, + to: this.toWhom, + id, + value, + }); + }); + } + + context('when called by the multiTokenHolder', async function () { + beforeEach(async function () { + this.toWhom = recipient; + this.transferLogs = await this.token.safeTransferFrom( + multiTokenHolder, + recipient, + firstTokenId, + firstAmount, + '0x', + { + from: multiTokenHolder, + }, + ); + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + }); + + it('preserves existing balances which are not transferred by multiTokenHolder', async function () { + const balance1 = await this.token.balanceOf(multiTokenHolder, secondTokenId); + expect(balance1).to.be.a.bignumber.equal(secondAmount); + + const balance2 = await this.token.balanceOf(recipient, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + + context('when called by an operator on behalf of the multiTokenHolder', function () { + context('when operator is not approved by multiTokenHolder', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount, '0x', { + from: proxy, + }), + 'ERC1155: caller is not token owner or approved', + ); + }); + }); + + context('when operator is approved by multiTokenHolder', function () { + beforeEach(async function () { + this.toWhom = recipient; + await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.transferLogs = await this.token.safeTransferFrom( + multiTokenHolder, + recipient, + firstTokenId, + firstAmount, + '0x', + { + from: proxy, + }, + ); + }); + + transferWasSuccessful.call(this, { + operator: proxy, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + }); + + it("preserves operator's balances not involved in the transfer", async function () { + const balance1 = await this.token.balanceOf(proxy, firstTokenId); + expect(balance1).to.be.a.bignumber.equal('0'); + + const balance2 = await this.token.balanceOf(proxy, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + }); + + context('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + false, + RECEIVER_BATCH_MAGIC_VALUE, + false, + ); + }); + + context('without data', function () { + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstAmount, + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + data: null, + }); + }); + }); + + context('with data', function () { + const data = '0xf00dd00d'; + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstAmount, + data, + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + data, + }); + }); + }); + }); + + context('to a receiver contract returning unexpected value', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new('0x00c0ffee', false, RECEIVER_BATCH_MAGIC_VALUE, false); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { + from: multiTokenHolder, + }), + 'ERC1155: ERC1155Receiver rejected tokens', + ); + }); + }); + + context('to a receiver contract that reverts', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + true, + RECEIVER_BATCH_MAGIC_VALUE, + false, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { + from: multiTokenHolder, + }), + 'ERC1155ReceiverMock: reverting on receive', + ); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + await expectRevert.unspecified( + this.token.safeTransferFrom(multiTokenHolder, invalidReceiver.address, firstTokenId, firstAmount, '0x', { + from: multiTokenHolder, + }), + ); + }); + }); + }); + + describe('safeBatchTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstAmount, '0x', { + from: minter, + }); + await this.token.$_mint(multiTokenHolder, secondTokenId, secondAmount, '0x', { + from: minter, + }); + }); + + it('reverts when transferring amount more than any of balances', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount.addn(1)], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: insufficient balance for transfer', + ); + }); + + it("reverts when ids array length doesn't match amounts array length", async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: ids and amounts length mismatch', + ); + + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: ids and amounts length mismatch', + ); + }); + + it('reverts when transferring to zero address', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + ZERO_ADDRESS, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: transfer to the zero address', + ); + }); + + function batchTransferWasSuccessful({ operator, from, ids, values }) { + it('debits transferred balances from sender', async function () { + const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(from), ids); + for (const newBalance of newBalances) { + expect(newBalance).to.be.a.bignumber.equal('0'); + } + }); + + it('credits transferred balances to receiver', async function () { + const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(this.toWhom), ids); + for (let i = 0; i < newBalances.length; i++) { + expect(newBalances[i]).to.be.a.bignumber.equal(values[i]); + } + }); + + it('emits a TransferBatch log', function () { + expectEvent(this.transferLogs, 'TransferBatch', { + operator, + from, + to: this.toWhom, + // ids, + // values, + }); + }); + } + + context('when called by the multiTokenHolder', async function () { + beforeEach(async function () { + this.toWhom = recipient; + this.transferLogs = await this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ); + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + }); + + context('when called by an operator on behalf of the multiTokenHolder', function () { + context('when operator is not approved by multiTokenHolder', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: proxy }, + ), + 'ERC1155: caller is not token owner or approved', + ); + }); + }); + + context('when operator is approved by multiTokenHolder', function () { + beforeEach(async function () { + this.toWhom = recipient; + await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.transferLogs = await this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: proxy }, + ); + }); + + batchTransferWasSuccessful.call(this, { + operator: proxy, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + + it("preserves operator's balances not involved in the transfer", async function () { + const balance1 = await this.token.balanceOf(proxy, firstTokenId); + expect(balance1).to.be.a.bignumber.equal('0'); + const balance2 = await this.token.balanceOf(proxy, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + }); + + context('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + false, + RECEIVER_BATCH_MAGIC_VALUE, + false, + ); + }); + + context('without data', function () { + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + + it('calls onERC1155BatchReceived', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstAmount, secondAmount], + data: null, + }); + }); + }); + + context('with data', function () { + const data = '0xf00dd00d'; + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + data, + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstAmount, secondAmount], + data, + }); + }); + }); + }); + + context('to a receiver contract returning unexpected value', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + false, + RECEIVER_SINGLE_MAGIC_VALUE, + false, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: ERC1155Receiver rejected tokens', + ); + }); + }); + + context('to a receiver contract that reverts', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + false, + RECEIVER_BATCH_MAGIC_VALUE, + true, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155ReceiverMock: reverting on batch receive', + ); + }); + }); + + context('to a receiver contract that reverts only on single transfers', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + true, + RECEIVER_BATCH_MAGIC_VALUE, + false, + ); + + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + + it('calls onERC1155BatchReceived', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstAmount, secondAmount], + data: null, + }); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + await expectRevert.unspecified( + this.token.safeBatchTransferFrom( + multiTokenHolder, + invalidReceiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + ); + }); + }); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155']); + }); +} + +module.exports = { + shouldBehaveLikeERC1155, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js new file mode 100644 index 0000000..ff432d3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js @@ -0,0 +1,235 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const { shouldBehaveLikeERC1155 } = require('./ERC1155.behavior'); +const ERC1155Mock = artifacts.require('$ERC1155'); + +contract('ERC1155', function (accounts) { + const [operator, tokenHolder, tokenBatchHolder, ...otherAccounts] = accounts; + + const initialURI = 'https://token-cdn-domain/{id}.json'; + + beforeEach(async function () { + this.token = await ERC1155Mock.new(initialURI); + }); + + shouldBehaveLikeERC1155(otherAccounts); + + describe('internal functions', function () { + const tokenId = new BN(1990); + const mintAmount = new BN(9001); + const burnAmount = new BN(3000); + + const tokenBatchIds = [new BN(2000), new BN(2010), new BN(2020)]; + const mintAmounts = [new BN(5000), new BN(10000), new BN(42195)]; + const burnAmounts = [new BN(5000), new BN(9001), new BN(195)]; + + const data = '0x12345678'; + + describe('_mint', function () { + it('reverts with a zero destination address', async function () { + await expectRevert( + this.token.$_mint(ZERO_ADDRESS, tokenId, mintAmount, data), + 'ERC1155: mint to the zero address', + ); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(tokenHolder, tokenId, mintAmount, data, { from: operator }); + }); + + it('emits a TransferSingle event', function () { + expectEvent(this.receipt, 'TransferSingle', { + operator, + from: ZERO_ADDRESS, + to: tokenHolder, + id: tokenId, + value: mintAmount, + }); + }); + + it('credits the minted amount of tokens', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintAmount); + }); + }); + }); + + describe('_mintBatch', function () { + it('reverts with a zero destination address', async function () { + await expectRevert( + this.token.$_mintBatch(ZERO_ADDRESS, tokenBatchIds, mintAmounts, data), + 'ERC1155: mint to the zero address', + ); + }); + + it('reverts if length of inputs do not match', async function () { + await expectRevert( + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts.slice(1), data), + 'ERC1155: ids and amounts length mismatch', + ); + + await expectRevert( + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds.slice(1), mintAmounts, data), + 'ERC1155: ids and amounts length mismatch', + ); + }); + + context('with minted batch of tokens', function () { + beforeEach(async function () { + this.receipt = await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts, data, { + from: operator, + }); + }); + + it('emits a TransferBatch event', function () { + expectEvent(this.receipt, 'TransferBatch', { + operator, + from: ZERO_ADDRESS, + to: tokenBatchHolder, + }); + }); + + it('credits the minted batch of tokens', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds, + ); + + for (let i = 0; i < holderBatchBalances.length; i++) { + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintAmounts[i]); + } + }); + }); + }); + + describe('_burn', function () { + it("reverts when burning the zero account's tokens", async function () { + await expectRevert(this.token.$_burn(ZERO_ADDRESS, tokenId, mintAmount), 'ERC1155: burn from the zero address'); + }); + + it('reverts when burning a non-existent token id', async function () { + await expectRevert(this.token.$_burn(tokenHolder, tokenId, mintAmount), 'ERC1155: burn amount exceeds balance'); + }); + + it('reverts when burning more than available tokens', async function () { + await this.token.$_mint(tokenHolder, tokenId, mintAmount, data, { from: operator }); + + await expectRevert( + this.token.$_burn(tokenHolder, tokenId, mintAmount.addn(1)), + 'ERC1155: burn amount exceeds balance', + ); + }); + + context('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mint(tokenHolder, tokenId, mintAmount, data); + this.receipt = await this.token.$_burn(tokenHolder, tokenId, burnAmount, { from: operator }); + }); + + it('emits a TransferSingle event', function () { + expectEvent(this.receipt, 'TransferSingle', { + operator, + from: tokenHolder, + to: ZERO_ADDRESS, + id: tokenId, + value: burnAmount, + }); + }); + + it('accounts for both minting and burning', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintAmount.sub(burnAmount)); + }); + }); + }); + + describe('_burnBatch', function () { + it("reverts when burning the zero account's tokens", async function () { + await expectRevert( + this.token.$_burnBatch(ZERO_ADDRESS, tokenBatchIds, burnAmounts), + 'ERC1155: burn from the zero address', + ); + }); + + it('reverts if length of inputs do not match', async function () { + await expectRevert( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts.slice(1)), + 'ERC1155: ids and amounts length mismatch', + ); + + await expectRevert( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds.slice(1), burnAmounts), + 'ERC1155: ids and amounts length mismatch', + ); + }); + + it('reverts when burning a non-existent token id', async function () { + await expectRevert( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts), + 'ERC1155: burn amount exceeds balance', + ); + }); + + context('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts, data); + this.receipt = await this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts, { from: operator }); + }); + + it('emits a TransferBatch event', function () { + expectEvent(this.receipt, 'TransferBatch', { + operator, + from: tokenBatchHolder, + to: ZERO_ADDRESS, + // ids: tokenBatchIds, + // values: burnAmounts, + }); + }); + + it('accounts for both minting and burning', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds, + ); + + for (let i = 0; i < holderBatchBalances.length; i++) { + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintAmounts[i].sub(burnAmounts[i])); + } + }); + }); + }); + }); + + describe('ERC1155MetadataURI', function () { + const firstTokenID = new BN('42'); + const secondTokenID = new BN('1337'); + + it('emits no URI event in constructor', async function () { + await expectEvent.notEmitted.inConstruction(this.token, 'URI'); + }); + + it('sets the initial URI for all token types', async function () { + expect(await this.token.uri(firstTokenID)).to.be.equal(initialURI); + expect(await this.token.uri(secondTokenID)).to.be.equal(initialURI); + }); + + describe('_setURI', function () { + const newURI = 'https://token-cdn-domain/{locale}/{id}.json'; + + it('emits no URI event', async function () { + const receipt = await this.token.$_setURI(newURI); + + expectEvent.notEmitted(receipt, 'URI'); + }); + + it('sets the new URI for all token types', async function () { + await this.token.$_setURI(newURI); + + expect(await this.token.uri(firstTokenID)).to.be.equal(newURI); + expect(await this.token.uri(secondTokenID)).to.be.equal(newURI); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js new file mode 100644 index 0000000..f80d993 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js @@ -0,0 +1,67 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC1155Burnable = artifacts.require('$ERC1155Burnable'); + +contract('ERC1155Burnable', function (accounts) { + const [holder, operator, other] = accounts; + + const uri = 'https://token.com'; + + const tokenIds = [new BN('42'), new BN('1137')]; + const amounts = [new BN('3000'), new BN('9902')]; + + beforeEach(async function () { + this.token = await ERC1155Burnable.new(uri); + + await this.token.$_mint(holder, tokenIds[0], amounts[0], '0x'); + await this.token.$_mint(holder, tokenIds[1], amounts[1], '0x'); + }); + + describe('burn', function () { + it('holder can burn their tokens', async function () { + await this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: holder }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: operator }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expectRevert( + this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: other }), + 'ERC1155: caller is not token owner or approved', + ); + }); + }); + + describe('burnBatch', function () { + it('holder can burn their tokens', async function () { + await this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: holder }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: operator }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expectRevert( + this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: other }), + 'ERC1155: caller is not token owner or approved', + ); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js new file mode 100644 index 0000000..f4d5ced --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js @@ -0,0 +1,108 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC1155Pausable = artifacts.require('$ERC1155Pausable'); + +contract('ERC1155Pausable', function (accounts) { + const [holder, operator, receiver, other] = accounts; + + const uri = 'https://token.com'; + + beforeEach(async function () { + this.token = await ERC1155Pausable.new(uri); + }); + + context('when token is paused', function () { + const firstTokenId = new BN('37'); + const firstTokenAmount = new BN('42'); + + const secondTokenId = new BN('19842'); + const secondTokenAmount = new BN('23'); + + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); + + await this.token.$_pause(); + }); + + it('reverts when trying to safeTransferFrom from holder', async function () { + await expectRevert( + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenAmount, '0x', { from: holder }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeTransferFrom from operator', async function () { + await expectRevert( + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenAmount, '0x', { from: operator }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeBatchTransferFrom from holder', async function () { + await expectRevert( + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenAmount], '0x', { from: holder }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeBatchTransferFrom from operator', async function () { + await expectRevert( + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenAmount], '0x', { + from: operator, + }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to mint', async function () { + await expectRevert( + this.token.$_mint(holder, secondTokenId, secondTokenAmount, '0x'), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to mintBatch', async function () { + await expectRevert( + this.token.$_mintBatch(holder, [secondTokenId], [secondTokenAmount], '0x'), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to burn', async function () { + await expectRevert( + this.token.$_burn(holder, firstTokenId, firstTokenAmount), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to burnBatch', async function () { + await expectRevert( + this.token.$_burnBatch(holder, [firstTokenId], [firstTokenAmount]), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + describe('setApprovalForAll', function () { + it('approves an operator', async function () { + await this.token.setApprovalForAll(other, true, { from: holder }); + expect(await this.token.isApprovedForAll(holder, other)).to.equal(true); + }); + }); + + describe('balanceOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const balance = await this.token.balanceOf(holder, firstTokenId); + expect(balance).to.be.bignumber.equal(firstTokenAmount); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(holder, operator)).to.equal(true); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js new file mode 100644 index 0000000..721d5a7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js @@ -0,0 +1,107 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC1155Supply = artifacts.require('$ERC1155Supply'); + +contract('ERC1155Supply', function (accounts) { + const [holder] = accounts; + + const uri = 'https://token.com'; + + const firstTokenId = new BN('37'); + const firstTokenAmount = new BN('42'); + + const secondTokenId = new BN('19842'); + const secondTokenAmount = new BN('23'); + + beforeEach(async function () { + this.token = await ERC1155Supply.new(uri); + }); + + context('before mint', function () { + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); + }); + }); + + context('after mint', function () { + context('single', function () { + beforeEach(async function () { + await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(true); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal(firstTokenAmount); + }); + }); + + context('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch( + holder, + [firstTokenId, secondTokenId], + [firstTokenAmount, secondTokenAmount], + '0x', + ); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(true); + expect(await this.token.exists(secondTokenId)).to.be.equal(true); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal(firstTokenAmount); + expect(await this.token.totalSupply(secondTokenId)).to.be.bignumber.equal(secondTokenAmount); + }); + }); + }); + + context('after burn', function () { + context('single', function () { + beforeEach(async function () { + await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); + await this.token.$_burn(holder, firstTokenId, firstTokenAmount); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); + }); + }); + + context('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch( + holder, + [firstTokenId, secondTokenId], + [firstTokenAmount, secondTokenAmount], + '0x', + ); + await this.token.$_burnBatch(holder, [firstTokenId, secondTokenId], [firstTokenAmount, secondTokenAmount]); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + expect(await this.token.exists(secondTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.totalSupply(secondTokenId)).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js new file mode 100644 index 0000000..95d9c18 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js @@ -0,0 +1,66 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { artifacts } = require('hardhat'); + +const ERC1155URIStorage = artifacts.require('$ERC1155URIStorage'); + +contract(['ERC1155URIStorage'], function (accounts) { + const [holder] = accounts; + + const erc1155Uri = 'https://token.com/nfts/'; + const baseUri = 'https://token.com/'; + + const tokenId = new BN('1'); + const amount = new BN('3000'); + + describe('with base uri set', function () { + beforeEach(async function () { + this.token = await ERC1155URIStorage.new(erc1155Uri); + await this.token.$_setBaseURI(baseUri); + + await this.token.$_mint(holder, tokenId, amount, '0x'); + }); + + it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(erc1155Uri); + }); + + it('can request the token uri, returning the concatenated uri if a token uri was set', async function () { + const tokenUri = '1234/'; + const receipt = await this.token.$_setURI(tokenId, tokenUri); + + const receivedTokenUri = await this.token.uri(tokenId); + + const expectedUri = `${baseUri}${tokenUri}`; + expect(receivedTokenUri).to.be.equal(expectedUri); + expectEvent(receipt, 'URI', { value: expectedUri, id: tokenId }); + }); + }); + + describe('with base uri set to the empty string', function () { + beforeEach(async function () { + this.token = await ERC1155URIStorage.new(''); + + await this.token.$_mint(holder, tokenId, amount, '0x'); + }); + + it('can request the token uri, returning an empty string if no token uri was set', async function () { + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(''); + }); + + it('can request the token uri, returning the token uri if a token uri was set', async function () { + const tokenUri = 'ipfs://1234/'; + const receipt = await this.token.$_setURI(tokenId, tokenUri); + + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(tokenUri); + expectEvent(receipt, 'URI', { value: tokenUri, id: tokenId }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js new file mode 100644 index 0000000..12d2594 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js @@ -0,0 +1,156 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +const { expect } = require('chai'); + +const ERC1155PresetMinterPauser = artifacts.require('ERC1155PresetMinterPauser'); + +contract('ERC1155PresetMinterPauser', function (accounts) { + const [deployer, other] = accounts; + + const firstTokenId = new BN('845'); + const firstTokenIdAmount = new BN('5000'); + + const secondTokenId = new BN('48324'); + const secondTokenIdAmount = new BN('77875'); + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const MINTER_ROLE = web3.utils.soliditySha3('MINTER_ROLE'); + const PAUSER_ROLE = web3.utils.soliditySha3('PAUSER_ROLE'); + + const uri = 'https://token.com'; + + beforeEach(async function () { + this.token = await ERC1155PresetMinterPauser.new(uri, { from: deployer }); + }); + + shouldSupportInterfaces(['ERC1155', 'AccessControl', 'AccessControlEnumerable']); + + it('deployer has the default admin role', async function () { + expect(await this.token.getRoleMemberCount(DEFAULT_ADMIN_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(DEFAULT_ADMIN_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the minter role', async function () { + expect(await this.token.getRoleMemberCount(MINTER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(MINTER_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the pauser role', async function () { + expect(await this.token.getRoleMemberCount(PAUSER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(PAUSER_ROLE, 0)).to.equal(deployer); + }); + + it('minter and pauser role admin is the default admin', async function () { + expect(await this.token.getRoleAdmin(MINTER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + expect(await this.token.getRoleAdmin(PAUSER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + describe('minting', function () { + it('deployer can mint tokens', async function () { + const receipt = await this.token.mint(other, firstTokenId, firstTokenIdAmount, '0x', { from: deployer }); + expectEvent(receipt, 'TransferSingle', { + operator: deployer, + from: ZERO_ADDRESS, + to: other, + value: firstTokenIdAmount, + id: firstTokenId, + }); + + expect(await this.token.balanceOf(other, firstTokenId)).to.be.bignumber.equal(firstTokenIdAmount); + }); + + it('other accounts cannot mint tokens', async function () { + await expectRevert( + this.token.mint(other, firstTokenId, firstTokenIdAmount, '0x', { from: other }), + 'ERC1155PresetMinterPauser: must have minter role to mint', + ); + }); + }); + + describe('batched minting', function () { + it('deployer can batch mint tokens', async function () { + const receipt = await this.token.mintBatch( + other, + [firstTokenId, secondTokenId], + [firstTokenIdAmount, secondTokenIdAmount], + '0x', + { from: deployer }, + ); + + expectEvent(receipt, 'TransferBatch', { operator: deployer, from: ZERO_ADDRESS, to: other }); + + expect(await this.token.balanceOf(other, firstTokenId)).to.be.bignumber.equal(firstTokenIdAmount); + }); + + it('other accounts cannot batch mint tokens', async function () { + await expectRevert( + this.token.mintBatch(other, [firstTokenId, secondTokenId], [firstTokenIdAmount, secondTokenIdAmount], '0x', { + from: other, + }), + 'ERC1155PresetMinterPauser: must have minter role to mint', + ); + }); + }); + + describe('pausing', function () { + it('deployer can pause', async function () { + const receipt = await this.token.pause({ from: deployer }); + expectEvent(receipt, 'Paused', { account: deployer }); + + expect(await this.token.paused()).to.equal(true); + }); + + it('deployer can unpause', async function () { + await this.token.pause({ from: deployer }); + + const receipt = await this.token.unpause({ from: deployer }); + expectEvent(receipt, 'Unpaused', { account: deployer }); + + expect(await this.token.paused()).to.equal(false); + }); + + it('cannot mint while paused', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.mint(other, firstTokenId, firstTokenIdAmount, '0x', { from: deployer }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('other accounts cannot pause', async function () { + await expectRevert( + this.token.pause({ from: other }), + 'ERC1155PresetMinterPauser: must have pauser role to pause', + ); + }); + + it('other accounts cannot unpause', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.unpause({ from: other }), + 'ERC1155PresetMinterPauser: must have pauser role to unpause', + ); + }); + }); + + describe('burning', function () { + it('holders can burn their tokens', async function () { + await this.token.mint(other, firstTokenId, firstTokenIdAmount, '0x', { from: deployer }); + + const receipt = await this.token.burn(other, firstTokenId, firstTokenIdAmount.subn(1), { from: other }); + expectEvent(receipt, 'TransferSingle', { + operator: other, + from: other, + to: ZERO_ADDRESS, + value: firstTokenIdAmount.subn(1), + id: firstTokenId, + }); + + expect(await this.token.balanceOf(other, firstTokenId)).to.be.bignumber.equal('1'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js new file mode 100644 index 0000000..864e89b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js @@ -0,0 +1,64 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const ERC1155Holder = artifacts.require('ERC1155Holder'); +const ERC1155 = artifacts.require('$ERC1155'); + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +contract('ERC1155Holder', function (accounts) { + const [creator] = accounts; + const uri = 'https://token-cdn-domain/{id}.json'; + const multiTokenIds = [new BN(1), new BN(2), new BN(3)]; + const multiTokenAmounts = [new BN(1000), new BN(2000), new BN(3000)]; + const transferData = '0x12345678'; + + beforeEach(async function () { + this.multiToken = await ERC1155.new(uri); + this.holder = await ERC1155Holder.new(); + await this.multiToken.$_mintBatch(creator, multiTokenIds, multiTokenAmounts, '0x'); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver']); + + it('receives ERC1155 tokens from a single ID', async function () { + await this.multiToken.safeTransferFrom( + creator, + this.holder.address, + multiTokenIds[0], + multiTokenAmounts[0], + transferData, + { from: creator }, + ); + + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[0])).to.be.bignumber.equal( + multiTokenAmounts[0], + ); + + for (let i = 1; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + } + }); + + it('receives ERC1155 tokens from a multiple IDs', async function () { + for (let i = 0; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + } + + await this.multiToken.safeBatchTransferFrom( + creator, + this.holder.address, + multiTokenIds, + multiTokenAmounts, + transferData, + { from: creator }, + ); + + for (let i = 0; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal( + multiTokenAmounts[i], + ); + } + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js new file mode 100644 index 0000000..41e47f0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js @@ -0,0 +1,322 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS, MAX_UINT256 } = constants; + +function shouldBehaveLikeERC20(errorPrefix, initialSupply, initialHolder, recipient, anotherAccount) { + describe('total supply', function () { + it('returns the total amount of tokens', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + }); + + describe('balanceOf', function () { + describe('when the requested account has no tokens', function () { + it('returns zero', async function () { + expect(await this.token.balanceOf(anotherAccount)).to.be.bignumber.equal('0'); + }); + }); + + describe('when the requested account has some tokens', function () { + it('returns the total amount of tokens', async function () { + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(initialSupply); + }); + }); + }); + + describe('transfer', function () { + shouldBehaveLikeERC20Transfer(errorPrefix, initialHolder, recipient, initialSupply, function (from, to, value) { + return this.token.transfer(to, value, { from }); + }); + }); + + describe('transfer from', function () { + const spender = recipient; + + describe('when the token owner is not the zero address', function () { + const tokenOwner = initialHolder; + + describe('when the recipient is not the zero address', function () { + const to = anotherAccount; + + describe('when the spender has enough allowance', function () { + beforeEach(async function () { + await this.token.approve(spender, initialSupply, { from: initialHolder }); + }); + + describe('when the token owner has enough balance', function () { + const amount = initialSupply; + + it('transfers the requested amount', async function () { + await this.token.transferFrom(tokenOwner, to, amount, { from: spender }); + + expect(await this.token.balanceOf(tokenOwner)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(amount); + }); + + it('decreases the spender allowance', async function () { + await this.token.transferFrom(tokenOwner, to, amount, { from: spender }); + + expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal('0'); + }); + + it('emits a transfer event', async function () { + expectEvent(await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'Transfer', { + from: tokenOwner, + to: to, + value: amount, + }); + }); + + it('emits an approval event', async function () { + expectEvent(await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'Approval', { + owner: tokenOwner, + spender: spender, + value: await this.token.allowance(tokenOwner, spender), + }); + }); + }); + + describe('when the token owner does not have enough balance', function () { + const amount = initialSupply; + + beforeEach('reducing balance', async function () { + await this.token.transfer(to, 1, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + `${errorPrefix}: transfer amount exceeds balance`, + ); + }); + }); + }); + + describe('when the spender does not have enough allowance', function () { + const allowance = initialSupply.subn(1); + + beforeEach(async function () { + await this.token.approve(spender, allowance, { from: tokenOwner }); + }); + + describe('when the token owner has enough balance', function () { + const amount = initialSupply; + + it('reverts', async function () { + await expectRevert( + this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + `${errorPrefix}: insufficient allowance`, + ); + }); + }); + + describe('when the token owner does not have enough balance', function () { + const amount = allowance; + + beforeEach('reducing balance', async function () { + await this.token.transfer(to, 2, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + `${errorPrefix}: transfer amount exceeds balance`, + ); + }); + }); + }); + + describe('when the spender has unlimited allowance', function () { + beforeEach(async function () { + await this.token.approve(spender, MAX_UINT256, { from: initialHolder }); + }); + + it('does not decrease the spender allowance', async function () { + await this.token.transferFrom(tokenOwner, to, 1, { from: spender }); + + expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal(MAX_UINT256); + }); + + it('does not emit an approval event', async function () { + expectEvent.notEmitted(await this.token.transferFrom(tokenOwner, to, 1, { from: spender }), 'Approval'); + }); + }); + }); + + describe('when the recipient is the zero address', function () { + const amount = initialSupply; + const to = ZERO_ADDRESS; + + beforeEach(async function () { + await this.token.approve(spender, amount, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + `${errorPrefix}: transfer to the zero address`, + ); + }); + }); + }); + + describe('when the token owner is the zero address', function () { + const amount = 0; + const tokenOwner = ZERO_ADDRESS; + const to = recipient; + + it('reverts', async function () { + await expectRevert(this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'from the zero address'); + }); + }); + }); + + describe('approve', function () { + shouldBehaveLikeERC20Approve( + errorPrefix, + initialHolder, + recipient, + initialSupply, + function (owner, spender, amount) { + return this.token.approve(spender, amount, { from: owner }); + }, + ); + }); +} + +function shouldBehaveLikeERC20Transfer(errorPrefix, from, to, balance, transfer) { + describe('when the recipient is not the zero address', function () { + describe('when the sender does not have enough balance', function () { + const amount = balance.addn(1); + + it('reverts', async function () { + await expectRevert(transfer.call(this, from, to, amount), `${errorPrefix}: transfer amount exceeds balance`); + }); + }); + + describe('when the sender transfers all balance', function () { + const amount = balance; + + it('transfers the requested amount', async function () { + await transfer.call(this, from, to, amount); + + expect(await this.token.balanceOf(from)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(amount); + }); + + it('emits a transfer event', async function () { + expectEvent(await transfer.call(this, from, to, amount), 'Transfer', { from, to, value: amount }); + }); + }); + + describe('when the sender transfers zero tokens', function () { + const amount = new BN('0'); + + it('transfers the requested amount', async function () { + await transfer.call(this, from, to, amount); + + expect(await this.token.balanceOf(from)).to.be.bignumber.equal(balance); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal('0'); + }); + + it('emits a transfer event', async function () { + expectEvent(await transfer.call(this, from, to, amount), 'Transfer', { from, to, value: amount }); + }); + }); + }); + + describe('when the recipient is the zero address', function () { + it('reverts', async function () { + await expectRevert( + transfer.call(this, from, ZERO_ADDRESS, balance), + `${errorPrefix}: transfer to the zero address`, + ); + }); + }); +} + +function shouldBehaveLikeERC20Approve(errorPrefix, owner, spender, supply, approve) { + describe('when the spender is not the zero address', function () { + describe('when the sender has enough balance', function () { + const amount = supply; + + it('emits an approval event', async function () { + expectEvent(await approve.call(this, owner, spender, amount), 'Approval', { + owner: owner, + spender: spender, + value: amount, + }); + }); + + describe('when there was no approved amount before', function () { + it('approves the requested amount', async function () { + await approve.call(this, owner, spender, amount); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + }); + }); + + describe('when the spender had an approved amount', function () { + beforeEach(async function () { + await approve.call(this, owner, spender, new BN(1)); + }); + + it('approves the requested amount and replaces the previous one', async function () { + await approve.call(this, owner, spender, amount); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + }); + }); + }); + + describe('when the sender does not have enough balance', function () { + const amount = supply.addn(1); + + it('emits an approval event', async function () { + expectEvent(await approve.call(this, owner, spender, amount), 'Approval', { + owner: owner, + spender: spender, + value: amount, + }); + }); + + describe('when there was no approved amount before', function () { + it('approves the requested amount', async function () { + await approve.call(this, owner, spender, amount); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + }); + }); + + describe('when the spender had an approved amount', function () { + beforeEach(async function () { + await approve.call(this, owner, spender, new BN(1)); + }); + + it('approves the requested amount and replaces the previous one', async function () { + await approve.call(this, owner, spender, amount); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + }); + }); + }); + }); + + describe('when the spender is the zero address', function () { + it('reverts', async function () { + await expectRevert( + approve.call(this, owner, ZERO_ADDRESS, supply), + `${errorPrefix}: approve to the zero address`, + ); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js new file mode 100644 index 0000000..6971eed --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js @@ -0,0 +1,305 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +} = require('./ERC20.behavior'); + +const ERC20 = artifacts.require('$ERC20'); +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); + +contract('ERC20', function (accounts) { + const [initialHolder, recipient, anotherAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.token = await ERC20.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + it('has a name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('has 18 decimals', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('18'); + }); + + describe('set decimals', function () { + const decimals = new BN(6); + + it('can set decimals during construction', async function () { + const token = await ERC20Decimals.new(name, symbol, decimals); + expect(await token.decimals()).to.be.bignumber.equal(decimals); + }); + }); + + shouldBehaveLikeERC20('ERC20', initialSupply, initialHolder, recipient, anotherAccount); + + describe('decrease allowance', function () { + describe('when the spender is not the zero address', function () { + const spender = recipient; + + function shouldDecreaseApproval(amount) { + describe('when there was no approved amount before', function () { + it('reverts', async function () { + await expectRevert( + this.token.decreaseAllowance(spender, amount, { from: initialHolder }), + 'ERC20: decreased allowance below zero', + ); + }); + }); + + describe('when the spender had an approved amount', function () { + const approvedAmount = amount; + + beforeEach(async function () { + await this.token.approve(spender, approvedAmount, { from: initialHolder }); + }); + + it('emits an approval event', async function () { + expectEvent( + await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }), + 'Approval', + { owner: initialHolder, spender: spender, value: new BN(0) }, + ); + }); + + it('decreases the spender allowance subtracting the requested amount', async function () { + await this.token.decreaseAllowance(spender, approvedAmount.subn(1), { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('1'); + }); + + it('sets the allowance to zero when all allowance is removed', async function () { + await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }); + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('0'); + }); + + it('reverts when more than the full allowance is removed', async function () { + await expectRevert( + this.token.decreaseAllowance(spender, approvedAmount.addn(1), { from: initialHolder }), + 'ERC20: decreased allowance below zero', + ); + }); + }); + } + + describe('when the sender has enough balance', function () { + const amount = initialSupply; + + shouldDecreaseApproval(amount); + }); + + describe('when the sender does not have enough balance', function () { + const amount = initialSupply.addn(1); + + shouldDecreaseApproval(amount); + }); + }); + + describe('when the spender is the zero address', function () { + const amount = initialSupply; + const spender = ZERO_ADDRESS; + + it('reverts', async function () { + await expectRevert( + this.token.decreaseAllowance(spender, amount, { from: initialHolder }), + 'ERC20: decreased allowance below zero', + ); + }); + }); + }); + + describe('increase allowance', function () { + const amount = initialSupply; + + describe('when the spender is not the zero address', function () { + const spender = recipient; + + describe('when the sender has enough balance', function () { + it('emits an approval event', async function () { + expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', { + owner: initialHolder, + spender: spender, + value: amount, + }); + }); + + describe('when there was no approved amount before', function () { + it('approves the requested amount', async function () { + await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount); + }); + }); + + describe('when the spender had an approved amount', function () { + beforeEach(async function () { + await this.token.approve(spender, new BN(1), { from: initialHolder }); + }); + + it('increases the spender allowance adding the requested amount', async function () { + await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1)); + }); + }); + }); + + describe('when the sender does not have enough balance', function () { + const amount = initialSupply.addn(1); + + it('emits an approval event', async function () { + expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', { + owner: initialHolder, + spender: spender, + value: amount, + }); + }); + + describe('when there was no approved amount before', function () { + it('approves the requested amount', async function () { + await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount); + }); + }); + + describe('when the spender had an approved amount', function () { + beforeEach(async function () { + await this.token.approve(spender, new BN(1), { from: initialHolder }); + }); + + it('increases the spender allowance adding the requested amount', async function () { + await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1)); + }); + }); + }); + }); + + describe('when the spender is the zero address', function () { + const spender = ZERO_ADDRESS; + + it('reverts', async function () { + await expectRevert( + this.token.increaseAllowance(spender, amount, { from: initialHolder }), + 'ERC20: approve to the zero address', + ); + }); + }); + }); + + describe('_mint', function () { + const amount = new BN(50); + it('rejects a null account', async function () { + await expectRevert(this.token.$_mint(ZERO_ADDRESS, amount), 'ERC20: mint to the zero address'); + }); + + describe('for a non zero account', function () { + beforeEach('minting', async function () { + this.receipt = await this.token.$_mint(recipient, amount); + }); + + it('increments totalSupply', async function () { + const expectedSupply = initialSupply.add(amount); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + + it('increments recipient balance', async function () { + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + }); + + it('emits Transfer event', async function () { + const event = expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: recipient }); + + expect(event.args.value).to.be.bignumber.equal(amount); + }); + }); + }); + + describe('_burn', function () { + it('rejects a null account', async function () { + await expectRevert(this.token.$_burn(ZERO_ADDRESS, new BN(1)), 'ERC20: burn from the zero address'); + }); + + describe('for a non zero account', function () { + it('rejects burning more than balance', async function () { + await expectRevert( + this.token.$_burn(initialHolder, initialSupply.addn(1)), + 'ERC20: burn amount exceeds balance', + ); + }); + + const describeBurn = function (description, amount) { + describe(description, function () { + beforeEach('burning', async function () { + this.receipt = await this.token.$_burn(initialHolder, amount); + }); + + it('decrements totalSupply', async function () { + const expectedSupply = initialSupply.sub(amount); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + + it('decrements initialHolder balance', async function () { + const expectedBalance = initialSupply.sub(amount); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(expectedBalance); + }); + + it('emits Transfer event', async function () { + const event = expectEvent(this.receipt, 'Transfer', { from: initialHolder, to: ZERO_ADDRESS }); + + expect(event.args.value).to.be.bignumber.equal(amount); + }); + }); + }; + + describeBurn('for entire balance', initialSupply); + describeBurn('for less amount than balance', initialSupply.subn(1)); + }); + }); + + describe('_transfer', function () { + shouldBehaveLikeERC20Transfer('ERC20', initialHolder, recipient, initialSupply, function (from, to, amount) { + return this.token.$_transfer(from, to, amount); + }); + + describe('when the sender is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.token.$_transfer(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20: transfer from the zero address', + ); + }); + }); + }); + + describe('_approve', function () { + shouldBehaveLikeERC20Approve('ERC20', initialHolder, recipient, initialSupply, function (owner, spender, amount) { + return this.token.$_approve(owner, spender, amount); + }); + + describe('when the owner is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.token.$_approve(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20: approve from the zero address', + ); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.behavior.js new file mode 100644 index 0000000..2edabc4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.behavior.js @@ -0,0 +1,106 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +function shouldBehaveLikeERC20Burnable(owner, initialBalance, [burner]) { + describe('burn', function () { + describe('when the given amount is not greater than balance of the sender', function () { + context('for a zero amount', function () { + shouldBurn(new BN(0)); + }); + + context('for a non-zero amount', function () { + shouldBurn(new BN(100)); + }); + + function shouldBurn(amount) { + beforeEach(async function () { + this.receipt = await this.token.burn(amount, { from: owner }); + }); + + it('burns the requested amount', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(amount)); + }); + + it('emits a transfer event', async function () { + expectEvent(this.receipt, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + value: amount, + }); + }); + } + }); + + describe('when the given amount is greater than the balance of the sender', function () { + const amount = initialBalance.addn(1); + + it('reverts', async function () { + await expectRevert(this.token.burn(amount, { from: owner }), 'ERC20: burn amount exceeds balance'); + }); + }); + }); + + describe('burnFrom', function () { + describe('on success', function () { + context('for a zero amount', function () { + shouldBurnFrom(new BN(0)); + }); + + context('for a non-zero amount', function () { + shouldBurnFrom(new BN(100)); + }); + + function shouldBurnFrom(amount) { + const originalAllowance = amount.muln(3); + + beforeEach(async function () { + await this.token.approve(burner, originalAllowance, { from: owner }); + this.receipt = await this.token.burnFrom(owner, amount, { from: burner }); + }); + + it('burns the requested amount', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(amount)); + }); + + it('decrements allowance', async function () { + expect(await this.token.allowance(owner, burner)).to.be.bignumber.equal(originalAllowance.sub(amount)); + }); + + it('emits a transfer event', async function () { + expectEvent(this.receipt, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + value: amount, + }); + }); + } + }); + + describe('when the given amount is greater than the balance of the sender', function () { + const amount = initialBalance.addn(1); + + it('reverts', async function () { + await this.token.approve(burner, amount, { from: owner }); + await expectRevert(this.token.burnFrom(owner, amount, { from: burner }), 'ERC20: burn amount exceeds balance'); + }); + }); + + describe('when the given amount is greater than the allowance', function () { + const allowance = new BN(100); + + it('reverts', async function () { + await this.token.approve(burner, allowance, { from: owner }); + await expectRevert( + this.token.burnFrom(owner, allowance.addn(1), { from: burner }), + 'ERC20: insufficient allowance', + ); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20Burnable, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js new file mode 100644 index 0000000..00acc81 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js @@ -0,0 +1,20 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { shouldBehaveLikeERC20Burnable } = require('./ERC20Burnable.behavior'); +const ERC20Burnable = artifacts.require('$ERC20Burnable'); + +contract('ERC20Burnable', function (accounts) { + const [owner, ...otherAccounts] = accounts; + + const initialBalance = new BN(1000); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Burnable.new(name, symbol, { from: owner }); + await this.token.$_mint(owner, initialBalance); + }); + + shouldBehaveLikeERC20Burnable(owner, initialBalance, otherAccounts); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.behavior.js new file mode 100644 index 0000000..97bad1d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.behavior.js @@ -0,0 +1,32 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +function shouldBehaveLikeERC20Capped(accounts, cap) { + describe('capped token', function () { + const user = accounts[0]; + + it('starts with the correct cap', async function () { + expect(await this.token.cap()).to.be.bignumber.equal(cap); + }); + + it('mints when amount is less than cap', async function () { + await this.token.$_mint(user, cap.subn(1)); + expect(await this.token.totalSupply()).to.be.bignumber.equal(cap.subn(1)); + }); + + it('fails to mint if the amount exceeds the cap', async function () { + await this.token.$_mint(user, cap.subn(1)); + await expectRevert(this.token.$_mint(user, 2), 'ERC20Capped: cap exceeded'); + }); + + it('fails to mint after cap is reached', async function () { + await this.token.$_mint(user, cap); + await expectRevert(this.token.$_mint(user, 1), 'ERC20Capped: cap exceeded'); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20Capped, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js new file mode 100644 index 0000000..a86d38c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js @@ -0,0 +1,23 @@ +const { ether, expectRevert } = require('@openzeppelin/test-helpers'); +const { shouldBehaveLikeERC20Capped } = require('./ERC20Capped.behavior'); + +const ERC20Capped = artifacts.require('$ERC20Capped'); + +contract('ERC20Capped', function (accounts) { + const cap = ether('1000'); + + const name = 'My Token'; + const symbol = 'MTKN'; + + it('requires a non-zero cap', async function () { + await expectRevert(ERC20Capped.new(name, symbol, 0), 'ERC20Capped: cap is 0'); + }); + + context('once deployed', async function () { + beforeEach(async function () { + this.token = await ERC20Capped.new(name, symbol, cap); + }); + + shouldBehaveLikeERC20Capped(accounts, cap); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js new file mode 100644 index 0000000..76d66ff --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js @@ -0,0 +1,204 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const ERC20FlashMintMock = artifacts.require('$ERC20FlashMintMock'); +const ERC3156FlashBorrowerMock = artifacts.require('ERC3156FlashBorrowerMock'); + +contract('ERC20FlashMint', function (accounts) { + const [initialHolder, other, anotherAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + const loanAmount = new BN(10000000000000); + + beforeEach(async function () { + this.token = await ERC20FlashMintMock.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + describe('maxFlashLoan', function () { + it('token match', async function () { + expect(await this.token.maxFlashLoan(this.token.address)).to.be.bignumber.equal(MAX_UINT256.sub(initialSupply)); + }); + + it('token mismatch', async function () { + expect(await this.token.maxFlashLoan(ZERO_ADDRESS)).to.be.bignumber.equal('0'); + }); + }); + + describe('flashFee', function () { + it('token match', async function () { + expect(await this.token.flashFee(this.token.address, loanAmount)).to.be.bignumber.equal('0'); + }); + + it('token mismatch', async function () { + await expectRevert(this.token.flashFee(ZERO_ADDRESS, loanAmount), 'ERC20FlashMint: wrong token'); + }); + }); + + describe('flashFeeReceiver', function () { + it('default receiver', async function () { + expect(await this.token.$_flashFeeReceiver()).to.be.eq(ZERO_ADDRESS); + }); + }); + + describe('flashLoan', function () { + it('success', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const { tx } = await this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver.address, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: receiver.address, + to: ZERO_ADDRESS, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, receiver, 'BalanceOf', { + token: this.token.address, + account: receiver.address, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(loanAmount), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + expect(await this.token.balanceOf(receiver.address)).to.be.bignumber.equal('0'); + expect(await this.token.allowance(receiver.address, this.token.address)).to.be.bignumber.equal('0'); + }); + + it('missing return value', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(false, true); + await expectRevert( + this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'), + 'ERC20FlashMint: invalid return value', + ); + }); + + it('missing approval', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, false); + await expectRevert( + this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'), + 'ERC20: insufficient allowance', + ); + }); + + it('unavailable funds', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const data = this.token.contract.methods.transfer(other, 10).encodeABI(); + await expectRevert( + this.token.flashLoan(receiver.address, this.token.address, loanAmount, data), + 'ERC20: burn amount exceeds balance', + ); + }); + + it('more than maxFlashLoan', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const data = this.token.contract.methods.transfer(other, 10).encodeABI(); + // _mint overflow reverts using a panic code. No reason string. + await expectRevert.unspecified(this.token.flashLoan(receiver.address, this.token.address, MAX_UINT256, data)); + }); + + describe('custom flash fee & custom fee receiver', function () { + const receiverInitialBalance = new BN(200000); + const flashFee = new BN(5000); + + beforeEach('init receiver balance & set flash fee', async function () { + this.receiver = await ERC3156FlashBorrowerMock.new(true, true); + const receipt = await this.token.$_mint(this.receiver.address, receiverInitialBalance); + await expectEvent(receipt, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: receiverInitialBalance, + }); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal(receiverInitialBalance); + + await this.token.setFlashFee(flashFee); + expect(await this.token.flashFee(this.token.address, loanAmount)).to.be.bignumber.equal(flashFee); + }); + + it('default flash fee receiver', async function () { + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanAmount, '0x'); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: ZERO_ADDRESS, + value: loanAmount.add(flashFee), + }); + await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { + token: this.token.address, + account: this.receiver.address, + value: receiverInitialBalance.add(loanAmount), + }); + await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(receiverInitialBalance).add(loanAmount), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal( + initialSupply.add(receiverInitialBalance).sub(flashFee), + ); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal( + receiverInitialBalance.sub(flashFee), + ); + expect(await this.token.balanceOf(await this.token.$_flashFeeReceiver())).to.be.bignumber.equal('0'); + expect(await this.token.allowance(this.receiver.address, this.token.address)).to.be.bignumber.equal('0'); + }); + + it('custom flash fee receiver', async function () { + const flashFeeReceiverAddress = anotherAccount; + await this.token.setFlashFeeReceiver(flashFeeReceiverAddress); + expect(await this.token.$_flashFeeReceiver()).to.be.eq(flashFeeReceiverAddress); + + expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal('0'); + + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanAmount, '0x'); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: ZERO_ADDRESS, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: flashFeeReceiverAddress, + value: flashFee, + }); + await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { + token: this.token.address, + account: this.receiver.address, + value: receiverInitialBalance.add(loanAmount), + }); + await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(receiverInitialBalance).add(loanAmount), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply.add(receiverInitialBalance)); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal( + receiverInitialBalance.sub(flashFee), + ); + expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal(flashFee); + expect(await this.token.allowance(this.receiver.address, flashFeeReceiverAddress)).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js new file mode 100644 index 0000000..ead442b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js @@ -0,0 +1,133 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC20Pausable = artifacts.require('$ERC20Pausable'); + +contract('ERC20Pausable', function (accounts) { + const [holder, recipient, anotherAccount] = accounts; + + const initialSupply = new BN(100); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Pausable.new(name, symbol); + await this.token.$_mint(holder, initialSupply); + }); + + describe('pausable token', function () { + describe('transfer', function () { + it('allows to transfer when unpaused', async function () { + await this.token.transfer(recipient, initialSupply, { from: holder }); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.transfer(recipient, initialSupply, { from: holder }); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); + }); + + it('reverts when trying to transfer when paused', async function () { + await this.token.$_pause(); + + await expectRevert( + this.token.transfer(recipient, initialSupply, { from: holder }), + 'ERC20Pausable: token transfer while paused', + ); + }); + }); + + describe('transfer from', function () { + const allowance = new BN(40); + + beforeEach(async function () { + await this.token.approve(anotherAccount, allowance, { from: holder }); + }); + + it('allows to transfer from when unpaused', async function () { + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); + }); + + it('reverts when trying to transfer from when paused', async function () { + await this.token.$_pause(); + + await expectRevert( + this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }), + 'ERC20Pausable: token transfer while paused', + ); + }); + }); + + describe('mint', function () { + const amount = new BN('42'); + + it('allows to mint when unpaused', async function () { + await this.token.$_mint(recipient, amount); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + }); + + it('allows to mint when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.$_mint(recipient, amount); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + }); + + it('reverts when trying to mint when paused', async function () { + await this.token.$_pause(); + + await expectRevert(this.token.$_mint(recipient, amount), 'ERC20Pausable: token transfer while paused'); + }); + }); + + describe('burn', function () { + const amount = new BN('42'); + + it('allows to burn when unpaused', async function () { + await this.token.$_burn(holder, amount); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(amount)); + }); + + it('allows to burn when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.$_burn(holder, amount); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(amount)); + }); + + it('reverts when trying to burn when paused', async function () { + await this.token.$_pause(); + + await expectRevert(this.token.$_burn(holder, amount), 'ERC20Pausable: token transfer while paused'); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Snapshot.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Snapshot.test.js new file mode 100644 index 0000000..fb0bb31 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Snapshot.test.js @@ -0,0 +1,207 @@ +const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const ERC20Snapshot = artifacts.require('$ERC20Snapshot'); + +const { expect } = require('chai'); + +contract('ERC20Snapshot', function (accounts) { + const [initialHolder, recipient, other] = accounts; + + const initialSupply = new BN(100); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Snapshot.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + describe('snapshot', function () { + it('emits a snapshot event', async function () { + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot'); + }); + + it('creates increasing snapshots ids, starting from 1', async function () { + for (const id of ['1', '2', '3', '4', '5']) { + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id }); + } + }); + }); + + describe('totalSupplyAt', function () { + it('reverts with a snapshot id of 0', async function () { + await expectRevert(this.token.totalSupplyAt(0), 'ERC20Snapshot: id is 0'); + }); + + it('reverts with a not-yet-created snapshot id', async function () { + await expectRevert(this.token.totalSupplyAt(1), 'ERC20Snapshot: nonexistent id'); + }); + + context('with initial snapshot', function () { + beforeEach(async function () { + this.initialSnapshotId = new BN('1'); + + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id: this.initialSnapshotId }); + }); + + context('with no supply changes after the snapshot', function () { + it('returns the current total supply', async function () { + expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply); + }); + }); + + context('with supply changes after the snapshot', function () { + beforeEach(async function () { + await this.token.$_mint(other, new BN('50')); + await this.token.$_burn(initialHolder, new BN('20')); + }); + + it('returns the total supply before the changes', async function () { + expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply); + }); + + context('with a second snapshot after supply changes', function () { + beforeEach(async function () { + this.secondSnapshotId = new BN('2'); + + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id: this.secondSnapshotId }); + }); + + it('snapshots return the supply before and after the changes', async function () { + expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply); + + expect(await this.token.totalSupplyAt(this.secondSnapshotId)).to.be.bignumber.equal( + await this.token.totalSupply(), + ); + }); + }); + + context('with multiple snapshots after supply changes', function () { + beforeEach(async function () { + this.secondSnapshotIds = ['2', '3', '4']; + + for (const id of this.secondSnapshotIds) { + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id }); + } + }); + + it('all posterior snapshots return the supply after the changes', async function () { + expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply); + + const currentSupply = await this.token.totalSupply(); + + for (const id of this.secondSnapshotIds) { + expect(await this.token.totalSupplyAt(id)).to.be.bignumber.equal(currentSupply); + } + }); + }); + }); + }); + }); + + describe('balanceOfAt', function () { + it('reverts with a snapshot id of 0', async function () { + await expectRevert(this.token.balanceOfAt(other, 0), 'ERC20Snapshot: id is 0'); + }); + + it('reverts with a not-yet-created snapshot id', async function () { + await expectRevert(this.token.balanceOfAt(other, 1), 'ERC20Snapshot: nonexistent id'); + }); + + context('with initial snapshot', function () { + beforeEach(async function () { + this.initialSnapshotId = new BN('1'); + + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id: this.initialSnapshotId }); + }); + + context('with no balance changes after the snapshot', function () { + it('returns the current balance for all accounts', async function () { + expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId)).to.be.bignumber.equal( + initialSupply, + ); + expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0'); + }); + }); + + context('with balance changes after the snapshot', function () { + beforeEach(async function () { + await this.token.transfer(recipient, new BN('10'), { from: initialHolder }); + await this.token.$_mint(other, new BN('50')); + await this.token.$_burn(initialHolder, new BN('20')); + }); + + it('returns the balances before the changes', async function () { + expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId)).to.be.bignumber.equal( + initialSupply, + ); + expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0'); + }); + + context('with a second snapshot after supply changes', function () { + beforeEach(async function () { + this.secondSnapshotId = new BN('2'); + + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id: this.secondSnapshotId }); + }); + + it('snapshots return the balances before and after the changes', async function () { + expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId)).to.be.bignumber.equal( + initialSupply, + ); + expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOfAt(initialHolder, this.secondSnapshotId)).to.be.bignumber.equal( + await this.token.balanceOf(initialHolder), + ); + expect(await this.token.balanceOfAt(recipient, this.secondSnapshotId)).to.be.bignumber.equal( + await this.token.balanceOf(recipient), + ); + expect(await this.token.balanceOfAt(other, this.secondSnapshotId)).to.be.bignumber.equal( + await this.token.balanceOf(other), + ); + }); + }); + + context('with multiple snapshots after supply changes', function () { + beforeEach(async function () { + this.secondSnapshotIds = ['2', '3', '4']; + + for (const id of this.secondSnapshotIds) { + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id }); + } + }); + + it('all posterior snapshots return the supply after the changes', async function () { + expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId)).to.be.bignumber.equal( + initialSupply, + ); + expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0'); + + for (const id of this.secondSnapshotIds) { + expect(await this.token.balanceOfAt(initialHolder, id)).to.be.bignumber.equal( + await this.token.balanceOf(initialHolder), + ); + expect(await this.token.balanceOfAt(recipient, id)).to.be.bignumber.equal( + await this.token.balanceOf(recipient), + ); + expect(await this.token.balanceOfAt(other, id)).to.be.bignumber.equal(await this.token.balanceOf(other)); + } + }); + }); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js new file mode 100644 index 0000000..e722ed1 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js @@ -0,0 +1,578 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { batchInBlock } = require('../../../helpers/txpool'); +const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { clock, clockFromReceipt } = require('../../../helpers/time'); + +const { shouldBehaveLikeEIP6372 } = require('../../../governance/utils/EIP6372.behavior'); + +const Delegation = [ + { name: 'delegatee', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { 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 supply = new BN('10000000000000000000000000'); + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.token = await artifact.new(name, symbol, name); + }); + + shouldBehaveLikeEIP6372(mode); + + 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 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); + }); + }); + + 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, + })); + + 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', + ); + }); + }); + }); + + 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 }); + 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); + }); + }); + + 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 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); + }); + }); + + // 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 }); + 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', + ); + }); + }); + }); + + 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: future lookup'); + }); + + 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', + ); + }); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20VotesComp.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20VotesComp.test.js new file mode 100644 index 0000000..5f95722 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20VotesComp.test.js @@ -0,0 +1,543 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { batchInBlock } = require('../../../helpers/txpool'); +const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { clock, clockFromReceipt } = require('../../../helpers/time'); + +const { shouldBehaveLikeEIP6372 } = require('../../../governance/utils/EIP6372.behavior'); + +const Delegation = [ + { name: 'delegatee', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { 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 supply = new BN('10000000000000000000000000'); + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.token = await artifact.new(name, symbol, name); + }); + + shouldBehaveLikeEIP6372(mode); + + 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 }); + 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); + }); + }); + + 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, + })); + + 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', + ); + }); + }); + }); + + 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 }); + 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); + }); + }); + + 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 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); + }); + }); + + // 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 }); + 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', + ); + }); + }); + }); + + 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: future lookup'); + }); + + 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', + ); + }); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js new file mode 100644 index 0000000..cfb47bf --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js @@ -0,0 +1,190 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS, MAX_UINT256 } = constants; + +const { shouldBehaveLikeERC20 } = require('../ERC20.behavior'); + +const NotAnERC20 = artifacts.require('CallReceiverMock'); +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); +const ERC20Wrapper = artifacts.require('$ERC20Wrapper'); + +contract('ERC20', function (accounts) { + const [initialHolder, recipient, anotherAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.underlying = await ERC20Decimals.new(name, symbol, 9); + await this.underlying.$_mint(initialHolder, initialSupply); + + this.token = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, this.underlying.address); + }); + + afterEach(async function () { + expect(await this.underlying.balanceOf(this.token.address)).to.be.bignumber.equal(await this.token.totalSupply()); + }); + + 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 the same decimals as the underlying token', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('9'); + }); + + it('decimals default back to 18 if token has no metadata', async function () { + const noDecimals = await NotAnERC20.new(); + const otherToken = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, noDecimals.address); + expect(await otherToken.decimals()).to.be.bignumber.equal('18'); + }); + + it('has underlying', async function () { + expect(await this.token.underlying()).to.be.bignumber.equal(this.underlying.address); + }); + + describe('deposit', function () { + it('valid', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + const { tx } = await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: initialHolder, + value: initialSupply, + }); + }); + + it('missing approval', async function () { + await expectRevert( + this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }), + 'ERC20: insufficient allowance', + ); + }); + + it('missing balance', async function () { + await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder }); + await expectRevert( + this.token.depositFor(initialHolder, MAX_UINT256, { from: initialHolder }), + 'ERC20: transfer amount exceeds balance', + ); + }); + + it('to other account', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + const { tx } = await this.token.depositFor(anotherAccount, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: anotherAccount, + value: initialSupply, + }); + }); + }); + + describe('withdraw', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + }); + + it('missing balance', async function () { + await expectRevert( + this.token.withdrawTo(initialHolder, MAX_UINT256, { from: initialHolder }), + 'ERC20: burn amount exceeds balance', + ); + }); + + it('valid', async function () { + const value = new BN(42); + + const { tx } = await this.token.withdrawTo(initialHolder, value, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + value: value, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: value, + }); + }); + + it('entire balance', async function () { + const { tx } = await this.token.withdrawTo(initialHolder, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: initialSupply, + }); + }); + + it('to other account', async function () { + const { tx } = await this.token.withdrawTo(anotherAccount, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: anotherAccount, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: initialSupply, + }); + }); + }); + + describe('recover', function () { + it('nothing to recover', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + + const { tx } = await this.token.$_recover(anotherAccount); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: anotherAccount, + value: '0', + }); + }); + + it('something to recover', async function () { + await this.underlying.transfer(this.token.address, initialSupply, { from: initialHolder }); + + const { tx } = await this.token.$_recover(anotherAccount); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: anotherAccount, + value: initialSupply, + }); + }); + }); + + describe('erc20 behaviour', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + }); + + shouldBehaveLikeERC20('ERC20', initialSupply, initialHolder, recipient, anotherAccount); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol new file mode 100644 index 0000000..03786b2 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "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"; + +contract ERC4626StdTest is ERC4626Test { + function setUp() public override { + _underlying_ = address(new ERC20Mock()); + _vault_ = address(new ERC4626Mock(_underlying_)); + _delta_ = 0; + _vaultMayBeEmpty = false; + _unlimitedAmount = true; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js new file mode 100644 index 0000000..0c67a2f --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js @@ -0,0 +1,610 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); +const ERC4626 = artifacts.require('$ERC4626'); +const ERC4626OffsetMock = artifacts.require('$ERC4626OffsetMock'); + +contract('ERC4626', function (accounts) { + const [holder, recipient, spender, other, user1, user2] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + 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)) { + const token = await ERC20Decimals.new('', '', decimals); + const vault = await ERC4626.new('', '', token.address); + expect(await vault.decimals()).to.be.bignumber.equal(decimals); + } + }); + + 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); + + const virtualAssets = web3.utils.toBN(1); + const virtualShares = web3.utils.toBN(10).pow(offset); + + 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 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 }); + }); + + 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 }); + }); + }); + }); + } + + /// 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 () { + // test designed with both asset using similar decimals + this.token = await ERC20Decimals.new(name, symbol, 18); + this.vault = await ERC4626.new(name + ' Vault', symbol + 'V', this.token.address); + + await this.token.$_mint(user1, 4000); + await this.token.$_mint(user2, 7001); + await this.token.approve(this.vault.address, 4000, { from: user1 }); + await this.token.approve(this.vault.address, 7001, { from: user2 }); + + // 1. Alice mints 2000 shares (costs 2000 tokens) + { + const { tx } = await this.vault.mint(2000, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user1, + to: this.vault.address, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + value: '2000', + }); + + expect(await this.vault.previewDeposit(2000)).to.be.bignumber.equal('2000'); + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('2000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('0'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('2000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('2000'); + } + + // 2. Bob deposits 4000 tokens (mints 4000 shares) + { + const { tx } = await this.vault.mint(4000, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user2, + to: this.vault.address, + value: '4000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + value: '4000', + }); + + expect(await this.vault.previewDeposit(4000)).to.be.bignumber.equal('4000'); + 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('2000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('4000'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('6000'); + } + + // 3. Vault mutates by +3000 tokens (simulated yield returned from strategy) + await this.token.$_mint(this.vault.address, 3000); + + 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('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'); + + // 4. Alice deposits 2000 tokens (mints 1333 shares) + { + const { tx } = await this.vault.deposit(2000, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user1, + to: this.vault.address, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + value: '1333', + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333'); + 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('4999'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('6000'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('7333'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('11000'); + } + + // 5. Bob mints 2000 shares (costs 3001 assets) + // NOTE: Bob's assets spent got rounded up + // NOTE: Alices's vault assets got rounded up + { + const { tx } = await this.vault.mint(2000, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user2, + to: this.vault.address, + value: '3000', // used to be 3001 + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + value: '2000', + }); + + 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('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('14000'); // used to be 14001 + } + + // 6. Vault mutates by +3000 tokens + // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000. + await this.token.$_mint(this.vault.address, 3000); + + 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('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('17000'); // used to be 17001 + + // 7. Alice redeem 1333 shares (2428 assets) + { + const { tx } = await this.vault.redeem(1333, user1, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + value: '1333', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user1, + value: '2427', // used to be 2428 + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + 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('3643'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('10929'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('8000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('14573'); + } + + // 8. Bob withdraws 2929 assets (1608 shares) + { + const { tx } = await this.vault.withdraw(2929, user2, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user2, + to: constants.ZERO_ADDRESS, + value: '1608', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user2, + value: '2929', + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + 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('3643'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('8000'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6392'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('11644'); + } + + // 9. Alice withdraws 3643 assets (2000 shares) + // NOTE: Bob's assets have been rounded back up + { + const { tx } = await this.vault.withdraw(3643, user1, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user1, + value: '3643', + }); + + 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('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'); + } + + // 10. Bob redeem 4392 shares (8001 tokens) + { + const { tx } = await this.vault.redeem(4392, user2, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user2, + to: constants.ZERO_ADDRESS, + value: '4392', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user2, + value: '8000', // used to be 8001 + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('0'); + expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0'); + 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('1'); // used to be 0 + } + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Permit.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Permit.test.js new file mode 100644 index 0000000..33c43c4 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/extensions/draft-ERC20Permit.test.js @@ -0,0 +1,103 @@ +/* eslint-disable */ + +const { BN, constants, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256 } = constants; + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const ERC20Permit = artifacts.require('$ERC20Permit'); + +const { Permit, getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { getChainId } = require('../../../helpers/chainid'); + +contract('ERC20Permit', function (accounts) { + const [initialHolder, spender] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + const version = '1'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.chainId = await getChainId(); + + this.token = await ERC20Permit.new(name, symbol, name); + await this.token.$_mint(initialHolder, initialSupply); + }); + + it('initial nonce is 0', async function () { + expect(await this.token.nonces(initialHolder)).to.be.bignumber.equal('0'); + }); + + it('domain separator', async function () { + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); + }); + + describe('permit', function () { + const wallet = Wallet.generate(); + + const owner = wallet.getAddressString(); + const value = new BN(42); + const nonce = 0; + const maxDeadline = MAX_UINT256; + + 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 { 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); + + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + + it('rejects reused signature', async function () { + 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); + + await expectRevert( + this.token.permit(owner, spender, value, maxDeadline, v, r, s), + 'ERC20Permit: invalid signature', + ); + }); + + it('rejects other signature', async function () { + const otherWallet = Wallet.generate(); + + 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), + 'ERC20Permit: invalid signature', + ); + }); + + it('rejects expired permit', async function () { + const deadline = (await time.latest()) - time.duration.weeks(1); + + 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/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js new file mode 100644 index 0000000..f1d0b53 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js @@ -0,0 +1,42 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const ERC20PresetFixedSupply = artifacts.require('ERC20PresetFixedSupply'); + +contract('ERC20PresetFixedSupply', function (accounts) { + const [deployer, owner] = accounts; + + const name = 'PresetFixedSupply'; + const symbol = 'PFS'; + + const initialSupply = new BN('50000'); + const amount = new BN('10000'); + + before(async function () { + this.token = await ERC20PresetFixedSupply.new(name, symbol, initialSupply, owner, { from: deployer }); + }); + + it('deployer has the balance equal to initial supply', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialSupply); + }); + + it('total supply is equal to initial supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + + describe('burning', function () { + it('holders can burn their tokens', async function () { + const remainingBalance = initialSupply.sub(amount); + const receipt = await this.token.burn(amount, { from: owner }); + expectEvent(receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, value: amount }); + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(remainingBalance); + }); + + it('decrements totalSupply', async function () { + const expectedSupply = initialSupply.sub(amount); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js new file mode 100644 index 0000000..ad9ff29 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js @@ -0,0 +1,110 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const ERC20PresetMinterPauser = artifacts.require('ERC20PresetMinterPauser'); + +contract('ERC20PresetMinterPauser', function (accounts) { + const [deployer, other] = accounts; + + const name = 'MinterPauserToken'; + const symbol = 'DRT'; + + const amount = new BN('5000'); + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const MINTER_ROLE = web3.utils.soliditySha3('MINTER_ROLE'); + const PAUSER_ROLE = web3.utils.soliditySha3('PAUSER_ROLE'); + + beforeEach(async function () { + this.token = await ERC20PresetMinterPauser.new(name, symbol, { from: deployer }); + }); + + it('deployer has the default admin role', async function () { + expect(await this.token.getRoleMemberCount(DEFAULT_ADMIN_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(DEFAULT_ADMIN_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the minter role', async function () { + expect(await this.token.getRoleMemberCount(MINTER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(MINTER_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the pauser role', async function () { + expect(await this.token.getRoleMemberCount(PAUSER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(PAUSER_ROLE, 0)).to.equal(deployer); + }); + + it('minter and pauser role admin is the default admin', async function () { + expect(await this.token.getRoleAdmin(MINTER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + expect(await this.token.getRoleAdmin(PAUSER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + describe('minting', function () { + it('deployer can mint tokens', async function () { + const receipt = await this.token.mint(other, amount, { from: deployer }); + expectEvent(receipt, 'Transfer', { from: ZERO_ADDRESS, to: other, value: amount }); + + expect(await this.token.balanceOf(other)).to.be.bignumber.equal(amount); + }); + + it('other accounts cannot mint tokens', async function () { + await expectRevert( + this.token.mint(other, amount, { from: other }), + 'ERC20PresetMinterPauser: must have minter role to mint', + ); + }); + }); + + describe('pausing', function () { + it('deployer can pause', async function () { + const receipt = await this.token.pause({ from: deployer }); + expectEvent(receipt, 'Paused', { account: deployer }); + + expect(await this.token.paused()).to.equal(true); + }); + + it('deployer can unpause', async function () { + await this.token.pause({ from: deployer }); + + const receipt = await this.token.unpause({ from: deployer }); + expectEvent(receipt, 'Unpaused', { account: deployer }); + + expect(await this.token.paused()).to.equal(false); + }); + + it('cannot mint while paused', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.mint(other, amount, { from: deployer }), + 'ERC20Pausable: token transfer while paused', + ); + }); + + it('other accounts cannot pause', async function () { + await expectRevert(this.token.pause({ from: other }), 'ERC20PresetMinterPauser: must have pauser role to pause'); + }); + + it('other accounts cannot unpause', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.unpause({ from: other }), + 'ERC20PresetMinterPauser: must have pauser role to unpause', + ); + }); + }); + + describe('burning', function () { + it('holders can burn their tokens', async function () { + await this.token.mint(other, amount, { from: deployer }); + + const receipt = await this.token.burn(amount.subn(1), { from: other }); + expectEvent(receipt, 'Transfer', { from: other, to: ZERO_ADDRESS, value: amount.subn(1) }); + + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('1'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js new file mode 100644 index 0000000..a6b10fa --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js @@ -0,0 +1,264 @@ +const { constants, 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 { getDomain, domainType, Permit } = require('../../../helpers/eip712'); + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +contract('SafeERC20', function (accounts) { + const [hasNoCode] = accounts; + + before(async function () { + this.mock = await SafeERC20.new(); + }); + + describe('with address that has no contract code', function () { + beforeEach(async function () { + this.token = { address: hasNoCode }; + }); + + shouldRevertOnAllCalls('Address: call to non-contract'); + }); + + describe('with token that returns false on all calls', function () { + beforeEach(async function () { + this.token = await ERC20ReturnFalseMock.new(); + }); + + shouldRevertOnAllCalls('SafeERC20: ERC20 operation did not succeed'); + }); + + describe('with token that returns true on all calls', function () { + beforeEach(async function () { + this.token = await ERC20ReturnTrueMock.new(); + }); + + shouldOnlyRevertOnErrors(); + }); + + describe('with token that returns no boolean values', function () { + beforeEach(async function () { + this.token = await ERC20NoReturnMock.new(); + }); + + shouldOnlyRevertOnErrors(); + }); + + describe("with token that doesn't revert on invalid permit", function () { + const wallet = Wallet.generate(); + const owner = wallet.getAddressString(); + const spender = hasNoCode; + + beforeEach(async function () { + this.token = await ERC20PermitNoRevertMock.new(); + + this.data = await getDomain(this.token).then(domain => ({ + primaryType: 'Permit', + 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 })); + }); + + it('accepts owner signature', async function () { + expect(await this.token.nonces(owner)).to.be.bignumber.equal('0'); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal('0'); + + await this.mock.$safePermit( + this.token.address, + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + this.signature.v, + this.signature.r, + this.signature.s, + ); + + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(this.data.message.value); + }); + + it('revert on reused signature', async function () { + expect(await this.token.nonces(owner)).to.be.bignumber.equal('0'); + // use valid signature and consume nounce + await this.mock.$safePermit( + this.token.address, + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + this.signature.v, + this.signature.r, + this.signature.s, + ); + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + // invalid call does not revert for this token implementation + await this.token.permit( + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + this.signature.v, + this.signature.r, + this.signature.s, + ); + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + // invalid call revert when called through the SafeERC20 library + await expectRevert( + this.mock.$safePermit( + this.token.address, + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + this.signature.v, + this.signature.r, + this.signature.s, + ), + 'SafeERC20: permit did not succeed', + ); + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + }); + + it('revert on invalid signature', async function () { + // signature that is not valid for owner + const invalidSignature = { + v: 27, + r: '0x71753dc5ecb5b4bfc0e3bc530d79ce5988760ed3f3a234c86a5546491f540775', + s: '0x0049cedee5aed990aabed5ad6a9f6e3c565b63379894b5fa8b512eb2b79e485d', + }; + + // invalid call does not revert for this token implementation + await this.token.permit( + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + invalidSignature.v, + invalidSignature.r, + invalidSignature.s, + ); + + // invalid call revert when called through the SafeERC20 library + await expectRevert( + this.mock.$safePermit( + this.token.address, + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + invalidSignature.v, + invalidSignature.r, + invalidSignature.s, + ), + 'SafeERC20: permit did not succeed', + ); + }); + }); +}); + +function shouldRevertOnAllCalls(reason) { + it('reverts on transfer', async function () { + await expectRevert(this.mock.$safeTransfer(this.token.address, constants.ZERO_ADDRESS, 0), reason); + }); + + it('reverts on transferFrom', async function () { + await expectRevert( + this.mock.$safeTransferFrom(this.token.address, this.mock.address, constants.ZERO_ADDRESS, 0), + reason, + ); + }); + + it('reverts on approve', async function () { + await expectRevert(this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 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)); + }); + + 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)); + }); +} + +function shouldOnlyRevertOnErrors() { + it("doesn't revert on transfer", async function () { + await this.mock.$safeTransfer(this.token.address, constants.ZERO_ADDRESS, 0); + }); + + it("doesn't revert on transferFrom", async function () { + await this.mock.$safeTransferFrom(this.token.address, this.mock.address, constants.ZERO_ADDRESS, 0); + }); + + describe('approvals', function () { + context('with zero allowance', function () { + beforeEach(async function () { + await this.token.setAllowance(this.mock.address, 0); + }); + + it("doesn't revert when approving a non-zero allowance", async function () { + await this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 100); + }); + + it("doesn't revert when approving a zero allowance", async function () { + await this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 0); + }); + + it("doesn't revert when increasing the allowance", async function () { + await this.mock.$safeIncreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 10); + }); + + it('reverts when decreasing the allowance', async function () { + await expectRevert( + this.mock.$safeDecreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 10), + 'SafeERC20: decreased allowance below zero', + ); + }); + }); + + context('with non-zero allowance', function () { + beforeEach(async function () { + await this.token.setAllowance(this.mock.address, 100); + }); + + it('reverts when approving a non-zero allowance', async function () { + await expectRevert( + this.mock.$safeApprove(this.token.address, constants.ZERO_ADDRESS, 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); + }); + + it("doesn't revert when increasing the allowance", async function () { + await this.mock.$safeIncreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 10); + }); + + 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); + }); + + it('reverts when decreasing the allowance to a negative value', async function () { + await expectRevert( + this.mock.$safeDecreaseAllowance(this.token.address, constants.ZERO_ADDRESS, 200), + 'SafeERC20: decreased allowance below zero', + ); + }); + }); + }); +} diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/utils/TokenTimelock.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/utils/TokenTimelock.test.js new file mode 100644 index 0000000..22e8071 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC20/utils/TokenTimelock.test.js @@ -0,0 +1,71 @@ +const { BN, expectRevert, time } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC20 = artifacts.require('$ERC20'); +const TokenTimelock = artifacts.require('TokenTimelock'); + +contract('TokenTimelock', function (accounts) { + const [beneficiary] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const amount = new BN(100); + + context('with token', function () { + beforeEach(async function () { + this.token = await ERC20.new(name, symbol); + }); + + it('rejects a release time in the past', async function () { + const pastReleaseTime = (await time.latest()).sub(time.duration.years(1)); + await expectRevert( + TokenTimelock.new(this.token.address, beneficiary, pastReleaseTime), + 'TokenTimelock: release time is before current time', + ); + }); + + context('once deployed', function () { + beforeEach(async function () { + this.releaseTime = (await time.latest()).add(time.duration.years(1)); + this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime); + await this.token.$_mint(this.timelock.address, amount); + }); + + it('can get state', async function () { + expect(await this.timelock.token()).to.equal(this.token.address); + expect(await this.timelock.beneficiary()).to.equal(beneficiary); + expect(await this.timelock.releaseTime()).to.be.bignumber.equal(this.releaseTime); + }); + + it('cannot be released before time limit', async function () { + await expectRevert(this.timelock.release(), 'TokenTimelock: current time is before release time'); + }); + + it('cannot be released just before time limit', async function () { + await time.increaseTo(this.releaseTime.sub(time.duration.seconds(3))); + await expectRevert(this.timelock.release(), 'TokenTimelock: current time is before release time'); + }); + + it('can be released just after limit', async function () { + await time.increaseTo(this.releaseTime.add(time.duration.seconds(1))); + await this.timelock.release(); + expect(await this.token.balanceOf(beneficiary)).to.be.bignumber.equal(amount); + }); + + it('can be released after time limit', async function () { + await time.increaseTo(this.releaseTime.add(time.duration.years(1))); + await this.timelock.release(); + expect(await this.token.balanceOf(beneficiary)).to.be.bignumber.equal(amount); + }); + + it('cannot be released twice', async function () { + await time.increaseTo(this.releaseTime.add(time.duration.years(1))); + await this.timelock.release(); + await expectRevert(this.timelock.release(), 'TokenTimelock: no tokens to release'); + expect(await this.token.balanceOf(beneficiary)).to.be.bignumber.equal(amount); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js new file mode 100644 index 0000000..6867db3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js @@ -0,0 +1,893 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +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), + {}, +); + +const firstTokenId = new BN('5042'); +const secondTokenId = new BN('79217'); +const nonExistentTokenId = new BN('13'); +const fourthTokenId = new BN(4); +const baseURI = 'https://api.example.com/v1/'; + +const RECEIVER_MAGIC_VALUE = '0x150b7a02'; + +function shouldBehaveLikeERC721(errorPrefix, owner, newOwner, approved, anotherApproved, operator, other) { + shouldSupportInterfaces(['ERC165', 'ERC721']); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + this.toWhom = other; // default to other for toWhom in context-dependent tests + }); + + describe('balanceOf', function () { + context('when the given address owns some tokens', function () { + it('returns the amount of tokens owned by the given address', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('2'); + }); + }); + + context('when the given address does not own any tokens', function () { + it('returns 0', async function () { + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('0'); + }); + }); + + context('when querying the zero address', function () { + it('throws', async function () { + await expectRevert(this.token.balanceOf(ZERO_ADDRESS), 'ERC721: address zero is not a valid owner'); + }); + }); + }); + + describe('ownerOf', function () { + context('when the given token ID was tracked by this token', function () { + const tokenId = firstTokenId; + + it('returns the owner of the given token ID', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owner); + }); + }); + + context('when the given token ID was not tracked by this token', function () { + const tokenId = nonExistentTokenId; + + it('reverts', async function () { + await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID'); + }); + }); + }); + + describe('transfers', function () { + const tokenId = firstTokenId; + const data = '0x42'; + + let receipt = null; + + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + await this.token.setApprovalForAll(operator, true, { from: owner }); + }); + + const transferWasSuccessful = function ({ owner, tokenId }) { + it('transfers the ownership of the given token ID to the given address', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(this.toWhom); + }); + + it('emits a Transfer event', async function () { + expectEvent(receipt, 'Transfer', { from: owner, to: this.toWhom, tokenId: tokenId }); + }); + + it('clears the approval for the token ID', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + + it('adjusts owners balances', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('adjusts owners tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + + expect(await this.token.tokenOfOwnerByIndex(this.toWhom, 0)).to.be.bignumber.equal(tokenId); + + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.not.equal(tokenId); + }); + }; + + const shouldTransferTokensByUsers = function (transferFunction) { + context('when called by the owner', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: owner }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the approved individual', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: approved }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the operator', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: operator }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the owner without an approved user', function () { + beforeEach(async function () { + await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: operator }); + }); + transferWasSuccessful({ owner, tokenId, approved: null }); + }); + + context('when sent to the owner', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, owner, tokenId, { from: owner }); + }); + + it('keeps ownership of the token', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owner); + }); + + it('clears the approval for the token ID', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + + it('emits only a transfer event', async function () { + expectEvent(receipt, 'Transfer', { + from: owner, + to: owner, + tokenId: tokenId, + }); + }); + + it('keeps the owner balance', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('2'); + }); + + it('keeps same tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenOfOwnerByIndex(owner, i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + }); + + context('when the address of the previous owner is incorrect', function () { + it('reverts', async function () { + await expectRevert( + transferFunction.call(this, other, other, tokenId, { from: owner }), + 'ERC721: transfer from incorrect owner', + ); + }); + }); + + context('when the sender is not authorized for the token id', function () { + it('reverts', async function () { + await expectRevert( + transferFunction.call(this, owner, other, tokenId, { from: other }), + 'ERC721: caller is not token owner or approved', + ); + }); + }); + + context('when the given token ID does not exist', function () { + it('reverts', async function () { + await expectRevert( + transferFunction.call(this, owner, other, nonExistentTokenId, { from: owner }), + 'ERC721: invalid token ID', + ); + }); + }); + + context('when the address to transfer the token to is the zero address', function () { + it('reverts', async function () { + await expectRevert( + transferFunction.call(this, owner, ZERO_ADDRESS, tokenId, { from: owner }), + 'ERC721: transfer to the zero address', + ); + }); + }); + }; + + describe('via transferFrom', function () { + shouldTransferTokensByUsers(function (from, to, tokenId, opts) { + return this.token.transferFrom(from, to, tokenId, opts); + }); + }); + + describe('via safeTransferFrom', function () { + const safeTransferFromWithData = function (from, to, tokenId, opts) { + return this.token.methods['safeTransferFrom(address,address,uint256,bytes)'](from, to, tokenId, data, opts); + }; + + const safeTransferFromWithoutData = function (from, to, tokenId, opts) { + return this.token.methods['safeTransferFrom(address,address,uint256)'](from, to, tokenId, opts); + }; + + const shouldTransferSafely = function (transferFun, data) { + describe('to a user account', function () { + shouldTransferTokensByUsers(transferFun); + }); + + describe('to a valid receiver contract', function () { + beforeEach(async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None); + this.toWhom = this.receiver.address; + }); + + shouldTransferTokensByUsers(transferFun); + + it('calls onERC721Received', async function () { + const receipt = await transferFun.call(this, owner, this.receiver.address, tokenId, { from: owner }); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + operator: owner, + from: owner, + tokenId: tokenId, + data: data, + }); + }); + + it('calls onERC721Received from approved', async function () { + const receipt = await transferFun.call(this, owner, this.receiver.address, tokenId, { from: approved }); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + operator: approved, + from: owner, + tokenId: tokenId, + data: data, + }); + }); + + describe('with an invalid token id', function () { + it('reverts', async function () { + await expectRevert( + transferFun.call(this, owner, this.receiver.address, nonExistentTokenId, { from: owner }), + 'ERC721: invalid token ID', + ); + }); + }); + }); + }; + + describe('with data', function () { + shouldTransferSafely(safeTransferFromWithData, data); + }); + + describe('without data', function () { + shouldTransferSafely(safeTransferFromWithoutData, null); + }); + + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ERC721ReceiverMock.new('0x42', Error.None); + await expectRevert( + this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + + describe('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithMessage); + await expectRevert( + this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }), + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + describe('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithoutMessage); + await expectRevert( + this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + + describe('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.Panic); + await expectRevert.unspecified( + this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }), + ); + }); + }); + + describe('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await NonERC721ReceiverMock.new(); + await expectRevert( + this.token.safeTransferFrom(owner, nonReceiver.address, tokenId, { from: owner }), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + }); + }); + + describe('safe mint', function () { + const tokenId = fourthTokenId; + const data = '0x42'; + + describe('via safeMint', function () { + // regular minting is tested in ERC721Mintable.test.js and others + it('calls onERC721Received — with data', async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None); + const receipt = await this.token.$_safeMint(this.receiver.address, tokenId, data); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + from: ZERO_ADDRESS, + tokenId: tokenId, + data: data, + }); + }); + + it('calls onERC721Received — without data', async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None); + const receipt = await this.token.$_safeMint(this.receiver.address, tokenId); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + from: ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + + context('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ERC721ReceiverMock.new('0x42', Error.None); + await expectRevert( + this.token.$_safeMint(invalidReceiver.address, tokenId), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + + context('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithMessage); + await expectRevert( + this.token.$_safeMint(revertingReceiver.address, tokenId), + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + context('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithoutMessage); + await expectRevert( + this.token.$_safeMint(revertingReceiver.address, tokenId), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + + context('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.Panic); + await expectRevert.unspecified(this.token.$_safeMint(revertingReceiver.address, tokenId)); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await NonERC721ReceiverMock.new(); + await expectRevert( + this.token.$_safeMint(nonReceiver.address, tokenId), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + }); + }); + + describe('approve', function () { + const tokenId = firstTokenId; + + let receipt = null; + + const itClearsApproval = function () { + it('clears approval for the token', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + }; + + const itApproves = function (address) { + it('sets the approval for the target address', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(address); + }); + }; + + const itEmitsApprovalEvent = function (address) { + it('emits an approval event', async function () { + expectEvent(receipt, 'Approval', { + owner: owner, + approved: address, + tokenId: tokenId, + }); + }); + }; + + context('when clearing approval', function () { + context('when there was no prior approval', function () { + beforeEach(async function () { + receipt = await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + }); + + itClearsApproval(); + itEmitsApprovalEvent(ZERO_ADDRESS); + }); + + context('when there was a prior approval', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + }); + + itClearsApproval(); + itEmitsApprovalEvent(ZERO_ADDRESS); + }); + }); + + context('when approving a non-zero address', function () { + context('when there was no prior approval', function () { + beforeEach(async function () { + receipt = await this.token.approve(approved, tokenId, { from: owner }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when there was a prior approval to the same address', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.approve(approved, tokenId, { from: owner }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when there was a prior approval to a different address', function () { + beforeEach(async function () { + await this.token.approve(anotherApproved, tokenId, { from: owner }); + receipt = await this.token.approve(anotherApproved, tokenId, { from: owner }); + }); + + itApproves(anotherApproved); + itEmitsApprovalEvent(anotherApproved); + }); + }); + + context('when the address that receives the approval is the owner', function () { + it('reverts', async function () { + await expectRevert(this.token.approve(owner, tokenId, { from: owner }), 'ERC721: approval to current owner'); + }); + }); + + context('when the sender does not own the given token ID', function () { + it('reverts', async function () { + await expectRevert( + this.token.approve(approved, tokenId, { from: other }), + 'ERC721: approve caller is not token owner or approved', + ); + }); + }); + + context('when the sender is approved for the given token ID', function () { + it('reverts', async function () { + await this.token.approve(approved, tokenId, { from: owner }); + await expectRevert( + this.token.approve(anotherApproved, tokenId, { from: approved }), + 'ERC721: approve caller is not token owner or approved for all', + ); + }); + }); + + context('when the sender is an operator', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + receipt = await this.token.approve(approved, tokenId, { from: operator }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when the given token ID does not exist', function () { + it('reverts', async function () { + await expectRevert( + this.token.approve(approved, nonExistentTokenId, { from: operator }), + 'ERC721: invalid token ID', + ); + }); + }); + }); + + describe('setApprovalForAll', function () { + context('when the operator willing to approve is not the owner', function () { + context('when there is no operator approval set by the sender', function () { + it('approves the operator', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + }); + + context('when the operator was set as not approved', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, false, { from: owner }); + }); + + it('approves the operator', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + + it('can unset the operator approval', async function () { + await this.token.setApprovalForAll(operator, false, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); + + context('when the operator was already approved', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + }); + + it('keeps the approval to the given address', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + }); + }); + + context('when the operator is the owner', function () { + it('reverts', async function () { + await expectRevert(this.token.setApprovalForAll(owner, true, { from: owner }), 'ERC721: approve to caller'); + }); + }); + }); + + describe('getApproved', async function () { + context('when token is not minted', async function () { + it('reverts', async function () { + await expectRevert(this.token.getApproved(nonExistentTokenId), 'ERC721: invalid token ID'); + }); + }); + + context('when token has been minted ', async function () { + it('should return the zero address', async function () { + expect(await this.token.getApproved(firstTokenId)).to.be.equal(ZERO_ADDRESS); + }); + + context('when account has been approved', async function () { + beforeEach(async function () { + await this.token.approve(approved, firstTokenId, { from: owner }); + }); + + it('returns approved account', async function () { + expect(await this.token.getApproved(firstTokenId)).to.be.equal(approved); + }); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expectRevert(this.token.$_mint(ZERO_ADDRESS, firstTokenId), 'ERC721: mint to the zero address'); + }); + + context('with minted token', async function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(owner, firstTokenId); + }); + + it('emits a Transfer event', function () { + expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: owner, tokenId: firstTokenId }); + }); + + it('creates the token', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + expect(await this.token.ownerOf(firstTokenId)).to.equal(owner); + }); + + it('reverts when adding a token id that already exists', async function () { + await expectRevert(this.token.$_mint(owner, firstTokenId), 'ERC721: token already minted'); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expectRevert(this.token.$_burn(nonExistentTokenId), 'ERC721: invalid token ID'); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + context('with burnt token', function () { + beforeEach(async function () { + this.receipt = await this.token.$_burn(firstTokenId); + }); + + it('emits a Transfer event', function () { + expectEvent(this.receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, tokenId: firstTokenId }); + }); + + it('deletes the token', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + await expectRevert(this.token.ownerOf(firstTokenId), 'ERC721: invalid token ID'); + }); + + it('reverts when burning a token id that has been deleted', async function () { + await expectRevert(this.token.$_burn(firstTokenId), 'ERC721: invalid token ID'); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Enumerable(errorPrefix, owner, newOwner, approved, anotherApproved, operator, other) { + shouldSupportInterfaces(['ERC721Enumerable']); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + this.toWhom = other; // default to other for toWhom in context-dependent tests + }); + + describe('totalSupply', function () { + it('returns total token supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal('2'); + }); + }); + + describe('tokenOfOwnerByIndex', function () { + describe('when the given index is lower than the amount of tokens owned by the given address', function () { + it('returns the token ID placed at the given index', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(firstTokenId); + }); + }); + + describe('when the index is greater than or equal to the total tokens owned by the given address', function () { + it('reverts', async function () { + await expectRevert(this.token.tokenOfOwnerByIndex(owner, 2), 'ERC721Enumerable: owner index out of bounds'); + }); + }); + + describe('when the given address does not own any token', function () { + it('reverts', async function () { + await expectRevert(this.token.tokenOfOwnerByIndex(other, 0), 'ERC721Enumerable: owner index out of bounds'); + }); + }); + + describe('after transferring all tokens to another user', function () { + beforeEach(async function () { + await this.token.transferFrom(owner, other, firstTokenId, { from: owner }); + await this.token.transferFrom(owner, other, secondTokenId, { from: owner }); + }); + + it('returns correct token IDs for target', async function () { + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('2'); + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenOfOwnerByIndex(other, i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + + it('returns empty collection for original owner', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('0'); + await expectRevert(this.token.tokenOfOwnerByIndex(owner, 0), 'ERC721Enumerable: owner index out of bounds'); + }); + }); + }); + + describe('tokenByIndex', function () { + it('returns all tokens', async function () { + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenByIndex(i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + + it('reverts if index is greater than supply', async function () { + await expectRevert(this.token.tokenByIndex(2), 'ERC721Enumerable: global index out of bounds'); + }); + + [firstTokenId, secondTokenId].forEach(function (tokenId) { + it(`returns all tokens after burning token ${tokenId} and minting new tokens`, async function () { + const newTokenId = new BN(300); + const anotherNewTokenId = new BN(400); + + await this.token.$_burn(tokenId); + await this.token.$_mint(newOwner, newTokenId); + await this.token.$_mint(newOwner, anotherNewTokenId); + + expect(await this.token.totalSupply()).to.be.bignumber.equal('3'); + + const tokensListed = await Promise.all([0, 1, 2].map(i => this.token.tokenByIndex(i))); + const expectedTokens = [firstTokenId, secondTokenId, newTokenId, anotherNewTokenId].filter( + x => x !== tokenId, + ); + expect(tokensListed.map(t => t.toNumber())).to.have.members(expectedTokens.map(t => t.toNumber())); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expectRevert(this.token.$_mint(ZERO_ADDRESS, firstTokenId), 'ERC721: mint to the zero address'); + }); + + context('with minted token', async function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(owner, firstTokenId); + }); + + it('adjusts owner tokens by index', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(firstTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0)).to.be.bignumber.equal(firstTokenId); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expectRevert(this.token.$_burn(firstTokenId), 'ERC721: invalid token ID'); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + context('with burnt token', function () { + beforeEach(async function () { + this.receipt = await this.token.$_burn(firstTokenId); + }); + + it('removes that token from the token list of the owner', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(secondTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0)).to.be.bignumber.equal(secondTokenId); + }); + + it('burns all tokens', async function () { + await this.token.$_burn(secondTokenId, { from: owner }); + expect(await this.token.totalSupply()).to.be.bignumber.equal('0'); + await expectRevert(this.token.tokenByIndex(0), 'ERC721Enumerable: global index out of bounds'); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Metadata(errorPrefix, name, symbol, owner) { + shouldSupportInterfaces(['ERC721Metadata']); + + describe('metadata', function () { + it('has a name', async function () { + expect(await this.token.name()).to.be.equal(name); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.be.equal(symbol); + }); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + }); + + it('return empty string by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expectRevert(this.token.tokenURI(nonExistentTokenId), 'ERC721: invalid token ID'); + }); + + describe('base URI', function () { + beforeEach(function () { + if (this.token.setBaseURI === undefined) { + this.skip(); + } + }); + + it('base URI can be set', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.baseURI()).to.equal(baseURI); + }); + + it('base URI is added as a prefix to the token URI', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + firstTokenId.toString()); + }); + + it('token URI can be changed by changing the base URI', async function () { + await this.token.setBaseURI(baseURI); + const newBaseURI = 'https://api.example.com/v2/'; + await this.token.setBaseURI(newBaseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + firstTokenId.toString()); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Enumerable, + shouldBehaveLikeERC721Metadata, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js new file mode 100644 index 0000000..312430c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js @@ -0,0 +1,15 @@ +const { shouldBehaveLikeERC721, shouldBehaveLikeERC721Metadata } = require('./ERC721.behavior'); + +const ERC721 = artifacts.require('$ERC721'); + +contract('ERC721', function (accounts) { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721.new(name, symbol); + }); + + shouldBehaveLikeERC721('ERC721', ...accounts); + shouldBehaveLikeERC721Metadata('ERC721', name, symbol, ...accounts); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js new file mode 100644 index 0000000..b32f22d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js @@ -0,0 +1,20 @@ +const { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Metadata, + shouldBehaveLikeERC721Enumerable, +} = require('./ERC721.behavior'); + +const ERC721Enumerable = artifacts.require('$ERC721Enumerable'); + +contract('ERC721Enumerable', function (accounts) { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Enumerable.new(name, symbol); + }); + + shouldBehaveLikeERC721('ERC721', ...accounts); + shouldBehaveLikeERC721Metadata('ERC721', name, symbol, ...accounts); + shouldBehaveLikeERC721Enumerable('ERC721', ...accounts); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js new file mode 100644 index 0000000..6a4bc6d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js @@ -0,0 +1,70 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC721Burnable = artifacts.require('$ERC721Burnable'); + +contract('ERC721Burnable', function (accounts) { + const [owner, approved] = accounts; + + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Burnable.new(name, symbol); + }); + + describe('like a burnable ERC721', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + describe('burn', function () { + const tokenId = firstTokenId; + let receipt = null; + + describe('when successful', function () { + beforeEach(async function () { + receipt = await this.token.burn(tokenId, { from: owner }); + }); + + it('burns the given token ID and adjusts the balance of the owner', async function () { + await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID'); + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('emits a burn event', async function () { + expectEvent(receipt, 'Transfer', { + from: owner, + to: constants.ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + }); + + describe('when there is a previous approval burned', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.burn(tokenId, { from: owner }); + }); + + context('getApproved', function () { + it('reverts', async function () { + await expectRevert(this.token.getApproved(tokenId), 'ERC721: invalid token ID'); + }); + }); + }); + + describe('when the given token ID was not tracked by this contract', function () { + it('reverts', async function () { + await expectRevert(this.token.burn(unknownTokenId, { from: owner }), 'ERC721: invalid token ID'); + }); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js new file mode 100644 index 0000000..3d49228 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js @@ -0,0 +1,205 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC721ConsecutiveMock = artifacts.require('$ERC721ConsecutiveMock'); +const ERC721ConsecutiveEnumerableMock = artifacts.require('$ERC721ConsecutiveEnumerableMock'); +const ERC721ConsecutiveNoConstructorMintMock = artifacts.require('$ERC721ConsecutiveNoConstructorMintMock'); + +contract('ERC721Consecutive', function (accounts) { + const [user1, user2, user3, receiver] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const batches = [ + { receiver: user1, amount: 0 }, + { receiver: user1, amount: 3 }, + { receiver: user2, amount: 5 }, + { receiver: user3, amount: 0 }, + { receiver: user1, amount: 7 }, + ]; + const delegates = [user1, user3]; + + describe('with valid batches', function () { + beforeEach(async function () { + this.token = await ERC721ConsecutiveMock.new( + name, + symbol, + delegates, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ); + }); + + describe('minting during construction', function () { + it('events are emitted at construction', async function () { + let first = 0; + + for (const batch of batches) { + if (batch.amount > 0) { + await expectEvent.inConstruction(this.token, 'ConsecutiveTransfer', { + fromTokenId: web3.utils.toBN(first), + toTokenId: web3.utils.toBN(first + batch.amount - 1), + fromAddress: constants.ZERO_ADDRESS, + toAddress: batch.receiver, + }); + } else { + // expectEvent.notEmitted.inConstruction only looks at event name, and doesn't check the parameters + } + first += batch.amount; + } + }); + + it('ownership is set', async function () { + const owners = batches.flatMap(({ receiver, amount }) => Array(amount).fill(receiver)); + + for (const tokenId in owners) { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owners[tokenId]); + } + }); + + it('balance & voting power are set', async function () { + for (const account of accounts) { + const balance = batches + .filter(({ receiver }) => receiver === account) + .map(({ amount }) => amount) + .reduce((a, b) => a + b, 0); + + expect(await this.token.balanceOf(account)).to.be.bignumber.equal(web3.utils.toBN(balance)); + + // If not delegated at construction, check before + do delegation + if (!delegates.includes(account)) { + expect(await this.token.getVotes(account)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await this.token.delegate(account, { from: account }); + } + + // At this point all accounts should have delegated + expect(await this.token.getVotes(account)).to.be.bignumber.equal(web3.utils.toBN(balance)); + } + }); + }); + + describe('minting after construction', function () { + it('consecutive minting is not possible after construction', async function () { + await expectRevert( + this.token.$_mintConsecutive(user1, 10), + 'ERC721Consecutive: batch minting restricted to constructor', + ); + }); + + it('simple minting is possible after construction', async function () { + const tokenId = batches.reduce((acc, { amount }) => acc + amount, 0); + + expect(await this.token.$_exists(tokenId)).to.be.equal(false); + + expectEvent(await this.token.$_mint(user1, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + tokenId: tokenId.toString(), + }); + }); + + it('cannot mint a token that has been batched minted', async function () { + const tokenId = batches.reduce((acc, { amount }) => acc + amount, 0) - 1; + + expect(await this.token.$_exists(tokenId)).to.be.equal(true); + + await expectRevert(this.token.$_mint(user1, tokenId), 'ERC721: token already minted'); + }); + }); + + describe('ERC721 behavior', function () { + it('core takes over ownership on transfer', async function () { + await this.token.transferFrom(user1, receiver, 1, { from: user1 }); + + expect(await this.token.ownerOf(1)).to.be.equal(receiver); + }); + + it('tokens can be burned and re-minted #1', async function () { + expectEvent(await this.token.$_burn(1, { from: user1 }), 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + tokenId: '1', + }); + + await expectRevert(this.token.ownerOf(1), 'ERC721: invalid token ID'); + + expectEvent(await this.token.$_mint(user2, 1), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + tokenId: '1', + }); + + expect(await this.token.ownerOf(1)).to.be.equal(user2); + }); + + it('tokens can be burned and re-minted #2', async function () { + const tokenId = batches.reduce((acc, { amount }) => acc.addn(amount), web3.utils.toBN(0)); + + expect(await this.token.$_exists(tokenId)).to.be.equal(false); + await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID'); + + // mint + await this.token.$_mint(user1, tokenId); + + expect(await this.token.$_exists(tokenId)).to.be.equal(true); + expect(await this.token.ownerOf(tokenId), user1); + + // burn + expectEvent(await this.token.$_burn(tokenId, { from: user1 }), 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + tokenId, + }); + + expect(await this.token.$_exists(tokenId)).to.be.equal(false); + await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID'); + + // re-mint + expectEvent(await this.token.$_mint(user2, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + tokenId, + }); + + expect(await this.token.$_exists(tokenId)).to.be.equal(true); + expect(await this.token.ownerOf(tokenId), user2); + }); + }); + }); + + describe('invalid use', function () { + it('cannot mint a batch larger than 5000', async function () { + await expectRevert( + ERC721ConsecutiveMock.new(name, symbol, [], [user1], ['5001']), + 'ERC721Consecutive: batch too large', + ); + }); + + it('cannot use single minting during construction', async function () { + await expectRevert( + ERC721ConsecutiveNoConstructorMintMock.new(name, symbol), + "ERC721Consecutive: can't mint during construction", + ); + }); + + it('cannot use single minting during construction', async function () { + await expectRevert( + ERC721ConsecutiveNoConstructorMintMock.new(name, symbol), + "ERC721Consecutive: can't mint during construction", + ); + }); + + it('consecutive mint not compatible with enumerability', async function () { + await expectRevert( + ERC721ConsecutiveEnumerableMock.new( + name, + symbol, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ), + 'ERC721Enumerable: consecutive transfers not supported', + ); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js new file mode 100644 index 0000000..c7fc823 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js @@ -0,0 +1,92 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC721Pausable = artifacts.require('$ERC721Pausable'); + +contract('ERC721Pausable', function (accounts) { + const [owner, receiver, operator] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Pausable.new(name, symbol); + }); + + context('when token is paused', function () { + const firstTokenId = new BN(1); + const secondTokenId = new BN(1337); + + const mockData = '0x42'; + + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId, { from: owner }); + await this.token.$_pause(); + }); + + it('reverts when trying to transferFrom', async function () { + await expectRevert( + this.token.transferFrom(owner, receiver, firstTokenId, { from: owner }), + 'ERC721Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeTransferFrom', async function () { + await expectRevert( + this.token.safeTransferFrom(owner, receiver, firstTokenId, { from: owner }), + 'ERC721Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeTransferFrom with data', async function () { + await expectRevert( + this.token.methods['safeTransferFrom(address,address,uint256,bytes)'](owner, receiver, firstTokenId, mockData, { + from: owner, + }), + 'ERC721Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to mint', async function () { + await expectRevert(this.token.$_mint(receiver, secondTokenId), 'ERC721Pausable: token transfer while paused'); + }); + + it('reverts when trying to burn', async function () { + await expectRevert(this.token.$_burn(firstTokenId), 'ERC721Pausable: token transfer while paused'); + }); + + describe('getApproved', function () { + it('returns approved address', async function () { + const approvedAccount = await this.token.getApproved(firstTokenId); + expect(approvedAccount).to.equal(constants.ZERO_ADDRESS); + }); + }); + + describe('balanceOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const balance = await this.token.balanceOf(owner); + expect(balance).to.be.bignumber.equal('1'); + }); + }); + + describe('ownerOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const ownerOfToken = await this.token.ownerOf(firstTokenId); + expect(ownerOfToken).to.equal(owner); + }); + }); + + describe('exists', function () { + it('returns token existence', async function () { + expect(await this.token.$_exists(firstTokenId)).to.equal(true); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js new file mode 100644 index 0000000..1c0536b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js @@ -0,0 +1,41 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); + +const { shouldBehaveLikeERC2981 } = require('../../common/ERC2981.behavior'); + +const ERC721Royalty = artifacts.require('$ERC721Royalty'); + +contract('ERC721Royalty', function (accounts) { + const [account1, account2] = accounts; + const tokenId1 = new BN('1'); + const tokenId2 = new BN('2'); + const royalty = new BN('200'); + const salePrice = new BN('1000'); + + beforeEach(async function () { + this.token = await ERC721Royalty.new('My Token', 'TKN'); + + await this.token.$_mint(account1, tokenId1); + await this.token.$_mint(account1, tokenId2); + this.account1 = account1; + this.account2 = account2; + this.tokenId1 = tokenId1; + this.tokenId2 = tokenId2; + this.salePrice = salePrice; + }); + + describe('token specific functions', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(tokenId1, account1, royalty); + }); + + it('removes royalty information after burn', async function () { + await this.token.$_burn(tokenId1); + const tokenInfo = await this.token.royaltyInfo(tokenId1, salePrice); + + expect(tokenInfo[0]).to.be.equal(constants.ZERO_ADDRESS); + expect(tokenInfo[1]).to.be.bignumber.equal(new BN('0')); + }); + }); + + shouldBehaveLikeERC2981(); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js new file mode 100644 index 0000000..60c8006 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js @@ -0,0 +1,100 @@ +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) { + const [owner] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + const firstTokenId = new BN('5042'); + const nonExistentTokenId = new BN('13'); + + beforeEach(async function () { + this.token = await ERC721URIStorageMock.new(name, symbol); + }); + + shouldSupportInterfaces(['0x49064906']); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + }); + + const baseURI = 'https://api.example.com/v1/'; + const sampleUri = 'mock://mytoken'; + + it('it is empty by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expectRevert(this.token.tokenURI(nonExistentTokenId), 'ERC721: invalid token ID'); + }); + + it('can be set for a token id', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + 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), + 'ERC721URIStorage: URI set of nonexistent token', + ); + }); + + it('base URI can be set', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.$_baseURI()).to.equal(baseURI); + }); + + it('base URI is added as a prefix to the token URI', async function () { + await this.token.setBaseURI(baseURI); + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + sampleUri); + }); + + it('token URI can be changed by changing the base URI', async function () { + await this.token.setBaseURI(baseURI); + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + const newBaseURI = 'https://api.example.com/v2/'; + await this.token.setBaseURI(newBaseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + sampleUri); + }); + + it('tokenId is appended to base URI for tokens with no URI', async function () { + await this.token.setBaseURI(baseURI); + + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + firstTokenId); + }); + + it('tokens without URI can be burnt ', async function () { + await this.token.$_burn(firstTokenId, { from: owner }); + + expect(await this.token.$_exists(firstTokenId)).to.equal(false); + await expectRevert(this.token.tokenURI(firstTokenId), 'ERC721: invalid token ID'); + }); + + it('tokens with URI can be burnt ', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + await this.token.$_burn(firstTokenId, { from: owner }); + + expect(await this.token.$_exists(firstTokenId)).to.equal(false); + await expectRevert(this.token.tokenURI(firstTokenId), 'ERC721: invalid token ID'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js new file mode 100644 index 0000000..92032db --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js @@ -0,0 +1,184 @@ +/* eslint-disable */ + +const { BN, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { getChainId } = require('../../../helpers/chainid'); + +const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); + +const ERC721Votes = artifacts.require('$ERC721Votes'); + +contract('ERC721Votes', function (accounts) { + const [account1, account2, account1Delegatee, other1, other2] = accounts; + + const name = 'My Vote'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.chainId = await getChainId(); + + this.votes = await ERC721Votes.new(name, symbol, name, '1'); + + this.NFT0 = new BN('10000000000000000000000000'); + this.NFT1 = new BN('10'); + this.NFT2 = new BN('20'); + this.NFT3 = new BN('30'); + }); + + describe('balanceOf', function () { + beforeEach(async function () { + await this.votes.$_mint(account1, this.NFT0); + await this.votes.$_mint(account1, this.NFT1); + await this.votes.$_mint(account1, this.NFT2); + await this.votes.$_mint(account1, this.NFT3); + }); + + it('grants to initial account', async function () { + expect(await this.votes.balanceOf(account1)).to.be.bignumber.equal('4'); + }); + }); + + describe('transfers', function () { + beforeEach(async function () { + await this.votes.$_mint(account1, this.NFT0); + }); + + it('no delegation', async function () { + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.NFT0 }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('sender delegation', async function () { + await this.votes.delegate(account1, { from: account1 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.NFT0 }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0' }); + + 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.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('receiver delegation', async function () { + await this.votes.delegate(account2, { from: account2 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.NFT0 }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, 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.account1Votes = '0'; + this.account2Votes = '1'; + }); + + it('full delegation', async function () { + await this.votes.delegate(account1, { from: account1 }); + await this.votes.delegate(account2, { from: account2 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.NFT0 }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, 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.account1Votes = '0'; + this.account2Votes = '1'; + }); + + it('returns the same total supply on transfers', async function () { + await this.votes.delegate(account1, { from: account1 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.votes.getPastTotalSupply(receipt.blockNumber - 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(receipt.blockNumber + 1)).to.be.bignumber.equal('1'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + await this.votes.$_mint(account1, this.NFT1); + await this.votes.$_mint(account1, this.NFT2); + await this.votes.$_mint(account1, this.NFT3); + + const total = await this.votes.balanceOf(account1); + + const t1 = await this.votes.delegate(other1, { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.votes.transferFrom(account1, other2, this.NFT0, { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.votes.transferFrom(account1, other2, this.NFT2, { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.votes.transferFrom(other2, account1, this.NFT2, { from: other2 }); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal(total); + expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal(total); + expect(await this.votes.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t2.receipt.blockNumber + 1)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('2'); + expect(await this.votes.getPastVotes(other1, t3.receipt.blockNumber + 1)).to.be.bignumber.equal('2'); + expect(await this.votes.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t4.receipt.blockNumber + 1)).to.be.bignumber.equal('3'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + afterEach(async function () { + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(this.account1Votes); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(this.account2Votes); + + // 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.votes.getPastVotes(account1, blockNumber)).to.be.bignumber.equal(this.account1Votes); + expect(await this.votes.getPastVotes(account2, blockNumber)).to.be.bignumber.equal(this.account2Votes); + }); + }); + + describe('Voting workflow', function () { + beforeEach(async function () { + this.account1 = account1; + this.account1Delegatee = account1Delegatee; + this.account2 = account2; + this.name = 'My Vote'; + }); + + // includes EIP6372 behavior check + shouldBehaveLikeVotes(); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js new file mode 100644 index 0000000..6e46d2e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -0,0 +1,283 @@ +const { BN, expectEvent, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +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.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 () { + 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 () { + it('only allows calls from underlying', async function () { + await expectRevert( + this.token.onERC721Received( + initialHolder, + this.token.address, + firstTokenId, + anotherAccount, // Correct data + { from: anotherAccount }, + ), + 'ERC721Wrapper: caller is not underlying', + ); + }); + + it('mints a token to from', 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); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js new file mode 100644 index 0000000..0af614b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js @@ -0,0 +1,122 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +const { expect } = require('chai'); + +const ERC721PresetMinterPauserAutoId = artifacts.require('ERC721PresetMinterPauserAutoId'); + +contract('ERC721PresetMinterPauserAutoId', function (accounts) { + const [deployer, other] = accounts; + + const name = 'MinterAutoIDToken'; + const symbol = 'MAIT'; + const baseURI = 'my.app/'; + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const MINTER_ROLE = web3.utils.soliditySha3('MINTER_ROLE'); + + beforeEach(async function () { + this.token = await ERC721PresetMinterPauserAutoId.new(name, symbol, baseURI, { from: deployer }); + }); + + shouldSupportInterfaces(['ERC721', 'ERC721Enumerable', 'AccessControl', 'AccessControlEnumerable']); + + it('token has correct name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('token has correct symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('deployer has the default admin role', async function () { + expect(await this.token.getRoleMemberCount(DEFAULT_ADMIN_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(DEFAULT_ADMIN_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the minter role', async function () { + expect(await this.token.getRoleMemberCount(MINTER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(MINTER_ROLE, 0)).to.equal(deployer); + }); + + it('minter role admin is the default admin', async function () { + expect(await this.token.getRoleAdmin(MINTER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + describe('minting', function () { + it('deployer can mint tokens', async function () { + const tokenId = new BN('0'); + + const receipt = await this.token.mint(other, { from: deployer }); + expectEvent(receipt, 'Transfer', { from: ZERO_ADDRESS, to: other, tokenId }); + + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('1'); + expect(await this.token.ownerOf(tokenId)).to.equal(other); + + expect(await this.token.tokenURI(tokenId)).to.equal(baseURI + tokenId); + }); + + it('other accounts cannot mint tokens', async function () { + await expectRevert( + this.token.mint(other, { from: other }), + 'ERC721PresetMinterPauserAutoId: must have minter role to mint', + ); + }); + }); + + describe('pausing', function () { + it('deployer can pause', async function () { + const receipt = await this.token.pause({ from: deployer }); + expectEvent(receipt, 'Paused', { account: deployer }); + + expect(await this.token.paused()).to.equal(true); + }); + + it('deployer can unpause', async function () { + await this.token.pause({ from: deployer }); + + const receipt = await this.token.unpause({ from: deployer }); + expectEvent(receipt, 'Unpaused', { account: deployer }); + + expect(await this.token.paused()).to.equal(false); + }); + + it('cannot mint while paused', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert(this.token.mint(other, { from: deployer }), 'ERC721Pausable: token transfer while paused'); + }); + + it('other accounts cannot pause', async function () { + await expectRevert( + this.token.pause({ from: other }), + 'ERC721PresetMinterPauserAutoId: must have pauser role to pause', + ); + }); + + it('other accounts cannot unpause', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.unpause({ from: other }), + 'ERC721PresetMinterPauserAutoId: must have pauser role to unpause', + ); + }); + }); + + describe('burning', function () { + it('holders can burn their tokens', async function () { + const tokenId = new BN('0'); + + await this.token.mint(other, { from: deployer }); + + const receipt = await this.token.burn(tokenId, { from: other }); + + expectEvent(receipt, 'Transfer', { from: other, to: ZERO_ADDRESS, tokenId }); + + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('0'); + expect(await this.token.totalSupply()).to.be.bignumber.equal('0'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js new file mode 100644 index 0000000..0fd8222 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js @@ -0,0 +1,22 @@ +const { expect } = require('chai'); + +const ERC721Holder = artifacts.require('ERC721Holder'); +const ERC721 = artifacts.require('$ERC721'); + +contract('ERC721Holder', function (accounts) { + const [owner] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const tokenId = web3.utils.toBN(1); + + it('receives an ERC721 token', async function () { + const token = await ERC721.new(name, symbol); + await token.$_mint(owner, tokenId); + + const receiver = await ERC721Holder.new(); + await token.safeTransferFrom(owner, receiver.address, tokenId, { from: owner }); + + expect(await token.ownerOf(tokenId)).to.be.equal(receiver.address); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/ERC777.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/ERC777.behavior.js new file mode 100644 index 0000000..b1585bc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/ERC777.behavior.js @@ -0,0 +1,597 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const ERC777SenderRecipientMock = artifacts.require('ERC777SenderRecipientMock'); + +function shouldBehaveLikeERC777DirectSendBurn(holder, recipient, data) { + shouldBehaveLikeERC777DirectSend(holder, recipient, data); + shouldBehaveLikeERC777DirectBurn(holder, data); +} + +function shouldBehaveLikeERC777OperatorSendBurn(holder, recipient, operator, data, operatorData) { + shouldBehaveLikeERC777OperatorSend(holder, recipient, operator, data, operatorData); + shouldBehaveLikeERC777OperatorBurn(holder, operator, data, operatorData); +} + +function shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, recipient, operator, data, operatorData) { + shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, recipient, operator, data, operatorData); + shouldBehaveLikeERC777UnauthorizedOperatorBurn(holder, operator, data, operatorData); +} + +function shouldBehaveLikeERC777DirectSend(holder, recipient, data) { + describe('direct send', function () { + context('when the sender has tokens', function () { + shouldDirectSendTokens(holder, recipient, new BN('0'), data); + shouldDirectSendTokens(holder, recipient, new BN('1'), data); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(holder); + await expectRevert.unspecified(this.token.send(recipient, balance.addn(1), data, { from: holder })); + }); + + it('reverts when sending to the zero address', async function () { + await expectRevert.unspecified(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from: holder })); + }); + }); + + context('when the sender has no tokens', function () { + removeBalance(holder); + + shouldDirectSendTokens(holder, recipient, new BN('0'), data); + + it('reverts when sending a non-zero amount', async function () { + await expectRevert.unspecified(this.token.send(recipient, new BN('1'), data, { from: holder })); + }); + }); + }); +} + +function shouldBehaveLikeERC777OperatorSend(holder, recipient, operator, data, operatorData) { + describe('operator send', function () { + context('when the sender has tokens', async function () { + shouldOperatorSendTokens(holder, operator, recipient, new BN('0'), data, operatorData); + shouldOperatorSendTokens(holder, operator, recipient, new BN('1'), data, operatorData); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(holder); + await expectRevert.unspecified( + this.token.operatorSend(holder, recipient, balance.addn(1), data, operatorData, { from: operator }), + ); + }); + + it('reverts when sending to the zero address', async function () { + await expectRevert.unspecified( + this.token.operatorSend(holder, ZERO_ADDRESS, new BN('1'), data, operatorData, { from: operator }), + ); + }); + }); + + context('when the sender has no tokens', function () { + removeBalance(holder); + + shouldOperatorSendTokens(holder, operator, recipient, new BN('0'), data, operatorData); + + it('reverts when sending a non-zero amount', async function () { + await expectRevert.unspecified( + this.token.operatorSend(holder, recipient, new BN('1'), data, operatorData, { from: operator }), + ); + }); + + it('reverts when sending from the zero address', async function () { + // This is not yet reflected in the spec + await expectRevert.unspecified( + this.token.operatorSend(ZERO_ADDRESS, recipient, new BN('0'), data, operatorData, { from: operator }), + ); + }); + }); + }); +} + +function shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, recipient, operator, data, operatorData) { + describe('operator send', function () { + it('reverts', async function () { + await expectRevert.unspecified(this.token.operatorSend(holder, recipient, new BN('0'), data, operatorData)); + }); + }); +} + +function shouldBehaveLikeERC777DirectBurn(holder, data) { + describe('direct burn', function () { + context('when the sender has tokens', function () { + shouldDirectBurnTokens(holder, new BN('0'), data); + shouldDirectBurnTokens(holder, new BN('1'), data); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(holder); + await expectRevert.unspecified(this.token.burn(balance.addn(1), data, { from: holder })); + }); + }); + + context('when the sender has no tokens', function () { + removeBalance(holder); + + shouldDirectBurnTokens(holder, new BN('0'), data); + + it('reverts when burning a non-zero amount', async function () { + await expectRevert.unspecified(this.token.burn(new BN('1'), data, { from: holder })); + }); + }); + }); +} + +function shouldBehaveLikeERC777OperatorBurn(holder, operator, data, operatorData) { + describe('operator burn', function () { + context('when the sender has tokens', async function () { + shouldOperatorBurnTokens(holder, operator, new BN('0'), data, operatorData); + shouldOperatorBurnTokens(holder, operator, new BN('1'), data, operatorData); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(holder); + await expectRevert.unspecified( + this.token.operatorBurn(holder, balance.addn(1), data, operatorData, { from: operator }), + ); + }); + }); + + context('when the sender has no tokens', function () { + removeBalance(holder); + + shouldOperatorBurnTokens(holder, operator, new BN('0'), data, operatorData); + + it('reverts when burning a non-zero amount', async function () { + await expectRevert.unspecified( + this.token.operatorBurn(holder, new BN('1'), data, operatorData, { from: operator }), + ); + }); + + it('reverts when burning from the zero address', async function () { + // This is not yet reflected in the spec + await expectRevert.unspecified( + this.token.operatorBurn(ZERO_ADDRESS, new BN('0'), data, operatorData, { from: operator }), + ); + }); + }); + }); +} + +function shouldBehaveLikeERC777UnauthorizedOperatorBurn(holder, operator, data, operatorData) { + describe('operator burn', function () { + it('reverts', async function () { + await expectRevert.unspecified(this.token.operatorBurn(holder, new BN('0'), data, operatorData)); + }); + }); +} + +function shouldDirectSendTokens(from, to, amount, data) { + shouldSendTokens(from, null, to, amount, data, null); +} + +function shouldOperatorSendTokens(from, operator, to, amount, data, operatorData) { + shouldSendTokens(from, operator, to, amount, data, operatorData); +} + +function shouldSendTokens(from, operator, to, amount, data, operatorData) { + const operatorCall = operator !== null; + + it(`${operatorCall ? 'operator ' : ''}can send an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + const initialToBalance = await this.token.balanceOf(to); + + let receipt; + if (!operatorCall) { + receipt = await this.token.send(to, amount, data, { from }); + expectEvent(receipt, 'Sent', { + operator: from, + from, + to, + amount, + data, + operatorData: null, + }); + } else { + receipt = await this.token.operatorSend(from, to, amount, data, operatorData, { from: operator }); + expectEvent(receipt, 'Sent', { + operator, + from, + to, + amount, + data, + operatorData, + }); + } + + expectEvent(receipt, 'Transfer', { + from, + to, + value: amount, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + const finalToBalance = await this.token.balanceOf(to); + + expect(finalTotalSupply).to.be.bignumber.equal(initialTotalSupply); + expect(finalToBalance.sub(initialToBalance)).to.be.bignumber.equal(amount); + expect(finalFromBalance.sub(initialFromBalance)).to.be.bignumber.equal(amount.neg()); + }); +} + +function shouldDirectBurnTokens(from, amount, data) { + shouldBurnTokens(from, null, amount, data, null); +} + +function shouldOperatorBurnTokens(from, operator, amount, data, operatorData) { + shouldBurnTokens(from, operator, amount, data, operatorData); +} + +function shouldBurnTokens(from, operator, amount, data, operatorData) { + const operatorCall = operator !== null; + + it(`${operatorCall ? 'operator ' : ''}can burn an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + + let receipt; + if (!operatorCall) { + receipt = await this.token.burn(amount, data, { from }); + expectEvent(receipt, 'Burned', { + operator: from, + from, + amount, + data, + operatorData: null, + }); + } else { + receipt = await this.token.operatorBurn(from, amount, data, operatorData, { from: operator }); + expectEvent(receipt, 'Burned', { + operator, + from, + amount, + data, + operatorData, + }); + } + + expectEvent(receipt, 'Transfer', { + from, + to: ZERO_ADDRESS, + value: amount, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + + expect(finalTotalSupply.sub(initialTotalSupply)).to.be.bignumber.equal(amount.neg()); + expect(finalFromBalance.sub(initialFromBalance)).to.be.bignumber.equal(amount.neg()); + }); +} + +function shouldBehaveLikeERC777InternalMint(recipient, operator, amount, data, operatorData) { + shouldInternalMintTokens(operator, recipient, new BN('0'), data, operatorData); + shouldInternalMintTokens(operator, recipient, amount, data, operatorData); + + it('reverts when minting tokens for the zero address', async function () { + await expectRevert.unspecified( + this.token.$_mint(ZERO_ADDRESS, amount, data, operatorData, true, { from: operator }), + ); + }); +} + +function shouldInternalMintTokens(operator, to, amount, data, operatorData) { + it(`can (internal) mint an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialToBalance = await this.token.balanceOf(to); + + const receipt = await this.token.$_mint(to, amount, data, operatorData, true, { from: operator }); + + expectEvent(receipt, 'Minted', { + operator, + to, + amount, + data, + operatorData, + }); + + expectEvent(receipt, 'Transfer', { + from: ZERO_ADDRESS, + to, + value: amount, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalToBalance = await this.token.balanceOf(to); + + expect(finalTotalSupply.sub(initialTotalSupply)).to.be.bignumber.equal(amount); + expect(finalToBalance.sub(initialToBalance)).to.be.bignumber.equal(amount); + }); +} + +function shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData) { + context('when TokensRecipient reverts', function () { + beforeEach(async function () { + await this.tokensRecipientImplementer.setShouldRevertReceive(true); + }); + + it('send reverts', async function () { + await expectRevert.unspecified(sendFromHolder(this.token, this.sender, this.recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await expectRevert.unspecified( + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }), + ); + }); + + it('mint (internal) reverts', async function () { + await expectRevert.unspecified( + this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }), + ); + }); + }); + + context('when TokensRecipient does not revert', function () { + beforeEach(async function () { + await this.tokensRecipientImplementer.setShouldRevertSend(false); + }); + + it('TokensRecipient receives send data and is called after state mutation', async function () { + const { tx } = await sendFromHolder(this.token, this.sender, this.recipient, amount, data); + + const postSenderBalance = await this.token.balanceOf(this.sender); + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + this.sender, + this.sender, + this.recipient, + amount, + data, + null, + postSenderBalance, + postRecipientBalance, + ); + }); + + it('TokensRecipient receives operatorSend data and is called after state mutation', async function () { + const { tx } = await this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { + from: operator, + }); + + const postSenderBalance = await this.token.balanceOf(this.sender); + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + operator, + this.sender, + this.recipient, + amount, + data, + operatorData, + postSenderBalance, + postRecipientBalance, + ); + }); + + it('TokensRecipient receives mint (internal) data and is called after state mutation', async function () { + const { tx } = await this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }); + + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + operator, + ZERO_ADDRESS, + this.recipient, + amount, + data, + operatorData, + new BN('0'), + postRecipientBalance, + ); + }); + }); +} + +function shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData) { + context('when TokensSender reverts', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevertSend(true); + }); + + it('send reverts', async function () { + await expectRevert.unspecified(sendFromHolder(this.token, this.sender, this.recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await expectRevert.unspecified( + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }), + ); + }); + + it('burn reverts', async function () { + await expectRevert.unspecified(burnFromHolder(this.token, this.sender, amount, data)); + }); + + it('operatorBurn reverts', async function () { + await expectRevert.unspecified( + this.token.operatorBurn(this.sender, amount, data, operatorData, { from: operator }), + ); + }); + }); + + context('when TokensSender does not revert', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevertSend(false); + }); + + it('TokensSender receives send data and is called before state mutation', async function () { + const preSenderBalance = await this.token.balanceOf(this.sender); + const preRecipientBalance = await this.token.balanceOf(this.recipient); + + const { tx } = await sendFromHolder(this.token, this.sender, this.recipient, amount, data); + + await assertTokensToSendCalled( + this.token, + tx, + this.sender, + this.sender, + this.recipient, + amount, + data, + null, + preSenderBalance, + preRecipientBalance, + ); + }); + + it('TokensSender receives operatorSend data and is called before state mutation', async function () { + const preSenderBalance = await this.token.balanceOf(this.sender); + const preRecipientBalance = await this.token.balanceOf(this.recipient); + + const { tx } = await this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { + from: operator, + }); + + await assertTokensToSendCalled( + this.token, + tx, + operator, + this.sender, + this.recipient, + amount, + data, + operatorData, + preSenderBalance, + preRecipientBalance, + ); + }); + + it('TokensSender receives burn data and is called before state mutation', async function () { + const preSenderBalance = await this.token.balanceOf(this.sender); + + const { tx } = await burnFromHolder(this.token, this.sender, amount, data, { from: this.sender }); + + await assertTokensToSendCalled( + this.token, + tx, + this.sender, + this.sender, + ZERO_ADDRESS, + amount, + data, + null, + preSenderBalance, + ); + }); + + it('TokensSender receives operatorBurn data and is called before state mutation', async function () { + const preSenderBalance = await this.token.balanceOf(this.sender); + + const { tx } = await this.token.operatorBurn(this.sender, amount, data, operatorData, { from: operator }); + + await assertTokensToSendCalled( + this.token, + tx, + operator, + this.sender, + ZERO_ADDRESS, + amount, + data, + operatorData, + preSenderBalance, + ); + }); + }); +} + +function removeBalance(holder) { + beforeEach(async function () { + await this.token.burn(await this.token.balanceOf(holder), '0x', { from: holder }); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + }); +} + +async function assertTokensReceivedCalled( + token, + txHash, + operator, + from, + to, + amount, + data, + operatorData, + fromBalance, + toBalance = '0', +) { + await expectEvent.inTransaction(txHash, ERC777SenderRecipientMock, 'TokensReceivedCalled', { + operator, + from, + to, + amount, + data, + operatorData, + token: token.address, + fromBalance, + toBalance, + }); +} + +async function assertTokensToSendCalled( + token, + txHash, + operator, + from, + to, + amount, + data, + operatorData, + fromBalance, + toBalance = '0', +) { + await expectEvent.inTransaction(txHash, ERC777SenderRecipientMock, 'TokensToSendCalled', { + operator, + from, + to, + amount, + data, + operatorData, + token: token.address, + fromBalance, + toBalance, + }); +} + +async function sendFromHolder(token, holder, to, amount, data) { + if ((await web3.eth.getCode(holder)).length <= '0x'.length) { + return token.send(to, amount, data, { from: holder }); + } else { + // assume holder is ERC777SenderRecipientMock contract + return (await ERC777SenderRecipientMock.at(holder)).send(token.address, to, amount, data); + } +} + +async function burnFromHolder(token, holder, amount, data) { + if ((await web3.eth.getCode(holder)).length <= '0x'.length) { + return token.burn(amount, data, { from: holder }); + } else { + // assume holder is ERC777SenderRecipientMock contract + return (await ERC777SenderRecipientMock.at(holder)).burn(token.address, amount, data); + } +} + +module.exports = { + shouldBehaveLikeERC777DirectSendBurn, + shouldBehaveLikeERC777OperatorSendBurn, + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, + shouldBehaveLikeERC777InternalMint, + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook, + shouldBehaveLikeERC777SendBurnWithSendHook, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/ERC777.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/ERC777.test.js new file mode 100644 index 0000000..44bc253 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/ERC777.test.js @@ -0,0 +1,556 @@ +const { BN, constants, expectEvent, expectRevert, singletons } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const { + shouldBehaveLikeERC777DirectSendBurn, + shouldBehaveLikeERC777OperatorSendBurn, + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, + shouldBehaveLikeERC777InternalMint, + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook, + shouldBehaveLikeERC777SendBurnWithSendHook, +} = require('./ERC777.behavior'); + +const { shouldBehaveLikeERC20, shouldBehaveLikeERC20Approve } = require('../ERC20/ERC20.behavior'); + +const ERC777 = artifacts.require('$ERC777Mock'); +const ERC777SenderRecipientMock = artifacts.require('$ERC777SenderRecipientMock'); + +contract('ERC777', function (accounts) { + const [registryFunder, holder, defaultOperatorA, defaultOperatorB, newOperator, anyone] = accounts; + + const initialSupply = new BN('10000'); + const name = 'ERC777Test'; + const symbol = '777T'; + const data = web3.utils.sha3('OZ777TestData'); + const operatorData = web3.utils.sha3('OZ777TestOperatorData'); + + const defaultOperators = [defaultOperatorA, defaultOperatorB]; + + beforeEach(async function () { + this.erc1820 = await singletons.ERC1820Registry(registryFunder); + }); + + context('with default operators', function () { + beforeEach(async function () { + this.token = await ERC777.new(name, symbol, defaultOperators); + await this.token.$_mint(holder, initialSupply, '0x', '0x'); + }); + + describe('as an ERC20 token', function () { + shouldBehaveLikeERC20('ERC777', initialSupply, holder, anyone, defaultOperatorA); + + describe('_approve', function () { + shouldBehaveLikeERC20Approve('ERC777', holder, anyone, initialSupply, function (owner, spender, amount) { + return this.token.$_approve(owner, spender, amount); + }); + + describe('when the owner is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.token.$_approve(ZERO_ADDRESS, anyone, initialSupply), + 'ERC777: approve from the zero address', + ); + }); + }); + }); + }); + + it('does not emit AuthorizedOperator events for default operators', async function () { + await expectEvent.notEmitted.inConstruction(this.token, 'AuthorizedOperator'); + }); + + describe('basic information', function () { + it('returns the name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('returns the symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('returns a granularity of 1', async function () { + expect(await this.token.granularity()).to.be.bignumber.equal('1'); + }); + + it('returns the default operators', async function () { + expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators); + }); + + it('default operators are operators for all accounts', async function () { + for (const operator of defaultOperators) { + expect(await this.token.isOperatorFor(operator, anyone)).to.equal(true); + } + }); + + it('returns the total supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + + it('returns 18 when decimals is called', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('18'); + }); + + it('the ERC777Token interface is registered in the registry', async function () { + expect( + await this.erc1820.getInterfaceImplementer(this.token.address, web3.utils.soliditySha3('ERC777Token')), + ).to.equal(this.token.address); + }); + + it('the ERC20Token interface is registered in the registry', async function () { + expect( + await this.erc1820.getInterfaceImplementer(this.token.address, web3.utils.soliditySha3('ERC20Token')), + ).to.equal(this.token.address); + }); + }); + + describe('balanceOf', function () { + context('for an account with no tokens', function () { + it('returns zero', async function () { + expect(await this.token.balanceOf(anyone)).to.be.bignumber.equal('0'); + }); + }); + + context('for an account with tokens', function () { + it('returns their balance', async function () { + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply); + }); + }); + }); + + context('with no ERC777TokensSender and no ERC777TokensRecipient implementers', function () { + describe('send/burn', function () { + shouldBehaveLikeERC777DirectSendBurn(holder, anyone, data); + + context('with self operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, holder, data, operatorData); + }); + + context('with first default operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorA, data, operatorData); + }); + + context('with second default operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorB, data, operatorData); + }); + + context('before authorizing a new operator', function () { + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); + }); + + context('with new authorized operator', function () { + beforeEach(async function () { + await this.token.authorizeOperator(newOperator, { from: holder }); + }); + + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, newOperator, data, operatorData); + + context('with revoked operator', function () { + beforeEach(async function () { + await this.token.revokeOperator(newOperator, { from: holder }); + }); + + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); + }); + }); + }); + + describe('mint (internal)', function () { + const to = anyone; + const amount = new BN('5'); + + context('with default operator', function () { + const operator = defaultOperatorA; + + shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); + }); + + context('with non operator', function () { + const operator = newOperator; + + shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); + }); + }); + + describe('mint (internal extended)', function () { + const amount = new BN('5'); + + context('to anyone', function () { + beforeEach(async function () { + this.recipient = anyone; + }); + + context('with default operator', function () { + const operator = defaultOperatorA; + + it('without requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, false, { from: operator }); + }); + + it('with requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }); + }); + }); + + context('with non operator', function () { + const operator = newOperator; + + it('without requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, false, { from: operator }); + }); + + it('with requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }); + }); + }); + }); + + context('to non ERC777TokensRecipient implementer', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = this.tokensRecipientImplementer.address; + }); + + context('with default operator', function () { + const operator = defaultOperatorA; + + it('without requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, false, { from: operator }); + }); + + it('with requireReceptionAck', async function () { + await expectRevert( + this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + }); + + context('with non operator', function () { + const operator = newOperator; + + it('without requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, false, { from: operator }); + }); + + it('with requireReceptionAck', async function () { + await expectRevert( + this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + }); + }); + }); + }); + + describe('operator management', function () { + it('accounts are their own operator', async function () { + expect(await this.token.isOperatorFor(holder, holder)).to.equal(true); + }); + + it('reverts when self-authorizing', async function () { + await expectRevert( + this.token.authorizeOperator(holder, { from: holder }), + 'ERC777: authorizing self as operator', + ); + }); + + it('reverts when self-revoking', async function () { + await expectRevert(this.token.revokeOperator(holder, { from: holder }), 'ERC777: revoking self as operator'); + }); + + it('non-operators can be revoked', async function () { + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(false); + + const receipt = await this.token.revokeOperator(newOperator, { from: holder }); + expectEvent(receipt, 'RevokedOperator', { operator: newOperator, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(false); + }); + + it('non-operators can be authorized', async function () { + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(false); + + const receipt = await this.token.authorizeOperator(newOperator, { from: holder }); + expectEvent(receipt, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(true); + }); + + describe('new operators', function () { + beforeEach(async function () { + await this.token.authorizeOperator(newOperator, { from: holder }); + }); + + it('are not added to the default operators list', async function () { + expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators); + }); + + it('can be re-authorized', async function () { + const receipt = await this.token.authorizeOperator(newOperator, { from: holder }); + expectEvent(receipt, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(true); + }); + + it('can be revoked', async function () { + const receipt = await this.token.revokeOperator(newOperator, { from: holder }); + expectEvent(receipt, 'RevokedOperator', { operator: newOperator, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(false); + }); + }); + + describe('default operators', function () { + it('can be re-authorized', async function () { + const receipt = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); + expectEvent(receipt, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(defaultOperatorA, holder)).to.equal(true); + }); + + it('can be revoked', async function () { + const receipt = await this.token.revokeOperator(defaultOperatorA, { from: holder }); + expectEvent(receipt, 'RevokedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(defaultOperatorA, holder)).to.equal(false); + }); + + it('cannot be revoked for themselves', async function () { + await expectRevert( + this.token.revokeOperator(defaultOperatorA, { from: defaultOperatorA }), + 'ERC777: revoking self as operator', + ); + }); + + context('with revoked default operator', function () { + beforeEach(async function () { + await this.token.revokeOperator(defaultOperatorA, { from: holder }); + }); + + it('default operator is not revoked for other holders', async function () { + expect(await this.token.isOperatorFor(defaultOperatorA, anyone)).to.equal(true); + }); + + it('other default operators are not revoked', async function () { + expect(await this.token.isOperatorFor(defaultOperatorB, holder)).to.equal(true); + }); + + it('default operators list is not modified', async function () { + expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators); + }); + + it('revoked default operator can be re-authorized', async function () { + const receipt = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); + expectEvent(receipt, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(defaultOperatorA, holder)).to.equal(true); + }); + }); + }); + }); + + describe('send and receive hooks', function () { + const amount = new BN('1'); + const operator = defaultOperatorA; + // sender and recipient are stored inside 'this', since in some tests their addresses are determined dynamically + + describe('tokensReceived', function () { + beforeEach(function () { + this.sender = holder; + }); + + context('with no ERC777TokensRecipient implementer', function () { + context('with contract recipient', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = this.tokensRecipientImplementer.address; + + // Note that tokensRecipientImplementer doesn't implement the recipient interface for the recipient + }); + + it('send reverts', async function () { + await expectRevert( + this.token.send(this.recipient, amount, data, { from: holder }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + + it('operatorSend reverts', async function () { + await expectRevert( + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + + it('mint (internal) reverts', async function () { + await expectRevert( + this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + + it('(ERC20) transfer succeeds', async function () { + await this.token.transfer(this.recipient, amount, { from: holder }); + }); + + it('(ERC20) transferFrom succeeds', async function () { + const approved = anyone; + await this.token.approve(approved, amount, { from: this.sender }); + await this.token.transferFrom(this.sender, this.recipient, amount, { from: approved }); + }); + }); + }); + + context('with ERC777TokensRecipient implementer', function () { + context('with contract as implementer for an externally owned account', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = anyone; + + await this.tokensRecipientImplementer.recipientFor(this.recipient); + + await this.erc1820.setInterfaceImplementer( + this.recipient, + web3.utils.soliditySha3('ERC777TokensRecipient'), + this.tokensRecipientImplementer.address, + { from: this.recipient }, + ); + }); + + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); + }); + + context('with contract as implementer for another contract', function () { + beforeEach(async function () { + this.recipientContract = await ERC777SenderRecipientMock.new(); + this.recipient = this.recipientContract.address; + + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + await this.tokensRecipientImplementer.recipientFor(this.recipient); + await this.recipientContract.registerRecipient(this.tokensRecipientImplementer.address); + }); + + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); + }); + + context('with contract as implementer for itself', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = this.tokensRecipientImplementer.address; + + await this.tokensRecipientImplementer.recipientFor(this.recipient); + }); + + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); + }); + }); + }); + + describe('tokensToSend', function () { + beforeEach(function () { + this.recipient = anyone; + }); + + context('with a contract as implementer for an externally owned account', function () { + beforeEach(async function () { + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + this.sender = holder; + + await this.tokensSenderImplementer.senderFor(this.sender); + + await this.erc1820.setInterfaceImplementer( + this.sender, + web3.utils.soliditySha3('ERC777TokensSender'), + this.tokensSenderImplementer.address, + { from: this.sender }, + ); + }); + + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); + }); + + context('with contract as implementer for another contract', function () { + beforeEach(async function () { + this.senderContract = await ERC777SenderRecipientMock.new(); + this.sender = this.senderContract.address; + + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + await this.tokensSenderImplementer.senderFor(this.sender); + await this.senderContract.registerSender(this.tokensSenderImplementer.address); + + // For the contract to be able to receive tokens (that it can later send), it must also implement the + // recipient interface. + + await this.senderContract.recipientFor(this.sender); + await this.token.send(this.sender, amount, data, { from: holder }); + }); + + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); + }); + + context('with a contract as implementer for itself', function () { + beforeEach(async function () { + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + this.sender = this.tokensSenderImplementer.address; + + await this.tokensSenderImplementer.senderFor(this.sender); + + // For the contract to be able to receive tokens (that it can later send), it must also implement the + // recipient interface. + + await this.tokensSenderImplementer.recipientFor(this.sender); + await this.token.send(this.sender, amount, data, { from: holder }); + }); + + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); + }); + }); + }); + }); + + context('with no default operators', function () { + beforeEach(async function () { + this.token = await ERC777.new(name, symbol, []); + }); + + it('default operators list is empty', async function () { + expect(await this.token.defaultOperators()).to.deep.equal([]); + }); + }); + + describe('relative order of hooks', function () { + beforeEach(async function () { + await singletons.ERC1820Registry(registryFunder); + this.sender = await ERC777SenderRecipientMock.new(); + await this.sender.registerRecipient(this.sender.address); + await this.sender.registerSender(this.sender.address); + this.token = await ERC777.new(name, symbol, []); + await this.token.$_mint(this.sender.address, 1, '0x', '0x'); + }); + + it('send', async function () { + const { receipt } = await this.sender.send(this.token.address, anyone, 1, '0x'); + + const internalBeforeHook = receipt.logs.findIndex(l => l.event === 'BeforeTokenTransfer'); + expect(internalBeforeHook).to.be.gte(0); + const externalSendHook = receipt.logs.findIndex(l => l.event === 'TokensToSendCalled'); + expect(externalSendHook).to.be.gte(0); + + expect(externalSendHook).to.be.lt(internalBeforeHook); + }); + + it('burn', async function () { + const { receipt } = await this.sender.burn(this.token.address, 1, '0x'); + + const internalBeforeHook = receipt.logs.findIndex(l => l.event === 'BeforeTokenTransfer'); + expect(internalBeforeHook).to.be.gte(0); + const externalSendHook = receipt.logs.findIndex(l => l.event === 'TokensToSendCalled'); + expect(externalSendHook).to.be.gte(0); + + expect(externalSendHook).to.be.lt(internalBeforeHook); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js new file mode 100644 index 0000000..e6a842b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js @@ -0,0 +1,49 @@ +const { BN, singletons } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC777PresetFixedSupply = artifacts.require('ERC777PresetFixedSupply'); + +contract('ERC777PresetFixedSupply', function (accounts) { + const [registryFunder, owner, defaultOperatorA, defaultOperatorB, anyone] = accounts; + + const initialSupply = new BN('10000'); + const name = 'ERC777Preset'; + const symbol = '777P'; + + const defaultOperators = [defaultOperatorA, defaultOperatorB]; + + before(async function () { + await singletons.ERC1820Registry(registryFunder); + }); + + beforeEach(async function () { + this.token = await ERC777PresetFixedSupply.new(name, symbol, defaultOperators, initialSupply, owner); + }); + + it('returns the name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('returns the symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('returns the default operators', async function () { + expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators); + }); + + it('default operators are operators for all accounts', async function () { + for (const operator of defaultOperators) { + expect(await this.token.isOperatorFor(operator, anyone)).to.equal(true); + } + }); + + it('returns the total supply equal to initial supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + + it('returns the balance of owner equal to initial supply', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialSupply); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js new file mode 100644 index 0000000..5d0f677 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js @@ -0,0 +1,157 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +function shouldBehaveLikeERC2981() { + const royaltyFraction = new BN('10'); + + shouldSupportInterfaces(['ERC2981']); + + describe('default royalty', function () { + beforeEach(async function () { + await this.token.$_setDefaultRoyalty(this.account1, royaltyFraction); + }); + + it('checks royalty is set', async function () { + const royalty = new BN((this.salePrice * royaltyFraction) / 10000); + + const initInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(initInfo[0]).to.be.equal(this.account1); + expect(initInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('updates royalty amount', async function () { + const newPercentage = new BN('25'); + + // Updated royalty check + await this.token.$_setDefaultRoyalty(this.account1, newPercentage); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + const newInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(newInfo[0]).to.be.equal(this.account1); + expect(newInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('holds same royalty value for different tokens', async function () { + const newPercentage = new BN('20'); + await this.token.$_setDefaultRoyalty(this.account1, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + + expect(token1Info[1]).to.be.bignumber.equal(token2Info[1]); + }); + + it('Remove royalty information', async function () { + const newValue = new BN('0'); + await this.token.$_deleteDefaultRoyalty(); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Test royalty info is still persistent across all tokens + expect(token1Info[0]).to.be.bignumber.equal(token2Info[0]); + expect(token1Info[1]).to.be.bignumber.equal(token2Info[1]); + // Test information was deleted + expect(token1Info[0]).to.be.equal(ZERO_ADDRESS); + expect(token1Info[1]).to.be.bignumber.equal(newValue); + }); + + it('reverts if invalid parameters', async function () { + await expectRevert(this.token.$_setDefaultRoyalty(ZERO_ADDRESS, royaltyFraction), 'ERC2981: invalid receiver'); + + await expectRevert( + this.token.$_setDefaultRoyalty(this.account1, new BN('11000')), + 'ERC2981: royalty fee will exceed salePrice', + ); + }); + }); + + describe('token based royalty', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, royaltyFraction); + }); + + it('updates royalty amount', async function () { + const newPercentage = new BN('25'); + let royalty = new BN((this.salePrice * royaltyFraction) / 10000); + // Initial royalty check + const initInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(initInfo[0]).to.be.equal(this.account1); + expect(initInfo[1]).to.be.bignumber.equal(royalty); + + // Updated royalty check + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, newPercentage); + royalty = new BN((this.salePrice * newPercentage) / 10000); + const newInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(newInfo[0]).to.be.equal(this.account1); + expect(newInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('holds different values for different tokens', async function () { + const newPercentage = new BN('20'); + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + + // must be different even at the same this.salePrice + expect(token1Info[1]).to.not.be.equal(token2Info.royaltyFraction); + }); + + it('reverts if invalid parameters', async function () { + await expectRevert( + this.token.$_setTokenRoyalty(this.tokenId1, ZERO_ADDRESS, royaltyFraction), + 'ERC2981: Invalid parameters', + ); + + await expectRevert( + this.token.$_setTokenRoyalty(this.tokenId1, this.account1, new BN('11000')), + 'ERC2981: royalty fee will exceed salePrice', + ); + }); + + it('can reset token after setting royalty', async function () { + const newPercentage = new BN('30'); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + await this.token.$_setTokenRoyalty(this.tokenId1, this.account2, newPercentage); + + const tokenInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + // Tokens must have own information + expect(tokenInfo[1]).to.be.bignumber.equal(royalty); + expect(tokenInfo[0]).to.be.equal(this.account2); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, new BN('0')); + const result = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Token must not share default information + expect(result[0]).to.be.equal(this.account1); + expect(result[1]).to.be.bignumber.equal(new BN('0')); + }); + + it('can hold default and token royalty information', async function () { + const newPercentage = new BN('30'); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account2, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Tokens must not have same values + expect(token1Info[1]).to.not.be.bignumber.equal(token2Info[1]); + expect(token1Info[0]).to.not.be.equal(token2Info[0]); + + // Updated token must have new values + expect(token2Info[0]).to.be.equal(this.account2); + expect(token2Info[1]).to.be.bignumber.equal(royalty); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC2981, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Address.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Address.test.js new file mode 100644 index 0000000..a78ae14 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Address.test.js @@ -0,0 +1,321 @@ +const { balance, constants, ether, expectRevert, send, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Address = artifacts.require('$Address'); +const EtherReceiver = artifacts.require('EtherReceiverMock'); +const CallReceiverMock = artifacts.require('CallReceiverMock'); + +contract('Address', function (accounts) { + const [recipient, other] = accounts; + + beforeEach(async function () { + this.mock = await Address.new(); + }); + + describe('isContract', function () { + it('returns false for account address', async function () { + expect(await this.mock.$isContract(other)).to.equal(false); + }); + + it('returns true for contract address', async function () { + expect(await this.mock.$isContract(this.mock.address)).to.equal(true); + }); + }); + + describe('sendValue', function () { + beforeEach(async function () { + this.recipientTracker = await balance.tracker(recipient); + }); + + context('when sender contract has no funds', function () { + it('sends 0 wei', async function () { + await this.mock.$sendValue(other, 0); + + expect(await this.recipientTracker.delta()).to.be.bignumber.equal('0'); + }); + + it('reverts when sending non-zero amounts', async function () { + await expectRevert(this.mock.$sendValue(other, 1), 'Address: insufficient balance'); + }); + }); + + context('when sender contract has funds', function () { + const funds = ether('1'); + beforeEach(async function () { + await send.ether(other, this.mock.address, funds); + }); + + it('sends 0 wei', async function () { + await this.mock.$sendValue(recipient, 0); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal('0'); + }); + + it('sends non-zero amounts', async function () { + await this.mock.$sendValue(recipient, funds.subn(1)); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal(funds.subn(1)); + }); + + it('sends the whole balance', async function () { + await this.mock.$sendValue(recipient, funds); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal(funds); + expect(await balance.current(this.mock.address)).to.be.bignumber.equal('0'); + }); + + it('reverts when sending more than the balance', async function () { + await expectRevert(this.mock.$sendValue(recipient, funds.addn(1)), 'Address: insufficient balance'); + }); + + context('with contract recipient', function () { + beforeEach(async function () { + this.target = await EtherReceiver.new(); + }); + + it('sends funds', async function () { + const tracker = await balance.tracker(this.target.address); + + await this.target.setAcceptEther(true); + await this.mock.$sendValue(this.target.address, funds); + + expect(await tracker.delta()).to.be.bignumber.equal(funds); + }); + + it('reverts on recipient revert', async function () { + await this.target.setAcceptEther(false); + await expectRevert( + this.mock.$sendValue(this.target.address, funds), + 'Address: unable to send value, recipient may have reverted', + ); + }); + }); + }); + }); + + describe('functionCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + context('with valid contract receiver', function () { + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const receipt = await this.mock.$functionCall(this.target.address, abiEncodedCall); + + expectEvent(receipt, 'return$functionCall_address_bytes', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + 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(); + + await expectRevert( + this.mock.$functionCall(this.target.address, abiEncodedCall), + 'Address: low-level call failed', + ); + }); + + it('reverts when the called function reverts, bubbling up the revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert(this.mock.$functionCall(this.target.address, abiEncodedCall), 'CallReceiverMock: reverting'); + }); + + it('reverts when the called function runs out of gas', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionOutOfGas().encodeABI(); + + await expectRevert( + this.mock.$functionCall(this.target.address, abiEncodedCall, { gas: '120000' }), + 'Address: low-level call failed', + ); + }); + + it('reverts when the called function throws', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionThrows().encodeABI(); + + await expectRevert.unspecified(this.mock.$functionCall(this.target.address, abiEncodedCall)); + }); + + it('reverts when function does not exist', async function () { + const abiEncodedCall = web3.eth.abi.encodeFunctionCall( + { + name: 'mockFunctionDoesNotExist', + type: 'function', + inputs: [], + }, + [], + ); + + await expectRevert( + this.mock.$functionCall(this.target.address, abiEncodedCall), + 'Address: low-level call failed', + ); + }); + }); + + context('with non-contract receiver', function () { + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevert(this.mock.$functionCall(recipient, abiEncodedCall), 'Address: call to non-contract'); + }); + }); + }); + + describe('functionCallWithValue', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + context('with zero value', function () { + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, 0); + expectEvent(receipt, 'return$functionCallWithValue_address_bytes_uint256', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + }); + }); + + context('with non-zero value', function () { + const amount = ether('1.2'); + + it('reverts if insufficient sender balance', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevert( + this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount), + 'Address: insufficient balance for call', + ); + }); + + it('calls the requested function with existing value', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const tracker = await balance.tracker(this.target.address); + + await send.ether(other, this.mock.address, amount); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount); + expectEvent(receipt, 'return$functionCallWithValue_address_bytes_uint256', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + + expect(await tracker.delta()).to.be.bignumber.equal(amount); + }); + + it('calls the requested function with transaction funds', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const tracker = await balance.tracker(this.target.address); + + expect(await balance.current(this.mock.address)).to.be.bignumber.equal('0'); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount, { + from: other, + value: amount, + }); + expectEvent(receipt, 'return$functionCallWithValue_address_bytes_uint256', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + + expect(await tracker.delta()).to.be.bignumber.equal(amount); + }); + + it('reverts when calling non-payable functions', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionNonPayable().encodeABI(); + + await send.ether(other, this.mock.address, amount); + await expectRevert( + this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount), + 'Address: low-level call with value failed', + ); + }); + }); + }); + + describe('functionStaticCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockStaticFunction().encodeABI(); + + expect(await this.mock.$functionStaticCall(this.target.address, abiEncodedCall)).to.be.equal( + web3.eth.abi.encodeParameters(['string'], ['0x1234']), + ); + }); + + it('reverts on a non-static function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevert( + this.mock.$functionStaticCall(this.target.address, abiEncodedCall), + 'Address: low-level static call failed', + ); + }); + + it('bubbles up revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert( + this.mock.$functionStaticCall(this.target.address, abiEncodedCall), + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevert(this.mock.$functionStaticCall(recipient, abiEncodedCall), 'Address: call to non-contract'); + }); + }); + + describe('functionDelegateCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + it('delegate calls the requested function', async function () { + // pseudorandom values + const slot = '0x93e4c53af435ddf777c3de84bb9a953a777788500e229a468ea1036496ab66a0'; + const value = '0x6a465d1c49869f71fb65562bcbd7e08c8044074927f0297127203f2a9924ff5b'; + + const abiEncodedCall = this.target.contract.methods.mockFunctionWritesStorage(slot, value).encodeABI(); + + expect(await web3.eth.getStorageAt(this.mock.address, slot)).to.be.equal(constants.ZERO_BYTES32); + + expectEvent( + await this.mock.$functionDelegateCall(this.target.address, abiEncodedCall), + 'return$functionDelegateCall_address_bytes', + { ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']) }, + ); + + expect(await web3.eth.getStorageAt(this.mock.address, slot)).to.be.equal(value); + }); + + it('bubbles up revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert( + this.mock.$functionDelegateCall(this.target.address, abiEncodedCall), + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevert(this.mock.$functionDelegateCall(recipient, abiEncodedCall), 'Address: call to non-contract'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Arrays.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Arrays.test.js new file mode 100644 index 0000000..d939d59 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Arrays.test.js @@ -0,0 +1,123 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const AddressArraysMock = artifacts.require('AddressArraysMock'); +const Bytes32ArraysMock = artifacts.require('Bytes32ArraysMock'); +const Uint256ArraysMock = artifacts.require('Uint256ArraysMock'); + +contract('Arrays', function () { + describe('findUpperBound', function () { + context('Even number of elements', function () { + const EVEN_ELEMENTS_ARRAY = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(EVEN_ELEMENTS_ARRAY); + }); + + it('returns correct index for the basic case', async function () { + expect(await this.arrays.findUpperBound(16)).to.be.bignumber.equal('5'); + }); + + it('returns 0 for the first element', async function () { + expect(await this.arrays.findUpperBound(11)).to.be.bignumber.equal('0'); + }); + + it('returns index of the last element', async function () { + expect(await this.arrays.findUpperBound(20)).to.be.bignumber.equal('9'); + }); + + it('returns first index after last element if searched value is over the upper boundary', async function () { + expect(await this.arrays.findUpperBound(32)).to.be.bignumber.equal('10'); + }); + + it('returns 0 for the element under the lower boundary', async function () { + expect(await this.arrays.findUpperBound(2)).to.be.bignumber.equal('0'); + }); + }); + + context('Odd number of elements', function () { + const ODD_ELEMENTS_ARRAY = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(ODD_ELEMENTS_ARRAY); + }); + + it('returns correct index for the basic case', async function () { + expect(await this.arrays.findUpperBound(16)).to.be.bignumber.equal('5'); + }); + + it('returns 0 for the first element', async function () { + expect(await this.arrays.findUpperBound(11)).to.be.bignumber.equal('0'); + }); + + it('returns index of the last element', async function () { + expect(await this.arrays.findUpperBound(21)).to.be.bignumber.equal('10'); + }); + + it('returns first index after last element if searched value is over the upper boundary', async function () { + expect(await this.arrays.findUpperBound(32)).to.be.bignumber.equal('11'); + }); + + it('returns 0 for the element under the lower boundary', async function () { + expect(await this.arrays.findUpperBound(2)).to.be.bignumber.equal('0'); + }); + }); + + context('Array with gap', function () { + const WITH_GAP_ARRAY = [11, 12, 13, 14, 15, 20, 21, 22, 23, 24]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(WITH_GAP_ARRAY); + }); + + it('returns index of first element in next filled range', async function () { + expect(await this.arrays.findUpperBound(17)).to.be.bignumber.equal('5'); + }); + }); + + context('Empty array', function () { + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new([]); + }); + + it('always returns 0 for empty array', async function () { + expect(await this.arrays.findUpperBound(10)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('unsafeAccess', function () { + for (const { type, artifact, elements } of [ + { + type: 'address', + artifact: AddressArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(20)), + }, + { + type: 'bytes32', + artifact: Bytes32ArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(32)), + }, + { + type: 'uint256', + artifact: Uint256ArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(32)), + }, + ]) { + it(type, async function () { + const contract = await artifact.new(elements); + + for (const i in elements) { + expect(await contract.unsafeAccess(i)).to.be.bignumber.equal(elements[i]); + } + }); + } + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Base64.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Base64.test.js new file mode 100644 index 0000000..dfff0b0 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Base64.test.js @@ -0,0 +1,33 @@ +const { expect } = require('chai'); + +const Base64 = artifacts.require('$Base64'); + +contract('Strings', function () { + beforeEach(async function () { + this.base64 = await Base64.new(); + }); + + describe('from bytes - base64', function () { + it('converts to base64 encoded string with double padding', async function () { + const TEST_MESSAGE = 'test'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdA=='); + }); + + it('converts to base64 encoded string with single padding', async function () { + const TEST_MESSAGE = 'test1'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdDE='); + }); + + it('converts to base64 encoded string without padding', async function () { + const TEST_MESSAGE = 'test12'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdDEy'); + }); + + it('empty bytes', async function () { + expect(await this.base64.$encode([])).to.equal(''); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Checkpoints.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Checkpoints.test.js new file mode 100644 index 0000000..48a00e3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Checkpoints.test.js @@ -0,0 +1,228 @@ +const { expectRevert, time } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const { batchInBlock } = require('../helpers/txpool'); + +const $Checkpoints = artifacts.require('$Checkpoints'); + +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(); + }); + + 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'); + + const ckpt = await latestCheckpoint(this.mock); + expect(ckpt[0]).to.be.equal(false); + expect(ckpt[1]).to.be.bignumber.equal('0'); + expect(ckpt[2]).to.be.bignumber.equal('0'); + }); + + 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'); + }); + }); + + describe('with checkpoints', function () { + beforeEach('pushing checkpoints', async function () { + this.tx1 = await push(this.mock, 1); + this.tx2 = await push(this.mock, 2); + await time.advanceBlock(); + this.tx3 = await push(this.mock, 3); + await time.advanceBlock(); + await time.advanceBlock(); + }); + + it('returns latest value', async function () { + expect(await latest(this.mock)).to.be.bignumber.equal('3'); + + const ckpt = await latestCheckpoint(this.mock); + 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]) { + 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'); + // 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'); + }); + it('reverts if block number >= current block', async function () { + await expectRevert( + getAtBlockVariant(this.mock, await web3.eth.getBlockNumber()), + 'Checkpoints: block not yet mined', + ); + + await expectRevert( + getAtBlockVariant(this.mock, (await web3.eth.getBlockNumber()) + 1), + 'Checkpoints: block not yet mined', + ); + }); + }); + } + + it('multiple checkpoints in the same block', async function () { + const lengthBefore = await getLength(this.mock); + + await batchInBlock([ + () => push(this.mock, 8, { gas: 100000 }), + () => push(this.mock, 9, { gas: 100000 }), + () => push(this.mock, 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'); + }); + + it('more than 5 checkpoints', async function () { + for (let i = 4; i <= 6; i++) { + await push(this.mock, i); + } + expect(await getLength(this.mock)).to.be.bignumber.equal('6'); + const block = await web3.eth.getBlockNumber(); + // recent + expect(await getAtRecentBlock(this.mock, block - 1)).to.be.bignumber.equal('5'); + // non-recent + expect(await getAtRecentBlock(this.mock, block - 9)).to.be.bignumber.equal('0'); + }); + }); + }); + + for (const length of [160, 224]) { + 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'); + + const ckpt = await latestCheckpoint(this.mock); + 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'); + }); + }); + + describe('with checkpoints', function () { + beforeEach('pushing checkpoints', async function () { + this.checkpoints = [ + { key: '2', value: '17' }, + { key: '3', value: '42' }, + { key: '5', value: '101' }, + { key: '7', value: '23' }, + { key: '11', value: '99' }, + ]; + for (const { key, value } of this.checkpoints) { + await push(this.mock, key, value); + } + }); + + it('length', async function () { + expect(await getLength(this.mock)).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); + + const ckpt = await latestCheckpoint(this.mock); + 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'); + }); + + 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()); + + // update last key + await push(this.mock, last(this.checkpoints).key, newValue); + expect(await latest(this.mock)).to.be.bignumber.equal(newValue); + + // check that length did not change + expect(await getLength(this.mock)).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); + } + }); + + 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); + } + }); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Context.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Context.behavior.js new file mode 100644 index 0000000..08f7558 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Context.behavior.js @@ -0,0 +1,42 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); + +const ContextMock = artifacts.require('ContextMock'); + +function shouldBehaveLikeRegularContext(sender) { + describe('msgSender', function () { + it('returns the transaction sender when called from an EOA', async function () { + const receipt = await this.context.msgSender({ from: sender }); + expectEvent(receipt, 'Sender', { sender }); + }); + + it('returns the transaction sender when from another contract', async function () { + const { tx } = await this.caller.callSender(this.context.address, { from: sender }); + await expectEvent.inTransaction(tx, ContextMock, 'Sender', { sender: this.caller.address }); + }); + }); + + describe('msgData', function () { + const integerValue = new BN('42'); + const stringValue = 'OpenZeppelin'; + + let callData; + + beforeEach(async function () { + callData = this.context.contract.methods.msgData(integerValue.toString(), stringValue).encodeABI(); + }); + + it('returns the transaction data when called from an EOA', async function () { + const receipt = await this.context.msgData(integerValue, stringValue); + expectEvent(receipt, 'Data', { data: callData, integerValue, stringValue }); + }); + + it('returns the transaction sender when from another contract', async function () { + const { tx } = await this.caller.callData(this.context.address, integerValue, stringValue); + await expectEvent.inTransaction(tx, ContextMock, 'Data', { data: callData, integerValue, stringValue }); + }); + }); +} + +module.exports = { + shouldBehaveLikeRegularContext, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Context.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Context.test.js new file mode 100644 index 0000000..f372f74 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Context.test.js @@ -0,0 +1,17 @@ +require('@openzeppelin/test-helpers'); + +const ContextMock = artifacts.require('ContextMock'); +const ContextMockCaller = artifacts.require('ContextMockCaller'); + +const { shouldBehaveLikeRegularContext } = require('./Context.behavior'); + +contract('Context', function (accounts) { + const [sender] = accounts; + + beforeEach(async function () { + this.context = await ContextMock.new(); + this.caller = await ContextMockCaller.new(); + }); + + shouldBehaveLikeRegularContext(sender); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Counters.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Counters.test.js new file mode 100644 index 0000000..6fb8992 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Counters.test.js @@ -0,0 +1,84 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const Counters = artifacts.require('$Counters'); + +contract('Counters', function () { + beforeEach(async function () { + this.counter = await Counters.new(); + }); + + it('starts at zero', async function () { + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + + describe('increment', function () { + context('starting from 0', function () { + it('increments the current value by one', async function () { + await this.counter.$increment(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('1'); + }); + + it('can be called multiple times', async function () { + await this.counter.$increment(0); + await this.counter.$increment(0); + await this.counter.$increment(0); + + expect(await this.counter.$current(0)).to.be.bignumber.equal('3'); + }); + }); + }); + + describe('decrement', function () { + beforeEach(async function () { + await this.counter.$increment(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('1'); + }); + context('starting from 1', function () { + it('decrements the current value by one', async function () { + await this.counter.$decrement(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + + it('reverts if the current value is 0', async function () { + await this.counter.$decrement(0); + await expectRevert(this.counter.$decrement(0), 'Counter: decrement overflow'); + }); + }); + context('after incremented to 3', function () { + it('can be called multiple times', async function () { + await this.counter.$increment(0); + await this.counter.$increment(0); + + expect(await this.counter.$current(0)).to.be.bignumber.equal('3'); + + await this.counter.$decrement(0); + await this.counter.$decrement(0); + await this.counter.$decrement(0); + + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('reset', function () { + context('null counter', function () { + it('does not throw', async function () { + await this.counter.$reset(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + }); + + context('non null counter', function () { + beforeEach(async function () { + await this.counter.$increment(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('1'); + }); + it('reset to 0', async function () { + await this.counter.$reset(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Create2.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Create2.test.js new file mode 100644 index 0000000..2fc27dc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Create2.test.js @@ -0,0 +1,89 @@ +const { balance, ether, expectEvent, expectRevert, send } = require('@openzeppelin/test-helpers'); +const { computeCreate2Address } = require('../helpers/create2'); +const { expect } = require('chai'); + +const Create2 = artifacts.require('$Create2'); +const VestingWallet = artifacts.require('VestingWallet'); +const ERC1820Implementer = artifacts.require('$ERC1820Implementer'); + +contract('Create2', function (accounts) { + const [deployerAccount, other] = accounts; + + const salt = 'salt message'; + const saltHex = web3.utils.soliditySha3(salt); + + const encodedParams = web3.eth.abi.encodeParameters(['address', 'uint64', 'uint64'], [other, 0, 0]).slice(2); + + const constructorByteCode = `${VestingWallet.bytecode}${encodedParams}`; + + beforeEach(async function () { + this.factory = await Create2.new(); + }); + describe('computeAddress', function () { + it('computes the correct contract address', async function () { + const onChainComputed = await this.factory.$computeAddress(saltHex, web3.utils.keccak256(constructorByteCode)); + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + expect(onChainComputed).to.equal(offChainComputed); + }); + + it('computes the correct contract address with deployer', async function () { + const onChainComputed = await this.factory.$computeAddress( + saltHex, + web3.utils.keccak256(constructorByteCode), + deployerAccount, + ); + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, deployerAccount); + expect(onChainComputed).to.equal(offChainComputed); + }); + }); + + describe('deploy', function () { + it('deploys a ERC1820Implementer from inline assembly code', async function () { + const offChainComputed = computeCreate2Address(saltHex, ERC1820Implementer.bytecode, this.factory.address); + + expectEvent(await this.factory.$deploy(0, saltHex, ERC1820Implementer.bytecode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(ERC1820Implementer.bytecode).to.include((await web3.eth.getCode(offChainComputed)).slice(2)); + }); + + it('deploys a contract with constructor arguments', async function () { + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + + expectEvent(await this.factory.$deploy(0, saltHex, constructorByteCode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(await VestingWallet.at(offChainComputed).then(instance => instance.beneficiary())).to.be.equal(other); + }); + + it('deploys a contract with funds deposited in the factory', async function () { + const deposit = ether('2'); + await send.ether(deployerAccount, this.factory.address, deposit); + expect(await balance.current(this.factory.address)).to.be.bignumber.equal(deposit); + + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + + expectEvent(await this.factory.$deploy(deposit, saltHex, constructorByteCode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(await balance.current(offChainComputed)).to.be.bignumber.equal(deposit); + }); + + it('fails deploying a contract in an existent address', async function () { + expectEvent(await this.factory.$deploy(0, saltHex, constructorByteCode), 'return$deploy'); + + await expectRevert(this.factory.$deploy(0, saltHex, constructorByteCode), 'Create2: Failed on deploy'); + }); + + it('fails deploying a contract if the bytecode length is zero', async function () { + await expectRevert(this.factory.$deploy(0, saltHex, '0x'), 'Create2: bytecode length is zero'); + }); + + it('fails deploying a contract if factory contract does not have sufficient balance', async function () { + await expectRevert(this.factory.$deploy(1, saltHex, constructorByteCode), 'Create2: insufficient balance'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Multicall.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Multicall.test.js new file mode 100644 index 0000000..cfb8007 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Multicall.test.js @@ -0,0 +1,68 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const ERC20MulticallMock = artifacts.require('$ERC20MulticallMock'); + +contract('Multicall', function (accounts) { + const [deployer, alice, bob] = accounts; + const amount = 12000; + + beforeEach(async function () { + this.multicallToken = await ERC20MulticallMock.new('name', 'symbol'); + await this.multicallToken.$_mint(deployer, amount); + }); + + it('batches function calls', async function () { + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + expect(await this.multicallToken.balanceOf(bob)).to.be.bignumber.equal(new BN('0')); + + await this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount / 2).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount / 3).encodeABI(), + ], + { from: deployer }, + ); + + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN(amount / 2)); + expect(await this.multicallToken.balanceOf(bob)).to.be.bignumber.equal(new BN(amount / 3)); + }); + + it('returns an array with the result of each call', async function () { + const MulticallTest = artifacts.require('MulticallTest'); + const multicallTest = await MulticallTest.new({ from: deployer }); + await this.multicallToken.transfer(multicallTest.address, amount, { from: deployer }); + expect(await this.multicallToken.balanceOf(multicallTest.address)).to.be.bignumber.equal(new BN(amount)); + + const recipients = [alice, bob]; + const amounts = [amount / 2, amount / 3].map(n => new BN(n)); + + await multicallTest.checkReturnValues(this.multicallToken.address, recipients, amounts); + }); + + it('reverts previous calls', async function () { + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + + const call = this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount).encodeABI(), + ], + { from: deployer }, + ); + + await expectRevert(call, 'ERC20: transfer amount exceeds balance'); + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + }); + + it('bubbles up revert reasons', async function () { + const call = this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount).encodeABI(), + ], + { from: deployer }, + ); + + await expectRevert(call, 'ERC20: transfer amount exceeds balance'); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js new file mode 100644 index 0000000..f41084a --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/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); + }); + }); + } +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js new file mode 100644 index 0000000..846512e --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js @@ -0,0 +1,210 @@ +const { constants, BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const StorageSlotMock = artifacts.require('StorageSlotMock'); + +const slot = web3.utils.keccak256('some.storage.slot'); +const otherSlot = web3.utils.keccak256('some.other.storage.slot'); + +contract('StorageSlot', function (accounts) { + beforeEach(async function () { + this.store = await StorageSlotMock.new(); + }); + + describe('boolean storage slot', function () { + beforeEach(async function () { + this.value = true; + }); + + it('set', async function () { + await this.store.setBoolean(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBoolean(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBoolean(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBoolean(otherSlot)).to.be.equal(false); + }); + }); + }); + + describe('address storage slot', function () { + beforeEach(async function () { + this.value = accounts[1]; + }); + + it('set', async function () { + await this.store.setAddress(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setAddress(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getAddress(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getAddress(otherSlot)).to.be.equal(constants.ZERO_ADDRESS); + }); + }); + }); + + describe('bytes32 storage slot', function () { + beforeEach(async function () { + this.value = web3.utils.keccak256('some byte32 value'); + }); + + it('set', async function () { + await this.store.setBytes32(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBytes32(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBytes32(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBytes32(otherSlot)).to.be.equal(constants.ZERO_BYTES32); + }); + }); + }); + + describe('uint256 storage slot', function () { + beforeEach(async function () { + this.value = new BN(1742); + }); + + it('set', async function () { + await this.store.setUint256(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setUint256(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getUint256(slot)).to.be.bignumber.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getUint256(otherSlot)).to.be.bignumber.equal('0'); + }); + }); + }); + + 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); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/Strings.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/Strings.test.js new file mode 100644 index 0000000..6658871 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/Strings.test.js @@ -0,0 +1,150 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const Strings = artifacts.require('$Strings'); + +contract('Strings', function () { + before(async function () { + this.strings = await Strings.new(); + }); + + describe('toString', function () { + const values = [ + '0', + '7', + '10', + '99', + '100', + '101', + '123', + '4132', + '12345', + '1234567', + '1234567890', + '123456789012345', + '12345678901234567890', + '123456789012345678901234567890', + '1234567890123456789012345678901234567890', + '12345678901234567890123456789012345678901234567890', + '123456789012345678901234567890123456789012345678901234567890', + '1234567890123456789012345678901234567890123456789012345678901234567890', + ]; + + describe('uint256', function () { + it('converts MAX_UINT256', async function () { + const value = constants.MAX_UINT256; + expect(await this.strings.methods['$toString(uint256)'](value)).to.equal(value.toString(10)); + }); + + for (const value of values) { + it(`converts ${value}`, async function () { + expect(await this.strings.methods['$toString(uint256)'](value)).to.equal(value); + }); + } + }); + + describe('int256', function () { + it('converts MAX_INT256', async function () { + const value = constants.MAX_INT256; + expect(await this.strings.methods['$toString(int256)'](value)).to.equal(value.toString(10)); + }); + + it('converts MIN_INT256', async function () { + const value = constants.MIN_INT256; + expect(await this.strings.methods['$toString(int256)'](value)).to.equal(value.toString(10)); + }); + + for (const value of values) { + it(`convert ${value}`, async function () { + expect(await this.strings.methods['$toString(int256)'](value)).to.equal(value); + }); + + it(`convert negative ${value}`, async function () { + const negated = new BN(value).neg(); + expect(await this.strings.methods['$toString(int256)'](negated)).to.equal(negated.toString(10)); + }); + } + }); + }); + + describe('toHexString', function () { + it('converts 0', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](0)).to.equal('0x00'); + }); + + it('converts a positive number', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](0x4132)).to.equal('0x4132'); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](constants.MAX_UINT256)).to.equal( + web3.utils.toHex(constants.MAX_UINT256), + ); + }); + }); + + describe('toHexString fixed', function () { + it('converts a positive number (long)', async function () { + expect(await this.strings.methods['$toHexString(uint256,uint256)'](0x4132, 32)).to.equal( + '0x0000000000000000000000000000000000000000000000000000000000004132', + ); + }); + + it('converts a positive number (short)', async function () { + await expectRevert( + this.strings.methods['$toHexString(uint256,uint256)'](0x4132, 1), + 'Strings: hex length insufficient', + ); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.strings.methods['$toHexString(uint256,uint256)'](constants.MAX_UINT256, 32)).to.equal( + web3.utils.toHex(constants.MAX_UINT256), + ); + }); + }); + + describe('toHexString address', function () { + it('converts a random address', async function () { + const addr = '0xa9036907dccae6a1e0033479b12e837e5cf5a02f'; + expect(await this.strings.methods['$toHexString(address)'](addr)).to.equal(addr); + }); + + it('converts an address with leading zeros', async function () { + const addr = '0x0000e0ca771e21bd00057f54a68c30d400000000'; + expect(await this.strings.methods['$toHexString(address)'](addr)).to.equal(addr); + }); + }); + + describe('equal', function () { + it('compares two empty strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('', '')).to.equal(true); + }); + + it('compares two equal strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'a')).to.equal(true); + }); + + it('compares two different strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'b')).to.equal(false); + }); + + it('compares two different strings of different lengths', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'aa')).to.equal(false); + expect(await this.strings.methods['$equal(string,string)']('aa', 'a')).to.equal(false); + }); + + it('compares two different large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(200) + 'b'; + expect(await this.strings.methods['$equal(string,string)'](str1, str2)).to.equal(false); + }); + + it('compares two equal large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(201); + expect(await this.strings.methods['$equal(string,string)'](str1, str2)).to.equal(true); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/TimersBlockNumberImpl.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/TimersBlockNumberImpl.test.js new file mode 100644 index 0000000..ee0d54b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/TimersBlockNumberImpl.test.js @@ -0,0 +1,55 @@ +const { BN, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const TimersBlockNumberImpl = artifacts.require('TimersBlockNumberImpl'); + +contract('TimersBlockNumber', function () { + beforeEach(async function () { + this.instance = await TimersBlockNumberImpl.new(); + this.now = await web3.eth.getBlock('latest').then(({ number }) => number); + }); + + it('unset', async function () { + expect(await this.instance.getDeadline()).to.be.bignumber.equal('0'); + expect(await this.instance.isUnset()).to.be.equal(true); + expect(await this.instance.isStarted()).to.be.equal(false); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('pending', async function () { + await this.instance.setDeadline(this.now + 3); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now + 3)); + expect(await this.instance.isUnset()).to.be.equal(false); + expect(await this.instance.isStarted()).to.be.equal(true); + expect(await this.instance.isPending()).to.be.equal(true); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('expired', async function () { + await this.instance.setDeadline(this.now - 3); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now - 3)); + expect(await this.instance.isUnset()).to.be.equal(false); + expect(await this.instance.isStarted()).to.be.equal(true); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(true); + }); + + it('reset', async function () { + await this.instance.reset(); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(0)); + expect(await this.instance.isUnset()).to.be.equal(true); + expect(await this.instance.isStarted()).to.be.equal(false); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('fast forward', async function () { + await this.instance.setDeadline(this.now + 3); + expect(await this.instance.isPending()).to.be.equal(true); + expect(await this.instance.isExpired()).to.be.equal(false); + await time.advanceBlockTo(this.now + 3); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(true); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/TimersTimestamp.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/TimersTimestamp.test.js new file mode 100644 index 0000000..fc32de7 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/TimersTimestamp.test.js @@ -0,0 +1,55 @@ +const { BN, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const TimersTimestampImpl = artifacts.require('TimersTimestampImpl'); + +contract('TimersTimestamp', function () { + beforeEach(async function () { + this.instance = await TimersTimestampImpl.new(); + this.now = await web3.eth.getBlock('latest').then(({ timestamp }) => timestamp); + }); + + it('unset', async function () { + expect(await this.instance.getDeadline()).to.be.bignumber.equal('0'); + expect(await this.instance.isUnset()).to.be.equal(true); + expect(await this.instance.isStarted()).to.be.equal(false); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('pending', async function () { + await this.instance.setDeadline(this.now + 100); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now + 100)); + expect(await this.instance.isUnset()).to.be.equal(false); + expect(await this.instance.isStarted()).to.be.equal(true); + expect(await this.instance.isPending()).to.be.equal(true); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('expired', async function () { + await this.instance.setDeadline(this.now - 100); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now - 100)); + expect(await this.instance.isUnset()).to.be.equal(false); + expect(await this.instance.isStarted()).to.be.equal(true); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(true); + }); + + it('reset', async function () { + await this.instance.reset(); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(0)); + expect(await this.instance.isUnset()).to.be.equal(true); + expect(await this.instance.isStarted()).to.be.equal(false); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('fast forward', async function () { + await this.instance.setDeadline(this.now + 100); + expect(await this.instance.isPending()).to.be.equal(true); + expect(await this.instance.isExpired()).to.be.equal(false); + await time.increaseTo(this.now + 100); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(true); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js new file mode 100644 index 0000000..ae73708 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js @@ -0,0 +1,260 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { toEthSignedMessageHash, toDataWithIntendedValidatorHash } = require('../../helpers/sign'); + +const { expect } = require('chai'); + +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); + if (long.length !== 65) { + throw new Error('invalid signature length (expected long format)'); + } + if (long[32] >> 7 === 1) { + throw new Error("invalid signature 's' value"); + } + const short = long.slice(0, 64); + short[32] |= long[64] % 27 << 7; // set the first bit of the 32nd byte to the v parity bit + return web3.utils.bytesToHex(short); +} + +function split(signature) { + const raw = web3.utils.hexToBytes(signature); + switch (raw.length) { + case 64: + return [ + web3.utils.bytesToHex(raw.slice(0, 32)), // r + web3.utils.bytesToHex(raw.slice(32, 64)), // vs + ]; + case 65: + return [ + raw[64], // v + web3.utils.bytesToHex(raw.slice(0, 32)), // r + web3.utils.bytesToHex(raw.slice(32, 64)), // s + ]; + default: + expect.fail('Invalid signature length, cannot split'); + } +} + +contract('ECDSA', function (accounts) { + const [other] = accounts; + + beforeEach(async function () { + this.ecdsa = await ECDSA.new(); + }); + + context('recover with invalid signature', function () { + it('with short signature', async function () { + await expectRevert(this.ecdsa.$recover(TEST_MESSAGE, '0x1234'), 'ECDSA: invalid signature length'); + }); + + it('with long signature', async function () { + await expectRevert( + // eslint-disable-next-line max-len + this.ecdsa.$recover( + TEST_MESSAGE, + '0x01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789', + ), + 'ECDSA: invalid signature length', + ); + }); + }); + + context('recover with valid signature', function () { + context('using web3.eth.sign', function () { + it('returns signer address with correct signature', async function () { + // Create the signature + const signature = await web3.eth.sign(TEST_MESSAGE, other); + + // Recover the signer address from the generated message and signature. + expect(await this.ecdsa.$recover(toEthSignedMessageHash(TEST_MESSAGE), signature)).to.equal(other); + }); + + it('returns signer address with correct signature for arbitrary length message', async function () { + // Create the signature + const signature = await web3.eth.sign(NON_HASH_MESSAGE, other); + + // Recover the signer address from the generated message and signature. + expect(await this.ecdsa.$recover(toEthSignedMessageHash(NON_HASH_MESSAGE), signature)).to.equal(other); + }); + + it('returns a different address', async function () { + const signature = await web3.eth.sign(TEST_MESSAGE, other); + expect(await this.ecdsa.$recover(WRONG_MESSAGE, signature)).to.not.equal(other); + }); + + it('reverts with invalid signature', async function () { + // eslint-disable-next-line max-len + const signature = + '0x332ce75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e01c'; + await expectRevert(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature'); + }); + }); + + context('with v=27 signature', function () { + // Signature generated outside ganache with method web3.eth.sign(signer, message) + const signer = '0x2cc1166f6212628A0deEf2B33BEFB2187D35b86c'; + // eslint-disable-next-line max-len + const signatureWithoutV = + '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892'; + + it('works with correct v value', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '1c'; // 28 = 1c. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.not.equal(signer); + }); + + it('reverts wrong v values', async function () { + for (const v of ['00', '01']) { + const signature = signatureWithoutV + v; + await expectRevert(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature'); + + await expectRevert( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + 'ECDSA: invalid signature', + ); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + await expectRevert( + this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)), + 'ECDSA: invalid signature length', + ); + }); + }); + + context('with v=28 signature', function () { + const signer = '0x1E318623aB09Fe6de3C9b8672098464Aeda9100E'; + // eslint-disable-next-line max-len + const signatureWithoutV = + '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0'; + + it('works with correct v value', async function () { + const v = '1c'; // 28 = 1c. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.not.equal(signer); + }); + + it('reverts invalid v values', async function () { + for (const v of ['00', '01']) { + const signature = signatureWithoutV + v; + await expectRevert(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature'); + + await expectRevert( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + 'ECDSA: invalid signature', + ); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '1c'; // 27 = 1b. + const signature = signatureWithoutV + v; + await expectRevert( + this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)), + 'ECDSA: invalid signature length', + ); + }); + }); + + it('reverts with high-s value signature', async function () { + const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'; + // eslint-disable-next-line max-len + const highSSignature = + '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b'; + await expectRevert(this.ecdsa.$recover(message, highSSignature), "ECDSA: invalid signature 's' value"); + await expectRevert( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(highSSignature)), + "ECDSA: invalid signature 's' value", + ); + expect(() => to2098Format(highSSignature)).to.throw("invalid signature 's' value"); + }); + }); + + context('toEthSignedMessageHash', function () { + it('prefixes bytes32 data correctly', async function () { + expect(await this.ecdsa.methods['$toEthSignedMessageHash(bytes32)'](TEST_MESSAGE)).to.equal( + toEthSignedMessageHash(TEST_MESSAGE), + ); + }); + + it('prefixes dynamic length data correctly', async function () { + expect(await this.ecdsa.methods['$toEthSignedMessageHash(bytes)'](NON_HASH_MESSAGE)).to.equal( + toEthSignedMessageHash(NON_HASH_MESSAGE), + ); + }); + }); + + 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)); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js new file mode 100644 index 0000000..f12f226 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js @@ -0,0 +1,70 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { getDomain, domainType, domainSeparator, hashTypedData } = require('../../helpers/eip712'); +const { getChainId } = require('../../helpers/chainid'); +const { mapValues } = require('../../helpers/map-values'); + +const EIP712Verifier = artifacts.require('$EIP712Verifier'); + +contract('EIP712', function (accounts) { + const [mailTo] = accounts; + + const name = 'A Name'; + const version = '1'; + + beforeEach('deploying', async function () { + this.eip712 = await EIP712Verifier.new(name, version); + + 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)); + }); + }); + + 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); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js new file mode 100644 index 0000000..62157b5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js @@ -0,0 +1,180 @@ +require('@openzeppelin/test-helpers'); + +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { MerkleTree } = require('merkletreejs'); +const keccak256 = require('keccak256'); + +const { expect } = require('chai'); + +const MerkleProof = artifacts.require('$MerkleProof'); + +contract('MerkleProof', function () { + beforeEach(async function () { + this.merkleProof = await MerkleProof.new(); + }); + + describe('verify', function () { + it('returns true for a valid Merkle proof', async function () { + const elements = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''); + const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true }); + + const root = merkleTree.getHexRoot(); + + const leaf = keccak256(elements[0]); + + const proof = merkleTree.getHexProof(leaf); + + expect(await this.merkleProof.$verify(proof, root, leaf)).to.equal(true); + expect(await this.merkleProof.$verifyCalldata(proof, root, leaf)).to.equal(true); + + // For demonstration, it is also possible to create valid proofs for certain 64-byte values *not* in elements: + const noSuchLeaf = keccak256( + Buffer.concat([keccak256(elements[0]), keccak256(elements[1])].sort(Buffer.compare)), + ); + expect(await this.merkleProof.$verify(proof.slice(1), root, noSuchLeaf)).to.equal(true); + expect(await this.merkleProof.$verifyCalldata(proof.slice(1), root, noSuchLeaf)).to.equal(true); + }); + + it('returns false for an invalid Merkle proof', async function () { + const correctElements = ['a', 'b', 'c']; + const correctMerkleTree = new MerkleTree(correctElements, keccak256, { hashLeaves: true, sortPairs: true }); + + const correctRoot = correctMerkleTree.getHexRoot(); + + const correctLeaf = keccak256(correctElements[0]); + + const badElements = ['d', 'e', 'f']; + const badMerkleTree = new MerkleTree(badElements); + + const badProof = badMerkleTree.getHexProof(badElements[0]); + + expect(await this.merkleProof.$verify(badProof, correctRoot, correctLeaf)).to.equal(false); + expect(await this.merkleProof.$verifyCalldata(badProof, correctRoot, correctLeaf)).to.equal(false); + }); + + it('returns false for a Merkle proof of invalid length', async function () { + const elements = ['a', 'b', 'c']; + const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true }); + + const root = merkleTree.getHexRoot(); + + const leaf = keccak256(elements[0]); + + const proof = merkleTree.getHexProof(leaf); + const badProof = proof.slice(0, proof.length - 5); + + expect(await this.merkleProof.$verify(badProof, root, leaf)).to.equal(false); + expect(await this.merkleProof.$verifyCalldata(badProof, root, leaf)).to.equal(false); + }); + }); + + describe('multiProofVerify', function () { + it('returns true for a valid Merkle multi proof', async function () { + const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const proofLeaves = ['b', 'f', 'd'].map(keccak256).sort(Buffer.compare); + const proof = merkleTree.getMultiProof(proofLeaves); + const proofFlags = merkleTree.getProofFlags(proofLeaves, proof); + + expect(await this.merkleProof.$multiProofVerify(proof, proofFlags, root, proofLeaves)).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata(proof, proofFlags, root, proofLeaves)).to.equal(true); + }); + + it('returns false for an invalid Merkle multi proof', async function () { + const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const badProofLeaves = ['g', 'h', 'i'].map(keccak256).sort(Buffer.compare); + const badMerkleTree = new MerkleTree(badProofLeaves); + const badProof = badMerkleTree.getMultiProof(badProofLeaves); + const badProofFlags = badMerkleTree.getProofFlags(badProofLeaves, badProof); + + expect(await this.merkleProof.$multiProofVerify(badProof, badProofFlags, root, badProofLeaves)).to.equal(false); + expect(await this.merkleProof.$multiProofVerifyCalldata(badProof, badProofFlags, root, badProofLeaves)).to.equal( + false, + ); + }); + + it('revert with invalid multi proof #1', async function () { + const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const badLeaf = keccak256('e'); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + + await expectRevert( + this.merkleProof.$multiProofVerify( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false], + root, + [leaves[0], badLeaf], // A, E + ), + 'MerkleProof: invalid multiproof', + ); + await expectRevert( + this.merkleProof.$multiProofVerifyCalldata( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false], + root, + [leaves[0], badLeaf], // A, E + ), + 'MerkleProof: invalid multiproof', + ); + }); + + it('revert with invalid multi proof #2', async function () { + const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const badLeaf = keccak256('e'); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + + await expectRevert( + this.merkleProof.$multiProofVerify( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false, false], + root, + [badLeaf, leaves[0]], // A, E + ), + 'reverted with panic code 0x32', + ); + + await expectRevert( + this.merkleProof.$multiProofVerifyCalldata( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false, false], + root, + [badLeaf, leaves[0]], // A, E + ), + 'reverted with panic code 0x32', + ); + }); + + it('limit case: works for tree containing a single leaf', async function () { + const leaves = ['a'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const proofLeaves = ['a'].map(keccak256).sort(Buffer.compare); + const proof = merkleTree.getMultiProof(proofLeaves); + const proofFlags = merkleTree.getProofFlags(proofLeaves, proof); + + expect(await this.merkleProof.$multiProofVerify(proof, proofFlags, root, proofLeaves)).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata(proof, proofFlags, root, proofLeaves)).to.equal(true); + }); + + it('limit case: can prove empty leaves', async function () { + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + expect(await this.merkleProof.$multiProofVerify([root], [], root, [])).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata([root], [], root, [])).to.equal(true); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js new file mode 100644 index 0000000..ba8b100 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js @@ -0,0 +1,87 @@ +const { toEthSignedMessageHash } = require('../../helpers/sign'); + +const { expect } = require('chai'); + +const SignatureChecker = artifacts.require('$SignatureChecker'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); +const ERC1271MaliciousMock = artifacts.require('ERC1271MaliciousMock'); + +const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin'); +const WRONG_MESSAGE = web3.utils.sha3('Nope'); + +contract('SignatureChecker (ERC1271)', function (accounts) { + const [signer, other] = accounts; + + before('deploying', async function () { + this.signaturechecker = await SignatureChecker.new(); + this.wallet = await ERC1271WalletMock.new(signer); + this.malicious = await ERC1271MaliciousMock.new(); + this.signature = await web3.eth.sign(TEST_MESSAGE, signer); + }); + + context('EOA account', function () { + it('with matching signer and signature', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(TEST_MESSAGE), this.signature), + ).to.equal(true); + }); + + it('with invalid signer', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(other, toEthSignedMessageHash(TEST_MESSAGE), this.signature), + ).to.equal(false); + }); + + it('with invalid signature', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(WRONG_MESSAGE), this.signature), + ).to.equal(false); + }); + }); + + context('ERC1271 wallet', function () { + 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[`$${signature}`]( + this.signaturechecker.address, + toEthSignedMessageHash(TEST_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[`$${signature}`]( + this.malicious.address, + toEthSignedMessageHash(TEST_MESSAGE), + this.signature, + ), + ).to.equal(false); + }); + }); + } + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/ConditionalEscrow.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/ConditionalEscrow.test.js new file mode 100644 index 0000000..9e17a8b --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/ConditionalEscrow.test.js @@ -0,0 +1,37 @@ +const { ether, expectRevert } = require('@openzeppelin/test-helpers'); +const { shouldBehaveLikeEscrow } = require('./Escrow.behavior'); + +const ConditionalEscrowMock = artifacts.require('ConditionalEscrowMock'); + +contract('ConditionalEscrow', function (accounts) { + const [owner, payee, ...otherAccounts] = accounts; + + beforeEach(async function () { + this.escrow = await ConditionalEscrowMock.new({ from: owner }); + }); + + context('when withdrawal is allowed', function () { + beforeEach(async function () { + await Promise.all(otherAccounts.map(payee => this.escrow.setAllowed(payee, true))); + }); + + shouldBehaveLikeEscrow(owner, otherAccounts); + }); + + context('when withdrawal is disallowed', function () { + const amount = ether('23'); + + beforeEach(async function () { + await this.escrow.setAllowed(payee, false); + }); + + it('reverts on withdrawals', async function () { + await this.escrow.deposit(payee, { from: owner, value: amount }); + + await expectRevert( + this.escrow.withdraw(payee, { from: owner }), + 'ConditionalEscrow: payee is not allowed to withdraw', + ); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/Escrow.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/Escrow.behavior.js new file mode 100644 index 0000000..f2059ed --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/Escrow.behavior.js @@ -0,0 +1,90 @@ +const { balance, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +function shouldBehaveLikeEscrow(owner, [payee1, payee2]) { + const amount = ether('42'); + + describe('as an escrow', function () { + describe('deposits', function () { + it('can accept a single deposit', async function () { + await this.escrow.deposit(payee1, { from: owner, value: amount }); + + expect(await balance.current(this.escrow.address)).to.be.bignumber.equal(amount); + + expect(await this.escrow.depositsOf(payee1)).to.be.bignumber.equal(amount); + }); + + it('can accept an empty deposit', async function () { + await this.escrow.deposit(payee1, { from: owner, value: 0 }); + }); + + it('only the owner can deposit', async function () { + await expectRevert(this.escrow.deposit(payee1, { from: payee2 }), 'Ownable: caller is not the owner'); + }); + + it('emits a deposited event', async function () { + const receipt = await this.escrow.deposit(payee1, { from: owner, value: amount }); + expectEvent(receipt, 'Deposited', { + payee: payee1, + weiAmount: amount, + }); + }); + + it('can add multiple deposits on a single account', async function () { + await this.escrow.deposit(payee1, { from: owner, value: amount }); + await this.escrow.deposit(payee1, { from: owner, value: amount.muln(2) }); + + expect(await balance.current(this.escrow.address)).to.be.bignumber.equal(amount.muln(3)); + + expect(await this.escrow.depositsOf(payee1)).to.be.bignumber.equal(amount.muln(3)); + }); + + it('can track deposits to multiple accounts', async function () { + await this.escrow.deposit(payee1, { from: owner, value: amount }); + await this.escrow.deposit(payee2, { from: owner, value: amount.muln(2) }); + + expect(await balance.current(this.escrow.address)).to.be.bignumber.equal(amount.muln(3)); + + expect(await this.escrow.depositsOf(payee1)).to.be.bignumber.equal(amount); + + expect(await this.escrow.depositsOf(payee2)).to.be.bignumber.equal(amount.muln(2)); + }); + }); + + describe('withdrawals', async function () { + it('can withdraw payments', async function () { + const balanceTracker = await balance.tracker(payee1); + + await this.escrow.deposit(payee1, { from: owner, value: amount }); + await this.escrow.withdraw(payee1, { from: owner }); + + expect(await balanceTracker.delta()).to.be.bignumber.equal(amount); + + expect(await balance.current(this.escrow.address)).to.be.bignumber.equal('0'); + expect(await this.escrow.depositsOf(payee1)).to.be.bignumber.equal('0'); + }); + + it('can do an empty withdrawal', async function () { + await this.escrow.withdraw(payee1, { from: owner }); + }); + + it('only the owner can withdraw', async function () { + await expectRevert(this.escrow.withdraw(payee1, { from: payee1 }), 'Ownable: caller is not the owner'); + }); + + it('emits a withdrawn event', async function () { + await this.escrow.deposit(payee1, { from: owner, value: amount }); + const receipt = await this.escrow.withdraw(payee1, { from: owner }); + expectEvent(receipt, 'Withdrawn', { + payee: payee1, + weiAmount: amount, + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeEscrow, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/Escrow.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/Escrow.test.js new file mode 100644 index 0000000..4762790 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/Escrow.test.js @@ -0,0 +1,14 @@ +require('@openzeppelin/test-helpers'); +const { shouldBehaveLikeEscrow } = require('./Escrow.behavior'); + +const Escrow = artifacts.require('Escrow'); + +contract('Escrow', function (accounts) { + const [owner, ...otherAccounts] = accounts; + + beforeEach(async function () { + this.escrow = await Escrow.new({ from: owner }); + }); + + shouldBehaveLikeEscrow(owner, otherAccounts); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/RefundEscrow.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/RefundEscrow.test.js new file mode 100644 index 0000000..c5344db --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/escrow/RefundEscrow.test.js @@ -0,0 +1,143 @@ +const { balance, constants, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const RefundEscrow = artifacts.require('RefundEscrow'); + +contract('RefundEscrow', function (accounts) { + const [owner, beneficiary, refundee1, refundee2] = accounts; + + const amount = ether('54'); + const refundees = [refundee1, refundee2]; + + it('requires a non-null beneficiary', async function () { + await expectRevert( + RefundEscrow.new(ZERO_ADDRESS, { from: owner }), + 'RefundEscrow: beneficiary is the zero address', + ); + }); + + context('once deployed', function () { + beforeEach(async function () { + this.escrow = await RefundEscrow.new(beneficiary, { from: owner }); + }); + + context('active state', function () { + it('has beneficiary and state', async function () { + expect(await this.escrow.beneficiary()).to.equal(beneficiary); + expect(await this.escrow.state()).to.be.bignumber.equal('0'); + }); + + it('accepts deposits', async function () { + await this.escrow.deposit(refundee1, { from: owner, value: amount }); + + expect(await this.escrow.depositsOf(refundee1)).to.be.bignumber.equal(amount); + }); + + it('does not refund refundees', async function () { + await this.escrow.deposit(refundee1, { from: owner, value: amount }); + await expectRevert(this.escrow.withdraw(refundee1), 'ConditionalEscrow: payee is not allowed to withdraw'); + }); + + it('does not allow beneficiary withdrawal', async function () { + await this.escrow.deposit(refundee1, { from: owner, value: amount }); + await expectRevert( + this.escrow.beneficiaryWithdraw(), + 'RefundEscrow: beneficiary can only withdraw while closed', + ); + }); + }); + + it('only the owner can enter closed state', async function () { + await expectRevert(this.escrow.close({ from: beneficiary }), 'Ownable: caller is not the owner'); + + const receipt = await this.escrow.close({ from: owner }); + expectEvent(receipt, 'RefundsClosed'); + }); + + context('closed state', function () { + beforeEach(async function () { + await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: owner, value: amount }))); + + await this.escrow.close({ from: owner }); + }); + + it('rejects deposits', async function () { + await expectRevert( + this.escrow.deposit(refundee1, { from: owner, value: amount }), + 'RefundEscrow: can only deposit while active', + ); + }); + + it('does not refund refundees', async function () { + await expectRevert(this.escrow.withdraw(refundee1), 'ConditionalEscrow: payee is not allowed to withdraw'); + }); + + it('allows beneficiary withdrawal', async function () { + const balanceTracker = await balance.tracker(beneficiary); + await this.escrow.beneficiaryWithdraw(); + expect(await balanceTracker.delta()).to.be.bignumber.equal(amount.muln(refundees.length)); + }); + + it('prevents entering the refund state', async function () { + await expectRevert( + this.escrow.enableRefunds({ from: owner }), + 'RefundEscrow: can only enable refunds while active', + ); + }); + + it('prevents re-entering the closed state', async function () { + await expectRevert(this.escrow.close({ from: owner }), 'RefundEscrow: can only close while active'); + }); + }); + + it('only the owner can enter refund state', async function () { + await expectRevert(this.escrow.enableRefunds({ from: beneficiary }), 'Ownable: caller is not the owner'); + + const receipt = await this.escrow.enableRefunds({ from: owner }); + expectEvent(receipt, 'RefundsEnabled'); + }); + + context('refund state', function () { + beforeEach(async function () { + await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: owner, value: amount }))); + + await this.escrow.enableRefunds({ from: owner }); + }); + + it('rejects deposits', async function () { + await expectRevert( + this.escrow.deposit(refundee1, { from: owner, value: amount }), + 'RefundEscrow: can only deposit while active', + ); + }); + + it('refunds refundees', async function () { + for (const refundee of [refundee1, refundee2]) { + const balanceTracker = await balance.tracker(refundee); + await this.escrow.withdraw(refundee, { from: owner }); + expect(await balanceTracker.delta()).to.be.bignumber.equal(amount); + } + }); + + it('does not allow beneficiary withdrawal', async function () { + await expectRevert( + this.escrow.beneficiaryWithdraw(), + 'RefundEscrow: beneficiary can only withdraw while closed', + ); + }); + + it('prevents entering the closed state', async function () { + await expectRevert(this.escrow.close({ from: owner }), 'RefundEscrow: can only close while active'); + }); + + it('prevents re-entering the refund state', async function () { + await expectRevert( + this.escrow.enableRefunds({ from: owner }), + 'RefundEscrow: can only enable refunds while active', + ); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js new file mode 100644 index 0000000..6d531c1 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js @@ -0,0 +1,11 @@ +const { shouldSupportInterfaces } = require('./SupportsInterface.behavior'); + +const ERC165 = artifacts.require('$ERC165'); + +contract('ERC165', function () { + beforeEach(async function () { + this.mock = await ERC165.new(); + }); + + shouldSupportInterfaces(['ERC165']); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js new file mode 100644 index 0000000..bb68428 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js @@ -0,0 +1,302 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC165Checker = artifacts.require('$ERC165Checker'); +const ERC165Storage = artifacts.require('$ERC165Storage'); +const ERC165MissingData = artifacts.require('ERC165MissingData'); +const ERC165MaliciousData = artifacts.require('ERC165MaliciousData'); +const ERC165NotSupported = artifacts.require('ERC165NotSupported'); +const ERC165ReturnBombMock = artifacts.require('ERC165ReturnBombMock'); + +const DUMMY_ID = '0xdeadbeef'; +const DUMMY_ID_2 = '0xcafebabe'; +const DUMMY_ID_3 = '0xdecafbad'; +const DUMMY_UNSUPPORTED_ID = '0xbaddcafe'; +const DUMMY_UNSUPPORTED_ID_2 = '0xbaadcafe'; +const DUMMY_ACCOUNT = '0x1111111111111111111111111111111111111111'; + +contract('ERC165Checker', function () { + beforeEach(async function () { + this.mock = await ERC165Checker.new(); + }); + + context('ERC165 missing return data', function () { + beforeEach(async function () { + this.target = await ERC165MissingData.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 malicious return data', function () { + beforeEach(async function () { + this.target = await ERC165MaliciousData.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + }); + + context('ERC165 not supported', function () { + beforeEach(async function () { + this.target = await ERC165NotSupported.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 supported', function () { + beforeEach(async function () { + this.target = await ERC165Storage.new(); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 and single interface supported', function () { + beforeEach(async function () { + this.target = await ERC165Storage.new(); + await this.target.$_registerInterface(DUMMY_ID); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('supports mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + + it('supports mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(true); + }); + + it('supports mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(true); + }); + + it('supports mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + }); + + context('ERC165 and many interfaces supported', function () { + beforeEach(async function () { + this.supportedInterfaces = [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3]; + this.target = await ERC165Storage.new(); + await Promise.all(this.supportedInterfaces.map(interfaceId => this.target.$_registerInterface(interfaceId))); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('supports each interfaceId via supportsInterface', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.$supportsInterface(this.target.address, interfaceId); + expect(supported).to.equal(true); + } + }); + + it('supports all interfaceIds via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, this.supportedInterfaces); + expect(supported).to.equal(true); + }); + + it('supports none of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + const supported = await this.mock.$supportsAllInterfaces(this.target.address, interfaceIdsToTest); + expect(supported).to.equal(false); + }); + + it('supports not all of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + const supported = await this.mock.$supportsAllInterfaces(this.target.address, interfaceIdsToTest); + expect(supported).to.equal(false); + }); + + it('supports all interfaceIds via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, this.supportedInterfaces); + expect(supported.length).to.equal(3); + expect(supported[0]).to.equal(true); + expect(supported[1]).to.equal(true); + expect(supported[2]).to.equal(true); + }); + + it('supports none of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + const supported = await this.mock.$getSupportedInterfaces(this.target.address, interfaceIdsToTest); + expect(supported.length).to.equal(2); + expect(supported[0]).to.equal(false); + expect(supported[1]).to.equal(false); + }); + + it('supports not all of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + const supported = await this.mock.$getSupportedInterfaces(this.target.address, interfaceIdsToTest); + expect(supported.length).to.equal(4); + expect(supported[0]).to.equal(true); + expect(supported[1]).to.equal(true); + expect(supported[2]).to.equal(true); + expect(supported[3]).to.equal(false); + }); + + it('supports each interfaceId via supportsERC165InterfaceUnchecked', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, interfaceId); + expect(supported).to.equal(true); + } + }); + }); + + context('account address does not support ERC165', function () { + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(DUMMY_ACCOUNT); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + it('Return bomb resistance', async function () { + this.target = await ERC165ReturnBombMock.new(); + + const tx1 = await this.mock.$supportsInterface.sendTransaction(this.target.address, DUMMY_ID); + expect(tx1.receipt.gasUsed).to.be.lessThan(120000); // 3*30k + 21k + some margin + + const tx2 = await this.mock.$getSupportedInterfaces.sendTransaction(this.target.address, [ + DUMMY_ID, + DUMMY_ID_2, + DUMMY_ID_3, + DUMMY_UNSUPPORTED_ID, + DUMMY_UNSUPPORTED_ID_2, + ]); + expect(tx2.receipt.gasUsed).to.be.lessThan(250000); // (2+5)*30k + 21k + some margin + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165Storage.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165Storage.test.js new file mode 100644 index 0000000..c78caf8 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC165Storage.test.js @@ -0,0 +1,23 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { shouldSupportInterfaces } = require('./SupportsInterface.behavior'); + +const ERC165Storage = artifacts.require('$ERC165Storage'); + +contract('ERC165Storage', function () { + beforeEach(async function () { + this.mock = await ERC165Storage.new(); + }); + + it('register interface', async function () { + expect(await this.mock.supportsInterface('0x00000001')).to.be.equal(false); + await this.mock.$_registerInterface('0x00000001'); + expect(await this.mock.supportsInterface('0x00000001')).to.be.equal(true); + }); + + it('does not allow 0xffffffff', async function () { + await expectRevert(this.mock.$_registerInterface('0xffffffff'), 'ERC165: invalid interface id'); + }); + + shouldSupportInterfaces(['ERC165']); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC1820Implementer.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC1820Implementer.test.js new file mode 100644 index 0000000..83d0a65 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/ERC1820Implementer.test.js @@ -0,0 +1,71 @@ +const { expectRevert, singletons } = require('@openzeppelin/test-helpers'); +const { bufferToHex, keccakFromString } = require('ethereumjs-util'); + +const { expect } = require('chai'); + +const ERC1820Implementer = artifacts.require('$ERC1820Implementer'); + +contract('ERC1820Implementer', function (accounts) { + const [registryFunder, implementee, other] = accounts; + + const ERC1820_ACCEPT_MAGIC = bufferToHex(keccakFromString('ERC1820_ACCEPT_MAGIC')); + + beforeEach(async function () { + this.implementer = await ERC1820Implementer.new(); + this.registry = await singletons.ERC1820Registry(registryFunder); + + this.interfaceA = bufferToHex(keccakFromString('interfaceA')); + this.interfaceB = bufferToHex(keccakFromString('interfaceB')); + }); + + context('with no registered interfaces', function () { + it('returns false when interface implementation is queried', async function () { + expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, implementee)).to.not.equal( + ERC1820_ACCEPT_MAGIC, + ); + }); + + it('reverts when attempting to set as implementer in the registry', async function () { + await expectRevert( + this.registry.setInterfaceImplementer(implementee, this.interfaceA, this.implementer.address, { + from: implementee, + }), + 'Does not implement the interface', + ); + }); + }); + + context('with registered interfaces', function () { + beforeEach(async function () { + await this.implementer.$_registerInterfaceForAddress(this.interfaceA, implementee); + }); + + it('returns true when interface implementation is queried', async function () { + expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, implementee)).to.equal( + ERC1820_ACCEPT_MAGIC, + ); + }); + + it('returns false when interface implementation for non-supported interfaces is queried', async function () { + expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceB, implementee)).to.not.equal( + ERC1820_ACCEPT_MAGIC, + ); + }); + + it('returns false when interface implementation for non-supported addresses is queried', async function () { + expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, other)).to.not.equal( + ERC1820_ACCEPT_MAGIC, + ); + }); + + it('can be set as an implementer for supported interfaces in the registry', async function () { + await this.registry.setInterfaceImplementer(implementee, this.interfaceA, this.implementer.address, { + from: implementee, + }); + + expect(await this.registry.getInterfaceImplementer(implementee, this.interfaceA)).to.equal( + this.implementer.address, + ); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js new file mode 100644 index 0000000..02d1478 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js @@ -0,0 +1,130 @@ +const { makeInterfaceId } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const INTERFACES = { + ERC165: ['supportsInterface(bytes4)'], + ERC721: [ + 'balanceOf(address)', + 'ownerOf(uint256)', + 'approve(address,uint256)', + 'getApproved(uint256)', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'transferFrom(address,address,uint256)', + 'safeTransferFrom(address,address,uint256)', + 'safeTransferFrom(address,address,uint256,bytes)', + ], + ERC721Enumerable: ['totalSupply()', 'tokenOfOwnerByIndex(address,uint256)', 'tokenByIndex(uint256)'], + ERC721Metadata: ['name()', 'symbol()', 'tokenURI(uint256)'], + ERC1155: [ + 'balanceOf(address,uint256)', + 'balanceOfBatch(address[],uint256[])', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'safeTransferFrom(address,address,uint256,uint256,bytes)', + 'safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)', + ], + ERC1155Receiver: [ + 'onERC1155Received(address,address,uint256,uint256,bytes)', + 'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)', + ], + AccessControl: [ + 'hasRole(bytes32,address)', + 'getRoleAdmin(bytes32)', + 'grantRole(bytes32,address)', + 'revokeRole(bytes32,address)', + 'renounceRole(bytes32,address)', + ], + AccessControlEnumerable: ['getRoleMember(bytes32,uint256)', 'getRoleMemberCount(bytes32)'], + Governor: [ + 'name()', + 'version()', + 'COUNTING_MODE()', + 'hashProposal(address[],uint256[],bytes[],bytes32)', + 'state(uint256)', + 'proposalSnapshot(uint256)', + 'proposalDeadline(uint256)', + 'votingDelay()', + 'votingPeriod()', + 'quorum(uint256)', + 'getVotes(address,uint256)', + 'hasVoted(uint256,address)', + 'propose(address[],uint256[],bytes[],string)', + 'execute(address[],uint256[],bytes[],bytes32)', + 'castVote(uint256,uint8)', + 'castVoteWithReason(uint256,uint8,string)', + 'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)', + ], + GovernorWithParams: [ + 'name()', + 'version()', + 'COUNTING_MODE()', + 'hashProposal(address[],uint256[],bytes[],bytes32)', + 'state(uint256)', + 'proposalSnapshot(uint256)', + 'proposalDeadline(uint256)', + 'votingDelay()', + 'votingPeriod()', + 'quorum(uint256)', + 'getVotes(address,uint256)', + 'getVotesWithParams(address,uint256,bytes)', + 'hasVoted(uint256,address)', + 'propose(address[],uint256[],bytes[],string)', + 'execute(address[],uint256[],bytes[],bytes32)', + 'castVote(uint256,uint8)', + 'castVoteWithReason(uint256,uint8,string)', + 'castVoteWithReasonAndParams(uint256,uint8,string,bytes)', + 'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)', + 'castVoteWithReasonAndParamsBySig(uint256,uint8,string,bytes,uint8,bytes32,bytes32)', + ], + GovernorTimelock: ['timelock()', 'proposalEta(uint256)', 'queue(address[],uint256[],bytes[],bytes32)'], + ERC2981: ['royaltyInfo(uint256,uint256)'], +}; + +const INTERFACE_IDS = {}; +const FN_SIGNATURES = {}; +for (const k of Object.getOwnPropertyNames(INTERFACES)) { + INTERFACE_IDS[k] = makeInterfaceId.ERC165(INTERFACES[k]); + for (const fnName of INTERFACES[k]) { + // the interface id of a single function is equivalent to its function signature + FN_SIGNATURES[fnName] = makeInterfaceId.ERC165([fnName]); + } +} + +function shouldSupportInterfaces(interfaces = []) { + describe('ERC165', function () { + beforeEach(function () { + this.contractUnderTest = this.mock || this.token || this.holder || this.accessControl; + }); + + it('supportsInterface uses less than 30k gas', async function () { + for (const k of interfaces) { + 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] ?? 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); + } + } + }); + }); +} + +module.exports = { + shouldSupportInterfaces, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/math/Math.t.sol b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/Math.t.sol new file mode 100644 index 0000000..916136c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/Math.t.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +import "../../../contracts/utils/math/Math.sol"; +import "../../../contracts/utils/math/SafeMath.sol"; + +contract MathTest is Test { + // CEILDIV + function testCeilDiv(uint256 a, uint256 b) public { + vm.assume(b > 0); + + uint256 result = Math.ceilDiv(a, b); + + if (result == 0) { + assertEq(a, 0); + } else { + uint256 maxdiv = UINT256_MAX / b; + bool overflow = maxdiv * b < a; + assertTrue(a > b * (result - 1)); + assertTrue(overflow ? result == maxdiv + 1 : a <= b * result); + } + } + + // SQRT + function testSqrt(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.sqrt(input, rounding); + + // square of result is bigger than input + if (_squareBigger(result, input)) { + assertTrue(rounding == Math.Rounding.Up); + assertTrue(_squareSmaller(result - 1, input)); + } + // square of result is smaller than input + else if (_squareSmaller(result, input)) { + assertFalse(rounding == Math.Rounding.Up); + assertTrue(_squareBigger(result + 1, input)); + } + // input is perfect square + else { + assertEq(result * result, input); + } + } + + function _squareBigger(uint256 value, uint256 ref) private pure returns (bool) { + (bool noOverflow, uint256 square) = SafeMath.tryMul(value, value); + return !noOverflow || square > ref; + } + + function _squareSmaller(uint256 value, uint256 ref) private pure returns (bool) { + return value * value < ref; + } + + // LOG2 + function testLog2(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log2(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf2Bigger(result, input)) { + assertTrue(rounding == Math.Rounding.Up); + assertTrue(_powerOf2Smaller(result - 1, input)); + } else if (_powerOf2Smaller(result, input)) { + assertFalse(rounding == Math.Rounding.Up); + assertTrue(_powerOf2Bigger(result + 1, input)); + } else { + assertEq(2 ** result, input); + } + } + + function _powerOf2Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 256 || 2 ** value > ref; // 2**256 overflows uint256 + } + + function _powerOf2Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 2 ** value < ref; + } + + // LOG10 + function testLog10(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log10(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf10Bigger(result, input)) { + assertTrue(rounding == Math.Rounding.Up); + assertTrue(_powerOf10Smaller(result - 1, input)); + } else if (_powerOf10Smaller(result, input)) { + assertFalse(rounding == Math.Rounding.Up); + assertTrue(_powerOf10Bigger(result + 1, input)); + } else { + assertEq(10 ** result, input); + } + } + + function _powerOf10Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 78 || 10 ** value > ref; // 10**78 overflows uint256 + } + + function _powerOf10Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 10 ** value < ref; + } + + // LOG256 + function testLog256(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log256(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf256Bigger(result, input)) { + assertTrue(rounding == Math.Rounding.Up); + assertTrue(_powerOf256Smaller(result - 1, input)); + } else if (_powerOf256Smaller(result, input)) { + assertFalse(rounding == Math.Rounding.Up); + assertTrue(_powerOf256Bigger(result + 1, input)); + } else { + assertEq(256 ** result, input); + } + } + + function _powerOf256Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 32 || 256 ** value > ref; // 256**32 overflows uint256 + } + + function _powerOf256Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 256 ** value < ref; + } + + // MULDIV + function testMulDiv(uint256 x, uint256 y, uint256 d) public { + // Full precision for x * y + (uint256 xyHi, uint256 xyLo) = _mulHighLow(x, y); + + // Assume result won't overflow (see {testMulDivDomain}) + // This also checks that `d` is positive + vm.assume(xyHi < d); + + // Perform muldiv + uint256 q = Math.mulDiv(x, y, d); + + // Full precision for q * d + (uint256 qdHi, uint256 qdLo) = _mulHighLow(q, d); + // Add remainder of x * y / d (computed as rem = (x * y % d)) + (uint256 qdRemLo, uint256 c) = _addCarry(qdLo, _mulmod(x, y, d)); + uint256 qdRemHi = qdHi + c; + + // Full precision check that x * y = q * d + rem + assertEq(xyHi, qdRemHi); + assertEq(xyLo, qdRemLo); + } + + function testMulDivDomain(uint256 x, uint256 y, uint256 d) public { + (uint256 xyHi, ) = _mulHighLow(x, y); + + // Violate {testMulDiv} assumption (covers d is 0 and result overflow) + vm.assume(xyHi >= d); + + // we are outside the scope of {testMulDiv}, we expect muldiv to revert + try this.muldiv(x, y, d) returns (uint256) { + fail(); + } catch {} + } + + // External call + function muldiv(uint256 x, uint256 y, uint256 d) external pure returns (uint256) { + return Math.mulDiv(x, y, d); + } + + // Helpers + function _asRounding(uint8 r) private pure returns (Math.Rounding) { + vm.assume(r < uint8(type(Math.Rounding).max)); + return Math.Rounding(r); + } + + function _mulmod(uint256 x, uint256 y, uint256 z) private pure returns (uint256 r) { + assembly { + r := mulmod(x, y, z) + } + } + + function _mulHighLow(uint256 x, uint256 y) private pure returns (uint256 high, uint256 low) { + (uint256 x0, uint256 x1) = (x & type(uint128).max, x >> 128); + (uint256 y0, uint256 y1) = (y & type(uint128).max, y >> 128); + + // Karatsuba algorithm + // https://en.wikipedia.org/wiki/Karatsuba_algorithm + uint256 z2 = x1 * y1; + uint256 z1a = x1 * y0; + uint256 z1b = x0 * y1; + uint256 z0 = x0 * y0; + + uint256 carry = ((z1a & type(uint128).max) + (z1b & type(uint128).max) + (z0 >> 128)) >> 128; + + high = z2 + (z1a >> 128) + (z1b >> 128) + carry; + + unchecked { + low = x * y; + } + } + + function _addCarry(uint256 x, uint256 y) private pure returns (uint256 res, uint256 carry) { + unchecked { + res = x + y; + } + carry = res < x ? 1 : 0; + } +} diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/math/Math.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/Math.test.js new file mode 100644 index 0000000..6b97a64 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/Math.test.js @@ -0,0 +1,289 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256 } = constants; +const { Rounding } = require('../../helpers/enums.js'); + +const Math = artifacts.require('$Math'); + +contract('Math', function () { + const min = new BN('1234'); + const max = new BN('5678'); + const MAX_UINT256_SUB1 = MAX_UINT256.sub(new BN('1')); + const MAX_UINT256_SUB2 = MAX_UINT256.sub(new BN('2')); + + beforeEach(async function () { + this.math = await Math.new(); + }); + + describe('max', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$max(max, min)).to.be.bignumber.equal(max); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$max(min, max)).to.be.bignumber.equal(max); + }); + }); + + describe('min', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$min(min, max)).to.be.bignumber.equal(min); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$min(max, min)).to.be.bignumber.equal(min); + }); + }); + + describe('average', function () { + function bnAverage(a, b) { + return a.add(b).divn(2); + } + + it('is correctly calculated with two odd numbers', async function () { + const a = new BN('57417'); + const b = new BN('95431'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with two even numbers', async function () { + const a = new BN('42304'); + const b = new BN('84346'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with one even and one odd number', async function () { + const a = new BN('57417'); + const b = new BN('84346'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with two max uint256 numbers', async function () { + const a = MAX_UINT256; + expect(await this.math.$average(a, a)).to.be.bignumber.equal(bnAverage(a, a)); + }); + }); + + describe('ceilDiv', function () { + it('does not round up on exact division', async function () { + const a = new BN('10'); + const b = new BN('5'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('2'); + }); + + it('rounds up on division with remainders', async function () { + const a = new BN('42'); + const b = new BN('13'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('4'); + }); + + it('does not overflow', async function () { + const b = new BN('2'); + const result = new BN('1').shln(255); + expect(await this.math.$ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(result); + }); + + it('correctly computes max uint256 divided by 1', async function () { + const b = new BN('1'); + expect(await this.math.$ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(MAX_UINT256); + }); + }); + + describe('muldiv', function () { + it('divide by 0', async function () { + await expectRevert.unspecified(this.math.$mulDiv(1, 1, 0, Rounding.Down)); + }); + + describe('does round down', async function () { + it('small values', async function () { + expect(await this.math.$mulDiv('3', '4', '5', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$mulDiv('3', '5', '5', Rounding.Down)).to.be.bignumber.equal('3'); + }); + + it('large values', async function () { + expect( + await this.math.$mulDiv(new BN('42'), MAX_UINT256_SUB1, MAX_UINT256, Rounding.Down), + ).to.be.bignumber.equal(new BN('41')); + + expect(await this.math.$mulDiv(new BN('17'), MAX_UINT256, MAX_UINT256, Rounding.Down)).to.be.bignumber.equal( + new BN('17'), + ); + + expect( + await this.math.$mulDiv(MAX_UINT256_SUB1, MAX_UINT256_SUB1, MAX_UINT256, Rounding.Down), + ).to.be.bignumber.equal(MAX_UINT256_SUB2); + + expect( + await this.math.$mulDiv(MAX_UINT256, MAX_UINT256_SUB1, MAX_UINT256, Rounding.Down), + ).to.be.bignumber.equal(MAX_UINT256_SUB1); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256, MAX_UINT256, Rounding.Down)).to.be.bignumber.equal( + MAX_UINT256, + ); + }); + }); + + describe('does round up', async function () { + it('small values', async function () { + expect(await this.math.$mulDiv('3', '4', '5', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$mulDiv('3', '5', '5', Rounding.Up)).to.be.bignumber.equal('3'); + }); + + it('large values', async function () { + expect(await this.math.$mulDiv(new BN('42'), MAX_UINT256_SUB1, MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + new BN('42'), + ); + + expect(await this.math.$mulDiv(new BN('17'), MAX_UINT256, MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + new BN('17'), + ); + + expect( + await this.math.$mulDiv(MAX_UINT256_SUB1, MAX_UINT256_SUB1, MAX_UINT256, Rounding.Up), + ).to.be.bignumber.equal(MAX_UINT256_SUB1); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256_SUB1, MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + MAX_UINT256_SUB1, + ); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256, MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + MAX_UINT256, + ); + }); + }); + }); + + describe('sqrt', function () { + it('rounds down', async function () { + expect(await this.math.$sqrt('0', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$sqrt('1', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('2', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('3', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('4', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('144', Rounding.Down)).to.be.bignumber.equal('12'); + expect(await this.math.$sqrt('999999', Rounding.Down)).to.be.bignumber.equal('999'); + expect(await this.math.$sqrt('1000000', Rounding.Down)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000001', Rounding.Down)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1002000', Rounding.Down)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1002001', Rounding.Down)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt(MAX_UINT256, Rounding.Down)).to.be.bignumber.equal( + '340282366920938463463374607431768211455', + ); + }); + + it('rounds up', async function () { + expect(await this.math.$sqrt('0', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$sqrt('1', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('2', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('3', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('4', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('144', Rounding.Up)).to.be.bignumber.equal('12'); + expect(await this.math.$sqrt('999999', Rounding.Up)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000000', Rounding.Up)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000001', Rounding.Up)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt('1002000', Rounding.Up)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt('1002001', Rounding.Up)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt(MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + '340282366920938463463374607431768211456', + ); + }); + }); + + describe('log', function () { + describe('log2', function () { + it('rounds down', async function () { + // For some reason calling .$log2() directly fails + expect(await this.math.methods['$log2(uint256,uint8)']('0', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('1', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('2', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('3', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('4', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('5', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('6', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('7', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('8', Rounding.Down)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('9', Rounding.Down)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)'](MAX_UINT256, Rounding.Down)).to.be.bignumber.equal( + '255', + ); + }); + + it('rounds up', async function () { + // For some reason calling .$log2() directly fails + expect(await this.math.methods['$log2(uint256,uint8)']('0', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('1', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('2', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('3', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('4', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('5', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('6', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('7', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('8', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('9', Rounding.Up)).to.be.bignumber.equal('4'); + expect(await this.math.methods['$log2(uint256,uint8)'](MAX_UINT256, Rounding.Up)).to.be.bignumber.equal('256'); + }); + }); + + describe('log10', function () { + it('rounds down', async function () { + expect(await this.math.$log10('0', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('1', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('2', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('9', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('10', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('11', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('99', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('100', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('101', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('999', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('1000', Rounding.Down)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1001', Rounding.Down)).to.be.bignumber.equal('3'); + expect(await this.math.$log10(MAX_UINT256, Rounding.Down)).to.be.bignumber.equal('77'); + }); + + it('rounds up', async function () { + expect(await this.math.$log10('0', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('1', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('2', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('9', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('10', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('11', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('99', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('100', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('101', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('999', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1000', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1001', Rounding.Up)).to.be.bignumber.equal('4'); + expect(await this.math.$log10(MAX_UINT256, Rounding.Up)).to.be.bignumber.equal('78'); + }); + }); + + describe('log256', function () { + it('rounds down', async function () { + expect(await this.math.$log256('0', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('1', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('2', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('255', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('256', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('257', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('65535', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('65536', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65537', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log256(MAX_UINT256, Rounding.Down)).to.be.bignumber.equal('31'); + }); + + it('rounds up', async function () { + expect(await this.math.$log256('0', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('1', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('2', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('255', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('256', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('257', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65535', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65536', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65537', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$log256(MAX_UINT256, Rounding.Up)).to.be.bignumber.equal('32'); + }); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js new file mode 100644 index 0000000..63223f5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js @@ -0,0 +1,152 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { range } = require('../../../scripts/helpers'); + +const SafeCast = artifacts.require('$SafeCast'); + +contract('SafeCast', async function () { + beforeEach(async function () { + this.safeCast = await SafeCast.new(); + }); + + function testToUint(bits) { + describe(`toUint${bits}`, () => { + const maxValue = new BN('2').pow(new BN(bits)).subn(1); + + it('downcasts 0', async function () { + expect(await this.safeCast[`$toUint${bits}`](0)).to.be.bignumber.equal('0'); + }); + + it('downcasts 1', async function () { + expect(await this.safeCast[`$toUint${bits}`](1)).to.be.bignumber.equal('1'); + }); + + it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () { + expect(await this.safeCast[`$toUint${bits}`](maxValue)).to.be.bignumber.equal(maxValue); + }); + + it(`reverts when downcasting 2^${bits} (${maxValue.addn(1)})`, async function () { + await expectRevert( + this.safeCast[`$toUint${bits}`](maxValue.addn(1)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + + it(`reverts when downcasting 2^${bits} + 1 (${maxValue.addn(2)})`, async function () { + await expectRevert( + this.safeCast[`$toUint${bits}`](maxValue.addn(2)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + }); + } + + range(8, 256, 8).forEach(bits => testToUint(bits)); + + describe('toUint256', () => { + const maxInt256 = new BN('2').pow(new BN(255)).subn(1); + const minInt256 = new BN('2').pow(new BN(255)).neg(); + + it('casts 0', async function () { + expect(await this.safeCast.$toUint256(0)).to.be.bignumber.equal('0'); + }); + + it('casts 1', async function () { + expect(await this.safeCast.$toUint256(1)).to.be.bignumber.equal('1'); + }); + + it(`casts INT256_MAX (${maxInt256})`, async function () { + expect(await this.safeCast.$toUint256(maxInt256)).to.be.bignumber.equal(maxInt256); + }); + + it('reverts when casting -1', async function () { + await expectRevert(this.safeCast.$toUint256(-1), 'SafeCast: value must be positive'); + }); + + it(`reverts when casting INT256_MIN (${minInt256})`, async function () { + await expectRevert(this.safeCast.$toUint256(minInt256), 'SafeCast: value must be positive'); + }); + }); + + function testToInt(bits) { + describe(`toInt${bits}`, () => { + const minValue = new BN('-2').pow(new BN(bits - 1)); + const maxValue = new BN('2').pow(new BN(bits - 1)).subn(1); + + it('downcasts 0', async function () { + expect(await this.safeCast[`$toInt${bits}`](0)).to.be.bignumber.equal('0'); + }); + + it('downcasts 1', async function () { + expect(await this.safeCast[`$toInt${bits}`](1)).to.be.bignumber.equal('1'); + }); + + it('downcasts -1', async function () { + expect(await this.safeCast[`$toInt${bits}`](-1)).to.be.bignumber.equal('-1'); + }); + + it(`downcasts -2^${bits - 1} (${minValue})`, async function () { + expect(await this.safeCast[`$toInt${bits}`](minValue)).to.be.bignumber.equal(minValue); + }); + + it(`downcasts 2^${bits - 1} - 1 (${maxValue})`, async function () { + expect(await this.safeCast[`$toInt${bits}`](maxValue)).to.be.bignumber.equal(maxValue); + }); + + it(`reverts when downcasting -2^${bits - 1} - 1 (${minValue.subn(1)})`, async function () { + await expectRevert( + this.safeCast[`$toInt${bits}`](minValue.subn(1)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + + it(`reverts when downcasting -2^${bits - 1} - 2 (${minValue.subn(2)})`, async function () { + await expectRevert( + this.safeCast[`$toInt${bits}`](minValue.subn(2)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + + it(`reverts when downcasting 2^${bits - 1} (${maxValue.addn(1)})`, async function () { + await expectRevert( + this.safeCast[`$toInt${bits}`](maxValue.addn(1)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + + it(`reverts when downcasting 2^${bits - 1} + 1 (${maxValue.addn(2)})`, async function () { + await expectRevert( + this.safeCast[`$toInt${bits}`](maxValue.addn(2)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + }); + } + + range(8, 256, 8).forEach(bits => testToInt(bits)); + + describe('toInt256', () => { + const maxUint256 = new BN('2').pow(new BN(256)).subn(1); + const maxInt256 = new BN('2').pow(new BN(255)).subn(1); + + it('casts 0', async function () { + expect(await this.safeCast.$toInt256(0)).to.be.bignumber.equal('0'); + }); + + it('casts 1', async function () { + expect(await this.safeCast.$toInt256(1)).to.be.bignumber.equal('1'); + }); + + it(`casts INT256_MAX (${maxInt256})`, async function () { + expect(await this.safeCast.$toInt256(maxInt256)).to.be.bignumber.equal(maxInt256); + }); + + it(`reverts when casting INT256_MAX + 1 (${maxInt256.addn(1)})`, async function () { + await expectRevert(this.safeCast.$toInt256(maxInt256.addn(1)), "SafeCast: value doesn't fit in an int256"); + }); + + it(`reverts when casting UINT256_MAX (${maxUint256})`, async function () { + await expectRevert(this.safeCast.$toInt256(maxUint256), "SafeCast: value doesn't fit in an int256"); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SafeMath.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SafeMath.test.js new file mode 100644 index 0000000..9598ac5 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SafeMath.test.js @@ -0,0 +1,433 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { MAX_UINT256 } = constants; + +const { expect } = require('chai'); + +const SafeMath = artifacts.require('$SafeMath'); +const SafeMathMemoryCheck = artifacts.require('$SafeMathMemoryCheck'); + +function expectStruct(value, expected) { + for (const key in expected) { + if (BN.isBN(value[key])) { + expect(value[key]).to.be.bignumber.equal(expected[key]); + } else { + expect(value[key]).to.be.equal(expected[key]); + } + } +} + +contract('SafeMath', function () { + beforeEach(async function () { + this.safeMath = await SafeMath.new(); + }); + + async function testCommutative(fn, lhs, rhs, expected, ...extra) { + expect(await fn(lhs, rhs, ...extra)).to.be.bignumber.equal(expected); + expect(await fn(rhs, lhs, ...extra)).to.be.bignumber.equal(expected); + } + + async function testFailsCommutative(fn, lhs, rhs, reason, ...extra) { + if (reason === undefined) { + await expectRevert.unspecified(fn(lhs, rhs, ...extra)); + await expectRevert.unspecified(fn(rhs, lhs, ...extra)); + } else { + await expectRevert(fn(lhs, rhs, ...extra), reason); + await expectRevert(fn(rhs, lhs, ...extra), reason); + } + } + + async function testCommutativeIterable(fn, lhs, rhs, expected, ...extra) { + expectStruct(await fn(lhs, rhs, ...extra), expected); + expectStruct(await fn(rhs, lhs, ...extra), expected); + } + + describe('with flag', function () { + describe('add', function () { + it('adds correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + testCommutativeIterable(this.safeMath.$tryAdd, a, b, [true, a.add(b)]); + }); + + it('reverts on addition overflow', async function () { + const a = MAX_UINT256; + const b = new BN('1'); + + testCommutativeIterable(this.safeMath.$tryAdd, a, b, [false, '0']); + }); + }); + + describe('sub', function () { + it('subtracts correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + expectStruct(await this.safeMath.$trySub(a, b), [true, a.sub(b)]); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$trySub(a, b), [false, '0']); + }); + }); + + describe('mul', function () { + it('multiplies correctly', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + testCommutativeIterable(this.safeMath.$tryMul, a, b, [true, a.mul(b)]); + }); + + it('multiplies by zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + testCommutativeIterable(this.safeMath.$tryMul, a, b, [true, a.mul(b)]); + }); + + it('reverts on multiplication overflow', async function () { + const a = MAX_UINT256; + const b = new BN('2'); + + testCommutativeIterable(this.safeMath.$tryMul, a, b, [false, '0']); + }); + }); + + describe('div', function () { + it('divides correctly', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('reverts on division by zero', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + expectStruct(await this.safeMath.$tryDiv(a, b), [false, '0']); + }); + }); + + describe('mod', function () { + describe('modulos correctly', async function () { + it('when the dividend is smaller than the divisor', async function () { + const a = new BN('284'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = new BN('17034'); // 17034 == 5678 * 3 + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryMod(a, b), [true, a.mod(b)]); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + expectStruct(await this.safeMath.$tryMod(a, b), [false, '0']); + }); + }); + }); + + describe('with default revert message', function () { + describe('add', function () { + it('adds correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + await testCommutative(this.safeMath.$add, a, b, a.add(b)); + }); + + it('reverts on addition overflow', async function () { + const a = MAX_UINT256; + const b = new BN('1'); + + await testFailsCommutative(this.safeMath.$add, a, b, undefined); + }); + }); + + describe('sub', function () { + it('subtracts correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + expect(await this.safeMath.$sub(a, b)).to.be.bignumber.equal(a.sub(b)); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await expectRevert.unspecified(this.safeMath.$sub(a, b)); + }); + }); + + describe('mul', function () { + it('multiplies correctly', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await testCommutative(this.safeMath.$mul, a, b, a.mul(b)); + }); + + it('multiplies by zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + await testCommutative(this.safeMath.$mul, a, b, '0'); + }); + + it('reverts on multiplication overflow', async function () { + const a = MAX_UINT256; + const b = new BN('2'); + + await testFailsCommutative(this.safeMath.$mul, a, b, undefined); + }); + }); + + describe('div', function () { + it('divides correctly', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal(a.div(b)); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal('0'); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal('1'); + }); + + it('reverts on division by zero', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + await expectRevert.unspecified(this.safeMath.$div(a, b)); + }); + }); + + describe('mod', function () { + describe('modulos correctly', async function () { + it('when the dividend is smaller than the divisor', async function () { + const a = new BN('284'); + const b = new BN('5678'); + + expect(await this.safeMath.$mod(a, b)).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expect(await this.safeMath.$mod(a, b)).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect(await this.safeMath.$mod(a, b)).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = new BN('17034'); // 17034 == 5678 * 3 + const b = new BN('5678'); + + expect(await this.safeMath.$mod(a, b)).to.be.bignumber.equal(a.mod(b)); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + await expectRevert.unspecified(this.safeMath.$mod(a, b)); + }); + }); + }); + + describe('with custom revert message', function () { + describe('sub', function () { + it('subtracts correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + expect( + await this.safeMath.methods['$sub(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.sub(b)); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await expectRevert( + this.safeMath.methods['$sub(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + 'MyErrorMessage', + ); + }); + }); + + describe('div', function () { + it('divides correctly', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$div(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.div(b)); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$div(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal('0'); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$div(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal('1'); + }); + + it('reverts on division by zero', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + await expectRevert( + this.safeMath.methods['$div(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + 'MyErrorMessage', + ); + }); + }); + + describe('mod', function () { + describe('modulos correctly', async function () { + it('when the dividend is smaller than the divisor', async function () { + const a = new BN('284'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = new BN('17034'); // 17034 == 5678 * 3 + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.mod(b)); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + await expectRevert( + this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + 'MyErrorMessage', + ); + }); + }); + }); + + describe('memory leakage', function () { + beforeEach(async function () { + this.safeMathMemoryCheck = await SafeMathMemoryCheck.new(); + }); + + it('add', async function () { + expect(await this.safeMathMemoryCheck.$addMemoryCheck()).to.be.bignumber.equal('0'); + }); + + it('sub', async function () { + expect(await this.safeMathMemoryCheck.$subMemoryCheck()).to.be.bignumber.equal('0'); + }); + + it('mul', async function () { + expect(await this.safeMathMemoryCheck.$mulMemoryCheck()).to.be.bignumber.equal('0'); + }); + + it('div', async function () { + expect(await this.safeMathMemoryCheck.$divMemoryCheck()).to.be.bignumber.equal('0'); + }); + + it('mod', async function () { + expect(await this.safeMathMemoryCheck.$modMemoryCheck()).to.be.bignumber.equal('0'); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js new file mode 100644 index 0000000..c014e22 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js @@ -0,0 +1,95 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MIN_INT256, MAX_INT256 } = constants; + +const SignedMath = artifacts.require('$SignedMath'); + +contract('SignedMath', function () { + const min = new BN('-1234'); + const max = new BN('5678'); + + beforeEach(async function () { + this.math = await SignedMath.new(); + }); + + describe('max', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$max(max, min)).to.be.bignumber.equal(max); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$max(min, max)).to.be.bignumber.equal(max); + }); + }); + + describe('min', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$min(min, max)).to.be.bignumber.equal(min); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$min(max, min)).to.be.bignumber.equal(min); + }); + }); + + describe('average', function () { + function bnAverage(a, b) { + return a.add(b).divn(2); + } + + it('is correctly calculated with various input', async function () { + const valuesX = [ + new BN('0'), + new BN('3'), + new BN('-3'), + new BN('4'), + new BN('-4'), + new BN('57417'), + new BN('-57417'), + new BN('42304'), + new BN('-42304'), + MIN_INT256, + MAX_INT256, + ]; + + const valuesY = [ + new BN('0'), + new BN('5'), + new BN('-5'), + new BN('2'), + new BN('-2'), + new BN('57417'), + new BN('-57417'), + new BN('42304'), + new BN('-42304'), + MIN_INT256, + MAX_INT256, + ]; + + for (const x of valuesX) { + for (const y of valuesY) { + expect(await this.math.$average(x, y)).to.be.bignumber.equal( + bnAverage(x, y), + `Bad result for average(${x}, ${y})`, + ); + } + } + }); + }); + + describe('abs', function () { + for (const n of [ + MIN_INT256, + MIN_INT256.addn(1), + new BN('-1'), + new BN('0'), + new BN('1'), + MAX_INT256.subn(1), + MAX_INT256, + ]) { + it(`correctly computes the absolute value of ${n}`, async function () { + expect(await this.math.$abs(n)).to.be.bignumber.equal(n.abs()); + }); + } + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SignedSafeMath.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SignedSafeMath.test.js new file mode 100644 index 0000000..3b6530c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/math/SignedSafeMath.test.js @@ -0,0 +1,152 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { MAX_INT256, MIN_INT256 } = constants; + +const { expect } = require('chai'); + +const SignedSafeMath = artifacts.require('$SignedSafeMath'); + +contract('SignedSafeMath', function () { + beforeEach(async function () { + this.safeMath = await SignedSafeMath.new(); + }); + + async function testCommutative(fn, lhs, rhs, expected) { + expect(await fn(lhs, rhs)).to.be.bignumber.equal(expected); + expect(await fn(rhs, lhs)).to.be.bignumber.equal(expected); + } + + async function testFailsCommutative(fn, lhs, rhs) { + await expectRevert.unspecified(fn(lhs, rhs)); + await expectRevert.unspecified(fn(rhs, lhs)); + } + + describe('add', function () { + it('adds correctly if it does not overflow and the result is positive', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await testCommutative(this.safeMath.$add, a, b, a.add(b)); + }); + + it('adds correctly if it does not overflow and the result is negative', async function () { + const a = MAX_INT256; + const b = MIN_INT256; + + await testCommutative(this.safeMath.$add, a, b, a.add(b)); + }); + + it('reverts on positive addition overflow', async function () { + const a = MAX_INT256; + const b = new BN('1'); + + await testFailsCommutative(this.safeMath.$add, a, b); + }); + + it('reverts on negative addition overflow', async function () { + const a = MIN_INT256; + const b = new BN('-1'); + + await testFailsCommutative(this.safeMath.$add, a, b); + }); + }); + + describe('sub', function () { + it('subtracts correctly if it does not overflow and the result is positive', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + const result = await this.safeMath.$sub(a, b); + expect(result).to.be.bignumber.equal(a.sub(b)); + }); + + it('subtracts correctly if it does not overflow and the result is negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + const result = await this.safeMath.$sub(a, b); + expect(result).to.be.bignumber.equal(a.sub(b)); + }); + + it('reverts on positive subtraction overflow', async function () { + const a = MAX_INT256; + const b = new BN('-1'); + + await expectRevert.unspecified(this.safeMath.$sub(a, b)); + }); + + it('reverts on negative subtraction overflow', async function () { + const a = MIN_INT256; + const b = new BN('1'); + + await expectRevert.unspecified(this.safeMath.$sub(a, b)); + }); + }); + + describe('mul', function () { + it('multiplies correctly', async function () { + const a = new BN('5678'); + const b = new BN('-1234'); + + await testCommutative(this.safeMath.$mul, a, b, a.mul(b)); + }); + + it('multiplies by zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + await testCommutative(this.safeMath.$mul, a, b, '0'); + }); + + it('reverts on multiplication overflow, positive operands', async function () { + const a = MAX_INT256; + const b = new BN('2'); + + await testFailsCommutative(this.safeMath.$mul, a, b); + }); + + it('reverts when minimum integer is multiplied by -1', async function () { + const a = MIN_INT256; + const b = new BN('-1'); + + await testFailsCommutative(this.safeMath.$mul, a, b); + }); + }); + + describe('div', function () { + it('divides correctly', async function () { + const a = new BN('-5678'); + const b = new BN('5678'); + + const result = await this.safeMath.$div(a, b); + expect(result).to.be.bignumber.equal(a.div(b)); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal('0'); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal('1'); + }); + + it('reverts on division by zero', async function () { + const a = new BN('-5678'); + const b = new BN('0'); + + await expectRevert.unspecified(this.safeMath.$div(a, b)); + }); + + it('reverts on overflow, negative second', async function () { + const a = new BN(MIN_INT256); + const b = new BN('-1'); + + await expectRevert.unspecified(this.safeMath.$div(a, b)); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js new file mode 100644 index 0000000..8a1470c --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js @@ -0,0 +1,145 @@ +const { BN } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const BitMap = artifacts.require('$BitMaps'); + +contract('BitMap', function () { + const keyA = new BN('7891'); + const keyB = new BN('451'); + const keyC = new BN('9592328'); + + beforeEach(async function () { + this.bitmap = await BitMap.new(); + }); + + it('starts empty', async function () { + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + describe('setTo', function () { + it('set a key to true', async function () { + await this.bitmap.$setTo(0, keyA, true); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('set a key to false', async function () { + await this.bitmap.$setTo(0, keyA, true); + await this.bitmap.$setTo(0, keyA, false); + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('set several consecutive keys', async function () { + await this.bitmap.$setTo(0, keyA.addn(0), true); + await this.bitmap.$setTo(0, keyA.addn(1), true); + await this.bitmap.$setTo(0, keyA.addn(2), true); + await this.bitmap.$setTo(0, keyA.addn(3), true); + await this.bitmap.$setTo(0, keyA.addn(4), true); + await this.bitmap.$setTo(0, keyA.addn(2), false); + await this.bitmap.$setTo(0, keyA.addn(4), false); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + }); + + describe('set', function () { + it('adds a key', async function () { + await this.bitmap.$set(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('adds several keys', async function () { + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(true); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('adds several consecutive keys', async function () { + await this.bitmap.$set(0, keyA.addn(0)); + await this.bitmap.$set(0, keyA.addn(1)); + await this.bitmap.$set(0, keyA.addn(3)); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + }); + + describe('unset', function () { + it('removes added keys', async function () { + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + await this.bitmap.$unset(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(true); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('removes consecutive added keys', async function () { + await this.bitmap.$set(0, keyA.addn(0)); + await this.bitmap.$set(0, keyA.addn(1)); + await this.bitmap.$set(0, keyA.addn(3)); + await this.bitmap.$unset(0, keyA.addn(1)); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + + it('adds and removes multiple keys', async function () { + // [] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyC); + + // [A, C] + + await this.bitmap.$unset(0, keyA); + await this.bitmap.$unset(0, keyB); + + // [C] + + await this.bitmap.$set(0, keyB); + + // [C, B] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$unset(0, keyC); + + // [A, B] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + + // [A, B] + + await this.bitmap.$set(0, keyC); + await this.bitmap.$unset(0, keyA); + + // [B, C] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$unset(0, keyB); + + // [A, C] + + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(true); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js new file mode 100644 index 0000000..2fbb8dc --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js @@ -0,0 +1,99 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const DoubleEndedQueue = artifacts.require('$DoubleEndedQueue'); + +/** Rebuild the content of the deque as a JS array. */ +const getContent = deque => + deque.$length(0).then(bn => + Promise.all( + Array(bn.toNumber()) + .fill() + .map((_, i) => deque.$at(0, i)), + ), + ); + +contract('DoubleEndedQueue', function () { + const bytesA = '0xdeadbeef'.padEnd(66, '0'); + const bytesB = '0x0123456789'.padEnd(66, '0'); + const bytesC = '0x42424242'.padEnd(66, '0'); + const bytesD = '0x171717'.padEnd(66, '0'); + + beforeEach(async function () { + this.deque = await DoubleEndedQueue.new(); + }); + + describe('when empty', function () { + it('getters', async function () { + expect(await this.deque.$empty(0)).to.be.equal(true); + expect(await getContent(this.deque)).to.have.ordered.members([]); + }); + + it('reverts on accesses', async function () { + await expectRevertCustomError(this.deque.$popBack(0), 'Empty()'); + await expectRevertCustomError(this.deque.$popFront(0), 'Empty()'); + await expectRevertCustomError(this.deque.$back(0), 'Empty()'); + await expectRevertCustomError(this.deque.$front(0), 'Empty()'); + }); + }); + + describe('when not empty', function () { + beforeEach(async function () { + await this.deque.$pushBack(0, bytesB); + await this.deque.$pushFront(0, bytesA); + await this.deque.$pushBack(0, bytesC); + this.content = [bytesA, bytesB, bytesC]; + }); + + it('getters', async function () { + expect(await this.deque.$empty(0)).to.be.equal(false); + expect(await this.deque.$length(0)).to.be.bignumber.equal(this.content.length.toString()); + expect(await this.deque.$front(0)).to.be.equal(this.content[0]); + expect(await this.deque.$back(0)).to.be.equal(this.content[this.content.length - 1]); + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('out of bounds access', async function () { + await expectRevertCustomError(this.deque.$at(0, this.content.length), 'OutOfBounds()'); + }); + + describe('push', function () { + it('front', async function () { + await this.deque.$pushFront(0, bytesD); + this.content.unshift(bytesD); // add element at the beginning + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('back', async function () { + await this.deque.$pushBack(0, bytesD); + this.content.push(bytesD); // add element at the end + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + }); + + describe('pop', function () { + it('front', async function () { + const value = this.content.shift(); // remove first element + expectEvent(await this.deque.$popFront(0), 'return$popFront', { value }); + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('back', async function () { + const value = this.content.pop(); // remove last element + expectEvent(await this.deque.$popBack(0), 'return$popBack', { value }); + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + }); + + it('clear', async function () { + await this.deque.$clear(0); + + expect(await this.deque.$empty(0)).to.be.equal(true); + expect(await getContent(this.deque)).to.have.ordered.members([]); + }); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js new file mode 100644 index 0000000..b4b5ee3 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js @@ -0,0 +1,185 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const zip = require('lodash.zip'); + +function shouldBehaveLikeMap(keys, values, zeroValue, methods, events) { + const [keyA, keyB, keyC] = keys; + const [valueA, valueB, valueC] = values; + + async function expectMembersMatch(map, keys, values) { + expect(keys.length).to.equal(values.length); + + await Promise.all(keys.map(async key => expect(await methods.contains(map, key)).to.equal(true))); + + expect(await methods.length(map)).to.bignumber.equal(keys.length.toString()); + + expect((await Promise.all(keys.map(key => methods.get(map, key)))).map(k => k.toString())).to.have.same.members( + values.map(value => value.toString()), + ); + + // To compare key-value pairs, we zip keys and values, and convert BNs to + // strings to workaround Chai limitations when dealing with nested arrays + expect( + await Promise.all( + [...Array(keys.length).keys()].map(async index => { + const entry = await methods.at(map, index); + return [entry[0].toString(), entry[1].toString()]; + }), + ), + ).to.have.same.deep.members( + zip( + keys.map(k => k.toString()), + values.map(v => v.toString()), + ), + ); + + // This also checks that both arrays have the same length + expect((await methods.keys(map)).map(k => k.toString())).to.have.same.members(keys.map(key => key.toString())); + } + + it('starts empty', async function () { + expect(await methods.contains(this.map, keyA)).to.equal(false); + + await expectMembersMatch(this.map, [], []); + }); + + describe('set', function () { + it('adds a key', async function () { + const receipt = await methods.set(this.map, keyA, valueA); + expectEvent(receipt, events.setReturn, { ret0: true }); + + await expectMembersMatch(this.map, [keyA], [valueA]); + }); + + it('adds several keys', async function () { + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyB, valueB); + + await expectMembersMatch(this.map, [keyA, keyB], [valueA, valueB]); + expect(await methods.contains(this.map, keyC)).to.equal(false); + }); + + it('returns false when adding keys already in the set', async function () { + await methods.set(this.map, keyA, valueA); + + const receipt = await methods.set(this.map, keyA, valueA); + expectEvent(receipt, events.setReturn, { ret0: false }); + + await expectMembersMatch(this.map, [keyA], [valueA]); + }); + + it('updates values for keys already in the set', async function () { + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyA, valueB); + + await expectMembersMatch(this.map, [keyA], [valueB]); + }); + }); + + describe('remove', function () { + it('removes added keys', async function () { + await methods.set(this.map, keyA, valueA); + + const receipt = await methods.remove(this.map, keyA); + expectEvent(receipt, events.removeReturn, { ret0: true }); + + expect(await methods.contains(this.map, keyA)).to.equal(false); + await expectMembersMatch(this.map, [], []); + }); + + it('returns false when removing keys not in the set', async function () { + const receipt = await methods.remove(this.map, keyA); + expectEvent(receipt, events.removeReturn, { ret0: false }); + + expect(await methods.contains(this.map, keyA)).to.equal(false); + }); + + it('adds and removes multiple keys', async function () { + // [] + + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyC, valueC); + + // [A, C] + + await methods.remove(this.map, keyA); + await methods.remove(this.map, keyB); + + // [C] + + await methods.set(this.map, keyB, valueB); + + // [C, B] + + await methods.set(this.map, keyA, valueA); + await methods.remove(this.map, keyC); + + // [A, B] + + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyB, valueB); + + // [A, B] + + await methods.set(this.map, keyC, valueC); + await methods.remove(this.map, keyA); + + // [B, C] + + await methods.set(this.map, keyA, valueA); + await methods.remove(this.map, keyB); + + // [A, C] + + await expectMembersMatch(this.map, [keyA, keyC], [valueA, valueC]); + + expect(await methods.contains(this.map, keyA)).to.equal(true); + expect(await methods.contains(this.map, keyB)).to.equal(false); + expect(await methods.contains(this.map, keyC)).to.equal(true); + }); + }); + + describe('read', function () { + beforeEach(async function () { + await methods.set(this.map, keyA, valueA); + }); + + describe('get', function () { + it('existing value', async function () { + expect(await methods.get(this.map, keyA).then(r => r.toString())).to.be.equal(valueA.toString()); + }); + it('missing value', async function () { + await expectRevert(methods.get(this.map, keyB), 'EnumerableMap: nonexistent key'); + }); + }); + + describe('get with message', function () { + it('existing value', async function () { + expect(await methods.getWithMessage(this.map, keyA, 'custom error string').then(r => r.toString())).to.be.equal( + valueA.toString(), + ); + }); + it('missing value', async function () { + await expectRevert(methods.getWithMessage(this.map, keyB, 'custom error string'), 'custom error string'); + }); + }); + + describe('tryGet', function () { + it('existing value', async function () { + const result = await methods.tryGet(this.map, keyA); + expect(result['0']).to.be.equal(true); + expect(result['1'].toString()).to.be.equal(valueA.toString()); + }); + it('missing value', async function () { + const result = await methods.tryGet(this.map, keyB); + expect(result['0']).to.be.equal(false); + expect(result['1'].toString()).to.be.equal(zeroValue.toString()); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeMap, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js new file mode 100644 index 0000000..548e737 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js @@ -0,0 +1,151 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { mapValues } = require('../../helpers/map-values'); + +const EnumerableMap = artifacts.require('$EnumerableMap'); + +const { shouldBehaveLikeMap } = require('./EnumerableMap.behavior'); + +const getMethods = ms => { + return mapValues( + ms, + m => + (self, ...args) => + self.methods[m](0, ...args), + ); +}; + +contract('EnumerableMap', function (accounts) { + const [accountA, accountB, accountC] = accounts; + + const keyA = new BN('7891'); + const keyB = new BN('451'); + const keyC = new BN('9592328'); + + const bytesA = '0xdeadbeef'.padEnd(66, '0'); + const bytesB = '0x0123456789'.padEnd(66, '0'); + const bytesC = '0x42424242'.padEnd(66, '0'); + + beforeEach(async function () { + this.map = await EnumerableMap.new(); + }); + + // AddressToUintMap + describe('AddressToUintMap', function () { + shouldBehaveLikeMap( + [accountA, accountB, accountC], + [keyA, keyB, keyC], + new BN('0'), + getMethods({ + set: '$set(uint256,address,uint256)', + get: '$get(uint256,address)', + getWithMessage: '$get(uint256,address,string)', + tryGet: '$tryGet(uint256,address)', + remove: '$remove(uint256,address)', + length: '$length_EnumerableMap_AddressToUintMap(uint256)', + at: '$at_EnumerableMap_AddressToUintMap(uint256,uint256)', + contains: '$contains(uint256,address)', + keys: '$keys_EnumerableMap_AddressToUintMap(uint256)', + }), + { + setReturn: 'return$set_EnumerableMap_AddressToUintMap_address_uint256', + removeReturn: 'return$remove_EnumerableMap_AddressToUintMap_address', + }, + ); + }); + + // UintToAddressMap + describe('UintToAddressMap', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC], + [accountA, accountB, accountC], + 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)', + }), + { + setReturn: 'return$set_EnumerableMap_UintToAddressMap_uint256_address', + removeReturn: 'return$remove_EnumerableMap_UintToAddressMap_uint256', + }, + ); + }); + + // Bytes32ToBytes32Map + describe('Bytes32ToBytes32Map', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC].map(k => '0x' + k.toString(16).padEnd(64, '0')), + [bytesA, bytesB, bytesC], + 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)', + }), + { + setReturn: 'return$set_EnumerableMap_Bytes32ToBytes32Map_bytes32_bytes32', + removeReturn: 'return$remove_EnumerableMap_Bytes32ToBytes32Map_bytes32', + }, + ); + }); + + // UintToUintMap + describe('UintToUintMap', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC], + [keyA, keyB, keyC].map(k => k.add(new BN('1332'))), + 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)', + }), + { + setReturn: 'return$set_EnumerableMap_UintToUintMap_uint256_uint256', + removeReturn: 'return$remove_EnumerableMap_UintToUintMap_uint256', + }, + ); + }); + + // Bytes32ToUintMap + describe('Bytes32ToUintMap', function () { + shouldBehaveLikeMap( + [bytesA, bytesB, bytesC], + [keyA, keyB, keyC], + 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)', + }), + { + setReturn: 'return$set_EnumerableMap_Bytes32ToUintMap_bytes32_uint256', + removeReturn: 'return$remove_EnumerableMap_Bytes32ToUintMap_bytes32', + }, + ); + }); +}); diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js new file mode 100644 index 0000000..f80eb81 --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js @@ -0,0 +1,129 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +function shouldBehaveLikeSet(values, methods, events) { + const [valueA, valueB, valueC] = values; + + async function expectMembersMatch(set, values) { + const contains = await Promise.all(values.map(value => methods.contains(set, value))); + expect(contains.every(Boolean)).to.be.equal(true); + + const length = await methods.length(set); + expect(length).to.bignumber.equal(values.length.toString()); + + // To compare values we convert to strings to workaround Chai + // limitations when dealing with nested arrays (required for BNs) + const indexedValues = await Promise.all( + Array(values.length) + .fill() + .map((_, index) => methods.at(set, index)), + ); + expect(indexedValues.map(v => v.toString())).to.have.same.members(values.map(v => v.toString())); + + const returnedValues = await methods.values(set); + expect(returnedValues.map(v => v.toString())).to.have.same.members(values.map(v => v.toString())); + } + + it('starts empty', async function () { + expect(await methods.contains(this.set, valueA)).to.equal(false); + + await expectMembersMatch(this.set, []); + }); + + describe('add', function () { + it('adds a value', async function () { + const receipt = await methods.add(this.set, valueA); + expectEvent(receipt, events.addReturn, { ret0: true }); + + await expectMembersMatch(this.set, [valueA]); + }); + + it('adds several values', async function () { + await methods.add(this.set, valueA); + await methods.add(this.set, valueB); + + await expectMembersMatch(this.set, [valueA, valueB]); + expect(await methods.contains(this.set, valueC)).to.equal(false); + }); + + it('returns false when adding values already in the set', async function () { + await methods.add(this.set, valueA); + + const receipt = await methods.add(this.set, valueA); + expectEvent(receipt, events.addReturn, { ret0: false }); + + await expectMembersMatch(this.set, [valueA]); + }); + }); + + describe('at', function () { + it('reverts when retrieving non-existent elements', async function () { + await expectRevert.unspecified(methods.at(this.set, 0)); + }); + }); + + describe('remove', function () { + it('removes added values', async function () { + await methods.add(this.set, valueA); + + const receipt = await methods.remove(this.set, valueA); + expectEvent(receipt, events.removeReturn, { ret0: true }); + + expect(await methods.contains(this.set, valueA)).to.equal(false); + await expectMembersMatch(this.set, []); + }); + + it('returns false when removing values not in the set', async function () { + const receipt = await methods.remove(this.set, valueA); + expectEvent(receipt, events.removeReturn, { ret0: false }); + + expect(await methods.contains(this.set, valueA)).to.equal(false); + }); + + it('adds and removes multiple values', async function () { + // [] + + await methods.add(this.set, valueA); + await methods.add(this.set, valueC); + + // [A, C] + + await methods.remove(this.set, valueA); + await methods.remove(this.set, valueB); + + // [C] + + await methods.add(this.set, valueB); + + // [C, B] + + await methods.add(this.set, valueA); + await methods.remove(this.set, valueC); + + // [A, B] + + await methods.add(this.set, valueA); + await methods.add(this.set, valueB); + + // [A, B] + + await methods.add(this.set, valueC); + await methods.remove(this.set, valueA); + + // [B, C] + + await methods.add(this.set, valueA); + await methods.remove(this.set, valueB); + + // [A, C] + + await expectMembersMatch(this.set, [valueA, valueC]); + + expect(await methods.contains(this.set, valueB)).to.equal(false); + }); + }); +} + +module.exports = { + shouldBehaveLikeSet, +}; diff --git a/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js new file mode 100644 index 0000000..862cb6d --- /dev/null +++ b/lib/crytic/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js @@ -0,0 +1,76 @@ +const EnumerableSet = artifacts.require('$EnumerableSet'); +const { mapValues } = require('../../helpers/map-values'); + +const { shouldBehaveLikeSet } = require('./EnumerableSet.behavior'); + +const getMethods = ms => { + return mapValues( + ms, + m => + (self, ...args) => + self.methods[m](0, ...args), + ); +}; + +contract('EnumerableSet', function (accounts) { + beforeEach(async function () { + this.set = await EnumerableSet.new(); + }); + + // Bytes32Set + describe('EnumerableBytes32Set', function () { + shouldBehaveLikeSet( + ['0xdeadbeef', '0x0123456789', '0x42424242'].map(e => e.padEnd(66, '0')), + getMethods({ + 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)', + }), + { + addReturn: 'return$add_EnumerableSet_Bytes32Set_bytes32', + removeReturn: 'return$remove_EnumerableSet_Bytes32Set_bytes32', + }, + ); + }); + + // AddressSet + describe('EnumerableAddressSet', function () { + shouldBehaveLikeSet( + accounts, + getMethods({ + 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)', + }), + { + addReturn: 'return$add_EnumerableSet_AddressSet_address', + removeReturn: 'return$remove_EnumerableSet_AddressSet_address', + }, + ); + }); + + // UintSet + describe('EnumerableUintSet', function () { + shouldBehaveLikeSet( + [1234, 5678, 9101112].map(e => web3.utils.toBN(e)), + getMethods({ + 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)', + }), + { + addReturn: 'return$add_EnumerableSet_UintSet_uint256', + removeReturn: 'return$remove_EnumerableSet_UintSet_uint256', + }, + ); + }); +}); diff --git a/lib/crytic/lib/solmate/.gas-snapshot b/lib/crytic/lib/solmate/.gas-snapshot new file mode 100644 index 0000000..c4c5c84 --- /dev/null +++ b/lib/crytic/lib/solmate/.gas-snapshot @@ -0,0 +1,459 @@ +AuthTest:testCallFunctionAsOwner() (gas: 29784) +AuthTest:testCallFunctionWithPermissiveAuthority() (gas: 124292) +AuthTest:testCallFunctionWithPermissiveAuthority(address) (runs: 256, μ: 129216, ~: 129235) +AuthTest:testFailCallFunctionAsNonOwner() (gas: 15523) +AuthTest:testFailCallFunctionAsNonOwner(address) (runs: 256, μ: 15685, ~: 15685) +AuthTest:testFailCallFunctionAsOwnerWithOutOfOrderAuthority() (gas: 136021) +AuthTest:testFailCallFunctionWithRestrictiveAuthority() (gas: 129144) +AuthTest:testFailCallFunctionWithRestrictiveAuthority(address) (runs: 256, μ: 129329, ~: 129329) +AuthTest:testFailSetAuthorityAsNonOwner() (gas: 18325) +AuthTest:testFailSetAuthorityAsNonOwner(address,address) (runs: 256, μ: 18594, ~: 18594) +AuthTest:testFailSetAuthorityWithRestrictiveAuthority() (gas: 129077) +AuthTest:testFailSetAuthorityWithRestrictiveAuthority(address,address) (runs: 256, μ: 129409, ~: 129409) +AuthTest:testFailTransferOwnershipAsNonOwner() (gas: 15641) +AuthTest:testFailTransferOwnershipAsNonOwner(address,address) (runs: 256, μ: 15922, ~: 15922) +AuthTest:testFailTransferOwnershipAsOwnerWithOutOfOrderAuthority() (gas: 136159) +AuthTest:testFailTransferOwnershipAsOwnerWithOutOfOrderAuthority(address) (runs: 256, μ: 136344, ~: 136344) +AuthTest:testFailTransferOwnershipWithRestrictiveAuthority() (gas: 129338) +AuthTest:testFailTransferOwnershipWithRestrictiveAuthority(address,address) (runs: 256, μ: 129588, ~: 129588) +AuthTest:testSetAuthorityAsOwner() (gas: 32214) +AuthTest:testSetAuthorityAsOwner(address) (runs: 256, μ: 32384, ~: 32384) +AuthTest:testSetAuthorityAsOwnerWithOutOfOrderAuthority() (gas: 226419) +AuthTest:testSetAuthorityWithPermissiveAuthority() (gas: 125962) +AuthTest:testSetAuthorityWithPermissiveAuthority(address,address) (runs: 256, μ: 130958, ~: 131055) +AuthTest:testTransferOwnershipAsOwner() (gas: 15298) +AuthTest:testTransferOwnershipAsOwner(address) (runs: 256, μ: 15469, ~: 15469) +AuthTest:testTransferOwnershipWithPermissiveAuthority() (gas: 127926) +AuthTest:testTransferOwnershipWithPermissiveAuthority(address,address) (runs: 256, μ: 130981, ~: 131000) +Bytes32AddressLibTest:testFillLast12Bytes() (gas: 223) +Bytes32AddressLibTest:testFromLast20Bytes() (gas: 191) +CREATE3Test:testDeployERC20() (gas: 853111) +CREATE3Test:testDeployERC20(bytes32,string,string,uint8) (runs: 256, μ: 923654, ~: 921961) +CREATE3Test:testFailDoubleDeployDifferentBytecode() (gas: 9079256848778914174) +CREATE3Test:testFailDoubleDeployDifferentBytecode(bytes32,bytes,bytes) (runs: 256, μ: 5062195514745832485, ~: 8937393460516727435) +CREATE3Test:testFailDoubleDeploySameBytecode() (gas: 9079256848778906218) +CREATE3Test:testFailDoubleDeploySameBytecode(bytes32,bytes) (runs: 256, μ: 5027837975401088877, ~: 8937393460516728677) +DSTestPlusTest:testBound() (gas: 14214) +DSTestPlusTest:testBound(uint256,uint256,uint256) (runs: 256, μ: 2787, ~: 2793) +DSTestPlusTest:testBrutalizeMemory() (gas: 823) +DSTestPlusTest:testFailBoundMinBiggerThanMax() (gas: 309) +DSTestPlusTest:testFailBoundMinBiggerThanMax(uint256,uint256,uint256) (runs: 256, μ: 460, ~: 462) +DSTestPlusTest:testRelApproxEqBothZeroesPasses() (gas: 425) +ERC1155Test:testApproveAll() (gas: 31009) +ERC1155Test:testApproveAll(address,bool) (runs: 256, μ: 16872, ~: 11440) +ERC1155Test:testBatchBalanceOf() (gas: 157631) +ERC1155Test:testBatchBalanceOf(address[],uint256[],uint256[],bytes) (runs: 256, μ: 3307946, ~: 2596398) +ERC1155Test:testBatchBurn() (gas: 151074) +ERC1155Test:testBatchBurn(address,uint256[],uint256[],uint256[],bytes) (runs: 256, μ: 3425444, ~: 3021348) +ERC1155Test:testBatchMintToEOA() (gas: 137337) +ERC1155Test:testBatchMintToEOA(address,uint256[],uint256[],bytes) (runs: 256, μ: 3261893, ~: 2923515) +ERC1155Test:testBatchMintToERC1155Recipient() (gas: 995703) +ERC1155Test:testBatchMintToERC1155Recipient(uint256[],uint256[],bytes) (runs: 256, μ: 7336290, ~: 6396323) +ERC1155Test:testBurn() (gas: 38598) +ERC1155Test:testBurn(address,uint256,uint256,bytes,uint256) (runs: 256, μ: 40221, ~: 42098) +ERC1155Test:testFailBalanceOfBatchWithArrayMismatch() (gas: 7933) +ERC1155Test:testFailBalanceOfBatchWithArrayMismatch(address[],uint256[]) (runs: 256, μ: 53386, ~: 54066) +ERC1155Test:testFailBatchBurnInsufficientBalance() (gas: 136156) +ERC1155Test:testFailBatchBurnInsufficientBalance(address,uint256[],uint256[],uint256[],bytes) (runs: 256, μ: 1278568, ~: 440335) +ERC1155Test:testFailBatchBurnWithArrayLengthMismatch() (gas: 135542) +ERC1155Test:testFailBatchBurnWithArrayLengthMismatch(address,uint256[],uint256[],uint256[],bytes) (runs: 256, μ: 77137, ~: 78751) +ERC1155Test:testFailBatchMintToNonERC1155Recipient() (gas: 167292) +ERC1155Test:testFailBatchMintToNonERC1155Recipient(uint256[],uint256[],bytes) (runs: 256, μ: 3131966, ~: 2673077) +ERC1155Test:testFailBatchMintToRevertingERC1155Recipient() (gas: 358811) +ERC1155Test:testFailBatchMintToRevertingERC1155Recipient(uint256[],uint256[],bytes) (runs: 256, μ: 3323504, ~: 2864613) +ERC1155Test:testFailBatchMintToWrongReturnDataERC1155Recipient() (gas: 310743) +ERC1155Test:testFailBatchMintToWrongReturnDataERC1155Recipient(uint256[],uint256[],bytes) (runs: 256, μ: 3275462, ~: 2816572) +ERC1155Test:testFailBatchMintToZero() (gas: 131737) +ERC1155Test:testFailBatchMintToZero(uint256[],uint256[],bytes) (runs: 256, μ: 3072466, ~: 2612336) +ERC1155Test:testFailBatchMintWithArrayMismatch() (gas: 9600) +ERC1155Test:testFailBatchMintWithArrayMismatch(address,uint256[],uint256[],bytes) (runs: 256, μ: 69252, ~: 68809) +ERC1155Test:testFailBurnInsufficientBalance() (gas: 34852) +ERC1155Test:testFailBurnInsufficientBalance(address,uint256,uint256,uint256,bytes) (runs: 256, μ: 35951, ~: 38209) +ERC1155Test:testFailMintToNonERC155Recipient() (gas: 68191) +ERC1155Test:testFailMintToNonERC155Recipient(uint256,uint256,bytes) (runs: 256, μ: 68507, ~: 69197) +ERC1155Test:testFailMintToRevertingERC155Recipient() (gas: 259435) +ERC1155Test:testFailMintToRevertingERC155Recipient(uint256,uint256,bytes) (runs: 256, μ: 259682, ~: 260373) +ERC1155Test:testFailMintToWrongReturnDataERC155Recipient() (gas: 259389) +ERC1155Test:testFailMintToWrongReturnDataERC155Recipient(uint256,uint256,bytes) (runs: 256, μ: 259706, ~: 260397) +ERC1155Test:testFailMintToZero() (gas: 33705) +ERC1155Test:testFailMintToZero(uint256,uint256,bytes) (runs: 256, μ: 33815, ~: 34546) +ERC1155Test:testFailSafeBatchTransferFromToNonERC1155Recipient() (gas: 321377) +ERC1155Test:testFailSafeBatchTransferFromToNonERC1155Recipient(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 3490437, ~: 2963551) +ERC1155Test:testFailSafeBatchTransferFromToRevertingERC1155Recipient() (gas: 512956) +ERC1155Test:testFailSafeBatchTransferFromToRevertingERC1155Recipient(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 3681974, ~: 3155082) +ERC1155Test:testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient() (gas: 464847) +ERC1155Test:testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 3633892, ~: 3107003) +ERC1155Test:testFailSafeBatchTransferFromToZero() (gas: 286556) +ERC1155Test:testFailSafeBatchTransferFromToZero(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 3455257, ~: 2928396) +ERC1155Test:testFailSafeBatchTransferFromWithArrayLengthMismatch() (gas: 162674) +ERC1155Test:testFailSafeBatchTransferFromWithArrayLengthMismatch(address,uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 81184, ~: 82042) +ERC1155Test:testFailSafeBatchTransferInsufficientBalance() (gas: 163555) +ERC1155Test:testFailSafeBatchTransferInsufficientBalance(address,uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 1497154, ~: 499517) +ERC1155Test:testFailSafeTransferFromInsufficientBalance() (gas: 63245) +ERC1155Test:testFailSafeTransferFromInsufficientBalance(address,uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 63986, ~: 67405) +ERC1155Test:testFailSafeTransferFromSelfInsufficientBalance() (gas: 34297) +ERC1155Test:testFailSafeTransferFromSelfInsufficientBalance(address,uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 36266, ~: 38512) +ERC1155Test:testFailSafeTransferFromToNonERC155Recipient() (gas: 96510) +ERC1155Test:testFailSafeTransferFromToNonERC155Recipient(uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 96580, ~: 100546) +ERC1155Test:testFailSafeTransferFromToRevertingERC1155Recipient() (gas: 287731) +ERC1155Test:testFailSafeTransferFromToRevertingERC1155Recipient(uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 287750, ~: 291719) +ERC1155Test:testFailSafeTransferFromToWrongReturnDataERC1155Recipient() (gas: 239587) +ERC1155Test:testFailSafeTransferFromToWrongReturnDataERC1155Recipient(uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 239629, ~: 243598) +ERC1155Test:testFailSafeTransferFromToZero() (gas: 62014) +ERC1155Test:testFailSafeTransferFromToZero(uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 62068, ~: 66037) +ERC1155Test:testMintToEOA() (gas: 34765) +ERC1155Test:testMintToEOA(address,uint256,uint256,bytes) (runs: 256, μ: 35426, ~: 35907) +ERC1155Test:testMintToERC1155Recipient() (gas: 661411) +ERC1155Test:testMintToERC1155Recipient(uint256,uint256,bytes) (runs: 256, μ: 691094, ~: 684374) +ERC1155Test:testSafeBatchTransferFromToEOA() (gas: 297822) +ERC1155Test:testSafeBatchTransferFromToEOA(address,uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 4692589, ~: 3776319) +ERC1155Test:testSafeBatchTransferFromToERC1155Recipient() (gas: 1175327) +ERC1155Test:testSafeBatchTransferFromToERC1155Recipient(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 7683519, ~: 6515438) +ERC1155Test:testSafeTransferFromSelf() (gas: 64177) +ERC1155Test:testSafeTransferFromSelf(uint256,uint256,bytes,uint256,address,bytes) (runs: 256, μ: 64824, ~: 68564) +ERC1155Test:testSafeTransferFromToEOA() (gas: 93167) +ERC1155Test:testSafeTransferFromToEOA(uint256,uint256,bytes,uint256,address,bytes) (runs: 256, μ: 93578, ~: 97450) +ERC1155Test:testSafeTransferFromToERC1155Recipient() (gas: 739583) +ERC1155Test:testSafeTransferFromToERC1155Recipient(uint256,uint256,bytes,uint256,bytes) (runs: 256, μ: 769591, ~: 765729) +ERC20Invariants:invariantBalanceSum() (runs: 256, calls: 3840, reverts: 2368) +ERC20Test:invariantMetadata() (runs: 256, calls: 3840, reverts: 2558) +ERC20Test:testApprove() (gas: 31058) +ERC20Test:testApprove(address,uint256) (runs: 256, μ: 30424, ~: 31280) +ERC20Test:testBurn() (gas: 56970) +ERC20Test:testBurn(address,uint256,uint256) (runs: 256, μ: 56678, ~: 59645) +ERC20Test:testFailBurnInsufficientBalance(address,uint256,uint256) (runs: 256, μ: 51897, ~: 55492) +ERC20Test:testFailPermitBadDeadline() (gas: 36935) +ERC20Test:testFailPermitBadDeadline(uint256,address,uint256,uint256) (runs: 256, μ: 32148, ~: 37218) +ERC20Test:testFailPermitBadNonce() (gas: 36874) +ERC20Test:testFailPermitBadNonce(uint256,address,uint256,uint256,uint256) (runs: 256, μ: 31628, ~: 37187) +ERC20Test:testFailPermitPastDeadline() (gas: 11191) +ERC20Test:testFailPermitPastDeadline(uint256,address,uint256,uint256) (runs: 256, μ: 12037, ~: 13101) +ERC20Test:testFailPermitReplay() (gas: 66274) +ERC20Test:testFailPermitReplay(uint256,address,uint256,uint256) (runs: 256, μ: 57071, ~: 66592) +ERC20Test:testFailTransferFromInsufficientAllowance() (gas: 80882) +ERC20Test:testFailTransferFromInsufficientAllowance(address,uint256,uint256) (runs: 256, μ: 79858, ~: 83393) +ERC20Test:testFailTransferFromInsufficientBalance() (gas: 81358) +ERC20Test:testFailTransferFromInsufficientBalance(address,uint256,uint256) (runs: 256, μ: 79359, ~: 83870) +ERC20Test:testFailTransferInsufficientBalance() (gas: 52806) +ERC20Test:testFailTransferInsufficientBalance(address,uint256,uint256) (runs: 256, μ: 51720, ~: 55310) +ERC20Test:testInfiniteApproveTransferFrom() (gas: 89793) +ERC20Test:testMetadata(string,string,uint8) (runs: 256, μ: 869043, ~: 863173) +ERC20Test:testMint() (gas: 53746) +ERC20Test:testMint(address,uint256) (runs: 256, μ: 52214, ~: 53925) +ERC20Test:testPermit() (gas: 63193) +ERC20Test:testPermit(uint248,address,uint256,uint256) (runs: 256, μ: 62584, ~: 63517) +ERC20Test:testTransfer() (gas: 60272) +ERC20Test:testTransfer(address,uint256) (runs: 256, μ: 58773, ~: 60484) +ERC20Test:testTransferFrom() (gas: 83777) +ERC20Test:testTransferFrom(address,uint256,uint256) (runs: 256, μ: 86308, ~: 92841) +ERC4626Test:invariantMetadata() (runs: 256, calls: 3840, reverts: 2936) +ERC4626Test:testFailDepositWithNoApproval() (gas: 13357) +ERC4626Test:testFailDepositWithNotEnoughApproval() (gas: 86993) +ERC4626Test:testFailDepositZero() (gas: 7780) +ERC4626Test:testFailMintWithNoApproval() (gas: 13296) +ERC4626Test:testFailRedeemWithNoShareAmount() (gas: 32342) +ERC4626Test:testFailRedeemWithNotEnoughShareAmount() (gas: 203631) +ERC4626Test:testFailRedeemZero() (gas: 7967) +ERC4626Test:testFailWithdrawWithNoUnderlyingAmount() (gas: 32289) +ERC4626Test:testFailWithdrawWithNotEnoughUnderlyingAmount() (gas: 203595) +ERC4626Test:testMetadata(string,string) (runs: 256, μ: 1489616, ~: 1481501) +ERC4626Test:testMintZero() (gas: 54595) +ERC4626Test:testMultipleMintDepositRedeemWithdraw() (gas: 411747) +ERC4626Test:testSingleDepositWithdraw(uint128) (runs: 256, μ: 201526, ~: 201536) +ERC4626Test:testSingleMintRedeem(uint128) (runs: 256, μ: 201451, ~: 201461) +ERC4626Test:testVaultInteractionsForSomeoneElse() (gas: 286209) +ERC4626Test:testWithdrawZero() (gas: 52462) +ERC721Test:invariantMetadata() (runs: 256, calls: 3840, reverts: 2183) +ERC721Test:testApprove() (gas: 78427) +ERC721Test:testApprove(address,uint256) (runs: 256, μ: 78637, ~: 78637) +ERC721Test:testApproveAll() (gas: 31063) +ERC721Test:testApproveAll(address,bool) (runs: 256, μ: 16970, ~: 11538) +ERC721Test:testApproveBurn() (gas: 65550) +ERC721Test:testApproveBurn(address,uint256) (runs: 256, μ: 65613, ~: 65624) +ERC721Test:testBurn() (gas: 46107) +ERC721Test:testBurn(address,uint256) (runs: 256, μ: 46152, ~: 46163) +ERC721Test:testFailApproveUnAuthorized() (gas: 55598) +ERC721Test:testFailApproveUnAuthorized(address,uint256,address) (runs: 256, μ: 55873, ~: 55873) +ERC721Test:testFailApproveUnMinted() (gas: 10236) +ERC721Test:testFailApproveUnMinted(uint256,address) (runs: 256, μ: 10363, ~: 10363) +ERC721Test:testFailBalanceOfZeroAddress() (gas: 5555) +ERC721Test:testFailBurnUnMinted() (gas: 7857) +ERC721Test:testFailBurnUnMinted(uint256) (runs: 256, μ: 7938, ~: 7938) +ERC721Test:testFailDoubleBurn() (gas: 58943) +ERC721Test:testFailDoubleBurn(uint256,address) (runs: 256, μ: 59174, ~: 59174) +ERC721Test:testFailDoubleMint() (gas: 53286) +ERC721Test:testFailDoubleMint(uint256,address) (runs: 256, μ: 53496, ~: 53496) +ERC721Test:testFailMintToZero() (gas: 5753) +ERC721Test:testFailMintToZero(uint256) (runs: 256, μ: 5835, ~: 5835) +ERC721Test:testFailOwnerOfUnminted() (gas: 7609) +ERC721Test:testFailOwnerOfUnminted(uint256) (runs: 256, μ: 7689, ~: 7689) +ERC721Test:testFailSafeMintToERC721RecipientWithWrongReturnData() (gas: 159076) +ERC721Test:testFailSafeMintToERC721RecipientWithWrongReturnData(uint256) (runs: 256, μ: 159125, ~: 159125) +ERC721Test:testFailSafeMintToERC721RecipientWithWrongReturnDataWithData() (gas: 159831) +ERC721Test:testFailSafeMintToERC721RecipientWithWrongReturnDataWithData(uint256,bytes) (runs: 256, μ: 160231, ~: 160182) +ERC721Test:testFailSafeMintToNonERC721Recipient() (gas: 89210) +ERC721Test:testFailSafeMintToNonERC721Recipient(uint256) (runs: 256, μ: 89279, ~: 89279) +ERC721Test:testFailSafeMintToNonERC721RecipientWithData() (gas: 89995) +ERC721Test:testFailSafeMintToNonERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 90420, ~: 90368) +ERC721Test:testFailSafeMintToRevertingERC721Recipient() (gas: 204743) +ERC721Test:testFailSafeMintToRevertingERC721Recipient(uint256) (runs: 256, μ: 204815, ~: 204815) +ERC721Test:testFailSafeMintToRevertingERC721RecipientWithData() (gas: 205517) +ERC721Test:testFailSafeMintToRevertingERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 205964, ~: 205915) +ERC721Test:testFailSafeTransferFromToERC721RecipientWithWrongReturnData() (gas: 187276) +ERC721Test:testFailSafeTransferFromToERC721RecipientWithWrongReturnData(uint256) (runs: 256, μ: 187360, ~: 187360) +ERC721Test:testFailSafeTransferFromToERC721RecipientWithWrongReturnDataWithData() (gas: 187728) +ERC721Test:testFailSafeTransferFromToERC721RecipientWithWrongReturnDataWithData(uint256,bytes) (runs: 256, μ: 188067, ~: 188063) +ERC721Test:testFailSafeTransferFromToNonERC721Recipient() (gas: 117413) +ERC721Test:testFailSafeTransferFromToNonERC721Recipient(uint256) (runs: 256, μ: 117495, ~: 117495) +ERC721Test:testFailSafeTransferFromToNonERC721RecipientWithData() (gas: 117872) +ERC721Test:testFailSafeTransferFromToNonERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 118280, ~: 118276) +ERC721Test:testFailSafeTransferFromToRevertingERC721Recipient() (gas: 233009) +ERC721Test:testFailSafeTransferFromToRevertingERC721Recipient(uint256) (runs: 256, μ: 233050, ~: 233050) +ERC721Test:testFailSafeTransferFromToRevertingERC721RecipientWithData() (gas: 233396) +ERC721Test:testFailSafeTransferFromToRevertingERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 233823, ~: 233819) +ERC721Test:testFailTransferFromNotOwner() (gas: 57872) +ERC721Test:testFailTransferFromNotOwner(address,address,uint256) (runs: 256, μ: 57515, ~: 58162) +ERC721Test:testFailTransferFromToZero() (gas: 53381) +ERC721Test:testFailTransferFromToZero(uint256) (runs: 256, μ: 53463, ~: 53463) +ERC721Test:testFailTransferFromUnOwned() (gas: 8000) +ERC721Test:testFailTransferFromUnOwned(address,address,uint256) (runs: 256, μ: 8311, ~: 8241) +ERC721Test:testFailTransferFromWrongFrom() (gas: 53361) +ERC721Test:testFailTransferFromWrongFrom(address,address,address,uint256) (runs: 256, μ: 53566, ~: 53752) +ERC721Test:testMetadata(string,string) (runs: 256, μ: 1341878, ~: 1332786) +ERC721Test:testMint() (gas: 54336) +ERC721Test:testMint(address,uint256) (runs: 256, μ: 54521, ~: 54521) +ERC721Test:testSafeMintToEOA() (gas: 56993) +ERC721Test:testSafeMintToEOA(uint256,address) (runs: 256, μ: 56976, ~: 57421) +ERC721Test:testSafeMintToERC721Recipient() (gas: 427035) +ERC721Test:testSafeMintToERC721Recipient(uint256) (runs: 256, μ: 426053, ~: 427142) +ERC721Test:testSafeMintToERC721RecipientWithData() (gas: 448149) +ERC721Test:testSafeMintToERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 480015, ~: 470905) +ERC721Test:testSafeTransferFromToEOA() (gas: 95666) +ERC721Test:testSafeTransferFromToEOA(uint256,address) (runs: 256, μ: 95352, ~: 96099) +ERC721Test:testSafeTransferFromToERC721Recipient() (gas: 485549) +ERC721Test:testSafeTransferFromToERC721Recipient(uint256) (runs: 256, μ: 484593, ~: 485682) +ERC721Test:testSafeTransferFromToERC721RecipientWithData() (gas: 506317) +ERC721Test:testSafeTransferFromToERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 538126, ~: 529082) +ERC721Test:testTransferFrom() (gas: 86347) +ERC721Test:testTransferFrom(uint256,address) (runs: 256, μ: 86469, ~: 86477) +ERC721Test:testTransferFromApproveAll() (gas: 92898) +ERC721Test:testTransferFromApproveAll(uint256,address) (runs: 256, μ: 93182, ~: 93182) +ERC721Test:testTransferFromSelf() (gas: 64776) +ERC721Test:testTransferFromSelf(uint256,address) (runs: 256, μ: 65061, ~: 65061) +FixedPointMathLibTest:testDifferentiallyFuzzSqrt(uint256) (runs: 256, μ: 13809, ~: 4181) +FixedPointMathLibTest:testDivWadDown() (gas: 820) +FixedPointMathLibTest:testDivWadDown(uint256,uint256) (runs: 256, μ: 712, ~: 813) +FixedPointMathLibTest:testDivWadDownEdgeCases() (gas: 439) +FixedPointMathLibTest:testDivWadUp() (gas: 943) +FixedPointMathLibTest:testDivWadUp(uint256,uint256) (runs: 256, μ: 792, ~: 952) +FixedPointMathLibTest:testDivWadUpEdgeCases() (gas: 442) +FixedPointMathLibTest:testFailDivWadDownOverflow(uint256,uint256) (runs: 256, μ: 442, ~: 419) +FixedPointMathLibTest:testFailDivWadDownZeroDenominator() (gas: 332) +FixedPointMathLibTest:testFailDivWadDownZeroDenominator(uint256) (runs: 256, μ: 387, ~: 387) +FixedPointMathLibTest:testFailDivWadUpOverflow(uint256,uint256) (runs: 256, μ: 397, ~: 374) +FixedPointMathLibTest:testFailDivWadUpZeroDenominator() (gas: 332) +FixedPointMathLibTest:testFailDivWadUpZeroDenominator(uint256) (runs: 256, μ: 386, ~: 386) +FixedPointMathLibTest:testFailMulDivDownOverflow(uint256,uint256,uint256) (runs: 256, μ: 434, ~: 414) +FixedPointMathLibTest:testFailMulDivDownZeroDenominator() (gas: 328) +FixedPointMathLibTest:testFailMulDivDownZeroDenominator(uint256,uint256) (runs: 256, μ: 385, ~: 385) +FixedPointMathLibTest:testFailMulDivUpOverflow(uint256,uint256,uint256) (runs: 256, μ: 457, ~: 437) +FixedPointMathLibTest:testFailMulDivUpZeroDenominator() (gas: 329) +FixedPointMathLibTest:testFailMulDivUpZeroDenominator(uint256,uint256) (runs: 256, μ: 428, ~: 428) +FixedPointMathLibTest:testFailMulWadDownOverflow(uint256,uint256) (runs: 256, μ: 421, ~: 387) +FixedPointMathLibTest:testFailMulWadUpOverflow(uint256,uint256) (runs: 256, μ: 398, ~: 364) +FixedPointMathLibTest:testMulDivDown() (gas: 1813) +FixedPointMathLibTest:testMulDivDown(uint256,uint256,uint256) (runs: 256, μ: 686, ~: 786) +FixedPointMathLibTest:testMulDivDownEdgeCases() (gas: 686) +FixedPointMathLibTest:testMulDivUp() (gas: 2095) +FixedPointMathLibTest:testMulDivUp(uint256,uint256,uint256) (runs: 256, μ: 821, ~: 1034) +FixedPointMathLibTest:testMulDivUpEdgeCases() (gas: 785) +FixedPointMathLibTest:testMulWadDown() (gas: 823) +FixedPointMathLibTest:testMulWadDown(uint256,uint256) (runs: 256, μ: 681, ~: 803) +FixedPointMathLibTest:testMulWadDownEdgeCases() (gas: 822) +FixedPointMathLibTest:testMulWadUp() (gas: 921) +FixedPointMathLibTest:testMulWadUp(uint256,uint256) (runs: 256, μ: 821, ~: 1053) +FixedPointMathLibTest:testMulWadUpEdgeCases() (gas: 899) +FixedPointMathLibTest:testRPow() (gas: 2164) +FixedPointMathLibTest:testSqrt() (gas: 2580) +FixedPointMathLibTest:testSqrt(uint256) (runs: 256, μ: 997, ~: 1013) +FixedPointMathLibTest:testSqrtBack(uint256) (runs: 256, μ: 15210, ~: 340) +FixedPointMathLibTest:testSqrtBackHashed(uint256) (runs: 256, μ: 59066, ~: 59500) +FixedPointMathLibTest:testSqrtBackHashedSingle() (gas: 58937) +LibStringTest:testDifferentiallyFuzzToString(uint256,bytes) (runs: 256, μ: 20892, ~: 8988) +LibStringTest:testDifferentiallyFuzzToStringInt(int256,bytes) (runs: 256, μ: 20081, ~: 8356) +LibStringTest:testToString() (gas: 10069) +LibStringTest:testToStringDirty() (gas: 8145) +LibStringTest:testToStringIntNegative() (gas: 9634) +LibStringTest:testToStringIntPositive() (gas: 10481) +LibStringTest:testToStringOverwrite() (gas: 506) +MerkleProofLibTest:testValidProofSupplied() (gas: 2153) +MerkleProofLibTest:testVerifyEmptyMerkleProofSuppliedLeafAndRootDifferent() (gas: 1458) +MerkleProofLibTest:testVerifyEmptyMerkleProofSuppliedLeafAndRootSame() (gas: 1452) +MerkleProofLibTest:testVerifyInvalidProofSupplied() (gas: 2172) +MultiRolesAuthorityTest:testCanCallPublicCapability() (gas: 34204) +MultiRolesAuthorityTest:testCanCallPublicCapability(address,address,bytes4) (runs: 256, μ: 34390, ~: 34361) +MultiRolesAuthorityTest:testCanCallWithAuthorizedRole() (gas: 80416) +MultiRolesAuthorityTest:testCanCallWithAuthorizedRole(address,uint8,address,bytes4) (runs: 256, μ: 80705, ~: 80671) +MultiRolesAuthorityTest:testCanCallWithCustomAuthority() (gas: 422439) +MultiRolesAuthorityTest:testCanCallWithCustomAuthority(address,address,bytes4) (runs: 256, μ: 422858, ~: 422858) +MultiRolesAuthorityTest:testCanCallWithCustomAuthorityOverridesPublicCapability() (gas: 247388) +MultiRolesAuthorityTest:testCanCallWithCustomAuthorityOverridesPublicCapability(address,address,bytes4) (runs: 256, μ: 247841, ~: 247841) +MultiRolesAuthorityTest:testCanCallWithCustomAuthorityOverridesUserWithRole() (gas: 256546) +MultiRolesAuthorityTest:testCanCallWithCustomAuthorityOverridesUserWithRole(address,uint8,address,bytes4) (runs: 256, μ: 256885, ~: 256852) +MultiRolesAuthorityTest:testSetPublicCapabilities() (gas: 27727) +MultiRolesAuthorityTest:testSetPublicCapabilities(bytes4) (runs: 256, μ: 27836, ~: 27835) +MultiRolesAuthorityTest:testSetRoleCapabilities() (gas: 28932) +MultiRolesAuthorityTest:testSetRoleCapabilities(uint8,bytes4) (runs: 256, μ: 29073, ~: 29073) +MultiRolesAuthorityTest:testSetRoles() (gas: 28918) +MultiRolesAuthorityTest:testSetRoles(address,uint8) (runs: 256, μ: 29030, ~: 29016) +MultiRolesAuthorityTest:testSetTargetCustomAuthority() (gas: 28102) +MultiRolesAuthorityTest:testSetTargetCustomAuthority(address,address) (runs: 256, μ: 28176, ~: 28146) +OwnedTest:testCallFunctionAsNonOwner() (gas: 11344) +OwnedTest:testCallFunctionAsNonOwner(address) (runs: 256, μ: 16252, ~: 16290) +OwnedTest:testCallFunctionAsOwner() (gas: 10435) +OwnedTest:testTransferOwnership() (gas: 13123) +OwnedTest:testTransferOwnership(address) (runs: 256, μ: 13154, ~: 13192) +ReentrancyGuardTest:invariantReentrancyStatusAlways1() (runs: 256, calls: 3840, reverts: 331) +ReentrancyGuardTest:testFailUnprotectedCall() (gas: 46147) +ReentrancyGuardTest:testNoReentrancy() (gas: 7515) +ReentrancyGuardTest:testProtectedCall() (gas: 33467) +RolesAuthorityTest:testCanCallPublicCapability() (gas: 33409) +RolesAuthorityTest:testCanCallPublicCapability(address,address,bytes4) (runs: 256, μ: 33560, ~: 33532) +RolesAuthorityTest:testCanCallWithAuthorizedRole() (gas: 79995) +RolesAuthorityTest:testCanCallWithAuthorizedRole(address,uint8,address,bytes4) (runs: 256, μ: 80272, ~: 80238) +RolesAuthorityTest:testSetPublicCapabilities() (gas: 29095) +RolesAuthorityTest:testSetPublicCapabilities(address,bytes4) (runs: 256, μ: 29209, ~: 29192) +RolesAuthorityTest:testSetRoleCapabilities() (gas: 30276) +RolesAuthorityTest:testSetRoleCapabilities(uint8,address,bytes4) (runs: 256, μ: 30506, ~: 30489) +RolesAuthorityTest:testSetRoles() (gas: 29005) +RolesAuthorityTest:testSetRoles(address,uint8) (runs: 256, μ: 29122, ~: 29108) +SSTORE2Test:testFailReadInvalidPointer() (gas: 2927) +SSTORE2Test:testFailReadInvalidPointer(address,bytes) (runs: 256, μ: 3889, ~: 3892) +SSTORE2Test:testFailReadInvalidPointerCustomBounds() (gas: 3099) +SSTORE2Test:testFailReadInvalidPointerCustomBounds(address,uint256,uint256,bytes) (runs: 256, μ: 4107, ~: 4130) +SSTORE2Test:testFailReadInvalidPointerCustomStartBound() (gas: 3004) +SSTORE2Test:testFailReadInvalidPointerCustomStartBound(address,uint256,bytes) (runs: 256, μ: 3980, ~: 3988) +SSTORE2Test:testFailWriteReadCustomBoundsOutOfRange(bytes,uint256,uint256,bytes) (runs: 256, μ: 46236, ~: 43603) +SSTORE2Test:testFailWriteReadCustomStartBoundOutOfRange(bytes,uint256,bytes) (runs: 256, μ: 46017, ~: 43452) +SSTORE2Test:testFailWriteReadEmptyOutOfBounds() (gas: 34470) +SSTORE2Test:testFailWriteReadOutOfBounds() (gas: 34426) +SSTORE2Test:testFailWriteReadOutOfStartBound() (gas: 34362) +SSTORE2Test:testWriteRead() (gas: 53497) +SSTORE2Test:testWriteRead(bytes,bytes) (runs: 256, μ: 44019, ~: 41555) +SSTORE2Test:testWriteReadCustomBounds() (gas: 34869) +SSTORE2Test:testWriteReadCustomBounds(bytes,uint256,uint256,bytes) (runs: 256, μ: 29483, ~: 44592) +SSTORE2Test:testWriteReadCustomStartBound() (gas: 34740) +SSTORE2Test:testWriteReadCustomStartBound(bytes,uint256,bytes) (runs: 256, μ: 46484, ~: 44053) +SSTORE2Test:testWriteReadEmptyBound() (gas: 34677) +SSTORE2Test:testWriteReadFullBoundedRead() (gas: 53672) +SSTORE2Test:testWriteReadFullStartBound() (gas: 34764) +SafeCastLibTest:testFailSafeCastTo128() (gas: 321) +SafeCastLibTest:testFailSafeCastTo128(uint256) (runs: 256, μ: 443, ~: 443) +SafeCastLibTest:testFailSafeCastTo16() (gas: 343) +SafeCastLibTest:testFailSafeCastTo16(uint256) (runs: 256, μ: 401, ~: 401) +SafeCastLibTest:testFailSafeCastTo160() (gas: 342) +SafeCastLibTest:testFailSafeCastTo160(uint256) (runs: 256, μ: 422, ~: 422) +SafeCastLibTest:testFailSafeCastTo192() (gas: 322) +SafeCastLibTest:testFailSafeCastTo192(uint256) (runs: 256, μ: 401, ~: 401) +SafeCastLibTest:testFailSafeCastTo224() (gas: 365) +SafeCastLibTest:testFailSafeCastTo224(uint256) (runs: 256, μ: 445, ~: 445) +SafeCastLibTest:testFailSafeCastTo24(uint256) (runs: 256, μ: 402, ~: 402) +SafeCastLibTest:testFailSafeCastTo248() (gas: 321) +SafeCastLibTest:testFailSafeCastTo248(uint256) (runs: 256, μ: 444, ~: 444) +SafeCastLibTest:testFailSafeCastTo32() (gas: 364) +SafeCastLibTest:testFailSafeCastTo32(uint256) (runs: 256, μ: 446, ~: 446) +SafeCastLibTest:testFailSafeCastTo64() (gas: 343) +SafeCastLibTest:testFailSafeCastTo64(uint256) (runs: 256, μ: 423, ~: 423) +SafeCastLibTest:testFailSafeCastTo8() (gas: 341) +SafeCastLibTest:testFailSafeCastTo8(uint256) (runs: 256, μ: 421, ~: 421) +SafeCastLibTest:testFailSafeCastTo96() (gas: 343) +SafeCastLibTest:testFailSafeCastTo96(uint256) (runs: 256, μ: 424, ~: 424) +SafeCastLibTest:testSafeCastTo128() (gas: 472) +SafeCastLibTest:testSafeCastTo128(uint256) (runs: 256, μ: 2756, ~: 2756) +SafeCastLibTest:testSafeCastTo16() (gas: 447) +SafeCastLibTest:testSafeCastTo16(uint256) (runs: 256, μ: 2734, ~: 2734) +SafeCastLibTest:testSafeCastTo160() (gas: 470) +SafeCastLibTest:testSafeCastTo160(uint256) (runs: 256, μ: 2731, ~: 2731) +SafeCastLibTest:testSafeCastTo192() (gas: 449) +SafeCastLibTest:testSafeCastTo192(uint256) (runs: 256, μ: 2711, ~: 2711) +SafeCastLibTest:testSafeCastTo224() (gas: 491) +SafeCastLibTest:testSafeCastTo224(uint256) (runs: 256, μ: 2710, ~: 2710) +SafeCastLibTest:testSafeCastTo24() (gas: 492) +SafeCastLibTest:testSafeCastTo248() (gas: 450) +SafeCastLibTest:testSafeCastTo248(uint256) (runs: 256, μ: 2755, ~: 2755) +SafeCastLibTest:testSafeCastTo32() (gas: 449) +SafeCastLibTest:testSafeCastTo32(uint256) (runs: 256, μ: 2733, ~: 2733) +SafeCastLibTest:testSafeCastTo64() (gas: 492) +SafeCastLibTest:testSafeCastTo64(uint256) (runs: 256, μ: 2732, ~: 2732) +SafeCastLibTest:testSafeCastTo8() (gas: 491) +SafeCastLibTest:testSafeCastTo8(uint256) (runs: 256, μ: 2710, ~: 2710) +SafeCastLibTest:testSafeCastTo96() (gas: 469) +SafeCastLibTest:testSafeCastTo96(uint256) (runs: 256, μ: 2711, ~: 2711) +SafeTransferLibTest:testApproveWithGarbage(address,uint256,bytes,bytes) (runs: 256, μ: 2664, ~: 2231) +SafeTransferLibTest:testApproveWithMissingReturn() (gas: 30751) +SafeTransferLibTest:testApproveWithMissingReturn(address,uint256,bytes) (runs: 256, μ: 30328, ~: 31566) +SafeTransferLibTest:testApproveWithNonContract() (gas: 3035) +SafeTransferLibTest:testApproveWithNonContract(address,address,uint256,bytes) (runs: 256, μ: 4121, ~: 4117) +SafeTransferLibTest:testApproveWithReturnsTooMuch() (gas: 31134) +SafeTransferLibTest:testApproveWithReturnsTooMuch(address,uint256,bytes) (runs: 256, μ: 30796, ~: 32034) +SafeTransferLibTest:testApproveWithStandardERC20() (gas: 30882) +SafeTransferLibTest:testApproveWithStandardERC20(address,uint256,bytes) (runs: 256, μ: 30522, ~: 31760) +SafeTransferLibTest:testFailApproveWithGarbage(address,uint256,bytes,bytes) (runs: 256, μ: 84437, ~: 77909) +SafeTransferLibTest:testFailApproveWithReturnsFalse() (gas: 5627) +SafeTransferLibTest:testFailApproveWithReturnsFalse(address,uint256,bytes) (runs: 256, μ: 6480, ~: 6475) +SafeTransferLibTest:testFailApproveWithReturnsTooLittle() (gas: 5568) +SafeTransferLibTest:testFailApproveWithReturnsTooLittle(address,uint256,bytes) (runs: 256, μ: 6444, ~: 6439) +SafeTransferLibTest:testFailApproveWithReturnsTwo(address,uint256,bytes) (runs: 256, μ: 6452, ~: 6447) +SafeTransferLibTest:testFailApproveWithReverting() (gas: 5502) +SafeTransferLibTest:testFailApproveWithReverting(address,uint256,bytes) (runs: 256, μ: 6403, ~: 6398) +SafeTransferLibTest:testFailTransferETHToContractWithoutFallback() (gas: 7244) +SafeTransferLibTest:testFailTransferETHToContractWithoutFallback(uint256,bytes) (runs: 256, μ: 7758, ~: 8055) +SafeTransferLibTest:testFailTransferFromWithGarbage(address,address,uint256,bytes,bytes) (runs: 256, μ: 123242, ~: 117401) +SafeTransferLibTest:testFailTransferFromWithReturnsFalse() (gas: 13663) +SafeTransferLibTest:testFailTransferFromWithReturnsFalse(address,address,uint256,bytes) (runs: 256, μ: 14593, ~: 14588) +SafeTransferLibTest:testFailTransferFromWithReturnsTooLittle() (gas: 13544) +SafeTransferLibTest:testFailTransferFromWithReturnsTooLittle(address,address,uint256,bytes) (runs: 256, μ: 14452, ~: 14447) +SafeTransferLibTest:testFailTransferFromWithReturnsTwo(address,address,uint256,bytes) (runs: 256, μ: 14559, ~: 14554) +SafeTransferLibTest:testFailTransferFromWithReverting() (gas: 9757) +SafeTransferLibTest:testFailTransferFromWithReverting(address,address,uint256,bytes) (runs: 256, μ: 10685, ~: 10680) +SafeTransferLibTest:testFailTransferWithGarbage(address,uint256,bytes,bytes) (runs: 256, μ: 90360, ~: 83989) +SafeTransferLibTest:testFailTransferWithReturnsFalse() (gas: 8532) +SafeTransferLibTest:testFailTransferWithReturnsFalse(address,uint256,bytes) (runs: 256, μ: 9451, ~: 9446) +SafeTransferLibTest:testFailTransferWithReturnsTooLittle() (gas: 8538) +SafeTransferLibTest:testFailTransferWithReturnsTooLittle(address,uint256,bytes) (runs: 256, μ: 9391, ~: 9386) +SafeTransferLibTest:testFailTransferWithReturnsTwo(address,uint256,bytes) (runs: 256, μ: 9378, ~: 9373) +SafeTransferLibTest:testFailTransferWithReverting() (gas: 8494) +SafeTransferLibTest:testFailTransferWithReverting(address,uint256,bytes) (runs: 256, μ: 9350, ~: 9345) +SafeTransferLibTest:testTransferETH() (gas: 34592) +SafeTransferLibTest:testTransferETH(address,uint256,bytes) (runs: 256, μ: 35865, ~: 37975) +SafeTransferLibTest:testTransferFromWithGarbage(address,address,uint256,bytes,bytes) (runs: 256, μ: 2907, ~: 2247) +SafeTransferLibTest:testTransferFromWithMissingReturn() (gas: 49186) +SafeTransferLibTest:testTransferFromWithMissingReturn(address,address,uint256,bytes) (runs: 256, μ: 48355, ~: 49598) +SafeTransferLibTest:testTransferFromWithNonContract() (gas: 3035) +SafeTransferLibTest:testTransferFromWithNonContract(address,address,address,uint256,bytes) (runs: 256, μ: 4222, ~: 4228) +SafeTransferLibTest:testTransferFromWithReturnsTooMuch() (gas: 49810) +SafeTransferLibTest:testTransferFromWithReturnsTooMuch(address,address,uint256,bytes) (runs: 256, μ: 49002, ~: 50237) +SafeTransferLibTest:testTransferFromWithStandardERC20() (gas: 47603) +SafeTransferLibTest:testTransferFromWithStandardERC20(address,address,uint256,bytes) (runs: 256, μ: 46786, ~: 48049) +SafeTransferLibTest:testTransferWithGarbage(address,uint256,bytes,bytes) (runs: 256, μ: 2620, ~: 2187) +SafeTransferLibTest:testTransferWithMissingReturn() (gas: 36666) +SafeTransferLibTest:testTransferWithMissingReturn(address,uint256,bytes) (runs: 256, μ: 36001, ~: 37546) +SafeTransferLibTest:testTransferWithNonContract() (gas: 3012) +SafeTransferLibTest:testTransferWithNonContract(address,address,uint256,bytes) (runs: 256, μ: 4185, ~: 4181) +SafeTransferLibTest:testTransferWithReturnsTooMuch() (gas: 37112) +SafeTransferLibTest:testTransferWithReturnsTooMuch(address,uint256,bytes) (runs: 256, μ: 36404, ~: 37949) +SafeTransferLibTest:testTransferWithStandardERC20() (gas: 36696) +SafeTransferLibTest:testTransferWithStandardERC20(address,uint256,bytes) (runs: 256, μ: 36054, ~: 37599) +SignedWadMathTest:testFailWadDivOverflow(int256,int256) (runs: 256, μ: 368, ~: 351) +SignedWadMathTest:testFailWadDivZeroDenominator(int256) (runs: 256, μ: 296, ~: 296) +SignedWadMathTest:testFailWadMulOverflow(int256,int256) (runs: 256, μ: 323, ~: 296) +SignedWadMathTest:testWadDiv(uint256,uint256,bool,bool) (runs: 256, μ: 5696, ~: 5664) +SignedWadMathTest:testWadMul(uint256,uint256,bool,bool) (runs: 256, μ: 5720, ~: 5688) +WETHInvariants:invariantTotalSupplyEqualsBalance() (runs: 256, calls: 3840, reverts: 1931) +WETHTest:testDeposit() (gas: 63535) +WETHTest:testDeposit(uint256) (runs: 256, μ: 62792, ~: 65880) +WETHTest:testFallbackDeposit() (gas: 63249) +WETHTest:testFallbackDeposit(uint256) (runs: 256, μ: 62516, ~: 65604) +WETHTest:testPartialWithdraw() (gas: 73281) +WETHTest:testWithdraw() (gas: 54360) +WETHTest:testWithdraw(uint256,uint256) (runs: 256, μ: 75443, ~: 78076) diff --git a/lib/crytic/lib/solmate/.gitattributes b/lib/crytic/lib/solmate/.gitattributes new file mode 100644 index 0000000..7c5f3db --- /dev/null +++ b/lib/crytic/lib/solmate/.gitattributes @@ -0,0 +1 @@ +.gas-snapshot linguist-language=Julia \ No newline at end of file diff --git a/lib/crytic/lib/solmate/.github/pull_request_template.md b/lib/crytic/lib/solmate/.github/pull_request_template.md new file mode 100644 index 0000000..5cca391 --- /dev/null +++ b/lib/crytic/lib/solmate/.github/pull_request_template.md @@ -0,0 +1,13 @@ +## Description + +Describe the changes made in your pull request here. + +## Checklist + +Ensure you completed **all of the steps** below before submitting your pull request: + +- [ ] Ran `forge snapshot`? +- [ ] Ran `npm run lint`? +- [ ] Ran `forge test`? + +_Pull requests with an incomplete checklist will be thrown out._ diff --git a/lib/crytic/lib/solmate/.github/workflows/tests.yml b/lib/crytic/lib/solmate/.github/workflows/tests.yml new file mode 100644 index 0000000..2a29890 --- /dev/null +++ b/lib/crytic/lib/solmate/.github/workflows/tests.yml @@ -0,0 +1,29 @@ +name: Tests + +on: [push, pull_request] + +jobs: + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Install dependencies + run: forge install + + - name: Check contract sizes + run: forge build --sizes + + - name: Check gas snapshots + run: forge snapshot --check + + - name: Run tests + run: forge test + env: + # Only fuzz intensely if we're running this action on a push to main or for a PR going into main: + FOUNDRY_PROFILE: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && 'intense' }} diff --git a/lib/crytic/lib/solmate/.gitignore b/lib/crytic/lib/solmate/.gitignore new file mode 100644 index 0000000..5dfe93f --- /dev/null +++ b/lib/crytic/lib/solmate/.gitignore @@ -0,0 +1,3 @@ +/cache +/node_modules +/out \ No newline at end of file diff --git a/lib/crytic/lib/solmate/.gitmodules b/lib/crytic/lib/solmate/.gitmodules new file mode 100644 index 0000000..e124719 --- /dev/null +++ b/lib/crytic/lib/solmate/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ds-test"] + path = lib/ds-test + url = https://github.com/dapphub/ds-test diff --git a/lib/crytic/lib/solmate/.prettierignore b/lib/crytic/lib/solmate/.prettierignore new file mode 100644 index 0000000..7951405 --- /dev/null +++ b/lib/crytic/lib/solmate/.prettierignore @@ -0,0 +1 @@ +lib \ No newline at end of file diff --git a/lib/crytic/lib/solmate/.prettierrc b/lib/crytic/lib/solmate/.prettierrc new file mode 100644 index 0000000..15ae8a7 --- /dev/null +++ b/lib/crytic/lib/solmate/.prettierrc @@ -0,0 +1,14 @@ +{ + "tabWidth": 2, + "printWidth": 100, + + "overrides": [ + { + "files": "*.sol", + "options": { + "tabWidth": 4, + "printWidth": 120 + } + } + ] +} diff --git a/lib/crytic/lib/solmate/LICENSE b/lib/crytic/lib/solmate/LICENSE new file mode 100644 index 0000000..29ebfa5 --- /dev/null +++ b/lib/crytic/lib/solmate/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/lib/crytic/lib/solmate/README.md b/lib/crytic/lib/solmate/README.md new file mode 100644 index 0000000..2bc3e3a --- /dev/null +++ b/lib/crytic/lib/solmate/README.md @@ -0,0 +1,69 @@ +# solmate + +**Modern**, **opinionated**, and **gas optimized** building blocks for **smart contract development**. + +## Contracts + +```ml +auth +├─ Owned — "Simple single owner authorization" +├─ Auth — "Flexible and updatable auth pattern" +├─ authorities +│ ├─ RolesAuthority — "Role based Authority that supports up to 256 roles" +│ ├─ MultiRolesAuthority — "Flexible and target agnostic role based Authority" +mixins +├─ ERC4626 — "Minimal ERC4626 tokenized Vault implementation" +tokens +├─ WETH — "Minimalist and modern Wrapped Ether implementation" +├─ ERC20 — "Modern and gas efficient ERC20 + EIP-2612 implementation" +├─ ERC721 — "Modern, minimalist, and gas efficient ERC721 implementation" +├─ ERC1155 — "Minimalist and gas efficient standard ERC1155 implementation" +utils +├─ SSTORE2 — "Library for cheaper reads and writes to persistent storage" +├─ CREATE3 — "Deploy to deterministic addresses without an initcode factor" +├─ LibString — "Library for creating string representations of uint values" +├─ SafeCastLib — "Safe unsigned integer casting lib that reverts on overflow" +├─ SignedWadMath — "Signed integer 18 decimal fixed point arithmetic library" +├─ MerkleProofLib — "Efficient merkle tree inclusion proof verification library" +├─ ReentrancyGuard — "Gas optimized reentrancy protection for smart contracts" +├─ FixedPointMathLib — "Arithmetic library with operations for fixed-point numbers" +├─ Bytes32AddressLib — "Library for converting between addresses and bytes32 values" +├─ SafeTransferLib — "Safe ERC20/ETH transfer lib that handles missing return values" +``` + +## Safety + +This is **experimental software** and is provided on an "as is" and "as available" basis. + +While each [major release has been audited](audits), these contracts are **not designed with user safety** in mind: + +- There are implicit invariants these contracts expect to hold. +- **You can easily shoot yourself in the foot if you're not careful.** +- You should thoroughly read each contract you plan to use top to bottom. + +We **do not give any warranties** and **will not be liable for any loss** incurred through any use of this codebase. + +## Installation + +To install with [**Foundry**](https://github.com/gakonst/foundry): + +```sh +forge install transmissions11/solmate +``` + +To install with [**Hardhat**](https://github.com/nomiclabs/hardhat) or [**Truffle**](https://github.com/trufflesuite/truffle): + +```sh +npm install solmate +``` + +## Acknowledgements + +These contracts were inspired by or directly modified from many sources, primarily: + +- [Gnosis](https://github.com/gnosis/gp-v2-contracts) +- [Uniswap](https://github.com/Uniswap/uniswap-lib) +- [Dappsys](https://github.com/dapphub/dappsys) +- [Dappsys V2](https://github.com/dapp-org/dappsys-v2) +- [0xSequence](https://github.com/0xSequence) +- [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts) diff --git a/lib/crytic/lib/solmate/audits/v6-Fixed-Point-Solutions.pdf b/lib/crytic/lib/solmate/audits/v6-Fixed-Point-Solutions.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5c4243425bf4fdaef1dcd87eceb2365ba97bd6f0 GIT binary patch literal 170456 zcmZsDc{r4B*tTsfQ~fM?N~vb1vFME`}r>DKAr;Gg!FL|V*nTM;Lx2?Sg`1+cYwIY}U z<)W#HGIDiw1Y-*yfCpYWtA|2MguhyFflavY_ER5UrY@jnrzd`RW*zavP+GbSiy@Eu+s<>ldR|No!$$p6hs zxb0?-QnWC&akjVh0>iv*yf!{L>0<2&MiZUvysn~-C?7^D8rwTLUiAWhgV~R}UU&7t zyII?Uv4-|HoowyT8X17mXRJN1p)|nkXTicwUY=(59>-l>++1&fgFR9S39tViTw>nu!xG9=3x~b9h9e+hrP86@)m8pXsmI_==QLt;-aJkgX6(* z82HM1=nyLQTFgmJQT>(i$LDg94zU_S5=Xx`_3=J%DLna8U4vh;^d7Fq>)HG7lSSWE zb(*BgcW&J!7PWb=sX~AB0qz~;`hu04w?>7$o zchlaCVXuy*l`Fl4zmqw+fGL+Oo<{?R{bpuC zKc3E0$P;X>IiGszX74ohaYyl(@WQ$d*BhR;|)7A`O* zF-N@+T-QD~K?7f2F^j*5Lp9)`odZW!pBx1bJqlXszZZ1t*FjSsQdcU5%K|zfX{ZU2 zGzE+ZrA#g>x%V`R>H4pR4APx!5pSzMWsjaU)c)ud=Q8Lc%LD{D=aIZLz0}ym7-jjz0C3{{_GkAPqq8K3N(xj!xKNvrOTf8F4z?y!j)h< zug^---nAdy2X@7S#-|!0){qxQLb#gtS`t6ax17$Q^8_NezME5#MK`n-_Pvv|<6BC3 zO5!%>*0c4p6ve;;oAzkq`&%L3iK3bQ$CtYv=m>H(D6gV~Hij0xQGr59sm%9d3|_YI z4IGVZ&#iYFUTz=D1X0bjI9ID92#)CBoop_v6E{AL+UjJG+o63jl5ZsWg44)gGL?Zk zg2bCS5aIhhDvz-VGNB@e&eA+-@f0;8!rh&Yr?I9@2@9n)a7qe{JC!y37*Xp z08*Y2#n@(Lz8Q8AtDBiUm7sDdAbM+tZ_pB#g{V_Nbn^Oq#&0e7S*cTmNIxmacj(VDg8K;c`q|BbC+ zdrvkV_E<%&U9i|RrwWTJSWcJKv1 z863u>fL-$9Pk);$aLt$yus*PD=p`@FR#%Ygb=hSFu=g^i5=+H0)~YXV9^)I-%Vn{L zx&qrlo|F+$yji#^bufg~6>uXipB5SB4}@2yg9oE}nJB&x_g~#Tf6O?{z<_LnV(?NZ z5_hSB-6}L6JQ?=5#Q>;((_Z-4^|ec+9sBoA7hc);Xk+hominO>+JmV5kL!UsU*v(e zFE>EUvXiYrSl+q)j4KbZg5+|LIzu$(h`f^aU##?cUsXKT59Ztnj65B6fp|G^y171X z$ZP1XZy7A&q)>mvkPUZJ5}&2}*Vm?96uL3S4w)u(MP@_LK)LZsHGv|>%}0!)@4I~; zX|n`eDi}X{wYb`WHGy3n%&#Sdg-G5nEJML^uG%;faWD;WRv5X%`ewcg zAK9~odxQsmIwh9Wj~BeV7Ed21ZURp)_W6r|Ib`!MDBA05NLgk}Feggag{_k1xgMOH z#wcyy6ukIi1$s~KQ~2W9C2m*-_N}Y|Z0Ca94}n_K^P4x$7cr>L9Z$~FF^>7#^#SOR zm~H8gdo%8^NCm)=rl*VtM(>AWIC`+i{;HP8Guk@~7yb)Xe6AOO&0XC*3vtyOFupl# z39`!6318QW0V{1-BYEwc!}YBdSITS!Y`hegq1|?`1fS0D?+XFPgO7gHlNTcJrNZLG zK)I6*id3dQl3ks=GP_mLf5Edc2=SCvr_!hsRJX^+AZ1n`>|0*$8M7~|d6V2Sq&g5e z_iZU?`9X3~g!J#u49O6!Uyq(JOM#AdKgzTIbeW()SpMB+GWjR(e{PA?#q`|T?R(96V(dT5oIfb9u>aua z$2T>WGHSSCMT{OIX02_n!VRv!pN-gpjkQ|0YbU(uO}vr%~Fec8%D zkv(>3a+nEL9(JXOm4XJ}jHoSs**n&d5x0_!*!wK1CAE3YV}w}(+*aEtgBY7%+`1%X zD{I|wJ}|cw-dv=_dsmj5ix=Te zlRS$DMrH(*Go&qK-7h;iMFan~?e{N?MtO)Lu8LY;;80=^js)+q(78P+#`XtsdFxr| z@0n)zNk(MH1-Cwx%hZ1PB-^ollo;-_pu66kU&!nZ*?t&WfHhUVrjgjmld?Q2MH_Z* zFf+$&gkVohUxSzLMupcoGIE)fmm{2`1j*G+aze0JZ{EJ`y^yu%C^%L1czBpqd06> z7IH{^EBat+OxHr6q3UQ)RvA-|9fFU?H{W0L-%yz7c7cB%Z_IJ^*AWq{8}F&TG{<4$CbjZ9NYFOsO3j2 z3S_|FZ`geAH;1gf5_V!8(i}<^-9}4O>NJaC@xvzwxuJZT1q}nQj;MM0q*A%?5_Aw=0%|?B0^Hos(xNu|*s)7xOfR8Gi`h{A*k| zM=X`2EC|C1vR#RED(}GMcad@;S}f7Wt5&0w6%OSIm2%Qgl3qa^?aZ;w4Prj!UZnCU zZL;@#cJr%F8ExBM`{V%S;fJZ5GKT3f|D9AyYUxHCY+z1nLe!80WFKZ5cSJxJo(;7| zP!8R!X2|M9EmmK(dU#~R*asD7XdeZ>-?cbO4)RNGiPz5WI*eC#W%GX2t>W8o2+2Jr z8W$AK+qxwUOhb-hFL2$F$poSm4v|4fx2bZSA;W>!A=S8;yuPdCgy>PjmL%;jtMSSt zsV8;YuLQnhzieP0x_Qq7J+wNM9U2;t9v_L&^8-e|P-Q(MdrL*qXjNkIxu`I~?C&0|Zsb}? zRc$;muLJ2(x)$e##W^_nx@sv)CVuW>vctJzN5W%ZW##CqJ#j?S|`W5bN8$w(2 z$EFLLEnEpTOntt6zGh~ILm6eQ%gLQy{&Va$E&x3E?!?;laNV_x+^e%o)N(kW*9IbT zK6HfZH61v?&^s_!!ruYey!Icuq&xC9-IOr4`>d4CSkT-@pC5sPKYl36gw@ZP!06(x zbRgF4wDHV;#^ht+0ox2p?`Lhifb3qKqVj`jKHoj38YgsoXOgxW5bKvCY++vr2fhpo z!-jX$3wR14&ahuqfBtsT=ON4iF=&r{?dRkGo5DkSItGNbx}{@pu1(n*5Wn3VT=pW} z$@?EUtx~x^wo6R59L?rChS9(-J$s^_z; zQkLR11iWu7==-*A=(g=wDzc8znImbp`SSzQ_1o$HoMdj_NZqNBH?vVTKIfMTEVec< zYT9HpeT>q}FT4~!{QW5c4hq19xgDBZl%SZXl=*1uhYr?kolKNR#*N$Y`%UK9Tm^WYD`ecdEwa%Jr!NP1V+R9e?6#v`ROekuk><}U6MMpe@rqk z8>xZuA_kctbbHjmKtAE@Hy}6Lj3=)WvvK zdsb%Tx`u8b$S13&YGKWIuiHLK5G>nKPml->466r+)pw1TEBOn1-*xKVy5j)<3~JSyQKi$$UubZwQo*+H=zHB4+E@O3RNf{; zMP4FiH84RcpRxrz3sHX<1kRQ{k*3ZL0q+_9@yJMsNgQLuqJ}WI40)c6{9ikpg*1P@ z(HIL%U(m16)DV_n5ebW!Nv%~b*1BN(eO#cWE zq6Z&tp7ZST;iL`}4rD(UrUgtqn0$4U_Y6=#n`RX#kEEZkOR!|;7-h_1)Zvw6K$4g) z*IT2IzNj>LrMQ{_?&CAx1a5TahkzfQcNGe%r&m=lS;0j8+voe!18lP-ylk})uC-0(N&xp`Ix!InfCk(13;)Rmq!Oly&3=*+em5nu9cnD zoyc_?@60*Hu6xC+8*+m|8r)^wB3O5J;LbK>*jn~LUn^~1H?yl)g6 ze0mi$GuAs$%i` z4oNtXEt3}YR z-R?>LKkjj2J`-s|LvsGf4&$F10Cp-)kQttA8Ofga)KSoM44QVKAeR5`Dz1Up*0h;r z;V@K6*?rXBr+x+HX^+-wcL-1^JTge5WO81Z2Zm*Woyl3=DX`$mlf6J(o`qI}R&F|r zZ^pTi6Dp6V0SqUj5(>CsOmd&I} z;#C}Wsh_BF$WwEW#)%mR&aTpnqCg@; zkTuEjLZ>hOdmoVA`)5cyS4MS<#a{4VusOzF)M?$CK_fN7-gPY7Z_?6{9l|0gVX<%V z%I`=qC5_@hS6o2aNUqD73kpz2xR7LCiT8fjl>cuv!k=y84&eRyOgZ&+O-R2)+L<=A za}7BTGDWvp&u3VE%L9?21KlBWpFnI=T@0yL%b@?9jCyn}5$_HV&i07_nX>08)xOMX zX6J@^n#qvN8S~F;Rn$&&IVHdU7lS-amTsooOzjg=4@;HnBf@6+6D02`!!|o!qU3g= z3y^C)O|zfZQJ!xF;FOfl$-$YY9)`@zOL6$pf6?W3GQ-vT=I1pJ*`-JQ=J(O0eYG(g594m&S#!WWkVyAZU`XCta((vC{4y0OS} zm_an`#E8~7Y@E{c1Us0N0|VCs)`R|GmN~B<^;LaUt(9sN5UtzKT2C1pzvlW4U_i)0 zZ9)^$u@>X#dv_Qt;d*1~CQyZ|Hh3+n`ru z5MeS7#a}Y(C&Gfv{R>&!;!Ph1l^d7qJKzdDCMKeE*hMEi(L)ER42xZ5xw>S4>F~MH z%<%7ylnvW#U|w}I_MN@oaH>(x5SyEJyJfNZ$V~@yJMZwg@I}J>EM{m`9nex%NRav3 z64xxYK5skF8oJ%>r!1>}fY3J{RRvgfUw20>u*4}oaCBcjIw&$uCjUyWQg`kul ze&FcF3NQY$c)Ix)7E_{W0`iwimIO@eV*!wmZ7k|pT9?1^pg1k>JuI=Hx2=RCDaFU;)d(Z!27@qBMtbyg#fa$!Xi9SkfKv z^+w7`kI7=3ImpMjOUk)6VES8-8+j)e>}o6EHoTJa`H7ItaX-2fu>Va|WUm3~8zYz` zb+YH5NG=d-{KLLquAx4CTv8^Ji`dt;>1L3dVWr`ixqP=HP-O{JzEG)n+!vyFa_NpX z-n=t0O3%h>yoEU#Q+KhIg1#wJ&BGWkbfF#m?B4?$C(4Y4T8%$iF{|%LsT204R0ge= z1x+22;AbA4EcOedOW#_&XKF6)4un2GFrNwx`zw=s7nMeIkrEgF3|pTy`p z3L#top^V&!xRgQlXA`r1BlkM>uyt@WBli_$@Uzliq%LF9tLUbGJhLwjKWPay!EVW*XI)Tcl5%Q)`~@1oZ*|<^F!tHBRO4O!-DhcCYC_K=ot}j^KXzG45d@IgMwKuam;ygoOTCxLm7!cI?R+ae zx8k@r=`Ho^D~{CUt>yKt;Ar@3398eWA-Es}Ck8b~c92z+R?_)~_h|sW!hlf!Vb$)i zaXL?6*qL%2{9krx1v%sp&3Ea!Gao?*keV8;7F>wgId3XLVY; zPX+79YOkDR7IB()XVC4}-U1i=*b%)vcFQFLOv(c*MHso@Oz%b4d5xBfd+Yr~tHZ~$ zRWfXTKiJDM6`&&1FEp1jG6#ukKO~PSCuaZi)k-95#Swp@7+YVZDL-I=D7t)>5q+*>AT;C)96>dRb6jV>Dw&{lBn;LMDfrE(@a$s1Xy>kiA@I!7T z4LA?~*3r}2?{Bv{3cPspt7wLsmKg3qb0^EXR7V?jW4 zin=F}azQmh1Zq8qSrM5K?(P2G!2szUZ9;g#42**5Q#Z<#K&@_of(zGz4_XMDLv)n!Z&~FlPj5mzbUubC^+gYgH&53;4WX6-k-UIsKDQ0lEv+T)EkO8 zV2BEb@%_0xv_JLr>cB_S9ti(T1$ozBV^8jxPdjkm>BnNjmn71Gb-rs%xpa&jTH`!d zhVJ2XlJyv+a$a8@reQ*N7BrAOb7;>@CVqB=WrlwtWaV=1m>^sbpfc+f7}m&mqua29 zjanK0%fJA(u*y>{AVk4;kDR(W`{#I6&|OdnM5eTEFQUxt^v8wa(@eSrHY!Rf#>ECx z?yB+EQguhGnc9n_D?=cxIN|+ysg!7_&kKEE76VesRMYgy5Ex&CfTF;QKvZa`;*I_U z>v#Ktt(V2-WoV`E!eRzlveuT1fld{XT z!T7!P>}|CA2opprvZh|0P$YAOx0RtZU;8OQ1n^iA$#y05Gr6CMM%jKNwNq;^x{}va z)Xkz9ayEkZfrr$9-u~|yjuSPGqHgAfxXF+Oo~=yS3M?rl!uR!m?HX{;okiKw`l!Xqqo*soMEkA{~(QZ#iY-2no84 zTdu($D>6Ry_kgyngE$mh{}1#hkor}&dEgX&g;NfBq7R_$&~y{7)kWI`h>ELhZ>);I zUs99$OSr*h9+?S#Q0J)p2u<`zzG@&`p3VNL?^h;^rk~yNKrz5WT7OPKkFcRc02b>1 z=2ppf^4nSbExph+#-#GTpBCLYaY8r%hwyx7pIx_a8Djk~B5&Zz9=eT#nAhK8U7mkf z(GD4BS!2TYTjRRYcy9B4LwhvsS`L1f8;#PuMp-inTb_xxB>YXNjej^g%TZ39#7Uu@ z9nlW1L0Q`PoF&oZP`CA!M$%J(8H~quisf9st`}^1@afhoa;#kgrte#*va@H43T4-Z zEpMljUC&P^Qry=lyPp}fU0U?_xVBV%)(`>mIurc~|1iAD$isW0X=d7Sz3dR#LWL2} zuUb8li(QgxvtrLzpd7ND@`Nw~ric->h2-1cEIin@g%Jr(tP?DA)R;H~p2WG973diq zY*@5i^gzEo4Ar%4l<$+zu29H{F$c|OW?xyJUvb}?9N6;C5q;T1dYKqRCYtp;6f7Q6 z&9ym6MPk==@Nm^ms*5RzjOg64eO4U{=7FnHIYYpXET$tU7P->Bp2i>R-O=0R(K7LH z`D>63If-sc#y10Sfv>%JPXwABnR`ctZl;rM6=Y=h9!-EWag|}3P~=u<7aWwuJUpHi z$A#@Jmr1vfSTzi%Y$x3=>hRUZ3Yoiu0C){A{w&cGeYK=q7M(6gMB()xrTlL#a$agw z$a^frF@2Nsd*(Su^rDW~uY)p2p$gmc2Q#uQZl{-Xf#!qs6nDvrj`fjPMoPnjo$W>} z+iW~x#4(63R|IDsGqiW`TYeEfhu=J>b~0q67z@hoZ zv7cE}WZ$Pg)n@~APfv6^3at+JSO{SkLn?0S#r;&aVm~j65LL+elx;?6q9T(?F;fK9 z#SN9f)DTAg2M*e4i5ap(6ww|-M&2F#qaStKwK5EhC^?ObXaO?YBQ(J7cyg_Zn z1TGHC8@EGV#pM??*u3=edr6Fx0N!C6%Ws$7B>V7X3>c)_Jl>cHUvk$n?Q> z`v-_imT}(bmbhB2kOcmXw+5lU1UlR|{i@k{!V|sr>h)9!pgb!crEAB%mb0m>O;CZf zHr$JJ!I_@tW|E_78PXHYbzP^p-zew(>%a2NI&#|Dq!IY}5&X z@A5=%-uj%FZj*h{k$qg(OreZh?w9OxlJp|nfdQAm&oVH|0pUOeut+`;&Thr*WijzMmjkf8SKQ$3Wj!IwOPNk@BO-WJI zKW5Gf2$4Tyhi(B3qZJZVRd-V<9X~SXkF4Lf$84Ed5T(gYL+|7pettVKQ+;uVR;|T5OaM zl_H%ODcUXRZ!Wd&pj*&I8|S=s-K?EKUVdJjhL0I1iU1zJ#O9r2klRKQBp2T^?w!(U z=)G92`|;PqqiLBIkFzCo@z$6-o!e_oouu(G{BS)qg-|@uF3{*jdMBU=a=K^q&gmh7 z2o9UR676t)ddffpDz0|lW{4H}SBf=TLEfIfJuY4MP1XFl?>pUShOrX2bEjz8@PmLD zuZ+9TRYB$S-{BGaMm%w^Jx@D1q)UG}BIj{Zfs=PZR2&`JqL)q<`d5uL!&OEyKm7>! zy0_r{VJQDwJDdIOPQhWQkU!ivvCLu1YgJGj+UQ-WnZbww?)%ugPrs8y2OKcTc+p>C z5_CH8gESg18Yf*byvbY?0lI$h(c?s~9f4oXpDbSqnc5!_Rd+D0sO0k=P=~U<%EgLQ zHAM7gnf(EJssKu0rQ$C}k=Nz7JQ0ENB@4C#sEoA=r!3+St;}!_ba;kdx-|F3%agM| z{G89t(Qin5ultEUutuZ2Q?^Ynf5JT<3CNv_<1Tvw0(;%VDHd=q57Gu(Srjz?>k88P zi58%9P7$(BT{KBx02+oKN(sDOYj5;$Z;%M(-`sJTABH_)GEw-72d?tvV5p&g`}QeK zWhOqgj%zjT#7Wfiil@eMlnDz&_(nCbbUPHaR{6^1Fob2DnCe-#c$VGCB8&&vUCEFh zAD+Q1+ZlAKbzsg4)OXcs#Rx|K56maUZUOo`FXm`{P7hT zL+t*ILoLkI@E_`$j0`0G63K!C^KhSeDyDtgt7&`m)pybDMiLdw@KqCgOV}sVc{Vn+ zAN_Exxx?s6lhG|}#p2o3uO&e?QxAkUSvIrT?c&mS{Xgc(?M5T#$}AA6kvE+@fmlCo z+XNew)ssb|C6|2zW1he6?G>lnENw}?a8Aa&ioMu^`G{&_+6j7kANwh7Bus2Fk3$9a1y5LEA`P2d^zfpclW% zTuKExMKA{Maf!Gm;Iw?Nqp`))Y6f5KKsgPGP>6JfnTS3?^X4>;^7Z$vhh`Scag|41 zeQmT0%S9m8{>R&(dhgrOr$6$Ri()~Ogapur`}Mq0LFy!e$qSJd!>}ZV(i-Kpf29F& z>ppy0-cF6k+4w-v=-5QRx_yW+&jqN^&$FOo2Wa`da|$mxQi;g#=}O*}VxS~7jC?jq za3dHQWdQJp%IpFRHP`)Y-5JupPPT8Cp%z2F;q_(}w) zJPxlfN5O)W6I92RV%{Vy6?s*m2WZG9URY2f6+Kn}UTYvzPc&1J$DI^T5|`h{{oWZY z0_D{CE_qNWRul2~JBvoL@MZ)vl9tyFS9$HivW3mj;WdO?Y*b_^m5~CnSCG^D_mNg< zl)eDPg7KQ02|Ny1BJADxz#;EL&zn^C2p@YdW(gyWhxq0WCdv?DS(s^Y|D>8cP~;ID z*oGleYNLqrJDC+#_swC-)pZ*v9tfJpX$9Apy8{vJSb!>kD=NxW+K2Y&b0B%`>P7lYsrwSjg{S655c#Plv z4Eo(usT}00+DJ$K5P^0rsODf=u3XhSILG9V`vTjK*eMpnYH~S6arg^SBR{TXuYq<3 zJ%=Q^X7^S1D~)m?Z@?Me3GV?d_H(M2a#HwB^!0|)M&jmmqRY_qE8nre2d6)dY)?6* z2^~JDvb^N=3&!f|*dfCGERosB8iL5qpR*xRJ3FwWTl1=P8|MKVTQq1{J!+pQ0xhhH zKhC4z37~|gnZdJF%@J;cTM%&#F(4>dNQvLJE;9*h&1zZ*aosuG7a&4q2qJ}&Gczyl zNksk}v$8{%F2jq7$u_>zEmY(@Ke-*4YAs=8=kYFa7OO^KPCdZ3Q0PH(6(ckC5-9P_ zjBBuMPk`RnOg>Q9JwH7zyf0cF3Y%Iiq?-*>A9h6^F+@1(yABb=I}Z9kE5CJ98}HtK z?OxN+G)yk2S%3sCty|JufU-ZyQR~NH8PM4*-_N!!S*A3)Z=PL=t0NaoJ;~^u!;b@Irej3>$YEqr@0bjOu`H%)=WdQ6eMWN_0^qjh@ zVhnUNNaMl?;=lP%OxpA=+`GGajp!Pr6Aa>qJwQQ71ge95?1};#q)OX|KISAbQ2$ANg~-`@Hi)~kn8HXTDZM4d*_-XAouyM|Wz}`7E9e+Pb z6^`dCev8nTMAy7P{xEhLq@d!!ZASCM-2lKzjeil=&NM`{21UmPCtWD>(tW>1+1oi0 zl|o2S5&E0}fd=-U#LG2=VEa1&mgIz&ya~+&9e#(p)&<|Ic-V!QKFR!8$3Z=CPvZ1n zwn(JgY|ACzM33C-4l}8w!^Wo2$r1gOBLbDo{rFrwy0xsGKR~gNm;Q%IBQ>9e1BUTU zbgaw0mkuDvO-r76IC>(*h5=-TLW0so7U=u(ZY+B)lyp3+rEgyU;t&Rug+>rs%N+r^ zly~wrQ1hYd@|N7d<@JStY7XSLXhimy?m~6^Sie^#aA{G$Lb9&{P!)+Hm!DFv1(enG zVfs78D~?NnWE>nrslEeX@dW~GZBNSwdEN^=5Y7}5dv(rE^2Gxfj?#M1I=|xS-PvIN z-$9IunZ7P4&|+Y--u<4Oz$|JGSdhF>2nzg84p=wxkzA>kDrPhlX~_?I=rb~FE{sKz z#F%%S@XLDzsFVdROKv?8@JMNGlMK5_Pd0J!@4Ci3ZEwR#QnMCt!q5qCHX#6q9N-INe{4Rx~xMk zCP%y~eL>2_CE3X-6NNzA$>S6=;^qsnH+>nF3$xH74f#;X_)5yhc*qGCwr&QhIM^I@ zaCUuwbLMkhE3actt_SbK_j^gi$)`Gay*k>>Hll#8Was)yqyyR?DfNXhB9UF=j&3_% zYl0vrU|{^u4?GGlI+XlaJwv*zt0rc*8f(u_J2XWD%0a$}gE{P+rxJnh9Kbp$K(O(2 zgZH{W0{fKLC+}Mv)c?bbNq75^zg%Do@`pVfihqU;u%}l7U}7y`f46L<@nyQL$0o8w zNSbO@lPxPqwG8rk!O%?OOJkR=ICP7DjNVA3n?Q?BnQ#9u;#b24xeV#^>Vuo2-mW0E z@ns!Cnm8<}M0!FLJh=e0Tc{`7sOUOLYU zxVj&%%hXv|Q5 zumXG?LA;i*Ia36Ae!WYwc4=Xc_D~&RWGQxqvfHx1=j^FX!5iq{7UO3K@zoJPO?abYeN2$NYmfckx! z0qJTn0P%%eMD5MoE=r}nFlGgc*qnBnFbSI~aAre7jgh&!!CTglZ*c##3Gv9ELbLCxxM{cp|o~Rw|5NYRjq;@I(X|cWR*Dog|PYB4Lb_O z0b7lxEJJTO`qv^}QYn1BsKu7-PT5KtvJdF1g%sfXKBGgWC!&Un{~Y&TG-`5G0$fi> z`3L(Myg|zlQ6nTlpEva`-n@}H9f4d|0raV0A2IkHfC%KYAwuVwE%Yf7@x3_-cRZP| zZUj)KRc#stW)eBp*EWOTn#%p(U2^76*35u7Q(PL{j5(p;A!X6jf>8-t9+l`85GUHjGG`F8LxkX z;EK*WBkEseSwrC3JB=wlHKLYbBRwkinDHj99Ng!5hlo(oC~H1gNHI1OFC>Y^ZL7Lt zGk+EksA@FITS_HEj-K=%6k&l`T=&fnbEgm(MsO9p-o>=BewZyN(8j{qvA&-qdh zLoUDI|S6^i?5ig{FOM z$Z#rT#S8dvP{jUmi8-q;uMWZa+zQ}V*4WZIsLO*<@MgF3Ztii5H-!5rED_<(Mze4FCeA0R7 zJQaX+Q4r3FJGL0+SV8aFaIJO^N7Zo$8(qnKk07D56{AEY6{uKuEi!AlzRu)~feeOh zdT&v{n7@!mA?i`GpT{|5YFg&i_T?t~6W5W1?;Ssc4H_A!_W3Hn2l;}#bLkhrU9ZF7 zR?r)nif7iM=E_+HaxLr2Ek1uvIH2h~(Bj&w-KWdm97TTxci~10;eP*7P>Sna2ce_f z{_W1xMC57#P$epePm!r0p6Z2}z415I`nJuR|kOyB2i9MW9O)QAJU1gLjHf zbiCQ8fs|ToVaRDv5LBcYa!|eO@JKvEqWzm2g#w_0`>Q)D{ggkb!eH}&=#LL|QX(mU zr1d<%QeVfn$0G)lS!=HFv1y$v4B(3=`Y{m+z+fJJW^Tr&3TL_fPzZW{k07}CeIbX) zvNf5A9i}49rJ{7AE`FK#VZ{F8gBFCW+rn~nQD{9_LC0wz9Ns@mrR>J`d!gxc@dv|} zyFaX&T}&qzXhr>mFA_c^<&0fs^9oSzoCWWRZ&k)CXBAijq9Z)P|FH_=*}jXjb=wbp z2Mu`1JprmWMe`FWWgKKVV_N&+6`*Ku!Js*56$lhfi`@g+#{()l_=FD4Jf6gM*bC@* z&)6G1BF+t-EAHDr_f-ss;1rB&b*u+xa@hm4FqGCoqeQ$o4Zygx4sYs?kqZ`@t$FVa zE0eaGSX(K!*1q!ZqAXyRqxOw~dJziGP2siVb{LeoOHxKl;ZwJ{52tySI=C(5ll00{ z(_Y3$oXN3CfBn<^)tp%%;-J*HpU`&%mfJbFz{2Xp26%#r0H46=z=xX!k-RweXR`xa z9Il8et_Q6*T%xaE&j;-T4hSPZnP(6hpHq}09_#_$&ePo^w+uuMF_PqrkM^9Y-|(r| zdHVV>rTOx)Ker8}t(!g#RB-hqx<@W)jIV-KG7`;_Gtg^QduSXljWC{K4^c%mZuEB zu$%*esWNgv&kq01u^iB$^ypu0(A^2W>q}v)Lw|@dh(ZgpFnKH9~ z#yKEaoP&zTb0>h!-!}!hG=MT~lTiUaYYZ_cCon8kKrk)FmGmO*WCW2_OX!SL^mN)Q zbGd9ZKqMK?GU021At1?APBDS$*FFcOcDGZ=6rQW!+4%^aub2VluaO9^@dC&yLO70PWDysO`JXDLQ3H%Ta)1*#nOHE`U1QvP4cztfycBcylt-Rek6+ zYkIK1o{^GPz8r{cVx;Jbf;S)m@9Z9}-vAdnV-LYR+vEIWXCjfsBx@NAZP)1s68x!1 zXJYpq8==!GMy_67Xn#N=fxLqY9$4BuyxSa(6PDJE<>;%5H6Ay$DYsAtJumhIusXy* zG1CMDn+O2?xtfGQNaq7s06-dSw`3W7)wOAlkWFfa8rL57eKE26|H7xnqfC^QKqci< zjyX6bec-DK@#w#z16$J~5jqRWPecqeo}V3%M&~=_>x$7r`wEZ6kwn=$`bRvK{%e9# z6!)mWX&TNP+&@;DgI@0PSSd5w^fGMV*E786D?YM;^r>i7q3H!Wixd3_C_8)Cz%a#K{o1bSK0S%506#3NSkjdK9i>%l>=*0sDYCPmK(rtUCnqjaFNZ$^OsOlS;vtpQpt$SY^Cr)cqGUXiJ#N)zD zk2Oik=J5@yFC3#}4xgnW^K?t&fxaJvz1^-llQ53Y)vV0uLIZv^s_2>GGcnKihY$aX z8a+^2wPB1+K7S4INzv%J>s&3rP) zAxH#1*KhSqkn6KNC%UPOt845{T#_TmCjQ+4d*R>1Mcb5s2*yker{9tc4zfju-;y zdjlf1lEQO4a0Ai1;I;v*`AUS6rwh{gJ?SL(#^K^K!G0d$pz4a>{C*{m4sIGxifMK$)nnr_){F!KJTXi45Zpoa}w})DKe=x&+pKS6(bH#(?Aw}b_ z<=h+v{?E9E2-@kpJcf>Fr2cn_Fmmk%Zw5V*)bA(lXz9@<>V!|>2=V>S^vypM3O_=0sk1CaApS}7Pkc`b(x?}ubDra_S}?)&Be zzdS4U=TU;j_RAM9#yOjgn0B8axE*`++5~aHnOqCNnOP`+C)SX`SHJ=e4q{pk5F{Qu zk(P%Dh76F^gjq+aMsMBSXqb$52k;?&+cJcb1P$|qi|peuL&O@-YVkj^`81r0RgPKZOSMUfQ1M zvn`cQ5lu*t;Rf#q!D}!WY~@Jc(6in;ap>764(k0eU}Smq;VlyL@i%%6XbQSE2t7ih zbbFRyvBydYaDZW8n9ROyU%>5PkEOIAw^6a98RbUZfg%ju&kR;5wBs!SJ~=MPpL#icRle8AfLD7V$C%E=GW~PJaAy?J}8s7FhXrK`|gavPn3(tY% zz?~COZ!+bcF`9M^`ilgzKdU3jbw1lO=v0!sH4ecQ$sdRiBrggKSE(I_v@}E&WwiE0Ma0na;6^Y{u<*Oss=3! zk(WPeM7;a>9N%2ZY-(K3T-wT0iUP-`3Nw1xDlY-hO1F&E-;WvZVc&eb(-R$wI8Flc zdo#m`i(I00u6C8)v9VGEBXj_zG+cEKv;wTmse9hF(X1OLbk@z+;IQZ5JHj(RxifgO zfYp|Q_BeR*x18poqp@!!?RxhFp$!o+>Bd_nX1PNyozhIO<^wBy%2DIL85Hade#qlG zC|oF_6YQsBIh4V0hwJI&Wp+`^*-5`nIlzyTat@;1PRU#B2W8>wP3wX`KKuY81owGI ziF__dTZgb!5-Do{Am_olyY4_cq>Y01Ypm|h+OZ7j4cnD~BE!k24pd~~;0okr6f$Zq zH=!>Xz?#S0^*~eDkZ(HArBh`{&~7I8&#Iljt($>9Ei4c8GF%hVWa+`@(H0XGY=QuN z3c-A!x%$YB9c`+h@_k)X^w~!%P{#|b48~#g;j7DBpyjSq(`{Zeqq`m`cr)lkZ`&;&FS$d3c1`E{%|E(u@u6uIvxwDQ)- zH3*d{#I;6I1BtH2S7m%Ee$-z?3qPY6$Y%8!?7kc$;Dh#9LmnrTrgK^GTISq<)AUt< zF~!!9`{YG?`1*ItJ?Z1UKSUS|m(+%RC6`!zerL5l+S zz?;wcM}Hr#K7aXUAHEE{C)xTCfVP4z_Gp%An<1N*3-s!aaZd>2wmfDuF#?hpB9I}t zj5LlLCQNfEmPb_}-t}nkt18o&^E_}G5j-J`O(5y_i2vRP_Ezi=-^}Q%llr5))sxG7d-)E-s!CihT&U>XEeGecBcr|KUafcjRUg`}5MU ze>a_$+kV6iXcuCLz$F6u?hZ=i0hhh^6DL(pZF}S+MtF-*?onty<33PLP!g~}1GZEC zIN|=Mo8p>{s_~4b4tJ3Ea%Gec6UPB|50;7Uxhx|Ku9iFpX}+CiYE7@>%cD?UrtyEy ztP#Sp&UPAyTW{wy=7~VJByE>z45LZjJ82X!J`3Qs<@KPri@m#!Lbwth5TK3u11rnn zTk*MeXfIkJxpVWtH^(ockduDHZE)931zv7T#Un}E*v2kJWFjHMWKaxai|k89mco<+AhKU*~zgx?>w%5ICL|e4SK{9br)lGCiYk(LH?( zK8xkP8du+PIB{z+g36E`&I3KpqVQyv=9a{~9%~DNsRMd`Cv4qa1u%_Z)%j0yrQ#c_ z?IsfYKIIsuf+GNvAq$;S~Lj!079J^DF_2 z>`4?0S!0iNjg}myG~Py+)*S#IQ7FDJym0d?3lPQOo&haG3i9SmD5h$X(Z8-2kdkWV zMn1V=F*`S1S$!wl^nr09Bs`eJSk@`$YNn#BJ|6Cp59>f~`Ay$3E&7T7J629_X^-ze z-1wW~xh4rm&39jsM)+ksGrR-L+;Ch9)6Q+{l=8PzT&chN^xhkCO>!q z#c*TAsCpHu$k!3u>t*nJZ=Hbtl7N)wKxBM;PJ6l!*%%-DfJG(#mol;entB>Y6%kyF z6$A*$iO_t*OS+Tf*E9y;ZIOgv^wqvbm)*M=zYyFjh)B)nrc!gc3YfAO6X^=)ItbLK z;Mre+7bs;Rtfm=Gxo=<3p-8T*gNN_mUQJ@;gbGqltnEt8HtiP7x|456rQ+MDv9kN# zXL2vJ^M`OPoP1yVBnR}aGU{(j>kL@D@$GomO@Tc#~q zVCJGgT_zk~L{W9WZ$IY}z6_R51B9KL@6(30Iz*k$k3J~5yL{>gAM&Q)Y))7a@~TNm z$q|1B7?qLT9q`VZ)q!W5<#Ign<$+lM% zNyhWD=c}>cFvkY7RtIjMAxxDIQ;7X&rzIM3VXD8vNk3O6$Ps& zO7dR!&6Y9r?`nTury>cvEv}i0?MfHm`r&Rf-NspVoA`+z_Qr*-Z*Cw<;hV{dT;|;@ z{h>5Y4K}S)T}9TXo*MJX)g$MN+171?m#uTl=VqF&8gxn*y|$GKi4ozkT;i#tL!m~z zx&~sB!bd~%E>w++zc#2EG4sVXMs3_wlSrX1IdEQMs-_+RRbtMgh|yO()lYh<)N->L z;l4$hH~wv91bD#?;(<(O9RVlFmyOdoyl* zgSR57;9_WY+k`6mXlR-DSDzp$srmr7?(m&wg9ZrR>A(J>jrN(OzEb{E#@5pFPZJ=Y z1X$)R;-|yk{dytwqu_v{=aRQQD@8V^S);ZAD&}Lg6Tg2w`KG?v^--m|-t_KYb zOcqG{F8|?yee!1k)!2VTt9~S9t0@?{tw&Hr0MhL!!C2-Mw%UQ8 zh!e)v%Sclbrz3$^0w|hO%k7=K)L=!ji=lw0W=@#Zy-R(SZjnzq*S1wtF^nT-Tfo*` ztX93Z8_eoi{>AUs>iVazp2F^j}3hU4klb8vgQMiupZS#5ldJKwO& zmou(H3eJe%_{P4w!l)zzvYc-Eh*(7a-3yA9H|7rf=`b5(BUa2JXP3KWI+&J`yTl&l z2p9_U<_#uL%=%8@A?Lb{9>sY__|`2Nb+dR}cJEHj$9wc)O@V&!~cP?z*V&={*D z4h~`$#YGut76S?zpW)dUfAxUqt7`mnLc-l-rD*u=6~HhzZm%F0xWmc&Q%2>{UA}^= zNr+2$$dy%4+aD$rabSfPwrA~(WOl>>bO#)iD?y=)+Sy}}8xHDB12Bo%@Z`{2|Bko> zgbj+^`P6-r-y16q4IN^M`8C7?gsNI(hxx6fX;f0X0*bL&=W)uEsK83fJ^Y;HeXtepy-BimWeXAbrbqKmL z?peFv;$04GjsslPB6W9K2&V}{r^68eMx_|Mu@XAsC!r#{AQ>T!N>aoc;+C7rc0I#h z93b#&uZIl+$^~GBZorYTQ#WLLC%L|^-<>jGHO?r(pp!K84M6Ng30@9PtSh0kn36Bx z0lBpo_nDo&`nBxMo5PJRajcV3xm40(e*j~1_>H4dQ*dwn7kd&YrdPLtQBWAM<2uoL zcTPdpMf!pB$zBRR#hU#Wovxo&e#4cjG5gepe=Lh@{o#6A#Wu%JaJpw@Ts;qX4dW&L z@Lz7j*PRtlqEd|(7SM3O4b{+S-q}*$RHu@qnM$@hh_-)%ta3!E;nLlXEi9;cBdwb` zGsNmLB-Sb}Se!QJg*c)CS3JI$9I;kIH=c$hO46cshADQ*y732B&;=2?wg7br>QmNoGDoO42`rmuzg|KU|@nI483UL+bWU+|o)wF7_Ewx0AvVSyb*p4aa*{^|?D{ zpV9BwZnKDCuqg|M?^v+PA&=;=ssXhy7$n$iVGFw+)3Um*f?g%N>{v|MEh10&a=HS; z7{Sn>?7}@$JW9%Te1G|=@MksZ;$AY$>Lb{u;OcSH8-p!)2-r@P>|0hJcb-_e# z|KspSJMR!ZT$AE*Oy5esRLiOrXQOIi6WMgyWlGqxV`i;f#j%3VnCDC2`R%2*>GtGl ze~d#BoZ;19FCfKHv1YG*mae|9l+EeAi5x8*F)gUY15Us19}I1d8@FDo zptAleb+W8$Yu|IJ*!;4s)i%A^J90uZXcC}zUcVfwR^A-MVWw$w*D`B8Q4ekke%LSc z@ytMVLDKp1wO>t_QtqE%J}P__Xc_+b<@WD+C2k%FJN2s8z_~{|VsyJ=q%GNyweNUbCuS2s?-8Zu;} zV`%l3X0=BiJ%220CxNa_-Fr{}Dd!+BQaWHlFeAIHVC`3Beza#T-9zm6TZycp;QLYLUk|jpA7xx53A7y+Y;n z;iP1tKc~4{4Y(am=syvknZF66x^5tzZ>QemxwJssa(tf=h<$Y4V%blm^^NeQxW80> z_Sq`$X~BS%dcmzTOP_;mNB`8*f?ofc;(B6F(@NgZ;Mks-JurUPG7#HSJWct4Z_hoV z`|vGoz};$#-MP3{sqE4u%cl#{kM8L^l-0ThH|AyLqeGLHSKkDcDui9?z2HOe(Z~LZ`>U(ePeLG6H zWP*v-=+sbMcNB?B&W8?|+shnJsk`Il!n;O1T=#_k;eNNpQ%>Zd^iV8gg(hFa|OsTj2fs znU6VP=5>x)B-85PpnWGZi0)8U4BSS<0ZB-);gDHkbwhwta4)*|^^U`yVt z<&ZdGQrMZ(-LcaR(6{-V9U={mrJ4*0=(Jmx-dmcx$QRmc!JxDJ$X{#7g=gW@4GTcD zeJYp)N8JFN6dm8bntm3!gnpLo4)V>o}z;5GTrrfFd-D+>W9rkK{ zMfQF`yx0)dz9`^@N~+LoV!IdkvfY*Czc@4t?{v zOX^0<_szz6ZYSQKc&$@8E%>45!RyY)SB2!^>eyhyv-nv5DHn;3!1V{7qYxD_n zrNgaPr&zO*^EY9=R6X$BYvwvPlcTyjnqP9b?gRsX?JiWogUd+O0%*;D^xuV`$&8*$ zy6@LFezfAtPExuTwRyPGmqj;%SKx4L91~Ra*urn^ow()zp*=gKLD`;sxF?nxJcE7} z#ri2xs40(o;q%Q+gH>dI#q@C_^X%OmFVOR4_QClBERz1OHAD018RgM9!K1i z3)_Ep;oJD;*axmEFkpDsbHT5}X(R$>+d#3VpPP)n0|0r(VY7$e8pF6dhP2Y;k~7CCF~=w9y~w244=-L%75G z?aU3969Kl!ZqHm2=$s2A_p!v-*Ax8*6~qB!*TSac&$#ZKJ-;K%ZuaGCOET3exZLzW z5MX`P)U*QYzUA`it%8JXfw3imi@5%Qz(;&I#+Lu+7oP5g>KIHc2~4xty;1|WY(<6} z-;7Pf^y0bjA74HQp)T_*qOUD#cvoxE5szqw9}wb_2S;w1Qbklq8ZFI5#(Zbdw&MYu zuQdhU(zxAJ!E!StU#D2yFX6yCs2(1qHKNOfP!AfskN5H(<(q zJZT+oN3x(wa+*1bS2`1D(dqg*=!kZEnak-da2OEMBCBzrb@2lEM0piy{vwpo1Gp0Dy&0BIK8~=(}Q_f$QQF1e#OEc|4-Jo9K z%nDKy-&o{B7DMJ6?yUqP?9VKp?u#kxd6E#w$}@2E+7r^)v4;w4$d<+Tl>yO!b4w*q zG~^?u>2pA(d~X@{`2e;SiKAVnP>d|N?!WkX;P&q?AP`>HvCw!7$f#x;fn@_R!r~^5 z@?Sv|W^#{&XCxqB5r1AKw}1M0GRKY@KkALOC)vtEy#-Z;%Req4)=#SwXfV4MOu}hFD%m?X*Zwjh+&C<(tn* zP2EWvLOVMOo9unRXrymWr;4bPtV=cNVf9>7ft~Hhx9<@fh!wTH&(X)mLU>QEJ^fYH zD%JM75R$u_r^T~G%JTT7kK~_I|I`Rxa#U{C6GL6&f-I!BfGIn0ky}o$G{Yo?o#f+YA31ML9!T;Tqv%%>3scl|npKd6_<)ONGpRIVjq$tt z?dXX9z26cjElql6-BHD72x(k{?;TB+Gi^Qvl25dB2~aXtg$9ihk>0Mx5>uDrouck| zd@+4hBJ>ATYr<+z`}#{%Oh+!~H3X8aRq>v}kmLuel9C{1_=MNSpFYuMPJPOE0w;lv z5h9OG(K8~m#m|t0ys##M`(j9#=PGhH?&lJE&tk%f4Dy@LUGxxoN9`!V*~-lHElr?+ ztK<2G$MCn2IV^M$X`Mh#-N1zXeQzWL%eW4aNiOrG<^6(xbhQLo0?F*Na&1cJE@Ysf z)+j=iDC|RaG0}1S`Gkmj%C+Ya?X>H|HiXxcCr7JEvjNe^iR;ZgNr=S#(rzVsSpI5} zD<;`#_Ax2gV$G`HTjgzCi|F||joAE|--CUk-~`DqhYDFl)!bLauW3}CeP^XZ>A#l}H7VNka#qF9}3G6RQwx$0U6lk8pr z1FYd5-h?2#eo?2E%!(uHh~N^HzEv@|9JK#Pg098v5IeDJ4z6IMu&2$d=@cM~Cgp60 z(EjffU8-w22w@d2(;IbPy^>0+rXa`SEBH(&le&+Um<3Ahc(?o6+4z@0q%uxtSBO+W zVk^l-OQMH&1(Ksc??%&ZsejNh2*{%C8nP~qJ6$a4X(52@IXgbHr?<&{Oe%GxAo`AV z3Vz=h{V@|6j{U+{I@gwacU~o-bxLgc z3Eb|jaz0}aP#fu)Z8Z1$f3DsC{%jqgZ!Vx61!Fybi~}kqjNIR~Y}o^%xrbwv_1xGT zff1$VC0({Qy!-r_VGyB{XO~gNKgVyCf)wl-P5hiW=lLfumCI%95=4vNAAkaBl47p zOLYV%78+oOdBgRHfbQ{J;Z{Mr*(opbmk|Tj6t#oSbUM!y`F6{GVsi_jXS^JI|iY;g{S>No_ za!6WwYndlkT5dKT82xD&U-w|W>0)NBX`;}u^0mWkL3 zCTcw7{t?mRq^maKduMpkup zl={@Kgpuc%WYf`Fz*5vTKRSx2$`;!5gsS`#QP1mEyl{(%AykQ!C)%MJR>%)%bpXCD zUf8rWV0|ID$Fe#=8*sevi@f`MK3COU4IyeA>D!xR&x*Oxxv#Kn(&d2PSmsGltx}0t zqVU+Ir46kvlasOyMKWx*EBP|2Lf(6|D*yELKTm)UaTa`LH8lvg(hMh9VujTDgq#AJ z92N`eqA-S!Km@y+Ojd2am7#HU%};cz08M{`wq6!!vvI;33pPg&A^W>tn^JIh(9}p85}zaNC3wW zo`WGy{4Z0`yLzrutaOc4kdbmo1FZEyE2r+={vox?9IHYa`Q^ij-Qs*>^B9qeb0wP4 zHmT}sU!PM$OSsWxmH07D*PWaW%8@+%sx$_>C=YIB!&(w)kj%nV1iPcmDHIKs2=HAm z58(dI#akWm`2eUnb zo`c@mtQq%!PjlyuEPpxOzUEirbW?JVb%i-Oy5YnKN%8}2=B0XOD}HF5Z`>h>{#-6d zT(E}WiuBlk6_Z7Ey6Ab*KkAMe2fIz$^;+H?Bd*3zks?Y-O-xxO5_K8#=-8`(DZ06q z^S$rGH;^SIW3Sfm3m819y@r}N7M9mi`ZTyd#|$RN>wNdPB(MeF(Yv(N*os&FO3KWp zTXOn^%rQV-Ib+L=xbNcooXh5uKO-4z#RQy%z>>UpK zrXbBzb(&QYRd>9|z$N>q)G^EmzJCMAg;ef8=FD#R3984-{kJ=H#Y>+NyS-G;yL;Q;e&NGSJw-=XBuDYNl z=#@^~PY9;gCVY$sJ80hGgavZpeQ zHP8otJ<_&A^*AWp9F5*Fr}$8jGk=$znLtPFh>h~~Cv5CyV$GT_;ZhdeQ41A$Jn!0h zSX$6Sis#Q~Ce4ULf;()r#V4pr@suIJ9uO%HJ_+vID16+%ZSyz@_%@PFdN@q5HqS!Q z3Y^bWkX3dT0qeP!Qf2eD4^~ypKE}=78#vz+sit%EX5h%F60`KJ_zuXCWOiX}6YbKk zpMlj&t)<_Yh~`VI;C^tLUts-@IAXToEc>%GGhwrqCvxoYsdUQFew6X28*K5w5S%_4 zF@b0C+1;NLO%>6VbdU3~(2)s$*r#{Xy4%5=9E^&i|lXD-ZPr2XkBevGEs6QP@qNH)jlo@Me zAG!o|keK__V7Z;0ONUTqeLZ#dg&k^QA>Ps{0DJ)A z=f{;?ZTfL2O1i<4OiJS6L46L+Ojn+ufUld5mk-aU7!&kLgqJ^)DAx*nXG*O&ij9_Ltl?j!baEyc?dE&piis9k zag?F!!X0gnS?7=?ep-8fO)d0r@g-p(6T7|3akB|aDN4(zPyJExXoxqS^kQr5R8ZD& zsi6T0O)I+WJE=|isQPc+>m$}vmII%<;9{cB z&AjN@Zn>%z)0P?&4~&lC_A~0-qTb{wLhOryl>13@AD_COcHUW|)+s;#u5r0oDKb(R z_4ZuE2WkdcUaBtRr+MQ8(rG%2?+5WLYIIa*-u5E4a$uxXsD%O5z_Tm0&5t$)4&2WK zgQ3tvb+Eg6M3fHBV{VkdDE~A{=;B5`Ld|{dc>sX5Z5^%mx7&~NERxR607tCVaVr3k z@Xqox$n~QRr)YL1-!xd-%#~(YM!s1UDg^q)M(r?u1~BxawtM`a zFBZf%j9(9&x>FHN)r;HgO^U(-nhwL*>*z&>T)r)>v7V8I;*D3ebDHqh=#OaY| zZ)TOMlU}f88DnCIJT0MgK?0Rp29%V7d2z&ANZr}4makDO$b?3hERE(`f$GtTI|9tD zX(fjFOh=63Ber&%U8X>M;x0shBBoq~EASjR z5|61#r%rcA?aTJhtS>N08B?N`+bi>Q;hd{d8^~?&@j;H*eJI^Ezb_al@~_`l zdZQ3)agf%4NqT8;)Z=?gN7gldLEGDEIvRDonalO~j^JyO6FajKrzL&hAfTm^K~9%) zp4LqDuEFsR@`N^iTdfIO`F6{$1_E0_V10bmn$p#)K{{~b7<$z-kh*g4w~YO_irN(? zyUg0J%#H8<2K*3Q&_M7{*=Fy4suw02;BTWCy(y`|u*mNP3bc zM?mzSq%}VZ@$*$$U{Gv{Vb)z($em>}yT$hso{bEYNc)RU-~6h2m|r?@+=5qq&m*`Q zn+s~CY!u$$v2i7ZB3^MBM z$n~$*OlW*8>F1d>+p0}b<;V)|-yEO~|Kgp*(^K~+=LmUY|CE5rILt0ZKQ7YkRy|!JT>OmL@I0pg>Q7fdytbFq%<+>g%bcJ?bmX4_`j8 z$_y?R$$Bw-UU=_^-;P5QP~|ow?ovu)p@@frh_f z7EZDC^*0S<0B2tnT6uM5li6WPrB4|Wl_O_%6iE&m^J|(5jA@FhJo2zkI;weP=PAE* z-3?mV##+!CUxpZiuoaPpj*|x({*6vA@ci&>P3&8GFp96VYdc=gkJ80wuOK46)g_%kRhaJ7Rx+Giy_o zca(orOPZ7F+qm@g1nV6f_5tfzH z6fVonFK-s>+;XIbEb$gr-@QjY%#5rW&;Pcei@Fy74or&Qdr5P!lA0}vvNGd-OQUC_ z`4V!h4i7#BM*oXH2N{MmOQ=BbczFM7y|s)jAbNkVe1w7Sx7{4p#n~G|3qeB~0^%~R z{#)9=PfJ?Z(8n}6cV=L`6NJYrO8Zv(N)LSp;-Av@`NErr{kp&GDG;yNUQN{ytW&X? zgU}t0L^c~1ql~S^DA~yJuGPLxS*WnM_2P#FQA48B`}I+?IQRR9&M{)!LRg?`N90ql z$UVYx`IYk<9Zk`?XOhEEc6Z7u|GZ$YchPzS%?$+3RIlt>r2=k#FNH0R3`7-3&oFYj z^(+cc4ZXlT=2J%w{Wqb`4t1@AK;V{rn%8zZEFm;P%p2?SXJnDM{NDFt!P9Gff1X{m zIt^r@uSh7WGxVoN5HT3g;5)D4^+)ZFv#Mt~nu(IC( zYZhSClmmRvWVe(8es4v)*!0QZ{=Voe+V@|B=6|AB@Ik+RRVzM?foI#tYB?d*&uw#DF9x1cW5*{j3`dsLX4$7lcgi=}G6jd>mSDkKY5 zd$o;-j*!o*$m>agxe3I=Mv$dX6su3LCX1t-^44CWAvfLG zP0Nn)*E#&|k>YOr<-7S;&c$T7k1g=(m`o8sY|kiyYO(aacTLXquHPm1l#QCp?N?Qi z3njXqnIcyv?-#V;U-XhdM1&%S+mf*ntH8@^z9vu!ylMX3L{~Z z+yKgcR6W3*2INz?=uAk9j7khiZ+y^B$#6U{gznkiybS=nqeE!wst`CN&E9kWwUy5U z0)3-C5P0Wbf?62+x?=5Fw~pIFH4BZsPjyJ0D_7_tpk*zJ&hwJ`a&`{=IDoq&8rFC+NnA!cp7{PX>wqK>G7lyJ!h0xu8e;z#AZs-2n6pC*AzmIi;Nc=e-; z>);$xlfZ%nN{?zi@MR zHY)&m-QwG#TSQ3P{h9x2nK-^?i8x}+lfiugRR6knAg5}8ZRI-WVu4#fJ;#E?jpanD z^tB@`ZrK%@120PX~2y#`U)T9ml#(X;Ev07FUBoB_K#m?DQ%85Pe@Q z*f<{oXU?rt={E(BI!Imrd|ZV3gdQ@_8drY;crl&qDsvNaVA3FKT=>$jqA2l~D)NKh zoolFw3%ak=A1K`t==y?O9RsiF*i+-*uiFrpAI>R*a!>k;vl&beXWa>Q-?0g$y6fe? zUw;u&#{=`sCFge|XI3`-H~v{pVw!P!kddEZaU)!dxgMB(h~!#ZTtsTV>!t*6W?8f& zf84e!)Py*T4pMK-Qrlux!FjnrQk>`%a|BgE@W|2(a6%d5W;P1+1&^w{F;kp0bFxzQ zW~DbeN$yxiat1^*%n*{PwMtpRHrv46yUyuArg7o8KVXp)T)S5)G$l6(KUQN`(*obb zc8I-v8TzoT#O>+pgYC#8OwA-0IF%*<_uU>w#y_g~6leMp*f=?W8%88zgf*LaZyq}P* zKav}U!?WKA)Z9)w`@XL1O@*lN@%epE2LFKT*Bi7!m+2odALp2hcz zQ&CQFAD1tOteTYZrZSi_=2g>zR0AU zcE|7RAIw&hU!9dPv36FR{n59nJln|7Da6$m!SNgb`@ZRzPn%&I&x1~6fx{O=1B9An z|A61|^bzcjD+n0@xTp;f8r8zecy(=TakwZKT%p%43n1HGKOHPG1Xkg7{JG2G8UDFb z?85Tff3hh%82u<8kssmU+RW!3Li2G-gtG$d434}{H+bw+TgLGMG<7j`sW3_)?`VkD zi=NgD^=x*M9aBHsIc|YQ!YyXA%D>mzZ=-}35fo)>sQn!cn0nVogcl#UnPfk0%j!ff z21XBAvIVR`L7{W6cy-TljEs~`61+DWm<06%`KgeD* z(9s%N^_eT>HV0Wr-|wjLmzJ8-!gbUH5cRcaG!qohP_FW2kG54bsd_BCFf-HGb9k5VBN|L5b{_?K>oH; za5#%p0`L1-O($;#Tqbi1cTsuHOoF{Pp3l(?aueIZ$H$Pv9c62AC1~fl8Z{1MtozQ; zq`OVNmiC9bg9_GeN({jEcJ4GmPpii*Qrfs?R`AO&d;}=x#a{{@?G(#4Zzvw>J#+~w zKs4CwTz2_4L%H;5Rj9?9=i>y&>ODF=bM8B48QBS^gKHpTV}sEGvD5EoRFW|; z{?DQ6b|*KU6i%+%^#^Gs6=!V*{m(M{>$YA!<3V6-{>+i{KAyw;U_)S}=}OG74XC+z zP5F#N%1w7LB_KeYVTmhrED}7rP|mD@ z1Fc=Zn#y&ao7x6tv3t>EB1XDEVwe?*ZWaV-gR!$R5;RO7pk{26Io{bXm1~cL1=ZG| z%rj8t<595Qu(!Pik*vNF%810|JWlO_JJgTJ0h_psLc5`q0mj|~$j^U@xvTOwAz~<2<~$4bwQg9%`7pSN*3p^PYZ4h ztgAW+VB7X)(peyh-375+C+HyRy}@&Z?-)uExhhnnU>@aaZ;-$!CD;cgOk||z%%Qcz z+Y%^YdiB9t_4c3(rC+rCdKh}+;mk5_9~X542KT`&JItYWc>B9Vd@ zyPcBL{yEs=0}rzEGsD-Macemq%||#^gE6b(zhAK_z1jg%qf#Aqw+C1hiQ9m$Azk{VFq{LF?BNHSt}mnAVMH4w~(~E@eeM zrvFV%XE^ucNm^2ze4(O_rZAD2@2xlE1Q)~8pG;i;eSYh1(3}Y`PJPQQ=odZUJwGhl zoFD8TmgG?h2a+W7tFl1;eALRU1(bf)JpGA53qkAlOHey|wVwFRt2gF1s1rYJ2(32i zlRme8F#U44{i83-?CKK8*T9F2$;%A-w}FKkY`irV-&etwrD^1^uG6DC>BSkW9j7W7 zEpu?{yH{f8iSz}obqX2U1RfGQ!5;2OWF9VKAogWLPw}FP!$}ECwn6!(vNANPv zqiUltW$A8i0Qdbp*(a346MjcunCy~i1*EXxsC^;CxQOjqtXU=uscskh2VTyEUE#V8 zaXuYP+xrSbrs9RPf6l_?2%PLXH_bqC($CARHRT_KtwKi*KhyxHS+5cuLgaW$NK&n$>h@ zo7fzO^5|Y*)JVkCFjmQ%TiF9$O)$S$*M!tw8oJ+6)Q%Qg6IrhOa00N)qT62TS|kS$`&=*ipgs2-5&JAPw7m)+9haGxr~ z3z$qjbPFH^@@!sUp3ouI!TyO$F5}T@`#Q}a_x^h)0hpG@=_aa0-@lAJ?Yh2we+N#GB5S@Jx{+5EkMN zMPE@#37)$=gZ{!K5&j7@WRLIl{Wfr_U(GPqJ#C3|4e_vZNXB1RxxO)kCsO0&=^K78!@2mMuz8lZN^Y&6`k2HZL??0$v!3iqxounaA5`+dO))KFeRT_iQ`6*?|Iy zvrKT#{K#s--cFTOWkI7R>J3)3_eAXGNpS=I*N{)Ho*&RiZAo zgAhIrdmY>#q3+wN(CUiNL7LFVU}gXMga%`2*ut#jBJ99nDLRmKJhWmHrGu{CEpUc!CG8JQ_l$RQ9*dvwaoC$>l% ztbQfJfrG(l*D^Ap>9(ShY!v#1usuZS#8JEdzfBK6Mjl{^n$uAWmDj(~e!*c~+MBie zZPAt8f1miCR`8Y7DlW{a`|kSr;l;@8BOjC#jNnB*D@^&o0Gjba9$>o^G?%!BfAeeg z$l#yreK$?F2Bx?U`dF%afBSj9zcl7LZVSJJ-0Bh>dROg}x>?P>^^Sbtz;*9FY<1*x zMMeDVwt4hmL&Mc~mHI-^QZPgS19lRYynJ9C6d2Bz4bMNE9vP{>F!%8C5$}>CInQ|}PI1l|Z_&j}^ur@+vv5O=#H`rSL$KUEz*YY9Xm@Hae*a)xo z9|fnVHw&U6*-WbNl0a-`(qks#vlRkZZhx}GJHJ$CVp4TvoGqcxgBbQt2U3w zRol$d(`Y(@86~q0i)^LrQP;=_T_dwD{rp=d?fCDdr~KD92)eg5pX5kXO7oS}CI{3% zB&3olZu(@y8Wf)IWd}U=`!~G&W=Y?~tH(LqsI-z@c)nr9bfjlMeWy~;Ra6V!FrkU6 zwu-ny4mSMs?v{tDaeCe@CY;|PtPCE4t$y_HDr#-mLT0*J`q;6P4U+V|4lBz={v{26o`fw zaHW%E1VT4DeEvk1V;7%WTNE@}N_?ppdTHzSLPI|+qe}TG;q;~NDeRl8CCfq)Prh#B z6XZy#l#13n6*udHhPFky+iv zbXsEvf$8*lY}A<#JK}}$mx;u2^sUK}Aaa+69S`ot!OTv_-T07`e55)!gq4#{*HthAI* zo%%?o$d+qnGcg&dx8h^lkiz&IE8CfLj_PAwGpV-u?RX}p9NWyns!Xaffdl?3*D90b zn9q?;9eu*ZJ_9Z(2QvLQ3mv!)jO_jvT;(h?cLB!mO7c>K?w4zTTr zHV%aE>2&(wU~RJ?(`l!S1WMlA+}!MqgR4W(# zIfR|7t(Ui_9aQgt@7zdE2xTD|A;$kto|MM>y4wj!n_eI}+1Yp_q>X(@-hY2`&c)in z4k1l&wDrCsq=b=0NbA@+I$ZIF?`06uXWX3KJdNG0ZQyUU?5;W5*lBxO`y!+@9lgB_ z?L5!8xwyNz+PQiQDI=uMIy!sXc?wCNb+-1l)3UR1vxVpC*||EvgE7jo7&SGa|9HC_ zNs}EIo_9>#EQKQ%dPXO?%MNjdOj#a&JZG7Q375}2ZG-sVe>s`?)&}wKFaPd?f6s$| zFN1$?1^?a&|L5$4#|BQ?_xrX~%{>kn!K}5~EGEC7P>uR_{c!R0fBA;d@!FKXb4!pz$B^y6M{$+^8pSnSUETiI7_R5&dKKcYkURutH&0s#!k1*=Z)7YG z(nb*Ng)S+{3dyOcNU6xmV3dRu=Vj4wiBSG>L5y-r9=J2-k@@gYgsxVcChS$jH4p0Rd!^tN`E_HuJ}fw(VC za&{w0tH>#nWNj5yWEJdWm39 z@BclqU>Gm{pN=g5M~zihkdjl9QxQ^@ky22Qkx^2C_A5)t$jU0q{SRs@<{xRRJVr`M zP631Y*T5>t%E$@HDacF7Da*_JlZ}NDcX9NVww94qfVl)iD{HS}4d2__*;}h9%8=|7 zt!E-MIO6jh`!@=8hyLb57~QWzCw6{Y{lt(X5tS`TfOk&#nUhOt+Y z0{mVPTCa?eQdE#t!u->%SC&(hQL>Y@fBUHuefItz~TN6frWgiZ;r2 zBstl?V{h%_eMOq_#m&>v+tJQTTHnXn+tJ9)+0IMjKYr@_-=~DaKhi0%%;go76l8^D zp?j3%6=hW5J0&TMjH0~4|An2R_>Xi7>YM?KitPXB=Kn8P#s3aTkX2HV{ZB|jvP;zWS3K|gr?c9} zx23PFGx4%cge%cH54Trcc*unPPMum}he8)|-p^AFo<90|^FvRSs$ltGwA`82pgU)p z17&j^XsP5^B-{RU8ctfpHb+ut^cqKkWWvTUdUedijc@&%5 z`Id6uP46q?MY$yb5+CROALiZysIF~Y)5e|P?jd-91uPaC+}+)ROK=Ym+}$O(OK^90 z2_D?tT?71U@6&Sjy9jNKlrLCpQE30%x6+!M;K}g=bsvmHq z5xI*t5xq*QGpj~wd=*ODgkI&2xw5=^4K8Stb4NEtd8Q`d>8hl)PDvFI-U^#{8 z#ftVTxTypBdMZ$9eZT)MI3K@9kyQdUr?-Y(_GucR5}Smdmf_(17|BdPNI1g=Y&R&r zDlv{P{rIdpuNpR7FYP8i>6BX@ZVM1A^35Aigyq{T$^Gu5cW5kyWYLc$0sTE}v>hrc zDc@nr8D}v%?~K=1xfC=QO)bq)Y$;0tJu*{ox54Kv+51D_{f?{BuX}PGy#4*58M>?A1joy zd>zgnMY=bMlqm_w`TYf+L@-NwtNrTd>`e;_N?19s*G)3Y5?_Hu)B_r@%)I6DN7yIn zeF9*fMi4z_Y?rgxii*$L)`cB@M;F!#wmp596ZL#9%jR$du}Efo5V^fq8-Gw0X|@Lc zMEpXwf4-$5U$w?y-Kn{v{Pivt(%gWzi6k~#rB5EIEDZ2W@tkB9hf&3Lcra%R0jI3+ z&Uo^CP>dxR+)QF`8%vT0@1!a0`CggFA5JX{`>`(_M=1u)m$vppRV7(=B>?Wsieeg< zHYTn5RZtq)GN>lc{Y8)agnht$<<|t|4~_Ao^xq3c1BA_R4z7|b`4#|POS7(PM~IJ! zVG7Q=bxY(qHk(NfxAJ*cbSj*T%?S85a2Dnki*BD`A3OSrGbz|?=$^_#KCMBYhJI5K z@Pxe+z~7!a2eo$355q`&g?;bvy}g0}Sy%^1n0c@r_WmfJpU7AONDc0%BuCiF&lSS_ zC~O+KKu3W9oSI@!f|JDp0x5X))W)%R(R0$1KEIctgckXXl%UKX%0xjxJLrO-t;ki6 zwwL-O=@gr#B4?@~fwy}c@Kwkl96O4Pd?dd)Ul0Z%zz2F6V*(|CS2CjTjv$m-G_HqwHrM5<9k zQA!!)Oyn1Z?HO+bWr{drv^6Q~gEN9FDpBk{=*Hle3CsCG&C1;%u{k8CfqfHi&#-v` z9S_Dq2$Cq=o<58sG*9lzoYeguT@78_ZO2{&LS&nS?T+&#YsKXAc6 zF-iJaSPW6ukvt+|IaF|gB0&BD;x<7;>NA4^V%;^+&^+rYR3oHEK_TiC;W_$L;jM(^ ziFf$;1@lL!;vCicw)!7w{8j$a!s1)JPB$OU*R?Yg@Hpy6bae;mABR}98Yp@LF9yeZ z<*`P6hatB}Uf2)C)Tu01s7~Vck9dU$Yhg$!BB_?MWUYsa9uO?R??lH8Q08BbK&&f> z1p|=;E3lf=w@}?JLz3viNXa+b9k2qLF%64w^H8Vrk&)0Pm9g^m_-`E-pY`4zGnQhJ zQ26BurG6(|1@APm6y&iX)9FP(02C1E)#JBpB7E0oV^L0ioJ#1Jh5^tGD6J9XtvOSr z$j!@4GSoAV^lA6w8POnKz`Mr$@uiatLUummN4?!S{1nRR%Oq)>T{O~ivW=M(KeJ4K z(p~%u6vdBtj=En=IFcG^ZL(=izk=##7|Jxb?>PzB|t&HxwpfB!%z&f%-hClxgtwg=hwIEVOgvIc>SxmwmV%UP-zE z%vo=GeQK)=zP|;JNz8q{a+PknjwDxLKz9LwX95>(1c4C>Q3l@UDy^?Q>YlmEU&)nD z(4_7YCH(WJJPm0rk}hZ~HD)Z@lvPljD3u5vXuSHm{PRmI~jZ;4G5w%lTCBn2*>z>$5$EG&@#%^{acJK|iI8Xf= z-q(+~V#MF*-(n8H_7U z%c8WD#<#a+KBp;*i=nW9h#O-FH`+fwLhUV{U+G_F5FRt>=?*#o7x0A=f_M5>6XD}Q z#Ck3LUVsoSx_2JBD7Kh5So+ospLBg|<Y)Ja@BNoE@IvJU{a z8>>B?Nplu#>{29`sP^FUsG&>^IY(&npm-_xg6o!5dHd`X2p=ujrfu6QT`?R7G%iC^ zJ*0c@7KXTTcD7z{x8iGg(&CtbmdX_oKC4l`YDbwnI>i{~+gTv(=Q&`-jSC2ZP8zja zAg4}nTTNE{6lvUT`%5st*yay@@65nS78gZmRyYw}q7vcWQYZg0v&*n9Opcm-;*R=T zkEYl@-jX@ttAG4?u^DhTznYs@{lh2rj*BpeL;M|jVQe3wtzUd0$&gFs+9LWTv{?Sl zZi;Kxwq=Wqv~MA7<*3T!qq{GO>mBdc=k_p08k;0`z!a}((8%Ra)u*wKSwrlV7jYIP z31Vb@;E`o`t5X>OZ|S zj_bx=2f&1Ao=soi(HL(e#Q+0^ZA@%2);COC#!U}rxkpOmS@F~#%b22z2Hn1kgxU1D z$$3(4=s^N-GdTzM&j2TirQpo?Kw!Z8bs0TMIjs4%`&ev?)RNZrM3#nPiAEpVz$5KB zaek6q_9C=Y`%By4&eNN(`E0}4I!<&+3X+68uO#NyZpS?W49^=%^fQ~N{US==7`D2m zlyp#3T^J=jpwdlrWIpUBqod}bPz{!r(L^Q91RpWyIb=6)o~3@A_wO=Ud66YdK?!qiM_4SuOQagPA|p%^6wA<12rCJsH{?yvX70*}oSB zS^pOCh=mg@C9nh8{-GWHDGGu$LMBcC_%Y`1ep>hsiGt2f7GE5hm6cWGl|)(pcvhm6 zVf~A!!uq#JN-P{eCJ+F8xL}78`~(eFmq6fG989cWSrqjD_yGKqs`S5mU;=`L(7!w| z=`KgDG+}sURUYg^j9z?$^n)NhpWvfmi9wU7L58vS`SMDJFc(+o%wtLF?EKTskO<#{ zHZ-~P{qYFB#K~hByl$uJD|)z+OzH-<{QlnA0M{KnOG4{l%hv6+jtOq ziQfRz*VBT+ws|MszRQ1r*)^Pi>^2gR4=FX@{}h^Oo`|?=#?fOWg3J@y#vZA?!SX&R zeJCX5QDlr0tu`%)apds&d#m}dmWj3Q`>D9R>73^imnVrq>bOQ~2Vzo6ts#pD^Vqb3 zx^rXs4x4oqoiq8OtvDW8Z+-7m+Sl3)fnXcBOUQoFgl&n(~RT|(xL z)5?E%vzxpLtpok)9%VyqFiBq3=22qCqooT(F?F0OMO3iLX7aCb>S{(uA$BkUC|fo zwOsrJ7b#QLNHM6~j#PayHLam8%}O0klS_r36(?hR zCPEl8WnsuLictw5H`=f^NEzhyuW*ZU^NAMZLp32Bi-vARZ*$@rzL&)iLQd8A9Zwkq zU5AW;U_IET@U;tWBAy4xP@ghmTP<{@#_s^(newi*LXE=Xdy&*bM|-G2%olM9+7!lI z{Kr@{0J9qX!W5SF!-nx(jFyGmXgH{@ib@n}25kvg=Ci|92l`+zy>SOC8_Fj)NoanL zEKA5}^Ak7VY-zkkwVG%HqlRE_9Z1Gv4r$HT@T#s}Y2bVqhl(yf zY$DD9mJBjD3Vr7^(Xk7m=8#(Yv>cQhZ41k@5h{{74=q;*|KROTC#YonC3a%Z!EZL_ z5u%mDxES{2TVH5)50a|RESBBzMpVpZ;QinfZmPH&HTuuJi~xipB{;#GR~wPo`sx~C z@D?1mZ|e`Z-5T&ilp8%5UQ-lwe(-!`G!m6iJ;YE*TFN_TatH%w2v=6-&!2nwVS9}a zIMEJimt9PyJXqf0r+8aJJXlkIfj|v`pOn+)HxM5xWWw7QT;eAs7p%c0qqVL(WN;0W zwu+5Z`eN4?A{r?;oxSRR-!b>zgRbjqd8tfNe7-Jt$#N;qqK;Di=SeT>LDMvtd)r@Iw)zMDVY+Jq4n%Q+ z(dSaoktR57~mKQ}3u-0W2kV2i6)9)7;M* zgy_iehV`1zX#yVoq*Vd&GbZE)Oq8EtgOGci-cSxn(+G0d58SJloW9gQ+LSqaF8M*f z-ZNNi>us{_8GZQUOB+0Ub}va5OxB*&(IU7T(5$5+b5kM9^yQ1D9F?Yi4a3q}6_d;k zqs7>T13(KtV!XLVYVZK zyMgr&tr#Y-GlSj|P`G23Z#D=T0MXZ0%^BA9juPoBI+5Y=J4O>y?@{R+g*DEY9JrSA zgN-`0txV6E(G@#{SGY_A5pu6(l;c1w@0FED(e?0LXk!C`IF$&$Z(@`lRY%WebnYT& zUcW_-6i0bheWh5 zi5`FvXYb!NE5aG_lKngOUAYsgvq4i^L%I&1o<{q2xW@9zO3-s%sxHs1NUsWUAHGW?oeZas&mJ-Jk=E z2*M&&sR>i^J}M!WR@BJkCd1d5Likg-z_6gFxV_*fyQQ>?_}|`~5^rk5Dt7EM3k+_4 zU-CI%C5}dD4Ah;v3vV1h8=|}rP#~3|6*UUO^R9x%#H`m@#cS^QqIATcp#pbQ`6ZW} zJNprJ&b^tHz|aJ@|0pwLiZm;D6B4g+at-z_{bbg%P?nya2vjvpbxg*iw8Za|p7@q0+nCztLizM|KJH8#sF@!9 zY~94E{Eg|&jqBB!*@ux;3Q&@f++LFWo`*_k;jpl>ACPS&PW1k#q^NqgQWE1?1eZdh{rJogQiGvNCiBNTiWKH(@_R5L4^}}fCY(V291t49&Abe#_ z^0MpF7bkkCI)u{|$=bbXj&Fzc>uZ;aE*r95^9{>32R=ZNf!v(jO5z47G8Q2HFiJ-! z9}z}7Kjo$@e<4w>&KTE3l_k&4TkNXsQv=T(j5^9*1Va3B6e@VyY?5)TNNG6e?r#bz zC4u38%xHSL+Z{$b zEuv2N9}SNcQ5d0zS=1u2VcmKMPcVy*k)BlMG?nhTV|Zao`474w$K821)sBAlvX}f& ztz+6-`5_?~{8cndE|LD~E1C~OXn?!Wq=h$mJAzji0&W|R-JJhVn6c3z_%QCN?lQZG z^TErb5m^2AQS#0~zdM@%YgV4K-y{sHM^c&a&s#X{--v``g4}RJ(cbYrNHKj=|G3ap zA_W=W7{+Oe!i~GB#&&SitDnvC4hH@*P>v#+H!U;p9u7jX9QkFOTDmaAEz3Een#n=> zHWjqhOYN0Hw6%o#Rq7p|r_}6Y3nmkj3?JetB|Y1;L!JQ@w4Uj%ZKe=GOw?J%R0|V? zHygBQJSSIY107Bk6*owCG%&IL0U)D-?pr}c4j=hE2rC4Mr34?z1rmOnNPh@R2D(qG zrVU|Y^XjfCZ5t-tlcoknmr@A?g{mcT&xz}x>{^Y){Msi|%84f3Hlii}jf30FDoUn{ zRZlr7OnaLw-MVJOpM9Ov?kccvg=s|O*;%zmrYo%>XP(P;+^OCX(pCV>60Skk71|?3 zaSY0Z8j_!g7*w}2I8IyZxj0jTyY?B9T#~&+iD3}B&O}vwfA)#R=R#A%jYaiiBBA&5P1ml8;A8qKEBs2fAJ>jX(4xv&WqA>9 zX-3UXtNNMAxewHYefBga60;F1i$Dba9%U}*!y((Pfy6u>c~yQG3_ zY?eRjLsNxk-jgluQZF+H{re*a-ES}#-`Xk5;-*l$m3c@x zGs~{H7)WE|lF-Br3%a2*8=iy1i4`Q%U}A{!;19-X{o+iNEBvXKy5rb*`q%>xEFH^Z&;$UG5E&}4!$Q`1&@W z{)~$@Byy*mxyTRS`uQ`lVls(i3?2)~ESX}3DJr$lgJWf4R?Y7g*PWTK@0~jDSdC?J z+|G|;sPnI-LGsJpDWGQy_cKTD`DnVQZwiY0=|*0c$N7r^xjKpYvg_ppSr5ui+y0d^ zd%N)cKU>cTanBca%6dEx%b&e2!;r7lTh{R^-5T*rtTdu_7|ex}kqaNDJEwnoEUm~d z-)auaPh^sruz9>pb2|}vtqZ5MyI7F;xYFAnw@V*CWL7tmQH<%O1JR(r$EenS%upbOGjZm;hj$5cE$% zB0G?i2@Dsq{MXWjf8sfRfH?mU5rJHPJ^H@|x?l%GUqJ9#{u9gsQ;)3RQ2>Gwt^W(i z#eYad{XZQ0KM@!I=nnZ$p_Tx4FqQ@;@&4el{-kZdlpGTnLS*?n;ln?v(tnY*p_E|( z0{?pU{}!^Am5T+8rg3nxkh6keM0NnjA6O!Q4UDFNIR17l@oygkwtpSCWnt(1gFt0v z{ewPZ0bl3XSvkqsz_Xu)9jvO8vw}5tb`X&DKZ5C*SlBr-nK+r7IG8wFGub+rF^ftn zC^LiKW@G`e|K%itanOI282;nDf!I0!`2Sfrz%BsmA8a&u26J$-13+MW3cv*BYXSck zuGnm*T*gLVZp;M4Y0AnDCTdMtxY)q;WMpd00p7mZ&~BJ zp3kJ1OB{{}zjd|p z&4ci$Hk2n%c;)4_vPeJk_3NBaO)IhL#nb=*Sl|F?9o4TNFN>4jR^!2mcM&!k&`6A& z={S*5>LwtH(Rt$V3!7~zkJs^xGEDk)uJmGK;9f(oL1g7$_R)2To<#aICPGKTBWO|S z`<2#W?rKE(xST~+ZCR(inx@(69J5YUJsCAxc|x&aXftpqw5+q349B9V%v^P?Fg=jh z!C&TpT-W96XO#*yl~4p>bs4)6^Zjz$gK+r~9!k>YGUc51+T_?^II-ta2$`YaT@4+F z*2{J1Zq3b890fe1h8!gAUZi5(QnIuyP!*3APEDqCZn@NuB^fh+C@L12qZ$?V@fr7P zo!NbLEZ8~VZ&z);pnvyPu$ru&Ic8F+$fv4CrS78t&4X|xy@rnK{OW9!-_?7bJE8NW zerlsMeaUt*wgB%O6u!G%Tcp*U|)kef=)oHomH; z98VCeG+-<`H!V==NC>Jokt{ouD3@v$^885 zOflH2V!;ui?bJ$_R*pD@W zT{3wH)Yx!?v){QQ$UpUZADRcjlQg3V4SOL-Ba6>tlQr@)s&K9HwUq7MTXCr&6$EZV z{lGJvZnZgzT;v(9cWZ%8 zo8h0-nz*^OJ=0Sg1XEAaUDzl}Jj%;jgC&#YCwRgUCjw)q8{u<6!u09kwP<_575g^? zdbf<*U1V==pJKMSa)L#NOY7VaT3R}JpwD8Kttg1a6tF|`yZvACN4ld((#kmJs zcW2)pvNK1<5m&swsD-zE)>#Owe%LXUnESJp{V+(ZB7dPBLuSXd!YqcJ#RK_#+ZLT@ zq1kw-uHLX?>GU;VVf$3Vs-_X%aLwu8q>jBc+i#Ve=8tY(Q$ZXQ)Z%xX8Eadt;`Gr> zyw3b{ryMSt{Z5=t^9X?lx2;uliKkWyuT`zoRG=nP4-fTuT^F9*TII7F=%*>pmU&LP zAgPgbnfN05h(70-Z^*B-LB4d={Dd&;YApR^>J^?{C+m%gC?+_)-C$zRDDeT_z?+Cf zH3OdtBU(a#%M&|A+7_cBSj`%AmVsMJJ|s564g-_k+5TXHs|ZNmR{>C%yl`w^kVZA{ zM;?MfPFtssdAJk))Xg3-7?P;62+?SY)b?S`R%@j68Nj@Ic+Xa5ff0kKV z2#k#`jp|F8_k={ROeHUFoNgVythQ(UsY?BR-S#M|kyF(XyTrfw#6!)!`Z;ve5p!|P zE3jP6hJS6FuYi-s7mEb6qrXDwh;#cn^#|F6Ip=zj{-}9&+nvDULBbnqDsqB&l>0@D zx4hGS?DO)VO^!{ogDrs0kOyYKFV8pth~TLj7F z29gI6`J_{s&XoBPEv~xOk}JYl>xG^h>OtMmhlv}JMCu%NeztZLM}9sv4T3RH{MWl$ zio&IYdUk1~sUKncbXlAm)>up&yjm%im5BXt%H~kr3s-&McOHF7Dj97M7Dig7sW*dK zv)uX}sfgDN)-$?7=aVYoJS_9P8ZB{Bvr9t=Xe4d5BvTwlmMNaiUa;NE%o<0|k!NR0 zTk@Y1guc0EHbz?}KX0g1^#&iS)%^~upKW?*u(9qOv*NqN%$gk5^cxc`!>D{0>amRR zF2o}cTEBX;+mxiY+spa;E$J_))>Y?MIYFi)fDYm=Ye%%3vYO5KkWt!6ZJr5oW;3r+ zgCKYt_$iKqkZ+t$$4jRDLA=|Ne1-w=ls~O-N=p`F90F%Ttn$}MJ1C}UqEv2>O>CP^ zn4;V^F*jQuuMT4zNg@H&?Ue8OR(BtSqNa=wyX=I?f0N`?vnQ-n;{+Wk^XqhX9Q`sc zR~mcVM7Ftv<z8_z$JkuZv)-Ll-0}*>+zkOr~sj4f2Ar>VU3{G zQ`I|*wqB^FI}|~84euNcX0rihc>c#P_7gN18-d-~33x6^r0$Y@X$uM11H_=Jxp#0L zCIR{D4AGadwKq5%H@L(H4d{6FFsZO4j(~;$x%}>~Xo72Pu8%s=_38RmZhczsTC14o z6LhrDE&AY(u42Af9@qWsy*;0-aSZ8yfDh#bpbulF1xiaE#xd}d4VkW^FOK0J0Idf0 zpNGU*z@fpOJSQG-JY4$vUk1=P;l}rHkVDAqw!IO_ZEt9EO;4IeSb8v zcgx#PL6c=zo0lm@l}bW60M9N71r4I-6OD~7940D~kvc|-4~Ri40&!b4RL6C9CCwJ1~1(FS*JreHI?3E_HW8aj&$y zr-9@H{#-FBJOy9iE^xiD$5i$W7jSKmPmF(cpCT~ueQ1avUjByonLTCGjz2%Mhyrag zmB(*l1yFi8o>DI%cj_Eoq3r^aRhScDDA`ooi{AQ`^D~gox2f?U|8_Ka(N2`GGiE=m zwj#0Ua>EL1D-zK^uxS8r@fGb-P(GOhHS8(v8nOCjDm3MIXUX6xXFXpdvU=evqCePE zBj&u-W%OMKd_zxAFonJ6mWTI?Qv72}I`1yAE!<5j-2?j<(`Leh?)84+nT?22>DI9c z%r$$OAW{+JmHJ&SP8j_{+Xp~r{E-sxVJc~=cb$7iG0ur*2~#_`kVbOl*SkF|D-Phvj^GG+~M zmf&~}VGA#XmuT^c1&hSfpQ5bxkNCLXcOM*iqs29?X0O=AN>;G-i!<@Zl=#UJlNw_- zt^^^ETnY2E1<~+x2s2pIg%+Q=(?9VxW|LZsgQNNPJi0!C@6#^pWW{5u^#uupclw@! z*!A?CR$-QYC*mJ`Lmsw}yH8#=Cj#1qPCxQ{bz3p+(vti#KVAXvXPe?056SrM4VSU1;Wm8!eRv05`oV!e5` zde(c(+m^jFLqo%4S0RH6&AJ3oY^1b-^6&%3I}mUr6sVnY530%TPrszxjMCGkGyoeN zuvJ28028&VwAGWX*)|I3fI!<7*)HM%0%xpu?A-?u;(+1xf(oQ8)CBp$I&l;d5%(~I zG0^6rJQa@QHaR&XA-uRplm=8xjhi3sF3}_7n9d#rdTa0F!fDd(mfuK0-vXAV=DQ85 zK`1PvzL9l*fkDMK`8V@}@l)P}^8|;F`YTt@fxr74nhxX#vlGc4?iqauqe!D*q9K_F zu5rBk@He#YkQ?8cgSrX(6p#=;v$PZQLBgR^^2$^gXtO=}7$8PvzWtyg9>je&dP#*J zyQw+B*kidc$vE&Vv7I)&>(TM@YVmQvD8&DHlQe4Hy>gACNLC#xc<`I^t(ylqOh=kgA{MC<2NH-uKR-J>ndYhnqA8O$? zZ1B&V4k4>MA}t29qOg)tPe+FP?(C$c`Q)?Mn}34UeymH*r2m))^`1knFgB(Yr3A^N z{^3}vOvLMM+Yfr`4Z52EhwI-<>}-EaUnp2@1=FfP5Z6Bm&m3S$5(rkL|09Ca-{02$ z4}w)#NmNiplJuv#ABRyZ5i>@?SR+{-+8F1pn7S5DOOzIS|Of#0l=?2fyO{!#4tO z{+){Qp9jRj!Tb;Z$dQ@d*bv0Y&IaHDH@O?LvYP^pxBw=c97deRe+apzoF*)vIk?!_ z4gY%N|GJI931nhrWdXPMgM$k|VAYj_6Zntm3=WC_CpUn5n}KW~j{n+X{+})Wtbl*a zX3oC?>EN`9e^rP6Bc=n$%ESs}0fJ>`@Kp>vqk(^hIdF0T*#7qJ<^PbE^nW~l;Jl(O^8(bXV=57uyuq*Lj+L`e0E8*Xbz&|+@|4C=@f0n`@sUIK!>z~OF|DzPZL&C}q zz7qexHV_>DrWF3EN8>*^5a83!3LXpq*g^ZJO86uA1H8;(`>$=%`CnARza4;oeUbN1 zl>ojGfPJ_>lO6thC9ra`f^Yv^e}A;Yzj{&N{Oei|__wU}SiylG-~b#>aHhlmxG4M) z_yJ-8$0Gc{HW&Ww2>k17J=Q=UJDGNI|>H|Da0Vbv(qrWVXfd8~O z{NFjY;HB5Ub!=@ua5)5>-(ufF?Ol07;3C%n^V%C$Z4Er|0K9mu-@LoVxJ^s1MvaZD zrIcD*AZ6tX+_Zu`A0T2STv^~u)D+@*Kj`}z3nBHH`) zWmn$YxwZ4{eDs3vdlMUX-zxvx@vbfN+fz=Uu`4xKV!5=9xzw(KOEOvgIGQ|DltsGjykv){dr^1W z-vHiiLlUc+4qrW>GgCzTOxZ_ehvDALTd<8AoKq1e{k-b+W&3u2G;8fxyu;!1OS}vJ z+nphkcsJm*`E04?`EhXcVvO#4+%?nrx7Yo%pIXZg$*Vu#zOiTpo>-TD%#XJ9TkS0Q z4ekY^PS<}BVZOQyL>xG1v6pAATkgD&qES9d;_IwBpTx$B7U=bG!E-Rhcb=T=vZi-)w1PorA-sqLYY8~%*M7G1V$>4q>T(+TI z^x)@0vN@OzGAun+xt7;(7v*0+B{T^vXWYwctnvS9@{& zkq)*|*d_z_7v9~(KSiIu#oWdpY?vIZbr=Q7Hd!=$J zvfA4??X|{AqK<^tFfIlQQF5GN1YbUsQ7@SlY?mq{ERJ9vbC=7!<4(x5)D+4O_#K>v z(aw1`lpW_XwRaI~gg5y+(e%cSiopt}Je-T;SmT!$=TU*2Nd|o7R;Qt~_iyHWZFb?)kw>^g48AuS%er0pp6Gs?)2v7^7* zBtKd3nA*joTR(o==F0cI#xo>}_ry16?g>oHlzH+(jCQY#E937K=XD8BBR6BgG#Qh6 zX`rm^)aa_Q6F-G@KSZ5RwKiB_V9~y+%X1T_i-PtHgzV{hww{UV3T;Nc_rY(&)g1*lH%4(cEa(v)h75jVlbd6}^;-i%0;F#sYgbW>qc}_hBuNg)#oL`~o_B{Z zm$=4u@<$(1Iq{K`c0r~<1#qZ*SS0i^S%+UBQj>Q-t0lRwZD8AG8u*=j!PiA)K2c$1 zXq)v;d2FZ{XQnzF(0C6?>KY6n%GVtwl#L0S?T=(ZgjGY>bQA|jqRf})k+EytWQ*fBO=9qD)`eB?u!gTE#()0hY^*U$G$0;~=#nvd;J+OJtwl0e zch8C!rVIa(8N<-88qw8nrNUnT6PjUno;qOOa9>NDjcbW*XX+~nqdM>D>PJWODnTTr z{Euezm*h7L-EFwz=9ZvXZ7ohWrLQO3-3!v+ZUT@DjYK$<$- zFEVWGH4}p^>}U>)R4YEoEfOy~7D1G8qkY8=-(u(W4%|n~d`s~r{cTMAq0@hO1g+Id zH|m%}!#zTu=Qt3wWIR}X9y~Gbw%Jcur<3lC!kR3eH3|!AZN`PZbWm-15y;M)Q~aX5 zME;I&l2=NXws=9-UbP`jwiTJ_q^(`+^ zqS#4V@LplmuDCP}lv?JSs5FG#^M{#(0%|>I&8%sg%+Q+VTkw~ z%7@~lUJrvQQ_e9>-rXvVLqUixT#4&pH=5|+K4!>4L$F@+^*hb!%B6qH)6`KAx?CHh zOrz%^DF@e4|C9%^wiaR2z*?62hYZ5!K+Db zm5bfIz@P1Lc1{MWHkQqZo$292&)hH>(q9W-9^by-1*hIYYNvO0;ay=g44+8Se}LBy zsbvP#-nUNlEJG-Nj0uP_L>#;E9kLWgpDWdwd&Vj!^$GU=k>SDTh9mW9*4Fi^{1MAb zhCVHwNWyxE;Ud(xF>({Kk!t;`$VTf5Q|%_<=6pOhAg>lDfphs9li|p8i&FQ@1#|hh z&!z}fnmRJUXd<5M=B4M217=n7)Qw0DaY}$+y%7JLayAY+Hp)_987G#yRh2_NefCQr zHCK+fQ*Q4LhL;;wHq+X7`8d4R~T=fc275Z09?&1-q+iu&!zI?gWLL7A|Xi9;`X zk-ip=dMNU+6ajjKDUTUxZBj&5`n^*z({0t(cgG=@DXRQwNp5{ zPf%WIaN^}NysP9<2=;T7*6bBEhQw9IlPxJ)|r>NoQG56b-x*4>LpVCzoZGtTq|;MaD9?k$qZ*j+Ai}4jie+<_bOJ?=9a6i1$tfedrjo8KJ42C=zeNr zdQCz56hUVEsGzs%VSQ3!rnnm?p8Fd>XG$w)8y=n45*W+`Z&KrUd(U^aK>wm^0ux^` zQmE_gP%LjsZ-PapD1NQ`OfhD(pN9+Yp!vq7N$M9?lF*9ah!Yv*u`1H??5_GPD{CY$ zk|NOug{8P8sxLK|*&RE%Kd4$W&^)6oyzGw8O5SkWX-tRgM%<9icIEsbvX?``EQcLi z9=W_-zAyxTW=SLQgj@a?W#mWKAY+D^C$}{hJ06GgNT~){%hIG=@6$n)F&5z>!hD-r z+}6BGFL!q7@8tk-bFn|kNTLXCPVgU+dkqPH%4CjD~%6fk1?6KeW8r$P8c>#f?<5Uc?R+Wvu0hiIIjQ}Ltt$w&H{`vfPIi6I}I zib*ynx)SwUK5gnMi6uA5qpv_Ia#PSfc1H-wq-RPJ6U;f$Jr+L5xRWvrKz__y?2I_G z^W%QmDWWde`LSN-@ue5D2tLmc;c ?uKH_LBG3w}|gz7C!T-OPS2=2wL82qXf;9 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

%X-{jq)zF)pGEGKPHkt7x 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

@!c9KnY4NvNgEvnPA? zEnW8}O_$7LB`;^PA`L0B4Tag<9NCgWLjJ7mcu$C|_^Lz#{L4i?yOOK-c3TZ`u8ish zF3HR2hdukfIo_DuZ`>IB|8XOu=lP^!V`qBcUT!*h+4R0>JYO;Xp7W)?w4S=;M&5o} zh>~@>Krs$p{O?;NPu^J8)%hr{r?8;*5a$7VXiz|9$cE-btx}me&Li2v(Q!dEUGx)| zkNIecs1N)-jHHtQyN9iL#?#*3XGC;Q4Q>2w+DtVse=Au{S-;C}Q=&&F)2Bt+@bGuS6M_2=y5WJ|{1OMG zGS4?oR>#FMxP#)oww6Fz#)S!2dIt6iqA*F98Vv%^SDyVguzI@r{s@#BKZFjB(K!b6 z#@||;eKBG_R|ovb!1#88Qxv<+o;d76VqX`_kLiSEYHa5ZHnB(fNI_s?nUefFkQL5R z;1fbf~ne*$M9g-sqA|+2CrVjcAKD8^Ib< z$`eDQ?83q!1Z)L?C<;XyO8xAU!KKrv6KhnGHPtRlsxTerl3r4lLA;;1YdGekUC*k^ z#=GNVuVZV+{cOH|ea~57R(V9ekSJ@rZ2|?e70QdCmJR`xP1ZLuaVjV!PT)c*&HVr> zd3taA0~vRvY?yfon;{@nuq)@;o-fx*%^u;!b)9D{%@^5KMXHYdd%iZ&FD9R(UZ)j+ zOF>IWZ~ffPh}nK!_;qdu$AD@(tlQS^qX4aE+EUDNuj54@9&GEro5w_aJFAQ6t`CWs zhD}*xEUg0HKgjfESkSVb@+NUly zFv2ZAqN^gGE`6ZwxUR8bZ<53VkR{)E5j^MIGwa+%se6ry+gOl-ejh@0sUl6QldAf* zn3!CG|3)NUB)+)L1yNka0B0aJMlH4cko|Z#IXOFfyk-5;%g+7Sg>(?l7 zZ_+4LRQbfTK})x1mErN7;|G^xpQOos&U{qgWKh^_`S}!0J=+it(|$Woqp`F-8uv1cX*rnoyMNzYlBIq}rgEHZVG@Z=n)bXlqzJ^I)UPX# z0Y$nWZxlAI09P6GRZn+bsd!@^j?mehD%P^YU8E)a%;*6#s2HD zLjwU0Nl-e0rlLh=C7MpI5*JE|-{EUrVLV{- zf97At^Guzh=)^2e<{8BaYIyFMk@ABiC?8r-o3j1ovx_lq?ybsb?eL*VipOaK*mTO& z1rRU6!q~yQ?T5VDx=bfz5{s;#6!L~Y`;8_1DL~Yt@Ir{(huZ7QNcB-Da?&v;Ik=qg zT3K>uG{jA0!J#XYS*HJC41y)9`%?wLU@+%F2Pf+0mFzW{d6FYgAX+_^cO)eNyGbbz zYx*7VSMZ-gd!V4M?r?V7uQFRw1@+%IFklcfu9RF9oK==o3`A-gwa}6)8KOXMiBP)>ew@&tXhq7;<$1nb(GC# zo@2q*+%&DDxeLcuafo8p47cdk2|}#?1;pjLf?qJdem#aakhIS5czw*H_uuwW{~qhg zCIQCj=|*FAyVI$!(DOtIi(7Dm!7h<8O{TBe$eH@gHG`J2Phi9^7e!K8Wh_?G`L*h~ znq%Ksr@NG=WG-x8;@u#uOqJ<$NJZ0GBDnT;J3cxfO2|O9ait-<(l0i{t*TwRS}ZcG zFqH<9U_>6RTXJ{$MCRjzJAzOsj822Yxc);3ZNtl9aktD^z-$k;G1G#(BEezi+Wesf znftpA>%p?Zs=_LI_-uXJmA<7tngW>JU6L@!vwdi}k^+ z=eEQ0eRaioN>jTg^=Z4!K`C9=-0Iq}2e&P4>+Y{FDcSs)QDgq5GdUl*TOi-t#NCP# zFi2pN(25_(+Y)Ce@X|S&KpT8fo%L4s&noLi*&7vN2RgkKIjd5s`%rel0v5I|!oGha z3xaW;5o#kN62!EOaurhrvjT~OU1i;_sUyO>bn%^$@R!Q7Px43vq>O;IIn4Erp7y`w ze27B2rp*q7ssmeLns9v3*j8SR1(&W{kUE$>rqqqK98ksFw_Cg0TMM$pKD5MYY&9*K zu{Og-p9Rb|=`m>;MvRTC){9Xye$<~Y#r#H_kNw+i;0Bt+aA8hny!v?ib>v?4m|@7b zf1w5Q^+U$)*u=hOLR)rbveve_cFxLHT&*5 zI(Gm0x_g;!B@IcG`9Sdr{9=9na!7bBqL?Q}S_NrkE2-XNMdAT;2xLRpU~RiI?OrPR zjvq-)mtFsE67}%n52NgN^!MLQ=m?RrW3Fj3%D;IMdbwD7ok+LqYJa)nHSQD3yK0GF zCsF^D!D>e^*Ci@!c_!+ta)OtLdpAlaEGV2=_=g!?GKlglb~;wKnLcu8I*BCTDW1m5 znx1rwHeG_OS(Wx=2$5LdymlcI)C8Wf9Q{)uduFH8<1vCft=s#PS(-6jTTkx?Uda+@ zLLKC^@W9Pp6q4EN%Vijp~&>P)rczzi(fs`_R<|4)lOX2@pFN zCd})a))vx@Qp8fUmz;JrYZOq>K<{3YA|3KO;M7^tmq)?Gc`P zA?~bLJDE=#LuDswmNc7iEO^%{D^v>%EFM)0<|>p~)fT9e4Hdk!&n$5~TMC!jMRXV} zr{)i`RHI}Ofj+GFPX9%dqLzm}TM&_A0a4QdG#7NnufK)Lug5Tn4SFVsL*Djv>h{0d z2;|#Nj_BhKWU*xzrMu(cU&uUYrlqlFlrrKK5v<)3VdtZh919T=r7|Y|mHu^y8Pp+{ zHZqbhM3WXJK!LGC{q);R^|Jp4kl_`N?Z}8AvC^OMYQK2Fg|PDLkOS`EA<(7&#lun; zEQ^0fbGuXqiF!a=P|?8$5F6Ld1|iDlEk#wW#uTsqD3J}cDMBKgR9;wLCUSNsE$L~x z=2|(2!TI-;yFHeAUFq{=blJ3`>6HzdXz?nU{yW|42t5!A5pPj0n%iw_ecb~iCd_(H?d(#)3+&WTMlLQL05 zWqp<-cA1l;PP=?1FvI>OXfZQ~7~^nlN8^3(?BKowt%cMn;aKL9$73ML?{vH4_^^7J zr=HXU*^uH*s~8N3da!Of-lXB^xH1-6Piid(U z?^Jc9Xs|Li09z89)XHZDWEd(6d6q%rax`*7Dugm#_}R>O8pB0{6U*!zb02KL7UgwZ*_h?p;KDL!Mk{slBoEd&MBy9_h zN$?WZ;vGTCHwAC?rM}^)QaXTXJJw8_-jQvlYi=O4GBA!k-#v5ZfVTXqKA>I)veF*2aQz65@2zcj`mgGID_S27OFwiaoe_!-X7poXHe zV4w1aw`n1_cj-zfJ={7EU~N}pt&Ba%sE*gzE;o(=NYftc2>p1xFd}*)K!};3e79rn zCnS}+sR^I#L9;fU?!oa>r{t*r5_gaCT6~#huFYurLSB=w3G7UA${x}zVI#&8z?I(9 zF7MqcM>>yH%sg+?I$!4;x zwaZDWd=rcH0yK4pbS0QmqR;!mPWYD=!q zve68=2W+PAl1)8St4s=D3F_Lz5dY@vQf$)cdq%dN>seAc>g`s22>^SqRg;^pMB0AN z2>AP1xs)c(s`dI$Z?F-FrR;AowznK&T=b}&FJ12)Z?sF$@~8Sv@(|Wd0FWq?LxEw= zaKD{^nT?}y$_~-fQeHT2n_v=d-8Q5vCu>CaUaL&w?EA6}FYuN&Gvq_HKdN_7$tCbm z)?F+2fe(9Y8+PyyLLehX?rFY5@V=pqaCA;zV_YvV(E`Z(Yo@n?7#Q_xVKOPe5br{BmHN~O;I8d z-)(m_=UAXe;g?E#E9-D|_`Bdbg%Prj!c(msuJ%<_V~XFCYa(21y^pskoC_{q>Opsw zXHFwD`;opp-Vz{l27%8b+Me-l*f}Zq3|1V?qoT3V$)$MCA?2?nTD`>p_gLvnSRR|> zbLV@SHAybVI%fVH`Y@IPchWMn`tMIOZqIC8a+2~Yu|p>5&06}y+-q|N6WKgn;|RME z97~SoA0Ks_zAWG7N#@5t4ZN4hV|a${*)?TpneZ8a-nGJ`9y zjtj7kF<8JFXj!hu3xMDqw|#l7LYMZwiot+n!*jST^$7jSi^G|5?ORw+3~%M*Ah*XR zK7HbcWLaL-Fo|6K74aFI4dGx>A1j_g;-{dl|!IOV3 zu;)D2W2z;}s=Fho3Fox~M$Dk8%lWs=jNA|;0w{(qu*GyVL#lohQr%^jPgow===5kX z4~Rb7I@Efu6Ggq)G8eAN$X9k@OQ`i@r^NSLY9@*AS(U15m-NC}TNi!|O-0Q;cKk8!r;{2Li_1KbLtF_mWVxCfxavFBW}G zqr3X>f_YR#(;ToF+eO1pt>w(rin6HQ&hAGZL{=Je;$zHaXD*ZgCRtAo91={f+@O#} zt(TA;qGx>=??{eSEW+Iem(V!1=Z9FursG%Y=LU@P_%s3#QXbuSUtFun31wTu5N)hukP19VFTO2p@MW7wQRZBPYDOIcEMO*qd@( zow(ClE%y+B4sh?W)n~9V+1EI2Ykb6*-lJuMF~_SBs2_LGhgb1@1y1>&Ud4Q_zAq7_ zQwNt0T)x%#V^0mt0;utXg`WmhQA(``r%3ybcYmXlUKsALj-Ki}y11z zQa{g0$geAf?1g$1 z^b7ec?shR=W|4wJqDh>l?eKx}2JCJ&`Ubbr!K(!UBHQCias&THiMT}5y*u`)7!7n| zDxS_jXDzZhH^?Y)&$~hCK<-oW@Q|sNhV4rkzcmuz_v7kb$uCGRfMXWuGt37IB!296 z;lBghg*Y@l?C8_ZS?OK7Ir_(QGW_xgTP3#c6Y6{HeS96;U}BlFG26hf2_k?84B@nj znQj1!@w55^*!iZ4Z299QyXJ3K+*0=LYUcayz0M&!m}RC#zFGe-IpdDFs-P)l>1}N> zmMHU@LusVGT0Ayvt|W1}Mw7?t6ZZUL!e{10DMS}8N_Vd-K3%KIs2`&;Simmd7M6148Y)mgvJGqFbt1b^5jlx_G`BV|kTL>>O7MQ)RKwcDY` zW*G$0@yLzDC2}=9lMHfC_?8Qf~EV_(8w4f6I5{Hd@{&6+c+%o|8i2u>3LSjgWq#556oOMLN z>H`Q-UyTs8grcKB$!Hq$ajU#GVr2@Xa~ zi!LQSk;hZl@DG@+Rz$;=ro)%+qYC0;{R@f#-a-^ZMEnCi1cDtU3p%4#20}2<7DkDs zKvX2qy6*+O>7o0b55RYQc^N!U>zSyR<2CKoEsz87(|4_3c?&7L=D^FZ?sn>;ngeVj zkIwzwTF-ODy&%;QZ~v*MjrY)R7n>w-2h_Fx(F_9AMVflK;|A(463{Z5SiY(rOeHeC zymDB$AFgqA*JDH5%GeMj z=60>aIBq;i$%Yyh;5QbV&+(YDTLhn!LSQxEz( zL;CR+oNKhxNW#NVd!t)XFp5n-aEwv(dF_{CAz(bKC{5zap+V2cW#%Jib5CdsXkJqt zyN5W=qj;PRJ{=dMwCA1N2RpPjil058vj^{KH7i|JzbLe3UQy;2S;j$a{ueo_BHdTB z;F%}R1pm*qSK=W**m==A08PxRu7!tTZiSJG^_(M>smd_dFN6Sv$_(FSyJ-8@-J`cI z*oDAHhI3JRN0VulsA5f=TlO@v%n>5So>q=m+ZoOBR0_hgxD02){kpK_$Cl#hc7*RM zP4^Y=Q+0|DT@u+>#}Au)2#w~RZFjb`9OQ+r0LDe zH9}5@4!1H?W%`m|ZRo#CU&oxcTsIy}NtX1$5e|N)cP~9(4LpTDHh(y7TvxkaoU-8` zJ$6jbEp99c9`?(EV zs3M~_TqoTQ1G?v_RI#H4v(`*Mbb_vN>4gJwPU6H0HC+PV?EONhdgkqj*)b&4+Ga6H+i`)|57qrEC}!#&2%YEh#X8eeav!s0q9nsRml=6a3sw55?cDN! zThqxXO#EXHl@lh`#PAgX6Pb)jcXIQOhn$}?I<)(_q^_~af(HES=Rz7edeoT#3~6G& z^;F8wnXUZdH>kn-b0>y;BjIl->cmt|j-NFER)xRnUYS&A-zq?j;kGiS@IV9jL8F`8lSEyAjBp_!~XRfohBO4P5`^b zu6qkT)eb-)TA|J^_E>s!iFJ>7np&k4O%UDWVwO4gc>J;GY~}P|rlxw$XjVvB5Q@s@ z(XJDionAQSVdo@9_|H}V8U;VwimC%6x}LFF6t{fK@Y2Y0S^4~EJ*xVu-?d1u!P(k- z1_k&0%!JD|qX`VfXDfT^irwZYEgfL$a)#@Iu!P;fDEVZrVpIcP`ijU=N%LXaXd~l!Z8!(P?GB5SU4EL=_G#qC zBI=D|976+i`4M{+F_g{Sq2z{9FZ+#%;szjTT6cu)pbtM90#>rrGzGnglJpJ|14c+N1~eUVRPv*|7N zwoxr~2xdJ{?M&oSuuV(N8GV6z_m9j)ei1i<%&sU-5KR=Tzl-<{>zXcmq+Ja0$0OKn zz=}-F?r5(XJ~p4NZWzrI4!`0bNP5@2liiyqGA|))i&L?@nWQv+ufhaepFkYfZgvS) zFQ)D31~d!#mFhCO2^Nle!Qn0>x|BJ!m~35BYn;g#X8&f3Un>C{1flcmU1VtSb%=X9 z+KwUwwmi7V%E#C(YE|33$c=+8iO@5^`Vj;2bLt=G1U6k(nNk=G5D#pUG^Q2XdTmmO zrYlaeQSR&lwO;ii=z`Am!6s89Wqfe~hgRc(=kdPS=TfNf4&C*Y5p&mNmKKgV3FNE} zsFy=WF&W%U{;Wk`wr`e>6&A6Mhzw+yB6}&Tz#luQ3U&gpK~IVl`^}Rrh0?xa*uWk| zrCC}wLFCG?r&l%6cf}EtRt^!*x)MGEN-v+mZbD_TF3?KV#`p&VvleN!%>zX%b;3(0 zsDP#~+4LhlBFvY|lRyqGsOwRCAe_f4AyHre_x>v4T!S;$$wu{BCT{lrCL5<%0ZExn z6j|i1Ce@gqplCyA|7YAF_r{OR4CDQH`(m=9GaIkUQFpi2r)unM+?WKi%>$e;ABD=M zh%&8zZm~dAnW!ydA4B{SyHeH)^iv=6UJf+*lI`t1&*=qIJ}p%^MYi?552c-^xguGQ z#+kB2Sgq%`7abhBAgH_)SB{&QHfaeTj4GA-`S&C{p35z|RCnP$*e^W?&x}tz!_&r= zKCnBIAzVQ&lZdSA>Xr6eUAI(3^6}q8WreYKEQOf2)tNIJ^5?3~xvn`$UlCk(U~+OS zC4@BT9&V{uV`~A2ohH-HYWKOgWunzY)fY(L{F{Z(y_O&62N4tsgDqXEHC6Ur_AP*0 zNPL>)I;0Vf>15aswcwVBhS00njYMK^rKUI0j}NM7WcIJ7S=-Dr#TGPRO*ed%`NoRd zJXTc=H(?Kls!uLZpnu|$qx?K#z^mB-S1yqt1O*;*3z94FkzX%%fJG$SzDh*-E86sd>K$-O)WPj#?!-!n~+l++utX zy`<-Htx(}DF7(yZ;?iZ=L~ofNfX-pqwd_gl7P2jJ$s_Z5-1&&%H&XQJ$L=YANFZR= zRZ3sH?I6uXa6q_5xOzb~q8%t#k&^N~4Iu zef>)P@_T#$R&2v@*C(7r)0-bu7@p)r~W8ItGuJsEiYBa^}bv0 zv;X-r;nO--1K0KHwLEf>j{jU+Sa@uy?T@?41?+Vsw$Wj{1uYBgwuy~bN1Tt7JzBwZ-tYa3lgF5-vtXe<+0MHKx6 zGu_0y;mu(kRv^q8UVenI=kh8-RX+ViN7(97^SCgkLx(o1b;xnv1pZ(>;nc6m{(yY9 zwrir;U$Mlg@iZ@$5uxZsdYch=!nO%h1|m$FNdtFwlZHz2g9CTgchKx6=8vuu8!8SJ z*6l}AhvbK*X}!gSrgLbG!&`TzchIy0mM=)D1_aELTB7{#Ls*W9yk>{@Bl#w2L<3RY z8PQ8Q@p6fBd4!_$_lp*{tvvKIBU|-eebI6E&}%W`O7BvTg!E>+$Di10Tgsn)2 z2I+jYm2GSu8XvPQ!AkpX20wBZufArHLM!5vcrVb6hDVKBNSFJ49kxn+tTyq#guLgH zNf<01x?61*OPO%KG~ox?qrceaLy8e(#18deQpH1eP1Bk0I3!**f z?EM(6gw6d)X~SkXxfb5Vx383UitcjON{F%EU1Qu1EQV;1_MwixhnWUKADC;te z?5hNb5!s9ggdLfNG6ei8m-&_)%b8t%^qu6k!uM4-&8?^&9FBNxFwJQkQ-@qkRIfV` zzH0D;8IL~{N_Z3tQgE6UON&J5*euHwq@pz~7r#%r@K)YmaLZMlm*qx0Ew=L=WsCZe zGzY5B@P{@^iKFEukMXku(bz6$U%fU^#kNJAmP*b<{{k5zY8;EGf*pF6h!hMnV7 zwS1CTeu-RS09|d9lW8Lt=1Md>;0wFziwzj1`jKJR+uiq6ixntSyH+aAS}qxV zX|5ac-}b1?<+J`Q@~1=?*ORj_iPrk|r|j4vN$n%HvUHMKCJ%kT_^IE4$0M{o_&GmO z&2{x3L?VxR1{x%+5yfK^MUu)3&Zq+o;WczbSaTINat(2ilK_ zkxMxTT%7L=DkIz6wIG~?qYvZ0%o_90r6RDBcpHUBpF$d!jb&J8Z^RJJkw&^d=_TvZ zUVN*PC9>NnkwCh$cRc`1D}nMO@eOPEr!e<^?e&xrU-4O$LeO8hUPcRIsdg_U}_ zbCqa9RD|_a-(5*Mvr;o^BgvrPSj^Ld-6NHleY|JPVRh0R?x~6qM(IW;`l|lw@F1&( z6F@Wl8sXHvpH<08K{GuT;Z*-^wsPmxp_Auj*YMpvnbm>0_BY0j$bt$G5i_dZ%_tSKC_?Zqvn5myB6m#dx7$dW}Aq)1h?AWi`=&{7l z{rs$8^<$I~V;<`AMc5)tZQ!BGA|aI6A{uCN1-XZ7a5pZjPNS)NndTUz&x`|nllDj~ zn*;FwF~?=<9a*08u;r5o1WF~nk}}6UM6QW!V{87E^-JV%gU#fnhhXlCa1NZ19daGE z#P9g4?FKxE`6yJ_E34FmQw*TrRxZDl<_ZdwEO{iu>peD(m9<1?CePpQrq3=sHw`O|}UyAh+c=|NnV3n zFxB+82m6~KYv7%JrW-4ve$lU(C5mWoPgf_ZA=G3tuSs6=}l zT&?FU+lt&Urq#l^tShPmnJK53rs=w6uGdt)`*forCryV1^5!v@lE*RQ zbxC8fhiRq09-krnw)|#*CF^=Mz5PCHgw@4T14KS1+LmZTd4BIJwY-#IQ(Cblf$~JY zJK`&EmgxiNUDO%f%Ss%B0T&!#*W|&juVs(t239*xM#1VqjtSBxI-*h`o;sr3P@=QQ zIUVV2sUMKq$q)=w9N zIhfE=Tk)l;FjvRWlOl>$7K%o~^$#l7Au8?xMz=vmKFcI6qa-}hHLrs8%lQT<(d3y3 z&M4?pZ{2jOz7}ZN5fWH;U60RgD(eMEwW~ zkW$wYO(UOi94lT^LsWk-)w)D{3HAE;3r(&&;cF?DM zwQ0WOvjWVpzen329vGi^cetae=vG-;Mw>wB=>okt8I>Huhy#0+9Dk)7+AP%vYHU@F z8ft~|Lk%+3WOWr04HP=b|E2Khy;CN@HtsZKgL35DdOs3g(^pWF`M62K|@Bj>(j#;5wc{o2XbFxsGUE23_g zZn<$plg{vx2HPrTD4&Cqa1qz+*)?lx*uk}B&_lPVpfhF4YOS+)#Y(!&R|7JlQPH7+1-z^Ct4oF#tW(?R)!`<2`6|Y7*~F{ zp1)l#KWeGHQ~^GZV{=soumYt&j$?N|ZgBy|%TK1(76;3_Q6}Q-z(hK^`Xh_e=@X~SqrsfO`o&35HOCF?O|$I|5vvP~al zl?X9Z?2s$P8patS|IMarU$NO)29l9#s$I6_X3{n{NS zYG2?htV2Xh)4;GX(hcIVhbi=ZAtz^Oc?30F1L`j_6HIoJXuGK#qO@$_eX&z-1b`^R zy6jJgF(0`CoXt&j1<~2o7lua9?I@owH5+pBlxx{Xq2lwNog0T7;`uDRx(#OkR_)A1ehTMM}s|mM;+A^?4&52xN7i{`+p_Qz+0y zH^omqCAhKaInV1jX*A{il;$U;333hLUa$W@)V) zyEhIYxHN=ca1ZVT8h4k5#)7-MHPZOW-uuWn=brz=eYg*ItTn1?jnC9fCwyYBSCK&y!!bizrvMxoWS`M~e z`rL{-jq2I1BDO~Mb|IL7e653_11DFd-)XRI+`o`>b_?0ONj0@GKiI#lA(_7|MTrKj za8<1Pc$#_E8pq)!l-qymNo{UNJ+eJLWNlF){ z2fhD1ba6v^4^l7LhF=Rih?n4~et1Rk>olh#K4A3E=|2vhN-haBWyq_6O=YO5?bUaN z7;~AfBMA|09FqkA!X#|qfqM;}DG#|te?J(0+(TK!6|%-^*%jP`2=`66_kep)i|rqR zFy2kexf}PF#6}`yaLXZ?$LN|U2k-I%}JvOYT&Gd8IO!!&fm?Ll4b$~wJx*=4b>V&OsG^}i2 z1Z+hZk}mb>(nK(uE%&?&>70PilW~jm{hV_*n!IH6_o2eX9uXr#S*TxT>27ttI2I>A z`Ee|@GGo-EdqLOCaED3Rdry_Xy?KE%)Z_{{=11BIK}L|EzxePi3y&S4m0@_9qQ+kh z6>?+EHI1AWYsvMaMG<(NpAb0t%JJ~{u=}v-(8XiQ6(Z9`-|{jG5?#NERC*0Z;70v2 zk9a^?E9;Ewk5fP#W*y3jkehSND)^>aWmlQQ$y&9GQRY8$g|a(|7ob zr1S=3TN2>}@ouMJm`YBW@KK%$rSe&&aOLfuLS-t2FwMrQq91E35h>CI8~NGP-(9C9 zeU$4oB*|!{tECAD&%ZVVGmL|h^q*6x@2UJ>gOXR?Joq4W0Fqjw0}&ood%IFEgi~6F zHak+q9~c6EO#a>GgodM{5{FCN&y9_|Wb0-&***GNnx0?no5I)T zESjJoz?}xkt7nVllTuNM#^EcUd-0|Rxp+xk5P63vR?y5Q%-*79e!=Fw$j6O;dNTBO za#Wri?S(Vf0>d)8LeV^gn1i_zGtuVnvp^^So9X%VSq8}o1RIX-41`wXoe6UgN3Nj& zwN0{Mrua6xw{Sn#Ucd{=i<0p1*l<@|j()=6ZhxoV+h#%SNeLIXn)dJrE%<{@&iv$~ z!$uu3jmK0@?5!bu?}r1`-KfaKnTTg)-}Vi>4zWgHlH}aATCjKD=;1l=s59Dl1>(Eh z`$E%gL$T6Sx8L}=rE7ae)z5`l>=G~V3av&Aqn^9ZmvcMKAgjlGV!*1wxVVOkAUM2Tr`hB4q=EGLKO1WAU`#;unB1cNp9S|6elKiyOZ-QE zR5V>hXq{9zXu4vJ2we_SCQ8rtmoev{3X4~fv*A{K z-&ulo%#_jX&BbH{flzv1YI|hw5e*m7W=6H=7E?5q)RG>_M5L=7J0bZTdH-EIe5Bz& z-}zOXhi4q|buWWsj>RBjJUGbkdZ1AQWYQajVq_yYyPl{ zWBkebiG#hctdM}J8okb)$!YnhdyX>0qNK$zg*eu0x7L0EByo0p=f8gE+Zp-T*#$kn zi&!Y7+UcFCW$x$QaSBk6Qdx1hQi)O_i2zztlw#DSI|Q?u!`LNHQtWMoX~fYlPq?KW zcVC2c`UY_ga#785M1}hW#G#oK=F99d0Fx6~@Y_oyf36iOb5ZCr70#tkSU&0Xq;c-) zX-hMpU&&s&-IF3}U8)m%m6m2Ne4&o)0K9EGsWdcx@hK{sTtu^76?kj{AKVs!f`g+a9vz5#PSh{`&4neQnNaoBi_;77Te_B z(yj3e^anl5T&vf51wZ}n6! zq_AU3@$nvogshh4;UXVrfs5ITu|kCnd~2>V6AUG^QIEUw^m8MYmQG z8U4U!`{tGqC@|95YeK6^*NO4Rz*9O3$NIaFFLCJ|ofqKyI;**A{($CV$U)>a1q{_UL58N(#2aPb&y^ZO$T+5! z>6f^2$hVX_qz$(o$0(!?BT{#3zd5t-8h>ii=@0x1bS-%)*tyQS|iw^%<>S-G9+ z#it9UIQ9)f2Dxm6&0jo|tD4NuA3yl@)eA!UEUX<)Kj{;ak$*$ES=07f_Of^Clbs{9rX&ud`+cp2W{d=WF z-OQQ&LcNEEXkrMRQu74a@RZl$5oo?ni0fm*dZARbSjE@&Q>b)Sspx_Ij{%dyPrr&; z11s+eh&s_~#f_l~$lgQq-^F+;|K6~RUgc&qIe0$p7rEhFMwtFf)qqEpa5=vM_@Q)0 zAzQe7dtJms(U(+~rY0l^bz=%Nb)i{%xtFCr9Rzku^z05YNvL>iK1S6S(48?=3FF5K zdL%zs4OvI6qqvxstU>KEli1w0S$TR=R}9igPW^FR;h2U@Arr&gXIhHR3Jwpy@KR(Z z?0%$seh^7RlZfy%r_rUF{&d;{OCFUGx&O?9y57NDtnvOEX~_wyo2nDqb5DlGE?fmi z7kAn&o|a@qw1XcQ)G8J~JI{ig6VbGhoH!wb)!ME2WsK~M{|rS*#=aovJf|$WL#4_= zgm^C05896OJ|qL$P@>0PTeC>0i{UOPNMefU;IsI{Lh?W_IL?mLdJGAinIPf z7s{G`^L%edihI+^Tew5nT#9?vDy1`O-9!-8k&OKx($-LYea_H8y6mtDkKd*k0R&%< zb4=BaTN5WZ(aYjV_jki*wVxX2vT8ap2H>1xTtB)3_Y=7qZ>L-6yz&OlZx--qvH{1+ zv0V1B$DHcK*U{d@>L1$~Z&hTD`~nr{Rk06S$LWl?_ppF1i0i96C%1BntCx#ZP{Ga3 z;^{=cgO`j60wB2%XI@ih-F@KD9M9`+*M9M_D6y=uJa~F&n_rp*CiIgkEk0! z1Z=cn(GVBj>)cHdWC=1L`EWfltmh%r4|0M4A1_oWb~q2P!_7gRa>G@_)b29{W2d-8 zEy!F8%U06SMDS^z5KJqs#A)^^K7gKB3){w*R<}1#6R&L371{t$SYrg= z=nYGq!etMOhv3rERDigjfuh9$?_ej7{kV=sXD94WD)*k4P^-dI-JZkAXyTx+ctYcL z4q69jKlL&|!Z>i-E}+KmoWE&JZRU-L^2YN!&-A>m$4(48dK{GopMr;T3A_XEE<+SQ z){S3CVrsu#e(2@wyfE?;mgi5_OV{6p1mHy7BVffs43qR@fb~%})P;RvPk?(#MI2#^ z;sxG;n?Aolpg^+(5wpg%>3Fp+3IX&G^!ZnpZ% zFL)M{NVGo2jh{e`cOYYArhfLL5_f%;Q9baA2LO<7T6C9~81sPdzvC6rX>U=G_M6Tr znT6S``7b@#xWYJGpuf&NCf4`e;7HiUuECv4&kCQpa}XxJlN>(MW071qMmICH8-EMK zcO%Yt44>oX)4;g5#p~kSYLfFb>6eH-)jPp7Jb6?y@3^*7RI+XB*Q@Qv?1XG9+11ZN zICzoAAd??+OsqRo$H0_oV|EQlB@nxW zIw#31|G#Y;$ho zbV&60M{CcQL96~WIr~}A`z%-hcPfDBy8fGJ5VFL*Ns$jz&?=)1k(U;)$)D@r5u#qP z;&UGvn##b~MmG?Bu^|4umMJ|y!ApppwQ*)yRd|L$Y1vOWj8){EMgXxvk<{A|9uW@-ZX(q$bSLUP9AVC-PW$CGx$`+q!KWAbpN#z;@^>fpy5_4HJe2)!hTLP*El4;q% z6*}_Ia%hi;+ckHA<~OF@m3L*ppe(fybEKkTE`$Lc(P~g2C zNID=HCR?HzrRs(FlqK-#`rc2yv(HN;!^SfTHCZstqX#IQ%*!h*0i&O6(qoV{8O9BK zcWzCvZPlK|Yj90;4Jk5#Om1oF>jKMPzoZG>(jwmsh5(@!>j&*6|mTX$-W%UDZ)-x|<)&~{=HN^(AR ztk}>FDrVV|SD&GYA~?l_!xWB8MmkBYx1ra*L{H&u)j5*A~!ucJBqI&u<> zX9~!&^94W8-#n8B=3a<%$?}OSU7zkoLzBvT&D?7OB5fBgAv9l*_x@~m)i`c_}VSH(*8W$dYtC({m|BCoRUDv&LjoZxe~ zBl;Nx!iTZEP+FYowj8(}38_9|o;jiNdLXGV3uTT_L6q^uqUVy=V{!^oOD^vD_Up?8 zGw&8T3v4cKAoixvbnU77K7{!FgI(b>xUl_%lnXZWI}CE<>$&%XSJ3DhsiV181%8hJ z8TJ7_QU#7P*id)w@gT1gjH#Y_U+w-9&YeeUXWKA-#u*P^NtJ%$G?$MN(ol{we=t(! zWNJ_O;E`Gove+3nHwH-ld|CKUTTnQ)NlzEMEypj^pr#`n+xE}7HPd|#{q6Fvqlb3F z&m9x(MkNYFkQc1IXVm8|shm-g(DaTGKcW|{UuER0e;}$@{BxA}9Yk-gi|0s&jmE^9 zRsQCkDf61u7^=U(4qDv==PcYn43VKlr~s$Jx%W9vDinxn8R?fampck)wisfaW6$kv z+6`cu$rAsAuAzH@GZ_jm@b)KB=&1LVPab%?@*r^UOdPuU2%m|r$?o^-rWBKOAc59% zo%P5(TqPPlt<5?I+(&0gNQ3TWzA_(kdGX!RmS~#{b2;A-v+Ep!pr9B+ z%wud}mQCs+p-2GJeCrvr`8a|py__eT=S*|;*bq$?H`oK~hkxyIsZ66g>+Yl@8Gy^l zgs0`7Q0cQ+lln$(j?W||vRlK2bl(Y^=cFUUg}&)BAos`V)9x+m^SoqTuG3lb2_ut8 zi+IMq)2G{OaT$ms;^{g<`(!@2`3Gp9CHWHFpQ#v_tR0&US!0!uX)oK!`5d=DC6+B> z!+|_8UP?ls46+s{hV`oQaPLL?mVJec&GItimc9}_2$FPk6*s{SwkvD~AVXoeCbhBm zoDTU)1MLxW^M}X1EIeJ0$`Fd#F4C@bMibKd3*yH5mndiiP1Ry^i$^2-;YRvgzL*2|GS$*UvDmB$_#JyvIc*jHCeCsxVm3&xf|l_l zfn~QC3j~wWmeZ4|Y?p;4AtVROT5Nkt)`t~F<}Y$4w*~tSN9$e25Gi-YeBtz#M;w02 z;`PX>RB4lh{@71ULF68fSb>1iXQ2sYt7ZfqRb{k2wq$?T9~~tZJh3Z!*PIwmC5t}f z>uTHn0v^G{ASe%17!rh?F_Fwma@w-fmB_kBpK-MpbDyK@P4U6OyB)lpnZ349wyr96 z|0|^JXBSziaIUCMw?1MAhonnB?}yj$el|no>zc$Txk@58!Ptw|x396yO#^))x&yZC z#WqY3mv{C0-?*7p!tfsgqJ`UJL0r59sZ$0qf>yJa$Qjjm6RC|ZmL4URtkVVKRCx<;E_N(lAW8VWD2bYN-Jbiwp zX&>3k8L;21F}P5OERFn0XvDUT-!E^0I(p+bB{$=gw#Dx2li1Kq*Er{V5?iSnf?OvP z))g978gFbMyx<~6Ct`V--<+Y%n5OC;z3sup82Q4IvYD0sW)m0Z@C#GQE|Qz8Vx@Td zIWIABkG>E>k-0EiT$t?wa;0$HpvRm$I`V|5m1Mo{g!l&>b5rI#X!=cOP~w|-^A=1r z_vVv`k9CGlk{mkr?nT=3#B~q8y&SrT?prMtW(?~<*t_Wxo^awJ%|C%L*;Q^_NF*fn0WxHh@F1Kl99Syx(K2h^bOJcrlj9{ z$rsSFcK;@D9uVgS+#C^(`J>As`F6ajd9+A+X<3;Cz~JkFOp@-HD2RxmUvP18lS%+@ zcH)tuL*BEQTO?FS`Nxgv##w}eW^sS=C|OWSGkNvXF_`0}Yb59;?+Mw;@1*^V-}^X} zm`-yI1&hD#ulY}iufN`o;U8oQyOj@Vxj=qL*e18n&nJ zcc6G8&OLmg$qncR(45^D@Sjumr2+y$hPh>4k_XGra3~S@UR}xdInPu_2$IJU@*yK4-DO z74lUGZ_)+O3z5uK!(a_#=CZ$h`R?WVL^FU>2f|eA$|XLNwR=J!7QGzC!39E z#s}W$r)1UWq&Slw^9c4ozoBW6mUMIeTq@aW(zMS+Z%Ri*kbo8v+wCMpFi#7KPR}5S zSS7lkI`B?f5>uz6)adn(6h@?9e|~Qx|6Y8e;Pv;gU@YbDDM04Su+%wa^KPOI*UOj{ z)DXC*UIKWK!0EWUun>RPs~69u9#)tM;N#4T#5hPsdZ)B6tu7BLtQq-3}+8a!) z!KSN%H9k#)Eo#2;*~q;wvEK&^ILT`BVp&7+j=>FYJIRCpL1GkWHN91{jsS`x^*Z@k5L0^lO8iK zrr+N#^b6OgcbF9B8W-*vz*k4>t6Z1lvzw;WxO?hzz&EySR8CF5_PwudC1I#ntD%FU zrDLjVG@`;J-fm|n1={fke}+X1@J=bF@{dhcnyPdZI5u1g|;WnJzp{ z$WZURo8^P45%KJc6H44|s-r2n9HZG^nM>Zu^KGu@n*n~H^<-PPxR>yN@Qt9~xs3hT zy8Iy7R?zo-32UnL!od>Y4&~ZIoOp}m3rU#@_v7F0GhIJW<{IUTnXjJu@T&o2*Efa|i`2K~>Wz7mtUO_x(tS5J5}s{=H5 zQLh9~LEpv@z*Mw*f$pTTO+D|`M@YbzDD$$XhO(zPvHBvi@lyqUUuNSF7frE9ThB`F9s8lJotV2(Pkp??3tsV%B13;qMydf4Wd92pTy^ ziQ60T+9h)JytL*4NZ^}l zkINxLfWbFaCPQeSLea5Qn5`a`q|O?FeniTy?bn2$-F}uKQJ9P*_yFnJV7MK|Jp^>@j@OS@}eMEl$VGM|Z3 zmA$S3EZUay&OW*+Vdb@Z=_W3h0Yvgc?zr?G^=kRe(0F!%0h?@7?;}%ClYgv0-XZqh zX`yyosS!hfPan)G=e&$4@Q;xvcSe_d)_cAU%(-XCy$54AbR5`41`_Ps_L>MGews$Q zL+%%ka=~`1`RVI2c^)YkLtTXP@~znE`r7UGp8dvQh{Of|?hSuHtS=QLn1U<&$y)-I{vX}fIITbI`97b$8|Qs4wc+Bsj5}KFPtaBclkifGU z=DV^1THlu%d1XE9>R7uO?&9p4wA+?E;;c9O0}YkLGo83V)*PTlD!~Im}J0&RL18<;>yJM0Lse!62+x3BE?W$jyrUx+)a%3PL`*^&N z(zJ?xyr3%0Sy5@>zsILHL`-JqyDG9b+tgq%#I~E_Q)!_wNKQR>`8M6|>33?fO421? zlGDlQ!k9V~6BJ44J{8+%VF7=+*}QyRteUuB8RdNHG(lnv{hmM=Dy1*|j?NP|k)9T} zn=#Kc+md-?*xDvLTP3RF&N!*!t#`*Q*X`Oek-yGKNB&yHR(gGAnrrC(!%7z;bfVp( z6PA6I1Is3}`aLc`phq`hUnL~E^P$3k93xUsp|H+1&FkyGn(Q;WLXf4j!Co_g>A$VB zMf3V3716ko1Z$ATi&eqgaa8$Ylenc7y~RnUhBS%sv|3$Ft za`mTi7A-6#whxHgMW{;r6iO{liT+<7nFrL%QMJe&@;<6nQW2+OGA-QeS%+e;pJ(am223*n{n%`);bhHws1l?m5Pq-XI)f0Zx^c}vj)|Wi}aT1JJozlue zfK|7OZX*%gyT1(lyqlr}{MxZPnUx!DlL1Hq8P*2xQTT`ZRA#D0c;rf{}A07;c1V?F!+d?4N!H>Vf9Y3lk+8& z!sEiZSc?Pg2mL7_DQLO|SM)!As(`K~W&d`6rve5S%(hnoWy< zZ)&^8TOI+S+?Pb1gMx74^-ce$5SmK@fi0V-Zzk#Elur@smuLcbj$_^sE9&KXWYOOQ zqV*VUzbSl7eQr(FZnqLn#>G#RVxOA{9z77y+;P!(b5SUJ^C<^6IdyD`QJ$NUnG zun|fOz{g~pxlj@3d zHd16b*wHL_x7oP@dYrLFVJFM)W7DpW;KJE(m)9F36&v)W4SY}fVMJuk1BC*Ji?c@u z_$TtxmAZ$)mk_ka14tRV1m<)T_~NVWu>yXUTzcm8@cI%%_k;nd`}a)T%wOcTr_BG&HAl;Q`+f~#0AzRBK5Y;4x#FtcUTu%O zyAof6qQPltw)z6TgRXeQCz#=kxmz;<5zs4PaVQC#{&gU=IfolY)Hym27g^uP42X4s zQFV^p!NnyuB3HUWa2|=xlBc*_7)H=Y4V=Ggv*{^e9ftNYoZFlv0V8=C4TecP#dpDQ zoPWruS|~@1@Kq^07+Ni*aU?srD;vyA>|_9D);vE@sW8thdh!^l2-YKW39PE%%*^_IvzWYnD*0q)F%U%!NBQ(A>o_up!SqY( zZ|S!0)3e7dc?XpF+tTc;Thq;~GmOSLc$XnOZRsu6Iq5E+AxQO;93R^Ij+@u_ zpP1e9DUJV@5Uxf$mBgie8?tzKrnlVa^q<@EKee0h9f_9q@{z7lh0RS>D1U?e+(L$~ zhJ*EZRXDgodv0k-*TBK%v?|Q2L3M7i_3!C$)~i*KHx0&f%MZFH$2QMSAy^Gk0t*of zUns2moW935s0%C&F6dI&Y&(5ZY4{|tSp4SAl4hp$j8nvTgC4PMy;H(C*jHekctP60 zGS(@Y6KvJEqP_6hz^cM2z6$KsxF)b5zigT56zc?bYFzbRP+hiaa{`@$0~^<|7o32Dy?+R~ZWf^7V31#K@WEC*`WjXrgDf{IB{R&8ovh6KN85PhA zW!Vbl$qVH~3KdW-W#3!M6I;p&SSn!e$a3w-Q}4)$?`BBNn8fU>#T>eb>yC=+ACBuSjT=0O>q(0nScvOu zmgIUw{LqvlfDY&}0Xh<1uTa*VliK+!9QKUYH7Do5=rC&(*D^ee|jD#!dPp{S0- z@{W-Aj-%F&6U2@q+K%G_fBmf^6#HaY^#sCoGU|LXL47h}{4Y;C7IXqdq#Tx_gwRor zno&;RQI4onj`L8CxluyjWetDIg0N@mccmS?hkVl>PX73>iz&S61*eOVu=M$48c5A6e^v zvsC+C| z)blHN@T^pS7 z+o0~1@ngX`H3L*e!Y=+I(~l8!q7EomfE`fxS@>~)PTc_2LooPXe)`d?oqPh6F~fFp zdNusm)K2XHRVA?NzcBTC4?WQXRM@~ya{4^{xS*%LfSP^SlW{kOA079JTze@AY|FS; z$&Z!$)T+HQ6?SFZ!|umabE4H=t^+$V?sM?ttU2{+ubziJtaVfPF}#9kfe5%r2;UG$ zU3|Eg;f|TPe;HB*4gBv&aVU=F2V2jr=<6yuSXEWUgTdZ&Ya+S|$ClYuv0h;3xm7=1 zwPUM}D$or$Xl@;KL6XAqeV2oX$sOeBv%B%il6kG(Zt)Gv?OFJJH>kNY8C0@aijmF{gA&l?#Y z%sw6@1|IaD|2sCK|1}g(i}g(dq3A}*>BceX##rel5a~v1>Bj#Z9ee45uoj|J7UDP; zVw@Hds1~A)7UIPgVgnaI$U;#vLU9a2F&07z1VYgoLh-ypu^vJojOHk%<~a7|7>DKr zisop8=6KQOSpQ}a8Zb%$7{?5Zu>mHK0Hbw)@q)luA0P+^9;F74FScYWwk9vO5-GMpwYGe3ZB1-# zC17oXy=Td_XHC6lCBA2aNNh=qQTHLXmL;}MNU4@lsg7@~mSe0Az+OwwUiY!0maU>r z#G&@RL!H2JE!T0KI7KZTMIBFOEo)|-ut6=8K^^~cE$4Ebm}o77XdQ1`Eqhy?sDCZ9 zf1TiCE%#%c1ez-?8c$T1@OK&ExIW=;48k!z{}nQ_#)Y%Se6ye^hQo4(5GKP>E5ivQ z!x1gRael)wFGDES%CO1`gmY!oX=Q?HWyEM@Tx?}5aOJOC8I}P+7yzRdfC&P?hz4Ms z7ck}lfMT={E44$|+eaPRCn(xS4BE#<+sFLdp=bfa3IP!2fKi)(36g*joq%z{fH9u{ zD9+Qc+7pEPY1HLug63(&uX)G8$KM}oX68%^0N2z~y&`U02@}go2hhqv#V~P)A z^3!697Gi!i$CSW7=Y9WN*pL1NpGoT@lMZ^3CR>pRm1IT^&Rs&HwLt!KxU>FDt{Z+{Z7?!2h|2yo!gs!i~Jze;AmavQ&D62CGXzbZk$3Ln23oQG1ihf3~;a+il{nujuzhboDOis1jn ziGOp$m3oZ%gVCAoLPJEBN#%#Bx+fS*VHM`)Bg!vmk<8=z4jLS~^tA_fTnX0A{rMyqF z74+OE2^;C#wXwIEOg$Y(6g|tpH!p$oRoVCHAJRD#i8wTi?zlR14?0+g{pu$(kpYU;w+?mwA;s4Mnj3mWRiAux&nPdJ**)dwF^ZLiy zRrz&N=d{|x7y=nf%?K?SN6i?;RdG9$jAbci^5#cr`O)R8gt#A5ALR!}g~+%GEDMx> zjC_{8;>`u=ca%quSmWk{(N}WgSOS(QoCozyC@UG+!Z?$xp&#` z^|8nBgxQ96nzIs<-9M|2kqNV}4>!51PK=@4t9GWwx_=5vq}ly#n3TI?b1xV4v*IfA zi7R+G_bSye`Pf~?d35~>v?5Kn5-OVXO%u2wM~==wg%t9I#l zl1eL)kCzD4{W7-UkyGSOiSdoLkqVR4pe-KH?(M%}1`tWD;NR5PWCg_ATyV5*3j;tT z7xc!xW0Q%<5=fItv4A&tz3c~w$Y!#p^f5WLxMA@^S5p`rmu&wNFvfkfn1jbaWS1>Y z%$_fpeXeocitX_}AJBjCpjz-?Z}T7$@Vxt%?!$vM!-LGrgHg|ec5cqKXC_W;N=IzQ zlVZx6vMJUM!nvSJu|Ux_C(^dSnlq=Gvp^OwC-|FFwb7hHymx3JLG6N7yl;OYGmSXxT#oR8%OmA)c zU$I1cB#~b9-S7Vb4?JP%eMFYchdZFwN4TujDN~?ikb&fO%{SVaK3#@OlBKQe4eH(`04S^8H7rsH~UGDEeE$*Yc=VB_gc> zO*bv+pPEIQc3Sd3wR|ev%iGKI&eVytn7nGrEB_T*WRzFimu8fwlvf>ylMHb%rq?%f1(tKME zLZ$HpgW?99w8p)=W4tz3k}m4EWD$E<*`=3@ds3$Yk5(b_UL6r|H#VM;jfVNh#Qn)2f5e!3JSG<5y9}xH9?B z#$WYRZj)1oF^u^lDBDSZ@t8;~PG@%5dU{j6N4NXrqOgtd!4{##r`n2j%t-!y-pLo8 zt<$51Yb<^J59?vSXcQ)-f6A1i`dX{1(jSG0_2bJ2L; z2dhz}E^;l4T(<<}9^d_!1=G_MW#9FkqEfpGqL`}nj!1)}V3UOuXP*BL2mL&SABQc` z>t5#ekhLvY?JcGmNA|+qfnV61f;h62ofvi=I;C)CJVpO6MF2ZVBh)RWlKWCK3z04tb{wG&wPvHGj4NE?j9p ziGIx@=vKgu{ADSq%%tvHzfOzy9#7+YN~G0!jfv@AwtVaq$&Ki^yo8t-THdMq6>!C( ze%2-Z%p10Ns%A58lI(Oddxq0?Yqz>CZs4PR9C@ZbkIe&fB1Ae>nYtx(QkrV4q-;{V znVS#J7S~>_YUrqL&$fJaOaSEy-2BaCpEtDVYD%MMOag4Zy)D0JGCPGdljf9tQWgKu z8-pi~ImP~C2Iq-fzpiITA;m`QAeQF5Vs)VP(ZkE%R$%O*+->iH7%Wiw_x(%o%tzu> z_wCai=9K3eDYf9en}8r5-P0q#wz9^tJ+lY3m$3+(pv^E&iY$`lKfWDCM%-U)W2H$t zC+E@+U7qf#T!zmpcf=fqX#!=i17*$vWD+{*d^RY1T3}hfT!yL0-DPFOf1f~=Uq`N+ zq)fbhZtNvgAMd_(U9ta|x7&2m5*5`u5!CWw$#zB)D}O+)Ez3MQvhXqU28;Q_rn;1J z0%wP;G|rFCPR0DNkB-!6;N$6nuVUW54|-nnH|`C8=NvbWMC$Fl|CFxLv~o^SHK+?h zTZ3sTOCr6RQjE`;b2GT5)b5OaIKe~tU$g!3c!qZKR~sJ%^JxXiOP(JgBX*l6HqIAD zZWn7)P8j?~0DaoFxSi67pEmWu7{me2^}>x zt-GX4U{~eDix=Q=7kGQVN8V6xk_lU%JKa4$qk2^EYDc{X7zplnon;Mr3tze&1lEi%6I*;j_Xsr;^0OFq}FzwlNd zLd8^LLD&)1pgU#lK`mtB8+$j=2D&RsGm;@e?HNxPR#7t6u4&jZg9GqZcbjCX;uG33T89dqSB z7iHHzTx{sv7f$81Tgt9rBz!cgu9MJuMM!+JTgt5vD10=gZh{!}f4idFnXXcX4d`7C zCGu_TM0%bc)+9@w{dlNkYyw|hP)`R5W}jv5xY0eQ?=tOtWm<#Z6EJUgXWtx;dqO-> zInz><*^BvSBJ9Tgn!TQ**I9>ghvt(g6;-BSqRO0ae>7^zW1{S|)q0Ltr;}S4D{+`A z>MbkX4>H$--32fNA~{W;#T$Si-Ia6VyXJvsC%0U^6$#=y(7>~W+pF%1#2hX4UE+Y4 zCFc`y5XBR^b|1Me21Uc4p;(WAZn7Zk5BPn!xI+dQ6FCNvhgJ=(q}6%M zuG8V{E}lO(k#lp0jO+JZ(&=d=VnNsDFyUzG3&U7__k$a6$Z1hXR!2?62|5tVY1!@` zRQQb>H1-b&8QY#3{GVp`8}~ENKlnfGJ+5%i54Rog`3|=^)?x`Rth;-e@iY5UZm-fq4ta1N3- zZ{vCo*rSEdq&YPlsq|3?;dyU6?R{43I?HFP<1peMG!DhHkWSbJa>QfiB97SGX1w-~ zEylSCxrn^sf=jV#7;$W0Fk>NR$ z!tZ6h1#LGPn`lL{mGXE4=8LDZl^9h{9o`kE{}7HH?`<}o++!7loUH|PEcxj9n(pq5 zJnQiDv~ooonOx{a9pB|WYFsNY&MiCC(;sqq&j)rAbnC0`dUXmayY09o4xL2Zs^V-i zlEPeHeHuqi*`siwdW+st@DNP>yby9yGzPMWhfCf4g5dcce(R0_J^Zew#mOw%RDD!C zL7avlOeimpuwsf+xPBVxXm6Eqm=tdL2QaMj;_?eJsA^~49g^=5WWG5BmtZc`Af;8KtybfCJP#=C zzm2>)4d^=STYMe`c{9`oORIW|)!U$RuO{V?`ucPr8c739Ek?-B<6OHyW9{9JYrPFc zh2LRg{bz~1?A4GSe^$mOf0xh4-EmUV$0o1$$E{g!XU7NNK5O#hiJ+ zafj>lwFSGt>8We8curr5_OYY0!!7bjt%yHgfm3gjA7Xpklcd*;3-$#BL%m7W6t4~)NskdcNyIbv|HRjuU}FCoqf5ec%!ZB9}xKih$b_ljcrG`7zfRt;N1EN zjg?0WXrG{ujyIMYps_Uf362cm@TLZBpD^7+!<8HqK*5zP3Q_mjC#tv{yRzwRIK~#f z>S$X9zUri2HDjT4R`W|@Tsc>;%24$Qrs_oVC*bv!8mV)>eS#BgS(HHmeQA`zJmY7d zgs2jQzPw;@xT2)e2SpRMvI*0IKWtvNbVWMh52$#QSkSAu|AF&@(hlY0KhW@}&p$gx zHkz-n$*vZfud-MN6ea;aE9%(8S)Z?OOLbP8y|8fn11mbRZDrGcz}$uPyi)8B6#nV+ zc^ln7J1WV2AAyqP%$atfwRBy$D&N+2lkHMW^)6s}lQL(qRl+x~H~$0{qghj{l?d6i zn&}8xtU@~i*0;*4z!`9t zBa9h8&RZ+~4qhj%@)^@-T&X(Zb*JB*8yikpyQuQd zcWL^M{iKf(jjK$kt?S#}zP?=_=Z_Ya1-fQ~p309GM}Rxv?c$Z-a-**P?G>=Xk|DZ8 zpoh=juIV~K3d1M%gvl6yd6*tY*qD>?T`80)V${T-U zQuv44@1&5GJB`1k{{);%%ZrW+p7h0wzZdQ^nGvFW9ZUf6w;IMPE(-}=TCaKj6f|B@ zvwMkIV>57?nYjJN)UFr&IQmTs%VO0bX}jH-AKv@VNIfo?_QKc!e=o+;+KU~oWj6Bg zPi2kP_JbM%DJAZ^1+r{)#+o0yeWmXqAZovtKvUm;`^t?i`_tGwPqXD;bPvz36 zOMIRTp2-P?l6VT&$eco96w^JBH4r;0&C`*Bcr=&$+;m;Uf#nk{==kCi1 zYmK=KJR{wqe(gUMVkKg*OY0l-h>w<{yna1^{g8h-SNh?#V-AXiOM@0&|4{*hfr0TF zHqdEUQ>A`Jjs8!X=&`Y)M)QCc?loYjSF@x>L;n6V>**g2ql*Xsu2idZbKd5%&2@9& zm2Si3x-bDwENUr zI{?n7uM6NI<(&YadRDn9+fy5^iq#|S`YXV9@$%=bIDP+@*k>pC;jCDGQXi@JcmU0mz@_Z?g8-hizgvNxCGx z;{asOvNvga%)@%M8&3C=^08SY{F2_W0Fr0Po47sl;s0*|=k}<@YcAcPQ`f(a`&Xi2 z@7p!{e@XYh^KW?9ZQDHIya#vfUOsWZNBvj#(eJavf1ULt4@3q5cm(?u4 z_D6Q}+9Ird`ERZpZtYKlY5%K1rFV1M$)%$l_H(Xp9(QCmlVAMw*!km*`Q!m8AN}&} z{nG9IlIj1`0O8F1m6s0%C>iDj)aQmKDOlSj&{~`D; z8GqmDE`L!RyZ0NUFd=LZ1L_}QaEs1nLx>w>i`uIIDgHOYX7d^BRfLo#qzS4<{r{8v zJsD5X6>6^%q&(pt^7mxQkV=FyK@4cU{~(_=DF=;fL8^W3BBZ+19#oCis|u+_X!Y;J zE~sM2eZ1^%*AHIvDNFClxKpx4*~&C+m+_Dxi_WTpSIt*;elGyvb@H~oWrwG$VDs(u zd=UYBR^OX78T=L-mw&_C>(v49v_C|!(V6}p27!`sECf^GSP<#l`t~M0{gSThv+eqR z;`(e4*k5~Q)KIEC=HgGZUq84>Ua*@RR3H#v-Q@EGJZ&F#dAYv=ws)P*`)01Hb$RDH zb%&*48oYVS^$?^-`?wyeqjXdsXS(i0D# zM)N}!=9;H&T@{vQ*Wd3M#ZEY|FP~TR+TU3tW6t?bc1J8RuDLAniAOoG^(GsVTr=+9 zyROmhuhDe4!xlAmTYpqHDfqOt5%Ahvis!waU%Y$mU3k0m3{J0m;e75ywR?2Y86ER@ zyE$}m0b$l!c4@SC@y023u`+~-)i4A|Eo^gMBfe#cI&60_VnZ9Pq z9Ls&Y_cG>5*@ljDU0j$RXKK|Gdo-D>74}y+IkLw24D)h_woes_Rw1GB_KhVw-RX z`Gogz(Y5OWh}yj7_WmRP5`Qk*uk^brI5-1#!DgR#OJf;cocaIQxjlbAg~Zk0d^x){ zG~B#cA0R0jImnw6*RkTG0Tu)~e)>g)hF&5eYHk}ZRbQYOd6O50En0p_^&sFp1s5)|r{E{c+l5frOuEbb+2fBtCOST%P zBo7C&HsnU{SdG$dji^7qU9KrF)PV_5oQBtsIf-c$v7o)qDQlS1&R0%@43d%da-7;4 zf?i|Vq9ub-EhQt1c_CiY=mV?yX>7rN8^+AFiUb<+rPLQ}q>z;=##9Ix01V zp}4m~QU^gTByt84?#5(*k^xSLl3T$2G67Q8eJCd_RYKpn5LB~>q32xexL16D`q(ls zZNoJ%vv^DAPt`;mC+m|MrwD`lZrBSDjq^fwq8p}xv&)XOe+#5G0T(1V` zP{u?po^=d7P*IYVvY>GeeZJ5%0eTQE$JY5*iF6aHZh7T&1e&2FO|52Om`~{B8v3<{ zxk@CPNjn9f!RIIhkg~R()IG;0!ob|dksv;Yg5C^A1Cn3}JS5J+he}ZE`{e5c^yPB| zU}GTRzVe>Fn5dU|><1z#2tY#Z(Vt@5tRn;y@iAr{I8?f zq+)htCwd^{lrb;2c{W*rJsy2wvNb-@&_kP+8g8H>WWM&vk`h^|3NvGet`68QW-aJe z2OT)r&u)w3+s`xnT8}XhU9d_ZHeZckOi&_2d{>O-Auc~u2H2;83?i$M9cM<1Qn8Gu zfG4=JA+(QHS7(p0E$W;%6C8Pn^!}xJJ zw>KrtV+h)Bu3a$OELCKeAXf)%r-^@N5QMuL9gf4c6{aIMuwe78;&iQbxB_p@Jwpp+ zjjON1VQpokqGK)0j=H~sp-FMAwa3Gbk|y)z*+`UkzPrNBx?`XMq$zjJ;!qW*iHIkK zD*RvvMhD&mj|$6v+Ar&LXqNnIs-0*W<6+vhOtNS@91Ujysz?mFT00v}OF_LsH?7S^ zE*^8^PtJ6XkX42uJ`gI~fCGlegQ;O$F37L&Kt|oP`k&`9RgQH}H+cr8z!?y@FXI+X zHKa0Ep9Ux>x0rDI32b=)I4_B`A-p(Dl<9Q31$3}~%@&&pQ~wtOK2%-kaFVhzqlo#1 zC(DucmzAXXkC)n16)csV++<_fW~3@)d2|A{5|j5n!@FRM@@;-gzB`-=y=kd%{n$6mAb# z@2!vgU*yD>qf^tSnILqcIc8G6RlO{<6Z3`ykBZ($Fl&q`PC<)hjQHK2DAP&O(JQ-ax7p{0WrudG36 z6ch&$6ahIQ9Q_LB5wonPU{BOEyT|#u0Gzl=Q1j7J*D$7LwQ0mZZ(-lYHe}x>)5e}i z{hH{!G^{@H0Ow<5oO&DXHn+0VW-{R%8UGwx&b9e{u~6I;^N{sW&paM*_N;c}w(!lx zBHJLlu}jQ{?>3M@j`88BYP+U=xHEp0)9|C5(#DcW!(!y{?D8@qB5Lf4{^@Xe4A$o> zB|lT%-7S4Bw{gcz*6^W&N$2Wx4Wthcp6S>Z@x!5TjT7~L0%xZr9Ubn8kV;u(M-`Rw z_2~vR70y;@I;Yv7Mk~|Sit*_=arK^Q)Dz;5k`$Ye!jARnISs3g>9Iu(MWaXV*l&=r zw!dSp%+!C!1U@lG89x$BLP*lN#==C!^%9s1RTjD%Xef06$)0_@r7;*W>Yj`eV2;bx zn+|E!p>#LD-INH!H8$`gr||tsf(;Cxh+SG=h&(LVFISNkXc`CUEm$I3||f>Wg0|*nxZ>t z!J@v!)V1LRE&+bZ12c0LzEcZ{YGt=4o{iN+np4m2+r-|vr8UQ_D_&ay`_hQ|hIi|H zeHrj_{qU0UZ?baA<$CCOU<(V5*~K;2j4nZ0LFL8zR2t_U<82bl-=E90eSiUSPWmO? zde$+i0ag6>AclmlfUaHLssmb!J)p;UiUe=LA=ULum|Dg_tWWXK`Zm3 zii7Z~j}?!r!!mz4vHI}?95M@d&kU1}GN?A&KmnwHkjqaq%s>zXBD;GgI7A(4N&ws! z=nD`L)Hho=6Ki7!M|%^4AAgvQp#>Zx3kxgDSB9^DI1dlKn7Ngsi9NlTm4Ty)h>4Mn zu?fA5iM5&I_peMGe0+cH3N7(7mGJqJfPUza9Psh+Vc`3POzcmJ&@T|B|2+lk|GN~- zj7)#!WBkg>$;`_1uQ{z$U~Ewq(K;^A#TP6{JLZQHtq4akjd`SMY9jeXl%<(vR!QIq z_5CS(n>_<^lI1B7A^i|#Bs9O{cw;HT=H%of`qzY4KpJbWq~=f_`=&8w84!gW zH`6KontN3Zmf>2@=_uQUy z-{k>BW9ExIN9xJwjv|nmSQIHDC=mDxoO9Yq*TV}Lssn_&0r7RUzen6U`xR2Wp-J~Ka7mwq5z{QdE;NvMn{j|d%3qnfjG~GnLH4N?i*V8Ty~bVa zaF7*j_g0uBK7CE{0$J-Lp}&KF-gnZWWt(7Y*%5bin0R)~oT40$T5zy4@ zZIDQt*g89cSs}P@UAAsb;Z>npmg8BliWao6^rMB%g8KwBj4^QXqyKmeqN4n3sExU) zYGK-RzZfz!9D!c7v(aJ1N%-(^ei9(>_O9{=^SeF0T><~|q%pYIv-J&?8&<2JU(pIG zN%!R*rkf@L_7q}JpkNLNyg(&OWE!YbH7c6`^UkK#wk@Ih7cZKqWPw2Gep)2*)I19r zJ4&J5SXr?BeYCDi@0aD+Qu~}Xk7dgq3!As-sY_7gyznFBy*1+2rWiKp`c&n-QP1pU zMPlo#ut@&fuXr!HXW*zRLqn*2OfvRXnI0gtBsGm}QFh#6WD&Z)F|8pt`hCZU(E&>l zr{lRu`}! zo)i{K>iiBd$UgwxZ^)xw_ExZeu2`UPpm7@Q&ZKTl3b0ua*k}G#Qc9u12O$dS$sT4s z7Gf43SJ`W$g)Jb>)a3X@!esoS&3fGLQnY2g80%L;U8L8~Lq1h~LZ z!0I;tqh{*e@5iIsZ=Mt~$U5K(#d`=nRgDY7xcdd9DJk$IUFrPoUyqDa3P|^{VGa=3 zhgsox$ICQTy=@dG{iH3u?OuMjI*CWMH(y*+oD&jZ`P5$+GdYo_$as5NO;X;d+CMJ3 z{1&P${%E01r(Q(t_6W@Y8M^n))@rB)xBId#_h=d_E@}v_k?XHPL`8~$O6(qV2pah4 zr(U{PY^`j4nhIPz2{dO46joI3!KsbFz<4#RO1f@AABUeVQX>KqOQ$ewX-;l%1D!8z zqyafe8t-k3SShDZC{|k4p@J4EJ+)+rU<*0AlA;L-QFuez$=A^V8uN#Z4)DSI-aM6C$G3} zd%|s6_b+rSQKzXV3wIIUMg7QPpD??K_Fzsw-j9}w9>JRlu@5=c9(2n(4zZ}1cj`Pja@3ye%yb~vdYiHzk#tCohBNXe%aU9NMv3MB@?k1My;@ZbtI@eN>iq1v zjMZs%hK{w&*K=aV=zg?E68W8R$9xyd*ACZNNX0}{6(N)Dkn1=bhY%=2`J{9KJ;%wB za$P`lMNV9RZrPhi*7=M&fN(>%x`m`S#+7KLh?Aq1BGoESn9YjySPlk(DjPYMq_w@# zIiH(e-7hpLDVkRJ1VX_H^^Y%V3tze#Px^k~e^#0}v9x z{5BLN3psi0etmZT4A-^NH12k7(-bZ1({wwv@WS{z-n<0Ikc^2`#3IDE&Xt#o-zORY zvdBVW0GM)2t=xJ3LM>jXX_Nc~#!E4Wb+gpH-SrI&lia5pb&ulayoYGRt2O)yCaP2d zls<-I2je5qYp2-IOqdj~`xF^lp0e;Ttn#ByV+veH&jd2U`%-PUjP-4vv-vnT2b80y&B zzzAmcTcopL+0$wMp#C%xj5~fxo}|sY+?kjqR@V=|oE3j!NG4f77i#e$6L;}kXB%Kq z++?yMh84c5=0?Y%TuMfnVaw5|fFhP9(3Cl;8sB7^0GXA#7V~xg3i!T*d=mmu)NpWN zwPXv}dYK{DfgcT9N)(;!xUd*+d)qjHfxA7lUWsXUdd@?2Tdr$5ev>_gZ}yf|tIDb~ zzdaCGZ2_ZoIDLqG@VUCJ-0QO5>bYv8ly`^l=&om}E%MV>RgI#(UPkR&J$JCB(mKmM zderyK=+Ipa3krW4g0c1D^8^j^a-Sty=H@eHOdIhvHqo z->!ZzKWc^TorDA($!|r0TO_SeCN)*ksJwxHL6zH)g^SH-@9fpvC1lCm+Il(q?cu@W z(QD(-Ela+I=Qri6&`Br*{UPVgnoc(}{?x1&UDx8_Yh-CbaVM(EEl^-1!k3!)FZzMX z;}5eU--=lLbVXeKoEn3+u@YVsy&^k>F&u#y`vqVXkY|LoDWD9Cmv1r)jed%`2#caN zmXd!EBp*iyJVQ=EJM#DvdQ3xqfxjz{oJhBVK#XHBWRjcVvi%a>1FinT1i<3ik_1p9 zJC+`e>AmRbwRct&m^;s2?lZZEb@Rc15gy_?87+xw>Oelv<`O{FrsG>S*i?*<@cW@C>5L=SgLURda0M% zdl@#gE|n6iM{Ds9CAV?Dgc`{^GFDz3p$tMh6algl95Lpi<*?}t3?obk5O(mn7}Q7- zUklPBumGw#=cMEz^QW*9S5sVfO0MBrMb$5}1R-GTZhw&u37-yp$l=`g$Z z{qfeOP?qgbfW2y)2>L;Zu~4@0P(lsDh1e36pw?J4Arype+!O?eg+p^NzM`3r07*Po z$pwnZRi@nEjU_b~$*VQpciglEclB4kxsLK{Roxf2Ya^I9es8K~FxSVaiZg~6xTDta|!6(C4v@Bc4r|M2}fM&WR z{N2kF1zo#Sa_9!Hq&T7pIT^%i)&ZbbgkDm!2Y_-_IV+1ArM)BT zxFWm2DiQ`O6aoX64BWFL(GBuOT*TT6I=W_kFKZbJ3TqF`0;z3&pKfm=?)$3p8G(F29Xgf z6cb?&+hKx3e-Zg~mlczzI%G>!8{OyF%>Ka4=H=)uHoQlZg&j%YMgSZw0&c3jd#`)% z$Z20JQ+Oh;Y}lezO8uhTfnG_~RTaD`rlMYQX;1sm`Wu^DBZQA-`lDM2kdo$XIYTB5 zHHN&rxV*;@A2PT2hH&u&0debz1c0T z^mv|5x%+hOKdgFBZ1R+D+HZngY(`4!+U%@TEsYBHkg!G_YY)_NDXQtpJaD5HHQF)sB@{xNTSdix=;{kGk2TpZBukK{m@@-PF z^@COJ@5WrLU zGf~n{FLsat)RAft%Vv#IRl_*hKGNfX+Gdg_1H@yU`p{;41q-5V+KI*JP7)FUVvHYsOJ5+%$hY%m7~Er_q?o9 zdKvyk`yhHoP=j)rxjocAz42y>B0)DNL%wt?D};(FOBA$4j4KjvEJuU>WJm=~SBdEf zw{0u#GUaAV-;Puba*wh`)#o?e!_Kxj**CpBJKLA^c*n!BHv46g5B(Koy*slaHqzO; z!y~{W>6QFK%Nk;j>4eHw)_&Zc);7cOZJxA6r!>$~Y9ROM8`$G&CA_AoIPL%lj1e9o zyaE-vcF@Ijl(vC?w+09ryv6XZuuI+9*RXrT!gF^$y{d`#pAeFF2;cUGYg>)8DaSO> z>xJ7*>clZ3cjFWme}pIIPk7)n-Bu$c(zrMZ>MCol%c;QaC7-%JiE0^Mk>(+Vv}#X~ zBn;;Typ7M_-dP+9xm9+i*evkdrejQ=G&wfSD#)4HnY;)++Py{D4>^b@fQeo~Qe8R^ z!wUjkUZ9dn`qd~YlSo0*7+L;CG?bKrma*fBUIe&CHi43Yd6TBWhs>h7)dZ9^nCvK9 zFX8St)182~*skgh5W$dmYo=Vq*s5%$5!&I!uUs(gmpiI#r=gW@eYBE!k=R-0Hz1Rr z&+xqo^VF2scC&+)z!sf+>&t-}*xrCz{MvH$!*S2pEa2914625i8Y-{2SmE+QwXF>Y z@0!`zXT4^Ci2-+O9N6100S&AN$0 z36V_HRJ4@n-adfFo4mbOfm#@ii|zAquD)X-OybFYJ+)`Isl;N&CNcFrWP7yhEO0xp zqM~3p)l1h`tr^j|r0xpUB1p{iT-V1$eVQ^oT!?0{;Z){NFatr4lxOD^0F-@gQbyh>{l--QUq}(uu7M0F z!Ld>Iu|=Cl!)$81XH5=qu)a7eP+{a?<-rUZP=|>z=~n_JKn!^_AH^V?mX)$!BzHV$ zD_LQ9+3RdK70PIK@jIu`xiP+srC&2Uvkz$E>g;F0=z3D~-`=g9WKH4?$TNeekj5pM zdN~OwLR*r_zV=YeCBAiMbNYsZHv`ru8fK1}CtRc8*5^W*F&m6it(p1z6^Yvz=38Qra0Z-2H$9l^xZCP(@7=pL?kgXSxJSXOI+m=mM~Z#5_}Hu|2EnVc z8zlJsP(u(0ltJ?XZBW3z4~Ua0e2)iD%>@EClF>p8gC?yPkpiuFfvWia)k2V>0h*HG z!pp|F=R|xs)$Q_ZjDh=d<932q?R5>fT?KyY+#V?J1FIXEjt^41(m=Coc`PU+R~S`9 zcMq>efIDLuL)mVKaDvhWUCGy!#w?suM0tj z*^i=VCvx05xkq70Zy>9);i~1LNUgDI$6@ z-CX0fYr!>}lYMuWz{l}4hobz2N4qm+VKLUF)xOMvqa5mt}+ zMPay82va0)l>vzijO*igqU^ya>cM&zu!PCB zNR%6C56!x>Lcc@x=ay{jMVSHRz5~r*K#bUWEIy{ z-0Tvwz6O5?Z%6Q0IBS5YqJRy$g9b|EUu1 zf#G#QscmCaN|qsbZ7bj_@x*VI&V|F$GQq-Ts|a8RU`7I61@Xa`6u)6>Ve+H~)h+wu z-B=ep6jw>S;X{HwJf~^dYReyS_}%Mp{KQ~=@{h~*L6cL@u+h@#{hcA-=+&|tvbOHi zaC5nl(y!Mk%!;@opM&ij22;gpEa4d5N=#g zi}53gsI4dh<);jzFe{c7cpP}KUPLYUkH&7vD;nX42kxlmn$aO1cio5{AlQou)^E>2 zxVT8;3m`NfbKfilS#W+VsoO4q!hFT`!G;F0swd=4)1Qh*{=D}rD9_)U0Iw7Xv&H~a zpERfmK_&4fsb{wlKEE0&z+dpyKT;_SAd6zUU9&)LP9C4Xb0-)k^ zEaN#w>5iaf?m04zmcN1wSMQxG)EBNAPs`tO<#G|w!UsB`;RbNrG~KY~_Qq)Hbn3_Ea_hlfc0m`Xd&3WT<==R~IYs6SN!nGD)3O0<3!gURnO*nl zsW+9wa76b7sK0dHtF1C$J^HRQL1*_J1QxuY=rU=go$KV&-rU4OaEX9Df0+~hIxP`C zX8BW7(nEZlK_?tDEQkRB1GYC=4@X+*E~Wiu^NNOhi7)kDR`s2mp%{&HQIrMh^fW3~2toxNO7Bkjt?=fT2G?gGrRjv*IQIwUcx`eOZ+GDJ^%_13dM zCZ!JJfg_nFR1mJyau80kN6cZq_he{bf4*JXC?OzHj*ZOkjOLnYoEDNd%CjRSa zHquC+r$coiTh;7k%u2gz>ii7sq7OHw46LorHSf%`4Ue_k%im5Ql(jf zw^N5lT&vPX6@1xZd|4^@JY8X#u8x}1{4P^33I0tB-qh#_KH--AGayHQPQHLdBH-dN z&lPUe>}z&u7^W<>2X6ezm_w2h*jBAZUwKo&^0^^R3lZn9y;xSi$uy&(kNLd*crVhE zq}Vkvu%G)puA~A#h-fhjw9UR}X(U5}p`E_>itTSl0A(P^`j`SB5&+T1=&}vj7STt8 z#L8^81Z9}e#qt#DQ-WEr9H@1r+4HX3#lgFsTaMAp7hBZS$ZLI|NAdb|xocAWkFm6u z>3UulZ;h?b4ufLylRox>Y<#biu9q)(=iGWt*nu%EX0MOh5&5y_W#xS79@_)Mv9}vk zl_doq(wl2QgUI(0I{P1F?a|m01sbcP_czonMQ(g5+&`(6Wp_=v4n<6r<>ea}CU#ph zcw@kv(x~G>=itbAhnXZ21Y2P(M!)tb8f;nxC}ZW1W+%SUrkU1D*+c&ATz^6))Kq7>INB&R z$&aoSQrw)%&?1jax9OwTlr2HoSTa;t9tAxEK9d+eU2375GXxRNOqi@-eKcEm(TgIS za#tf^-WJwni_{ftBMi?KlYoV~_Ky5mz7J>8zCeMuvIx17!q}VFi#6rF>*X79IaCpx zX6G?!o{W8fy@p8}pv;jT)S)9BGbj9q+V_BB9W!2HiRWV418mpp&mWQss6nt#>(@X6 z{lmh%5Y%B)^`?4 z@Ei0-e1%0uT62aasM&MH&JUjMerhJZn*oa}r(irE{tGQE3n4QYP0M8_&DX|D=Z3n4 zjq}&D*Y`}(XzOH7OVI)w^IE&fn})7S-RC6Qk%z@58guyqRdW2}ORtNw;7GL+#nT)% z+@SI!<3=jA~h#-gv*MiM7X>6H$G4HU$qOAje}*ed6Yap8Sq zw>{AsN9#qejrmnv96^^V;=&EDrLy)sFGTK+p8F?{V>D>7L!Cji2usJ&3k|!VzOA_v z1{Tp3sDYx(afI`6M5a_vrkP-I+$p(w4VS+~3aA$8!tlL)QhVek*;#zZURo_`47c%^ z!Ox)qnX4RMV+O^mgk_psu8>JA|x3eOcdb6R&1o66q>_n`?1-Ic;pm# z{2vD{H&V$QLI_Hl@|Bw7g4I+qxDl9Q0>WbP^0 z=|U7Fz#mS`t1?~?sBkCT*@B{r+rVaap$de^AG{>ZNI$xhf!A1<`R9B|^jDNueHn~| zWiv9^;(?tV#S}`9$Q2e^`;=>>t7jJ}MgDo=8%As~85y;A_f(Dv7bR|=`T5$?XaPbPfLew&G`2G4_i51DVZaq$paZ+A0b3kBzb4$tG@ zax>InY&@_{2iuC5Jvg9RLHei4DAv<~w_3^qXs`<#YTeBSD*AiXR!C(f6k+$Ah$0#a zh$hzGM-=s$cIV;Ah4`s?K8Ab-L1c+;-d;UDOl)WN`B4{esXdj?@7$n^w#!X@00%yX zXZ$yQy$w~31O`4|g2^5=jon7qd9yRIfA>HL@G`|Bw4%9-DJNxGi_&_Qb%(W+#P{d^ zj@S`WlnCYs!OafvbYSD>sr1|9gRj9PltbjyMcv(>b`%n6BJ>kQgg`pz4@8wAcHgCp z78(__Oqf=9!a%m?swN3GmOvT$#?ONh@=^g6QJ2}YRXmYUha3w6Z5V0`7qX5}D`K$fl=iU^v68G7$1>|sA=tO-&XYWfRn9C8c) zwMP@A6^*k3SoTML0uX1O7+mM{G}j9w1}5+NaHmh;`XX;rmCamBF2a`4#S$9bZ&@>B z8RAT1SyXMIicPfQ3cL9QQ*EWlK`4a9iIVXa`-U=YYRk40J*N)s+eR0)twlOw!JOoS zGYienRn@#FyVx1G_!BW7vSicQ=}4babWwBLvuEQkoL2>mjAXx5;KG>GpTVRJ|7 ziK>IgbvDLZ%2_fMY0L;UZ$nJsi|A{NgdcDw!PZ%0Y&q^!I|E*mviM3qqPuvRFni#6 z6Hfmf4Nuav>QLPAgmUok5!Ha%D1c0qF|9|yQ?jrqY$pLuFY>`gxHWYrsm`6N(R|Dj z6Thm8X@V;q8uQ!dA7YSK*WOlDUZb0=zW-47vICPEUwPR<7(qz3ocOWY+9ZtPi8d6_ zY0_ue#k=o8o%JT#4hVrUyYw)BPkhE7Knqp*`T3j0=^3L(Bfm9m#_LpJnu}iQLLeQf zzh-VlWrL;UYyD+Ft{%8(2qE!z8O{}}b0HB`qkO+HA`%=v#KCP_Q3fUWxPN zDsJcE$}M8tEFj#1wP`+5+wz7}b8LU9k%1DH{1p2ZGq%JDWgbiFB$-A^XEps@vQdn5 z_Cg6Vw_Mk#`pFSss-VL;V@C(w6gQxIZGwm(P# zy@42A;d_2=&_uC{+F~qWG<#HzAtXU4FXC zXs2nb^*j+k)tdzMjIi%_5waq_h72*sKUG0OfHOj>a~KoQ=4rY)A^o@ppdnK4%7{-9 z=vFt4&^iI@*Yg}5SCJbC-p|^X5PRR>Pd~qjzPIPt=Gkr+9f^~pTl3#ew7?l+2pz;~ek z2WLQ-zq-+0j=OGU>qZ!iqg^R!N!yk6Mm9M9*s%+&rFWz4;I5&A_5!($r6rJL@AH~K zu6MC5%Zjb{`M#g;^L;k?H)ze;5&ygLd&;|hzwO`U|AONKMUUz0^&L8|V`?$p)^P}K zs)62C3u;AIP!A25x~`%J_vq4FFA4aVKNaQE^_8f}7)=zk-+N3TkE!zmrb(1(GQ$m* zbV@iTRY{x_fQuvrE|QqNO5^i0XYNf2RFxe3^-VM97tdr}8bg=vZn~B1ZenYvu$z;{ z8ueZDkIh_=4Q@y5W8q@x^T^fERqLknb>u1|&yK~CQNVR(6xfxCH+*>!f?YqIeNDsBd#;`IFuMyUzI%EO?JxiMIBO6rs@OM?;t ziRMVWRKT_z^J%Fdw-uRetSw2b`$&<3%-mt5)i=)W?jH_amge>TY!@4L;PHSnnztL{ z<>1BCjB|of=CJjEGk)UgGdnJBTKn;H4Zj$BqQCIXO`CszblaALyMDX(&Y=UC|5@D> zF3?xQ1<(EMFJ~{EI|G`{q%K-OISW(G=6g;IxnXW0UoX_l3)R*9I$^!MTJ?pY3$kU? z18*K2jd0<)Ecj2M&+3hm@xjTF@$Qu1?C2D?F1S20&s`DxNpyv~McfkZ<$CiBWMf@( zoVhm4jlAvZEk>)s83xIB6$zc>-hdrD87>?O#qeSvbMrVeUDjcSi%aqCi<}!_JrWaLe zxF^;pXZLs28jZsbrMjZH&{87MsgnU)l1vnr04 zvL?zudNOt6gX;q~vGv(S9Kd(4Det_na&P}7uFgMk(Th*Nju$zH+Hs7Uy&sPp_}9Q~ zqwx62HTacXQ`a1!E)t>=HVYpi2Wwt|C1X7@HZm^aMK(l!?SD;sUGqh?ky=}%BSIoj zkCD+>W`s}U{kp5*FqgDKgcp%=z{1vG$RkdIAfDStZ3&7veqsh*y`&q+Vu0F#KP zQB05pLZOjx1{DD~D8-T#1BbOP3+jn-8I2u$$r>I#=zE{VutRx~5AjJ9N4;1FnBFPe-|I7V>g8oo>dDo4VDr3{#XP(MJ=KAqVr3DeCz+iIbyu?!-yT zNmJS^E>D+dDk~@^)Yib&!s&3a`Obj@q3Cm)XD!d4IAPwj&QAVUdmGnfY8D57qtrC~ zaPQs6DG?73)bU?YA_~xGyxwb2Rl!QB32T;GZHe-T$cU6$YNd)NsTI~EYK^r>TB5E| z`;`BM17nI)We*iUR5q)uCDodeD&iHRs!}y-O}u*4g7|__Kay6)SB`2(HK#6>U5no+ zzFB5Ewix~+_jdb8Hzcu6ViclrtdBIK4s;&T*vf79CJ3&pE7e7=U$MjKL|RGY<(+r1 z;doAi)9jEGEjhO^#ca)Cw&vWoHHX=nW3$hw8aZ2ot3-I8vo!}o!6UHgosBw9prTmG zDZNv_tPkoWrdR26Xrp7q=uyyCFM@B=UHB%Qd7I9>O^+l~8{=Sa$=YG|cB|X?j>GkL z^=2tNUBFKlyk>!zM%t7d$98f7vW!y0<$TU5Pn#ACp`l@B_xN#j!qko1_v8ie=C)6J zetO}h51%@+`qS1wf3^R}_NR{?duq$kCDFRXgjLHb+kTF-pTCOn-dCINuKl)i%OCjB z7dlRzJAL*vq73auh`&a=mW5Y*fNZ+)!%l{Wv4zF!1S#jM`I8!9rzSg*jN>!?ro{^w z>8>DIs^U+`Ub-SPDB}(p+pNdf9>^e%WX~2zAj4o`Lg8eV?c^w2N6+@=B#|wUM1}^V z!tcro-~yk&2ep-JZD7&KRAk!h9-G@>x7uy?piOMfN-$nMgWf|AT@NaxJLd`_fEqJY zIPe@sX)ad!;HMF}M`&Lz4qi`*)=$sO`#xkr|e9FsT5 z&GLbJr>@9@vJ#VN#*zrf%Od{_Mxr1RMU)Z(A_qt-X(Juv3K2U<58)6gBoe2o-G(ol+YvrPFZCHp zK9&PgKFaL~Tn}r?6zXw4Ry0 z3V5Y^f&Z4)Mdem_`C=|xiHpQ#GOug@6?#Qp_JevN%vi8IW#~X2I-n?D^9=aMh5VBW z7ZeLa@r;iSXD5PX85xE&`Wh72i8wpqJx|Ywga|~el&4cE#P2CflqdO3$|e2_Q92^x zVzE?8_$G-H&NwVZv2Q}2{>bc7+6AvJ>DfHw56>G*agwhErDzV0;6Mew3KFBCzi1x zs%cvTM6l6KkPsn2tr~4GR32(3pj%b(5-BTVbo_y$j$&u${2YU!i>-Uky}tLv{(a~B ze&5IQf+UIfL=wfAz`F&3XIM7I$!?C5WxQco5#epg@q&mMOUdj}A~~xF zK|0XDwv=^a1Ej<#I)<|%g;LZ)%pANu(-VRFfH(z+Q?QdMCnx~K2@0YKQ0@ICYG1&*;K#%D6 zyNGxt5(W8!F1@yJnN()$0C)V}oUtCt$FXOMpi{>v8>SgqUOYNB!3_FGdVyj~#@JzY zSi0u@G{jxxMnbe#3`Hc<3P}tT36%35Vkrc~N6LJfJQPFSv7Q(m!#ZYDJRkXi0MNN-~)24&N#8SA!?15mb{Ayrv z%agCxv+@V|6MU8lo=X9@ zrGVQ~9=I(9NT7t_4pL!oTMD=>eE#18pbEGxg}5=0Lj??-g78~uG70I*i1RYXnykstwH^bwIWnN@1?K&K!zDjvxbzak#f~v?FztNYz%_Zbk!;69Ofd`Zf(d)% zD*n5T)tLA&+=CyuFoV}6S(F8t;kCHV+b!gfons)6f0fv6yoCT|;>Wy?K-{%w{iWr* zpVH)k@vG*o+t0>#9h|*p!KBT(b@UtGZU5Gev$=P%L!oAke#TZ}6m66btvcc{$uDtX zCIZPEgp%vX%m*Jh1=*+0<>!gd^UdP7`BqU(YW2=~W3oA0Yjidmv&{^bk)F}A&aCl_ z+0L~~En2&?-Doktk3163*_JZTa?i?3)z!>OZl%0hmA&Pxpkv8!M=i)c7Hk87q#VdT zf=R9l+St`Q1El^i0nb1t1P7Qv10^81qOoL+fG9x|LINX9yn;1?Tz?`EN!H-GJxZx| z5__FMXBF@*2Yl^-Z-KR-Ka>For}2_R4rpp(S#l~7*X%>&w2nk}B%3Y45+|e7Z7j7o z$99mmB`x9>Nh`P&5=(j$xy7YT#h_6h2t`zBD4Ny#larqyW7DlSujFqZ>+gD_|M0f1 ze%gg9w{OT_%bmOR8VVrW*)wPVcJj<={Dr#mt!xEG&`AZ*iu86>`kP%@MTEa7#t=HzT^R*?~r^+pVUQ={CW0aQ@l{d=m3T5|2hh(J5X?eN4MP@?) zVF=*FzU@X@AwbIJ*!jJpq5B-L1ZPJel*wL;kYdZ7$W=?%I%5=p~vdX7CDPNc32F9355@ zo;rH6`UE{kT|&3gAFH33*NvOL8`gc=fmoZntXvW7yt|ymzqmZy~7~2CQ<b}mtZQv*h+;j6$<9Y_Zz=}7{P zcQW>TC8#jf<99vxUj9GdJO9ebjy<`GKW<#N@8E{@d-JWdIIRgyKtfM`>%Q&xW-@;| zckVBzE_`%~bhvF8n!jRHbn1ijw6D96#-a$DWM{IA*q7K&mX~x<5+$2UmuwUxA_XWx z$x>Cfh{SNngy z{r<|ispV^P7f2OSqn|N-xC%9lH@%4syTkR;d}&tn`S8l{52fwW>(PC#cdGx)*d%Y6 z>8)w3{>aN&^m8<=O+vDn5i?Ro&L|l*V`~%Jq&B%tX;a&51Mz`MM`b)(867tzx5sPc2)1J>6QPW?yc;tIvhV4H>!$GG+dlSij!z@QdLNYWA~6r zq&SHdCw`nO(#}BL60tI-%4}IE?qQV){<5R=fppkcO^P4%rF;v0%X|lYANqKQFX;Op z+0`B!#c{@G=Jqvn`@Zu%ZG3*5ZElH8>@&s*sTYw55*J(^B^Ypp+6F{Id8I1QKm#g@ zNtBSJkplD~(o`y;idqb|F{HGXnnrolid6wkP*E%ur3l4R8d3fT1^4^r4wts}?d-R6 zH@man-;N_^50%}Zh zv3L@=S#ky|HT#CHlg_hG?cUj*f90JcJ@e-lUS7WE+-mQH`Q*mkk0%l>+5Nviv~uG+ zdp`V_K2Z6@_QxK4pe~hfeR$uJg}a)ngGEnmNG)5ttfQ{7DkkdN=I>s+`skx?Vx87c zeZdOq5t1Yyogo5pu&$xVF|zZ)*qf$=nwFpul5lz82x#4rsN>d>T59=ulTPWzL;Rt2 z`c{3f{*tZ`U{0^;C-hN$T-S7L)`(SlsaZ?oi$TOJy`;y=hD7xegD!D0?EPSAWolMp zmHJusI7!ht1MB}sq(b|h1b*yZL4=>|0uvG5Yio1gL)jVx`6T+Uq1~$keD44xtMlUM zdgf-nI`5mCX6@g9YG^1HG|l+=QTHp4z0SV%Jk>Yde&P9BuPmOGK_C4PuxvtUfT#DI zAsO%uuSgbIE|w@dxZ5^AUJPQi-iRek8cRe0%sp@uX-ni&Nt6>Asa29vr6hfHKvK$1 z^gvR=cXC>vB&9w{BD_m|l9YloiTcDse@rFmXp$zEWH3e*C`~e-XV})vYnc<7sf>~_ z^L)B-a7uWNkMjwx@H>rzPd5%OpUee5mE-+ozu;1vaE8z3OVX%4r@aluHTnM{1Ud-% zy=z{nbI2mfD6VZe7SnV?GgJeFh+<}mWq4VFGNe%02mKe;*0jseG(vFNJV5*7mLV3 zv68N2y~ZlOo~~ybjg5RK*+F-(UB*tnL-f;r_Dtki{ebZt{~0;VUlwnY*Tp$*TpP&9g!jl(L@?Vhv*@p;A-e6iYlZ^aX^#r&f$IV)d^DM(7`YY zA~6(wfpe11qF3ZBQ&lqxVQaY@fN$U!3&sM{($ytHnGHLHZWwtk;+zW-VGM{#oKo0` z0Lo$*j8RP&JVL12Vp6l#2*Z%?<&2Ne>`dT}i zuk<0+K(^5}58<*4O1EEa4*K`J-QS$TQ!fyZAOJ;lx9BB(y*0EgmPpR&h_zAr>)V@t zcO_q)3O+k?d$ZDTYyXBVE564LKypBKXoRSzAv=7fs+1jPh>y%vqK_sUl~&dm=Lbzo zw%DscQNi+ZX6cL3LEDvIKx;+I3+1)&B9xfGhN$L%H!M@bf-*hI6rp$mFT6WI=RwyQ z8*?v?x#xp1%szB5cARosz+%Wk1;%MXnJL&K-Wu_2=Q~>iVLhnLMUtdD>SMqG(YbwGH1Tu}EC6G_uhuP_TKuU<7uNwCnd7_uCIf z7HXls*yxTfa29%x_-mYH{uBDQjSc=T?fd$7jWgO=XW0Lzc9SeS^Ib{iQiXhPAWyyUIoFV}4b+>ipfmu6@ZXqZ;nml%p$0TaJz# z{c_r7h3zOl@eJL_>rUQA8E5Mei<)_BWa?trfhc7`_7$X7vuHe~iKy2g0&j(~Osw@b zdAq&mJmCoiauLH(3e108-6v^nOK=@NcTy-oZHRN;vg4Lz8z6TAVZ>oMQKu_~Fsl2C;drKP z$?f@oT^i$3l_o5p;`qS}-xfz8>-(k8bgv_LzrP zQCFqw)U8ll5h$)>L-a=M#(GJK(u=S6^`(HB0ev==6E(}bPqZyvEoUbN^jvAyhuIl&7H%{QR1oeBXf=LPpN)4sN#?S%r6*0_ ze0p6{uJfiQPKlh7Blrct23@dL-tGLb-$`b{0R=t~>x4JzEjP362qnlBK?+Jhk$4hI zBB<0w8Y8s(_FHF>=WFTC)y}KR ztHu%g$Ihras*UO&INS*nota3CS6CUho!%GSM-N7g7XMMDSMQCkvJcV2;&Ajd8!_LF zzHk4@y%f3dZ}!UuHj3j4z;9;Hd;52{dwX~Go$n6THvXYUZ3qALf(eWH37{GqFtjE) zf`bopV0_plCeX-g_aYO6}Kr*G%Y&(6-hdHdcQ`6bWqjH`+{{c))pm_9w^!Nfvj-p$J- zT?Fa@MWOhOFvp9QfNqEt5qq;J3T{c3i73hiE&)?M9pkx&=(@*HF{z*)RnQDY)Tyo* z7vO?SjdG9!0J1L2v<-E++_%R$s3ym!f(6D3lK8($a;tun{?_M~Tk<#P(>SDzHvJt_Zfr#tpHmYU>Slb8E6$=n0vXYNb}`Y1A4$4c;R@ zwaTpWFDvXcJN=!(w3+s&gG1sj&yeqdzyraDJzw!1G!Ob83p}Abtv+j<^_>a4q5LuM z7te%oBQP1AF>O(Wel;3#>5KLKx}b;OU%s2P+ zGb~q?fT}8f)6_IoWD`Kth|-$qxhRc}&;_S-)P)@wp&homz_d+zpLx!t<_KwdMkl4P zB%-h`M_aa~)oN{;(5_8tRKpP`Yjo5NT`(N6_Ml@#_)XD4QgT5v(`RX%G38l0t z;l;1)R50Ny4JPu|gPsO+7&IS$CChP}*zZ;fgP{uZ;4cQ|&1qg%id zzc!rfT{x?D&${|t&oQHFR%DwVb5%_o*|~4eF1qdJ3&&eJ*RU+73VqLIv@0(;ZhOoT zdQqY#nQIo+qYu4g%P5e$Fl)uyd3yy4vuTxFV~pARo+dq(r)`Tf*E%eC0TL_vTh(%$Q)p zXxtcQn>&HWlz6jo6_1EleJtkZQ%%GBd>r@Ci3CnMhP!!cHmQ&(nbw}fbcwa|rnT?Q^g2I+ zf9|GlOXP9sdlDU#9+K!Kwqv1iI2w(yTvpXFy^a|yZ;nl6d#lr7G&_;hm>!BgWz5Mf@2FigWP823 z==Qpe2w>(LA(-*++gIl+Yp83eZ>*bJ+~xEaq)rAQ7yLhqu`Db!~HJcltizYDdFerbW$ggVuK}!h3t;8f0orhFt59ca zP*0zE6<|H;I2;a#!{Kl^91e%W;cz${4u`|xa5x+ehr{7; zI2;a#!{Kl^91e%W;ruTEFZ=}W01uxy4mj!Ik=4BVkhw`$B@{jW}u7|z=$H0QQP>a7t zlsaGwq_Av-4D=yc7=j&6%Ob1|pv>-F*q(MqRAbLV=*6D}tFf&IpU=XeQ%hl)!qL0% z-i;#{qMXKO+1Ru*rVGhB^L68x?N|=LHf+nl=8v%!Hfx_VVQnY&W}Vft(bdPSxwW;8R>zi<)tc$cWQTU7tVNlD9hrfy zY&z3dZ7uBWwN|Hlwqysb)v3YMz^+txbz4hYTgQ_4!hv*GZ)?X#)ttgg4_aMTcA%>} zwY_U#o0Zvo+xJ=NJ}ZlTYx~mKRJXMz+m%h>!+qT~nE@+&cw8(3K2Ml#XI~6I$Y+F7ydH|JDR7lda z-;s&|LOTq}bUU>@kSx+52|!(>`;yg0s?{Y+Znf+y(r@m(0qWs3tcKU%5AY_o)2!Fw z5H!JikO)554mGeD>ZqDbqmk7V-4e3j2b(cjHId&tslx1pR??jcOQ`Dg$0YS7EQMNr zie}Y991Nm(O(HDT;RLk+%HXV60V7}nAu|t`seoFqHmR3kHyq;cshbcBPC{-Lw5o5k zPt;!_lV&^zTj4Bj>T!S&mCt*58XB!;G;W&=Dv@%tsTA@Gfv5;2X3XO1(s2PsJr|8hy)yt|Kk|6`` zC4ZXWIJWS}&E=8NgqTJs4S|s)nG3&%Kf(z#@eMXtb7)zbM|)Cz2>oCf<;_&sLo@%5 z*Vq!GrTkq{pvKZWqZXdE(1v&5JUVeG-iP;-m#Zx(ySNn1I2{Q#Ya zb+8YvVIR!FV*DvqVGY*dv$z#o@dRFCV^}GBh+W}Td_F%a#u7~ykBSxAN^OmPDH4dh z9r++~O=YQ-P)zx-oUDHic93U>pbbtForMdiVJ!9}GSG!na52#mT!+8Hdfbamw95&+ zfM4Q2@hVh`af4p2vfHE?HH_HxeD- z=Y>Po4+#`QC!sJ9 z^2qvfqB#`rEtGMu!zpwSc1}#ke4IeY%)mJ~9~Tmm&)_!P9kqQw9wC%I#w%oV92*d| z`EE9xjb--{J-{m2e72EoVomHL_8qtJSl){#@N_Kh>uCLUa^?%rYWXrcrvK8B=+cww^+CGd4 zQFgus2jI7G+lA-&a_;8`U_Hwg$?P~gPWe0oDtHm2Ol9@Biamu*Y_PUaAH_!DL}(Xj zg!Q}ZCH5^F#fz{IC&L^ztYbC3pLms;Jn7Dvdpol%GYL*a?3Tc1*;}Y!9DAS#VV3YXNZa?XaKE$EV-`^8?tg$E>A1o`|nfT`0vY z{1;ci*+j~s5&Sb)0S~cH;4+=#RqzX}5VK)DWMd6ngjeWP4ACCe)Aa=W6RQ?s))$+A ziM{0ANF0n@>j%%^biPf$!cJ4gZ4-7l!+%ZIx3T@aNVIDuSVbq`DOd^f)pA&*1;k1E z^5S?uq*9^X3^hDUxTsx9Ri%t-+Ce(qhp7&X;YBo(M42;z@?r{Ah;2mAQ=Jf$LDh7| zr&1L=4o!L~YlhicPo%0t_4rt%1g5E1V5^!9535a(N%f#k)zFId@C9sudaR8srnkq|4AYJFIIOmCslYOVS+W%pfFVYk9e z_z8SYUVcM6jOQ(o9ht})Q~{qy{+@+mwMPv^J5;Hk(L41B?6zr8ZgW$NC7vXI7egg0 zQIGM;NHyWGfl%-eS_`QDtoC@Pl#cO?&i`@VsN9h`BZmJlJ8RfIL+{SaaHkKs>j!D6 zgUvxMW8j^43`lV%Cnfez=-0PT@AzIl;~cT}9x*mu6PzJr_|1ZlA=5%qq?zN#XIg!; zoCeBo8wg4IERqG?b)*rBsu|riJ*4^Ie`$I;G(BCK7;of3US@{jHx1e9GmU1PRvaLH zozDy!@^X|fit-zyd>rvE7fmqyNmV{WV#x5zg2$`E{*aHBYlyXbO>d<=GXomzvBbs_ zClk$i4VajZQHCY@a~l}M#F0_bY5M#!+4NZ!NS^91uaJ|91AbqM%N5Mbkm#Ld&Xiz| zmA%|i74Sy4k-AsfqT3kNmN&4*Xvk;@uWgQpnIX5M!mKDS3rJobwD#!jrhR=f@yXAV zzVFiFeY}CX+odTy>`$sTtZq15XUJa`2X2?TtYK??xWbYyWYMz7yq6L} z8nXt~GAWms)DPX@su=Wq^74>+U1v zog;c`{8g}6D^I#ojpVm@>2}NXbSp({UWzH%m>=yA&&+tdnVIIic!L^(4<-?|<-y#c z1i#B=1$a%f2WC=7E-Man^bMGq(g>cR?x18LOVV;nk}$=REW0J?njSJKlbfP{DidT( zTGy{veE+`ws$7Zv|A)A;LtZ%9EG(WDF#O?AC$@#9-FhAJoGw`>C;NH>JcV^~EQLp< zl$2#%%2p@fkRp|SdNipknr$(ZmC+G23S@j}e8)3rce(!0NzJO=niXxnpVn!n%yoC~ zkLuR%W}YL=$zXa_7M4y6hwcC2zRZKGs;@YH?)n}oCM;TCP^n@66)Fc4LOPjsmhpZZ^ZLWr@SKevJ~RXL0|V_HGTQDb&q9ZD{<74$!C|>e z&)j|{^bd9Fh?I`g(!rj;1iAL;;5f8Pnr?B_#4yDfA=S_-kOOAgFUh^`SH!|zPk6`0 zQQ&!Mr@w$3-Gwp(-a^mW-X7VYJeY2>ay{=J_SbQah1i>}*8V_-+y9WE z{s38me@$ThrJ#W||8D$Yq0C|bVbBroapObF!D{yUXJjX}4g6B>brySltP#Qd*@NF+%u3R8bC);6KM|wr6^T~sZto!H zY{s6gvI(1h(`~h{a$7CWYYyJ=#5&?N+mD*(4m1wyVCtPxMf$r7m0t|(qh2#PvpIOz zYYhU9z)cw5p}rZk6SUELp&}QHJhiAC($~t`A+5=11rFT-=u;8u@FSYR(UR zst?pB{$398c8Cu^8-6qmpX{ZzLG!bz59DaDJms&!sdoQ7B2PhAMgAG{)2f(%UKaPu zI5o9}{2s+AdaR7julZ4PoaRW)bDC$O@o}0qzs_#Lk2Md!Bo$#?Uln31I=&gkK6#k? zE(-#`IN0Xz3AQ`kgYA9+&wl`3u#Iy+)Lv7|gR@~h9Te5llw2;2>ZmtD?hW(VR+Deu zmmirrT59y`;_s9t-f8Zg9BB029L6B_MDHrM5}R+3)tsZ3vx0a;4(6#%%w33Fp>;uP zqO%q|Yb~mm8s~NT1)V!Wx|w=0PRh{zh>=lKm8#4ulSco96u2ei+JmxC?@G_1`sm#! zACRueEb>IFT<=q}K(4o6__Rw3Z{1v%H<@T%a z>!rdS!~9zLhC5#tJG=3{-^(TL9o#kZyzk*B{h9wh>xQu2k_xAk*jmo>N5KvqXZF|= zlquZFGStjVgV8lYOlNxlx{I9{tQYbzSD^7fwD5c06z`ka4e1XRT|cY zi`MO8!Tl})Up4l9PqI=zB$r!9gJaNA>!@Tp58#6Uekgp8$ez(XA^)L~$L*(_1Y+k!a2UMszuwCdd=+E@ z{}_G9IQqy|`jcCwM&t~+`v$=k<)EF-;caCg}`=m zWOLY8_CogaaBebOZ+2?_>EDQ)Itg~B=AUi?ck}#jKs`VGXXta#^^AX)d5=M#PrW}g zAO1n`Ec^-hdq6qQk3+MdLqHGEo%!n&+K+Vj4*kOE`M*CtFQsR>9X^;h_w(WeBxDve%Y-AK=^)=6mqnII>mRgC$_ z&I?{9_hjJTZG0PTRlr{kN>d14p>}0Z>kg22+n_JO_lCAbH7&}m9dc|ZHSLS$FSJHp zL`^LSF+YY+lSjBd#1uum7GEejtKAn}%Ri+?r`PHKmXGRugf3&HK#?d6S`_iVv_l`z z3Ex?td!c;1@3>$-)|W(l939@reJ|=~vL(A6vADZX=(mNt_mkc~(jgwl?eP}!*l1!p z$O8kz8rn#{p#Kkg18P*T2HB&@kEI~_Gbw=I3#gm_VZB^nt1Qnr{+#dH7FoHpOWP>8 z&;hd%l|&ti11lD+2<<9Wk;&9U2UBngaSn~BpasEA#4$u<;Duqq%|)kzCT#P58M-A* z&5Rlq4KjoALe$#x?)SXk`<!~Q;Vi-@=1bdkP+ z^nlKxB8GZvwrYa9lsm{C&M84Gt5o*THlcL{klig)pu?%-FzPG zgdz>tr#)UShX+WPlP<>>S40Ex+vDXA{J#lXhAqRtH$xk~yeWLvbVUnonMS@f1Pf#m zeturCi#FdiPvO(&201B@50iFc=VD^$P`sa@L{((GT$yH8`f_P+`H zZ@D123EUbNk0tGkb?NF&3#HnG|L4FY-Diu)U_Dp%EG0|}_t^b9L-#D~&mAt;{Wsfm zeJoc|-jnKJA8>|roC@cw8kQ;EdhX~v?h0oxScPWlkR=YvnoYLerMBLLs0GF`t~UDV zFzDm&#N%ouvd65($^R%x9c~bF|A;qe~KOwsbL*;-c`X!^7VY4 z4eUSsigc}=yR&w!##67Hcb(1=P34ag;aiD+vg#|=&6SNGm4W zX5O8a7tjj8effoBmg03}zQ^}B;XL>Mh~z(cW8@J_+D3kl%H-pchh zj^6Tz7eoH=Z($t0wL7dB@`oK_d}kIz{+a*BIC@*>+G5DBJ;XSs6hr=$;&I@gc*o|R z;cdDV`PcZ}q*~vBO}kE5FqB`(QHm z+^X*K`d#N}>pj?w@!`jOABt`1Cij;F^Cb3<@CG~!&$<6Y+eZD9U?YnUoDfZ&waT^tg;$|IJ4RMJA>~VE2E?S=#aalUUh@|@NkwbzdXzmn*@D= zRN7ua~O|038Y2W#Eh^2yj-7}P4j+M)? z_g~k+WIJZYiw+BdI`kNt$;RuSuqIhMo+%nXgZm}$uM-LP5xdWjk#Q;7>lj&DS|uBz z{mdhxuR7Ir`L#dR?~vi~&*ZqUU51C#*rPgh^LwoG*;1BTeEW|0Vu{1)rW5V9F_>-j z;-FxQR9Wpn?8@7;jSg88UMDL!6QhcCO{$~vnj*A&JT2`bKOd~d&;0zIEzlcw-N|nZ zDy1&0x%>W0(7QCz-SGwFzY1HE`>6Lz^X=UvuWPN#|2bR(bCU1+%`8g( zckN5sx8JTw%6D-O%?g&yQ$6Zu9d2ew?Z=>#!5T!c0*iv>i8s*x=T5YKIK4ugP-8EIJGmQD8z~1J zH~VAxG(r6nWd}PV*7b4N0xvjLDcqGB?(OIPEY1@Y);ZuD+``*bacRAaN`$hDtCD-b z8|lLYIqzWW6VFP{UpyjNr?68lblPh-^XRYsU2(pzwzNq$T3^sAL)EtsclDkh8~jb$ zdTKt?!nvu|yFr``DL*h=APwG&=ALjNKH+2YT(}4=0Q9xQ@w{V0qW#RDuqWAd9wXbZ z_ZPz3c8H>7=x;vU=k&Jf*eeopA0+wR<4S$6{{{2tlxo!t!FZ{*`elx^L$$w`@8|{Q zu++a$PSu# z^NS<3FaHw!_Q5MtiTIcPh!h94_O36}BACgLQDF9B1=8IVWFH9{hmxOW07dFxvalu_8ggXX+*E zJtA2&ahCRya=UDugh;ZPzuUgDem(6`&f}%zqbU4J_dnwMjnvzL0-?Rk-lQ%2EiF^p zT_*fU8p_(FAsP(J%=Yk9vpus%#s<@6AbZ*$j%TlTy7zNLAM+{}5}sAtP*L8_Xq-oNx+ zYfkiP%yzFy?7ekZRo&J%jC6;D2m%|Bu3c={q(})!iG*~A64KobA}uKhhzKH$h;)~P zbV^D{hje^vd*A2Q^S$?Zp69);^T&Ix>rt0$uDNE6@f%~tm}|^ELq2|5VcUM-$TLkG zRZ;WY^|PG(GOS#i-~@-5f*T*nQuR zDjt3+c7m(RuSRV?F1%qvMbV!KZRJy*-^3kF#-yD%g`xSLD4X`BcFSYmG7Nrk)JlcddNQRn&+ zWkpm_U`1Qt=AHo!1qE}^(mm1~z`mdDYb9W_{)QJzeSN&ZeYS3!yR8R_^S?=9b+S8JUj)8RM%Aq}!8()SZRu^m+Hl_YB?c#H`e?kk>?b77aRU%zb} z`ygPPtc^P7fkK+VID|zWs}`?+uNJHAWevBf z%kI$nWcH)8vHk~XIIHu4UZ zYAM>mcf$MV5=~zMI)IIwx)~Oj)IP?;fjGk$&B);UVtEL=V`*d?ogtMEP>{kurJ3 z_L|!p&kI}Y+uy2oqb-Te-2!6?k|v(BAKjt9=7f6E#o8;4xEQ2GJG_?DSh&NU7|~Do zHlx$QjN?0R8}*F*&E9LsI}%E&A^JUU38>Lz{8T{(ds1CubGTqEFLu$?2j*g9L8VD4 zY_GdFyg9k;T(zn$4C1R&ieGbIeCvJj+@{QOoo6zqS7W!}ZEjL=NktWJA%ULOt$Jz> zb@|e)xVJ+Bjg)WBiS0P?bRtehr?{jqay_YW3hIwQhFasu_;bwRgK?JjAL(w- zdC(eErZq@M-4O<(JwsP(yfwFEC*g6NW?XrXW5dO7Uw~2coJeGpHpbS6d{ohgT=MMY zL>aFLW0Xpc&0FUWsv1VLUk9JQxEifhi>9P(O>2)xeOQnmm74Ild`p%8T|yddhD!N4 zNy?pjqU4XF!c5V|zcGs5L0iSf_P@9zR!Cc78$&EYkbaF2?H%DD2Iev04$ad*4GfwA zqL0Vw4-VD;oUo) zuW0A{7sdOBJw|k20|$od!%Ue6h@GxsG~&ke=ebo@>-@-$l}nX)^V%W)Ytm`xL0n`- zT>;f}7#1}t)5lAQ7HN+E7tmNhUVW$zV*p!bAdA$Fj&jR&rsJrbk|10$XVMp>O*5WG zcw`&2ek@WY?`}{@y=XWtpZxY%VJx1T)P7$wIrqrlh65j!;Mp4~r%~Ek#H%2oyIz(=h7QWMsWBp?}R`PYHuV z#U?iCG`Oe_UZHdJZZz~rTIdAMskF#{e@NI5gU^zt$C4)Me$F)kQ$XUnn9F{*Vn|&0 zvBj8jY0Jngaj^ZE8*jz%g~D*2PFj%crr*-a5nbiA@5r-PUo2Qq*Us%&!E+Z%Bx7(q zdz2);vcmIFJ7Qy8XMwY;Y+*M#^6JDMLMerREGHJws`;&d(xbIjE#G{?wRi3{&7)@h zJ0AknJ4RJwMkI=JD{2iS#gYbkmn3D1%1YLzLLS?~KHe4WrwZ3z{7yH^FmmMmh$Ccjtt3I?dvf=kJne%Xt%Yam{ZIpZL92Ivy=3{(SGds-RNZccZNK5xY~N zVK(nUh$-?zo_${R2v3t(CHZEXm#{id6ry9qW!A+xuuYr!`?GiNAVD!^2*Z*eViQ(T z28fT9EIo&oTE?``UPmdlt2qJUZ1^9jf>Ah;O*YKCwp# zybF%G{bj)`TE+N@#Zt_NPy&vAj^pf<$e~43k;2<<*=*g{+uQUK#&3czzo^BV1*e@o zt4(Ex)#Aw?$V63UNsXpV8CL{d4=F!;*9B=;dZY4qXWR7V57u&SwutBI)L)~z@Qe$W z#$l9q#T_*FtTyNhO z^}k%gtmzed*1kLOg| z6>aY%y>}i5qZhyO`+mE)=+&LQTlaU`2P=2SwQSxmC1A1hAlJ$o>(Wz%o__y+JMUrM z&8`%V5v&f&c#2FCiU#EeSZoJZ zmm%3%q&*dHTz+(fK3)jq-(@r$5VU`)T%EN|h}rIv8^mnL-qiH6<`B2er1RbgVcRo3 z{?bORCs!EL7tJ%;m95_t2wioYtg{i0RA z`Yz|&wJoaoEmH5wuzGDN13K-{jmRaMZKdbc?5UIEc58%uoUI;og>U7h6-3XbmKJQ@ zbBgQQ(@%6qzhzH=(ieo&wD~=K|E%yC?u~kmdF>$Ms!dMuX>E0XSlZ^^tB{}#9{VLfRR|fpTE{V%9&l+LY>~pt$zn6Au-j62j(o{ZM-gpWn90Y* z8DZgg<9)L_yDlF-rI|l_HzKSo06pz^;>fpgl(tRt)qWS@(7AQ;AV=E{n+Ni)gdIah zWdol(eRaY({UC>kVQR3JM?I0}coylSquUwo^es5nJsFWkIy(HSETZBp1mciKS;04H zWdaWju3@9G8eA*=yYub@5zs%+yVHR{ATR{*@IVih@Q)Ms1QD?R(Q$Y%$nVGB>BclY zZUGa9Z2RETO-b5o%NUWOGn>S;jFwrG%#F)G)-ufz46XI1t{hwep`blNUq`JSj*U6Ns#V2H`wn zc5CiPH4Xy}dkpLOT|+C7vMc)=H2D!w!T$+d5HMWecf49P^z3M*DZFP5AkoAT9j^5j zw@v5Uu^7WBhNVR`Y|9ie?Bj%ZInF)$UZ(souOi0Pk1^Z+I&tRRSGTTdQ!eN!xv;0I zav9dqQ)9kM_q>Q9P5Rx}INWUSS?VNHc?nDDK~Lt%cjkvCN1m=+K7v-hy{QG3amkWw zH(4f~VQQn1`@KJw`_pQaYA3co+4^#hXBRwrIif-0$pO!-GT<*S?>(H^TK@h?m~w?n zLOUfPFkLmXZ%pcS(uPc`A!gSrav$fXq4*CCBzhz1#6?BBbox#O+#L)|TTDEV!z<3+b1O63lw>J7Z2K|#*qAQ+A!x2sXyRM4 zSGk?cPCa(r)R}S;gO88fluPDOak1^;!ui7Se8*?(;uwVClyfiN!j?hu)o|@&1Eye( ziHTJfO z+&WFiqVfP-YeNyXUF+@hnodYr`*T$M#tQBKf{IYXB212v~0Wy<+Ik; z$5B0fI``sTmd(wB7IdeJ0F$RSKg7u2DJSQ}CqYjvbluzU2=_)Zao(T$_TjF8CiD&~ zNX0J4NlD`NHQw=rEWE+Dw-YKjn%>-VM0Y5iTq}J`SaS^zw4htPp+ID8KawMM`+KKC zE#1o9JRL+f9)MciEr3$xg~&BF~jUC;uWZS%2HEGBsiv4r5oA z64I89F#s3#KpQGG#=5uzuSoEC3m&y^T4bmBf$P8BYM zDTic#KnscZOa_-|3dACzvx_a%>!VnKPw~^x=`GoG)!WmEa57CXQ>xO744<5$+ zegA^|M{f;>ga5g&=10I#G5_u9s4&Ps_tkMT5rJUR;O%`1#|ixeYMaUcTm|38$P1$x zF+at2Tf->EH#h1p+V8J5V_!c`Mt1DpJ|DP6nm>8G@`S&9y%&MU7pJRs_b^x`?~(L9Ehz;q2@g9pBU?wFyLQ&5e3Eif zYVM9sW;SxR=5`>IWKm7<0iTp62m%I!`A`|9%p6S|te!gAIiM2!(J=YcoQ<8_pPHcx zK&5#Igu#5M|9@uT)6@a$AmDHij9&l*1$09IE(k)EjSz$YVHk)X0h}w0K!5}QwGsek zVNfIl1P8-G2mv^VpPwHjhaX`MGcYYwB00M*n$`pVjK>}a_fJh(`fdmo> z0)_K~^`J=5pVa|63S>m`3jzg$08&s@!})bkwF~eI>cItoivFYnIO6yxB?zz%iWmU_ zm>w{36afDuO8}ySK=S{CIz50ufCdze0s=Y!UZ|j+0E)st2!?@>(4XWYVLC_{LJyz~ ziJ}>ZN0AG#4P=Lap(xUSvH}4E&k&$EfF%e76$b7owjfY2Z~^QAtU&-AAW&2}s5k)~ z6gB`CKe6El7)Ahv@k5}%9iR=s7A61%m;xXH155}A0*6Ke6$2M4jQp7n3_|?81Hb@z z-~eH8fK)gHh)0zLU@Qns_xMq=LP3b+*8_wPf*=6-0QEr-{J@0((g3s}fM=9kQ1TE! zU4PU80Z@Sm0{MY@AcAlJ`JZ*^K?H$vfVxn0LI7kTNT42oRtRuG0eXMZ4A27w1J5Yh zAz&STexx200>lAjp?HBp0G)vVW&8~D>!8xX0q}mN2g-v(`SqXxeo&PDpfG^)19}LA zQTbu~I!KhN0J;YSv;@UF6i^i?z$*#^C>*YX0E7yK19<>7L16-g3+lijf00#u1-@x}uJt&|;Pyv+iQFjDD zJD|@HC=d^5EEvEG1_kawS^!TNAR8E1P)85}*Mk9gzyMlc0Ik3<2VAIj1Ed9TfC0So z|GWcvASfDue1Ias01V)OF2SG>9aJ0;)`I~$1p{;m1_v%EkRBLW`2iYWFo+Hul@AKh zgTa6_0A6rF&tNcq;6k-Wpe~qz4om<6yhp_Y<)i2W+7}GK4kiFxs5TE^1_N+`0c{?} zkJ3dTjvuN62QY`BXaV>}pm^cu*ZBh%B!C<0`dK#!MFT&;KLk~`0Khk(b1*>P1OPl? z2!xIRO1^Li2!W~xMK{pC-~et2lzdS-3jvxoKr27cfB`uIdIq!)fM0$DAUBi_qVxtR z0|8*j4>U@C6n01e1As?VSAy!V04#vAQS|}xheAL|fEJ)b1QZtxpo;|FLSS&D9vl!Y z91s&q#BeZ51%d7jC=L#R{uDb3A^|`J1yJHfb#JJq2|yqKT>OFnY``7WFCm~n?*Vjy z`~Y0YpUn_RgMt-k5&}T=;NMHp(-RXz_4+?;*gt#hKj%ft4yI-fR<;)Ga;9dsPF7Ct z9DEPVEUbXz;@#OLfDC3FK*#;`skNC6@EQdEr*eLF?0=Rc;b?+N0CZE3pF@Nh5C*z_ z6d@1zB#oZlGqbX=bV3ouhZ-GFX?dUmP}Fht7LFkJ&oSWcT{|}&9#oHqdIjM16Foq; ze!i74vazxTi1M%lp++N)KO(KH&47Lns0n4ZKlmA^WMpIZw?h|d*imzGFmp1onmVG^yKR<2tQzA z^>`hF?Qh5GpS=FJH2@tb@^1%S$=_>EP=BIAp-Hu6P9G)o!T${oG-@Vi@19fR7}IVn ze*g_$Jvw(b2)&OG6zzXA*Y7=Z4kU{@C`p)wKq80LLvjlwBX!3-zSkF3na%v z_kqPH>T7~=*Z^(W{^0%wwc0xR$frA%Yg9I6i2n3K0aKPVSOseif>T_thPBPQbIhtL z^|Sj)epgBp!I*5vxFg{tNrgw?uJ1jv+w(G{@&P*_T!sL47iKZGuZ|pt>Op{8{ZC%r8h8TjdszU9sM_j?>RE^V;9z2ZqI#X>v~w-fZ!A8(D0p^|0{-bvi~j@C*X*R7 zo+T9RM)`z$5{9{NT^@Ta89t64u&{il`yQ|V1m4xTPR_jHb89jflWHO1)mioYy6Sv? z;3oO2;YQ)9tNJD0s}Wg${;)QFc^Vn1o%rib(bgfkgKX5=+L+sAoy?ZkYa7?U-FEZq z=s{Zwt_?ts3H3W)in*3mLim7@a{d|gX;8KqJ7q3PhAbTMz#x7kkd zfb0s|-E&S^#~jw?EG&Xy(s>(Hz4`?rY-etW8&x@iW1!cMK65mD0f*aHo>IXwXNR?i z+abcIHSg9_F_(L$8%nchbklosQwmajR-6R6o+yYFQ>@~VnfF%7XEZiGN?QS~g2)1r zF9Jig-q4z-Yf>PpBJ^%y`lC-9l3_AdF_6A2c{lKaB_V<175N(bzy&luShpbi!~ADT z+d@$x5fP+AHOKn!&9pn2r2fIcuD@Dzp_Bw{u8GeH)Se<$A_cD26<5n{7D+S1jE%Rx zpKpDPpeDv*<`b_Vt;5+0^JBTFqDvCO`lK1OR_t?5Jl(~be~;B0k7J`WqHL0rh+DQ> z){=Ekx;ww)^(Ku0RdMkSGKl0Qd zpG~MP_n@t^(y`U}o+kEePHe!E0h`jMAN08#XEd7xykOd&z(+eJk9vy1blOMA!m zXvh9%f)2iV?$z65YYA6bOq0ATig6WdFFeAtMFlfj4M$4*`!`53QYv8BKyy2A21ub{SYJr9_8e@<~k zHWc~6Ax!_H^H)`)HpPob5g(`RUUF>3=a23yX{nE#LX;c$7N)!jMY_g#6WyDwKXjUN zLLG(MUhrOf5lABvOB2BHxlw^&?N+7tRKz9arNb!yLK|I{TQ^MBq`jaMzQp zpq*vP>F$z)PE1Docz#R>P3v%w?rf{9%O%GJ8II$(o67~0=uLyVPG^bBZEIPPJYIU= z+PYb{x`P91<>%vehufuTuCmz`gfa~bC#pholufQm4I>pDy#*AB6!N&`;eMw0OR^G% z#R2rrH@_2qCf1h-EBsEaqmdnR3j}(%w_2KahofCzxTBqaF49!_OD$!Z;-fARdIgis%|mG}c-(k!`z^z-RxDL@D zY4}Z-71)>a)E~*wiVe>-edKe`5kIncb*V6Tp&li2pnWiI{AuOiCunO%_ZutrazRrC8N zZgOlBz64;jRe_3+e>X0preXhs^(F`c4EucqF4WYqn?g|dj1|u<3RO^SQ}}25Wed)f zI4c^FU>!bq{XEU%-qLNCPn)yRuicQ@!>yYy8b9q#*YCe{d|ML%3ZO8%M;o#wFyc9^ z>8gI=AvZ8mU(j!hD>S3Ny>T@YudueO@JQFAtl)c}nEp0dldhxZ@aJ*nq3c-}pIjdd zE4*LD39t;*$mDFtGQZE*%R&{DGh+5bvTA*7jO1*y$oIo(xpv`l-CNC?&>t(acH)Hy zUk0kADGU!sv5)gq@uqR^@pO)?U50VSeaHt9CM*@OlQ_~o+}H%tFQlF({V(e@=f{>- z28+m93+=Z}wcdr6d$I;yybS*FI3|%by~$%Dn12(rIO_c-t-@>=HhD|H?2Jch2=V3Q%(5o8{vqthIdy83H__Pn%aY5b) zH<>^URw$Idx17`}CXvuhg^7IZt)EYPIVLk-th~=2sad?Y%X(a~ir9Dp6BuOf8f!vR z?7Uj&c3!eJXv~Xty>=R}@qy{+ zZNmPt!f2lM2`a(LS02XJu_OKrF$Q0vTlpH3C}`)Rht{^ItfW7>)t%#|JPa#Oa*(>i z>->SN=FX!>(eqooF%p^Apy&>%!?RQmWA5V_c@2D#P7@5QbO|yz6jd@j_#h zJ-34Om38VYIAVM^DPqm|-T*5V*LYHj(>$KT8!fsN=J4azn;RBJ9;L)!CZ<nPe*0&a?klr5N!%P3Ug?yjY_BJyovq7Otn?M2 z4FutipHjk0!dMT{Glz&fx%^&rzHO%$U5hrdeM6JBel**etGfBj!*vVKiVDAKbn_0! zo~J%RQMT4DE81rXRi#vjrFML_hjp@FuU1@i0-_qXLqgG}M62+X>gh^kfROz_==_b) zIklF!mNyE~IXm`v_$=HJrnfyD&y3>O`|vmIF*~!Rn`~wSmRu&$KXLeNj3LgySw1^# zL}1H&Zqk?-(o%L-()Lb~^ISF`?|c28h`GI!Y+ni~b|FeTJ7uuq~B14^y6DVa|Kc;R*j#KT(Wl zTS%o=BE^N+?$aLS>@LmmOO`}*Ws?L%hP_2q8A?+7Gi{tMtGVE zw#k?q7CL0T$LpGj#TP=Dz8lF4afr%Sy{Az4j9O`s#SOO=>y_7X{*T6bJL>~;d9=q8 zD}$fflPhj$v}euo;C+8#*`8>2q$7Rv#prxPjAKMgLJ2l)O@uvnf+BZIK*@Z<*67Hf zkXF@E=w@Ezk85>ak6ddmOV&s{4_cWg`aoIBP? z{7_Dd?CBLP(7fC_UwAxaaO*=2eVvE1!(^5!6~CmecEYpR4`{l?UlR8p31+UB(>_;n z)iB&`@AhuXF%U37jIAcEtgiS(H8e$SU_KE(91=c#iyn?`T zEwCcN_jg9Bk)xBMovD?%m6<8Kln@kH!a!N}P+$QK4(9<2uz|sB9RDz7A^c!IMI$E% zD>oeoP(G?6)b(3fk59$Q%)|_}Vk{!UCn0rL+Cb9I=Bb^tttn~&7>JXyGf^{hasn12 z9D&tAFt9d*vgYsqkH}DQuyO(HYrcDCM!;Hz81M&J!f>>6b}%sm3Io;&|5$|h$NIAj zVEO+({&Gk5;x~gygSO8o9ESt#1vuV|YLH4$@F6+qTifFv+#VL+SyP0Ero21}F>?ai znb$CO2YF6Ze&`&L(S~tpl4*YXzMOlS^?jGT++26q>AoMmVDe zGLo$j4r^uYhw5nuw|1L?=dd%`a@2X;-L2YuITNAMvG)7c7mJ~qFY3_=(YOe>R{mb3 zC})H}&HjHDDICrV2G)%JjUt7?|Lr3ELkj;Uk^ZsT^RGo(ir=h4D1GGBMn`#&GCn9K z8_e{0rYt)&(X&Zyk|u&?!Ks1n`Juik&oyc~ zz_r4gz^F{_TSeg;fQ~)0D)%o$9JB8lK}r{;Qva1aD^UJ zo2=c|{H!XmSY%})!WjmNNU96Rv8k-Uy{k*Jt#f1QPPR$$E}JLYZP`$1#!$teQ*)7yx)h!iX$$a0^S{Xi<~%44@#hHGk;vM-|c zt>`0j4_df8$`HAZCVdOBe0GJU-?SzdGB*=^0AadNa4P@3Fn{}GCgEUZWDSAy?Q_ z9gcadvi-PmidOpAV~u`1W#Xn=%D1!q9@?#P3KvTPGx#xR+C>)a`+$@@TkcL->NFuH zA;$JKvmh5^!YpqYCIrRGmus>ZcE)i37dKChO%v~94KP}imFeh0uB*HyS)G0mQYdvuDLKQVjA z&uoHl-`wuOj|;k?$Xooij7jkhrNTuNGE?`yjObWQ-^GvSN&a5qeGx8w&pe9ildS~L zs>}4X;q|M{^bng6r_0lo00zJn49{h}=x+oJj6%Qp5BzHZ1L;s*+y4sqKTyE`@byE@ zO8#XF{&PC=zXJXb6!32=GLjOgDJh?_iXsT|#|Is0Hz!#&C)Cu@#OUWcyQd&?BWp*q z-@0!=_`l7h|8A=M$M+lo_&<3OeNLKEnz}<8vVB3}IiXRKF_EKrH})>bW<;Zc=|S$- zhm6z-`01pC4`%BZF)E3OY+};nn4Tz?pY<0ud^WdZqPR1Ak-Z}kKH>bZg07&fT0W=P zPKwI^-~+sn>rCDgCzwBCq2|-Gg{nLdubtH=nIyk^19+J05&XQPhZ>^V?s~4?;kFq+ z@N&yUKbl=Nq#hMLBrq+n9#?B=>DvCb7<)>L9_6HTpO+r_rh<$olGBdKBPzWK1P zwzb&gDSo>zUrE^c4(XxsI^XScHxvM@oIFsJoxyI$;RhRLt&sJaC?vq40NR}^y3`t`m zUG!y}vifB`(||j^Q^zJ|zkddv_4lBR-4~Q~FD`oqJiQbxqaF1rQ56orfhBoqtT; z{!L~l@ckcU!~Ux&?th5c3G{#e(q{QjFgpS7oqyj-0^nBlUyJnrNwX6W;cu48f0o&a z00Ztz|2_c%K0E)F0RMkxXQ|b{!R&k&_urbG!GD>ZZCcuA{Vww2fK}o`z^U~2R>?nH zp8uOk>rdeRchdTwH)#bt!u~QR|0}EHXV><>0{#ya@Nav_{!0P>X1)At%j16+j{cup zI0AgL|7yYih2Vbo0dz~(i|erkwl+u~UE=diNn<9w(ySEfDAG@uROjn`srW@O8^(oMeq(!$Ja9U zuo|;N@CWl`tw#>@-XTL1HNoN=!%ji6RCU5wN@?W2$F`puXC@{MsGHpA%L^9pLsZr( ztL!dtMea_#QJ>d6Gb4u|Ju7ZQztM?T9UC7oad=(VPN}h5urMMiw1g8|=0ce7p7X6G zz4O|4p(VwGU_YJ!jsJXffHo?Rnur z9}_2vMf>=rp4CiQP(VUT+_z`Yq4WS@2ewYGF2{mLF}19EQTmHPOZ;8y0RdAzI5FRT zT)lU!Cz8#0N#NMjhbgok#ra#D&$Px=1gMT^=F@qg}x0A@3&$@DLy;J3XHzd4!y+zTN9`0b0k7f`C&ts?PvCj`zvBK1=>cBe zD5vLt6a~11|CaTSS^+O>UZf!W=dK;VCmMm^MIxaXW z88Dy(z>)bMMEy$l7b*YD6G-qcZhocxmH$`iDCg#X)cz~>w>tmkEfNmn6@&{Q5PE>K zIN)pli+#Z1o*(6K{}&#=Lca+8756Iy{i~W^Ayi4fp8jG;50DT5#;?4B{5rpc^fS|6 zIQ>e5ivNpKJ>WYgYNG@y@{f%YD98T4#E((|;Ir0!W?gaj) zCjL2l_|thC3Fha83IGoIzdLM0_<02Z?SuU0whe*sA|Y@v;%}U{5ePUhKR=+5ARZVL z&I@d~0TdSsh6?ijRAC4hCcp~;BVmGn`g8;C+km4tK+PYgulroydK&8<=sKHO2zVGovXd63|35b?0PK3oO=qd&z20WL4-Ratm9XD;`PfPhZs z2qqEUkA8mm5d;CzVe(T;uFI_N8$0?}-0Np&xA*(ErEO=AK6_X!e@0sLeOAQBM5|E2 zMmHtQ1Un6`&dj_(*AmAFb2mP&;K-ni7fZ(;=q7&ENzHF{5QGyiaD^QM#lBNW?S0jf zV_td(?bWt2nx1gGXQfPB;!JPrG4&dw>-|NHJqv`~Bp-fl{Je3ADlMjb&Sx z;Vq$Y`Dwe4nmobv_RRyKtoh;tqERQ~^ltRjLPkqzrcU&Y9^4GYnQ-@|*9=ujUPLj^ zPf~^Eyz{Qk*S@&l&;Y)sUA&3Vymn=M%!*7L5_MItcQlcmvCK~_;F1~9%IL(}DY7R2 zPQ1zTv6MN1r844;fLE)Gh_rQ3l@~QJlS&MTZt@zK?gJN^y41UYY3zps%JX6x_!?4d zX6Pd9hoSzaVuaZ`hC-n+Xc8ZYSWPB)sO=&vQpei%E=X5M-NP<%W#R8>joGtFqD>~e zYk9>?uKPZ}uV56@O+?;yIWJ^w7wkqM!#HZ_hH-|C;BYWPZx=AG3nT=ECN&9hQRo=5 zyb+H+X@S@f4f<0XM9(*A@iEhAa3$Tjm4}PO1dMByB3c}%j%fxmI9+#In0>; z!xwTZS*aV`$b%S$g#MCiUS%5OKVd~Q4UDohI6ouGCx6sNcs zh0B*sHiKO~jE)oYX7LzDsy#{&-{d%%wms+~`f#m*X|RJ=0AtFFZa$}aKJwm(z>iIr z&-FwvgSgoxh3LtmSEZv{Fh?nI_nsuWkzo=i-0#aP533o+U43pJaIwL>6*407e3dl^ zuG^6j>fFq48SWm5UM88W{`ch843uv<4m6=I54Vxd8aM_Ke`>C*o0c8iV+r1(cUvJR7t4ILMFWX^1&#oTWpWicw7**3My`Jw5U zz4kms*Wlx4V*{5_@w9b{q!bU%o+CHjqoo^SO1x@B6wc8XxUTzRokC${>dMt$jWVmn z3SV6qUK<=??;D^ zeeXN_mFKXQtnki)Sj&{d*lme?`Ow`pr{x*qTdsn?5<9TRb#Qd_x?kn3T?xF(YkhAC zs|xWY6~_y;7g4r{%&l&ZzfEgzr9}_%c*iD7PfGgVvMXI>sH-8CYz$aTy%L;f4+I}=JcBrK{uqT zrNc<&VKI5m>ND?ip@K8ZQ2TnEpq7Z|^O_VjEoqpJZt+ayEt!n1J6wWWp){kz{_`qM zqKf$j3e0P--W$laaVL{jTF{z#?(@0H=*yn)B!$`Erh!v5+x%C0yhNnoB+J4!^3_bFbwmU#=(fq|5mFkM*L**Xl2|plzJh zIM5X3r|-e-(X3U@aZ?HzCMPAq0sWK=INKzdo+A$j-W6K1iTRsb!(NmIVE4R_cP9@#V(+UYomr|3j^;stx6H+$U{5 zU^HjTx-!C1uG6f(M@Hmgi!6m>(MMS8$fX}1$mz(_N;I1x^a>=X=jzqds1nMKebPzi zAe9i2Nqm=5LU%!ZdQTjx($f9vOI#gLqnT9ctxfO|+Y3pgLLhpZn^u68f>cHP_!iUs zw7}Ce|4%if>oqwpv?ZIt$$jg~js_uTxVi=j5@D(dT|Q`?-g7?qANagT)`R;>(7t_q z{}{Pv#0ziw5%6lGnzWZGW-(g2R1h7h7@@L2c{`ag&!Q>RDe{$c^|vRhVhDovvdb6_ zc%Yzp0P9BP+jqXrjsavLB_=z!-UYOY^cla3RqLJ1tKHdVo9yGVAww_$S19!}r-MqNhF@GQu<|wH6lwL}Wu@jT zTw!aPDSoE7Q<44^>>KNpKso)OS+6Q@mcGGT|4J`?D-)m zqy`)+xl8i-tiv~|T=S9$TcV&udyBji>Y}6j1!L?!rebrw(2`Ijl4gNTC5f!IP}hJ& zLC|zYdSC|pB8Ra7Ice9b=w;J%5@FMQ@?&33oUf{%<(db^Ca)ptCfT8BZeyu=}a@h!=c{( z+8CtNEo3aeyTZA;kkD)Fpu+E@A${Tg~O`%xal?8?56f9>ne zr``D1zJH}|i7^L(oe6xfd!i+>SVUyZ<8qfc$}%3tz;53sSW`Xay?6i$0KLV^+(}m9 z<)#`XU;xvtH({4EZde_1d-~UPx|CjQI3Cu0RQ6Ihm#BR+z_CDSE6pWs*XGuSDILB5 zX%lIaZ=ZzFCyi%_QU{j~h)@_<@YBf2Mk70)fz11j<;LnA{(nN}I6U#kCpzf3<@ zhK>Fg+Qq0JtR5I&-+ZnAdRE(0mv-GMo9RokrBVf}(Dj*cj&Q5+qua!ax7KpRx>kM! zW}Z6xblL4rT`2j+HI#}^Wv(>L8Z2in8q67N_)a!_ZRj;vD?Vh{Vc2b05ud-BzOn)F zkrGxAP~e2%$Y8Y_T<4qMtNbKijChyDpOH$%@6K=YcyiR~?V75Z7A(hHwRbP|>1N5N z^H09Pk6S9|!QxpV&d`<7Sh^*_YX5XkTI5j*8c}*$V7ljBw^%ZB!@6;A>zg`F8s$VA z>KbigCP}UM_6=?iYH7ZuYmz;rxZ+tU`qZtvE+VA-tYdi>wDKUhlWNF%>vs!~Fo%SZR zYj|fmv*sfriN4&?3aLJ0~m>f7W zih70AN7EQdg?mMa+-r~Ts$2()z38!K=SiTE$K!9Fb8^Fc({usG{&Y8OlJ80Xa7Lkb z@uAmdXeFCl*Q9zS*ORJ|qK@^o$&^aR#|*`EI%!xtie!yr7EF1kD=SPde4V#XkSkZ` zkB3fhAcr*Qo8M3N_F?s@9=6lfq5Yb^L&xXjD~Ojm_AYG`L>4!$rF*B0iCPHjI8gEI zPdqDcDt}}V-{&Nv_LOz|{#FW=MOmL|x*RgzjrH=`H$vpa{u+a_fsps^!C39+T9q<` z$VI!A^|u3Yr3NRDjv6-O04_MP@EyNL(b9v*h=1{(FRy!21f9V#6X z9dh^dzPWt!_@=GfP_J1*X79>LxbjIsd-^mZz=yVpXZPJ*Yj0iZYga9@tIuC7Z#!n( zDU^tQE4TSBH6ySD%&EXOi|<=e>iI-Q%Tri;ETsaB>SEQ7jJ?1ADl zDJE9qko_IXa7L=K%v&Ih>k3ryV_mdMAf(jS+o9o6<3>0SV+0pKcCpO2GX&+(?PGmo zs^*nHUNdMBXjK$xRk+@zx<~Aubc=aA_UMbb&mFJZ;m2}*=^(Z)@vhJ%<~@i9Zr5uv zImY~_*LdTU=P1$x`{xM+i7e*Tj^lJ0HM{seYFtE~%NND2FS+jFoWxIqtX_u<#|d3$ zin6D}kY~?DH+%RRzu+}z!5f;vpvU>ozvuhYQ{~=y|p}RJ1)5vq;$;ZA8laY@~42H$!0^<@cVRc=^iJY*5>=_}pe;5y_#3(+&Y zF;TT4>=N$X?_(%lmN{;A2&-u>Dl-^w7%$$SIg9d=a6QC1i=Q#%FCpi&LUx6S zmfZN-JoANjoJe-g-VK->^L%GKpz^@43-Y<^Yvc!3S!F&5p6zr!AoV09Zsh#9=6FGN9pXb1ub1%(-wMLn`HMUOAXz7oS4;t9vH?(mZ z@V%nnqP_K1z0dx2)y5nLhQ-R6z*#BtZix0-T-Pm=()P&>`{!;J0X>_$tfz73{!20( z`BqVBaK(Ph7b%G|wbDvG(;Dyhw;sncSWgvshXy=%ogK<|Oe&iBbhJA0&NZ|C;*^A1 zOK|mTlk^c02R(jENHjI_@j-IwV*9N4ynlGSJZq9tiqK|LD80|pmo*rD+9SmJ?u6rV zUs{8q(MfijLWb6-jjp^5AM=w43(X?!i|Kv7!bdf>7a=zU>JRp~(hznNoYqs9-=9ak zOssL)o;cGUssDa~qwl*omnA^b;Jn0O$Kbs(W3pZ6dmc#6HlNAhbFj;nCw8&1&!?1m zvbRw!T)#*+yZe0Gt;4l;QTXdF-S+WwSFa8r+ILwPd+Gzxa#b}~vGcp>7s%f7a%h^_ zYXO@daLRU)B`JT|TT^{#jvcSRac ze6Ng%MLMqxPUzdQJA`~|b6f`xbzij1EbTy%g&iehk(44>hY&gu%Gcv+Dqrj;llKA^ zh>t(M)K>H~IEzhXjWWuUiIm_8;k2%o6Aph*6pJyeG4PlTE0JDUeSXK8{cYI3^PK2g z(sL|H*@p)k{3Wj>YsYlPU)y6@iBAg@qI+#}KC^Nlv*Z&{%d#}cN=Vy%_ASR>I^$&& zNg`iSoS~L|s%?;6>p&9*S5Q`PEs+|{hpDXQ!%nO-168k&)fbH?0xRtV->?o#>FIg+ zGPm=!#-7aeR_pulakp9+>V4nV()~)7rvL2z#$ZR_`!ChO7+jsY)`Kmw&9am?XYUzY zQ|6#w$yYg>JZVpe=4#KkPtd%x9a@)2Ec?{pSVRzCGw!Qn(c)9WbIpU>YQsYFP9rTLqw3bZ>(hT*3k+oxJ7%tQ~_~{w1|$!`-|OD zQ}CgkxZWLF)oOgqaa-%1F=k)qIKK1Qf={|{q8oWJG2p=~erUH<9T zl%dfSgjT~>@r17*W>hn#KJV=mz&=Yw( zw6Ik=vfu0F6TGM@2*WT^QPyi@s$uvPb;jT#XRRweU7ys&nc_VX{cW8LrLB( z@A|A2szAe^QHqTz7}KhP#QqQ2BP01;`uMu^8Z^*TP+lD6ZI`~c#3K1E8}g!|ikS8T zg?Jhb(Re}5MWGzrP?$#s>MEEY{}i%NkEl|rP%7mV;^|l+72gxN7izrT|FBY3_$sd@ zlfSA(yIIjH?bdkfTjIBLPggErhgpDj={u;rTyskvidv+>PEmpq4}AxEJ?$%?A8Mu_ z|Ej`=T5=S|R|Jt|?Rf!|zerLvdP~9hXt)qRTsoUH?udr2yu72&)3Lm`d}vj;Y?#j@ z`O5dv!}M_Zq=Mpl!Kn&YFN&||xVR8`HHNfm($)t?!3I|lVT1r~yr(02Aci28BGw`l zaygzd5it{S5OGz`2@1B#r?P@oNEXRt*SPyL<>=5zba0Uz-8G;vLc8^f&<>p<#acy* zHOr19H*FW8$&Dk_?9VLYRHM&4)HW7f_mc<;lkiUH5ik-0ZdfN+p#nh#MKmQSn0F-w zGS?my7@#{K5Oho3;X?wc)SEKfYG{~V0W-Mi&-8L6hhE-gFlDZ7+nIh1I}isE0{t4V zujp4Wlb%NnFycKQu@-RL52F$UURrJHk zKU3UQ^qXCtH21o;8T4bQKu~P#V|@6>;6e066eA`f6c{>%p;J(XScX`Ks6Z&N&MB;O z3hNw0ypK2q8HgaFCqhL}R$?<%^h9N#ox5!;{eT_?8#47ceMhG6)3;^%9{q<*-$m*| zdW^nZ>2gC`E#?E(k&sGA(=lJ9Z|+JmyTffw^dPdwjrVj!KB5O=2x2KhK@ZZz$`Nie zK4d=}QvsH&gzshgGHg&maGX0BXpb`H;kQ7myD)^ewVt&B8Vsyhg;9PBJns1R zQaRonoGMPU!AZ9w&8&3x$7;sPKx20`G4NV@-G4eSxW9K+Q4C&k?stFcsbZwk{RyUQ z-Ru6?xzPP?dX)-O4g{(Ql4_4!bf2@Od;2lD=q$`wUFm*|lfCX4&b!^?opQ#=NXC7o z7z-NRy#s^X_u%t7IET4|rTEOf?tJHc?z~8;=Df~ccLsJLEfP${&Zao!Mtv^%f&Fr- z$e3VbXegJGy zNSyHR3=m*)Sfc#S&x*NSBPt4=p&~};Lc8>7N4iuT8V+5Cc`B~=@l_EGE}){X9jP#P zfi8X9RkTd&Ql$*{uEl*Wb!~bp|DHE)7+Qc zhx_NN1s(R`RvJm+zlB9~LSz{AUdN9Br? zTOBFq$NE?Gi zY#AJr%N&a><7Fz^$VHq^EaGy?MTi5OauFwS$VK}9RU|!HWMM;*g>p**`KydGQbvEi zzKs4nmPz|hKO@_vrIB5&3x^Np`+#C!!AL}L#iD6r>=k9hJf5Ay3!@u^K=H8QV>lf; zvZBy8vO~piUkA_5)`R~hdoa&#?dz};1{d@lxN~rDWQWSu!PW)7p&bf$-Q6=g=a#k> zHnf%9^KTy3lRqq*w{>^U-(=_T?7MkeIlQeL-qzj0yXCe(mhqkgcdDRWA-bJ1-9@z; zl-J^TZ(+MwX;K?mcw2kzkHuFr{>45mdf__U(diL9t4Z4?ZFv^z6wfm7&0aLi{#a{o zd^On=&5|(LKbTFi%3(W*X8t1UoxGm_X86I<~_L1-w*)AD$lS{*I;U*~^nl(y$uP)7If zB0(3K0;PpQg{wz^Ta8zN!g8iJ1Nji3{(BbXbq;*m^jQWe31xPz|xf z9{wI?!d&4atTh+(kO*y|CrpGTq-%I842E-THsnB8cmO7mvhcw06XB=A8{s9`C%hA` z11&gUI9|uYKZ~D*&p;Ebu^d*xIr5Zx4+OE5GA#K5Oor7$5hLNz;TzZkFFc5SV9*VY zlS4EOpFR@4BX%-fXpc{MF*|5C@H+6OLy$d_WEfp}JY2e9ma(QVQf^&O~?vj>1XeBX81)qE5^d zgW@CMkHG@Xpda@36|DI!`JFz7*G%DU)-l`;49J%!Ik({-@D*{8bkc+LrzvzIT_a2e z6}H$6uMsd7`MnaKeio%>FV)c#!i#Jxt5GC`&W8;+BLR30UVt}=9!KgSrQ~sPihM)c z(;@UZ`nB*3+sr;x4#iR52NPfkY=z&6nY1Lm$h~9?nNH@DC&?;uoSY<=Xj|Hsj;B|I zF+z#(I%|hlA6Cj{i}S=qic6t^p(CMxhJFuchUY;ql!sZ^`{l3(N45`6z~^|KgRhB5 zw8VfHKlSZL9>wc1vV?4q&!Bf>D<{d<YLtHFy3zdhxABxvFobMGVaXa86qC?&}NGfSVx*}(W zka47hJcOK_LspZQ+>|z_?Pw3Y?xQ1V3Hn}7(cSbEy&)(C ztzZCVLh>cvP zuLwO+3SMVz#DU-yo`+Y35;6n!&;kHWjcPH?LuFYN&XPR==F9-DasMPf!Q#g zeg>COj~BqRWCR-xPe2x#4&TAcs1+&V1Bz6ImAp&GvT_ zYQ+`$IZTBUOao_yZP@!0^i`o7yDIi3V^9NTz&t1k&w_`=f$T#v8U)fG{Omkhx9LJA z^CF#zR%I~Sw7sa^)o2IW3f(Zpj*`!ky#isM}q|j`W1s zG2Dcf)6Z!iy5iRPMQ;0v9e%*;Rph`o1k2X}Bgx|;u& z(fJPU;12HK4({L%?%)pY;12HK4({Op7?j8_Ttxn@ekHWqP00m?vWl(>#(>B!2%u52 z3k2d+3h@FJ4$x+xCaXwOu%}7a^Xl@tOV{$c)#X7xhNW7(HOugtye2>12r#Ji2#0Ee z{7d#8c8LEr%o_fV6^b80Jh(}-;QU4jEfc7ksT1e`<7+XmIgiF1b^ei{Ak+$KCRji% zDomhODJ4*Al~TM$r7WZxjhVP4b(8zt9d3~{R}?0Dtu^|&}(^lQeNbatioVkq25f?+;kf zKlJv1siakx&_CkHmgQvpa0bdg1ds6WFrB| ztW-%-70KEKYYi%-L6dT=;XV)~!6OL5Hq#4>mhf@b6fkmMzoPc)f$O_ zSz?lT(PI1$^-f8TzL4@}v~0lczeZLwB~*3BYmX^D3wKQimUpl&BZ zy~ug;)q#C0$_IT|Q}@Nsp?`%`*!q^xSuz`rg9f_q(V#+XMcL>X3=koYQlcSwprHar zK+#g!ss{{#i7*q^q4KQLu3w40xK?!Sf^=D)Wqy|~OLdot$(-9PBdd9q)uK=)w`h^G z_ju0%nYk^5_+*sv%Tiogc)HBpAQaWiurVbc7gF-gQ!+&?X)1KtF?1n z`}n>wgRO((ddH7fj@J&4x!*cIt~mZ-`k-Q(_7UTJ#Y*K0>0SF5^pxV1_O#LAa52&1 z((7%d>Y&$`ouMY6mef?e%xx;=Ivg}$st1DDwPmiOi=s-5w~{o@EY2=cR02iNl79#y zMl!d^%8ZRQqi`vFiOGQ&DK;y!g-Htd5|xU6<3CzAt#V4caUZS!_~9q_ZJs`T^XA8< zcP^qI5k~IXHe^>Q{6#1fdTaa2*T@T@XRll(W5~Fl$Ijz(aSj<&gS^o|Y0x7C^``9c zY$jbwSE<-GM%17Xsh}2#j*?>PNzfVbfC>P&m`=@2@R&ZLZ1(vZU80^}#T2{t=M5_6JAxFv4{-q3!tH@J3 z>-FJUR3okxMUN#Mb>=eo&1$2J=$M$uD&Y#aZsC;D3+PcZZsjAukDg zYdgObT92x+ypFH;+zxximr<902qtuKJe*LTup;J_n74GNbf@E0>KMBr)gh=e#0+gU zs;hvaC&g&2=9rjc2BXCgV=)-@D1X5igT`eI8rI>8Y%m6`#AhjNwicN+eh|s-T(OR z?TZI2ZnXIc`gz@JJ?1=lh^VG4x%N&SDU-?<9oewDvPXU_{bgHd+ThUje;$3Z@;qPF zx*<2MsLu(I3YEd+@o}VsGHC4(*TFN$+}AT+7@-`Y8fPBinWCENoU5AWJf-?L)}%y* z-kt36dAwY+O^sYZeNR0_QHm!Y4UzrIF+sKHiWd`I7Co-FErV9r<1dwD-l1+HvoM+x}crZp6@YX+SSZ0fIv5YhgC$3>Ee)4qfij!njX( z{MUu-#`eX_L*`IT)#>fz2XgdzzEA3dvmA%BYy%%;z`0;f^H`D++bOnF;9K4I8KOFa z%zznWI-8;@(N5M))jwie1m$Ego2QzkouiwlUt)XT^mdFn5vRM->2Yx4@uYLo#1r5$ z;7al6z-0$rysPQDrlhIa>r#k~TxPwi^q`uktLW&UlvZjCdQbq+MK?-DYOEqp?#;B9 zR-k{1`ISkf)&{S}8njaDvStll4O(x`mcPunIkzbNa?~0{#UUaRlS|Oe34eEyu;aJOYWUM_ol%ciKe7$;T^=;r`eOj?unH95Y;t9gAG6V>devIDUxz)^ptxb64z|*zK`G ztCSH6n#|3Y4|!|%dK8{Ut{#RV+*UbJr$q8m&xo4s<`&9bO>#ktT4uV7H@KVmF0|{_gF^OmdyhQ7m}?k?eW+&hSU}$Aw+woi2nwZ|D)N|+M-&YA3h9s! zl>3nDRngr{3D*|%=w-o>Wg`Z+3<6>wZX1NcIN1_gCxbScC2 zh2Z*1_tQcAOaF9Gr5HqO-V;RJPg!BBVk>SQ^AzAvc|;;kRSp=04SrjMTAJ7GGQ_1j zF5}1UkRpw9uL7+TY0m#x>)Pf5sSOM7(OIFPyGTCC+Z7sxBMjF8h=sWFE5Sfq!Qtsr zhBR6=MqMl|5SB^rif=0pNmnJUN-QM(X-{d4wnF+<_pAO_gPQ4>o*4wKMlCXij+IKG zRO&FSQs|VpHS#ER7EGXm;9)uomQcGyQRPwyiYhuOs0Nkp`yl^ud^ORc5Nm^God-rL zh2A~c33iSN%NSu*gaoxcb%&Jabiy(n(eb!sRGv`MnaVOHRX%Mz^=X9VaR~ggY*6|P=`2JU7?L8Yul zKO4e-a49S#lS_(xxFPci{MbMUBrB8x&H5)D_~q8R=hlBtep%Hq(U~Py-{?pVggVec zWW~M*mn=fLS%EhCd*rW4Uf*T~dotG1*WWkFSE`<)R*ZE_6(^}nwX?<9T19fKTCgXl zx?&U5>KL;tH8mv#oCz-ElH27nfyy3G^z{dHj>ZWtkGyXwN^3n>)*<;+>3X-z^-ekh zb%-C8yqOUfJ>WwpC^Ls^84s_Zflcp~jv768>435~ z7l)oEcge^RJTqO zQ)<>JbuGtt?EP>vzEX_}e4bO}Q%eD3X9#!*Ar7}K;877(oNM^t z$eP!UFL*`W>KA*H%(Aq!BEE$slZj2ie2GcO9dlAvCbKC6-0D!P#mwyv+kN=1&|4QT zhdzC72Wfx!3~Ai@VAkQMH-9sD!ngBY{F>5cS8CoQ4}5r$^xJv%vmJZ{on6`6RG~0R7??Pci5>ytI=un8bM)=wZz863W|8a<|SqW-s~!;m&9sJUPw#Bv8Li@ z7LkR-7Hh+8x`m>M_`R9YZ5(eImQ=e& zNUQxsm?Kti59MzQ>9_NqY{H(*#h$34OE6XL$x`QVndTx`;l1Xwxz@s6WxWMpx>!r4vRD`0?4ZFad z)2MU8&qpyD*SFt*{>9$acrOPc#lw`fVMP1%&9n(*UHit3dVZgix(>bl{>4`SD5VXp*uW)GJq%FmW| zwY*C{W7?IK9idG!BD7ITg!=pun&661yCZTYm9CevJ>oKPhlsL(YwJ>22Nl55adX!b z&cRg>%^pl#hRtnYrwV1$fcxFbGF(}U3QH#E)fLsx6W>U4LCrE9Jj_=s>?>cPQn9Zh zWCeAEBJV^{dHDKEUkMtNRER2o;wGc>ZBaz;B9HP~R~)7v;^ThZjs;f&D2(_#iA)X7 z1Zq@SXuOI|)6LVpqZ8D+PP$G;A%*$%jST~Zd)YMoLx%Z!m6nRCTzv~e586e*?VqZf zzMVm{lCBa~C|9U939l#>W@jMqUIt^rl}6nbE%WdEW|g%0x?VICLbKXw{4JT-c<@$p`7uA#A4KHb=xlWWM# zk%N1hU~2RPBdriU6euZ@jW>z4wa6h}lu+U$rj;a#+?x>_*BrNc;{H(o9if3@b6w@>Jav8E9Q5&q+~ z-Kt>6Tmc`jw_~mCIX<|-58efw%NAV@U}s)+3fMulMpoZi0NSqItGdZ)dQq{rXewd zY(wn*9RuPQ*;Y|0&Ls$DmsV{JcyQTqlqHY^V}SE2&Uv#lQpCNHn-9{_6^W6+o5}dX zEZf-}33ozZ%BJXyz;LpFw0Mtn+`2oo_uz?8^`>`7!l$Q6{KMZr`9bJYdW=jUFB}fN zbmm-W-JW;Ipf^Ilhfa`e62FURpAKDwh$q78aQ^jRhXKLnBTeHiw2Rcma<6o+g=uvz zR6(%WBWt8NpmKN|1pgd%ebh$8-RzK-6kYFjxnYfr7|*B&YIC9EM7>@Uh8z3}n(|b) z`=2WOIrMI50eSSmnxd}F=7biC)dus(y%Y9_>gu)$Wbw?wv#omU>3Wn@bUv}4iKJ`L zXx18txrK9(dz5N|o0+S^U+*$IvXNfhm6)7u;_-y!Y$-~OQHuGW?Metl^0B-Wr93}a ziUGf&v$M0Ok9M$gf^)L^A;ZJQxtayWXZ4$nRmMw(?~IZ`r}LPM7L&xOA?Y2?NQ$OT5tNx!N9qX zyI{ZE@a9uyAts|kFCV@~&fdj_mqpP} zMi_$5Tq)6la3dNtqwuB;0=j@PKA|ba+40FUB_CFJ*VFPN?>}F`Bp$xIQ$2$){e=5PB)O~8GgfyG8xTRKEH&w{WdHC)z^1GVB;qTaw z=m}*&DERzvVK^%lrZDDDZZ70H+Y6nPT@wo29g;dG_Yn$}gA)ccS{P$!qz@#~Bq7<~ z!kF#r;4erYP+x9bBF#;j?SD$Y z!nnff@+TSeTG5Msb-YTcU;&rj1CT;e9GTvLnFP#zWu0x-;EG+q4d^X<2!62RIA?t8NuoRR z64dCJ92d>XjC$5d$?~C*e99l)U05x)SZ0%FLxI{J82p-k$U8G8Zt2r=aO=?hy~d7y z>|f8k_~$&a+PHml#roWq3c z3f7}l<(``bN`jhzaUdJ0dRN6_`O*=KOGh?qt?I}+tEL%W7B3lbX(2Yrl@7_M+)LyZ=cITI&+83W7`tOAvwUr0=3_C2p%f&q>CgK8VP<)x-LUktXrsBs9vT!q`RuqdUQQ?l%WHP`x~`KC0fuEMW4(=MGK{( zno#k3j|RP!kt#Bhs(A0UjdFXcNSSJx3gd(X^)%QhcL*g*=~_xDPceDKo+8aa4`rEn zNW3bF=%p;!r7hkR@ls0odrA(w6nU-eh`VghzwN6M(W4FvdK;BsM7I4>sWuZ%&{?Yr z{~S5W0A8fYG1msYA)8mYk0 z#ZxGeR~oHOr`8*cMx70^0=j{@~?%`BtHgOspWJRw7(A7uR!$JtyMU~2B zwOg!KyIH4JyR2pmnoT;R(Ic5Gl4LTgbt=16G@2xoE77VG1-oQ4s?{nLMLTUbn@uKA zIczqE)K*P;fd_PWw<3Zdl3sf~`~V>?u8J($8MWDtxNddm5!N~4>g?SMMt1o2*6*y~ z#mzQ9d8!BcJ>72h4{s%CiRT-nBS-L-cceaa^9|?5h;w7&Q)t%MtHReK6XwUn)W0Sy z>T?<}WtT1}23yK=IGImiOk@IM%t&Ig&{5=vT7;|#J$m$9lB1=D*nar1htJvM+qXgw z><_({th8A|@1jcNKfCwZ)*sQm{9Ji&>-njjZj>Mg4^r7|3Myd|6 z#BFoi(;BB{=d#?!o!C8%`>P7mMybZ8P1DWSy{r3E|7V&hC)+@nl%AAr%k*08LsBND z&=hC7A>Xjnu+|VZh-(cy3|9<-!Qd2ZRdh=**1p{0bSj}BS(E7$v?)WSq2Tu>RndEc zQgV>L5cUKz0y_d?pjj^0VzvnVc_a3X+i~FT(tDbZ|6(-BDp)Y{;e-nN11A?Q*wRx{+Y%2rZNrXC z9Gp2}?3fLKgxUQ%Zk^kGR(Fd*?@01%9%yn`VTrwDQJ3J*&P^Y>S~K^qmgLJuPN`A1 z^m~f$?Qz$GID_+W2Kl~$e>3G&a2pYI#w4-1SRjh|?g}?`yAz#R&UVg8?qzO8tC+ml zJV)2qu8tyAk$#}DDE2>*3= zQ+kNtioT9ikgJ5bNj~X81QO@EJ16?OYcfASxyIM(5_zG(Kl$KP<~(LYiPwiK1uo9$ zxk}(mOcro${_FKklUH_6-Z^YXNig)U*AI-R+5MiJw(X^<)3%A#b-yj`vGiDJ=t}6+ z3uMK?ev6L3ck*q1{@*ivNw|zs?||dMyVW}4cD9dcZ|f7&$5tFuYC5yl>-MPkYWC=KvAC!Hh6;wnA;yWunMT1#xUhE0kk18*VG=BZ zb#NZ8;&Np)YH^7-JGDx?lWCnsVoWk5#$zv%v}ta%m}t*BIju=2l*FyfS5jrO`0OL{ zs$Rlh&PhKtJQ>a`A#Z2G zl~=zA{XY5oh1<`#cf`#cv|!7|Ipdxnb8WAkAPGdXjnG*;*2j;(|E-Ts9ex}ot0Qvh zT=e|>RB)??GQD4)t?!^0n_HSY2hhHn-j+Vj(R743Qa#*K>^$WDSo|dB%ead%7cEz8 zKgL~@B`DVIPIGXv>*C-tsBB7;^i5-1(dPOtv_Rj{(#bhM(_cSYe^K#W>EUnT6C|ZKno<+cKGWsRyq=`tTpsCnYW@4r(=A?tl6UuYSu#$1!^-v1RI9GPh zs9<%wj3Om}t1a(>?16CnC0bmmz0J8&qgF>4hGIr;eofeN}?BW&ayXrjK zrcQfl)1wcqpSNal&5LV^P~NL8HQeY(&F>$3^X)I*KY~2#g4*ap$+9BP&IU)g!D*%a zgd(v>-A_AG7%xs#kJPFpkcdQ+&7X@mEY}^%X69CL&75t`-5hP5z08B-dOL@jCpd;W zA5uJIy-u&&C5R0$?_N!E?ZD9`(eqc*%f-C zcewdcmOqfqX)u9XMmKTCW=ToPU{Y%KO)QJ*Vp_Ml3%GeqOS@i@CVOpl(N}_bbtQSx zw`!4{Bq^C(FKm%*utn*WT{+^F-^nY4`>GrNyzl$a6=FH_2{Dk`OPb2L!xz_mL3`<1 z_Fp)CGwE-8aW`?JEzprhp|hbsCC`rPF=Y9?_G4b=eqIbNPi44MvB9pO%c3U6xb(P; zxM19*xaV}w>o@CF4t*niMckn{7RN`|$l=aTQ0WDo(WxO;nr4Y%f&w&aEyNOz2{N0X zfk2-k^7+WFW-YVja}tfyoxKd(deI(tfK-DQt`iN|arn5c<6nT4^3ajHT*MvfJoy_~ zxu(czu0=8_)Jla4mlO%No?ucK<4GDxOPw`~q@iF<&NBI$XEo2x;d=_yL#~Ea{tcJP zwQFM>v!`_(9N#jtcZU-vgw=~n#%FgNV17Z8cC_?Y4%Cj(-q8GJH8k}#PHy9CliW3VS>tt$ zl`Xt2Qt}&j)OPe1r1bUnO&O~k?j4>|+_%r-m~ZTXRxvKE@f0st$h7XVLSEzBvJ$>kxz4};av}QG`TuF{OTgnOu7s<) zd-|H5nVv&)=xpn@B}=v>TOJ|s7+)A;$yl~Q#sbEpku>%k(#%M*urVeahCsk^HfuY_ zk2%7zB>0jKAOweN!?l>@NPrJ8A0`13Hr~X`hB%V;Rdvs3jGbh6|Ft~budAzG)jR6d zdv(m5)T4s|uwovv_(8|cDt)<`^i0nzh!p7fo4bnNv)9}(KYjgeUMn8j_ui@a>)-n6 zbq|K$+w-%}cRzUj=7)cB-NuKn%)h*%p?gj9zB_R1`@1l{bJy0ttpC$%8y{t-y?*TJ zSDt<0S&;rVgxF7MG_?P5`-Fv~``5}nz9x@oSL`mLVg$gUL6kv-8iiXG}+Ks5DOP>(eH>cUl?362f zo_*WsmSaPYEgc=)u>4!CFbw`-N7n;C7`ukKciX0pyRIL55_Ie~=whvOmRvyB2fEs& z?b04;pL9(6P&y?ENGg%~rLEFEM$!psLXt})7^?)1VI`j3f)Q`xIhhwKOo)D2_CD?y zcY@=Oai=&2aT<3Vo;a>e%utwYr8~)hGMw?liO7=!bcr6QxNUTFl>6;#ubs)`D$l%2 z*2nJ~zZ|#FHagJmz%tHMVY+~8G~H@4c|?;*;5ddeIT5y)8P=t6c9U5k?K1O1q20C} z`aQ%DiejmdV&cyM}(qiBaKV8039%cvSciE45;Xxjk@s&b_=;!B1b1m(b zPOg)`Qs|Vf=SEDsr5E^r<=*B`@}CL+$$us0Ib_+yvK+(n0)%4l0P$Fbz`F#2XF0CI zB)d!|Sq8~-A_n=AU&s;7W+ZduOCn9B5HQ;UWg7Kg^0&j#W3E6<1^9gk;*fUGH=knp zXv*TANxswRnt{xGjS;ZH@a*xEc$sW4gu9n+aTP!UVk=9p`j*3hEY%kIC9$Zel_yKi zMSi%wc|fDL{ZovMg>+7S02$xQ#!nnOFojNOA8?b~2M1I?uixmCLT~%cnK^x|f1z8z z@jiz|mm6wxxmxK3N_~02OA7yPe}SGIcXd){m2^k4cf1S>pwRfAJ{w<;pZ;L{-Wwoz z`zhWxJ~YmooFEb^G zXbX#cqD42I!WQ$d?mYeCQV#e^_+~%c%B%_M= zl$YuE?(y#P9`kZumTAm$8v~2uoPouY8B|WU>X9xCEBa|3V&bynikr7fvM38O%d3@k z-dccdvcq5)SyqP5Lv=cDwh`jyFl^g>gYRE^?{ZZhownhU)I(h5&bLQb%Q%DKwv z4hCm=MbiucBS953aBXLPNE8jyeZ=_%*jkPPkcB83gJ$Lv$5%f&F;LU>Wmnha;RzBQ zknS&am^!3&rgahrecVZRmLg-HX|6A_;DOtpe-FDi{q~Lz$G>>|z_wct9K2=Q0mg}| z?iw2ZXzbPBeghX{%PTLx^7`{HzXVlp8;@{PfG-a4@?H!4NKvP&7phBDZmzaZV@kBC zN?B1uUPIBvMg7`#O>FVB6kO`Lw4hVGN?Ge!Td-c-phVP|XG6g;?G4xa-uLt0C_d>r zS$sm9(A;HQjarj8i)&FAahIxV)KAR6EgDzNb}K{3U9kFY0z zUn(j@KMU+KGd0XK?*+_KW<=rV=FRmj^=&WSQ*3H-HWkb*Uf^6%0Kt4g$QdfQws>pt zoBUgjU-O?SpL^A*OsP_n=VxXqOPEE<8YaTLqrB(+*!`LB*9CuJY?!mS@*(cD@-7Ic zkkw;tL?r68VbvC}U2EHF<7{dBd7{pu;1ws<(?+EY+OY z$&}jvs+a0m{9M*cJ*jq`PLka>geZUJNB~k_+-9Zg>|IH+3a-mvk9!2L6}Q}XQDp8_ zS6_7T#TQ)dD&{Kh9k`_Bp{m7muT74&5lbdU?Hh zy|UgiS~*%}BWpY5Q)id2kvq-ZmEG0pvUK^@^6$t$PP(PK3MsD zrMrkMXFH1hYs9JwMdtFg$~?|oSCmfzqrwv3TwlBI8sA>uYd+rQEAb_KANsfw-`zgO z_aw6lB7Q{TCzb4oQ1Nl_lCX*yvK8*2%iTn`#1&iZO&Hg$Es7Q~MTL0+S6F8*$;bKS zzJSx)?A_pybhqfu;xY&{EA6U7b*e01 zYS9XiR4o)>({#8LyWnw(wX6V@mRS^WD!9SbRg%ota0RGDEh2-4zAcGf=pz5Lnj3E< zQOW>u^Cu56R8>~hL0mVx`JDAO_#=zcG|-!Sz;^ql%^PP`eCLJT?epeL`*z3mPpz@< zQ&N%5>)r19f}5Y-xjOQ~^{>5yFD%@U3@^B_%v;g0lo{)MiFF>3y0t?Qz-H{X2l&>?3{b@9FT zs27FrV?uXgAv*r8JIB7WtTvy}auf8L6ZD&XpL!hSlX)NT5E;$sCX48&0#hBXrWz+M z7oBbeJKbjJ@OB^vHM%Rj9_nIv@G%eewB^%oPh5=rQ~6AP{+|4O`4jnEKE$_KgFwz7 zYSM9t1UaeAmknFL$aoiE8R*+1X4Rr9FX9>4tZyDk|0!RRHi_E{-r$JoJd&0KtW z$KAIveh3yZIYq^O3cQf<)kkJQh+b;<%cM73?0yN{t0s|Ln4=S)AA~zL?vUeG0jYRO z6RL&_JbfCFz}rS{xWLo9fkV}GO-O@_O__?SrApb4X33YJ#qw&rn&}j;lzMOv6A>fQ zMl_6vnGtcLG%Rn!+n8I~+lAZ2Z%RKzyQFW+KSuY-PoX2ie)&c8y!<_3m7oNsVm6=QJSK05fvv#7NQpuDiwXjH!ZUa9lDR1INQ;m2PuLDS{)0awRh#YAsM=Cxt+rJ;>RoeCvtwAiRounyRP5aYkYwMMF#57> z+qP}1tIKwE*|u%l=q}r~(Pi5mHsU-YBL$YM_g+JZA2A8J^mEfV<#mWdeOSOv7unOknj zraEE&`8#0UkKV;u*I3XVen$wOAHy)^ z>hg*`VZ9sm)~dqYQN@U2vvGNHIRY5`)BbBkmcC-nXt~T`y!m6T)~YgKA$z->CvU$@ zR=+?>T;Qx6c#w5GGoujan$PN+TE76#T%{&k-_Bnv*>aW8Pg^4ot>Tr_%5IgdL=@{_e&CRhSC@#i>6xg~o#p;qk>{F?1PuiF&1YNxQG#WWR)+*VQpngBFij-B+6`+@h{NdRIGNz_ettTDS+lmsDL<+Hqsng(#M%1$I zhbv8^nW(gkwpT<8hzT2J+F_Bq;MQSYMpUDIvhY(~9~V&nOJtE4;cB3oq_XDb;Q6|kat2E51{1DLwhc2 zoLXo+ODK#;sJgSSL0wAv@+eHQY44U5@-&9$(fPE8QSgip@M<}MqkT^)>X`JhPa!x` zEpX(yF@_X9ul2F%M4_RLZbtRz#{GPY#}!skom-gl7@+nz)NFta(pm~YS4cCD0i^)P=;6L(A#=ZK8ZedEq55ZaL9!54131r`z_)A1oK00f|`EJJRP1E~eotz4{8uKK=2Pu~-f zD!PMIrmY>J%0xZDI&04wE-V8f6f4U?YaM^l-4xm+t-C!Z<0t>C|Jwl82>pk|8!1}o z1D@h-I!3hs5+|EBXeGxS(MTl47;35?pnuPv7CJJ^Z-6lSX@444l{C(9s{#gzRM*dKBO3nS#@+T*wGNVM0LhK|^M zJb^Zj$sP6QuK<)!9a!%G;MB*Myq9;Tm9;42UByfzBvL`-r*H_*2zh4V$zdFK=%~IS zzLZ5Nn6B~hDs82Rxby@WHS=!~O8P(zTl4Sw%XfOzg0oNddSWiO1P3igeY+`716NXw zZmL^1}QPpOI1S~g2UJ)6R4RaEqNhg?puyO+<;MjkzAcQ*qT$Gst_J1(w4W zwYQFv!}s$u^|LA_fJbt@Y0wmT?X%8eLnI;fO%BH$b{soE4P#6hNXm~-of;R@v`7ln+SYpsqejYK)2wCKH}}FMoK&E zA|^=~!M=k1M8jhU@{E&g*v7_!L3S$4u$Yni-hv3D6qGZwTERAa_%j?S6PAy?xY;b7|R*xRS)rdysltwbzrBtTeq+A1*QhG--KCK z!=x|jyy3caH=1`Mzj3!p{lW|BdxO%=CDuX2UeJX-aB^Dixf3v3LE1$qAa&`?J1=l!wFM46W;N>X zmXRhN{pg@Z$_r)`Ho#x*<0uD`ttGy_K(bZ&)e_q#P}0GXj%q1!aHmYO`r2Y#h@>i0 z{Vx&XQv4uAc&L1YHP$-_PnCQ=D0*NQ61bfDIBDVAZAwUn7BE6yAqTTqq@Wuo0NUK+ zo=y==RcIX1NMpDUA)c`HQ0y1775RO7YNTqDO$N~)wXgB0S)*u)yL5UgZK?*S; zLHv3?F-Ea1+4O^p0w=`Ek|->t#9jp2jN;2(6zG-&Hc~TeA~4!_6n1mP&_*gz3t}6I z4{P_uRelMJIWyRnig1NDb65P5sXi2!97T_%;f&noyH@67#c*ybTM`g?F4N9zdRUIW zL~6w5(`I3@QG$JzxZj1zB&AyMi3N%p+4YHL;^P!aWrQMQ@R$u^Fj6DjSs4jhM}C9(GU!)x{p*%{hEtJ98ls1Y>H;T$w-0PIctrlOokEI)yHxilZ zEobqLZ48x(1RZf{tD4fcU}u^V(u)^2WLtjAdyGgVhs&%NzA<>=7iLOeImPl7IxxzP znQCPAY{)xNh*_BxTR9yr{Z6hc6g$(V|LsGxj#j@?N^fWpR*?y;3QKfitPCc(f`8}D z!V12~G<`Z!GE|yP9_5W+u*7a;{MOa*+^XdcD~-W+wpy4qTT|(OEg(E*?gsmP_9eNe z0r%u0FFj)$V`c(n-#N#x0q|J0bpi?GnKJL%4EpnD+b zswuL#62#|waZZx5#ka#5bJ~o`Cbbl;F2dE3PFp&kJ4Sjy9toxMqkc)k23lB6Eh%b}1y5!`@)k;a&J*>2erT*aDL?LV zK6vios0YH@kTo416^O((mgd+eM`|LjY<_f(vkIf{a_C2-!%Jg)4Gv7>!KUraADoJZ_h}ckb=?cW@hhrC$NDoH~s#iYZlotQyS)phHk z&-{ucU5;koviHC;Efn^KJ(k!o3>eesc)@Q;Z+!ZYJJzMLZ1_2^Y|}V1JbeE$$pJMLzIYmhx~17 zMO*%MD7VtRxwtHdptiikaEet~+R-PUF5~vIFLyFe3(B$^M29vr;)t1R3y8xng&JnNtZ7a7igCO{9>o ztB@a14XAM&osLqPh;l&*!rK?mVXj;_#1iqu8dMNL1iZ5aP9fjoHe4&% z=rJM18W8rN#I}rS;$SSi0&4Vl;-xI|I`x<^q=fyHxsasHk303W0$hkS^2H+rXx~R{ zT{uwWijYPU(IQ^jM$>tf-ao zr3FaiTp#tQWF=*b#Phec=@Tp>04647QI# z!Rm_yh86vZ(ZZA-ieWn>G4F$N`&+BoQlVT<*I?jb;s@b^AwCT%9m|tLDM4up+(BY$^lYwLC2$l%=JGVM%oW%Pv9Sf=Ln>~ z#ARGb#C{SFA0|X;1xqJPZL1kcO~eb_NU#LjpLsYlE5WUtup0NZ5)^3!OzBb%w3?DO z@D|hw1g~lgEq)4bO)U6k$DpJz0iB9j{=a^5)$jMztCUq}6*oNI&Cdh}6_j1s;v4<6 zu+VKWnu&kDRiQJtnOi|OPoYigs;)51W3#yq4}wmiwbV3^qrDmBLl6y~6QKcNL;zPV zDMP6}_sdQ>k_CHx6*J=%d4|kch%zG%6I5anVL{Pg$G9wB0p|jQ61~TABm!E2Sq|tJ zu}w9z$y$IMc=6BW3Uewv6&$%!k0M;dBBR0p(+>%AjNewkax4IMFdJwTmHOc!C zM+?3K5~a(Y3N}AI4szFv<6o|nCgyizsvbux!=j80B?caFDnK1TIbFUs>$FnN@%uIo z22~(|5a$R19+!Z<^yY zl4!MdzaHCg72rlD6uCiIsCcn9^8;mF1BMmYRxT7s_*1eAoEu5LSR;&IVvmLDsLjZ#exYb>aQUl`w)c^spf$70d?`x=}4o2FFh1cW9voZBpbUF z#ufjxNyC5>E%f8*5}i=~9t_{y+BW#>N;?^xL?%}&0+0bT%)#mQGxG_Q(T0nHXeAV%Zy=41{7U=DhkTpRp zB4_Li3H*(aOJhW*>tPa^_*PR8aG_67%sd_Ye_uEIiw7zsOD|_*Z>4YfH_`kbEF`8s zu-89ZNdHWsE4$em)Bjrp{U877FBIi}4B0V$UDx`%m?RN4uWBWa&57`lt-BrLQsTUe z*(D7@Nn(5XtS?8B0Aa8wa4k2uW2&@#c!<%=cD$8!UUDSN$^WQ2xmHBe!V z;^47fl?*Rb)=s5r0sNzZKiC9vH`D6k0fP;l+B53tg&a@nW;nk5wJxOq`$G8hF&4wT z6bB|2@d0`PujF8He&KvJ)bIO5sV({j(kRTiDC|NahgASCTvS=7l*K~3VSD{X{!bf6 zj?Ld2iQi>ykKC~nPeuepSXDq@E_su|UvdYmVqwJbjWmn$HMkXfwC)1W&2Djg^QW#~ zT+xDu!kHyc4L#xyi&$f)>Uf2jjkUp_&-6xv1_k!Lb8kV0oW^$TBKNujSN#^jvyp3B zYs}HxN73q5ndCH3cISWk41|1$~ zvt5o?sjN7L6}w@>_@slOwvbh@vDu-fGfNoPBsoAVPdOv9jvGZ{W}0Yzo=$%i{Z!{Y z7(!XGZNTbMC+-tNq0(~u8^bG#qzjO#XgdtfST@~c;?Z5MlfP9r=%RQFDK>0DsENOF z1-L-Sxd#MkH>(sZKy~Iy$M#kN@`4vs7*xLwnXF8zl09ilzq^d92~HrKt4>CszFfIM zYT1{99DB+|`UHlK^e@tSMS@AO`|6$`I~GeD^s34w@^QDc?tTkEmkn(#2WJ z^(0te1r3T#TtJWxLjW)jfLdq<&wKJS|ECcohXWB+BlPJ9*~Oa+%Bm0^^wmdQZnRd` zW7y?U&e2ODBd_E1QabUWA-w>mq0I_L*i^FqpBr^YlbonA^DCo;3zbY|&;YB1_byUO zR>yYwR-d6Ku_)Tc@lv{Jg`mFT2`t`*Olc72Zj)G?-?`yrHZFrQ!7{cwPBcvx*K*q- zI;zHG3;P?X*rfq**-Or@aBdCbUp2)s@LBBOwyXiEucEHW?i3eof0POv?@*|xae(@s z>7^2IG1$?FE7-G*8kKtNNU(CI9w-1^k?N5A)AKrl_$g1~GX8sPhQ_W_ ztbXVpz?Xvwr@x<%uScZL&ZA0F#(o>Lv?B7iH*3%gY)1V2Iq-U0^b{C{k`Qw_smdR% z>*Lw>;@N<(tBW>tiMD9KBVUm+WO_KZ`}=uc>Fg4Jyf}Xevwy2n2AB{87?RyD806(h zD14bzmhUZL0Vem^@Y?)Z=j}u0t(C{T6F>+Ypd%cffpUZ+Kw?XugkDZ1#YU2}cjDx0 zbZwnI{vh2TX=FO)NC;?=PiO`JnWjnhf4A;3{gK80xuE_VRGWd0>5Jm~5)c^}7+5&J zs5^5@M`QaxT%Mz`h_RuKk@0`gn3plOHgz=nvK<-dW%V8H&0RGa>AvdtKmYxutxd0B zZfs~QX>DTjhlLgq64e#9v9h&svNrlt<-eX2u`&E+?C5B2ZR+p`+++UJ9Vq=5S3|+x z-1%$O=_QQyjg0O2zJBPHj2>WAI|Zh1>N=04Ars~ z{VR39ueP$2bDro81OwmtIX9$=X8UMaR_=mce{X^Xc zJ@N&m91{V-kO&G%pjwfjy(^l-3!D))C`TG+f;Lt0CKM{s`rUQ7_3=bWu3VHcuiWmf zPt<}>iCZNG7t9wpGu0JE6J?enG$R(G4Px=Vc&=P((Pb?>m9y*6&<$!Y zX1@1JuO4h#GJsoFbVUS-R!Na?-~T978AYNk zGBlIh9t>J3LRrZwrr}q(SH30Xl#{*Nm|YC5Gm4QsvxAg?ft-P)fuMn1ZW>AQ@`V2m za~NqD>eq0vAYVK=xz3K)?ahvs8rKGkHTQ)&cJn8Ub7KuPUze|RuF=2SLo)yMAVlB6 z_z$2>|F;c|R>;QE=>K=$p83xn^xyY7{=fM4+F#f_Gw0vEa{?BYzq9n(tPGlem*D># zZv2Bv|1a9SHX8>4`(G({c1F#=v+(~4t823}6MP-B{9Skdqq8#;{C&mbS!KvU)21U+0IPI_T{t_Ffy>P({Zpeva0f%Iw zI;Fxow8`=073lW>&|myc_apA}d1ImqaBmRkXmH#jQ`aTtZpzkI|2IH--N7PVno9sr z6Nuhq6@Vglc?atEDlL2#EDuj0eMeRmwH(+lxCb9GSY@$6OR4FtogH8p!}sc8C3qC7 znWhg|fdhH$@%MMFSu-doQ5^$u@0QN|$=4rIp9BIC@C4RB3=^8JH-@Q+0D=vdm7uj; zUJjZp{D;#cga+RWV`hPU)^C@aIim5o>kKbz3_HkaKwnyhEd&Vs0drcfKPVYyfQF)< zOVpv}Up`XE!WOq~!7;#-asi>xBtm!q&W&(Xfy%#&nngot=1RMxVyQE$AwoIXDU`b* z9>mgb16gYNGAM=zs68-@3w@~2uoHKN9e~IYd|C#2Aczskh)D==;BWJwnh@;ejgLWS zR>wrR@&oyReVrc+VYZ_YPzzD;v#m2>Tl2SS`r)8QS2a|lVu(*yXw&z?-JrPzR=8;B zL3xOpIyM#TP|b^aoWW8D47iRpt&dCK1$0Vm_lDgv8H#NCX0m|8;qS=wzzexrCCUSR zE%RNsEth|n$)M6Rnwm4}K|TDQoj^uhEy$K{C1lJrHxqcwA{I`l113}!q6dZm&uwsq zxhI4Jb||NG61%_M4)5JT=sifz2WG9<4H(dA=awt-imSI1ur&+H0!)y3PntOB^C@!z z!gP93A82J@>aggU=L#A;a{SR&rwx(i7nIl$VKwOe_;1UQd$mas4Dwt|h*bdC*_fk% zbK5d!+_k8C0dayi80!~W5sUTMs0Zqvk163RgPf^w*U}v>kWSGvy&Pedhwst0jM4A* zIa$qC)t+oG4IpkF&*6e?Izb8nY-%yn{r7#>b1f4ymtC>TAK-CK;6s!NTWhFY zLe!)5{hgs0;@1KGh}G`~^~VJe@`OASPDj9qrc|MwjlLpHARj>-Foam!PJ!62?SzTM z^$vJAo1t%Fh*cQOJZx^BS4-3F6b4RUi`r=cYS2IDS-*wc91@EVl9=NMLn})N=~(Bq z@R&TiAD?Cnp~al?(HOV`#(3PY=8(sf0X~_?vdipph1xMTzA)&zEL|c+7eVCBozHr! zjTt5nY2qI^Z`TYi66+#U(cv*HDmz6L=D#5zo?=9JHBX_vyV9>kdrdBE_}aa|%IM>F zqa3rQ=BxWZiDhoe{px$JeoyUF(kt)84$h-5$v?9y*}BJZd>t9!ShznUtRL`h{+#$01m{FgZ-R7 z?Ip~Fu*Vm9j|(w|7=KS`)ZqpLU#cV(eBfq0Ny{7o660a{9>!yo*nKse$^hK7Qg|u zxK0Ln|J~z9Q~cPI`^l?^tZcJ4h|ebbz2A8&V{8}(O?seYUANc~KjFcFW*N1FH@9AP1gdF) z@>w>!ahsD>AYLh4QFZxe*%5jSK@Qo!Ws-OHV07W9*TeVxuwoxv_g;g3DA?@mX`%6D zl-TUXgTfKt06GJHT2kYe&6I!Q+lM^cJr!MqbU-)r1(0PUxT+I<-F+|Wp4+Ll=*{~b_fvwOQGSDd6fzt5tq`xUO9XmPR$yIF`AZX7a5SEGu$P~IARv!zcw#W!nh!Mz8dYi7_JhV$}DW)258#2(R zR?(LA;hkki&YONqAg6yV2xIk9d@0~cQFm2f%kW+CT|iH_JGYh$IoU3^%#}g3G#bFvuI6w{__U_xSL(bzwrVSTsV_1g0&Ewlk-?JbXePK`@;KQXu z`2M(0KpY%j<7hjtqU-l(pYmNF=%Yn6a-{oLfS zAl}Pfr>YmoQ`OLyZ*L(rOd9EM+22m%I{k%ppOw2l+L#{NoCxj)1o4lUu4(+c`GmX! zzl}BHYxN0^8Pa@Dq~D!Zy}*B*(jzm<%Ys4-2(9@xssUYZpBts71J5&g%5j%sy3_Kb z7%2y5x{(!UI=CC~^uR%26%c%{BfJlwE!nnhCshmWC>Gi+t@X_`ike8 zEt}obRiy*{GPSA~%NLm%AetX`+5_=`u>JcZpTARGten6buRreT4}@K7N1TFR=mj&M zaJ{Dx=QLn+ic?97YIF)l@|H@k4%9bV7Z};j(J?A}F}e}9;IlRadWpC`Xx9^=K0@C3 zqe(4;dg3*eGsLl^mvBubBZ5yfue6bH{g%cpW1Kak1?Mp z)H#3xX&esuoh2KDABJm(Q$7Lm9Ts=bpPSpAZT*+kKfrlzJ9_oI*AMA0IlM65pEIEN zi9Cl?z~r{ll*lJ%T$52vt-ZaKYdCB!(GMl_y^ARr__=Ryss9#szG~^hnW$I#wwCwQ zp}YQ(G*y2%C}8lhn$V~k&^SZ757-z#SP)}#3@!0u0`|yyzc^ex0BsTdY|3#6QXI($ zK}%tgQbxT-tEPKE+LE#}U|Z;VzqPSTt%o}K>coa=2rD=1)Q`@Ew^CMf!+N-LwR6XF zAge6rJm<0ptaJBsuNCkH&4w!TM++Zp`}^3=_*UqUc5>pHMF$%n$tEf$G$z`mA3j1pjGw!cXyY`W zE@JE$jNK_?4b7!_^&;8{-l?RuZf$q1;bQ;d=Nk3e&vo{eOK1MG3)@S3{%!Bc_i~S_ zSFcBO$Xz5JNMxi@WGdtXQko~J+oboOHR8uJh(pJA&re6YyU{WH*)BYvPxHG)L-gF8 zCr`9Pz#R_qd)ZGto7hLNAW!7;({wb8a*gqeBaHQH&}J=Qgp9DMi;a;M>@)4- z{I*9g*uM}Rv%)lL!JNF!vUsIM4^NH=$IsWON;!)I%bN``}n$XcMx2tIu#DXGi`4{+68Z*`*l;O^{Z(uZ5xW zv2P=wQd9h0v-JXOxgqgIsd z82RC&*6-U@@(d3&!(+R^1_&$O6tCHr>j8ZF2qLwgU~m*hF-En6*Y z`_?4r5^~|ZZq<6u+c88LsG zOLhQ9C2dBp^#54|t&i&oxY+Gf4RsL+zRkx&RG+6_6_~L_;Tfa;qM`;k)h+l0ci~Ta zMgIio9q6&8?+U5oE3QYU+^bRQui6bw-#c~%)(%zGb9zNO9>A_oe-xyl7&)^A6y=_qH2dWS5CIyJROQG|UIGJ>yln)T#9t)-w-LNsJdbGW$lM;L0kQKE6d#gk{z%;( zCz7y%Bo3xfHaUH_jV%mc&{Sx^aKGfvNW>oL4U=0?yOd5}<};XGTwcE{(y&f#OuOU; zkxhb&9=arnq!ET>u<#YiPD~5s)WfDaJR(TOuc?sAL5_6W&^wKo2IfNg1dGk_zW*nGu#AYOt za;g(XFYMJYv#b`_nJ z=P4U0e2IKSmHMnPXYo^Y%+RgI(JrC97%in%w@J?jw zPt_hS-JXFy5dD+!URArebb1Ecm~w7tQ`@w(dWPGW(=qnp*Eaup2JGyMYlL4Lvo!Q8 z#H*LjIHyMV%;5p_HQs9guC8jC{Y=w2@IAq6D7yA?8U9T7O#A`)ITFW!zfSkdY-e|l z#0{~U7F?A;;{oH|Qg6p~>UDO7tMn~-K2(`iHg8p?kxej>tSh=LL^2O%LG~unowfep zgkA#^w>92?XOGuv&fbd?-2+>rwayoNgi?c!SxWTmq&Njd3O_*?Z#%_zWGCDuA zUMssy5|b<_@{xQinbq*^#79Bqi38>(J=ZJfXVJ*o(1T%03lOHsTd2MYmB`?w;v!?S z4i$DDYzuBhMoI`KEh#L9m7l_h<7Bd!KRRRNG@Qb4Ie5~N-v|tQ1`RUJ;yupHcOaKf z)8MgsiA?(%l}1&G>+lVFl&-zB9q2$s#qDsSskt3x~}_klB%x9dsN5k)vPb|Ja`Z}f|ta~TJ=~{AzfrO5YjBDH^Di#=`E=)_zqx{el308+7ObKX-?MQ zSS8f2QVa#fi-ekTTZR~UI&{k$Jvn&$N$#Mz0$cYN&M;9t@ZDLZeV~*x58h2umpINj zsaTzaOR6LEEc#c87OgF6E#-9;h3uGhD`+M;N7*~9IVJrJ zMu-uDLQgi;T{Z)3c@RM>P{St0=?q0m-FoV-ZuI@pL#!tf7eUdaDpw6jLGQ>p_4MQu zVq|J<2d}O4EoezZ8U{s}-8s3t<9-Hv*c{kj@l8d}O%)fl-D@`}-;#co@AxC-C@YQ* zLCE&l-Fh`j!!OID)i|8?$6J6m4oX;oK47JxudY-kd9BY$fi-eH*VUuE3aFpZ(b!P; z=cyJTMwkq9V0E!<=&QFf_4U}_<2{kB3+DX_?2^STpVVF1nwnQ9W9j%gFa*l=5II5t+0ow-Ts-Fn^**Ree+V`D(y2!oromuqlIr6(t=o*n=ROOiaxZy6d2dZ;XW-ZaVgT!G_tNn7T2opFe z%5%e)Rpn81wi=P}JStH`l9_NpH$i@8`ovVv@u<&wqSBw9NMJ>!1onATO5Tk(G^|`% zK2&o>bMOc!P&oTaKv^i?8t$TGF}3&%72IN-i`gLWjUnsJ4l*0rc5@qrWCX0Ng6LYR zE7~jasjEFJr5l@9oM*w0fUTlH_r2iGq0Tf=cd50s!xKu$4CnM>9JvD#fT9JO>O1F< zvX77BtxsVf$L{vj3pH~w{QTw9Vb&o~unMvDFo8rL@}uh!)3`Zj%wZ<$2|lS}5tE4} zrlaMFM)5!DbjUiboc1~Eh(Ye0y!iY8%);Mc5xHH)}?v_ZR0vShv2vE{nU zeMiiB!UAsUe27_iy>!y|&4(Qb-^$9gH&td>IyRmF*e_o(g|H#gCrsyua5?Pyd~l_? z@M3))npN(A!-JHidKk~~Y|%6YZEynwcAUwQu?V<^Z3#gznejzpJ_)x*Z!NZ!cr{z= z9Ktwjor_u@NJhsTN@iM{_>bT+2$Uq7sdwo|gS1`M?{BT)n+mqM85gJhiagqP zw9y_n2FHg>%c6I}OQ9%5ZO3)7en9xsbd{i9ITwLi{g?VJP}g$(#E6$Cww-%N`Px~b z3Xj}e<8hv~cgxX>^(y_VgokDp;Aq8ToPCw3#Es=~^bIML8vyZr;x#OBmyEf|`Q+b*M$S}Gi@IY7`kHRINk8%4s z?A+#8piujY}-Kih&Rj3*Avte z(G1?rgd#;z{0Tz&h@@DGe?pK*0Y(R^pLAk@2&dFnXo;l|53^7F69{|mY5zE*A0 z(8>oVbyxTk0!84Z?sESGh%mgwBf&7dR@aPr`b#&ITK;s^v?($_s=i^%Uw2LHb);UgAmNPn&Qi z8tI(kPY}w-C0$Yc6M{tAAl6hs=&m=x_kGT>+&L*{b`PXd67+%S18hKbpe`XjF)fjw zE~_QCx_VH7bfK1k=z~H0YWV#$yYt9#qt9a7C1e1=}w!@XK@6ZLJ zIc$qrRiT9idT64ThZ|~Bon;K!UF3r1dR(es=}%%is{A2tq(iP7 z7$b0!8$$#)7~V&OoeJD&;ib1wf4mFZGqL)XzPO;$U&MAC`M2Cix-NTZBQ&-QbX?yC zm~A(3$=0IEbJhTbHe@^GWUlT0ODDj+3PsqFqq5thM>v~d$X-0S zfb=}JVA(FZpqFu7@nG-;ZU{7*yg6M#O6o|M8)sl?nUmFl_Hp+)^fo(+)G3~BAnHluH{KqY6yOu(Ji7nhyZy}Ke ziy;u@jgzX-jMnnwEsQEU<4%p{Zn}Wy0ueX~>cyBG<;`*U6#cT;uv3xR zX#sUB#5m0{5ulEf6HM2pHL>k|dTN${#QbjyDd`@(7K+7e3tas4Z>gW)G4}Uq_BY1( z5`)hRs1p>|R$B=#Vd?~nx!EK}vlY}xMOdQ*INh7b23o+C{p5IiBp>b496Z>>D!zZOC^=05~` zmA&OQ1q4Z&DX*Hf^eU?YVjkdzWFLsfgcC zqON*o7cI$++!~dKnD0y%@LbqK+|=8K`v>oW4tO?``-c11H8)RcE!kR(DuS>vuRHNp z?x_ml=xTo4=CO!|%{+tZT!gc;9NFM^lgyb9MT~72u@eY^i*5-P{!@|N8M8ODH?GK) z%o`}<{H#hDXVO!)gJ(n;zsaCgLR!fLa?JghQJ=+Rsc$$<$0@h-c5ap5YNpbkrCC<< za>?*N^;<*%I>GIQZt*)cK8}8`tgMXVS5Qs>h<5H_igwPper^=cZ7b|Q7pbwgSINbT ztg{8=aMNyW5m~Z#lQ3Vy|g7S*BI~|*~HEN4Lf6pso=Ax_9hriewL%6~dM|UZV zcxBRF!@N9rOi7-+Q-m6Pr5wVYnUulFW5yQcbf#WHP7m(acwDJ(SU$gasDH4eUAR~Z zOp2EEq&}C}BoUOBa>yZ!wWJg^EYR?5Z{s%D?e9L%l#ry9H7D!U>0)O)W_It=&-ksA zA^J$`1*dqDA*io{^-be7P~$t|%o3GI?EIO(8X&v?jdV9O3JBc2Ul*BeXp@~x*B}dS ziSNsaZ^$-2N!akTWV9cwH>si#h)nPFE9jK5<~GQhf69GYb+p>G5E^8i9+LiW0?^M9 zTt892K3lRih({1Sa#fH zZ0Sg@>{pB=0+ege@C9;|g&A3}a%upoeeOu49lrClw)jtBVabxntn%9u33_bveFkO$ zv{z6y@dgtf=>>jWpq>2)&;ca#Wngd#ibhNwIcY$TTAoWjeEa7xT(nU@B9FvVO4OT%>Tf#AC{_EA?Rt^B}TMkHa2E&|2bS-{w0Ym?aonQdwd(N3se-UXGgX(2Gq~Yj@8A z$$B<-`SDVbo*?PxXKd-TpvI;fAH#FLwFACxgFm6a$M)2j3o6gB)&4%%#TAg3`Ey zoo@#B7NHkGCYKcHaF8IRBuW@@+XLDmRgJY6i8A7C30M=x8^GMcDTQ;A&vSDGtH{-H zN9{eI z3o>LqZd`HGIas9FDZ8;(oZWY%<}@0DiL0+m6oc_&5^U;Vm(vpFU@cICpci?O7{es? zCx;;C%e)kI1+NeAK^uY3+6HY? z1xz$wlyB2$G3FR1p7k)%Yx`2KhqjO)t2!}``%yK+)NQ~5>gow^jdsTi0Jn$N4oOgP zimlj*I_C9rxI%6&_PrXRR`%6>xM%x3+^7n&d&-{m%QD&V;>^&@{`ze>W4Xvv=BCXJ zRN;lX=7;!BDOQJQssL%zyLbgXQ(%)%fLg1t$yn+EIX|mp4lhG8GaYKd26_7g;zTyF zG=^%{0o$DYxV6F&?zRKuinKwTxMVAq#L7fkwJULoflRo|kl2CLmOP=^SXgLX)J~LME-Hjl*WjieC ze@z22g63@hd**eC_o=xF_y`5#NUz61>RnkCe(2uI+xPk%!)aWGK)ib4vGf)~?8E1) zZyd`C)I8A~4Ax->Lw4~p5&oJ5G@Xwau{&^1L2XxjKl!SuogUmD=`=?w(tU#Si7pEd z`6t$p;4fUsbPQB6yBO_>E0(%UT}9l81rTrli_mFY)6|!)5!>X zP^;k^1*67sChS8E{6Kd$Z_sa4!-XW_DJ&{R&xnFs-A9`$I_5eJfrA-7xAd)96eSAE7ocg?4d7b;s3+-1{epI}*aQ%wxx$VOa~CdN9*r0QsfoShBL44n$d zhM3t8S5wvir+$DaS(cAj#!kViw{oExPJ%<{`d>zOFI7uMgd zA`?r~8u~i3TZmDrqhAoj3%9

QsKH{N_IQtXo9hrt1|lnPuADU$b1Mf#WXL540@w zE<8@#F0Z8OQxUAFsjSgKwwhJD+i5%cV&Ul8z(u5vo@C4{Sa@78++QjDNjO}NSzP!J zEF1A8vI^c3Ml)v>mo(K7Ze+e)Qol0+;n4{k;B$2Ea^cjyNbaRX>g8DMIY7)wN;Ap4s1QrbZe#tE*5V``zp#LMbd0k* zyt}*?88(@Q#xrr}_&P`1MDLw@di^-2mEG^NJ6nViKOwLe+-5(nRz+kG%f{oKcdB2% z)Y$K7_A2h6@k+M$`EcS&4=TT>B66uMFGB8c*j1}z%+$D_dF@YVTs_uVK~L9=^m%&; zx<0+3kYUyl4lFS>&5ACFR+pGr zCWU59xj;fP1n-ZiW%HwLCQ9rDznh?3h`5J@7OfDIc$2S*B;{ccIcoRk8_x zB<%P@B~t@)I?g7{5nPkOrvpWKu2J%5Sd{e3_W=*ZMN>GWq5{%PW}dyBdrm2b5r>Sd;WUmJT7;@%JP-o2;ZM&zu`w7PG+FBd?2brht`)&#Dh)%tM zI5V|){ffS+l+OK`L6hHamtk&t2PKag)Gp5*ZCvF^c$&PAbQ(9=ezln`Sx(dYc7@oC zszF7|)26D{sut5`p+Rk_f=)Rs%ixc))F9I~(X^qGg%Og^k2d0$`XwlulGw-gZApw+ zg*;a^=67bKYZU5U>xPo5DKN#gWsPh2k44pyNv)n~qd=~CMPQ73wvD4Uy01KS+@r;}n zCFI;N_;Pk?@B$vev$=tGocD}=0(FxS#7HKgHv?~IL%X~3BchkOG&)x(#%x@*xvkPN z5s>)zN7N?hR&Ei;lEwxrIAR?i*mInzs)x>c(5j5nEh8UlR@f=_NMuESHcI4|dJs z^wSFr;_?jt6&KasK(vFv`eKRd6Yq9uJ+Rd>V${lg!1g zF(N8hesC2$6RMOi^38_ept4iO5mk)A8nncRmg#u!W%O{K>NONOm94QZ3y9ZbeLl@y zA$|Id7SRAPBNM#k?QlFg^rlr_&CSBhA+DpkT&q8smZ#c`!%?{n2hv!S^w@1-GBzPI zM7+EHk`dT7DWoIPL!M-#e zF9b!xU?bZ_-DM2(dz6+A7GPUUM2$B|gag9`sunbn>ln@J?|g?d7ja{Qba(tysH5=f zgG?Z!0XJzSgleCH1B_E$zCj7!#sC3dIETOD?fb`C%pkYhM$%ixS+Vz8gd)#QWYBXI zL&a|&VPrCK{%8}lL*V&&c_T6!Eh7I2Q*b65X8(b&qT(^o^}{z21ijUn6)bDFF2Wq1 zDgQJ-tfI9`mIZx5ee z*BOwlhNf@{kzg&j%ogRXN^9rYIqaJ{0nVL&nER@s1omPM1ddcG#{kSkR3|u;TaMC# z-t$&a0<0kY3^Ix|XcOBQT2=@xy#{z#W^$zW%&QorkS^~pnEG}n`MctScT=`IQ+s6i zYz%*3Yoiiz5vG)3$H$mq#VS_Q35oKmL)5iwk_ozvU%?w)P!nYko1Of%RG>)nE#MQ+0f zlO@59IMZ9%%YbDRd}!olf4`BCtDitUKT%fLGB%-5h$%)Km2C|?gVr8HAcRJ^|Cqm7 z&Bo|MA+8*Qnqh%bhTfjx0W~&{WDlj;*QTMbXD~ehGn3t@R(y?gb?Q$`-_&9jCMUQ6 zqR`TDc)1XA&oSXa0Js&_0C*U?6RyJ;YCucdrUDeMdGuwqK+qbO*iNhSR1A`*Zd~n+ zC5dz5Io3f#nI1l?enx@7dQ0m6lj9THf=O{eAH00z`!IJa&M*h>`r;Y1s;z4XR)I#yPT5SQ0qeyc1D7|!qHmj#<1!6)rEa&q!7$haw~J(;62yt&1b? z^PQhFGnXUzV2X6dzv3F#i$So2HKY&At#{{HmU+8c_i~JUg9R7D5SX9J<1dMT+H2*X zK#?{vO&a!F{gUC!^vNZk5a5^i+>OIdVMcC79+)3sMR?}tv%O8KYsi`9-+ufD?x&#v;< z#xv!NYDkCI^Q;|%-bsY~MQX~S4CEx#cseOYnXhBfPc(z{8XWCB51@({8sX?%T$;F! zsNe1~hO#lFB+G~MA}spah`8X}x#DzdLk#ifzl=SFveBxfl5c7c<`UBcKNnFkcG{!& z9bakk$Z*)`Rt;ezxW`RlHZyTblUzIc*e{lcIPd49Uy#giwb$=Immcj7pB_$h?xu}C zQB5}vD7{C&lE3o2Y|&*n?bbBZ-{f*|;J26%L+v+ykZ($PF_xLF#M1vl#ss(lRANzX zsDIbQT{krn76=*9%UeqSM3!ceW}a6>+qTRkS={%SRI-=?0ToX8Il5sSsdKz-Mx3sW zw%)q&Pd#HfCprB2OmCYRxpQ(E0=K2b{uOjC>= z6U`7C=3WHe#bU|7ui++SQt)*WZ7c6qFD-VfamrX~6N0p9TFh`oJ+C@=M{ z@-T#nDvAB~T{8$_T73~rqd+mfSiCcK`+^Dow^h#N(g~&?9N>CGuguXN7~C~mNa+GN zRjF3W4bV4Qq5#S$1i`tZUhtJM=CNH{9T8V;6txJ+6KkAc)I3M{#!`FfnnCoKy~s^` z=TOi{2Wz5XLENok9D9GN9$`|fD?bW3j6l_OXflI}*Z~w%(RG4Eo2%j7t~F)Um3iJi z{_f>%YHxLc(XR9l?bn;~y1>`?3bI0sQM!`R$;>>Q-{`yL6_S>F0-xzT;P@8TV@N!6 zpu0BoCK&?L?O9j!cAICbn;{Q=KCgW#OlePeAzL0^zO`M`9R6c7qTNfF2-C%ryyypW5!kKU?@)gIdmx|+^B zt~57t*=>}4+aqTs(h?xj|DCDeI1y>{^b;f(P<;fS#=+pz{RflGUs7{WkI=w>3WgSb zMo8$VR#?P`bRgVCvoe4(3P-~)U9Q{&->Rl<^%SsK zu)1f1+k_)=4iE~HouNqw$+8TxUmhIjCSVvfz1c#IVYuE?RSNnCJ!3fS)q6rThBvdC zFK(&@Un+Vc=>18zwYz!@IOrU`kJuv(r-jXiX6$l>8Ypfh%3yaC;EniVbtAqYvS2mn z?ZABd_A6e^wqSXN82nG02Rdg*|1KY@rTBdJJp7JC#Py-X^X-Jp4oS96@@mVB3{zzztk4(-=;M3DWBv za;{jI^wjKCa1zh$E1?tQ=BXexg0cPWa>W|vj5wcr=L`x8A5n=?7_%Vu9wE)q00A;> zLw*(sXEHV)G75qmpS38$s9!DLk{{uh2CV;Km=NJejQ1|?7sQ&3*^iNQ4z z6NIEFFAsePM|X3Kdzyj4st)##=2Db<(E7Emnf;i?drRl^j@@)o`s8wKo~3qZ*Qf5o>^;931jr7UecA zI_H9JJNXjSEinz(3$!V1fI3U7R#b;|uGA`Yy3Ak}D7=fw(Wsh*GG($+HY4^Bju<~C zNWso1oh3^__pBFBZ(Mt7?t;XHLx;dW153zJm3SG(xr>pxF#hPx*tGHPGp%U;fs zpW^+DoFVkcWsqE$SUGsPLI-hrL`i8ehf`lGs=whdF3#t@+7?_3c@2PSif_Fq3{!k* z8h35{e{fEyvcS|bZhjf=ae*o*RV*r*5C~Q8pOZ7@KA9#eC^GPw_###FC0mI<*xmAm zU#pu;inS_26ZJ&&s}H=os4xuelt)FdBEwgkQY2!fGOw#GSS6BE!DvsYg%YpKqgp5p zbqJS6jBt%kA>3TG@f!KzrjUF08Q3AsVyIk!NcLpm8J49IdD8`I;XRs+ZgE{9kTOFW zwJ=7BQshxLYFsTsUrJ`T(G5e<0D%RYpFgV_#mH$yZ6hUpdMn2Og@>0EW+YIGY zGIY?Luyou|*Kz4qBq`!Nxg@I;dG&Hx@pZAHYJb(6>qPL_@U|%<&L&MJRi}`BP;*A0 zyvA`MXZg05zv7~vI{JL{9di=7mL?pdMR2)EtzRqra`4r=+F>K{ZgNT99As{;oPTD> zEw6qWAo62dp0L_<;-wO$lAKry>>;a`%T>gYzSSRLr;pL0oul@CmpZ}lgr`)t{C4ey z^>DXIpXrYSAs-Kjr7m1KK+D8eq9uusl+7SRc_Wyk&=dfWQn3?0|#O?-+T^ z2s4;Mo>?;i;$=_t?k_{C6}+`3vhsj64JAdyUk2&2<@sFaqa!(i zS}76J-RLtu`p#LlT%|OeHSVMB6nIJP#Arg*nkPIlHDUgqLg#*U|69j;P2LHRC5Be& z=3xz*ERI;YMo&5puN!zvoi4AkwgEkxeQzxjn!vr8Uj`9-+*P_-GhF=CmNt&qidHEc zM2|jbC4!|=pHkvdsJ?#{!4pTR$Fig(eF1U*@aD1C!8^dL=g%^MPV$vNl z$Fe;UKmTowh15(w1><8yS*4YE)J<1~1$Eb~`sm|(dHBn6HaT3zo|&LJ&O|+MzzwwU zb|ZI-g|Xpeey@C1T~Q_sS4H5VPeO`kMCdixoGWjz}wpDI5Cq=jkIs7K+&$` z8Gx25UVbs0^7Mw^y;UeYToBsDX~KZY+JEnSczIS>EKuRHf!j=cd4B1{N43c0#8nC7 z_UVp#;Z(K@tNi_@vYOR!eIbJ3*@RIMtHQ<5ysf>m^m)tZx`rA4k(LdrjsV+57&Du= zCLzcriaG#p`{7JYw!q$4_woTkwCG}$J9!B~ge4(|4hc-d0MtGu0v-p@ufXd?t<*s5OCu{fVS+wP^VlyNB!hVTX!#A(@8yTq85epeh1?`^-wPYaMMRZ)^268a2Opz^ zuBKas-P-PpR0*ukn;$_P-%ehclHKW2exe8d4;=M z^o2K*`Jl^sQDS&Gs2#P;@#vzM`Knv>;~iN#Cf)z)T7#UAOMQsEs+$k-c?BSzkm-j2LmEF_RvD4BH!k&M$etNN~tVpt$uQES5NLqBS z?r140#2V;SU6UOsWYf~{HOTRV{4uApRJW|LCBG;1N1Q}GJqa#3Pz(#rE&YeBJB`$4 zSQ5MC?x(~`)&XN~Rfj%KMTHXj>c%ECv0N$you!}t^Ybc=%*`RC%+1uLcL)s-F49c+ z18a&Z3UsV#SZKPXnD%x;;TZ%|8PqbFEH*8&6B=u0TAGoTeZ`WQY^Aod{T-?C zMbfdwXrsTS(^Tn=gncty7H|FhMj#c8(;|)c#?2jtvnyK-T!&b>GF-wh1-iLg?y(M8 zlmNm31TBX?=vNEhc1`(NLv2F5hPVqIB!!X4ZN*W3(edGcD zU%Ce1rC`$%r_to7e_*2-j5kbHR+?2E?&<1;wVu*<$oV)b?R{5+aa-W`hyH$_0=U@U zcb(K&KCwdU(`~A_WnL&}GL^qW8=qK!uWVGpC=WO92u~z=Xg_w~zAZq%5ndSSU*-`} zlmHhyON!?{L@t+Y%z7Bw_?q|vId7Tk9I&U@5ODxkZ@fQZWHFcE;@AP>oKxNXVOm*DK zR{|-qH>-$cd;palvR?Uf(W7FQXuA0iiy!-#sQOlby(}Qvjm)!jwRLH^RJBEEb;(W9 z5>Q96=ceCQ`w9Om_5GrL<-=C^rF@&YNDtT1UL56aelVFGWI4wC?5E29h_%-pzQ&vW zT032-+-JMFpX_FV4I=K+?q9Rl-fbJwwj!NrFixSHCeXfrwwOe7jZGQZPSU?44pFwVwM0^h=b7`4fg0}_tY=ylWKN6J!*eF1 z(r5E0F?r9W31=lEuJN|5yq4SW>oJIteN?pHk+Y~-z?w&t0U=sM(<%M$uF`+Vga0q0 zAk+Wh)o96&{bj8>Zcw?4g1@Zs@{~!}G!-`n0^Ud)hx0BYHH>%(QdP!eA>6Pc@>>sL-n` z{jhL}6H})ilI$C7nJ_$-@EV0}WGk05_?-l>hF0n%NJB07Xfp+HDPly&*b5Rtk( zcgDQ45^CR`fPEOHthjYpdQsZc0;oC;QXHzdV)DFcAu3CeeN(b)I1iMkN~#m$*FpL} zLlN@}Y&>|L$gIiqv6H{{R+f99l$L!IdP~;-_i_14Wd4^c#Q$&aO5R4_#?j^31-M?3&6I3Cf{|8DEG;%PoH?wuLvHwTW{p%P0|KhFyVBd=g z$Obm9{)JaD0@!Hj8JPe8Ee1vnCLoydWdVRiVJ0A0DP>}#|J%*K4<=R?FyaIRD{G8w z^t3=m7BH*?c9OttfDFu9VACB8>;b{^EKFeJiGYb-0}Kz-GBPrQttTcH4Q3X`f5A@# z%uKAb46NV)2$+EYTCf$x%1Xct4uS1&33! zz)H*f&z6~ith8XGiUG`S0hz!mD=Uyqi86B{c4+$ENOs8<$nJ0Ke^cKG8* z#eZ>OOiW;H3*3RfCfL9C45SCrGO;j#6967ST2^LorwD-bth6lu^b|K%$!E5~c zH86(8s=){ryjWTP#>>daMhjqLWB{j#iBaQ!j-CHY7yD05^S^X4FbxLYB@-*1fS#?W zk(r69BLO%LS~eyy;`R4f{(IEZFoJnw1^_tZzeF|IhX(v}sQ<&~(y%Zx(}KGW1h)dG zl#T80C^9gB2b>L@J{B-81_Te%-x2-4aj}1C#Q%+p{pU&gzu97}OyCg){0-}$vIKwE z`=4{||0qiE&pGt}ZHqC2llkAa7$cC86?}4oPkSRhEBLRj8Rs1?o+t|sP@dMQ8-TbC zM`TfF|GFz2Cexr(WL4PwRhAW~Ord&hR)PiN*L9IH&o2zQInJ z42jg5E<=9D9H7B1Gf(|V#R;2DZ@xwEcU%^kxqNa+Cu5o8^DxgIx|f8b7Np$j)64** zP%;88MudgVNA;*dL092rbc}51lPEkDhRSz=Ny3(9R5{D?*}C3OLtgiQimhY{Y9q~_ z2AKP%-q4%SmQ5hI*38xP-8tencw8xx7a0n=tZ7^Eu_8gWA-jpj0@vTiGjiD~RoG|? zhc0bo0rTBl-R$WU&y=TcD}hB_G6LvEx2j(UU)P56RvF=Wc2urR@3Hg?%TKlmSsd=I{CVTvB1gO6F2AQ3gQl0XhKZ>xr z{KN`@PoNH#w{Xsy75X0e+sl;s;mN1(uJ0!eFFNl=Hf+KNpN_^46pS%HE zlXidXwxuL1qJJTs~j_R1+34Rz+oD~DGuBCMcr@> zUTslMr!{VM1QLU;FjSq@X?~Lc-A34D6nFXprL1p^QfTc%7rJcen-iAxR3SHK5Sazl z<(bW^NJDT*vS-Gs#gtqi=f@4FOPhGBBjYRb2^5c#>>d!~aF)2jqXHl?nymRTgDl*7 zK5dI{ER=SF^!g5(=7SVz+apy;rpGa?nkaFir#&OhG{kZ zo>q%9^s8|u$IpjFJ<8aojT8$_DQ#bjY&FpAeyt*9iJFVwYNgGI&sWF6m zUS4~sxGbT2-c6z797v;6P`mtF>=)qd%Ig41hOXbZ=)Xzp>G=m}b^TzH84%$ResyMeqE6 zc}y9ln(HH;u1J%#DhKqGYOq5(eGvXI{H1T?yoR^vUH@E*Gj7%m(tuuc`x=LQ;5h+& z!(9Mqp>Xh8?c~EoRQ<&-?GCB)v)^V}R=Dsp86m}1CE-n&FYfTKH8hd66Mgl?3LT<_ ze2hsH`|5`1;n&GO>H8fF8Q7o=Ok=G`m_B-14tn%QUVR-#d{~P!%TN`Hz|EgIV;VI` zE+JkM*An7LBVboxnZe?=W!k;V4YRBu#e6qX{HV1nGnlP6zg#_Fr#89ZC zxYk43~>XeI6FG($gs4rqV*{ zyMX@l8846dT6?^*4+97@>4E}nMzSmAQ;UBmMF%2$?AFtnmXRHTZRG zfwIa%ADuxqU}XFWtK9z+UOlp88{yuvC0OUqzEv3c4+^FeQK zy8Y!3?nt-r)1PzNbEY8Xx%rP5?my~_F-Iyi(wym6%5CKhDgvv@m}uCCbEY(g(9N1w zp$oIq6en-1m0xmi9U+ChD$Etb@9RqDN>b&T->HC>UmC5Po>2oaU*O$9)$=7IN?H|` zg6Ek^>E+KYWJ*qDWfGC>N(%+?Zx(PR7_eI)5d!WKR(V{`QJ?Ox=A5yg?FrQw3}s}B zaMe*+Dpj}vBf~?$ETew<{#ybZMpsoB*N=#eu7#W^ zIw52g5MYI?=Xcci7*UEog2X;E$`J>ie#)a*`X z?rjvV%(-fO>pu*C@>JGTwJW0)e5$lzb=f$u3;X6fL-nIug-bsp7JZ_n?Bq8uU9o=r zO7%dgL)km?GyB44B3ewZoU(2^sb5JJvp=n{-|A1wq4R?OZ0qEmP!GhP;D5fN{AKYI zG2ex+TW@jtJ)1vCerURI8?!T@4D{J<%oWPqvJi2>qU8P8ax~Tz-L`qE5qJ<@kux4S#qUFpoPL(q!k}A_-8)DS z#O3|M6XW%I0CL={p-S|5p3!ey0%3?;2y(go28Go7zCUc4PCT04je&&yca5FeK6+HV zO5gb=y(iL9yujbm4?3iP6u|FC@%lMF)r$yT+XNuwj~kr*m-i@q@VMiwlon;kN=o zm=`{W>251I%G~h#gIH|#nu$D+S-2s5H)Zx4A!%&Xm)^s!A_g-*wi@lD@4K>oy7~x` z9r>6tJXd!FdnQS zhc=I6SRWL&e`@7j_^ou>ZN#+)Yq24)*j6@}ZM@LijP(GMKgnY_v4bhh^&Z%oHN%vV zM=3l}@@L3FiS`SxmQNs^74RuQCqm&oKXCO?Si?-?YgiQ1E?r#H)nNNK1%o>^g~ecagZyPn=HN=*@|FDYK5rxMtZ@f7ZlA#J ziH9rVSC*atq+BBLg7Cs!>socrADp|SwKAR*2q9C3T&biSV;cKk)X0j*I1Y%f#ndQW zMiCDP-T2?D7$$ND3ThIZDPa{Ri(ZqiUCd=vN~qQk90ywEHO;D?tBR^DRkF$>%j3&? zfkTZecL^5d<+F`*cV!w5LoIt7W`E#ZkRPT2S;i9K;^EQ~;u2yO35zsVuIhH3EMg;TUM&H4v3z6ktx&GNeg6k3h0C%{wwmY)ntH=!*=4wSs(Irfz$V-#|3Ys|zM|yC>*OoG<(SWHocA%2J4b~ZjD^fU+c;r#J|<}&>0FdJAM6t+F43YqRT(COyq&DZb5kux{CcJC=|p3dc@&Qp4z*40wZk`drVJXyW*;M z%b&2k5hsc{9y?#TyOOr1@N*y=VygELuY(`^Jh^-V{uBtkQoaMWMw_op9_t%Yl57#H z_qE?~h_2+h{r}{(KT+SlZ(Z6viM`{3vOv6JPvH9#y~DB(d2VzbG2f{wa}r;vd4_!U zem`BjBEFMX<}JL^y|Z-xqPvz@7qK|P`$lLE6Kor1`mN9Acl{H87a!nzYF@1=QLkW2 z2#Vb0xXD1~{vu1~&&UErED(5R3JCQb8b%@G<#jaDW#92|k zqhtr+W#=s6#?^a~|C=PW1*MQ#=vPWnSy-R2wTiNY+ z)Ozi)Hg2xbK2u)Ap6Q}H4aVT|zcXpB{TN3WW*6F}Wj;H2y~4|;Fc~*e$Bf+%RZnP1 zk+=GtS#mK}LJc$h*J16`wY3|%232uQFldaqNZ~!%>V1qEWRwo7oA6mV1T9(Sd;16U z>eNQuT%1G|L^NWVtI2Z3!OG%M_`;Jt0%Qe|_bK!Eb<<(Eac?m{%tRmwAdQ7?%6ork zTk7T9w%R5h--2n|g2)y-lzHIpbA>!2+@`0;e*{C{Pab^HpN4)y{<7OHI9?l0AOl}t zem0@6c70vwCEBLGgg*SHb}X|^r(0VH+b{j+;{pvq-uG+d@ZQ&(90cS`PJLD*p*I@hNrHBAbSUxuE<6YDDb1p*PSn$4l>Z7mr<}hZJ{YevuO5ZQ298nu* zMneB}X&r$b>z8)8>NFeK7j_dW$!V{ga;a%`+2v0P>|OY`YP`pY9zEVb!Wxw`KbS70 z+dP=6KkX2_-Fe@lVn06uF^CmEhHXqZGVWqG|s5>Hr$i7^| zF2}2yPi$E6;Tq_CqY?XM3~>*|5RW7z#@ii|MiSG9#0Ed@kTX0Vl6%;Qm`0!o^{EXB zQRAVKg|9~DDg?4|5ehlLoS)O2ud;IlqVr1|rt7%-&|Ak4pxND_n-D5nvu69>W=qQ%WZczr7SSb`35rlJorVm(Ck z6HY;zZmlrlCs-U7MIII+$(JlqCB-F+$rfdoDtRRRhHnUWr~~lnrArpUG@qZm}+VDX(i4O&$bhj!$Qea7b< z^BqYM5uz^spukXl%Qg}4i0Rk{V~2&pCO{-j-xwT%cumVhKHN?-4jF@35O$E76N3ER zn=bZ+WH&(5;t&o7KWS8F0gsSbwEtt#JrVe8AQi`2-HpPQCm9Q@?(wDp_-C zhxozg8W&%4?cQRe!jWvjVgi>mH{mYJk8HfX$p_`eS+SP}FrdU?^zZLfdKSB!C3Q4s z=PNHs2=m^*eAIkoA1ec@zZiWEmZCpPeO>pv-k_tV$bSFM8^Q9bx^e}hS$&Uo z*RJSXd@r$*s*ZT)ugDyrY5n-sK1xv9q~>$zEBRZ|pPfHYirVujFlx{!Q`0!cS@RiW zB)d&epoQ&jIOiC@7kNd?o*RX2Xv!L&k6rRLK9s|-pRPzCpJn8_{K6G-wovwQKd#8< z+FdR=m(a{#C`fIs%NgNn17f?+G)M2BaO$Gk0 z;oz-}fo1URY0?b&NUP*S@Vg}~O}B;y{RCcx`O#Nfs|HaeD|JlEO7crTnhH5Gob&H8 z`kojIO$SN(`43f6WC^(K%;~x{a_IIU5>Ayh3QKcj2|g`NX}s{_RpQ8S%%}Wk4wN4L z=WV(MRVowiy_KoDu0b4w5PeMRS7aFWVH^|S$qh`hFBYxoDZ0bN)@Pj_B`erPcF1s^ z1uK$BXIwO+5dJm=d|PH^S^ho+q^Yt%DfKWIsIEDzR9Reibrxi}D>kbZn1#+_)Q=_A z81{mlE>iUUARS$fZVJ2@6Oij%z{xY6{yPy|79TYDt=M1ZNshQQE35N3cN{NkTKn@4 zOpUB=|0i^J_JvY7)V?6*`x?pQatASTMC{GwJ|?b;-1b@#!?re8!A{yv=z`zvNo`5a zbm}K3yI5MX`>}U$VaNj#H}#r$CrmjITVBvDT<16O z3?d+HyQ^zO#?E%GLn5?4TjOr0u2HVcbt!n)t(~8ott?plG*Kxwbn*5!h^`D1nO>9l zE@ge5il@;xn1$pJ$o-k~Jf16|+p*Lw;m`fJRvW;LlH?1{#aHglo{~esmlNb^-ru;E z)^vO0>y9pUX`(L0?LB(l#e-SX<9J?Bj!@y&H5f_9VyElN$XUl?(4oT>6;o*KN%xqS z@*V+sy|{!8Ef+tNDWqQM33*oHqXx9XU06%ZrNz{!=H|Sw5YXXqWK*Rx<8<;IuLQ`) zMF7{b#MgDUn<3hU6IcaxQm&(D6Ex}LNfNg zh2hOwqdt_qsF;q5hJFg*SF2RB$X=+sVGGwttU#StT>&?fh+*t+)RQBO|Q?haIRN^1{s;}`yUcFKje zR8q^~md#+^C8mXh2mjNG_;0K8c_%fo6NJ0OgI*O5&mO{3!Z*?M8J`WwzSyg#Jbg~l z`Vxl8{*yk+Bpy-Pog!OB(%Rt^gb9J#Cc!WP6x&s2xq@@m1s#mr_uwf_#fw7|I-J>{ zt|#kz8hk5HgfH_KyEyJ=C)v{W(MbjH3(OWF7`6?IzI76lVRm}qZsDPhUHM42;rS@ z{_3lbqjJ+<^W6Js%lpmhrZX;{sjX3kDRhH`5b7$x>mZVz+&mThL!!{vGBc*;wPQ5t z!3@b3H3Wxns4iwt8HqP^FY@rmBv>tzb#RG8bY=_Zt#i*4A@b})?9pJ_LjfhoG1H{Y zG@IHxB67Bl`y&i$sVsFhywrsTHOcU!qjd;umqE5X_?yD62!Rrnfb-$rNA%T?+m2amU;83r~4Z5|eG zc6ML%aULI)@`Ln&qJ>JdY%L1c)9Sn2=PG8z2&3xS2Asu^PKEbhPS5S`Gv6BTU7cfj zM!N&8^I@I^mrh_T0KdFgpFFvhU4FMb<#!>vGPghGkBnJ@F3xD2X#y46R0QW4UFB90 z1MdZL-^BIGn|Q6m!6mHr_Vlfe%`oeO9go=!ZJVq7lU@F7bvqP$zs~+LfhPg?5!F@dw1;4ss}}Wkw73o zq+AEE|G-U#?7K^Z;j?FVb;m-N7HObjFVYT=xCNwdU}9%)bQo2QciP@3OY{zPwUOK! z1d)e8m%J? z&EHNf<`$Qw*=;7zQW6*Py>W;^qS6boQ?CY-zkA52mvWB}y;kv!mfUE_wU~W()mrd< zD;{3D0HinTcwVWnzSuLAH6LrCD(|8JgQY)uM%l$xEe#YTiQvcAbcc@Ud5t>&$w<5o zZw#(rV!C`r$Sp0Vn+#9F9F&)fpb!mL&dN(Qtk`O~6m^P;1q-9bVkVk#kopZl#z~Sx z?&6g5^Jhn`uvQ}$@i|i|mDqg6#`d|8fVy-sG~a1!CMYx6Wx3Cn5Z{P4GdLWU*Jbbl z|Jxw2D2#=!_t$u_EppF44#j3`*nB?Eme;fUV7~d*tq`8AB3{{h6xpGk$Y)DRFeC&B z8m!jV8vOY2?BU9+(lKXKr%g(Q?UOkwn@K$JF=I&tb$fF*tXu=XL)mWx9giBrt23$e zcN|j0F%1Din!an7vdyP*Uo#wyK*Q1HDalLY^hCV zy9IuxM%$*{fX#In^(KqSgYS__TAg^!D?q;11s4@7oc%ybg61&<#AM?mm`)Yy#9S}D zGkkkA-sy^#@#s^dU3|SE<=(tGbEOQEk3+1ZihqVVxh38f-9n36)VWDmZ$|j}?^vOt zRn*u5aal6vAzYm+XEEc(3N5|E3q{9RiLgn^q!4Me7oD-rOD7=aEdJ7KyEth!PE3xB zF#N$`sv4dthlt8-N&0OR8kJu3RdjsnH$jQ1c(+^v{eO&?T-@WZcfL8_!e-a(F)>A~r|apV{yMNLG&X!+1Bj-?vR_YQFon6e<|AXu zk7YkGYGvc?sy5`@+J)@WgozpwXq*%BHfOHRJp4T^S$VKH5b3Hsq|6n3;}TdHvUr0t ze_4RMhf}!fpD(WS2=F<3?eW zPo|os(W=PzJfZ%9=i~m1D^mE)v*n`9ij|kq<_zTEdH!;Q%IiRXEYG|La4OrlO;>Lq z0|6(KDPYP470_Et#}%TWrX&qHYRoT9Y$mJ@&Wf{=G?AZxjh&$)vA7?^P%(#{&~=Mw z7wdN5_7+n=hptiVi-6gKE_Z1ANG$dE278Bkg8(Tdo&VPPyNtHU^G|>O zbA??=kzfB>4a7a<01V&snlJUPbYO%TBo)$&u$?6^)iVGYVe$`>B12slwE>*0mzsVz zV>#A3p#r2O5Y&`O<&dul*Jky2-S||N?cu@Wxe4|zjSug<26-eNpJ5;O$GaW?KPoyM z5dV2UYezcCndh;!&g7~jdRbzM$3F22<74UY$+eePN!>a5aQk`FA6eV67Jv&8X1%NS zYu!GK%#yF0svt<|ibWtSXYDQ7A%5LtsPN(_X=jRF(Jm|5^UL+j?oHxL!0!VO?Y@s> ziAaGDqucz{=lKrx{7MsPNH%9~y6&{n>l0|{)8b>})x-(Thv)MF-3hHvcR|=qb4$Vt5oSS!7>I;L1_V_6sM^jZ$OuMztnB^Iwo zak04mHJoI^UX_e_Tr+|9z4bvhJxfYnVVAWWxka z)Z%$}d`J_a=G4$Bs1Od<;Z{<$<_v3XQ$arR=C|U25Z-Q^h@e6DPx&v4=zd>q=27fj z*^03*M0ZDF8K%2pQHViN%6F1SX-amCl(A5EC8bs28e$f~>~0Ydo*Vr|VSRZ>A%ox$QdKh9_ztpOdx)DOLA;0OW>M{f@^VYGm}xH^WSu zf#mlJlpg|-pfE%15WNE8JAdW>D6qvd1Mm`qF$*mkLW>$O6)|nyl!PyhnBVI)V?2vgb~iPMZ`X=qGL99!>c&T0N}5P(F~Ny!*=m@HtDW5qpY;Y^ z%Ns$)!(mw$4|ZUt=+*cra_bU%vH->Bb$q^`p_MC612?bg?St5O=yt8m{Yv9| ztMcNLb0gSIT41?BHD=%$?UtW2NnopNrn@*pAdsIyNZI}6#y*>133@ogh zrJnLR9o<{yScs+gJRRF1e{=W0G+Vwb)-(Z7U7C9=XXzRJ$UR@%36?ZC3yM*k6NP6G zvgNy>`4lR{;J2C87_3Z4kxt-a7tWtIm^a#C4k_%{aIV>(8M4QuQyJVJ)Uo&3bKKjw zt6B4DWoEyq!=_*9wa+CSl$W3lJ4Hk{0hp@0$g#zLDP55Y7m><-1GPX%Ix}5^ufXv+v z)R}eP%JaPQu9ZB>uAd=k1lzFe3if!$Q|gaG?*R7{#{`U$jT*o5xA*XSYNt`>+~8qX z_JXegBDqL6x+X0LaA@SW8*i1CCVD`is&0LlG7ld)Ciu^Ua(e-3ZCkjsOuhkIW43cF zP8+WCQAy)v=&p&E(RYe7w>t#4L~?UTcnU~3GQXcd%%$R$oy-cAF953-0kV@pQae%Q zwv^&bHYvoumQYwKS{m3H|OIxVB))1O4d7Lzy+`Z(D1r12aT!pIZbSNUH zgo}-5Q>8V!(WR_J9im~EQF7rGC1cSK%pE+eIexgo5)|IoKIStQRtq0j?&0${}5_ z0+z0nDO!rGy&i1jBxpX6oX~C7yaf4JJs0NCINUa~F^7#FqyX_EiPi^i-u1r1UsCIx zu79>_ye-7~i@5-Dk$kmoO=Tr)-LjH5UcoC^qYUKYzY!MSy^Q`O5tc853DilJt>cbP z(x%r!sz&>t(dDq6s|;wMWZv~w;y>I|UxYpT9s@LV7dqS*M&!Vq@xKfiDyEGmelFd- z>G()3ai`RqG|g57sGT;JePQbo?b-CPNT}A(|=34DstGwHIL zvdPIK3TU9!m?^W#iqGC=wk*XOS^x$|=1O$Ga@vMbw$s-gcZWN3VohXsVQFUyMJjJ| zpY5_na&jQLI|8mzPT1j^CQ$6WCCe9$Le)L`c9@!r{eFdD#Kb2x@vu-(K~7Fa{93T? zPgofk3y;eqT36UK7$H9vw6qRO5#v?y_3smdi5X%7K=1bDTy4KO8!Yo!j^ z!C}?mbZQyT=V4!MZG-fzdByo84#UI#2Kvn~HjLMPy;tgNTCcQWORreqYxE@i`evzW zo8O|ex*u7gD>S_7Dl;HR80Qz*w*jgr$h;kzMvPbQ5A3`h!hEO^h=;0Q?3$}~MEqE^ zDvScO4UHGz>>v88niw}v@m=4eiPEok=Hlf5T(&mmToRAaY&^feqH>r`c`jR>vq~Oa zJsR_v#B`sH?|)wmc(~`yWG6C5GIXGH8j9k&bY7Bnx6i)xFn{Jc%tUX|Q<-s;cVWd; z<*-(h%Y|DVMShIc=7}#bt`|w_G5siOcN#4;Td|knTe2F-S^_W}p?Rg86?pT!G!woO z)4tjqb)-0)xs5hn$7>OlWiR6$((AT!a5v^w8<&nTwo*R*RV=CktlJk{!FM9cjq77S z6xffz+nzh@`@b)~GRBg)o~*YB4R`zG2Qi-L6S#-xO)Ww-6rL#%Jz1(`%qC!4LMW(Y zETb8Aozok;9uXz(_4J5R1!&c=vx?_V$$wG9Uo_s#nzid(p#DT>88yJ8rezIuucS{ z0dwa!a?!SmK*HXz>9moUXvo?%Qa-e|4SarM=s?kpdktbPw=d(%&6`#++b_H_>&s z-^X|Yj6@gv-O0gtot`DfE2y|yrwyq*=Tpvwf_FvSg@$TfUxNrN+H-x*x?3Dr%- ztuL|IkYj};y{?UPdOR;NZWA{Pez^Xat`QUJ9L0PLy0^2I(K{X$y+p=KuttUaUUZBW z*k;4muH1tbbJ4~8u}aKNd)b@Augxz~uGSat_ovJv3eBq&2`b=%se|u(MX9A4uNr|c zJMOY;t@lx8G@9Xq=hI=VL+xDm^IR&oo?HEOEiO~Gu4)Cx?bs`ix}8x(9UdVUE`2lCRLT`n zd4_$x4_((nq0qeN2iV!0&H1ub_5&Xrpxb7?@6!Zn{747BoG+N(k-|_21vmtxGeqV5 zD^PlV=d%2CfZRLESus+NrecXH0%#G1(kK|{hHtnVFcF#6wp=wT;`rwB{_f^_-{PH} zi!=Hd=_Ql1uzjozDyMb{86;h8O14Kbc?M}Tkt2U)B=f)mu<(Jk>VtYYMt{Z|Qs{sY$&Ji`(D5Im+zoK66NtjJW2s(?0Aq|u?TdQ$Voii# z%&3>gR;erWEzj@vc!8!C^UHOa+1~7u+6D&zS&e=fv%UD<;+pzAR&@f!vbrOA!jHme zogNffHX{va$|s_RPwPe~PS+?n1VD0K6!^*lV^JyNX?ON(p79_<$26VCt-dV0T^1kly@5inus;``{e!GruYBpF5jyeMsANx^WdAHo`(p;=l9 zeMMYaiD~4W!V24)V6?)KHE0~d65H7dt8$>R1ZDvK(t8edR{q#dTiD*2l}9s-#uTZI zUrJMgplTTk+*^gQqGr&wh-MknkJU25KH6>>a7B21U?03AU1ASpbQiPI zjs&}(U1CoF-0`p_$)xG(GFm!^RCvsrPHO9nkBKIub+pIQS?`_6fA{iN$;voB(&i{@ z^A@$1N?g|?nxLBCj!Q;P#8(W}`Z>H7Ce+_nAIW5x9P5@WO?*FLR=XOE{!$C5_|utJ z>aH#Ds;;&weqJXdZHSAK65V0o>@ivxkq~%GyP=`2%TQ+hE<+MBxKD7k*aR3dAmsIR?PSm~{-TIO+BSee5Cvyx9H3VdXye)mB@f^ z37v$0dNz?~?~v3}B4C&ULc&6BtluK|l$YQLUgGf)bvX4q*H%Y!!sR6V!`)0yVGi!( zu|*c(h}|8!D$L=}q6$8gPIIsKcZA?piA67qCIJt6lP2a1rK4aee4x(-E6hb#ELVtt>f zBlA+Q*~OAyMskg5!Ny0yRCc(tI|N^#COv8zg4v#L5)F`3mK~da63^GH1 z6K-SYY%(`3&3ss{ZpkXl-$Vatulb&b$JY420m}Egf1HeOFvR>1Q}w?=n}DN*fi=y4 zDH$2%|DR3UH*5O;Xxi9V{)>b$vVDsurf2o9|-FIME-VW|FM&aRg0CC^;;W#lc(=2zfsmVuKEWz`mY1B{l@|Sog*`c z*1sa^d>4&{nc&}Ys`JRmXov`bYS`s`!tl zrl;5Wp9JimC-1*6CxQPaVBhxaA8wHOe-JPhTK0eFyZ#rn+dXfyT5-Zu2 zxHkf}qnk3kG#qtTWdJz6%_=uNIPdz+r{`_+ZG-P>ALjhR#dX`NrhR(!2k4K7S`3WF z$~1QGF|}#~cp!2L2tCz_%Dd*T)n_n%K*bNk>sh5C>8P>}6Gs1O|7YA`=`^PH`-${x z5a+(P3rHg|Sp3(y5wEV5eTLwyx-5vz78Z3o-vY@Aj{89s2_vPK`1*q!?l-0k854)L0>R*02QmkNGykw==rS zfZjAdr19L|P9*8v!8gZ&Wy21Hy&3|%BsJu}-Lb^JkoQ_fe4@c!?AM1E9+g}?jd53m zWh=+}!PV?T&eCKAQT?9YxHj&*9FVvpqj6y4kqFbhw;iRACH>+T`{1%ng^+gJne#~3 z=)~Qy$8{S1@;rO~ae}$Qw+nE?CyDv%_8(k*=c4S8!!H@w%fa`t6Q|b*Is2`}{zkOs zP;5s}Z0hgm>|^!eKj*;_fgx~DDbmO{BHo@+9}s#%fpC~d=EX~TTZbb1#M5d5W|Y{c zyY_&r!=9t*aXq2ngT5#8YF1}eTl?`fiN94*Id;%MintIiGdS zMN$2Q_I4WP5=#6+?^h2sFA&?v8TbaUJGhRmt2spE#qlH#$w%zA0p$$?lYgZKro4Rq zOA(9=QA3y|nz0!)1AD6r!2+QkW^Qkdey31BRx`pR9%h`(7stl_b>F4v!P*&$lsv4Q zPDs@3X2=Imz)i~od5@68?~ZfsJ$@K+Pn~Nfw5?stKFwT6=@%Oo*APWDcyDf zByEu-a8MPRG>&`hlQZ|Daj-GXL;&wtW6BPeq9l^jFG-9RIr=oZDb(J#fAK*m4P*Cl z5SAiUNj7rGnFdDjvufS(q6tdi3IZ7VBU@`h^N^f!GVEEtUyodl<(7TKmP@U2}KdCRM1L4-F5}b^b zkL}4XJ|IB+3uu(+yVq^MJjAjST`J@&_#9I2dYs{>Z}1>QSqAf+zbSWFB6uKCzD;5) zHE3QohQIbMC<=r^Dfo{BdcQn(G}GF}8Qm8k(fC1gXx?9*98flY!R+trPQ>id!MFH| zl`?K-Ww@W!bS=fPUmj~HmR}Kb6z9V)XkOqg@a}%?HV2%WE%N5Ys0th|&lHM&dc%t9 zuXP3R*&WT#jFP^;5~kiZb7Y7qVx4`lbj{`% z=Vw_fKHgAZ;KX0PAuJIq>uWGh-Q$dXaaWJqSHc(a$`f|M7->*P#ewa+^9i;k{bXpp z%EhudyUfQYerj|HqB(T#yTix6C|yBfF6Z?^1}g&`$&AQfl21ji%bhZmrs5EYt?BML zmX7TxlOHrIV8CJrdkJmta^jhQ$8V+4!31(GGWvVFayUz3AOcd>g`0I31&Bl5gpOA| z4tTbno@Rt^dEC`4;fb-|_Fd=?J-k2XoNl81tx)jQY(Ce(d?ucC8>k<;yup^gxV>p` zhBzH=qF*@mpy%?U+lv*OE}LhFwoNe zR5E?Ez0t=hcN(?9f({VbuasXzT@CT@tyr%7prtDWYbu^R8P-~0Fh+evw=(kX_SkP@ zX2vVwxM5w>vW43^s2=Lr@#h&Jye};yJn;|39@*l=3QK1B_CE(a8*hKtDy#uH6}A|} z+;B}G_VfX4^89rKIgk+OpnR}r*T3oQ`?mZskzbfkdMzKZ8?+C#jp{I!^6}q~q|;h| zolt=XdXzlc(~{MoPDbUXd8+s?Ua=Pnm>Xb00nqla0Ib>zorBpn_nvf$LXbUdbF@y8 zX9&0nCZ|lQ4WMK}hDOsW`B?Rt5_k0Gc)lG%)6lpZPVQd|y*(rN=43WER22b07eBPs z?zcln)oZAH;O|1f<^7I{VN?5C`smdMo_blHfT|6c&pfTkwm|rP|BefA_6z@zX2uy& zyWybOoOu-KWRrF5 z*qS$W%QqpH4StQje#_Y>WRK2&0wbu%4*O)4!1)PoUo3HUNO5%vXNz7KQhLuTxcNPe zQzYs>DTJZ5Qf$1yhe4%U;Aw2yGTtp31jaFFQyLrcyr#4aL;(Z-d9ZF@XSE>An54Sg zWPhiFx^CEOjZp-H8ac>(;*VuIqO?AFyJ2VCKJQ>J#0Ug}EZsM1?p%32X>>!pC$|q@ z>wD}iGs14jUHD)rh)hIP!^{TtoR}HpYlf+I-jw^N?e~nY<@qn`>CY01Wi9WVv}O^G z_oo`xQ@rs>Gw|TYz2}Wk{dSng9n|W`HeO+!cc`;|F8b^Mif4h`VNNFOqrsp(h=EWc zy;sgH!r~%=kz)cJ?R#=hLJi@iIImGvMWLxU1ezkUQ>zCiQ4Ax^BQt0X7OlbN`WDcj z88Hk>7~~~r>=3cwOTns}sGHw6+3v#L3h%m|NIkzk;cHg052K$+-4nZLI%&Ezwp_Qo z?ZoWVu8psWuHmj}uM>G^&F(q8A-j$Bpto(h*L|MfT*+oYDSET?Wx^%HWp92l%ZW>! zq|kF4B;^87d*~n&%o7MDBUcb6I%Il@~rrXeH)IujM*3 zpQ_JEN!b1B%6^cT3psc{;CDPexI2hAm>u2kL8Y4?ud1H4+OpzUzN>NRTsqZUw(=2N z79#X@1kzH5vL=*ER639={7WSs5R1vIxMN%Rm&dw;A2e}Bu2n~!${GO=r5VyIgmc$u zSF29cThv>u6Q_sWH*$HW$s=2rPLTkWVrDH9J^wFz;a}Inzd4!Y^ncj~TAJg5(F*;! z2zdnq?t&&u4Hy^ZTA-o4gELOhpT^AD;s{BMNFaO zjPfPAkseDgrKgx>heb|P20U)L;OOODv2#@0@?LZynu=Jcigacf_NFgyn~+afVjhNh1K2QzW<=o z$5HNcPlG_#N3sqWrAICP%bW(slm}(nNBx3k+OM4!gyse`5!PReiq|N+ZcUS29L~Z1o=SX4rMj6Jumcv_)UW59S%RivOWQa0DP3tF>L{nm?56{fSdt2 zL_HjJsuz7g^x^>1F-jN_Ttg&>WIBHT0MsL=lRs%ub;#lI!^AQE>YtW@3s$ z4vCQa8GBSaL z7*9O%{3J$7`FKg?VyyBa&IEzSlUb~?-x+0sGz*e83$mIsI``YWSD#6c3ZB4q=?UuqGO+M89Sp7GL!0HWI!;@R@7BThw5&vfip))>qf1iGRKO)htEVz>NBlUvt~{jIIVKC z=F;#-cZbuMy47;6>Xfdh))rY~YE7xe)r@#Fx>6~u*NFP`fIS%`>B-dZ65s@)k1oqY zgYS^EBIkseJcxP5>lX9PNBqa~;=qmoO5+`F! ztQ5j-$e9S_WX#q6#m5jYK^-yrzy{#@2>O($VL)HQ=5b=ejWiWS>o?TEi8RAIG675J z^QH!>QXrBtEUWxEZcL*=wUkj*=bX|@O&w{{z)Br<_{S!dz;P>@Vi5Wxa^Qa6Q6R}U zTD61?L&kK_uxYgbM>dsHNs>}2FbiL-we;o`Bo{|EW+t_^dvVSbBKRhD7Kr|Lpi^KLk z_;(_yTso(X=VDZPgXwfSm)&PzNF>^}!?BJVokqL$Ys6V{h3a;L>1Dgu^0wPoXf(XF z=S_YXzK8RDO4WMvwY&9k^=9m~Mn-C}nd_un6)qJi=`@UU^NN`z%u=$F4`eT$IWMg%Y342Cr{VSMm1u+3j93qx zRiY`v0SdsUA)kL7?PMH1qT?>EmuP~v-@=TBZb&f?S#&2T+uLNLTePc=y4p;CSjBuw zP4c&z=GBoZbiT&r#$VAqcv;E1JbImv?D&#|*Ib>^JuYc0-|AA*{;FUT?Yw=h4QZKS zX|8AqP4a@aiZG3-qNTo$__&-uZ-42CnlmZv=gr1b;4x&8{Yvr~SdA}*a6xNc7ZWfV z&{!0H>p)v-{m^+uu~b*wy@_Y>c}qrdjlO-AWSX-QPlfsl$GUN=W+*9B$&2Kaj$SAd zRSmmUy*vCXdENbhyjXFDf}xOOigAk1;cYGfi>*60TwA!?s$-SqG~HplVR*bmOER93 zGE{pes8*D^t*Sx41M+eF@+2k(9uqtz;GEwAXh!O(DJB@wkXqBgL+VoE0t?_EK`TvRVMv~-Diyx10(?K3;Lj>nb~qh?E&>UT9CX%RJ7Ub8|FTT@0(lT#sMq*U;_vkVCUmc7L5Q->CiF> zn`_@H^!tY;-Kxbm{ucXkrcfoD4*NC6$mMkfE%waq>r$IdTJPL7O7GmX1y2RCkgLBu zJ%zfH?vujg{OZ93J3CyK1$%vyjjmhPUN+9sR`(9=xK`G~uIq~ww(uvlD{EqB#Pd?w zj-&7^>!y$G;$3h`H9yZ-l)5sAi?;7)7tb9Y0gaxM%HM%av7XtLx{CnwIobsL+cyy3 z9=5ds)&ESDcLo-}+AH=5WHUUcdG$iAnrDdfjx|y3ahuoUX~i%UM>; zy}{|#gui-T@HhjlY$9oj;YFnPQuPGvA53|fdXc)5dMy5d5nwmBqQD6j%-{ zc6zBI);1WliF1cyXt2D%DG28QoP(NE3Daa@we=8Jl5Cby5+a66%fqdGf3u|J z11=>mM)3f{Y#F__(PVbe)N$Cvb=U-b*pz+Hba~jsaks{Lx0Z6ZChcL9(a9>Ii%qu9 zq8j~&!2$*=TeKjaIWW|c->3#U8@llJWSf?PJ08>*Rara#eN0X`PCLn*{J|d!`&_~c z?nK&iDXY{!hq#kP4gBRi9PUv5!HtwjOZqcMlYahs6j4Wg|C z#mVaAjuW^gc>$4aS`(@NaszQgecysfvk z1)GoOQ??VRTU(*(lXKjy>yNGK!xpRWNdv1*g{FZ>SiJTmtu&o}p{T7jn11}Yo=G4+ zIpxz>d4y#;ydPKnnP5hmXxIU7xh8Ba-rRnaIfW_TcqE7uw`yDmRGA}0BU?<49W zD@9d#&^gy)oD0U8`Uh2BDU7kGp#56ZZFtx)rqAmFe5QbKA)l=1*)22>SS=$#j*&zt zI#`1dxMp+fSQEoZ`A5B0mCavkqeAimB~dcn;EnM}=?#)dls2^H=Rq8j4q_1~Q!V=_ z()-Hti~xLlR8?1-cQ&58bVP}YJTsXy{~VT|=KfEkj)a~RI#LWZCPF#7dg|z$h*Q=9 z>95?0bwd%+9-20VM2h?Jxz2OLLXHklMHcf8l^J|TNcgRTiU|DG4ZBnU*)4N!Ve&1(7ihXB1@$POdIX)VOb2U9i? zrB3R^=|ZXg>y)+d%P8OW%46rY`u5~u-UKGRTSSRR~w->y&8S&x72E}J1ym4sJG;&ql3;v>&!{8;MkO8=C3u;_NeM2 zxw)VR4Bzd1{F&HO3joW|grEL}<**&FlRh4{%b-oB93;0 zhMSc8yBp%2;GOVn&}-mv4`gq7Zy8BEVnN`HDmwWp^{i0NnDjYOY#jPfaWo7rr0Ry(18yoIdqOssz~_{c9$@+;e zH12S52<}4|tf{9QSy4xH$f4x~Y0gPc@|ke-!FM?7Gkt{Tb}S57(}kD9pw7p4)GSJB zQ!kO7f>&nFdzlUx?qpBMKiCdJbt*f6xH{9#6b|AlLA7YzRi zCmr!OR=kDh#~$IvYReDi(;sWIKiXf-9cJPgAAZu)ioWdh1f9xbOo-Wm9X`{myMEzX zXZP#dd4c??g$Iv0%t8QLp8m43CkrEN$09hQId&XkZmB| z$2tk~gF-x2863D-qK5|t^ZAD{5f3BXk48)I8BOrGrthWhkUs|YYBtsdLsb;>4go-z-%W|0=iLSvCc zcwR&W5P4D0g^?!CmiAv@q>i70X5W$U>|}cc8~@Nd6Vc8O+`dsM8&1}|W4x85p6WEA znL{I|qp{lEgRE1(zq`qOrOQ>NkCNcv60P!+nReBYrh=37-%yqzDT%^|*d^xH|t zqBW$eT3h)BpSIp#E>T{pnT3svO$r#RXhl3$3~f{6{o)L>*NUkG{4E}d@zbpSaq4n;z{DnMj2B6QEQ5BJ{>VnK{lL9`N$E16_97i5VQiWnPD$N4zVsG=gA*{J=+*WS&(pRV^#X`D}2 zT$d1hIswm^y*fKLS0+$tWd2I15W%@IZYQouumid^Qq4X9U8`wgY%;;DI9rm>CBo@| z^I)WC53-h@NE%WYwthMxbxgV$A$8n*)b&2HhxWmSrdU@RBt5)R{_1Jg_yebCY#2&g zqg&xg@)@HC<2qS5Y}vXI&7X^+m>)Zv+bplWQ5T&f{`JJ$TU!g0Z#1mTq}kd^EMsvE z(InNO>=QJ@%8j#L^Y}=8-I(kR`ImNgqwU?Dmm2!@=bz^pT<8|wr^R_pTvIi)X+8Rq zKkI>=zONbwkp;%LAzWPVulsa-Kj|v*06z0^G7G06{$+Li4U2|oS zoScw2auFSG*I|3dA;-fvI7sRk-6b*T?^AF&yts-EJ~00xnt?z>+CTBGIJUO5xmlYq zGcAT}!8|Z()Whm_GBc5hk_{f!;W*{6AS`oqC&@0vHbuwK#!|#qg<~V~#ZDP5HfB`C zdPtWW$;P7Z8B#}#6t0*{AaIM;=sbAZCx?0K-{?M4i8&;rIWp#fy9HMNMZMIkYZ(H{J+chq>47grvc}*|l=<+f>jMeNqnms}9!SJ#^=o+_uv)Q})A?TUn*DUNS_NQpTtn->ov8Evl1d&jTq}VTXAWAs5-mHv6;|Kx8y<>=EOvEGi z2LVYz5rS_}E0OwrHxv=bHYolAhW$626#W;^-l#J&I+=fFr|XL5&Tm;eb?=YlNE32l zHuu$xRFB(EMZYaWmm`)qf8^ejbADR5ME)roVeHcH3(Hs*>4xl=Tv=UBTIa){*KztB z&un#=YgH-6XPl8AAXg6O#d|7iFQ8XWHv2u9+LgQYVBj6HA|$$RNTQ%zZ9CrmCRvV6 zjVC#^srlk?=Q!7igH{L+^B3MvTnq{AydZOe4w#OpFxVQ5Y7F7tnSOqzL*Q50Tibr2 zp^~U+jBR>Lh(&(^#xYI>DHcuzyQE%ydaS?dVuC>6$TO@EX@qCaV!i(L2Ku5PepCWf z#SnoCw0Ri?2Ql@ z)4fMyyjF(aPW1ek6;nP(6~_XFtk6-T=AK+Ub(|<+LAZ25EZ@SZXF#jcRX4c?x)u2~ zTpLshFSXGm<0qZLndE%l1dDoJnLI1%r8MpLUjAdx8z*|RceALR=5dXdj&emurZ25dT8 z8!MBLXci|@kBBU6BVC6G*~ospWMB#5S*AhbCUzX%%thMxGvs;5GvxTWYk}6nWxZuXD113DAh{Xt@KKVLRVf3dSyMOj)uCz z<3Ii&YFUqtX__i7%4!7j6p?p~i328OTx+=#jRJ>MDtKNW*V5yY;oF`>49P zKQIA`dp4I@+e2?{m~F)@oBfJHe!yk+`NAhxw>nG|Err z8-G&;GSG`@>}v0(X2X?2>%jdwrCE(bfv3=QU0m(IwQXD`1$1&2+{YIJpCXDmdwK`V zW~+*&USVUfUZA&a=$7%-L|Aq86jIc%$b*au5S^>S%4c3^FA{Ma8p~q-Ud^2O z&Fy_YgxA5l+5D}zdLE{>-5h&EkE1$d_Prk08Ju>4`a5{(Z9i64?dm>%{yfh8GWsI@ z^L5#P5C2Jjn%*^5=>Y9l@n!qDZ?uKo;Y{V{bK;h?gdU$8MNdBSN7An)XDCmPT>z&_ zk9><*601rhp_f_s*PqpJynHocXnlG#_u5m2JH#|`vbhW{Q?;?y`9PSw>WZjqwky|) z6cZEPh2FUH@yAi5f+%LUM_OWS6Tp_+fRJ{SOcY# zKzp{UB}Fi)8zR5qyDkR8xd=NoZnL{z6MLS`9CQ(4!q|tdN;IuZI2zQO$q5Xz z{bTljhS=@S+h>0J3ssEUZmwNDj~Qkx+d8AAWqM@Hn!5aQ@^c2NAl|fGH%22UF~faA zJNe^;PLp2yu91>e*S?)l zmbtY>|2bN@5%WRXiQ|3$j;z%~c-kVj&0c0L8Y}WRV<35a1_>>?{mQxgcX8x2S-i*H z9B3W5m{l=eIMoy(mDDPa%hHm1;>@W96H3frC?92#mI(MV!14OxiS44X=Qgrq|T2qi#Q`oGWefML2 z#(>6pFyfG6O~GzEwEV)RUgYmv7e-#iN#TlT^&uC0El;&!!U`{H+!o9Av1NFjD=zEx z%~+nB_vLf3$4)!#*{qmX71Szmz46YvpzF^ntBzhK*{|;FfE_wDIv@1+(KM<V@--mWOcTSJR9=;^0jpYslxj}w17phB>p6b5=Uxg3&b_`7vn<`Xb zuwp?x{)vxGg>}_nl@B5qV2VJCMOvlK8z2w0GEZs5$|YZnHv=ZsKm(0RW)2;mblW_Y zbfQxGi~2jX+Fp(PiwHi1+JhTQvpJ6tOEOYeXdGo;YEO!eMyaMgp(m;%z&F99|0N6& zU&@wrbW)?2jgQYw>SLZS4*1R`M{d4dn;T$;xQdA*%@s#ca;@`%BDpv_!?rhU3EI}? z8Wg(HN>9XBW>=LSH;+Qwgf^u^o3jYDDrUc`!@R1Shf=p1k(YK6L*8P@a-4p(nAq90 zQGi;B>3KAT&`1yen~z(cZJLQgQETj%5~-tWWto(=EBcf+y8N#6Wk~#7vS=B#P=nWC zpw+LXaCnp>`h^Nv$amdZ@@5=8D*=^KU5)xuZ<5ZhzL}kr`Ch#sGCzQS<5$c}R@gpV zHRNZ#)8*<1ympbGG`)K^N_>hjs=@aAYq!Zgaq1S7@5iBBjlGpO<3sd;5SIJyBr!s4 zMdMDN-EG{9vUEW!-N_zdB=4VYPQpJe!z-6{mjw|hh~k3G_x#!s%lp4C+Q_z2%(|8j zWPtEx2!$Pu)6}&?3!92G%Tg#y3pv5EAZN>HTz)BuIj>Hn2DVLsY>W_ZEaWdd8O|z|`G0u3%h*PqeO=U( zNiyMN!pzLf%#04>gc&Arm?zB4%*@OaW@ct)=H%wT?z(sFv$drooe$@O<+kN+ca=+S zseWD0D>tqRNYax99Y0fCj<0#LGxCqmp#f)!x4>M@4HW)a{Q|>4(9@cDd=yy7c@b| zs*q!_??$GeaN3~2yoQL4c@IlW)8xeDBxxE|>_e@DYuQK@C9mHCfRbiVFM41*b-L?V ziyKyAz%nq30-kl^$n}-TO^3j?6h87R)qn-VE<)_i_Y+nGyFPw`7y|^$rRu0%cXkBC zm9cb)tCnR7r=G(nvCGS{ZhSVCFs=(zGe6;+5)81cX_B?%!tMJ)(x4TIfa)X^`Fx^R+NAvUeo?QHb z^M&MijSUpqUHBlv7jnsMxIaxmBGtb@?C35Vlp6I3!fV zyhO7)&RQ6>ep8l|zqseSM(o5D)6cwk62VgA@zD95N-Zp+nlzG1#$S1hh*I$k8evpA z<~)sb#3zc9?*R;tdqwlYohrN`NJ;BwkD51oZ*Nxyb;0rxg0gG%*KvhEdJm`xHGq2u z7F_R1LPgtW?6d(`Io9#b*}=>p4ZX0+!b{92#hDrIk$N20YzN z*iHbmS`v|Lzg=sh#dmga{OhkxIg;b2#iS4PU8eYcStXt{G}bHCIff=^o|>szYgt=R z)7f+3l+F(~&mG;UdzF#o8@U^54a|%!IU7v&*Di6j*0NoyD6frF83Sf3=kz3n=atzS zLT(!OjHwP$S-m2T2q&k z(M3>2IcT80OqnsC4K4{9G40|K!8X1)y0p_$ZCWGb1Wg-6MK7pdR_8lykj%0>M-|Fk z&Cz@s_f5x;YTrt5PzYeI2+S@@BO12%pA|U~7N#Q(l8jYNJj@xm`B_=t9C}M?RAw>y z6FVydiZ&J(lsgB z53kFvi2n%TL#zIL<^E8#GgeIqorJcs4;=e@MMEfB9$`N=FG(qr1zHL&X-<6KDV)d%G*$5fglvg4T;Jao5$vhQdB7C1CoV2BgJ_(!(1{WOz%Jby ze$Kez;*7h6*s;^f;@#Dzf6_2j^&9#u^v&&UQc8~r6d)+7TnCzbwEk2uM@y71I%T+Tq5aO#^!M`cSk%!ts9UsIar zii%R&?Sy1}e7cs^mJL6OkWf)C?TAFvuNgIq)It>NX*LjzSro7??JaT-!0pCi9;kK6 zH7_)iFIu;)+Vct`oEX6gobv-cqT{3mdg+BNAXP|=J`CMHR& zR~u>Js44IP35+AEa+Re?&xlwnf?X#VNK7tQ!(e0pCiWnnM>lG?y2hgm@>Sgm=k`S@ zG%gkd=;GYjT6(Zt+V@YKahr}#%lB1{yhijIr{YRe`PG)%#e18f-#PSu5`-MDAdK#h zd_d-5BG9^NJswe<&nKwS3F^?fmdYdOM~Hdw%G+<{E(#FfJ*oE~adR;1eGft31C63d zbYeGbC8TV{-F{L6;)*c$uy>JbX94#@CQ`LADU3poMfr?rii=!aq_ng;rXqQkKoYm~ zzU9q>ki(yVy1bu zvIAu&eu)M5t(t*+6bKF{Re`(0uot5f4s>jyG6K4OG^M5v`uBmQv>_1OrF4KO-4-WH zo+QBWBBzY|^#cA;6VL^Msajk)><{Pc!ZUo+`~J}Atn}KsA#Tt( zZY)HE*WJWKLNCN6O;?-VWKm*5CB`q-o~=+iwJjH#=Siu2lEx>o=mO7n1Sd(ncN|PJ@_KEv7i=Sep>4 zNGx2^@q5I;KQX_0B{emyh~jwIq~5{K{L3J}(@gKi7->NtY2(%Do;INMAq9_z(*~a- zyHl!$N9?OEemmM?aba*IA>UeP1gl)iMu6S*=2S>8F74e>lx^p%ge`g>cU0s>Zm_aQ z${}q47)aV^YM3uU99YzTyuqo_8{}oUj`rBkl#+_UtX*USX6&Gi4Vo3ljnc|51b1(J zD)aBVL;A~XIzEjyQ(!JH6k14$9f?{To~p<5E-}~)#OY45U#LB~GTwjPKc)p4%Vj=b zaYk3aWs;J(EzG=r=|i9m+raz=&}Yscs^CD^@)__3Ms-!js^XAb^3GlCtK{!bb6gAoEG0JZ&>G0zl>ZT!-VcPmEM;cirPov@C#_W2A!A1$X9Is1UY%+Kw5{kPx!L)%5ZEdl>G6n4AoAQ;DQFb@d`TBN>SKVyg@DX5~*_}J>1h8f!CwI&e&CVZ=&Q=L&_Wfp1&jpjF9 zbc0-9jgWpEh!AK>adKaZe0rkqm;`+yMOq7AhDeeLYCE3anaG4d(D{Zy_Wg`jtO9D|!q?M4NLV5J4RhFAu z4=)a77C;3YX6lWaKZ8hLVOPy5HMeU~Xi2x-vC9z88Ro(N-A06v3o|!p0cWw9TGUP! zCgs&x?w|2lvi9Ee>`*sns1sh)f)?|YtuadteR%_SzC^Zo;l_J$f4J;d z#wLfmOnITGmKJJWRvC4$HcQ4K(Tv?f4pJ+zhA06q4Jd21TS>i@2U%RGIIAe$8kvQc z!Aodwj!2GQsD+cQB@;yz=oA+q=UhLYJ6@w4KuKCXU*w#o;*uot`6E0x?fzY3KqgAZ zseq#ZB}$Rpb!Ut&Y2lo%ducYLZ-xtd(cr=*nlBo_Vq3MsqPSxU|xc{>M(GzkYAH0EiB(Umi~ zLAVH;+;jL@|9sUBXW*zzP31=WeH^)$_SMB)Uk3hjQAdr@bqwLANWc7rrY7_6^{0v3 z!NWu?E~k2q9|ySfx(?TInz5b72_1_~ada)G=-Cq7+3QV2IQjhNVpJjt@QKd`Z|j(HwU&CFm~S&;~t zsn)N=Mo71n2zKDJ7R;8iqY`s!>~FKT{(!bM<$$ zG+904Tj^hMt{=-ApR-xutKhAKGbjBC?#n%@dsc-PrVa^MN9_=;_`d z4pI><&8(=tblJ}|Ana=*qz-C$k#CkT}5k^W7kQa)cLwq9xxQDIYF~RtOyws`A#`ngv_j1 z7hm5jP%$x@^yKUfu|lkD_Q@E^&^_d{2ddOE4@A`0Hh@Cn1tlW9U03|%yE#`55rAZ; z^m{^oN(|LYta&r{2wWf?TlS=SxEl}i4NeloM90Z|8q)<#Nfp8#yHe3Kwp9+ES_s^s zs=*#k*|voE0>L)RbE-$BU19Ek;=3qp9D`h}2I4T+6^;rW_$u-#HGcZB@AMJyM!dSz zi{+jd-NS#D3F4VWZh!XIuU{<^FTr8`&LV|`c#MEG8a`S)bm3eX%v<(Mm+!)qYVthf ztdLcxk-e(|=)K&3vvdv9nb3Negoxa@l59 zzLz0lPbcaX1nmVeI;R`Q{7K=A^Qp;Y%zssNb(Rj=H$*#Pzx3;%=x|DVWd|{R=nNlvtG{Z8&wbqQM zGnf2B);%W{XG}FCaqO|<87{?UnJHy%K~+R@P35Zc2J6$;KlsY4+m>YN5;C~Us#W2Y zwr+EX>10s19LE#8YRFKGr7Csbcl(VDSNOqa+Gash`V4vr1-oC}*yHa}2w+Eg>dqAf z;rriOGtfp*5R|KD0dVB`I!L8x_{hhM2ywk6~+0{R-!SkcN z9l)LfflZN?2$^>l#W>+GmVRKgK1)VkiuJM~XXL>fxbkd+pj_nJYP zABh9ElzJ9%8rTifb&klHQp#Vo!aqMaDo;HG(PY0-pjijm-@*$6NG}UCjtE+bKotbn1k^q$VWBlgmhE$6_EGN0}BpbSw5>_h$|(?&Fn&NtDK?Jh)Cf z>>@BQE)Wl4;GB%>LK+#F2-i-YgKNYT4asC?M)QI8Q`c{97S%ASV`H;Iy2h0 zI85r5hd#*=BiO#(_aQuj(_5#14m|l;k~gKXECvEcJc(^_` zqc2#yP}F&B(4q=2*jzkbt-e7WBXmpUU{_9l=X+v~Ryd+WvtdVw#Ii+O6>Ydif$kVv z&+8+}3E-rqQX66qgZ946#i!#-1Z2;#rj7lsAi&;s&f0S##a@ZEF$!l|AT{^sv&f;D zkfcoveo;mNXfLV7rsKtJ#C|8MV8_Z05}iHbI)Nd%nT4q6|6?<4uTpn&C~jAVhNRTY z6#%x5jhoh7L2{Ou_`bex?jn6;(02)i&!NuH)Bbzorx&Q$y%OWr*L3FeUn*tKZxck3 z=6-ruqP0%0BMXn-Tl11yPAK?Q=^c|hnG3hu$jXdx$n^&1x9SzJb=BAhE zCsB15b(+8v=|EiF#?IH)#~!7jK!S{MJ5mPu(L{?y%LQ}r;Uk8Nxpb6Hm%FEyg0zJ5N8mTRiy0cFWVzTee5%lT7E2!r!}^8r)jhQNX)R2;xjOQF!su%m8NH zbSTUC^#YIT!-^*g*)kuC>7j2x_pW}E_=A!mxvtsonoAoz>5oP@N9Uex2hk`#T%}=w zA~d$=xjdZpa=#cZOuCec=qgIHbspG>s`soU0=nGo?JBhg)cs4Dl2bLGP62n zwmt9Jz#!l(n^9ybt+hJZ11Gl5KtH~-t(N1yHzz~=YCcD8-iTxT?<`Po01Ey0)nN_JwI6mC=XVAHF#_3={Gl#*{{4P$5AyH~k7quCYrS!PTDVqg@ zJv(a_H$Q%mf;Hv@F+!M^`iXz%tr$;URLF<^?2pG zH#mzl@d_&z;$mTr#x}sBLaY}T3Ret`G+U7cr35ixBET)tEv0(c2rh>tpI^$YMEp}b z|78BLo5(xx?|fvTq)XX}v$8b=3s)I)T7E(xep#`+lEh{QtMFLlnOFXf%R3rj%ZJ@F zIpDG&Z0_Dl?2;XQ5jkR)-20sDU}@6O+~M&nNwcxQs>Z8iTW%F;apx#v1>tDreOr zpvOKNAYdJjRz<{b!YMuyj2qXHgKOb9yfINdGL|^Ih}cs8D7Z2br=)-s%=%zRlX+2c z@7ZS|{KqVAom;}onTbVJ8GxSRUTyTxMOmer^JR~s4t=v5rJA>pW(hr{Kc$l*DR#|) z#+<48+f&1~{(QutDtiZIbmD+s%06(2(RdqgMRl*9V!| zfJXrP;etzh4U%%rG>w zMf3|-hU&~w@?xN>5+mZ9=}dyzu%a8i2x21wR6+V=dvb_{hUc&R*gpUvI9hDEh91*k zi%6pOK4MuTN@<%t5ou#`BeKe%d+XIbvV7B~)uyhhQ6V}0uNmn+P*m{lX?K(++adLw zFM}?Py-sk^ZC+-#tAbG`8D{%av0ytXKIH}5fa^nxoJy{n-~$Zq^L7O6S_BOJ8>=E1 zdN-+V)D}{oln!w-EWPADqBiKTy)4+GP{Z{uWF@k$g7`r*o>;P&h#hD+TL(&a#0&^0 zWA3Soi`#*~E(8%b2S2SNYJZP&bOuY( z_rF&FTl5)sa{oGXj-e*l;`H{LBQ5HpF!kUzq>T^FU=!ln(2rGZ#5FM5bjCODQbdf2 z@jV=jZt!3yC$-;-<5@V}u3iD5(&--)sE9b`7uwl7wW(dKe{SDiRkZUC`0=}4KLk-1 z#U9whgC74+9!a~cWc4$wISF{T=P?bZjGNdRZN8rfEfexY&EIM!08}TkaWLR zFO}2rZPT<@ASYg{)PAR>UPf&tU)q;8cR-Dw%bMX8EL{HVc70c+x=^@<5VgzP1oW@B z<1fxZM!q+TmAHg!dW(V`-uJrWE*h;hlkK|Ac{PgLZA^-x$}7LRlKr{$%2d5pX8r7i zoVe8kT*EeGNh78|-l7h&${tmj3wg`NIhv=Ik51)x=16)9$9XccoQ+yDKoI*WGGGM? zgBR+$;B2#Dl>KGwitM1iXJaT=U9`S9`-uW0RB2T!%bi2_Iizp9p z!`~0c^LW%X`BD|Us<>f*4l1S|pkn~4#VS>UN9+oW{PWjcm=49^<;I~a>{*HdTxG{6 zX6^oq_$7tg&yxz`x241^87c)U-l&Q4N|&Z3o>39ud{j!#wJT~aXMt}}7Mm)Fp~_o2 z$xPlAY5|^+N+n7m=FOL(5)-fqGagkocEd)FdW9t@8QG18%=>GMj5DSB{?HBYV?)IW zF$p)d46L>a`Ya239RUuuQw>Z)>%%b#%BABkY4m<1m< zXqT5___KED*D=fRQBz$)`{uU(m)K@(O1SRfsn|CBFw#`S?q6933f`kpP08VljOuL6 zLg#h}>_)E5t!nxgSEVfF!R1{_>kUvA8I+~z0WH5{SD4yk3)gg(hct9)vT&DELQbqW zYy%&y-9%!^Stbl~-JJd0%RX{#3qOrLQDYdzih0KrD0y$lHgLcJj9tF9=}pvFY8;yT z)>R{*bt)@zYR{EY>k*6*Z4-xhiOzJ=#}P9uygkP3cZ$ux+*aaV{mK{rmTWQ1T{)VTBaXKISi;}a}RLLHbm6rp>Z~WRB8qSW^$jTPCdM2<@8`-Wc2UcNf^!dNK+9z04xO$Z4-wHF+9)QIB zyM=GM6fo=~52dw?w7Jw|rOa5HL+GDHPDJfVhD0k4$|B?&Q`XzM5V>&ILV67y=&|$H zZrcqAk?-COPORK9*n%#qcFPG5;Pxkg+L&KIAhDNt!LN~X;HrHImE_9s+DzAaoZQ=1 zIqKx&42kxU_EGlD?IYryht%e+qk=%#Vsc|5irPL-%TAb(3`Wds^JH9{(sO8}u;C{J z*#k|dhEAw%0k2PUTEz?$>{|rMjZOEA@xwRyH18=QJHH zP3oMnGbiS@ddb$j^I7CgIAFiN<#SW|$$d%~X@aro94gmf7gui3Jboo&kFzX{cwSp@ zgNe%A=hJYFm3Ff1gjMrwSK^ju_Kn3W-gsiZgm-90Ds#}PD%O;?oVU&ClgbMsY2IR3 zqra{Sw+4m3*E;_gQ?t+60h_Bzx2u(CEZ!NK(I{%!;LCJCtWke>u_;R`<=>Y$-GDN6 z2ds#RTe~;wjG;z}hn7>TdxcTgkyLHJZQ8NDuIHbx!$^UyOqp6latu#$dH>Pz1ftih z20aCpmJ;!y7414|p4k|hvh!WS zb^aCA)`QpG@eHJk&Ai3|2yQ}V1@a4LLL^f2ZBIN-aSFFG-tw$%K+QxCTJP^PAp)_e}zFPIr7%{$tToHRn|UN$2Pa8rr?$&D`e2kO*~ zN@@SDeC;QM>ZmqJb}Uv}K#i1C4qEY<(!)O~}|Z zBGr6Y5!?9}jgf>^8<;^c`4W@8$1#&@l_OnP zeelD8^i1A@f@--|c{C;Goox1s0pJ=CjKMhD6bi*Ls8aI?KvG+n0B~a%4YU`KNOUmfA3Mp)W~5h%Psh z%w7U(fWCPzT3MB!Ws-&J;Y=ui-XWv?1O5zbBV+p`(&cv{vL%H|7Q~J~-(=eMv(?z9 z7m^{2GRn+`0u5dnlnW;)4{G#~8R+qSf(v!WlXCcEUq6t`C{E=E-6>>Fmkl?QQwibQf0A!a)FvxZ4i<`YJtZ0&gxqMMJ~b zVL{kf5HWqMe{HTW<)@Rrj!t2?bT+txVIL?h76(L2x<&!yqVP5E5)+idSD+s$$9pUz z%HP1hCEq|rUF)c>1;$Y{G?qkt7?}G>V3Q*eLd0lgED)v{X0!R+;XMyD^Ayl@D7Z{| zDw`8rY03YV0sm@cxl>e1SNgb~f_sDx3)V<%Qzaag$f@$82OA78k?N)trrN_MtJ|1k z*IRKmu2ElLB%BJx2`lsfBWl>`1Tv?`!wNx6P9!UJ#M}s|{oB5s>GLb8jEhnPVB{E! z;zZ3J_i&yBTw3m{!?l{_T4C~5Puq|=rIg&FsCUelLXF$@d*%w0p}t7Ank8pMF@&uG zchEV>294_7+`81+S`34ANTC1V9qS=?-_QFlq0m1#Kk}iwufC>fwP|U|XX$oz?<_n# zT+m&(>z##k(Cc-&J)b<+jlG`So6WI|SDPVcCFklPOW|lNE6^zXVStXM8wW#mi?lJB zdSNe?sF15iQH!)HqtD7>FrJ z^5V1~GHl%KR--##yP62<-b6S9%lvpr+i2asZn?OudT)LhT%ot@s(9~wI0fy>hN^;i z@5m$H+$riZtUEq#*~E6E?3!%kjJkAg_{1E{AT>YDD#x$%Zt$w^?CNxgDt9NkH7dK^ zGYQ!}|H~8e7OS*T)4Z32&HEIV^};W{jLTjOXlGmV70PB6ieqVX$3j7=4!QH?H4Hk$9rJio|#2aUj2ULthm_6osOrC zab12#&21#loX%I}ch`%y%T6Z&MK$lZWfv<+Pqs1kCmY7;IOB-#99{nd2j5-9OiJ&w zu%>$(D?*fwCC`Go1b)S|M2@h<`$aG!?wv_{t)V%s)Q#q1m)GIh`%%HkFpy0?IeuNP0fH`I41)g8w(37 z^M4RZ4n`(A)_(((EdRxyWMpCcw@yhw`>)S@S)yOaCL1f;7emR&{3TNUv-#icNw$AA z;h*#Vmp%Fab>x3VCmH@tPO^M?m|wglGsk}#Ct~biXm4%@w6*8s`{&pCr$PUKt^XYL ze>;@fm>Agqe{k}PF6ChOuOs_h6AGw3@A|RX!5m8y5pI=EK;u`*N>-NF%DZN(Fh&sBM`2>(`+RvaiXB~u$L0OkQ2{ED+>uFDMg`hvWF3i z1ReN;2-_-x=l#OdRxGdI%G`d%foJ!#mP2eF51q>!xo1eW5>T!?_C>> zx0k;BARP4Hgg&|s1<~QYPe1_&o4T&<8u)!G_eBES{q(csfJf*evpHQ?8#bQqeZ1`C z0rv)1VbL4b>H56OaPNXo1VoC&_PdRTk;te`K1H$lmlum%o8@`uS=`q9h*ZPG&&!XX zyO(?KfkE3*k(VxlhJOA{(iE^PG{y>2yjjoQP39^ zqvet{M$pZEpX&=VYc0b#^^2dR)$GMDLR(a_*iHhVeqvsj&bq!qt!3q)4Obc2GpM zUyFq{&JFoCP6dA$MZm&zR64Q53VceW1*x1 zdyVr4pGFAIa^4U4Q;ZKxOWchDT#1j&hOFcfldTrhr)sCu>%ou>`X)kG)-#uHLB3tS zZTQundv}Cm>PQ{lcR5z+9cfhC@u`y=5*ZVj{4qeaBB?dmlIM%kIhMyUWJxD^3r1VX z@qU(7X8g2w_^-e>(@q}o| zux&kqhpTSQ$(tX{Zlr0*UHzR994+sMQ>t$> zom^|-9L^uZ~wT_l{S-?JV=gXYUGgGr3Jj%DqasEx=_>PSo5JAYk%Z-Cv2R za<@yqirx@px#q@(YzLf`^*)-*lfWz$2s<<&_kyp$47M$=_6na(U1_c4?0Ft@0(iNZ z{47409B#XBRe7h&BT^Xq!!QALnT>?5gGYJwnQ`URTk-`{n2o9ago-1EzTSWbdoLgjgU7hmlcj_A6;A};8iK$SV3Dos@ zBW{O$`x*=eg8=Sp4=jWNCrP~3$vr^vva_A|Cj8-5Z^&;NYI$pecQ!;LDOWz!Zg|ZS^E)$#s;+}|N<@`&-ordk z+``HqC27vf2D!0dl&;=yUHIXgFhgw`Jn($>lzdG&`eD?*u;=L)dK))1KD4a zHpsWo!X3(XvgQeOc=4Bf1KBFN!Bcm~X?D-nZcY=L~taEFV0``_%NLyv^Ey!z%Y~kgVxOqwL zWHz_M0hMk;}e=}&Yqfp+}1PI)~r4=!s9R!#F&W-v7Nq}(de;z@NZK3Jo?>EvG1>p z6(jS0`-qevwV6j zL0OgR$kst<{?kzc+>B+;+JRU8bBWYuvI|lZU7lB}f<~a029i`eT(bFHX={3hHT~N{ zaRZIr3B~IUR#D(Cfhhv3$s#LU@gaAyF~;NIw@IVL8xlJewxLumUgiwj`G;2B*=n`S zX!pa^cD%j?dHUjZZZxRKU4dap?{w{P?Ye<5xOI(GH)p(%lRMAvqn zw&XyMZLT^fGSBLMAKdETb;i<&&D2VlG68nuW7l)mP8!SC%E#$ha!d!c(hpCYCzM62 z)~a#^Z;E?88v0PM?$1pba`HoL!7*B9;lb=~;zt%)*iE!(J4|^e{o;3g0H%+s#FBZZ za(0~*Za2{~SaT5sG4bEC43JD7MZL|7f9mmNO##rq=2V^D_<(WQle4;RzDg@CnstSi zs|^_|cn`!6Ox#0R$@Q+W+uL|iMMKPsb$xX`fK&6U@<*%tdRLFk>ciVy1(XnTgH{f$ zF_gM~B1KXQQSCK)Ji0Vahm$d8(|4AD&710)q)tito*t75T(ru-0DLYqHrX3@mZ(+c zW#)P2&AKrM-=dAWfx7K` zm$R%WPxq^}Zc)DkKU6;$h-+y>yRXt;_e^)zw=}oA&0sI)dv=)f`nQ8IwcX}}_LrTq z9JLMC{Y14yoYwQLjH6(ubE~6tkY??#rG$S)@Xs2}&zKyoo2pXryVgn3l8eLNV0FhP zjWRsA=(m}lG~TRqN5JWKnOl;wdQGpFJ>auO53ip+K|mROx3ChPE82WOc0$&!)h_Y>cCF*JFK`@yI+>{s>_zSC$IKBz^e=v zt1Xuu&tT5noIqcRR{L#?K+njWnA-x@M>_kQ>gelu&*+z}&zzhf+TzyxJ9|1uItL~X zsh`2$gq+yls!VNbd(UVe*j{ZP+#lfGliq#dYKhM%+@m@sBWrf8f=QPdxVx3on+Grt z*ZS9af(~zZ_(B$MJaqr^wnxh!6kQYX1*{L^8E+b(wPkrGy|dbGofgNnQV5Xg$f+qr zyV>Qk)Suy#bz(pYjTn`?CrmIY+x-@ zQ_%x%gHumdY1X_kAJUeUtE=-lKa@MPGfRgR$x?DvR1DolD_NR#LJ8rx<>5tnq zY1ehY!NKg;sX+)%64h&c&wrWbNi-Vx=EmYlVnsZzAzfbI0q+Vmy;zilXDThVMt>jRkrm4`G)41pL^=*C7JX%$Y*4wRM zyg^T#?R@*54gR;hWn+lX`XV4zXlbpr)HD1Bxi7aJkA za(i3rjE283#+K}+ux5$wsxfM?ID{ORo~Ku4p%)7FCaAcCAtOJT&3oLi$e(^7AnIwP z-0c^>&(HZnlz9Wn-f4>S_7qDiwWmyKoLcM&I&Mm6?F;xjVi9d06Ni=N8@NB+zW1wo z2dS$^o|SpmT_K$I?9{Dtdw{quMu6B_S7bCLs+P5)NiEbXjdb$~h@i#Y`J(D7{=Uxm=N5)l_N7 zpfkt3H>#qaEay~zq5g5xZkYx_61Av7#5iS!m|BHp*ywShl%^TwY4Iz2gZczw1>)|# ztoGh z>@-S>zL}|)(M%Oi)z55X*3K}8CdI4TEK(I&CYV|z@M;>@kPQcRl`9i7yzXaxuMVj2 zx(laVq0=8>06S>8Zc2`Szqs=L zmi+c<)1K8Omu_$F=IEOyZ?9M>Mn|J_cP2V%kuZt&{<7?VPMe~{W~{m#U+X2;`yMX0 zb!c7NtoJ_dYZlnZdJB=Zl@vyfZTeS@gQF-#`FyLA29F(8Dah~8X!`aDfZ}u| zS^u+(!I~%QBHt5USD--C&(FPB_0;~VCw;ad2*-nocEnTZV}6JgO8#T530FIB*fk9| z9mLkzPOia~5W?B`y4l=qBM&|^PINNw*_Ge%>wvVE#eRpDsBx({?LKs4o5x#tD+!G9xXsL`=G>E(!vI{bxvj;MEHCcBGX!eA5% zZDYm>-9o#@;(_BYt^wQ&%r~O1wl9rQf z7D5JFK%E{8F&<3__arJ16s_;?zZsmOLkKBN9g<8~ogGFSF#;4Nz>88=QGIxLPz7=` zraA?qcG@}b2hp&L_I^3Cc$Q+JvRQ~_@m_N)Kk~+X?Wz!LY?qd1)Hl`ZN(+AP{-~+Z zEw?N$S)I}*SJi26skHH24@8T}+C&lvS8^}9U^Z%J!i_QGFc8`07HI~^sDDE(4j~$? z=5h+g-S&^a4{#5s_%26q?qsklR?kf~e?$byFU$m^qu6`I7X5wtM~%;hADGinxDXTH z2=208huhrGKqzCyZ8cQ*i=P?Oc8@NTMvT2Wfd=OReZlRU;r)3g;zaPscI-Gz`SLS@ z`w5c_2FU%IF>(rGF;+y=c@W5M;tFUiCVk{+Ye>*oHOW%pp+B!n=aO?=FsKX=drh5k z4+o4zfui>c+JVHzj$NDaaRo(#rP{IQPD+U3zv;}J(wHPL6ln-!f`@|Skom@R*yQg5 z^VIrwEHqX0sI0d)qJv4e{*VPi1rnMs7HVx0{=_)JS|+UHjvbgzG|t507XLFZ%-xp& zMNC#PR4MQ$kB~gy%*{J`tww+Y@y@X9h%sU##w~m#Xis<X%uxJ~NoFO+s3!2dAsOf}#D!&FyIp6|EI}1CFnV%q0_3LI@a~ zOvVwTAzAD9mb#;!MU`a z^7J`BKR830Lpp1)N2(Xa68P{$&5^`@!tCb`N+kb%*%P8c39Am(mu5vgemf8CevR< z__&*ZiWvOmr3Zg84T0B@ApT&{Fy{R38&vxxO^-8Y^}SJSRIbZu2nZJ?ye3>Vh3K3L zL_Zi>E_8W$EHhdnp zT3?_OQJafHW~%L~{U?K_A4Z;GSuL6a4{|*$n;HSpJF%H<-#Wy{cqo?7M06;VPXj9z z0*LW%x&|ZQ+#jO6J70MdW4r{v*01ZL!Uv>9U_6Mdm-gU`O)1Us$ZUj^A%(Pa(GADN zFC{hY<67SPvKL6RtCDi@>ein#KbT?^FiRBDufsFo)k90TAj!G4>=HD4M!1h#CTmK{ z$|XwB%;bML_ElAf5*BlW%YZ3a3TQ+p!lH&LxEYp`3q|e&X`uGQ>_~w7vWBX2sHI^$ z)f%D+PYP74-JgS!>?ISAz0z4H`zA$U#*IcI2`L_Pk)aHwC%A#M zS#jrZ#a1vxWe{_}t-@^2(P{OFmt}*PnK^*Bc?4G^h`oEve?Zv^e=v7V>(9ufy6Rx~+*IYI#A5OZ=a~y4 zz|Aw;iR*PO=rL3QMQ8i?B>()R`s*L7M*fHAnz>5m_QXbpn8j6h3QTE6-+fU z1g|I)H4_y#g2QjIalktf_c8Q5Inm~o`wcU$-9)JO&?QD{v&joU*5^taHUfGKqr5`$nEc&4~f&dqIElqEqvArbI)CBYg5ZT|2xVI{7&I~>f)&3_rBS8 zLGGNfm;RGwg$z94!9e3w#yq>qmQ0rGF*0i+=VpGU+hAEuVx9BJ9VLOgl-ld+Q%XoN ztZ`_5KIn69L@@sA^ z3E-s@feH@~a4elz8&`qt}4 zFLYD6bD(xXe8L$pd_EL=!@a%_;NA{a7CHy)=aEe+v`DEDmQJLpADkh}Az)iPK9w`4 z4J7mK$|p(pE<1+HB)nTlo!c-D0;RPb!zzKHV`)M!8RN>QCWZWiheFOb`lV*);ZYNk z9F{>dDi9ODP1YNyf^47UGt>A#nj)>u%e{0uB&|R3qcgir|L4llKhbFau1W|C5-`#+ z{J(_^Q5T>%0H_Z%rZ?38=iUFcl)>?zoy5$ofX4R!lwN?wBF2WcM#ldxUl1^{aAm_)_+*4nZNi^?>p1vn)3uiIev2^Pi)k4FjlJ7X z{mrI+a~%8gbH8`_8NbVPJgCYACw-=|Mw>mI^4z#R%VVSm8APm4{FCF=b%AW-57!@! zle?ArM8UM#v*Ho;Q-AZ5OQ{-$Efwz1T)3t|)p8Mlw^}GGbMX@7+{jsOD(S9n-Jd`| zKHr0)bZbnD1bfACBvPn>e1Qt9YiF@>jMbv<=V50jli%Y~q~kUkrqt95jDz{H7T|gg z9=87f4}0$%BCVyKLL`t>5WBuTS51`o8|-#EW|) z?jM=)<%-M|ncs*t*O)8EnA2mHbx05iMp~)cco(Zf|7$YIHT!TQD#I$-XS27P-qo6BX_7aVCk9l4A z1^WuuhL`rSAS&|hXa~11Vh()(_Wjk=dSg6d&Ye$xTbxu{A9Obzqhj^rKbhn*{s>ka7G+SEZKW`8n#qtuJ-N^9M!{n!3N)Xt{$bnID@0Y@2E2_BZE95m0dJY9g&omdj2=k{OFYO=mnBpzTqUO$|Od}-X#%u^qAc8Ok>M)&OuQy6?k=)gdBR64NM+M zXE_g53`U=#Xk;7IEuTc!`g-aCzmSQcQWJt>a3?CUJJ zZOVzoa%npyFHr3cd@4_AQ1;Mo#l2l@UxBnDe*=7DNut{|807VNz>?&tkYwNRTPK}} zbxkkab3uq*#ZD(t#)%qR)jJua2Nh@t>ts+tV)|N$24|g|(&hAHrK-6UoBUpFHb^3iSlE8eX!Ewi-Gs01$%-ofDJpNnmIW&KG4!kaA7D#q99`R^HSr5 zud)Fm9_)dE#+yhAIF0gv$jYzd4^XOBJ%~^k8E_$d&sN&}d^>ZEaO;c|V~m*&nePgb zqH%&_tr0Tm1_=)$>L`YhxrEK)@#HNu5~Z-mFCJ2K74%V&VOq=vFl^mNPkJ=IfWtK= ze!ZLG+qm9_uZtp)EXa6XTCizi@(3|SNl0yQDJ@LgY`*Jj4mCp=bz#N7loA6$6Bf4eRK?B)w zjBuys+ZBu>I6TzqwOUy2WEH%Z#8K@Gd3J(>!Y| zKrq!8^s||}zHu!EbhnDdoEBxa<3l-cnr&oz?SMXq^y4O!$ zDx+u3zl0s%=67}1tk@sh&D|wMq@o~LPV9ud%{Cy z2$KLXT0DX^Hw+`Ot4QN*xj^9x$&N%rdKq`)CS>OjYS<}p$FyKR%4GLU;R~H6x{8cY z97*%XdFcSKneTDoiQMzl79#Bhhar^=P=XYYhY@m_4e}2oHQAq7Q8~j+p<8x-*c)o~ zl1KgE?BRQxZmOxd@&xKTlRVuWFUKi9%9ZP8*Ys4 z4u;XsRlR-mYnWWP)DhEASSO_>j+g~W#-P!8P!`ir1EIjipzfD5YI=facgCO;rfigs zl#@`zQ)52oqYJdsa1--a+)Re`F9EEllQ+i5)`$_7Cddy$*e*P`DL8-=7oW?)N?AD$ zR2n)Cg0)gSwS^8Gt94cXR(|25_TU!q_I^0H`TWTEwqgwqx;=eM^e%U9Ebe|^@oaH3 zeYL;6zg(8Qg&eAwsyRH2|9%_Z%JKOckBRyE@LbCLI=P(u{hN03g=PKYV>09|gf-?V z2QPhme9~!2@oESgI7*hTli?DPG) znY$-YA3$}MBf>V%gOqwlM&ov4ZCHjkUwm5!zuT+_-uNSDd%9jCU(0-zsFdn82LKpg zLy=nQpVQKRXgkf%Z{w;#M??3m;Q4-H|F*2NeK&`tVWXp?V`Bf7?)(!1s^{P+Wn*Y& zY-VKmQ;>s!j-Kti(JVa!13eQH6Ez(x866!N`QK?OJu@Axl%Au#nXAS(&;6eG-yZ*P ztwk$qW@KO_W^HW4#YM{}$SM~`WmwKX3l@{Y*8aUL!)oW5DyQnype;Alf8k__hiiMEdNJ7!=PkTNq3|z)^xp(#f7i(Uzag!I>XZG}FM1B*qTZ)1&+&)^5t(n) zhXph?HKK$-p}xB#JGGKM;XxFD8rYmriD*_wuByZLLie$)&5Z5LPpx^JVBpHEl2J#vNx7A1(HO4T75P?k4lXcyl?Et1=Ua`@_a++ zv_XRO&msJ)!}mXhko{YJ_pbzyiRE7o;9pA8f7zP+w*~%R0mvjV{@0r9xKf#r}j zL4Is$N!6S_^6DBi-YW@9MSL14EdAk>s@+UF>5;kX7CxYYsYr6vof%$4(S1MFa6L zWn^Lh$EcJj-)rsv3*|j2g(MGF#rFZT zxjVJf!3?>Ga4^-=Zi$+#iDHHBkxr}TAe<8@RD80z*qvO>(sS>Cou6V7nYmdx@w$MeC20i&XO=vC zhlkjErh`aEghPl7TuPV<-gBYiJiAkSS4dBW9X!?I8U}Mx{=Bcz3e26cjr_w0?tBCe za|dBcf_)ulHHz?>=d^t|dQi-v7P%oKZST!uQr2mOx?%WN!=L|G5BXo8v(JQy-fZ@YQu| zo&F1yVd8RPs#;~Vi$ifLn#&Eovs!Pz%89gRMkfHwJ2=9LDrsGn`@6n}(~@hlpdB|X zv15{jhcZeg89qH{q~2~s)yeerKzxfXfvU?+M2#1&o!7%BIEO7UdL>nxAB(cP*}KI& zpp0yDrR2n#ox1R3zzw_GHjF*;Li1HBh}w z9ChG&3Zr;T=pQ&an5my@1Y;!m?}4U25V-MY4wP-~R6b@S`O`;6gmRV7e~KO)q*p2k zno0K(gD#=0%WJSV2`$Ehoc`ith{rZhi$tMEJz&tMu$NV2Oku)dPMv?RxMx9~r2iUn z+jzn~v4F7SekQf0y%Vkscx$-n%u%}g0A+kBjr`{^^&j(+zZ)$CzR9|ok-fB$i>!i_ z;{VTn3zqM6<(t?1or?U|ehUJ276KN!@AQV9m4!v?KW*`Uo8#|Pz`?-C+L3^b@te`n zvwwRm{=;|iop;eNFnk*({=;{{_&p&5I|DoGzk4sfJs97viNDc%Y6f~5rf+8iD>DH# z3oAPf3)}Y<3nMEH%lEAG1m6i69Su7>3*BES-1ld`1CtTMU&#~8UnEohZ)1ORU;IyZ z_n(z0v-@pf&!Y5QDNPid3Nx z6#h^uvWONaouNU7PhKX@$YT$$msg!nTLvcG^G6eDH9jV!*aQH%eri3vvE_K3!Mxpv z@v{InU9de_<)?OHGAfO*XIGZsu_)0Q494mY9yyUfvYi0Br}USvn43x!L+>!LU$DOC zQx(Nhsr3&dSMz`!WOklgkO?;J=IT$k06o9hd)U4PZVal|nHQ+HQDX>DWCp+%s2fpy zG3xL#*^Gvw@cY`aDpi1ghDc>|Si`W}*%JR6H3ZnJCpWOpEKbesf_sy&?RZ+HR~V{T zLhk^d!2qVC&3KHtnU}WWE(C-y=)M)weG=aK+UcsjVc?Hhpq*v2OSgaX><`{7JA zd}jaarIXGNb|6#gnOm-pg)KUkAZK1Z9$2SGA1SEHkT%n|rq%?u0}fmdeYQX3nwdVf z(>2CGkBdtX#umcSmVF}dKo*uVR(WX~(;^p4LU|-8tQIg2tGS1$6=ez0pO6lYC*SD$ z2l-%{pJm8kY=Fsnvbw8v8~FdbC80HpSVo+%;xy!;hHF@wn&UcmOo=u zPzZuBKe1pQ#wTP>0u@p)Lq~?0t-oi?6FdCko;uASXGYjj9kZ0+O#jDd&dn!$0t-@~ zTk`JMFyWz*Ei5h^rminz=;%+J{x(Nfc$jiTk1}9exE}VEx}?NiW(hG?C`0ZQ@%9AZ z&`w0xN$SwFnB1Ub(zR{4%n!W|Z8&+_08JSh;=MVX-eY_0sZrtSfj2{2k6X%i=$baw zzynpA{)%ZNJ+!HHxVBJMFl0oF1y?*^mT96whyV%12pC&bqKN@coUrFrL7ZBU$A0S3 znozuP%wMBc7d`T>cyZ7B${%#1?1_D6{Xv4>tcU+YC81(RXdgDX!1=paGI>zh8pk%){)R;^ z&dvL+TP@g28yNemADrhDKfnN4p4?PABSsi_|ExZ(Dz%^?^bk1K)jk-Mw>{a~){S2JmCU*ta_I1(wA@9cW zc9=!vYTl+6#X&+D;gKId<%3Th8FLRL}C-y zvJE4YMuSeYP#%RKKoYoF2kM8Ek#!kytfC2KY&>Te3B4?Kd{Ggo|JFOBiI^6qw42A>VSf+Wsz?ue-dr-S&d#;%T_ z(}B_OMdAo=&JcieMWvR4(u&5yU2WeW%J0#f8>y&)jgPqOtK3qKJuw?1vkP^R=yAZ+ zEr!}FK8So*to(!#)}z(Rol|$mISAt>ZOL@lm_6(t+njk zpm9aN8o-qe?xAuuCk&6yHY{KE0PUd!o1~1u|9ah)gZ&DY8NCvvy>Ar64su6cy2cQ{ zps5cz7vz2hv%f?`5*n?Irxc~VWO3Et@&R>At0bz4V8BC-p}G-u#`%o^e6%=?$8F2R zAM)|8v!l6oqjHUE{==AYIqN;ACn$MO6NBs(mt5CEcj=k-D3KL+;6PR|GH*;DrDyIFxh3JRS zKHx2hnIMhi9M&t^hSb*}V)P!0rtj~pjA`oq?ETHXg?C+VCY@p45#BN0UfxNY?UtLI z>n-tSQSB5@GWH)z61eg)jTw%q_gE(=W&w`D_s%CcCrBrZb4NvIg;(Od@pvhpJJ}bX z{S^=C9o98l*pG)E&>b5cMVt0Ev{#Z>jGI30I@e;JU^y#CPeER7T{~Trp73wkcM9Eq zY97u$NV_+#ZbaVYe007rzMcVKApr5~Nny(b_(w46gERAVf1**qBn6X(7zbU#O~O*c zaAUYL-1C=`H!?SJH&Ql|HPYUT9SgQH;lMvZEQJgQ)j;XoMeSp6um;;yZaMOb$xuii z=H!`ln1oL!W|Q+OxD_v@<(ZgINwPbvrGc8@@g!I(H5xabYH+qZn&Ymk&vP_8$)7bY zo~ffZZEn5Fo;6fWH+{<}^P1`&3KnBDz7~?VlxJC5E>Z+7h|(;jNaIkn8sW5Ak>Kk8*Z(_A_2$UTjFB;;rI8;uFjw z-wN%_xb;0(b@bm0J(4|&R4$lZskLiDZ>Bb@aWQZ>O>~Qth4_!*= zwXeG62U?%Hb-yb(521%B2P?bizT*x&4~O1Z<6_|BXWzpj(p$e4--+4B^OkW7AndJ} zh$HOXFmg}d^DypC6f&~rr1>0nF;-RCBkpCXQ>ueEDYt0*VdTtlbUyGP?u~QMbz#$g zlIwRU4m?+)3?=B~6L6(65kSgG?zAldS|gC>XyoQYTJP*Yr*5^*Am8S32_ zC)Q)qL00o`l{P-;REelRwOpEUFTV1f@vziC)Ghu<m&fOF8FpB^FL@B+E@tEL#Yuz=xASCqk+xv?lJj+a zR)oi6zoCRj1K@h4;k=_Dc^ZqSqF?>f+y^5cvzRrHBil*+&l{b`t}x%n)SUk5qZG~Maaze(ogZUy*H)3BI*1fb1UEOUy{wLt^&JzSLck zcbKRA!EET7Uc_fe>L>HYh3+2mdo7(`(C?&`LKX~g7qdwiB9S7rx~!|$+{g2mK{awv znSDz5>UWvAWWJqklRmYTE!92tArU4*v`6^T) zB<}Pwx#$f*PKODCe2IcWe~v+UVM}&c?}Jq0Oh$QUIbE|Wg|Bu&>ytY|+nW#z?nvta zy+dL~JnMZe1!c?_-O(qH)l72X>yu2weDRv`3_hpB{4i!YSEMBeBD3Gdk6+Gz`5Y+S zV$~r~Rt5;`3&>nM-SguNh-nT)Wlv;WgTKD&^rQ?3bPR~RA6s-vITy4vhjc`=e{duH z;w2O8GsIts(cT2#7qACt&ezEiA|k<#?pN6-z9)_8BfBQY85-F~c#n7&l#b7tMf>u{ z+b6eAe-Fl6z~7g-x0{Mpj-){*33kTn*Au75+b#qSd!7OpA z=#B&viTWe#cfjw6jLD7u$-T=1G&^{Ec!wA}nOu|FaF1+_{;GpTyR$Z_b+k*POQlO# zYu1*O@92NTv&*ydIp{UzHRv_oWXo&EJD+nxd%ty$@{yEX+&#O+PJWc{GsAm=xjIJ9 zj#?rtA$mQO&5yr_>5ckD^(FJk{^{n;+#T%WrxT%Ui@P;abCfXyyfR|5%X&wfr?uW^ zBjjVq`Ni-B)g7=k+CA1i)ID{zyS2TwzqPw{=yG>;?eXmL()sT3&g0Gd#q$ODMd;)E z70Nq;&tLHh`9u9@fFEChQG&q)Vyiwq(fcKg}IA(HRd5+(EzvKq?o$3?+UF#j@kBrOR(oMq) zw%qVW|MbC8Ua>~cmaq3R|EKmRk2m5gIQ(5qUPx`CPH^@L@o^6Ij?F>J9p!V&z&OGgL%01ghcy_Li1I^SVs@>pvcbh_KP0>u9mDtbP*t2(dXZsF8iUi6;iY8J4 z%Hw;mf>F!5)pNL#@r#?+cR$^qnQ5q_(L?t3cek8QG(V{*F6HN%G@j<_Z^K=UVzN8S z-Jed@YQB6Wz~HdB43BFiLUdSmZ%@25gM=)AgEgTL~*-tmip!+U*Bkb%d4Suzo!bst3U+>Ow_5vqC4SMi*s>^er(xexyy z{_=SW-@9=Ya#J&VveuGlM?pn%yiCkV$v}=U7O7|G&(rO>x^rKrDe1RvP@f+ z#1YYU>K$=4H|#JVLF_1!O-H^{2JMLQ@Brvbmyw$I(?5&>; zA#<&$MD}pQ7VB&&uX}nxK2lkD>N{DiNaP0Q9;S5AuhlN=%ZHMPO73ZV7?7790BTZn z(vab+?iFHQ1@0`zvhvfm1dY-xHJ?a|5(rjSd9Z)>WM;1uo^#ODwIl{{XEHC?MK~tc zE|yzukR#O|@?idrt-7s+zsByP*8pH}R&YuQtP+i>wJ{P^rnfXBbkp96Ma_!el3lgC z|C+tV^H~2~(%{JzTLrF)r)6n)E*&cqc)BQW^Wn~8uLzw830(7Zuwr(F zc_GS>MSE`iGH^rb^m7QjTvg(O#HN5~hM3Oov(TL+%FCM==J)85Vasp}NsM3T7^jb` zQ_qs>4#c0xlLJkgz?XjORow^=tD~p=fko(c6#XR=(|ORQ!}Y%BXr4L}IFlm4ehxZ` z<#3>nSVFAMy^hxSQ-DncNQt48o_D(+Y%sjcAk*d@NaXfT1^Ff)o_W|7CP%E|{Ko@R zU#Lmn3hslDJB^`2jY7g56Jd;KNW`3m59 z5L)9<9t{6hT!ndR_}QyFdLUZU=zi5orYS7-ta1;%$^yt;x7l=I^=WtK=BHE|1MY@Z z4-V-XcmgsTlzugZ0Ig#qiRfp^x8J%tZo8dw+%j`~#%=5C&-HNgJqilSEu zj@P*&VS#D$DZcq1r`rSChGVn10cu6+8zUjtl&ER1W5#JXZSt0co10PmUR#Rl1@|wX z!wKmLWGia=&X0}v4A{SgrfXbyYrHpa|J<=_(%}~a2ghXc>bPm^*!=l*ck~43>M>oD z!&}VGZeiI&336z&)2HeB*;xMS9L_@4LSxJHsI3~nN+0Jqz7oGadSTgKNw68I#!9~y zi+IizaX=B3%1RDJL2=ibMF*>g+s6ZfcS@I)X1&uBU&=wFIkfM9ExmwI?wUT(1&! zztTq_d9PZE{+qm|PWXky;A7FRfilmyd&QH!deSQP4gVnVA1eJ(zEf;MP8{8t*t36D z8Vc&Of5Vh$lND38?WEEm&2!M>QWY}}Zl>wGm8)h`BvTI93$;(obvVe!q?)UZ!S2xn zK{Uf0yhgkrR73Hn!VhtbgWG)!coHm$Owjf^Qyv1_X5!s_YTDFo!k=~0T}3!0Kkc}) zKHToBNcX$rKFW3ASzHBK90ysP28rrZM<6H@;h<`K-@UL}ct2zjq-u0L?witmiknEb zDa7GyHd{@c7$~l>Hv4n({yL-7p*Hy&JPA8Ra_uq{JEd^O6e2hAIIbdsJ#qR6d!g7E z1Q85>*%*ReH+@%am?hMH%7IoKh+R#dc7(`OkNLI`8UWTq>-OByi!c?6W8uHv`wbx4 z#xlvQ1!WXlbkw8(Mx<;A9kL#19|s7#Vxjvkg*qQ)Yp)~SFtLjWOJcG!+MWNd;-zDe zeN$&c^DVw6$SjH$cUh!;V!K4?n~P4 z&oZ`4vOp4`5Xr=_yBuC&qU;O45l$1d#q=O*HP!Jxhk9E}v}U})#88vkPeOa#rykb;+v52yeJ65@%X3QIjb~DP~1e@T*x@4W`b#An~7urLFiI8@9 zkBWsNRQ#$T1bi}H(CEFy$T3u0@2=0+*Smfwg7C9a=zDb#F>lwc=rKXARKLtImV{gc z&9r9!l&=phq{CQHNia&hgtWxgvMbx5gEi(bhp zTP;;w%wo2F+sZEm)IUW$eJdEHg!ceI#mf)Zpglng)yb$`qxjTk@^GS}v8*+Kg!#d7Q#Ad=!{9 z0IsbWJVUPC5gP{G;+pI0+%HDCe8>b4_gLW%01Ud0kfu5b$6pOp?3HyS9JzAzhKdjF z{FfEI>cm-VlDe)=jAHf0D{zO@)`0x_4OdQucj;Kp(hu(0>mD|+sWmmV%E#kQS{_fY z5rsTi!qeWBvksK4NGf~8z%*6Xniu6}=Mzw3Dw6;MI1V%|Gf3*13l`89ef8<5)MILm zh2|I*DpRLQ4$e5Pb)8FS*L9LO;My#39q5q`^E8&4p+;qP)^?e19d>8qo=TmIZ=M$h zV*~U?M=@!(pQ(_$sgNi1n&y#Lne_Dr+sMPuhQpr*k#9a2$gkt{N4gH4F~?h;BWTAm zaMf3CjCT`fz)E|Fr`YJ4ytAup7L`lCLEYm6%u2X5d7ak`S2rbVRmgP2xKhWR#Ze#36o6^*(Qo}y5;xp-52+~*QA<^( zv3GFEd2k+9#v5_S<)2oKl1m2jb2?BwRIH~-WLQk<1*&ySd3e0!8CJg4Y?tUU*2)D} zt*E{X+B%t^5Bj>{^m@I=RFUk~=NKQny2o51q+{rHOyvQ-hND=>_qxkvF>ZGQ?Bkac zahNYzngEC^p05FBS%XQ=%<3p`#GR5X&KU=x`{;w;i~Ly#P?F(|+bd_e?PS)RHl@wf zZ{|zQzzlhnW6 zX&Gy=#J0fWccbHj{P(9)tOhZjmf&?rcD8X_R}iXNc#{cfin=bpc2n|fW}HV`r(0D9 z-WTYV(JSfbpb}AX?vZYYD}LykyVzFBHi9;$HW-F&lp}Kw?iF%&(CK!V(;bdhR24et zX))>DPaa;tW(@L)gjnBXsRTilRbpbAaKah z6eqUsm@Q~HvZP&;-n_e(?E3bsI6v&=Mcd=p(gd_~m+myzXd17$QV{~YgwD6%B@jz0 zbaBu9KdyPEUKn>1iCIWKj0~CDq9#b6;zC9!Zh_q5JY{~|8$|D2ekVlTGB}bH2{B|j z!)F{lklOc-2BHBHvDqFwoE_bkNW`f7z*t4}(buQVg82k1WbBMD!nX(@1jxh5c`6#9 zz&rMu4^p=1mI16c>z&tlnZ8>H5;$^5+`D}eK!zA?iJD}W^PhsNrI;rw{ABZ_?!FQB z9xvlB=xZ#bl3~RIGGT`HQuXvN?zdWTU4yP!*`j{xslh-)Kbs+I?!a(DY<5&Sf)ibB ztGq@5I<|hWeaX#*pOcid%%htkd2J1@TW=20iou9WicyJKilUK%6WQ1u+ppvz#8{6= zrSQQ{d6DVgnW;u4uK2DyAb67~?~=Y0;$!lai*cuk7RQ?v`mOU@3sv&Su*6&K6R=Bq z7jh-ZBkz)n56^O*1UM3J2*JvbdK#KC?eTg^9z=uqm7iJO1GxI^YA? zV^NNf#r_6E&dfZoxcTa%$GN1&XpJ%6o|FUu46Tka;Dy+ES;(Y99J41vCW0XQRwpix z6m$~%Y9)ps^Z2K09f_Y$fTz6-{NH9^(K-HLSw{T|&Q5qBRdiA4!w*>?UcRXeYN|J!GHhCr%4j^2wxz`9vf(%Fz6nG!kP+dHFc z8+$VPy!~vxRge><9tSKAIJgJD&R05Sa*rc&8_zmvjT zJ3#8#v7DwCOo?yv7*TdMk_6!Yh=0`DKt%rXQjbx;rD#RNlD*>rr0sEUlm$k>SJ`$` z=_RquiAFm`YsEeI!cz_9*hX|k+bpR#fr_*}nqxhFxHo@B;W^mc-8BTk**>~q+>wv; z4M76dZiAK|4LG8f^bS>t@C9!2ArvRS^}2oA@7;H>db8~^vAcj5_2_w;%f`*8yYM9F z?FQTzBrChr%~EtbR@{*9^inz)qwIE zMMW9~|6eeS=dOM!yI`=(N{8q{_W4vUoua~ikt5CX-rGSSm>`R#w(ZRa&vrY{cBQ4J zi0YxzTd3Vxw_?CMg>$~VnWI4wP!Z4^8B)U1l0|@)gQTzWsp^jI(6F-|zX)7BjT6U|4!ktP=|3=B&F`CZ8wNgGwB3Tc@>>zY=dD zmZ!b-qe(d}F+I{fqE*|+I5pVJ>f}_?DR`6g_hUF^b<)Z`=IM-s-R-y||7fl6Sh+&^ zmKYOn1I28IM%AAcMejLYz`%VH^^=Kvb7H9S+O^WjsRmTad-({pSW&ws@gFo;OBF&4 zvbDdnSH!`ZYo3@iuIw~xTi5TDEeaJ$QR7yMRCN?Z85L5SQy+{u?r2rs?(PK{>K1F7 zcg$T9x~40MytaB5h_aD0R?G{+fbYHHp`m_;YUl*OZ)0Q%cCAb#_{^*909Q>A7t~)E zLjKf)vMU<#>9}CqZwiIJjk~uWk3LANTN0vL)!(53jyEN+EvWE!#t?h9gWS?QoX&~j<*iL0PsT|9dElLQHUK-*xf*Z zVyq)?MLI4&mU<-@Ca;#$l(ANvNSIdO;>S~{B$}pV={LSbTd86bm5#MREg8LniV){h zoZP>V$}GnbCQlbbrZG=^Kj4bC4RM?_TzkE64Jk2SQ3v`epwX^L88 zcVzkDrEWAavqI9#TOq(wwMybP6|Xm69$TohI2N^PyVuIY!XZ)kj>XZ>H|*rB9TBz9Fi56_5K4dR5TMa8>ZVkeEs5& z0L^Hk>AN3{P8yFg>8u0^mIo%&ybG%fRI<_XZO*!Q;fQ$M3i&-$31UC$$OrX^prrEe z;?}Ywshc<^6$lM0w2T$wdQ2;%viTkRR$M%A+DRCbAmW{KI$EW&B=aEk>g2K?@-*j5 zpnKcQ%X=ggu!Dpl(-8^2i|Ax<*ra++RB&x5$Tvw4H`Jk)?}Asp@%JH#nQtfT?Htx~ zZLrNy1sW!0Gj#*!&S#YGlcS6`Y-kKo(zv8>fXEqW$P&UrzCY508^9z|ZG~}$+aAip zaej~*E8AmQ@vw}-+d-o>3P*%w9hBvY^Qls(Drh5m^4#YSmb!9JVvTF zv_ERK#^Y_~JiEPAZA5s&Cq|`q)P`{X(fOkh7IgIf9x)MaT{yVgwDKqGBQKi03> zF+puzcNgHPZ55_)rYCd{H*t`UphmYEgnEYtsF=3Q9q~ye525<2SD|XljgVW!=|*IW zk|cHz$$SZgNnX)e7lr&1A?pA^3evPH7_z#DYXm}j)z*YWcI03HwDP@X$O4mgjqga= zB`7|V2x>;#Ni2<2Pi<~-1kJ0G++v;<57d#l;Ha4+$2S+EIP)ZTdknkP+@2R(T~J1E zPj%gJ{{7pEK_ZOxra&&QiTr@&^NF#58tl73H>>LNJEDAsbVXdl*05$kDqCPZN)T^L zZmTC+47-1jR}-tr#As#$Guf@>VndwOY19f-l(rd-e2U>++^=R%^9e^2&_BYc20)W8 zuV{BUuPlr?KWs$i;!@_=;yWax3qBPPVNWaMuu-9kRyQR-mrcK$!|P&W{Yo^kO!29v zgjO;?RvZC@Zf>{h2$%N5XzSM64xBGZ?a=FMRF?qFzhqM%VG1S)B1GXTAuDZ37uc*F zHHiu!%#A>f82;=2c&pm5??p_xbQqNIEo zjG>idGwRKcru~I^hGHI?V{%1Hq}y)9b?F&0z76iB!EyKHA~LUZ78{$z zZ9~hFx{-K9?AHWp&eRo)@oVHj92qA1rMP!5a-%W*Gu5REJBoBSk^Y%+(!L-~*dL+l zD5|jYX540Po20dOQ4|M8`C(ts5LNi5qL-sxkQ{8N=+lKnn2r; z8Og3lN-869k2GKFA!QD1BF9@&9Ckt!OVTfQvD$+`*P_FaDnqnkp_xoHbN9;;q|Q<}7VWIL-Sjvr7ZAk4{1eqjQq;m8^5NZ<&FQKmG#mCb&~ zt8yciJ|TM4$C_0796^W9&7_QP)6^QDv!hY0nw&rJnxQ!Q3#8yLJ)IY|T-=yV!`~SH z+`^L#d2r=exxYQ-%cAF~+01YKe#?2PszRzXPVYYs&@2);UyW-3j+Id!UTE_+sGYfr zZuh#pUfef(OjqS92)&}Y8ikM58H!1i5D49d4b`#Xc#3e#rCZMALQv5c0GWmxW1e(9 zl*~Rl5Z?R=f2ZfxoR^{JtCy%3zeC!u*?+#x(qFt?QZDnbWdTD$6gS>6S1W~mAMCl; zx#!9HVm+3g%}VVP;G^-#_kcczZ2lq2Uhc+M@`M$Mm#}tTzYJ0_1kV@6Q3ypT=8ZQQ zm1iqtIBOXul%5Ca%%9L`t{{y$OpY_T-_W|EV4P@}OwP18U1StXZRpW(*YI+la-w|< z!-oXI?DhD=N6i~-wAN`=SbPK*SGdxd0J*GL-I0?*UA7vdDyHOJIs$?`4{ET3XOqCx zNxd^Up`4ilHfiYjob3kdeR4mj6|zsfQ9DmJ83(%{K9lXnjJr}qh(CRTP0%onNP}(& zL0o9fX&Bcf7rZA>wh^8@EHb{KlE@w^oOmyZ=?dgsmm$BGZJfjKHdkry=-lTZM?stB zQZ26gwm>5!MRk%Ribwv@T|b2S{r-;`rE)YrV|^l4v5v=mn#gBrgYE_R_>p#}eus|5 zyhh^Cz-x`ym5p|@^^O*;<|=5>ZNH&EXQ;fHzuFlp&b*1dJpOdCJh_ODTq$!pBq?3G zq%QwMS#znR`8EhYS!p6iRqj4$lR2e0QQovw<4?;&{3$z(Xm}JQuOL}>EU)^xj!+HrS34q~A$6r%9jUxjAO(;KsoRPzToDXwzXQ!^Sx@B6hs(I^iy-PWob zpv1XveZ&|tfUT+ALzGLS&zz0Vr=L~Xl5eVP8TR1$jQJjF-37XmO*6u{t7BRH9=G}` zj3ebI?4ru)_JFI>QhA&Fm@cIGLHUf?2VD=?AgEO(-6oG-k~3=z;v8K|4Xq{ne8u zFL%MuAibMjxx9k1=hre%5We%AJQQN45$t8>bhm_yM_Elo7wxF4KNRYMmxRgL3dOYa zR=or_d4syObO>MPmGPVd@PgPpWS3inUOFEU=?WAmd^4DQgy313Ns!4&zY+@^VUh^& zg(#E^na5U%b4k`_@l}ECCm^+uRr-^;$m3S;>Gshq7;o~bn+^~yD7-l~?K_GLPPACbE{o#ERCeH%rVFiofspZ%2;mP3G&uxnhOU&avZ=ccV`!~*It(VIy~kF+M;72I`= z2F;k3p%~sQ!nP5d2h1p0)Mxj--&M)V&+s%6%HW}chP45ALlwzVo>uCiatj0@SvWHx zO@U-eYLHRY(N7nOl*9y~Zu8$fDW@S|rf zh%SX@tQUnhtEo)<3~%;mxxlLYIC#uwx4Pyptf^s`s8~f(~fb9en+bl%Xy0z9>=)wP~yN#6L~E5iCtC z0Kw&CvXG$Ca#2`HBn4$3xz7F`UqN#I5(<{PoG?99x&YCUrbrq;w6;3Z zwv~VrC))5g&@x5^a-&OsIlQ)^g=^5ZO)wDi*%a#Ba zV#sg+ed3m0%W!?e2Hfx2o!T=e4%W%u5pFUJh@Wx{VVvcY5BqcLnnBcLXwBGt&e%;h zKNgO~lZT^L^h7i(N&#?Z^?y1~*v<7807h9&mFQ_nt9BLLz!S4h9Ayl@<8HaA z_wVSh_-bn=gztQJ!1|0S-(6u~B7>3F0K3TGH@i^zHHULTjP7Ww>APob_SU*1Rt$}7 zQ{Nab`K1+!{V9f5gOagzyL^$I1n<4~lDVF+yoUG7c8i|b?Xc;Qqb(%b!o&ZfK`WX| zF@S47Q1V!^I=s7s#zX2}>Hxc3Kzua+{AHG`LqdQupEkI#1;iw{SfplLtx(fY6G0Ot zUWYUi-I$^Ta^7+NejcX&bJMTOyBBbl9W#Dv^>Wj?%Q`Ro{BoAU3ZJifq`@tVM`R@K zVg%Z>q2M+n@S?ZnwsmvUJMXO1q2ulj|FQbk`gY8~zGMXr)Hbb56Y0mmkLf34TffT4 zsZB{063Z!=@eLZ6lBujod-G&)e)T4itdeS3c;%(C5`EcC$;)sNdw$!a5XOH$&yWt?}y3CD-_seF6ke!BQUFkAnxmZr^9H z$1Rd+MLp@bgf696d9_no&ck=0hZy4LcYPh?Q+gXTCcVg?el@cfJy7Kq=~2wVb?I}WN}WiZE#Jt&*q=+QcYdiTFILioKAd)wrAoNGp+z%@Smu+%OWe43K zi4RJSPY=)!kxQF5jBIaavTZ{{k5%KifE`;P zv=N#09&yBk!FRN6w5k{O8B??^!nn><$cr>3eYL1rqE)JrP0yRD8`7O(){xDa)`e7Y zIZ<@ekiZce^5BDk?%lpEOMdlor&B8FjE$I88Wr>R^LFG+i74TLZe{$oi;87*iB-_Y zh&2?kk^<{yw09RgZD+j+){#YqUX3#+<6s+V22KfCOM&@H$S91AjAM3B2+F(F;uj8J zqFO(xJlE4g6qf1|oYLzGmQc^&wAksZDX8J+@$KTkHQDwfbVQ!?WvM^sD3YK_OVD9Y zg6^dv9)|=x;i0@XH4jor(}@n8$|6cNu4SJxvhw)54i1nM4^55NkjW#48k#{)e}pT{ z8a4Al115A*C(tup!ckG$9GD!{tVA0M_G+oX0xHJt6u3zAmGRM=(ewvzK;_ncyV`J; zS%+k%^Ws@aTIk3|p$0_;J^QKqg#!8HkRgr)qN8~nQ)UQLdGMU|HbeA++23Se;>S8@ zFF6*{iq%C`zke2m$ynezsM9;v{JNCW!1^GaMGY#nss&u43-Uasbfrka6%Njo6;Z_L zdW)9RmD6c%d^OJ@2N&s<0BwOI`nu)_eK>O{XJp2-#(Fl1!Dft7?RNXO`nD+i=Q<6E{@Ivx$R z(@`!4g^7ufEz|GlKZOQ6AQV0?&W!vp{0&%NlR%_b9{@{1Sib<$U7wr`IXD#_3-Q1J zdZ$j09)Otobzt|F^AvtWV#H?-E{;9;tP==OKe<+oo#NKN>huwnR1}94B#y4|%nwm% z9B8b0zM-)d{=<$I#p1^wyzsd{YmgbD{gVeKxu_W(DcS|oOxfldBKWm=W16hr{o7yU zZH4$RrdLq)K#LeK9CrB0;ayw&zx9ec%&uZ?)9el{h1_Yj;|$77lxzO@?DJLz8_Zqo zOUz5wx*mMdsv=s{7Bg+g4ADxih`zJOe-p{`29$;B5)tZ8mD%Q$%V|;`Srg|F8;|-K zN%OT@SSsX)lirIksG)ifwA>a~vpS~>3CAF@&(PA5SnfF3^}AI&2| z57Z(RUhWldUNe%=3JA6;hg(^pEr{tDH_t&Aff>)i-y~f6d|qO_F5NerFePK=DU5&8 zs-;|83u7J}P8_dku7U0TVcU6&cH5hmZwb*54%PZoIKojrgz{G`VQE>&hBiU%;_a7w zi>=-0_>A#N8rq$(t+hb^DiDOe7gHKj+=irOTf z?h87JC5jNG&6%kbQ?+ok;a@u;+;VEuvgL{NE4V@ca2ktP`J0@FS8V3hjvTmfY3ui& ze`U#tildFE^~0uTq^M(0Pbiixb`n%3hcHP>XxX$>NY-&N!G462HPAX*9Jf#6q{UCV znH179RnyIz(2j5BxKlq6H?u6v9FV4jEF!drUJ@n3Z=W4f9L=F`BeP+3V%r{W1;Bhj zi^A|>xCK;QSej3<$3o<8kv6J1Ydkgw{Y$gHaW!Ea{#H9IOQB^9Aa`3y-! ztOi35`2$Bn4(jRp%L^=ez&u4AAT z%pKqSrHzg&vv(Q{>o<3tZy}dQC>!9Pgw-iRN~0#qpBbIayMq>1oJXoTox=GoB*n0i4UqN(_+cVJr8Ok8*1$y* zht)tCDt|I4WT!;mQ!E0F{}YoWcja43JQwo>GU{s@{NN9H2$3ygqp?He z#K;&lB^WMTyh~GMj3yMO>u8&~q@MT{#0rN_V%967aWJ;E&Ss_L+wax?9&#JZPJkBEBRCM-00^ia98_|@!ompKE!nHT6i;h!A>FO=kzXtElelNTz;x`qyu|u;6r6XgaRIrfKM-(iygXucPbrvGHom#z5oTTJ zQb;dF7o*l;9s#2*rCk-!_!UIirA4AVj-wF5oj=8FlunOWi=bmOYvC5FF3>4}rr>}< zfJ*N{fT!aB$A&)Gs2S!to2>+IsbPf13QPxDih7?5Z$CuXjl8X?X%s1AQljKneV@tQ z1?ZT^@%91Q)zm+Ut80RegJM##rmSxq29)&yb1G%9;!2&uOa|w&sO+KQ8+8=!WTV$6 zqN;CjQgr_xh_Iagy~X1ZC>v=Z$J-QWK$SqkG{ppnVi0GRW=2BKAPc7;$5^k>m1$9r z59H)4`sxSjshplw6kvin9aZ7w99=~ABlqN&`F8dou0o^fcFY6q$KBDBX{goG1mFDj z3<N=b7+v;`qz9P`-W#ob=+_4cB$ix4q<}QyKWui4mV1|N0>^-n-C0k8 zXhP8>LrJBysu?SpZ*;Wkh8^pYw0oAm6UsIgZv$M09UaZ z7?nTf^k%{@1c(AX8|E_;{A>cXN7=ks(am7|)Sw2unlzz^xRFHH0ro+tNJ-891f*ZZ zb3fM_wW6uilW%m>S{(opa7=<{H~`R&m~@Z(vsbSsS9`o!V9;l*gm+-_E4(~HP?-FpK&LGH*>e59DG5}r~c06_m9t8=owdO zcpW52m8u3%@hf0DuSfYhki@sHOm2 zb!Y`WX@3Wy)ti_Qfej65FDGjfw!zr#jMadh2rY8(4g#rx8RA#PY16{!QY;CTzxkcn z1m8*DU*8En+cVsVRkXCfHl(#OJ*qRlw@>ff_27f15lfIcN3*M(5c1m zwhnwGSxQp=8LEAFqS64A@k{0xcB4q=wuRUj< z%mt}a$u4~Vf|&$CaHt*CB|d7nLku-?*qJ?lk;X5>>elP^EQ&}yKEHgdyqTTERl%gN z?-QnJ&6X%Fd8O`4v}FnE8e|we#x|o@#7BVUTxt4z=~Ix9gEeE26n0RwMbu5bY{Tvm z-kG}E3qzj7ug)$i3d67ys+^0vxTC-$)riSHn|VDNlb9jP{5vsq*A8VW2B5R}IS#(w zBh>mWqO5ULS{j=^$WB(}Kr!1GPTtwrk_Yv>`aAmBZ>qs7t5 z(frZy(e_Ycg9;A=s=LgG%11Y-^z%hcqq3}`=c*!Br)Q0IytHE6cuj?x>$(<4aK&A; zYs@-TXekjkV@<@fk&G+256Fd@p~7qjlVGmwG)K5%tFmnYV%eRp-Ly@~^BN6BclW8V z6}X+D+4S?ZX0JENu8RAVPCk#v5KF8#2eN`+Ch>+?dV`tNi9QH!)}mjNeeJs@*ZiMb<}V=d$`9_GP7`jG(#33HNy-R}TzB zO8OOS79!8#qGq5q8fe82Li;xuR0~+8DU{P)iGk1)mL#7vHyJO3_Qb5K&)=k1v;zwV zL4)j6Lnqi2LcZSVxWvMqo%gUwKs|umXJdsd@?dTtu@Y~(tc)yAdv#4 zR;M_CiWdm9R}9xy!ne{ipgplc%w?)ywWo6)+1^VVL|S-bo(4L!bFW`l!_;;11Q^vh zvLXr-N(Az+7kYss+qCKxk?LT5{qdsmq&@Qo4hT~ICsg*@uPd6E5SwAU&V3eFICQ2V zJc9O?xUCuQo8xLINo!@_mkR_lE{D`h$ZUj(fTw7auv;PA~?f zM!ViCb9MeZQ$YqL{ zhcamsUsg*25I!0y0_wnvfsX+%cI>d=fi?LQK1j+t{v_w}$l4d?l5zU_P`R|o0$LOj zUaX7D69*JEZQ6{bqXrErbiVdGQ2FF4`AB^lm4YFIrqqT3AI()$=!&-5@tcRTCCc${ zH2p-OfwyIXWswVUDqCYsK}sl?leBXwE~!k23#@olgEfh3Af~Mz0#aVbb_W+FcIW(O zC2Ob+;Bpk>BA#d?Q5_vm<~OvMbXu=OVvz*jjaX795eP!>HA}hf>9Z0jK!sb?DyJpq zuylzC`2q$FG1UtG1pQiW@nf+u9I7gjN;PqD%9w{E$OH{*g~E9irkAZY=VI?!&Ep*Y zb(1;kJIRvu63$}IlJ?{D6EznJ7t9_8s`DTZ?XK?a-kSoUUzJ!Zhs|EqqQ3nGH?6D6 zpn_DyR2FrYxvgVSQE()qs^+mqcEe?{Z3f>EN;n*jb3eQvxUdL6J-Rk#!C1^!7-NfCzML2dZByXO z`Wk#e#k8=NFl)+$jibA@O0G#n3&)*l=j@=PPC?+w7HI*(6hEp%#F9y)hV{NLjI$<< zT666W!FZdr3ATQ*z9dr@?{#yqAN(}(v75Wes;Q}N%?kXo*Z?LANlh#|0A__oEy1_N zLDtJ!=!l5b-6f%BXKm{&D-|4+pI#mf?lg5{(7`&jtcv#XWTmh=RsFN^S0c&Gy2x*0 z?X-Vh^-yF<+JQT`TRDdf-F&()qoN~I*|ylh9-&jWjYYhhG~K~bWba;)dpr`Gd!$iG z9QuHN;6I~Uqd23Sz?9C&E`(CT0egGZUs8KBe#@5`QuIbpvzcbVE0-6Um4Ifz);b|5 zI84(>-3sL=I8Hfb7f8tG_B^Rg#^{=$GDN+H=-#EGO6E-`S&{G4;o}XK!X;lWLnN;X z>$@7=ocf|oUB;EUt;OGhu7flL>F-&gqvYemu_u$ftqlXXa0_{l)r4gz1M`5qUcJ`b zC@!a$n4N9!3Q;A0l1bF7^!Fp29T|6`A{6z2kP0*JBs$v_-zp#4nkVn;2FJ&}-ezw^ zPr`q5O(q3a$ntmY?qzIMGrm~I5lpfX8qLdw4NX@U>^c1gjb22p>aie0Mpj;@7Hdq| zOKnFZIX_vrj=vf1q-5C-RHzJ0={oUtvrb*P(h!(zRBChwL;^>aYA6tS?Gx#W;yG7*1k_PHO)cl zBZ~QwHXI-A2SK*`ux5=#Wj(+~r>MxJvH}SHH0~AwI@wgRd~`y%VtiW6`?J=&!vw*H zGRpz5`c*ZhUr`87FVpTQ@m=E?>rS#C99n9ZmcD|8??qoR)x0jH8=HL%CQ;fq%HXKR z!>z`GD$LS`R`((=9UooH`m-=UsrA;I(lLCjPsdXl`Zi0-+DR&1GG$Gsd<@lB|4sw= zijY8E@m$6RCoa^GQvw=$GJh~LV}<=M(tNxasuAynwoX^rrz&k~kJ7AI8^&&&CfM`u zgO{4hO&DzyS4(c+XE(6WW{xufGNtky-Wo&QDVt2ef&PBDCyx z+79)E*tc=Z>O`wtFaF z5!dp6+pU>xlJ%lK|M&>`Xy0V2nI5vlOvTg6$uKIY% zc_xI?pUr2Z0k)YBhZb)oaNM^Pz~2|ma63|;@9WirV{EEnHD)OhbQnEd`?^0Ge!bfZ zBInS5$0malGQ1?9wWZO&2MyKSCY*>L#g7?g7om*@qI$Y`l#bvsz4u3sQVj@UJqMzN zwAIqIUtn_`^OLPrJjodv7zBRxdD(WLW(9M150a|+Q67#UxG3I<^^6ZA> z3-rF8!aQGwh0d%NUEr=iulFq(zCbfUa8A6I>})5n3o3c)95Ks~lGM0eqKf9I@9?}o z`gIFNqG~seumpNq!pSqKx8l@w1%K5O?|(c@ebtkhC^m2161LwU5{@CcVt+ccB(Xq5 zb4Lv5H@$92H1J8vR|qkz#vTcJ6|lQ~@fKh$QWivhiB%63+)f+xw26iCpx#dj>=dL? zZ^BPyFMW&13u5wFb>u2}IRi@X*nfWOHhDw1X$~!&PIj%kYHMHBJ2koK9tuZajn>)j z4-y1Y!`L^#BXy3}A#FGqaghEMf89{cO+>|yaX4 z69P7!IWsskHO!z(1TYUT(URAPY8Hn$ZZ_zjhun}iD`MmYR7mEr(ruX*->n} zTS|C{kWR1O87V2>Sd=I9?*P~lYGC*X1G2W!%Z35Bmc99x;J z;bT>wXlKjK5|=B^vpzWAm!o9Ph7F6R#p=Fo)f~XFyBycehrw^pFqKc+T$CEH>Bzj5 zL4mnig*L@E_W>LhPZ%)hka1mVKJ{ux3%&C1@FB$c;c_{c>NGuMSt8_ee~6DisKRid z(@}|ma{8v`wEzS%cB;zlN*YnLe>%y}k8>fZ-DKpJH)${nT;_NUdPZz40>Og@AG#3P#w4~uW5GE zxkf#(F4DZ{)@pCK-kblpz@^*LbY1)nk`%&pQUuIXres-%5BNM{q3zp8&ZUw5)@I@7 zSH%_T2wzNRFX*S#Qoz^aFKIA)vB;UPH=#-E|IID{On{K}R<<*J?Y`Z} z+KR7#ONrL=dZiapl*DuUGVQ>9U7N|JbNZ``?%zEdx)Pe?$&Cgg;&;`m%2M18$Jcu~ zv}2gv4~DTtR4%#{k{Gf?SGJ>+^IXbc3yaO;kwATOQn2kR@BJB^>RJN^e&mc8 zsZgqb?2>Q=@Lc3A+lf2iV3HgajkS31*YAVhB|$OGYBZt1*-VocYWPxYw(DNkVAN@H zSb^DcwQWT(LH8@;i(}Xyo{6ze#lx9o`Oe)!OU#L|M5TK_4;iB*yph@a~Jp@}L zvZP7ledlg$6Eqj5J}u)KtdH$jrfFAg^V~FlLEE&*n5$0)vsN~qtyZQK1Pz(#+JIfB z{6I1R;=65>HD*4A_d!iCW&$O}A`JpMuBFl&KBs-1jK)ZSn;^E1I9`sKo?RpKsmu){qzFvnL+isnIU)EI2X?sk;cK?G3RkoH_wy`Fn(E#*l zUAHL^4b6!94En%{cWT$&=uWmC=E}&mwq>&5Fr~_}v&?1;PLAL7O%Olbb-p8I$S*>o2bJQrW&ZNv1OcH!R@-~V8w$Cji?uWReL9Qvfn+@$y^r zxktR(;nBRVfS$enI+C7EiQ(_K_V3o3;kNseB-3Lzt8Ya^(rn-9_r4D)v(rBITpGoJ zJ7DakuCHvaURl^pF|Wa1)5y}Cwu8O=vSzo+Ix?L2Kqaw5=|%O-zXw(q5rk%#-u4@S zn?aOufp>xjS3&r+M;{;9#7kA?U1*6X0Ei79D+QCh48Q^a_QhFCfDInlPoRsgyeyw4 zr@e(+QC%GoL}~b>!XrJ3y!1Qb&>oeb*3-)-PU~rXmitJFO=(d^j=LQyD#C)4l#GBB zLrO_;aNH)mXGp?27h=PddGkDx*ccfTj zWpN)_#JW3F?z55>e@zvQ5+B_cw^`#eI6Vu*8|_~A?}t`(F3wu9#wmFf((%$>)v(y0 zIH@bh@dZ0|XEDSSqO3#BKq`M~RmRnPxztXhA=Eu}>!Y$*LQ?0XD&3YLVY96bW9}R| z7P@kFg*dLjLW7~TW;L^e zw)+Kb?ek<9maXxce79lG1N3R;-v7>MN;+{*8}C>*1#5vTaRq`@4Au8LO!jMRUTcYq z#^CB|_iHP+Z{^T!d zLpwr;bb?VL54pjbaC&W>+vsX!JyV>NT6#w;MtI>^7&jH`<6e1|ob0z<(Kwz=TSBm` zP7#mN*}0LtfVu{A%}~Ib?g>R7txIE@vIboS0dg)D#F7jKu7Bmp_2N-xD$;-~tDmQ~ zKbvW5J2NwvXcPN|Em*f!bv0EuK; zQP-VC5_X+J{oXA`WWWwum6UeT!Xri<=cWmZPZglTA**PNC?K1#Eji};n_JORzGjme z&H?|rJ1!?Yhh#K>hNNu?{a$*#nU2q88>ojF&;Q9OoI6}VLl*sBeC4rwC6Y8xpm!0C z)d4!7v;R3w|I3{349H|Yz5K(|NA;5b##xy0O{CDP%Jaoa4r5Ei{WTG36567WmrHuT zu^?cb(KoV-2cX*yl)GS3a-r=M%~7BpST&z_@p*!cV(0?)`IX%Fw$(R0*Ty!fE@j=^ z)7DvCZtKGZqPnQ0GHF@RccU;t3|YU0QxLJffi_g5$>*MGNBIC_|CB#?NJru2yOHic zuXCnvQVxL44UXLj%HE0q7Ydpgje+1PIfi+@(16SnA2rrSqJzEvhtG z{E-?)Dn+z@M@ine%Vhp zNrG?s9M8(u`tuIy4|fCZg z(7Q&~){-NMUjQK7B~~6$B2zL|I#HHb`s4GG3ne6Gatsi#&^9(*C6qI>DID*bd!&8{ za21==Z8zGV;dU~2=BhvXyK>I3s}1S@F&%WddS$hxk(VQ zYgU>2`DVmO$#-bm0iA*7i0#Yu7tPx~nQkg)Ox4I}5c|o`i0{wTSxArbF|&F{a2nTH zUQj8hYIqe3r=uc+*98?{09UGvAzd)5yfs7dU6pYeEtOy3ri^O&;BOh{-D3TR*RQiF7E;jnFmgU^J zh`&=ZPsGnHubkX$Sud)j8Yt~gPn(`_->|=tUw*H4M#rc0QuXBiOPdL2P|rN{cLI#R z16rvB^pcT`ocNSqBoJwp4%62SA0@2mMrJd+x>nN!6L)*0_Y!VWOL~{n&#Lv0qm#w` z+m6qh^Ljx%N5neZ&wU>cne6r3uz0iQ3=GyhnL8|IX>Z0?O`4!MzPUR1UY^W_>gws4Dkv$8kt z*2SB_Qg*(rvRA=*UH%tJjEZ^>+VBpwx0YLHVv>`m;yM`3`uyqpo#8{}yyn8fQngxT7> zIt^7-hVD|frbcq)q(<)A4^n%wq^eVi$Z7sM&kZjdOW2w(kK@c37#_EH_hf~q7?jSZ zc(L%^$jt8*_Ux>z=p~2U{^!fKlVFRoKy4;ELDN|1n-!^gwtCk3xY^OwQCF46O7WvG zD6yC7esbKBZ=4$t2|<2w9I5zTz`riv$i1+zkRFk8CByAKV@je4VFTW_{**AtUa5M% zNkgwUz#TD-*4^3U$(^O(S&2|5Gg4bG$Do%%8gm(ks8sZ! zqhI{+(&HJ-U9Nkj!vl8n9Vyt!M5%zo%6QX@g06K|f`0eQmaycF-G&pXCi}6?>oG%S z@%s~enn;g`b>-T10-O^uH*3o}>T{*H7o~{izXr~<6UO%Eu(O3r0usUya$ zWmmzZ$Q4zvROQF1(x56KY870(wmP$zRtwU*?}C+bK^3I8E5f>SnR@U;OE}VfC_V;W zBkw#{EENNH3Z8PrhIzmuJoei4$SLh;O=arJakQm9^4DsM`>>K1Gp(6g!f{PQL^Nw0 zhM_BohT&vabS(Ds%A`>+Q0#rGW>ikitH9*f){wiPfY>&G+?*QPfQL>^lNp+`(2x;i z+neaANPj=QsFcIQ!ihQR&6$*q7^i&6r$?N+Pl|m*GG|561Wv5>uySK?p*hmMnJ!9< zWZIe%&c~wY<1O?Z;7|I@i4V#r3_{54P~-ia2;c-y1axd|p5mPTG5$Hj$mhKs9K#UP zhwhorQ*uz3i1s6>8E2r+Y!fSLC08KELfR|o;JW6pj zyA-i7ICTkrA?|5;VX7$B>Aq-B=*ZTafcmF=^WceneY`(heE)uon6q{ax#KdGd_yMC zIdj%rbuWM0LD$KWK>P2mfFvVMk?XC34UG9N#6^0W z`^-iH_cd{4bG(6rrL!koYk;%PV1W2%hSO#{vS}xKDn3uD(o$Yu-2r{Dp)VB9K-OsM zE4MN~HVrM2y&6qd9{#AkZgI?jE7C5{do;=Ri$6qdEmW==f94gV1Ebjha8~NJ zO3|ewK(qF111RkEVumY=9G2mi(4jS?N2#sV&bua#U?%qQ-K&XJ|1?3xiOGSZ7>1;w z`P(a1I=1fv_Uu&74bzyQ;2Ayn|BGGVH$hrgh)|x*lrv;eAEiy}irtdBQ7u$h5~yj9 zJGv;rdStX*&XmqmKwU>(2H02X6f!IuSUZG$;jR}Hb^PZrAl*ZC(4d`^--AnsZvYyKLK3g=6@cc==Mj{+anl!m>GV{nv6B@b`*- zn|zr&8t>$JLye#86vV-5jyM%0)q2RDh;8Lpc2N&|3%o}LXr2>=1f05=d>3fOMp!U} z&Qd>o^jIGmJ3THQK)A^I&oLQ$%o{^C_Jfgi_JdJC15{EnvWnI`%HG{2Y;IhS+D--c z*vAWOh-~{WY}3lnSEMzcPf8-c(7nuwWOQz>1$@*nB2qQ8yA~uQ2CJ;cvGqwk5kR?I6h}=Xx@pINrzQNmJ0V@GPOR{ zpr{1)&@^5B2X+iQSt?PqpbU%w^(5?wDvm7Y_mcfO!_n-eakhaBeWgfVT?aC)Cxl`- zc^w)T7E08!CGyJZ3iQ zSbZq)i{gao+EhZvx%2X~>7eidF1lgbp=;oR+;kl0Xqs!wHTlw&`@&894e=-X;N|sY zx`zP`$JbGVqyjsE#4?#EjhdH0B~pk!92|k6KbvfJdlU=7g}9!nA0A7D6md-u23@co z@Bqo+OvHk65|L>bMdMjk88#5wf1(fWZs2c*cCUn90Z-J_lg{vJunJrAa^)8_r|jpT({Lip?c+>u_7*Xq<`kS{&uT#{C zlM}tJm|_^7J9w8Ne+bi%^!7!#K%sRk`ik!urQ@|Vo?2FU1?fi5P%)A>Su!RT=7|90 zT+r)W&|naaBZR3K`Ra))QCFF9a5qk#H)cn;h=b?2V0!wJ+&dbb#RV}#^i@hBVq`jU z$nY)bWlZvLyyeWg>+dxe&~8q%d#4qDSA*k)F>8-1WFib66BT%fB(qIaKVw1ru9DnT z{SZdM@FX$ON+|=<@b;3gQT|Vu!aRnrXeLbu+_Q|AGm|=vPtIuzN$Q<+_7De8W6T~I zpC0b`RS`sNOGaKwGeb*g2kB>b>LjN#Dvq z%}O`AXWdjKKkcJlsBlxNWrKsYz9hL7#PGR=J-rH6vmGkn%02qZ@H%@ml0O44dL)BA zHroil-1@#2H#*vWcDkE2HzM4~1nS_%{?nZrH*IrM6Dw5>4eNhdlLOkeJRo*W^V3p?bkpouY}+CW1o>NXxUpVFj!=dR$;#UzNlyZT@CU7gYe zcPHcW*7L6dH5weQF?shHlNxX$jT+B2buhw=GrYOEj{ zNBr(0AVN){Q1dx{<_Nrfwa?sj4S_W^=5!3+`oI*_$cy3~l%~w?rSlcXD(6H0Axps8 zbL?qUD(EO0>xVBbDpDEEfSL91u!ZH_CV)ROSZ!UXNMxl{@EQgtb{6g}Ekgp#XBzpO z0W)Jh8-tH`0jSxP5_o7)0D&2O5Qrz`V5ngpQ6y9^nOj+%>QBEN7^{-{%@}(fSGl0H zuGeV7ZRm!J9{A%P)AP~A2B+Ng_kC?}d`Q6Rs<;AQ@I+hC($Bq(5xMOZI z5eOWGFoF>c>tR{)9&%iVbxX;@VyANU_RLyZ*bpJ({REoURq(KPdv>FcTZx+;BWv*0 zL1>vML{Yk9=3(InPxtmQU>>xBN||Dvm83d4Iwk_&Nj@fnzQexRlPrc*VaDyk6y&0b zrimv>ltmrYm*h#y^CVGOnlv{7sT0(&hvXdfQG{(dvJ{eAzO`X*<|sLn1;(t+8iwY} z%#tJYcE_~q74<8XUnBTT?9LGzHw^1IHwz$~ouD=OkT;%yF+nxypSurIg!-YhcFYO-F@DPj55Em<_SR3^h*mK z@qNTja;Y0;QCT*uP#s70`=Lj`MUZTn(<4EL193!#|4Ewwa`1PcJc8m}D-BMyt7ykp zHnibni378?Y8!G$T22^A?lr7=zGax$6obSCmx<{YMwtaeuiz(_!o@>;vcdh+8V}9? zq+&DO=@Gxtq#bd|Yy%O-sT^73;#kv_-X369zzP;0EF|TNFSe8{Y<7WmY294Y0A0n%OCPNtqKYb?SnJX8gC(jhZjR?7GwdCXV=SyjtEg;2SaJpSV2f97_tIo-sc4Bm2noy>B{5i5Gohv0vMPO- zp*hi#Lz>0lxkh=4KwEsnhSjzDo~qEsEl?@V()IsQKrXjRTVH4t8nb}GZ?Zsp+WihL zf?V#~z^*hf2fpsPbEJ)CI#oMrf>DHPrWH(7NiovMLbNs}@RB?&$@{@EcnPYl$*+yq zl66;L29$#bBKwO?ro2pP=;B~Z_xf0Uh!5a{$j?t3nP134^)-P#5t|Eo9$z6#;XGjr z50Nzl6xPlt&ZABkzzw?3JHj1xe%tWMawa2@RvqukVc*A>^7aNQuv-ZWPN@WmW=x*Z z1*x9j;UuS-)Mgoi3!G~-63$5_r!kAUb)8fY9aK_?*G!r`p4+Nsl*&)q zsS>Q-m~DWd78fAs1D7uwtUMZGo1)L+fy_rdfT=XtNjso%xS$oQk8`kMGCxd1@M>9{_Dw$d;L;4_X$5iD4pNw70@oIoc;r7%)dYKxxG2 zVXPKa&6Ye~3%V9bH(raHM%@#ykHf0Tcy>C6ec?M^3%F#T)+*xCb;pXqnn!5^ocM=I zjXcBe12HHGK(jT3yfT09gS@hMPgYS)a4&_tGHFB1zlb$nuPlmK&4LI*<#1Qbnz&B^ zOT2bb1d+Na?vLdERwAgSDC+W5P1KNEjY6==zj{L^mcvjEzmiBH4^C8ndiNi|94a zhqTMVy#jeacUQ>s1*PN>V+Px53?s^6aTfuQ+Mor($w31OfD-ti{Dm@iTlq1Rn6n!D zCKKfowdiOG9N%~na%AV{m>*?cZk>*$G@&?;=9X zfwaMnFX9%J71gA(<@taGLeFE1I%@b7(-gXl-=GC@DpVIRXW@ch6|lTAThoqqvP*sJ z({oQ9O1`_$6*VqOc9i~+JQAx7r*@$Xu`PNp`XMM1I}0{@$LN+gE@G3}@P)FT(o&xz zdl-T?L9`>GU=*Q{nZKD?7Nu0BbwzR)ZspJKS*#E-`X04Av%-BZ#GJYvLDYDe(2SN# zE$l(*M`FH`vi2yY8*AQEw~kF0zDY|I|B6@2ei>JA#7goz;BeSoX!IfFDU*%wZkM)+ zO5;ryzqxlwEG1dOmp1?0^rlF6ke=kWoM1LPcfF zcowOMD?U+gFM?`X+Wm(HAUv*{Q!@iSMR7t*h7e-dm@^(VU3LJ}XuTPj+MFk&-u>wK zFLS{k8rPUjR}b7;kI+w?sRZG`7vd}mBEV{)JK~~oaA#Aq_M|#5uwg-|&T)AZ*ekoZ>7J z&OuT2yh(e}`WiFkR+&HRox>C*Vy$66@mh>G`3=P4tXE4LqKMwwJP>;f`p&)rYRT9# z#ROtzlEotNWz~;=9n{b{|FB~tm= z$ty8e7jtk?R7gaS%B;h-r4$@D;tk9Ege26m(Q`Uz;xI|XmsMDnAxS1cJru^~jC9+b zlnoYE^;FLrIBJf};4P1yCR8S5KLVG^s<#K_R4pQ6FFytep~?n}{pOqqlTJ}UgM+e# zD7S<^4_EClu}5N*96)2%WWu8+aL5ui63$VNwrK6a1d{ket7ZbH+q71)(Q&CfW7duI zh67!HVd7ztZOjsh=SiSpABlqjyDSwc_cv`hjB}qa|#*+d&<1-MEjj`!X_n&~=6@a%4&BZXo)39X@RZ88M z70Gjzlabd(0bC(A+CfL!+rjcy3kt%VY%VGD4BhA%I3=iLEdib5Hwd!=OACm?vi-XK zvL`HQ0Z>8~fCnuJfv|fD-Z2EsVGbHlc&=nerdi=Ghe6s`sw?m+J<} zr;5oqpf_2mSMW(vG6-Xy$woju{a9LHh=(cQv~;}v!D!OZ|H%+Hq4!NJBZPxs6n1#b zGg(VfE|a9R-;9sV6Pgk|I>A6~g-Hp-%Bp(M@}IW)bjwjBG7n=)1O=xLkDseKH>qsY zAp=!dS{N|cVVz?J26H?~KS_&d`*QLyvSH%j;niS{GkeK8oTd{eHma(ni( z`AG+QcYsg8XWk(*%S+^HNriVC_0>ZX5Rnc8M$wy=Lt#R!I{4UH07z_P1I;yr4aO6K zuaJTIZ7KHhtROEnTUIhDIpXh!uBk7h%OVU8poEyxa?*CFM#yJ4(T2~ zE+tSm=fKGcHz)6wdOntmq)!w{p0W1^=fpkU*^?bTVFX>Gf&BshLGsdVYZuY}a|K7!cUjR~R<_wNaL6+EXyaK($JKE^A*=Idyl;oZ$uY?I9Uxtil??}W9Q!&#@M zS7XWh(NK<{>bxPwD*5|tAsx;Yf%t~1Fz1|VJZYm_9}N9N`z&;LY3%9 z!blX|YfcLI`N+#k-XC+yeyzbQmVcp+?nf3fbNZ*D zyv|!bmRz6so8VH6YHnjq}-4b>hiF0wG@h` z^Vo;B{?^747T$@&`A~Wexdn6ieMN0QL^Q39DvO^#a0Nx#k@q&|;?|#i& z)uFIORSG4uqk9&&zWrKb6{m3;lt#7G`naL~a<#~N!PnjEy+l@K26X1b0CiwR z$oh}=nmu~#&}^O04%v^S8deG4+YhZ7g;_(#^@%`Skg6v&5I@ioiB zjkDCx*EpQ1SWXBW7*9`*mT}0TH!i9q-KsfI!6jJCK0^?YAb1B8nr@#MmPR-Q(8&Q+ z67o-!`~W(@tfp#4=iZppLQ*; z00F@rELsG1ydAT`*RHl#5sV$Tu-`pMk%oF`T0TLGR3v@~{T}Y7Ou} z{ZDCvvEvo@yI6&4XvR{vLBUtqE4tv-{mN27{Ixg+A~VLe0l_O>teG1%$*;S`OKR84 zE4$=B@0BsmJTFFmzqe(Bfs~i9BZK41n+5ste@XTK%{>%$a}rf_`VULqQ2#$q|0m<||AcX7U}a?ef2c#TutC)e+YMIu zpX(lfyq3H;cP}Jx=vM^WE#NIVU|?2g!Sq();AL^emfr6VoUsJqafNx8I%L5(G2ENz zm;IY<*?;z*SwSgJ{@Ps`fpvfgAuk(aH#>D(fvPH^0`Kfd_*syPz5O@eQ%3J!lGEE> zy;uF_o7cVcyX${&YdlTeGvoRt(%-G`zxlIr5#J#e=SxydS|jE=_hcy}RdqCye`fwz zlK7jIp`-Wp!jP%6j|85OtJ{4z$HzdRWdQ%2DSS?0l#Zh}yKl`a=WR zEnaq-r?;Iy8^9j1^|P(@n<0|et5HnDM|tCQDF1~fzVX@fKdfQM*hvLFfw>u)3wa?kR_HXYn-=f1g5iE1X z-S;)aRClC0n?nmaY44V+aoJvHqKeapV3ROcL z`b}93djn32atcYy1n>u3BrReBhL#hqaR-6ur5;Q;RYsS~Jp8sfQZ`xvzU{%(`%)F2 z?**o$4Abz02VJ4m*2Q0hG=-N2)lLhH@@`=_c3luCz3xlBGZK+;iZmgGcqAbF(RxF1 zKlyMAkkh7rFO=GYnE&X|dCO1nmKzWP{G>btjxzDSa;{~|DgWAI1WtGmqZ+&*W8eS^7ugMg0jl9l*eQJ5x!8G_FSs;>Mb>k@oF?tBu08S%q4|IkjeOyT}~9B+1Y@S7whbijn%mcw22RKe~QazSDp zOTI8p)=xsbo;1OD^XRIE>jifQHL3VgHO(8P1C^Q`1o{9NJ%s(-A5c%Jrcd5Rh4wnl zEZBE=I=!0JDwME|m`Mo7EluVcs=Ht`6>Ew*1GV`C8F z>fNUwv=5lRaZ&Xh|0GNQ`t9(fQkdW6YN01rBJq}7zVxmGSW{U$Dpaz9lZh4>wX{Lf z%-sa*;N_5Q)L=tZY+#E)pvJVWFCGwH#?O&p9uULaBG(ZSND_kxsK5c=b9du3Is;m~ zN&IXydSYshmjKo<1g%@~%FBf6?^wf}Ri{p`x;-kFg9NC|84prd3*e@YZDFeT`4fr| zlAza`?+N*T#_nlBJD8ukL7dVJwY3 z<*fb<)%7k4=2TvAV*h9EfmvX1+fk*M3*9{f$iUhV#2~F_?;vAsXli5%GNcsdWM*Vy z2iF*8VrFIn004B1Y!r-)6jXmL>PyVT%E%z2=U`{*q6r=-!43cA?|1LD8RSht1|SJ5 zBWrGM1_5C~5gj3GOB-uPD??>h8xVM%u(g2_$iczX%Gmx_-D0+1N3ZxV9)`S~snf54 zS{$Tj2(se^|1c%d}x52;Ujs_@6vr*iZY} zvQbs=sJ;=vVBnx4>h6tIB%9_t-IoCbrDWU%f*f?q^W3N5`rhV6lmz`i);rR#NirT25KMV-Jb5@UN|@w6HAF|iE_34#WZX7|rU$_hS@zt&s+qeuY&dPZh&m;L)h z$^!Vei}cq->)$5QU&Y-2nMi98zRM$t+_?7;VqT`qPx6WdkeaR3hWOPt)MEr8U_O3+ z>-d%8hUirutbz4Dt(aD2_@V}CC*pVZrSZY_snI33eH=o$MXHJ~2G00za-27!cZO+A zLTZKuNpb57)fc2kygBNN8vMy3o-Lp2ZwF-h^Bz~$6#}Yg<9Wd%bX*}r|8o%n|B(ne zz$L=}odN^^|Lp?&OL6pnO*Q;q@5x`a-~X`y0a8Q1?#Y&ukHZQAo0T=D+|ZbFp6riuBWnDZ6yn_eos3iJ>7Yi#=lxzWW%6_fgJ z7ncx;?#X~^~Ogp1$w&SVfyJjwH?;w>-#1bPeOo_q@F1u*^YJuRG_tA|Q2J7;g z9yM@XNv?t{2xth$Q);O{7v?X$^0)iZ)WKdJWcQm^v-+*(JA;t5g|(fMjh+DrT;koy z)BvO?CirK%Rvct%Y~nx+VEljdDH9uzK}kl>-u$-`?ti@0B`o!fL4Pq()a3NdKn4yB zA59G%Oo*8PU>n8W!49NniHzWqeyoY8^!6jh&#Ea^u9>z%7AJsY%0?NXGMu@TCTD=H z8J)&qo<ME2CzPp#RA zyUgazsW}t7h2GVC5fzynXnplSn4_jkwpA+&Si>o;GMPB5*EswX>RP(1tKrYQ31_E$ z$d`osV)ml`_4#o(sp7uje1Ob-*uDolBcaY7K9G~Et}xFXu$8I37yLng4t_KV=M(9U zm?g;Y1}13Im!Q#0wlY6{-qbV0xz*eqM9u;IF>5WR5rv*C?vyD>A`dYtQZiO}xPQ1^ zRwruWLh~lR2m6e{1HOh^Umzc6h&O^L2Pc$~1+2*?V80Q4f$yCUm?a_%8WXi(-KMA<)5Gna_Mr1Huy?v>!rNw` zHr8UGhZ^42|5p9;;IH$)sGN8Jm*j#K_Wfvj zjabjVd_@vtD_F@hVr^_j9Vh+0kNX6V@Ziz=)x3A&+ufi2?+o`d%_tCivuNesE19f1 zX?I`w z?-V6!PnXyH6u5X6Mr^Nj3||wlC&v|Yq_9pxzAHY!EJSO&7G`H@N0Nf>O*FBvH5kG+ z;{aHrX!p7@UR#tsivZ9fTEeES1h_Y-iJ90)Kb|NC9RfcaU82s5P6%)RFZ95~vU1qbqR-@m$tzc)E zH?!*Jm}T!)WK37rwC4seWrT0tP|jZ~cjKWQSg26W#47rtkx6{#ReZS#>G71A*Za&G z<34IUC&O)40e;kJIjD%^qnam5!*4ouFGtJ8Bp{C-kIVLIjDiB}TA!fyzSeB|p2K6G zYhyBIMMbd45{(daO3GbN$y8DJy_M$x+_{JjG=ASM}z|d?#`TF%nGYX66XekLA#>!(hHGdjtXU7#mE6d^!|9oUeLGjFGBBGoe4E6vm0FfK7JLFTAo|rt}0kh!91Wd{FK26e1#S6oJ)jB|x|5 zvcXc_46e821a4iXOHwG%koC&Q z5}B%&VX=``sqZ@VnmE z34Z?5tgi^%3yh6E&HMA`9nT|VC0X%&9?RM=V11>&#-?DM z>q;pAR=6N4@MOWp#sXyd%YFmP<5vsH)?yOEGI}-)f7^*c_#-hR!>{iX2H6|fnc6s5 z+x_OT`lFKxyz8%RetEZ;|6;BEc8DJ}88ra_7J3#|4iO~j zWg|Lfuv-aiRRURlxdy?0IlynH{hQ~Bj*SIK&&~t{FcH&%uU&c$4j>~3F?j01P7eUL zLCnO+3Z!RZWo7|@-HYIU0AKka=HI&MFV^g@b+USvp#Lc|2?sq3Qv(4jV+#utktzV1ft~rORpI6>e@a1oin81;*PGz%p!uy~lnAz6|b|t&7zHE8686Ve;@w%zGRh(!%eEuLR+)xq? z(^DuXp60OG!h|M_Oo6uY^}UB#8*WoiQ)00;h6XYb3zhlzdOpRh_n}q--PfRqET+OA z!}oN;+H-FQt`<^Eakn>lQ$oHxctt zRj7S&N4jSqE8R|w271KSeS6h?fj_aDo(v?Z>rBi{mJ@`!Z?{*p+R2YFpl=t$ut&1I zk51)6t-|J}X>(V$XYGIkQviG4`o}bp47(0xRf|8?fR0HjZFWfS z96HaA{hBV7w?zl=eV1)jES0dJJUlujbR@QB zUQ55_shLPqyXNq)vK_mt*Y3EQ#F#KVHW9p_% zIv=BeuPG=q(Rv)c&+~wxRhc+x;&{(ISxYFY9~v;|lAc;Kbm>3bm5D-(YAr-$@Y+&1 z4K#`ze=MC3P?bH52pC_mT5}eK1PyMhjVbPJLeXt}ZxnLMo!FpTq$bJ@>bAeE#u2Ma zkiEMA_^k=sZV)zSB~6L*#v=p|W|5Tk`)EONpx0tc&CfJj>W>m$^DMSep z@F}I}jgwzCeqRW6!ediJIO0S8tVI(jaFV51-<2Q8>>s<$sqr2j>X2%XUCMl0BVK_5 zMag^<+Pu}=5COzdIEB~8S-$IR$HAGa%{(5(On^wjLMdwWAiK^xbVk%*=N{yY^+2u6 zHww{$Em61qW^Ha%e0Ur6v$UsRg`Rci=;CE&9`M-SU799*vz}Uha%eP44}U$LtSz_A zjBgA5$b-&|3|2(*ruqYgP!?Tr$66zrn9|m9vN`OwfmfaPz`Vh!X^&CvkRE^h`)JAa zDf4OWaK_tf{dpx$OAM)+!m86@?O4!#$q29oRbh zGC?MY*Lv#wTze0sbS$GCz-NiK*}J3X}It=$0=_XzQM6N0@}iK|C}I z-*BobB3x#y;|LN)h?`M7jPvj3y$|HJ{`R;n*S>6pX> z(1DXDJCR}_NtD@w((;5P;6>Y{&#{V>W8K2-r!a}16yxVcM%?4?vLwoQO*Ww03@;9A z1-rH@hy_){?}Z-)wO@U=1R|S>@uT`a@#Y~}1bGWOp5gru8uF`HXT_N1ushU7!%}Vm zk@y2;E|D^o)@9NCjd#%ptuCRM_{EX)k!~|ZpRpBbd-3?X-Hc0uVnj;D zRj4iWLSv-RaM)%R;xszp!ouCdUm#ay1e#!7@_@5z(DpnL&CkJX4Qf??hli1I+iMIO!o|c{gs(sEF^D=*4x~`KXEhjBx!`GVZ+OquXEB>Gj ziB!7T35$ltIlQH08Q5OL4usQFrvA6e#Jobw$wKy>X`Sb99K7CH(53$DR8pLFt*ThjMVuPhdSbSX zZd<*C8Qk8}!HGxxPH+V;J|?c%U3fU#ZF@H!mW#Ceg8xh`!J~&-v-X^0%eeQI9d$o! zn^#GCaMhKzvg<6X&+^dVw^EBkrLPmLRs0gHOVSTCR^bNwKK!AUD$Spzlklw%ONsX^Q+Z%_I}vX>yb%`dOq{Z4dWrzNl&d{g=NqyQe`_ zJoWNEHY#p!Q8TClbFW9T(#jsc7Am`z4oX$97N^&b-;~0FGkraoLp^4@KYbaf|1n6Y#yP?@Y+{UWHw6WF75?`VZor4G63fcHJI7LV#Eg z9AEj}oq~rab>(f&hKM6&>#c%4A+TJnU^YKnKN)#QC)C3-oUl!{dPXxmq3tAsT?g6# z$=$2r;)QeW3#g`pd>4m_>kB--hEqcc_gFPzG5$OYi-(oa1jS)a;2S>ga zv79t|<#DqtDyXL0D`wJLkAqk<$*Nfg+`;qNy&sz#XC9Tm>6`Nwd>ldCg+44Ve*Bby zR^ahdsjb2e{Ez}AT{mlPvDjGk8Tp}c)cePWLxSK(&4#ljJDL4P%frX=(HZ*ms`WMM zF-3dDT`@ksyWNAVAV;T8SE1eUHX2AO0Jxa?k-1g6Viexv z?oAH$v*I1qr~$(BP3gVrg_`kMSfVG&+3uBRhZ3_k z(u=I>?nv1d+{nZ%$M|gfIV`CCnI$|_DscTl8FI`YXNQK(>iUUZv$N3BP0>?tq3wL; zOj$1D?ep=sjO~7(tU}jl+-StAP!DRNeV+aDHf$fOr4AkQnxTYU3&NiF*UMcx=X5o5 zL{wRokIU!Uw^>(DQMK6Z^_wMpK-I7qY9M{_ImOGoC(7q)>e-PJ+^)wpRI1UlA?mdT za84yzPH}M)jXu20T)=O`mLwdrtay;SagnLmO3|t8V9c zY1C@qK{T=!a|D&EN>|Tn+26H@A zff@B0+u^ehI3IhU_{y(YJzm>a>+gb6qc&r!Conz|&=875v)jTw2~09g+*j5|6C4Q3 zr60&cRuoxYa<__}jFa4Fjw*gYG|DOeVBVv@Knx58)j$Em5~{Z?pf76ehx@u*C^Em_ zoIyYGJR`RgC%++;hY7P$APeoWs}XSNu{z7Vm3JrQO`-#ZAJM`0PcVy(Mk8*;*_F{I zxNQZUBf4rm8!^7`ETX0vl!M*C@UBaV8*&fS^$Ig^|yiDJ?|h+-yg;T)W$ZhwTP zb`qS6_U`fwuMAjofUI_fc*#ka9kmC~DaMQS{h;R6Y-)pnpE~u>myfNPmVKoR7x>32 z?S3lndP_^pW-h7^f_e~YB;rGPHnMMV%E)m^47M$qB?^Zm>7#0B^J#4)m@| zg~}>8q05ZaSi4GxYRuGpPGV2EoaS%f+}0Yif?MH^AV0y`2N4Z_M-C@m_PDc~m85^Tyuy zycGURDV7h-;4baRM)7B~qr-h;lEcc;iKlIupil&c{u zSD_xRebguhQpU*=| ztOtKX=03!;aOyJ51@Vhh;%G?YKKGL(_Fk?_kmpaP z5uv|h8bI2CaDF7_)sw~QfZDdOm3-{C(q*gdEf2Ysc%=12E9#W9oR^_h#Hyv7O%$oa z!J^siZ_=$`#~ND2u8^zx3cIA+f#cmHp)Ljd(!#W(gAAkq>e5Le! zo22Fi^!`xuZGpe~N!JOL{WCfK_n)AFSa4#03`I#HPBjF4>XRhYe#V7(WP`4SS3vag zFUb+HBZg>0dU5j>KryVL4;BsSgR`HafQwXBVrhpHJD=;Dh%76`(q5)a-sW4>Uh^)o zzm)$JA5<&Li9~i3Wrp1LL07BlEE4jSc~cZT>9fmvizI%f`L-I@N2p_4*qVmV+r6*X z;s=Dyt1CoezR4dqanEzDV+!;>k5KGL!;oz-Z30j4qt~Fsd|W%2e&k4J;7w0x_=ul-%|)iQ&+MtO3(^E{<#|aC_S*_(|Wh1&sfzp4dK-% z4v42v@#Xh$r@fT#?as*gaRv{PcrySd$cCYC6#>gdB#~yV_8_@K;*F#Ki1+T1*y7V0c#GniHP~rhPYBmHx8s?Jw*v0DO+xOK zIqX7?&bM|Ak+|r*v*TX! z)JwDPyumd^{wBuZQN0;pbd!Vnas;ZK<*MQQtX;CLqrfFW-er>GQ5T(k1>o!)hfK>; zIE)eEAw3>R%*Yox%fWd+hLVWZa~F4Zycp|p8BY_uF=l8j$&r2fDDMReHgUV{AHA~YP0amD#S`xwxP9Pa*|?b=%x18B~3MD3{`*3+Y_Dk zdr$1VRLs{iG}%6@-_-PCuksm}2@9#eudG`QGk&P4U}HR}6c}h_5@9P;qZwRkcGk2$ zrnJTn&Mux*wTMv%P`Wxp6;pbAgrLJqZ%NY#Q;Jjk-m<>8tW{6rUwSZ2eJJeu7VDVV z)WpsdUlM6a#QV6`k_u(6e%{67l!Ty3r@Rwqysr2+e)bd zlIcw6Jde}eAeEmI$ka+DkY2vh>xGN`x_HFRfjFPceteC=^JNkwtWwhMOUh^Ge~Nf! z;Jv6kbA4=obbo$1*L(f4UN`+5f02Kf^*>)PWl>j-kfZjwtmk4r;Y`uKl*!~tumS#o zvxi5>2xpUG2M5)aKC=y@Vp|2P1D}ZAst#(eD3#-XN1i#%R3ztEA7K_kEW(0Jq^!Vn zsG${~o38Os3W}daZpK*}Jw|a1lkXKwv8h8DrqlT7uxagB&aKoG1nbc!0{XCti5Ylv zZq%iIMx5pJAzrQuXF!a8*0=F`K-=gd1eRHPBio(i{dd(a|TD`mRh5z+f)g>n4OFgbNh`v}GCq8INCv?M$%<*X@@n~20iBfzt2&g~E90E? zoHJU$>Z^Gjv^Fn3zWY=H4^YN>>v{4psqB0Aq8`|VEIdUPJRPhbW|i?cZ#FCqPeND? z<5Jxw$vPCB;*trgSUINsqbQN}RV2?8#ZCKl8bMc%OWx6wqUEVONT`l`<820gw_iW! zAg@H=_4GL&Ir#ax6399S1;1K7IUJn2@nU(%;#2V-!VVK<2+e9KJ|B{Zn%%7Q7C}ya z_&63A8atRpO>?$a=XFY_RjW<%xT zA;0v8alWd;ucoCAbg6KqcktAFoej-at)%(&dJRj3B%f}?z9xPt=5?Lr%@q-baUeuh zLT=nyt`>N|AiiMv6<%(G?ii7`={%?ij$p0ra4T~mkHx;PCU6NZW07ZfW#C)Hhb9B# znjL5410Xw}>2u}BkJlN=?rv4xKZT5zzgaw-7AcBJe-*2s8Fx-aWkT1LG6gx}ugEvh z2Np2CG#_jhw!QS)L4mr4H()~ra+H-d6*8hHy~}0~k)QfCPu|l~1KRXliWdWAk!Pqm z{R5qYQ9+2PL`U;eElqMK@Cd7(OX9^XT8c5Vb;jeRaAl#laUZ0!bknMTs~B%@lDR)%qPwGJZQEi|bw7=I2(oNHSNVqpleeaJgan zrWKTHsyXvA*B%mCtg}$+rI`~Wy$BK&u&CGGQBIPnAA-6T*QhVt8EIL3bJ{uP z;85RW8R309l{b>P*_Q@AlgDkZYxK$J=k##+o)1T!{kc7yk&z5;R-*Zu+8jwrldFL} zd8+Ni@dlTpN`~Vk>f)!Fd4e?K!j!uvQ{0rdlXfR8_Pz5$qUL&Q`Mc742^m~K1}}?6 z;kVXCJ3G7E(nnlC9((;yMu8k4eNm&zl&lQX>-6|U6g|EW=9g4a3n$O#e0nCPsY01B z**Xo8-7TY@@Hx5*{rl_vnQt%ItCkb7pA}GKa&hCsJVtXZ2KyrW6lfc|`tp~~0Pt6v zRBxRLelnA=Ow1{3v5eahuM&Yh@&~3^GM#RwCbm~`?Sn$) zHy7j9D56UCA-&QYC2t)oQq_yfR!tt-FU!k6j?g0a_tgQ0spH7ij(-YiqePU{4DOZv ztn`eHJclu%U7A!S`b-d(Nv=Wj(V#SiMy5FBrl-zfTDl$(>jPAhAFW<2ZZg!wJAS=V zl#|i+?LLEY`jNu2TjPGTFHQT$CKF)fUN|qS{XSImL2H-`j-_hVn8@s2|DBtH^?{t9 zjivdG#0xYk*a-adV2s~IA^ytg({ zB}BHv4_x0e{l7rsra2D{yj!c85w;1dG4Py^gHp2AU3YfoNb!7;tsZj2qpuL{BEW(3 zB{GQ&8*LODDP`(xtu4Q6*Hgn4DQqp+{{YRF zu7}}7&;_Rr4F4?O#WXF8GXOv_Q#0=meBGICE}hXndfF9P*JE_Quk|d1FILyngC!`j z)Q^BmggqDMK@yJvg{dw3>UiHOzTuu>5)`S2idp^xXNdS6UjTLklp< zdEbPh;hHOa;?pM$DIw8$4mq@OvGfn}96gPvZpJ^pn_c_P(>66wz$hpF$QT4{(gBI( z(~P2)cs>5SxUpafG)lb3+`LF0XV^eEIj(*k5bG;mR!cbIGsS6`V0YCPDizoDPRJ|v zI|7(6qvnF!#%k{DdOL{n6>TmEBKu}j6r$oC2bAa~5oD~g_H09cA@u9MR0qX5yjNFI znV6P1xcw;y$m1-!w?Hyw>#t(4tgCHmcw7aDzUA1ZG}Jy{^)CfoJGG3et%S%MDBXnR zh#U;l>;m7LX}U0nE>8FxPRkU@yx5g#!ocspcqw(@OK+0F5WiD;qP7-|Z^J*-sd76k zaYAd2P$=!uWlAeqdue!AuuarTjNBtAwUdZQ=b=@vHSsoeEuKbW{)lQ9-iyI=vDXk8 zJN`>I+-}CI5$wC|Ra*Eju^tJfy^;badyVvOHp@>(csJOvHbW^*R*p*K79Zg%#5Epv zIU=uO@;Irv*?IRI4Cg)8Rn}F}P_)@4A^|I@*lW^dagw$xJv9o zfvnO=%P%$aH4cE-j%}7A>4hj>nm9A;ZkEFf$q2=D3-}MgpM5xe8l%jInt^$#R&bgX zftjKckv~QyoSg4q!U0pW!UC-dM;)qj)vg7!HnC8pbnIQ|HIqhKq~s|0F~Ky4Rs7v) zB~GLppQlIt$-eD73eko*2rEQsYr@WEB0g{@mf(acA7Z3qi9e8}GA9?$`dQ}1*a{uDd#^HOMOroHkT|9NoE>-c zRFt61ZUcM08Iw!z-af!cuYA#yt54MA{-R>i#W04&#| zgJ;9D)BVq>hpVKe4{6WU+&ns~HT$GrJh@t1G%_lytW=MF=sE$6k=MM{2QchTSKkY7 z!Qhh~#hG_TS`}ZMRRId2M;M02hER`o*^c^VaMvIOk@-1$TJt_+TkH!%$-Q@V`_kqr zNB&{CYK;-s-|9Z@S>!8V{kxTLtOYqG`~~X%Epq>lBK=QbKH2{g6!~uw=|4vXX~X`PGN0_f3-SJ=2>9D$T6 z!mcMrm{?m&O)u6_Jw}jZ3N)Y`j+$7Uae|5twDwnPPDdhZ z!D%Bu(I8H_G@`2^HhzMS(Jf7~`rtm4!z8fRbH&YpL%k9qkjaA8_AoWDkYXvx`sEbE zze?5T_$tDZSFU0A-fEZ)DVuOpK!Fi9W9)J{ImrkDE7wAk%4_wT>mjQb+PgYP^62+= z@5Nx_Ov&a&*NFR@bYO?7JTW0nu1>f&$jrI!X4H_@?rcV38L&bl#cc!0nDe!z9f&1^ zM}^_@*~y#H3&cZ+o8Kgezusq_4zY+*wgY@?mh|M|{TvDtC=&lsi!qMPmsRR9AI&n; zB(5~yZLuX5+KiPaHfDy*F+F4kaz^WUnR&fWZEHn?4-H&pEEM#rHLy>HDNkK_=mHuJ zp%C*=hf9v%TO|L3(~%|PFcEG#~BT$=(U6YxG zot_QI!OB9+!U3e`U}FXXwV4^gx!{ReS;5Q<2M04V_!CVafP)_Ji=YAT&kAIxX9utW zf4%>$Js=p6VPaus*JfqX1hN6?*;v_rv)>qrfh+)U>#Sf72*|9-%E1nXZ~&~}1rAMC z7BKkpYvFg_^9u%IVga%-gV%vS{dI_7KnM&5F*30NiCI{{X?R!xz+cJ?OuEpsGqW?X z5HmA_kCK@QjO;KH1K7c!5#SfT^Y^vv>_B>E7DfOYcpnZhdGw3(VFiK{`~1R-e)rwr zQwDQD0A}!^6SFb`=~;d|K^A5vaE2i;$n?9t0qkH%2#hhY5VL`K9`I+s!At-)R(eJb zaHsqgVES7Z{}EvNO=y3kod10Q6M+5~sq_bYiG_{+msG)6&_CjrIDSp$6@O!ze$Oxc z8zgY>d*>Ge2RJao2*T2ZgbUmnF*c?o z$Oy+J3gqLrFgR;gZcgsnDi1#`Z7toLxjlNmG~Kv-s=B!Xuk&aft(tpq!e$~Z6;KkF zAN&!Ma@SCV8bT2|NKyK9@PkQ2^c>&rgTmDPR~irT=kb`hs_r)N_-XIpV}evJtNxkm zlD?2dTGG&Pg2apzl|)-g_?w?F8Yo@D8^epNKCGO#*^GZtb(th?Zh(`2o*T)eW!4^+Ey&N^ue(SRzQ-V{^ zsS`@Md8P7x-i$H}`)Gkiyg;f)EBPm}7HNC*Y%1_DerE^|WVU z%sJ9_ttTLHEN8(Tw@DbdLRO^228>%gcPplPNZAP!4()vE@rLh*go7mX!S?R+cJo>1 z2QEp+Eohn1pA2&J%(c{DNiAHFUD_hhMHme;ZTk}Q#TMIx zI!Fn=j?{+ed1v`bgBK@5R-E9JqG6_OD%$Zr9(D8s-JIAI=%{#nNQ;6Zy$ znrka+tMjuxf%bkjx4=`!NAj%&N;v*is`i!~gl z(KxyFM_IfA<8e+8n2Kp%O4;47RWuL_mnGTzm(|1PPr(;x_t?|?d_Kma5A?;31dgV0 z&qx)~+U|Vp8~f2tA+tkK#W@xtjs%<;!G3=602|Qby zrx|t1I*(=xVt27!A*}F1KsU>gkmYEkPf=6S^UidPxIj^Qx;1`>9tb>hqD3lfUxrg3 z_iJjqF=mceU(%uQEAo#ws4E;Ub4^-dXJ(moAH;Ivl9$MZA^AWz{n2<4XV`|h-Tg>Zih%rvj_$WJ zeKQ^jnxxCdPP z_7*H&PQcXE{RlvfPf#g3Dm3OqwEynwjqD;)T4U11p6fyuCk#doJ%@W;hvpY`soavf za4{r!1-$caxar!7BMQ8rWGhs+LgKzJb05|D+sv!vvMmatyvZa{O$459QTy}w#>svN zNc8*p-@fmcjSey49iPoSK`e)|i!S>%z#bagI8hPZlyVe&>kb99S9m*rOmusI-h}q( zm|c*~agIYb?(!kCDr3;*3}lcEN1gFM?a_dvuu&3ja)osPm_ic4|B6bu0 z7-1f85n@;y!ZVku|3gh}vM8s9qL7$z%X{dPK96&haOh~Z17au5agS3S)<%ss-wSc( z`Zwv$MUkHYbTja&H?j+u0a|VD==QGkm|*R?qMDHVCP7xED#sdau@3rh=Ee!Rl=MA(9YhTLwvfnKTi9N)C(XF3-2%*<^SRgyPX?P@RVToc?5nwE|9 zripK)}xf zI(eu}c2pTSqtHJ?Xz*=I8i2tIZsFsPgeCH8kLX+$4xflCb|jH&d&GOL4a{GSHcR!) zbMSy^Lk2%^OFtN^|3B=#1#Dbfx-@Ern3*Yd%*;$NGcz+YbBr-_%*@P8F*7qWGqe5s z%*?$vbKjZy&yz;)&5_1-OV;kzR`;%6Yp+$`S5-k#EC8i^#U%XNa?>X@<-oJfsK@KxsTUVC<0@q2?G%9=Y`Y)mqZ}0c91D3XW}i@33|v$P z%*Qr6HJgcpI&YyC?0{S!XEIc3eSuQsDyr^wBzsbvW#HF#$M2_~(9cxo^9Ef7_GH$3 z_B712K4LhOuR?r;YAZX6Rq!rxlX&RBdYv?zJ@$oFL~e456=j(qHU!VhI8rcrhE3+e z`S8pa^e%N%NV#h`WUMh3T7RmTxym{qcK{bmxeLU3Yf!k|DW*~4)>|4q8&&kyNGs-6 zyv@spE+$FadLHo~s`~zV4D`si8$G0>{p=;wt_kRNs%`1 z$o)lzt?g4pB4;U}6A<3F1k9iGir^z|m0-_BOiG@#<~>zng(Dfo6kdgHvKV4CUJ41_ zfvP2O5}%3#AG5X$BP!DBC+A_>pQ4x{p9hGv$=$MbxO*DrI)oXv0q!o(hvUYT)+5Q* zX-`Ai5{9t$RBpEpIuyqZ?p6=VM!5n)OzWIGy+lvrFUnu{n3&+q?pBY|4j$uaik*|q zi(m20{M??>q#7fr9~CdX9Gylv)|^pjtTJhO(7$mpTP3@Di*{G-_|o4Mx1rDb8fQkFwMMm&SFb;dAy+&cW7oa^my_&yvy}0dxN$* zrC*!6&yFcb@5sz(vOWTrS_AdG_0RY!E9mZV&7?ikUM!}c-tAu34?FhHr82YTTVPjD zgtivXe72*=sA9xm3{U%Z(mLVd)JhR<*nf}R-WPZ#(7#M zzNTD#Qv2*=rcf+6?OJp$seZ?2S92eR(ej<=`Wf#*9JKDZsDoLlIJ%g5?6zNCkm_b1 zzwU?PHg1L1Z{nq*)a?S4D)V{V(bF`ey=Sm?#Iky8l!{$a=c}C(3(3Pi@9LAl6~dzB3ExJnOE1|r@T83sm0@`XRg_8 z=Sp|oI_^2<=QF}P>^0qwSc1~qnRGz+dAV7JtTtc_Up6@?N3p8XJVC+> z{kjFUC__9vcI5@x5x2dwZ5O{nD!vQ*SoI=@o6un@VQ+>&N15+A5|*f~Pu=_Cc-yzi(VvTo>MkCNJ>wPbsQ$yCoWV})xEGgrGZecR<5GlN-;Rg^P~T$ zDywR<%28imFQvyR90xsR^}^5o<=(kMtYTdG>{@l%T*Q+1XdnO9$Sw443h*hIItnh$ zn>ExpTvdK92*#k>qDZ+$8UGeVYx##8TrM|sQ4#;qVbl{@l}ss0o?g%cFSh>-(Y9eo ztN2~ig7Sdyu0)fXRSfQ9;EMq6kM-eort*MZ8HtueGP)9d>OPIY83PauDZ;Mr%+NUm zxmHFiN(8rR`fZn=bJwg+Ne9O5vU$mwz1`F=j6Kel{@C5Ojlsj|+}dwDe`%7fzwiZz!~LXRpCq!3llgsNMSnVy znw|MBiTprwL3i=WQ`QIfx_!cd z`ex1TL7&l8aMl07$eosdb?HH!(Z7EU>Or6_ut0cS@W|jnr`?s2cgW~Rvpf7?*X~=f zQ*vPI=4-u0bCvKg?7`q2U^GQ}wwJfk-Eg5?Md2Nnp1bG)G`h)if%HQ39{t`UJt_ZU z?3Mi9HGWa^g3U8dGog{(|Dj)c{Nk1L-sipVJ>jAD^L@wrlH!G&W_!0b3N=^<;dAO| z3I9+C?r7;Ph6l4r0iy2$(L}xiFtYOgpXs#`B4gD#35-Hi6~u7qq({)8OrW+b5ZcJo zQO75gsuH!3#19-VOI1SLYQpNLVXHJs;VF8_t1w+n!d1judaw1k+DPUIx=-`&P4PT= zpAWxQedErK?1j9f$3aY~>UIZJEm3eeV0cPxhpz~U)uZqv)5_`Ia;yq(M_fKMe+rDi z?`oK6*n+8&KS6v)u?}hIS-!!+K{@~Ke8~99Z+uX?0He(zjn?CSL!p@~?x1>-wcew3 z$^A-wH;FfZz!UNs777>5&cmPnB7m(EV=5th_8^L_2m70TN#R4kG?J}qsT4GeQqW7Y zRm$r3;sDhW&lD}M0wiuAN|}^5(7(fIP-a9K&-9yOY0kIKz_c_zmD>0_)Rr=v5^8AZ z7Gm`|k{$i=*jYT%E|IP33$d5+ebuun++6G}fBkv)n;-Tosk;x?z|@zosM~TPWK2ah z(1B@fsrbi(PbUO(kz6BBge9YTz&n!F{<~Ek%<){r#=|6wdTfDZjk1=dnXR&xRthOt zvwK2yO|q769ZD%WyRl48OJk49yS#E^YLEoXGq{5Q3Ls)Sb)Z_%Ar`*uf{f@ci$Hkb z%^1AQggfv%cG>p|*gj`fbSMi@9=?zLd~hlo+k;Q@Z8Ws$P)}cM&|RP(K0TmbOZ$0! zG-2ff_xr>uS>(v6$(X-^r1rONUHXQT_-KDyr;8jB^9Jw+VzAW2ceZ0GoCl*P&*H9< z8LOd1l__G7Ngyvs6b7w>+7n>)8f zhG+^|1#|fMGM?!S;H-zsu8Z@ng$|Bwfs2=AgfOM%j8}T(D{f$Fzni`nfeD@tz#ah{ z7KA}p?gda_>OeJ}5>mH0XoPQ5@GfNrxu%H#2X6BQ=D_A>xl;Q9*GT4;qqRZn@+$)IYm$+~>6<-X^& z_z`Mu`$HK@zGpQ$Poy3}-sX>F9R}Z+7u3CX&kND`Rq!ADAZmGOd;`^F-l(=HN#9W~ z*yy^iY$PnP=EeLM%jqxCwQzb|mBI;s4G8KgI(Cm0MK}b+_ZEMw@-tVnIZVfYWSRl0iX(~F;hUEpNatw z&_G_4yWXn7_IQ9{>hUw}G4%NG=LeEeWkN+hK6R5AJ5?rkG;~eoRf2$56hfl+>QjK9 z?~pP5kndDZDQMyPG6By3J8GPip(a$JHPNxEjH}EXxE__J_(Q&h&aU9%gfDN$=jb4V z>UcuK5YU;gF#}xHY zUcnA~T}eTaj}Jwl#!(rPK#`vhjiJU_?rQ#gRiggEMG3KEyEyH;0Jk&@B!72e$>#yF z)DI+I{|Xls;rb9JkRAo6tF_pa0lLd^r3(dg%Xin1`6BvRSZqgV4*6*PPY24& z6-Ayv;`3Qrq^IqXW^Dk;u1b-CNKd8MMUk1`Drx{&ViBH=_w(JCt5|`R;cz9G=aAiZz!%Qnth7Go8y59u^hoiYRUU!EQ6K(?hopx}S}sS5?o9IL%3Q}tX2gEGAiFmP#v zO~Jz*@f>eC*&)8`Jft-=KI3+PmwQDpW5=K*V^3tp?uREb!*f{U5NX4bb(GylIgrA8 z2|H>!D@rxuE3h^P-+{T6&C#!g%9>d^HUl61kJA*KT29J^Bo<9qLB^k zDV%Q=A&Lr&J>+rtDktTFCQ1O`Y1P#0R!q$K@Eg$6 zKAuUFHTae_haO8sdjrs?1~n8J?ud%+F~bW(H&c${W!7rK*Bf*h1A3Eb5T~Ydp$gnI zF7pPq&a|Q5M_rO(V~UEtwi#0S^8!|x3JRL37sdSBW?H!mlz*LuC@T8Vcc^;j+lITq zsudt$ysBnU-;Vx3HJ$I_DhC`&xAxy77n)HOq>-@nzkNGjAV!^m<*F|M4Sd1onDAX{ z>o)>Cs6aOp=!T=D-FdgaNV5+CpIKaAugi3LRi^VsfgR5Tt{4aUs_{5MSj5HUJ}(Km zy7G-{>O(yh@Ox)l17knB$nOUTm1#Bq0ih zif%U4>?ocW=>1V$alC=9n0qqo3WRaO z6)R<`yOsXSn4+{~Pt%sh25pXfHV18%`uWY6&Lk+RAL2@bla#}}hz$!Mq!g)Tj}hjV zw&@0EUUJMN9i8h+68hGGVRx{m9dKcByb|lyR_|)*9Dt6Q)nCR84%E1(=|UE6O=~Z5#XfaBU=f zZ42@>`M_bScNdM_s#yiXtQ1!gvOzC4%uCbl)O%os-3E>#<)KjbC12CoM-+pUXF3aD zS?24~(aZkwcM2Kasqad6q!2z<(mhJo=<4&^tE7K>)#V&)_vlUxXi1%)$lsK-_s>7K45%-8w~@bEDtUh{Tv|_4d~+Ih zc`W2Ct(!*OJpZl*<^6i2_gb41uV24iy=}*P?c)gO4dw(f0=I(HNOI7(|G$6VFZ*9Y z0Nhz8(YbPY`_V-@k;Poob&OS19xTsv3Q}MTbF6TINA(8)?d10zSftC9hxC^W6G{A$ ziWjN73E4J9BaIM(1c4;BVA;1I>xubGAW)yxD;J!0Mr=dO{e;(g?4W9H^&nTs$DgY?9rrQIcfxVC$ zVse&=b(r6DOJI;o&S$b-ELF?yaEOj(OhEMzwjqH8yOsV(w@D2>(- zY>&&Iw57ZqjP}qu6IgA{kgqxqd-%F6NuUtf?B;v4ZV+%4%OSZFpXF{hD;E_K`BWX4A>*8_jt}*t_9i5ErMn1M13Pk;Ec&?AGn6C9X!&&}i9^~Hcc@iR(aBY`-dJ;E1Tl`8q3ko=NGc7u zR&`nkfr{P59of}AR$e~|yCsAn?0>&pps9S4GEdS z8ToP?w_78Q1Xk{9wmDbjiYMv*{$ZNGw%OW>XU*m;>^5l6k%95fx0zM;mD=jI9w73F zqY!^VxnRaSDr3{14A^vx+&7krRo`}Gw(E=E5SqkJ_pno_=F<0%bjo{ZI!BICXQ6h; z$K&ZVTw8gGfR|1crUy(s2&W%`%D3Ox6+L(pY^yF?WkdHi;gy8?ZIvnELgl0;=q1}# z`=76in7l^~7(9=qYbMl?Vp@mqUhJ+`8=Qq}xOlX*x~*L8=Q${KEgxl-4!BO*j>xXP z>ODDJR=^(5{a=_WI~X4)J0s7GrM3jfpXVp?s)fQ0r0rntY{(S#6xhXG^W;}mF=Ya* z{cYl4Y;#}u5Y(83Mo6F2tamtuSm35t*ml=_BBf{V^NmthZ+M6hrf20AJ-7SKtti%r z`TLDCw`DlzX9@MKm{(^$kl!u?OD~nx#CC=;HWg4rI8xeVi}|{U45rCKYv5Ab9oA7v z%J9~;lSIfkJ`aV5$2n?zdX1~nFI4?w{KT+myy6nqYkm;> zMCp8gZCJc@cg+u?ACq|fXkBW}2cC&68O+^mwmj#deAmI8d7Ze#t6frardFEY1~J=W zD^7!JN21&URvISe$0sp!MTV~$i6u#leng+NmPf*H(RfZq6MwcpB^@4%shrhTcPum- zayTcrW$eEW&zqc`-;cj-{kSUl`k-}xl9!@W(01C7 zdoqXlR`V8Ag#{O>#+uKTreyoVRVPxBY8yTCxJr|y$7C3p=i-c}`n-#2uV*J5vSIpm z>@_aAQhPNtH?@Or_&h+VV7XT@s;+9AV8}fF- zG{F1@4)GichGK^_HTeMJP*f$1?-8LaFhHl*{=rx{0cxG)E937&Jgm#t^1Qk~0|(9P zEe_d8yf2o#N-yKVO1!;aY7$6jcwS9cNDAW0?K}4i^2?7uQ=8A1RA{L!AEHjwrN1-? zmDId6ph#$j0?5x37nL87=W%7T*@-dEV9$#vvk|i+l1o9!BktgOKc{q6J*sU^vPea! zcRVZy;k_AMLbb|bm|xN3*#zvB=?8~lXQX;3#Cy6aU9O?Edc)!fPmji(LNaQE-18Q+ z)ZbJ0V=Vr=`dWp3inOymNX<=H(ka*eqCF_6D!_xnI>vcQ6m;|f~S%^Jb>e;s-R4{ zSpdfsubBKoCTKQBwEzbtoSfkC)(K6 z_9QJRu~-Ptd)50QP^RgF&et^8lF!rLXJYk-jt`A2WjmBj!;?uTY8vhj2$*J{nx{v} z@Av0TK81Yvo!(X}RIFf^xKX^o(1%h{r^ilk(N($oT8vtSN=lu@#Tnd2i-E6i-*(Q_ z$N@5t3yZFL7aJLQDw#oS0XmgPfOEP5RBT`r(+0qaf5i*+GVd+j+7ezE>Rm%UnbJ5* zKEo-MU!;nx?p;&bl}>6c^!Ap2Z&a*HpnYpf@DZ82-;{W*7tV-ypetO+Y0{(c7(?zI zf34$FXi&RJA(3SbzRKv?AQFNc1X2vYJRp{xRA@S`C=mz`T!guX*GD_h4HePRn)d>|=s^9@;?>Bm!@E>x*^g2Qwmb4n)A{Q2t%0ZN78#fVxm_ct@6vy14LY{4}5ni)UINmM3IGA_36)M-7JtG`P)uj&anz42uzcFj-usI-wi_KP;8$9_czcUbzxC86@Y zI@dn^Iq#q(_py9CN!Q8A>+M6bo<^_s$k0h^Jv~$jeW-W&$gI1(f)NV*q#{L)YVu=M z+Il!fNFUz3z9wtXJ9P7*p@nw?! z*1{Eg^{u#dK%#9zcyk^0xwQx(*SE`X@-=Ni$6H&ub&LIvp{R`vQatry78}J(aIgzh za$`4O7~i5Dsmr}pu3Z+cKe~;T>6H|Y#T=b4E-)8UHzOtI=v~vGBPW%Sj&Xm3F>O58Ja4=o zhHJPRZ?cZz)!@WqrkY=1l&5BNM*VsvxIxtAy>))MI`Wbp5JOkk3g{T5uxQvRx}pod zvPu5UKToJPAW2f7mdu~rO!wrQe*f74?zF7<85_6vxz?%IIgQ^?>~lUi%%_xRA|A%? zf@ItYKVk9kQPXCok&scfItxrs$x9!l`E3!^YSgsuWkd?i+YG^Wqf22pq>Y{7r9fSCq$bZQZ0PFp z8Cf-md>8%6TT8A!X^IdMDFhpvq_|m^gx#g`dT>tcvW~UIg@d@o#naPb%n2k{OSP;W zMYyE7O88W7s$SnI5xy~d;e=#0&78)W9b;L1(6y82R(>f{=vBt{GZ2{AbcPfYCPnWO z(VSy;xzwpIf>=_uJ52FtyaJ&NPBs^@{*y)^6XrmmlTPk2cm-0Ymy9s4`Q_|i5evOvj+Ep7U$N#s}3 zU?-&)?@Oz^>7x!K#SY!vH_9nohT_prCv*kLr9HS%BQ#b0i24m&bEN5Q){%}Q88!W| zM?W3iu|+yxsNFUEKD*MmV@q6meCLAA^75$XDi`&9Aag&-)tQ{b4U&yISfZox*5DhP z&=nM_iOZJ^r*?JyYF`uHA`Bx%e>O16d66s4Cia1-6T_i?KTEP;ru# zW6uCpETM?W6QwDW7|Swb@?(aPsVrQLd$c)K<#8^RpKzL#d|+eT5E;-)Xv46Pc=1RlR4GZP+{4+i+wncNq&4M6p(%E z61mV62FXYAwAuFHPE=CsLukOXQdiVJkPu+LE1J?uFyPu90fheXyL zm9R+*CzaI*|EYlsQ}d(kYfBFyzX?B@jYph>&g(t`RMvKiWZ5dVQ}Z+Smc$ zLE?8kWR9wr&vCL6%}y9}(?>U{RZ~4j?(pahVB|2s_WP~5zbIM$uxgv_52YD=w4?rA zlFZD9YI|D<{w-a*>O-}?a5B;^4nYR_n`k>!p-55D79M^Ufps8l#(RA+p=Yg!d7h&F zb5(9p7}kKlm&q@l&<~fRf9H(K?&ax+nA#(u(-- z(Yv{CUNq5?kD*A)H!K$g@(xPA`mCo8H&dwmD{o&QSY0x(UbW$s5b*=Mn z0`!$A>E`vVDIYG*JA+r_gNt?|kA0zDdBB9r%%RNm9>j-;0TVH}^vPE@_542Q)aPzgG+i<}6D7OLpR00q~1@H&C0+Yba8sOMq1o-4W(9Ol#co7YK z#HLoeYXwwavaA?|+T0dU&1X@SRs7_g0~kOeJVOAWVv@9CSH(o5R<6IN+7?jEE&r8n zdal26MG&Rznt#pJQ-ZldoWYaB%=B1at>IiQdoGVtd%)h^{jL4QY8~i%y5EIC%dTRH zXU?Nc7yL)#CZQ-H{?d+L_Y1%GHVXkw$8p08p@%ZbLd zk&aUB#k=N=xcBjW9AL{g40h!fO z6gz=}lGqiZso4pWL04Ujgu&r9`?Noj(g3EIZ#5+@oZKwDz^Hk0L8amoIVT1~zfM4_ z4dI0>zoKfNX2+M1S0LnKb@wBcE1WA@2RVFhVhXJKV$CfG4guX2wB*0GsRR$~V#S%x&17osMW z{JTol7@3fAfDv@W{$s98%oOjy1?LZvRiA@-2qM}=neR>+CKX|!d1|sihuOT7yDGAF z!LFY9Dva^;q|p=@E4eLki<367rY(g_o1(~RYc-q=comkn*i;9ZOG&`v7#B-{p*gSA z79xe@=}}393ASXsf!IyTZq#%d>~rO4GQN*RkjM z`L#>0k3Dzt3i`a^&2+%Jy4=CZT^SF0&uLNu;2%%DG=u;h7+fgY(C_ylMh# zXG`OQcERyrOyS_Pi=p^aJruF z4w39o)zm1%U39=u=h0kQDW_p>xHosQqvz4ATE8 zd)3A`DA>gi2=ni6s5$@3Tukf#g^zZdM|4&)}zo`bC?HAGE-$VFsuK}l{{Y|d)FB_A8)zAEw z0PBAP_`fyaf6M({>G7*qQv)HOg79j?`fm-m(j>VPYZ^vfF|03|zpV^XvB2PwJ4u@~ zGSY1=ETekw-Ib4UBT|as;D~P^y1a2ItADakznP1cHG;l>1SQt~v_@#tO*c`0HDiE% zM`|yj_L_=*sP|#VBJqT<4@B?o&$6od&1EMYCDZ$*mHp|p<>>DFtlCrf zea=PKSWSX$f+Vm3Dvyfn|Hp7k7F?k&Xh`X{`3dCG)m-VHX0)pDhDNXmab66TPpJn z-x#Ty*ts4^^2$c8SA(HoAzAFw)NdqqD_9y^Bb+oHcV{)+csTq;(9fGLMiVI{;k>?7 zpcpTCQB7$$Qn)`%R1%H8&*dSWegz8a?3Dv`4KVUq%Cs%(m|nx{9Yd3tbGSCrnBGA{ zd2_8|x<+BMZN1>h@%en*cdb@>3BUW;UkP?rl-R&XA8A~)1At_>Ba-@u{A0?PTuzk? zYucr0xDB8355d!e4=-vI&24YGX4%>-M{0etp5^tXwt_>(F#r=7n*#qE+~xZUoV}Sr zd$&%Ar+z6551@C0P^MTO-PrRunG=QHpc_uC{!2$7N_ppXBo?1`<(s5i9d8cBsbo zigyv^o|Pu^n9VyzmD;$iS5wrimC>1d2?Ge=^exV<+D!WMXZDvXg55JMU&%bYI>zv8 z4hix`f-D`h;7rm{fm3IPE;zwz@O`>t$yR2NA?h4_?P85>F(5e$ow#!~)mBo|Q+|ef z+J*eU>UM?Bwm_Ny9Vg)xyNLTKDb@#j6+bhtvl8yU_0#;6HU$eYq;D?}64YDR8%hTqiU1SBw9%_ZM-)%EWHjT; z8t51%Vd7xP_7P^D-)El4SmLk9RBcHrm9|7(gIr(t1tx;~AwQLQigBB7N@84rjUkH< z4OLnSEp3>U2S5{B6s4)036Q5DtJjIA*sDK7e2+oG^`-jMwW`}QTVs8Oqg6y z&Fb`C|62h=G5I2UwZW{qdzn;?TUhc4O$(se<9HESt`_j1^{gW+d z_#k7IVjxZXHGP2U2~{mT5}niuti2{mB;9lb`n(kN?Wj3{9n^^YeRHdhZR7(l!Bz#3 zWm64j#*9W#4!G(mT-)?hI<0d33HQq(YC_U&gXTqAd8VWSb?s3Q)Ji9<*T64&MS3;{ zxtj^mI>h9-qIo1q5f15fATzN;j2c>fotIVisiXy^dO$fz6xtNT+yo)2l6xFg8rx~o zG9L4Em!iuR6}4e$yXK{bsmOKZD8*(Yxd%1*rZ{JqIo3Z04~dP;R<`e%Y}47p-39cX zr}@O?)>Q5Ip(=pCVS#s+Rr4v_Cf=d3 zT@edmO{z@jEc=WrN`evzrH~s;D@l%9=$m+=%T)`Z@ignfb}BLI>ryyY88!1l`+|W| z^vzOQOwzS;b8SA5g4wx9*wSbMr}efCV}yjHym*u0q|#FH2kbK05i=x?$;Bfq6;p<& zSR`{JmoWj>ut*tt2yg0r2#)&%*Y?J*(pDw$KrDIR@QrlzBy47wro$R!lS&-uIZHpr z>*~hd#Y#_Kp}N;`HQJcIYb+I-Q{EWUMBHZfz*&0CkJ{fxYb4Nx8UX@Fn|eM8a#xI5@`{=NMe9qm8lNB#u1 zhjeuRN{>8-{~JFt`l*W+-v9g=*?z{)mW8a0O9`G2nTCxFx2G>gj%bGG;!u(?C@JkR z(9l7rG{<8GtRE>SyeMb`M)yRoD#4(r?^@I~#X`cVATQ6A;py53^dw#d1%&~MU2jCp zFxTJGv>NU#kjz3_O+hi`2K%xzU;`|JBuA0T)z!4un>?OgFxvLo;&nSn`A0htGynw@ z#s2R@`VaY%KLh1O_pfx#WBBKc$-k@Z;a|;V{>Fa%*(k3Mi=2NQ<;CznphyWd-xo89Lf-71cbY?-1*tXe&1IEic2ttgm+2TzQa zB}aAWTSl2@s_Bweb==Kd6GyDdEbE{pj96yJ%#dRjPivbny9}HNandki7pWX}*a?Yi zQuZN4;pF8}xOp(2uM98`4|z}(EtzivDq&14jRAJgF(bvV4VR9xq8IC4bqx>CfzftVzwx${ z=Lhibt~jBjL>9;^iZ(A$(O${*7CSwSBnTP7VdpuF1a<{r!3h~C`=9aWRYdmJ+2t-B zi|0%&gXfU$|H$|}RdOQtJR6|-%_FIo`B^GITrW4c$WSQiVx!;8{65GI#Z%}Kv1BH_ zC@xGkt1Ihs;BGF8lFC^)lB1^yYtEpH=wk_5zn&bHK1Pwg**Do_UFke@R&l0XRBVQw@1j7!?yJZo>Y-+4uRo`lHwJAkmppA2V zi$I0Q0zI8SLxLOrXlZS+Iy$@D$A4c(24<+24a@C9I@GB5=!^vH#%N=R_CbIE*G?<` zYBNpHxiPzKYZtbYsHP7R0oZ>jKcVjZ#pdt{n2(XBjVI~F7n(3p+?ERtRz8pc==t23 zVRp&CHDCXbdj^w`^-czq_3jIX#?xLf$PPeD$umED*cli9Dg$!- zp~vLwv@wXAs|5O>^?MqACxix{!%Lj9iskt61r6$>;9byr_3;YdR2Xgk90nK1=h7_a z5b<51E)S7072gsSPYZ)E z;lOk}e;7~VqdgIZX}jj<0B;6hZS$%$%0n+B1=vR9_gA6slgx18FN1mkEj>6hdJcjO z6R|@Oupk8F$h*T9DUH(E1~(xG`Z?-;l@PnJMh2PZ;r17;vSp{RWvJ&%HbOGvXTbte z*w7qbS^|n0)EUR&Z~;C+wbiDlZ7HzvquJ)iOd9H8f15Jb#H1UiDgm`LMSDi zc&F#PAk_zXBiK1l665wPN_Ce_){vpNw$A!Iy8eU9#G{TBC!SaIUDM0CP}T3q8DU_I%gO z72@nMRf#KOEI0Q@aacNh2^VP+EhHVihqPiJgr4X?YBWeqAHA%pY(>tav zNc0#3VO0SCD(<;P{mX$hR5hjoM%m#7iP%eb%W6xlql9mC)q9Fcu32MUi*^l1cR$xnJMpdR*e|v|s-Bd{a{ptS~LY)5(O#i}mx~_k0{%2yO`L7$}AD!+;7dl~n;zNUU z-mJ%o+xx?J>AbZlcZv|{XcNaixZw{W`KjWfk4@2K=IM$Ihx1XP1=gjaFWBjri1$v! zg=BqErDZfA68I62g~32jEdd>_0vTZ)Tl3-1kc zh!NN%<(FhS!I}mW5`%TlI=Wv<1pgG^Ul{4%SsDG+&=3DV#lU|zzhFALU#bHC6yRT2i2nfmC#n_E z{lYc;;aU;hFFgSN7;QQhmS5aCf2$R#T4S-md(BsD=&KV^z*++Z0;tw6-|(sl@P0!T z++-Eo_#BNR3_0Pwj)B{fTN;l&-%?$<_JwT++PJ-mTgu1wg{vUp)>qRrabm#-qPt~w z=l*=btqZFJSog^VR?3IKOy{P>o#i9GD5S1i*3&ar;*vAZ+T4>*C@A=UhgHl4SN>ZH%Zq5zWuN%)&^xI9DOEMI5*;B%<0X2mRX}wr!?~~_n zmmgs3=-vS9nI>KmqFmNQ&UKAl&3ppz2d`X1h}m^B)M*n9Q-v%jcvD&YX+TG^%Z2Kr z;E2uOx>LN}@sx&mVz%zGQc2e?-1%iVOZ^i-_0iQq9dkFqKrg|FKEx6u6Q^|j(E|QB z()u~39_Y#f6yHoBwQDmj@=zi5cUoFia++M*q*ERWYebaGCvgSc@yq40GZ%hddU&Dk zpi*gSHALsfNY2w2KAu$UMiLfl5fb?*KjG0^odEls@C!$(Wrz`PndSDsj|J0@lF-<; zvYh`IzZYLKNR1r zP)@sxsbH=WhGNc?Cl^mgG31u3AzE}ot?#xj!^veb0&>3bNro4L-5JtG8(C%?gVHek z1PsKzO@xuV9K2!kYs*HXPwvlS87Lg02o%6NiItj1g$Sq5sA!8Gi~gMsXNTGF3bF%= zvJiIy1oLL;a8(TB`N1N^BJ+>-AaZx+s0 zryitU%Uq=z_AI)#T`h}k0+;B~Xe!%!X;P}g%WF{|!Y$OKXehPCcX4|gGpkKK`MHrr zO=XE9ER1AH2<3L$ni1Zl7tlXbvrn^D!a-ndC-a)E`!Hu$cGJn=w_#!ixY4|?)Y%=% zq3N{1`pbYBLmCcFI+C06FYYw>4(Y)GFo6d`Gyn?dV@|j&_i6{WPoV z0$F)TC!N3aoXsULFIOb=iCP>ZV{9cdevo-eg)U42&Ka;Q67zc=WB(59USR{;8tgC* z`b|}RzG-xU{X>%oq-+nh*hYhZHEL&Qta2oI(SG<&IjZu4F1cK%|B>vED>j+s8Nacd zd?z!~_)qK#hQPr~XiB-Jq}jEIaCxP#ji~)p=OB2ErM$2D4?kL({E!^bKk?q;nDF<6 zu_X74!61BgD4p*n)bHTE_AjPowk@Tooy0)A!XQT}CZD~@f}k?t=gDSYhjn+lu)JS> zdu>{WboZE7`*GZuKt6G)P}a#br>1(~KCn_lm<1p1=)7|=4Q8|umBgYHKT@WJk*wMCm*{{4KJ z0x&uV2d@p8ms3tk6W(4c*+ttlW&LkJa*bm_5y*TVu-b9Ze$1$%49%5f=N5^UWg$CQ zjNdOY@TZ1rS%^g4j$vt%m{U2VA8c&fyTXns<1W$dx?3xg$qvLQzh>9nYMx!fJ&PU^ zOh>{1O5}|#jDdik!1;=a@wr<@@mEntRMH zO&JA<{Kf%i?sw4p8et#)|O@nP5Js8O~3P|i9JG--cdrZ~H z7pB+HFg^r4Z;;odO>sF|xyqkqMQ$=a;#0;Sw0{2XcId+-{eO5werp%?4^MG?st=27 z{69mfhT&h?2}%Fky7C{V;rv;;lRs?a{}H5rhEfgvZ;QWwRdXx-UrTxaMQHr*=GK4P zQq4zN!9N<6^wb~wR%+Id97jer&EKPR{#drx-?q1OjLbBWx(;@xF6tk#1Rp2<>*JUI zHECo_4fPF0t&FTWIcfL=_yx89QfP3rGWg9u|Kpf|wZ6QegM+D+vHfo~gTD=`a|>9Smti40R0*?YKXFXygp-tsU+34L?rC#P+vu!#@J>A9N@Ge_5)T@~jD;`b&2* zHo462PqDxBHvSQ=?vIvgSXk-*r&2@z_cg6QO5L5NNSY(@q5HgIpac;6mTlzeAQTBB zaDI2Y$aFz)yClNxi4Ad?@cT}}1(BT0IOnw!rT4W?#Y{X8Pt1P_-MmUswzMw%%!sFk z!*&W%e8nPG(&0Xhm4P$PY0q%)l=H->nuE|k86@I9?7p@=7$lv?Vo}Z=P&yswXbvQu zO@5{TlGAdo@GFwb7_?jo@rD0lF0tgsB7La4}Eh2-tX9g zPUuOX!w~J?Z{TdHaF~^hqNt;XRubq4R-g|CWRV_Tp7%t=S80}_l}{Tg4yaEx?*lV^ z6d`vDHGX?;TLhEc7oJ?t-FH_{WLocM9!_HXzow z21ugIj9s@<%aF_itl5e+I2{ETzm0d`MSSK%)cKUrNLYar4E)^l*2Zk7O;W=8iAk3u z0Moy+Vk*6N!OQT9Q^?cPoI$uT-$UlZd>9X#X{)XLjLEM(6`yV@7AfMZ!8SOHea}4f z8>^ggMGU$=*B1xNoOJ|0b8CVXi#H7--KS?^7dGJG3@n!a5@nDg3bp}$1MHWocfxAU0s|{04Qy`| z3}hCSZ}|E4TG+rbc*$l3|E#BR<}ekF{21kN^C&{k*RgF=gS)USEv#!n)U$bdbx@J9 zFdMz0)F1G;siFn~UGfF0V;N4Egr@`kq#NxC8~HUcHc&K6GV0RnqU^ghvP!)6tLu$x ziDZnQ7f8*`TOFB=YzoVkY&_&yyy5M;7+nm6%t5s4crHh(o=pU@`FY~ZQD$~fM!m2cz3vASj)JGO`xyq-#z)}l%Wg|p4!e07H9PaOV{?=ZSe zZ)daOon8hbJP#>e!aSTjX^2ZD<2+MJ&~GUaff|B^xGHSzeX;mSTYtm_OobfH#IF?L z8l3Tby5B-114226@c*#))=_n(%i1sQ1c%@n+}+(>g1fuByK8WFcXtgQ+}(p)a0!Hu z&fe$j>~lN)^&PkG7&~Y5KQLgi)?91WoG(?s_o;d`j3JK@mT##)ry+l`fg_vFj~+Ie zBcs|@OHdfTrq6vkT(bsU!rPk?KDeG{KdoC$-;?u}>`7K5^uuPd+m*ZP#DP8m5}B*g zoO*-5XzUpo;S0AJOP1`nPFQH`F>a55yrrJ85VWZszXk%F&4PC#pLkd5jT;k1%T|cS z-}*l2iZn-Z!9HY6e5ssqOnf6^wOZ0vX(Cir@F4X@(4hG$=&8wN!AhuJ9p>zU&D&2x z(rJdWjk%4s5l@m0t817_dbVZXO?9~98q4krWt%1rDr2e#!1xFhTi)jUwJYXG(#RRZ zu+&tA5kna8G)e_%+)7m`KN#fjF@DHZVUoIvsD|=&8ge4FLaFQM6}z!`{qSv0^hD14 z%%p0ijfJgBJbqJ~%}Mt&qR`R|9`P?z2B#+E&Pyja<@BKPe8(EW9c68_Rff6&;>4*r z_H$dI6Ko(kZH|FeL6Axt$QiXU^WW0Oxz|4RuSVW1FGEaBhwk?r7wIPe3}@gM&JOA# zBm0<&^GYI=ZzD}}D64fNOHeAhRA8Wu22gBoZsWsR50>(%P`^1Am?eS$#1J_ni!n3D z3#77W+66E<%8Wqk?eK_1V9da_36D3*&)EW>iA)z@PS0zw_cz3@vgvK-H|qyI$Z+Z3 zu?fN^N3r7n;)`%ZwJ<;I7xMuMmVE^+RbGR(&3PU*eYrx@etIc#5$yx@VcQ$L3Ube(4cQ z&I>)3Ea!9?rLp0gyGbTd|S6>>uz<5i13(*b`@R3IIQ9lGq%6 z6tIAwxA`)ld?wn#K*{iF#(Upq&1>;&l4xLF9>|%9(6Cvi7vZ8BfBvIQ5!XC1_A1Ck z2W_=C5@VbIDH=7W@Ttz4Zv%y~h=Qd<3}d3xdk@ZCytd?`kGYpilrw1PVHjK#pQNhU zL~O0u*mX+KG$0pJ+h~l%z?zp-dEXJZn#GB9=NoB>iW5Z;$Dz26*8!@dQ8ukV7(O-FBxmCL-lHyf>BqNTUS!IbLzCMKl76+Rl<5^FVWK?I4LQ z%>*rGn-{KElZhn75~$aGt_x07BpGW48lP}nZh`Rhl2lKl$-Xud$@nHcS%|1g6>z|2 z2kX@2qLS(GY~Cqn+P2+Gl=6DXAjx1E=aPQvSRiZ4MKZ^1 z*QGGy@#kGT)|NY+T3C}wA2B8!Acg4sN@c{95@l}q?2umC!EmF36$mXMLD@5ibs%;Q znD-w_Gyoj{O*j=wpC~Vz8pVCu8yD<#c>VXY11jN}pfV9!J;ExMdFQ}ozbiJj$UtJ*)#dPvk_9)%`f=VbkkxcSghgze5cABR&&&?`WdpjI)?Vb z36rA>n{o|b5T}WIgTwUXCJLb8KA4E*whE67#8mEAUBp|a4g0CF?IOQDoB2q0E0Y@( zDfk&Gz^sB3zF|cVB?BZP&{MU+o}6`6ss*Ii#lQw@p}6b3YCYMUt77x!tb|*2*W>*9K0W4Qg5y zoz=LR89v_m4(58)LBV$`&VDNwy z|K0ldyBPkT*}(r0mHz_MP5wEM>Ce`E9z%=ZkwV5I{tdrB*Zt z0a%ztS{TzKFmyE%sWqVIJC4pF0+eB=R#7!SK}4ZToHZ`zyDzR>xF>byNi6c>lUVQNONuTC-i$mZF?>q(j%wm~jGRdCTzFV-fB@V8vnc^=$U+cABk+tj{VKmb1T5O_`95@f?(HDgeU@6B6yNS3W!cTu zT0IY~j%u6d-!3LPHreTrzrbNy6A(m?Sq_-(b5)rb>BKAFH_b4+y>{OcN{znId^^}I zlWeUY6~J{6Rr^?sv-l!^lJi7E9OC=DIba-fFG}P^F zx6mc$Dx_xF{YFlq$(^oS-V`5+r3Q$?P9;7eji9!xp;Rj0?7=!|R1jvowUSs6B`xdx z?t^%WxURUNbz0~{`z%wVrl4UCkLAZ`&84MU?WCD!m%(uZGtpRfg{@PukCqy}O`cn& zntS^&Gl3RUf$VMplnc6aR~MSaC-%7q95OR;yoylQfLx}li+QpMHl;#7zHgfqERcpv zE9M(7kWuY;8i2E!w#zNvkt574knDc4!!`e?yQ~q*&xkyVC4iKpwU{x|dYLmqG%Zv{ zo#vIB81+pZ`sAA%Tu8HA3*3WH%tnCNLY%GYyU1c9o29Lk43`|9K$^c-gvD|PX z0%^OgN#xdK6Djt1ZSed1po#C`0sb><%Ul&hG4~-?lPpa zmW|7|Ih8=UNJm3S9Df4h_lJ$Z?&~bfKXVFaTm%u)8`ZFrzK?6;OmJwcf|>0M=37fM zY~-hLvAY&{7{8tuJLirKiECi6-WYTgJw^sr5L?pE5Fow_xGZPgLphYA$za9#NXnxv zjER#K`VYJqw*PnSZ?z(_d~YOm)DGNe_ZaESDxw%`qy8ct*l z$qe2n!dY_5s}4kd^0YHNJQv}f7wapg#C0<=5DzCq5@%&OT!0=as;_*Q)ZVB%3Vn|B zsAvnOL27u9at-4^L&lXYjfACsz@a5(CDFWN?unmzrClUL9DmKr762ys#tu=)IPx;k}wMxK_9)%K3|-{S3j&+X~^_mB`vJsXtcV_LN zB5j%~>-nU#v=t@}Zf-91>Jvf`hVJ~*VjH%1ADiIcBRtv50kgdX&R=IgxZb$lL_J?e zbf{=6M*BCUkwj2{+0S*+JC&*&yel^z(c0`oa7;RVM+g=cZCQSfhbB2M?+NfA;75k%JF+p&bh?9d zMHQNcCfR8mp|3a2ML!^#N@%I|O(PB=l3kunt@XOMWC0>wdv9Ae#-2Prk4D1|(R!#% zc)dhf8u_VXqYeZkO}+`#h8=z3Y0ntz@+MncfveX9679iy3&xL0vop47!H}1)XnWMO z^voyOUEl?z@_4^YWO}(wPMG;VWiz3c@?{L!++4IlV2pPk@uJPfR zQVH#^CMT(+CsKP-7?KjiU?EdWY1gqJ({=eAvs}buD33Bn3ZI_^>3cQb6;z_ft&bN~ zUYRB%ExDVlgHCc+WU_3wPx!a@Hx~&=^eYCsbwBH8$axFqpZNuR%O#v{*Df}q5?%;^ z(G+3O$7++-8k!|C_suYW=TIB#{_NG!WUK+4!(WLaMp^Da#DX1RpyCM0jOAx=Gx~9u z@R0U%QB17dR^Wg@G>qLRJ7`&*1O8RKlXc6Z59A-LgzpYdV5NHTF!&0vYN2D+x|6{6 zOdN0U%Hlz#4a1IVMw>x_)EIQXTmaOkRP$c|gyao2cH8U+>%25sYKL1sWy%<07s)o( zL`{5dwxG;?qiX)iNR|*yUiSiYuy#Yo6kW1-E&qd%oDX-Y)1~jLkj5m~q4b3aB%6z3 z9Ax1mU3ADIAq7ui`{sm}COu{T+)%wN4|N)sZX}KLM=elFRLOqUT3NxMp!nll&Lw1d zF(o~l&aN249W{i7ps3rEs<~*wR3tguQ}U!G2LkbtBi3QFu1puo;exT+B>Eas2~AK} znG%)kxv6kfRgOjChmUkn7>9G(UB4uwG#_utX#FDg-0cOS07xc@x}NUGQmo(Uc zO}WgBNf6t-VO87DsTL{`7M+N6-oZ%^90lRdRxZ2aZTyAI;7ZFeBF>#ihma+r@D?|% zPY2KNE3DQAmF_``h2$m7kPAJI!BqKW$QVaKBc5A@u-2;gqPpY}iah7x_Iem8TOGsv zM}~1z7qd#w#^!GKoO;K{QAbh@aREog3mF^K6$|h^ zp!pJdc#|N9`f2Ko0mdedWsaRsii}Sl_ENn81K#*Jgegbq0kG-8Lq4&@qAjefDCf(6 z3_fMB18@W#%X+UJ2o0HpBTU2~_yR=>&_($k;dd(zrk@gkU!iB1`7azL$;$S>q-U7v zr$pdafI7^-CD4D7=7;sWxzjHQb(ntO0KXd4VfqV2Tdd!$oqis`{{eMse#g;B^HKn{EUF2LirbKEpOe00zZC4%{L24exWpV&Z-2>>W9aMRcZWnJ-1yo(oGt$H`1#yE+8G zkj~owri;a_j0^YF1_o1g7w*5&X=?R`m4RGRQajUsd-`!{@_yp^tADSx_Ql?_v07BR z`I5>ctWCi)&bhGn?iQM_aDJ8-*FEDQ6774L&BWynrpXJNs7x8t2nG_#xR)^)Xum{B zb@qHj*u@7*iuw#gS{X}MSe+iOzOcfa^oL|(bTBL92Fio{AtrFWx$>ZbZUYx9X|dy_ za>&b+=yFm%JeExiCYp}zcbH;(r=!>MnTrE1*=uhoksL3(%u{-E7hxB7f(RFHyZSC4 z`{KgAUV2eqKEsL@I@(`Y^-JVW>on_^w%ogX@w2CnqW;Ft+Lk=VeVU6MJ>N5&p%N^2 zEDtl!CeF@X;9$WPtZ*Kx9dR6ve!mjNVbT*)v4n48+2rsvYnw2t92(Z6$3pk?Efp-D z%}ts|w!-`=P275OBcF00+hwL-GAUXtE&9eihz_6lq@n*U&29XSd#N5a&#>|3?Ll-n zt`Y*E;alf;*3|H(JRNY>4&`qr(LPG?@JrjQ{mCC~vkOw1W7%PJi6u3ZO=U8b@exx? z#^B{snb|H@roE3@V5}xm0g+jWhd1VAlj*=8D0N)2fD3N0q@US zcM~V1OzxH_AAzR%eRb@Mm_fSepmg!(Y>AeIe2rs!nmO0*dv}+84m%IZD)>BJ*|-F3 z9pwWld3AaHmagttxBan1oZYB+0*d+M5FG{C2S0n}B9UeK7$sDz(_loMrv_A3uaSJ|Dgo|a}*5Uvql4QjnmOcQZwOQY;z(HJDNTN zT8y-5xlP~9O+Hs+l~r`)V<;R^)ltf1;bvv41)#|ANNN@b2g~-M3e{*gKj#}HA);kH zBiCgof3BSFca5jTJ$nvx2UJuVCyrmjU5L})nymWRan>TdF2o-9rVzWI zWJ69F{$N2p>{wr;BY$FR&aBYQiMAQ8=uJWDGc0trRqou4EOPH%9ba2;gmEz2T24Zy zsyoDRJcH4V+y25?ris6kG7?uhx%HTI@lvSfy%=31m$8|?5RVwC5yJ5!ldbW7DyTVKV)jnd)b0_!xVK1U*#9i{UHZd<~Ui z3NulBRAB`-;XE}sp0 zKMJ7jGT|0`#^rI>=P0nTy}*ajTiGN=^yab`1~LD@`qEte&{CWp zg9>3ygabgBNV?-qsFB8jxH5><5_z|H@m_3m3_anNwkbF>r1vJXQGr`ICY>) znl0mwR+a@4c-uyA`&H~Y7tIyh=@-w)a7{brjHvV!@9ei2_;tq{*e}H9%%V#u7SVa4 z$p(ub55-4~11rM!zkLJROG9yeUBCcRz=7R`H7hAg6MFyaQapb7$EBD7)h0HPG7?AI z4PsXlG~9lPCVL|H%?-SH)f!mG5Y(r4=j-lG+en$=)pozGyL+9+DkTq#c1OGVDq|PT z*%>NsrFAOJ`^eOtt_>}kE^d#TyR=;%=kUERZT-6|{hszN2 zu9Q&!Fkt#!*_Goxx#aIIu`GWQ;Cw%Ef7kcFUVYEk^tPb|+f|uMh!86e6DY#+IS;@Qr-p%!!rdqB}kt1Bdbmh!fIa`<~aeC-yeFaz8%;Q-e#C;DaFphQ&<|q;0DoZP*mL zdfcp>JohAL>s?X=ybHbqd+%bcG^Lwid$eXMos6f`S<0ZMIxP0c<9PCTfg8)Rptp$Vq|Qu&O^7c z8zm<6V%-jEV%oud_|;dNZL^uhtg5ArSws7)LL>qKyXp9rm9e%Z$bxh^@*1FNS@IaF zfb!5(_3{`-M-m)f)1<&=v|7N5AlE|EtHL9;i86(^E*r+#OMWj6LT`O z+l49zI$c0o{%Ym?DBPf^cU9vlf2*MwiUU;eZKcT@*YWRsQGNz}&j6jTYCToNdaQ3PjPuTg9&@ zgRQqIFOzck@A#CbtMjuJVzLB~lToJ$j0&yZCoyGZIHu8spxD5k4eIS_-lX2p8?6tJ zX9V-`c%xICLg*|h%_zHM!~j^Ay+dk)1xlpSTV0N6ec|{dqz`&Kjf&#e9fGLuxxrKI!R0a z3F~1SKVVlj4di&4_=JMM|40z1Bme>T#9yYbZRlcs!h0~g3!DPaqW|GTE?$8v3Xdp> z{$w=L)RJ8))u%o>P3yhq<$9bKZJihf}kX9=<%WA{$BMIW^(=R0WmaUBD_p%y+FOKJjNd#eYI(h zUvq_2ga??5Fz1;xgXetL)x?x6W|K$+|Su< zr}5qvmUM>ne0VfO11Ky+$KoRZEz*oB2%3)p(yOiH^dx!=i1@lM6TtP?q0%)s%x_Na zQ1s!*{-MMCK59xD;wi$z_2@)EfkZ1=1XhCTcr^MJ?>{t1+LmM7@rJqrq25ujNP~wp zinf@D4s#ym*cHNUrApB0D%(;A5i6DZ4*2W#@XTtSMnT|VlcUzh&O%#|n-R4*bBcbW z&+Q&^i9mkfjIMRds**!*@Kts%f%>c)rJ$i@7+Q=R_x7o6#$@HQeq>?{&fJ+Ot(JJ8 zFVuqwi7R$2)EnePbaf`j)4hpfI`pe@=oY47&+-!G=@RUv`R?e!R8;fCdDAt8HVlOl zI0h%!9womv#(A>zkd$P40eb<}VUCxN(gi!dZhY&)HW6Xo%?B#5aGWOhm0cv{_d3K4 z^2g5DOzjw|UC;>E?kprbR(26fVlr?r2i5DQa`C=fp``k@?hJCx>?-Mz=m_*s5QMeW zLEDY~?*L7SImfe6HVcPemlXOos7z2^RU&B;H?yrBW_6nM_fqvDwdnnEx!peWa8$mD zO9Yh2fs=Rv+cK&jUa-&It)kszW--PO0}S8pOrD`@^n3P!cy2CmUmkjSPw7f~(kN-6 zML=Od%A(6=oWOu++QPGu%Btj@5@~Y|4wH6v_{Cn3nG`uP3)j(2wNZ0c%%nIZL`^j; z=woBCuR&wwt!ki5IZgZZ0}Gm<~Z*?gpd!Q21?UIHw{meS$c0%>BrMMs{^0w8EZH2wZXTy(--nDK-od;f+INaE_AXML zg}l6hG8tm#$t*8D=ONrVK7Bnm?cvhP`)Y67PDWaK?|5a+t8K*_@73#KD?7>BbxGxJN?G}Yb#=+nHOcheLGNnzr&xcz#R(0bdhXJ?vxI2oRj; z&%3+dZkbvQzUaQd%tTY7dA;?J(*W9u-3?Jeoa%a=R3)PmfAISS+fM42~s!10`1 z;&)eA)<4d3T~Pme1vTpreN2BuOunyde+T#%4DfINMgAGMKMe2>Waa0Ob@#|B$G`n@b$uxp9u61B=qx^S z?Zox)%u$mv^a&W@aYELD6AGpCTcX*6ZmlCm z4bS9sQPcK#)GsMJNVb(nY#<&q1@AEiMS;O^+0>sITx;Cy#1bmf+bGJX3ZbU>CG<`O zXyl8j$zngHFO<`mx@}cP+ktEHbv-GtmqZ+HS`(GM$i(yV@%KwA;rWXqs**YK%Wm$+ zPuYJeo{At}fIl-bbuikVTeVqRg}%u!UgN10W&Zz*GP zaK}Zk0XX_wgBx%vP<&a$o6>3#?=u@L_-SPhPNIw$uRZ5ee)gz_)4FHNC}Q_(gN6JT z&yu4HzOn5>LB8H_mCsc+e4>Ll!!YqBeG zPt2!MjSUw1--M4%VKHzVq@xHsU6Y=WJX0~b87fHF2_HBUIYwe{C%=JuN4q;iJxKSO zVcK9rcgXMNy7KO`=2bG|FwI=SS{1&(>?gel{7q z2qPNxIt=C>F@u@{7aNKEDK4kC!4ERya7+7;bjLgT12tbdDTbu5kO77;Rh_WBVdO$Lr|z zMZ1^%>l~FbpnEo{_0;dB^&Q(3_CQS}K$@@zfek)u7Z|!PX`k^lk6RjF#$U z;FN&6Ka`aaLb3Cku4UGtGR!DF3e0MZYlPcPZ8urSrFvaTHlgXd(ZO3n59Zx}P+SUs ztAoxdKDRj)1uXT(L;_45Vb-L5v%M0N9m?*Cz~>_60TX#2zM`T>obdy2_O@Npu^;6K zei2@F789RS2xq>UE2+a?4t|dzxsNP{GqQZ@Ir%<*JvC3*WdY6y_sP4C_G!pMZp&*T0I&i6h-i+?!?H*O=P3jx^iwB%Y(~!q zzOWf{gPAdijO`kY?qEg>y3}#&Cgt;Sn#S$V2CePuzjZK@T#S{a-3UL`bhfB=buEX` zw8rXvdpMoDT{%3Sux@-=FYmt&zIj-=sYtFgxjlY(H7xaTckDo@TiSLY3!@<2YM_p$l9E*tQeqwPYrhA*b9l8qeH?l0xIavBX=y3O!Q&_Nc~ck$hz(V-Mi%oMN zxL_Sqpp?}(F$we*`QzMr?hS;4Qz3fTUneCGSg_IH4P!2tgNdHx6nea}Yz4)8A+;6KH6 z=;@jMrF3#h*No{g>!pPWI`@LYUJy^frWd~!kz?QlLh^ojB>SqqKA6ij%5&%b9 z#Cv%m@sh|~xtnhTxlHprr0v;kf0y3N50*1H)WhOxo4fT)Y`8VdQI{qimNN`dzUX- zIivi2uAdOaW3YN$Jx-cZ=u%7KQ@$IgRhv-kpBDI{D*G*x8F(YS{nX8&zhKnu7#;SpOvwN;p^vAcs+eecr2{{ z`UwB})c^k8e@GR7&Lo*$9pq{LVRcW3_v%Q@M*ribe5&TIqps}wGM+%laY1Oe9;&`S z6qbQZQHw-k8XMGCLp3-cc4SQP4tuV_!Ej9_@jcf`D=kDhudM0d+vv!JwQl>&Yf3WUK`Hi9Zj%w z1f_*>pR;ej#AmwgUpRY*7he*?2Nu<>x^^~3nvCsCKAJEx(KVF0Nx{lxBzJieaAQ7S z+mj50Ft?*$ZA75E3AP=cXl~*Hordwribb9Kc_Y-5F(-61?0(A}6SQFYP)C*tbG+cK zR~=?z88K92Cf>zV09z+LTIJ6zbD%H)XLQ_z#Dqnx_Uu4zna}O4y~(+4tNSgSNDmzQ zt=ly)3(baeW-0arKmSJa7ya0UaP4L@ZkLPl9o4~(x76<Y5p&AOoHP zDb@s=!}Hlv8>+qO>2h; zd6v&>U&t0hnNDb7tKEkp%`;R8cb=K&w#4z!_5xlo9syx%!XC7{y=8T1?7cx_T_G$` zS^;k)}oG}BA8u-8BF=s zE()%p#ue+c1sZ5-gNn5ajzI@3qlwKvqCnhOqIFa!8(2eNkl)@VkhO^~(g|0(JweC7&|St_$>1sK@zipw%jOtHm}ql3XdNj)g0XlPd$4R~TF(cY93W zw_bd(B_GRm=9yq{*Ip)?dyZm?YSxT%%X>oBQiKd9ge4wg)qT?zmMM3Ag(y$2W<2xs zoL%L2M^OsQ$|r8=k#}4Yma$Mw2YBP_64)Uv6Bkk#-48afU(xlJMZw&? zz8RhpFTOxoz~Vb2)_i!QR*fbE)n8iR?t+f zwmy{R0&TtT?h4nH#52_OS?kcs zuBq8mN-eI=)O9ATa83#{6(db8?J<>KO882jX5vLWEh~v`_TvOea`dTg@Rlw%r^jm_ zJ>^ApY}L-I){g7s0}jq69Mz>P9Ncj@4#70AKRB~DPDUa3RWyQTI_^>J=UUJ71CW-1THqDINGJPMCR3FhYk<8*AD!9`nCovvQtCEBZ6 zx?AD*JE)CWYXGxGOOS)aZn=BirDL zp`@nr;KrWIT+zdE~N zdS823LtiF0Z$zT8a9jkuH*&PRWta$P3;!SYT(Gv&?;ItGk-#9Mvt~3@-+Y&uBmfy3cz!u)KP z4jb_a`%AMkOY?C!yMIy|aW{~S4=oz)8?ejOtggJlwawc*on^}mEGP(=?i+kTE>{drREKMhV3dslYAQe4AB8Q%`&s##{nH+-5=EUyI_#DW}pXO_}X zifN6e+wjTkYUCO8o}bGJ;$xyQ=@$UU(X5P>9!%~HJ`U1F!uSP;ycM;l2VNpGOBg1> z>X%&3$<0P~|6+$pBwD}RXP-$XV@!iM5W|TGFfd_GV1YrPHbuPK09xg#6K#V5B$Mi~ zY=nx^J#w5$3@kpvWIqPrK)5#uM z!WRx1xMSDLoSozcyK5I>A)&0bqI2`IH|@1jqLNZ|2@~;IXcPy91Te-;_63rc&Tk!7 z(+r4erKAip^X^*YGV?=sCs=5Y&89P^6%u-7xBGp!$%4{(`atU*=gI7(1_=j~9i>lP z{V^aK0uK{Lvy8r)b1?;L6XcaI_?PPivVznYsGPSpbnx>*bj7icuy78D8S!-}@_2(= zGZFdarFi_>eg+V>8DTr;YZl|JR45;NlIA5sYAC_e-)1|RE@(pyn@ z;UK_X?&(nCLWM~Qn*+doOYZ0V3YcX4f;E%QG*2HrWvJ-h8t~*3gIm2Tjb9~bUdseC zGGZQFF~q{T9OKMIlMS;?JKUDJw9Mv_@BA$6434`~Zfl`0va`r*y)wYU+t{hUreYXu zZ_yHWBQOg-^(hKPUm{t*JhzvwakXdOp&X~ocw|rmdt@+?#<<*nK)O;_V$t+=y=Cgd z{Jif>!WHXE(i@znMY1wi!6&CT*mdbelo%XNoV0_Bnmx{|t|X3{TsoE_<^h#&-l!l< z5&E$~4mjSdVjMv=8mXzjL-D#$6%c`)3{#mHfAWjY z_Rt`XCKqPKDq|FsV`Z!5=KPid`I%Hq%(BvjsxGs@m5#&GQmK10X^{e9OKeMQirY=V zlFq!&-W$PZ9F4pBIfjTM<#H54kEVt?H|LJ*gq4MIt=)15c4c?w^F_zgN=**udY4pk zmUFeGn&rH$icl_Fy2}d94oo%Xx%>LLin95y81Ckc3z28*6SvFrw}Ka^uHYZG(dYCGt}y7iie11hbGZAJC(YXV zmY)#S!tYeloMWNSotd>mox9ypw1pZ@*!yV;cFT2)Q}n~uito+T)GtD|&AWLD?$wwz zFZ{NThxQ}L)`c3z;mA8P$uqL#pUj5N<(@F?SiA7PnH%-X+ZM9nzUMTeNJFlY)BNB( zsbko-O>y9uK!Va0;E`}gx-Qm!Db}xCJMby#^>~0MN_LVCr+9E6!lCMX^RN}6@cPmwY(C@DbdJ^id!rw1#Ju@(4wv_IxeX{E8 z@LYN0MU*0HWUK(j!^pJ0zXQHwOTEv)X=xB~U5{{qoz9GCl!}Y9>wow;Dx;kuC7n{e zu}RXOBB7&t!*)0YGs0m&lK7rk+nwY5Q_2Oz#{Bxa)iDlE;GR-W;e0B3JEZZ9TVL|@ zOdKaVRW!P-baG1h2WEm*$uAb8oBEvyxVW=*!UQ8Xf&tN}Xxg}usk#DCMc1m_R+MVk z%+so`V`@k9A3`;jM+HZ1PQ8L6=` zEj=s<4p^MT#N$0_AH%Q%LK&GrUjrMt24vBu!p58bHFgywA z;o?z?fgrL3=Gy-2Qwe3riMuU(p5Z){9SLEng9j_b6sJEGs7dJ7Ppi(DJ969jl*14cyu(L5GcoR|ba z(wpEU4lo7%&{-{d-@#XfJVP)8!0xbRhNnPg@hkIm5U)^|poqO&+i1_~wRLWd7S9^CX%cD)PU5l#2l zj+mW6`0yoiC?5@)-rW^)^`n-s&RURU)2FF-#$$qvOF^A;JC?%Kl{6;WM{g8}j~ADu z*W&x?`X~#A^C3Bn4KFMlSxh(@W|%ocZP+0TXF}kf_}XjwY&BJ~ zJ`e&c1233931_oK9E0p;mkGGJrn&3Nm5X(2VO;hyhHdbD5z}y8{2eQ{2XeURo) z%s)Vxs+UWPQL3dE7Z}j{#9G&_WDJeSALxuvz(Xo#e<7eM3;n;3YoG0 ziL!D>-tFCnF4-{u1`dfLBf&lrFBR2-P=0VZKePW^nyh0!lW@h>`UPli5@l)8GUd!& z`nCuxlK1K1$2!VRaHj(c6!uZ2?W}rqMD!_oQhIM?Mih~ta94x@Ln8zi8&f}Ap%0_e ze=07I%Fsow({15@U#wkOeVU+#+zFHFYXO$tEq`6E8kC?sU`QHWI693Za)C)Ruko2S zs)kp9CYOdloSOgB*=X~%KA~)?lxq^o;{s)kiT>{3XtSE;LB5u1R=UPc0(L^&#S-1Y zmy{3b2hC!pJS0;Ti%0U3ri^NWJO&@G_oFY?avDlsVOF;gfWj* zD9cuI#~7O#*xcst`?d%1ZnCk|6=o>KXA8lOxrh`bi>vuZ4lX1kBNs&WTQOnP7wU-k zJY|lRRI_W|>sIj*FB4ym7GYna+$-yz@(#6pg%su*F1G8LRiT6V1y zdTgovf*F~<%nxrbrM!pN+>FR0rs!_Aiaru0%Ty-0WbHglr;keMgv2m4DeBB+=V$(| zfh3oa%u&|3#Q#WIHVyIyMs!fzUU{>tEqExj$3mhAD>9aYR@H!tcvc{IS8#u@PJM;I zaR9B{O$W7v>colqOF~W8YIy(2W$&)`zPrp_a?By{JD>|-q+5FRnL)xw3xm@Q5&2S| z-Cm;wYrk!XM-Lb0<7|lZw?_~zpDr4SDRjs1B&pMjHxOR^T(hLOar7guqGy@b{)dMU#l&-N4tC7+b3#q4g)sb# zc>@o13GCE{~QUTWjnW<&Gmk>J}CSHSF4*-!v0}rGwkh87LbtA(H!SQR^i^WXFP(9{0#Hu}%{ zUcbdF{;wPQ=Zu+-h5o-%7=K*QI?maK2nN+7SzWp~4$VZXB|w)GgrR4Y%4iRH^lbr0 zDxqlHQH!z)kRrao3fHa2t@9i4wN+`i2Hg4Hd=WL(2xI5^q^ElzRViRcVyv8af{2;i zsg8}+#NC^}NFN;DX1EN{cv0DY@_U09+LMmR=Zd$+xDiCS#S9L^-A2gHY_*?b z3WxYn<0QVlVK@0!4sg}xtF$XjH2eR?_8bPv;Z*)T(&CeVKWq2!bh{9ao ztP*kaPD$yRR)a#l*!#d0;UcBmc#mkM>sf0~KUzi;Rue42?Zx#=!>I78p{IK?)LBpN zlGG-*sz6kQN90HZ#$XeCKqO^UC<2sYX=C!;gC941!|l3s^-vm# zaNE4(zzRj@U=G*A^-v3b<%{o={W*l83irMlZ*?}LD`~$alVL0G+$=N%?ft%Zqo+)Y z*u1vJlEk4y3;bv!5!4megiSAtgkkZie4yFXYMi-}1V(OS-HQGJcJG{|+?YaA1%3Rg zf_mZ3J*)8OOVWtbuGbWXMDxi zE8Jsufx*-t0#y8FJ>G^wJ7mpO0oSz_B3I}rpfc`z-KR2^Ji?aJF`T@fHHG5-^5E5(c@!8QxpybG zH`h(QNmO^OYW{Y-M5Zx_!VzBCUhaB+GPdaGW0H%O?EzdvEH@((doZsb^(eYLBZ)ng z$u)^Q6^P&tks~Xc-dP{oM$POdI>|+Sw#}@8+I}tME=UUqH*ddIMV;2Hi9T`S7 zyOTbqJW*pfzsX=;99Z&+@Enx`nph1) z70(`cW>}=6Q5bhk!rjAo@XB8RqaA=|NU8DM@tLEf1_~ew7y)>3fB}w7C~W}v;!^7i zRI95X1E#`_YjXNK`{O?_l3MT^NuOYXs~R=Y6hWbUO)Wavqr~VIn;9f80DY@}C@CAi zd;n8sr6W_D~Sw|ga;W~cNiYLZpYy#Fg z$XF0%)nv_uwZ2*#pROJW;5!oYm(hW~*6R7@?P6wP9&q;x(yNQA*?>WTMgF)GD`i=7 zVnsRAjv^3jvFegB5PZcHP}aa&^;0;cW;ZJRsV&fp#^phXA&4SQzsh2Mjss*#GPTQ0 zIg}8Cx7lfG&*ih%_5&evG1G5$*^$)BjSMD z_5+l|a~b_?b;mX$X)H@BdzD1*zc`4#2Lu6dpdy#~{Sy1bWZoaR?f!M){&Cy=a&9|% z+8<10e=dT%^Iq&Z4M0~9JHlqZn?w^^^&H!{&{hnJnKU%pnz9O^bywbH~^3W6n~ON2$XqL zUHzNK+w7IG8G##hOSZ>u8!NMU1d$-v!2q1_jP)zm1IxakormX098);$J8S2wMV8TH zctb(Ip#60+uiB+A{(Z09ZCvaxH*YOhJhHYkC@=baEW9X=^;^*0Fjj@N^<1tGCjz9C zy}+-*3<|qVZEJ|iM~yv{^rH;z-(XaHF8a3ALt^T6RW@{ns5hfGCn>i|qk7gvOJ;QF zB4=K_SwFW+Th$ey7Zz_jGKb9_nUyLp%V5oy%yV+eG;T_l+ysT^(cVF2GzOkmj8~;| zq{6VU0-n$eWE4={75`|xr*~WB#hT)UuyLTqf_l|VX`jXPx9uHno>!rtx}%5N!^dcF zl;1-g2+hxa$z4~gwUdUI_OWHXym5lx$OHqKc@NCy&tM1OM+@V8e)h7-E?pLloNMar zksBBOqDtXIAoi9~S}7`Xugn;Fa(ge!5uk+LCv$JlZu<^BS9`CSsr;W%DXOcX;JUzoD2#B9XfJK z0y0mvmkMX@F7{v{UPIS=7dZO;2s-C*ObqIpl@qOFJRJkLYEcsqmh;F9SIEz{%4>q*xVczyRehrhSLS=01guoI6{Ky*kwVR-c+nKZ zISbH6^*n|k*`(QU#UQsp7hTU2jUu)eMv%5 zo&<>Y8D3ZyPpJ476(Bd3o0?+;Q_alI^{jRfBf1z9e2hIRsks)<$kE%x&%}X`ijW*U zI<)#V5s`RYj4l;x1wOfbkBmdDZOgMW)CuxPKy zwq{!iWnon*25E~R4`v!wra}_e+@3LPS4MNS7h|^Yb)IT+DMZ6&BlQqGW2!0PfJ9~S z{f06o<<>i`=ch2XH+Em-$s334;A0Lyj2#~e4_h2HGdA`Q53Kqe(h3;p1U%sn4xDhL zuW*rK+6pFYco`HTVD1*dN5LB2+V=*^EWFfvFUU;PcN!hkzJ)k;$f?`n`dSoJ9V%8? zndIcrr8tcVI|9KA&>1uZ=&Rh;A(fsk7sW~6~SWIa@17cctR0gF_6MX*OS{T%_q^EwoGInf}V z>)}%e1jo8X1zPWDEvf*6`IdUnImZs;QdF+H{9n*bXfWcF!=kBtlh9#0e}IYz&GX zWD;}SSNW!~w3EtR?8N%-Go5njI=*tj(;Jr@nqTvPaxEYTYd3|9FMurrEMgO`Q>LaK zj8R+~#%i?^gLy+8&E1H~NW!b2P4q5XMXRbS68JIY3bT|JsT6bdf4{YHmk+V*NJ|kn zArg?(W?&4v&_I@jEp~?Sax|4V@*T`!TV2hxgxOSR$m}Kb0Mc^Jc6D-!s_k~qvBXU> z^TuR8k&Phj(0Xr7Ep_05x7|csP4o1cp;V=bP7|kp7XC14$m@a2AAp~96tjc^f^$$K zhzD&kW(8tK*I9E!;Sey_~*$+%~^_ym;}rKiR3fr$n=qeD!dzet5X+T`gC5U7|_eJdIN< zkH<;g9HxEPJ~$pdo<7()sbgbPPN|i!G#y9dT?+EHmE@&ODe>33?sZ*BS)SOsOgA3& zVtP;Yo@SNlJ-2aNd#iz_7N4P4#n)}+H-M>Q8AKJ!QM|5uLBGX8Ov+AqWC=zf^M`%l30D=<3x ze^Hsg2JtZdhDUxuMo0Gp*7;8f|Ne}Q?l)rbSMA|p{B79q=K}sWqci6G3m9Eg;#+9C zoiQcr@g(A16Q@-iKv^T9xUfrO?2z26Zp!{D<{ued@T(z5ZaM%EfCC}9^zWD09|k7> zu*3fW_58f&`=`VI+jaQ#KV*pfk-*A zKc(T#j#bl(CFUrsbL zzcIQY&Wmsw9ynaMNcQ6$Uv7dAY) zl@%F~a5=4EEUlITPT4uq=hHaRupD%}Wc%P+6K5+WrOdlEXfufjwH!fj=Sb{{Mf1fY zU(#6x`zt??+yPt{go6v%iEo}LQ3QsEVLJ9ty7ULP`k>EN%fF2n$21byoD87?#JdN?xmGByLq@g1F`CvPoLm~hP&|qdR79HK-94KK!sjGk=pdpZDf`rE z%)nV3Idb?uoh*OCvVO@Z!rZ=gO)`f@`kHEAVBlZ@VXd#rI~BE6glldA8eIP=eiL`v;n85O-b;Q! zlN$s*3aeJ>)FCT34$mK=1)28Tmi>YbV~t(4<_(w2gVnIWNd&+ggf%J5ybaMyF-Q*o zD(5E7R}Z#PO*Py6zFSj56#xo;wxM$4bbt%a>mb}+4g5nwCq0U{pChe^9AaE5_=7Kf z=rD$J)2pg*X+G`e5KVo%bY#!VI;Y$2;@h=EWG0b^07GJ-c;u&)($axYC6+JF3~gi@ z2Xx{|%q7V9JIlrl?FtuKLd2H_qo=gDjMBI2jhvxHx|%f+YGmr~D)|H1Mef4_UHrF9 zKX9>Jl?J+mnUUpQfA1qH9ndfYs82MxD0oqoz-GCJ0X)2NDx#@lcB?halYQ}BGuZGm-OS?&kxM^KtWJha1aw{s{6pW*!xU(yVSR)Vn>)Zy(QYr zHQgi{D+Jut#hh3GX5!iK-rKXH+Fi_0aI>kc2E}gRMAkQIt|{(=X~}!zj3jzY->|S?(fextj3>zgCtm$7TXaB)+LEX z>U%a~io4r>o`lWVPW_GhAh&Z;Xp~S7gYp;w+$HrY8(`q@(;zh93=R)pkD5A=t#3Y{ z2c(-;9^fPht#^GCyT*?K&w71}2H;|76#u(D3H?tQ!LNXQ7=C+P|5YvKzklp!HjrNi z`_TWC8T<;^hvBbu+cErhGW$6-_}f~u=zkyuzZ&*o_$$4241bJb{|4CSf2~;<( z#QuPD{-|mEe&PP10>2&=VEB{Ho$saXAAx^Cfq%d`e|QJ~Ko5Qn0{#KFe>?2+{haXc zJM&LtpYPA6|MPaHV`2V}Rj)mYixx}FaPGIit$IaBWM~2M26U}H!7`3~3&BVV(Lawy z9aXz&_GaspBS$!BDYnKzN5tAJ2!V|uiOrS`C)~^W!TEru53kwHb8Ge;E#>Kqkmqv; zvrr2?xmhTSly~-&2Mg`1t)so&)27&18TX_$90*l)2D(*lYiNC|l(Q55c;MaMmu%Qi z%)EXF@FOytrq!gMnDg(m$v0zVeYQOrdW}jI&G!f*J&tuvQT(?(Zy7nlp%}+96MZO8gdns6S%xOHUgkW_Q# z(4gGnc564y`E-s8ZZ%z&+dfJ|FOAN>xzcoFH2VokOxv<6evlTFD9-KM zWUPvms5u46zWCu-q!0L~PR16HDT?%|lP$92Z8;SauUU#Sirh=bp{>)T)N8ir@{cGo zPIzxaTB}?TQy^CwIq))f;VOgJb;zf~r=UWx zt|{00YMsOqU=3-z-8yc1<`BMZ71hRAZXD0m5;p^%XqPSANWq>1_oMOyAq$x{ZjW)* zmLbrV!RgU6gbi`8K#is^c6R2Pt|U&ccV}4|{wkYa?z;EEr%$Z|DI%6@8dk!Y`>YH= z2wX=whD+H5Eg~paT!W{&Sq&TbT$i6A%mYwx_gs19+iu>t`gJ+t=j)Oc92Kisqke`v znye%Bxsy2M_Yh5mB=pjem30DBYKZ9Ip|ba+(b5k^SR+WZgOlbNOYw=5@>b2m&v%W0 z&yC(FdhkR| zh51~IGQT{H_v|V&fW>q2#s)AVWX*0t4?#xZP2-&HU`?(X8J#JGG+%ge>em76>7~2H z1c8KWcSS>Z%KVzZ9k~bv6obq}CzTtINR-x!L|ShTz5YI+wXL3B`QR=9YTR%J0rghR zbG}b8TVJUmf`HzZtkTpHHtVVqYS_$6c68}qb4!#(b^yk>ccAiee*Q*9PXiVWr~(8l zw3Gs-t@Unwp5(WnWa@1qBIiB~{or@PQ_?ySkv%7M$3i^qucnrHqzM_(Y)&RbF)K%Rmmh%0DQ_tNgAAku*dN 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

fwy2<7q zDUf=Nh}CM0fE@!qOXtsLFjQ>$FZ2yw)|OeY5B{dg9ZVSOX9Cpw#z`7!j7aa6(6{a$4FhsBu72G5Gt3ar2e+Aijb6l&EFnK zgbkye>R;w7rO=AxuAv~#+b(Q)j+Y#7Nn#15O)!WjhFJ*}vDBRwPW>2EYH(nfeo!Zs zP>e)wKb@f2;oB4uV%v|fqUSmpTAMbtW&7L?cX91cn|dOtrX8qUXNP$Ynz=hWo;#yF zeTFVdpOqs}-XfM|7RKBO^#dvUB!<69j0Pv*DFGL^*?2Xg4WcIZ81Ze(rMDXv=B5gr z<9w|<*ww7#S7KM{6vkIj!s}wu^RAU+} z_+K98!d36qresKVe%TT&ENQq3Sg+fC`0q?GZUKkR?AYGfa}DTY*=Qf_l#vck<3kiw z)H!4f1H7PuBOsy~O!MjSBzK9$Qk%vRJ3`)gI9gz7WnCOjxn86hH5G zgD2-V=1O-9F}V6$>;W)YiiN_{+hFUvN-Wr1Z;}-~3CYu48b8G4sV%T5_<6e;?41i< zjxjYG61gXMT!-zH)h1a@ zzc@*6>iAi^b8nC5UC}~_MsyT}^^(~wsL=@x7|M-zzxr9lm%+QP@EdH+{C$fX`+;Q( z6QV%O;N3e8@LmWGzhK^LA0Q5QC4-Bno^1V-xPGwh2!?h-RL=3UU`*a$N(Myz9YXbe zGV-Jy;QRF*wM$$KEGL|k|4~5yvx}Jma+ZO|rC!)gkGV|_;9cFr$DKk)>BWN~(;Eu9o zomyAR7ZTY?Mw9i78#mq71J%i>vEvcO@L4c;SS7$}G0MR95G$TbzhB=wK7TeZ^v?q7 ziLHMk4zvAQPw@rFW*L67mPFv?af}v=)9%L|y^|wk-!-aR|Llg~K39@`R9^xSxPBM= z%b2T` zPo$0~?@P|iQG+?;Gs3Zeo zXbX#;hntIv%fKX0ES1%mVtNWu);V)bS{0CYn#r{ph#h?w# z6aK&5lWm|BG){A;kL3ay6mvhXy9Cy3k{vbYCUbt;C6TYg5`sON*TKz6$DWUL*^*E{x;lj@bJ z`4&lWklridPA3CY5l%c%$^n1Pm&%PAQplvCa{3Hib?3gz27P1s91=R+^1+6H6s zX}R-IsHye2ggRzPgJVhe%bq-+OzFo;e9%7PGPj1Aleg=h9i%k;OnTRh-aB0J;p<7I zw8+$Jd~qD@_#kGO7hC21FO8qv#;DYxlStWbP@_fqy&$j#>utVouc?l14i?Wu0^zp8s}gvot|7hnFNC zNiTi`YloFI@S9Z0z=e9|Zi9c5kfAEH;n^;ShS75#=|_e?dpF__yh8mH z@lHAhs3jbuCqTWS2G)ou-vDLCDK&o^B(jY&xUPFgnaQZU-r>t&d!_}x_}*z9Py%dJ zo~*7^s3fb$Hh);$S4u^*)^*L&3AJx#kqJWrpA%fu8vwaoV>(@ZVbbi9->7^y3+t`j zOdyK|8R>PHS>NTy{V24#@~TB{Ai*l~%)=y%p0F5LwJi!m{hd_H>zP%|P&@OPnn{(p z)I&0*F`{<3ibJlFcSRyTh*HXKypRwbS9wdOry13AL+CQ-QzNa5dJR*(3EzXU-09Q2 z$F+?M%r#y(sagSlaDIZ#Eb7m`f~_?_>%~Z)9B&#@`Qs7Z=aw|SF4b$MV9zTjxm^UQ&3@=GE<<&7(JLN9}mZ)$p_t0B4G1_N`E7X0ysF_!kS!O6?rx z)DQcdDb-YS_Km5JRCsx{yrWTQgN%2B{gCK!8Y`28OY9u+Ko1@@IW}nN?#MruYBeF; vmz$7%8{kQOm<9x(L!%4$|Fbnt&IXRo?v5s=upAsL9Bk~cBqSnoqOku9foUHh literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v4.9.3/audits/2022-10-Checkpoints.pdf b/lib/openzeppelin-contracts-v4.9.3/audits/2022-10-Checkpoints.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7e0d08387ad3be0a3e74201566eca3167aead1c2 GIT binary patch literal 155606 zcmcFr2V4}%(iagF6c8myMiCTn7j~CjSjiwDIp-`nrzJ-NK@m8KN|Y=a$r%wzB1!Th zK{ApgXZ!~6PVS!Gd%W-7@8>$rbamCgs=8~sr>lov=8iB30%pgh{~8ybgbSf%rM0?e zip#}?%c9_HZ9vN+qibYfhsz>vqHjm5PKyBQRDOpncLf$SXtUJ0;cJ4M27%U6g?Z z!0*>g*dXj+7=i!A4$yw@;eRm{ z9LWYovi{J~(h6l@2h!CCx-y`pt~ubaBYS_>`R54!irxws7cSq&1xU}>K+nwD3b39X z$lT(@(#TE^;CN{Aqapkk zCH^Yj&fdZTkaF1IXz2f&1}NQo<^~`uLlDr-4*J+(r#^}u|E8tArM(?sY-?K+2cSQJ z4DBuT{^%Y@0p>3ZU`Pa@8WM^;7^<4Ing^r%=->A+bD-hxV_e7yB_e;&Q4dG1E(FYa zSkTj@g&Z_u;s5=PApg;wgPSVS_e_DFen@Eof&-%$!O9AUK_O5!Bn*aN<)DSI9mRnp=^wFZON+bt`1d4;!PZ#keEsozv=+hj z(EIrK<7sT`*kLL}NfZg)7_`m~>>06;Wy9R4i>)VY zH(4oeIP}!Dj4X@Gzp?txb4)&KtBtD#N>J(HH1 zMJb~O&;1_Tp4Tg!W0*J8y;GE*=wQt772`w8^S1dCX&p~3YI>N?Q=>mizv5o?MW7?2fpRQ_nRMMuN+Uc>+eV4mg>VCb_LU3q!TI zlnM=?j9EJ!Et>h(vln(Bf7#uTD4WKJh8y2ho2{F!jbnO?c%RstfH80G5~*Qd%dc@M zc%3$Oufwc^gm{lk?4p&ed}q!F{sjNB>iAHB`#EQBTD*mKu+tK)RY=rkZ-xIxbJ~p! zl~f6x^?le*$ajz6Om=pDhIDgK1nI-R37Ydl&h)|}j}c#3aKf)^E9;^gg?fn#@n5Lr zbkA>>*B523F?)WRRUTW##qt)?8`!4!Agd={q?unoZsCgPZZh9+v$J=1T++)mGVU=S zEtusAwDeG4eDVJBEctR|2dwm45BEFr_mve6^E6+CAzlaL;d|%)J~9r%@$Vz!#}wsY z$k_rh=J#i{q=CMPu7H&j5TXx;790r&L)qbQAU<%gLBJdwNOlAp5GH^L$x&#cJ)EiF zvd9_OS=rm_0Z;YAmXN~RgVyibCnlq8^d*LPGeuZQ0uSM_Vi5RfLD_Dw<;PK%t>3x(0%+x2b;@n ze=^@1KU%W!3HQuR%DFa{#67Ffl7QD6O0m^$uG<6heJ*(G!!v#vG*a5%I`(6~Jp%P0 z)I1z$HfFJHX>GBp!lsHnn`&yyz-`-LcX4Xb;~P

2ojH?x0tMLX1p#1!i~6c>Ik8Oj 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 literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v4.9.3/audits/2022-10-ERC4626.pdf b/lib/openzeppelin-contracts-v4.9.3/audits/2022-10-ERC4626.pdf new file mode 100644 index 0000000000000000000000000000000000000000..154fe75212e317a87cfa249b9101a04e789281bd GIT binary patch literal 204184 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 P3ADOAJw3B!^LYOO&o2YP literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v4.9.3/audits/2023-05-v4.9.pdf b/lib/openzeppelin-contracts-v4.9.3/audits/2023-05-v4.9.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e7e6d715b04b0fffb92f424b63120a01e2207f72 GIT binary patch literal 483005 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 literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v4.9.3/audits/README.md b/lib/openzeppelin-contracts-v4.9.3/audits/README.md new file mode 100644 index 0000000..c629f51 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/audits/README.md @@ -0,0 +1,16 @@ +# Audits + +| 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) | + +# Formal Verification + +| Date | Version | Commit | Tool | Scope | Links | +| ------------ | ------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | +| May 2022 | v4.7.0 | `109778c` | Certora | Initializable, GovernorPreventLateQuorum, ERC1155Burnable, ERC1155Pausable, ERC1155Supply, ERC1155Holder, ERC1155Receiver | [🔗](../certora/reports/2022-05.pdf) | +| March 2022 | v4.4.0 | `4088540` | Certora | ERC20Votes, ERC20FlashMint, ERC20Wrapper, TimelockController, ERC721Votes, Votes, AccessControl, ERC1155 | [🔗](../certora/reports/2022-03.pdf) | +| October 2021 | v4.4.0 | `4088540` | Certora | Governor, GovernorCountingSimple, GovernorProposalThreshold, GovernorTimelockControl, GovernorVotes, GovernorVotesQuorumFraction | [🔗](../certora/reports/2021-10.pdf) | diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/.gitignore b/lib/openzeppelin-contracts-v4.9.3/certora/.gitignore new file mode 100644 index 0000000..893adcd --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/.gitignore @@ -0,0 +1 @@ +patched diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/Makefile b/lib/openzeppelin-contracts-v4.9.3/certora/Makefile new file mode 100644 index 0000000..50fd6da --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/Makefile @@ -0,0 +1,54 @@ +default: help + +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)" + +clean: + git clean -fdX + +FORCE: ; diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/README.md b/lib/openzeppelin-contracts-v4.9.3/certora/README.md new file mode 100644 index 0000000..cd85ba3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/README.md @@ -0,0 +1,60 @@ +# Running the certora verification tool + +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). + +## 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 Certora Verification Tool proves specs for contracts, which are defined by the `./specs.json` file along with their pre-configured options. + +The verification script `./run.js` is used to submit verification jobs to the Certora Verification service. + +You can run it from the root of the repository with the following command: + +```bash +node certora/run.js [[CONTRACT_NAME:]SPEC_NAME] [OPTIONS...] +``` + +Where: + +- `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. + +> **Note** +> A single spec may be configured to run for multiple contracts, whereas a single contract may run multiple specs. + +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. + +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: + +```bash +make -C certora apply +``` + +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 +``` diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/diff/token_ERC721_ERC721.sol.patch b/lib/openzeppelin-contracts-v4.9.3/certora/diff/token_ERC721_ERC721.sol.patch new file mode 100644 index 0000000..c3eae35 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol new file mode 100644 index 0000000..29fd3a7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/AccessControlHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/AccessControlHarness.sol new file mode 100644 index 0000000..0cb1e55 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/DoubleEndedQueueHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/DoubleEndedQueueHarness.sol new file mode 100644 index 0000000..b4f0bc8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20FlashMintHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20FlashMintHarness.sol new file mode 100644 index 0000000..119eb47 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20PermitHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20PermitHarness.sol new file mode 100644 index 0000000..dd0aaca --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20PermitHarness.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../patched/token/ERC20/extensions/ERC20Permit.sol"; + +contract ERC20PermitHarness is 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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20WrapperHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC20WrapperHarness.sol new file mode 100644 index 0000000..50a96cc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC3156FlashBorrowerHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC3156FlashBorrowerHarness.sol new file mode 100644 index 0000000..0ad29a1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC721Harness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC721Harness.sol new file mode 100644 index 0000000..3307369 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC721ReceiverHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/ERC721ReceiverHarness.sol new file mode 100644 index 0000000..7e5739e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/EnumerableMapHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/EnumerableMapHarness.sol new file mode 100644 index 0000000..3bcf1b5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/EnumerableSetHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/EnumerableSetHarness.sol new file mode 100644 index 0000000..64383e6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/InitializableHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/InitializableHarness.sol new file mode 100644 index 0000000..19437e0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/Ownable2StepHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/Ownable2StepHarness.sol new file mode 100644 index 0000000..4d30e50 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/OwnableHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/OwnableHarness.sol new file mode 100644 index 0000000..93cbb47 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/PausableHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/PausableHarness.sol new file mode 100644 index 0000000..37c5d59 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/TimelockControllerHarness.sol b/lib/openzeppelin-contracts-v4.9.3/certora/harnesses/TimelockControllerHarness.sol new file mode 100644 index 0000000..d1ea990 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/reports/2021-10.pdf b/lib/openzeppelin-contracts-v4.9.3/certora/reports/2021-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..22df9c61e6a9f74b29f90b6e36bd3d04f99756f5 GIT binary patch literal 92882 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 aXJ@ZxYwu)>@+&A9#pUoWT@sTO$NL{da>MEX literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/reports/2022-03.pdf b/lib/openzeppelin-contracts-v4.9.3/certora/reports/2022-03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b6ff81d1812c808e2f683c1e5fe10abf71ba5438 GIT binary patch literal 199401 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

E02esqZ$^2gTs{2 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 literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/reports/2022-05.pdf b/lib/openzeppelin-contracts-v4.9.3/certora/reports/2022-05.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f24a44910c4fba449300987456b5f440e7f99511 GIT binary patch literal 132223 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%0D7|ieYKPVYBX59b!U}f9eB5UvK%HwkWL{dR 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 UVZ$VVhf9Eu51oMlq$-2{KaJIBBLDyZ literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/run.js b/lib/openzeppelin-contracts-v4.9.3/certora/run.js new file mode 100755 index 0000000..fdee42d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/run.js @@ -0,0 +1,146 @@ +#!/usr/bin/env node + +// USAGE: +// 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 proc = require('child_process'); +const { PassThrough } = require('stream'); +const events = require('events'); + +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); +} + +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; + } +} + +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 +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 job id, print the output link + stream.on('data', function logStatusUrl(data) { + 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); + } + }); + + // 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:\/\/prover.certora.com\/output\/\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:', + url ? `[link](${url?.replace('/output/', '/jobStatus/')})` : 'error', + url ? `[link](${url})` : 'error', + ), + ); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs.json b/lib/openzeppelin-contracts-v4.9.3/certora/specs.json new file mode 100644 index 0000000..3e5acb5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs.json @@ -0,0 +1,86 @@ +[ + { + "spec": "Pausable", + "contract": "PausableHarness", + "files": ["certora/harnesses/PausableHarness.sol"] + }, + { + "spec": "AccessControl", + "contract": "AccessControlHarness", + "files": ["certora/harnesses/AccessControlHarness.sol"] + }, + { + "spec": "AccessControlDefaultAdminRules", + "contract": "AccessControlDefaultAdminRulesHarness", + "files": ["certora/harnesses/AccessControlDefaultAdminRulesHarness.sol"] + }, + { + "spec": "DoubleEndedQueue", + "contract": "DoubleEndedQueueHarness", + "files": ["certora/harnesses/DoubleEndedQueueHarness.sol"] + }, + { + "spec": "Ownable", + "contract": "OwnableHarness", + "files": ["certora/harnesses/OwnableHarness.sol"] + }, + { + "spec": "Ownable2Step", + "contract": "Ownable2StepHarness", + "files": ["certora/harnesses/Ownable2StepHarness.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"] + }, + { + "spec": "ERC20Wrapper", + "contract": "ERC20WrapperHarness", + "files": [ + "certora/harnesses/ERC20PermitHarness.sol", + "certora/harnesses/ERC20WrapperHarness.sol" + ], + "options": [ + "--link ERC20WrapperHarness:_underlying=ERC20PermitHarness", + "--optimistic_loop" + ] + }, + { + "spec": "ERC721", + "contract": "ERC721Harness", + "files": ["certora/harnesses/ERC721Harness.sol", "certora/harnesses/ERC721ReceiverHarness.sol"], + "options": ["--optimistic_loop"] + }, + { + "spec": "Initializable", + "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", + "files": ["certora/harnesses/TimelockControllerHarness.sol"], + "options": ["--optimistic_hashing", "--optimistic_loop"] + } +] diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/AccessControl.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/AccessControl.spec new file mode 100644 index 0000000..cd5af2a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/AccessControl.spec @@ -0,0 +1,126 @@ +import "helpers/helpers.spec" +import "methods/IAccessControl.spec" + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Definitions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition DEFAULT_ADMIN_ROLE() returns bytes32 = 0x0000000000000000000000000000000000000000000000000000000000000000; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Identify entrypoints: only grantRole, revokeRole and renounceRole can alter permissions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyGrantCanGrant(env e, method f, bytes32 role, address account) { + calldataarg args; + + bool hasRoleBefore = hasRole(role, account); + f(e, args); + bool hasRoleAfter = hasRole(role, account); + + assert ( + !hasRoleBefore && + hasRoleAfter + ) => ( + f.selector == grantRole(bytes32, address).selector + ); + + assert ( + hasRoleBefore && + !hasRoleAfter + ) => ( + f.selector == revokeRole(bytes32, address).selector || + f.selector == renounceRole(bytes32, address).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: grantRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule grantRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + grantRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> isCallerAdmin; + + // effect + assert success => hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: revokeRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule revokeRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + revokeRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> isCallerAdmin; + + // effect + assert success => !hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: renounceRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule renounceRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + renounceRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> account == e.msg.sender; + + // effect + assert success => !hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/AccessControlDefaultAdminRules.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/AccessControlDefaultAdminRules.spec new file mode 100644 index 0000000..a4baa18 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/DoubleEndedQueue.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/DoubleEndedQueue.spec new file mode 100644 index 0000000..2a19677 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/DoubleEndedQueue.spec @@ -0,0 +1,366 @@ +import "helpers/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"; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20.spec new file mode 100644 index 0000000..3bd2b38 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20.spec @@ -0,0 +1,414 @@ +import "helpers/helpers.spec" +import "methods/IERC20.spec" +import "methods/IERC2612.spec" + +methods { + // non standard ERC20 functions + increaseAllowance(address,uint256) returns (bool) + decreaseAllowance(address,uint256) returns (bool) + + // exposed for FV + mint(address,uint256) + burn(address,uint256) +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20FlashMint.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20FlashMint.spec new file mode 100644 index 0000000..70a7c07 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20FlashMint.spec @@ -0,0 +1,48 @@ +import "helpers/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20Wrapper.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20Wrapper.spec new file mode 100644 index 0000000..badfa7a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC20Wrapper.spec @@ -0,0 +1,198 @@ +import "helpers/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC721.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC721.spec new file mode 100644 index 0000000..9db13f4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/ERC721.spec @@ -0,0 +1,589 @@ +import "helpers/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/EnumerableMap.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/EnumerableMap.spec new file mode 100644 index 0000000..dea5d85 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/EnumerableMap.spec @@ -0,0 +1,334 @@ +import "helpers/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/EnumerableSet.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/EnumerableSet.spec new file mode 100644 index 0000000..d63c556 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/EnumerableSet.spec @@ -0,0 +1,247 @@ +import "helpers/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 + ); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/Initializable.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/Initializable.spec new file mode 100644 index 0000000..0e0b1b7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/Initializable.spec @@ -0,0 +1,165 @@ +import "helpers/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"; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/Ownable.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/Ownable.spec new file mode 100644 index 0000000..4bf9e30 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/Ownable.spec @@ -0,0 +1,78 @@ +import "helpers/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) { + address oldCurrent = owner(); + + method f; 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/lib/openzeppelin-contracts-v4.9.3/certora/specs/Ownable2Step.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/Ownable2Step.spec new file mode 100644 index 0000000..47b1b8d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/Ownable2Step.spec @@ -0,0 +1,108 @@ +import "helpers/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/Pausable.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/Pausable.spec new file mode 100644 index 0000000..aea3800 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/Pausable.spec @@ -0,0 +1,96 @@ +import "helpers/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()"; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/TimelockController.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/TimelockController.spec new file mode 100644 index 0000000..05ecb13 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/TimelockController.spec @@ -0,0 +1,275 @@ +import "helpers/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/helpers/helpers.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/helpers/helpers.spec new file mode 100644 index 0000000..24842d6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/helpers/helpers.spec @@ -0,0 +1 @@ +definition nonpayable(env e) returns bool = e.msg.value == 0; diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IAccessControl.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IAccessControl.spec new file mode 100644 index 0000000..4d41ffd --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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) +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IAccessControlDefaultAdminRules.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IAccessControlDefaultAdminRules.spec new file mode 100644 index 0000000..a9dd08b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC20.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC20.spec new file mode 100644 index 0000000..cfa454e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC2612.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC2612.spec new file mode 100644 index 0000000..0c1689d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC3156.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC3156.spec new file mode 100644 index 0000000..18c10c5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC5313.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC5313.spec new file mode 100644 index 0000000..d4c5a04 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC5313.spec @@ -0,0 +1,3 @@ +methods { + owner() returns (address) envfree +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC721.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IERC721.spec new file mode 100644 index 0000000..e6d4e1e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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) +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IOwnable.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IOwnable.spec new file mode 100644 index 0000000..cfa15f9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IOwnable.spec @@ -0,0 +1,5 @@ +methods { + owner() returns (address) envfree + transferOwnership(address) + renounceOwnership() +} diff --git a/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IOwnable2Step.spec b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IOwnable2Step.spec new file mode 100644 index 0000000..c8e671d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/certora/specs/methods/IOwnable2Step.spec @@ -0,0 +1,7 @@ +methods { + owner() returns (address) envfree + pendingOwner() returns (address) envfree + transferOwnership(address) + acceptOwnership() + renounceOwnership() +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControl.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControl.sol new file mode 100644 index 0000000..0ec6be3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControl.sol @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; +import "../utils/Context.sol"; +import "../utils/Strings.sol"; +import "../utils/introspection/ERC165.sol"; + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * 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)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * 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. We recommend using {AccessControlDefaultAdminRules} + * to enforce additional security measures for this role. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address => bool) members; + bytes32 adminRole; + } + + mapping(bytes32 => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with a standardized message including the required role. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + * + * _Available since v4.1._ + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual override returns (bool) { + return _roles[role].members[account]; + } + + /** + * @dev Revert with a standard message if `_msgSender()` is missing `role`. + * Overriding this function changes the behavior of the {onlyRole} modifier. + * + * Format of the revert message is described in {_checkRole}. + * + * _Available since v4.6._ + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Revert with a standard message if `account` is missing `role`. + * + * The format of the revert reason is given by the following regular expression: + * + * /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert( + string( + abi.encodePacked( + "AccessControl: account ", + Strings.toHexString(account), + " is missing role ", + Strings.toHexString(uint256(role), 32) + ) + ) + ); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual override returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address account) public virtual override { + require(account == _msgSender(), "AccessControl: can only renounce roles for self"); + + _revokeRole(role, account); + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. Note that unlike {grantRole}, this function doesn't perform any + * checks on the calling account. + * + * May emit a {RoleGranted} event. + * + * [WARNING] + * ==== + * This function should only be called from the constructor when setting + * up the initial roles for the system. + * + * Using this function in any other way is effectively circumventing the admin + * system imposed by {AccessControl}. + * ==== + * + * NOTE: This function is deprecated in favor of {_grantRole}. + */ + function _setupRole(bytes32 role, address account) internal virtual { + _grantRole(role, account); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Grants `role` to `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual { + if (!hasRole(role, account)) { + _roles[role].members[account] = true; + emit RoleGranted(role, account, _msgSender()); + } + } + + /** + * @dev Revokes `role` from `account`. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual { + if (hasRole(role, account)) { + _roles[role].members[account] = false; + emit RoleRevoked(role, account, _msgSender()); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlCrossChain.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlCrossChain.sol new file mode 100644 index 0000000..95be509 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlCrossChain.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (access/AccessControlCrossChain.sol) + +pragma solidity ^0.8.4; + +import "./AccessControl.sol"; +import "../crosschain/CrossChainEnabled.sol"; + +/** + * @dev An extension to {AccessControl} with support for cross-chain access management. + * For each role, is extension implements an equivalent "aliased" role that is used for + * restricting calls originating from other chains. + * + * For example, if a function `myFunction` is protected by `onlyRole(SOME_ROLE)`, and + * if an address `x` has role `SOME_ROLE`, it would be able to call `myFunction` directly. + * A wallet or contract at the same address on another chain would however not be able + * to call this function. In order to do so, it would require to have the role + * `_crossChainRoleAlias(SOME_ROLE)`. + * + * This aliasing is required to protect against multiple contracts living at the same + * address on different chains but controlled by conflicting entities. + * + * _Available since v4.6._ + */ +abstract contract AccessControlCrossChain is AccessControl, CrossChainEnabled { + bytes32 public constant CROSSCHAIN_ALIAS = keccak256("CROSSCHAIN_ALIAS"); + + /** + * @dev See {AccessControl-_checkRole}. + */ + function _checkRole(bytes32 role) internal view virtual override { + if (_isCrossChain()) { + _checkRole(_crossChainRoleAlias(role), _crossChainSender()); + } else { + super._checkRole(role); + } + } + + /** + * @dev Returns the aliased role corresponding to `role`. + */ + function _crossChainRoleAlias(bytes32 role) internal pure virtual returns (bytes32) { + return role ^ CROSSCHAIN_ALIAS; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlDefaultAdminRules.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlDefaultAdminRules.sol new file mode 100644 index 0000000..9de3200 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlDefaultAdminRules.sol @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.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. + * * 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: + * + * ```solidity + * contract MyToken is AccessControlDefaultAdminRules { + * constructor() AccessControlDefaultAdminRules( + * 3 days, + * msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder + * ) {} + * } + * ``` + * + * _Available since v4.9._ + */ +abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl { + // pending admin pair read/written together frequently + address private _pendingDefaultAdmin; + uint48 private _pendingDefaultAdminSchedule; // 0 == unset + + 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} and {defaultAdmin} address. + */ + constructor(uint48 initialDelay, address initialDefaultAdmin) { + require(initialDefaultAdmin != address(0), "AccessControl: 0 default admin"); + _currentDelay = initialDelay; + _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC5313-owner}. + */ + function owner() public view virtual returns (address) { + return defaultAdmin(); + } + + /// + /// Override AccessControl role management + /// + + /** + * @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-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 renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { + (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin(); + require( + newDefaultAdmin == address(0) && _isScheduleSet(schedule) && _hasSchedulePassed(schedule), + "AccessControl: only can renounce in two delayed steps" + ); + delete _pendingDefaultAdminSchedule; + } + super.renounceRole(role, account); + } + + /** + * @dev See {AccessControl-_grantRole}. + * + * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the + * role has been previously renounced. + * + * 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 {AccessControl-_revokeRole}. + */ + function _revokeRole(bytes32 role, address account) internal virtual override { + if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { + delete _currentDefaultAdmin; + } + 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); + } + + /// + /// AccessControlDefaultAdminRules accessors + /// + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdmin() public view virtual returns (address) { + return _currentDefaultAdmin; + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + 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/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlEnumerable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlEnumerable.sol new file mode 100644 index 0000000..354e1be --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/AccessControlEnumerable.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControlEnumerable.sol"; +import "./AccessControl.sol"; +import "../utils/structs/EnumerableSet.sol"; + +/** + * @dev Extension of {AccessControl} that allows enumerating the members of each role. + */ +abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { + using EnumerableSet for EnumerableSet.AddressSet; + + mapping(bytes32 => EnumerableSet.AddressSet) private _roleMembers; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) public view virtual override returns (address) { + return _roleMembers[role].at(index); + } + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) public view virtual override returns (uint256) { + return _roleMembers[role].length(); + } + + /** + * @dev Overload {_grantRole} to track enumerable memberships + */ + function _grantRole(bytes32 role, address account) internal virtual override { + super._grantRole(role, account); + _roleMembers[role].add(account); + } + + /** + * @dev Overload {_revokeRole} to track enumerable memberships + */ + function _revokeRole(bytes32 role, address account) internal virtual override { + super._revokeRole(role, account); + _roleMembers[role].remove(account); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControl.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControl.sol new file mode 100644 index 0000000..f773ecc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControl.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol) + +pragma solidity ^0.8.0; + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + * + * _Available since v3.1._ + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `account`. + */ + function renounceRole(bytes32 role, address account) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControlDefaultAdminRules.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControlDefaultAdminRules.sol new file mode 100644 index 0000000..434324e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControlDefaultAdminRules.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated 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 {defaultAdmin} transfer is started, setting `newAdmin` as the next + * address to become the {defaultAdmin} by calling {acceptDefaultAdminTransfer} only after `acceptSchedule` + * passes. + */ + event DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule); + + /** + * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule. + */ + 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. + */ + function defaultAdmin() external view returns (address); + + /** + * @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 newAdmin, uint48 acceptSchedule); + + /** + * @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 defaultAdminDelay() external view returns (uint48); + + /** + * @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 {defaultAdmin}. + * + * Emits a DefaultAdminRoleChangeStarted event. + */ + function beginDefaultAdminTransfer(address newAdmin) external; + + /** + * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. + * + * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function. + * + * Requirements: + * + * - 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 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: + * + * - Only can be called by the current {defaultAdmin}. + * + * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event. + */ + 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/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControlEnumerable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControlEnumerable.sol new file mode 100644 index 0000000..61aaf57 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/IAccessControlEnumerable.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) + +pragma solidity ^0.8.0; + +import "./IAccessControl.sol"; + +/** + * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. + */ +interface IAccessControlEnumerable is IAccessControl { + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) external view returns (address); + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/access/Ownable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/Ownable.sol new file mode 100644 index 0000000..c181ea1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/Ownable.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the deployer as the initial owner. + */ + constructor() { + _transferOwnership(_msgSender()); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + require(owner() == _msgSender(), "Ownable: caller is not the owner"); + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "Ownable: new owner is the zero address"); + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/access/Ownable2Step.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/access/Ownable2Step.sol new file mode 100644 index 0000000..e6f6998 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/Ownable2Step.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol) + +pragma solidity ^0.8.0; + +import "./Ownable.sol"; + +/** + * @dev Contract module which provides access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * By default, the owner account will be the one that deploys the contract. This + * can later be changed with {transferOwnership} and {acceptOwnership}. + * + * This module is used through inheritance. It will make available all functions + * from parent (Ownable). + */ +abstract contract Ownable2Step is Ownable { + address private _pendingOwner; + + event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Returns the address of the pending owner. + */ + function pendingOwner() public view virtual returns (address) { + return _pendingOwner; + } + + /** + * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual override onlyOwner { + _pendingOwner = newOwner; + emit OwnershipTransferStarted(owner(), newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual override { + delete _pendingOwner; + super._transferOwnership(newOwner); + } + + /** + * @dev The new owner accepts the ownership transfer. + */ + function acceptOwnership() public virtual { + address sender = _msgSender(); + require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner"); + _transferOwnership(sender); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/access/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/access/README.adoc new file mode 100644 index 0000000..80ca002 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/access/README.adoc @@ -0,0 +1,27 @@ += Access Control + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access + +This directory provides ways to restrict who can access the functions of a contract or when they can do it. + +- {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. +- {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. + +== Authorization + +{{Ownable}} + +{{Ownable2Step}} + +{{IAccessControl}} + +{{AccessControl}} + +{{AccessControlCrossChain}} + +{{IAccessControlEnumerable}} + +{{AccessControlEnumerable}} + +{{AccessControlDefaultAdminRules}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/CrossChainEnabled.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/CrossChainEnabled.sol new file mode 100644 index 0000000..4c9b9e5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/CrossChainEnabled.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (crosschain/CrossChainEnabled.sol) + +pragma solidity ^0.8.4; + +import "./errors.sol"; + +/** + * @dev Provides information for building cross-chain aware contracts. This + * abstract contract provides accessors and modifiers to control the execution + * flow when receiving cross-chain messages. + * + * Actual implementations of cross-chain aware contracts, which are based on + * this abstraction, will have to inherit from a bridge-specific + * specialization. Such specializations are provided under + * `crosschain//CrossChainEnabled.sol`. + * + * _Available since v4.6._ + */ +abstract contract CrossChainEnabled { + /** + * @dev Throws if the current function call is not the result of a + * cross-chain execution. + */ + modifier onlyCrossChain() { + if (!_isCrossChain()) revert NotCrossChainCall(); + _; + } + + /** + * @dev Throws if the current function call is not the result of a + * cross-chain execution initiated by `account`. + */ + modifier onlyCrossChainSender(address expected) { + address actual = _crossChainSender(); + if (expected != actual) revert InvalidCrossChainSender(actual, expected); + _; + } + + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message. + */ + function _isCrossChain() internal view virtual returns (bool); + + /** + * @dev Returns the address of the sender of the cross-chain message that + * triggered the current function call. + * + * IMPORTANT: Should revert with `NotCrossChainCall` if the current function + * call is not the result of a cross-chain message. + */ + function _crossChainSender() internal view virtual returns (address); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/README.adoc new file mode 100644 index 0000000..266b153 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/README.adoc @@ -0,0 +1,34 @@ += Cross Chain Awareness + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/crosschain + +This directory provides building blocks to improve cross-chain awareness of smart contracts. + +- {CrossChainEnabled} is an abstraction that contains accessors and modifiers to control the execution flow when receiving cross-chain messages. + +== CrossChainEnabled specializations + +The following specializations of {CrossChainEnabled} provide implementations of the {CrossChainEnabled} abstraction for specific bridges. This can be used to complex cross-chain aware components such as {AccessControlCrossChain}. + +{{CrossChainEnabledAMB}} + +{{CrossChainEnabledArbitrumL1}} + +{{CrossChainEnabledArbitrumL2}} + +{{CrossChainEnabledOptimism}} + +{{CrossChainEnabledPolygonChild}} + +== Libraries for cross-chain + +In addition to the {CrossChainEnabled} abstraction, cross-chain awareness is also available through libraries. These libraries can be used to build complex designs such as contracts with the ability to interact with multiple bridges. + +{{LibAMB}} + +{{LibArbitrumL1}} + +{{LibArbitrumL2}} + +{{LibOptimism}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/amb/CrossChainEnabledAMB.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/amb/CrossChainEnabledAMB.sol new file mode 100644 index 0000000..e69355d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/amb/CrossChainEnabledAMB.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/amb/CrossChainEnabledAMB.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "./LibAMB.sol"; + +/** + * @dev https://docs.tokenbridge.net/amb-bridge/about-amb-bridge[AMB] + * specialization or the {CrossChainEnabled} abstraction. + * + * As of february 2020, AMB bridges are available between the following chains: + * + * - https://docs.tokenbridge.net/eth-xdai-amb-bridge/about-the-eth-xdai-amb[ETH ⇌ xDai] + * - https://docs.tokenbridge.net/eth-qdai-bridge/about-the-eth-qdai-amb[ETH ⇌ qDai] + * - https://docs.tokenbridge.net/eth-etc-amb-bridge/about-the-eth-etc-amb[ETH ⇌ ETC] + * - https://docs.tokenbridge.net/eth-bsc-amb/about-the-eth-bsc-amb[ETH ⇌ BSC] + * - https://docs.tokenbridge.net/eth-poa-amb-bridge/about-the-eth-poa-amb[ETH ⇌ POA] + * - https://docs.tokenbridge.net/bsc-xdai-amb/about-the-bsc-xdai-amb[BSC ⇌ xDai] + * - https://docs.tokenbridge.net/poa-xdai-amb/about-the-poa-xdai-amb[POA ⇌ xDai] + * - https://docs.tokenbridge.net/rinkeby-xdai-amb-bridge/about-the-rinkeby-xdai-amb[Rinkeby ⇌ xDai] + * - https://docs.tokenbridge.net/kovan-sokol-amb-bridge/about-the-kovan-sokol-amb[Kovan ⇌ Sokol] + * + * _Available since v4.6._ + */ +contract CrossChainEnabledAMB is CrossChainEnabled { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _bridge; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) { + _bridge = bridge; + } + + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return LibAMB.isCrossChain(_bridge); + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return LibAMB.crossChainSender(_bridge); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/amb/LibAMB.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/amb/LibAMB.sol new file mode 100644 index 0000000..aef9c43 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/amb/LibAMB.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/amb/LibAMB.sol) + +pragma solidity ^0.8.4; + +import {IAMB as AMB_Bridge} from "../../vendor/amb/IAMB.sol"; +import "../errors.sol"; + +/** + * @dev Primitives for cross-chain aware contracts using the + * https://docs.tokenbridge.net/amb-bridge/about-amb-bridge[AMB] + * family of bridges. + */ +library LibAMB { + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message relayed by `bridge`. + */ + function isCrossChain(address bridge) internal view returns (bool) { + return msg.sender == bridge; + } + + /** + * @dev Returns the address of the sender that triggered the current + * cross-chain message through `bridge`. + * + * NOTE: {isCrossChain} should be checked before trying to recover the + * sender, as it will revert with `NotCrossChainCall` if the current + * function call is not the result of a cross-chain message. + */ + function crossChainSender(address bridge) internal view returns (address) { + if (!isCrossChain(bridge)) revert NotCrossChainCall(); + return AMB_Bridge(bridge).messageSender(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol new file mode 100644 index 0000000..5068da3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "./LibArbitrumL1.sol"; + +/** + * @dev https://arbitrum.io/[Arbitrum] specialization or the + * {CrossChainEnabled} abstraction the L1 side (mainnet). + * + * This version should only be deployed on L1 to process cross-chain messages + * originating from L2. For the other side, use {CrossChainEnabledArbitrumL2}. + * + * The bridge contract is provided and maintained by the arbitrum team. You can + * find the address of this contract on the rinkeby testnet in + * https://developer.offchainlabs.com/docs/useful_addresses[Arbitrum's developer documentation]. + * + * _Available since v4.6._ + */ +abstract contract CrossChainEnabledArbitrumL1 is CrossChainEnabled { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _bridge; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) { + _bridge = bridge; + } + + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return LibArbitrumL1.isCrossChain(_bridge); + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return LibArbitrumL1.crossChainSender(_bridge); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol new file mode 100644 index 0000000..e85993d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "./LibArbitrumL2.sol"; + +/** + * @dev https://arbitrum.io/[Arbitrum] specialization or the + * {CrossChainEnabled} abstraction the L2 side (arbitrum). + * + * This version should only be deployed on L2 to process cross-chain messages + * originating from L1. For the other side, use {CrossChainEnabledArbitrumL1}. + * + * Arbitrum L2 includes the `ArbSys` contract at a fixed address. Therefore, + * this specialization of {CrossChainEnabled} does not include a constructor. + * + * _Available since v4.6._ + * + * WARNING: There is currently a bug in Arbitrum that causes this contract to + * fail to detect cross-chain calls when deployed behind a proxy. This will be + * fixed when the network is upgraded to Arbitrum Nitro, currently scheduled for + * August 31st 2022. + */ +abstract contract CrossChainEnabledArbitrumL2 is CrossChainEnabled { + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return LibArbitrumL2.isCrossChain(LibArbitrumL2.ARBSYS); + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return LibArbitrumL2.crossChainSender(LibArbitrumL2.ARBSYS); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/LibArbitrumL1.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/LibArbitrumL1.sol new file mode 100644 index 0000000..be7236b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/LibArbitrumL1.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (crosschain/arbitrum/LibArbitrumL1.sol) + +pragma solidity ^0.8.4; + +import {IBridge as ArbitrumL1_Bridge} from "../../vendor/arbitrum/IBridge.sol"; +import {IOutbox as ArbitrumL1_Outbox} from "../../vendor/arbitrum/IOutbox.sol"; +import "../errors.sol"; + +/** + * @dev Primitives for cross-chain aware contracts for + * https://arbitrum.io/[Arbitrum]. + * + * This version should only be used on L1 to process cross-chain messages + * originating from L2. For the other side, use {LibArbitrumL2}. + */ +library LibArbitrumL1 { + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message relayed by the `bridge`. + */ + function isCrossChain(address bridge) internal view returns (bool) { + return msg.sender == bridge; + } + + /** + * @dev Returns the address of the sender that triggered the current + * cross-chain message through the `bridge`. + * + * NOTE: {isCrossChain} should be checked before trying to recover the + * sender, as it will revert with `NotCrossChainCall` if the current + * function call is not the result of a cross-chain message. + */ + function crossChainSender(address bridge) internal view returns (address) { + if (!isCrossChain(bridge)) revert NotCrossChainCall(); + + address sender = ArbitrumL1_Outbox(ArbitrumL1_Bridge(bridge).activeOutbox()).l2ToL1Sender(); + require(sender != address(0), "LibArbitrumL1: system messages without sender"); + + return sender; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/LibArbitrumL2.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/LibArbitrumL2.sol new file mode 100644 index 0000000..715a387 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/arbitrum/LibArbitrumL2.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (crosschain/arbitrum/LibArbitrumL2.sol) + +pragma solidity ^0.8.4; + +import {IArbSys as ArbitrumL2_Bridge} from "../../vendor/arbitrum/IArbSys.sol"; +import "../errors.sol"; + +/** + * @dev Primitives for cross-chain aware contracts for + * https://arbitrum.io/[Arbitrum]. + * + * This version should only be used on L2 to process cross-chain messages + * originating from L1. For the other side, use {LibArbitrumL1}. + * + * WARNING: There is currently a bug in Arbitrum that causes this contract to + * fail to detect cross-chain calls when deployed behind a proxy. This will be + * fixed when the network is upgraded to Arbitrum Nitro, currently scheduled for + * August 31st 2022. + */ +library LibArbitrumL2 { + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message relayed by `arbsys`. + */ + address public constant ARBSYS = 0x0000000000000000000000000000000000000064; + + function isCrossChain(address arbsys) internal view returns (bool) { + return ArbitrumL2_Bridge(arbsys).wasMyCallersAddressAliased(); + } + + /** + * @dev Returns the address of the sender that triggered the current + * cross-chain message through `arbsys`. + * + * NOTE: {isCrossChain} should be checked before trying to recover the + * sender, as it will revert with `NotCrossChainCall` if the current + * function call is not the result of a cross-chain message. + */ + function crossChainSender(address arbsys) internal view returns (address) { + if (!isCrossChain(arbsys)) revert NotCrossChainCall(); + + return ArbitrumL2_Bridge(arbsys).myCallersAddressWithoutAliasing(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/errors.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/errors.sol new file mode 100644 index 0000000..004460e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/errors.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (crosschain/errors.sol) + +pragma solidity ^0.8.4; + +error NotCrossChainCall(); +error InvalidCrossChainSender(address actual, address expected); diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol new file mode 100644 index 0000000..1005864 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/optimism/CrossChainEnabledOptimism.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "./LibOptimism.sol"; + +/** + * @dev https://www.optimism.io/[Optimism] specialization or the + * {CrossChainEnabled} abstraction. + * + * The messenger (`CrossDomainMessenger`) contract is provided and maintained by + * the optimism team. You can find the address of this contract on mainnet and + * kovan in the https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts/deployments[deployments section of Optimism monorepo]. + * + * _Available since v4.6._ + */ +abstract contract CrossChainEnabledOptimism is CrossChainEnabled { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _messenger; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address messenger) { + _messenger = messenger; + } + + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return LibOptimism.isCrossChain(_messenger); + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return LibOptimism.crossChainSender(_messenger); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/optimism/LibOptimism.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/optimism/LibOptimism.sol new file mode 100644 index 0000000..d963ade --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/optimism/LibOptimism.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (crosschain/optimism/LibOptimism.sol) + +pragma solidity ^0.8.4; + +import {ICrossDomainMessenger as Optimism_Bridge} from "../../vendor/optimism/ICrossDomainMessenger.sol"; +import "../errors.sol"; + +/** + * @dev Primitives for cross-chain aware contracts for https://www.optimism.io/[Optimism]. + * See the https://community.optimism.io/docs/developers/bridge/messaging/#accessing-msg-sender[documentation] + * for the functionality used here. + */ +library LibOptimism { + /** + * @dev Returns whether the current function call is the result of a + * cross-chain message relayed by `messenger`. + */ + function isCrossChain(address messenger) internal view returns (bool) { + return msg.sender == messenger; + } + + /** + * @dev Returns the address of the sender that triggered the current + * cross-chain message through `messenger`. + * + * NOTE: {isCrossChain} should be checked before trying to recover the + * sender, as it will revert with `NotCrossChainCall` if the current + * function call is not the result of a cross-chain message. + */ + function crossChainSender(address messenger) internal view returns (address) { + if (!isCrossChain(messenger)) revert NotCrossChainCall(); + + return Optimism_Bridge(messenger).xDomainMessageSender(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol new file mode 100644 index 0000000..1a201fd --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (crosschain/polygon/CrossChainEnabledPolygonChild.sol) + +pragma solidity ^0.8.4; + +import "../CrossChainEnabled.sol"; +import "../../security/ReentrancyGuard.sol"; +import "../../utils/Address.sol"; +import "../../vendor/polygon/IFxMessageProcessor.sol"; + +address constant DEFAULT_SENDER = 0x000000000000000000000000000000000000dEaD; + +/** + * @dev https://polygon.technology/[Polygon] specialization or the + * {CrossChainEnabled} abstraction the child side (polygon/mumbai). + * + * This version should only be deployed on child chain to process cross-chain + * messages originating from the parent chain. + * + * The fxChild contract is provided and maintained by the polygon team. You can + * find the address of this contract polygon and mumbai in + * https://docs.polygon.technology/docs/develop/l1-l2-communication/fx-portal/#contract-addresses[Polygon's Fx-Portal documentation]. + * + * _Available since v4.6._ + */ +abstract contract CrossChainEnabledPolygonChild is IFxMessageProcessor, CrossChainEnabled, ReentrancyGuard { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _fxChild; + address private _sender = DEFAULT_SENDER; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address fxChild) { + _fxChild = fxChild; + } + + /** + * @dev see {CrossChainEnabled-_isCrossChain} + */ + function _isCrossChain() internal view virtual override returns (bool) { + return msg.sender == _fxChild; + } + + /** + * @dev see {CrossChainEnabled-_crossChainSender} + */ + function _crossChainSender() internal view virtual override onlyCrossChain returns (address) { + return _sender; + } + + /** + * @dev External entry point to receive and relay messages originating + * from the fxChild. + * + * Non-reentrancy is crucial to avoid a cross-chain call being able + * to impersonate anyone by just looping through this with user-defined + * arguments. + * + * Note: if _fxChild calls any other function that does a delegate-call, + * then security could be compromised. + */ + function processMessageFromRoot( + uint256 /* stateId */, + address rootMessageSender, + bytes calldata data + ) external override nonReentrant { + if (!_isCrossChain()) revert NotCrossChainCall(); + + _sender = rootMessageSender; + Address.functionDelegateCall(address(this), data, "cross-chain execution failed"); + _sender = DEFAULT_SENDER; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/finance/PaymentSplitter.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/finance/PaymentSplitter.sol new file mode 100644 index 0000000..daa9090 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/finance/PaymentSplitter.sol @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (finance/PaymentSplitter.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/utils/SafeERC20.sol"; +import "../utils/Address.sol"; +import "../utils/Context.sol"; + +/** + * @title PaymentSplitter + * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware + * that the Ether will be split in this way, since it is handled transparently by the contract. + * + * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each + * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim + * an amount proportional to the percentage of total shares they were assigned. The distribution of shares is set at the + * time of contract deployment and can't be updated thereafter. + * + * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the + * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release} + * function. + * + * NOTE: This contract assumes that ERC20 tokens will behave similarly to native tokens (Ether). Rebasing tokens, and + * tokens that apply fees during transfers, are likely to not be supported as expected. If in doubt, we encourage you + * to run tests before sending real value to this contract. + */ +contract PaymentSplitter is Context { + event PayeeAdded(address account, uint256 shares); + event PaymentReleased(address to, uint256 amount); + event ERC20PaymentReleased(IERC20 indexed token, address to, uint256 amount); + event PaymentReceived(address from, uint256 amount); + + uint256 private _totalShares; + uint256 private _totalReleased; + + mapping(address => uint256) private _shares; + mapping(address => uint256) private _released; + address[] private _payees; + + mapping(IERC20 => uint256) private _erc20TotalReleased; + mapping(IERC20 => mapping(address => uint256)) private _erc20Released; + + /** + * @dev Creates an instance of `PaymentSplitter` where each account in `payees` is assigned the number of shares at + * the matching position in the `shares` array. + * + * All addresses in `payees` must be non-zero. Both arrays must have the same non-zero length, and there must be no + * duplicates in `payees`. + */ + constructor(address[] memory payees, uint256[] memory shares_) payable { + require(payees.length == shares_.length, "PaymentSplitter: payees and shares length mismatch"); + require(payees.length > 0, "PaymentSplitter: no payees"); + + for (uint256 i = 0; i < payees.length; i++) { + _addPayee(payees[i], shares_[i]); + } + } + + /** + * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully + * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the + * reliability of the events, and not the actual splitting of Ether. + * + * To learn more about this see the Solidity documentation for + * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback + * functions]. + */ + receive() external payable virtual { + emit PaymentReceived(_msgSender(), msg.value); + } + + /** + * @dev Getter for the total shares held by payees. + */ + function totalShares() public view returns (uint256) { + return _totalShares; + } + + /** + * @dev Getter for the total amount of Ether already released. + */ + function totalReleased() public view returns (uint256) { + return _totalReleased; + } + + /** + * @dev Getter for the total amount of `token` already released. `token` should be the address of an IERC20 + * contract. + */ + function totalReleased(IERC20 token) public view returns (uint256) { + return _erc20TotalReleased[token]; + } + + /** + * @dev Getter for the amount of shares held by an account. + */ + function shares(address account) public view returns (uint256) { + return _shares[account]; + } + + /** + * @dev Getter for the amount of Ether already released to a payee. + */ + function released(address account) public view returns (uint256) { + return _released[account]; + } + + /** + * @dev Getter for the amount of `token` tokens already released to a payee. `token` should be the address of an + * IERC20 contract. + */ + function released(IERC20 token, address account) public view returns (uint256) { + return _erc20Released[token][account]; + } + + /** + * @dev Getter for the address of the payee number `index`. + */ + function payee(uint256 index) public view returns (address) { + return _payees[index]; + } + + /** + * @dev Getter for the amount of payee's releasable Ether. + */ + function releasable(address account) public view returns (uint256) { + uint256 totalReceived = address(this).balance + totalReleased(); + return _pendingPayment(account, totalReceived, released(account)); + } + + /** + * @dev Getter for the amount of payee's releasable `token` tokens. `token` should be the address of an + * IERC20 contract. + */ + function releasable(IERC20 token, address account) public view returns (uint256) { + uint256 totalReceived = token.balanceOf(address(this)) + totalReleased(token); + return _pendingPayment(account, totalReceived, released(token, account)); + } + + /** + * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the + * total shares and their previous withdrawals. + */ + function release(address payable account) public virtual { + require(_shares[account] > 0, "PaymentSplitter: account has no shares"); + + uint256 payment = releasable(account); + + require(payment != 0, "PaymentSplitter: account is not due payment"); + + // _totalReleased is the sum of all values in _released. + // If "_totalReleased += payment" does not overflow, then "_released[account] += payment" cannot overflow. + _totalReleased += payment; + unchecked { + _released[account] += payment; + } + + Address.sendValue(account, payment); + emit PaymentReleased(account, payment); + } + + /** + * @dev Triggers a transfer to `account` of the amount of `token` tokens they are owed, according to their + * percentage of the total shares and their previous withdrawals. `token` must be the address of an IERC20 + * contract. + */ + function release(IERC20 token, address account) public virtual { + require(_shares[account] > 0, "PaymentSplitter: account has no shares"); + + uint256 payment = releasable(token, account); + + require(payment != 0, "PaymentSplitter: account is not due payment"); + + // _erc20TotalReleased[token] is the sum of all values in _erc20Released[token]. + // If "_erc20TotalReleased[token] += payment" does not overflow, then "_erc20Released[token][account] += payment" + // cannot overflow. + _erc20TotalReleased[token] += payment; + unchecked { + _erc20Released[token][account] += payment; + } + + SafeERC20.safeTransfer(token, account, payment); + emit ERC20PaymentReleased(token, account, payment); + } + + /** + * @dev internal logic for computing the pending payment of an `account` given the token historical balances and + * already released amounts. + */ + function _pendingPayment( + address account, + uint256 totalReceived, + uint256 alreadyReleased + ) private view returns (uint256) { + return (totalReceived * _shares[account]) / _totalShares - alreadyReleased; + } + + /** + * @dev Add a new payee to the contract. + * @param account The address of the payee to add. + * @param shares_ The number of shares owned by the payee. + */ + function _addPayee(address account, uint256 shares_) private { + require(account != address(0), "PaymentSplitter: account is the zero address"); + require(shares_ > 0, "PaymentSplitter: shares are 0"); + require(_shares[account] == 0, "PaymentSplitter: account already has shares"); + + _payees.push(account); + _shares[account] = shares_; + _totalShares = _totalShares + shares_; + emit PayeeAdded(account, shares_); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/finance/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/finance/README.adoc new file mode 100644 index 0000000..b64af31 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/finance/README.adoc @@ -0,0 +1,20 @@ += Finance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/finance + +This directory includes primitives for financial systems: + +- {PaymentSplitter} allows to split Ether and ERC20 payments among a group of accounts. The sender does not need to be + aware that the assets will be split in this way, since it is handled transparently by the contract. The split can be + in equal parts or in any other arbitrary proportion. + +- {VestingWallet} handles the vesting of Ether and ERC20 tokens for a given beneficiary. Custody of multiple tokens can + be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting + schedule. + +== Contracts + +{{PaymentSplitter}} + +{{VestingWallet}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/finance/VestingWallet.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/finance/VestingWallet.sol new file mode 100644 index 0000000..45cf9ce --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/finance/VestingWallet.sol @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (finance/VestingWallet.sol) +pragma solidity ^0.8.0; + +import "../token/ERC20/utils/SafeERC20.sol"; +import "../utils/Address.sol"; +import "../utils/Context.sol"; + +/** + * @title VestingWallet + * @dev This contract handles the vesting of Eth and ERC20 tokens for a given beneficiary. Custody of multiple tokens + * can be given to this contract, which will release the token to the beneficiary following a given vesting schedule. + * The vesting schedule is customizable through the {vestedAmount} function. + * + * 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. + */ +contract VestingWallet is Context { + event EtherReleased(uint256 amount); + event ERC20Released(address indexed token, uint256 amount); + + uint256 private _released; + mapping(address => uint256) private _erc20Released; + address private immutable _beneficiary; + uint64 private immutable _start; + uint64 private immutable _duration; + + /** + * @dev Set the beneficiary, start timestamp and vesting duration of the vesting wallet. + */ + constructor(address beneficiaryAddress, uint64 startTimestamp, uint64 durationSeconds) payable { + require(beneficiaryAddress != address(0), "VestingWallet: beneficiary is zero address"); + _beneficiary = beneficiaryAddress; + _start = startTimestamp; + _duration = durationSeconds; + } + + /** + * @dev The contract should be able to receive Eth. + */ + receive() external payable virtual {} + + /** + * @dev Getter for the beneficiary address. + */ + function beneficiary() public view virtual returns (address) { + return _beneficiary; + } + + /** + * @dev Getter for the start timestamp. + */ + function start() public view virtual returns (uint256) { + return _start; + } + + /** + * @dev Getter for the vesting duration. + */ + function duration() public view virtual returns (uint256) { + return _duration; + } + + /** + * @dev Amount of eth already released + */ + function released() public view virtual returns (uint256) { + return _released; + } + + /** + * @dev Amount of token already released + */ + function released(address token) public view virtual returns (uint256) { + return _erc20Released[token]; + } + + /** + * @dev Getter for the amount of releasable eth. + */ + function releasable() public view virtual returns (uint256) { + return vestedAmount(uint64(block.timestamp)) - released(); + } + + /** + * @dev Getter for the amount of releasable `token` tokens. `token` should be the address of an + * IERC20 contract. + */ + function releasable(address token) public view virtual returns (uint256) { + return vestedAmount(token, uint64(block.timestamp)) - released(token); + } + + /** + * @dev Release the native token (ether) that have already vested. + * + * Emits a {EtherReleased} event. + */ + function release() public virtual { + uint256 amount = releasable(); + _released += amount; + emit EtherReleased(amount); + Address.sendValue(payable(beneficiary()), amount); + } + + /** + * @dev Release the tokens that have already vested. + * + * Emits a {ERC20Released} event. + */ + function release(address token) public virtual { + uint256 amount = releasable(token); + _erc20Released[token] += amount; + emit ERC20Released(token, amount); + SafeERC20.safeTransfer(IERC20(token), beneficiary(), amount); + } + + /** + * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve. + */ + function vestedAmount(uint64 timestamp) public view virtual returns (uint256) { + return _vestingSchedule(address(this).balance + released(), timestamp); + } + + /** + * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve. + */ + function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) { + return _vestingSchedule(IERC20(token).balanceOf(address(this)) + released(token), timestamp); + } + + /** + * @dev Virtual implementation of the vesting formula. This returns the amount vested, as a function of time, for + * an asset given its total historical allocation. + */ + function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) { + if (timestamp < start()) { + return 0; + } else if (timestamp > start() + duration()) { + return totalAllocation; + } else { + return (totalAllocation * (timestamp - start())) / duration(); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/Governor.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/Governor.sol new file mode 100644 index 0000000..e6fe222 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/Governor.sol @@ -0,0 +1,723 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.1) (governance/Governor.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/IERC721Receiver.sol"; +import "../token/ERC1155/IERC1155Receiver.sol"; +import "../utils/cryptography/ECDSA.sol"; +import "../utils/cryptography/EIP712.sol"; +import "../utils/introspection/ERC165.sol"; +import "../utils/math/SafeCast.sol"; +import "../utils/structs/DoubleEndedQueue.sol"; +import "../utils/Address.sol"; +import "../utils/Context.sol"; +import "./IGovernor.sol"; + +/** + * @dev Core of the governance system, designed to be extended though 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} + * - Additionally, {votingPeriod} must also be implemented + * + * _Available since v4.3._ + */ +abstract contract Governor is Context, ERC165, EIP712, IGovernor, IERC721Receiver, IERC1155Receiver { + using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; + + 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 { + // --- 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; + } + // 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 + // {onlyGovernance} modifier needs to be whitelisted in this queue. Whitelisting is set in {_beforeExecute}, + // consumed by the {onlyGovernance} modifier and eventually reset in {_afterExecute}. This ensures that the + // execution of {onlyGovernance} protected calls can only be achieved through successful proposals. + DoubleEndedQueue.Bytes32Deque private _governanceCall; + + /** + * @dev Restricts a function so it can only be executed through governance proposals. For example, governance + * parameter setters in {GovernorSettings} are protected using this modifier. + * + * The governance executing address may be different from the Governor's own address, for example it could be a + * timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these + * functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus, + * for example, additional timelock proposers are not able to change governance parameters without going through the + * governance protocol (since v4.6). + */ + modifier onlyGovernance() { + require(_msgSender() == _executor(), "Governor: onlyGovernance"); + if (_executor() != address(this)) { + bytes32 msgDataHash = keccak256(_msgData()); + // loop until popping the expected operation - throw if deque is empty (operation not authorized) + while (_governanceCall.popFront() != msgDataHash) {} + } + _; + } + + /** + * @dev Sets the value for {name} and {version} + */ + constructor(string memory name_) EIP712(name_, version()) { + _name = name_; + } + + /** + * @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), "Governor: must send to executor"); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + 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 == governor43Id || + interfaceId == governor46Id || + interfaceId == governorCancelId || + interfaceId == type(IERC1155Receiver).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IGovernor-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IGovernor-version}. + */ + function version() public view virtual override returns (string memory) { + return "1"; + } + + /** + * @dev See {IGovernor-hashProposal}. + * + * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array + * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id + * can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in + * advance, before the proposal is submitted. + * + * Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the + * same proposal (with same operation and same description) will have the same id if submitted on multiple governors + * across multiple networks. This also means that in order to execute the same operation twice (on the same + * governor) the proposer will have to change the description in order to avoid proposal id conflicts. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public pure virtual override returns (uint256) { + return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash))); + } + + /** + * @dev See {IGovernor-state}. + */ + function state(uint256 proposalId) public view virtual override returns (ProposalState) { + ProposalCore storage proposal = _proposals[proposalId]; + + if (proposal.executed) { + return ProposalState.Executed; + } + + if (proposal.canceled) { + return ProposalState.Canceled; + } + + uint256 snapshot = proposalSnapshot(proposalId); + + if (snapshot == 0) { + revert("Governor: unknown proposal id"); + } + + uint256 currentTimepoint = clock(); + + if (snapshot >= currentTimepoint) { + return ProposalState.Pending; + } + + uint256 deadline = proposalDeadline(proposalId); + + if (deadline >= currentTimepoint) { + return ProposalState.Active; + } + + if (_quorumReached(proposalId) && _voteSucceeded(proposalId)) { + return ProposalState.Succeeded; + } else { + return ProposalState.Defeated; + } + } + + /** + * @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; + } + + /** + * @dev See {IGovernor-proposalDeadline}. + */ + function proposalDeadline(uint256 proposalId) public view virtual override returns (uint256) { + return _proposals[proposalId].voteEnd; + } + + /** + * @dev Returns the account that created a given proposal. + */ + function proposalProposer(uint256 proposalId) public view virtual override returns (address) { + return _proposals[proposalId].proposer; + } + + /** + * @dev Amount of votes already cast passes the threshold limit. + */ + function _quorumReached(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Is the proposal successful or not. + */ + function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`. + */ + 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`. + * + * Note: Support is generic and can represent various things depending on the voting system used. + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal virtual; + + /** + * @dev Default additional encoded parameters used by castVote methods that don't include them + * + * Note: Should be overridden by specific implementations to use an appropriate value, the + * meaning of the additional params, in the context of that implementation + */ + function _defaultParams() internal view virtual returns (bytes memory) { + return ""; + } + + /** + * @dev See {IGovernor-propose}. This function has opt-in frontrunning protection, described in {_isValidDescriptionForProposer}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual override returns (uint256) { + address proposer = _msgSender(); + require(_isValidDescriptionForProposer(proposer, description), "Governor: proposer restricted"); + + uint256 currentTimepoint = clock(); + require( + getVotes(proposer, currentTimepoint - 1) >= proposalThreshold(), + "Governor: proposer votes below proposal threshold" + ); + + uint256 proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description))); + + 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].voteStart == 0, "Governor: proposal already exists"); + + uint256 snapshot = currentTimepoint + votingDelay(); + uint256 deadline = snapshot + votingPeriod(); + + _proposals[proposalId] = ProposalCore({ + proposer: proposer, + voteStart: SafeCast.toUint64(snapshot), + voteEnd: SafeCast.toUint64(deadline), + executed: false, + canceled: false, + __gap_unused0: 0, + __gap_unused1: 0 + }); + + emit ProposalCreated( + proposalId, + proposer, + targets, + values, + new string[](targets.length), + calldatas, + snapshot, + deadline, + description + ); + + return proposalId; + } + + /** + * @dev See {IGovernor-execute}. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual override returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + ProposalState currentState = state(proposalId); + require( + currentState == ProposalState.Succeeded || currentState == ProposalState.Queued, + "Governor: proposal not successful" + ); + _proposals[proposalId].executed = true; + + emit ProposalExecuted(proposalId); + + _beforeExecute(proposalId, targets, values, calldatas, descriptionHash); + _execute(proposalId, targets, values, calldatas, descriptionHash); + _afterExecute(proposalId, targets, values, calldatas, descriptionHash); + + return proposalId; + } + + /** + * @dev See {IGovernor-cancel}. + */ + 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"); + return _cancel(targets, values, calldatas, descriptionHash); + } + + /** + * @dev Internal execution mechanism. Can be overridden to implement different execution mechanism + */ + function _execute( + uint256 /* proposalId */, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual { + string memory errorMessage = "Governor: call reverted without message"; + for (uint256 i = 0; i < targets.length; ++i) { + (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); + Address.verifyCallResult(success, returndata, errorMessage); + } + } + + /** + * @dev Hook before execution is triggered. + */ + function _beforeExecute( + uint256 /* proposalId */, + address[] memory targets, + uint256[] memory /* values */, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual { + if (_executor() != address(this)) { + for (uint256 i = 0; i < targets.length; ++i) { + if (targets[i] == address(this)) { + _governanceCall.pushBack(keccak256(calldatas[i])); + } + } + } + } + + /** + * @dev Hook after execution is triggered. + */ + function _afterExecute( + uint256 /* proposalId */, + address[] memory /* targets */, + uint256[] memory /* values */, + bytes[] memory /* calldatas */, + bytes32 /*descriptionHash*/ + ) internal virtual { + if (_executor() != address(this)) { + if (!_governanceCall.empty()) { + _governanceCall.clear(); + } + } + } + + /** + * @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( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + ProposalState currentState = state(proposalId); + + require( + currentState != ProposalState.Canceled && + currentState != ProposalState.Expired && + currentState != ProposalState.Executed, + "Governor: proposal not active" + ); + _proposals[proposalId].canceled = true; + + emit ProposalCanceled(proposalId); + + return proposalId; + } + + /** + * @dev See {IGovernor-getVotes}. + */ + function getVotes(address account, uint256 timepoint) public view virtual override returns (uint256) { + return _getVotes(account, timepoint, _defaultParams()); + } + + /** + * @dev See {IGovernor-getVotesWithParams}. + */ + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) public view virtual override returns (uint256) { + return _getVotes(account, timepoint, params); + } + + /** + * @dev See {IGovernor-castVote}. + */ + function castVote(uint256 proposalId, uint8 support) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, ""); + } + + /** + * @dev See {IGovernor-castVoteWithReason}. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParams}. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) public virtual override returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev See {IGovernor-castVoteBySig}. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override returns (uint256) { + address voter = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support))), + v, + r, + s + ); + return _castVote(proposalId, voter, support, ""); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override returns (uint256) { + address voter = ECDSA.recover( + _hashTypedDataV4( + keccak256( + abi.encode( + EXTENDED_BALLOT_TYPEHASH, + proposalId, + support, + keccak256(bytes(reason)), + keccak256(params) + ) + ) + ), + v, + r, + s + ); + + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams(). + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason + ) internal virtual returns (uint256) { + return _castVote(proposalId, account, support, reason, _defaultParams()); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual returns (uint256) { + ProposalCore storage proposal = _proposals[proposalId]; + require(state(proposalId) == ProposalState.Active, "Governor: vote not currently active"); + + uint256 weight = _getVotes(account, proposal.voteStart, params); + _countVote(proposalId, account, support, weight, params); + + if (params.length == 0) { + emit VoteCast(account, proposalId, support, weight, reason); + } else { + emit VoteCastWithParams(account, proposalId, support, weight, reason, params); + } + + return weight; + } + + /** + * @dev Relays a transaction or function call to an arbitrary target. In cases where the governance executor + * is some contract other than the governor itself, like when using a timelock, this function can be invoked + * in a governance proposal to recover tokens or Ether that was sent to the governor contract by mistake. + * Note that if the executor is simply the governor itself, use of `relay` is redundant. + */ + function relay(address target, uint256 value, bytes calldata data) external payable virtual onlyGovernance { + (bool success, bytes memory returndata) = target.call{value: value}(data); + Address.verifyCallResult(success, returndata, "Governor: relay reverted without message"); + } + + /** + * @dev Address through which the governor executes action. Will be overloaded by module that execute actions + * through another contract such as a timelock. + */ + function _executor() internal view virtual returns (address) { + return address(this); + } + + /** + * @dev See {IERC721Receiver-onERC721Received}. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { + return this.onERC721Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155Received}. + */ + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155BatchReceived}. + */ + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } + + /** + * @dev Check if the proposer is authorized to submit a proposal with the given description. + * + * If the proposal description ends with `#proposer=0x???`, where `0x???` is an address written as a hex string + * (case insensitive), then the submission of this proposal will only be authorized to said address. + * + * This is used for frontrunning protection. By adding this pattern at the end of their proposal, one can ensure + * that no other address can submit the same proposal. An attacker would have to either remove or change that part, + * which would result in a different proposal id. + * + * If the description does not match this pattern, it is unrestricted and anyone can submit it. This includes: + * - If the `0x???` part is not a valid hex string. + * - If the `0x???` part is a valid hex string, but does not contain exactly 40 hex digits. + * - If it ends with the expected suffix followed by newlines or other whitespace. + * - If it ends with some other similar suffix, e.g. `#other=abc`. + * - If it does not end with any such suffix. + */ + function _isValidDescriptionForProposer( + address proposer, + string memory description + ) internal view virtual returns (bool) { + uint256 len = bytes(description).length; + + // Length is too short to contain a valid proposer suffix + if (len < 52) { + return true; + } + + // Extract what would be the `#proposer=0x` marker beginning the suffix + bytes12 marker; + assembly { + // - Start of the string contents in memory = description + 32 + // - First character of the marker = len - 52 + // - Length of "#proposer=0x0000000000000000000000000000000000000000" = 52 + // - We read the memory word starting at the first character of the marker: + // - (description + 32) + (len - 52) = description + (len - 20) + // - Note: Solidity will ignore anything past the first 12 bytes + marker := mload(add(description, sub(len, 20))) + } + + // If the marker is not found, there is no proposer suffix to check + if (marker != bytes12("#proposer=0x")) { + return true; + } + + // Parse the 40 characters following the marker as uint160 + uint160 recovered = 0; + for (uint256 i = len - 40; i < len; ++i) { + (bool isHex, uint8 value) = _tryHexToUint(bytes(description)[i]); + // If any of the characters is not a hex digit, ignore the suffix entirely + if (!isHex) { + return true; + } + recovered = (recovered << 4) | value; + } + + return recovered == uint160(proposer); + } + + /** + * @dev Try to parse a character from a string as a hex value. Returns `(true, value)` if the char is in + * `[0-9a-fA-F]` and `(false, 0)` otherwise. Value is guaranteed to be in the range `0 <= value < 16` + */ + function _tryHexToUint(bytes1 char) private pure returns (bool, uint8) { + uint8 c = uint8(char); + unchecked { + // Case 0-9 + if (47 < c && c < 58) { + return (true, c - 48); + } + // Case A-F + else if (64 < c && c < 71) { + return (true, c - 55); + } + // Case a-f + else if (96 < c && c < 103) { + return (true, c - 87); + } + // Else: not a hex char + else { + return (false, 0); + } + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/IGovernor.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/IGovernor.sol new file mode 100644 index 0000000..492d95b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/IGovernor.sol @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/IGovernor.sol) + +pragma solidity ^0.8.0; + +import "../interfaces/IERC165.sol"; +import "../interfaces/IERC6372.sol"; + +/** + * @dev Interface of the {Governor} core. + * + * _Available since v4.3._ + */ +abstract contract IGovernor is IERC165, IERC6372 { + enum ProposalState { + Pending, + Active, + Canceled, + Defeated, + Succeeded, + Queued, + Expired, + Executed + } + + /** + * @dev Emitted when a proposal is created. + */ + event ProposalCreated( + uint256 proposalId, + address proposer, + address[] targets, + uint256[] values, + string[] signatures, + bytes[] calldatas, + uint256 voteStart, + uint256 voteEnd, + string description + ); + + /** + * @dev Emitted when a proposal is canceled. + */ + event ProposalCanceled(uint256 proposalId); + + /** + * @dev Emitted when a proposal is executed. + */ + event ProposalExecuted(uint256 proposalId); + + /** + * @dev Emitted when a vote is cast without params. + * + * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. + */ + event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason); + + /** + * @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 interpepretation also depends on the voting module used. + */ + event VoteCastWithParams( + address indexed voter, + uint256 proposalId, + uint8 support, + uint256 weight, + string reason, + bytes params + ); + + /** + * @notice module:core + * @dev Name of the governor instance (used in building the ERC712 domain separator). + */ + function name() public view virtual returns (string memory); + + /** + * @notice module:core + * @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1" + */ + 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 + * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of + * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`. + * + * There are 2 standard keys: `support` and `quorum`. + * + * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`. + * - `quorum=bravo` means that only For votes are counted towards quorum. + * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum. + * + * If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique + * name that describes the behavior. For example: + * + * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain. + * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote. + * + * NOTE: The string can be decoded by the standard + * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`] + * JavaScript class. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public view virtual returns (string memory); + + /** + * @notice module:core + * @dev Hashing function used to (re)build the proposal id from the proposal details.. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public pure virtual returns (uint256); + + /** + * @notice module:core + * @dev Current state of a proposal, following Compound's convention + */ + function state(uint256 proposalId) public view virtual returns (ProposalState); + + /** + * @notice module:core + * @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 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: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 + * 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 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 + * duration compared to the voting delay. + */ + function votingPeriod() public view virtual returns (uint256); + + /** + * @notice module:user-config + * @dev Minimum number of cast voted required for a proposal to be successful. + * + * 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 timepoint) public view virtual returns (uint256); + + /** + * @notice module:reputation + * @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 timepoint) public view virtual returns (uint256); + + /** + * @notice module:reputation + * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters. + */ + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) public view virtual returns (uint256); + + /** + * @notice module:voting + * @dev Returns whether `account` has cast a vote on `proposalId`. + */ + function hasVoted(uint256 proposalId, address account) public view virtual returns (bool); + + /** + * @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. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual returns (uint256 proposalId); + + /** + * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the + * deadline to be reached. + * + * Emits a {ProposalExecuted} event. + * + * Note: some module can modify the requirements for execution, for example by adding an additional timelock. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual returns (uint256 proposalId); + + /** + * @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( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256 proposalId); + + /** + * @dev Cast a vote + * + * Emits a {VoteCast} event. + */ + function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason + * + * Emits a {VoteCast} event. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote using the user's cryptographic signature. + * + * Emits a {VoteCast} event. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters using the user's cryptographic signature. + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual returns (uint256 balance); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/README.adoc new file mode 100644 index 0000000..6d53e97 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/README.adoc @@ -0,0 +1,176 @@ += Governance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/governance + +This directory includes primitives for on-chain governance. + +== Governor + +This modular system of Governor contracts allows the deployment on-chain voting protocols similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo] and beyond, through the ability to easily customize multiple aspects of the protocol. + +[TIP] +==== +For a guided experience, set up your Governor contract using https://wizard.openzeppelin.com/#governor[Contracts Wizard]. + +For a written walkthrough, check out our guide on xref:ROOT:governance.adoc[How to set up on-chain governance]. +==== + +* {Governor}: The core contract that contains all the logic and primitives. It is abstract and requires choosing one of each of the modules below, or custom ones. + +Votes modules determine the source of voting power, and sometimes quorum number. + +* {GovernorVotes}: Extracts voting weight from an {ERC20Votes}, or since v4.5 an {ERC721Votes} token. + +* {GovernorVotesComp}: Extracts voting weight from a COMP-like or {ERC20VotesComp} token. + +* {GovernorVotesQuorumFraction}: Combines with `GovernorVotes` to set the quorum as a fraction of the total token supply. + +Counting modules determine valid voting options. + +* {GovernorCountingSimple}: Simple voting mechanism with 3 voting options: Against, For and Abstain. + +Timelock extensions add a delay for governance decisions to be executed. The workflow is extended to require a `queue` step before execution. With these modules, proposals are executed by the external timelock contract, thus it is the timelock that has to hold the assets that are being governed. + +* {GovernorTimelockControl}: Connects with an instance of {TimelockController}. Allows multiple proposers and executors, in addition to the Governor itself. + +* {GovernorTimelockCompound}: Connects with an instance of Compound's https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[`Timelock`] contract. + +Other extensions can customize the behavior or interface in multiple ways. + +* {GovernorCompatibilityBravo}: Extends the interface to be fully `GovernorBravo`-compatible. Note that events are compatible regardless of whether this extension is included or not. + +* {GovernorSettings}: Manages some of the settings (voting delay, voting period duration, and proposal threshold) in a way that can be updated through a governance proposal, without requiring an upgrade. + +* {GovernorPreventLateQuorum}: Ensures there is a minimum voting period after quorum is reached as a security protection against large voters. + +In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications: + +* <>: 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. + +=== Core + +{{IGovernor}} + +{{Governor}} + +=== Modules + +{{GovernorCountingSimple}} + +{{GovernorVotes}} + +{{GovernorVotesQuorumFraction}} + +{{GovernorVotesComp}} + +=== Extensions + +{{GovernorTimelockControl}} + +{{GovernorTimelockCompound}} + +{{GovernorSettings}} + +{{GovernorPreventLateQuorum}} + +{{GovernorCompatibilityBravo}} + +=== Deprecated + +{{GovernorProposalThreshold}} + +== Utils + +{{Votes}} + +== Timelock + +In a governance system, the {TimelockController} contract is in charge of introducing a delay between a proposal and its execution. It can be used with or without a {Governor}. + +{{TimelockController}} + +[[timelock-terminology]] +==== Terminology + +* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content. +* *Operation status:* +** *Unset:* An operation that is not part of the timelock mechanism. +** *Pending:* An operation that has been scheduled, before the timer expires. +** *Ready:* An operation that has been scheduled, after the timer expires. +** *Done:* An operation that has been executed. +* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations. +* *Role*: +** *Admin:* An address (smart contract or EOA) that is in charge of granting the roles of Proposer and Executor. +** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations. +** *Executor:* An address (smart contract or EOA) that is in charge of executing operations once the timelock has expired. This role can be given to the zero address to allow anyone to execute operations. + +[[timelock-operation]] +==== Operation structure + +Operation executed by the xref:api:governance.adoc#TimelockController[`TimelockController`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations. + +Both operations contain: + +* *Target*, the address of the smart contract that the timelock should operate on. +* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction. +* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encoded using web3js as follows: + +```javascript +const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI() +``` + +* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency. +* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value. + +In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length. + +[[timelock-operation-lifecycle]] +==== Operation lifecycle + +Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle: + +`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done` + +* By calling xref:api:governance.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:governance.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:governance.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method. +* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed. +* By calling xref:api:governance.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:governance.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed. +* xref:api:governance.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled. + +Operations status can be queried using the functions: + +* xref:api:governance.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`] +* xref:api:governance.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`] +* xref:api:governance.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`] + +[[timelock-roles]] +==== Roles + +[[timelock-admin]] +===== Admin + +The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, the admin role can be granted to any address (in addition to the timelock itself). After further configuration and testing, this optional admin should renounce its role such that all further maintenance operations have to go through the timelock process. + +This role is identified by the *TIMELOCK_ADMIN_ROLE* value: `0x5f58e3a2316349923ce3780f8d587db2d72378aed66a8261c916544fa6846ca5` + +[[timelock-proposer]] +===== Proposer + +The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO. + +WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers. + +This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1` + +[[timelock-executor]] +===== Executor + +The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executors can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers. Alternatively, it is possible to allow _any_ address to execute a proposal once the timelock has expired by granting the executor role to the zero address. + +This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63` + +WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management. diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/TimelockController.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/TimelockController.sol new file mode 100644 index 0000000..f70a7d1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/TimelockController.sol @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/TimelockController.sol) + +pragma solidity ^0.8.0; + +import "../access/AccessControl.sol"; +import "../token/ERC721/IERC721Receiver.sol"; +import "../token/ERC1155/IERC1155Receiver.sol"; + +/** + * @dev Contract module which acts as a timelocked controller. When set as the + * owner of an `Ownable` smart contract, it enforces a timelock on all + * `onlyOwner` maintenance operations. This gives time for users of the + * controlled contract to exit before a potentially dangerous maintenance + * operation is applied. + * + * By default, this contract is self administered, meaning administration tasks + * have to go through the timelock process. The proposer (resp executor) role + * is in charge of proposing (resp executing) operations. A common use case is + * to position this {TimelockController} as the owner of a smart contract, with + * a multisig or a DAO as the sole proposer. + * + * _Available since v3.3._ + */ +contract TimelockController is AccessControl, IERC721Receiver, IERC1155Receiver { + bytes32 public constant TIMELOCK_ADMIN_ROLE = keccak256("TIMELOCK_ADMIN_ROLE"); + bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); + bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); + bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); + uint256 internal constant _DONE_TIMESTAMP = uint256(1); + + mapping(bytes32 => uint256) private _timestamps; + uint256 private _minDelay; + + /** + * @dev Emitted when a call is scheduled as part of operation `id`. + */ + event CallScheduled( + bytes32 indexed id, + uint256 indexed index, + address target, + uint256 value, + bytes data, + bytes32 predecessor, + uint256 delay + ); + + /** + * @dev Emitted when a call is performed as part of operation `id`. + */ + 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. + */ + event Cancelled(bytes32 indexed id); + + /** + * @dev Emitted when the minimum delay for future operations is modified. + */ + event MinDelayChange(uint256 oldDuration, uint256 newDuration); + + /** + * @dev Initializes the contract with the following parameters: + * + * - `minDelay`: initial minimum delay for operations + * - `proposers`: accounts to be granted proposer and canceller roles + * - `executors`: accounts to be granted executor role + * - `admin`: optional account to be granted admin role; disable with zero address + * + * IMPORTANT: The optional admin can aid with initial configuration of roles after deployment + * without being subject to delay, but this role should be subsequently renounced in favor of + * administration through timelocked proposals. Previous versions of this contract would assign + * this admin to the deployer automatically and should be renounced as well. + */ + constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) { + _setRoleAdmin(TIMELOCK_ADMIN_ROLE, TIMELOCK_ADMIN_ROLE); + _setRoleAdmin(PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE); + _setRoleAdmin(EXECUTOR_ROLE, TIMELOCK_ADMIN_ROLE); + _setRoleAdmin(CANCELLER_ROLE, TIMELOCK_ADMIN_ROLE); + + // self administration + _setupRole(TIMELOCK_ADMIN_ROLE, address(this)); + + // optional admin + if (admin != address(0)) { + _setupRole(TIMELOCK_ADMIN_ROLE, admin); + } + + // register proposers and cancellers + for (uint256 i = 0; i < proposers.length; ++i) { + _setupRole(PROPOSER_ROLE, proposers[i]); + _setupRole(CANCELLER_ROLE, proposers[i]); + } + + // register executors + for (uint256 i = 0; i < executors.length; ++i) { + _setupRole(EXECUTOR_ROLE, executors[i]); + } + + _minDelay = minDelay; + emit MinDelayChange(0, minDelay); + } + + /** + * @dev Modifier to make a function callable only by a certain role. In + * addition to checking the sender's role, `address(0)` 's role is also + * considered. Granting a role to `address(0)` is equivalent to enabling + * this role for everyone. + */ + modifier onlyRoleOrOpenRole(bytes32 role) { + if (!hasRole(role, address(0))) { + _checkRole(role, _msgSender()); + } + _; + } + + /** + * @dev Contract might receive/hold ETH as part of the maintenance process. + */ + receive() external payable {} + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, AccessControl) returns (bool) { + return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @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) { + return getTimestamp(id) > 0; + } + + /** + * @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) { + return getTimestamp(id) > _DONE_TIMESTAMP; + } + + /** + * @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) { + uint256 timestamp = getTimestamp(id); + return timestamp > _DONE_TIMESTAMP && timestamp <= block.timestamp; + } + + /** + * @dev Returns whether an operation is done or not. + */ + function isOperationDone(bytes32 id) public view virtual returns (bool) { + return getTimestamp(id) == _DONE_TIMESTAMP; + } + + /** + * @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) { + return _timestamps[id]; + } + + /** + * @dev Returns the minimum delay for an operation to become valid. + * + * This value can be changed by executing an operation that calls `updateDelay`. + */ + function getMinDelay() public view virtual returns (uint256) { + return _minDelay; + } + + /** + * @dev Returns the identifier of an operation containing a single + * transaction. + */ + function hashOperation( + address target, + uint256 value, + bytes calldata data, + bytes32 predecessor, + bytes32 salt + ) public pure virtual returns (bytes32) { + return keccak256(abi.encode(target, value, data, predecessor, salt)); + } + + /** + * @dev Returns the identifier of an operation containing a batch of + * transactions. + */ + function hashOperationBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt + ) public pure virtual returns (bytes32) { + return keccak256(abi.encode(targets, values, payloads, predecessor, salt)); + } + + /** + * @dev Schedule an operation containing a single transaction. + * + * Emits {CallSalt} if salt is nonzero, and {CallScheduled}. + * + * Requirements: + * + * - the caller must have the 'proposer' role. + */ + function schedule( + address target, + uint256 value, + bytes calldata data, + bytes32 predecessor, + bytes32 salt, + uint256 delay + ) public virtual onlyRole(PROPOSER_ROLE) { + 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 {CallSalt} if salt is nonzero, and one {CallScheduled} event per transaction in the batch. + * + * Requirements: + * + * - the caller must have the 'proposer' role. + */ + function scheduleBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt, + uint256 delay + ) public virtual onlyRole(PROPOSER_ROLE) { + require(targets.length == values.length, "TimelockController: length mismatch"); + require(targets.length == payloads.length, "TimelockController: length mismatch"); + + bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + _schedule(id, delay); + 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); + } + } + + /** + * @dev Schedule an operation that is to become valid after a given delay. + */ + function _schedule(bytes32 id, uint256 delay) private { + require(!isOperation(id), "TimelockController: operation already scheduled"); + require(delay >= getMinDelay(), "TimelockController: insufficient delay"); + _timestamps[id] = block.timestamp + delay; + } + + /** + * @dev Cancel an operation. + * + * Requirements: + * + * - the caller must have the 'canceller' role. + */ + function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) { + require(isOperationPending(id), "TimelockController: operation cannot be cancelled"); + delete _timestamps[id]; + + emit Cancelled(id); + } + + /** + * @dev Execute an (ready) operation containing a single transaction. + * + * Emits a {CallExecuted} event. + * + * Requirements: + * + * - the caller must have the 'executor' role. + */ + // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, + // thus any modifications to the operation during reentrancy should be caught. + // slither-disable-next-line reentrancy-eth + function execute( + address target, + uint256 value, + bytes calldata payload, + bytes32 predecessor, + bytes32 salt + ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { + bytes32 id = hashOperation(target, value, payload, predecessor, salt); + + _beforeCall(id, predecessor); + _execute(target, value, payload); + emit CallExecuted(id, 0, target, value, payload); + _afterCall(id); + } + + /** + * @dev Execute an (ready) operation containing a batch of transactions. + * + * Emits one {CallExecuted} event per transaction in the batch. + * + * Requirements: + * + * - the caller must have the 'executor' role. + */ + // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, + // thus any modifications to the operation during reentrancy should be caught. + // slither-disable-next-line reentrancy-eth + function executeBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt + ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { + require(targets.length == values.length, "TimelockController: length mismatch"); + require(targets.length == payloads.length, "TimelockController: length mismatch"); + + bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + + _beforeCall(id, predecessor); + for (uint256 i = 0; i < targets.length; ++i) { + address target = targets[i]; + uint256 value = values[i]; + bytes calldata payload = payloads[i]; + _execute(target, value, payload); + emit CallExecuted(id, i, target, value, payload); + } + _afterCall(id); + } + + /** + * @dev Execute an operation's call. + */ + function _execute(address target, uint256 value, bytes calldata data) internal virtual { + (bool success, ) = target.call{value: value}(data); + require(success, "TimelockController: underlying transaction reverted"); + } + + /** + * @dev Checks before execution of an operation's calls. + */ + function _beforeCall(bytes32 id, bytes32 predecessor) private view { + require(isOperationReady(id), "TimelockController: operation is not ready"); + require(predecessor == bytes32(0) || isOperationDone(predecessor), "TimelockController: missing dependency"); + } + + /** + * @dev Checks after execution of an operation's calls. + */ + function _afterCall(bytes32 id) private { + require(isOperationReady(id), "TimelockController: operation is not ready"); + _timestamps[id] = _DONE_TIMESTAMP; + } + + /** + * @dev Changes the minimum timelock duration for future operations. + * + * Emits a {MinDelayChange} event. + * + * Requirements: + * + * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing + * an operation where the timelock is the target and the data is the ABI-encoded call to this function. + */ + function updateDelay(uint256 newDelay) external virtual { + require(msg.sender == address(this), "TimelockController: caller must be timelock"); + emit MinDelayChange(_minDelay, newDelay); + _minDelay = newDelay; + } + + /** + * @dev See {IERC721Receiver-onERC721Received}. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { + return this.onERC721Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155Received}. + */ + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155BatchReceived}. + */ + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/compatibility/GovernorCompatibilityBravo.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/compatibility/GovernorCompatibilityBravo.sol new file mode 100644 index 0000000..ecc94fb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/compatibility/GovernorCompatibilityBravo.sol @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/compatibility/GovernorCompatibilityBravo.sol) + +pragma solidity ^0.8.0; + +import "../../utils/math/SafeCast.sol"; +import "../extensions/IGovernorTimelock.sol"; +import "../Governor.sol"; +import "./IGovernorCompatibilityBravo.sol"; + +/** + * @dev Compatibility layer that implements GovernorBravo compatibility on top of {Governor}. + * + * This compatibility layer includes a voting system and requires a {IGovernorTimelock} compatible module to be added + * through inheritance. It does not include token bindings, nor does it include any variable upgrade patterns. + * + * NOTE: When using this module, you may need to enable the Solidity optimizer to avoid hitting the contract size limit. + * + * _Available since v4.3._ + */ +abstract contract GovernorCompatibilityBravo is IGovernorTimelock, IGovernorCompatibilityBravo, Governor { + enum VoteType { + Against, + For, + Abstain + } + + struct ProposalDetails { + address proposer; + address[] targets; + uint256[] values; + string[] signatures; + bytes[] calldatas; + uint256 forVotes; + uint256 againstVotes; + uint256 abstainVotes; + mapping(address => Receipt) receipts; + bytes32 descriptionHash; + } + + mapping(uint256 => ProposalDetails) private _proposalDetails; + + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo&quorum=bravo"; + } + + // ============================================== Proposal lifecycle ============================================== + /** + * @dev See {IGovernor-propose}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + 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); + } + + /** + * @dev See {IGovernorCompatibilityBravo-propose}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + 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 + // 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); + } + + /** + * @dev See {IGovernorCompatibilityBravo-queue}. + */ + function queue(uint256 proposalId) public virtual override { + ( + 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 { + ( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) = _getProposalParameters(proposalId); + + execute(targets, values, calldatas, descriptionHash); + } + + /** + * @dev Cancel a proposal with GovernorBravo logic. + */ + function cancel(uint256 proposalId) public virtual override { + ( + 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( + _msgSender() == proposer || getVotes(proposer, clock() - 1) < proposalThreshold(), + "GovernorBravo: proposer above threshold" + ); + + return _cancel(targets, values, calldatas, descriptionHash); + } + + /** + * @dev Encodes calldatas with optional function signature. + */ + function _encodeCalldata( + string[] memory signatures, + bytes[] memory calldatas + ) private pure returns (bytes[] memory) { + bytes[] memory fullcalldatas = new bytes[](calldatas.length); + 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]); + } + + 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 (if not already present) for later lookup. + */ + function _storeProposal( + address proposer, + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) private { + bytes32 descriptionHash = keccak256(bytes(description)); + uint256 proposalId = hashProposal(targets, values, _encodeCalldata(signatures, calldatas), descriptionHash); + + ProposalDetails storage details = _proposalDetails[proposalId]; + if (details.descriptionHash == bytes32(0)) { + details.proposer = proposer; + details.targets = targets; + details.values = values; + details.signatures = signatures; + details.calldatas = calldatas; + details.descriptionHash = descriptionHash; + } + } + + // ==================================================== Views ===================================================== + /** + * @dev See {IGovernorCompatibilityBravo-proposals}. + */ + function proposals( + uint256 proposalId + ) + public + view + virtual + override + returns ( + uint256 id, + address proposer, + uint256 eta, + uint256 startBlock, + uint256 endBlock, + uint256 forVotes, + uint256 againstVotes, + uint256 abstainVotes, + bool canceled, + bool executed + ) + { + id = proposalId; + eta = proposalEta(proposalId); + startBlock = proposalSnapshot(proposalId); + endBlock = proposalDeadline(proposalId); + + ProposalDetails storage details = _proposalDetails[proposalId]; + proposer = details.proposer; + forVotes = details.forVotes; + againstVotes = details.againstVotes; + abstainVotes = details.abstainVotes; + + ProposalState currentState = state(proposalId); + canceled = currentState == ProposalState.Canceled; + executed = currentState == ProposalState.Executed; + } + + /** + * @dev See {IGovernorCompatibilityBravo-getActions}. + */ + function getActions( + uint256 proposalId + ) + public + view + virtual + override + returns ( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas + ) + { + ProposalDetails storage details = _proposalDetails[proposalId]; + return (details.targets, details.values, details.signatures, details.calldatas); + } + + /** + * @dev See {IGovernorCompatibilityBravo-getReceipt}. + */ + function getReceipt(uint256 proposalId, address voter) public view virtual override returns (Receipt memory) { + return _proposalDetails[proposalId].receipts[voter]; + } + + /** + * @dev See {IGovernorCompatibilityBravo-quorumVotes}. + */ + function quorumVotes() public view virtual override returns (uint256) { + return quorum(clock() - 1); + } + + // ==================================================== Voting ==================================================== + /** + * @dev See {IGovernor-hasVoted}. + */ + function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { + return _proposalDetails[proposalId].receipts[account].hasVoted; + } + + /** + * @dev See {Governor-_quorumReached}. In this module, only forVotes count toward the quorum. + */ + function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { + ProposalDetails storage details = _proposalDetails[proposalId]; + return quorum(proposalSnapshot(proposalId)) <= details.forVotes; + } + + /** + * @dev See {Governor-_voteSucceeded}. In this module, the forVotes must be strictly over the againstVotes. + */ + function _voteSucceeded(uint256 proposalId) internal view virtual override returns (bool) { + ProposalDetails storage details = _proposalDetails[proposalId]; + return details.forVotes > details.againstVotes; + } + + /** + * @dev See {Governor-_countVote}. In this module, the support follows Governor Bravo. + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory // params + ) internal virtual override { + ProposalDetails storage details = _proposalDetails[proposalId]; + Receipt storage receipt = details.receipts[account]; + + require(!receipt.hasVoted, "GovernorCompatibilityBravo: vote already cast"); + receipt.hasVoted = true; + receipt.support = support; + receipt.votes = SafeCast.toUint96(weight); + + if (support == uint8(VoteType.Against)) { + details.againstVotes += weight; + } else if (support == uint8(VoteType.For)) { + details.forVotes += weight; + } else if (support == uint8(VoteType.Abstain)) { + details.abstainVotes += weight; + } else { + revert("GovernorCompatibilityBravo: invalid vote type"); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol new file mode 100644 index 0000000..e64a66a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/compatibility/IGovernorCompatibilityBravo.sol) + +pragma solidity ^0.8.0; + +import "../IGovernor.sol"; + +/** + * @dev Interface extension that adds missing functions to the {Governor} core to provide `GovernorBravo` compatibility. + * + * _Available since v4.3._ + */ +abstract contract IGovernorCompatibilityBravo is IGovernor { + /** + * @dev Proposal structure from Compound Governor Bravo. Not actually used by the compatibility layer, as + * {{proposal}} returns a very different structure. + */ + struct Proposal { + uint256 id; + address proposer; + uint256 eta; + address[] targets; + uint256[] values; + string[] signatures; + bytes[] calldatas; + uint256 startBlock; + uint256 endBlock; + uint256 forVotes; + uint256 againstVotes; + uint256 abstainVotes; + bool canceled; + bool executed; + mapping(address => Receipt) receipts; + } + + /** + * @dev Receipt structure from Compound Governor Bravo + */ + struct Receipt { + bool hasVoted; + uint8 support; + uint96 votes; + } + + /** + * @dev Part of the Governor Bravo's interface. + */ + function quorumVotes() public view virtual returns (uint256); + + /** + * @dev Part of the Governor Bravo's interface: _"The official record of all proposals ever proposed"_. + */ + function proposals( + uint256 + ) + public + view + virtual + returns ( + uint256 id, + address proposer, + uint256 eta, + uint256 startBlock, + uint256 endBlock, + uint256 forVotes, + uint256 againstVotes, + uint256 abstainVotes, + bool canceled, + bool executed + ); + + /** + * @dev Part of the Governor Bravo's interface: _"Function used to propose a new proposal"_. + */ + function propose( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) public virtual returns (uint256); + + /** + * @dev Part of the Governor Bravo's interface: _"Queues a proposal of state succeeded"_. + */ + function queue(uint256 proposalId) public virtual; + + /** + * @dev Part of the Governor Bravo's interface: _"Executes a queued proposal if eta has passed"_. + */ + 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"_. + */ + function getActions( + uint256 proposalId + ) + public + view + virtual + returns ( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas + ); + + /** + * @dev Part of the Governor Bravo's interface: _"Gets the receipt for a voter on a given proposal"_. + */ + function getReceipt(uint256 proposalId, address voter) public view virtual returns (Receipt memory); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorCountingSimple.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorCountingSimple.sol new file mode 100644 index 0000000..b951744 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorCountingSimple.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/extensions/GovernorCountingSimple.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; + +/** + * @dev Extension of {Governor} for simple, 3 options, vote counting. + * + * _Available since v4.3._ + */ +abstract contract GovernorCountingSimple is Governor { + /** + * @dev Supported vote types. Matches Governor Bravo ordering. + */ + enum VoteType { + Against, + For, + Abstain + } + + struct ProposalVote { + uint256 againstVotes; + uint256 forVotes; + uint256 abstainVotes; + mapping(address => bool) hasVoted; + } + + mapping(uint256 => ProposalVote) private _proposalVotes; + + /** + * @dev See {IGovernor-COUNTING_MODE}. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo&quorum=for,abstain"; + } + + /** + * @dev See {IGovernor-hasVoted}. + */ + function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { + return _proposalVotes[proposalId].hasVoted[account]; + } + + /** + * @dev Accessor to the internal vote counts. + */ + function proposalVotes( + uint256 proposalId + ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + return (proposalVote.againstVotes, proposalVote.forVotes, proposalVote.abstainVotes); + } + + /** + * @dev See {Governor-_quorumReached}. + */ + function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + return quorum(proposalSnapshot(proposalId)) <= proposalVote.forVotes + proposalVote.abstainVotes; + } + + /** + * @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) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + return proposalVote.forVotes > proposalVote.againstVotes; + } + + /** + * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo). + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory // params + ) internal virtual override { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + require(!proposalVote.hasVoted[account], "GovernorVotingSimple: vote already cast"); + proposalVote.hasVoted[account] = true; + + if (support == uint8(VoteType.Against)) { + proposalVote.againstVotes += weight; + } else if (support == uint8(VoteType.For)) { + proposalVote.forVotes += weight; + } else if (support == uint8(VoteType.Abstain)) { + proposalVote.abstainVotes += weight; + } else { + revert("GovernorVotingSimple: invalid value for enum VoteType"); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorPreventLateQuorum.sol new file mode 100644 index 0000000..752a92c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/extensions/GovernorPreventLateQuorum.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; +import "../../utils/math/Math.sol"; + +/** + * @dev A module that ensures there is a minimum voting period after quorum is reached. This prevents a large voter from + * swaying a vote and triggering quorum at the last minute, by ensuring there is always time for other voters to react + * 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 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 { + uint64 private _voteExtension; + + /// @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); + + /// @dev Emitted when the {lateQuorumVoteExtension} parameter is changed. + event LateQuorumVoteExtensionSet(uint64 oldVoteExtension, uint64 newVoteExtension); + + /** + * @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); + } + + /** + * @dev Returns the proposal deadline, which may have been extended beyond that set at proposal creation, if the + * 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]); + } + + /** + * @dev Casts a vote and detects if it caused quorum to be reached, potentially extending the voting period. See + * {Governor-_castVote}. + * + * May emit a {ProposalExtended} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual override returns (uint256) { + uint256 result = super._castVote(proposalId, account, support, reason, params); + + if (_extendedDeadlines[proposalId] == 0 && _quorumReached(proposalId)) { + uint64 extendedDeadline = clock() + lateQuorumVoteExtension(); + + if (extendedDeadline > proposalDeadline(proposalId)) { + emit ProposalExtended(proposalId, extendedDeadline); + } + + _extendedDeadlines[proposalId] = extendedDeadline; + } + + return result; + } + + /** + * @dev Returns the current value of the vote extension parameter: the number of blocks that are required to pass + * from the time a proposal reaches quorum until its voting period ends. + */ + function lateQuorumVoteExtension() public view virtual returns (uint64) { + return _voteExtension; + } + + /** + * @dev Changes the {lateQuorumVoteExtension}. This operation can only be performed by the governance executor, + * generally through a governance proposal. + * + * Emits a {LateQuorumVoteExtensionSet} event. + */ + function setLateQuorumVoteExtension(uint64 newVoteExtension) public virtual onlyGovernance { + _setLateQuorumVoteExtension(newVoteExtension); + } + + /** + * @dev Changes the {lateQuorumVoteExtension}. This is an internal function that can be exposed in a public function + * like {setLateQuorumVoteExtension} if another access control mechanism is needed. + * + * Emits a {LateQuorumVoteExtensionSet} event. + */ + function _setLateQuorumVoteExtension(uint64 newVoteExtension) internal virtual { + emit LateQuorumVoteExtensionSet(_voteExtension, newVoteExtension); + _voteExtension = newVoteExtension; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorProposalThreshold.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorProposalThreshold.sol new file mode 100644 index 0000000..3feebac --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorProposalThreshold.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (governance/extensions/GovernorProposalThreshold.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; + +/** + * @dev Extension of {Governor} for proposal restriction to token holders with a minimum balance. + * + * _Available since v4.3._ + * _Deprecated since v4.4._ + */ +abstract contract GovernorProposalThreshold is Governor { + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual override returns (uint256) { + return super.propose(targets, values, calldatas, description); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorSettings.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorSettings.sol new file mode 100644 index 0000000..ec6a983 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorSettings.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/extensions/GovernorSettings.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; + +/** + * @dev Extension of {Governor} for settings updatable through governance. + * + * _Available since v4.4._ + */ +abstract contract GovernorSettings is Governor { + uint256 private _votingDelay; + uint256 private _votingPeriod; + uint256 private _proposalThreshold; + + event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay); + event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod); + event ProposalThresholdSet(uint256 oldProposalThreshold, uint256 newProposalThreshold); + + /** + * @dev Initialize the governance parameters. + */ + constructor(uint256 initialVotingDelay, uint256 initialVotingPeriod, uint256 initialProposalThreshold) { + _setVotingDelay(initialVotingDelay); + _setVotingPeriod(initialVotingPeriod); + _setProposalThreshold(initialProposalThreshold); + } + + /** + * @dev See {IGovernor-votingDelay}. + */ + function votingDelay() public view virtual override returns (uint256) { + return _votingDelay; + } + + /** + * @dev See {IGovernor-votingPeriod}. + */ + function votingPeriod() public view virtual override returns (uint256) { + return _votingPeriod; + } + + /** + * @dev See {Governor-proposalThreshold}. + */ + function proposalThreshold() public view virtual override returns (uint256) { + return _proposalThreshold; + } + + /** + * @dev Update the voting delay. This operation can only be performed through a governance proposal. + * + * Emits a {VotingDelaySet} event. + */ + function setVotingDelay(uint256 newVotingDelay) public virtual onlyGovernance { + _setVotingDelay(newVotingDelay); + } + + /** + * @dev Update the voting period. This operation can only be performed through a governance proposal. + * + * Emits a {VotingPeriodSet} event. + */ + function setVotingPeriod(uint256 newVotingPeriod) public virtual onlyGovernance { + _setVotingPeriod(newVotingPeriod); + } + + /** + * @dev Update the proposal threshold. This operation can only be performed through a governance proposal. + * + * Emits a {ProposalThresholdSet} event. + */ + function setProposalThreshold(uint256 newProposalThreshold) public virtual onlyGovernance { + _setProposalThreshold(newProposalThreshold); + } + + /** + * @dev Internal setter for the voting delay. + * + * Emits a {VotingDelaySet} event. + */ + function _setVotingDelay(uint256 newVotingDelay) internal virtual { + emit VotingDelaySet(_votingDelay, newVotingDelay); + _votingDelay = newVotingDelay; + } + + /** + * @dev Internal setter for the voting period. + * + * Emits a {VotingPeriodSet} event. + */ + function _setVotingPeriod(uint256 newVotingPeriod) internal virtual { + // voting period must be at least one block long + require(newVotingPeriod > 0, "GovernorSettings: voting period too low"); + emit VotingPeriodSet(_votingPeriod, newVotingPeriod); + _votingPeriod = newVotingPeriod; + } + + /** + * @dev Internal setter for the proposal threshold. + * + * Emits a {ProposalThresholdSet} event. + */ + function _setProposalThreshold(uint256 newProposalThreshold) internal virtual { + emit ProposalThresholdSet(_proposalThreshold, newProposalThreshold); + _proposalThreshold = newProposalThreshold; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorTimelockCompound.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorTimelockCompound.sol new file mode 100644 index 0000000..a706da6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/extensions/GovernorTimelockCompound.sol) + +pragma solidity ^0.8.0; + +import "./IGovernorTimelock.sol"; +import "../Governor.sol"; +import "../../utils/math/SafeCast.sol"; +import "../../vendor/compound/ICompoundTimelock.sol"; + +/** + * @dev Extension of {Governor} that binds the execution process to a Compound Timelock. This adds a delay, enforced by + * the external timelock to all successful proposal (in addition to the voting duration). The {Governor} needs to be + * the admin of the timelock for any operation to be performed. A public, unrestricted, + * {GovernorTimelockCompound-__acceptAdmin} is available to accept ownership of the timelock. + * + * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * inaccessible. + * + * _Available since v4.3._ + */ +abstract contract GovernorTimelockCompound is IGovernorTimelock, Governor { + ICompoundTimelock private _timelock; + + /// @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. + */ + event TimelockChange(address oldTimelock, address newTimelock); + + /** + * @dev Set the timelock. + */ + constructor(ICompoundTimelock timelockAddress) { + _updateTimelock(timelockAddress); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, Governor) returns (bool) { + return interfaceId == type(IGovernorTimelock).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @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 currentState = super.state(proposalId); + + if (currentState != ProposalState.Succeeded) { + return currentState; + } + + uint256 eta = proposalEta(proposalId); + if (eta == 0) { + return currentState; + } else if (block.timestamp >= eta + _timelock.GRACE_PERIOD()) { + return ProposalState.Expired; + } else { + return ProposalState.Queued; + } + } + + /** + * @dev Public accessor to check the address of the timelock + */ + function timelock() public view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Public accessor to check the eta of a queued proposal + */ + function proposalEta(uint256 proposalId) public view virtual override returns (uint256) { + return _proposalTimelocks[proposalId]; + } + + /** + * @dev Function to queue a proposal to the timelock. + */ + function queue( + 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.Succeeded, "Governor: proposal not successful"); + + uint256 eta = block.timestamp + _timelock.delay(); + _proposalTimelocks[proposalId] = SafeCast.toUint64(eta); + + for (uint256 i = 0; i < targets.length; ++i) { + require( + !_timelock.queuedTransactions(keccak256(abi.encode(targets[i], values[i], "", calldatas[i], eta))), + "GovernorTimelockCompound: identical proposal action already queued" + ); + _timelock.queueTransaction(targets[i], values[i], "", calldatas[i], eta); + } + + emit ProposalQueued(proposalId, eta); + + return proposalId; + } + + /** + * @dev Overridden execute function that run the already queued proposal through the timelock. + */ + function _execute( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual override { + uint256 eta = proposalEta(proposalId); + require(eta > 0, "GovernorTimelockCompound: proposal not yet queued"); + Address.sendValue(payable(_timelock), msg.value); + for (uint256 i = 0; i < targets.length; ++i) { + _timelock.executeTransaction(targets[i], values[i], "", calldatas[i], eta); + } + } + + /** + * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it as already + * been queued. + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + 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); + } + } + + return proposalId; + } + + /** + * @dev Address through which the governor executes action. In this case, the timelock. + */ + function _executor() internal view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Accept admin right over the timelock. + */ + // solhint-disable-next-line private-vars-leading-underscore + function __acceptAdmin() public { + _timelock.acceptAdmin(); + } + + /** + * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates + * must be proposed, scheduled, and executed through governance proposals. + * + * For security reasons, the timelock must be handed over to another admin before setting up a new one. The two + * operations (hand over the timelock) and do the update can be batched in a single proposal. + * + * Note that if the timelock admin has been handed over in a previous operation, we refuse updates made through the + * timelock if admin of the timelock has already been accepted and the operation is executed outside the scope of + * governance. + + * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. + */ + function updateTimelock(ICompoundTimelock newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(ICompoundTimelock newTimelock) private { + emit TimelockChange(address(_timelock), address(newTimelock)); + _timelock = newTimelock; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorTimelockControl.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorTimelockControl.sol new file mode 100644 index 0000000..7cb60ba --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorTimelockControl.sol @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/extensions/GovernorTimelockControl.sol) + +pragma solidity ^0.8.0; + +import "./IGovernorTimelock.sol"; +import "../Governor.sol"; +import "../TimelockController.sol"; + +/** + * @dev Extension of {Governor} that binds the execution process to an instance of {TimelockController}. This adds a + * delay, enforced by the {TimelockController} to all successful proposal (in addition to the voting duration). The + * {Governor} needs the proposer (and ideally the executor) roles for the {Governor} to work properly. + * + * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * inaccessible. + * + * WARNING: Setting up the TimelockController to have additional proposers besides the governor is very risky, as it + * grants them powers that they must be trusted or known not to use: 1) {onlyGovernance} functions like {relay} are + * available to them through the timelock, and 2) approved governance proposals can be blocked by them, effectively + * executing a Denial of Service attack. This risk will be mitigated in a future release. + * + * _Available since v4.3._ + */ +abstract contract GovernorTimelockControl is IGovernorTimelock, Governor { + TimelockController private _timelock; + mapping(uint256 => bytes32) private _timelockIds; + + /** + * @dev Emitted when the timelock controller used for proposal execution is modified. + */ + event TimelockChange(address oldTimelock, address newTimelock); + + /** + * @dev Set the timelock. + */ + constructor(TimelockController timelockAddress) { + _updateTimelock(timelockAddress); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, Governor) returns (bool) { + return interfaceId == type(IGovernorTimelock).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @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 currentState = super.state(proposalId); + + 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 currentState; + } else if (_timelock.isOperationDone(queueid)) { + return ProposalState.Executed; + } else if (_timelock.isOperationPending(queueid)) { + return ProposalState.Queued; + } else { + return ProposalState.Canceled; + } + } + + /** + * @dev Public accessor to check the address of the timelock + */ + function timelock() public view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Public accessor to check the eta of a queued proposal + */ + function proposalEta(uint256 proposalId) public view virtual override returns (uint256) { + uint256 eta = _timelock.getTimestamp(_timelockIds[proposalId]); + return eta == 1 ? 0 : eta; // _DONE_TIMESTAMP (1) should be replaced with a 0 value + } + + /** + * @dev Function to queue a proposal to the timelock. + */ + function queue( + 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.Succeeded, "Governor: proposal not successful"); + + uint256 delay = _timelock.getMinDelay(); + _timelockIds[proposalId] = _timelock.hashOperationBatch(targets, values, calldatas, 0, descriptionHash); + _timelock.scheduleBatch(targets, values, calldatas, 0, descriptionHash, delay); + + emit ProposalQueued(proposalId, block.timestamp + delay); + + return proposalId; + } + + /** + * @dev Overridden execute function that run the already queued proposal through the timelock. + */ + function _execute( + uint256 /* proposalId */, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override { + _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, descriptionHash); + } + + /** + * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it as already + * been queued. + */ + // This function can reenter through the external call to the timelock, but we assume the timelock is trusted and + // well behaved (according to TimelockController) and this will not happen. + // slither-disable-next-line reentrancy-no-eth + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + if (_timelockIds[proposalId] != 0) { + _timelock.cancel(_timelockIds[proposalId]); + delete _timelockIds[proposalId]; + } + + return proposalId; + } + + /** + * @dev Address through which the governor executes action. In this case, the timelock. + */ + function _executor() internal view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates + * must be proposed, scheduled, and executed through governance proposals. + * + * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. + */ + function updateTimelock(TimelockController newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(TimelockController newTimelock) private { + emit TimelockChange(address(_timelock), address(newTimelock)); + _timelock = newTimelock; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotes.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotes.sol new file mode 100644 index 0000000..c2e65cb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotes.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/extensions/GovernorVotes.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; +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._ + */ +abstract contract GovernorVotes is Governor { + IERC5805 public immutable token; + + constructor(IVotes 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"; + } + } + + /** + * Read the voting weight from the token's built in snapshot mechanism (see {Governor-_getVotes}). + */ + function _getVotes( + address account, + uint256 timepoint, + bytes memory /*params*/ + ) internal view virtual override returns (uint256) { + return token.getPastVotes(account, timepoint); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotesComp.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotesComp.sol new file mode 100644 index 0000000..e7d7c2c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotesComp.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/extensions/GovernorVotesComp.sol) + +pragma solidity ^0.8.0; + +import "../Governor.sol"; +import "../../token/ERC20/extensions/ERC20VotesComp.sol"; + +/** + * @dev Extension of {Governor} for voting weight extraction from a Comp token. + * + * _Available since v4.3._ + */ +abstract contract GovernorVotesComp is Governor { + ERC20VotesComp public immutable token; + + constructor(ERC20VotesComp token_) { + token = token_; + } + + /** + * @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 timepoint, + bytes memory /*params*/ + ) internal view virtual override returns (uint256) { + return token.getPriorVotes(account, timepoint); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotesQuorumFraction.sol new file mode 100644 index 0000000..097a796 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/extensions/GovernorVotesQuorumFraction.sol) + +pragma solidity ^0.8.0; + +import "./GovernorVotes.sol"; +import "../../utils/Checkpoints.sol"; +import "../../utils/math/SafeCast.sol"; + +/** + * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a + * fraction of the total supply. + * + * _Available since v4.3._ + */ +abstract contract GovernorVotesQuorumFraction is GovernorVotes { + using Checkpoints for Checkpoints.Trace224; + + uint256 private _quorumNumerator; // DEPRECATED in favor of _quorumNumeratorHistory + + /// @custom:oz-retyped-from Checkpoints.History + Checkpoints.Trace224 private _quorumNumeratorHistory; + + event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator); + + /** + * @dev Initialize quorum as a fraction of the token's total supply. + * + * The fraction is specified as `numerator / denominator`. By default the denominator is 100, so quorum is + * specified as a percent: a numerator of 10 corresponds to quorum being 10% of total supply. The denominator can be + * customized by overriding {quorumDenominator}. + */ + constructor(uint256 quorumNumeratorValue) { + _updateQuorumNumerator(quorumNumeratorValue); + } + + /** + * @dev Returns the current quorum numerator. See {quorumDenominator}. + */ + function quorumNumerator() public view virtual returns (uint256) { + return _quorumNumeratorHistory._checkpoints.length == 0 ? _quorumNumerator : _quorumNumeratorHistory.latest(); + } + + /** + * @dev Returns the quorum numerator at a specific timepoint. See {quorumDenominator}. + */ + 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) { + return _quorumNumerator; + } + + // Optimistic search, check the latest checkpoint + Checkpoints.Checkpoint224 memory latest = _quorumNumeratorHistory._checkpoints[length - 1]; + if (latest._key <= timepoint) { + return latest._value; + } + + // Otherwise, do the binary search + return _quorumNumeratorHistory.upperLookupRecent(SafeCast.toUint32(timepoint)); + } + + /** + * @dev Returns the quorum denominator. Defaults to 100, but may be overridden. + */ + function quorumDenominator() public view virtual returns (uint256) { + return 100; + } + + /** + * @dev Returns the quorum for a timepoint, in terms of number of votes: `supply * numerator / denominator`. + */ + function quorum(uint256 timepoint) public view virtual override returns (uint256) { + return (token.getPastTotalSupply(timepoint) * quorumNumerator(timepoint)) / quorumDenominator(); + } + + /** + * @dev Changes the quorum numerator. + * + * Emits a {QuorumNumeratorUpdated} event. + * + * Requirements: + * + * - Must be called through a governance proposal. + * - New numerator must be smaller or equal to the denominator. + */ + function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance { + _updateQuorumNumerator(newQuorumNumerator); + } + + /** + * @dev Changes the quorum numerator. + * + * Emits a {QuorumNumeratorUpdated} event. + * + * Requirements: + * + * - New numerator must be smaller or equal to the denominator. + */ + function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual { + require( + newQuorumNumerator <= quorumDenominator(), + "GovernorVotesQuorumFraction: quorumNumerator over quorumDenominator" + ); + + uint256 oldQuorumNumerator = quorumNumerator(); + + // 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: SafeCast.toUint224(oldQuorumNumerator)}) + ); + } + + // Set new quorum for future proposals + _quorumNumeratorHistory.push(SafeCast.toUint32(clock()), SafeCast.toUint224(newQuorumNumerator)); + + emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/IGovernorTimelock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/IGovernorTimelock.sol new file mode 100644 index 0000000..40402f6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/extensions/IGovernorTimelock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (governance/extensions/IGovernorTimelock.sol) + +pragma solidity ^0.8.0; + +import "../IGovernor.sol"; + +/** + * @dev Extension of the {IGovernor} for timelock supporting modules. + * + * _Available since v4.3._ + */ +abstract contract IGovernorTimelock is IGovernor { + event ProposalQueued(uint256 proposalId, uint256 eta); + + function timelock() public view virtual returns (address); + + function proposalEta(uint256 proposalId) public view virtual returns (uint256); + + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256 proposalId); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/utils/IVotes.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/utils/IVotes.sol new file mode 100644 index 0000000..647f796 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/utils/IVotes.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (governance/utils/IVotes.sol) +pragma solidity ^0.8.0; + +/** + * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. + * + * _Available since v4.5._ + */ +interface IVotes { + /** + * @dev Emitted when an account changes their delegate. + */ + event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); + + /** + * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes. + */ + event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance); + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) external view returns (uint256); + + /** + * @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 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 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 + * vote. + */ + function getPastTotalSupply(uint256 timepoint) external view returns (uint256); + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) external view returns (address); + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) external; + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/governance/utils/Votes.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/utils/Votes.sol new file mode 100644 index 0000000..f0a53ba --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/governance/utils/Votes.sol @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.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"; + +/** + * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be + * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of + * "representative" that will pool delegated voting units from different accounts and can then use it to vote in + * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to + * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative. + * + * This contract is often combined with a token contract such that voting units correspond to token units. For an + * example, see {ERC721Votes}. + * + * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed + * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the + * cost of this history tracking optional. + * + * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return + * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the + * previous example, it would be included in {ERC721-_beforeTokenTransfer}). + * + * _Available since v4.5._ + */ +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; + + /// @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, "Votes: broken clock mode"); + return "mode=blocknumber&from=default"; + } + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) public view virtual override returns (uint256) { + return _delegateCheckpoints[account].latest(); + } + + /** + * @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 at the end of the corresponding block. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + 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 a specific moment in the past. If the `clock()` is + * 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 + * vote. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastTotalSupply(uint256 timepoint) public view virtual override returns (uint256) { + require(timepoint < clock(), "Votes: future lookup"); + return _totalCheckpoints.upperLookupRecent(SafeCast.toUint32(timepoint)); + } + + /** + * @dev Returns the current total supply of votes. + */ + function _getTotalSupply() internal view virtual returns (uint256) { + return _totalCheckpoints.latest(); + } + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) public view virtual override returns (address) { + return _delegation[account]; + } + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) public virtual override { + address account = _msgSender(); + _delegate(account, 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, "Votes: signature expired"); + address signer = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(_DELEGATION_TYPEHASH, delegatee, nonce, expiry))), + v, + r, + s + ); + require(nonce == _useNonce(signer), "Votes: invalid nonce"); + _delegate(signer, delegatee); + } + + /** + * @dev Delegate all of `account`'s voting units to `delegatee`. + * + * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. + */ + function _delegate(address account, address delegatee) internal virtual { + address oldDelegate = delegates(account); + _delegation[account] = delegatee; + + emit DelegateChanged(account, oldDelegate, delegatee); + _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account)); + } + + /** + * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to` + * should be zero. Total supply of voting units will be adjusted with mints and burns. + */ + function _transferVotingUnits(address from, address to, uint256 amount) internal virtual { + if (from == address(0)) { + _push(_totalCheckpoints, _add, SafeCast.toUint224(amount)); + } + if (to == address(0)) { + _push(_totalCheckpoints, _subtract, SafeCast.toUint224(amount)); + } + _moveDelegateVotes(delegates(from), delegates(to), amount); + } + + /** + * @dev Moves delegated votes from one delegate to another. + */ + function _moveDelegateVotes(address from, address to, uint256 amount) private { + if (from != to && amount > 0) { + if (from != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[from], + _subtract, + SafeCast.toUint224(amount) + ); + emit DelegateVotesChanged(from, oldValue, newValue); + } + if (to != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[to], + _add, + SafeCast.toUint224(amount) + ); + emit DelegateVotesChanged(to, oldValue, newValue); + } + } + } + + 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(uint224 a, uint224 b) private pure returns (uint224) { + return a - b; + } + + /** + * @dev Consumes a nonce. + * + * Returns the current value and increments nonce. + */ + function _useNonce(address owner) internal virtual returns (uint256 current) { + Counters.Counter storage nonce = _nonces[owner]; + current = nonce.current(); + nonce.increment(); + } + + /** + * @dev Returns an address nonce. + */ + function nonces(address owner) public view virtual returns (uint256) { + return _nonces[owner].current(); + } + + /** + * @dev Returns the contract's {EIP712} domain separator. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view returns (bytes32) { + return _domainSeparatorV4(); + } + + /** + * @dev Must return the voting units held by an account. + */ + function _getVotingUnits(address) internal view virtual returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155.sol new file mode 100644 index 0000000..f891132 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC1155/IERC1155.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155MetadataURI.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155MetadataURI.sol new file mode 100644 index 0000000..2aa885f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155MetadataURI.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155MetadataURI.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC1155/extensions/IERC1155MetadataURI.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155Receiver.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155Receiver.sol new file mode 100644 index 0000000..a6d4ead --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1155Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1155Receiver.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC1155/IERC1155Receiver.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1271.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1271.sol new file mode 100644 index 0000000..5ec44c7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1271.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC1271 standard signature validation method for + * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. + * + * _Available since v4.1._ + */ +interface IERC1271 { + /** + * @dev Should return whether the signature provided is valid for the provided data + * @param hash Hash of the data to be signed + * @param signature Signature byte array associated with _data + */ + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363.sol new file mode 100644 index 0000000..817f3da --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1363.sol) + +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. + * 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)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) + */ + + /** + * @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 amount uint256 The amount of tokens to be transferred + * @return true unless throwing + */ + 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 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 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 amount uint256 The amount of tokens to be transferred + * @return true unless throwing + */ + 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 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 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 amount uint256 The amount of tokens to be spent + */ + 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 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 amount, bytes memory data) external returns (bool); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363Receiver.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363Receiver.sol new file mode 100644 index 0000000..382d7f1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363Receiver.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1363Receiver.sol) + +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. + * 0x88a7ca5c === bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)")) + */ + + /** + * @notice Handle the receipt of ERC1363 tokens + * @dev Any ERC1363 smart contract calls this function on the recipient + * after a `transfer` or a `transferFrom`. This function MAY throw to revert and reject the + * transfer. Return of other than the magic value MUST result in the + * transaction being reverted. + * 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 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 + */ + function onTransferReceived( + address operator, + address from, + uint256 amount, + bytes memory data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363Spender.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363Spender.sol new file mode 100644 index 0000000..09a7bd2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1363Spender.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1363Spender.sol) + +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. + * 0x7b04a2d0 === bytes4(keccak256("onApprovalReceived(address,uint256,bytes)")) + */ + + /** + * @notice Handle the approval of ERC1363 tokens + * @dev Any ERC1363 smart contract calls this function on the recipient + * after an `approve`. This function MAY throw to revert and reject the + * approval. Return of other than the magic value MUST result in the + * transaction being reverted. + * Note: the token contract address is always the message sender. + * @param owner address The address which called `approveAndCall` function + * @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 + */ + function onApprovalReceived(address owner, uint256 amount, bytes memory data) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC165.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC165.sol new file mode 100644 index 0000000..b97c4da --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC165.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC165.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1820Implementer.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1820Implementer.sol new file mode 100644 index 0000000..a83a7a3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1820Implementer.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1820Implementer.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC1820Implementer.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1820Registry.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1820Registry.sol new file mode 100644 index 0000000..1b1ba9f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1820Registry.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1820Registry.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC1820Registry.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1967.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1967.sol new file mode 100644 index 0000000..6fb112a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC1967.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol) + +pragma solidity ^0.8.0; + +/** + * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. + * + * _Available since v4.8.3._ + */ +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/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC20.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC20.sol new file mode 100644 index 0000000..a819316 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC20.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/IERC20.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC20Metadata.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC20Metadata.sol new file mode 100644 index 0000000..aa5c639 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC20Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20Metadata.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2309.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2309.sol new file mode 100644 index 0000000..b3fec44 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2309.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (interfaces/IERC2309.sol) + +pragma solidity ^0.8.0; + +/** + * @dev ERC-2309: ERC-721 Consecutive Transfer Extension. + * + * _Available since v4.8._ + */ +interface IERC2309 { + /** + * @dev Emitted when the tokens from `fromTokenId` to `toTokenId` are transferred from `fromAddress` to `toAddress`. + */ + event ConsecutiveTransfer( + uint256 indexed fromTokenId, + uint256 toTokenId, + address indexed fromAddress, + address indexed toAddress + ); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2612.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2612.sol new file mode 100644 index 0000000..cd5fca4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2612.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2612.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/extensions/IERC20Permit.sol"; + +interface IERC2612 is IERC20Permit {} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2981.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2981.sol new file mode 100644 index 0000000..465b872 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC2981.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol) + +pragma solidity ^0.8.0; + +import "../utils/introspection/IERC165.sol"; + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + * + * _Available since v4.5._ + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156.sol new file mode 100644 index 0000000..1238190 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156.sol) + +pragma solidity ^0.8.0; + +import "./IERC3156FlashBorrower.sol"; +import "./IERC3156FlashLender.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156FlashBorrower.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156FlashBorrower.sol new file mode 100644 index 0000000..84bd721 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156FlashBorrower.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC3156FlashBorrower.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC3156 FlashBorrower, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + * + * _Available since v4.1._ + */ +interface IERC3156FlashBorrower { + /** + * @dev Receive a flash loan. + * @param initiator The initiator of the loan. + * @param token The loan currency. + * @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 "ERC3156FlashBorrower.onFlashLoan" + */ + function onFlashLoan( + address initiator, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) external returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156FlashLender.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156FlashLender.sol new file mode 100644 index 0000000..3101283 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC3156FlashLender.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC3156FlashLender.sol) + +pragma solidity ^0.8.0; + +import "./IERC3156FlashBorrower.sol"; + +/** + * @dev Interface of the ERC3156 FlashLender, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + * + * _Available since v4.1._ + */ +interface IERC3156FlashLender { + /** + * @dev The amount of currency available to be lended. + * @param token The loan currency. + * @return The amount of `token` that can be borrowed. + */ + function maxFlashLoan(address token) external view returns (uint256); + + /** + * @dev The fee to be charged for a given loan. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @return The amount of `token` to be charged for the loan, on top of the returned principal. + */ + function flashFee(address token, uint256 amount) external view returns (uint256); + + /** + * @dev Initiate a flash loan. + * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @param data Arbitrary data structure, intended to contain user-defined parameters. + */ + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 amount, + bytes calldata data + ) external returns (bool); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC4626.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC4626.sol new file mode 100644 index 0000000..77dd96a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC4626.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4626.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC20/IERC20.sol"; +import "../token/ERC20/extensions/IERC20Metadata.sol"; + +/** + * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in + * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. + * + * _Available since v4.7._ + */ +interface IERC4626 is IERC20, IERC20Metadata { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, + address indexed receiver, + address indexed owner, + uint256 assets, + uint256 shares + ); + + /** + * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + * + * - MUST be an ERC-20 token contract. + * - MUST NOT revert. + */ + function asset() external view returns (address assetTokenAddress); + + /** + * @dev Returns the total amount of the underlying asset that is “managed” by Vault. + * + * - SHOULD include any compounding that occurs from yield. + * - MUST be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT revert. + */ + function totalAssets() external view returns (uint256 totalManagedAssets); + + /** + * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + * scenario where all the conditions are met. + * + * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + * - MUST NOT revert. + * + * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + * from. + */ + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + * scenario where all the conditions are met. + * + * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + * - MUST NOT revert. + * + * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + * from. + */ + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + * through a deposit call. + * + * - MUST return a limited value if receiver is subject to some deposit limit. + * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + * - MUST NOT revert. + */ + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + * current on-chain conditions. + * + * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + * in the same transaction. + * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + * deposit would be accepted, regardless if the user has enough tokens approved, etc. + * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by depositing. + */ + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + * + * - MUST emit the Deposit event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * deposit execution, and are accounted for during deposit. + * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + * approving enough underlying tokens to the Vault contract, etc). + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + */ + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /** + * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + * - MUST return a limited value if receiver is subject to some mint limit. + * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + * - MUST NOT revert. + */ + function maxMint(address receiver) external view returns (uint256 maxShares); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + * current on-chain conditions. + * + * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + * same transaction. + * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + * would be accepted, regardless if the user has enough tokens approved, etc. + * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by minting. + */ + function previewMint(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + * + * - MUST emit the Deposit event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + * execution, and are accounted for during mint. + * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + * approving enough underlying tokens to the Vault contract, etc). + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + */ + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /** + * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + * Vault, through a withdraw call. + * + * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + * - MUST NOT revert. + */ + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + * given current on-chain conditions. + * + * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + * called + * in the same transaction. + * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + * the withdrawal would be accepted, regardless if the user has enough shares, etc. + * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by depositing. + */ + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. + * + * - MUST emit the Withdraw event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * withdraw execution, and are accounted for during withdraw. + * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + * not having enough shares, etc). + * + * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + * Those methods should be performed separately. + */ + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /** + * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + * through a redeem call. + * + * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + * - MUST NOT revert. + */ + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + * given current on-chain conditions. + * + * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + * same transaction. + * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + * redemption would be accepted, regardless if the user has enough shares, etc. + * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by redeeming. + */ + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. + * + * - MUST emit the Withdraw event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * redeem execution, and are accounted for during redeem. + * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + * not having enough shares, etc). + * + * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + * Those methods should be performed separately. + */ + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC4906.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC4906.sol new file mode 100644 index 0000000..f5a6e00 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC4906.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4906.sol) + +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/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5267.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5267.sol new file mode 100644 index 0000000..4d3a6b9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5267.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol) + +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/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5313.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5313.sol new file mode 100644 index 0000000..e26094c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5313.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5313.sol) + +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); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5805.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5805.sol new file mode 100644 index 0000000..a012ccb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC5805.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5805.sol) + +pragma solidity ^0.8.0; + +import "../governance/utils/IVotes.sol"; +import "./IERC6372.sol"; + +interface IERC5805 is IERC6372, IVotes {} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC6372.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC6372.sol new file mode 100644 index 0000000..4c5fe03 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC6372.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (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/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721.sol new file mode 100644 index 0000000..822b311 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/IERC721.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Enumerable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Enumerable.sol new file mode 100644 index 0000000..e39a5a0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Enumerable.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Enumerable.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/extensions/IERC721Enumerable.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Metadata.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Metadata.sol new file mode 100644 index 0000000..afe2707 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Metadata.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Receiver.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Receiver.sol new file mode 100644 index 0000000..c9c153a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC721Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC721Receiver.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC721/IERC721Receiver.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777.sol new file mode 100644 index 0000000..b97ba7b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC777/IERC777.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777Recipient.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777Recipient.sol new file mode 100644 index 0000000..0ce2704 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777Recipient.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777Recipient.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC777/IERC777Recipient.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777Sender.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777Sender.sol new file mode 100644 index 0000000..f1f17a2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/IERC777Sender.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (interfaces/IERC777Sender.sol) + +pragma solidity ^0.8.0; + +import "../token/ERC777/IERC777Sender.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/README.adoc new file mode 100644 index 0000000..4525bc9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/README.adoc @@ -0,0 +1,73 @@ += Interfaces + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/interfaces + +== List of standardized interfaces +These interfaces are available as `.sol` files, and also as compiler `.json` ABI files (through the npm package). These +are useful to interact with third party contracts that implement them. + +- {IERC20} +- {IERC20Metadata} +- {IERC165} +- {IERC721} +- {IERC721Receiver} +- {IERC721Enumerable} +- {IERC721Metadata} +- {IERC777} +- {IERC777Recipient} +- {IERC777Sender} +- {IERC1155} +- {IERC1155Receiver} +- {IERC1155MetadataURI} +- {IERC1271} +- {IERC1363} +- {IERC1363Receiver} +- {IERC1363Spender} +- {IERC1820Implementer} +- {IERC1820Registry} +- {IERC1822Proxiable} +- {IERC2612} +- {IERC2981} +- {IERC3156FlashLender} +- {IERC3156FlashBorrower} +- {IERC4626} +- {IERC4906} +- {IERC5267} +- {IERC5313} +- {IERC5805} +- {IERC6372} + +== Detailed ABI + +{{IERC1271}} + +{{IERC1363}} + +{{IERC1363Receiver}} + +{{IERC1363Spender}} + +{{IERC1820Implementer}} + +{{IERC1820Registry}} + +{{IERC1822Proxiable}} + +{{IERC2612}} + +{{IERC2981}} + +{{IERC3156FlashLender}} + +{{IERC3156FlashBorrower}} + +{{IERC4626}} + +{{IERC5313}} + +{{IERC5267}} + +{{IERC5805}} + +{{IERC6372}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/draft-IERC1822.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/draft-IERC1822.sol new file mode 100644 index 0000000..3b73d74 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/draft-IERC1822.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) + +pragma solidity ^0.8.0; + +/** + * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified + * proxy whose upgrades are fully controlled by the current implementation. + */ +interface IERC1822Proxiable { + /** + * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation + * address. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. + */ + function proxiableUUID() external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/draft-IERC2612.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/draft-IERC2612.sol new file mode 100644 index 0000000..024b753 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/interfaces/draft-IERC2612.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/draft-IERC2612.sol) + +pragma solidity ^0.8.0; + +// EIP-2612 is Final as of 2022-11-01. This file is deprecated. + +import "./IERC2612.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/ERC2771Context.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/ERC2771Context.sol new file mode 100644 index 0000000..3835802 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/ERC2771Context.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.3) (metatx/ERC2771Context.sol) + +pragma solidity ^0.8.9; + +import "../utils/Context.sol"; + +/** + * @dev Context variant with ERC2771 support. + */ +abstract contract ERC2771Context is Context { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _trustedForwarder; + + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address trustedForwarder) { + _trustedForwarder = trustedForwarder; + } + + function isTrustedForwarder(address forwarder) public view virtual returns (bool) { + return forwarder == _trustedForwarder; + } + + function _msgSender() internal view virtual override returns (address sender) { + if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { + // The assembly code is more direct than the Solidity version using `abi.decode`. + /// @solidity memory-safe-assembly + assembly { + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + } else { + return super._msgSender(); + } + } + + function _msgData() internal view virtual override returns (bytes calldata) { + if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { + return msg.data[:msg.data.length - 20]; + } else { + return super._msgData(); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/MinimalForwarder.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/MinimalForwarder.sol new file mode 100644 index 0000000..de26462 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/MinimalForwarder.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (metatx/MinimalForwarder.sol) + +pragma solidity ^0.8.0; + +import "../utils/cryptography/ECDSA.sol"; +import "../utils/cryptography/EIP712.sol"; + +/** + * @dev Simple minimal forwarder to be used together with an ERC2771 compatible contract. See {ERC2771Context}. + * + * MinimalForwarder is mainly meant for testing, as it is missing features to be a good production-ready forwarder. This + * contract does not intend to have all the properties that are needed for a sound forwarding system. A fully + * functioning forwarding system with good properties requires more complexity. We suggest you look at other projects + * such as the GSN which do have the goal of building a system like that. + */ +contract MinimalForwarder is EIP712 { + using ECDSA for bytes32; + + struct ForwardRequest { + address from; + address to; + uint256 value; + uint256 gas; + uint256 nonce; + bytes data; + } + + bytes32 private constant _TYPEHASH = + keccak256("ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data)"); + + mapping(address => uint256) private _nonces; + + constructor() EIP712("MinimalForwarder", "0.0.1") {} + + function getNonce(address from) public view returns (uint256) { + return _nonces[from]; + } + + function verify(ForwardRequest calldata req, bytes calldata signature) public view returns (bool) { + address signer = _hashTypedDataV4( + keccak256(abi.encode(_TYPEHASH, req.from, req.to, req.value, req.gas, req.nonce, keccak256(req.data))) + ).recover(signature); + return _nonces[req.from] == req.nonce && signer == req.from; + } + + function execute( + ForwardRequest calldata req, + bytes calldata signature + ) public payable returns (bool, bytes memory) { + require(verify(req, signature), "MinimalForwarder: signature does not match request"); + _nonces[req.from] = req.nonce + 1; + + (bool success, bytes memory returndata) = req.to.call{gas: req.gas, value: req.value}( + abi.encodePacked(req.data, req.from) + ); + + // Validate that the relayer has sent enough gas for the call. + // See https://ronan.eth.limo/blog/ethereum-gas-dangers/ + if (gasleft() <= req.gas / 63) { + // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since + // neither revert or assert consume all gas since Solidity 0.8.0 + // https://docs.soliditylang.org/en/v0.8.0/control-structures.html#panic-via-assert-and-error-via-require + /// @solidity memory-safe-assembly + assembly { + invalid() + } + } + + return (success, returndata); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/README.adoc new file mode 100644 index 0000000..eccdeaf --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/metatx/README.adoc @@ -0,0 +1,12 @@ += Meta Transactions + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx + +== Core + +{{ERC2771Context}} + +== Utils + +{{MinimalForwarder}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/AccessControlCrossChainMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/AccessControlCrossChainMock.sol new file mode 100644 index 0000000..cd4c3a5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/AccessControlCrossChainMock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +import "../access/AccessControlCrossChain.sol"; +import "../crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol"; + +contract AccessControlCrossChainMock is AccessControlCrossChain, CrossChainEnabledArbitrumL2 {} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ArraysMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ArraysMock.sol new file mode 100644 index 0000000..2ea17a0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ArraysMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Arrays.sol"; + +contract Uint256ArraysMock { + using Arrays for uint256[]; + + uint256[] private _array; + + constructor(uint256[] memory array) { + _array = array; + } + + function findUpperBound(uint256 element) external view returns (uint256) { + return _array.findUpperBound(element); + } + + function unsafeAccess(uint256 pos) external view returns (uint256) { + return _array.unsafeAccess(pos).value; + } +} + +contract AddressArraysMock { + using Arrays for address[]; + + address[] private _array; + + constructor(address[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (address) { + return _array.unsafeAccess(pos).value; + } +} + +contract Bytes32ArraysMock { + using Arrays for bytes32[]; + + bytes32[] private _array; + + constructor(bytes32[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (bytes32) { + return _array.unsafeAccess(pos).value; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/CallReceiverMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/CallReceiverMock.sol new file mode 100644 index 0000000..492adbe --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/CallReceiverMock.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract CallReceiverMock { + event MockFunctionCalled(); + event MockFunctionCalledWithArgs(uint256 a, uint256 b); + + uint256[] private _array; + + function mockFunction() public payable returns (string memory) { + emit MockFunctionCalled(); + + return "0x1234"; + } + + function mockFunctionEmptyReturn() public payable { + emit MockFunctionCalled(); + } + + function mockFunctionWithArgs(uint256 a, uint256 b) public payable returns (string memory) { + emit MockFunctionCalledWithArgs(a, b); + + return "0x1234"; + } + + function mockFunctionNonPayable() public returns (string memory) { + emit MockFunctionCalled(); + + return "0x1234"; + } + + function mockStaticFunction() public pure returns (string memory) { + return "0x1234"; + } + + function mockFunctionRevertsNoReason() public payable { + revert(); + } + + function mockFunctionRevertsReason() public payable { + revert("CallReceiverMock: reverting"); + } + + function mockFunctionThrows() public payable { + assert(false); + } + + function mockFunctionOutOfGas() public payable { + for (uint256 i = 0; ; ++i) { + _array.push(i); + } + } + + function mockFunctionWritesStorage(bytes32 slot, bytes32 value) public returns (string memory) { + assembly { + sstore(slot, value) + } + return "0x1234"; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ConditionalEscrowMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ConditionalEscrowMock.sol new file mode 100644 index 0000000..ececf05 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ConditionalEscrowMock.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/escrow/ConditionalEscrow.sol"; + +// mock class using ConditionalEscrow +contract ConditionalEscrowMock is ConditionalEscrow { + mapping(address => bool) private _allowed; + + function setAllowed(address payee, bool allowed) public { + _allowed[payee] = allowed; + } + + function withdrawalAllowed(address payee) public view override returns (bool) { + return _allowed[payee]; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ContextMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ContextMock.sol new file mode 100644 index 0000000..6cc0abc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ContextMock.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +contract ContextMock is Context { + event Sender(address sender); + + function msgSender() public { + emit Sender(_msgSender()); + } + + event Data(bytes data, uint256 integerValue, string stringValue); + + function msgData(uint256 integerValue, string memory stringValue) public { + emit Data(_msgData(), integerValue, stringValue); + } + + event DataShort(bytes data); + + function msgDataShort() public { + emit DataShort(_msgData()); + } +} + +contract ContextMockCaller { + function callSender(ContextMock context) public { + context.msgSender(); + } + + function callData(ContextMock context, uint256 integerValue, string memory stringValue) public { + context.msgData(integerValue, stringValue); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/DummyImplementation.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/DummyImplementation.sol new file mode 100644 index 0000000..ddcca66 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/DummyImplementation.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +abstract contract Impl { + function version() public pure virtual returns (string memory); +} + +contract DummyImplementation { + uint256 public value; + string public text; + uint256[] public values; + + function initializeNonPayable() public { + value = 10; + } + + function initializePayable() public payable { + value = 100; + } + + function initializeNonPayableWithValue(uint256 _value) public { + value = _value; + } + + function initializePayableWithValue(uint256 _value) public payable { + value = _value; + } + + function initialize(uint256 _value, string memory _text, uint256[] memory _values) public { + value = _value; + text = _text; + values = _values; + } + + function get() public pure returns (bool) { + return true; + } + + function version() public pure virtual returns (string memory) { + return "V1"; + } + + function reverts() public pure { + require(false, "DummyImplementation reverted"); + } +} + +contract DummyImplementationV2 is DummyImplementation { + function migrate(uint256 newVal) public payable { + value = newVal; + } + + function version() public pure override returns (string memory) { + return "V2"; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/EIP712Verifier.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/EIP712Verifier.sol new file mode 100644 index 0000000..dcef9ef --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/EIP712Verifier.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/cryptography/ECDSA.sol"; +import "../utils/cryptography/EIP712.sol"; + +abstract contract EIP712Verifier is EIP712 { + function verify(bytes memory signature, address signer, address mailTo, string memory mailContents) external view { + bytes32 digest = _hashTypedDataV4( + keccak256(abi.encode(keccak256("Mail(address to,string contents)"), mailTo, keccak256(bytes(mailContents)))) + ); + address recoveredSigner = ECDSA.recover(digest, signature); + require(recoveredSigner == signer); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC1271WalletMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC1271WalletMock.sol new file mode 100644 index 0000000..0152889 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC1271WalletMock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../access/Ownable.sol"; +import "../interfaces/IERC1271.sol"; +import "../utils/cryptography/ECDSA.sol"; + +contract ERC1271WalletMock is Ownable, IERC1271 { + constructor(address originalOwner) { + transferOwnership(originalOwner); + } + + function isValidSignature(bytes32 hash, bytes memory signature) public view override returns (bytes4 magicValue) { + return ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0); + } +} + +contract ERC1271MaliciousMock is IERC1271 { + function isValidSignature(bytes32, bytes memory) public pure override returns (bytes4) { + assembly { + mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0, 32) + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165MaliciousData.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165MaliciousData.sol new file mode 100644 index 0000000..2446f3d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165MaliciousData.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC165MaliciousData { + function supportsInterface(bytes4) public pure returns (bool) { + assembly { + mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0, 32) + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165MissingData.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165MissingData.sol new file mode 100644 index 0000000..59cd51a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165MissingData.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC165MissingData { + function supportsInterface(bytes4 interfaceId) public view {} // missing return +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165NotSupported.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165NotSupported.sol new file mode 100644 index 0000000..486c7f0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165NotSupported.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract ERC165NotSupported {} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165ReturnBomb.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165ReturnBomb.sol new file mode 100644 index 0000000..e53235d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC165/ERC165ReturnBomb.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +contract ERC165ReturnBombMock is IERC165 { + function supportsInterface(bytes4 interfaceId) public pure override returns (bool) { + if (interfaceId == type(IERC165).interfaceId) { + assembly { + mstore(0, 1) + } + } + assembly { + return(0, 101500) + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC20Mock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC20Mock.sol new file mode 100644 index 0000000..cc75923 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC20Mock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ERC20} from "../token/ERC20/ERC20.sol"; + +contract ERC20Mock is ERC20 { + constructor() ERC20("ERC20Mock", "E20M") {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC20Reentrant.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC20Reentrant.sol new file mode 100644 index 0000000..c0184b7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC2771ContextMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC2771ContextMock.sol new file mode 100644 index 0000000..387df78 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC2771ContextMock.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.9; + +import "./ContextMock.sol"; +import "../metatx/ERC2771Context.sol"; + +// By inheriting from ERC2771Context, Context's internal functions are overridden automatically +contract ERC2771ContextMock is ContextMock, ERC2771Context { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address trustedForwarder) ERC2771Context(trustedForwarder) { + emit Sender(_msgSender()); // _msgSender() should be accessible during construction + } + + function _msgSender() internal view override(Context, ERC2771Context) returns (address) { + return ERC2771Context._msgSender(); + } + + function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) { + return ERC2771Context._msgData(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC3156FlashBorrowerMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC3156FlashBorrowerMock.sol new file mode 100644 index 0000000..6a4410f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC3156FlashBorrowerMock.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../token/ERC20/IERC20.sol"; +import "../interfaces/IERC3156.sol"; +import "../utils/Address.sol"; + +/** + * @dev WARNING: this IERC3156FlashBorrower mock implementation is for testing purposes ONLY. + * Writing a secure flash lock borrower is not an easy task, and should be done with the utmost care. + * This is not an example of how it should be done, and no pattern present in this mock should be considered secure. + * Following best practices, always have your contract properly audited before using them to manipulate important funds on + * live networks. + */ +contract ERC3156FlashBorrowerMock is IERC3156FlashBorrower { + bytes32 internal constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + bool immutable _enableApprove; + bool immutable _enableReturn; + + event BalanceOf(address token, address account, uint256 value); + event TotalSupply(address token, uint256 value); + + constructor(bool enableReturn, bool enableApprove) { + _enableApprove = enableApprove; + _enableReturn = enableReturn; + } + + function onFlashLoan( + address /*initiator*/, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) public override returns (bytes32) { + require(msg.sender == token); + + emit BalanceOf(token, address(this), IERC20(token).balanceOf(address(this))); + emit TotalSupply(token, IERC20(token).totalSupply()); + + if (data.length > 0) { + // WARNING: This code is for testing purposes only! Do not use. + Address.functionCall(token, data); + } + + if (_enableApprove) { + IERC20(token).approve(token, amount + fee); + } + + return _enableReturn ? _RETURN_VALUE : bytes32(0); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC4626Mock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC4626Mock.sol new file mode 100644 index 0000000..ef2d1a4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ERC4626Mock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../token/ERC20/extensions/ERC4626.sol"; + +contract ERC4626Mock is ERC4626 { + constructor(address underlying) ERC20("ERC4626Mock", "E4626M") ERC4626(IERC20(underlying)) {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/EtherReceiverMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/EtherReceiverMock.sol new file mode 100644 index 0000000..a11e646 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/EtherReceiverMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract EtherReceiverMock { + bool private _acceptEther; + + function setAcceptEther(bool acceptEther) public { + _acceptEther = acceptEther; + } + + receive() external payable { + if (!_acceptEther) { + revert(); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/InitializableMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/InitializableMock.sol new file mode 100644 index 0000000..34040b6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/InitializableMock.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../proxy/utils/Initializable.sol"; + +/** + * @title InitializableMock + * @dev This contract is a mock to test initializable functionality + */ +contract InitializableMock is Initializable { + bool public initializerRan; + bool public onlyInitializingRan; + uint256 public x; + + function isInitializing() public view returns (bool) { + return _isInitializing(); + } + + function initialize() public initializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyInitializing { + onlyInitializingRan = true; + } + + function initializerNested() public initializer { + initialize(); + } + + function onlyInitializingNested() public initializer { + initializeOnlyInitializing(); + } + + function initializeWithX(uint256 _x) public payable initializer { + x = _x; + } + + function nonInitializable(uint256 _x) public payable { + x = _x; + } + + function fail() public pure { + require(false, "InitializableMock forced failure"); + } +} + +contract ConstructorInitializableMock is Initializable { + bool public initializerRan; + bool public onlyInitializingRan; + + constructor() initializer { + initialize(); + initializeOnlyInitializing(); + } + + function initialize() public initializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyInitializing { + onlyInitializingRan = true; + } +} + +contract ChildConstructorInitializableMock is ConstructorInitializableMock { + bool public childInitializerRan; + + constructor() initializer { + childInitialize(); + } + + function childInitialize() public initializer { + childInitializerRan = true; + } +} + +contract ReinitializerMock is Initializable { + uint256 public counter; + + function getInitializedVersion() public view returns (uint8) { + return _getInitializedVersion(); + } + + function initialize() public initializer { + doStuff(); + } + + function reinitialize(uint8 i) public reinitializer(i) { + doStuff(); + } + + function nestedReinitialize(uint8 i, uint8 j) public reinitializer(i) { + reinitialize(j); + } + + function chainReinitialize(uint8 i, uint8 j) public { + reinitialize(i); + reinitialize(j); + } + + function disableInitializers() public { + _disableInitializers(); + } + + function doStuff() public onlyInitializing { + counter++; + } +} + +contract DisableNew is Initializable { + constructor() { + _disableInitializers(); + } +} + +contract DisableOld is Initializable { + constructor() initializer {} +} + +contract DisableBad1 is DisableNew, DisableOld {} + +contract DisableBad2 is Initializable { + constructor() initializer { + _disableInitializers(); + } +} + +contract DisableOk is DisableOld, DisableNew {} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/MulticallTest.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/MulticallTest.sol new file mode 100644 index 0000000..fcbec6a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/MulticallTest.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./token/ERC20MulticallMock.sol"; + +contract MulticallTest { + function checkReturnValues( + ERC20MulticallMock multicallToken, + address[] calldata recipients, + uint256[] calldata amounts + ) external { + bytes[] memory calls = new bytes[](recipients.length); + for (uint256 i = 0; i < recipients.length; i++) { + calls[i] = abi.encodeWithSignature("transfer(address,uint256)", recipients[i], amounts[i]); + } + + bytes[] memory results = multicallToken.multicall(calls); + for (uint256 i = 0; i < results.length; i++) { + require(abi.decode(results[i], (bool))); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/MultipleInheritanceInitializableMocks.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/MultipleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..e79cd92 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/MultipleInheritanceInitializableMocks.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../proxy/utils/Initializable.sol"; + +// Sample contracts showing upgradeability with multiple inheritance. +// Child contract inherits from Father and Mother contracts, and Father extends from Gramps. +// +// Human +// / \ +// | Gramps +// | | +// Mother Father +// | | +// -- Child -- + +/** + * Sample base initializable contract that is a human + */ +contract SampleHuman is Initializable { + bool public isHuman; + + function initialize() public initializer { + __SampleHuman_init(); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleHuman_init() internal onlyInitializing { + __SampleHuman_init_unchained(); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleHuman_init_unchained() internal onlyInitializing { + isHuman = true; + } +} + +/** + * Sample base initializable contract that defines a field mother + */ +contract SampleMother is Initializable, SampleHuman { + uint256 public mother; + + function initialize(uint256 value) public initializer { + __SampleMother_init(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleMother_init(uint256 value) internal onlyInitializing { + __SampleHuman_init(); + __SampleMother_init_unchained(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleMother_init_unchained(uint256 value) internal onlyInitializing { + mother = value; + } +} + +/** + * Sample base initializable contract that defines a field gramps + */ +contract SampleGramps is Initializable, SampleHuman { + string public gramps; + + function initialize(string memory value) public initializer { + __SampleGramps_init(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleGramps_init(string memory value) internal onlyInitializing { + __SampleHuman_init(); + __SampleGramps_init_unchained(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleGramps_init_unchained(string memory value) internal onlyInitializing { + gramps = value; + } +} + +/** + * Sample base initializable contract that defines a field father and extends from gramps + */ +contract SampleFather is Initializable, SampleGramps { + uint256 public father; + + function initialize(string memory _gramps, uint256 _father) public initializer { + __SampleFather_init(_gramps, _father); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleFather_init(string memory _gramps, uint256 _father) internal onlyInitializing { + __SampleGramps_init(_gramps); + __SampleFather_init_unchained(_father); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleFather_init_unchained(uint256 _father) internal onlyInitializing { + father = _father; + } +} + +/** + * Child extends from mother, father (gramps) + */ +contract SampleChild is Initializable, SampleMother, SampleFather { + uint256 public child; + + function initialize(uint256 _mother, string memory _gramps, uint256 _father, uint256 _child) public initializer { + __SampleChild_init(_mother, _gramps, _father, _child); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleChild_init( + uint256 _mother, + string memory _gramps, + uint256 _father, + uint256 _child + ) internal onlyInitializing { + __SampleMother_init(_mother); + __SampleFather_init(_gramps, _father); + __SampleChild_init_unchained(_child); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleChild_init_unchained(uint256 _child) internal onlyInitializing { + child = _child; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/PausableMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/PausableMock.sol new file mode 100644 index 0000000..98bcfd5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/PausableMock.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../security/Pausable.sol"; + +contract PausableMock is Pausable { + bool public drasticMeasureTaken; + uint256 public count; + + constructor() { + drasticMeasureTaken = false; + count = 0; + } + + function normalProcess() external whenNotPaused { + count++; + } + + function drasticMeasure() external whenPaused { + drasticMeasureTaken = true; + } + + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/PullPaymentMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/PullPaymentMock.sol new file mode 100644 index 0000000..8a708e3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/PullPaymentMock.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../security/PullPayment.sol"; + +// mock class using PullPayment +contract PullPaymentMock is PullPayment { + constructor() payable {} + + // test helper function to call asyncTransfer + function callTransfer(address dest, uint256 amount) public { + _asyncTransfer(dest, amount); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ReentrancyAttack.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ReentrancyAttack.sol new file mode 100644 index 0000000..4de1812 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ReentrancyAttack.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +contract ReentrancyAttack is Context { + function callSender(bytes4 data) public { + (bool success, ) = _msgSender().call(abi.encodeWithSelector(data)); + require(success, "ReentrancyAttack: failed call"); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ReentrancyMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ReentrancyMock.sol new file mode 100644 index 0000000..161e1d3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/ReentrancyMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../security/ReentrancyGuard.sol"; +import "./ReentrancyAttack.sol"; + +contract ReentrancyMock is ReentrancyGuard { + uint256 public counter; + + constructor() { + counter = 0; + } + + function callback() external nonReentrant { + _count(); + } + + function countLocalRecursive(uint256 n) public nonReentrant { + if (n > 0) { + _count(); + countLocalRecursive(n - 1); + } + } + + function countThisRecursive(uint256 n) public nonReentrant { + if (n > 0) { + _count(); + (bool success, ) = address(this).call(abi.encodeWithSignature("countThisRecursive(uint256)", n - 1)); + require(success, "ReentrancyMock: failed call"); + } + } + + function countAndCall(ReentrancyAttack attacker) public nonReentrant { + _count(); + bytes4 func = bytes4(keccak256("callback()")); + attacker.callSender(func); + } + + function _count() private { + counter += 1; + } + + function guardedCheckEntered() public nonReentrant { + require(_reentrancyGuardEntered()); + } + + function unguardedCheckNotEntered() public view { + require(!_reentrancyGuardEntered()); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/RegressionImplementation.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/RegressionImplementation.sol new file mode 100644 index 0000000..be6b501 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/RegressionImplementation.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../proxy/utils/Initializable.sol"; + +contract Implementation1 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } +} + +contract Implementation2 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } +} + +contract Implementation3 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue(uint256 _number) public view returns (uint256) { + return _value + _number; + } +} + +contract Implementation4 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } + + fallback() external { + _value = 1; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/SafeMathMemoryCheck.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/SafeMathMemoryCheck.sol new file mode 100644 index 0000000..9694688 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/SafeMathMemoryCheck.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/math/SafeMath.sol"; + +library SafeMathMemoryCheck { + function addMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.add(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } + + function subMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.sub(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } + + function mulMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.mul(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } + + function divMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.div(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } + + function modMemoryCheck() internal pure returns (uint256 mem) { + uint256 length = 32; + assembly { + mem := mload(0x40) + } + for (uint256 i = 0; i < length; ++i) { + SafeMath.mod(1, 1); + } + assembly { + mem := sub(mload(0x40), mem) + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/SingleInheritanceInitializableMocks.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/SingleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..6c82dd2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/SingleInheritanceInitializableMocks.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../proxy/utils/Initializable.sol"; + +/** + * @title MigratableMockV1 + * @dev This contract is a mock to test initializable functionality through migrations + */ +contract MigratableMockV1 is Initializable { + uint256 public x; + + function initialize(uint256 value) public payable initializer { + x = value; + } +} + +/** + * @title MigratableMockV2 + * @dev This contract is a mock to test migratable functionality with params + */ +contract MigratableMockV2 is MigratableMockV1 { + bool internal _migratedV2; + uint256 public y; + + function migrate(uint256 value, uint256 anotherValue) public payable { + require(!_migratedV2); + x = value; + y = anotherValue; + _migratedV2 = true; + } +} + +/** + * @title MigratableMockV3 + * @dev This contract is a mock to test migratable functionality without params + */ +contract MigratableMockV3 is MigratableMockV2 { + bool internal _migratedV3; + + function migrate() public payable { + require(!_migratedV3); + uint256 oldX = x; + x = y; + y = oldX; + _migratedV3 = true; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/StorageSlotMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/StorageSlotMock.sol new file mode 100644 index 0000000..1da577c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/StorageSlotMock.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/StorageSlot.sol"; + +contract StorageSlotMock { + using StorageSlot for *; + + function setBoolean(bytes32 slot, bool value) public { + slot.getBooleanSlot().value = value; + } + + function setAddress(bytes32 slot, address value) public { + slot.getAddressSlot().value = value; + } + + function setBytes32(bytes32 slot, bytes32 value) public { + slot.getBytes32Slot().value = value; + } + + function setUint256(bytes32 slot, uint256 value) public { + slot.getUint256Slot().value = value; + } + + function getBoolean(bytes32 slot) public view returns (bool) { + return slot.getBooleanSlot().value; + } + + function getAddress(bytes32 slot) public view returns (address) { + return slot.getAddressSlot().value; + } + + function getBytes32(bytes32 slot) public view returns (bytes32) { + return slot.getBytes32Slot().value; + } + + 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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimelockReentrant.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimelockReentrant.sol new file mode 100644 index 0000000..a9344f5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimersBlockNumberImpl.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimersBlockNumberImpl.sol new file mode 100644 index 0000000..84633e6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimersBlockNumberImpl.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Timers.sol"; + +contract TimersBlockNumberImpl { + using Timers for Timers.BlockNumber; + + Timers.BlockNumber private _timer; + + function getDeadline() public view returns (uint64) { + return _timer.getDeadline(); + } + + function setDeadline(uint64 timestamp) public { + _timer.setDeadline(timestamp); + } + + function reset() public { + _timer.reset(); + } + + function isUnset() public view returns (bool) { + return _timer.isUnset(); + } + + function isStarted() public view returns (bool) { + return _timer.isStarted(); + } + + function isPending() public view returns (bool) { + return _timer.isPending(); + } + + function isExpired() public view returns (bool) { + return _timer.isExpired(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimersTimestampImpl.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimersTimestampImpl.sol new file mode 100644 index 0000000..07f9a1b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/TimersTimestampImpl.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../utils/Timers.sol"; + +contract TimersTimestampImpl { + using Timers for Timers.Timestamp; + + Timers.Timestamp private _timer; + + function getDeadline() public view returns (uint64) { + return _timer.getDeadline(); + } + + function setDeadline(uint64 timestamp) public { + _timer.setDeadline(timestamp); + } + + function reset() public { + _timer.reset(); + } + + function isUnset() public view returns (bool) { + return _timer.isUnset(); + } + + function isStarted() public view returns (bool) { + return _timer.isStarted(); + } + + function isPending() public view returns (bool) { + return _timer.isPending(); + } + + function isExpired() public view returns (bool) { + return _timer.isExpired(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/VotesMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/VotesMock.sol new file mode 100644 index 0000000..829504e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/VotesMock.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../governance/utils/Votes.sol"; + +abstract contract VotesMock is Votes { + mapping(address => uint256) private _balances; + mapping(uint256 => address) private _owners; + + function getTotalSupply() public view returns (uint256) { + return _getTotalSupply(); + } + + function delegate(address account, address newDelegation) public { + return _delegate(account, newDelegation); + } + + function _getVotingUnits(address account) internal view override returns (uint256) { + return _balances[account]; + } + + function _mint(address account, uint256 voteId) internal { + _balances[account] += 1; + _owners[voteId] = account; + _transferVotingUnits(address(0), account, 1); + } + + function _burn(uint256 voteId) internal { + address owner = _owners[voteId]; + _balances[owner] -= 1; + _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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/compound/CompTimelock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/compound/CompTimelock.sol new file mode 100644 index 0000000..49ffa4b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/compound/CompTimelock.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: BSD-3-Clause +// solhint-disable private-vars-leading-underscore +/** + * Copyright 2020 Compound Labs, Inc. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +pragma solidity ^0.8.0; + +contract CompTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + + uint256 public constant GRACE_PERIOD = 14 days; + uint256 public constant MINIMUM_DELAY = 2 days; + uint256 public constant MAXIMUM_DELAY = 30 days; + + address public admin; + address public pendingAdmin; + uint256 public delay; + + mapping(bytes32 => bool) public queuedTransactions; + + constructor(address admin_, uint256 delay_) { + require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay."); + require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); + + admin = admin_; + delay = delay_; + } + + receive() external payable {} + + function setDelay(uint256 delay_) public { + require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock."); + require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay."); + require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); + delay = delay_; + + emit NewDelay(delay); + } + + function acceptAdmin() public { + require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin."); + admin = msg.sender; + pendingAdmin = address(0); + + emit NewAdmin(admin); + } + + function setPendingAdmin(address pendingAdmin_) public { + require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock."); + pendingAdmin = pendingAdmin_; + + emit NewPendingAdmin(pendingAdmin); + } + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public returns (bytes32) { + require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin."); + require( + eta >= getBlockTimestamp() + delay, + "Timelock::queueTransaction: Estimated execution block must satisfy delay." + ); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + queuedTransactions[txHash] = true; + + emit QueueTransaction(txHash, target, value, signature, data, eta); + return txHash; + } + + function cancelTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public { + require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin."); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + queuedTransactions[txHash] = false; + + emit CancelTransaction(txHash, target, value, signature, data, eta); + } + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public payable returns (bytes memory) { + require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin."); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued."); + require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock."); + require(getBlockTimestamp() <= eta + GRACE_PERIOD, "Timelock::executeTransaction: Transaction is stale."); + + queuedTransactions[txHash] = false; + + bytes memory callData; + + if (bytes(signature).length == 0) { + callData = data; + } else { + callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data); + } + + // solium-disable-next-line security/no-call-value + (bool success, bytes memory returnData) = target.call{value: value}(callData); + require(success, "Timelock::executeTransaction: Transaction execution reverted."); + + emit ExecuteTransaction(txHash, target, value, signature, data, eta); + + return returnData; + } + + function getBlockTimestamp() internal view returns (uint256) { + // solium-disable-next-line security/no-block-members + return block.timestamp; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/crosschain/bridges.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/crosschain/bridges.sol new file mode 100644 index 0000000..41baffe --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/crosschain/bridges.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/Address.sol"; +import "../../vendor/polygon/IFxMessageProcessor.sol"; + +abstract contract BaseRelayMock { + // needed to parse custom errors + error NotCrossChainCall(); + error InvalidCrossChainSender(address sender, address expected); + + address internal _currentSender; + + function relayAs(address target, bytes calldata data, address sender) external virtual { + address previousSender = _currentSender; + + _currentSender = sender; + + (bool success, bytes memory returndata) = target.call(data); + Address.verifyCallResultFromTarget(target, success, returndata, "low-level call reverted"); + + _currentSender = previousSender; + } +} + +/** + * AMB + */ +contract BridgeAMBMock is BaseRelayMock { + function messageSender() public view returns (address) { + return _currentSender; + } +} + +/** + * Arbitrum + */ +contract BridgeArbitrumL1Mock is BaseRelayMock { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable inbox = address(new BridgeArbitrumL1Inbox()); + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable outbox = address(new BridgeArbitrumL1Outbox()); + + function activeOutbox() public view returns (address) { + return outbox; + } + + function currentSender() public view returns (address) { + return _currentSender; + } +} + +contract BridgeArbitrumL1Inbox { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable bridge = msg.sender; +} + +contract BridgeArbitrumL1Outbox { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable bridge = msg.sender; + + function l2ToL1Sender() public view returns (address) { + return BridgeArbitrumL1Mock(bridge).currentSender(); + } +} + +contract BridgeArbitrumL2Mock is BaseRelayMock { + function wasMyCallersAddressAliased() public view returns (bool) { + return _currentSender != address(0); + } + + function myCallersAddressWithoutAliasing() public view returns (address) { + return _currentSender; + } +} + +/** + * Optimism + */ +contract BridgeOptimismMock is BaseRelayMock { + function xDomainMessageSender() public view returns (address) { + return _currentSender; + } +} + +/** + * Polygon + */ +contract BridgePolygonChildMock is BaseRelayMock { + function relayAs(address target, bytes calldata data, address sender) external override { + IFxMessageProcessor(target).processMessageFromRoot(0, sender, data); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/crosschain/receivers.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/crosschain/receivers.sol new file mode 100644 index 0000000..601a2ac --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/crosschain/receivers.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.4; + +import "../../access/Ownable.sol"; +import "../../crosschain/amb/CrossChainEnabledAMB.sol"; +import "../../crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol"; +import "../../crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol"; +import "../../crosschain/optimism/CrossChainEnabledOptimism.sol"; +import "../../crosschain/polygon/CrossChainEnabledPolygonChild.sol"; + +abstract contract Receiver is CrossChainEnabled { + // we don't use Ownable because it messes up testing for the upgradeable contracts + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address public immutable owner = msg.sender; + + function crossChainRestricted() external onlyCrossChain {} + + function crossChainOwnerRestricted() external onlyCrossChainSender(owner) {} +} + +/** + * AMB + */ +contract CrossChainEnabledAMBMock is Receiver, CrossChainEnabledAMB { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) CrossChainEnabledAMB(bridge) {} +} + +/** + * Arbitrum + */ +contract CrossChainEnabledArbitrumL1Mock is Receiver, CrossChainEnabledArbitrumL1 { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) CrossChainEnabledArbitrumL1(bridge) {} +} + +contract CrossChainEnabledArbitrumL2Mock is Receiver, CrossChainEnabledArbitrumL2 {} + +/** + * Optimism + */ +contract CrossChainEnabledOptimismMock is Receiver, CrossChainEnabledOptimism { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) CrossChainEnabledOptimism(bridge) {} +} + +/** + * Polygon + */ +contract CrossChainEnabledPolygonChildMock is Receiver, CrossChainEnabledPolygonChild { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address bridge) CrossChainEnabledPolygonChild(bridge) {} +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorCompMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorCompMock.sol new file mode 100644 index 0000000..cc368c4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorCompMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotesComp.sol"; + +abstract contract GovernorCompMock is GovernorVotesComp, GovernorCountingSimple { + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol new file mode 100644 index 0000000..1b87d14 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorCompatibilityBravoMock.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/compatibility/GovernorCompatibilityBravo.sol"; +import "../../governance/extensions/GovernorTimelockCompound.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorVotesComp.sol"; + +abstract contract GovernorCompatibilityBravoMock is + GovernorCompatibilityBravo, + GovernorSettings, + GovernorTimelockCompound, + GovernorVotesComp +{ + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function supportsInterface( + bytes4 interfaceId + ) public view override(IERC165, Governor, GovernorTimelockCompound) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function state( + uint256 proposalId + ) public view override(IGovernor, Governor, GovernorTimelockCompound) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalEta( + uint256 proposalId + ) public view override(IGovernorTimelock, GovernorTimelockCompound) returns (uint256) { + return super.proposalEta(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public override(IGovernor, Governor, GovernorCompatibilityBravo) returns (uint256) { + return super.propose(targets, values, calldatas, description); + } + + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 salt + ) public override(IGovernorTimelock, GovernorTimelockCompound) returns (uint256) { + return super.queue(targets, values, calldatas, salt); + } + + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 salt + ) public payable override(IGovernor, Governor) returns (uint256) { + return super.execute(targets, values, calldatas, salt); + } + + 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( + 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 salt + ) internal override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) { + return super._cancel(targets, values, calldatas, salt); + } + + function _executor() internal view override(Governor, GovernorTimelockCompound) returns (address) { + return super._executor(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorMock.sol new file mode 100644 index 0000000..8a1db47 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorMock.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorProposalThreshold.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorMock is + GovernorProposalThreshold, + GovernorSettings, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public override(Governor, GovernorProposalThreshold) returns (uint256) { + return super.propose(targets, values, calldatas, description); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol new file mode 100644 index 0000000..79d8948 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorPreventLateQuorum.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorPreventLateQuorumMock is + GovernorSettings, + GovernorVotes, + GovernorCountingSimple, + GovernorPreventLateQuorum +{ + uint256 private _quorum; + + constructor(uint256 quorum_) { + _quorum = quorum_; + } + + function quorum(uint256) public view override returns (uint256) { + return _quorum; + } + + function proposalDeadline( + uint256 proposalId + ) public view override(Governor, GovernorPreventLateQuorum) returns (uint256) { + return super.proposalDeadline(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal override(Governor, GovernorPreventLateQuorum) returns (uint256) { + return super._castVote(proposalId, account, support, reason, params); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorTimelockCompoundMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorTimelockCompoundMock.sol new file mode 100644 index 0000000..b374628 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorTimelockCompoundMock.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorTimelockCompound.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockCompoundMock is + GovernorSettings, + GovernorTimelockCompound, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function supportsInterface( + bytes4 interfaceId + ) public view override(Governor, GovernorTimelockCompound) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state( + uint256 proposalId + ) public view override(Governor, GovernorTimelockCompound) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + 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 salt + ) internal override(Governor, GovernorTimelockCompound) returns (uint256 proposalId) { + return super._cancel(targets, values, calldatas, salt); + } + + function _executor() internal view override(Governor, GovernorTimelockCompound) returns (address) { + return super._executor(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorTimelockControlMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorTimelockControlMock.sol new file mode 100644 index 0000000..0630914 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorTimelockControlMock.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorTimelockControl.sol"; +import "../../governance/extensions/GovernorSettings.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockControlMock is + GovernorSettings, + GovernorTimelockControl, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function supportsInterface( + bytes4 interfaceId + ) public view override(Governor, GovernorTimelockControl) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + 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 proposalId) { + return super._cancel(targets, values, calldatas, descriptionHash); + } + + function _executor() internal view override(Governor, GovernorTimelockControl) returns (address) { + return super._executor(); + } + + function nonGovernanceFunction() external {} +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorVoteMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorVoteMock.sol new file mode 100644 index 0000000..9b533bd --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorVoteMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorVoteMocks is GovernorVotes, GovernorCountingSimple { + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorWithParamsMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorWithParamsMock.sol new file mode 100644 index 0000000..361c287 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/governance/GovernorWithParamsMock.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorWithParamsMock is GovernorVotes, GovernorCountingSimple { + event CountParams(uint256 uintParam, string strParam); + + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } + + function _getVotes( + address account, + uint256 blockNumber, + bytes memory params + ) internal view override(Governor, GovernorVotes) returns (uint256) { + uint256 reduction = 0; + // If the user provides parameters, we reduce the voting weight by the amount of the integer param + if (params.length > 0) { + (reduction, ) = abi.decode(params, (uint256, string)); + } + // reverts on overflow + return super._getVotes(account, blockNumber, params) - reduction; + } + + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal override(Governor, GovernorCountingSimple) { + if (params.length > 0) { + (uint256 _uintParam, string memory _strParam) = abi.decode(params, (uint256, string)); + emit CountParams(_uintParam, _strParam); + } + return super._countVote(proposalId, account, support, weight, params); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/BadBeacon.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/BadBeacon.sol new file mode 100644 index 0000000..bedcfed --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/BadBeacon.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract BadBeaconNoImpl {} + +contract BadBeaconNotContract { + function implementation() external pure returns (address) { + return address(0x1); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/ClashingImplementation.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/ClashingImplementation.sol new file mode 100644 index 0000000..5c272a8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/ClashingImplementation.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +/** + * @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 payable returns (address) { + return 0x0000000000000000000000000000000011111142; + } + + function delegatedFunction() external pure returns (bool) { + return true; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/UUPSLegacy.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/UUPSLegacy.sol new file mode 100644 index 0000000..6956f56 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/UUPSLegacy.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./UUPSUpgradeableMock.sol"; + +// This contract implements the pre-4.5 UUPS upgrade function with a rollback test. +// It's used to test that newer UUPS contracts are considered valid upgrades by older UUPS contracts. +contract UUPSUpgradeableLegacyMock is UUPSUpgradeableMock { + // Inlined from ERC1967Upgrade + bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; + + // ERC1967Upgrade._setImplementation is private so we reproduce it here. + // An extra underscore prevents a name clash error. + function __setImplementation(address newImplementation) private { + require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + } + + function _upgradeToAndCallSecureLegacyV1(address newImplementation, bytes memory data, bool forceCall) internal { + address oldImplementation = _getImplementation(); + + // Initial upgrade and setup call + __setImplementation(newImplementation); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(newImplementation, data); + } + + // Perform rollback test if not already in progress + StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT); + if (!rollbackTesting.value) { + // Trigger rollback using upgradeTo from the new implementation + rollbackTesting.value = true; + Address.functionDelegateCall( + newImplementation, + abi.encodeWithSignature("upgradeTo(address)", oldImplementation) + ); + rollbackTesting.value = false; + // Check rollback was effective + require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades"); + // Finally reset to the new implementation and log the upgrade + _upgradeTo(newImplementation); + } + } + + // hooking into the old mechanism + function upgradeTo(address newImplementation) public override { + _upgradeToAndCallSecureLegacyV1(newImplementation, bytes(""), false); + } + + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { + _upgradeToAndCallSecureLegacyV1(newImplementation, data, false); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/UUPSUpgradeableMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/UUPSUpgradeableMock.sol new file mode 100644 index 0000000..f02271c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/proxy/UUPSUpgradeableMock.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../proxy/utils/UUPSUpgradeable.sol"; +import "../../utils/Counters.sol"; + +contract NonUpgradeableMock { + Counters.Counter internal _counter; + + function current() external view returns (uint256) { + return Counters.current(_counter); + } + + function increment() external { + return Counters.increment(_counter); + } +} + +contract UUPSUpgradeableMock is NonUpgradeableMock, UUPSUpgradeable { + // Not having any checks in this function is dangerous! Do not do this outside tests! + function _authorizeUpgrade(address) internal override {} +} + +contract UUPSUpgradeableUnsafeMock is UUPSUpgradeableMock { + function upgradeTo(address newImplementation) public override { + ERC1967Upgrade._upgradeToAndCall(newImplementation, bytes(""), false); + } + + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { + ERC1967Upgrade._upgradeToAndCall(newImplementation, data, false); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC1155ReceiverMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC1155ReceiverMock.sol new file mode 100644 index 0000000..317d724 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC1155ReceiverMock.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC1155/IERC1155Receiver.sol"; +import "../../utils/introspection/ERC165.sol"; + +contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { + bytes4 private _recRetval; + bool private _recReverts; + bytes4 private _batRetval; + bool private _batReverts; + + event Received(address operator, address from, uint256 id, uint256 value, bytes data, uint256 gas); + event BatchReceived(address operator, address from, uint256[] ids, uint256[] values, bytes data, uint256 gas); + + constructor(bytes4 recRetval, bool recReverts, bytes4 batRetval, bool batReverts) { + _recRetval = recRetval; + _recReverts = recReverts; + _batRetval = batRetval; + _batReverts = batReverts; + } + + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external override returns (bytes4) { + require(!_recReverts, "ERC1155ReceiverMock: reverting on receive"); + emit Received(operator, from, id, value, data, gasleft()); + return _recRetval; + } + + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external override returns (bytes4) { + require(!_batReverts, "ERC1155ReceiverMock: reverting on batch receive"); + emit BatchReceived(operator, from, ids, values, data, gasleft()); + return _batRetval; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20DecimalsMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20DecimalsMock.sol new file mode 100644 index 0000000..32f2874 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20DecimalsMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20DecimalsMock is ERC20 { + uint8 private immutable _decimals; + + constructor(uint8 decimals_) { + _decimals = decimals_; + } + + function decimals() public view override returns (uint8) { + return _decimals; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ExcessDecimalsMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ExcessDecimalsMock.sol new file mode 100644 index 0000000..0fb35a6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20FlashMintMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20FlashMintMock.sol new file mode 100644 index 0000000..b4de7b7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20FlashMintMock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/extensions/ERC20FlashMint.sol"; + +abstract contract ERC20FlashMintMock is ERC20FlashMint { + uint256 _flashFeeAmount; + address _flashFeeReceiverAddress; + + function setFlashFee(uint256 amount) public { + _flashFeeAmount = amount; + } + + function _flashFee(address, uint256) internal view override returns (uint256) { + return _flashFeeAmount; + } + + function setFlashFeeReceiver(address receiver) public { + _flashFeeReceiverAddress = receiver; + } + + function _flashFeeReceiver() internal view override returns (address) { + return _flashFeeReceiverAddress; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ForceApproveMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ForceApproveMock.sol new file mode 100644 index 0000000..955224b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20MulticallMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20MulticallMock.sol new file mode 100644 index 0000000..145e97a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20MulticallMock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/ERC20.sol"; +import "../../utils/Multicall.sol"; + +abstract contract ERC20MulticallMock is ERC20, Multicall {} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20NoReturnMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20NoReturnMock.sol new file mode 100644 index 0000000..348c0d6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20NoReturnMock.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20NoReturnMock is ERC20 { + function transfer(address to, uint256 amount) public override returns (bool) { + super.transfer(to, amount); + assembly { + return(0, 0) + } + } + + 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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20PermitNoRevertMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20PermitNoRevertMock.sol new file mode 100644 index 0000000..2176c51 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20PermitNoRevertMock.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/ERC20.sol"; +import "../../token/ERC20/extensions/draft-ERC20Permit.sol"; + +abstract contract ERC20PermitNoRevertMock is ERC20Permit { + function permitThatMayRevert( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + super.permit(owner, spender, value, deadline, v, r, s); + } + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override { + try this.permitThatMayRevert(owner, spender, value, deadline, v, r, s) { + // do nothing + } catch { + // do nothing + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ReturnFalseMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ReturnFalseMock.sol new file mode 100644 index 0000000..c4dc692 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20ReturnFalseMock.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20ReturnFalseMock is ERC20 { + function transfer(address, uint256) public pure override returns (bool) { + return false; + } + + function transferFrom(address, address, uint256) public pure override returns (bool) { + return false; + } + + function approve(address, uint256) public pure override returns (bool) { + return false; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20VotesLegacyMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC20VotesLegacyMock.sol new file mode 100644 index 0000000..09a2675 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC4626OffsetMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC4626OffsetMock.sol new file mode 100644 index 0000000..6e270ca --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC4646FeesMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC4646FeesMock.sol new file mode 100644 index 0000000..cd8f410 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol new file mode 100644 index 0000000..55c40ac --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import "../../token/ERC721/extensions/ERC721Enumerable.sol"; + +contract ERC721ConsecutiveEnumerableMock is ERC721Consecutive, ERC721Enumerable { + constructor( + string memory name, + string memory symbol, + address[] memory receivers, + uint96[] memory amounts + ) ERC721(name, symbol) { + for (uint256 i = 0; i < receivers.length; ++i) { + _mintConsecutive(receivers[i], amounts[i]); + } + } + + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC721, ERC721Enumerable) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) { + return super._ownerOf(tokenId); + } + + function _mint(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Consecutive) { + super._mint(to, tokenId); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Enumerable) { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + } + + function _afterTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Consecutive) { + super._afterTokenTransfer(from, to, firstTokenId, batchSize); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ConsecutiveMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ConsecutiveMock.sol new file mode 100644 index 0000000..427f44a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ConsecutiveMock.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import "../../token/ERC721/extensions/ERC721Enumerable.sol"; +import "../../token/ERC721/extensions/ERC721Pausable.sol"; +import "../../token/ERC721/extensions/draft-ERC721Votes.sol"; + +/** + * @title ERC721ConsecutiveMock + */ +contract ERC721ConsecutiveMock is ERC721Consecutive, ERC721Pausable, ERC721Votes { + constructor( + string memory name, + string memory symbol, + address[] memory delegates, + address[] memory receivers, + uint96[] memory amounts + ) ERC721(name, symbol) EIP712(name, "1") { + for (uint256 i = 0; i < delegates.length; ++i) { + _delegate(delegates[i], delegates[i]); + } + + for (uint256 i = 0; i < receivers.length; ++i) { + _mintConsecutive(receivers[i], amounts[i]); + } + } + + function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) { + return super._ownerOf(tokenId); + } + + function _mint(address to, uint256 tokenId) internal virtual override(ERC721, ERC721Consecutive) { + super._mint(to, tokenId); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Pausable) { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + } + + function _afterTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Votes, ERC721Consecutive) { + super._afterTokenTransfer(from, to, firstTokenId, batchSize); + } +} + +contract ERC721ConsecutiveNoConstructorMintMock is ERC721Consecutive { + constructor(string memory name, string memory symbol) ERC721(name, symbol) { + _mint(msg.sender, 0); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ReceiverMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ReceiverMock.sol new file mode 100644 index 0000000..dd25788 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721ReceiverMock.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC721/IERC721Receiver.sol"; + +contract ERC721ReceiverMock is IERC721Receiver { + enum Error { + None, + RevertWithMessage, + RevertWithoutMessage, + Panic + } + + bytes4 private immutable _retval; + Error private immutable _error; + + event Received(address operator, address from, uint256 tokenId, bytes data, uint256 gas); + + constructor(bytes4 retval, Error error) { + _retval = retval; + _error = error; + } + + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes memory data + ) public override returns (bytes4) { + if (_error == Error.RevertWithMessage) { + revert("ERC721ReceiverMock: reverting"); + } else if (_error == Error.RevertWithoutMessage) { + revert(); + } else if (_error == Error.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + emit Received(operator, from, tokenId, data, gasleft()); + return _retval; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721URIStorageMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721URIStorageMock.sol new file mode 100644 index 0000000..455c933 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC721URIStorageMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC721/extensions/ERC721URIStorage.sol"; + +abstract contract ERC721URIStorageMock is ERC721URIStorage { + string private _baseTokenURI; + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + function setBaseURI(string calldata newBaseTokenURI) public { + _baseTokenURI = newBaseTokenURI; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC777Mock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC777Mock.sol new file mode 100644 index 0000000..685277e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC777Mock.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC777/ERC777.sol"; + +abstract contract ERC777Mock is ERC777 { + event BeforeTokenTransfer(); + + function _beforeTokenTransfer(address, address, address, uint256) internal override { + emit BeforeTokenTransfer(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC777SenderRecipientMock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC777SenderRecipientMock.sol new file mode 100644 index 0000000..3bec6d9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/ERC777SenderRecipientMock.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../token/ERC777/IERC777.sol"; +import "../../token/ERC777/IERC777Sender.sol"; +import "../../token/ERC777/IERC777Recipient.sol"; +import "../../utils/Context.sol"; +import "../../utils/introspection/IERC1820Registry.sol"; +import "../../utils/introspection/ERC1820Implementer.sol"; + +contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer { + event TokensToSendCalled( + address operator, + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData, + address token, + uint256 fromBalance, + uint256 toBalance + ); + + event TokensReceivedCalled( + address operator, + address from, + address to, + uint256 amount, + bytes data, + bytes operatorData, + address token, + uint256 fromBalance, + uint256 toBalance + ); + + // Emitted in ERC777Mock. Here for easier decoding + event BeforeTokenTransfer(); + + bool private _shouldRevertSend; + bool private _shouldRevertReceive; + + IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); + + bytes32 private constant _TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); + bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); + + function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external override { + if (_shouldRevertSend) { + revert(); + } + + IERC777 token = IERC777(_msgSender()); + + uint256 fromBalance = token.balanceOf(from); + // when called due to burn, to will be the zero address, which will have a balance of 0 + uint256 toBalance = token.balanceOf(to); + + emit TokensToSendCalled( + operator, + from, + to, + amount, + userData, + operatorData, + address(token), + fromBalance, + toBalance + ); + } + + function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external override { + if (_shouldRevertReceive) { + revert(); + } + + IERC777 token = IERC777(_msgSender()); + + uint256 fromBalance = token.balanceOf(from); + // when called due to burn, to will be the zero address, which will have a balance of 0 + uint256 toBalance = token.balanceOf(to); + + emit TokensReceivedCalled( + operator, + from, + to, + amount, + userData, + operatorData, + address(token), + fromBalance, + toBalance + ); + } + + function senderFor(address account) public { + _registerInterfaceForAddress(_TOKENS_SENDER_INTERFACE_HASH, account); + + address self = address(this); + if (account == self) { + registerSender(self); + } + } + + function registerSender(address sender) public { + _erc1820.setInterfaceImplementer(address(this), _TOKENS_SENDER_INTERFACE_HASH, sender); + } + + function recipientFor(address account) public { + _registerInterfaceForAddress(_TOKENS_RECIPIENT_INTERFACE_HASH, account); + + address self = address(this); + if (account == self) { + registerRecipient(self); + } + } + + function registerRecipient(address recipient) public { + _erc1820.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, recipient); + } + + function setShouldRevertSend(bool shouldRevert) public { + _shouldRevertSend = shouldRevert; + } + + function setShouldRevertReceive(bool shouldRevert) public { + _shouldRevertReceive = shouldRevert; + } + + function send(IERC777 token, address to, uint256 amount, bytes memory data) public { + // This is 777's send function, not the Solidity send function + token.send(to, amount, data); // solhint-disable-line check-send-result + } + + function burn(IERC777 token, uint256 amount, bytes memory data) public { + token.burn(amount, data); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/VotesTimestamp.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/token/VotesTimestamp.sol new file mode 100644 index 0000000..179c500 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor1.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor1.sol new file mode 100644 index 0000000..37ecfd5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor1.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "../../governance/Governor.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import "../../governance/extensions/GovernorTimelockControl.sol"; + +contract MyGovernor1 is + Governor, + GovernorTimelockControl, + GovernorVotes, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + constructor( + IVotes _token, + TimelockController _timelock + ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} + + function votingDelay() public pure override returns (uint256) { + return 1; // 1 block + } + + function votingPeriod() public pure override returns (uint256) { + return 45818; // 1 week + } + + // The following functions are overrides required by Solidity. + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(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, 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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor2.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor2.sol new file mode 100644 index 0000000..1472b67 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor2.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "../../governance/Governor.sol"; +import "../../governance/extensions/GovernorProposalThreshold.sol"; +import "../../governance/extensions/GovernorCountingSimple.sol"; +import "../../governance/extensions/GovernorVotes.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import "../../governance/extensions/GovernorTimelockControl.sol"; + +contract MyGovernor2 is + Governor, + GovernorTimelockControl, + GovernorProposalThreshold, + GovernorVotes, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + constructor( + IVotes _token, + TimelockController _timelock + ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} + + function votingDelay() public pure override returns (uint256) { + return 1; // 1 block + } + + function votingPeriod() public pure override returns (uint256) { + return 45818; // 1 week + } + + function proposalThreshold() public pure override returns (uint256) { + return 1000e18; + } + + // The following functions are overrides required by Solidity. + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(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/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor3.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor3.sol new file mode 100644 index 0000000..aa15884 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/mocks/wizard/MyGovernor3.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.2; + +import "../../governance/Governor.sol"; +import "../../governance/compatibility/GovernorCompatibilityBravo.sol"; +import "../../governance/extensions/GovernorVotes.sol"; +import "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import "../../governance/extensions/GovernorTimelockControl.sol"; + +contract MyGovernor3 is + Governor, + GovernorTimelockControl, + GovernorCompatibilityBravo, + GovernorVotes, + GovernorVotesQuorumFraction +{ + constructor( + IVotes _token, + TimelockController _timelock + ) Governor("MyGovernor") GovernorVotes(_token) GovernorVotesQuorumFraction(4) GovernorTimelockControl(_timelock) {} + + function votingDelay() public pure override returns (uint256) { + return 1; // 1 block + } + + function votingPeriod() public pure override returns (uint256) { + return 45818; // 1 week + } + + function proposalThreshold() public pure override returns (uint256) { + return 1000e18; + } + + // The following functions are overrides required by Solidity. + + function quorum( + uint256 blockNumber + ) public view override(IGovernor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state( + uint256 proposalId + ) public view override(Governor, IGovernor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public override(Governor, GovernorCompatibilityBravo, IGovernor) returns (uint256) { + return super.propose(targets, values, calldatas, description); + } + + 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( + 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, IERC165, GovernorTimelockControl) returns (bool) { + return super.supportsInterface(interfaceId); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/package.json b/lib/openzeppelin-contracts-v4.9.3/contracts/package.json new file mode 100644 index 0000000..9412b07 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/package.json @@ -0,0 +1,32 @@ +{ + "name": "@openzeppelin/contracts", + "description": "Secure Smart Contract library for Solidity", + "version": "4.9.3", + "files": [ + "**/*.sol", + "/build/contracts/*.json", + "!/mocks/**/*" + ], + "scripts": { + "prepare": "bash ../scripts/prepare-contracts-package.sh", + "prepare-docs": "cd ..; npm run prepare-docs" + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "security", + "zeppelin" + ], + "author": "OpenZeppelin Community ", + "license": "MIT", + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, + "homepage": "https://openzeppelin.com/contracts/" +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/Clones.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/Clones.sol new file mode 100644 index 0000000..583e022 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/Clones.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol) + +pragma solidity ^0.8.0; + +/** + * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for + * deploying minimal proxy contracts, also known as "clones". + * + * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies + * > a minimal bytecode implementation that delegates all calls to a known, fixed address. + * + * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` + * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the + * deterministic method. + * + * _Available since v3.4._ + */ +library Clones { + /** + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. + * + * This function uses the create opcode, which should never revert. + */ + function clone(address implementation) internal returns (address instance) { + /// @solidity memory-safe-assembly + assembly { + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create(0, 0x09, 0x37) + } + require(instance != address(0), "ERC1167: create failed"); + } + + /** + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. + * + * This function uses the create2 opcode and a `salt` to deterministically deploy + * the clone. Using the same `implementation` and `salt` multiple time will revert, since + * the clones cannot be deployed twice at the same address. + */ + function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { + /// @solidity memory-safe-assembly + assembly { + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create2(0, 0x09, 0x37, salt) + } + require(instance != address(0), "ERC1167: create2 failed"); + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt, + address deployer + ) internal pure returns (address predicted) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(add(ptr, 0x38), deployer) + mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) + mstore(add(ptr, 0x14), implementation) + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) + mstore(add(ptr, 0x58), salt) + mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) + predicted := keccak256(add(ptr, 0x43), 0x55) + } + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt + ) internal view returns (address predicted) { + return predictDeterministicAddress(implementation, salt, address(this)); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/ERC1967/ERC1967Proxy.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/ERC1967/ERC1967Proxy.sol new file mode 100644 index 0000000..a04d701 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/ERC1967/ERC1967Proxy.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol) + +pragma solidity ^0.8.0; + +import "../Proxy.sol"; +import "./ERC1967Upgrade.sol"; + +/** + * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an + * implementation address that can be changed. This address is stored in storage in the location specified by + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the + * implementation behind the proxy. + */ +contract ERC1967Proxy is Proxy, ERC1967Upgrade { + /** + * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`. + * + * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded + * function call, and allows initializing the storage of the proxy like a Solidity constructor. + */ + constructor(address _logic, bytes memory _data) payable { + _upgradeToAndCall(_logic, _data, false); + } + + /** + * @dev Returns the current implementation address. + */ + function _implementation() internal view virtual override returns (address impl) { + return ERC1967Upgrade._getImplementation(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/ERC1967/ERC1967Upgrade.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/ERC1967/ERC1967Upgrade.sol new file mode 100644 index 0000000..cc9e569 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/ERC1967/ERC1967Upgrade.sol @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol) + +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"; + +/** + * @dev This abstract contract provides getters and event emitting update functions for + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. + * + * _Available since v4.1._ + */ +abstract contract ERC1967Upgrade is IERC1967 { + // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 + bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; + + /** + * @dev Storage slot with the address of the current implementation. + * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is + * validated in the constructor. + */ + bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + /** + * @dev Returns the current implementation address. + */ + function _getImplementation() internal view returns (address) { + return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 implementation slot. + */ + function _setImplementation(address newImplementation) private { + require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); + StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + } + + /** + * @dev Perform implementation upgrade + * + * Emits an {Upgraded} event. + */ + function _upgradeTo(address newImplementation) internal { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + } + + /** + * @dev Perform implementation upgrade with additional setup call. + * + * Emits an {Upgraded} event. + */ + function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal { + _upgradeTo(newImplementation); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(newImplementation, data); + } + } + + /** + * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. + * + * Emits an {Upgraded} event. + */ + function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal { + // Upgrades from old implementations will perform a rollback test. This test requires the new + // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing + // this special case will break upgrade paths from old UUPS implementation to new ones. + if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { + _setImplementation(newImplementation); + } else { + try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { + require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); + } catch { + revert("ERC1967Upgrade: new implementation is not UUPS"); + } + _upgradeToAndCall(newImplementation, data, forceCall); + } + } + + /** + * @dev Storage slot with the admin of the contract. + * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is + * validated in the constructor. + */ + bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + /** + * @dev Returns the current admin. + */ + function _getAdmin() internal view returns (address) { + return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 admin slot. + */ + function _setAdmin(address newAdmin) private { + require(newAdmin != address(0), "ERC1967: new admin is the zero address"); + StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; + } + + /** + * @dev Changes the admin of the proxy. + * + * Emits an {AdminChanged} event. + */ + function _changeAdmin(address newAdmin) internal { + emit AdminChanged(_getAdmin(), newAdmin); + _setAdmin(newAdmin); + } + + /** + * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. + * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. + */ + bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + + /** + * @dev Returns the current beacon. + */ + function _getBeacon() internal view returns (address) { + return StorageSlot.getAddressSlot(_BEACON_SLOT).value; + } + + /** + * @dev Stores a new beacon in the EIP1967 beacon slot. + */ + function _setBeacon(address newBeacon) private { + require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); + require( + Address.isContract(IBeacon(newBeacon).implementation()), + "ERC1967: beacon implementation is not a contract" + ); + StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; + } + + /** + * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does + * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). + * + * Emits a {BeaconUpgraded} event. + */ + function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal { + _setBeacon(newBeacon); + emit BeaconUpgraded(newBeacon); + if (data.length > 0 || forceCall) { + Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/Proxy.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/Proxy.sol new file mode 100644 index 0000000..988cf72 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/Proxy.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol) + +pragma solidity ^0.8.0; + +/** + * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM + * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to + * be specified by overriding the virtual {_implementation} function. + * + * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a + * different contract through the {_delegate} function. + * + * The success and return data of the delegated call will be returned back to the caller of the proxy. + */ +abstract contract Proxy { + /** + * @dev Delegates the current call to `implementation`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _delegate(address implementation) internal virtual { + assembly { + // Copy msg.data. We take full control of memory in this inline assembly + // block because it will not return to Solidity code. We overwrite the + // Solidity scratch pad at memory position 0. + calldatacopy(0, 0, calldatasize()) + + // Call the implementation. + // out and outsize are 0 because we don't know the size yet. + let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) + + // Copy the returned data. + returndatacopy(0, 0, returndatasize()) + + switch result + // delegatecall returns 0 on error. + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + + /** + * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function + * and {_fallback} should delegate. + */ + function _implementation() internal view virtual returns (address); + + /** + * @dev Delegates the current call to the address returned by `_implementation()`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _fallback() internal virtual { + _beforeFallback(); + _delegate(_implementation()); + } + + /** + * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other + * function in the contract matches the call data. + */ + fallback() external payable virtual { + _fallback(); + } + + /** + * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data + * is empty. + */ + receive() external payable virtual { + _fallback(); + } + + /** + * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback` + * call, or as part of the Solidity `fallback` or `receive` functions. + * + * If overridden should call `super._beforeFallback()`. + */ + function _beforeFallback() internal virtual {} +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/README.adoc new file mode 100644 index 0000000..89717a7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/README.adoc @@ -0,0 +1,87 @@ += Proxies + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/proxy + +This is a low-level set of contracts implementing different proxy patterns with and without upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page. + +Most of the proxies below are built on an abstract base contract. + +- {Proxy}: Abstract contract implementing the core delegation functionality. + +In order to avoid clashes with the storage variables of the implementation contract behind a proxy, we use https://eips.ethereum.org/EIPS/eip-1967[EIP1967] storage slots. + +- {ERC1967Upgrade}: Internal functions to get and set the storage slots defined in EIP1967. +- {ERC1967Proxy}: A proxy using EIP1967 storage slots. Not upgradeable by default. + +There are two alternative ways to add upgradeability to an ERC1967 proxy. Their differences are explained below in <>. + +- {TransparentUpgradeableProxy}: A proxy with a built in admin and upgrade interface. +- {UUPSUpgradeable}: An upgradeability mechanism to be included in the implementation contract. + +CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Truffle and Hardhat. + +A different family of proxies are beacon proxies. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. + +- {BeaconProxy}: A proxy that retrieves its implementation from a beacon contract. +- {UpgradeableBeacon}: A beacon contract with a built in admin that can upgrade the {BeaconProxy} pointing to it. + +In this pattern, the proxy contract doesn't hold the implementation address in storage like an ERC1967 proxy. Instead, the address is stored in a separate beacon contract. The `upgrade` operations are sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded. + +Outside the realm of upgradeability, proxies can also be useful to make cheap contract clones, such as those created by an on-chain factory contract that creates many instances of the same contract. These instances are designed to be both cheap to deploy, and cheap to call. + +- {Clones}: A library that can deploy cheap minimal non-upgradeable proxies. + +[[transparent-vs-uups]] +== Transparent vs UUPS Proxies + +The original proxies included in OpenZeppelin followed the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[Transparent Proxy Pattern]. While this pattern is still provided, our recommendation is now shifting towards UUPS proxies, which are both lightweight and versatile. The name UUPS comes from https://eips.ethereum.org/EIPS/eip-1822[EIP1822], which first documented the pattern. + +While both of these share the same interface for upgrades, in UUPS proxies the upgrade is handled by the implementation, and can eventually be removed. Transparent proxies, on the other hand, include the upgrade and admin logic in the proxy itself. This means {TransparentUpgradeableProxy} is more expensive to deploy than what is possible with UUPS proxies. + +UUPS proxies are implemented using an {ERC1967Proxy}. Note that this proxy is not by itself upgradeable. It is the role of the implementation to include, alongside the contract's logic, all the code necessary to update the implementation's address that is stored at a specific slot in the proxy's storage space. This is where the {UUPSUpgradeable} contract comes in. Inheriting from it (and overriding the {xref-UUPSUpgradeable-_authorizeUpgrade-address-}[`_authorizeUpgrade`] function with the relevant access control mechanism) will turn your contract into a UUPS compliant implementation. + +Note that since both proxies use the same storage slot for the implementation address, using a UUPS compliant implementation with a {TransparentUpgradeableProxy} might allow non-admins to perform upgrade operations. + +By default, the upgrade functionality included in {UUPSUpgradeable} contains a security mechanism that will prevent any upgrades to a non UUPS compliant implementation. This prevents upgrades to an implementation contract that wouldn't contain the necessary upgrade mechanism, as it would lock the upgradeability of the proxy forever. This security mechanism can be bypassed by either of: + +- Adding a flag mechanism in the implementation that will disable the upgrade function when triggered. +- Upgrading to an implementation that features an upgrade mechanism without the additional security check, and then upgrading again to another implementation without the upgrade mechanism. + +The current implementation of this security mechanism uses https://eips.ethereum.org/EIPS/eip-1822[EIP1822] to detect the storage slot used by the implementation. A previous implementation, now deprecated, relied on a rollback check. It is possible to upgrade from a contract using the old mechanism to a new one. The inverse is however not possible, as old implementations (before version 4.5) did not include the `ERC1822` interface. + +== Core + +{{Proxy}} + +== ERC1967 + +{{IERC1967}} + +{{ERC1967Proxy}} + +{{ERC1967Upgrade}} + +== Transparent Proxy + +{{TransparentUpgradeableProxy}} + +{{ProxyAdmin}} + +== Beacon + +{{BeaconProxy}} + +{{IBeacon}} + +{{UpgradeableBeacon}} + +== Minimal Clones + +{{Clones}} + +== Utils + +{{Initializable}} + +{{UUPSUpgradeable}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/BeaconProxy.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/BeaconProxy.sol new file mode 100644 index 0000000..d217b15 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/BeaconProxy.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (proxy/beacon/BeaconProxy.sol) + +pragma solidity ^0.8.0; + +import "./IBeacon.sol"; +import "../Proxy.sol"; +import "../ERC1967/ERC1967Upgrade.sol"; + +/** + * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. + * + * The beacon address is stored in storage slot `uint256(keccak256('eip1967.proxy.beacon')) - 1`, so that it doesn't + * conflict with the storage layout of the implementation behind the proxy. + * + * _Available since v3.4._ + */ +contract BeaconProxy is Proxy, ERC1967Upgrade { + /** + * @dev Initializes the proxy with `beacon`. + * + * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This + * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity + * constructor. + * + * Requirements: + * + * - `beacon` must be a contract with the interface {IBeacon}. + */ + constructor(address beacon, bytes memory data) payable { + _upgradeBeaconToAndCall(beacon, data, false); + } + + /** + * @dev Returns the current beacon address. + */ + function _beacon() internal view virtual returns (address) { + return _getBeacon(); + } + + /** + * @dev Returns the current implementation address of the associated beacon. + */ + function _implementation() internal view virtual override returns (address) { + return IBeacon(_getBeacon()).implementation(); + } + + /** + * @dev Changes the proxy to use a new beacon. Deprecated: see {_upgradeBeaconToAndCall}. + * + * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. + * + * Requirements: + * + * - `beacon` must be a contract. + * - The implementation returned by `beacon` must be a contract. + */ + function _setBeacon(address beacon, bytes memory data) internal virtual { + _upgradeBeaconToAndCall(beacon, data, false); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/IBeacon.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/IBeacon.sol new file mode 100644 index 0000000..fba3ee2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/IBeacon.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) + +pragma solidity ^0.8.0; + +/** + * @dev This is the interface that {BeaconProxy} expects of its beacon. + */ +interface IBeacon { + /** + * @dev Must return an address that can be used as a delegate call target. + * + * {BeaconProxy} will check that this address is a contract. + */ + function implementation() external view returns (address); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/UpgradeableBeacon.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/UpgradeableBeacon.sol new file mode 100644 index 0000000..5d83ceb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/beacon/UpgradeableBeacon.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (proxy/beacon/UpgradeableBeacon.sol) + +pragma solidity ^0.8.0; + +import "./IBeacon.sol"; +import "../../access/Ownable.sol"; +import "../../utils/Address.sol"; + +/** + * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their + * implementation contract, which is where they will delegate all function calls. + * + * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. + */ +contract UpgradeableBeacon is IBeacon, Ownable { + address private _implementation; + + /** + * @dev Emitted when the implementation returned by the beacon is changed. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Sets the address of the initial implementation, and the deployer account as the owner who can upgrade the + * beacon. + */ + constructor(address implementation_) { + _setImplementation(implementation_); + } + + /** + * @dev Returns the current implementation address. + */ + function implementation() public view virtual override returns (address) { + return _implementation; + } + + /** + * @dev Upgrades the beacon to a new implementation. + * + * Emits an {Upgraded} event. + * + * Requirements: + * + * - msg.sender must be the owner of the contract. + * - `newImplementation` must be a contract. + */ + function upgradeTo(address newImplementation) public virtual onlyOwner { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + } + + /** + * @dev Sets the implementation contract address for this beacon + * + * Requirements: + * + * - `newImplementation` must be a contract. + */ + function _setImplementation(address newImplementation) private { + require(Address.isContract(newImplementation), "UpgradeableBeacon: implementation is not a contract"); + _implementation = newImplementation; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/transparent/ProxyAdmin.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/transparent/ProxyAdmin.sol new file mode 100644 index 0000000..5715305 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/transparent/ProxyAdmin.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.3) (proxy/transparent/ProxyAdmin.sol) + +pragma solidity ^0.8.0; + +import "./TransparentUpgradeableProxy.sol"; +import "../../access/Ownable.sol"; + +/** + * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an + * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. + */ +contract ProxyAdmin is Ownable { + /** + * @dev Returns the current implementation of `proxy`. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + 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"); + require(success); + return abi.decode(returndata, (address)); + } + + /** + * @dev Returns the current admin of `proxy`. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + 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"); + require(success); + return abi.decode(returndata, (address)); + } + + /** + * @dev Changes the admin of `proxy` to `newAdmin`. + * + * Requirements: + * + * - This contract must be the current admin of `proxy`. + */ + function changeProxyAdmin(ITransparentUpgradeableProxy proxy, address newAdmin) public virtual onlyOwner { + proxy.changeAdmin(newAdmin); + } + + /** + * @dev Upgrades `proxy` to `implementation`. See {TransparentUpgradeableProxy-upgradeTo}. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function upgrade(ITransparentUpgradeableProxy proxy, address implementation) public virtual onlyOwner { + proxy.upgradeTo(implementation); + } + + /** + * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. See + * {TransparentUpgradeableProxy-upgradeToAndCall}. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + */ + function upgradeAndCall( + ITransparentUpgradeableProxy proxy, + address implementation, + bytes memory data + ) public payable virtual onlyOwner { + proxy.upgradeToAndCall{value: msg.value}(implementation, data); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/transparent/TransparentUpgradeableProxy.sol new file mode 100644 index 0000000..6f18b49 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/transparent/TransparentUpgradeableProxy.sol) + +pragma solidity ^0.8.0; + +import "../ERC1967/ERC1967Proxy.sol"; + +/** + * @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); + + 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. + * + * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector + * clashing], which can potentially be used in an attack, this contract uses the + * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two + * things that go hand in hand: + * + * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if + * that call matches one of the admin functions exposed by the proxy itself. + * 2. If the admin calls the proxy, it can access the admin functions, but its calls will never be forwarded to the + * implementation. If the admin tries to call a function on the implementation it will fail with an error that says + * "admin cannot fallback to proxy target". + * + * These properties mean that the admin account can only be used for admin actions like upgrading the proxy or changing + * the admin, so it's best if it's a dedicated account that is not used for anything else. This will avoid headaches due + * to sudden errors when trying to call a function from the proxy implementation. + * + * 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. + * + * 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 { + /** + * @dev Initializes an upgradeable proxy managed by `_admin`, backed by the implementation at `_logic`, and + * optionally initialized with `_data` as explained in {ERC1967Proxy-constructor}. + */ + constructor(address _logic, address admin_, bytes memory _data) payable ERC1967Proxy(_logic, _data) { + _changeAdmin(admin_); + } + + /** + * @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()) { + _; + } else { + _fallback(); + } + } + + /** + * @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. + * + * 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 _dispatchAdmin() private returns (bytes memory) { + _requireZeroValue(); + + address admin = _getAdmin(); + return abi.encode(admin); + } + + /** + * @dev Returns the current implementation. + * + * 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 _dispatchImplementation() private returns (bytes memory) { + _requireZeroValue(); + + address implementation = _implementation(); + return abi.encode(implementation); + } + + /** + * @dev Changes the admin of the proxy. + * + * Emits an {AdminChanged} event. + */ + 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. + */ + 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. + */ + function _dispatchUpgradeToAndCall() private returns (bytes memory) { + (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes)); + _upgradeToAndCall(newImplementation, data, true); + + return ""; + } + + /** + * @dev Returns the current admin. + * + * CAUTION: This function is deprecated. Use {ERC1967Upgrade-_getAdmin} instead. + */ + function _admin() internal view virtual returns (address) { + return _getAdmin(); + } + + /** + * @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/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/utils/Initializable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/utils/Initializable.sol new file mode 100644 index 0000000..33ec227 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/utils/Initializable.sol @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) + +pragma solidity ^0.8.2; + +import "../../utils/Address.sol"; + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * 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"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Indicates that the contract has been initialized. + * @custom:oz-retyped-from bool + */ + uint8 private _initialized; + + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool private _initializing; + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint8 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a + * constructor. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + bool isTopLevelCall = !_initializing; + require( + (isTopLevelCall && _initialized < 1) || (!Address.isContract(address(this)) && _initialized == 1), + "Initializable: contract is already initialized" + ); + _initialized = 1; + if (isTopLevelCall) { + _initializing = true; + } + _; + if (isTopLevelCall) { + _initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: setting the version to 255 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint8 version) { + require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); + _initialized = version; + _initializing = true; + _; + _initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + require(_initializing, "Initializable: contract is not initializing"); + _; + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + require(!_initializing, "Initializable: contract is initializing"); + if (_initialized != type(uint8).max) { + _initialized = type(uint8).max; + emit Initialized(type(uint8).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint8) { + return _initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _initializing; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/utils/UUPSUpgradeable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/utils/UUPSUpgradeable.sol new file mode 100644 index 0000000..86684cf --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/proxy/utils/UUPSUpgradeable.sol @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol) + +pragma solidity ^0.8.0; + +import "../../interfaces/draft-IERC1822.sol"; +import "../ERC1967/ERC1967Upgrade.sol"; + +/** + * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an + * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. + * + * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is + * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing + * `UUPSUpgradeable` with a custom implementation of upgrades. + * + * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. + * + * _Available since v4.1._ + */ +abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment + address private immutable __self = address(this); + + /** + * @dev Check that the execution is being performed through a delegatecall call and that the execution context is + * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case + * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a + * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to + * fail. + */ + modifier onlyProxy() { + require(address(this) != __self, "Function must be called through delegatecall"); + require(_getImplementation() == __self, "Function must be called through active proxy"); + _; + } + + /** + * @dev Check that the execution is not being performed through a delegate call. This allows a function to be + * callable on the implementing contract but not through proxies. + */ + modifier notDelegated() { + require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); + _; + } + + /** + * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the + * implementation. It is used to validate the implementation's compatibility when performing an upgrade. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. + */ + function proxiableUUID() external view virtual override notDelegated returns (bytes32) { + return _IMPLEMENTATION_SLOT; + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeTo(address newImplementation) public virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call + * encoded in `data`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, data, true); + } + + /** + * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by + * {upgradeTo} and {upgradeToAndCall}. + * + * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. + * + * ```solidity + * function _authorizeUpgrade(address) internal override onlyOwner {} + * ``` + */ + function _authorizeUpgrade(address newImplementation) internal virtual; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/security/Pausable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/security/Pausable.sol new file mode 100644 index 0000000..bdd1184 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/security/Pausable.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) + +pragma solidity ^0.8.0; + +import "../utils/Context.sol"; + +/** + * @dev Contract module which allows children to implement an emergency stop + * mechanism that can be triggered by an authorized account. + * + * This module is used through inheritance. It will make available the + * modifiers `whenNotPaused` and `whenPaused`, which can be applied to + * the functions of your contract. Note that they will not be pausable by + * simply including this module, only once the modifiers are put in place. + */ +abstract contract Pausable is Context { + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); + + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); + + bool private _paused; + + /** + * @dev Initializes the contract in unpaused state. + */ + constructor() { + _paused = false; + } + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + _requireNotPaused(); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + * + * Requirements: + * + * - The contract must be paused. + */ + modifier whenPaused() { + _requirePaused(); + _; + } + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** + * @dev Throws if the contract is paused. + */ + function _requireNotPaused() internal view virtual { + require(!paused(), "Pausable: paused"); + } + + /** + * @dev Throws if the contract is not paused. + */ + function _requirePaused() internal view virtual { + require(paused(), "Pausable: not paused"); + } + + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(_msgSender()); + } + + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(_msgSender()); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/security/PullPayment.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/security/PullPayment.sol new file mode 100644 index 0000000..65b4980 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/security/PullPayment.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (security/PullPayment.sol) + +pragma solidity ^0.8.0; + +import "../utils/escrow/Escrow.sol"; + +/** + * @dev Simple implementation of a + * https://consensys.github.io/smart-contract-best-practices/development-recommendations/general/external-calls/#favor-pull-over-push-for-external-calls[pull-payment] + * strategy, where the paying contract doesn't interact directly with the + * receiver account, which must withdraw its payments itself. + * + * Pull-payments are often considered the best practice when it comes to sending + * Ether, security-wise. It prevents recipients from blocking execution, and + * eliminates reentrancy concerns. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + * + * 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}. + */ +abstract contract PullPayment { + Escrow private immutable _escrow; + + constructor() { + _escrow = new Escrow(); + } + + /** + * @dev Withdraw accumulated payments, forwarding all gas to the recipient. + * + * Note that _any_ account can call this function, not just the `payee`. + * This means that contracts unaware of the `PullPayment` protocol can still + * receive funds this way, by having a separate account call + * {withdrawPayments}. + * + * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. + * Make sure you trust the recipient, or are either following the + * checks-effects-interactions pattern or using {ReentrancyGuard}. + * + * @param payee Whose payments will be withdrawn. + * + * Causes the `escrow` to emit a {Withdrawn} event. + */ + function withdrawPayments(address payable payee) public virtual { + _escrow.withdraw(payee); + } + + /** + * @dev Returns the payments owed to an address. + * @param dest The creditor's address. + */ + function payments(address dest) public view returns (uint256) { + return _escrow.depositsOf(dest); + } + + /** + * @dev Called by the payer to store the sent amount as credit to be pulled. + * Funds sent in this way are stored in an intermediate {Escrow} contract, so + * there is no danger of them being spent before withdrawal. + * + * @param dest The destination address of the funds. + * @param amount The amount to transfer. + * + * Causes the `escrow` to emit a {Deposited} event. + */ + function _asyncTransfer(address dest, uint256 amount) internal virtual { + _escrow.deposit{value: amount}(dest); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/security/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/security/README.adoc new file mode 100644 index 0000000..66f398f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/security/README.adoc @@ -0,0 +1,20 @@ += Security + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/security + +These contracts aim to cover common security practices. + +* {PullPayment}: A pattern that can be used to avoid reentrancy attacks. +* {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions. +* {Pausable}: A common emergency response mechanism that can pause functionality while a remediation is pending. + +TIP: For an overview on reentrancy and the possible mechanisms to prevent it, read our article https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + +== Contracts + +{{PullPayment}} + +{{ReentrancyGuard}} + +{{Pausable}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/security/ReentrancyGuard.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/security/ReentrancyGuard.sol new file mode 100644 index 0000000..dac508b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/security/ReentrancyGuard.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant _NOT_ENTERED = 1; + uint256 private constant _ENTERED = 2; + + uint256 private _status; + + constructor() { + _status = _NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + _nonReentrantBefore(); + _; + _nonReentrantAfter(); + } + + function _nonReentrantBefore() private { + // On the first call to nonReentrant, _status will be _NOT_ENTERED + require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); + + // Any calls to nonReentrant after this point will fail + _status = _ENTERED; + } + + function _nonReentrantAfter() private { + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = _NOT_ENTERED; + } + + /** + * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a + * `nonReentrant` function in the call stack. + */ + function _reentrancyGuardEntered() internal view returns (bool) { + return _status == _ENTERED; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/ERC1155.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/ERC1155.sol new file mode 100644 index 0000000..6260e4c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/ERC1155.sol @@ -0,0 +1,497 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/ERC1155.sol) + +pragma solidity ^0.8.0; + +import "./IERC1155.sol"; +import "./IERC1155Receiver.sol"; +import "./extensions/IERC1155MetadataURI.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of the basic standard multi-token. + * See https://eips.ethereum.org/EIPS/eip-1155 + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + * + * _Available since v3.1._ + */ +contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI { + using Address for address; + + // Mapping from token ID to account balances + mapping(uint256 => mapping(address => uint256)) private _balances; + + // Mapping from account to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json + string private _uri; + + /** + * @dev See {_setURI}. + */ + constructor(string memory uri_) { + _setURI(uri_); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC1155).interfaceId || + interfaceId == type(IERC1155MetadataURI).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function uri(uint256) public view virtual override returns (string memory) { + return _uri; + } + + /** + * @dev See {IERC1155-balanceOf}. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) public view virtual override returns (uint256) { + require(account != address(0), "ERC1155: address zero is not a valid owner"); + return _balances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] memory accounts, + uint256[] memory ids + ) public view virtual override returns (uint256[] memory) { + require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts[i], ids[i]); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) public view virtual override returns (bool) { + return _operatorApprovals[account][operator]; + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: caller is not token owner or approved" + ); + _safeTransferFrom(from, to, id, amount, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) public virtual override { + require( + from == _msgSender() || isApprovedForAll(from, _msgSender()), + "ERC1155: caller is not token owner or approved" + ); + _safeBatchTransferFrom(from, to, ids, amounts, data); + } + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: transfer to the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + _balances[id][to] += amount; + + emit TransferSingle(operator, from, to, id, amount); + + _afterTokenTransfer(operator, from, to, ids, amounts, data); + + _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + require(to != address(0), "ERC1155: transfer to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: insufficient balance for transfer"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + _balances[id][to] += amount; + } + + emit TransferBatch(operator, from, to, ids, amounts); + + _afterTokenTransfer(operator, from, to, ids, amounts, data); + + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data); + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the amounts in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setURI(string memory newuri) internal virtual { + _uri = newuri; + } + + /** + * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + _balances[id][to] += amount; + emit TransferSingle(operator, address(0), to, id, amount); + + _afterTokenTransfer(operator, address(0), to, ids, amounts, data); + + _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), to, ids, amounts, data); + + for (uint256 i = 0; i < ids.length; i++) { + _balances[ids[i]][to] += amounts[i]; + } + + emit TransferBatch(operator, address(0), to, ids, amounts); + + _afterTokenTransfer(operator, address(0), to, ids, amounts, data); + + _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, ids, amounts, data); + } + + /** + * @dev Destroys `amount` tokens of token type `id` from `from` + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `amount` tokens of token type `id`. + */ + function _burn(address from, uint256 id, uint256 amount) internal virtual { + require(from != address(0), "ERC1155: burn from the zero address"); + + address operator = _msgSender(); + uint256[] memory ids = _asSingletonArray(id); + uint256[] memory amounts = _asSingletonArray(amount); + + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + + emit TransferSingle(operator, from, address(0), id, amount); + + _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + */ + function _burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) internal virtual { + require(from != address(0), "ERC1155: burn from the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, from, address(0), ids, amounts, ""); + + for (uint256 i = 0; i < ids.length; i++) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC1155: burn amount exceeds balance"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + } + + emit TransferBatch(operator, from, address(0), ids, amounts); + + _afterTokenTransfer(operator, from, address(0), ids, amounts, ""); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + require(owner != operator, "ERC1155: setting approval status for self"); + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Hook that is called before any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `ids` and `amounts` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + /** + * @dev Hook that is called after any token transfer. This includes minting + * and burning, as well as batched variants. + * + * The same hook is called on both single and batched variants. For single + * transfers, the length of the `id` and `amount` arrays will be 1. + * + * Calling conditions (for each `id` and `amount` pair): + * + * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * of token type `id` will be transferred to `to`. + * - When `from` is zero, `amount` tokens of token type `id` will be minted + * for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens of token type `id` + * will be burned. + * - `from` and `to` are never both zero. + * - `ids` and `amounts` have the same, non-zero length. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual {} + + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) private { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non-ERC1155Receiver implementer"); + } + } + } + + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) private { + if (to.isContract()) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns ( + bytes4 response + ) { + if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + revert("ERC1155: ERC1155Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC1155: transfer to non-ERC1155Receiver implementer"); + } + } + } + + function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) { + uint256[] memory array = new uint256[](1); + array[0] = element; + + return array; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/IERC1155.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/IERC1155.sol new file mode 100644 index 0000000..3446e60 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/IERC1155.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/IERC1155.sol) + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC1155 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-1155[EIP]. + * + * _Available since v3.1._ + */ +interface IERC1155 is IERC165 { + /** + * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`. + */ + event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); + + /** + * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all + * transfers. + */ + event TransferBatch( + address indexed operator, + address indexed from, + address indexed to, + uint256[] ids, + uint256[] values + ); + + /** + * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to + * `approved`. + */ + event ApprovalForAll(address indexed account, address indexed operator, bool approved); + + /** + * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. + * + * If an {URI} event was emitted for `id`, the standard + * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value + * returned by {IERC1155MetadataURI-uri}. + */ + event URI(string value, uint256 indexed id); + + /** + * @dev Returns the amount of tokens of token type `id` owned by `account`. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) external view returns (uint256); + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] calldata accounts, + uint256[] calldata ids + ) external view returns (uint256[] memory); + + /** + * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the caller. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address account, address operator) external view returns (bool); + + /** + * @dev Transfers `amount` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. + * - `from` must have a balance of tokens of type `id` of at least `amount`. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external; + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] calldata ids, + uint256[] calldata amounts, + bytes calldata data + ) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/IERC1155Receiver.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/IERC1155Receiver.sol new file mode 100644 index 0000000..0dd271d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/IERC1155Receiver.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol) + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev _Available since v3.1._ + */ +interface IERC1155Receiver is IERC165 { + /** + * @dev Handles the receipt of a single ERC1155 token type. This function is + * called at the end of a `safeTransferFrom` after the balance has been updated. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + * (i.e. 0xf23a6e61, or its own function selector). + * + * @param operator The address which initiated the transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param id The ID of the token being transferred + * @param value The amount of tokens being transferred + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4); + + /** + * @dev Handles the receipt of a multiple ERC1155 token types. This function + * is called at the end of a `safeBatchTransferFrom` after the balances have + * been updated. + * + * NOTE: To accept the transfer(s), this must return + * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + * (i.e. 0xbc197c81, or its own function selector). + * + * @param operator The address which initiated the batch transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param ids An array containing ids of each token being transferred (order and length must match values array) + * @param values An array containing amounts of each token being transferred (order and length must match ids array) + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/README.adoc new file mode 100644 index 0000000..13ffbdb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/README.adoc @@ -0,0 +1,49 @@ += ERC 1155 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc1155 + +This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-1155[ERC1155 Multi Token Standard]. + +The EIP consists of three interfaces which fulfill different roles, found here as {IERC1155}, {IERC1155MetadataURI} and {IERC1155Receiver}. + +{ERC1155} implements the mandatory {IERC1155} interface, as well as the optional extension {IERC1155MetadataURI}, by relying on the substitution mechanism to use the same URI for all token types, dramatically reducing gas costs. + +Additionally there are multiple custom extensions, including: + +* designation of addresses that can pause token transfers for all users ({ERC1155Pausable}). +* destruction of own tokens ({ERC1155Burnable}). + +NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC1155 (such as <>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc1155.adoc#Presets[ERC1155 Presets] (such as {ERC1155PresetMinterPauser}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts. + +== Core + +{{IERC1155}} + +{{IERC1155MetadataURI}} + +{{ERC1155}} + +{{IERC1155Receiver}} + +{{ERC1155Receiver}} + +== Extensions + +{{ERC1155Pausable}} + +{{ERC1155Burnable}} + +{{ERC1155Supply}} + +{{ERC1155URIStorage}} + +== 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. + +{{ERC1155PresetMinterPauser}} + +== Utilities + +{{ERC1155Holder}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Burnable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Burnable.sol new file mode 100644 index 0000000..9ee3719 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Burnable.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/extensions/ERC1155Burnable.sol) + +pragma solidity ^0.8.0; + +import "../ERC1155.sol"; + +/** + * @dev Extension of {ERC1155} that allows token holders to destroy both their + * own tokens and those that they have been approved to use. + * + * _Available since v3.1._ + */ +abstract contract ERC1155Burnable is ERC1155 { + function burn(address account, uint256 id, uint256 value) public virtual { + require( + account == _msgSender() || isApprovedForAll(account, _msgSender()), + "ERC1155: caller is not token owner or approved" + ); + + _burn(account, id, value); + } + + function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual { + require( + account == _msgSender() || isApprovedForAll(account, _msgSender()), + "ERC1155: caller is not token owner or approved" + ); + + _burnBatch(account, ids, values); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Pausable.sol new file mode 100644 index 0000000..07bb390 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC1155/extensions/ERC1155Pausable.sol) + +pragma solidity ^0.8.0; + +import "../ERC1155.sol"; +import "../../../security/Pausable.sol"; + +/** + * @dev ERC1155 token with pausable token transfers, minting and burning. + * + * 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. + * + * _Available since v3.1._ + */ +abstract contract ERC1155Pausable is ERC1155, Pausable { + /** + * @dev See {ERC1155-_beforeTokenTransfer}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override { + super._beforeTokenTransfer(operator, from, to, ids, amounts, data); + + require(!paused(), "ERC1155Pausable: token transfer while paused"); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Supply.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Supply.sol new file mode 100644 index 0000000..ec24389 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155Supply.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155Supply.sol) + +pragma solidity ^0.8.0; + +import "../ERC1155.sol"; + +/** + * @dev Extension of ERC1155 that adds tracking of total supply per id. + * + * Useful for scenarios where Fungible and Non-fungible tokens have to be + * clearly identified. Note: While a totalSupply of 1 might mean the + * corresponding is an NFT, there is no guarantees that no other token with the + * same id are not going to be minted. + */ +abstract contract ERC1155Supply is ERC1155 { + mapping(uint256 => uint256) private _totalSupply; + + /** + * @dev Total amount of tokens in with a given id. + */ + function totalSupply(uint256 id) public view virtual returns (uint256) { + return _totalSupply[id]; + } + + /** + * @dev Indicates whether any token exist with a given id, or not. + */ + function exists(uint256 id) public view virtual returns (bool) { + return ERC1155Supply.totalSupply(id) > 0; + } + + /** + * @dev See {ERC1155-_beforeTokenTransfer}. + */ + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override { + super._beforeTokenTransfer(operator, from, to, ids, amounts, data); + + if (from == address(0)) { + for (uint256 i = 0; i < ids.length; ++i) { + _totalSupply[ids[i]] += amounts[i]; + } + } + + if (to == address(0)) { + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + uint256 supply = _totalSupply[id]; + require(supply >= amount, "ERC1155: burn amount exceeds totalSupply"); + unchecked { + _totalSupply[id] = supply - amount; + } + } + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol new file mode 100644 index 0000000..623504f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC1155/extensions/ERC1155URIStorage.sol) + +pragma solidity ^0.8.0; + +import "../../../utils/Strings.sol"; +import "../ERC1155.sol"; + +/** + * @dev ERC1155 token with storage based token URI management. + * Inspired by the ERC721URIStorage extension + * + * _Available since v4.6._ + */ +abstract contract ERC1155URIStorage is ERC1155 { + using Strings for uint256; + + // Optional base URI + string private _baseURI = ""; + + // Optional mapping for token URIs + mapping(uint256 => string) private _tokenURIs; + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the concatenation of the `_baseURI` + * and the token-specific uri if the latter is set + * + * This enables the following behaviors: + * + * - if `_tokenURIs[tokenId]` is set, then the result is the concatenation + * of `_baseURI` and `_tokenURIs[tokenId]` (keep in mind that `_baseURI` + * is empty per default); + * + * - if `_tokenURIs[tokenId]` is NOT set then we fallback to `super.uri()` + * which in most cases will contain `ERC1155._uri`; + * + * - if `_tokenURIs[tokenId]` is NOT set, and if the parents do not have a + * uri value set, then the result is empty. + */ + function uri(uint256 tokenId) public view virtual override returns (string memory) { + string memory tokenURI = _tokenURIs[tokenId]; + + // If token URI is set, concatenate base URI and tokenURI (via abi.encodePacked). + return bytes(tokenURI).length > 0 ? string(abi.encodePacked(_baseURI, tokenURI)) : super.uri(tokenId); + } + + /** + * @dev Sets `tokenURI` as the tokenURI of `tokenId`. + */ + function _setURI(uint256 tokenId, string memory tokenURI) internal virtual { + _tokenURIs[tokenId] = tokenURI; + emit URI(uri(tokenId), tokenId); + } + + /** + * @dev Sets `baseURI` as the `_baseURI` for all tokens + */ + function _setBaseURI(string memory baseURI) internal virtual { + _baseURI = baseURI; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol new file mode 100644 index 0000000..520a297 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol) + +pragma solidity ^0.8.0; + +import "../IERC1155.sol"; + +/** + * @dev Interface of the optional ERC1155MetadataExtension interface, as defined + * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. + * + * _Available since v3.1._ + */ +interface IERC1155MetadataURI is IERC1155 { + /** + * @dev Returns the URI for token type `id`. + * + * If the `\{id\}` substring is present in the URI, it must be replaced by + * clients with the actual token type ID. + */ + function uri(uint256 id) external view returns (string memory); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol new file mode 100644 index 0000000..2f68dca --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC1155/presets/ERC1155PresetMinterPauser.sol) + +pragma solidity ^0.8.0; + +import "../ERC1155.sol"; +import "../extensions/ERC1155Burnable.sol"; +import "../extensions/ERC1155Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; + +/** + * @dev {ERC1155} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC1155PresetMinterPauser is Context, AccessControlEnumerable, ERC1155Burnable, ERC1155Pausable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE`, and `PAUSER_ROLE` to the account that + * deploys the contract. + */ + constructor(string memory uri) ERC1155(uri) { + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _setupRole(MINTER_ROLE, _msgSender()); + _setupRole(PAUSER_ROLE, _msgSender()); + } + + /** + * @dev Creates `amount` new tokens for `to`, of token type `id`. + * + * See {ERC1155-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 id, uint256 amount, bytes memory data) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have minter role to mint"); + + _mint(to, id, amount, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] variant of {mint}. + */ + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have minter role to mint"); + + _mintBatch(to, ids, amounts, data); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC1155Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC1155Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC1155PresetMinterPauser: must have pauser role to unpause"); + _unpause(); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(AccessControlEnumerable, ERC1155) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function _beforeTokenTransfer( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual override(ERC1155, ERC1155Pausable) { + super._beforeTokenTransfer(operator, from, to, ids, amounts, data); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/presets/README.md b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/presets/README.md new file mode 100644 index 0000000..468200b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/presets/README.md @@ -0,0 +1 @@ +Contract presets are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com/) as a more powerful alternative. diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/utils/ERC1155Holder.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/utils/ERC1155Holder.sol new file mode 100644 index 0000000..7249de8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/utils/ERC1155Holder.sol) + +pragma solidity ^0.8.0; + +import "./ERC1155Receiver.sol"; + +/** + * Simple implementation of `ERC1155Receiver` that will allow a contract to hold ERC1155 tokens. + * + * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be + * stuck. + * + * @dev _Available since v3.1._ + */ +contract ERC1155Holder is ERC1155Receiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/utils/ERC1155Receiver.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/utils/ERC1155Receiver.sol new file mode 100644 index 0000000..2e6804a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC1155/utils/ERC1155Receiver.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC1155/utils/ERC1155Receiver.sol) + +pragma solidity ^0.8.0; + +import "../IERC1155Receiver.sol"; +import "../../../utils/introspection/ERC165.sol"; + +/** + * @dev _Available since v3.1._ + */ +abstract contract ERC1155Receiver is ERC165, IERC1155Receiver { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/ERC20.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/ERC20.sol new file mode 100644 index 0000000..91b7f98 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/ERC20.sol @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol) + +pragma solidity ^0.8.0; + +import "./IERC20.sol"; +import "./extensions/IERC20Metadata.sol"; +import "../../utils/Context.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * For a generic mechanism see {ERC20PresetMinterPauser}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + * + * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} + * functions have been added to mitigate the well-known issues around setting + * allowances. See {IERC20-approve}. + */ +contract ERC20 is Context, IERC20, IERC20Metadata { + mapping(address => uint256) private _balances; + + mapping(address => mapping(address => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual override returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual override returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `amount`. + */ + function transfer(address to, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, amount); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 amount) public virtual override returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, amount); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + * - the caller must have allowance for ``from``'s tokens of at least + * `amount`. + */ + function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, amount); + _transfer(from, to, amount); + return true; + } + + /** + * @dev Atomically increases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, allowance(owner, spender) + addedValue); + return true; + } + + /** + * @dev Atomically decreases the allowance granted to `spender` by the caller. + * + * This is an alternative to {approve} that can be used as a mitigation for + * problems described in {IERC20-approve}. + * + * Emits an {Approval} event indicating the updated allowance. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `spender` must have allowance for the caller of at least + * `subtractedValue`. + */ + function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { + address owner = _msgSender(); + uint256 currentAllowance = allowance(owner, spender); + require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); + unchecked { + _approve(owner, spender, currentAllowance - subtractedValue); + } + + return true; + } + + /** + * @dev Moves `amount` of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `from` must have a balance of at least `amount`. + */ + function _transfer(address from, address to, uint256 amount) internal virtual { + require(from != address(0), "ERC20: transfer from the zero address"); + require(to != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(from, to, amount); + + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by + // decrementing then incrementing. + _balances[to] += amount; + } + + emit Transfer(from, to, amount); + + _afterTokenTransfer(from, to, amount); + } + + /** @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function _mint(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), account, amount); + + _totalSupply += amount; + unchecked { + // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. + _balances[account] += amount; + } + emit Transfer(address(0), account, amount); + + _afterTokenTransfer(address(0), account, amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, reducing the + * total supply. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * Requirements: + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + */ + function _burn(address account, uint256 amount) internal virtual { + require(account != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(account, address(0), amount); + + uint256 accountBalance = _balances[account]; + require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); + unchecked { + _balances[account] = accountBalance - amount; + // Overflow not possible: amount <= accountBalance <= totalSupply. + _totalSupply -= amount; + } + + emit Transfer(account, address(0), amount); + + _afterTokenTransfer(account, address(0), amount); + } + + /** + * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + */ + function _approve(address owner, address spender, uint256 amount) internal virtual { + require(owner != address(0), "ERC20: approve from the zero address"); + require(spender != address(0), "ERC20: approve to the zero address"); + + _allowances[owner][spender] = amount; + emit Approval(owner, spender, amount); + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * + * Does not update the allowance amount in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Might emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC20: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount); + } + } + } + + /** + * @dev Hook that is called before any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {} + + /** + * @dev Hook that is called after any transfer of tokens. This includes + * minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * has been transferred to `to`. + * - when `from` is zero, `amount` tokens have been minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens have been burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {} +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/IERC20.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/IERC20.sol new file mode 100644 index 0000000..6d5b4e9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/IERC20.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 amount) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 amount) external returns (bool); + + /** + * @dev Moves `amount` tokens from `from` to `to` using the + * allowance mechanism. `amount` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 amount) external returns (bool); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/README.adoc new file mode 100644 index 0000000..b3f68e5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/README.adoc @@ -0,0 +1,78 @@ += ERC 20 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc20 + +This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-20[ERC20 Token Standard]. + +TIP: For an overview of ERC20 tokens and a walk through on how to create a token contract read our xref:ROOT:erc20.adoc[ERC20 guide]. + +There are a few core contracts that implement the behavior specified in the EIP: + +* {IERC20}: the interface all ERC20 implementations should conform to. +* {IERC20Metadata}: the extended ERC20 interface including the <>, <> and <> functions. +* {ERC20}: the implementation of the ERC20 interface, including the <>, <> and <> optional standard extension to the base interface. + +Additionally there are multiple custom extensions, including: + +* {ERC20Burnable}: destruction of own tokens. +* {ERC20Capped}: enforcement of a cap to the total supply when minting tokens. +* {ERC20Pausable}: ability to pause token transfers. +* {ERC20Snapshot}: efficient storage of past token balances to be later queried at any point in time. +* {ERC20Permit}: gasless approval of tokens (standardized as ERC2612). +* {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC3156). +* {ERC20Votes}: support for voting and vote delegation. +* {ERC20VotesComp}: support for voting and vote delegation (compatible with Compound's token, with uint96 restrictions). +* {ERC20Wrapper}: wrapper to create an ERC20 backed by another ERC20, with deposit and withdraw methods. Useful in conjunction with {ERC20Votes}. +* {ERC4626}: tokenized vault that manages shares (represented as ERC20) that are backed by assets (another ERC20). + +Finally, there are some utilities to interact with ERC20 contracts in various ways. + +* {SafeERC20}: a wrapper around the interface that eliminates the need to handle boolean return values. +* {TokenTimelock}: hold tokens for a beneficiary until a specified time. + +NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC20 (such as <>) and expose them as external functions in the way they prefer. On the other hand, xref:ROOT:erc20.adoc#Presets[ERC20 Presets] (such as {ERC20PresetMinterPauser}) are designed using opinionated patterns to provide developers with ready to use, deployable contracts. + +== Core + +{{IERC20}} + +{{IERC20Metadata}} + +{{ERC20}} + +== Extensions + +{{ERC20Burnable}} + +{{ERC20Capped}} + +{{ERC20Pausable}} + +{{ERC20Permit}} + +{{ERC20Snapshot}} + +{{ERC20Votes}} + +{{ERC20VotesComp}} + +{{ERC20Wrapper}} + +{{ERC20FlashMint}} + +{{ERC4626}} + +== 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. + +{{ERC20PresetMinterPauser}} + +{{ERC20PresetFixedSupply}} + +== Utilities + +{{SafeERC20}} + +{{TokenTimelock}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Burnable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Burnable.sol new file mode 100644 index 0000000..1cd08ee --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../../../utils/Context.sol"; + +/** + * @dev Extension of {ERC20} that allows token holders to destroy both their own + * tokens and those that they have an allowance for, in a way that can be + * recognized off-chain (via event analysis). + */ +abstract contract ERC20Burnable is Context, ERC20 { + /** + * @dev Destroys `amount` tokens from the caller. + * + * See {ERC20-_burn}. + */ + function burn(uint256 amount) public virtual { + _burn(_msgSender(), amount); + } + + /** + * @dev Destroys `amount` tokens from `account`, deducting from the caller's + * allowance. + * + * See {ERC20-_burn} and {ERC20-allowance}. + * + * Requirements: + * + * - the caller must have allowance for ``accounts``'s tokens of at least + * `amount`. + */ + function burnFrom(address account, uint256 amount) public virtual { + _spendAllowance(account, _msgSender(), amount); + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Capped.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Capped.sol new file mode 100644 index 0000000..16f830d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Capped.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Capped.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; + +/** + * @dev Extension of {ERC20} that adds a cap to the supply of tokens. + */ +abstract contract ERC20Capped is ERC20 { + uint256 private immutable _cap; + + /** + * @dev Sets the value of the `cap`. This value is immutable, it can only be + * set once during construction. + */ + constructor(uint256 cap_) { + require(cap_ > 0, "ERC20Capped: cap is 0"); + _cap = cap_; + } + + /** + * @dev Returns the cap on the token's total supply. + */ + function cap() public view virtual returns (uint256) { + return _cap; + } + + /** + * @dev See {ERC20-_mint}. + */ + function _mint(address account, uint256 amount) internal virtual override { + require(ERC20.totalSupply() + amount <= cap(), "ERC20Capped: cap exceeded"); + super._mint(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20FlashMint.sol new file mode 100644 index 0000000..063fe99 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/extensions/ERC20FlashMint.sol) + +pragma solidity ^0.8.0; + +import "../../../interfaces/IERC3156FlashBorrower.sol"; +import "../../../interfaces/IERC3156FlashLender.sol"; +import "../ERC20.sol"; + +/** + * @dev Implementation of the ERC3156 Flash loans extension, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + * + * Adds the {flashLoan} method, which provides flash loan support at the token + * level. By default there is no fee, but this can be changed by overriding {flashFee}. + * + * _Available since v4.1._ + */ +abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { + bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + /** + * @dev Returns the maximum amount of tokens available for loan. + * @param token The address of the token that is requested. + * @return The amount of token that can be loaned. + */ + function maxFlashLoan(address token) public view virtual override returns (uint256) { + return token == address(this) ? type(uint256).max - ERC20.totalSupply() : 0; + } + + /** + * @dev Returns the fee applied when doing flash loans. This function calls + * the {_flashFee} function which returns the fee applied when doing flash + * loans. + * @param token The token to be flash loaned. + * @param amount The amount of tokens to be loaned. + * @return The fees applied to the corresponding flash loan. + */ + function flashFee(address token, uint256 amount) public view virtual override returns (uint256) { + require(token == address(this), "ERC20FlashMint: wrong token"); + return _flashFee(token, amount); + } + + /** + * @dev Returns the fee applied when doing flash loans. By default this + * implementation has 0 fees. This function can be overloaded to make + * the flash loan mechanism deflationary. + * @param token The token to be flash loaned. + * @param amount The amount of tokens to be loaned. + * @return The fees applied to the corresponding flash loan. + */ + function _flashFee(address token, uint256 amount) internal view virtual returns (uint256) { + // silence warning about unused variable without the addition of bytecode. + token; + amount; + return 0; + } + + /** + * @dev Returns the receiver address of the flash fee. By default this + * implementation returns the address(0) which means the fee amount will be burnt. + * This function can be overloaded to change the fee receiver. + * @return The address for which the flash fee will be sent to. + */ + function _flashFeeReceiver() internal view virtual returns (address) { + return address(0); + } + + /** + * @dev Performs a flash loan. New tokens are minted and sent to the + * `receiver`, who is required to implement the {IERC3156FlashBorrower} + * interface. By the end of the flash loan, the receiver is expected to own + * amount + fee tokens and have them approved back to the token contract itself so + * they can be burned. + * @param receiver The receiver of the flash loan. Should implement the + * {IERC3156FlashBorrower-onFlashLoan} interface. + * @param token The token to be flash loaned. Only `address(this)` is + * supported. + * @param amount The amount of tokens to be loaned. + * @param data An arbitrary datafield that is passed to the receiver. + * @return `true` if the flash loan was successful. + */ + // This function can reenter, but it doesn't pose a risk because it always preserves the property that the amount + // minted at the beginning is always recovered and burned at the end, or else the entire function will revert. + // slither-disable-next-line reentrancy-no-eth + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 amount, + bytes calldata data + ) public virtual override returns (bool) { + require(amount <= maxFlashLoan(token), "ERC20FlashMint: amount exceeds maxFlashLoan"); + uint256 fee = flashFee(token, amount); + _mint(address(receiver), amount); + require( + receiver.onFlashLoan(msg.sender, token, amount, fee, data) == _RETURN_VALUE, + "ERC20FlashMint: invalid return value" + ); + address flashFeeReceiver = _flashFeeReceiver(); + _spendAllowance(address(receiver), address(this), amount + fee); + if (fee == 0 || flashFeeReceiver == address(0)) { + _burn(address(receiver), amount + fee); + } else { + _burn(address(receiver), amount); + _transfer(address(receiver), flashFeeReceiver, fee); + } + return true; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Pausable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Pausable.sol new file mode 100644 index 0000000..3b2b632 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Pausable.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../../../security/Pausable.sol"; + +/** + * @dev ERC20 token with pausable token transfers, minting and burning. + * + * 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 { + /** + * @dev See {ERC20-_beforeTokenTransfer}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { + super._beforeTokenTransfer(from, to, amount); + + require(!paused(), "ERC20Pausable: token transfer while paused"); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Permit.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Permit.sol new file mode 100644 index 0000000..7ee7331 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Permit.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Permit.sol) + +pragma solidity ^0.8.0; + +import "./IERC20Permit.sol"; +import "../ERC20.sol"; +import "../../../utils/cryptography/ECDSA.sol"; +import "../../../utils/cryptography/EIP712.sol"; +import "../../../utils/Counters.sol"; + +/** + * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + * + * _Available since v3.4._ + */ +abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 { + using Counters for Counters.Counter; + + mapping(address => Counters.Counter) private _nonces; + + // solhint-disable-next-line var-name-mixedcase + bytes32 private constant _PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + /** + * @dev In previous versions `_PERMIT_TYPEHASH` was declared as `immutable`. + * However, to ensure consistency with the upgradeable transpiler, we will continue + * to reserve a slot. + * @custom:oz-renamed-from _PERMIT_TYPEHASH + */ + // solhint-disable-next-line var-name-mixedcase + bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT; + + /** + * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. + * + * It's a good idea to use the same `name` that is defined as the ERC20 token name. + */ + constructor(string memory name) EIP712(name, "1") {} + + /** + * @dev See {IERC20Permit-permit}. + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual override { + require(block.timestamp <= deadline, "ERC20Permit: expired deadline"); + + bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); + + bytes32 hash = _hashTypedDataV4(structHash); + + address signer = ECDSA.recover(hash, v, r, s); + require(signer == owner, "ERC20Permit: invalid signature"); + + _approve(owner, spender, value); + } + + /** + * @dev See {IERC20Permit-nonces}. + */ + function nonces(address owner) public view virtual override returns (uint256) { + return _nonces[owner].current(); + } + + /** + * @dev See {IERC20Permit-DOMAIN_SEPARATOR}. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view override returns (bytes32) { + return _domainSeparatorV4(); + } + + /** + * @dev "Consume a nonce": return the current value and increment. + * + * _Available since v4.1._ + */ + function _useNonce(address owner) internal virtual returns (uint256 current) { + Counters.Counter storage nonce = _nonces[owner]; + current = nonce.current(); + nonce.increment(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Snapshot.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Snapshot.sol new file mode 100644 index 0000000..504e7a9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Snapshot.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Snapshot.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../../../utils/Arrays.sol"; +import "../../../utils/Counters.sol"; + +/** + * @dev This contract extends an ERC20 token with a snapshot mechanism. When a snapshot is created, the balances and + * total supply at the time are recorded for later access. + * + * This can be used to safely create mechanisms based on token balances such as trustless dividends or weighted voting. + * In naive implementations it's possible to perform a "double spend" attack by reusing the same balance from different + * accounts. By using snapshots to calculate dividends or voting power, those attacks no longer apply. It can also be + * used to create an efficient ERC20 forking mechanism. + * + * Snapshots are created by the internal {_snapshot} function, which will emit the {Snapshot} event and return a + * snapshot id. To get the total supply at the time of a snapshot, call the function {totalSupplyAt} with the snapshot + * id. To get the balance of an account at the time of a snapshot, call the {balanceOfAt} function with the snapshot id + * and the account address. + * + * NOTE: Snapshot policy can be customized by overriding the {_getCurrentSnapshotId} method. For example, having it + * return `block.number` will trigger the creation of snapshot at the beginning of each new block. When overriding this + * function, be careful about the monotonicity of its result. Non-monotonic snapshot ids will break the contract. + * + * Implementing snapshots for every block using this method will incur significant gas costs. For a gas-efficient + * alternative consider {ERC20Votes}. + * + * ==== Gas Costs + * + * Snapshots are efficient. Snapshot creation is _O(1)_. Retrieval of balances or total supply from a snapshot is _O(log + * n)_ in the number of snapshots that have been created, although _n_ for a specific account will generally be much + * smaller since identical balances in subsequent snapshots are stored as a single entry. + * + * There is a constant overhead for normal ERC20 transfers due to the additional snapshot bookkeeping. This overhead is + * only significant for the first transfer that immediately follows a snapshot for a particular account. Subsequent + * transfers will have normal cost until the next snapshot, and so on. + */ + +abstract contract ERC20Snapshot is ERC20 { + // Inspired by Jordi Baylina's MiniMeToken to record historical balances: + // https://github.com/Giveth/minime/blob/ea04d950eea153a04c51fa510b068b9dded390cb/contracts/MiniMeToken.sol + + using Arrays for uint256[]; + using Counters for Counters.Counter; + + // Snapshotted values have arrays of ids and the value corresponding to that id. These could be an array of a + // Snapshot struct, but that would impede usage of functions that work on an array. + struct Snapshots { + uint256[] ids; + uint256[] values; + } + + mapping(address => Snapshots) private _accountBalanceSnapshots; + Snapshots private _totalSupplySnapshots; + + // Snapshot ids increase monotonically, with the first value being 1. An id of 0 is invalid. + Counters.Counter private _currentSnapshotId; + + /** + * @dev Emitted by {_snapshot} when a snapshot identified by `id` is created. + */ + event Snapshot(uint256 id); + + /** + * @dev Creates a new snapshot and returns its snapshot id. + * + * Emits a {Snapshot} event that contains the same id. + * + * {_snapshot} is `internal` and you have to decide how to expose it externally. Its usage may be restricted to a + * set of accounts, for example using {AccessControl}, or it may be open to the public. + * + * [WARNING] + * ==== + * While an open way of calling {_snapshot} is required for certain trust minimization mechanisms such as forking, + * you must consider that it can potentially be used by attackers in two ways. + * + * First, it can be used to increase the cost of retrieval of values from snapshots, although it will grow + * logarithmically thus rendering this attack ineffective in the long term. Second, it can be used to target + * specific accounts and increase the cost of ERC20 transfers for them, in the ways specified in the Gas Costs + * section above. + * + * We haven't measured the actual numbers; if this is something you're interested in please reach out to us. + * ==== + */ + function _snapshot() internal virtual returns (uint256) { + _currentSnapshotId.increment(); + + uint256 currentId = _getCurrentSnapshotId(); + emit Snapshot(currentId); + return currentId; + } + + /** + * @dev Get the current snapshotId + */ + function _getCurrentSnapshotId() internal view virtual returns (uint256) { + return _currentSnapshotId.current(); + } + + /** + * @dev Retrieves the balance of `account` at the time `snapshotId` was created. + */ + function balanceOfAt(address account, uint256 snapshotId) public view virtual returns (uint256) { + (bool snapshotted, uint256 value) = _valueAt(snapshotId, _accountBalanceSnapshots[account]); + + return snapshotted ? value : balanceOf(account); + } + + /** + * @dev Retrieves the total supply at the time `snapshotId` was created. + */ + function totalSupplyAt(uint256 snapshotId) public view virtual returns (uint256) { + (bool snapshotted, uint256 value) = _valueAt(snapshotId, _totalSupplySnapshots); + + return snapshotted ? value : totalSupply(); + } + + // Update balance and/or total supply snapshots before the values are modified. This is implemented + // in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations. + function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual override { + super._beforeTokenTransfer(from, to, amount); + + if (from == address(0)) { + // mint + _updateAccountSnapshot(to); + _updateTotalSupplySnapshot(); + } else if (to == address(0)) { + // burn + _updateAccountSnapshot(from); + _updateTotalSupplySnapshot(); + } else { + // transfer + _updateAccountSnapshot(from); + _updateAccountSnapshot(to); + } + } + + function _valueAt(uint256 snapshotId, Snapshots storage snapshots) private view returns (bool, uint256) { + require(snapshotId > 0, "ERC20Snapshot: id is 0"); + require(snapshotId <= _getCurrentSnapshotId(), "ERC20Snapshot: nonexistent id"); + + // When a valid snapshot is queried, there are three possibilities: + // a) The queried value was not modified after the snapshot was taken. Therefore, a snapshot entry was never + // created for this id, and all stored snapshot ids are smaller than the requested one. The value that corresponds + // to this id is the current one. + // b) The queried value was modified after the snapshot was taken. Therefore, there will be an entry with the + // requested id, and its value is the one to return. + // c) More snapshots were created after the requested one, and the queried value was later modified. There will be + // no entry for the requested id: the value that corresponds to it is that of the smallest snapshot id that is + // larger than the requested one. + // + // In summary, we need to find an element in an array, returning the index of the smallest value that is larger if + // it is not found, unless said value doesn't exist (e.g. when all values are smaller). Arrays.findUpperBound does + // exactly this. + + uint256 index = snapshots.ids.findUpperBound(snapshotId); + + if (index == snapshots.ids.length) { + return (false, 0); + } else { + return (true, snapshots.values[index]); + } + } + + function _updateAccountSnapshot(address account) private { + _updateSnapshot(_accountBalanceSnapshots[account], balanceOf(account)); + } + + function _updateTotalSupplySnapshot() private { + _updateSnapshot(_totalSupplySnapshots, totalSupply()); + } + + function _updateSnapshot(Snapshots storage snapshots, uint256 currentValue) private { + uint256 currentId = _getCurrentSnapshotId(); + if (_lastSnapshotId(snapshots.ids) < currentId) { + snapshots.ids.push(currentId); + snapshots.values.push(currentValue); + } + } + + function _lastSnapshotId(uint256[] storage ids) private view returns (uint256) { + if (ids.length == 0) { + return 0; + } else { + return ids[ids.length - 1]; + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Votes.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Votes.sol new file mode 100644 index 0000000..8b31fda --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Votes.sol) + +pragma solidity ^0.8.0; + +import "./ERC20Permit.sol"; +import "../../../interfaces/IERC5805.sol"; +import "../../../utils/math/Math.sol"; +import "../../../utils/math/SafeCast.sol"; +import "../../../utils/cryptography/ECDSA.sol"; + +/** + * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's, + * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1. + * + * NOTE: If exact COMP compatibility is required, use the {ERC20VotesComp} variant of this module. + * + * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either + * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting + * power can be queried through the public accessors {getVotes} and {getPastVotes}. + * + * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it + * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. + * + * _Available since v4.2._ + */ +abstract contract ERC20Votes is ERC20Permit, IERC5805 { + 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 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, "ERC20Votes: broken clock mode"); + return "mode=blocknumber&from=default"; + } + + /** + * @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 `timepoint`. + * + * Requirements: + * + * - `timepoint` must be in the past + */ + 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 `timepoint`. Note, this value is the sum of all balances. + * It is NOT the sum of all the delegated votes! + * + * Requirements: + * + * - `timepoint` must be in the past + */ + 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 timepoint) private view returns (uint256) { + // 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). + // 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 `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 `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; + + uint256 low = 0; + uint256 high = length; + + if (length > 5) { + uint256 mid = length - Math.sqrt(length); + if (_unsafeAccess(ckpts, mid).fromBlock > timepoint) { + high = mid; + } else { + low = mid + 1; + } + } + + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(ckpts, mid).fromBlock > timepoint) { + 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 == clock()) { + _unsafeAccess(ckpts, pos - 1).votes = SafeCast.toUint224(newWeight); + } else { + ckpts.push(Checkpoint({fromBlock: SafeCast.toUint32(clock()), 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/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20VotesComp.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20VotesComp.sol new file mode 100644 index 0000000..0461310 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20VotesComp.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20VotesComp.sol) + +pragma solidity ^0.8.0; + +import "./ERC20Votes.sol"; + +/** + * @dev Extension of ERC20 to support Compound's voting and delegation. This version exactly matches Compound's + * interface, with the drawback of only supporting supply up to (2^96^ - 1). + * + * NOTE: You should use this contract if you need exact compatibility with COMP (for example in order to use your token + * with Governor Alpha or Bravo) and if you are sure the supply cap of 2^96^ is enough for you. Otherwise, use the + * {ERC20Votes} variant of this module. + * + * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either + * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting + * power can be queried through the public accessors {getCurrentVotes} and {getPriorVotes}. + * + * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it + * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. + * + * _Available since v4.2._ + */ +abstract contract ERC20VotesComp is ERC20Votes { + /** + * @dev Comp version of the {getVotes} accessor, with `uint96` return type. + */ + function getCurrentVotes(address account) external view virtual returns (uint96) { + return SafeCast.toUint96(getVotes(account)); + } + + /** + * @dev Comp version of the {getPastVotes} accessor, with `uint96` return type. + */ + function getPriorVotes(address account, uint256 blockNumber) external view virtual returns (uint96) { + return SafeCast.toUint96(getPastVotes(account, blockNumber)); + } + + /** + * @dev Maximum token supply. Reduced to `type(uint96).max` (2^96^ - 1) to fit COMP interface. + */ + function _maxSupply() internal view virtual override returns (uint224) { + return type(uint96).max; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Wrapper.sol new file mode 100644 index 0000000..bc85a0b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC20Wrapper.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../utils/SafeERC20.sol"; + +/** + * @dev Extension of the ERC20 token contract to support token wrapping. + * + * Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful + * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC20Votes} will allow the + * wrapping of an existing "basic" ERC20 into a governance token. + * + * _Available since v4.2._ + */ +abstract contract ERC20Wrapper is ERC20 { + IERC20 private immutable _underlying; + + constructor(IERC20 underlyingToken) { + require(underlyingToken != this, "ERC20Wrapper: cannot self wrap"); + _underlying = underlyingToken; + } + + /** + * @dev See {ERC20-decimals}. + */ + function decimals() public view virtual override returns (uint8) { + 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) { + address sender = _msgSender(); + require(sender != address(this), "ERC20Wrapper: wrapper can't deposit"); + SafeERC20.safeTransferFrom(_underlying, sender, address(this), amount); + _mint(account, amount); + return true; + } + + /** + * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens. + */ + function withdrawTo(address account, uint256 amount) public virtual returns (bool) { + _burn(_msgSender(), amount); + SafeERC20.safeTransfer(_underlying, account, amount); + return true; + } + + /** + * @dev Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake. Internal + * 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(); + _mint(account, value); + return value; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC4626.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC4626.sol new file mode 100644 index 0000000..4f6a2d6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC4626.sol @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/ERC4626.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../utils/SafeERC20.sol"; +import "../../../interfaces/IERC4626.sol"; +import "../../../utils/math/Math.sol"; + +/** + * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in + * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626]. + * + * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for + * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends + * 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] + * ==== + * 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 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 _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_); + _underlyingDecimals = success ? assetDecimals : 18; + _asset = asset_; + } + + /** + * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way. + */ + function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool, uint8) { + (bool success, bytes memory encodedDecimals) = address(asset_).staticcall( + abi.encodeWithSelector(IERC20Metadata.decimals.selector) + ); + if (success && encodedDecimals.length >= 32) { + uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256)); + if (returnedDecimals <= type(uint8).max) { + return (true, uint8(returnedDecimals)); + } + } + return (false, 0); + } + + /** + * @dev Decimals are 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) { + return _underlyingDecimals + _decimalsOffset(); + } + + /** @dev See {IERC4626-asset}. */ + function asset() public view virtual override returns (address) { + return address(_asset); + } + + /** @dev See {IERC4626-totalAssets}. */ + function totalAssets() public view virtual override returns (uint256) { + return _asset.balanceOf(address(this)); + } + + /** @dev See {IERC4626-convertToShares}. */ + function convertToShares(uint256 assets) public view virtual override returns (uint256) { + return _convertToShares(assets, Math.Rounding.Down); + } + + /** @dev See {IERC4626-convertToAssets}. */ + function convertToAssets(uint256 shares) public view virtual override returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Down); + } + + /** @dev See {IERC4626-maxDeposit}. */ + function maxDeposit(address) public view virtual override returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4626-maxMint}. */ + function maxMint(address) public view virtual override returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4626-maxWithdraw}. */ + function maxWithdraw(address owner) public view virtual override returns (uint256) { + return _convertToAssets(balanceOf(owner), Math.Rounding.Down); + } + + /** @dev See {IERC4626-maxRedeem}. */ + function maxRedeem(address owner) public view virtual override returns (uint256) { + return balanceOf(owner); + } + + /** @dev See {IERC4626-previewDeposit}. */ + function previewDeposit(uint256 assets) public view virtual override returns (uint256) { + return _convertToShares(assets, Math.Rounding.Down); + } + + /** @dev See {IERC4626-previewMint}. */ + function previewMint(uint256 shares) public view virtual override returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Up); + } + + /** @dev See {IERC4626-previewWithdraw}. */ + function previewWithdraw(uint256 assets) public view virtual override returns (uint256) { + return _convertToShares(assets, Math.Rounding.Up); + } + + /** @dev See {IERC4626-previewRedeem}. */ + function previewRedeem(uint256 shares) public view virtual override returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Down); + } + + /** @dev See {IERC4626-deposit}. */ + function deposit(uint256 assets, address receiver) public virtual override returns (uint256) { + require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max"); + + uint256 shares = previewDeposit(assets); + _deposit(_msgSender(), receiver, assets, shares); + + return shares; + } + + /** @dev See {IERC4626-mint}. + * + * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero. + * In this case, the shares will be minted without requiring any assets to be deposited. + */ + function mint(uint256 shares, address receiver) public virtual override returns (uint256) { + require(shares <= maxMint(receiver), "ERC4626: mint more than max"); + + uint256 assets = previewMint(shares); + _deposit(_msgSender(), receiver, assets, shares); + + return assets; + } + + /** @dev See {IERC4626-withdraw}. */ + function withdraw(uint256 assets, address receiver, address owner) public virtual override returns (uint256) { + require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max"); + + uint256 shares = previewWithdraw(assets); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return shares; + } + + /** @dev See {IERC4626-redeem}. */ + function redeem(uint256 shares, address receiver, address owner) public virtual override returns (uint256) { + require(shares <= maxRedeem(owner), "ERC4626: redeem more than max"); + + uint256 assets = previewRedeem(shares); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return assets; + } + + /** + * @dev Internal conversion function (from assets to shares) with support for rounding direction. + */ + function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) { + 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) { + return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding); + } + + /** + * @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 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. + // + // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the + // assets are transferred and before the shares are minted, which is a valid state. + // slither-disable-next-line reentrancy-no-eth + SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); + _mint(receiver, shares); + + emit Deposit(caller, receiver, assets, shares); + } + + /** + * @dev Withdraw/redeem common workflow. + */ + function _withdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) internal virtual { + if (caller != owner) { + _spendAllowance(owner, caller, shares); + } + + // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the + // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, + // calls the vault, which is assumed not malicious. + // + // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the + // shares are burned and after the assets are transferred, which is a valid state. + _burn(owner, shares); + SafeERC20.safeTransfer(_asset, receiver, assets); + + emit Withdraw(caller, receiver, owner, assets, shares); + } + + function _decimalsOffset() internal view virtual returns (uint8) { + return 0; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/IERC20Metadata.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/IERC20Metadata.sol new file mode 100644 index 0000000..83ba6ac --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/IERC20Metadata.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) + +pragma solidity ^0.8.0; + +import "../IERC20.sol"; + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + * + * _Available since v4.1._ + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/IERC20Permit.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/IERC20Permit.sol new file mode 100644 index 0000000..0deb54b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/IERC20Permit.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + */ +interface IERC20Permit { + /** + * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, + * given ``owner``'s signed approval. + * + * IMPORTANT: The same issues {IERC20-approve} has related to transaction + * ordering also apply here. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `deadline` must be a timestamp in the future. + * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` + * over the EIP712-formatted function arguments. + * - the signature must use ``owner``'s current nonce (see {nonces}). + * + * For more information on the signature format, see the + * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP + * section]. + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @dev Returns the current nonce for `owner`. This value must be + * included whenever a signature is generated for {permit}. + * + * Every successful call to {permit} increases ``owner``'s nonce by one. This + * prevents a signature from being used multiple times. + */ + function nonces(address owner) external view returns (uint256); + + /** + * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/draft-ERC20Permit.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/draft-ERC20Permit.sol new file mode 100644 index 0000000..55b38b2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/draft-ERC20Permit.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-ERC20Permit.sol) + +pragma solidity ^0.8.0; + +// EIP-2612 is Final as of 2022-11-01. This file is deprecated. + +import "./ERC20Permit.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/draft-IERC20Permit.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/draft-IERC20Permit.sol new file mode 100644 index 0000000..ff6ede3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/draft-IERC20Permit.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/draft-IERC20Permit.sol) + +pragma solidity ^0.8.0; + +// EIP-2612 is Final as of 2022-11-01. This file is deprecated. + +import "./IERC20Permit.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol new file mode 100644 index 0000000..d293999 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/presets/ERC20PresetFixedSupply.sol) +pragma solidity ^0.8.0; + +import "../extensions/ERC20Burnable.sol"; + +/** + * @dev {ERC20} token, including: + * + * - Preminted initial supply + * - Ability for holders to burn (destroy) their tokens + * - No access control mechanism (for minting/pausing) and hence no governance + * + * This contract uses {ERC20Burnable} to include burn capabilities - head to + * its documentation for details. + * + * _Available since v3.4._ + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC20PresetFixedSupply is ERC20Burnable { + /** + * @dev Mints `initialSupply` amount of token and transfers them to `owner`. + * + * See {ERC20-constructor}. + */ + constructor(string memory name, string memory symbol, uint256 initialSupply, address owner) ERC20(name, symbol) { + _mint(owner, initialSupply); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol new file mode 100644 index 0000000..e711a89 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/presets/ERC20PresetMinterPauser.sol) + +pragma solidity ^0.8.0; + +import "../ERC20.sol"; +import "../extensions/ERC20Burnable.sol"; +import "../extensions/ERC20Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; + +/** + * @dev {ERC20} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC20PresetMinterPauser is Context, AccessControlEnumerable, ERC20Burnable, ERC20Pausable { + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the + * account that deploys the contract. + * + * See {ERC20-constructor}. + */ + constructor(string memory name, string memory symbol) ERC20(name, symbol) { + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _setupRole(MINTER_ROLE, _msgSender()); + _setupRole(PAUSER_ROLE, _msgSender()); + } + + /** + * @dev Creates `amount` new tokens for `to`. + * + * See {ERC20-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to, uint256 amount) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have minter role to mint"); + _mint(to, amount); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC20Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC20PresetMinterPauser: must have pauser role to unpause"); + _unpause(); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 amount + ) internal virtual override(ERC20, ERC20Pausable) { + super._beforeTokenTransfer(from, to, amount); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/README.md b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/README.md new file mode 100644 index 0000000..468200b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/presets/README.md @@ -0,0 +1 @@ +Contract presets are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com/) as a more powerful alternative. diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/utils/SafeERC20.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/utils/SafeERC20.sol new file mode 100644 index 0000000..d4bcd98 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/utils/SafeERC20.sol @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol) + +pragma solidity ^0.8.0; + +import "../IERC20.sol"; +import "../extensions/IERC20Permit.sol"; +import "../../../utils/Address.sol"; + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +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)); + } + + /** + * @dev Deprecated. This function has issues similar to the ones found in + * {IERC20-approve}, and its usage is discouraged. + * + * Whenever possible, use {safeIncreaseAllowance} and + * {safeDecreaseAllowance} instead. + */ + function safeApprove(IERC20 token, address spender, uint256 value) internal { + // safeApprove should only be called when setting an initial allowance, + // or when resetting it to zero. To increase and decrease it, use + // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' + require( + (value == 0) || (token.allowance(address(this), spender) == 0), + "SafeERC20: approve from non-zero to non-zero allowance" + ); + _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 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"); + _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. Meant to be used with tokens that require the approval + * to be set to zero before setting it to a non-zero value, such as USDT. + */ + 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, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) internal { + uint256 nonceBefore = token.nonces(owner); + token.permit(owner, spender, value, deadline, v, r, s); + uint256 nonceAfter = token.nonces(owner); + require(nonceAfter == nonceBefore + 1, "SafeERC20: permit 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). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that + // 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"); + 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/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/utils/TokenTimelock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/utils/TokenTimelock.sol new file mode 100644 index 0000000..cffdac5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/utils/TokenTimelock.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/TokenTimelock.sol) + +pragma solidity ^0.8.0; + +import "./SafeERC20.sol"; + +/** + * @dev A token holder contract that will allow a beneficiary to extract the + * tokens after a given release time. + * + * Useful for simple vesting schedules like "advisors get all of their tokens + * after 1 year". + */ +contract TokenTimelock { + using SafeERC20 for IERC20; + + // ERC20 basic token contract being held + IERC20 private immutable _token; + + // beneficiary of tokens after they are released + address private immutable _beneficiary; + + // timestamp when token release is enabled + uint256 private immutable _releaseTime; + + /** + * @dev Deploys a timelock instance that is able to hold the token specified, and will only release it to + * `beneficiary_` when {release} is invoked after `releaseTime_`. The release time is specified as a Unix timestamp + * (in seconds). + */ + constructor(IERC20 token_, address beneficiary_, uint256 releaseTime_) { + require(releaseTime_ > block.timestamp, "TokenTimelock: release time is before current time"); + _token = token_; + _beneficiary = beneficiary_; + _releaseTime = releaseTime_; + } + + /** + * @dev Returns the token being held. + */ + function token() public view virtual returns (IERC20) { + return _token; + } + + /** + * @dev Returns the beneficiary that will receive the tokens. + */ + function beneficiary() public view virtual returns (address) { + return _beneficiary; + } + + /** + * @dev Returns the time when the tokens are released in seconds since Unix epoch (i.e. Unix timestamp). + */ + function releaseTime() public view virtual returns (uint256) { + return _releaseTime; + } + + /** + * @dev Transfers tokens held by the timelock to the beneficiary. Will only succeed if invoked after the release + * time. + */ + function release() public virtual { + require(block.timestamp >= releaseTime(), "TokenTimelock: current time is before release time"); + + uint256 amount = token().balanceOf(address(this)); + require(amount > 0, "TokenTimelock: no tokens to release"); + + token().safeTransfer(beneficiary(), amount); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/ERC721.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/ERC721.sol new file mode 100644 index 0000000..7942e6f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/ERC721.sol @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/ERC721.sol) + +pragma solidity ^0.8.0; + +import "./IERC721.sol"; +import "./IERC721Receiver.sol"; +import "./extensions/IERC721Metadata.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/Strings.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +contract ERC721 is Context, ERC165, IERC721, IERC721Metadata { + using Address for address; + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + // Mapping from token ID to owner address + mapping(uint256 => address) private _owners; + + // Mapping owner address to token count + mapping(address => uint256) private _balances; + + // Mapping from token ID to approved address + mapping(uint256 => address) private _tokenApprovals; + + // Mapping from owner to operator approvals + mapping(address => mapping(address => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual override returns (uint256) { + require(owner != address(0), "ERC721: address zero is not a valid owner"); + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual override returns (address) { + address owner = _ownerOf(tokenId); + require(owner != address(0), "ERC721: invalid token ID"); + return owner; + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + _requireMinted(tokenId); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : ""; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual override { + address owner = ERC721.ownerOf(tokenId); + require(to != owner, "ERC721: approval to current owner"); + + require( + _msgSender() == owner || isApprovedForAll(owner, _msgSender()), + "ERC721: approve caller is not token owner or approved for all" + ); + + _approve(to, tokenId); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual override returns (address) { + _requireMinted(tokenId); + + return _tokenApprovals[tokenId]; + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual override { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual override { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); + + _transfer(from, to, tokenId); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override { + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); + _safeTransfer(from, to, tokenId, data); + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * `data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { + _transfer(from, to, tokenId); + require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer"); + } + + /** + * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + */ + function _ownerOf(uint256 tokenId) internal view virtual returns (address) { + return _owners[tokenId]; + } + + /** + * @dev Returns whether `tokenId` exists. + * + * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. + * + * Tokens start existing when they are minted (`_mint`), + * and stop existing when they are burned (`_burn`). + */ + function _exists(uint256 tokenId) internal view virtual returns (bool) { + return _ownerOf(tokenId) != address(0); + } + + /** + * @dev Returns whether `spender` is allowed to manage `tokenId`. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { + address owner = ERC721.ownerOf(tokenId); + return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender); + } + + /** + * @dev Safely mints `tokenId` and transfers it to `to`. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal virtual { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { + _mint(to, tokenId); + require( + _checkOnERC721Received(address(0), to, tokenId, data), + "ERC721: transfer to non ERC721Receiver implementer" + ); + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal virtual { + require(to != address(0), "ERC721: mint to the zero address"); + require(!_exists(tokenId), "ERC721: token already minted"); + + _beforeTokenTransfer(address(0), to, tokenId, 1); + + // Check that tokenId was not minted by `_beforeTokenTransfer` hook + require(!_exists(tokenId), "ERC721: token already minted"); + + unchecked { + // Will not overflow unless all 2**256 token ids are minted to the same owner. + // Given that tokens are minted one by one, it is impossible in practice that + // this ever happens. Might change if we allow batch minting. + // The ERC fails to describe this case. + _balances[to] += 1; + } + + _owners[tokenId] = to; + + emit Transfer(address(0), to, tokenId); + + _afterTokenTransfer(address(0), to, tokenId, 1); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This is an internal function that does not check if the sender is authorized to operate on the token. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal virtual { + address owner = ERC721.ownerOf(tokenId); + + _beforeTokenTransfer(owner, address(0), tokenId, 1); + + // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook + owner = ERC721.ownerOf(tokenId); + + // Clear approvals + delete _tokenApprovals[tokenId]; + + unchecked { + // Cannot overflow, as that would require more tokens to be burned/transferred + // out than the owner initially received through minting and transferring in. + _balances[owner] -= 1; + } + delete _owners[tokenId]; + + emit Transfer(owner, address(0), tokenId); + + _afterTokenTransfer(owner, address(0), tokenId, 1); + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal virtual { + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); + require(to != address(0), "ERC721: transfer to the zero address"); + + _beforeTokenTransfer(from, to, tokenId, 1); + + // Check that tokenId was not transferred by `_beforeTokenTransfer` hook + require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); + + // Clear approvals from the previous owner + delete _tokenApprovals[tokenId]; + + unchecked { + // `_balances[from]` cannot overflow for the same reason as described in `_burn`: + // `from`'s balance is the number of token held, which is at least one before the current + // transfer. + // `_balances[to]` could overflow in the conditions described in `_mint`. That would require + // all 2**256 token ids to be minted, which in practice is impossible. + _balances[from] -= 1; + _balances[to] += 1; + } + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + + _afterTokenTransfer(from, to, tokenId, 1); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * Emits an {Approval} event. + */ + function _approve(address to, uint256 tokenId) internal virtual { + _tokenApprovals[tokenId] = to; + emit Approval(ERC721.ownerOf(tokenId), to, tokenId); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + require(owner != operator, "ERC721: approve to caller"); + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Reverts if the `tokenId` has not been minted yet. + */ + function _requireMinted(uint256 tokenId) internal view virtual { + require(_exists(tokenId), "ERC721: invalid token ID"); + } + + /** + * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address. + * The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param data bytes optional data to send along with the call + * @return bool whether the call correctly returned the expected magic value + */ + function _checkOnERC721Received( + address from, + address to, + uint256 tokenId, + bytes memory data + ) private returns (bool) { + if (to.isContract()) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { + return retval == IERC721Receiver.onERC721Received.selector; + } catch (bytes memory reason) { + if (reason.length == 0) { + revert("ERC721: transfer to non ERC721Receiver implementer"); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } else { + return true; + } + } + + /** + * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is + * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`. + * - When `from` is zero, the tokens will be minted for `to`. + * - When `to` is zero, ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * - `batchSize` is non-zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {} + + /** + * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is + * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1. + * + * Calling conditions: + * + * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`. + * - When `from` is zero, the tokens were minted for `to`. + * - When `to` is zero, ``from``'s tokens were burned. + * - `from` and `to` are never both zero. + * - `batchSize` is non-zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _afterTokenTransfer(address from, address to, uint256 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/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/IERC721.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/IERC721.sol new file mode 100644 index 0000000..293f566 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/IERC721.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the caller. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/IERC721Receiver.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/IERC721Receiver.sol new file mode 100644 index 0000000..de67209 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/IERC721Receiver.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) + +pragma solidity ^0.8.0; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/README.adoc new file mode 100644 index 0000000..f571f5c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/README.adoc @@ -0,0 +1,73 @@ += ERC 721 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc721 + +This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-721[ERC721 Non-Fungible Token Standard]. + +TIP: For a walk through on how to create an ERC721 token read our xref:ROOT:erc721.adoc[ERC721 guide]. + +The EIP specifies four interfaces: + +* {IERC721}: Core functionality required in all compliant implementation. +* {IERC721Metadata}: Optional extension that adds name, symbol, and token URI, almost always included. +* {IERC721Enumerable}: Optional extension that allows enumerating the tokens on chain, often not included since it requires large gas overhead. +* {IERC721Receiver}: An interface that must be implemented by contracts if they want to accept tokens through `safeTransferFrom`. + +OpenZeppelin Contracts provides implementations of all four interfaces: + +* {ERC721}: The core and metadata extensions, with a base URI mechanism. +* {ERC721Enumerable}: The enumerable extension. +* {ERC721Holder}: A bare bones implementation of the receiver interface. + +Additionally there are a few of other extensions: + +* {ERC721Consecutive}: An implementation of https://eips.ethereum.org/EIPS/eip-2309[ERC2309] for minting batchs of tokens during construction, in accordance with ERC721. +* {ERC721URIStorage}: A more flexible but more expensive way of storing metadata. +* {ERC721Votes}: Support for voting and vote delegation. +* {ERC721Royalty}: A way to signal royalty information following ERC2981. +* {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. + +== Core + +{{IERC721}} + +{{IERC721Metadata}} + +{{IERC721Enumerable}} + +{{ERC721}} + +{{ERC721Enumerable}} + +{{IERC721Receiver}} + +== Extensions + +{{ERC721Pausable}} + +{{ERC721Burnable}} + +{{ERC721Consecutive}} + +{{ERC721URIStorage}} + +{{ERC721Votes}} + +{{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. + +{{ERC721PresetMinterPauserAutoId}} + +== Utilities + +{{ERC721Holder}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Burnable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Burnable.sol new file mode 100644 index 0000000..0dc7dae --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Burnable.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Burnable.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../utils/Context.sol"; + +/** + * @title ERC721 Burnable Token + * @dev ERC721 Token that can be burned (destroyed). + */ +abstract contract ERC721Burnable is Context, ERC721 { + /** + * @dev Burns `tokenId`. See {ERC721-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) public virtual { + //solhint-disable-next-line max-line-length + require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved"); + _burn(tokenId); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Consecutive.sol new file mode 100644 index 0000000..4312d98 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/extensions/ERC721Consecutive.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../interfaces/IERC2309.sol"; +import "../../../utils/Checkpoints.sol"; +import "../../../utils/structs/BitMaps.sol"; + +/** + * @dev Implementation of the ERC2309 "Consecutive Transfer Extension" as defined in + * https://eips.ethereum.org/EIPS/eip-2309[EIP-2309]. + * + * This extension allows the minting of large batches of tokens, during contract construction only. For upgradeable + * contracts this implies that batch minting is only available during proxy deployment, and not in subsequent upgrades. + * These batches are limited to 5000 tokens at a time by default to accommodate off-chain indexers. + * + * Using this extension removes the ability to mint single tokens during contract construction. This ability is + * regained after construction. During construction, only batch minting is allowed. + * + * IMPORTANT: This extension bypasses the hooks {_beforeTokenTransfer} and {_afterTokenTransfer} for tokens minted in + * batch. When using this extension, you should consider the {_beforeConsecutiveTokenTransfer} and + * {_afterConsecutiveTokenTransfer} hooks in addition to {_beforeTokenTransfer} and {_afterTokenTransfer}. + * + * IMPORTANT: When overriding {_afterTokenTransfer}, be careful about call ordering. {ownerOf} may return invalid + * values during the {_afterTokenTransfer} execution if the super call is not called first. To be safe, execute the + * super call before your custom logic. + * + * _Available since v4.8._ + */ +abstract contract ERC721Consecutive is IERC2309, ERC721 { + using BitMaps for BitMaps.BitMap; + using Checkpoints for Checkpoints.Trace160; + + Checkpoints.Trace160 private _sequentialOwnership; + BitMaps.BitMap private _sequentialBurn; + + /** + * @dev Maximum size of a batch of consecutive tokens. This is designed to limit stress on off-chain indexing + * services that have to record one entry per token, and have protections against "unreasonably large" batches of + * tokens. + * + * NOTE: Overriding the default value of 5000 will not cause on-chain issues, but may result in the asset not being + * correctly supported by off-chain indexing services (including marketplaces). + */ + function _maxBatchSize() internal view virtual returns (uint96) { + return 5000; + } + + /** + * @dev See {ERC721-_ownerOf}. Override that checks the sequential ownership structure for tokens that have + * been minted as part of a batch, and not yet transferred. + */ + function _ownerOf(uint256 tokenId) internal view virtual override returns (address) { + address owner = super._ownerOf(tokenId); + + // If token is owned by the core, or beyond consecutive range, return base value + if (owner != address(0) || tokenId > type(uint96).max) { + return owner; + } + + // Otherwise, check the token was not burned, and fetch ownership from the anchors + // Note: no need for safe cast, we know that tokenId <= type(uint96).max + return _sequentialBurn.get(tokenId) ? address(0) : address(_sequentialOwnership.lowerLookup(uint96(tokenId))); + } + + /** + * @dev Mint a batch of tokens of length `batchSize` for `to`. Returns the token id of the first token minted in the + * batch; if `batchSize` is 0, returns the number of consecutive ids minted so far. + * + * Requirements: + * + * - `batchSize` must not be greater than {_maxBatchSize}. + * - The function is called in the constructor of the contract (directly or indirectly). + * + * CAUTION: Does not emit a `Transfer` event. This is ERC721 compliant as long as it is done inside of the + * constructor, which is enforced by this function. + * + * CAUTION: Does not invoke `onERC721Received` on the receiver. + * + * Emits a {IERC2309-ConsecutiveTransfer} event. + */ + function _mintConsecutive(address to, uint96 batchSize) internal virtual returns (uint96) { + uint96 first = _totalConsecutiveSupply(); + + // minting a batch of size 0 is a no-op + if (batchSize > 0) { + require(!Address.isContract(address(this)), "ERC721Consecutive: batch minting restricted to constructor"); + require(to != address(0), "ERC721Consecutive: mint to the zero address"); + require(batchSize <= _maxBatchSize(), "ERC721Consecutive: batch too large"); + + // hook before + _beforeTokenTransfer(address(0), to, first, batchSize); + + // push an ownership checkpoint & emit event + uint96 last = first + batchSize - 1; + _sequentialOwnership.push(last, uint160(to)); + + // 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 + _afterTokenTransfer(address(0), to, first, batchSize); + } + + return first; + } + + /** + * @dev See {ERC721-_mint}. Override version that restricts normal minting to after construction. + * + * Warning: Using {ERC721Consecutive} prevents using {_mint} during construction in favor of {_mintConsecutive}. + * After construction, {_mintConsecutive} is no longer available and {_mint} becomes available. + */ + function _mint(address to, uint256 tokenId) internal virtual override { + require(Address.isContract(address(this)), "ERC721Consecutive: can't mint during construction"); + super._mint(to, tokenId); + } + + /** + * @dev See {ERC721-_afterTokenTransfer}. Burning of tokens that have been sequentially minted must be explicit. + */ + function _afterTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override { + if ( + to == address(0) && // if we burn + firstTokenId < _totalConsecutiveSupply() && // and the tokenId was minted in a batch + !_sequentialBurn.get(firstTokenId) // and the token was never marked as burnt + ) { + require(batchSize == 1, "ERC721Consecutive: batch burn not supported"); + _sequentialBurn.set(firstTokenId); + } + super._afterTokenTransfer(from, to, firstTokenId, batchSize); + } + + function _totalConsecutiveSupply() private view returns (uint96) { + (bool exists, uint96 latestId, ) = _sequentialOwnership.latestCheckpoint(); + return exists ? latestId + 1 : 0; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Enumerable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Enumerable.sol new file mode 100644 index 0000000..aab81a9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Enumerable.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Enumerable.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "./IERC721Enumerable.sol"; + +/** + * @dev This implements an optional extension of {ERC721} defined in the EIP that adds + * enumerability of all the token ids in the contract as well as all token ids owned by each + * account. + */ +abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { + // Mapping from owner to list of owned token IDs + mapping(address => mapping(uint256 => uint256)) private _ownedTokens; + + // Mapping from token ID to index of the owner tokens list + mapping(uint256 => uint256) private _ownedTokensIndex; + + // Array with all token ids, used for enumeration + uint256[] private _allTokens; + + // Mapping from token id to position in the allTokens array + mapping(uint256 => uint256) private _allTokensIndex; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual override returns (uint256) { + require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); + return _ownedTokens[owner][index]; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual override returns (uint256) { + return _allTokens.length; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual override returns (uint256) { + require(index < ERC721Enumerable.totalSupply(), "ERC721Enumerable: global index out of bounds"); + return _allTokens[index]; + } + + /** + * @dev See {ERC721-_beforeTokenTransfer}. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + + if (batchSize > 1) { + // Will only trigger during construction. Batch transferring (minting) is not available afterwards. + revert("ERC721Enumerable: consecutive transfers not supported"); + } + + uint256 tokenId = firstTokenId; + + if (from == address(0)) { + _addTokenToAllTokensEnumeration(tokenId); + } else if (from != to) { + _removeTokenFromOwnerEnumeration(from, tokenId); + } + if (to == address(0)) { + _removeTokenFromAllTokensEnumeration(tokenId); + } else if (to != from) { + _addTokenToOwnerEnumeration(to, tokenId); + } + } + + /** + * @dev Private function to add a token to this extension's ownership-tracking data structures. + * @param to address representing the new owner of the given token ID + * @param tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + uint256 length = ERC721.balanceOf(to); + _ownedTokens[to][length] = tokenId; + _ownedTokensIndex[tokenId] = length; + } + + /** + * @dev Private function to add a token to this extension's token tracking data structures. + * @param tokenId uint256 ID of the token to be added to the tokens list + */ + function _addTokenToAllTokensEnumeration(uint256 tokenId) private { + _allTokensIndex[tokenId] = _allTokens.length; + _allTokens.push(tokenId); + } + + /** + * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that + * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for + * gas optimizations e.g. when performing a transfer operation (avoiding double writes). + * This has O(1) time complexity, but alters the order of the _ownedTokens array. + * @param from address representing the previous owner of the given token ID + * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { + // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; + uint256 tokenIndex = _ownedTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + + _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + } + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[tokenId]; + delete _ownedTokens[from][lastTokenIndex]; + } + + /** + * @dev Private function to remove a token from this extension's token tracking data structures. + * This has O(1) time complexity, but alters the order of the _allTokens array. + * @param tokenId uint256 ID of the token to be removed from the tokens list + */ + function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { + // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = _allTokens.length - 1; + uint256 tokenIndex = _allTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so + // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding + // an 'if' statement (like in _removeTokenFromOwnerEnumeration) + uint256 lastTokenId = _allTokens[lastTokenIndex]; + + _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + + // This also deletes the contents at the last position of the array + delete _allTokensIndex[tokenId]; + _allTokens.pop(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Pausable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Pausable.sol new file mode 100644 index 0000000..e8eb4b1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.2) (token/ERC721/extensions/ERC721Pausable.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../security/Pausable.sol"; + +/** + * @dev ERC721 token with pausable token transfers, minting and burning. + * + * 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 { + /** + * @dev See {ERC721-_beforeTokenTransfer}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + + require(!paused(), "ERC721Pausable: token transfer while paused"); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Royalty.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Royalty.sol new file mode 100644 index 0000000..298e342 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Royalty.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/ERC721Royalty.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../common/ERC2981.sol"; +import "../../../utils/introspection/ERC165.sol"; + +/** + * @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment + * information. + * + * Royalty information can be specified globally for all token ids via {ERC2981-_setDefaultRoyalty}, and/or individually for + * specific token ids via {ERC2981-_setTokenRoyalty}. The latter takes precedence over the first. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + * + * _Available since v4.5._ + */ +abstract contract ERC721Royalty is ERC2981, ERC721 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) { + return super.supportsInterface(interfaceId); + } + + /** + * @dev See {ERC721-_burn}. This override additionally clears the royalty information for the token. + */ + function _burn(uint256 tokenId) internal virtual override { + super._burn(tokenId); + _resetTokenRoyalty(tokenId); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721URIStorage.sol new file mode 100644 index 0000000..c9d79b6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721URIStorage.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/extensions/ERC721URIStorage.sol) + +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 IERC4906, ERC721 { + using Strings for uint256; + + // 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}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + _requireMinted(tokenId); + + string memory _tokenURI = _tokenURIs[tokenId]; + string memory base = _baseURI(); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked). + if (bytes(_tokenURI).length > 0) { + return string(abi.encodePacked(base, _tokenURI)); + } + + return super.tokenURI(tokenId); + } + + /** + * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. + * + * Emits {MetadataUpdate}. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { + require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token"); + _tokenURIs[tokenId] = _tokenURI; + + emit MetadataUpdate(tokenId); + } + + /** + * @dev See {ERC721-_burn}. This override additionally checks to see if a + * token-specific URI was set for the token, and if so, it deletes the token URI from + * the storage mapping. + */ + function _burn(uint256 tokenId) internal virtual override { + super._burn(tokenId); + + if (bytes(_tokenURIs[tokenId]).length != 0) { + delete _tokenURIs[tokenId]; + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Votes.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Votes.sol new file mode 100644 index 0000000..55b82c1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Votes.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/extensions/ERC721Votes.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../../../governance/utils/Votes.sol"; + +/** + * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts + * as 1 vote unit. + * + * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost + * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of + * the votes in governance decisions, or they can delegate to themselves to be their own representative. + * + * _Available since v4.5._ + */ +abstract contract ERC721Votes is ERC721, Votes { + /** + * @dev See {ERC721-_afterTokenTransfer}. Adjusts votes when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _afterTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override { + _transferVotingUnits(from, to, batchSize); + super._afterTokenTransfer(from, to, firstTokenId, batchSize); + } + + /** + * @dev Returns the balance of `account`. + * + * 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/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Wrapper.sol new file mode 100644 index 0000000..c7ff06d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/extensions/ERC721Wrapper.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.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, IERC721Receiver { + IERC721 private immutable _underlying; + + 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) { + uint256 length = tokenIds.length; + for (uint256 i = 0; i < length; ++i) { + 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; + } + + /** + * @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 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 from, + uint256 tokenId, + bytes memory + ) public virtual override returns (bytes4) { + require(address(underlying()) == _msgSender(), "ERC721Wrapper: caller is not underlying"); + _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/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/IERC721Enumerable.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/IERC721Enumerable.sol new file mode 100644 index 0000000..dfea427 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/IERC721Enumerable.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC721/extensions/IERC721Enumerable.sol) + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/IERC721Metadata.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/IERC721Metadata.sol new file mode 100644 index 0000000..dca77ba --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/IERC721Metadata.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity ^0.8.0; + +import "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/draft-ERC721Votes.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/draft-ERC721Votes.sol new file mode 100644 index 0000000..c6aa7c5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/extensions/draft-ERC721Votes.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC721/extensions/draft-ERC721Votes.sol) + +pragma solidity ^0.8.0; + +// ERC721Votes was marked as draft due to the EIP-712 dependency. +// EIP-712 is Final as of 2022-08-11. This file is deprecated. + +import "./ERC721Votes.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol new file mode 100644 index 0000000..da53b88 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol) + +pragma solidity ^0.8.0; + +import "../ERC721.sol"; +import "../extensions/ERC721Enumerable.sol"; +import "../extensions/ERC721Burnable.sol"; +import "../extensions/ERC721Pausable.sol"; +import "../../../access/AccessControlEnumerable.sol"; +import "../../../utils/Context.sol"; +import "../../../utils/Counters.sol"; + +/** + * @dev {ERC721} token, including: + * + * - ability for holders to burn (destroy) their tokens + * - a minter role that allows for token minting (creation) + * - a pauser role that allows to stop all token transfers + * - token ID and URI autogeneration + * + * This contract uses {AccessControl} to lock permissioned functions using the + * different roles - head to its documentation for details. + * + * The account that deploys the contract will be granted the minter and pauser + * roles, as well as the default admin role, which will let it grant both minter + * and pauser roles to other accounts. + * + * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._ + */ +contract ERC721PresetMinterPauserAutoId is + Context, + AccessControlEnumerable, + ERC721Enumerable, + ERC721Burnable, + ERC721Pausable +{ + using Counters for Counters.Counter; + + bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); + bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE"); + + Counters.Counter private _tokenIdTracker; + + string private _baseTokenURI; + + /** + * @dev Grants `DEFAULT_ADMIN_ROLE`, `MINTER_ROLE` and `PAUSER_ROLE` to the + * account that deploys the contract. + * + * Token URIs will be autogenerated based on `baseURI` and their token IDs. + * See {ERC721-tokenURI}. + */ + constructor(string memory name, string memory symbol, string memory baseTokenURI) ERC721(name, symbol) { + _baseTokenURI = baseTokenURI; + + _setupRole(DEFAULT_ADMIN_ROLE, _msgSender()); + + _setupRole(MINTER_ROLE, _msgSender()); + _setupRole(PAUSER_ROLE, _msgSender()); + } + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + /** + * @dev Creates a new token for `to`. Its token ID will be automatically + * assigned (and available on the emitted {IERC721-Transfer} event), and the token + * URI autogenerated based on the base URI passed at construction. + * + * See {ERC721-_mint}. + * + * Requirements: + * + * - the caller must have the `MINTER_ROLE`. + */ + function mint(address to) public virtual { + require(hasRole(MINTER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have minter role to mint"); + + // We cannot just use balanceOf to create the new tokenId because tokens + // can be burned (destroyed), so we need a separate counter. + _mint(to, _tokenIdTracker.current()); + _tokenIdTracker.increment(); + } + + /** + * @dev Pauses all token transfers. + * + * See {ERC721Pausable} and {Pausable-_pause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function pause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to pause"); + _pause(); + } + + /** + * @dev Unpauses all token transfers. + * + * See {ERC721Pausable} and {Pausable-_unpause}. + * + * Requirements: + * + * - the caller must have the `PAUSER_ROLE`. + */ + function unpause() public virtual { + require(hasRole(PAUSER_ROLE, _msgSender()), "ERC721PresetMinterPauserAutoId: must have pauser role to unpause"); + _unpause(); + } + + function _beforeTokenTransfer( + address from, + address to, + uint256 firstTokenId, + uint256 batchSize + ) internal virtual override(ERC721, ERC721Enumerable, ERC721Pausable) { + super._beforeTokenTransfer(from, to, firstTokenId, batchSize); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(AccessControlEnumerable, ERC721, ERC721Enumerable) returns (bool) { + return super.supportsInterface(interfaceId); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/presets/README.md b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/presets/README.md new file mode 100644 index 0000000..468200b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/presets/README.md @@ -0,0 +1 @@ +Contract presets are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com/) as a more powerful alternative. diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/utils/ERC721Holder.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/utils/ERC721Holder.sol new file mode 100644 index 0000000..f18ad8a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC721/utils/ERC721Holder.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol) + +pragma solidity ^0.8.0; + +import "../IERC721Receiver.sol"; + +/** + * @dev Implementation of the {IERC721Receiver} interface. + * + * Accepts all token transfers. + * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. + */ +contract ERC721Holder is IERC721Receiver { + /** + * @dev See {IERC721Receiver-onERC721Received}. + * + * Always returns `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { + return this.onERC721Received.selector; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/ERC777.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/ERC777.sol new file mode 100644 index 0000000..c9a17d8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/ERC777.sol @@ -0,0 +1,514 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC777/ERC777.sol) + +pragma solidity ^0.8.0; + +import "./IERC777.sol"; +import "./IERC777Recipient.sol"; +import "./IERC777Sender.sol"; +import "../ERC20/IERC20.sol"; +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "../../utils/introspection/IERC1820Registry.sol"; + +/** + * @dev Implementation of the {IERC777} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * + * Support for ERC20 is included in this contract, as specified by the EIP: both + * the ERC777 and ERC20 interfaces can be safely used when interacting with it. + * Both {IERC777-Sent} and {IERC20-Transfer} events are emitted on token + * movements. + * + * 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; + + IERC1820Registry internal constant _ERC1820_REGISTRY = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); + + mapping(address => uint256) private _balances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + bytes32 private constant _TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); + bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); + + // This isn't ever read from - it's only used to respond to the defaultOperators query. + address[] private _defaultOperatorsArray; + + // Immutable, but accounts may revoke them (tracked in __revokedDefaultOperators). + mapping(address => bool) private _defaultOperators; + + // For each account, a mapping of its operators and revoked default operators. + mapping(address => mapping(address => bool)) private _operators; + mapping(address => mapping(address => bool)) private _revokedDefaultOperators; + + // ERC20-allowances + mapping(address => mapping(address => uint256)) private _allowances; + + /** + * @dev `defaultOperators` may be an empty array. + */ + constructor(string memory name_, string memory symbol_, address[] memory defaultOperators_) { + _name = name_; + _symbol = symbol_; + + _defaultOperatorsArray = defaultOperators_; + for (uint256 i = 0; i < defaultOperators_.length; i++) { + _defaultOperators[defaultOperators_[i]] = true; + } + + // register interfaces + _ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC777Token"), address(this)); + _ERC1820_REGISTRY.setInterfaceImplementer(address(this), keccak256("ERC20Token"), address(this)); + } + + /** + * @dev See {IERC777-name}. + */ + function name() public view virtual override returns (string memory) { + return _name; + } + + /** + * @dev See {IERC777-symbol}. + */ + function symbol() public view virtual override returns (string memory) { + return _symbol; + } + + /** + * @dev See {ERC20-decimals}. + * + * Always returns 18, as per the + * [ERC777 EIP](https://eips.ethereum.org/EIPS/eip-777#backward-compatibility). + */ + function decimals() public pure virtual returns (uint8) { + return 18; + } + + /** + * @dev See {IERC777-granularity}. + * + * This implementation always returns `1`. + */ + function granularity() public view virtual override returns (uint256) { + return 1; + } + + /** + * @dev See {IERC777-totalSupply}. + */ + function totalSupply() public view virtual override(IERC20, IERC777) returns (uint256) { + return _totalSupply; + } + + /** + * @dev Returns the amount of tokens owned by an account (`tokenHolder`). + */ + function balanceOf(address tokenHolder) public view virtual override(IERC20, IERC777) returns (uint256) { + return _balances[tokenHolder]; + } + + /** + * @dev See {IERC777-send}. + * + * Also emits a {IERC20-Transfer} event for ERC20 compatibility. + */ + function send(address recipient, uint256 amount, bytes memory data) public virtual override { + _send(_msgSender(), recipient, amount, data, "", true); + } + + /** + * @dev See {IERC20-transfer}. + * + * Unlike `send`, `recipient` is _not_ required to implement the {IERC777Recipient} + * interface if it is a contract. + * + * Also emits a {Sent} event. + */ + function transfer(address recipient, uint256 amount) public virtual override returns (bool) { + _send(_msgSender(), recipient, amount, "", "", false); + return true; + } + + /** + * @dev See {IERC777-burn}. + * + * Also emits a {IERC20-Transfer} event for ERC20 compatibility. + */ + function burn(uint256 amount, bytes memory data) public virtual override { + _burn(_msgSender(), amount, data, ""); + } + + /** + * @dev See {IERC777-isOperatorFor}. + */ + function isOperatorFor(address operator, address tokenHolder) public view virtual override returns (bool) { + return + operator == tokenHolder || + (_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) || + _operators[tokenHolder][operator]; + } + + /** + * @dev See {IERC777-authorizeOperator}. + */ + function authorizeOperator(address operator) public virtual override { + require(_msgSender() != operator, "ERC777: authorizing self as operator"); + + if (_defaultOperators[operator]) { + delete _revokedDefaultOperators[_msgSender()][operator]; + } else { + _operators[_msgSender()][operator] = true; + } + + emit AuthorizedOperator(operator, _msgSender()); + } + + /** + * @dev See {IERC777-revokeOperator}. + */ + function revokeOperator(address operator) public virtual override { + require(operator != _msgSender(), "ERC777: revoking self as operator"); + + if (_defaultOperators[operator]) { + _revokedDefaultOperators[_msgSender()][operator] = true; + } else { + delete _operators[_msgSender()][operator]; + } + + emit RevokedOperator(operator, _msgSender()); + } + + /** + * @dev See {IERC777-defaultOperators}. + */ + function defaultOperators() public view virtual override returns (address[] memory) { + return _defaultOperatorsArray; + } + + /** + * @dev See {IERC777-operatorSend}. + * + * Emits {Sent} and {IERC20-Transfer} events. + */ + function operatorSend( + address sender, + address recipient, + uint256 amount, + bytes memory data, + bytes memory operatorData + ) public virtual override { + require(isOperatorFor(_msgSender(), sender), "ERC777: caller is not an operator for holder"); + _send(sender, recipient, amount, data, operatorData, true); + } + + /** + * @dev See {IERC777-operatorBurn}. + * + * Emits {Burned} and {IERC20-Transfer} events. + */ + function operatorBurn( + address account, + uint256 amount, + bytes memory data, + bytes memory operatorData + ) public virtual override { + require(isOperatorFor(_msgSender(), account), "ERC777: caller is not an operator for holder"); + _burn(account, amount, data, operatorData); + } + + /** + * @dev See {IERC20-allowance}. + * + * Note that operator and allowance concepts are orthogonal: operators may + * not have allowance, and accounts with allowance may not be operators + * themselves. + */ + function allowance(address holder, address spender) public view virtual override returns (uint256) { + return _allowances[holder][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Note that accounts cannot have allowance issued by their operators. + */ + function approve(address spender, uint256 value) public virtual override returns (bool) { + address holder = _msgSender(); + _approve(holder, spender, value); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Note that operator and allowance concepts are orthogonal: operators cannot + * call `transferFrom` (unless they have allowance), and accounts with + * allowance cannot call `operatorSend` (unless they are operators). + * + * Emits {Sent}, {IERC20-Transfer} and {IERC20-Approval} events. + */ + function transferFrom(address holder, address recipient, uint256 amount) public virtual override returns (bool) { + address spender = _msgSender(); + _spendAllowance(holder, spender, amount); + _send(holder, recipient, amount, "", "", false); + return true; + } + + /** + * @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * If a send hook is registered for `account`, the corresponding function + * will be called with the caller address as the `operator` and with + * `userData` and `operatorData`. + * + * See {IERC777Sender} and {IERC777Recipient}. + * + * Emits {Minted} and {IERC20-Transfer} events. + * + * Requirements + * + * - `account` cannot be the zero address. + * - if `account` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function _mint(address account, uint256 amount, bytes memory userData, bytes memory operatorData) internal virtual { + _mint(account, amount, userData, operatorData, true); + } + + /** + * @dev Creates `amount` tokens and assigns them to `account`, increasing + * the total supply. + * + * If `requireReceptionAck` is set to true, and if a send hook is + * registered for `account`, the corresponding function will be called with + * `operator`, `data` and `operatorData`. + * + * See {IERC777Sender} and {IERC777Recipient}. + * + * Emits {Minted} and {IERC20-Transfer} events. + * + * Requirements + * + * - `account` cannot be the zero address. + * - if `account` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function _mint( + address account, + uint256 amount, + bytes memory userData, + bytes memory operatorData, + bool requireReceptionAck + ) internal virtual { + require(account != address(0), "ERC777: mint to the zero address"); + + address operator = _msgSender(); + + _beforeTokenTransfer(operator, address(0), account, amount); + + // Update state variables + _totalSupply += amount; + _balances[account] += amount; + + _callTokensReceived(operator, address(0), account, amount, userData, operatorData, requireReceptionAck); + + emit Minted(operator, account, amount, userData, operatorData); + emit Transfer(address(0), account, amount); + } + + /** + * @dev Send tokens + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient + */ + function _send( + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData, + bool requireReceptionAck + ) internal virtual { + require(from != address(0), "ERC777: transfer from the zero address"); + require(to != address(0), "ERC777: transfer to the zero address"); + + address operator = _msgSender(); + + _callTokensToSend(operator, from, to, amount, userData, operatorData); + + _move(operator, from, to, amount, userData, operatorData); + + _callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck); + } + + /** + * @dev Burn tokens + * @param from address token holder address + * @param amount uint256 amount of tokens to burn + * @param data bytes extra information provided by the token holder + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _burn(address from, uint256 amount, bytes memory data, bytes memory operatorData) internal virtual { + require(from != address(0), "ERC777: burn from the zero address"); + + address operator = _msgSender(); + + _callTokensToSend(operator, from, address(0), amount, data, operatorData); + + _beforeTokenTransfer(operator, from, address(0), amount); + + // Update state variables + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC777: burn amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + } + _totalSupply -= amount; + + emit Burned(operator, from, amount, data, operatorData); + emit Transfer(from, address(0), amount); + } + + function _move( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) private { + _beforeTokenTransfer(operator, from, to, amount); + + uint256 fromBalance = _balances[from]; + require(fromBalance >= amount, "ERC777: transfer amount exceeds balance"); + unchecked { + _balances[from] = fromBalance - amount; + } + _balances[to] += amount; + + emit Sent(operator, from, to, amount, userData, operatorData); + emit Transfer(from, to, amount); + } + + /** + * @dev See {ERC20-_approve}. + * + * Note that accounts cannot have allowance issued by their operators. + */ + function _approve(address holder, address spender, uint256 value) internal virtual { + require(holder != address(0), "ERC777: approve from the zero address"); + require(spender != address(0), "ERC777: approve to the zero address"); + + _allowances[holder][spender] = value; + emit Approval(holder, spender, value); + } + + /** + * @dev Call from.tokensToSend() if the interface is registered + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + */ + function _callTokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData + ) private { + address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(from, _TOKENS_SENDER_INTERFACE_HASH); + if (implementer != address(0)) { + IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData); + } + } + + /** + * @dev Call to.tokensReceived() if the interface is registered. Reverts if the recipient is a contract but + * tokensReceived() was not registered for the recipient + * @param operator address operator requesting the transfer + * @param from address token holder address + * @param to address recipient address + * @param amount uint256 amount of tokens to transfer + * @param userData bytes extra information provided by the token holder (if any) + * @param operatorData bytes extra information provided by the operator (if any) + * @param requireReceptionAck if true, contract recipients are required to implement ERC777TokensRecipient + */ + function _callTokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes memory userData, + bytes memory operatorData, + bool requireReceptionAck + ) private { + address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(to, _TOKENS_RECIPIENT_INTERFACE_HASH); + if (implementer != address(0)) { + IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData); + } else if (requireReceptionAck) { + require(!to.isContract(), "ERC777: token recipient contract has no implementer for ERC777TokensRecipient"); + } + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `amount`. + * + * Does not update the allowance amount in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Might emit an {IERC20-Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 amount) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + require(currentAllowance >= amount, "ERC777: insufficient allowance"); + unchecked { + _approve(owner, spender, currentAllowance - amount); + } + } + } + + /** + * @dev Hook that is called before any token transfer. This includes + * calls to {send}, {transfer}, {operatorSend}, {transferFrom}, minting and burning. + * + * Calling conditions: + * + * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens + * will be to transferred to `to`. + * - when `from` is zero, `amount` tokens will be minted for `to`. + * - when `to` is zero, `amount` of ``from``'s tokens will be burned. + * - `from` and `to` are never both zero. + * + * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. + */ + function _beforeTokenTransfer(address operator, address from, address to, uint256 amount) internal virtual {} +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777.sol new file mode 100644 index 0000000..2d4f6df --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC777/IERC777.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC777Token standard as defined in the EIP. + * + * This contract uses the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let + * token holders and recipients react to token movements by using setting implementers + * for the associated interfaces in said registry. See {IERC1820Registry} and + * {ERC1820Implementer}. + */ +interface IERC777 { + /** + * @dev Emitted when `amount` tokens are created by `operator` and assigned to `to`. + * + * Note that some additional user `data` and `operatorData` can be logged in the event. + */ + event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); + + /** + * @dev Emitted when `operator` destroys `amount` tokens from `account`. + * + * Note that some additional user `data` and `operatorData` can be logged in the event. + */ + event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); + + /** + * @dev Emitted when `operator` is made operator for `tokenHolder`. + */ + event AuthorizedOperator(address indexed operator, address indexed tokenHolder); + + /** + * @dev Emitted when `operator` is revoked its operator status for `tokenHolder`. + */ + event RevokedOperator(address indexed operator, address indexed tokenHolder); + + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the smallest part of the token that is not divisible. This + * means all token operations (creation, movement and destruction) must have + * amounts that are a multiple of this number. + * + * For most token contracts, this value will equal 1. + */ + function granularity() external view returns (uint256); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by an account (`owner`). + */ + function balanceOf(address owner) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * If send or receive hooks are registered for the caller and `recipient`, + * the corresponding functions will be called with `data` and empty + * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. + * + * Emits a {Sent} event. + * + * Requirements + * + * - the caller must have at least `amount` tokens. + * - `recipient` cannot be the zero address. + * - if `recipient` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function send(address recipient, uint256 amount, bytes calldata data) external; + + /** + * @dev Destroys `amount` tokens from the caller's account, reducing the + * total supply. + * + * If a send hook is registered for the caller, the corresponding function + * will be called with `data` and empty `operatorData`. See {IERC777Sender}. + * + * Emits a {Burned} event. + * + * Requirements + * + * - the caller must have at least `amount` tokens. + */ + function burn(uint256 amount, bytes calldata data) external; + + /** + * @dev Returns true if an account is an operator of `tokenHolder`. + * Operators can send and burn tokens on behalf of their owners. All + * accounts are their own operator. + * + * See {operatorSend} and {operatorBurn}. + */ + function isOperatorFor(address operator, address tokenHolder) external view returns (bool); + + /** + * @dev Make an account an operator of the caller. + * + * See {isOperatorFor}. + * + * Emits an {AuthorizedOperator} event. + * + * Requirements + * + * - `operator` cannot be calling address. + */ + function authorizeOperator(address operator) external; + + /** + * @dev Revoke an account's operator status for the caller. + * + * See {isOperatorFor} and {defaultOperators}. + * + * Emits a {RevokedOperator} event. + * + * Requirements + * + * - `operator` cannot be calling address. + */ + function revokeOperator(address operator) external; + + /** + * @dev Returns the list of default operators. These accounts are operators + * for all token holders, even if {authorizeOperator} was never called on + * them. + * + * This list is immutable, but individual holders may revoke these via + * {revokeOperator}, in which case {isOperatorFor} will return false. + */ + function defaultOperators() external view returns (address[] memory); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must + * be an operator of `sender`. + * + * If send or receive hooks are registered for `sender` and `recipient`, + * the corresponding functions will be called with `data` and + * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. + * + * Emits a {Sent} event. + * + * Requirements + * + * - `sender` cannot be the zero address. + * - `sender` must have at least `amount` tokens. + * - the caller must be an operator for `sender`. + * - `recipient` cannot be the zero address. + * - if `recipient` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function operatorSend( + address sender, + address recipient, + uint256 amount, + bytes calldata data, + bytes calldata operatorData + ) external; + + /** + * @dev Destroys `amount` tokens from `account`, reducing the total supply. + * The caller must be an operator of `account`. + * + * If a send hook is registered for `account`, the corresponding function + * will be called with `data` and `operatorData`. See {IERC777Sender}. + * + * Emits a {Burned} event. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + * - the caller must be an operator for `account`. + */ + function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external; + + event Sent( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777Recipient.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777Recipient.sol new file mode 100644 index 0000000..717dd8f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777Recipient.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Recipient.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. + * + * Accounts can be notified of {IERC777} tokens being sent to them by having a + * contract implement this interface (contract holders can be their own + * implementer) and registering it on the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. + * + * See {IERC1820Registry} and {ERC1820Implementer}. + */ +interface IERC777Recipient { + /** + * @dev Called by an {IERC777} token contract whenever tokens are being + * moved or created into a registered account (`to`). The type of operation + * is conveyed by `from` being the zero address or not. + * + * This call occurs _after_ the token contract's state is updated, so + * {IERC777-balanceOf}, etc., can be used to query the post-operation state. + * + * This function may revert to prevent the operation from being executed. + */ + function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777Sender.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777Sender.sol new file mode 100644 index 0000000..969e3e3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/IERC777Sender.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC777/IERC777Sender.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC777TokensSender standard as defined in the EIP. + * + * {IERC777} Token holders can be notified of operations performed on their + * tokens by having a contract implement this interface (contract holders can be + * their own implementer) and registering it on the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. + * + * See {IERC1820Registry} and {ERC1820Implementer}. + */ +interface IERC777Sender { + /** + * @dev Called by an {IERC777} token contract whenever a registered holder's + * (`from`) tokens are about to be moved or destroyed. The type of operation + * is conveyed by `to` being the zero address or not. + * + * This call occurs _before_ the token contract's state is updated, so + * {IERC777-balanceOf}, etc., can be used to query the pre-operation state. + * + * This function may revert to prevent the operation from being executed. + */ + function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/README.adoc new file mode 100644 index 0000000..ac326ab --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/README.adoc @@ -0,0 +1,32 @@ += ERC 777 + +[.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]. + +The token behavior itself is implemented in the core contracts: {IERC777}, {ERC777}. + +Additionally there are interfaces used to develop contracts that react to token movements: {IERC777Sender}, {IERC777Recipient}. + +== Core + +{{IERC777}} + +{{ERC777}} + +== Hooks + +{{IERC777Sender}} + +{{IERC777Recipient}} + +== Presets + +These contracts are preconfigured combinations of features. They can be used through inheritance or as models to copy and paste their source code. + +{{ERC777PresetFixedSupply}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol new file mode 100644 index 0000000..8bd4b79 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (token/ERC777/presets/ERC777PresetFixedSupply.sol) +pragma solidity ^0.8.0; + +import "../ERC777.sol"; + +/** + * @dev {ERC777} token, including: + * + * - Preminted initial supply + * - No access control mechanism (for minting/pausing) and hence no governance + * + * _Available since v3.4._ + */ +contract ERC777PresetFixedSupply is ERC777 { + /** + * @dev Mints `initialSupply` amount of token and transfers them to `owner`. + * + * See {ERC777-constructor}. + */ + constructor( + string memory name, + string memory symbol, + address[] memory defaultOperators, + uint256 initialSupply, + address owner + ) ERC777(name, symbol, defaultOperators) { + _mint(owner, initialSupply, "", ""); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/common/ERC2981.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/token/common/ERC2981.sol new file mode 100644 index 0000000..7d47b6c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/common/ERC2981.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (token/common/ERC2981.sol) + +pragma solidity ^0.8.0; + +import "../../interfaces/IERC2981.sol"; +import "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. + * + * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for + * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. + * + * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the + * fee is specified in basis points by default. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + * + * _Available since v4.5._ + */ +abstract contract ERC2981 is IERC2981, ERC165 { + struct RoyaltyInfo { + address receiver; + uint96 royaltyFraction; + } + + RoyaltyInfo private _defaultRoyaltyInfo; + mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @inheritdoc IERC2981 + */ + function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual override returns (address, uint256) { + RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId]; + + if (royalty.receiver == address(0)) { + royalty = _defaultRoyaltyInfo; + } + + uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator(); + + return (royalty.receiver, royaltyAmount); + } + + /** + * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a + * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an + * override. + */ + function _feeDenominator() internal pure virtual returns (uint96) { + return 10000; + } + + /** + * @dev Sets the royalty information that all ids in this contract will default to. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: invalid receiver"); + + _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Removes default royalty information. + */ + function _deleteDefaultRoyalty() internal virtual { + delete _defaultRoyaltyInfo; + } + + /** + * @dev Sets the royalty information for a specific token id, overriding the global default. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { + require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); + require(receiver != address(0), "ERC2981: Invalid parameters"); + + _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Resets royalty information for the token id back to the global default. + */ + function _resetTokenRoyalty(uint256 tokenId) internal virtual { + delete _tokenRoyaltyInfo[tokenId]; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/token/common/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/token/common/README.adoc new file mode 100644 index 0000000..af61674 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/token/common/README.adoc @@ -0,0 +1,10 @@ += Common (Tokens) + +Functionality that is common to multiple token standards. + +* {ERC2981}: NFT Royalties compatible with both ERC721 and ERC1155. +** For ERC721 consider {ERC721Royalty} which clears the royalty information from storage on burn. + +== Contracts + +{{ERC2981}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Address.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Address.sol new file mode 100644 index 0000000..0791a66 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Address.sol @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * + * Furthermore, `isContract` will also return true if the target contract within + * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, + * which only has an effect at the end of a transaction. + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * 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"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling + * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. + * + * _Available since v4.8._ + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + // only check isContract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + /** + * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason or using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert(bytes memory returndata, string memory errorMessage) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Arrays.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Arrays.sol new file mode 100644 index 0000000..66fe322 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Arrays.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Arrays.sol) + +pragma solidity ^0.8.0; + +import "./StorageSlot.sol"; +import "./math/Math.sol"; + +/** + * @dev Collection of functions related to array types. + */ +library Arrays { + using StorageSlot for bytes32; + + /** + * @dev Searches a sorted `array` and returns the first index that contains + * a value greater or equal to `element`. If no such index exists (i.e. all + * values in the array are strictly less than `element`), the array length is + * returned. Time complexity O(log n). + * + * `array` is expected to be sorted in ascending order, and to contain no + * repeated elements. + */ + function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { + if (array.length == 0) { + return 0; + } + + uint256 low = 0; + uint256 high = array.length; + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds down (it does integer division with truncation). + if (unsafeAccess(array, mid).value > element) { + high = mid; + } else { + low = mid + 1; + } + } + + // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. + if (low > 0 && unsafeAccess(array, low - 1).value == element) { + return low - 1; + } else { + return low; + } + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getAddressSlot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getBytes32Slot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.17/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getUint256Slot(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Base64.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Base64.sol new file mode 100644 index 0000000..4e08cd5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Base64.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + * + * _Available since v4.5._ + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + /// @solidity memory-safe-assembly + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Checkpoints.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Checkpoints.sol new file mode 100644 index 0000000..9d4f0f9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Checkpoints.sol @@ -0,0 +1,560 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Checkpoints.sol) +// This file was procedurally generated from scripts/generate/templates/Checkpoints.js. + +pragma solidity ^0.8.0; + +import "./math/Math.sol"; +import "./math/SafeCast.sol"; + +/** + * @dev This library defines the `History` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type `Checkpoints.History` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + * + * _Available since v4.5._ + */ +library Checkpoints { + struct History { + Checkpoint[] _checkpoints; + } + + struct Checkpoint { + uint32 _blockNumber; + uint224 _value; + } + + /** + * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one + * before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the + * block, the requested block number must be in the past, excluding the current block. + */ + function getAtBlock(History storage self, uint256 blockNumber) internal view returns (uint256) { + require(blockNumber < block.number, "Checkpoints: block not yet mined"); + uint32 key = SafeCast.toUint32(blockNumber); + + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one + * before it is returned, or zero otherwise. Similar to {upperLookup} but optimized for the case when the searched + * checkpoint is probably "recent", defined as being among the last sqrt(N) checkpoints where N is the number of + * checkpoints. + */ + function getAtProbablyRecentBlock(History storage self, uint256 blockNumber) internal view returns (uint256) { + require(blockNumber < block.number, "Checkpoints: block not yet mined"); + uint32 key = SafeCast.toUint32(blockNumber); + + uint256 len = self._checkpoints.length; + + uint256 low = 0; + uint256 high = len; + + if (len > 5) { + uint256 mid = len - Math.sqrt(len); + if (key < _unsafeAccess(self._checkpoints, mid)._blockNumber) { + high = mid; + } else { + low = mid + 1; + } + } + + uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high); + + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block. + * + * Returns previous value and new value. + */ + function push(History storage self, uint256 value) internal returns (uint256, uint256) { + return _insert(self._checkpoints, SafeCast.toUint32(block.number), SafeCast.toUint224(value)); + } + + /** + * @dev Pushes a value onto a History, by updating the latest value using binary operation `op`. The new value will + * be set to `op(latest, delta)`. + * + * Returns previous value and new value. + */ + function push( + History storage self, + function(uint256, uint256) view returns (uint256) op, + uint256 delta + ) internal returns (uint256, uint256) { + return push(self, op(latest(self), delta)); + } + + /** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ + function latest(History storage self) internal view returns (uint224) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint( + History storage self + ) internal view returns (bool exists, uint32 _blockNumber, uint224 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._blockNumber, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(History storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + require(last._blockNumber <= key, "Checkpoint: decreasing keys"); + + // Update or push new checkpoint + if (last._blockNumber == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint({_blockNumber: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint({_blockNumber: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the 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. + */ + function _upperBinaryLookup( + Checkpoint[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._blockNumber > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._blockNumber < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess(Checkpoint[] storage self, uint256 pos) private pure returns (Checkpoint storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace224 { + Checkpoint224[] _checkpoints; + } + + struct Checkpoint224 { + uint32 _key; + uint224 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + */ + function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the 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; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @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; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @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). + */ + 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. + */ + function latest(Trace224 storage self) internal view returns (uint224) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace224 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint224 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + require(last._key <= key, "Checkpoint: decreasing keys"); + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint224({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint224({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the 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. + */ + function _upperBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint224[] storage self, + uint256 pos + ) private pure returns (Checkpoint224 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace160 { + Checkpoint160[] _checkpoints; + } + + struct Checkpoint160 { + uint96 _key; + uint160 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + */ + function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the 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; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @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; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @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). + */ + 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. + */ + function latest(Trace160 storage self) internal view returns (uint160) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace160 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint160 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + require(last._key <= key, "Checkpoint: decreasing keys"); + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint160({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint160({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the 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. + */ + function _upperBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint160[] storage self, + uint256 pos + ) private pure returns (Checkpoint160 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Context.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Context.sol new file mode 100644 index 0000000..f304065 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Context.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Counters.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Counters.sol new file mode 100644 index 0000000..8a4f2a2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Counters.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol) + +pragma solidity ^0.8.0; + +/** + * @title Counters + * @author Matt Condon (@shrugs) + * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number + * of elements in a mapping, issuing ERC721 ids, or counting request ids. + * + * Include with `using Counters for Counters.Counter;` + */ +library Counters { + struct Counter { + // This variable should never be directly accessed by users of the library: interactions must be restricted to + // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add + // this feature: see https://github.com/ethereum/solidity/issues/4637 + uint256 _value; // default: 0 + } + + function current(Counter storage counter) internal view returns (uint256) { + return counter._value; + } + + function increment(Counter storage counter) internal { + unchecked { + counter._value += 1; + } + } + + function decrement(Counter storage counter) internal { + uint256 value = counter._value; + require(value > 0, "Counter: decrement overflow"); + unchecked { + counter._value = value - 1; + } + } + + function reset(Counter storage counter) internal { + counter._value = 0; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Create2.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Create2.sol new file mode 100644 index 0000000..29fa973 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Create2.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Create2.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. + * `CREATE2` can be used to compute in advance the address where a smart + * contract will be deployed, which allows for interesting new mechanisms known + * as 'counterfactual interactions'. + * + * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more + * information. + */ +library Create2 { + /** + * @dev Deploys a contract using `CREATE2`. The address where the contract + * will be deployed can be known in advance via {computeAddress}. + * + * The bytecode for a contract can be obtained from Solidity with + * `type(contractName).creationCode`. + * + * Requirements: + * + * - `bytecode` must not be empty. + * - `salt` must have not been used for `bytecode` already. + * - the factory must have a balance of at least `amount`. + * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. + */ + function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { + require(address(this).balance >= amount, "Create2: insufficient balance"); + require(bytecode.length != 0, "Create2: bytecode length is zero"); + /// @solidity memory-safe-assembly + assembly { + addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) + } + require(addr != address(0), "Create2: Failed on deploy"); + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the + * `bytecodeHash` or `salt` will result in a new destination address. + */ + function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { + return computeAddress(salt, bytecodeHash, address(this)); + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at + * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. + */ + function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) // Get free memory pointer + + // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | + // |-------------------|---------------------------------------------------------------------------| + // | bytecodeHash | CCCCCCCCCCCCC...CC | + // | salt | BBBBBBBBBBBBB...BB | + // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | + // | 0xFF | FF | + // |-------------------|---------------------------------------------------------------------------| + // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | + // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | + + mstore(add(ptr, 0x40), bytecodeHash) + mstore(add(ptr, 0x20), salt) + mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes + let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff + mstore8(start, 0xff) + addr := keccak256(start, 85) + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Multicall.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Multicall.sol new file mode 100644 index 0000000..5729f84 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Multicall.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Multicall.sol) + +pragma solidity ^0.8.0; + +import "./Address.sol"; + +/** + * @dev Provides a function to batch together multiple calls in a single external call. + * + * _Available since v4.1._ + */ +abstract contract Multicall { + /** + * @dev Receives and executes a batch of function calls on this contract. + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { + results = new bytes[](data.length); + for (uint256 i = 0; i < data.length; i++) { + results[i] = Address.functionDelegateCall(address(this), data[i]); + } + return results; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/README.adoc b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/README.adoc new file mode 100644 index 0000000..5e8af93 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/README.adoc @@ -0,0 +1,113 @@ += Utilities + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils + +Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives. + +The {Address}, {Arrays}, {Base64} and {Strings} libraries provide more operations related to these native data types, while {SafeCast} adds ways to safely convert between the different signed and unsigned numeric types. +{Multicall} provides a function to batch together multiple calls in a single external call. + +For new data types: + + * {Counters}: a simple way to get a counter that can only be incremented, decremented or reset. Very useful for ID generation, counting contract activity, among others. + * {EnumerableMap}: like Solidity's https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] type, but with key-value _enumeration_: this will let you know how many entries a mapping has, and iterate over them (which is not possible with `mapping`). + * {EnumerableSet}: like {EnumerableMap}, but for https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets]. Can be used to store privileged accounts, issued IDs, etc. + +[NOTE] +==== +Because Solidity does not support generic types, {EnumerableMap} and {EnumerableSet} are specialized to a limited number of key-value types. + +As of v3.0, {EnumerableMap} supports `uint256 -> address` (`UintToAddressMap`), and {EnumerableSet} supports `address` and `uint256` (`AddressSet` and `UintSet`). +==== + +Finally, {Create2} contains all necessary utilities to safely use the https://blog.openzeppelin.com/getting-the-most-out-of-create2/[`CREATE2` EVM opcode], without having to deal with low-level assembly. + +== Math + +{{Math}} + +{{SignedMath}} + +{{SafeCast}} + +{{SafeMath}} + +{{SignedSafeMath}} + +== Cryptography + +{{ECDSA}} + +{{SignatureChecker}} + +{{MerkleProof}} + +{{EIP712}} + +== Escrow + +{{ConditionalEscrow}} + +{{Escrow}} + +{{RefundEscrow}} + +== Introspection + +This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[type introspection] of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_. + +Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors. + +There are two main ways to approach this. + +* Locally, where a contract implements `IERC165` and declares an interface, and a second one queries it directly via `ERC165Checker`. +* Globally, where a global and unique registry (`IERC1820Registry`) is used to register implementers of a certain interface (`IERC1820Implementer`). It is then the registry that is queried, which allows for more complex setups, like contracts implementing interfaces for externally-owned accounts. + +Note that, in all cases, accounts simply _declare_ their interfaces, but they are not required to actually implement them. This mechanism can therefore be used to both prevent errors and allow for complex interactions (see `ERC777`), but it must not be relied on for security. + +{{IERC165}} + +{{ERC165}} + +{{ERC165Storage}} + +{{ERC165Checker}} + +{{IERC1820Registry}} + +{{IERC1820Implementer}} + +{{ERC1820Implementer}} + +== Data Structures + +{{BitMaps}} + +{{EnumerableMap}} + +{{EnumerableSet}} + +{{DoubleEndedQueue}} + +{{Checkpoints}} + +== Libraries + +{{Create2}} + +{{Address}} + +{{Arrays}} + +{{Base64}} + +{{Counters}} + +{{Strings}} + +{{ShortStrings}} + +{{StorageSlot}} + +{{Multicall}} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/ShortStrings.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/ShortStrings.sol new file mode 100644 index 0000000..90a0549 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/ShortStrings.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol) + +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 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: + * + * ```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 { + // Used as an identifier for strings longer than 31 bytes. + bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; + + error StringTooLong(string str); + error InvalidShortString(); + + /** + * @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 = byteLength(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 byteLength(ShortString sstr) internal pure returns (uint256) { + uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; + if (result > 31) { + revert InvalidShortString(); + } + return result; + } + + /** + * @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(_FALLBACK_SENTINEL); + } + } + + /** + * @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 (ShortString.unwrap(value) != _FALLBACK_SENTINEL) { + return toString(value); + } else { + 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/lib/openzeppelin-contracts-v4.9.3/contracts/utils/StorageSlot.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/StorageSlot.sol new file mode 100644 index 0000000..df62b8f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/StorageSlot.sol @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol) +// This file was procedurally generated from scripts/generate/templates/StorageSlot.js. + +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; + * } + * } + * ``` + * + * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._ + * _Available since v4.9 for `string`, `bytes`._ + */ +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + struct StringSlot { + string value; + } + + struct BytesSlot { + bytes value; + } + + /** + * @dev Returns an `AddressSlot` with member `value` located at `slot`. + */ + function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + 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/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Strings.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Strings.sol new file mode 100644 index 0000000..657ebd6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Strings.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) + +pragma solidity ^0.8.0; + +import "./math/Math.sol"; +import "./math/SignedMath.sol"; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toString(int256 value) internal pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value)))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Timers.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Timers.sol new file mode 100644 index 0000000..04f8664 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/Timers.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/Timers.sol) + +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 { + uint64 _deadline; + } + + function getDeadline(Timestamp memory timer) internal pure returns (uint64) { + return timer._deadline; + } + + function setDeadline(Timestamp storage timer, uint64 timestamp) internal { + timer._deadline = timestamp; + } + + function reset(Timestamp storage timer) internal { + timer._deadline = 0; + } + + function isUnset(Timestamp memory timer) internal pure returns (bool) { + return timer._deadline == 0; + } + + function isStarted(Timestamp memory timer) internal pure returns (bool) { + return timer._deadline > 0; + } + + function isPending(Timestamp memory timer) internal view returns (bool) { + return timer._deadline > block.timestamp; + } + + function isExpired(Timestamp memory timer) internal view returns (bool) { + return isStarted(timer) && timer._deadline <= block.timestamp; + } + + struct BlockNumber { + uint64 _deadline; + } + + function getDeadline(BlockNumber memory timer) internal pure returns (uint64) { + return timer._deadline; + } + + function setDeadline(BlockNumber storage timer, uint64 timestamp) internal { + timer._deadline = timestamp; + } + + function reset(BlockNumber storage timer) internal { + timer._deadline = 0; + } + + function isUnset(BlockNumber memory timer) internal pure returns (bool) { + return timer._deadline == 0; + } + + function isStarted(BlockNumber memory timer) internal pure returns (bool) { + return timer._deadline > 0; + } + + function isPending(BlockNumber memory timer) internal view returns (bool) { + return timer._deadline > block.number; + } + + function isExpired(BlockNumber memory timer) internal view returns (bool) { + return isStarted(timer) && timer._deadline <= block.number; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/ECDSA.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/ECDSA.sol new file mode 100644 index 0000000..4326e5b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/ECDSA.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol) + +pragma solidity ^0.8.0; + +import "../Strings.sol"; + +/** + * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. + * + * These functions can be used to verify that a message was signed by the holder + * of the private keys of a given address. + */ +library ECDSA { + enum RecoverError { + NoError, + InvalidSignature, + InvalidSignatureLength, + InvalidSignatureS, + InvalidSignatureV // Deprecated in v4.8 + } + + function _throwError(RecoverError error) private pure { + if (error == RecoverError.NoError) { + return; // no error: do nothing + } else if (error == RecoverError.InvalidSignature) { + revert("ECDSA: invalid signature"); + } else if (error == RecoverError.InvalidSignatureLength) { + revert("ECDSA: invalid signature length"); + } else if (error == RecoverError.InvalidSignatureS) { + revert("ECDSA: invalid signature 's' value"); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature` or error string. This address can then be used for verification purposes. + * + * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {toEthSignedMessageHash} on it. + * + * Documentation for signature generation: + * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] + * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] + * + * _Available since v4.3._ + */ + function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) { + if (signature.length == 65) { + bytes32 r; + bytes32 s; + uint8 v; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + /// @solidity memory-safe-assembly + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + return tryRecover(hash, v, r, s); + } else { + return (address(0), RecoverError.InvalidSignatureLength); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature`. This address can then be used for verification purposes. + * + * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {toEthSignedMessageHash} on it. + */ + function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, signature); + _throwError(error); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. + * + * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] + * + * _Available since v4.3._ + */ + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) { + bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + uint8 v = uint8((uint256(vs) >> 255) + 27); + return tryRecover(hash, v, r, s); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. + * + * _Available since v4.2._ + */ + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, r, vs); + _throwError(error); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `v`, + * `r` and `s` signature fields separately. + * + * _Available since v4.3._ + */ + function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) { + // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature + // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines + // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most + // signatures from current libraries generate a unique signature with an s-value in the lower half order. + // + // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value + // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or + // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept + // these malleable signatures as well. + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + return (address(0), RecoverError.InvalidSignatureS); + } + + // If the signature is valid (and not malleable), return the signer address + address signer = ecrecover(hash, v, r, s); + if (signer == address(0)) { + return (address(0), RecoverError.InvalidSignature); + } + + return (signer, RecoverError.NoError); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { + (address recovered, RecoverError error) = tryRecover(hash, v, r, s); + _throwError(error); + return recovered; + } + + /** + * @dev Returns an Ethereum Signed Message, created from a `hash`. This + * produces hash corresponding to the one signed with the + * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] + * JSON-RPC method as part of EIP-191. + * + * See {recover}. + */ + function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) { + // 32 is the length in bytes of hash, + // enforced by the type signature above + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, "\x19Ethereum Signed Message:\n32") + mstore(0x1c, hash) + message := keccak256(0x00, 0x3c) + } + } + + /** + * @dev Returns an Ethereum Signed Message, created from `s`. This + * produces hash corresponding to the one signed with the + * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] + * JSON-RPC method as part of EIP-191. + * + * See {recover}. + */ + function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) { + return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s)); + } + + /** + * @dev Returns an Ethereum Signed Typed Data, created from a + * `domainSeparator` and a `structHash`. This produces hash corresponding + * to the one signed with the + * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] + * JSON-RPC method as part of EIP-712. + * + * See {recover}. + */ + 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) + } + } + + /** + * @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/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/EIP712.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/EIP712.sol new file mode 100644 index 0000000..2a0e734 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/EIP712.sol @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol) + +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. + * + * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible, + * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding + * they need in their contracts using a combination of `abi.encode` and `keccak256`. + * + * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding + * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA + * ({_hashTypedDataV4}). + * + * The implementation of the domain separator was designed to be as efficient as possible while still properly updating + * the chain id to protect against replay attacks on an eventual fork of the chain. + * + * 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 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; + + bytes32 private immutable _hashedName; + bytes32 private immutable _hashedVersion; + + ShortString private immutable _name; + ShortString private immutable _version; + string private _nameFallback; + string private _versionFallback; + + /** + * @dev Initializes the domain separator and parameter caches. + * + * The meaning of `name` and `version` is specified in + * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: + * + * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. + * - `version`: the current major version of the signing domain. + * + * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart + * 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); + } + + /** + * @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(); + } + } + + function _buildDomainSeparator() private view returns (bytes32) { + return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); + } + + /** + * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this + * function returns the hash of the fully encoded EIP712 message for this domain. + * + * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: + * + * ```solidity + * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( + * keccak256("Mail(address to,string contents)"), + * mailTo, + * keccak256(bytes(mailContents)) + * ))); + * address signer = ECDSA.recover(digest, signature); + * ``` + */ + function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { + return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash); + } + + /** + * @dev See {EIP-5267}. + * + * _Available since v4.9._ + */ + 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/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/MerkleProof.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/MerkleProof.sol new file mode 100644 index 0000000..19806ea --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/MerkleProof.sol @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.0; + +/** + * @dev These functions deal with verification of Merkle Tree proofs. + * + * The tree and the proofs can be generated using our + * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. + * You will find a quickstart guide in the readme. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the merkle tree could be reinterpreted as a leaf value. + * OpenZeppelin's JavaScript library generates merkle trees that are safe + * against this attack out of the box. + */ +library MerkleProof { + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Calldata version of {verify} + * + * _Available since v4.7._ + */ + function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProofCalldata(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + * + * _Available since v4.4._ + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = _hashPair(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @dev Calldata version of {processProof} + * + * _Available since v4.7._ + */ + function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = _hashPair(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by + * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. + * + * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. + * + * _Available since v4.7._ + */ + function multiProofVerify( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProof(proof, proofFlags, leaves) == root; + } + + /** + * @dev Calldata version of {multiProofVerify} + * + * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. + * + * _Available since v4.7._ + */ + function multiProofVerifyCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProofCalldata(proof, proofFlags, leaves) == root; + } + + /** + * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction + * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another + * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false + * respectively. + * + * CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree + * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the + * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). + * + * _Available since v4.7._ + */ + function processMultiProof( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32[] memory leaves + ) internal pure returns (bytes32 merkleRoot) { + // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by + // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the + // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of + // the merkle tree. + uint256 leavesLen = leaves.length; + uint256 proofLen = proof.length; + uint256 totalHashes = proofFlags.length; + + // Check proof validity. + require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof"); + + // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using + // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". + bytes32[] memory hashes = new bytes32[](totalHashes); + uint256 leafPos = 0; + uint256 hashPos = 0; + uint256 proofPos = 0; + // At each step, we compute the next hash using two values: + // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we + // get the next hash. + // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the + // `proof` array. + for (uint256 i = 0; i < totalHashes; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = _hashPair(a, b); + } + + if (totalHashes > 0) { + require(proofPos == proofLen, "MerkleProof: invalid multiproof"); + unchecked { + return hashes[totalHashes - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @dev Calldata version of {processMultiProof}. + * + * CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details. + * + * _Available since v4.7._ + */ + function processMultiProofCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32[] memory leaves + ) internal pure returns (bytes32 merkleRoot) { + // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by + // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the + // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of + // the merkle tree. + uint256 leavesLen = leaves.length; + uint256 proofLen = proof.length; + uint256 totalHashes = proofFlags.length; + + // Check proof validity. + require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof"); + + // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using + // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". + bytes32[] memory hashes = new bytes32[](totalHashes); + uint256 leafPos = 0; + uint256 hashPos = 0; + uint256 proofPos = 0; + // At each step, we compute the next hash using two values: + // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we + // get the next hash. + // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the + // `proof` array. + for (uint256 i = 0; i < totalHashes; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = _hashPair(a, b); + } + + if (totalHashes > 0) { + require(proofPos == proofLen, "MerkleProof: invalid multiproof"); + unchecked { + return hashes[totalHashes - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { + return a < b ? _efficientHash(a, b) : _efficientHash(b, a); + } + + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/SignatureChecker.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/SignatureChecker.sol new file mode 100644 index 0000000..1815d27 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/SignatureChecker.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol) + +pragma solidity ^0.8.0; + +import "./ECDSA.sol"; +import "../../interfaces/IERC1271.sol"; + +/** + * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA + * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like + * Argent and Gnosis Safe. + * + * _Available since v4.1._ + */ +library SignatureChecker { + /** + * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the + * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. + * + * 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 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + (address recovered, ECDSA.RecoverError error) = ECDSA.tryRecover(hash, signature); + 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) + ); + return (success && + result.length >= 32 && + abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/draft-EIP712.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/draft-EIP712.sol new file mode 100644 index 0000000..fdae3ba --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/cryptography/draft-EIP712.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/draft-EIP712.sol) + +pragma solidity ^0.8.0; + +// EIP-712 is Final as of 2022-08-11. This file is deprecated. + +import "./EIP712.sol"; diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/ConditionalEscrow.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/ConditionalEscrow.sol new file mode 100644 index 0000000..87f5381 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/ConditionalEscrow.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/escrow/ConditionalEscrow.sol) + +pragma solidity ^0.8.0; + +import "./Escrow.sol"; + +/** + * @title ConditionalEscrow + * @dev Base abstract escrow to only allow withdrawal if a condition is met. + * @dev Intended usage: See {Escrow}. Same usage guidelines apply here. + */ +abstract contract ConditionalEscrow is Escrow { + /** + * @dev Returns whether an address is allowed to withdraw their funds. To be + * implemented by derived contracts. + * @param payee The destination address of the funds. + */ + function withdrawalAllowed(address payee) public view virtual returns (bool); + + function withdraw(address payable payee) public virtual override { + require(withdrawalAllowed(payee), "ConditionalEscrow: payee is not allowed to withdraw"); + super.withdraw(payee); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/Escrow.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/Escrow.sol new file mode 100644 index 0000000..48dd51a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/Escrow.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (utils/escrow/Escrow.sol) + +pragma solidity ^0.8.0; + +import "../../access/Ownable.sol"; +import "../Address.sol"; + +/** + * @title Escrow + * @dev Base escrow contract, holds funds designated for a payee until they + * withdraw them. + * + * Intended usage: This contract (and derived escrow contracts) should be a + * standalone contract, that only interacts with the contract that instantiated + * it. That way, it is guaranteed that all Ether will be handled according to + * the `Escrow` rules, and there is no need to check for payable functions or + * transfers in the inheritance tree. The contract that uses the escrow as its + * payment method should be its owner, and provide public methods redirecting + * to the escrow's deposit and withdraw. + */ +contract Escrow is Ownable { + using Address for address payable; + + event Deposited(address indexed payee, uint256 weiAmount); + event Withdrawn(address indexed payee, uint256 weiAmount); + + mapping(address => uint256) private _deposits; + + function depositsOf(address payee) public view returns (uint256) { + return _deposits[payee]; + } + + /** + * @dev Stores the sent amount as credit to be withdrawn. + * @param payee The destination address of the funds. + * + * Emits a {Deposited} event. + */ + function deposit(address payee) public payable virtual onlyOwner { + uint256 amount = msg.value; + _deposits[payee] += amount; + emit Deposited(payee, amount); + } + + /** + * @dev Withdraw accumulated balance for a payee, forwarding all gas to the + * recipient. + * + * WARNING: Forwarding all gas opens the door to reentrancy vulnerabilities. + * Make sure you trust the recipient, or are either following the + * checks-effects-interactions pattern or using {ReentrancyGuard}. + * + * @param payee The address whose funds will be withdrawn and transferred to. + * + * Emits a {Withdrawn} event. + */ + function withdraw(address payable payee) public virtual onlyOwner { + uint256 payment = _deposits[payee]; + + _deposits[payee] = 0; + + payee.sendValue(payment); + + emit Withdrawn(payee, payment); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/RefundEscrow.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/RefundEscrow.sol new file mode 100644 index 0000000..0e9621f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/escrow/RefundEscrow.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/escrow/RefundEscrow.sol) + +pragma solidity ^0.8.0; + +import "./ConditionalEscrow.sol"; + +/** + * @title RefundEscrow + * @dev Escrow that holds funds for a beneficiary, deposited from multiple + * parties. + * @dev Intended usage: See {Escrow}. Same usage guidelines apply here. + * @dev The owner account (that is, the contract that instantiates this + * contract) may deposit, close the deposit period, and allow for either + * withdrawal by the beneficiary, or refunds to the depositors. All interactions + * with `RefundEscrow` will be made through the owner contract. + */ +contract RefundEscrow is ConditionalEscrow { + using Address for address payable; + + enum State { + Active, + Refunding, + Closed + } + + event RefundsClosed(); + event RefundsEnabled(); + + State private _state; + address payable private immutable _beneficiary; + + /** + * @dev Constructor. + * @param beneficiary_ The beneficiary of the deposits. + */ + constructor(address payable beneficiary_) { + require(beneficiary_ != address(0), "RefundEscrow: beneficiary is the zero address"); + _beneficiary = beneficiary_; + _state = State.Active; + } + + /** + * @return The current state of the escrow. + */ + function state() public view virtual returns (State) { + return _state; + } + + /** + * @return The beneficiary of the escrow. + */ + function beneficiary() public view virtual returns (address payable) { + return _beneficiary; + } + + /** + * @dev Stores funds that may later be refunded. + * @param refundee The address funds will be sent to if a refund occurs. + */ + function deposit(address refundee) public payable virtual override { + require(state() == State.Active, "RefundEscrow: can only deposit while active"); + super.deposit(refundee); + } + + /** + * @dev Allows for the beneficiary to withdraw their funds, rejecting + * further deposits. + */ + function close() public virtual onlyOwner { + require(state() == State.Active, "RefundEscrow: can only close while active"); + _state = State.Closed; + emit RefundsClosed(); + } + + /** + * @dev Allows for refunds to take place, rejecting further deposits. + */ + function enableRefunds() public virtual onlyOwner { + require(state() == State.Active, "RefundEscrow: can only enable refunds while active"); + _state = State.Refunding; + emit RefundsEnabled(); + } + + /** + * @dev Withdraws the beneficiary's funds. + */ + function beneficiaryWithdraw() public virtual { + require(state() == State.Closed, "RefundEscrow: beneficiary can only withdraw while closed"); + beneficiary().sendValue(address(this).balance); + } + + /** + * @dev Returns whether refundees can withdraw their deposits (be refunded). The overridden function receives a + * 'payee' argument, but we ignore it here since the condition is global, not per-payee. + */ + function withdrawalAllowed(address) public view override returns (bool) { + return state() == State.Refunding; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165.sol new file mode 100644 index 0000000..3bf5613 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165Checker.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165Checker.sol new file mode 100644 index 0000000..4831b65 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165Checker.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/introspection/ERC165Checker.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Library used to query support of an interface declared via {IERC165}. + * + * Note that these functions return the actual result of the query: they do not + * `revert` if an interface is not supported. It is up to the caller to decide + * what to do in these cases. + */ +library ERC165Checker { + // As per the EIP-165 spec, no interface should ever match 0xffffffff + bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; + + /** + * @dev Returns true if `account` supports the {IERC165} interface. + */ + function supportsERC165(address account) internal view returns (bool) { + // Any contract that implements ERC165 must explicitly indicate support of + // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid + return + supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && + !supportsERC165InterfaceUnchecked(account, _INTERFACE_ID_INVALID); + } + + /** + * @dev Returns true if `account` supports the interface defined by + * `interfaceId`. Support for {IERC165} itself is queried automatically. + * + * See {IERC165-supportsInterface}. + */ + function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { + // query support of both ERC165 as per the spec and support of _interfaceId + return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); + } + + /** + * @dev Returns a boolean array where each value corresponds to the + * interfaces passed in and whether they're supported or not. This allows + * you to batch check interfaces for a contract where your expectation + * is that some interfaces may not be supported. + * + * See {IERC165-supportsInterface}. + * + * _Available since v3.4._ + */ + function getSupportedInterfaces( + address account, + bytes4[] memory interfaceIds + ) internal view returns (bool[] memory) { + // an array of booleans corresponding to interfaceIds and whether they're supported or not + bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); + + // query support of ERC165 itself + if (supportsERC165(account)) { + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); + } + } + + return interfaceIdsSupported; + } + + /** + * @dev Returns true if `account` supports all the interfaces defined in + * `interfaceIds`. Support for {IERC165} itself is queried automatically. + * + * Batch-querying can lead to gas savings by skipping repeated checks for + * {IERC165} support. + * + * See {IERC165-supportsInterface}. + */ + function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { + // query support of ERC165 itself + if (!supportsERC165(account)) { + return false; + } + + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { + return false; + } + } + + // all interfaces supported + return true; + } + + /** + * @notice Query if a contract implements an interface, does not check ERC165 support + * @param account The address of the contract to query for support of an interface + * @param interfaceId The interface identifier, as specified in ERC-165 + * @return true if the contract at account indicates support of the interface with + * identifier interfaceId, false otherwise + * @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) { + // prepare call + bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); + + // perform static call + bool success; + uint256 returnSize; + uint256 returnValue; + assembly { + success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) + returnSize := returndatasize() + returnValue := mload(0x00) + } + + return success && returnSize >= 0x20 && returnValue > 0; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165Storage.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165Storage.sol new file mode 100644 index 0000000..c99d9f3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC165Storage.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Storage.sol) + +pragma solidity ^0.8.0; + +import "./ERC165.sol"; + +/** + * @dev Storage based implementation of the {IERC165} interface. + * + * Contracts may inherit from this and call {_registerInterface} to declare + * their support of an interface. + */ +abstract contract ERC165Storage is ERC165 { + /** + * @dev Mapping of interface ids to whether or not it's supported. + */ + mapping(bytes4 => bool) private _supportedInterfaces; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId]; + } + + /** + * @dev Registers the contract as an implementer of the interface defined by + * `interfaceId`. Support of the actual ERC165 interface is automatic and + * registering its interface id is not required. + * + * See {IERC165-supportsInterface}. + * + * Requirements: + * + * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). + */ + function _registerInterface(bytes4 interfaceId) internal virtual { + require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); + _supportedInterfaces[interfaceId] = true; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC1820Implementer.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC1820Implementer.sol new file mode 100644 index 0000000..7a684ed --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/ERC1820Implementer.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/introspection/ERC1820Implementer.sol) + +pragma solidity ^0.8.0; + +import "./IERC1820Implementer.sol"; + +/** + * @dev Implementation of the {IERC1820Implementer} interface. + * + * Contracts may inherit from this and call {_registerInterfaceForAddress} to + * 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"); + + mapping(bytes32 => mapping(address => bool)) private _supportedInterfaces; + + /** + * @dev See {IERC1820Implementer-canImplementInterfaceForAddress}. + */ + function canImplementInterfaceForAddress( + bytes32 interfaceHash, + address account + ) public view virtual override returns (bytes32) { + return _supportedInterfaces[interfaceHash][account] ? _ERC1820_ACCEPT_MAGIC : bytes32(0x00); + } + + /** + * @dev Declares the contract as willing to be an implementer of + * `interfaceHash` for `account`. + * + * See {IERC1820Registry-setInterfaceImplementer} and + * {IERC1820Registry-interfaceHash}. + */ + function _registerInterfaceForAddress(bytes32 interfaceHash, address account) internal virtual { + _supportedInterfaces[interfaceHash][account] = true; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC165.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC165.sol new file mode 100644 index 0000000..e8cdbdb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC1820Implementer.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC1820Implementer.sol new file mode 100644 index 0000000..c4d0b30 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC1820Implementer.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC1820Implementer.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface for an ERC1820 implementer, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[EIP]. + * Used by contracts that will be registered as implementers in the + * {IERC1820Registry}. + */ +interface IERC1820Implementer { + /** + * @dev Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract + * implements `interfaceHash` for `account`. + * + * See {IERC1820Registry-setInterfaceImplementer}. + */ + function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC1820Registry.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC1820Registry.sol new file mode 100644 index 0000000..922df04 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/introspection/IERC1820Registry.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/introspection/IERC1820Registry.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the global ERC1820 Registry, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register + * implementers for interfaces in this registry, as well as query support. + * + * Implementers may be shared by multiple accounts, and can also implement more + * than a single interface for each account. Contracts can implement interfaces + * for themselves, but externally-owned accounts (EOA) must delegate this to a + * contract. + * + * {IERC165} interfaces can also be queried via the registry. + * + * For an in-depth explanation and source code analysis, see the EIP text. + */ +interface IERC1820Registry { + event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer); + + event ManagerChanged(address indexed account, address indexed newManager); + + /** + * @dev Sets `newManager` as the manager for `account`. A manager of an + * account is able to set interface implementers for it. + * + * By default, each account is its own manager. Passing a value of `0x0` in + * `newManager` will reset the manager to this initial state. + * + * Emits a {ManagerChanged} event. + * + * Requirements: + * + * - the caller must be the current manager for `account`. + */ + function setManager(address account, address newManager) external; + + /** + * @dev Returns the manager for `account`. + * + * See {setManager}. + */ + function getManager(address account) external view returns (address); + + /** + * @dev Sets the `implementer` contract as ``account``'s implementer for + * `interfaceHash`. + * + * `account` being the zero address is an alias for the caller's address. + * The zero address can also be used in `implementer` to remove an old one. + * + * See {interfaceHash} to learn how these are created. + * + * Emits an {InterfaceImplementerSet} event. + * + * Requirements: + * + * - the caller must be the current manager for `account`. + * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not + * end in 28 zeroes). + * - `implementer` must implement {IERC1820Implementer} and return true when + * queried for support, unless `implementer` is the caller. See + * {IERC1820Implementer-canImplementInterfaceForAddress}. + */ + function setInterfaceImplementer(address account, bytes32 _interfaceHash, address implementer) external; + + /** + * @dev Returns the implementer of `interfaceHash` for `account`. If no such + * implementer is registered, returns the zero address. + * + * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28 + * zeroes), `account` will be queried for support of it. + * + * `account` being the zero address is an alias for the caller's address. + */ + function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address); + + /** + * @dev Returns the interface hash for an `interfaceName`, as defined in the + * corresponding + * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP]. + */ + function interfaceHash(string calldata interfaceName) external pure returns (bytes32); + + /** + * @notice Updates the cache with whether the contract implements an ERC165 interface or not. + * @param account Address of the contract for which to update the cache. + * @param interfaceId ERC165 interface for which to update the cache. + */ + function updateERC165Cache(address account, bytes4 interfaceId) external; + + /** + * @notice Checks whether a contract implements an ERC165 interface or not. + * If the result is not cached a direct lookup on the contract address is performed. + * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling + * {updateERC165Cache} with the contract address. + * @param account Address of the contract to check. + * @param interfaceId ERC165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); + + /** + * @notice Checks whether a contract implements an ERC165 interface or not without using or updating the cache. + * @param account Address of the contract to check. + * @param interfaceId ERC165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/Math.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/Math.sol new file mode 100644 index 0000000..551b1a5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/Math.sol @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Down, // Toward negative infinity + Up, // Toward infinity + Zero // Toward zero + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds up instead + * of rounding down. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) + * with further edits by Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod0 := mul(x, y) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // 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; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1, "Math: mulDiv overflow"); + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. + // See https://cs.stackexchange.com/q/138556/92363. + + // Does not overflow because the denominator cannot be zero at this stage in the function. + uint256 twos = denominator & (~denominator + 1); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works + // in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SafeCast.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SafeCast.sol new file mode 100644 index 0000000..435a5f9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SafeCast.sol @@ -0,0 +1,1136 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol) +// This file was procedurally generated from scripts/generate/templates/SafeCast.js. + +pragma solidity ^0.8.0; + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. `SafeCast` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + * + * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing + * all math on `uint256` and `int256` and then downcasting. + */ +library SafeCast { + /** + * @dev Returns the downcasted uint248 from uint256, reverting on + * overflow (when the input is greater than largest uint248). + * + * Counterpart to Solidity's `uint248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + * + * _Available since v4.7._ + */ + function toUint248(uint256 value) internal pure returns (uint248) { + require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits"); + return uint248(value); + } + + /** + * @dev Returns the downcasted uint240 from uint256, reverting on + * overflow (when the input is greater than largest uint240). + * + * Counterpart to Solidity's `uint240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + * + * _Available since v4.7._ + */ + function toUint240(uint256 value) internal pure returns (uint240) { + require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits"); + return uint240(value); + } + + /** + * @dev Returns the downcasted uint232 from uint256, reverting on + * overflow (when the input is greater than largest uint232). + * + * Counterpart to Solidity's `uint232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + * + * _Available since v4.7._ + */ + function toUint232(uint256 value) internal pure returns (uint232) { + require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits"); + return uint232(value); + } + + /** + * @dev Returns the downcasted uint224 from uint256, reverting on + * overflow (when the input is greater than largest uint224). + * + * Counterpart to Solidity's `uint224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + * + * _Available since v4.2._ + */ + function toUint224(uint256 value) internal pure returns (uint224) { + require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits"); + return uint224(value); + } + + /** + * @dev Returns the downcasted uint216 from uint256, reverting on + * overflow (when the input is greater than largest uint216). + * + * Counterpart to Solidity's `uint216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + * + * _Available since v4.7._ + */ + function toUint216(uint256 value) internal pure returns (uint216) { + require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits"); + return uint216(value); + } + + /** + * @dev Returns the downcasted uint208 from uint256, reverting on + * overflow (when the input is greater than largest uint208). + * + * Counterpart to Solidity's `uint208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + * + * _Available since v4.7._ + */ + function toUint208(uint256 value) internal pure returns (uint208) { + require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits"); + return uint208(value); + } + + /** + * @dev Returns the downcasted uint200 from uint256, reverting on + * overflow (when the input is greater than largest uint200). + * + * Counterpart to Solidity's `uint200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + * + * _Available since v4.7._ + */ + function toUint200(uint256 value) internal pure returns (uint200) { + require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits"); + return uint200(value); + } + + /** + * @dev Returns the downcasted uint192 from uint256, reverting on + * overflow (when the input is greater than largest uint192). + * + * Counterpart to Solidity's `uint192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + * + * _Available since v4.7._ + */ + function toUint192(uint256 value) internal pure returns (uint192) { + require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits"); + return uint192(value); + } + + /** + * @dev Returns the downcasted uint184 from uint256, reverting on + * overflow (when the input is greater than largest uint184). + * + * Counterpart to Solidity's `uint184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + * + * _Available since v4.7._ + */ + function toUint184(uint256 value) internal pure returns (uint184) { + require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits"); + return uint184(value); + } + + /** + * @dev Returns the downcasted uint176 from uint256, reverting on + * overflow (when the input is greater than largest uint176). + * + * Counterpart to Solidity's `uint176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + * + * _Available since v4.7._ + */ + function toUint176(uint256 value) internal pure returns (uint176) { + require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits"); + return uint176(value); + } + + /** + * @dev Returns the downcasted uint168 from uint256, reverting on + * overflow (when the input is greater than largest uint168). + * + * Counterpart to Solidity's `uint168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + * + * _Available since v4.7._ + */ + function toUint168(uint256 value) internal pure returns (uint168) { + require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits"); + return uint168(value); + } + + /** + * @dev Returns the downcasted uint160 from uint256, reverting on + * overflow (when the input is greater than largest uint160). + * + * Counterpart to Solidity's `uint160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + * + * _Available since v4.7._ + */ + function toUint160(uint256 value) internal pure returns (uint160) { + require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits"); + return uint160(value); + } + + /** + * @dev Returns the downcasted uint152 from uint256, reverting on + * overflow (when the input is greater than largest uint152). + * + * Counterpart to Solidity's `uint152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + * + * _Available since v4.7._ + */ + function toUint152(uint256 value) internal pure returns (uint152) { + require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits"); + return uint152(value); + } + + /** + * @dev Returns the downcasted uint144 from uint256, reverting on + * overflow (when the input is greater than largest uint144). + * + * Counterpart to Solidity's `uint144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + * + * _Available since v4.7._ + */ + function toUint144(uint256 value) internal pure returns (uint144) { + require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits"); + return uint144(value); + } + + /** + * @dev Returns the downcasted uint136 from uint256, reverting on + * overflow (when the input is greater than largest uint136). + * + * Counterpart to Solidity's `uint136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + * + * _Available since v4.7._ + */ + function toUint136(uint256 value) internal pure returns (uint136) { + require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits"); + return uint136(value); + } + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + * + * _Available since v2.5._ + */ + function toUint128(uint256 value) internal pure returns (uint128) { + require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits"); + return uint128(value); + } + + /** + * @dev Returns the downcasted uint120 from uint256, reverting on + * overflow (when the input is greater than largest uint120). + * + * Counterpart to Solidity's `uint120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + * + * _Available since v4.7._ + */ + function toUint120(uint256 value) internal pure returns (uint120) { + require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits"); + return uint120(value); + } + + /** + * @dev Returns the downcasted uint112 from uint256, reverting on + * overflow (when the input is greater than largest uint112). + * + * Counterpart to Solidity's `uint112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + * + * _Available since v4.7._ + */ + function toUint112(uint256 value) internal pure returns (uint112) { + require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits"); + return uint112(value); + } + + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + * + * _Available since v4.7._ + */ + function toUint104(uint256 value) internal pure returns (uint104) { + require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits"); + return uint104(value); + } + + /** + * @dev Returns the downcasted uint96 from uint256, reverting on + * overflow (when the input is greater than largest uint96). + * + * Counterpart to Solidity's `uint96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + * + * _Available since v4.2._ + */ + function toUint96(uint256 value) internal pure returns (uint96) { + require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits"); + return uint96(value); + } + + /** + * @dev Returns the downcasted uint88 from uint256, reverting on + * overflow (when the input is greater than largest uint88). + * + * Counterpart to Solidity's `uint88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + * + * _Available since v4.7._ + */ + function toUint88(uint256 value) internal pure returns (uint88) { + require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits"); + return uint88(value); + } + + /** + * @dev Returns the downcasted uint80 from uint256, reverting on + * overflow (when the input is greater than largest uint80). + * + * Counterpart to Solidity's `uint80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + * + * _Available since v4.7._ + */ + function toUint80(uint256 value) internal pure returns (uint80) { + require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits"); + return uint80(value); + } + + /** + * @dev Returns the downcasted uint72 from uint256, reverting on + * overflow (when the input is greater than largest uint72). + * + * Counterpart to Solidity's `uint72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + * + * _Available since v4.7._ + */ + function toUint72(uint256 value) internal pure returns (uint72) { + require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits"); + return uint72(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + * + * _Available since v2.5._ + */ + function toUint64(uint256 value) internal pure returns (uint64) { + require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits"); + return uint64(value); + } + + /** + * @dev Returns the downcasted uint56 from uint256, reverting on + * overflow (when the input is greater than largest uint56). + * + * Counterpart to Solidity's `uint56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + * + * _Available since v4.7._ + */ + function toUint56(uint256 value) internal pure returns (uint56) { + require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits"); + return uint56(value); + } + + /** + * @dev Returns the downcasted uint48 from uint256, reverting on + * overflow (when the input is greater than largest uint48). + * + * Counterpart to Solidity's `uint48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + * + * _Available since v4.7._ + */ + function toUint48(uint256 value) internal pure returns (uint48) { + require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits"); + return uint48(value); + } + + /** + * @dev Returns the downcasted uint40 from uint256, reverting on + * overflow (when the input is greater than largest uint40). + * + * Counterpart to Solidity's `uint40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + * + * _Available since v4.7._ + */ + function toUint40(uint256 value) internal pure returns (uint40) { + require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits"); + return uint40(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + * + * _Available since v2.5._ + */ + function toUint32(uint256 value) internal pure returns (uint32) { + require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits"); + return uint32(value); + } + + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + * + * _Available since v4.7._ + */ + function toUint24(uint256 value) internal pure returns (uint24) { + require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits"); + return uint24(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + * + * _Available since v2.5._ + */ + function toUint16(uint256 value) internal pure returns (uint16) { + require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits"); + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + * + * _Available since v2.5._ + */ + function toUint8(uint256 value) internal pure returns (uint8) { + require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits"); + return uint8(value); + } + + /** + * @dev Converts a signed int256 into an unsigned uint256. + * + * Requirements: + * + * - input must be greater than or equal to 0. + * + * _Available since v3.0._ + */ + function toUint256(int256 value) internal pure returns (uint256) { + require(value >= 0, "SafeCast: value must be positive"); + return uint256(value); + } + + /** + * @dev Returns the downcasted int248 from int256, reverting on + * overflow (when the input is less than smallest int248 or + * greater than largest int248). + * + * Counterpart to Solidity's `int248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + * + * _Available since v4.7._ + */ + function toInt248(int256 value) internal pure returns (int248 downcasted) { + downcasted = int248(value); + require(downcasted == value, "SafeCast: value doesn't fit in 248 bits"); + } + + /** + * @dev Returns the downcasted int240 from int256, reverting on + * overflow (when the input is less than smallest int240 or + * greater than largest int240). + * + * Counterpart to Solidity's `int240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + * + * _Available since v4.7._ + */ + function toInt240(int256 value) internal pure returns (int240 downcasted) { + downcasted = int240(value); + require(downcasted == value, "SafeCast: value doesn't fit in 240 bits"); + } + + /** + * @dev Returns the downcasted int232 from int256, reverting on + * overflow (when the input is less than smallest int232 or + * greater than largest int232). + * + * Counterpart to Solidity's `int232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + * + * _Available since v4.7._ + */ + function toInt232(int256 value) internal pure returns (int232 downcasted) { + downcasted = int232(value); + require(downcasted == value, "SafeCast: value doesn't fit in 232 bits"); + } + + /** + * @dev Returns the downcasted int224 from int256, reverting on + * overflow (when the input is less than smallest int224 or + * greater than largest int224). + * + * Counterpart to Solidity's `int224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + * + * _Available since v4.7._ + */ + function toInt224(int256 value) internal pure returns (int224 downcasted) { + downcasted = int224(value); + require(downcasted == value, "SafeCast: value doesn't fit in 224 bits"); + } + + /** + * @dev Returns the downcasted int216 from int256, reverting on + * overflow (when the input is less than smallest int216 or + * greater than largest int216). + * + * Counterpart to Solidity's `int216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + * + * _Available since v4.7._ + */ + function toInt216(int256 value) internal pure returns (int216 downcasted) { + downcasted = int216(value); + require(downcasted == value, "SafeCast: value doesn't fit in 216 bits"); + } + + /** + * @dev Returns the downcasted int208 from int256, reverting on + * overflow (when the input is less than smallest int208 or + * greater than largest int208). + * + * Counterpart to Solidity's `int208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + * + * _Available since v4.7._ + */ + function toInt208(int256 value) internal pure returns (int208 downcasted) { + downcasted = int208(value); + require(downcasted == value, "SafeCast: value doesn't fit in 208 bits"); + } + + /** + * @dev Returns the downcasted int200 from int256, reverting on + * overflow (when the input is less than smallest int200 or + * greater than largest int200). + * + * Counterpart to Solidity's `int200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + * + * _Available since v4.7._ + */ + function toInt200(int256 value) internal pure returns (int200 downcasted) { + downcasted = int200(value); + require(downcasted == value, "SafeCast: value doesn't fit in 200 bits"); + } + + /** + * @dev Returns the downcasted int192 from int256, reverting on + * overflow (when the input is less than smallest int192 or + * greater than largest int192). + * + * Counterpart to Solidity's `int192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + * + * _Available since v4.7._ + */ + function toInt192(int256 value) internal pure returns (int192 downcasted) { + downcasted = int192(value); + require(downcasted == value, "SafeCast: value doesn't fit in 192 bits"); + } + + /** + * @dev Returns the downcasted int184 from int256, reverting on + * overflow (when the input is less than smallest int184 or + * greater than largest int184). + * + * Counterpart to Solidity's `int184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + * + * _Available since v4.7._ + */ + function toInt184(int256 value) internal pure returns (int184 downcasted) { + downcasted = int184(value); + require(downcasted == value, "SafeCast: value doesn't fit in 184 bits"); + } + + /** + * @dev Returns the downcasted int176 from int256, reverting on + * overflow (when the input is less than smallest int176 or + * greater than largest int176). + * + * Counterpart to Solidity's `int176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + * + * _Available since v4.7._ + */ + function toInt176(int256 value) internal pure returns (int176 downcasted) { + downcasted = int176(value); + require(downcasted == value, "SafeCast: value doesn't fit in 176 bits"); + } + + /** + * @dev Returns the downcasted int168 from int256, reverting on + * overflow (when the input is less than smallest int168 or + * greater than largest int168). + * + * Counterpart to Solidity's `int168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + * + * _Available since v4.7._ + */ + function toInt168(int256 value) internal pure returns (int168 downcasted) { + downcasted = int168(value); + require(downcasted == value, "SafeCast: value doesn't fit in 168 bits"); + } + + /** + * @dev Returns the downcasted int160 from int256, reverting on + * overflow (when the input is less than smallest int160 or + * greater than largest int160). + * + * Counterpart to Solidity's `int160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + * + * _Available since v4.7._ + */ + function toInt160(int256 value) internal pure returns (int160 downcasted) { + downcasted = int160(value); + require(downcasted == value, "SafeCast: value doesn't fit in 160 bits"); + } + + /** + * @dev Returns the downcasted int152 from int256, reverting on + * overflow (when the input is less than smallest int152 or + * greater than largest int152). + * + * Counterpart to Solidity's `int152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + * + * _Available since v4.7._ + */ + function toInt152(int256 value) internal pure returns (int152 downcasted) { + downcasted = int152(value); + require(downcasted == value, "SafeCast: value doesn't fit in 152 bits"); + } + + /** + * @dev Returns the downcasted int144 from int256, reverting on + * overflow (when the input is less than smallest int144 or + * greater than largest int144). + * + * Counterpart to Solidity's `int144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + * + * _Available since v4.7._ + */ + function toInt144(int256 value) internal pure returns (int144 downcasted) { + downcasted = int144(value); + require(downcasted == value, "SafeCast: value doesn't fit in 144 bits"); + } + + /** + * @dev Returns the downcasted int136 from int256, reverting on + * overflow (when the input is less than smallest int136 or + * greater than largest int136). + * + * Counterpart to Solidity's `int136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + * + * _Available since v4.7._ + */ + function toInt136(int256 value) internal pure returns (int136 downcasted) { + downcasted = int136(value); + require(downcasted == value, "SafeCast: value doesn't fit in 136 bits"); + } + + /** + * @dev Returns the downcasted int128 from int256, reverting on + * overflow (when the input is less than smallest int128 or + * greater than largest int128). + * + * Counterpart to Solidity's `int128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + * + * _Available since v3.1._ + */ + function toInt128(int256 value) internal pure returns (int128 downcasted) { + downcasted = int128(value); + require(downcasted == value, "SafeCast: value doesn't fit in 128 bits"); + } + + /** + * @dev Returns the downcasted int120 from int256, reverting on + * overflow (when the input is less than smallest int120 or + * greater than largest int120). + * + * Counterpart to Solidity's `int120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + * + * _Available since v4.7._ + */ + function toInt120(int256 value) internal pure returns (int120 downcasted) { + downcasted = int120(value); + require(downcasted == value, "SafeCast: value doesn't fit in 120 bits"); + } + + /** + * @dev Returns the downcasted int112 from int256, reverting on + * overflow (when the input is less than smallest int112 or + * greater than largest int112). + * + * Counterpart to Solidity's `int112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + * + * _Available since v4.7._ + */ + function toInt112(int256 value) internal pure returns (int112 downcasted) { + downcasted = int112(value); + require(downcasted == value, "SafeCast: value doesn't fit in 112 bits"); + } + + /** + * @dev Returns the downcasted int104 from int256, reverting on + * overflow (when the input is less than smallest int104 or + * greater than largest int104). + * + * Counterpart to Solidity's `int104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + * + * _Available since v4.7._ + */ + function toInt104(int256 value) internal pure returns (int104 downcasted) { + downcasted = int104(value); + require(downcasted == value, "SafeCast: value doesn't fit in 104 bits"); + } + + /** + * @dev Returns the downcasted int96 from int256, reverting on + * overflow (when the input is less than smallest int96 or + * greater than largest int96). + * + * Counterpart to Solidity's `int96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + * + * _Available since v4.7._ + */ + function toInt96(int256 value) internal pure returns (int96 downcasted) { + downcasted = int96(value); + require(downcasted == value, "SafeCast: value doesn't fit in 96 bits"); + } + + /** + * @dev Returns the downcasted int88 from int256, reverting on + * overflow (when the input is less than smallest int88 or + * greater than largest int88). + * + * Counterpart to Solidity's `int88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + * + * _Available since v4.7._ + */ + function toInt88(int256 value) internal pure returns (int88 downcasted) { + downcasted = int88(value); + require(downcasted == value, "SafeCast: value doesn't fit in 88 bits"); + } + + /** + * @dev Returns the downcasted int80 from int256, reverting on + * overflow (when the input is less than smallest int80 or + * greater than largest int80). + * + * Counterpart to Solidity's `int80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + * + * _Available since v4.7._ + */ + function toInt80(int256 value) internal pure returns (int80 downcasted) { + downcasted = int80(value); + require(downcasted == value, "SafeCast: value doesn't fit in 80 bits"); + } + + /** + * @dev Returns the downcasted int72 from int256, reverting on + * overflow (when the input is less than smallest int72 or + * greater than largest int72). + * + * Counterpart to Solidity's `int72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + * + * _Available since v4.7._ + */ + function toInt72(int256 value) internal pure returns (int72 downcasted) { + downcasted = int72(value); + require(downcasted == value, "SafeCast: value doesn't fit in 72 bits"); + } + + /** + * @dev Returns the downcasted int64 from int256, reverting on + * overflow (when the input is less than smallest int64 or + * greater than largest int64). + * + * Counterpart to Solidity's `int64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + * + * _Available since v3.1._ + */ + function toInt64(int256 value) internal pure returns (int64 downcasted) { + downcasted = int64(value); + require(downcasted == value, "SafeCast: value doesn't fit in 64 bits"); + } + + /** + * @dev Returns the downcasted int56 from int256, reverting on + * overflow (when the input is less than smallest int56 or + * greater than largest int56). + * + * Counterpart to Solidity's `int56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + * + * _Available since v4.7._ + */ + function toInt56(int256 value) internal pure returns (int56 downcasted) { + downcasted = int56(value); + require(downcasted == value, "SafeCast: value doesn't fit in 56 bits"); + } + + /** + * @dev Returns the downcasted int48 from int256, reverting on + * overflow (when the input is less than smallest int48 or + * greater than largest int48). + * + * Counterpart to Solidity's `int48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + * + * _Available since v4.7._ + */ + function toInt48(int256 value) internal pure returns (int48 downcasted) { + downcasted = int48(value); + require(downcasted == value, "SafeCast: value doesn't fit in 48 bits"); + } + + /** + * @dev Returns the downcasted int40 from int256, reverting on + * overflow (when the input is less than smallest int40 or + * greater than largest int40). + * + * Counterpart to Solidity's `int40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + * + * _Available since v4.7._ + */ + function toInt40(int256 value) internal pure returns (int40 downcasted) { + downcasted = int40(value); + require(downcasted == value, "SafeCast: value doesn't fit in 40 bits"); + } + + /** + * @dev Returns the downcasted int32 from int256, reverting on + * overflow (when the input is less than smallest int32 or + * greater than largest int32). + * + * Counterpart to Solidity's `int32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + * + * _Available since v3.1._ + */ + function toInt32(int256 value) internal pure returns (int32 downcasted) { + downcasted = int32(value); + require(downcasted == value, "SafeCast: value doesn't fit in 32 bits"); + } + + /** + * @dev Returns the downcasted int24 from int256, reverting on + * overflow (when the input is less than smallest int24 or + * greater than largest int24). + * + * Counterpart to Solidity's `int24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + * + * _Available since v4.7._ + */ + function toInt24(int256 value) internal pure returns (int24 downcasted) { + downcasted = int24(value); + require(downcasted == value, "SafeCast: value doesn't fit in 24 bits"); + } + + /** + * @dev Returns the downcasted int16 from int256, reverting on + * overflow (when the input is less than smallest int16 or + * greater than largest int16). + * + * Counterpart to Solidity's `int16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + * + * _Available since v3.1._ + */ + function toInt16(int256 value) internal pure returns (int16 downcasted) { + downcasted = int16(value); + require(downcasted == value, "SafeCast: value doesn't fit in 16 bits"); + } + + /** + * @dev Returns the downcasted int8 from int256, reverting on + * overflow (when the input is less than smallest int8 or + * greater than largest int8). + * + * Counterpart to Solidity's `int8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + * + * _Available since v3.1._ + */ + function toInt8(int256 value) internal pure returns (int8 downcasted) { + downcasted = int8(value); + require(downcasted == value, "SafeCast: value doesn't fit in 8 bits"); + } + + /** + * @dev Converts an unsigned uint256 into a signed int256. + * + * Requirements: + * + * - input must be less than or equal to maxInt256. + * + * _Available since v3.0._ + */ + function toInt256(uint256 value) internal pure returns (int256) { + // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive + require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256"); + return int256(value); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SafeMath.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SafeMath.sol new file mode 100644 index 0000000..f7315a6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SafeMath.sol @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol) + +pragma solidity ^0.8.0; + +// CAUTION +// This version of SafeMath should only be used with Solidity 0.8 or later, +// because it relies on the compiler's built in overflow checks. + +/** + * @dev Wrappers over Solidity's arithmetic operations. + * + * NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler + * now has built in overflow checking. + */ +library SafeMath { + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + * + * _Available since v3.4._ + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + * + * _Available since v3.4._ + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the addition of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(uint256 a, uint256 b) internal pure returns (uint256) { + return a + b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting on + * overflow (when the result is negative). + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b) internal pure returns (uint256) { + return a - b; + } + + /** + * @dev Returns the multiplication of two unsigned integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(uint256 a, uint256 b) internal pure returns (uint256) { + return a * b; + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b) internal pure returns (uint256) { + return a / b; + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting when dividing by zero. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b) internal pure returns (uint256) { + return a % b; + } + + /** + * @dev Returns the subtraction of two unsigned integers, reverting with custom message on + * overflow (when the result is negative). + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {trySub}. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + unchecked { + require(b <= a, errorMessage); + return a - b; + } + } + + /** + * @dev Returns the integer division of two unsigned integers, reverting with custom message on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. Note: this function uses a + * `revert` opcode (which leaves remaining gas untouched) while Solidity + * uses an invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + unchecked { + require(b > 0, errorMessage); + return a / b; + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), + * reverting with custom message when dividing by zero. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryMod}. + * + * Counterpart to Solidity's `%` operator. This function uses a `revert` + * opcode (which leaves remaining gas untouched) while Solidity uses an + * invalid opcode to revert (consuming all remaining gas). + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { + unchecked { + require(b > 0, errorMessage); + return a % b; + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SignedMath.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SignedMath.sol new file mode 100644 index 0000000..3ea9f8b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SignedMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SignedSafeMath.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SignedSafeMath.sol new file mode 100644 index 0000000..6704d4c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/math/SignedSafeMath.sol @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/math/SignedSafeMath.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Wrappers over Solidity's arithmetic operations. + * + * NOTE: `SignedSafeMath` is no longer needed starting with Solidity 0.8. The compiler + * now has built in overflow checking. + */ +library SignedSafeMath { + /** + * @dev Returns the multiplication of two signed integers, reverting on + * overflow. + * + * Counterpart to Solidity's `*` operator. + * + * Requirements: + * + * - Multiplication cannot overflow. + */ + function mul(int256 a, int256 b) internal pure returns (int256) { + return a * b; + } + + /** + * @dev Returns the integer division of two signed integers. Reverts on + * division by zero. The result is rounded towards zero. + * + * Counterpart to Solidity's `/` operator. + * + * Requirements: + * + * - The divisor cannot be zero. + */ + function div(int256 a, int256 b) internal pure returns (int256) { + return a / b; + } + + /** + * @dev Returns the subtraction of two signed integers, reverting on + * overflow. + * + * Counterpart to Solidity's `-` operator. + * + * Requirements: + * + * - Subtraction cannot overflow. + */ + function sub(int256 a, int256 b) internal pure returns (int256) { + return a - b; + } + + /** + * @dev Returns the addition of two signed integers, reverting on + * overflow. + * + * Counterpart to Solidity's `+` operator. + * + * Requirements: + * + * - Addition cannot overflow. + */ + function add(int256 a, int256 b) internal pure returns (int256) { + return a + b; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/BitMaps.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/BitMaps.sol new file mode 100644 index 0000000..2567fce --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/BitMaps.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/BitMaps.sol) +pragma solidity ^0.8.0; + +/** + * @dev Library for managing uint256 to bool mapping in a compact and efficient way, providing the keys are sequential. + * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. + */ +library BitMaps { + struct BitMap { + mapping(uint256 => uint256) _data; + } + + /** + * @dev Returns whether the bit at `index` is set. + */ + function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + return bitmap._data[bucket] & mask != 0; + } + + /** + * @dev Sets the bit at `index` to the boolean `value`. + */ + function setTo(BitMap storage bitmap, uint256 index, bool value) internal { + if (value) { + set(bitmap, index); + } else { + unset(bitmap, index); + } + } + + /** + * @dev Sets the bit at `index`. + */ + function set(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] |= mask; + } + + /** + * @dev Unsets the bit at `index`. + */ + function unset(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] &= ~mask; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/DoubleEndedQueue.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/DoubleEndedQueue.sol new file mode 100644 index 0000000..325918d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/DoubleEndedQueue.sol @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/DoubleEndedQueue.sol) +pragma solidity ^0.8.4; + +import "../math/SafeCast.sol"; + +/** + * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of + * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and + * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that + * the existing queue contents are left in storage. + * + * 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; + * ``` + * + * _Available since v4.6._ + */ +library DoubleEndedQueue { + /** + * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty. + */ + error Empty(); + + /** + * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds. + */ + error OutOfBounds(); + + /** + * @dev Indices are signed integers because the queue can grow in any direction. They are 128 bits so begin and end + * are packed in a single storage slot for efficient access. Since the items are added one at a time we can safely + * assume that these 128-bit indices will not overflow, and use unchecked arithmetic. + * + * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to + * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and + * lead to unexpected behavior. + * + * Indices are in the range [begin, end) which means the first item is at data[begin] and the last item is at + * data[end - 1]. + */ + struct Bytes32Deque { + int128 _begin; + int128 _end; + mapping(int128 => bytes32) _data; + } + + /** + * @dev Inserts an item at the end of the queue. + */ + function pushBack(Bytes32Deque storage deque, bytes32 value) internal { + int128 backIndex = deque._end; + deque._data[backIndex] = value; + unchecked { + deque._end = backIndex + 1; + } + } + + /** + * @dev Removes the item at the end of the queue and returns it. + * + * Reverts with `Empty` if the queue is empty. + */ + function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) { + if (empty(deque)) revert Empty(); + int128 backIndex; + unchecked { + backIndex = deque._end - 1; + } + value = deque._data[backIndex]; + delete deque._data[backIndex]; + deque._end = backIndex; + } + + /** + * @dev Inserts an item at the beginning of the queue. + */ + function pushFront(Bytes32Deque storage deque, bytes32 value) internal { + int128 frontIndex; + unchecked { + frontIndex = deque._begin - 1; + } + deque._data[frontIndex] = value; + deque._begin = frontIndex; + } + + /** + * @dev Removes the item at the beginning of the queue and returns it. + * + * Reverts with `Empty` if the queue is empty. + */ + function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) { + if (empty(deque)) revert Empty(); + int128 frontIndex = deque._begin; + value = deque._data[frontIndex]; + delete deque._data[frontIndex]; + unchecked { + deque._begin = frontIndex + 1; + } + } + + /** + * @dev Returns the item at the beginning of the queue. + * + * Reverts with `Empty` if the queue is empty. + */ + function front(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) revert Empty(); + int128 frontIndex = deque._begin; + return deque._data[frontIndex]; + } + + /** + * @dev Returns the item at the end of the queue. + * + * Reverts with `Empty` if the queue is empty. + */ + function back(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) revert Empty(); + int128 backIndex; + unchecked { + backIndex = deque._end - 1; + } + return deque._data[backIndex]; + } + + /** + * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at + * `length(deque) - 1`. + * + * Reverts with `OutOfBounds` if the index is out of bounds. + */ + function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) { + // int256(deque._begin) is a safe upcast + int128 idx = SafeCast.toInt128(int256(deque._begin) + SafeCast.toInt256(index)); + if (idx >= deque._end) revert OutOfBounds(); + return deque._data[idx]; + } + + /** + * @dev Resets the queue back to being empty. + * + * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses + * out on potential gas refunds. + */ + function clear(Bytes32Deque storage deque) internal { + deque._begin = 0; + deque._end = 0; + } + + /** + * @dev Returns the number of items in the queue. + */ + function length(Bytes32Deque storage deque) internal view returns (uint256) { + // The interface preserves the invariant that begin <= end so we assume this will not overflow. + // We also assume there are at most int256.max items in the queue. + unchecked { + return uint256(int256(deque._end) - int256(deque._begin)); + } + } + + /** + * @dev Returns true if the queue is empty. + */ + function empty(Bytes32Deque storage deque) internal view returns (bool) { + return deque._end <= deque._begin; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/EnumerableMap.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/EnumerableMap.sol new file mode 100644 index 0000000..c49d2d6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/EnumerableMap.sol @@ -0,0 +1,598 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableMap.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. + +pragma solidity ^0.8.0; + +import "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * ``` + * + * The following map types are supported: + * + * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 + * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 + * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 + * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 + * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +library EnumerableMap { + using EnumerableSet for EnumerableSet.Bytes32Set; + + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Map type with + // bytes32 keys and values. + // The Map implementation uses private functions, and user-facing + // implementations (such as Uint256ToAddressMap) are just wrappers around + // the underlying Map. + // This means that we can only create new EnumerableMaps for types that fit + // in bytes32. + + struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 => bytes32) _values; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key"); + return value; + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + Bytes32ToBytes32Map storage map, + bytes32 key, + string memory errorMessage + ) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), errorMessage); + return value; + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { + return map._keys.values(); + } + + // UintToUintMap + + struct UintToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(key))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get(UintToUintMap storage map, uint256 key, string memory errorMessage) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(key), errorMessage)); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintToAddressMap + + struct UintToAddressMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToAddressMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), address(uint160(uint256(value)))); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, address(uint160(uint256(value)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(key))))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + UintToAddressMap storage map, + uint256 key, + string memory errorMessage + ) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage)))); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressToUintMap + + struct AddressToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { + return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(AddressToUintMap storage map, address key) internal returns (bool) { + return remove(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(AddressToUintMap storage map, address key) internal view returns (bool) { + return contains(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(AddressToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (address(uint160(uint256(key))), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(AddressToUintMap storage map, address key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(uint256(uint160(key))))); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + AddressToUintMap storage map, + address key, + string memory errorMessage + ) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage)); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(AddressToUintMap storage map) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // Bytes32ToUintMap + + struct Bytes32ToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { + return set(map._inner, key, bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { + return remove(map._inner, key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { + return contains(map._inner, key); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(Bytes32ToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (key, uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, key); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { + return uint256(get(map._inner, key)); + } + + /** + * @dev Same as {get}, with a custom error message when `key` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ + function get( + Bytes32ToUintMap storage map, + bytes32 key, + string memory errorMessage + ) internal view returns (uint256) { + return uint256(get(map._inner, key, errorMessage)); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { + bytes32[] memory store = keys(map._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/EnumerableSet.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/EnumerableSet.sol new file mode 100644 index 0000000..447f963 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/utils/structs/EnumerableSet.sol @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. + +pragma solidity ^0.8.0; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + // Position of the value in the `values` array, plus 1 because index 0 + // means a value is not in the set. + mapping(bytes32 => uint256) _indexes; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastValue; + // Update the index for the moved value + set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { + bytes32[] memory store = _values(set._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(AddressSet storage set) internal view returns (address[] memory) { + bytes32[] memory store = _values(set._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(UintSet storage set) internal view returns (uint256[] memory) { + bytes32[] memory store = _values(set._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/amb/IAMB.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/amb/IAMB.sol new file mode 100644 index 0000000..658f726 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/amb/IAMB.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (vendor/amb/IAMB.sol) +pragma solidity ^0.8.0; + +interface IAMB { + event UserRequestForAffirmation(bytes32 indexed messageId, bytes encodedData); + event UserRequestForSignature(bytes32 indexed messageId, bytes encodedData); + event AffirmationCompleted( + address indexed sender, + address indexed executor, + bytes32 indexed messageId, + bool status + ); + event RelayedMessage(address indexed sender, address indexed executor, bytes32 indexed messageId, bool status); + + function messageSender() external view returns (address); + + function maxGasPerTx() external view returns (uint256); + + function transactionHash() external view returns (bytes32); + + function messageId() external view returns (bytes32); + + function messageSourceChainId() external view returns (bytes32); + + function messageCallStatus(bytes32 _messageId) external view returns (bool); + + function failedMessageDataHash(bytes32 _messageId) external view returns (bytes32); + + function failedMessageReceiver(bytes32 _messageId) external view returns (address); + + function failedMessageSender(bytes32 _messageId) external view returns (address); + + function requireToPassMessage(address _contract, bytes calldata _data, uint256 _gas) external returns (bytes32); + + function requireToConfirmMessage(address _contract, bytes calldata _data, uint256 _gas) external returns (bytes32); + + function sourceChainId() external view returns (uint256); + + function destinationChainId() external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IArbSys.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IArbSys.sol new file mode 100644 index 0000000..ea4e750 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IArbSys.sol @@ -0,0 +1,134 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.9.0) (vendor/arbitrum/IArbSys.sol) + +pragma solidity >=0.4.21 <0.9.0; + +/** + * @title System level functionality + * @notice For use by contracts to interact with core L2-specific functionality. + * Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064. + */ +interface IArbSys { + /** + * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0) + * @return block number as int + */ + function arbBlockNumber() external view returns (uint256); + + /** + * @notice Get Arbitrum block hash (reverts unless currentBlockNum-256 <= arbBlockNum < currentBlockNum) + * @return block hash + */ + function arbBlockHash(uint256 arbBlockNum) external view returns (bytes32); + + /** + * @notice Gets the rollup's unique chain identifier + * @return Chain identifier as int + */ + function arbChainID() external view returns (uint256); + + /** + * @notice Get internal version number identifying an ArbOS build + * @return version number as int + */ + function arbOSVersion() external view returns (uint256); + + /** + * @notice Returns 0 since Nitro has no concept of storage gas + * @return uint 0 + */ + function getStorageGasAvailable() external view returns (uint256); + + /** + * @notice (deprecated) check if current call is top level (meaning it was triggered by an EoA or a L1 contract) + * @dev this call has been deprecated and may be removed in a future release + * @return true if current execution frame is not a call by another L2 contract + */ + function isTopLevelCall() external view returns (bool); + + /** + * @notice map L1 sender contract address to its L2 alias + * @param sender sender address + * @param unused argument no longer used + * @return aliased sender address + */ + function mapL1SenderContractAddressToL2Alias(address sender, address unused) external pure returns (address); + + /** + * @notice check if the caller (of this caller of this) is an aliased L1 contract address + * @return true iff the caller's address is an alias for an L1 contract address + */ + function wasMyCallersAddressAliased() external view returns (bool); + + /** + * @notice return the address of the caller (of this caller of this), without applying L1 contract address aliasing + * @return address of the caller's caller, without applying L1 contract address aliasing + */ + function myCallersAddressWithoutAliasing() external view returns (address); + + /** + * @notice Send given amount of Eth to dest from sender. + * This is a convenience function, which is equivalent to calling sendTxToL1 with empty data. + * @param destination recipient address on L1 + * @return unique identifier for this L2-to-L1 transaction. + */ + function withdrawEth(address destination) external payable returns (uint256); + + /** + * @notice Send a transaction to L1 + * @dev it is not possible to execute on the L1 any L2-to-L1 transaction which contains data + * to a contract address without any code (as enforced by the Bridge contract). + * @param destination recipient address on L1 + * @param data (optional) calldata for L1 contract call + * @return a unique identifier for this L2-to-L1 transaction. + */ + function sendTxToL1(address destination, bytes calldata data) external payable returns (uint256); + + /** + * @notice Get send Merkle tree state + * @return size number of sends in the history + * @return root root hash of the send history + * @return partials hashes of partial subtrees in the send history tree + */ + function sendMerkleTreeState() external view returns (uint256 size, bytes32 root, bytes32[] memory partials); + + /** + * @notice creates a send txn from L2 to L1 + * @param position = (level << 192) + leaf = (0 << 192) + leaf = leaf + */ + event L2ToL1Tx( + address caller, + address indexed destination, + uint256 indexed hash, + uint256 indexed position, + uint256 arbBlockNum, + uint256 ethBlockNum, + uint256 timestamp, + uint256 callvalue, + bytes data + ); + + /// @dev DEPRECATED in favour of the new L2ToL1Tx event above after the nitro upgrade + event L2ToL1Transaction( + address caller, + address indexed destination, + uint256 indexed uniqueId, + uint256 indexed batchNumber, + uint256 indexInBatch, + uint256 arbBlockNum, + uint256 ethBlockNum, + uint256 timestamp, + uint256 callvalue, + bytes data + ); + + /** + * @notice logs a merkle branch for proof synthesis + * @param reserved an index meant only to align the 4th index with L2ToL1Transaction's 4th event + * @param hash the merkle hash + * @param position = (level << 192) + leaf + */ + event SendMerkleUpdate(uint256 indexed reserved, bytes32 indexed hash, uint256 indexed position); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IBridge.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IBridge.sol new file mode 100644 index 0000000..398fb61 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IBridge.sol @@ -0,0 +1,102 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.9.0) (vendor/arbitrum/IBridge.sol) + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +interface IBridge { + event MessageDelivered( + uint256 indexed messageIndex, + bytes32 indexed beforeInboxAcc, + address inbox, + uint8 kind, + address sender, + bytes32 messageDataHash, + uint256 baseFeeL1, + uint64 timestamp + ); + + event BridgeCallTriggered(address indexed outbox, address indexed to, uint256 value, bytes data); + + event InboxToggle(address indexed inbox, bool enabled); + + event OutboxToggle(address indexed outbox, bool enabled); + + event SequencerInboxUpdated(address newSequencerInbox); + + function allowedDelayedInboxList(uint256) external returns (address); + + function allowedOutboxList(uint256) external returns (address); + + /// @dev Accumulator for delayed inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message. + function delayedInboxAccs(uint256) external view returns (bytes32); + + /// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message. + function sequencerInboxAccs(uint256) external view returns (bytes32); + + // OpenZeppelin: changed return type from IOwnable + function rollup() external view returns (address); + + function sequencerInbox() external view returns (address); + + function activeOutbox() external view returns (address); + + function allowedDelayedInboxes(address inbox) external view returns (bool); + + function allowedOutboxes(address outbox) external view returns (bool); + + function sequencerReportedSubMessageCount() external view returns (uint256); + + /** + * @dev Enqueue a message in the delayed inbox accumulator. + * These messages are later sequenced in the SequencerInbox, either + * by the sequencer as part of a normal batch, or by force inclusion. + */ + function enqueueDelayedMessage( + uint8 kind, + address sender, + bytes32 messageDataHash + ) external payable returns (uint256); + + function executeCall( + address to, + uint256 value, + bytes calldata data + ) external returns (bool success, bytes memory returnData); + + function delayedMessageCount() external view returns (uint256); + + function sequencerMessageCount() external view returns (uint256); + + // ---------- onlySequencerInbox functions ---------- + + function enqueueSequencerMessage( + bytes32 dataHash, + uint256 afterDelayedMessagesRead, + uint256 prevMessageCount, + uint256 newMessageCount + ) external returns (uint256 seqMessageIndex, bytes32 beforeAcc, bytes32 delayedAcc, bytes32 acc); + + /** + * @dev Allows the sequencer inbox to submit a delayed message of the batchPostingReport type + * This is done through a separate function entrypoint instead of allowing the sequencer inbox + * to call `enqueueDelayedMessage` to avoid the gas overhead of an extra SLOAD in either + * every delayed inbox or every sequencer inbox call. + */ + function submitBatchSpendingReport(address batchPoster, bytes32 dataHash) external returns (uint256 msgNum); + + // ---------- onlyRollupOrOwner functions ---------- + + function setSequencerInbox(address _sequencerInbox) external; + + function setDelayedInbox(address inbox, bool enabled) external; + + function setOutbox(address inbox, bool enabled) external; + + // ---------- initializer ---------- + + // OpenZeppelin: changed rollup_ type from IOwnable + function initialize(address rollup_) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IDelayedMessageProvider.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IDelayedMessageProvider.sol new file mode 100644 index 0000000..914c25f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IDelayedMessageProvider.sol @@ -0,0 +1,16 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.8.0) (vendor/arbitrum/IDelayedMessageProvider.sol) + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +interface IDelayedMessageProvider { + /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator + event InboxMessageDelivered(uint256 indexed messageNum, bytes data); + + /// @dev event emitted when a inbox message is added to the Bridge's delayed accumulator + /// same as InboxMessageDelivered but the batch data is available in tx.input + event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IInbox.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IInbox.sol new file mode 100644 index 0000000..a8b6751 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IInbox.sol @@ -0,0 +1,152 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.8.0) (vendor/arbitrum/IInbox.sol) + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +import "./IBridge.sol"; +import "./IDelayedMessageProvider.sol"; + +interface IInbox is IDelayedMessageProvider { + function bridge() external view returns (IBridge); + + // OpenZeppelin: changed return type from ISequencerInbox + function sequencerInbox() external view returns (address); + + /** + * @notice Send a generic L2 message to the chain + * @dev This method is an optimization to avoid having to emit the entirety of the messageData in a log. Instead validators are expected to be able to parse the data from the transaction's input + * @param messageData Data of the message being sent + */ + function sendL2MessageFromOrigin(bytes calldata messageData) external returns (uint256); + + /** + * @notice Send a generic L2 message to the chain + * @dev This method can be used to send any type of message that doesn't require L1 validation + * @param messageData Data of the message being sent + */ + function sendL2Message(bytes calldata messageData) external returns (uint256); + + function sendL1FundedUnsignedTransaction( + uint256 gasLimit, + uint256 maxFeePerGas, + uint256 nonce, + address to, + bytes calldata data + ) external payable returns (uint256); + + function sendL1FundedContractTransaction( + uint256 gasLimit, + uint256 maxFeePerGas, + address to, + bytes calldata data + ) external payable returns (uint256); + + function sendUnsignedTransaction( + uint256 gasLimit, + uint256 maxFeePerGas, + uint256 nonce, + address to, + uint256 value, + bytes calldata data + ) external returns (uint256); + + function sendContractTransaction( + uint256 gasLimit, + uint256 maxFeePerGas, + address to, + uint256 value, + bytes calldata data + ) external returns (uint256); + + /** + * @notice Get the L1 fee for submitting a retryable + * @dev This fee can be paid by funds already in the L2 aliased address or by the current message value + * @dev This formula may change in the future, to future proof your code query this method instead of inlining!! + * @param dataLength The length of the retryable's calldata, in bytes + * @param baseFee The block basefee when the retryable is included in the chain, if 0 current block.basefee will be used + */ + function calculateRetryableSubmissionFee(uint256 dataLength, uint256 baseFee) external view returns (uint256); + + /** + * @notice Deposit eth from L1 to L2 to address of the sender if sender is an EOA, and to its aliased address if the sender is a contract + * @dev This does not trigger the fallback function when receiving in the L2 side. + * Look into retryable tickets if you are interested in this functionality. + * @dev This function should not be called inside contract constructors + */ + function depositEth() external payable returns (uint256); + + /** + * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts + * @dev all msg.value will deposited to callValueRefundAddress on L2 + * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error + * @param to destination L2 contract address + * @param l2CallValue call value for retryable L2 message + * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee + * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance + * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled + * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) + * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) + * @param data ABI encoded data of L2 message + * @return unique message number of the retryable transaction + */ + function createRetryableTicket( + address to, + uint256 l2CallValue, + uint256 maxSubmissionCost, + address excessFeeRefundAddress, + address callValueRefundAddress, + uint256 gasLimit, + uint256 maxFeePerGas, + bytes calldata data + ) external payable returns (uint256); + + /** + * @notice Put a message in the L2 inbox that can be reexecuted for some fixed amount of time if it reverts + * @dev Same as createRetryableTicket, but does not guarantee that submission will succeed by requiring the needed funds + * come from the deposit alone, rather than falling back on the user's L2 balance + * @dev Advanced usage only (does not rewrite aliases for excessFeeRefundAddress and callValueRefundAddress). + * createRetryableTicket method is the recommended standard. + * @dev Gas limit and maxFeePerGas should not be set to 1 as that is used to trigger the RetryableData error + * @param to destination L2 contract address + * @param l2CallValue call value for retryable L2 message + * @param maxSubmissionCost Max gas deducted from user's L2 balance to cover base submission fee + * @param excessFeeRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance + * @param callValueRefundAddress l2Callvalue gets credited here on L2 if retryable txn times out or gets cancelled + * @param gasLimit Max gas deducted from user's L2 balance to cover L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) + * @param maxFeePerGas price bid for L2 execution. Should not be set to 1 (magic value used to trigger the RetryableData error) + * @param data ABI encoded data of L2 message + * @return unique message number of the retryable transaction + */ + function unsafeCreateRetryableTicket( + address to, + uint256 l2CallValue, + uint256 maxSubmissionCost, + address excessFeeRefundAddress, + address callValueRefundAddress, + uint256 gasLimit, + uint256 maxFeePerGas, + bytes calldata data + ) external payable returns (uint256); + + // ---------- onlyRollupOrOwner functions ---------- + + /// @notice pauses all inbox functionality + function pause() external; + + /// @notice unpauses all inbox functionality + function unpause() external; + + // ---------- initializer ---------- + + /** + * @dev function to be called one time during the inbox upgrade process + * this is used to fix the storage slots + */ + function postUpgradeInit(IBridge _bridge) external; + + // OpenZeppelin: changed _sequencerInbox type from ISequencerInbox + function initialize(IBridge _bridge, address _sequencerInbox) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IOutbox.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IOutbox.sol new file mode 100644 index 0000000..359ea6c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/arbitrum/IOutbox.sol @@ -0,0 +1,117 @@ +// Copyright 2021-2022, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +// SPDX-License-Identifier: BUSL-1.1 +// OpenZeppelin Contracts (last updated v4.9.0) (vendor/arbitrum/IOutbox.sol) + +// solhint-disable-next-line compiler-version +pragma solidity >=0.6.9 <0.9.0; + +import "./IBridge.sol"; + +interface IOutbox { + event SendRootUpdated(bytes32 indexed blockHash, bytes32 indexed outputRoot); + event OutBoxTransactionExecuted( + address indexed to, + address indexed l2Sender, + uint256 indexed zero, + uint256 transactionIndex + ); + + function rollup() external view returns (address); // the rollup contract + + function bridge() external view returns (IBridge); // the bridge contract + + function spent(uint256) external view returns (bytes32); // packed spent bitmap + + function roots(bytes32) external view returns (bytes32); // maps root hashes => L2 block hash + + // solhint-disable-next-line func-name-mixedcase + function OUTBOX_VERSION() external view returns (uint128); // the outbox version + + function updateSendRoot(bytes32 sendRoot, bytes32 l2BlockHash) external; + + /// @notice When l2ToL1Sender returns a nonzero address, the message was originated by an L2 account + /// When the return value is zero, that means this is a system message + /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies + function l2ToL1Sender() external view returns (address); + + /// @return l2Block return L2 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active + function l2ToL1Block() external view returns (uint256); + + /// @return l1Block return L1 block when the L2 tx was initiated or 0 if no L2 to L1 transaction is active + function l2ToL1EthBlock() external view returns (uint256); + + /// @return timestamp return L2 timestamp when the L2 tx was initiated or 0 if no L2 to L1 transaction is active + function l2ToL1Timestamp() external view returns (uint256); + + /// @return outputId returns the unique output identifier of the L2 to L1 tx or 0 if no L2 to L1 transaction is active + function l2ToL1OutputId() external view returns (bytes32); + + /** + * @notice Executes a messages in an Outbox entry. + * @dev Reverts if dispute period hasn't expired, since the outbox entry + * is only created once the rollup confirms the respective assertion. + * @dev it is not possible to execute any L2-to-L1 transaction which contains data + * to a contract address without any code (as enforced by the Bridge contract). + * @param proof Merkle proof of message inclusion in send root + * @param index Merkle path to message + * @param l2Sender sender if original message (i.e., caller of ArbSys.sendTxToL1) + * @param to destination address for L1 contract call + * @param l2Block l2 block number at which sendTxToL1 call was made + * @param l1Block l1 block number at which sendTxToL1 call was made + * @param l2Timestamp l2 Timestamp at which sendTxToL1 call was made + * @param value wei in L1 message + * @param data abi-encoded L1 message data + */ + function executeTransaction( + bytes32[] calldata proof, + uint256 index, + address l2Sender, + address to, + uint256 l2Block, + uint256 l1Block, + uint256 l2Timestamp, + uint256 value, + bytes calldata data + ) external; + + /** + * @dev function used to simulate the result of a particular function call from the outbox + * it is useful for things such as gas estimates. This function includes all costs except for + * proof validation (which can be considered offchain as a somewhat of a fixed cost - it's + * not really a fixed cost, but can be treated as so with a fixed overhead for gas estimation). + * We can't include the cost of proof validation since this is intended to be used to simulate txs + * that are included in yet-to-be confirmed merkle roots. The simulation entrypoint could instead pretend + * to confirm a pending merkle root, but that would be less practical for integrating with tooling. + * It is only possible to trigger it when the msg sender is address zero, which should be impossible + * unless under simulation in an eth_call or eth_estimateGas + */ + function executeTransactionSimulation( + uint256 index, + address l2Sender, + address to, + uint256 l2Block, + uint256 l1Block, + uint256 l2Timestamp, + uint256 value, + bytes calldata data + ) external; + + /** + * @param index Merkle path to message + * @return true if the message has been spent + */ + function isSpent(uint256 index) external view returns (bool); + + function calculateItemHash( + address l2Sender, + address to, + uint256 l2Block, + uint256 l1Block, + uint256 l2Timestamp, + uint256 value, + bytes calldata data + ) external pure returns (bytes32); + + function calculateMerkleRoot(bytes32[] memory proof, uint256 path, bytes32 item) external pure returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/compound/ICompoundTimelock.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/compound/ICompoundTimelock.sol new file mode 100644 index 0000000..fb33a68 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/compound/ICompoundTimelock.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.6.0) (vendor/compound/ICompoundTimelock.sol) + +pragma solidity ^0.8.0; + +/** + * https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[Compound's timelock] interface + */ +interface ICompoundTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + + receive() external payable; + + // solhint-disable-next-line func-name-mixedcase + function GRACE_PERIOD() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function MINIMUM_DELAY() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function MAXIMUM_DELAY() external view returns (uint256); + + function admin() external view returns (address); + + function pendingAdmin() external view returns (address); + + function delay() external view returns (uint256); + + function queuedTransactions(bytes32) external view returns (bool); + + function setDelay(uint256) external; + + function acceptAdmin() external; + + function setPendingAdmin(address) external; + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external returns (bytes32); + + function cancelTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external; + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external payable returns (bytes memory); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/compound/LICENSE b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/compound/LICENSE new file mode 100644 index 0000000..7da2324 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/compound/LICENSE @@ -0,0 +1,11 @@ +Copyright 2020 Compound Labs, Inc. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/optimism/ICrossDomainMessenger.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/optimism/ICrossDomainMessenger.sol new file mode 100644 index 0000000..461b88f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/optimism/ICrossDomainMessenger.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (vendor/optimism/ICrossDomainMessenger.sol) +pragma solidity >0.5.0 <0.9.0; + +/** + * @title ICrossDomainMessenger + */ +interface ICrossDomainMessenger { + /********** + * Events * + **********/ + + event SentMessage(address indexed target, address sender, bytes message, uint256 messageNonce, uint256 gasLimit); + event RelayedMessage(bytes32 indexed msgHash); + event FailedRelayedMessage(bytes32 indexed msgHash); + + /************* + * Variables * + *************/ + + function xDomainMessageSender() external view returns (address); + + /******************** + * Public Functions * + ********************/ + + /** + * Sends a cross domain message to the target messenger. + * @param _target Target contract address. + * @param _message Message to send to the target. + * @param _gasLimit Gas limit for the provided message. + */ + function sendMessage(address _target, bytes calldata _message, uint32 _gasLimit) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/optimism/LICENSE b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/optimism/LICENSE new file mode 100644 index 0000000..6a7da52 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/optimism/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright 2020-2021 Optimism + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/polygon/IFxMessageProcessor.sol b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/polygon/IFxMessageProcessor.sol new file mode 100644 index 0000000..1c7b6f6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/contracts/vendor/polygon/IFxMessageProcessor.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.9.0) (vendor/polygon/IFxMessageProcessor.sol) +pragma solidity ^0.8.0; + +interface IFxMessageProcessor { + function processMessageFromRoot(uint256 stateId, address rootMessageSender, bytes calldata data) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/foundry.toml b/lib/openzeppelin-contracts-v4.9.3/foundry.toml new file mode 100644 index 0000000..d0aa4ea --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/foundry.toml @@ -0,0 +1,3 @@ +[fuzz] +runs = 10000 +max_test_rejects = 150000 diff --git a/lib/openzeppelin-contracts-v4.9.3/hardhat.config.js b/lib/openzeppelin-contracts-v4.9.3/hardhat.config.js new file mode 100644 index 0000000..5fd703d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/hardhat.config.js @@ -0,0 +1,118 @@ +/// ENVVAR +// - CI: output gas report to file instead of stdout +// - COVERAGE: enable coverage report +// - ENABLE_GAS_REPORT: enable gas report +// - COMPILE_MODE: production modes enables optimizations (default: development) +// - COMPILE_VERSION: compiler version (default: 0.8.9) +// - COINMARKETCAP: coinmarkercat api key for USD value in gas report + +const fs = require('fs'); +const path = require('path'); +const argv = require('yargs/yargs')() + .env('') + .options({ + coverage: { + type: 'boolean', + default: false, + }, + gas: { + alias: 'enableGasReport', + type: 'boolean', + default: false, + }, + gasReport: { + alias: 'enableGasReportPath', + type: 'string', + implies: 'gas', + default: undefined, + }, + mode: { + alias: 'compileMode', + type: 'string', + choices: ['production', 'development'], + default: 'development', + }, + ir: { + alias: 'enableIR', + type: 'boolean', + default: false, + }, + compiler: { + alias: 'compileVersion', + type: 'string', + default: '0.8.13', + }, + coinmarketcap: { + alias: 'coinmarketcapApiKey', + type: 'string', + }, + }).argv; + +require('@nomiclabs/hardhat-truffle5'); +require('hardhat-ignore-warnings'); +require('hardhat-exposed'); + +require('solidity-docgen'); + +for (const f of fs.readdirSync(path.join(__dirname, 'hardhat'))) { + require(path.join(__dirname, 'hardhat', f)); +} + +const withOptimizations = argv.gas || argv.compileMode === 'production'; + +/** + * @type import('hardhat/config').HardhatUserConfig + */ +module.exports = { + solidity: { + version: argv.compiler, + settings: { + optimizer: { + enabled: withOptimizations, + runs: 200, + }, + viaIR: withOptimizations && argv.ir, + outputSelection: { '*': { '*': ['storageLayout'] } }, + }, + }, + warnings: { + 'contracts-exposed/**/*': { + 'code-size': 'off', + }, + '*': { + 'code-size': withOptimizations, + 'unused-param': !argv.coverage, // coverage causes unused-param warnings + default: 'error', + }, + }, + networks: { + hardhat: { + blockGasLimit: 10000000, + allowUnlimitedContractSize: !withOptimizations, + }, + }, + exposed: { + initializers: true, + exclude: [ + 'vendor/**/*', + // Exclude Timers from hardhat-exposed because its overloaded functions are not transformed correctly + 'utils/Timers{,Upgradeable}.sol', + ], + }, + docgen: require('./docs/config'), +}; + +if (argv.gas) { + require('hardhat-gas-reporter'); + module.exports.gasReporter = { + showMethodSig: true, + currency: 'USD', + outputFile: argv.gasReport, + coinmarketcap: argv.coinmarketcap, + }; +} + +if (argv.coverage) { + require('solidity-coverage'); + module.exports.networks.hardhat.initialBaseFeePerGas = 0; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/hardhat/env-artifacts.js b/lib/openzeppelin-contracts-v4.9.3/hardhat/env-artifacts.js new file mode 100644 index 0000000..fbbea2e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/hardhat/env-contract.js b/lib/openzeppelin-contracts-v4.9.3/hardhat/env-contract.js new file mode 100644 index 0000000..74d54cf --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/hardhat/env-contract.js @@ -0,0 +1,10 @@ +extendEnvironment(env => { + const { contract } = env; + + env.contract = function (name, body) { + // remove the default account from the accounts list used in tests, in order + // to protect tests against accidentally passing due to the contract + // deployer being used subsequently as function caller + contract(name, accounts => body(accounts.slice(1))); + }; +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/hardhat/ignore-unreachable-warnings.js b/lib/openzeppelin-contracts-v4.9.3/hardhat/ignore-unreachable-warnings.js new file mode 100644 index 0000000..8e3e343 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/hardhat/ignore-unreachable-warnings.js @@ -0,0 +1,45 @@ +// Warnings about unreachable code are emitted with a source location that corresponds to the unreachable code. +// We have some testing contracts that purposely cause unreachable code, but said code is in the library contracts, and +// with hardhat-ignore-warnings we are not able to selectively ignore them without potentially ignoring relevant +// warnings that we don't want to miss. +// Thus, we need to handle these warnings separately. We force Hardhat to compile them in a separate compilation job and +// then ignore the warnings about unreachable code that come from that compilation job. + +const { task } = require('hardhat/config'); +const { + TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, + TASK_COMPILE_SOLIDITY_COMPILE, +} = require('hardhat/builtin-tasks/task-names'); + +const marker = Symbol('unreachable'); +const markedCache = new WeakMap(); + +task(TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, async (params, _, runSuper) => { + const job = await runSuper(params); + // If the file is in the unreachable directory, we make a copy of the config and mark it, which will cause it to get + // compiled separately (along with the other marked files). + if (params.file.sourceName.startsWith('contracts/mocks/') && /\bunreachable\b/.test(params.file.sourceName)) { + const originalConfig = job.solidityConfig; + let markedConfig = markedCache.get(originalConfig); + if (markedConfig === undefined) { + markedConfig = { ...originalConfig, [marker]: true }; + markedCache.set(originalConfig, markedConfig); + } + job.solidityConfig = markedConfig; + } + return job; +}); + +const W_UNREACHABLE_CODE = '5740'; + +task(TASK_COMPILE_SOLIDITY_COMPILE, async (params, _, runSuper) => { + const marked = params.compilationJob.solidityConfig[marker]; + const result = await runSuper(params); + if (marked) { + result.output = { + ...result.output, + errors: result.output.errors?.filter(e => e.severity !== 'warning' || e.errorCode !== W_UNREACHABLE_CODE), + }; + } + return result; +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/hardhat/skip-foundry-tests.js b/lib/openzeppelin-contracts-v4.9.3/hardhat/skip-foundry-tests.js new file mode 100644 index 0000000..965ba37 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/hardhat/skip-foundry-tests.js @@ -0,0 +1,6 @@ +const { subtask } = require('hardhat/config'); +const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require('hardhat/builtin-tasks/task-names'); + +subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, __, runSuper) => + (await runSuper()).filter(path => !path.endsWith('.t.sol')), +); diff --git a/lib/openzeppelin-contracts-v4.9.3/hardhat/task-test-get-files.js b/lib/openzeppelin-contracts-v4.9.3/hardhat/task-test-get-files.js new file mode 100644 index 0000000..108f40a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/hardhat/task-test-get-files.js @@ -0,0 +1,25 @@ +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 (args, hre, runSuper) => { + const path = require('path'); + const { promises: fs } = require('fs'); + + const hasProxies = await fs + .access(path.join(hre.config.paths.sources, 'proxy/Proxy.sol')) + .then(() => true) + .catch(() => false); + + const ignoredIfProxy = [ + '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(hre.config.paths.tests, p)); + + return (await runSuper(args)).filter(file => hasProxies || !ignoredIfProxy.includes(file)); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/ERC4626.prop.sol b/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/ERC4626.prop.sol new file mode 100644 index 0000000..c34512b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/ERC4626.prop.sol @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "forge-std/Test.sol"; + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC20} from "forge-std/interfaces/IERC20.sol"; +interface IERC20 { + event Transfer(address indexed from, address indexed to, uint value); + event Approval(address indexed owner, address indexed spender, uint value); + function totalSupply() external view returns (uint); + function balanceOf(address account) external view returns (uint); + function transfer(address to, uint amount) external returns (bool); + function allowance(address owner, address spender) external view returns (uint); + function approve(address spender, uint amount) external returns (bool); + function transferFrom(address from, address to, uint amount) external returns (bool); +} + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC4626} from "forge-std/interfaces/IERC4626.sol"; +interface IERC4626 is IERC20 { + event Deposit(address indexed caller, address indexed owner, uint assets, uint shares); + event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint assets, uint shares); + function asset() external view returns (address assetTokenAddress); + function totalAssets() external view returns (uint totalManagedAssets); + function convertToShares(uint assets) external view returns (uint shares); + function convertToAssets(uint shares) external view returns (uint assets); + function maxDeposit(address receiver) external view returns (uint maxAssets); + function previewDeposit(uint assets) external view returns (uint shares); + function deposit(uint assets, address receiver) external returns (uint shares); + function maxMint(address receiver) external view returns (uint maxShares); + function previewMint(uint shares) external view returns (uint assets); + function mint(uint shares, address receiver) external returns (uint assets); + function maxWithdraw(address owner) external view returns (uint maxAssets); + function previewWithdraw(uint assets) external view returns (uint shares); + function withdraw(uint assets, address receiver, address owner) external returns (uint shares); + function maxRedeem(address owner) external view returns (uint maxShares); + function previewRedeem(uint shares) external view returns (uint assets); + function redeem(uint shares, address receiver, address owner) external returns (uint assets); +} + +abstract contract ERC4626Prop is Test { + uint internal _delta_; + + address internal _underlying_; + address internal _vault_; + + bool internal _vaultMayBeEmpty; + bool internal _unlimitedAmount; + + // + // asset + // + + // asset + // "MUST NOT revert." + function prop_asset(address caller) public { + vm.prank(caller); IERC4626(_vault_).asset(); + } + + // totalAssets + // "MUST NOT revert." + function prop_totalAssets(address caller) public { + vm.prank(caller); IERC4626(_vault_).totalAssets(); + } + + // + // convert + // + + // convertToShares + // "MUST NOT show any variations depending on the caller." + function prop_convertToShares(address caller1, address caller2, uint assets) public { + vm.prank(caller1); uint res1 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // convertToAssets + // "MUST NOT show any variations depending on the caller." + function prop_convertToAssets(address caller1, address caller2, uint shares) public { + vm.prank(caller1); uint res1 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // + // deposit + // + + // maxDeposit + // "MUST NOT revert." + function prop_maxDeposit(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxDeposit(receiver); + } + + // previewDeposit + // "MUST return as close to and no more than the exact amount of Vault + // shares that would be minted in a deposit call in the same transaction. + // I.e. deposit should return the same or more shares as previewDeposit if + // called in the same transaction." + function prop_previewDeposit(address caller, address receiver, address other, uint assets) public { + vm.prank(other); uint sharesPreview = vault_previewDeposit(assets); // "MAY revert due to other conditions that would also cause deposit to revert." + vm.prank(caller); uint sharesActual = vault_deposit(assets, receiver); + assertApproxGeAbs(sharesActual, sharesPreview, _delta_); + } + + // deposit + function prop_deposit(address caller, address receiver, uint assets) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint shares = vault_deposit(assets, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // mint + // + + // maxMint + // "MUST NOT revert." + function prop_maxMint(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxMint(receiver); + } + + // previewMint + // "MUST return as close to and no fewer than the exact amount of assets + // that would be deposited in a mint call in the same transaction. I.e. mint + // should return the same or fewer assets as previewMint if called in the + // same transaction." + function prop_previewMint(address caller, address receiver, address other, uint shares) public { + vm.prank(other); uint assetsPreview = vault_previewMint(shares); + vm.prank(caller); uint assetsActual = vault_mint(shares, receiver); + assertApproxLeAbs(assetsActual, assetsPreview, _delta_); + } + + // mint + function prop_mint(address caller, address receiver, uint shares) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint assets = vault_mint(shares, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // withdraw + // + + // maxWithdraw + // "MUST NOT revert." + // NOTE: some implementations failed due to arithmetic overflow + function prop_maxWithdraw(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxWithdraw(owner); + } + + // previewWithdraw + // "MUST return as close to and no fewer than the exact amount of Vault + // shares that would be burned in a withdraw call in the same transaction. + // I.e. withdraw should return the same or fewer shares as previewWithdraw + // if called in the same transaction." + function prop_previewWithdraw(address caller, address receiver, address owner, address other, uint assets) public { + vm.prank(other); uint preview = vault_previewWithdraw(assets); + vm.prank(caller); uint actual = vault_withdraw(assets, receiver, owner); + assertApproxLeAbs(actual, preview, _delta_); + } + + // withdraw + function prop_withdraw(address caller, address receiver, address owner, uint assets) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint shares = vault_withdraw(assets, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // redeem + // + + // maxRedeem + // "MUST NOT revert." + function prop_maxRedeem(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxRedeem(owner); + } + + // previewRedeem + // "MUST return as close to and no more than the exact amount of assets that + // would be withdrawn in a redeem call in the same transaction. I.e. redeem + // should return the same or more assets as previewRedeem if called in the + // same transaction." + function prop_previewRedeem(address caller, address receiver, address owner, address other, uint shares) public { + vm.prank(other); uint preview = vault_previewRedeem(shares); + vm.prank(caller); uint actual = vault_redeem(shares, receiver, owner); + assertApproxGeAbs(actual, preview, _delta_); + } + + // redeem + function prop_redeem(address caller, address receiver, address owner, uint shares) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint assets = vault_redeem(shares, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // round trip properties + // + + // redeem(deposit(a)) <= a + function prop_RT_deposit_redeem(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares = vault_deposit(assets, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets, _delta_); + } + + // s = deposit(a) + // s' = withdraw(a) + // s' >= s + function prop_RT_deposit_withdraw(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares1 = vault_deposit(assets, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares1, _delta_); + } + + // deposit(redeem(s)) <= s + function prop_RT_redeem_deposit(address caller, uint shares) public { + vm.prank(caller); uint assets = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares, _delta_); + } + + // a = redeem(s) + // a' = mint(s) + // a' >= a + function prop_RT_redeem_mint(address caller, uint shares) public { + vm.prank(caller); uint assets1 = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets1, _delta_); + } + + // withdraw(mint(s)) >= s + function prop_RT_mint_withdraw(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets = vault_mint(shares, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares, _delta_); + } + + // a = mint(s) + // a' = redeem(s) + // a' <= a + function prop_RT_mint_redeem(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets1 = vault_mint(shares, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets1, _delta_); + } + + // mint(withdraw(a)) >= a + function prop_RT_withdraw_mint(address caller, uint assets) public { + vm.prank(caller); uint shares = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets, _delta_); + } + + // s = withdraw(a) + // s' = deposit(a) + // s' <= s + function prop_RT_withdraw_deposit(address caller, uint assets) public { + vm.prank(caller); uint shares1 = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares1, _delta_); + } + + // + // utils + // + + function vault_convertToShares(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToShares.selector, assets)); + } + function vault_convertToAssets(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToAssets.selector, shares)); + } + + function vault_maxDeposit(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxDeposit.selector, receiver)); + } + function vault_maxMint(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxMint.selector, receiver)); + } + function vault_maxWithdraw(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxWithdraw.selector, owner)); + } + function vault_maxRedeem(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxRedeem.selector, owner)); + } + + function vault_previewDeposit(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewDeposit.selector, assets)); + } + function vault_previewMint(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewMint.selector, shares)); + } + function vault_previewWithdraw(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewWithdraw.selector, assets)); + } + function vault_previewRedeem(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewRedeem.selector, shares)); + } + + function vault_deposit(uint assets, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.deposit.selector, assets, receiver)); + } + function vault_mint(uint shares, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.mint.selector, shares, receiver)); + } + function vault_withdraw(uint assets, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.withdraw.selector, assets, receiver, owner)); + } + function vault_redeem(uint shares, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.redeem.selector, shares, receiver, owner)); + } + + function _call_vault(bytes memory data) internal returns (uint) { + (bool success, bytes memory retdata) = _vault_.call(data); + if (success) return abi.decode(retdata, (uint)); + vm.assume(false); // if reverted, discard the current fuzz inputs, and let the fuzzer to start a new fuzz run + return 0; // silence warning + } + + function assertApproxGeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a >= b)) { + uint dt = b - a; + if (dt > maxDelta) { + emit log ("Error: a >=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } + + function assertApproxLeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a <= b)) { + uint dt = a - b; + if (dt > maxDelta) { + emit log ("Error: a <=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/ERC4626.test.sol b/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/ERC4626.test.sol new file mode 100644 index 0000000..6254a05 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/ERC4626.test.sol @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "./ERC4626.prop.sol"; + +interface IMockERC20 is IERC20 { + function mint(address to, uint value) external; + function burn(address from, uint value) external; +} + +abstract contract ERC4626Test is ERC4626Prop { + function setUp() public virtual; + + uint constant N = 4; + + struct Init { + address[N] user; + uint[N] share; + uint[N] asset; + int yield; + } + + // setup initial vault state as follows: + // + // totalAssets == sum(init.share) + init.yield + // totalShares == sum(init.share) + // + // init.user[i]'s assets == init.asset[i] + // init.user[i]'s shares == init.share[i] + function setUpVault(Init memory init) public virtual { + // setup initial shares and assets for individual users + for (uint i = 0; i < N; i++) { + address user = init.user[i]; + vm.assume(_isEOA(user)); + // shares + uint shares = init.share[i]; + try IMockERC20(_underlying_).mint(user, shares) {} catch { vm.assume(false); } + _approve(_underlying_, user, _vault_, shares); + vm.prank(user); try IERC4626(_vault_).deposit(shares, user) {} catch { vm.assume(false); } + // assets + uint assets = init.asset[i]; + try IMockERC20(_underlying_).mint(user, assets) {} catch { vm.assume(false); } + } + + // setup initial yield for vault + setUpYield(init); + } + + // setup initial yield + function setUpYield(Init memory init) public virtual { + if (init.yield >= 0) { // gain + uint gain = uint(init.yield); + try IMockERC20(_underlying_).mint(_vault_, gain) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } else { // loss + vm.assume(init.yield > type(int).min); // avoid overflow in conversion + uint loss = uint(-1 * init.yield); + try IMockERC20(_underlying_).burn(_vault_, loss) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } + } + + // + // asset + // + + function test_asset(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_asset(caller); + } + + function test_totalAssets(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_totalAssets(caller); + } + + // + // convert + // + + function test_convertToShares(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToShares(caller1, caller2, assets); + } + + function test_convertToAssets(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToAssets(caller1, caller2, shares); + } + + // + // deposit + // + + function test_maxDeposit(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxDeposit(caller, receiver); + } + + function test_previewDeposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewDeposit(caller, receiver, other, assets); + } + + function test_deposit(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_deposit(caller, receiver, assets); + } + + // + // mint + // + + function test_maxMint(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxMint(caller, receiver); + } + + function test_previewMint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewMint(caller, receiver, other, shares); + } + + function test_mint(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_mint(caller, receiver, shares); + } + + // + // withdraw + // + + function test_maxWithdraw(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxWithdraw(caller, owner); + } + + function test_previewWithdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewWithdraw(caller, receiver, owner, other, assets); + } + + function test_withdraw(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, allowance); + prop_withdraw(caller, receiver, owner, assets); + } + + function testFail_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + vm.assume(caller != owner); + vm.assume(assets > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); uint shares = IERC4626(_vault_).withdraw(assets, receiver, owner); + assertGt(shares, 0); // this assert is expected to fail + } + + // + // redeem + // + + function test_maxRedeem(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxRedeem(caller, owner); + } + + function test_previewRedeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewRedeem(caller, receiver, owner, other, shares); + } + + function test_redeem(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, allowance); + prop_redeem(caller, receiver, owner, shares); + } + + function testFail_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + vm.assume(caller != owner); + vm.assume(shares > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); IERC4626(_vault_).redeem(shares, receiver, owner); + } + + // + // round trip tests + // + + function test_RT_deposit_redeem(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_redeem(caller, assets); + } + + function test_RT_deposit_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_withdraw(caller, assets); + } + + function test_RT_redeem_deposit(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_deposit(caller, shares); + } + + function test_RT_redeem_mint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_mint(caller, shares); + } + + function test_RT_mint_withdraw(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_withdraw(caller, shares); + } + + function test_RT_mint_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_redeem(caller, shares); + } + + function test_RT_withdraw_mint(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_mint(caller, assets); + } + + function test_RT_withdraw_deposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_deposit(caller, assets); + } + + // + // utils + // + + function _isContract(address account) internal view returns (bool) { return account.code.length > 0; } + function _isEOA (address account) internal view returns (bool) { return account.code.length == 0; } + + function _approve(address token, address owner, address spender, uint amount) internal { + vm.prank(owner); _safeApprove(token, spender, 0); + vm.prank(owner); _safeApprove(token, spender, amount); + } + + function _safeApprove(address token, address spender, uint amount) internal { + (bool success, bytes memory retdata) = token.call(abi.encodeWithSelector(IERC20.approve.selector, spender, amount)); + vm.assume(success); + if (retdata.length > 0) vm.assume(abi.decode(retdata, (bool))); + } + + function _max_deposit(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_underlying_).balanceOf(from); + } + + function _max_mint(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToShares(IERC20(_underlying_).balanceOf(from)); + } + + function _max_withdraw(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToAssets(IERC20(_vault_).balanceOf(from)); // may be different from maxWithdraw(from) + } + + function _max_redeem(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_vault_).balanceOf(from); // may be different from maxRedeem(from) + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/LICENSE b/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/README.md b/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/README.md new file mode 100644 index 0000000..651e443 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/erc4626-tests/README.md @@ -0,0 +1,116 @@ +# ERC4626 Property Tests + +Foundry (dapptools-style) property-based tests for [ERC4626] standard conformance. + +[ERC4626]: + +You can read our post on "_[Generalized property tests for ERC4626 vaults][post]_." + +[post]: + +## Overview + +#### What is it? +- Test suites for checking if the given ERC4626 implementation satisfies the **standard requirements**. +- Dapptools-style **property-based tests** for fuzzing or symbolic execution testing. +- Tests that are **independent** from implementation details, thus applicable for any ERC4626 vaults. + +#### What isn’t it? +- It does NOT test implementation-specific details, e.g., how to generate and distribute yields, how to compute the share price, etc. + +#### Testing properties: + +- **Round-trip properties**: no one can make a free profit by depositing and immediately withdrawing back and forth. + +- **Functional correctness**: the `deposit()`, `mint()`, `withdraw()`, and `redeem()` functions update the balance and allowance properly. + +- The `preview{Deposit,Redeem}()` functions **MUST NOT over-estimate** the exact amount.[^1] + +[^1]: That is, the `deposit()` and `redeem()` functions “MUST return the same or more amounts as their preview function if called in the same transaction.” + +- The `preview{Mint,Withdraw}()` functions **MUST NOT under-estimate** the exact amount.[^2] + +[^2]: That is, the `mint()` and `withdraw()` functions “MUST return the same or fewer amounts as their preview function if called in the same transaction.” + +- The `convertTo{Shares,Assets}` functions “**MUST NOT show any variations** depending on the caller.” + +- The `asset()`, `totalAssets()`, and `max{Deposit,Mint,Withdraw,Redeem}()` functions “**MUST NOT revert**.” + +## Usage + +**Step 0**: Install [foundry] and add [forge-std] in your vault repo: +```bash +$ curl -L https://foundry.paradigm.xyz | bash + +$ cd /path/to/your-erc4626-vault +$ forge install foundry-rs/forge-std +``` + +[foundry]: +[forge-std]: + +**Step 1**: Add this [erc4626-tests] as a dependency to your vault: +```bash +$ cd /path/to/your-erc4626-vault +$ forge install a16z/erc4626-tests +``` + +[erc4626-tests]: + +**Step 2**: Extend the abstract test contract [`ERC4626Test`](ERC4626.test.sol) with your own custom vault setup method, for example: + +```solidity +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "erc4626-tests/ERC4626.test.sol"; + +import { ERC20Mock } from "/path/to/mocks/ERC20Mock.sol"; +import { ERC4626Mock } from "/path/to/mocks/ERC4626Mock.sol"; + +contract ERC4626StdTest is ERC4626Test { + function setUp() public override { + _underlying_ = address(new ERC20Mock("Mock ERC20", "MERC20", 18)); + _vault_ = address(new ERC4626Mock(ERC20Mock(__underlying__), "Mock ERC4626", "MERC4626")); + _delta_ = 0; + _vaultMayBeEmpty = false; + _unlimitedAmount = false; + } +} +``` + +Specifically, set the state variables as follows: +- `_vault_`: the address of your ERC4626 vault. +- `_underlying_`: the address of the underlying asset of your vault. Note that the default `setupVault()` and `setupYield()` methods of `ERC4626Test` assume that it implements `mint(address to, uint value)` and `burn(address from, uint value)`. You can override the setup methods with your own if such `mint()` and `burn()` are not implemented. +- `_delta_`: the maximum approximation error size to be passed to [`assertApproxEqAbs()`]. It must be given as an absolute value (not a percentage) in the smallest unit (e.g., Wei or Satoshi). Note that all the tests are expected to pass with `__delta__ == 0` as long as your vault follows the [preferred rounding direction] as specified in the standard. If your vault doesn't follow the preferred rounding direction, you can set `__delta__` to a reasonable size of rounding errors where the adversarial profit of exploiting such rounding errors stays sufficiently small compared to the gas cost. (You can read our [post] for more about the adversarial profit.) +- `_vaultMayBeEmpty`: when set to false, fuzz inputs that empties the vault are ignored. +- `_unlimitedAmount`: when set to false, fuzz inputs are restricted to the currently available amount from the caller. Limiting the amount can speed up fuzzing, but may miss some edge cases. + +[`assertApproxEqAbs()`]: + +[preferred rounding direction]: + +**Step 3**: Run `forge test` + +``` +$ forge test +``` + +## Examples + +Below are examples of adding these property tests to existing ERC4626 vaults: +- [OpenZeppelin ERC4626] [[diff](https://github.com/daejunpark/openzeppelin-contracts/pull/1/files)] +- [Solmate ERC4626] [[diff](https://github.com/daejunpark/solmate/pull/1/files)] +- [Revenue Distribution Token] [[diff](https://github.com/daejunpark/revenue-distribution-token/pull/1/files)] +- [Yield Daddy ERC4626 wrappers] [[diff](https://github.com/daejunpark/yield-daddy/pull/1/files)][^bug] + +[OpenZeppelin ERC4626]: +[Solmate ERC4626]: +[Revenue Distribution Token]: +[Yield Daddy ERC4626 wrappers]: + +[^bug]: Our property tests indeed revealed an [issue](https://github.com/timeless-fi/yield-daddy/issues/7) in their eToken testing mock contract. The tests passed after it is [fixed](https://github.com/daejunpark/yield-daddy/commit/721cf4bd766805fd409455434aa5fd1a9b2df25c). + +## Disclaimer + +_These smart contracts are being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the user interface or the smart contracts. They have not been audited and as such there can be no assurance they will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. THE SMART CONTRACTS CONTAINED HEREIN ARE FURNISHED AS IS, WHERE IS, WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY, NON-INFRINGEMENT OR FITNESS FOR ANY PARTICULAR PURPOSE. Further, use of any of these smart contracts may be restricted or prohibited under applicable law, including securities laws, and it is therefore strongly advised for you to contact a reputable attorney in any jurisdiction where these smart contracts may be accessible for any questions or concerns with respect thereto. Further, no information provided in this repo should be construed as investment advice or legal advice for any particular facts or circumstances, and is not meant to replace competent counsel. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See a16z.com/disclosures for more info._ diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.github/workflows/ci.yml b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..96b2336 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + # Backwards compatibility checks. + - name: Check compatibility with 0.8.0 + if: always() + run: forge build --skip test --use solc:0.8.0 + + - name: Check compatibility with 0.7.6 + if: always() + run: forge build --skip test --use solc:0.7.6 + + - name: Check compatibility with 0.7.0 + if: always() + run: forge build --skip test --use solc:0.7.0 + + - name: Check compatibility with 0.6.12 + if: always() + run: forge build --skip test --use solc:0.6.12 + + - name: Check compatibility with 0.6.2 + if: always() + run: forge build --skip test --use solc:0.6.2 + + # via-ir compilation time checks. + - name: Measure compilation time of Test with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTest.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of TestBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTestBase.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of Script with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScript.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of ScriptBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScriptBase.sol --use solc:0.8.17 --via-ir + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Run tests + run: forge test -vvv + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Check formatting + run: forge fmt --check diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.gitignore b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.gitmodules b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.gitmodules new file mode 100644 index 0000000..e124719 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ds-test"] + path = lib/ds-test + url = https://github.com/dapphub/ds-test diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/LICENSE-APACHE b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/LICENSE-APACHE @@ -0,0 +1,203 @@ +Copyright Contributors to Forge Standard Library + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/LICENSE-MIT b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright Contributors to Forge Standard Library + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER +DEALINGS IN THE SOFTWARE.R diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/README.md b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/README.md new file mode 100644 index 0000000..8494a7d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/README.md @@ -0,0 +1,250 @@ +# Forge Standard Library • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml) + +Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes. + +**Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).** + +## Install + +```bash +forge install foundry-rs/forge-std +``` + +## Contracts +### stdError + +This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors. + +See the contract itself for all error codes. + +#### Example usage + +```solidity + +import "forge-std/Test.sol"; + +contract TestContract is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } +} + +contract ErrorsTest { + function arithmeticError(uint256 a) public { + uint256 a = a - 100; + } +} +``` + +### stdStorage + +This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`). + +This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth. + +I.e.: +```solidity +struct T { + // depth 0 + uint256 a; + // depth 1 + uint256 b; +} +``` + +#### Example usage + +```solidity +import "forge-std/Test.sol"; + +contract TestContract is Test { + using stdStorage for StdStorage; + + Storage test; + + function setUp() public { + test = new Storage(); + } + + function testFindExists() public { + // Lets say we want to find the slot for the public + // variable `exists`. We just pass in the function selector + // to the `find` command + uint256 slot = stdstore.target(address(test)).sig("exists()").find(); + assertEq(slot, 0); + } + + function testWriteExists() public { + // Lets say we want to write to the slot for the public + // variable `exists`. We just pass in the function selector + // to the `checked_write` command + stdstore.target(address(test)).sig("exists()").checked_write(100); + assertEq(test.exists(), 100); + } + + // It supports arbitrary storage layouts, like assembly based storage locations + function testFindHidden() public { + // `hidden` is a random hash of a bytes, iteration through slots would + // not find it. Our mechanism does + // Also, you can use the selector instead of a string + uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find(); + assertEq(slot, uint256(keccak256("my.random.var"))); + } + + // If targeting a mapping, you have to pass in the keys necessary to perform the find + // i.e.: + function testFindMapping() public { + uint256 slot = stdstore + .target(address(test)) + .sig(test.map_addr.selector) + .with_key(address(this)) + .find(); + // in the `Storage` constructor, we wrote that this address' value was 1 in the map + // so when we load the slot, we expect it to be 1 + assertEq(uint(vm.load(address(test), bytes32(slot))), 1); + } + + // If the target is a struct, you can specify the field depth: + function testFindStruct() public { + // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc. + uint256 slot_for_a_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(0) + .find(); + + uint256 slot_for_b_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(1) + .find(); + + assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1); + assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2); + } +} + +// A complex storage contract +contract Storage { + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + constructor() { + map_addr[msg.sender] = 1; + } + + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + // mapping(address => Packed) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basicStruct = UnpackedStruct({ + a: 1, + b: 2 + }); + + function hidden() public view returns (bytes32 t) { + // an extremely hidden storage slot + bytes32 slot = keccak256("my.random.var"); + assembly { + t := sload(slot) + } + } +} +``` + +### stdCheats + +This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you. + + +#### Example usage: +```solidity + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +// Inherit the stdCheats +contract StdCheatsTest is Test { + Bar test; + function setUp() public { + test = new Bar(); + } + + function testHoax() public { + // we call `hoax`, which gives the target address + // eth and then calls `prank` + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + + // overloaded to allow you to specify how much eth to + // initialize the address with + hoax(address(1337), 1); + test.bar{value: 1}(address(1337)); + } + + function testStartHoax() public { + // we call `startHoax`, which gives the target address + // eth and then calls `startPrank` + // + // it is also overloaded so that you can specify an eth amount + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } +} + +contract Bar { + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } +} +``` + +### Std Assertions + +Expand upon the assertion functions from the `DSTest` library. + +### `console.log` + +Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log). +It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console2.sol"; +... +console2.log(someValue); +``` + +If you need compatibility with Hardhat, you must use the standard `console.sol` instead. +Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console.sol"; +... +console.log(someValue); +``` + +## License + +Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/foundry.toml b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/foundry.toml new file mode 100644 index 0000000..36e4e63 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/foundry.toml @@ -0,0 +1,21 @@ +[profile.default] +fs_permissions = [{ access = "read-write", path = "./"}] + +[rpc_endpoints] +# The RPC URLs are modified versions of the default for testing initialization. +mainnet = "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5" # Different API key. +optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash. +arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash. +needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}" + +[fmt] +# These are all the `forge fmt` defaults. +line_length = 120 +tab_width = 4 +bracket_spacing = false +int_types = 'long' +multiline_func_header = 'attributes_first' +quote_style = 'double' +number_underscore = 'preserve' +single_line_statement_blocks = 'preserve' +ignore = ["src/console.sol", "src/console2.sol"] \ No newline at end of file diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/.github/workflows/build.yml b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/.github/workflows/build.yml new file mode 100644 index 0000000..a2c31df --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: "Build" +on: + pull_request: + push: +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v18 + with: + nix_path: nixpkgs=channel:nixos-unstable + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: setup dapp binary cache + uses: cachix/cachix-action@v12 + with: + name: dapp + + - name: install dapptools + run: nix profile install github:dapphub/dapptools#dapp --accept-flake-config + + - name: install foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: test with solc-0.5.17 + run: dapp --use solc-0.5.17 test -v + + - name: test with solc-0.6.11 + run: dapp --use solc-0.6.11 test -v + + - name: test with solc-0.7.6 + run: dapp --use solc-0.7.6 test -v + + - name: test with solc-0.8.18 + run: dapp --use solc-0.8.18 test -v + + - name: Run tests with foundry + run: forge test -vvv + diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/.gitignore b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/.gitignore new file mode 100644 index 0000000..462a994 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/.gitignore @@ -0,0 +1,4 @@ +/.dapple +/build +/out +/cache/ diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/LICENSE b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/Makefile b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/Makefile new file mode 100644 index 0000000..661dac4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/Makefile @@ -0,0 +1,14 @@ +all:; dapp build + +test: + -dapp --use solc:0.4.23 build + -dapp --use solc:0.4.26 build + -dapp --use solc:0.5.17 build + -dapp --use solc:0.6.12 build + -dapp --use solc:0.7.5 build + +demo: + DAPP_SRC=demo dapp --use solc:0.7.5 build + -hevm dapp-test --verbose 3 + +.PHONY: test demo diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/default.nix b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/default.nix new file mode 100644 index 0000000..cf65419 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/default.nix @@ -0,0 +1,4 @@ +{ solidityPackage, dappsys }: solidityPackage { + name = "ds-test"; + src = ./src; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/demo/demo.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/demo/demo.sol new file mode 100644 index 0000000..f3bb48e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/demo/demo.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import "../src/test.sol"; + +contract DemoTest is DSTest { + function test_this() public pure { + require(true); + } + function test_logs() public { + emit log("-- log(string)"); + emit log("a string"); + + emit log("-- log_named_uint(string, uint)"); + emit log_named_uint("uint", 512); + + emit log("-- log_named_int(string, int)"); + emit log_named_int("int", -512); + + emit log("-- log_named_address(string, address)"); + emit log_named_address("address", address(this)); + + emit log("-- log_named_bytes32(string, bytes32)"); + emit log_named_bytes32("bytes32", "a string"); + + emit log("-- log_named_bytes(string, bytes)"); + emit log_named_bytes("bytes", hex"cafefe"); + + emit log("-- log_named_string(string, string)"); + emit log_named_string("string", "a string"); + + emit log("-- log_named_decimal_uint(string, uint, uint)"); + emit log_named_decimal_uint("decimal uint", 1.0e18, 18); + + emit log("-- log_named_decimal_int(string, int, uint)"); + emit log_named_decimal_int("decimal int", -1.0e18, 18); + } + event log_old_named_uint(bytes32,uint); + function test_old_logs() public { + emit log_old_named_uint("key", 500); + emit log_named_bytes32("bkey", "val"); + } + function test_trace() public view { + this.echo("string 1", "string 2"); + } + function test_multiline() public { + emit log("a multiline\\nstring"); + emit log("a multiline string"); + emit log_bytes("a string"); + emit log_bytes("a multiline\nstring"); + emit log_bytes("a multiline\\nstring"); + emit logs(hex"0000"); + emit log_named_bytes("0x0000", hex"0000"); + emit logs(hex"ff"); + } + function echo(string memory s1, string memory s2) public pure + returns (string memory, string memory) + { + return (s1, s2); + } + + function prove_this(uint x) public { + emit log_named_uint("sym x", x); + assertGt(x + 1, 0); + } + + function test_logn() public { + assembly { + log0(0x01, 0x02) + log1(0x01, 0x02, 0x03) + log2(0x01, 0x02, 0x03, 0x04) + log3(0x01, 0x02, 0x03, 0x04, 0x05) + } + } + + event MyEvent(uint, uint indexed, uint, uint indexed); + function test_events() public { + emit MyEvent(1, 2, 3, 4); + } + + function test_asserts() public { + string memory err = "this test has failed!"; + emit log("## assertTrue(bool)\n"); + assertTrue(false); + emit log("\n"); + assertTrue(false, err); + + emit log("\n## assertEq(address,address)\n"); + assertEq(address(this), msg.sender); + emit log("\n"); + assertEq(address(this), msg.sender, err); + + emit log("\n## assertEq32(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(uint,uint)\n"); + assertEq(uint(0), 1); + emit log("\n"); + assertEq(uint(0), 1, err); + + emit log("\n## assertEq(int,int)\n"); + assertEq(-1, -2); + emit log("\n"); + assertEq(-1, -2, err); + + emit log("\n## assertEqDecimal(int,int,uint)\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertEqDecimal(uint,uint,uint)\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGt(uint,uint)\n"); + assertGt(uint(0), 0); + emit log("\n"); + assertGt(uint(0), 0, err); + + emit log("\n## assertGt(int,int)\n"); + assertGt(-1, -1); + emit log("\n"); + assertGt(-1, -1, err); + + emit log("\n## assertGtDecimal(int,int,uint)\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGtDecimal(uint,uint,uint)\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGe(uint,uint)\n"); + assertGe(uint(0), 1); + emit log("\n"); + assertGe(uint(0), 1, err); + + emit log("\n## assertGe(int,int)\n"); + assertGe(-1, 0); + emit log("\n"); + assertGe(-1, 0, err); + + emit log("\n## assertGeDecimal(int,int,uint)\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGeDecimal(uint,uint,uint)\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertLt(uint,uint)\n"); + assertLt(uint(0), 0); + emit log("\n"); + assertLt(uint(0), 0, err); + + emit log("\n## assertLt(int,int)\n"); + assertLt(-1, -1); + emit log("\n"); + assertLt(-1, -1, err); + + emit log("\n## assertLtDecimal(int,int,uint)\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLtDecimal(uint,uint,uint)\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertLe(uint,uint)\n"); + assertLe(uint(1), 0); + emit log("\n"); + assertLe(uint(1), 0, err); + + emit log("\n## assertLe(int,int)\n"); + assertLe(0, -1); + emit log("\n"); + assertLe(0, -1, err); + + emit log("\n## assertLeDecimal(int,int,uint)\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLeDecimal(uint,uint,uint)\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertEq(string,string)\n"); + string memory s1 = "string 1"; + string memory s2 = "string 2"; + assertEq(s1, s2); + emit log("\n"); + assertEq(s1, s2, err); + + emit log("\n## assertEq0(bytes,bytes)\n"); + assertEq0(hex"abcdef01", hex"abcdef02"); + emit log("\n"); + assertEq0(hex"abcdef01", hex"abcdef02", err); + } +} + +contract DemoTestWithSetUp { + function setUp() public { + } + function test_pass() public pure { + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/package.json b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/package.json new file mode 100644 index 0000000..4802ada --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "ds-test", + "version": "1.0.0", + "description": "Assertions, equality checks and other test helpers ", + "bugs": "https://github.com/dapphub/ds-test/issues", + "license": "GPL-3.0", + "author": "Contributors to ds-test", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/dapphub/ds-test.git" + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/src/test.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/src/test.sol new file mode 100644 index 0000000..de504d3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/src/test.sol @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.5.0; + +contract DSTest { + event log (string); + event logs (bytes); + + event log_address (address); + event log_bytes32 (bytes32); + event log_int (int); + event log_uint (uint); + event log_bytes (bytes); + event log_string (string); + + event log_named_address (string key, address val); + event log_named_bytes32 (string key, bytes32 val); + event log_named_decimal_int (string key, int val, uint decimals); + event log_named_decimal_uint (string key, uint val, uint decimals); + event log_named_int (string key, int val); + event log_named_uint (string key, uint val); + event log_named_bytes (string key, bytes val); + event log_named_string (string key, string val); + + bool public IS_TEST = true; + bool private _failed; + + address constant HEVM_ADDRESS = + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); + + modifier mayRevert() { _; } + modifier testopts(string memory) { _; } + + function failed() public returns (bool) { + if (_failed) { + return _failed; + } else { + bool globalFailed = false; + if (hasHEVMContext()) { + (, bytes memory retdata) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("load(address,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed")) + ) + ); + globalFailed = abi.decode(retdata, (bool)); + } + return globalFailed; + } + } + + function fail() internal virtual { + if (hasHEVMContext()) { + (bool status, ) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("store(address,bytes32,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) + ) + ); + status; // Silence compiler warnings + } + _failed = true; + } + + function hasHEVMContext() internal view returns (bool) { + uint256 hevmCodeSize = 0; + assembly { + hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) + } + return hevmCodeSize > 0; + } + + modifier logs_gas() { + uint startGas = gasleft(); + _; + uint endGas = gasleft(); + emit log_named_uint("gas", startGas - endGas); + } + + function assertTrue(bool condition) internal { + if (!condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertTrue(bool condition, string memory err) internal { + if (!condition) { + emit log_named_string("Error", err); + assertTrue(condition); + } + } + + function assertEq(address a, address b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [address]"); + emit log_named_address(" Left", a); + emit log_named_address(" Right", b); + fail(); + } + } + function assertEq(address a, address b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes32 a, bytes32 b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [bytes32]"); + emit log_named_bytes32(" Left", a); + emit log_named_bytes32(" Right", b); + fail(); + } + } + function assertEq(bytes32 a, bytes32 b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + function assertEq32(bytes32 a, bytes32 b) internal { + assertEq(a, b); + } + function assertEq32(bytes32 a, bytes32 b, string memory err) internal { + assertEq(a, b, err); + } + + function assertEq(int a, int b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + fail(); + } + } + function assertEq(int a, int b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEq(uint a, uint b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + fail(); + } + } + function assertEq(uint a, uint b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEqDecimal(int a, int b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal int]"); + emit log_named_decimal_int(" Left", a, decimals); + emit log_named_decimal_int(" Right", b, decimals); + fail(); + } + } + function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + function assertEqDecimal(uint a, uint b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Left", a, decimals); + emit log_named_decimal_uint(" Right", b, decimals); + fail(); + } + } + function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + + function assertGt(uint a, uint b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGt(uint a, uint b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGt(int a, int b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGt(int a, int b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGtDecimal(int a, int b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + function assertGtDecimal(uint a, uint b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + + function assertGe(uint a, uint b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGe(uint a, uint b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGe(int a, int b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGe(int a, int b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGeDecimal(int a, int b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + function assertGeDecimal(uint a, uint b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertLt(uint a, uint b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLt(uint a, uint b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLt(int a, int b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLt(int a, int b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLtDecimal(int a, int b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + function assertLtDecimal(uint a, uint b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + + function assertLe(uint a, uint b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLe(uint a, uint b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLe(int a, int b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLe(int a, int b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLeDecimal(int a, int b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + function assertLeDecimal(uint a, uint b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + + function assertEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log("Error: a == b not satisfied [string]"); + emit log_named_string(" Left", a); + emit log_named_string(" Right", b); + fail(); + } + } + function assertEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { + ok = true; + if (a.length == b.length) { + for (uint i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + ok = false; + } + } + } else { + ok = false; + } + } + function assertEq0(bytes memory a, bytes memory b) internal { + if (!checkEq0(a, b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Left", a); + emit log_named_bytes(" Right", b); + fail(); + } + } + function assertEq0(bytes memory a, bytes memory b, string memory err) internal { + if (!checkEq0(a, b)) { + emit log_named_string("Error", err); + assertEq0(a, b); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/src/test.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/src/test.t.sol new file mode 100644 index 0000000..996f52f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/lib/ds-test/src/test.t.sol @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import {DSTest} from "./test.sol"; + +contract DemoTest is DSTest { + + // --- assertTrue --- + + function testAssertTrue() public { + assertTrue(true, "msg"); + assertTrue(true); + } + function testFailAssertTrue() public { + assertTrue(false); + } + function testFailAssertTrueWithMsg() public { + assertTrue(false, "msg"); + } + + // --- assertEq (Addr) --- + + function testAssertEqAddr() public { + assertEq(address(0x0), address(0x0), "msg"); + assertEq(address(0x0), address(0x0)); + } + function testFailAssertEqAddr() public { + assertEq(address(0x0), address(0x1)); + } + function testFailAssertEqAddrWithMsg() public { + assertEq(address(0x0), address(0x1), "msg"); + } + + // --- assertEq (Bytes32) --- + + function testAssertEqBytes32() public { + assertEq(bytes32("hi"), bytes32("hi"), "msg"); + assertEq(bytes32("hi"), bytes32("hi")); + } + function testFailAssertEqBytes32() public { + assertEq(bytes32("hi"), bytes32("ho")); + } + function testFailAssertEqBytes32WithMsg() public { + assertEq(bytes32("hi"), bytes32("ho"), "msg"); + } + + // --- assertEq (Int) --- + + function testAssertEqInt() public { + assertEq(-1, -1, "msg"); + assertEq(-1, -1); + } + function testFailAssertEqInt() public { + assertEq(-1, -2); + } + function testFailAssertEqIntWithMsg() public { + assertEq(-1, -2, "msg"); + } + + // --- assertEq (UInt) --- + + function testAssertEqUInt() public { + assertEq(uint(1), uint(1), "msg"); + assertEq(uint(1), uint(1)); + } + function testFailAssertEqUInt() public { + assertEq(uint(1), uint(2)); + } + function testFailAssertEqUIntWithMsg() public { + assertEq(uint(1), uint(2), "msg"); + } + + // --- assertEqDecimal (Int) --- + + function testAssertEqDecimalInt() public { + assertEqDecimal(-1, -1, 18, "msg"); + assertEqDecimal(-1, -1, 18); + } + function testFailAssertEqDecimalInt() public { + assertEqDecimal(-1, -2, 18); + } + function testFailAssertEqDecimalIntWithMsg() public { + assertEqDecimal(-1, -2, 18, "msg"); + } + + // --- assertEqDecimal (UInt) --- + + function testAssertEqDecimalUInt() public { + assertEqDecimal(uint(1), uint(1), 18, "msg"); + assertEqDecimal(uint(1), uint(1), 18); + } + function testFailAssertEqDecimalUInt() public { + assertEqDecimal(uint(1), uint(2), 18); + } + function testFailAssertEqDecimalUIntWithMsg() public { + assertEqDecimal(uint(1), uint(2), 18, "msg"); + } + + // --- assertGt (UInt) --- + + function testAssertGtUInt() public { + assertGt(uint(2), uint(1), "msg"); + assertGt(uint(3), uint(2)); + } + function testFailAssertGtUInt() public { + assertGt(uint(1), uint(2)); + } + function testFailAssertGtUIntWithMsg() public { + assertGt(uint(1), uint(2), "msg"); + } + + // --- assertGt (Int) --- + + function testAssertGtInt() public { + assertGt(-1, -2, "msg"); + assertGt(-1, -3); + } + function testFailAssertGtInt() public { + assertGt(-2, -1); + } + function testFailAssertGtIntWithMsg() public { + assertGt(-2, -1, "msg"); + } + + // --- assertGtDecimal (UInt) --- + + function testAssertGtDecimalUInt() public { + assertGtDecimal(uint(2), uint(1), 18, "msg"); + assertGtDecimal(uint(3), uint(2), 18); + } + function testFailAssertGtDecimalUInt() public { + assertGtDecimal(uint(1), uint(2), 18); + } + function testFailAssertGtDecimalUIntWithMsg() public { + assertGtDecimal(uint(1), uint(2), 18, "msg"); + } + + // --- assertGtDecimal (Int) --- + + function testAssertGtDecimalInt() public { + assertGtDecimal(-1, -2, 18, "msg"); + assertGtDecimal(-1, -3, 18); + } + function testFailAssertGtDecimalInt() public { + assertGtDecimal(-2, -1, 18); + } + function testFailAssertGtDecimalIntWithMsg() public { + assertGtDecimal(-2, -1, 18, "msg"); + } + + // --- assertGe (UInt) --- + + function testAssertGeUInt() public { + assertGe(uint(2), uint(1), "msg"); + assertGe(uint(2), uint(2)); + } + function testFailAssertGeUInt() public { + assertGe(uint(1), uint(2)); + } + function testFailAssertGeUIntWithMsg() public { + assertGe(uint(1), uint(2), "msg"); + } + + // --- assertGe (Int) --- + + function testAssertGeInt() public { + assertGe(-1, -2, "msg"); + assertGe(-1, -1); + } + function testFailAssertGeInt() public { + assertGe(-2, -1); + } + function testFailAssertGeIntWithMsg() public { + assertGe(-2, -1, "msg"); + } + + // --- assertGeDecimal (UInt) --- + + function testAssertGeDecimalUInt() public { + assertGeDecimal(uint(2), uint(1), 18, "msg"); + assertGeDecimal(uint(2), uint(2), 18); + } + function testFailAssertGeDecimalUInt() public { + assertGeDecimal(uint(1), uint(2), 18); + } + function testFailAssertGeDecimalUIntWithMsg() public { + assertGeDecimal(uint(1), uint(2), 18, "msg"); + } + + // --- assertGeDecimal (Int) --- + + function testAssertGeDecimalInt() public { + assertGeDecimal(-1, -2, 18, "msg"); + assertGeDecimal(-1, -2, 18); + } + function testFailAssertGeDecimalInt() public { + assertGeDecimal(-2, -1, 18); + } + function testFailAssertGeDecimalIntWithMsg() public { + assertGeDecimal(-2, -1, 18, "msg"); + } + + // --- assertLt (UInt) --- + + function testAssertLtUInt() public { + assertLt(uint(1), uint(2), "msg"); + assertLt(uint(1), uint(3)); + } + function testFailAssertLtUInt() public { + assertLt(uint(2), uint(2)); + } + function testFailAssertLtUIntWithMsg() public { + assertLt(uint(3), uint(2), "msg"); + } + + // --- assertLt (Int) --- + + function testAssertLtInt() public { + assertLt(-2, -1, "msg"); + assertLt(-1, 0); + } + function testFailAssertLtInt() public { + assertLt(-1, -2); + } + function testFailAssertLtIntWithMsg() public { + assertLt(-1, -1, "msg"); + } + + // --- assertLtDecimal (UInt) --- + + function testAssertLtDecimalUInt() public { + assertLtDecimal(uint(1), uint(2), 18, "msg"); + assertLtDecimal(uint(2), uint(3), 18); + } + function testFailAssertLtDecimalUInt() public { + assertLtDecimal(uint(1), uint(1), 18); + } + function testFailAssertLtDecimalUIntWithMsg() public { + assertLtDecimal(uint(2), uint(1), 18, "msg"); + } + + // --- assertLtDecimal (Int) --- + + function testAssertLtDecimalInt() public { + assertLtDecimal(-2, -1, 18, "msg"); + assertLtDecimal(-2, -1, 18); + } + function testFailAssertLtDecimalInt() public { + assertLtDecimal(-2, -2, 18); + } + function testFailAssertLtDecimalIntWithMsg() public { + assertLtDecimal(-1, -2, 18, "msg"); + } + + // --- assertLe (UInt) --- + + function testAssertLeUInt() public { + assertLe(uint(1), uint(2), "msg"); + assertLe(uint(1), uint(1)); + } + function testFailAssertLeUInt() public { + assertLe(uint(4), uint(2)); + } + function testFailAssertLeUIntWithMsg() public { + assertLe(uint(3), uint(2), "msg"); + } + + // --- assertLe (Int) --- + + function testAssertLeInt() public { + assertLe(-2, -1, "msg"); + assertLe(-1, -1); + } + function testFailAssertLeInt() public { + assertLe(-1, -2); + } + function testFailAssertLeIntWithMsg() public { + assertLe(-1, -3, "msg"); + } + + // --- assertLeDecimal (UInt) --- + + function testAssertLeDecimalUInt() public { + assertLeDecimal(uint(1), uint(2), 18, "msg"); + assertLeDecimal(uint(2), uint(2), 18); + } + function testFailAssertLeDecimalUInt() public { + assertLeDecimal(uint(1), uint(0), 18); + } + function testFailAssertLeDecimalUIntWithMsg() public { + assertLeDecimal(uint(1), uint(0), 18, "msg"); + } + + // --- assertLeDecimal (Int) --- + + function testAssertLeDecimalInt() public { + assertLeDecimal(-2, -1, 18, "msg"); + assertLeDecimal(-2, -2, 18); + } + function testFailAssertLeDecimalInt() public { + assertLeDecimal(-2, -3, 18); + } + function testFailAssertLeDecimalIntWithMsg() public { + assertLeDecimal(-1, -2, 18, "msg"); + } + + // --- fail override --- + + // ensure that fail can be overridden + function fail() internal override { + super.fail(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/package.json b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/package.json new file mode 100644 index 0000000..96003f7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.5.0", + "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", + "homepage": "https://book.getfoundry.sh/forge/forge-std", + "bugs": "https://github.com/foundry-rs/forge-std/issues", + "license": "(Apache-2.0 OR MIT)", + "author": "Contributors to Forge Standard Library", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/foundry-rs/forge-std.git" + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Base.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..83c5c1c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Base.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {StdStorage} from "./StdStorage.sol"; +import {Vm, VmSafe} from "./Vm.sol"; + +abstract contract CommonBase { + // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. + address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + // console.sol and console2.sol work by executing a staticcall to this address. + address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; + // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38. + address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))); + // Address of the test contract, deployed by the DEFAULT_SENDER. + address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; + // Deterministic deployment address of the Multicall3 contract. + address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11; + + uint256 internal constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + Vm internal constant vm = Vm(VM_ADDRESS); + StdStorage internal stdstore; +} + +abstract contract TestBase is CommonBase {} + +abstract contract ScriptBase is CommonBase { + // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Script.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..bffccad --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Script.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Standard Library's default Script. + +// 🧩 MODULES +import {ScriptBase} from "./Base.sol"; +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheatsSafe} from "./StdCheats.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorageSafe} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {VmSafe} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {ScriptBase} from "./Base.sol"; + +// ⭐️ SCRIPT +abstract contract Script is StdChains, StdCheatsSafe, StdUtils, ScriptBase { + // Note: IS_SCRIPT() must return true. + bool public IS_SCRIPT = true; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdAssertions.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..198a1ba --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {DSTest} from "ds-test/test.sol"; +import {stdMath} from "./StdMath.sol"; + +abstract contract StdAssertions is DSTest { + event log_array(uint256[] val); + event log_array(int256[] val); + event log_array(address[] val); + event log_named_array(string key, uint256[] val); + event log_named_array(string key, int256[] val); + event log_named_array(string key, address[] val); + + function fail(string memory err) internal virtual { + emit log_named_string("Error", err); + fail(); + } + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); + } + + function assertEq(bool a, bool b) internal virtual { + if (a != b) { + emit log("Error: a == b not satisfied [bool]"); + emit log_named_string(" Left", a ? "true" : "false"); + emit log_named_string(" Right", b ? "true" : "false"); + fail(); + } + } + + function assertEq(bool a, bool b, string memory err) internal virtual { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes memory a, bytes memory b) internal virtual { + assertEq0(a, b); + } + + function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { + assertEq0(a, b, err); + } + + function assertEq(uint256[] memory a, uint256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [uint[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(int256[] memory a, int256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [int[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(address[] memory a, address[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [address[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + // Legacy helper + function assertEqUint(uint256 a, uint256 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_decimal_uint(" Left", a, decimals); + emit log_named_decimal_uint(" Right", b, decimals); + emit log_named_decimal_uint(" Max Delta", maxDelta, decimals); + emit log_named_decimal_uint(" Delta", delta, decimals); + fail(); + } + } + + function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, string memory err) + internal + virtual + { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_decimal_int(" Left", a, decimals); + emit log_named_decimal_int(" Right", b, decimals); + emit log_named_decimal_uint(" Max Delta", maxDelta, decimals); + emit log_named_decimal_uint(" Delta", delta, decimals); + fail(); + } + } + + function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, string memory err) + internal + virtual + { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_decimal_uint(" Left", a, decimals); + emit log_named_decimal_uint(" Right", b, decimals); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_decimal_int(" Left", a, decimals); + emit log_named_decimal_int(" Right", b, decimals); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, string memory err) + internal + virtual + { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + } + + function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB) internal virtual { + assertEqCall(target, callDataA, target, callDataB, true); + } + + function assertEqCall(address targetA, bytes memory callDataA, address targetB, bytes memory callDataB) + internal + virtual + { + assertEqCall(targetA, callDataA, targetB, callDataB, true); + } + + function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB, bool strictRevertData) + internal + virtual + { + assertEqCall(target, callDataA, target, callDataB, strictRevertData); + } + + function assertEqCall( + address targetA, + bytes memory callDataA, + address targetB, + bytes memory callDataB, + bool strictRevertData + ) internal virtual { + (bool successA, bytes memory returnDataA) = address(targetA).call(callDataA); + (bool successB, bytes memory returnDataB) = address(targetB).call(callDataB); + + if (successA && successB) { + assertEq(returnDataA, returnDataB, "Call return data does not match"); + } + + if (!successA && !successB && strictRevertData) { + assertEq(returnDataA, returnDataB, "Call revert data does not match"); + } + + if (!successA && successB) { + emit log("Error: Calls were not equal"); + emit log_named_bytes(" Left call revert data", returnDataA); + emit log_named_bytes(" Right call return data", returnDataB); + fail(); + } + + if (successA && !successB) { + emit log("Error: Calls were not equal"); + emit log_named_bytes(" Left call return data", returnDataA); + emit log_named_bytes(" Right call revert data", returnDataB); + fail(); + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdChains.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..b1f0e6d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdChains.sol @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +/** + * StdChains provides information about EVM compatible chains that can be used in scripts/tests. + * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are + * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of + * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the + * alias used in this contract, which can be found as the first argument to the + * `setChainWithDefaultRpcUrl` call in the `initialize` function. + * + * There are two main ways to use this contract: + * 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or + * `setChain(string memory chainAlias, Chain memory chain)` + * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. + * + * The first time either of those are used, chains are initialized with the default set of RPC URLs. + * This is done in `initialize`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in + * `defaultRpcUrls`. + * + * The `setChain` function is straightforward, and it simply saves off the given chain data. + * + * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say + * we want to retrieve `mainnet`'s RPC URL: + * - If you haven't set any mainnet chain info with `setChain`, you haven't specified that + * chain in `foundry.toml` and no env var is set, the default data and RPC URL will be returned. + * - If you have set a mainnet RPC URL in `foundry.toml` it will return that, if valid (e.g. if + * a URL is given or if an environment variable is given and that environment variable exists). + * Otherwise, the default data is returned. + * - If you specified data with `setChain` it will return that. + * + * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults. + */ +abstract contract StdChains { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private initialized; + + struct ChainData { + string name; + uint256 chainId; + string rpcUrl; + } + + struct Chain { + // The chain name. + string name; + // The chain's Chain ID. + uint256 chainId; + // The chain's alias. (i.e. what gets specified in `foundry.toml`). + string chainAlias; + // A default RPC endpoint for this chain. + // NOTE: This default RPC URL is included for convenience to facilitate quick tests and + // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy + // usage as you will be throttled and this is a disservice to others who need this endpoint. + string rpcUrl; + } + + // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data. + mapping(string => Chain) private chains; + // Maps from the chain's alias to it's default RPC URL. + mapping(string => string) private defaultRpcUrls; + // Maps from a chain ID to it's alias. + mapping(uint256 => string) private idToAlias; + + bool private fallbackToDefaultRpcUrls = true; + + // The RPC URL will be fetched from config or defaultRpcUrls if possible. + function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) { + require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string."); + + initialize(); + chain = chains[chainAlias]; + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + function getChain(uint256 chainId) internal virtual returns (Chain memory chain) { + require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0."); + initialize(); + string memory chainAlias = idToAlias[chainId]; + + chain = chains[chainAlias]; + + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, ChainData memory chain) internal virtual { + require( + bytes(chainAlias).length != 0, + "StdChains setChain(string,ChainData): Chain alias cannot be the empty string." + ); + + require(chain.chainId != 0, "StdChains setChain(string,ChainData): Chain ID cannot be 0."); + + initialize(); + string memory foundAlias = idToAlias[chain.chainId]; + + require( + bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)), + string( + abi.encodePacked( + "StdChains setChain(string,ChainData): Chain ID ", + vm.toString(chain.chainId), + " already used by \"", + foundAlias, + "\"." + ) + ) + ); + + uint256 oldChainId = chains[chainAlias].chainId; + delete idToAlias[oldChainId]; + + chains[chainAlias] = + Chain({name: chain.name, chainId: chain.chainId, chainAlias: chainAlias, rpcUrl: chain.rpcUrl}); + idToAlias[chain.chainId] = chainAlias; + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, Chain memory chain) internal virtual { + setChain(chainAlias, ChainData({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl})); + } + + function _toUpper(string memory str) private pure returns (string memory) { + bytes memory strb = bytes(str); + bytes memory copy = new bytes(strb.length); + for (uint256 i = 0; i < strb.length; i++) { + bytes1 b = strb[i]; + if (b >= 0x61 && b <= 0x7A) { + copy[i] = bytes1(uint8(b) - 32); + } else { + copy[i] = b; + } + } + return string(copy); + } + + // lookup rpcUrl, in descending order of priority: + // current -> config (foundry.toml) -> environment variable -> default + function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) private returns (Chain memory) { + if (bytes(chain.rpcUrl).length == 0) { + try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) { + chain.rpcUrl = configRpcUrl; + } catch (bytes memory err) { + string memory envName = string(abi.encodePacked(_toUpper(chainAlias), "_RPC_URL")); + if (fallbackToDefaultRpcUrls) { + chain.rpcUrl = vm.envOr(envName, defaultRpcUrls[chainAlias]); + } else { + chain.rpcUrl = vm.envString(envName); + } + // distinguish 'not found' from 'cannot read' + bytes memory notFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + if (keccak256(notFoundError) != keccak256(err) || bytes(chain.rpcUrl).length == 0) { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, err), mload(err)) + } + } + } + } + return chain; + } + + function setFallbackToDefaultRpcUrls(bool useDefault) internal { + fallbackToDefaultRpcUrls = useDefault; + } + + function initialize() private { + if (initialized) return; + + initialized = true; + + // If adding an RPC here, make sure to test the default RPC URL in `testRpcs` + setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545")); + setChainWithDefaultRpcUrl( + "mainnet", ChainData("Mainnet", 1, "https://mainnet.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b") + ); + setChainWithDefaultRpcUrl( + "goerli", ChainData("Goerli", 5, "https://goerli.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b") + ); + setChainWithDefaultRpcUrl( + "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b") + ); + setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io")); + setChainWithDefaultRpcUrl("optimism_goerli", ChainData("Optimism Goerli", 420, "https://goerli.optimism.io")); + setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl( + "arbitrum_one_goerli", ChainData("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc") + ); + setChainWithDefaultRpcUrl("arbitrum_nova", ChainData("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl("polygon", ChainData("Polygon", 137, "https://polygon-rpc.com")); + setChainWithDefaultRpcUrl( + "polygon_mumbai", ChainData("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com") + ); + setChainWithDefaultRpcUrl("avalanche", ChainData("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc")); + setChainWithDefaultRpcUrl( + "avalanche_fuji", ChainData("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc") + ); + setChainWithDefaultRpcUrl( + "bnb_smart_chain", ChainData("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org") + ); + setChainWithDefaultRpcUrl( + "bnb_smart_chain_testnet", + ChainData("BNB Smart Chain Testnet", 97, "https://rpc.ankr.com/bsc_testnet_chapel") + ); + setChainWithDefaultRpcUrl("gnosis_chain", ChainData("Gnosis Chain", 100, "https://rpc.gnosischain.com")); + } + + // set chain info, with priority to chainAlias' rpc url in foundry.toml + function setChainWithDefaultRpcUrl(string memory chainAlias, ChainData memory chain) private { + string memory rpcUrl = chain.rpcUrl; + defaultRpcUrls[chainAlias] = rpcUrl; + chain.rpcUrl = ""; + setChain(chainAlias, chain); + chain.rpcUrl = rpcUrl; // restore argument + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdCheats.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..126d831 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdCheats.sol @@ -0,0 +1,624 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {Vm} from "./Vm.sol"; + +abstract contract StdCheatsSafe { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private gasMeteringOff; + + // Data structures to parse Transaction objects from the broadcast artifact + // that conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawTx1559 { + string[] arguments; + address contractAddress; + string contractName; + // json value name = function + string functionSig; + bytes32 hash; + // json value name = tx + RawTx1559Detail txDetail; + // json value name = type + string opcode; + } + + struct RawTx1559Detail { + AccessList[] accessList; + bytes data; + address from; + bytes gas; + bytes nonce; + address to; + bytes txType; + bytes value; + } + + struct Tx1559 { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + bytes32 hash; + Tx1559Detail txDetail; + string opcode; + } + + struct Tx1559Detail { + AccessList[] accessList; + bytes data; + address from; + uint256 gas; + uint256 nonce; + address to; + uint256 txType; + uint256 value; + } + + // Data structures to parse Transaction objects from the broadcast artifact + // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct TxLegacy { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + string hash; + string opcode; + TxDetailLegacy transaction; + } + + struct TxDetailLegacy { + AccessList[] accessList; + uint256 chainId; + bytes data; + address from; + uint256 gas; + uint256 gasPrice; + bytes32 hash; + uint256 nonce; + bytes1 opcode; + bytes32 r; + bytes32 s; + uint256 txType; + address to; + uint8 v; + uint256 value; + } + + struct AccessList { + address accessAddress; + bytes32[] storageKeys; + } + + // Data structures to parse Receipt objects from the broadcast artifact. + // The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawReceipt { + bytes32 blockHash; + bytes blockNumber; + address contractAddress; + bytes cumulativeGasUsed; + bytes effectiveGasPrice; + address from; + bytes gasUsed; + RawReceiptLog[] logs; + bytes logsBloom; + bytes status; + address to; + bytes32 transactionHash; + bytes transactionIndex; + } + + struct Receipt { + bytes32 blockHash; + uint256 blockNumber; + address contractAddress; + uint256 cumulativeGasUsed; + uint256 effectiveGasPrice; + address from; + uint256 gasUsed; + ReceiptLog[] logs; + bytes logsBloom; + uint256 status; + address to; + bytes32 transactionHash; + uint256 transactionIndex; + } + + // Data structures to parse the entire broadcast artifact, assuming the + // transactions conform to EIP1559. + + struct EIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + Receipt[] receipts; + uint256 timestamp; + Tx1559[] transactions; + TxReturn[] txReturns; + } + + struct RawEIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + RawReceipt[] receipts; + TxReturn[] txReturns; + uint256 timestamp; + RawTx1559[] transactions; + } + + struct RawReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + bytes blockNumber; + bytes data; + bytes logIndex; + bool removed; + bytes32[] topics; + bytes32 transactionHash; + bytes transactionIndex; + bytes transactionLogIndex; + } + + struct ReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + uint256 blockNumber; + bytes data; + uint256 logIndex; + bytes32[] topics; + uint256 transactionIndex; + uint256 transactionLogIndex; + bool removed; + } + + struct TxReturn { + string internalType; + string value; + } + + function assumeNoPrecompiles(address addr) internal virtual { + // Assembly required since `block.chainid` was introduced in 0.8.0. + uint256 chainId; + assembly { + chainId := chainid() + } + assumeNoPrecompiles(addr, chainId); + } + + function assumeNoPrecompiles(address addr, uint256 chainId) internal pure virtual { + // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific + // address), but the same rationale for excluding them applies so we include those too. + + // These should be present on all EVM-compatible chains. + vm.assume(addr < address(0x1) || addr > address(0x9)); + + // forgefmt: disable-start + if (chainId == 10 || chainId == 420) { + // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21 + vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800)); + } else if (chainId == 42161 || chainId == 421613) { + // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains + vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068)); + } else if (chainId == 43114 || chainId == 43113) { + // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59 + vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff)); + vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF)); + vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff)); + } + // forgefmt: disable-end + } + + function readEIP1559ScriptArtifact(string memory path) + internal + view + virtual + returns (EIP1559ScriptArtifact memory) + { + string memory data = vm.readFile(path); + bytes memory parsedData = vm.parseJson(data); + RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact)); + EIP1559ScriptArtifact memory artifact; + artifact.libraries = rawArtifact.libraries; + artifact.path = rawArtifact.path; + artifact.timestamp = rawArtifact.timestamp; + artifact.pending = rawArtifact.pending; + artifact.txReturns = rawArtifact.txReturns; + artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts); + artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions); + return artifact; + } + + function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) { + Tx1559[] memory txs = new Tx1559[](rawTxs.length); + for (uint256 i; i < rawTxs.length; i++) { + txs[i] = rawToConvertedEIPTx1559(rawTxs[i]); + } + return txs; + } + + function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) { + Tx1559 memory transaction; + transaction.arguments = rawTx.arguments; + transaction.contractName = rawTx.contractName; + transaction.functionSig = rawTx.functionSig; + transaction.hash = rawTx.hash; + transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail); + transaction.opcode = rawTx.opcode; + return transaction; + } + + function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail) + internal + pure + virtual + returns (Tx1559Detail memory) + { + Tx1559Detail memory txDetail; + txDetail.data = rawDetail.data; + txDetail.from = rawDetail.from; + txDetail.to = rawDetail.to; + txDetail.nonce = _bytesToUint(rawDetail.nonce); + txDetail.txType = _bytesToUint(rawDetail.txType); + txDetail.value = _bytesToUint(rawDetail.value); + txDetail.gas = _bytesToUint(rawDetail.gas); + txDetail.accessList = rawDetail.accessList; + return txDetail; + } + + function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions"); + RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[])); + return rawToConvertedEIPTx1559s(rawTxs); + } + + function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559)); + return rawToConvertedEIPTx1559(rawTx); + } + + // Analogous to readTransactions, but for receipts. + function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts"); + RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[])); + return rawToConvertedReceipts(rawReceipts); + } + + function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt)); + return rawToConvertedReceipt(rawReceipt); + } + + function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) { + Receipt[] memory receipts = new Receipt[](rawReceipts.length); + for (uint256 i; i < rawReceipts.length; i++) { + receipts[i] = rawToConvertedReceipt(rawReceipts[i]); + } + return receipts; + } + + function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) { + Receipt memory receipt; + receipt.blockHash = rawReceipt.blockHash; + receipt.to = rawReceipt.to; + receipt.from = rawReceipt.from; + receipt.contractAddress = rawReceipt.contractAddress; + receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice); + receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed); + receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed); + receipt.status = _bytesToUint(rawReceipt.status); + receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex); + receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber); + receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs); + receipt.logsBloom = rawReceipt.logsBloom; + receipt.transactionHash = rawReceipt.transactionHash; + return receipt; + } + + function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs) + internal + pure + virtual + returns (ReceiptLog[] memory) + { + ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length); + for (uint256 i; i < rawLogs.length; i++) { + logs[i].logAddress = rawLogs[i].logAddress; + logs[i].blockHash = rawLogs[i].blockHash; + logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber); + logs[i].data = rawLogs[i].data; + logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex); + logs[i].topics = rawLogs[i].topics; + logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex); + logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex); + logs[i].removed = rawLogs[i].removed; + } + return logs; + } + + // Deploy a contract by fetching the contract bytecode from + // the artifacts directory + // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))` + function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed."); + } + + function deployCode(string memory what) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string): Deployment failed."); + } + + /// @dev deploy contract with value on construction + function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed."); + } + + function deployCode(string memory what, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed."); + } + + // creates a labeled address and the corresponding private key + function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) { + privateKey = uint256(keccak256(abi.encodePacked(name))); + addr = vm.addr(privateKey); + vm.label(addr, name); + } + + // creates a labeled address + function makeAddr(string memory name) internal virtual returns (address addr) { + (addr,) = makeAddrAndKey(name); + } + + function deriveRememberKey(string memory mnemonic, uint32 index) + internal + virtual + returns (address who, uint256 privateKey) + { + privateKey = vm.deriveKey(mnemonic, index); + who = vm.rememberKey(privateKey); + } + + function _bytesToUint(bytes memory b) private pure returns (uint256) { + require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function isFork() internal view virtual returns (bool status) { + try vm.activeFork() { + status = true; + } catch (bytes memory) {} + } + + modifier skipWhenForking() { + if (!isFork()) { + _; + } + } + + modifier skipWhenNotForking() { + if (isFork()) { + _; + } + } + + modifier noGasMetering() { + vm.pauseGasMetering(); + // To prevent turning gas monitoring back on with nested functions that use this modifier, + // we check if gasMetering started in the off position. If it did, we don't want to turn + // it back on until we exit the top level function that used the modifier + // + // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well. + // funcA will have `gasStartedOff` as false, funcB will have it as true, + // so we only turn metering back on at the end of the funcA + bool gasStartedOff = gasMeteringOff; + gasMeteringOff = true; + + _; + + // if gas metering was on when this modifier was called, turn it back on at the end + if (!gasStartedOff) { + gasMeteringOff = false; + vm.resumeGasMetering(); + } + } + + // a cheat for fuzzing addresses that are payable only + // see https://github.com/foundry-rs/foundry/issues/3631 + function assumePayable(address addr) internal virtual { + (bool success,) = payable(addr).call{value: 0}(""); + vm.assume(success); + } +} + +// Wrappers around cheatcodes to avoid footguns +abstract contract StdCheats is StdCheatsSafe { + using stdStorage for StdStorage; + + StdStorage private stdstore; + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + // Skip forward or rewind time by the specified number of seconds + function skip(uint256 time) internal virtual { + vm.warp(block.timestamp + time); + } + + function rewind(uint256 time) internal virtual { + vm.warp(block.timestamp - time); + } + + // Setup a prank from an address that has some ether + function hoax(address msgSender) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.prank(msgSender); + } + + function hoax(address msgSender, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.prank(msgSender); + } + + function hoax(address msgSender, address origin) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.prank(msgSender, origin); + } + + function hoax(address msgSender, address origin, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.prank(msgSender, origin); + } + + // Start perpetual prank from an address that has some ether + function startHoax(address msgSender) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.startPrank(msgSender); + } + + function startHoax(address msgSender, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.startPrank(msgSender); + } + + // Start perpetual prank from an address that has some ether + // tx.origin is set to the origin parameter + function startHoax(address msgSender, address origin) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.startPrank(msgSender, origin); + } + + function startHoax(address msgSender, address origin, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.startPrank(msgSender, origin); + } + + function changePrank(address msgSender) internal virtual { + vm.stopPrank(); + vm.startPrank(msgSender); + } + + // The same as Vm's `deal` + // Use the alternative signature for ERC20 tokens + function deal(address to, uint256 give) internal virtual { + vm.deal(to, give); + } + + // Set the balance of an account for any ERC20 token + // Use the alternative signature to update `totalSupply` + function deal(address token, address to, uint256 give) internal virtual { + deal(token, to, give, false); + } + + // Set the balance of an account for any ERC1155 token + // Use the alternative signature to update `totalSupply` + function dealERC1155(address token, address to, uint256 id, uint256 give) internal virtual { + dealERC1155(token, to, id, give, false); + } + + function deal(address token, address to, uint256 give, bool adjust) internal virtual { + // get current balance + (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to)); + uint256 prevBal = abi.decode(balData, (uint256)); + + // update balance + stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give); + + // update total supply + if (adjust) { + (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd)); + uint256 totSup = abi.decode(totSupData, (uint256)); + if (give < prevBal) { + totSup -= (prevBal - give); + } else { + totSup += (give - prevBal); + } + stdstore.target(token).sig(0x18160ddd).checked_write(totSup); + } + } + + function dealERC1155(address token, address to, uint256 id, uint256 give, bool adjust) internal virtual { + // get current balance + (, bytes memory balData) = token.call(abi.encodeWithSelector(0x00fdd58e, to, id)); + uint256 prevBal = abi.decode(balData, (uint256)); + + // update balance + stdstore.target(token).sig(0x00fdd58e).with_key(to).with_key(id).checked_write(give); + + // update total supply + if (adjust) { + (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0xbd85b039, id)); + require( + totSupData.length != 0, + "StdCheats deal(address,address,uint,uint,bool): target contract is not ERC1155Supply." + ); + uint256 totSup = abi.decode(totSupData, (uint256)); + if (give < prevBal) { + totSup -= (prevBal - give); + } else { + totSup += (give - prevBal); + } + stdstore.target(token).sig(0xbd85b039).with_key(id).checked_write(totSup); + } + } + + function dealERC721(address token, address to, uint256 id) internal virtual { + // check if token id is already minted and the actual owner. + (bool successMinted, bytes memory ownerData) = token.staticcall(abi.encodeWithSelector(0x6352211e, id)); + require(successMinted, "StdCheats deal(address,address,uint,bool): id not minted."); + + // get owner current balance + (, bytes memory fromBalData) = token.call(abi.encodeWithSelector(0x70a08231, abi.decode(ownerData, (address)))); + uint256 fromPrevBal = abi.decode(fromBalData, (uint256)); + + // get new user current balance + (, bytes memory toBalData) = token.call(abi.encodeWithSelector(0x70a08231, to)); + uint256 toPrevBal = abi.decode(toBalData, (uint256)); + + // update balances + stdstore.target(token).sig(0x70a08231).with_key(abi.decode(ownerData, (address))).checked_write(--fromPrevBal); + stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(++toPrevBal); + + // update owner + stdstore.target(token).sig(0x6352211e).with_key(id).checked_write(to); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdError.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdError.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test +pragma solidity >=0.6.2 <0.9.0; + +library stdError { + bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); + bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); + bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); + bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); + bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); + bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); + bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); + bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); + bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdInvariant.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdInvariant.sol new file mode 100644 index 0000000..efa1129 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdInvariant.sol @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +contract StdInvariant { + struct FuzzSelector { + address addr; + bytes4[] selectors; + } + + address[] private _excludedContracts; + address[] private _excludedSenders; + address[] private _targetedContracts; + address[] private _targetedSenders; + + string[] private _excludedArtifacts; + string[] private _targetedArtifacts; + + FuzzSelector[] private _targetedArtifactSelectors; + FuzzSelector[] private _targetedSelectors; + + // Functions for users: + // These are intended to be called in tests. + + function excludeContract(address newExcludedContract_) internal { + _excludedContracts.push(newExcludedContract_); + } + + function excludeSender(address newExcludedSender_) internal { + _excludedSenders.push(newExcludedSender_); + } + + function excludeArtifact(string memory newExcludedArtifact_) internal { + _excludedArtifacts.push(newExcludedArtifact_); + } + + function targetArtifact(string memory newTargetedArtifact_) internal { + _targetedArtifacts.push(newTargetedArtifact_); + } + + function targetArtifactSelector(FuzzSelector memory newTargetedArtifactSelector_) internal { + _targetedArtifactSelectors.push(newTargetedArtifactSelector_); + } + + function targetContract(address newTargetedContract_) internal { + _targetedContracts.push(newTargetedContract_); + } + + function targetSelector(FuzzSelector memory newTargetedSelector_) internal { + _targetedSelectors.push(newTargetedSelector_); + } + + function targetSender(address newTargetedSender_) internal { + _targetedSenders.push(newTargetedSender_); + } + + // Functions for forge: + // These are called by forge to run invariant tests and don't need to be called in tests. + + function excludeArtifacts() public view returns (string[] memory excludedArtifacts_) { + excludedArtifacts_ = _excludedArtifacts; + } + + function excludeContracts() public view returns (address[] memory excludedContracts_) { + excludedContracts_ = _excludedContracts; + } + + function excludeSenders() public view returns (address[] memory excludedSenders_) { + excludedSenders_ = _excludedSenders; + } + + function targetArtifacts() public view returns (string[] memory targetedArtifacts_) { + targetedArtifacts_ = _targetedArtifacts; + } + + function targetArtifactSelectors() public view returns (FuzzSelector[] memory targetedArtifactSelectors_) { + targetedArtifactSelectors_ = _targetedArtifactSelectors; + } + + function targetContracts() public view returns (address[] memory targetedContracts_) { + targetedContracts_ = _targetedContracts; + } + + function targetSelectors() public view returns (FuzzSelector[] memory targetedSelectors_) { + targetedSelectors_ = _targetedSelectors; + } + + function targetSenders() public view returns (address[] memory targetedSenders_) { + targetedSenders_ = _targetedSenders; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdJson.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..014e6b1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdJson.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +// Helpers for parsing and writing JSON files +// To parse: +// ``` +// using stdJson for string; +// string memory json = vm.readFile("some_peth"); +// json.parseUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "deploymentArtifact"; +// Contract contract = new Contract(); +// json.serialize("contractAddress", address(contract)); +// json = json.serialize("deploymentTimes", uint(1)); +// // store the stringified JSON to the 'json' variable we have been using as a key +// // as we won't need it any longer +// string memory json2 = "finalArtifact"; +// string memory final = json2.serialize("depArtifact", json); +// final.write(""); +// ``` + +library stdJson { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) { + return vm.parseJson(json, key); + } + + function readUint(string memory json, string memory key) internal returns (uint256) { + return vm.parseJsonUint(json, key); + } + + function readUintArray(string memory json, string memory key) internal returns (uint256[] memory) { + return vm.parseJsonUintArray(json, key); + } + + function readInt(string memory json, string memory key) internal returns (int256) { + return vm.parseJsonInt(json, key); + } + + function readIntArray(string memory json, string memory key) internal returns (int256[] memory) { + return vm.parseJsonIntArray(json, key); + } + + function readBytes32(string memory json, string memory key) internal returns (bytes32) { + return vm.parseJsonBytes32(json, key); + } + + function readBytes32Array(string memory json, string memory key) internal returns (bytes32[] memory) { + return vm.parseJsonBytes32Array(json, key); + } + + function readString(string memory json, string memory key) internal returns (string memory) { + return vm.parseJsonString(json, key); + } + + function readStringArray(string memory json, string memory key) internal returns (string[] memory) { + return vm.parseJsonStringArray(json, key); + } + + function readAddress(string memory json, string memory key) internal returns (address) { + return vm.parseJsonAddress(json, key); + } + + function readAddressArray(string memory json, string memory key) internal returns (address[] memory) { + return vm.parseJsonAddressArray(json, key); + } + + function readBool(string memory json, string memory key) internal returns (bool) { + return vm.parseJsonBool(json, key); + } + + function readBoolArray(string memory json, string memory key) internal returns (bool[] memory) { + return vm.parseJsonBoolArray(json, key); + } + + function readBytes(string memory json, string memory key) internal returns (bytes memory) { + return vm.parseJsonBytes(json, key); + } + + function readBytesArray(string memory json, string memory key) internal returns (bytes[] memory) { + return vm.parseJsonBytesArray(json, key); + } + + function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bool[] memory value) + internal + returns (string memory) + { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256[] memory value) + internal + returns (string memory) + { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256[] memory value) + internal + returns (string memory) + { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address[] memory value) + internal + returns (string memory) + { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string[] memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function write(string memory jsonKey, string memory path) internal { + vm.writeJson(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeJson(jsonKey, path, valueKey); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdMath.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +library stdMath { + int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; + + function abs(int256 a) internal pure returns (uint256) { + // Required or it will fail when `a = type(int256).min` + if (a == INT256_MIN) { + return 57896044618658097711785492504343953926634992332820282019728792003956564819968; + } + + return uint256(a > 0 ? a : -a); + } + + function delta(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a - b : b - a; + } + + function delta(int256 a, int256 b) internal pure returns (uint256) { + // a and b are of the same sign + // this works thanks to two's complement, the left-most bit is the sign bit + if ((a ^ b) > -1) { + return delta(abs(a), abs(b)); + } + + // a and b are of opposite signs + return abs(a) + abs(b); + } + + function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + + return absDelta * 1e18 / b; + } + + function percentDelta(int256 a, int256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + uint256 absB = abs(b); + + return absDelta * 1e18 / absB; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdStorage.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..73a5ceb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; + mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; +} + +library stdStorageSafe { + event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot); + event WARNING_UninitedSlot(address who, uint256 slot); + + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against + // slot complexity: + // if flat, will be bytes32(uint256(uint)); + // if map, will be keccak256(abi.encode(key, uint(slot))); + // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot))))); + // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); + function find(StdStorage storage self) internal returns (uint256) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + vm.record(); + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + (bytes32[] memory reads,) = vm.accesses(address(who)); + if (reads.length == 1) { + bytes32 curr = vm.load(who, reads[0]); + if (curr == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[0])); + } + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + } else if (reads.length > 1) { + for (uint256 i = 0; i < reads.length; i++) { + bytes32 prev = vm.load(who, reads[i]); + if (prev == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[i])); + } + // store + vm.store(who, reads[i], bytes32(hex"1337")); + bool success; + bytes memory rdat; + { + (success, rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + if (success && fdat == bytes32(hex"1337")) { + // we found which of the slots is the actual one + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + vm.store(who, reads[i], prev); + break; + } + vm.store(who, reads[i], prev); + } + } else { + revert("stdStorage find(StdStorage): No storage use detected for target."); + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], + "stdStorage find(StdStorage): Slot(s) not found." + ); + + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + self._target = _target; + return self; + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + self._sig = _sig; + return self; + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + self._sig = sigs(_sig); + return self; + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + self._keys.push(bytes32(uint256(uint160(who)))); + return self; + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + self._keys.push(bytes32(amt)); + return self; + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + self._keys.push(key); + return self; + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + self._depth = _depth; + return self; + } + + function read(StdStorage storage self) private returns (bytes memory) { + address t = self._target; + uint256 s = find(self); + return abi.encode(vm.load(t, bytes32(s))); + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return abi.decode(read(self), (bytes32)); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + int256 v = read_int(self); + if (v == 0) return false; + if (v == 1) return true; + revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + } + + function read_address(StdStorage storage self) internal returns (address) { + return abi.decode(read(self), (address)); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return abi.decode(read(self), (uint256)); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return abi.decode(read(self), (int256)); + } + + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} + +library stdStorage { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return stdStorageSafe.sigs(sigStr); + } + + function find(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.find(self); + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + return stdStorageSafe.target(self, _target); + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, who); + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, amt); + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, key); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function checked_write(StdStorage storage self, address who) internal { + checked_write(self, bytes32(uint256(uint160(who)))); + } + + function checked_write(StdStorage storage self, uint256 amt) internal { + checked_write(self, bytes32(amt)); + } + + function checked_write(StdStorage storage self, bool write) internal { + bytes32 t; + /// @solidity memory-safe-assembly + assembly { + t := write + } + checked_write(self, t); + } + + function checked_write(StdStorage storage self, bytes32 set) internal { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + find(self); + } + bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]); + + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + bytes32 curr = vm.load(who, slot); + + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + vm.store(who, slot, set); + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return stdStorageSafe.read_bytes32(self); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + return stdStorageSafe.read_bool(self); + } + + function read_address(StdStorage storage self) internal returns (address) { + return stdStorageSafe.read_address(self); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.read_uint(self); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return stdStorageSafe.read_int(self); + } + + // Private function so needs to be copied over + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + // Private function so needs to be copied over + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdStyle.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdStyle.sol new file mode 100644 index 0000000..46f4e81 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdStyle.sol @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +import {Vm} from "./Vm.sol"; + +library StdStyle { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + string constant RED = "\u001b[91m"; + string constant GREEN = "\u001b[92m"; + string constant YELLOW = "\u001b[93m"; + string constant BLUE = "\u001b[94m"; + string constant MAGENTA = "\u001b[95m"; + string constant CYAN = "\u001b[96m"; + string constant BOLD = "\u001b[1m"; + string constant DIM = "\u001b[2m"; + string constant ITALIC = "\u001b[3m"; + string constant UNDERLINE = "\u001b[4m"; + string constant INVERSE = "\u001b[7m"; + string constant RESET = "\u001b[0m"; + + function styleConcat(string memory style, string memory self) private pure returns (string memory) { + return string(abi.encodePacked(style, self, RESET)); + } + + function red(string memory self) internal pure returns (string memory) { + return styleConcat(RED, self); + } + + function red(uint256 self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function red(int256 self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function red(address self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function red(bool self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function redBytes(bytes memory self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function redBytes32(bytes32 self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function green(string memory self) internal pure returns (string memory) { + return styleConcat(GREEN, self); + } + + function green(uint256 self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function green(int256 self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function green(address self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function green(bool self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function greenBytes(bytes memory self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function greenBytes32(bytes32 self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function yellow(string memory self) internal pure returns (string memory) { + return styleConcat(YELLOW, self); + } + + function yellow(uint256 self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellow(int256 self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellow(address self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellow(bool self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellowBytes(bytes memory self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellowBytes32(bytes32 self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function blue(string memory self) internal pure returns (string memory) { + return styleConcat(BLUE, self); + } + + function blue(uint256 self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blue(int256 self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blue(address self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blue(bool self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blueBytes(bytes memory self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blueBytes32(bytes32 self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function magenta(string memory self) internal pure returns (string memory) { + return styleConcat(MAGENTA, self); + } + + function magenta(uint256 self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magenta(int256 self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magenta(address self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magenta(bool self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magentaBytes(bytes memory self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magentaBytes32(bytes32 self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function cyan(string memory self) internal pure returns (string memory) { + return styleConcat(CYAN, self); + } + + function cyan(uint256 self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyan(int256 self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyan(address self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyan(bool self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyanBytes(bytes memory self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyanBytes32(bytes32 self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function bold(string memory self) internal pure returns (string memory) { + return styleConcat(BOLD, self); + } + + function bold(uint256 self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function bold(int256 self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function bold(address self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function bold(bool self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function boldBytes(bytes memory self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function boldBytes32(bytes32 self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function dim(string memory self) internal pure returns (string memory) { + return styleConcat(DIM, self); + } + + function dim(uint256 self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dim(int256 self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dim(address self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dim(bool self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dimBytes(bytes memory self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dimBytes32(bytes32 self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function italic(string memory self) internal pure returns (string memory) { + return styleConcat(ITALIC, self); + } + + function italic(uint256 self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italic(int256 self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italic(address self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italic(bool self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italicBytes(bytes memory self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italicBytes32(bytes32 self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function underline(string memory self) internal pure returns (string memory) { + return styleConcat(UNDERLINE, self); + } + + function underline(uint256 self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underline(int256 self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underline(address self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underline(bool self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underlineBytes(bytes memory self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underlineBytes32(bytes32 self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function inverse(string memory self) internal pure returns (string memory) { + return styleConcat(INVERSE, self); + } + + function inverse(uint256 self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverse(int256 self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverse(address self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverse(bool self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverseBytes(bytes memory self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverseBytes32(bytes32 self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdUtils.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..f68d11f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {IMulticall3} from "./interfaces/IMulticall3.sol"; +// TODO Remove import. +import {VmSafe} from "./Vm.sol"; + +abstract contract StdUtils { + /*////////////////////////////////////////////////////////////////////////// + CONSTANTS + //////////////////////////////////////////////////////////////////////////*/ + + IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11); + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; + uint256 private constant INT256_MIN_ABS = + 57896044618658097711785492504343953926634992332820282019728792003956564819968; + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + // Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address private constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { + require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); + // If x is between min and max, return x directly. This is to ensure that dictionary values + // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 + if (x >= min && x <= max) return x; + + uint256 size = max - min + 1; + + // If the value is 0, 1, 2, 3, warp that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. + // This helps ensure coverage of the min/max values. + if (x <= 3 && size > x) return min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); + + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. + if (x > max) { + uint256 diff = x - max; + uint256 rem = diff % size; + if (rem == 0) return max; + result = min + rem - 1; + } else if (x < min) { + uint256 diff = min - x; + uint256 rem = diff % size; + if (rem == 0) return min; + result = max - rem + 1; + } + } + + function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log("Bound Result", result); + } + + function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) { + require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min."); + + // Shifting all int256 values to uint256 to use _bound function. The range of two types are: + // int256 : -(2**255) ~ (2**255 - 1) + // uint256: 0 ~ (2**256 - 1) + // So, add 2**255, INT256_MIN_ABS to the integer values. + // + // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow. + // So, use `~uint256(x) + 1` instead. + uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS); + uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS); + uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS); + + uint256 y = _bound(_x, _min, _max); + + // To move it back to int256 value, subtract INT256_MIN_ABS at here. + result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS); + console2_log("Bound result", vm.toString(result)); + } + + function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { + require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce + /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) + function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { + // forgefmt: disable-start + // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0. + // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it. + if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80)))); + if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce)))); + + // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length. + if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce)))); + if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce)))); + if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce)))); + // forgefmt: disable-end + + // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp + // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) + // We assume nobody can have a nonce large enough to require more than 32 bytes. + return addressFromLast20Bytes( + keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))) + ); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash))); + } + + /// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) { + return computeCreate2Address(salt, initCodeHash, CREATE2_FACTORY); + } + + /// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments + /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode + function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) { + return hashInitCode(creationCode, ""); + } + + /// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2 + /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode + /// @param args the ABI-encoded arguments to the constructor of C + function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(creationCode, args)); + } + + // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses. + function getTokenBalances(address token, address[] memory addresses) + internal + virtual + returns (uint256[] memory balances) + { + uint256 tokenCodeSize; + assembly { + tokenCodeSize := extcodesize(token) + } + require(tokenCodeSize > 0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract."); + + // ABI encode the aggregate call to Multicall3. + uint256 length = addresses.length; + IMulticall3.Call[] memory calls = new IMulticall3.Call[](length); + for (uint256 i = 0; i < length; ++i) { + // 0x70a08231 = bytes4("balanceOf(address)")) + calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))}); + } + + // Make the aggregate call. + (, bytes[] memory returnData) = multicall.aggregate(calls); + + // ABI decode the return data and return the balances. + balances = new uint256[](length); + for (uint256 i = 0; i < length; ++i) { + balances[i] = abi.decode(returnData[i], (uint256)); + } + } + + /*////////////////////////////////////////////////////////////////////////// + PRIVATE FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { + return address(uint160(uint256(bytesValue))); + } + + // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere. + + function console2_log(string memory p0, uint256 p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + status; + } + + function console2_log(string memory p0, string memory p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1)); + status; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Test.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..9ff5cb8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Test.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// 💬 ABOUT +// Standard Library's default Test + +// 🧩 MODULES +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdAssertions} from "./StdAssertions.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheats} from "./StdCheats.sol"; +import {stdError} from "./StdError.sol"; +import {StdInvariant} from "./StdInvariant.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; +import {StdStyle} from "./StdStyle.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; +import {DSTest} from "ds-test/test.sol"; + +// ⭐️ TEST +abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils, TestBase { +// Note: IS_TEST() must return true. +// Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76. +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Vm.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..99d54e0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/Vm.sol @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// Cheatcodes are marked as view/pure/none using the following rules: +// 0. A call's observable behaviour includes its return value, logs, reverts and state writes, +// 1. If you can influence a later call's observable behaviour, you're neither `view` nor `pure (you are modifying some state be it the EVM, interpreter, filesystem, etc), +// 2. Otherwise if you can be influenced by an earlier call, or if reading some state, you're `view`, +// 3. Otherwise you're `pure`. + +interface VmSafe { + struct Log { + bytes32[] topics; + bytes data; + address emitter; + } + + struct Rpc { + string key; + string url; + } + + struct FsMetadata { + bool isDir; + bool isSymlink; + uint256 length; + bool readOnly; + uint256 modified; + uint256 accessed; + uint256 created; + } + + // Loads a storage slot from an address + function load(address target, bytes32 slot) external view returns (bytes32 data); + // Signs data + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + // Gets the address for a given private key + function addr(uint256 privateKey) external pure returns (address keyAddr); + // Gets the nonce of an account + function getNonce(address account) external view returns (uint64 nonce); + // Performs a foreign function call via the terminal + function ffi(string[] calldata commandInput) external returns (bytes memory result); + // Sets environment variables + function setEnv(string calldata name, string calldata value) external; + // Reads environment variables, (name) => (value) + function envBool(string calldata name) external view returns (bool value); + function envUint(string calldata name) external view returns (uint256 value); + function envInt(string calldata name) external view returns (int256 value); + function envAddress(string calldata name) external view returns (address value); + function envBytes32(string calldata name) external view returns (bytes32 value); + function envString(string calldata name) external view returns (string memory value); + function envBytes(string calldata name) external view returns (bytes memory value); + // Reads environment variables as arrays + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + // Read environment variables with default value + function envOr(string calldata name, bool defaultValue) external returns (bool value); + function envOr(string calldata name, uint256 defaultValue) external returns (uint256 value); + function envOr(string calldata name, int256 defaultValue) external returns (int256 value); + function envOr(string calldata name, address defaultValue) external returns (address value); + function envOr(string calldata name, bytes32 defaultValue) external returns (bytes32 value); + function envOr(string calldata name, string calldata defaultValue) external returns (string memory value); + function envOr(string calldata name, bytes calldata defaultValue) external returns (bytes memory value); + // Read environment variables as arrays with default value + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + returns (bool[] memory value); + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + returns (uint256[] memory value); + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + returns (int256[] memory value); + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + returns (address[] memory value); + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + returns (bytes32[] memory value); + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + returns (string[] memory value); + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + returns (bytes[] memory value); + // Records all storage reads and writes + function record() external; + // Gets all accessed reads and write slot from a recording session, for a given address + function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots); + // Gets the _creation_ bytecode from an artifact file. Takes in the relative path to the json file + function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode); + // Gets the _deployed_ bytecode from an artifact file. Takes in the relative path to the json file + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + // Labels an address in call traces + function label(address account, string calldata newLabel) external; + // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain + function broadcast() external; + // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain + function broadcast(address signer) external; + // Has the next call (at this call depth only) create a transaction with the private key provided as the sender that can later be signed and sent onchain + function broadcast(uint256 privateKey) external; + // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain + function startBroadcast() external; + // Has all subsequent calls (at this call depth only) create transactions with the address provided that can later be signed and sent onchain + function startBroadcast(address signer) external; + // Has all subsequent calls (at this call depth only) create transactions with the private key provided that can later be signed and sent onchain + function startBroadcast(uint256 privateKey) external; + // Stops collecting onchain transactions + function stopBroadcast() external; + // Reads the entire content of file to string + function readFile(string calldata path) external view returns (string memory data); + // Reads the entire content of file as binary. Path is relative to the project root. + function readFileBinary(string calldata path) external view returns (bytes memory data); + // Get the path of the current project root + function projectRoot() external view returns (string memory path); + // Get the metadata for a file/directory + function fsMetadata(string calldata fileOrDir) external returns (FsMetadata memory metadata); + // Reads next line of file to string + function readLine(string calldata path) external view returns (string memory line); + // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does. + function writeFile(string calldata path, string calldata data) external; + // Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does. + // Path is relative to the project root. + function writeFileBinary(string calldata path, bytes calldata data) external; + // Writes line to file, creating a file if it does not exist. + function writeLine(string calldata path, string calldata data) external; + // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine. + function closeFile(string calldata path) external; + // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases: + // - Path points to a directory. + // - The file doesn't exist. + // - The user lacks permissions to remove the file. + function removeFile(string calldata path) external; + // Convert values to a string + function toString(address value) external pure returns (string memory stringifiedValue); + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + function toString(bool value) external pure returns (string memory stringifiedValue); + function toString(uint256 value) external pure returns (string memory stringifiedValue); + function toString(int256 value) external pure returns (string memory stringifiedValue); + // Convert values from a string + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + // Record all the transaction logs + function recordLogs() external; + // Gets all the recorded logs + function getRecordedLogs() external returns (Log[] memory logs); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index} + function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at {derivationPath}{index} + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index) + external + pure + returns (uint256 privateKey); + // Adds a private key to the local forge wallet and returns the address + function rememberKey(uint256 privateKey) external returns (address keyAddr); + // + // parseJson + // + // ---- + // In case the returned value is a JSON object, it's encoded as a ABI-encoded tuple. As JSON objects + // don't have the notion of ordered, but tuples do, they JSON object is encoded with it's fields ordered in + // ALPHABETICAL order. That means that in order to successfully decode the tuple, we need to define a tuple that + // encodes the fields in the same order, which is alphabetical. In the case of Solidity structs, they are encoded + // as tuples, with the attributes in the order in which they are defined. + // For example: json = { 'a': 1, 'b': 0xa4tb......3xs} + // a: uint256 + // b: address + // To decode that json, we need to define a struct or a tuple as follows: + // struct json = { uint256 a; address b; } + // If we defined a json struct with the opposite order, meaning placing the address b first, it would try to + // decode the tuple in that order, and thus fail. + // ---- + // Given a string of JSON, return it as ABI-encoded + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + // The following parseJson cheatcodes will do type coercion, for the type that they indicate. + // For example, parseJsonUint will coerce all values to a uint256. That includes stringified numbers '12' + // and hex numbers '0xEF'. + // Type coercion works ONLY for discrete values or arrays. That means that the key must return a value or array, not + // a JSON object. + function parseJsonUint(string calldata, string calldata) external returns (uint256); + function parseJsonUintArray(string calldata, string calldata) external returns (uint256[] memory); + function parseJsonInt(string calldata, string calldata) external returns (int256); + function parseJsonIntArray(string calldata, string calldata) external returns (int256[] memory); + function parseJsonBool(string calldata, string calldata) external returns (bool); + function parseJsonBoolArray(string calldata, string calldata) external returns (bool[] memory); + function parseJsonAddress(string calldata, string calldata) external returns (address); + function parseJsonAddressArray(string calldata, string calldata) external returns (address[] memory); + function parseJsonString(string calldata, string calldata) external returns (string memory); + function parseJsonStringArray(string calldata, string calldata) external returns (string[] memory); + function parseJsonBytes(string calldata, string calldata) external returns (bytes memory); + function parseJsonBytesArray(string calldata, string calldata) external returns (bytes[] memory); + function parseJsonBytes32(string calldata, string calldata) external returns (bytes32); + function parseJsonBytes32Array(string calldata, string calldata) external returns (bytes32[] memory); + + // Serialize a key and value to a JSON object stored in-memory that can be later written to a file + // It returns the stringified version of the specific JSON file up to that moment. + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + // + // writeJson + // + // ---- + // Write a serialized JSON object to a file. If the file exists, it will be overwritten. + // Let's assume we want to write the following JSON to a file: + // + // { "boolean": true, "number": 342, "object": { "title": "finally json serialization" } } + // + // ``` + // string memory json1 = "some key"; + // vm.serializeBool(json1, "boolean", true); + // vm.serializeBool(json1, "number", uint256(342)); + // json2 = "some other key"; + // string memory output = vm.serializeString(json2, "title", "finally json serialization"); + // string memory finalJson = vm.serialize(json1, "object", output); + // vm.writeJson(finalJson, "./output/example.json"); + // ``` + // The critical insight is that every invocation of serialization will return the stringified version of the JSON + // up to that point. That means we can construct arbitrary JSON objects and then use the return stringified version + // to serialize them as values to another JSON object. + // + // json1 and json2 are simply keys used by the backend to keep track of the objects. So vm.serializeJson(json1,..) + // will find the object in-memory that is keyed by "some key". + function writeJson(string calldata json, string calldata path) external; + // Write a serialized JSON object to an **existing** JSON file, replacing a value with key = + // This is useful to replace a specific value of a JSON file, without having to parse the entire thing + function writeJson(string calldata json, string calldata path, string calldata valueKey) external; + // Returns the RPC url for the given alias + function rpcUrl(string calldata rpcAlias) external view returns (string memory json); + // Returns all rpc urls and their aliases `[alias, url][]` + function rpcUrls() external view returns (string[2][] memory urls); + // Returns all rpc urls and their aliases as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + // If the condition is false, discard this run's fuzz inputs and generate new ones. + function assume(bool condition) external pure; + // Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + // Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; +} + +interface Vm is VmSafe { + // Sets block.timestamp + function warp(uint256 newTimestamp) external; + // Sets block.height + function roll(uint256 newHeight) external; + // Sets block.basefee + function fee(uint256 newBasefee) external; + // Sets block.difficulty + function difficulty(uint256 newDifficulty) external; + // Sets block.chainid + function chainId(uint256 newChainId) external; + // Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) external; + // Sets the nonce of an account; must be higher than the current nonce of the account + function setNonce(address account, uint64 newNonce) external; + // Sets the *next* call's msg.sender to be the input address + function prank(address msgSender) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called + function startPrank(address msgSender) external; + // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input + function prank(address msgSender, address txOrigin) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input + function startPrank(address msgSender, address txOrigin) external; + // Resets subsequent calls' msg.sender to be `address(this)` + function stopPrank() external; + // Sets an address' balance + function deal(address account, uint256 newBalance) external; + // Sets an address' code + function etch(address target, bytes calldata newRuntimeBytecode) external; + // Expects an error on next call + function expectRevert(bytes calldata revertData) external; + function expectRevert(bytes4 revertData) external; + function expectRevert() external; + // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + // Call this function, then emit an event, then call a function. Internally after the call, we check if + // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external; + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) + external; + // Mocks a call to an address, returning specified data. + // Calldata can either be strict or a partial match, e.g. if you only + // pass a Solidity selector to the expected calldata, then the entire Solidity + // function will be mocked. + function mockCall(address callee, bytes calldata data, bytes calldata returnData) external; + // Mocks a call to an address with a specific msg.value, returning specified data. + // Calldata match takes precedence over msg.value in case of ambiguity. + function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external; + // Clears all mocked calls + function clearMockedCalls() external; + // Expects a call to an address with the specified calldata. + // Calldata can either be a strict or a partial match + function expectCall(address callee, bytes calldata data) external; + // Expects a call to an address with the specified msg.value and calldata + function expectCall(address callee, uint256 msgValue, bytes calldata data) external; + // Expect a call to an address with the specified msg.value, gas, and calldata. + function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data) external; + // Expect a call to an address with the specified msg.value and calldata, and a *minimum* amount of gas. + function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data) external; + // Sets block.coinbase + function coinbase(address newCoinbase) external; + // Snapshot the current state of the evm. + // Returns the id of the snapshot that was created. + // To revert a snapshot use `revertTo` + function snapshot() external returns (uint256 snapshotId); + // Revert the state of the EVM to a previous snapshot + // Takes the snapshot id to revert to. + // This deletes the snapshot and all snapshots taken after the given snapshot id. + function revertTo(uint256 snapshotId) external returns (bool success); + // Creates a new fork with the given endpoint and block and returns the identifier of the fork + function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork + function createFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before the transaction, + // and returns the identifier of the fork + function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates _and_ also selects new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before + // the transaction, returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active. + function selectFork(uint256 forkId) external; + /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + // Updates the currently active fork to given block number + // This is similar to `roll` but for the currently active fork + function rollFork(uint256 blockNumber) external; + // Updates the currently active fork to given transaction + // this will `rollFork` with the number of the block the transaction was mined in and replays all transaction mined before it in the block + function rollFork(bytes32 txHash) external; + // Updates the given fork to given block number + function rollFork(uint256 forkId, uint256 blockNumber) external; + // Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block + function rollFork(uint256 forkId, bytes32 txHash) external; + // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup + // Meaning, changes made to the state of this account will be kept when switching forks + function makePersistent(address account) external; + function makePersistent(address account0, address account1) external; + function makePersistent(address account0, address account1, address account2) external; + function makePersistent(address[] calldata accounts) external; + // Revokes persistent status from the address, previously added via `makePersistent` + function revokePersistent(address account) external; + function revokePersistent(address[] calldata accounts) external; + // Returns true if the account is marked as persistent + function isPersistent(address account) external view returns (bool persistent); + // In forking mode, explicitly grant the given address cheatcode access + function allowCheatcodes(address account) external; + // Fetches the given transaction from the active fork and executes it on the current state + function transact(bytes32 txHash) external; + // Fetches the given transaction from the given fork and executes it on the current state + function transact(uint256 forkId, bytes32 txHash) external; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/console.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/console.sol new file mode 100644 index 0000000..ad57e53 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/console.sol @@ -0,0 +1,1533 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/console2.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..8596233 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/console2.sol @@ -0,0 +1,1546 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +/// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should +/// use `int256` and `uint256`. This modified version fixes that. This version is recommended +/// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in +/// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`. +/// Reference: https://github.com/NomicFoundation/hardhat/issues/2178 +library console2 { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function logUint(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function log(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint256 p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); + } + + function log(uint256 p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); + } + + function log(uint256 p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); + } + + function log(uint256 p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); + } + + function log(string memory p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function log(string memory p0, int256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint256 p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC1155.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..f7dd2b4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC1155.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-1155 Multi Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-1155 +/// Note: The ERC-165 identifier for this interface is 0xd9b67a26. +interface IERC1155 is IERC165 { + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_id` argument MUST be the token type being transferred. + /// - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferSingle( + address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value + ); + + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_ids` argument MUST be the list of tokens being transferred. + /// - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferBatch( + address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values + ); + + /// @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled). + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. + /// The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". + event URI(string _value, uint256 indexed _id); + + /// @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + /// - MUST revert on any other error. + /// - MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + /// - After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _id ID of the token type + /// @param _value Transfer amount + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; + + /// @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if length of `_ids` is not the same as length of `_values`. + /// - MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + /// - MUST revert on any other error. + /// - MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + /// - Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + /// - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _ids IDs of each token type (order and length must match _values array) + /// @param _values Transfer amounts per token type (order and length must match _ids array) + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + function safeBatchTransferFrom( + address _from, + address _to, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data + ) external; + + /// @notice Get the balance of an account's tokens. + /// @param _owner The address of the token holder + /// @param _id ID of the token + /// @return The _owner's balance of the token type requested + function balanceOf(address _owner, uint256 _id) external view returns (uint256); + + /// @notice Get the balance of multiple account/token pairs + /// @param _owners The addresses of the token holders + /// @param _ids ID of the tokens + /// @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair) + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) + external + view + returns (uint256[] memory); + + /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + /// @dev MUST emit the ApprovalForAll event on success. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Queries the approval status of an operator for a given owner. + /// @param _owner The owner of the tokens + /// @param _operator Address of authorized operator + /// @return True if the operator is approved, false if not + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC165.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC165.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +interface IERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC20.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC20.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +/// @dev Interface of the ERC20 standard as defined in the EIP. +/// @dev This includes the optional name, symbol, and decimals metadata. +interface IERC20 { + /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` + /// is the new allowance. + event Approval(address indexed owner, address indexed spender, uint256 value); + + /// @notice Returns the amount of tokens in existence. + function totalSupply() external view returns (uint256); + + /// @notice Returns the amount of tokens owned by `account`. + function balanceOf(address account) external view returns (uint256); + + /// @notice Moves `amount` tokens from the caller's account to `to`. + function transfer(address to, uint256 amount) external returns (bool); + + /// @notice Returns the remaining number of tokens that `spender` is allowed + /// to spend on behalf of `owner` + function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. + /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. + /// `amount` is then deducted from the caller's allowance. + function transferFrom(address from, address to, uint256 amount) external returns (bool); + + /// @notice Returns the name of the token. + function name() external view returns (string memory); + + /// @notice Returns the symbol of the token. + function symbol() external view returns (string memory); + + /// @notice Returns the decimals places of the token. + function decimals() external view returns (uint8); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC4626.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..bfe3a11 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC4626.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC20.sol"; + +/// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in +/// https://eips.ethereum.org/EIPS/eip-4626 +interface IERC4626 is IERC20 { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares + ); + + /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + /// @dev + /// - MUST be an ERC-20 token contract. + /// - MUST NOT revert. + function asset() external view returns (address assetTokenAddress); + + /// @notice Returns the total amount of the underlying asset that is “managed” by Vault. + /// @dev + /// - SHOULD include any compounding that occurs from yield. + /// - MUST be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT revert. + function totalAssets() external view returns (uint256 totalManagedAssets); + + /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + /// through a deposit call. + /// @dev + /// - MUST return a limited value if receiver is subject to some deposit limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + /// - MUST NOT revert. + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + /// call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + /// in the same transaction. + /// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + /// deposit would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// deposit execution, and are accounted for during deposit. + /// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + /// @dev + /// - MUST return a limited value if receiver is subject to some mint limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + /// - MUST NOT revert. + function maxMint(address receiver) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + /// in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + /// same transaction. + /// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + /// would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by minting. + function previewMint(uint256 shares) external view returns (uint256 assets); + + /// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + /// execution, and are accounted for during mint. + /// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + /// Vault, through a withdraw call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST NOT revert. + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + /// call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + /// called + /// in the same transaction. + /// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + /// the withdrawal would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// withdraw execution, and are accounted for during withdraw. + /// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + /// through a redeem call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + /// - MUST NOT revert. + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + /// in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + /// same transaction. + /// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + /// redemption would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by redeeming. + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// redeem execution, and are accounted for during redeem. + /// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC721.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..0a16f45 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IERC721.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-721 Non-Fungible Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. +interface IERC721 is IERC165 { + /// @dev This emits when ownership of any NFT changes by any mechanism. + /// This event emits when NFTs are created (`from` == 0) and destroyed + /// (`to` == 0). Exception: during contract creation, any number of NFTs + /// may be created and assigned without emitting Transfer. At the time of + /// any transfer, the approved address for that NFT (if any) is reset to none. + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + + /// @dev This emits when the approved address for an NFT is changed or + /// reaffirmed. The zero address indicates there is no approved address. + /// When a Transfer event emits, this also indicates that the approved + /// address for that NFT (if any) is reset to none. + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + /// @dev This emits when an operator is enabled or disabled for an owner. + /// The operator can manage all NFTs of the owner. + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @notice Count all NFTs assigned to an owner + /// @dev NFTs assigned to the zero address are considered invalid, and this + /// function throws for queries about the zero address. + /// @param _owner An address for whom to query the balance + /// @return The number of NFTs owned by `_owner`, possibly zero + function balanceOf(address _owner) external view returns (uint256); + + /// @notice Find the owner of an NFT + /// @dev NFTs assigned to zero address are considered invalid, and queries + /// about them do throw. + /// @param _tokenId The identifier for an NFT + /// @return The address of the owner of the NFT + function ownerOf(uint256 _tokenId) external view returns (address); + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. When transfer is complete, this function + /// checks if `_to` is a smart contract (code size > 0). If so, it calls + /// `onERC721Received` on `_to` and throws if the return value is not + /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + /// @param data Additional data with no specified format, sent in call to `_to` + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev This works identically to the other function with an extra data parameter, + /// except this function just sets data to "". + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE + /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE + /// THEY MAY BE PERMANENTLY LOST + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Change or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param _approved The new approved NFT controller + /// @param _tokenId The NFT to approve + function approve(address _approved, uint256 _tokenId) external payable; + + /// @notice Enable or disable approval for a third party ("operator") to manage + /// all of `msg.sender`'s assets + /// @dev Emits the ApprovalForAll event. The contract MUST allow + /// multiple operators per owner. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Get the approved address for a single NFT + /// @dev Throws if `_tokenId` is not a valid NFT. + /// @param _tokenId The NFT to find the approved address for + /// @return The approved address for this NFT, or the zero address if there is none + function getApproved(uint256 _tokenId) external view returns (address); + + /// @notice Query if an address is an authorized operator for another address + /// @param _owner The address that owns the NFTs + /// @param _operator The address that acts on behalf of the owner + /// @return True if `_operator` is an approved operator for `_owner`, false otherwise + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} + +/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02. +interface IERC721TokenReceiver { + /// @notice Handle the receipt of an NFT + /// @dev The ERC721 smart contract calls this function on the recipient + /// after a `transfer`. This function MAY throw to revert and reject the + /// transfer. Return of other than the magic value MUST result in the + /// transaction being reverted. + /// Note: the contract address is always the message sender. + /// @param _operator The address which called `safeTransferFrom` function + /// @param _from The address which previously owned the token + /// @param _tokenId The NFT identifier which is being transferred + /// @param _data Additional data with no specified format + /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + /// unless throwing + function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) + external + returns (bytes4); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x5b5e139f. +interface IERC721Metadata is IERC721 { + /// @notice A descriptive name for a collection of NFTs in this contract + function name() external view returns (string memory _name); + + /// @notice An abbreviated name for NFTs in this contract + function symbol() external view returns (string memory _symbol); + + /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. + /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC + /// 3986. The URI may point to a JSON file that conforms to the "ERC721 + /// Metadata JSON Schema". + function tokenURI(uint256 _tokenId) external view returns (string memory); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x780e9d63. +interface IERC721Enumerable is IERC721 { + /// @notice Count NFTs tracked by this contract + /// @return A count of valid NFTs tracked by this contract, where each one of + /// them has an assigned and queryable owner not equal to the zero address + function totalSupply() external view returns (uint256); + + /// @notice Enumerate valid NFTs + /// @dev Throws if `_index` >= `totalSupply()`. + /// @param _index A counter less than `totalSupply()` + /// @return The token identifier for the `_index`th NFT, + /// (sort order not specified) + function tokenByIndex(uint256 _index) external view returns (uint256); + + /// @notice Enumerate NFTs assigned to an owner + /// @dev Throws if `_index` >= `balanceOf(_owner)` or if + /// `_owner` is the zero address, representing invalid NFTs. + /// @param _owner An address where we are interested in NFTs owned by them + /// @param _index A counter less than `balanceOf(_owner)` + /// @return The token identifier for the `_index`th NFT assigned to `_owner`, + /// (sort order not specified) + function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IMulticall3.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IMulticall3.sol new file mode 100644 index 0000000..0d031b7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/src/interfaces/IMulticall3.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +interface IMulticall3 { + struct Call { + address target; + bytes callData; + } + + struct Call3 { + address target; + bool allowFailure; + bytes callData; + } + + struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; + } + + struct Result { + bool success; + bytes returnData; + } + + function aggregate(Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes[] memory returnData); + + function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData); + + function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData); + + function blockAndAggregate(Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); + + function getBasefee() external view returns (uint256 basefee); + + function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash); + + function getBlockNumber() external view returns (uint256 blockNumber); + + function getChainId() external view returns (uint256 chainid); + + function getCurrentBlockCoinbase() external view returns (address coinbase); + + function getCurrentBlockDifficulty() external view returns (uint256 difficulty); + + function getCurrentBlockGasLimit() external view returns (uint256 gaslimit); + + function getCurrentBlockTimestamp() external view returns (uint256 timestamp); + + function getEthBalance(address addr) external view returns (uint256 balance); + + function getLastBlockHash() external view returns (bytes32 blockHash); + + function tryAggregate(bool requireSuccess, Call[] calldata calls) + external + payable + returns (Result[] memory returnData); + + function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdAssertions.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..2922780 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,954 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdAssertionsTest is Test { + string constant CUSTOM_ERROR = "guh!"; + + bool constant EXPECT_PASS = false; + bool constant EXPECT_FAIL = true; + + bool constant SHOULD_REVERT = true; + bool constant SHOULD_RETURN = false; + + bool constant STRICT_REVERT_DATA = true; + bool constant NON_STRICT_REVERT_DATA = false; + + TestTest t = new TestTest(); + + /*////////////////////////////////////////////////////////////////////////// + FAIL(STRING) + //////////////////////////////////////////////////////////////////////////*/ + + function testShouldFail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._fail(CUSTOM_ERROR); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_FALSE + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertFalse_Pass() external { + t._assertFalse(false, EXPECT_PASS); + } + + function testAssertFalse_Fail() external { + vm.expectEmit(false, false, false, true); + emit log("Error: Assertion Failed"); + t._assertFalse(true, EXPECT_FAIL); + } + + function testAssertFalse_Err_Pass() external { + t._assertFalse(false, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertFalse_Err_Fail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertFalse(true, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BOOL) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bool_Pass(bool a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bool_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bool]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BoolErr_Pass(bool a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BoolErr_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BYTES) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bytes_Pass(bytes calldata a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bytes_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bytes]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BytesErr_Pass(bytes calldata a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BytesErr_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(ARRAY) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_UintArr_Pass(uint256 e0, uint256 e1, uint256 e2) public { + uint256[] memory a = new uint256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + uint256[] memory b = new uint256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_IntArr_Pass(int256 e0, int256 e1, int256 e2) public { + int256[] memory a = new int256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + int256[] memory b = new int256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_AddressArr_Pass(address e0, address e1, address e2) public { + address[] memory a = new address[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + address[] memory b = new address[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_UintArr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_UintArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEqUint() public { + assertEqUint(uint8(1), uint128(1)); + assertEqUint(uint64(2), uint64(2)); + } + + function testFailAssertEqUint() public { + assertEqUint(uint64(1), uint96(2)); + assertEqUint(uint160(3), uint160(4)); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS_DECIMAL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbsDecimal_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqAbsDecimal_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqAbsDecimal_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbsDecimal_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Int_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Int_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_IntErr_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_IntErr_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS_DECIMAL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbsDecimal_Int_Pass(int256 a, int256 b, uint256 maxDelta, uint256 decimals) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqAbsDecimal_Int_Fail(int256 a, int256 b, uint256 maxDelta, uint256 decimals) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqAbsDecimal_IntErr_Pass(int256 a, int256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbsDecimal_IntErr_Fail(int256 a, int256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL_DECIMAL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRelDecimal_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals) + external + { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals) + external + { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqRelDecimal_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals) + external + { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals) + external + { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL_DECIMAL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRelDecimal_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqRelDecimal_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ_CALL + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEqCall_Return_Pass( + bytes memory callDataA, + bytes memory callDataB, + bytes memory returnData, + bool strictRevertData + ) external { + address targetA = address(new TestMockCall(returnData, SHOULD_RETURN)); + address targetB = address(new TestMockCall(returnData, SHOULD_RETURN)); + + t._assertEqCall(targetA, targetB, callDataA, callDataB, returnData, returnData, strictRevertData, EXPECT_PASS); + } + + function testAssertEqCall_Return_Fail( + bytes memory callDataA, + bytes memory callDataB, + bytes memory returnDataA, + bytes memory returnDataB, + bool strictRevertData + ) external { + vm.assume(keccak256(returnDataA) != keccak256(returnDataB)); + + address targetA = address(new TestMockCall(returnDataA, SHOULD_RETURN)); + address targetB = address(new TestMockCall(returnDataB, SHOULD_RETURN)); + + vm.expectEmit(true, true, true, true); + emit log_named_string("Error", "Call return data does not match"); + t._assertEqCall(targetA, targetB, callDataA, callDataB, returnDataA, returnDataB, strictRevertData, EXPECT_FAIL); + } + + function testAssertEqCall_Revert_Pass( + bytes memory callDataA, + bytes memory callDataB, + bytes memory revertDataA, + bytes memory revertDataB + ) external { + address targetA = address(new TestMockCall(revertDataA, SHOULD_REVERT)); + address targetB = address(new TestMockCall(revertDataB, SHOULD_REVERT)); + + t._assertEqCall( + targetA, targetB, callDataA, callDataB, revertDataA, revertDataB, NON_STRICT_REVERT_DATA, EXPECT_PASS + ); + } + + function testAssertEqCall_Revert_Fail( + bytes memory callDataA, + bytes memory callDataB, + bytes memory revertDataA, + bytes memory revertDataB + ) external { + vm.assume(keccak256(revertDataA) != keccak256(revertDataB)); + + address targetA = address(new TestMockCall(revertDataA, SHOULD_REVERT)); + address targetB = address(new TestMockCall(revertDataB, SHOULD_REVERT)); + + vm.expectEmit(true, true, true, true); + emit log_named_string("Error", "Call revert data does not match"); + t._assertEqCall( + targetA, targetB, callDataA, callDataB, revertDataA, revertDataB, STRICT_REVERT_DATA, EXPECT_FAIL + ); + } + + function testAssertEqCall_Fail( + bytes memory callDataA, + bytes memory callDataB, + bytes memory returnDataA, + bytes memory returnDataB, + bool strictRevertData + ) external { + address targetA = address(new TestMockCall(returnDataA, SHOULD_RETURN)); + address targetB = address(new TestMockCall(returnDataB, SHOULD_REVERT)); + + vm.expectEmit(true, true, true, true); + emit log_named_bytes(" Left call return data", returnDataA); + vm.expectEmit(true, true, true, true); + emit log_named_bytes(" Right call revert data", returnDataB); + t._assertEqCall(targetA, targetB, callDataA, callDataB, returnDataA, returnDataB, strictRevertData, EXPECT_FAIL); + + vm.expectEmit(true, true, true, true); + emit log_named_bytes(" Left call revert data", returnDataB); + vm.expectEmit(true, true, true, true); + emit log_named_bytes(" Right call return data", returnDataA); + t._assertEqCall(targetB, targetA, callDataB, callDataA, returnDataB, returnDataA, strictRevertData, EXPECT_FAIL); + } +} + +contract TestTest is Test { + modifier expectFailure(bool expectFail) { + bool preState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + _; + bool postState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + + if (preState == true) { + return; + } + + if (expectFail) { + require(postState == true, "expected failure not triggered"); + + // unwind the expected failure + vm.store(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x00))); + } else { + require(postState == false, "unexpected failure was triggered"); + } + } + + function _fail(string memory err) external expectFailure(true) { + fail(err); + } + + function _assertFalse(bool data, bool expectFail) external expectFailure(expectFail) { + assertFalse(data); + } + + function _assertFalse(bool data, string memory err, bool expectFail) external expectFailure(expectFail) { + assertFalse(data, err); + } + + function _assertEq(bool a, bool b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bool a, bool b, string memory err, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b, err); + } + + function _assertEq(bytes memory a, bytes memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bytes memory a, bytes memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(int256[] memory a, int256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(address[] memory a, address[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(int256[] memory a, int256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(address[] memory a, address[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + + function _assertApproxEqAbsDecimal( + uint256 a, + uint256 b, + uint256 maxDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals, err); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + + function _assertApproxEqAbsDecimal( + int256 a, + int256 b, + uint256 maxDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals, err); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRelDecimal(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + + function _assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, err); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + + function _assertApproxEqRelDecimal( + int256 a, + int256 b, + uint256 maxPercentDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, err); + } + + function _assertEqCall( + address targetA, + address targetB, + bytes memory callDataA, + bytes memory callDataB, + bytes memory returnDataA, + bytes memory returnDataB, + bool strictRevertData, + bool expectFail + ) external expectFailure(expectFail) { + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } +} + +contract TestMockCall { + bytes returnData; + bool shouldRevert; + + constructor(bytes memory returnData_, bool shouldRevert_) { + returnData = returnData_; + shouldRevert = shouldRevert_; + } + + fallback() external payable { + bytes memory returnData_ = returnData; + + if (shouldRevert) { + assembly { + revert(add(returnData_, 0x20), mload(returnData_)) + } + } else { + assembly { + return(add(returnData_, 0x20), mload(returnData_)) + } + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdChains.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..c2b215d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdChainsTest is Test { + function testChainRpcInitialization() public { + // RPCs specified in `foundry.toml` should be updated. + assertEq(getChain(1).rpcUrl, "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5"); + assertEq(getChain("optimism_goerli").rpcUrl, "https://goerli.optimism.io/"); + assertEq(getChain("arbitrum_one_goerli").rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/"); + + // Environment variables should be the next fallback + assertEq(getChain("arbitrum_nova").rpcUrl, "https://nova.arbitrum.io/rpc"); + vm.setEnv("ARBITRUM_NOVA_RPC_URL", "myoverride"); + assertEq(getChain("arbitrum_nova").rpcUrl, "myoverride"); + vm.setEnv("ARBITRUM_NOVA_RPC_URL", "https://nova.arbitrum.io/rpc"); + + // Cannot override RPCs defined in `foundry.toml` + vm.setEnv("MAINNET_RPC_URL", "myoverride2"); + assertEq(getChain("mainnet").rpcUrl, "https://mainnet.infura.io/v3/16a8be88795540b9b3903d8de0f7baa5"); + + // Other RPCs should remain unchanged. + assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545"); + assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b"); + } + + function testRpc(string memory rpcAlias) internal { + string memory rpcUrl = getChain(rpcAlias).rpcUrl; + vm.createSelectFork(rpcUrl); + } + + // Ensure we can connect to the default RPC URL for each chain. + function testRpcs() public { + testRpc("mainnet"); + testRpc("goerli"); + testRpc("sepolia"); + testRpc("optimism"); + testRpc("optimism_goerli"); + testRpc("arbitrum_one"); + testRpc("arbitrum_one_goerli"); + testRpc("arbitrum_nova"); + testRpc("polygon"); + testRpc("polygon_mumbai"); + testRpc("avalanche"); + testRpc("avalanche_fuji"); + testRpc("bnb_smart_chain"); + testRpc("bnb_smart_chain_testnet"); + testRpc("gnosis_chain"); + } + + function testChainNoDefault() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found."); + getChain("does_not_exist"); + } + + function testSetChainFirstFails() public { + vm.expectRevert("StdChains setChain(string,ChainData): Chain ID 31337 already used by \"anvil\"."); + setChain("anvil2", ChainData("Anvil", 31337, "URL")); + } + + function testChainBubbleUp() public { + setChain("needs_undefined_env_var", ChainData("", 123456789, "")); + vm.expectRevert( + "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found" + ); + getChain("needs_undefined_env_var"); + } + + function testCannotSetChain_ChainIdExists() public { + setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + + vm.expectRevert('StdChains setChain(string,ChainData): Chain ID 123456789 already used by "custom_chain".'); + + setChain("another_custom_chain", ChainData("", 123456789, "")); + } + + function testSetChain() public { + setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + Chain memory customChain = getChain("custom_chain"); + assertEq(customChain.name, "Custom Chain"); + assertEq(customChain.chainId, 123456789); + assertEq(customChain.chainAlias, "custom_chain"); + assertEq(customChain.rpcUrl, "https://custom.chain/"); + Chain memory chainById = getChain(123456789); + assertEq(chainById.name, customChain.name); + assertEq(chainById.chainId, customChain.chainId); + assertEq(chainById.chainAlias, customChain.chainAlias); + assertEq(chainById.rpcUrl, customChain.rpcUrl); + customChain.name = "Another Custom Chain"; + customChain.chainId = 987654321; + setChain("another_custom_chain", customChain); + Chain memory anotherCustomChain = getChain("another_custom_chain"); + assertEq(anotherCustomChain.name, "Another Custom Chain"); + assertEq(anotherCustomChain.chainId, 987654321); + assertEq(anotherCustomChain.chainAlias, "another_custom_chain"); + assertEq(anotherCustomChain.rpcUrl, "https://custom.chain/"); + // Verify the first chain data was not overwritten + chainById = getChain(123456789); + assertEq(chainById.name, "Custom Chain"); + assertEq(chainById.chainId, 123456789); + } + + function testSetNoEmptyAlias() public { + vm.expectRevert("StdChains setChain(string,ChainData): Chain alias cannot be the empty string."); + setChain("", ChainData("", 123456789, "")); + } + + function testSetNoChainId0() public { + vm.expectRevert("StdChains setChain(string,ChainData): Chain ID cannot be 0."); + setChain("alias", ChainData("", 0, "")); + } + + function testGetNoChainId0() public { + vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0."); + getChain(0); + } + + function testGetNoEmptyAlias() public { + vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string."); + getChain(""); + } + + function testChainIdNotFound() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found."); + getChain("no_such_alias"); + } + + function testChainAliasNotFound() public { + vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found."); + getChain(321); + } + + function testSetChain_ExistingOne() public { + setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + assertEq(getChain(123456789).chainId, 123456789); + + setChain("custom_chain", ChainData("Modified Chain", 999999999, "https://modified.chain/")); + vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); + getChain(123456789); + + Chain memory modifiedChain = getChain(999999999); + assertEq(modifiedChain.name, "Modified Chain"); + assertEq(modifiedChain.chainId, 999999999); + assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); + } + + function testDontUseDefaultRpcUrl() public { + // Should error if default RPCs flag is set to false. + setFallbackToDefaultRpcUrls(false); + vm.expectRevert( + "Failed to get environment variable `ANVIL_RPC_URL` as type `string`: environment variable not found" + ); + getChain(31337); + vm.expectRevert( + "Failed to get environment variable `SEPOLIA_RPC_URL` as type `string`: environment variable not found" + ); + getChain("sepolia"); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdCheats.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..6ec8e0d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,401 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdCheats.sol"; +import "../src/Test.sol"; +import "../src/StdJson.sol"; + +contract StdCheatsTest is Test { + Bar test; + + using stdJson for string; + + function setUp() public { + test = new Bar(); + } + + function testSkip() public { + vm.warp(100); + skip(25); + assertEq(block.timestamp, 125); + } + + function testRewind() public { + vm.warp(100); + rewind(25); + assertEq(block.timestamp, 75); + } + + function testHoax() public { + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + } + + function testHoaxOrigin() public { + hoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + } + + function testHoaxDifferentAddresses() public { + hoax(address(1337), address(7331)); + test.origin{value: 100}(address(1337), address(7331)); + } + + function testStartHoax() public { + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testStartHoaxOrigin() public { + startHoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + test.origin{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testChangePrank() public { + vm.startPrank(address(1337)); + test.bar(address(1337)); + changePrank(address(0xdead)); + test.bar(address(0xdead)); + changePrank(address(1337)); + test.bar(address(1337)); + vm.stopPrank(); + } + + function testMakeAddrEquivalence() public { + (address addr,) = makeAddrAndKey("1337"); + assertEq(makeAddr("1337"), addr); + } + + function testMakeAddrSigning() public { + (address addr, uint256 key) = makeAddrAndKey("1337"); + bytes32 hash = keccak256("some_message"); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash); + assertEq(ecrecover(hash, v, r, s), addr); + } + + function testDeal() public { + deal(address(this), 1 ether); + assertEq(address(this).balance, 1 ether); + } + + function testDealToken() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18); + assertEq(barToken.balanceOf(address(this)), 10000e18); + } + + function testDealTokenAdjustTotalSupply() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18, true); + assertEq(barToken.balanceOf(address(this)), 10000e18); + assertEq(barToken.totalSupply(), 20000e18); + deal(bar, address(this), 0, true); + assertEq(barToken.balanceOf(address(this)), 0); + assertEq(barToken.totalSupply(), 10000e18); + } + + function testDealERC1155Token() public { + BarERC1155 barToken = new BarERC1155(); + address bar = address(barToken); + dealERC1155(bar, address(this), 0, 10000e18, false); + assertEq(barToken.balanceOf(address(this), 0), 10000e18); + } + + function testDealERC1155TokenAdjustTotalSupply() public { + BarERC1155 barToken = new BarERC1155(); + address bar = address(barToken); + dealERC1155(bar, address(this), 0, 10000e18, true); + assertEq(barToken.balanceOf(address(this), 0), 10000e18); + assertEq(barToken.totalSupply(0), 20000e18); + dealERC1155(bar, address(this), 0, 0, true); + assertEq(barToken.balanceOf(address(this), 0), 0); + assertEq(barToken.totalSupply(0), 10000e18); + } + + function testDealERC721Token() public { + BarERC721 barToken = new BarERC721(); + address bar = address(barToken); + dealERC721(bar, address(2), 1); + assertEq(barToken.balanceOf(address(2)), 1); + assertEq(barToken.balanceOf(address(1)), 0); + dealERC721(bar, address(1), 2); + assertEq(barToken.balanceOf(address(1)), 1); + assertEq(barToken.balanceOf(bar), 1); + } + + function testDeployCode() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes("")); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar"); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeVal() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes(""), 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + function testDeployCodeValNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar", 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + // We need this so we can call "this.deployCode" rather than "deployCode" directly + function deployCodeHelper(string memory what) external { + deployCode(what); + } + + function testDeployCodeFail() public { + vm.expectRevert(bytes("StdCheats deployCode(string): Deployment failed.")); + this.deployCodeHelper("StdCheats.t.sol:RevertingContract"); + } + + function getCode(address who) internal view returns (bytes memory o_code) { + /// @solidity memory-safe-assembly + assembly { + // retrieve the size of the code, this needs assembly + let size := extcodesize(who) + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + o_code := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(o_code, size) + // actually retrieve the code, this needs assembly + extcodecopy(who, add(o_code, 0x20), 0, size) + } + } + + function testDeriveRememberKey() public { + string memory mnemonic = "test test test test test test test test test test test junk"; + + (address deployer, uint256 privateKey) = deriveRememberKey(mnemonic, 0); + assertEq(deployer, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); + } + + function testBytesToUint() public { + assertEq(3, bytesToUint_test(hex"03")); + assertEq(2, bytesToUint_test(hex"02")); + assertEq(255, bytesToUint_test(hex"ff")); + assertEq(29625, bytesToUint_test(hex"73b9")); + } + + function testParseJsonTxDetail() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + string memory json = vm.readFile(path); + bytes memory transactionDetails = json.parseRaw(".transactions[0].tx"); + RawTx1559Detail memory rawTxDetail = abi.decode(transactionDetails, (RawTx1559Detail)); + Tx1559Detail memory txDetail = rawToConvertedEIP1559Detail(rawTxDetail); + assertEq(txDetail.from, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(txDetail.to, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512); + assertEq( + txDetail.data, + hex"23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004" + ); + assertEq(txDetail.nonce, 3); + assertEq(txDetail.txType, 2); + assertEq(txDetail.gas, 29625); + assertEq(txDetail.value, 0); + } + + function testReadEIP1559Transaction() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 0; + Tx1559 memory transaction = readTx1559(path, index); + transaction; + } + + function testReadEIP1559Transactions() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Tx1559[] memory transactions = readTx1559s(path); + transactions; + } + + function testReadReceipt() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 5; + Receipt memory receipt = readReceipt(path, index); + assertEq( + receipt.logsBloom, + hex"00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100" + ); + } + + function testReadReceipts() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Receipt[] memory receipts = readReceipts(path); + receipts; + } + + function testGasMeteringModifier() public { + uint256 gas_start_normal = gasleft(); + addInLoop(); + uint256 gas_used_normal = gas_start_normal - gasleft(); + + uint256 gas_start_single = gasleft(); + addInLoopNoGas(); + uint256 gas_used_single = gas_start_single - gasleft(); + + uint256 gas_start_double = gasleft(); + addInLoopNoGasNoGas(); + uint256 gas_used_double = gas_start_double - gasleft(); + + emit log_named_uint("Normal gas", gas_used_normal); + emit log_named_uint("Single modifier gas", gas_used_single); + emit log_named_uint("Double modifier gas", gas_used_double); + assertTrue(gas_used_double + gas_used_single < gas_used_normal); + } + + function addInLoop() internal pure returns (uint256) { + uint256 b; + for (uint256 i; i < 10000; i++) { + b += i; + } + return b; + } + + function addInLoopNoGas() internal noGasMetering returns (uint256) { + return addInLoop(); + } + + function addInLoopNoGasNoGas() internal noGasMetering returns (uint256) { + return addInLoopNoGas(); + } + + function bytesToUint_test(bytes memory b) private pure returns (uint256) { + uint256 number; + for (uint256 i = 0; i < b.length; i++) { + number = number + uint256(uint8(b[i])) * (2 ** (8 * (b.length - (i + 1)))); + } + return number; + } + + function testAssumeNoPrecompiles(address addr) external { + assumeNoPrecompiles(addr, getChain("optimism_goerli").chainId); + assertTrue( + addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) + || addr > address(0x4200000000000000000000000000000000000800) + ); + } + + function testAssumePayable() external { + // all should revert since these addresses are not payable + + // VM address + vm.expectRevert(); + assumePayable(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + // Console address + vm.expectRevert(); + assumePayable(0x000000000000000000636F6e736F6c652e6c6f67); + + // Create2Deployer + vm.expectRevert(); + assumePayable(0x4e59b44847b379578588920cA78FbF26c0B4956C); + } + + function testAssumePayable(address addr) external { + assumePayable(addr); + assertTrue( + addr != 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D && addr != 0x000000000000000000636F6e736F6c652e6c6f67 + && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C + ); + } +} + +contract Bar { + constructor() payable { + /// `DEAL` STDCHEAT + totalSupply = 10000e18; + balanceOf[address(this)] = totalSupply; + } + + /// `HOAX` STDCHEATS + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } + + function origin(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedSender, "!prank"); + } + + function origin(address expectedSender, address expectedOrigin) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedOrigin, "!prank"); + } + + /// `DEAL` STDCHEAT + mapping(address => uint256) public balanceOf; + uint256 public totalSupply; +} + +contract BarERC1155 { + constructor() payable { + /// `DEALERC1155` STDCHEAT + _totalSupply[0] = 10000e18; + _balances[0][address(this)] = _totalSupply[0]; + } + + function balanceOf(address account, uint256 id) public view virtual returns (uint256) { + return _balances[id][account]; + } + + function totalSupply(uint256 id) public view virtual returns (uint256) { + return _totalSupply[id]; + } + + /// `DEALERC1155` STDCHEAT + mapping(uint256 => mapping(address => uint256)) private _balances; + mapping(uint256 => uint256) private _totalSupply; +} + +contract BarERC721 { + constructor() payable { + /// `DEALERC721` STDCHEAT + _owners[1] = address(1); + _balances[address(1)] = 1; + _owners[2] = address(this); + _owners[3] = address(this); + _balances[address(this)] = 2; + } + + function balanceOf(address owner) public view virtual returns (uint256) { + return _balances[owner]; + } + + function ownerOf(uint256 tokenId) public view virtual returns (address) { + address owner = _owners[tokenId]; + return owner; + } + + mapping(uint256 => address) private _owners; + mapping(address => uint256) private _balances; +} + +contract RevertingContract { + constructor() { + revert(); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdError.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..ccd3efa --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdError.sol"; +import "../src/Test.sol"; + +contract StdErrorsTest is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectAssertion() public { + vm.expectRevert(stdError.assertionError); + test.assertionError(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } + + function testExpectDiv() public { + vm.expectRevert(stdError.divisionError); + test.divError(0); + } + + function testExpectMod() public { + vm.expectRevert(stdError.divisionError); + test.modError(0); + } + + function testExpectEnum() public { + vm.expectRevert(stdError.enumConversionError); + test.enumConversion(1); + } + + function testExpectEncodeStg() public { + vm.expectRevert(stdError.encodeStorageError); + test.encodeStgError(); + } + + function testExpectPop() public { + vm.expectRevert(stdError.popError); + test.pop(); + } + + function testExpectOOB() public { + vm.expectRevert(stdError.indexOOBError); + test.indexOOBError(1); + } + + function testExpectMem() public { + vm.expectRevert(stdError.memOverflowError); + test.mem(); + } + + function testExpectIntern() public { + vm.expectRevert(stdError.zeroVarError); + test.intern(); + } +} + +contract ErrorsTest { + enum T {T1} + + uint256[] public someArr; + bytes someBytes; + + function assertionError() public pure { + assert(false); + } + + function arithmeticError(uint256 a) public pure { + a -= 100; + } + + function divError(uint256 a) public pure { + 100 / a; + } + + function modError(uint256 a) public pure { + 100 % a; + } + + function enumConversion(uint256 a) public pure { + T(a); + } + + function encodeStgError() public { + /// @solidity memory-safe-assembly + assembly { + sstore(someBytes.slot, 1) + } + keccak256(someBytes); + } + + function pop() public { + someArr.pop(); + } + + function indexOOBError(uint256 a) public pure { + uint256[] memory t = new uint256[](0); + t[a]; + } + + function mem() public pure { + uint256 l = 2 ** 256 / 32; + new uint256[](l); + } + + function intern() public returns (uint256) { + function(uint256) internal returns (uint256) x; + x(2); + return 7; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdMath.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..95037ea --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdMath.t.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdMath.sol"; +import "../src/Test.sol"; + +contract StdMathTest is Test { + function testGetAbs() external { + assertEq(stdMath.abs(-50), 50); + assertEq(stdMath.abs(50), 50); + assertEq(stdMath.abs(-1337), 1337); + assertEq(stdMath.abs(0), 0); + + assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1); + assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1)); + } + + function testGetAbs_Fuzz(int256 a) external { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function testGetDelta_Uint() external { + assertEq(stdMath.delta(uint256(0), uint256(0)), 0); + assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337); + assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max); + assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max); + assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max); + + assertEq(stdMath.delta(0, uint256(0)), 0); + assertEq(stdMath.delta(1337, uint256(0)), 1337); + assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max); + assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max); + assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max); + + assertEq(stdMath.delta(1337, uint256(1337)), 0); + assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0); + assertEq(stdMath.delta(5000, uint256(1250)), 3750); + } + + function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external { + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetDelta_Int() external { + assertEq(stdMath.delta(int256(0), int256(0)), 0); + assertEq(stdMath.delta(int256(0), int256(1337)), 1337); + assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1); + assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1); + assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1); + + assertEq(stdMath.delta(0, int256(0)), 0); + assertEq(stdMath.delta(1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1); + assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1); + assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1); + + assertEq(stdMath.delta(-0, int256(0)), 0); + assertEq(stdMath.delta(-1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(int256(0), -0), 0); + assertEq(stdMath.delta(int256(0), -1337), 1337); + assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(1337, int256(1337)), 0); + assertEq(stdMath.delta(type(int256).max, type(int256).max), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).min), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max); + assertEq(stdMath.delta(5000, int256(1250)), 3750); + } + + function testGetDelta_Int_Fuzz(int256 a, int256 b) external { + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetPercentDelta_Uint() external { + assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); + assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); + assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); + assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(uint256(1), 0); + } + + function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external { + vm.assume(b != 0); + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / b; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + function testGetPercentDelta_Int() external { + assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); + assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, int256(1337)), 0); + assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); + assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); + + assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, int256(2500)), 0); + assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(int256(1), 0); + } + + function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external { + vm.assume(b != 0); + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / absB; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function getAbs(int256 a) private pure returns (uint256) { + if (a < 0) { + return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); + } + + return uint256(a); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdStorage.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..d4c563a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdStorage.sol"; +import "../src/Test.sol"; + +contract StdStorageTest is Test { + using stdStorage for StdStorage; + + StorageTest internal test; + + function setUp() public { + test = new StorageTest(); + } + + function testStorageHidden() public { + assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find()); + } + + function testStorageObvious() public { + assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find()); + } + + function testStorageCheckedWriteHidden() public { + stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100); + assertEq(uint256(test.hidden()), 100); + } + + function testStorageCheckedWriteObvious() public { + stdstore.target(address(test)).sig(test.exists.selector).checked_write(100); + assertEq(test.exists(), 100); + } + + function testStorageMapStructA() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot); + } + + function testStorageMapStructB() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot); + } + + function testStorageDeepMap() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key( + address(this) + ).find(); + assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(5)))))), slot); + } + + function testStorageCheckedWriteDeepMap() public { + stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(address(this)) + .checked_write(100); + assertEq(100, test.deep_map(address(this), address(this))); + } + + function testStorageDeepMapStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(0).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 0), + bytes32(slot) + ); + } + + function testStorageDeepMapStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(1).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 1), + bytes32(slot) + ); + } + + function testStorageCheckedWriteDeepMapStructA() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(100, a); + assertEq(0, b); + } + + function testStorageCheckedWriteDeepMapStructB() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(0, a); + assertEq(100, b); + } + + function testStorageCheckedWriteMapStructA() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 100); + assertEq(b, 0); + } + + function testStorageCheckedWriteMapStructB() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 0); + assertEq(b, 100); + } + + function testStorageStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find(); + assertEq(uint256(7), slot); + } + + function testStorageStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find(); + assertEq(uint256(7) + 1, slot); + } + + function testStorageCheckedWriteStructA() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 100); + assertEq(b, 1337); + } + + function testStorageCheckedWriteStructB() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 1337); + assertEq(b, 100); + } + + function testStorageMapAddrFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find(); + assertEq(uint256(keccak256(abi.encode(address(this), uint256(1)))), slot); + } + + function testStorageMapUintFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find(); + assertEq(uint256(keccak256(abi.encode(100, uint256(2)))), slot); + } + + function testStorageCheckedWriteMapUint() public { + stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100); + assertEq(100, test.map_uint(100)); + } + + function testStorageCheckedWriteMapAddr() public { + stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100); + assertEq(100, test.map_addr(address(this))); + } + + function testStorageCheckedWriteMapBool() public { + stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true); + assertTrue(test.map_bool(address(this))); + } + + function testFailStorageCheckedWriteMapPacked() public { + // expect PackedSlot error but not external call so cant expectRevert + stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))) + .checked_write(100); + } + + function testStorageCheckedWriteMapPackedSuccess() public { + uint256 full = test.map_packed(address(1337)); + // keep upper 128, set lower 128 to 1337 + full = (full & (uint256((1 << 128) - 1) << 128)) | 1337; + stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write( + full + ); + assertEq(1337, test.read_struct_lower(address(1337))); + } + + function testFailStorageConst() public { + // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()")))); + stdstore.target(address(test)).sig("const()").find(); + } + + function testFailStorageNativePack() public { + stdstore.target(address(test)).sig(test.tA.selector).find(); + stdstore.target(address(test)).sig(test.tB.selector).find(); + + // these both would fail + stdstore.target(address(test)).sig(test.tC.selector).find(); + stdstore.target(address(test)).sig(test.tD.selector).find(); + } + + function testStorageReadBytes32() public { + bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32(); + assertEq(val, hex"1337"); + } + + function testStorageReadBool_False() public { + bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool(); + assertEq(val, false); + } + + function testStorageReadBool_True() public { + bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool(); + assertEq(val, true); + } + + function testStorageReadBool_Revert() public { + vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + this.readNonBoolValue(); + } + + function readNonBoolValue() public { + stdstore.target(address(test)).sig(test.tE.selector).read_bool(); + } + + function testStorageReadAddress() public { + address val = stdstore.target(address(test)).sig(test.tF.selector).read_address(); + assertEq(val, address(1337)); + } + + function testStorageReadUint() public { + uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint(); + assertEq(val, 1); + } + + function testStorageReadInt() public { + int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int(); + assertEq(val, type(int256).min); + } +} + +contract StorageTest { + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + mapping(uint256 => uint256) public map_uint; + mapping(address => uint256) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basic; + + uint248 public tA; + bool public tB; + + bool public tC = false; + uint248 public tD = 1; + + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + mapping(address => bool) public map_bool; + + bytes32 public tE = hex"1337"; + address public tF = address(1337); + int256 public tG = type(int256).min; + bool public tH = true; + + constructor() { + basic = UnpackedStruct({a: 1337, b: 1337}); + + uint256 two = (1 << 128) | 1; + map_packed[msg.sender] = two; + map_packed[address(uint160(1337))] = 1 << 128; + } + + function read_struct_upper(address who) public view returns (uint256) { + return map_packed[who] >> 128; + } + + function read_struct_lower(address who) public view returns (uint256) { + return map_packed[who] & ((1 << 128) - 1); + } + + function hidden() public view returns (bytes32 t) { + bytes32 slot = keccak256("my.random.var"); + /// @solidity memory-safe-assembly + assembly { + t := sload(slot) + } + } + + function const() public pure returns (bytes32 t) { + t = bytes32(hex"1337"); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdStyle.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdStyle.t.sol new file mode 100644 index 0000000..e63ed68 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdStyle.t.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdStyleTest is Test { + function testStyleColor() public view { + console2.log(StdStyle.red("StdStyle.red String Test")); + console2.log(StdStyle.red(uint256(10e18))); + console2.log(StdStyle.red(int256(-10e18))); + console2.log(StdStyle.red(true)); + console2.log(StdStyle.red(address(0))); + console2.log(StdStyle.redBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.redBytes32("StdStyle.redBytes32")); + console2.log(StdStyle.green("StdStyle.green String Test")); + console2.log(StdStyle.green(uint256(10e18))); + console2.log(StdStyle.green(int256(-10e18))); + console2.log(StdStyle.green(true)); + console2.log(StdStyle.green(address(0))); + console2.log(StdStyle.greenBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.greenBytes32("StdStyle.greenBytes32")); + console2.log(StdStyle.yellow("StdStyle.yellow String Test")); + console2.log(StdStyle.yellow(uint256(10e18))); + console2.log(StdStyle.yellow(int256(-10e18))); + console2.log(StdStyle.yellow(true)); + console2.log(StdStyle.yellow(address(0))); + console2.log(StdStyle.yellowBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.yellowBytes32("StdStyle.yellowBytes32")); + console2.log(StdStyle.blue("StdStyle.blue String Test")); + console2.log(StdStyle.blue(uint256(10e18))); + console2.log(StdStyle.blue(int256(-10e18))); + console2.log(StdStyle.blue(true)); + console2.log(StdStyle.blue(address(0))); + console2.log(StdStyle.blueBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.blueBytes32("StdStyle.blueBytes32")); + console2.log(StdStyle.magenta("StdStyle.magenta String Test")); + console2.log(StdStyle.magenta(uint256(10e18))); + console2.log(StdStyle.magenta(int256(-10e18))); + console2.log(StdStyle.magenta(true)); + console2.log(StdStyle.magenta(address(0))); + console2.log(StdStyle.magentaBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.magentaBytes32("StdStyle.magentaBytes32")); + console2.log(StdStyle.cyan("StdStyle.cyan String Test")); + console2.log(StdStyle.cyan(uint256(10e18))); + console2.log(StdStyle.cyan(int256(-10e18))); + console2.log(StdStyle.cyan(true)); + console2.log(StdStyle.cyan(address(0))); + console2.log(StdStyle.cyanBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.cyanBytes32("StdStyle.cyanBytes32")); + } + + function testStyleFontWeight() public view { + console2.log(StdStyle.bold("StdStyle.bold String Test")); + console2.log(StdStyle.bold(uint256(10e18))); + console2.log(StdStyle.bold(int256(-10e18))); + console2.log(StdStyle.bold(address(0))); + console2.log(StdStyle.bold(true)); + console2.log(StdStyle.boldBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.boldBytes32("StdStyle.boldBytes32")); + console2.log(StdStyle.dim("StdStyle.dim String Test")); + console2.log(StdStyle.dim(uint256(10e18))); + console2.log(StdStyle.dim(int256(-10e18))); + console2.log(StdStyle.dim(address(0))); + console2.log(StdStyle.dim(true)); + console2.log(StdStyle.dimBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.dimBytes32("StdStyle.dimBytes32")); + console2.log(StdStyle.italic("StdStyle.italic String Test")); + console2.log(StdStyle.italic(uint256(10e18))); + console2.log(StdStyle.italic(int256(-10e18))); + console2.log(StdStyle.italic(address(0))); + console2.log(StdStyle.italic(true)); + console2.log(StdStyle.italicBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.italicBytes32("StdStyle.italicBytes32")); + console2.log(StdStyle.underline("StdStyle.underline String Test")); + console2.log(StdStyle.underline(uint256(10e18))); + console2.log(StdStyle.underline(int256(-10e18))); + console2.log(StdStyle.underline(address(0))); + console2.log(StdStyle.underline(true)); + console2.log(StdStyle.underlineBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.underlineBytes32("StdStyle.underlineBytes32")); + console2.log(StdStyle.inverse("StdStyle.inverse String Test")); + console2.log(StdStyle.inverse(uint256(10e18))); + console2.log(StdStyle.inverse(int256(-10e18))); + console2.log(StdStyle.inverse(address(0))); + console2.log(StdStyle.inverse(true)); + console2.log(StdStyle.inverseBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.inverseBytes32("StdStyle.inverseBytes32")); + } + + function testStyleCombined() public view { + console2.log(StdStyle.red(StdStyle.bold("Red Bold String Test"))); + console2.log(StdStyle.green(StdStyle.dim(uint256(10e18)))); + console2.log(StdStyle.yellow(StdStyle.italic(int256(-10e18)))); + console2.log(StdStyle.blue(StdStyle.underline(address(0)))); + console2.log(StdStyle.magenta(StdStyle.inverse(true))); + } + + function testStyleCustom() public view { + console2.log(h1("Custom Style 1")); + console2.log(h2("Custom Style 2")); + } + + function h1(string memory a) private pure returns (string memory) { + return StdStyle.cyan(StdStyle.inverse(StdStyle.bold(a))); + } + + function h2(string memory a) private pure returns (string memory) { + return StdStyle.magenta(StdStyle.bold(StdStyle.underline(a))); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdUtils.t.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..a085b19 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/StdUtils.t.sol @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdUtilsMock is StdUtils { + // We deploy a mock version so we can properly test expected reverts. + function getTokenBalances_(address token, address[] memory addresses) + external + returns (uint256[] memory balances) + { + return getTokenBalances(token, addresses); + } +} + +contract StdUtilsTest is Test { + /*////////////////////////////////////////////////////////////////////////// + BOUND UINT + //////////////////////////////////////////////////////////////////////////*/ + + function testBound() public { + assertEq(bound(uint256(5), 0, 4), 0); + assertEq(bound(uint256(0), 69, 69), 69); + assertEq(bound(uint256(0), 68, 69), 68); + assertEq(bound(uint256(10), 150, 190), 174); + assertEq(bound(uint256(300), 2800, 3200), 3107); + assertEq(bound(uint256(9999), 1337, 6666), 4669); + } + + function testBound_WithinRange() public { + assertEq(bound(uint256(51), 50, 150), 51); + assertEq(bound(uint256(51), 50, 150), bound(bound(uint256(51), 50, 150), 50, 150)); + assertEq(bound(uint256(149), 50, 150), 149); + assertEq(bound(uint256(149), 50, 150), bound(bound(uint256(149), 50, 150), 50, 150)); + } + + function testBound_EdgeCoverage() public { + assertEq(bound(uint256(0), 50, 150), 50); + assertEq(bound(uint256(1), 50, 150), 51); + assertEq(bound(uint256(2), 50, 150), 52); + assertEq(bound(uint256(3), 50, 150), 53); + assertEq(bound(type(uint256).max, 50, 150), 150); + assertEq(bound(type(uint256).max - 1, 50, 150), 149); + assertEq(bound(type(uint256).max - 2, 50, 150), 148); + assertEq(bound(type(uint256).max - 3, 50, 150), 147); + } + + function testBound_DistributionIsEven(uint256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, UINT256_MAX / 2, UINT256_MAX / 2 + size); + uint256 max = min + size - 1; + uint256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + i, min, max); + assertEq(result, min + (i - 1) % size); + // x < min + result = bound(min - i, min, max); + assertEq(result, max - (i - 1) % size); + } + } + + function testBound(uint256 num, uint256 min, uint256 max) public { + if (min > max) (min, max) = (max, min); + + uint256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundUint256Max() public { + assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1); + assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max); + } + + function testCannotBoundMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(uint256(5), 100, 10); + } + + function testCannotBoundMaxLessThanMin(uint256 num, uint256 min, uint256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(num, min, max); + } + + /*////////////////////////////////////////////////////////////////////////// + BOUND INT + //////////////////////////////////////////////////////////////////////////*/ + + function testBoundInt() public { + assertEq(bound(-3, 0, 4), 2); + assertEq(bound(0, -69, -69), -69); + assertEq(bound(0, -69, -68), -68); + assertEq(bound(-10, 150, 190), 154); + assertEq(bound(-300, 2800, 3200), 2908); + assertEq(bound(9999, -1337, 6666), 1995); + } + + function testBoundInt_WithinRange() public { + assertEq(bound(51, -50, 150), 51); + assertEq(bound(51, -50, 150), bound(bound(51, -50, 150), -50, 150)); + assertEq(bound(149, -50, 150), 149); + assertEq(bound(149, -50, 150), bound(bound(149, -50, 150), -50, 150)); + } + + function testBoundInt_EdgeCoverage() public { + assertEq(bound(type(int256).min, -50, 150), -50); + assertEq(bound(type(int256).min + 1, -50, 150), -49); + assertEq(bound(type(int256).min + 2, -50, 150), -48); + assertEq(bound(type(int256).min + 3, -50, 150), -47); + assertEq(bound(type(int256).min, 10, 150), 10); + assertEq(bound(type(int256).min + 1, 10, 150), 11); + assertEq(bound(type(int256).min + 2, 10, 150), 12); + assertEq(bound(type(int256).min + 3, 10, 150), 13); + + assertEq(bound(type(int256).max, -50, 150), 150); + assertEq(bound(type(int256).max - 1, -50, 150), 149); + assertEq(bound(type(int256).max - 2, -50, 150), 148); + assertEq(bound(type(int256).max - 3, -50, 150), 147); + assertEq(bound(type(int256).max, -50, -10), -10); + assertEq(bound(type(int256).max - 1, -50, -10), -11); + assertEq(bound(type(int256).max - 2, -50, -10), -12); + assertEq(bound(type(int256).max - 3, -50, -10), -13); + } + + function testBoundInt_DistributionIsEven(int256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, -int256(size / 2), int256(size - size / 2)); + int256 max = min + int256(size) - 1; + int256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + int256(i), min, max); + assertEq(result, min + int256((i - 1) % size)); + // x < min + result = bound(min - int256(i), min, max); + assertEq(result, max - int256((i - 1) % size)); + } + } + + function testBoundInt(int256 num, int256 min, int256 max) public { + if (min > max) (min, max) = (max, min); + + int256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundIntInt256Max() public { + assertEq(bound(0, type(int256).max - 1, type(int256).max), type(int256).max - 1); + assertEq(bound(1, type(int256).max - 1, type(int256).max), type(int256).max); + } + + function testBoundIntInt256Min() public { + assertEq(bound(0, type(int256).min, type(int256).min + 1), type(int256).min); + assertEq(bound(1, type(int256).min, type(int256).min + 1), type(int256).min + 1); + } + + function testCannotBoundIntMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(-5, 100, 10); + } + + function testCannotBoundIntMaxLessThanMin(int256 num, int256 min, int256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(num, min, max); + } + + /*////////////////////////////////////////////////////////////////////////// + BYTES TO UINT + //////////////////////////////////////////////////////////////////////////*/ + + function testBytesToUint() external { + bytes memory maxUint = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + bytes memory two = hex"02"; + bytes memory millionEther = hex"d3c21bcecceda1000000"; + + assertEq(bytesToUint(maxUint), type(uint256).max); + assertEq(bytesToUint(two), 2); + assertEq(bytesToUint(millionEther), 1_000_000 ether); + } + + function testCannotConvertGT32Bytes() external { + bytes memory thirty3Bytes = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + vm.expectRevert("StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + bytesToUint(thirty3Bytes); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function testComputeCreateAddress() external { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE2 ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function testComputeCreate2Address() external { + bytes32 salt = bytes32(uint256(31415)); + bytes32 initcodeHash = keccak256(abi.encode(0x6080)); + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + address create2Address = computeCreate2Address(salt, initcodeHash, deployer); + assertEq(create2Address, 0xB147a5d25748fda14b463EB04B111027C290f4d3); + } + + function testComputeCreate2AddressWithDefaultDeployer() external { + bytes32 salt = 0xc290c670fde54e5ef686f9132cbc8711e76a98f0333a438a92daa442c71403c0; + bytes32 initcodeHash = hashInitCode(hex"6080", ""); + assertEq(initcodeHash, 0x1a578b7a4b0b5755db6d121b4118d4bc68fe170dca840c59bc922f14175a76b0); + address create2Address = computeCreate2Address(salt, initcodeHash); + assertEq(create2Address, 0xc0ffEe2198a06235aAbFffe5Db0CacF1717f5Ac6); + } +} + +contract StdUtilsForkTest is Test { + /*////////////////////////////////////////////////////////////////////////// + GET TOKEN BALANCES + //////////////////////////////////////////////////////////////////////////*/ + + address internal SHIB = 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE; + address internal SHIB_HOLDER_0 = 0x855F5981e831D83e6A4b4EBFCAdAa68D92333170; + address internal SHIB_HOLDER_1 = 0x8F509A90c2e47779cA408Fe00d7A72e359229AdA; + address internal SHIB_HOLDER_2 = 0x0e3bbc0D04fF62211F71f3e4C45d82ad76224385; + + address internal USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address internal USDC_HOLDER_0 = 0xDa9CE944a37d218c3302F6B82a094844C6ECEb17; + address internal USDC_HOLDER_1 = 0x3e67F4721E6d1c41a015f645eFa37BEd854fcf52; + + function setUp() public { + // All tests of the `getTokenBalances` method are fork tests using live contracts. + vm.createSelectFork({urlOrAlias: "mainnet", blockNumber: 16_428_900}); + } + + function testCannotGetTokenBalances_NonTokenContract() external { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + // The UniswapV2Factory contract has neither a `balanceOf` function nor a fallback function, + // so the `balanceOf` call should revert. + address token = address(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); + address[] memory addresses = new address[](1); + addresses[0] = USDC_HOLDER_0; + + vm.expectRevert("Multicall3: call failed"); + stdUtils.getTokenBalances_(token, addresses); + } + + function testCannotGetTokenBalances_EOA() external { + address eoa = vm.addr({privateKey: 1}); + address[] memory addresses = new address[](1); + addresses[0] = USDC_HOLDER_0; + vm.expectRevert("StdUtils getTokenBalances(address,address[]): Token address is not a contract."); + getTokenBalances(eoa, addresses); + } + + function testGetTokenBalances_Empty() external { + address[] memory addresses = new address[](0); + uint256[] memory balances = getTokenBalances(USDC, addresses); + assertEq(balances.length, 0); + } + + function testGetTokenBalances_USDC() external { + address[] memory addresses = new address[](2); + addresses[0] = USDC_HOLDER_0; + addresses[1] = USDC_HOLDER_1; + uint256[] memory balances = getTokenBalances(USDC, addresses); + assertEq(balances[0], 159_000_000_000_000); + assertEq(balances[1], 131_350_000_000_000); + } + + function testGetTokenBalances_SHIB() external { + address[] memory addresses = new address[](3); + addresses[0] = SHIB_HOLDER_0; + addresses[1] = SHIB_HOLDER_1; + addresses[2] = SHIB_HOLDER_2; + uint256[] memory balances = getTokenBalances(SHIB, addresses); + assertEq(balances[0], 3_323_256_285_484.42e18); + assertEq(balances[1], 1_271_702_771_149.99999928e18); + assertEq(balances[2], 606_357_106_247e18); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationScript.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..e205cff --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationScript.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScript is Script {} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationScriptBase.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..ce8e0e9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationScriptBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScriptBase is ScriptBase {} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationTest.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..9beeafe --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationTest.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTest is Test {} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationTestBase.sol b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..e993535 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/compilation/CompilationTestBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTestBase is TestBase {} diff --git a/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/fixtures/broadcast.log.json b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/fixtures/broadcast.log.json new file mode 100644 index 0000000..0a0200b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/lib/forge-std/test/fixtures/broadcast.log.json @@ -0,0 +1,187 @@ +{ + "transactions": [ + { + "hash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "function": "multiple_arguments(uint256,address,uint256[]):(uint256)", + "arguments": ["1", "0000000000000000000000000000000000001337", "[3,4]"], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "gas": "0x73b9", + "value": "0x0", + "data": "0x23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004", + "nonce": "0x3", + "accessList": [] + } + }, + { + "hash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "function": "inc():(uint256)", + "arguments": [], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "gas": "0xdcb2", + "value": "0x0", + "data": "0x371303c0", + "nonce": "0x4", + "accessList": [] + } + }, + { + "hash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "function": "t(uint256):(uint256)", + "arguments": ["1"], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "gas": "0x8599", + "value": "0x0", + "data": "0xafe29f710000000000000000000000000000000000000000000000000000000000000001", + "nonce": "0x5", + "accessList": [] + } + } + ], + "receipts": [ + { + "transactionHash": "0x481dc86e40bba90403c76f8e144aa9ff04c1da2164299d0298573835f0991181", + "transactionIndex": "0x0", + "blockHash": "0xef0730448490304e5403be0fa8f8ce64f118e9adcca60c07a2ae1ab921d748af", + "blockNumber": "0x1", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": null, + "cumulativeGasUsed": "0x13f3a", + "gasUsed": "0x13f3a", + "contractAddress": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x6a187183545b8a9e7f1790e847139379bf5622baff2cb43acf3f5c79470af782", + "transactionIndex": "0x0", + "blockHash": "0xf3acb96a90071640c2a8c067ae4e16aad87e634ea8d8bbbb5b352fba86ba0148", + "blockNumber": "0x2", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": null, + "cumulativeGasUsed": "0x45d80", + "gasUsed": "0x45d80", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x064ad173b4867bdef2fb60060bbdaf01735fbf10414541ea857772974e74ea9d", + "transactionIndex": "0x0", + "blockHash": "0x8373d02109d3ee06a0225f23da4c161c656ccc48fe0fcee931d325508ae73e58", + "blockNumber": "0x3", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "cumulativeGasUsed": "0x45feb", + "gasUsed": "0x45feb", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", + "transactionIndex": "0x0", + "blockHash": "0x16712fae5c0e18f75045f84363fb6b4d9a9fe25e660c4ce286833a533c97f629", + "blockNumber": "0x4", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "cumulativeGasUsed": "0x5905", + "gasUsed": "0x5905", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", + "transactionIndex": "0x0", + "blockHash": "0x156b88c3eb9a1244ba00a1834f3f70de735b39e3e59006dd03af4fe7d5480c11", + "blockNumber": "0x5", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "cumulativeGasUsed": "0xa9c4", + "gasUsed": "0xa9c4", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "transactionIndex": "0x0", + "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", + "blockNumber": "0x6", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "cumulativeGasUsed": "0x66c5", + "gasUsed": "0x66c5", + "contractAddress": null, + "logs": [ + { + "address": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "topics": [ + "0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000", + "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", + "blockNumber": "0x6", + "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "transactionIndex": "0x1", + "logIndex": "0x0", + "transactionLogIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x11fbb10230c168ca1e36a7e5c69a6dbcd04fd9e64ede39d10a83e36ee8065c16", + "transactionIndex": "0x0", + "blockHash": "0xf1e0ed2eda4e923626ec74621006ed50b3fc27580dc7b4cf68a07ca77420e29c", + "blockNumber": "0x7", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x0000000000000000000000000000000000001337", + "cumulativeGasUsed": "0x5208", + "gasUsed": "0x5208", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + } + ], + "libraries": [ + "src/Broadcast.t.sol:F:0x5fbdb2315678afecb367f032d93f642f64180aa3" + ], + "pending": [], + "path": "broadcast/Broadcast.t.sol/31337/run-latest.json", + "returns": {}, + "timestamp": 1655140035 +} diff --git a/lib/openzeppelin-contracts-v4.9.3/logo.svg b/lib/openzeppelin-contracts-v4.9.3/logo.svg new file mode 100644 index 0000000..f1e14c2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/lib/openzeppelin-contracts-v4.9.3/netlify.toml b/lib/openzeppelin-contracts-v4.9.3/netlify.toml new file mode 100644 index 0000000..0447f41 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/netlify.toml @@ -0,0 +1,3 @@ +[build] +command = "npm run docs" +publish = "build/site" diff --git a/lib/openzeppelin-contracts-v4.9.3/package-lock.json b/lib/openzeppelin-contracts-v4.9.3/package-lock.json new file mode 100644 index 0000000..2ef7afc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/package-lock.json @@ -0,0 +1,28833 @@ +{ + "name": "openzeppelin-solidity", + "version": "4.9.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "openzeppelin-solidity", + "version": "4.9.0", + "license": "MIT", + "bin": { + "openzeppelin-contracts-migrate-imports": "scripts/migrate-imports.js" + }, + "devDependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-truffle5": "^2.0.5", + "@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", + "eth-sig-util": "^3.0.0", + "ethereumjs-util": "^7.0.7", + "ethereumjs-wallet": "^1.0.1", + "glob": "^8.0.3", + "graphlib": "^2.1.8", + "hardhat": "^2.9.1", + "hardhat-exposed": "^0.3.3", + "hardhat-gas-reporter": "^1.0.4", + "hardhat-ignore-warnings": "^0.2.0", + "keccak256": "^1.0.2", + "lodash.startcase": "^4.4.0", + "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", + "semver": "^7.3.5", + "solhint": "^3.3.6", + "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" + } + }, + "node_modules/@babel/code-frame": { + "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" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "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" + }, + "engines": { + "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", + "integrity": "sha512-ECDNeoc3nfeAe1jqJb5aFQX7CqzQhD2klXRez2JDb/aVpGUbX673HgKrnrgJRuQR/9f2TtLoYIzrGB9qwD77mg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/config": "^2.3.0", + "@changesets/get-version-range-type": "^0.3.2", + "@changesets/git": "^2.0.0", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^5.4.1" + } + }, + "node_modules/@changesets/apply-release-plan/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/@changesets/assemble-release-plan": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.3.tgz", + "integrity": "sha512-g7EVZCmnWz3zMBAdrcKhid4hkHT+Ft1n0mLussFMcB1dE2zCuwcvGoy9ec3yOgPGF4hoMtgHaMIk3T3TBdvU9g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "semver": "^5.4.1" + } + }, + "node_modules/@changesets/assemble-release-plan/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/@changesets/changelog-git": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.1.14.tgz", + "integrity": "sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1" + } + }, + "node_modules/@changesets/changelog-github": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.4.8.tgz", + "integrity": "sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw==", + "dev": true, + "dependencies": { + "@changesets/get-github-info": "^0.5.2", + "@changesets/types": "^5.2.1", + "dotenv": "^8.1.0" + } + }, + "node_modules/@changesets/cli": { + "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", + "@changesets/apply-release-plan": "^6.1.3", + "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/changelog-git": "^0.1.14", + "@changesets/config": "^2.3.0", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/get-release-plan": "^3.0.16", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@changesets/write": "^0.2.3", + "@manypkg/get-packages": "^1.1.3", + "@types/is-ci": "^3.0.0", + "@types/semver": "^6.0.0", + "ansi-colors": "^4.1.3", + "chalk": "^2.1.0", + "enquirer": "^2.3.0", + "external-editor": "^3.1.0", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "is-ci": "^3.0.1", + "meow": "^6.0.0", + "outdent": "^0.5.0", + "p-limit": "^2.2.0", + "preferred-pm": "^3.0.0", + "resolve-from": "^5.0.0", + "semver": "^5.4.1", + "spawndamnit": "^2.0.0", + "term-size": "^2.1.0", + "tty-table": "^4.1.5" + }, + "bin": { + "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", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@changesets/config": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.0.tgz", + "integrity": "sha512-EgP/px6mhCx8QeaMAvWtRrgyxW08k/Bx2tpGT+M84jEdX37v3VKfh4Cz1BkwrYKuMV2HZKeHOh8sHvja/HcXfQ==", + "dev": true, + "dependencies": { + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/logger": "^0.0.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.2" + } + }, + "node_modules/@changesets/errors": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.1.4.tgz", + "integrity": "sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==", + "dev": true, + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.5.tgz", + "integrity": "sha512-w1eEvnWlbVDIY8mWXqWuYE9oKhvIaBhzqzo4ITSJY9hgoqQ3RoBqwlcAzg11qHxv/b8ReDWnMrpjpKrW6m1ZTA==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "semver": "^5.4.1" + } + }, + "node_modules/@changesets/get-dependents-graph/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/@changesets/get-github-info": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.5.2.tgz", + "integrity": "sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==", + "dev": true, + "dependencies": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.16.tgz", + "integrity": "sha512-OpP9QILpBp1bY2YNIKFzwigKh7Qe9KizRsZomzLe6pK8IUo8onkAAVUD8+JRKSr8R7d4+JRuQrfSSNlEwKyPYg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/config": "^2.3.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz", + "integrity": "sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==", + "dev": true + }, + "node_modules/@changesets/git": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-2.0.0.tgz", + "integrity": "sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.2", + "spawndamnit": "^2.0.0" + } + }, + "node_modules/@changesets/logger": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.0.5.tgz", + "integrity": "sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==", + "dev": true, + "dependencies": { + "chalk": "^2.1.0" + } + }, + "node_modules/@changesets/parse": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.16.tgz", + "integrity": "sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1", + "js-yaml": "^3.13.1" + } + }, + "node_modules/@changesets/pre": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-1.0.14.tgz", + "integrity": "sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.5.9.tgz", + "integrity": "sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/parse": "^0.3.16", + "@changesets/types": "^5.2.1", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0" + } + }, + "node_modules/@changesets/types": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz", + "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==", + "dev": true + }, + "node_modules/@changesets/write": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.2.3.tgz", + "integrity": "sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/types": "^5.2.1", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "prettier": "^2.7.1" + } + }, + "node_modules/@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dev": true, + "dependencies": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + } + }, + "node_modules/@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true, + "dependencies": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + } + }, + "node_modules/@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + } + }, + "node_modules/@ensdomains/ensjs/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/@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true + }, + "node_modules/@eslint-community/eslint-utils": { + "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" + }, + "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.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.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.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/js": { + "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" + } + }, + "node_modules/@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "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/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "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/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bignumber/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/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "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/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "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/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "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" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "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/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "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/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/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key/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/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "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/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "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/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^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/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "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/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "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/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@frangio/servbot": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@frangio/servbot/-/servbot-0.2.5.tgz", + "integrity": "sha512-ogja4iAPZ1VwM5MU3C1ZhB88358F0PGbmSTGOkIZwOyLaDoMHIqOVCnavHjR7DV5h+oAI4Z4KDqlam3myQUrmg==", + "dev": true, + "engines": { + "node": ">=12.x", + "pnpm": "7.5.1" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "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", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "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", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/@noble/hashes": { + "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": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@noble/secp256k1": { + "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": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block": { + "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": "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": "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": "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", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "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": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash": { + "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": "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" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm": { + "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": { + "@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", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "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" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager": { + "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": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "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": "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": "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" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "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": { + "@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": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util": { + "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": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "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": { + "@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", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "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" + }, + "peerDependencies": { + "hardhat": "^2.9.5" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "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.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.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" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomiclabs/hardhat-truffle5": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-truffle5/-/hardhat-truffle5-2.0.7.tgz", + "integrity": "sha512-Pw8451IUZp1bTp0QqCHCYfCHs66sCnyxPcaorapu9mfOV9xnZsVaFdtutnhNEiXdiZwbed7LFKpRsde4BjFwig==", + "dev": true, + "dependencies": { + "@nomiclabs/truffle-contract": "^4.2.23", + "@types/chai": "^4.2.0", + "chai": "^4.2.0", + "ethereumjs-util": "^7.1.4", + "fs-extra": "^7.0.1" + }, + "peerDependencies": { + "@nomiclabs/hardhat-web3": "^2.0.0", + "hardhat": "^2.6.4", + "web3": "^1.0.0-beta.36" + } + }, + "node_modules/@nomiclabs/hardhat-web3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-web3/-/hardhat-web3-2.0.0.tgz", + "integrity": "sha512-zt4xN+D+fKl3wW2YlTX3k9APR3XZgPkxJYf36AcliJn3oujnKEVRZaHu0PhgLjO+gR+F/kiYayo9fgd2L8970Q==", + "dev": true, + "dependencies": { + "@types/bignumber.js": "^5.0.0" + }, + "peerDependencies": { + "hardhat": "^2.0.0", + "web3": "^1.0.0-beta.36" + } + }, + "node_modules/@nomiclabs/truffle-contract": { + "version": "4.5.10", + "resolved": "https://registry.npmjs.org/@nomiclabs/truffle-contract/-/truffle-contract-4.5.10.tgz", + "integrity": "sha512-nF/6InFV+0hUvutyFgsdOMCoYlr//2fJbRER4itxYtQtc4/O1biTwZIKRu+5l2J5Sq6LU2WX7vZHtDgQdhWxIQ==", + "dev": true, + "dependencies": { + "@ensdomains/ensjs": "^2.0.1", + "@truffle/blockchain-utils": "^0.1.3", + "@truffle/contract-schema": "^3.4.7", + "@truffle/debug-utils": "^6.0.22", + "@truffle/error": "^0.1.0", + "@truffle/interface-adapter": "^0.5.16", + "bignumber.js": "^7.2.1", + "ethereum-ens": "^0.8.0", + "ethers": "^4.0.0-beta.1", + "source-map-support": "^0.5.19" + }, + "peerDependencies": { + "web3": "^1.2.1", + "web3-core-helpers": "^1.2.1", + "web3-core-promievent": "^1.2.1", + "web3-eth-abi": "^1.2.1", + "web3-utils": "^1.2.1" + } + }, + "node_modules/@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@openzeppelin/docs-utils": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/docs-utils/-/docs-utils-0.1.3.tgz", + "integrity": "sha512-O/iJ4jEi5ryNc/T74G9gbnFwQ8QaQ2bpAVoYXLPknZJyK52GEAvxC12UMP33KodTNV3rMzeeQrSBIdI8skjDJg==", + "dev": true, + "dependencies": { + "@frangio/servbot": "^0.2.5", + "chalk": "^3.0.0", + "chokidar": "^3.5.3", + "env-paths": "^2.2.0", + "find-up": "^4.1.0", + "is-port-reachable": "^3.0.0", + "js-yaml": "^3.13.1", + "lodash.startcase": "^4.4.0", + "minimist": "^1.2.0" + }, + "bin": { + "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", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dev": true, + "dependencies": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "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", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@openzeppelin/upgrades-core": { + "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", + "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/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/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/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": ">=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": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@truffle/abi-utils": { + "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", + "fast-check": "3.1.1", + "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.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.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", + "@truffle/compile-common": "^0.9.4", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "7.3.7", + "utf8": "^3.0.0", + "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": { + "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/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", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "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", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "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", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@truffle/compile-common": { + "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", + "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.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.7", + "@truffle/contract-schema": "^3.4.13", + "@truffle/debug-utils": "^6.0.48", + "@truffle/error": "^0.2.0", + "@truffle/interface-adapter": "^0.5.32", + "bignumber.js": "^7.2.1", + "debug": "^4.3.1", + "ethers": "^4.0.32", + "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.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", + "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/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": { + "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", + "debug": "^4.3.1", + "highlightjs-solidity": "^2.0.6" + } + }, + "node_modules/@truffle/debug-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/error": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.1.1.tgz", + "integrity": "sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter": { + "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", + "ethers": "^4.0.32", + "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", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dev": true, + "dependencies": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "strip-indent": "^2.0.0" + } + }, + "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, + "engines": { + "node": ">=4" + } + }, + "node_modules/@types/bignumber.js": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bignumber.js/-/bignumber.js-5.0.0.tgz", + "integrity": "sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==", + "deprecated": "This is a stub types definition for bignumber.js (https://github.com/MikeMcl/bignumber.js/). bignumber.js provides its own type definitions, so you don't need @types/bignumber.js installed!", + "dev": true, + "dependencies": { + "bignumber.js": "*" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "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": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "node_modules/@types/is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.1.0" + } + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "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/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "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", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz", + "integrity": "sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true + }, + "node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/abstract-level/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "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" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", + "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "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/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/antlr4": { + "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", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "dev": true + }, + "node_modules/astral-regex": { + "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": ">=8" + } + }, + "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/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "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": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/bigint-crypto-utils": { + "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": ">=14.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "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/body-parser": { + "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.5", + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "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", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/breakword": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/breakword/-/breakword-1.0.5.tgz", + "integrity": "sha512-ex5W9DoOQ/LUEU3PMdLs9ua/CYZl1678NUkKOdUSi8Aw5F1idieaiRURCBFJCwVcrD1J8Iy3vfWSloaMwO2qFg==", + "dev": true, + "dependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "node_modules/browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-reverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==", + "dev": true + }, + "node_modules/buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/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/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", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "dev": true, + "peerDependencies": { + "bn.js": "^4.11.0", + "chai": "^4.0.0" + } + }, + "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/change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/ci-info": { + "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", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/cids/node_modules/multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "dev": true + }, + "node_modules/classic-level": { + "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.2.2", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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/cliui/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "node_modules/commander": { + "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" + } + }, + "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", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "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", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-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/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, + "dependencies": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "dependencies": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "node_modules/content-type": { + "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" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "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", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + } + }, + "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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-addr-codec": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.7.tgz", + "integrity": "sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, + "node_modules/crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", + "dev": true + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "dev": true, + "dependencies": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + }, + "engines": { + "node": ">= 0.1.90" + } + }, + "node_modules/csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "dev": true + }, + "node_modules/csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "node_modules/csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", + "dev": true + }, + "node_modules/death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-properties": { + "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", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "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.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "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" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "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.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "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.5", + "is-array-buffer": "^3.0.2", + "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.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", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "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", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/escodegen/node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/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/escodegen/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/escodegen/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/eslint": { + "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.2", + "@eslint/js": "8.39.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.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", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "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" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "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", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "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": { + "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": ">=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", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/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/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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "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", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "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.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.4.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "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" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dev": true, + "dependencies": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "node_modules/eth-ens-namehash/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/eth-gas-reporter": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz", + "integrity": "sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.0.0-beta.146", + "@solidity-parser/parser": "^0.14.0", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^4.0.40", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^7.1.1", + "req-cwd": "^2.0.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "peerDependencies": { + "@codechecks/client": "^0.1.0" + }, + "peerDependenciesMeta": { + "@codechecks/client": { + "optional": true + } + } + }, + "node_modules/eth-gas-reporter/node_modules/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/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/eth-gas-reporter/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/eth-gas-reporter/node_modules/chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.1" + } + }, + "node_modules/eth-gas-reporter/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eth-gas-reporter/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eth-gas-reporter/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==", + "dev": true + }, + "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { + "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.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": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/eth-gas-reporter/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": { + "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": "*" + } + }, + "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", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eth-gas-reporter/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/eth-gas-reporter/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/eth-gas-reporter/node_modules/mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/eth-gas-reporter/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "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-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", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eth-gas-reporter/node_modules/readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eth-gas-reporter/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/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/eth-gas-reporter/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_modules/eth-gas-reporter/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==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/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_modules/eth-gas-reporter/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-gas-reporter/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/eth-gas-reporter/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/eth-gas-reporter/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/eth-lib/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/eth-lib/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/eth-sig-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-3.0.1.tgz", + "integrity": "sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==", + "deprecated": "Deprecated in favor of '@metamask/eth-sig-util'", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^5.1.1", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.0" + } + }, + "node_modules/eth-sig-util/node_modules/ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "dependencies": { + "js-sha3": "^0.8.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereum-ens": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ethereum-ens/-/ethereum-ens-0.8.0.tgz", + "integrity": "sha512-a8cBTF4AWw1Q1Y37V1LSCS9pRY4Mh3f8vCg5cbXCCEJ3eno1hbI/+Ccv9SZLISYpqQhaglP3Bxb/34lS4Qf7Bg==", + "dev": true, + "dependencies": { + "bluebird": "^3.4.7", + "eth-ens-namehash": "^2.0.0", + "js-sha3": "^0.5.7", + "pako": "^1.0.4", + "underscore": "^1.8.3", + "web3": "^1.0.0-beta.34" + } + }, + "node_modules/ethereum-ens/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethereumjs-util/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/ethereumjs-wallet": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz", + "integrity": "sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==", + "dev": true, + "dependencies": { + "aes-js": "^3.1.2", + "bs58check": "^2.1.2", + "ethereum-cryptography": "^0.1.3", + "ethereumjs-util": "^7.1.2", + "randombytes": "^2.1.0", + "scrypt-js": "^3.0.1", + "utf8": "^3.0.0", + "uuid": "^8.3.2" + } + }, + "node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/ethers/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/ethers/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/ethers/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/ethers/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "node_modules/ethers/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "node_modules/ethers/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true + }, + "node_modules/ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-abi/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-abi/node_modules/js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==", + "dev": true + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "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", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "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", + "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", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dev": true, + "dependencies": { + "pure-rand": "^5.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "dev": true + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "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", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + }, + "bin": { + "testrpc-sc": "index.js" + } + }, + "node_modules/glob": { + "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", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/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_modules/globals": { + "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" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "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/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "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": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/hardhat": { + "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": "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", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat-exposed": { + "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", + "solidity-ast": "^0.4.25" + }, + "peerDependencies": { + "hardhat": "^2.3.0" + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "dependencies": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + }, + "peerDependencies": { + "hardhat": "^2.0.2" + } + }, + "node_modules/hardhat-ignore-warnings": { + "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", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + } + }, + "node_modules/hardhat-ignore-warnings/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/hardhat-ignore-warnings/node_modules/minimatch": { + "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" + }, + "engines": { + "node": ">=10" + } + }, + "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": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "node_modules/hardhat/node_modules/ethereum-cryptography": { + "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.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/hardhat/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/hardhat/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/hardhat/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/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/hardhat/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/hardhat/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/hardhat/node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/hardhat/node_modules/solc/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/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "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", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-solidity": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/htmlparser2": { + "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", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-cache-semantics": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "dev": true + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "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", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-id": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz", + "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "dependencies": { + "punycode": "2.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "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": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "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", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "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.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "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.2.0", + "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", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/is-port-reachable": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-3.1.0.tgz", + "integrity": "sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/js-sdsl": { + "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", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "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", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keccak": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", + "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keccak256": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz", + "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0", + "buffer": "^6.0.3", + "keccak": "^3.0.2" + } + }, + "node_modules/keccak256/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/keccak256/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "dependencies": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/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/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", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "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", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "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/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", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, + "node_modules/lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.2" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/meow": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", + "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/merkletreejs": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.2.32.tgz", + "integrity": "sha512-TostQBiwYRIwSE5++jGmacu3ODcKAgqb0Y/pnIohXS7sWxh1gCkSptbmF1a43faehRDpcHf7J/kv0Ml2D/zblQ==", + "dev": true, + "dependencies": { + "bignumber.js": "^9.0.1", + "buffer-reverse": "^1.0.1", + "crypto-js": "^3.1.9-1", + "treeify": "^1.1.0", + "web3-utils": "^1.3.4" + }, + "engines": { + "node": ">= 7.6.0" + } + }, + "node_modules/merkletreejs/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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "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" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mixme": { + "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" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", + "dev": true, + "dependencies": { + "mkdirp": "*" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "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", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "dev": true + }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "varint": "^5.0.0" + } + }, + "node_modules/multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "node_modules/multihashes/node_modules/multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/nano-base32": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==", + "dev": true + }, + "node_modules/nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-macros": { + "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": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "node_modules/node-environment-flags/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/node-fetch": { + "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" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "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", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-interval-tree": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-2.1.2.tgz", + "integrity": "sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==", + "dev": true, + "dependencies": { + "shallowequal": "^1.1.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "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/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/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/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "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" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "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.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "node_modules/oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dev": true, + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-filter/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "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", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "dev": true + }, + "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/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "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", + "integrity": "sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0", + "find-yarn-workspace-root2": "1.2.16", + "path-exists": "^4.0.0", + "which-pm": "2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/preferred-pm/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/preferred-pm/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "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" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-solidity": { + "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.16.0", + "semver": "^7.3.8", + "solidity-comments-extractor": "^0.0.7" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "prettier": ">=2.3.0 || >=3.0.0-alpha.0" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { + "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" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "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" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "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", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/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/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/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/read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/readable-stream": { + "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", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "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.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "dependencies": { + "req-from": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from/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" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.12.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "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/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/responselike/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/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/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/rlp/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/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "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", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/sc-istanbul/node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "node_modules/sc-istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sc-istanbul/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_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "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" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "dependencies": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dev": true, + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/sha3/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/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/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dev": true, + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "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": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-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/slice-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/slice-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/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", + "integrity": "sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==", + "dev": true, + "dependencies": { + "array.prototype.flat": "^1.2.3", + "breakword": "^1.0.5", + "grapheme-splitter": "^1.0.4", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^15.1.0" + }, + "bin": { + "smartwrap": "src/terminal-adapter.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/smartwrap/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, + "engines": { + "node": ">=8" + } + }, + "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": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/smartwrap/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "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": ">=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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/smartwrap/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dev": true, + "dependencies": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + }, + "bin": { + "solcjs": "solcjs" + } + }, + "node_modules/solc/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "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" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/solc/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/solc/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "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", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "node_modules/solc/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/solc/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/solc/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "node_modules/solc/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/solc/node_modules/yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "dependencies": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "node_modules/solc/node_modules/yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + }, + "node_modules/solhint": { + "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.16.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": "^2.8.3" + } + }, + "node_modules/solhint/node_modules/@solidity-parser/parser": { + "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" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint/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/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": "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/solhint/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/solhint/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/solhint/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/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/solhint/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint/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/solidity-ast": { + "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": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments/-/solidity-comments-0.0.2.tgz", + "integrity": "sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "solidity-comments-darwin-arm64": "0.0.2", + "solidity-comments-darwin-x64": "0.0.2", + "solidity-comments-freebsd-x64": "0.0.2", + "solidity-comments-linux-arm64-gnu": "0.0.2", + "solidity-comments-linux-arm64-musl": "0.0.2", + "solidity-comments-linux-x64-gnu": "0.0.2", + "solidity-comments-linux-x64-musl": "0.0.2", + "solidity-comments-win32-arm64-msvc": "0.0.2", + "solidity-comments-win32-ia32-msvc": "0.0.2", + "solidity-comments-win32-x64-msvc": "0.0.2" + } + }, + "node_modules/solidity-comments-darwin-arm64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-arm64/-/solidity-comments-darwin-arm64-0.0.2.tgz", + "integrity": "sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-darwin-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-x64/-/solidity-comments-darwin-x64-0.0.2.tgz", + "integrity": "sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "node_modules/solidity-comments-freebsd-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-freebsd-x64/-/solidity-comments-freebsd-x64-0.0.2.tgz", + "integrity": "sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-gnu/-/solidity-comments-linux-arm64-gnu-0.0.2.tgz", + "integrity": "sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-musl/-/solidity-comments-linux-arm64-musl-0.0.2.tgz", + "integrity": "sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-gnu/-/solidity-comments-linux-x64-gnu-0.0.2.tgz", + "integrity": "sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-musl/-/solidity-comments-linux-x64-musl-0.0.2.tgz", + "integrity": "sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-arm64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-arm64-msvc/-/solidity-comments-win32-arm64-msvc-0.0.2.tgz", + "integrity": "sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-ia32-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-ia32-msvc/-/solidity-comments-win32-ia32-msvc-0.0.2.tgz", + "integrity": "sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-x64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-x64-msvc/-/solidity-comments-win32-x64-msvc-0.0.2.tgz", + "integrity": "sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-coverage": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.2.tgz", + "integrity": "sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.14.1", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "7.1.2", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "bin": { + "solidity-coverage": "plugins/bin.js" + }, + "peerDependencies": { + "hardhat": "^2.11.0" + } + }, + "node_modules/solidity-coverage/node_modules/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/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/solidity-coverage/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/solidity-coverage/node_modules/chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.1" + } + }, + "node_modules/solidity-coverage/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/solidity-coverage/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/solidity-coverage/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/solidity-coverage/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==", + "dev": true + }, + "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", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/solidity-coverage/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/solidity-coverage/node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/solidity-coverage/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/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": ">=8" + } + }, + "node_modules/solidity-coverage/node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/solidity-coverage/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/solidity-coverage/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/solidity-coverage/node_modules/mocha": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", + "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", + "dev": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "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": { + "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": "*" + } + }, + "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": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "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-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", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/solidity-coverage/node_modules/readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/solidity-coverage/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==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/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/solidity-coverage/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_modules/solidity-coverage/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==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/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_modules/solidity-coverage/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-coverage/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/solidity-coverage/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/solidity-coverage/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/solidity-coverage/node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/solidity-docgen": { + "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", + "solidity-ast": "^0.4.38" + }, + "peerDependencies": { + "hardhat": "^2.8.0" + } + }, + "node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz", + "integrity": "sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/spawndamnit/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/spawndamnit/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/spawndamnit/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==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit/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/spawndamnit/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_modules/spawndamnit/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/spdx-correct": { + "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", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "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": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "dev": true, + "dependencies": { + "mixme": "^0.5.1" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "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", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "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/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "node_modules/swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + } + }, + "node_modules/swarm-js/node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swarm-js/node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/swarm-js/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/swarm-js/node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/swarm-js/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "dependencies": { + "get-port": "^3.1.0" + } + }, + "node_modules/table": { + "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": "^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": ">=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": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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": "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "deprecated": "testrpc has been renamed to ganache-cli, please use this package from now on.", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tough-cookie/node_modules/punycode": { + "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" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "node_modules/tty-table": { + "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.3", + "kleur": "^4.1.5", + "smartwrap": "^2.0.2", + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.1", + "yargs": "^17.7.1" + }, + "bin": { + "tty-table": "adapters/terminal-adapter.js" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/tty-table/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, + "engines": { + "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", + "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/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", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "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", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "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", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/undici": { + "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" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, + "node_modules/upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "dev": true + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web3": { + "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.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.9.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.9.0.tgz", + "integrity": "sha512-9Zli9dikX8GdHwBb5/WPzpSVuy3EWMKY3P4EokCQra31fD7DLizqAAaTUsFwnK7xYkw5ogpHgelw9uKHHzNajg==", + "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/web3-core": { + "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.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "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.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.9.0", + "web3-utils": "1.9.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method": { + "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.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.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" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager": { + "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.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.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.9.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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/web3-eth": { + "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.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.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.9.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts": { + "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", + "@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.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-utils": "1.9.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/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/web3-eth-accounts/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/web3-eth-contract": { + "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.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.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.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.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.9.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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/web3-eth-personal": { + "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.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.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.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.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.9.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc": { + "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.9.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws": { + "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.9.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-shh": { + "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.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.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", + "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/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/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dev": true, + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", + "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", + "dev": true, + "dependencies": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8.15" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true, + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/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, + "engines": { + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "dependencies": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "node_modules/xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "dependencies": { + "xhr-request": "^1.1.0" + } + }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "dev": true, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "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", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "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/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": ">=6" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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/yargs/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "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" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/runtime": { + "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", + "integrity": "sha512-ECDNeoc3nfeAe1jqJb5aFQX7CqzQhD2klXRez2JDb/aVpGUbX673HgKrnrgJRuQR/9f2TtLoYIzrGB9qwD77mg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/config": "^2.3.0", + "@changesets/get-version-range-type": "^0.3.2", + "@changesets/git": "^2.0.0", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@changesets/assemble-release-plan": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.3.tgz", + "integrity": "sha512-g7EVZCmnWz3zMBAdrcKhid4hkHT+Ft1n0mLussFMcB1dE2zCuwcvGoy9ec3yOgPGF4hoMtgHaMIk3T3TBdvU9g==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@changesets/changelog-git": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.1.14.tgz", + "integrity": "sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==", + "dev": true, + "requires": { + "@changesets/types": "^5.2.1" + } + }, + "@changesets/changelog-github": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.4.8.tgz", + "integrity": "sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw==", + "dev": true, + "requires": { + "@changesets/get-github-info": "^0.5.2", + "@changesets/types": "^5.2.1", + "dotenv": "^8.1.0" + } + }, + "@changesets/cli": { + "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", + "@changesets/apply-release-plan": "^6.1.3", + "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/changelog-git": "^0.1.14", + "@changesets/config": "^2.3.0", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/get-release-plan": "^3.0.16", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@changesets/write": "^0.2.3", + "@manypkg/get-packages": "^1.1.3", + "@types/is-ci": "^3.0.0", + "@types/semver": "^6.0.0", + "ansi-colors": "^4.1.3", + "chalk": "^2.1.0", + "enquirer": "^2.3.0", + "external-editor": "^3.1.0", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "is-ci": "^3.0.1", + "meow": "^6.0.0", + "outdent": "^0.5.0", + "p-limit": "^2.2.0", + "preferred-pm": "^3.0.0", + "resolve-from": "^5.0.0", + "semver": "^5.4.1", + "spawndamnit": "^2.0.0", + "term-size": "^2.1.0", + "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", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@changesets/config": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.0.tgz", + "integrity": "sha512-EgP/px6mhCx8QeaMAvWtRrgyxW08k/Bx2tpGT+M84jEdX37v3VKfh4Cz1BkwrYKuMV2HZKeHOh8sHvja/HcXfQ==", + "dev": true, + "requires": { + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.5", + "@changesets/logger": "^0.0.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.2" + } + }, + "@changesets/errors": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.1.4.tgz", + "integrity": "sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==", + "dev": true, + "requires": { + "extendable-error": "^0.1.5" + } + }, + "@changesets/get-dependents-graph": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.5.tgz", + "integrity": "sha512-w1eEvnWlbVDIY8mWXqWuYE9oKhvIaBhzqzo4ITSJY9hgoqQ3RoBqwlcAzg11qHxv/b8ReDWnMrpjpKrW6m1ZTA==", + "dev": true, + "requires": { + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "semver": "^5.4.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@changesets/get-github-info": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@changesets/get-github-info/-/get-github-info-0.5.2.tgz", + "integrity": "sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==", + "dev": true, + "requires": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "@changesets/get-release-plan": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.16.tgz", + "integrity": "sha512-OpP9QILpBp1bY2YNIKFzwigKh7Qe9KizRsZomzLe6pK8IUo8onkAAVUD8+JRKSr8R7d4+JRuQrfSSNlEwKyPYg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/assemble-release-plan": "^5.2.3", + "@changesets/config": "^2.3.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3" + } + }, + "@changesets/get-version-range-type": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz", + "integrity": "sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==", + "dev": true + }, + "@changesets/git": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-2.0.0.tgz", + "integrity": "sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.2", + "spawndamnit": "^2.0.0" + } + }, + "@changesets/logger": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.0.5.tgz", + "integrity": "sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==", + "dev": true, + "requires": { + "chalk": "^2.1.0" + } + }, + "@changesets/parse": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.16.tgz", + "integrity": "sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==", + "dev": true, + "requires": { + "@changesets/types": "^5.2.1", + "js-yaml": "^3.13.1" + } + }, + "@changesets/pre": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-1.0.14.tgz", + "integrity": "sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "@changesets/read": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.5.9.tgz", + "integrity": "sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/parse": "^0.3.16", + "@changesets/types": "^5.2.1", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0" + } + }, + "@changesets/types": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz", + "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==", + "dev": true + }, + "@changesets/write": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.2.3.tgz", + "integrity": "sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.20.1", + "@changesets/types": "^5.2.1", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "prettier": "^2.7.1" + } + }, + "@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dev": true, + "requires": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + } + }, + "@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "dev": true, + "requires": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + } + }, + "@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dev": true, + "requires": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + }, + "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" + } + } + } + }, + "@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "dev": true + }, + "@eslint-community/eslint-utils": { + "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.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.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.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "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": { + "argparse": "^2.0.1" + } + } + } + }, + "@eslint/js": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", + "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "dev": true + }, + "@ethereumjs/common": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.5.0.tgz", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "requires": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "requires": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.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 + } + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + }, + "dependencies": { + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + } + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true + }, + "@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "requires": { + "@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/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + }, + "dependencies": { + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "requires": {} + } + } + }, + "@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + }, + "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 + } + } + }, + "@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^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/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@frangio/servbot": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@frangio/servbot/-/servbot-0.2.5.tgz", + "integrity": "sha512-ogja4iAPZ1VwM5MU3C1ZhB88358F0PGbmSTGOkIZwOyLaDoMHIqOVCnavHjR7DV5h+oAI4Z4KDqlam3myQUrmg==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "requires": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + }, + "dependencies": { + "@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "requires": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "dependencies": { + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + } + } + }, + "@noble/hashes": { + "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.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": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@nomicfoundation/ethereumjs-block": { + "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": "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": "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": "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", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + } + }, + "@nomicfoundation/ethereumjs-common": { + "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": "9.0.1", + "crc-32": "^1.2.0" + } + }, + "@nomicfoundation/ethereumjs-ethash": { + "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": "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": "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": { + "@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", + "rustbn.js": "~0.2.0" + } + }, + "@nomicfoundation/ethereumjs-rlp": { + "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": "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": "4.0.1", + "@nomicfoundation/ethereumjs-rlp": "5.0.1", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "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": "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": "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": "5.0.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz", + "integrity": "sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w==", + "dev": true, + "requires": { + "@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": "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": { + "@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": "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": "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", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + } + }, + "@nomicfoundation/hardhat-network-helpers": { + "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" + } + }, + "@nomicfoundation/solidity-analyzer": { + "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.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.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.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.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.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.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.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.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.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.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.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 + }, + "@nomiclabs/hardhat-truffle5": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-truffle5/-/hardhat-truffle5-2.0.7.tgz", + "integrity": "sha512-Pw8451IUZp1bTp0QqCHCYfCHs66sCnyxPcaorapu9mfOV9xnZsVaFdtutnhNEiXdiZwbed7LFKpRsde4BjFwig==", + "dev": true, + "requires": { + "@nomiclabs/truffle-contract": "^4.2.23", + "@types/chai": "^4.2.0", + "chai": "^4.2.0", + "ethereumjs-util": "^7.1.4", + "fs-extra": "^7.0.1" + } + }, + "@nomiclabs/hardhat-web3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-web3/-/hardhat-web3-2.0.0.tgz", + "integrity": "sha512-zt4xN+D+fKl3wW2YlTX3k9APR3XZgPkxJYf36AcliJn3oujnKEVRZaHu0PhgLjO+gR+F/kiYayo9fgd2L8970Q==", + "dev": true, + "requires": { + "@types/bignumber.js": "^5.0.0" + } + }, + "@nomiclabs/truffle-contract": { + "version": "4.5.10", + "resolved": "https://registry.npmjs.org/@nomiclabs/truffle-contract/-/truffle-contract-4.5.10.tgz", + "integrity": "sha512-nF/6InFV+0hUvutyFgsdOMCoYlr//2fJbRER4itxYtQtc4/O1biTwZIKRu+5l2J5Sq6LU2WX7vZHtDgQdhWxIQ==", + "dev": true, + "requires": { + "@ensdomains/ensjs": "^2.0.1", + "@truffle/blockchain-utils": "^0.1.3", + "@truffle/contract-schema": "^3.4.7", + "@truffle/debug-utils": "^6.0.22", + "@truffle/error": "^0.1.0", + "@truffle/interface-adapter": "^0.5.16", + "bignumber.js": "^7.2.1", + "ethereum-ens": "^0.8.0", + "ethers": "^4.0.0-beta.1", + "source-map-support": "^0.5.19" + } + }, + "@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + } + } + }, + "@openzeppelin/docs-utils": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/docs-utils/-/docs-utils-0.1.3.tgz", + "integrity": "sha512-O/iJ4jEi5ryNc/T74G9gbnFwQ8QaQ2bpAVoYXLPknZJyK52GEAvxC12UMP33KodTNV3rMzeeQrSBIdI8skjDJg==", + "dev": true, + "requires": { + "@frangio/servbot": "^0.2.5", + "chalk": "^3.0.0", + "chokidar": "^3.5.3", + "env-paths": "^2.2.0", + "find-up": "^4.1.0", + "is-port-reachable": "^3.0.0", + "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": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@openzeppelin/test-helpers/-/test-helpers-0.5.16.tgz", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dev": true, + "requires": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "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", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@openzeppelin/upgrades-core": { + "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", + "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": { + "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", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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" + } + } + } + }, + "@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "dev": true + }, + "@scure/bip32": { + "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.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "@scure/bip39": { + "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.2.0", + "@scure/base": "~1.1.0" + } + }, + "@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "requires": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + } + }, + "@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true + }, + "@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true + }, + "@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "@truffle/abi-utils": { + "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", + "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.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.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", + "@truffle/compile-common": "^0.9.4", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "7.3.7", + "utf8": "^3.0.0", + "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", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@truffle/compile-common": { + "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", + "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.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.7", + "@truffle/contract-schema": "^3.4.13", + "@truffle/debug-utils": "^6.0.48", + "@truffle/error": "^0.2.0", + "@truffle/interface-adapter": "^0.5.32", + "bignumber.js": "^7.2.1", + "debug": "^4.3.1", + "ethers": "^4.0.32", + "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 + }, + "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 + } + } + } + } + }, + "@truffle/contract-schema": { + "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", + "debug": "^4.3.1" + } + }, + "@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, + "requires": { + "@truffle/codec": "^0.14.17", + "@trufflesuite/chromafi": "^3.0.0", + "bn.js": "^5.1.3", + "chalk": "^2.4.2", + "debug": "^4.3.1", + "highlightjs-solidity": "^2.0.6" + }, + "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 + } + } + }, + "@truffle/error": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.1.1.tgz", + "integrity": "sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA==", + "dev": true + }, + "@truffle/interface-adapter": { + "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", + "ethers": "^4.0.32", + "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" + } + } + } + }, + "@trufflesuite/chromafi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@trufflesuite/chromafi/-/chromafi-3.0.0.tgz", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "strip-indent": "^2.0.0" + }, + "dependencies": { + "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 + } + } + }, + "@types/bignumber.js": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bignumber.js/-/bignumber.js-5.0.0.tgz", + "integrity": "sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==", + "dev": true, + "requires": { + "bignumber.js": "*" + } + }, + "@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "@types/chai": { + "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": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "dev": true + }, + "@types/is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==", + "dev": true, + "requires": { + "ci-info": "^3.1.0" + } + }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "@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 + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "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", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/semver": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-6.2.3.tgz", + "integrity": "sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==", + "dev": true + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true + }, + "abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "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": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "aes-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", + "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true + }, + "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-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "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" + } + }, + "antlr4": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.12.0.tgz", + "integrity": "sha512-23iB5IzXJZRZeK9TigzUyrNc9pSmNqAerJRBcNq1ETrmttMWRgaYZzC561IgEO3ygKsDJTYDTozABXa4b/fTQQ==", + "dev": true + }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.reduce": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz", + "integrity": "sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "dev": true + }, + "astral-regex": { + "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": { + "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", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true + }, + "aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + } + } + }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "requires": { + "is-windows": "^1.0.0" + } + }, + "big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "dev": true + }, + "big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "dev": true + }, + "bigint-crypto-utils": { + "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": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "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 + }, + "body-parser": { + "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.5", + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "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" + } + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "breakword": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/breakword/-/breakword-1.0.5.tgz", + "integrity": "sha512-ex5W9DoOQ/LUEU3PMdLs9ua/CYZl1678NUkKOdUSi8Aw5F1idieaiRURCBFJCwVcrD1J8Iy3vfWSloaMwO2qFg==", + "dev": true, + "requires": { + "wcwidth": "^1.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "requires": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-reverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==", + "dev": true + }, + "buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "dev": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "dev": true + }, + "cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "dev": true + }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "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", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true + }, + "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" + } + }, + "chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "dev": true, + "requires": {} + }, + "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" + } + }, + "change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dev": true, + "requires": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, + "cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "requires": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + } + }, + "cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true + }, + "cids": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "dependencies": { + "multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + } + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "dev": true + }, + "classic-level": { + "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.2.2", + "node-gyp-build": "^4.3.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "requires": { + "colors": "^1.1.2", + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "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 + }, + "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 + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true + }, + "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 + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "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", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "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", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "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 + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, + "requires": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "requires": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "content-type": { + "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": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "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", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" + }, + "dependencies": { + "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": { + "argparse": "^2.0.1" + } + } + } + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-fetch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", + "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "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": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true + }, + "crypto-addr-codec": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.7.tgz", + "integrity": "sha512-X4hzfBzNhy4mAc3UpiXEC/L0jo5E8wAa9unsnA8nNXYzXjCcGk83hfC5avJWCSGT8V91xMnAS9AKMHmjw5+XCg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, + "crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", + "dev": true + }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "dev": true, + "requires": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + } + }, + "csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "dev": true + }, + "csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "dev": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", + "dev": true + }, + "death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + }, + "decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true + } + } + }, + "decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } + } + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "define-properties": { + "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", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true + }, + "detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "requires": { + "address": "^1.0.1", + "debug": "4" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "requires": { + "heap": ">= 0.2.0" + } + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domutils": { + "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.3" + } + }, + "dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "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.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "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.5", + "is-array-buffer": "^3.0.2", + "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.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", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "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", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "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 + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "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" + } + }, + "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 + }, + "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" + } + } + } + }, + "eslint": { + "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.2", + "@eslint/js": "8.39.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.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", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "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": "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", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "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" + } + }, + "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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "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": { + "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" + } + } + } + }, + "eslint-config-prettier": { + "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.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", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "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.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.4.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "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" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dev": true, + "requires": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + } + } + }, + "eth-gas-reporter": { + "version": "0.2.25", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz", + "integrity": "sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.0.0-beta.146", + "@solidity-parser/parser": "^0.14.0", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^4.0.40", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^7.1.1", + "req-cwd": "^2.0.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.5", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "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 + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "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==", + "dev": true + }, + "ethereum-cryptography": { + "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.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "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" + } + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "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-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", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "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==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + }, + "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": "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" + } + }, + "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" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } + }, + "eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + }, + "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 + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + } + } + }, + "eth-sig-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-3.0.1.tgz", + "integrity": "sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==", + "dev": true, + "requires": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^5.1.1", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.0" + }, + "dependencies": { + "ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + } + } + }, + "ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "requires": { + "js-sha3": "^0.8.0" + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereum-ens": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ethereum-ens/-/ethereum-ens-0.8.0.tgz", + "integrity": "sha512-a8cBTF4AWw1Q1Y37V1LSCS9pRY4Mh3f8vCg5cbXCCEJ3eno1hbI/+Ccv9SZLISYpqQhaglP3Bxb/34lS4Qf7Bg==", + "dev": true, + "requires": { + "bluebird": "^3.4.7", + "eth-ens-namehash": "^2.0.0", + "js-sha3": "^0.5.7", + "pako": "^1.0.4", + "underscore": "^1.8.3", + "web3": "^1.0.0-beta.34" + }, + "dependencies": { + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + } + } + }, + "ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "dependencies": { + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + } + } + }, + "ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "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 + } + } + }, + "ethereumjs-wallet": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz", + "integrity": "sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==", + "dev": true, + "requires": { + "aes-js": "^3.1.2", + "bs58check": "^2.1.2", + "ethereum-cryptography": "^0.1.3", + "ethereumjs-util": "^7.1.2", + "randombytes": "^2.1.0", + "scrypt-js": "^3.0.1", + "utf8": "^3.0.0", + "uuid": "^8.3.2" + } + }, + "ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "requires": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + }, + "dependencies": { + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "dev": true + } + } + }, + "ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==", + "dev": true + } + } + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "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", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "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" + } + }, + "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" + } + } + } + }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "requires": { + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true + }, + "fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dev": true, + "requires": { + "pure-rand": "^5.0.1" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "dev": true, + "requires": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "requires": { + "is-callable": "^1.1.3" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, + "get-intrinsic": { + "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", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + } + }, + "glob": { + "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", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "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" + } + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + } + }, + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "dependencies": { + "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" + } + } + } + }, + "globals": { + "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" + } + }, + "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": { + "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" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + } + }, + "graceful-fs": { + "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": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "handlebars": { + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, + "hardhat": { + "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": "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", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "dependencies": { + "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": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "ethereum-cryptography": { + "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.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "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" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "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 + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "requires": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + } + } + }, + "hardhat-exposed": { + "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", + "solidity-ast": "^0.4.25" + } + }, + "hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "requires": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + } + }, + "hardhat-ignore-warnings": { + "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", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "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" + } + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "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 + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true + }, + "highlightjs-solidity": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "htmlparser2": { + "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.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "requires": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + } + }, + "http-cache-semantics": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "dev": true + }, + "http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "requires": { + "@types/node": "^10.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "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": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-id": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz", + "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "requires": { + "punycode": "2.1.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "immutable": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", + "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "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": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "internal-slot": { + "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.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true + }, + "io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "requires": { + "fp-ts": "^1.0.0" + } + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "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.2.0", + "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", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "requires": { + "ci-info": "^3.2.0" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true + }, + "is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, + "requires": { + "lower-case": "^1.1.0" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "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 + }, + "is-port-reachable": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-3.1.0.tgz", + "integrity": "sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "requires": { + "better-path-resolve": "1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, + "requires": { + "upper-case": "^1.1.0" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "js-sdsl": { + "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": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "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", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "keccak": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.3.tgz", + "integrity": "sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ==", + "dev": true, + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + } + }, + "keccak256": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz", + "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==", + "dev": true, + "requires": { + "bn.js": "^5.2.0", + "buffer": "^6.0.3", + "keccak": "^3.0.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 + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "requires": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + } + }, + "level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true + }, + "level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "requires": { + "error-ex": "^1.2.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 + }, + "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" + } + } + } + }, + "load-yaml-file": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "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", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "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", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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" + } + } + } + }, + "loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, + "lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, + "requires": { + "lower-case": "^1.1.2" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true + }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "requires": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true + }, + "meow": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", + "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" + }, + "dependencies": { + "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 + } + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "merkletreejs": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.2.32.tgz", + "integrity": "sha512-TostQBiwYRIwSE5++jGmacu3ODcKAgqb0Y/pnIohXS7sWxh1gCkSptbmF1a43faehRDpcHf7J/kv0Ml2D/zblQ==", + "dev": true, + "requires": { + "bignumber.js": "^9.0.1", + "buffer-reverse": "^1.0.1", + "crypto-js": "^3.1.9-1", + "treeify": "^1.1.0", + "web3-utils": "^1.3.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 + } + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true + }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + } + }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mixme": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/mixme/-/mixme-0.5.9.tgz", + "integrity": "sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "dev": true, + "requires": { + "mkdirp": "*" + } + }, + "mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "requires": { + "obliterator": "^2.0.0" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "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 + }, + "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 + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "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": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "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 + } + } + }, + "mock-fs": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.14.0.tgz", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "dev": true + }, + "module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "dev": true, + "requires": { + "varint": "^5.0.0" + } + }, + "multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, + "nano-base32": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==", + "dev": true + }, + "nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "napi-macros": { + "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": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "requires": { + "lodash": "^4.17.21" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-fetch": { + "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.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": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-2.1.2.tgz", + "integrity": "sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==", + "dev": true, + "requires": { + "shallowequal": "^1.1.0" + } + }, + "nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true + }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + } + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "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": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "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" + } + }, + "object.getownpropertydescriptors": { + "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.2.0", + "es-abstract": "^1.21.2", + "safe-array-concat": "^1.0.0" + } + }, + "obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dev": true, + "requires": { + "http-https": "^1.0.0" + } + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "requires": { + "p-map": "^2.0.0" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "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": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "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": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "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" + } + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "requires": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, + "requires": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==", + "dev": true, + "requires": { + "find-up": "^5.0.0", + "find-yarn-workspace-root2": "1.2.16", + "path-exists": "^4.0.0", + "which-pm": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + } + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "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": { + "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.16.0", + "semver": "^7.3.8", + "solidity-comments-extractor": "^0.0.7" + }, + "dependencies": { + "@solidity-parser/parser": { + "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" + } + } + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "dev": true + }, + "pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "dev": true + }, + "qs": { + "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" + } + }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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 + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "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", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "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 + } + } + }, + "read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + } + }, + "readable-stream": { + "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", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "requires": { + "minimatch": "^3.0.5" + } + }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "dependencies": { + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + } + } + }, + "regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true + }, + "regexp.prototype.flags": { + "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.2.0", + "functions-have-names": "^1.2.3" + } + }, + "req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "requires": { + "req-from": "^2.0.0" + } + }, + "req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + }, + "dependencies": { + "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 + } + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "dev": true, + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "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 + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "requires": { + "lowercase-keys": "^2.0.0" + }, + "dependencies": { + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "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", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "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" + } + } + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "dev": true + }, + "rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "requires": { + "bn.js": "^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 + } + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "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", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + }, + "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" + } + } + } + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "requires": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "semver": { + "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" + }, + "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==", + "dev": true, + "requires": { + "yallist": "^4.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 + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "requires": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "requires": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + } + }, + "sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dev": true, + "requires": { + "buffer": "6.0.3" + }, + "dependencies": { + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + } + } + }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "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" + } + } + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dev": true, + "requires": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + }, + "dependencies": { + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + } + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "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": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.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" + } + }, + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + } + } + }, + "smartwrap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/smartwrap/-/smartwrap-2.0.2.tgz", + "integrity": "sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==", + "dev": true, + "requires": { + "array.prototype.flat": "^1.2.3", + "breakword": "^1.0.5", + "grapheme-splitter": "^1.0.4", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^15.1.0" + }, + "dependencies": { + "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": "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", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.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 + }, + "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 + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + } + } + }, + "snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0" + } + }, + "solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dev": true, + "requires": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "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", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "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" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "requires": { + "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", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + } + } + }, + "solhint": { + "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.16.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": { + "@solidity-parser/parser": { + "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" + } + }, + "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": "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", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "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" + } + }, + "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 + }, + "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": { + "argparse": "^2.0.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "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": { + "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" + } + } + } + }, + "solidity-ast": { + "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": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments/-/solidity-comments-0.0.2.tgz", + "integrity": "sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==", + "dev": true, + "requires": { + "solidity-comments-darwin-arm64": "0.0.2", + "solidity-comments-darwin-x64": "0.0.2", + "solidity-comments-freebsd-x64": "0.0.2", + "solidity-comments-linux-arm64-gnu": "0.0.2", + "solidity-comments-linux-arm64-musl": "0.0.2", + "solidity-comments-linux-x64-gnu": "0.0.2", + "solidity-comments-linux-x64-musl": "0.0.2", + "solidity-comments-win32-arm64-msvc": "0.0.2", + "solidity-comments-win32-ia32-msvc": "0.0.2", + "solidity-comments-win32-x64-msvc": "0.0.2" + } + }, + "solidity-comments-darwin-arm64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-arm64/-/solidity-comments-darwin-arm64-0.0.2.tgz", + "integrity": "sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==", + "dev": true, + "optional": true + }, + "solidity-comments-darwin-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-x64/-/solidity-comments-darwin-x64-0.0.2.tgz", + "integrity": "sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==", + "dev": true, + "optional": true + }, + "solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "solidity-comments-freebsd-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-freebsd-x64/-/solidity-comments-freebsd-x64-0.0.2.tgz", + "integrity": "sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-arm64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-gnu/-/solidity-comments-linux-arm64-gnu-0.0.2.tgz", + "integrity": "sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-arm64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-musl/-/solidity-comments-linux-arm64-musl-0.0.2.tgz", + "integrity": "sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-x64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-gnu/-/solidity-comments-linux-x64-gnu-0.0.2.tgz", + "integrity": "sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==", + "dev": true, + "optional": true + }, + "solidity-comments-linux-x64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-musl/-/solidity-comments-linux-x64-musl-0.0.2.tgz", + "integrity": "sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-arm64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-arm64-msvc/-/solidity-comments-win32-arm64-msvc-0.0.2.tgz", + "integrity": "sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-ia32-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-ia32-msvc/-/solidity-comments-win32-ia32-msvc-0.0.2.tgz", + "integrity": "sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==", + "dev": true, + "optional": true + }, + "solidity-comments-win32-x64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-x64-msvc/-/solidity-comments-win32-x64-msvc-0.0.2.tgz", + "integrity": "sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==", + "dev": true, + "optional": true + }, + "solidity-coverage": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.2.tgz", + "integrity": "sha512-cv2bWb7lOXPE9/SSleDO6czkFiMHgP4NXPj+iW9W7iEKLBk7Cj0AGBiNmGX3V1totl9wjPrT0gHmABZKZt65rQ==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.14.1", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "7.1.2", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "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 + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "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==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", + "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": 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" + } + }, + "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", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz", + "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "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" + } + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "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-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", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "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==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "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" + } + }, + "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": "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" + } + }, + "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" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } + }, + "solidity-docgen": { + "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", + "solidity-ast": "^0.4.38" + } + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "spawndamnit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz", + "integrity": "sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==", + "dev": true, + "requires": { + "cross-spawn": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "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==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "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 + }, + "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" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + } + } + }, + "spdx-correct": { + "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", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "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": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "dependencies": { + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + } + } + }, + "stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "requires": { + "type-fest": "^0.7.1" + }, + "dependencies": { + "type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", + "dev": true + }, + "stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "dev": true, + "requires": { + "mixme": "^0.5.1" + } + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "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", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "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 + }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "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" + } + }, + "swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, + "requires": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + }, + "dependencies": { + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + }, + "p-cancelable": { + "version": "2.1.1", + "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 + } + } + }, + "sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "requires": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + } + }, + "sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "requires": { + "get-port": "^3.1.0" + } + }, + "table": { + "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": "^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": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "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 + }, + "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": "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "requires": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "requires": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + } + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true + }, + "title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, + "requires": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "dependencies": { + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "dev": true + }, + "trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "tty-table": { + "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.3", + "kleur": "^4.1.5", + "smartwrap": "^2.0.2", + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.1", + "yargs": "^17.7.1" + }, + "dependencies": { + "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": "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", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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 + }, + "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": { + "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" + } + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "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", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "undici": { + "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" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, + "upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, + "requires": { + "upper-case": "^1.1.1" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "dev": true + }, + "utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "web3": { + "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.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.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", + "got": "12.1.0", + "swarm-js": "^0.1.40" + } + }, + "web3-core": { + "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.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "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": { + "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.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.9.0", + "web3-utils": "1.9.0" + } + }, + "web3-core-method": { + "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.9.0", + "web3-core-promievent": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-utils": "1.9.0" + } + }, + "web3-core-promievent": { + "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.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.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.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.9.0" + } + }, + "web3-eth": { + "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.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.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.9.0" + } + }, + "web3-eth-accounts": { + "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", + "@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.9.0", + "web3-core-helpers": "1.9.0", + "web3-core-method": "1.9.0", + "web3-utils": "1.9.0" + }, + "dependencies": { + "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-eth-contract": { + "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.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.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.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.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.9.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 + } + } + }, + "web3-eth-personal": { + "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.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.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.9.0", + "web3-core-method": "1.9.0", + "web3-utils": "1.9.0" + } + }, + "web3-providers-http": { + "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.9.0" + } + }, + "web3-providers-ipc": { + "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.9.0" + } + }, + "web3-providers-ws": { + "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.9.0", + "websocket": "^1.0.32" + } + }, + "web3-shh": { + "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.9.0", + "web3-core-method": "1.9.0", + "web3-core-subscriptions": "1.9.0", + "web3-net": "1.9.0" + } + }, + "web3-utils": { + "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", + "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 + } + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dev": true, + "requires": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", + "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", + "dev": true, + "requires": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dev": true, + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "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": "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + }, + "xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "requires": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "requires": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "requires": { + "xhr-request": "^1.1.0" + } + }, + "xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "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", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "dependencies": { + "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 + }, + "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 + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "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" + }, + "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", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "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 + } + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/package.json b/lib/openzeppelin-contracts-v4.9.3/package.json new file mode 100644 index 0000000..5e72e73 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/package.json @@ -0,0 +1,96 @@ +{ + "name": "openzeppelin-solidity", + "description": "Secure Smart Contract library for Solidity", + "version": "4.9.3", + "files": [ + "/contracts/**/*.sol", + "/build/contracts/*.json", + "!/contracts/mocks/**/*" + ], + "bin": { + "openzeppelin-contracts-migrate-imports": "scripts/migrate-imports.js" + }, + "scripts": { + "compile": "hardhat compile", + "coverage": "env COVERAGE=true hardhat coverage", + "docs": "npm run prepare-docs && oz-docs", + "docs:watch": "oz-docs watch contracts docs/templates docs/config.js", + "prepare-docs": "scripts/prepare-docs.sh", + "lint": "npm run lint:js && npm run lint:sol", + "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' --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", + "prepack": "scripts/prepack.sh", + "generate": "scripts/generate/run.js", + "release": "scripts/release/release.sh", + "version": "scripts/release/version.sh", + "test": "hardhat test", + "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 ." + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "security", + "zeppelin" + ], + "author": "OpenZeppelin Community ", + "license": "MIT", + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, + "homepage": "https://openzeppelin.com/contracts/", + "devDependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-truffle5": "^2.0.5", + "@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", + "eth-sig-util": "^3.0.0", + "ethereumjs-util": "^7.0.7", + "ethereumjs-wallet": "^1.0.1", + "glob": "^8.0.3", + "graphlib": "^2.1.8", + "hardhat": "^2.9.1", + "hardhat-exposed": "^0.3.3", + "hardhat-gas-reporter": "^1.0.4", + "hardhat-ignore-warnings": "^0.2.0", + "keccak256": "^1.0.2", + "lodash.startcase": "^4.4.0", + "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", + "semver": "^7.3.5", + "solhint": "^3.3.6", + "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/lib/openzeppelin-contracts-v4.9.3/remappings.txt b/lib/openzeppelin-contracts-v4.9.3/remappings.txt new file mode 100644 index 0000000..2479e3d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/remappings.txt @@ -0,0 +1 @@ +openzeppelin/=contracts/ diff --git a/lib/openzeppelin-contracts-v4.9.3/renovate.json b/lib/openzeppelin-contracts-v4.9.3/renovate.json new file mode 100644 index 0000000..c0b97d8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/renovate.json @@ -0,0 +1,4 @@ +{ + "extends": ["github>OpenZeppelin/configs"], + "labels": ["ignore-changeset"] +} diff --git a/lib/openzeppelin-contracts-v4.9.3/requirements.txt b/lib/openzeppelin-contracts-v4.9.3/requirements.txt new file mode 100644 index 0000000..da3e957 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/requirements.txt @@ -0,0 +1 @@ +certora-cli==3.6.4 diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/checks/compare-layout.js b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/compare-layout.js new file mode 100644 index 0000000..7b7df99 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/compare-layout.js @@ -0,0 +1,19 @@ +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(report.explain()); + process.exitCode = 1; + } + } else { + console.log(`WARNING: ${name} is missing from the current branch`); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/checks/compareGasReports.js b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/compareGasReports.js new file mode 100755 index 0000000..160c8cc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/compareGasReports.js @@ -0,0 +1,243 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const chalk = require('chalk'); +const { argv } = require('yargs') + .env() + .options({ + style: { + type: 'string', + choices: ['shell', 'markdown'], + default: 'shell', + }, + hideEqual: { + type: 'boolean', + default: true, + }, + strictTesting: { + type: 'boolean', + default: false, + }, + }); + +// Deduce base tx cost from the percentage denominator +const BASE_TX_COST = 21000; + +// Utilities +function sum(...args) { + return args.reduce((a, b) => a + b, 0); +} + +function average(...args) { + return sum(...args) / args.length; +} + +function variation(current, previous, offset = 0) { + return { + value: current, + delta: current - previous, + prcnt: (100 * (current - previous)) / (previous - offset), + }; +} + +// Report class +class Report { + // Read report file + static load(filepath) { + return JSON.parse(fs.readFileSync(filepath, 'utf8')); + } + + // Compare two reports + 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'); + } + + const deployments = update.info.deployments + .map(contract => + Object.assign(contract, { previousVersion: ref.info.deployments.find(({ name }) => name === contract.name) }), + ) + .filter(contract => contract.gasData?.length && contract.previousVersion?.gasData?.length) + .flatMap(contract => [ + { + contract: contract.name, + method: '[bytecode length]', + avg: variation(contract.bytecode.length / 2 - 1, contract.previousVersion.bytecode.length / 2 - 1), + }, + { + contract: contract.name, + method: '[construction cost]', + avg: variation( + ...[contract.gasData, contract.previousVersion.gasData].map(x => Math.round(average(...x))), + BASE_TX_COST, + ), + }, + ]) + .sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`)); + + const methods = Object.keys(update.info.methods) + .filter(key => ref.info.methods[key]) + .filter(key => update.info.methods[key].numberOfCalls > 0) + .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, + min: variation(...[update, ref].map(x => Math.min(...x.info.methods[key].gasData)), BASE_TX_COST), + max: variation(...[update, ref].map(x => Math.max(...x.info.methods[key].gasData)), BASE_TX_COST), + avg: variation(...[update, ref].map(x => Math.round(average(...x.info.methods[key].gasData))), BASE_TX_COST), + })) + .sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`)); + + return [] + .concat(deployments, methods) + .filter(row => !opts.hideEqual || row.min?.delta || row.max?.delta || row.avg?.delta); + } +} + +// Display +function center(text, length) { + return text.padStart((text.length + length) / 2).padEnd(length); +} + +function plusSign(num) { + return num > 0 ? '+' : ''; +} + +function formatCellShell(cell) { + const format = chalk[cell?.delta > 0 ? 'red' : cell?.delta < 0 ? 'green' : 'reset']; + return [ + format((!isFinite(cell?.value) ? '-' : cell.value.toString()).padStart(8)), + format((!isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString()).padStart(8)), + format((!isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%').padStart(8)), + ]; +} + +function formatCmpShell(rows) { + const contractLength = Math.max(8, ...rows.map(({ contract }) => contract.length)); + const methodLength = Math.max(7, ...rows.map(({ method }) => method.length)); + + const COLS = [ + { txt: '', length: 0 }, + { txt: 'Contract', length: contractLength }, + { txt: 'Method', length: methodLength }, + { txt: 'Min', length: 30 }, + { txt: 'Max', length: 30 }, + { txt: 'Avg', length: 30 }, + { txt: '', length: 0 }, + ]; + const HEADER = COLS.map(entry => chalk.bold(center(entry.txt, entry.length || 0))) + .join(' | ') + .trim(); + const SEPARATOR = COLS.map(({ length }) => (length > 0 ? '-'.repeat(length + 2) : '')) + .join('|') + .trim(); + + return [ + '', + HEADER, + ...rows.map(entry => + [ + '', + chalk.grey(entry.contract.padEnd(contractLength)), + entry.method.padEnd(methodLength), + ...formatCellShell(entry.min), + ...formatCellShell(entry.max), + ...formatCellShell(entry.avg), + '', + ] + .join(' | ') + .trim(), + ), + '', + ] + .join(`\n${SEPARATOR}\n`) + .trim(); +} + +function alignPattern(align) { + switch (align) { + case 'left': + case undefined: + return ':-'; + case 'right': + return '-:'; + case 'center': + return ':-:'; + } +} + +function trend(value) { + return value > 0 ? ':x:' : value < 0 ? ':heavy_check_mark:' : ':heavy_minus_sign:'; +} + +function formatCellMarkdown(cell) { + return [ + !isFinite(cell?.value) ? '-' : cell.value.toString(), + !isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString(), + !isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%' + trend(cell.delta), + ]; +} + +function formatCmpMarkdown(rows) { + const COLS = [ + { txt: '' }, + { txt: 'Contract', align: 'left' }, + { txt: 'Method', align: 'left' }, + { txt: 'Min', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: 'Max', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: 'Avg', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: '' }, + ]; + const HEADER = COLS.map(entry => entry.txt) + .join(' | ') + .trim(); + const SEPARATOR = COLS.map(entry => (entry.txt ? alignPattern(entry.align) : '')) + .join('|') + .trim(); + + return [ + '# Changes to gas costs', + '', + HEADER, + SEPARATOR, + rows + .map(entry => + [ + '', + entry.contract, + entry.method, + ...formatCellMarkdown(entry.min), + ...formatCellMarkdown(entry.max), + ...formatCellMarkdown(entry.avg), + '', + ] + .join(' | ') + .trim(), + ) + .join('\n'), + '', + ] + .join('\n') + .trim(); +} + +// MAIN +const report = Report.compare(Report.load(argv._[0]), Report.load(argv._[1]), argv); + +switch (argv.style) { + case 'markdown': + console.log(formatCmpMarkdown(report)); + break; + case 'shell': + default: + console.log(formatCmpShell(report)); + break; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/checks/extract-layout.js b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/extract-layout.js new file mode 100644 index 0000000..d0c9cf3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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)))); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/checks/generation.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/generation.sh new file mode 100755 index 0000000..00d609f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/generation.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +npm run generate +git diff -R --exit-code diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/checks/inheritance-ordering.js b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/inheritance-ordering.js new file mode 100755 index 0000000..45c707e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/checks/inheritance-ordering.js @@ -0,0 +1,54 @@ +#!/usr/bin/env node + +const path = require('path'); +const graphlib = require('graphlib'); +const { findAll } = require('solidity-ast/utils'); +const { _: artifacts } = require('yargs').argv; + +for (const artifact of artifacts) { + const { output: solcOutput } = require(path.resolve(__dirname, '../..', artifact)); + + const graph = new graphlib.Graph({ directed: true }); + const names = {}; + const linearized = []; + + for (const source in solcOutput.contracts) { + if (source.includes('/mocks/')) { + continue; + } + + for (const contractDef of findAll('ContractDefinition', solcOutput.sources[source].ast)) { + names[contractDef.id] = contractDef.name; + linearized.push(contractDef.linearizedBaseContracts); + + contractDef.linearizedBaseContracts.forEach((c1, i, contracts) => + contracts.slice(i + 1).forEach(c2 => { + graph.setEdge(c1, c2); + }), + ); + } + } + + /// graphlib.alg.findCycles will not find minimal cycles. + /// We are only interested int cycles of lengths 2 (needs proof) + graph.nodes().forEach((x, i, nodes) => + nodes + .slice(i + 1) + .filter(y => graph.hasEdge(x, y) && graph.hasEdge(y, x)) + .forEach(y => { + console.log(`Conflict between ${names[x]} and ${names[y]} detected in the following dependency chains:`); + linearized + .filter(chain => chain.includes(parseInt(x)) && chain.includes(parseInt(y))) + .forEach(chain => { + const comp = chain.indexOf(parseInt(x)) < chain.indexOf(parseInt(y)) ? '>' : '<'; + console.log(`- ${names[x]} ${comp} ${names[y]} in ${names[chain.find(Boolean)]}`); + // console.log(`- ${names[x]} ${comp} ${names[y]}: ${chain.reverse().map(id => names[id]).join(', ')}`); + }); + process.exitCode = 1; + }), + ); +} + +if (!process.exitCode) { + console.log('Contract ordering is consistent.'); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/gen-nav.js b/lib/openzeppelin-contracts-v4.9.3/scripts/gen-nav.js new file mode 100644 index 0000000..de3d0da --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/gen-nav.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node + +const path = require('path'); +const glob = require('glob'); +const startCase = require('lodash.startcase'); + +const baseDir = process.argv[2]; + +const files = glob.sync(baseDir + '/**/*.adoc').map(f => path.relative(baseDir, f)); + +console.log('.API'); + +function getPageTitle(directory) { + switch (directory) { + case 'metatx': + return 'Meta Transactions'; + case 'common': + return 'Common (Tokens)'; + default: + return startCase(directory); + } +} + +const links = files.map(file => { + const doc = file.replace(baseDir, ''); + const title = path.parse(file).name; + + return { + xref: `* xref:${doc}[${getPageTitle(title)}]`, + title, + }; +}); + +// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20') +const sortedLinks = links.sort(function (a, b) { + return a.title.toLowerCase().localeCompare(b.title.toLowerCase(), undefined, { numeric: true }); +}); + +for (const link of sortedLinks) { + console.log(link.xref); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/generate/format-lines.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/format-lines.js new file mode 100644 index 0000000..fa3d6b1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/format-lines.js @@ -0,0 +1,16 @@ +function formatLines(...lines) { + return [...indentEach(0, lines)].join('\n') + '\n'; +} + +function* indentEach(indent, lines) { + for (const line of lines) { + if (Array.isArray(line)) { + yield* indentEach(indent + 1, line); + } else { + const padding = ' '.repeat(indent); + yield* line.split('\n').map(subline => (subline === '' ? '' : padding + subline)); + } + } +} + +module.exports = formatLines; diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/generate/run.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/run.js new file mode 100755 index 0000000..368b53a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/run.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node + +const cp = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const format = require('./format-lines'); + +function getVersion(path) { + try { + return fs.readFileSync(path, 'utf8').match(/\/\/ OpenZeppelin Contracts \(last updated v[^)]+\)/)[0]; + } catch (err) { + return null; + } +} + +function generateFromTemplate(file, template, outputPrefix = '') { + const script = path.relative(path.join(__dirname, '../..'), __filename); + const input = path.join(path.dirname(script), template); + const output = path.join(outputPrefix, file); + const version = getVersion(output); + const content = format( + '// SPDX-License-Identifier: MIT', + ...(version ? [version + ` (${file})`] : []), + `// This file was procedurally generated from ${input}.`, + '', + require(template), + ); + + 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/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.js new file mode 100644 index 0000000..8c9f1f8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.js @@ -0,0 +1,304 @@ +const format = require('../format-lines'); +const { OPTS, LEGACY_OPTS } = require('./Checkpoints.opts.js'); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.0; + +import "./math/Math.sol"; +import "./math/SafeCast.sol"; + +/** + * @dev This library defines the \`History\` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type \`Checkpoints.History\` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + * + * _Available since v4.5._ + */ +`; + +const types = opts => `\ +struct ${opts.historyTypeName} { + ${opts.checkpointTypeName}[] ${opts.checkpointFieldName}; +} + +struct ${opts.checkpointTypeName} { + ${opts.keyTypeName} ${opts.keyFieldName}; + ${opts.valueTypeName} ${opts.valueFieldName}; +} +`; + +/* eslint-disable max-len */ +const operations = opts => `\ +/** + * @dev Pushes a (\`key\`, \`value\`) pair into a ${opts.historyTypeName} so that it is stored as the checkpoint. + * + * Returns previous value and new value. + */ +function push( + ${opts.historyTypeName} storage self, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) internal returns (${opts.valueTypeName}, ${opts.valueTypeName}) { + return _insert(self.${opts.checkpointFieldName}, key, value); +} + +/** + * @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; + uint256 pos = _lowerBinaryLookup(self.${opts.checkpointFieldName}, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos).${opts.valueFieldName}; +} + +/** + * @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; + 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 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). + */ +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 => `\ +/** + * @dev Returns the value at a given block number. If a checkpoint is not available at that block, the closest one + * before it is returned, or zero otherwise. Because the number returned corresponds to that at the end of the + * block, the requested block number must be in the past, excluding the current block. + */ +function getAtBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) { + require(blockNumber < block.number, "Checkpoints: block not yet mined"); + uint32 key = SafeCast.toUint32(blockNumber); + + uint256 len = self.${opts.checkpointFieldName}.length; + 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 at a given block number. If a checkpoint is not available at that block, the closest one + * before it is returned, or zero otherwise. Similar to {upperLookup} but optimized for the case when the searched + * checkpoint is probably "recent", defined as being among the last sqrt(N) checkpoints where N is the number of + * checkpoints. + */ +function getAtProbablyRecentBlock(${opts.historyTypeName} storage self, uint256 blockNumber) internal view returns (uint256) { + require(blockNumber < block.number, "Checkpoints: block not yet mined"); + uint32 key = SafeCast.toUint32(blockNumber); + + uint256 len = self.${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)._blockNumber) { + 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}; +} + +/** + * @dev Pushes a value onto a History so that it is stored as the checkpoint for the current block. + * + * Returns previous value and new value. + */ +function push(${opts.historyTypeName} storage self, uint256 value) internal returns (uint256, uint256) { + return _insert(self.${opts.checkpointFieldName}, SafeCast.toUint32(block.number), SafeCast.toUint224(value)); +} + +/** + * @dev Pushes a value onto a History, by updating the latest value using binary operation \`op\`. The new value will + * be set to \`op(latest, delta)\`. + * + * Returns previous value and new value. + */ +function push( + ${opts.historyTypeName} storage self, + function(uint256, uint256) view returns (uint256) op, + uint256 delta +) internal returns (uint256, uint256) { + return push(self, op(latest(self), delta)); +} +`; + +const common = opts => `\ +/** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ +function latest(${opts.historyTypeName} storage self) internal view returns (${opts.valueTypeName}) { + uint256 pos = self.${opts.checkpointFieldName}.length; + return pos == 0 ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1).${opts.valueFieldName}; +} + +/** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ +function latestCheckpoint(${opts.historyTypeName} storage self) + internal + view + returns ( + bool exists, + ${opts.keyTypeName} ${opts.keyFieldName}, + ${opts.valueTypeName} ${opts.valueFieldName} + ) +{ + uint256 pos = self.${opts.checkpointFieldName}.length; + if (pos == 0) { + return (false, 0, 0); + } else { + ${opts.checkpointTypeName} memory ckpt = _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1); + return (true, ckpt.${opts.keyFieldName}, ckpt.${opts.valueFieldName}); + } +} + +/** + * @dev Returns the number of checkpoint. + */ +function length(${opts.historyTypeName} storage self) internal view returns (uint256) { + return self.${opts.checkpointFieldName}.length; +} + +/** + * @dev Pushes a (\`key\`, \`value\`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ +function _insert( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) private returns (${opts.valueTypeName}, ${opts.valueTypeName}) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + ${opts.checkpointTypeName} memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + require(last.${opts.keyFieldName} <= key, "Checkpoint: decreasing keys"); + + // Update or push new checkpoint + if (last.${opts.keyFieldName} == key) { + _unsafeAccess(self, pos - 1).${opts.valueFieldName} = value; + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + } + return (last.${opts.valueFieldName}, value); + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + return (0, value); + } +} + +/** + * @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. + */ +function _upperBinaryLookup( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + uint256 low, + uint256 high +) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid).${opts.keyFieldName} > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; +} + +/** + * @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. + */ +function _lowerBinaryLookup( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + uint256 low, + uint256 high +) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid).${opts.keyFieldName} < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; +} + +/** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ +function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos) + private + pure + returns (${opts.checkpointTypeName} storage result) +{ + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } +} +`; +/* eslint-enable max-len */ + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library Checkpoints {', + [ + // Legacy types & functions + types(LEGACY_OPTS), + legacyOperations(LEGACY_OPTS), + common(LEGACY_OPTS), + // New flavors + ...OPTS.flatMap(opts => [types(opts), operations(opts), common(opts)]), + ], + '}', +); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.opts.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.opts.js new file mode 100644 index 0000000..03c5a95 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.t.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.t.js new file mode 100644 index 0000000..b3da933 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/Checkpoints.t.js @@ -0,0 +1,256 @@ +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]; + if (lastKey > 0) { + 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]; + if (lastKey > 0) { + 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/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/EnumerableMap.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/EnumerableMap.js new file mode 100644 index 0000000..2bbb69e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/EnumerableMap.js @@ -0,0 +1,310 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); + +const TYPES = [ + { name: 'UintToUintMap', keyType: 'uint256', valueType: 'uint256' }, + { name: 'UintToAddressMap', keyType: 'uint256', valueType: 'address' }, + { name: 'AddressToUintMap', keyType: 'address', valueType: 'uint256' }, + { name: 'Bytes32ToUintMap', keyType: 'bytes32', valueType: 'uint256' }, +]; + +/* eslint-disable max-len */ +const header = `\ +pragma solidity ^0.8.0; + +import "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[\`mapping\`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * \`\`\` + * + * The following map types are supported: + * + * - \`uint256 -> address\` (\`UintToAddressMap\`) since v3.0.0 + * - \`address -> uint256\` (\`AddressToUintMap\`) since v4.6.0 + * - \`bytes32 -> bytes32\` (\`Bytes32ToBytes32Map\`) since v4.6.0 + * - \`uint256 -> uint256\` (\`UintToUintMap\`) since v4.7.0 + * - \`bytes32 -> uint256\` (\`Bytes32ToUintMap\`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +`; +/* eslint-enable max-len */ + +const defaultMap = () => `\ +// To implement this library for multiple types with as little code +// repetition as possible, we write it in terms of a generic Map type with +// bytes32 keys and values. +// The Map implementation uses private functions, and user-facing +// implementations (such as Uint256ToAddressMap) are just wrappers around +// the underlying Map. +// This means that we can only create new EnumerableMaps for types that fit +// in bytes32. + +struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 => bytes32) _values; +} + +/** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ +function set( + Bytes32ToBytes32Map storage map, + bytes32 key, + bytes32 value +) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); +} + +/** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ +function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); +} + +/** + * @dev Returns the number of key-value pairs in the map. O(1). + */ +function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); +} + +/** + * @dev Returns the key-value pair stored at position \`index\` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); +} + +/** + * @dev Tries to returns the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key"); + return value; +} + +/** + * @dev Same as {get}, with a custom error message when \`key\` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ +function get( + Bytes32ToBytes32Map storage map, + bytes32 key, + string memory errorMessage +) internal view returns (bytes32) { + bytes32 value = map._values[key]; + require(value != 0 || contains(map, key), errorMessage); + return value; +} + +/** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { + return map._keys.values(); +} +`; + +const customMap = ({ name, keyType, valueType }) => `\ +// ${name} + +struct ${name} { + Bytes32ToBytes32Map _inner; +} + +/** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ +function set( + ${name} storage map, + ${keyType} key, + ${valueType} value +) internal returns (bool) { + return set(map._inner, ${toBytes32(keyType, 'key')}, ${toBytes32(valueType, 'value')}); +} + +/** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ +function remove(${name} storage map, ${keyType} key) internal returns (bool) { + return remove(map._inner, ${toBytes32(keyType, 'key')}); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(${name} storage map, ${keyType} key) internal view returns (bool) { + return contains(map._inner, ${toBytes32(keyType, 'key')}); +} + +/** + * @dev Returns the number of elements in the map. O(1). + */ +function length(${name} storage map) internal view returns (uint256) { + return length(map._inner); +} + +/** + * @dev Returns the element stored at position \`index\` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(${name} storage map, uint256 index) internal view returns (${keyType}, ${valueType}) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (${fromBytes32(keyType, 'key')}, ${fromBytes32(valueType, 'value')}); +} + +/** + * @dev Tries to returns the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(${name} storage map, ${keyType} key) internal view returns (bool, ${valueType}) { + (bool success, bytes32 value) = tryGet(map._inner, ${toBytes32(keyType, 'key')}); + return (success, ${fromBytes32(valueType, 'value')}); +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(${name} storage map, ${keyType} key) internal view returns (${valueType}) { + return ${fromBytes32(valueType, `get(map._inner, ${toBytes32(keyType, 'key')})`)}; +} + +/** + * @dev Same as {get}, with a custom error message when \`key\` is not in the map. + * + * CAUTION: This function is deprecated because it requires allocating memory for the error + * message unnecessarily. For custom revert reasons use {tryGet}. + */ +function get( + ${name} storage map, + ${keyType} key, + string memory errorMessage +) internal view returns (${valueType}) { + return ${fromBytes32(valueType, `get(map._inner, ${toBytes32(keyType, 'key')}, errorMessage)`)}; +} + +/** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function keys(${name} storage map) internal view returns (${keyType}[] memory) { + bytes32[] memory store = keys(map._inner); + ${keyType}[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableMap {', + [ + 'using EnumerableSet for EnumerableSet.Bytes32Set;', + '', + defaultMap(), + TYPES.map(details => customMap(details).trimEnd()).join('\n\n'), + ], + '}', +); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/EnumerableSet.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/EnumerableSet.js new file mode 100644 index 0000000..2b6a9c6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/EnumerableSet.js @@ -0,0 +1,250 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); + +const TYPES = [ + { name: 'Bytes32Set', type: 'bytes32' }, + { name: 'AddressSet', type: 'address' }, + { name: 'UintSet', type: 'uint256' }, +]; + +/* eslint-disable max-len */ +const header = `\ +pragma solidity ^0.8.0; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * \`\`\` + * + * As of v3.3.0, sets of type \`bytes32\` (\`Bytes32Set\`), \`address\` (\`AddressSet\`) + * and \`uint256\` (\`UintSet\`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +`; +/* eslint-enable max-len */ + +const defaultSet = () => `\ +// To implement this library for multiple types with as little code +// repetition as possible, we write it in terms of a generic Set type with +// bytes32 values. +// The Set implementation uses private functions, and user-facing +// implementations (such as AddressSet) are just wrappers around the +// underlying Set. +// This means that we can only create new EnumerableSets for types that fit +// in bytes32. + +struct Set { + // Storage of set values + bytes32[] _values; + // Position of the value in the \`values\` array, plus 1 because index 0 + // means a value is not in the set. + mapping(bytes32 => uint256) _indexes; +} + +/** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ +function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._indexes[value] = set._values.length; + return true; + } else { + return false; + } +} + +/** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ +function _remove(Set storage set, bytes32 value) private returns (bool) { + // We read and store the value's index to prevent multiple reads from the same storage slot + uint256 valueIndex = set._indexes[value]; + + if (valueIndex != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 toDeleteIndex = valueIndex - 1; + uint256 lastIndex = set._values.length - 1; + + if (lastIndex != toDeleteIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the last value to the index where the value to delete is + set._values[toDeleteIndex] = lastValue; + // Update the index for the moved value + set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the index for the deleted slot + delete set._indexes[value]; + + return true; + } else { + return false; + } +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._indexes[value] != 0; +} + +/** + * @dev Returns the number of values on the set. O(1). + */ +function _length(Set storage set) private view returns (uint256) { + return set._values.length; +} + +/** + * @dev Returns the value stored at position \`index\` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; +} + +/** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; +} +`; + +const customSet = ({ name, type }) => `\ +// ${name} + +struct ${name} { + Set _inner; +} + +/** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ +function add(${name} storage set, ${type} value) internal returns (bool) { + return _add(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ +function remove(${name} storage set, ${type} value) internal returns (bool) { + return _remove(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function contains(${name} storage set, ${type} value) internal view returns (bool) { + return _contains(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Returns the number of values in the set. O(1). + */ +function length(${name} storage set) internal view returns (uint256) { + return _length(set._inner); +} + +/** + * @dev Returns the value stored at position \`index\` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(${name} storage set, uint256 index) internal view returns (${type}) { + return ${fromBytes32(type, '_at(set._inner, index)')}; +} + +/** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function values(${name} storage set) internal view returns (${type}[] memory) { + bytes32[] memory store = _values(set._inner); + ${type}[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableSet {', + [defaultSet(), TYPES.map(details => customSet(details).trimEnd()).join('\n\n')], + '}', +); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/SafeCast.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/SafeCast.js new file mode 100644 index 0000000..3e2b148 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/SafeCast.js @@ -0,0 +1,163 @@ +const assert = require('assert'); +const format = require('../format-lines'); +const { range } = require('../../helpers'); + +const LENGTHS = range(8, 256, 8).reverse(); // 248 → 8 (in steps of 8) + +// Returns the version of OpenZeppelin Contracts in which a particular function was introduced. +// This is used in the docs for each function. +const version = (selector, length) => { + switch (selector) { + case 'toUint(uint)': { + switch (length) { + case 8: + case 16: + case 32: + case 64: + case 128: + return '2.5'; + case 96: + case 224: + return '4.2'; + default: + assert(LENGTHS.includes(length)); + return '4.7'; + } + } + case 'toInt(int)': { + switch (length) { + case 8: + case 16: + case 32: + case 64: + case 128: + return '3.1'; + default: + assert(LENGTHS.includes(length)); + return '4.7'; + } + } + case 'toUint(int)': { + switch (length) { + case 256: + return '3.0'; + default: + assert(false); + return; + } + } + case 'toInt(uint)': { + switch (length) { + case 256: + return '3.0'; + default: + assert(false); + return; + } + } + default: + assert(false); + } +}; + +const header = `\ +pragma solidity ^0.8.0; + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. \`SafeCast\` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + * + * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing + * all math on \`uint256\` and \`int256\` and then downcasting. + */ +`; + +const toUintDownCast = length => `\ +/** + * @dev Returns the downcasted uint${length} from uint256, reverting on + * overflow (when the input is greater than largest uint${length}). + * + * Counterpart to Solidity's \`uint${length}\` operator. + * + * Requirements: + * + * - input must fit into ${length} bits + * + * _Available since v${version('toUint(uint)', length)}._ + */ +function toUint${length}(uint256 value) internal pure returns (uint${length}) { + require(value <= type(uint${length}).max, "SafeCast: value doesn't fit in ${length} bits"); + return uint${length}(value); +} +`; + +/* eslint-disable max-len */ +const toIntDownCast = length => `\ +/** + * @dev Returns the downcasted int${length} from int256, reverting on + * overflow (when the input is less than smallest int${length} or + * greater than largest int${length}). + * + * Counterpart to Solidity's \`int${length}\` operator. + * + * Requirements: + * + * - input must fit into ${length} bits + * + * _Available since v${version('toInt(int)', length)}._ + */ +function toInt${length}(int256 value) internal pure returns (int${length} downcasted) { + downcasted = int${length}(value); + require(downcasted == value, "SafeCast: value doesn't fit in ${length} bits"); +} +`; +/* eslint-enable max-len */ + +const toInt = length => `\ +/** + * @dev Converts an unsigned uint${length} into a signed int${length}. + * + * Requirements: + * + * - input must be less than or equal to maxInt${length}. + * + * _Available since v${version('toInt(uint)', length)}._ + */ +function toInt${length}(uint${length} value) internal pure returns (int${length}) { + // Note: Unsafe cast below is okay because \`type(int${length}).max\` is guaranteed to be positive + require(value <= uint${length}(type(int${length}).max), "SafeCast: value doesn't fit in an int${length}"); + return int${length}(value); +} +`; + +const toUint = length => `\ +/** + * @dev Converts a signed int${length} into an unsigned uint${length}. + * + * Requirements: + * + * - input must be greater than or equal to 0. + * + * _Available since v${version('toUint(int)', length)}._ + */ +function toUint${length}(int${length} value) internal pure returns (uint${length}) { + require(value >= 0, "SafeCast: value must be positive"); + return uint${length}(value); +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library SafeCast {', + [...LENGTHS.map(toUintDownCast), toUint(256), ...LENGTHS.map(toIntDownCast), toInt(256)], + '}', +); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/StorageSlot.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/StorageSlot.js new file mode 100644 index 0000000..69fa7cc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/conversion.js b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/conversion.js new file mode 100644 index 0000000..9221f7c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/generate/templates/conversion.js @@ -0,0 +1,30 @@ +function toBytes32(type, value) { + switch (type) { + case 'bytes32': + return value; + case 'uint256': + return `bytes32(${value})`; + case 'address': + return `bytes32(uint256(uint160(${value})))`; + default: + throw new Error(`Conversion from ${type} to bytes32 not supported`); + } +} + +function fromBytes32(type, value) { + switch (type) { + case 'bytes32': + return value; + case 'uint256': + return `uint256(${value})`; + case 'address': + return `address(uint160(uint256(${value})))`; + default: + throw new Error(`Conversion from bytes32 to ${type} not supported`); + } +} + +module.exports = { + toBytes32, + fromBytes32, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/git-user-config.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/git-user-config.sh new file mode 100644 index 0000000..e7b81c3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/git-user-config.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail -x + +git config user.name 'github-actions' +git config user.email '41898282+github-actions[bot]@users.noreply.github.com' diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/helpers.js b/lib/openzeppelin-contracts-v4.9.3/scripts/helpers.js new file mode 100644 index 0000000..fb9aad4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/helpers.js @@ -0,0 +1,37 @@ +function chunk(array, size = 1) { + return Array.range(Math.ceil(array.length / size)).map(i => array.slice(i * size, i * size + size)); +} + +function range(start, stop = undefined, step = 1) { + if (!stop) { + stop = start; + start = 0; + } + return start < stop + ? Array(Math.ceil((stop - start) / step)) + .fill() + .map((_, i) => start + i * step) + : []; +} + +function unique(array, op = x => x) { + return array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i); +} + +function zip(...args) { + return Array(Math.max(...args.map(arg => arg.length))) + .fill(null) + .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/lib/openzeppelin-contracts-v4.9.3/scripts/migrate-imports.js b/lib/openzeppelin-contracts-v4.9.3/scripts/migrate-imports.js new file mode 100755 index 0000000..f604419 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/migrate-imports.js @@ -0,0 +1,180 @@ +#!/usr/bin/env node + +const { promises: fs } = require('fs'); +const path = require('path'); + +const pathUpdates = { + // 'access/AccessControl.sol': undefined, + // 'access/Ownable.sol': undefined, + 'access/TimelockController.sol': 'governance/TimelockController.sol', + 'cryptography/ECDSA.sol': 'utils/cryptography/ECDSA.sol', + 'cryptography/MerkleProof.sol': 'utils/cryptography/MerkleProof.sol', + 'drafts/EIP712.sol': 'utils/cryptography/EIP712.sol', + 'drafts/ERC20Permit.sol': 'token/ERC20/extensions/ERC20Permit.sol', + 'drafts/IERC20Permit.sol': 'token/ERC20/extensions/IERC20Permit.sol', + 'GSN/Context.sol': 'utils/Context.sol', + // 'GSN/GSNRecipientERC20Fee.sol': undefined, + // 'GSN/GSNRecipientSignature.sol': undefined, + // 'GSN/GSNRecipient.sol': undefined, + // 'GSN/IRelayHub.sol': undefined, + // 'GSN/IRelayRecipient.sol': undefined, + 'introspection/ERC165Checker.sol': 'utils/introspection/ERC165Checker.sol', + 'introspection/ERC165.sol': 'utils/introspection/ERC165.sol', + 'introspection/ERC1820Implementer.sol': 'utils/introspection/ERC1820Implementer.sol', + 'introspection/IERC165.sol': 'utils/introspection/IERC165.sol', + 'introspection/IERC1820Implementer.sol': 'utils/introspection/IERC1820Implementer.sol', + 'introspection/IERC1820Registry.sol': 'utils/introspection/IERC1820Registry.sol', + 'math/Math.sol': 'utils/math/Math.sol', + 'math/SafeMath.sol': 'utils/math/SafeMath.sol', + 'math/SignedSafeMath.sol': 'utils/math/SignedSafeMath.sol', + 'payment/escrow/ConditionalEscrow.sol': 'utils/escrow/ConditionalEscrow.sol', + 'payment/escrow/Escrow.sol': 'utils/escrow/Escrow.sol', + 'payment/escrow/RefundEscrow.sol': 'utils/escrow/RefundEscrow.sol', + 'payment/PaymentSplitter.sol': 'finance/PaymentSplitter.sol', + 'utils/PaymentSplitter.sol': 'finance/PaymentSplitter.sol', + 'payment/PullPayment.sol': 'security/PullPayment.sol', + 'presets/ERC1155PresetMinterPauser.sol': 'token/ERC1155/presets/ERC1155PresetMinterPauser.sol', + 'presets/ERC20PresetFixedSupply.sol': 'token/ERC20/presets/ERC20PresetFixedSupply.sol', + 'presets/ERC20PresetMinterPauser.sol': 'token/ERC20/presets/ERC20PresetMinterPauser.sol', + 'presets/ERC721PresetMinterPauserAutoId.sol': 'token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol', + 'presets/ERC777PresetFixedSupply.sol': 'token/ERC777/presets/ERC777PresetFixedSupply.sol', + 'proxy/BeaconProxy.sol': 'proxy/beacon/BeaconProxy.sol', + // 'proxy/Clones.sol': undefined, + 'proxy/IBeacon.sol': 'proxy/beacon/IBeacon.sol', + 'proxy/Initializable.sol': 'proxy/utils/Initializable.sol', + 'utils/Initializable.sol': 'proxy/utils/Initializable.sol', + 'proxy/ProxyAdmin.sol': 'proxy/transparent/ProxyAdmin.sol', + // 'proxy/Proxy.sol': undefined, + 'proxy/TransparentUpgradeableProxy.sol': 'proxy/transparent/TransparentUpgradeableProxy.sol', + 'proxy/UpgradeableBeacon.sol': 'proxy/beacon/UpgradeableBeacon.sol', + 'proxy/UpgradeableProxy.sol': 'proxy/ERC1967/ERC1967Proxy.sol', + 'token/ERC1155/ERC1155Burnable.sol': 'token/ERC1155/extensions/ERC1155Burnable.sol', + 'token/ERC1155/ERC1155Holder.sol': 'token/ERC1155/utils/ERC1155Holder.sol', + 'token/ERC1155/ERC1155Pausable.sol': 'token/ERC1155/extensions/ERC1155Pausable.sol', + 'token/ERC1155/ERC1155Receiver.sol': 'token/ERC1155/utils/ERC1155Receiver.sol', + // 'token/ERC1155/ERC1155.sol': undefined, + 'token/ERC1155/IERC1155MetadataURI.sol': 'token/ERC1155/extensions/IERC1155MetadataURI.sol', + // 'token/ERC1155/IERC1155Receiver.sol': undefined, + // 'token/ERC1155/IERC1155.sol': undefined, + 'token/ERC20/ERC20Burnable.sol': 'token/ERC20/extensions/ERC20Burnable.sol', + 'token/ERC20/ERC20Capped.sol': 'token/ERC20/extensions/ERC20Capped.sol', + 'token/ERC20/ERC20Pausable.sol': 'token/ERC20/extensions/ERC20Pausable.sol', + 'token/ERC20/ERC20Snapshot.sol': 'token/ERC20/extensions/ERC20Snapshot.sol', + // 'token/ERC20/ERC20.sol': undefined, + // 'token/ERC20/IERC20.sol': undefined, + 'token/ERC20/SafeERC20.sol': 'token/ERC20/utils/SafeERC20.sol', + 'token/ERC20/TokenTimelock.sol': 'token/ERC20/utils/TokenTimelock.sol', + 'token/ERC721/ERC721Burnable.sol': 'token/ERC721/extensions/ERC721Burnable.sol', + 'token/ERC721/ERC721Holder.sol': 'token/ERC721/utils/ERC721Holder.sol', + 'token/ERC721/ERC721Pausable.sol': 'token/ERC721/extensions/ERC721Pausable.sol', + // 'token/ERC721/ERC721.sol': undefined, + 'token/ERC721/IERC721Enumerable.sol': 'token/ERC721/extensions/IERC721Enumerable.sol', + 'token/ERC721/IERC721Metadata.sol': 'token/ERC721/extensions/IERC721Metadata.sol', + // 'token/ERC721/IERC721Receiver.sol': undefined, + // 'token/ERC721/IERC721.sol': undefined, + // 'token/ERC777/ERC777.sol': undefined, + // 'token/ERC777/IERC777Recipient.sol': undefined, + // 'token/ERC777/IERC777Sender.sol': undefined, + // 'token/ERC777/IERC777.sol': undefined, + // 'utils/Address.sol': undefined, + // 'utils/Arrays.sol': undefined, + // 'utils/Context.sol': undefined, + // 'utils/Counters.sol': undefined, + // 'utils/Create2.sol': undefined, + 'utils/EnumerableMap.sol': 'utils/structs/EnumerableMap.sol', + 'utils/EnumerableSet.sol': 'utils/structs/EnumerableSet.sol', + 'utils/Pausable.sol': 'security/Pausable.sol', + 'utils/ReentrancyGuard.sol': 'security/ReentrancyGuard.sol', + 'utils/SafeCast.sol': 'utils/math/SafeCast.sol', + // 'utils/Strings.sol': undefined, + 'utils/cryptography/draft-EIP712.sol': 'utils/cryptography/EIP712.sol', + 'token/ERC20/extensions/draft-ERC20Permit.sol': 'token/ERC20/extensions/ERC20Permit.sol', + 'token/ERC20/extensions/draft-IERC20Permit.sol': 'token/ERC20/extensions/IERC20Permit.sol', +}; + +async function main(paths = ['contracts']) { + const files = await listFilesRecursively(paths, /\.sol$/); + + const updatedFiles = []; + for (const file of files) { + if (await updateFile(file, updateImportPaths)) { + updatedFiles.push(file); + } + } + + if (updatedFiles.length > 0) { + console.log(`${updatedFiles.length} file(s) were updated`); + for (const c of updatedFiles) { + console.log('-', c); + } + } else { + console.log('No files were updated'); + } +} + +async function listFilesRecursively(paths, filter) { + const queue = paths; + const files = []; + + while (queue.length > 0) { + const top = queue.shift(); + const stat = await fs.stat(top); + if (stat.isFile()) { + if (top.match(filter)) { + files.push(top); + } + } else if (stat.isDirectory()) { + for (const name of await fs.readdir(top)) { + queue.push(path.join(top, name)); + } + } + } + + return files; +} + +async function updateFile(file, update) { + const content = await fs.readFile(file, 'utf8'); + const updatedContent = update(content); + if (updatedContent !== content) { + await fs.writeFile(file, updatedContent); + return true; + } else { + return false; + } +} + +function updateImportPaths(source) { + for (const [oldPath, newPath] of Object.entries(pathUpdates)) { + source = source.replace( + path.join('@openzeppelin/contracts', oldPath), + path.join('@openzeppelin/contracts', newPath), + ); + source = source.replace( + path.join('@openzeppelin/contracts-upgradeable', getUpgradeablePath(oldPath)), + path.join('@openzeppelin/contracts-upgradeable', getUpgradeablePath(newPath)), + ); + } + + return source; +} + +function getUpgradeablePath(file) { + const { dir, name, ext } = path.parse(file); + const upgradeableName = name + 'Upgradeable'; + return path.format({ dir, ext, name: upgradeableName }); +} + +module.exports = { + pathUpdates, + updateImportPaths, + getUpgradeablePath, +}; + +if (require.main === module) { + const args = process.argv.length > 2 ? process.argv.slice(2) : undefined; + main(args).catch(e => { + console.error(e); + process.exit(1); + }); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/prepack.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/prepack.sh new file mode 100755 index 0000000..6f1bd4c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/prepack.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -euo pipefail +shopt -s globstar + +# cross platform `mkdir -p` +node -e 'fs.mkdirSync("build/contracts", { recursive: true })' + +cp artifacts/contracts/**/*.json build/contracts +rm build/contracts/*.dbg.json + +node scripts/remove-ignored-artifacts.js diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/prepare-contracts-package.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/prepare-contracts-package.sh new file mode 100755 index 0000000..3f62fd4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/prepare-contracts-package.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +# cd to the root of the repo +cd "$(git rev-parse --show-toplevel)" + +# avoids re-compilation during publishing of both packages +if [[ ! -v ALREADY_COMPILED ]]; then + npm run clean + npm run prepare + npm run prepack +fi + +cp README.md contracts/ +mkdir contracts/build contracts/build/contracts +cp -r build/contracts/*.json contracts/build/contracts diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/prepare-docs.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/prepare-docs.sh new file mode 100755 index 0000000..d1317b0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/prepare-docs.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail +shopt -s globstar + +OUTDIR="$(node -p 'require("./docs/config.js").outputDir')" + +if [ ! -d node_modules ]; then + npm ci +fi + +rm -rf "$OUTDIR" + +hardhat docgen + +# copy examples and adjust imports +examples_source_dir="contracts/mocks/docs" +examples_target_dir="docs/modules/api/examples" + +for f in "$examples_source_dir"/**/*.sol; do + name="${f/#"$examples_source_dir/"/}" + mkdir -p "$examples_target_dir/$(dirname "$name")" + sed -Ee '/^import/s|"(\.\./)+|"@openzeppelin/contracts/|' "$f" > "$examples_target_dir/$name" +done + +node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc" diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/prepare.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/prepare.sh new file mode 100755 index 0000000..7014a70 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/prepare.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [ "${SKIP_COMPILE:-}" == true ]; then + exit +fi + +npm run clean +env COMPILE_MODE=production npm run compile diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/format-changelog.js b/lib/openzeppelin-contracts-v4.9.3/scripts/release/format-changelog.js new file mode 100755 index 0000000..b8bcc8c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/format-changelog.js @@ -0,0 +1,33 @@ +#!/usr/bin/env node + +// Adjusts the format of the changelog that changesets generates. +// This is run automatically when npm version is run. + +const fs = require('fs'); +const changelog = fs.readFileSync('CHANGELOG.md', 'utf8'); + +// Groups: +// - 1: Pull Request Number and URL +// - 2: Changeset entry +const RELEASE_LINE_REGEX = /^- (\[#.*?\]\(.*?\))?.*?! - (.*)$/gm; + +// Captures vX.Y.Z or vX.Y.Z-rc.W +const VERSION_TITLE_REGEX = /^## (\d+\.\d+\.\d+(-rc\.\d+)?)$/gm; + +const isPrerelease = process.env.PRERELEASE === 'true'; + +const formatted = changelog + // Remove titles + .replace(/^### Major Changes\n\n/gm, '') + .replace(/^### Minor Changes\n\n/gm, '') + .replace(/^### Patch Changes\n\n/gm, '') + // Remove extra whitespace between items + .replace(/^(- \[.*\n)\n(?=-)/gm, '$1') + // Format each release line + .replace(RELEASE_LINE_REGEX, (_, pr, entry) => (pr ? `- ${entry} (${pr})` : `- ${entry}`)) + // Add date to new version + .replace(VERSION_TITLE_REGEX, `\n## $1 (${new Date().toISOString().split('T')[0]})`) + // Conditionally allow vX.Y.Z.rc-.W sections only in prerelease + .replace(/^## \d\.\d\.\d-rc\S+[^]+?(?=^#)/gm, section => (isPrerelease ? section : '')); + +fs.writeFileSync('CHANGELOG.md', formatted); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/synchronize-versions.js b/lib/openzeppelin-contracts-v4.9.3/scripts/release/synchronize-versions.js new file mode 100755 index 0000000..15aa259 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/synchronize-versions.js @@ -0,0 +1,15 @@ +#!/usr/bin/env node + +// Synchronizes the version in contracts/package.json with the one in package.json. +// This is run automatically when npm version is run. + +const fs = require('fs'); + +setVersion('package.json', 'contracts/package.json'); + +function setVersion(from, to) { + const fromJson = JSON.parse(fs.readFileSync(from)); + const toJson = JSON.parse(fs.readFileSync(to)); + toJson.version = fromJson.version; + fs.writeFileSync(to, JSON.stringify(toJson, null, 2) + '\n'); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/update-comment.js b/lib/openzeppelin-contracts-v4.9.3/scripts/release/update-comment.js new file mode 100755 index 0000000..9d6df26 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/update-comment.js @@ -0,0 +1,34 @@ +#!/usr/bin/env node +const fs = require('fs'); +const proc = require('child_process'); +const semver = require('semver'); +const run = (cmd, ...args) => proc.execFileSync(cmd, args, { encoding: 'utf8' }).trim(); + +const gitStatus = run('git', 'status', '--porcelain', '-uno', 'contracts/**/*.sol'); +if (gitStatus.length > 0) { + console.error('Contracts directory is not clean'); + process.exit(1); +} + +const { version } = require('../../package.json'); + +// Get latest tag according to semver. +const [tag] = run('git', 'tag') + .split(/\r?\n/) + .filter(semver.coerce) // check version can be processed + .filter(v => semver.satisfies(v, `< ${version}`)) // ignores prereleases unless currently a prerelease + .sort(semver.rcompare); + +// Ordering tag → HEAD is important here. +const files = run('git', 'diff', tag, 'HEAD', '--name-only', 'contracts/**/*.sol') + .split(/\r?\n/) + .filter(file => file && !file.match(/mock/i) && fs.existsSync(file)); + +for (const file of files) { + const current = fs.readFileSync(file, 'utf8'); + const updated = current.replace( + /(\/\/ SPDX-License-Identifier:.*)$(\n\/\/ OpenZeppelin Contracts .*$)?/m, + `$1\n// OpenZeppelin Contracts (last updated v${version}) (${file.replace('contracts/', '')})`, + ); + fs.writeFileSync(file, updated); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/version.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/release/version.sh new file mode 100755 index 0000000..7b0ddea --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/version.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euo pipefail + +changeset version + +scripts/release/format-changelog.js +scripts/release/synchronize-versions.js +scripts/release/update-comment.js + +oz-docs update-version diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/exit-prerelease.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/exit-prerelease.sh new file mode 100644 index 0000000..bcf9b9a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/exit-prerelease.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +npx changeset pre exit rc +git add . +git commit -m "Exit release candidate" +git push origin diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/github-release.js b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/github-release.js new file mode 100644 index 0000000..92a47d9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/github-release.js @@ -0,0 +1,47 @@ +const { readFileSync } = require('fs'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ github, context }) => { + const changelog = readFileSync('CHANGELOG.md', 'utf8'); + + await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `v${version}`, + body: extractSection(changelog, version), + prerelease: process.env.PRERELEASE === 'true', + }); +}; + +// From https://github.com/frangio/extract-changelog/blob/master/src/utils/word-regexp.ts +function makeWordRegExp(word) { + const start = word.length > 0 && /\b/.test(word[0]) ? '\\b' : ''; + const end = word.length > 0 && /\b/.test(word[word.length - 1]) ? '\\b' : ''; + return new RegExp(start + [...word].map(c => (/[a-z0-9]/i.test(c) ? c : '\\' + c)).join('') + end); +} + +// From https://github.com/frangio/extract-changelog/blob/master/src/core.ts +function extractSection(document, wantedHeading) { + // ATX Headings as defined in GitHub Flavored Markdown (https://github.github.com/gfm/#atx-headings) + const heading = /^ {0,3}(?#{1,6})(?: [ \t\v\f]*(?.*?)[ \t\v\f]*)?(?:[\n\r]+|$)/gm; + + const wantedHeadingRe = makeWordRegExp(wantedHeading); + + let start, end; + + for (const m of document.matchAll(heading)) { + if (!start) { + if (m.groups.text.search(wantedHeadingRe) === 0) { + start = m; + } + } else if (m.groups.lead.length <= start.groups.lead.length) { + end = m; + break; + } + } + + if (start) { + return document.slice(start.index + start[0].length, end?.index); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/integrity-check.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/integrity-check.sh new file mode 100644 index 0000000..86e99f9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/pack.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/pack.sh new file mode 100644 index 0000000..ce30712 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/pack.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +dist_tag() { + PACKAGE_JSON_NAME="$(jq -r .name ./package.json)" + LATEST_NPM_VERSION="$(npm info "$PACKAGE_JSON_NAME" version)" + PACKAGE_JSON_VERSION="$(jq -r .version ./package.json)" + + if [ "$PRERELEASE" = "true" ]; then + echo "next" + elif npx semver -r ">$LATEST_NPM_VERSION" "$PACKAGE_JSON_VERSION" > /dev/null; then + echo "latest" + else + # This is a patch for an older version + # npm can't publish without a tag + echo "tmp" + fi +} + +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/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/publish.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/publish.sh new file mode 100644 index 0000000..41a9975 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/publish.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Intentionally escape $ to avoid interpolation and writing the token to disk +echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > .npmrc + +# Actual publish +npm publish "$TARBALL" --tag "$TAG" + +delete_tag() { + PACKAGE_JSON_NAME="$(tar xfO "$TARBALL" package/package.json | jq -r .name)" + npm dist-tag rm "$PACKAGE_JSON_NAME" "$1" +} + +if [ "$TAG" = tmp ]; then + delete_tag "$TAG" +elif [ "$TAG" = latest ]; then + delete_tag next +fi diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/rerun.js b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/rerun.js new file mode 100644 index 0000000..f48ce6e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/rerun.js @@ -0,0 +1,7 @@ +module.exports = ({ github, context }) => + github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release-cycle.yml', + ref: process.env.REF || process.env.GITHUB_REF_NAME, + }); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/set-changesets-pr-title.js b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/set-changesets-pr-title.js new file mode 100644 index 0000000..59b03b2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/set-changesets-pr-title.js @@ -0,0 +1,17 @@ +const { coerce, inc, rsort } = require('semver'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ core }) => { + // Variables not in the context + const refName = process.env.GITHUB_REF_NAME; + + // Compare package.json version's next patch vs. first version patch + // A recently opened branch will give the next patch for the previous minor + // So, we get the max against the patch 0 of the release branch's version + const branchPatch0 = coerce(refName.replace('release-v', '')).version; + const packageJsonNextPatch = inc(version, 'patch'); + const [nextVersion] = rsort([branchPatch0, packageJsonNextPatch], false); + + core.exportVariable('TITLE', `Release v${nextVersion}`); +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/start.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/start.sh new file mode 100644 index 0000000..7683ec5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/start.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Set changeset status location +# This is needed because `changeset status --output` only works with relative routes +CHANGESETS_STATUS_JSON="$(realpath --relative-to=. "$RUNNER_TEMP/status.json")" + +# Save changeset status to temp file +npx changeset status --output="$CHANGESETS_STATUS_JSON" + +# Defensive assertion. SHOULD NOT BE REACHED +if [ "$(jq '.releases | length' "$CHANGESETS_STATUS_JSON")" != 1 ]; then + echo "::error file=$CHANGESETS_STATUS_JSON::The status doesn't contain only 1 release" + exit 1; +fi; + +# Create branch +BRANCH_SUFFIX="$(jq -r '.releases[0].newVersion | gsub("\\.\\d+$"; "")' $CHANGESETS_STATUS_JSON)" +RELEASE_BRANCH="release-v$BRANCH_SUFFIX" +git checkout -b "$RELEASE_BRANCH" + +# Output branch +echo "branch=$RELEASE_BRANCH" >> $GITHUB_OUTPUT + +# Enter in prerelease state +npx changeset pre enter rc +git add . +git commit -m "Start release candidate" + +# Push 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 diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/state.js b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/state.js new file mode 100644 index 0000000..5cfaafb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/release/workflow/state.js @@ -0,0 +1,112 @@ +const { readPreState } = require('@changesets/pre'); +const { default: readChangesets } = require('@changesets/read'); +const { join } = require('path'); +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 }); + + function setOutput(key, value) { + core.info(`State ${key} = ${value}`); + core.setOutput(key, value); + } + + // Jobs to trigger + setOutput('start', shouldRunStart(state)); + setOutput('promote', shouldRunPromote(state)); + setOutput('changesets', shouldRunChangesets(state)); + setOutput('publish', shouldRunPublish(state)); + setOutput('merge', shouldRunMerge(state)); + + // Global Variables + setOutput('is_prerelease', state.prerelease); +}; + +function shouldRunStart({ isMaster, isWorkflowDispatch, botRun }) { + return isMaster && isWorkflowDispatch && !botRun; +} + +function shouldRunPromote({ isReleaseBranch, isWorkflowDispatch, botRun }) { + return isReleaseBranch && isWorkflowDispatch && !botRun; +} + +function shouldRunChangesets({ isReleaseBranch, isPush, isWorkflowDispatch, botRun }) { + return (isReleaseBranch && isPush) || (isReleaseBranch && isWorkflowDispatch && botRun); +} + +function shouldRunPublish({ isReleaseBranch, isPush, hasPendingChangesets, isPublishedOnNpm }) { + return isReleaseBranch && isPush && !hasPendingChangesets && !isPublishedOnNpm; +} + +function shouldRunMerge({ + isReleaseBranch, + isPush, + prerelease, + isCurrentFinalVersion, + hasPendingChangesets, + prBackExists, +}) { + return isReleaseBranch && isPush && !prerelease && isCurrentFinalVersion && !hasPendingChangesets && prBackExists; +} + +async function getState({ github, context, core }) { + // Variables not in the context + const refName = process.env.GITHUB_REF_NAME; + const botRun = process.env.TRIGGERING_ACTOR === 'github-actions[bot]'; + + const { changesets, preState } = await readChangesetState(); + + // Static vars + const state = { + refName, + hasPendingChangesets: changesets.length > 0, + prerelease: preState?.mode === 'pre', + isMaster: refName === 'master', + isReleaseBranch: refName.startsWith('release-v'), + isWorkflowDispatch: context.eventName === 'workflow_dispatch', + isPush: context.eventName === 'push', + isCurrentFinalVersion: !version.includes('-rc.'), + botRun, + }; + + // Async vars + const { data: prs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: `${context.repo.owner}:merge/${state.refName}`, + base: 'master', + state: 'open', + }); + + 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}`); + + return state; +} + +// From https://github.com/changesets/action/blob/v1.4.1/src/readChangesetState.ts +async function readChangesetState(cwd = process.cwd()) { + const preState = await readPreState(cwd); + const isInPreMode = preState !== undefined && preState.mode === 'pre'; + + let changesets = await readChangesets(cwd); + + if (isInPreMode) { + changesets = changesets.filter(x => !preState.changesets.includes(x.id)); + } + + return { + preState: isInPreMode ? preState : undefined, + changesets, + }; +} + +async function isPublishedOnNpm(package, version) { + const res = await fetch(`https://registry.npmjs.com/${package}/${version}`); + return res.ok; +} diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/remove-ignored-artifacts.js b/lib/openzeppelin-contracts-v4.9.3/scripts/remove-ignored-artifacts.js new file mode 100644 index 0000000..f3e45b8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/remove-ignored-artifacts.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node + +// This script removes the build artifacts of ignored contracts. + +const fs = require('fs'); +const path = require('path'); +const match = require('micromatch'); + +function readJSON(path) { + return JSON.parse(fs.readFileSync(path)); +} + +const pkgFiles = readJSON('package.json').files; + +// Get only negated patterns. +const ignorePatterns = pkgFiles + .filter(pat => pat.startsWith('!')) + // Remove the negation part. Makes micromatch usage more intuitive. + .map(pat => pat.slice(1)); + +const ignorePatternsSubtrees = ignorePatterns + // Add **/* to ignore all files contained in the directories. + .concat(ignorePatterns.map(pat => path.join(pat, '**/*'))) + .map(p => p.replace(/^\//, '')); + +const artifactsDir = 'build/contracts'; +const buildinfo = 'artifacts/build-info'; +const filenames = fs.readdirSync(buildinfo); + +let n = 0; + +for (const filename of filenames) { + const solcOutput = readJSON(path.join(buildinfo, filename)).output; + for (const sourcePath in solcOutput.contracts) { + const ignore = match.any(sourcePath, ignorePatternsSubtrees); + if (ignore) { + for (const contract in solcOutput.contracts[sourcePath]) { + fs.unlinkSync(path.join(artifactsDir, contract + '.json')); + n += 1; + } + } + } +} + +console.error(`Removed ${n} mock artifacts`); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/update-docs-branch.js b/lib/openzeppelin-contracts-v4.9.3/scripts/update-docs-branch.js new file mode 100644 index 0000000..4e94ba6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/scripts/update-docs-branch.js @@ -0,0 +1,63 @@ +const proc = require('child_process'); +const read = cmd => proc.execSync(cmd, { encoding: 'utf8' }).trim(); +const run = cmd => { + proc.execSync(cmd, { stdio: 'inherit' }); +}; +const tryRead = cmd => { + try { + return read(cmd); + } catch (e) { + return undefined; + } +}; + +const releaseBranchRegex = /^release-v(?(?\d+)\.(?\d+)(?:\.(?\d+))?)$/; + +const currentBranch = read('git rev-parse --abbrev-ref HEAD'); +const match = currentBranch.match(releaseBranchRegex); + +if (!match) { + console.error('Not currently on a release branch'); + process.exit(1); +} + +if (/-.*$/.test(require('../package.json').version)) { + console.error('Refusing to update docs: prerelease detected'); + process.exit(0); +} + +const current = match.groups; +const docsBranch = `docs-v${current.major}.x`; + +// Fetch remotes and find the docs branch if it exists +run('git fetch --all --no-tags'); +const matchingDocsBranches = tryRead(`git rev-parse --glob='*/${docsBranch}'`); + +if (!matchingDocsBranches) { + // Create the branch + run(`git checkout --orphan ${docsBranch}`); +} else { + const [publishedRef, ...others] = new Set(matchingDocsBranches.split('\n')); + if (others.length > 0) { + console.error( + `Found conflicting ${docsBranch} branches.\n` + + 'Either local branch is outdated or there are multiple matching remote branches.', + ); + process.exit(1); + } + const publishedVersion = JSON.parse(read(`git show ${publishedRef}:package.json`)).version; + const publishedMinor = publishedVersion.match(/\d+\.(?\d+)\.\d+/).groups.minor; + if (current.minor < publishedMinor) { + console.error('Refusing to update docs: newer version is published'); + process.exit(0); + } + + run('git checkout --quiet --detach'); + run(`git reset --soft ${publishedRef}`); + run(`git checkout ${docsBranch}`); +} + +run('npm run prepare-docs'); +run('git add -f docs'); // --force needed because generated docs files are gitignored +run('git commit -m "Update docs"'); +run(`git checkout ${currentBranch}`); diff --git a/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/README.md b/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/README.md new file mode 100644 index 0000000..2309f9e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/patch-apply.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/patch-apply.sh new file mode 100755 index 0000000..d9e1758 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/patch-save.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/patch-save.sh new file mode 100755 index 0000000..111e6f1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/transpile-onto.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/transpile-onto.sh new file mode 100644 index 0000000..a966a9b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/transpile.sh b/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/transpile.sh new file mode 100644 index 0000000..e3aa31c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/upgradeable.patch b/lib/openzeppelin-contracts-v4.9.3/scripts/upgradeable/upgradeable.patch new file mode 100644 index 0000000..e1988c8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/slither.config.json b/lib/openzeppelin-contracts-v4.9.3/slither.config.json new file mode 100644 index 0000000..069da1f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/slither.config.json @@ -0,0 +1,5 @@ +{ + "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" +} diff --git a/lib/openzeppelin-contracts-v4.9.3/test/TESTING.md b/lib/openzeppelin-contracts-v4.9.3/test/TESTING.md new file mode 100644 index 0000000..a5ee932 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/TESTING.md @@ -0,0 +1,3 @@ +## Testing + +Unit test are critical to OpenZeppelin Contracts. They help ensure code quality and mitigate against security vulnerabilities. The directory structure within the `/test` directory corresponds to the `/contracts` directory. diff --git a/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControl.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControl.behavior.js new file mode 100644 index 0000000..3e61616 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControl.behavior.js @@ -0,0 +1,867 @@ +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']); + + describe('default admin', function () { + it('deployer has default admin role', async function () { + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin)).to.equal(true); + }); + + it("other roles's admin is the default admin role", async function () { + expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + it("default admin role's admin is itself", async function () { + expect(await this.accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + }); + + describe('granting', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('non-admin cannot grant role to other accounts', async function () { + await expectRevert( + this.accessControl.grantRole(ROLE, authorized, { from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, + ); + }); + + it('accounts can be granted a role multiple times', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleGranted'); + }); + }); + + describe('revoking', function () { + it('roles that are not had can be revoked', async function () { + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + + context('with granted role', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('admin can revoke role', async function () { + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: admin }); + + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + }); + + it('non-admin cannot revoke role', async function () { + await expectRevert( + this.accessControl.revokeRole(ROLE, authorized, { from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${DEFAULT_ADMIN_ROLE}`, + ); + }); + + it('a role can be revoked multiple times', async function () { + await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + }); + }); + + describe('renouncing', function () { + it('roles that are not had can be renounced', async function () { + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + + context('with granted role', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('bearer can renounce role', async function () { + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: authorized }); + + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + }); + + it('only the sender can renounce their roles', async function () { + await expectRevert( + this.accessControl.renounceRole(ROLE, authorized, { from: admin }), + `${errorPrefix}: can only renounce roles for self`, + ); + }); + + it('a role can be renounced multiple times', async function () { + await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + }); + }); + + describe('setting role admin', function () { + beforeEach(async function () { + const receipt = await this.accessControl.$_setRoleAdmin(ROLE, OTHER_ROLE); + expectEvent(receipt, 'RoleAdminChanged', { + role: ROLE, + previousAdminRole: DEFAULT_ADMIN_ROLE, + newAdminRole: OTHER_ROLE, + }); + + await this.accessControl.grantRole(OTHER_ROLE, otherAdmin, { from: admin }); + }); + + it("a role's admin role can be changed", async function () { + expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(OTHER_ROLE); + }); + + it('the new admin can grant roles', async function () { + const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin }); + expectEvent(receipt, 'RoleGranted', { account: authorized, role: ROLE, sender: otherAdmin }); + }); + + it('the new admin can revoke roles', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin }); + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: otherAdmin }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: otherAdmin }); + }); + + it("a role's previous admins no longer grant roles", async function () { + await expectRevert( + this.accessControl.grantRole(ROLE, authorized, { from: admin }), + `${errorPrefix}: account ${admin.toLowerCase()} is missing role ${OTHER_ROLE}`, + ); + }); + + it("a role's previous admins no longer revoke roles", async function () { + await expectRevert( + this.accessControl.revokeRole(ROLE, authorized, { from: admin }), + `${errorPrefix}: account ${admin.toLowerCase()} is missing role ${OTHER_ROLE}`, + ); + }); + }); + + describe('onlyRole modifier', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('do not revert if sender has role', async function () { + await this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: authorized }); + }); + + it("revert if sender doesn't have role #1", async function () { + await expectRevert( + this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: other }), + `${errorPrefix}: account ${other.toLowerCase()} is missing role ${ROLE}`, + ); + }); + + it("revert if sender doesn't have role #2", async function () { + await expectRevert( + this.accessControl.methods['$_checkRole(bytes32)'](OTHER_ROLE, { from: authorized }), + `${errorPrefix}: account ${authorized.toLowerCase()} is missing role ${OTHER_ROLE}`, + ); + }); + }); +} + +function shouldBehaveLikeAccessControlEnumerable(errorPrefix, admin, authorized, other, otherAdmin, otherAuthorized) { + shouldSupportInterfaces(['AccessControlEnumerable']); + + describe('enumerating', function () { + it('role bearers can be enumerated', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + await this.accessControl.grantRole(ROLE, other, { from: admin }); + await this.accessControl.grantRole(ROLE, otherAuthorized, { from: admin }); + await this.accessControl.revokeRole(ROLE, other, { from: admin }); + + const memberCount = await this.accessControl.getRoleMemberCount(ROLE); + expect(memberCount).to.bignumber.equal('2'); + + const bearers = []; + for (let i = 0; i < memberCount; ++i) { + bearers.push(await this.accessControl.getRoleMember(ROLE, i)); + } + + expect(bearers).to.have.members([authorized, otherAuthorized]); + }); + it('role enumeration should be in sync after renounceRole call', async function () { + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('0'); + await this.accessControl.grantRole(ROLE, admin, { from: admin }); + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('1'); + await this.accessControl.renounceRole(ROLE, admin, { from: admin }); + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('0'); + }); + }); +} + +function shouldBehaveLikeAccessControlDefaultAdminRules(errorPrefix, delay, defaultAdmin, newDefaultAdmin, other) { + shouldSupportInterfaces(['AccessControlDefaultAdminRules']); + + 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 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); + 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 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); + }); + }); + }); + + 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); + }); + } + }); + }); + + 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 () { + 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 a default admin transfer', function () { + let receipt; + let acceptSchedule; + + 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 acceptSchedule; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + acceptSchedule = web3.utils.toBN(await time.latest()).add(delay); + }); + + 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 () { + beforeEach(async function () { + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + }); + + it('accepts a transfer and changes default admin', async function () { + const receipt = await this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }); + + // 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 schedule + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(constants.ZERO_ADDRESS); + expect(schedule).to.be.bignumber.equal(ZERO); + }); + }); + + 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('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('renounces admin', function () { + let expectedSchedule; + let delayPassed; + let delayNotPassed; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(constants.ZERO_ADDRESS, { from: defaultAdmin }); + 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 () { + await time.setNextBlockTimestamp(delayPassed); + await expectRevert( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from: defaultAdmin }), + `${errorPrefix}: can only renounce roles for self`, + ); + }); + + 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); + + // 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, defaultAdmin, { from: defaultAdmin }); + + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.false; + expect(await this.accessControl.defaultAdmin()).to.be.equal(constants.ZERO_ADDRESS); + expectEvent(receipt, 'RoleRevoked', { + role: DEFAULT_ADMIN_ROLE, + 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 () { + await time.setNextBlockTimestamp(delayPassed); + await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }); + + const grantRoleReceipt = await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, other); + expectEvent(grantRoleReceipt, 'RoleGranted', { + role: DEFAULT_ADMIN_ROLE, + account: other, + }); + }); + + describe('schedule not passed', function () { + 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: defaultAdmin }), + `${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 }); + }); + + 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); + }); + }); + }); +} + +module.exports = { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, + shouldBehaveLikeAccessControlDefaultAdminRules, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControl.test.js b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControl.test.js new file mode 100644 index 0000000..90efad3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControl.test.js @@ -0,0 +1,12 @@ +const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js'); + +const AccessControl = artifacts.require('$AccessControl'); + +contract('AccessControl', function (accounts) { + beforeEach(async function () { + this.accessControl = await AccessControl.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl('AccessControl', ...accounts); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlCrossChain.test.js b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlCrossChain.test.js new file mode 100644 index 0000000..d5a4107 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlCrossChain.test.js @@ -0,0 +1,49 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { BridgeHelper } = require('../helpers/crosschain'); + +const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js'); + +const crossChainRoleAlias = role => + web3.utils.leftPad( + web3.utils.toHex(web3.utils.toBN(role).xor(web3.utils.toBN(web3.utils.soliditySha3('CROSSCHAIN_ALIAS')))), + 64, + ); + +const AccessControlCrossChainMock = artifacts.require('$AccessControlCrossChainMock'); + +const ROLE = web3.utils.soliditySha3('ROLE'); + +contract('AccessControl', function (accounts) { + before(async function () { + this.bridge = await BridgeHelper.deploy(); + }); + + beforeEach(async function () { + this.accessControl = await AccessControlCrossChainMock.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl('AccessControl', ...accounts); + + describe('CrossChain enabled', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, accounts[0], { from: accounts[0] }); + await this.accessControl.grantRole(crossChainRoleAlias(ROLE), accounts[1], { from: accounts[0] }); + }); + + it('check alliassing', async function () { + expect(await this.accessControl.$_crossChainRoleAlias(ROLE)).to.be.bignumber.equal(crossChainRoleAlias(ROLE)); + }); + + it('Crosschain calls not authorized to non-aliased addresses', async function () { + await expectRevert( + this.bridge.call(accounts[0], this.accessControl, '$_checkRole(bytes32)', [ROLE]), + `AccessControl: account ${accounts[0].toLowerCase()} is missing role ${crossChainRoleAlias(ROLE)}`, + ); + }); + + it('Crosschain calls not authorized to non-aliased addresses', async function () { + await this.bridge.call(accounts[1], this.accessControl, '$_checkRole(bytes32)', [ROLE]); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlDefaultAdminRules.test.js b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlDefaultAdminRules.test.js new file mode 100644 index 0000000..be11248 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlDefaultAdminRules.test.js @@ -0,0 +1,25 @@ +const { time, constants, expectRevert } = 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.hours(10)); + + beforeEach(async function () { + 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); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlEnumerable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlEnumerable.test.js new file mode 100644 index 0000000..2aa59f4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/access/AccessControlEnumerable.test.js @@ -0,0 +1,17 @@ +const { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, +} = require('./AccessControl.behavior.js'); + +const AccessControlEnumerable = artifacts.require('$AccessControlEnumerable'); + +contract('AccessControl', function (accounts) { + beforeEach(async function () { + this.accessControl = await AccessControlEnumerable.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl('AccessControl', ...accounts); + shouldBehaveLikeAccessControlEnumerable('AccessControl', ...accounts); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/access/Ownable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/access/Ownable.test.js new file mode 100644 index 0000000..1091508 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/access/Ownable.test.js @@ -0,0 +1,59 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const Ownable = artifacts.require('$Ownable'); + +contract('Ownable', function (accounts) { + const [owner, other] = accounts; + + beforeEach(async function () { + this.ownable = await Ownable.new({ from: owner }); + }); + + it('has an owner', async function () { + expect(await this.ownable.owner()).to.equal(owner); + }); + + describe('transfer ownership', function () { + it('changes owner after transfer', async function () { + const receipt = await this.ownable.transferOwnership(other, { from: owner }); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(other); + }); + + it('prevents non-owners from transferring', async function () { + await expectRevert(this.ownable.transferOwnership(other, { from: other }), 'Ownable: caller is not the owner'); + }); + + it('guards ownership against stuck state', async function () { + await expectRevert( + this.ownable.transferOwnership(ZERO_ADDRESS, { from: owner }), + 'Ownable: new owner is the zero address', + ); + }); + }); + + describe('renounce ownership', function () { + it('loses ownership after renouncement', async function () { + const receipt = await this.ownable.renounceOwnership({ from: owner }); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(ZERO_ADDRESS); + }); + + 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/lib/openzeppelin-contracts-v4.9.3/test/access/Ownable2Step.test.js b/lib/openzeppelin-contracts-v4.9.3/test/access/Ownable2Step.test.js new file mode 100644 index 0000000..ce04305 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/access/Ownable2Step.test.js @@ -0,0 +1,67 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { expect } = require('chai'); + +const Ownable2Step = artifacts.require('$Ownable2Step'); + +contract('Ownable2Step', function (accounts) { + const [owner, accountA, accountB] = accounts; + + beforeEach(async function () { + this.ownable2Step = await Ownable2Step.new({ from: owner }); + }); + + describe('transfer ownership', function () { + it('starting a transfer does not change owner', async function () { + const receipt = await this.ownable2Step.transferOwnership(accountA, { from: owner }); + expectEvent(receipt, 'OwnershipTransferStarted', { previousOwner: owner, newOwner: accountA }); + expect(await this.ownable2Step.owner()).to.equal(owner); + expect(await this.ownable2Step.pendingOwner()).to.equal(accountA); + }); + + it('changes owner after transfer', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + const receipt = await this.ownable2Step.acceptOwnership({ from: accountA }); + expectEvent(receipt, 'OwnershipTransferred', { previousOwner: owner, newOwner: accountA }); + expect(await this.ownable2Step.owner()).to.equal(accountA); + 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 ... + // without it is difficult to cleanly renounce with the two step process + // see: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620#discussion_r957930388 + expect(await this.ownable2Step.owner()).to.equal(ZERO_ADDRESS); + }); + + it('pending owner resets after renouncing ownership', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + expect(await this.ownable2Step.pendingOwner()).to.equal(accountA); + await this.ownable2Step.renounceOwnership({ from: owner }); + expect(await this.ownable2Step.pendingOwner()).to.equal(ZERO_ADDRESS); + await expectRevert( + this.ownable2Step.acceptOwnership({ from: accountA }), + '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/lib/openzeppelin-contracts-v4.9.3/test/crosschain/CrossChainEnabled.test.js b/lib/openzeppelin-contracts-v4.9.3/test/crosschain/CrossChainEnabled.test.js new file mode 100644 index 0000000..9e7d263 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/crosschain/CrossChainEnabled.test.js @@ -0,0 +1,78 @@ +const { BridgeHelper } = require('../helpers/crosschain'); +const { expectRevertCustomError } = require('../helpers/customError'); + +function randomAddress() { + return web3.utils.toChecksumAddress(web3.utils.randomHex(20)); +} + +const CrossChainEnabledAMBMock = artifacts.require('CrossChainEnabledAMBMock'); +const CrossChainEnabledArbitrumL1Mock = artifacts.require('CrossChainEnabledArbitrumL1Mock'); +const CrossChainEnabledArbitrumL2Mock = artifacts.require('CrossChainEnabledArbitrumL2Mock'); +const CrossChainEnabledOptimismMock = artifacts.require('CrossChainEnabledOptimismMock'); +const CrossChainEnabledPolygonChildMock = artifacts.require('CrossChainEnabledPolygonChildMock'); + +function shouldBehaveLikeReceiver(sender = randomAddress()) { + it('should reject same-chain calls', async function () { + await expectRevertCustomError(this.receiver.crossChainRestricted(), 'NotCrossChainCall()'); + + await expectRevertCustomError(this.receiver.crossChainOwnerRestricted(), 'NotCrossChainCall()'); + }); + + it('should restrict to cross-chain call from a invalid sender', async function () { + await expectRevertCustomError( + this.bridge.call(sender, this.receiver, 'crossChainOwnerRestricted()'), + `InvalidCrossChainSender("${sender}", "${await this.receiver.owner()}")`, + ); + }); + + it('should grant access to cross-chain call from the owner', async function () { + await this.bridge.call(await this.receiver.owner(), this.receiver, 'crossChainOwnerRestricted()'); + }); +} + +contract('CrossChainEnabled', function () { + describe('AMB', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('AMB'); + this.receiver = await CrossChainEnabledAMBMock.new(this.bridge.address); + }); + + shouldBehaveLikeReceiver(); + }); + + describe('Arbitrum-L1', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('Arbitrum-L1'); + this.receiver = await CrossChainEnabledArbitrumL1Mock.new(this.bridge.address); + }); + + shouldBehaveLikeReceiver(); + }); + + describe('Arbitrum-L2', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('Arbitrum-L2'); + this.receiver = await CrossChainEnabledArbitrumL2Mock.new(); + }); + + shouldBehaveLikeReceiver(); + }); + + describe('Optimism', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('Optimism'); + this.receiver = await CrossChainEnabledOptimismMock.new(this.bridge.address); + }); + + shouldBehaveLikeReceiver(); + }); + + describe('Polygon-Child', function () { + beforeEach(async function () { + this.bridge = await BridgeHelper.deploy('Polygon-Child'); + this.receiver = await CrossChainEnabledPolygonChildMock.new(this.bridge.address); + }); + + shouldBehaveLikeReceiver(); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/finance/PaymentSplitter.test.js b/lib/openzeppelin-contracts-v4.9.3/test/finance/PaymentSplitter.test.js new file mode 100644 index 0000000..1408c9f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/finance/PaymentSplitter.test.js @@ -0,0 +1,217 @@ +const { balance, constants, ether, expectEvent, send, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const PaymentSplitter = artifacts.require('PaymentSplitter'); +const ERC20 = artifacts.require('$ERC20'); + +contract('PaymentSplitter', function (accounts) { + const [owner, payee1, payee2, payee3, nonpayee1, payer1] = accounts; + + const amount = ether('1'); + + it('rejects an empty set of payees', async function () { + await expectRevert(PaymentSplitter.new([], []), 'PaymentSplitter: no payees'); + }); + + it('rejects more payees than shares', async function () { + await expectRevert( + PaymentSplitter.new([payee1, payee2, payee3], [20, 30]), + 'PaymentSplitter: payees and shares length mismatch', + ); + }); + + it('rejects more shares than payees', async function () { + await expectRevert( + PaymentSplitter.new([payee1, payee2], [20, 30, 40]), + 'PaymentSplitter: payees and shares length mismatch', + ); + }); + + it('rejects null payees', async function () { + await expectRevert( + PaymentSplitter.new([payee1, ZERO_ADDRESS], [20, 30]), + 'PaymentSplitter: account is the zero address', + ); + }); + + it('rejects zero-valued shares', async function () { + await expectRevert(PaymentSplitter.new([payee1, payee2], [20, 0]), 'PaymentSplitter: shares are 0'); + }); + + it('rejects repeated payees', async function () { + await expectRevert(PaymentSplitter.new([payee1, payee1], [20, 30]), 'PaymentSplitter: account already has shares'); + }); + + context('once deployed', function () { + beforeEach(async function () { + this.payees = [payee1, payee2, payee3]; + this.shares = [20, 10, 70]; + + this.contract = await PaymentSplitter.new(this.payees, this.shares); + this.token = await ERC20.new('MyToken', 'MT'); + await this.token.$_mint(owner, ether('1000')); + }); + + it('has total shares', async function () { + expect(await this.contract.totalShares()).to.be.bignumber.equal('100'); + }); + + it('has payees', async function () { + await Promise.all( + this.payees.map(async (payee, index) => { + expect(await this.contract.payee(index)).to.equal(payee); + expect(await this.contract.released(payee)).to.be.bignumber.equal('0'); + expect(await this.contract.releasable(payee)).to.be.bignumber.equal('0'); + }), + ); + }); + + describe('accepts payments', function () { + it('Ether', async function () { + await send.ether(owner, this.contract.address, amount); + + expect(await balance.current(this.contract.address)).to.be.bignumber.equal(amount); + }); + + it('Token', async function () { + await this.token.transfer(this.contract.address, amount, { from: owner }); + + expect(await this.token.balanceOf(this.contract.address)).to.be.bignumber.equal(amount); + }); + }); + + describe('shares', function () { + it('stores shares if address is payee', async function () { + expect(await this.contract.shares(payee1)).to.be.bignumber.not.equal('0'); + }); + + it('does not store shares if address is not payee', async function () { + expect(await this.contract.shares(nonpayee1)).to.be.bignumber.equal('0'); + }); + }); + + describe('release', function () { + describe('Ether', function () { + it('reverts if no funds to claim', async function () { + await expectRevert(this.contract.release(payee1), 'PaymentSplitter: account is not due payment'); + }); + it('reverts if non-payee want to claim', async function () { + await send.ether(payer1, this.contract.address, amount); + await expectRevert(this.contract.release(nonpayee1), 'PaymentSplitter: account has no shares'); + }); + }); + + describe('Token', function () { + it('reverts if no funds to claim', async function () { + await expectRevert( + this.contract.release(this.token.address, payee1), + 'PaymentSplitter: account is not due payment', + ); + }); + it('reverts if non-payee want to claim', async function () { + await this.token.transfer(this.contract.address, amount, { from: owner }); + await expectRevert( + this.contract.release(this.token.address, nonpayee1), + 'PaymentSplitter: account has no shares', + ); + }); + }); + }); + + describe('tracks releasable and released', function () { + it('Ether', async function () { + await send.ether(payer1, this.contract.address, amount); + const payment = amount.divn(10); + expect(await this.contract.releasable(payee2)).to.be.bignumber.equal(payment); + await this.contract.release(payee2); + expect(await this.contract.releasable(payee2)).to.be.bignumber.equal('0'); + expect(await this.contract.released(payee2)).to.be.bignumber.equal(payment); + }); + + it('Token', async function () { + await this.token.transfer(this.contract.address, amount, { from: owner }); + const payment = amount.divn(10); + expect(await this.contract.releasable(this.token.address, payee2, {})).to.be.bignumber.equal(payment); + await this.contract.release(this.token.address, payee2); + expect(await this.contract.releasable(this.token.address, payee2, {})).to.be.bignumber.equal('0'); + expect(await this.contract.released(this.token.address, payee2)).to.be.bignumber.equal(payment); + }); + }); + + describe('distributes funds to payees', function () { + it('Ether', async function () { + await send.ether(payer1, this.contract.address, amount); + + // receive funds + const initBalance = await balance.current(this.contract.address); + expect(initBalance).to.be.bignumber.equal(amount); + + // distribute to payees + + const tracker1 = await balance.tracker(payee1); + const receipt1 = await this.contract.release(payee1); + const profit1 = await tracker1.delta(); + expect(profit1).to.be.bignumber.equal(ether('0.20')); + expectEvent(receipt1, 'PaymentReleased', { to: payee1, amount: profit1 }); + + const tracker2 = await balance.tracker(payee2); + const receipt2 = await this.contract.release(payee2); + const profit2 = await tracker2.delta(); + expect(profit2).to.be.bignumber.equal(ether('0.10')); + expectEvent(receipt2, 'PaymentReleased', { to: payee2, amount: profit2 }); + + const tracker3 = await balance.tracker(payee3); + const receipt3 = await this.contract.release(payee3); + const profit3 = await tracker3.delta(); + expect(profit3).to.be.bignumber.equal(ether('0.70')); + expectEvent(receipt3, 'PaymentReleased', { to: payee3, amount: profit3 }); + + // end balance should be zero + expect(await balance.current(this.contract.address)).to.be.bignumber.equal('0'); + + // check correct funds released accounting + expect(await this.contract.totalReleased()).to.be.bignumber.equal(initBalance); + }); + + it('Token', async function () { + expect(await this.token.balanceOf(payee1)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(payee2)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(payee3)).to.be.bignumber.equal('0'); + + await this.token.transfer(this.contract.address, amount, { from: owner }); + + expectEvent(await this.contract.release(this.token.address, payee1), 'ERC20PaymentReleased', { + token: this.token.address, + to: payee1, + amount: ether('0.20'), + }); + + await this.token.transfer(this.contract.address, amount, { from: owner }); + + expectEvent(await this.contract.release(this.token.address, payee1), 'ERC20PaymentReleased', { + token: this.token.address, + to: payee1, + amount: ether('0.20'), + }); + + expectEvent(await this.contract.release(this.token.address, payee2), 'ERC20PaymentReleased', { + token: this.token.address, + to: payee2, + amount: ether('0.20'), + }); + + expectEvent(await this.contract.release(this.token.address, payee3), 'ERC20PaymentReleased', { + token: this.token.address, + to: payee3, + amount: ether('1.40'), + }); + + expect(await this.token.balanceOf(payee1)).to.be.bignumber.equal(ether('0.40')); + expect(await this.token.balanceOf(payee2)).to.be.bignumber.equal(ether('0.20')); + expect(await this.token.balanceOf(payee3)).to.be.bignumber.equal(ether('1.40')); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/finance/VestingWallet.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/finance/VestingWallet.behavior.js new file mode 100644 index 0000000..afd4c04 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/finance/VestingWallet.behavior.js @@ -0,0 +1,59 @@ +const { time } = require('@nomicfoundation/hardhat-network-helpers'); +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +function releasedEvent(token, amount) { + return token ? ['ERC20Released', { token: token.address, amount }] : ['EtherReleased', { amount }]; +} + +function shouldBehaveLikeVesting(beneficiary) { + it('check vesting schedule', async function () { + const [vestedAmount, releasable, ...args] = this.token + ? ['vestedAmount(address,uint64)', 'releasable(address)', this.token.address] + : ['vestedAmount(uint64)', 'releasable()']; + + for (const timestamp of this.schedule) { + await time.increaseTo(timestamp); + const vesting = this.vestingFn(timestamp); + + expect(await this.mock.methods[vestedAmount](...args, timestamp)).to.be.bignumber.equal(vesting); + + expect(await this.mock.methods[releasable](...args)).to.be.bignumber.equal(vesting); + } + }); + + it('execute vesting schedule', async function () { + const [release, ...args] = this.token ? ['release(address)', this.token.address] : ['release()']; + + let released = web3.utils.toBN(0); + const before = await this.getBalance(beneficiary); + + { + const receipt = await this.mock.methods[release](...args); + + await expectEvent.inTransaction(receipt.tx, this.mock, ...releasedEvent(this.token, '0')); + + await this.checkRelease(receipt, beneficiary, '0'); + + expect(await this.getBalance(beneficiary)).to.be.bignumber.equal(before); + } + + for (const timestamp of this.schedule) { + await time.setNextBlockTimestamp(timestamp); + const vested = this.vestingFn(timestamp); + + const receipt = await this.mock.methods[release](...args); + await expectEvent.inTransaction(receipt.tx, this.mock, ...releasedEvent(this.token, vested.sub(released))); + + await this.checkRelease(receipt, beneficiary, vested.sub(released)); + + expect(await this.getBalance(beneficiary)).to.be.bignumber.equal(before.add(vested)); + + released = vested; + } + }); +} + +module.exports = { + shouldBehaveLikeVesting, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/finance/VestingWallet.test.js b/lib/openzeppelin-contracts-v4.9.3/test/finance/VestingWallet.test.js new file mode 100644 index 0000000..5b90a69 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/finance/VestingWallet.test.js @@ -0,0 +1,67 @@ +const { constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { web3 } = require('@openzeppelin/test-helpers/src/setup'); +const { expect } = require('chai'); + +const VestingWallet = artifacts.require('VestingWallet'); +const ERC20 = artifacts.require('$ERC20'); + +const { shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); + +const min = (...args) => args.slice(1).reduce((x, y) => (x.lt(y) ? x : y), args[0]); + +contract('VestingWallet', function (accounts) { + const [sender, beneficiary] = accounts; + + const amount = web3.utils.toBN(web3.utils.toWei('100')); + const duration = web3.utils.toBN(4 * 365 * 86400); // 4 years + + beforeEach(async function () { + this.start = (await time.latest()).addn(3600); // in 1 hour + this.mock = await VestingWallet.new(beneficiary, this.start, duration); + }); + + it('rejects zero address for beneficiary', async function () { + await expectRevert( + VestingWallet.new(constants.ZERO_ADDRESS, this.start, duration), + 'VestingWallet: beneficiary is zero address', + ); + }); + + it('check vesting contract', async function () { + expect(await this.mock.beneficiary()).to.be.equal(beneficiary); + expect(await this.mock.start()).to.be.bignumber.equal(this.start); + expect(await this.mock.duration()).to.be.bignumber.equal(duration); + }); + + describe('vesting schedule', function () { + beforeEach(async function () { + this.schedule = Array(64) + .fill() + .map((_, i) => web3.utils.toBN(i).mul(duration).divn(60).add(this.start)); + this.vestingFn = timestamp => min(amount, amount.mul(timestamp.sub(this.start)).div(duration)); + }); + + describe('Eth vesting', function () { + beforeEach(async function () { + await web3.eth.sendTransaction({ from: sender, to: this.mock.address, value: amount }); + this.getBalance = account => web3.eth.getBalance(account).then(web3.utils.toBN); + this.checkRelease = () => {}; + }); + + shouldBehaveLikeVesting(beneficiary); + }); + + describe('ERC20 vesting', function () { + beforeEach(async function () { + this.token = await ERC20.new('Name', 'Symbol'); + this.getBalance = account => this.token.balanceOf(account); + this.checkRelease = (receipt, to, value) => + expectEvent.inTransaction(receipt.tx, this.token, 'Transfer', { from: this.mock.address, to, value }); + + await this.token.$_mint(this.mock.address, amount); + }); + + shouldBehaveLikeVesting(beneficiary); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/Governor.t.sol b/lib/openzeppelin-contracts-v4.9.3/test/governance/Governor.t.sol new file mode 100644 index 0000000..43c4c5d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/Governor.t.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import "forge-std/Test.sol"; +import "../../contracts/utils/Strings.sol"; +import "../../contracts/governance/Governor.sol"; + +contract GovernorInternalTest is Test, Governor { + constructor() Governor("") {} + + function testValidDescriptionForProposer(string memory description, address proposer, bool includeProposer) public { + if (includeProposer) { + description = string.concat(description, "#proposer=", Strings.toHexString(proposer)); + } + assertTrue(_isValidDescriptionForProposer(proposer, description)); + } + + function testInvalidDescriptionForProposer( + string memory description, + address commitProposer, + address actualProposer + ) public { + vm.assume(commitProposer != actualProposer); + description = string.concat(description, "#proposer=", Strings.toHexString(commitProposer)); + assertFalse(_isValidDescriptionForProposer(actualProposer, description)); + } + + // We don't need to truly implement implement the missing functions because we are just testing + // internal helpers. + + function clock() public pure override returns (uint48) {} + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public pure override returns (string memory) {} + + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) {} + + function votingDelay() public pure virtual override returns (uint256) {} + + function votingPeriod() public pure virtual override returns (uint256) {} + + function quorum(uint256) public pure virtual override returns (uint256) {} + + function hasVoted(uint256, address) public pure virtual override returns (bool) {} + + function _quorumReached(uint256) internal pure virtual override returns (bool) {} + + function _voteSucceeded(uint256) internal pure virtual override returns (bool) {} + + function _getVotes(address, uint256, bytes memory) internal pure virtual override returns (uint256) {} + + function _countVote(uint256, address, uint8, uint256, bytes memory) internal virtual override {} +} diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/Governor.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/Governor.test.js new file mode 100644 index 0000000..53f63ab --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/Governor.test.js @@ -0,0 +1,782 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +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 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 name = 'OZ-Governor'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, mode); + + 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 }); + + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + '', + ); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver', 'Governor', 'GovernorWithParams', 'GovernorCancel']); + 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('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 }); + + 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(); + + 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.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'), + }); + + await this.helper.waitForDeadline(); + + const txExecute = await this.helper.execute(); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + + 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.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()); + + 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('frontrun protection using description suffix', function () { + describe('without protection', function () { + describe('without suffix', function () { + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + + describe('with different suffix', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#wrong-suffix=${proposer}`, + ); + }); + + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + + describe('with proposer suffix but bad address part', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#proposer=0x3C44CdDdB6a900fa2b585dd299e03d12FA429XYZ`, // XYZ are not a valid hex char + ); + }); + + it('propose can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + }); + + describe('with protection via proposer suffix', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#proposer=${proposer}`, + ); + }); + + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else cannot propose', async function () { + await expectRevert(this.helper.propose({ from: voter1 }), 'Governor: proposer restricted'); + }); + }); + }); + + 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 = 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 }, + ); + }); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/TimelockController.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/TimelockController.test.js new file mode 100644 index 0000000..82a8474 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/TimelockController.test.js @@ -0,0 +1,1254 @@ +const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS, ZERO_BYTES32 } = constants; + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); + +const TimelockController = artifacts.require('TimelockController'); +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); + +const salt = '0x025e7b0be353a74631ad648c667493c0e1cd31caa4cc2d3520fdc171ea0cc726'; // a random value + +function genOperation(target, value, data, predecessor, salt) { + const id = web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address', 'uint256', 'bytes', 'uint256', 'bytes32'], + [target, value, data, predecessor, salt], + ), + ); + return { id, target, value, data, predecessor, salt }; +} + +function genOperationBatch(targets, values, payloads, predecessor, salt) { + const id = web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address[]', 'uint256[]', 'bytes[]', 'uint256', 'bytes32'], + [targets, values, payloads, predecessor, salt], + ), + ); + return { id, targets, values, payloads, predecessor, salt }; +} + +contract('TimelockController', function (accounts) { + const [, admin, proposer, canceller, executor, other] = accounts; + + const TIMELOCK_ADMIN_ROLE = web3.utils.soliditySha3('TIMELOCK_ADMIN_ROLE'); + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + beforeEach(async function () { + // Deploy new timelock + this.mock = await TimelockController.new(MINDELAY, [proposer], [executor], admin); + + expect(await this.mock.hasRole(CANCELLER_ROLE, proposer)).to.be.equal(true); + await this.mock.revokeRole(CANCELLER_ROLE, proposer, { from: admin }); + await this.mock.grantRole(CANCELLER_ROLE, canceller, { from: admin }); + + // Mocks + this.callreceivermock = await CallReceiverMock.new({ from: admin }); + this.implementation2 = await Implementation2.new({ from: admin }); + }); + + shouldSupportInterfaces(['ERC1155Receiver']); + + it('initial state', async function () { + expect(await this.mock.getMinDelay()).to.be.bignumber.equal(MINDELAY); + + expect(await this.mock.TIMELOCK_ADMIN_ROLE()).to.be.equal(TIMELOCK_ADMIN_ROLE); + expect(await this.mock.PROPOSER_ROLE()).to.be.equal(PROPOSER_ROLE); + expect(await this.mock.EXECUTOR_ROLE()).to.be.equal(EXECUTOR_ROLE); + expect(await this.mock.CANCELLER_ROLE()).to.be.equal(CANCELLER_ROLE); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, proposer))), + ).to.be.deep.equal([true, false, false]); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, canceller))), + ).to.be.deep.equal([false, true, false]); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, executor))), + ).to.be.deep.equal([false, false, true]); + }); + + it('optional admin', async function () { + const mock = await TimelockController.new(MINDELAY, [proposer], [executor], ZERO_ADDRESS, { from: other }); + + expect(await mock.hasRole(TIMELOCK_ADMIN_ROLE, admin)).to.be.equal(false); + expect(await mock.hasRole(TIMELOCK_ADMIN_ROLE, other)).to.be.equal(false); + }); + + describe('methods', function () { + describe('operation hashing', function () { + it('hashOperation', async function () { + this.operation = genOperation( + '0x29cebefe301c6ce1bb36b58654fea275e1cacc83', + '0xf94fdd6e21da21d2', + '0xa3bc5104', + '0xba41db3be0a9929145cfe480bd0f1f003689104d275ae912099f925df424ef94', + '0x60d9109846ab510ed75c15f979ae366a8a2ace11d34ba9788c13ac296db50e6e', + ); + expect( + await this.mock.hashOperation( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ).to.be.equal(this.operation.id); + }); + + it('hashOperationBatch', async function () { + this.operation = genOperationBatch( + Array(8).fill('0x2d5f21620e56531c1d59c2df9b8e95d129571f71'), + Array(8).fill('0x2b993cfce932ccee'), + Array(8).fill('0xcf51966b'), + '0xce8f45069cc71d25f71ba05062de1a3974f9849b004de64a70998bca9d29c2e7', + '0x8952d74c110f72bfe5accdf828c74d53a7dfb71235dfa8a1e8c75d8576b372ff', + ); + expect( + await this.mock.hashOperationBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ).to.be.equal(this.operation.id); + }); + }); + describe('simple', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperation( + '0x31754f590B97fD975Eb86938f18Cc304E264D2F2', + 0, + '0x3bf92ccc', + ZERO_BYTES32, + salt, + ); + }); + + it('proposer can schedule', async function () { + const receipt = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + expectEvent(receipt, 'CallScheduled', { + id: this.operation.id, + index: web3.utils.toBN(0), + target: this.operation.target, + value: web3.utils.toBN(this.operation.value), + data: this.operation.data, + 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); + + expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( + web3.utils.toBN(block.timestamp).add(MINDELAY), + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + + await expectRevert( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockController: operation already scheduled', + ); + }); + + it('prevent non-proposer from committing', async function () { + await expectRevert( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: other }, + ), + `AccessControl: account ${other.toLowerCase()} is missing role ${PROPOSER_ROLE}`, + ); + }); + + it('enforce minimum delay', async function () { + await expectRevert( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1, + { from: proposer }, + ), + '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 () { + beforeEach(async function () { + this.operation = genOperation( + '0xAe22104DCD970750610E6FE15E623468A98b15f7', + 0, + '0x13e414de', + ZERO_BYTES32, + '0xc1059ed2dc130227aa1d1d539ac94c641306905c020436c636e19e3fab56fc7f', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expectRevert( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + ({ receipt: this.receipt, logs: this.logs } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('revert if execution comes too early 1/2', async function () { + await expectRevert( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + it('revert if execution comes too early 2/2', async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp - 5); // -1 is too tight, test sometime fails + + await expectRevert( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + describe('on time', function () { + beforeEach(async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp); + }); + + it('executor can reveal', async function () { + const receipt = await this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ); + expectEvent(receipt, 'CallExecuted', { + id: this.operation.id, + index: web3.utils.toBN(0), + target: this.operation.target, + value: web3.utils.toBN(this.operation.value), + data: this.operation.data, + }); + }); + + it('prevent non-executor from revealing', async function () { + await expectRevert( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: other }, + ), + `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, + }); + }); + }); + }); + }); + }); + + describe('batch', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0xEd912250835c812D4516BBD80BdaEA1bB63a293C'), + Array(8).fill(0), + Array(8).fill('0x2fcb7a88'), + ZERO_BYTES32, + '0x6cf9d042ade5de78bed9ffd075eb4b2a4f6b1736932c2dc8af517d6e066f51f5', + ); + }); + + it('proposer can schedule', async function () { + const receipt = await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + for (const i in this.operation.targets) { + expectEvent(receipt, 'CallScheduled', { + id: this.operation.id, + index: web3.utils.toBN(i), + target: this.operation.targets[i], + value: web3.utils.toBN(this.operation.values[i]), + data: this.operation.payloads[i], + 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); + + expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( + web3.utils.toBN(block.timestamp).add(MINDELAY), + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockController: operation already scheduled', + ); + }); + + it('length of batch parameter must match #1', async function () { + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockController: length mismatch', + ); + }); + + it('length of batch parameter must match #1', async function () { + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockController: length mismatch', + ); + }); + + it('prevent non-proposer from committing', async function () { + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: other }, + ), + `AccessControl: account ${other.toLowerCase()} is missing role ${PROPOSER_ROLE}`, + ); + }); + + it('enforce minimum delay', async function () { + await expectRevert( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1, + { from: proposer }, + ), + 'TimelockController: insufficient delay', + ); + }); + }); + + describe('execute', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0x76E53CcEb05131Ef5248553bEBDb8F70536830b1'), + Array(8).fill(0), + Array(8).fill('0x58a60f63'), + ZERO_BYTES32, + '0x9545eeabc7a7586689191f78a5532443698538e54211b5bd4d7dc0fc0102b5c7', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + ({ receipt: this.receipt, logs: this.logs } = await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('revert if execution comes too early 1/2', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + it('revert if execution comes too early 2/2', async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp - 5); // -1 is to tight, test sometime fails + + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: operation is not ready', + ); + }); + + describe('on time', function () { + beforeEach(async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp); + }); + + it('executor can reveal', async function () { + const receipt = await this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ); + for (const i in this.operation.targets) { + expectEvent(receipt, 'CallExecuted', { + id: this.operation.id, + index: web3.utils.toBN(i), + target: this.operation.targets[i], + value: web3.utils.toBN(this.operation.values[i]), + data: this.operation.payloads[i], + }); + } + }); + + it('prevent non-executor from revealing', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: other }, + ), + `AccessControl: account ${other.toLowerCase()} is missing role ${EXECUTOR_ROLE}`, + ); + }); + + it('length mismatch #1', async function () { + await expectRevert( + this.mock.executeBatch( + [], + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: length mismatch', + ); + }); + + it('length mismatch #2', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockController: length mismatch', + ); + }); + + it('length mismatch #3', async function () { + await expectRevert( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + '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], + }); + } + }); + }); + }); + + it('partial execution', async function () { + const operation = genOperationBatch( + [this.callreceivermock.address, this.callreceivermock.address, this.callreceivermock.address], + [0, 0, 0], + [ + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(), + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + ], + ZERO_BYTES32, + '0x8ac04aa0d6d66b8812fb41d39638d37af0a9ab11da507afd65c509f8ed079d3e', + ); + + await this.mock.scheduleBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevert( + this.mock.executeBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + { from: executor }, + ), + 'TimelockController: underlying transaction reverted', + ); + }); + }); + }); + + describe('cancel', function () { + beforeEach(async function () { + this.operation = genOperation( + '0xC6837c44AA376dbe1d2709F13879E040CAb653ca', + 0, + '0x296e58dd', + ZERO_BYTES32, + '0xa2485763600634800df9fc9646fb2c112cf98649c55f63dd1d9c7d13a64399d9', + ); + ({ receipt: this.receipt, logs: this.logs } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('canceller can cancel', async function () { + const receipt = await this.mock.cancel(this.operation.id, { from: canceller }); + expectEvent(receipt, 'Cancelled', { id: this.operation.id }); + }); + + it('cannot cancel invalid operation', async function () { + await expectRevert( + this.mock.cancel(constants.ZERO_BYTES32, { from: canceller }), + 'TimelockController: operation cannot be cancelled', + ); + }); + + it('prevent non-canceller from canceling', async function () { + await expectRevert( + this.mock.cancel(this.operation.id, { from: other }), + `AccessControl: account ${other.toLowerCase()} is missing role ${CANCELLER_ROLE}`, + ); + }); + }); + }); + + describe('maintenance', function () { + it('prevent unauthorized maintenance', async function () { + await expectRevert(this.mock.updateDelay(0, { from: other }), 'TimelockController: caller must be timelock'); + }); + + it('timelock scheduled maintenance', async function () { + const newDelay = time.duration.hours(6); + const operation = genOperation( + this.mock.address, + 0, + this.mock.contract.methods.updateDelay(newDelay.toString()).encodeABI(), + ZERO_BYTES32, + '0xf8e775b2c5f4d66fb5c7fa800f35ef518c262b6014b3c0aee6ea21bff157f108', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + const receipt = await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor }, + ); + expectEvent(receipt, 'MinDelayChange', { newDuration: newDelay.toString(), oldDuration: MINDELAY }); + + expect(await this.mock.getMinDelay()).to.be.bignumber.equal(newDelay); + }); + }); + + describe('dependency', function () { + beforeEach(async function () { + this.operation1 = genOperation( + '0xdE66bD4c97304200A95aE0AadA32d6d01A867E39', + 0, + '0x01dc731a', + ZERO_BYTES32, + '0x64e932133c7677402ead2926f86205e2ca4686aebecf5a8077627092b9bb2feb', + ); + this.operation2 = genOperation( + '0x3c7944a3F1ee7fc8c5A5134ba7c79D11c3A1FCa3', + 0, + '0x8f531849', + this.operation1.id, + '0x036e1311cac523f9548e6461e29fb1f8f9196b91910a41711ea22f5de48df07d', + ); + await this.mock.schedule( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + MINDELAY, + { from: proposer }, + ); + await this.mock.schedule( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + }); + + it('cannot execute before dependency', async function () { + await expectRevert( + this.mock.execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + { from: executor }, + ), + 'TimelockController: missing dependency', + ); + }); + + it('can execute after dependency', async function () { + await this.mock.execute( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + { from: executor }, + ); + await this.mock.execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + { from: executor }, + ); + }); + }); + + describe('usage scenario', function () { + this.timeout(10000); + + it('call', async function () { + const operation = genOperation( + this.implementation2.address, + 0, + this.implementation2.contract.methods.setValue(42).encodeABI(), + ZERO_BYTES32, + '0x8043596363daefc89977b25f9d9b4d06c3910959ef0c4d213557a903e1b555e2', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor }, + ); + + expect(await this.implementation2.getValue()).to.be.bignumber.equal(web3.utils.toBN(42)); + }); + + it('call reverting', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + ZERO_BYTES32, + '0xb1b1b276fdf1a28d1e00537ea73b04d56639128b08063c1a2f70a52e38cba693', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'TimelockController: underlying transaction reverted', + ); + }); + + it('call throw', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(), + ZERO_BYTES32, + '0xe5ca79f295fc8327ee8a765fe19afb58f4a0cbc5053642bfdd7e73bc68e0fc67', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'TimelockController: underlying transaction reverted', + ); + }); + + it('call out of gas', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionOutOfGas().encodeABI(), + ZERO_BYTES32, + '0xf3274ce7c394c5b629d5215723563a744b817e1730cca5587c567099a14578fd', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + gas: '70000', + }), + 'TimelockController: underlying transaction reverted', + ); + }); + + it('call payable with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + ZERO_BYTES32, + '0x5ab73cd33477dcd36c1e05e28362719d0ed59a7b9ff14939de63a43073dc1f44', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor, value: 1 }, + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(1)); + }); + + it('call nonpayable with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunctionNonPayable().encodeABI(), + ZERO_BYTES32, + '0xb78edbd920c7867f187e5aa6294ae5a656cfbf0dea1ccdca3751b740d0f2bdf8', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'TimelockController: underlying transaction reverted', + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + it('call reverting with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + ZERO_BYTES32, + '0xdedb4563ef0095db01d81d3f2decf57cf83e4a72aa792af14c43a792b56f4de6', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await expectRevert( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'TimelockController: underlying transaction reverted', + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + }); + + 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(other, tokenId); + }); + + it('can receive an ERC721 safeTransfer', async function () { + await this.token.safeTransferFrom(other, this.mock.address, tokenId, { from: other }); + }); + }); + + 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(other, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it('can receive ERC1155 safeTransfer', async function () { + await this.token.safeTransferFrom( + other, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: other }, + ); + }); + + it('can receive ERC1155 safeBatchTransfer', async function () { + await this.token.safeBatchTransferFrom( + other, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: other }, + ); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/compatibility/GovernorCompatibilityBravo.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/compatibility/GovernorCompatibilityBravo.test.js new file mode 100644 index 0000000..5a8104a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/compatibility/GovernorCompatibilityBravo.test.js @@ -0,0 +1,283 @@ +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 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 + .sha3(RLP.encode([creator, nonce])) + .slice(12) + .substring(14), + ); +} + +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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const proposalThreshold = web3.utils.toWei('10'); + const value = web3.utils.toWei('1'); + + 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); + + // 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.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: 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()', + }, + ], + '', + ); + }); + + 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.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, + 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', + }); + }); + + 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 () { + 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/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorComp.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorComp.test.js new file mode 100644 index 0000000..bfcd0af --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorComp.test.js @@ -0,0 +1,88 @@ +const { expect } = require('chai'); +const Enums = require('../../helpers/enums'); +const { GovernorHelper } = require('../../helpers/governance'); + +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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, mode); + + 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 }); + + // 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('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); + + 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/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorERC721.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorERC721.test.js new file mode 100644 index 0000000..c1f424c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorERC721.test.js @@ -0,0 +1,115 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const Enums = require('../../helpers/enums'); +const { GovernorHelper } = require('../../helpers/governance'); + +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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockNFToken'; + const tokenSymbol = 'MTKN'; + 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'); + + 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, mode); + + 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 }); + + // 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('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: 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/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorPreventLateQuorum.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorPreventLateQuorum.test.js new file mode 100644 index 0000000..f81bd52 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorPreventLateQuorum.test.js @@ -0,0 +1,189 @@ +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 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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + 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'); + + 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, mode); + + 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 }); + + // 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 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/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorTimelockCompound.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorTimelockCompound.test.js new file mode 100644 index 0000000..23d0adb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorTimelockCompound.test.js @@ -0,0 +1,352 @@ +const { constants, 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 { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +const Timelock = artifacts.require('CompTimelock'); +const Governor = artifacts.require('$GovernorTimelockCompoundMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); + +function makeContractAddress(creator, nonce) { + return web3.utils.toChecksumAddress( + web3.utils + .sha3(RLP.encode([creator, nonce])) + .slice(12) + .substring(14), + ); +} + +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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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); + + // 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, 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.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 () { + 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); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorTimelockControl.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorTimelockControl.test.js new file mode 100644 index 0000000..ef50dc7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorTimelockControl.test.js @@ -0,0 +1,445 @@ +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 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; + + const TIMELOCK_ADMIN_ROLE = web3.utils.soliditySha3('TIMELOCK_ADMIN_ROLE'); + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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.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(); + + 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); + + 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.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. + }); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorVotesQuorumFraction.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorVotesQuorumFraction.test.js new file mode 100644 index 0000000..ca91580 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorVotesQuorumFraction.test.js @@ -0,0 +1,154 @@ +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 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; + + const name = 'OZ-Governor'; + // const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + 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'); + + 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, mode); + + 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 }); + + // 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 clock[mode]().then(timepoint => this.mock.quorum(timepoint - 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, + }); + + 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', + ); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorWithParams.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorWithParams.test.js new file mode 100644 index 0000000..4e14694 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/extensions/GovernorWithParams.test.js @@ -0,0 +1,173 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { fromRpcSig } = require('ethereumjs-util'); +const Enums = require('../../helpers/enums'); +const { getDomain, domainType } = require('../../helpers/eip712'); +const { GovernorHelper } = require('../../helpers/governance'); + +const Governor = artifacts.require('$GovernorWithParamsMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); + +const rawParams = { + 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; + + const name = 'OZ-Governor'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, mode); + + 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 }); + + // 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('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); + }); + + it('Voting with params is properly supported', async function () { + await this.helper.propose({ from: proposer }); + 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, + }, + { 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' }, + ], + }, + 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); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/utils/EIP6372.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/utils/EIP6372.behavior.js new file mode 100644 index 0000000..022ec35 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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/lib/openzeppelin-contracts-v4.9.3/test/governance/utils/Votes.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/utils/Votes.behavior.js new file mode 100644 index 0000000..864a2f9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/utils/Votes.behavior.js @@ -0,0 +1,361 @@ +const { constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); + +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +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' }, + { name: 'nonce', type: 'uint256' }, + { name: 'expiry', type: 'uint256' }, +]; + +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'); + }); + + it('domain separator', async function () { + expect(await this.votes.DOMAIN_SEPARATOR()).to.equal(domainSeparator(await getDomain(this.votes))); + }); + + describe('delegation with signature', function () { + const delegator = Wallet.generate(); + const delegatorAddress = web3.utils.toChecksumAddress(delegator.getAddressString()); + const nonce = 0; + + const buildAndSignData = async (contract, message, pk) => { + const data = await getDomain(contract).then(domain => ({ + primaryType: 'Delegation', + 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 } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + 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, + toDelegate: delegatorAddress, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: delegatorAddress, + previousBalance: '0', + newBalance: '1', + }); + + 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, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(delegatorAddress, timepoint)).to.be.bignumber.equal('1'); + }); + + it('rejects reused signature', async function () { + 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); + + await expectRevert( + this.votes.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s), + 'Votes: invalid nonce', + ); + }); + + it('rejects bad delegatee', async function () { + 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); + 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(this.account1Delegatee); + }); + + it('rejects bad nonce', async function () { + 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', + ); + }); + + it('rejects expired permit', async function () { + const expiry = (await time.latest()) - time.duration.weeks(1); + + const { v, r, s } = await buildAndSignData( + this.votes, + { + delegatee: delegatorAddress, + nonce, + expiry, + }, + delegator.getPrivateKey(), + ); + + await expectRevert( + this.votes.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), + 'Votes: signature expired', + ); + }); + }); + + describe('set delegation', function () { + describe('call', function () { + it('delegation with tokens', async function () { + await this.votes.$_mint(this.account1, this.NFT0); + 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, + toDelegate: this.account1, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: this.account1, + previousBalance: '0', + newBalance: '1', + }); + + 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, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(this.account1, timepoint)).to.be.bignumber.equal('1'); + }); + + it('delegation without tokens', async function () { + expect(await this.votes.delegates(this.account1)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.votes.delegate(this.account1, { from: this.account1 }); + expectEvent(receipt, 'DelegateChanged', { + delegator: this.account1, + fromDelegate: ZERO_ADDRESS, + toDelegate: this.account1, + }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + expect(await this.votes.delegates(this.account1)).to.be.equal(this.account1); + }); + }); + }); + + describe('change delegation', function () { + beforeEach(async function () { + await this.votes.$_mint(this.account1, this.NFT0); + await this.votes.delegate(this.account1, { from: this.account1 }); + }); + + it('call', async function () { + 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, + toDelegate: this.account1Delegatee, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: this.account1, + previousBalance: '1', + newBalance: '0', + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: this.account1Delegatee, + previousBalance: '0', + newBalance: '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, 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, timepoint)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(this.account1Delegatee, timepoint)).to.be.bignumber.equal('1'); + }); + }); + + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.votes.delegate(this.account1, { from: this.account1 }); + }); + + it('reverts if block number >= current block', async function () { + await expectRevert(this.votes.getPastTotalSupply(5e10), 'future lookup'); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastTotalSupply(0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + 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(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 { 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(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 () { + const t1 = await this.votes.$_mint(this.account1, this.NFT1); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.votes.$_burn(this.NFT1); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.votes.$_mint(this.account1, this.NFT2); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.votes.$_burn(this.NFT2); + await time.advanceBlock(); + await time.advanceBlock(); + const t5 = await this.votes.$_mint(this.account1, this.NFT3); + 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); + 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'); + }); + }); + + // 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.votes.$_mint(this.account1, this.NFT0); + await this.votes.$_mint(this.account1, this.NFT1); + await this.votes.$_mint(this.account1, this.NFT2); + await this.votes.$_mint(this.account1, this.NFT3); + }); + + describe('getPastVotes', function () { + it('reverts if block number >= current block', async function () { + await expectRevert(this.votes.getPastVotes(this.account2, 5e10), 'future lookup'); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastVotes(this.account2, 0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + 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); + 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 { 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, timepoint - 1)).to.be.bignumber.equal('0'); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeVotes, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/governance/utils/Votes.test.js b/lib/openzeppelin-contracts-v4.9.3/test/governance/utils/Votes.test.js new file mode 100644 index 0000000..62b1ab2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/governance/utils/Votes.test.js @@ -0,0 +1,71 @@ +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 MODES = { + blocknumber: artifacts.require('$VotesMock'), + timestamp: artifacts.require('$VotesTimestampMock'), +}; + +contract('Votes', function (accounts) { + const [account1, account2, account3] = accounts; + + 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'); + }); + + 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); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/chainid.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/chainid.js new file mode 100644 index 0000000..58757eb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/chainid.js @@ -0,0 +1,10 @@ +const hre = require('hardhat'); + +async function getChainId() { + const chainIdHex = await hre.network.provider.send('eth_chainId', []); + return new hre.web3.utils.BN(chainIdHex, 'hex'); +} + +module.exports = { + getChainId, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/create2.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/create2.js new file mode 100644 index 0000000..afe07da --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/create2.js @@ -0,0 +1,11 @@ +function computeCreate2Address(saltHex, bytecode, deployer) { + return web3.utils.toChecksumAddress( + `0x${web3.utils + .sha3(`0x${['ff', deployer, saltHex, web3.utils.soliditySha3(bytecode)].map(x => x.replace(/0x/, '')).join('')}`) + .slice(-40)}`, + ); +} + +module.exports = { + computeCreate2Address, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/crosschain.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/crosschain.js new file mode 100644 index 0000000..9e6ff96 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/crosschain.js @@ -0,0 +1,61 @@ +const { promisify } = require('util'); + +const BridgeAMBMock = artifacts.require('BridgeAMBMock'); +const BridgeArbitrumL1Mock = artifacts.require('BridgeArbitrumL1Mock'); +const BridgeArbitrumL2Mock = artifacts.require('BridgeArbitrumL2Mock'); +const BridgeOptimismMock = artifacts.require('BridgeOptimismMock'); +const BridgePolygonChildMock = artifacts.require('BridgePolygonChildMock'); + +class BridgeHelper { + static async deploy(type) { + return new BridgeHelper(await deployBridge(type)); + } + + constructor(bridge) { + this.bridge = bridge; + this.address = bridge.address; + } + + call(from, target, selector = undefined, args = []) { + return this.bridge.relayAs( + target.address || target, + selector ? target.contract.methods[selector](...args).encodeABI() : '0x', + from, + ); + } +} + +async function deployBridge(type = 'Arbitrum-L2') { + switch (type) { + case 'AMB': + return BridgeAMBMock.new(); + + case 'Arbitrum-L1': + return BridgeArbitrumL1Mock.new(); + + case 'Arbitrum-L2': { + const instance = await BridgeArbitrumL2Mock.new(); + const code = await web3.eth.getCode(instance.address); + await promisify(web3.currentProvider.send.bind(web3.currentProvider))({ + jsonrpc: '2.0', + method: 'hardhat_setCode', + params: ['0x0000000000000000000000000000000000000064', code], + id: new Date().getTime(), + }); + return BridgeArbitrumL2Mock.at('0x0000000000000000000000000000000000000064'); + } + + case 'Optimism': + return BridgeOptimismMock.new(); + + case 'Polygon-Child': + return BridgePolygonChildMock.new(); + + default: + throw new Error(`CrossChain: ${type} is not supported`); + } +} + +module.exports = { + BridgeHelper, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/customError.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/customError.js new file mode 100644 index 0000000..3cfcd72 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/customError.js @@ -0,0 +1,24 @@ +const { config } = require('hardhat'); + +const optimizationsEnabled = config.solidity.compilers.some(c => c.settings.optimizer.enabled); + +/** Revert handler that supports custom errors. */ +async function expectRevertCustomError(promise, reason) { + try { + await promise; + expect.fail("Expected promise to throw but it didn't"); + } catch (revert) { + if (reason) { + if (optimizationsEnabled) { + // Optimizations currently mess with Hardhat's decoding of custom errors + expect(revert.message).to.include.oneOf([reason, 'unrecognized return data or custom error']); + } else { + expect(revert.message).to.include(reason); + } + } + } +} + +module.exports = { + expectRevertCustomError, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/eip712.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/eip712.js new file mode 100644 index 0000000..b12a623 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/eip712.js @@ -0,0 +1,67 @@ +const ethSigUtil = require('eth-sig-util'); +const keccak256 = require('keccak256'); + +const EIP712Domain = [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + { name: 'salt', type: 'bytes32' }, +]; + +const Permit = [ + { name: 'owner', type: 'address' }, + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint256' }, +]; + +function bufferToHexString(buffer) { + return '0x' + buffer.toString('hex'); +} + +function hexStringToBuffer(hexstr) { + return Buffer.from(hexstr.replace(/^0x/, ''), 'hex'); +} + +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', domain, { EIP712Domain: domainType(domain) }), + ); +} + +function hashTypedData(domain, structHash) { + return bufferToHexString( + keccak256(Buffer.concat(['0x1901', domainSeparator(domain), structHash].map(str => hexStringToBuffer(str)))), + ); +} + +module.exports = { + Permit, + getDomain, + domainType, + domainSeparator, + hashTypedData, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/enums.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/enums.js new file mode 100644 index 0000000..ced6c38 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/enums.js @@ -0,0 +1,12 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +function Enum(...options) { + return Object.fromEntries(options.map((key, i) => [key, new BN(i)])); +} + +module.exports = { + Enum, + ProposalState: Enum('Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'), + VoteType: Enum('Against', 'For', 'Abstain'), + Rounding: Enum('Down', 'Up', 'Zero'), +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/erc1967.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/erc1967.js new file mode 100644 index 0000000..9abbcc8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/erc1967.js @@ -0,0 +1,24 @@ +const ImplementationLabel = 'eip1967.proxy.implementation'; +const AdminLabel = 'eip1967.proxy.admin'; +const BeaconLabel = 'eip1967.proxy.beacon'; + +function labelToSlot(label) { + return '0x' + web3.utils.toBN(web3.utils.keccak256(label)).subn(1).toString(16); +} + +function getSlot(address, slot) { + return web3.eth.getStorageAt( + web3.utils.isAddress(address) ? address : address.address, + web3.utils.isHex(slot) ? slot : labelToSlot(slot), + ); +} + +module.exports = { + ImplementationLabel, + AdminLabel, + BeaconLabel, + ImplementationSlot: labelToSlot(ImplementationLabel), + AdminSlot: labelToSlot(AdminLabel), + BeaconSlot: labelToSlot(BeaconLabel), + getSlot, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/governance.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/governance.js new file mode 100644 index 0000000..4b38b75 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/governance.js @@ -0,0 +1,201 @@ +const { forward } = require('../helpers/time'); + +function zip(...args) { + return Array(Math.max(...args.map(array => array.length))) + .fill() + .map((_, i) => args.map(array => array[i])); +} + +function concatHex(...args) { + return web3.utils.bytesToHex([].concat(...args.map(h => web3.utils.hexToBytes(h || '0x')))); +} + +function concatOpts(args, opts = null) { + return opts ? args.concat(opts) : args; +} + +class GovernorHelper { + constructor(governor, mode = 'blocknumber') { + this.governor = governor; + this.mode = mode; + } + + delegate(delegation = {}, opts = null) { + return Promise.all([ + delegation.token.delegate(delegation.to, { from: delegation.to }), + delegation.value && delegation.token.transfer(...concatOpts([delegation.to, delegation.value]), opts), + delegation.tokenId && + delegation.token + .ownerOf(delegation.tokenId) + .then(owner => + delegation.token.transferFrom(...concatOpts([owner, delegation.to, delegation.tokenId], opts)), + ), + ]); + } + + propose(opts = null) { + const proposal = this.currentProposal; + + return this.governor.methods[ + proposal.useCompatibilityInterface + ? 'propose(address[],uint256[],string[],bytes[],string)' + : 'propose(address[],uint256[],bytes[],string)' + ](...concatOpts(proposal.fullProposal, opts)); + } + + queue(opts = null) { + const proposal = this.currentProposal; + + return proposal.useCompatibilityInterface + ? this.governor.methods['queue(uint256)'](...concatOpts([proposal.id], opts)) + : this.governor.methods['queue(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } + + execute(opts = null) { + const proposal = this.currentProposal; + + return proposal.useCompatibilityInterface + ? this.governor.methods['execute(uint256)'](...concatOpts([proposal.id], opts)) + : this.governor.methods['execute(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } + + cancel(visibility = 'external', opts = null) { + const proposal = this.currentProposal; + + switch (visibility) { + case 'external': + 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), + ); + default: + throw new Error(`unsuported visibility "${visibility}"`); + } + } + + vote(vote = {}, opts = null) { + const proposal = this.currentProposal; + + return vote.signature + ? // if signature, and either params or reason → + vote.params || vote.reason + ? vote + .signature(this.governor, { + proposalId: proposal.id, + support: vote.support, + reason: vote.reason || '', + params: vote.params || '', + }) + .then(({ v, r, s }) => + this.governor.castVoteWithReasonAndParamsBySig( + ...concatOpts([proposal.id, vote.support, vote.reason || '', vote.params || '', v, r, s], opts), + ), + ) + : vote + .signature(this.governor, { + proposalId: proposal.id, + support: vote.support, + }) + .then(({ v, r, s }) => + this.governor.castVoteBySig(...concatOpts([proposal.id, vote.support, v, r, s], opts)), + ) + : vote.params + ? // otherwise if params + this.governor.castVoteWithReasonAndParams( + ...concatOpts([proposal.id, vote.support, vote.reason || '', vote.params], opts), + ) + : vote.reason + ? // otherwise if reason + this.governor.castVoteWithReason(...concatOpts([proposal.id, vote.support, vote.reason], opts)) + : this.governor.castVote(...concatOpts([proposal.id, vote.support], opts)); + } + + async waitForSnapshot(offset = 0) { + const proposal = this.currentProposal; + const timepoint = await this.governor.proposalSnapshot(proposal.id); + return forward[this.mode](timepoint.addn(offset)); + } + + async waitForDeadline(offset = 0) { + const proposal = this.currentProposal; + const timepoint = await this.governor.proposalDeadline(proposal.id); + return forward[this.mode](timepoint.addn(offset)); + } + + async waitForEta(offset = 0) { + const proposal = this.currentProposal; + const timestamp = await this.governor.proposalEta(proposal.id); + return forward.timestamp(timestamp.addn(offset)); + } + + /** + * Specify a proposal either as + * 1) an array of objects [{ target, value, data, signature? }] + * 2) an object of arrays { targets: [], values: [], data: [], signatures?: [] } + */ + setProposal(actions, description) { + let targets, values, signatures, data, useCompatibilityInterface; + + if (Array.isArray(actions)) { + useCompatibilityInterface = actions.some(a => 'signature' in a); + targets = actions.map(a => a.target); + values = actions.map(a => a.value || '0'); + signatures = actions.map(a => a.signature || ''); + data = actions.map(a => a.data || '0x'); + } else { + useCompatibilityInterface = Array.isArray(actions.signatures); + ({ targets, values, signatures = [], data } = actions); + } + + const fulldata = zip( + signatures.map(s => s && web3.eth.abi.encodeFunctionSignature(s)), + data, + ).map(hexs => concatHex(...hexs)); + + const descriptionHash = web3.utils.keccak256(description); + + // condensed version for queueing end executing + const shortProposal = [targets, values, fulldata, descriptionHash]; + + // full version for proposing + const fullProposal = [targets, values, ...(useCompatibilityInterface ? [signatures] : []), data, description]; + + // proposal id + const id = web3.utils.toBN( + web3.utils.keccak256( + web3.eth.abi.encodeParameters(['address[]', 'uint256[]', 'bytes[]', 'bytes32'], shortProposal), + ), + ); + + this.currentProposal = { + id, + targets, + values, + signatures, + data, + fulldata, + description, + descriptionHash, + shortProposal, + fullProposal, + useCompatibilityInterface, + }; + + return this.currentProposal; + } +} + +module.exports = { + GovernorHelper, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/map-values.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/map-values.js new file mode 100644 index 0000000..d2f7b2a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/map-values.js @@ -0,0 +1,7 @@ +function mapValues(obj, fn) { + return Object.fromEntries([...Object.entries(obj)].map(([k, v]) => [k, fn(v)])); +} + +module.exports = { + mapValues, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/sign.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/sign.js new file mode 100644 index 0000000..d537116 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/sign.js @@ -0,0 +1,63 @@ +function toEthSignedMessageHash(messageHex) { + const messageBuffer = Buffer.from(messageHex.substring(2), 'hex'); + const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`); + 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 + * @param contract TruffleContract + * @param signer address + * @param redeemer address + * @param methodName string + * @param methodArgs any[] + */ +const getSignFor = + (contract, signer) => + (redeemer, methodName, methodArgs = []) => { + const parts = [contract.address, redeemer]; + + const REAL_SIGNATURE_SIZE = 2 * 65; // 65 bytes in hexadecimal string length + const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length + const DUMMY_SIGNATURE = `0x${web3.utils.padLeft('', REAL_SIGNATURE_SIZE)}`; + + // if we have a method, add it to the parts that we're signing + if (methodName) { + if (methodArgs.length > 0) { + parts.push( + contract.contract.methods[methodName](...methodArgs.concat([DUMMY_SIGNATURE])) + .encodeABI() + .slice(0, -1 * PADDED_SIGNATURE_SIZE), + ); + } else { + const abi = contract.abi.find(abi => abi.name === methodName); + parts.push(abi.signature); + } + } + + // return the signature of the "Ethereum Signed Message" hash of the hash of `parts` + const messageHex = web3.utils.soliditySha3(...parts); + return web3.eth.sign(messageHex, signer); + }; + +module.exports = { + toEthSignedMessageHash, + toDataWithIntendedValidatorHash, + getSignFor, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/time.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/time.js new file mode 100644 index 0000000..30df8dc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/time.js @@ -0,0 +1,17 @@ +const ozHelpers = require('@openzeppelin/test-helpers'); +const helpers = require('@nomicfoundation/hardhat-network-helpers'); + +module.exports = { + clock: { + 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: ozHelpers.time.advanceBlockTo, + timestamp: helpers.time.increaseTo, + }, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/helpers/txpool.js b/lib/openzeppelin-contracts-v4.9.3/test/helpers/txpool.js new file mode 100644 index 0000000..ecdba54 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/helpers/txpool.js @@ -0,0 +1,38 @@ +const { network } = require('hardhat'); +const { promisify } = require('util'); + +const queue = promisify(setImmediate); + +async function countPendingTransactions() { + return parseInt(await network.provider.send('eth_getBlockTransactionCountByNumber', ['pending'])); +} + +async function batchInBlock(txs) { + try { + // disable auto-mining + await network.provider.send('evm_setAutomine', [false]); + // send all transactions + const promises = txs.map(fn => fn()); + // wait for node to have all pending transactions + while (txs.length > (await countPendingTransactions())) { + await queue(); + } + // mine one block + await network.provider.send('evm_mine'); + // fetch receipts + const receipts = await Promise.all(promises); + // Sanity check, all tx should be in the same block + const minedBlocks = new Set(receipts.map(({ receipt }) => receipt.blockNumber)); + expect(minedBlocks.size).to.equal(1); + + return receipts; + } finally { + // enable auto-mining + await network.provider.send('evm_setAutomine', [true]); + } +} + +module.exports = { + countPendingTransactions, + batchInBlock, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/metatx/ERC2771Context.test.js b/lib/openzeppelin-contracts-v4.9.3/test/metatx/ERC2771Context.test.js new file mode 100644 index 0000000..5108d11 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/metatx/ERC2771Context.test.js @@ -0,0 +1,122 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); + +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC2771ContextMock = artifacts.require('ERC2771ContextMock'); +const MinimalForwarder = artifacts.require('MinimalForwarder'); +const ContextMockCaller = artifacts.require('ContextMockCaller'); + +const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior'); + +contract('ERC2771Context', function (accounts) { + const [, trustedForwarder] = accounts; + + beforeEach(async function () { + this.forwarder = await MinimalForwarder.new(); + this.recipient = await ERC2771ContextMock.new(this.forwarder.address); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }; + }); + + it('recognize trusted forwarder', async function () { + expect(await this.recipient.isTrustedForwarder(this.forwarder.address)); + }); + + context('when called directly', function () { + beforeEach(async function () { + this.context = this.recipient; // The Context behavior expects the contract in this.context + this.caller = await ContextMockCaller.new(); + }); + + shouldBehaveLikeRegularContext(...accounts); + }); + + context('when receiving a relayed call', function () { + beforeEach(async function () { + this.wallet = Wallet.generate(); + this.sender = web3.utils.toChecksumAddress(this.wallet.getAddressString()); + this.data = { + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + }; + }); + + describe('msgSender', function () { + it('returns the relayed transaction original sender', async function () { + const data = this.recipient.contract.methods.msgSender().encodeABI(); + + const req = { + from: this.sender, + to: this.recipient.address, + value: '0', + gas: '100000', + nonce: (await this.forwarder.getNonce(this.sender)).toString(), + data, + }; + + const sign = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { data: { ...this.data, message: req } }); + expect(await this.forwarder.verify(req, sign)).to.equal(true); + + const { tx } = await this.forwarder.execute(req, sign); + await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Sender', { sender: this.sender }); + }); + + it('returns the original sender when calldata length is less than 20 bytes (address length)', async function () { + // The forwarder doesn't produce calls with calldata length less than 20 bytes + const recipient = await ERC2771ContextMock.new(trustedForwarder); + + const { receipt } = await recipient.msgSender({ from: trustedForwarder }); + + await expectEvent(receipt, 'Sender', { sender: trustedForwarder }); + }); + }); + + describe('msgData', function () { + it('returns the relayed transaction original data', async function () { + const integerValue = '42'; + const stringValue = 'OpenZeppelin'; + const data = this.recipient.contract.methods.msgData(integerValue, stringValue).encodeABI(); + + const req = { + from: this.sender, + to: this.recipient.address, + value: '0', + gas: '100000', + nonce: (await this.forwarder.getNonce(this.sender)).toString(), + data, + }; + + const sign = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { data: { ...this.data, message: req } }); + expect(await this.forwarder.verify(req, sign)).to.equal(true); + + const { tx } = await this.forwarder.execute(req, sign); + await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Data', { data, integerValue, stringValue }); + }); + }); + + it('returns the full original data when calldata length is less than 20 bytes (address length)', async function () { + // The forwarder doesn't produce calls with calldata length less than 20 bytes + const recipient = await ERC2771ContextMock.new(trustedForwarder); + + const { receipt } = await recipient.msgDataShort({ from: trustedForwarder }); + + const data = recipient.contract.methods.msgDataShort().encodeABI(); + await expectEvent(receipt, 'DataShort', { data }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/metatx/MinimalForwarder.test.js b/lib/openzeppelin-contracts-v4.9.3/test/metatx/MinimalForwarder.test.js new file mode 100644 index 0000000..4884cc7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/metatx/MinimalForwarder.test.js @@ -0,0 +1,169 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); + +const { expectRevert, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const MinimalForwarder = artifacts.require('MinimalForwarder'); +const CallReceiverMock = artifacts.require('CallReceiverMock'); + +contract('MinimalForwarder', function (accounts) { + beforeEach(async function () { + this.forwarder = await MinimalForwarder.new(); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'data', type: 'bytes' }, + ], + }; + }); + + context('with message', function () { + beforeEach(async function () { + this.wallet = Wallet.generate(); + this.sender = web3.utils.toChecksumAddress(this.wallet.getAddressString()); + this.req = { + from: this.sender, + to: constants.ZERO_ADDRESS, + value: '0', + gas: '100000', + nonce: Number(await this.forwarder.getNonce(this.sender)), + data: '0x', + }; + this.sign = () => + ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { + data: { + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + message: this.req, + }, + }); + }); + + context('verify', function () { + context('valid signature', function () { + beforeEach(async function () { + expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); + }); + + it('success', async function () { + expect(await this.forwarder.verify(this.req, this.sign())).to.be.equal(true); + }); + + afterEach(async function () { + expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); + }); + }); + + context('invalid signature', function () { + it('tampered from', async function () { + expect(await this.forwarder.verify({ ...this.req, from: accounts[0] }, this.sign())).to.be.equal(false); + }); + it('tampered to', async function () { + expect(await this.forwarder.verify({ ...this.req, to: accounts[0] }, this.sign())).to.be.equal(false); + }); + it('tampered value', async function () { + expect(await this.forwarder.verify({ ...this.req, value: web3.utils.toWei('1') }, this.sign())).to.be.equal( + false, + ); + }); + it('tampered nonce', async function () { + expect(await this.forwarder.verify({ ...this.req, nonce: this.req.nonce + 1 }, this.sign())).to.be.equal( + false, + ); + }); + it('tampered data', async function () { + expect(await this.forwarder.verify({ ...this.req, data: '0x1742' }, this.sign())).to.be.equal(false); + }); + it('tampered signature', async function () { + const tamperedsign = web3.utils.hexToBytes(this.sign()); + tamperedsign[42] ^= 0xff; + expect(await this.forwarder.verify(this.req, web3.utils.bytesToHex(tamperedsign))).to.be.equal(false); + }); + }); + }); + + context('execute', function () { + context('valid signature', function () { + beforeEach(async function () { + expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal(web3.utils.toBN(this.req.nonce)); + }); + + it('success', async function () { + await this.forwarder.execute(this.req, this.sign()); // expect to not revert + }); + + afterEach(async function () { + expect(await this.forwarder.getNonce(this.req.from)).to.be.bignumber.equal( + web3.utils.toBN(this.req.nonce + 1), + ); + }); + }); + + context('invalid signature', function () { + it('tampered from', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, from: accounts[0] }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered to', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, to: accounts[0] }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered value', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, value: web3.utils.toWei('1') }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered nonce', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, nonce: this.req.nonce + 1 }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered data', async function () { + await expectRevert( + this.forwarder.execute({ ...this.req, data: '0x1742' }, this.sign()), + 'MinimalForwarder: signature does not match request', + ); + }); + it('tampered signature', async function () { + const tamperedsign = web3.utils.hexToBytes(this.sign()); + tamperedsign[42] ^= 0xff; + await expectRevert( + this.forwarder.execute(this.req, web3.utils.bytesToHex(tamperedsign)), + 'MinimalForwarder: signature does not match request', + ); + }); + }); + + it('bubble out of gas', async function () { + const receiver = await CallReceiverMock.new(); + const gasAvailable = 100000; + this.req.to = receiver.address; + this.req.data = receiver.contract.methods.mockFunctionOutOfGas().encodeABI(); + this.req.gas = 1000000; + + await expectRevert.assertion(this.forwarder.execute(this.req, this.sign(), { gas: gasAvailable })); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + expect(gasUsed).to.be.equal(gasAvailable); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/migrate-imports.test.js b/lib/openzeppelin-contracts-v4.9.3/test/migrate-imports.test.js new file mode 100644 index 0000000..5a5c37a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/migrate-imports.test.js @@ -0,0 +1,33 @@ +const path = require('path'); +const { + promises: fs, + constants: { F_OK }, +} = require('fs'); +const { expect } = require('chai'); + +const { pathUpdates, updateImportPaths, getUpgradeablePath } = require('../scripts/migrate-imports.js'); + +describe('migrate-imports.js', function () { + it('every new path exists', async function () { + for (const p of Object.values(pathUpdates)) { + 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); + } + } + }); + + it('replaces import paths in a file', async function () { + const source = ` +import '@openzeppelin/contracts/math/Math.sol'; +import '@openzeppelin/contracts-upgradeable/math/MathUpgradeable.sol'; + `; + const expected = ` +import '@openzeppelin/contracts/utils/math/Math.sol'; +import '@openzeppelin/contracts-upgradeable/utils/math/MathUpgradeable.sol'; + `; + expect(updateImportPaths(source)).to.equal(expected); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/Clones.behaviour.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/Clones.behaviour.js new file mode 100644 index 0000000..b5fd3c5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/Clones.behaviour.js @@ -0,0 +1,136 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const DummyImplementation = artifacts.require('DummyImplementation'); + +module.exports = function shouldBehaveLikeClone(createClone) { + before('deploy implementation', async function () { + this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('initializes the proxy', async function () { + const dummy = new DummyImplementation(this.proxy); + expect(await dummy.value()).to.be.bignumber.equal(value.toString()); + }); + + it('has expected balance', async function () { + expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString()); + }); + }; + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createClone(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100; + const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods + .initializeNonPayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createClone(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42; + const initializeData = new DummyImplementation('').contract.methods + .initializePayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/Clones.test.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/Clones.test.js new file mode 100644 index 0000000..947b2ed --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/Clones.test.js @@ -0,0 +1,61 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { computeCreate2Address } = require('../helpers/create2'); +const { expect } = require('chai'); + +const shouldBehaveLikeClone = require('./Clones.behaviour'); + +const Clones = artifacts.require('$Clones'); + +contract('Clones', function (accounts) { + const [deployer] = accounts; + + describe('clone', function () { + shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { + const factory = await Clones.new(); + const receipt = await factory.$clone(implementation); + const address = receipt.logs.find(({ event }) => event === 'return$clone').args.instance; + await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); + return { address }; + }); + }); + + describe('cloneDeterministic', function () { + shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + const receipt = await factory.$cloneDeterministic(implementation, salt); + const address = receipt.logs.find(({ event }) => event === 'return$cloneDeterministic').args.instance; + await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); + return { address }; + }); + + it('address already used', async function () { + const implementation = web3.utils.randomHex(20); + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + // deploy once + expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic'); + // deploy twice + await expectRevert(factory.$cloneDeterministic(implementation, salt), 'ERC1167: create2 failed'); + }); + + it('address prediction', async function () { + const implementation = web3.utils.randomHex(20); + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + const predicted = await factory.$predictDeterministicAddress(implementation, salt); + + const creationCode = [ + '0x3d602d80600a3d3981f3363d3d373d3d3d363d73', + implementation.replace(/0x/, '').toLowerCase(), + '5af43d82803e903d91602b57fd5bf3', + ].join(''); + + expect(computeCreate2Address(salt, creationCode, factory.address)).to.be.equal(predicted); + + expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic', { + instance: predicted, + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/ERC1967/ERC1967Proxy.test.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/ERC1967/ERC1967Proxy.test.js new file mode 100644 index 0000000..22df960 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/ERC1967/ERC1967Proxy.test.js @@ -0,0 +1,13 @@ +const shouldBehaveLikeProxy = require('../Proxy.behaviour'); + +const ERC1967Proxy = artifacts.require('ERC1967Proxy'); + +contract('ERC1967Proxy', function (accounts) { + const [proxyAdminOwner] = accounts; + + const createProxy = async function (implementation, _admin, initData, opts) { + return ERC1967Proxy.new(implementation, initData, opts); + }; + + shouldBehaveLikeProxy(createProxy, undefined, proxyAdminOwner); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/Proxy.behaviour.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/Proxy.behaviour.js new file mode 100644 index 0000000..0867b93 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/Proxy.behaviour.js @@ -0,0 +1,225 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { getSlot, ImplementationSlot } = require('../helpers/erc1967'); + +const { expect } = require('chai'); + +const DummyImplementation = artifacts.require('DummyImplementation'); + +module.exports = function shouldBehaveLikeProxy(createProxy, proxyAdminAddress, proxyCreator) { + it('cannot be initialized with a non-contract address', async function () { + const nonContractAddress = proxyCreator; + const initializeData = Buffer.from(''); + await expectRevert.unspecified( + createProxy(nonContractAddress, proxyAdminAddress, initializeData, { + from: proxyCreator, + }), + ); + }); + + before('deploy implementation', async function () { + this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('sets the implementation address', async function () { + const implementationSlot = await getSlot(this.proxy, ImplementationSlot); + const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40)); + expect(implementationAddress).to.be.equal(this.implementation); + }); + + it('initializes the proxy', async function () { + const dummy = new DummyImplementation(this.proxy); + expect(await dummy.value()).to.be.bignumber.equal(value.toString()); + }); + + it('has expected balance', async function () { + expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString()); + }); + }; + + describe('without initialization', function () { + const initializeData = Buffer.from(''); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ value: 0, balance: 0 }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + value, + }) + ).address; + }); + + assertProxyInitialization({ value: 0, balance: value }); + }); + }); + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified( + createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator, value }), + ); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100; + const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + value, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods + .initializeNonPayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified( + createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator, value }), + ); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42; + const initializeData = new DummyImplementation('').contract.methods + .initializePayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = ( + await createProxy(this.implementation, proxyAdminAddress, initializeData, { + from: proxyCreator, + value, + }) + ).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + + describe('reverting initialization', function () { + const initializeData = new DummyImplementation('').contract.methods.reverts().encodeABI(); + + it('reverts', async function () { + await expectRevert( + createProxy(this.implementation, proxyAdminAddress, initializeData, { from: proxyCreator }), + 'DummyImplementation reverted', + ); + }); + }); + }); +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/beacon/BeaconProxy.test.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/beacon/BeaconProxy.test.js new file mode 100644 index 0000000..968f00b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/beacon/BeaconProxy.test.js @@ -0,0 +1,139 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { getSlot, BeaconSlot } = require('../../helpers/erc1967'); + +const { expect } = require('chai'); + +const UpgradeableBeacon = artifacts.require('UpgradeableBeacon'); +const BeaconProxy = artifacts.require('BeaconProxy'); +const DummyImplementation = artifacts.require('DummyImplementation'); +const DummyImplementationV2 = artifacts.require('DummyImplementationV2'); +const BadBeaconNoImpl = artifacts.require('BadBeaconNoImpl'); +const BadBeaconNotContract = artifacts.require('BadBeaconNotContract'); + +contract('BeaconProxy', function (accounts) { + const [anotherAccount] = accounts; + + describe('bad beacon is not accepted', async function () { + it('non-contract beacon', async function () { + await expectRevert(BeaconProxy.new(anotherAccount, '0x'), 'ERC1967: new beacon is not a contract'); + }); + + it('non-compliant beacon', async function () { + const beacon = await BadBeaconNoImpl.new(); + await expectRevert.unspecified(BeaconProxy.new(beacon.address, '0x')); + }); + + it('non-contract implementation', async function () { + const beacon = await BadBeaconNotContract.new(); + await expectRevert(BeaconProxy.new(beacon.address, '0x'), 'ERC1967: beacon implementation is not a contract'); + }); + }); + + before('deploy implementation', async function () { + this.implementationV0 = await DummyImplementation.new(); + this.implementationV1 = await DummyImplementationV2.new(); + }); + + describe('initialization', function () { + before(function () { + this.assertInitialized = async ({ value, balance }) => { + const beaconSlot = await getSlot(this.proxy, BeaconSlot); + const beaconAddress = web3.utils.toChecksumAddress(beaconSlot.substr(-40)); + expect(beaconAddress).to.equal(this.beacon.address); + + const dummy = new DummyImplementation(this.proxy.address); + expect(await dummy.value()).to.bignumber.eq(value); + + expect(await web3.eth.getBalance(this.proxy.address)).to.bignumber.eq(balance); + }; + }); + + beforeEach('deploy beacon', async function () { + this.beacon = await UpgradeableBeacon.new(this.implementationV0.address); + }); + + it('no initialization', async function () { + const data = Buffer.from(''); + const balance = '10'; + this.proxy = await BeaconProxy.new(this.beacon.address, data, { value: balance }); + await this.assertInitialized({ value: '0', balance }); + }); + + it('non-payable initialization', async function () { + const value = '55'; + const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); + this.proxy = await BeaconProxy.new(this.beacon.address, data); + await this.assertInitialized({ value, balance: '0' }); + }); + + it('payable initialization', async function () { + const value = '55'; + const data = this.implementationV0.contract.methods.initializePayableWithValue(value).encodeABI(); + const balance = '100'; + this.proxy = await BeaconProxy.new(this.beacon.address, data, { value: balance }); + await this.assertInitialized({ value, balance }); + }); + + it('reverting initialization', async function () { + const data = this.implementationV0.contract.methods.reverts().encodeABI(); + await expectRevert(BeaconProxy.new(this.beacon.address, data), 'DummyImplementation reverted'); + }); + }); + + it('upgrade a proxy by upgrading its beacon', async function () { + const beacon = await UpgradeableBeacon.new(this.implementationV0.address); + + const value = '10'; + const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); + const proxy = await BeaconProxy.new(beacon.address, data); + + const dummy = new DummyImplementation(proxy.address); + + // test initial values + expect(await dummy.value()).to.bignumber.eq(value); + + // test initial version + expect(await dummy.version()).to.eq('V1'); + + // upgrade beacon + await beacon.upgradeTo(this.implementationV1.address); + + // test upgraded version + expect(await dummy.version()).to.eq('V2'); + }); + + it('upgrade 2 proxies by upgrading shared beacon', async function () { + const value1 = '10'; + const value2 = '42'; + + const beacon = await UpgradeableBeacon.new(this.implementationV0.address); + + const proxy1InitializeData = this.implementationV0.contract.methods + .initializeNonPayableWithValue(value1) + .encodeABI(); + const proxy1 = await BeaconProxy.new(beacon.address, proxy1InitializeData); + + const proxy2InitializeData = this.implementationV0.contract.methods + .initializeNonPayableWithValue(value2) + .encodeABI(); + const proxy2 = await BeaconProxy.new(beacon.address, proxy2InitializeData); + + const dummy1 = new DummyImplementation(proxy1.address); + const dummy2 = new DummyImplementation(proxy2.address); + + // test initial values + expect(await dummy1.value()).to.bignumber.eq(value1); + expect(await dummy2.value()).to.bignumber.eq(value2); + + // test initial version + expect(await dummy1.version()).to.eq('V1'); + expect(await dummy2.version()).to.eq('V1'); + + // upgrade beacon + await beacon.upgradeTo(this.implementationV1.address); + + // test upgraded version + expect(await dummy1.version()).to.eq('V2'); + expect(await dummy2.version()).to.eq('V2'); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/beacon/UpgradeableBeacon.test.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/beacon/UpgradeableBeacon.test.js new file mode 100644 index 0000000..d65f3e0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/beacon/UpgradeableBeacon.test.js @@ -0,0 +1,44 @@ +const { expectRevert, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const UpgradeableBeacon = artifacts.require('UpgradeableBeacon'); +const Implementation1 = artifacts.require('Implementation1'); +const Implementation2 = artifacts.require('Implementation2'); + +contract('UpgradeableBeacon', function (accounts) { + const [owner, other] = accounts; + + it('cannot be created with non-contract implementation', async function () { + await expectRevert(UpgradeableBeacon.new(accounts[0]), 'UpgradeableBeacon: implementation is not a contract'); + }); + + context('once deployed', async function () { + beforeEach('deploying beacon', async function () { + this.v1 = await Implementation1.new(); + this.beacon = await UpgradeableBeacon.new(this.v1.address, { from: owner }); + }); + + it('returns implementation', async function () { + expect(await this.beacon.implementation()).to.equal(this.v1.address); + }); + + it('can be upgraded by the owner', async function () { + const v2 = await Implementation2.new(); + const receipt = await this.beacon.upgradeTo(v2.address, { from: owner }); + expectEvent(receipt, 'Upgraded', { implementation: v2.address }); + expect(await this.beacon.implementation()).to.equal(v2.address); + }); + + it('cannot be upgraded to a non-contract', async function () { + await expectRevert( + this.beacon.upgradeTo(other, { from: owner }), + 'UpgradeableBeacon: implementation is not a contract', + ); + }); + + it('cannot be upgraded by other account', async function () { + const v2 = await Implementation2.new(); + await expectRevert(this.beacon.upgradeTo(v2.address, { from: other }), 'Ownable: caller is not the owner'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/ProxyAdmin.test.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/ProxyAdmin.test.js new file mode 100644 index 0000000..6d473d8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/ProxyAdmin.test.js @@ -0,0 +1,127 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +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; + + before('set implementations', async function () { + this.implementationV1 = await ImplV1.new(); + this.implementationV2 = await ImplV2.new(); + }); + + beforeEach(async function () { + const initializeData = Buffer.from(''); + this.proxyAdmin = await ProxyAdmin.new({ from: proxyAdminOwner }); + 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 () { + expect(await this.proxyAdmin.owner()).to.equal(proxyAdminOwner); + }); + + describe('#getProxyAdmin', function () { + it('returns proxyAdmin as admin of the proxy', async function () { + const admin = await this.proxyAdmin.getProxyAdmin(this.proxy.address); + expect(admin).to.be.equal(this.proxyAdmin.address); + }); + + it('call to invalid proxy', async function () { + await expectRevert.unspecified(this.proxyAdmin.getProxyAdmin(this.implementationV1.address)); + }); + }); + + describe('#changeProxyAdmin', function () { + it('fails to change proxy admin if its not the proxy owner', async function () { + await expectRevert( + this.proxyAdmin.changeProxyAdmin(this.proxy.address, newAdmin, { from: anotherAccount }), + 'caller is not the owner', + ); + }); + + it('changes proxy admin', async function () { + await this.proxyAdmin.changeProxyAdmin(this.proxy.address, newAdmin, { from: proxyAdminOwner }); + expect(await this.proxy.admin.call({ from: newAdmin })).to.eq(newAdmin); + }); + }); + + describe('#getProxyImplementation', function () { + it('returns proxy implementation address', async function () { + const implementationAddress = await this.proxyAdmin.getProxyImplementation(this.proxy.address); + expect(implementationAddress).to.be.equal(this.implementationV1.address); + }); + + it('call to invalid proxy', async function () { + await expectRevert.unspecified(this.proxyAdmin.getProxyImplementation(this.implementationV1.address)); + }); + }); + + describe('#upgrade', function () { + context('with unauthorized account', function () { + it('fails to upgrade', async function () { + await expectRevert( + this.proxyAdmin.upgrade(this.proxy.address, this.implementationV2.address, { from: anotherAccount }), + 'caller is not the owner', + ); + }); + }); + + context('with authorized account', function () { + it('upgrades implementation', async function () { + await this.proxyAdmin.upgrade(this.proxy.address, this.implementationV2.address, { from: proxyAdminOwner }); + const implementationAddress = await this.proxyAdmin.getProxyImplementation(this.proxy.address); + expect(implementationAddress).to.be.equal(this.implementationV2.address); + }); + }); + }); + + describe('#upgradeAndCall', function () { + context('with unauthorized account', function () { + it('fails to upgrade', async function () { + const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI(); + await expectRevert( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: anotherAccount, + }), + 'caller is not the owner', + ); + }); + }); + + context('with authorized account', function () { + context('with invalid callData', function () { + it('fails to upgrade', async function () { + const callData = '0x12345678'; + await expectRevert.unspecified( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: proxyAdminOwner, + }), + ); + }); + }); + + context('with valid callData', function () { + it('upgrades implementation', async function () { + const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI(); + await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: proxyAdminOwner, + }); + const implementationAddress = await this.proxyAdmin.getProxyImplementation(this.proxy.address); + expect(implementationAddress).to.be.equal(this.implementationV2.address); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js new file mode 100644 index 0000000..5e3f561 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -0,0 +1,433 @@ +const { BN, expectRevert, expectEvent, constants } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { getSlot, ImplementationSlot, AdminSlot } = require('../../helpers/erc1967'); + +const { expect } = require('chai'); +const { web3 } = require('hardhat'); + +const Implementation1 = artifacts.require('Implementation1'); +const Implementation2 = artifacts.require('Implementation2'); +const Implementation3 = artifacts.require('Implementation3'); +const Implementation4 = artifacts.require('Implementation4'); +const MigratableMockV1 = artifacts.require('MigratableMockV1'); +const MigratableMockV2 = artifacts.require('MigratableMockV2'); +const MigratableMockV3 = artifacts.require('MigratableMockV3'); +const InitializableMock = artifacts.require('InitializableMock'); +const DummyImplementation = artifacts.require('DummyImplementation'); +const ClashingImplementation = artifacts.require('ClashingImplementation'); + +module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProxy, accounts) { + const [proxyAdminAddress, proxyAdminOwner, anotherAccount] = accounts; + + before(async function () { + this.implementationV0 = (await DummyImplementation.new()).address; + this.implementationV1 = (await DummyImplementation.new()).address; + }); + + beforeEach(async function () { + const initializeData = Buffer.from(''); + this.proxy = await createProxy(this.implementationV0, proxyAdminAddress, initializeData, { + from: proxyAdminOwner, + }); + this.proxyAddress = this.proxy.address; + }); + + describe('implementation', function () { + it('returns the current implementation address', async function () { + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); + + expect(implementation).to.be.equal(this.implementationV0); + }); + + it('delegates to the implementation', async function () { + const dummy = new DummyImplementation(this.proxyAddress); + const value = await dummy.get(); + + expect(value).to.equal(true); + }); + }); + + describe('upgradeTo', function () { + describe('when the sender is the admin', function () { + const from = proxyAdminAddress; + + describe('when the given implementation is different from the current one', function () { + it('upgrades to the requested implementation', async function () { + await this.proxy.upgradeTo(this.implementationV1, { from }); + + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.implementationV1); + }); + + it('emits an event', async function () { + expectEvent(await this.proxy.upgradeTo(this.implementationV1, { from }), 'Upgraded', { + implementation: this.implementationV1, + }); + }); + }); + + describe('when the given implementation is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.proxy.upgradeTo(ZERO_ADDRESS, { from }), + 'ERC1967: new implementation is not a contract', + ); + }); + }); + }); + + describe('when the sender is not the admin', function () { + const from = anotherAccount; + + it('reverts', async function () { + await expectRevert.unspecified(this.proxy.upgradeTo(this.implementationV1, { from })); + }); + }); + }); + + describe('upgradeToAndCall', function () { + describe('without migrations', function () { + beforeEach(async function () { + this.behavior = await InitializableMock.new(); + }); + + describe('when the call does not fail', function () { + const initializeData = new InitializableMock('').contract.methods['initializeWithX(uint256)'](42).encodeABI(); + + describe('when the sender is the admin', function () { + const from = proxyAdminAddress; + const value = 1e5; + + beforeEach(async function () { + this.receipt = await this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from, value }); + }); + + it('upgrades to the requested implementation', async function () { + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.behavior.address); + }); + + it('emits an event', function () { + expectEvent(this.receipt, 'Upgraded', { implementation: this.behavior.address }); + }); + + it('calls the initializer function', async function () { + const migratable = new InitializableMock(this.proxyAddress); + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + }); + + it('sends given value to the proxy', async function () { + const balance = await web3.eth.getBalance(this.proxyAddress); + expect(balance.toString()).to.be.bignumber.equal(value.toString()); + }); + + it('uses the storage of the proxy', async function () { + // storage layout should look as follows: + // - 0: Initializable storage ++ initializerRan ++ onlyInitializingRan + // - 1: x + const storedValue = await web3.eth.getStorageAt(this.proxyAddress, 1); + expect(parseInt(storedValue)).to.eq(42); + }); + }); + + describe('when the sender is not the admin', function () { + it('reverts', async function () { + await expectRevert.unspecified( + this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from: anotherAccount }), + ); + }); + }); + }); + + describe('when the call does fail', function () { + const initializeData = new InitializableMock('').contract.methods.fail().encodeABI(); + + it('reverts', async function () { + await expectRevert.unspecified( + this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from: proxyAdminAddress }), + ); + }); + }); + }); + + describe('with migrations', function () { + describe('when the sender is the admin', function () { + const from = proxyAdminAddress; + const value = 1e5; + + describe('when upgrading to V1', function () { + const v1MigrationData = new MigratableMockV1('').contract.methods.initialize(42).encodeABI(); + + beforeEach(async function () { + this.behaviorV1 = await MigratableMockV1.new(); + this.balancePreviousV1 = new BN(await web3.eth.getBalance(this.proxyAddress)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV1.address, v1MigrationData, { from, value }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.behaviorV1.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV1.address }); + }); + + it("calls the 'initialize' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV1(this.proxyAddress); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + + const balance = await web3.eth.getBalance(this.proxyAddress); + expect(new BN(balance)).to.be.bignumber.equal(this.balancePreviousV1.addn(value)); + }); + + describe('when upgrading to V2', function () { + const v2MigrationData = new MigratableMockV2('').contract.methods.migrate(10, 42).encodeABI(); + + beforeEach(async function () { + this.behaviorV2 = await MigratableMockV2.new(); + this.balancePreviousV2 = new BN(await web3.eth.getBalance(this.proxyAddress)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV2.address, v2MigrationData, { + from, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.behaviorV2.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV2.address }); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV2(this.proxyAddress); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('10'); + + const y = await migratable.y(); + expect(y).to.be.bignumber.equal('42'); + + const balance = new BN(await web3.eth.getBalance(this.proxyAddress)); + expect(balance).to.be.bignumber.equal(this.balancePreviousV2.addn(value)); + }); + + describe('when upgrading to V3', function () { + const v3MigrationData = new MigratableMockV3('').contract.methods['migrate()']().encodeABI(); + + beforeEach(async function () { + this.behaviorV3 = await MigratableMockV3.new(); + this.balancePreviousV3 = new BN(await web3.eth.getBalance(this.proxyAddress)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV3.address, v3MigrationData, { + from, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await this.proxy.implementation({ from: proxyAdminAddress }); + expect(implementation).to.be.equal(this.behaviorV3.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV3.address }); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV3(this.proxyAddress); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + + const y = await migratable.y(); + expect(y).to.be.bignumber.equal('10'); + + const balance = new BN(await web3.eth.getBalance(this.proxyAddress)); + expect(balance).to.be.bignumber.equal(this.balancePreviousV3.addn(value)); + }); + }); + }); + }); + }); + + describe('when the sender is not the admin', function () { + const from = anotherAccount; + + it('reverts', async function () { + const behaviorV1 = await MigratableMockV1.new(); + const v1MigrationData = new MigratableMockV1('').contract.methods.initialize(42).encodeABI(); + await expectRevert.unspecified(this.proxy.upgradeToAndCall(behaviorV1.address, v1MigrationData, { from })); + }); + }); + }); + }); + + describe('changeAdmin', function () { + describe('when the new proposed admin is not the zero address', function () { + const newAdmin = anotherAccount; + + describe('when the sender is the admin', function () { + beforeEach('transferring', async function () { + this.receipt = await this.proxy.changeAdmin(newAdmin, { from: proxyAdminAddress }); + }); + + it('assigns new proxy admin', async function () { + const newProxyAdmin = await this.proxy.admin({ from: newAdmin }); + expect(newProxyAdmin).to.be.equal(anotherAccount); + }); + + it('emits an event', function () { + expectEvent(this.receipt, 'AdminChanged', { + previousAdmin: proxyAdminAddress, + newAdmin: newAdmin, + }); + }); + }); + + describe('when the sender is not the admin', function () { + it('reverts', async function () { + await expectRevert.unspecified(this.proxy.changeAdmin(newAdmin, { from: anotherAccount })); + }); + }); + }); + + describe('when the new proposed admin is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.proxy.changeAdmin(ZERO_ADDRESS, { from: proxyAdminAddress }), + 'ERC1967: new admin is the zero address', + ); + }); + }); + }); + + describe('storage', function () { + it('should store the implementation address in specified location', async function () { + const implementationSlot = await getSlot(this.proxy, ImplementationSlot); + const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40)); + expect(implementationAddress).to.be.equal(this.implementationV0); + }); + + it('should store the admin proxy in specified location', async function () { + const proxyAdminSlot = await getSlot(this.proxy, AdminSlot); + const proxyAdminAddress = web3.utils.toChecksumAddress(proxyAdminSlot.substr(-40)); + expect(proxyAdminAddress).to.be.equal(proxyAdminAddress); + }); + }); + + describe('transparent proxy', function () { + beforeEach('creating proxy', async function () { + const initializeData = Buffer.from(''); + this.impl = await ClashingImplementation.new(); + this.proxy = await createProxy(this.impl.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + this.clashing = new ClashingImplementation(this.proxy.address); + }); + + it('proxy admin cannot call delegated functions', async function () { + await expectRevert( + this.clashing.delegatedFunction({ from: proxyAdminAddress }), + 'TransparentUpgradeableProxy: admin cannot fallback to proxy target', + ); + }); + + 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({ 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({ 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({ from: proxyAdminAddress, value: 1 })); + }); + + it('when sender is other value should be accepted', async function () { + const value = await this.proxy.admin({ from: anotherAccount, value: 1 }); + expect(value).to.be.equal('0x0000000000000000000000000000000011111142'); + }); + }); + }); + + describe('regression', () => { + const initializeData = Buffer.from(''); + + it('should add new function', async () => { + const instance1 = await Implementation1.new(); + const proxy = await createProxy(instance1.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const proxyInstance1 = new Implementation1(proxy.address); + await proxyInstance1.setValue(42); + + const instance2 = await Implementation2.new(); + await proxy.upgradeTo(instance2.address, { from: proxyAdminAddress }); + + const proxyInstance2 = new Implementation2(proxy.address); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('42'); + }); + + it('should remove function', async () => { + const instance2 = await Implementation2.new(); + const proxy = await createProxy(instance2.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const proxyInstance2 = new Implementation2(proxy.address); + await proxyInstance2.setValue(42); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('42'); + + const instance1 = await Implementation1.new(); + await proxy.upgradeTo(instance1.address, { from: proxyAdminAddress }); + + const proxyInstance1 = new Implementation2(proxy.address); + await expectRevert.unspecified(proxyInstance1.getValue()); + }); + + it('should change function signature', async () => { + const instance1 = await Implementation1.new(); + const proxy = await createProxy(instance1.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const proxyInstance1 = new Implementation1(proxy.address); + await proxyInstance1.setValue(42); + + const instance3 = await Implementation3.new(); + await proxy.upgradeTo(instance3.address, { from: proxyAdminAddress }); + const proxyInstance3 = new Implementation3(proxy.address); + + const res = await proxyInstance3.getValue(8); + expect(res.toString()).to.eq('50'); + }); + + it('should add fallback function', async () => { + const initializeData = Buffer.from(''); + const instance1 = await Implementation1.new(); + const proxy = await createProxy(instance1.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const instance4 = await Implementation4.new(); + await proxy.upgradeTo(instance4.address, { from: proxyAdminAddress }); + const proxyInstance4 = new Implementation4(proxy.address); + + const data = '0x'; + await web3.eth.sendTransaction({ to: proxy.address, from: anotherAccount, data }); + + const res = await proxyInstance4.getValue(); + expect(res.toString()).to.eq('1'); + }); + + it('should remove fallback function', async () => { + const instance4 = await Implementation4.new(); + const proxy = await createProxy(instance4.address, proxyAdminAddress, initializeData, { from: proxyAdminOwner }); + + const instance2 = await Implementation2.new(); + await proxy.upgradeTo(instance2.address, { from: proxyAdminAddress }); + + const data = '0x'; + await expectRevert.unspecified(web3.eth.sendTransaction({ to: proxy.address, from: anotherAccount, data })); + + const proxyInstance2 = new Implementation2(proxy.address); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('0'); + }); + }); +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/TransparentUpgradeableProxy.test.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/TransparentUpgradeableProxy.test.js new file mode 100644 index 0000000..d60a31a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/transparent/TransparentUpgradeableProxy.test.js @@ -0,0 +1,17 @@ +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) { + const { address } = await TransparentUpgradeableProxy.new(logic, admin, initData, opts); + return ITransparentUpgradeableProxy.at(address); + }; + + shouldBehaveLikeProxy(createProxy, proxyAdminAddress, proxyAdminOwner); + shouldBehaveLikeTransparentUpgradeableProxy(createProxy, accounts); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/utils/Initializable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/utils/Initializable.test.js new file mode 100644 index 0000000..39c820b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/utils/Initializable.test.js @@ -0,0 +1,218 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const InitializableMock = artifacts.require('InitializableMock'); +const ConstructorInitializableMock = artifacts.require('ConstructorInitializableMock'); +const ChildConstructorInitializableMock = artifacts.require('ChildConstructorInitializableMock'); +const ReinitializerMock = artifacts.require('ReinitializerMock'); +const SampleChild = artifacts.require('SampleChild'); +const DisableBad1 = artifacts.require('DisableBad1'); +const DisableBad2 = artifacts.require('DisableBad2'); +const DisableOk = artifacts.require('DisableOk'); + +contract('Initializable', function () { + describe('basic testing without inheritance', function () { + beforeEach('deploying', async function () { + this.contract = await InitializableMock.new(); + }); + + describe('before initialize', function () { + it('initializer has not run', async function () { + expect(await this.contract.initializerRan()).to.equal(false); + }); + + it('_initializing returns false before initialization', async function () { + expect(await this.contract.isInitializing()).to.equal(false); + }); + }); + + describe('after initialize', function () { + beforeEach('initializing', async function () { + await this.contract.initialize(); + }); + + it('initializer has run', async function () { + expect(await this.contract.initializerRan()).to.equal(true); + }); + + it('_initializing returns false after initialization', async function () { + expect(await this.contract.isInitializing()).to.equal(false); + }); + + it('initializer does not run again', async function () { + await expectRevert(this.contract.initialize(), 'Initializable: contract is already initialized'); + }); + }); + + describe('nested under an initializer', function () { + it('initializer modifier reverts', async function () { + await expectRevert(this.contract.initializerNested(), 'Initializable: contract is already initialized'); + }); + + it('onlyInitializing modifier succeeds', async function () { + await this.contract.onlyInitializingNested(); + expect(await this.contract.onlyInitializingRan()).to.equal(true); + }); + }); + + it('cannot call onlyInitializable function outside the scope of an initializable function', async function () { + await expectRevert(this.contract.initializeOnlyInitializing(), 'Initializable: contract is not initializing'); + }); + }); + + it('nested initializer can run during construction', async function () { + const contract2 = await ConstructorInitializableMock.new(); + expect(await contract2.initializerRan()).to.equal(true); + expect(await contract2.onlyInitializingRan()).to.equal(true); + }); + + it('multiple constructor levels can be initializers', async function () { + const contract2 = await ChildConstructorInitializableMock.new(); + expect(await contract2.initializerRan()).to.equal(true); + expect(await contract2.childInitializerRan()).to.equal(true); + expect(await contract2.onlyInitializingRan()).to.equal(true); + }); + + describe('reinitialization', function () { + beforeEach('deploying', async function () { + this.contract = await ReinitializerMock.new(); + }); + + it('can reinitialize', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.initialize(); + expect(await this.contract.counter()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(2); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + await this.contract.reinitialize(3); + expect(await this.contract.counter()).to.be.bignumber.equal('3'); + }); + + it('can jump multiple steps', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.initialize(); + expect(await this.contract.counter()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(128); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + }); + + it('cannot nest reinitializers', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await expectRevert(this.contract.nestedReinitialize(2, 2), 'Initializable: contract is already initialized'); + await expectRevert(this.contract.nestedReinitialize(2, 3), 'Initializable: contract is already initialized'); + await expectRevert(this.contract.nestedReinitialize(3, 2), 'Initializable: contract is already initialized'); + }); + + it('can chain reinitializers', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.chainReinitialize(2, 3); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + }); + + it('_getInitializedVersion returns right version', async function () { + await this.contract.initialize(); + expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(12); + expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('12'); + }); + + describe('contract locking', function () { + it('prevents initialization', async function () { + await this.contract.disableInitializers(); + await expectRevert(this.contract.initialize(), 'Initializable: contract is already initialized'); + }); + + it('prevents re-initialization', async function () { + await this.contract.disableInitializers(); + await expectRevert(this.contract.reinitialize(255), 'Initializable: contract is already initialized'); + }); + + it('can lock contract after initialization', async function () { + await this.contract.initialize(); + await this.contract.disableInitializers(); + await expectRevert(this.contract.reinitialize(255), 'Initializable: contract is already initialized'); + }); + }); + }); + + describe('events', function () { + it('constructor initialization emits event', async function () { + const contract = await ConstructorInitializableMock.new(); + + await expectEvent.inTransaction(contract.transactionHash, contract, 'Initialized', { version: '1' }); + }); + + it('initialization emits event', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.initialize(); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1); + expectEvent(receipt, 'Initialized', { version: '1' }); + }); + + it('reinitialization emits event', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.reinitialize(128); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1); + expectEvent(receipt, 'Initialized', { version: '128' }); + }); + + it('chained reinitialization emits multiple events', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.chainReinitialize(2, 3); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(2); + expectEvent(receipt, 'Initialized', { version: '2' }); + expectEvent(receipt, 'Initialized', { version: '3' }); + }); + }); + + describe('complex testing with inheritance', function () { + const mother = '12'; + const gramps = '56'; + const father = '34'; + const child = '78'; + + beforeEach('deploying', async function () { + this.contract = await SampleChild.new(); + }); + + beforeEach('initializing', async function () { + await this.contract.initialize(mother, gramps, father, child); + }); + + it('initializes human', async function () { + expect(await this.contract.isHuman()).to.be.equal(true); + }); + + it('initializes mother', async function () { + expect(await this.contract.mother()).to.be.bignumber.equal(mother); + }); + + it('initializes gramps', async function () { + expect(await this.contract.gramps()).to.be.bignumber.equal(gramps); + }); + + it('initializes father', async function () { + expect(await this.contract.father()).to.be.bignumber.equal(father); + }); + + it('initializes child', async function () { + expect(await this.contract.child()).to.be.bignumber.equal(child); + }); + }); + + describe('disabling initialization', function () { + it('old and new patterns in bad sequence', async function () { + await expectRevert(DisableBad1.new(), 'Initializable: contract is already initialized'); + await expectRevert(DisableBad2.new(), 'Initializable: contract is initializing'); + }); + + it('old and new patterns in good sequence', async function () { + const ok = await DisableOk.new(); + await expectEvent.inConstruction(ok, 'Initialized', { version: '1' }); + await expectEvent.inConstruction(ok, 'Initialized', { version: '255' }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/proxy/utils/UUPSUpgradeable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/proxy/utils/UUPSUpgradeable.test.js new file mode 100644 index 0000000..b0c1b3f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/proxy/utils/UUPSUpgradeable.test.js @@ -0,0 +1,85 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { web3 } = require('@openzeppelin/test-helpers/src/setup'); +const { getSlot, ImplementationSlot } = require('../../helpers/erc1967'); + +const ERC1967Proxy = artifacts.require('ERC1967Proxy'); +const UUPSUpgradeableMock = artifacts.require('UUPSUpgradeableMock'); +const UUPSUpgradeableUnsafeMock = artifacts.require('UUPSUpgradeableUnsafeMock'); +const UUPSUpgradeableLegacyMock = artifacts.require('UUPSUpgradeableLegacyMock'); +const NonUpgradeableMock = artifacts.require('NonUpgradeableMock'); + +contract('UUPSUpgradeable', function () { + before(async function () { + this.implInitial = await UUPSUpgradeableMock.new(); + this.implUpgradeOk = await UUPSUpgradeableMock.new(); + this.implUpgradeUnsafe = await UUPSUpgradeableUnsafeMock.new(); + this.implUpgradeNonUUPS = await NonUpgradeableMock.new(); + }); + + beforeEach(async function () { + const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x'); + this.instance = await UUPSUpgradeableMock.at(address); + }); + + it('upgrade to upgradeable implementation', async function () { + const { receipt } = await this.instance.upgradeTo(this.implUpgradeOk.address); + expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address }); + }); + + it('upgrade to upgradeable implementation with call', async function () { + expect(await this.instance.current()).to.be.bignumber.equal('0'); + + const { receipt } = await this.instance.upgradeToAndCall( + this.implUpgradeOk.address, + this.implUpgradeOk.contract.methods.increment().encodeABI(), + ); + expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address }); + + expect(await this.instance.current()).to.be.bignumber.equal('1'); + }); + + it('upgrade to and unsafe upgradeable implementation', async function () { + const { receipt } = await this.instance.upgradeTo(this.implUpgradeUnsafe.address); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeUnsafe.address }); + }); + + // delegate to a non existing upgradeTo function causes a low level revert + it('reject upgrade to non uups implementation', async function () { + await expectRevert( + this.instance.upgradeTo(this.implUpgradeNonUUPS.address), + 'ERC1967Upgrade: new implementation is not UUPS', + ); + }); + + it('reject proxy address as implementation', async function () { + const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x'); + const otherInstance = await UUPSUpgradeableMock.at(address); + + await expectRevert( + this.instance.upgradeTo(otherInstance.address), + 'ERC1967Upgrade: new implementation is not UUPS', + ); + }); + + it('can upgrade from legacy implementations', async function () { + const legacyImpl = await UUPSUpgradeableLegacyMock.new(); + const legacyInstance = await ERC1967Proxy.new(legacyImpl.address, '0x').then(({ address }) => + UUPSUpgradeableLegacyMock.at(address), + ); + + const receipt = await legacyInstance.upgradeTo(this.implInitial.address); + + const UpgradedEvents = receipt.logs.filter( + ({ address, event }) => address === legacyInstance.address && event === 'Upgraded', + ); + expect(UpgradedEvents.length).to.be.equal(1); + + expectEvent(receipt, 'Upgraded', { implementation: this.implInitial.address }); + + const implementationSlot = await getSlot(legacyInstance, ImplementationSlot); + const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40)); + expect(implementationAddress).to.be.equal(this.implInitial.address); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/security/Pausable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/security/Pausable.test.js new file mode 100644 index 0000000..5cca11e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/security/Pausable.test.js @@ -0,0 +1,85 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const PausableMock = artifacts.require('PausableMock'); + +contract('Pausable', function (accounts) { + const [pauser] = accounts; + + beforeEach(async function () { + this.pausable = await PausableMock.new(); + }); + + context('when unpaused', function () { + beforeEach(async function () { + expect(await this.pausable.paused()).to.equal(false); + }); + + it('can perform normal process in non-pause', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('cannot take drastic measure in non-pause', async function () { + await expectRevert(this.pausable.drasticMeasure(), 'Pausable: not paused'); + expect(await this.pausable.drasticMeasureTaken()).to.equal(false); + }); + + context('when paused', function () { + beforeEach(async function () { + this.receipt = await this.pausable.pause({ from: pauser }); + }); + + it('emits a Paused event', function () { + expectEvent(this.receipt, 'Paused', { account: pauser }); + }); + + it('cannot perform normal process in pause', async function () { + await expectRevert(this.pausable.normalProcess(), 'Pausable: paused'); + }); + + it('can take a drastic measure in a pause', async function () { + await this.pausable.drasticMeasure(); + expect(await this.pausable.drasticMeasureTaken()).to.equal(true); + }); + + it('reverts when re-pausing', async function () { + await expectRevert(this.pausable.pause(), 'Pausable: paused'); + }); + + describe('unpausing', function () { + it('is unpausable by the pauser', async function () { + await this.pausable.unpause(); + expect(await this.pausable.paused()).to.equal(false); + }); + + context('when unpaused', function () { + beforeEach(async function () { + this.receipt = await this.pausable.unpause({ from: pauser }); + }); + + it('emits an Unpaused event', function () { + expectEvent(this.receipt, 'Unpaused', { account: pauser }); + }); + + it('should resume allowing normal process', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('should prevent drastic measure', async function () { + await expectRevert(this.pausable.drasticMeasure(), 'Pausable: not paused'); + }); + + it('reverts when re-unpausing', async function () { + await expectRevert(this.pausable.unpause(), 'Pausable: not paused'); + }); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/security/PullPayment.test.js b/lib/openzeppelin-contracts-v4.9.3/test/security/PullPayment.test.js new file mode 100644 index 0000000..5bf72bb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/security/PullPayment.test.js @@ -0,0 +1,51 @@ +const { balance, ether } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const PullPaymentMock = artifacts.require('PullPaymentMock'); + +contract('PullPayment', function (accounts) { + const [payer, payee1, payee2] = accounts; + + const amount = ether('17'); + + beforeEach(async function () { + this.contract = await PullPaymentMock.new({ value: amount }); + }); + + describe('payments', function () { + it('can record an async payment correctly', async function () { + await this.contract.callTransfer(payee1, 100, { from: payer }); + expect(await this.contract.payments(payee1)).to.be.bignumber.equal('100'); + }); + + it('can add multiple balances on one account', async function () { + await this.contract.callTransfer(payee1, 200, { from: payer }); + await this.contract.callTransfer(payee1, 300, { from: payer }); + expect(await this.contract.payments(payee1)).to.be.bignumber.equal('500'); + }); + + it('can add balances on multiple accounts', async function () { + await this.contract.callTransfer(payee1, 200, { from: payer }); + await this.contract.callTransfer(payee2, 300, { from: payer }); + + expect(await this.contract.payments(payee1)).to.be.bignumber.equal('200'); + + expect(await this.contract.payments(payee2)).to.be.bignumber.equal('300'); + }); + }); + + describe('withdrawPayments', function () { + it('can withdraw payment', async function () { + const balanceTracker = await balance.tracker(payee1); + + await this.contract.callTransfer(payee1, amount, { from: payer }); + expect(await this.contract.payments(payee1)).to.be.bignumber.equal(amount); + + await this.contract.withdrawPayments(payee1); + + expect(await balanceTracker.delta()).to.be.bignumber.equal(amount); + expect(await this.contract.payments(payee1)).to.be.bignumber.equal('0'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/security/ReentrancyGuard.test.js b/lib/openzeppelin-contracts-v4.9.3/test/security/ReentrancyGuard.test.js new file mode 100644 index 0000000..1a80bc8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/security/ReentrancyGuard.test.js @@ -0,0 +1,43 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ReentrancyMock = artifacts.require('ReentrancyMock'); +const ReentrancyAttack = artifacts.require('ReentrancyAttack'); + +contract('ReentrancyGuard', function () { + beforeEach(async function () { + this.reentrancyMock = await ReentrancyMock.new(); + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('0'); + }); + + it('nonReentrant function can be called', async function () { + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('0'); + await this.reentrancyMock.callback(); + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('1'); + }); + + it('does not allow remote callback', async function () { + const attacker = await ReentrancyAttack.new(); + await expectRevert(this.reentrancyMock.countAndCall(attacker.address), 'ReentrancyAttack: failed call'); + }); + + it('_reentrancyGuardEntered should be true when guarded', async function () { + await this.reentrancyMock.guardedCheckEntered(); + }); + + it('_reentrancyGuardEntered should be false when unguarded', async function () { + await this.reentrancyMock.unguardedCheckNotEntered(); + }); + + // The following are more side-effects than intended behavior: + // I put them here as documentation, and to monitor any changes + // in the side-effects. + it('does not allow local recursion', async function () { + await expectRevert(this.reentrancyMock.countLocalRecursive(10), 'ReentrancyGuard: reentrant call'); + }); + + it('does not allow indirect local recursion', async function () { + await expectRevert(this.reentrancyMock.countThisRecursive(10), 'ReentrancyMock: failed call'); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/ERC1155.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/ERC1155.behavior.js new file mode 100644 index 0000000..96d448a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/ERC1155.behavior.js @@ -0,0 +1,767 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +const ERC1155ReceiverMock = artifacts.require('ERC1155ReceiverMock'); + +function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, multiTokenHolder, recipient, proxy]) { + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); + + const firstAmount = new BN(1000); + const secondAmount = new BN(2000); + + const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; + const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; + + describe('like an ERC1155', function () { + describe('balanceOf', function () { + it('reverts when queried about the zero address', async function () { + await expectRevert( + this.token.balanceOf(ZERO_ADDRESS, firstTokenId), + 'ERC1155: address zero is not a valid owner', + ); + }); + + context("when accounts don't own tokens", function () { + it('returns zero for given addresses', async function () { + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + }); + }); + + context('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstAmount, '0x', { + from: minter, + }); + await this.token.$_mint(secondTokenHolder, secondTokenId, secondAmount, '0x', { + from: minter, + }); + }); + + it('returns the amount of tokens owned by the given addresses', async function () { + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal(firstAmount); + + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal(secondAmount); + + expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('balanceOfBatch', function () { + it("reverts when input arrays don't match up", async function () { + await expectRevert( + this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder, secondTokenHolder], + [firstTokenId, secondTokenId, unknownTokenId], + ), + 'ERC1155: accounts and ids length mismatch', + ); + + await expectRevert( + this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder], + [firstTokenId, secondTokenId, unknownTokenId], + ), + 'ERC1155: accounts and ids length mismatch', + ); + }); + + it('reverts when one of the addresses is the zero address', async function () { + await expectRevert( + this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, ZERO_ADDRESS], + [firstTokenId, secondTokenId, unknownTokenId], + ), + 'ERC1155: address zero is not a valid owner', + ); + }); + + context("when accounts don't own tokens", function () { + it('returns zeros for each account', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [firstTokenId, secondTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal('0'); + expect(result[1]).to.be.a.bignumber.equal('0'); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + }); + + context('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstAmount, '0x', { + from: minter, + }); + await this.token.$_mint(secondTokenHolder, secondTokenId, secondAmount, '0x', { + from: minter, + }); + }); + + it('returns amounts owned by each account in order passed', async function () { + const result = await this.token.balanceOfBatch( + [secondTokenHolder, firstTokenHolder, firstTokenHolder], + [secondTokenId, firstTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal(secondAmount); + expect(result[1]).to.be.a.bignumber.equal(firstAmount); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + + it('returns multiple times the balance of the same address when asked', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [firstTokenId, secondTokenId, firstTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal(result[2]); + expect(result[0]).to.be.a.bignumber.equal(firstAmount); + expect(result[1]).to.be.a.bignumber.equal(secondAmount); + expect(result[2]).to.be.a.bignumber.equal(firstAmount); + }); + }); + }); + + describe('setApprovalForAll', function () { + let receipt; + beforeEach(async function () { + receipt = await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + }); + + it('sets approval status which can be queried via isApprovedForAll', async function () { + expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(true); + }); + + it('emits an ApprovalForAll log', function () { + expectEvent(receipt, 'ApprovalForAll', { account: multiTokenHolder, operator: proxy, approved: true }); + }); + + it('can unset approval for an operator', async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(false); + }); + + it('reverts if attempting to approve self as an operator', async function () { + await expectRevert( + this.token.setApprovalForAll(multiTokenHolder, true, { from: multiTokenHolder }), + 'ERC1155: setting approval status for self', + ); + }); + }); + + describe('safeTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstAmount, '0x', { + from: minter, + }); + await this.token.$_mint(multiTokenHolder, secondTokenId, secondAmount, '0x', { + from: minter, + }); + }); + + it('reverts when transferring more than balance', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount.addn(1), '0x', { + from: multiTokenHolder, + }), + 'ERC1155: insufficient balance for transfer', + ); + }); + + it('reverts when transferring to zero address', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, ZERO_ADDRESS, firstTokenId, firstAmount, '0x', { + from: multiTokenHolder, + }), + 'ERC1155: transfer to the zero address', + ); + }); + + function transferWasSuccessful({ operator, from, id, value }) { + it('debits transferred balance from sender', async function () { + const newBalance = await this.token.balanceOf(from, id); + expect(newBalance).to.be.a.bignumber.equal('0'); + }); + + it('credits transferred balance to receiver', async function () { + const newBalance = await this.token.balanceOf(this.toWhom, id); + expect(newBalance).to.be.a.bignumber.equal(value); + }); + + it('emits a TransferSingle log', function () { + expectEvent(this.transferLogs, 'TransferSingle', { + operator, + from, + to: this.toWhom, + id, + value, + }); + }); + } + + context('when called by the multiTokenHolder', async function () { + beforeEach(async function () { + this.toWhom = recipient; + this.transferLogs = await this.token.safeTransferFrom( + multiTokenHolder, + recipient, + firstTokenId, + firstAmount, + '0x', + { + from: multiTokenHolder, + }, + ); + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + }); + + it('preserves existing balances which are not transferred by multiTokenHolder', async function () { + const balance1 = await this.token.balanceOf(multiTokenHolder, secondTokenId); + expect(balance1).to.be.a.bignumber.equal(secondAmount); + + const balance2 = await this.token.balanceOf(recipient, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + + context('when called by an operator on behalf of the multiTokenHolder', function () { + context('when operator is not approved by multiTokenHolder', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstAmount, '0x', { + from: proxy, + }), + 'ERC1155: caller is not token owner or approved', + ); + }); + }); + + context('when operator is approved by multiTokenHolder', function () { + beforeEach(async function () { + this.toWhom = recipient; + await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.transferLogs = await this.token.safeTransferFrom( + multiTokenHolder, + recipient, + firstTokenId, + firstAmount, + '0x', + { + from: proxy, + }, + ); + }); + + transferWasSuccessful.call(this, { + operator: proxy, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + }); + + it("preserves operator's balances not involved in the transfer", async function () { + const balance1 = await this.token.balanceOf(proxy, firstTokenId); + expect(balance1).to.be.a.bignumber.equal('0'); + + const balance2 = await this.token.balanceOf(proxy, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + }); + + context('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + false, + RECEIVER_BATCH_MAGIC_VALUE, + false, + ); + }); + + context('without data', function () { + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstAmount, + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + data: null, + }); + }); + }); + + context('with data', function () { + const data = '0xf00dd00d'; + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstAmount, + data, + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstAmount, + data, + }); + }); + }); + }); + + context('to a receiver contract returning unexpected value', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new('0x00c0ffee', false, RECEIVER_BATCH_MAGIC_VALUE, false); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { + from: multiTokenHolder, + }), + 'ERC1155: ERC1155Receiver rejected tokens', + ); + }); + }); + + context('to a receiver contract that reverts', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + true, + RECEIVER_BATCH_MAGIC_VALUE, + false, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstAmount, '0x', { + from: multiTokenHolder, + }), + 'ERC1155ReceiverMock: reverting on receive', + ); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + await expectRevert.unspecified( + this.token.safeTransferFrom(multiTokenHolder, invalidReceiver.address, firstTokenId, firstAmount, '0x', { + from: multiTokenHolder, + }), + ); + }); + }); + }); + + describe('safeBatchTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstAmount, '0x', { + from: minter, + }); + await this.token.$_mint(multiTokenHolder, secondTokenId, secondAmount, '0x', { + from: minter, + }); + }); + + it('reverts when transferring amount more than any of balances', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount.addn(1)], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: insufficient balance for transfer', + ); + }); + + it("reverts when ids array length doesn't match amounts array length", async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: ids and amounts length mismatch', + ); + + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: ids and amounts length mismatch', + ); + }); + + it('reverts when transferring to zero address', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + ZERO_ADDRESS, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: transfer to the zero address', + ); + }); + + function batchTransferWasSuccessful({ operator, from, ids, values }) { + it('debits transferred balances from sender', async function () { + const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(from), ids); + for (const newBalance of newBalances) { + expect(newBalance).to.be.a.bignumber.equal('0'); + } + }); + + it('credits transferred balances to receiver', async function () { + const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(this.toWhom), ids); + for (let i = 0; i < newBalances.length; i++) { + expect(newBalances[i]).to.be.a.bignumber.equal(values[i]); + } + }); + + it('emits a TransferBatch log', function () { + expectEvent(this.transferLogs, 'TransferBatch', { + operator, + from, + to: this.toWhom, + // ids, + // values, + }); + }); + } + + context('when called by the multiTokenHolder', async function () { + beforeEach(async function () { + this.toWhom = recipient; + this.transferLogs = await this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ); + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + }); + + context('when called by an operator on behalf of the multiTokenHolder', function () { + context('when operator is not approved by multiTokenHolder', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: proxy }, + ), + 'ERC1155: caller is not token owner or approved', + ); + }); + }); + + context('when operator is approved by multiTokenHolder', function () { + beforeEach(async function () { + this.toWhom = recipient; + await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.transferLogs = await this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: proxy }, + ); + }); + + batchTransferWasSuccessful.call(this, { + operator: proxy, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + + it("preserves operator's balances not involved in the transfer", async function () { + const balance1 = await this.token.balanceOf(proxy, firstTokenId); + expect(balance1).to.be.a.bignumber.equal('0'); + const balance2 = await this.token.balanceOf(proxy, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + }); + + context('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + false, + RECEIVER_BATCH_MAGIC_VALUE, + false, + ); + }); + + context('without data', function () { + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + + it('calls onERC1155BatchReceived', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstAmount, secondAmount], + data: null, + }); + }); + }); + + context('with data', function () { + const data = '0xf00dd00d'; + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + data, + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstAmount, secondAmount], + data, + }); + }); + }); + }); + + context('to a receiver contract returning unexpected value', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + false, + RECEIVER_SINGLE_MAGIC_VALUE, + false, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155: ERC1155Receiver rejected tokens', + ); + }); + }); + + context('to a receiver contract that reverts', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + false, + RECEIVER_BATCH_MAGIC_VALUE, + true, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155ReceiverMock: reverting on batch receive', + ); + }); + }); + + context('to a receiver contract that reverts only on single transfers', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + true, + RECEIVER_BATCH_MAGIC_VALUE, + false, + ); + + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstAmount, secondAmount], + }); + + it('calls onERC1155BatchReceived', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstAmount, secondAmount], + data: null, + }); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + await expectRevert.unspecified( + this.token.safeBatchTransferFrom( + multiTokenHolder, + invalidReceiver.address, + [firstTokenId, secondTokenId], + [firstAmount, secondAmount], + '0x', + { from: multiTokenHolder }, + ), + ); + }); + }); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155']); + }); +} + +module.exports = { + shouldBehaveLikeERC1155, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/ERC1155.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/ERC1155.test.js new file mode 100644 index 0000000..ff432d3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/ERC1155.test.js @@ -0,0 +1,235 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const { shouldBehaveLikeERC1155 } = require('./ERC1155.behavior'); +const ERC1155Mock = artifacts.require('$ERC1155'); + +contract('ERC1155', function (accounts) { + const [operator, tokenHolder, tokenBatchHolder, ...otherAccounts] = accounts; + + const initialURI = 'https://token-cdn-domain/{id}.json'; + + beforeEach(async function () { + this.token = await ERC1155Mock.new(initialURI); + }); + + shouldBehaveLikeERC1155(otherAccounts); + + describe('internal functions', function () { + const tokenId = new BN(1990); + const mintAmount = new BN(9001); + const burnAmount = new BN(3000); + + const tokenBatchIds = [new BN(2000), new BN(2010), new BN(2020)]; + const mintAmounts = [new BN(5000), new BN(10000), new BN(42195)]; + const burnAmounts = [new BN(5000), new BN(9001), new BN(195)]; + + const data = '0x12345678'; + + describe('_mint', function () { + it('reverts with a zero destination address', async function () { + await expectRevert( + this.token.$_mint(ZERO_ADDRESS, tokenId, mintAmount, data), + 'ERC1155: mint to the zero address', + ); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(tokenHolder, tokenId, mintAmount, data, { from: operator }); + }); + + it('emits a TransferSingle event', function () { + expectEvent(this.receipt, 'TransferSingle', { + operator, + from: ZERO_ADDRESS, + to: tokenHolder, + id: tokenId, + value: mintAmount, + }); + }); + + it('credits the minted amount of tokens', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintAmount); + }); + }); + }); + + describe('_mintBatch', function () { + it('reverts with a zero destination address', async function () { + await expectRevert( + this.token.$_mintBatch(ZERO_ADDRESS, tokenBatchIds, mintAmounts, data), + 'ERC1155: mint to the zero address', + ); + }); + + it('reverts if length of inputs do not match', async function () { + await expectRevert( + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts.slice(1), data), + 'ERC1155: ids and amounts length mismatch', + ); + + await expectRevert( + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds.slice(1), mintAmounts, data), + 'ERC1155: ids and amounts length mismatch', + ); + }); + + context('with minted batch of tokens', function () { + beforeEach(async function () { + this.receipt = await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts, data, { + from: operator, + }); + }); + + it('emits a TransferBatch event', function () { + expectEvent(this.receipt, 'TransferBatch', { + operator, + from: ZERO_ADDRESS, + to: tokenBatchHolder, + }); + }); + + it('credits the minted batch of tokens', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds, + ); + + for (let i = 0; i < holderBatchBalances.length; i++) { + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintAmounts[i]); + } + }); + }); + }); + + describe('_burn', function () { + it("reverts when burning the zero account's tokens", async function () { + await expectRevert(this.token.$_burn(ZERO_ADDRESS, tokenId, mintAmount), 'ERC1155: burn from the zero address'); + }); + + it('reverts when burning a non-existent token id', async function () { + await expectRevert(this.token.$_burn(tokenHolder, tokenId, mintAmount), 'ERC1155: burn amount exceeds balance'); + }); + + it('reverts when burning more than available tokens', async function () { + await this.token.$_mint(tokenHolder, tokenId, mintAmount, data, { from: operator }); + + await expectRevert( + this.token.$_burn(tokenHolder, tokenId, mintAmount.addn(1)), + 'ERC1155: burn amount exceeds balance', + ); + }); + + context('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mint(tokenHolder, tokenId, mintAmount, data); + this.receipt = await this.token.$_burn(tokenHolder, tokenId, burnAmount, { from: operator }); + }); + + it('emits a TransferSingle event', function () { + expectEvent(this.receipt, 'TransferSingle', { + operator, + from: tokenHolder, + to: ZERO_ADDRESS, + id: tokenId, + value: burnAmount, + }); + }); + + it('accounts for both minting and burning', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintAmount.sub(burnAmount)); + }); + }); + }); + + describe('_burnBatch', function () { + it("reverts when burning the zero account's tokens", async function () { + await expectRevert( + this.token.$_burnBatch(ZERO_ADDRESS, tokenBatchIds, burnAmounts), + 'ERC1155: burn from the zero address', + ); + }); + + it('reverts if length of inputs do not match', async function () { + await expectRevert( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts.slice(1)), + 'ERC1155: ids and amounts length mismatch', + ); + + await expectRevert( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds.slice(1), burnAmounts), + 'ERC1155: ids and amounts length mismatch', + ); + }); + + it('reverts when burning a non-existent token id', async function () { + await expectRevert( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts), + 'ERC1155: burn amount exceeds balance', + ); + }); + + context('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintAmounts, data); + this.receipt = await this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnAmounts, { from: operator }); + }); + + it('emits a TransferBatch event', function () { + expectEvent(this.receipt, 'TransferBatch', { + operator, + from: tokenBatchHolder, + to: ZERO_ADDRESS, + // ids: tokenBatchIds, + // values: burnAmounts, + }); + }); + + it('accounts for both minting and burning', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds, + ); + + for (let i = 0; i < holderBatchBalances.length; i++) { + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintAmounts[i].sub(burnAmounts[i])); + } + }); + }); + }); + }); + + describe('ERC1155MetadataURI', function () { + const firstTokenID = new BN('42'); + const secondTokenID = new BN('1337'); + + it('emits no URI event in constructor', async function () { + await expectEvent.notEmitted.inConstruction(this.token, 'URI'); + }); + + it('sets the initial URI for all token types', async function () { + expect(await this.token.uri(firstTokenID)).to.be.equal(initialURI); + expect(await this.token.uri(secondTokenID)).to.be.equal(initialURI); + }); + + describe('_setURI', function () { + const newURI = 'https://token-cdn-domain/{locale}/{id}.json'; + + it('emits no URI event', async function () { + const receipt = await this.token.$_setURI(newURI); + + expectEvent.notEmitted(receipt, 'URI'); + }); + + it('sets the new URI for all token types', async function () { + await this.token.$_setURI(newURI); + + expect(await this.token.uri(firstTokenID)).to.be.equal(newURI); + expect(await this.token.uri(secondTokenID)).to.be.equal(newURI); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Burnable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Burnable.test.js new file mode 100644 index 0000000..f80d993 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Burnable.test.js @@ -0,0 +1,67 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC1155Burnable = artifacts.require('$ERC1155Burnable'); + +contract('ERC1155Burnable', function (accounts) { + const [holder, operator, other] = accounts; + + const uri = 'https://token.com'; + + const tokenIds = [new BN('42'), new BN('1137')]; + const amounts = [new BN('3000'), new BN('9902')]; + + beforeEach(async function () { + this.token = await ERC1155Burnable.new(uri); + + await this.token.$_mint(holder, tokenIds[0], amounts[0], '0x'); + await this.token.$_mint(holder, tokenIds[1], amounts[1], '0x'); + }); + + describe('burn', function () { + it('holder can burn their tokens', async function () { + await this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: holder }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: operator }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expectRevert( + this.token.burn(holder, tokenIds[0], amounts[0].subn(1), { from: other }), + 'ERC1155: caller is not token owner or approved', + ); + }); + }); + + describe('burnBatch', function () { + it('holder can burn their tokens', async function () { + await this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: holder }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: operator }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expectRevert( + this.token.burnBatch(holder, tokenIds, [amounts[0].subn(1), amounts[1].subn(2)], { from: other }), + 'ERC1155: caller is not token owner or approved', + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Pausable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Pausable.test.js new file mode 100644 index 0000000..f4d5ced --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Pausable.test.js @@ -0,0 +1,108 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC1155Pausable = artifacts.require('$ERC1155Pausable'); + +contract('ERC1155Pausable', function (accounts) { + const [holder, operator, receiver, other] = accounts; + + const uri = 'https://token.com'; + + beforeEach(async function () { + this.token = await ERC1155Pausable.new(uri); + }); + + context('when token is paused', function () { + const firstTokenId = new BN('37'); + const firstTokenAmount = new BN('42'); + + const secondTokenId = new BN('19842'); + const secondTokenAmount = new BN('23'); + + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); + + await this.token.$_pause(); + }); + + it('reverts when trying to safeTransferFrom from holder', async function () { + await expectRevert( + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenAmount, '0x', { from: holder }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeTransferFrom from operator', async function () { + await expectRevert( + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenAmount, '0x', { from: operator }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeBatchTransferFrom from holder', async function () { + await expectRevert( + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenAmount], '0x', { from: holder }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeBatchTransferFrom from operator', async function () { + await expectRevert( + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenAmount], '0x', { + from: operator, + }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to mint', async function () { + await expectRevert( + this.token.$_mint(holder, secondTokenId, secondTokenAmount, '0x'), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to mintBatch', async function () { + await expectRevert( + this.token.$_mintBatch(holder, [secondTokenId], [secondTokenAmount], '0x'), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to burn', async function () { + await expectRevert( + this.token.$_burn(holder, firstTokenId, firstTokenAmount), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to burnBatch', async function () { + await expectRevert( + this.token.$_burnBatch(holder, [firstTokenId], [firstTokenAmount]), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + describe('setApprovalForAll', function () { + it('approves an operator', async function () { + await this.token.setApprovalForAll(other, true, { from: holder }); + expect(await this.token.isApprovedForAll(holder, other)).to.equal(true); + }); + }); + + describe('balanceOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const balance = await this.token.balanceOf(holder, firstTokenId); + expect(balance).to.be.bignumber.equal(firstTokenAmount); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(holder, operator)).to.equal(true); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Supply.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Supply.test.js new file mode 100644 index 0000000..721d5a7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155Supply.test.js @@ -0,0 +1,107 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC1155Supply = artifacts.require('$ERC1155Supply'); + +contract('ERC1155Supply', function (accounts) { + const [holder] = accounts; + + const uri = 'https://token.com'; + + const firstTokenId = new BN('37'); + const firstTokenAmount = new BN('42'); + + const secondTokenId = new BN('19842'); + const secondTokenAmount = new BN('23'); + + beforeEach(async function () { + this.token = await ERC1155Supply.new(uri); + }); + + context('before mint', function () { + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); + }); + }); + + context('after mint', function () { + context('single', function () { + beforeEach(async function () { + await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(true); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal(firstTokenAmount); + }); + }); + + context('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch( + holder, + [firstTokenId, secondTokenId], + [firstTokenAmount, secondTokenAmount], + '0x', + ); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(true); + expect(await this.token.exists(secondTokenId)).to.be.equal(true); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal(firstTokenAmount); + expect(await this.token.totalSupply(secondTokenId)).to.be.bignumber.equal(secondTokenAmount); + }); + }); + }); + + context('after burn', function () { + context('single', function () { + beforeEach(async function () { + await this.token.$_mint(holder, firstTokenId, firstTokenAmount, '0x'); + await this.token.$_burn(holder, firstTokenId, firstTokenAmount); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); + }); + }); + + context('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch( + holder, + [firstTokenId, secondTokenId], + [firstTokenAmount, secondTokenAmount], + '0x', + ); + await this.token.$_burnBatch(holder, [firstTokenId, secondTokenId], [firstTokenAmount, secondTokenAmount]); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + expect(await this.token.exists(secondTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.totalSupply(firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.totalSupply(secondTokenId)).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155URIStorage.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155URIStorage.test.js new file mode 100644 index 0000000..95d9c18 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/extensions/ERC1155URIStorage.test.js @@ -0,0 +1,66 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { artifacts } = require('hardhat'); + +const ERC1155URIStorage = artifacts.require('$ERC1155URIStorage'); + +contract(['ERC1155URIStorage'], function (accounts) { + const [holder] = accounts; + + const erc1155Uri = 'https://token.com/nfts/'; + const baseUri = 'https://token.com/'; + + const tokenId = new BN('1'); + const amount = new BN('3000'); + + describe('with base uri set', function () { + beforeEach(async function () { + this.token = await ERC1155URIStorage.new(erc1155Uri); + await this.token.$_setBaseURI(baseUri); + + await this.token.$_mint(holder, tokenId, amount, '0x'); + }); + + it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(erc1155Uri); + }); + + it('can request the token uri, returning the concatenated uri if a token uri was set', async function () { + const tokenUri = '1234/'; + const receipt = await this.token.$_setURI(tokenId, tokenUri); + + const receivedTokenUri = await this.token.uri(tokenId); + + const expectedUri = `${baseUri}${tokenUri}`; + expect(receivedTokenUri).to.be.equal(expectedUri); + expectEvent(receipt, 'URI', { value: expectedUri, id: tokenId }); + }); + }); + + describe('with base uri set to the empty string', function () { + beforeEach(async function () { + this.token = await ERC1155URIStorage.new(''); + + await this.token.$_mint(holder, tokenId, amount, '0x'); + }); + + it('can request the token uri, returning an empty string if no token uri was set', async function () { + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(''); + }); + + it('can request the token uri, returning the token uri if a token uri was set', async function () { + const tokenUri = 'ipfs://1234/'; + const receipt = await this.token.$_setURI(tokenId, tokenUri); + + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(tokenUri); + expectEvent(receipt, 'URI', { value: tokenUri, id: tokenId }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js new file mode 100644 index 0000000..12d2594 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/presets/ERC1155PresetMinterPauser.test.js @@ -0,0 +1,156 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +const { expect } = require('chai'); + +const ERC1155PresetMinterPauser = artifacts.require('ERC1155PresetMinterPauser'); + +contract('ERC1155PresetMinterPauser', function (accounts) { + const [deployer, other] = accounts; + + const firstTokenId = new BN('845'); + const firstTokenIdAmount = new BN('5000'); + + const secondTokenId = new BN('48324'); + const secondTokenIdAmount = new BN('77875'); + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const MINTER_ROLE = web3.utils.soliditySha3('MINTER_ROLE'); + const PAUSER_ROLE = web3.utils.soliditySha3('PAUSER_ROLE'); + + const uri = 'https://token.com'; + + beforeEach(async function () { + this.token = await ERC1155PresetMinterPauser.new(uri, { from: deployer }); + }); + + shouldSupportInterfaces(['ERC1155', 'AccessControl', 'AccessControlEnumerable']); + + it('deployer has the default admin role', async function () { + expect(await this.token.getRoleMemberCount(DEFAULT_ADMIN_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(DEFAULT_ADMIN_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the minter role', async function () { + expect(await this.token.getRoleMemberCount(MINTER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(MINTER_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the pauser role', async function () { + expect(await this.token.getRoleMemberCount(PAUSER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(PAUSER_ROLE, 0)).to.equal(deployer); + }); + + it('minter and pauser role admin is the default admin', async function () { + expect(await this.token.getRoleAdmin(MINTER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + expect(await this.token.getRoleAdmin(PAUSER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + describe('minting', function () { + it('deployer can mint tokens', async function () { + const receipt = await this.token.mint(other, firstTokenId, firstTokenIdAmount, '0x', { from: deployer }); + expectEvent(receipt, 'TransferSingle', { + operator: deployer, + from: ZERO_ADDRESS, + to: other, + value: firstTokenIdAmount, + id: firstTokenId, + }); + + expect(await this.token.balanceOf(other, firstTokenId)).to.be.bignumber.equal(firstTokenIdAmount); + }); + + it('other accounts cannot mint tokens', async function () { + await expectRevert( + this.token.mint(other, firstTokenId, firstTokenIdAmount, '0x', { from: other }), + 'ERC1155PresetMinterPauser: must have minter role to mint', + ); + }); + }); + + describe('batched minting', function () { + it('deployer can batch mint tokens', async function () { + const receipt = await this.token.mintBatch( + other, + [firstTokenId, secondTokenId], + [firstTokenIdAmount, secondTokenIdAmount], + '0x', + { from: deployer }, + ); + + expectEvent(receipt, 'TransferBatch', { operator: deployer, from: ZERO_ADDRESS, to: other }); + + expect(await this.token.balanceOf(other, firstTokenId)).to.be.bignumber.equal(firstTokenIdAmount); + }); + + it('other accounts cannot batch mint tokens', async function () { + await expectRevert( + this.token.mintBatch(other, [firstTokenId, secondTokenId], [firstTokenIdAmount, secondTokenIdAmount], '0x', { + from: other, + }), + 'ERC1155PresetMinterPauser: must have minter role to mint', + ); + }); + }); + + describe('pausing', function () { + it('deployer can pause', async function () { + const receipt = await this.token.pause({ from: deployer }); + expectEvent(receipt, 'Paused', { account: deployer }); + + expect(await this.token.paused()).to.equal(true); + }); + + it('deployer can unpause', async function () { + await this.token.pause({ from: deployer }); + + const receipt = await this.token.unpause({ from: deployer }); + expectEvent(receipt, 'Unpaused', { account: deployer }); + + expect(await this.token.paused()).to.equal(false); + }); + + it('cannot mint while paused', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.mint(other, firstTokenId, firstTokenIdAmount, '0x', { from: deployer }), + 'ERC1155Pausable: token transfer while paused', + ); + }); + + it('other accounts cannot pause', async function () { + await expectRevert( + this.token.pause({ from: other }), + 'ERC1155PresetMinterPauser: must have pauser role to pause', + ); + }); + + it('other accounts cannot unpause', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.unpause({ from: other }), + 'ERC1155PresetMinterPauser: must have pauser role to unpause', + ); + }); + }); + + describe('burning', function () { + it('holders can burn their tokens', async function () { + await this.token.mint(other, firstTokenId, firstTokenIdAmount, '0x', { from: deployer }); + + const receipt = await this.token.burn(other, firstTokenId, firstTokenIdAmount.subn(1), { from: other }); + expectEvent(receipt, 'TransferSingle', { + operator: other, + from: other, + to: ZERO_ADDRESS, + value: firstTokenIdAmount.subn(1), + id: firstTokenId, + }); + + expect(await this.token.balanceOf(other, firstTokenId)).to.be.bignumber.equal('1'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/utils/ERC1155Holder.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/utils/ERC1155Holder.test.js new file mode 100644 index 0000000..864e89b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC1155/utils/ERC1155Holder.test.js @@ -0,0 +1,64 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const ERC1155Holder = artifacts.require('ERC1155Holder'); +const ERC1155 = artifacts.require('$ERC1155'); + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +contract('ERC1155Holder', function (accounts) { + const [creator] = accounts; + const uri = 'https://token-cdn-domain/{id}.json'; + const multiTokenIds = [new BN(1), new BN(2), new BN(3)]; + const multiTokenAmounts = [new BN(1000), new BN(2000), new BN(3000)]; + const transferData = '0x12345678'; + + beforeEach(async function () { + this.multiToken = await ERC1155.new(uri); + this.holder = await ERC1155Holder.new(); + await this.multiToken.$_mintBatch(creator, multiTokenIds, multiTokenAmounts, '0x'); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver']); + + it('receives ERC1155 tokens from a single ID', async function () { + await this.multiToken.safeTransferFrom( + creator, + this.holder.address, + multiTokenIds[0], + multiTokenAmounts[0], + transferData, + { from: creator }, + ); + + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[0])).to.be.bignumber.equal( + multiTokenAmounts[0], + ); + + for (let i = 1; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + } + }); + + it('receives ERC1155 tokens from a multiple IDs', async function () { + for (let i = 0; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + } + + await this.multiToken.safeBatchTransferFrom( + creator, + this.holder.address, + multiTokenIds, + multiTokenAmounts, + transferData, + { from: creator }, + ); + + for (let i = 0; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal( + multiTokenAmounts[i], + ); + } + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/ERC20.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/ERC20.behavior.js new file mode 100644 index 0000000..41e47f0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/ERC20.behavior.js @@ -0,0 +1,322 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS, MAX_UINT256 } = constants; + +function shouldBehaveLikeERC20(errorPrefix, initialSupply, initialHolder, recipient, anotherAccount) { + describe('total supply', function () { + it('returns the total amount of tokens', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + }); + + describe('balanceOf', function () { + describe('when the requested account has no tokens', function () { + it('returns zero', async function () { + expect(await this.token.balanceOf(anotherAccount)).to.be.bignumber.equal('0'); + }); + }); + + describe('when the requested account has some tokens', function () { + it('returns the total amount of tokens', async function () { + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(initialSupply); + }); + }); + }); + + describe('transfer', function () { + shouldBehaveLikeERC20Transfer(errorPrefix, initialHolder, recipient, initialSupply, function (from, to, value) { + return this.token.transfer(to, value, { from }); + }); + }); + + describe('transfer from', function () { + const spender = recipient; + + describe('when the token owner is not the zero address', function () { + const tokenOwner = initialHolder; + + describe('when the recipient is not the zero address', function () { + const to = anotherAccount; + + describe('when the spender has enough allowance', function () { + beforeEach(async function () { + await this.token.approve(spender, initialSupply, { from: initialHolder }); + }); + + describe('when the token owner has enough balance', function () { + const amount = initialSupply; + + it('transfers the requested amount', async function () { + await this.token.transferFrom(tokenOwner, to, amount, { from: spender }); + + expect(await this.token.balanceOf(tokenOwner)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(amount); + }); + + it('decreases the spender allowance', async function () { + await this.token.transferFrom(tokenOwner, to, amount, { from: spender }); + + expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal('0'); + }); + + it('emits a transfer event', async function () { + expectEvent(await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'Transfer', { + from: tokenOwner, + to: to, + value: amount, + }); + }); + + it('emits an approval event', async function () { + expectEvent(await this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'Approval', { + owner: tokenOwner, + spender: spender, + value: await this.token.allowance(tokenOwner, spender), + }); + }); + }); + + describe('when the token owner does not have enough balance', function () { + const amount = initialSupply; + + beforeEach('reducing balance', async function () { + await this.token.transfer(to, 1, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + `${errorPrefix}: transfer amount exceeds balance`, + ); + }); + }); + }); + + describe('when the spender does not have enough allowance', function () { + const allowance = initialSupply.subn(1); + + beforeEach(async function () { + await this.token.approve(spender, allowance, { from: tokenOwner }); + }); + + describe('when the token owner has enough balance', function () { + const amount = initialSupply; + + it('reverts', async function () { + await expectRevert( + this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + `${errorPrefix}: insufficient allowance`, + ); + }); + }); + + describe('when the token owner does not have enough balance', function () { + const amount = allowance; + + beforeEach('reducing balance', async function () { + await this.token.transfer(to, 2, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + `${errorPrefix}: transfer amount exceeds balance`, + ); + }); + }); + }); + + describe('when the spender has unlimited allowance', function () { + beforeEach(async function () { + await this.token.approve(spender, MAX_UINT256, { from: initialHolder }); + }); + + it('does not decrease the spender allowance', async function () { + await this.token.transferFrom(tokenOwner, to, 1, { from: spender }); + + expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal(MAX_UINT256); + }); + + it('does not emit an approval event', async function () { + expectEvent.notEmitted(await this.token.transferFrom(tokenOwner, to, 1, { from: spender }), 'Approval'); + }); + }); + }); + + describe('when the recipient is the zero address', function () { + const amount = initialSupply; + const to = ZERO_ADDRESS; + + beforeEach(async function () { + await this.token.approve(spender, amount, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevert( + this.token.transferFrom(tokenOwner, to, amount, { from: spender }), + `${errorPrefix}: transfer to the zero address`, + ); + }); + }); + }); + + describe('when the token owner is the zero address', function () { + const amount = 0; + const tokenOwner = ZERO_ADDRESS; + const to = recipient; + + it('reverts', async function () { + await expectRevert(this.token.transferFrom(tokenOwner, to, amount, { from: spender }), 'from the zero address'); + }); + }); + }); + + describe('approve', function () { + shouldBehaveLikeERC20Approve( + errorPrefix, + initialHolder, + recipient, + initialSupply, + function (owner, spender, amount) { + return this.token.approve(spender, amount, { from: owner }); + }, + ); + }); +} + +function shouldBehaveLikeERC20Transfer(errorPrefix, from, to, balance, transfer) { + describe('when the recipient is not the zero address', function () { + describe('when the sender does not have enough balance', function () { + const amount = balance.addn(1); + + it('reverts', async function () { + await expectRevert(transfer.call(this, from, to, amount), `${errorPrefix}: transfer amount exceeds balance`); + }); + }); + + describe('when the sender transfers all balance', function () { + const amount = balance; + + it('transfers the requested amount', async function () { + await transfer.call(this, from, to, amount); + + expect(await this.token.balanceOf(from)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(amount); + }); + + it('emits a transfer event', async function () { + expectEvent(await transfer.call(this, from, to, amount), 'Transfer', { from, to, value: amount }); + }); + }); + + describe('when the sender transfers zero tokens', function () { + const amount = new BN('0'); + + it('transfers the requested amount', async function () { + await transfer.call(this, from, to, amount); + + expect(await this.token.balanceOf(from)).to.be.bignumber.equal(balance); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal('0'); + }); + + it('emits a transfer event', async function () { + expectEvent(await transfer.call(this, from, to, amount), 'Transfer', { from, to, value: amount }); + }); + }); + }); + + describe('when the recipient is the zero address', function () { + it('reverts', async function () { + await expectRevert( + transfer.call(this, from, ZERO_ADDRESS, balance), + `${errorPrefix}: transfer to the zero address`, + ); + }); + }); +} + +function shouldBehaveLikeERC20Approve(errorPrefix, owner, spender, supply, approve) { + describe('when the spender is not the zero address', function () { + describe('when the sender has enough balance', function () { + const amount = supply; + + it('emits an approval event', async function () { + expectEvent(await approve.call(this, owner, spender, amount), 'Approval', { + owner: owner, + spender: spender, + value: amount, + }); + }); + + describe('when there was no approved amount before', function () { + it('approves the requested amount', async function () { + await approve.call(this, owner, spender, amount); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + }); + }); + + describe('when the spender had an approved amount', function () { + beforeEach(async function () { + await approve.call(this, owner, spender, new BN(1)); + }); + + it('approves the requested amount and replaces the previous one', async function () { + await approve.call(this, owner, spender, amount); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + }); + }); + }); + + describe('when the sender does not have enough balance', function () { + const amount = supply.addn(1); + + it('emits an approval event', async function () { + expectEvent(await approve.call(this, owner, spender, amount), 'Approval', { + owner: owner, + spender: spender, + value: amount, + }); + }); + + describe('when there was no approved amount before', function () { + it('approves the requested amount', async function () { + await approve.call(this, owner, spender, amount); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + }); + }); + + describe('when the spender had an approved amount', function () { + beforeEach(async function () { + await approve.call(this, owner, spender, new BN(1)); + }); + + it('approves the requested amount and replaces the previous one', async function () { + await approve.call(this, owner, spender, amount); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(amount); + }); + }); + }); + }); + + describe('when the spender is the zero address', function () { + it('reverts', async function () { + await expectRevert( + approve.call(this, owner, ZERO_ADDRESS, supply), + `${errorPrefix}: approve to the zero address`, + ); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/ERC20.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/ERC20.test.js new file mode 100644 index 0000000..6971eed --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/ERC20.test.js @@ -0,0 +1,305 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +} = require('./ERC20.behavior'); + +const ERC20 = artifacts.require('$ERC20'); +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); + +contract('ERC20', function (accounts) { + const [initialHolder, recipient, anotherAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.token = await ERC20.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + it('has a name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('has 18 decimals', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('18'); + }); + + describe('set decimals', function () { + const decimals = new BN(6); + + it('can set decimals during construction', async function () { + const token = await ERC20Decimals.new(name, symbol, decimals); + expect(await token.decimals()).to.be.bignumber.equal(decimals); + }); + }); + + shouldBehaveLikeERC20('ERC20', initialSupply, initialHolder, recipient, anotherAccount); + + describe('decrease allowance', function () { + describe('when the spender is not the zero address', function () { + const spender = recipient; + + function shouldDecreaseApproval(amount) { + describe('when there was no approved amount before', function () { + it('reverts', async function () { + await expectRevert( + this.token.decreaseAllowance(spender, amount, { from: initialHolder }), + 'ERC20: decreased allowance below zero', + ); + }); + }); + + describe('when the spender had an approved amount', function () { + const approvedAmount = amount; + + beforeEach(async function () { + await this.token.approve(spender, approvedAmount, { from: initialHolder }); + }); + + it('emits an approval event', async function () { + expectEvent( + await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }), + 'Approval', + { owner: initialHolder, spender: spender, value: new BN(0) }, + ); + }); + + it('decreases the spender allowance subtracting the requested amount', async function () { + await this.token.decreaseAllowance(spender, approvedAmount.subn(1), { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('1'); + }); + + it('sets the allowance to zero when all allowance is removed', async function () { + await this.token.decreaseAllowance(spender, approvedAmount, { from: initialHolder }); + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal('0'); + }); + + it('reverts when more than the full allowance is removed', async function () { + await expectRevert( + this.token.decreaseAllowance(spender, approvedAmount.addn(1), { from: initialHolder }), + 'ERC20: decreased allowance below zero', + ); + }); + }); + } + + describe('when the sender has enough balance', function () { + const amount = initialSupply; + + shouldDecreaseApproval(amount); + }); + + describe('when the sender does not have enough balance', function () { + const amount = initialSupply.addn(1); + + shouldDecreaseApproval(amount); + }); + }); + + describe('when the spender is the zero address', function () { + const amount = initialSupply; + const spender = ZERO_ADDRESS; + + it('reverts', async function () { + await expectRevert( + this.token.decreaseAllowance(spender, amount, { from: initialHolder }), + 'ERC20: decreased allowance below zero', + ); + }); + }); + }); + + describe('increase allowance', function () { + const amount = initialSupply; + + describe('when the spender is not the zero address', function () { + const spender = recipient; + + describe('when the sender has enough balance', function () { + it('emits an approval event', async function () { + expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', { + owner: initialHolder, + spender: spender, + value: amount, + }); + }); + + describe('when there was no approved amount before', function () { + it('approves the requested amount', async function () { + await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount); + }); + }); + + describe('when the spender had an approved amount', function () { + beforeEach(async function () { + await this.token.approve(spender, new BN(1), { from: initialHolder }); + }); + + it('increases the spender allowance adding the requested amount', async function () { + await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1)); + }); + }); + }); + + describe('when the sender does not have enough balance', function () { + const amount = initialSupply.addn(1); + + it('emits an approval event', async function () { + expectEvent(await this.token.increaseAllowance(spender, amount, { from: initialHolder }), 'Approval', { + owner: initialHolder, + spender: spender, + value: amount, + }); + }); + + describe('when there was no approved amount before', function () { + it('approves the requested amount', async function () { + await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount); + }); + }); + + describe('when the spender had an approved amount', function () { + beforeEach(async function () { + await this.token.approve(spender, new BN(1), { from: initialHolder }); + }); + + it('increases the spender allowance adding the requested amount', async function () { + await this.token.increaseAllowance(spender, amount, { from: initialHolder }); + + expect(await this.token.allowance(initialHolder, spender)).to.be.bignumber.equal(amount.addn(1)); + }); + }); + }); + }); + + describe('when the spender is the zero address', function () { + const spender = ZERO_ADDRESS; + + it('reverts', async function () { + await expectRevert( + this.token.increaseAllowance(spender, amount, { from: initialHolder }), + 'ERC20: approve to the zero address', + ); + }); + }); + }); + + describe('_mint', function () { + const amount = new BN(50); + it('rejects a null account', async function () { + await expectRevert(this.token.$_mint(ZERO_ADDRESS, amount), 'ERC20: mint to the zero address'); + }); + + describe('for a non zero account', function () { + beforeEach('minting', async function () { + this.receipt = await this.token.$_mint(recipient, amount); + }); + + it('increments totalSupply', async function () { + const expectedSupply = initialSupply.add(amount); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + + it('increments recipient balance', async function () { + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + }); + + it('emits Transfer event', async function () { + const event = expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: recipient }); + + expect(event.args.value).to.be.bignumber.equal(amount); + }); + }); + }); + + describe('_burn', function () { + it('rejects a null account', async function () { + await expectRevert(this.token.$_burn(ZERO_ADDRESS, new BN(1)), 'ERC20: burn from the zero address'); + }); + + describe('for a non zero account', function () { + it('rejects burning more than balance', async function () { + await expectRevert( + this.token.$_burn(initialHolder, initialSupply.addn(1)), + 'ERC20: burn amount exceeds balance', + ); + }); + + const describeBurn = function (description, amount) { + describe(description, function () { + beforeEach('burning', async function () { + this.receipt = await this.token.$_burn(initialHolder, amount); + }); + + it('decrements totalSupply', async function () { + const expectedSupply = initialSupply.sub(amount); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + + it('decrements initialHolder balance', async function () { + const expectedBalance = initialSupply.sub(amount); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(expectedBalance); + }); + + it('emits Transfer event', async function () { + const event = expectEvent(this.receipt, 'Transfer', { from: initialHolder, to: ZERO_ADDRESS }); + + expect(event.args.value).to.be.bignumber.equal(amount); + }); + }); + }; + + describeBurn('for entire balance', initialSupply); + describeBurn('for less amount than balance', initialSupply.subn(1)); + }); + }); + + describe('_transfer', function () { + shouldBehaveLikeERC20Transfer('ERC20', initialHolder, recipient, initialSupply, function (from, to, amount) { + return this.token.$_transfer(from, to, amount); + }); + + describe('when the sender is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.token.$_transfer(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20: transfer from the zero address', + ); + }); + }); + }); + + describe('_approve', function () { + shouldBehaveLikeERC20Approve('ERC20', initialHolder, recipient, initialSupply, function (owner, spender, amount) { + return this.token.$_approve(owner, spender, amount); + }); + + describe('when the owner is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.token.$_approve(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20: approve from the zero address', + ); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Burnable.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Burnable.behavior.js new file mode 100644 index 0000000..2edabc4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Burnable.behavior.js @@ -0,0 +1,106 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +function shouldBehaveLikeERC20Burnable(owner, initialBalance, [burner]) { + describe('burn', function () { + describe('when the given amount is not greater than balance of the sender', function () { + context('for a zero amount', function () { + shouldBurn(new BN(0)); + }); + + context('for a non-zero amount', function () { + shouldBurn(new BN(100)); + }); + + function shouldBurn(amount) { + beforeEach(async function () { + this.receipt = await this.token.burn(amount, { from: owner }); + }); + + it('burns the requested amount', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(amount)); + }); + + it('emits a transfer event', async function () { + expectEvent(this.receipt, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + value: amount, + }); + }); + } + }); + + describe('when the given amount is greater than the balance of the sender', function () { + const amount = initialBalance.addn(1); + + it('reverts', async function () { + await expectRevert(this.token.burn(amount, { from: owner }), 'ERC20: burn amount exceeds balance'); + }); + }); + }); + + describe('burnFrom', function () { + describe('on success', function () { + context('for a zero amount', function () { + shouldBurnFrom(new BN(0)); + }); + + context('for a non-zero amount', function () { + shouldBurnFrom(new BN(100)); + }); + + function shouldBurnFrom(amount) { + const originalAllowance = amount.muln(3); + + beforeEach(async function () { + await this.token.approve(burner, originalAllowance, { from: owner }); + this.receipt = await this.token.burnFrom(owner, amount, { from: burner }); + }); + + it('burns the requested amount', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(amount)); + }); + + it('decrements allowance', async function () { + expect(await this.token.allowance(owner, burner)).to.be.bignumber.equal(originalAllowance.sub(amount)); + }); + + it('emits a transfer event', async function () { + expectEvent(this.receipt, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + value: amount, + }); + }); + } + }); + + describe('when the given amount is greater than the balance of the sender', function () { + const amount = initialBalance.addn(1); + + it('reverts', async function () { + await this.token.approve(burner, amount, { from: owner }); + await expectRevert(this.token.burnFrom(owner, amount, { from: burner }), 'ERC20: burn amount exceeds balance'); + }); + }); + + describe('when the given amount is greater than the allowance', function () { + const allowance = new BN(100); + + it('reverts', async function () { + await this.token.approve(burner, allowance, { from: owner }); + await expectRevert( + this.token.burnFrom(owner, allowance.addn(1), { from: burner }), + 'ERC20: insufficient allowance', + ); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20Burnable, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Burnable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Burnable.test.js new file mode 100644 index 0000000..00acc81 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Burnable.test.js @@ -0,0 +1,20 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { shouldBehaveLikeERC20Burnable } = require('./ERC20Burnable.behavior'); +const ERC20Burnable = artifacts.require('$ERC20Burnable'); + +contract('ERC20Burnable', function (accounts) { + const [owner, ...otherAccounts] = accounts; + + const initialBalance = new BN(1000); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Burnable.new(name, symbol, { from: owner }); + await this.token.$_mint(owner, initialBalance); + }); + + shouldBehaveLikeERC20Burnable(owner, initialBalance, otherAccounts); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Capped.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Capped.behavior.js new file mode 100644 index 0000000..97bad1d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Capped.behavior.js @@ -0,0 +1,32 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +function shouldBehaveLikeERC20Capped(accounts, cap) { + describe('capped token', function () { + const user = accounts[0]; + + it('starts with the correct cap', async function () { + expect(await this.token.cap()).to.be.bignumber.equal(cap); + }); + + it('mints when amount is less than cap', async function () { + await this.token.$_mint(user, cap.subn(1)); + expect(await this.token.totalSupply()).to.be.bignumber.equal(cap.subn(1)); + }); + + it('fails to mint if the amount exceeds the cap', async function () { + await this.token.$_mint(user, cap.subn(1)); + await expectRevert(this.token.$_mint(user, 2), 'ERC20Capped: cap exceeded'); + }); + + it('fails to mint after cap is reached', async function () { + await this.token.$_mint(user, cap); + await expectRevert(this.token.$_mint(user, 1), 'ERC20Capped: cap exceeded'); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20Capped, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Capped.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Capped.test.js new file mode 100644 index 0000000..a86d38c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Capped.test.js @@ -0,0 +1,23 @@ +const { ether, expectRevert } = require('@openzeppelin/test-helpers'); +const { shouldBehaveLikeERC20Capped } = require('./ERC20Capped.behavior'); + +const ERC20Capped = artifacts.require('$ERC20Capped'); + +contract('ERC20Capped', function (accounts) { + const cap = ether('1000'); + + const name = 'My Token'; + const symbol = 'MTKN'; + + it('requires a non-zero cap', async function () { + await expectRevert(ERC20Capped.new(name, symbol, 0), 'ERC20Capped: cap is 0'); + }); + + context('once deployed', async function () { + beforeEach(async function () { + this.token = await ERC20Capped.new(name, symbol, cap); + }); + + shouldBehaveLikeERC20Capped(accounts, cap); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20FlashMint.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20FlashMint.test.js new file mode 100644 index 0000000..76d66ff --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20FlashMint.test.js @@ -0,0 +1,204 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const ERC20FlashMintMock = artifacts.require('$ERC20FlashMintMock'); +const ERC3156FlashBorrowerMock = artifacts.require('ERC3156FlashBorrowerMock'); + +contract('ERC20FlashMint', function (accounts) { + const [initialHolder, other, anotherAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + const loanAmount = new BN(10000000000000); + + beforeEach(async function () { + this.token = await ERC20FlashMintMock.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + describe('maxFlashLoan', function () { + it('token match', async function () { + expect(await this.token.maxFlashLoan(this.token.address)).to.be.bignumber.equal(MAX_UINT256.sub(initialSupply)); + }); + + it('token mismatch', async function () { + expect(await this.token.maxFlashLoan(ZERO_ADDRESS)).to.be.bignumber.equal('0'); + }); + }); + + describe('flashFee', function () { + it('token match', async function () { + expect(await this.token.flashFee(this.token.address, loanAmount)).to.be.bignumber.equal('0'); + }); + + it('token mismatch', async function () { + await expectRevert(this.token.flashFee(ZERO_ADDRESS, loanAmount), 'ERC20FlashMint: wrong token'); + }); + }); + + describe('flashFeeReceiver', function () { + it('default receiver', async function () { + expect(await this.token.$_flashFeeReceiver()).to.be.eq(ZERO_ADDRESS); + }); + }); + + describe('flashLoan', function () { + it('success', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const { tx } = await this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver.address, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: receiver.address, + to: ZERO_ADDRESS, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, receiver, 'BalanceOf', { + token: this.token.address, + account: receiver.address, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(loanAmount), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + expect(await this.token.balanceOf(receiver.address)).to.be.bignumber.equal('0'); + expect(await this.token.allowance(receiver.address, this.token.address)).to.be.bignumber.equal('0'); + }); + + it('missing return value', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(false, true); + await expectRevert( + this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'), + 'ERC20FlashMint: invalid return value', + ); + }); + + it('missing approval', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, false); + await expectRevert( + this.token.flashLoan(receiver.address, this.token.address, loanAmount, '0x'), + 'ERC20: insufficient allowance', + ); + }); + + it('unavailable funds', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const data = this.token.contract.methods.transfer(other, 10).encodeABI(); + await expectRevert( + this.token.flashLoan(receiver.address, this.token.address, loanAmount, data), + 'ERC20: burn amount exceeds balance', + ); + }); + + it('more than maxFlashLoan', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const data = this.token.contract.methods.transfer(other, 10).encodeABI(); + // _mint overflow reverts using a panic code. No reason string. + await expectRevert.unspecified(this.token.flashLoan(receiver.address, this.token.address, MAX_UINT256, data)); + }); + + describe('custom flash fee & custom fee receiver', function () { + const receiverInitialBalance = new BN(200000); + const flashFee = new BN(5000); + + beforeEach('init receiver balance & set flash fee', async function () { + this.receiver = await ERC3156FlashBorrowerMock.new(true, true); + const receipt = await this.token.$_mint(this.receiver.address, receiverInitialBalance); + await expectEvent(receipt, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: receiverInitialBalance, + }); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal(receiverInitialBalance); + + await this.token.setFlashFee(flashFee); + expect(await this.token.flashFee(this.token.address, loanAmount)).to.be.bignumber.equal(flashFee); + }); + + it('default flash fee receiver', async function () { + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanAmount, '0x'); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: ZERO_ADDRESS, + value: loanAmount.add(flashFee), + }); + await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { + token: this.token.address, + account: this.receiver.address, + value: receiverInitialBalance.add(loanAmount), + }); + await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(receiverInitialBalance).add(loanAmount), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal( + initialSupply.add(receiverInitialBalance).sub(flashFee), + ); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal( + receiverInitialBalance.sub(flashFee), + ); + expect(await this.token.balanceOf(await this.token.$_flashFeeReceiver())).to.be.bignumber.equal('0'); + expect(await this.token.allowance(this.receiver.address, this.token.address)).to.be.bignumber.equal('0'); + }); + + it('custom flash fee receiver', async function () { + const flashFeeReceiverAddress = anotherAccount; + await this.token.setFlashFeeReceiver(flashFeeReceiverAddress); + expect(await this.token.$_flashFeeReceiver()).to.be.eq(flashFeeReceiverAddress); + + expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal('0'); + + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanAmount, '0x'); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: ZERO_ADDRESS, + value: loanAmount, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: flashFeeReceiverAddress, + value: flashFee, + }); + await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { + token: this.token.address, + account: this.receiver.address, + value: receiverInitialBalance.add(loanAmount), + }); + await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(receiverInitialBalance).add(loanAmount), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply.add(receiverInitialBalance)); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal( + receiverInitialBalance.sub(flashFee), + ); + expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal(flashFee); + expect(await this.token.allowance(this.receiver.address, flashFeeReceiverAddress)).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Pausable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Pausable.test.js new file mode 100644 index 0000000..ead442b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Pausable.test.js @@ -0,0 +1,133 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC20Pausable = artifacts.require('$ERC20Pausable'); + +contract('ERC20Pausable', function (accounts) { + const [holder, recipient, anotherAccount] = accounts; + + const initialSupply = new BN(100); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Pausable.new(name, symbol); + await this.token.$_mint(holder, initialSupply); + }); + + describe('pausable token', function () { + describe('transfer', function () { + it('allows to transfer when unpaused', async function () { + await this.token.transfer(recipient, initialSupply, { from: holder }); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.transfer(recipient, initialSupply, { from: holder }); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); + }); + + it('reverts when trying to transfer when paused', async function () { + await this.token.$_pause(); + + await expectRevert( + this.token.transfer(recipient, initialSupply, { from: holder }), + 'ERC20Pausable: token transfer while paused', + ); + }); + }); + + describe('transfer from', function () { + const allowance = new BN(40); + + beforeEach(async function () { + await this.token.approve(anotherAccount, allowance, { from: holder }); + }); + + it('allows to transfer from when unpaused', async function () { + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); + }); + + it('reverts when trying to transfer from when paused', async function () { + await this.token.$_pause(); + + await expectRevert( + this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }), + 'ERC20Pausable: token transfer while paused', + ); + }); + }); + + describe('mint', function () { + const amount = new BN('42'); + + it('allows to mint when unpaused', async function () { + await this.token.$_mint(recipient, amount); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + }); + + it('allows to mint when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.$_mint(recipient, amount); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(amount); + }); + + it('reverts when trying to mint when paused', async function () { + await this.token.$_pause(); + + await expectRevert(this.token.$_mint(recipient, amount), 'ERC20Pausable: token transfer while paused'); + }); + }); + + describe('burn', function () { + const amount = new BN('42'); + + it('allows to burn when unpaused', async function () { + await this.token.$_burn(holder, amount); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(amount)); + }); + + it('allows to burn when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.$_burn(holder, amount); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(amount)); + }); + + it('reverts when trying to burn when paused', async function () { + await this.token.$_pause(); + + await expectRevert(this.token.$_burn(holder, amount), 'ERC20Pausable: token transfer while paused'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Snapshot.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Snapshot.test.js new file mode 100644 index 0000000..fb0bb31 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Snapshot.test.js @@ -0,0 +1,207 @@ +const { BN, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const ERC20Snapshot = artifacts.require('$ERC20Snapshot'); + +const { expect } = require('chai'); + +contract('ERC20Snapshot', function (accounts) { + const [initialHolder, recipient, other] = accounts; + + const initialSupply = new BN(100); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Snapshot.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + describe('snapshot', function () { + it('emits a snapshot event', async function () { + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot'); + }); + + it('creates increasing snapshots ids, starting from 1', async function () { + for (const id of ['1', '2', '3', '4', '5']) { + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id }); + } + }); + }); + + describe('totalSupplyAt', function () { + it('reverts with a snapshot id of 0', async function () { + await expectRevert(this.token.totalSupplyAt(0), 'ERC20Snapshot: id is 0'); + }); + + it('reverts with a not-yet-created snapshot id', async function () { + await expectRevert(this.token.totalSupplyAt(1), 'ERC20Snapshot: nonexistent id'); + }); + + context('with initial snapshot', function () { + beforeEach(async function () { + this.initialSnapshotId = new BN('1'); + + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id: this.initialSnapshotId }); + }); + + context('with no supply changes after the snapshot', function () { + it('returns the current total supply', async function () { + expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply); + }); + }); + + context('with supply changes after the snapshot', function () { + beforeEach(async function () { + await this.token.$_mint(other, new BN('50')); + await this.token.$_burn(initialHolder, new BN('20')); + }); + + it('returns the total supply before the changes', async function () { + expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply); + }); + + context('with a second snapshot after supply changes', function () { + beforeEach(async function () { + this.secondSnapshotId = new BN('2'); + + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id: this.secondSnapshotId }); + }); + + it('snapshots return the supply before and after the changes', async function () { + expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply); + + expect(await this.token.totalSupplyAt(this.secondSnapshotId)).to.be.bignumber.equal( + await this.token.totalSupply(), + ); + }); + }); + + context('with multiple snapshots after supply changes', function () { + beforeEach(async function () { + this.secondSnapshotIds = ['2', '3', '4']; + + for (const id of this.secondSnapshotIds) { + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id }); + } + }); + + it('all posterior snapshots return the supply after the changes', async function () { + expect(await this.token.totalSupplyAt(this.initialSnapshotId)).to.be.bignumber.equal(initialSupply); + + const currentSupply = await this.token.totalSupply(); + + for (const id of this.secondSnapshotIds) { + expect(await this.token.totalSupplyAt(id)).to.be.bignumber.equal(currentSupply); + } + }); + }); + }); + }); + }); + + describe('balanceOfAt', function () { + it('reverts with a snapshot id of 0', async function () { + await expectRevert(this.token.balanceOfAt(other, 0), 'ERC20Snapshot: id is 0'); + }); + + it('reverts with a not-yet-created snapshot id', async function () { + await expectRevert(this.token.balanceOfAt(other, 1), 'ERC20Snapshot: nonexistent id'); + }); + + context('with initial snapshot', function () { + beforeEach(async function () { + this.initialSnapshotId = new BN('1'); + + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id: this.initialSnapshotId }); + }); + + context('with no balance changes after the snapshot', function () { + it('returns the current balance for all accounts', async function () { + expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId)).to.be.bignumber.equal( + initialSupply, + ); + expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0'); + }); + }); + + context('with balance changes after the snapshot', function () { + beforeEach(async function () { + await this.token.transfer(recipient, new BN('10'), { from: initialHolder }); + await this.token.$_mint(other, new BN('50')); + await this.token.$_burn(initialHolder, new BN('20')); + }); + + it('returns the balances before the changes', async function () { + expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId)).to.be.bignumber.equal( + initialSupply, + ); + expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0'); + }); + + context('with a second snapshot after supply changes', function () { + beforeEach(async function () { + this.secondSnapshotId = new BN('2'); + + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id: this.secondSnapshotId }); + }); + + it('snapshots return the balances before and after the changes', async function () { + expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId)).to.be.bignumber.equal( + initialSupply, + ); + expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOfAt(initialHolder, this.secondSnapshotId)).to.be.bignumber.equal( + await this.token.balanceOf(initialHolder), + ); + expect(await this.token.balanceOfAt(recipient, this.secondSnapshotId)).to.be.bignumber.equal( + await this.token.balanceOf(recipient), + ); + expect(await this.token.balanceOfAt(other, this.secondSnapshotId)).to.be.bignumber.equal( + await this.token.balanceOf(other), + ); + }); + }); + + context('with multiple snapshots after supply changes', function () { + beforeEach(async function () { + this.secondSnapshotIds = ['2', '3', '4']; + + for (const id of this.secondSnapshotIds) { + const receipt = await this.token.$_snapshot(); + expectEvent(receipt, 'Snapshot', { id }); + } + }); + + it('all posterior snapshots return the supply after the changes', async function () { + expect(await this.token.balanceOfAt(initialHolder, this.initialSnapshotId)).to.be.bignumber.equal( + initialSupply, + ); + expect(await this.token.balanceOfAt(recipient, this.initialSnapshotId)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOfAt(other, this.initialSnapshotId)).to.be.bignumber.equal('0'); + + for (const id of this.secondSnapshotIds) { + expect(await this.token.balanceOfAt(initialHolder, id)).to.be.bignumber.equal( + await this.token.balanceOf(initialHolder), + ); + expect(await this.token.balanceOfAt(recipient, id)).to.be.bignumber.equal( + await this.token.balanceOf(recipient), + ); + expect(await this.token.balanceOfAt(other, id)).to.be.bignumber.equal(await this.token.balanceOf(other)); + } + }); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Votes.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Votes.test.js new file mode 100644 index 0000000..e722ed1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Votes.test.js @@ -0,0 +1,578 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { batchInBlock } = require('../../../helpers/txpool'); +const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { clock, clockFromReceipt } = require('../../../helpers/time'); + +const { shouldBehaveLikeEIP6372 } = require('../../../governance/utils/EIP6372.behavior'); + +const Delegation = [ + { name: 'delegatee', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { 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 supply = new BN('10000000000000000000000000'); + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.token = await artifact.new(name, symbol, name); + }); + + shouldBehaveLikeEIP6372(mode); + + 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 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); + }); + }); + + 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, + })); + + 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', + ); + }); + }); + }); + + 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 }); + 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); + }); + }); + + 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 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); + }); + }); + + // 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 }); + 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', + ); + }); + }); + }); + + 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: future lookup'); + }); + + 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', + ); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20VotesComp.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20VotesComp.test.js new file mode 100644 index 0000000..5f95722 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20VotesComp.test.js @@ -0,0 +1,543 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { batchInBlock } = require('../../../helpers/txpool'); +const { getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { clock, clockFromReceipt } = require('../../../helpers/time'); + +const { shouldBehaveLikeEIP6372 } = require('../../../governance/utils/EIP6372.behavior'); + +const Delegation = [ + { name: 'delegatee', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { 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 supply = new BN('10000000000000000000000000'); + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.token = await artifact.new(name, symbol, name); + }); + + shouldBehaveLikeEIP6372(mode); + + 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 }); + 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); + }); + }); + + 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, + })); + + 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', + ); + }); + }); + }); + + 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 }); + 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); + }); + }); + + 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 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); + }); + }); + + // 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 }); + 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', + ); + }); + }); + }); + + 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: future lookup'); + }); + + 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', + ); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Wrapper.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Wrapper.test.js new file mode 100644 index 0000000..cfb47bf --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC20Wrapper.test.js @@ -0,0 +1,190 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS, MAX_UINT256 } = constants; + +const { shouldBehaveLikeERC20 } = require('../ERC20.behavior'); + +const NotAnERC20 = artifacts.require('CallReceiverMock'); +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); +const ERC20Wrapper = artifacts.require('$ERC20Wrapper'); + +contract('ERC20', function (accounts) { + const [initialHolder, recipient, anotherAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.underlying = await ERC20Decimals.new(name, symbol, 9); + await this.underlying.$_mint(initialHolder, initialSupply); + + this.token = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, this.underlying.address); + }); + + afterEach(async function () { + expect(await this.underlying.balanceOf(this.token.address)).to.be.bignumber.equal(await this.token.totalSupply()); + }); + + 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 the same decimals as the underlying token', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('9'); + }); + + it('decimals default back to 18 if token has no metadata', async function () { + const noDecimals = await NotAnERC20.new(); + const otherToken = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, noDecimals.address); + expect(await otherToken.decimals()).to.be.bignumber.equal('18'); + }); + + it('has underlying', async function () { + expect(await this.token.underlying()).to.be.bignumber.equal(this.underlying.address); + }); + + describe('deposit', function () { + it('valid', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + const { tx } = await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: initialHolder, + value: initialSupply, + }); + }); + + it('missing approval', async function () { + await expectRevert( + this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }), + 'ERC20: insufficient allowance', + ); + }); + + it('missing balance', async function () { + await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder }); + await expectRevert( + this.token.depositFor(initialHolder, MAX_UINT256, { from: initialHolder }), + 'ERC20: transfer amount exceeds balance', + ); + }); + + it('to other account', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + const { tx } = await this.token.depositFor(anotherAccount, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: anotherAccount, + value: initialSupply, + }); + }); + }); + + describe('withdraw', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + }); + + it('missing balance', async function () { + await expectRevert( + this.token.withdrawTo(initialHolder, MAX_UINT256, { from: initialHolder }), + 'ERC20: burn amount exceeds balance', + ); + }); + + it('valid', async function () { + const value = new BN(42); + + const { tx } = await this.token.withdrawTo(initialHolder, value, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + value: value, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: value, + }); + }); + + it('entire balance', async function () { + const { tx } = await this.token.withdrawTo(initialHolder, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: initialSupply, + }); + }); + + it('to other account', async function () { + const { tx } = await this.token.withdrawTo(anotherAccount, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: anotherAccount, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: initialSupply, + }); + }); + }); + + describe('recover', function () { + it('nothing to recover', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + + const { tx } = await this.token.$_recover(anotherAccount); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: anotherAccount, + value: '0', + }); + }); + + it('something to recover', async function () { + await this.underlying.transfer(this.token.address, initialSupply, { from: initialHolder }); + + const { tx } = await this.token.$_recover(anotherAccount); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: anotherAccount, + value: initialSupply, + }); + }); + }); + + describe('erc20 behaviour', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + }); + + shouldBehaveLikeERC20('ERC20', initialSupply, initialHolder, recipient, anotherAccount); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC4626.t.sol b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC4626.t.sol new file mode 100644 index 0000000..f220086 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC4626.t.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {ERC4626Test} from "erc4626-tests/ERC4626.test.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(_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/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC4626.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC4626.test.js new file mode 100644 index 0000000..55b3e5d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/ERC4626.test.js @@ -0,0 +1,1031 @@ +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; + + const name = 'My Token'; + const symbol = 'MTKN'; + 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)) { + const token = await ERC20Decimals.new('', '', decimals); + const vault = await ERC4626.new('', '', token.address); + expect(await vault.decimals()).to.be.bignumber.equal(decimals); + } + }); + + 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)', + ); + } + }); + + 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); + + const virtualAssets = web3.utils.toBN(1); + const virtualShares = web3.utils.toBN(10).pow(offset); + + 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 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 }); + }); + + 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), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: parseToken(1), + shares: 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), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: parseToken(1), + shares: 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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: depositAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: expectedAssets, + shares: 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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: depositAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: expectedAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: withdrawAssets, + shares: 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 () { + const effectiveAssets = await this.vault.totalAssets().then(x => x.add(virtualAssets)); + const effectiveShares = await this.vault.totalSupply().then(x => x.add(virtualShares)); + + 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: expectedAssets, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: redeemShares, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: expectedAssets, + shares: redeemShares, + }); + }); + + 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 }); + }); + }); + }); + } + + 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 () { + // test designed with both asset using similar decimals + this.token = await ERC20Decimals.new(name, symbol, 18); + this.vault = await ERC4626.new(name + ' Vault', symbol + 'V', this.token.address); + + await this.token.$_mint(user1, 4000); + await this.token.$_mint(user2, 7001); + await this.token.approve(this.vault.address, 4000, { from: user1 }); + await this.token.approve(this.vault.address, 7001, { from: user2 }); + + // 1. Alice mints 2000 shares (costs 2000 tokens) + { + const { tx } = await this.vault.mint(2000, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user1, + to: this.vault.address, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + value: '2000', + }); + + expect(await this.vault.previewDeposit(2000)).to.be.bignumber.equal('2000'); + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('2000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('0'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('2000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('2000'); + } + + // 2. Bob deposits 4000 tokens (mints 4000 shares) + { + const { tx } = await this.vault.mint(4000, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user2, + to: this.vault.address, + value: '4000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + value: '4000', + }); + + expect(await this.vault.previewDeposit(4000)).to.be.bignumber.equal('4000'); + 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('2000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('4000'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('6000'); + } + + // 3. Vault mutates by +3000 tokens (simulated yield returned from strategy) + await this.token.$_mint(this.vault.address, 3000); + + 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('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'); + + // 4. Alice deposits 2000 tokens (mints 1333 shares) + { + const { tx } = await this.vault.deposit(2000, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user1, + to: this.vault.address, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + value: '1333', + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333'); + 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('4999'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('6000'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('7333'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('11000'); + } + + // 5. Bob mints 2000 shares (costs 3001 assets) + // NOTE: Bob's assets spent got rounded up + // NOTE: Alices's vault assets got rounded up + { + const { tx } = await this.vault.mint(2000, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user2, + to: this.vault.address, + value: '3000', // used to be 3001 + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + value: '2000', + }); + + 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('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('14000'); // used to be 14001 + } + + // 6. Vault mutates by +3000 tokens + // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000. + await this.token.$_mint(this.vault.address, 3000); + + 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('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('17000'); // used to be 17001 + + // 7. Alice redeem 1333 shares (2428 assets) + { + const { tx } = await this.vault.redeem(1333, user1, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + value: '1333', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user1, + value: '2427', // used to be 2428 + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + 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('3643'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('10929'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('8000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('14573'); + } + + // 8. Bob withdraws 2929 assets (1608 shares) + { + const { tx } = await this.vault.withdraw(2929, user2, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user2, + to: constants.ZERO_ADDRESS, + value: '1608', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user2, + value: '2929', + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + 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('3643'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('8000'); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6392'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('11644'); + } + + // 9. Alice withdraws 3643 assets (2000 shares) + // NOTE: Bob's assets have been rounded back up + { + const { tx } = await this.vault.withdraw(3643, user1, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user1, + value: '3643', + }); + + 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('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'); + } + + // 10. Bob redeem 4392 shares (8001 tokens) + { + const { tx } = await this.vault.redeem(4392, user2, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user2, + to: constants.ZERO_ADDRESS, + value: '4392', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user2, + value: '8000', // used to be 8001 + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('0'); + expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0'); + 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('1'); // used to be 0 + } + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/draft-ERC20Permit.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/draft-ERC20Permit.test.js new file mode 100644 index 0000000..33c43c4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/extensions/draft-ERC20Permit.test.js @@ -0,0 +1,103 @@ +/* eslint-disable */ + +const { BN, constants, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256 } = constants; + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const ERC20Permit = artifacts.require('$ERC20Permit'); + +const { Permit, getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { getChainId } = require('../../../helpers/chainid'); + +contract('ERC20Permit', function (accounts) { + const [initialHolder, spender] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + const version = '1'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.chainId = await getChainId(); + + this.token = await ERC20Permit.new(name, symbol, name); + await this.token.$_mint(initialHolder, initialSupply); + }); + + it('initial nonce is 0', async function () { + expect(await this.token.nonces(initialHolder)).to.be.bignumber.equal('0'); + }); + + it('domain separator', async function () { + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); + }); + + describe('permit', function () { + const wallet = Wallet.generate(); + + const owner = wallet.getAddressString(); + const value = new BN(42); + const nonce = 0; + const maxDeadline = MAX_UINT256; + + 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 { 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); + + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + + it('rejects reused signature', async function () { + 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); + + await expectRevert( + this.token.permit(owner, spender, value, maxDeadline, v, r, s), + 'ERC20Permit: invalid signature', + ); + }); + + it('rejects other signature', async function () { + const otherWallet = Wallet.generate(); + + 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), + 'ERC20Permit: invalid signature', + ); + }); + + it('rejects expired permit', async function () { + const deadline = (await time.latest()) - time.duration.weeks(1); + + 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/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js new file mode 100644 index 0000000..f1d0b53 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/presets/ERC20PresetFixedSupply.test.js @@ -0,0 +1,42 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const ERC20PresetFixedSupply = artifacts.require('ERC20PresetFixedSupply'); + +contract('ERC20PresetFixedSupply', function (accounts) { + const [deployer, owner] = accounts; + + const name = 'PresetFixedSupply'; + const symbol = 'PFS'; + + const initialSupply = new BN('50000'); + const amount = new BN('10000'); + + before(async function () { + this.token = await ERC20PresetFixedSupply.new(name, symbol, initialSupply, owner, { from: deployer }); + }); + + it('deployer has the balance equal to initial supply', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialSupply); + }); + + it('total supply is equal to initial supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + + describe('burning', function () { + it('holders can burn their tokens', async function () { + const remainingBalance = initialSupply.sub(amount); + const receipt = await this.token.burn(amount, { from: owner }); + expectEvent(receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, value: amount }); + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(remainingBalance); + }); + + it('decrements totalSupply', async function () { + const expectedSupply = initialSupply.sub(amount); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js new file mode 100644 index 0000000..ad9ff29 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/presets/ERC20PresetMinterPauser.test.js @@ -0,0 +1,110 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const ERC20PresetMinterPauser = artifacts.require('ERC20PresetMinterPauser'); + +contract('ERC20PresetMinterPauser', function (accounts) { + const [deployer, other] = accounts; + + const name = 'MinterPauserToken'; + const symbol = 'DRT'; + + const amount = new BN('5000'); + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const MINTER_ROLE = web3.utils.soliditySha3('MINTER_ROLE'); + const PAUSER_ROLE = web3.utils.soliditySha3('PAUSER_ROLE'); + + beforeEach(async function () { + this.token = await ERC20PresetMinterPauser.new(name, symbol, { from: deployer }); + }); + + it('deployer has the default admin role', async function () { + expect(await this.token.getRoleMemberCount(DEFAULT_ADMIN_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(DEFAULT_ADMIN_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the minter role', async function () { + expect(await this.token.getRoleMemberCount(MINTER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(MINTER_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the pauser role', async function () { + expect(await this.token.getRoleMemberCount(PAUSER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(PAUSER_ROLE, 0)).to.equal(deployer); + }); + + it('minter and pauser role admin is the default admin', async function () { + expect(await this.token.getRoleAdmin(MINTER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + expect(await this.token.getRoleAdmin(PAUSER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + describe('minting', function () { + it('deployer can mint tokens', async function () { + const receipt = await this.token.mint(other, amount, { from: deployer }); + expectEvent(receipt, 'Transfer', { from: ZERO_ADDRESS, to: other, value: amount }); + + expect(await this.token.balanceOf(other)).to.be.bignumber.equal(amount); + }); + + it('other accounts cannot mint tokens', async function () { + await expectRevert( + this.token.mint(other, amount, { from: other }), + 'ERC20PresetMinterPauser: must have minter role to mint', + ); + }); + }); + + describe('pausing', function () { + it('deployer can pause', async function () { + const receipt = await this.token.pause({ from: deployer }); + expectEvent(receipt, 'Paused', { account: deployer }); + + expect(await this.token.paused()).to.equal(true); + }); + + it('deployer can unpause', async function () { + await this.token.pause({ from: deployer }); + + const receipt = await this.token.unpause({ from: deployer }); + expectEvent(receipt, 'Unpaused', { account: deployer }); + + expect(await this.token.paused()).to.equal(false); + }); + + it('cannot mint while paused', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.mint(other, amount, { from: deployer }), + 'ERC20Pausable: token transfer while paused', + ); + }); + + it('other accounts cannot pause', async function () { + await expectRevert(this.token.pause({ from: other }), 'ERC20PresetMinterPauser: must have pauser role to pause'); + }); + + it('other accounts cannot unpause', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.unpause({ from: other }), + 'ERC20PresetMinterPauser: must have pauser role to unpause', + ); + }); + }); + + describe('burning', function () { + it('holders can burn their tokens', async function () { + await this.token.mint(other, amount, { from: deployer }); + + const receipt = await this.token.burn(amount.subn(1), { from: other }); + expectEvent(receipt, 'Transfer', { from: other, to: ZERO_ADDRESS, value: amount.subn(1) }); + + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('1'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/utils/SafeERC20.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/utils/SafeERC20.test.js new file mode 100644 index 0000000..d4981dd --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/utils/SafeERC20.test.js @@ -0,0 +1,350 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const SafeERC20 = artifacts.require('$SafeERC20'); +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'); + +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; + + before(async function () { + this.mock = await SafeERC20.new(); + }); + + describe('with address that has no contract code', function () { + beforeEach(async function () { + this.token = { address: hasNoCode }; + }); + + 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(name, symbol); + }); + + 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(name, symbol); + }); + + shouldOnlyRevertOnErrors(accounts); + }); + + describe('with token that returns no boolean values', function () { + beforeEach(async function () { + this.token = await ERC20NoReturnMock.new(name, symbol); + }); + + shouldOnlyRevertOnErrors(accounts); + }); + + describe("with token that doesn't revert on invalid permit", function () { + const wallet = Wallet.generate(); + const owner = wallet.getAddressString(); + const spender = hasNoCode; + + beforeEach(async function () { + this.token = await ERC20PermitNoRevertMock.new(name, symbol, name); + + this.data = await getDomain(this.token).then(domain => ({ + primaryType: 'Permit', + 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 })); + }); + + it('accepts owner signature', async function () { + expect(await this.token.nonces(owner)).to.be.bignumber.equal('0'); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal('0'); + + await this.mock.$safePermit( + this.token.address, + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + this.signature.v, + this.signature.r, + this.signature.s, + ); + + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(this.data.message.value); + }); + + it('revert on reused signature', async function () { + expect(await this.token.nonces(owner)).to.be.bignumber.equal('0'); + // use valid signature and consume nounce + await this.mock.$safePermit( + this.token.address, + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + this.signature.v, + this.signature.r, + this.signature.s, + ); + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + // invalid call does not revert for this token implementation + await this.token.permit( + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + this.signature.v, + this.signature.r, + this.signature.s, + ); + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + // invalid call revert when called through the SafeERC20 library + await expectRevert( + this.mock.$safePermit( + this.token.address, + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + this.signature.v, + this.signature.r, + this.signature.s, + ), + 'SafeERC20: permit did not succeed', + ); + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + }); + + it('revert on invalid signature', async function () { + // signature that is not valid for owner + const invalidSignature = { + v: 27, + r: '0x71753dc5ecb5b4bfc0e3bc530d79ce5988760ed3f3a234c86a5546491f540775', + s: '0x0049cedee5aed990aabed5ad6a9f6e3c565b63379894b5fa8b512eb2b79e485d', + }; + + // invalid call does not revert for this token implementation + await this.token.permit( + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + invalidSignature.v, + invalidSignature.r, + invalidSignature.s, + ); + + // invalid call revert when called through the SafeERC20 library + await expectRevert( + this.mock.$safePermit( + this.token.address, + this.data.message.owner, + this.data.message.spender, + this.data.message.value, + this.data.message.deadline, + invalidSignature.v, + invalidSignature.r, + invalidSignature.s, + ), + 'SafeERC20: permit did not succeed', + ); + }); + }); + + 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([receiver, spender], reason) { + it('reverts on transfer', async function () { + 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, receiver, 0), reason); + }); + + it('reverts on approve', async function () { + 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, 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, spender, 0)); + }); + + it('reverts on forceApprove', async function () { + await expectRevert(this.mock.$forceApprove(this.token.address, spender, 0), reason); + }); +} + +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 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.$_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, 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, 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, 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, spender, 10), + 'SafeERC20: decreased allowance below zero', + ); + }); + }); + + context('with non-zero allowance', function () { + beforeEach(async function () { + 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, 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, 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, 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, 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, spender, 200), + 'SafeERC20: decreased allowance below zero', + ); + }); + }); + }); +} diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/utils/TokenTimelock.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/utils/TokenTimelock.test.js new file mode 100644 index 0000000..22e8071 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC20/utils/TokenTimelock.test.js @@ -0,0 +1,71 @@ +const { BN, expectRevert, time } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC20 = artifacts.require('$ERC20'); +const TokenTimelock = artifacts.require('TokenTimelock'); + +contract('TokenTimelock', function (accounts) { + const [beneficiary] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const amount = new BN(100); + + context('with token', function () { + beforeEach(async function () { + this.token = await ERC20.new(name, symbol); + }); + + it('rejects a release time in the past', async function () { + const pastReleaseTime = (await time.latest()).sub(time.duration.years(1)); + await expectRevert( + TokenTimelock.new(this.token.address, beneficiary, pastReleaseTime), + 'TokenTimelock: release time is before current time', + ); + }); + + context('once deployed', function () { + beforeEach(async function () { + this.releaseTime = (await time.latest()).add(time.duration.years(1)); + this.timelock = await TokenTimelock.new(this.token.address, beneficiary, this.releaseTime); + await this.token.$_mint(this.timelock.address, amount); + }); + + it('can get state', async function () { + expect(await this.timelock.token()).to.equal(this.token.address); + expect(await this.timelock.beneficiary()).to.equal(beneficiary); + expect(await this.timelock.releaseTime()).to.be.bignumber.equal(this.releaseTime); + }); + + it('cannot be released before time limit', async function () { + await expectRevert(this.timelock.release(), 'TokenTimelock: current time is before release time'); + }); + + it('cannot be released just before time limit', async function () { + await time.increaseTo(this.releaseTime.sub(time.duration.seconds(3))); + await expectRevert(this.timelock.release(), 'TokenTimelock: current time is before release time'); + }); + + it('can be released just after limit', async function () { + await time.increaseTo(this.releaseTime.add(time.duration.seconds(1))); + await this.timelock.release(); + expect(await this.token.balanceOf(beneficiary)).to.be.bignumber.equal(amount); + }); + + it('can be released after time limit', async function () { + await time.increaseTo(this.releaseTime.add(time.duration.years(1))); + await this.timelock.release(); + expect(await this.token.balanceOf(beneficiary)).to.be.bignumber.equal(amount); + }); + + it('cannot be released twice', async function () { + await time.increaseTo(this.releaseTime.add(time.duration.years(1))); + await this.timelock.release(); + await expectRevert(this.timelock.release(), 'TokenTimelock: no tokens to release'); + expect(await this.token.balanceOf(beneficiary)).to.be.bignumber.equal(amount); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721.behavior.js new file mode 100644 index 0000000..6867db3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721.behavior.js @@ -0,0 +1,893 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +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), + {}, +); + +const firstTokenId = new BN('5042'); +const secondTokenId = new BN('79217'); +const nonExistentTokenId = new BN('13'); +const fourthTokenId = new BN(4); +const baseURI = 'https://api.example.com/v1/'; + +const RECEIVER_MAGIC_VALUE = '0x150b7a02'; + +function shouldBehaveLikeERC721(errorPrefix, owner, newOwner, approved, anotherApproved, operator, other) { + shouldSupportInterfaces(['ERC165', 'ERC721']); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + this.toWhom = other; // default to other for toWhom in context-dependent tests + }); + + describe('balanceOf', function () { + context('when the given address owns some tokens', function () { + it('returns the amount of tokens owned by the given address', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('2'); + }); + }); + + context('when the given address does not own any tokens', function () { + it('returns 0', async function () { + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('0'); + }); + }); + + context('when querying the zero address', function () { + it('throws', async function () { + await expectRevert(this.token.balanceOf(ZERO_ADDRESS), 'ERC721: address zero is not a valid owner'); + }); + }); + }); + + describe('ownerOf', function () { + context('when the given token ID was tracked by this token', function () { + const tokenId = firstTokenId; + + it('returns the owner of the given token ID', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owner); + }); + }); + + context('when the given token ID was not tracked by this token', function () { + const tokenId = nonExistentTokenId; + + it('reverts', async function () { + await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID'); + }); + }); + }); + + describe('transfers', function () { + const tokenId = firstTokenId; + const data = '0x42'; + + let receipt = null; + + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + await this.token.setApprovalForAll(operator, true, { from: owner }); + }); + + const transferWasSuccessful = function ({ owner, tokenId }) { + it('transfers the ownership of the given token ID to the given address', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(this.toWhom); + }); + + it('emits a Transfer event', async function () { + expectEvent(receipt, 'Transfer', { from: owner, to: this.toWhom, tokenId: tokenId }); + }); + + it('clears the approval for the token ID', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + + it('adjusts owners balances', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('adjusts owners tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + + expect(await this.token.tokenOfOwnerByIndex(this.toWhom, 0)).to.be.bignumber.equal(tokenId); + + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.not.equal(tokenId); + }); + }; + + const shouldTransferTokensByUsers = function (transferFunction) { + context('when called by the owner', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: owner }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the approved individual', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: approved }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the operator', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: operator }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the owner without an approved user', function () { + beforeEach(async function () { + await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: operator }); + }); + transferWasSuccessful({ owner, tokenId, approved: null }); + }); + + context('when sent to the owner', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, owner, tokenId, { from: owner }); + }); + + it('keeps ownership of the token', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owner); + }); + + it('clears the approval for the token ID', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + + it('emits only a transfer event', async function () { + expectEvent(receipt, 'Transfer', { + from: owner, + to: owner, + tokenId: tokenId, + }); + }); + + it('keeps the owner balance', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('2'); + }); + + it('keeps same tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenOfOwnerByIndex(owner, i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + }); + + context('when the address of the previous owner is incorrect', function () { + it('reverts', async function () { + await expectRevert( + transferFunction.call(this, other, other, tokenId, { from: owner }), + 'ERC721: transfer from incorrect owner', + ); + }); + }); + + context('when the sender is not authorized for the token id', function () { + it('reverts', async function () { + await expectRevert( + transferFunction.call(this, owner, other, tokenId, { from: other }), + 'ERC721: caller is not token owner or approved', + ); + }); + }); + + context('when the given token ID does not exist', function () { + it('reverts', async function () { + await expectRevert( + transferFunction.call(this, owner, other, nonExistentTokenId, { from: owner }), + 'ERC721: invalid token ID', + ); + }); + }); + + context('when the address to transfer the token to is the zero address', function () { + it('reverts', async function () { + await expectRevert( + transferFunction.call(this, owner, ZERO_ADDRESS, tokenId, { from: owner }), + 'ERC721: transfer to the zero address', + ); + }); + }); + }; + + describe('via transferFrom', function () { + shouldTransferTokensByUsers(function (from, to, tokenId, opts) { + return this.token.transferFrom(from, to, tokenId, opts); + }); + }); + + describe('via safeTransferFrom', function () { + const safeTransferFromWithData = function (from, to, tokenId, opts) { + return this.token.methods['safeTransferFrom(address,address,uint256,bytes)'](from, to, tokenId, data, opts); + }; + + const safeTransferFromWithoutData = function (from, to, tokenId, opts) { + return this.token.methods['safeTransferFrom(address,address,uint256)'](from, to, tokenId, opts); + }; + + const shouldTransferSafely = function (transferFun, data) { + describe('to a user account', function () { + shouldTransferTokensByUsers(transferFun); + }); + + describe('to a valid receiver contract', function () { + beforeEach(async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None); + this.toWhom = this.receiver.address; + }); + + shouldTransferTokensByUsers(transferFun); + + it('calls onERC721Received', async function () { + const receipt = await transferFun.call(this, owner, this.receiver.address, tokenId, { from: owner }); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + operator: owner, + from: owner, + tokenId: tokenId, + data: data, + }); + }); + + it('calls onERC721Received from approved', async function () { + const receipt = await transferFun.call(this, owner, this.receiver.address, tokenId, { from: approved }); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + operator: approved, + from: owner, + tokenId: tokenId, + data: data, + }); + }); + + describe('with an invalid token id', function () { + it('reverts', async function () { + await expectRevert( + transferFun.call(this, owner, this.receiver.address, nonExistentTokenId, { from: owner }), + 'ERC721: invalid token ID', + ); + }); + }); + }); + }; + + describe('with data', function () { + shouldTransferSafely(safeTransferFromWithData, data); + }); + + describe('without data', function () { + shouldTransferSafely(safeTransferFromWithoutData, null); + }); + + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ERC721ReceiverMock.new('0x42', Error.None); + await expectRevert( + this.token.safeTransferFrom(owner, invalidReceiver.address, tokenId, { from: owner }), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + + describe('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithMessage); + await expectRevert( + this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }), + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + describe('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithoutMessage); + await expectRevert( + this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + + describe('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.Panic); + await expectRevert.unspecified( + this.token.safeTransferFrom(owner, revertingReceiver.address, tokenId, { from: owner }), + ); + }); + }); + + describe('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await NonERC721ReceiverMock.new(); + await expectRevert( + this.token.safeTransferFrom(owner, nonReceiver.address, tokenId, { from: owner }), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + }); + }); + + describe('safe mint', function () { + const tokenId = fourthTokenId; + const data = '0x42'; + + describe('via safeMint', function () { + // regular minting is tested in ERC721Mintable.test.js and others + it('calls onERC721Received — with data', async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None); + const receipt = await this.token.$_safeMint(this.receiver.address, tokenId, data); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + from: ZERO_ADDRESS, + tokenId: tokenId, + data: data, + }); + }); + + it('calls onERC721Received — without data', async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.None); + const receipt = await this.token.$_safeMint(this.receiver.address, tokenId); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + from: ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + + context('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ERC721ReceiverMock.new('0x42', Error.None); + await expectRevert( + this.token.$_safeMint(invalidReceiver.address, tokenId), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + + context('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithMessage); + await expectRevert( + this.token.$_safeMint(revertingReceiver.address, tokenId), + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + context('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.RevertWithoutMessage); + await expectRevert( + this.token.$_safeMint(revertingReceiver.address, tokenId), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + + context('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, Error.Panic); + await expectRevert.unspecified(this.token.$_safeMint(revertingReceiver.address, tokenId)); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await NonERC721ReceiverMock.new(); + await expectRevert( + this.token.$_safeMint(nonReceiver.address, tokenId), + 'ERC721: transfer to non ERC721Receiver implementer', + ); + }); + }); + }); + }); + + describe('approve', function () { + const tokenId = firstTokenId; + + let receipt = null; + + const itClearsApproval = function () { + it('clears approval for the token', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + }; + + const itApproves = function (address) { + it('sets the approval for the target address', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(address); + }); + }; + + const itEmitsApprovalEvent = function (address) { + it('emits an approval event', async function () { + expectEvent(receipt, 'Approval', { + owner: owner, + approved: address, + tokenId: tokenId, + }); + }); + }; + + context('when clearing approval', function () { + context('when there was no prior approval', function () { + beforeEach(async function () { + receipt = await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + }); + + itClearsApproval(); + itEmitsApprovalEvent(ZERO_ADDRESS); + }); + + context('when there was a prior approval', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + }); + + itClearsApproval(); + itEmitsApprovalEvent(ZERO_ADDRESS); + }); + }); + + context('when approving a non-zero address', function () { + context('when there was no prior approval', function () { + beforeEach(async function () { + receipt = await this.token.approve(approved, tokenId, { from: owner }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when there was a prior approval to the same address', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.approve(approved, tokenId, { from: owner }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when there was a prior approval to a different address', function () { + beforeEach(async function () { + await this.token.approve(anotherApproved, tokenId, { from: owner }); + receipt = await this.token.approve(anotherApproved, tokenId, { from: owner }); + }); + + itApproves(anotherApproved); + itEmitsApprovalEvent(anotherApproved); + }); + }); + + context('when the address that receives the approval is the owner', function () { + it('reverts', async function () { + await expectRevert(this.token.approve(owner, tokenId, { from: owner }), 'ERC721: approval to current owner'); + }); + }); + + context('when the sender does not own the given token ID', function () { + it('reverts', async function () { + await expectRevert( + this.token.approve(approved, tokenId, { from: other }), + 'ERC721: approve caller is not token owner or approved', + ); + }); + }); + + context('when the sender is approved for the given token ID', function () { + it('reverts', async function () { + await this.token.approve(approved, tokenId, { from: owner }); + await expectRevert( + this.token.approve(anotherApproved, tokenId, { from: approved }), + 'ERC721: approve caller is not token owner or approved for all', + ); + }); + }); + + context('when the sender is an operator', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + receipt = await this.token.approve(approved, tokenId, { from: operator }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when the given token ID does not exist', function () { + it('reverts', async function () { + await expectRevert( + this.token.approve(approved, nonExistentTokenId, { from: operator }), + 'ERC721: invalid token ID', + ); + }); + }); + }); + + describe('setApprovalForAll', function () { + context('when the operator willing to approve is not the owner', function () { + context('when there is no operator approval set by the sender', function () { + it('approves the operator', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + }); + + context('when the operator was set as not approved', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, false, { from: owner }); + }); + + it('approves the operator', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + + it('can unset the operator approval', async function () { + await this.token.setApprovalForAll(operator, false, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); + + context('when the operator was already approved', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + }); + + it('keeps the approval to the given address', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + }); + }); + + context('when the operator is the owner', function () { + it('reverts', async function () { + await expectRevert(this.token.setApprovalForAll(owner, true, { from: owner }), 'ERC721: approve to caller'); + }); + }); + }); + + describe('getApproved', async function () { + context('when token is not minted', async function () { + it('reverts', async function () { + await expectRevert(this.token.getApproved(nonExistentTokenId), 'ERC721: invalid token ID'); + }); + }); + + context('when token has been minted ', async function () { + it('should return the zero address', async function () { + expect(await this.token.getApproved(firstTokenId)).to.be.equal(ZERO_ADDRESS); + }); + + context('when account has been approved', async function () { + beforeEach(async function () { + await this.token.approve(approved, firstTokenId, { from: owner }); + }); + + it('returns approved account', async function () { + expect(await this.token.getApproved(firstTokenId)).to.be.equal(approved); + }); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expectRevert(this.token.$_mint(ZERO_ADDRESS, firstTokenId), 'ERC721: mint to the zero address'); + }); + + context('with minted token', async function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(owner, firstTokenId); + }); + + it('emits a Transfer event', function () { + expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: owner, tokenId: firstTokenId }); + }); + + it('creates the token', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + expect(await this.token.ownerOf(firstTokenId)).to.equal(owner); + }); + + it('reverts when adding a token id that already exists', async function () { + await expectRevert(this.token.$_mint(owner, firstTokenId), 'ERC721: token already minted'); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expectRevert(this.token.$_burn(nonExistentTokenId), 'ERC721: invalid token ID'); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + context('with burnt token', function () { + beforeEach(async function () { + this.receipt = await this.token.$_burn(firstTokenId); + }); + + it('emits a Transfer event', function () { + expectEvent(this.receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, tokenId: firstTokenId }); + }); + + it('deletes the token', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + await expectRevert(this.token.ownerOf(firstTokenId), 'ERC721: invalid token ID'); + }); + + it('reverts when burning a token id that has been deleted', async function () { + await expectRevert(this.token.$_burn(firstTokenId), 'ERC721: invalid token ID'); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Enumerable(errorPrefix, owner, newOwner, approved, anotherApproved, operator, other) { + shouldSupportInterfaces(['ERC721Enumerable']); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + this.toWhom = other; // default to other for toWhom in context-dependent tests + }); + + describe('totalSupply', function () { + it('returns total token supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal('2'); + }); + }); + + describe('tokenOfOwnerByIndex', function () { + describe('when the given index is lower than the amount of tokens owned by the given address', function () { + it('returns the token ID placed at the given index', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(firstTokenId); + }); + }); + + describe('when the index is greater than or equal to the total tokens owned by the given address', function () { + it('reverts', async function () { + await expectRevert(this.token.tokenOfOwnerByIndex(owner, 2), 'ERC721Enumerable: owner index out of bounds'); + }); + }); + + describe('when the given address does not own any token', function () { + it('reverts', async function () { + await expectRevert(this.token.tokenOfOwnerByIndex(other, 0), 'ERC721Enumerable: owner index out of bounds'); + }); + }); + + describe('after transferring all tokens to another user', function () { + beforeEach(async function () { + await this.token.transferFrom(owner, other, firstTokenId, { from: owner }); + await this.token.transferFrom(owner, other, secondTokenId, { from: owner }); + }); + + it('returns correct token IDs for target', async function () { + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('2'); + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenOfOwnerByIndex(other, i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + + it('returns empty collection for original owner', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('0'); + await expectRevert(this.token.tokenOfOwnerByIndex(owner, 0), 'ERC721Enumerable: owner index out of bounds'); + }); + }); + }); + + describe('tokenByIndex', function () { + it('returns all tokens', async function () { + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenByIndex(i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + + it('reverts if index is greater than supply', async function () { + await expectRevert(this.token.tokenByIndex(2), 'ERC721Enumerable: global index out of bounds'); + }); + + [firstTokenId, secondTokenId].forEach(function (tokenId) { + it(`returns all tokens after burning token ${tokenId} and minting new tokens`, async function () { + const newTokenId = new BN(300); + const anotherNewTokenId = new BN(400); + + await this.token.$_burn(tokenId); + await this.token.$_mint(newOwner, newTokenId); + await this.token.$_mint(newOwner, anotherNewTokenId); + + expect(await this.token.totalSupply()).to.be.bignumber.equal('3'); + + const tokensListed = await Promise.all([0, 1, 2].map(i => this.token.tokenByIndex(i))); + const expectedTokens = [firstTokenId, secondTokenId, newTokenId, anotherNewTokenId].filter( + x => x !== tokenId, + ); + expect(tokensListed.map(t => t.toNumber())).to.have.members(expectedTokens.map(t => t.toNumber())); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expectRevert(this.token.$_mint(ZERO_ADDRESS, firstTokenId), 'ERC721: mint to the zero address'); + }); + + context('with minted token', async function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(owner, firstTokenId); + }); + + it('adjusts owner tokens by index', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(firstTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0)).to.be.bignumber.equal(firstTokenId); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expectRevert(this.token.$_burn(firstTokenId), 'ERC721: invalid token ID'); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + context('with burnt token', function () { + beforeEach(async function () { + this.receipt = await this.token.$_burn(firstTokenId); + }); + + it('removes that token from the token list of the owner', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(secondTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0)).to.be.bignumber.equal(secondTokenId); + }); + + it('burns all tokens', async function () { + await this.token.$_burn(secondTokenId, { from: owner }); + expect(await this.token.totalSupply()).to.be.bignumber.equal('0'); + await expectRevert(this.token.tokenByIndex(0), 'ERC721Enumerable: global index out of bounds'); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Metadata(errorPrefix, name, symbol, owner) { + shouldSupportInterfaces(['ERC721Metadata']); + + describe('metadata', function () { + it('has a name', async function () { + expect(await this.token.name()).to.be.equal(name); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.be.equal(symbol); + }); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + }); + + it('return empty string by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expectRevert(this.token.tokenURI(nonExistentTokenId), 'ERC721: invalid token ID'); + }); + + describe('base URI', function () { + beforeEach(function () { + if (this.token.setBaseURI === undefined) { + this.skip(); + } + }); + + it('base URI can be set', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.baseURI()).to.equal(baseURI); + }); + + it('base URI is added as a prefix to the token URI', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + firstTokenId.toString()); + }); + + it('token URI can be changed by changing the base URI', async function () { + await this.token.setBaseURI(baseURI); + const newBaseURI = 'https://api.example.com/v2/'; + await this.token.setBaseURI(newBaseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + firstTokenId.toString()); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Enumerable, + shouldBehaveLikeERC721Metadata, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721.test.js new file mode 100644 index 0000000..312430c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721.test.js @@ -0,0 +1,15 @@ +const { shouldBehaveLikeERC721, shouldBehaveLikeERC721Metadata } = require('./ERC721.behavior'); + +const ERC721 = artifacts.require('$ERC721'); + +contract('ERC721', function (accounts) { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721.new(name, symbol); + }); + + shouldBehaveLikeERC721('ERC721', ...accounts); + shouldBehaveLikeERC721Metadata('ERC721', name, symbol, ...accounts); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721Enumerable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721Enumerable.test.js new file mode 100644 index 0000000..b32f22d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/ERC721Enumerable.test.js @@ -0,0 +1,20 @@ +const { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Metadata, + shouldBehaveLikeERC721Enumerable, +} = require('./ERC721.behavior'); + +const ERC721Enumerable = artifacts.require('$ERC721Enumerable'); + +contract('ERC721Enumerable', function (accounts) { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Enumerable.new(name, symbol); + }); + + shouldBehaveLikeERC721('ERC721', ...accounts); + shouldBehaveLikeERC721Metadata('ERC721', name, symbol, ...accounts); + shouldBehaveLikeERC721Enumerable('ERC721', ...accounts); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Burnable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Burnable.test.js new file mode 100644 index 0000000..6a4bc6d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Burnable.test.js @@ -0,0 +1,70 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC721Burnable = artifacts.require('$ERC721Burnable'); + +contract('ERC721Burnable', function (accounts) { + const [owner, approved] = accounts; + + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Burnable.new(name, symbol); + }); + + describe('like a burnable ERC721', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + describe('burn', function () { + const tokenId = firstTokenId; + let receipt = null; + + describe('when successful', function () { + beforeEach(async function () { + receipt = await this.token.burn(tokenId, { from: owner }); + }); + + it('burns the given token ID and adjusts the balance of the owner', async function () { + await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID'); + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('emits a burn event', async function () { + expectEvent(receipt, 'Transfer', { + from: owner, + to: constants.ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + }); + + describe('when there is a previous approval burned', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.burn(tokenId, { from: owner }); + }); + + context('getApproved', function () { + it('reverts', async function () { + await expectRevert(this.token.getApproved(tokenId), 'ERC721: invalid token ID'); + }); + }); + }); + + describe('when the given token ID was not tracked by this contract', function () { + it('reverts', async function () { + await expectRevert(this.token.burn(unknownTokenId, { from: owner }), 'ERC721: invalid token ID'); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Consecutive.t.sol b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Consecutive.t.sol new file mode 100644 index 0000000..3cc8689 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Consecutive.t.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +// solhint-disable func-name-mixedcase + +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/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Consecutive.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Consecutive.test.js new file mode 100644 index 0000000..a92aef4 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Consecutive.test.js @@ -0,0 +1,206 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC721ConsecutiveMock = artifacts.require('$ERC721ConsecutiveMock'); +const ERC721ConsecutiveEnumerableMock = artifacts.require('$ERC721ConsecutiveEnumerableMock'); +const ERC721ConsecutiveNoConstructorMintMock = artifacts.require('$ERC721ConsecutiveNoConstructorMintMock'); + +contract('ERC721Consecutive', function (accounts) { + const [user1, user2, user3, receiver] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const batches = [ + { receiver: user1, amount: 0 }, + { receiver: user1, amount: 1 }, + { receiver: user1, amount: 2 }, + { receiver: user2, amount: 5 }, + { receiver: user3, amount: 0 }, + { receiver: user1, amount: 7 }, + ]; + const delegates = [user1, user3]; + + describe('with valid batches', function () { + beforeEach(async function () { + this.token = await ERC721ConsecutiveMock.new( + name, + symbol, + delegates, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ); + }); + + describe('minting during construction', function () { + it('events are emitted at construction', async function () { + let first = 0; + + for (const batch of batches) { + if (batch.amount > 0) { + await expectEvent.inConstruction(this.token, 'ConsecutiveTransfer', { + fromTokenId: web3.utils.toBN(first), + toTokenId: web3.utils.toBN(first + batch.amount - 1), + fromAddress: constants.ZERO_ADDRESS, + toAddress: batch.receiver, + }); + } else { + // expectEvent.notEmitted.inConstruction only looks at event name, and doesn't check the parameters + } + first += batch.amount; + } + }); + + it('ownership is set', async function () { + const owners = batches.flatMap(({ receiver, amount }) => Array(amount).fill(receiver)); + + for (const tokenId in owners) { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owners[tokenId]); + } + }); + + it('balance & voting power are set', async function () { + for (const account of accounts) { + const balance = batches + .filter(({ receiver }) => receiver === account) + .map(({ amount }) => amount) + .reduce((a, b) => a + b, 0); + + expect(await this.token.balanceOf(account)).to.be.bignumber.equal(web3.utils.toBN(balance)); + + // If not delegated at construction, check before + do delegation + if (!delegates.includes(account)) { + expect(await this.token.getVotes(account)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await this.token.delegate(account, { from: account }); + } + + // At this point all accounts should have delegated + expect(await this.token.getVotes(account)).to.be.bignumber.equal(web3.utils.toBN(balance)); + } + }); + }); + + describe('minting after construction', function () { + it('consecutive minting is not possible after construction', async function () { + await expectRevert( + this.token.$_mintConsecutive(user1, 10), + 'ERC721Consecutive: batch minting restricted to constructor', + ); + }); + + it('simple minting is possible after construction', async function () { + const tokenId = batches.reduce((acc, { amount }) => acc + amount, 0); + + expect(await this.token.$_exists(tokenId)).to.be.equal(false); + + expectEvent(await this.token.$_mint(user1, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + tokenId: tokenId.toString(), + }); + }); + + it('cannot mint a token that has been batched minted', async function () { + const tokenId = batches.reduce((acc, { amount }) => acc + amount, 0) - 1; + + expect(await this.token.$_exists(tokenId)).to.be.equal(true); + + await expectRevert(this.token.$_mint(user1, tokenId), 'ERC721: token already minted'); + }); + }); + + describe('ERC721 behavior', function () { + it('core takes over ownership on transfer', async function () { + await this.token.transferFrom(user1, receiver, 1, { from: user1 }); + + expect(await this.token.ownerOf(1)).to.be.equal(receiver); + }); + + it('tokens can be burned and re-minted #1', async function () { + expectEvent(await this.token.$_burn(1, { from: user1 }), 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + tokenId: '1', + }); + + await expectRevert(this.token.ownerOf(1), 'ERC721: invalid token ID'); + + expectEvent(await this.token.$_mint(user2, 1), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + tokenId: '1', + }); + + expect(await this.token.ownerOf(1)).to.be.equal(user2); + }); + + it('tokens can be burned and re-minted #2', async function () { + const tokenId = batches.reduce((acc, { amount }) => acc.addn(amount), web3.utils.toBN(0)); + + expect(await this.token.$_exists(tokenId)).to.be.equal(false); + await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID'); + + // mint + await this.token.$_mint(user1, tokenId); + + expect(await this.token.$_exists(tokenId)).to.be.equal(true); + expect(await this.token.ownerOf(tokenId), user1); + + // burn + expectEvent(await this.token.$_burn(tokenId, { from: user1 }), 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + tokenId, + }); + + expect(await this.token.$_exists(tokenId)).to.be.equal(false); + await expectRevert(this.token.ownerOf(tokenId), 'ERC721: invalid token ID'); + + // re-mint + expectEvent(await this.token.$_mint(user2, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + tokenId, + }); + + expect(await this.token.$_exists(tokenId)).to.be.equal(true); + expect(await this.token.ownerOf(tokenId), user2); + }); + }); + }); + + describe('invalid use', function () { + it('cannot mint a batch larger than 5000', async function () { + await expectRevert( + ERC721ConsecutiveMock.new(name, symbol, [], [user1], ['5001']), + 'ERC721Consecutive: batch too large', + ); + }); + + it('cannot use single minting during construction', async function () { + await expectRevert( + ERC721ConsecutiveNoConstructorMintMock.new(name, symbol), + "ERC721Consecutive: can't mint during construction", + ); + }); + + it('cannot use single minting during construction', async function () { + await expectRevert( + ERC721ConsecutiveNoConstructorMintMock.new(name, symbol), + "ERC721Consecutive: can't mint during construction", + ); + }); + + it('consecutive mint not compatible with enumerability', async function () { + await expectRevert( + ERC721ConsecutiveEnumerableMock.new( + name, + symbol, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ), + 'ERC721Enumerable: consecutive transfers not supported', + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Pausable.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Pausable.test.js new file mode 100644 index 0000000..c7fc823 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Pausable.test.js @@ -0,0 +1,92 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC721Pausable = artifacts.require('$ERC721Pausable'); + +contract('ERC721Pausable', function (accounts) { + const [owner, receiver, operator] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Pausable.new(name, symbol); + }); + + context('when token is paused', function () { + const firstTokenId = new BN(1); + const secondTokenId = new BN(1337); + + const mockData = '0x42'; + + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId, { from: owner }); + await this.token.$_pause(); + }); + + it('reverts when trying to transferFrom', async function () { + await expectRevert( + this.token.transferFrom(owner, receiver, firstTokenId, { from: owner }), + 'ERC721Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeTransferFrom', async function () { + await expectRevert( + this.token.safeTransferFrom(owner, receiver, firstTokenId, { from: owner }), + 'ERC721Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to safeTransferFrom with data', async function () { + await expectRevert( + this.token.methods['safeTransferFrom(address,address,uint256,bytes)'](owner, receiver, firstTokenId, mockData, { + from: owner, + }), + 'ERC721Pausable: token transfer while paused', + ); + }); + + it('reverts when trying to mint', async function () { + await expectRevert(this.token.$_mint(receiver, secondTokenId), 'ERC721Pausable: token transfer while paused'); + }); + + it('reverts when trying to burn', async function () { + await expectRevert(this.token.$_burn(firstTokenId), 'ERC721Pausable: token transfer while paused'); + }); + + describe('getApproved', function () { + it('returns approved address', async function () { + const approvedAccount = await this.token.getApproved(firstTokenId); + expect(approvedAccount).to.equal(constants.ZERO_ADDRESS); + }); + }); + + describe('balanceOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const balance = await this.token.balanceOf(owner); + expect(balance).to.be.bignumber.equal('1'); + }); + }); + + describe('ownerOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const ownerOfToken = await this.token.ownerOf(firstTokenId); + expect(ownerOfToken).to.equal(owner); + }); + }); + + describe('exists', function () { + it('returns token existence', async function () { + expect(await this.token.$_exists(firstTokenId)).to.equal(true); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Royalty.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Royalty.test.js new file mode 100644 index 0000000..1c0536b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Royalty.test.js @@ -0,0 +1,41 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); + +const { shouldBehaveLikeERC2981 } = require('../../common/ERC2981.behavior'); + +const ERC721Royalty = artifacts.require('$ERC721Royalty'); + +contract('ERC721Royalty', function (accounts) { + const [account1, account2] = accounts; + const tokenId1 = new BN('1'); + const tokenId2 = new BN('2'); + const royalty = new BN('200'); + const salePrice = new BN('1000'); + + beforeEach(async function () { + this.token = await ERC721Royalty.new('My Token', 'TKN'); + + await this.token.$_mint(account1, tokenId1); + await this.token.$_mint(account1, tokenId2); + this.account1 = account1; + this.account2 = account2; + this.tokenId1 = tokenId1; + this.tokenId2 = tokenId2; + this.salePrice = salePrice; + }); + + describe('token specific functions', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(tokenId1, account1, royalty); + }); + + it('removes royalty information after burn', async function () { + await this.token.$_burn(tokenId1); + const tokenInfo = await this.token.royaltyInfo(tokenId1, salePrice); + + expect(tokenInfo[0]).to.be.equal(constants.ZERO_ADDRESS); + expect(tokenInfo[1]).to.be.bignumber.equal(new BN('0')); + }); + }); + + shouldBehaveLikeERC2981(); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721URIStorage.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721URIStorage.test.js new file mode 100644 index 0000000..60c8006 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721URIStorage.test.js @@ -0,0 +1,100 @@ +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) { + const [owner] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + const firstTokenId = new BN('5042'); + const nonExistentTokenId = new BN('13'); + + beforeEach(async function () { + this.token = await ERC721URIStorageMock.new(name, symbol); + }); + + shouldSupportInterfaces(['0x49064906']); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + }); + + const baseURI = 'https://api.example.com/v1/'; + const sampleUri = 'mock://mytoken'; + + it('it is empty by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expectRevert(this.token.tokenURI(nonExistentTokenId), 'ERC721: invalid token ID'); + }); + + it('can be set for a token id', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + 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), + 'ERC721URIStorage: URI set of nonexistent token', + ); + }); + + it('base URI can be set', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.$_baseURI()).to.equal(baseURI); + }); + + it('base URI is added as a prefix to the token URI', async function () { + await this.token.setBaseURI(baseURI); + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + sampleUri); + }); + + it('token URI can be changed by changing the base URI', async function () { + await this.token.setBaseURI(baseURI); + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + const newBaseURI = 'https://api.example.com/v2/'; + await this.token.setBaseURI(newBaseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + sampleUri); + }); + + it('tokenId is appended to base URI for tokens with no URI', async function () { + await this.token.setBaseURI(baseURI); + + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + firstTokenId); + }); + + it('tokens without URI can be burnt ', async function () { + await this.token.$_burn(firstTokenId, { from: owner }); + + expect(await this.token.$_exists(firstTokenId)).to.equal(false); + await expectRevert(this.token.tokenURI(firstTokenId), 'ERC721: invalid token ID'); + }); + + it('tokens with URI can be burnt ', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + await this.token.$_burn(firstTokenId, { from: owner }); + + expect(await this.token.$_exists(firstTokenId)).to.equal(false); + await expectRevert(this.token.tokenURI(firstTokenId), 'ERC721: invalid token ID'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Votes.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Votes.test.js new file mode 100644 index 0000000..92032db --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Votes.test.js @@ -0,0 +1,184 @@ +/* eslint-disable */ + +const { BN, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { getChainId } = require('../../../helpers/chainid'); + +const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); + +const ERC721Votes = artifacts.require('$ERC721Votes'); + +contract('ERC721Votes', function (accounts) { + const [account1, account2, account1Delegatee, other1, other2] = accounts; + + const name = 'My Vote'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.chainId = await getChainId(); + + this.votes = await ERC721Votes.new(name, symbol, name, '1'); + + this.NFT0 = new BN('10000000000000000000000000'); + this.NFT1 = new BN('10'); + this.NFT2 = new BN('20'); + this.NFT3 = new BN('30'); + }); + + describe('balanceOf', function () { + beforeEach(async function () { + await this.votes.$_mint(account1, this.NFT0); + await this.votes.$_mint(account1, this.NFT1); + await this.votes.$_mint(account1, this.NFT2); + await this.votes.$_mint(account1, this.NFT3); + }); + + it('grants to initial account', async function () { + expect(await this.votes.balanceOf(account1)).to.be.bignumber.equal('4'); + }); + }); + + describe('transfers', function () { + beforeEach(async function () { + await this.votes.$_mint(account1, this.NFT0); + }); + + it('no delegation', async function () { + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.NFT0 }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('sender delegation', async function () { + await this.votes.delegate(account1, { from: account1 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.NFT0 }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0' }); + + 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.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('receiver delegation', async function () { + await this.votes.delegate(account2, { from: account2 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.NFT0 }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, 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.account1Votes = '0'; + this.account2Votes = '1'; + }); + + it('full delegation', async function () { + await this.votes.delegate(account1, { from: account1 }); + await this.votes.delegate(account2, { from: account2 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: this.NFT0 }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousBalance: '1', newBalance: '0' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, 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.account1Votes = '0'; + this.account2Votes = '1'; + }); + + it('returns the same total supply on transfers', async function () { + await this.votes.delegate(account1, { from: account1 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, this.NFT0, { from: account1 }); + + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.votes.getPastTotalSupply(receipt.blockNumber - 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(receipt.blockNumber + 1)).to.be.bignumber.equal('1'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + await this.votes.$_mint(account1, this.NFT1); + await this.votes.$_mint(account1, this.NFT2); + await this.votes.$_mint(account1, this.NFT3); + + const total = await this.votes.balanceOf(account1); + + const t1 = await this.votes.delegate(other1, { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.votes.transferFrom(account1, other2, this.NFT0, { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.votes.transferFrom(account1, other2, this.NFT2, { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.votes.transferFrom(other2, account1, this.NFT2, { from: other2 }); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber)).to.be.bignumber.equal(total); + expect(await this.votes.getPastVotes(other1, t1.receipt.blockNumber + 1)).to.be.bignumber.equal(total); + expect(await this.votes.getPastVotes(other1, t2.receipt.blockNumber)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t2.receipt.blockNumber + 1)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t3.receipt.blockNumber)).to.be.bignumber.equal('2'); + expect(await this.votes.getPastVotes(other1, t3.receipt.blockNumber + 1)).to.be.bignumber.equal('2'); + expect(await this.votes.getPastVotes(other1, t4.receipt.blockNumber)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t4.receipt.blockNumber + 1)).to.be.bignumber.equal('3'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + afterEach(async function () { + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(this.account1Votes); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(this.account2Votes); + + // 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.votes.getPastVotes(account1, blockNumber)).to.be.bignumber.equal(this.account1Votes); + expect(await this.votes.getPastVotes(account2, blockNumber)).to.be.bignumber.equal(this.account2Votes); + }); + }); + + describe('Voting workflow', function () { + beforeEach(async function () { + this.account1 = account1; + this.account1Delegatee = account1Delegatee; + this.account2 = account2; + this.name = 'My Vote'; + }); + + // includes EIP6372 behavior check + shouldBehaveLikeVotes(); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Wrapper.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Wrapper.test.js new file mode 100644 index 0000000..6e46d2e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -0,0 +1,283 @@ +const { BN, expectEvent, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +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.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 () { + 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 () { + it('only allows calls from underlying', async function () { + await expectRevert( + this.token.onERC721Received( + initialHolder, + this.token.address, + firstTokenId, + anotherAccount, // Correct data + { from: anotherAccount }, + ), + 'ERC721Wrapper: caller is not underlying', + ); + }); + + it('mints a token to from', 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); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js new file mode 100644 index 0000000..0af614b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/presets/ERC721PresetMinterPauserAutoId.test.js @@ -0,0 +1,122 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +const { expect } = require('chai'); + +const ERC721PresetMinterPauserAutoId = artifacts.require('ERC721PresetMinterPauserAutoId'); + +contract('ERC721PresetMinterPauserAutoId', function (accounts) { + const [deployer, other] = accounts; + + const name = 'MinterAutoIDToken'; + const symbol = 'MAIT'; + const baseURI = 'my.app/'; + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const MINTER_ROLE = web3.utils.soliditySha3('MINTER_ROLE'); + + beforeEach(async function () { + this.token = await ERC721PresetMinterPauserAutoId.new(name, symbol, baseURI, { from: deployer }); + }); + + shouldSupportInterfaces(['ERC721', 'ERC721Enumerable', 'AccessControl', 'AccessControlEnumerable']); + + it('token has correct name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('token has correct symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('deployer has the default admin role', async function () { + expect(await this.token.getRoleMemberCount(DEFAULT_ADMIN_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(DEFAULT_ADMIN_ROLE, 0)).to.equal(deployer); + }); + + it('deployer has the minter role', async function () { + expect(await this.token.getRoleMemberCount(MINTER_ROLE)).to.be.bignumber.equal('1'); + expect(await this.token.getRoleMember(MINTER_ROLE, 0)).to.equal(deployer); + }); + + it('minter role admin is the default admin', async function () { + expect(await this.token.getRoleAdmin(MINTER_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + describe('minting', function () { + it('deployer can mint tokens', async function () { + const tokenId = new BN('0'); + + const receipt = await this.token.mint(other, { from: deployer }); + expectEvent(receipt, 'Transfer', { from: ZERO_ADDRESS, to: other, tokenId }); + + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('1'); + expect(await this.token.ownerOf(tokenId)).to.equal(other); + + expect(await this.token.tokenURI(tokenId)).to.equal(baseURI + tokenId); + }); + + it('other accounts cannot mint tokens', async function () { + await expectRevert( + this.token.mint(other, { from: other }), + 'ERC721PresetMinterPauserAutoId: must have minter role to mint', + ); + }); + }); + + describe('pausing', function () { + it('deployer can pause', async function () { + const receipt = await this.token.pause({ from: deployer }); + expectEvent(receipt, 'Paused', { account: deployer }); + + expect(await this.token.paused()).to.equal(true); + }); + + it('deployer can unpause', async function () { + await this.token.pause({ from: deployer }); + + const receipt = await this.token.unpause({ from: deployer }); + expectEvent(receipt, 'Unpaused', { account: deployer }); + + expect(await this.token.paused()).to.equal(false); + }); + + it('cannot mint while paused', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert(this.token.mint(other, { from: deployer }), 'ERC721Pausable: token transfer while paused'); + }); + + it('other accounts cannot pause', async function () { + await expectRevert( + this.token.pause({ from: other }), + 'ERC721PresetMinterPauserAutoId: must have pauser role to pause', + ); + }); + + it('other accounts cannot unpause', async function () { + await this.token.pause({ from: deployer }); + + await expectRevert( + this.token.unpause({ from: other }), + 'ERC721PresetMinterPauserAutoId: must have pauser role to unpause', + ); + }); + }); + + describe('burning', function () { + it('holders can burn their tokens', async function () { + const tokenId = new BN('0'); + + await this.token.mint(other, { from: deployer }); + + const receipt = await this.token.burn(tokenId, { from: other }); + + expectEvent(receipt, 'Transfer', { from: other, to: ZERO_ADDRESS, tokenId }); + + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('0'); + expect(await this.token.totalSupply()).to.be.bignumber.equal('0'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/utils/ERC721Holder.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/utils/ERC721Holder.test.js new file mode 100644 index 0000000..0fd8222 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC721/utils/ERC721Holder.test.js @@ -0,0 +1,22 @@ +const { expect } = require('chai'); + +const ERC721Holder = artifacts.require('ERC721Holder'); +const ERC721 = artifacts.require('$ERC721'); + +contract('ERC721Holder', function (accounts) { + const [owner] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const tokenId = web3.utils.toBN(1); + + it('receives an ERC721 token', async function () { + const token = await ERC721.new(name, symbol); + await token.$_mint(owner, tokenId); + + const receiver = await ERC721Holder.new(); + await token.safeTransferFrom(owner, receiver.address, tokenId, { from: owner }); + + expect(await token.ownerOf(tokenId)).to.be.equal(receiver.address); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/ERC777.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/ERC777.behavior.js new file mode 100644 index 0000000..b1585bc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/ERC777.behavior.js @@ -0,0 +1,597 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const ERC777SenderRecipientMock = artifacts.require('ERC777SenderRecipientMock'); + +function shouldBehaveLikeERC777DirectSendBurn(holder, recipient, data) { + shouldBehaveLikeERC777DirectSend(holder, recipient, data); + shouldBehaveLikeERC777DirectBurn(holder, data); +} + +function shouldBehaveLikeERC777OperatorSendBurn(holder, recipient, operator, data, operatorData) { + shouldBehaveLikeERC777OperatorSend(holder, recipient, operator, data, operatorData); + shouldBehaveLikeERC777OperatorBurn(holder, operator, data, operatorData); +} + +function shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, recipient, operator, data, operatorData) { + shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, recipient, operator, data, operatorData); + shouldBehaveLikeERC777UnauthorizedOperatorBurn(holder, operator, data, operatorData); +} + +function shouldBehaveLikeERC777DirectSend(holder, recipient, data) { + describe('direct send', function () { + context('when the sender has tokens', function () { + shouldDirectSendTokens(holder, recipient, new BN('0'), data); + shouldDirectSendTokens(holder, recipient, new BN('1'), data); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(holder); + await expectRevert.unspecified(this.token.send(recipient, balance.addn(1), data, { from: holder })); + }); + + it('reverts when sending to the zero address', async function () { + await expectRevert.unspecified(this.token.send(ZERO_ADDRESS, new BN('1'), data, { from: holder })); + }); + }); + + context('when the sender has no tokens', function () { + removeBalance(holder); + + shouldDirectSendTokens(holder, recipient, new BN('0'), data); + + it('reverts when sending a non-zero amount', async function () { + await expectRevert.unspecified(this.token.send(recipient, new BN('1'), data, { from: holder })); + }); + }); + }); +} + +function shouldBehaveLikeERC777OperatorSend(holder, recipient, operator, data, operatorData) { + describe('operator send', function () { + context('when the sender has tokens', async function () { + shouldOperatorSendTokens(holder, operator, recipient, new BN('0'), data, operatorData); + shouldOperatorSendTokens(holder, operator, recipient, new BN('1'), data, operatorData); + + it('reverts when sending more than the balance', async function () { + const balance = await this.token.balanceOf(holder); + await expectRevert.unspecified( + this.token.operatorSend(holder, recipient, balance.addn(1), data, operatorData, { from: operator }), + ); + }); + + it('reverts when sending to the zero address', async function () { + await expectRevert.unspecified( + this.token.operatorSend(holder, ZERO_ADDRESS, new BN('1'), data, operatorData, { from: operator }), + ); + }); + }); + + context('when the sender has no tokens', function () { + removeBalance(holder); + + shouldOperatorSendTokens(holder, operator, recipient, new BN('0'), data, operatorData); + + it('reverts when sending a non-zero amount', async function () { + await expectRevert.unspecified( + this.token.operatorSend(holder, recipient, new BN('1'), data, operatorData, { from: operator }), + ); + }); + + it('reverts when sending from the zero address', async function () { + // This is not yet reflected in the spec + await expectRevert.unspecified( + this.token.operatorSend(ZERO_ADDRESS, recipient, new BN('0'), data, operatorData, { from: operator }), + ); + }); + }); + }); +} + +function shouldBehaveLikeERC777UnauthorizedOperatorSend(holder, recipient, operator, data, operatorData) { + describe('operator send', function () { + it('reverts', async function () { + await expectRevert.unspecified(this.token.operatorSend(holder, recipient, new BN('0'), data, operatorData)); + }); + }); +} + +function shouldBehaveLikeERC777DirectBurn(holder, data) { + describe('direct burn', function () { + context('when the sender has tokens', function () { + shouldDirectBurnTokens(holder, new BN('0'), data); + shouldDirectBurnTokens(holder, new BN('1'), data); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(holder); + await expectRevert.unspecified(this.token.burn(balance.addn(1), data, { from: holder })); + }); + }); + + context('when the sender has no tokens', function () { + removeBalance(holder); + + shouldDirectBurnTokens(holder, new BN('0'), data); + + it('reverts when burning a non-zero amount', async function () { + await expectRevert.unspecified(this.token.burn(new BN('1'), data, { from: holder })); + }); + }); + }); +} + +function shouldBehaveLikeERC777OperatorBurn(holder, operator, data, operatorData) { + describe('operator burn', function () { + context('when the sender has tokens', async function () { + shouldOperatorBurnTokens(holder, operator, new BN('0'), data, operatorData); + shouldOperatorBurnTokens(holder, operator, new BN('1'), data, operatorData); + + it('reverts when burning more than the balance', async function () { + const balance = await this.token.balanceOf(holder); + await expectRevert.unspecified( + this.token.operatorBurn(holder, balance.addn(1), data, operatorData, { from: operator }), + ); + }); + }); + + context('when the sender has no tokens', function () { + removeBalance(holder); + + shouldOperatorBurnTokens(holder, operator, new BN('0'), data, operatorData); + + it('reverts when burning a non-zero amount', async function () { + await expectRevert.unspecified( + this.token.operatorBurn(holder, new BN('1'), data, operatorData, { from: operator }), + ); + }); + + it('reverts when burning from the zero address', async function () { + // This is not yet reflected in the spec + await expectRevert.unspecified( + this.token.operatorBurn(ZERO_ADDRESS, new BN('0'), data, operatorData, { from: operator }), + ); + }); + }); + }); +} + +function shouldBehaveLikeERC777UnauthorizedOperatorBurn(holder, operator, data, operatorData) { + describe('operator burn', function () { + it('reverts', async function () { + await expectRevert.unspecified(this.token.operatorBurn(holder, new BN('0'), data, operatorData)); + }); + }); +} + +function shouldDirectSendTokens(from, to, amount, data) { + shouldSendTokens(from, null, to, amount, data, null); +} + +function shouldOperatorSendTokens(from, operator, to, amount, data, operatorData) { + shouldSendTokens(from, operator, to, amount, data, operatorData); +} + +function shouldSendTokens(from, operator, to, amount, data, operatorData) { + const operatorCall = operator !== null; + + it(`${operatorCall ? 'operator ' : ''}can send an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + const initialToBalance = await this.token.balanceOf(to); + + let receipt; + if (!operatorCall) { + receipt = await this.token.send(to, amount, data, { from }); + expectEvent(receipt, 'Sent', { + operator: from, + from, + to, + amount, + data, + operatorData: null, + }); + } else { + receipt = await this.token.operatorSend(from, to, amount, data, operatorData, { from: operator }); + expectEvent(receipt, 'Sent', { + operator, + from, + to, + amount, + data, + operatorData, + }); + } + + expectEvent(receipt, 'Transfer', { + from, + to, + value: amount, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + const finalToBalance = await this.token.balanceOf(to); + + expect(finalTotalSupply).to.be.bignumber.equal(initialTotalSupply); + expect(finalToBalance.sub(initialToBalance)).to.be.bignumber.equal(amount); + expect(finalFromBalance.sub(initialFromBalance)).to.be.bignumber.equal(amount.neg()); + }); +} + +function shouldDirectBurnTokens(from, amount, data) { + shouldBurnTokens(from, null, amount, data, null); +} + +function shouldOperatorBurnTokens(from, operator, amount, data, operatorData) { + shouldBurnTokens(from, operator, amount, data, operatorData); +} + +function shouldBurnTokens(from, operator, amount, data, operatorData) { + const operatorCall = operator !== null; + + it(`${operatorCall ? 'operator ' : ''}can burn an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialFromBalance = await this.token.balanceOf(from); + + let receipt; + if (!operatorCall) { + receipt = await this.token.burn(amount, data, { from }); + expectEvent(receipt, 'Burned', { + operator: from, + from, + amount, + data, + operatorData: null, + }); + } else { + receipt = await this.token.operatorBurn(from, amount, data, operatorData, { from: operator }); + expectEvent(receipt, 'Burned', { + operator, + from, + amount, + data, + operatorData, + }); + } + + expectEvent(receipt, 'Transfer', { + from, + to: ZERO_ADDRESS, + value: amount, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalFromBalance = await this.token.balanceOf(from); + + expect(finalTotalSupply.sub(initialTotalSupply)).to.be.bignumber.equal(amount.neg()); + expect(finalFromBalance.sub(initialFromBalance)).to.be.bignumber.equal(amount.neg()); + }); +} + +function shouldBehaveLikeERC777InternalMint(recipient, operator, amount, data, operatorData) { + shouldInternalMintTokens(operator, recipient, new BN('0'), data, operatorData); + shouldInternalMintTokens(operator, recipient, amount, data, operatorData); + + it('reverts when minting tokens for the zero address', async function () { + await expectRevert.unspecified( + this.token.$_mint(ZERO_ADDRESS, amount, data, operatorData, true, { from: operator }), + ); + }); +} + +function shouldInternalMintTokens(operator, to, amount, data, operatorData) { + it(`can (internal) mint an amount of ${amount}`, async function () { + const initialTotalSupply = await this.token.totalSupply(); + const initialToBalance = await this.token.balanceOf(to); + + const receipt = await this.token.$_mint(to, amount, data, operatorData, true, { from: operator }); + + expectEvent(receipt, 'Minted', { + operator, + to, + amount, + data, + operatorData, + }); + + expectEvent(receipt, 'Transfer', { + from: ZERO_ADDRESS, + to, + value: amount, + }); + + const finalTotalSupply = await this.token.totalSupply(); + const finalToBalance = await this.token.balanceOf(to); + + expect(finalTotalSupply.sub(initialTotalSupply)).to.be.bignumber.equal(amount); + expect(finalToBalance.sub(initialToBalance)).to.be.bignumber.equal(amount); + }); +} + +function shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData) { + context('when TokensRecipient reverts', function () { + beforeEach(async function () { + await this.tokensRecipientImplementer.setShouldRevertReceive(true); + }); + + it('send reverts', async function () { + await expectRevert.unspecified(sendFromHolder(this.token, this.sender, this.recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await expectRevert.unspecified( + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }), + ); + }); + + it('mint (internal) reverts', async function () { + await expectRevert.unspecified( + this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }), + ); + }); + }); + + context('when TokensRecipient does not revert', function () { + beforeEach(async function () { + await this.tokensRecipientImplementer.setShouldRevertSend(false); + }); + + it('TokensRecipient receives send data and is called after state mutation', async function () { + const { tx } = await sendFromHolder(this.token, this.sender, this.recipient, amount, data); + + const postSenderBalance = await this.token.balanceOf(this.sender); + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + this.sender, + this.sender, + this.recipient, + amount, + data, + null, + postSenderBalance, + postRecipientBalance, + ); + }); + + it('TokensRecipient receives operatorSend data and is called after state mutation', async function () { + const { tx } = await this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { + from: operator, + }); + + const postSenderBalance = await this.token.balanceOf(this.sender); + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + operator, + this.sender, + this.recipient, + amount, + data, + operatorData, + postSenderBalance, + postRecipientBalance, + ); + }); + + it('TokensRecipient receives mint (internal) data and is called after state mutation', async function () { + const { tx } = await this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }); + + const postRecipientBalance = await this.token.balanceOf(this.recipient); + + await assertTokensReceivedCalled( + this.token, + tx, + operator, + ZERO_ADDRESS, + this.recipient, + amount, + data, + operatorData, + new BN('0'), + postRecipientBalance, + ); + }); + }); +} + +function shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData) { + context('when TokensSender reverts', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevertSend(true); + }); + + it('send reverts', async function () { + await expectRevert.unspecified(sendFromHolder(this.token, this.sender, this.recipient, amount, data)); + }); + + it('operatorSend reverts', async function () { + await expectRevert.unspecified( + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }), + ); + }); + + it('burn reverts', async function () { + await expectRevert.unspecified(burnFromHolder(this.token, this.sender, amount, data)); + }); + + it('operatorBurn reverts', async function () { + await expectRevert.unspecified( + this.token.operatorBurn(this.sender, amount, data, operatorData, { from: operator }), + ); + }); + }); + + context('when TokensSender does not revert', function () { + beforeEach(async function () { + await this.tokensSenderImplementer.setShouldRevertSend(false); + }); + + it('TokensSender receives send data and is called before state mutation', async function () { + const preSenderBalance = await this.token.balanceOf(this.sender); + const preRecipientBalance = await this.token.balanceOf(this.recipient); + + const { tx } = await sendFromHolder(this.token, this.sender, this.recipient, amount, data); + + await assertTokensToSendCalled( + this.token, + tx, + this.sender, + this.sender, + this.recipient, + amount, + data, + null, + preSenderBalance, + preRecipientBalance, + ); + }); + + it('TokensSender receives operatorSend data and is called before state mutation', async function () { + const preSenderBalance = await this.token.balanceOf(this.sender); + const preRecipientBalance = await this.token.balanceOf(this.recipient); + + const { tx } = await this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { + from: operator, + }); + + await assertTokensToSendCalled( + this.token, + tx, + operator, + this.sender, + this.recipient, + amount, + data, + operatorData, + preSenderBalance, + preRecipientBalance, + ); + }); + + it('TokensSender receives burn data and is called before state mutation', async function () { + const preSenderBalance = await this.token.balanceOf(this.sender); + + const { tx } = await burnFromHolder(this.token, this.sender, amount, data, { from: this.sender }); + + await assertTokensToSendCalled( + this.token, + tx, + this.sender, + this.sender, + ZERO_ADDRESS, + amount, + data, + null, + preSenderBalance, + ); + }); + + it('TokensSender receives operatorBurn data and is called before state mutation', async function () { + const preSenderBalance = await this.token.balanceOf(this.sender); + + const { tx } = await this.token.operatorBurn(this.sender, amount, data, operatorData, { from: operator }); + + await assertTokensToSendCalled( + this.token, + tx, + operator, + this.sender, + ZERO_ADDRESS, + amount, + data, + operatorData, + preSenderBalance, + ); + }); + }); +} + +function removeBalance(holder) { + beforeEach(async function () { + await this.token.burn(await this.token.balanceOf(holder), '0x', { from: holder }); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + }); +} + +async function assertTokensReceivedCalled( + token, + txHash, + operator, + from, + to, + amount, + data, + operatorData, + fromBalance, + toBalance = '0', +) { + await expectEvent.inTransaction(txHash, ERC777SenderRecipientMock, 'TokensReceivedCalled', { + operator, + from, + to, + amount, + data, + operatorData, + token: token.address, + fromBalance, + toBalance, + }); +} + +async function assertTokensToSendCalled( + token, + txHash, + operator, + from, + to, + amount, + data, + operatorData, + fromBalance, + toBalance = '0', +) { + await expectEvent.inTransaction(txHash, ERC777SenderRecipientMock, 'TokensToSendCalled', { + operator, + from, + to, + amount, + data, + operatorData, + token: token.address, + fromBalance, + toBalance, + }); +} + +async function sendFromHolder(token, holder, to, amount, data) { + if ((await web3.eth.getCode(holder)).length <= '0x'.length) { + return token.send(to, amount, data, { from: holder }); + } else { + // assume holder is ERC777SenderRecipientMock contract + return (await ERC777SenderRecipientMock.at(holder)).send(token.address, to, amount, data); + } +} + +async function burnFromHolder(token, holder, amount, data) { + if ((await web3.eth.getCode(holder)).length <= '0x'.length) { + return token.burn(amount, data, { from: holder }); + } else { + // assume holder is ERC777SenderRecipientMock contract + return (await ERC777SenderRecipientMock.at(holder)).burn(token.address, amount, data); + } +} + +module.exports = { + shouldBehaveLikeERC777DirectSendBurn, + shouldBehaveLikeERC777OperatorSendBurn, + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, + shouldBehaveLikeERC777InternalMint, + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook, + shouldBehaveLikeERC777SendBurnWithSendHook, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/ERC777.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/ERC777.test.js new file mode 100644 index 0000000..44bc253 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/ERC777.test.js @@ -0,0 +1,556 @@ +const { BN, constants, expectEvent, expectRevert, singletons } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const { + shouldBehaveLikeERC777DirectSendBurn, + shouldBehaveLikeERC777OperatorSendBurn, + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn, + shouldBehaveLikeERC777InternalMint, + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook, + shouldBehaveLikeERC777SendBurnWithSendHook, +} = require('./ERC777.behavior'); + +const { shouldBehaveLikeERC20, shouldBehaveLikeERC20Approve } = require('../ERC20/ERC20.behavior'); + +const ERC777 = artifacts.require('$ERC777Mock'); +const ERC777SenderRecipientMock = artifacts.require('$ERC777SenderRecipientMock'); + +contract('ERC777', function (accounts) { + const [registryFunder, holder, defaultOperatorA, defaultOperatorB, newOperator, anyone] = accounts; + + const initialSupply = new BN('10000'); + const name = 'ERC777Test'; + const symbol = '777T'; + const data = web3.utils.sha3('OZ777TestData'); + const operatorData = web3.utils.sha3('OZ777TestOperatorData'); + + const defaultOperators = [defaultOperatorA, defaultOperatorB]; + + beforeEach(async function () { + this.erc1820 = await singletons.ERC1820Registry(registryFunder); + }); + + context('with default operators', function () { + beforeEach(async function () { + this.token = await ERC777.new(name, symbol, defaultOperators); + await this.token.$_mint(holder, initialSupply, '0x', '0x'); + }); + + describe('as an ERC20 token', function () { + shouldBehaveLikeERC20('ERC777', initialSupply, holder, anyone, defaultOperatorA); + + describe('_approve', function () { + shouldBehaveLikeERC20Approve('ERC777', holder, anyone, initialSupply, function (owner, spender, amount) { + return this.token.$_approve(owner, spender, amount); + }); + + describe('when the owner is the zero address', function () { + it('reverts', async function () { + await expectRevert( + this.token.$_approve(ZERO_ADDRESS, anyone, initialSupply), + 'ERC777: approve from the zero address', + ); + }); + }); + }); + }); + + it('does not emit AuthorizedOperator events for default operators', async function () { + await expectEvent.notEmitted.inConstruction(this.token, 'AuthorizedOperator'); + }); + + describe('basic information', function () { + it('returns the name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('returns the symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('returns a granularity of 1', async function () { + expect(await this.token.granularity()).to.be.bignumber.equal('1'); + }); + + it('returns the default operators', async function () { + expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators); + }); + + it('default operators are operators for all accounts', async function () { + for (const operator of defaultOperators) { + expect(await this.token.isOperatorFor(operator, anyone)).to.equal(true); + } + }); + + it('returns the total supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + + it('returns 18 when decimals is called', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('18'); + }); + + it('the ERC777Token interface is registered in the registry', async function () { + expect( + await this.erc1820.getInterfaceImplementer(this.token.address, web3.utils.soliditySha3('ERC777Token')), + ).to.equal(this.token.address); + }); + + it('the ERC20Token interface is registered in the registry', async function () { + expect( + await this.erc1820.getInterfaceImplementer(this.token.address, web3.utils.soliditySha3('ERC20Token')), + ).to.equal(this.token.address); + }); + }); + + describe('balanceOf', function () { + context('for an account with no tokens', function () { + it('returns zero', async function () { + expect(await this.token.balanceOf(anyone)).to.be.bignumber.equal('0'); + }); + }); + + context('for an account with tokens', function () { + it('returns their balance', async function () { + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply); + }); + }); + }); + + context('with no ERC777TokensSender and no ERC777TokensRecipient implementers', function () { + describe('send/burn', function () { + shouldBehaveLikeERC777DirectSendBurn(holder, anyone, data); + + context('with self operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, holder, data, operatorData); + }); + + context('with first default operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorA, data, operatorData); + }); + + context('with second default operator', function () { + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, defaultOperatorB, data, operatorData); + }); + + context('before authorizing a new operator', function () { + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); + }); + + context('with new authorized operator', function () { + beforeEach(async function () { + await this.token.authorizeOperator(newOperator, { from: holder }); + }); + + shouldBehaveLikeERC777OperatorSendBurn(holder, anyone, newOperator, data, operatorData); + + context('with revoked operator', function () { + beforeEach(async function () { + await this.token.revokeOperator(newOperator, { from: holder }); + }); + + shouldBehaveLikeERC777UnauthorizedOperatorSendBurn(holder, anyone, newOperator, data, operatorData); + }); + }); + }); + + describe('mint (internal)', function () { + const to = anyone; + const amount = new BN('5'); + + context('with default operator', function () { + const operator = defaultOperatorA; + + shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); + }); + + context('with non operator', function () { + const operator = newOperator; + + shouldBehaveLikeERC777InternalMint(to, operator, amount, data, operatorData); + }); + }); + + describe('mint (internal extended)', function () { + const amount = new BN('5'); + + context('to anyone', function () { + beforeEach(async function () { + this.recipient = anyone; + }); + + context('with default operator', function () { + const operator = defaultOperatorA; + + it('without requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, false, { from: operator }); + }); + + it('with requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }); + }); + }); + + context('with non operator', function () { + const operator = newOperator; + + it('without requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, false, { from: operator }); + }); + + it('with requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }); + }); + }); + }); + + context('to non ERC777TokensRecipient implementer', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = this.tokensRecipientImplementer.address; + }); + + context('with default operator', function () { + const operator = defaultOperatorA; + + it('without requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, false, { from: operator }); + }); + + it('with requireReceptionAck', async function () { + await expectRevert( + this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + }); + + context('with non operator', function () { + const operator = newOperator; + + it('without requireReceptionAck', async function () { + await this.token.$_mint(this.recipient, amount, data, operatorData, false, { from: operator }); + }); + + it('with requireReceptionAck', async function () { + await expectRevert( + this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + }); + }); + }); + }); + + describe('operator management', function () { + it('accounts are their own operator', async function () { + expect(await this.token.isOperatorFor(holder, holder)).to.equal(true); + }); + + it('reverts when self-authorizing', async function () { + await expectRevert( + this.token.authorizeOperator(holder, { from: holder }), + 'ERC777: authorizing self as operator', + ); + }); + + it('reverts when self-revoking', async function () { + await expectRevert(this.token.revokeOperator(holder, { from: holder }), 'ERC777: revoking self as operator'); + }); + + it('non-operators can be revoked', async function () { + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(false); + + const receipt = await this.token.revokeOperator(newOperator, { from: holder }); + expectEvent(receipt, 'RevokedOperator', { operator: newOperator, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(false); + }); + + it('non-operators can be authorized', async function () { + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(false); + + const receipt = await this.token.authorizeOperator(newOperator, { from: holder }); + expectEvent(receipt, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(true); + }); + + describe('new operators', function () { + beforeEach(async function () { + await this.token.authorizeOperator(newOperator, { from: holder }); + }); + + it('are not added to the default operators list', async function () { + expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators); + }); + + it('can be re-authorized', async function () { + const receipt = await this.token.authorizeOperator(newOperator, { from: holder }); + expectEvent(receipt, 'AuthorizedOperator', { operator: newOperator, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(true); + }); + + it('can be revoked', async function () { + const receipt = await this.token.revokeOperator(newOperator, { from: holder }); + expectEvent(receipt, 'RevokedOperator', { operator: newOperator, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(newOperator, holder)).to.equal(false); + }); + }); + + describe('default operators', function () { + it('can be re-authorized', async function () { + const receipt = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); + expectEvent(receipt, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(defaultOperatorA, holder)).to.equal(true); + }); + + it('can be revoked', async function () { + const receipt = await this.token.revokeOperator(defaultOperatorA, { from: holder }); + expectEvent(receipt, 'RevokedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(defaultOperatorA, holder)).to.equal(false); + }); + + it('cannot be revoked for themselves', async function () { + await expectRevert( + this.token.revokeOperator(defaultOperatorA, { from: defaultOperatorA }), + 'ERC777: revoking self as operator', + ); + }); + + context('with revoked default operator', function () { + beforeEach(async function () { + await this.token.revokeOperator(defaultOperatorA, { from: holder }); + }); + + it('default operator is not revoked for other holders', async function () { + expect(await this.token.isOperatorFor(defaultOperatorA, anyone)).to.equal(true); + }); + + it('other default operators are not revoked', async function () { + expect(await this.token.isOperatorFor(defaultOperatorB, holder)).to.equal(true); + }); + + it('default operators list is not modified', async function () { + expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators); + }); + + it('revoked default operator can be re-authorized', async function () { + const receipt = await this.token.authorizeOperator(defaultOperatorA, { from: holder }); + expectEvent(receipt, 'AuthorizedOperator', { operator: defaultOperatorA, tokenHolder: holder }); + + expect(await this.token.isOperatorFor(defaultOperatorA, holder)).to.equal(true); + }); + }); + }); + }); + + describe('send and receive hooks', function () { + const amount = new BN('1'); + const operator = defaultOperatorA; + // sender and recipient are stored inside 'this', since in some tests their addresses are determined dynamically + + describe('tokensReceived', function () { + beforeEach(function () { + this.sender = holder; + }); + + context('with no ERC777TokensRecipient implementer', function () { + context('with contract recipient', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = this.tokensRecipientImplementer.address; + + // Note that tokensRecipientImplementer doesn't implement the recipient interface for the recipient + }); + + it('send reverts', async function () { + await expectRevert( + this.token.send(this.recipient, amount, data, { from: holder }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + + it('operatorSend reverts', async function () { + await expectRevert( + this.token.operatorSend(this.sender, this.recipient, amount, data, operatorData, { from: operator }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + + it('mint (internal) reverts', async function () { + await expectRevert( + this.token.$_mint(this.recipient, amount, data, operatorData, true, { from: operator }), + 'ERC777: token recipient contract has no implementer for ERC777TokensRecipient', + ); + }); + + it('(ERC20) transfer succeeds', async function () { + await this.token.transfer(this.recipient, amount, { from: holder }); + }); + + it('(ERC20) transferFrom succeeds', async function () { + const approved = anyone; + await this.token.approve(approved, amount, { from: this.sender }); + await this.token.transferFrom(this.sender, this.recipient, amount, { from: approved }); + }); + }); + }); + + context('with ERC777TokensRecipient implementer', function () { + context('with contract as implementer for an externally owned account', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = anyone; + + await this.tokensRecipientImplementer.recipientFor(this.recipient); + + await this.erc1820.setInterfaceImplementer( + this.recipient, + web3.utils.soliditySha3('ERC777TokensRecipient'), + this.tokensRecipientImplementer.address, + { from: this.recipient }, + ); + }); + + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); + }); + + context('with contract as implementer for another contract', function () { + beforeEach(async function () { + this.recipientContract = await ERC777SenderRecipientMock.new(); + this.recipient = this.recipientContract.address; + + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + await this.tokensRecipientImplementer.recipientFor(this.recipient); + await this.recipientContract.registerRecipient(this.tokensRecipientImplementer.address); + }); + + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); + }); + + context('with contract as implementer for itself', function () { + beforeEach(async function () { + this.tokensRecipientImplementer = await ERC777SenderRecipientMock.new(); + this.recipient = this.tokensRecipientImplementer.address; + + await this.tokensRecipientImplementer.recipientFor(this.recipient); + }); + + shouldBehaveLikeERC777SendBurnMintInternalWithReceiveHook(operator, amount, data, operatorData); + }); + }); + }); + + describe('tokensToSend', function () { + beforeEach(function () { + this.recipient = anyone; + }); + + context('with a contract as implementer for an externally owned account', function () { + beforeEach(async function () { + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + this.sender = holder; + + await this.tokensSenderImplementer.senderFor(this.sender); + + await this.erc1820.setInterfaceImplementer( + this.sender, + web3.utils.soliditySha3('ERC777TokensSender'), + this.tokensSenderImplementer.address, + { from: this.sender }, + ); + }); + + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); + }); + + context('with contract as implementer for another contract', function () { + beforeEach(async function () { + this.senderContract = await ERC777SenderRecipientMock.new(); + this.sender = this.senderContract.address; + + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + await this.tokensSenderImplementer.senderFor(this.sender); + await this.senderContract.registerSender(this.tokensSenderImplementer.address); + + // For the contract to be able to receive tokens (that it can later send), it must also implement the + // recipient interface. + + await this.senderContract.recipientFor(this.sender); + await this.token.send(this.sender, amount, data, { from: holder }); + }); + + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); + }); + + context('with a contract as implementer for itself', function () { + beforeEach(async function () { + this.tokensSenderImplementer = await ERC777SenderRecipientMock.new(); + this.sender = this.tokensSenderImplementer.address; + + await this.tokensSenderImplementer.senderFor(this.sender); + + // For the contract to be able to receive tokens (that it can later send), it must also implement the + // recipient interface. + + await this.tokensSenderImplementer.recipientFor(this.sender); + await this.token.send(this.sender, amount, data, { from: holder }); + }); + + shouldBehaveLikeERC777SendBurnWithSendHook(operator, amount, data, operatorData); + }); + }); + }); + }); + + context('with no default operators', function () { + beforeEach(async function () { + this.token = await ERC777.new(name, symbol, []); + }); + + it('default operators list is empty', async function () { + expect(await this.token.defaultOperators()).to.deep.equal([]); + }); + }); + + describe('relative order of hooks', function () { + beforeEach(async function () { + await singletons.ERC1820Registry(registryFunder); + this.sender = await ERC777SenderRecipientMock.new(); + await this.sender.registerRecipient(this.sender.address); + await this.sender.registerSender(this.sender.address); + this.token = await ERC777.new(name, symbol, []); + await this.token.$_mint(this.sender.address, 1, '0x', '0x'); + }); + + it('send', async function () { + const { receipt } = await this.sender.send(this.token.address, anyone, 1, '0x'); + + const internalBeforeHook = receipt.logs.findIndex(l => l.event === 'BeforeTokenTransfer'); + expect(internalBeforeHook).to.be.gte(0); + const externalSendHook = receipt.logs.findIndex(l => l.event === 'TokensToSendCalled'); + expect(externalSendHook).to.be.gte(0); + + expect(externalSendHook).to.be.lt(internalBeforeHook); + }); + + it('burn', async function () { + const { receipt } = await this.sender.burn(this.token.address, 1, '0x'); + + const internalBeforeHook = receipt.logs.findIndex(l => l.event === 'BeforeTokenTransfer'); + expect(internalBeforeHook).to.be.gte(0); + const externalSendHook = receipt.logs.findIndex(l => l.event === 'TokensToSendCalled'); + expect(externalSendHook).to.be.gte(0); + + expect(externalSendHook).to.be.lt(internalBeforeHook); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js new file mode 100644 index 0000000..e6a842b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/ERC777/presets/ERC777PresetFixedSupply.test.js @@ -0,0 +1,49 @@ +const { BN, singletons } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC777PresetFixedSupply = artifacts.require('ERC777PresetFixedSupply'); + +contract('ERC777PresetFixedSupply', function (accounts) { + const [registryFunder, owner, defaultOperatorA, defaultOperatorB, anyone] = accounts; + + const initialSupply = new BN('10000'); + const name = 'ERC777Preset'; + const symbol = '777P'; + + const defaultOperators = [defaultOperatorA, defaultOperatorB]; + + before(async function () { + await singletons.ERC1820Registry(registryFunder); + }); + + beforeEach(async function () { + this.token = await ERC777PresetFixedSupply.new(name, symbol, defaultOperators, initialSupply, owner); + }); + + it('returns the name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('returns the symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('returns the default operators', async function () { + expect(await this.token.defaultOperators()).to.deep.equal(defaultOperators); + }); + + it('default operators are operators for all accounts', async function () { + for (const operator of defaultOperators) { + expect(await this.token.isOperatorFor(operator, anyone)).to.equal(true); + } + }); + + it('returns the total supply equal to initial supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + + it('returns the balance of owner equal to initial supply', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialSupply); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/token/common/ERC2981.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/token/common/ERC2981.behavior.js new file mode 100644 index 0000000..5d0f677 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/token/common/ERC2981.behavior.js @@ -0,0 +1,157 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); + +function shouldBehaveLikeERC2981() { + const royaltyFraction = new BN('10'); + + shouldSupportInterfaces(['ERC2981']); + + describe('default royalty', function () { + beforeEach(async function () { + await this.token.$_setDefaultRoyalty(this.account1, royaltyFraction); + }); + + it('checks royalty is set', async function () { + const royalty = new BN((this.salePrice * royaltyFraction) / 10000); + + const initInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(initInfo[0]).to.be.equal(this.account1); + expect(initInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('updates royalty amount', async function () { + const newPercentage = new BN('25'); + + // Updated royalty check + await this.token.$_setDefaultRoyalty(this.account1, newPercentage); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + const newInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(newInfo[0]).to.be.equal(this.account1); + expect(newInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('holds same royalty value for different tokens', async function () { + const newPercentage = new BN('20'); + await this.token.$_setDefaultRoyalty(this.account1, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + + expect(token1Info[1]).to.be.bignumber.equal(token2Info[1]); + }); + + it('Remove royalty information', async function () { + const newValue = new BN('0'); + await this.token.$_deleteDefaultRoyalty(); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Test royalty info is still persistent across all tokens + expect(token1Info[0]).to.be.bignumber.equal(token2Info[0]); + expect(token1Info[1]).to.be.bignumber.equal(token2Info[1]); + // Test information was deleted + expect(token1Info[0]).to.be.equal(ZERO_ADDRESS); + expect(token1Info[1]).to.be.bignumber.equal(newValue); + }); + + it('reverts if invalid parameters', async function () { + await expectRevert(this.token.$_setDefaultRoyalty(ZERO_ADDRESS, royaltyFraction), 'ERC2981: invalid receiver'); + + await expectRevert( + this.token.$_setDefaultRoyalty(this.account1, new BN('11000')), + 'ERC2981: royalty fee will exceed salePrice', + ); + }); + }); + + describe('token based royalty', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, royaltyFraction); + }); + + it('updates royalty amount', async function () { + const newPercentage = new BN('25'); + let royalty = new BN((this.salePrice * royaltyFraction) / 10000); + // Initial royalty check + const initInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(initInfo[0]).to.be.equal(this.account1); + expect(initInfo[1]).to.be.bignumber.equal(royalty); + + // Updated royalty check + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, newPercentage); + royalty = new BN((this.salePrice * newPercentage) / 10000); + const newInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(newInfo[0]).to.be.equal(this.account1); + expect(newInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('holds different values for different tokens', async function () { + const newPercentage = new BN('20'); + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + + // must be different even at the same this.salePrice + expect(token1Info[1]).to.not.be.equal(token2Info.royaltyFraction); + }); + + it('reverts if invalid parameters', async function () { + await expectRevert( + this.token.$_setTokenRoyalty(this.tokenId1, ZERO_ADDRESS, royaltyFraction), + 'ERC2981: Invalid parameters', + ); + + await expectRevert( + this.token.$_setTokenRoyalty(this.tokenId1, this.account1, new BN('11000')), + 'ERC2981: royalty fee will exceed salePrice', + ); + }); + + it('can reset token after setting royalty', async function () { + const newPercentage = new BN('30'); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + await this.token.$_setTokenRoyalty(this.tokenId1, this.account2, newPercentage); + + const tokenInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + // Tokens must have own information + expect(tokenInfo[1]).to.be.bignumber.equal(royalty); + expect(tokenInfo[0]).to.be.equal(this.account2); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, new BN('0')); + const result = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Token must not share default information + expect(result[0]).to.be.equal(this.account1); + expect(result[1]).to.be.bignumber.equal(new BN('0')); + }); + + it('can hold default and token royalty information', async function () { + const newPercentage = new BN('30'); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account2, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Tokens must not have same values + expect(token1Info[1]).to.not.be.bignumber.equal(token2Info[1]); + expect(token1Info[0]).to.not.be.equal(token2Info[0]); + + // Updated token must have new values + expect(token2Info[0]).to.be.equal(this.account2); + expect(token2Info[1]).to.be.bignumber.equal(royalty); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC2981, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Address.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Address.test.js new file mode 100644 index 0000000..4f9f9ee --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Address.test.js @@ -0,0 +1,361 @@ +const { balance, constants, ether, expectRevert, send, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Address = artifacts.require('$Address'); +const EtherReceiver = artifacts.require('EtherReceiverMock'); +const CallReceiverMock = artifacts.require('CallReceiverMock'); + +contract('Address', function (accounts) { + const [recipient, other] = accounts; + + beforeEach(async function () { + this.mock = await Address.new(); + }); + + describe('isContract', function () { + it('returns false for account address', async function () { + expect(await this.mock.$isContract(other)).to.equal(false); + }); + + it('returns true for contract address', async function () { + expect(await this.mock.$isContract(this.mock.address)).to.equal(true); + }); + }); + + describe('sendValue', function () { + beforeEach(async function () { + this.recipientTracker = await balance.tracker(recipient); + }); + + context('when sender contract has no funds', function () { + it('sends 0 wei', async function () { + await this.mock.$sendValue(other, 0); + + expect(await this.recipientTracker.delta()).to.be.bignumber.equal('0'); + }); + + it('reverts when sending non-zero amounts', async function () { + await expectRevert(this.mock.$sendValue(other, 1), 'Address: insufficient balance'); + }); + }); + + context('when sender contract has funds', function () { + const funds = ether('1'); + beforeEach(async function () { + await send.ether(other, this.mock.address, funds); + }); + + it('sends 0 wei', async function () { + await this.mock.$sendValue(recipient, 0); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal('0'); + }); + + it('sends non-zero amounts', async function () { + await this.mock.$sendValue(recipient, funds.subn(1)); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal(funds.subn(1)); + }); + + it('sends the whole balance', async function () { + await this.mock.$sendValue(recipient, funds); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal(funds); + expect(await balance.current(this.mock.address)).to.be.bignumber.equal('0'); + }); + + it('reverts when sending more than the balance', async function () { + await expectRevert(this.mock.$sendValue(recipient, funds.addn(1)), 'Address: insufficient balance'); + }); + + context('with contract recipient', function () { + beforeEach(async function () { + this.target = await EtherReceiver.new(); + }); + + it('sends funds', async function () { + const tracker = await balance.tracker(this.target.address); + + await this.target.setAcceptEther(true); + await this.mock.$sendValue(this.target.address, funds); + + expect(await tracker.delta()).to.be.bignumber.equal(funds); + }); + + it('reverts on recipient revert', async function () { + await this.target.setAcceptEther(false); + await expectRevert( + this.mock.$sendValue(this.target.address, funds), + 'Address: unable to send value, recipient may have reverted', + ); + }); + }); + }); + }); + + describe('functionCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + context('with valid contract receiver', function () { + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const receipt = await this.mock.$functionCall(this.target.address, abiEncodedCall); + + expectEvent(receipt, 'return$functionCall_address_bytes', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + 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(); + + await expectRevert( + this.mock.$functionCall(this.target.address, abiEncodedCall), + 'Address: low-level call failed', + ); + }); + + it('reverts when the called function reverts, bubbling up the revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert(this.mock.$functionCall(this.target.address, abiEncodedCall), 'CallReceiverMock: reverting'); + }); + + it('reverts when the called function runs out of gas', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionOutOfGas().encodeABI(); + + await expectRevert( + this.mock.$functionCall(this.target.address, abiEncodedCall, { gas: '120000' }), + 'Address: low-level call failed', + ); + }); + + it('reverts when the called function throws', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionThrows().encodeABI(); + + 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( + { + name: 'mockFunctionDoesNotExist', + type: 'function', + inputs: [], + }, + [], + ); + + await expectRevert( + this.mock.$functionCall(this.target.address, abiEncodedCall), + 'Address: low-level call failed', + ); + }); + }); + + context('with non-contract receiver', function () { + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevert(this.mock.$functionCall(recipient, abiEncodedCall), 'Address: call to non-contract'); + }); + }); + }); + + describe('functionCallWithValue', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + context('with zero value', function () { + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, 0); + expectEvent(receipt, 'return$functionCallWithValue_address_bytes_uint256', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + }); + }); + + context('with non-zero value', function () { + const amount = ether('1.2'); + + it('reverts if insufficient sender balance', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevert( + this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount), + 'Address: insufficient balance for call', + ); + }); + + it('calls the requested function with existing value', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const tracker = await balance.tracker(this.target.address); + + await send.ether(other, this.mock.address, amount); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount); + expectEvent(receipt, 'return$functionCallWithValue_address_bytes_uint256', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + + expect(await tracker.delta()).to.be.bignumber.equal(amount); + }); + + it('calls the requested function with transaction funds', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const tracker = await balance.tracker(this.target.address); + + expect(await balance.current(this.mock.address)).to.be.bignumber.equal('0'); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount, { + from: other, + value: amount, + }); + expectEvent(receipt, 'return$functionCallWithValue_address_bytes_uint256', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + + expect(await tracker.delta()).to.be.bignumber.equal(amount); + }); + + it('reverts when calling non-payable functions', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionNonPayable().encodeABI(); + + await send.ether(other, this.mock.address, amount); + await expectRevert( + this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount), + '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); + }); + }); + }); + + describe('functionStaticCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockStaticFunction().encodeABI(); + + expect(await this.mock.$functionStaticCall(this.target.address, abiEncodedCall)).to.be.equal( + web3.eth.abi.encodeParameters(['string'], ['0x1234']), + ); + }); + + it('reverts on a non-static function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevert( + this.mock.$functionStaticCall(this.target.address, abiEncodedCall), + 'Address: low-level static call failed', + ); + }); + + it('bubbles up revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert( + this.mock.$functionStaticCall(this.target.address, abiEncodedCall), + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + 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 () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + it('delegate calls the requested function', async function () { + // pseudorandom values + const slot = '0x93e4c53af435ddf777c3de84bb9a953a777788500e229a468ea1036496ab66a0'; + const value = '0x6a465d1c49869f71fb65562bcbd7e08c8044074927f0297127203f2a9924ff5b'; + + const abiEncodedCall = this.target.contract.methods.mockFunctionWritesStorage(slot, value).encodeABI(); + + expect(await web3.eth.getStorageAt(this.mock.address, slot)).to.be.equal(constants.ZERO_BYTES32); + + expectEvent( + await this.mock.$functionDelegateCall(this.target.address, abiEncodedCall), + 'return$functionDelegateCall_address_bytes', + { ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']) }, + ); + + expect(await web3.eth.getStorageAt(this.mock.address, slot)).to.be.equal(value); + }); + + it('bubbles up revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert( + this.mock.$functionDelegateCall(this.target.address, abiEncodedCall), + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + 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); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Arrays.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Arrays.test.js new file mode 100644 index 0000000..d939d59 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Arrays.test.js @@ -0,0 +1,123 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const AddressArraysMock = artifacts.require('AddressArraysMock'); +const Bytes32ArraysMock = artifacts.require('Bytes32ArraysMock'); +const Uint256ArraysMock = artifacts.require('Uint256ArraysMock'); + +contract('Arrays', function () { + describe('findUpperBound', function () { + context('Even number of elements', function () { + const EVEN_ELEMENTS_ARRAY = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(EVEN_ELEMENTS_ARRAY); + }); + + it('returns correct index for the basic case', async function () { + expect(await this.arrays.findUpperBound(16)).to.be.bignumber.equal('5'); + }); + + it('returns 0 for the first element', async function () { + expect(await this.arrays.findUpperBound(11)).to.be.bignumber.equal('0'); + }); + + it('returns index of the last element', async function () { + expect(await this.arrays.findUpperBound(20)).to.be.bignumber.equal('9'); + }); + + it('returns first index after last element if searched value is over the upper boundary', async function () { + expect(await this.arrays.findUpperBound(32)).to.be.bignumber.equal('10'); + }); + + it('returns 0 for the element under the lower boundary', async function () { + expect(await this.arrays.findUpperBound(2)).to.be.bignumber.equal('0'); + }); + }); + + context('Odd number of elements', function () { + const ODD_ELEMENTS_ARRAY = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(ODD_ELEMENTS_ARRAY); + }); + + it('returns correct index for the basic case', async function () { + expect(await this.arrays.findUpperBound(16)).to.be.bignumber.equal('5'); + }); + + it('returns 0 for the first element', async function () { + expect(await this.arrays.findUpperBound(11)).to.be.bignumber.equal('0'); + }); + + it('returns index of the last element', async function () { + expect(await this.arrays.findUpperBound(21)).to.be.bignumber.equal('10'); + }); + + it('returns first index after last element if searched value is over the upper boundary', async function () { + expect(await this.arrays.findUpperBound(32)).to.be.bignumber.equal('11'); + }); + + it('returns 0 for the element under the lower boundary', async function () { + expect(await this.arrays.findUpperBound(2)).to.be.bignumber.equal('0'); + }); + }); + + context('Array with gap', function () { + const WITH_GAP_ARRAY = [11, 12, 13, 14, 15, 20, 21, 22, 23, 24]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(WITH_GAP_ARRAY); + }); + + it('returns index of first element in next filled range', async function () { + expect(await this.arrays.findUpperBound(17)).to.be.bignumber.equal('5'); + }); + }); + + context('Empty array', function () { + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new([]); + }); + + it('always returns 0 for empty array', async function () { + expect(await this.arrays.findUpperBound(10)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('unsafeAccess', function () { + for (const { type, artifact, elements } of [ + { + type: 'address', + artifact: AddressArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(20)), + }, + { + type: 'bytes32', + artifact: Bytes32ArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(32)), + }, + { + type: 'uint256', + artifact: Uint256ArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(32)), + }, + ]) { + it(type, async function () { + const contract = await artifact.new(elements); + + for (const i in elements) { + expect(await contract.unsafeAccess(i)).to.be.bignumber.equal(elements[i]); + } + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Base64.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Base64.test.js new file mode 100644 index 0000000..dfff0b0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Base64.test.js @@ -0,0 +1,33 @@ +const { expect } = require('chai'); + +const Base64 = artifacts.require('$Base64'); + +contract('Strings', function () { + beforeEach(async function () { + this.base64 = await Base64.new(); + }); + + describe('from bytes - base64', function () { + it('converts to base64 encoded string with double padding', async function () { + const TEST_MESSAGE = 'test'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdA=='); + }); + + it('converts to base64 encoded string with single padding', async function () { + const TEST_MESSAGE = 'test1'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdDE='); + }); + + it('converts to base64 encoded string without padding', async function () { + const TEST_MESSAGE = 'test12'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdDEy'); + }); + + it('empty bytes', async function () { + expect(await this.base64.$encode([])).to.equal(''); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Checkpoints.t.sol b/lib/openzeppelin-contracts-v4.9.3/test/utils/Checkpoints.t.sol new file mode 100644 index 0000000..f2cb587 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Checkpoints.t.sol @@ -0,0 +1,347 @@ +// 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]; + if (lastKey > 0) { + 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]; + if (lastKey > 0) { + 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]; + if (lastKey > 0) { + 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); + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Checkpoints.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Checkpoints.test.js new file mode 100644 index 0000000..f395663 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Checkpoints.test.js @@ -0,0 +1,255 @@ +const { expectRevert, time } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +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 () { + describe('without checkpoints', function () { + it('returns zero as latest value', async function () { + expect(await this.methods.history.latest()).to.be.bignumber.equal('0'); + + 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'); + }); + + it('returns zero as past value', async function () { + await time.advanceBlock(); + 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 this.methods.history.push(1); + this.tx2 = await this.methods.history.push(2); + await time.advanceBlock(); + this.tx3 = await this.methods.history.push(3); + await time.advanceBlock(); + await time.advanceBlock(); + }); + + it('returns latest value', async function () { + expect(await this.methods.history.latest()).to.be.bignumber.equal('3'); + + 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']) { + describe(`lookup: ${getAtBlockVariant}`, function () { + it('returns past values', async function () { + 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 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( + this.methods.history[getAtBlockVariant](await web3.eth.getBlockNumber()), + 'Checkpoints: block not yet mined', + ); + + await expectRevert( + this.methods.history[getAtBlockVariant]((await web3.eth.getBlockNumber()) + 1), + 'Checkpoints: block not yet mined', + ); + }); + }); + } + + it('multiple checkpoints in the same block', async function () { + const lengthBefore = await this.methods.history.length(); + + await batchInBlock([ + () => this.methods.history.push(8, { gas: 100000 }), + () => this.methods.history.push(9, { gas: 100000 }), + () => this.methods.history.push(10, { gas: 100000 }), + ]); + + 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 this.methods.history.push(i); + } + expect(await this.methods.history.length()).to.be.bignumber.equal('6'); + const block = await web3.eth.getBlockNumber(); + // recent + expect(await this.methods.history.getAtRecentBlock(block - 1)).to.be.bignumber.equal('5'); + // non-recent + expect(await this.methods.history.getAtRecentBlock(block - 9)).to.be.bignumber.equal('0'); + }); + }); + }); + + for (const length of traceLengths) { + describe(`Trace${length}`, function () { + describe('without checkpoints', function () { + it('returns zero as latest value', async function () { + expect(await this.methods.trace[length].latest()).to.be.bignumber.equal('0'); + + 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 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'); + }); + }); + + describe('with checkpoints', function () { + beforeEach('pushing checkpoints', async function () { + this.checkpoints = [ + { key: '2', value: '17' }, + { key: '3', value: '42' }, + { key: '5', value: '101' }, + { key: '7', value: '23' }, + { key: '11', value: '99' }, + ]; + for (const { key, value } of this.checkpoints) { + await this.methods.trace[length].push(key, value); + } + }); + + it('length', async function () { + expect(await this.methods.trace[length].length()).to.be.bignumber.equal(this.checkpoints.length.toString()); + }); + + it('returns latest value', async function () { + expect(await this.methods.trace[length].latest()).to.be.bignumber.equal(last(this.checkpoints).value); + + 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( + 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 this.methods.trace[length].length()).to.be.bignumber.equal(this.checkpoints.length.toString()); + + // update last key + 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 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 this.methods.trace[length].lowerLookup(i)).to.be.bignumber.equal(value); + } + }); + + 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 this.methods.trace[length].upperLookup(i)).to.be.bignumber.equal(value); + expect(await this.methods.trace[length].upperLookupRecent(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 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 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/lib/openzeppelin-contracts-v4.9.3/test/utils/Context.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Context.behavior.js new file mode 100644 index 0000000..08f7558 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Context.behavior.js @@ -0,0 +1,42 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); + +const ContextMock = artifacts.require('ContextMock'); + +function shouldBehaveLikeRegularContext(sender) { + describe('msgSender', function () { + it('returns the transaction sender when called from an EOA', async function () { + const receipt = await this.context.msgSender({ from: sender }); + expectEvent(receipt, 'Sender', { sender }); + }); + + it('returns the transaction sender when from another contract', async function () { + const { tx } = await this.caller.callSender(this.context.address, { from: sender }); + await expectEvent.inTransaction(tx, ContextMock, 'Sender', { sender: this.caller.address }); + }); + }); + + describe('msgData', function () { + const integerValue = new BN('42'); + const stringValue = 'OpenZeppelin'; + + let callData; + + beforeEach(async function () { + callData = this.context.contract.methods.msgData(integerValue.toString(), stringValue).encodeABI(); + }); + + it('returns the transaction data when called from an EOA', async function () { + const receipt = await this.context.msgData(integerValue, stringValue); + expectEvent(receipt, 'Data', { data: callData, integerValue, stringValue }); + }); + + it('returns the transaction sender when from another contract', async function () { + const { tx } = await this.caller.callData(this.context.address, integerValue, stringValue); + await expectEvent.inTransaction(tx, ContextMock, 'Data', { data: callData, integerValue, stringValue }); + }); + }); +} + +module.exports = { + shouldBehaveLikeRegularContext, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Context.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Context.test.js new file mode 100644 index 0000000..f372f74 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Context.test.js @@ -0,0 +1,17 @@ +require('@openzeppelin/test-helpers'); + +const ContextMock = artifacts.require('ContextMock'); +const ContextMockCaller = artifacts.require('ContextMockCaller'); + +const { shouldBehaveLikeRegularContext } = require('./Context.behavior'); + +contract('Context', function (accounts) { + const [sender] = accounts; + + beforeEach(async function () { + this.context = await ContextMock.new(); + this.caller = await ContextMockCaller.new(); + }); + + shouldBehaveLikeRegularContext(sender); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Counters.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Counters.test.js new file mode 100644 index 0000000..6fb8992 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Counters.test.js @@ -0,0 +1,84 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const Counters = artifacts.require('$Counters'); + +contract('Counters', function () { + beforeEach(async function () { + this.counter = await Counters.new(); + }); + + it('starts at zero', async function () { + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + + describe('increment', function () { + context('starting from 0', function () { + it('increments the current value by one', async function () { + await this.counter.$increment(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('1'); + }); + + it('can be called multiple times', async function () { + await this.counter.$increment(0); + await this.counter.$increment(0); + await this.counter.$increment(0); + + expect(await this.counter.$current(0)).to.be.bignumber.equal('3'); + }); + }); + }); + + describe('decrement', function () { + beforeEach(async function () { + await this.counter.$increment(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('1'); + }); + context('starting from 1', function () { + it('decrements the current value by one', async function () { + await this.counter.$decrement(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + + it('reverts if the current value is 0', async function () { + await this.counter.$decrement(0); + await expectRevert(this.counter.$decrement(0), 'Counter: decrement overflow'); + }); + }); + context('after incremented to 3', function () { + it('can be called multiple times', async function () { + await this.counter.$increment(0); + await this.counter.$increment(0); + + expect(await this.counter.$current(0)).to.be.bignumber.equal('3'); + + await this.counter.$decrement(0); + await this.counter.$decrement(0); + await this.counter.$decrement(0); + + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('reset', function () { + context('null counter', function () { + it('does not throw', async function () { + await this.counter.$reset(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + }); + + context('non null counter', function () { + beforeEach(async function () { + await this.counter.$increment(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('1'); + }); + it('reset to 0', async function () { + await this.counter.$reset(0); + expect(await this.counter.$current(0)).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Create2.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Create2.test.js new file mode 100644 index 0000000..2fc27dc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Create2.test.js @@ -0,0 +1,89 @@ +const { balance, ether, expectEvent, expectRevert, send } = require('@openzeppelin/test-helpers'); +const { computeCreate2Address } = require('../helpers/create2'); +const { expect } = require('chai'); + +const Create2 = artifacts.require('$Create2'); +const VestingWallet = artifacts.require('VestingWallet'); +const ERC1820Implementer = artifacts.require('$ERC1820Implementer'); + +contract('Create2', function (accounts) { + const [deployerAccount, other] = accounts; + + const salt = 'salt message'; + const saltHex = web3.utils.soliditySha3(salt); + + const encodedParams = web3.eth.abi.encodeParameters(['address', 'uint64', 'uint64'], [other, 0, 0]).slice(2); + + const constructorByteCode = `${VestingWallet.bytecode}${encodedParams}`; + + beforeEach(async function () { + this.factory = await Create2.new(); + }); + describe('computeAddress', function () { + it('computes the correct contract address', async function () { + const onChainComputed = await this.factory.$computeAddress(saltHex, web3.utils.keccak256(constructorByteCode)); + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + expect(onChainComputed).to.equal(offChainComputed); + }); + + it('computes the correct contract address with deployer', async function () { + const onChainComputed = await this.factory.$computeAddress( + saltHex, + web3.utils.keccak256(constructorByteCode), + deployerAccount, + ); + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, deployerAccount); + expect(onChainComputed).to.equal(offChainComputed); + }); + }); + + describe('deploy', function () { + it('deploys a ERC1820Implementer from inline assembly code', async function () { + const offChainComputed = computeCreate2Address(saltHex, ERC1820Implementer.bytecode, this.factory.address); + + expectEvent(await this.factory.$deploy(0, saltHex, ERC1820Implementer.bytecode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(ERC1820Implementer.bytecode).to.include((await web3.eth.getCode(offChainComputed)).slice(2)); + }); + + it('deploys a contract with constructor arguments', async function () { + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + + expectEvent(await this.factory.$deploy(0, saltHex, constructorByteCode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(await VestingWallet.at(offChainComputed).then(instance => instance.beneficiary())).to.be.equal(other); + }); + + it('deploys a contract with funds deposited in the factory', async function () { + const deposit = ether('2'); + await send.ether(deployerAccount, this.factory.address, deposit); + expect(await balance.current(this.factory.address)).to.be.bignumber.equal(deposit); + + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + + expectEvent(await this.factory.$deploy(deposit, saltHex, constructorByteCode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(await balance.current(offChainComputed)).to.be.bignumber.equal(deposit); + }); + + it('fails deploying a contract in an existent address', async function () { + expectEvent(await this.factory.$deploy(0, saltHex, constructorByteCode), 'return$deploy'); + + await expectRevert(this.factory.$deploy(0, saltHex, constructorByteCode), 'Create2: Failed on deploy'); + }); + + it('fails deploying a contract if the bytecode length is zero', async function () { + await expectRevert(this.factory.$deploy(0, saltHex, '0x'), 'Create2: bytecode length is zero'); + }); + + it('fails deploying a contract if factory contract does not have sufficient balance', async function () { + await expectRevert(this.factory.$deploy(1, saltHex, constructorByteCode), 'Create2: insufficient balance'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Multicall.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Multicall.test.js new file mode 100644 index 0000000..cfb8007 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Multicall.test.js @@ -0,0 +1,68 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); + +const ERC20MulticallMock = artifacts.require('$ERC20MulticallMock'); + +contract('Multicall', function (accounts) { + const [deployer, alice, bob] = accounts; + const amount = 12000; + + beforeEach(async function () { + this.multicallToken = await ERC20MulticallMock.new('name', 'symbol'); + await this.multicallToken.$_mint(deployer, amount); + }); + + it('batches function calls', async function () { + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + expect(await this.multicallToken.balanceOf(bob)).to.be.bignumber.equal(new BN('0')); + + await this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount / 2).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount / 3).encodeABI(), + ], + { from: deployer }, + ); + + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN(amount / 2)); + expect(await this.multicallToken.balanceOf(bob)).to.be.bignumber.equal(new BN(amount / 3)); + }); + + it('returns an array with the result of each call', async function () { + const MulticallTest = artifacts.require('MulticallTest'); + const multicallTest = await MulticallTest.new({ from: deployer }); + await this.multicallToken.transfer(multicallTest.address, amount, { from: deployer }); + expect(await this.multicallToken.balanceOf(multicallTest.address)).to.be.bignumber.equal(new BN(amount)); + + const recipients = [alice, bob]; + const amounts = [amount / 2, amount / 3].map(n => new BN(n)); + + await multicallTest.checkReturnValues(this.multicallToken.address, recipients, amounts); + }); + + it('reverts previous calls', async function () { + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + + const call = this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount).encodeABI(), + ], + { from: deployer }, + ); + + await expectRevert(call, 'ERC20: transfer amount exceeds balance'); + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + }); + + it('bubbles up revert reasons', async function () { + const call = this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount).encodeABI(), + ], + { from: deployer }, + ); + + await expectRevert(call, 'ERC20: transfer amount exceeds balance'); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/ShortStrings.t.sol b/lib/openzeppelin-contracts-v4.9.3/test/utils/ShortStrings.t.sol new file mode 100644 index 0000000..7c4faa8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/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; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/ShortStrings.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/ShortStrings.test.js new file mode 100644 index 0000000..f5cd82f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/ShortStrings.test.js @@ -0,0 +1,55 @@ +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const ShortStrings = artifacts.require('$ShortStrings'); + +function length(sstr) { + return parseInt(sstr.slice(64), 16); +} + +function decode(sstr) { + return web3.utils.toUtf8(sstr).slice(0, length(sstr)); +} + +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.$byteLength(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; + + const promise = this.mock.$toString(ret0); + if (str.length < 32) { + expect(await promise).to.be.equal(str); + } else { + 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); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/StorageSlot.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/StorageSlot.test.js new file mode 100644 index 0000000..846512e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/StorageSlot.test.js @@ -0,0 +1,210 @@ +const { constants, BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const StorageSlotMock = artifacts.require('StorageSlotMock'); + +const slot = web3.utils.keccak256('some.storage.slot'); +const otherSlot = web3.utils.keccak256('some.other.storage.slot'); + +contract('StorageSlot', function (accounts) { + beforeEach(async function () { + this.store = await StorageSlotMock.new(); + }); + + describe('boolean storage slot', function () { + beforeEach(async function () { + this.value = true; + }); + + it('set', async function () { + await this.store.setBoolean(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBoolean(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBoolean(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBoolean(otherSlot)).to.be.equal(false); + }); + }); + }); + + describe('address storage slot', function () { + beforeEach(async function () { + this.value = accounts[1]; + }); + + it('set', async function () { + await this.store.setAddress(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setAddress(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getAddress(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getAddress(otherSlot)).to.be.equal(constants.ZERO_ADDRESS); + }); + }); + }); + + describe('bytes32 storage slot', function () { + beforeEach(async function () { + this.value = web3.utils.keccak256('some byte32 value'); + }); + + it('set', async function () { + await this.store.setBytes32(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBytes32(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBytes32(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBytes32(otherSlot)).to.be.equal(constants.ZERO_BYTES32); + }); + }); + }); + + describe('uint256 storage slot', function () { + beforeEach(async function () { + this.value = new BN(1742); + }); + + it('set', async function () { + await this.store.setUint256(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setUint256(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getUint256(slot)).to.be.bignumber.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getUint256(otherSlot)).to.be.bignumber.equal('0'); + }); + }); + }); + + 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); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/Strings.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/Strings.test.js new file mode 100644 index 0000000..6658871 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/Strings.test.js @@ -0,0 +1,150 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const Strings = artifacts.require('$Strings'); + +contract('Strings', function () { + before(async function () { + this.strings = await Strings.new(); + }); + + describe('toString', function () { + const values = [ + '0', + '7', + '10', + '99', + '100', + '101', + '123', + '4132', + '12345', + '1234567', + '1234567890', + '123456789012345', + '12345678901234567890', + '123456789012345678901234567890', + '1234567890123456789012345678901234567890', + '12345678901234567890123456789012345678901234567890', + '123456789012345678901234567890123456789012345678901234567890', + '1234567890123456789012345678901234567890123456789012345678901234567890', + ]; + + describe('uint256', function () { + it('converts MAX_UINT256', async function () { + const value = constants.MAX_UINT256; + expect(await this.strings.methods['$toString(uint256)'](value)).to.equal(value.toString(10)); + }); + + for (const value of values) { + it(`converts ${value}`, async function () { + expect(await this.strings.methods['$toString(uint256)'](value)).to.equal(value); + }); + } + }); + + describe('int256', function () { + it('converts MAX_INT256', async function () { + const value = constants.MAX_INT256; + expect(await this.strings.methods['$toString(int256)'](value)).to.equal(value.toString(10)); + }); + + it('converts MIN_INT256', async function () { + const value = constants.MIN_INT256; + expect(await this.strings.methods['$toString(int256)'](value)).to.equal(value.toString(10)); + }); + + for (const value of values) { + it(`convert ${value}`, async function () { + expect(await this.strings.methods['$toString(int256)'](value)).to.equal(value); + }); + + it(`convert negative ${value}`, async function () { + const negated = new BN(value).neg(); + expect(await this.strings.methods['$toString(int256)'](negated)).to.equal(negated.toString(10)); + }); + } + }); + }); + + describe('toHexString', function () { + it('converts 0', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](0)).to.equal('0x00'); + }); + + it('converts a positive number', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](0x4132)).to.equal('0x4132'); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](constants.MAX_UINT256)).to.equal( + web3.utils.toHex(constants.MAX_UINT256), + ); + }); + }); + + describe('toHexString fixed', function () { + it('converts a positive number (long)', async function () { + expect(await this.strings.methods['$toHexString(uint256,uint256)'](0x4132, 32)).to.equal( + '0x0000000000000000000000000000000000000000000000000000000000004132', + ); + }); + + it('converts a positive number (short)', async function () { + await expectRevert( + this.strings.methods['$toHexString(uint256,uint256)'](0x4132, 1), + 'Strings: hex length insufficient', + ); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.strings.methods['$toHexString(uint256,uint256)'](constants.MAX_UINT256, 32)).to.equal( + web3.utils.toHex(constants.MAX_UINT256), + ); + }); + }); + + describe('toHexString address', function () { + it('converts a random address', async function () { + const addr = '0xa9036907dccae6a1e0033479b12e837e5cf5a02f'; + expect(await this.strings.methods['$toHexString(address)'](addr)).to.equal(addr); + }); + + it('converts an address with leading zeros', async function () { + const addr = '0x0000e0ca771e21bd00057f54a68c30d400000000'; + expect(await this.strings.methods['$toHexString(address)'](addr)).to.equal(addr); + }); + }); + + describe('equal', function () { + it('compares two empty strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('', '')).to.equal(true); + }); + + it('compares two equal strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'a')).to.equal(true); + }); + + it('compares two different strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'b')).to.equal(false); + }); + + it('compares two different strings of different lengths', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'aa')).to.equal(false); + expect(await this.strings.methods['$equal(string,string)']('aa', 'a')).to.equal(false); + }); + + it('compares two different large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(200) + 'b'; + expect(await this.strings.methods['$equal(string,string)'](str1, str2)).to.equal(false); + }); + + it('compares two equal large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(201); + expect(await this.strings.methods['$equal(string,string)'](str1, str2)).to.equal(true); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/TimersBlockNumberImpl.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/TimersBlockNumberImpl.test.js new file mode 100644 index 0000000..ee0d54b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/TimersBlockNumberImpl.test.js @@ -0,0 +1,55 @@ +const { BN, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const TimersBlockNumberImpl = artifacts.require('TimersBlockNumberImpl'); + +contract('TimersBlockNumber', function () { + beforeEach(async function () { + this.instance = await TimersBlockNumberImpl.new(); + this.now = await web3.eth.getBlock('latest').then(({ number }) => number); + }); + + it('unset', async function () { + expect(await this.instance.getDeadline()).to.be.bignumber.equal('0'); + expect(await this.instance.isUnset()).to.be.equal(true); + expect(await this.instance.isStarted()).to.be.equal(false); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('pending', async function () { + await this.instance.setDeadline(this.now + 3); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now + 3)); + expect(await this.instance.isUnset()).to.be.equal(false); + expect(await this.instance.isStarted()).to.be.equal(true); + expect(await this.instance.isPending()).to.be.equal(true); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('expired', async function () { + await this.instance.setDeadline(this.now - 3); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now - 3)); + expect(await this.instance.isUnset()).to.be.equal(false); + expect(await this.instance.isStarted()).to.be.equal(true); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(true); + }); + + it('reset', async function () { + await this.instance.reset(); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(0)); + expect(await this.instance.isUnset()).to.be.equal(true); + expect(await this.instance.isStarted()).to.be.equal(false); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('fast forward', async function () { + await this.instance.setDeadline(this.now + 3); + expect(await this.instance.isPending()).to.be.equal(true); + expect(await this.instance.isExpired()).to.be.equal(false); + await time.advanceBlockTo(this.now + 3); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(true); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/TimersTimestamp.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/TimersTimestamp.test.js new file mode 100644 index 0000000..fc32de7 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/TimersTimestamp.test.js @@ -0,0 +1,55 @@ +const { BN, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const TimersTimestampImpl = artifacts.require('TimersTimestampImpl'); + +contract('TimersTimestamp', function () { + beforeEach(async function () { + this.instance = await TimersTimestampImpl.new(); + this.now = await web3.eth.getBlock('latest').then(({ timestamp }) => timestamp); + }); + + it('unset', async function () { + expect(await this.instance.getDeadline()).to.be.bignumber.equal('0'); + expect(await this.instance.isUnset()).to.be.equal(true); + expect(await this.instance.isStarted()).to.be.equal(false); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('pending', async function () { + await this.instance.setDeadline(this.now + 100); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now + 100)); + expect(await this.instance.isUnset()).to.be.equal(false); + expect(await this.instance.isStarted()).to.be.equal(true); + expect(await this.instance.isPending()).to.be.equal(true); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('expired', async function () { + await this.instance.setDeadline(this.now - 100); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(this.now - 100)); + expect(await this.instance.isUnset()).to.be.equal(false); + expect(await this.instance.isStarted()).to.be.equal(true); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(true); + }); + + it('reset', async function () { + await this.instance.reset(); + expect(await this.instance.getDeadline()).to.be.bignumber.equal(new BN(0)); + expect(await this.instance.isUnset()).to.be.equal(true); + expect(await this.instance.isStarted()).to.be.equal(false); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(false); + }); + + it('fast forward', async function () { + await this.instance.setDeadline(this.now + 100); + expect(await this.instance.isPending()).to.be.equal(true); + expect(await this.instance.isExpired()).to.be.equal(false); + await time.increaseTo(this.now + 100); + expect(await this.instance.isPending()).to.be.equal(false); + expect(await this.instance.isExpired()).to.be.equal(true); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/ECDSA.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/ECDSA.test.js new file mode 100644 index 0000000..ae73708 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/ECDSA.test.js @@ -0,0 +1,260 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { toEthSignedMessageHash, toDataWithIntendedValidatorHash } = require('../../helpers/sign'); + +const { expect } = require('chai'); + +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); + if (long.length !== 65) { + throw new Error('invalid signature length (expected long format)'); + } + if (long[32] >> 7 === 1) { + throw new Error("invalid signature 's' value"); + } + const short = long.slice(0, 64); + short[32] |= long[64] % 27 << 7; // set the first bit of the 32nd byte to the v parity bit + return web3.utils.bytesToHex(short); +} + +function split(signature) { + const raw = web3.utils.hexToBytes(signature); + switch (raw.length) { + case 64: + return [ + web3.utils.bytesToHex(raw.slice(0, 32)), // r + web3.utils.bytesToHex(raw.slice(32, 64)), // vs + ]; + case 65: + return [ + raw[64], // v + web3.utils.bytesToHex(raw.slice(0, 32)), // r + web3.utils.bytesToHex(raw.slice(32, 64)), // s + ]; + default: + expect.fail('Invalid signature length, cannot split'); + } +} + +contract('ECDSA', function (accounts) { + const [other] = accounts; + + beforeEach(async function () { + this.ecdsa = await ECDSA.new(); + }); + + context('recover with invalid signature', function () { + it('with short signature', async function () { + await expectRevert(this.ecdsa.$recover(TEST_MESSAGE, '0x1234'), 'ECDSA: invalid signature length'); + }); + + it('with long signature', async function () { + await expectRevert( + // eslint-disable-next-line max-len + this.ecdsa.$recover( + TEST_MESSAGE, + '0x01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789', + ), + 'ECDSA: invalid signature length', + ); + }); + }); + + context('recover with valid signature', function () { + context('using web3.eth.sign', function () { + it('returns signer address with correct signature', async function () { + // Create the signature + const signature = await web3.eth.sign(TEST_MESSAGE, other); + + // Recover the signer address from the generated message and signature. + expect(await this.ecdsa.$recover(toEthSignedMessageHash(TEST_MESSAGE), signature)).to.equal(other); + }); + + it('returns signer address with correct signature for arbitrary length message', async function () { + // Create the signature + const signature = await web3.eth.sign(NON_HASH_MESSAGE, other); + + // Recover the signer address from the generated message and signature. + expect(await this.ecdsa.$recover(toEthSignedMessageHash(NON_HASH_MESSAGE), signature)).to.equal(other); + }); + + it('returns a different address', async function () { + const signature = await web3.eth.sign(TEST_MESSAGE, other); + expect(await this.ecdsa.$recover(WRONG_MESSAGE, signature)).to.not.equal(other); + }); + + it('reverts with invalid signature', async function () { + // eslint-disable-next-line max-len + const signature = + '0x332ce75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e01c'; + await expectRevert(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature'); + }); + }); + + context('with v=27 signature', function () { + // Signature generated outside ganache with method web3.eth.sign(signer, message) + const signer = '0x2cc1166f6212628A0deEf2B33BEFB2187D35b86c'; + // eslint-disable-next-line max-len + const signatureWithoutV = + '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892'; + + it('works with correct v value', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '1c'; // 28 = 1c. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.not.equal(signer); + }); + + it('reverts wrong v values', async function () { + for (const v of ['00', '01']) { + const signature = signatureWithoutV + v; + await expectRevert(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature'); + + await expectRevert( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + 'ECDSA: invalid signature', + ); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + await expectRevert( + this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)), + 'ECDSA: invalid signature length', + ); + }); + }); + + context('with v=28 signature', function () { + const signer = '0x1E318623aB09Fe6de3C9b8672098464Aeda9100E'; + // eslint-disable-next-line max-len + const signatureWithoutV = + '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0'; + + it('works with correct v value', async function () { + const v = '1c'; // 28 = 1c. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.not.equal(signer); + }); + + it('reverts invalid v values', async function () { + for (const v of ['00', '01']) { + const signature = signatureWithoutV + v; + await expectRevert(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSA: invalid signature'); + + await expectRevert( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + 'ECDSA: invalid signature', + ); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '1c'; // 27 = 1b. + const signature = signatureWithoutV + v; + await expectRevert( + this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)), + 'ECDSA: invalid signature length', + ); + }); + }); + + it('reverts with high-s value signature', async function () { + const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'; + // eslint-disable-next-line max-len + const highSSignature = + '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b'; + await expectRevert(this.ecdsa.$recover(message, highSSignature), "ECDSA: invalid signature 's' value"); + await expectRevert( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(highSSignature)), + "ECDSA: invalid signature 's' value", + ); + expect(() => to2098Format(highSSignature)).to.throw("invalid signature 's' value"); + }); + }); + + context('toEthSignedMessageHash', function () { + it('prefixes bytes32 data correctly', async function () { + expect(await this.ecdsa.methods['$toEthSignedMessageHash(bytes32)'](TEST_MESSAGE)).to.equal( + toEthSignedMessageHash(TEST_MESSAGE), + ); + }); + + it('prefixes dynamic length data correctly', async function () { + expect(await this.ecdsa.methods['$toEthSignedMessageHash(bytes)'](NON_HASH_MESSAGE)).to.equal( + toEthSignedMessageHash(NON_HASH_MESSAGE), + ); + }); + }); + + 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)); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/EIP712.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/EIP712.test.js new file mode 100644 index 0000000..54a4e77 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/EIP712.test.js @@ -0,0 +1,103 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { getDomain, domainType, domainSeparator, hashTypedData } = require('../../helpers/eip712'); +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 shortName = 'A Name'; + const shortVersion = '1'; + + const longName = 'A'.repeat(40); + const longVersion = 'B'.repeat(40); + + const cases = [ + ['short', shortName, shortVersion], + ['long', longName, longVersion], + ]; + + 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); + + 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 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 () { + 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); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/MerkleProof.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/MerkleProof.test.js new file mode 100644 index 0000000..9ed10fd --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/MerkleProof.test.js @@ -0,0 +1,200 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MerkleTree } = require('merkletreejs'); +const keccak256 = require('keccak256'); + +const MerkleProof = artifacts.require('$MerkleProof'); + +contract('MerkleProof', function () { + beforeEach(async function () { + this.merkleProof = await MerkleProof.new(); + }); + + describe('verify', function () { + it('returns true for a valid Merkle proof', async function () { + const elements = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''); + const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true }); + + const root = merkleTree.getHexRoot(); + + const leaf = keccak256(elements[0]); + + const proof = merkleTree.getHexProof(leaf); + + expect(await this.merkleProof.$verify(proof, root, leaf)).to.equal(true); + expect(await this.merkleProof.$verifyCalldata(proof, root, leaf)).to.equal(true); + + // For demonstration, it is also possible to create valid proofs for certain 64-byte values *not* in elements: + const noSuchLeaf = keccak256( + Buffer.concat([keccak256(elements[0]), keccak256(elements[1])].sort(Buffer.compare)), + ); + expect(await this.merkleProof.$verify(proof.slice(1), root, noSuchLeaf)).to.equal(true); + expect(await this.merkleProof.$verifyCalldata(proof.slice(1), root, noSuchLeaf)).to.equal(true); + }); + + it('returns false for an invalid Merkle proof', async function () { + const correctElements = ['a', 'b', 'c']; + const correctMerkleTree = new MerkleTree(correctElements, keccak256, { hashLeaves: true, sortPairs: true }); + + const correctRoot = correctMerkleTree.getHexRoot(); + + const correctLeaf = keccak256(correctElements[0]); + + const badElements = ['d', 'e', 'f']; + const badMerkleTree = new MerkleTree(badElements); + + const badProof = badMerkleTree.getHexProof(badElements[0]); + + expect(await this.merkleProof.$verify(badProof, correctRoot, correctLeaf)).to.equal(false); + expect(await this.merkleProof.$verifyCalldata(badProof, correctRoot, correctLeaf)).to.equal(false); + }); + + it('returns false for a Merkle proof of invalid length', async function () { + const elements = ['a', 'b', 'c']; + const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true }); + + const root = merkleTree.getHexRoot(); + + const leaf = keccak256(elements[0]); + + const proof = merkleTree.getHexProof(leaf); + const badProof = proof.slice(0, proof.length - 5); + + expect(await this.merkleProof.$verify(badProof, root, leaf)).to.equal(false); + expect(await this.merkleProof.$verifyCalldata(badProof, root, leaf)).to.equal(false); + }); + }); + + describe('multiProofVerify', function () { + it('returns true for a valid Merkle multi proof', async function () { + const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const proofLeaves = ['b', 'f', 'd'].map(keccak256).sort(Buffer.compare); + const proof = merkleTree.getMultiProof(proofLeaves); + const proofFlags = merkleTree.getProofFlags(proofLeaves, proof); + + expect(await this.merkleProof.$multiProofVerify(proof, proofFlags, root, proofLeaves)).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata(proof, proofFlags, root, proofLeaves)).to.equal(true); + }); + + it('returns false for an invalid Merkle multi proof', async function () { + const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const badProofLeaves = ['g', 'h', 'i'].map(keccak256).sort(Buffer.compare); + const badMerkleTree = new MerkleTree(badProofLeaves); + const badProof = badMerkleTree.getMultiProof(badProofLeaves); + const badProofFlags = badMerkleTree.getProofFlags(badProofLeaves, badProof); + + expect(await this.merkleProof.$multiProofVerify(badProof, badProofFlags, root, badProofLeaves)).to.equal(false); + expect(await this.merkleProof.$multiProofVerifyCalldata(badProof, badProofFlags, root, badProofLeaves)).to.equal( + false, + ); + }); + + it('revert with invalid multi proof #1', async function () { + const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const badLeaf = keccak256('e'); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + + await expectRevert( + this.merkleProof.$multiProofVerify( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false], + root, + [leaves[0], badLeaf], // A, E + ), + 'MerkleProof: invalid multiproof', + ); + await expectRevert( + this.merkleProof.$multiProofVerifyCalldata( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false], + root, + [leaves[0], badLeaf], // A, E + ), + 'MerkleProof: invalid multiproof', + ); + }); + + it('revert with invalid multi proof #2', async function () { + const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const badLeaf = keccak256('e'); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + + await expectRevert( + this.merkleProof.$multiProofVerify( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false, false], + root, + [badLeaf, leaves[0]], // A, E + ), + 'reverted with panic code 0x32', + ); + + await expectRevert( + this.merkleProof.$multiProofVerifyCalldata( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false, false], + root, + [badLeaf, leaves[0]], // A, E + ), + 'reverted with panic code 0x32', + ); + }); + + it('limit case: works for tree containing a single leaf', async function () { + const leaves = ['a'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const proofLeaves = ['a'].map(keccak256).sort(Buffer.compare); + const proof = merkleTree.getMultiProof(proofLeaves); + const proofFlags = merkleTree.getProofFlags(proofLeaves, proof); + + expect(await this.merkleProof.$multiProofVerify(proof, proofFlags, root, proofLeaves)).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata(proof, proofFlags, root, proofLeaves)).to.equal(true); + }); + + it('limit case: can prove empty leaves', async function () { + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + expect(await this.merkleProof.$multiProofVerify([root], [], root, [])).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata([root], [], root, [])).to.equal(true); + }); + + it('reverts processing manipulated proofs with a zero-value node at depth 1', async function () { + // Create a merkle tree that contains a zero leaf at depth 1 + const leaves = [keccak256('real leaf'), Buffer.alloc(32, 0)]; + const merkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true }); + + const root = merkleTree.getRoot(); + + // Now we can pass any ** malicious ** fake leaves as valid! + const maliciousLeaves = ['some', 'malicious', 'leaves'].map(keccak256).sort(Buffer.compare); + const maliciousProof = [leaves[0], leaves[0]]; + const maliciousProofFlags = [true, true, false]; + + await expectRevert( + this.merkleProof.$multiProofVerify(maliciousProof, maliciousProofFlags, root, maliciousLeaves), + 'MerkleProof: invalid multiproof', + ); + + await expectRevert( + this.merkleProof.$multiProofVerifyCalldata(maliciousProof, maliciousProofFlags, root, maliciousLeaves), + 'MerkleProof: invalid multiproof', + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/SignatureChecker.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/SignatureChecker.test.js new file mode 100644 index 0000000..ba8b100 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/cryptography/SignatureChecker.test.js @@ -0,0 +1,87 @@ +const { toEthSignedMessageHash } = require('../../helpers/sign'); + +const { expect } = require('chai'); + +const SignatureChecker = artifacts.require('$SignatureChecker'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); +const ERC1271MaliciousMock = artifacts.require('ERC1271MaliciousMock'); + +const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin'); +const WRONG_MESSAGE = web3.utils.sha3('Nope'); + +contract('SignatureChecker (ERC1271)', function (accounts) { + const [signer, other] = accounts; + + before('deploying', async function () { + this.signaturechecker = await SignatureChecker.new(); + this.wallet = await ERC1271WalletMock.new(signer); + this.malicious = await ERC1271MaliciousMock.new(); + this.signature = await web3.eth.sign(TEST_MESSAGE, signer); + }); + + context('EOA account', function () { + it('with matching signer and signature', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(TEST_MESSAGE), this.signature), + ).to.equal(true); + }); + + it('with invalid signer', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(other, toEthSignedMessageHash(TEST_MESSAGE), this.signature), + ).to.equal(false); + }); + + it('with invalid signature', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(WRONG_MESSAGE), this.signature), + ).to.equal(false); + }); + }); + + context('ERC1271 wallet', function () { + 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[`$${signature}`]( + this.signaturechecker.address, + toEthSignedMessageHash(TEST_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[`$${signature}`]( + this.malicious.address, + toEthSignedMessageHash(TEST_MESSAGE), + this.signature, + ), + ).to.equal(false); + }); + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/ConditionalEscrow.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/ConditionalEscrow.test.js new file mode 100644 index 0000000..9e17a8b --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/ConditionalEscrow.test.js @@ -0,0 +1,37 @@ +const { ether, expectRevert } = require('@openzeppelin/test-helpers'); +const { shouldBehaveLikeEscrow } = require('./Escrow.behavior'); + +const ConditionalEscrowMock = artifacts.require('ConditionalEscrowMock'); + +contract('ConditionalEscrow', function (accounts) { + const [owner, payee, ...otherAccounts] = accounts; + + beforeEach(async function () { + this.escrow = await ConditionalEscrowMock.new({ from: owner }); + }); + + context('when withdrawal is allowed', function () { + beforeEach(async function () { + await Promise.all(otherAccounts.map(payee => this.escrow.setAllowed(payee, true))); + }); + + shouldBehaveLikeEscrow(owner, otherAccounts); + }); + + context('when withdrawal is disallowed', function () { + const amount = ether('23'); + + beforeEach(async function () { + await this.escrow.setAllowed(payee, false); + }); + + it('reverts on withdrawals', async function () { + await this.escrow.deposit(payee, { from: owner, value: amount }); + + await expectRevert( + this.escrow.withdraw(payee, { from: owner }), + 'ConditionalEscrow: payee is not allowed to withdraw', + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/Escrow.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/Escrow.behavior.js new file mode 100644 index 0000000..f2059ed --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/Escrow.behavior.js @@ -0,0 +1,90 @@ +const { balance, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +function shouldBehaveLikeEscrow(owner, [payee1, payee2]) { + const amount = ether('42'); + + describe('as an escrow', function () { + describe('deposits', function () { + it('can accept a single deposit', async function () { + await this.escrow.deposit(payee1, { from: owner, value: amount }); + + expect(await balance.current(this.escrow.address)).to.be.bignumber.equal(amount); + + expect(await this.escrow.depositsOf(payee1)).to.be.bignumber.equal(amount); + }); + + it('can accept an empty deposit', async function () { + await this.escrow.deposit(payee1, { from: owner, value: 0 }); + }); + + it('only the owner can deposit', async function () { + await expectRevert(this.escrow.deposit(payee1, { from: payee2 }), 'Ownable: caller is not the owner'); + }); + + it('emits a deposited event', async function () { + const receipt = await this.escrow.deposit(payee1, { from: owner, value: amount }); + expectEvent(receipt, 'Deposited', { + payee: payee1, + weiAmount: amount, + }); + }); + + it('can add multiple deposits on a single account', async function () { + await this.escrow.deposit(payee1, { from: owner, value: amount }); + await this.escrow.deposit(payee1, { from: owner, value: amount.muln(2) }); + + expect(await balance.current(this.escrow.address)).to.be.bignumber.equal(amount.muln(3)); + + expect(await this.escrow.depositsOf(payee1)).to.be.bignumber.equal(amount.muln(3)); + }); + + it('can track deposits to multiple accounts', async function () { + await this.escrow.deposit(payee1, { from: owner, value: amount }); + await this.escrow.deposit(payee2, { from: owner, value: amount.muln(2) }); + + expect(await balance.current(this.escrow.address)).to.be.bignumber.equal(amount.muln(3)); + + expect(await this.escrow.depositsOf(payee1)).to.be.bignumber.equal(amount); + + expect(await this.escrow.depositsOf(payee2)).to.be.bignumber.equal(amount.muln(2)); + }); + }); + + describe('withdrawals', async function () { + it('can withdraw payments', async function () { + const balanceTracker = await balance.tracker(payee1); + + await this.escrow.deposit(payee1, { from: owner, value: amount }); + await this.escrow.withdraw(payee1, { from: owner }); + + expect(await balanceTracker.delta()).to.be.bignumber.equal(amount); + + expect(await balance.current(this.escrow.address)).to.be.bignumber.equal('0'); + expect(await this.escrow.depositsOf(payee1)).to.be.bignumber.equal('0'); + }); + + it('can do an empty withdrawal', async function () { + await this.escrow.withdraw(payee1, { from: owner }); + }); + + it('only the owner can withdraw', async function () { + await expectRevert(this.escrow.withdraw(payee1, { from: payee1 }), 'Ownable: caller is not the owner'); + }); + + it('emits a withdrawn event', async function () { + await this.escrow.deposit(payee1, { from: owner, value: amount }); + const receipt = await this.escrow.withdraw(payee1, { from: owner }); + expectEvent(receipt, 'Withdrawn', { + payee: payee1, + weiAmount: amount, + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeEscrow, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/Escrow.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/Escrow.test.js new file mode 100644 index 0000000..4762790 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/Escrow.test.js @@ -0,0 +1,14 @@ +require('@openzeppelin/test-helpers'); +const { shouldBehaveLikeEscrow } = require('./Escrow.behavior'); + +const Escrow = artifacts.require('Escrow'); + +contract('Escrow', function (accounts) { + const [owner, ...otherAccounts] = accounts; + + beforeEach(async function () { + this.escrow = await Escrow.new({ from: owner }); + }); + + shouldBehaveLikeEscrow(owner, otherAccounts); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/RefundEscrow.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/RefundEscrow.test.js new file mode 100644 index 0000000..c5344db --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/escrow/RefundEscrow.test.js @@ -0,0 +1,143 @@ +const { balance, constants, ether, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const RefundEscrow = artifacts.require('RefundEscrow'); + +contract('RefundEscrow', function (accounts) { + const [owner, beneficiary, refundee1, refundee2] = accounts; + + const amount = ether('54'); + const refundees = [refundee1, refundee2]; + + it('requires a non-null beneficiary', async function () { + await expectRevert( + RefundEscrow.new(ZERO_ADDRESS, { from: owner }), + 'RefundEscrow: beneficiary is the zero address', + ); + }); + + context('once deployed', function () { + beforeEach(async function () { + this.escrow = await RefundEscrow.new(beneficiary, { from: owner }); + }); + + context('active state', function () { + it('has beneficiary and state', async function () { + expect(await this.escrow.beneficiary()).to.equal(beneficiary); + expect(await this.escrow.state()).to.be.bignumber.equal('0'); + }); + + it('accepts deposits', async function () { + await this.escrow.deposit(refundee1, { from: owner, value: amount }); + + expect(await this.escrow.depositsOf(refundee1)).to.be.bignumber.equal(amount); + }); + + it('does not refund refundees', async function () { + await this.escrow.deposit(refundee1, { from: owner, value: amount }); + await expectRevert(this.escrow.withdraw(refundee1), 'ConditionalEscrow: payee is not allowed to withdraw'); + }); + + it('does not allow beneficiary withdrawal', async function () { + await this.escrow.deposit(refundee1, { from: owner, value: amount }); + await expectRevert( + this.escrow.beneficiaryWithdraw(), + 'RefundEscrow: beneficiary can only withdraw while closed', + ); + }); + }); + + it('only the owner can enter closed state', async function () { + await expectRevert(this.escrow.close({ from: beneficiary }), 'Ownable: caller is not the owner'); + + const receipt = await this.escrow.close({ from: owner }); + expectEvent(receipt, 'RefundsClosed'); + }); + + context('closed state', function () { + beforeEach(async function () { + await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: owner, value: amount }))); + + await this.escrow.close({ from: owner }); + }); + + it('rejects deposits', async function () { + await expectRevert( + this.escrow.deposit(refundee1, { from: owner, value: amount }), + 'RefundEscrow: can only deposit while active', + ); + }); + + it('does not refund refundees', async function () { + await expectRevert(this.escrow.withdraw(refundee1), 'ConditionalEscrow: payee is not allowed to withdraw'); + }); + + it('allows beneficiary withdrawal', async function () { + const balanceTracker = await balance.tracker(beneficiary); + await this.escrow.beneficiaryWithdraw(); + expect(await balanceTracker.delta()).to.be.bignumber.equal(amount.muln(refundees.length)); + }); + + it('prevents entering the refund state', async function () { + await expectRevert( + this.escrow.enableRefunds({ from: owner }), + 'RefundEscrow: can only enable refunds while active', + ); + }); + + it('prevents re-entering the closed state', async function () { + await expectRevert(this.escrow.close({ from: owner }), 'RefundEscrow: can only close while active'); + }); + }); + + it('only the owner can enter refund state', async function () { + await expectRevert(this.escrow.enableRefunds({ from: beneficiary }), 'Ownable: caller is not the owner'); + + const receipt = await this.escrow.enableRefunds({ from: owner }); + expectEvent(receipt, 'RefundsEnabled'); + }); + + context('refund state', function () { + beforeEach(async function () { + await Promise.all(refundees.map(refundee => this.escrow.deposit(refundee, { from: owner, value: amount }))); + + await this.escrow.enableRefunds({ from: owner }); + }); + + it('rejects deposits', async function () { + await expectRevert( + this.escrow.deposit(refundee1, { from: owner, value: amount }), + 'RefundEscrow: can only deposit while active', + ); + }); + + it('refunds refundees', async function () { + for (const refundee of [refundee1, refundee2]) { + const balanceTracker = await balance.tracker(refundee); + await this.escrow.withdraw(refundee, { from: owner }); + expect(await balanceTracker.delta()).to.be.bignumber.equal(amount); + } + }); + + it('does not allow beneficiary withdrawal', async function () { + await expectRevert( + this.escrow.beneficiaryWithdraw(), + 'RefundEscrow: beneficiary can only withdraw while closed', + ); + }); + + it('prevents entering the closed state', async function () { + await expectRevert(this.escrow.close({ from: owner }), 'RefundEscrow: can only close while active'); + }); + + it('prevents re-entering the refund state', async function () { + await expectRevert( + this.escrow.enableRefunds({ from: owner }), + 'RefundEscrow: can only enable refunds while active', + ); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165.test.js new file mode 100644 index 0000000..6d531c1 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165.test.js @@ -0,0 +1,11 @@ +const { shouldSupportInterfaces } = require('./SupportsInterface.behavior'); + +const ERC165 = artifacts.require('$ERC165'); + +contract('ERC165', function () { + beforeEach(async function () { + this.mock = await ERC165.new(); + }); + + shouldSupportInterfaces(['ERC165']); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165Checker.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165Checker.test.js new file mode 100644 index 0000000..bb68428 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165Checker.test.js @@ -0,0 +1,302 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC165Checker = artifacts.require('$ERC165Checker'); +const ERC165Storage = artifacts.require('$ERC165Storage'); +const ERC165MissingData = artifacts.require('ERC165MissingData'); +const ERC165MaliciousData = artifacts.require('ERC165MaliciousData'); +const ERC165NotSupported = artifacts.require('ERC165NotSupported'); +const ERC165ReturnBombMock = artifacts.require('ERC165ReturnBombMock'); + +const DUMMY_ID = '0xdeadbeef'; +const DUMMY_ID_2 = '0xcafebabe'; +const DUMMY_ID_3 = '0xdecafbad'; +const DUMMY_UNSUPPORTED_ID = '0xbaddcafe'; +const DUMMY_UNSUPPORTED_ID_2 = '0xbaadcafe'; +const DUMMY_ACCOUNT = '0x1111111111111111111111111111111111111111'; + +contract('ERC165Checker', function () { + beforeEach(async function () { + this.mock = await ERC165Checker.new(); + }); + + context('ERC165 missing return data', function () { + beforeEach(async function () { + this.target = await ERC165MissingData.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 malicious return data', function () { + beforeEach(async function () { + this.target = await ERC165MaliciousData.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + }); + + context('ERC165 not supported', function () { + beforeEach(async function () { + this.target = await ERC165NotSupported.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 supported', function () { + beforeEach(async function () { + this.target = await ERC165Storage.new(); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 and single interface supported', function () { + beforeEach(async function () { + this.target = await ERC165Storage.new(); + await this.target.$_registerInterface(DUMMY_ID); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('supports mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + + it('supports mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(true); + }); + + it('supports mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(true); + }); + + it('supports mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + }); + + context('ERC165 and many interfaces supported', function () { + beforeEach(async function () { + this.supportedInterfaces = [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3]; + this.target = await ERC165Storage.new(); + await Promise.all(this.supportedInterfaces.map(interfaceId => this.target.$_registerInterface(interfaceId))); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('supports each interfaceId via supportsInterface', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.$supportsInterface(this.target.address, interfaceId); + expect(supported).to.equal(true); + } + }); + + it('supports all interfaceIds via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, this.supportedInterfaces); + expect(supported).to.equal(true); + }); + + it('supports none of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + const supported = await this.mock.$supportsAllInterfaces(this.target.address, interfaceIdsToTest); + expect(supported).to.equal(false); + }); + + it('supports not all of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + const supported = await this.mock.$supportsAllInterfaces(this.target.address, interfaceIdsToTest); + expect(supported).to.equal(false); + }); + + it('supports all interfaceIds via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, this.supportedInterfaces); + expect(supported.length).to.equal(3); + expect(supported[0]).to.equal(true); + expect(supported[1]).to.equal(true); + expect(supported[2]).to.equal(true); + }); + + it('supports none of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + const supported = await this.mock.$getSupportedInterfaces(this.target.address, interfaceIdsToTest); + expect(supported.length).to.equal(2); + expect(supported[0]).to.equal(false); + expect(supported[1]).to.equal(false); + }); + + it('supports not all of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + const supported = await this.mock.$getSupportedInterfaces(this.target.address, interfaceIdsToTest); + expect(supported.length).to.equal(4); + expect(supported[0]).to.equal(true); + expect(supported[1]).to.equal(true); + expect(supported[2]).to.equal(true); + expect(supported[3]).to.equal(false); + }); + + it('supports each interfaceId via supportsERC165InterfaceUnchecked', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, interfaceId); + expect(supported).to.equal(true); + } + }); + }); + + context('account address does not support ERC165', function () { + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(DUMMY_ACCOUNT); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + it('Return bomb resistance', async function () { + this.target = await ERC165ReturnBombMock.new(); + + const tx1 = await this.mock.$supportsInterface.sendTransaction(this.target.address, DUMMY_ID); + expect(tx1.receipt.gasUsed).to.be.lessThan(120000); // 3*30k + 21k + some margin + + const tx2 = await this.mock.$getSupportedInterfaces.sendTransaction(this.target.address, [ + DUMMY_ID, + DUMMY_ID_2, + DUMMY_ID_3, + DUMMY_UNSUPPORTED_ID, + DUMMY_UNSUPPORTED_ID_2, + ]); + expect(tx2.receipt.gasUsed).to.be.lessThan(250000); // (2+5)*30k + 21k + some margin + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165Storage.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165Storage.test.js new file mode 100644 index 0000000..c78caf8 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC165Storage.test.js @@ -0,0 +1,23 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { shouldSupportInterfaces } = require('./SupportsInterface.behavior'); + +const ERC165Storage = artifacts.require('$ERC165Storage'); + +contract('ERC165Storage', function () { + beforeEach(async function () { + this.mock = await ERC165Storage.new(); + }); + + it('register interface', async function () { + expect(await this.mock.supportsInterface('0x00000001')).to.be.equal(false); + await this.mock.$_registerInterface('0x00000001'); + expect(await this.mock.supportsInterface('0x00000001')).to.be.equal(true); + }); + + it('does not allow 0xffffffff', async function () { + await expectRevert(this.mock.$_registerInterface('0xffffffff'), 'ERC165: invalid interface id'); + }); + + shouldSupportInterfaces(['ERC165']); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC1820Implementer.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC1820Implementer.test.js new file mode 100644 index 0000000..83d0a65 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/ERC1820Implementer.test.js @@ -0,0 +1,71 @@ +const { expectRevert, singletons } = require('@openzeppelin/test-helpers'); +const { bufferToHex, keccakFromString } = require('ethereumjs-util'); + +const { expect } = require('chai'); + +const ERC1820Implementer = artifacts.require('$ERC1820Implementer'); + +contract('ERC1820Implementer', function (accounts) { + const [registryFunder, implementee, other] = accounts; + + const ERC1820_ACCEPT_MAGIC = bufferToHex(keccakFromString('ERC1820_ACCEPT_MAGIC')); + + beforeEach(async function () { + this.implementer = await ERC1820Implementer.new(); + this.registry = await singletons.ERC1820Registry(registryFunder); + + this.interfaceA = bufferToHex(keccakFromString('interfaceA')); + this.interfaceB = bufferToHex(keccakFromString('interfaceB')); + }); + + context('with no registered interfaces', function () { + it('returns false when interface implementation is queried', async function () { + expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, implementee)).to.not.equal( + ERC1820_ACCEPT_MAGIC, + ); + }); + + it('reverts when attempting to set as implementer in the registry', async function () { + await expectRevert( + this.registry.setInterfaceImplementer(implementee, this.interfaceA, this.implementer.address, { + from: implementee, + }), + 'Does not implement the interface', + ); + }); + }); + + context('with registered interfaces', function () { + beforeEach(async function () { + await this.implementer.$_registerInterfaceForAddress(this.interfaceA, implementee); + }); + + it('returns true when interface implementation is queried', async function () { + expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, implementee)).to.equal( + ERC1820_ACCEPT_MAGIC, + ); + }); + + it('returns false when interface implementation for non-supported interfaces is queried', async function () { + expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceB, implementee)).to.not.equal( + ERC1820_ACCEPT_MAGIC, + ); + }); + + it('returns false when interface implementation for non-supported addresses is queried', async function () { + expect(await this.implementer.canImplementInterfaceForAddress(this.interfaceA, other)).to.not.equal( + ERC1820_ACCEPT_MAGIC, + ); + }); + + it('can be set as an implementer for supported interfaces in the registry', async function () { + await this.registry.setInterfaceImplementer(implementee, this.interfaceA, this.implementer.address, { + from: implementee, + }); + + expect(await this.registry.getInterfaceImplementer(implementee, this.interfaceA)).to.equal( + this.implementer.address, + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/SupportsInterface.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/SupportsInterface.behavior.js new file mode 100644 index 0000000..201a55f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/introspection/SupportsInterface.behavior.js @@ -0,0 +1,146 @@ +const { makeInterfaceId } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const INTERFACES = { + ERC165: ['supportsInterface(bytes4)'], + ERC721: [ + 'balanceOf(address)', + 'ownerOf(uint256)', + 'approve(address,uint256)', + 'getApproved(uint256)', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'transferFrom(address,address,uint256)', + 'safeTransferFrom(address,address,uint256)', + 'safeTransferFrom(address,address,uint256,bytes)', + ], + ERC721Enumerable: ['totalSupply()', 'tokenOfOwnerByIndex(address,uint256)', 'tokenByIndex(uint256)'], + ERC721Metadata: ['name()', 'symbol()', 'tokenURI(uint256)'], + ERC1155: [ + 'balanceOf(address,uint256)', + 'balanceOfBatch(address[],uint256[])', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'safeTransferFrom(address,address,uint256,uint256,bytes)', + 'safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)', + ], + ERC1155Receiver: [ + 'onERC1155Received(address,address,uint256,uint256,bytes)', + 'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)', + ], + AccessControl: [ + 'hasRole(bytes32,address)', + 'getRoleAdmin(bytes32)', + 'grantRole(bytes32,address)', + 'revokeRole(bytes32,address)', + 'renounceRole(bytes32,address)', + ], + AccessControlEnumerable: ['getRoleMember(bytes32,uint256)', 'getRoleMemberCount(bytes32)'], + AccessControlDefaultAdminRules: [ + 'defaultAdminDelay()', + 'pendingDefaultAdminDelay()', + 'defaultAdmin()', + 'pendingDefaultAdmin()', + 'defaultAdminDelayIncreaseWait()', + 'changeDefaultAdminDelay(uint48)', + 'rollbackDefaultAdminDelay()', + 'beginDefaultAdminTransfer(address)', + 'acceptDefaultAdminTransfer()', + 'cancelDefaultAdminTransfer()', + ], + Governor: [ + 'name()', + 'version()', + 'COUNTING_MODE()', + 'hashProposal(address[],uint256[],bytes[],bytes32)', + 'state(uint256)', + 'proposalSnapshot(uint256)', + 'proposalDeadline(uint256)', + 'votingDelay()', + 'votingPeriod()', + 'quorum(uint256)', + 'getVotes(address,uint256)', + 'hasVoted(uint256,address)', + 'propose(address[],uint256[],bytes[],string)', + 'execute(address[],uint256[],bytes[],bytes32)', + 'castVote(uint256,uint8)', + 'castVoteWithReason(uint256,uint8,string)', + 'castVoteBySig(uint256,uint8,uint8,bytes32,bytes32)', + ], + GovernorWithParams: [ + 'name()', + 'version()', + 'COUNTING_MODE()', + 'hashProposal(address[],uint256[],bytes[],bytes32)', + 'state(uint256)', + 'proposalSnapshot(uint256)', + 'proposalDeadline(uint256)', + 'votingDelay()', + 'votingPeriod()', + 'quorum(uint256)', + 'getVotes(address,uint256)', + 'getVotesWithParams(address,uint256,bytes)', + 'hasVoted(uint256,address)', + 'propose(address[],uint256[],bytes[],string)', + 'execute(address[],uint256[],bytes[],bytes32)', + 'castVote(uint256,uint8)', + 'castVoteWithReason(uint256,uint8,string)', + 'castVoteWithReasonAndParams(uint256,uint8,string,bytes)', + '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)'], +}; + +const INTERFACE_IDS = {}; +const FN_SIGNATURES = {}; +for (const k of Object.getOwnPropertyNames(INTERFACES)) { + INTERFACE_IDS[k] = makeInterfaceId.ERC165(INTERFACES[k]); + for (const fnName of INTERFACES[k]) { + // the interface id of a single function is equivalent to its function signature + FN_SIGNATURES[fnName] = makeInterfaceId.ERC165([fnName]); + } +} + +function shouldSupportInterfaces(interfaces = []) { + describe('ERC165', function () { + beforeEach(function () { + this.contractUnderTest = this.mock || this.token || this.holder || this.accessControl; + }); + + it('supportsInterface uses less than 30k gas', async function () { + for (const k of interfaces) { + 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] ?? k; + expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true, `does not support ${k}`); + } + }); + + 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, + `did not find ${fnName}`, + ); + } + } + }); + }); +} + +module.exports = { + shouldSupportInterfaces, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/math/Math.t.sol b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/Math.t.sol new file mode 100644 index 0000000..916136c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/Math.t.sol @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +import "../../../contracts/utils/math/Math.sol"; +import "../../../contracts/utils/math/SafeMath.sol"; + +contract MathTest is Test { + // CEILDIV + function testCeilDiv(uint256 a, uint256 b) public { + vm.assume(b > 0); + + uint256 result = Math.ceilDiv(a, b); + + if (result == 0) { + assertEq(a, 0); + } else { + uint256 maxdiv = UINT256_MAX / b; + bool overflow = maxdiv * b < a; + assertTrue(a > b * (result - 1)); + assertTrue(overflow ? result == maxdiv + 1 : a <= b * result); + } + } + + // SQRT + function testSqrt(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.sqrt(input, rounding); + + // square of result is bigger than input + if (_squareBigger(result, input)) { + assertTrue(rounding == Math.Rounding.Up); + assertTrue(_squareSmaller(result - 1, input)); + } + // square of result is smaller than input + else if (_squareSmaller(result, input)) { + assertFalse(rounding == Math.Rounding.Up); + assertTrue(_squareBigger(result + 1, input)); + } + // input is perfect square + else { + assertEq(result * result, input); + } + } + + function _squareBigger(uint256 value, uint256 ref) private pure returns (bool) { + (bool noOverflow, uint256 square) = SafeMath.tryMul(value, value); + return !noOverflow || square > ref; + } + + function _squareSmaller(uint256 value, uint256 ref) private pure returns (bool) { + return value * value < ref; + } + + // LOG2 + function testLog2(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log2(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf2Bigger(result, input)) { + assertTrue(rounding == Math.Rounding.Up); + assertTrue(_powerOf2Smaller(result - 1, input)); + } else if (_powerOf2Smaller(result, input)) { + assertFalse(rounding == Math.Rounding.Up); + assertTrue(_powerOf2Bigger(result + 1, input)); + } else { + assertEq(2 ** result, input); + } + } + + function _powerOf2Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 256 || 2 ** value > ref; // 2**256 overflows uint256 + } + + function _powerOf2Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 2 ** value < ref; + } + + // LOG10 + function testLog10(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log10(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf10Bigger(result, input)) { + assertTrue(rounding == Math.Rounding.Up); + assertTrue(_powerOf10Smaller(result - 1, input)); + } else if (_powerOf10Smaller(result, input)) { + assertFalse(rounding == Math.Rounding.Up); + assertTrue(_powerOf10Bigger(result + 1, input)); + } else { + assertEq(10 ** result, input); + } + } + + function _powerOf10Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 78 || 10 ** value > ref; // 10**78 overflows uint256 + } + + function _powerOf10Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 10 ** value < ref; + } + + // LOG256 + function testLog256(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log256(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf256Bigger(result, input)) { + assertTrue(rounding == Math.Rounding.Up); + assertTrue(_powerOf256Smaller(result - 1, input)); + } else if (_powerOf256Smaller(result, input)) { + assertFalse(rounding == Math.Rounding.Up); + assertTrue(_powerOf256Bigger(result + 1, input)); + } else { + assertEq(256 ** result, input); + } + } + + function _powerOf256Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 32 || 256 ** value > ref; // 256**32 overflows uint256 + } + + function _powerOf256Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 256 ** value < ref; + } + + // MULDIV + function testMulDiv(uint256 x, uint256 y, uint256 d) public { + // Full precision for x * y + (uint256 xyHi, uint256 xyLo) = _mulHighLow(x, y); + + // Assume result won't overflow (see {testMulDivDomain}) + // This also checks that `d` is positive + vm.assume(xyHi < d); + + // Perform muldiv + uint256 q = Math.mulDiv(x, y, d); + + // Full precision for q * d + (uint256 qdHi, uint256 qdLo) = _mulHighLow(q, d); + // Add remainder of x * y / d (computed as rem = (x * y % d)) + (uint256 qdRemLo, uint256 c) = _addCarry(qdLo, _mulmod(x, y, d)); + uint256 qdRemHi = qdHi + c; + + // Full precision check that x * y = q * d + rem + assertEq(xyHi, qdRemHi); + assertEq(xyLo, qdRemLo); + } + + function testMulDivDomain(uint256 x, uint256 y, uint256 d) public { + (uint256 xyHi, ) = _mulHighLow(x, y); + + // Violate {testMulDiv} assumption (covers d is 0 and result overflow) + vm.assume(xyHi >= d); + + // we are outside the scope of {testMulDiv}, we expect muldiv to revert + try this.muldiv(x, y, d) returns (uint256) { + fail(); + } catch {} + } + + // External call + function muldiv(uint256 x, uint256 y, uint256 d) external pure returns (uint256) { + return Math.mulDiv(x, y, d); + } + + // Helpers + function _asRounding(uint8 r) private pure returns (Math.Rounding) { + vm.assume(r < uint8(type(Math.Rounding).max)); + return Math.Rounding(r); + } + + function _mulmod(uint256 x, uint256 y, uint256 z) private pure returns (uint256 r) { + assembly { + r := mulmod(x, y, z) + } + } + + function _mulHighLow(uint256 x, uint256 y) private pure returns (uint256 high, uint256 low) { + (uint256 x0, uint256 x1) = (x & type(uint128).max, x >> 128); + (uint256 y0, uint256 y1) = (y & type(uint128).max, y >> 128); + + // Karatsuba algorithm + // https://en.wikipedia.org/wiki/Karatsuba_algorithm + uint256 z2 = x1 * y1; + uint256 z1a = x1 * y0; + uint256 z1b = x0 * y1; + uint256 z0 = x0 * y0; + + uint256 carry = ((z1a & type(uint128).max) + (z1b & type(uint128).max) + (z0 >> 128)) >> 128; + + high = z2 + (z1a >> 128) + (z1b >> 128) + carry; + + unchecked { + low = x * y; + } + } + + function _addCarry(uint256 x, uint256 y) private pure returns (uint256 res, uint256 carry) { + unchecked { + res = x + y; + } + carry = res < x ? 1 : 0; + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/math/Math.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/Math.test.js new file mode 100644 index 0000000..6b97a64 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/Math.test.js @@ -0,0 +1,289 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256 } = constants; +const { Rounding } = require('../../helpers/enums.js'); + +const Math = artifacts.require('$Math'); + +contract('Math', function () { + const min = new BN('1234'); + const max = new BN('5678'); + const MAX_UINT256_SUB1 = MAX_UINT256.sub(new BN('1')); + const MAX_UINT256_SUB2 = MAX_UINT256.sub(new BN('2')); + + beforeEach(async function () { + this.math = await Math.new(); + }); + + describe('max', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$max(max, min)).to.be.bignumber.equal(max); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$max(min, max)).to.be.bignumber.equal(max); + }); + }); + + describe('min', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$min(min, max)).to.be.bignumber.equal(min); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$min(max, min)).to.be.bignumber.equal(min); + }); + }); + + describe('average', function () { + function bnAverage(a, b) { + return a.add(b).divn(2); + } + + it('is correctly calculated with two odd numbers', async function () { + const a = new BN('57417'); + const b = new BN('95431'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with two even numbers', async function () { + const a = new BN('42304'); + const b = new BN('84346'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with one even and one odd number', async function () { + const a = new BN('57417'); + const b = new BN('84346'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with two max uint256 numbers', async function () { + const a = MAX_UINT256; + expect(await this.math.$average(a, a)).to.be.bignumber.equal(bnAverage(a, a)); + }); + }); + + describe('ceilDiv', function () { + it('does not round up on exact division', async function () { + const a = new BN('10'); + const b = new BN('5'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('2'); + }); + + it('rounds up on division with remainders', async function () { + const a = new BN('42'); + const b = new BN('13'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('4'); + }); + + it('does not overflow', async function () { + const b = new BN('2'); + const result = new BN('1').shln(255); + expect(await this.math.$ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(result); + }); + + it('correctly computes max uint256 divided by 1', async function () { + const b = new BN('1'); + expect(await this.math.$ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(MAX_UINT256); + }); + }); + + describe('muldiv', function () { + it('divide by 0', async function () { + await expectRevert.unspecified(this.math.$mulDiv(1, 1, 0, Rounding.Down)); + }); + + describe('does round down', async function () { + it('small values', async function () { + expect(await this.math.$mulDiv('3', '4', '5', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$mulDiv('3', '5', '5', Rounding.Down)).to.be.bignumber.equal('3'); + }); + + it('large values', async function () { + expect( + await this.math.$mulDiv(new BN('42'), MAX_UINT256_SUB1, MAX_UINT256, Rounding.Down), + ).to.be.bignumber.equal(new BN('41')); + + expect(await this.math.$mulDiv(new BN('17'), MAX_UINT256, MAX_UINT256, Rounding.Down)).to.be.bignumber.equal( + new BN('17'), + ); + + expect( + await this.math.$mulDiv(MAX_UINT256_SUB1, MAX_UINT256_SUB1, MAX_UINT256, Rounding.Down), + ).to.be.bignumber.equal(MAX_UINT256_SUB2); + + expect( + await this.math.$mulDiv(MAX_UINT256, MAX_UINT256_SUB1, MAX_UINT256, Rounding.Down), + ).to.be.bignumber.equal(MAX_UINT256_SUB1); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256, MAX_UINT256, Rounding.Down)).to.be.bignumber.equal( + MAX_UINT256, + ); + }); + }); + + describe('does round up', async function () { + it('small values', async function () { + expect(await this.math.$mulDiv('3', '4', '5', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$mulDiv('3', '5', '5', Rounding.Up)).to.be.bignumber.equal('3'); + }); + + it('large values', async function () { + expect(await this.math.$mulDiv(new BN('42'), MAX_UINT256_SUB1, MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + new BN('42'), + ); + + expect(await this.math.$mulDiv(new BN('17'), MAX_UINT256, MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + new BN('17'), + ); + + expect( + await this.math.$mulDiv(MAX_UINT256_SUB1, MAX_UINT256_SUB1, MAX_UINT256, Rounding.Up), + ).to.be.bignumber.equal(MAX_UINT256_SUB1); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256_SUB1, MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + MAX_UINT256_SUB1, + ); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256, MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + MAX_UINT256, + ); + }); + }); + }); + + describe('sqrt', function () { + it('rounds down', async function () { + expect(await this.math.$sqrt('0', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$sqrt('1', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('2', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('3', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('4', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('144', Rounding.Down)).to.be.bignumber.equal('12'); + expect(await this.math.$sqrt('999999', Rounding.Down)).to.be.bignumber.equal('999'); + expect(await this.math.$sqrt('1000000', Rounding.Down)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000001', Rounding.Down)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1002000', Rounding.Down)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1002001', Rounding.Down)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt(MAX_UINT256, Rounding.Down)).to.be.bignumber.equal( + '340282366920938463463374607431768211455', + ); + }); + + it('rounds up', async function () { + expect(await this.math.$sqrt('0', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$sqrt('1', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('2', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('3', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('4', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('144', Rounding.Up)).to.be.bignumber.equal('12'); + expect(await this.math.$sqrt('999999', Rounding.Up)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000000', Rounding.Up)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000001', Rounding.Up)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt('1002000', Rounding.Up)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt('1002001', Rounding.Up)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt(MAX_UINT256, Rounding.Up)).to.be.bignumber.equal( + '340282366920938463463374607431768211456', + ); + }); + }); + + describe('log', function () { + describe('log2', function () { + it('rounds down', async function () { + // For some reason calling .$log2() directly fails + expect(await this.math.methods['$log2(uint256,uint8)']('0', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('1', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('2', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('3', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('4', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('5', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('6', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('7', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('8', Rounding.Down)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('9', Rounding.Down)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)'](MAX_UINT256, Rounding.Down)).to.be.bignumber.equal( + '255', + ); + }); + + it('rounds up', async function () { + // For some reason calling .$log2() directly fails + expect(await this.math.methods['$log2(uint256,uint8)']('0', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('1', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('2', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('3', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('4', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('5', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('6', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('7', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('8', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('9', Rounding.Up)).to.be.bignumber.equal('4'); + expect(await this.math.methods['$log2(uint256,uint8)'](MAX_UINT256, Rounding.Up)).to.be.bignumber.equal('256'); + }); + }); + + describe('log10', function () { + it('rounds down', async function () { + expect(await this.math.$log10('0', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('1', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('2', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('9', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('10', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('11', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('99', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('100', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('101', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('999', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('1000', Rounding.Down)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1001', Rounding.Down)).to.be.bignumber.equal('3'); + expect(await this.math.$log10(MAX_UINT256, Rounding.Down)).to.be.bignumber.equal('77'); + }); + + it('rounds up', async function () { + expect(await this.math.$log10('0', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('1', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('2', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('9', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('10', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('11', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('99', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('100', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('101', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('999', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1000', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1001', Rounding.Up)).to.be.bignumber.equal('4'); + expect(await this.math.$log10(MAX_UINT256, Rounding.Up)).to.be.bignumber.equal('78'); + }); + }); + + describe('log256', function () { + it('rounds down', async function () { + expect(await this.math.$log256('0', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('1', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('2', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('255', Rounding.Down)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('256', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('257', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('65535', Rounding.Down)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('65536', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65537', Rounding.Down)).to.be.bignumber.equal('2'); + expect(await this.math.$log256(MAX_UINT256, Rounding.Down)).to.be.bignumber.equal('31'); + }); + + it('rounds up', async function () { + expect(await this.math.$log256('0', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('1', Rounding.Up)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('2', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('255', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('256', Rounding.Up)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('257', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65535', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65536', Rounding.Up)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65537', Rounding.Up)).to.be.bignumber.equal('3'); + expect(await this.math.$log256(MAX_UINT256, Rounding.Up)).to.be.bignumber.equal('32'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SafeCast.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SafeCast.test.js new file mode 100644 index 0000000..63223f5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SafeCast.test.js @@ -0,0 +1,152 @@ +const { BN, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { range } = require('../../../scripts/helpers'); + +const SafeCast = artifacts.require('$SafeCast'); + +contract('SafeCast', async function () { + beforeEach(async function () { + this.safeCast = await SafeCast.new(); + }); + + function testToUint(bits) { + describe(`toUint${bits}`, () => { + const maxValue = new BN('2').pow(new BN(bits)).subn(1); + + it('downcasts 0', async function () { + expect(await this.safeCast[`$toUint${bits}`](0)).to.be.bignumber.equal('0'); + }); + + it('downcasts 1', async function () { + expect(await this.safeCast[`$toUint${bits}`](1)).to.be.bignumber.equal('1'); + }); + + it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () { + expect(await this.safeCast[`$toUint${bits}`](maxValue)).to.be.bignumber.equal(maxValue); + }); + + it(`reverts when downcasting 2^${bits} (${maxValue.addn(1)})`, async function () { + await expectRevert( + this.safeCast[`$toUint${bits}`](maxValue.addn(1)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + + it(`reverts when downcasting 2^${bits} + 1 (${maxValue.addn(2)})`, async function () { + await expectRevert( + this.safeCast[`$toUint${bits}`](maxValue.addn(2)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + }); + } + + range(8, 256, 8).forEach(bits => testToUint(bits)); + + describe('toUint256', () => { + const maxInt256 = new BN('2').pow(new BN(255)).subn(1); + const minInt256 = new BN('2').pow(new BN(255)).neg(); + + it('casts 0', async function () { + expect(await this.safeCast.$toUint256(0)).to.be.bignumber.equal('0'); + }); + + it('casts 1', async function () { + expect(await this.safeCast.$toUint256(1)).to.be.bignumber.equal('1'); + }); + + it(`casts INT256_MAX (${maxInt256})`, async function () { + expect(await this.safeCast.$toUint256(maxInt256)).to.be.bignumber.equal(maxInt256); + }); + + it('reverts when casting -1', async function () { + await expectRevert(this.safeCast.$toUint256(-1), 'SafeCast: value must be positive'); + }); + + it(`reverts when casting INT256_MIN (${minInt256})`, async function () { + await expectRevert(this.safeCast.$toUint256(minInt256), 'SafeCast: value must be positive'); + }); + }); + + function testToInt(bits) { + describe(`toInt${bits}`, () => { + const minValue = new BN('-2').pow(new BN(bits - 1)); + const maxValue = new BN('2').pow(new BN(bits - 1)).subn(1); + + it('downcasts 0', async function () { + expect(await this.safeCast[`$toInt${bits}`](0)).to.be.bignumber.equal('0'); + }); + + it('downcasts 1', async function () { + expect(await this.safeCast[`$toInt${bits}`](1)).to.be.bignumber.equal('1'); + }); + + it('downcasts -1', async function () { + expect(await this.safeCast[`$toInt${bits}`](-1)).to.be.bignumber.equal('-1'); + }); + + it(`downcasts -2^${bits - 1} (${minValue})`, async function () { + expect(await this.safeCast[`$toInt${bits}`](minValue)).to.be.bignumber.equal(minValue); + }); + + it(`downcasts 2^${bits - 1} - 1 (${maxValue})`, async function () { + expect(await this.safeCast[`$toInt${bits}`](maxValue)).to.be.bignumber.equal(maxValue); + }); + + it(`reverts when downcasting -2^${bits - 1} - 1 (${minValue.subn(1)})`, async function () { + await expectRevert( + this.safeCast[`$toInt${bits}`](minValue.subn(1)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + + it(`reverts when downcasting -2^${bits - 1} - 2 (${minValue.subn(2)})`, async function () { + await expectRevert( + this.safeCast[`$toInt${bits}`](minValue.subn(2)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + + it(`reverts when downcasting 2^${bits - 1} (${maxValue.addn(1)})`, async function () { + await expectRevert( + this.safeCast[`$toInt${bits}`](maxValue.addn(1)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + + it(`reverts when downcasting 2^${bits - 1} + 1 (${maxValue.addn(2)})`, async function () { + await expectRevert( + this.safeCast[`$toInt${bits}`](maxValue.addn(2)), + `SafeCast: value doesn't fit in ${bits} bits`, + ); + }); + }); + } + + range(8, 256, 8).forEach(bits => testToInt(bits)); + + describe('toInt256', () => { + const maxUint256 = new BN('2').pow(new BN(256)).subn(1); + const maxInt256 = new BN('2').pow(new BN(255)).subn(1); + + it('casts 0', async function () { + expect(await this.safeCast.$toInt256(0)).to.be.bignumber.equal('0'); + }); + + it('casts 1', async function () { + expect(await this.safeCast.$toInt256(1)).to.be.bignumber.equal('1'); + }); + + it(`casts INT256_MAX (${maxInt256})`, async function () { + expect(await this.safeCast.$toInt256(maxInt256)).to.be.bignumber.equal(maxInt256); + }); + + it(`reverts when casting INT256_MAX + 1 (${maxInt256.addn(1)})`, async function () { + await expectRevert(this.safeCast.$toInt256(maxInt256.addn(1)), "SafeCast: value doesn't fit in an int256"); + }); + + it(`reverts when casting UINT256_MAX (${maxUint256})`, async function () { + await expectRevert(this.safeCast.$toInt256(maxUint256), "SafeCast: value doesn't fit in an int256"); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SafeMath.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SafeMath.test.js new file mode 100644 index 0000000..9598ac5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SafeMath.test.js @@ -0,0 +1,433 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { MAX_UINT256 } = constants; + +const { expect } = require('chai'); + +const SafeMath = artifacts.require('$SafeMath'); +const SafeMathMemoryCheck = artifacts.require('$SafeMathMemoryCheck'); + +function expectStruct(value, expected) { + for (const key in expected) { + if (BN.isBN(value[key])) { + expect(value[key]).to.be.bignumber.equal(expected[key]); + } else { + expect(value[key]).to.be.equal(expected[key]); + } + } +} + +contract('SafeMath', function () { + beforeEach(async function () { + this.safeMath = await SafeMath.new(); + }); + + async function testCommutative(fn, lhs, rhs, expected, ...extra) { + expect(await fn(lhs, rhs, ...extra)).to.be.bignumber.equal(expected); + expect(await fn(rhs, lhs, ...extra)).to.be.bignumber.equal(expected); + } + + async function testFailsCommutative(fn, lhs, rhs, reason, ...extra) { + if (reason === undefined) { + await expectRevert.unspecified(fn(lhs, rhs, ...extra)); + await expectRevert.unspecified(fn(rhs, lhs, ...extra)); + } else { + await expectRevert(fn(lhs, rhs, ...extra), reason); + await expectRevert(fn(rhs, lhs, ...extra), reason); + } + } + + async function testCommutativeIterable(fn, lhs, rhs, expected, ...extra) { + expectStruct(await fn(lhs, rhs, ...extra), expected); + expectStruct(await fn(rhs, lhs, ...extra), expected); + } + + describe('with flag', function () { + describe('add', function () { + it('adds correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + testCommutativeIterable(this.safeMath.$tryAdd, a, b, [true, a.add(b)]); + }); + + it('reverts on addition overflow', async function () { + const a = MAX_UINT256; + const b = new BN('1'); + + testCommutativeIterable(this.safeMath.$tryAdd, a, b, [false, '0']); + }); + }); + + describe('sub', function () { + it('subtracts correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + expectStruct(await this.safeMath.$trySub(a, b), [true, a.sub(b)]); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$trySub(a, b), [false, '0']); + }); + }); + + describe('mul', function () { + it('multiplies correctly', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + testCommutativeIterable(this.safeMath.$tryMul, a, b, [true, a.mul(b)]); + }); + + it('multiplies by zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + testCommutativeIterable(this.safeMath.$tryMul, a, b, [true, a.mul(b)]); + }); + + it('reverts on multiplication overflow', async function () { + const a = MAX_UINT256; + const b = new BN('2'); + + testCommutativeIterable(this.safeMath.$tryMul, a, b, [false, '0']); + }); + }); + + describe('div', function () { + it('divides correctly', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('reverts on division by zero', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + expectStruct(await this.safeMath.$tryDiv(a, b), [false, '0']); + }); + }); + + describe('mod', function () { + describe('modulos correctly', async function () { + it('when the dividend is smaller than the divisor', async function () { + const a = new BN('284'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = new BN('17034'); // 17034 == 5678 * 3 + const b = new BN('5678'); + + expectStruct(await this.safeMath.$tryMod(a, b), [true, a.mod(b)]); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + expectStruct(await this.safeMath.$tryMod(a, b), [false, '0']); + }); + }); + }); + + describe('with default revert message', function () { + describe('add', function () { + it('adds correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + await testCommutative(this.safeMath.$add, a, b, a.add(b)); + }); + + it('reverts on addition overflow', async function () { + const a = MAX_UINT256; + const b = new BN('1'); + + await testFailsCommutative(this.safeMath.$add, a, b, undefined); + }); + }); + + describe('sub', function () { + it('subtracts correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + expect(await this.safeMath.$sub(a, b)).to.be.bignumber.equal(a.sub(b)); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await expectRevert.unspecified(this.safeMath.$sub(a, b)); + }); + }); + + describe('mul', function () { + it('multiplies correctly', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await testCommutative(this.safeMath.$mul, a, b, a.mul(b)); + }); + + it('multiplies by zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + await testCommutative(this.safeMath.$mul, a, b, '0'); + }); + + it('reverts on multiplication overflow', async function () { + const a = MAX_UINT256; + const b = new BN('2'); + + await testFailsCommutative(this.safeMath.$mul, a, b, undefined); + }); + }); + + describe('div', function () { + it('divides correctly', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal(a.div(b)); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal('0'); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal('1'); + }); + + it('reverts on division by zero', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + await expectRevert.unspecified(this.safeMath.$div(a, b)); + }); + }); + + describe('mod', function () { + describe('modulos correctly', async function () { + it('when the dividend is smaller than the divisor', async function () { + const a = new BN('284'); + const b = new BN('5678'); + + expect(await this.safeMath.$mod(a, b)).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expect(await this.safeMath.$mod(a, b)).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect(await this.safeMath.$mod(a, b)).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = new BN('17034'); // 17034 == 5678 * 3 + const b = new BN('5678'); + + expect(await this.safeMath.$mod(a, b)).to.be.bignumber.equal(a.mod(b)); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + await expectRevert.unspecified(this.safeMath.$mod(a, b)); + }); + }); + }); + + describe('with custom revert message', function () { + describe('sub', function () { + it('subtracts correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + expect( + await this.safeMath.methods['$sub(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.sub(b)); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await expectRevert( + this.safeMath.methods['$sub(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + 'MyErrorMessage', + ); + }); + }); + + describe('div', function () { + it('divides correctly', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$div(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.div(b)); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$div(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal('0'); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$div(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal('1'); + }); + + it('reverts on division by zero', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + await expectRevert( + this.safeMath.methods['$div(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + 'MyErrorMessage', + ); + }); + }); + + describe('mod', function () { + describe('modulos correctly', async function () { + it('when the dividend is smaller than the divisor', async function () { + const a = new BN('284'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.mod(b)); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = new BN('17034'); // 17034 == 5678 * 3 + const b = new BN('5678'); + + expect( + await this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + ).to.be.bignumber.equal(a.mod(b)); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + await expectRevert( + this.safeMath.methods['$mod(uint256,uint256,string)'](a, b, 'MyErrorMessage'), + 'MyErrorMessage', + ); + }); + }); + }); + + describe('memory leakage', function () { + beforeEach(async function () { + this.safeMathMemoryCheck = await SafeMathMemoryCheck.new(); + }); + + it('add', async function () { + expect(await this.safeMathMemoryCheck.$addMemoryCheck()).to.be.bignumber.equal('0'); + }); + + it('sub', async function () { + expect(await this.safeMathMemoryCheck.$subMemoryCheck()).to.be.bignumber.equal('0'); + }); + + it('mul', async function () { + expect(await this.safeMathMemoryCheck.$mulMemoryCheck()).to.be.bignumber.equal('0'); + }); + + it('div', async function () { + expect(await this.safeMathMemoryCheck.$divMemoryCheck()).to.be.bignumber.equal('0'); + }); + + it('mod', async function () { + expect(await this.safeMathMemoryCheck.$modMemoryCheck()).to.be.bignumber.equal('0'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SignedMath.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SignedMath.test.js new file mode 100644 index 0000000..c014e22 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SignedMath.test.js @@ -0,0 +1,95 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MIN_INT256, MAX_INT256 } = constants; + +const SignedMath = artifacts.require('$SignedMath'); + +contract('SignedMath', function () { + const min = new BN('-1234'); + const max = new BN('5678'); + + beforeEach(async function () { + this.math = await SignedMath.new(); + }); + + describe('max', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$max(max, min)).to.be.bignumber.equal(max); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$max(min, max)).to.be.bignumber.equal(max); + }); + }); + + describe('min', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$min(min, max)).to.be.bignumber.equal(min); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$min(max, min)).to.be.bignumber.equal(min); + }); + }); + + describe('average', function () { + function bnAverage(a, b) { + return a.add(b).divn(2); + } + + it('is correctly calculated with various input', async function () { + const valuesX = [ + new BN('0'), + new BN('3'), + new BN('-3'), + new BN('4'), + new BN('-4'), + new BN('57417'), + new BN('-57417'), + new BN('42304'), + new BN('-42304'), + MIN_INT256, + MAX_INT256, + ]; + + const valuesY = [ + new BN('0'), + new BN('5'), + new BN('-5'), + new BN('2'), + new BN('-2'), + new BN('57417'), + new BN('-57417'), + new BN('42304'), + new BN('-42304'), + MIN_INT256, + MAX_INT256, + ]; + + for (const x of valuesX) { + for (const y of valuesY) { + expect(await this.math.$average(x, y)).to.be.bignumber.equal( + bnAverage(x, y), + `Bad result for average(${x}, ${y})`, + ); + } + } + }); + }); + + describe('abs', function () { + for (const n of [ + MIN_INT256, + MIN_INT256.addn(1), + new BN('-1'), + new BN('0'), + new BN('1'), + MAX_INT256.subn(1), + MAX_INT256, + ]) { + it(`correctly computes the absolute value of ${n}`, async function () { + expect(await this.math.$abs(n)).to.be.bignumber.equal(n.abs()); + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SignedSafeMath.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SignedSafeMath.test.js new file mode 100644 index 0000000..3b6530c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/math/SignedSafeMath.test.js @@ -0,0 +1,152 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { MAX_INT256, MIN_INT256 } = constants; + +const { expect } = require('chai'); + +const SignedSafeMath = artifacts.require('$SignedSafeMath'); + +contract('SignedSafeMath', function () { + beforeEach(async function () { + this.safeMath = await SignedSafeMath.new(); + }); + + async function testCommutative(fn, lhs, rhs, expected) { + expect(await fn(lhs, rhs)).to.be.bignumber.equal(expected); + expect(await fn(rhs, lhs)).to.be.bignumber.equal(expected); + } + + async function testFailsCommutative(fn, lhs, rhs) { + await expectRevert.unspecified(fn(lhs, rhs)); + await expectRevert.unspecified(fn(rhs, lhs)); + } + + describe('add', function () { + it('adds correctly if it does not overflow and the result is positive', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await testCommutative(this.safeMath.$add, a, b, a.add(b)); + }); + + it('adds correctly if it does not overflow and the result is negative', async function () { + const a = MAX_INT256; + const b = MIN_INT256; + + await testCommutative(this.safeMath.$add, a, b, a.add(b)); + }); + + it('reverts on positive addition overflow', async function () { + const a = MAX_INT256; + const b = new BN('1'); + + await testFailsCommutative(this.safeMath.$add, a, b); + }); + + it('reverts on negative addition overflow', async function () { + const a = MIN_INT256; + const b = new BN('-1'); + + await testFailsCommutative(this.safeMath.$add, a, b); + }); + }); + + describe('sub', function () { + it('subtracts correctly if it does not overflow and the result is positive', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + const result = await this.safeMath.$sub(a, b); + expect(result).to.be.bignumber.equal(a.sub(b)); + }); + + it('subtracts correctly if it does not overflow and the result is negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + const result = await this.safeMath.$sub(a, b); + expect(result).to.be.bignumber.equal(a.sub(b)); + }); + + it('reverts on positive subtraction overflow', async function () { + const a = MAX_INT256; + const b = new BN('-1'); + + await expectRevert.unspecified(this.safeMath.$sub(a, b)); + }); + + it('reverts on negative subtraction overflow', async function () { + const a = MIN_INT256; + const b = new BN('1'); + + await expectRevert.unspecified(this.safeMath.$sub(a, b)); + }); + }); + + describe('mul', function () { + it('multiplies correctly', async function () { + const a = new BN('5678'); + const b = new BN('-1234'); + + await testCommutative(this.safeMath.$mul, a, b, a.mul(b)); + }); + + it('multiplies by zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + await testCommutative(this.safeMath.$mul, a, b, '0'); + }); + + it('reverts on multiplication overflow, positive operands', async function () { + const a = MAX_INT256; + const b = new BN('2'); + + await testFailsCommutative(this.safeMath.$mul, a, b); + }); + + it('reverts when minimum integer is multiplied by -1', async function () { + const a = MIN_INT256; + const b = new BN('-1'); + + await testFailsCommutative(this.safeMath.$mul, a, b); + }); + }); + + describe('div', function () { + it('divides correctly', async function () { + const a = new BN('-5678'); + const b = new BN('5678'); + + const result = await this.safeMath.$div(a, b); + expect(result).to.be.bignumber.equal(a.div(b)); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal('0'); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expect(await this.safeMath.$div(a, b)).to.be.bignumber.equal('1'); + }); + + it('reverts on division by zero', async function () { + const a = new BN('-5678'); + const b = new BN('0'); + + await expectRevert.unspecified(this.safeMath.$div(a, b)); + }); + + it('reverts on overflow, negative second', async function () { + const a = new BN(MIN_INT256); + const b = new BN('-1'); + + await expectRevert.unspecified(this.safeMath.$div(a, b)); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/BitMap.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/BitMap.test.js new file mode 100644 index 0000000..8a1470c --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/BitMap.test.js @@ -0,0 +1,145 @@ +const { BN } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const BitMap = artifacts.require('$BitMaps'); + +contract('BitMap', function () { + const keyA = new BN('7891'); + const keyB = new BN('451'); + const keyC = new BN('9592328'); + + beforeEach(async function () { + this.bitmap = await BitMap.new(); + }); + + it('starts empty', async function () { + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + describe('setTo', function () { + it('set a key to true', async function () { + await this.bitmap.$setTo(0, keyA, true); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('set a key to false', async function () { + await this.bitmap.$setTo(0, keyA, true); + await this.bitmap.$setTo(0, keyA, false); + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('set several consecutive keys', async function () { + await this.bitmap.$setTo(0, keyA.addn(0), true); + await this.bitmap.$setTo(0, keyA.addn(1), true); + await this.bitmap.$setTo(0, keyA.addn(2), true); + await this.bitmap.$setTo(0, keyA.addn(3), true); + await this.bitmap.$setTo(0, keyA.addn(4), true); + await this.bitmap.$setTo(0, keyA.addn(2), false); + await this.bitmap.$setTo(0, keyA.addn(4), false); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + }); + + describe('set', function () { + it('adds a key', async function () { + await this.bitmap.$set(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('adds several keys', async function () { + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(true); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('adds several consecutive keys', async function () { + await this.bitmap.$set(0, keyA.addn(0)); + await this.bitmap.$set(0, keyA.addn(1)); + await this.bitmap.$set(0, keyA.addn(3)); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + }); + + describe('unset', function () { + it('removes added keys', async function () { + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + await this.bitmap.$unset(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(true); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('removes consecutive added keys', async function () { + await this.bitmap.$set(0, keyA.addn(0)); + await this.bitmap.$set(0, keyA.addn(1)); + await this.bitmap.$set(0, keyA.addn(3)); + await this.bitmap.$unset(0, keyA.addn(1)); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + + it('adds and removes multiple keys', async function () { + // [] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyC); + + // [A, C] + + await this.bitmap.$unset(0, keyA); + await this.bitmap.$unset(0, keyB); + + // [C] + + await this.bitmap.$set(0, keyB); + + // [C, B] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$unset(0, keyC); + + // [A, B] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + + // [A, B] + + await this.bitmap.$set(0, keyC); + await this.bitmap.$unset(0, keyA); + + // [B, C] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$unset(0, keyB); + + // [A, C] + + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(true); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/DoubleEndedQueue.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/DoubleEndedQueue.test.js new file mode 100644 index 0000000..2fbb8dc --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/DoubleEndedQueue.test.js @@ -0,0 +1,99 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const DoubleEndedQueue = artifacts.require('$DoubleEndedQueue'); + +/** Rebuild the content of the deque as a JS array. */ +const getContent = deque => + deque.$length(0).then(bn => + Promise.all( + Array(bn.toNumber()) + .fill() + .map((_, i) => deque.$at(0, i)), + ), + ); + +contract('DoubleEndedQueue', function () { + const bytesA = '0xdeadbeef'.padEnd(66, '0'); + const bytesB = '0x0123456789'.padEnd(66, '0'); + const bytesC = '0x42424242'.padEnd(66, '0'); + const bytesD = '0x171717'.padEnd(66, '0'); + + beforeEach(async function () { + this.deque = await DoubleEndedQueue.new(); + }); + + describe('when empty', function () { + it('getters', async function () { + expect(await this.deque.$empty(0)).to.be.equal(true); + expect(await getContent(this.deque)).to.have.ordered.members([]); + }); + + it('reverts on accesses', async function () { + await expectRevertCustomError(this.deque.$popBack(0), 'Empty()'); + await expectRevertCustomError(this.deque.$popFront(0), 'Empty()'); + await expectRevertCustomError(this.deque.$back(0), 'Empty()'); + await expectRevertCustomError(this.deque.$front(0), 'Empty()'); + }); + }); + + describe('when not empty', function () { + beforeEach(async function () { + await this.deque.$pushBack(0, bytesB); + await this.deque.$pushFront(0, bytesA); + await this.deque.$pushBack(0, bytesC); + this.content = [bytesA, bytesB, bytesC]; + }); + + it('getters', async function () { + expect(await this.deque.$empty(0)).to.be.equal(false); + expect(await this.deque.$length(0)).to.be.bignumber.equal(this.content.length.toString()); + expect(await this.deque.$front(0)).to.be.equal(this.content[0]); + expect(await this.deque.$back(0)).to.be.equal(this.content[this.content.length - 1]); + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('out of bounds access', async function () { + await expectRevertCustomError(this.deque.$at(0, this.content.length), 'OutOfBounds()'); + }); + + describe('push', function () { + it('front', async function () { + await this.deque.$pushFront(0, bytesD); + this.content.unshift(bytesD); // add element at the beginning + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('back', async function () { + await this.deque.$pushBack(0, bytesD); + this.content.push(bytesD); // add element at the end + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + }); + + describe('pop', function () { + it('front', async function () { + const value = this.content.shift(); // remove first element + expectEvent(await this.deque.$popFront(0), 'return$popFront', { value }); + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('back', async function () { + const value = this.content.pop(); // remove last element + expectEvent(await this.deque.$popBack(0), 'return$popBack', { value }); + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + }); + + it('clear', async function () { + await this.deque.$clear(0); + + expect(await this.deque.$empty(0)).to.be.equal(true); + expect(await getContent(this.deque)).to.have.ordered.members([]); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableMap.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableMap.behavior.js new file mode 100644 index 0000000..b4b5ee3 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableMap.behavior.js @@ -0,0 +1,185 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const zip = require('lodash.zip'); + +function shouldBehaveLikeMap(keys, values, zeroValue, methods, events) { + const [keyA, keyB, keyC] = keys; + const [valueA, valueB, valueC] = values; + + async function expectMembersMatch(map, keys, values) { + expect(keys.length).to.equal(values.length); + + await Promise.all(keys.map(async key => expect(await methods.contains(map, key)).to.equal(true))); + + expect(await methods.length(map)).to.bignumber.equal(keys.length.toString()); + + expect((await Promise.all(keys.map(key => methods.get(map, key)))).map(k => k.toString())).to.have.same.members( + values.map(value => value.toString()), + ); + + // To compare key-value pairs, we zip keys and values, and convert BNs to + // strings to workaround Chai limitations when dealing with nested arrays + expect( + await Promise.all( + [...Array(keys.length).keys()].map(async index => { + const entry = await methods.at(map, index); + return [entry[0].toString(), entry[1].toString()]; + }), + ), + ).to.have.same.deep.members( + zip( + keys.map(k => k.toString()), + values.map(v => v.toString()), + ), + ); + + // This also checks that both arrays have the same length + expect((await methods.keys(map)).map(k => k.toString())).to.have.same.members(keys.map(key => key.toString())); + } + + it('starts empty', async function () { + expect(await methods.contains(this.map, keyA)).to.equal(false); + + await expectMembersMatch(this.map, [], []); + }); + + describe('set', function () { + it('adds a key', async function () { + const receipt = await methods.set(this.map, keyA, valueA); + expectEvent(receipt, events.setReturn, { ret0: true }); + + await expectMembersMatch(this.map, [keyA], [valueA]); + }); + + it('adds several keys', async function () { + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyB, valueB); + + await expectMembersMatch(this.map, [keyA, keyB], [valueA, valueB]); + expect(await methods.contains(this.map, keyC)).to.equal(false); + }); + + it('returns false when adding keys already in the set', async function () { + await methods.set(this.map, keyA, valueA); + + const receipt = await methods.set(this.map, keyA, valueA); + expectEvent(receipt, events.setReturn, { ret0: false }); + + await expectMembersMatch(this.map, [keyA], [valueA]); + }); + + it('updates values for keys already in the set', async function () { + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyA, valueB); + + await expectMembersMatch(this.map, [keyA], [valueB]); + }); + }); + + describe('remove', function () { + it('removes added keys', async function () { + await methods.set(this.map, keyA, valueA); + + const receipt = await methods.remove(this.map, keyA); + expectEvent(receipt, events.removeReturn, { ret0: true }); + + expect(await methods.contains(this.map, keyA)).to.equal(false); + await expectMembersMatch(this.map, [], []); + }); + + it('returns false when removing keys not in the set', async function () { + const receipt = await methods.remove(this.map, keyA); + expectEvent(receipt, events.removeReturn, { ret0: false }); + + expect(await methods.contains(this.map, keyA)).to.equal(false); + }); + + it('adds and removes multiple keys', async function () { + // [] + + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyC, valueC); + + // [A, C] + + await methods.remove(this.map, keyA); + await methods.remove(this.map, keyB); + + // [C] + + await methods.set(this.map, keyB, valueB); + + // [C, B] + + await methods.set(this.map, keyA, valueA); + await methods.remove(this.map, keyC); + + // [A, B] + + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyB, valueB); + + // [A, B] + + await methods.set(this.map, keyC, valueC); + await methods.remove(this.map, keyA); + + // [B, C] + + await methods.set(this.map, keyA, valueA); + await methods.remove(this.map, keyB); + + // [A, C] + + await expectMembersMatch(this.map, [keyA, keyC], [valueA, valueC]); + + expect(await methods.contains(this.map, keyA)).to.equal(true); + expect(await methods.contains(this.map, keyB)).to.equal(false); + expect(await methods.contains(this.map, keyC)).to.equal(true); + }); + }); + + describe('read', function () { + beforeEach(async function () { + await methods.set(this.map, keyA, valueA); + }); + + describe('get', function () { + it('existing value', async function () { + expect(await methods.get(this.map, keyA).then(r => r.toString())).to.be.equal(valueA.toString()); + }); + it('missing value', async function () { + await expectRevert(methods.get(this.map, keyB), 'EnumerableMap: nonexistent key'); + }); + }); + + describe('get with message', function () { + it('existing value', async function () { + expect(await methods.getWithMessage(this.map, keyA, 'custom error string').then(r => r.toString())).to.be.equal( + valueA.toString(), + ); + }); + it('missing value', async function () { + await expectRevert(methods.getWithMessage(this.map, keyB, 'custom error string'), 'custom error string'); + }); + }); + + describe('tryGet', function () { + it('existing value', async function () { + const result = await methods.tryGet(this.map, keyA); + expect(result['0']).to.be.equal(true); + expect(result['1'].toString()).to.be.equal(valueA.toString()); + }); + it('missing value', async function () { + const result = await methods.tryGet(this.map, keyB); + expect(result['0']).to.be.equal(false); + expect(result['1'].toString()).to.be.equal(zeroValue.toString()); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeMap, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableMap.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableMap.test.js new file mode 100644 index 0000000..f540ec9 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableMap.test.js @@ -0,0 +1,154 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { mapValues } = require('../../helpers/map-values'); + +const EnumerableMap = artifacts.require('$EnumerableMap'); + +const { shouldBehaveLikeMap } = require('./EnumerableMap.behavior'); + +const getMethods = ms => { + return mapValues( + ms, + m => + (self, ...args) => + self.methods[m](0, ...args), + ); +}; + +// 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; + + const keyA = new BN('7891'); + const keyB = new BN('451'); + const keyC = new BN('9592328'); + + const bytesA = '0xdeadbeef'.padEnd(66, '0'); + const bytesB = '0x0123456789'.padEnd(66, '0'); + const bytesC = '0x42424242'.padEnd(66, '0'); + + beforeEach(async function () { + this.map = await EnumerableMap.new(); + }); + + // AddressToUintMap + describe('AddressToUintMap', function () { + shouldBehaveLikeMap( + [accountA, accountB, accountC], + [keyA, keyB, keyC], + new BN('0'), + getMethods({ + set: '$set(uint256,address,uint256)', + get: '$get(uint256,address)', + getWithMessage: '$get(uint256,address,string)', + tryGet: '$tryGet(uint256,address)', + remove: '$remove(uint256,address)', + length: `$length_${library}_AddressToUintMap(uint256)`, + at: `$at_${library}_AddressToUintMap(uint256,uint256)`, + contains: '$contains(uint256,address)', + keys: `$keys_${library}_AddressToUintMap(uint256)`, + }), + { + setReturn: `return$set_${library}_AddressToUintMap_address_uint256`, + removeReturn: `return$remove_${library}_AddressToUintMap_address`, + }, + ); + }); + + // UintToAddressMap + describe('UintToAddressMap', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC], + [accountA, accountB, accountC], + constants.ZERO_ADDRESS, + getMethods({ + set: '$set(uint256,uint256,address)', + 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_${library}_UintToAddressMap_uint256_address`, + removeReturn: `return$remove_${library}_UintToAddressMap_uint256`, + }, + ); + }); + + // Bytes32ToBytes32Map + describe('Bytes32ToBytes32Map', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC].map(k => '0x' + k.toString(16).padEnd(64, '0')), + [bytesA, bytesB, bytesC], + constants.ZERO_BYTES32, + getMethods({ + set: '$set(uint256,bytes32,bytes32)', + 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_${library}_Bytes32ToBytes32Map_bytes32_bytes32`, + removeReturn: `return$remove_${library}_Bytes32ToBytes32Map_bytes32`, + }, + ); + }); + + // UintToUintMap + describe('UintToUintMap', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC], + [keyA, keyB, keyC].map(k => k.add(new BN('1332'))), + new BN('0'), + getMethods({ + set: '$set(uint256,uint256,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_${library}_UintToUintMap_uint256_uint256`, + removeReturn: `return$remove_${library}_UintToUintMap_uint256`, + }, + ); + }); + + // Bytes32ToUintMap + describe('Bytes32ToUintMap', function () { + shouldBehaveLikeMap( + [bytesA, bytesB, bytesC], + [keyA, keyB, keyC], + new BN('0'), + getMethods({ + set: '$set(uint256,bytes32,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_${library}_Bytes32ToUintMap_bytes32_uint256`, + removeReturn: `return$remove_${library}_Bytes32ToUintMap_bytes32`, + }, + ); + }); +}); diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableSet.behavior.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableSet.behavior.js new file mode 100644 index 0000000..f80eb81 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableSet.behavior.js @@ -0,0 +1,129 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +function shouldBehaveLikeSet(values, methods, events) { + const [valueA, valueB, valueC] = values; + + async function expectMembersMatch(set, values) { + const contains = await Promise.all(values.map(value => methods.contains(set, value))); + expect(contains.every(Boolean)).to.be.equal(true); + + const length = await methods.length(set); + expect(length).to.bignumber.equal(values.length.toString()); + + // To compare values we convert to strings to workaround Chai + // limitations when dealing with nested arrays (required for BNs) + const indexedValues = await Promise.all( + Array(values.length) + .fill() + .map((_, index) => methods.at(set, index)), + ); + expect(indexedValues.map(v => v.toString())).to.have.same.members(values.map(v => v.toString())); + + const returnedValues = await methods.values(set); + expect(returnedValues.map(v => v.toString())).to.have.same.members(values.map(v => v.toString())); + } + + it('starts empty', async function () { + expect(await methods.contains(this.set, valueA)).to.equal(false); + + await expectMembersMatch(this.set, []); + }); + + describe('add', function () { + it('adds a value', async function () { + const receipt = await methods.add(this.set, valueA); + expectEvent(receipt, events.addReturn, { ret0: true }); + + await expectMembersMatch(this.set, [valueA]); + }); + + it('adds several values', async function () { + await methods.add(this.set, valueA); + await methods.add(this.set, valueB); + + await expectMembersMatch(this.set, [valueA, valueB]); + expect(await methods.contains(this.set, valueC)).to.equal(false); + }); + + it('returns false when adding values already in the set', async function () { + await methods.add(this.set, valueA); + + const receipt = await methods.add(this.set, valueA); + expectEvent(receipt, events.addReturn, { ret0: false }); + + await expectMembersMatch(this.set, [valueA]); + }); + }); + + describe('at', function () { + it('reverts when retrieving non-existent elements', async function () { + await expectRevert.unspecified(methods.at(this.set, 0)); + }); + }); + + describe('remove', function () { + it('removes added values', async function () { + await methods.add(this.set, valueA); + + const receipt = await methods.remove(this.set, valueA); + expectEvent(receipt, events.removeReturn, { ret0: true }); + + expect(await methods.contains(this.set, valueA)).to.equal(false); + await expectMembersMatch(this.set, []); + }); + + it('returns false when removing values not in the set', async function () { + const receipt = await methods.remove(this.set, valueA); + expectEvent(receipt, events.removeReturn, { ret0: false }); + + expect(await methods.contains(this.set, valueA)).to.equal(false); + }); + + it('adds and removes multiple values', async function () { + // [] + + await methods.add(this.set, valueA); + await methods.add(this.set, valueC); + + // [A, C] + + await methods.remove(this.set, valueA); + await methods.remove(this.set, valueB); + + // [C] + + await methods.add(this.set, valueB); + + // [C, B] + + await methods.add(this.set, valueA); + await methods.remove(this.set, valueC); + + // [A, B] + + await methods.add(this.set, valueA); + await methods.add(this.set, valueB); + + // [A, B] + + await methods.add(this.set, valueC); + await methods.remove(this.set, valueA); + + // [B, C] + + await methods.add(this.set, valueA); + await methods.remove(this.set, valueB); + + // [A, C] + + await expectMembersMatch(this.set, [valueA, valueC]); + + expect(await methods.contains(this.set, valueB)).to.equal(false); + }); + }); +} + +module.exports = { + shouldBehaveLikeSet, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableSet.test.js b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableSet.test.js new file mode 100644 index 0000000..3ba9d7f --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/test/utils/structs/EnumerableSet.test.js @@ -0,0 +1,79 @@ +const EnumerableSet = artifacts.require('$EnumerableSet'); +const { mapValues } = require('../../helpers/map-values'); + +const { shouldBehaveLikeSet } = require('./EnumerableSet.behavior'); + +const getMethods = ms => { + return mapValues( + ms, + m => + (self, ...args) => + self.methods[m](0, ...args), + ); +}; + +// 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(); + }); + + // Bytes32Set + describe('EnumerableBytes32Set', function () { + shouldBehaveLikeSet( + ['0xdeadbeef', '0x0123456789', '0x42424242'].map(e => e.padEnd(66, '0')), + getMethods({ + add: '$add(uint256,bytes32)', + remove: '$remove(uint256,bytes32)', + contains: '$contains(uint256,bytes32)', + length: `$length_${library}_Bytes32Set(uint256)`, + at: `$at_${library}_Bytes32Set(uint256,uint256)`, + values: `$values_${library}_Bytes32Set(uint256)`, + }), + { + addReturn: `return$add_${library}_Bytes32Set_bytes32`, + removeReturn: `return$remove_${library}_Bytes32Set_bytes32`, + }, + ); + }); + + // AddressSet + describe('EnumerableAddressSet', function () { + shouldBehaveLikeSet( + accounts, + getMethods({ + add: '$add(uint256,address)', + remove: '$remove(uint256,address)', + contains: '$contains(uint256,address)', + length: `$length_${library}_AddressSet(uint256)`, + at: `$at_${library}_AddressSet(uint256,uint256)`, + values: `$values_${library}_AddressSet(uint256)`, + }), + { + addReturn: `return$add_${library}_AddressSet_address`, + removeReturn: `return$remove_${library}_AddressSet_address`, + }, + ); + }); + + // UintSet + describe('EnumerableUintSet', function () { + shouldBehaveLikeSet( + [1234, 5678, 9101112].map(e => web3.utils.toBN(e)), + getMethods({ + add: '$add(uint256,uint256)', + remove: '$remove(uint256,uint256)', + contains: '$contains(uint256,uint256)', + length: `$length_${library}_UintSet(uint256)`, + at: `$at_${library}_UintSet(uint256,uint256)`, + values: `$values_${library}_UintSet(uint256)`, + }), + { + addReturn: `return$add_${library}_UintSet_uint256`, + removeReturn: `return$remove_${library}_UintSet_uint256`, + }, + ); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/.changeset/config.json b/lib/openzeppelin-contracts-v5.0.0/.changeset/config.json new file mode 100644 index 0000000..66794fa --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.changeset/config.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", + "changelog": [ + "@changesets/changelog-github", + { + "repo": "OpenZeppelin/openzeppelin-contracts" + } + ], + "commit": false, + "access": "public", + "baseBranch": "master" +} diff --git a/lib/openzeppelin-contracts-v5.0.0/.codecov.yml b/lib/openzeppelin-contracts-v5.0.0/.codecov.yml new file mode 100644 index 0000000..9455306 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.codecov.yml @@ -0,0 +1,12 @@ +comment: off +github_checks: + annotations: false +coverage: + status: + patch: + default: + target: 95% + only_pulls: true + project: + default: + threshold: 1% diff --git a/lib/openzeppelin-contracts-v5.0.0/.editorconfig b/lib/openzeppelin-contracts-v5.0.0/.editorconfig new file mode 100644 index 0000000..f162e8d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = false +max_line_length = 120 + +[*.sol] +indent_size = 4 + +[*.js] +indent_size = 2 + +[*.{adoc,md}] +max_line_length = 0 diff --git a/lib/openzeppelin-contracts-v5.0.0/.eslintrc b/lib/openzeppelin-contracts-v5.0.0/.eslintrc new file mode 100644 index 0000000..a5418c5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.eslintrc @@ -0,0 +1,20 @@ +{ + "root": true, + "extends" : [ + "eslint:recommended", + "prettier", + ], + "env": { + "es2022": true, + "browser": true, + "node": true, + "mocha": true, + }, + "globals" : { + "artifacts": "readonly", + "contract": "readonly", + "web3": "readonly", + "extendEnvironment": "readonly", + "expect": "readonly", + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/bug_report.md b/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..2797a08 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,21 @@ +--- +name: Bug report +about: Report a bug in OpenZeppelin Contracts + +--- + + + + + +**💻 Environment** + + + +**📝 Details** + + + +**🔢 Code to reproduce bug** + + diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/config.yml b/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..4018cef --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: + - name: Questions & Support Requests + url: https://forum.openzeppelin.com/c/support/contracts/18 + about: Ask in the OpenZeppelin Forum diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/feature_request.md b/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..ff596b0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,14 @@ +--- +name: Feature request +about: Suggest an idea for OpenZeppelin Contracts + +--- + +**🧐 Motivation** + + +**📝 Details** + + + + diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/PULL_REQUEST_TEMPLATE.md b/lib/openzeppelin-contracts-v5.0.0/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2394518 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,20 @@ + + + + + +Fixes #???? + + + + + +#### PR Checklist + + + + + +- [ ] Tests +- [ ] Documentation +- [ ] Changeset entry (run `npx changeset add`) diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/actions/gas-compare/action.yml b/lib/openzeppelin-contracts-v5.0.0/.github/actions/gas-compare/action.yml new file mode 100644 index 0000000..e38c48e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/actions/gas-compare/action.yml @@ -0,0 +1,49 @@ +name: Compare gas costs +inputs: + token: + description: github token + required: true + report: + description: report to read from + required: false + default: gasReporterOutput.json + out_report: + description: report to read + required: false + default: ${{ github.ref_name }}.gasreport.json + ref_report: + description: report to read from + required: false + default: ${{ github.base_ref }}.gasreport.json + +runs: + using: composite + steps: + - name: Download reference report + 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 gasreport + env: + GITHUB_TOKEN: ${{ inputs.token }} + shell: bash + continue-on-error: true + id: reference + - name: Compare reports + if: steps.reference.outcome == 'success' && github.event_name == 'pull_request' + run: | + node scripts/checks/compareGasReports.js ${{ inputs.report }} ${{ inputs.ref_report }} >> $GITHUB_STEP_SUMMARY + env: + STYLE: markdown + shell: bash + - name: Rename report for upload + if: github.event_name != 'pull_request' + run: | + mv ${{ inputs.report }} ${{ inputs.out_report }} + shell: bash + - name: Save report + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: gasreport + path: ${{ inputs.out_report }} diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/actions/setup/action.yml b/lib/openzeppelin-contracts-v5.0.0/.github/actions/setup/action.yml new file mode 100644 index 0000000..cab1188 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/actions/setup/action.yml @@ -0,0 +1,21 @@ +name: Setup + +runs: + using: composite + steps: + - uses: actions/setup-node@v3 + with: + node-version: 16.x + - uses: actions/cache@v3 + id: cache + with: + path: '**/node_modules' + key: npm-v3-${{ hashFiles('**/package-lock.json') }} + - name: Install dependencies + run: npm ci + shell: bash + if: steps.cache.outputs.cache-hit != 'true' + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/actions/storage-layout/action.yml b/lib/openzeppelin-contracts-v5.0.0/.github/actions/storage-layout/action.yml new file mode 100644 index 0000000..fdfd5a2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.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 }} + 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/lib/openzeppelin-contracts-v5.0.0/.github/workflows/actionlint.yml b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/actionlint.yml new file mode 100644 index 0000000..3e42c8a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/actionlint.yml @@ -0,0 +1,18 @@ +name: lint workflows + +on: + pull_request: + paths: + - '.github/**/*.ya?ml' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Add problem matchers + run: | + # https://github.com/rhysd/actionlint/blob/3a2f2c7/docs/usage.md#problem-matchers + curl -LO https://raw.githubusercontent.com/rhysd/actionlint/main/.github/actionlint-matcher.json + echo "::add-matcher::actionlint-matcher.json" + - uses: docker://rhysd/actionlint:latest diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/workflows/changeset.yml b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/changeset.yml new file mode 100644 index 0000000..efc5c53 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/changeset.yml @@ -0,0 +1,28 @@ +name: changeset + +on: + pull_request: + branches: + - master + types: + - opened + - synchronize + - labeled + - unlabeled + +concurrency: + group: changeset-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + if: ${{ !contains(github.event.pull_request.labels.*.name, 'ignore-changeset') }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Include history so Changesets finds merge-base + - name: Set up environment + uses: ./.github/actions/setup + - name: Check changeset + run: npx changeset status --since=origin/${{ github.base_ref }} diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/workflows/checks.yml b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/checks.yml new file mode 100644 index 0000000..5b32bdb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/checks.yml @@ -0,0 +1,118 @@ +name: checks + +on: + push: + branches: + - master + - next-v* + - release-v* + pull_request: {} + workflow_dispatch: {} + +concurrency: + group: checks-${{ github.ref }} + cancel-in-progress: true + +env: + NODE_OPTIONS: --max_old_space_size=5120 + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: npm run lint + + tests: + runs-on: ubuntu-latest + env: + FORCE_COLOR: 1 + GAS: true + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - name: Run tests and generate gas report + run: npm run test + - name: Check linearisation of the inheritance graph + run: npm run test:inheritance + - name: Check proceduraly generated contracts are up-to-date + run: npm run test:generation + - name: Compare gas costs + uses: ./.github/actions/gas-compare + if: github.base_ref == 'master' + with: + token: ${{ github.token }} + + tests-upgradeable: + runs-on: ubuntu-latest + env: + FORCE_COLOR: 1 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Include history so patch conflicts are resolved automatically + - name: Set up environment + uses: ./.github/actions/setup + - name: Copy non-upgradeable contracts as dependency + run: | + mkdir -p lib/openzeppelin-contracts + cp -rnT contracts lib/openzeppelin-contracts/contracts + - name: Transpile to upgradeable + run: bash scripts/upgradeable/transpile.sh + - name: Run tests + run: npm run test + - name: Check linearisation of the inheritance graph + run: npm run test:inheritance + - name: Check storage layout + uses: ./.github/actions/storage-layout + if: github.base_ref == 'master' + continue-on-error: ${{ contains(github.event.pull_request.labels.*.name, 'breaking change') }} + with: + token: ${{ github.token }} + + tests-foundry: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Set up environment + uses: ./.github/actions/setup + - name: Run tests + run: forge test -vv + + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: npm run coverage + - uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + + slither: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: rm foundry.toml + - uses: crytic/slither-action@v0.3.0 + with: + node-version: 18.15 + + codespell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run CodeSpell + uses: codespell-project/actions-codespell@v2.0 + with: + check_hidden: true + check_filenames: true + skip: package-lock.json,*.pdf diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/workflows/docs.yml b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/docs.yml new file mode 100644 index 0000000..04b8131 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/docs.yml @@ -0,0 +1,19 @@ +name: Build Docs + +on: + push: + branches: [release-v*] + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - run: node scripts/update-docs-branch.js + - run: git push --all origin diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/workflows/formal-verification.yml b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/formal-verification.yml new file mode 100644 index 0000000..6b4ca2c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/formal-verification.yml @@ -0,0 +1,68 @@ +name: formal verification + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + workflow_dispatch: {} + +env: + PIP_VERSION: '3.10' + JAVA_VERSION: '11' + SOLC_VERSION: '0.8.20' + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + apply-diff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - 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@v4 + 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: + 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 ${{ steps.arguments.outputs.result }} >> "$GITHUB_STEP_SUMMARY" + env: + CERTORAKEY: ${{ secrets.CERTORAKEY }} diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/workflows/release-cycle.yml b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/release-cycle.yml new file mode 100644 index 0000000..12da449 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/release-cycle.yml @@ -0,0 +1,214 @@ +# 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: + push: + branches: + - release-v* + workflow_dispatch: {} + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + state: + name: Check state + permissions: + pull-requests: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - id: state + name: Get state + uses: actions/github-script@v6 + env: + TRIGGERING_ACTOR: ${{ github.triggering_actor }} + with: + result-encoding: string + script: await require('./scripts/release/workflow/state.js')({ github, context, core }) + outputs: + # Job Flags + start: ${{ steps.state.outputs.start }} + changesets: ${{ steps.state.outputs.changesets }} + promote: ${{ steps.state.outputs.promote }} + publish: ${{ steps.state.outputs.publish }} + merge: ${{ steps.state.outputs.merge }} + + # Global variables + is_prerelease: ${{ steps.state.outputs.is_prerelease }} + + start: + needs: state + name: Start new release candidate + permissions: + contents: write + actions: write + if: needs.state.outputs.start == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - id: start + name: Create branch with release candidate + run: bash scripts/release/workflow/start.sh + - name: Re-run workflow + uses: actions/github-script@v6 + env: + REF: ${{ steps.start.outputs.branch }} + with: + script: await require('./scripts/release/workflow/rerun.js')({ github, context }) + + promote: + needs: state + name: Promote to final release + permissions: + contents: write + actions: write + if: needs.state.outputs.promote == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Exit prerelease state + if: needs.state.outputs.is_prerelease == 'true' + run: bash scripts/release/workflow/exit-prerelease.sh + - name: Re-run workflow + uses: actions/github-script@v6 + with: + script: await require('./scripts/release/workflow/rerun.js')({ github, context }) + + changesets: + needs: state + name: Update PR to release + permissions: + contents: write + pull-requests: write + if: needs.state.outputs.changesets == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # To get all tags + - name: Set up environment + uses: ./.github/actions/setup + - name: Set release title + uses: actions/github-script@v6 + with: + result-encoding: string + script: await require('./scripts/release/workflow/set-changesets-pr-title.js')({ core }) + - name: Create PR + uses: changesets/action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRERELEASE: ${{ needs.state.outputs.is_prerelease }} + with: + version: npm run version + title: ${{ env.TITLE }} + commit: ${{ env.TITLE }} + body: | # Wait for support on this https://github.com/changesets/action/pull/250 + This is an automated PR for releasing ${{ github.repository }} + Check [CHANGELOG.md](${{ github.repository }}/CHANGELOG.md) + + publish: + needs: state + name: Publish to npm + environment: npm + permissions: + contents: write + if: needs.state.outputs.publish == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - id: pack + name: Pack + 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: Publish + run: bash scripts/release/workflow/publish.sh + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + TARBALL: ${{ steps.pack.outputs.tarball }} + TAG: ${{ steps.pack.outputs.tag }} + - name: Create Github Release + uses: actions/github-script@v6 + env: + 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@v4 + - 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 + name: Create PR back to master + permissions: + contents: write + pull-requests: write + if: needs.state.outputs.merge == 'true' + runs-on: ubuntu-latest + env: + MERGE_BRANCH: merge/${{ github.ref_name }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # All branches + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Create branch to merge + run: | + git checkout -B "$MERGE_BRANCH" "$GITHUB_REF_NAME" + git push -f origin "$MERGE_BRANCH" + - name: Create PR back to master + uses: actions/github-script@v6 + with: + script: | + await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head: process.env.MERGE_BRANCH, + base: 'master', + title: '${{ format('Merge {0} branch', github.ref_name) }}' + }); diff --git a/lib/openzeppelin-contracts-v5.0.0/.github/workflows/upgradeable.yml b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/upgradeable.yml new file mode 100644 index 0000000..46bf15a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.github/workflows/upgradeable.yml @@ -0,0 +1,34 @@ +name: transpile upgradeable + +on: + push: + branches: + - master + - release-v* + +jobs: + transpile: + environment: push-upgradeable + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + repository: OpenZeppelin/openzeppelin-contracts-upgradeable + fetch-depth: 0 + token: ${{ secrets.GH_TOKEN_UPGRADEABLE }} + - name: Fetch current non-upgradeable branch + run: | + git fetch "$REMOTE" master # Fetch default branch first for patch to apply cleanly + git fetch "$REMOTE" "$REF" + git checkout FETCH_HEAD + env: + REF: ${{ github.ref }} + REMOTE: https://github.com/${{ github.repository }}.git + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Transpile to upgradeable + run: bash scripts/upgradeable/transpile-onto.sh ${{ github.ref_name }} origin/${{ github.ref_name }} + env: + SUBMODULE_REMOTE: https://github.com/${{ github.repository }}.git + - run: git push origin ${{ github.ref_name }} diff --git a/lib/openzeppelin-contracts-v5.0.0/.gitignore b/lib/openzeppelin-contracts-v5.0.0/.gitignore new file mode 100644 index 0000000..a6caa9f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.gitignore @@ -0,0 +1,72 @@ +*.swp +*.swo + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +allFiredEvents +scTopics + +# Coverage directory used by tools like istanbul +coverage +coverage.json +coverageEnv + +# node-waf configuration +.lock-wscript + +# Dependency directory +node_modules + +# Debug log from npm +npm-debug.log + +# local env variables +.env + +# truffle build directory +build/ + +# macOS +.DS_Store + +# truffle +.node-xmlhttprequest-* + +# IntelliJ IDE +.idea + +# docs artifacts +docs/modules/api + +# only used to package @openzeppelin/contracts +contracts/build/ +contracts/README.md + +# temporary artifact from solidity-coverage +allFiredEvents +.coverage_artifacts +.coverage_cache +.coverage_contracts + +# hardat-exposed +contracts-exposed + +# Hardhat +/cache +/artifacts + +# Foundry +/out +/cache_forge + +# Certora +.certora* +.last_confs +certora_* +.zip-output-url.txt diff --git a/lib/openzeppelin-contracts-v5.0.0/.gitmodules b/lib/openzeppelin-contracts-v5.0.0/.gitmodules new file mode 100644 index 0000000..08a09bb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.gitmodules @@ -0,0 +1,7 @@ +[submodule "lib/forge-std"] + branch = v1 + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "lib/erc4626-tests"] + path = lib/erc4626-tests + url = https://github.com/a16z/erc4626-tests.git diff --git a/lib/openzeppelin-contracts-v5.0.0/.mocharc.js b/lib/openzeppelin-contracts-v5.0.0/.mocharc.js new file mode 100644 index 0000000..920662d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.mocharc.js @@ -0,0 +1,4 @@ +module.exports = { + require: 'hardhat/register', + timeout: 4000, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/.prettierrc b/lib/openzeppelin-contracts-v5.0.0/.prettierrc new file mode 100644 index 0000000..39c004c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.prettierrc @@ -0,0 +1,15 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all", + "arrowParens": "avoid", + "overrides": [ + { + "files": "*.sol", + "options": { + "singleQuote": false + } + } + ], + "plugins": ["prettier-plugin-solidity"] +} diff --git a/lib/openzeppelin-contracts-v5.0.0/.solcover.js b/lib/openzeppelin-contracts-v5.0.0/.solcover.js new file mode 100644 index 0000000..e0dea5e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/.solcover.js @@ -0,0 +1,13 @@ +module.exports = { + norpc: true, + testCommand: 'npm test', + compileCommand: 'npm run compile', + skipFiles: ['mocks'], + providerOptions: { + default_balance_ether: '10000000000000000000000000', + }, + mocha: { + fgrep: '[skip-on-coverage]', + invert: true, + }, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/CHANGELOG.md b/lib/openzeppelin-contracts-v5.0.0/CHANGELOG.md new file mode 100644 index 0000000..9575afb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/CHANGELOG.md @@ -0,0 +1,972 @@ +# Changelog + +## 5.0.0 (2023-10-05) + +### Additions Summary + +The following contracts and libraries were added: + +- `AccessManager`: A consolidated system for managing access control in complex systems. + - `AccessManaged`: A module for connecting a contract to an authority in charge of its access control. + - `GovernorTimelockAccess`: An adapter for time-locking governance proposals using an `AccessManager`. + - `AuthorityUtils`: A library of utilities for interacting with authority contracts. +- `GovernorStorage`: A Governor module that stores proposal details in storage. +- `ERC2771Forwarder`: An ERC2771 forwarder for meta transactions. +- `ERC1967Utils`: A library with ERC1967 events, errors and getters. +- `Nonces`: An abstraction for managing account nonces. +- `MessageHashUtils`: A library for producing digests for ECDSA operations. +- `Time`: A library with helpers for manipulating time-related objects. + +### Removals Summary + +The following contracts, libraries, and functions were removed: + +- `Address.isContract` (because of its ambiguous nature and potential for misuse) +- `Checkpoints.History` +- `Counters` +- `ERC20Snapshot` +- `ERC20VotesComp` +- `ERC165Storage` (in favor of inheritance based approach) +- `ERC777` +- `ERC1820Implementer` +- `GovernorVotesComp` +- `GovernorProposalThreshold` (deprecated since 4.4) +- `PaymentSplitter` +- `PullPayment` +- `SafeMath` +- `SignedSafeMath` +- `Timers` +- `TokenTimelock` (in favor of `VestingWallet`) +- All escrow contracts (`Escrow`, `ConditionalEscrow` and `RefundEscrow`) +- All cross-chain contracts, including `AccessControlCrossChain` and all the vendored bridge interfaces +- All presets in favor of [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/) + +These removals were implemented in the following PRs: [#3637](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3637), [#3880](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3880), [#3945](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3945), [#4258](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4258), [#4276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4276), [#4289](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4289) + +### Changes by category + +#### General + +- Replaced revert strings and require statements with custom errors. ([#4261](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4261)) +- Bumped minimum compiler version required to 0.8.20 ([#4288](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4288)) +- Use of `abi.encodeCall` in place of `abi.encodeWithSelector` and `abi.encodeWithSignature` for improved type-checking of parameters ([#4293](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4293)) +- Replaced some uses of `abi.encodePacked` with clearer alternatives (e.g. `bytes.concat`, `string.concat`). ([#4504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4504)) ([#4296](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4296)) +- Overrides are now used internally for a number of functions that were previously hardcoded to their default implementation in certain locations: `ERC1155Supply.totalSupply`, `ERC721.ownerOf`, `ERC721.balanceOf` and `ERC721.totalSupply` in `ERC721Enumerable`, `ERC20.totalSupply` in `ERC20FlashMint`, and `ERC1967._getImplementation` in `ERC1967Proxy`. ([#4299](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4299)) +- Removed the `override` specifier from functions that only override a single interface function. ([#4315](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4315)) +- Switched to using explicit Solidity import statements. Some previously available symbols may now have to be separately imported. ([#4399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4399)) +- `Governor`, `Initializable`, and `UUPSUpgradeable`: Use internal functions in modifiers to optimize bytecode size. ([#4472](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4472)) +- Upgradeable contracts now use namespaced storage (EIP-7201). ([#4534](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4534)) +- Upgradeable contracts no longer transpile interfaces and libraries. ([#4628](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4628)) + +#### Access + +- `Ownable`: Added an `initialOwner` parameter to the constructor, making the ownership initialization explicit. ([#4267](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4267)) +- `Ownable`: Prevent using address(0) as the initial owner. ([#4531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4531)) +- `AccessControl`: Added a boolean return value to the internal `_grantRole` and `_revokeRole` functions indicating whether the role was granted or revoked. ([#4241](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4241)) +- `access`: Moved `AccessControl` extensions to a dedicated directory. ([#4359](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4359)) +- `AccessManager`: Added a new contract for managing access control of complex systems in a consolidated location. ([#4121](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4121)) +- `AccessManager`, `AccessManaged`, `GovernorTimelockAccess`: Ensure that calldata shorter than 4 bytes is not padded to 4 bytes. ([#4624](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4624)) +- `AccessManager`: Use named return parameters in functions that return multiple values. ([#4624](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4624)) +- `AccessManager`: Make `schedule` and `execute` more conservative when delay is 0. ([#4644](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4644)) + +#### Finance + +- `VestingWallet`: Fixed revert during 1 second time window when duration is 0. ([#4502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4502)) +- `VestingWallet`: Use `Ownable` instead of an immutable `beneficiary`. ([#4508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4508)) + +#### Governance + +- `Governor`: Optimized use of storage for proposal data ([#4268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4268)) +- `Governor`: Added validation in ERC1155 and ERC721 receiver hooks to ensure Governor is the executor. ([#4314](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4314)) +- `Governor`: Refactored internals to implement common queuing logic in the core module of the Governor. Added `queue` and `_queueOperations` functions that act at different levels. Modules that implement queuing via timelocks are expected to override `_queueOperations` to implement the timelock-specific logic. Added `_executeOperations` as the equivalent for execution. ([#4360](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4360)) +- `Governor`: Added `voter` and `nonce` parameters in signed ballots, to avoid forging signatures for random addresses, prevent signature replay, and allow invalidating signatures. Add `voter` as a new parameter in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. ([#4378](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4378)) +- `Governor`: Added support for casting votes with ERC-1271 signatures by using a `bytes memory signature` instead of `r`, `s` and `v` arguments in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. ([#4418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4418)) +- `Governor`: Added a mechanism to restrict the address of the proposer using a suffix in the description. +- `GovernorStorage`: Added a new governor extension that stores the proposal details in storage, with an interface that operates on `proposalId`, as well as proposal enumerability. This replaces the old `GovernorCompatibilityBravo` module. ([#4360](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4360)) +- `GovernorTimelockAccess`: Added a module to connect a governor with an instance of `AccessManager`, allowing the governor to make calls that are delay-restricted by the manager using the normal `queue` workflow. ([#4523](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4523)) +- `GovernorTimelockControl`: Clean up timelock id on execution for gas refund. ([#4118](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4118)) +- `GovernorTimelockControl`: Added the Governor instance address as part of the TimelockController operation `salt` to avoid operation id collisions between governors using the same TimelockController. ([#4432](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4432)) +- `TimelockController`: Changed the role architecture to use `DEFAULT_ADMIN_ROLE` as the admin for all roles, instead of the bespoke `TIMELOCK_ADMIN_ROLE` that was used previously. This aligns with the general recommendation for `AccessControl` and makes the addition of new roles easier. Accordingly, the `admin` parameter and timelock will now be granted `DEFAULT_ADMIN_ROLE` instead of `TIMELOCK_ADMIN_ROLE`. ([#3799](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3799)) +- `TimelockController`: Added a state getter that returns an `OperationState` enum. ([#4358](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4358)) +- `Votes`: Use Trace208 for checkpoints. This enables EIP-6372 clock support for keys but reduces the max supported voting power to uint208. ([#4539](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4539)) + +#### Metatx + +- `ERC2771Forwarder`: Added `deadline` for expiring transactions, batching, and more secure handling of `msg.value`. ([#4346](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4346)) +- `ERC2771Context`: Return the forwarder address whenever the `msg.data` of a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes), as specified by ERC-2771. ([#4481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4481)) +- `ERC2771Context`: Prevent revert in `_msgData()` when a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes). Return the full calldata in that case. ([#4484](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4484)) + +#### Proxy + +- `ProxyAdmin`: Removed `getProxyAdmin` and `getProxyImplementation` getters. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820)) +- `TransparentUpgradeableProxy`: Removed `admin` and `implementation` getters, which were only callable by the proxy owner and thus not very useful. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820)) +- `ERC1967Utils`: Refactored the `ERC1967Upgrade` abstract contract as a library. ([#4325](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4325)) +- `TransparentUpgradeableProxy`: Admin is now stored in an immutable variable (set during construction) to avoid unnecessary storage reads on every proxy call. This removed the ability to ever change the admin. Transfer of the upgrade capability is exclusively handled through the ownership of the `ProxyAdmin`. ([#4354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4354)) +- Moved the logic to validate ERC-1822 during an upgrade from `ERC1967Utils` to `UUPSUpgradeable`. ([#4356](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4356)) +- `UUPSUpgradeable`, `TransparentUpgradeableProxy` and `ProxyAdmin`: Removed `upgradeTo` and `upgrade` functions, and made `upgradeToAndCall` and `upgradeAndCall` ignore the data argument if it is empty. It is no longer possible to invoke the receive function (or send value with empty data) along with an upgrade. ([#4382](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4382)) +- `BeaconProxy`: Reject value in initialization unless a payable function is explicitly invoked. ([#4382](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4382)) +- `Proxy`: Removed redundant `receive` function. ([#4434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4434)) +- `BeaconProxy`: Use an immutable variable to store the address of the beacon. It is no longer possible for a `BeaconProxy` to upgrade by changing to another beacon. ([#4435](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4435)) +- `Initializable`: Use the namespaced storage pattern to avoid putting critical variables in slot 0. Allow reinitializer versions greater than 256. ([#4460](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4460)) +- `Initializable`: Use intermediate variables to improve readability. ([#4576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4576)) + +#### Token + +- `ERC20`, `ERC721`, `ERC1155`: Deleted `_beforeTokenTransfer` and `_afterTokenTransfer` hooks, added a new internal `_update` function for customizations, and refactored all extensions using those hooks to use `_update` instead. ([#3838](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3838), [#3876](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3876), [#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4377)) +- `ERC20`: Removed `Approval` event previously emitted in `transferFrom` to indicate that part of the allowance was consumed. With this change, allowances are no longer reconstructible from events. See the code for guidelines on how to re-enable this event if needed. ([#4370](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4370)) +- `ERC20`: Removed the non-standard `increaseAllowance` and `decreaseAllowance` functions. ([#4585](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4585)) +- `ERC20Votes`: Changed internal vote accounting to reusable `Votes` module previously used by `ERC721Votes`. Removed implicit `ERC20Permit` inheritance. Note that the `DOMAIN_SEPARATOR` getter was previously guaranteed to be available for `ERC20Votes` contracts, but is no longer available unless `ERC20Permit` is explicitly used; ERC-5267 support is included in `ERC20Votes` with `EIP712` and is recommended as an alternative. ([#3816](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3816)) +- `SafeERC20`: Refactored `safeDecreaseAllowance` and `safeIncreaseAllowance` to support USDT-like tokens. ([#4260](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4260)) +- `SafeERC20`: Removed `safePermit` in favor of documentation-only `permit` recommendations. Based on recommendations from @trust1995 ([#4582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4582)) +- `ERC721`: `_approve` no longer allows approving the owner of the tokenId. ([#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/4377)) `_setApprovalForAll` no longer allows setting address(0) as an operator. ([#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4377)) +- `ERC721`: Renamed `_requireMinted` to `_requireOwned` and added a return value with the current owner. Implemented `ownerOf` in terms of `_requireOwned`. ([#4566](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4566)) +- `ERC721Consecutive`: Added a `_firstConsecutiveId` internal function that can be overridden to change the id of the first token minted through `_mintConsecutive`. ([#4097](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4097)) +- `ERC721URIStorage`: Allow setting the token URI prior to minting. ([#4559](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4559)) +- `ERC721URIStorage`, `ERC721Royalty`: Stop resetting token-specific URI and royalties when burning. ([#4561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4561)) +- `ERC1155`: Optimized array allocation. ([#4196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4196)) +- `ERC1155`: Removed check for address zero in `balanceOf`. ([#4263](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4263)) +- `ERC1155`: Optimized array accesses by skipping bounds checking when unnecessary. ([#4300](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4300)) +- `ERC1155`: Bubble errors triggered in the `onERC1155Received` and `onERC1155BatchReceived` hooks. ([#4314](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4314)) +- `ERC1155Supply`: Added a `totalSupply()` function that returns the total amount of token circulating, this change will restrict the total tokens minted across all ids to 2**256-1 . ([#3962](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3962)) +- `ERC1155Receiver`: Removed in favor of `ERC1155Holder`. ([#4450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4450)) + +#### Utils + +- `Address`: Removed the ability to customize error messages. A common custom error is always used if the underlying revert reason cannot be bubbled up. ([#4502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4502)) +- `Arrays`: Added `unsafeMemoryAccess` helpers to read from a memory array without checking the length. ([#4300](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4300)) +- `Arrays`: Optimized `findUpperBound` by removing redundant SLOAD. ([#4442](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4442)) +- `Checkpoints`: Library moved from `utils` to `utils/structs` ([#4275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4275)) +- `DoubleEndedQueue`: Refactored internal structure to use `uint128` instead of `int128`. This has no effect on the library interface. ([#4150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4150)) +- `ECDSA`: Use unchecked arithmetic for the `tryRecover` function that receives the `r` and `vs` short-signature fields separately. ([#4301](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4301)) +- `EIP712`: Added internal getters for the name and version strings ([#4303](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4303)) +- `Math`: Makes `ceilDiv` to revert on 0 division even if the numerator is 0 ([#4348](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4348)) +- `Math`: Optimized stack operations in `mulDiv`. ([#4494](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4494)) +- `Math`: Renamed members of `Rounding` enum, and added a new rounding mode for "away from zero". ([#4455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4455)) +- `MerkleProof`: Use custom error to report invalid multiproof instead of reverting with overflow panic. ([#4564](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4564)) +- `MessageHashUtils`: Added a new library for creating message digest to be used along with signing or recovery such as ECDSA or ERC-1271. These functions are moved from the `ECDSA` library. ([#4430](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4430)) +- `Nonces`: Added a new contract to keep track of user nonces. Used for signatures in `ERC20Permit`, `ERC20Votes`, and `ERC721Votes`. ([#3816](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3816)) +- `ReentrancyGuard`, `Pausable`: Moved to `utils` directory. ([#4551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4551)) +- `Strings`: Renamed `toString(int256)` to `toStringSigned(int256)`. ([#4330](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4330)) +- Optimized `Strings.equal` ([#4262](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4262)) + +### How to migrate from 4.x + +#### ERC20, ERC721, and ERC1155 + +These breaking changes will require modifications to ERC20, ERC721, and ERC1155 contracts, since the `_afterTokenTransfer` and `_beforeTokenTransfer` functions were removed. Thus, any customization made through those hooks should now be done overriding the new `_update` function instead. + +Minting and burning are implemented by `_update` and customizations should be done by overriding this function as well. `_transfer`, `_mint` and `_burn` are no longer virtual (meaning they are not overridable) to guard against possible inconsistencies. + +For example, a contract using `ERC20`'s `_beforeTokenTransfer` hook would have to be changed in the following way. + +```diff +-function _beforeTokenTransfer( ++function _update( + address from, + address to, + uint256 amount + ) internal virtual override { +- super._beforeTokenTransfer(from, to, amount); + require(!condition(), "ERC20: wrong condition"); ++ super._update(from, to, amount); + } +``` + +#### More about ERC721 + +In the case of `ERC721`, the `_update` function does not include a `from` parameter, as the sender is implicitly the previous owner of the `tokenId`. The address of this previous owner is returned by the `_update` function, so it can be used for a posteriori checks. In addition to `to` and `tokenId`, a third parameter (`auth`) is present in this function. This parameter enabled an optional check that the caller/spender is approved to do the transfer. This check cannot be performed after the transfer (because the transfer resets the approval), and doing it before `_update` would require a duplicate call to `_ownerOf`. + +In this logic of removing hidden SLOADs, the `_isApprovedOrOwner` function was removed in favor of a new `_isAuthorized` function. Overrides that used to target the `_isApprovedOrOwner` should now be performed on the `_isAuthorized` function. Calls to `_isApprovedOrOwner` that preceded a call to `_transfer`, `_burn` or `_approve` should be removed in favor of using the `auth` argument in `_update` and `_approve`. This is showcased in `ERC721Burnable.burn` and in `ERC721Wrapper.withdrawTo`. + +The `_exists` function was removed. Calls to this function can be replaced by `_ownerOf(tokenId) != address(0)`. + +#### ERC165Storage + +Users that were registering EIP-165 interfaces with `_registerInterface` from `ERC165Storage` should instead do so so by overriding the `supportsInterface` function as seen below: + +```solidity +function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); +} +``` + +#### Adapting Governor modules + +Custom Governor modules that override internal functions may require modifications if migrated to v5. In particular, the new internal functions `_queueOperations` and `_executeOperations` may need to be used. If assistance with this migration is needed reach out via the [OpenZeppelin Support Forum](https://forum.openzeppelin.com/c/support/contracts/18). + +#### ECDSA and MessageHashUtils + +The `ECDSA` library is now focused on signer recovery. Previously it also included utility methods for producing digests to be used with signing or recovery. These utilities have been moved to the `MessageHashUtils` library and should be imported if needed: + +```diff + import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; ++import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; + + contract Verifier { + using ECDSA for bytes32; ++ using MessageHashUtils for bytes32; + + function _verify(bytes32 data, bytes memory signature, address account) internal pure returns (bool) { + return data + .toEthSignedMessageHash() + .recover(signature) == account; + } + } +``` + +#### Interfaces and libraries in upgradeable contracts + +The upgradeable version of the contracts library used to include a variant suffixed with `Upgradeable` for every contract. These variants, which are produced automatically, mainly include changes for dealing with storage that don't apply to libraries and interfaces. + +The upgradeable library no longer includes upgradeable variants for libraries and interfaces. Projects migrating to 5.0 should replace their library and interface imports with their corresponding non-upgradeable version: + +```diff + // Libraries +-import {AddressUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol'; ++import {Address} from '@openzeppelin/contracts/utils/Address.sol'; + + // Interfaces +-import {IERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/interfaces/IERC20.sol'; ++import {IERC20} from '@openzeppelin/contracts/interfaces/IERC20.sol'; +``` + +#### Offchain Considerations + +Some changes may affect offchain systems if they rely on assumptions that are changed along with these new breaking changes. These cases are: + +##### Relying on revert strings for processing errors + +A concrete example is AccessControl, where it was previously advised to catch revert reasons using the following regex: + +``` +/^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ +``` + +Instead, contracts now revert with custom errors. Systems that interact with smart contracts outside of the network should consider reliance on revert strings and possibly support the new custom errors. + +##### Relying on storage locations for retrieving data + +After 5.0, the storage location of some variables were changed. This is the case for `Initializable` and all the upgradeable contracts since they now use namespaced storaged locations. Any system relying on storage locations for retrieving data or detecting capabilities should be updated to support these new locations. + +## 4.9.2 (2023-06-16) + +- `MerkleProof`: Fix a bug in `processMultiProof` and `processMultiProofCalldata` that allows proving arbitrary leaves if the tree contains a node with value 0 at depth 1. + +## 4.9.1 (2023-06-07) + +- `Governor`: Add a mechanism to restrict the address of the proposer using a suffix in the description. + +## 4.9.0 (2023-05-23) + +- `ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714)) +- `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. ([#3863](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3863)) +- `EnumerableMap`: add a `keys()` function that returns an array containing all the keys. ([#3920](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3920)) +- `Governor`: add a public `cancel(uint256)` function. ([#3983](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3983)) +- `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. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934)) +- `Strings`: add `equal` method. ([#3774](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3774)) +- `IERC5313`: Add an interface for EIP-5313 that is now final. ([#4013](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4013)) +- `IERC4906`: Add an interface for ERC-4906 that is now Final. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012)) +- `StorageSlot`: Add support for `string` and `bytes`. ([#4008](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4008)) +- `Votes`, `ERC20Votes`, `ERC721Votes`: support timestamp checkpointing using EIP-6372. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934)) +- `ERC4626`: Add mitigation to the inflation attack through virtual shares and assets. ([#3979](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3979)) +- `Strings`: add `toString` method for signed integers. ([#3773](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3773)) +- `ERC20Wrapper`: Make the `underlying` variable private and add a public accessor. ([#4029](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4029)) +- `EIP712`: add EIP-5267 support for better domain discovery. ([#3969](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3969)) +- `AccessControlDefaultAdminRules`: Add an extension of `AccessControl` with additional security rules for the `DEFAULT_ADMIN_ROLE`. ([#4009](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4009)) +- `SignatureChecker`: Add `isValidERC1271SignatureNow` for checking a signature directly against a smart contract using ERC-1271. ([#3932](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3932)) +- `SafeERC20`: Add a `forceApprove` function to improve compatibility with tokens behaving like USDT. ([#4067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4067)) +- `ERC1967Upgrade`: removed contract-wide `oz-upgrades-unsafe-allow delegatecall` annotation, replaced by granular annotation in `UUPSUpgradeable`. ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971)) +- `ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitly forbidden. ([#4100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4100)) +- `ECDSA`: optimize bytes32 computation by using assembly instead of `abi.encodePacked`. ([#3853](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3853)) +- `ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012)) +- `ShortStrings`: Added a library for handling short strings in a gas efficient way, with fallback to storage for longer strings. ([#4023](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4023)) +- `SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers. ([#4038](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4038)) +- `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`). ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971)) +- `Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. ([#3787](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3787)) +- `Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. ([#3960](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3960)) +- `UUPSUpgradeable.sol`: Change visibility to the functions `upgradeTo ` and `upgradeToAndCall ` from `external` to `public`. ([#3959](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3959)) +- `TimelockController`: Add the `CallSalt` event to emit on operation schedule. ([#4001](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4001)) +- Reformatted codebase with latest version of Prettier Solidity. ([#3898](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3898)) +- `Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) +- `ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748)) +- `Multicall`: annotate `multicall` function as upgrade safe to not raise a flag for its delegatecall. ([#3961](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3961)) +- `ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality ([#4007](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4007)) +- `ECDSA`: Add a function `toDataWithIntendedValidatorHash` that encodes data with version 0x00 following EIP-191. ([#4063](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4063)) +- `MerkleProof`: optimize by using unchecked arithmetic. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) + +### 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)) +- `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.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`. + +### 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)) + +## 4.8.0 (2022-11-08) + +- `TimelockController`: Added a new `admin` constructor parameter that is assigned the admin role instead of the deployer account. ([#3722](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3722)) +- `Initializable`: add internal functions `_getInitializedVersion` and `_isInitializing` ([#3598](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3598)) +- `ERC165Checker`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339)) +- `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468)) +- `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469)) +- `Governor`: make the `relay` function payable, and add support for EOA payments. ([#3730](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3730)) +- `GovernorCompatibilityBravo`: remove unused `using` statements. ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506)) +- `ERC20`: optimize `_transfer`, `_mint` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) +- `ERC20Votes`, `ERC721Votes`: optimize `getPastVotes` for looking up recent checkpoints. ([#3673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3673)) +- `ERC20FlashMint`: add an internal `_flashFee` function for overriding. ([#3551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3551)) +- `ERC4626`: use the same `decimals()` as the underlying asset by default (if available). ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639)) +- `ERC4626`: add internal `_initialConvertToShares` and `_initialConvertToAssets` functions to customize empty vaults behavior. ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639)) +- `ERC721`: optimize transfers by making approval clearing implicit instead of emitting an event. ([#3481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3481)) +- `ERC721`: optimize burn by making approval clearing implicit instead of emitting an event. ([#3538](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3538)) +- `ERC721`: Fix balance accounting when a custom `_beforeTokenTransfer` hook results in a transfer of the token under consideration. ([#3611](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3611)) +- `ERC721`: use unchecked arithmetic for balance updates. ([#3524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3524)) +- `ERC721Consecutive`: Implementation of EIP-2309 that allows batch minting of ERC721 tokens during construction. ([#3311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3311)) +- `ReentrancyGuard`: Reduce code size impact of the modifier by using internal functions. ([#3515](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3515)) +- `SafeCast`: optimize downcasting of signed integers. ([#3565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3565)) +- `ECDSA`: Remove redundant check on the `v` value. ([#3591](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3591)) +- `VestingWallet`: add `releasable` getters. ([#3580](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3580)) +- `VestingWallet`: remove unused library `Math.sol`. ([#3605](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3605)) +- `VestingWallet`: make constructor payable. ([#3665](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3665)) +- `Create2`: optimize address computation by using assembly instead of `abi.encodePacked`. ([#3600](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3600)) +- `Clones`: optimized the assembly to use only the scratch space during deployments, and optimized `predictDeterministicAddress` to use fewer operations. ([#3640](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3640)) +- `Checkpoints`: Use procedural generation to support multiple key/value lengths. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Checkpoints`: Add new lookup mechanisms. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Arrays`: Add `unsafeAccess` functions that allow reading and writing to an element in a storage array bypassing Solidity's "out-of-bounds" check. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Strings`: optimize `toString`. ([#3573](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3573)) +- `Ownable2Step`: extension of `Ownable` that makes the ownership transfers a two step process. ([#3620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620)) +- `Math` and `SignedMath`: optimize function `max` by using `>` instead of `>=`. ([#3679](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3679)) +- `Math`: Add `log2`, `log10` and `log256`. ([#3670](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3670)) +- Arbitrum: Update the vendored arbitrum contracts to match the nitro upgrade. ([#3692](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3692)) + +### Breaking changes + +- `ERC721`: In order to add support for batch minting via `ERC721Consecutive` it was necessary to make a minor breaking change in the internal interface of `ERC721`. Namely, the hooks `_beforeTokenTransfer` and `_afterTokenTransfer` have one additional argument that may need to be added to overrides: + +```diff + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId, ++ uint256 batchSize + ) internal virtual override +``` + +- `ERC4626`: Conversion from shares to assets (and vice-versa) in an empty vault used to consider the possible mismatch between the underlying asset's and the vault's decimals. This initial conversion rate is now set to 1-to-1 irrespective of decimals, which are meant for usability purposes only. The vault now uses the assets decimals by default, so off-chain the numbers should appear the same. Developers overriding the vault decimals to a value that does not match the underlying asset may want to override the `_initialConvertToShares` and `_initialConvertToAssets` to replicate the previous behavior. + +- `TimelockController`: During deployment, the TimelockController used to grant the `TIMELOCK_ADMIN_ROLE` to the deployer and to the timelock itself. The deployer was then expected to renounce this role once configuration of the timelock is over. Failing to renounce that role allows the deployer to change the timelock permissions (but not to bypass the delay for any time-locked actions). The role is no longer given to the deployer by default. A new parameter `admin` can be set to a non-zero address to grant the admin role during construction (to the deployer or any other address). Just like previously, this admin role should be renounced after configuration. If this param is given `address(0)`, the role is not allocated and doesn't need to be revoked. In any case, the timelock itself continues to have this role. + +### Deprecations + +- `EIP712`: Added the file `EIP712.sol` and deprecated `draft-EIP712.sol` since the EIP is no longer a Draft. Developers are encouraged to update their imports. ([#3621](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3621)) + +```diff +-import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; ++import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +``` + +- `ERC721Votes`: Added the file `ERC721Votes.sol` and deprecated `draft-ERC721Votes.sol` since it no longer depends on a Draft EIP (EIP-712). Developers are encouraged to update their imports. ([#3699](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3699)) + +```diff +-import "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol"; ++import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol"; +``` + +### ERC-721 Compatibility Note + +ERC-721 integrators that interpret contract state from events should make sure that they implement the clearing of approval that is implicit in every transfer according to the EIP. Previous versions of OpenZeppelin Contracts emitted an explicit `Approval` event even though it was not required by the specification, and this is no longer the case. + +With the new `ERC721Consecutive` extension, the internal workings of `ERC721` are slightly changed. Custom extensions to ERC721 should be reviewed to ensure they remain correct. The internal functions that should be considered are `_ownerOf` (new), `_beforeTokenTransfer`, and `_afterTokenTransfer`. + +### ERC-4626 Upgrade Note + +Existing `ERC4626` contracts that are upgraded to 4.8 must initialize a new variable that holds the vault token decimals. The recommended way to do this is to use a [reinitializer]: + +[reinitializer]: https://docs.openzeppelin.com/contracts/4.x/api/proxy#Initializable-reinitializer-uint8- + +```solidity +function migrateToV48() public reinitializer(2) { + __ERC4626_init(IERC20Upgradeable(asset())); +} +``` + +## 4.7.3 (2022-08-10) + +### Breaking changes + +- `ECDSA`: `recover(bytes32,bytes)` and `tryRecover(bytes32,bytes)` no longer accept compact signatures to prevent malleability. Compact signature support remains available using `recover(bytes32,bytes32,bytes32)` and `tryRecover(bytes32,bytes32,bytes32)`. + +## 4.7.2 (2022-07-25) + +- `LibArbitrumL2`, `CrossChainEnabledArbitrumL2`: Fixed detection of cross-chain calls for EOAs. Previously, calls from EOAs would be classified as cross-chain calls. ([#3578](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3578)) +- `GovernorVotesQuorumFraction`: Fixed quorum updates so they do not affect past proposals that failed due to lack of quorum. ([#3561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3561)) +- `ERC165Checker`: Added protection against large returndata. ([#3587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3587)) + +## 4.7.1 (2022-07-18) + +- `SignatureChecker`: Fix an issue that causes `isValidSignatureNow` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552)) +- `ERC165Checker`: Fix an issue that causes `supportsInterface` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552)) + +## 4.7.0 (2022-06-29) + +- `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317)) +- `CrossChainEnabledPolygonChild`: replace the `require` statement with the custom error `NotCrossChainCall`. ([#3380](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3380)) +- `ERC20FlashMint`: Add customizable flash fee receiver. ([#3327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3327)) +- `ERC4626`: add an extension of `ERC20` that implements the ERC4626 Tokenized Vault Standard. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171)) +- `SafeERC20`: add `safePermit` as mitigation against phantom permit functions. ([#3280](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3280)) +- `Math`: add a `mulDiv` function that can round the result either up or down. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171)) +- `Math`: Add a `sqrt` function to compute square roots of integers, rounding either up or down. ([#3242](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3242)) +- `Strings`: add a new overloaded function `toHexString` that converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. ([#3403](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3403)) +- `EnumerableMap`: add new `UintToUintMap` map type. ([#3338](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3338)) +- `EnumerableMap`: add new `Bytes32ToUintMap` map type. ([#3416](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3416)) +- `SafeCast`: add support for many more types, using procedural code generation. ([#3245](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3245)) +- `MerkleProof`: add `multiProofVerify` to prove multiple values are part of a Merkle tree. ([#3276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3276)) +- `MerkleProof`: add calldata versions of the functions to avoid copying input arrays to memory and save gas. ([#3200](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3200)) +- `ERC721`, `ERC1155`: simplified revert reasons. ([#3254](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3254), ([#3438](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3438))) +- `ERC721`: removed redundant require statement. ([#3434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3434)) +- `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350)) +- `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450)) +- `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) + +### Breaking changes + +- `Initializable`: functions decorated with the modifier `reinitializer(1)` may no longer invoke each other. + +## 4.6.0 (2022-04-26) + +- `crosschain`: Add a new set of contracts for cross-chain applications. `CrossChainEnabled` is a base contract with instantiations for several chains and bridges, and `AccessControlCrossChain` is an extension of access control that allows cross-chain operation. ([#3183](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3183)) +- `AccessControl`: add a virtual `_checkRole(bytes32)` function that can be overridden to alter the `onlyRole` modifier behavior. ([#3137](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3137)) +- `EnumerableMap`: add new `AddressToUintMap` map type. ([#3150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3150)) +- `EnumerableMap`: add new `Bytes32ToBytes32Map` map type. ([#3192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3192)) +- `ERC20FlashMint`: support infinite allowance when paying back a flash loan. ([#3226](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3226)) +- `ERC20Wrapper`: the `decimals()` function now tries to fetch the value from the underlying token instance. If that calls revert, then the default value is used. ([#3259](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3259)) +- `draft-ERC20Permit`: replace `immutable` with `constant` for `_PERMIT_TYPEHASH` since the `keccak256` of string literals is treated specially and the hash is evaluated at compile time. ([#3196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3196)) +- `ERC1155`: Add a `_afterTokenTransfer` hook for improved extensibility. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166)) +- `ERC1155URIStorage`: add a new extension that implements a `_setURI` behavior similar to ERC721's `_setTokenURI`. ([#3210](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3210)) +- `DoubleEndedQueue`: a new data structure that supports efficient push and pop to both front and back, useful for FIFO and LIFO queues. ([#3153](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3153)) +- `Governor`: improved security of `onlyGovernance` modifier when using an external executor contract (e.g. a timelock) that can operate without necessarily going through the governance protocol. ([#3147](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3147)) +- `Governor`: Add a way to parameterize votes. This can be used to implement voting systems such as fractionalized voting, ERC721 based voting, or any number of other systems. The `params` argument added to `_countVote` method, and included in the newly added `_getVotes` method, can be used by counting and voting modules respectively for such purposes. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: rewording of revert reason for consistency. ([#3275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3275)) +- `Governor`: fix an inconsistency in data locations that could lead to invalid bytecode being produced. ([#3295](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3295)) +- `Governor`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by governors. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230)) +- `TimelockController`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by timelocks. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230)) +- `TimelockController`: Add a separate canceller role for the ability to cancel. ([#3165](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3165)) +- `Initializable`: add a reinitializer modifier that enables the initialization of new modules, added to already initialized contracts through upgradeability. ([#3232](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3232)) +- `Initializable`: add an Initialized event that tracks initialized version numbers. ([#3294](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3294)) +- `ERC2981`: make `royaltyInfo` public to allow super call in overrides. ([#3305](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3305)) + +### Upgradeability notice + +- `TimelockController`: **(Action needed)** The upgrade from <4.6 to >=4.6 introduces a new `CANCELLER_ROLE` that requires set up to be assignable. After the upgrade, only addresses with this role will have the ability to cancel. Proposers will no longer be able to cancel. Assigning cancellers can be done by an admin (including the timelock itself) once the role admin is set up. To do this, we recommend upgrading to the `TimelockControllerWith46MigrationUpgradeable` contract and then calling the `migrateTo46` function. + +### Breaking changes + +- `Governor`: Adds internal virtual `_getVotes` method that must be implemented; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing voting module extension, rename `getVotes` to `_getVotes` and add a `bytes memory` argument. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: Adds `params` parameter to internal virtual `_countVote` method; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing counting module extension, add a `bytes memory` argument to `_countVote`. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: Does not emit `VoteCast` event when params data is non-empty; instead emits `VoteCastWithParams` event. To fix this on an integration that consumes the `VoteCast` event, also fetch/monitor `VoteCastWithParams` events. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Votes`: The internal virtual function `_getVotingUnits` was made `view` (which was accidentally missing). Any overrides should now be updated so they are `view` as well. + +## 4.5.0 (2022-02-09) + +- `ERC2981`: add implementation of the royalty standard, and the respective extensions for `ERC721` and `ERC1155`. ([#3012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3012)) +- `GovernorTimelockControl`: improve the `state()` function to have it reflect cases where a proposal has been canceled directly on the timelock. ([#2977](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2977)) +- Preset contracts are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com). ([#2986](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2986)) +- `Governor`: add a relay function to help recover assets sent to a governor that is not its own executor (e.g. when using a timelock). ([#2926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2926)) +- `GovernorPreventLateQuorum`: add new module to ensure a minimum voting duration is available after the quorum is reached. ([#2973](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2973)) +- `ERC721`: improved revert reason when transferring from wrong owner. ([#2975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2975)) +- `Votes`: Added a base contract for vote tracking with delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944)) +- `ERC721Votes`: Added an extension of ERC721 enabled with vote tracking and delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944)) +- `ERC2771Context`: use immutable storage to store the forwarder address, no longer an issue since Solidity >=0.8.8 allows reading immutable variables in the constructor. ([#2917](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2917)) +- `Base64`: add a library to parse bytes into base64 strings using `encode(bytes memory)` function, and provide examples to show how to use to build URL-safe `tokenURIs`. ([#2884](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2884)) +- `ERC20`: reduce allowance before triggering transfer. ([#3056](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3056)) +- `ERC20`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085)) +- `ERC20`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `ERC20Burnable`: do not update allowance on `burnFrom` when allowance is `type(uint256).max`. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `ERC777`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085)) +- `ERC777`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `SignedMath`: a new signed version of the Math library with `max`, `min`, and `average`. ([#2686](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2686)) +- `SignedMath`: add an `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984)) +- `ERC1967Upgrade`: Refactor the secure upgrade to use `ERC1822` instead of the previous rollback mechanism. This reduces code complexity and attack surface with similar security guarantees. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021)) +- `UUPSUpgradeable`: Add `ERC1822` compliance to support the updated secure upgrade mechanism. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021)) +- Some more functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. + +### Breaking changes + +- `ERC1967Upgrade`: The function `_upgradeToAndCallSecure` was renamed to `_upgradeToAndCallUUPS`, along with the change in security mechanism described above. +- `Address`: The Solidity pragma is increased from `^0.8.0` to `^0.8.1`. This is required by the `account.code.length` syntax that replaces inline assembly. This may require users to bump their compiler version from `0.8.0` to `0.8.1` or later. Note that other parts of the code already include stricter requirements. + +## 4.4.2 (2022-01-11) + +### Bugfixes + +- `GovernorCompatibilityBravo`: Fix error in the encoding of calldata for proposals submitted through the compatibility interface with explicit signatures. ([#3100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3100)) + +## 4.4.1 (2021-12-14) + +- `Initializable`: change the existing `initializer` modifier and add a new `onlyInitializing` modifier to prevent reentrancy risk. ([#3006](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3006)) + +### Breaking change + +It is no longer possible to call an `initializer`-protected function from within another `initializer` function outside the context of a constructor. Projects using OpenZeppelin upgradeable proxies should continue to work as is, since in the common case the initializer is invoked in the constructor directly. If this is not the case for you, the suggested change is to use the new `onlyInitializing` modifier in the following way: + +```diff + contract A { +- function initialize() public initializer { ... } ++ function initialize() internal onlyInitializing { ... } + } + contract B is A { + function initialize() public initializer { + A.initialize(); + } + } +``` + +## 4.4.0 (2021-11-25) + +- `Ownable`: add an internal `_transferOwnership(address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControl`: add internal `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControl`: mark `_setupRole(bytes32,address)` as deprecated in favor of `_grantRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControlEnumerable`: hook into `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2946](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2946)) +- `EIP712`: cache `address(this)` to immutable storage to avoid potential issues if a vanilla contract is used in a delegatecall context. ([#2852](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2852)) +- Add internal `_setApprovalForAll` to `ERC721` and `ERC1155`. ([#2834](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2834)) +- `Governor`: shift vote start and end by one block to better match Compound's GovernorBravo and prevent voting at the Governor level if the voting snapshot is not ready. ([#2892](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2892)) +- `GovernorCompatibilityBravo`: consider quorum an inclusive rather than exclusive minimum to match Compound's GovernorBravo. ([#2974](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2974)) +- `GovernorSettings`: a new governor module that manages voting settings updatable through governance actions. ([#2904](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2904)) +- `PaymentSplitter`: now supports ERC20 assets in addition to Ether. ([#2858](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2858)) +- `ECDSA`: add a variant of `toEthSignedMessageHash` for arbitrary length message hashing. ([#2865](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2865)) +- `MerkleProof`: add a `processProof` function that returns the rebuilt root hash given a leaf and a proof. ([#2841](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2841)) +- `VestingWallet`: new contract that handles the vesting of Ether and ERC20 tokens following a customizable vesting schedule. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2748)) +- `Governor`: enable receiving Ether when a Timelock contract is not used. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849)) +- `GovernorTimelockCompound`: fix ability to use Ether stored in the Timelock contract. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849)) + +## 4.3.3 (2021-11-08) + +- `ERC1155Supply`: Handle `totalSupply` changes by hooking into `_beforeTokenTransfer` to ensure consistency of balances and supply during `IERC1155Receiver.onERC1155Received` calls. + +## 4.3.2 (2021-09-14) + +- `UUPSUpgradeable`: Add modifiers to prevent `upgradeTo` and `upgradeToAndCall` being executed on any contract that is not the active ERC1967 proxy. This prevents these functions being called on implementation contracts or minimal ERC1167 clones, in particular. + +## 4.3.1 (2021-08-26) + +- `TimelockController`: Add additional isOperationReady check. + +## 4.3.0 (2021-08-17) + +- `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754)) +- `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768)) +- `Governor`: added a modular system of `Governor` contracts based on `GovernorAlpha` and `GovernorBravo`. ([#2672](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2672)) +- Add an `interfaces` folder containing solidity interfaces to final ERCs. ([#2517](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2517)) +- `ECDSA`: add `tryRecover` functions that will not throw if the signature is invalid, and will return an error flag instead. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661)) +- `SignatureChecker`: Reduce gas usage of the `isValidSignatureNow` function for the "signature by EOA" case. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661)) + +## 4.2.0 (2021-06-30) + +- `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632)) +- `ERC20VotesComp`: Variant of `ERC20Votes` that is compatible with Compound's `Comp` token interface but restricts supply to `uint96`. ([#2706](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2706)) +- `ERC20Wrapper`: add a new extension of the `ERC20` token which wraps an underlying token. Deposit and withdraw guarantee that the total supply is backed by a corresponding amount of underlying token. ([#2633](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2633)) +- Enumerables: Improve gas cost of removal in `EnumerableSet` and `EnumerableMap`. +- Enumerables: Improve gas cost of lookup in `EnumerableSet` and `EnumerableMap`. +- `Counter`: add a reset method. ([#2678](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2678)) +- Tokens: Wrap definitely safe subtractions in `unchecked` blocks. +- `Math`: Add a `ceilDiv` method for performing ceiling division. +- `ERC1155Supply`: add a new `ERC1155` extension that keeps track of the totalSupply of each tokenId. ([#2593](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2593)) +- `BitMaps`: add a new `BitMaps` library that provides a storage efficient datastructure for `uint256` to `bool` mapping with contiguous keys. ([#2710](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2710)) + +### Breaking Changes + +- `ERC20FlashMint` is no longer a Draft ERC. ([#2673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2673))) + +**How to update:** Change your import paths by removing the `draft-` prefix from `@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20FlashMint.sol`. + +> See [Releases and Stability: Drafts](https://docs.openzeppelin.com/contracts/4.x/releases-stability#drafts). + +## 4.1.0 (2021-04-29) + +- `IERC20Metadata`: add a new extended interface that includes the optional `name()`, `symbol()` and `decimals()` functions. ([#2561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2561)) +- `ERC777`: make reception acquirement optional in `_mint`. ([#2552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2552)) +- `ERC20Permit`: add a `_useNonce` to enable further usage of ERC712 signatures. ([#2565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2565)) +- `ERC20FlashMint`: add an implementation of the ERC3156 extension for flash-minting ERC20 tokens. ([#2543](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2543)) +- `SignatureChecker`: add a signature verification library that supports both EOA and ERC1271 compliant contracts as signers. ([#2532](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2532)) +- `Multicall`: add abstract contract with `multicall(bytes[] calldata data)` function to bundle multiple calls together ([#2608](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2608)) +- `ECDSA`: add support for ERC2098 short-signatures. ([#2582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2582)) +- `AccessControl`: add an `onlyRole` modifier to restrict specific function to callers bearing a specific role. ([#2609](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2609)) +- `StorageSlot`: add a library for reading and writing primitive types to specific storage slots. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542)) +- UUPS Proxies: add `UUPSUpgradeable` to implement the UUPS proxy pattern together with `EIP1967Proxy`. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542)) + +### Breaking changes + +This release includes two small breaking changes in `TimelockController`. + +1. The `onlyRole` modifier in this contract was designed to let anyone through if the role was granted to `address(0)`, + allowing the possibility to to make a role "open", which can be used for `EXECUTOR_ROLE`. This modifier is now + replaced by `AccessControl.onlyRole`, which does not have this ability. The previous behavior was moved to the + modifier `TimelockController.onlyRoleOrOpenRole`. +2. It was possible to make `PROPOSER_ROLE` an open role (as described in the previous item) if it was granted to + `address(0)`. This would affect the `schedule`, `scheduleBatch`, and `cancel` operations in `TimelockController`. + This ability was removed as it does not make sense to open up the `PROPOSER_ROLE` in the same way that it does for + `EXECUTOR_ROLE`. + +## 4.0.0 (2021-03-23) + +- Now targeting the 0.8.x line of Solidity compilers. For 0.6.x (resp 0.7.x) support, use version 3.4.0 (resp 3.4.0-solc-0.7) of OpenZeppelin. +- `Context`: making `_msgData` return `bytes calldata` instead of `bytes memory` ([#2492](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2492)) +- `ERC20`: removed the `_setDecimals` function and the storage slot associated to decimals. ([#2502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2502)) +- `Strings`: addition of a `toHexString` function. ([#2504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2504)) +- `EnumerableMap`: change implementation to optimize for `key → value` lookups instead of enumeration. ([#2518](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2518)) +- `GSN`: deprecate GSNv1 support in favor of upcoming support for GSNv2. ([#2521](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2521)) +- `ERC165`: remove uses of storage in the base ERC165 implementation. ERC165 based contracts now use storage-less virtual functions. Old behavior remains available in the `ERC165Storage` extension. ([#2505](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2505)) +- `Initializable`: make initializer check stricter during construction. ([#2531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2531)) +- `ERC721`: remove enumerability of tokens from the base implementation. This feature is now provided separately through the `ERC721Enumerable` extension. ([#2511](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2511)) +- `AccessControl`: removed enumerability by default for a more lightweight contract. It is now opt-in through `AccessControlEnumerable`. ([#2512](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2512)) +- Meta Transactions: add `ERC2771Context` and a `MinimalForwarder` for meta-transactions. ([#2508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2508)) +- Overall reorganization of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503)) +- `ERC20Capped`: optimize gas usage by enforcing the check directly in `_mint`. ([#2524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2524)) +- Rename `UpgradeableProxy` to `ERC1967Proxy`. ([#2547](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2547)) +- `ERC777`: optimize the gas costs of the constructor. ([#2551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2551)) +- `ERC721URIStorage`: add a new extension that implements the `_setTokenURI` behavior as it was available in 3.4.0. ([#2555](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2555)) +- `AccessControl`: added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562)) +- `ERC1155`: make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576)) + +### Bug fixes for beta releases + +- `AccessControlEnumerable`: Fixed `renounceRole` not updating enumerable set of addresses for a role. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572)) + +### How to upgrade from 3.x + +Since this version has moved a few contracts to different directories, users upgrading from a previous version will need to adjust their import statements. To make this easier, the package includes a script that will migrate import statements automatically. After upgrading to the latest version of the package, run: + +``` +npx openzeppelin-contracts-migrate-imports +``` + +Make sure you're using git or another version control system to be able to recover from any potential error in our script. + +### How to upgrade from 4.0-beta.x + +Some further changes have been done between the different beta iterations. Transitions made during this period are configured in the `migrate-imports` script. Consequently, you can upgrade from any previous 4.0-beta.x version using the same script as described in the _How to upgrade from 3.x_ section. + +## 3.4.2 (2021-07-24) + +- `TimelockController`: Add additional isOperationReady check. + +## 3.4.1 (2021-03-03) + +- `ERC721`: made `_approve` an internal function (was private). + +## 3.4.0 (2021-02-02) + +- `BeaconProxy`: added new kind of proxy that allows simultaneous atomic upgrades. ([#2411](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2411)) +- `EIP712`: added helpers to verify EIP712 typed data signatures on chain. ([#2418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2418)) +- `ERC20Permit`: added an implementation of the ERC20 permit extension for gasless token approvals. ([#2237](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237)) +- Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399)) +- `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) +- `Clones`: added a library for deploying EIP 1167 minimal proxies. ([#2449](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2449)) +- `Context`: moved from `contracts/GSN` to `contracts/utils`. ([#2453](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2453)) +- `PaymentSplitter`: replace usage of `.transfer()` with `Address.sendValue` for improved compatibility with smart wallets. ([#2455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2455)) +- `UpgradeableProxy`: bubble revert reasons from initialization calls. ([#2454](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2454)) +- `SafeMath`: fix a memory allocation issue by adding new `SafeMath.tryOp(uint,uint)→(bool,uint)` functions. `SafeMath.op(uint,uint,string)→uint` are now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462)) +- `EnumerableMap`: fix a memory allocation issue by adding new `EnumerableMap.tryGet(uint)→(bool,address)` functions. `EnumerableMap.get(uint)→string` is now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462)) +- `ERC165Checker`: added batch `getSupportedInterfaces`. ([#2469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2469)) +- `RefundEscrow`: `beneficiaryWithdraw` will forward all available gas to the beneficiary. ([#2480](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2480)) +- Many view and pure functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. + +### Security Fixes + +- `ERC777`: fix potential reentrancy issues for custom extensions to `ERC777`. ([#2483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483)) + +If you're using our implementation of ERC777 from version 3.3.0 or earlier, and you define a custom `_beforeTokenTransfer` function that writes to a storage variable, you may be vulnerable to a reentrancy attack. If you're affected and would like assistance please write to security@openzeppelin.com. [Read more in the pull request.](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483) + +## 3.3.0 (2020-11-26) + +- Now supports both Solidity 0.6 and 0.7. Compiling with solc 0.7 will result in warnings. Install the `solc-0.7` tag to compile without warnings. +- `Address`: added `functionStaticCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) +- `TimelockController`: added a contract to augment access control schemes with a delay. ([#2354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2354)) +- `EnumerableSet`: added `Bytes32Set`, for sets of `bytes32`. ([#2395](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2395)) + +## 3.2.2-solc-0.7 (2020-10-28) + +- Resolve warnings introduced by Solidity 0.7.4. ([#2396](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2396)) + +## 3.2.1-solc-0.7 (2020-09-15) + +- `ERC777`: Remove a warning about function state visibility in Solidity 0.7. ([#2327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2327)) + +## 3.2.0 (2020-09-10) + +### New features + +- Proxies: added the proxy contracts from OpenZeppelin SDK. ([#2335](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2335)) + +#### Proxy changes with respect to OpenZeppelin SDK + +Aside from upgrading them from Solidity 0.5 to 0.6, we've changed a few minor things from the proxy contracts as they were found in OpenZeppelin SDK. + +- `UpgradeabilityProxy` was renamed to `UpgradeableProxy`. +- `AdminUpgradeabilityProxy` was renamed to `TransparentUpgradeableProxy`. +- `Proxy._willFallback` was renamed to `Proxy._beforeFallback`. +- `UpgradeabilityProxy._setImplementation` and `AdminUpgradeabilityProxy._setAdmin` were made private. + +### Improvements + +- `Address.isContract`: switched from `extcodehash` to `extcodesize` for less gas usage. ([#2311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2311)) + +### Breaking changes + +- `ERC20Snapshot`: switched to using `_beforeTokenTransfer` hook instead of overriding ERC20 operations. ([#2312](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2312)) + +This small change in the way we implemented `ERC20Snapshot` may affect users who are combining this contract with +other ERC20 flavors, since it no longer overrides `_transfer`, `_mint`, and `_burn`. This can result in having to remove Solidity `override(...)` specifiers in derived contracts for these functions, and to instead have to add it for `_beforeTokenTransfer`. See [Using Hooks](https://docs.openzeppelin.com/contracts/3.x/extending-contracts#using-hooks) in the documentation. + +## 3.1.0 (2020-06-23) + +### New features + +- `SafeCast`: added functions to downcast signed integers (e.g. `toInt32`), improving usability of `SignedSafeMath`. ([#2243](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2243)) +- `functionCall`: new helpers that replicate Solidity's function call semantics, reducing the need to rely on `call`. ([#2264](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2264)) +- `ERC1155`: added support for a base implementation, non-standard extensions and a preset contract. ([#2014](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2014), [#2230](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2230)) + +### Improvements + +- `ReentrancyGuard`: reduced overhead of using the `nonReentrant` modifier. ([#2171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2171)) +- `AccessControl`: added a `RoleAdminChanged` event to `_setAdminRole`. ([#2214](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2214)) +- Made all `public` functions in the token preset contracts `virtual`. ([#2257](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2257)) + +### Deprecations + +- `SafeERC20`: deprecated `safeApprove`. ([#2268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2268)) + +## 3.0.2 (2020-06-08) + +### Improvements + +- Added SPX license identifier to all contracts. ([#2235](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2235)) + +## 3.0.1 (2020-04-27) + +### Bugfixes + +- `ERC777`: fixed the `_approve` internal function not validating some of their arguments for non-zero addresses. ([#2213](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2213)) + +## 3.0.0 (2020-04-20) + +### New features + +- `AccessControl`: new contract for managing permissions in a system, replacement for `Ownable` and `Roles`. ([#2112](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2112)) +- `SafeCast`: new functions to convert to and from signed and unsigned values: `toUint256` and `toInt256`. ([#2123](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2123)) +- `EnumerableMap`: a new data structure for key-value pairs (like `mapping`) that can be iterated over. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) + +### Breaking changes + +- `ERC721`: `burn(owner, tokenId)` was removed, use `burn(tokenId)` instead. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `ERC721`: `_checkOnERC721Received` was removed. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `ERC721`: `_transferFrom` and `_safeTransferFrom` were renamed to `_transfer` and `_safeTransfer`. ([#2162](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2162)) +- `Ownable`: removed `_transferOwnership`. ([#2162](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2162)) +- `PullPayment`, `Escrow`: `withdrawWithGas` was removed. The old `withdraw` function now forwards all gas. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `Roles` was removed, use `AccessControl` as a replacement. ([#2112](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2112)) +- `ECDSA`: when receiving an invalid signature, `recover` now reverts instead of returning the zero address. ([#2114](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2114)) +- `Create2`: added an `amount` argument to `deploy` for contracts with `payable` constructors. ([#2117](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2117)) +- `Pausable`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Strings`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Counters`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `SignedSafeMath`: moved to the `math` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `ERC20Snapshot`: moved to the `token/ERC20` directory. `snapshot` was changed into an `internal` function. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Ownable`: moved to the `access` directory. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Ownable`: removed `isOwner`. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Secondary`: removed from the library, use `Ownable` instead. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Escrow`, `ConditionalEscrow`, `RefundEscrow`: these now use `Ownable` instead of `Secondary`, their external API changed accordingly. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `ERC20`: removed `_burnFrom`. ([#2119](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2119)) +- `Address`: removed `toPayable`, use `payable(address)` instead. ([#2133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2133)) +- `ERC777`: `_send`, `_mint` and `_burn` now use the caller as the operator. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134)) +- `ERC777`: removed `_callsTokensToSend` and `_callTokensReceived`. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134)) +- `EnumerableSet`: renamed `get` to `at`. ([#2151](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2151)) +- `ERC165Checker`: functions no longer have a leading underscore. ([#2150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2150)) +- `ERC721Metadata`, `ERC721Enumerable`: these contracts were removed, and their functionality merged into `ERC721`. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) +- `ERC721`: added a constructor for `name` and `symbol`. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) +- `ERC20Detailed`: this contract was removed and its functionality merged into `ERC20`. ([#2161](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2161)) +- `ERC20`: added a constructor for `name` and `symbol`. `decimals` now defaults to 18. ([#2161](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2161)) +- `Strings`: renamed `fromUint256` to `toString` ([#2188](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2188)) + +## 2.5.1 (2020-04-24) + +### Bugfixes + +- `ERC777`: fixed the `_send` and `_approve` internal functions not validating some of their arguments for non-zero addresses. ([#2212](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2212)) + +## 2.5.0 (2020-02-04) + +### New features + +- `SafeCast.toUintXX`: new library for integer downcasting, which allows for safe operation on smaller types (e.g. `uint32`) when combined with `SafeMath`. ([#1926](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1926)) +- `ERC721Metadata`: added `baseURI`, which can be used for dramatic gas savings when all token URIs share a prefix (e.g. `http://api.myapp.com/tokens/`). ([#1970](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1970)) +- `EnumerableSet`: new library for storing enumerable sets of values. Only `AddressSet` is supported in this release. ([#2061](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/2061)) +- `Create2`: simple library to make usage of the `CREATE2` opcode easier. ([#1744](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1744)) + +### Improvements + +- `ERC777`: `_burn` is now internal, providing more flexibility and making it easier to create tokens that deflate. ([#1908](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1908)) +- `ReentrancyGuard`: greatly improved gas efficiency by using the net gas metering mechanism introduced in the Istanbul hardfork. ([#1992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1992), [#1996](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1996)) +- `ERC777`: improve extensibility by making `_send` and related functions `internal`. ([#2027](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2027)) +- `ERC721`: improved revert reason when transferring tokens to a non-recipient contract. ([#2018](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018)) + +### Breaking changes + +- `ERC165Checker` now requires a minimum Solidity compiler version of 0.5.10. ([#1829](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1829)) + +## 2.4.0 (2019-10-29) + +### New features + +- `Address.toPayable`: added a helper to convert between address types without having to resort to low-level casting. ([#1773](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1773)) +- Facilities to make metatransaction-enabled contracts through the Gas Station Network. ([#1844](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1844)) +- `Address.sendValue`: added a replacement to Solidity's `transfer`, removing the fixed gas stipend. ([#1962](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1962)) +- Added replacement for functions that don't forward all gas (which have been deprecated): ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976)) + - `PullPayment.withdrawPaymentsWithGas(address payable payee)` + - `Escrow.withdrawWithGas(address payable payee)` +- `SafeMath`: added support for custom error messages to `sub`, `div` and `mod` functions. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828)) + +### Improvements + +- `Address.isContract`: switched from `extcodesize` to `extcodehash` for less gas usage. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) +- `ERC20` and `ERC777` updated to throw custom errors on subtraction overflows. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828)) + +### Deprecations + +- Deprecated functions that don't forward all gas: ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976)) + - `PullPayment.withdrawPayments(address payable payee)` + - `Escrow.withdraw(address payable payee)` + +### Breaking changes + +- `Address` now requires a minimum Solidity compiler version of 0.5.5. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) +- `SignatureBouncer` has been removed from drafts, both to avoid confusions with the GSN and `GSNRecipientSignature` (previously called `GSNBouncerSignature`) and because the API was not very clear. ([#1879](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1879)) + +### How to upgrade from 2.4.0-beta + +The final 2.4.0 release includes a refactor of the GSN contracts that will be a breaking change for 2.4.0-beta users. + +- The default empty implementations of `_preRelayedCall` and `_postRelayedCall` were removed and must now be explicitly implemented always in custom recipients. If your custom recipient didn't include an implementation, you can provide an empty one. +- `GSNRecipient`, `GSNBouncerBase`, and `GSNContext` were all merged into `GSNRecipient`. +- `GSNBouncerSignature` and `GSNBouncerERC20Fee` were renamed to `GSNRecipientSignature` and `GSNRecipientERC20Fee`. +- It is no longer necessary to inherit from `GSNRecipient` when using `GSNRecipientSignature` and `GSNRecipientERC20Fee`. + +For example, a contract using `GSNBouncerSignature` would have to be changed in the following way. + +```diff +-contract MyDapp is GSNRecipient, GSNBouncerSignature { ++contract MyDapp is GSNRecipientSignature { +``` + +Refer to the table below to adjust your inheritance list. + +| 2.4.0-beta | 2.4.0 | +| ----------------------------------- | ----------------------- | +| `GSNRecipient, GSNBouncerSignature` | `GSNRecipientSignature` | +| `GSNRecipient, GSNBouncerERC20Fee` | `GSNRecipientERC20Fee` | +| `GSNBouncerBase` | `GSNRecipient` | + +## 2.3.0 (2019-05-27) + +### New features + +- `ERC1820`: added support for interacting with the [ERC1820](https://eips.ethereum.org/EIPS/eip-1820) registry contract (`IERC1820Registry`), as well as base contracts that can be registered as implementers there. ([#1677](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1677)) +- `ERC777`: support for the [ERC777 token](https://eips.ethereum.org/EIPS/eip-777), which has multiple improvements over `ERC20` (but is backwards compatible with it) such as built-in burning, a more straightforward permission system, and optional sender and receiver hooks on transfer (mandatory for contracts!). ([#1684](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1684)) +- All contracts now have revert reason strings, which give insight into error conditions, and help debug failing transactions. ([#1704](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1704)) + +### Improvements + +- Reverted the Solidity version bump done in v2.2.0, setting the minimum compiler version to v0.5.0, to prevent unexpected build breakage. Users are encouraged however to stay on top of new compiler releases, which usually include bugfixes. ([#1729](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1729)) + +### Bugfixes + +- `PostDeliveryCrowdsale`: some validations where skipped when paired with other crowdsale flavors, such as `AllowanceCrowdsale`, or `MintableCrowdsale` and `ERC20Capped`, which could cause buyers to not be able to claim their purchased tokens. ([#1721](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1721)) +- `ERC20._transfer`: the `from` argument was allowed to be the zero address, so it was possible to internally trigger a transfer of 0 tokens from the zero address. This address is not a valid destinatary of transfers, nor can it give or receive allowance, so this behavior was inconsistent. It now reverts. ([#1752](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1752)) + +## 2.2.0 (2019-03-14) + +### New features + +- `ERC20Snapshot`: create snapshots on demand of the token balances and total supply, to later retrieve and e.g. calculate dividends at a past time. ([#1617](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1617)) +- `SafeERC20`: `ERC20` contracts with no return value (i.e. that revert on failure) are now supported. ([#1655](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1655)) +- `ERC20`: added internal `_approve(address owner, address spender, uint256 value)`, allowing derived contracts to set the allowance of arbitrary accounts. ([#1609](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1609)) +- `ERC20Metadata`: added internal `_setTokenURI(string memory tokenURI)`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618)) +- `TimedCrowdsale`: added internal `_extendTime(uint256 newClosingTime)` as well as `TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime)` event allowing to extend the crowdsale, as long as it hasn't already closed. + +### Improvements + +- Upgraded the minimum compiler version to v0.5.2: this removes many Solidity warnings that were false positives. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606)) +- `ECDSA`: `recover` no longer accepts malleable signatures (those using upper-range values for `s`, or 0/1 for `v`). ([#1622](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1622)) +- `ERC721`'s transfers are now more gas efficient due to removal of unnecessary `SafeMath` calls. ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610)) +- Fixed variable shadowing issues. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606)) + +### Bugfixes + +- (minor) `SafeERC20`: `safeApprove` wasn't properly checking for a zero allowance when attempting to set a non-zero allowance. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647)) + +### Breaking changes in drafts + +- `TokenMetadata` has been renamed to `ERC20Metadata`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618)) +- The library `Counter` has been renamed to `Counters` and its API has been improved. See an example in `ERC721`, lines [17](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L17) and [204](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L204). ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610)) + +## 2.1.3 (2019-02-26) + +- Backported `SafeERC20.safeApprove` bugfix. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647)) + +## 2.1.2 (2019-01-17) + +- Removed most of the test suite from the npm package, except `PublicRole.behavior.js`, which may be useful to users testing their own `Roles`. + +## 2.1.1 (2019-01-04) + +- Version bump to avoid conflict in the npm registry. + +## 2.1.0 (2019-01-04) + +### New features + +- Now targeting the 0.5.x line of Solidity compilers. For 0.4.24 support, use version 2.0 of OpenZeppelin. +- `WhitelistCrowdsale`: a crowdsale where only whitelisted accounts (`WhitelistedRole`) can purchase tokens. Adding or removing accounts from the whitelist is done by whitelist admins (`WhitelistAdminRole`). Similar to the pre-2.0 `WhitelistedCrowdsale`. ([#1525](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1525), [#1589](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1589)) +- `RefundablePostDeliveryCrowdsale`: replacement for `RefundableCrowdsale` (deprecated, see below) where tokens are only granted once the crowdsale ends (if it meets its goal). ([#1543](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1543)) +- `PausableCrowdsale`: allows for pausers (`PauserRole`) to pause token purchases. Other crowdsale operations (e.g. withdrawals and refunds, if applicable) are not affected. ([#832](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/832)) +- `ERC20`: `transferFrom` and `_burnFrom ` now emit `Approval` events, to represent the token's state comprehensively through events. ([#1524](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1524)) +- `ERC721`: added `_burn(uint256 tokenId)`, replacing the similar deprecated function (see below). ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) +- `ERC721`: added `_tokensOfOwner(address owner)`, allowing to internally retrieve the array of an account's owned tokens. ([#1522](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1522)) +- Crowdsales: all constructors are now `public`, meaning it is not necessary to extend these contracts in order to deploy them. The exception is `FinalizableCrowdsale`, since it is meaningless unless extended. ([#1564](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1564)) +- `SignedSafeMath`: added overflow-safe operations for signed integers (`int256`). ([#1559](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1559), [#1588](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1588)) + +### Improvements + +- The compiler version required by `Array` was behind the rest of the library so it was updated to `v0.4.24`. ([#1553](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1553)) +- Now conforming to a 4-space indentation code style. ([1508](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1508)) +- `ERC20`: more gas efficient due to removed redundant `require`s. ([#1409](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1409)) +- `ERC721`: fixed a bug that prevented internal data structures from being properly cleaned, missing potential gas refunds. ([#1539](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1539) and [#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549)) +- `ERC721`: general gas savings on `transferFrom`, `_mint` and `_burn`, due to redundant `require`s and `SSTORE`s. ([#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549)) + +### Bugfixes + +### Breaking changes + +### Deprecations + +- `ERC721._burn(address owner, uint256 tokenId)`: due to the `owner` parameter being unnecessary. ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) +- `RefundableCrowdsale`: due to trading abuse potential on crowdsales that miss their goal. ([#1543](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1543)) diff --git a/lib/openzeppelin-contracts-v5.0.0/CODE_OF_CONDUCT.md b/lib/openzeppelin-contracts-v5.0.0/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..cd7770d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at contact@openzeppelin.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/lib/openzeppelin-contracts-v5.0.0/CONTRIBUTING.md b/lib/openzeppelin-contracts-v5.0.0/CONTRIBUTING.md new file mode 100644 index 0000000..1a44cc2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing Guidelines + +There are many ways to contribute to OpenZeppelin Contracts. + +## Troubleshooting + +You can help other users in the community to solve their smart contract issues in the [OpenZeppelin Forum]. + +[OpenZeppelin Forum]: https://forum.openzeppelin.com/ + +## Opening an issue + +You can [open an issue] to suggest a feature or report a minor bug. For serious bugs please do not open an issue, instead refer to our [security policy] for appropriate steps. + +If you believe your issue may be due to user error and not a problem in the library, consider instead posting a question on the [OpenZeppelin Forum]. + +Before opening an issue, be sure to search through the existing open and closed issues, and consider posting a comment in one of those instead. + +When requesting a new feature, include as many details as you can, especially around the use cases that motivate it. Features are prioritized according to the impact they may have on the ecosystem, so we appreciate information showing that the impact could be high. + +[security policy]: https://github.com/OpenZeppelin/openzeppelin-contracts/security +[open an issue]: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/new/choose + +## Submitting a pull request + +If you would like to contribute code or documentation you may do so by forking the repository and submitting a pull request. + +Any non-trivial code contribution must be first discussed with the maintainers in an issue (see [Opening an issue](#opening-an-issue)). Only very minor changes are accepted without prior discussion. + +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/lib/openzeppelin-contracts-v5.0.0/GUIDELINES.md b/lib/openzeppelin-contracts-v5.0.0/GUIDELINES.md new file mode 100644 index 0000000..4b7f5e7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/GUIDELINES.md @@ -0,0 +1,148 @@ +# Engineering Guidelines + +## Testing + +Code must be thoroughly tested with quality unit tests. + +We defer to the [Moloch Testing Guide](https://github.com/MolochVentures/moloch/tree/master/test#readme) for specific recommendations, though not all of it is relevant here. Note the introduction: + +> Tests should be written, not only to verify correctness of the target code, but to be comprehensively reviewed by other programmers. Therefore, for mission critical Solidity code, the quality of the tests are just as important (if not more so) than the code itself, and should be written with the highest standards of clarity and elegance. + +Every addition or change to the code must come with relevant and comprehensive tests. + +Refactors should avoid simultaneous changes to tests. + +Flaky tests are not acceptable. + +The test suite should run automatically for every change in the repository, and in pull requests tests must pass before merging. + +The test suite coverage must be kept as close to 100% as possible, enforced in pull requests. + +In some cases unit tests may be insufficient and complementary techniques should be used: + +1. Property-based tests (aka. fuzzing) for math-heavy code. +2. Formal verification for state machines. + +## Code style + +Solidity code should be written in a consistent format enforced by a linter, following the official [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html). See below for further [Solidity Conventions](#solidity-conventions). + +The code should be simple and straightforward, prioritizing readability and understandability. Consistency and predictability should be maintained across the codebase. In particular, this applies to naming, which should be systematic, clear, and concise. + +Sometimes these guidelines may be broken if doing so brings significant efficiency gains, but explanatory comments should be added. + +Modularity should be pursued, but not at the cost of the above priorities. + +## Documentation + +For contributors, project guidelines and processes must be documented publicly. + +For users, features must be abundantly documented. Documentation should include answers to common questions, solutions to common problems, and recommendations for critical decisions that the user may face. + +All changes to the core codebase (excluding tests, auxiliary scripts, etc.) must be documented in a changelog, except for purely cosmetic or documentation changes. + +## Peer review + +All changes must be submitted through pull requests and go through peer code review. + +The review must be approached by the reviewer in a similar way as if it was an audit of the code in question (but importantly it is not a substitute for and should not be considered an audit). + +Reviewers should enforce code and project guidelines. + +External contributions must be reviewed separately by multiple maintainers. + +## Automation + +Automation should be used as much as possible to reduce the possibility of human error and forgetfulness. + +Automations that make use of sensitive credentials must use secure secret management, and must be strengthened against attacks such as [those on GitHub Actions worklows](https://github.com/nikitastupin/pwnhub). + +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. + +* All state variables should be private. + + Changes to state should be accompanied by events, and in some cases it is not correct to arbitrarily set state. Encapsulating variables as private and only allowing modification via setters enables us to ensure that events and other rules are followed reliably and prevents this kind of user error. + +* Internal or private state variables or functions should have an underscore prefix. + + ```solidity + contract TestContract { + uint256 private _privateVar; + uint256 internal _internalVar; + function _testInternal() internal { ... } + function _testPrivate() private { ... } + } + ``` + +* Functions should be declared virtual, with few exceptions listed below. The + contract logic should be written considering that these functions may be + overridden by developers, e.g. getting a value using an internal getter rather + than reading directly from a state variable. + + If function A is an "alias" of function B, i.e. it invokes function B without + significant additional logic, then function A should not be virtual so that + any user overrides are implemented on B, preventing inconsistencies. + +* Events should generally be emitted immediately after the state change that they + represent, and should be named in the past tense. Some exceptions may be made for gas + efficiency if the result doesn't affect observable ordering of events. + + ```solidity + function _burn(address who, uint256 value) internal { + super._burn(who, value); + emit TokensBurned(who, value); + } + ``` + + Some standards (e.g. ERC20) use present tense, and in those cases the + standard specification is used. + +* Interface names should have a capital I prefix. + + ```solidity + interface IERC777 { + ``` + +* Contracts not intended to be used standalone should be marked abstract + so they are required to be inherited to other contracts. + + ```solidity + abstract contract AccessControl is ..., { + ``` + +* Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted. + +* Custom errors should be declared following the [EIP-6093](https://eips.ethereum.org/EIPS/eip-6093) rationale whenever reasonable. Also, consider the following: + + * The domain prefix should be picked in the following order: + 1. Use `ERC` if the error is a violation of an ERC specification. + 2. Use the name of the underlying component where it belongs (eg. `Governor`, `ECDSA`, or `Timelock`). + + * The location of custom errors should be decided in the following order: + 1. Take the errors from their underlying ERCs if they're already defined. + 2. Declare the errors in the underlying interface/library if the error makes sense in its context. + 3. Declare the error in the implementation if the underlying interface/library is not suitable to do so (eg. interface/library already specified in an ERC). + 4. Declare the error in an extension if the error only happens in such extension or child contracts. + + * Custom error names should not be declared twice along the library to avoid duplicated identifier declarations when inheriting from multiple contracts. diff --git a/lib/openzeppelin-contracts-v5.0.0/LICENSE b/lib/openzeppelin-contracts-v5.0.0/LICENSE new file mode 100644 index 0000000..817249a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016-2023 zOS Global Limited and contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/openzeppelin-contracts-v5.0.0/README.md b/lib/openzeppelin-contracts-v5.0.0/README.md new file mode 100644 index 0000000..9ca4157 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/README.md @@ -0,0 +1,107 @@ +# OpenZeppelin + +[![NPM Package](https://img.shields.io/npm/v/@openzeppelin/contracts.svg)](https://www.npmjs.org/package/@openzeppelin/contracts) +[![Coverage Status](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts/graph/badge.svg)](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts) +[![GitPOAPs](https://public-api.gitpoap.io/v1/repo/OpenZeppelin/openzeppelin-contracts/badge)](https://www.gitpoap.io/gh/OpenZeppelin/openzeppelin-contracts) +[![Docs](https://img.shields.io/badge/docs-%F0%9F%93%84-yellow)](https://docs.openzeppelin.com/contracts) +[![Forum](https://img.shields.io/badge/forum-%F0%9F%92%AC-yellow)](https://docs.openzeppelin.com/contracts) + +**A library for secure smart contract development.** Build on a solid foundation of community-vetted code. + + * Implementations of standards like [ERC20](https://docs.openzeppelin.com/contracts/erc20) and [ERC721](https://docs.openzeppelin.com/contracts/erc721). + * Flexible [role-based permissioning](https://docs.openzeppelin.com/contracts/access-control) scheme. + * Reusable [Solidity components](https://docs.openzeppelin.com/contracts/utilities) to build custom contracts and complex decentralized systems. + +:mage: **Not sure how to get started?** Check out [Contracts Wizard](https://wizard.openzeppelin.com/) — an interactive smart contract generator. + +:building_construction: **Want to scale your decentralized application?** Check out [OpenZeppelin Defender](https://openzeppelin.com/defender) — a secure platform for automating and monitoring your operations. + +> [!IMPORTANT] +> OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, for example, it is unsafe to upgrade from 4.9.3 to 5.0.0. Learn more at [Backwards Compatibility](https://docs.openzeppelin.com/contracts/backwards-compatibility). + +## Overview + +### Installation + +#### Hardhat, Truffle (npm) + +``` +$ npm install @openzeppelin/contracts +``` + +#### Foundry (git) + +> [!WARNING] +> When installing via git, it is a common error to use the `master` branch. This is a development branch that should be avoided in favor of tagged releases. The release process involves security measures that the `master` branch does not guarantee. + +> [!WARNING] +> Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch. + +``` +$ forge install OpenZeppelin/openzeppelin-contracts +``` + +Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.` + +### Usage + +Once installed, you can use the contracts in the library by importing them: + +```solidity +pragma solidity ^0.8.20; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +contract MyCollectible is ERC721 { + constructor() ERC721("MyCollectible", "MCO") { + } +} +``` + +_If you're new to smart contract development, head to [Developing Smart Contracts](https://docs.openzeppelin.com/learn/developing-smart-contracts) to learn about creating a new project and compiling your contracts._ + +To keep your system secure, you should **always** use the installed code as-is, and neither copy-paste it from online sources nor modify it yourself. The library is designed so that only the contracts and functions you use are deployed, so you don't need to worry about it needlessly increasing gas costs. + +## Learn More + +The guides in the [documentation site](https://docs.openzeppelin.com/contracts) will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides: + +* [Access Control](https://docs.openzeppelin.com/contracts/access-control): decide who can perform each of the actions on your system. +* [Tokens](https://docs.openzeppelin.com/contracts/tokens): create tradeable assets or collectives, and distribute them via [Crowdsales](https://docs.openzeppelin.com/contracts/crowdsales). +* [Utilities](https://docs.openzeppelin.com/contracts/utilities): generic useful tools including non-overflowing math, signature verification, and trustless paying systems. + +The [full API](https://docs.openzeppelin.com/contracts/api/token/ERC20) is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts's development in the [community forum](https://forum.openzeppelin.com). + +Finally, you may want to take a look at the [guides on our blog](https://blog.openzeppelin.com/), which cover several common use cases and good practices. The following articles provide great background reading, though please note that some of the referenced tools have changed, as the tooling in the ecosystem continues to rapidly evolve. + +* [The Hitchhiker’s Guide to Smart Contracts in Ethereum](https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05) will help you get an overview of the various tools available for smart contract development, and help you set up your environment. +* [A Gentle Introduction to Ethereum Programming, Part 1](https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094) provides very useful information on an introductory level, including many basic concepts from the Ethereum platform. +* For a more in-depth dive, you may read the guide [Designing the Architecture for Your Ethereum Application](https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317), which discusses how to better structure your application and its relationship to the real world. + +## Security + +This project is maintained by [OpenZeppelin](https://openzeppelin.com) with the goal of providing a secure and reliable library of smart contract components for the ecosystem. We address security through risk management in various areas such as engineering and open source best practices, scoping and API design, multi-layered review processes, and incident response preparedness. + +The [OpenZeppelin Contracts Security Center](https://contracts.openzeppelin.com/security) contains more details about the secure development process. + +The security policy is detailed in [`SECURITY.md`](./SECURITY.md) as well, and specifies how you can report security vulnerabilities, which versions will receive security patches, and how to stay informed about them. We run a [bug bounty program on Immunefi](https://immunefi.com/bounty/openzeppelin) to reward the responsible disclosure of vulnerabilities. + +The engineering guidelines we follow to promote project quality can be found in [`GUIDELINES.md`](./GUIDELINES.md). + +Past audits can be found in [`audits/`](./audits). + +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. + +## Contribute + +OpenZeppelin Contracts exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the [contribution guide](CONTRIBUTING.md)! + +## License + +OpenZeppelin Contracts is released under the [MIT License](LICENSE). + +## Legal + +Your use of this Project is governed by the terms found at www.openzeppelin.com/tos (the "Terms"). diff --git a/lib/openzeppelin-contracts-v5.0.0/RELEASING.md b/lib/openzeppelin-contracts-v5.0.0/RELEASING.md new file mode 100644 index 0000000..06dd218 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/RELEASING.md @@ -0,0 +1,45 @@ +# Releasing + +OpenZeppelin Contracts uses a fully automated release process that takes care of compiling, packaging, and publishing the library, all of which is carried out in a clean CI environment (GitHub Actions), implemented in the ([`release-cycle`](.github/workflows/release-cycle.yml)) workflow. This helps to reduce the potential for human error and inconsistencies, and ensures that the release process is ongoing and reliable. + +## Changesets + +[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. + +## Branching model + +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. + +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" + + checkout master + commit id: "Feature C" + commit id: "Fix A" + + checkout release-vX.Y + cherry-pick id: "Fix A" tag: "" + commit id: "Release vX.Y.0-rc.1" + commit id: "Release vX.Y.0" + + 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" +``` diff --git a/lib/openzeppelin-contracts-v5.0.0/SECURITY.md b/lib/openzeppelin-contracts-v5.0.0/SECURITY.md new file mode 100644 index 0000000..e9a5148 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/SECURITY.md @@ -0,0 +1,42 @@ +# Security Policy + +Security vulnerabilities should be disclosed to the project maintainers through [Immunefi], or alternatively by email to security@openzeppelin.com. + +[Immunefi]: https://immunefi.com/bounty/openzeppelin + +## Bug Bounty + +Responsible disclosure of security vulnerabilities is rewarded through a bug bounty program on [Immunefi]. + +There is a bonus reward for issues introduced in release candidates that are reported before making it into a stable release. + +## Security Patches + +Security vulnerabilities will be patched as soon as responsibly possible, and published as an advisory on this repository (see [advisories]) and on the affected npm packages. + +[advisories]: https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories + +Projects that build on OpenZeppelin Contracts are encouraged to clearly state, in their source code and websites, how to be contacted about security issues in the event that a direct notification is considered necessary. We recommend including it in the NatSpec for the contract as `/// @custom:security-contact security@example.com`. + +Additionally, we recommend installing the library through npm and setting up vulnerability alerts such as [Dependabot]. + +[Dependabot]: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-supply-chain-security#what-is-dependabot + +### Supported Versions + +Security patches will be released for the latest minor of a given major release. For example, if an issue is found in versions >=4.6.0 and the latest is 4.8.0, the patch will be released only in version 4.8.1. + +Only critical severity bug fixes will be backported to past major releases. + +| Version | Critical security fixes | Other security fixes | +| ------- | ----------------------- | -------------------- | +| 4.x | :white_check_mark: | :white_check_mark: | +| 3.4 | :white_check_mark: | :x: | +| 2.5 | :white_check_mark: | :x: | +| < 2.0 | :x: | :x: | + +Note as well that the Solidity language itself only guarantees security updates for the latest release. + +## Legal + +Smart contracts are a nascent technology and carry a high level of technical risk and uncertainty. OpenZeppelin Contracts is made available under the MIT License, which disclaims all warranties in relation to the project and which limits the liability of those that contribute and maintain the project, including OpenZeppelin. Your use of the project is also governed by the terms found at www.openzeppelin.com/tos (the "Terms"). As set out in the Terms, you are solely responsible for any use of OpenZeppelin Contracts and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an on-going duty by any contributor, including OpenZeppelin, to correct any flaws or alert you to all or any of the potential risks of utilizing the project. diff --git a/lib/openzeppelin-contracts-v5.0.0/audits/2017-03.md b/lib/openzeppelin-contracts-v5.0.0/audits/2017-03.md new file mode 100644 index 0000000..4cd6dbf --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/audits/2017-03.md @@ -0,0 +1,292 @@ +# OpenZeppelin Audit + +NOTE ON 2021-07-19: This report makes reference to Zeppelin, OpenZeppelin, OpenZeppelin Contracts, the OpenZeppelin team, and OpenZeppelin library. Many of these things have since been renamed and know that this audit applies to what is currently called the OpenZeppelin Contracts which are maintained by the OpenZeppelin Contracts Community. + +March, 2017 +Authored by Dennis Peterson and Peter Vessenes + +# Introduction + +Zeppelin requested that New Alchemy perform an audit of the contracts in their OpenZeppelin library. The OpenZeppelin contracts are a set of contracts intended to be a safe building block for a variety of uses by parties that may not be as sophisticated as the OpenZeppelin team. It is a design goal that the contracts be deployable safely and "as-is". + +The contracts are hosted at: + +https://github.com/OpenZeppelin/zeppelin-solidity + +All the contracts in the "contracts" folder are in scope. + +The git commit hash we evaluated is: +9c5975a706b076b7000e8179f8101e0c61024c87 + +# Disclaimer + +The audit makes no statements or warrantees about utility of the code, safety of the code, suitability of the business model, regulatory regime for the business model, or any other statements about fitness of the contracts to purpose, or their bugfree status. The audit documentation is for discussion purposes only. + +# Executive Summary + +Overall the OpenZeppelin codebase is of reasonably high quality -- it is clean, modular and follows best practices throughout. + +It is still in flux as a codebase, and needs better documentation per file as to expected behavior and future plans. It probably needs more comprehensive and aggressive tests written by people less nice than the current OpenZeppelin team. + +We identified two critical errors and one moderate issue, and would not recommend this commit hash for public use until these bugs are remedied. + +The repository includes a set of Truffle unit tests, a requirement and best practice for smart contracts like these; we recommend these be bulked up. + +# Discussion + +## Big Picture: Is This A Worthwhile Project? + +As soon as a developer touches OpenZeppelin contracts, they will modify something, leaving them in an un-audited state. We do not recommend developers deploy any unaudited code to the Blockchain if it will handle money, information or other things of value. + +> "In accordance with Unix philosophy, Perl gives you enough rope to hang yourself" +> --Larry Wall + +We think this is an incredibly worthwhile project -- aided by the high code quality. Creating a framework that can be easily extended helps increase the average code quality on the Blockchain by charting a course for developers and encouraging containment of modifications to certain sections. + +> "Rust: The language that makes you take the safety off before shooting yourself in the foot" +> -- (@mbrubeck) + +We think much more could be done here, and recommend the OpenZeppelin team keep at this and keep focusing on the design goal of removing rope and adding safety. + +## Solidity Version Updates Recommended + +Most of the code uses Solidity 0.4.11, but some files under `Ownership` are marked 0.4.0. These should be updated. + +Solidity 0.4.10 will add several features which could be useful in these contracts: + +- `assert(condition)`, which throws if the condition is false + +- `revert()`, which rolls back without consuming all remaining gas. + +- `address.transfer(value)`, which is like `send` but automatically propagates exceptions, and supports `.gas()`. See https://github.com/ethereum/solidity/issues/610 for more on this. + +## Error Handling: Throw vs Return False +Solidity standards allow two ways to handle an error -- either calling `throw` or returning `false`. Both have benefits. In particular, a `throw` guarantees a complete wipe of the call stack (up to the preceding external call), whereas `false` allows a function to continue. + +In general we prefer `throw` in our code audits, because it is simpler -- it's less for an engineer to keep track of. Returning `false` and using logic to check results can quickly become a poorly-tracked state machine, and this sort of complexity can cause errors. + +In the OpenZeppelin contracts, both styles are used in different parts of the codebase. `SimpleToken` transfers throw upon failure, while the full ERC20 token returns `false`. Some modifiers `throw`, others just wrap the function body in a conditional, effectively allowing the function to return false if the condition is not met. + +We don't love this, and would usually recommend you stick with one style or the other throughout the codebase. + +In at least one case, these different techniques are combined cleverly (see the Multisig comments, line 65). As a set of contracts intended for general use, we recommend you either strive for more consistency or document explicit design criteria that govern which techniques are used where. + +Note that it may be impossible to use either one in all situations. For example, SafeMath functions pretty much have to throw upon failure, but ERC20 specifies returning booleans. Therefore we make no particular recommendations, but simply point out inconsistencies to consider. + +# Critical Issues + +## Stuck Ether in Crowdsale contract +CrowdsaleToken.sol has no provision for withdrawing the raised ether. We *strongly* recommend a standard `withdraw` function be added. There is no scenario in which someone should deploy this contract as is, whether for testing or live. + +## Recursive Call in MultisigWallet +Line 45 of `MultisigWallet.sol` checks if the amount being sent by `execute` is under a daily limit. + +This function can only be called by the "Owner". As a first angle of attack, it's worth asking what will happen if the multisig wallet owners reset the daily limit by approving a call to `resetSpentToday`. + +If a chain of calls can be constructed in which the owner confirms the `resetSpentToday` function and then withdraws through `execute` in a recursive call, the contract can be drained. In fact, this could be done without a recursive call, just through repeated `execute` calls alternating with the `confirm` calls. + +We are still working through the confirmation protocol in `Shareable.sol`, but we are not convinced that this is impossible, in fact it looks possible. The flexibility any shared owner has in being able to revoke confirmation later is another worrisome angle of approach even if some simple patches are included. + +This bug has a number of causes that need to be addressed: + +1. `resetSpentToday` and `confirm` together do not limit the days on which the function can be called or (it appears) the number of times it can be called. +1. Once a call has been confirmed and `execute`d it appears that it can be re-executed. This is not good. +3. `confirmandCheck` doesn't seem to have logic about whether or not the function in question has been called. +4. Even if it did, `revoke` would need updates and logic to deal with revocation requests after a function call had been completed. + +We do not recommend using the MultisigWallet until these issues are fixed. + +# Moderate to Minor Issues + +## PullPayment +PullPayment.sol needs some work. It has no explicit provision for cancelling a payment. This would be desirable in a number of scenarios; consider a payee losing their wallet, or giving a griefing address, or just an address that requires more than the default gas offered by `send`. + +`asyncSend` has no overflow checking. This is a bad plan. We recommend overflow and underflow checking at the layer closest to the data manipulation. + +`asyncSend` allows more balance to be queued up for sending than the contract holds. This is probably a bad idea, or at the very least should be called something different. If the intent is to allow this, it should have provisions for dealing with race conditions between competing `withdrawPayments` calls. + +It would be nice to see how many payments are pending. This would imply a bit of a rewrite; we recommend this contract get some design time, and that developers don't rely on it in its current state. + +## Shareable Contract + +We do not believe the `Shareable.sol` contract is ready for primetime. It is missing functions, and as written may be vulnerable to a reordering attack -- an attack in which a miner or other party "racing" with a smart contract participant inserts their own information into a list or mapping. + +The confirmation and revocation code needs to be looked over with a very careful eye imagining extraordinarily bad behavior by shared owners before this contract can be called safe. + +No sanity checks on the initial constructor's `required` argument are worrisome as well. + +# Line by Line Comments + +## Lifecycle + +### Killable + +Very simple, allows owner to call selfdestruct, sending funds to owner. No issues. However, note that `selfdestruct` should typically not be used; it is common that a developer may want to access data in a former contract, and they may not understand that `selfdestruct` limits access to the contract. We recommend better documentation about this dynamic, and an alternate function name for `kill` like `completelyDestroy` while `kill` would perhaps merely send funds to the owner. + +Also note that a killable function allows the owner to take funds regardless of other logic. This may be desirable or undesirable depending on the circumstances. Perhaps `Killable` should have a different name as well. + +### Migrations + +I presume that the goal of this contract is to allow and annotate a migration to a new smart contract address. We are not clear here how this would be accomplished by the code; we'd like to review with the OpenZeppelin team. + +### Pausable + +We like these pauses! Note that these allow significant griefing potential by owners, and that this might not be obvious to participants in smart contracts using the OpenZeppelin framework. We would recommend that additional sample logic be added to for instance the TokenContract showing safer use of the pause and resume functions. In particular, we would recommend a timelock after which anyone could unpause the contract. + +The modifiers use the pattern `if(bool){_;}`. This is fine for functions that return false upon failure, but could be problematic for functions expected to throw upon failure. See our comments above on standardizing on `throw` or `return(false)`. + +## Ownership + +### Ownable + +Line 19: Modifier throws if doesn't meet condition, in contrast to some other inheritable modifiers (e.g. in Pausable) that use `if(bool){_;}`. + +### Claimable + +Inherits from Ownable but the existing owner sets a pendingOwner who has to claim ownership. + +Line 17: Another modifier that throws. + +### DelayedClaimable + +Is there any reason to descend from Ownable directly, instead of just Claimable, which descends from Ownable? If not, descending from both just adds confusion. + +### Contactable + +Allows owner to set a public string of contract information. No issues. + +### Shareable + +This needs some work. Doesn't check if `_required <= len(_owners)` for instance, that would be a bummer. What if _required were like `MAX - 1`? + +I have a general concern about the difference between `owners`, `_owners`, and `owner` in `Ownable.sol`. I recommend "Owners" be renamed. In general we do not recomment single character differences in variable names, although a preceding underscore is not uncommon in Solidity code. + +Line 34: "this contract only has six types of events"...actually only two. + +Line 61: Why is `ownerIndex` keyed by addresses hashed to `uint`s? Why not use the addresses directly, so `ownerIndex` is less obscure, and so there's stronger typing? + +Line 62: Do not love `++i) ... owners[2+ i]`. Makes me do math, which is not what I want to do. I want to not have to do math. + +There should probably be a function for adding a new operation, so the developer doesn't have to work directly with the internal data. (This would make the multisig contract even shorter.) + +There's a `revoke` function but not a `propose` function that we can see. + +Beware reordering. If `propose` allows the user to choose a bytes string for their proposal, bad things(TM) will happen as currently written. + + +### Multisig + +Just an interface. Note it allows changing an owner address, but not changing the number of owners. This is somewhat limiting but also simplifies implementation. + +## Payment + +### PullPayment + +Safe from reentrance attack since ether send is at the end, plus it uses `.send()` rather than `.call.value()`. + +There's an argument to be made that `.call.value()` is a better option *if* you're sure that it will be done after all state updates, since `.send` will fail if the recipient has an expensive fallback function. However, in the context of a function meant to be embedded in other contracts, it's probably better to use `.send`. One possible compromise is to add a function which allows only the owner to send ether via `.call.value`. + +If you don't use `call.value` you should implement a `cancel` function in case some value is pending here. + +Line 14: +Doesn't use safeAdd. Although it appears that payout amounts can only be increased, in fact the payer could lower the payout as much as desired via overflow. Also, the payer could add a large non-overflowing amount, causing the payment to exceed the contract balance and therefore fail when withdraw is attempted. + +Recommendation: track the sum of non-withdrawn asyncSends, and don't allow a new one which exceeds the leftover balance. If it's ever desirable to make payments revocable, it should be done explicitly. + +## Tokens + +### ERC20 + +Standard ERC20 interface only. + +There's a security hole in the standard, reported at Edcon: `approve` does not protect against race conditions and simply replaces the current value. An approved spender could wait for the owner to call `approve` again, then attempt to spend the old limit before the new limit is applied. If successful, this attacker could successfully spend the sum of both limits. + +This could be fixed by either (1) including the old limit as a parameter, so the update will fail if some gets spent, or (2) using the value parameter as a delta instead of replacement value. + +This is not fixable while adhering to the current full ERC20 standard, though it would be possible to add a "secureApprove" function. The impact isn't extreme since at least you can only be attacked by addresses you approved. Also, users could mitigate this by always setting spending limits to zero and checking for spends, before setting the new limit. + +Edcon slides: +https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view + +### ERC20Basic + +Simpler interface skipping the Approve function. Note this departs from ERC20 in another way: transfer throws instead of returning false. + +### BasicToken + +Uses `SafeSub` and `SafeMath`, so transfer `throw`s instead of returning false. This complies with ERC20Basic but not the actual ERC20 standard. + +### StandardToken + +Implementation of full ERC20 token. + +Transfer() and transferFrom() use SafeMath functions, which will cause them to throw instead of returning false. Not a security issue but departs from standard. + +### SimpleToken + +Sample instantiation of StandardToken. Note that in this sample, decimals is 18 and supply only 10,000, so the supply is a small fraction of a single nominal token. + +### CrowdsaleToken + +StandardToken which mints tokens at a fixed price when sent ether. + +There's no provision for owner withdrawing the ether. As a sample for crowdsales it should be Ownable and allow the owner to withdraw ether, rather than stranding the ether in the contract. + +Note: an alternative pattern is a mint() function which is only callable from a separate crowdsale contract, so any sort of rules can be added without modifying the token itself. + +### VestedToken + +Lines 23, 27: +Functions `transfer()` and `transferFrom()` have a modifier canTransfer which throws if not enough tokens are available. However, transfer() returns a boolean success. Inconsistent treatment of failure conditions may cause problems for other contracts using the token. (Note that transferableTokens() relies on safeSub(), so will also throw if there's insufficient balance.) + +Line 64: +Delete not actually necessary since the value is overwritten in the next line anyway. + +## Root level + +### Bounty + +Avoids potential race condition by having each researcher deploy a separate contract for attack; if a research manages to break his associated contract, other researchers can't immediately claim the reward, they have to reproduce the attack in their own contracts. + +A developer could subvert this intent by implementing `deployContract()` to always return the same address. However, this would break the `researchers` mapping, updating the researcher address associated with the contract. This could be prevented by blocking rewrites in `researchers`. + +### DayLimit + +The modifier `limitedDaily` calls `underLimit`, which both checks that the spend is below the daily limit, and adds the input value to the daily spend. This is fine if all functions throw upon failure. However, not all OpenZeppelin functions do this; there are functions that returns false, and modifiers that wrap the function body in `if (bool) {_;}`. In these cases, `_value` will be added to `spentToday`, but ether may not actually be sent because other preconditions were not met. (However in the OpenZeppelin multisig this is not a problem.) + +Lines 4, 11: +Comment claims that `DayLimit` is multiowned, and Shareable is imported, but DayLimit does not actually inherit from Shareable. The intent may be for child contracts to inherit from Shareable (as Multisig does); in this case the import should be removed and the comment altered. + +Line 46: +Manual overflow check instead of using safeAdd. Since this is called from a function that throws upon failure anyway, there's no real downside to using safeAdd. + +### LimitBalance + +No issues. + +### MultisigWallet + +Lines 28, 76, 80: +`kill`, `setDailyLimit`, and `resetSpentToday` only happen with multisig approval, and hashes for these actions are logged by Shareable. However, they should probably post their own events for easy reading. + +Line 45: +This call to underLimit will reduce the daily limit, and then either throw or return 0. So in this case there's no danger that the limit will be reduced without the operation going through. + +Line 65: +Shareable's onlyManyOwners will take the user's confirmation, and execute the function body if and only if enough users have confirmed. Whole thing throws if the send fails, which will roll back the confirmation. Confirm returns false if not enough have confirmed yet, true if the whole thing succeeds, and throws only in the exceptional circumstance that the designated transaction unexpectedly fails. Elegant design. + +Line 68: +Throw here is good but note this function can fail either by returning false or by throwing. + +Line 92: +A bit odd to split `clearPending()` between this contract and Shareable. However this does allow contracts inheriting from Shareable to use custom structs for pending transactions. + + +### SafeMath + +Another interesting comment from the same Edcon presentation was that the overflow behavior of Solidity is undocumented, so in theory, source code that relies on it could break with a future revision. + +However, compiled code should be fine, and in the unlikely event that the compiler is revised in this way, there should be plenty of warning. (But this is an argument for keeping overflow checks isolated in SafeMath.) + +Aside from that small caveat, these are fine. + diff --git a/lib/openzeppelin-contracts-v5.0.0/audits/2018-10.pdf b/lib/openzeppelin-contracts-v5.0.0/audits/2018-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d5bf12741c8a6d44ed597de7204fde72d91dec35 GIT binary patch literal 1000527 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%0AXGSxD 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%0Ds@WxhHVsCq?&%C$272odl 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

{23QAMhgmDFwY9!) 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

%X-{jq)zF)pGEGKPHkt7x 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

@!c9KnY4NvNgEvnPA? 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

QsKH{N_IQtXo9hrt1|lnPuADU$b1Mf#WXL540@w zE<8@#F0Z8OQxUAFsjSgKwwhJD+i5%cV&Ul8z(u5vo@C4{Sa@78++QjDNjO}NSzP!J zEF1A8vI^c3Ml)v>mo(K7Ze+e)Qol0+;n4{k;B$2Ea^cjyNbaRX>g8DMIY7)wN;Ap4s1QrbZe#tE*5V``zp#LMbd0k* zyt}*?88(@Q#xrr}_&P`1MDLw@di^-2mEG^NJ6nViKOwLe+-5(nRz+kG%f{oKcdB2% z)Y$K7_A2h6@k+M$`EcS&4=TT>B66uMFGB8c*j1}z%+$D_dF@YVTs_uVK~L9=^m%&; zx<0+3kYUyl4lFS>&5ACFR+pGr zCWU59xj;fP1n-ZiW%HwLCQ9rDznh?3h`5J@7OfDIc$2S*B;{ccIcoRk8_x zB<%P@B~t@)I?g7{5nPkOrvpWKu2J%5Sd{e3_W=*ZMN>GWq5{%PW}dyBdrm2b5r>Sd;WUmJT7;@%JP-o2;ZM&zu`w7PG+FBd?2brht`)&#Dh)%tM zI5V|){ffS+l+OK`L6hHamtk&t2PKag)Gp5*ZCvF^c$&PAbQ(9=ezln`Sx(dYc7@oC zszF7|)26D{sut5`p+Rk_f=)Rs%ixc))F9I~(X^qGg%Og^k2d0$`XwlulGw-gZApw+ zg*;a^=67bKYZU5U>xPo5DKN#gWsPh2k44pyNv)n~qd=~CMPQ73wvD4Uy01KS+@r;}n zCFI;N_;Pk?@B$vev$=tGocD}=0(FxS#7HKgHv?~IL%X~3BchkOG&)x(#%x@*xvkPN z5s>)zN7N?hR&Ei;lEwxrIAR?i*mInzs)x>c(5j5nEh8UlR@f=_NMuESHcI4|dJs z^wSFr;_?jt6&KasK(vFv`eKRd6Yq9uJ+Rd>V${lg!1g zF(N8hesC2$6RMOi^38_ept4iO5mk)A8nncRmg#u!W%O{K>NONOm94QZ3y9ZbeLl@y zA$|Id7SRAPBNM#k?QlFg^rlr_&CSBhA+DpkT&q8smZ#c`!%?{n2hv!S^w@1-GBzPI zM7+EHk`dT7DWoIPL!M-#e zF9b!xU?bZ_-DM2(dz6+A7GPUUM2$B|gag9`sunbn>ln@J?|g?d7ja{Qba(tysH5=f zgG?Z!0XJzSgleCH1B_E$zCj7!#sC3dIETOD?fb`C%pkYhM$%ixS+Vz8gd)#QWYBXI zL&a|&VPrCK{%8}lL*V&&c_T6!Eh7I2Q*b65X8(b&qT(^o^}{z21ijUn6)bDFF2Wq1 zDgQJ-tfI9`mIZx5ee z*BOwlhNf@{kzg&j%ogRXN^9rYIqaJ{0nVL&nER@s1omPM1ddcG#{kSkR3|u;TaMC# z-t$&a0<0kY3^Ix|XcOBQT2=@xy#{z#W^$zW%&QorkS^~pnEG}n`MctScT=`IQ+s6i zYz%*3Yoiiz5vG)3$H$mq#VS_Q35oKmL)5iwk_ozvU%?w)P!nYko1Of%RG>)nE#MQ+0f zlO@59IMZ9%%YbDRd}!olf4`BCtDitUKT%fLGB%-5h$%)Km2C|?gVr8HAcRJ^|Cqm7 z&Bo|MA+8*Qnqh%bhTfjx0W~&{WDlj;*QTMbXD~ehGn3t@R(y?gb?Q$`-_&9jCMUQ6 zqR`TDc)1XA&oSXa0Js&_0C*U?6RyJ;YCucdrUDeMdGuwqK+qbO*iNhSR1A`*Zd~n+ zC5dz5Io3f#nI1l?enx@7dQ0m6lj9THf=O{eAH00z`!IJa&M*h>`r;Y1s;z4XR)I#yPT5SQ0qeyc1D7|!qHmj#<1!6)rEa&q!7$haw~J(;62yt&1b? z^PQhFGnXUzV2X6dzv3F#i$So2HKY&At#{{HmU+8c_i~JUg9R7D5SX9J<1dMT+H2*X zK#?{vO&a!F{gUC!^vNZk5a5^i+>OIdVMcC79+)3sMR?}tv%O8KYsi`9-+ufD?x&#v;< z#xv!NYDkCI^Q;|%-bsY~MQX~S4CEx#cseOYnXhBfPc(z{8XWCB51@({8sX?%T$;F! zsNe1~hO#lFB+G~MA}spah`8X}x#DzdLk#ifzl=SFveBxfl5c7c<`UBcKNnFkcG{!& z9bakk$Z*)`Rt;ezxW`RlHZyTblUzIc*e{lcIPd49Uy#giwb$=Immcj7pB_$h?xu}C zQB5}vD7{C&lE3o2Y|&*n?bbBZ-{f*|;J26%L+v+ykZ($PF_xLF#M1vl#ss(lRANzX zsDIbQT{krn76=*9%UeqSM3!ceW}a6>+qTRkS={%SRI-=?0ToX8Il5sSsdKz-Mx3sW zw%)q&Pd#HfCprB2OmCYRxpQ(E0=K2b{uOjC>= z6U`7C=3WHe#bU|7ui++SQt)*WZ7c6qFD-VfamrX~6N0p9TFh`oJ+C@=M{ z@-T#nDvAB~T{8$_T73~rqd+mfSiCcK`+^Dow^h#N(g~&?9N>CGuguXN7~C~mNa+GN zRjF3W4bV4Qq5#S$1i`tZUhtJM=CNH{9T8V;6txJ+6KkAc)I3M{#!`FfnnCoKy~s^` z=TOi{2Wz5XLENok9D9GN9$`|fD?bW3j6l_OXflI}*Z~w%(RG4Eo2%j7t~F)Um3iJi z{_f>%YHxLc(XR9l?bn;~y1>`?3bI0sQM!`R$;>>Q-{`yL6_S>F0-xzT;P@8TV@N!6 zpu0BoCK&?L?O9j!cAICbn;{Q=KCgW#OlePeAzL0^zO`M`9R6c7qTNfF2-C%ryyypW5!kKU?@)gIdmx|+^B zt~57t*=>}4+aqTs(h?xj|DCDeI1y>{^b;f(P<;fS#=+pz{RflGUs7{WkI=w>3WgSb zMo8$VR#?P`bRgVCvoe4(3P-~)U9Q{&->Rl<^%SsK zu)1f1+k_)=4iE~HouNqw$+8TxUmhIjCSVvfz1c#IVYuE?RSNnCJ!3fS)q6rThBvdC zFK(&@Un+Vc=>18zwYz!@IOrU`kJuv(r-jXiX6$l>8Ypfh%3yaC;EniVbtAqYvS2mn z?ZABd_A6e^wqSXN82nG02Rdg*|1KY@rTBdJJp7JC#Py-X^X-Jp4oS96@@mVB3{zzztk4(-=;M3DWBv za;{jI^wjKCa1zh$E1?tQ=BXexg0cPWa>W|vj5wcr=L`x8A5n=?7_%Vu9wE)q00A;> zLw*(sXEHV)G75qmpS38$s9!DLk{{uh2CV;Km=NJejQ1|?7sQ&3*^iNQ4z z6NIEFFAsePM|X3Kdzyj4st)##=2Db<(E7Emnf;i?drRl^j@@)o`s8wKo~3qZ*Qf5o>^;931jr7UecA zI_H9JJNXjSEinz(3$!V1fI3U7R#b;|uGA`Yy3Ak}D7=fw(Wsh*GG($+HY4^Bju<~C zNWso1oh3^__pBFBZ(Mt7?t;XHLx;dW153zJm3SG(xr>pxF#hPx*tGHPGp%U;fs zpW^+DoFVkcWsqE$SUGsPLI-hrL`i8ehf`lGs=whdF3#t@+7?_3c@2PSif_Fq3{!k* z8h35{e{fEyvcS|bZhjf=ae*o*RV*r*5C~Q8pOZ7@KA9#eC^GPw_###FC0mI<*xmAm zU#pu;inS_26ZJ&&s}H=os4xuelt)FdBEwgkQY2!fGOw#GSS6BE!DvsYg%YpKqgp5p zbqJS6jBt%kA>3TG@f!KzrjUF08Q3AsVyIk!NcLpm8J49IdD8`I;XRs+ZgE{9kTOFW zwJ=7BQshxLYFsTsUrJ`T(G5e<0D%RYpFgV_#mH$yZ6hUpdMn2Og@>0EW+YIGY zGIY?Luyou|*Kz4qBq`!Nxg@I;dG&Hx@pZAHYJb(6>qPL_@U|%<&L&MJRi}`BP;*A0 zyvA`MXZg05zv7~vI{JL{9di=7mL?pdMR2)EtzRqra`4r=+F>K{ZgNT99As{;oPTD> zEw6qWAo62dp0L_<;-wO$lAKry>>;a`%T>gYzSSRLr;pL0oul@CmpZ}lgr`)t{C4ey z^>DXIpXrYSAs-Kjr7m1KK+D8eq9uusl+7SRc_Wyk&=dfWQn3?0|#O?-+T^ z2s4;Mo>?;i;$=_t?k_{C6}+`3vhsj64JAdyUk2&2<@sFaqa!(i zS}76J-RLtu`p#LlT%|OeHSVMB6nIJP#Arg*nkPIlHDUgqLg#*U|69j;P2LHRC5Be& z=3xz*ERI;YMo&5puN!zvoi4AkwgEkxeQzxjn!vr8Uj`9-+*P_-GhF=CmNt&qidHEc zM2|jbC4!|=pHkvdsJ?#{!4pTR$Fig(eF1U*@aD1C!8^dL=g%^MPV$vNl z$Fe;UKmTowh15(w1><8yS*4YE)J<1~1$Eb~`sm|(dHBn6HaT3zo|&LJ&O|+MzzwwU zb|ZI-g|Xpeey@C1T~Q_sS4H5VPeO`kMCdixoGWjz}wpDI5Cq=jkIs7K+&$` z8Gx25UVbs0^7Mw^y;UeYToBsDX~KZY+JEnSczIS>EKuRHf!j=cd4B1{N43c0#8nC7 z_UVp#;Z(K@tNi_@vYOR!eIbJ3*@RIMtHQ<5ysf>m^m)tZx`rA4k(LdrjsV+57&Du= zCLzcriaG#p`{7JYw!q$4_woTkwCG}$J9!B~ge4(|4hc-d0MtGu0v-p@ufXd?t<*s5OCu{fVS+wP^VlyNB!hVTX!#A(@8yTq85epeh1?`^-wPYaMMRZ)^268a2Opz^ zuBKas-P-PpR0*ukn;$_P-%ehclHKW2exe8d4;=M z^o2K*`Jl^sQDS&Gs2#P;@#vzM`Knv>;~iN#Cf)z)T7#UAOMQsEs+$k-c?BSzkm-j2LmEF_RvD4BH!k&M$etNN~tVpt$uQES5NLqBS z?r140#2V;SU6UOsWYf~{HOTRV{4uApRJW|LCBG;1N1Q}GJqa#3Pz(#rE&YeBJB`$4 zSQ5MC?x(~`)&XN~Rfj%KMTHXj>c%ECv0N$you!}t^Ybc=%*`RC%+1uLcL)s-F49c+ z18a&Z3UsV#SZKPXnD%x;;TZ%|8PqbFEH*8&6B=u0TAGoTeZ`WQY^Aod{T-?C zMbfdwXrsTS(^Tn=gncty7H|FhMj#c8(;|)c#?2jtvnyK-T!&b>GF-wh1-iLg?y(M8 zlmNm31TBX?=vNEhc1`(NLv2F5hPVqIB!!X4ZN*W3(edGcD zU%Ce1rC`$%r_to7e_*2-j5kbHR+?2E?&<1;wVu*<$oV)b?R{5+aa-W`hyH$_0=U@U zcb(K&KCwdU(`~A_WnL&}GL^qW8=qK!uWVGpC=WO92u~z=Xg_w~zAZq%5ndSSU*-`} zlmHhyON!?{L@t+Y%z7Bw_?q|vId7Tk9I&U@5ODxkZ@fQZWHFcE;@AP>oKxNXVOm*DK zR{|-qH>-$cd;palvR?Uf(W7FQXuA0iiy!-#sQOlby(}Qvjm)!jwRLH^RJBEEb;(W9 z5>Q96=ceCQ`w9Om_5GrL<-=C^rF@&YNDtT1UL56aelVFGWI4wC?5E29h_%-pzQ&vW zT032-+-JMFpX_FV4I=K+?q9Rl-fbJwwj!NrFixSHCeXfrwwOe7jZGQZPSU?44pFwVwM0^h=b7`4fg0}_tY=ylWKN6J!*eF1 z(r5E0F?r9W31=lEuJN|5yq4SW>oJIteN?pHk+Y~-z?w&t0U=sM(<%M$uF`+Vga0q0 zAk+Wh)o96&{bj8>Zcw?4g1@Zs@{~!}G!-`n0^Ud)hx0BYHH>%(QdP!eA>6Pc@>>sL-n` z{jhL}6H})ilI$C7nJ_$-@EV0}WGk05_?-l>hF0n%NJB07Xfp+HDPly&*b5Rtk( zcgDQ45^CR`fPEOHthjYpdQsZc0;oC;QXHzdV)DFcAu3CeeN(b)I1iMkN~#m$*FpL} zLlN@}Y&>|L$gIiqv6H{{R+f99l$L!IdP~;-_i_14Wd4^c#Q$&aO5R4_#?j^31-M?3&6I3Cf{|8DEG;%PoH?wuLvHwTW{p%P0|KhFyVBd=g z$Obm9{)JaD0@!Hj8JPe8Ee1vnCLoydWdVRiVJ0A0DP>}#|J%*K4<=R?FyaIRD{G8w z^t3=m7BH*?c9OttfDFu9VACB8>;b{^EKFeJiGYb-0}Kz-GBPrQttTcH4Q3X`f5A@# z%uKAb46NV)2$+EYTCf$x%1Xct4uS1&33! zz)H*f&z6~ith8XGiUG`S0hz!mD=Uyqi86B{c4+$ENOs8<$nJ0Ke^cKG8* z#eZ>OOiW;H3*3RfCfL9C45SCrGO;j#6967ST2^LorwD-bth6lu^b|K%$!E5~c zH86(8s=){ryjWTP#>>daMhjqLWB{j#iBaQ!j-CHY7yD05^S^X4FbxLYB@-*1fS#?W zk(r69BLO%LS~eyy;`R4f{(IEZFoJnw1^_tZzeF|IhX(v}sQ<&~(y%Zx(}KGW1h)dG zl#T80C^9gB2b>L@J{B-81_Te%-x2-4aj}1C#Q%+p{pU&gzu97}OyCg){0-}$vIKwE z`=4{||0qiE&pGt}ZHqC2llkAa7$cC86?}4oPkSRhEBLRj8Rs1?o+t|sP@dMQ8-TbC zM`TfF|GFz2Cexr(WL4PwRhAW~Ord&hR)PiN*L9IH&o2zQInJ z42jg5E<=9D9H7B1Gf(|V#R;2DZ@xwEcU%^kxqNa+Cu5o8^DxgIx|f8b7Np$j)64** zP%;88MudgVNA;*dL092rbc}51lPEkDhRSz=Ny3(9R5{D?*}C3OLtgiQimhY{Y9q~_ z2AKP%-q4%SmQ5hI*38xP-8tencw8xx7a0n=tZ7^Eu_8gWA-jpj0@vTiGjiD~RoG|? zhc0bo0rTBl-R$WU&y=TcD}hB_G6LvEx2j(UU)P56RvF=Wc2urR@3Hg?%TKlmSsd=I{CVTvB1gO6F2AQ3gQl0XhKZ>xr z{KN`@PoNH#w{Xsy75X0e+sl;s;mN1(uJ0!eFFNl=Hf+KNpN_^46pS%HE zlXidXwxuL1qJJTs~j_R1+34Rz+oD~DGuBCMcr@> zUTslMr!{VM1QLU;FjSq@X?~Lc-A34D6nFXprL1p^QfTc%7rJcen-iAxR3SHK5Sazl z<(bW^NJDT*vS-Gs#gtqi=f@4FOPhGBBjYRb2^5c#>>d!~aF)2jqXHl?nymRTgDl*7 zK5dI{ER=SF^!g5(=7SVz+apy;rpGa?nkaFir#&OhG{kZ zo>q%9^s8|u$IpjFJ<8aojT8$_DQ#bjY&FpAeyt*9iJFVwYNgGI&sWF6m zUS4~sxGbT2-c6z797v;6P`mtF>=)qd%Ig41hOXbZ=)Xzp>G=m}b^TzH84%$ResyMeqE6 zc}y9ln(HH;u1J%#DhKqGYOq5(eGvXI{H1T?yoR^vUH@E*Gj7%m(tuuc`x=LQ;5h+& z!(9Mqp>Xh8?c~EoRQ<&-?GCB)v)^V}R=Dsp86m}1CE-n&FYfTKH8hd66Mgl?3LT<_ ze2hsH`|5`1;n&GO>H8fF8Q7o=Ok=G`m_B-14tn%QUVR-#d{~P!%TN`Hz|EgIV;VI` zE+JkM*An7LBVboxnZe?=W!k;V4YRBu#e6qX{HV1nGnlP6zg#_Fr#89ZC zxYk43~>XeI6FG($gs4rqV*{ zyMX@l8846dT6?^*4+97@>4E}nMzSmAQ;UBmMF%2$?AFtnmXRHTZRG zfwIa%ADuxqU}XFWtK9z+UOlp88{yuvC0OUqzEv3c4+^FeQK zy8Y!3?nt-r)1PzNbEY8Xx%rP5?my~_F-Iyi(wym6%5CKhDgvv@m}uCCbEY(g(9N1w zp$oIq6en-1m0xmi9U+ChD$Etb@9RqDN>b&T->HC>UmC5Po>2oaU*O$9)$=7IN?H|` zg6Ek^>E+KYWJ*qDWfGC>N(%+?Zx(PR7_eI)5d!WKR(V{`QJ?Ox=A5yg?FrQw3}s}B zaMe*+Dpj}vBf~?$ETew<{#ybZMpsoB*N=#eu7#W^ zIw52g5MYI?=Xcci7*UEog2X;E$`J>ie#)a*`X z?rjvV%(-fO>pu*C@>JGTwJW0)e5$lzb=f$u3;X6fL-nIug-bsp7JZ_n?Bq8uU9o=r zO7%dgL)km?GyB44B3ewZoU(2^sb5JJvp=n{-|A1wq4R?OZ0qEmP!GhP;D5fN{AKYI zG2ex+TW@jtJ)1vCerURI8?!T@4D{J<%oWPqvJi2>qU8P8ax~Tz-L`qE5qJ<@kux4S#qUFpoPL(q!k}A_-8)DS z#O3|M6XW%I0CL={p-S|5p3!ey0%3?;2y(go28Go7zCUc4PCT04je&&yca5FeK6+HV zO5gb=y(iL9yujbm4?3iP6u|FC@%lMF)r$yT+XNuwj~kr*m-i@q@VMiwlon;kN=o zm=`{W>251I%G~h#gIH|#nu$D+S-2s5H)Zx4A!%&Xm)^s!A_g-*wi@lD@4K>oy7~x` z9r>6tJXd!FdnQS zhc=I6SRWL&e`@7j_^ou>ZN#+)Yq24)*j6@}ZM@LijP(GMKgnY_v4bhh^&Z%oHN%vV zM=3l}@@L3FiS`SxmQNs^74RuQCqm&oKXCO?Si?-?YgiQ1E?r#H)nNNK1%o>^g~ecagZyPn=HN=*@|FDYK5rxMtZ@f7ZlA#J ziH9rVSC*atq+BBLg7Cs!>socrADp|SwKAR*2q9C3T&biSV;cKk)X0j*I1Y%f#ndQW zMiCDP-T2?D7$$ND3ThIZDPa{Ri(ZqiUCd=vN~qQk90ywEHO;D?tBR^DRkF$>%j3&? zfkTZecL^5d<+F`*cV!w5LoIt7W`E#ZkRPT2S;i9K;^EQ~;u2yO35zsVuIhH3EMg;TUM&H4v3z6ktx&GNeg6k3h0C%{wwmY)ntH=!*=4wSs(Irfz$V-#|3Ys|zM|yC>*OoG<(SWHocA%2J4b~ZjD^fU+c;r#J|<}&>0FdJAM6t+F43YqRT(COyq&DZb5kux{CcJC=|p3dc@&Qp4z*40wZk`drVJXyW*;M z%b&2k5hsc{9y?#TyOOr1@N*y=VygELuY(`^Jh^-V{uBtkQoaMWMw_op9_t%Yl57#H z_qE?~h_2+h{r}{(KT+SlZ(Z6viM`{3vOv6JPvH9#y~DB(d2VzbG2f{wa}r;vd4_!U zem`BjBEFMX<}JL^y|Z-xqPvz@7qK|P`$lLE6Kor1`mN9Acl{H87a!nzYF@1=QLkW2 z2#Vb0xXD1~{vu1~&&UErED(5R3JCQb8b%@G<#jaDW#92|k zqhtr+W#=s6#?^a~|C=PW1*MQ#=vPWnSy-R2wTiNY+ z)Ozi)Hg2xbK2u)Ap6Q}H4aVT|zcXpB{TN3WW*6F}Wj;H2y~4|;Fc~*e$Bf+%RZnP1 zk+=GtS#mK}LJc$h*J16`wY3|%232uQFldaqNZ~!%>V1qEWRwo7oA6mV1T9(Sd;16U z>eNQuT%1G|L^NWVtI2Z3!OG%M_`;Jt0%Qe|_bK!Eb<<(Eac?m{%tRmwAdQ7?%6ork zTk7T9w%R5h--2n|g2)y-lzHIpbA>!2+@`0;e*{C{Pab^HpN4)y{<7OHI9?l0AOl}t zem0@6c70vwCEBLGgg*SHb}X|^r(0VH+b{j+;{pvq-uG+d@ZQ&(90cS`PJLD*p*I@hNrHBAbSUxuE<6YDDb1p*PSn$4l>Z7mr<}hZJ{YevuO5ZQ298nu* zMneB}X&r$b>z8)8>NFeK7j_dW$!V{ga;a%`+2v0P>|OY`YP`pY9zEVb!Wxw`KbS70 z+dP=6KkX2_-Fe@lVn06uF^CmEhHXqZGVWqG|s5>Hr$i7^| zF2}2yPi$E6;Tq_CqY?XM3~>*|5RW7z#@ii|MiSG9#0Ed@kTX0Vl6%;Qm`0!o^{EXB zQRAVKg|9~DDg?4|5ehlLoS)O2ud;IlqVr1|rt7%-&|Ak4pxND_n-D5nvu69>W=qQ%WZczr7SSb`35rlJorVm(Ck z6HY;zZmlrlCs-U7MIII+$(JlqCB-F+$rfdoDtRRRhHnUWr~~lnrArpUG@qZm}+VDX(i4O&$bhj!$Qea7b< z^BqYM5uz^spukXl%Qg}4i0Rk{V~2&pCO{-j-xwT%cumVhKHN?-4jF@35O$E76N3ER zn=bZ+WH&(5;t&o7KWS8F0gsSbwEtt#JrVe8AQi`2-HpPQCm9Q@?(wDp_-C zhxozg8W&%4?cQRe!jWvjVgi>mH{mYJk8HfX$p_`eS+SP}FrdU?^zZLfdKSB!C3Q4s z=PNHs2=m^*eAIkoA1ec@zZiWEmZCpPeO>pv-k_tV$bSFM8^Q9bx^e}hS$&Uo z*RJSXd@r$*s*ZT)ugDyrY5n-sK1xv9q~>$zEBRZ|pPfHYirVujFlx{!Q`0!cS@RiW zB)d&epoQ&jIOiC@7kNd?o*RX2Xv!L&k6rRLK9s|-pRPzCpJn8_{K6G-wovwQKd#8< z+FdR=m(a{#C`fIs%NgNn17f?+G)M2BaO$Gk0 z;oz-}fo1URY0?b&NUP*S@Vg}~O}B;y{RCcx`O#Nfs|HaeD|JlEO7crTnhH5Gob&H8 z`kojIO$SN(`43f6WC^(K%;~x{a_IIU5>Ayh3QKcj2|g`NX}s{_RpQ8S%%}Wk4wN4L z=WV(MRVowiy_KoDu0b4w5PeMRS7aFWVH^|S$qh`hFBYxoDZ0bN)@Pj_B`erPcF1s^ z1uK$BXIwO+5dJm=d|PH^S^ho+q^Yt%DfKWIsIEDzR9Reibrxi}D>kbZn1#+_)Q=_A z81{mlE>iUUARS$fZVJ2@6Oij%z{xY6{yPy|79TYDt=M1ZNshQQE35N3cN{NkTKn@4 zOpUB=|0i^J_JvY7)V?6*`x?pQatASTMC{GwJ|?b;-1b@#!?re8!A{yv=z`zvNo`5a zbm}K3yI5MX`>}U$VaNj#H}#r$CrmjITVBvDT<16O z3?d+HyQ^zO#?E%GLn5?4TjOr0u2HVcbt!n)t(~8ott?plG*Kxwbn*5!h^`D1nO>9l zE@ge5il@;xn1$pJ$o-k~Jf16|+p*Lw;m`fJRvW;LlH?1{#aHglo{~esmlNb^-ru;E z)^vO0>y9pUX`(L0?LB(l#e-SX<9J?Bj!@y&H5f_9VyElN$XUl?(4oT>6;o*KN%xqS z@*V+sy|{!8Ef+tNDWqQM33*oHqXx9XU06%ZrNz{!=H|Sw5YXXqWK*Rx<8<;IuLQ`) zMF7{b#MgDUn<3hU6IcaxQm&(D6Ex}LNfNg zh2hOwqdt_qsF;q5hJFg*SF2RB$X=+sVGGwttU#StT>&?fh+*t+)RQBO|Q?haIRN^1{s;}`yUcFKje zR8q^~md#+^C8mXh2mjNG_;0K8c_%fo6NJ0OgI*O5&mO{3!Z*?M8J`WwzSyg#Jbg~l z`Vxl8{*yk+Bpy-Pog!OB(%Rt^gb9J#Cc!WP6x&s2xq@@m1s#mr_uwf_#fw7|I-J>{ zt|#kz8hk5HgfH_KyEyJ=C)v{W(MbjH3(OWF7`6?IzI76lVRm}qZsDPhUHM42;rS@ z{_3lbqjJ+<^W6Js%lpmhrZX;{sjX3kDRhH`5b7$x>mZVz+&mThL!!{vGBc*;wPQ5t z!3@b3H3Wxns4iwt8HqP^FY@rmBv>tzb#RG8bY=_Zt#i*4A@b})?9pJ_LjfhoG1H{Y zG@IHxB67Bl`y&i$sVsFhywrsTHOcU!qjd;umqE5X_?yD62!Rrnfb-$rNA%T?+m2amU;83r~4Z5|eG zc6ML%aULI)@`Ln&qJ>JdY%L1c)9Sn2=PG8z2&3xS2Asu^PKEbhPS5S`Gv6BTU7cfj zM!N&8^I@I^mrh_T0KdFgpFFvhU4FMb<#!>vGPghGkBnJ@F3xD2X#y46R0QW4UFB90 z1MdZL-^BIGn|Q6m!6mHr_Vlfe%`oeO9go=!ZJVq7lU@F7bvqP$zs~+LfhPg?5!F@dw1;4ss}}Wkw73o zq+AEE|G-U#?7K^Z;j?FVb;m-N7HObjFVYT=xCNwdU}9%)bQo2QciP@3OY{zPwUOK! z1d)e8m%J? z&EHNf<`$Qw*=;7zQW6*Py>W;^qS6boQ?CY-zkA52mvWB}y;kv!mfUE_wU~W()mrd< zD;{3D0HinTcwVWnzSuLAH6LrCD(|8JgQY)uM%l$xEe#YTiQvcAbcc@Ud5t>&$w<5o zZw#(rV!C`r$Sp0Vn+#9F9F&)fpb!mL&dN(Qtk`O~6m^P;1q-9bVkVk#kopZl#z~Sx z?&6g5^Jhn`uvQ}$@i|i|mDqg6#`d|8fVy-sG~a1!CMYx6Wx3Cn5Z{P4GdLWU*Jbbl z|Jxw2D2#=!_t$u_EppF44#j3`*nB?Eme;fUV7~d*tq`8AB3{{h6xpGk$Y)DRFeC&B z8m!jV8vOY2?BU9+(lKXKr%g(Q?UOkwn@K$JF=I&tb$fF*tXu=XL)mWx9giBrt23$e zcN|j0F%1Din!an7vdyP*Uo#wyK*Q1HDalLY^hCV zy9IuxM%$*{fX#In^(KqSgYS__TAg^!D?q;11s4@7oc%ybg61&<#AM?mm`)Yy#9S}D zGkkkA-sy^#@#s^dU3|SE<=(tGbEOQEk3+1ZihqVVxh38f-9n36)VWDmZ$|j}?^vOt zRn*u5aal6vAzYm+XEEc(3N5|E3q{9RiLgn^q!4Me7oD-rOD7=aEdJ7KyEth!PE3xB zF#N$`sv4dthlt8-N&0OR8kJu3RdjsnH$jQ1c(+^v{eO&?T-@WZcfL8_!e-a(F)>A~r|apV{yMNLG&X!+1Bj-?vR_YQFon6e<|AXu zk7YkGYGvc?sy5`@+J)@WgozpwXq*%BHfOHRJp4T^S$VKH5b3Hsq|6n3;}TdHvUr0t ze_4RMhf}!fpD(WS2=F<3?eW zPo|os(W=PzJfZ%9=i~m1D^mE)v*n`9ij|kq<_zTEdH!;Q%IiRXEYG|La4OrlO;>Lq z0|6(KDPYP470_Et#}%TWrX&qHYRoT9Y$mJ@&Wf{=G?AZxjh&$)vA7?^P%(#{&~=Mw z7wdN5_7+n=hptiVi-6gKE_Z1ANG$dE278Bkg8(Tdo&VPPyNtHU^G|>O zbA??=kzfB>4a7a<01V&snlJUPbYO%TBo)$&u$?6^)iVGYVe$`>B12slwE>*0mzsVz zV>#A3p#r2O5Y&`O<&dul*Jky2-S||N?cu@Wxe4|zjSug<26-eNpJ5;O$GaW?KPoyM z5dV2UYezcCndh;!&g7~jdRbzM$3F22<74UY$+eePN!>a5aQk`FA6eV67Jv&8X1%NS zYu!GK%#yF0svt<|ibWtSXYDQ7A%5LtsPN(_X=jRF(Jm|5^UL+j?oHxL!0!VO?Y@s> ziAaGDqucz{=lKrx{7MsPNH%9~y6&{n>l0|{)8b>})x-(Thv)MF-3hHvcR|=qb4$Vt5oSS!7>I;L1_V_6sM^jZ$OuMztnB^Iwo zak04mHJoI^UX_e_Tr+|9z4bvhJxfYnVVAWWxka z)Z%$}d`J_a=G4$Bs1Od<;Z{<$<_v3XQ$arR=C|U25Z-Q^h@e6DPx&v4=zd>q=27fj z*^03*M0ZDF8K%2pQHViN%6F1SX-amCl(A5EC8bs28e$f~>~0Ydo*Vr|VSRZ>A%ox$QdKh9_ztpOdx)DOLA;0OW>M{f@^VYGm}xH^WSu zf#mlJlpg|-pfE%15WNE8JAdW>D6qvd1Mm`qF$*mkLW>$O6)|nyl!PyhnBVI)V?2vgb~iPMZ`X=qGL99!>c&T0N}5P(F~Ny!*=m@HtDW5qpY;Y^ z%Ns$)!(mw$4|ZUt=+*cra_bU%vH->Bb$q^`p_MC612?bg?St5O=yt8m{Yv9| ztMcNLb0gSIT41?BHD=%$?UtW2NnopNrn@*pAdsIyNZI}6#y*>133@ogh zrJnLR9o<{yScs+gJRRF1e{=W0G+Vwb)-(Z7U7C9=XXzRJ$UR@%36?ZC3yM*k6NP6G zvgNy>`4lR{;J2C87_3Z4kxt-a7tWtIm^a#C4k_%{aIV>(8M4QuQyJVJ)Uo&3bKKjw zt6B4DWoEyq!=_*9wa+CSl$W3lJ4Hk{0hp@0$g#zLDP55Y7m><-1GPX%Ix}5^ufXv+v z)R}eP%JaPQu9ZB>uAd=k1lzFe3if!$Q|gaG?*R7{#{`U$jT*o5xA*XSYNt`>+~8qX z_JXegBDqL6x+X0LaA@SW8*i1CCVD`is&0LlG7ld)Ciu^Ua(e-3ZCkjsOuhkIW43cF zP8+WCQAy)v=&p&E(RYe7w>t#4L~?UTcnU~3GQXcd%%$R$oy-cAF953-0kV@pQae%Q zwv^&bHYvoumQYwKS{m3H|OIxVB))1O4d7Lzy+`Z(D1r12aT!pIZbSNUH zgo}-5Q>8V!(WR_J9im~EQF7rGC1cSK%pE+eIexgo5)|IoKIStQRtq0j?&0${}5_ z0+z0nDO!rGy&i1jBxpX6oX~C7yaf4JJs0NCINUa~F^7#FqyX_EiPi^i-u1r1UsCIx zu79>_ye-7~i@5-Dk$kmoO=Tr)-LjH5UcoC^qYUKYzY!MSy^Q`O5tc853DilJt>cbP z(x%r!sz&>t(dDq6s|;wMWZv~w;y>I|UxYpT9s@LV7dqS*M&!Vq@xKfiDyEGmelFd- z>G()3ai`RqG|g57sGT;JePQbo?b-CPNT}A(|=34DstGwHIL zvdPIK3TU9!m?^W#iqGC=wk*XOS^x$|=1O$Ga@vMbw$s-gcZWN3VohXsVQFUyMJjJ| zpY5_na&jQLI|8mzPT1j^CQ$6WCCe9$Le)L`c9@!r{eFdD#Kb2x@vu-(K~7Fa{93T? zPgofk3y;eqT36UK7$H9vw6qRO5#v?y_3smdi5X%7K=1bDTy4KO8!Yo!j^ z!C}?mbZQyT=V4!MZG-fzdByo84#UI#2Kvn~HjLMPy;tgNTCcQWORreqYxE@i`evzW zo8O|ex*u7gD>S_7Dl;HR80Qz*w*jgr$h;kzMvPbQ5A3`h!hEO^h=;0Q?3$}~MEqE^ zDvScO4UHGz>>v88niw}v@m=4eiPEok=Hlf5T(&mmToRAaY&^feqH>r`c`jR>vq~Oa zJsR_v#B`sH?|)wmc(~`yWG6C5GIXGH8j9k&bY7Bnx6i)xFn{Jc%tUX|Q<-s;cVWd; z<*-(h%Y|DVMShIc=7}#bt`|w_G5siOcN#4;Td|knTe2F-S^_W}p?Rg86?pT!G!woO z)4tjqb)-0)xs5hn$7>OlWiR6$((AT!a5v^w8<&nTwo*R*RV=CktlJk{!FM9cjq77S z6xffz+nzh@`@b)~GRBg)o~*YB4R`zG2Qi-L6S#-xO)Ww-6rL#%Jz1(`%qC!4LMW(Y zETb8Aozok;9uXz(_4J5R1!&c=vx?_V$$wG9Uo_s#nzid(p#DT>88yJ8rezIuucS{ z0dwa!a?!SmK*HXz>9moUXvo?%Qa-e|4SarM=s?kpdktbPw=d(%&6`#++b_H_>&s z-^X|Yj6@gv-O0gtot`DfE2y|yrwyq*=Tpvwf_FvSg@$TfUxNrN+H-x*x?3Dr%- ztuL|IkYj};y{?UPdOR;NZWA{Pez^Xat`QUJ9L0PLy0^2I(K{X$y+p=KuttUaUUZBW z*k;4muH1tbbJ4~8u}aKNd)b@Augxz~uGSat_ovJv3eBq&2`b=%se|u(MX9A4uNr|c zJMOY;t@lx8G@9Xq=hI=VL+xDm^IR&oo?HEOEiO~Gu4)Cx?bs`ix}8x(9UdVUE`2lCRLT`n zd4_$x4_((nq0qeN2iV!0&H1ub_5&Xrpxb7?@6!Zn{747BoG+N(k-|_21vmtxGeqV5 zD^PlV=d%2CfZRLESus+NrecXH0%#G1(kK|{hHtnVFcF#6wp=wT;`rwB{_f^_-{PH} zi!=Hd=_Ql1uzjozDyMb{86;h8O14Kbc?M}Tkt2U)B=f)mu<(Jk>VtYYMt{Z|Qs{sY$&Ji`(D5Im+zoK66NtjJW2s(?0Aq|u?TdQ$Voii# z%&3>gR;erWEzj@vc!8!C^UHOa+1~7u+6D&zS&e=fv%UD<;+pzAR&@f!vbrOA!jHme zogNffHX{va$|s_RPwPe~PS+?n1VD0K6!^*lV^JyNX?ON(p79_<$26VCt-dV0T^1kly@5inus;``{e!GruYBpF5jyeMsANx^WdAHo`(p;=l9 zeMMYaiD~4W!V24)V6?)KHE0~d65H7dt8$>R1ZDvK(t8edR{q#dTiD*2l}9s-#uTZI zUrJMgplTTk+*^gQqGr&wh-MknkJU25KH6>>a7B21U?03AU1ASpbQiPI zjs&}(U1CoF-0`p_$)xG(GFm!^RCvsrPHO9nkBKIub+pIQS?`_6fA{iN$;voB(&i{@ z^A@$1N?g|?nxLBCj!Q;P#8(W}`Z>H7Ce+_nAIW5x9P5@WO?*FLR=XOE{!$C5_|utJ z>aH#Ds;;&weqJXdZHSAK65V0o>@ivxkq~%GyP=`2%TQ+hE<+MBxKD7k*aR3dAmsIR?PSm~{-TIO+BSee5Cvyx9H3VdXye)mB@f^ z37v$0dNz?~?~v3}B4C&ULc&6BtluK|l$YQLUgGf)bvX4q*H%Y!!sR6V!`)0yVGi!( zu|*c(h}|8!D$L=}q6$8gPIIsKcZA?piA67qCIJt6lP2a1rK4aee4x(-E6hb#ELVtt>f zBlA+Q*~OAyMskg5!Ny0yRCc(tI|N^#COv8zg4v#L5)F`3mK~da63^GH1 z6K-SYY%(`3&3ss{ZpkXl-$Vatulb&b$JY420m}Egf1HeOFvR>1Q}w?=n}DN*fi=y4 zDH$2%|DR3UH*5O;Xxi9V{)>b$vVDsurf2o9|-FIME-VW|FM&aRg0CC^;;W#lc(=2zfsmVuKEWz`mY1B{l@|Sog*`c z*1sa^d>4&{nc&}Ys`JRmXov`bYS`s`!tl zrl;5Wp9JimC-1*6CxQPaVBhxaA8wHOe-JPhTK0eFyZ#rn+dXfyT5-Zu2 zxHkf}qnk3kG#qtTWdJz6%_=uNIPdz+r{`_+ZG-P>ALjhR#dX`NrhR(!2k4K7S`3WF z$~1QGF|}#~cp!2L2tCz_%Dd*T)n_n%K*bNk>sh5C>8P>}6Gs1O|7YA`=`^PH`-${x z5a+(P3rHg|Sp3(y5wEV5eTLwyx-5vz78Z3o-vY@Aj{89s2_vPK`1*q!?l-0k854)L0>R*02QmkNGykw==rS zfZjAdr19L|P9*8v!8gZ&Wy21Hy&3|%BsJu}-Lb^JkoQ_fe4@c!?AM1E9+g}?jd53m zWh=+}!PV?T&eCKAQT?9YxHj&*9FVvpqj6y4kqFbhw;iRACH>+T`{1%ng^+gJne#~3 z=)~Qy$8{S1@;rO~ae}$Qw+nE?CyDv%_8(k*=c4S8!!H@w%fa`t6Q|b*Is2`}{zkOs zP;5s}Z0hgm>|^!eKj*;_fgx~DDbmO{BHo@+9}s#%fpC~d=EX~TTZbb1#M5d5W|Y{c zyY_&r!=9t*aXq2ngT5#8YF1}eTl?`fiN94*Id;%MintIiGdS zMN$2Q_I4WP5=#6+?^h2sFA&?v8TbaUJGhRmt2spE#qlH#$w%zA0p$$?lYgZKro4Rq zOA(9=QA3y|nz0!)1AD6r!2+QkW^Qkdey31BRx`pR9%h`(7stl_b>F4v!P*&$lsv4Q zPDs@3X2=Imz)i~od5@68?~ZfsJ$@K+Pn~Nfw5?stKFwT6=@%Oo*APWDcyDf zByEu-a8MPRG>&`hlQZ|Daj-GXL;&wtW6BPeq9l^jFG-9RIr=oZDb(J#fAK*m4P*Cl z5SAiUNj7rGnFdDjvufS(q6tdi3IZ7VBU@`h^N^f!GVEEtUyodl<(7TKmP@U2}KdCRM1L4-F5}b^b zkL}4XJ|IB+3uu(+yVq^MJjAjST`J@&_#9I2dYs{>Z}1>QSqAf+zbSWFB6uKCzD;5) zHE3QohQIbMC<=r^Dfo{BdcQn(G}GF}8Qm8k(fC1gXx?9*98flY!R+trPQ>id!MFH| zl`?K-Ww@W!bS=fPUmj~HmR}Kb6z9V)XkOqg@a}%?HV2%WE%N5Ys0th|&lHM&dc%t9 zuXP3R*&WT#jFP^;5~kiZb7Y7qVx4`lbj{`% z=Vw_fKHgAZ;KX0PAuJIq>uWGh-Q$dXaaWJqSHc(a$`f|M7->*P#ewa+^9i;k{bXpp z%EhudyUfQYerj|HqB(T#yTix6C|yBfF6Z?^1}g&`$&AQfl21ji%bhZmrs5EYt?BML zmX7TxlOHrIV8CJrdkJmta^jhQ$8V+4!31(GGWvVFayUz3AOcd>g`0I31&Bl5gpOA| z4tTbno@Rt^dEC`4;fb-|_Fd=?J-k2XoNl81tx)jQY(Ce(d?ucC8>k<;yup^gxV>p` zhBzH=qF*@mpy%?U+lv*OE}LhFwoNe zR5E?Ez0t=hcN(?9f({VbuasXzT@CT@tyr%7prtDWYbu^R8P-~0Fh+evw=(kX_SkP@ zX2vVwxM5w>vW43^s2=Lr@#h&Jye};yJn;|39@*l=3QK1B_CE(a8*hKtDy#uH6}A|} z+;B}G_VfX4^89rKIgk+OpnR}r*T3oQ`?mZskzbfkdMzKZ8?+C#jp{I!^6}q~q|;h| zolt=XdXzlc(~{MoPDbUXd8+s?Ua=Pnm>Xb00nqla0Ib>zorBpn_nvf$LXbUdbF@y8 zX9&0nCZ|lQ4WMK}hDOsW`B?Rt5_k0Gc)lG%)6lpZPVQd|y*(rN=43WER22b07eBPs z?zcln)oZAH;O|1f<^7I{VN?5C`smdMo_blHfT|6c&pfTkwm|rP|BefA_6z@zX2uy& zyWybOoOu-KWRrF5 z*qS$W%QqpH4StQje#_Y>WRK2&0wbu%4*O)4!1)PoUo3HUNO5%vXNz7KQhLuTxcNPe zQzYs>DTJZ5Qf$1yhe4%U;Aw2yGTtp31jaFFQyLrcyr#4aL;(Z-d9ZF@XSE>An54Sg zWPhiFx^CEOjZp-H8ac>(;*VuIqO?AFyJ2VCKJQ>J#0Ug}EZsM1?p%32X>>!pC$|q@ z>wD}iGs14jUHD)rh)hIP!^{TtoR}HpYlf+I-jw^N?e~nY<@qn`>CY01Wi9WVv}O^G z_oo`xQ@rs>Gw|TYz2}Wk{dSng9n|W`HeO+!cc`;|F8b^Mif4h`VNNFOqrsp(h=EWc zy;sgH!r~%=kz)cJ?R#=hLJi@iIImGvMWLxU1ezkUQ>zCiQ4Ax^BQt0X7OlbN`WDcj z88Hk>7~~~r>=3cwOTns}sGHw6+3v#L3h%m|NIkzk;cHg052K$+-4nZLI%&Ezwp_Qo z?ZoWVu8psWuHmj}uM>G^&F(q8A-j$Bpto(h*L|MfT*+oYDSET?Wx^%HWp92l%ZW>! zq|kF4B;^87d*~n&%o7MDBUcb6I%Il@~rrXeH)IujM*3 zpQ_JEN!b1B%6^cT3psc{;CDPexI2hAm>u2kL8Y4?ud1H4+OpzUzN>NRTsqZUw(=2N z79#X@1kzH5vL=*ER639={7WSs5R1vIxMN%Rm&dw;A2e}Bu2n~!${GO=r5VyIgmc$u zSF29cThv>u6Q_sWH*$HW$s=2rPLTkWVrDH9J^wFz;a}Inzd4!Y^ncj~TAJg5(F*;! z2zdnq?t&&u4Hy^ZTA-o4gELOhpT^AD;s{BMNFaO zjPfPAkseDgrKgx>heb|P20U)L;OOODv2#@0@?LZynu=Jcigacf_NFgyn~+afVjhNh1K2QzW<=o z$5HNcPlG_#N3sqWrAICP%bW(slm}(nNBx3k+OM4!gyse`5!PReiq|N+ZcUS29L~Z1o=SX4rMj6Jumcv_)UW59S%RivOWQa0DP3tF>L{nm?56{fSdt2 zL_HjJsuz7g^x^>1F-jN_Ttg&>WIBHT0MsL=lRs%ub;#lI!^AQE>YtW@3s$ z4vCQa8GBSaL z7*9O%{3J$7`FKg?VyyBa&IEzSlUb~?-x+0sGz*e83$mIsI``YWSD#6c3ZB4q=?UuqGO+M89Sp7GL!0HWI!;@R@7BThw5&vfip))>qf1iGRKO)htEVz>NBlUvt~{jIIVKC z=F;#-cZbuMy47;6>Xfdh))rY~YE7xe)r@#Fx>6~u*NFP`fIS%`>B-dZ65s@)k1oqY zgYS^EBIkseJcxP5>lX9PNBqa~;=qmoO5+`F! ztQ5j-$e9S_WX#q6#m5jYK^-yrzy{#@2>O($VL)HQ=5b=ejWiWS>o?TEi8RAIG675J z^QH!>QXrBtEUWxEZcL*=wUkj*=bX|@O&w{{z)Br<_{S!dz;P>@Vi5Wxa^Qa6Q6R}U zTD61?L&kK_uxYgbM>dsHNs>}2FbiL-we;o`Bo{|EW+t_^dvVSbBKRhD7Kr|Lpi^KLk z_;(_yTso(X=VDZPgXwfSm)&PzNF>^}!?BJVokqL$Ys6V{h3a;L>1Dgu^0wPoXf(XF z=S_YXzK8RDO4WMvwY&9k^=9m~Mn-C}nd_un6)qJi=`@UU^NN`z%u=$F4`eT$IWMg%Y342Cr{VSMm1u+3j93qx zRiY`v0SdsUA)kL7?PMH1qT?>EmuP~v-@=TBZb&f?S#&2T+uLNLTePc=y4p;CSjBuw zP4c&z=GBoZbiT&r#$VAqcv;E1JbImv?D&#|*Ib>^JuYc0-|AA*{;FUT?Yw=h4QZKS zX|8AqP4a@aiZG3-qNTo$__&-uZ-42CnlmZv=gr1b;4x&8{Yvr~SdA}*a6xNc7ZWfV z&{!0H>p)v-{m^+uu~b*wy@_Y>c}qrdjlO-AWSX-QPlfsl$GUN=W+*9B$&2Kaj$SAd zRSmmUy*vCXdENbhyjXFDf}xOOigAk1;cYGfi>*60TwA!?s$-SqG~HplVR*bmOER93 zGE{pes8*D^t*Sx41M+eF@+2k(9uqtz;GEwAXh!O(DJB@wkXqBgL+VoE0t?_EK`TvRVMv~-Diyx10(?K3;Lj>nb~qh?E&>UT9CX%RJ7Ub8|FTT@0(lT#sMq*U;_vkVCUmc7L5Q->CiF> zn`_@H^!tY;-Kxbm{ucXkrcfoD4*NC6$mMkfE%waq>r$IdTJPL7O7GmX1y2RCkgLBu zJ%zfH?vujg{OZ93J3CyK1$%vyjjmhPUN+9sR`(9=xK`G~uIq~ww(uvlD{EqB#Pd?w zj-&7^>!y$G;$3h`H9yZ-l)5sAi?;7)7tb9Y0gaxM%HM%av7XtLx{CnwIobsL+cyy3 z9=5ds)&ESDcLo-}+AH=5WHUUcdG$iAnrDdfjx|y3ahuoUX~i%UM>; zy}{|#gui-T@HhjlY$9oj;YFnPQuPGvA53|fdXc)5dMy5d5nwmBqQD6j%-{ zc6zBI);1WliF1cyXt2D%DG28QoP(NE3Daa@we=8Jl5Cby5+a66%fqdGf3u|J z11=>mM)3f{Y#F__(PVbe)N$Cvb=U-b*pz+Hba~jsaks{Lx0Z6ZChcL9(a9>Ii%qu9 zq8j~&!2$*=TeKjaIWW|c->3#U8@llJWSf?PJ08>*Rara#eN0X`PCLn*{J|d!`&_~c z?nK&iDXY{!hq#kP4gBRi9PUv5!HtwjOZqcMlYahs6j4Wg|C z#mVaAjuW^gc>$4aS`(@NaszQgecysfvk z1)GoOQ??VRTU(*(lXKjy>yNGK!xpRWNdv1*g{FZ>SiJTmtu&o}p{T7jn11}Yo=G4+ zIpxz>d4y#;ydPKnnP5hmXxIU7xh8Ba-rRnaIfW_TcqE7uw`yDmRGA}0BU?<49W zD@9d#&^gy)oD0U8`Uh2BDU7kGp#56ZZFtx)rqAmFe5QbKA)l=1*)22>SS=$#j*&zt zI#`1dxMp+fSQEoZ`A5B0mCavkqeAimB~dcn;EnM}=?#)dls2^H=Rq8j4q_1~Q!V=_ z()-Hti~xLlR8?1-cQ&58bVP}YJTsXy{~VT|=KfEkj)a~RI#LWZCPF#7dg|z$h*Q=9 z>95?0bwd%+9-20VM2h?Jxz2OLLXHklMHcf8l^J|TNcgRTiU|DG4ZBnU*)4N!Ve&1(7ihXB1@$POdIX)VOb2U9i? zrB3R^=|ZXg>y)+d%P8OW%46rY`u5~u-UKGRTSSRR~w->y&8S&x72E}J1ym4sJG;&ql3;v>&!{8;MkO8=C3u;_NeM2 zxw)VR4Bzd1{F&HO3joW|grEL}<**&FlRh4{%b-oB93;0 zhMSc8yBp%2;GOVn&}-mv4`gq7Zy8BEVnN`HDmwWp^{i0NnDjYOY#jPfaWo7rr0Ry(18yoIdqOssz~_{c9$@+;e zH12S52<}4|tf{9QSy4xH$f4x~Y0gPc@|ke-!FM?7Gkt{Tb}S57(}kD9pw7p4)GSJB zQ!kO7f>&nFdzlUx?qpBMKiCdJbt*f6xH{9#6b|AlLA7YzRi zCmr!OR=kDh#~$IvYReDi(;sWIKiXf-9cJPgAAZu)ioWdh1f9xbOo-Wm9X`{myMEzX zXZP#dd4c??g$Iv0%t8QLp8m43CkrEN$09hQId&XkZmB| z$2tk~gF-x2863D-qK5|t^ZAD{5f3BXk48)I8BOrGrthWhkUs|YYBtsdLsb;>4go-z-%W|0=iLSvCc zcwR&W5P4D0g^?!CmiAv@q>i70X5W$U>|}cc8~@Nd6Vc8O+`dsM8&1}|W4x85p6WEA znL{I|qp{lEgRE1(zq`qOrOQ>NkCNcv60P!+nReBYrh=37-%yqzDT%^|*d^xH|t zqBW$eT3h)BpSIp#E>T{pnT3svO$r#RXhl3$3~f{6{o)L>*NUkG{4E}d@zbpSaq4n;z{DnMj2B6QEQ5BJ{>VnK{lL9`N$E16_97i5VQiWnPD$N4zVsG=gA*{J=+*WS&(pRV^#X`D}2 zT$d1hIswm^y*fKLS0+$tWd2I15W%@IZYQouumid^Qq4X9U8`wgY%;;DI9rm>CBo@| z^I)WC53-h@NE%WYwthMxbxgV$A$8n*)b&2HhxWmSrdU@RBt5)R{_1Jg_yebCY#2&g zqg&xg@)@HC<2qS5Y}vXI&7X^+m>)Zv+bplWQ5T&f{`JJ$TU!g0Z#1mTq}kd^EMsvE z(InNO>=QJ@%8j#L^Y}=8-I(kR`ImNgqwU?Dmm2!@=bz^pT<8|wr^R_pTvIi)X+8Rq zKkI>=zONbwkp;%LAzWPVulsa-Kj|v*06z0^G7G06{$+Li4U2|oS zoScw2auFSG*I|3dA;-fvI7sRk-6b*T?^AF&yts-EJ~00xnt?z>+CTBGIJUO5xmlYq zGcAT}!8|Z()Whm_GBc5hk_{f!;W*{6AS`oqC&@0vHbuwK#!|#qg<~V~#ZDP5HfB`C zdPtWW$;P7Z8B#}#6t0*{AaIM;=sbAZCx?0K-{?M4i8&;rIWp#fy9HMNMZMIkYZ(H{J+chq>47grvc}*|l=<+f>jMeNqnms}9!SJ#^=o+_uv)Q})A?TUn*DUNS_NQpTtn->ov8Evl1d&jTq}VTXAWAs5-mHv6;|Kx8y<>=EOvEGi z2LVYz5rS_}E0OwrHxv=bHYolAhW$626#W;^-l#J&I+=fFr|XL5&Tm;eb?=YlNE32l zHuu$xRFB(EMZYaWmm`)qf8^ejbADR5ME)roVeHcH3(Hs*>4xl=Tv=UBTIa){*KztB z&un#=YgH-6XPl8AAXg6O#d|7iFQ8XWHv2u9+LgQYVBj6HA|$$RNTQ%zZ9CrmCRvV6 zjVC#^srlk?=Q!7igH{L+^B3MvTnq{AydZOe4w#OpFxVQ5Y7F7tnSOqzL*Q50Tibr2 zp^~U+jBR>Lh(&(^#xYI>DHcuzyQE%ydaS?dVuC>6$TO@EX@qCaV!i(L2Ku5PepCWf z#SnoCw0Ri?2Ql@ z)4fMyyjF(aPW1ek6;nP(6~_XFtk6-T=AK+Ub(|<+LAZ25EZ@SZXF#jcRX4c?x)u2~ zTpLshFSXGm<0qZLndE%l1dDoJnLI1%r8MpLUjAdx8z*|RceALR=5dXdj&emurZ25dT8 z8!MBLXci|@kBBU6BVC6G*~ospWMB#5S*AhbCUzX%%thMxGvs;5GvxTWYk}6nWxZuXD113DAh{Xt@KKVLRVf3dSyMOj)uCz z<3Ii&YFUqtX__i7%4!7j6p?p~i328OTx+=#jRJ>MDtKNW*V5yY;oF`>49P zKQIA`dp4I@+e2?{m~F)@oBfJHe!yk+`NAhxw>nG|Err z8-G&;GSG`@>}v0(X2X?2>%jdwrCE(bfv3=QU0m(IwQXD`1$1&2+{YIJpCXDmdwK`V zW~+*&USVUfUZA&a=$7%-L|Aq86jIc%$b*au5S^>S%4c3^FA{Ma8p~q-Ud^2O z&Fy_YgxA5l+5D}zdLE{>-5h&EkE1$d_Prk08Ju>4`a5{(Z9i64?dm>%{yfh8GWsI@ z^L5#P5C2Jjn%*^5=>Y9l@n!qDZ?uKo;Y{V{bK;h?gdU$8MNdBSN7An)XDCmPT>z&_ zk9><*601rhp_f_s*PqpJynHocXnlG#_u5m2JH#|`vbhW{Q?;?y`9PSw>WZjqwky|) z6cZEPh2FUH@yAi5f+%LUM_OWS6Tp_+fRJ{SOcY# zKzp{UB}Fi)8zR5qyDkR8xd=NoZnL{z6MLS`9CQ(4!q|tdN;IuZI2zQO$q5Xz z{bTljhS=@S+h>0J3ssEUZmwNDj~Qkx+d8AAWqM@Hn!5aQ@^c2NAl|fGH%22UF~faA zJNe^;PLp2yu91>e*S?)l zmbtY>|2bN@5%WRXiQ|3$j;z%~c-kVj&0c0L8Y}WRV<35a1_>>?{mQxgcX8x2S-i*H z9B3W5m{l=eIMoy(mDDPa%hHm1;>@W96H3frC?92#mI(MV!14OxiS44X=Qgrq|T2qi#Q`oGWefML2 z#(>6pFyfG6O~GzEwEV)RUgYmv7e-#iN#TlT^&uC0El;&!!U`{H+!o9Av1NFjD=zEx z%~+nB_vLf3$4)!#*{qmX71Szmz46YvpzF^ntBzhK*{|;FfE_wDIv@1+(KM<V@--mWOcTSJR9=;^0jpYslxj}w17phB>p6b5=Uxg3&b_`7vn<`Xb zuwp?x{)vxGg>}_nl@B5qV2VJCMOvlK8z2w0GEZs5$|YZnHv=ZsKm(0RW)2;mblW_Y zbfQxGi~2jX+Fp(PiwHi1+JhTQvpJ6tOEOYeXdGo;YEO!eMyaMgp(m;%z&F99|0N6& zU&@wrbW)?2jgQYw>SLZS4*1R`M{d4dn;T$;xQdA*%@s#ca;@`%BDpv_!?rhU3EI}? z8Wg(HN>9XBW>=LSH;+Qwgf^u^o3jYDDrUc`!@R1Shf=p1k(YK6L*8P@a-4p(nAq90 zQGi;B>3KAT&`1yen~z(cZJLQgQETj%5~-tWWto(=EBcf+y8N#6Wk~#7vS=B#P=nWC zpw+LXaCnp>`h^Nv$amdZ@@5=8D*=^KU5)xuZ<5ZhzL}kr`Ch#sGCzQS<5$c}R@gpV zHRNZ#)8*<1ympbGG`)K^N_>hjs=@aAYq!Zgaq1S7@5iBBjlGpO<3sd;5SIJyBr!s4 zMdMDN-EG{9vUEW!-N_zdB=4VYPQpJe!z-6{mjw|hh~k3G_x#!s%lp4C+Q_z2%(|8j zWPtEx2!$Pu)6}&?3!92G%Tg#y3pv5EAZN>HTz)BuIj>Hn2DVLsY>W_ZEaWdd8O|z|`G0u3%h*PqeO=U( zNiyMN!pzLf%#04>gc&Arm?zB4%*@OaW@ct)=H%wT?z(sFv$drooe$@O<+kN+ca=+S zseWD0D>tqRNYax99Y0fCj<0#LGxCqmp#f)!x4>M@4HW)a{Q|>4(9@cDd=yy7c@b| zs*q!_??$GeaN3~2yoQL4c@IlW)8xeDBxxE|>_e@DYuQK@C9mHCfRbiVFM41*b-L?V ziyKyAz%nq30-kl^$n}-TO^3j?6h87R)qn-VE<)_i_Y+nGyFPw`7y|^$rRu0%cXkBC zm9cb)tCnR7r=G(nvCGS{ZhSVCFs=(zGe6;+5)81cX_B?%!tMJ)(x4TIfa)X^`Fx^R+NAvUeo?QHb z^M&MijSUpqUHBlv7jnsMxIaxmBGtb@?C35Vlp6I3!fV zyhO7)&RQ6>ep8l|zqseSM(o5D)6cwk62VgA@zD95N-Zp+nlzG1#$S1hh*I$k8evpA z<~)sb#3zc9?*R;tdqwlYohrN`NJ;BwkD51oZ*Nxyb;0rxg0gG%*KvhEdJm`xHGq2u z7F_R1LPgtW?6d(`Io9#b*}=>p4ZX0+!b{92#hDrIk$N20YzN z*iHbmS`v|Lzg=sh#dmga{OhkxIg;b2#iS4PU8eYcStXt{G}bHCIff=^o|>szYgt=R z)7f+3l+F(~&mG;UdzF#o8@U^54a|%!IU7v&*Di6j*0NoyD6frF83Sf3=kz3n=atzS zLT(!OjHwP$S-m2T2q&k z(M3>2IcT80OqnsC4K4{9G40|K!8X1)y0p_$ZCWGb1Wg-6MK7pdR_8lykj%0>M-|Fk z&Cz@s_f5x;YTrt5PzYeI2+S@@BO12%pA|U~7N#Q(l8jYNJj@xm`B_=t9C}M?RAw>y z6FVydiZ&J(lsgB z53kFvi2n%TL#zIL<^E8#GgeIqorJcs4;=e@MMEfB9$`N=FG(qr1zHL&X-<6KDV)d%G*$5fglvg4T;Jao5$vhQdB7C1CoV2BgJ_(!(1{WOz%Jby ze$Kez;*7h6*s;^f;@#Dzf6_2j^&9#u^v&&UQc8~r6d)+7TnCzbwEk2uM@y71I%T+Tq5aO#^!M`cSk%!ts9UsIar zii%R&?Sy1}e7cs^mJL6OkWf)C?TAFvuNgIq)It>NX*LjzSro7??JaT-!0pCi9;kK6 zH7_)iFIu;)+Vct`oEX6gobv-cqT{3mdg+BNAXP|=J`CMHR& zR~u>Js44IP35+AEa+Re?&xlwnf?X#VNK7tQ!(e0pCiWnnM>lG?y2hgm@>Sgm=k`S@ zG%gkd=;GYjT6(Zt+V@YKahr}#%lB1{yhijIr{YRe`PG)%#e18f-#PSu5`-MDAdK#h zd_d-5BG9^NJswe<&nKwS3F^?fmdYdOM~Hdw%G+<{E(#FfJ*oE~adR;1eGft31C63d zbYeGbC8TV{-F{L6;)*c$uy>JbX94#@CQ`LADU3poMfr?rii=!aq_ng;rXqQkKoYm~ zzU9q>ki(yVy1bu zvIAu&eu)M5t(t*+6bKF{Re`(0uot5f4s>jyG6K4OG^M5v`uBmQv>_1OrF4KO-4-WH zo+QBWBBzY|^#cA;6VL^Msajk)><{Pc!ZUo+`~J}Atn}KsA#Tt( zZY)HE*WJWKLNCN6O;?-VWKm*5CB`q-o~=+iwJjH#=Siu2lEx>o=mO7n1Sd(ncN|PJ@_KEv7i=Sep>4 zNGx2^@q5I;KQX_0B{emyh~jwIq~5{K{L3J}(@gKi7->NtY2(%Do;INMAq9_z(*~a- zyHl!$N9?OEemmM?aba*IA>UeP1gl)iMu6S*=2S>8F74e>lx^p%ge`g>cU0s>Zm_aQ z${}q47)aV^YM3uU99YzTyuqo_8{}oUj`rBkl#+_UtX*USX6&Gi4Vo3ljnc|51b1(J zD)aBVL;A~XIzEjyQ(!JH6k14$9f?{To~p<5E-}~)#OY45U#LB~GTwjPKc)p4%Vj=b zaYk3aWs;J(EzG=r=|i9m+raz=&}Yscs^CD^@)__3Ms-!js^XAb^3GlCtK{!bb6gAoEG0JZ&>G0zl>ZT!-VcPmEM;cirPov@C#_W2A!A1$X9Is1UY%+Kw5{kPx!L)%5ZEdl>G6n4AoAQ;DQFb@d`TBN>SKVyg@DX5~*_}J>1h8f!CwI&e&CVZ=&Q=L&_Wfp1&jpjF9 zbc0-9jgWpEh!AK>adKaZe0rkqm;`+yMOq7AhDeeLYCE3anaG4d(D{Zy_Wg`jtO9D|!q?M4NLV5J4RhFAu z4=)a77C;3YX6lWaKZ8hLVOPy5HMeU~Xi2x-vC9z88Ro(N-A06v3o|!p0cWw9TGUP! zCgs&x?w|2lvi9Ee>`*sns1sh)f)?|YtuadteR%_SzC^Zo;l_J$f4J;d z#wLfmOnITGmKJJWRvC4$HcQ4K(Tv?f4pJ+zhA06q4Jd21TS>i@2U%RGIIAe$8kvQc z!Aodwj!2GQsD+cQB@;yz=oA+q=UhLYJ6@w4KuKCXU*w#o;*uot`6E0x?fzY3KqgAZ zseq#ZB}$Rpb!Ut&Y2lo%ducYLZ-xtd(cr=*nlBo_Vq3MsqPSxU|xc{>M(GzkYAH0EiB(Umi~ zLAVH;+;jL@|9sUBXW*zzP31=WeH^)$_SMB)Uk3hjQAdr@bqwLANWc7rrY7_6^{0v3 z!NWu?E~k2q9|ySfx(?TInz5b72_1_~ada)G=-Cq7+3QV2IQjhNVpJjt@QKd`Z|j(HwU&CFm~S&;~t zsn)N=Mo71n2zKDJ7R;8iqY`s!>~FKT{(!bM<$$ zG+904Tj^hMt{=-ApR-xutKhAKGbjBC?#n%@dsc-PrVa^MN9_=;_`d z4pI><&8(=tblJ}|Ana=*qz-C$k#CkT}5k^W7kQa)cLwq9xxQDIYF~RtOyws`A#`ngv_j1 z7hm5jP%$x@^yKUfu|lkD_Q@E^&^_d{2ddOE4@A`0Hh@Cn1tlW9U03|%yE#`55rAZ; z^m{^oN(|LYta&r{2wWf?TlS=SxEl}i4NeloM90Z|8q)<#Nfp8#yHe3Kwp9+ES_s^s zs=*#k*|voE0>L)RbE-$BU19Ek;=3qp9D`h}2I4T+6^;rW_$u-#HGcZB@AMJyM!dSz zi{+jd-NS#D3F4VWZh!XIuU{<^FTr8`&LV|`c#MEG8a`S)bm3eX%v<(Mm+!)qYVthf ztdLcxk-e(|=)K&3vvdv9nb3Negoxa@l59 zzLz0lPbcaX1nmVeI;R`Q{7K=A^Qp;Y%zssNb(Rj=H$*#Pzx3;%=x|DVWd|{R=nNlvtG{Z8&wbqQM zGnf2B);%W{XG}FCaqO|<87{?UnJHy%K~+R@P35Zc2J6$;KlsY4+m>YN5;C~Us#W2Y zwr+EX>10s19LE#8YRFKGr7Csbcl(VDSNOqa+Gash`V4vr1-oC}*yHa}2w+Eg>dqAf z;rriOGtfp*5R|KD0dVB`I!L8x_{hhM2ywk6~+0{R-!SkcN z9l)LfflZN?2$^>l#W>+GmVRKgK1)VkiuJM~XXL>fxbkd+pj_nJYP zABh9ElzJ9%8rTifb&klHQp#Vo!aqMaDo;HG(PY0-pjijm-@*$6NG}UCjtE+bKotbn1k^q$VWBlgmhE$6_EGN0}BpbSw5>_h$|(?&Fn&NtDK?Jh)Cf z>>@BQE)Wl4;GB%>LK+#F2-i-YgKNYT4asC?M)QI8Q`c{97S%ASV`H;Iy2h0 zI85r5hd#*=BiO#(_aQuj(_5#14m|l;k~gKXECvEcJc(^_` zqc2#yP}F&B(4q=2*jzkbt-e7WBXmpUU{_9l=X+v~Ryd+WvtdVw#Ii+O6>Ydif$kVv z&+8+}3E-rqQX66qgZ946#i!#-1Z2;#rj7lsAi&;s&f0S##a@ZEF$!l|AT{^sv&f;D zkfcoveo;mNXfLV7rsKtJ#C|8MV8_Z05}iHbI)Nd%nT4q6|6?<4uTpn&C~jAVhNRTY z6#%x5jhoh7L2{Ou_`bex?jn6;(02)i&!NuH)Bbzorx&Q$y%OWr*L3FeUn*tKZxck3 z=6-ruqP0%0BMXn-Tl11yPAK?Q=^c|hnG3hu$jXdx$n^&1x9SzJb=BAhE zCsB15b(+8v=|EiF#?IH)#~!7jK!S{MJ5mPu(L{?y%LQ}r;Uk8Nxpb6Hm%FEyg0zJ5N8mTRiy0cFWVzTee5%lT7E2!r!}^8r)jhQNX)R2;xjOQF!su%m8NH zbSTUC^#YIT!-^*g*)kuC>7j2x_pW}E_=A!mxvtsonoAoz>5oP@N9Uex2hk`#T%}=w zA~d$=xjdZpa=#cZOuCec=qgIHbspG>s`soU0=nGo?JBhg)cs4Dl2bLGP62n zwmt9Jz#!l(n^9ybt+hJZ11Gl5KtH~-t(N1yHzz~=YCcD8-iTxT?<`Po01Ey0)nN_JwI6mC=XVAHF#_3={Gl#*{{4P$5AyH~k7quCYrS!PTDVqg@ zJv(a_H$Q%mf;Hv@F+!M^`iXz%tr$;URLF<^?2pG zH#mzl@d_&z;$mTr#x}sBLaY}T3Ret`G+U7cr35ixBET)tEv0(c2rh>tpI^$YMEp}b z|78BLo5(xx?|fvTq)XX}v$8b=3s)I)T7E(xep#`+lEh{QtMFLlnOFXf%R3rj%ZJ@F zIpDG&Z0_Dl?2;XQ5jkR)-20sDU}@6O+~M&nNwcxQs>Z8iTW%F;apx#v1>tDreOr zpvOKNAYdJjRz<{b!YMuyj2qXHgKOb9yfINdGL|^Ih}cs8D7Z2br=)-s%=%zRlX+2c z@7ZS|{KqVAom;}onTbVJ8GxSRUTyTxMOmer^JR~s4t=v5rJA>pW(hr{Kc$l*DR#|) z#+<48+f&1~{(QutDtiZIbmD+s%06(2(RdqgMRl*9V!| zfJXrP;etzh4U%%rG>w zMf3|-hU&~w@?xN>5+mZ9=}dyzu%a8i2x21wR6+V=dvb_{hUc&R*gpUvI9hDEh91*k zi%6pOK4MuTN@<%t5ou#`BeKe%d+XIbvV7B~)uyhhQ6V}0uNmn+P*m{lX?K(++adLw zFM}?Py-sk^ZC+-#tAbG`8D{%av0ytXKIH}5fa^nxoJy{n-~$Zq^L7O6S_BOJ8>=E1 zdN-+V)D}{oln!w-EWPADqBiKTy)4+GP{Z{uWF@k$g7`r*o>;P&h#hD+TL(&a#0&^0 zWA3Soi`#*~E(8%b2S2SNYJZP&bOuY( z_rF&FTl5)sa{oGXj-e*l;`H{LBQ5HpF!kUzq>T^FU=!ln(2rGZ#5FM5bjCODQbdf2 z@jV=jZt!3yC$-;-<5@V}u3iD5(&--)sE9b`7uwl7wW(dKe{SDiRkZUC`0=}4KLk-1 z#U9whgC74+9!a~cWc4$wISF{T=P?bZjGNdRZN8rfEfexY&EIM!08}TkaWLR zFO}2rZPT<@ASYg{)PAR>UPf&tU)q;8cR-Dw%bMX8EL{HVc70c+x=^@<5VgzP1oW@B z<1fxZM!q+TmAHg!dW(V`-uJrWE*h;hlkK|Ac{PgLZA^-x$}7LRlKr{$%2d5pX8r7i zoVe8kT*EeGNh78|-l7h&${tmj3wg`NIhv=Ik51)x=16)9$9XccoQ+yDKoI*WGGGM? zgBR+$;B2#Dl>KGwitM1iXJaT=U9`S9`-uW0RB2T!%bi2_Iizp9p z!`~0c^LW%X`BD|Us<>f*4l1S|pkn~4#VS>UN9+oW{PWjcm=49^<;I~a>{*HdTxG{6 zX6^oq_$7tg&yxz`x241^87c)U-l&Q4N|&Z3o>39ud{j!#wJT~aXMt}}7Mm)Fp~_o2 z$xPlAY5|^+N+n7m=FOL(5)-fqGagkocEd)FdW9t@8QG18%=>GMj5DSB{?HBYV?)IW zF$p)d46L>a`Ya239RUuuQw>Z)>%%b#%BABkY4m<1m< zXqT5___KED*D=fRQBz$)`{uU(m)K@(O1SRfsn|CBFw#`S?q6933f`kpP08VljOuL6 zLg#h}>_)E5t!nxgSEVfF!R1{_>kUvA8I+~z0WH5{SD4yk3)gg(hct9)vT&DELQbqW zYy%&y-9%!^Stbl~-JJd0%RX{#3qOrLQDYdzih0KrD0y$lHgLcJj9tF9=}pvFY8;yT z)>R{*bt)@zYR{EY>k*6*Z4-xhiOzJ=#}P9uygkP3cZ$ux+*aaV{mK{rmTWQ1T{)VTBaXKISi;}a}RLLHbm6rp>Z~WRB8qSW^$jTPCdM2<@8`-Wc2UcNf^!dNK+9z04xO$Z4-wHF+9)QIB zyM=GM6fo=~52dw?w7Jw|rOa5HL+GDHPDJfVhD0k4$|B?&Q`XzM5V>&ILV67y=&|$H zZrcqAk?-COPORK9*n%#qcFPG5;Pxkg+L&KIAhDNt!LN~X;HrHImE_9s+DzAaoZQ=1 zIqKx&42kxU_EGlD?IYryht%e+qk=%#Vsc|5irPL-%TAb(3`Wds^JH9{(sO8}u;C{J z*#k|dhEAw%0k2PUTEz?$>{|rMjZOEA@xwRyH18=QJHH zP3oMnGbiS@ddb$j^I7CgIAFiN<#SW|$$d%~X@aro94gmf7gui3Jboo&kFzX{cwSp@ zgNe%A=hJYFm3Ff1gjMrwSK^ju_Kn3W-gsiZgm-90Ds#}PD%O;?oVU&ClgbMsY2IR3 zqra{Sw+4m3*E;_gQ?t+60h_Bzx2u(CEZ!NK(I{%!;LCJCtWke>u_;R`<=>Y$-GDN6 z2ds#RTe~;wjG;z}hn7>TdxcTgkyLHJZQ8NDuIHbx!$^UyOqp6latu#$dH>Pz1ftih z20aCpmJ;!y7414|p4k|hvh!WS zb^aCA)`QpG@eHJk&Ai3|2yQ}V1@a4LLL^f2ZBIN-aSFFG-tw$%K+QxCTJP^PAp)_e}zFPIr7%{$tToHRn|UN$2Pa8rr?$&D`e2kO*~ zN@@SDeC;QM>ZmqJb}Uv}K#i1C4qEY<(!)O~}|Z zBGr6Y5!?9}jgf>^8<;^c`4W@8$1#&@l_OnP zeelD8^i1A@f@--|c{C;Goox1s0pJ=CjKMhD6bi*Ls8aI?KvG+n0B~a%4YU`KNOUmfA3Mp)W~5h%Psh z%w7U(fWCPzT3MB!Ws-&J;Y=ui-XWv?1O5zbBV+p`(&cv{vL%H|7Q~J~-(=eMv(?z9 z7m^{2GRn+`0u5dnlnW;)4{G#~8R+qSf(v!WlXCcEUq6t`C{E=E-6>>Fmkl?QQwibQf0A!a)FvxZ4i<`YJtZ0&gxqMMJ~b zVL{kf5HWqMe{HTW<)@Rrj!t2?bT+txVIL?h76(L2x<&!yqVP5E5)+idSD+s$$9pUz z%HP1hCEq|rUF)c>1;$Y{G?qkt7?}G>V3Q*eLd0lgED)v{X0!R+;XMyD^Ayl@D7Z{| zDw`8rY03YV0sm@cxl>e1SNgb~f_sDx3)V<%Qzaag$f@$82OA78k?N)trrN_MtJ|1k z*IRKmu2ElLB%BJx2`lsfBWl>`1Tv?`!wNx6P9!UJ#M}s|{oB5s>GLb8jEhnPVB{E! z;zZ3J_i&yBTw3m{!?l{_T4C~5Puq|=rIg&FsCUelLXF$@d*%w0p}t7Ank8pMF@&uG zchEV>294_7+`81+S`34ANTC1V9qS=?-_QFlq0m1#Kk}iwufC>fwP|U|XX$oz?<_n# zT+m&(>z##k(Cc-&J)b<+jlG`So6WI|SDPVcCFklPOW|lNE6^zXVStXM8wW#mi?lJB zdSNe?sF15iQH!)HqtD7>FrJ z^5V1~GHl%KR--##yP62<-b6S9%lvpr+i2asZn?OudT)LhT%ot@s(9~wI0fy>hN^;i z@5m$H+$riZtUEq#*~E6E?3!%kjJkAg_{1E{AT>YDD#x$%Zt$w^?CNxgDt9NkH7dK^ zGYQ!}|H~8e7OS*T)4Z32&HEIV^};W{jLTjOXlGmV70PB6ieqVX$3j7=4!QH?H4Hk$9rJio|#2aUj2ULthm_6osOrC zab12#&21#loX%I}ch`%y%T6Z&MK$lZWfv<+Pqs1kCmY7;IOB-#99{nd2j5-9OiJ&w zu%>$(D?*fwCC`Go1b)S|M2@h<`$aG!?wv_{t)V%s)Q#q1m)GIh`%%HkFpy0?IeuNP0fH`I41)g8w(37 z^M4RZ4n`(A)_(((EdRxyWMpCcw@yhw`>)S@S)yOaCL1f;7emR&{3TNUv-#icNw$AA z;h*#Vmp%Fab>x3VCmH@tPO^M?m|wglGsk}#Ct~biXm4%@w6*8s`{&pCr$PUKt^XYL ze>;@fm>Agqe{k}PF6ChOuOs_h6AGw3@A|RX!5m8y5pI=EK;u`*N>-NF%DZN(Fh&sBM`2>(`+RvaiXB~u$L0OkQ2{ED+>uFDMg`hvWF3i z1ReN;2-_-x=l#OdRxGdI%G`d%foJ!#mP2eF51q>!xo1eW5>T!?_C>> zx0k;BARP4Hgg&|s1<~QYPe1_&o4T&<8u)!G_eBES{q(csfJf*evpHQ?8#bQqeZ1`C z0rv)1VbL4b>H56OaPNXo1VoC&_PdRTk;te`K1H$lmlum%o8@`uS=`q9h*ZPG&&!XX zyO(?KfkE3*k(VxlhJOA{(iE^PG{y>2yjjoQP39^ zqvet{M$pZEpX&=VYc0b#^^2dR)$GMDLR(a_*iHhVeqvsj&bq!qt!3q)4Obc2GpM zUyFq{&JFoCP6dA$MZm&zR64Q53VceW1*x1 zdyVr4pGFAIa^4U4Q;ZKxOWchDT#1j&hOFcfldTrhr)sCu>%ou>`X)kG)-#uHLB3tS zZTQundv}Cm>PQ{lcR5z+9cfhC@u`y=5*ZVj{4qeaBB?dmlIM%kIhMyUWJxD^3r1VX z@qU(7X8g2w_^-e>(@q}o| zux&kqhpTSQ$(tX{Zlr0*UHzR994+sMQ>t$> zom^|-9L^uZ~wT_l{S-?JV=gXYUGgGr3Jj%DqasEx=_>PSo5JAYk%Z-Cv2R za<@yqirx@px#q@(YzLf`^*)-*lfWz$2s<<&_kyp$47M$=_6na(U1_c4?0Ft@0(iNZ z{47409B#XBRe7h&BT^Xq!!QALnT>?5gGYJwnQ`URTk-`{n2o9ago-1EzTSWbdoLgjgU7hmlcj_A6;A};8iK$SV3Dos@ zBW{O$`x*=eg8=Sp4=jWNCrP~3$vr^vva_A|Cj8-5Z^&;NYI$pecQ!;LDOWz!Zg|ZS^E)$#s;+}|N<@`&-ordk z+``HqC27vf2D!0dl&;=yUHIXgFhgw`Jn($>lzdG&`eD?*u;=L)dK))1KD4a zHpsWo!X3(XvgQeOc=4Bf1KBFN!Bcm~X?D-nZcY=L~taEFV0``_%NLyv^Ey!z%Y~kgVxOqwL zWHz_M0hMk;}e=}&Yqfp+}1PI)~r4=!s9R!#F&W-v7Nq}(de;z@NZK3Jo?>EvG1>p z6(jS0`-qevwV6j zL0OgR$kst<{?kzc+>B+;+JRU8bBWYuvI|lZU7lB}f<~a029i`eT(bFHX={3hHT~N{ zaRZIr3B~IUR#D(Cfhhv3$s#LU@gaAyF~;NIw@IVL8xlJewxLumUgiwj`G;2B*=n`S zX!pa^cD%j?dHUjZZZxRKU4dap?{w{P?Ye<5xOI(GH)p(%lRMAvqn zw&XyMZLT^fGSBLMAKdETb;i<&&D2VlG68nuW7l)mP8!SC%E#$ha!d!c(hpCYCzM62 z)~a#^Z;E?88v0PM?$1pba`HoL!7*B9;lb=~;zt%)*iE!(J4|^e{o;3g0H%+s#FBZZ za(0~*Za2{~SaT5sG4bEC43JD7MZL|7f9mmNO##rq=2V^D_<(WQle4;RzDg@CnstSi zs|^_|cn`!6Ox#0R$@Q+W+uL|iMMKPsb$xX`fK&6U@<*%tdRLFk>ciVy1(XnTgH{f$ zF_gM~B1KXQQSCK)Ji0Vahm$d8(|4AD&710)q)tito*t75T(ru-0DLYqHrX3@mZ(+c zW#)P2&AKrM-=dAWfx7K` zm$R%WPxq^}Zc)DkKU6;$h-+y>yRXt;_e^)zw=}oA&0sI)dv=)f`nQ8IwcX}}_LrTq z9JLMC{Y14yoYwQLjH6(ubE~6tkY??#rG$S)@Xs2}&zKyoo2pXryVgn3l8eLNV0FhP zjWRsA=(m}lG~TRqN5JWKnOl;wdQGpFJ>auO53ip+K|mROx3ChPE82WOc0$&!)h_Y>cCF*JFK`@yI+>{s>_zSC$IKBz^e=v zt1Xuu&tT5noIqcRR{L#?K+njWnA-x@M>_kQ>gelu&*+z}&zzhf+TzyxJ9|1uItL~X zsh`2$gq+yls!VNbd(UVe*j{ZP+#lfGliq#dYKhM%+@m@sBWrf8f=QPdxVx3on+Grt z*ZS9af(~zZ_(B$MJaqr^wnxh!6kQYX1*{L^8E+b(wPkrGy|dbGofgNnQV5Xg$f+qr zyV>Qk)Suy#bz(pYjTn`?CrmIY+x-@ zQ_%x%gHumdY1X_kAJUeUtE=-lKa@MPGfRgR$x?DvR1DolD_NR#LJ8rx<>5tnq zY1ehY!NKg;sX+)%64h&c&wrWbNi-Vx=EmYlVnsZzAzfbI0q+Vmy;zilXDThVMt>jRkrm4`G)41pL^=*C7JX%$Y*4wRM zyg^T#?R@*54gR;hWn+lX`XV4zXlbpr)HD1Bxi7aJkA za(i3rjE283#+K}+ux5$wsxfM?ID{ORo~Ku4p%)7FCaAcCAtOJT&3oLi$e(^7AnIwP z-0c^>&(HZnlz9Wn-f4>S_7qDiwWmyKoLcM&I&Mm6?F;xjVi9d06Ni=N8@NB+zW1wo z2dS$^o|SpmT_K$I?9{Dtdw{quMu6B_S7bCLs+P5)NiEbXjdb$~h@i#Y`J(D7{=Uxm=N5)l_N7 zpfkt3H>#qaEay~zq5g5xZkYx_61Av7#5iS!m|BHp*ywShl%^TwY4Iz2gZczw1>)|# ztoGh z>@-S>zL}|)(M%Oi)z55X*3K}8CdI4TEK(I&CYV|z@M;>@kPQcRl`9i7yzXaxuMVj2 zx(laVq0=8>06S>8Zc2`Szqs=L zmi+c<)1K8Omu_$F=IEOyZ?9M>Mn|J_cP2V%kuZt&{<7?VPMe~{W~{m#U+X2;`yMX0 zb!c7NtoJ_dYZlnZdJB=Zl@vyfZTeS@gQF-#`FyLA29F(8Dah~8X!`aDfZ}u| zS^u+(!I~%QBHt5USD--C&(FPB_0;~VCw;ad2*-nocEnTZV}6JgO8#T530FIB*fk9| z9mLkzPOia~5W?B`y4l=qBM&|^PINNw*_Ge%>wvVE#eRpDsBx({?LKs4o5x#tD+!G9xXsL`=G>E(!vI{bxvj;MEHCcBGX!eA5% zZDYm>-9o#@;(_BYt^wQ&%r~O1wl9rQf z7D5JFK%E{8F&<3__arJ16s_;?zZsmOLkKBN9g<8~ogGFSF#;4Nz>88=QGIxLPz7=` zraA?qcG@}b2hp&L_I^3Cc$Q+JvRQ~_@m_N)Kk~+X?Wz!LY?qd1)Hl`ZN(+AP{-~+Z zEw?N$S)I}*SJi26skHH24@8T}+C&lvS8^}9U^Z%J!i_QGFc8`07HI~^sDDE(4j~$? z=5h+g-S&^a4{#5s_%26q?qsklR?kf~e?$byFU$m^qu6`I7X5wtM~%;hADGinxDXTH z2=208huhrGKqzCyZ8cQ*i=P?Oc8@NTMvT2Wfd=OReZlRU;r)3g;zaPscI-Gz`SLS@ z`w5c_2FU%IF>(rGF;+y=c@W5M;tFUiCVk{+Ye>*oHOW%pp+B!n=aO?=FsKX=drh5k z4+o4zfui>c+JVHzj$NDaaRo(#rP{IQPD+U3zv;}J(wHPL6ln-!f`@|Skom@R*yQg5 z^VIrwEHqX0sI0d)qJv4e{*VPi1rnMs7HVx0{=_)JS|+UHjvbgzG|t507XLFZ%-xp& zMNC#PR4MQ$kB~gy%*{J`tww+Y@y@X9h%sU##w~m#Xis<X%uxJ~NoFO+s3!2dAsOf}#D!&FyIp6|EI}1CFnV%q0_3LI@a~ zOvVwTAzAD9mb#;!MU`a z^7J`BKR830Lpp1)N2(Xa68P{$&5^`@!tCb`N+kb%*%P8c39Am(mu5vgemf8CevR< z__&*ZiWvOmr3Zg84T0B@ApT&{Fy{R38&vxxO^-8Y^}SJSRIbZu2nZJ?ye3>Vh3K3L zL_Zi>E_8W$EHhdnp zT3?_OQJafHW~%L~{U?K_A4Z;GSuL6a4{|*$n;HSpJF%H<-#Wy{cqo?7M06;VPXj9z z0*LW%x&|ZQ+#jO6J70MdW4r{v*01ZL!Uv>9U_6Mdm-gU`O)1Us$ZUj^A%(Pa(GADN zFC{hY<67SPvKL6RtCDi@>ein#KbT?^FiRBDufsFo)k90TAj!G4>=HD4M!1h#CTmK{ z$|XwB%;bML_ElAf5*BlW%YZ3a3TQ+p!lH&LxEYp`3q|e&X`uGQ>_~w7vWBX2sHI^$ z)f%D+PYP74-JgS!>?ISAz0z4H`zA$U#*IcI2`L_Pk)aHwC%A#M zS#jrZ#a1vxWe{_}t-@^2(P{OFmt}*PnK^*Bc?4G^h`oEve?Zv^e=v7V>(9ufy6Rx~+*IYI#A5OZ=a~y4 zz|Aw;iR*PO=rL3QMQ8i?B>()R`s*L7M*fHAnz>5m_QXbpn8j6h3QTE6-+fU z1g|I)H4_y#g2QjIalktf_c8Q5Inm~o`wcU$-9)JO&?QD{v&joU*5^taHUfGKqr5`$nEc&4~f&dqIElqEqvArbI)CBYg5ZT|2xVI{7&I~>f)&3_rBS8 zLGGNfm;RGwg$z94!9e3w#yq>qmQ0rGF*0i+=VpGU+hAEuVx9BJ9VLOgl-ld+Q%XoN ztZ`_5KIn69L@@sA^ z3E-s@feH@~a4elz8&`qt}4 zFLYD6bD(xXe8L$pd_EL=!@a%_;NA{a7CHy)=aEe+v`DEDmQJLpADkh}Az)iPK9w`4 z4J7mK$|p(pE<1+HB)nTlo!c-D0;RPb!zzKHV`)M!8RN>QCWZWiheFOb`lV*);ZYNk z9F{>dDi9ODP1YNyf^47UGt>A#nj)>u%e{0uB&|R3qcgir|L4llKhbFau1W|C5-`#+ z{J(_^Q5T>%0H_Z%rZ?38=iUFcl)>?zoy5$ofX4R!lwN?wBF2WcM#ldxUl1^{aAm_)_+*4nZNi^?>p1vn)3uiIev2^Pi)k4FjlJ7X z{mrI+a~%8gbH8`_8NbVPJgCYACw-=|Mw>mI^4z#R%VVSm8APm4{FCF=b%AW-57!@! zle?ArM8UM#v*Ho;Q-AZ5OQ{-$Efwz1T)3t|)p8Mlw^}GGbMX@7+{jsOD(S9n-Jd`| zKHr0)bZbnD1bfACBvPn>e1Qt9YiF@>jMbv<=V50jli%Y~q~kUkrqt95jDz{H7T|gg z9=87f4}0$%BCVyKLL`t>5WBuTS51`o8|-#EW|) z?jM=)<%-M|ncs*t*O)8EnA2mHbx05iMp~)cco(Zf|7$YIHT!TQD#I$-XS27P-qo6BX_7aVCk9l4A z1^WuuhL`rSAS&|hXa~11Vh()(_Wjk=dSg6d&Ye$xTbxu{A9Obzqhj^rKbhn*{s>ka7G+SEZKW`8n#qtuJ-N^9M!{n!3N)Xt{$bnID@0Y@2E2_BZE95m0dJY9g&omdj2=k{OFYO=mnBpzTqUO$|Od}-X#%u^qAc8Ok>M)&OuQy6?k=)gdBR64NM+M zXE_g53`U=#Xk;7IEuTc!`g-aCzmSQcQWJt>a3?CUJJ zZOVzoa%npyFHr3cd@4_AQ1;Mo#l2l@UxBnDe*=7DNut{|807VNz>?&tkYwNRTPK}} zbxkkab3uq*#ZD(t#)%qR)jJua2Nh@t>ts+tV)|N$24|g|(&hAHrK-6UoBUpFHb^3iSlE8eX!Ewi-Gs01$%-ofDJpNnmIW&KG4!kaA7D#q99`R^HSr5 zud)Fm9_)dE#+yhAIF0gv$jYzd4^XOBJ%~^k8E_$d&sN&}d^>ZEaO;c|V~m*&nePgb zqH%&_tr0Tm1_=)$>L`YhxrEK)@#HNu5~Z-mFCJ2K74%V&VOq=vFl^mNPkJ=IfWtK= ze!ZLG+qm9_uZtp)EXa6XTCizi@(3|SNl0yQDJ@LgY`*Jj4mCp=bz#N7loA6$6Bf4eRK?B)w zjBuys+ZBu>I6TzqwOUy2WEH%Z#8K@Gd3J(>!Y| zKrq!8^s||}zHu!EbhnDdoEBxa<3l-cnr&oz?SMXq^y4O!$ zDx+u3zl0s%=67}1tk@sh&D|wMq@o~LPV9ud%{Cy z2$KLXT0DX^Hw+`Ot4QN*xj^9x$&N%rdKq`)CS>OjYS<}p$FyKR%4GLU;R~H6x{8cY z97*%XdFcSKneTDoiQMzl79#Bhhar^=P=XYYhY@m_4e}2oHQAq7Q8~j+p<8x-*c)o~ zl1KgE?BRQxZmOxd@&xKTlRVuWFUKi9%9ZP8*Ys4 z4u;XsRlR-mYnWWP)DhEASSO_>j+g~W#-P!8P!`ir1EIjipzfD5YI=facgCO;rfigs zl#@`zQ)52oqYJdsa1--a+)Re`F9EEllQ+i5)`$_7Cddy$*e*P`DL8-=7oW?)N?AD$ zR2n)Cg0)gSwS^8Gt94cXR(|25_TU!q_I^0H`TWTEwqgwqx;=eM^e%U9Ebe|^@oaH3 zeYL;6zg(8Qg&eAwsyRH2|9%_Z%JKOckBRyE@LbCLI=P(u{hN03g=PKYV>09|gf-?V z2QPhme9~!2@oESgI7*hTli?DPG) znY$-YA3$}MBf>V%gOqwlM&ov4ZCHjkUwm5!zuT+_-uNSDd%9jCU(0-zsFdn82LKpg zLy=nQpVQKRXgkf%Z{w;#M??3m;Q4-H|F*2NeK&`tVWXp?V`Bf7?)(!1s^{P+Wn*Y& zY-VKmQ;>s!j-Kti(JVa!13eQH6Ez(x866!N`QK?OJu@Axl%Au#nXAS(&;6eG-yZ*P ztwk$qW@KO_W^HW4#YM{}$SM~`WmwKX3l@{Y*8aUL!)oW5DyQnype;Alf8k__hiiMEdNJ7!=PkTNq3|z)^xp(#f7i(Uzag!I>XZG}FM1B*qTZ)1&+&)^5t(n) zhXph?HKK$-p}xB#JGGKM;XxFD8rYmriD*_wuByZLLie$)&5Z5LPpx^JVBpHEl2J#vNx7A1(HO4T75P?k4lXcyl?Et1=Ua`@_a++ zv_XRO&msJ)!}mXhko{YJ_pbzyiRE7o;9pA8f7zP+w*~%R0mvjV{@0r9xKf#r}j zL4Is$N!6S_^6DBi-YW@9MSL14EdAk>s@+UF>5;kX7CxYYsYr6vof%$4(S1MFa6L zWn^Lh$EcJj-)rsv3*|j2g(MGF#rFZT zxjVJf!3?>Ga4^-=Zi$+#iDHHBkxr}TAe<8@RD80z*qvO>(sS>Cou6V7nYmdx@w$MeC20i&XO=vC zhlkjErh`aEghPl7TuPV<-gBYiJiAkSS4dBW9X!?I8U}Mx{=Bcz3e26cjr_w0?tBCe za|dBcf_)ulHHz?>=d^t|dQi-v7P%oKZST!uQr2mOx?%WN!=L|G5BXo8v(JQy-fZ@YQu| zo&F1yVd8RPs#;~Vi$ifLn#&Eovs!Pz%89gRMkfHwJ2=9LDrsGn`@6n}(~@hlpdB|X zv15{jhcZeg89qH{q~2~s)yeerKzxfXfvU?+M2#1&o!7%BIEO7UdL>nxAB(cP*}KI& zpp0yDrR2n#ox1R3zzw_GHjF*;Li1HBh}w z9ChG&3Zr;T=pQ&an5my@1Y;!m?}4U25V-MY4wP-~R6b@S`O`;6gmRV7e~KO)q*p2k zno0K(gD#=0%WJSV2`$Ehoc`ith{rZhi$tMEJz&tMu$NV2Oku)dPMv?RxMx9~r2iUn z+jzn~v4F7SekQf0y%Vkscx$-n%u%}g0A+kBjr`{^^&j(+zZ)$CzR9|ok-fB$i>!i_ z;{VTn3zqM6<(t?1or?U|ehUJ276KN!@AQV9m4!v?KW*`Uo8#|Pz`?-C+L3^b@te`n zvwwRm{=;|iop;eNFnk*({=;{{_&p&5I|DoGzk4sfJs97viNDc%Y6f~5rf+8iD>DH# z3oAPf3)}Y<3nMEH%lEAG1m6i69Su7>3*BES-1ld`1CtTMU&#~8UnEohZ)1ORU;IyZ z_n(z0v-@pf&!Y5QDNPid3Nx z6#h^uvWONaouNU7PhKX@$YT$$msg!nTLvcG^G6eDH9jV!*aQH%eri3vvE_K3!Mxpv z@v{InU9de_<)?OHGAfO*XIGZsu_)0Q494mY9yyUfvYi0Br}USvn43x!L+>!LU$DOC zQx(Nhsr3&dSMz`!WOklgkO?;J=IT$k06o9hd)U4PZVal|nHQ+HQDX>DWCp+%s2fpy zG3xL#*^Gvw@cY`aDpi1ghDc>|Si`W}*%JR6H3ZnJCpWOpEKbesf_sy&?RZ+HR~V{T zLhk^d!2qVC&3KHtnU}WWE(C-y=)M)weG=aK+UcsjVc?Hhpq*v2OSgaX><`{7JA zd}jaarIXGNb|6#gnOm-pg)KUkAZK1Z9$2SGA1SEHkT%n|rq%?u0}fmdeYQX3nwdVf z(>2CGkBdtX#umcSmVF}dKo*uVR(WX~(;^p4LU|-8tQIg2tGS1$6=ez0pO6lYC*SD$ z2l-%{pJm8kY=Fsnvbw8v8~FdbC80HpSVo+%;xy!;hHF@wn&UcmOo=u zPzZuBKe1pQ#wTP>0u@p)Lq~?0t-oi?6FdCko;uASXGYjj9kZ0+O#jDd&dn!$0t-@~ zTk`JMFyWz*Ei5h^rminz=;%+J{x(Nfc$jiTk1}9exE}VEx}?NiW(hG?C`0ZQ@%9AZ z&`w0xN$SwFnB1Ub(zR{4%n!W|Z8&+_08JSh;=MVX-eY_0sZrtSfj2{2k6X%i=$baw zzynpA{)%ZNJ+!HHxVBJMFl0oF1y?*^mT96whyV%12pC&bqKN@coUrFrL7ZBU$A0S3 znozuP%wMBc7d`T>cyZ7B${%#1?1_D6{Xv4>tcU+YC81(RXdgDX!1=paGI>zh8pk%){)R;^ z&dvL+TP@g28yNemADrhDKfnN4p4?PABSsi_|ExZ(Dz%^?^bk1K)jk-Mw>{a~){S2JmCU*ta_I1(wA@9cW zc9=!vYTl+6#X&+D;gKId<%3Th8FLRL}C-y zvJE4YMuSeYP#%RKKoYoF2kM8Ek#!kytfC2KY&>Te3B4?Kd{Ggo|JFOBiI^6qw42A>VSf+Wsz?ue-dr-S&d#;%T_ z(}B_OMdAo=&JcieMWvR4(u&5yU2WeW%J0#f8>y&)jgPqOtK3qKJuw?1vkP^R=yAZ+ zEr!}FK8So*to(!#)}z(Rol|$mISAt>ZOL@lm_6(t+njk zpm9aN8o-qe?xAuuCk&6yHY{KE0PUd!o1~1u|9ah)gZ&DY8NCvvy>Ar64su6cy2cQ{ zps5cz7vz2hv%f?`5*n?Irxc~VWO3Et@&R>At0bz4V8BC-p}G-u#`%o^e6%=?$8F2R zAM)|8v!l6oqjHUE{==AYIqN;ACn$MO6NBs(mt5CEcj=k-D3KL+;6PR|GH*;DrDyIFxh3JRS zKHx2hnIMhi9M&t^hSb*}V)P!0rtj~pjA`oq?ETHXg?C+VCY@p45#BN0UfxNY?UtLI z>n-tSQSB5@GWH)z61eg)jTw%q_gE(=W&w`D_s%CcCrBrZb4NvIg;(Od@pvhpJJ}bX z{S^=C9o98l*pG)E&>b5cMVt0Ev{#Z>jGI30I@e;JU^y#CPeER7T{~Trp73wkcM9Eq zY97u$NV_+#ZbaVYe007rzMcVKApr5~Nny(b_(w46gERAVf1**qBn6X(7zbU#O~O*c zaAUYL-1C=`H!?SJH&Ql|HPYUT9SgQH;lMvZEQJgQ)j;XoMeSp6um;;yZaMOb$xuii z=H!`ln1oL!W|Q+OxD_v@<(ZgINwPbvrGc8@@g!I(H5xabYH+qZn&Ymk&vP_8$)7bY zo~ffZZEn5Fo;6fWH+{<}^P1`&3KnBDz7~?VlxJC5E>Z+7h|(;jNaIkn8sW5Ak>Kk8*Z(_A_2$UTjFB;;rI8;uFjw z-wN%_xb;0(b@bm0J(4|&R4$lZskLiDZ>Bb@aWQZ>O>~Qth4_!*= zwXeG62U?%Hb-yb(521%B2P?bizT*x&4~O1Z<6_|BXWzpj(p$e4--+4B^OkW7AndJ} zh$HOXFmg}d^DypC6f&~rr1>0nF;-RCBkpCXQ>ueEDYt0*VdTtlbUyGP?u~QMbz#$g zlIwRU4m?+)3?=B~6L6(65kSgG?zAldS|gC>XyoQYTJP*Yr*5^*Am8S32_ zC)Q)qL00o`l{P-;REelRwOpEUFTV1f@vziC)Ghu<m&fOF8FpB^FL@B+E@tEL#Yuz=xASCqk+xv?lJj+a zR)oi6zoCRj1K@h4;k=_Dc^ZqSqF?>f+y^5cvzRrHBil*+&l{b`t}x%n)SUk5qZG~Maaze(ogZUy*H)3BI*1fb1UEOUy{wLt^&JzSLck zcbKRA!EET7Uc_fe>L>HYh3+2mdo7(`(C?&`LKX~g7qdwiB9S7rx~!|$+{g2mK{awv znSDz5>UWvAWWJqklRmYTE!92tArU4*v`6^T) zB<}Pwx#$f*PKODCe2IcWe~v+UVM}&c?}Jq0Oh$QUIbE|Wg|Bu&>ytY|+nW#z?nvta zy+dL~JnMZe1!c?_-O(qH)l72X>yu2weDRv`3_hpB{4i!YSEMBeBD3Gdk6+Gz`5Y+S zV$~r~Rt5;`3&>nM-SguNh-nT)Wlv;WgTKD&^rQ?3bPR~RA6s-vITy4vhjc`=e{duH z;w2O8GsIts(cT2#7qACt&ezEiA|k<#?pN6-z9)_8BfBQY85-F~c#n7&l#b7tMf>u{ z+b6eAe-Fl6z~7g-x0{Mpj-){*33kTn*Au75+b#qSd!7OpA z=#B&viTWe#cfjw6jLD7u$-T=1G&^{Ec!wA}nOu|FaF1+_{;GpTyR$Z_b+k*POQlO# zYu1*O@92NTv&*ydIp{UzHRv_oWXo&EJD+nxd%ty$@{yEX+&#O+PJWc{GsAm=xjIJ9 zj#?rtA$mQO&5yr_>5ckD^(FJk{^{n;+#T%WrxT%Ui@P;abCfXyyfR|5%X&wfr?uW^ zBjjVq`Ni-B)g7=k+CA1i)ID{zyS2TwzqPw{=yG>;?eXmL()sT3&g0Gd#q$ODMd;)E z70Nq;&tLHh`9u9@fFEChQG&q)Vyiwq(fcKg}IA(HRd5+(EzvKq?o$3?+UF#j@kBrOR(oMq) zw%qVW|MbC8Ua>~cmaq3R|EKmRk2m5gIQ(5qUPx`CPH^@L@o^6Ij?F>J9p!V&z&OGgL%01ghcy_Li1I^SVs@>pvcbh_KP0>u9mDtbP*t2(dXZsF8iUi6;iY8J4 z%Hw;mf>F!5)pNL#@r#?+cR$^qnQ5q_(L?t3cek8QG(V{*F6HN%G@j<_Z^K=UVzN8S z-Jed@YQB6Wz~HdB43BFiLUdSmZ%@25gM=)AgEgTL~*-tmip!+U*Bkb%d4Suzo!bst3U+>Ow_5vqC4SMi*s>^er(xexyy z{_=SW-@9=Ya#J&VveuGlM?pn%yiCkV$v}=U7O7|G&(rO>x^rKrDe1RvP@f+ z#1YYU>K$=4H|#JVLF_1!O-H^{2JMLQ@Brvbmyw$I(?5&>; zA#<&$MD}pQ7VB&&uX}nxK2lkD>N{DiNaP0Q9;S5AuhlN=%ZHMPO73ZV7?7790BTZn z(vab+?iFHQ1@0`zvhvfm1dY-xHJ?a|5(rjSd9Z)>WM;1uo^#ODwIl{{XEHC?MK~tc zE|yzukR#O|@?idrt-7s+zsByP*8pH}R&YuQtP+i>wJ{P^rnfXBbkp96Ma_!el3lgC z|C+tV^H~2~(%{JzTLrF)r)6n)E*&cqc)BQW^Wn~8uLzw830(7Zuwr(F zc_GS>MSE`iGH^rb^m7QjTvg(O#HN5~hM3Oov(TL+%FCM==J)85Vasp}NsM3T7^jb` zQ_qs>4#c0xlLJkgz?XjORow^=tD~p=fko(c6#XR=(|ORQ!}Y%BXr4L}IFlm4ehxZ` z<#3>nSVFAMy^hxSQ-DncNQt48o_D(+Y%sjcAk*d@NaXfT1^Ff)o_W|7CP%E|{Ko@R zU#Lmn3hslDJB^`2jY7g56Jd;KNW`3m59 z5L)9<9t{6hT!ndR_}QyFdLUZU=zi5orYS7-ta1;%$^yt;x7l=I^=WtK=BHE|1MY@Z z4-V-XcmgsTlzugZ0Ig#qiRfp^x8J%tZo8dw+%j`~#%=5C&-HNgJqilSEu zj@P*&VS#D$DZcq1r`rSChGVn10cu6+8zUjtl&ER1W5#JXZSt0co10PmUR#Rl1@|wX z!wKmLWGia=&X0}v4A{SgrfXbyYrHpa|J<=_(%}~a2ghXc>bPm^*!=l*ck~43>M>oD z!&}VGZeiI&336z&)2HeB*;xMS9L_@4LSxJHsI3~nN+0Jqz7oGadSTgKNw68I#!9~y zi+IizaX=B3%1RDJL2=ibMF*>g+s6ZfcS@I)X1&uBU&=wFIkfM9ExmwI?wUT(1&! zztTq_d9PZE{+qm|PWXky;A7FRfilmyd&QH!deSQP4gVnVA1eJ(zEf;MP8{8t*t36D z8Vc&Of5Vh$lND38?WEEm&2!M>QWY}}Zl>wGm8)h`BvTI93$;(obvVe!q?)UZ!S2xn zK{Uf0yhgkrR73Hn!VhtbgWG)!coHm$Owjf^Qyv1_X5!s_YTDFo!k=~0T}3!0Kkc}) zKHToBNcX$rKFW3ASzHBK90ysP28rrZM<6H@;h<`K-@UL}ct2zjq-u0L?witmiknEb zDa7GyHd{@c7$~l>Hv4n({yL-7p*Hy&JPA8Ra_uq{JEd^O6e2hAIIbdsJ#qR6d!g7E z1Q85>*%*ReH+@%am?hMH%7IoKh+R#dc7(`OkNLI`8UWTq>-OByi!c?6W8uHv`wbx4 z#xlvQ1!WXlbkw8(Mx<;A9kL#19|s7#Vxjvkg*qQ)Yp)~SFtLjWOJcG!+MWNd;-zDe zeN$&c^DVw6$SjH$cUh!;V!K4?n~P4 z&oZ`4vOp4`5Xr=_yBuC&qU;O45l$1d#q=O*HP!Jxhk9E}v}U})#88vkPeOa#rykb;+v52yeJ65@%X3QIjb~DP~1e@T*x@4W`b#An~7urLFiI8@9 zkBWsNRQ#$T1bi}H(CEFy$T3u0@2=0+*Smfwg7C9a=zDb#F>lwc=rKXARKLtImV{gc z&9r9!l&=phq{CQHNia&hgtWxgvMbx5gEi(bhp zTP;;w%wo2F+sZEm)IUW$eJdEHg!ceI#mf)Zpglng)yb$`qxjTk@^GS}v8*+Kg!#d7Q#Ad=!{9 z0IsbWJVUPC5gP{G;+pI0+%HDCe8>b4_gLW%01Ud0kfu5b$6pOp?3HyS9JzAzhKdjF z{FfEI>cm-VlDe)=jAHf0D{zO@)`0x_4OdQucj;Kp(hu(0>mD|+sWmmV%E#kQS{_fY z5rsTi!qeWBvksK4NGf~8z%*6Xniu6}=Mzw3Dw6;MI1V%|Gf3*13l`89ef8<5)MILm zh2|I*DpRLQ4$e5Pb)8FS*L9LO;My#39q5q`^E8&4p+;qP)^?e19d>8qo=TmIZ=M$h zV*~U?M=@!(pQ(_$sgNi1n&y#Lne_Dr+sMPuhQpr*k#9a2$gkt{N4gH4F~?h;BWTAm zaMf3CjCT`fz)E|Fr`YJ4ytAup7L`lCLEYm6%u2X5d7ak`S2rbVRmgP2xKhWR#Ze#36o6^*(Qo}y5;xp-52+~*QA<^( zv3GFEd2k+9#v5_S<)2oKl1m2jb2?BwRIH~-WLQk<1*&ySd3e0!8CJg4Y?tUU*2)D} zt*E{X+B%t^5Bj>{^m@I=RFUk~=NKQny2o51q+{rHOyvQ-hND=>_qxkvF>ZGQ?Bkac zahNYzngEC^p05FBS%XQ=%<3p`#GR5X&KU=x`{;w;i~Ly#P?F(|+bd_e?PS)RHl@wf zZ{|zQzzlhnW6 zX&Gy=#J0fWccbHj{P(9)tOhZjmf&?rcD8X_R}iXNc#{cfin=bpc2n|fW}HV`r(0D9 z-WTYV(JSfbpb}AX?vZYYD}LykyVzFBHi9;$HW-F&lp}Kw?iF%&(CK!V(;bdhR24et zX))>DPaa;tW(@L)gjnBXsRTilRbpbAaKah z6eqUsm@Q~HvZP&;-n_e(?E3bsI6v&=Mcd=p(gd_~m+myzXd17$QV{~YgwD6%B@jz0 zbaBu9KdyPEUKn>1iCIWKj0~CDq9#b6;zC9!Zh_q5JY{~|8$|D2ekVlTGB}bH2{B|j z!)F{lklOc-2BHBHvDqFwoE_bkNW`f7z*t4}(buQVg82k1WbBMD!nX(@1jxh5c`6#9 zz&rMu4^p=1mI16c>z&tlnZ8>H5;$^5+`D}eK!zA?iJD}W^PhsNrI;rw{ABZ_?!FQB z9xvlB=xZ#bl3~RIGGT`HQuXvN?zdWTU4yP!*`j{xslh-)Kbs+I?!a(DY<5&Sf)ibB ztGq@5I<|hWeaX#*pOcid%%htkd2J1@TW=20iou9WicyJKilUK%6WQ1u+ppvz#8{6= zrSQQ{d6DVgnW;u4uK2DyAb67~?~=Y0;$!lai*cuk7RQ?v`mOU@3sv&Su*6&K6R=Bq z7jh-ZBkz)n56^O*1UM3J2*JvbdK#KC?eTg^9z=uqm7iJO1GxI^YA? zV^NNf#r_6E&dfZoxcTa%$GN1&XpJ%6o|FUu46Tka;Dy+ES;(Y99J41vCW0XQRwpix z6m$~%Y9)ps^Z2K09f_Y$fTz6-{NH9^(K-HLSw{T|&Q5qBRdiA4!w*>?UcRXeYN|J!GHhCr%4j^2wxz`9vf(%Fz6nG!kP+dHFc z8+$VPy!~vxRge><9tSKAIJgJD&R05Sa*rc&8_zmvjT zJ3#8#v7DwCOo?yv7*TdMk_6!Yh=0`DKt%rXQjbx;rD#RNlD*>rr0sEUlm$k>SJ`$` z=_RquiAFm`YsEeI!cz_9*hX|k+bpR#fr_*}nqxhFxHo@B;W^mc-8BTk**>~q+>wv; z4M76dZiAK|4LG8f^bS>t@C9!2ArvRS^}2oA@7;H>db8~^vAcj5_2_w;%f`*8yYM9F z?FQTzBrChr%~EtbR@{*9^inz)qwIE zMMW9~|6eeS=dOM!yI`=(N{8q{_W4vUoua~ikt5CX-rGSSm>`R#w(ZRa&vrY{cBQ4J zi0YxzTd3Vxw_?CMg>$~VnWI4wP!Z4^8B)U1l0|@)gQTzWsp^jI(6F-|zX)7BjT6U|4!ktP=|3=B&F`CZ8wNgGwB3Tc@>>zY=dD zmZ!b-qe(d}F+I{fqE*|+I5pVJ>f}_?DR`6g_hUF^b<)Z`=IM-s-R-y||7fl6Sh+&^ zmKYOn1I28IM%AAcMejLYz`%VH^^=Kvb7H9S+O^WjsRmTad-({pSW&ws@gFo;OBF&4 zvbDdnSH!`ZYo3@iuIw~xTi5TDEeaJ$QR7yMRCN?Z85L5SQy+{u?r2rs?(PK{>K1F7 zcg$T9x~40MytaB5h_aD0R?G{+fbYHHp`m_;YUl*OZ)0Q%cCAb#_{^*909Q>A7t~)E zLjKf)vMU<#>9}CqZwiIJjk~uWk3LANTN0vL)!(53jyEN+EvWE!#t?h9gWS?QoX&~j<*iL0PsT|9dElLQHUK-*xf*Z zVyq)?MLI4&mU<-@Ca;#$l(ANvNSIdO;>S~{B$}pV={LSbTd86bm5#MREg8LniV){h zoZP>V$}GnbCQlbbrZG=^Kj4bC4RM?_TzkE64Jk2SQ3v`epwX^L88 zcVzkDrEWAavqI9#TOq(wwMybP6|Xm69$TohI2N^PyVuIY!XZ)kj>XZ>H|*rB9TBz9Fi56_5K4dR5TMa8>ZVkeEs5& z0L^Hk>AN3{P8yFg>8u0^mIo%&ybG%fRI<_XZO*!Q;fQ$M3i&-$31UC$$OrX^prrEe z;?}Ywshc<^6$lM0w2T$wdQ2;%viTkRR$M%A+DRCbAmW{KI$EW&B=aEk>g2K?@-*j5 zpnKcQ%X=ggu!Dpl(-8^2i|Ax<*ra++RB&x5$Tvw4H`Jk)?}Asp@%JH#nQtfT?Htx~ zZLrNy1sW!0Gj#*!&S#YGlcS6`Y-kKo(zv8>fXEqW$P&UrzCY508^9z|ZG~}$+aAip zaej~*E8AmQ@vw}-+d-o>3P*%w9hBvY^Qls(Drh5m^4#YSmb!9JVvTF zv_ERK#^Y_~JiEPAZA5s&Cq|`q)P`{X(fOkh7IgIf9x)MaT{yVgwDKqGBQKi03> zF+puzcNgHPZ55_)rYCd{H*t`UphmYEgnEYtsF=3Q9q~ye525<2SD|XljgVW!=|*IW zk|cHz$$SZgNnX)e7lr&1A?pA^3evPH7_z#DYXm}j)z*YWcI03HwDP@X$O4mgjqga= zB`7|V2x>;#Ni2<2Pi<~-1kJ0G++v;<57d#l;Ha4+$2S+EIP)ZTdknkP+@2R(T~J1E zPj%gJ{{7pEK_ZOxra&&QiTr@&^NF#58tl73H>>LNJEDAsbVXdl*05$kDqCPZN)T^L zZmTC+47-1jR}-tr#As#$Guf@>VndwOY19f-l(rd-e2U>++^=R%^9e^2&_BYc20)W8 zuV{BUuPlr?KWs$i;!@_=;yWax3qBPPVNWaMuu-9kRyQR-mrcK$!|P&W{Yo^kO!29v zgjO;?RvZC@Zf>{h2$%N5XzSM64xBGZ?a=FMRF?qFzhqM%VG1S)B1GXTAuDZ37uc*F zHHiu!%#A>f82;=2c&pm5??p_xbQqNIEo zjG>idGwRKcru~I^hGHI?V{%1Hq}y)9b?F&0z76iB!EyKHA~LUZ78{$z zZ9~hFx{-K9?AHWp&eRo)@oVHj92qA1rMP!5a-%W*Gu5REJBoBSk^Y%+(!L-~*dL+l zD5|jYX540Po20dOQ4|M8`C(ts5LNi5qL-sxkQ{8N=+lKnn2r; z8Og3lN-869k2GKFA!QD1BF9@&9Ckt!OVTfQvD$+`*P_FaDnqnkp_xoHbN9;;q|Q<}7VWIL-Sjvr7ZAk4{1eqjQq;m8^5NZ<&FQKmG#mCb&~ zt8yciJ|TM4$C_0796^W9&7_QP)6^QDv!hY0nw&rJnxQ!Q3#8yLJ)IY|T-=yV!`~SH z+`^L#d2r=exxYQ-%cAF~+01YKe#?2PszRzXPVYYs&@2);UyW-3j+Id!UTE_+sGYfr zZuh#pUfef(OjqS92)&}Y8ikM58H!1i5D49d4b`#Xc#3e#rCZMALQv5c0GWmxW1e(9 zl*~Rl5Z?R=f2ZfxoR^{JtCy%3zeC!u*?+#x(qFt?QZDnbWdTD$6gS>6S1W~mAMCl; zx#!9HVm+3g%}VVP;G^-#_kcczZ2lq2Uhc+M@`M$Mm#}tTzYJ0_1kV@6Q3ypT=8ZQQ zm1iqtIBOXul%5Ca%%9L`t{{y$OpY_T-_W|EV4P@}OwP18U1StXZRpW(*YI+la-w|< z!-oXI?DhD=N6i~-wAN`=SbPK*SGdxd0J*GL-I0?*UA7vdDyHOJIs$?`4{ET3XOqCx zNxd^Up`4ilHfiYjob3kdeR4mj6|zsfQ9DmJ83(%{K9lXnjJr}qh(CRTP0%onNP}(& zL0o9fX&Bcf7rZA>wh^8@EHb{KlE@w^oOmyZ=?dgsmm$BGZJfjKHdkry=-lTZM?stB zQZ26gwm>5!MRk%Ribwv@T|b2S{r-;`rE)YrV|^l4v5v=mn#gBrgYE_R_>p#}eus|5 zyhh^Cz-x`ym5p|@^^O*;<|=5>ZNH&EXQ;fHzuFlp&b*1dJpOdCJh_ODTq$!pBq?3G zq%QwMS#znR`8EhYS!p6iRqj4$lR2e0QQovw<4?;&{3$z(Xm}JQuOL}>EU)^xj!+HrS34q~A$6r%9jUxjAO(;KsoRPzToDXwzXQ!^Sx@B6hs(I^iy-PWob zpv1XveZ&|tfUT+ALzGLS&zz0Vr=L~Xl5eVP8TR1$jQJjF-37XmO*6u{t7BRH9=G}` zj3ebI?4ru)_JFI>QhA&Fm@cIGLHUf?2VD=?AgEO(-6oG-k~3=z;v8K|4Xq{ne8u zFL%MuAibMjxx9k1=hre%5We%AJQQN45$t8>bhm_yM_Elo7wxF4KNRYMmxRgL3dOYa zR=or_d4syObO>MPmGPVd@PgPpWS3inUOFEU=?WAmd^4DQgy313Ns!4&zY+@^VUh^& zg(#E^na5U%b4k`_@l}ECCm^+uRr-^;$m3S;>Gshq7;o~bn+^~yD7-l~?K_GLPPACbE{o#ERCeH%rVFiofspZ%2;mP3G&uxnhOU&avZ=ccV`!~*It(VIy~kF+M;72I`= z2F;k3p%~sQ!nP5d2h1p0)Mxj--&M)V&+s%6%HW}chP45ALlwzVo>uCiatj0@SvWHx zO@U-eYLHRY(N7nOl*9y~Zu8$fDW@S|rf zh%SX@tQUnhtEo)<3~%;mxxlLYIC#uwx4Pyptf^s`s8~f(~fb9en+bl%Xy0z9>=)wP~yN#6L~E5iCtC z0Kw&CvXG$Ca#2`HBn4$3xz7F`UqN#I5(<{PoG?99x&YCUrbrq;w6;3Z zwv~VrC))5g&@x5^a-&OsIlQ)^g=^5ZO)wDi*%a#Ba zV#sg+ed3m0%W!?e2Hfx2o!T=e4%W%u5pFUJh@Wx{VVvcY5BqcLnnBcLXwBGt&e%;h zKNgO~lZT^L^h7i(N&#?Z^?y1~*v<7807h9&mFQ_nt9BLLz!S4h9Ayl@<8HaA z_wVSh_-bn=gztQJ!1|0S-(6u~B7>3F0K3TGH@i^zHHULTjP7Ww>APob_SU*1Rt$}7 zQ{Nab`K1+!{V9f5gOagzyL^$I1n<4~lDVF+yoUG7c8i|b?Xc;Qqb(%b!o&ZfK`WX| zF@S47Q1V!^I=s7s#zX2}>Hxc3Kzua+{AHG`LqdQupEkI#1;iw{SfplLtx(fY6G0Ot zUWYUi-I$^Ta^7+NejcX&bJMTOyBBbl9W#Dv^>Wj?%Q`Ro{BoAU3ZJifq`@tVM`R@K zVg%Z>q2M+n@S?ZnwsmvUJMXO1q2ulj|FQbk`gY8~zGMXr)Hbb56Y0mmkLf34TffT4 zsZB{063Z!=@eLZ6lBujod-G&)e)T4itdeS3c;%(C5`EcC$;)sNdw$!a5XOH$&yWt?}y3CD-_seF6ke!BQUFkAnxmZr^9H z$1Rd+MLp@bgf696d9_no&ck=0hZy4LcYPh?Q+gXTCcVg?el@cfJy7Kq=~2wVb?I}WN}WiZE#Jt&*q=+QcYdiTFILioKAd)wrAoNGp+z%@Smu+%OWe43K zi4RJSPY=)!kxQF5jBIaavTZ{{k5%KifE`;P zv=N#09&yBk!FRN6w5k{O8B??^!nn><$cr>3eYL1rqE)JrP0yRD8`7O(){xDa)`e7Y zIZ<@ekiZce^5BDk?%lpEOMdlor&B8FjE$I88Wr>R^LFG+i74TLZe{$oi;87*iB-_Y zh&2?kk^<{yw09RgZD+j+){#YqUX3#+<6s+V22KfCOM&@H$S91AjAM3B2+F(F;uj8J zqFO(xJlE4g6qf1|oYLzGmQc^&wAksZDX8J+@$KTkHQDwfbVQ!?WvM^sD3YK_OVD9Y zg6^dv9)|=x;i0@XH4jor(}@n8$|6cNu4SJxvhw)54i1nM4^55NkjW#48k#{)e}pT{ z8a4Al115A*C(tup!ckG$9GD!{tVA0M_G+oX0xHJt6u3zAmGRM=(ewvzK;_ncyV`J; zS%+k%^Ws@aTIk3|p$0_;J^QKqg#!8HkRgr)qN8~nQ)UQLdGMU|HbeA++23Se;>S8@ zFF6*{iq%C`zke2m$ynezsM9;v{JNCW!1^GaMGY#nss&u43-Uasbfrka6%Njo6;Z_L zdW)9RmD6c%d^OJ@2N&s<0BwOI`nu)_eK>O{XJp2-#(Fl1!Dft7?RNXO`nD+i=Q<6E{@Ivx$R z(@`!4g^7ufEz|GlKZOQ6AQV0?&W!vp{0&%NlR%_b9{@{1Sib<$U7wr`IXD#_3-Q1J zdZ$j09)Otobzt|F^AvtWV#H?-E{;9;tP==OKe<+oo#NKN>huwnR1}94B#y4|%nwm% z9B8b0zM-)d{=<$I#p1^wyzsd{YmgbD{gVeKxu_W(DcS|oOxfldBKWm=W16hr{o7yU zZH4$RrdLq)K#LeK9CrB0;ayw&zx9ec%&uZ?)9el{h1_Yj;|$77lxzO@?DJLz8_Zqo zOUz5wx*mMdsv=s{7Bg+g4ADxih`zJOe-p{`29$;B5)tZ8mD%Q$%V|;`Srg|F8;|-K zN%OT@SSsX)lirIksG)ifwA>a~vpS~>3CAF@&(PA5SnfF3^}AI&2| z57Z(RUhWldUNe%=3JA6;hg(^pEr{tDH_t&Aff>)i-y~f6d|qO_F5NerFePK=DU5&8 zs-;|83u7J}P8_dku7U0TVcU6&cH5hmZwb*54%PZoIKojrgz{G`VQE>&hBiU%;_a7w zi>=-0_>A#N8rq$(t+hb^DiDOe7gHKj+=irOTf z?h87JC5jNG&6%kbQ?+ok;a@u;+;VEuvgL{NE4V@ca2ktP`J0@FS8V3hjvTmfY3ui& ze`U#tildFE^~0uTq^M(0Pbiixb`n%3hcHP>XxX$>NY-&N!G462HPAX*9Jf#6q{UCV znH179RnyIz(2j5BxKlq6H?u6v9FV4jEF!drUJ@n3Z=W4f9L=F`BeP+3V%r{W1;Bhj zi^A|>xCK;QSej3<$3o<8kv6J1Ydkgw{Y$gHaW!Ea{#H9IOQB^9Aa`3y-! ztOi35`2$Bn4(jRp%L^=ez&u4AAT z%pKqSrHzg&vv(Q{>o<3tZy}dQC>!9Pgw-iRN~0#qpBbIayMq>1oJXoTox=GoB*n0i4UqN(_+cVJr8Ok8*1$y* zht)tCDt|I4WT!;mQ!E0F{}YoWcja43JQwo>GU{s@{NN9H2$3ygqp?He z#K;&lB^WMTyh~GMj3yMO>u8&~q@MT{#0rN_V%967aWJ;E&Ss_L+wax?9&#JZPJkBEBRCM-00^ia98_|@!ompKE!nHT6i;h!A>FO=kzXtElelNTz;x`qyu|u;6r6XgaRIrfKM-(iygXucPbrvGHom#z5oTTJ zQb;dF7o*l;9s#2*rCk-!_!UIirA4AVj-wF5oj=8FlunOWi=bmOYvC5FF3>4}rr>}< zfJ*N{fT!aB$A&)Gs2S!to2>+IsbPf13QPxDih7?5Z$CuXjl8X?X%s1AQljKneV@tQ z1?ZT^@%91Q)zm+Ut80RegJM##rmSxq29)&yb1G%9;!2&uOa|w&sO+KQ8+8=!WTV$6 zqN;CjQgr_xh_Iagy~X1ZC>v=Z$J-QWK$SqkG{ppnVi0GRW=2BKAPc7;$5^k>m1$9r z59H)4`sxSjshplw6kvin9aZ7w99=~ABlqN&`F8dou0o^fcFY6q$KBDBX{goG1mFDj z3<N=b7+v;`qz9P`-W#ob=+_4cB$ix4q<}QyKWui4mV1|N0>^-n-C0k8 zXhP8>LrJBysu?SpZ*;Wkh8^pYw0oAm6UsIgZv$M09UaZ z7?nTf^k%{@1c(AX8|E_;{A>cXN7=ks(am7|)Sw2unlzz^xRFHH0ro+tNJ-891f*ZZ zb3fM_wW6uilW%m>S{(opa7=<{H~`R&m~@Z(vsbSsS9`o!V9;l*gm+-_E4(~HP?-FpK&LGH*>e59DG5}r~c06_m9t8=owdO zcpW52m8u3%@hf0DuSfYhki@sHOm2 zb!Y`WX@3Wy)ti_Qfej65FDGjfw!zr#jMadh2rY8(4g#rx8RA#PY16{!QY;CTzxkcn z1m8*DU*8En+cVsVRkXCfHl(#OJ*qRlw@>ff_27f15lfIcN3*M(5c1m zwhnwGSxQp=8LEAFqS64A@k{0xcB4q=wuRUj< z%mt}a$u4~Vf|&$CaHt*CB|d7nLku-?*qJ?lk;X5>>elP^EQ&}yKEHgdyqTTERl%gN z?-QnJ&6X%Fd8O`4v}FnE8e|we#x|o@#7BVUTxt4z=~Ix9gEeE26n0RwMbu5bY{Tvm z-kG}E3qzj7ug)$i3d67ys+^0vxTC-$)riSHn|VDNlb9jP{5vsq*A8VW2B5R}IS#(w zBh>mWqO5ULS{j=^$WB(}Kr!1GPTtwrk_Yv>`aAmBZ>qs7t5 z(frZy(e_Ycg9;A=s=LgG%11Y-^z%hcqq3}`=c*!Br)Q0IytHE6cuj?x>$(<4aK&A; zYs@-TXekjkV@<@fk&G+256Fd@p~7qjlVGmwG)K5%tFmnYV%eRp-Ly@~^BN6BclW8V z6}X+D+4S?ZX0JENu8RAVPCk#v5KF8#2eN`+Ch>+?dV`tNi9QH!)}mjNeeJs@*ZiMb<}V=d$`9_GP7`jG(#33HNy-R}TzB zO8OOS79!8#qGq5q8fe82Li;xuR0~+8DU{P)iGk1)mL#7vHyJO3_Qb5K&)=k1v;zwV zL4)j6Lnqi2LcZSVxWvMqo%gUwKs|umXJdsd@?dTtu@Y~(tc)yAdv#4 zR;M_CiWdm9R}9xy!ne{ipgplc%w?)ywWo6)+1^VVL|S-bo(4L!bFW`l!_;;11Q^vh zvLXr-N(Az+7kYss+qCKxk?LT5{qdsmq&@Qo4hT~ICsg*@uPd6E5SwAU&V3eFICQ2V zJc9O?xUCuQo8xLINo!@_mkR_lE{D`h$ZUj(fTw7auv;PA~?f zM!ViCb9MeZQ$YqL{ zhcamsUsg*25I!0y0_wnvfsX+%cI>d=fi?LQK1j+t{v_w}$l4d?l5zU_P`R|o0$LOj zUaX7D69*JEZQ6{bqXrErbiVdGQ2FF4`AB^lm4YFIrqqT3AI()$=!&-5@tcRTCCc${ zH2p-OfwyIXWswVUDqCYsK}sl?leBXwE~!k23#@olgEfh3Af~Mz0#aVbb_W+FcIW(O zC2Ob+;Bpk>BA#d?Q5_vm<~OvMbXu=OVvz*jjaX795eP!>HA}hf>9Z0jK!sb?DyJpq zuylzC`2q$FG1UtG1pQiW@nf+u9I7gjN;PqD%9w{E$OH{*g~E9irkAZY=VI?!&Ep*Y zb(1;kJIRvu63$}IlJ?{D6EznJ7t9_8s`DTZ?XK?a-kSoUUzJ!Zhs|EqqQ3nGH?6D6 zpn_DyR2FrYxvgVSQE()qs^+mqcEe?{Z3f>EN;n*jb3eQvxUdL6J-Rk#!C1^!7-NfCzML2dZByXO z`Wk#e#k8=NFl)+$jibA@O0G#n3&)*l=j@=PPC?+w7HI*(6hEp%#F9y)hV{NLjI$<< zT666W!FZdr3ATQ*z9dr@?{#yqAN(}(v75Wes;Q}N%?kXo*Z?LANlh#|0A__oEy1_N zLDtJ!=!l5b-6f%BXKm{&D-|4+pI#mf?lg5{(7`&jtcv#XWTmh=RsFN^S0c&Gy2x*0 z?X-Vh^-yF<+JQT`TRDdf-F&()qoN~I*|ylh9-&jWjYYhhG~K~bWba;)dpr`Gd!$iG z9QuHN;6I~Uqd23Sz?9C&E`(CT0egGZUs8KBe#@5`QuIbpvzcbVE0-6Um4Ifz);b|5 zI84(>-3sL=I8Hfb7f8tG_B^Rg#^{=$GDN+H=-#EGO6E-`S&{G4;o}XK!X;lWLnN;X z>$@7=ocf|oUB;EUt;OGhu7flL>F-&gqvYemu_u$ftqlXXa0_{l)r4gz1M`5qUcJ`b zC@!a$n4N9!3Q;A0l1bF7^!Fp29T|6`A{6z2kP0*JBs$v_-zp#4nkVn;2FJ&}-ezw^ zPr`q5O(q3a$ntmY?qzIMGrm~I5lpfX8qLdw4NX@U>^c1gjb22p>aie0Mpj;@7Hdq| zOKnFZIX_vrj=vf1q-5C-RHzJ0={oUtvrb*P(h!(zRBChwL;^>aYA6tS?Gx#W;yG7*1k_PHO)cl zBZ~QwHXI-A2SK*`ux5=#Wj(+~r>MxJvH}SHH0~AwI@wgRd~`y%VtiW6`?J=&!vw*H zGRpz5`c*ZhUr`87FVpTQ@m=E?>rS#C99n9ZmcD|8??qoR)x0jH8=HL%CQ;fq%HXKR z!>z`GD$LS`R`((=9UooH`m-=UsrA;I(lLCjPsdXl`Zi0-+DR&1GG$Gsd<@lB|4sw= zijY8E@m$6RCoa^GQvw=$GJh~LV}<=M(tNxasuAynwoX^rrz&k~kJ7AI8^&&&CfM`u zgO{4hO&DzyS4(c+XE(6WW{xufGNtky-Wo&QDVt2ef&PBDCyx z+79)E*tc=Z>O`wtFaF z5!dp6+pU>xlJ%lK|M&>`Xy0V2nI5vlOvTg6$uKIY% zc_xI?pUr2Z0k)YBhZb)oaNM^Pz~2|ma63|;@9WirV{EEnHD)OhbQnEd`?^0Ge!bfZ zBInS5$0malGQ1?9wWZO&2MyKSCY*>L#g7?g7om*@qI$Y`l#bvsz4u3sQVj@UJqMzN zwAIqIUtn_`^OLPrJjodv7zBRxdD(WLW(9M150a|+Q67#UxG3I<^^6ZA> z3-rF8!aQGwh0d%NUEr=iulFq(zCbfUa8A6I>})5n3o3c)95Ks~lGM0eqKf9I@9?}o z`gIFNqG~seumpNq!pSqKx8l@w1%K5O?|(c@ebtkhC^m2161LwU5{@CcVt+ccB(Xq5 zb4Lv5H@$92H1J8vR|qkz#vTcJ6|lQ~@fKh$QWivhiB%63+)f+xw26iCpx#dj>=dL? zZ^BPyFMW&13u5wFb>u2}IRi@X*nfWOHhDw1X$~!&PIj%kYHMHBJ2koK9tuZajn>)j z4-y1Y!`L^#BXy3}A#FGqaghEMf89{cO+>|yaX4 z69P7!IWsskHO!z(1TYUT(URAPY8Hn$ZZ_zjhun}iD`MmYR7mEr(ruX*->n} zTS|C{kWR1O87V2>Sd=I9?*P~lYGC*X1G2W!%Z35Bmc99x;J z;bT>wXlKjK5|=B^vpzWAm!o9Ph7F6R#p=Fo)f~XFyBycehrw^pFqKc+T$CEH>Bzj5 zL4mnig*L@E_W>LhPZ%)hka1mVKJ{ux3%&C1@FB$c;c_{c>NGuMSt8_ee~6DisKRid z(@}|ma{8v`wEzS%cB;zlN*YnLe>%y}k8>fZ-DKpJH)${nT;_NUdPZz40>Og@AG#3P#w4~uW5GE zxkf#(F4DZ{)@pCK-kblpz@^*LbY1)nk`%&pQUuIXres-%5BNM{q3zp8&ZUw5)@I@7 zSH%_T2wzNRFX*S#Qoz^aFKIA)vB;UPH=#-E|IID{On{K}R<<*J?Y`Z} z+KR7#ONrL=dZiapl*DuUGVQ>9U7N|JbNZ``?%zEdx)Pe?$&Cgg;&;`m%2M18$Jcu~ zv}2gv4~DTtR4%#{k{Gf?SGJ>+^IXbc3yaO;kwATOQn2kR@BJB^>RJN^e&mc8 zsZgqb?2>Q=@Lc3A+lf2iV3HgajkS31*YAVhB|$OGYBZt1*-VocYWPxYw(DNkVAN@H zSb^DcwQWT(LH8@;i(}Xyo{6ze#lx9o`Oe)!OU#L|M5TK_4;iB*yph@a~Jp@}L zvZP7ledlg$6Eqj5J}u)KtdH$jrfFAg^V~FlLEE&*n5$0)vsN~qtyZQK1Pz(#+JIfB z{6I1R;=65>HD*4A_d!iCW&$O}A`JpMuBFl&KBs-1jK)ZSn;^E1I9`sKo?RpKsmu){qzFvnL+isnIU)EI2X?sk;cK?G3RkoH_wy`Fn(E#*l zUAHL^4b6!94En%{cWT$&=uWmC=E}&mwq>&5Fr~_}v&?1;PLAL7O%Olbb-p8I$S*>o2bJQrW&ZNv1OcH!R@-~V8w$Cji?uWReL9Qvfn+@$y^r zxktR(;nBRVfS$enI+C7EiQ(_K_V3o3;kNseB-3Lzt8Ya^(rn-9_r4D)v(rBITpGoJ zJ7DakuCHvaURl^pF|Wa1)5y}Cwu8O=vSzo+Ix?L2Kqaw5=|%O-zXw(q5rk%#-u4@S zn?aOufp>xjS3&r+M;{;9#7kA?U1*6X0Ei79D+QCh48Q^a_QhFCfDInlPoRsgyeyw4 zr@e(+QC%GoL}~b>!XrJ3y!1Qb&>oeb*3-)-PU~rXmitJFO=(d^j=LQyD#C)4l#GBB zLrO_;aNH)mXGp?27h=PddGkDx*ccfTj zWpN)_#JW3F?z55>e@zvQ5+B_cw^`#eI6Vu*8|_~A?}t`(F3wu9#wmFf((%$>)v(y0 zIH@bh@dZ0|XEDSSqO3#BKq`M~RmRnPxztXhA=Eu}>!Y$*LQ?0XD&3YLVY96bW9}R| z7P@kFg*dLjLW7~TW;L^e zw)+Kb?ek<9maXxce79lG1N3R;-v7>MN;+{*8}C>*1#5vTaRq`@4Au8LO!jMRUTcYq z#^CB|_iHP+Z{^T!d zLpwr;bb?VL54pjbaC&W>+vsX!JyV>NT6#w;MtI>^7&jH`<6e1|ob0z<(Kwz=TSBm` zP7#mN*}0LtfVu{A%}~Ib?g>R7txIE@vIboS0dg)D#F7jKu7Bmp_2N-xD$;-~tDmQ~ zKbvW5J2NwvXcPN|Em*f!bv0EuK; zQP-VC5_X+J{oXA`WWWwum6UeT!Xri<=cWmZPZglTA**PNC?K1#Eji};n_JORzGjme z&H?|rJ1!?Yhh#K>hNNu?{a$*#nU2q88>ojF&;Q9OoI6}VLl*sBeC4rwC6Y8xpm!0C z)d4!7v;R3w|I3{349H|Yz5K(|NA;5b##xy0O{CDP%Jaoa4r5Ei{WTG36567WmrHuT zu^?cb(KoV-2cX*yl)GS3a-r=M%~7BpST&z_@p*!cV(0?)`IX%Fw$(R0*Ty!fE@j=^ z)7DvCZtKGZqPnQ0GHF@RccU;t3|YU0QxLJffi_g5$>*MGNBIC_|CB#?NJru2yOHic zuXCnvQVxL44UXLj%HE0q7Ydpgje+1PIfi+@(16SnA2rrSqJzEvhtG z{E-?)Dn+z@M@ine%Vhp zNrG?s9M8(u`tuIy4|fCZg z(7Q&~){-NMUjQK7B~~6$B2zL|I#HHb`s4GG3ne6Gatsi#&^9(*C6qI>DID*bd!&8{ za21==Z8zGV;dU~2=BhvXyK>I3s}1S@F&%WddS$hxk(VQ zYgU>2`DVmO$#-bm0iA*7i0#Yu7tPx~nQkg)Ox4I}5c|o`i0{wTSxArbF|&F{a2nTH zUQj8hYIqe3r=uc+*98?{09UGvAzd)5yfs7dU6pYeEtOy3ri^O&;BOh{-D3TR*RQiF7E;jnFmgU^J zh`&=ZPsGnHubkX$Sud)j8Yt~gPn(`_->|=tUw*H4M#rc0QuXBiOPdL2P|rN{cLI#R z16rvB^pcT`ocNSqBoJwp4%62SA0@2mMrJd+x>nN!6L)*0_Y!VWOL~{n&#Lv0qm#w` z+m6qh^Ljx%N5neZ&wU>cne6r3uz0iQ3=GyhnL8|IX>Z0?O`4!MzPUR1UY^W_>gws4Dkv$8kt z*2SB_Qg*(rvRA=*UH%tJjEZ^>+VBpwx0YLHVv>`m;yM`3`uyqpo#8{}yyn8fQngxT7> zIt^7-hVD|frbcq)q(<)A4^n%wq^eVi$Z7sM&kZjdOW2w(kK@c37#_EH_hf~q7?jSZ zc(L%^$jt8*_Ux>z=p~2U{^!fKlVFRoKy4;ELDN|1n-!^gwtCk3xY^OwQCF46O7WvG zD6yC7esbKBZ=4$t2|<2w9I5zTz`riv$i1+zkRFk8CByAKV@je4VFTW_{**AtUa5M% zNkgwUz#TD-*4^3U$(^O(S&2|5Gg4bG$Do%%8gm(ks8sZ! zqhI{+(&HJ-U9Nkj!vl8n9Vyt!M5%zo%6QX@g06K|f`0eQmaycF-G&pXCi}6?>oG%S z@%s~enn;g`b>-T10-O^uH*3o}>T{*H7o~{izXr~<6UO%Eu(O3r0usUya$ zWmmzZ$Q4zvROQF1(x56KY870(wmP$zRtwU*?}C+bK^3I8E5f>SnR@U;OE}VfC_V;W zBkw#{EENNH3Z8PrhIzmuJoei4$SLh;O=arJakQm9^4DsM`>>K1Gp(6g!f{PQL^Nw0 zhM_BohT&vabS(Ds%A`>+Q0#rGW>ikitH9*f){wiPfY>&G+?*QPfQL>^lNp+`(2x;i z+neaANPj=QsFcIQ!ihQR&6$*q7^i&6r$?N+Pl|m*GG|561Wv5>uySK?p*hmMnJ!9< zWZIe%&c~wY<1O?Z;7|I@i4V#r3_{54P~-ia2;c-y1axd|p5mPTG5$Hj$mhKs9K#UP zhwhorQ*uz3i1s6>8E2r+Y!fSLC08KELfR|o;JW6pj zyA-i7ICTkrA?|5;VX7$B>Aq-B=*ZTafcmF=^WceneY`(heE)uon6q{ax#KdGd_yMC zIdj%rbuWM0LD$KWK>P2mfFvVMk?XC34UG9N#6^0W z`^-iH_cd{4bG(6rrL!koYk;%PV1W2%hSO#{vS}xKDn3uD(o$Yu-2r{Dp)VB9K-OsM zE4MN~HVrM2y&6qd9{#AkZgI?jE7C5{do;=Ri$6qdEmW==f94gV1Ebjha8~NJ zO3|ewK(qF111RkEVumY=9G2mi(4jS?N2#sV&bua#U?%qQ-K&XJ|1?3xiOGSZ7>1;w z`P(a1I=1fv_Uu&74bzyQ;2Ayn|BGGVH$hrgh)|x*lrv;eAEiy}irtdBQ7u$h5~yj9 zJGv;rdStX*&XmqmKwU>(2H02X6f!IuSUZG$;jR}Hb^PZrAl*ZC(4d`^--AnsZvYyKLK3g=6@cc==Mj{+anl!m>GV{nv6B@b`*- zn|zr&8t>$JLye#86vV-5jyM%0)q2RDh;8Lpc2N&|3%o}LXr2>=1f05=d>3fOMp!U} z&Qd>o^jIGmJ3THQK)A^I&oLQ$%o{^C_Jfgi_JdJC15{EnvWnI`%HG{2Y;IhS+D--c z*vAWOh-~{WY}3lnSEMzcPf8-c(7nuwWOQz>1$@*nB2qQ8yA~uQ2CJ;cvGqwk5kR?I6h}=Xx@pINrzQNmJ0V@GPOR{ zpr{1)&@^5B2X+iQSt?PqpbU%w^(5?wDvm7Y_mcfO!_n-eakhaBeWgfVT?aC)Cxl`- zc^w)T7E08!CGyJZ3iQ zSbZq)i{gao+EhZvx%2X~>7eidF1lgbp=;oR+;kl0Xqs!wHTlw&`@&894e=-X;N|sY zx`zP`$JbGVqyjsE#4?#EjhdH0B~pk!92|k6KbvfJdlU=7g}9!nA0A7D6md-u23@co z@Bqo+OvHk65|L>bMdMjk88#5wf1(fWZs2c*cCUn90Z-J_lg{vJunJrAa^)8_r|jpT({Lip?c+>u_7*Xq<`kS{&uT#{C zlM}tJm|_^7J9w8Ne+bi%^!7!#K%sRk`ik!urQ@|Vo?2FU1?fi5P%)A>Su!RT=7|90 zT+r)W&|naaBZR3K`Ra))QCFF9a5qk#H)cn;h=b?2V0!wJ+&dbb#RV}#^i@hBVq`jU z$nY)bWlZvLyyeWg>+dxe&~8q%d#4qDSA*k)F>8-1WFib66BT%fB(qIaKVw1ru9DnT z{SZdM@FX$ON+|=<@b;3gQT|Vu!aRnrXeLbu+_Q|AGm|=vPtIuzN$Q<+_7De8W6T~I zpC0b`RS`sNOGaKwGeb*g2kB>b>LjN#Dvq z%}O`AXWdjKKkcJlsBlxNWrKsYz9hL7#PGR=J-rH6vmGkn%02qZ@H%@ml0O44dL)BA zHroil-1@#2H#*vWcDkE2HzM4~1nS_%{?nZrH*IrM6Dw5>4eNhdlLOkeJRo*W^V3p?bkpouY}+CW1o>NXxUpVFj!=dR$;#UzNlyZT@CU7gYe zcPHcW*7L6dH5weQF?shHlNxX$jT+B2buhw=GrYOEj{ zNBr(0AVN){Q1dx{<_Nrfwa?sj4S_W^=5!3+`oI*_$cy3~l%~w?rSlcXD(6H0Axps8 zbL?qUD(EO0>xVBbDpDEEfSL91u!ZH_CV)ROSZ!UXNMxl{@EQgtb{6g}Ekgp#XBzpO z0W)Jh8-tH`0jSxP5_o7)0D&2O5Qrz`V5ngpQ6y9^nOj+%>QBEN7^{-{%@}(fSGl0H zuGeV7ZRm!J9{A%P)AP~A2B+Ng_kC?}d`Q6Rs<;AQ@I+hC($Bq(5xMOZI z5eOWGFoF>c>tR{)9&%iVbxX;@VyANU_RLyZ*bpJ({REoURq(KPdv>FcTZx+;BWv*0 zL1>vML{Yk9=3(InPxtmQU>>xBN||Dvm83d4Iwk_&Nj@fnzQexRlPrc*VaDyk6y&0b zrimv>ltmrYm*h#y^CVGOnlv{7sT0(&hvXdfQG{(dvJ{eAzO`X*<|sLn1;(t+8iwY} z%#tJYcE_~q74<8XUnBTT?9LGzHw^1IHwz$~ouD=OkT;%yF+nxypSurIg!-YhcFYO-F@DPj55Em<_SR3^h*mK z@qNTja;Y0;QCT*uP#s70`=Lj`MUZTn(<4EL193!#|4Ewwa`1PcJc8m}D-BMyt7ykp zHnibni378?Y8!G$T22^A?lr7=zGax$6obSCmx<{YMwtaeuiz(_!o@>;vcdh+8V}9? zq+&DO=@Gxtq#bd|Yy%O-sT^73;#kv_-X369zzP;0EF|TNFSe8{Y<7WmY294Y0A0n%OCPNtqKYb?SnJX8gC(jhZjR?7GwdCXV=SyjtEg;2SaJpSV2f97_tIo-sc4Bm2noy>B{5i5Gohv0vMPO- zp*hi#Lz>0lxkh=4KwEsnhSjzDo~qEsEl?@V()IsQKrXjRTVH4t8nb}GZ?Zsp+WihL zf?V#~z^*hf2fpsPbEJ)CI#oMrf>DHPrWH(7NiovMLbNs}@RB?&$@{@EcnPYl$*+yq zl66;L29$#bBKwO?ro2pP=;B~Z_xf0Uh!5a{$j?t3nP134^)-P#5t|Eo9$z6#;XGjr z50Nzl6xPlt&ZABkzzw?3JHj1xe%tWMawa2@RvqukVc*A>^7aNQuv-ZWPN@WmW=x*Z z1*x9j;UuS-)Mgoi3!G~-63$5_r!kAUb)8fY9aK_?*G!r`p4+Nsl*&)q zsS>Q-m~DWd78fAs1D7uwtUMZGo1)L+fy_rdfT=XtNjso%xS$oQk8`kMGCxd1@M>9{_Dw$d;L;4_X$5iD4pNw70@oIoc;r7%)dYKxxG2 zVXPKa&6Ye~3%V9bH(raHM%@#ykHf0Tcy>C6ec?M^3%F#T)+*xCb;pXqnn!5^ocM=I zjXcBe12HHGK(jT3yfT09gS@hMPgYS)a4&_tGHFB1zlb$nuPlmK&4LI*<#1Qbnz&B^ zOT2bb1d+Na?vLdERwAgSDC+W5P1KNEjY6==zj{L^mcvjEzmiBH4^C8ndiNi|94a zhqTMVy#jeacUQ>s1*PN>V+Px53?s^6aTfuQ+Mor($w31OfD-ti{Dm@iTlq1Rn6n!D zCKKfowdiOG9N%~na%AV{m>*?cZk>*$G@&?;=9X zfwaMnFX9%J71gA(<@taGLeFE1I%@b7(-gXl-=GC@DpVIRXW@ch6|lTAThoqqvP*sJ z({oQ9O1`_$6*VqOc9i~+JQAx7r*@$Xu`PNp`XMM1I}0{@$LN+gE@G3}@P)FT(o&xz zdl-T?L9`>GU=*Q{nZKD?7Nu0BbwzR)ZspJKS*#E-`X04Av%-BZ#GJYvLDYDe(2SN# zE$l(*M`FH`vi2yY8*AQEw~kF0zDY|I|B6@2ei>JA#7goz;BeSoX!IfFDU*%wZkM)+ zO5;ryzqxlwEG1dOmp1?0^rlF6ke=kWoM1LPcfF zcowOMD?U+gFM?`X+Wm(HAUv*{Q!@iSMR7t*h7e-dm@^(VU3LJ}XuTPj+MFk&-u>wK zFLS{k8rPUjR}b7;kI+w?sRZG`7vd}mBEV{)JK~~oaA#Aq_M|#5uwg-|&T)AZ*ekoZ>7J z&OuT2yh(e}`WiFkR+&HRox>C*Vy$66@mh>G`3=P4tXE4LqKMwwJP>;f`p&)rYRT9# z#ROtzlEotNWz~;=9n{b{|FB~tm= z$ty8e7jtk?R7gaS%B;h-r4$@D;tk9Ege26m(Q`Uz;xI|XmsMDnAxS1cJru^~jC9+b zlnoYE^;FLrIBJf};4P1yCR8S5KLVG^s<#K_R4pQ6FFytep~?n}{pOqqlTJ}UgM+e# zD7S<^4_EClu}5N*96)2%WWu8+aL5ui63$VNwrK6a1d{ket7ZbH+q71)(Q&CfW7duI zh67!HVd7ztZOjsh=SiSpABlqjyDSwc_cv`hjB}qa|#*+d&<1-MEjj`!X_n&~=6@a%4&BZXo)39X@RZ88M z70Gjzlabd(0bC(A+CfL!+rjcy3kt%VY%VGD4BhA%I3=iLEdib5Hwd!=OACm?vi-XK zvL`HQ0Z>8~fCnuJfv|fD-Z2EsVGbHlc&=nerdi=Ghe6s`sw?m+J<} zr;5oqpf_2mSMW(vG6-Xy$woju{a9LHh=(cQv~;}v!D!OZ|H%+Hq4!NJBZPxs6n1#b zGg(VfE|a9R-;9sV6Pgk|I>A6~g-Hp-%Bp(M@}IW)bjwjBG7n=)1O=xLkDseKH>qsY zAp=!dS{N|cVVz?J26H?~KS_&d`*QLyvSH%j;niS{GkeK8oTd{eHma(ni( z`AG+QcYsg8XWk(*%S+^HNriVC_0>ZX5Rnc8M$wy=Lt#R!I{4UH07z_P1I;yr4aO6K zuaJTIZ7KHhtROEnTUIhDIpXh!uBk7h%OVU8poEyxa?*CFM#yJ4(T2~ zE+tSm=fKGcHz)6wdOntmq)!w{p0W1^=fpkU*^?bTVFX>Gf&BshLGsdVYZuY}a|K7!cUjR~R<_wNaL6+EXyaK($JKE^A*=Idyl;oZ$uY?I9Uxtil??}W9Q!&#@M zS7XWh(NK<{>bxPwD*5|tAsx;Yf%t~1Fz1|VJZYm_9}N9N`z&;LY3%9 z!blX|YfcLI`N+#k-XC+yeyzbQmVcp+?nf3fbNZ*D zyv|!bmRz6so8VH6YHnjq}-4b>hiF0wG@h` z^Vo;B{?^747T$@&`A~Wexdn6ieMN0QL^Q39DvO^#a0Nx#k@q&|;?|#i& z)uFIORSG4uqk9&&zWrKb6{m3;lt#7G`naL~a<#~N!PnjEy+l@K26X1b0CiwR z$oh}=nmu~#&}^O04%v^S8deG4+YhZ7g;_(#^@%`Skg6v&5I@ioiB zjkDCx*EpQ1SWXBW7*9`*mT}0TH!i9q-KsfI!6jJCK0^?YAb1B8nr@#MmPR-Q(8&Q+ z67o-!`~W(@tfp#4=iZppLQ*; z00F@rELsG1ydAT`*RHl#5sV$Tu-`pMk%oF`T0TLGR3v@~{T}Y7Ou} z{ZDCvvEvo@yI6&4XvR{vLBUtqE4tv-{mN27{Ixg+A~VLe0l_O>teG1%$*;S`OKR84 zE4$=B@0BsmJTFFmzqe(Bfs~i9BZK41n+5ste@XTK%{>%$a}rf_`VULqQ2#$q|0m<||AcX7U}a?ef2c#TutC)e+YMIu zpX(lfyq3H;cP}Jx=vM^WE#NIVU|?2g!Sq();AL^emfr6VoUsJqafNx8I%L5(G2ENz zm;IY<*?;z*SwSgJ{@Ps`fpvfgAuk(aH#>D(fvPH^0`Kfd_*syPz5O@eQ%3J!lGEE> zy;uF_o7cVcyX${&YdlTeGvoRt(%-G`zxlIr5#J#e=SxydS|jE=_hcy}RdqCye`fwz zlK7jIp`-Wp!jP%6j|85OtJ{4z$HzdRWdQ%2DSS?0l#Zh}yKl`a=WR zEnaq-r?;Iy8^9j1^|P(@n<0|et5HnDM|tCQDF1~fzVX@fKdfQM*hvLFfw>u)3wa?kR_HXYn-=f1g5iE1X z-S;)aRClC0n?nmaY44V+aoJvHqKeapV3ROcL z`b}93djn32atcYy1n>u3BrReBhL#hqaR-6ur5;Q;RYsS~Jp8sfQZ`xvzU{%(`%)F2 z?**o$4Abz02VJ4m*2Q0hG=-N2)lLhH@@`=_c3luCz3xlBGZK+;iZmgGcqAbF(RxF1 zKlyMAkkh7rFO=GYnE&X|dCO1nmKzWP{G>btjxzDSa;{~|DgWAI1WtGmqZ+&*W8eS^7ugMg0jl9l*eQJ5x!8G_FSs;>Mb>k@oF?tBu08S%q4|IkjeOyT}~9B+1Y@S7whbijn%mcw22RKe~QazSDp zOTI8p)=xsbo;1OD^XRIE>jifQHL3VgHO(8P1C^Q`1o{9NJ%s(-A5c%Jrcd5Rh4wnl zEZBE=I=!0JDwME|m`Mo7EluVcs=Ht`6>Ew*1GV`C8F z>fNUwv=5lRaZ&Xh|0GNQ`t9(fQkdW6YN01rBJq}7zVxmGSW{U$Dpaz9lZh4>wX{Lf z%-sa*;N_5Q)L=tZY+#E)pvJVWFCGwH#?O&p9uULaBG(ZSND_kxsK5c=b9du3Is;m~ zN&IXydSYshmjKo<1g%@~%FBf6?^wf}Ri{p`x;-kFg9NC|84prd3*e@YZDFeT`4fr| zlAza`?+N*T#_nlBJD8ukL7dVJwY3 z<*fb<)%7k4=2TvAV*h9EfmvX1+fk*M3*9{f$iUhV#2~F_?;vAsXli5%GNcsdWM*Vy z2iF*8VrFIn004B1Y!r-)6jXmL>PyVT%E%z2=U`{*q6r=-!43cA?|1LD8RSht1|SJ5 zBWrGM1_5C~5gj3GOB-uPD??>h8xVM%u(g2_$iczX%Gmx_-D0+1N3ZxV9)`S~snf54 zS{$Tj2(se^|1c%d}x52;Ujs_@6vr*iZY} zvQbs=sJ;=vVBnx4>h6tIB%9_t-IoCbrDWU%f*f?q^W3N5`rhV6lmz`i);rR#NirT25KMV-Jb5@UN|@w6HAF|iE_34#WZX7|rU$_hS@zt&s+qeuY&dPZh&m;L)h z$^!Vei}cq->)$5QU&Y-2nMi98zRM$t+_?7;VqT`qPx6WdkeaR3hWOPt)MEr8U_O3+ z>-d%8hUirutbz4Dt(aD2_@V}CC*pVZrSZY_snI33eH=o$MXHJ~2G00za-27!cZO+A zLTZKuNpb57)fc2kygBNN8vMy3o-Lp2ZwF-h^Bz~$6#}Yg<9Wd%bX*}r|8o%n|B(ne zz$L=}odN^^|Lp?&OL6pnO*Q;q@5x`a-~X`y0a8Q1?#Y&ukHZQAo0T=D+|ZbFp6riuBWnDZ6yn_eos3iJ>7Yi#=lxzWW%6_fgJ z7ncx;?#X~^~Ogp1$w&SVfyJjwH?;w>-#1bPeOo_q@F1u*^YJuRG_tA|Q2J7;g z9yM@XNv?t{2xth$Q);O{7v?X$^0)iZ)WKdJWcQm^v-+*(JA;t5g|(fMjh+DrT;koy z)BvO?CirK%Rvct%Y~nx+VEljdDH9uzK}kl>-u$-`?ti@0B`o!fL4Pq()a3NdKn4yB zA59G%Oo*8PU>n8W!49NniHzWqeyoY8^!6jh&#Ea^u9>z%7AJsY%0?NXGMu@TCTD=H z8J)&qo<ME2CzPp#RA zyUgazsW}t7h2GVC5fzynXnplSn4_jkwpA+&Si>o;GMPB5*EswX>RP(1tKrYQ31_E$ z$d`osV)ml`_4#o(sp7uje1Ob-*uDolBcaY7K9G~Et}xFXu$8I37yLng4t_KV=M(9U zm?g;Y1}13Im!Q#0wlY6{-qbV0xz*eqM9u;IF>5WR5rv*C?vyD>A`dYtQZiO}xPQ1^ zRwruWLh~lR2m6e{1HOh^Umzc6h&O^L2Pc$~1+2*?V80Q4f$yCUm?a_%8WXi(-KMA<)5Gna_Mr1Huy?v>!rNw` zHr8UGhZ^42|5p9;;IH$)sGN8Jm*j#K_Wfvj zjabjVd_@vtD_F@hVr^_j9Vh+0kNX6V@Ziz=)x3A&+ufi2?+o`d%_tCivuNesE19f1 zX?I`w z?-V6!PnXyH6u5X6Mr^Nj3||wlC&v|Yq_9pxzAHY!EJSO&7G`H@N0Nf>O*FBvH5kG+ z;{aHrX!p7@UR#tsivZ9fTEeES1h_Y-iJ90)Kb|NC9RfcaU82s5P6%)RFZ95~vU1qbqR-@m$tzc)E zH?!*Jm}T!)WK37rwC4seWrT0tP|jZ~cjKWQSg26W#47rtkx6{#ReZS#>G71A*Za&G z<34IUC&O)40e;kJIjD%^qnam5!*4ouFGtJ8Bp{C-kIVLIjDiB}TA!fyzSeB|p2K6G zYhyBIMMbd45{(daO3GbN$y8DJy_M$x+_{JjG=ASM}z|d?#`TF%nGYX66XekLA#>!(hHGdjtXU7#mE6d^!|9oUeLGjFGBBGoe4E6vm0FfK7JLFTAo|rt}0kh!91Wd{FK26e1#S6oJ)jB|x|5 zvcXc_46e821a4iXOHwG%koC&Q z5}B%&VX=``sqZ@VnmE z34Z?5tgi^%3yh6E&HMA`9nT|VC0X%&9?RM=V11>&#-?DM z>q;pAR=6N4@MOWp#sXyd%YFmP<5vsH)?yOEGI}-)f7^*c_#-hR!>{iX2H6|fnc6s5 z+x_OT`lFKxyz8%RetEZ;|6;BEc8DJ}88ra_7J3#|4iO~j zWg|Lfuv-aiRRURlxdy?0IlynH{hQ~Bj*SIK&&~t{FcH&%uU&c$4j>~3F?j01P7eUL zLCnO+3Z!RZWo7|@-HYIU0AKka=HI&MFV^g@b+USvp#Lc|2?sq3Qv(4jV+#utktzV1ft~rORpI6>e@a1oin81;*PGz%p!uy~lnAz6|b|t&7zHE8686Ve;@w%zGRh(!%eEuLR+)xq? z(^DuXp60OG!h|M_Oo6uY^}UB#8*WoiQ)00;h6XYb3zhlzdOpRh_n}q--PfRqET+OA z!}oN;+H-FQt`<^Eakn>lQ$oHxctt zRj7S&N4jSqE8R|w271KSeS6h?fj_aDo(v?Z>rBi{mJ@`!Z?{*p+R2YFpl=t$ut&1I zk51)6t-|J}X>(V$XYGIkQviG4`o}bp47(0xRf|8?fR0HjZFWfS z96HaA{hBV7w?zl=eV1)jES0dJJUlujbR@QB zUQ55_shLPqyXNq)vK_mt*Y3EQ#F#KVHW9p_% zIv=BeuPG=q(Rv)c&+~wxRhc+x;&{(ISxYFY9~v;|lAc;Kbm>3bm5D-(YAr-$@Y+&1 z4K#`ze=MC3P?bH52pC_mT5}eK1PyMhjVbPJLeXt}ZxnLMo!FpTq$bJ@>bAeE#u2Ma zkiEMA_^k=sZV)zSB~6L*#v=p|W|5Tk`)EONpx0tc&CfJj>W>m$^DMSep z@F}I}jgwzCeqRW6!ediJIO0S8tVI(jaFV51-<2Q8>>s<$sqr2j>X2%XUCMl0BVK_5 zMag^<+Pu}=5COzdIEB~8S-$IR$HAGa%{(5(On^wjLMdwWAiK^xbVk%*=N{yY^+2u6 zHww{$Em61qW^Ha%e0Ur6v$UsRg`Rci=;CE&9`M-SU799*vz}Uha%eP44}U$LtSz_A zjBgA5$b-&|3|2(*ruqYgP!?Tr$66zrn9|m9vN`OwfmfaPz`Vh!X^&CvkRE^h`)JAa zDf4OWaK_tf{dpx$OAM)+!m86@?O4!#$q29oRbh zGC?MY*Lv#wTze0sbS$GCz-NiK*}J3X}It=$0=_XzQM6N0@}iK|C}I z-*BobB3x#y;|LN)h?`M7jPvj3y$|HJ{`R;n*S>6pX> z(1DXDJCR}_NtD@w((;5P;6>Y{&#{V>W8K2-r!a}16yxVcM%?4?vLwoQO*Ww03@;9A z1-rH@hy_){?}Z-)wO@U=1R|S>@uT`a@#Y~}1bGWOp5gru8uF`HXT_N1ushU7!%}Vm zk@y2;E|D^o)@9NCjd#%ptuCRM_{EX)k!~|ZpRpBbd-3?X-Hc0uVnj;D zRj4iWLSv-RaM)%R;xszp!ouCdUm#ay1e#!7@_@5z(DpnL&CkJX4Qf??hli1I+iMIO!o|c{gs(sEF^D=*4x~`KXEhjBx!`GVZ+OquXEB>Gj ziB!7T35$ltIlQH08Q5OL4usQFrvA6e#Jobw$wKy>X`Sb99K7CH(53$DR8pLFt*ThjMVuPhdSbSX zZd<*C8Qk8}!HGxxPH+V;J|?c%U3fU#ZF@H!mW#Ceg8xh`!J~&-v-X^0%eeQI9d$o! zn^#GCaMhKzvg<6X&+^dVw^EBkrLPmLRs0gHOVSTCR^bNwKK!AUD$Spzlklw%ONsX^Q+Z%_I}vX>yb%`dOq{Z4dWrzNl&d{g=NqyQe`_ zJoWNEHY#p!Q8TClbFW9T(#jsc7Am`z4oX$97N^&b-;~0FGkraoLp^4@KYbaf|1n6Y#yP?@Y+{UWHw6WF75?`VZor4G63fcHJI7LV#Eg z9AEj}oq~rab>(f&hKM6&>#c%4A+TJnU^YKnKN)#QC)C3-oUl!{dPXxmq3tAsT?g6# z$=$2r;)QeW3#g`pd>4m_>kB--hEqcc_gFPzG5$OYi-(oa1jS)a;2S>ga zv79t|<#DqtDyXL0D`wJLkAqk<$*Nfg+`;qNy&sz#XC9Tm>6`Nwd>ldCg+44Ve*Bby zR^ahdsjb2e{Ez}AT{mlPvDjGk8Tp}c)cePWLxSK(&4#ljJDL4P%frX=(HZ*ms`WMM zF-3dDT`@ksyWNAVAV;T8SE1eUHX2AO0Jxa?k-1g6Viexv z?oAH$v*I1qr~$(BP3gVrg_`kMSfVG&+3uBRhZ3_k z(u=I>?nv1d+{nZ%$M|gfIV`CCnI$|_DscTl8FI`YXNQK(>iUUZv$N3BP0>?tq3wL; zOj$1D?ep=sjO~7(tU}jl+-StAP!DRNeV+aDHf$fOr4AkQnxTYU3&NiF*UMcx=X5o5 zL{wRokIU!Uw^>(DQMK6Z^_wMpK-I7qY9M{_ImOGoC(7q)>e-PJ+^)wpRI1UlA?mdT za84yzPH}M)jXu20T)=O`mLwdrtay;SagnLmO3|t8V9c zY1C@qK{T=!a|D&EN>|Tn+26H@A zff@B0+u^ehI3IhU_{y(YJzm>a>+gb6qc&r!Conz|&=875v)jTw2~09g+*j5|6C4Q3 zr60&cRuoxYa<__}jFa4Fjw*gYG|DOeVBVv@Knx58)j$Em5~{Z?pf76ehx@u*C^Em_ zoIyYGJR`RgC%++;hY7P$APeoWs}XSNu{z7Vm3JrQO`-#ZAJM`0PcVy(Mk8*;*_F{I zxNQZUBf4rm8!^7`ETX0vl!M*C@UBaV8*&fS^$Ig^|yiDJ?|h+-yg;T)W$ZhwTP zb`qS6_U`fwuMAjofUI_fc*#ka9kmC~DaMQS{h;R6Y-)pnpE~u>myfNPmVKoR7x>32 z?S3lndP_^pW-h7^f_e~YB;rGPHnMMV%E)m^47M$qB?^Zm>7#0B^J#4)m@| zg~}>8q05ZaSi4GxYRuGpPGV2EoaS%f+}0Yif?MH^AV0y`2N4Z_M-C@m_PDc~m85^Tyuy zycGURDV7h-;4baRM)7B~qr-h;lEcc;iKlIupil&c{u zSD_xRebguhQpU*=| ztOtKX=03!;aOyJ51@Vhh;%G?YKKGL(_Fk?_kmpaP z5uv|h8bI2CaDF7_)sw~QfZDdOm3-{C(q*gdEf2Ysc%=12E9#W9oR^_h#Hyv7O%$oa z!J^siZ_=$`#~ND2u8^zx3cIA+f#cmHp)Ljd(!#W(gAAkq>e5Le! zo22Fi^!`xuZGpe~N!JOL{WCfK_n)AFSa4#03`I#HPBjF4>XRhYe#V7(WP`4SS3vag zFUb+HBZg>0dU5j>KryVL4;BsSgR`HafQwXBVrhpHJD=;Dh%76`(q5)a-sW4>Uh^)o zzm)$JA5<&Li9~i3Wrp1LL07BlEE4jSc~cZT>9fmvizI%f`L-I@N2p_4*qVmV+r6*X z;s=Dyt1CoezR4dqanEzDV+!;>k5KGL!;oz-Z30j4qt~Fsd|W%2e&k4J;7w0x_=ul-%|)iQ&+MtO3(^E{<#|aC_S*_(|Wh1&sfzp4dK-% z4v42v@#Xh$r@fT#?as*gaRv{PcrySd$cCYC6#>gdB#~yV_8_@K;*F#Ki1+T1*y7V0c#GniHP~rhPYBmHx8s?Jw*v0DO+xOK zIqX7?&bM|Ak+|r*v*TX! z)JwDPyumd^{wBuZQN0;pbd!Vnas;ZK<*MQQtX;CLqrfFW-er>GQ5T(k1>o!)hfK>; zIE)eEAw3>R%*Yox%fWd+hLVWZa~F4Zycp|p8BY_uF=l8j$&r2fDDMReHgUV{AHA~YP0amD#S`xwxP9Pa*|?b=%x18B~3MD3{`*3+Y_Dk zdr$1VRLs{iG}%6@-_-PCuksm}2@9#eudG`QGk&P4U}HR}6c}h_5@9P;qZwRkcGk2$ zrnJTn&Mux*wTMv%P`Wxp6;pbAgrLJqZ%NY#Q;Jjk-m<>8tW{6rUwSZ2eJJeu7VDVV z)WpsdUlM6a#QV6`k_u(6e%{67l!Ty3r@Rwqysr2+e)bd zlIcw6Jde}eAeEmI$ka+DkY2vh>xGN`x_HFRfjFPceteC=^JNkwtWwhMOUh^Ge~Nf! z;Jv6kbA4=obbo$1*L(f4UN`+5f02Kf^*>)PWl>j-kfZjwtmk4r;Y`uKl*!~tumS#o zvxi5>2xpUG2M5)aKC=y@Vp|2P1D}ZAst#(eD3#-XN1i#%R3ztEA7K_kEW(0Jq^!Vn zsG${~o38Os3W}daZpK*}Jw|a1lkXKwv8h8DrqlT7uxagB&aKoG1nbc!0{XCti5Ylv zZq%iIMx5pJAzrQuXF!a8*0=F`K-=gd1eRHPBio(i{dd(a|TD`mRh5z+f)g>n4OFgbNh`v}GCq8INCv?M$%<*X@@n~20iBfzt2&g~E90E? zoHJU$>Z^Gjv^Fn3zWY=H4^YN>>v{4psqB0Aq8`|VEIdUPJRPhbW|i?cZ#FCqPeND? z<5Jxw$vPCB;*trgSUINsqbQN}RV2?8#ZCKl8bMc%OWx6wqUEVONT`l`<820gw_iW! zAg@H=_4GL&Ir#ax6399S1;1K7IUJn2@nU(%;#2V-!VVK<2+e9KJ|B{Zn%%7Q7C}ya z_&63A8atRpO>?$a=XFY_RjW<%xT zA;0v8alWd;ucoCAbg6KqcktAFoej-at)%(&dJRj3B%f}?z9xPt=5?Lr%@q-baUeuh zLT=nyt`>N|AiiMv6<%(G?ii7`={%?ij$p0ra4T~mkHx;PCU6NZW07ZfW#C)Hhb9B# znjL5410Xw}>2u}BkJlN=?rv4xKZT5zzgaw-7AcBJe-*2s8Fx-aWkT1LG6gx}ugEvh z2Np2CG#_jhw!QS)L4mr4H()~ra+H-d6*8hHy~}0~k)QfCPu|l~1KRXliWdWAk!Pqm z{R5qYQ9+2PL`U;eElqMK@Cd7(OX9^XT8c5Vb;jeRaAl#laUZ0!bknMTs~B%@lDR)%qPwGJZQEi|bw7=I2(oNHSNVqpleeaJgan zrWKTHsyXvA*B%mCtg}$+rI`~Wy$BK&u&CGGQBIPnAA-6T*QhVt8EIL3bJ{uP z;85RW8R309l{b>P*_Q@AlgDkZYxK$J=k##+o)1T!{kc7yk&z5;R-*Zu+8jwrldFL} zd8+Ni@dlTpN`~Vk>f)!Fd4e?K!j!uvQ{0rdlXfR8_Pz5$qUL&Q`Mc742^m~K1}}?6 z;kVXCJ3G7E(nnlC9((;yMu8k4eNm&zl&lQX>-6|U6g|EW=9g4a3n$O#e0nCPsY01B z**Xo8-7TY@@Hx5*{rl_vnQt%ItCkb7pA}GKa&hCsJVtXZ2KyrW6lfc|`tp~~0Pt6v zRBxRLelnA=Ow1{3v5eahuM&Yh@&~3^GM#RwCbm~`?Sn$) zHy7j9D56UCA-&QYC2t)oQq_yfR!tt-FU!k6j?g0a_tgQ0spH7ij(-YiqePU{4DOZv ztn`eHJclu%U7A!S`b-d(Nv=Wj(V#SiMy5FBrl-zfTDl$(>jPAhAFW<2ZZg!wJAS=V zl#|i+?LLEY`jNu2TjPGTFHQT$CKF)fUN|qS{XSImL2H-`j-_hVn8@s2|DBtH^?{t9 zjivdG#0xYk*a-adV2s~IA^ytg({ zB}BHv4_x0e{l7rsra2D{yj!c85w;1dG4Py^gHp2AU3YfoNb!7;tsZj2qpuL{BEW(3 zB{GQ&8*LODDP`(xtu4Q6*Hgn4DQqp+{{YRF zu7}}7&;_Rr4F4?O#WXF8GXOv_Q#0=meBGICE}hXndfF9P*JE_Quk|d1FILyngC!`j z)Q^BmggqDMK@yJvg{dw3>UiHOzTuu>5)`S2idp^xXNdS6UjTLklp< zdEbPh;hHOa;?pM$DIw8$4mq@OvGfn}96gPvZpJ^pn_c_P(>66wz$hpF$QT4{(gBI( z(~P2)cs>5SxUpafG)lb3+`LF0XV^eEIj(*k5bG;mR!cbIGsS6`V0YCPDizoDPRJ|v zI|7(6qvnF!#%k{DdOL{n6>TmEBKu}j6r$oC2bAa~5oD~g_H09cA@u9MR0qX5yjNFI znV6P1xcw;y$m1-!w?Hyw>#t(4tgCHmcw7aDzUA1ZG}Jy{^)CfoJGG3et%S%MDBXnR zh#U;l>;m7LX}U0nE>8FxPRkU@yx5g#!ocspcqw(@OK+0F5WiD;qP7-|Z^J*-sd76k zaYAd2P$=!uWlAeqdue!AuuarTjNBtAwUdZQ=b=@vHSsoeEuKbW{)lQ9-iyI=vDXk8 zJN`>I+-}CI5$wC|Ra*Eju^tJfy^;badyVvOHp@>(csJOvHbW^*R*p*K79Zg%#5Epv zIU=uO@;Irv*?IRI4Cg)8Rn}F}P_)@4A^|I@*lW^dagw$xJv9o zfvnO=%P%$aH4cE-j%}7A>4hj>nm9A;ZkEFf$q2=D3-}MgpM5xe8l%jInt^$#R&bgX zftjKckv~QyoSg4q!U0pW!UC-dM;)qj)vg7!HnC8pbnIQ|HIqhKq~s|0F~Ky4Rs7v) zB~GLppQlIt$-eD73eko*2rEQsYr@WEB0g{@mf(acA7Z3qi9e8}GA9?$`dQ}1*a{uDd#^HOMOroHkT|9NoE>-c zRFt61ZUcM08Iw!z-af!cuYA#yt54MA{-R>i#W04&#| zgJ;9D)BVq>hpVKe4{6WU+&ns~HT$GrJh@t1G%_lytW=MF=sE$6k=MM{2QchTSKkY7 z!Qhh~#hG_TS`}ZMRRId2M;M02hER`o*^c^VaMvIOk@-1$TJt_+TkH!%$-Q@V`_kqr zNB&{CYK;-s-|9Z@S>!8V{kxTLtOYqG`~~X%Epq>lBK=QbKH2{g6!~uw=|4vXX~X`PGN0_f3-SJ=2>9D$T6 z!mcMrm{?m&O)u6_Jw}jZ3N)Y`j+$7Uae|5twDwnPPDdhZ z!D%Bu(I8H_G@`2^HhzMS(Jf7~`rtm4!z8fRbH&YpL%k9qkjaA8_AoWDkYXvx`sEbE zze?5T_$tDZSFU0A-fEZ)DVuOpK!Fi9W9)J{ImrkDE7wAk%4_wT>mjQb+PgYP^62+= z@5Nx_Ov&a&*NFR@bYO?7JTW0nu1>f&$jrI!X4H_@?rcV38L&bl#cc!0nDe!z9f&1^ zM}^_@*~y#H3&cZ+o8Kgezusq_4zY+*wgY@?mh|M|{TvDtC=&lsi!qMPmsRR9AI&n; zB(5~yZLuX5+KiPaHfDy*F+F4kaz^WUnR&fWZEHn?4-H&pEEM#rHLy>HDNkK_=mHuJ zp%C*=hf9v%TO|L3(~%|PFcEG#~BT$=(U6YxG zot_QI!OB9+!U3e`U}FXXwV4^gx!{ReS;5Q<2M04V_!CVafP)_Ji=YAT&kAIxX9utW zf4%>$Js=p6VPaus*JfqX1hN6?*;v_rv)>qrfh+)U>#Sf72*|9-%E1nXZ~&~}1rAMC z7BKkpYvFg_^9u%IVga%-gV%vS{dI_7KnM&5F*30NiCI{{X?R!xz+cJ?OuEpsGqW?X z5HmA_kCK@QjO;KH1K7c!5#SfT^Y^vv>_B>E7DfOYcpnZhdGw3(VFiK{`~1R-e)rwr zQwDQD0A}!^6SFb`=~;d|K^A5vaE2i;$n?9t0qkH%2#hhY5VL`K9`I+s!At-)R(eJb zaHsqgVES7Z{}EvNO=y3kod10Q6M+5~sq_bYiG_{+msG)6&_CjrIDSp$6@O!ze$Oxc z8zgY>d*>Ge2RJao2*T2ZgbUmnF*c?o z$Oy+J3gqLrFgR;gZcgsnDi1#`Z7toLxjlNmG~Kv-s=B!Xuk&aft(tpq!e$~Z6;KkF zAN&!Ma@SCV8bT2|NKyK9@PkQ2^c>&rgTmDPR~irT=kb`hs_r)N_-XIpV}evJtNxkm zlD?2dTGG&Pg2apzl|)-g_?w?F8Yo@D8^epNKCGO#*^GZtb(th?Zh(`2o*T)eW!4^+Ey&N^ue(SRzQ-V{^ zsS`@Md8P7x-i$H}`)Gkiyg;f)EBPm}7HNC*Y%1_DerE^|WVU z%sJ9_ttTLHEN8(Tw@DbdLRO^228>%gcPplPNZAP!4()vE@rLh*go7mX!S?R+cJo>1 z2QEp+Eohn1pA2&J%(c{DNiAHFUD_hhMHme;ZTk}Q#TMIx zI!Fn=j?{+ed1v`bgBK@5R-E9JqG6_OD%$Zr9(D8s-JIAI=%{#nNQ;6Zy$ znrka+tMjuxf%bkjx4=`!NAj%&N;v*is`i!~gl z(KxyFM_IfA<8e+8n2Kp%O4;47RWuL_mnGTzm(|1PPr(;x_t?|?d_Kma5A?;31dgV0 z&qx)~+U|Vp8~f2tA+tkK#W@xtjs%<;!G3=602|Qby zrx|t1I*(=xVt27!A*}F1KsU>gkmYEkPf=6S^UidPxIj^Qx;1`>9tb>hqD3lfUxrg3 z_iJjqF=mceU(%uQEAo#ws4E;Ub4^-dXJ(moAH;Ivl9$MZA^AWz{n2<4XV`|h-Tg>Zih%rvj_$WJ zeKQ^jnxxCdPP z_7*H&PQcXE{RlvfPf#g3Dm3OqwEynwjqD;)T4U11p6fyuCk#doJ%@W;hvpY`soavf za4{r!1-$caxar!7BMQ8rWGhs+LgKzJb05|D+sv!vvMmatyvZa{O$459QTy}w#>svN zNc8*p-@fmcjSey49iPoSK`e)|i!S>%z#bagI8hPZlyVe&>kb99S9m*rOmusI-h}q( zm|c*~agIYb?(!kCDr3;*3}lcEN1gFM?a_dvuu&3ja)osPm_ic4|B6bu0 z7-1f85n@;y!ZVku|3gh}vM8s9qL7$z%X{dPK96&haOh~Z17au5agS3S)<%ss-wSc( z`Zwv$MUkHYbTja&H?j+u0a|VD==QGkm|*R?qMDHVCP7xED#sdau@3rh=Ee!Rl=MA(9YhTLwvfnKTi9N)C(XF3-2%*<^SRgyPX?P@RVToc?5nwE|9 zripK)}xf zI(eu}c2pTSqtHJ?Xz*=I8i2tIZsFsPgeCH8kLX+$4xflCb|jH&d&GOL4a{GSHcR!) zbMSy^Lk2%^OFtN^|3B=#1#Dbfx-@Ern3*Yd%*;$NGcz+YbBr-_%*@P8F*7qWGqe5s z%*?$vbKjZy&yz;)&5_1-OV;kzR`;%6Yp+$`S5-k#EC8i^#U%XNa?>X@<-oJfsK@KxsTUVC<0@q2?G%9=Y`Y)mqZ}0c91D3XW}i@33|v$P z%*Qr6HJgcpI&YyC?0{S!XEIc3eSuQsDyr^wBzsbvW#HF#$M2_~(9cxo^9Ef7_GH$3 z_B712K4LhOuR?r;YAZX6Rq!rxlX&RBdYv?zJ@$oFL~e456=j(qHU!VhI8rcrhE3+e z`S8pa^e%N%NV#h`WUMh3T7RmTxym{qcK{bmxeLU3Yf!k|DW*~4)>|4q8&&kyNGs-6 zyv@spE+$FadLHo~s`~zV4D`si8$G0>{p=;wt_kRNs%`1 z$o)lzt?g4pB4;U}6A<3F1k9iGir^z|m0-_BOiG@#<~>zng(Dfo6kdgHvKV4CUJ41_ zfvP2O5}%3#AG5X$BP!DBC+A_>pQ4x{p9hGv$=$MbxO*DrI)oXv0q!o(hvUYT)+5Q* zX-`Ai5{9t$RBpEpIuyqZ?p6=VM!5n)OzWIGy+lvrFUnu{n3&+q?pBY|4j$uaik*|q zi(m20{M??>q#7fr9~CdX9Gylv)|^pjtTJhO(7$mpTP3@Di*{G-_|o4Mx1rDb8fQkFwMMm&SFb;dAy+&cW7oa^my_&yvy}0dxN$* zrC*!6&yFcb@5sz(vOWTrS_AdG_0RY!E9mZV&7?ikUM!}c-tAu34?FhHr82YTTVPjD zgtivXe72*=sA9xm3{U%Z(mLVd)JhR<*nf}R-WPZ#(7#M zzNTD#Qv2*=rcf+6?OJp$seZ?2S92eR(ej<=`Wf#*9JKDZsDoLlIJ%g5?6zNCkm_b1 zzwU?PHg1L1Z{nq*)a?S4D)V{V(bF`ey=Sm?#Iky8l!{$a=c}C(3(3Pi@9LAl6~dzB3ExJnOE1|r@T83sm0@`XRg_8 z=Sp|oI_^2<=QF}P>^0qwSc1~qnRGz+dAV7JtTtc_Up6@?N3p8XJVC+> z{kjFUC__9vcI5@x5x2dwZ5O{nD!vQ*SoI=@o6un@VQ+>&N15+A5|*f~Pu=_Cc-yzi(VvTo>MkCNJ>wPbsQ$yCoWV})xEGgrGZecR<5GlN-;Rg^P~T$ zDywR<%28imFQvyR90xsR^}^5o<=(kMtYTdG>{@l%T*Q+1XdnO9$Sw443h*hIItnh$ zn>ExpTvdK92*#k>qDZ+$8UGeVYx##8TrM|sQ4#;qVbl{@l}ss0o?g%cFSh>-(Y9eo ztN2~ig7Sdyu0)fXRSfQ9;EMq6kM-eort*MZ8HtueGP)9d>OPIY83PauDZ;Mr%+NUm zxmHFiN(8rR`fZn=bJwg+Ne9O5vU$mwz1`F=j6Kel{@C5Ojlsj|+}dwDe`%7fzwiZz!~LXRpCq!3llgsNMSnVy znw|MBiTprwL3i=WQ`QIfx_!cd z`ex1TL7&l8aMl07$eosdb?HH!(Z7EU>Or6_ut0cS@W|jnr`?s2cgW~Rvpf7?*X~=f zQ*vPI=4-u0bCvKg?7`q2U^GQ}wwJfk-Eg5?Md2Nnp1bG)G`h)if%HQ39{t`UJt_ZU z?3Mi9HGWa^g3U8dGog{(|Dj)c{Nk1L-sipVJ>jAD^L@wrlH!G&W_!0b3N=^<;dAO| z3I9+C?r7;Ph6l4r0iy2$(L}xiFtYOgpXs#`B4gD#35-Hi6~u7qq({)8OrW+b5ZcJo zQO75gsuH!3#19-VOI1SLYQpNLVXHJs;VF8_t1w+n!d1judaw1k+DPUIx=-`&P4PT= zpAWxQedErK?1j9f$3aY~>UIZJEm3eeV0cPxhpz~U)uZqv)5_`Ia;yq(M_fKMe+rDi z?`oK6*n+8&KS6v)u?}hIS-!!+K{@~Ke8~99Z+uX?0He(zjn?CSL!p@~?x1>-wcew3 z$^A-wH;FfZz!UNs777>5&cmPnB7m(EV=5th_8^L_2m70TN#R4kG?J}qsT4GeQqW7Y zRm$r3;sDhW&lD}M0wiuAN|}^5(7(fIP-a9K&-9yOY0kIKz_c_zmD>0_)Rr=v5^8AZ z7Gm`|k{$i=*jYT%E|IP33$d5+ebuun++6G}fBkv)n;-Tosk;x?z|@zosM~TPWK2ah z(1B@fsrbi(PbUO(kz6BBge9YTz&n!F{<~Ek%<){r#=|6wdTfDZjk1=dnXR&xRthOt zvwK2yO|q769ZD%WyRl48OJk49yS#E^YLEoXGq{5Q3Ls)Sb)Z_%Ar`*uf{f@ci$Hkb z%^1AQggfv%cG>p|*gj`fbSMi@9=?zLd~hlo+k;Q@Z8Ws$P)}cM&|RP(K0TmbOZ$0! zG-2ff_xr>uS>(v6$(X-^r1rONUHXQT_-KDyr;8jB^9Jw+VzAW2ceZ0GoCl*P&*H9< z8LOd1l__G7Ngyvs6b7w>+7n>)8f zhG+^|1#|fMGM?!S;H-zsu8Z@ng$|Bwfs2=AgfOM%j8}T(D{f$Fzni`nfeD@tz#ah{ z7KA}p?gda_>OeJ}5>mH0XoPQ5@GfNrxu%H#2X6BQ=D_A>xl;Q9*GT4;qqRZn@+$)IYm$+~>6<-X^& z_z`Mu`$HK@zGpQ$Poy3}-sX>F9R}Z+7u3CX&kND`Rq!ADAZmGOd;`^F-l(=HN#9W~ z*yy^iY$PnP=EeLM%jqxCwQzb|mBI;s4G8KgI(Cm0MK}b+_ZEMw@-tVnIZVfYWSRl0iX(~F;hUEpNatw z&_G_4yWXn7_IQ9{>hUw}G4%NG=LeEeWkN+hK6R5AJ5?rkG;~eoRf2$56hfl+>QjK9 z?~pP5kndDZDQMyPG6By3J8GPip(a$JHPNxEjH}EXxE__J_(Q&h&aU9%gfDN$=jb4V z>UcuK5YU;gF#}xHY zUcnA~T}eTaj}Jwl#!(rPK#`vhjiJU_?rQ#gRiggEMG3KEyEyH;0Jk&@B!72e$>#yF z)DI+I{|Xls;rb9JkRAo6tF_pa0lLd^r3(dg%Xin1`6BvRSZqgV4*6*PPY24& z6-Ayv;`3Qrq^IqXW^Dk;u1b-CNKd8MMUk1`Drx{&ViBH=_w(JCt5|`R;cz9G=aAiZz!%Qnth7Go8y59u^hoiYRUU!EQ6K(?hopx}S}sS5?o9IL%3Q}tX2gEGAiFmP#v zO~Jz*@f>eC*&)8`Jft-=KI3+PmwQDpW5=K*V^3tp?uREb!*f{U5NX4bb(GylIgrA8 z2|H>!D@rxuE3h^P-+{T6&C#!g%9>d^HUl61kJA*KT29J^Bo<9qLB^k zDV%Q=A&Lr&J>+rtDktTFCQ1O`Y1P#0R!q$K@Eg$6 zKAuUFHTae_haO8sdjrs?1~n8J?ud%+F~bW(H&c${W!7rK*Bf*h1A3Eb5T~Ydp$gnI zF7pPq&a|Q5M_rO(V~UEtwi#0S^8!|x3JRL37sdSBW?H!mlz*LuC@T8Vcc^;j+lITq zsudt$ysBnU-;Vx3HJ$I_DhC`&xAxy77n)HOq>-@nzkNGjAV!^m<*F|M4Sd1onDAX{ z>o)>Cs6aOp=!T=D-FdgaNV5+CpIKaAugi3LRi^VsfgR5Tt{4aUs_{5MSj5HUJ}(Km zy7G-{>O(yh@Ox)l17knB$nOUTm1#Bq0ih zif%U4>?ocW=>1V$alC=9n0qqo3WRaO z6)R<`yOsXSn4+{~Pt%sh25pXfHV18%`uWY6&Lk+RAL2@bla#}}hz$!Mq!g)Tj}hjV zw&@0EUUJMN9i8h+68hGGVRx{m9dKcByb|lyR_|)*9Dt6Q)nCR84%E1(=|UE6O=~Z5#XfaBU=f zZ42@>`M_bScNdM_s#yiXtQ1!gvOzC4%uCbl)O%os-3E>#<)KjbC12CoM-+pUXF3aD zS?24~(aZkwcM2Kasqad6q!2z<(mhJo=<4&^tE7K>)#V&)_vlUxXi1%)$lsK-_s>7K45%-8w~@bEDtUh{Tv|_4d~+Ih zc`W2Ct(!*OJpZl*<^6i2_gb41uV24iy=}*P?c)gO4dw(f0=I(HNOI7(|G$6VFZ*9Y z0Nhz8(YbPY`_V-@k;Poob&OS19xTsv3Q}MTbF6TINA(8)?d10zSftC9hxC^W6G{A$ ziWjN73E4J9BaIM(1c4;BVA;1I>xubGAW)yxD;J!0Mr=dO{e;(g?4W9H^&nTs$DgY?9rrQIcfxVC$ zVse&=b(r6DOJI;o&S$b-ELF?yaEOj(OhEMzwjqH8yOsV(w@D2>(- zY>&&Iw57ZqjP}qu6IgA{kgqxqd-%F6NuUtf?B;v4ZV+%4%OSZFpXF{hD;E_K`BWX4A>*8_jt}*t_9i5ErMn1M13Pk;Ec&?AGn6C9X!&&}i9^~Hcc@iR(aBY`-dJ;E1Tl`8q3ko=NGc7u zR&`nkfr{P59of}AR$e~|yCsAn?0>&pps9S4GEdS z8ToP?w_78Q1Xk{9wmDbjiYMv*{$ZNGw%OW>XU*m;>^5l6k%95fx0zM;mD=jI9w73F zqY!^VxnRaSDr3{14A^vx+&7krRo`}Gw(E=E5SqkJ_pno_=F<0%bjo{ZI!BICXQ6h; z$K&ZVTw8gGfR|1crUy(s2&W%`%D3Ox6+L(pY^yF?WkdHi;gy8?ZIvnELgl0;=q1}# z`=76in7l^~7(9=qYbMl?Vp@mqUhJ+`8=Qq}xOlX*x~*L8=Q${KEgxl-4!BO*j>xXP z>ODDJR=^(5{a=_WI~X4)J0s7GrM3jfpXVp?s)fQ0r0rntY{(S#6xhXG^W;}mF=Ya* z{cYl4Y;#}u5Y(83Mo6F2tamtuSm35t*ml=_BBf{V^NmthZ+M6hrf20AJ-7SKtti%r z`TLDCw`DlzX9@MKm{(^$kl!u?OD~nx#CC=;HWg4rI8xeVi}|{U45rCKYv5Ab9oA7v z%J9~;lSIfkJ`aV5$2n?zdX1~nFI4?w{KT+myy6nqYkm;> zMCp8gZCJc@cg+u?ACq|fXkBW}2cC&68O+^mwmj#deAmI8d7Ze#t6frardFEY1~J=W zD^7!JN21&URvISe$0sp!MTV~$i6u#leng+NmPf*H(RfZq6MwcpB^@4%shrhTcPum- zayTcrW$eEW&zqc`-;cj-{kSUl`k-}xl9!@W(01C7 zdoqXlR`V8Ag#{O>#+uKTreyoVRVPxBY8yTCxJr|y$7C3p=i-c}`n-#2uV*J5vSIpm z>@_aAQhPNtH?@Or_&h+VV7XT@s;+9AV8}fF- zG{F1@4)GichGK^_HTeMJP*f$1?-8LaFhHl*{=rx{0cxG)E937&Jgm#t^1Qk~0|(9P zEe_d8yf2o#N-yKVO1!;aY7$6jcwS9cNDAW0?K}4i^2?7uQ=8A1RA{L!AEHjwrN1-? zmDId6ph#$j0?5x37nL87=W%7T*@-dEV9$#vvk|i+l1o9!BktgOKc{q6J*sU^vPea! zcRVZy;k_AMLbb|bm|xN3*#zvB=?8~lXQX;3#Cy6aU9O?Edc)!fPmji(LNaQE-18Q+ z)ZbJ0V=Vr=`dWp3inOymNX<=H(ka*eqCF_6D!_xnI>vcQ6m;|f~S%^Jb>e;s-R4{ zSpdfsubBKoCTKQBwEzbtoSfkC)(K6 z_9QJRu~-Ptd)50QP^RgF&et^8lF!rLXJYk-jt`A2WjmBj!;?uTY8vhj2$*J{nx{v} z@Av0TK81Yvo!(X}RIFf^xKX^o(1%h{r^ilk(N($oT8vtSN=lu@#Tnd2i-E6i-*(Q_ z$N@5t3yZFL7aJLQDw#oS0XmgPfOEP5RBT`r(+0qaf5i*+GVd+j+7ezE>Rm%UnbJ5* zKEo-MU!;nx?p;&bl}>6c^!Ap2Z&a*HpnYpf@DZ82-;{W*7tV-ypetO+Y0{(c7(?zI zf34$FXi&RJA(3SbzRKv?AQFNc1X2vYJRp{xRA@S`C=mz`T!guX*GD_h4HePRn)d>|=s^9@;?>Bm!@E>x*^g2Qwmb4n)A{Q2t%0ZN78#fVxm_ct@6vy14LY{4}5ni)UINmM3IGA_36)M-7JtG`P)uj&anz42uzcFj-usI-wi_KP;8$9_czcUbzxC86@Y zI@dn^Iq#q(_py9CN!Q8A>+M6bo<^_s$k0h^Jv~$jeW-W&$gI1(f)NV*q#{L)YVu=M z+Il!fNFUz3z9wtXJ9P7*p@nw?! z*1{Eg^{u#dK%#9zcyk^0xwQx(*SE`X@-=Ni$6H&ub&LIvp{R`vQatry78}J(aIgzh za$`4O7~i5Dsmr}pu3Z+cKe~;T>6H|Y#T=b4E-)8UHzOtI=v~vGBPW%Sj&Xm3F>O58Ja4=o zhHJPRZ?cZz)!@WqrkY=1l&5BNM*VsvxIxtAy>))MI`Wbp5JOkk3g{T5uxQvRx}pod zvPu5UKToJPAW2f7mdu~rO!wrQe*f74?zF7<85_6vxz?%IIgQ^?>~lUi%%_xRA|A%? zf@ItYKVk9kQPXCok&scfItxrs$x9!l`E3!^YSgsuWkd?i+YG^Wqf22pq>Y{7r9fSCq$bZQZ0PFp z8Cf-md>8%6TT8A!X^IdMDFhpvq_|m^gx#g`dT>tcvW~UIg@d@o#naPb%n2k{OSP;W zMYyE7O88W7s$SnI5xy~d;e=#0&78)W9b;L1(6y82R(>f{=vBt{GZ2{AbcPfYCPnWO z(VSy;xzwpIf>=_uJ52FtyaJ&NPBs^@{*y)^6XrmmlTPk2cm-0Ymy9s4`Q_|i5evOvj+Ep7U$N#s}3 zU?-&)?@Oz^>7x!K#SY!vH_9nohT_prCv*kLr9HS%BQ#b0i24m&bEN5Q){%}Q88!W| zM?W3iu|+yxsNFUEKD*MmV@q6meCLAA^75$XDi`&9Aag&-)tQ{b4U&yISfZox*5DhP z&=nM_iOZJ^r*?JyYF`uHA`Bx%e>O16d66s4Cia1-6T_i?KTEP;ru# zW6uCpETM?W6QwDW7|Swb@?(aPsVrQLd$c)K<#8^RpKzL#d|+eT5E;-)Xv46Pc=1RlR4GZP+{4+i+wncNq&4M6p(%E z61mV62FXYAwAuFHPE=CsLukOXQdiVJkPu+LE1J?uFyPu90fheXyL zm9R+*CzaI*|EYlsQ}d(kYfBFyzX?B@jYph>&g(t`RMvKiWZ5dVQ}Z+Smc$ zLE?8kWR9wr&vCL6%}y9}(?>U{RZ~4j?(pahVB|2s_WP~5zbIM$uxgv_52YD=w4?rA zlFZD9YI|D<{w-a*>O-}?a5B;^4nYR_n`k>!p-55D79M^Ufps8l#(RA+p=Yg!d7h&F zb5(9p7}kKlm&q@l&<~fRf9H(K?&ax+nA#(u(-- z(Yv{CUNq5?kD*A)H!K$g@(xPA`mCo8H&dwmD{o&QSY0x(UbW$s5b*=Mn z0`!$A>E`vVDIYG*JA+r_gNt?|kA0zDdBB9r%%RNm9>j-;0TVH}^vPE@_542Q)aPzgG+i<}6D7OLpR00q~1@H&C0+Yba8sOMq1o-4W(9Ol#co7YK z#HLoeYXwwavaA?|+T0dU&1X@SRs7_g0~kOeJVOAWVv@9CSH(o5R<6IN+7?jEE&r8n zdal26MG&Rznt#pJQ-ZldoWYaB%=B1at>IiQdoGVtd%)h^{jL4QY8~i%y5EIC%dTRH zXU?Nc7yL)#CZQ-H{?d+L_Y1%GHVXkw$8p08p@%ZbLd zk&aUB#k=N=xcBjW9AL{g40h!fO z6gz=}lGqiZso4pWL04Ujgu&r9`?Noj(g3EIZ#5+@oZKwDz^Hk0L8amoIVT1~zfM4_ z4dI0>zoKfNX2+M1S0LnKb@wBcE1WA@2RVFhVhXJKV$CfG4guX2wB*0GsRR$~V#S%x&17osMW z{JTol7@3fAfDv@W{$s98%oOjy1?LZvRiA@-2qM}=neR>+CKX|!d1|sihuOT7yDGAF z!LFY9Dva^;q|p=@E4eLki<367rY(g_o1(~RYc-q=comkn*i;9ZOG&`v7#B-{p*gSA z79xe@=}}393ASXsf!IyTZq#%d>~rO4GQN*RkjM z`L#>0k3Dzt3i`a^&2+%Jy4=CZT^SF0&uLNu;2%%DG=u;h7+fgY(C_ylMh# zXG`OQcERyrOyS_Pi=p^aJruF z4w39o)zm1%U39=u=h0kQDW_p>xHosQqvz4ATE8 zd)3A`DA>gi2=ni6s5$@3Tukf#g^zZdM|4&)}zo`bC?HAGE-$VFsuK}l{{Y|d)FB_A8)zAEw z0PBAP_`fyaf6M({>G7*qQv)HOg79j?`fm-m(j>VPYZ^vfF|03|zpV^XvB2PwJ4u@~ zGSY1=ETekw-Ib4UBT|as;D~P^y1a2ItADakznP1cHG;l>1SQt~v_@#tO*c`0HDiE% zM`|yj_L_=*sP|#VBJqT<4@B?o&$6od&1EMYCDZ$*mHp|p<>>DFtlCrf zea=PKSWSX$f+Vm3Dvyfn|Hp7k7F?k&Xh`X{`3dCG)m-VHX0)pDhDNXmab66TPpJn z-x#Ty*ts4^^2$c8SA(HoAzAFw)NdqqD_9y^Bb+oHcV{)+csTq;(9fGLMiVI{;k>?7 zpcpTCQB7$$Qn)`%R1%H8&*dSWegz8a?3Dv`4KVUq%Cs%(m|nx{9Yd3tbGSCrnBGA{ zd2_8|x<+BMZN1>h@%en*cdb@>3BUW;UkP?rl-R&XA8A~)1At_>Ba-@u{A0?PTuzk? zYucr0xDB8355d!e4=-vI&24YGX4%>-M{0etp5^tXwt_>(F#r=7n*#qE+~xZUoV}Sr zd$&%Ar+z6551@C0P^MTO-PrRunG=QHpc_uC{!2$7N_ppXBo?1`<(s5i9d8cBsbo zigyv^o|Pu^n9VyzmD;$iS5wrimC>1d2?Ge=^exV<+D!WMXZDvXg55JMU&%bYI>zv8 z4hix`f-D`h;7rm{fm3IPE;zwz@O`>t$yR2NA?h4_?P85>F(5e$ow#!~)mBo|Q+|ef z+J*eU>UM?Bwm_Ny9Vg)xyNLTKDb@#j6+bhtvl8yU_0#;6HU$eYq;D?}64YDR8%hTqiU1SBw9%_ZM-)%EWHjT; z8t51%Vd7xP_7P^D-)El4SmLk9RBcHrm9|7(gIr(t1tx;~AwQLQigBB7N@84rjUkH< z4OLnSEp3>U2S5{B6s4)036Q5DtJjIA*sDK7e2+oG^`-jMwW`}QTVs8Oqg6y z&Fb`C|62h=G5I2UwZW{qdzn;?TUhc4O$(se<9HESt`_j1^{gW+d z_#k7IVjxZXHGP2U2~{mT5}niuti2{mB;9lb`n(kN?Wj3{9n^^YeRHdhZR7(l!Bz#3 zWm64j#*9W#4!G(mT-)?hI<0d33HQq(YC_U&gXTqAd8VWSb?s3Q)Ji9<*T64&MS3;{ zxtj^mI>h9-qIo1q5f15fATzN;j2c>fotIVisiXy^dO$fz6xtNT+yo)2l6xFg8rx~o zG9L4Em!iuR6}4e$yXK{bsmOKZD8*(Yxd%1*rZ{JqIo3Z04~dP;R<`e%Y}47p-39cX zr}@O?)>Q5Ip(=pCVS#s+Rr4v_Cf=d3 zT@edmO{z@jEc=WrN`evzrH~s;D@l%9=$m+=%T)`Z@ignfb}BLI>ryyY88!1l`+|W| z^vzOQOwzS;b8SA5g4wx9*wSbMr}efCV}yjHym*u0q|#FH2kbK05i=x?$;Bfq6;p<& zSR`{JmoWj>ut*tt2yg0r2#)&%*Y?J*(pDw$KrDIR@QrlzBy47wro$R!lS&-uIZHpr z>*~hd#Y#_Kp}N;`HQJcIYb+I-Q{EWUMBHZfz*&0CkJ{fxYb4Nx8UX@Fn|eM8a#xI5@`{=NMe9qm8lNB#u1 zhjeuRN{>8-{~JFt`l*W+-v9g=*?z{)mW8a0O9`G2nTCxFx2G>gj%bGG;!u(?C@JkR z(9l7rG{<8GtRE>SyeMb`M)yRoD#4(r?^@I~#X`cVATQ6A;py53^dw#d1%&~MU2jCp zFxTJGv>NU#kjz3_O+hi`2K%xzU;`|JBuA0T)z!4un>?OgFxvLo;&nSn`A0htGynw@ z#s2R@`VaY%KLh1O_pfx#WBBKc$-k@Z;a|;V{>Fa%*(k3Mi=2NQ<;CznphyWd-xo89Lf-71cbY?-1*tXe&1IEic2ttgm+2TzQa zB}aAWTSl2@s_Bweb==Kd6GyDdEbE{pj96yJ%#dRjPivbny9}HNandki7pWX}*a?Yi zQuZN4;pF8}xOp(2uM98`4|z}(EtzivDq&14jRAJgF(bvV4VR9xq8IC4bqx>CfzftVzwx${ z=Lhibt~jBjL>9;^iZ(A$(O${*7CSwSBnTP7VdpuF1a<{r!3h~C`=9aWRYdmJ+2t-B zi|0%&gXfU$|H$|}RdOQtJR6|-%_FIo`B^GITrW4c$WSQiVx!;8{65GI#Z%}Kv1BH_ zC@xGkt1Ihs;BGF8lFC^)lB1^yYtEpH=wk_5zn&bHK1Pwg**Do_UFke@R&l0XRBVQw@1j7!?yJZo>Y-+4uRo`lHwJAkmppA2V zi$I0Q0zI8SLxLOrXlZS+Iy$@D$A4c(24<+24a@C9I@GB5=!^vH#%N=R_CbIE*G?<` zYBNpHxiPzKYZtbYsHP7R0oZ>jKcVjZ#pdt{n2(XBjVI~F7n(3p+?ERtRz8pc==t23 zVRp&CHDCXbdj^w`^-czq_3jIX#?xLf$PPeD$umED*cli9Dg$!- zp~vLwv@wXAs|5O>^?MqACxix{!%Lj9iskt61r6$>;9byr_3;YdR2Xgk90nK1=h7_a z5b<51E)S7072gsSPYZ)E z;lOk}e;7~VqdgIZX}jj<0B;6hZS$%$%0n+B1=vR9_gA6slgx18FN1mkEj>6hdJcjO z6R|@Oupk8F$h*T9DUH(E1~(xG`Z?-;l@PnJMh2PZ;r17;vSp{RWvJ&%HbOGvXTbte z*w7qbS^|n0)EUR&Z~;C+wbiDlZ7HzvquJ)iOd9H8f15Jb#H1UiDgm`LMSDi zc&F#PAk_zXBiK1l665wPN_Ce_){vpNw$A!Iy8eU9#G{TBC!SaIUDM0CP}T3q8DU_I%gO z72@nMRf#KOEI0Q@aacNh2^VP+EhHVihqPiJgr4X?YBWeqAHA%pY(>tav zNc0#3VO0SCD(<;P{mX$hR5hjoM%m#7iP%eb%W6xlql9mC)q9Fcu32MUi*^l1cR$xnJMpdR*e|v|s-Bd{a{ptS~LY)5(O#i}mx~_k0{%2yO`L7$}AD!+;7dl~n;zNUU z-mJ%o+xx?J>AbZlcZv|{XcNaixZw{W`KjWfk4@2K=IM$Ihx1XP1=gjaFWBjri1$v! zg=BqErDZfA68I62g~32jEdd>_0vTZ)Tl3-1kc zh!NN%<(FhS!I}mW5`%TlI=Wv<1pgG^Ul{4%SsDG+&=3DV#lU|zzhFALU#bHC6yRT2i2nfmC#n_E z{lYc;;aU;hFFgSN7;QQhmS5aCf2$R#T4S-md(BsD=&KV^z*++Z0;tw6-|(sl@P0!T z++-Eo_#BNR3_0Pwj)B{fTN;l&-%?$<_JwT++PJ-mTgu1wg{vUp)>qRrabm#-qPt~w z=l*=btqZFJSog^VR?3IKOy{P>o#i9GD5S1i*3&ar;*vAZ+T4>*C@A=UhgHl4SN>ZH%Zq5zWuN%)&^xI9DOEMI5*;B%<0X2mRX}wr!?~~_n zmmgs3=-vS9nI>KmqFmNQ&UKAl&3ppz2d`X1h}m^B)M*n9Q-v%jcvD&YX+TG^%Z2Kr z;E2uOx>LN}@sx&mVz%zGQc2e?-1%iVOZ^i-_0iQq9dkFqKrg|FKEx6u6Q^|j(E|QB z()u~39_Y#f6yHoBwQDmj@=zi5cUoFia++M*q*ERWYebaGCvgSc@yq40GZ%hddU&Dk zpi*gSHALsfNY2w2KAu$UMiLfl5fb?*KjG0^odEls@C!$(Wrz`PndSDsj|J0@lF-<; zvYh`IzZYLKNR1r zP)@sxsbH=WhGNc?Cl^mgG31u3AzE}ot?#xj!^veb0&>3bNro4L-5JtG8(C%?gVHek z1PsKzO@xuV9K2!kYs*HXPwvlS87Lg02o%6NiItj1g$Sq5sA!8Gi~gMsXNTGF3bF%= zvJiIy1oLL;a8(TB`N1N^BJ+>-AaZx+s0 zryitU%Uq=z_AI)#T`h}k0+;B~Xe!%!X;P}g%WF{|!Y$OKXehPCcX4|gGpkKK`MHrr zO=XE9ER1AH2<3L$ni1Zl7tlXbvrn^D!a-ndC-a)E`!Hu$cGJn=w_#!ixY4|?)Y%=% zq3N{1`pbYBLmCcFI+C06FYYw>4(Y)GFo6d`Gyn?dV@|j&_i6{WPoV z0$F)TC!N3aoXsULFIOb=iCP>ZV{9cdevo-eg)U42&Ka;Q67zc=WB(59USR{;8tgC* z`b|}RzG-xU{X>%oq-+nh*hYhZHEL&Qta2oI(SG<&IjZu4F1cK%|B>vED>j+s8Nacd zd?z!~_)qK#hQPr~XiB-Jq}jEIaCxP#ji~)p=OB2ErM$2D4?kL({E!^bKk?q;nDF<6 zu_X74!61BgD4p*n)bHTE_AjPowk@Tooy0)A!XQT}CZD~@f}k?t=gDSYhjn+lu)JS> zdu>{WboZE7`*GZuKt6G)P}a#br>1(~KCn_lm<1p1=)7|=4Q8|umBgYHKT@WJk*wMCm*{{4KJ z0x&uV2d@p8ms3tk6W(4c*+ttlW&LkJa*bm_5y*TVu-b9Ze$1$%49%5f=N5^UWg$CQ zjNdOY@TZ1rS%^g4j$vt%m{U2VA8c&fyTXns<1W$dx?3xg$qvLQzh>9nYMx!fJ&PU^ zOh>{1O5}|#jDdik!1;=a@wr<@@mEntRMH zO&JA<{Kf%i?sw4p8et#)|O@nP5Js8O~3P|i9JG--cdrZ~H z7pB+HFg^r4Z;;odO>sF|xyqkqMQ$=a;#0;Sw0{2XcId+-{eO5werp%?4^MG?st=27 z{69mfhT&h?2}%Fky7C{V;rv;;lRs?a{}H5rhEfgvZ;QWwRdXx-UrTxaMQHr*=GK4P zQq4zN!9N<6^wb~wR%+Id97jer&EKPR{#drx-?q1OjLbBWx(;@xF6tk#1Rp2<>*JUI zHECo_4fPF0t&FTWIcfL=_yx89QfP3rGWg9u|Kpf|wZ6QegM+D+vHfo~gTD=`a|>9Smti40R0*?YKXFXygp-tsU+34L?rC#P+vu!#@J>A9N@Ge_5)T@~jD;`b&2* zHo462PqDxBHvSQ=?vIvgSXk-*r&2@z_cg6QO5L5NNSY(@q5HgIpac;6mTlzeAQTBB zaDI2Y$aFz)yClNxi4Ad?@cT}}1(BT0IOnw!rT4W?#Y{X8Pt1P_-MmUswzMw%%!sFk z!*&W%e8nPG(&0Xhm4P$PY0q%)l=H->nuE|k86@I9?7p@=7$lv?Vo}Z=P&yswXbvQu zO@5{TlGAdo@GFwb7_?jo@rD0lF0tgsB7La4}Eh2-tX9g zPUuOX!w~J?Z{TdHaF~^hqNt;XRubq4R-g|CWRV_Tp7%t=S80}_l}{Tg4yaEx?*lV^ z6d`vDHGX?;TLhEc7oJ?t-FH_{WLocM9!_HXzow z21ugIj9s@<%aF_itl5e+I2{ETzm0d`MSSK%)cKUrNLYar4E)^l*2Zk7O;W=8iAk3u z0Moy+Vk*6N!OQT9Q^?cPoI$uT-$UlZd>9X#X{)XLjLEM(6`yV@7AfMZ!8SOHea}4f z8>^ggMGU$=*B1xNoOJ|0b8CVXi#H7--KS?^7dGJG3@n!a5@nDg3bp}$1MHWocfxAU0s|{04Qy`| z3}hCSZ}|E4TG+rbc*$l3|E#BR<}ekF{21kN^C&{k*RgF=gS)USEv#!n)U$bdbx@J9 zFdMz0)F1G;siFn~UGfF0V;N4Egr@`kq#NxC8~HUcHc&K6GV0RnqU^ghvP!)6tLu$x ziDZnQ7f8*`TOFB=YzoVkY&_&yyy5M;7+nm6%t5s4crHh(o=pU@`FY~ZQD$~fM!m2cz3vASj)JGO`xyq-#z)}l%Wg|p4!e07H9PaOV{?=ZSe zZ)daOon8hbJP#>e!aSTjX^2ZD<2+MJ&~GUaff|B^xGHSzeX;mSTYtm_OobfH#IF?L z8l3Tby5B-114226@c*#))=_n(%i1sQ1c%@n+}+(>g1fuByK8WFcXtgQ+}(p)a0!Hu z&fe$j>~lN)^&PkG7&~Y5KQLgi)?91WoG(?s_o;d`j3JK@mT##)ry+l`fg_vFj~+Ie zBcs|@OHdfTrq6vkT(bsU!rPk?KDeG{KdoC$-;?u}>`7K5^uuPd+m*ZP#DP8m5}B*g zoO*-5XzUpo;S0AJOP1`nPFQH`F>a55yrrJ85VWZszXk%F&4PC#pLkd5jT;k1%T|cS z-}*l2iZn-Z!9HY6e5ssqOnf6^wOZ0vX(Cir@F4X@(4hG$=&8wN!AhuJ9p>zU&D&2x z(rJdWjk%4s5l@m0t817_dbVZXO?9~98q4krWt%1rDr2e#!1xFhTi)jUwJYXG(#RRZ zu+&tA5kna8G)e_%+)7m`KN#fjF@DHZVUoIvsD|=&8ge4FLaFQM6}z!`{qSv0^hD14 z%%p0ijfJgBJbqJ~%}Mt&qR`R|9`P?z2B#+E&Pyja<@BKPe8(EW9c68_Rff6&;>4*r z_H$dI6Ko(kZH|FeL6Axt$QiXU^WW0Oxz|4RuSVW1FGEaBhwk?r7wIPe3}@gM&JOA# zBm0<&^GYI=ZzD}}D64fNOHeAhRA8Wu22gBoZsWsR50>(%P`^1Am?eS$#1J_ni!n3D z3#77W+66E<%8Wqk?eK_1V9da_36D3*&)EW>iA)z@PS0zw_cz3@vgvK-H|qyI$Z+Z3 zu?fN^N3r7n;)`%ZwJ<;I7xMuMmVE^+RbGR(&3PU*eYrx@etIc#5$yx@VcQ$L3Ube(4cQ z&I>)3Ea!9?rLp0gyGbTd|S6>>uz<5i13(*b`@R3IIQ9lGq%6 z6tIAwxA`)ld?wn#K*{iF#(Upq&1>;&l4xLF9>|%9(6Cvi7vZ8BfBvIQ5!XC1_A1Ck z2W_=C5@VbIDH=7W@Ttz4Zv%y~h=Qd<3}d3xdk@ZCytd?`kGYpilrw1PVHjK#pQNhU zL~O0u*mX+KG$0pJ+h~l%z?zp-dEXJZn#GB9=NoB>iW5Z;$Dz26*8!@dQ8ukV7(O-FBxmCL-lHyf>BqNTUS!IbLzCMKl76+Rl<5^FVWK?I4LQ z%>*rGn-{KElZhn75~$aGt_x07BpGW48lP}nZh`Rhl2lKl$-Xud$@nHcS%|1g6>z|2 z2kX@2qLS(GY~Cqn+P2+Gl=6DXAjx1E=aPQvSRiZ4MKZ^1 z*QGGy@#kGT)|NY+T3C}wA2B8!Acg4sN@c{95@l}q?2umC!EmF36$mXMLD@5ibs%;Q znD-w_Gyoj{O*j=wpC~Vz8pVCu8yD<#c>VXY11jN}pfV9!J;ExMdFQ}ozbiJj$UtJ*)#dPvk_9)%`f=VbkkxcSghgze5cABR&&&?`WdpjI)?Vb z36rA>n{o|b5T}WIgTwUXCJLb8KA4E*whE67#8mEAUBp|a4g0CF?IOQDoB2q0E0Y@( zDfk&Gz^sB3zF|cVB?BZP&{MU+o}6`6ss*Ii#lQw@p}6b3YCYMUt77x!tb|*2*W>*9K0W4Qg5y zoz=LR89v_m4(58)LBV$`&VDNwy z|K0ldyBPkT*}(r0mHz_MP5wEM>Ce`E9z%=ZkwV5I{tdrB*Zt z0a%ztS{TzKFmyE%sWqVIJC4pF0+eB=R#7!SK}4ZToHZ`zyDzR>xF>byNi6c>lUVQNONuTC-i$mZF?>q(j%wm~jGRdCTzFV-fB@V8vnc^=$U+cABk+tj{VKmb1T5O_`95@f?(HDgeU@6B6yNS3W!cTu zT0IY~j%u6d-!3LPHreTrzrbNy6A(m?Sq_-(b5)rb>BKAFH_b4+y>{OcN{znId^^}I zlWeUY6~J{6Rr^?sv-l!^lJi7E9OC=DIba-fFG}P^F zx6mc$Dx_xF{YFlq$(^oS-V`5+r3Q$?P9;7eji9!xp;Rj0?7=!|R1jvowUSs6B`xdx z?t^%WxURUNbz0~{`z%wVrl4UCkLAZ`&84MU?WCD!m%(uZGtpRfg{@PukCqy}O`cn& zntS^&Gl3RUf$VMplnc6aR~MSaC-%7q95OR;yoylQfLx}li+QpMHl;#7zHgfqERcpv zE9M(7kWuY;8i2E!w#zNvkt574knDc4!!`e?yQ~q*&xkyVC4iKpwU{x|dYLmqG%Zv{ zo#vIB81+pZ`sAA%Tu8HA3*3WH%tnCNLY%GYyU1c9o29Lk43`|9K$^c-gvD|PX z0%^OgN#xdK6Djt1ZSed1po#C`0sb><%Ul&hG4~-?lPpa zmW|7|Ih8=UNJm3S9Df4h_lJ$Z?&~bfKXVFaTm%u)8`ZFrzK?6;OmJwcf|>0M=37fM zY~-hLvAY&{7{8tuJLirKiECi6-WYTgJw^sr5L?pE5Fow_xGZPgLphYA$za9#NXnxv zjER#K`VYJqw*PnSZ?z(_d~YOm)DGNe_ZaESDxw%`qy8ct*l z$qe2n!dY_5s}4kd^0YHNJQv}f7wapg#C0<=5DzCq5@%&OT!0=as;_*Q)ZVB%3Vn|B zsAvnOL27u9at-4^L&lXYjfACsz@a5(CDFWN?unmzrClUL9DmKr762ys#tu=)IPx;k}wMxK_9)%K3|-{S3j&+X~^_mB`vJsXtcV_LN zB5j%~>-nU#v=t@}Zf-91>Jvf`hVJ~*VjH%1ADiIcBRtv50kgdX&R=IgxZb$lL_J?e zbf{=6M*BCUkwj2{+0S*+JC&*&yel^z(c0`oa7;RVM+g=cZCQSfhbB2M?+NfA;75k%JF+p&bh?9d zMHQNcCfR8mp|3a2ML!^#N@%I|O(PB=l3kunt@XOMWC0>wdv9Ae#-2Prk4D1|(R!#% zc)dhf8u_VXqYeZkO}+`#h8=z3Y0ntz@+MncfveX9679iy3&xL0vop47!H}1)XnWMO z^voyOUEl?z@_4^YWO}(wPMG;VWiz3c@?{L!++4IlV2pPk@uJPfR zQVH#^CMT(+CsKP-7?KjiU?EdWY1gqJ({=eAvs}buD33Bn3ZI_^>3cQb6;z_ft&bN~ zUYRB%ExDVlgHCc+WU_3wPx!a@Hx~&=^eYCsbwBH8$axFqpZNuR%O#v{*Df}q5?%;^ z(G+3O$7++-8k!|C_suYW=TIB#{_NG!WUK+4!(WLaMp^Da#DX1RpyCM0jOAx=Gx~9u z@R0U%QB17dR^Wg@G>qLRJ7`&*1O8RKlXc6Z59A-LgzpYdV5NHTF!&0vYN2D+x|6{6 zOdN0U%Hlz#4a1IVMw>x_)EIQXTmaOkRP$c|gyao2cH8U+>%25sYKL1sWy%<07s)o( zL`{5dwxG;?qiX)iNR|*yUiSiYuy#Yo6kW1-E&qd%oDX-Y)1~jLkj5m~q4b3aB%6z3 z9Ax1mU3ADIAq7ui`{sm}COu{T+)%wN4|N)sZX}KLM=elFRLOqUT3NxMp!nll&Lw1d zF(o~l&aN249W{i7ps3rEs<~*wR3tguQ}U!G2LkbtBi3QFu1puo;exT+B>Eas2~AK} znG%)kxv6kfRgOjChmUkn7>9G(UB4uwG#_utX#FDg-0cOS07xc@x}NUGQmo(Uc zO}WgBNf6t-VO87DsTL{`7M+N6-oZ%^90lRdRxZ2aZTyAI;7ZFeBF>#ihma+r@D?|% zPY2KNE3DQAmF_``h2$m7kPAJI!BqKW$QVaKBc5A@u-2;gqPpY}iah7x_Iem8TOGsv zM}~1z7qd#w#^!GKoO;K{QAbh@aREog3mF^K6$|h^ zp!pJdc#|N9`f2Ko0mdedWsaRsii}Sl_ENn81K#*Jgegbq0kG-8Lq4&@qAjefDCf(6 z3_fMB18@W#%X+UJ2o0HpBTU2~_yR=>&_($k;dd(zrk@gkU!iB1`7azL$;$S>q-U7v zr$pdafI7^-CD4D7=7;sWxzjHQb(ntO0KXd4VfqV2Tdd!$oqis`{{eMse#g;B^HKn{EUF2LirbKEpOe00zZC4%{L24exWpV&Z-2>>W9aMRcZWnJ-1yo(oGt$H`1#yE+8G zkj~owri;a_j0^YF1_o1g7w*5&X=?R`m4RGRQajUsd-`!{@_yp^tADSx_Ql?_v07BR z`I5>ctWCi)&bhGn?iQM_aDJ8-*FEDQ6774L&BWynrpXJNs7x8t2nG_#xR)^)Xum{B zb@qHj*u@7*iuw#gS{X}MSe+iOzOcfa^oL|(bTBL92Fio{AtrFWx$>ZbZUYx9X|dy_ za>&b+=yFm%JeExiCYp}zcbH;(r=!>MnTrE1*=uhoksL3(%u{-E7hxB7f(RFHyZSC4 z`{KgAUV2eqKEsL@I@(`Y^-JVW>on_^w%ogX@w2CnqW;Ft+Lk=VeVU6MJ>N5&p%N^2 zEDtl!CeF@X;9$WPtZ*Kx9dR6ve!mjNVbT*)v4n48+2rsvYnw2t92(Z6$3pk?Efp-D z%}ts|w!-`=P275OBcF00+hwL-GAUXtE&9eihz_6lq@n*U&29XSd#N5a&#>|3?Ll-n zt`Y*E;alf;*3|H(JRNY>4&`qr(LPG?@JrjQ{mCC~vkOw1W7%PJi6u3ZO=U8b@exx? z#^B{snb|H@roE3@V5}xm0g+jWhd1VAlj*=8D0N)2fD3N0q@US zcM~V1OzxH_AAzR%eRb@Mm_fSepmg!(Y>AeIe2rs!nmO0*dv}+84m%IZD)>BJ*|-F3 z9pwWld3AaHmagttxBan1oZYB+0*d+M5FG{C2S0n}B9UeK7$sDz(_loMrv_A3uaSJ|Dgo|a}*5Uvql4QjnmOcQZwOQY;z(HJDNTN zT8y-5xlP~9O+Hs+l~r`)V<;R^)ltf1;bvv41)#|ANNN@b2g~-M3e{*gKj#}HA);kH zBiCgof3BSFca5jTJ$nvx2UJuVCyrmjU5L})nymWRan>TdF2o-9rVzWI zWJ69F{$N2p>{wr;BY$FR&aBYQiMAQ8=uJWDGc0trRqou4EOPH%9ba2;gmEz2T24Zy zsyoDRJcH4V+y25?ris6kG7?uhx%HTI@lvSfy%=31m$8|?5RVwC5yJ5!ldbW7DyTVKV)jnd)b0_!xVK1U*#9i{UHZd<~Ui z3NulBRAB`-;XE}sp0 zKMJ7jGT|0`#^rI>=P0nTy}*ajTiGN=^yab`1~LD@`qEte&{CWp zg9>3ygabgBNV?-qsFB8jxH5><5_z|H@m_3m3_anNwkbF>r1vJXQGr`ICY>) znl0mwR+a@4c-uyA`&H~Y7tIyh=@-w)a7{brjHvV!@9ei2_;tq{*e}H9%%V#u7SVa4 z$p(ub55-4~11rM!zkLJROG9yeUBCcRz=7R`H7hAg6MFyaQapb7$EBD7)h0HPG7?AI z4PsXlG~9lPCVL|H%?-SH)f!mG5Y(r4=j-lG+en$=)pozGyL+9+DkTq#c1OGVDq|PT z*%>NsrFAOJ`^eOtt_>}kE^d#TyR=;%=kUERZT-6|{hszN2 zu9Q&!Fkt#!*_Goxx#aIIu`GWQ;Cw%Ef7kcFUVYEk^tPb|+f|uMh!86e6DY#+IS;@Qr-p%!!rdqB}kt1Bdbmh!fIa`<~aeC-yeFaz8%;Q-e#C;DaFphQ&<|q;0DoZP*mL zdfcp>JohAL>s?X=ybHbqd+%bcG^Lwid$eXMos6f`S<0ZMIxP0c<9PCTfg8)Rptp$Vq|Qu&O^7c z8zm<6V%-jEV%oud_|;dNZL^uhtg5ArSws7)LL>qKyXp9rm9e%Z$bxh^@*1FNS@IaF zfb!5(_3{`-M-m)f)1<&=v|7N5AlE|EtHL9;i86(^E*r+#OMWj6LT`O z+l49zI$c0o{%Ym?DBPf^cU9vlf2*MwiUU;eZKcT@*YWRsQGNz}&j6jTYCToNdaQ3PjPuTg9&@ zgRQqIFOzck@A#CbtMjuJVzLB~lToJ$j0&yZCoyGZIHu8spxD5k4eIS_-lX2p8?6tJ zX9V-`c%xICLg*|h%_zHM!~j^Ay+dk)1xlpSTV0N6ec|{dqz`&Kjf&#e9fGLuxxrKI!R0a z3F~1SKVVlj4di&4_=JMM|40z1Bme>T#9yYbZRlcs!h0~g3!DPaqW|GTE?$8v3Xdp> z{$w=L)RJ8))u%o>P3yhq<$9bKZJihf}kX9=<%WA{$BMIW^(=R0WmaUBD_p%y+FOKJjNd#eYI(h zUvq_2ga??5Fz1;xgXetL)x?x6W|K$+|Su< zr}5qvmUM>ne0VfO11Ky+$KoRZEz*oB2%3)p(yOiH^dx!=i1@lM6TtP?q0%)s%x_Na zQ1s!*{-MMCK59xD;wi$z_2@)EfkZ1=1XhCTcr^MJ?>{t1+LmM7@rJqrq25ujNP~wp zinf@D4s#ym*cHNUrApB0D%(;A5i6DZ4*2W#@XTtSMnT|VlcUzh&O%#|n-R4*bBcbW z&+Q&^i9mkfjIMRds**!*@Kts%f%>c)rJ$i@7+Q=R_x7o6#$@HQeq>?{&fJ+Ot(JJ8 zFVuqwi7R$2)EnePbaf`j)4hpfI`pe@=oY47&+-!G=@RUv`R?e!R8;fCdDAt8HVlOl zI0h%!9womv#(A>zkd$P40eb<}VUCxN(gi!dZhY&)HW6Xo%?B#5aGWOhm0cv{_d3K4 z^2g5DOzjw|UC;>E?kprbR(26fVlr?r2i5DQa`C=fp``k@?hJCx>?-Mz=m_*s5QMeW zLEDY~?*L7SImfe6HVcPemlXOos7z2^RU&B;H?yrBW_6nM_fqvDwdnnEx!peWa8$mD zO9Yh2fs=Rv+cK&jUa-&It)kszW--PO0}S8pOrD`@^n3P!cy2CmUmkjSPw7f~(kN-6 zML=Od%A(6=oWOu++QPGu%Btj@5@~Y|4wH6v_{Cn3nG`uP3)j(2wNZ0c%%nIZL`^j; z=woBCuR&wwt!ki5IZgZZ0}Gm<~Z*?gpd!Q21?UIHw{meS$c0%>BrMMs{^0w8EZH2wZXTy(--nDK-od;f+INaE_AXML zg}l6hG8tm#$t*8D=ONrVK7Bnm?cvhP`)Y67PDWaK?|5a+t8K*_@73#KD?7>BbxGxJN?G}Yb#=+nHOcheLGNnzr&xcz#R(0bdhXJ?vxI2oRj; z&%3+dZkbvQzUaQd%tTY7dA;?J(*W9u-3?Jeoa%a=R3)PmfAISS+fM42~s!10`1 z;&)eA)<4d3T~Pme1vTpreN2BuOunyde+T#%4DfINMgAGMKMe2>Waa0Ob@#|B$G`n@b$uxp9u61B=qx^S z?Zox)%u$mv^a&W@aYELD6AGpCTcX*6ZmlCm z4bS9sQPcK#)GsMJNVb(nY#<&q1@AEiMS;O^+0>sITx;Cy#1bmf+bGJX3ZbU>CG<`O zXyl8j$zngHFO<`mx@}cP+ktEHbv-GtmqZ+HS`(GM$i(yV@%KwA;rWXqs**YK%Wm$+ zPuYJeo{At}fIl-bbuikVTeVqRg}%u!UgN10W&Zz*GP zaK}Zk0XX_wgBx%vP<&a$o6>3#?=u@L_-SPhPNIw$uRZ5ee)gz_)4FHNC}Q_(gN6JT z&yu4HzOn5>LB8H_mCsc+e4>Ll!!YqBeG zPt2!MjSUw1--M4%VKHzVq@xHsU6Y=WJX0~b87fHF2_HBUIYwe{C%=JuN4q;iJxKSO zVcK9rcgXMNy7KO`=2bG|FwI=SS{1&(>?gel{7q z2qPNxIt=C>F@u@{7aNKEDK4kC!4ERya7+7;bjLgT12tbdDTbu5kO77;Rh_WBVdO$Lr|z zMZ1^%>l~FbpnEo{_0;dB^&Q(3_CQS}K$@@zfek)u7Z|!PX`k^lk6RjF#$U z;FN&6Ka`aaLb3Cku4UGtGR!DF3e0MZYlPcPZ8urSrFvaTHlgXd(ZO3n59Zx}P+SUs ztAoxdKDRj)1uXT(L;_45Vb-L5v%M0N9m?*Cz~>_60TX#2zM`T>obdy2_O@Npu^;6K zei2@F789RS2xq>UE2+a?4t|dzxsNP{GqQZ@Ir%<*JvC3*WdY6y_sP4C_G!pMZp&*T0I&i6h-i+?!?H*O=P3jx^iwB%Y(~!q zzOWf{gPAdijO`kY?qEg>y3}#&Cgt;Sn#S$V2CePuzjZK@T#S{a-3UL`bhfB=buEX` zw8rXvdpMoDT{%3Sux@-=FYmt&zIj-=sYtFgxjlY(H7xaTckDo@TiSLY3!@<2YM_p$l9E*tQeqwPYrhA*b9l8qeH?l0xIavBX=y3O!Q&_Nc~ck$hz(V-Mi%oMN zxL_Sqpp?}(F$we*`QzMr?hS;4Qz3fTUneCGSg_IH4P!2tgNdHx6nea}Yz4)8A+;6KH6 z=;@jMrF3#h*No{g>!pPWI`@LYUJy^frWd~!kz?QlLh^ojB>SqqKA6ij%5&%b9 z#Cv%m@sh|~xtnhTxlHprr0v;kf0y3N50*1H)WhOxo4fT)Y`8VdQI{qimNN`dzUX- zIivi2uAdOaW3YN$Jx-cZ=u%7KQ@$IgRhv-kpBDI{D*G*x8F(YS{nX8&zhKnu7#;SpOvwN;p^vAcs+eecr2{{ z`UwB})c^k8e@GR7&Lo*$9pq{LVRcW3_v%Q@M*ribe5&TIqps}wGM+%laY1Oe9;&`S z6qbQZQHw-k8XMGCLp3-cc4SQP4tuV_!Ej9_@jcf`D=kDhudM0d+vv!JwQl>&Yf3WUK`Hi9Zj%w z1f_*>pR;ej#AmwgUpRY*7he*?2Nu<>x^^~3nvCsCKAJEx(KVF0Nx{lxBzJieaAQ7S z+mj50Ft?*$ZA75E3AP=cXl~*Hordwribb9Kc_Y-5F(-61?0(A}6SQFYP)C*tbG+cK zR~=?z88K92Cf>zV09z+LTIJ6zbD%H)XLQ_z#Dqnx_Uu4zna}O4y~(+4tNSgSNDmzQ zt=ly)3(baeW-0arKmSJa7ya0UaP4L@ZkLPl9o4~(x76<Y5p&AOoHP zDb@s=!}Hlv8>+qO>2h; zd6v&>U&t0hnNDb7tKEkp%`;R8cb=K&w#4z!_5xlo9syx%!XC7{y=8T1?7cx_T_G$` zS^;k)}oG}BA8u-8BF=s zE()%p#ue+c1sZ5-gNn5ajzI@3qlwKvqCnhOqIFa!8(2eNkl)@VkhO^~(g|0(JweC7&|St_$>1sK@zipw%jOtHm}ql3XdNj)g0XlPd$4R~TF(cY93W zw_bd(B_GRm=9yq{*Ip)?dyZm?YSxT%%X>oBQiKd9ge4wg)qT?zmMM3Ag(y$2W<2xs zoL%L2M^OsQ$|r8=k#}4Yma$Mw2YBP_64)Uv6Bkk#-48afU(xlJMZw&? zz8RhpFTOxoz~Vb2)_i!QR*fbE)n8iR?t+f zwmy{R0&TtT?h4nH#52_OS?kcs zuBq8mN-eI=)O9ATa83#{6(db8?J<>KO882jX5vLWEh~v`_TvOea`dTg@Rlw%r^jm_ zJ>^ApY}L-I){g7s0}jq69Mz>P9Ncj@4#70AKRB~DPDUa3RWyQTI_^>J=UUJ71CW-1THqDINGJPMCR3FhYk<8*AD!9`nCovvQtCEBZ6 zx?AD*JE)CWYXGxGOOS)aZn=BirDL zp`@nr;KrWIT+zdE~N zdS823LtiF0Z$zT8a9jkuH*&PRWta$P3;!SYT(Gv&?;ItGk-#9Mvt~3@-+Y&uBmfy3cz!u)KP z4jb_a`%AMkOY?C!yMIy|aW{~S4=oz)8?ejOtggJlwawc*on^}mEGP(=?i+kTE>{drREKMhV3dslYAQe4AB8Q%`&s##{nH+-5=EUyI_#DW}pXO_}X zifN6e+wjTkYUCO8o}bGJ;$xyQ=@$UU(X5P>9!%~HJ`U1F!uSP;ycM;l2VNpGOBg1> z>X%&3$<0P~|6+$pBwD}RXP-$XV@!iM5W|TGFfd_GV1YrPHbuPK09xg#6K#V5B$Mi~ zY=nx^J#w5$3@kpvWIqPrK)5#uM z!WRx1xMSDLoSozcyK5I>A)&0bqI2`IH|@1jqLNZ|2@~;IXcPy91Te-;_63rc&Tk!7 z(+r4erKAip^X^*YGV?=sCs=5Y&89P^6%u-7xBGp!$%4{(`atU*=gI7(1_=j~9i>lP z{V^aK0uK{Lvy8r)b1?;L6XcaI_?PPivVznYsGPSpbnx>*bj7icuy78D8S!-}@_2(= zGZFdarFi_>eg+V>8DTr;YZl|JR45;NlIA5sYAC_e-)1|RE@(pyn@ z;UK_X?&(nCLWM~Qn*+doOYZ0V3YcX4f;E%QG*2HrWvJ-h8t~*3gIm2Tjb9~bUdseC zGGZQFF~q{T9OKMIlMS;?JKUDJw9Mv_@BA$6434`~Zfl`0va`r*y)wYU+t{hUreYXu zZ_yHWBQOg-^(hKPUm{t*JhzvwakXdOp&X~ocw|rmdt@+?#<<*nK)O;_V$t+=y=Cgd z{Jif>!WHXE(i@znMY1wi!6&CT*mdbelo%XNoV0_Bnmx{|t|X3{TsoE_<^h#&-l!l< z5&E$~4mjSdVjMv=8mXzjL-D#$6%c`)3{#mHfAWjY z_Rt`XCKqPKDq|FsV`Z!5=KPid`I%Hq%(BvjsxGs@m5#&GQmK10X^{e9OKeMQirY=V zlFq!&-W$PZ9F4pBIfjTM<#H54kEVt?H|LJ*gq4MIt=)15c4c?w^F_zgN=**udY4pk zmUFeGn&rH$icl_Fy2}d94oo%Xx%>LLin95y81Ckc3z28*6SvFrw}Ka^uHYZG(dYCGt}y7iie11hbGZAJC(YXV zmY)#S!tYeloMWNSotd>mox9ypw1pZ@*!yV;cFT2)Q}n~uito+T)GtD|&AWLD?$wwz zFZ{NThxQ}L)`c3z;mA8P$uqL#pUj5N<(@F?SiA7PnH%-X+ZM9nzUMTeNJFlY)BNB( zsbko-O>y9uK!Va0;E`}gx-Qm!Db}xCJMby#^>~0MN_LVCr+9E6!lCMX^RN}6@cPmwY(C@DbdJ^id!rw1#Ju@(4wv_IxeX{E8 z@LYN0MU*0HWUK(j!^pJ0zXQHwOTEv)X=xB~U5{{qoz9GCl!}Y9>wow;Dx;kuC7n{e zu}RXOBB7&t!*)0YGs0m&lK7rk+nwY5Q_2Oz#{Bxa)iDlE;GR-W;e0B3JEZZ9TVL|@ zOdKaVRW!P-baG1h2WEm*$uAb8oBEvyxVW=*!UQ8Xf&tN}Xxg}usk#DCMc1m_R+MVk z%+so`V`@k9A3`;jM+HZ1PQ8L6=` zEj=s<4p^MT#N$0_AH%Q%LK&GrUjrMt24vBu!p58bHFgywA z;o?z?fgrL3=Gy-2Qwe3riMuU(p5Z){9SLEng9j_b6sJEGs7dJ7Ppi(DJ969jl*14cyu(L5GcoR|ba z(wpEU4lo7%&{-{d-@#XfJVP)8!0xbRhNnPg@hkIm5U)^|poqO&+i1_~wRLWd7S9^CX%cD)PU5l#2l zj+mW6`0yoiC?5@)-rW^)^`n-s&RURU)2FF-#$$qvOF^A;JC?%Kl{6;WM{g8}j~ADu z*W&x?`X~#A^C3Bn4KFMlSxh(@W|%ocZP+0TXF}kf_}XjwY&BJ~ zJ`e&c1233931_oK9E0p;mkGGJrn&3Nm5X(2VO;hyhHdbD5z}y8{2eQ{2XeURo) z%s)Vxs+UWPQL3dE7Z}j{#9G&_WDJeSALxuvz(Xo#e<7eM3;n;3YoG0 ziL!D>-tFCnF4-{u1`dfLBf&lrFBR2-P=0VZKePW^nyh0!lW@h>`UPli5@l)8GUd!& z`nCuxlK1K1$2!VRaHj(c6!uZ2?W}rqMD!_oQhIM?Mih~ta94x@Ln8zi8&f}Ap%0_e ze=07I%Fsow({15@U#wkOeVU+#+zFHFYXO$tEq`6E8kC?sU`QHWI693Za)C)Ruko2S zs)kp9CYOdloSOgB*=X~%KA~)?lxq^o;{s)kiT>{3XtSE;LB5u1R=UPc0(L^&#S-1Y zmy{3b2hC!pJS0;Ti%0U3ri^NWJO&@G_oFY?avDlsVOF;gfWj* zD9cuI#~7O#*xcst`?d%1ZnCk|6=o>KXA8lOxrh`bi>vuZ4lX1kBNs&WTQOnP7wU-k zJY|lRRI_W|>sIj*FB4ym7GYna+$-yz@(#6pg%su*F1G8LRiT6V1y zdTgovf*F~<%nxrbrM!pN+>FR0rs!_Aiaru0%Ty-0WbHglr;keMgv2m4DeBB+=V$(| zfh3oa%u&|3#Q#WIHVyIyMs!fzUU{>tEqExj$3mhAD>9aYR@H!tcvc{IS8#u@PJM;I zaR9B{O$W7v>colqOF~W8YIy(2W$&)`zPrp_a?By{JD>|-q+5FRnL)xw3xm@Q5&2S| z-Cm;wYrk!XM-Lb0<7|lZw?_~zpDr4SDRjs1B&pMjHxOR^T(hLOar7guqGy@b{)dMU#l&-N4tC7+b3#q4g)sb# zc>@o13GCE{~QUTWjnW<&Gmk>J}CSHSF4*-!v0}rGwkh87LbtA(H!SQR^i^WXFP(9{0#Hu}%{ zUcbdF{;wPQ=Zu+-h5o-%7=K*QI?maK2nN+7SzWp~4$VZXB|w)GgrR4Y%4iRH^lbr0 zDxqlHQH!z)kRrao3fHa2t@9i4wN+`i2Hg4Hd=WL(2xI5^q^ElzRViRcVyv8af{2;i zsg8}+#NC^}NFN;DX1EN{cv0DY@_U09+LMmR=Zd$+xDiCS#S9L^-A2gHY_*?b z3WxYn<0QVlVK@0!4sg}xtF$XjH2eR?_8bPv;Z*)T(&CeVKWq2!bh{9ao ztP*kaPD$yRR)a#l*!#d0;UcBmc#mkM>sf0~KUzi;Rue42?Zx#=!>I78p{IK?)LBpN zlGG-*sz6kQN90HZ#$XeCKqO^UC<2sYX=C!;gC941!|l3s^-vm# zaNE4(zzRj@U=G*A^-v3b<%{o={W*l83irMlZ*?}LD`~$alVL0G+$=N%?ft%Zqo+)Y z*u1vJlEk4y3;bv!5!4megiSAtgkkZie4yFXYMi-}1V(OS-HQGJcJG{|+?YaA1%3Rg zf_mZ3J*)8OOVWtbuGbWXMDxi zE8Jsufx*-t0#y8FJ>G^wJ7mpO0oSz_B3I}rpfc`z-KR2^Ji?aJF`T@fHHG5-^5E5(c@!8QxpybG zH`h(QNmO^OYW{Y-M5Zx_!VzBCUhaB+GPdaGW0H%O?EzdvEH@((doZsb^(eYLBZ)ng z$u)^Q6^P&tks~Xc-dP{oM$POdI>|+Sw#}@8+I}tME=UUqH*ddIMV;2Hi9T`S7 zyOTbqJW*pfzsX=;99Z&+@Enx`nph1) z70(`cW>}=6Q5bhk!rjAo@XB8RqaA=|NU8DM@tLEf1_~ew7y)>3fB}w7C~W}v;!^7i zRI95X1E#`_YjXNK`{O?_l3MT^NuOYXs~R=Y6hWbUO)Wavqr~VIn;9f80DY@}C@CAi zd;n8sr6W_D~Sw|ga;W~cNiYLZpYy#Fg z$XF0%)nv_uwZ2*#pROJW;5!oYm(hW~*6R7@?P6wP9&q;x(yNQA*?>WTMgF)GD`i=7 zVnsRAjv^3jvFegB5PZcHP}aa&^;0;cW;ZJRsV&fp#^phXA&4SQzsh2Mjss*#GPTQ0 zIg}8Cx7lfG&*ih%_5&evG1G5$*^$)BjSMD z_5+l|a~b_?b;mX$X)H@BdzD1*zc`4#2Lu6dpdy#~{Sy1bWZoaR?f!M){&Cy=a&9|% z+8<10e=dT%^Iq&Z4M0~9JHlqZn?w^^^&H!{&{hnJnKU%pnz9O^bywbH~^3W6n~ON2$XqL zUHzNK+w7IG8G##hOSZ>u8!NMU1d$-v!2q1_jP)zm1IxakormX098);$J8S2wMV8TH zctb(Ip#60+uiB+A{(Z09ZCvaxH*YOhJhHYkC@=baEW9X=^;^*0Fjj@N^<1tGCjz9C zy}+-*3<|qVZEJ|iM~yv{^rH;z-(XaHF8a3ALt^T6RW@{ns5hfGCn>i|qk7gvOJ;QF zB4=K_SwFW+Th$ey7Zz_jGKb9_nUyLp%V5oy%yV+eG;T_l+ysT^(cVF2GzOkmj8~;| zq{6VU0-n$eWE4={75`|xr*~WB#hT)UuyLTqf_l|VX`jXPx9uHno>!rtx}%5N!^dcF zl;1-g2+hxa$z4~gwUdUI_OWHXym5lx$OHqKc@NCy&tM1OM+@V8e)h7-E?pLloNMar zksBBOqDtXIAoi9~S}7`Xugn;Fa(ge!5uk+LCv$JlZu<^BS9`CSsr;W%DXOcX;JUzoD2#B9XfJK z0y0mvmkMX@F7{v{UPIS=7dZO;2s-C*ObqIpl@qOFJRJkLYEcsqmh;F9SIEz{%4>q*xVczyRehrhSLS=01guoI6{Ky*kwVR-c+nKZ zISbH6^*n|k*`(QU#UQsp7hTU2jUu)eMv%5 zo&<>Y8D3ZyPpJ476(Bd3o0?+;Q_alI^{jRfBf1z9e2hIRsks)<$kE%x&%}X`ijW*U zI<)#V5s`RYj4l;x1wOfbkBmdDZOgMW)CuxPKy zwq{!iWnon*25E~R4`v!wra}_e+@3LPS4MNS7h|^Yb)IT+DMZ6&BlQqGW2!0PfJ9~S z{f06o<<>i`=ch2XH+Em-$s334;A0Lyj2#~e4_h2HGdA`Q53Kqe(h3;p1U%sn4xDhL zuW*rK+6pFYco`HTVD1*dN5LB2+V=*^EWFfvFUU;PcN!hkzJ)k;$f?`n`dSoJ9V%8? zndIcrr8tcVI|9KA&>1uZ=&Rh;A(fsk7sW~6~SWIa@17cctR0gF_6MX*OS{T%_q^EwoGInf}V z>)}%e1jo8X1zPWDEvf*6`IdUnImZs;QdF+H{9n*bXfWcF!=kBtlh9#0e}IYz&GX zWD;}SSNW!~w3EtR?8N%-Go5njI=*tj(;Jr@nqTvPaxEYTYd3|9FMurrEMgO`Q>LaK zj8R+~#%i?^gLy+8&E1H~NW!b2P4q5XMXRbS68JIY3bT|JsT6bdf4{YHmk+V*NJ|kn zArg?(W?&4v&_I@jEp~?Sax|4V@*T`!TV2hxgxOSR$m}Kb0Mc^Jc6D-!s_k~qvBXU> z^TuR8k&Phj(0Xr7Ep_05x7|csP4o1cp;V=bP7|kp7XC14$m@a2AAp~96tjc^f^$$K zhzD&kW(8tK*I9E!;Sey_~*$+%~^_ym;}rKiR3fr$n=qeD!dzet5X+T`gC5U7|_eJdIN< zkH<;g9HxEPJ~$pdo<7()sbgbPPN|i!G#y9dT?+EHmE@&ODe>33?sZ*BS)SOsOgA3& zVtP;Yo@SNlJ-2aNd#iz_7N4P4#n)}+H-M>Q8AKJ!QM|5uLBGX8Ov+AqWC=zf^M`%l30D=<3x ze^Hsg2JtZdhDUxuMo0Gp*7;8f|Ne}Q?l)rbSMA|p{B79q=K}sWqci6G3m9Eg;#+9C zoiQcr@g(A16Q@-iKv^T9xUfrO?2z26Zp!{D<{ued@T(z5ZaM%EfCC}9^zWD09|k7> zu*3fW_58f&`=`VI+jaQ#KV*pfk-*A zKc(T#j#bl(CFUrsbL zzcIQY&Wmsw9ynaMNcQ6$Uv7dAY) zl@%F~a5=4EEUlITPT4uq=hHaRupD%}Wc%P+6K5+WrOdlEXfufjwH!fj=Sb{{Mf1fY zU(#6x`zt??+yPt{go6v%iEo}LQ3QsEVLJ9ty7ULP`k>EN%fF2n$21byoD87?#JdN?xmGByLq@g1F`CvPoLm~hP&|qdR79HK-94KK!sjGk=pdpZDf`rE z%)nV3Idb?uoh*OCvVO@Z!rZ=gO)`f@`kHEAVBlZ@VXd#rI~BE6glldA8eIP=eiL`v;n85O-b;Q! zlN$s*3aeJ>)FCT34$mK=1)28Tmi>YbV~t(4<_(w2gVnIWNd&+ggf%J5ybaMyF-Q*o zD(5E7R}Z#PO*Py6zFSj56#xo;wxM$4bbt%a>mb}+4g5nwCq0U{pChe^9AaE5_=7Kf z=rD$J)2pg*X+G`e5KVo%bY#!VI;Y$2;@h=EWG0b^07GJ-c;u&)($axYC6+JF3~gi@ z2Xx{|%q7V9JIlrl?FtuKLd2H_qo=gDjMBI2jhvxHx|%f+YGmr~D)|H1Mef4_UHrF9 zKX9>Jl?J+mnUUpQfA1qH9ndfYs82MxD0oqoz-GCJ0X)2NDx#@lcB?halYQ}BGuZGm-OS?&kxM^KtWJha1aw{s{6pW*!xU(yVSR)Vn>)Zy(QYr zHQgi{D+Jut#hh3GX5!iK-rKXH+Fi_0aI>kc2E}gRMAkQIt|{(=X~}!zj3jzY->|S?(fextj3>zgCtm$7TXaB)+LEX z>U%a~io4r>o`lWVPW_GhAh&Z;Xp~S7gYp;w+$HrY8(`q@(;zh93=R)pkD5A=t#3Y{ z2c(-;9^fPht#^GCyT*?K&w71}2H;|76#u(D3H?tQ!LNXQ7=C+P|5YvKzklp!HjrNi z`_TWC8T<;^hvBbu+cErhGW$6-_}f~u=zkyuzZ&*o_$$4241bJb{|4CSf2~;<( z#QuPD{-|mEe&PP10>2&=VEB{Ho$saXAAx^Cfq%d`e|QJ~Ko5Qn0{#KFe>?2+{haXc zJM&LtpYPA6|MPaHV`2V}Rj)mYixx}FaPGIit$IaBWM~2M26U}H!7`3~3&BVV(Lawy z9aXz&_GaspBS$!BDYnKzN5tAJ2!V|uiOrS`C)~^W!TEru53kwHb8Ge;E#>Kqkmqv; zvrr2?xmhTSly~-&2Mg`1t)so&)27&18TX_$90*l)2D(*lYiNC|l(Q55c;MaMmu%Qi z%)EXF@FOytrq!gMnDg(m$v0zVeYQOrdW}jI&G!f*J&tuvQT(?(Zy7nlp%}+96MZO8gdns6S%xOHUgkW_Q# z(4gGnc564y`E-s8ZZ%z&+dfJ|FOAN>xzcoFH2VokOxv<6evlTFD9-KM zWUPvms5u46zWCu-q!0L~PR16HDT?%|lP$92Z8;SauUU#Sirh=bp{>)T)N8ir@{cGo zPIzxaTB}?TQy^CwIq))f;VOgJb;zf~r=UWx zt|{00YMsOqU=3-z-8yc1<`BMZ71hRAZXD0m5;p^%XqPSANWq>1_oMOyAq$x{ZjW)* zmLbrV!RgU6gbi`8K#is^c6R2Pt|U&ccV}4|{wkYa?z;EEr%$Z|DI%6@8dk!Y`>YH= z2wX=whD+H5Eg~paT!W{&Sq&TbT$i6A%mYwx_gs19+iu>t`gJ+t=j)Oc92Kisqke`v znye%Bxsy2M_Yh5mB=pjem30DBYKZ9Ip|ba+(b5k^SR+WZgOlbNOYw=5@>b2m&v%W0 z&yC(FdhkR| zh51~IGQT{H_v|V&fW>q2#s)AVWX*0t4?#xZP2-&HU`?(X8J#JGG+%ge>em76>7~2H z1c8KWcSS>Z%KVzZ9k~bv6obq}CzTtINR-x!L|ShTz5YI+wXL3B`QR=9YTR%J0rghR zbG}b8TVJUmf`HzZtkTpHHtVVqYS_$6c68}qb4!#(b^yk>ccAiee*Q*9PXiVWr~(8l zw3Gs-t@Unwp5(WnWa@1qBIiB~{or@PQ_?ySkv%7M$3i^qucnrHqzM_(Y)&RbF)K%Rmmh%0DQ_tNgAAku*dN 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

fwy2<7q zDUf=Nh}CM0fE@!qOXtsLFjQ>$FZ2yw)|OeY5B{dg9ZVSOX9Cpw#z`7!j7aa6(6{a$4FhsBu72G5Gt3ar2e+Aijb6l&EFnK zgbkye>R;w7rO=AxuAv~#+b(Q)j+Y#7Nn#15O)!WjhFJ*}vDBRwPW>2EYH(nfeo!Zs zP>e)wKb@f2;oB4uV%v|fqUSmpTAMbtW&7L?cX91cn|dOtrX8qUXNP$Ynz=hWo;#yF zeTFVdpOqs}-XfM|7RKBO^#dvUB!<69j0Pv*DFGL^*?2Xg4WcIZ81Ze(rMDXv=B5gr z<9w|<*ww7#S7KM{6vkIj!s}wu^RAU+} z_+K98!d36qresKVe%TT&ENQq3Sg+fC`0q?GZUKkR?AYGfa}DTY*=Qf_l#vck<3kiw z)H!4f1H7PuBOsy~O!MjSBzK9$Qk%vRJ3`)gI9gz7WnCOjxn86hH5G zgD2-V=1O-9F}V6$>;W)YiiN_{+hFUvN-Wr1Z;}-~3CYu48b8G4sV%T5_<6e;?41i< zjxjYG61gXMT!-zH)h1a@ zzc@*6>iAi^b8nC5UC}~_MsyT}^^(~wsL=@x7|M-zzxr9lm%+QP@EdH+{C$fX`+;Q( z6QV%O;N3e8@LmWGzhK^LA0Q5QC4-Bno^1V-xPGwh2!?h-RL=3UU`*a$N(Myz9YXbe zGV-Jy;QRF*wM$$KEGL|k|4~5yvx}Jma+ZO|rC!)gkGV|_;9cFr$DKk)>BWN~(;Eu9o zomyAR7ZTY?Mw9i78#mq71J%i>vEvcO@L4c;SS7$}G0MR95G$TbzhB=wK7TeZ^v?q7 ziLHMk4zvAQPw@rFW*L67mPFv?af}v=)9%L|y^|wk-!-aR|Llg~K39@`R9^xSxPBM= z%b2T` zPo$0~?@P|iQG+?;Gs3Zeo zXbX#;hntIv%fKX0ES1%mVtNWu);V)bS{0CYn#r{ph#h?w# z6aK&5lWm|BG){A;kL3ay6mvhXy9Cy3k{vbYCUbt;C6TYg5`sON*TKz6$DWUL*^*E{x;lj@bJ z`4&lWklridPA3CY5l%c%$^n1Pm&%PAQplvCa{3Hib?3gz27P1s91=R+^1+6H6s zX}R-IsHye2ggRzPgJVhe%bq-+OzFo;e9%7PGPj1Aleg=h9i%k;OnTRh-aB0J;p<7I zw8+$Jd~qD@_#kGO7hC21FO8qv#;DYxlStWbP@_fqy&$j#>utVouc?l14i?Wu0^zp8s}gvot|7hnFNC zNiTi`YloFI@S9Z0z=e9|Zi9c5kfAEH;n^;ShS75#=|_e?dpF__yh8mH z@lHAhs3jbuCqTWS2G)ou-vDLCDK&o^B(jY&xUPFgnaQZU-r>t&d!_}x_}*z9Py%dJ zo~*7^s3fb$Hh);$S4u^*)^*L&3AJx#kqJWrpA%fu8vwaoV>(@ZVbbi9->7^y3+t`j zOdyK|8R>PHS>NTy{V24#@~TB{Ai*l~%)=y%p0F5LwJi!m{hd_H>zP%|P&@OPnn{(p z)I&0*F`{<3ibJlFcSRyTh*HXKypRwbS9wdOry13AL+CQ-QzNa5dJR*(3EzXU-09Q2 z$F+?M%r#y(sagSlaDIZ#Eb7m`f~_?_>%~Z)9B&#@`Qs7Z=aw|SF4b$MV9zTjxm^UQ&3@=GE<<&7(JLN9}mZ)$p_t0B4G1_N`E7X0ysF_!kS!O6?rx z)DQcdDb-YS_Km5JRCsx{yrWTQgN%2B{gCK!8Y`28OY9u+Ko1@@IW}nN?#MruYBeF; vmz$7%8{kQOm<9x(L!%4$|Fbnt&IXRo?v5s=upAsL9Bk~cBqSnoqOku9foUHh literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v5.0.0/audits/2022-10-Checkpoints.pdf b/lib/openzeppelin-contracts-v5.0.0/audits/2022-10-Checkpoints.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7e0d08387ad3be0a3e74201566eca3167aead1c2 GIT binary patch literal 155606 zcmcFr2V4}%(iagF6c8myMiCTn7j~CjSjiwDIp-`nrzJ-NK@m8KN|Y=a$r%wzB1!Th zK{ApgXZ!~6PVS!Gd%W-7@8>$rbamCgs=8~sr>lov=8iB30%pgh{~8ybgbSf%rM0?e zip#}?%c9_HZ9vN+qibYfhsz>vqHjm5PKyBQRDOpncLf$SXtUJ0;cJ4M27%U6g?Z z!0*>g*dXj+7=i!A4$yw@;eRm{ z9LWYovi{J~(h6l@2h!CCx-y`pt~ubaBYS_>`R54!irxws7cSq&1xU}>K+nwD3b39X z$lT(@(#TE^;CN{Aqapkk zCH^Yj&fdZTkaF1IXz2f&1}NQo<^~`uLlDr-4*J+(r#^}u|E8tArM(?sY-?K+2cSQJ z4DBuT{^%Y@0p>3ZU`Pa@8WM^;7^<4Ing^r%=->A+bD-hxV_e7yB_e;&Q4dG1E(FYa zSkTj@g&Z_u;s5=PApg;wgPSVS_e_DFen@Eof&-%$!O9AUK_O5!Bn*aN<)DSI9mRnp=^wFZON+bt`1d4;!PZ#keEsozv=+hj z(EIrK<7sT`*kLL}NfZg)7_`m~>>06;Wy9R4i>)VY zH(4oeIP}!Dj4X@Gzp?txb4)&KtBtD#N>J(HH1 zMJb~O&;1_Tp4Tg!W0*J8y;GE*=wQt772`w8^S1dCX&p~3YI>N?Q=>mizv5o?MW7?2fpRQ_nRMMuN+Uc>+eV4mg>VCb_LU3q!TI zlnM=?j9EJ!Et>h(vln(Bf7#uTD4WKJh8y2ho2{F!jbnO?c%RstfH80G5~*Qd%dc@M zc%3$Oufwc^gm{lk?4p&ed}q!F{sjNB>iAHB`#EQBTD*mKu+tK)RY=rkZ-xIxbJ~p! zl~f6x^?le*$ajz6Om=pDhIDgK1nI-R37Ydl&h)|}j}c#3aKf)^E9;^gg?fn#@n5Lr zbkA>>*B523F?)WRRUTW##qt)?8`!4!Agd={q?unoZsCgPZZh9+v$J=1T++)mGVU=S zEtusAwDeG4eDVJBEctR|2dwm45BEFr_mve6^E6+CAzlaL;d|%)J~9r%@$Vz!#}wsY z$k_rh=J#i{q=CMPu7H&j5TXx;790r&L)qbQAU<%gLBJdwNOlAp5GH^L$x&#cJ)EiF zvd9_OS=rm_0Z;YAmXN~RgVyibCnlq8^d*LPGeuZQ0uSM_Vi5RfLD_Dw<;PK%t>3x(0%+x2b;@n ze=^@1KU%W!3HQuR%DFa{#67Ffl7QD6O0m^$uG<6heJ*(G!!v#vG*a5%I`(6~Jp%P0 z)I1z$HfFJHX>GBp!lsHnn`&yyz-`-LcX4Xb;~P

2ojH?x0tMLX1p#1!i~6c>Ik8Oj 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 literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v5.0.0/audits/2022-10-ERC4626.pdf b/lib/openzeppelin-contracts-v5.0.0/audits/2022-10-ERC4626.pdf new file mode 100644 index 0000000000000000000000000000000000000000..154fe75212e317a87cfa249b9101a04e789281bd GIT binary patch literal 204184 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 P3ADOAJw3B!^LYOO&o2YP literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v5.0.0/audits/2023-05-v4.9.pdf b/lib/openzeppelin-contracts-v5.0.0/audits/2023-05-v4.9.pdf new file mode 100644 index 0000000000000000000000000000000000000000..21cd7f59307483e93957a3b2c94aa11c0efe40ec GIT binary patch literal 485395 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

DA5c*CxgHUhhcBZ>@bV^8E) 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 z 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

O=UN>c$5c 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

&uA=()A&${K3d1zHWJ6254Xdjgnm9RgW zObD9)PtZmGh_Eq=p&;13RyqeF@cX(v0}1T4R-Fc11cQF0iecI&PBwFFoscT|sTxY7 z=D7-3(IpN#dyN-NWa?o|6(F+&Pm#fKVdMF|ELcjGeRKlcu~=x7`NY1xerA2@2qND3 za1Y3f{*wu(HS#O8=PPr>t1OKAP#%bUbbkUG!Kdj)p6g!|Kqi4z`r4D0PDe|aAh1~J zl8_uBJYvqeL;Cj!LqR3dbhs9#StLS89j!+LV_)K-Yrr@~v1=e{GLUmf1ZFn?X>fG< zI?Ud*KLiM2@_00xw@!Ec;hs~2DC3FD{@VI@P&4o(<5WkbilOU=iw5*X_@ zgHd3B*734&w#j}*Z88kSBHiqgLWX~&@({Q)pMpS{w;iw$ZoIKjx~9jokqd&rguy$f zLzYypS=j4F{Oe*Vp{Y^|HLjZ4uR_%+llLMt6L8_~Nt(z*6A?@(MZ%cO0wQ6_0LVCEPGDVS&?EXG^bRtP6WBQXPC{4U7L_qQ zQJlzkW@MIj`nzdD7^-Y2Mcm%UFG!da1$Ifhaoo|WNaMd~n@j=|5^UDO(YQtERojgp zyyeUnq{YP?V0g=nDT)izhXv^%iI(<~iV}gz9aQA)3OQy80Lyq>HI*RmjtZ<$bxf07 z4aV`)KyqsEOni?lM?w+Hea1;<;Ucv2WCEQ&rC;AMUfov;m9U)TCv_xjf|L@iHNx2l zY=sDIyX6r9SpSv^LKZYNexwr52}Lqtq*4I;k~x=16mKI8R!OO3hrLyQ|kcDzsL<*n}v0`8>Zb@ zFrC5>T?U@jeO@Y7w@;F0KPtig1LR5=O5Y#OE!XkezcK*1xB5hHbE4qFWiGft0a6R_yD=m^7fa*m_aK;`kmwu>Coc-nn<<+$e zI8ZM@Sn7=otIA8VzeGNFkDyVX;od3i`_`p2WeANsbV?0hFI!lF_&!DvUBOVHfSJUuACesr^h--pUXZ*Z(Z ze9l3Ezx>=B%*OR;F>)3B!)E$zTuEyp@QYwZ5IPuGLKcD~wMyyMfl4s{&9Oh^^EV~w zUH}P%W;7N{Fs)Yf=MMqSPRRX#>?;M=BKk{3`^P^V7tD%R(b{weAFmZYI@1Td+|=C#O162{X}WXqB@G4&0W}7d^IPC!eg`A@OD*Ku@8v0X z_tR+LC;TRNCWPJnGO3?U9?0%3$t~%C$#aBcoBiPikNxVxOv5uYAM571I9? zzvdf`wWPoE4TwFnwZ9vIn_qo_0)fbHh6R6MC+rId!gDisvIVLDafW^TU5ffc)N1BR zV)Nt2tszU5ZG-x3ZREC5C&r7H$$l=}1?#14;nqp4%v}9EzP2}?`T0#ws~E|!590=&hMa?I z-N|zS9kIDXtG8IbhmQ(JzL|O^-bY@HcNniomnOa{UYzZ&N4y*E@zPIl4f1+F@9iTH zU*~u_FDz!+Te{GAjp+|k+1e#O0XI)PaVxn=a0gwZf8dXG@YS#bVSu*-Qpjt>Tq_Kd zBQ?9mfv>dqH9jcNcI!!eGoEw+b%izxD{NCRpi){XFS|CX#n<;JmHxsL(Fgz%GZT}l7iRmf`*0_`A@oj{!6E=`jRJ4T;voQ z1q^4pt9zw(Q?@xmAJJZ|{=xQ+jQGOq-wuF>XJ{^+`?N^XTX;)1+6x_L>M80L-C0la z8NS&nLtULm(zo<)F;K_Mo&2;X@2Wi5Nte#`Iu=_L`^D!q@gVB;X%kkaup};&sidta z_&iM{xmSA*Lcqa__4{w$jz?0^K}EAUxr@ARt(G#2c>y$`H^C!ImHDy~N2>SMf~@5B z9g0e6m_-+x1m~SDwkAQvX3qV{RLc;9x_F~$>DHmukhRs6%UhDQ5ssIWb5qgpWcR5+nrfZ!~{zhlB zia+ybBmac2X1DpP@E(hVpg}-9_BdC?D0$qV<gX+Nf32&ea#Y z8~|5VWe!eS^x06j&siB0jIVQPP3l7;>Q*Iz7u4bQl0ao;zb5bk9NI!}r`+fcnAbEb zFKpD|c6M&Y74ivVB-P`=~c0RA|$>CnUGk!D>cj+7=uqLS)&Y4z)I_Ba^zJ)ue zPESWG$iC*`AS4^m>kHY@ox6Ltjl4tQiH2ZO)t(9NdXG(OA+Mg6i=$lb$38v7lF6oR>e{gerwH~dCfv- z0GAy-&(KDN3no%+-9?ynTQ?4@+LCG7C5G-%4ql~|Q300Q4;IaOmGXc%ZdVsw&WUCK z*Q~k6%;CCkt=8(LMXD^P4}0EIbY_cBlU!Ev-`Mjm)?9%np_?eiCWFIc?+CgY zU86PKS#hZuQRnOU%BbsTX}86<`*FrnHh`WC@x2Z>~nT>vn(d*&-xEG^+_BiAw zQdVj(pmYHf1+qxpy{4Dom>H3#JNy%7Ct}o1(>H=?Cj9Zvwr*Nh-`988peOKh()l;} zPOe8barFT_xNO|Z!><OL7)%&K@(-+}ACxJA5krCCF@gRn4}NG8-zTgJOS4)PlwU$~iEDynB^L}V zof14pr0^%zGgd{CZHAj8qkulZ>ZDatVg|#(fmTikM>C;G>l!1xL6{24m!{M)H`QPf zX7Yqi8ld=s$R`0NN{VGdQkMz0&&V^Dkgmc*$5tT2oP`46@RmSWSFBNnM|&XtX_YTw z3R2vsnNn5Qgh8>l1|{IV22w4yF(kEdh)@N4JUs4#gse?QEZy&hbgOYX+7FUON%;$e zsU=)tCw@HtI4GG?X#ff_Tw=avki+;O6?kkwg5(EKTF5mFg~EZDhw!t#VFqP_!erRp zK)F*4uZ^Q~_C!u0(lo7+Bz6hK_dV|9L0>MBtvy9dpm~&Jv}xZ!8atmvk%>S{73G-T zL_p5>7~CR1H_3kC2PTp|hMkrCx1theF7cQa{)o2OD zYC@v@v#NOB<+;5s^maZMkr5@3j3VwnSa9vwcq^BZ;R#CUMSv+W{9Rq6LF75)Os$O( zDbia>M|Inwy0)V5MqLb)qZphAHj!(*-p$bPll+m~lXP_nX-J4No*^cx4j%g~OQLp= zbcQfhmGd?y>xpZ&tXz$tgP|MT1ZJmIFp?Py?>Zx^!{A_SdArKWL<~Z^=!l_w$rvq1 zcJxo}3~9?D*u%;t#6)TLH4O$)y7KON!IDgd-$+(%Rw(fx3~|}PMFTTo3Q{A1N-~I2 z^N|ZQ@>4^kXt5eGAoUag7;#yvP99k!r8%e<#n&AP&B4bF1$zXBe%;~#6edZJP5@L7 zWV64-j}u+vf)ATEFp}47|EQ9cn$89o>?pq8&a7cy#jArK(KB3 zPsvfa2Qpgu+^=hr<@P~YaU|{oEE4Xh$FaYG3-qHuqq_*>XkEaBLdM+e!Avr53K(Z5)&|D1 zqY;Ry&9^)lhdbw>*L?s{a5(MhR^VhxK#*vL*t|-a6PBcvGBFDykz*}uip0E13t7O) z;1!Ow;O_BSjo=0ut+vx07@D2nbU&;00QD@^Ld|$^+Bv@_S0t|1g9l3BLQ7n1>Z&(4 z*bv5Adt`%0Mr1>)ove&o0ZcF(XDz3gUZv;q++M_g0<)TxQphF@i0WDnvwyWsDF6nt z;|1HttMe@4Z_De6&K>lppkKdBW%D3>+o3@}_z~}zv3%}D)PuH!_Zh^<)7kQLfKKy% z3;ASs42Ha>m67ZP1P7og28HH13Ota5Y-kili!)Fjj@UB^SBwmd zf4DMlovf#372_Y7@T3F(eq-Ss>%0lRoftlih!lek32>#8z)4|fB(@0W37S5U=aZF=bLtua9U z4t`|!#!^3i-_|>|$S=0*9m&q~`XKj}F?9F)m9jdZ?d5&P@LKu>B!0YQ|KHr*{t>7C z=SuTmLRXgm*om|JrE<6D4VSore`IDEInV@oY z;Q->RhnT2#tYTv0d}k+FgEkX085Pq_1W)IVVsEw-=@UIVODKFN{qS{q|58w9XJK)J z!2S)iuB_omBu$g`?NY z>HV~<*ZcaqoGN};Qg+*Wc#%5D&xbCQ4q?F`)(dcjK8Ymy3w1-o$0xz;Y08!pvd>(e zGkUGT>5C@!lM6nFHyb}1rqCS8F&=@Xjwk~p-1rpOmnD0Gy1|+1vruO)!P2CBA5OIo8-{D5ve9d zTg@Bi1ti2j`lJ3mV$Qs8gxsf$rFrA?h2kDCLJGIP6IutwOBYiV#O)~kU~aLEe|St5 zlJlY^c_>`fI9rdo38$XgM|rcKU`@Kgd&>%Ivm>KV z#EF)74fC2et#j!re1J{n^IT`|#>>erhH-@r)jGytNV9Vv5%wG@Qxb!@4?Y;an&vW*$&aQ!&5OM-#R;9z)da(sC zB34hldcPds*im&9MhFR_qDXV1?CTxZ*}G^k+K`$VB! zO&?LBSD1vvRM}*>z=0F8`spE#hki`DfX-+3Cj*dKkd}l%G=#Q~x}8*o(GKkC$rtUJ zIo7(0Z@tARhFk^)&aCE~M&*O_fZ%bfZNfyT(nQJhv*SRi9m3lJvFTIcwK2^AteDl( zo@#O@02Xg75(1w&0&~Xorqf4*dnPjjQ#Zf&w@tlXosDcoj1a~c{otV?e@uerd9-So zS(mX(C(jX~lTBJFzYjDJ!;&WDZlGx>tL3RA><xO*!zl~;(4W%&=7TeIGFZaOxC0O;5;ZFM1qxSt_oR zv+(g^n}Ti;N!EsmFPDzILsu}lDWW8BW`va>YPaq&GmBP^yQwK$7MIirnI%tSpzvua z9MGP?NY$15H-ONA)h~@S_+e!BM>1kCr%?CzerfZE1*TC@EXM98J52VFDF;BFTF7^qvSgV~aGC7n zWF}JmO&^h3O}~8{O2T1|6%S37aV?`D-X=)~ildD@2&CP}(Gn8XC8IauB|d2)$*Gzv zevX(cE$Mo09D?OH5$0sPV4sSYljJNKLpO~kFTnuZUOe>}h_&aD8fOvStH74txMRWS zjgG7KlG9@{(2lZp-}>HVgD+3Ya4n1A6})9h3bUj(xiK7fpNt6uu{+fGDF0A2Ty1YZ z7zl|RUU3gI^PdiJ$Dnk&VYGVTqW03(6i5g3YE@V6dE4%fbityUhZxW2R_W74$6&NG zh@+XY>y+)K4GS~vJ1Ofv&k(5IiHLB>M}Xr&S0F_W5VEh(c10iE#* zIR(bAoH`Xc4()1x)|c)MTd|O;>hO)(p0*XB^so!i5&)~Urq%8qI#FG7^17cHK%KO= z-;u}t#`>3O?N-Omnpdp!-) z40Qu<+;wxM8H~DK0uivG?S8Firx25@L|M1_;Q|)M4REg)vDivCzJckxJi2LPwQswF zha(U~4K5^2y4hHUJuo1Qbs6WGS^r2YdXWI zn;(f=#H9X?L$9U)*6)Dtv0KlcS=d7vlo1WXa47CXJR)chsBpP(O}Xbh$!v}|E+ z{(9)-1o#*O)+CS^tS_zs_}RKFIA&=XSk)c}4m2UDK{ZgU6{mJUE<|d6{f@D|0wn4s z+4n&_Y0G5aR?CjL7VYkyYsbX!hV`&@ySSGMibl#<(CXL*i==vlscH5nFGa^x|7K*i zIEek~HCk5b;%>(+H{koHv$k2B7kq_3W447q*1W?qX0nSJJNS@X!3tmV5qXc6?0O?R z*g&{j4LTVu&h;Bgxy}E&K!Y1*&I~S%Lgpq+xQoYbkpd&u7o2?l=(HZTigLRbF zaLYp3fY!RsIee0wtT_w*uB>Zy$zIz^I_Cr3dTuj~wL!*2&Hh zQm!cOdLlBWjG5@()00Rq!`+qY09LFD(OGzx_-k6QS4b;5ThepfQODJ!DXAH%uQFbzO6_2+bVOGAvmO0rFs+oNY}@?{_+Zz4@C>F@Kz{B<;dTEk zDmM!x6f|u2FqBxlE9$u8iL3jNP4zbY)Qc`u0}{W=>3RJvbeoHLxCUO^-qn_RMaqZo z&Tkjh`j)A=MKc$D=+xEiXv48UER8(nLu5esYe$>U`i4zjyMUw;&L)^a`k8%n6g3vz z;ch4EeCJavRq15e3l}|QKCbk^^DLwq{(QPPZ8zNph+c^u;F{!^(mBdsYX1oD8D3-U zcc5bpVRe@mee@k9ZV7ZW?Kp7g)ko9v>-bcq&5bu(;P43P#zQmvFOTlQZ88~!l#?!i zllj1ToqRDqKyL0}Aiz^M+1^MM6~;&Q>7tlqFcw)qE|?}?cM`q7j88AAXGG) z@W0={q-L&l{`8s%t&?;uyMvRtgH5f?vP>a7^7^O>R4x|`dJQgRPKWLt-G;Dj?N)C| zyjJebAW^J)m$ouU(ZkaDV_z9V@;OFlerpxv2AyQ3Mt{*&P(6*->hCeP;M(HAECXEp z!Pi`;mDrMA+X}`lthL^AMOWR(y&d)L-+05V7jmalMO8eSf^(}!Zb#9~C$Y|w>nBXj zHsxx^XT3h8jGRCmmpcMAMZ~4iGqe;^G~eNHu8v<^RpK*k{+z&DO_zp76PngUWt7<9&j(Od;2DC;Wfc42p7=aww^>ZA)29uALW z`Zj}pK~k*@xQ|^I#OV#{{o+bHd`=R+=BM*B`U71RzY?4+0OM{HRl~TprK&3XLM+D~ zvNe+V(;Zv{7XplPyFl>;j7h@KU#yhum$~~>;{FOK6UL<@vr&I6@xxR2ph`{(z=`j} zLBgFdUDmt>%g;Q+OVf)4p`l^+GBAUSkH8e`T83;E@h|XMV9A}r@?P5l4XhFbVy6*S z7P)Z|f<>J zXRm}TSwx*(PCg$@&(KWHP1Wt6B9hD4CtoiT`M@GB@ol?cUDNk(SJ>8nyTW3~<^*-a zJpA~}#1-S1u1p7-1eF-*KwCbYs9cJt-N*+s>-$&MfrCEgeNFfF%Z;Y>ZN5&}nj?IFmX9 zXj(2k1aUa_kF69WJZn7lbz$AUb&Fo{UU_84Wfr(i)-Mlb$p#s%RN03%;Cr5{bQyQm35-0 z+C1lA^UQ}~uMt3way>a8AiL#V2Cig?2)Z_?N=*%i6dVB<%wsx$E{^yNkf8*y5khaK z2)VIS2Cmdoy5~f3sy))qXuIvV%I0ulLZaq@X(7u#nO#Hx-_R0Lf`{57py{YH_IOTT zq>2)2u)m(5p&4e@OYu< zVdXpF%Y*S56bTmsmh_H&IFdF~7FeH5X{?cp^dGWOx5BPIyX3mFgi%0eagc!P)5hU` zB`P!dSO;(z*kk?S1oIN|lr4JfWq4>yx@xD z=YU^^tjR83l=GixSd#B(SQSFqZOn{Yf>`1pea3?GTrts>v^<3Ey!(yTd&$uy-*CU5 z2;)ei(R>7xO~jeKzXd3dSs)JC=KiJD*o#~tHX9q4x6`)}@Sb$*{)T$|rq-mfx&jd9 z_*aD!3{huqCj9_ej($sy#qJZA%Nf>?uz#L_4$UQ%;>i>UC0*E$%)OYNr}eFk5+^Oa znh`Q^W|oefChW;sZWw!^{3VHL_9WZJ+UH=e8EhS7>8<5}(@JUT?J6sq+-TA}pD2&C zpILJP-pRX}Xd{Czd_%#HJnM)^MMgQuI{3V_igh56sqJtAS^*6&@4Jk17PANCS5cPN^Bb%eU{T5!$rWbO z=h;B3yIyTN+!;%oAyTVa+^70wOGkZFZhYQvk5sRPTnoJ;bm|8WwlpqkCMT^A*gpnK zz5j1e_Fv%jzsDB;Ln6k^_@5Fn21b@|i5TmDClT9EkT6^SS0aX!^!Q7J{uQOfKcIeJ z8Vu2K4Mf$pIwC#UoDjiGY)wn6#HJOT;=CZK8B~p)8hMeUJ+(%aZloL}P+m!2a7lp{ zR9bO@hmFEVCtDnv0x*mb2V}Ago+VJ5gPk4W=wKyS>g;KEZ;CefjtZ7^@qNK!a_?R+ zI1P8}QgySyYPSz%H;E=vhy72C=&hNgWE7U?o2|+E*@9^MM!cRDtxB)M z@vTx6Mg@>jGVbnVsVX(u&HH&QZd6?_|?x%uX6XDSL0V6dQ1{3q+{X66&O6U;ajMY>@#9M~itosuZ zJ`pSEj2`~++4_UB`$wcBAkKeLC;x>@CBwgNlQ>L_e?ff4zaT#2Ul5=1FNn|h7sO}$ z3*s~W1@RgGg7}R8g81M4{OynF-~Rr0LH&Op_J0wm|IhpW_XF>*pp1ovh30=Hcny4K zixM>1cxGwQPW@ar-4x+b?v~UCc05;3gwpcm7$0XH5~M-zp5*`ZEOjo6;@qg?%zIFw zR9t&6OjDp(j4)>^iKPE{Ny+^ZC@VyfyMAYr5O*jBY6Pn^vV@_XgXG z)7?XM&i(!Dt5WG=mcymO2tAT)&}4CQ{Pj6%$>CGIHZGEuq^^R>**O>MLL`$|~sV-7xcE zjH3J&S#3=?k`(FGnZzCXD*_HHQl=G5&2=W&w6gKx z?bTzCKp@ShvQ9mIw;UyP_gDG1jr`&F z{j(0t9ng~NX#0r#5O+IRY~POY>uJBbz_R;6-=Y(n)Kzy>N&Xq(o~~Z#ntaCYTZ zN3%rePoZyjOn{4bn+;zvw@Um?wJ1b^Z=j+R<5PGh9N#oIbKg2q6-DH}3I;<6gzjTT zc$T)uKQEKm=$SiGR2{R-LwH{C^hTIh(u9*$;GqShiNxHai`iRuzZV(G@%{m}>+P|P z+sg^Pl_JRJ(4y4WNT6ZB+Z-sMy>I5Ki{1U>Zgi$wAeRdwb)W9EVq2+nQSB_8?Q?4< z=x8-!wZ-^JaCkEC1#c23D5a;5Yx6STLU~lOn423*_%|syJsWC&%Z86U-oWOi5CT%U zvsc}Wiq&f-B9U4x-NDCx+|#7Br?5#OBpIn6i-B+cJsFz?=kChxVW_Nbq2f!T+pgj(|>5=2?ZNXMj@jn1$wGN_lskglfd|Mn1R zZ^9xC{RfsGn+2iUT^COehnUHCs%zjKYzwChdP;N(47jODExm0Ed3c?@JsgU#ozDFb zbYTYDiWGA*6YuDX_^or^#x|~oNoo$me}6vQ2cFwUKCSv=(3uf7%)u?HGP)u zVq7~xFu;?NIZO|yK7tNK^`UzmyqA|y6Y1vTlZjARnC`kP;}ySxSW0!e zUdpRLvn3*V3-A$(-Uie~1YGwgFvsm>IjdNv7nu%#FAV%A-Vh4j0~$ z<^sn#heV+v?!IARBhaFzYBqLKDNlM&pA*VF5j{7}E)#-OsQzd& zQ>{(1o8jX+aTlLd3YHgeIZcoC#@ob(E*;4*oe;mI*s<}idfL~)8bfq}biy;My^i;) z3VV>(vq3X=yUqCg=q2XFUR$2@Tm1wi3hC6J%`&M#8Z#`UZec_&4gt+|@WCMKQg$vP z0f?-t398ZDyr6qX&NP}nJ!JkEzKXuYtM;)?7GO_~c}2%~stI>_gXB`CNQFE%gQwIw z9gCuM;^aSGt zDl&0}@y6@?>Q{6#OOZ zT?PDm;q9r#xw^x_z9zVljf~s7^4@qX*$OUKY0-joA2OrGxzMA{Piawta94HIY7KVP z5yXe7GQ5r}1Ga&-$tLA@qJ0>5=<9E<-H0(+qzibgZ0xHs!~!#R`PDS5F-`5^ywH`i zafRe%Aitqel%unaxxF1VklAt{h7nd_8UZYZrp_acc^H<_L?Y_zbNOIpsxkX#96{7o zp%Hnx%IG!?*a1;()J$b(impB5`2B*PRwPR`Gc1fe*A00{9fe|NRHeuGacE`5=J>`) zsKl}^xzTJAy ziY}NT2?lQr)-rv@s&j2=y;a*)uJZvRe+!{j8kKoAGH5Du@EyREtCu5I&3Dd@=+Wxfkl{7X4w~mz}gWvv-NdjnV@pb2uUcc^th~ z=ly9}Ov`~}Xu*)D!!im*vJ$Zv5x7HAE!&$-k_afdsf{-!H(iMX2+`=nf;QysWFQcl zyF84Y3d#Ul;b-THcDTZ@s!Z^e2LW*yOri|BYm5m<RSr@|V;D|mjf%jgm9Ldyo<_>s9+qf02cB>;Z!Juxq>-8FC)%7;; zL|%3u=<*3`I(bw1K87bVhV&kq%Ntx5YRbEF^u2Y{^89E^IE?Xj(9n+#@@ZttOllS1 zS7+Z9s7#=mdT^6!z%US<$pLKZu4`O3lYG!iv7>Bb!?mr1YnSvmJedwWWAjisn~n&q z*nls~H|?L2OMGY&@1hzSQSKN5dH(3nV)B;Vn0wJtR1Vs#ia#;F8ri=J^;miToR|#@ zZmoMJn%H-f0jgZMBl-@M=$I76H!JgNZHfGS+?ga=GznI3d70InPgcp~=b?E$J=(eX zTVVf@Lf5dJGfC^W3K)HSLBj~&SXq68n9PyMLH7xLL@XR}5!=v++>>+ggd z0I4ooBAu-`Wf4Ux#@v+hQHO;CuDW^w*M2<%KbDsWGIe2heO+#Ky)`|l?BM#qE*NSb zWg;M#4d#zU(_q@1Auo1sIY!%)bVn?9Tm2gTic-`yhN_em7(n|aVD`hk8l-;!%^Ob{ z@H%MG`-0bOdnsdPk{0R-U7{tCibVPkVmW|KeIP*6BA`I@d};gBfrfA)_vl#x8;DNVrO=JSh4y#cRR8QI5DOFeNvGkpCYWpg7fWJya3a-sj~&Si=7;< zoXV7Oq6^YujH@SFu8Ib4b5xDGRSv(MvT!Rv#O8`bgE>x4Np|Y3fmeK=_M|cM_=UqTc46)Iz z08b3%!%z4EvswG(Wbfc?`Vii*DL=Qfqj_w2*uD4*e_Wu_0UQ6vmw1~I2f#W2E(#Gm z-1H0)_xX$k-J6nnGJtr!S(;t})YxCJ(+uv-Yb5Yfx?aoX12l803xsTrjJWCDHlAsp z!OhI>G(CLbsMOLKHA~>RLnZjn<27*<-7)|w|}`cT+vH$ z19Y=Y*HJfRwx;93w$+`Kbu2_V5sV7vn=b}MZvXbwW1f@Isv~;V|&fE zxC#No7FY>@shl9ohYlI=c%6MXWtilF+SE2!%x1v{IH>fXM zHSv9$>e43sTT8K%*EjPzv}<<%%}t77tRwu6&W|c<5Ya4pmEw;2(mst*q_BQ^ETGcq zvX4$eO{DFW**2R`%4w?=ki>GjcU?^wu?R50-Yg#6#c&B|6g|<-impHuz%Dli`+$ki z{PX3h>-``~NHo%13n{fo`s6C#!JE53Shfm#_EqZc>`}_s!6J_g|cZZUE& zdCpMp&~ADExtxi$6W{m6pskm^o~eLd3-Rge)v9O?wBtdY%}Nn<9U-ES!Rf7Nu4B@J z4{PLnCb0{f;=q**h@Z6LDb?174nq^=iV>P~E?t=$s0*uo2O9MKr_p?wYtv4H6*Ec9 z%**B&z|EhN=D=3=N}>s@;`vz;cr=R~uMH*8Lw6O)Fa&b*LC3IqSDP%x^d$BY zWpn)z+iu5$una*1)s;t93{J|Yv8Mi6c-9L-qDkY|d6cmC*Nm0>*OAx9gOw*OTTgRI zmf@Oj{nopP1$Tj@)Q5hSPT$EzR-?tbg<9DLayxz93>-lko^mdlcO!5U!Bc}Q# zaP84^GY3M&r9yF^5ln-V>$&dLNB+m&ZAahGxAdhn_f>nmkJIt0h*-@rMC#qX%D^;j zKcj7Rx^79>o=FS^it74<&}s&Z;E;dsHCOO{ zok(?lHO2dx3psQ?4cI7*aco_bwUVV{JL_fv?)%3N#$>PanE`999Bt2BeSj{k8;rDZ zJ6*c{+@_hF)$Rk?n=?+B3^I9~aphDcWYoQt3E2N$8)$D7%TO;yLr7E!ca0MOH!FZh zLwRw%j1!iz>P5%eG||QSK>J_9Xo|>INnuD(h<1%rg2m2aa)rOyA#Z^;-_vj@33U@K z(3j^LKz6Vb>d{2fWYOyqGR0Idxw3$Zr)4-D$+YKMiP&@C#B=(&0E2nW`qNqBLSk*e zlA}0`=V%-ClgMJ)RA!PGlMZ=VL-iUeV=XMBXZ?yJhPvfsJzVBf75+YT;)r;HaLj+(1_PWRYiBBMOQE@Y0dOx1X!2j?%iwBleEFX;lJ z+a4<1^SDet3Y@D;C&1JZ<}Og{;J6r9U`aW;7fT#ug*&g|lDYs)&Dp(rx04oUn#GRuO#-?sCO zg4x2+rf_m#joNB8a+9*{jBvT-s%@~NE3#!1LUMyWEz*H6=H=Y zKh(a|^w>03&&V)*0Tn%lfO~cp;w))5k)M4N;qC-@wG2$!|<*)yraJq$n`j?9F`d zh0j7_-M~P(nP!pWv~VZCrm1hxFq@fup}XIwmaeL5Rg@C8F1*_3#WvV%M}wDrU*yr< zO?S2j7+!^rH?0HjqKJH(Xr{UOL zYPx3wf}>f@rzh$g5bDs^{~;y^;zWKSxV0(peQ*`ppp<_i+@OSRe{9cj0d;EI-q+l` zhp00*JU9;+ph#<50rrZyK4%*oNWkO;nX3(?b1DeAnyD|Zd4c5IgFC9Dc)8;d6c_+O z6o<57r~tTXjYJ%vh~{RXG>2V9#x8{)!*cXab6=PJ2dx9XvsD)v$RFonCN%r zM?m9k8t8wOgE#W(IHIm(#CYvm1-Yt^Re?!b{|NB|;yxwhwhdjzzxnBsIz0DK4xClWml0SAi9CV=e@LWMQ?YI@P*^zdeTRC zk8|8~{-E@ju1gUg*F{d=5~+qpvh_V%krGshZ)$53fG)TGxh^}N*b0242Xtmilzl8; zho~*ZGd>0|*p8tMhQSBTqXT_sYdqrM?N;ZLENrYW+QuQUq(HD(wtd%=2jkhOg~KoP z&UhLLg&BD6qIOCWBg>w=aephaf=}cPHDjPA3QUG~ZKN#1SbRm|?dJKj$U-~& z*o_zF7SwEkiD$X?xot6Iiz%aeeQXqD>5>L5gEvWA5!%|itt*t_w*y}zb(~# zB*?Nr^+yi~uQGJWC&@WpEVZc3DAli9T$7l&W)diB?O5M0q)!hbSZ-D6MaNV}q-({X zZkgvES`{)Nacw7FJgvyxxbCo1s5b=&q|J}sRt?OwsjLUwsc^Q`!GDscFm4XS-G>Zf zkE>E02)W#mMf+sDl=~9I{Q( zUEG(|reaBSDX3F{A}p=>J-mkio~UXGU3DOL5SuT)BcQ}lC!(QPC9l{iX3$mt!Y1rZ zIj|OwsS@*@e#{z{PWQugw$0qSLEElpPT8!v5qIhLaLh{0_6oqY=Y1+tN>f}MyqCX* z)%}?4!LJuRPyXt-Gs8Z!Mzs*Z2NiOa^@r9}2~vZ)9Z){nC|NniwC=Xnq@MzAOtwsE zwkzX>iKRK$Y+pYL%)3^8I{Orn9m3tJHkdQG)TjvDWh$D}aRlCN=;x-EooUB~Z zL2oT_5Qus^q>7YTGPsZH(4&4kuf&0`bm{MHA9>KHM6=gyM`~y>p_j*s{IMl#42qU5 zO@uG;dRHEv!EaTeV%+M@@egdI^z5JZP~4yUDdt0bXb(=00{?HJS17Wz60(8T6!?h5}Zs{7of*+o<#O;V+)4XC^V86vI8FQ&E z@WsBv%(TQ&(9Gy0d0(toj*Tb)Sw&97-?nM~jBHAFbfdS)Xy=aVwm}TuD^_799qy2d zG^rz0c2pzQRktqzf_|OQluAXfxP51tQmH~N5*3PRo)kS zK3$|{*aOyHv?RX6I0V5R9?d45UxLyY=CGl=$eUJ-@J|F`f}In|AO?Xrq&0=(o|$`C zi)5VZ&1x89FSNTR{a)roH~pwP`=yWiZh==iG?MRu>OpySVmW!&HNwiOsm4p{6-0XP zyw-DC^5dV*ONRv6oY<`5`G6`sZKc>2qHXnZm|(1Z23HD^xSf&N{d5u$g_dQkMb;QB zF-BH7cYEMO*^z}|Z2!da8#U~a#dycY0<-yp#sjm5RwDC;d0U24TUb&x^2GFtL>7}h z4K>w8LH&k&i~eX67d3-ageKP&x+cYQ+n+Vn>5mgef6hc zUC+wB;*zqWL=5y>EovnNjhb4j3N7}SWK_^}w5EH`bjhDHAw^@P0^nK3GfK?klj>~| z0ugs&`HnYDHkYhZ167jYTLtilPFf<(%UB*T;2b!lk%=9Go%uv+kDo2wpfNtzwQ1!` z6}V80aXj( z;pA1;n=RkS~-~CNbBcWkvv1Ow`BLzy01oTIy;dwQYV;MT4N>w9KW5i`nB; ze`#E*();}EM!6%Sx=zdA@Qw}XgL%)--dH2pH#`m?LI^Q2ok1HP+!x0N&{HW+VG|ZW zQ{mx)YQEL-_2!w-#v7i~YXV}dkpFfY825Y{A2-L!Qm%rka!RJmeygZePpFl$dMK!m z-`?A9mJdoD2Me1}M;UV!n4j0#LqFA-iw$eRCr09D#5&=&Rw;hG0qSs#a|L6-Qaln< z0*e52N>(5T64f61n>~eW*27cUb;x$Q4UvHu!0Jo_t1>|`>o&>^{7_}V%r7V>o_HwW zI!2QpU%%mflk_v7pV=WTgFY#tOH>`{9+*oc$^y(+Q(BwfX;8Okwy(k6*nwmh>fpE; zb|p3p()0v17|Z0?M+@he95#Ab!edrPFY2JI+C>1Gf>hf;%%gb!Ui5>G69R?-V4 zGf;+Ii+KZlJ71R?{TH?Wzj#6ar@oizFC~cSFC~cSFC~cSFC~cS zFC~cSFC~cSFC~cSFC~cSFC~ci|A-RwZ>RqkQG)(?-~Ufa5EC;4^Z%S8oL2`p*DAj$ zL05N3cN9Dpo7CRb-k8JaEFpL+X3L2&K`E?8lt6U==^W2batai&1DzIA&)Q01dAMb1 z`ZdbTip*sXDm`6RjPKN}oCWcE)<7UG86*ErYBD(OWow*YwujiK~?)Ud0dU2+0ubcO8XX~mhQiBB9&AzW(*~^~? zKfGW@Q9WN$#jf2BT#ujLlmdGgpJH^>9hocNHU-;kprV#6PW%S13pjUvIyg~!adpj| zw9OWE#dEiUo?)XljayKOsW%v?Tc`iFOnYhV?$|kGer>m3Cy< zPmy1*9y%D5O)(#6m&{-sv$X9eSj_M-VC+Tw@Xzd(X_G8>0j1CKg(xQ~$cJyR*-p0U z>TnJh=lbH4q~5EvqmoRhzX_gUw3!di^%~(V<&(<|i__ZG`1wBrHg}ZNv%kUAPt^r_e6LwfSVWdc44j?*g$G?<8EicY=GuSfj~(%F@jGD0QeyPx! z^r(0}t6QMl?Rp@$IHDxT@9S+JzDQu@(Hfwpkgy)Mh(%Hl;phV#4QiI|pRQtB;*keX zFc7tRJ`ue}5C>8UGcJ7Ighdz#+7p{86}@HtIi2zewHFQq^d*PPxUKeMxDj=0`r4lTlSs2(dZFkTlF|lMJ!qcEmv}0?Blap^(Z&h3xV$Zai;t_aax}qP>?KFcw$$?xHHTawHEE)wi!hsfF5()Ia zxnJV9PiRIilQu|R@gJI^6f%C?K8i}}XxCC(RuS}#)2!IB^xaID$myHSfR-$43Jz>n zp8XV)JQ7HbVX?$1%Z3%Tu2lBz4j4*Z+gVH;$|>dEGbqu;VBy-*R-MfKs`bExI! z&-aQL>x29$gske`DNIeyo}56^r;1|2nOohV4HrMF-I+$(0)CW>cY_y9&XOEGp&M4f zc4P3ICz|Bw8>T?K*qgII7-G$kmR@kS0A z3DptdmI2IU@gxOerBI@;88F5HNe0uyb7D5}SP5xm1${FVoshPQLX2M5WE3}tNN0{j zacSb0#V3n=Asf`!N#8%BUrnaj%kP~_L~_qf+Tnj{iA;zgUU}jH=?s)e#lFXdr+nBL zcKHl`EFmuBt#byB2M=iOpXcAF3C4iQzvc~CpA)3v;ome81_zv@SmI%>wI&27 z(bYSs_)A%Iw=fIGPfpd&1uolFSBt#GpkIGV${9(t+X}>l@>kf#h!in2e#s9_?RaZz zIQ~q&dnyy~B^e!p1|G`d3c`7*(#m%KwRJrj_)7-q^vfiCHn|j@-K88laq{ke8eh-j z4p8+TQD40-*%QF}AtlHefoj2>pN{Gb9msk|s(B}0{NgG}<77~PH%iu1&?M*NJK$P4 z$~kS<{nojtIR7iLc_$+ZJf@JB(RG3UuZk2iX+K=SX*B+;116;hcLcSy? zRon^P7XkD8b&UlWM{p4nf^L@ns;;jWti+^bm?#q-hd_Fg^fV-k=T-Em8LIiJqlPT%Y>+SN?0E;y7$fpRaJNtGwild!OM z@5AKgX(cPzlIE!!>zCZK+yu=4KWNy-Md_%=GvjogKP~G|)Y(sTD=PXxzwGi^yXayP zH0ok@H*^b2F+E27);)ec6Z4T?V3nc*x;Fg|c^dvh$VS!OFqnZ&?1{bZBP22PhRLSh zDUF&6{)|4YY42{`xLR}2Y~6k^>agWhjd-*pQ54=FO;M7PE>U?q2k z$mW`p_j|?*N(H*@1DPq9&r02}Lz;!L)L)$8zIG1}9ENFIEHGa})aW;2btrgfc^INbD}bxJmZ)ncH&)%EdA1H%3y44+)w!zc z+rad`@Pp0ki-=1pkw)j>KDXb<{{4RTLoUD58ej49T?!FJS_n7!+wCQIY)uXM0i$|L zdmcHt2(w^_usw#EqHa$ZX^52N=|hRjsjO>2>0tq8@?el_)DI_IMQjZ?H@?9q&u=~pw4OS7&Qo{8LL70cK^4RM-(_L&5o>8LxR3@7i-x#-^5 z4bjud%X&ENFGBtdgkoKds~yt#gz2hJm8^vTW+YO^>}%Eg?ismY)e>Vn)$2p2giA9~UziX!k}FVx+@WT!%E^ z3#@D-ms6gbLd;7}Qs)fMs|bbPi?9eHyKP}c>Ie%xjlt3Cs<_5HI~;ExgFSz@=4;IU zVEEM=bPP<|tT!;Lx+Hu@(Tce@86hEtkK0mtNu5C(&<_mye(t7s^btZ>+Q#EvKPHfq z1)+gUmoLL*Z$H0W=)pm~+C23Ze}JH4d9(uvK!)nFa7nRdF%&#)_B^+@wmPAyR-bNaLKm&(u z87{L8pC*Rqz_3iNyU_D?bja{Ysl*}6#^beI(O4L24z0>Iu_!b~fq13(`0!suH?rqv ze6+06WwgdTa{xli<&+oc@fqQgOhVv67ZJ8{wQQ=CJDLF^Zh;`trG$uD-%bS6iz3}R zu)5z{GMGN+R;@^s?ZDybNUfmFZy1b)jA;4X`+(Qv)H+CzkhVU8g$Lbp*(vDhWnIWQ ztplS*&NO3l2r&-hdpU)0BNo~9scS-uf=L9u zp)89LJL5MN7XpBN2H|{t>_Jyg`S1fNoN6a_2Gm)PomJOJCL~MWo)vrKnC3;KAYKQc zpjp{HDmF)>o{a&q~Ib=~N^m$A~AJ$wjpQs=>8FsJX?^zvl7G_YeL(_)tCESL~W zYGzKWP+Xc&BwI6Lo5$WtX||z!z36E?a&Kv;H{4TgHD?mrLA|foF#P=>9>i|fdCDxf zd1iFn#<@u4;xs5aC9Ma_k2Amcrm9WQ^Qj<0e&u5>wm9i-iFPr!hXM9ee%J-Ku6wiG&nqcYNB1fGU^%Y+ z8HoB)0&2Ww>lb0gZQ~{MRk}xR$|}FUToDU9VKva?6>;p!FnG0ta6VQ5n&kYU=e5D3 z>k}ZgjVpISHnj6Ds7w()+QY9IYw6>VCc1;;W+Vvb==U~I; ztX{Ct9G6fVfB_y2CZ<=kR9%*HYlSPd?w*fu`z{Q)#}QWg`n{!`CLJzJPi|HyPxjwB zVL030cZicT|55DIP2S(d4(gospT*86_g!%eIIA-jU-OR55&?zIN_3&-l^rHq@kZKS~6hWAEa=&+!RWz0&;h8otr zeWq=3)4=uGtJgM`Y@@PPjvv9K;s;uJx6*Cv2aJijP zrqHMTKWXSa(hWS&BY$#tZUcho4*2o1u)w}VD7ha$Pscya4&Ue9tZC{Arss4ep79ZZ zuZR=bo`8$&%beq~2C?XiS#uU9t6+d<)tqhi=$MU#iKGR&8LdD~(3NR%zmM(aW(W%^ zA!xqPwj{*8syuibvY%f5@l7}zrM**%QSyFWRZj*Yw@4i*7W%2GI;2F~UC=hDi6!3Y z=(5Q~CRVY+a%x9hVKGsCOVxS>qmQ{ZgJh;Mq{=q9a^sRRr|qd|*_pO7&Q|QYiHCN_ zbSSmVQk~kJRtrMJ3#!;dd@JMUl5qV7POod?`io#EK3t4;Uh-M+662IuPJh)3 zlN}?d>HEXaq>#D(3D!vJ9z~OQ z{Kl*&d#@MV<%Yq@CuR8n#lcDRp}YfbR?)m^3dXyv3-q3)$>#+ITF53@BHFs9;6z=b zfx(n~C44E~1D$DmB0~Am1O-kL<8_EFNw9B}*J!vE90OVCGUi z1I|%(A^d(>3X#i79qQIOH;`BVK?yzK#%TGqigSd2`L4c>+)}IMdRWr3xA5lzuXgqs zX-MLD_;tDK5FR_7?xY1vL8i`J-M(twcg@qat{_!&tyRA0%7IWLN}Pjmhnz_}B_zMB z_yUSMjg529rqrg5L1;d-J+#G65r0@SzvNJ9U$3;&Z8M1Dvf@3aKH6m*wllFrH*-~7 z5G<9`CF8`E+Wt)e#VG|!><~{0FKJHD{3zI_O0692$dAf~ps$N7@-M6tq$q>ekU1?K!K34r za1}KlMCawyF%-`p`Y?HLliGL^#Hj&((B+8ltI!cuZq~pzunZkjPAXe!W$^h9?!Ak^ zpoHUf$*y$Ku54mr*U#_NAe~G)@ji@dqy)1id7lZqd+{gGp=01)Zd^@i2DnCTXD!M_ za9Ln>m?K+ySQ2U6d0qe5zz(v*WKu>`SMC)IeOgqqepQ_F>-*FpA_$^whDSaD_fgnW z-<@ikfJXomv2R-z1iTT(Fu(1ONRvP}Jc@GBRMw>FAXPG=I1CjZ;&_WS2=!`Vy zhrC#Zd#2oZWd9I_z#5o|z*Daa6^6lrsfWr0iX@LD>p3$aX%qeskk+>>2a^9`{acy| zKJQtxF0^tdLPt{%iqJFIsvopl!aSF`0@-3mlz=%&#auL^9|XN0537I}IW1YP!n;8T zSEz<`fQ(69k2fTHCAT={Jr<~6J0!T;9PUCME;U)*&u{|IFQ;+(50S}0DWCumfSDOG zT6>kLun54u35F_jPRI&lOpjt~usFd7U$4&vKT?WtnDRE30(MBmIed`tvqF*~pJ)Uj zVb8074c{WZ%R(546|Y>ZdmT0@Q%1s%DRnZHoZx6&(g9Q9X2C#$15?55xI*#ltm$tX znnd}qLKE`ca9yEaBkSj2OUt(RA;|2pKO;3Sz?wBAGK&5v4M$q1K=YKuV3I-$cj-zs zuEy-^!RdIjx1v92lQvq4Mx29fW}S8aBvel`Z?zesqXrI88Wbgi{nDk*z07v#LF^6q z^hvBM7n>}F0KP1jNs5`FJZPnB5Eb*2IQ7*xHd)=>E|Y+wCMYW4wRcxT>z`{X*g>Nf z%rH_(#t7|`LnazBRk5@2H&$sLzo%eSMQ+ashV7Uq97)cP%h`vUjg8km%bhnCv9&X= zo{NN{3Q-&|(wTO?V}$4*sJ`Vr+v+p75ul zHBa(PHX_ny%K9>ZE?Axoaubw&w4|$y)RMlBMCD;PyY3U{+)zbt7JHfxeUIFuBtLFH zACs%vnT%HR9OSpgP?|KXn)Hh#luA~{M61G>NHnWVPiGk!6H*Hn2T3Qa)gPn>bH~ap ztz_B_zoTpfcnUDU{IJ$h)I6*tdtPtMx}*nXJ{)0IFDREoG!p9#^yHH}rsIL@S$QbdBf;z=IGpp z_-1V{)>-g+F3Y}>dQZzWH?>VxbqBQ%R=UQ)k>=CF{si!yh9!%e)wU2>Y!sD;wI<57 z&Ngc-CHgdv;J6>7(UD7zl}kU!1<{HY>fJ`xYF_KR*(-GVm`xMr1(>8!n=af)iwsQ0 zBq(#@gu2W%82uqrZJVhpHbY}3gRCS+JYe|yW5=HvkhPPZ(=ojp1ytuMIm_!9yCKw} zd!y#)JQO=V(|5ZS3Puj7;m{`x2@?IV6AH`}EaegZ;0RsFq1u@y6X2Cg(5=9k8bN5B z;NTGq)+c*Ub{Y}T?@q%c)xb6iZ2btbB{yKdI!%|~`f&tzU*B3M*lb8+3p{@FD9UgZ zp0#Ku)yND6i*k$~`0~!__Bx9H`92s+z(TDt7vr@qad(%S(Xn;-85Kdav?o~LwkL*Z zaINuA->cvwccBbVy!F|^Oart@wbsAHJ{oe@RKRWlHf$HC35gg3_h1;wgjQ`*^ z!+*le{zDNGn(`ijqRB`LikA0TxYM$uKAIMMUiZ(9%fh+7IlXye zV7eMHagHksF%g0$0wy3Jhvv>bQg+`qM*+l|0|}reINDDDkU=7dx-gmofPJMgOF%qv zZS69t&*jsFhvZi`b`oceqn4|bhe@63!F$be>r7Wi(zDMW-S~=6q_Dzkt=XsUH+yXq zr#+K~8b=bacRsaQ(AO5tinhyM@22@0KTElML9a-#jC}4@Eeyvo^dX9Y(YpnVoW*^V z&e|uS=Q>;7e2mUI_-a+ZfHJ;1%^PpaAN494M5dC^s!4UY&YHJGn&Mj(liBL|OsBAD z$FT;3`EE?cB}cXHowhFNhq8-HDCXQ}yd8ut#F<$|O>^HR6CBZ$EO=f=G^WIr1?NS$ zijJu*DAHw=b~qh>P6~ib<7i(m63{XCv*|<$<~<<6kAK-(Q;ZhbWJk?QQckw(SB6yT z9?Ku!6(S3Ugw46>6OES)Dz>=S25xTlV={3$E{(;DSgI?^O}kVKX| zS>18)Dp@!)*HN5KBp1h>FB*na6??y7hL3f?j-HxAViubIF}*ht-YK6=qj zH`0DKUzX96v*==zd0)xD=IwEuhF-;X;exkrqg6M#`#kE_a-Xs(a`ZCgZnsAv?$g&* zI_j9Xrl0U6%J1gk`Jmrj1dV-7k8BPj!IS52!h+wX5u}fq3z!iqUbTR7*x6q^07LbLx>X!gGf&Hh)R+5aju`(K4-|Cd7l-v&_pi>m)0 z(&m4*_dlP^e*-Akm>B@&f?eUnm55-Fc9ud$FDv1!uUoy(_)U_X(^>Q=kH!-oBmlBK6Sz}Wb_w}0y8ZWfV~ z)AH|o5UcDmyGnrfJX%0%h!DKumu!Qzfkf<2&0aQ<_~B{T(g!qY{Io*v@&%0Y4>k(` zb|I_y2~EhJHGPf#an;4UFL?C*>UCb^t0cuJ)ZQ>{rLb;ZdGpO$8NZtyDne<-#_sj1 z_k>qA!&j{HRA89XhZY=K!FTDnMY3y4a+>h0en85am|YKz?WF&@UHI;AJPGX%@ww@3 z`?_v;o2gB@6)WC=e$Po#MEvCYUObFLxtrF`b>DPU@u{BYPO#kX0%y>>Kh*k$o}pk{ z=s7=W(?7TTmXELS@o0)Qc#3gzbnWw`_YvQx_w5iE zB5Bg6UO^Nb1}1Wx&<*+)MS5s;Y7Ocdw9nms85JDG28JrRVA0!~p*gjbh2w1_cD z77QM>lWf*;3T8*JwO_(oLb}YLAl>|uhpB#!un2!0CV{3|KjC%cJi_qw2yw^E+PWW8 zdCBi~Lwqu?<|I)QYf;Hb7jlaQ^mi5o!~hy@w!Z4m6&k|7&+3@K)&p2mPKnDXy* za1!I-*lsaRHln~AW~Ipt70~%_9sa|ycZH^%o3Ty%@LWw-( zClowf0(9ODsYeWp$Zm%}ZVd3G|1=E}s@m?Q21CznZY$(khrm|%{-I6y-ls)5wNBVY z_gZmt75^0=ezvej_)36nc(qRWs`tav&v8M9Q-ArRSrnrx8sf`1=)&?Bf%X!P^iN6) zG_DT@Slcb{k55ep8Zo)1E+;unebf5)VZqa*a^Q=3q{Mj%Io|ij z%-qil_&>E{WH3{97(&q6D~9s7MPhLLIi4Dsw?8dCw>=Cv_pT#yFduIpbkx??faR9r z&w4z~9N5l-ijK%Ue*O+5+H8g&RZ2`#YNv-m;V=B;lqA4twO8N??fn56X*bCvk(eiA zbq7U87z~hdL$-c#ml&)2u!D>l;4NYht>`{h)KGKI>-RtncK*v($)A!O?JWI9l?U~z zk)ji?hdbwo+UkT9@M*3nphlHQ-Tpq2Z^q}ytD`OXTQ62E;yn|tiU^jq!E38q-ewhw zw?|gNCca&xwKLyTP?5!U5bA(CM!6<-F{fN($9%~SXLvmJ&ATX6!^S0uSeE_^lx7a< z5Ex%znom)+FtXq?7{}!mXq>ijbfR7Af&q*0gTW^2q5w)<^<$Is?`^n&h*^7Rx1UkP zj|F0Nf{{-!*7x5<4MxllkX2TdfieUz9O&x|O4*4bKbl8mbK8I;6>$svk7rVp=H8=s zW==!uBb6Hsugom$#}B9B2v*a!#{8CCnGhOT=|!ubp}C2_$b6> zBWhUGOvE9BajQ-|u3ji;GKETwjE!|x0B{L;y3s`$j=o#h6F<@}HeN)29E50pyx{&K zoJ=MGaIGZ7fWnN1_dx{4hN%Pw?ACwJz;teWpQYP~ zjH718{J;vHaY$Y<34Kv#*RmPUX3s;?!*WXO#6IjDmT27cFd=g6rk9xwLe7 zw*I1jcn(YYQ`I>}9i9=8tnva!r0RKzcxl-m?Lx#R)x@UcysN(iHtBeEG+QOMu?1#U zn7~fL)%&*B%HQ>cWn?)%474%^W8m?H`d&cHfHk7*W7l_bU9`E}SocAL--+h*4)2MK zMoum-7+UAWuJBHN)%C9_R%VUL zFU-le1%=sLcJQ__Y>-oy4gEL(ywrl3yn#Ft_7LsV;Xu0gamYD@vUiuOM4P-8*O7v4C_dsYYPFLKyX(8<#Aue8x2U6PYm9UTP3v zUFvrxu)fT<@(FtaQx}>+qtF0Wb=Bs9HL+u>XXm;g;qC2ymtnDw;>U(jka{T-v(j2& zxj{FscOW}$08!hJN31YV1yZxCZ;gLN_!i0=?H_K~-RJd=7TMo<-0G_`z7Kc4fQiCs zBo1fLX*;YsZyEBvX8b+C4EK0?4pku%7@#eK_TU5@N7Xjm0I`QdaEk7!KwFvOEgzK9 zKB+A>^=gfu_NL5kcLHxnfdOkcsc9y|&6q`*?F*t#eo&yvcIA1%UFDJI^_3|_a#UqF zvC8t6{qEeQce7iXVbs$85qPA^6lFnDpt#%K_XT4812l*B%4PgFap4K3h%GRd!$ zi>3M779AI`J;w9SX1Ng_c^zgasGHuoXWlTy8Fs$;6{9x7!5dWzuk)ly+exO2W2#68 zSs0FF+VRKem!>(j%zSpQF(*8n?(qKfaO=!~#^mw!TTqb!(@B}6!Mu;@QSZ1slsY=W zz*~{JaX#!icS5P-3B3D4yt4f6L|PdKBLa@nZ~p(p=*Pn3;ff34S>hhjqZam97{>(u zG3%yI4|FEPy0N{O{nP3et^C9;3?_B)R^EffgYcs?B~A z5!UWnKVxkYkCC7m=HlM@*c?MH)G!E|x%^=kt5MpJO#P~QP}?;dcWu-@ewOcWId*%R zD)!33svt6EnrbuM4@KJ z%XH2co?_PVb8XLyHeF~U$&xEJ#&J4x1~(Vl?&WY6^fep~xwDJscuTWUd z>~Tmr0|i_*fT6~sjG+yqN$AFyYbR&33k*4My>Tlepdt-OmpoP2yuwa z6F219A60#G^fJSZm*!=&&yh939gdH{w9Pr5+|wtlv?0ag*Gtu{i52jbVb7G2u0rJOPU0**+a{A zMytMkp_`#huI_$$X+0z{-Q<-@<8GP87ym#g*tyhM-spa6bOF(_DCIG5>2l{IJmA!t z+TxfbkKI>&qkz{R8;qHks5ZO($W&>=kBb@z#|hgsBBf1Z$Y+H!)jA0)<}qAYeRcaq z9PW?=D@7Q~>h8Zpv*kmuovUYPA>f6MzNR6yvn{scHeq53JsDdXpykKZSwyLh(c%KX z%c1XMSMPjgcbUw;g>qT-(KKNNl5XDV0JpM_IZo4L&6mUaw%?2_;*gBN#eA69V-1-D z_O;g3A*0OeKr4$3AD@9MCqI4@liJYbqirSsu8TCkWnV+H&I7u1KkxXb$KJ8YfPF~O z>b3RRjaEQ6+_2V0KaIGsnc&FH@af0`xl7l%vHfMhIz*|hG`aEIf@f~MM^G73GqW6f znn3J2J+Nntd2sOz1$cU0__pb_TT4{y^(baRf|pat=F=teEsX8i4}CeUBl0>vCaW(% zXTh1Ji*GWM;<{1t7?58{&2my%&9Y`>;w2H## z+?IZZ27+sOnV6|7c7#M+xB`M-YG_lc?ce%q8Au2rc>}e16Ca~U9!tcC^8tV#!HV11 zslvne716J%+MPLruu~!WdJ=>8C#IKx)^C!ZM3W|w3qyTT1KJk}2* zG*shjIi(S6p2YdtIK(qeQHHY*x!}?7N~PO0(g3$r7SSLRp^tKBg&&2BE3Qs<=Qoxh z#gSJ%Rg8KMSUs^%GsJqD@Ef zu3ho@XD+}8@B8P|^u?Em$NkBAa;{jN&&Ccct(O>t$)m`OF>nclx_%#lat%3&^n3W8k+-^3bRD8(=q2ucAW z!c#{lLe%ABm0x494dSUpzi}-6%c#-i`lzA60PG3$@`>7bz+IAe@P5tUh1F>forO%I z+g50tgRFBOVq%OI*TbVnl{2xKKKG9NqL73gi60u4*R(flma6VAqtWqD84YXBb%k>s zFVk{(12b(}Bxo5R2MZ3IOoIznmWQQx+e}3l2=zDX8xkc!ITtMdEnQ6Y;SEpsI`{?Qk=`82?K32QH)RH)b*l zCjMqd^%(aux7i?+e>0=;H#0s{?ATRpgF^gyerO*n$v{gPGfGcbDZL0a6HXaZdTh3e<#&yy_&8va`MD;0@i#Lj_qRGJ zq>DcWCjtL~S1~4%G4S_f@h)ORB6W$sHWP9rEFQ^7(DNBkC%lU9Iu#9+nN6Ne)irUn zVx!*S{H-{i7OaUQL8&S>!0JFksm2Z@p1}ynlh2(7;@@S=AJDXa_?<|<@&2uhj`#j( z{6JEGRgL%(->*eACmln+AksAgQ?T9=AAmO0hK;N8ConWd?!;&o;?fLb+@m zqmk@v7%gOTr?^u!KyS7rL&^MbsYjo4neEyhb`AdWFKPVs&5Tr_v_wkj7<4P?+yl*;vI(ZIuRDbE3GWnHV{f{7R*zW0o2Zks#)p?9yK} zELdoNXQjcbpC%b;KQkr~31uWGT2V+wmyopffyKKR*hw}~DG*~*zU!@35ZFDVNDHnLAJ^Dh<*}O-UwKBX1KwZC2jPeh1?Q1;QZTCs)J^ zkq|zT$NxgtpzU(Xj%qi~5cjRz44|6g#-y{zSpN;G3sq=^)B=q)YSMKq)ACb5qT(kpoyckZHP<9yg_-q|DE9I+gqx z%p7~KfT?BRZR;#Cj4b3&p2MJuMKQWZpy!nnD%cy+FBLGQWLSi*F#UV=GhsB_6hfuE zMFoZC9xIACJWHG`L0Xt*Z3EWmQa?_0V8&=(&4rOpteXC$POMt{bYQlcB@EaSp0K!T zRjFSitT1bNWfqHIn;Cd5<~-4Qr^rND!0dF(W7VqIxgc6`a!(hgRn-;vTAqcg!;weK z=H>*rB~Y&}UPy}e%qT@k;t*diaAFHk#Ln7$D$2^8FkzE^|M22QX&^t@9vNW}#Z5Az zx4meU&^a9{AtltO?^PD_=A#Wy+N-Y)qZKcTe#$Z2ILd=P64MVTKBk7|~za#0f$8die z+UomTjCOay5{(|JWxB_b^X-&`K~rJE*fJ)=*$y1S^YMEV7ozNtJ{0fy^}9DNzHO2HKhffTvQFe814_u3q@L}4frPBA?EDy0-2@bH;6xM=#m}ZqC#{x+ zBw4ECTJ{SUjbK59uDNcCqrj%FBTjEELw^aADuXyC!+7(oLX(lH_%!0g0{uJ!xp3n= z$8kFPVU-TJ-9aDfEnn=ewh9C6*LI)fA&#t{5ccaMCRFaIF}pGxElXz%5A4GZRg@!{ zC1D0>9kOO3cV3N%^zbL~`03IoTWU9r4hd3}*-cRhoD_yAjEkHrVBsvp1hP_3ksQ*- zSTc)Mh1ZPYjl#;+tDPvLB^U-Dj_Xx}}dz%YnIUU|w?;-a0CknF``aM?Vv zRsKTI1IT&=CjD<_%Ri#`ceeab<@?(+%Ko=!l;dwKJ;z`D zzxv1Vw+EHu?|2-4$K(7v9_QcjIRB2v`FA|de~tHlsfPc~%Kv{y4ga;h|M@iiFE!*~ z{9j`0r*zh1NJj0wb8C-H0cj3DfM~$tU@Tx)OC;<;B~adH7r3bh%&_v_xBs|`>|Yo; zJIhU-o26*ewB9w;lEv=qqPt`d%6Q*U1j%qj?diNI&Yx?CUUM^>P+u!ha`>1jg2;r>k6hJ-1SIx8G zzMkJUSH!x@2LF7ycADibAw?Up;Ah6%@tc#L#RWf z{Aq^J&68u3FlQk_Y!#PWgPu>)C(jJ!Wk!2$8b6P`3VvI;MRFhBYgXwqkI20s0xkj= z^s~&WPt1Fona_fsqM(TFz`Ns(nbQysqU=XRx4q3zhJ{|T2JEaczvEPd!a40f!&;xQ z-BhWgBPh&La>F9Bn%IqQOlAASR|)GMKDGdUIp~!P8b>SN*T|{2-kx5k?iiU;ixxv# zXPL}SvMm^ZmJhyQyzgggvwO6?^knu}Y(1A*9%AjrgXT`k-Gx=SrD-|qG2kBQS_eV9 zVxC((+)3j+w8QGkZOqC#2NYnFoS;l{N3hMQ6DVvzK4cqooLrS9@6(?1%Ml@>ol-1x z_2opnMT|B{ux(mNiSOcb&n3xYe+1-|yuo~W8pF?j{cz|ATNjzAre33zH9Lx(0P|Wr z;@Rtd6t@?*(Aw(!+N}$CBmaMhMjg)MACV#w4vG zT29U^kv%S2nU~bB_rs5?o?a_SZpyiCRhlsM&x455SZbiPVp1~EODoZx)<5sh^k0vg zAq{Op!_8qUD}7Zl@NFJhVpvJozx|>9Fp)0m8^U51tD2K55e zhHNVJdj=KiST`F+f8blJsU3Ki*(gWb%Z$RdkVFq^Ms}XoC@nQpDJwj`W||2*F9j^| z&<$MO*DBD@B3K(V!bo*zLHcvOWg67sUwM16SI`%P3EOi=0#mQt{SiCO{JBkb<%FAInE3F{|;i|qW~gFGv$@eT%Slu@9X1SAIYwS z62I5i=bt}cXLp7E3M>|Vbi{o*8s|&!p2_9KDR4_1^L1w?rI~EU3%gchTP(fO_GyZ_ zs)vO-1Uic0hT^yTRGHguRhDK&CO{`j0$IwU2c)86OF|oF-N)Jr4sowYuq;sz>1*Lj zcH4rq`Ki%uJ1z(B;*9dG)>K^2*vIA-Gkr5bO3&tnQc6BDD%Twa*}Fk5pKa&pL)d?^rgSmrFZTLEPG<gQlnz%BkZpS|R0sS`Rin z#^AL<8ZwI3jV4n{YqHh1PeQh|6Z8H6Pu%2?8dkDHTCifjhZDUW$xPmHGj@w%c%kf7 zODQFSUUN1T>bFA>8wA9;$Djz92KG%n5b!3Ov}a3*DB3Q0k6ENEjc|$ZlT8Wa(3}o> zTKgxyxuwfhWBOmmnGU-0x;>;(@lk^Lk=oNyaFlmKcT)kMQq~gHe+ykbiKnIr$B?{1<1*}hy)t{)0@tPeIc+r$8B#$?Cpd7JOv5B;~ z@;HxUb{qpi%rNa*;Y|>c^m}@FTcU~|LSq4|>gO^xg?AnTzAox_;DK=FoGeBZv}cYG zOg8vXc;{l>7~%<>Gc5f+b2G;<4hwPw+M3H_m)9>svk5oK(Qq^pWo=Da$wer=4h1iv zD?LYS<@tm~ElwlXDOhw#52@$*6y3NM@ukPM`-v9!UC6G_?L@(Sfq7*fFgak;y7B>= z2|I;1+++-AzjqDt+RI)8INzyb&dpEHA`X&f+AD8IAo1_B0Q3+5g!Sw`|EAcJ4NQPh z4#PN3xrIu8#F|-GZ;$GU;!lHuoVKyuTHp7ND}Ed|cGX<`Upz8CGg6gg1Na6CXQOXj zABi4ap9|#97v$D>xxICT!0D+mU6JSI9nT9(9cAF&$vas!pC}(oxi%Ui5Wue6*Gm>*fz7(4%DT@!QMzqaGA5XR>;4cLm^Q-Kq9^f#NT^ zla^?4JLUWqU16`Z;i!M0Tf6u~5IL&WUytCMS-$etEGWs(&8*H%Q?G(dK|!*^(!5Rb z5$ybwqfqDHHTyu`vPPtY>lFQ*eXZv+`zYey7@3y#4r6BtkwnEsK?FS$!>RTi5WDav z61Py=>a6l5V&?j3!fjOi=ht&R)LWD;i=vA>uP;N8K^hb z*U3{m8YO6n#QWn8ots!o>cP86tP>UYH6^Euh;>UztxQSwAMX_HZkRA7810s3zN&-Fw7;feOkgs1( z9iQJ_0ViuXlLq*ZwQ^U0{H(0K5VxY?fF`{*= zEwezj2@KYciW848(M)9b3l68<3B^hcT0XP+q?leI9Io;+nvhEGG3XWxu3LZ|_@F^f^F5~1Iv*(adqmhRoyxuHgCDWuLcBn@=Sb8}^)&|; zFO)etx7?kkS5=M@Q_e~(PAL#4c$W2(fgbKFR~PSW1u0!;t%AnuN`!$&Sjd!>{T#c} z$#YSdN+z_~gUBJz0@pEqK%n4S>cYBZpG8(R?ZdfKQnQMlx2Fm!c&mbj0zr%>J{0p( z{{BZ;cq@Pi(oA~c{RSH+>HBaInlB%ijQTTj!cl9>t3Lt9shICVV*()+ZG^^7i|=?6 z_;G@=aAC~XKIWAJZg}tItVMY)75rKj=$QIdcG2m>>TuZo?74X{>EDl7oFmDY(K@5jgq$VM z&c!q&W<1TjWf_AK8rMSFedh!ocT(%)&v_*=QWn~K%6S!TnR94k2)kGm(>tOLoaCM| z&#yn>>0Jn((Gy!)=jmN4tmTqrgWm5a^6t1F-K_M4kWA>BC_a94Nthrm5hW}0LP}qtnio~ zHl$))Gw(Q@e}^OTiUYxXLXhJ+b#63@5K5F7yJBPjb8nCV5Xnt zyVa9)r#o#fyP@4r&A&(aVv2=IbNIzGSf{oRtC;GkD z{dASL%*`(7eOc$!U4Fi-sFsRPXDac+t{Ff>Ivr{8#%2(IRJY{-i89lMW~+&udOUWC zw7Y1p7#K-uK16HFEsiQ9#ez;D3fV$01bF#z%t6jWlTXJED2lI@6#5Q(&$48?ZA_fP zv@Z<2%M&i;FDb}94EazvDE7}C(@x>vJ0@;+1Hg0z0{b+>UkUR_!s1Im#)Y!rw2F#T$xtUJ^y5L~>|e2Dx$zMGPLs@i%E#!E4qO zno)u$W~WQ;tUqasf{TjuJ0OZpisD%Ob9^$tmz8%y8NXNS)_lf;{&JaHB-zyo;hrKJ z&l;1efdM}FZHsh?X_#3h?P!MrF{~!OxwqVAifO`8{ z49bM}IZMeyG3IeQ5v?-mcQ)fJzgu<oVBcB0uq$3@O32aj=y_5P=8BWExe}8V z;oD~^QeJOYC2={I%MM;q`m$Lg8&EGixbpRi!wQp$_^iMv;ogKkXC=R{qs7Z}VLwfC zOBA0wvg4?^UO@%sBoW1^v#;mG07Z{y*bcgFl~5B-YRTm2l6Y3vt;++j&KngvTjo~m zjLL*NrMJVi&=XzGiiczOcF%g!-k$Hpl@BHx^;)N`bllXq50Od=MKO=?{bE}PV6cUn zHrp`1%GVcT_ck)tvF!2HMst-p=l5e;3xgt~bK9QZ?Va79h7s$zgtu$haUOciw^p0% z-E10}E@H+Oc!KMl&EVlDn!TF`@-(YAt~jV$p6a%vJ@1tEMd#w0zDjkFI*4wl+ew|s z)p}zrg^=AphB`SOyksc0YdvL-WlxSzIv6O$@OvgA6*$2+`Jx?+^G*Md-CvvYx%E#U zf>qCGdaSihcMU7-oThU3{9F=ifbiTde-qW3M8A6X0>>8vc<&nFJ@I2X?8y5R{s8)w zqiK^`tyJ_(0&)RINxwUPkVv_{cK0Iv`;?;Kj#a`k!Ry0jwvNB02YXN`8s)%7**USckLXsd`=rR}B}TIqF3P zysSgT{rC|?9&crPxn&;$GAr->E23l#CJ7C)fft=*%s*-K!=vbPMP$FT(0~41P)4aI zVhxWhKTD-`wxO(0=@emnSd?>(i8X`JNC(?DpU&8=oIFM!oKVPpA)5Cn)#Q?|f4`yd z@qaSFX)Agii&FHJN9y9sfE&maCy%*_@QpcGM4|kE<1EArJW=#l4Kn9PCJXfRfBPW;i6JhaU&KOf$P*H|6tRKIA7dR$MY^u-! z&y*%wT3#~a&^;qm0IFJ$)^sflUv*C0X?0>ur}&7(0Pn@m7#A@g3h=yq9kQwuCyOsr zvfm6&Qf^KfT0nFZ>Jq!P;K7<6s3Cc|sn3xnqR?LL6XZU=8OxB^{uZB6kz=Ub^c;_p=5a?H&M&I0L^)2sD|YJW3_wci zQ`AN9L7i%pi7&y2hD^30VRH#SX-HpEG!$$1xd8zzwZXOub2L5EOxXZkXiE)g9(BI! zw%;SX7R-OAu#aEFDb=}Om7#EbPxEBF>on!$kae_NM* z(n_SWJ?*!XSB7Rj^FZ%;g^v?5On73)0OlP&U9BLP$}<6OL||cfSgM)tbovruK}9(aFW+37EWB7lsAA#7E(yGq(+0x zJ63?1CP67trK(522L29URb1dGV5LPDY0(X^ywUWo0o0Od#)!_~5g1!eAT_C^gj+jS zXfBh3KKEeMSVN9s zjfXFL0j+0!6nG#eZHKRvGh8KTp4B9R&Yf#^Q$Ziev}aR(wPeN_4&Q2k1X2=r|I z(-d4&FmBKl-78FPXVd(%4s5yBi<;4HR+;q~lP`k>(M>eEBhb`I2S7+AIz>(8bYa0B?L*@V z5>$v`Cc5Fx>9h5-3j11mUBIC2iYxD>Drf4mZ1bLzj@OZz_1AIG(ryt58f5o~5PuqD zj2g(~#4VEu^ESpz9}T&L@EKJKgwalEqb59(#QIGlzp*zAJxMktpmZvM5A~!dQ#4@- z8k`zByeR-$8)pV%0tU_4S@xkT!vYSPNQ8~};4(Cl*RfE#NPc3-n;tuV3?A9+0lx_m z>!gtLBWsR&1g!qUb5<`4M8CDo(;>@}=nP9(^OE8PQ6UZCF}4ipxG^)HA2a^m;_92A z!ePIZl0kkg0|(pfGr4~^E=XT8a2jL}b*(r9R1G0Ks5n$YcxQ#lM1X+POM+__75wpu z4Gz2Z#vD0g4z_nQx?qB7C?o4yVMin5nT5GKzLRRQrx`0ff-igknCU%Hdsv%7pR^Dn zI(G%RT0$g(A@I>{574Wu7iwDU>odgQ#YIpM-jhW{MqtwXVh-zl{{pGznMDcUmNHAYvY`MZJhJ3jdT9n#@QMEZR6|=|F&^ZQ4CtgRT}{Gm{kaB6@W= zKj&;Px7Ym{-y%?jk5t&Yu3r@On8>))nd{^13Z9?;Of>uRvzOcXttv$?%HgJ{+=Tjz z`{T^KH2klJZ+@O+hT@lzQgX>TXaarF&wsBv;>ORqpUTg7Or}sVO{yP~(TRcH_)v<^ z{~g+l?)x!V>+`TT9`wEB-244??jI`SJMikB;@sghh_Crp$+J>;_cysy^DnvF`>ot2 z_t$IPQheW!>&@7qHqHw+jqE*Mo5viF z4R1+fPZ6FkFNPsk@inu-kMW8$B1+DOcLS^WIUp}o4siBCwzc6mhgw}HrdB;whob{P zJ!=?B-&zd2PKq;0(rlc<{-TiO7C;X{Re)Y3o7D3UDAUCdAJ<}z{BG}5@IG+v6;y2v za1UYeOotwx_jE4+&w}#?1M;}c1d~^5B1_8oV>ydcjcj4KSEJhkoJ_`*;Wg=uP7y_s z_UN>0C&OEVW1}N}oCi)bT#B_-E}!SK-mk;f-mI#@Af4)alP|fqk)5ZdjpC0|yepMw z18{%Mr>sCd;Z^IoJQK)2}&#k)em$trK<|`Y% zuFi`FqWt&xuKCa?o4mXkS=8ep#j;CyB$Y}Z?S8c#!q@PBl=z$U!WSvF$*P+{Y--WO zbk31?)uw?d5DuMQdqepn+&AXJWX{s4_=a+b-tPTLUhNYoNO9+AQ%)lnT}shXdYd-) z+l+336o_Tv!Uj5BR};YjvRn)X8I^8i7X=`KDm~JV(G06YzqF_wc1a8;QT9?R~y8`gx^nZ@oy)Q(-jEY4O0zZ z$Oo;OQO?Nkr^W^(-+aC{pL{<)Ro`GRQy$LC#`}(2OLExKn{JRl+A7jxonoojt{$j$ z$f#!RJM|)tBwxB3;3MXt9~ufh$lmNy-o`KwOus*ka0*%>?M-Q;L8#VPjfDF75X9cn zu4}5r?akO);4gq*1mEfwX+(A65y{A#MTocaLJ2Uy`^>N*;71w4{NY!V?g=Lah(07D zzB_a3i(Hvu_P5jY#q$gg$eR~BewG>lh%{=yrD6{hQI5jqhv={YeW}9)X!VtFg2%l+ z$*~i@=E4v0&rNb=uIia>w1K2LHZ}Hx2=C3 ztucI?)r-St!H_dSua@&+;p5II9S6Gb>Bb}p; zHvJ#ey;E>z?Z2)Y+qP}nM#t>fNyoO6j`_wmI!?#7ZQEAI+UfuI%~fmGUh`n@vvvN~ zTTj*a4L$cY?rUBp(gbP6o7tpglJNI)W51!He{JlZKq2Kf9m|cJ#P3LmQYnXTO`@44B~q0+?4Qy02R6^!<)e)1Edl*x4byrX?c4Que0XM07SDY z)=h572vMmufWW>01EA2+Ro^PeM80&-nG5U_h4H(SB~Afv10&;h?iW+8H+%0h0@R z$Mio8FR(u<&zu@P-CDLl+`4V{>gNLVkk6sX90FX|Zu>^pa^5xlI6dWP<6P&O*+{bM zcYf8sX77jMT}tuV11g5=Tz*tjeSIRnDO2P?J|*0aCa=Z#6v5dsQAgIox#596#aONf zrmw;{Vw6em$?*Myl) zK8skg^;Typ7J5OnQY&s}=SqVM2}gi#@!Z2j}H#?;AAJOOH@BH0wq- zk1){2j~P>`&^PCcw;-U zqC;;T$2?cNzWcCS#?cod60=wz$7 z9Pwt^+KLQbrL!3gGlA%zio1549^=IfB3-Dpf=-WU#TlVlk23}N60^?sqHx?Rr%d}z zPc)3AIyG#E2V{8-Hb(A^+d8A_ zv;yZ$8l`=9XK_ejF|WJPQNO;gdnPpGVE_q~rR?fZGIYF*U!uvL8rw?y77sBLR+6XS zzDA`p`@BLOZ8h|LDY+Bur90dG4}z($>@I}$r$WI`ei!wHwSgV@w!Z5)9zIr__1d02 z)I4DoIMS@96RI;Gi`$4SVN`a*M-f?vKyDfO?%@tLa;RURj4ZJ3mUGbX+MRI_xhS zV>{@_2dyU%_tz?N?^cf>9=zzNQx7cCddv)r{Yp-JXXP-xotAP4qts#H0m@KebIWqL zGU(Bh*bW8sroYhPWjUHGaLz8mD0zFQg4@U!CJcp`e~K?n7*2Nv=u!AW_>yPxcNG9r z>}uVC_8LgB6YUFET&-myi8auQ5ejEEcE93+hi_EN2)h=%sGIEA)CiSB z4|x|vf)>2V{Zdo?Txue}HS+v}2>cDWfC@H<_^=53g(NZn0?EiA@gMsdQcy~bLs5s7 ztRnMqdxIe5kv6Uw1y&g$TVVoZmEv;Gf!tFn19K!!RUUmRx;45}+q(uYzti)4JO@SO z3dd<*4Aw_fBnTo8<9|XBTqeM~_j^bz-08u{9|AQIGia&JGxm?d;|x-PJKzAVC~R~Pv&lZ)Z!wM{Gc!}ho)rS z*HYtdCeH(vyIDC))kx1tE~ye@T7ePS(itfr&~(p3ApboZOe@mVBK38Jbj%;b(J#O# z>p5e~37!m&cy@w33c0`Ub)mVS89`|rKd9gB!;_)G=tI%ia zT-V3<0ZHE?&v}hI1N9lGdhk}BDIj#pH}E+tp?MlADGBP@;5J`H+(mmkRgqVsDr_!w zIjR+S%BB{aT4G}yEuFJ_tbd|=1RbJ|tei^-ZW&VUfp(iH)BvXd(I1j_3Hs6-w3ayE zhMUkU9y|;#e&{E}gGAe-S1dSJ>bcG5z_6l5(fzUv6%4-q-6af_Bp1*9=X!AsujsQ7 zvJ$0vCMu2JbL>^;=K&(_+QF%&$XnIk()>@sXL@a3!Kx+(p3!u`taP>X+iqLe`*sEHlqa=pb)4XbXh@mchc0vd1`UwukO4Cxb>#OXZhZi=#y5 zEBCiZkG(y8J{N=HPr~hxsRBhtLBIi?pnIF2V&5e(;|uzc_&P6p2#@h2Rrt_SCQJNd zY-KZFNAXXI4c?hun;#q8ZYEtK_cNVa)Pin22TEPVy}aHVC!;cB zY*HBqk|xPS79@*(f4d2gz+zT>0p_w>P=IA8Dfx0VmngL4dqWJspL!sZ&t0@XfpVE2 z7ua_Hn9o1(EtCSSwEkZ&6du@WjOjA!3Jp~GShPG;B&%yfZ4VG%7g2dG`+veufo2=T zuY3BBT*+rz>OtPB*}yQR9)0`E30e$KMQ*dQ$70(I{%&>eb~tz*!;3eKwKTqy@58Iv7OCH4NIl=uAY?s9BHXrt zy~&puHsd6?`lDTB9nquTlDpy4F(u>2Z%!xtQ4ymg7W}9Y z)#Pe0@~n<#pUs!xzJ{r@PBL<7BjA{rLU$iZn*$%_dD~AWlz3k#`p%9^1L-q`lRbL3 z`UpD540AYrbs5*W@SsYAY@RS>l(42LTo(=papia=8Hu;G${#Z+_*33xUYoHA*=b_3 zAzYxk3%}NL(2oKlEc`3sW#`eY`zesVq1o5ZKws*Ba>q?KW+GT_Mw6 zSP3-B5B#(8pKD;xy_!(q1v*%5gV*ViMOP-c5R7#GqDB`xcDA3hB;r2W^)O`6nb=WN&&r z0F&)*8~;1v3Ua!~wi>c_kAyWy&p5CoYtHs0dmJdV&De8Xn!?w@vh|^&&9YlJVkR|&vuP6Dxi~+03 zkG1qtU&{HH582n@Uf6S%M8cWXKQB(vl;qsDeh%Yxqjug?HfQ^kdrCN^@4RQ1#zM}y!()K7|*33aiV{4UF--6c|(aZQUG{)XcyB$qA<^%SYGvUIh` z!yZd}#}=zVjKf3z)rfBo?KIfk{>1cH^GNgjtYFU94q4lStZ}EkD}YO4FJX|2o@%CO zkPA0&BqPXIeE4~r^NzYOL&puxOE@y=}m+rWuh4C$6R*tkr<>0>xOJYiIP zS-4C1a~5>|Vq~E+#8K*;JJBwMOF!$WkAl2R10xk(!<-Qdk(2t&J zx%46#$bUTm`9lJJe?tJ_7Z}O=Mk=z$!!^(pBfnEwfW*T?-oGxz#eB$4P`u6YG$6Dp zUPrx^GT3xeIO7l=-X8Ld0~{kbclQRiZ_80C7VD7~?f3M;59jz*{%RmOFkx8p;X-_? z21zbZN9AFMIe6Kr?&W1-${W6W*gf?gi$m@^XR&!=e^fsxQ05a%eVl$UoOba<0+hXz zE+OD>XSR-OcelKjvGt?Vk;TKO*xYG4gYvU#ld+jw98{rq*ljWkA3y29I~c=t5r5%l zqd=nPW6cXGZ;4eRkEnUK!;pYo7e|XZ*h{||tQUkBQBgsUuBL{268}*4S4N_N z)2u?vmtN)}?DUMf4C1ayRgamg^bV;H#z}bH($Yl%gC_J|DWv7>RJ2P%@!V5cb3<&l z8=1nrejgbEHi@yBjg09U7+qGJKtIxNWqC;dHDV6wb_Uw;h@X;hB@}f*?^C`u!nu<_gY5cW|fuIk)sEX;g24e6*6FO)x^nZTZNzDvTV6P5o`AFZ-z4}$8g9LqkI^-8X0?I-1aGZCmjUP zqXf;*i(j8LnJ~Y;Ss}qOIO5t3$~lX2yNuucOTov=J&~k+9BV+W4)=}Dcg`A(6)J^B zeNwD{hoPhxmq2RQhl9uYofGZf1U=I|nHJ@~%`K%eQw4zvBjL}51H3Cr9>1%oZ%v2; zd>bSoG^;Nn-~P**h5RE#Q@rOKBI56ldV&!z|ABBr`}8PT-=?_I>_ow7A$$e#-Ks! zs&c4)F28onUeZze{My7ftm9_G|E=3}IM<~NwVEYW*?)=+e$ zW1dO6B^P47Ho?QNq6ofm7#XOb&-;^-F{fzN74Q3SE$x?q3oag)j0h_QolaHDLW(0&3QQ5@K_2d>O}aU zfVah03yR}NHL!bY!?u93sk2*YN(07oajfcEf{8p2}eKs1`pxYsiW>&^4QJitg<3q4v3;|^iY+S7L?#(sX3BpFzK9I zl28pPX@U-cWxQ)ZAh>?ND{v|y8Xc|iPK)=ZuZ+Q%@RSkd=nebQ)fg8}ye?;tE61uS7Uxo#8^-RYRxkTrZ zM7DA!^OrAXC+UmX$;{}d3sDraxp^1=Ua!1J@ zcdDD`7{OwYX0Nhbon(7wG+)%OkF`5!!r;D{)sr*x1v%2DypeBdGUx($pU)4J@}T&+ zmUx|VmaQ%lky)?e)q4kqFx4gDqi zHyQX5YuN2rI`mxBVAUxn>6o@p6nf6-umSi$8{&ZId@A3>3P9IQw4rVpegA`l7wJ{* zu^DQ|Ns&dQ`tRm57xoNglrIOn(LWCMR2AB52_60MVjYgUUqzNw@qF6BfaPjUpe}=o zNDr|Xl>rM9_$=IX7j|seU`HHwOv8;&fG=~Y3%#%z&q(T>`^QS1Zo%637(t*o5l&O$J z5p`=46sb{DSh5DP0J4LB_3PP8Am8#GGAkW|*8pC4I}(Tgv9HJUeA(BjneH(psV+`0 z`N*Fm`{O-zL4~NL@u(5Q{0`EsBS}YwjCzB4TQc4aTFw^|0sUX{b3Hzh7 zRdl`utHVHNh$+}d*$4btM(yQyL7mhus_&<=0p5w9rK z;y;Nd*B3d$-#NO(#ZTNEbR4ZN+ka;-tO#5sp9+xJIKJ4(rawNz_K-|Nr6EaPD< z46Yxcyycn^50D`8PyhIs4XqZRxPov+7>CGoOU~XiWbJy0%d( zMdwa8UM2MvTR_Cu9? z;Grg7%#&eZKT5`s<^WJ0FBnGuos>PARQszfBDqQ_r7gL7;VivoL3wPZbPTl6x>D1z zQERtQ?k?rnYOz@EW|Q2e0AeM%X+gqiSDjJ&a53T^aHsY^;Lh0K=DF)L(G8tCPJc*I zcWu^ZuRfk3CcU)GNHAKHc54!s%l*r28DQ3>teMF~g=O(hm7MXwJe#5jja;B_hLbZ| zO^4SnEPWxBSGpn6Z=AJ&1+tBs)iVVq=TgR#0{V;HiHrMUcXlmStcJ;J&zE0i1I){X z-FGR@T*~dqL*kMqcfgIf7VGRhG+u|Cc;Y3^_ML4s<@PVeuQ$?awKeY3f3;_gJ{w1D z&H^n=I(hI$Xa2{%K0rZx%gs<~!qsvA7LRBp{cO_us?ha1cIB%eQKx6^X_jGHYMY#<=Q>mBz9*4i zYmIcA4c0G7p1g%`%fJTTGQ&cjoy*ONm#DH!IQa;O*%krEBZ$EDP`U$ zmLyZHk_nlIGi?`-d)rR>9Bd-a9~z=5>eMNgUVq}$&xBB>gtUdR9*rtv>5`3zgn|5| z&g~}cmYuVHQ-p~A?qM}91nNEQ5D17VH0{+(H7NSP%>N8Iv0X&>Gw*0v7jDWED+!SN zX;N4#wEyhM4J{Fh1cn3n=zP(ytx=_T2FAY#nV9hv@&b;79IS{t&}=1Vef{iIWtP`dlU6 z`l4bIASM+44>R?@IS>AAn&4#mr#XU?=^r|Vlj$EihLh0dgA`CmGQ z`CmGQ`CmGQ`TrLk^PfNezle_cyWao#r2MbO2u=>J|3=5~Tg84^&9{y;#?66kZ{C3r zAf>{+1Mq2iUg5N1ZVlaBmqeH_g(gGa-c`{fO=?TH*I3|@xeD(^fw_^&m)Uqmeo-3eRO zk$qXso!qOByr0%ILO+3VDsHK8{-Y)Kl&VQTcCF7Z9Jow{oE<%H<-hx+kWOxn=7CoWm zO@$tJ_IA#?-u_HH3clZ$ZlGLuxxZaIK234TJpZR@p61ER|5JRpuUeM;N?zuN_V&GQ zu+m4s81Q;d^EhcA$lJ4;4||R{{&S_goeaTNfujPsAfMN{=}wZ3r+k*#XkX+d^qk%2 z+0zbU=#_v!5cd@(W`X=pYM+rK)MntDJ1Rz{@vN5r6i|$8y%sNH_vXI%^WT1X%)kBe ztOi{8V47C2%JVcB_FeAcSFp}nkVp(69IIe|$TCQ_&HX|14N!?t?2jgP@kMb5fme_F zT5;PskNEtx=fFEB3*`iI5d1*zMaZY7<4g5hMqNVmQI%@QW7Jt7a=Fs2V>T%d)pR`Q-nJi}1zg3Hp+ zS8F&VP`g|3soLNP`^OMge0I2dUIodXJNw9;{`1U%16)hnh6NTO%bNVhItUv z7YaHJk?RF+J9B|`56&)mBp*!0Fvt2^PMTmX4=Kurv|%I%!!5)0TZKA=BN((kK2*)k z-EPvu|8Y<@DoZJ2ebbZ!lCJVNr6~i@ql_iEV6De)4)7P2k$|bvWY)OvubZ_4W1(N( zAp)(`f@Vt9YIIgTY=Km@61M|J?z++xESg;cDyR8a^=}|L76vou)$~xRT8wS3SzleA zfRnSjLk|LF;EBO-FQ`ol50=te92%2Aj3?<@I^~M45@i{-6Ax?Xq>-=E-tU285okk) zcWRM)(^jf8^(^-G|R9M}J{iRQczv*3DwBUZuKj`h%mDQ$zQ+gSwdV zK0v=UoCqYFg5kT%-EYT@N>E%;^_r>T4|F>%mu{S`5bRZJN%YjRa5_HLxn>&?ad(hS z=s_qNe?caSdtlw`A0z60%UZotp+MOyyqHnR*GOz|hFIxm-4Y^|mq9$xZk{f zDUaZ$#jo*ES$o?w2PR8bM>EF;gbTMYnuChrs?%`Q0z>pK26ClO56lYGjB+Cn6qNO^ z+4K@AwMF$3m@brlb0tVJ*?vS~KtLXBz>e6+oAJbOWift*RvNWV|0PbRV4PUbKH+>; zA>a2%RorTZK~wND2NN*zi)Ld8G%5x&BMKJ98=^+r@qy?b#a30bf`W?8PU!`uEM@vo z9!w`P?HrgOW!#AppY+%`8ivOM#2qCXdHasIfSEK8Wt-s#NCsF0w;}K)JvZX^;(5$B zdy9mzwsC-JnEEYejSQf{R;e12qN`B}r{A>jSS1S3ArM^f+mY*qZ8gmBo9(NGktJld zS3NU+(RirsV#Y%1sx4i>NR7me=3Lh|k&;kby0urv6ypU$C|5)K;DFjiM&O_H1eG>c z{Dg=IlsLwdOvgyqcRf4(CXGlSQe1HI7zNnr7#9qAEp1-Vp^Cltt>AqAJ9O7s}$a4{`;XYwSr))r0N$VvSkioG_!)hkOl4< zSxy}XjMcG~W|z8NUcyB4rQO-rrxAJ-H2-g$eP>}FOw*+O9pQvn)(aH^e&+vLlP zgl9)iQ>9_n9_#hNWXlp1i{o5AIr*I&I&>FS zlRMBg7*v%`K-%4I{A&!8zs68{EpyY96Oyg66v8Py!*n(!LjYi-34Le%0@W9&`EkmI z0!DVEv%Ekw8Q~Hzv{oD!dLdA^P^K2;v?l2PrQL)Wh>FM>+qbUjQzx8-WF;#!-oeAYq)z54f7}oaM~Mt# z+H=`X{2(A$^#HWqvkW=SVNDf3!s@RTdD?aue6Dr{a`aIgWug4g{Zoz zZeY}d85;n(4AN9>%s0-dqQ8t;6k_r1rfuNXxx~X_cU;BR8(3)FuYu_rvhWM!Q81r< z!pkudj4fH4(Df3y4vu@JT|HYc145e<>;CRtz2VF$yMyKOowt3pX>ZL{O z<`!d8FCE!8YehF_(32gJ!OGR{)$Y^GY`_NFDJ09r63?idd-cZwh{V+}|^dM$-InVOXTUc1@Gz^qBuRI5*I-L}5+=ff(*M6nhA zakUt|5{t6cq0F8Y0%Z(if+SK}jRh*FUE0VN%mB^T)W@s?w6F!Fw!yrk+=O7|#X4D2 z47Tm@>hor!&2GzXIk2@2nz^+}t0V6R!OOtmX$d;SKh}+ECGWcph0og|LJl%0&p`+R zrtlS{QQQwN>Z|AeXwzT0o2=s-L%oLHv1CB>#ciTPax9T5gHIcBr677E9YhT<;{`}0 zWQemkeGqTpfcv`(4x?NQa4Lz=gq~3bfdQz&+#tcApIE0G19%tBv4mW%UU)ADDM3!I zz{TV`HZcwX0lI@2Pr<#Gs&U)DsUb+Paz*_E@&|rE1OlD1GXbL-Vj=Q%>oVhKJJ46C z({&p{r|YF0JL>#4wJ50+RS;F-d4sc$)^Tc9E9uJuwS^4fhytw#eBJi#?It|@n~G(< zqop&vH{JL|cT33|B4OW5@w?Wa;YK!vp9I?d9YX~j7L{h-Fj8lT?!E2vjuGG zrijGaCJ58Y$6ZO?P`Q>-DKnGyl52TpuoN{=xf-5@AY?zpn|7n`GfyLBr44IczH+3)~6o`;~!uIQ3MO3P8WiUH%dz?JKUhy5qFaG6M% zV@M{od7$Eb0*B9D*5lTw21$u;=qA0@${j1i!~cm@gsS*XjU$z3zj_~9or|Jm(0KFD z4*vma%H3{O|AZg%!QJTPwky&F{O~UGa=T_u)^9W;X_eda2Ix>UKJgty!4>_=PAB>+4S(h^zoj!%_6=`*wHb_qk)yySwVGG}uD?q#YH$ zOL(nucGTqY8t<7c=viAQxypw~irPd4Dy+jLvA1oLq?QH+>=gj14Z-E^P>SMg5AIfq z_p2kTzRlmW#_SJ+7!=4QyMw0@5a+HHc z!CW({--V(P4L2V(qbzw8yJ^nWq6c{T5J z8MIYJ9wt7u+~&+?ff!ui&xcygXL$W#*7agjSqP?7iDJ2Y!GK`r^`{_}hy-=cND2ia z?de7gWaX0#$WUPfMn>+|H<+XyN%&|Lv{6`^)-5+2+3nd^?Vs*%~$BTE%&>MN9&HH*KRH$~Ri$Z?}%= zx)gIvQRd}*vtVOvq@ca=vB1GT44-+?8N-V)LO$awoh@NVh{&-r@M}Ln3%E;@;uBmC zF4Bc3Ho4an^hxfwLp>S-8Pi#AL9%^H9x0t@#w1i}JsJuf{Qyw)DDAZiJ7&MM?2H!4 zMX;PL@SOIOVh^YjO&KuNd2lc+FL8JN1W4BQ6h^Gu_i&05&_-K^&bJl$o_+qs{0&Ui z>P)G33~&_%H;G0ZxAS4teJEUJs9|Vh`8;CAxeqNy(ZbA4aUtgFlm16{je zzkB~hzQY=>J+5!8mwbP;np)+rBoZ^4`oWd^8rA$-Y}B%smK#pI_EZ-k&3+vocKY+FMDwLYJ_x5^dVbzJLYrsK1uwA9#(XT8w z?Q1Vzbi(6u@6+NZvNyQYygjTIb>?T3JlmTjZIK;t-8hEN>Q2?;e>=CKoK%8RoPBLj z9w)t$GBC_~;a!-o1Pa;_UE1S2uSDn;-g|dr>@o!B59M=#0u|uj(Lt@Z$}!1vSidYx zsuM%gb7<*jyfx=M-+R9t+OAgOB5KsGW|!xOUR-m!tk&1Dc3@@{^WAWZuq zM|ricyRJu(b0)eP4BlLaVY*RPUXkNOoxRiy?=4GX!nu~SBFq_=zamtBv%~)8WX{T) zPls5Wx?@}7LD@2``}RWhXZ2Ty>(quEXkbG^d7G7jPs&B~u6CYmHIv2xo z#rECkjv4XQ(xq9KVDAWVHA!YeoL(K#87-e(t)9x`@44Th2D32$=MjnVzkNlPRSoy!PglU z@2F~wqpD)Dczy6aaaQMc6q|a{2Ti^K?D?pzNdDO(2@1&ce|*T4bhqp1rs8TCx$@yO zllpqxmnuV;Y58-|h!aTxH|p@%V+R=J<)D!X_^!mlyHTjuvgzt0bP=K?#Vf0GA&lqJ zinZR72h2^lH+J8mTgG*N=4c{B$A6>VTq|(!X!)&-0r8Wq`iilOiCJg3T|iC~_p^U$ z>06??r4ujXct*>cKz>OIwOns}p5(^j1hyQ()*RmwBV^EC5fs$9QXiJt%pyfjw`K%v zF8Et}h}SfY+*+LmdIRKJM-u;D*+r{M1Xds91yQEH)YXr+ZjPUOYfvJxeL31a7-L2V zNRr+e0?|E;dp2eeG!`5sP!IN$jZ`Cq)xQ{T9<9-k;z5@yZ}V{DskgfG_OE|oV+EA$ z5pG{~AznUFvY6(4cHCYiYY7r`r!siYmRr9c)!*c&MpUv_9neJ$v3`9o z;Ml4zmzG*%<|)WU!HDz@eX?85%ipPy&=8Q=6VX@OJ`M#=ErzpM3vvr)mRXhAgNH8u zCBs6=M5i#4Lvq1h2Mm$G;B2!kii|k&471=>zwqrw5mMgJiq&iX+NUGwdBndP4^Xf< zcY^VX#fI&~DkLOZ6X8*oC8@y=3Z8a6N)J*`inOuBWq$no;>eRX5JZ9?=+?(=eiAOc zv(0unB}79NniI&K43gU?#5UhQqQbqc&cZRb7C)T0U_Ys8(WD}d098u_-3C52utqV> z@SN;K%-Yge+>ozK9-2ZySnJO?&dBaivW=`Y>Anu<{f&x?Je+Lyy_&p4DVW&5;Ng#s zh;%+bHCIXc5Bv!GLcl(+9yY?ow|cJR<5%GrE&1T>iJ?qhQG{_6J!o+|aNA$|z_(!1 z!fooU6A8*Gc)lZ0;XQFlw$Tei!K0Dv&4B)E&g8-Z2R^i9bd+NTCjSu-^kVgKHuU&}vSZrB z%b0MMe7BK_nTLS=G7uC|sN?Fi?!dWwsXD4=04gl|xYZNG)*{4X{u&4%+7b`6yLZZG z#o7~t^S;-OZWEEPB}r@5o(LsL6RoBvL2Q*{C_4g~;wYUJvmqmf){Yub>#9-!e25Ra zZ}ZB&70T1u#}>!VOQ?rap)iDVVk&=CgG0YiMq%F)jFe}yJ;AgB_A@@EYF8?PWy8r6 z9ELm{$jHCrLmv&t7wT+4sm?}0&!e^mNpAvv%*Uf6rf;G#@XluQEI-W0@w@=w3To4@S!Tz6X&}X4lt&USrJt z+MI=GFg*LJgvd7&`ALU3F|%_(ZXzC;10)!UmQcPEm6s(&zK7=Vw-O?C4y`THnuOA@ zJV>;0t^0#sDT|}&yv1~-58gRD{Mz3V2`R#PPpJ?P#P(3a2qmkfqT0=UG=@qiygKNj zgtOHs(&G4}(F|v&^gev!@fxDXAyX6twV0J*|24o+1)ZG=fHTUq+=3 ziwjdYga>IJ2P?{uq6vR4T+xFQ_TzjeeJ~d7>4mKMOGA(j$}zcsCATNJwJzS+Z=Knf z3lAuhu<>8~Qv(n6o88tppV@xTBzoPl@kY7^{JGvvz}QOFXKfjG!nWAUQ&AT5gvoTe zX)hrzA|sEeNKAxg=0;Z5tjFO+wLE{_qqLcAxY(p(=$G;n^Rv`ehW$+vhL4MIMenLE zjZsuqq2=z8gIV&Sf0JOF*B2hV>_fgS;sdvjVlSi&N3R7hBa(oxUvgonKqiCdP$ev5ei&}e{@SB z7E`VN?Qo-31KJK2@vnn`*ycLqTD5rT^W}Z3>k~N9tOM8d=w7wecP?Zp$p&L; z_?j=<-E}!4Tq}JU{c&|A^j=QEClZQrp~2Haju#%a{m<1WaD%K3(*Gg$`y1W;&#BeF zs`LL9C3CR-)e-#9s`GvID=Rc+q<0Mv-x)+XmIP^vct^#epCaNX)Zhb%D;w5V$1ab} z8-1txSL=wiKS7acMSki6#!+q$Co)n@Wk+cm^@t0iggr>Gzl%$;NPw$jSSNr;u>hBM zi?4v>5+MzPp_9>O^iU_p@d$8G-pWsejyc_Zoc&Hs@XUPNFnjmrh#A`{VqUs)XsmMH z*h+62oAsd^GyOi!J2$qw=IfyPxbZb~T&b2b8Wcs}T(r#%_EnjW0K*!Si#C=mVpT|G z9Q8AA>zogqMXV($)iddioXNIGM12hQ4Wo{eGKlZHE8usLBmM2^FxRxErk>wVZxWoO z6Aq|UnJgk1h-gv*53#aRO5M^MXQs?rs|MwMW8Phw<+v{0@0r}PJwsJc5BL0ui>-+j z02Y|U@JQ`QbK8qS_ID3M`CSNH5jjd(-X~8&kO1+J{N2OVYv+xc+%z+3LGeg_$}1tm zOf95mxs76}+vc{mN13lR$|8tQ8la#PWR)MJOjuE(IvJ0i8NrdX76ADtgG5P<3OLq^iz6u>*)m;n0#14q0F+z5@i?|we?Hg$O{m#9SpS>TV1REehVILR{*L}`-EF$T=+Eq5 zXFo}j;ePRiCEvarnw@=u75M-%BC!9MQb-l9tZ_eIkC@4t%8F7hrqnJwK;xr&eb*B5 z`EPv#->2i#t1$h{+`=M}{re0J<7(S}-wbwxJ7HG%kUrVEX9E=`zd<`eJ%=pIDsCM# zrh8Q=p&;)Y6(ff9e}>uR6V5pAe3x1&D;$zB%h5n!H`^32XR*aHIg_pGzC`0#&e!U!TTyBCq^j zPBU_Rxh$K&-Y{bc8ACr`l&Mp89xDe17Z^UTtHp0sAVvm5*ZCy>bN`;|{f& z+a8rz19h2sAO5^C$%egZxz2PU82m-Q=X1zhyf@Uc|HKn>Z1iG**KJ_YLwbn6*kHa+ zTYaXpDB*PEIW^};DEP5+eJ`mvo-6Dvd~zPcO-B*BO@C}U{6kvUbov0HlK^OJH@}Vs z)?U>!yai|v=BrD+Y!F~$=kqYW`~Z!<4$PTlr1b~5sys`Fcn)#UGsZ_)RW>daV?Sl5R=>k8|S z)@ChqLEBRs6(j4*Xd6EbpQTF}SN8QKQWWJJIn??UY)^Wh^6hD>#&svW?E~txp#urB zt6SN|*f=)Mj%`ARSrUkr2beKb>au03h=$pBHuzr`9Pz{d)Le68Gn5O z??lB-IOEc+*KV6Jzu`uG4~kGbaNPf4+ItGWY-t8vbxHk*%$HvQ!wtol%4roNqONx> zLA|p_HND1C5hYS^!%&N%caaDT-sXL@>xWDh9N2e45GmMs^857>ie;SOxQdi(+HU#^ zv6DEmb&4jSLy!sf&^X0%uMe`F$;Y=J{zK^#!`QlCbrN5i%c(w3o;MhKc#rUKi9mQ; zOl#oAXR_(XeQEz!ttymtOa_WGKCPoaRp-+3fDf0Ixo+(?N-q-aefu)@CM6ekbG3cc z%^ZICbR#!Y1sBFdPo0COo0b^;i2X|s7^eN|oc!0{kn&A^(I{0Z*#qYeayE6Od(d|M zW=rRjYYY_q)cA>QV;G6Qmpu*;>^{`Y=mG8{g+$j?10ZR{nFCxg(860R1D(HNgS;jV z=qdiN+gxbj@5|_;kl9!h$aw+{VzG79dHX7RFpJ>iv@1Ll&h6}r8`-M1_oX!)8-cI8L-4YwZo z!CIzpV*4jk>Ds=dxck#^Hgc`2ww|K9e-;$7JC-Tbc!D5FTCtx3r&*!mZV}gD;}SKr zjzPTM?(e1eJYP9b_!{AFJkm58cnkn9==RVuK95)Y`DrtHKdm=m{D4y>AxUWwzr_04 z;e51W-{qWM{?wZ0a^tZR4{6oFACT&SR=0Cv3f8Th#OL z>DzsWBDL=m0x$X}a$*|BKm(%js>TIA_1uliWW9!PxQ3Pu#Ttc+QpMje`~@NvqlS36 zm^l7w+B$iC#+8XGu{UEtb%k*SO_Q=5c&d*E=Lu%J8AuSG=Nw{jGsw=sAj=AfqZP>^ zv`I}z(q6kZvx?O`tFO(KppOloxS8~;eWhz<(b%ARx`I*QOLh}W`0>67X^+7mlDN{04$ml8nzBsT=S|T&KP2ooiIN$wOu_mza7a!Ok`XCcD?7T_8DDgV~qVQ z|3C~kO?&Z=OJpBEdY?U17_ea^GCMxsy>_ ztTQLC0Tv$9pRP!JrliH89bt{~xR8b!X!wMIL(Nm$dH6z_sr~%0xY# zd#g7uRqJ$^F+ZU-*7BPXZgnLPY9K~A*6qY4YRGWsJj}kqY7#^S&F4B8o2w^w1`m;O zWY-Ph1^RgkEIGh(4A=-ijbjmcvPI`+0Y*U(&ra+|uA;OED<35T8f#$-lRAlauDR(O)KlJ+Xw=YSea|Yh zUp%*bQStI^V=tMcw{p8O8h@2ZN5n%hU4Kyb;5qc&<{1je1QKqtWq9eod)EX#d`0zt zeBO8*#=hcA#i5+Dhdh6uq2O4?D<0X@@$5wqo=Ip_1^sA zsEE!Or#L>-VM4^39ubj-FYtRNXGvtGS& zu7Zyi(3OT=zOYKsY<@@7Q5|;>8ew#+>06@AQcdjOUCt7;%jE-uaN4l@T$yt*_W8p1 zZVmlZe7-k4?DL=}-b%=1!PX}8O`j^P8eH3%eR>sj%t(K^;$j0VM2y0-25naJx zfo^!33?b>nKm+){Q1L-nsDH?On|Ck$X(f19l=}6<+?wpXLy6k;(rkJ1DU|7~1Qrit z#7&pG-|CS?y~duuPUiaCmU`%X;yG*b&UY)>vu_+Ni#2(00jhbGH$Sx$$Sc9l*(>)+ zSx-82)#kzYx`}qh;k8WOb*LABpdpI@I8BMefOlVueuwvtQO4BEna<0S*tjjMSGc~J@%Qkn6QNDvx2o+%^AV~ z-K37ef8T@O8^rAvQ`b<@t4uxDP67-~cPqlPk%CPp3`&Ck`2L367+fq#bx3UxH#*Ao zzUJ(yoC@ud(#`klirPfAS#V1p4vY1!L+2{msD#hN<1C-q!KuGVob$1QOolABZ_bX* zhGNIjJ&T#{X^oz7g#-M&^ZTAnUs8JCPE<6sIEmEaO1A2pTrZGSE1IRr)yz=%>j%;A zk^E2|4L9#n;(N?FsX5`=SV82b3e}dWjF0)dEL4BIMbrhf5?705F>=6$%{Uyjv}z*O zSkq$gENdEvY%GP(ju+qkOg7GwwJGx0-7ByVZ_tLZNn`KWB780JD*lJ4N0u%|7J6Zp zs|_r5tA(p~!fRE5rQJ{&J6o)WvYur-l#QK#KN)uLBU9*Q>z%1{0 zkwRU#H2xEbUB^|y?gf4>lZgk>#pL7;cPbN<`RaOQmf&d06*itElvLXs9>ej4LDzn- z{+~Ie^aDHC!PCL$m5uSS*9ctDYKe` zsKt_$4SFB(YTA+q@2Suu6G0&HiQyT)rMbL%v5cb`I6Rxxvy@6F7Qey1Z)XST0m~Jd zEMh}HanWuvEim+M3hfzoFu|NX{Y_t7*FkJC>`r_*jhv-#|7o{(SCU7di-?~2;Yai_Qao_n9icu@S^(qER@HSW=nxKr*M_2eeRv6J^3^JIV?EVan6DK zZBLE=^Lm)Sk|&-NupdT;S_7NO{q1T0(X!|2nnh=`>$4p%sa!C($WFnIJ+qo>v^Wpv zn*EM|{NU*M&C7}7o@NRwWWX!B=##Cpl)~=LOjv9ybr%H{&S4vp(f3;4@fe3h-Q^a4 zLZYYFSCC>K>{F=Edm>^EZc-hENf=cfmyktWjc5mJS^>uvI3}XWxjU1ILW29BmixP! z-w2RjNqu?wE{XwoU1i6xHIo$nQ5+)cJ>GO`(3h|n2|w{GojkJD&=MNrx<9y!K<&g) zU!t~{@K{ZnYuP~4l{FZcs~XvKY+o7){wI~k*?3+ zo_ee*PaZ;$72A6VbXJu?YNNFR2UK7L+l@e?bJ;jl{C~m>w<8Cg4sU7qp^qCNkVm_* zdk=@$EtX{Y&RK z-MMKdedkrP*k1{bfTcOm4$6)N>jIMdB;K)c-4LI7w{s-i3wvWA*x0CUF~n=Nr_>dO z)~chZOaUmZeu5m{2hStmC18^UO9_1XW2!^=6N#w{G>H8!C;*KZ9v9D?beXejSj~g= z-lK+dguI2(dSI3Cl$q2XKa^74Z~j+s`t~p$2TzD_2=pH4ZF2fE6*FnP=QoPpH@rKz z?q7?`p{;ghk&{@TOF1jg2r>mp0=JRxW4RAijgaMecGL~u4X=&@=Ovis0JhJu91-bh zjW$CC&KCFrCG|XfpXL*F2tRnxS--Fh3Cicdx!$KtMiGYO40QM>IBO1bEB&*908+FF zwFVAVfJ*$VH8xFKYfW>uWKNpW0e2hr4wn2|_^=LhKi<@D1qUfq$$<^fC)Tp-q}>jT z&Y*OWD?<*i6j&$+*vUAl`tuQL+{LtGStcnBZ>k4zphe@989gAmGQ>&Fe)F%E=2P*0C#$R$rfQ1Y*(H5WEzx(6~k^BWGO zinVIM&bD}12BQ~tV}he#7BpU;EATQS@2+^^vIn9AcQM@`fe~*pL$AeU$34O1!NPUL z{Rz;C&j2c+MeU7k&$qSs-7xIg;`5$2>%*&dq6{wo&5T^u+3UkL8+02)Y2r54P3x(6 znQ?HDBHYnrtl5}~SN+Xn#G*}=)Bjkv42Pif){D-Pyph5F>P0~nv_{@jVZxSp!cII* zn>A)^gqt*uS3T#NF-Gayoe~Rt`hiHr>BkkNd}hju%>Oz>9+(gCiA#J2M}iKAS~AB4 zsc+-!5Tr$kgejBSQ&$DY&KXHd5@s{HP$;J_!q0EL`wA$(iBoZ{j3>#EiEHgMUNk&Nzjb5*daKJM>cnAb z6vm(=NefpL67j=Gn+N{(Rx6NdCRM~`p>a5Ewdt#*zQm^NvU!%ykuZpoC>`(+8O51{ zQ=^|I$s}inFD^8U&)F1?Z$e)yK40o!EAKWE9}o_MITfB3AVK^5%Fzwm?;5e%QF9$h z(<%x(Z+@jaj$a>jn5}HB)VVHX93$Up-#!HR{iBSpz!M8jyD*{O{w79{5X<%ttzi8A zX+=WGq2B-!@w5)}FjOS7I7684>rD5W9w!{4v*Ia8-ye@FQC4KpNUh=RM_h0?y2$!0 zoX&K$Qb^VXj*_4d%^`quC7Q*d738fP=euOoSJUf2E;;q8wxR0ShD2>TXbfTc)vh@T zqH|pOe|VUD!|ttjZG#E)mOP{mEFDLHf-uD9eSD1{9H}#wO5~zGUF;1(IjJ2U#k%jC z87ET%^+mF(gRsQ*Y$}R!{jLKV*PdSOkb%l}`3DzX1YcxKwVljt51-ryTQ79C0>0=w zuMKE`_2gQrxy*Wt221m*jTefwAm0V|wEEhQZo8`}Ta4q0vxTm%5NE9vP?OJR-jpG`g=ka7ZR6L_cLqZI5PAB! zmuuwfvTv(i1I@UQT}`*0ZBh|#+2o!tGnXez@HxlU1TK3BJR{`&hU)*eR` z!gxgkTB~L3a%}<{+q~|M-w3*1#@V+5W+w<9_t7GTVEa9)K&K19H#$8y8h=go8q zA(Gjon7HmjEr&~(pf(;8EFFkcvSvfQb5z}RaHqiM8>T!Yauwz}9=Dm=b0!%m8ejA7 z@2>&i-7*XgxJFxKOlUVhQI-rOUh)y#QTDp7f(4<~evko3`FECtgSJSbZcDJs#H4*J zU`NPwpj4)G42bkNXWZy(*@{P5K6Op!lMiG1LL#+4*=^qnjh4`rq%FgB;(zUTAfhoz z{Sm{$TOLYa;%oZ0*P5#8C|&@UD3I(~j6|m_J3M$=~n$Kd=0M(-U?k zCg%T>?^}r`ZH~KoK!2d^q1uEbWF@>9tFNKcFp46S9^z9`bJbE`pe4Kt^z|hP5M)kG zO3TtYwa~zHWe%4V1KZnAdM(-R<~M%^@O_DY`MzlY--o||#{02~52gJzPc8pXe6q%R zf~nLr9D{P1nc-YBo3?k5)0h@NyP5i<#r(+e`KG@A3j{&+B@u30KQMy2M|e!`%o#A= ziI|;zUl9HE-ksFst*Xo@*6KE4tF&ra9rNX(-8&n+iXKNuK> zUNJY+;`N0)EcV!x&O8o`vhE z@7y$n#P5>_E1s_z6D04vf>=H-(4T!*f(|;g*<*LhQyYLFsZ6e%W)JN%^koR7liljmgY!k2$# z{;}`VLwoin-Eq1ZlktaR)vqjR*>kqZ*mLjL2%T{8fT=NM^k@(99sbD%O-%MPioLur zY^`dSb15wa#*POjU@rH7T+q+FY60nT0mjOpK=~0uZ7vEtGF%9gu_l2i2#v0g0GyI| z;vF`*u4cOJZ79}1DZE@i2E}%la?K>=ATiXEqa19l!5|1rK+y4|%!Ls%F0bXLOoCi@ zMPmXKrPntLx$9CsEpHPVXNTC8@dbMb_0HOimeq0>0>HHT$+hdtuNjtd1r@|-7cNF~2&|5v0){ZjUteO44NAnOBV+uZ5=l+Mv(NT|E|9 zjwaEpB^*kwI>=T8%rP2)sqba_3V*|2lRwrCR}rJ|mzu@nmzuK)igSh%_I{(S3IjX; zkj$B322PeD?~Ssb)i|1EE_OXhJuc{ec|?#>s!<-*ofU+itCen*V8U+$i9=~YZ^4Mu z{lPdr7O27#-jYTl=W$g#xOT9itY%EGl$8@&f*mwf)C+yM3H)89k$204M0i74+!^ZH z<^^Lx$9b-89kw87Fz2=S)N7ax+oAX%)+5;(Oi|I$Vdj0G6{<< zvztLe2jl@%ZaM|y9zkd`mXahosFw%oW05PP4fS(f-X z081J&p}3HRe`)-K9AC{|zX$46$WguO(6E-c0BJzFt2DEq3^WJq8JLx_%VOAUa+DH~ ze;2NCUw&$%4|lGgG8+_c6WerMyVhLx31)V?wh&;CJ1H|_0fYQN6fhY?h%Ar$F-g+; z);VR?P$;)L{DZ&$kr6gwzUlB*Ia=QF%eqZv<`mA+RKGxoTgnW4O@1|&$B($AL4pk_W3oS%m{CC@C zVvjx|E-WHi#E$YJgv4pBX~=SJYe8bm3nU0WAX~J*Un}a3(ui@-&t?f*j^n9(=XA zr6&nTTQobxN->edMS7PISxiVU943)lvO-P+k(cOYe|$DwkHUVU@mMt+ai~&m#xN|w zhgFIag|p38go7Z`zD^C#i*!lfoHuXr_&B?4Lk7-oX&o)-FK8`h5(u5;17D23&>`~U>o6p$IQ}2`k%H`|0?$R@tG9 z&Rt(rA6%)5zy0kePRx8-&c!NQu@b1VxNm~{w%eiPvR+f8%GBLdi#7!`ZgYy;qIuPc zkSC<4?iR*HLbEgPF&U(~neJuE&9XRRv0+j7{9*kDZ3Z$#N7Kft#-8Y@b6%p#r^340 ziOX3a8mKJ|l+CZ@pWpXV#q@}y_8u7RD;}0pMiwSoJjh#zprGumOND*;$1*COCXfJ5~kBi_PN42 z{^3R)6!WL(l`vhvRF3j+pj#sLV=}a_D=~VbwV156gk$T_6CNp+Yj)(d&+})R7+$~D z!of50VC%paSzNbk*Q}fB7wtUo+!Zq z`C((YCoz-oV11(Y5#~MQ{9XBj)bTM1$#a&Xl~26Z^tSoIL!DkmSx%L69SWVi(2pYZ zz7-4twGaD%>>cEqLonTxFc`%?g^kn>Ji z>)`uhM;^A93&8{cZDqwK`{(-Fsj-mg^_4H zV*(SM&VE63XFIJP2Uudj19kT_(#U)m5VC^;m>iq4U$knrB{5j3&EV7?i8CPtO&dE| zzsI4j79#M$i@&{e%8!e(fBe}pkoO}rK-$kpU^n0o0)vyaD{YK41watR?%xQ(w%l_- zXocYNw>@hf*uX}5#e1K&F&!s*NT5R%(`D#q`0hbfpt^#jdkMB>;Y?z5jLCeIuE}_n zuCpMYQllJI`?88lAp;)qAxn_Fpi=_)dvG4=hNntRe6CQuR%CtAU32|2`VVrN8bK+vy|swaE&2(+wKp0tzNI(r_{a!_ZY#HhB>)nm$zjkZSXc4i00ke zAMIhVXq&O1p+PKAfiT?>_Cp7xS@Hb{m8JS=fXE4@E`^`bFfwtG8W+NfmAq!ATHz3|x|-Z6rA)%JmEhZHxxk=FPs|&@+4$;4k@l z+*-cdWrD4`pZ&i?{C9$^snS30i^;-8h6`T@t1VO;Q z$;H1(`pk}8G)YrF4xzJR1HZiL>`=4aYS_r|MH$d;DPOl?bmYTp4ywq!4+i6C0FIS_ zz`4h#UVek*U(Y7RVS4sWJ14ytIsEfi4)S_&TYwOI^676x6a--5n!F2$VV=naRm&J4 z@KC)Ryly}wd+*EiiD;^dc3hN`%YdkCUGK{Jwj zEZB8EjyYs!-Ef7s!^qFh4oSThYdca0DBGrZOQav5xZx) zjq=1EU(W+c#@=URW5N!Z&b_J9*fUfMYZO z5Q;tgLjts0Rg9T74Ud4_!rJ9Elwf)OYu&IpVY&YQy4N-GA+_S`9E831dRW0jn()aQ z_8@Iw-HMNx`~KJc#{HA9-J<#v0jq$}fP9pu7(qtIBFr1qP6M=SumfsmrBGbTwrg4_ zX5aRlnGm6Kf0QOuSO7k1Ti?c!Uiz8FS`Zg|Q#`rT0kl!p zXAWxyy1jjj-Cp65m=mhaVCTD;UPfTuj{LY_=n8MgrOT6Zn?Y#HvB>pwDcsN$B#vI1 zuW)~MsxQY1q{9s?rrY>8&y|S%9RFB;4yc6xd~~9hx%pIfb>q(q1j3juDP&d}<1X`M zBPS)!=KyYyL~mNjsoGB>^M-BNJJI3Yw~kDjZ-Y%0>+I( zV9d%}bNi~O;}7}O#)I5H^JA?H-EA|4t-3FH3S5dXFNA~_yC^7|sujPbvYLomHq%U7 zH_~Gk@RG{Tbt*N4tQa=kVA{g>Bp#fabru3gtMo7prg!Utc(@~|r^2QloLedcH??XE zDUzo~l|J5lLK>`lG_nqUNu-V$UU{F|EI7IJ16#SPIGvPbb~qBg`8%~caT2$EXP=8M zp~o$jVfNr;_0>+c-c$f*waExE>0Tf!2Uej zGng+(hs^!i&7qs6#L!c&g?qfDoI!GlJ($-eTFTh(Ol_i2=UpxSo6l7HsZqg=ke{7xA7We$~*gdDXp8+y!Zr@sI zR-&ay_6M8|FM`4!oroY;4|09sF1qL5zT;&-^ z>4G}`@o=MI)yX}8Q!|$EedU=WVIN@_iGc&t&ihTpA882-N40uXTkQsuoJ6)tr;Wk< z;Jzz-S2tosM=LoegT#qmh6rdwD1dijmz&O`*Ni~2T}N@j7CSHXpI#;X@OTK@(D zCEGNrx_xtfqnyW7-j^Q0n~Hh{uWb!;5Yqsn+TS3u}2Dj z^yWK30dBGsVC~XNou7}ij&4T~o2$aUH&4r5G%s9I59uT?14LhhbZ-yVH2dgFb1m!D zo@t>4{SW9D2>I|CRu;N-+>vDkNT*Rx1HWGUT--PM`;w^TKYR{7PU1QeS_ejN3t+%Z zzb!fKGWqkgpdk47KWv+HE^$e41iAW)AYo8|twRK2xM5IkQaHmu(7~qY|C&&-)9iTw zqv9$W&Eq#yA0u;wcf&Wg*oGZMU@~7{V@OwU>2rq!X__LfF$jTobtBnl4&eTi$K9JN z%6G+`OAPp13!svu54iGZN2Lw`qiQbqh<=Ss30qUI((JAK!%oWy(~HTysdU7p=YVae zlu6g_N!b2+yQ>GKC^z$S_bdIg=nDfqrBfn z^{z%?(spR|JI=?1RCmX#ozc_8k8m=MOoz}7rD(Fdyg%<{n_UjNxATUpM-!JU(NCzh zy66;FRtHr1IoaKi_7Q1THteq1W+_*P8Wr)XMN@1qHN9TtgVYjPDw$i(?X2#uCak-( ziwV1o8QMvCEk8*v4huGuCEOVfgO_d}X@XOA(Ag=c!mV|vbUIZDX=OY&5ueyU1&0|- z)m~nB*?e65YtPulwc*3iVnugQFyx2Mw6ar*sl?w_z!t_&q_I)q^Fe?iz%CgP-g`3) zmo42_!Qe^OSmzDy-}WqliM$u|2(8#*;$d2&S@Q8YxGT?8C_s zMQPN0;PDf8R>?8hhlvvR9j;`~!i!q4{!m@FXIdDymduAIC4xx0*R%`|T6P64h0p}C zrcu!rNp@4XwkF58-WBj1_)hL4 zf=0Jxrp|X?@N!GQAZ0-vs(4)o5|anJ`1@7j0C{uxN{k8jSi~~UMV^7^Am~?p0jGLj zISTqluC66`k;*NQdq9bC8yIBhUtkiY!7pPo8VgpJBpNyiL(BdEc{wmonmVh*lxqwk z?4&mihUAl=bpU3&_h&(^-&7Ec*f$BRzFD&fhH_{`gVj7jH$BB3EYy$$1ajQr+f-CZ zM=HW^VbxvEcPI_ZF#0zq=dv6q-}z7mKKZ^NZ~)QB!h-%x4|GI15*eJ{{Xuf z`%4kqY=&xhlLT2^MmB(z3|oNE`z6XNC0)VBF**r;{aCVJ!gf$w2A`s?NUYvODOJ#2 z036#VLnaZx=k+5UYSc4$E{;|OD^mhi)+AolnoGe1xwoFfd{qU zm8JH@YkaEkU=!`F>rSTdvfU}`U^kkQK;Xq(YWednavVna7{5T_&9G83fBb;Sv=q=1 zlWXQ#iYpbx#`Y>ikO*Oy#mS6ZBZmRtk|7YYH#X)-@>?Mx(ma?+Q_PHJ!b?Yq*#Q>Z$PK0VFm|BC!xQphY{Kk_2imsGC@GaANdRhBQ`A^wLs;ltRnGkwxfLlBbP`d%2sX z@Ss3A)cd5exIVG#&&OA3(mPRASQ!7vR+CH#-|~$B;wWw``m%JKivWgTMKqN zBlk|ELk~0n#3Vq*%kT_gfzvEHtxjVI)!!|`%JdGw+YETeyce>wzrw5T)7J}V9n+_- z0}jAoio}=BGQKe-N&_j}L_{A#cQw8-zvZ?{3_DoD|DQ2w{AY5!DDX(>)Xjo9hzG1&EDw{3c+brXib1RtVd7b&_UH>;EL+8Pn=x zWqQe;`74voI|$y;DbA@d$7{v6=+urZXa$K95=5J<6#}JuM@}~3QYpDRLVp{yW5$E8 zhmEz%f{@7gglEmvMyRdv>>fmzirU}K`Wg04Nh<^CeLX$OQ%W43rFw#2F-OSsh5o@N zJ;34t*d+D8*yOE~js4JnG`!Z!>~+-|(sKKv6B9khtBe^VT4_6LskIsGKgU%zrS_(F zDG`Z-dX1NPNFESay8>sewk!IQ30jbMJu)+F17y?ut-eSKcIiu0K86TU#^S1#J?kX70!d^cTOF1h*ig(z6` zf&bsctAC@=|2Yl(PY%w+$n;-9I2+U7Ae@Q$e@epllNGISnBa!H!*dzdgpEh*OxzO% znu`VXXKdlv#3boc9+xlZSuw<(PKw9dD*Zi=*UTU7my@mYx4w+E(&~g$Bz2%>S9gg` zQ$V@m^yyj+yKnfDErK)ULAr|=&owE@!fJ}ufLkK z=PtiIJx~a(FTy!(FSJ?Q(2j{d+iB{mdi^lpO!e-zwpoVX%S^dz_4PJ!@Nzca7;nSo zV}V7Bh8~p+?q-+35tibvafvS?DXTSmx8-N`l4NmkCQKM$lecQHT&01VQ zCRPP@R~P<3UI99%wAfZw-oP6A+I{vYJb(E<=;5t)w2U7UpgNP?>%^1?MgUbnJ{V2fR=8&~(Dfw1j{l(!3Ec zCQFdSUZWEVNP#g(0W%d4ll|CDYBtQkMB)qUvuG6m9jUKG?70VxIE7ytp%EHa6d05_ z1))qg&;%AMp*R-`p=Js=+3ye_|E+yS?uK~=UU;=RG9Xbf zQ(23S&vPX&HyBL8%2Xnn(L|yT0+671!3wV^M_K@ZlwAwNllFlIvP>h9Ua|d|@S#${ zfdo^k&ifg3{zcUTWb0I3@ZT)q|IH%(UlRh%|4sz3{4){of1Bw4GY;_oP@@0$`~J`O z@PF};>@5FBpYIzp>u1{V?O`a)TG^Uh#&^dJ-b8E(7b zIkO@uKWkcg5gaomhr!RCiTnsHx;PNXDvE`D0OS&*+PouG?hHuE#5`YCKt3KFm>+cA z&m)I7k{!P@DA(q%+*f!Vescw2+8k<2t%kKwo+`%bPI7W~rUqu@{N=LUzqy<3>E$w) zQ~-~-ix>4AYPa=u@llA(Jq>{wag$e@XOfUh&L-6l;kA3k!88Fielu6fs6NLc1%57cPyvWpykAOR=)N!M?Cl0FlFh zOp}(9_>{!#-z)Q-bORaxj2m{u-C~X$5{%kAhoIaGuXZ4DhQ6@g+&Dx)+0DymnOTo# zv5M#Wb(64tOxlnwE;l+`NW)`&Y}6+kyOyI-9K*1`pt19Sk@?%>STLiqt}|3CEv675 zt{!%@;==#V>!9t>@?tquDZ5)jXy5*bkZceN8UH@b1LX+@1(_5YhZJB1{I#z*Oxdd| zXgvy^YDJAIQ11B+L;uJVC1qQkr7U%#Fx`vH1Rx;dII*Wh1k!_|SEtyS3LfMNX@Z6< zxuVkU<7PPm-sDVSaUrsi_MnbJoOdn-WuX_+_N`~-`?Wk(aC4F96l}`YM^;6s?HK^l|;ZA7eFXOQdH zGoSJ>T86Ravcct?#JTk#CmKp)&MPGhi=sENmjt;a8oA2(hD2yi^baa3B@~@3&%ES8 zWd=}D!2|A}>i!Silu&AX}i4Mmu(v0cUN#YVntCjE5kP^msZd z&uZbnuvJ1)hG8}nYbJ(&7}U{|dNKIZbSb%MFNK3ks|Z^RtU(oOV`L)6n@Md1s?Ua1 zLTm6WqJ#{kudx}@4Kq79XCqqx+C#vJ~+y~Do_=P#vGx#()U~fheVXLyO z9hX>b(8g2D6Q8uH|K@1Qh+${5?QoTDni6=gN232(qiQx1O0-XgZAaJ!^ZbHDEaINQ z6NCedI7{2hvJe16pX;Oe{ZYCl*n;a4!Ie>V-*3yznbB|FFQ-~q9+V#sfpdIq5c}7z zTwfxi zxx6G&MLt-(`~H}8+SgkqR`z=>JvYalBoS=ADCNYI#$-W7ifH$gkLsHwHOAe&G$q-e zqrfni*>qcOsAsHg+pup{m_s;}$PRJ=5DjUt=9*sL>7Wq-v&~W*Dk;%J<5EETW9#WcFr1ScCa71Wm@oTAb zvSZWIiZR~d(Mp%h)wOAinmyU55jXBl4I`}6PIom^4ZT>m!5tEUz$?z*XP#P;|9MkS;pjC-fiO|zeSIvnrVFsLXjqkM8DB3WCU;7PX zm-=#RH3hN$hbtD=`c*B4ENU$mE(Hr9Ekw-KMTB{^)cxsS^FJE*HqvA3AL$^v+x$YY zx-$KaifS8y%=$Z}dob#hVgk%_K=V*G=GgG@JTGox>WgLF5M85}n}+_B6S9;;81d3N z?#a<@BM>6No&)Jo1CM?85N~!Q@|ATO2!=tYvS@V7{?is_G3$Kfo=md?s$7Qh8Hci8 zb(F6}|DIE%eO%7KOw~E;f89hZp>v{va;cp42z@K>!Zf-2RJs)?WLI0ZRh(y%-0R^S z!zBw6%(1u5T8_5#_#DW%jHl$i*pDaDxi8c(?=s(^1*WUxZ44Qz8a!yaXJ70M8CuU( zkG*KLd8A)7c{Gn;+Xh%b4e4Qew@#s_H6=mVGA8`oe-1A0bZj@*?bG|)*Lj}7)yI9( zD=*r=JiRK5+j%Qw#StkJ4Qwpyeye6myl73+IWN>CD``Tas+OEw4#QqxCC|AGaaJ$0 z9B+tajwFeKEDIqo!?*v=P|CQ?9p*jdouu$N>~TD0!@c7Fi5c}akP!>je$xWw^W{~# z2CHtSM{bQcdkWrb)P{@R_dDa3Q>%j^RiyqH4VRCQeY`f6+yXCfILRtYi~_uM-!Z*I zplBS)j=Y%35|JI68H>;0*u{aRvfkRkmpRxXSJCznM;>HUfi;J?S(9JRC{i~d7~ORp z^TL?U;#DlW((^>ydF53Bse0b(qO~=#cjGry2S+zkzNX!R##M^3Fte%A{l=L}@!c+3 z>T;rWCUitZEN-*$-qp?uS^a+M#<$_(6!9CdvvT(6T_@!(4K!aDUY)#_==XuO@qBj$ zY_AvD{FnViJ?eCMr}sK@KF&$${1<#%7m+)SELo8|>Qi*nl2i2V`*sp7>!aXHx_^c{Lj;UR!1Xb47UTPn~`KK=Mf8R zo3K7^j_Y)MwD3D+gB;&rI2_u#=OQc@$1(O%z(cX9ST9M-c|*0Rad*XJt2yObHOiy# z{0v>aZ_RY8m8x6)G3($tc*WH=9m8x3Z~c6#LKM~%T4>E>6XUb&8tVnW_f9&q<<(j2%eg!l^n-bzqCEMkoo z7DIFAvgWO$QX2B}U@;yY@nvfJ16^SUBkI+?v*^w45TUZivZ=WOe~u9m=p+0yFmYwW z(P|e2!}K~lipq{Z80h=?>6C|p8l-sn0DLj=`s>Qi81~(H#czoQpIetVa`829_*b+M z+!vQ!+-x88C$wv>yr%wF1nmVMtn+|J{Iqd>>UL)%z{7wPhGEqMQat(a$98`QwL@_h zXUbDOqpNWJiNzG19WR}*19N1`;=-Ja^@2(p zrOI8=Y)^buN!Y ziJ&zYsz3kb^Naq?KoQ#YO&pEk0e4z8$8GhjA5(&RZw(V})tTJL9&&Mwn{ci4Ee=%U) zHpQGpd`-EpE|2eqvL_ORBPSMHeN;&2u^%T$MIUQg!7p^F*8%zB#v=oc29l7TNc!&8 zvxg)+(rXU=6l>*VXs)f)5hSELMb6;?t<`e_;WiAIIN}KgJhJKL#{N+?lXByEK`^3$ zj`~$gbF{@Gz}cW8%!qBC5bk7U0Zh#k<5=xEY=yk8ma&rS6&sf9mItAAD;-H0-MPa*vdwFLV8UEIM-R8S$BmTAqu03yc2aD!LS97^|WKx^=! zCQs{E#T4)Mx6zK@TB@Q_;-(z_TaP(G)o;;-X$4OqFov3S00lb)dV!q`Z`urhG%ozf z$S-GS&ERF~Sz1!Jh}&gp9_9kCw952v{LE(ZIM4Y#8V)Lwd@!S2MF$CPSX_EV0d%mX zJl`zzQmP>OwKJQLTGQRkSU$cV@H;Pt)*>2yjD(zJcZJERQlHVj&#aIuR@HBVZdK^2 ztv79HTN3MVFOrm}R41&=n>bKz3A^GJ03$}UoH9O%K{A|8+nb1~GQOb9OJmlrQt zt4+^#Jf8ZxVaK5DD`&YP*QN1R{Vsm7$}#5wy;BpMU2r$BlbW@+U#j-cYt1)oqNG;& zaAcGuk(bnf@>_gV9v}2?2l3JE=UtG-mZ#GrvDCXRJz&wc-CI=u*(;^RtxiLyGRsN3 z*F=RYP68Dn!Pnr$bFWJiI&HUY&UKs)DNF?WU^7#hUeUJJ6)(R~9rzsU&7;f*xvrl7 z7L%vkAUC+lOfyu58lD@(iJWql0_ez7X%Y8my#y+|i4o2ovN+p+Fw+5rWaW()M%i^51fSXx79_+&iI-vFOv+4#eYqnq z>$e|{Hv?eiRA5D9-lG8q_439eAyY>i8!J(@BweAXJ#au7q`qOHTe;ORcP4M{P9k}{ z1Y}3jZ!uK9`S6VhT_NedC5~u>B_FgCi)fW}w-O6;`)!sa68)Sg45A|uC{wx1tXxQg zQF46rRAnmAMCkYchsu)41mzTbeMSkHA%sn+C2{R7R0y?nLVQ*o#}g5fc|~HH z$a~*Id~Uzcg}5OEa@14I6(TdJ24F*lnPL-2J-eU2A>A>L$izKj6jl0X%G zdf3%iEjZquWiF%}1DHf?hdmaD7};3n0*ropVpNqOI@uvt!&}(tBSDa3Kn)}epayci zK3oLh;U++yBB9@5Sdqf56V3($S}#c8a7eBPNCAO7(wMUAsUq*nUSItwRY;Ox4kusB z%PHen_Doc(0%dU0#wBBpq`4Q?&>ftW1_AGw8CpiGetx?Jo2U?MrpUo^BNKwav5G!W z?PQlZZWoplQkS4?Ttvyx-xJPzpACgfE{?FIC0R%+hL_CWr*Ap;Jg(zZHc*%`iFE5$ zJeDO32pjK@Qc5(B)%Xph+C8 z*@o3b(~z5;nU<^zvdG3(F?DAzS#G^0LKKddyIW~a*Z^l36L9{<1PLHm$6@-(Ws=M7 znNn59qzJlZ-{Ik}{Hu|U#%z~tEw*G+;2WI>Xgy}d3}x*UGN*gtpPr9;6;R17SUy{P zRJns%#;O{sDg}JSxj9ztOEUOe4^6E8T4-*~b7t^xdejSD68e=3b=MV%<`{55J8qGy z8dbKH3nssB@WdKcsF^Syt4#b0N)*$WiQSTF0O6eVfN;)gn_Z*wHM7QH(Gbvm#>TAb z`jQUo^GIFPMra0CQ#{-P*aN3GlDt@>A`$Y0Uwkd1DG~kL%!mgD-BQ%?vi<>%#ZM@@vtT_hN))0($F=$?BBLTYulf%he!M)+8 z0?!#fx;+rI1pD!(0-g=Fb7^e#dJm!x3soU!Qz@XKTR%m9ne+Yj(fj=a+$MEiQjySG z_o{lc))8(Oj{ZoV%^ftWI9nTQ^j-Md2`%c&M=!*6A5Vx*2J4XawK)Boxv0}_Qa>l| z&SdZb3+LV2#BM*yW%MWbhtEXde^aaf|86e#7dQP^OeZ}96M#1TkFcpOnn%3vCwzbB zNTS->#KqW$=pICR1|9^epbS;)@JZmPC5pBDQK7SRMO9T*HCpoH*7#fIpc>h>D5R!o zwN`I|1T@?#X49t#5OewNxDww z^ypuSreF1uwU}Wv8u#CFWenHBCMH)fO{WtVi)0XD`H_yw7+2;xexM(Bj-#3+ac6~C z4L0%A_Ol)qJS&@!h4!jo%|waX;#HKe+Zgks#+L^xvt0f3I!dW`D)KTHEy^PlF!x>{ z5|+y@4*6KP754%90*mQ${okC(|0VDA-_V2MukDfHukDfHukDfHukDfHukDfHukDfH zukDfH|HSsl@()@0zXy{1Gv5DSNWwzL`k#_v7xEkjNzcP7awP9e}0}kx8}c7Bfyet>$|{E6@Q1vXDl4wO?Gmf#6u_#r==8gVVyLmsTRF{X`EeWS>jrX()M`#y}C3_ z!Ypc5o&=v8eSNoH7@YO~c6#}_yV#jqq51Vwcxx~iw?l4DD!(n)8yERqaB=c(5>dlD z&s*|YyXua&uyTZpMt(WzFx0v^>2!P3gW}Qt-H&Ub1M$38xO=)I0@0 zX$J(J`01x!_W3tHMBC3k@956n^TwfnEmCg+;6((O-TymkUhpj#fjoqWQ*30o*YIVV|>Im%`Xw_9j)d%9H^qNAnQ6ce63UdM4fLK9= z0oCB9NZsjz9Npn<49Rfmg=7bI9y}=lfH?;68o1|`H^h<`*02C`#(7O|6ZRRQURKYI zUlyquPoq;9q+^YtytdsvZ0N_a`qM(hM1ABim`C=@$aim&q_G%ns|xbjPNdveYd(T^ z(cMt*gdw(=IJLI@PuAGI7nhJe3sk!cI>E4Sk*aM4Q0;xGNM;-87JfE|bdRl-od91y zrvAj@7utlai9v)YR^<_z_^N@rUxV|T$K2(o3dQH()UP)vK3#GXWzLs=!FzS+2{1s<;q1@-jB%eoj=-U2p8MA%mbHL+xq> zqgAe%Biq*Et#wJD8DFt4{<~n*>bpbYVDnsNx4A{-*~%ByrmY!AyZ|J8gr>xV@XO0 zf`BslftzDaO&3T!ZQ+pl%G3DbEY{v!z9Jh2=y`L@VSz)qW$JcNwH#g zkBlJCcvkV7T-;W1iLFL)b?JHWB$Jmy`{ZIv9@jm$sWe&}OlCKT3x>oTVGvl9VgYDl z77k~MMt*TG{SIo+EJ8%2Q465VX{apQYTy_tr?3{pvBPL}4_Hd=eHsI-GI`DBn9oxk zzL}(6U{a2QO#+w&tz6>}=_nR5n8_Hk;l8lkG$F8=9N51m3L@Z&xqcnNApma#2;8{P z<_m)>e+z9FI=`|AiJNZBwdxXe=nuy4|Gg@K zvdS`b+c()o3&&1uXDlk{-&6pJ6p73W-Vb?xp4$S1`=(*kW*?0doY%1LNwpkkAQY%Z z8(J`Tf?ccG)yqiX%ycwiF|R9`CN!~@lXjfDO}mWi%$G2d@`agnV{U((&ckgg?`x0- zsQQub>=P^_5mx;KL507n2?R$s{=z952|TMv}W%1lK%*Q_@nh#);I+ z6+W(SQdR_rR<|P4P+nmmTUPpFI^^Mwq0Ky*s%zMT;AvB9q+<3pWh0(&C$SK@IL9+U zg3JVLrwAQ!BbY)CD;HxmIMw&zWk)t3-KP2e+Pporh}k&*vCAY;A(W`okTHD66ya3HgM0f3hkms03t~f5z>s{_~ zPjY0RYM5L0hmO(y4NZ)ygatI|J^^3&L@Kn8yELJ^avfYHBEiZl>6nuWvo0pycAPXjT9wpe4Rmu~;%`zZck zEfH%8Ecs%#>-+?#Dc9wxeIaA~h1jwX+F6A4cX&2>EfxGEY|=IX<+;(+7Z96WM!0G} zxwgED>42EkF6@3iz*Jd}HID#8(mbj_Tw#$(rv-|*CHBFmN85uxv+R9FsIp7hnqYy) zBv^^R#XJ~U z_xtv)3bgHZ5+XLM&TCGC#ju@DGjJeGF#Fbdps_pU8wgeI)s#K<^fSEuB*ish-@a` z{MAY570fO337vI0^=MhJKOO#1QfNV`PCi|RD^VE!KUS(mVu-;@t~Q==7^g(;Q~17w z?OvIh!=w>TRIgo5Vp)98YE@qm*RY)&6jaENeUk;_PNvbltYRHpI3#HPPpkyJo>zFm zFnw12R~hnOxC&6I?ec}fH{~JrZN(b@%vmq zw38rKqkv40+SGqC1KrO*M<&3nc}_83vo66*tt=M~o@M}-SaF(RhTu3mVX2s$)~Wfo z0-1a@Bh%T}q3TB|@N$DlQJ@oo3ct_gPUTw0e%uJc*9?&r)R$)f2z;U$=C^ac#vHO2KS;t(buzdtF$1ub1>hV;0whL{U4l;9qc~tjx#^ zUO&c!Tx=klV++V)!G4h8v6{;edd1{97nG?ZZn-hEt$)0BTbwwj$>?!cSCOeOEjH^n*K?-KPz$)Gq7cdg+JQ|_(;lxgW-PaUlXIh7f<^6!gCr4;JZQnq|dM6>^SQ@6Uwqh=)}ls8g`UfnCCSy zK)W%Ozg>AuoyD-}Kohja=**0Nf7VGUuQmJ!+Q4`!j$|i>Rd!%B!p(W1<5$VS!@4M5 z5_Kx5v_5x_=cewtjn(vlUtDyIrnRJ5TzQs50{wgXe97hMsul%D7A+aV7IVmvT;~2J zer4lbu9LOG&?~l^waoqmml96Beu)P_E<#pcI^icMP4@QacY=)6$d&65(`BGV(|mzB zlF%>5fCb^_8tS5nEq_IP#)@LbS98JkW1#KUs__7yf?Hpti#*~CF}cqN?RC+dvX}qKunsr z0xpck;-kv1!0R?><=ZzPo0_j1R1>X3_`_Y;l4E*hMd}VsLb{Tu*T3=FqncC|T+^`0 zgF1F1&Y`PdBi}$&I1VLWNd&N|cM=&HTf>~f5KDxX0-OAqJ|QpH2>bE>EW27d5u-CE z_s=N^*JQ@6@IWC}J0&>4%>{P-WBJbnex9*n@yw{Dhixup*}al z!*$c2o%TuSuimfk;o-H*(zWJ7c0q;UY;6h~c@`r_DoO4NA`?j=I#_0W)xR|Z-x@Sl z;4)yEK9n;4_A1fWG+w=7X~p#2Ui<0YAr;P8tWBI|?i0arvnczSr$-IBn#s}mznXmbOGw1^SR3KU+C>=+KWNS4_G!fFkSE9l*XIMQMGb0EijE#znP=lM-uodjhxgZoG%;Zm z8F#6D8|3vKO2xkNy6ygP%BP~G7q;mqBa1B=DyKn#nprxhtB?&w>4g-N3%9b=>CBXd za98}>o(nQVLydvPGi;bQ$K+T;c7F=S%rn?9? z$>!NM=2`88M695<(~n7_&nVAWAWqF;m88K9XyPup&ogDOgC_^~daJ+ij0fLJ1tawG zw&%>^z!Ec0)lcGjyqWF(-du5Xd8!KTjd8~uV`XeMu3gdXvC5VF@l6BEPvB+a5*I1m z#ksnAW;e+>TE!~(Lr6u&)i2X--mE-tCd%q!vPJd~d60~^(L22cWK!cpWw#C2 zam!}MU#CU_W%IIY`{@}Dt08PrPWw>EdyQx3ZXh&InnmiR{j_REz3_5?1MVQuuuR}P zqV?$`DaLp4x@pYe1(3aOhzkfju?--humPV*O^9Vm=mwj-5d3N$C>^u zS(CUHF0U!8DTGL?FL%Lw`kx?gtpXK~(hA;m&KZWEPbnFjo}`Y(H@6$HH%GXhaxBZc zg2qr0d*)q@D<%XDbKMzCNcQ+ z>T~i3ZjVhyWCp)ZcnD*_vaNgG9V=YxHdH!E@Kn;DMso=Nx^eAhm%pp2;q$P9YJRsk zvk0`H&m)ae3w2>5Z2irTPKs0pzhe?e(xwiY$NCMT0j?bW#$PEUy5yct&RMEnCFh8e zos0k~2*S2b;P2apq${qv2q^uoEJ2Y&9?+H7X%X2D|G-e4VO;e6d*?0J$}%i7w8;^e(WmSU7sS#hYzKT^~taC$MqMPHzjVl z!DT3~lu)ZW(sGx^#`@vghx%#S5bcE~(*5auhu_UPAN=n!>)#ivG#keTny(C zC$c>|K_9lF>-o>{j6Oym(+LLh)L=j6@wW3I=yJlZ{;h% z8@HoS>8cr3%Pxn9s=ps->jjiZv1Mk_%o!eRhg^t;cLT8ZEvPlY=e^kFbru^`vmFL^ z^2EC_RsOQmXCtW~ZdiYF?5^r_TQ5oElhCMLn>?%$W#V0#wARWx5ys@)T%^JDm)i>K zEnd@rz}J7FK<|z5?`cdPXYG}_I7o-L(`6b7$@Fu z+|D`PNRO#rpf>quEamP`2>!Sx^(ShHRq#6TjwFqt`sN1BSqW9AH8FDA=v!a_yPi|v z2qgJZzJ)D+2yApp%rZUVo-VgT{gIxD>?K5gEfPxNB^W;zD|ufb!zPGcCDBA~u_)H)DtjWAgWb?hCcYTNOOEbjw<9w6RA_LpS(-P)e)K@ZOcYCWWIR%a zcs*H$OP4jdFU_C?ce`QlLbxfW`87tZBvb!~+M5WJMEi40AH$ZKn5frx9=Xa=U^3!s z!hN9XN{u*6FQR7^g=8C2=UQy4r1n%f1fHJ9Lm{-(KF_#un+p%kR)W?a7V6|8#s;W^ z#H+B!Nn=^6D9_->|FoMdKzchNS*5pa*>Aa*pcGrYA}r^p&q7`1AhlPk+7jHGVOqo5 zYzHg3948+3)~5@Ns~YdFUa~CukaTjV&roW+ z)4R8k=b)Xr>N0~z+jnxm03x4edMu;`8Ldw&`kk0g+j)hUV_8qre9-!YHUA)PfGD5! z>r_jb9GT)qAfJ0h5#&t#$07(-znRYwFKq7Nj1GDx6_xmJ#*$b)_azZLt|T)Xq5K~S zcA@h_IDIH((?22!)n*4;Q7UAUT2U(JPcf?I<-(_nMu7t?%2o6l)OLPL-iC%VnGx0) z1z4(S1zQ5x7Mo3J61AOqKMg57^ysk)py{O2dqXoz+B#J!@J%t*v@Us-^`SN&g_V$B zJOX5~9ep@*?bgYCvm$Z+sDiETpQe+C5oFfuBk7U(@WdTG)6x|frA)=F&e@< zCm~ft@2yC5tmU>F4^7fVyZT?y`iQRr^3c>8FziIBI2u0Wwk|{cuKFYvPL;OBzTs15 z^kVkelo|6JYM#R#IuJ~b4IQmiiS3;mJXsl>Ehw(XjjR^0#c(|&k`y^j?4L8*b-Yug zJU)PuN`+k+_k9a)boi4Ze6jVhYyJ7Qx*0Q5cKZwt=P-32iLW`?QH_q!a9BF|-e>Rm z+1nEHD^b8^{h7Lxt3s+_=!t$*BYI*jh`gK9`vVtCLBa3;O<`I75ZC`1D*g*+Gc*6& zJjuw!3c%T{|C4ueEn(Vx^#}aGCvvw|L$D}&h7@}O!jYCx_74$uFiiIi~Vz($Fd?wX2+4+^=t0j}+DHUxR&L>+BqLO{a-}nLlW?q~5iu?1(7-%p9O|w5$x8 z;lxUfwmrHn2y>NlWSI*~E6|nh>sE`9dZk#IORk@mX=Yj^ms7;4V!ud}TeDhelOK&Y zDvxfRTs5mroSkZK#eb<%DUvR=Te0R#vP;qX_#VM11srDs63f_%_YJccxQd)0=UeTQ ze0hUo=KFfx`=$SE2kwoYtq??6lJ7S)kC86yIhL=wYu~(`%+gk^$e)?F`Kz_n(CkK)uO;AGXyxC*5C7xla*uR|_@~Np#q3H(# zlU{q&T*1ND_4R77=EK9DnClc3_w0Qo$&xE`k&K+R$gna3+208;F^eQcd-!r-FLlz; z?(Oh-^AjXM@B4^32uS>b8L-k9fRFR!8G}XZ<)_JL^d{JGnUexq{MzL_YQ!h9&X;e2 z$^QS%Jo#VJrvHo9|FtMG{tYc={7df{|I&NLzx1B*FTH2{OYa%~(tF0g^q%n_dXLA# z`1g2Be~-uX_jpWykH_@S@%}fhkSzav=>HyNUH&g;5>( zURv#xm^C4E<1q`jZh&rVfSEuw0soPa{o*7@ozJ zn=MhVSC!Mc{Y)Y8MP`+P=i)8C-RhaUgh7o==LDYS!g=LOWOh6b*AIQuEO!jX(OTS( z-MjZnX7^FInI4gmq4s`k`&wPHy_GMz6cdlvTynvMf@!_A?s3_m%xv@C3Ast^&dwfEM6uu5Ouj8;nmK-r_s6Jnt=%*zaK&{|z&sRKoN zgSnTS9IE@@qP?a{I%5wxc1geLp9xU(ron)Fnm`Jo*jlhRXPpUSa4Up0QrBt@risuo?lmUo+VV;013*z$7_LVBZCyp@ zUOAk=&9* z){Q3&V*LEs_K}LGCzqTOhsoP_Cfki-K?Ec$7CmkOO%s#9!sv|NA4*OYwpUClZxhNl zrZQde4H2rqhc&e)z`0)_j6c+us}95hM$Io$SF~G|Ni{0c>$)PR_W>SM{3jN*Zci}o zm#{4c=6uf~gg@hu>WK^GZFXh|6dkZOfnxkJbdPPzL@{wH@pWf8^9)>M0B*p5i^RFK z`mv4YgAIC?R8oREECx`RHpm=x%t9vX)^_mZ1W{kevya)KmP6B*6Nl&FN!~&=j8KBK zz1hZ>VHOfIglEBz{ZNcYK=BMzYft9p{&K;2ELDkl)#Rcm^!2w$W_u)D*XGYjd3P`` ze2v(`bnG4W*pk9Ob=#HaKU5L0Hm;`K@>q%LsW15#IAe~ZJ3gD3Lzkp(U9A}^u%)C) zq=q^T(+u!Z<8yb@GeHj9=DE0B-;<*#%%aB(!^B-G>^;$H^pD_fZMozE6`q;sRne0O z=dU<1EeV^yAM#Cvbn=ccD|)C9DbF^PszORMR2rdXb#0d$qvB|%f|gCzo9d-&J#6(q z)+9zAuVxw)rPX4tG2A+sSr=`h3DGm+Sb)#AJC3l9`$-h@z<} zsQf#4CR^Qc+E>W+mN#~M>&Y#GoO|C132+qCLf}4!Y(m>_9R@*pT|vu6YUL=j zh3Ba(35K$HxCgpx!m+tM4n45Fl?ZZ4em4D_k8zx97Bt+#Fu2g-)?wk~?BJB<@@p95 zwMOMOGN7}I!N#qGSf?aZWJ@R@Tdf4W)%_C%^_i6Vl|E<*GPBqeMA=4L6rF^n4Ho8y1opBY^iGcg}8PT0lwi9a5=H zrmyzkgI~GrCtK9&C?eGfXVg4ZT|%a9@M`tpLYRsw-;!vKy@tlJgRY%fE>$yIZt)Q5efUmwq0zKXQ zY>1ElM*SuF8mtH(O(-4s$^@Wfa<2sx38xC;;n0y_!{3LqbTGaNp6a9=l^b`%!UYY% zv!!P8_!~JqNzNE6OsamR-4C^KRW?T zSr_b#GMt=@ZyP1q5sk379Z!T|clazFOHAJSZ~WgMJmzMTOak*NF(^>*Loh z`x4f1dCU93dG^u$;IdS2fMAVv!*1Fq876)O!2G0h-F*04C{F5einMxmMnY;ckNKyH1wW`HAi^~s8hWX)P6gxQ5P7cv~QQ~!) zi`z1XIAXf?yxY=V$TMd-BIf2GZ=&2&1T*Tlu^zRA3Fi{sYG?ByyesErC4ojD8MWLP zhwA2sLE5a7sG1>l#xAADbvs55tfWM-_C)_K^F8^HX4#J~9@P$;!}} zLvR`rMID<8kQ1ycJff|79_od9?+l!DSR_*byBaPe$X*XsyKQTDn@eOF3u&GnteEIN z6<_G^CKSOW1bO7Ie6&s}_tbe&Ifuj)(Je08`qM=EZ44;y zHjj)dDq7K-dW30MIeYsMFY zG{~@B&aU>E@JnQ13-bQBRo`^wIUoRGXZbm~gw#duX%KphRnNQj>stO!Z3@7sG2JyB zgR_~E(5)rG-S|b)?6?yX2_hf%q+=5JppE+9K31(i?$f+o)5;to^nU*wJlk@+qMB%U z4Gv<`o_haY5gs$LuQQjo&4^`Mi*^E!;WCB88I4D067IQc+D2fDT1DOu;>YzR>fuMX zCWkMU3H=rGGBBfI4Y=@&PH5;Jyz|>cV)36Bf?k|2nP<8^>a)HZ@G}MJ(bU2CfML8A z`Y!o2G6pB0|K7l2@aJ}@2m+;pVW9U#d4Bwn4da`oK#!}O-M7N78=oWL5*pJ|2u_qd zQEqmjL6$BfIsd~FyGeb@msdh9vi7`@eM%fdS)J|Nc_nm24QlyRZGP6MNIkEO2&8mI@rZ+dureI^kJas!4>nlGV_Kg}7^F{%>`8y&dI|RW> z^PlH7hJA{S37ZTEzNOg9uga96J7L#yZNVFk%L5CN@43zA?3j=Tw=VKA&Scg8y0fh# zG&0}?E6$z~&D(HT{g9z+Q!eKATx2}3aC2BXm_?-OfdTp8HSlXtnaaHHg)MgX-(VYG z(5eR^969|mxFd-QNQLKdf0JsweoxSnigof7Sbt)q0qJ^HmNqMn~o@% z8RG4}G8WDVO0l?wX@CU&m}d2`*H2}FkJ4qhofT0*jwozjJV_4cx^GE=_Q)MA5j3=Z zAC5B~nvfamcke}-?0CW=O@HLI^+|eeC+Kp;Re(Sq$I7md)$$GDb|ZB!1Iv77%GYAq zvYpnt5DrV(BrZAH0;n-9CVbcqCEALJudlmIU3T}U{G9v{SC)4joVIe=k|1#-0rDo9 zv>EOPK2*6suSHh@UxoU;(xy%2e2ZVwQnm=&;?}^v{|H!Dt%3j+M+<6%)zXH-TaD0g z&KkGLvMI3I6a*1#B$Td7J>I98G=iBG6D8qLMD$Usi$uyRGfo(|LnepI_rMZC{{Hd& z*!i~qNE+6sktIFS2Epr%%3nSC#9twDdI;zGN_zih`dPSMSl6t-$e2Y3Pr!Bw9Etz^ zl1V6I9URfg%RQ{Mob7Zy%Ze+($vX_7XC53>k6m>a3x2QoftwDfi=89Ln|6-lo_nP| zs*XuNLR^b(5(2DZIBF~_g6(=^nRz{$To1?op_R(fm~w6M_G4T(BF@t-+1Rh^cBMT< zJWEe*>m8FYRg`P$1R*Q8IZBS=Ou8$M{CyaKu9b^*m~Ph=JWDpg3BiP3FW}2HXBqP; zv8QE8eYMJV8YqRuDd~;;>He&fY4gggxx9<5FrDGvfof3JdmFdFTe64!;6<(5L5+b$ zO5*uLCSnPChX9371Nc?Ag@+`2g^f_;u`?h?1omSB&WGQfhG9b;4vF`V?ySMh$KW?# zSeASZ5?yi|*<-X8`XQfgoL!IlEsfa77uWcT8muq99@p(mXs|BuFR*#$KjA zw3xX^DmqE6RTHBrp8o2`;_h%b6sYdtuz9Bk&g6s;&bqK7ce)h^Gtb=9S|V=d<}~!8 z_S}r_tGcrM)m1rJ5tuZ?yy?j0!bpJ=NYUfb;brXPhCWa!ZBv6pwDgNBg?oQt`j-fC zroE{wNo*paS4@(C|Ev-q=s8eQs~9Ohy1iBC93eG^0O#3aR*7ZDbyx|o+C*9W1^=~! zv#|?K++>U^=kU2bOQ6Pd^Vtb-`WP|L>lOazn*J57T8zLA-w884mu~5cT(TXqto$&2 z={Q`u9Ccc$ZN zKV$KO-ujpm6gT9ydxcw}u5>KGuNyB4jA2{T6CiDL+=GJwTlELycdJn;VUjdDWJ<}P z1r!XBzJb{?CPU(u|51Q%#`p({klPX?FHzk%-}glzs(7dl#|onE2RzHwLyv;^gi$JK8TSoOJ3h`A;C{zr2tf>UZ+)(h{`nW~Qr*5Z=OgQ9@n3Kd6Fo&vIu;M}L&JN%E} zf^+YH(>3c!G>bbQ#cE4;`V@899L0>K@bLp_bI#nhKkKCQYgPNrz&7EaHX0xG?=AfO z-!o@!;rdY&?MI|+c_K-3s%-^UrC>W079<`yHcAUAM=EEvv(<*9#IC7B zFnMYMAmPNr=FQ>4NMPW2{_c}#18#wU_LAWj+J5CgEgj<@37Y}-C8MC*(>8d_26fcO z`n3^1^LU0y&rB0yy*rgzNVapVF4)!X6<{09D?!2%mX^0itfP0|85A#LU;^)}I2W{C znWh#GE7R$>AJd@%DOehh0_C$`n7eHDh@vA!Tj$-!-X#ui??o+l2^C*EdafCt&5a=! zYkgeyOn6Z0rSu|D6Rk7TV#$yo;%3=vdSduCG`7EZsBM42BKak+fJupEu$V@P6}ri~ ztghLOXtnL8(*&!Hy>Qyx-? zofn~ZrW|e(;=9>4BCzVRb<MlwvEq7oXvcdjcXAt~XJaT|6)%or@NMxEiB9j%Wc| zw9G^!GxDmhcPr?|1w78-w)P{i29Zhno+GfzDObp)iZB>v|MQ7)kR2o8efK_jFYsL& zsyQpDv%5L72#d0$k-j4mc)LQX)D?rq?B%V{Z}9~$_w>=Lg&W8?3`Bbbex6Ibrl~~0 z(;T=sEz6PxWU#h@V!QzJtGm#livc#PXvAGdj;1Rqk_772umfouCV~t|F6NnJB6N8Q zRZ8Qov)%Zqwxf z?S3yA`Eeh+{yGflTclEDqN&!~Hvu(IpTQ)S-+q~$R5tr0FDY>@>6h3CpPW(|w@$mI zFwy!w#klHj8_8vEev`6o@#!Q_W>>DeUQ3EKk1!H%Iu|d%9gXZmuk%F89LJ@`gNKpQ z@*Y^S+tB8wDKq$Nz;w5Lo}+Xyw5-Clqc0yiJtM%&8;c`bca|%Z=9?-?B3e+GlD3_GeVVomw2* z(M_&7Q0#V|?BA~;xfjwdivoG9btupL>w^yxEm^lc>g)Qc4m^eZ2Y!ARgkddkPkFB) zaO;2X-5TPU1_Qa5xV`#_QO91<65f3`O9D(Xg})Tu#ALxgP)7CR*k5{YJFMF{nQgx( z&K(dvl_LuGEkDD(Q6~;o?eLFha$8l2S-IuiG`;A|QxazKAHH_LBU{q0o(p5&><^g^ z%Cp_3y(^PjWTGO$_Gh^l zlJZ!2C*M>cF`;qWCoa|v8Ll=s`pPMAr;(Y#B_qBQB-q5GLy#ks>Mh8>SGl3yI^or046?}g_M9t z-68#M`~AP141*IDy!8Bcm)=e=jJh=&&d{SWvPxKMcbORojc?#mVyt`7eL-BNcHQ9( zH}6}MHjGR=NlX`_QfiGBpcE%OZ`aTlA^f|&PV1b-MRE{C=kch=qOPshX}!-@K`PEg zwVg%O1B2-YZ<(EKdG(eox6WGM6sPKoM6f-Xxm`b~<{Q$UK0#!g;zfkZ;|u-PXpiQc zqVVPbTA@cC+_httoOEk%?dRK6HS)Xcm=>IQ4JWS!^IdW#R@03NnaXD@+vgj0)USat z`=?T*s3=i~oIrNNl~_|p+O}TvVVAJ?H48m~c=NZ7culE%D9da-Z|B)_;=N0;2Hgwy zvGpqmMFs8vaN z9$P6G>;%P8v*g#@6|2%krs1S1amc3;#nURO6#`6;*tDBGztzvTrdaw}S|O+PKaYk6<3# z7I#uap4YNK%}1CZ?sbdjkS-mYzuJ7Rg|m|gP52hGqShi4y7rGqNIi^RC*=p_*&mS* z-9I9s_Sg94u1cIEdA;3)+1(N1&|pPn3HITP;{fEaDRLSeM57O$MLDJ~()_}y(45I4 z-8#Gx`0=Q`DpT7?Py07^!vH*j&EK?y2hMmO8>0URKG=)7)i`faT9kyyj*>JA1(X@C^{E{w_%MYMn_<9?B45BjNYSa=+jt!S2%XT zH=_L-7@~S2V9^mvv}~~!hHSSUG@aPS9kn_}^-!aD+kliYPpsm6cDsn6MB9MIrzY+w znWg!4wo45=N37yS$1h~W=)xnwJKD`8s{=86`gFQI8EfNSRT>XwVxj}zJ9t=nx)2^E zne}ZBPgjsrSZ>Bak0Z`@nhZAa-+ORb$#39hGV-a;xMss%(=x2P>OW|^wG`Cx`&eT#C%CxQu65q#)+4;L;8vQ z11y2D!q39f1{}JSwq0NJB0T+ufV|>Ujl^(>CtDMX?Eie@N``3W^Tvbh)vu^nIHx zV<-ikO%qcI(UpV2gT?5NOo$<&QNEeb`;3~n$SHGlRTm%=0tBr`DUyD$8p{mZxQH(X z@eHX(1-x9qb-vI3Kh&LNSX|qJV37a;g1fuBJ0!u~-QC^Y-GaLWcXuafL2&or?(S2$ zH@9C;zwViDe$H?BpeW8hwa?ybuVw2iDpKF*`aF2H--P-7I8@7dEzy9*YLH9U`X+q8 zjcTB(>+$%wS$((pZg4|E9wZqKTGr-L@3lNnLl=4fQ(?d~P zi|Y^iSRlem^sFz-j5w`l1Wx+IeO!y=%mNj-eoVlG8H76fIj|xW53d#FHM=#o_ai`zWl7wF(vZNLUF0B)1E-3@KH;pyiSX?YHlFbo~d-DNO$6>%Wf}qF8YGNPJubUdr|#NP5w?uWjIbjg`7*1u zuh+{v2_gvjQ{Xe>#{;_fiL_{;8lO;5Qd<<_K#w$9Jb1`>S}Mf2Pj0sLA8A&Cw-3Ch zG3BzQmd=HH>Vu^yjXvyFArsapKN2RvKtHN0ef9G`6g6%albh?9P=rXLGf}}pBdEX? zy0S7B^*Kdi&m&cKyJYovx4$bNb2tohuXYI)E1MRyXI_I&1l5=HcVPYGO6!xDJ22Xn z+X%i=5Uq|68C}*WpBH-JCT|>~N2$&cEc0|PhU4QZX`*1>*mAw-ild+S!iZwt{x5Yx_+ub&ydcMr5^)$$Gfw~iE zyJ_IKh1pX5J$J2v()FR-&N&EDBEF_f?l>cpkiId@HkNN)bH2(e}$wtIJo}z0=%}mEop0< z&q8&HDY(ovzuy<|yE8ZRyC=+cxD~^bKqU+Jni8F!_0ZR69Hb6@6XRqB3-!}4nt*C% zEF(sG$TTUS31vf;?N!&oL!4^pm(2cz>wAmhKZsPZvQC35AT&YJWJ-h#O(usz>zGV# zX=!Fx#_}(V`}0G|zQg@~&gv^dV=r}1{CD=nU&ODu$%%)LPEY$A=RPjg7|u`6?`N~8 z^%?<8BLj*`k*Zt}o=^M5S?GTdsjlZk3fB!qo(6;X&`$3+@SY5~V8?U$RmRzny!)1;)swv&HL&V!%qrar1Gc^2|9mHl(&HcJ{ z#XA%|E&=7g$irR78Kyk;Ur8^=2L{?uQDQP2!zs~f5O@LzFF|CH1va(c{BVb<8?58q z4n}A%XZ>)U8$9A4q)@$uL;Fc0kOeNpw?Ofc1r9(HnjXBQw){nWr^|&8OT4@|!gE?Y z#kK~hi!IF6k0uyWuEgnM#JQd$hK>llZqdeMg95@4GxEje)!(_1jWZi;68}QBfLw z>v>m5mlYE6ES?Jb<}XeuEoj&c!jQl{oXAKb#{(ui{7|vHG)25n-^pkndkw4{)6s1} zoIH)9hC2R)3@c|o#n|Nzh$HpEWG6JlXdtIXHuSj*2o-#W|Eb_;;Om#sZ8&p1`cM8E z-=qVH^Yq*iMMqgS^Y1?+aW(?Z1(S=*A*OMhJA8wpy}3*R;6)Zg2Yf9+Q;8B|GE5E% z9rwkB5HyKymFO5OJIj4fKk7WRK`KFl6~myPQXiq8S51AsPNB{XgJS!74^7ePM0NlY(R&910X!$h;sW%gw4VUy-otEq zVSSKXALdeRKzQ4Lr~lV&3E9;e0Q-U?5v)%M>8vbvsJA}cFnkx`#GIxj;>}94H4-6D z49e;Sz9H}Fc}-oAJ6gboSPpaU&kBuOh^|cRA}6@lF^$NhdU!>(lDJy4@0i6Q0yQc= zVKE1m?McZ2tP9kTX4WTD0+Zi1*1U8h`Q{aKI}@>GOn206+ShXGNb5`ZnLKSq0=`Tr z>m^q0ORX6-KCbq0*AUTyZ?7?0GW+H1^#E=kara&Wbluo17sZ11yaYD5n$GFf6nJ_V zf<&h!sfkXk$ir#%@(v%-Qd1@!(ZFTkuV_FND>Ul~1Jxp=S89#H`DFR9fQL<+ORTJh z!!+w0SnDaxC^)~{1PO%2jstBU_qbH>n_A}5wx^DKt+?+l&Y zq(cr&04mZz;q1>sFj)HO)(jz_Rk8O*2c5iW0^N8#!+_Rp zfBIe0xNJ+LL(|&VUMdud%u^Qe=3;k=&#RE|G1L;E740J1VR=aVSX)3x3-be+kw^q< zWLbii)o-HB7wBl2d0`p&rJZguB{Ze#1jId?V~-%cZh#A4|6IL>{II|GZ*+wz(DQT8 zpDP}ACAgu7q;8Y*!Lp!%(r5h3#+nAMMpIRH-DEKVeBpI9Y5W-y!)Y~5lu*Pd7o^M4 zEY5FYd3i__T68+3A79JO8w4v4%qh=}!<7D)y~9ETV>LG9k` z+`7~X^a$C``mhA$0?@MGmqji^SpE+}evcSbsDvgiZ!uGH<~}L;b~e%V^Zgled;-M` zMy0`7OC+Hu(-m$TT9x$<|93&II@>n4=%w7yWU{9VMZ9h-NwMpo7z6lYxBA5j4OT<- zMUW%bauq^=L-LO*02YL#qMhy(y+K%>3sKAw+otv^a6=6a=nBESgF=h4T0}k!Wp$^@ zrsLH9Z7}%Kizo^q=yd};`7UF9{roLJ8mMGo#b{(-cFmk43PmVQ@$fsbratN`M;Vz1 zOw%Zt#U~kN1IDw9jkPuD-7U{VXOiZMBGbPPkS%pq>^}FWalSjI3lWMSgKmwgsgQ99 zF}c+76Um%OT^kTVctY9_xjSgfub`t-%tkwX*g|DnmcQ@e3Zsn76k|$1OZ)B(98s@W zoMTf~I(7E&@|H8miF#SfJtCte^D!|#T8O9K_)d_nP3~S+;~ZiK)y+N;c&Yu*uXTx( z%$FBM5xnTccj&@{dHstoHLYkz9qB}S4zd}_HdSO5N4{wx=NXtVeJ_bR@oP9o9x%Y$ zGj)t|VN=nHYP8LMJ#A|Y=Mrn6q?R*QnQAr%SmZM{T$ZZ;@Vt%X&WnnU^@AvmVFYZD|pKDoZ1%6%Mt;mtxC9vRg2Pkd@y0egpGfw z|C~>bn@RE6;$kiF+pg<|&wb=Mhl`_fS^NhFf`)jN~^G!R)f%Fz?SEAX_Fbe5dw$9V@|%#&i8$~wad>6i*3_?6Qv zHpjpl+L{!m8cpV}6_^^;x-Hu0%xELUqGA%-c8V2XdO!G8-)VGu)dQ5yiPp_jMNhjl zIzlz>3?DUbnwFEATF&v84SaCK>x8ZQwHsMVVKjG37xSMo!~`4R0vaoAkbH`}MLNHJ zZ3vg<5F^8|fP6g8uu^l~;G01+uPeXjt;!a!ce_2y$U9WM-M8SjZ1&cug;|;Vy3mx8 zS36}L=FD@3GTED%26l|DFH;EiKTvR&!{^DJ6pB0LJqa#vU-wz!d zxYpTK#P*mTc-#~rGIw_yorh3g(z=(lHObkabU>-0iL=ITz}%KpHAW~Sn}GK=gg4fx zu{RCTMrxVIS>7{q*oFan0lWGAbQLTUxGFsq1B=RBY&lEM{%l3o2WC+An!#? zCxSapKEq`{4+MPP*L;2M35HywmrTiNNIrd@N)=m=kkMKRFgBH*#tbL5uPft|Ia?6f zeqA1m`WSUjDM#WyTEhCP+V^3XL16lWx&2zN5q!hJhJo1@&l^eQ!qZG>$7{mV%}qp3 z!{bfF92kL_j%0$mXD-K)eKW@q(HZ;Wm-9EL_5I!@Z$|z7<^xv(N&Wlcmzww4@^rWS ziP@(di%yP^yJ1WR2TEH16HQhMTh=9h7-_B;r*%5i?1TssA0%EBN0U`|AF`@-Yfe1( zU=0PT)_bqemeEMp&NF{c3-^zO$zS3oQI!NWfBSWwSb%S4X00?$rhNI+S`u+yzV|*) z|Nr*h(8>n^Z#n6MsTEf69Y1OjFRI5;qVFa~US4(IUl+O`2MT_UpTJbFED)uCIeXo? zEvJ@x7U(n>VvJaKyo*Y*UdS%J?y7Cs;9z?0Y}K#FpQx@?Z?2rsneU-MZWQu)xXXAs z>Op4ch8A>GlVm<}PxzKZ8CKNF`smDVDa56Dj248Es@@!c(DJF=|Y>rjz z50$wZFEZyh^T6GOcSyEQr_?jw0H0OteQ ziWE$vv4KjfUc3%+a2B$L@ATHok*5)@3NVu7;ww)YO*g^zH?miu6(tb~A#9^Vb5C;%W<#Q zk+)J`#hFeT;o%{>7DH+RM4X4uWY7rCZc%7O1bPg9zMc(=@LN)rCEsG%{sQIiB>KqN zQM~I;5!?D3HVFX5S0b*uZvzG9wg&X!BEB30zx^3xAUYakdr-trRPMuH#;EA%NuXoz z-Uq>;Cr_Hc+s=@L_fdHR@e}o=Q4xiX&QnOPcVFKb&t}p=u6xVZKh2XcVb_6F1fyDK&{M%(pidVtlasf%z4+Ob*S!5PESte=0!yZ zH{5<$b^pRyV(PT^{q|VA=Es+KJdT#o2KS`1w5BG)2PY_oYF+E^Z3LQ`=_&2C zffSQc;<8mYZ0A(?P6yRIGL@nj2!<@GE1dO>{wI@W-S!375iKD5e85^E@c)ph`pGN( z9t3`hV#?w$1e$G)hw!H#wu~3=O)seIm$K_DF_Ej!^H<)*Jmn&tZcwj_anzdH<2V_N3nF_E^S0bz zn5JK>X{t3g&pZMtmJty|VYlA^CgtR?U7cKPX|jDhx6j+DpzJ)(eFmZ#dNJ;vg*#7- zX^pq*-cvGTQfE~G8&VqVhp;XDLH&+| zx$)~#jhS*Ky;sesuKi$}q37p$o&)D23uiA=%U?GUj@a~dug;8A@sp0XXTmv*vz4!B zKHEZDL%lWRqTUnSE%TaZl-EY?6L_s{WZln4$|tL9Q{N4rFV}2vFwl?>*Qm%Bev(2= zaM4kj2=sa-cW6+~8r6PSrS2rvmY>k&YWb=!4}T$);to6`R5(TF;w2|lR*fA4)JqMn zgZRXeSl|&nFwN=XJr;nuIDEWovLAp8sREh>?>!O0(XFo^7cn~s5|^dp_%q3;JT+1h3<#t|3rq#W~5A?=~j{ev<7^mjH3U8L*c z95_GGU8{A-S70QIF)UZS@MIaSqdit7H9$md@A8m5S5qsDI3;fJ;T`+?P*g)d%j91> zSx-F+?fMw2`SaU6rbgNDxLxhxcs-MB{YbriJ}8MQh<{JP{klc>Qj%PlY-0cQ?7&Mgq(d#1U10f5w*L@P=3E0u1CC1m79G_4y6nLBS z7LVq8eY30Nz0FqVHK@uiy;_M#@^cXdknuP$FYbL9JI(;g$H}4r6l_rikV`X>Mb6D8 z>8Ut_8$P~|K>1^l2w@^#vr;O4Fh%zsmumRn;jqoO zj12DXgUoVg*scp61Wi$l340jI74Q~oU&p#+WewIgo9mCJUuB_W=f9EtJe_Nuv|i;h6~_8 z)>z#uLF~xJX!-lNO~;r>kJ~Hp=G8#i+%71lc=$h;b$ zF0zp%oMp4iRM{`@lqO-3ANDwDkpQ;5eA$tC9g1&FHpX&uruf6}LnJXm@LSmE!4w_$ zf1bD&BXPyZy*iD?`wd>#0h!`rH=9P|{;%+c>(2Oij5`Qmt2} zdI+4Ny-ak+vGm@~EcQswE7(A;4=IUICoiE=t3Iox3a$>FO;Mx@Tq$17f2O}l6139v zyA?W-@N?HxtO2v>loo+#*h1$L&o#xR@VmG|UU;SxF?eTVr;Hp$7b5JmM zbSG2ZF4gL@_*v2x9aLzGj0Zgg*dJct&>L&F1Xnw`V0G}II2dZ3Y`hpW&j37RW1(Q= z@VALc(KG;xBRVfF=!;S8`+h!{3wl+wTY{s7omfWWcAGcm2niyyYU46Z`9xRe_bhk zdxpq*8h;k}P0yTnp9ATcEvfaluB#16i$XEsIR3=#Temzk?@soP!n9SgF_|MaiiO22 zN&ljplk?XfP!Mz-Wrxt;Mz16~$~hsx;{Jo4@pR8$QmR|byk3iSE!5$k4jq`sUXV=g z)*vHTjR9`f(m|*+Dz*x=EO!u|%C1()!F%r}9TaLe!Atnl?2$}A?nxk~6H7+s`+ao&ETmpONH35|-$I zbl7^<-o=u(Ngn4fcDtcAWC{N4Bn^tLEqW+U+TGr z28|2x$0R8}dUb)La<2AOr%*!uvert~BPD7PLt#J3IKsn^7X?K;)Cq>qN~=t_{Q-*f zt>L>`wp5ocYCdyfPb?DQWa2VUcC%=2d&QbTBGf52ya27f(wtSzv-XtGmVIjg-E2H< z7(gC!w@S`4f>$rwPI0j+N&h-;w$LfA`dj>&U9Y8$p~3DhwpMFmtXz_0%8m^Gtd$a_ z6oQNrP_@(gUsXHbRMp{FxHHZ2Q1UK?+LSW4KrPi2t+A)1=Z=F(!t zi+`DR-eAx+gn+7@;2uc7GvaX(q<=v)7O=J6tLvC+TkXq2wjNZ=#7RHTJhbPE5{0ZE z{MBajXO-s2_hw;sPSpYG)+5G>85(5~$nK!f5_#QupiFA|#BiEM0?LUY&B$zt-J|5x zeKReS%H-zC(op46#8dOi<_}#aL~-D>Gg2C^h2cxiNt?w^@@bTJ!ij-72-3!RpA35W zGWg|jD&oa2w(5@Q3lhtUNU?Jmfu5ahcFWC0@o%VOJ+La2SQy@g6ZlH)O-f9(7 zklY_vu)6w@fjwkA5;Y`Hd_BT^YTBACUjF4H2eYeyg5;cIR1CU6JeZ=bPtcDln{mZ> z-Tv6w<0B9W@fR`o&nGksMi~T~&a&F}|1R1w{9CjW`nPCjSnqGq4i?5+^5;$8Z=1B+ z@%0uGy)5oc##>IK&Nyi*iQhLxm;H=9rf+%y{OlbyS|K4B+s~7BJl+K98fAe~PwJ55 zp~x4B{@4^wF|N)_G!k<_uxgo} z!o)|el$ceEM#Xa6h%8XTeGE$~TbPqbidUm@CuSR$GxYYlt`M&OR-E0zx#Me_T82zg;^o(yqFZN{rJ6_H2!M zM*0P)naJn)k&)?=8V0VEpOnv%y(+=iu(+=jpOgjfagr@DkAT-Gk^pv~E<#BvrbZRpqPTxf= z(*+_nR~UL5-70k!{3??*qKY0FwOy5InKbF_Cq+`qgsqoRkF|fWTYR&&*R=i*gy!*s z74SoA)YNLMOqc!Mq+as$r+Ncx7`&vv_p<`O3+*4(4r$JhIsf?k#FQSC zcmp$FzmCj#srEJnEVv#fmBOS>rx`}o>X&MwgBvJLO!SH7`rO-gCOmNY_U-55e=_ZK zk^>PMF5j4+n(4XATq(^n!;g36M(Z@|1jHHJ0TLm7nr-Ya)|pE2mA+4>x<1dI3h9+_ zdK^tUjlpo*s@%>Mk%(CEM_jt6LNWX4S55Fb6sm?C4KFU;J~?j|7!K8<*R7K|MIWkP z?%%hbwTAwi?f?IC<@|4WhKuo+^Y^gpsQ$%B1>*H;hbr6`o6^$w8mP3|*f= zqn3rD3Z-%o3O!E0kWzt=_7pX<$zf{g|IfG==kjFuwHnx*(02;(Ll5Bn~&jbQsifxXf`Ms7!K#~S{FUthtF zDnAxV)KJFIBvK9T7hn&8G+1>lrOgtbP5)h1rsZMHdJ&Ef5>Tt3?JN& zv`Z~;bSW-x0?Jknoh67(uF?GJ(%)ly<6}u$cTGCf@R4^Wub&DnrGXJiZo*TTtteL- z$(1}m7(aAOvp=zvv%$m=_J=PnC9IEorPsa0`~)w713I#}`V$ngN87uBBm_V5y(I2P z%Si8*V+7hK7L!>-8aW=+4Bz*12*5sp^x2mP|2Nm=Z^Y!kU@7c>a1{1GI12k89EJT4 zj>7&2NBJvCqd>^xcY*gq{3;z5jRYgp-kjpWo5R!C2oK4#sVHPFp>e zwACJ1;E|sIOB{U$2?A}Hw}4wCsm$%W5Oj5p{g6M{GlKB+9P?3!pq|;X&Qqkb2|b^@ zTY?$$%U~}_+Ec|rH-Y8TKVlvR0@;n6S>(=_WfZXH_lA+kJNidE7ZEysp55t3k}VaW zWF7P7(PMg<7GP%k6aQ1AmaOm7)M0n&e+uvjjmR83y$x;1=<*#1XT9GEtSJBS@>Do$ zb-<7BT?=G4uZTKf{PyzP-h>ilt^bBjs1{jBrJQtR#~z;A6Ktjnj?Jr1A z!)|S9bPpvwv8rzqug>4DU)C68HoWe`k^GSF2N`A+a$fc0o+aAYmy8i@4dMDHCPp01 zS-mAug+FBlpPw^bKHJLbzBa_l!{fKyG?G-`%w$o~pSx=dNF3)EC#_DM#A)byZl#sq7Ut3f!`*^?brG ziE^$*$PD#&boX7Fj4eZ{v`U~nvR)8WzG^-NIZWt4&sUnZa=1bcY$R62SLQl4;@eXF zv5kz1)fUvkVGbzD4GBuKk*^QJ4QSpUg|^2jUGQA=3td}iN-y7g#fEmk$bn>5H8?K%<2HTC2~K`a;88?IhM zId;XECFs24DllLBG_u(=b@Hw0@fTGDwk8%6 zl1kK7Lj)6T|9XyInSd@1&TRXE57>3MQswftn@N2~a2Bcb3Qs zk;RAl3ih$6r6!tgTzC=Xv%qDhUGe2#Gak!vATnaD%^?t!V${R&k3Auoy#xcJ?)5$& zuq(+?8pGUjL!h*$_`i~)-hkWBBJ}7tfC*zRO?HV3_~nQT@Zww+RHWSiL>-=h$^_!v z1RuhfC#KCT&)l#+cg6M48$;rm$TyH{(4EcHfQ|t#y%t`ddE!Cllc;7VC`7{IsJ50^(7tb{ z92-8bZ!V;Z)X+m8R(UGjocga)ppS~tKu@QU6NuTgd|#V&-)#D1+P@CW-Ky!& z%u?+c#*qk+c<*z*Ml?zr!cpa`9O~t#XBH9_vGx>mW8x1Ho<&zhD<#e+&Iegq)Wk68 zuJ<)vaT1;)?6_1kOG*%>`aNK%t!Gg46XTv*RP&*ZCCZOIa(@=4tQzj)gHPBi`z$IO z|7gi~Rt6#NT%r7Z1f;qfU{*3!rFV;kvFZ9`IZGoF#$Ib4LPlc#HMezFo2g6hGuP=3S+8_A2>fYxzJ;isa6o*t61!JN{N z(^CEvQJyEOQNJJLl*gf8F|xn&As7y`wi(Fb=$cI4aqL01MOTb1zte(aq8; z(Ec*a^Vu{0n1gbTgqehK98l;7c5w_ai{Yfq{<3H$D52cb@y(_3vm{g4go-DOE{Kc1 zeEvG<5Sf}gc32$NSRstn67X^z_52DhoM`)A| z2+1UVt<`XFQ4x3cA(R%FTO|f4>qEQ>xKBVnj7-o+ZWI^dY1uq`7et1|a9xz)w`wET zI4nPzh`;4e0j8HGaKSJ=03V%JU)Zb`IJAoy2Xo&(_I8Q-&bV|L8^TI8mtn*4Rh zRe(g%af6w(1Uuikvzk~p3^yg%a>kG{f}5RV*5x?&B+l36`0LtR^nxjguFgOaNb;m7 zF9g2m@X{ksdJh=w84=1ifZcn{)G+Hzz9aVk4x1)Z$tOGIaKq2flm!s_1>nhvg_uu*fvo` zkcsbVQn8m=V?5n_e4R5k&m7j-uD&F28}D>{tKVJS_iub!*SHyM-kV?CidV1M->h6! z&)o(zg>mX>L=G9c-ybKsc`|A^5u2KYVnoY`v@gq5rf{u8uq8@J24 zhC5V8nh5t9P#4_W1)X-YlapG9Aa7>TA>4VOp}nh715uo*2;%@UjoRHgDl`KY=LjmfDl;053V>4T;v+WrHN zU@YeLP{uykV&$(-%Czq=YmDyQKM<<((C#GH%m?}DY<1>7y*juunfFkv1_wb{gtoL9j?G$r zT1)UQq*%H>^T*J4+Kv@f`S|>@b7Sni%J;s>@cdG+;5NtuHgc9K&S4bzwGJRvbhZtE zsDtF&}+qZiroTF9G{E7c6UP(O(nJ9^c@O$8t%xb3Ihl;2C5Kl`pBE%LyhIZP~{zoF{dqkpYW5SF zblSR~I?NJ-mrPIS5-n4C4**@!hcr zw0b9Nzhny9_g*|#+@li=OBml?wb%*xwPK{MY3jQv7r5F#`yqur<-06xxd6pG7 z_i~m7tDZo0S0GP)JZx%Y?jw>Wh7HOnjJ1nfF9UC{7$b=>iwNFaQdn@A?#hmYV1Ai@ z<}bS5m$)BCTw3plb~=Xh%XrJ=m+Fr-gG%E8+!}TlqB+Ex1aP~CXqvMNy&lOrNxlNN93Q|A+deD>M4lVDXqSs$2mzlAJ2}xC1Ux2? zmoRyry^l|$FE&4&#=Fmq zpAjy`my8WvQS&1DpRZcDsL?pxx-oU-G&^NzCNSONtk)Rbf-w+Qt8H?{iug2}{he2& zDj5)^QY?9^=`ldIXKc#d#)64dKyw~kNIFtUcNs3IueXnk{Tnv8P6xi+D{*8zk4D&G zN%&&vH}~Z=6=V>Z3uMuikQBl0*O|thN5?-sqjV_Sr)|_&W$Av1p4ToOFxm(2W<<*v zcyg-?R|;2>g6apvlXVJRS=xB4lf(E~35(zNVUta>Zr=bd{RR3Pp#mEcy z`kcz?mYg|PdDM;VaWWbAEaivpbIYow8x#xJb|3noOxQb~DIkj!(Sm}4%> zAy71?tnm-4OpTtS_b@qX`JZVI*CNTUy3^2mbS_dk)t1ZsT7P~zZtt;KkTesM$55A^ zZeo3=&5zmF(YH4e*bdT#E)K_xMuSNQ<cpHH=`gnSL1m~DxakgL| zbUWHueIXlIEdXCn>tQ6-`ioIvN*Wv+U8*P3KaHF+(tv^L}3q~*WK@OG*Dzk_2)4x{F3Iz zVq<6oR66-N%AJgAJ2O&KpgJMj&jO&&u>(*;+4Z00DB=ia0iQuVnCFcm-F|5({gs8w z62f(M_}55xLIyi ze0r3ZV9sYh_Mrs!D(-SToov97GvV097woQm@;!%f zWUG2@SC{L?IXM}Zh@Uz>%?Mp-|7O$7dq+bmo7y%^3i85u-X0~1zF}NX)M60<{_!z zf))=8#kPS`3{*T1evWhM807dp8op(LrtFg7J-{pVyE9R=M*KFBWw>$?@h`TH|En5? z3sriPXWMQ030Ercv7RG(mp;Gi^&&#r5R|#Er5kptzO(k zg}iPcl9^c4QH9YUVtL%$T_YQ9valY)R+?Xkhf0s6@8_LYn((R)bU#Xmdg#VXqGoClinJDye&iU-j{k_jW|#RybH<^GnX2!fVI zJ^A=0q!Q|T8VPJBK{4sp6od2);;$=m+U2{od+BrkYDjOsFLYrMonKiwp1Ov%bik`` zy2N{wS7ZoQU)ia1DjzGb%HDXsg*fSh`>e#~CqILDwv8VKht`|?J)4N4#Ed?Edukk5 zW9HOFH+B%_>4k<67Q{t^yX@ss!2PYQ*~<)$X+YIQdhxe^?qk(!twA;Eo)Pr)uWawI54BzF+IW6T zj7=pMN~>Lc-|lxiak0GDixhnEn!3AtrI4vH(Dq(H?0#}|yu2R^Id9kPrXRJX!i5v#7#jo@^;zEvvde-v0}^t$ND4rIkF&#aCN$d!Jj{Y z!HF#0R&h87(UqK@8tv~jJ{=*P-wRgTS^q3p#X)?-67~go4&s$Mx(r+@HsAS4=K)X! zlh2r*WPPvk4l`Xr28z&5r1lfetnJ_2w>4ge9@{_U_0#GeCkyEf^f}Lbf{<* znsWY0*AX|5BInrp`rgQgmmxhklWoh0xMRN>scE8QT+z+u^->zJ#oeg|l%d4nDJq5zyu|9fiDPwM^Lm6U>F<*ZKVx$MLrp^v$}&rbxt>FEL=zQmaj8&)L&VM2Cy zekl-LS@4&(LB44G%3aD;E&2EFKG{#hA}20u4hU*6U)mk>)L~+6TfghK2Vc*8suh{5 zR%97c`+0e)@Y3K#-@;!(a>%Sa>0Ew0;sSUoJin8Bec&MI{uN6;R~;Z&jv@F(}A5V55~eOtR%P=Z_9 zTcBk)k+7NmZT|A!i4Ws@+WnGwm2f;NE)Vl28U;hYWE`!g_?75NYaH89?R8p?tFp<< z=>t7~am#&~p8I~nbb47{(MJkH0Q*Jw}8?rG7%h2j{D<`Y@WJ3gV zw7SCMbU*~<)-ngx6bheO!OtlbTbgZ-^f!V6xLAsHN`_1}DlgiLBJ0Yc{u6xaK;Ap@ za{=6E!nU$6G&QIwlKxosCN|Cv9LBvE*({rb`5J<*PTwRdFZ>o@TQCkSn72(b;vKU>4 ze~^@J*-S}x62CIO+9{x+A1k0Qr=klySIE$H>ykm%lZK{`B%(nsXa*m<|ABfFVzQPf}oNrzJYDLhTBAfD5#Xgmh9oZBm zf$l1;+DOGEk3)|b>5-UTwtT@w{3*9vg}YVNu0I8SsB}>N?j}wB-Y%$xs(P@mu6NeMDj3?S^gxF5-R04 ze&X~m{DhR5x~lzKe0h3&iSLh0r1Q8AZ1KL>8k$Y*^CJO;6LuPT9!G%D+pLE@DcKUP z_*giJcx!7Msx=3>k}M{Ch=D#6oyMXHGjjyNrpVrzs6~}WOt0A`Nr&}L8-e&s?NGYp zU#X{=Incz+hd6~l0E#$2I@%tJ#1-pGZ~Vy|@GD3@{2V}z=`6!4#Bty0G~(n(jWrob zR_~}LAD~I_DY*Mpb%&sUN3wgTB3CmZ?E-V zttYaja!Rhl_*HP6Dks*EcA;`)HWd=#!PR?ODl}1kgF=fojna4&8ZxqfEH2mz-(TZ} z6BM!7=uYac)Bq~SLbu`1`07-OFOBiNL?J+ni%CHX@*Aq~Gg-tVa=CCC;o#~#d-xlB zyRiD9E0flh*;z-RRzxn4Kq=fs*`9L~|8EeK)%~rPToa-JVuZCR^U8X)sV#~JaP?Ur zgu-UHn6?n5xaI9+FYhQrKl#H7nL6q+gsQn5<98lU%bf}{WK%-X3Qy@5{2D>9m zwFFDHV*9N0t?z(~LoFme*cdudL^<9%IQql1V-=)nBCH~Pidyu^7pq=uxEanoHtP<{ zO>E~@%S#PuAc3-{5hbFHPiSPhgj_#|3uT?CL}xKmq;`(nBp+xMxnl7<_5?t0ZL~^3 z2@BqJvf}$4d#d{@_QU{b`PhU#D#3iR@`%xOA1>YSfr<=SL7d;rbbz)cy{n;&)HREm z{?k%o)NKc;n6K2{t{9B`76s?il(b=z7e8Z?K5cbQL;uD;nwa|Ws+NC;WU#BK`G4s> z#di#2APWL6@LmXcnG)F6sI|iV7t|fy{4ry0Pg1;KFs|~v9>gy@X|KPokHc(ap|v|J zSE~baPnq2`=XBC?rya?^A(YFEfsT~!_08dW_msej&A3;l7tqVA+XbL*44Bp!I~Ox= z;{W2h|G}B3E|1}M)}lgl#@&kNUX^NaUan)dk^pPf@NrLFV@Ah;47D)Who7jI-C~W^KKC%BUK5_hy5Q>s?Bq|f)D-9@v2cx)hnL;=% z_;DU_#YYyJfUWQC6!k1t88#-&d2b#p1Qm{$i`!csVhd1C_nyEgEH6!Yzh^M61?s?O zHppF)1x)1%(SGXB0qK5VkV+UBdv)1qkF4IdHa^h+Ef-_99qm^y^^q2L7)nE@3BHiDrGPV|4O0 zMDDD<8|`>L1o2xhrl>4sx^=cQ6vd-TBJJ1ZXs8%#TJ?F|w+1B6t25b?+2i z*|)E2$7V$pr@~57v2EM7ZL?zA72CGWif!9=a%TNkt=(2@-`?M8`|@1Oi`&0bawcDN zjeV7BhhIJhJxA+Fh!s;E^Fp54rclLH>P1a{Ly_Q@z^>J%WfHz}3(io;Ay{bfv<6f; zPF-Url0QEbJO2_@nM1DG<~u$b@VGL+EP=LvT~1-tSg9c(_1I&+=e_@ zu}fRmqX^u}t85dFmMi;%t13eIBBWZiq!I#W+O8nHA7sb1h%YdZ#yL~=f3sr#!x8rH z+7gz(wIl!1D*@&|{??eV{GA(N`8zkl@^@~8<)68c|K)rL>p%bG|DE}efA05xezg9& zo0yqc>Hc#*WI$^*ikQXTtE#H_5IkY$9RvoAJhQ|2*RZQ}Wwcdg4ZQmvMlN77`h8#1u2LeMWoBz*< z$lK5+;%4SuZj{ewR%D}>vIMPgi))1WHARtb^r!1ub_~0=q_|w$^F`4nu6Nq9lo}29 z-r4zYYPss-Y{kr$6+aP57Y2^BjULL4H@LE}3q&~H9>K$V!T!rld`AUbtMwiE8FKuF z1qoXU1(!=6yw3OMH zakVGBA31*N3eLK;S6AqJ6#>UZjqaB^R1_&MmFY7C6QH`4@h+SF<-S?6M#h8K0FQnj zyexJ@^OzIzSoqoCJxu{&kcx)cj%IY4*#c>HuQ$)(pdOihoFg)tSy^HoW+#C)gGU*u zBbNnvJssC)x!c|Ui}YeemuPVQ8I%JBz5*-+EsGM_jFx=z&|L->Va`;K9!^+DHAnOE zcfNZCoezMUHXynuiKtzS_)|X+pjb(LKWup)cbmYLVYfni7Cbk&y~0OC75p)wib3{f ze-%5o5d`oLZ*gPIyoSw0WLHgP57q~`-i2dZf#Qkn?|GlmkrI|>^8&(SC_JD=jgeY@ zld%yP8abFh;X1SPLEVrmA0CpJTY_wZmu>P5FQAcoC?>rbnnn#(?CoLZQz zMG^r8#$iNv2iu2uAq55YCWWQ@sVKZ!Ui2zOP?b!%;sNGJ|D}IgoV48mk;^aNddy?9 z6t(R*8bTd($h6+0BapnhdREz0zfya3z?|Vr)J7cv`2MmLQI>jaVPIHAe7EfnCRBT!Cq64TD(!q4q^mV&>vi=Tqu)3$*@h$1 z35j&u9IezIueac6YRlyy>}tQj#B>mbUx#pvQTB!f3AI@y#LKONKuWi+C6}OFpznuO z@I}|dnWID90US)%47O? z2{y~jW;_3=cvt2wFLEBAFsxVSFgfR%k!D}o0V~EvHV-V;ezltNO4AE$INzHM(al$&HMbBJw2u{EYF4N&IC_9*G&li%cc>%OBr|w(MFM026b;Qg)RA+j+?~iE89)rtV z8kF=IExB$7u$Fa_C;B{#++!Ed<W}iK`&-=_fS$KyS_=H0=uo29X1tbdBHS(}G#CA@pRCuhEIiq;DQvqKs z_V0y3g0zd=hVpEn^24~+t_qLcBWFdJyWWL|Snh%0Vpl2!D)qT07hR}|@rLH6T-e^& zf8>7c;W$;hRS3!ezLC;q=aP?aQ%c-Hh@2(hT<0M{V92^IcHYaJI!h?W@Dql0#W#6?}Uv{}9 zkDehU6?xitS|NWw8_EHO`6`)zbAfVsi7D1I9q;Wh0^!9vlrkA-gy#Cu^ib>~_P?LB zV>8tyg74fQYqpeyxgA5$PDI1Po>ze4s|l_L)<2uc>%(^Sua6^@tFQ49KT_yDFPLA9y7sNFn+&|qYK_n>Q^dI7ACC_*Ak7FoGGUTa)tXjBs=pV zCblS?(`oMP8j`PoJq^c`Ipf)FJ)P6gW7YFN7JWWH)-Qcp?YzBKLcGcn!7TS#TnekA zOxe?bzJOb}&-b}(e%{D@-t0!&kzlUKx?jcM#2Ok)Ry~?;MZ_C1trav~o;)!+tE;gVg0G-MM%^RJ_VvKK7+@r$=n-fqSl~Xh(?Cl* zxy#`mM~4IMwt);o(l8%&knVZe<1C^jr>5a31)2r+mczYxuJoDu|3OT;ed7$af@3IJ%o z0RYVd$FG&@T+5=cSAlHxZCG!n~&GyWR}UTu3%;{m4eG8_+(bC z1s8aa(h2I~s%4bQX)RqK1Ppdv6I~mB&*sNnFi$&AT6J?LbG1!}mw?63ffT6E;S{EU z+UEz7`)03WF)OW^gX<`inGJdt?elG6uPvo0Hcix{7cGQZPX#&SZ*%Q4e{?J8YXgzQ~x7pFx^eY8s(!Tt-tM}y5Kx{7ep+8Sh~v49|*Gbh!X zS;ih|qRDa5Ys6FQy}?EjNU>9{2qt zTr5u9SdMQ8rJF}W9vW+de8ldnhU3w?Han*ppZ0Gine;(=ogek`yV@Rn_3AB7Qd*S(jXo_DmVQvb-Bvz3V?@)_{7 z1y~4ityGs@hk<~d?7Nf#yWru>DJ}*-^5u=Jm5L0#>%0I{)!t6~`ctg|e>Ux_)egx} zK;yw3FQs&1T;9NtA&cP!aaV%LYco=&*u$VS3W`%Tu|{_#3sCMfPz1BTt%~lEnKjgpn|Jsy4%dxC$izU=Gc_1b2(Bjs4 zHL&fFL>0==K(%&6_GTQ2nim#6STZJ+i`q~>`q&EUf^sVzLDA3bE z--}{j#coYT=B=v%w2WjEyoOKObDsdz>?pPGE7&nvx4F)67!$0ilE_HlURiu z(o8@#<&+C1Bjj?PeBshzVaT6wr;{by>jn!C%t{jN9;{-^ETb1+DZN9J)`UWwY1r%o z_HsP)rMb|smyXef6ruLZ46zgY$j|vQr_L=>OTxdI%w+{A9AZ@ z>h90K9U3~3N>I`1e>g(%?k9k-%dJ%s!k=C04J=Vn|q)h?e+*UkP4eZ^Zd zWr}SpEjs)T*cSrr&AqC4dciC6y^DJvK{h4ad>)rO!T2KOGM8N zOV?66t^+kDO0K;&-i~~!&R0KZ(%V-ut_-MGO%opBk3yw3b$ee;BJ??&nymmQyN&d8 zDIQpXQSoD(tYUCrD9|82^nALPUD@xm5aXUWav#5e7I^OVF5h3MS7gm(OM3M$+XK(x zq0>^_Bj~>Ms#yA(0K( z=QK`-FBr2ML1hgRWymTw)aHk=7F~Ex;1R^@CokYtsumNYXnmt{V}j;!Hgv$B0c5q5zirQBJWz9_p`tvI zQ^`DilIsSv6RN9T5i+pLLyj_&McK@qASanH{`)5752kU7-!}Ln(|O7g+u;<1@z85XS9BWv`R+IadCfk+>c(iK|8!q%b6lYn?Xn-FHTWJ7nY1)zlfs$CY>NB~XhvMGb&-7xxR3uj{IIV)_;}pm(mJs;<82)8wWQkk% z^od#t53D7Z2jaSrye`-B!l(n$X-f8yHgKov1xUvR?q&^bPu2jusvX{FN)q0dRJNRu zmIBX%6z-OgRJz=st{!OY!EDd`OCF%eu$Y%6bZdlS0w^+kMUh>hV~PLY-K?Bxp!TKEND1 zmnKO}-eeYlbvzNU0&U<22=`k|_cneR|9%UFlKRRiZ{c+CH6qC^AQ`oCk|?xGUfrUd z!rlq5WS<>4A?-KOKJazbTAbCb=uJ(Etr&C*eRP7pP2rp&-uA1*=~vO6nh|5k3(ZP_ z*k{I9&Dfsdw;~7iSg+s+*r5xd55Azf2#JYOOzHtxRx$4lqY?@_2DzQ`4)SYIS&fz|xy>}!>Tgoa zb_b0!#1E@)=t@Rw19l@7Ew}$4MTYnvMMf+@k?{ghWHbz}9nwGZjm@9|6d9pW3*~C< zrm1A6nMPqor6p)YZgcW>=Hx!QQia7Wq>#ZiX@+stR(^lr>R}VH)yi5~vUUZ-n&6=j z6rv>nt`@G|LWxRQ*v)o2s*bAX`l&l~YHpMDub6AdAGAGPve#3_YDs$Wk9JhZQ+5oa zG(7UDAXn4$XrfdrmVxe+!^vnVSXINxpeK>YVo8ZLa9I+^WLhw>=BcNcxAdFuA?m{} z)FW#YPp2_&G}uN4tpNi5NfzD87F5D{-w=^%8_YwO%_IGpDgMimQIF$hsuEy|ux4HZ zaAd6fasi^w@&`t;X|i{*YA_xZpo+$P%OlRmKP_^PqD^S-kF=fX<;I1 z7@M=z8!j{~KXk-?r%zSzLe1@$vAt`f)JJQ&ke4%Hqg{vTnpoxy*2${U^J(iqd zfNoyG^OuBfC-_H_ff{Nww4pDT%MuKoCt z72un3Uy1w)so;ly`rk0JKlS_nGy3^URayQk+fPsTf1#=tYqS8W>ZiRTKs;_LOq5t1 zlY|aKPW7BUHRE597*7&qwSYkUen0OWuvZ1mg!1R~!{RF6K2czQ0W7a7~Nu5O+8~WplH*c*`km6WO9ZzUU%$ zxV_+sDe>76VQ{S6foXnYk%hCLleH+7NfzJwE%ht*sFgKxV2Sqzui9LQdhV*oRMjWHB)(7Vw$}_RN^@`JJQbZixepWdNQt|y_}%@X)~(q zs(ka7cQcE?W(^KxHSH$2&uMmzkTcpNJ=^#)o4#4#*7xE#zj^lj_)bfM{#i=P8_Z~j zTu%#5KqAV1#`ulTDpenCG;Huw^~==J>7*F)ApD(jg73P@XD#Wj)*_}o9Zvf?5WDKt zHww~~O@sX(=J;0G>Ox(Qk0j-AR;v(t2(iQa6bA7n_058?kvc(&^ep!S4wOUpwx7D@ zGcpEs)bEzmnOFO+4c18oVp`9w&(Qo6qzW7BEy=Dbl%J4D=pSj~ zCfyPp!NXyxZ>`iZ^p>7=D`O*2|1{zBfu#l7OviisZ z_xnFTxBrD~nOXl6*`8}@RP8m!dSB{HPeSBgc>_lPpJ@&8`njGP`t>6`QWjYR8y2-Kbc6q)~~_)o$^K;JD|TViZ=gJzBO6J_!gg@DL+creEW8N_ZXj+ zTU1uTYx|z3l=;UcQTJ#q{;kz?5+71is2i=`tuwQpS%H29yDsw4xw44I$L>WY`;STj z7|YUD4*YxmSv?@W{&s$M8lE}#Z1dSL-8g9uGx!~2l3H3E9KY`wp9UNC<&5-CsK5QS z52FY_1|b+n4JvOX;$bVuez-t7H`x=Kf$W;L1ns6t|;z5Vs^_H{F}(=EF0@I1j2 zhLoUZcn4MQ#&SYIkrarB-II&0fYf9LiUT~4WnY`;*wDJC{Al8tSl0?p(%eFI%UOOQ zQCQt21VX?Cb_I-mEC=dMyt&c%r+&t`Ak~=76uwt%wj1^ykaWB!baFb5SjES((74rknf>DLk_vK& zW<1(?D5zi5op%Fgjt(qGlXT4dk(%yQVp63>%SfSaCH2azkad1g;O4=2JCbNmTc$YbzEh?v7g5;shv1P%;MQ_n zd~X=-;20#=sD)Fj=&UJ_GLK_;3YngU^|Oo9ZeL}Fda6pnwt<>If7n%kd?gmvhz4Cb z>TBfK7;?b9W_DjTIGkheif*x*jx*oU{&`;7|bc!OiCu z)FtD|b{4f?ZN zGw(rCVMDo(Tzv!ELV!?foVs$_bg@`X~s-{yX^==wQv zj8*wooa+S#*s;mDgilx&+y5XxJ>rbW-$imH<^s>ih5xb$4MxVW!j2wDYbs$*Z?^4tdIrD_r==SBh|X0P5HXedC|AO|ws!#@$!(jxpY zFoBB(C%J8Nn#ybXYXj&5y?8mCc$vaRXn6&K{<}PeLSoIm+91_tZ3{Y(1HfMdV zH&EBLnM5jJu3Eta}c-z2`v-}3ea)YZnpO1CC zAK%4^&&6q?f;W3z8`Xzl+JjZ2ul-QA-#2CqLM|(Q3PmU%6UZ@=$w-EfgFO+W_d97* zOiL2iYci|HJ~lt6^%J@Uukm=o)?bN>&4k@RS>UbV)-?~MfpqqwJ)y;O=nf>!K6lCZ zC=?yIN3p$NEObuwhQFvvCYnB9sGjK13|C;v3;=ez9p<6AqPPoqQK!3HS^htT>(6hSJ?*(&xAh%CxaXk_TM3mO)G80DU-DD}vmXNAZC$EYiaNPXVF`wwNu(*3{Lphe z1z&Gjxy0K`a=F0}v2Dz;)yn0P!oRa=RfAk@yev6SnL5$K_Oy5;JsG{}ax2fcF5;SX zud$#+PGr$}EaHr8aJ_l+dxW?X99$oFn>sFujoC*ZXz#aatQoBDvgvZ9T0CEPHg)uK zT+NeiWGN(N;fb-VO609=4;c{MMpuh-m5fVpoGqm$o%jFdA|-w2?LEe0aWO_xK_P=>=OD;4(o53~4}19>0o4 z`@^`tfK=TC3IYw&u$P^6OwaL2yt>gXpr>7CqrpSM1XLBe&l!6y*iNh0XgIfSB3vv(+PtqEEnT4KmH3LsPK-4IODNFck&(^ax3ub{$k7XE+_>#d3uT4`AL~He$;5i&` z3}A`s!Kd$k$8zV&34mb8^*x@t_`xMs{)H(EY(>~sE8D0#H)}AFsS|HTV42VB>K5-O za=rnf$I@)?ClBzg&mLGrisNqygl}cb_wR+3Z5oRHFHe>d)apZYbe&C9w$=4X7s*`uqh4l0Gygg*64D3Vn^+pcb@^^|_N(Ejb(87TNL?Hy3 zU5t?ACsF-auP+QqOtYdNunj-C$Jq_#alAOe5K$r!180W)0=&8}W+nyQiaU;M4&;~Q zFxoAvyV{|N5+`qbdGO`PsftM-ccZQAZ$_?pvy?9FwrHp? zk!7gsed_9)&rOm&?Qs%`t~#{g<%7@6p;Z|WC2ru8gx5q>hF`+K+LC?{R`J08Uhu3; z8>~EDu3M{Fk&r8;EWd^mlt z3h8=12DXpN-x}>RI!VL@@yJRf5O^IknbdoM@9--*vDsFvjOy9*K0;+5tYZ5gUZ;R{@hIheA81 zUTJ2rHwxEyM0hm_s6YiUL$Cc5aHdva7oyf1e#FSurr+4n@)MPqcFV}j?tPE;!RAn>9fQlKS# zSoT7>!N~sTxrRzt9gNruy7}qlw|=TBV)2OYz&JMkPh^Q#bhA;KiKT`->D3GDrrbmPw5F9Ma5-yeJW|j;_AnoTe^ircVK+MVqc2x9EXa3?ogeOu4;3@ zaE>e%fDA=<+)xTn8(3e;5__q2QlssT^py>!a%F&zF|=2k)|XWiefJn})V- z$0sUnbJ!d$+C3(XbDdXBf@Uk5ylG=asbI>$n;q{dsl(oUDnTge9Rx!#2-zvpEKmwZ zg&lbo$oAu~vzpVyd>M)&oai}eSUwSE<^fJqSCGZBujdQAx%?a?)C~^ZZAM?XU?>|$ zFAb`A4Ot$NSMOs5SPL_48cvD8_Yk{GCyxTi%X%Enn4f0bE<2bY3`0urw0UogPBaUY6_$qpMnF zYGKv^*#mdip>lrTOqRTPv0CP!Wm<>0vV`PUu$+d>Vmrof z^nPytI@uBXuuF4C`P7ErCkCJLy%Au}mG|Ba3hR>@;r*UB(G}SBX=i`9886@d?zKP3 zRlyHc_|~s8N{(rwIVe*FN-3H0CD{%%sdFm|jdMfEzI)=Ub$Sh^M%dP4k2%|*SHR%b zMYoVOIOWf@N0at-+orhm=eygIde{vU{+fXwq3U(agg@E06cj6^6i7%dQ!fysMqmYf z_*=702~)`1tI$t@O8nq=lhv+`FJxo*^9P_va2Yu7V=eB!gR!y=6Q*$e=vOB=xx&`O z!kZLp~5DK@=d91Lm5l947FS*j?!MA(W*N~?1O=TX)g)sJ9XISlOdL$ued2VbXFD*HN*x#57{*xrh27qYU( zr&Mo{(F=SC;~+W7Ri3lZiZ-e&+=0J`T!=Up$ECy!RWD@1jI$$2HtxtUx=-gFn14;t zo1zqT+byOgtdG^Mp4C|faeFuv$)u>8DFhlPh2+;$Wj9eGCvPSJx#{9)y_@`ryg&Mt zZ#QNao5ur|nPhSMk{_jzE@BvUiDNFuwFXWHpT4_oey`}KNM#L(D<=f4@>Htqz%UFs zsGty%m~Q5FKu|xP1u$+R>OFb3VENyt*Y?^%Lr5AVcJ! z2^JUn&#^6SxLrX~Nz7zM=*{1I$#go92-$^Ts#7O}$dzhBKZ1*aGT|~&qbQ>&T-mL^ zw~3w$d0sOsgJ1zQ!!~({$$D0)2`yd?R+rNS#&PGf2(vsF0-&vO-(Ayh^FAZxU-Co^ zJ&^ix(KBDlq<)tucdzEf<*g*>D`8jG-bzN)?S)wT&)} zo)cyc)gq>)sBDRmH;@u*{zk7n>_MzaK9}30F$G|@Zz5si#w6Jc$>PezgnOdmHSAw1 zV*z>CR%FwBOcYZxN62_xC4=Q?0;-m0WMX<2o?fO09Ixzw=zQM}6&?^h6^6s7+P)h6 zZF&x0c_JQpJc8FSs^t@rxM-n3U>8T0l^y{3Pr!OcZs%Ey0vBUtS#~^(GRh1)<8QJm z;E#{JCNQDOJ0Z99^*& z_1CiB#E*fk0c*a*gA6!~^|aL`@IPhjUm9VpqsCpQ<1IUU;}pj+Sb85|i=*d#`7Bsp zG}E(8Q(O6yf)9@B7gEbjuTi#4V)gBrH0kc#>lM=p|Fp4VSvcY;D5J1JYvAJ4u0uT7 zgs#-LC{+RK)2y>^#RDJ}{e8dBoZCSZLl~vY=&=7Vl9B^nOs7$~f}UZv4j*+@=|>8x z5@e)%154D@>mVwONDO-x~zlD>H#gNOMNXa#DTYithv%pE` zqXKmF>N8bC)<9Sg6xN7XV0ATKo+fUYw+|X2EHx_|Fs9rP@HeVc(P1yrn)>IK%Kc&< za8Is=hpJ_=Hpr#3-PMm=GjF&Ss|J5|wB#|cQu5kd!5*icN@XxJBfu?$d2w$4B5%il znx7ylO5)yQIP!y)da{AMR4X`W%-2$U(0$FZ4>c$P+Z!pjUq$$C0KO(neor3RAe~qV zmM7Z7v;J4}M_sE&hhXHa3JCSw5HB?_2JygD?tC^O=~d2s5zNIA%t37Gp1qZAPf$$a z#5Mvm&adUB_Og#2E?iDtkUu@_OT(*6+pEhp8qD{@${WJF2tE;my&&^Z9&XrzQB9kc z2VAzJAe?}%mnl5J(Zs)NFnRRiJgf6{%w^Mm=7&xI-Wz&n=JT7)9$f311KkSQst2=X z`msv#-Se)a;4A3=Rs_ER;F@oL}cxm{E6Lf6LGeKFaO zC)xZ8?jIwDEE1hGBTc{LnKy{9A;9MRzCi)Zt@;f;qF7XzS3gdwfqxqaGj?+p=F_3g zBl~m5vM=jGO%r<|u#q`9?nT|RyWmf3G(Rqu?L__3+n^b`ogLFtwbEvFp~I(cYOs2t ze6&_d${ICSLcc9Iy}vT>aoxBZ)6-(=8?0yy4zlC~FbUwgyFcrbsTO zeXb0%g4ddV5s#zaplxcX`bC}q+z|;J`;259Vi;=>h6qbW5D?{{EYZ@}7_N?~+zGM8 zOqzu(ltvpEk3GWiG^t~}qr$yBNXQ6do!^_9wLBza!FA&qugNmJz{R*rNs zYQb+PMB!1Emo=VFc`Q_vC|t*n_as;f<3l0XK_E$xn_s+dmt%OH=by4GnI}o2rX4BF z%T6;1AeMfYPY$B&_;#VPp@dnw-NwPiA!m8js^e3(V5PPy)#ZA_EW^SfgiW9emM8fA z2CiJ6X8I(6A035Oby?^W@k=i&Dy#R0H_^9?yy$>{b6Oos&ALu)`1gTUbuI0-*?5)1 zA(kH@k{6)I%>px_EIlIOEO|(N;!Lgyu}E_Kc+=n4Qo$43f2pw=e(U3Yk*V&EUx7++ zJQV-|MYUG?IiQ~{n(Gts)~vW4MI7K+1`|v?oTao~1Oy7?@Zewi->mrma1Q(%7_V#kFdIo)za-KXU4db?&xjKF~QbO zk61maK+|I-4$Kqs?Ywm1HK>-$Q}hQT%G%4TL&Xjso;jD2~pDed#RbEm`W zuf$CP%DA+Z3u7BwJIkK&`HEk(xqd2^@p;XI?etn+s2gE_ZF#nr$ONtJv64My!qNjO z*LHn;NF$9ubP<$Lh$^6Z$4u~t;|)K(%!;XO|6BpI#qZZGxWmxBe4WhV&hmbI^m#q#Tg0DSkplh%y?Va8)FC&D zm)`&(7o5mY_I+0UaI%%**#J})&Ek8&t`v}y7Q|~a1Nz&&-->v=T-F2Z3osvnluVvZ zx2t}3IrOY~xeWqBV^^(=&*McH5d6+-stiH}O6=l^h*yt4$>{~{i8U?Is6wjm(eLo~Xhq-rUTiAHkKekAE^Xq% za(4O*f(Ye2&QF@v(320{FN13AN&VChfigHm5dd*qLH@eRunG9z`05yIE@Cp=%L(Jy z4nDrlslq}d|Sfiaq@*x>6AnVD3lyyjH8V^9{ut-PHnR8 zddlTlnoyWez+41EJ7J~Giiyl85Ytn%tPKUGMY;kI`1M1Sudau?Dj6bkE@PZ@zfo4* zNX0DQ(K(Ztx5Q5C99Ni9F`bI1&O%^JGxI24-&RUAVMWYe1 z#SNdA(HS)%;KS|>%qg|viXYjp1*ae%(TEONKOOAk(*Afzzt!L!-1WANm^A^>J7oOjETc(>4-T{! zX#ii=q9W_!=7s9M-s^PPdVS_V>`s4(2~HW|jSkEkb8c^c<7?R9!m<0*FXEze4Me-w zg$E6XmG(q@Yd4FH1DDpW(B7gBxfS=ZOL`d3o|lf-R}KeI9{J|ba2Xe!R;rqYraShh zwtVf$_vMZn&o$!kwm!B^{%z^xCK1c%hz{ygqQSkxct$rf7&W6XU^w>CVyfTl;DC46 zUoI3D$MP+ofhR++^f;+l1w~Sb{+T1xU&oT{N)Z@|>JE+1Bxuz>VI2W^c)RU26>M6;+FI&Z~<=$X}Og?LVRY z)MzulH;)N(vYeDp zp&-gbQNso~&!KEB8|E#rMY(_J&hd48;q&qnamJ_~2?Yy`b99|ThGzMB9tpjSo&b+U z=uU4M(nS0D8~C8>%OkTCtq`@Tg)MJj5R~Us46qFs29@|v?ftuNfG~hr)lROKUks?` zvqwqD-ZdRsPYdV7ydAgBTwZy~jyZY7wTL#87he17w$iNL9NOI?*4I=%Z}6zH!k(YJ z$G=ph0<-ZH=99Jd4sr_{j7M9kRi|NORxpq(k^uvA{-q&Z=u;sG$UAfrR?(ZirBv(8~4!#uLgS| zHQzCU%I2A4l8*3|F6@=H($a2+i&F6*@g{X#Vn^xX6;FgYF#Q##b*Bmu7T@iS=;uHv z0`1^)-g+*Y6lpU5+3&sI?Lb-X!)F&dHn@;sYp5Oe)Ox594D#u4!l7LQEF@~z-_Vg3 z@!c5h@iWl(d1$c}BX6ERZbNpDnu>IA6>Lj<7|a-88o2As;%=sJXVXF-^lC>S zGJb_Vyc1RK*vMoGO%H8MJNr;FGK@-+LcT@V^o-d}T|XP*Sc^faX@u%Xvo1o`Za4PZ zB?9AE@!1i2N3M{ooRZklisme?Ujy-P9lI^-PtC`Oy|A+*z8|yBRdkd8AL`yQ$d+&I z_AJ}BZQHiB%eHOXw#{9(tzEWl@3Oo8=bZO;-?;bfi0*Iq!-~kYa>a^VnRCvZ`TXV> zgIs#^l0zm?pb684R;p6WO0MSbd%9@aRFk^J8o1%u^ZW8otQy2| zsU*3J#3%C=?XfpPX8jUw2{|u9X*!?w^m}O!)jNXx*0UMUNx(H*Ank0 zeJbTg`RMT1)6IJ#+OW&wTQTpmCI*4`4dlie8yTZ~g=q2^#oU~6t`ztO4WAn?&5A&9 zZ&h%Eu!E%jhl{TbulPv%WOJV8^SM4p|Lg?I-Yi(}^ED zpL7Xb&B<#jV2adjJW)4QtbT+~6?G|-ey7dAJMfLtxoVj;0}T6&Njm!g5I&Rp$|Q2__Fs@@Io0q{|T)W@=F&WaDF^S5NyvXL`NJ0N;rG7!fzve;&QP^8$dzQ|t zlQRqUbT+u4`ORP69Gs}{sL@ni(yLk7-ir=rc{rg?)MMmWzvH$rRQ^_ewOp7Q+iEzc zpa@$R5R{X7Su;cBj@kv_`ayfqQ1kH^4vySx%4$Y2C+Uk~3%2wtR)>tmoG>@Gj}SgX zBV#ycC&to+%z*$glkXNm{(OLX-910J(AOsE!HXdf0QtV6Xz|6h9;0YimPIR>#Nyik zKmP)X;dWcUt`#we0wjbgrsai{G9te}{{riN(QI9RZxwkL^Z#ldP< zDu!x+I6qUgWJwr*v8PSYLmuZ_pp0RzgtxKqx$CgNoK{|Q$Nwl0LxAh@v~STu7EY;=YlsvogQ(+nF*#_+XAUa=cCtp@cmnYCi(Ba0m_*PH%HsNK>rN4uc{DtVP+?AC0>E-tiUs>YZ|QwPX%I|5c@ekaor{*hNV z%yvE80~>qNQUIcrNbnX^SSaXd^f7Kw?1qZdc4Pj8V~wO2a>b?Hz|x)9C;9oP>xJrT z-5y~O#l?o^SXA%IvtciDq5QG6UU&NF#w+o_f7~qk#Xj#`BZ`Z?bV>RbPIf-xLEbyd zhv$@mQx{Nr8b~T(%i-Mfq&ceYrMiR~EZ$(+tp|A7U=8-vOnK{R~jo4yeZvnIXx!`?|?d&-74(tAXCGntp zS#Q+3K&v=3ok8fdu5BIgEsIvFv3+G$aAT8&%$*sQGvVTRH_L3aHTd{+_t_McZqA7# zIlM*767lKXpg)uiDdz#G2Qad9j$?yVH`OLJO+ZJX7l3zJp$^GEDTzatQ=m$t4>66) zOP4h$OaWY!)AIA^q|Oy9?zpRn0QN%cfXth2A*K}ttT{ed$-U|2gn75_vZiY^Pn8GH znO_j|Rw}md9sKL+-9#%Kk0#jDXvOlK3G?k|X$#1;2W+g_l1+R*bs-LgX=8CL~l`K;Wt$r=^p8z2x$28+a?D~HJhv$}~104UakHiaZWTOsPK3m`g+ zBuk=Bq9u^lVJxd0Y)c2g`*jQ(S~zocWJqaN%-jDuoVXkS@{MvkB^b;rZoF@@Q~pwt z9=xj&sa^Mo@I-6-0@ogcxZ+|W`TpYUOCfFUo>SIAf7OF*mqHG;n%9?x*H`mu^fqkg+$Hfb`1LFFBpicw zc2&X!wZUDx?ERrb8kS}C4$h_B367gjj=TofM}I+E&v%Plj|(410^mj3z}pQ zRDAf&xO-fC;EEVOwx_nW$9*vqr7iK@$l&!yYbMx+)y*nt9RFx}c3++4(DvG-4u!K| zvmWm^3nohjs(D8vz_5E}xEX5IGPRkhi-z{x{Sh)~kSO>SyDcmqpN6D@{EW3Hc6s=@P{)$oq?{p;C+hg&lo#Br{mcki-@W5{NUNk!#R7YlW7XaiXV`bG=Vjjqci$g< zELa?Cti{T?vs;{{}lWjC4Yn|K4O z*Ok>j)f80q2i!h(2&{GRXjkm%5SOh2b57>{&+op~6JVq=SnFm(z)rRZ)Tz1O9J%YR z>pwFFoimPHo(1oYz7mQ@H1NfySN~uyJ33%8O@{ndim{!7`3f;aX4VFC9OXY za3gS|>U1Rt6&r?bYDp)I^xemTbXzy^KMjv5{$zgf9yv@HN>>BbiF?G=Vq|?nV`{wX zMzVU!KPvw4&AJ_zIO-j%Bn%s_Au-qDpcu@J0QPGlse2%)X#wvq5lg)IFat6UeDXFF z?N9>C6!hzLj`3=p+k=d3dJQ;flc2`z5*%O?b?4?G!EVbCqx<@;Mph4}8&qnyWj2hD zok5ZPSy|HV>HS0ohoVF%QkGTs1IMDM&ll4{FdMjzpT9W^+lAtCDp}Zx!|`Xr_bxnE z!LM6H^H#GO8r-$;vtN0`*)scSq}Tma^G`P>qE}$w6Eg{Gqn=yNV|M@ePER1O*}S2& z%I&?d2%S={(_?+|bcLR*i+E@Hh6dv=?+(JK%zBIACO@*jJ{Oz|ei>3|2t*Q)2L|UGa`ww6zg%R!uEK<(p#7xWDLHx}=ggrT5(}|A$AHuGHtVdL!4=)ASi(bNvs6l7Ns?CJ< zcBPU4Y^f0+Jh+eQ5(~Ocx+6trOt!LY^+&Hj)Q)DaCzQG8=h&rXc__BeHE-dxFtpL2W9J10O;r2D;Y3V3USAKw2_L$czN8NEitn4P$AygFNM*CQ2<_BI~B2 zA}!nr1F(cY_#Gor`-86}i~w;VQ(^ofFo7_Gzv~nf3v*Ivp^(VeTT(R92O!6l;fOtA zB2PS25}-mdA;40KDga?^0n+d`2Wl7VzRU28OY1YSrw?@?LJp0t{Wo9d(*yg5ucwX2 zqsH2gQyFp&LEW0(7TasvD|4!7$PYG0spx?SACCwL00YPanh`@r-jG(E;_+dml9npW zhdqp(lI<*lxv4KJHHlIsYB+_W1 zkSgvi24q~V7!scit(8JfvNB(;X5xT^ku^zFv*uDTK?-j%E$Kh03`xcj$QUVgQO-=) zQO5L^Mo%fAl@sN>{ZvpToBt6-7o8C|C#V`CLqTlNGm|OEpTd!ONSBH#x1vgl-4RO|+xiAe zUvheiN8w8XYSsFJ4E#2oRxac|6o1LY6`)MOr=*Yf8P2qRBpx3v9PsD%#JbXNw_Zv{ zdPVf+TM7Lk>}>xK_7xtKwGi74sQ@tI&QkITjqa^b?6dEjt6a7Dc zT{_dyO;P5M#M;IFAt^85Q>&26#&%emx*-hvvyn~m5wg9z%&imB-vi>5(yw9+9GvGn=K@=@ zZE|ON#sn(WO+~ew1`9fG6cNNs5mJyWT@Cg`u&ghOJr5eY+;sOl)au16fK~Uv>Ibr` z7_rEL-|3=C{}~~LS!eN8J1LjVGVGRK1p`^bYGs_mXuC7{f$a7Ff$Y3SHfo<8?d+c% zEIA0#nphHH75+WAH~L(^)`(;Hc_b4Mz7}hW3_^0bdUCB)RXSi$)8PIwn{Hc#{Z5ab zy!-*}=$;S5sP#}*qxkItjHSSB7sK)g6I?ZWwco4vy3~pXw<-S6kBsrseUOrjP3Ekp zNFA56Z_0oJzev-?O%rRaLZI1#tDWI$^#|({d?tTpe7Zv!m>4?PXwV+m)ZX0Gu9KCv zKW5YAn*qE}Xk_KC+LIduj@}=Zj5nc1A$>ny)4(-*ducWLHFUjukDq$IpYN?Z0rNCY z$nd^ri{8_Xu^+F5H@25C%(XuPovZ>pL+-E3sU^jvD;=&K1|8Z<-w*!2Y(Url4RZVk z5B~Rr?0<#q|8kiAe~0Xg0tjE~Xx?*S*Vli((sd}oRZ)TqXEmWC;j^Yn(Pfej5|JM^X>~Xc5z3w5YlNway7AYj^|#z~LqVIOswK z;UI7=1i%l3(1Z?$TLTOj(-JHan9SqlQzQ4ztBPuLJ3pAJEKlNT7Ur+bqc5{y?NK?e z%t_6XI^NUt(Mb7n`c)&f@?^O?JhQb=0sq+~=Yh3kx!^Lv6+@2({dk_u??=hfX+|oq z=U?r7dK?W=EOwAk;7(4fG3}q7@Wl3_nqyaKA?CdPwBx$^=9`Wd1rA#C5_6GCJgw3~ zsak(ZsoD-$o~6w?K8izoypCiN+02_+*x4NT1slXyrU^>LS zW?WZ!qJ>4HDD?0`A>|Uu4y1W>#`DFYXgj+*^z^K?JAK_Y`Cyipn^z)eNeoQ<$M0X{ z>{W=|nm`f*W~E|9?tJ4^xd5;bWLCmCEwnD`OB8FOiRPlAT@9wXX5&n(Mp}JdLyWbA z`cY?+KoNf+3WapV*52X9KbVmu2aJgXN4Pc4!Fq$PnQ)t)b~BUP+iTuXCwY%izz$T@ zV(NSkiM{)tEh|!K!lkl+5yg=z+$Efg{2QEiZF0(;78X;NSH|%s?1HTqm(3@~7GJB> zrCTP+a@1i^b?D7SVLt&H)F#_(4ra2*MHeHQ$d%C*KVEfvAta0Bzyhq zoXJHeqvZ-tK)g&JZU#WQ`bo}d#Jo8=cno+AE13tdYfsSn<>7dDVK0DsFfb}s3+4D1 z1^^B6p4;4a7R0<$RN!!TQQr5JhLxl;%9y6Kd_KXG`>q8>%cFf*SY6ci;2=F97y#y+ z-v0mE_Wz}s{!iQg4{qmR_%~kXVE8v)=V16ZUgu!=7heDWh|B-Y?*Grh<^MX~|9&v| zkG`6fiQ|95<-^g#u~(dzkQANzNPAHN97`ECv3R%;|Vkr@-Wx<|5s>cRVdZ4x%DHgG60##S55>*eqU zkg}E`eJ!$V!zs*xcs)Ppj})nam!=p_g?hP646I<-8Dyuc;O*B7;1wih=XfH15Z+^phCg}2i}Bbso4K+ppMA1{;T!F} zOZfi#j(FTq&-?uH)rh4xs_~+=xsV@o9B?vzyIIih`5ocG!I~|kCsS$j(%o37H-&%U zrM1ln`v-i=D|2U#EZk(p>WF}bPYU=O6vL4w~|f}3oOzttG$#%410BaufvOiNX7 zPg(d_v4&|njlfItPYkFGu~@`1NZP{&c4WT{cF{b^*@>{+QUDnJ>eW-7)j_StfSAlOrFJuV`V53fEw=*=5Wo5Wij^*Cn2Z#?abvc8PQ%Id0^PiW2cq$P3a|2&8 zpQ{$BCyx6%PIQ=B+1kb#M8V?z1SP{}vz&IHAYQV^bTGk6ie}(ZJ*TAorLwXlTXArc zzO5ZU%aUS&^6NmGSJ|Kt9*|kfNIRjzN!WYkRPQQ&zNg3$t0^OsjzP{?L%9r@qvVABqrO7RSSlP+tN!D7W7=W52mRUS;1Q zk+(a8jf9Ps^V%xCcYRd~_*gtZ#+!lMG}H9O3!QYgMg~eJg-F2<%#7hxRxi0E0Ss%N zDMPNeqA83+K)$%{!Gs&=o-+ty-4Bv#*iDY`cSb*K$HEJ@g3kG2FxEUwlr9+Pu%0=L zYhdpt7;+Mmc84jx|GbnO>*LP;HJgMNMV}EyU&lZ5Q0Y)~ops{^`lP*1c=a^xFcu~D z)oHzZ@TbO%b%3B{I<_1yT}nPslBq03m(oeJMmSbfLI)^6*F;XU#yrYG0_ue&(ph1QM#wx zWmJsL%i`;LgQ`ORdx`H)i3`jGdrFD3m5*8zuice89Ifa{s-cfR1;t}UVZOAUQ<5(!P8iZt}HtvM0~+5$p=mD>vf)EPNH6 zv^|e?kPi>XbXZUU65O0*8^*ZVBg@_RtQA}k-XwZ&pOj|1;`6Sy5>&%?#{K<$_~-0l z`{>imS6%)qmFa1F;Bhh+V`i^gy4Gyhdgt$H=!3K;v>Dr$q32Bkv|YwUXz8=8`1_bV z_|f<@9UeOi6OF7lz{&IUFr+UaM>V_QuYSZ#LwucrLtWu5AXIFj8E{y57e>`RwOgRM z#QL%5Ihy{z(Lp_cyjHGYFOKED;{t0iVEM8(m+7`(KgFj2aOyP3%~!P~Sj3;Wbnl-P zQTR>K)j0N5B9%~nIwK0KGyQg48v9{LFirjw{$VrWP{f)eul>qUc&5Phb3nf(Mi=Tb zKkRQLU*+219TB9mQV?l{-W26p!^4k z_v;yYG)1zwF~;Zlk$uO{$;PNHE-s}}+Qu%=_1K+L9$Q|{hI`UfXy?kO8(AjQDGlA) z?#WI&@+Z@!h1bMI?3Dw~uq+9&+hdyiv`d^9m+2Yy;}LS^;PKbdl0g91SUMcRB52wv zJKKjz&!Yi|j_umk{v;V)ePwe3cdPk+F1uXNVuKFcQ0?&sN4#EKJ6C#I&<%L1MTf7M zta|UufyYz{+`-BVIo@#=3UjxwHHgg|kLYrEngkKdxOllF8oG`Iq@mRSHWMY_0hTW( zfO-AymxlTtFB1$a+`zlU*iZ?p8}W(hQr|ZB&CYi_r3WAlGZ_mnFk$w3?^J zEd=T?6T-WlMvj-0MFh-?#lxUppZa?7?l!JoT|FN!Jn=kb6|JoVC=(o`C!;kExm%Fd z9tXk%kB<0!JI(6fN7|w@+=YH|FAgrSW6|Ngd|5XSS^YO$RF47By?&MMGCml}3oq=q(F;UCk_4{BU-(e-hUDxt?y?me zX8Sg~7aT!C=+TXPc9na>8EcInxgCtDL~i+nS3&~+j$$W>TGIu`kyliPnA>2_E0i1I zl-?IRW7kRNiOKoYVvoCl!jiA@@|C|&snu$YWxFA;0}Y12WL>&cUP1(97bTqXWEKrJ zHpoaeNGTp6gO*do9Qi6R;36`A35P&#>MYN-a&Ih^76+LMfrFe&9!>@bt=O9r@RfnN zVwRi5LuFA31BFHJd9)_VqkY|0mpO$bVbOpF6_YzwuO@9WzJY@4Ryq+tm~11uCaRrd z0*?q=LB~ky-n=R1Ze4rpmTF9?*s<>v5PgW=0O)>NC!{+^Ix;YuD<}$AB%gHjxw(U_ zSDk|dZ3=s2r6a~s*-|htQ)l@wYx~JO?Ga~Sw^c;#ARzKglLewGO!l;pd@QDWtyuM* zAsyG_;=8D7RiEtgzs|C9-Ti7F1H;0jOs+g@?6%YcmdtTI7h-`p>p>(h5FauCh;=I;&N~QV}GnQ zwS3e_y3@JekeT26a*<}8q(8{JVV?J^aSJz>yb-c?jW5gAdUZ zhRcR~yj5v|RpHf9VrOOR6~V0X^Up*p?}As+SLfTZ<)dWZwdzumH+{n=XW%xUw*|NT zy4a%AZ`*NsEq?=Dmgg#%lh;6Zg`LLkb1&pIu&wVu`6N{>=n@&Gx;ht4Z~HylCn)D{ zjZDnYu5W(`DssYmMyXqupD}B86&G~Ra?nS-fYvvaRq)ZrMeUxQE=j9Mj*&&0psY;7 zm4+wjw#tMl3>XpWotEq&wm~PnZVFwn@T39-{>-+mdc$6w5I|`X(gy$ZTi#XJQh!D* zR&S0Xii^6&<04^taD2v(Fc`)<;k$J^37CU_`t6yw!tHdwNvNyslC~7n#@}x07}pi9ewk7qWs_PI{^w7(sCo?@db=aa*w)Ince^Xd5np7h1)9M{@ z9_PW?7SxX~Vpd$zxn}aVALZwt_=KpuyXj)$SJ^dZ?nldOxvo78h+ji$yQnnW`?``xVKeuPjZ{`;|Uvd9iSq6 z^GaeltOY8!h@os8*GBuNL$V`*IU=VAh+*8hYDrFf zAMWPvgsJrAEqL_l_A`U~5I!V(T8n6li{qe-3oj_?T_O+Y#n72_!jk?6#gs5g;E2LH zf(jXd`f}>z*$c%x%s7BmFi6DUsUefSL@bo`BvM;b1bGB0_|CO|i8s zT*w(%u+Q1xJwX<(0?5>f3bbsK(0V8+9`7t4~b7xrSQ>_!~oDo5pPW<98q)v%R3lg zv1J6s>LXz{Z4j|#b6OtgwZ>j0;^36ERr)w)a~ra`S!7_?+Ak}9EzlxPF5YS(>wtY- zUo>lxdY58fSR&vcWj0J~#$^ytP1+i}Av#q& zer)|7;+ewQ2E5Hbo zR7VYMW&&LWm>yz?iu;1g(PBF2wuoG%prfHW>^x?tW!vZk0$-M)r6s7mvdmQCFDvR` z3EE9lj~2WN(6FRiz^L+Kv4=XalE`?K`Al5Viv%f4dTWF;0x(rW*(xkf2|18-bkefF~o6XCbbAweI?0UmA{Ac)nXHL9fngnv2y-#^UtUA+_ZYwOmI*# zKYj*+Pzk%BwjPO;-inI@wR{xmUZoKq>icNUk~b)A=H^#j)a@*SuZ4!_Fw?y5b6Ge) zB159Rs08~Dpz}r$hQ83vmDCRu(@ZGQT+hNFR;v<<^}is8zlzh9VBK)YoUTEH*G5}V zSf5Xs+ON^1kaUr7BDct=?VROtPZF+6+&Bkiopr-+gKgsxBAvw-0Uq;X-lA;=mRnR% z?dgY}Kz0c1jIUgXv67oK`aRljRdNwavBEUDGSm~E~s8}rz6C7cc^GI}$*wC%Ek+c46 zS0u`I)R-RNq1nu`C^h#t*(Ted-H32{2#FZ&jmTDP7H=FC4+T1Q*zp@#seX1evxn+@ zbw-8PGlTmqsU-y{&F7?j!P*mo+A zOJNp+gcl-d3q6p6p~Tu!svf?_H}#cW^dP1?l7b1Mlc$F5!OiW>?s~agzTJ@08pI>O z6N`sd?z=s?LFkC*+nn*7nwJ6?TtK!y81!K>{T*%DG_9HH2`ERv_O0v?x|COwXpHv%>96|*pBxp_>xNpEdwLW}hx>ovf zcOfgS2vR^!?+J0gjm^Zf4dW=uA^1C7Aft**szMvK9y3nNI(sL2s%+)*sRrKqQW?3E zmS4AYv33T-%W~dPSrK3TvJ`&H=k$G+4L2&I>t?(nP6taWZ@GG>iB>uDKvJ>p{uiE~ zxO?cr?gB7IaXWb*f{njpJea@4Re3TTLzR?bvoijgwQ@;KndAcR&6bOfjOZP9OBI_M z%teP-6)RUsG5cn!ZU`1ypQr_z259Z%rohvq9ja1>?%L4vop7DNmE0#jVSd3_JJPuqglFwn1VS}8!obON#B6Gz z<1P$fO$CQDBt8%fz;OhF{Qu_4{6E}z|3_K=->NnahJUNtI2it;YGeG5s*UkKsy4=d ztK>Ks|5L_i{7)I5@jqpJ#{XYs{D1w(|3PK^e~$ORZ`%LECYAAjvPqrN*@`1+jq$tb zEzE-znR^D;he6ok^pc>9&9RPO?dN@Xm>%MIz}wv%{CpQzN)}O7e_U=FZM-w&nXgqr zl1xB(R5gml`ud#c`)**TI!P?#&*jJSR^ z?91!ogQ{on1)1U1MU+vDB10*{l7siSFum{N3;eIE=N-Hlb;N&!aJSF&&93A%pU59P zmM?kBXuh2=y-~|xzFF`eNdVkdxIiBOcmTke1fTj$iwE+}aNePh`goH_U@oA2EM3TQ zA6@o3J%$=-e#eeI$IX5(wFmDzxIMn`IyWwAir_~17e$WKYlj6V0a_)>W2F!;K=z7^ z=*ZdrK7a{lP-Liss2a(jYp2dU_#oEN$|dSFclm*3e+xMY6pqHs%VhJ-#v}U*Y;pUi z(vwd#o&95totr4;LkecnOPHIrHHCKnDdzwek-Xh^50%BM1O{`|SmZ zO|Uh=lohn_U!U76X-Zi$hubUn%!SVT=%|TfMlA8GLX)2IG!6!5-}=<%X#A@WGV*dT z8=G@Y>qX8F>PQCo?6)+Q>BiFJ20%g8a*YK3N@B!nF&2h|#GSHzx9y%ge`c4P_WD0! z952$fd!b|>f{yt1`)SPHYv*h}j;)gShgiTBllSQaQ=97l z8Oqf6-|mn3zSaK((|K)@{2L=4XL>*9p#^64t$#4mh;nT~lLg*7yq45SdRK!bsHPP+ zalmHgaX&}7B|H+-(lSiQdR7)R>jpj;F^K}`m8U<=5WoQAS;ulfdddrvlsVynQF#di z3YrT-fT6*S5%afTX+;n^c5z{{2GU=tQkF%D%Q;oW?ZL6{j$s`W^v{rPLkm&8*z_yG ztlX=K5O!2y4qXH*=QY-g3GkIDdf_}r6oa@H!6S6sTi{cCGWC|U_w#4(_ZPgLtnPsA zMcoFQT<6)!EVmsWmmNRVMqCSS;szOCv5nCV*&x52x_i)(jr!3QFX~(8OT%6+)TgW8 zs}0m3Y|o!baJGW_bei!K39R=MeBb*ic)wp66@o)S1%$)CGub2Gq~X@Re)*E3(J!+9XO?>EiG95vvLFfhvY< zzWvi&?^?7);$3y*j_>F7yW2`7gdw1M1YbSa!*TRA%%_?T4@89=jD&1Gj2xM@te3Ct zM)l-M26{+`+v;4gNhi!W2Md;YOc}!0CX59Jx?z%mM-;JE;M$S32H}8!m4M6NpA9k8 zoF7};Az_)>PE_1V)`EdL5;|C`fzHfHv@l7Dw_*cH-(mxgSxO^=-6y25Y2{zc>sr|g z1{z3dp{zfNm}~p-iyd9hHNxSh#U*5*{Q1Xrttf;hU6XYZsH`(Yd21Rh-)z)I^4?|~c&1I3gbaf$;T=v|DV7s8RX7Mp898fd?xq>w7Ag+T| zH4|2q?qyzD)hy8xgP8eza?r3BU)QdqazSAMm#XXmCNneg5w+MX3zsC@I-pmQX)>zfaT zGeJ&MyaMxn)vx8F>utv_=1>u$b!%d*1M)64T`~3?0+@6s>(MuVtWFK}i&*cp0;p++ zg2S<+rbp1CeR$l#$*hQDje)`lrVO${GIvR@b<}1nP-Q1BteX7W>mQ{yxe>Lccqkwk z>btDxMooJYdjfLFeZk-wrvP+L2{j>++yJw)O#bN=wjjeu_#fJ)T~72`IEk8R&vbEY ztP6TR_qa`x1C5NtaH54;gNQm)k)6vn9~ zrKQtYk_j!Una{%xd%I}s!s+11{0^VKo*%?U@}H+o1WptR!E)RuFgPa98cEF zQkdE}8_oBY&p^|Lf93W?4mn6|Jma6ZU8hTEni&u^>Vq#k1$3MzyX@; zma$;y@2wm65c8lmiGj{jzzI{~^g6}P{Rklki279Sw(;&Qj+#=it)w5ga8%F#-G=Nf zt=3|L#6!y?iAC-eJ|xa(aBskN`ZS$$Vgy9DWRPyTed{gb`FYRS_YJ4}0gi*h_ni#%K+rSL%uGp6!*p#vsnXiL;O_39e$}TA zP+NN?J*zWXBB)Q?zpCW$@>CZM!E8Lm6Ikh5s5m zZI;JP->THK?044oDtg&DcuCIkwoWJR2-UB-hLH4LH|5$KfKEp43Kn$A40CTho$n=P zW;hs-bCliB`*w8U9X&^TdK`XbB;%Y)58(z0fHU#oS=W`9{3iJsrk<&clL&B7+F%7y zr_2@UbPCXt`4%vv?gjVh$~n%_+?CjtnK27R3D}Iqz;F|>$V3tFU`R#eW zZFq~ihas;X47PxO`XiaQ{eSx7G%#~vh9aQ?l5nK6>v0U+9|_Ev%C_bi<)JSbEyKM} zoJ{iD%k~?pO#}R-r%R@Ii*}QGnLQ88!v!zc`?tfUa5Qvk|FZgU(r2;5zmhCIbK{5f z;IYiPEdtHUJtrYuEgZ|wdVN}29;arn*Ro&iX6lTypE$WY3eGws8RU7xZ^`nYt!%7e&04} z#A!i!4@1+hykprl4Ry{dI?BrON4Pm@IU!rQxppq-r-R?@_SQi}B7Vw&a$b#uW$%A{3B2^_%^vu^P~MTu?w?>Gr_ftH;jQT=o$ zv$nhLR5EcLpt%Bls)FKCkTWQa>u_%%o@kd4FOC#~d)Z9#C1Jv-Q<4m^b#fd#{S%@C zK{s>h2y>O$&s$Q6HV^FmenZLC9-RwIN)2*H@}rSk3cTW^XXoB0UrT}&SWXwMFidfs z8~4VL>HRYV#UaaD@KgTZF|Ny=7lPUDB1BS~Z~4x~P0u|dCCkv>^KXzhmK2&OSk$Lk zO}e+t72W-!{^`||Nmu@Xfl<|`b<7b^Q|K?nZ%F8D{F=#M2CCcdWYP^8UzW2_c7MZK zv75*cZ|1*Um)E{wy7Q8aTDNO)UCav{@_=h>Xrp{?<#X0L)|vCz4vw(MKrlK^hr{pg z0RDzyvSBo5*}x8vhK#2CHMRm&m1kaWmMxrL2H{&<4|bdSQBqSQKFGF^{Uni139G** zqY)=Q<8`FZZSMy|X(7KDTOr|ZMxllLb2qnxRc2$3erDF@h-cb1v$n$_l*@c@95gP% za_U_Qr@>q>g+xdoO|KB128#&7m-_`eo3B6u=ULQXf7rp|~apnA;0yNj9nNU5BZDQ!9m{ z1qxD{8sq;x52R%r`x(pZ_|+3=E}LT1v#Vt$8h6NA$f&0e?k?k#ex35e%(Z1AUkQCf z&z4A2EC}rB_d%u36?`M5ywTrEeuL6I=rvJ1=*^Np>is2t+zDVaH4Dmmz@L#3-ay5r zg;F{19V+>ff7#V-q9AFey72+uF=75(YR#*bKzlm-wvtgJD_N^~&f`h*!7?*1Lq0Rm z<@T#FxpA%3-1q6-TaGZRmuJfB+14JF50HC|aPe;MN9^L@$yPVjHS0f&G1{IK?%ZR! ziPoW|x5WX%!zSKmn_Ui-$%SWrh9zQLNbYKW_G#aKX?LjO2#CsXt98vw;onMc*hl5> zdWKTV)^?)9hhHWMVWvkXg$ts-Ld{Ahv3B5YRYAZ>=mjbYhX8{iGxqETYRRW?ImC|% zz*%qU&bR(~1|IXj7#4#^*5y|Xq{bm*THnZ;mDAR7w0zk;VmioiSSyU5%glEB4Hcm# z=93<%xYNBSJ3ifC9J!&F%@D<0;e{R;N=Jj$aisZtwM(ih!&3TZJr;cw$=A)H;0jL6 z-~{S}+yR`}6(;)0Hcz487AXyje@_SW=ZQmy)F){g+P8RKYhAMu(o}On{}dEseff8BIKu0Z<~lh7+M1mx4d<446;Aw8?_6%NFv2fE zT9LcrZKVx01=!VtW_r4{5ag?)wNQ7~%+7(e4EW)g zg&mD-zLw^*V&CVo=WLkbu432s#A2gH;K3kjiqHlB5n3mjY8Te0X)V3A2jdafXBP}; z#acyT7j$dR{3O|dE)1rUX^8M{5(&PKASQS+@(uVa@(V9Uvv%V!cm<7U$h4gTYTy*A zk1NE5>&-932{U}VJCUJa~Zz;s;NgQsF3QhZfrCS2me}q^kgK=S+ zwGR5WD7|mFPIMJ-^`Ap$YOE&qz}Fg+;xmV$h5W=iFH^%H34Ezm<0Awnb^GqsA?<=c zBqJ56*#0N7fJ1OV%FKTzhXSzn}Qn zm&ZMb#HbO4P3v+lbI`7>4>@Y0--3X30o{-Rd}-at2hbWLJT#NTqm;O|z*M_nK4L6+ z$$pw^7aJbGW4Vq1vXj)@Fcx+FWY&ofjcld4Y3@O7%H-0)n^0wMC9_Q#Xu1ybd6nz> z%Lz$xh+83>xqRTojS}fhanfXwq(kR00JY0=54AbL3TYesC!O*(Vw315Kv!rw0^uVP z_Jl5e!CAZ@HS$kIGT;P=q+qXFCvCjq3eKW_LV6(PM=ToH@L0N-Q9j96K(tB{pYphO zGHT+i!Fmi?^n>3a4z_@Q0r3nbjtqs7NoX`79F9YDfBl*4Z<2wxTO+5(V~aWLj5 zBiU4$Ol@Wf&{z}1upJXP%S+7LmsyY>>IfOqHhP#5yQ(n~A#=(khpE)VoTTT`BZDL$ z9nlj{T!plky+GoKvAQ>fF}BNbK#3frsJu>INgqIb?*v9)ZbTVxO(Y6Qe8R#z80e5; z1V!p2K~FakY|BQunk)U=k~A`F!J3U#+%$;3*b=Xqj4eyWak9@mPAt|`Icdt8V>C3e zuaPu?_?;A5VlDxpU;`;udC6Sq370lh7EImw|Dx_4gKPWRF7Md3ZQDMvabnxHb7I@c ziEZ1qZ96BnI{*7VcU8Y#&(mG~e(MkWL#lSJntSfK=9+u`t}%uIdzuwXI~+?IOqunH zS&i0RtRhg!{7S>AXhQfES%7Vt1yk5NG$wc#e#R)t*+4kBleZCDoum~}fYOaOL@8%e zBFqQ!F-#O5hTl`cAQ4C6!OU<>X4~|bfN5!3-mI`0LFp)4tX(u%yw(~6P?D1=(8B;@ zk5OtEC!Sbr^4u^YN!`7Dpd*h1jOaN>JaN<3P+a7b31L>gU{O!rtX>vZksJHxru5t?is#DnWZ`YW z4@DuP7qPRcHTuF66O@)m|E@@|&2$^y`ML$xXUX$eAltPqPSS#4)i|YP0?u65Z~W-7 zY!}U)f1}P_G=O!z5KUPcRZ$2gv_P9_;=Y9A42?#<`-8Sp3TkQtvoJKat$@rEl~qhz z(L*mF3C^HKDzZv}n48k>DA%;NgyEKue$f0;kyT75d}~DJ_9v!m*ldnsEia|fXsd+` zbUO}ex%#85JU;9;vDDSVjYfh)tf7CCgQKFFg!H}y(UXV{G*et=t6}y?l z9hC;xl@Oh>JRS5lXpoYt&OMnYeGUox(_m7~7tooKqnPVE3!3<@FeGt+V&9>ED|m39r+8o+vns`Syhk6xq6l$<)*JHznB|)M&mKT!fBL{rgO8nh194aTJQEGKzJbCKT~$PPi!o^kS{jTCC@Q z1%Fogd6qoZAF65V2`8EzL*{TR9LokQC$|(rP05vv*vAZJ{c@qrC6g;>otEDstX8yt ziLmVJL~Ll+4@tf;IU{E-4+#vQDK}_DicT3enKkhmoj=zlc*5ayt$#6 zO|RqYMp@p5aajw~fkPABP8sTZ9q7{pfv`mO&PfEd0qcigu+}05w?y+m%pDP?^+@Fx z@qE5%S2H z@`>+nv~bD1%#TSBZmk}`wtmuC&t(>gXum#vkqRrS{TJ}-e;;x8Z!F2d@*gb8%F6za z=PAQ~%OzE0zCBOBvngS9?)7|sx+=R$sD0j`yF7t?w8Y?qO01~RLn31}u2*(-VI;0`97vQ|6iB_c(CYP0`dtDVg z7H&!% zN^@?!LRiKREnY}A{jr?T<#q?i@;KDwP;j{2XJzkK#k$cK6MXr37rUUvin=ol7GQ#s z8U8{-6nQ#WvX87B$<~iqqKQLe^0Wy;_Cg7H#onK^2gwE~OVW1M-N`(M=mym5W|Lv55cOz7Xwjs<}LZL9*!B?0M% zP(*0{Y4yXht^WcAAHf2BiPU7n05_2cc1n3?7eg`Xz5Q(yLwu(8C#^X4@)+@O!-Ps} zmTe){wsbPr0mMHzLXI<85=QEMFw~~^zFu;~<+Jq_Hcv5swq+L*$Vjj6a~@6uV=EXld8<>uL8@L z@EJ4$2|(=KVP3Q^;_p_x?>1XRF@)N}lgozl<)2WpyS4O0X!%rdOi!$zeaUyWkX)J? z#p5Tm(MpXcT)~+JFT6)-bkMNflb?FIKCXuQlHo~R9V`h0-?vWX zp~5J>P^+ZH8Eb8AlYfjpgKMq+nKH7@0*!6YCV{^w@U-xO%dmZB))q=_`E2TQ*?hyF*5_)PA*i%pPQwotY3B$E7uiEUp`OlKi+ibED0fRdIeO`@hg?_}>15fmd(C;b4HAubQ> z!^v~nwY$SCogMOAqT;yr39Ol6^cYyj@?pn-)L@)J%4}PvTnN9C->`x+RjzVb?za)K z^NyMk!Mx657OALy8TT2>WO6?XU8FZSXEPMqizB}IsE}mY$^c?+p03wrrNp6n)QFG(M1+Y=> zpwm;hB~TGzraaZ&fjwtt8-FIlWqx&;!NI=6_dI%1-Zi`!jQPikg$87f2J0^j$WjP0*yatAErY5V7ygV!F}#Fx}k``*ALmjZr1%DNzw zVot1lq;&>XR92R#2}E*kX#HEkRz1XJLPc^7d8PsPu(LFjAMSEwVr(!i4hdJ^A3%p* z!Y4=Eh0$GkW(YrryaImb7&ruB2m>AQ2+mgp)9N0c zctOf>Ne6;r9zu`-QUBLRUosDb>q7fgx93;?8)|0+PNLm?FWAIyYE6Wv?!#5o&d3dI z;6JNnw#?CjQ7-DkS{z7l_-JSb6rP#hH7*SZ7Uy9?Y{i>qgf2}=GYjo7mByxXs+u!J z6n=1M{u~-3e(X`8;W-;U+j@lZ*}XzAqmrb|ScwW2;e-KEc>a2X0Qo^q7*tzfzap1N zJL$v0i7sVs4w%acuY8pL28{Q7skd)cXZpsUb>1(stk6azI1gXsw zDfz(-1#)1``>`K_h3kQTk4^e}Y^gY~RkW1G7`NQvXGv6M`5ZZVa-sQxfN+iA;RL15 z?pI8uzogN5U55mz-%Qw8L*24vPAf`fX}Qy|!3;`B+Aqy~z$BL~cw&i?uD3e;62tX0 zR3Scgd0}xP%)qIlgK-xI41O&%i$Trg3%yTB#V-s|;(fV4=d1sFs|ps@te=)T1%SjsNyfqk2ix~{Hi6XccrT_uJ>N}2+FSFeYRwz|M)0KpEySa> zC%k?7IdSO|K{1Vo9+|Gvnpqt!QGi^EJMJw}KgyT15;s=7>+yM+I|EJnohJJ8Hk-*e zvpNaeBjhJFz1QY3*P<&)4DIPyO7*N>sj0i_T&b%|6x|Z@Cg)StH7;5=s!n}+$~N!9 zi)mMw|$e1;=SZByL<;xFF zL~DjOv}76bj++rBRq2PZ9vzL7;H*m(k1LX)yqyBvpAgo5$%NTM$)8h`q~4n)w#h7} ztIGL_>l^mERR|<|n<+$(Z6`CCXt*gmE1#po<-G$xgS-T8m-Rpd78%|FnZLg_=O%#K zpn&sz8Ki95l}x)2XkPvz61ULaYVV8uCGDwf&m-q!}5|2b~kty@YHriHFMA=C4zN%fE#qO_+_mQ6n`dHkfY^%ft! z%D+xj!$!j0+s<~(`m_oxvE5_7{04RU!{k~Eb$L)bnaQb8;jK|kSXrywt@k!#hTcY_ z=FA89UH0qjB{){%bVh@X1B%&=#a{X1=w>R&wez*_ai5~^6`MWiXM1RcGUNccvM=4D zA}BTQWTcEm1cl-3Y4Mhf6rc8O5gngq`-A6B$SE4Cy$CK1n;4af*Y@co0v3dK$&ZiC z)~yIAU3nePZ9$)HW3p$+6Ex*obQPdU5xQS{0@WU|Xp*DOvVa;ONgGLFO=q|`;>8XW ze6%ziUMF)ELpdpp7PKlrIaK;E9m2>t?M?L=kq@GGl2vJLK?0mv2E_DoXXQts&uMmW z)uYvB1J*>Yn9vsFDRc^Q-c^su?LT|MIw>FP0GAJ(NcrUt+#5@v)}Ddy10Mk2X_SI{ zPZBTWp%N58FHsP!-|bgnLtZn*I+nYXge5A+JXKwJW6i6(KBTc#^ce!H`F-5JuCBf= zk0%?PnR0lE(=0pZPF(C>$7jT+CPvQ{X1x~@nl#8+sklI$crFhf2(05b3xotUmEb8T zxOM{a;N6tCb0Dao-eJSx9xzdU^B}M?!73r|$rgtNPhwi5fTN(`UJK5GcP!#j`2UL! zyh4vQsCM_{K`-eS7j@6&jcZi@knC|pG=EgB{0;zH`k)Anut>R^;ojKTrKJ(I%o=8+ z!%Ulli|eS_eHg_Mm#bugw8v@`-U3Ik!njpx5s3kfN=T=l70ySn*1y&^Q zGZ$KSXWwC7TjAVsGp#44vmD{Q-s7NNA(AduhWL`Uqkh2Tna(}Kij0mlb62 zH0t$X*vk3E2zzl{_~kWp%0>NogsWjbE35tivB%mw5nEI@7?28^Kr%$o3*3c zB|?AF<-0=XtvwyC&dW|LwChbUuyix-eeIJgS;tvzLdZ)|J?TvmG447jU)G<#(C)sn8~N+1 zwIeXJ_-B2^zk;N}U!E!ySL)^=YU^UxObm@jum7l0 zbp$M~uBe)y({xnuV5@xsfE6-$w!XG?Eg3(0m(LRJ`~vgowCXX>F>}CyKq00~q&7RQ z&L^*s4Vex(DB>`sy<#ZwArH~phh^XWp*#h=aRxik7OHaCVO!5LV`huRmu;o!)(=Rt z;0N@Gp%L5Eh@cK0;an`B2}K$4#3WHoK<7kSLY=^8Ko8HE>_k2y)=jDNQ%{?%#!enQ zs4DS%*ZVt2^6oS^DxxIA@Uoe$9i@DE+PmCe&1ikwKINXf=JP=t_^lmr3-j2d`oRY6 zJYDv#%)^N&Ab({w8%7IcPH^8HJ)ZcIF;1=&z-#t5%pZ#MFj32?(N)|+_p-&b(C3#P z>=+_-VfoNIK5}DdNx-T$;g7^JNT5HatgSk1J1iIz0em^)#B~1; z1m7Ro+D@#KDuDa!L3DdrxPj_e`%lRW7|Bw&{6SO)bk^Dn^mAdNnck1gvT`4Z;SR1U zZ^&##xLhZ7)ReBd6iT!ka`r&wnQJc=7SK}_a9(qc^c`S$g#i ztGHu3!fpjw30PXgvwBf3^EeXii)J;!U@3g0$TWMR!(r)!`7-w4C@^T(y?Wps>Im{6 zhQOa-0YR@YXywG9z|kIB?5Vu9s4{}>5dtWY-|w;j?`SWVMbus|>v)n0Bu;yz8dRY2 zQ0#BcfC!K_{A+Gep@>$n1QsMqZ?Pk zKWQ-A?b<1Xwlxj<6Q|Dbvzm6WbFG8{tIU-oHpgAip5doltx0(F@)N+5j$?pnL+P2H ze=ZOo#+e^`Jz%(=!S`vbHhS1WlF3u@s*03^cPX>1jW1rZ9VKWrzJE)8Hz2zHp$B5R zTx{O<2v^2Pbe>;X4&u_kj`)q^U*%c@@Km<*lXL+))ETjI>?Mer{Q3x8oAV|NJllKp&Q#q* zeN*kIa+pNrHhRB4QUctK$~XHieC)MsbXtc~ed!amvo|RqtCs>p;t%f$CqjFO5+(Bn z_f6X13cA=fYhJdPSI6_9CL6lp1|!8Xxx>cAa~UH#_`5WRW{E^WwqJW%RBKMItTBw) z#U}e6%0%1uUQ;DoP9U;xDIEEqX*`a$n!ZEf-5a8A#Z#OSwHJ`d9ue$VKIYl0d=#&h z`abq@KivU-U%|S+#e5T>Y+JJ7jVfFw53DLm)7$vov;yug7}e@u==tHX&s{vi1QQmd zOnlM_)mH=+BJYiFTwQ@!oA6^wY&|hdQ|cuS34Ahq-Dp7dYwFk->+ENH4D5QATgnsF z)|D>J-R%TEBIgOs1~~oX<}W&lWB@nJwk}f@q;MTugq>sH5Q+)ftt&9DIbP(0F@EPs zO~(8EU9rH=0!N6Q5#Rf(M~ z=PnR+7oYga`FHDmzXbI~Wveh>D=o>a(M2!B{K_BL1Dw#=H9(-bnJ-e{(9`qPaJ@m! zn$}ow;BCiQ(03}X+GN84rwoUfw2?|8DC!k}&pZaA+yZ&^fve6NFcc$;))kNG`?45H zWCuQ!tpxxWIJRWr1XpxH?W)Jz{WLp&siFVVo5Atw$Bv4b7e)9?&+rUE_$NJJ{p9uT zH>5GP3Mce}&<%DGq`Wm+=Hl=}M~&mdQ|+<2Rc8@T#eGARn?!1LOS;$k1|()fr~2GoE$7BEE45 zj+f7^Rrr>2M;`&kDQi-+XJC}y5IrZt0DqPs4-f)bHScLlZ_X9;1P?DtI2FRfp`SyfK6@2I;~LRo`Flc&)u2?dL^Wjyn(L!fI}wryl5k z!Cg_;6UOz;u)LLQ(7Py1`44>QCf>239}e_{JhI3&Xm?Y9!^JF}@f@HXTh!u?+%lgd z>ZBs?$Xl9lTeJWa>zEh{y!Q_>y6rqb!u8TcUrB^~0-QFq)Q~%Wu7h&f39F}=>GH>< zoM_=#@*QetUt*;m=i00umGRH)$Mv$_kUNOY_II+I99G;9x}Wt0YHU3#U3HZU!Duhj z*?_g>`O@kx?hay(t|2VSCLi~$Z}KVwW}zR~_mA=NLTjKmwY5wizrI{i11(42^R6P? z@HDjy4*y|IZ~WCJ4y({N==`L#qxaj+6ln{K44m}Iic*(8BmX+h8+&lwJbpy6YpQl? zH#LJ0&UpQpIpnH-A{hdFN+!3gG)+16nVX5QHvY7nSKOoz{ z{fOhYsRc=I$a74h=bYGiDFEHj!SMVqQRPI|{b*78%=MIEMJVzPl&k1WZS=a4snhFu z!W1d{eiY;5ZfiwhK)IksVhQkJIxs zMpIxka5*35d#Oy)M#ltYCu!4_mPY8)lk$0x%V|n8^9&vsy9L;!rIjQOZ%CR4S~D3W z9KiLFBPc09_0qgPdw=%zAhAPNBcvD2u(c)E@u9lNc&pTRBq_ydX6o9hKeralQADdo zL)oNx7!8ibOc-=w=_-0@1+&YFdwWpTk&S+Udo|*fR@ElVgucXWk^e5|SY#fH)G09a z3A3b&R3lFAr|iPa-iQw)O`&HM!K{%^MSZkvUCqRBmc2PNn2_EJRGKg}+CN0H@;QhA z{^8Srgf%;^mILwIlqf`ixG~{P6n-_VMus zgF7-s=g4I$z7mSe6y%Zr8&h>d>R@ahlBPdTm)Btrejyv3#N|s|f%IksT}zFGj7nA_ z#dc{;_PG}xNl!A-I$ega8}mSF44zn+rf<1PQjV zf|gvGy3c;3PZ|{tk?({pgp0$ZmH#~LAoW3Ms*F3GNrI9A+q=-nQJfT&39@1Z9~I zZU>2?N8;HatG+-b^kCgm*!UBfO)T=!Civd^kwWuS+~xG( z7pF>d$ubtvN>iKE1IL~O>|p-q*lZ=ZzykF#$2e12iF!L1M7|`&3=+K({Qx5r_q*?F#9th)i*WweLoV3qI}82Aw7gb$bd86S@2dF8rh#_-RjCLWyG;BpWD2UBF#cDxZ z*A`+Oj_%|9A(DF3Q^~V5Qc0GPDL_M0?0tu6nSYiN)wy~}_L7&B>41ct4DxjO9ud=; z5l28OCUp4L@{%9b#FK5I5YGhhmf_t^*F^74zh*)7_@$ax`Z>VKEWK zvK*2(h>^-UV06%?t4X4y)w)8wGyfp-~orKwLtk5idXpLgyPG6Y|ScZ9g%a)2$ zuPc4j`JM+Q#hXz-I*x<44LX$lixRu%^Zu>-{nL{v{m>hioBykL%!gjNtIBAsjNZoy z0!}JeX;oHVx;wYnrm$tjFj|vxM|;)amO=V#Ec*-8#R+%dzre!(`%uMywC6wBBW2cicxXVn|wI1P#aj;(}@heRf!Pa&NCLjp2SI4BC|vr@Y_nF+kjo+3Oo7j7geCE`L*F zwpvH4WISn5!E34PfUC43K}Tg#1Gg=^1z62~n#1Vkt>yap9U8h8sf=9K2CoVpB3tY0 zNIua%=&xNlK9LPc-(0?P7XT(w*d(eiQA(NPk0c+E50wZa*rPE9|3|fHYuO#nV;MGP zc%&cU&fw;&mck%aku{jG{%uvAt^E%=q;qm0>rYLmlI%DE!KnGI}>)pVL-2m&WeamTVKfZ|YuqDb{*q_E`pz1|OW+C?pm>PWOK>cUz7 zN9z$+3EE`y4Y|KVAu) z8G^%fY6S}WABX3=_H}sO0my*2H4l)8GCAroa6K%zyg}nE&<{F#i>L zGyko}{I?$S-+Ih{>oNbW$NaY*^WSmuPfuf!&Lv@X;k?4fd7x33T({( zOAspWdNfUQ)YS*-hZRBiAM_rKo-Jn>l2CS89Fj)^{I<7=u-cP)fjan?4^m3Wys~l+ z3ohp2^WJB1nj~Sx4v9RA35EXYYM6I=&wK|u%GdqF`Q0nY(O}C>u zmqEPA8+>2x_gAAtzRycvc-=2MhRWl;r0LZI2Np8wb0z!T=lh9N@nC_QJcrolG z{?F^1>ug<%%kKvCH11VFgDGcuA@&CJ!Gs$qc&>9-dw!j zKKN;yZZ5KNQ?@*B*Sn*GQKl~qVJ6Wr2q}Hoj^}kBC00_$Y}!vlZOn_N^-)7Fga^|x z*Vp$5+CKA|xpq7Px45;f&t>J7(Oe+cSCkrJ9?!+uU9W$N`2%j05Wl20HTi*u@OPj5 zn;`E&E37&CZ3P2<>hFRa!fzB^S65BHGj}8JKBehbZk9gESR*&j-*H%5{SG8{g$o7k zgN@y7>`Mg--x-ZiMi6enAjRRa5mY@fOj`@!1kxRl&(G`((ooK+-*hoP{pD#|O(&ry{)yl9@;Gd(O0um22@AH#^A46g^zQeSAXF!H zCI9&m_CPklC3elsb;`=S%Xa*VJ(fUN?x=4e`vYIW^y&;#90&t7RI14HNmdb1i1sc6UUw+R6x!mtw7X5eMC?M**bGA3Qd@%!c3xLT0rWS4)2EdNnZ!!5ae;R0*kOVFfu>Hi zc|zvJ63Z=DvBc|@Qg`jMObwR*OUPa);)nSO_G#VWt@_Co^PK=ZKK2y!M@PUues|DH zx~VupYNLNJWYNof?^%feML^b$>IMpc1m(BcLVvaZ%qJYI{wgThMt?X3SC9$J1gDdH zyaT0QcEUAvPdyc9N-POZBx)5S^+I`~ZEg+3iH%eb^UUmP){e@c^yOh_4iwE7Qa50y z^gRs6P9-wII1FZ|I9t>|--c^iD%VNt)V1vQ9N1a>-fo8xTply;*a8>#2QZ`_#w7ftfTqN=`x$WJZ5O<_Qw6F4&lyd@=wOPp%V+^ z&V<_lo1lZpp1o8B214#i$5(Lx{m!o)YfX}OD7zAjlo@UK7I0#)8^ItU#tor}u}KVw zmOz5T;E(JKG+!ZAA-mIuq+t*o*+0t6!UM% z*B}+uE~1eTB5?gA|GrYMJ%|kbX-zDy1mNloPcRgOxP4Zh{NO#RkhSFLMNu*}4xjke z$wE%6KY`w8;s+H=_^0_IP~zS1aS4}E^lO&M4>!XJ);v8<5+ezggz~)KnBgmg^4Z3c z5(y(WC0^C;!$akSqtB%lmObMknPcIAv-}6w1aRqYI7FI=f?mh#!!dxUYXxH_pjw=2+`R zczEC;LnHTA21rhD^*LoYIs8HK!2?~S<=R!Cos$n{WiMHf@B0yB+x7AKmIM&jDo!?L zXag~&@`29Ch>u3Bho&%wwQ=qcTHW<>y6y86l0-4HtnZaD(*tdd21Ek0KGQa1`0@*4 zk_)!bs{94!`+tjPf3b_EW`x^2p^9d_M}0-FN6VN=bAz&~!pUqev-x7i^&Lqp&* zpX9UT#N*kd;_40EpHy==6(-bWVj=waIZ95r=xr9kS!-huZx&A`6jyr3nOd$G#s@eD z=?&T9wglx{eQw~33j7I?+M8d(g&}n=Q!ym)o8xQthlJ_)V<~L`?=E;N`!BXJ(kq6P z+Pk;nKJ$j9axb-krSBv8o_pu`h}-k0qtPb)spAN<{W@?+(dF@5wEzLsBMVw^ruDb! zxxmfeTWSFeN5y+@KRIx1N`jq+I%@DEBDvWQ_%^g1!AWO-*SSNt-xB3sTa8TFL*GPK zEqFNA;L}Tj5!uu9*OprBy310+AQ3H1vzXxZ%R70&@-RZe&V?fLPtcE>Up>niIZz;p zZy`)C4~XY1lJY$*J9g6(nlXrq3@Uxw1V+EPw#1S>?HreXu-N<_^=Ou1IRu0oQy>B7 z1zVaud0xUv#O-DVzmXs4KO4EkJG%z}Kct8cAS_d(__~YYq~QMk?=1NDcZUdUB~YA^ z#^3K6EDRo_ql2T>BEaLqHKnx>c7cL7Y9W4;EmAr6mPmB(YaoAgMB&(ZzL)ANt6-Ru zB_0sW4kisV`7uQBHfb=N7*%e6r9_RBB@!P`8;0%kCo0|5t;IY-caCbpgtumK5w$c4 z?ZxzGqT*ebEUiX9R7a<8iCE?uOE?3?tbP&JCW)J70F(237a3<8%tr{urYBdUIm)OY z{4KQ0-6ST(tGDSVXtn`-y@QTD}m7kmhJnCw$7iRJ}SqZy{f>{v}5HY`(_#U#H(;JSRXrkzp}W9LGHnw?W zNzeaag39I(6{gGWjSVur5TWG@!L5cIGSHh?Cy=kBr2)`k%=daBr@40vg$lMgBD#Dh zRvPoxrKq>F&u^WFvCrX+yodNe`q*b5b=bXl9O_KXz6{^GqSMl~tQlNgJJU8Sjp5P&U`7y+Gc@$$1r_aW!m7Ru`LW z=a~lcd{CR*JsjC#bmbLG>iqVsctZmTLY!G$%5~Daiyrg6roTjedVi)L(@qLD87+K{ zW1-KHV9yU1Ke`|7Idby3hd_MhFCbTveQYNAtq&aYSpg zVu$PsB3QC)bD`K_(@=Y4YJlzmLG`EKRlFv5OA+SWL(mAzM)4AiM)8Vp_afzFK84&G zo({`36o5pn`+nCm`7?n|Bn3v}(4}{&yF=oq#R!5b$$p>dJC{tcUiSOb=FE6E*^?sI zBJSlJwBh4qhA_etT@G!NR8y1QD_fYZS9LIbtD4e!#^tnT z5eN{IbPh@?MjWf+n9d%E+7&dF>ugSdMA_a9D(lEE~Y#4e9&@l*IRp$+mZH#Ttjza%T(Oo*FUMpw`E_fd|`1ljE zP*!|xL9F1KcfTp*)u;O1c?+sTsb^=RZ_VR#(`qIp$tdWref)M|9`7>>osWMsr|d?Y zZbBK*)fm$qzaUFwm-ZFVv@ze#f_Tq4=qP{t5_)Y$9HO0*aCqEE-*O~y*k{mjpnzX_ zOObtEFJ>^{o_E`-dBPu{x+PMnpT2UE3Su#GRD|*gwv5l4B&~{sc#kH1*xLypW85my zY{D0L_2c-3?@qox5&%_z039fG<*ek!IMA8V*MysaO~zIezGAPL`pDQ~wYI6v&$4qw zcQsUL=s@Sj{W1{OpLV{7tV@FFL2}~MlEj`2c*PcMI%z)Kj-wJ+bj^&F%^Ih7>F6WD zGb}ItwDaV-wiYCUQQ|A!W9!PI2lB1P2GyNZQ+c7}up%2;#p>`$3o?T*2rZ}}Z?ytG0Rz zbGlx;C-X^6Q;GPcjRq^82w|D`3a%+!_(_XSC96xq`H7s<9kl($_q=~)o_7Cu`5ZIY zk+&>&Pe`}Kr7=X*SY6pYam2=sI5Y)vrJNAt*He(qs=AR zlBZoLx-S-)Ub~7Fh$1L=^zd3LI7$hE1tsN15H-}altq-zApNYE`b08RDJn#}Pzt~< zDlCXwK&SkTBK->kkKZCU5K?r6D7sL*B^-F~W0w1oe&^O|h%3CKp%o?7BE9YpPDE13 zmFVpGm`)dK)|@h*v&z}f#_UrQ)gpb^&Er1IO4h5BFp=FIrX0zTwx0nufj8jF)$8FBvkxvNm>J7M0_f; zxN!(=K_0Z5>y5lqi+CQCv=TxcAi4{p=&lfq=>$T<4;H9GWX(l*P#a(#1JYLE$c0oI zBK^_ls((*Cxf}*uLW%ek&n4D!#8S(%o4d#erpQs{RyLrw@bfY3RZ4HvX}z)o5%q>8=KWW~CXNK?V4Wzty6s)+4HsQggETf0^euL;`0 zOT}3xL(A5C2bUEKTE z1@+@WI{ql3GAdY0@sb(1Wv#1{<$+j@xA{Md$0i(i3U{0bb#PdJ-6DuA|CuG+jN44- z+R-@aE3T-1N{X_L67-K^9xZXP=D4+qMp6-&t~s*ej?6lF2%m+{ZqgwOYpCprQh-}9 zAFI~>sF~AJ7-cOOkF&vbJzJxe1%dEV@r^)#813s_p%Sm>45<-$dO4IaecA|SaL{d^mQ8YVN}lbpaGoWz2%$! zRFmA8bQT(1m;Urg3UtuxpixTf--2vS`W_PYyTRWzA3zsM%z87}in?WY$h`CNBeyHK zxLKKTsFnX@Vj6sBVp601{tj^>yD}_`NVg3B&cvKNAklKP8*xEj?KVD}Ptxgpr1ETm zoTetkQ-Hk=$KJ)Y11m9sNjsGXuQ2|h0J!W`BKJ=w=AVeM6)Js*emSIc44;6p&T5VF z{26SX*Pe1Fjs?9c#?&$^zw3RileVHY0`(4ci6Q}WCy~X+xfKHV7V7J7TZO7k_in!6!@T=l5G(dBxO`{J}u4A-VM z|4Me8pUBQpB)?kJ2}x#~E_6A!AdMqE5h5lG|! zsloC$YgOl-nCt7AgD{v-kO&rAs3;7yU^h6b;8N}1a{=PrVW@Hpe)VC_@Gda{sYHoL z3*3YO0!u_4;xs!aU{Kf{-Asc?v)YWnRj^f2_3Yn4sm5v6-sfTA&M{Y%M={IY=dQRdqeItnw=kcb?$G4-0?hl8? z(>b5^7h{DJ6NTr~OY6H^x~)6-5k{~1#(v!_CB`3wc4MP~QKI7Mp|b&brm`<)-pd=f zD*YwawST@i%P-z8?L0j@Zxu+@*&;{m?h_*t#tVJ8HLKOSjZlYaA9jrOj*Y6M zAyimK8{a-N)+(1s$h&pT=uOX2EswbhwNd(4<4&N|^eD)?sTIoTv_K;*^DLj<8XiNO zo(Pa?4gwonR2cdkkurZfO|X`VsqD{Gjmi@G=4wwZ;a7OOu2^9y42>?kNJwfREF5G; z`_V8VOFGNHVD+l*)%4eFU1WUN`C^z>zxEgZ@p0PJX3y*pQ?o@APT(^d_!$He<1A(% zxJaQ?Q-Bkgmx>s7Aa-tL_p?h~*qkkln22q!6(nGogM*w(xpN8uJOdo=Ndm`8qRycR z8b_%17sIduJ2p-?tt&ZBiScb{Jptp=9XiQCK;R0GMC=F&Bt0b@Pf7$W5$VC(EC)Bj z#5|$G{z-M@>;o^DLjK8g;U3Npq0}OAGn6-RgV|+1qFnci5Qm2DJK)@J^E!E@hUZqT zK;eTilG)co%(&;TXMx`~Avnkx$r^s8B*LStk}!`1yCztqqOu+hpVB0Gw+kcjFjlGI zqRAzK{?kio2^bmrH-_nM!h1wyT>%5W-_G8AG@$>5vo|BdKh*Z`b@d-2%<`Ayviv2v zEPqKZ%fCqO|23KYSC#*l$m~A@{_nS%|732mF);jpG~_tiF(m9a-admoVtF@DAt;r? z1f0SI2RnJO1b8O@gSvZ)j;(vxL?7F>?PSMJc5K_Wy<^*UvSZt}tsUF8)7kI;{l@6i zr@wPXU-m`a)mXL0SaVg?n!owX$HWyWkE0+E{F7JtpicYpB>Mt08X4ZGzS*UbuWanW zxV`N`r+1p3`8^>sTVaf`<>TbzvN$U}zqq*augfZDH@J?5bOvYBah<>D^wno*NpK!~ z7#BCD#m{c0veaN4)V)0>Z14d9mwQTpG1T-5qvpoe&2wJ(eCj`q2V^gNhWOCIU(~1j zGmZ^*MkFZo4%d9W7-RCl3nwTn*jRaf8a=s?uz;`~U{t~qm-3cTf)^*?hiL>v*yE9@ zMADXkDkL_oo?$lrJQKN`Ngvq=9X7pkX&Z}Xt#wea^^_>ru5)HJvW z6Wpx-ssZ_0X37|VZEn!hUtH3Y_o54QN5nE-KTf`^4xUntrbic9zHA?-vbZ*ZjS#aP z9L+uAD=&7}j>463jgksA%)UpXTAy3i07l_G76*PEcmH`~jjh|~Zq1Uzg(9SOL<3)h z?w-t<05w$jT|Q9s=Aq{iVnQRCCpve!*_U4^Ia4(=NO_QK_O!J7)h=y}MLO>-mSj0gQMlt} z-!=2|qfsPZEQ;<6khwY!uPburoQuh8b@$1dM2pegGP%#tp}@_f(lnWi5pm8`z=WcL z*2#>2fEZF(DhznkfXELecHC*8t3O}L>U!ST*!JzGyEe;idcT4c^`ugG`?^)?X5W7A zf#={o=Y8S+od2|zySwVNc$gi2wV;FAtEF4$gFx6|$R&r#OY}`GnQu5B% zW0mTLSBlp~(U5-HrOJo78jPKOBrh%U*ZW(ehYzH^?3{`4+)~pw2qHGTgT0@f>%{A> zA9EzylS3CL zQLR3O(eRZhQYNaCwc6xpPw@!x`$DXD(_3GsJC#l5b2Z4p zzQb;Opec%v2wPa7`Y7z$>$Oho=b`}Wrj5=>Rs_6ZT>!uXrmFlax+J0F$d`_s?5m^q z_FNd;g1Jiubr=L76#RbbA=zLOoH$J%tWq_NfVwn07>XFfGpsuR)+;+JxSL_Ek=G)v znYBO6)8;dF*Y(qvP(yF1uprQRRdTs%+!A}M`F!p+GAuEf!QniZz<+jubb{PHiNYyJ zu~Gs;@d>Z6C~&zLLBKg%>&hePq2O&Ap^K8Av5{`~ZnzI|={MQ41*F*qUjhWIrGswL^=+>zZe~W`>O1 zY8CFSKE7-7+`8j!KGU9KBmY>;h7j|^7?=f2h08*1Q68A{9jG7dsAKWX=i>7n;|q*q ztLk)`e@i@5B)_e^?DJ`!N6$~Ro6(5-6Oy7?;N+YH=Omgy!`H0vEm&KV9rUtL zVfs3-W@E~ylm>gwGB6AcSnCd+G_kFVY{$u=qVBF^=3Qo-oPo5JIx$DE!5_SdDoFRS z+%~)o>FfqLUNdgaXm5$p6k&5a21Z7i+$+Rs8m@JbaCC@thU}K$ba9qD(rpf@+8Ekx z^SUAoDn`SpNl(ak&U@yW`5lBe5Dd9~pP#>wdn8Q$^R)y&e0eQ1Z5+sUdJvhVIR3ur z5=c{YqJ6UtrTnus#>532Pm)rHrJbrqj4n-*wb!jBNZy}s6Tc27{)d6n&)*+;!&K7l zI)QP}ANS#7^c5eXHVI)hMQX~3XOw7Jdd9qnhNJ_!lNVCy)MV4+UPj!7FRLY3I^y%C?aTxYk&w{Q_Fn*p zO8grh&qjPPZvvcFUZ}XCWo~_ybYm0O?0dn;Jz_vc7CnSFbQB+`(h4@kBki?@r6q)u z1Pgp>FHHEl+T>&~5sTyqGE5+F+z7bBPY6ECbcxYxanl-GAY37O5I|on+gAdCzp|@I zy=p228`E3abuv)%Ma>|hbuY@bnZ)NZUqIUixotjZCU#C zbq}(Y+V5E4o3|}b?5tbWZCBE!hD`PyU*k#||AeY_M{H7&BAXohn0lqmkkwT-zS6Tz z{w?X3|J40{bH|p`sm<(IKQGQCNOZF~XffKyqL#vj;0< z_$UnkI2EAnjj7x{x_g3^K~0mia*Y!h*=b;d1uisDlm0@y-#BWVnMUSHj891y>4Wlz zhep}DTcO@p4T@ya0d?h1mE#(D4d>DyhJDV_KY=^fOb5+<#!0KZewO_6h^ zAZ81-g4Eu)9$3dG*W+-+c{ukl(Q?=tmf7~ctnV^hkXQFwhjv9eQ!5;e6Ia%%4-VhI zAJYR-E}Ofh9|h|^Z`nHAeBlpkSKfCA_`KMI9z5g_O{$hL9U51S+2lt{&b=8AI{F{8 zZJTM=BU;`(al_R=#@<4XIr;7>HU#%B&mc>GSEuneNR*2!OH`Wz8>lFI66~E~xn#hKsDXo*)=uS6v_9TOiQqRhTglO|S2tVS)4 zJdUQnAtTuql>2*fwr8(3OCX{dZYO>$;&d){a07RZ2UT3~?go{y&}~cFlC@G68aXFl zL-#OZOM&w>uu<-wS%3_#>H5I3B>1Ny+s1;T*e1V?0KtLv30QJqZ>oX&J5NxZGtbE9 zZAV7+FSF#X`))7YXtM*|&>$@!^bumW82DiNM#(WsAB{4ZHgi1jhGEbHY!E!%>~&JI zFgPRBCvn+mRtGJd(?-h~I3atSB3xv3y4mh{Cb2f~Xv>aGp?R&uR~6^;pVrt7dLcEV z4135>I*oI{<--Dbhrua<=rXUl{*W z<{&oFW+TqoX2UV&JiZjxG=&*!8hpbIELD;c==y<`8>PXadNjf0!)BhES>y`)?5!LK z@cP?)rDv5EOQre&m;BFzX5w4IRPg8riZmR@^nQImpIBX1V*jMaYo6nU2x%?W1X3v} z9Ulag639F7{wgf6ZK1|tctghHKnVA(46~I?vt%m7Uht0`5}D+HkqV9~l1iMa>W|6N zK=i|onQYl@o%X1z=G*&oH!pDw+ljLv%TCU+WsQq6Nv6th>Fgh349Z3Nq13e^JU4)aI}*!2gH`1(d2*k+H&b+O;)c#@g;-WwLE7*p3ij}w;vK`E~7*3RhP9zw3byD zepMee8BLJk2kMPqco`1(JHZPo$qMJ_w!b8c*J4JR*2Y8TQ#)K;xh`Sb0m+vy7_kgK~dc&Y;D2MdZM$#_{*={%nzXc{TsqZaE zh;GeMyU;AMo)1SXG%>3t8=eIt@-#_iIm}`5S)9Hpc4>cO0%J@FjAfcola0X5gDgsM zoSsXk*j8ftVHM0w>^!zX73+}0h^h8~n=FZ@Pz_c_s;K@jDKorKX#+crJ7cMX^C!o2 zsVGVLXv`5KwE0gursD@1khM%^1KSYV%m=2XEaUr;_XaeHKa9ANlQ)QXU&-M83t%R-$8Dkh5WeC7w21xd~KS=84T;Tla0__X z%~eh3iOIuD+p9`YfLd7WvbWk!8I6%UD_8=@)N3i7-dJq{J+Ok=*J9FZtEroa5YL?W zZ<9oR3IoQnpCTI813A))zCv)@zs8>ygbF<^qQd)4yYysBAG-s#y06wh;rFBYJlk&_ zr%SF*gt?b^xnZNT$H9PT^*~!P1`cq@U#n1*uf1}38nP!ggGxKH%p?)}xX<#;{oWt~ z1kQSd@q&2mfA+ueu(EMi3LQ1P*{cqLa;BJLV{8SYDCJ-G0NV*FqX-yhMGCX3PZHiAXxg<^b5Jh zXfFhAsrSj3go2wOWHaLU>mB3AHY*L#_sm**l&WWftZ^Nt1+>)EPU~A~VrKk!kH9|& zAi$y!mLRJ62*hYwEnM=Y8n^8!RC%*MV$P48w~#>ZL8WCeJqZ)|hoy?cl>+o9yPN=U z!3y+A=!o+5;3Wo4EN~&EIbfC}LEEyZ9QcvHVL|;`Zk*N6WwbdRI&HSGu>$phsxgo{ z8rM_b8#4@jP*a=wKALJ^zvo^-2!*!OK$<0r$kVTscvQZUG?Aq3-H9K{J7`3jS(Hkc zdl42E&WWf|ti4!9jDv8O#vE?x`odb+b~Z)Dk1~myKbwHcYvZHl4#KQ<-8_EN+;o1qfXBt}}7F&D z&+8(ep-^Gb&!UnTx}}HAGN(J|i$TMPm`t0WLnVQnU^!EvZfr-4lRidLx#E;NMuK2H zDG_i{7L&v($0}Efb_&FaIz@Cu<)!RVtY=)JUoaDQfVQ%m ziH4yIQz5l5A_g5=Z>FL^72!21Y?)9gTNsg$k5S@~4Y-Ln10_N|O^`~@3}0BN8CR%R zFg^p>i+j6NK2>~gB-$b92XQR4D6oq~cuNpFjHp0U0>X40XOH_-X$Mu-aAne3U}jqd z)rIx2I0jo-Bl6ndF^yUo}%p+-P zIZP21Ho@`t{=jNyBoWy`Mo@{ba!Qq1u%L5>Q2{?ng7T6jE5IHJmh@l;m>1v)oW@R#o0mcj`)jx*R1 zjuaVH4DWeA8#3uI3w4OLMxBwXj+CVn$RQ%v&%P>x_NkMmikifaJNIB>3#xF2aIMr>8}k{JzXq6cBD$LBIa#OT z?pJ1BZ?M;9z(0)0Z;oxlbt{_c2UrZ(cc79CAF779KOO0^zx!v6`%PURzs_h(;&Z(o zmUnwTuux3SJ?-0QMJ=4cc~QAuaXR?_yevMwjUe>2Mv(RFvl%>6D)Clxn^qa^sM}P< zf93ezvw3d18<6ClRO$a6rDA0G|L%1Bk4XJbb)`&9-=VwzzOFQ0Qt~GwLeQ5)PZZsR zAyYy~qM$S3cV8*0fc(yTZ-Y-qJ(`8%4cd7L0hb201H zGq0=Zw^|Rn(NrBh6v;|0xuE@Y2du%VXbQ(v$SnAgO?YxD9u$mO*~*t*ZQyM-#<`E#U19fV*LB<)EgO!{)Fm0vJm89v7<8FW|O7 z>0>{d%eDeAn15Y`H5ns!*UsS!9eNjwl*(uo@X4873Eke#NAHHR2LR4q%HV%@f&OyE z|4JMGhR~S*4WTjr8$x6LH-yIWZwQU$pAZ@WJIlWm!txJd{2$ZDKcDu06Mg(W;s1a7 zU}0nXpXpDHU-y(w_j@dp4JFbViDKipCM9&9{&3;f374@Un@fGMw*ZXXh1 zaV2MES?Mdc`hY)iY94Y0&+%%7F;L!JOV_#%9ukzp+tGK${q*20!m_fOemxJO<=p01 z@$jO!>xqsEn>c*pZY~Lu;>DgFcnz$IOsm-SplH9f;C((%uVs6BsB+=~VXW-rK`9E( z8)SxkK0dB960#R=uD;rN8>TIwhA7Zu4x0hY7MMvHPoPBDmry4T+B9-xf+TNE(i8p@!{Jpajgvs z3zj^f7+*1B@cD4P@78R+Ut_-BKT9@HuJHlBqi1iqiOzr3gPb37j3LIM`1Wi*L1tzs zD=%}r`j=n#%4L3{OJU65<8+~RxgpoMmvmbH4u%G0g1e0BVdWjdM569#3Py1X6I+rj zE`A^}Uf^^qx1zJu^o8Ou^s>lwqnhYN!1JV5S7H+|U2&Jr9ntZ_gtcQ%`^@f%Pc;5l z%@o!dd6p6so_c^5K^ghb*tM?K;P_ZLLdKB<$7KeW$e|XyUbbi?7*!7R!TKGNrF?h4 zfCcgp<4xK+^5JV66kBkb#Sw!BZWOVsyh%+@A+jqJqh`*JvKO zmBdi3<+tqh=famhU5nVOsNp_$h|XB|BuUAMlX{kNDdMP0)_#oUb-CRRR9NTLKJOn_ ze0b8ST8cW4qigW88qz~TH^2#&AMc6F_@zfFlcMxCXK}342B@px4O01f`FCs)vv_#E zW6>_d7Vj{~w%g8285Bo%hrhq^!unS0oY-*#^IE2Q{N1R3sNShn_pFbc+#$2h^FAI zOpnhZL2aDv896Sh6lCo-xwIAgFK|&;oj1h|8AQ{8D%A3Q-hWS{yv~P@m#<6+y9Da2 zEDRNG6VBC`&oOG)bxR8^Z=41SB*~lmkLK0}>cWG?I;&`s_kwv|A48^Y+jjt_Lw54x zM&AkeI{GSLHwX0kf>_X!jbq{@1EHikA9Gg}^b>;B>EHJH8K>CYOGg=+W!U+$p4*+n zT}8A;UpF~$7?RI%79REI5Tf+2u+{g+mKRQ5FAFg@I;3y1^wCgZ+0nrS#-e@cO9k!i zB!~Tx>3K;d8W0SL3J32AFur>m`r{Tjye+4j)uW=b;iTkW>{XgG$S9_{Qv@tZ#n0ULB& zr3y9Hx|J+n=5_pX#Oxmy{xy_#$b-&4Xhm~uLT7v*b7QN$RsygzT-s0;sc?SP?yiWc zj;o&o=O<)Tz|A#O5kvt}9ypPumjtMDdS23lvsp;_L2KM5rVY zi#b%5y~3`|;VPv&^O8A(@zY}30%30uWJ9BjM{lV#>FxoZ@J>UY|7O~A%$6X)fQM5m zYT!_rR4`gm8q>R?cwe;}1{4(Td;AyI`*Ug&8a7g7u&qK{=Y+KUuQ!LmeevHBs9Hn7 zQs~7HQ4avR>KC}bYHZR6dfrqtSxk~9yNb(}kR2R$juhN0EhIK`l<@|$$x~P5T%Zr; zA3xj^t?Q^tZTbx4!L-m`g*A9N1@@1uX;GiXD-9lN&oHY8aE@wyYI!rpW+=J*sMCEJ zD_|zg&!qyEgCxf7Omy{i#Bvutp+NtLbWwc4h$ zXqh4NL_}>b)2cZFUQ%pjc-PKXFoE1qV*kn@l#%sd_`@Vu5@>tdz3no;?n)zKY+{&? zIx=lrkMhMzy~CepW@nqJDR&O5vYVZ9=aR&!XVha>BlB>K41VMld+jRsXC|W&gb?QH&Do4PU2#Bl$a!%=ID<<~>v+Xrqq&ngT#?`ZHW>|CHZDS9|_d7Pq!Qml{oZTje6>&+=7a8DVnQXUWpPiJI!K+ zyl3}s3-2Cc!t!-d;-VbH`px-v5@&HY@aogOko(`m?XY`&o5r2u2a={%bm)O|BF&^( z__M!(?ic_cRemk}rtD|(R{?(Kxi7(S`+{qssmNTLb{0=(K_@5__Vw6Gc~0_bQp~Z1 zVCZ-0(TLGVPhEgkK3R~+q;HPC-|idvQ1PN`+L^pc@N0ya*hrUcsXOd?V#5qTTdu}0 zrokX4PAcqgcM=QHRzmbf{Fr*f*mK~!@;HDP2(S)aGFPr+`n=uR@_cK@S8-zcW$6Tc zcD>z+*OQWVZ|oj&F^3|F(wS;NeG{MnYS2Aby?nW^o{=pl5aO)0WYUpuo3c1A6qi22 z7}2FUN~FUujaZTx;G5yCF74Ls0Le#UxG-)`t$-x+(bu+Xx&S<;Qvk;wB5qn(|F(E% z?S!(QnbYw#Gi>z&;*cgjks?es5Fe%KH3g(X+dVN|S}Tv+zG|GdVXrZIuV#`pfqkaO zxhU3gz#h6DXdE2wvZjs)sQA0ixn~FKq|#We;-I4i@B1M_1pC%;oybuzTb0H^mqM33 zNjhqojkChB(U>0+ZV7jvx{wZfN~`U#KF`!n?qdq4%c9e9y7%M{P6zb7M%N^6ncVE&dP)5jmV0^=*7fVx9A4x*vqA{=Q~+aW#vZT&xm#X067ew?*8j_Xtg}U4?6^_shCHDH z7qn&Q;+t@Lc6T@;i7~;};#mty%-E5}BkwTnqZ07COLs=wO8RQH54Q`yJIv07v!+@o zC7Nsp;XRv}I^*bw=7c*GC(&yiX@)5?h-X@-r(Uy(m8aq!`2 zF}B%~-ZPIA_Y^pwEQ8jmAv8NiiP*(pq_|(@7>xCIW`$;%cw5!?j8Yxy3>3%lN2iHd z#$RZ#I|oBQYlXY+@?iX(yTIA`WZX7lKH%%!M^bs-tyLCLP`hrtR!aAy-ImC_m&5+b zXQ%BdJASESXH?Up{R7u!KJ;Lz@@Q!Ctw{`8ppH?7VbGr|2M#Y3RdDFNKp>X;dXgmI zMG)xH3qT5UwJAPOLICMnAQsGRZOK4{5D2JSAa=k5OrQ=?%D31MgED$nI@c4bA)+b} z>Yw+KXqCkA{#N2BzuzPk>u1)EjZf1O8``HQ69bNVf>eMN<<^8>*1psh9HMIzv}Ebl zE(y+Rlq?y7o&}#$}=3xNsC2jodWRF; z?Qdx}=PnZGj(-L2${Hmz|M=tN?H)M=43;$|9|Cz%Qhz0BdO{<>U7_=2sX9Lus7q$s zfLol>cs_MURCwUD^|aBp?!f{&btMTC`*~S5T`nXt#MB8kCJ@v0Fz4oRGG8?lIuyqS zdM*j>JX|acKQdY$&ZDMc`$GG~^0O);6fd|P)jfuoF7HwVz-w@n!F7GAJ-4!9VX;8C z(M6Yizp0sPH;}%=xf@^hn8qX)+U;gC0cuIS1{9n>1871~MpADk;Y!8_c$i=>3@%!+ zjLs(mMzPH?1{k9rE-NI-$!(PHXxs}hrM*;^o&TpR8A%8IA!pCq*tcbioh5Fjto z0E^5_vF=#*>C&}o&#XwFI*Sg1?F8B-_t1eCHgWJ=7L4$)5VfaWx``g?F$w>G{k3aG zKr5A_+}AuO?SCzG0<-Zqt^*NygT{dTUF2p~2NMLiLAwwzJi;Z`=a_AP-`=Z#I?8E5 zZxRTr%9hY0%OAq7(ew8uY({00Xzw&^8~S_Dql&nrQb*)6OX2L^+Y*NsyurMVlPu$l z*8aX`ys1zEQuL~|+{+T(cIs$4CMRSA^$F+AOXnTNV<8WobqxL-mcR;bHu@GB=3G;; zLLdY%FFkl^L}*zyXj?iSrO-e-wh~zcf-)^jYD#1#P|5@Wf#`tvZSCxpz9+;5&=!L+ohAfwI-&*Rr4&LAL_SD<)ak+EBW*XQ54kK(F zJKHc}j5u<|y%~p9E^bhzUL!l}TLeW$-&-s;wVaUU=7R8Wu4p2ZLS zb`EB?*uFqYdrVj2&WXSz0Day-YVST(88YeN@Fo<(hB~}-H1;9s6;8W2(O!w%oe#te z>}-|%ANbz9iT1senRaU$FvzVY)gIt6X+an@^ zddX3-DxQg%jp?_T@Jj+8jPd4%fl7>^Rh!v&f^btO=>(j0)fe@U(mwbdQTLLnIOwjT^g6>?Wp7&{q?4o+_p zQ7m{fT^Msv%Zxglm=Jul5XQ~d01FyG$D_0%XcVM!WJN5)b_h4Ei%Lyut`%Y||FBdU z1K2i60OX5WILE9E9qIs(wfao(fI&%bXeAI9ei47!tc7RMqM>~eTO&+Aq_iGp3bS=r z+AO_g7aR(|I3!&H5jDzAy0Vaioo+6<&irHeZ;5LUtTDPdx9uc?7h_P}yFL~EKVsN} zPwC3{FxbJyQH+Vtgk6knqinTdn++Nb#;QcEtrG@{79^}IglIPu#I-8}nHHow8KS~g z61Cy5%W85&W=#|pB;6!{j4P$=VhkbGg8yL-qw4}1<~VVU+Ef0x-U+Np!EfdWPDJV9 ziBdcxV`gk8`~EYJ9v4=iE5=^qQ$mCs76y7L{}8wG4|7NivLGv1&`?4?BM(8T!*_I8 z3kOKgByK-ouE9h2Qr#eLr%94hqaZSoe3K^R@A>Agjose6)r!o)NGlSI4>38uzGE*Cj>rPwioi%H-3ia5KS>H#RD99nOe?7^8g)fq6cXuE z0S+;0_Pfx`XSB9iv@EX+!oKc6+65dWAV9f!904pdm$q0}Cm>V*b z$J7*d(tj2gLha`%Ss$WmWP*O!{==mc)YHZ8nAD?W3<`of8--`-HJWd#&cq?%MNzgi z6^wIIJ2Zv4&?h%Os0!?bP+kwV#_VGItsG_TU^K3ax_eAqR$Aq}ST)=bDU~V_(?cvy ztGOj*%V6{Amra0zO|RCG%$zn_71^4VtelW_1X+(+rWL}Awh^837eLt@35j6w`enJ+ z!{mghKYq$c+ypA+!^^8HKu3=|;)Yu+>u=W)WW?9vO$YA8jJlyi(n)w43+rwWl-oI_ zjIoN4m1;b@bNd%XOg&V8Y-N0Nm9Bk@93F5Q2#i>GzHp_0uv*>E3t3b<(MTL4nO7$gM2o_5-;XoC9l^%j@z2G$19e>;r28 z4%TjtiC=GjO8c*p+Hj6x;O}D~mrifvuJOO_H*~w+@B&RP&hof!g;;#uhV5mg|s4zz|hCMYp(BAHhRz9x^1 zTy2a~$ozK3HHww~6RML8O!Eh^Pbd79SfGxX00xNLI58x6^e_cb96@o=?3ANkU~P{p zC&Cb-gI*AamW}NqZVvRr!Hy2kWk|tg`rP4XY`0Ddlhqbgqs6#~>Npu+sqD|w?m~Sr z?X~iW(YwTT=2m*c#l*_8cCB&?_2q>D(m)g-&Jt_@Q)?Lc`8hfkB6A76g{>o%7gemc zGTZo9JD59)=GI>CwQOmX_KOSs)yWf<};P4d`yNL5(M6l0-eiQIuen#7AjE{t{ z^nubo)V}_tb#dk}%WVEIQCNFwoiIU<@e_`J0^1R)W(Y1{jf?8zh;_q7>EM#PKB7=N zD-hmIu_sm&r^leNhd`6o({+PH58tWvlF+tcy@F3@J(~joiR76EDr|~we-~=x2Z2Oz z3iaoZzHlI<311(1-DF<+`ksg#eDiXT3(B_^y`5!Dud1o&+(I^7r+rN zm~azcirXgOnEVfrFZ$?q<6$AP*xX|8vuMcmE&ry-fFg#N{Hht?aBlGb zZdCn6m;VK3SpLnJu>6xT`G%K&p@!vOsA2gRYFPe-8rFZIhV@^lVf`0sSpUteu>Nzr z|6{QE=ji`8fz96&{_k(l|H`VcG5tTlW`pN%R>kJ(gZlMPPtwB&APyKi`6F0L#2!zz zy(`@9jN-hb$jmR_tdRGQSQJwEMQt9IgByZS^k3AqB;f^O;Rdy@_wv0tTjtL>`}c_o z(Y?4w(;+$V7U9|1O<;a!_?5Q>oszsbQILv{vuSScG&`&5lw1HIdk4AyNvtTh^f+?7 zA4K%?`GWmTteE|iSc&^itl;{*yzPwt$80+N*GySJ4HF}V&&diaA77ux-Gc<-4W%UH z+wJe~&_iN~+hs9cC2ZzCd5{*2c&I_nM09w(JX5Gqvr&l1P2KS1mL+HO=uXKH$Pxs{8DYtz9JbB-T zuafG-DQ!{ZpnWz1Q~>U3-_N$wygi<$_lo%*Q5z%`rG(xL!uUKt_V_-|T$d#&z{dmY z0*4P|X1ou(cDkpHGiBj9cjjVdrmmOo?pk}+OC$SVHuc+MpB{?QS*4*yNq%q`M{Z5{ zgWrA_l0StnsAaR&rAdKW!&<}I!IGRUjC{P{_4<4QG+aNzEv$}OR_237xk7PL4rP+O z`+xRnK+k+}cy>#MfDL2}{Kmavx;$?U^?U6KjULzy7b?L8Ss&R@8e7nI6^<-nEXbr$ zL8;y~EkLZLVCZ#&>6Otoj9kqlT^%ry#0xaF21xN#g{h6`8>nmG+K@Z#kUMNJ0H~^0 z72eMVc@tb<=6!e}>01~!$T>FPHj=B2$Qe*tcI#qQumUF)dRuQUy{$;t{#v*}f{h+l z&DM>TRV*zA$3OWq2OoA3w%ubrvbp`ZEyG?a)T*dZ$SlSH^-EfNu9-yWuHqVWg0#0^ z@b!9m64caDUEMAxZECn`U)g*arp!Eg+x7$roY<~ICQH}cqY#YNoP0AZn5#X055yBg zm2HrI$`>6{!$t^+YILs=k?fv*_d$li+pzv4L5wiwHK~QxqNujb1>Sc>U7{O^3oh7a7nEgb>bB28rula+`&FJ|`zd@)sSBaSTU= zL&D^&rN+Uy&*wZFpXdAOF+qC6vu*^34E*XB-lsn_D*~Uf@+Sdh48pILB-1sM)1cppNe~>HyCXFObK?LF1>9#zC2#R z^()ps1N90~Y$H!wYVm%(-^|Ay zAYEg^7@{B-WH*48tbD*-G*YxGqcJq|iTJQ(NgBYh*Z0IDWXPKTSqmtROsLr2U^qg# zVD9LQNRIDRJU$@!I+%fyr59E#MntIyz}N#w4Pr3~lQ)=R@wD@#LH_oSk zdLB#)#Dwg=N4UxJvJkh(Ady!QIG`_zFBHVBS6G7&2QueEeCh>Ab6Bb`vGv40%l2KO zA-87%$ZV0(Q7YC64$Z=4`*#)RMStUJno^wrm<=x0=c0?~IzgjBLLIdX(~S1;9V}zY z8c{DkII){B*zD_QdC8qgyJMzlVYk>+8hvc7)+I!;WDcFvk0Y;aH>q73;?GG>YiQ4~ z$`)C!x`_A$h})>}iB10{w~#;9kUjzDyS{D-#|_4{nJ>H*YRr=8hne3U^tt4}q3`Ty z7ZGgJX9L_1dOd;Ht3@rt6P7?%VcmV9;K_ErFYxuD{6Ki$i_TtROoS2CL0Gstym5w5m{Q4%hh2I2{;!H#t}E=R+`S$ z2-v~O@rVmMWwkzbJxdL`W){lPp=EG*{Ls-Uxh+?123!RgW@6H>PDLyVbQwza1-vsW zH^X9Pg3ZIkcMFn3XCN;X&gPN1rF#Z0n|NF2%^$t>aoIL3V&eoD)dFw)Vdq9svg!eP zk!;^kRPlG^_Qw8i$v=|p7~B$_{CeMG9bnj0O4~GUh-Tv@=b+0M_?_Hh@>}S|VXA2RT@}2p#nfwSmoB*H`gNmj%}K`7HczYfNlSH3di0lI_wQQev$PrOl9Kt=7~Dt`SM=7kD@ zoAqz{t^(+e>OzMqDGST95zh}?R6PLjKrWegc(7%vEY!nUPSx! zWDt=ZO^RrMWT6Xu0i^rI5zO7w`}LcC9&0@)Faw}mJ(vu_u`16!d@)9%#gS(ScU!-Y zP1#K_3{~5zI4!sO=aF9y9Qb;!#}Jyk6N#Xh7Z0El4+Hx4)VMK#>(HBlpa>gj=ZTW} z5Q(ZK#U>vz1B81+{IV%fldi@=nO##6jwA+&a$c|ea)9IJ>0y=5bg|Ni^yc<~qZRm8 zJe2mLmQhK4u8| zjUZi(3%&d9ObrdwZBdvkkQ8!$$cfr1MNy8 z1CA7Nm*-jNFn1cZtpUsZ)uFKaRW+ugMCo>uOI%b5FUx)i8f!VqZH;4*}b&?#Y}gE zn^{>=ha&^T~d*p-rpY}8fSH1^FctRG9D^-KKQxyq{&i`7*rlUnq@ zHWOwq2lCYeagej)@aWhnL6Aw_X{W@(+!CBVyHmympBYJkXDz#^!G4v?*cRf=j1vuM zhTnJit_j0t)99e=QB|PXbrtc>a-+@vC?_qC>|Vm1+Dor|+<4L$P%%m$beTS=v9B%f zlWS#*5l(~ULk+1~1`&a}l)9DA#%f%+;|=Pgffa$=)QfUk@bIVZd`hig`6E>W|6Hfg zvy%!y$_bJ<78MKLR+~d1@q2Q!Z8%twjKB#u4{-Utcc9_4Y!Tcp>J0FU*ii3 zc-txyyM}@RVsfS{-`C|8!8OFyn~u1{kzNHQzK!xqx_MYXjTP0X=%*81=T@bB4Fkna zN)E60^L&U;>y1hN(v(B4s44fFe_7mh$IOF(WU%pNR#7$6kCU(6OV3=VcqM zs=0d$RddaE*#@PejiyT+m8v3}$iuuyPfE?5a?_2bs!QWzpI7KEq|l%0pjm9o&emZwQqaph&YWAPt25apT#Zm3NPp~O~DYxz7W$jF9<#>XeU>lLOAR_agMsZ=L zxLg;2;20GPWaHjEFauJwe4|?6GD+!iJpt`1d(Y%>EpWAUCHk<`LmU0Dky8LyF)pbg z|EwopH>r*o#IfFe{AL;TQ>s`*>Hfi^8SEm6|5bF0m=y7QqvOzo55YgD#MBzCZMBCj z{H(h|4r#?wq}t9m`>t z5}SuWvJ-X|gDdvSj^;VN{z=%UHTS{lxsI)0FI~ae5?fK&t%tD<3Oh8 zxHKmhFx4Qlcx%%lJ%O9oHCFSbh-T^bG7@Ht^rplQ992!9pU(~S)m#-IG$L}g@4SGC zXz$!BDj{70DysP#14|zS>WAY1_{Trc*i1Zae|iJn%>#B|m;{1618p;N0PDx1=|Mkj z9b=>x<)-jQxWY_9i?fSSunYj9)1V~e0ifD)PGr%X>GmmU}h zoq*9JEpYI?M4Qxlj)a7Ij^w&NPQI9anIruCo!IdZk!DB9L^SH}v8vqO5!gix&r43y`CHrXr)_^c{n)Z|x6wYL9 z3`>gE={X}14(JAL3XSv=6Z(y41)Dv41(_*0HA20wwNF<##=E4S(%Jw6DnzU;c$Kmt zPzpSxVdO!H9Rbzyvakx>na2Xu9+q8F1?wJ2P7PSn(I3FFqoo+g$`ZC`;ffDw^SLE* zd#FLH3i`Mxv6<9(pUV35?Uzt*Z;4TNEgw#UL52%`_>&PJ_AivXB^D*ux&h6x{Duh` z)TM_TS9d0={*SItki9WuN5wh{?wGA?Z<=nKmZk+b`UV$RPgvm~s+M{ZY262kUkhUz z?~D!mwPhmjo4LNa$#(GR6{TVxekDBHTiWY=2iEJH!VE76%qD>3bu1xZE*X9H%>FZN zYt>Sp+)|D;b_28bKYwwn^~dQ02-M%Txi*{L+PW+Wy#L6C3LOFT6n^oNouzD-ncN{K z-%(N+=Ih(~;%wRLj(c-^vp<-&tm*quehGtKxo!#1Ub{a*U(enK8?}B%ONz!l&(-DY zJ09J>5)#M-H?uMqoU!DAp|$&7?-&WUZbY*J8MujW-?C#&%5k?-{IeH2Z$@ZP?^&Do zsUk`&7mht*6_v%=KyZSYmz|6r;REu-zbI^b#$L->1*|k6w7(YS5EPVBNFxv$@K`bX zxZm=0Rte@Rz>2J`zt%PGfr7wBM&Z__2x2}-v6U)36N**3s zgg} z%@*eR?3`nAHii;3iJ981a{y3 zaJ-p5f0A{ycZp@zpzmBvHgwu(V`C-iBo)uQ^D?o_weT}2vTb;Co6B)|yrJMAr8LRx zZtC28NuM1pskaAx9+`X)uy=X-==?lZDYHKBu~yLDQ33;w`x7%H2f1J->3HuZsK<7) z)vmlBM-mf%8Uf|;@>r8Q)9D;A%=2#qJMm0ruerh)$S8EimN}4{+|zh*a;&iKq*=uH znE+yBkyk#)7}%cv*|;G%JhBDGx}QV7d?Z%(bwDOHu{=qKQaKIo!3nTr>%((_YH>P{ za^R(656V4t;24_V-2a2Rw+xD-4cB#Xm*DR1K0t7H3GPmC*Wm8%1a}DT?jGEOySoL4 zGx@%(E$ggxPVJxj7gbO^)icxG^HyK)b>IB-{z_!FUX&NLuu37jgUp#DK@7Vol=~U! zuYI?saUfc7KHn=cL|e=-!g+Tx!i}#??AILTVePF5Rv1ycU}DCjv;2@iHuJGnOe)k) z`O1%QkPyZQm8p+KJdB+a?Y@FLc%6!AH=qtq*Z?wS$?AJyYttlp2fm^?{UG2vpBb64 zmahMf`0z`S)V+z?!=&5f4=#d`tO=;9U83}8(Qp}Zd)g`jlA__11Owl` zUwLz6-xe~ULbtvoc<}(e7=AiK@iON+VYIx!LiSUkKEBVAN>#%^T*QsmgZ2!XxOMRL z313Ldkw+qKWNi}V;(Bxjhv85XuEm2-;wo6n<&b6u4VYy&0WEku!>vRa=PM@Lluf45 zmWOj;&i>pxYi%waJBfmybNc7>$*_Ljj`K}^_PT~z#DXM_0Q&PJPK zYJ6n-3jif^F2j>57}gZLNsKHwi&2kKgFf)06fcP$(Y30l#+Q#b{S^i^iLM4(&@P|D$5L0iwuj#Hej!2 zuGibyOEQ-tk^=G3Dw2OB3X?yQhW3I@eRihFqk&RVCkdJUOq_LHQ8 z&hz%eTZWSaB}aEN`(e1AcX&E=8Aow7_kIOA3dmkv6nz#>r+Qkc3N8MV@F;}S2w=kT zwy`{deCE48&vgbCRuOP5hhEoDwNXu=89KSV_#PlbBfNm|qLC zi8AY=u?Olq3yw0duY3TD>v<S^RzK-5=VTWXYK#@nt)@x`Vn61&7w~_-^Qes#BzW z_bbEDEY}Y5oSJCdOBhY~x;`724^l-Xuss7aV@=5Pb z?xpzn`x9iN>H)UiylpdKN(v!4a z30cUQqOdM=beR;Vn}*mf_()xjC~n=V)l(5yn^na6V~C{=93f3 zC-fqhfS5>kkESa5T}dAOisPk`VSS=`_VV4=R{u?$t|2S%RKfkl0lW8mE^+Mh9LaO+ z{pRnB!a0lj{RqvTqSr?AnTV90-xEd7KR8})TOkA3JPV}|!U$y=5F7lX^wJ|R@oJ6+ zLs(-)I9HDe3qFux)XKr606pE{B%w!A0p|ROa_x;OO>TLERhOKc%_eXPtWw4NWVLUB zwTB`$8fK9R=m<$J0Iv0wN4^C5Zeiiy0wep9oh&5!QOH{9AkVK??;Pk_JViSsXc;`~dVIRBC-&cEb|^DoKb{5y~HpLzeM zB#Pyqss9&|sDBRlzrV)+gG6yNv;42>(8ND|Rt}f97`OC23>!>-_8@fekiTk3HHT}8 zh>`2-J?SBwz(&4}T$cRMAdk$vNZ*JAa7QjAELblFyX;o}F^7CgwgpCyDT?p|d9nqF zeE3Q!JUmw5AQ%NKXZQ;ZV*iLB&yQ2S_+7lmVgw)8o1xVLgwA4d>pM!bG(?SyGGQ~r z?yrweSNoeE=NWe0@7ty8s6cr~fZ+X&uE<*Hr*@G}kp6=Zo!^tj`)BuJB7xW8>s=xq zsPkFW#965+YM+mZsgIkI%jz%G>eDUIN1ywvL-oPC55b&DW{14N()t~Ro+czd`Kj_# zfP1ZikVE|=CsBirw$y$Nmo9Her3G&F@~2@52Fu|;y2DV$9lI6hP%g`@$g8+!Qmn|q zZS3C2e_+}KW8gJP&}etBRBafZf<9$95{IFbe1vov(8`#*_C*pP^l|rBLm;?Jh)FTt zD!qNWWCszxMa`|5c~<JoU}-kk{=m0W@b6 z0+R6(6334~z>jR4ZJ{|&91`*FKXFR={36%PYR2JfN2avqjr6%~ykj*vPEl#zPZMJ=c zGAFz6in{_nx(wnRq8MTnXl+<7l;2cXF+3jpZ=uvT z;J>d5*bC%!lvf^&xjvUN+3s>z_W-JXdmHgnzL%XX?JIsG&TbKS#hVX3>iTXT{?=Ok z%4gKM#~0j8vyE18IBt{_jSC&?SgM>VQE)imJ~^I>J6swA--~~!nX+9X&y*7W&~wvl zBwN>W2%!*i%@30;RUD|GE;G$yA&J{dpE!ji`+D0e)`^{yiHM5C&x-5J9LEgHTnH?3 zfRK%hQSa#(Kp67tY8D{~t8-iJHT;5t2d~1&2*A>yDhHhc$3oP}Wc=bzuI5vd!h_?&fhpniGl^eTC}37t&xKou?>U{kiC z^dK}AJT)VOYUuhZa3DJV?N=Decwia-g~bkw?}#{3MH1|ob*@_ght>jipm4hW3FUC@iX`OuVGOhk;dF{|_XtmGy&x@F|cIP|O;ebdr z$Y0m6xwc<~1$n4aLDyO?O55BQ$vdWE;Suf!A0BoR-i2~DC!%Hc)2Lf^M`&_@?Q_54 zkyUey)NkrMzbz4Va~)*&p_5n!UbqMTMDoyArcDdm>0q*=+s5)+g*=Fhi;`>!VIQCi z*$Hw80TcU#7KtRyJi>fm1&L3on{*1}r6!>!A*2JH4M|7f!EMq_E*4WO(q4a-Mm~N& zF5!oVj0KAE>MASDUVgJ~8ip$2IY*ay5(w9kK_Oj+TNCDaoCM0ym>a%TD_P#?{Z3mx zU|~ovT=Pvu8gy87aVxX=d9b`9@B~rTHtqS|S(&*E&E70&&aiRZ>Dc9@^g@skz4dW+X_!^uV z2)OnHdqWK{dOj%$s?NzDnQqIAe#LGu01PjL)M{1F8Sg?xSCWZ2U$=9HrH5`8`o6xLyd#oF3 zZ2L`dfI07)jm-QWF}I&BJmrMn9Pcy5K5nIX7q#SWi6r#ad|$#39e6m(%QA7|!8lKu zXJz5T3|f%P@@`&vIRE>W1Q>+LCWGn$Y7WK#s_G1e@2KbXmDruZ8&Z}JBh}t6W$iPj zfns5Ti;VLI(=u~I{G$J%e>_rX6=G>Z9W1Kxa=8B*KT88y(zG;z>w0fi`WTE|CU8%- zxRuhzJ|r~${lvr6J@oMp!{nzd$2TFd`D_>4^X4o#S^T;H#yPttZ-Kl=-#YK^#2@N* zo5p*Qj}IKH4}g9yo~vrxwJxly=Jl>knye-3O`aS~LCjrG+szE`m)g%qgPKGI0)07y z)K})PP7!;UAcxewaV?awRTdCD!`|}i3pIwtw2n_dN(H`#D48f-@l(f*RPR+;i`LnWiU%FuS3S1;vz9M2zbAieY{V|CqMy9J3Q{E9WLFkE*$~>YFnwNg z+@<~ruP|mULnY9$SBXbuGS5NbbbHlfa~b)f9`TMAARG?UNyp=p@! zHdqlpf8TCrz=3(D;#ln@hu$CmarhiGw-{bQID7PV3YAdTA~;^NEN{8GO?L`4l@hEn ztBdL8yS)V|RYVN7)aNL!-MGcZnthhI)htP4+TH%GnES;-N5Fl8@W|_{ncgAu6_%2P zmO>uI4>Ts_ZN1?bCw_I$%2@rBa!{Wx^T!w@v;7v(L-83F{ zD(oIf#^1;DK{3eT2!US3G7+wxER7{-a0B!g>Ogok0)+ZT3S6k~gKc!V!4M?}7GQ)* zW3&`p0m@rRvbm9MU-bhTfJ=@jXRcz)G&+nNiq9z7vc%}q;_Kh+J^#1sEfre&&-JFy znT&w&voRe;4QuQ1&W0n_qQLya6uyj`46@ls=*$d#(J{ewGVe1wQ)V>QW==18q&(`6jgFLQ0%g|91zeqm$iP3pg*5C6v$o(wCsTRA(Rc;73f?8N- zJta|z59TqXC_3;A%{mn(ElJH1qoVP1dhJs2Z8FD_u;dOZwm*?V#tmb>l$<~AC2%ER zw?mj%r?L5;-xVJ;NM)YxcJiZE6U-$$swLofb?{4QOudbJhS^|qP8L^x%82?D^3uR3 zt*5}c-oGwwzR2Fp1+d)Z{6g71}$L_GqEzB32WQNWL%rIr?!4E`?l-|lb28)N1 zuuX^9%zlw$g9wL0|bHM1SJ0&T9=Ogbhi<^jHEz(m)5KK6-7nP={Of-1f+T zr{2aQ?Pi>T#R{B^^h8*L0Db~DbJ#`ch}-XK<)5NzrQUWGM4-xf-oL4vKwVpMlRevD znz#-h3OU?OmaTL;VVsxl{2V`NtvaD)ww`hpcAk?pb75sga|y-4LHPbs)5lbnygPHK zE}I*aA?%On=4G;X=j~YUDc&67oIS>W$U1kje3|Z#N0u_jzFTXQz%SaGeC6SiP%JJL z-*BeSt!S)*9kUf=L5MrBW@|cXF-f%I@V2H-WQlFZ_WC4wrA4i0c*UR`h$p4a?jgmR znJV^!ro=;od-+m5hDc$!CC|ngQjbqE+fTTDnmdY z(rRm2rC3np5ZjZEIyJ*mHodgv*Vczl^zrQvOlS_a$WEw3*DYr+-{%IXuC}rEPcg zB-)s}Hvt~5oDQIzW{opZwyEa1*cGw|cbTm%k`a!1P0Q{BVv)q|XQMsVI3Z0oSp9(VhSf=i7;wr3o0Ko}d_eGY?2a7mcg z*m2U;S7no7%L7t=(D-(X&NIk;+P`sRB4jf@*~{Psn2O2J==mo;g)ghx5hwAn!_e*r9z{Y+9Q{)da5vQ>|B}Q%!|YK z*W$)x`D?KlW;vVRT|AY3P1Y{&q>>uxaEsAj)tWdc@<4UIxw*{o++lZjM$~e1`N7^4 z^=9e%;ufYo9yjxeJ7zt|(_z%-UR3GYu-VKd4V<^aJImaLgtwe(d0oa#YkxK4J;PsUm!YOb4p9wek!lJm|*J;>M)C zko*a0)=;*5e*oxLmB8=0zF85MOSjjy)e~l@F-0Dh+GqYu35!XK!s+NC+uBc|CJ)~* zgI!`_8f8}5O+Kch_L=f)euCsG>RM&(xka@|72X-M$_~&zEYQuJCm*UEld1)ZqWXv!hRX{+aJbz;zK# zHu9Ds=okN8zJ0P!hOMQll%%a+QDB>Z?g}(XQTWuhkt~LF2)2~IdF@@^=RJsG4`&#X zhCgv~bk7xEc2TUl@iWB}P%4KmUvThelnUVOo$nZySmPoRXgQ8BRf6?E@SyVZs2EA} zw*C#23zuC+T#C}Ya&i|#hN&fn4IQL2iosZ+*tBFcpc!el&30Gp zSZLfKFd7y?(-B3z{``4~{l^ugqQq>0mQ1OXGfLD2Gzf_;34R&+7xEADr%1;o}fWlmTy8eUFQkhCGSS)L3Iz6&zAU5-~FM`<_ ztwq<(PjR0rc9RqyE>HIRbo?>S0RTbHBa6mBpj2V06CU~$LpVzm7=SdKYt0fTh;^fi zgU!1c2uQQXmqB47F+}@8jDbBC05HK6LG-Z3xO(&hD-vIOlwC7MDMZ-*hn3 z6koumwIc}^);WYC+5VkJAv{|Vf14HBPpN=QNsss=f^QjDA|ZA#2=t|L>!1l(0Tvw_h zQ!Zy`f0QQplqvNcz_mOK$3$9^C*AR>kg*EIc`+RI2dY=lR-(6>vI#@{gsK;Il2K)Ew$k7 zKy}vb_pCvHeHXHJi25oz6$B?nsFgeC4&CpBK^sC{tk{pCY#XjPNE5-|7F1d*t{!B{ z@g=T?qi5#hn9Sa*pqiaHTdT8yR^ordW@LgK)VuD_0X0b+rjR;LUA(=VBP%UTw8rIO zGzbFWM@El`w9Q@8l?Hj7*q$ZjFuzhws^HRoocV2u$rcQ2nE^YFG>S#b+{6~1>+(cB zDjXc48ky%EM;CgC2EJGLe;>-OwAj^^TQV5Yomgrahs9g6j48g>Ub*<8^ucw-1|Ga944wLF!6-^N*2Yw>s(*l_f4*(IZ;S1lAP1gL47nPY|Z-~wA z_?HDw>F*N47hSRk;>lY%yxJQW|H@TCqr(oHEM2=T0Pa;x_m}=1=C@a-svGa%{|Zz5 ze>ai*%gun*NdE!O0LwiysIv7iZ-GF5XcmM;tmIga-f!gNuL7&Nk zDTKrZxAp^>4?!gBnKRb_MUemx1`V_3GE}@(ABEpt=HXYP@|u``iDbLK@XVQ)NCvLsh9J(PRkk{D7l zSLVULo8$HA`$VM5zJefimIEjRilj{iX9$`jDkvGOquLJTqvph-DdFws>eX_a5S!Kg z<2$=TJ%DbR5q-^fb;!6p4O9%8e7ef20|$8;MT^|bmv4&Am-`pAjVE_I!81#4+|CnK zeNr+P)b`4}0wx?>5@618DZ&l%?l$B$`OrGt?ovllF%NWZt4Cd`NNbFZlP+v)?$vDv zGFp5=5E^tGmhcaf22shATEiKxzEW4%)V7)q$PvB+5mqR3xxP&LliIMWQ11y$q4I6s z>jTHy^5;F_2uuE{axC7DefVxDWF`7xta9s*^*#j9C#Cas?+Wo36}MQ?{g9>zwvT%?Fql}pV$lwVlQ zobg6*b3jZJUb06(!zP6criUVmCR`A&x;Z03QF`_3w$!{!*2JeeD7AqOSp5&5s*jt2T3)|_Ai@9g_wrAq{(OqC3U^~z?6xG#jMXy=G__PPB28*b+85fjs{M%h zGh-`A$|D9nu4j_?=^k$zLq25W6=?Rc*S@_wKCep2&CFH*sTTShuVcuDMX^DYb`l4TaCZqJlDBK36pdxG`TOg_@f_D$+LoJ5BT*<`R(cW~f186w z##P9{LO(|7puH}APYw3@bX&Bmxm=*?G)bYs)E{Q&VX)hrqtHf+Y~Vz5oHV6%O2d`x zzjnw}V(0UC&AIvZI9%_l-19Mbdw4k4?XCEeuYa>J$v3DQ?!E7$m5N$4#FKGKF{J7J z=l<(eV+>IXIG~}31aJlVj%%xdqJw?WD#!Q+<3j-Z`3qI%qZ=bTF2Oq=@m$s1j}}^l z>t-Pj!o8wb#-}1jpXp=pT_eI;z6GMO?rFyKh*$@!;SNX^s6ub=$A{a)&1(7B`$RPs z?8rG0w(F5V6HsEuiN5+J;ZjzGaaNQMXPq9G8m@kqIP%Qah7y2+Y^ZPfn`JxTiz_PQmuiVNIL2rWDuI1vZc0TbNHhFuehA!~ZOBXD1KyJE1ppvu z=*$`{L9WmsO%D<6TwL*Iufo_Bq@uSMF7ET?yhCgtgUh>W=Dmz9oSOh;m^+>X*-JP_ z(1n<-j;QY)gCBW#B3`90EUU22q{T2r~k3?n9S4kZVC-^na#Qg9du&sYe;kI}!AbB##BW z9A+=6Kvvn7#q>xm?Y9eaFePgAejVza74NDzm;O~ql6<3ehMA1U7d2_>g}dd!Ke?OR zp#U#ewsGA?W?J)sUKz`$xthiHJKPqp0CFJ&BZaeULi^t7LiIX66Ue<##CQa(7 zPaV`EVGrWKbzD6Qk`g1{I>h#h8QnIgU+8FAoLrne-Y&YFztL>oWnNsq#;$kJop2vX z5eq@Hp9olCS!ZF`XoBhgJR7-+3720$BS*j1l?n0;g04J@tPyMsJK=5H+$9*L&bM_S z7wG`cz3(77(E#8+P6`R;qf5>l0q@tt*pHUFHl5Kb`)kpV2mTkuj?PSAFSxV3s8CxWrSZ3>G|AR7ipRm90bn}^?-~>?~WEW?G6i_ zQ*yu8tKyYnFXCy4;DTn*9vA|vCNlc%t^|xwFdz6fWsF)_GSNV#RR@UOEalxYXCrlI zHAo4Tif$sMva~AW=SB4AHlu8aGtsz8RgS&Hg&><~Ex9e(bA#!8Yl~~}t&O=H z0xg3f3)dwOh~qr}YT7b6M>6z1X%xZ(22%p9K>|s%_|>L{i?Xv{X}7M9x78Yw2IVn( zxG*EZsPN_W(|TyvtPbS?e>M5c6rU@az?7AI&}lJKPRPEjT$LNzY{FgvH-S(9DWa3#-0R{ApdP~*kMJugQ|)-)H54DNqxVqlp6x(0J5L7$w!+# zTSz*?tG%{L;ac!ULn4fmJ(HTDll_vPU!m+rAXF5|Fb_$zs6qe%;0+F;Ej%5_2Y|lS z5sE>^LKi8b)!U>$?~hwYU{H}*N7in#C9~pVkx#R&qbj&VYLWk0ngB$*d4-EjY5_Ol zT=TE*PDW;P_#1r|h?Gwq=cT%5+Fut)&=`)D2q76cFAU}@Yl_$lWpK=^D|vN(etOFv zJA#-qF;+vWXCt~AXBC1Y-ZmKeBD7N3YfrHzfoM6QC>@=uIFeNf02o10Y)>ixMYSu* z61ZtSCFcfV;?k{u@69oxSPnmPT}dQcWOAdw=S2fWwO5i0q|4n_#4COesahFJ-3@4D zaftNA`?sv1q?(3|W^I3j2>W3Y(X@TgxB)h8@!GY`8>2wnW0fG$&)j>S3&p+K^HuNx8>c>iRgVu z@!5RbSvUL49vtseCEHcxUL}*q6fW5ol2C9Jy;Z3 zY%URZV|@1=;f~+KRnL>o=X5HE&ht7~NI96E9f~i;eDs>ov3vA-bwRwuv5ceJzk_2I z5mWXB`DFzEePld9ni3*u^LYaaO5Y~3*2O3;K^-1F)8&XBdbT%?O3VQ5 zj0AZ?h>yw&d*ujmdI&!sxb#T@E`7j(OP?sUeXq0kz{1(KK42HQ`Q3{tyHbymw;LMn zi+GjD$*|-rRuSrb!c$YxGw<<1iMh&6@l&vJU6FQMMN7iz1}D@kDMQN;L|=dk-b3mN zDY!EFn)?kZQZaZuvKn7cO^|k2!Xh(zfNn=96pAY(uORVx3*?$?I(S7c_L_-%GRY&* z1j1Gb-Gzg4W8z2~^Mf=Jy+W`-hc@4>u85)Sh&=?}(2jsNv@(}(L~L?W#V&6cvdRdC zioYIe1BM z$LGl&3QA7d&zv614%ul;_JxnfHS2@c;L?_ zIPO@2*R+Q%Rk)goP6)U`EQ7KK)U_nVPp8kc+=*ID5~PhAXfll7Nj%(lvh&s_$yLld zgJdd+w$=|I#qtWv6ZlLwS;T|TjXnI@crS@708BpYJ1_7MlfNH@N*fhn6xS`V}ZU zUaf(5z8Vh&{FRQc2Ay4A0#OK*#>2=u+4wspVr_SEHF0i+`d>MTkY69r=tYnXgd4XKM z_{i|sdad+o>(8`=i5gw!c@Eb93`C`WrolZiC?!|tF?`aXrR4G$Zknz3A#x#2z7@$bNLb(5B%+}Yy2^MFXX zB3m=VE`{PDDVb`nxYT(=VRTzvAMSL&C7r;~MjPnvLH~{cPxBhpdg|bHKEEZySx~hH z=8Q#!Eg{+b%dp)f!}a1okj*3aRkPDfYsAPt8Y`%sRb{sxh_&O~Ya0yMVVjl+jevCs z)Zv4KOyopZg!2wy_BBFLKPac<@QcCO^oAu5XsIBN7;NPk$qCX$L2L9Cz*(po-a>A2 zcygU0dgb=*;RyOT=Ck|WAm*^|oPquD!%>kBev_X_HLdQmvPxhP`HVQj&r|||pRv-4 zJh1xT4kBLbuRhkL-Mnle&g-lq2TlXFOgnt%Hb!sWDAL|}Cp?IeJrMHGUD9*%mXY{x zJo1@&gB#s3t+pzmnkcD@U5@Px=5;F_`{T)rr+~qOrI~?Mm*>$rg0`YH45n~XyHNL3 z?}5mV>4n!%*@b7CbXHV0HaADYgJhgwKH7bJ*jdGMkC6Gl!MiQp$jvKu7h!dj!AkZg zA2kTuAVa$hvifT|0;Z80v0mQ+&Q8?))`&hsi$l1t^{_`I%M=TmnwO)OB#Yv&qWOK* zKd;dIZd~(Algu#6xOk7Cw^g%zk$pdQ_a;AtvoFq9lLeT1;d)h`!kdLzr2eE0ItA5- zsQT_W#-I^!D^nDX&e|Y24NWCag$<>Uiju=X#%%M0v6>UKjA+!L!gQ9{O&}&FpN*H~ z$U`#uV9CZ4F*P_M=0Nv^_VuB+>U;r)4G#S2RQe5eofB8>XD29p*6Z4+0WFCkia%Mz zf`(r4$?DUI5E%)geP&W2n@jL?Mj-vHQz~Fsi}>PZ8C3WP4CmLf#eneO(;mJke~8Fk z=sT#XjF{JHEun@m;wCqjvF9*rzuoEg$E*H970Afu``ijpj2dCGa5NvkpiRmpU=g{2 zN=h|UvD(Y=9(!Gs$uVhRFV3H0C9J@oy{4~G*;VXDh|@dJroTX~vD2VrbwtH`iIO5F z=0BrmpaMx)u)}UiLK7+`Jy0-5skVVTPq5>_Vy(Bb!dWbJ7M0<6{dp2a;DzGTJCGP) zCul#&Q<$yjAdRBg;Cvv)5lySZ&wHDnqL^roHPNfc`pqLB7&xfVA`;loh1Thvnj4j6 zzZZ|Z2)1;^B{wtXQ>3~TFO8EcdlboTP%oQ7Rlvy6v?K;7)GKuKM5#XpS>~|PcsP5j zN?fEU@^@_3$UG=)ZAf1Jbq07dT*Qs(#UdD`kSil>dF#F;V6oE8#JCU6tqss2leSOC z*Nlf*svwOQxnbV+Mq=fv;`#vr^CYq?)`!&_-&%`04Jt?%XH714-T4*cEd;T@ZU|rc zJ#I6sO#A=M!I1ukLY5p9YlB`-GiV9WF%}8mTFx(xe@lQIFephN21V45rlefT)vO=g z!X;x*1O^VC3MNYBu6&P%T2)1+q44`0UFgCF>{Vj>)2lQpdc$P$r&lR4oIM;e=CsWS zfJ%`dxuv25Pf|1l^v8VqH1dw(J5GRkgUm_fn>!K_6J``!Y^l;}=A`J7(zQ^iRbPmu zT0>9-XER~9VEKB;b-p>`3+XvVl8u1tz>hctjp2hx zNAE};3%+Bp{3ilt4*Ua5(^PVe0qh}V2H{%mxN^MiQ5UdOiSN($=_l`OXpqnkNloeJU--jnX`jf1$BvqgDzQ3BOS!Qk3L#aGcl8SEwxWfbzp_ zc1n9occ>NO@1^;v{g8)?-{Ks&PyGjgbsb7iuCXeZbT8NmB_CwrV{uH_oC!0EDFR?O zi>`&;T=eD>JF)B&e!Liw0}@|Szk2scGt2%%l;@gYZyAt>lQN0XTU=*djRoGvgEn#)2*Q4(mT*gKkROM2QY)SV~EcY-G$v#RKW0R(uIj#BTuF43&#G_ zse~1_{cF6-l&&=%%fS>%9vC+$zA=QfIT^E#x?t6G1Bm0f8s6vwTZr-eh9?^{aS6E9 z^Fa^R2MuuL5t%_?>eDJ80}l~+y>1uqec;2MxWV5tbKO2Ys6Lp|JVG&fy`-E^l%wks zK30exPIsHA{KcM9(i1V&6}48O_tYc*4$WMlWy=-0`W)$#0PQjV=o9!j_W?#Qv^)7< z0kA*r%zyvP{9gbDELQq!m#_g*m^?Ate}});;wGfQSJO(|Xsn zi40DhQg_l6)VUw}A$w#})jcJ=SNi0Lc8rf+YJguTs2j1{Yb9xJ(No|pa*hTzWL~Fu z^E%okE@%~TRYqNnl}O?|F;%LS{+GVol_Ei>gBWI?^qj&(G)?@L^I8$xZBmcp0A?M|8#jn z)>TQeprk;Zk1!gHVkx9W=3nhT0Q>T@ntL{9oa5aDBsni34;2DZiKN0*lFL{{lR-4T zm(CLDoC%5_=uCaddcpdyK8rut=0BkvuD>o6*IyTk>#qyN_1A^s`s+e*{dJ+Z{<>9M ze-RMZUj)SU*RA6IJCFPCJnp~qxc|=M{yUHR?>z3m^SJ-cxo%>T{&jJ7Um)YN| zi;I<&>wiU46S~^5^vw=FoBAwMP-{DHVAx=Lf}ggCV+h7-3W$;0oqlV;{Dug-jqA?& zv2$*$Fl9ZJIa9$

UgFi>W!$7Dumk8kqm#Q+fQ6Fef9;4duq=^X)l@s!^1w`!~G* znD0OS7P7q|(BHax=;rgjt-x}5T>apG`#nsx4r6|bnVKN~l-sBmpu8N~AFH3;^)#oj z`SxBSK-8cO_Q6Ex^ZI&6)cxgW7xg~>+~yY=jPAFo{@8BM=XVLxszCiZ;3Fduq{vYc zchAS0!g|fj=oK-)O&Hh6o1YYjHIqKIwSEq;&k*C0EZimbT>PLFjk>d?*!JD-6c6Cs zmHi2_VxFrYd`9XZC2fJ)6^;CI$q?<-x;;Y3JsVtAExiSFc40AkZc07b3`j&d?>Bdw zHy8C|Kd14g&KJy{mqdLY1oH&UCycyDq=}-mI`%&Z-rs2(ueZXM8RIwXjW)3B-Q^a( zb?x5H5giLOYV0c;1prz~!F2yLTOC5<)wvK_`#!#h`hILX*F1^(W<%p4G{7f)oQIa! zb(JSkS%zHHgtzb^O7?7)uKZCku6z}I6W(=*-& z1E2A4lDmP{P2Y=sr$CxxntP+9N;r>jjX;AVh2i>1+}C+3h@93ic&Mus#{Qh>UpihEEFmiBQU83%v(--D^e+6vGtvG8eB|P4;_Ls zw4OlR6O+DCYOYoynuO)3y!--h@GRY6e}$?(zg{}*yH6@dfzIxC`!)fd!~VavW&kDC z&RE6IVc@i7<^ltTX(7Kf<@OQYT3L;3N?Cto(5vAb#M{8x;*WHfKNEXp)o-(Pip?H< zozH8&L zO$u-mS*@D|sF65*>^4x+eJk|vY@y6I&53}NK#8@4kol_o7?)#MX|+N;;+{&V-4L$U zz6B6au@fWJw_jcU@=!4L?1CW3gGhIu=9zm5ua3r6As%ADYkLc9GM+o|#Zq1u@Tf$w>vi#R<4O)mWU=jx7f6aQmSjW&)H-s+CagJj zTexF|=Hh5&7U1-8PA1?p}54um90-KsRu zMZ!WdgmYPr!d_~@(;z{Ho{KQRt_xA%jJV9IQ7PeQgd@w$Vh})}K=Ori(f))b%7TvQ zDP^#|oJ~SYHq0jMYJ%qbRYtvh9iG_S>4^v`F@W)-n1Qk@m&agtCyJ4bjM0)_+YDDy zJUHrc6%8+MPcn&qM;ymeQEYDK4)$a|f5l2{O<6`_-4EIWdi{(eg5Px)?i}yP;bf|3 z)LMJ0p3@;E7t=luY7qAPe76mn|M?cMUGO03U~ieR`H~4nK1byJ`n)_~ls(kl?sIU` z7K44Og7_Y7?2AjzcK={Kf--K}NOYQs=(N|1QkJ%&P6Qg|}Kq`*rMd0puL&(U8QL&B_9= zr>`fHfs}EQ=?kRLN0XFCgeuk-_VV?qw@*CyfTHx(hhfh#oRDzYQVskdb!6VK1B$5n;Xwm z+l&!}KqD+WVb)mf{UOFPWm{9o7mrOt+)pq2dpMZ>`cr4pl?Mev4@FYxzOI|33y^E6 zb8oG6d*6DS% zw45F38~lP)n_%{L3?PI6yd#oQ!#3u#m!q*g?WmXnvbk>!6USEGk=J{}&zN&C?H!|g z63!9Uc3&`gsqTGc!vqr+7_1%zh%UW9=cRwBz3(wQv%cFVzng^&9by>)vdu zBS1ttsrhPMC6Y8EFF%kp-^X1iEcU%aj_Zz)8mt8H)X5|XJ9;P4NvcX9)y^l&pg=z) zWF~+s}OR^6g)b%UhWx^ZHlsho1p)Py0?stTx+*=!_3Ug=`b@hb*R(fbeNf$nVFfHnVFfHlMX|N=~l0A?X7#R z&c4$5c}lX%uCi=Pw!$M7?Hkma-G=hwgnt0?kR&>sq86#y2mN~>m2f~nalRO>M( znvF9-ruJiCgEt8G%vToM$CMy8X`?|WNmzzW*mY|8Qfzkc+qs+;?CUOx@BrnF_wCAA=~A^s!bE)SkAu6*!}(e*MUuXRHSK5q8u z?UDuZJcBz>luC0=;Qrl*FwbDdaT{uH6WVwul};#<9}@#`BAetQmYCMwISDb` zco9b`NH3vVoWh8OLKPd1I7Igq3QT)yD@~Hm1^ek{#Qc1PPEWZhJ`986etQO+dLZT% zWpt0+7|RC`&s6A@xcy)U|8~V?bE8qV1T=)ITVYrB5;4M*W0RNXX@hvLa!(NW?3%}K zq9)YjY-@iX*gN40YSD9Zcv(3hW^>^o;KEdesJq)c&ByK~OwK$D7 zxg%u)pp*tC%q(g6=Dks2g^sj;&wj{&xvvLQn26^e0%`<#t9y?eVln2AxzQ7Y{IO#@ zXEb$7m#m*W+b@ea2#H&Fw)TnpMy7w7bj~fxfiLi@*>kHj*MyT!*zh_f9F4ps1d3a^ z!)j{!GmVpQsuyY}IP4TWOg><(mT3zr$;R&o9UdOZ8T<3o>Bhd%F6Kh)B zBXx{@v5g?pTvwRPz7t>$*JU}i#zY?A80#hjb(>p68wR_;NUtIyRQT;2cw$Dsq&cOa z$!pGw7{!I$i4+zBl+9ku0W&>6cFMVPW##LMDw>8Ox5$LOy$OjVCbS7 zb{Bh_y|!?u_k*h~E)>0rm7K8z>DrfHx!GFFE&=ykt9Y5LSf`bHWTk)X!)u5HrHVSE z;^~bYj?{z6KH<=ZOKb)6_d`4{XvuA-K<61Ew_E8qv9ieNlTxikbiU> zOCAwNXu+neE8&o&U8Jie;W+#w1B^o8#A%tCG2K0Y7bL1S7 z#=PTcVew%?eDbyw1lK5dn8P~XXUy`4om)Z<4nH9%^>Db}g2tjA-l`<+tmmZA4k%OG zyDiBMT^YK^b!@3TwI~Zp%{Z3d2nmKXs}{5;pPm-+B_w~uAFH+zth~5)S9e!Dm?iBW zxLs^$Ii|$76W<1vOvF9=2WAh)+2Pnlr~Ep|8+#JTOdN=J5ED`G^fUDz#Pp?{JPT|+ z4`cAvKjVt2^`f?<=mx@5y8PUJ9dA(!r+he^2|69bURd4?C%07!=Izg23 zWJ0XFU#E&D$}k?*q@a-UpZl@TA7fO+Q$0Qh&`^IMYR|C0ILO@D* zhK4nDmpt4Ujb(#f<;?djC~rRK0?}&UTXS6AlW5^Ril)Y=2iDr=Kp@K+EO4t`TSpQL zV|Xc!Ue>YQKq>LnID$I(n7G$A-C3{aJ)vPpsONsMaf!0zZ-*8VezwE;rE3{Dnqe*|uQqZMNO zSax}+Eb%%4skq~4_0x40AQG^e*%}2u+p#b*%n0&K+8mkaDy{yIrO+P_rH4P}ape)E zgcfMYyJDgia*D!ig!qSj2=yH{1`(67ja9HY*H!yw5%|L>TRUR~q3mtj5wW`h>K<*9 zFj0Obk~&x(@;gw^(y}C?I8MVWns`p@8Z@cecGEa7SdUQye3O}9q5SApdB!=t;XTo8 zIf^6TJ;Ucqdxux(L2)g2N=Tv447lAh>mg>;!5e&hi#Kjw3^eozBmA5 z>~kZboWC*7ev&cBkzPDAqcJv%^g$KdeFxD)H0wutyfkG-y65x3Xr45n8Ja^z9BU>+ z(4G5IXwgjXSyP#lw-F}Zz}PQfuwmKeiAIBrVSnjVupmzQJcTrbgoHTPF3H1xZlN>y z)y+hPJsh&_u-rT}oj$XxRr4cpI|IS0`nL3;9ZnQWH!`m)mn2^^tH{fx{JvAVCn7;2 zvU97{#DS(hdP9eH5nnl}So96;EN-FBsedcNs_TZrUL&h5lfseVWZ~}d)|rXvR=hf* z31uhTUqDV#i@8Gp)TDX-ahr7EE&Ec?c3Ubba=~-J4bn9|5d?w2O{EUsB;$K%uF$4l zKf<6Fk46ZZoPr7P6iaLksD}aL(@-i22tolQlsuJTkD!)N=X~JPH0e-Zsg<=Z5A_g? zfTNPMxaEv`H&1)7+67L(-n_^3z1L-)jrq{oWKNs-&yLw0BKQR=NH@ibdbm**xpC)okfx$3nfb@ zIj=qr+gs3{TQoUz_d^RIH*dy@O0u*+>0yX#E02-c2th3Bn# z*f%AR)f>@F*)4|;&8#NQ+jRXe(86 zyVnhHV!V4P?_!4_q9w9jQrA0Ao>ePuH!)Wp6-t0-Z#_Io5Qld+J7iuVnPr<&BNp5y z(3-JUk4Fqm!U|SeL{S4+8V1!TC_&NGgMS|>(-EsQ#&kl1=ZWAIS@(CK5e*SDt@0=G zTp*6)msHM-adV7iT!HiTRl1bMhsaxczrr;|Lj3IcbM z&JP+Kp^saZwXTJbVrnZ?{d6<=>mgw^*kwCbv#09dC(?!nZ^n!fwGOWwSq|i@8D8Zv zIuyR729mc&xW=uD+WGIt(y4rVF()2%-aI6lpw{3+O2EZIZBl6Ju7PBl?YBv}iVMmm z$_p9mO32%vtzfAM49NvX><85gBRr3E^#P$DAhzMToo4Tf^jpEcxZ@%LHb(PsgkDy- zVPNVzN$5Ku7U1BVzQXBNscR85Jr~@m)PC}+zFMjGoSk9CLITY#<0GIA#{7`ZI6bwO_*nd7pP zSjn+EhSYRNFhaULF)MCtseQwI67niURcaY5$<>zn=CtodHk#AHEA3 zvq4Ltor#qw2&_JGx$Fq>UU!UZ_1$rf6XqmtlxdqewVEg`C?lEh;61{v%{XU%d5 zZZeH0A=vhwBoX1zuMY&DjGOzXUEEE*Do&v`#GI3&@3dfYc`UKbHeFTT*taB&)d-=p zF0H+HXCvee`MHd5)Q0IS8}3W#OMlofg@haqDd%pzPKf| zpY=}*N&oWVx0mSk35SutwnJ(NOE!eIAW^M?N(nkUFBgpvb2 zbMS2|H`T)(*HSl|Uy|!Jff#!_v=7o1Y#x*k4D}f3w{4&vdfB`H;n{O4@m%$b2?Yc<0#~3hO@U1wybzCQBF`A0uodlBO=2I+_ zc*aCAmU3)9Br^Jhuao~B8G$SDcI-RmtiYbwF^-<232Bvc&eMclFR~J5Qh~KqVL{y< z0@U&Fz*8c00bN3L16=E6UEH$f!3Jtw3{*&>XlU^JrDhbKj({iL0`|5p7DkLw&)oVx zz#szqV}1QvPjxV0c=YsIDztUQVFSB?+snq|sHhCi!ZAnf+{{}?ts`-k=N>Zln2`$6 zLWgdbHs{uLSpu7(@uz$HxLo5W+9k#%ssdHaa7U}g#Rh6ZQ?~gZg~2ZCR?`*n8P(U1 z-0%E+c#iS(#s>>m+PD0=#+y<r zZDo%!yDe+doD^0i4JYed*kXok4rVR*GUCTBX!Fs+n z^#CE@?=W>jz&zK<-&MnS|Nee*`uF!dJ4CCwYAoNs>tC2vh!v^6^TE^Yh=0dR84KyE zl;e+MVD6M0+*xj=ToJc`rp}^06L>#T;|vKIY`>=M#Euqx$nLx$91 zj2XFmM>U(PAbFZUUDp;C)?jQae{SY&Jico~8mlnw=4n>OrfTpcq;2tSv?%AOfKzJJ zoPW*yIVw56;VxpYPqC(~Oe(s}KCHYbj|A~Xk@$sCy6Z4Fo}UU_{xK6_zSn-Oyo_Ar z6Vk3a5|kKDZhvJz$*~&2G{uvlE!M)ps$*F?o2F>cCX?_c=%uLmRp~imyJ;6+S%KGf zoSdVskSjUqv&s#C>8pc`1b0(MTIN6r>zN*O$W2k1`;l< zc)0Pqxh#9NQa&*PMuk>tb&}8LCO70WrFWaW_&aHTBbPvK7S|?PS;1bw7ET`L^_aui(x-Cd0KkrQEIMp zaucFs&BER)J%Pm(^Zgl$^_18w@S2}2#(p`x@u<7Y|9eJ+(#3|`(D zoW1cV&+pD5Ye0aqP-!zV!P&jQho}D@+pE;@DK)iIwp? z&%?F!OBniZtzAs*LoR^0&_7CzMk>r5=T7JuN+@-Ekow3mO3LUNsmipmO(w)9b<`{^76!FON_cCS&54qEw(6M#CBWfGQ|4?V`Ky5fgLK0l4#V(>Gqc5psZ7k|6&&{BO1wr9PTP`Nk zvJ~HezbAfdEn!}!5j{7jFQKG&HWeMav9!c>ebZ_#apuGZR7B=n$V>E^WKlmAP4;Q) zG?cYDv0kxBZ`^yxiC&Mz>?gZd%t%nt9N%HT6)1kRespL8As=d~ECOmXX zeu{4}7w+?*tDG1-O+J4#)=<=e7ns+PET)w6;aVFB#!Q~5*gJmyG;hu7?n&1uXDE1R z=uE{6A5hi-7%%FN_o2ot%2twcipXk$Y%q^ckk)C(Iyu!9Z=sHo5+`)TsK;o>w(9nz zB@CXEOjSFF%L^sb-gL6l;+3)4rY_^D zf;B4F!_H9e`NHpH>sF*8LZ~S6lhWh&rG@c&L=|=On_RI)65Fb*P+qLuBf{^t#q7qa z+Me*Am9UIZPwCsaoR7#Aeq4&tNy&LFNtb`-FOL-Wma<=Y(GMex+GJThh9n^2+95gZS_ zkH?i`75Hc7^LMriFibkvPM;1(Qr-EqPPQ(1Pko&3krj#MFVG7Q!~d;|*!%)`!7om7biQw(!C>g5G=h+YdWl}(WrUYb5c;3E~C)v8aS)aJ>Ke> zWL5&w^x)yfhAFd;cURhW76OPvF;9fyF+Nx0`_5~XEvj#yN6HHqXEhP~El&51y3a?C zPy27$>K|HH&PT@D=$alc6&`7HEvom-y6jGMtCpBSXPLm8yL=FPHwC=9wmj`9pO>cOZl?mQ9w;#8;2i`{Q+0W-Wuu^5&X{04hf%KNfv2K9z4bxQsI}|E#jNsGB!NA z;2WCo8;Qvu7}*Ib^k7Zb5G*$(%y6(tFxU0PL>$Ov8yblCm+>Lj;y3lS6F3<-LaW$* z%L6AI7K=n5RwLDoA7|SS1D?7wm>KmJxWAy#m%AN=NeDqiD^Mx$98TVC;|O1L8Hr{n zQf3*UewQ-jyJoO%pyX8^j7K^xB{EdJ)K^A~q`Z`;H8D!gy88AZcoAXBBWun~@^2s^ z>xh}B5a%EwTv~czRZQFEPV=DPJx;kRW46S^Fc@j;s>2K}E*!g2r*g@!586I&xeW9b zK=Q?ls>EQpH9vz!CX(^Yaw zqHL&=2@ACIe{29OfgN>9*8hzGjrp&c>wh(%aWVdD^!kS|4={2u{cH644?Y{P{IAiA z=|9FXE~bBtUQGWQy_o(rdNKWD*#fNp&-VUL4PVUv?DhX5!`D9t{6DwC{~Es7+1Qx> z7sD4IHkPy{?)nwooqdiK-U z(erux)br)Y`pbSq0gxvNpbumdG`<4mjHOb279mQXmxOe_C%J2Uovqb)6-_M+_}~kC z?A>fp=1PGc^%02msg#p3t(!axOIUSB;-IVDDw#CBs`A&g%%4|nVjwPSygVQfUg8^A zc_qnL=xWcuswucI(QFS4II*(3wh}jJX1bhjj-GF>#+JepR6BUX4wRhabIV9yeHd!P z4aaM||G94wcz-V`a0UPp^cSM;1D0`yzESn!hk6Gp_`e$X`3=$Bz$WJGfg0KD6~qc1 z)d&oX+_RM2<*|qDohUuM2%#D<9PtD$>`Z>FZtH$Woa<{?x8Fd0`Wp3NdD88vIWQUy zu@l6JrJy-*ohjnma{<_=TlV;&>ECR@qrc@lr`b`lQr@d%*SuFaD(zS=A5Xd>!JjW+ zE+jUxd=LCRke1)4^gA{+&pw{q!pB`YSOY0ZdkPtCW4+9M${ z!4`8ijd4+SZBuyb&M&|=G@kQjZ&va-kab{0A9qYLmlxMNHV9!PyB|hSoI>?B*MKhS9N&bH zhD^eNp(pz^C>m1#7o&gQ=XbJRD+MAECb63X!G@LDyb>%(;mjD1fGT2EBr-UX$0-E? z@23ylo}MN@2(lIbL!4OK%jbmgkz6v1WN&s=)gc_vI!9pxUJD%l>u}4ANk-jl zayK80`fj0H!k&Uh$?k`7su({7Fg$d< zbRR(fSYnXYtBdE|rbJ^au6b%b!GGR?6kQxZ?A&p_3No*yO#89_IDO8Qxe>C(-&1I) zTN7hNu%4ZDwZ$=eGC@|ZRj~T}aU=T{l?I#;9}i-nY+{^}fT}p0zEGL?1MZ{DAOlLLGjfv3OXh8@?N={^IHG2WU)DqX0`!bKGr4{Osqup7&)tDKH{Styl+*15NoQj5cT!$zX8cbGrVVdoP!L}AnZyH$Sfn_iSY-)C zK>xVF23@7oIJYkS5bZ=kxR4XOehoEDRLAA<260C|gt|fRMM9UbAwEX44NyA5UWdTT zZH7Dpp&xCFz7g-lQe-rb+vuJl4|98g7$()N>4=G};S3vQ`EvXp_Z%m#MOTXwo4cqQmh#!zrcP!R?>%4_*dNjKE> zG;FJY)8>b`iVa=&VxknEA_<0rwK(Tgffo`B5mjPrQSsU-pEm0cE@((PAVrl}$#tqd z3i0oWAmGq!pBOOJb!Mr)8?#woKne-;QZ;yU$Hl)udJwvx%(>A>?7t(y!XO3nvj$=T z-j!{P;t&iNB?0SHcEI0@a^})MSwN|I5_{8+-DY)@q$XiJ-tzyL)~0r;5bta2?mrmn zze>Rh7LpeKcEt<_5djT->)6148H3qu10jabCQl5C< zPU#B$<-XtxOE+iwSQcuP;)kloa|-3}*wr{T6^Ba|7HAfKz&u@nxMdaemU#cX>( zn}Fl=NAl&tVDH!OMY>3>op$)^T8u}l zZ(aL@ObL(5X=6A!jOg~o6r_6B1;9(-)m+dc=sp}TsRptr)&(JD##B_5Z9)2EbK4Y- zuHW_3)cX72Z@D9}m{N^H!2az3PBs1T%nn9**;~il>eKS927${(<*9Z7Z3oo#VgxdH z2?oG^=8ynrJFauuq);IGym}VppvK_>s-UX6gwXB~f69&bV%a77VD^m}Zz6Js_Q>E= zwLArAw1SBZ%u)b>s)Y6g%G?s}%3&RaYTJUlE4`Al1^hYS4hWXQ=dR$ znjTe z0k<$xh?AZ1Pb*bKtnWLOi~K8LD& zTq@OM3`v6ykQ;D4>tdDuhL30(8q^gdWlWFH-qJssj;uTGYipWR-|JB8N6_Mxc|_uDO2QvpLS!cdpnBZ2v%0Ns zVxBuf+z#7@#skSDhqTv=hs7}(D!7?BL6%3f z-_BXI{cG&cH(uNq2YN#D`+UJ2WOX{Zta~JqBGE43y5O^JBJ`*S}b(fN06>4t!*4<8f-7`%<+4Cwg)=1I+*=!&oMqn!syY=~0og1AG}F@Ucr{FB zaWfq#7r!Fc?>^K{$bnh#HDqepI^3tMb?#w4@WYxCW4v&_=@zdj+sS3Du=l>g(NCGx z+~vae8A+ZyMVrkA`|2Pwvs4{Ty0WOx^wOY!em4yWgtY=(1?)$*+R^0JO1NayO1L+y zj?7XcjHhU5UHYag0??Q1M14xQ5Uwm>`kmIy$m+#N_;dPh0f?zCp-F)}Fk zGTOB7>*{h6tQf}Gqphsp6!s>LxbheJ$12va*Q6^Zym*k7n{Fm#9Dt<>8s^tNjAi^9 zh?|p>WT(bhPt3Csxihj)+edV)!|G5w$WG3MX(z(3JM>6U{nqD=63%R%e9KCv{_^Y;!^@PMvS^=jopl_H z&M?8?snb#7s8VHryRS-(q@9BOQ-naOn06cO`1W%25Ca9l$bBPZrF>N@*q7;C(w%x! zt}baru?~a8;L9q{>mp`$upS3X*TLzvrY|OoqYq{A$3w>mWyiCQwZa`qRXjfq-XeSBx|&U2b1&4^ug7wc2AB0+3wuItt~%mPFC5W#Q(!Gzq15B^|`-o?kGiSEd#18F(A)d-ST2>OLj7&O9mjb}6SH zq_f?3u!0+W>c3^D%4lbxOdjEGlslj&Uu5oix;%>?fa3FK9FW)@e8V3_X5A!yzQ1qs z1eF1plVta1&s*G~f3H9osgV+Bq)R8l3QkMr1cM! z7DKubLMH2^^~X}A^6yok@h_C10UC?kfoo8``wzq?4% z^JH}s59qqS0x$Rc1HIgLWm6vN$&_Y(Z4qA!OX}=FIct%#Xf^6%R{O_I$UiKqcO749 zHF|I!q68mR1h%LzMtB8VjbaXuP1a50WD?h#1e2>LI}Vb8{fe>#msD>YQ=^@MM}XfUaAOR6I#TUD8f$x2@UC#u zYa*84piEjm7Bf7~>~*wvn(l@P+vqFWC(?4p&0Ex79(bTboR%AqwwK;OR)Vl%I-d0` zdAQn&m|9%Gs-58=fZ-As5!U8h&q=PO>l@H7Df^n%F4Y4gUC+NM;EkrDqFbe!<$*BZ zCt9^=WDTBa5~S6hSl9h}T)LD?9*|2tL1$~~_a7x?v=8dpDs1AXrr77})o(tc*78Bd zXIMKXCt34uUcvp5+3?V^0thgEYu z^zuJl&G1bzf6gU#bKaH)l-9=5#Q6r8wunpt@^Di~wmX7(9J-)R(2yrK?mHj^C5IDt zfI8{8*>qvq2|n(;$_7HQqGyls5XEAJqK1ixHwM;~aN?S@GV0-#)B7R4dqq#B z_Vqyzg$Ap3l%T19VRG5u*C&YOjW>R}5CPaeghIgb`fF{pGDOshT;KU7UCW{FM=9bhq92tY z2_z%R5vH(c(Ihu|2w|0Pr#$`_P|g>B>w!<~mh0Qec+bk8*B78cfCU?IZg-|srwRSg805#qZK#jj8 zVf0LeL@PxyKRp-BW^R0)WHS#x4-vvhpgvD(5?tLwmWh!gdMH`os7C7(;l3e-d&<3x z%^|TV3+*x4H+`dC`i9^?!*iSl3c0*`f;LUS!fx{112IN_A|4mdnItwlYrdiZT7Eic zTJRree4^dYC`udnY11+;nVns}q9(XfiuM3di&?r*7&ah$h{C_r_d zL+kJ>H%*|n)uX`h-@f;o^`ZW3hHjMUUeX$ktgbSuDpf5b&$P4Lg}s+i;H4(G&ed-n zm_vn;rzQz+?5kg74QGUqi90M^Mv+FjiAJSm7tWOvDO``|x|MX)A_VSWK0y)X4}jQS<=Y}bF406iR1RQeh=u9> zWo3NELjYJAC`5f&-86Et)j|!%NqwPwtVsY?#&5wSDWdiCB#4{}3?+LYBb<Sv>f|Zn?YI$02*%vfW{jNp3O#>@|fz}yr%bm2`;D~lbfg}fuM3X z8XY>yv`x!a%`fUDa1&!|q_YFWb{K|lC1pa6o*6iU3oT`PI11uL4YB}e{4OfZ*8d+lzl)=4tyit|xSkMX+B_)ZsS*rxg4(^Ja#hT7%?TDeS37ZI3$oFE#TFGFD zr9J)fYpi2cS36|HBJJY;;l>BdyPw}7x>`q}u*vH}w|*xCZ3B~)49^p*5E3I=%X=t+ z32cyNjF}`$u?S&d2jg8q(di5JVtGqe7z^TkZ&JB2X~p2CKdh>}v8r61>S#BiwkdLu zQ2QzDZ$8r0iB2{$VuNvi)rtbii!0f}ayUf<$cV9p5^lWR~e9$}Rak+(!zm(g*glz~0 z&0?73fE^_KBIK?d7ysWWWq&aT|FgXFACaAl<-as`HWrru-@N5bK;H6#AQB*N*&mR% z+|dB|bl9WG-{#p8H3Go#v4c^V)f9Ph;2(eFYZNu1N^-xihZq`D22Q>|_OM9BqLms7 z5hwht;1#bc71pnlS9f(49On+%cQwLxuBok$bCLgUYIhC3El0 z#9`C@u(qipve4A=u+Z`Alw&69WfRV2LrHB5^S*uN@@@0UZK<(1Vd%-uPSxqMmcIO# z!MLhgdLm5uS$Qq62#pApJ&7)N>6uCho=8}8Wn1*|lZPD7p_8_Xn*o1SgnMgxk4C4V zq`Xc0Qi7(;+h&NuQM7nniqL-S`nWH#p2Q*_Ej!D!?p(i-H@B0Yq{-^8zT-&&4p zY44iNu1D-QnsJRACiamEim3<-4G?}sWVynK2c$7+-f37F<8YJLW6R6Nk`==Z*~vz=tturYNPv&&h{C8zRwRK zM>H%CnLa^j^-Dn*vO!=6N-@pOtoiks*Jc}Dy^fx+@emmFnuYrf*t+&bbsDYO0AHRhg^JEq;Z>MC#^czd~aG+2d44)Hd zeZlBs#$IG~XGBWW+8vFH>nFXmgOHtKJKaRF&}=`^C?T~Zp*s}6(kCK7p7pF(H~imS zbbqDR|BpQTk7NswW&b0P0>1y{Z!rHW%QF8f%QF8f%QF8f%QF8f%QF8f%QF8f^RoQQ z^I-W`=4JVJdo2HK@Bdh~{b%q0H_5ht5BPt+um6>8**KWk|KGCh5+Gw4uchv9#!(H#QLgGCTkHD( zl3UeOV&vm+Wj}cK#GZmK-Y24K?RbfyFC?y(3NQ>cPu0S0j*oz++k67|=Z7wBtJe=@ zM)5XRM>{2&XRPQiPmR4<6OOdRd}o9669$B9U&Koh{~!N?;nl7Y+s9FB+Y%keC8{3K zGRFn4K0*dkcD`;V0Ce~R#SZG-99PdT&*yVB>9qtUoj%0(gWQYh?_u91p3{EKfFCQF zNz8!056%;~Yi08>R?lwib^N&)yneaM%+6}9q7?|7V98F%eIXieewXyd6QEqL_dM%t zm!QwV{t`LqYH}%37*sxHH%p9aX4&SOkVfZ+$W++$DP9|Ync9iI_G#fXUsli<()$*T zgYezU?i2|ThRK#5q)gb>jXjiCvYIh%5_P30_beBN0(u1$_Ij|D;3uQ%uWa$`WHc!n zc&AT0_SqBuTDdxc45Eax56}IR=%A^7t8qp2OS?jC$O;-I)#3RR4sI{<#I&Oe`E$_2 zg~I}t@0FlrtdMaX33}$sdoj?NH-Xc7xU*!97mc}oh+8nUAMA|DX6e!;j#uYTyYg1! zsGNzXtgR3{*a;3WyYkvF%HhP4r{KBJhp`P#CY>&al0_GhY`J(iZ03Y& zhZY2>sLGr-Wt`vl8($m7*&O~8*3DsCnG^W6w)@o4(hFOWYltzzB@QV+?hadK0G0cN z@7V{30!LhO(1WM|xifovP-`RPINS?xjr1dW7d7$>^Vu=8=uaShDfmR*qN z-iL_gjpieChf|oALReOE@*q)RV|MS@f#0tj>vj`s;oZsc*}0DUkgKNd-B=MbZT6tZ zT_pgc$^6qphOe73(e5LzJ;V)vdCgWcMz%F;h%VA>304!lxx{jDqam5t2IW%} z7txN@&?*K(88TIedeQ_gSUAfv8pRv9HHRosqJn(WcL{RlJCy4!O!|W%%PL5q4RAA! zY=wD)5-y4ZvUhS6;4s%3vf!m)Hi09eyfH;`N7{J>uA4w6zo^wY1+LR}a5hO1 zj}+2VAd!qU>Cziz5Z>o9V4bXx+?B3KJ^5GaIn3WBnc(ZO@e*t6>TG^!u(ikuf_vp) zTCX(F7+qI~g@G7HofDeyhU*o;Y0=^xYWF_^Tm_~yx0nXv$L$grR)40oYUJE|InOPh z%6p|r-t&$5(ab#ohAee=aGUr$nwVB4cyY& z;Co3vwEbq}cI}`LFYBQiPy#X%e?a?6ITzBG{{ue}wlh3;t&z7xKCh<7LZ_$R*a(grPUKz+*HM$lA~Xv_Tyg3#vig3mgo4B`)69M&kyz zch*O2ikyq;E>&uq`_DIz`MwmR8}D5=Md1{&Q=L`%AZ>R=NIr6?x|)(IC5lu+@uQ38 zdTH<}F>E19>T5z0EBaf(0}AA2wl`aq!;=lt>s%qyl8U^iY@^;>iVKZMp0Px|fW8|~ z2?&O=K3DNx(S)>AN_dfss=yvW2mzvP@}XqQ$rj@?f_T*1mMbo?I_xts1g40-jXI9k zvA|3SOjTh9*%OfIufVooDBy7+aRP9x`QKyU5I<(vfPzlqZTH$BZ11(=wVuf1Iez~# zR4Y8U=UjQZQIlx}4ezz~V-E*i{4*8|^iLyr*XU&$;ZxDH3Ar z!pWiA8!$lGsIrWKGcDNMq;+lBIGl(w9~ZDoZnX0P43-k!%~8s!V|$;;J6k~t+gx&) zKZbdj>Bs2KWELBzOTSGL7z8es2j~**;M`oHL_6~iQ}Qp|_d4x#VN%zgoy6g6j@E%u zs*Y^dI5nvpbmxF=%u+tC@$b8t7L)2P91%W?$g%H@L(7_-} z88M+#j!Aa&PyF+d=IaZerp(FG9?xc&s^XYGE060`0~@^koXu zqtYm)`hA3>Q>s*(@j0v@tBmL!+KbPm;be~E4o>tx2kPVpwLyDsC+Uv0=;+<|kXp6J zM%qPkPtt!cIt<8$G>d@O>|{_lv>ufXq~+T#mMY+0b?!WXT4nW(>bl&=1!r? z9#_*_EG`_Glq}#jJnDG=Oc`mvDCjw6LZ?pOW)||tPabdykX~D)MVDm zI2ZoG3a%D)Q*)HLSw6>?hDopmU(6xvB*NAb4S$w`9|`Z%&K78`jl;F||4{c%QIV0ws2 zUN^DHciaW3G(rxc5}r6wO_5dtcr50%duUDh;hO!#FsT9Fj@2(tNFlBtTz5QorTz3k zOMcvKs3f>S0Q~@y9O>aNn(vk{IEq7xjZF4^F!ajB(DZ7t)zOJp%hM=jRD;i?DJl4 z;yAC4H_G{x`!o7{9rQ3+Il3bAlb6VFrMtLBNrnL}(9^GI6xl&IFmvOutV+^L@}XXm zgUBT7M-r^-AozJ{lA;6@;PZ8%Q@Rj2p_|SeL2L4t#gGiT=d`I(UpRq(cM$G^U+A>L zZZFyiR7RR>OuYuQ5X^0QzbhToK?M5xjMd(}6KX0#Y+-uSNtmex!TW|o(k46qJ}1vH zA`kRMSHgCMwMn_+;Ktalw%y(X2Oe`~(SYzal}eR|$aHa^T{+Mi7=oI1axm4$vp1Npl@ow4D2R5Cvr>%D@ zvrM6}&kY387$+I%Y}6UH+c)hmPBn)QEL^jb+aFziEI0jJf2J^Puys|dz;FH*j`b6{ z<46(yRK{6vvRXU%n&Ux-+Le2M`v~gI;w?x)uTT4Hc2T7|Yssv}wz%PXJwdxeKx|h9 zTUoyq-cE-ZqtoM6E%YfvVSV0@bJfkav|7CG^({V=$1qD%Hf3tXMw;9#@dm^ z3Q1g36+@E`hh`cWcZt47w)9T8XYBEOC-(M3%)SiK{w-InQz290Z|pg68!N%N_Z3_T zTFNt7QFsWU&`;wz@Eeplu3Qa2-u8a)kDk0FjlKy>aa$3~hAz%lcjfOAlv*CTFUkNP zRuG&XD{5st$MQ5u0yOFLH^!*@7j3>OPCQjDbuJAl18B7FLPF{b9Q>`XIjP{k-b2iwzR2M3x9o^Z8z$tx;O!JiZY1&~DOk zPezNs8B}x+?X9B;q!*sY^ZDS|4H^TCf#g2-$Zs2}qFn~4)j7g(XZZhBS7FWag zCV%*a;}V?FZ&{-yGo32qc4a_c2;qH);QQog+52ivbait+wx#vcmt%Wahy!*uTX@q;Q%3BKg}^6p;E%5uV-UCB=Zop??mz?8vYvn>UdWcArAzkSZ=vwqJ?zB4)L3c2siP=9j?RAgF zSTSy(go%PHib#BAQfeSllSD|?m+GeQrbRN|vOCAM`c5I=Sv}Mqpep+i{0|SGObIYm! z)zA(*(JA04f)EC1+6K6aPjRXL$($zsFsI`xMJbNmrvUms`ZRZW9$(Ag9r*ISBZZbQ zn%yCMfUKCo7lkkZ|CgqqOo34hN9OeYNw_GLi2GOP>c0HkWv$=srKvxU2Eyu%In~?w zWoAv?Eznv@6~QS`j7jH9nH`pSuw2T4!QU2Pgwbzrh!PSdm63Eg@jLaK9ynB9@t4%mc(ic) zNh)N{BHAm{D`R_Y2W2Q-x&PkJo>Va&k2?5>UH#_N4`5EA34HtPqU_J6Y_plFkxk~L z5t-xGY{jCcf%F50_+WoD#dgXm|4CEqN(F^HbM?#I&=D?!H4~PuH`tU(g4z|&oC!)< ztA19${gklyi+pK(gRLk^y%kxY-H9Pn{2L4wMAz3Jqr%t&Adkl{Bi1C6B>#Vs;+}sa zDW+UKlm-GwiUGu_T12TC%|bN%zdG7I#r}IoJLN1&1hMuZkh~?T*ci;d9#UeJ1Ie?x zH0E}UX5m+w!H|*#iWvP@Z77%&d+WNBUc7N0)Ro|iHOXLb;`ZgpV{UWpE2%q?|D`F` z#pl-(6=+U68(E-&gX>a+AnDI6fs=ix?TZ|-FptCA3ITtp0YiVgwGOuPb?!b^zSN;dh^(oXV^mUg&*wY10mua@=z1%pE&-H7qu z#gfq-sGadY_Mxy4!d3GW^S_N6kCvOu$h05l;i>(rru{O>y-J*Ogb}z(IUAJ-s+KQ& zziY&5N9<}eUF$IXck>GXIJG416_m8z>x>jbj*;!Ov-o-yanXDJe_Pr&|9eY&6|=`I zGC9E%(J-oIi{UYYU^$1#tXL`{>*BFc)_<>QFT_a`FIApuU=#AxF}I?G`u)saSwU^ZXw@?YaXjo|X4> zk?c~blnSS1Wtw_yN#e1rvQv5JA)0ip8AJ6jS^vRQ3@(H(Jf>PfYPN?>X7i-*l+kFR z)Zr$v=0~V?%Vvs=!cMn1QKg!h6{IdN`?|=SV*0CjvUB!)mwlO8!-4>(1bWET8(9&G zIjJZ~I;<;1t{sZLm&9vLJ=!@lb zzC5C)h`jemwi_GECSL1g;K%(Gn*`2ILqJ)P4`e;yO+M!C=T!zx6EtE90>tn!ZuAr7 zeUdrqm_dA0eFX-pE9EW;XhW*lgn$Bo9zL&ZStEEe6_i3cW#12)6P%OdV9ZNacB0(7 zdSY$d>Gtq!CT*UJ{-yeOy4neU2xG`wcmK?#`0OLngO_FF)f6-1pn$oPVykJ)VZ+UX zwdU45*QT5XE5m##&ORPwfl4 zjH!+`9#BXF^801_Sh}oCke)I|&AdD!(MeU`98_crW5;;qhRThqdrCz6)n`9dDs%;} zf&oDwdn;Zb3XbHh?deHPsP2<)%-XBa) zc;IfyKM{6jsCFtLa{>MHAi~$az(Jq@H8Kdf0?8R>lgYk;t1Cc_3{7xE_?=H>kVxbA zNzOT5m8vL_MdSX`MkQ69ZHIFWr{&Y56X@soW?7b0#E1LG_0_yU1?sUSJ>vQYYa5_m z8~)n7K&{vq@AtJ>I7W^46j|!tfqs(y`5Ne zMcyEKj{5bw7gl+FA)$Ocj(KV=(#!@TiCzLe`CTycM)!|4L&BaAuwkZ6Fg2@2Ws z!Sc=BA!mf^iK=;Q8?5iW_E`rvcn%z$pw|ujAoE>yX=|o&muQq$$Kq*reJ^x>aHb6{ zl6W-mO8Fl5P?-13FmLB`pl}h2@agb&_jfAx!uB+&2KBd3o$z%LJ970nStu#Om$!L&7ZpdcuLBd&0m4* zKzp>ykNTD_u(i}WYJlD^F!9R*M7UR2)OH6IbQ50nY?-wq`1;5*!F5^hd1Di)tqP=b zcM)dxSom!37XNf24`?@T&#VA-6F&!1OEeTNQX!ya%k?AA#vj3hj(M{<6;NSS_4xRF zMSk^^rhqzw}_ zpwJ&3)WgmG!mZVfvcITG&->+JuiN+S$m-Fy7l;Nk02HmUwoUV8^nUo{Gy?=%g4vhv zw3^pT7c)jVJw3TfT!<}V@s`9oiCFfYw~vbe^@lMfX<8*Q2|_2>OdppZ^be9)tb!iG zCrT~M^B2baJ}wfvDx<#kYRL$p8q)7`Ttz%{TmemE=H^2(Rp#Q>%!Ppk!oe=$+M2^b z2q$17vq}~3o#R|&fEHR*!fc7AWjAJc%04a3VZohZ^xsPE%&3~wxjY;Z2X=8H5e##_ zR=wjOqY2dE-ETW?-LGGAWS(OrQVnP#l+Vo*gOj|xMyXOa8yg`6ZWdF)5b@G(7s=kdxrB#BYj5*FnZ z?y^GNt=QQY+#RG~UPW(FL3FzIl|Wh;TTmtW4$3R#0PfA1l&4=O`NE-}Ulf@2h1+iC z!Y`B}73#tf#;`C__0>bIkI3SVoN-WYbXRbK`+!=|4;BS|?Kb?f>-ls~?^|^dHGL6P zkuN*ubH5m5*F+euD&#)pi8Y2M*A+|yc4sKf-4kEvrT8iiXU|JtlKfzB0}i}(Y<~tU zBg{lSWAjnajv6RB?;*{Ev9$lng>^0bP3o~^-*a|@I>bsYSTj&Ry*&gk26CZ}6S=Z_ zDm{17f^6q{_A7Y zq!lIogJMEhCWbWGjai4X@7tQlWHA^uDBsZ%`Me_I!oq_OiRTMvyaFm&@ob#LXK3X#?VY+GI-irUsOMiNO=6p6Da;vuc z`z>r&f<+BiS#Emm?_?M5_BH%Upb(?d;%T&+wv-Qr(45d_o6TkyF8-Bov~z7ZnjZB| zqGE2eNr4(lZ8n6xwnWQ~)i^}oKOSqoeLSos4{%0CL&V-HDv!S4l&23LAlFS(nS}M3 zO6)F5rrA{dj%3|$5|piYk1e#OsiACkG1ZONy9mE~N7Sl1S^R(|L-EPu5g>lFYsr4p z`wi0$HNPpf#%phM8GJ=j-EUVB3{dVyu{X8xpc-8D5^imtCTMY))MnQ=4c;;|*=LA0 zOhV7SCP&8;WQ{0JSUjbrR_xT@E~@U`A61e*Bdavgy*BGfI=WiXj&@vYB1;2n&yse~ zM2EAZCr*9U_6FFEqb1%R0(!Hhu-TU>E~?ZB@GmqVJ*Edqyb1+6Cp%gjBaHUg9;do% z50AaTUncKqt=Zj;eC~%penm?)qtoB=1$1p_>I9yEk}T0JdwaRqSltgV1EHj;M{$Fv zRrbIRYVyPyWh;Ok5(xBR_!*!Z5w>}RYe6VcOq=(vEFcFzivcMT?i`l&=nS-KT4`-V znYsd2-(%bkM`**M=`=5o zbP~lSj2p~gg_BVM{lK5n+1yqeiy-n+(k$e?C3N5leKS*gSsZ6_HF~HS9MBA!v;9A% z$GErI)loB8oKrXMRaS>R{LON3MwQUPm>jqHCJv7q)d;=d`Z-q$m-328J*-GBTmpd2 z8qSJ^i+LrrSNDS4K;uzEX(c|21fU&?cvnFZZFK6=ZJSBU(y;L0`3w3;Na<`8cl)rQ zBKjPv?jO2{(G$jMERyR&AF&P`RnW}}(rR`Vw2*#?`AgY@g_= zPxQYMP1N@cy2_hJ(wSIC&%7ht8U{NUt%Vf*iabwDZI%vbmVAwi>>WH#OO9E5B5_z> zq@XI2SjoOGCIecLMqTEYZ?E?)jU5^vrP{p-}(#-MI;~ryX|E=*kYRMO6#A0@*Oytf~3R( z;@ip2w@8a?}8llK5Dk&nbqMO$HidAWB-II(43q?!NLkTb%R}}l&RWad%zG1~ey+JmXf*AoP&tL2WoRP$WpjVB zv`g#SPxQ1CUp|oQQ$Y{h(lW0Z-7F1t+dx@vsvGZNiQnHEHj;0vZE}G8$?lSjAK9iQ z4;>mO>yr;JCq%39c3g(5ZRmAeev6ilNS9u7Tx)|P*m#v(<}vVcra8Y4Xz2@v+;1dI z0*A-(rdH=PBs*n@b=xLevje@@5Ea!OV62e=nHXBb z+1q{Ybt27jmU(3Dpk}=&dt+^Nd_MOLoNw2OnT<&Um0QVsE`z;Fe+ox;t)$=E~1IHo9#R4du~G1{lWdy6lYl7Q3Q- z_Iz+4Q)+v@a}UhMuHmpZ!+Q>KrxaXj)9~^6Jb7D%Zjaiyot@nEu09&xd>%!7oV{L! zM6aKEd^ZZD+j2SO>8=F{^tTgvtgLdxD#0~b`Vi%I6v)4r=(_e;Xs(-2o!Yo7E@)I5 zi(Pj`G*hdFzq;lvJx?6rCFIu0rAaX}>EKx>Ile2pbf%qGnHym#P`}aCg0GO+emGvv zb2LYKsmYRj7Ms$+Kk66hBpzr@LytOk!?LoM=_%tQ`7Gx6cpCwsXS$`d*!S;wsM08L zv9Gcm1z7@xabx3aM^~)cwf6vcb?qMqKa*PGgIQCtKM8b zKbl#Aq7H9#dYF~QBX8<8Y#>|iQqO|((ej#5Me2OXvj5OykroXttUO~ww!cya;)|E( zt`{{B*juF_+O8>~jGa7CtRUmA<{;sa7Pv2motz|woec0V$qdO>Z3F*I!vwUYD`WmS zNWxp3o-!s!^YT(hlrY#zB(Lyr#PheMNjyJW^k6MYzlu=yTb)ABs)t+jZ3GQ@M z(M=HWwJR&w*KCPE1uQ7}2J zHRekJP-tuf4i=!uU$H4E;m?!bByi$x#BuzZlBfxTRucH-4A``04O~Ey|8W$`Hy*z{ zijF}`z!xf>Xe=5?M}fc#adEfdIu``{8kKix7sMDm1St&BCH%#8j-N@6HBsHaiB++c zBwi3d%T6%?_FWm)Btx+s`~w}yYwlf#>`hAecQDwhHnIkO%-;#%wIEZ(wji6@p+c|Xg~UaW{h~K3 zU@sV)F0P$18sxSEI0=Qb&dy6(eTfpjmygofBFNXuAk!I-%1Y0em3!&_Go!fyU}>+_ z-x|jQep@7{QiJOzuHE7kIg>-pqxG=_O(kkzUp|KNId;`bdWtuEUp<#7FA=@ZY{t9 z{y5<2w(V6Rj*2L>X=GA9iD(%q#XV`MXIi_bF7v$_eIu`}dL~(=*t5BHwW$laky0;y zgC#N!ni7uAp-V^i7dWC38A^))JW1|(sPTZ4I;7F}_As4Zanq=keN7J>FwlNC_u6K- zUSbuCLxq{xL@5mH_Rk^r0QdEmK%K(0$-suvSEp0^Ighff508z16?eeYt79)?u(r{KW547eG96xFm51>dFBOMcVMmu@cYTn; z^-|n{eAu4Ydg}6h{rN_^#K!KM;GEk-PC~E6U=__B@F%Ua`=4!tW(Ho5j=pE$-?lV` zxdlSCyVgrUJ6@Q#H8$63eNXtb6=)CtOai{}5qQ{pvcnCN#B-sN-6{yxuZZmq&Hdzg z+Ut%-@pyeb?XI!79}etSBR<{H({`5hA8%QJ(ea;0q1$U`Z7_^VPDAtEr=#$?L&EMc z)u!EjWA3R!Lx92#Y$wKOMXMCH{Dyn&I&MtLebkQ-x?1gzMf#(vUoE=zP+JgOW}vie zJ)=Z&Y?*1}D{nnU_-B;&j+q=vi%UlhTBe_JZ^&Nl=EN5;>H*CFO7>$EVNT;{%R35u zt?)W^zFrkYYD71ePJ%tXXmK&SpJ-IOYCVMV4EQ~(y&8sFib$W*z)Yj8p~6?b(>~yY zLiZQ_ZfZ_v>f)5!C`u&4mOGBma03t{Uq(-v?-nz@V!s~|8b4jRN? z*Vxo77Yz*=vB4`YRn{!LDppuxxL+X~Z>^+wC>Ut%(7bmbF=msGi0Y0hM)NZS(1xmV zg*_K6u~@^W<~h%tX$~zhkaM$5h8i0V=j+%5)*A>+v z{FIAByR&jx2ElTv5`cM9;dqur}7h(=9q4Euy3iux)(q*9oM5vY#~T^QVZD`r3Ds+lF4AK%~a%VX4*aGo$d)lOZp-hQ~3b7lvP3( zS_GXlV1!b*TaFy4ptM46N$*d5>qJ@r>errUhC(Tc$;#8v%RXch&6)H@*bOyzGc!pB zwq`Y|QZ;aK$doBl6~D3#TAm?h6Fy0nyiSFcid(U=V91P9U7JsGWi7EV;yVh0ydT9X z0D_&5B{SAl_=c=oa>whMI4W8XuuPBUt%gK{Us~ZSJ^-DvB(QCmBY!vmvtfCUDJM$o z>y2<+Jugd>%@U~c-+xWj}Xr^z-x#Vb8( zU_H?^Dzaoif+c8L`v+N}iaS~ue0lUXx{SmX^Be7rw_+q|BAYC82%0j!=jdaN!4;ap z7Q3=eyL9+6SA8+%5Ig0ByTb(Gr&-9M_?6%@g0>Z1jH#<-pry2Z7GcrQu4IuSX8XMu z37uwV8I?PLJH>+n+PC+6^;M|DJVn7}o&)7wXxz_FVmLFrR7GcIXzyllA1ts9O~RIuF~wVka_>LPv1@eb;)bilVFZKfh~j4#2m z_7A&SkRJ4Ud@SK%HHA*3;Cu^Ah=O(Sz4H1|aH;HnZRc(a#!xQU56+3&R=HQ5>Nyr7 zvMwFh3)W>&inpL||6J4Ae@ZErQS-c?tH9kM`$j+DF3cPjMzjSi=4Uw+mkFP&Pm41K z-Et_@86X$e=%A%M)Q()j;7ytzxkFyIzV@S0GB`*7G_Yp1H=oR@DzF@2oyG^y%xbv! z!9*2+by`$O*#<#Nvgin#+$;qCJY2K975gc0A%RtXo~4d8a9Ccj9oc7msbvBRXGt># zKr=<#94XZFh_^uU}zmK{^-mVZr0~J*P2$(ROz<8h_-EB zIB=do8VxBAsKu)p(C&vNrDR2!ONYnhaD>SjKUzfnMW@uSLXcYT0*paQ(y}CWJ(DAHr=01#MULr%soaazgJ;1r)}rQBj;9O2Vo6td%^H@B@Hl zf}B*MXN%b;j92xFunT*Gad#Eq0AQxpCMm`Z^3+7nNn4Bh$eQ|2d#z!!^=VFVNAwWy z)84jz!0BOQ2OQbaS`8pR_XPb#m@U+-hay7&1V5Ykjkbi(_x-4*8@RBw5y5*;&KC2- zm$Az_+C{CY+X;4QKHV)R>&ZFjjmh5^m)r1Nj%Cw*Gw|u_74P{nBaJ64n@2=jhXoM3Yrf4Q`F%`p&n>pd40bs11s!WZ5 zIxIFVqm2%+kY~{}J^#%OE;z~V4z5UWyYI*590>vrkB2oP|MZ+-Oi@KH#KBcvxUIeO{FyNR{wd=e zb_FEAOy>Ni->LjNM*G`QW-d^JFYfa~Gkx`S`}p|Vu$JdMyL6lf%J^M7+Bz1faG&^a zFtG3>kUx&Hpb{#Wn$%tFo2y=thwGBeqiwd?(*4QJjW!TP^`EzaYrtc-G|wp)ctMQ zt=|+@1y%${Z}QQHe^1%QUq zP2~hN9(hW>o+~wn)Kieh;rDLRi;UZMOO97gotugu*n15naOxSn$y0@+d$_3qTvngL z5YkZN(I}qfwLSOczpg*Cx(-csd0Z5^?U4~z9c!rs&0}=^@|n|^tnRh~ zmV-l0G1zMl+SOTKHv;y3aTGi+1x~CO$<8zB`)=d;6=YGkj zwe?|OeAg*@it}xG0Ux}fi2jOCR+xTF?X5S+G2p<~{_H44DcDaJQhma9-$hCuW5jo3 zq>qZp<%z`^82{7KpK=V_SvU|C#Q7U%xL^(jCgRt%Sx}IKaB?Loo3!thZMi!)%|M_) zXNH0t|L$k|hm`&gYRmeU!m|FQu&jS6EbCti%lenXvi_y8tbZvi>t71X`j^78{-wHX z{}}IoH)Z(G%;Nt=H1;1S{GV6Af6-Vr*8f+^a1f9(1lYj;qzq|#{-g{YfL7vTcZ4I1 zzYeDa@JvixXaa2Dakp_>fRy1f&6M-Bqo-?(%b%3tWZO^M4i>dbw71vfkWbQoqzrAp zzjVBslmb$QC)xz|@2MO6fD+bAElNyoFr%bMFS}n!v>(l%!?zbT?VtJhPAr=T?gPn^*(z-`+JWcK^??9ivE5#fZmk9`UTA5^tiVL>U z`l$e4u#b4JA+T@e@~oHBu+g1mvQ@Xl(I`Y|(#H3ctFnnNME+v0OL)%Aq=lV~751~! zXBRbkgp`SZ7Fy$3Kvu+0a7^}Wp|)kcdHM%@#3GV9>h7|EiR|L>kF??-k?0Rms> zcEp4@d+g#mxO?pae5%LrEwS;=91t?rAG8LlA%^4NHtLW0?ICdA^AHMj>Zfn8XtuLA3!ogkAT zMP(phFJ0nU)Bdh8&2f^)d`e2zV+Nc{XLUuC8IIuegJWqT zzEJCiMC^U6=XMU~gWs3Q@&OXaqDd}Ub385SEl=?ULzc`IFkPF0DILF0B2;h2co+zw zbiXMF)M&N?2$hgDR#qzDxAGoFezijdh9@Bfnj0@`<%OYepd6U2)qy$odov8!>jnJ> z!R@8@y0u;IAUrUb=&cy*Qd-UGyM4k`Xamei8P|$A)P|+0DA&s$ino|bunQ`iS{$&x zAdm5#TLU}xNwKDLP>zbc5g`q+jS&s>8@a(W?49g)vKURs>8FPwCjT` z7Mb3j$A}sG(VEI8q#^3Rai+?Lt86D-mhzPa~kIi(a zc5MCHTR}7!3e)i<>*l;wOsmYZ2tHicK{@ndoEO$O=45ew4}Y2#cLwwHJf~fTBeb={ zu8%X~(7mKOEn0vqjty67T35%?A+z3oo)75MgZ1rXiQL&%|$2m{0;Xnw7TU(-fr@N?)|g?9~>}w?^UI z)bY6 z{3kZW(pxP%Rf|U-!;cn$m~27o9Uqpr;7K$pZ-!qNJ0TS8=7UQd1I?wWq}af-@!l38 zJ{*=(J$|sj<_=voZF#kIp*okK&0Oz0-N@3H4_+6zWC=1z4hJvxKu!l z)i3IDhN*JWvR3aBV4wtN&cfJ&o2Ls#^`?`m%Hg0ue%(k)x?PE_SaLaIfk(A?_a1#M z!R2iVEyfKr-$aI+!m+j2UYm=-9~YXB5m0_C!7DVskmeShT~Bv~EogPwu(e=n&9l#( zi)XX*-VbZ$ol!utkrZ3SKW1Ronhx0K(SQy1Kvij`CE4Ba=3s83#iDPrx34H&D;7WJ zRBo@zt+rcwDWWY(T?B8oI_9OGN~HLBcW#Q_7tZ2?;*wp$Gi)$BYCGhm|AibViAoA* zS_ltQL>Zg?@f^T;fGL46N-0+CU?$5Ma(Iz-v%0unAjCU;UYX4!k2ocvJ4&wg;4!<3 zup?zU#z=3tR`(q^MqhEN2os;HjtQ(w!EI}-x)TP41s)@%ElbCX8|>T}5~k`z-D{&> z<;aeVw>S=U!WYB1n=^X~|AwI^s(W&}vQ50SgM;Gw*tu=^q3fh!8)|);cbJJSOX{nz z2fa~V^yBX-I}SUhFhw%-rX2R!^PoBJq@5PWLt!!m>oy$_f~hQR5}f$ygd*2!5&U5e zzO2)8!7>!6={Fiya;Xm7DHMeG@0b|*9XpSR>Zy2oGYJ<65k zF=Z|l7elIT4%%5nj{CE5`V3=CJ987@M$>{9g*Y=Np&Hmiic+s^CQ-B45?$!j-7=5V zCs7Gb5Z4SZ@%Udi?Uw!7dvHcj=PIQ@wz#O<_i@pe*PYF~Xh)*znj`{NWYLw$j}2Hd zRn1ZNVP!RN*d3UEmn#QF4UqBDG}z?)@X>r8sYR;a7GUX5#N3&qzrQy`p69s@2$wf> z{t)Cg=bQ7<3Td<6AU8V7smb=$%lrM@(deQC6q=GMz3~gnOZ{;grh~_ZQvqFHHu?$ASOU~Qw-hoR_)?ei`{@R61n$9wJm(~%(%iwZfG20DgL-k5M^%TT85Q7mmQilc{ zt+vMQxHA#DNv2y&vQLN|oJ(P6gH_&|4c?r9!)gSDUniAkB6AmEO!jJ^g470Lx5j;+|eibA1GLUSs&&{7)6I$qn*j5V~5 z-MDT@wbY89R#$TGq2hxUfQqS!ihSSDcQ{PD<`F3o#zJzF1LG?d8OD2%@8GfmOFwnl=Jr%Ilke;;WKGNVkAMfWVdpj%sDIH=(a|4rw#3m z2q@vcy}%AGZN1&Ke}Df#4tDgWE6S|anLM5^4&4N3{T$?(z zJb{Y+HwsSoW>A~nf(+&_s6h^IkWu+EZPHfSDQI3Z2k>x zH)1W%@mMaBC3QGF`Dp*7XO{Bj=hp}X#ru}yc$I#ps5NDma@)o=5$x#@qXQaCo(Qx$ zb~O`|+;2}Kw)K`(UZ)!tK8I!=j%(zu^$HEC*wZj(IUDva!`T#$C-X}bMB0zI8mHXk zNX0R`s6|LDH}dk&5K|QM>z-@& z7<1eHY@7z5^Qy59&2Qw_#Nm@mSa zD{51`z{fNQQA1h!L%vI=l#|k`@MxlR|$?S0;+#k z1BCOY?ucCpQcXs%tO1zINMeOMd59U0fn#h{w>Y18ovL=b7i?Vwv^q8ac3ZMc-U2Fx zYNNLzMZ&xOo8)egq?B%uBo1hm#o7vC^i!I=XaoQ9QB#dRp)s2H zh7Ugu&>z_S7)pn-KZ(bzr(-A+h_q@Y3C;RlGMvpXoxh?-Tyj;S-J;)}9<7OH!$)I^ zP0~*=0|d||QxOEF#>7klSfPhcq`OIpCqkX~cQb~F_YT(6BNX&x0e#`Y3|MBJ5*w~5 z;*!QB7etjvi6!2&$i7$joDHmX5oQ-rT1y3%*{f5xHYjhf^OEb)fN_69*Xn z>`hPx2a&!pW-G&*DS0AwZiqG_B~1M!ykU=6tb1c+MX+sX_Gld?8M6CuN1Q2Xyje#& zI<~Ig>N(iLrzwl$5G4*5Zqlb}_b{}$c1w=GiH6Q=*T8W-Ko*(7R15d@z6w74CXiqd z=(~Q6F~>a3cZUKSHs+Px?Wu?1Fvk0FPrLop3)+~9NfHn8W3Z{f4$}d-H8C zNwBA?Iqr_Zd1zU{?B(YrxZPXF!&SOhc&&t`#-@;Mmk@Jz1UbS6hRbb2ux#&AVv5xk zcW~1f=N6i`_NpV=>TF?W#_WPUp^iU8U!+UX%%P|8hr^)y;C|uM`MSdf8i~zy2e<7r z41~;~whW-yh6-19-_XC1^Y;1j*THbmmNpiS&Pw<5%P`;j$7Ak83kq-O7HBn7-}D!( zpeKmBnU`lFUEiV{J=L$B%Z*~IJX>8UKNRK@1gO0-aZuD+6~sCv9q%e)71h5xtNS=> zCi{EVX^n93+7W;rbUvi8Rm8?P;H7T%Eh*TsUkZQE4gds5A{cV)C^Q z-aDHf)_dDVE3A^`nf1!(`>mYb_s4lX^pZCShsJ=XdAtU;DGkJ8|LJoq6A5x(U2^7O zS8k328wlTziDs&Wqli+U+Fnb&BpmRmmKcyN|FdV)=YwDe zrSGcJF4S)x;dG3gw+xv*U2tK5g5#R{CX>BE8EjECsVizfgPZ(pH`P9YCzJ_pm<6G0 zWbBgdXqc9Dk{w;SCcu0FugMsCKqi)Ui!wWw)&Q=4E@}1KJ3Z+9n_~fDCE$+w9izEHA z-n2pC>YQ#6427HOqr-wCoMUONz>-qL1QC%E;y0)wBLPy_3EOO|88tt_HP}rK*0Mivm5Y>NII$ z{!^IT6iT7I?B;t1je%-iq)k-0q|Y(uuo7S1cKHlwI}c$i(zWVa)v-GPw zkV<1$2C)a8=hZ)pYfmna=*;PZq0H&x*$P>9qzLu(dI&ASW+S=Itmu*|uT})9H33c} z2kZns-D>H3qfaJ5ogdQyy=k>#wb5e6({M_m#~ym?&X;5YSxmiB;!6wf?1D{WZ;WgA zNld58wL{MGj0>MlEEDp~Jfhwjpps}!OgAX@Cl`OyvLQYJAK*bF_o8s*2(f*wX^@=W zVS@(q<(>^octU0qI9FtAmg6(JSI^~q0TB?zYjJr?izXno7d`In3Cn)sqB@EdLZu{* zL-xi+B__r)dbbimd;TS5uy5Q=rV$$#K`5c<2$v{tB)mx7e6XC4ZL2*ni*B!M9Sftf zKub&poEYC4o`3R%KilV#JU-mkC**PX=Q0jzCgui6l!SKoKlfJeAwik*IjMY{zR>e$ z<>=?6p=vTtoLnKpK|k-x*+V^@ajplVHi%+4EY809ecrr4I*t4Eqq-`_saiD4A%e|@ z;c8AX1^ZZi$zQq2)e(z1u!854A6(Q=Zem+>rvc|mgKL58c&#wrot!s2ZDQ;D1QiEH z;@lR4bcRSOllKaE`0k9qz<>S;$@kgm^lCRs4>0iET&Cy}da3yC?md-FK4D~)TibUU z*2ttGr_O@uqvlKc{WeCZBJcQN)>pIsW-Ntt2q>tE*@>GLw#I82>C`8cfAo!=gey$m z&vNCvlFOrwfDwUH~Yd%^4GeEH-3rj1eyR9bz>E zvL%bgOE3^Xf{R`g#;Iza`lj7q=p3xAHLf|URh(i!a1Evxr02OS;BT%S+;bmV8xhwFCG*NZ|*_5k5 z2$`#B$GlJc)2zA{c;+D6=fASRox>+A&|EV%DCMYf?SADLf1|*Lr(rT>0m}L`FspGI z&aB4{)qcYes1&Tb;N6XL#gK|aI09I*#(i-P5{Wn2X>WbER^-49N!v`Ebwo(j8X`oY z$|ij^h9lc8yJg57Ic-ciy91)zBiedU$3S^#;%o^8Ppb71IR^dqx<=5XKH~H_L)Y~y z!ghz64I)NLEl&nlR-h}A46uh-716h_}1-#gt88Vcr^*h)&k^^fX!qLA|X$Zij z1cMCvV+mFOabRYaTT;^lf(7e;7Y9aa%!vl4|ET&;d0^wzFd}~?2Pa5M)~2K{dnhl^ zBC-1_)Y#Sm`6SPrzC|3bm0z3>6-S|Efu-aRdk-a>m$46N?!&48)@%dPNh*xlUg20MLs=&^RuTWc04MhyNS(gRvE^M2lyi zy;#*OLdx#COt}JX??WpQI?2wm@%%qHdL7JUb22oXsB10StlLaW4{YMWS96Z>mi@{f z3fsLhcP6NS0@@fr0qx8-wF^H}hs9y9zl3KnM*RE?0jDoMcG3K_P(Lev)R-Ao8m?rY z5;)l~wuX~Lkhyxx#0?EAHoCQJU#RYBoN+9=YF-l3TwK!bx=8tK+&*V*uPhED2Z?5K zWqdX&hZCP#ZyCcaA^o7qgJQ9$Zp5az%FV+63@H z6(GvAr*OsL=$f^K*)9LI)H;S#U3i-eiC_*6oG;!yjFg9+iN zm-r#XMS5^ zGWjo>h8k@e>P4a@&SLY=HQz;BD(xL0>Zj%%hUe`Z^C&EHi>i$+SKQQQ*`hF|?K=jH z<(8UM9a*t%h!h(%>9}wg8O;OpN;PnE+32i61FXhZQ_W=7n$%eUo$>o*eE|+Q0D_*b zvdR7+-WcHv#+Q%;QDac5Z#76soWv+1DK#8~HY3{$lgUk=W1*((dCpA_x11Q+Zz*z} zGTd|kO(o?Om|saB`lo+3%03p*Kf6|0FdcBR!@Q|N`)|U)v^;n3%KlEO(A#ktdk*JU zGH|~jE)AF>qs}}VNQn>V)NmrADJOkkbr2QRj< zPknzAsJw_A`8P!FPer4!J8y7CIBz$*&4ez)iSzih(SVsFV&MM-aJ*)kwifIvG>KG4n>lQ zJ51Fb0Y!s6GfyehUaCzPA)qCf(JhgT8ssLPOe_)XI(KMT=J4=9_##O|ubu7kGI&HA z&2ZLr_VH<)6Ja%FK$~NCoPJTv*Kz}1<)IoUxYU|^c64jiz)tmUy=gey-ZEHc6~{%8 z0R#5df_&EZ3(>KPN@Na{!e>Fkgc@DNnrsOTqH|PHj6{uDf;TJGRmDbS5&r{-I2y+a%4Y#O$_C(A}kl3h&yr-WA0ne9$RnnYpu97 z?B!pWNUiWxk=2hB6ru&@%mK-ElgE0H6`vElP0m$GMm%9ZRpVUyWtZbz65jl>Yabq= z9$mGloNnix&Zf)fp+L+-4*?qKe$|H+qcU>}BccwPUvSL+7aX(y1;^}v!7=+^aLoP}9JBuc$Ny_k{Acw4OQ87og#Ysy z{?9sE4#t0t?T+*6#E>;cUB1ygFZ&sL`vMJsxJ)dII9$6Yz@xmxhGb`_VTEjfW_mVt z`jUxBDm$yl%X+roBba>tn)E4rCxxtZOrdx35aRuxq21qgv??%nb(m0VK9TezU^ybZ z9%U*}!>dlOMBDUch2AiJ*A9#WrBu&hl-3DIAM`f(Ft zKAsP^BN7yzA16Q7yYRzRr!{}zqY^Fr&g?GELVWw~X6z_8Flj5`>*B_N$U#{w97#nR zoPn(2#GmZ0o^j=Wc(Dz$_O%HE$r3VO1J2c>717lrBe?9lP~UY#fGmG%SY+iUp$sZv z*MTE@GhP%EwTDh_>jNQz-s^ryWyjlg<>y_MKHuZV_opj8JqzocdIV&joVt6{$Cn}B z(TuO#&Gwq7V80;!1a51U-lXj&8GWLgUPZh^vOzb1`nOIPx<_ymI<@cB?57;P1hgN@ zW;1;806OohaZe;L$QfX7%aj;$YOSwu2zx{;KfG$>Jb^oaIBDR^T_yeU>HP9Q62cE) z)D!E$!LHo+p{ke=3cizKT>0IEUq)O+h7pm$o!3DhX&{JoF+gJ0N^w!(ldbg^co~^p z+6TBi13mb~Y->~45w;xJGMXn%9`#?3ln%`(_0g^gMUzR`Hn&&I@@9&%; z|BUSQ{d5_MXv~RTtiPfpKA}+-0377c3WBz?t~;N|%~b8G8h+W~{_?hpUO05c4wVaT zz&`iBYJexF+SRbDe)4A z_~T(?2t&sXvRpn0517oiv@A5iE(Sk#55i2Y_swkv*R*8G8Q10HqS5zjaGhvqC^lqK z_nG~IT4tg|eZ4|@O2z^zGt>fYaw6zwB7ICVXtWmEt^|7ds|t-gp6}lR8YENtzfkBz z4}U7llC-aZs`jfiJ*px=p?1>fDx{abVl>PbFt}O(h^JDF3ERoRs3`{HM<|u{!&+OF z)0C%bN1o{&Ir@EjzqjN@%1yUq2otIwPJf@)J0@D5cBUMZi{FwV>%jb#vG?sZ%3~`P zZ7>+fh{ukt3lVAdD3dCeYr;LLO`1!ZGu0b233gbWbbG>osQ{+F>z5aNJ+(^=$<`Mq z&_+K~aA4YI#OeIS^%AIOh&$dW(=G-eSL)#So}hk+vdprn>0Pk%JK_sq!rkVvD}ImV z-K{z9PFM5TGZWTvU_WS?lj0d7u7GcXwq{7s7Uj`Vcskh8uvyuYm5Zg4sxBq-ipEp@ zifbcGhOB%xg-h{k%!9EN{Y5o=F`;YD5ds<97%rETs@q~?JpDhnlXJ>4HCQN!X|xT5 zkj2-R*R1?-*}pprOE|u*78N*eK*KKrH<}Lf#_rJ$u~%D=`y!7g^$Q5 zDI}c3_Fhb11|FTVf_O7vqG{5CEnpxvnwizLbc<|mcsMqw7N zyAXNb!-*T}OT6Zcyyg};zU9TK4xbLE3-?;&7f3v#n+6gWoMcxn z0mrm$@4K48?hlju&G>^?)6(rOun8ukYIpGC$z%ph@^Wn zw-9kH&p11|>Dt5ETgsa?0pZN{B4t<22td!5G}vDLoG}l6Ipa*RacRaJ2v}TSrS@&4 zgiZ7n6_!pxP3FG|7A>c1%5YNs;N1xB$lkK@d5}M`vB5;c`9CA@F(;v-xw0 zL$8(CoMFstw7XX%31odoZ_PhW^&z=GXRM-jizjlzv&4cJQQ<2MI5A5Zp*Y%1i3v5E zt=9BC`cc|&<)%e^UqEON36TNbu6|geVMEX3mJE%>HA#kR>xqWp(K5B%-9?Bb;q{HLb_7@z7e(8 zy72iSa7VbI;{?7^()L)hdCBp7hKUIHFr;IIzdhmwEP2`5P0PckM-4^mda}?YFD})N4Aj zP@oHzho{p4e5{fJ)Cic<3>t8bvRKzQpl}3Avtk=X45rjkxJ%NU#99{ftl7$itfxQnU}>)rNIr)Jki-##pSnE%ladUiokdM?zXbsyYVB5IT@TsbA!(*?3(7p5R=&9oK(?YDC^#kR;TlYmi z*HYa}OpNUXi&MtWn*$GCEOq2>;#BymydBkA5G*+tOec+a5*?;LIPeUwA5xuCFT6sU z1qwO3+p|?Th6FZKsm4Bw0kd+*`>d(HWAr`fAAV)Jz+$Y;A9x`|Kw>D}L+PUdl!tSs zaw5f;k!K>%porwp0Bmo{ce$_-^4#EfN;D8Qz>q4{cO7TQEJVB_klvsk*#j(FO(fSa z3&6zERn>ClO8)Hv&}V(bI|u}Z%`#j3cGJsS)7-_b6^`PRAUUc`1*rntMSeyXw63_O znH7boeboiujfcV>@Lre;vR>Bg5vco3QrKk%J-q6cPzd)*km*coIEgeU7k|BOx){MT+DuQvh#&m;iP4a7i<3#wO;Me4{o=P z=yIv4UkTF^*wOOT6QEOcso~7m!6S58>IK>CHEZ;+I_w)>-g&IVCv{nq57_7j`=WQ) ze_g=KHtX0hrWji>5wb|(Hp-hacaJX2K7Qio4DkWi*=-CB2^-E;tUnMRXD65&Y5Ixt z-VOd2lF)5OM37;{N!R)|BTi`fvG=rL(9t4Uu*);p9c?gaSBeOLPO6?iZudCLqnTTRA{UQ{G>Iz;i3Uke-LI9DdLeb5q&=v}O zh2s1HL0e9PrerwEHW!U0+QW41vW0O4ce}XTvOpSSP|@!f*a6HZzl&`*hREV3tRa(V zhYC}{3&rgLIJEh@=(Y@bQ?NHaGkD@2n20zBedMo=JR|E6SCa z(TyKeFv<*#$n?|c z{Cg9ByM&~NJ=rih5`uFBDfkWLXc$r8@>U?z4*Td8`BYM5KdypR><=a`C>niSi zFGdXUzGj(T^b=l2@6c^LkcDDcRG7im-!?EEZTUHlN4Yfa`_T(J;;x=&8Uod^D=RV| z%2RFo`uWUVNC^g7>=`y?kISqdX7(?wJ^dt4y=#LTFbEEIFaa&pS zw3~Z+2c(O+h?7@Z?8|(XD@?oi>=nyf`AQzuijr;V%4dQC~6#`JzO-TH7JgfB>7@Px6b42Sy<@?Y^Noowq zO~35oYq&@7tto|`q@bXXBOneD&luFX7=7vg_j;!TJUu6C8;*&eCAsX~B29%FbDj;a zB^5eC+F5W3SLYRv0Um~jYJsXph%T#W^kB8Nq3%xE_Jdgrvz5NI&2HPsI^@?0f1dh! zV+6??wLNTOcoRbL{?FQP?z$V->P0URr(m<~gGpt;V4f>Y>{Sj12M7BptuDiWB~RlS zjPOm;g%S>QjE}Lp?&iwziLYJ`J~K<4xqQ1`m_5&kPf$FA+K@8cx@^&15wR zr8(Y`U=L!ulkH^j*W3Y7)Q|G5dcWUElQgxuzX(TpdZEsw1b)s);k#&)nHjh4 zXh7zViJ*u&bjqo^=C*6QuS!pPiSC$Db=4K=;aT~dpQSX=jQ54CAKeqUlXe>z%lxR% z&i{wN7DN4c+?w;6n}$vxIMaKo&?iQdBBNGkn8QZoAOnvN`gM6F7I{LHk!qi=5IuHi zRXo4k!BZ9CqDq9&oL|?FL^o8^PbUHjd#h_4qkEPvVnF z(N%^{5Z}Y*AFgdgs~#2v$bveLu1h&ggb*U4Gf?a&5cXQ(RctRxpB!ePq~KbV7DT2V zza6EuN!*zh(Ci#=(T-iUt6G5qnrx#7pP5}hNf6H{2E=#MxsgR#%-uQIk&lopQPLKu z5}jP}i*-?KL7db_Y4*L4>W^a)bW!_v3vVbQcj|?TI*c1oK6aR9Z>y2=yj-c1attJc zeBj1fLGFu^0<(m^Qdck1|Affz@r*Q#RDZeNf{%|}|9Sz!-PXr;c@!qLy~P|Go>|KF zsy|=N4sa*t0i$BZeW`-14{&Y2iGwQd4-U4(NXB(y-qjooAj?e7HMgUka*CT zGt_Nq{h?RwFf${2$C{fwePRp5ww&2)Qzbi$yfD)E#AT4a_RWD9f0N2v&p{BV_4)FoRE$aA|(rec~?Y6)I&J zcn;?&ZpH76=BoqX0|`A9tgY+~aUS&ud_d}zu=_#!R6RDxQR&R?Lj9oR6Fp3~QFNuGF+F6=U#cEpfTV85u=>ZMOqCT9fxv*|$3%V2>sOdVpv?mQqR=P)SCc>&ZDyk-tt}o$G z=28~b`9Ijw<7Yr|MY%(}shC>C|JV~lbpP9)IRD3rq#u>zGuj6ylin8xdNzNfgA-!g7D$xMgse7`xCz7&nn_0w$7pW98nGj;{%Gt56hkIkXi@Vb09y{ZlO zFN5gxjzIgZPb@5Zs^6(E%>kywWLx}ntESsGxVw4G9Z8Hq+mz6M^ofHimi3qx-R+1i z)PW-K2RMNECj=DES1i88fmpFoZX=jP2?THa< zn)SE;uqO%_TC2RZ)N`ckQ8k{z6we3B@MixqD%*EA>qW+_Z)UO8 z`luz3(#CIe&N}5kvs=d{Bk+O9ADdV4?~v8+`}+U+hW0;@6+7F1AuCp{-_cLb|CIb( zQ<1e?V+0VZ0NoXl!f7+scqw%WX~b`W294&qg^*gws7izE)fnmT&m+S{%RRzUh&n^v zVaa-u3Peg_;_7$g@ped3btI|#nco&RlKP-!m0QlfnHbqSS6j5QIvwYiCWR3T4)NLqeE_5b-$}@&~tYDaaXlnuX7gsP=t3~-O{`RyGb7v zt>vsI+{;D&NM$fumCUVjY%fv*ZT_j^rovYh;dv zkA6Uh>QB^W_T>e?kTu_iR?2&Wf1XY>i-z|woz!4@0fNKGwJr}c%CgkT1J_y(N3gaQ z&KOgAU&}XdDvzjPV12`%)B}M70!k7O|91z|Z#eWnfzsb3A;;fjBFA6A#PJs}ar^~L z9De~5$6vt2@fR?0`~gh=Yq0d^+y9rq((eiX=kxHt5{PU}T>lD|*8e4eC`boLAXfR| z4N=;mhz)WFTVuPYX06vFjX@(Fc6a8KevPBOcY3&wRHf7nPD^AF>38Q zN3PfFh~5t%1l6ZRxGnv_2x>uM<6>v-_w&k-N;wb3!Or(hsZIVeD#7J`L*)cDE^yD+ z)mxZg{?_3Fw0c~vPA~gMD7U5~UOV%9Et2aDc}SgRXzxFsLqTU|dXv+b9Dc%%=Yz@4 zk8@iAeA(2s>)Fw520a>Mc|=WbcmY32w2zrZsnf%dwpR(h&T@W_Ys;8Acb~_~-QrFB zjyEt?bHZ2&1;!+5$;f+x=1avTktpvfnzOl=W*W`7Gp@@@*;%!9}qJXw?m5DXupfw`tY^yDQ3$2>^PSizh<_g#7{yR3WCjp(xcD zGPfJUj)M1z&SjCP@kt&Hfk5~l2_dML@TI`q4x#%#6+vC#NZjK*-=d8OlHJvt~0lI~^_n<~VndzAptjeclvx1oFmSfm-q zG6zP$n`u8LdkRQs#A!Kx#=7HsAarrro-)AZ$n^>(t+Y}f+pJi$uJkZaw!_8V34sVTqg}XFaC4+vk$~gQKSPm&g zzREVIRA;Z7(gOVoNB(O++BxOw6hSqU&O^PCQNEm|W0f77n-#XFMZ|hy@tn1hjV;>) z&u{=oguXutixi&e5OzSUGZ){50P7e?zBNVmJ#BdZ%e8Z_XKNgOm2grFGT5)%?hH=% zSUX&@*O8F`s#-y5=5Xar`72x_G+FFVu%SL-zBqVe@JG~lnt6o~h`Gx{4gtZ#MV4mi z$|_pWkbAMyLhd*tE z2F6(tnOjET+Ef6y9n*_Wx|gX;&+}K6f31R+e&5w8uxN0YX`#~;f>GdDNU0)_l=MfK z`(>;%)41`*sR-)?8grDQBjhZtZgXL3k^tys{!RpACQJH-(AwQMOY!R0Q>`5z^L|wg z3E`2ZWCHE9!m)T`+arCrq+q9u)P2N5lXNeGVE=Z@d#(s;)cuO%sEcwU3dP`$%n z*wvcjEZl0h%^3HgR}w{~+Bqc@r`2C;2z2Yge?dE&f*M9-D_dM?e!%vHpWg~!o|S5X_ZDLALKRh+(~UMWm`1`{xjvmD z<{{f+<{|6iJ0%%N=$caV1z9r(*rmjqu*z@E(q=hKLX3O~o+Fq{KP(GE#F1MW*1Bpg zT?X8M5v_Rc&TTxpW=Ks@z~=&oSRb{5$O5;by)dEs`?ESuq*L4uW4 zm`r3!D}gzp#0Tk_d0PslBqrM-0jHV-2V^lVenF&&mCX!-oKLX^#lwImk0JjISCq~Z zrWcY8>A{Vc39z&?N+*!7i3?!&PqFU+sd%T+Zf9kWLfOuZBJ&g{KedmZA@Mglfz8I%o0%-g@Q8!f zqwLPhw|fD$;Rkz{7%e8_&blk(q^07p~%!I-n^VX^g6pc!?N$XN;pwOH!CHPgEEh*TV zyVDd`m0`>E)(@$Q3#?1 zdEzB>o%W1xtT}|*7-WSB*-=;HjRNnZo!*^9ae@u-UKS;JA3e^!0t|&&@?#Cu8o%yP zYhg5UA6bEFl$v?&TV#8FWi$COfUBs|G^nL6NS3LyB*Tp0P(t4#Pld=eR;oi7DWrFo zf59rJrB%{*PbPbnjhD&WZNEMJTD&svUc1hpZ2FKX9f}-4nv}U276lGgN#K)ncTXsI*8TG3jU0_+5 ziNNXJO-HP}6}S4?aPSR_qPiRj3LsHuPy%B;had1=)=E7f$<-}=+V%#dTzoA#yPJ9xJM!3K)m zDPA8B9NW|uPB`x3vPFyrD{x4X-jTPfn`m|Zy@ROWg6V%RD(HjZ6jB4lDuQsabWMXB zkjd+IA-!S$-y<4UY@hLb{$cW65=ETq{qDNA)Aw=lrN)=9`BR}`N<1q$XN1lYO|jO@ z3ESqZmEV-RBDK;91$0vt;YrCVEOezy&*FHv=EI&#EpqVWl{r*+KiNioR$2%{k4+Z| zndPY=B7N8Hznz2kO z;NcR7Ee|+u<)%d~C>fMSFnweIs3;5CIKDiMdJRok*CcT!CZP zF8$0gScuNsj%}?6PPn&kVUYMtgg`};X zoQ2s7&ii-z7lQWQ1MHNyZ7md`IF(Y$JVFt%DUb;^IZ;0|awlC&VmujfIYQN-drnVP zg*cni)LFcG;4y#E-8yP=$-BoF1HT*#BvmGuo$syjQhv;F3{=z{^7@R zZujLw=^hmG%GD~7X%I24;+c=}J42ZBFn-5xwmQ_CpwarSD$~_WSf|6CsvaExqrK1| z)zF~pd$8x)*4N~27(wx?{i#rL#9*e|BSCYHFClh&uV$!vLL059K(XoxzOo&gEa-z7^1Iluu)g|4_*#Tw4 z!m1&b)htBAp;&L~tQ@~Zk298zttnY!bVzg@QP@@vL%KPp-OCwGSBKD6Z?g_f57-Um zaOAA0fhwKy2pwO(oN3L49Uo7uDQExb21c9iEQM2 zxV*dXE`U|qY|!XRq+}KQ*MY3tzNz3Gzie_o5Ff5B9ep>GohjIj>xuB+7vGhuzz!bm zDM#$>C=aH*tvTk-2XelC#<%&0PFmh7b(o{)dru@ek`zKMXFxdyQNy|z z`xSG($%WH46iBOn#ZWt)qa)4S?he@LkLhLFI**=DJDla88QV(S>`i35)?- zGG1Uc4Z@UHFUtYugYQ9bbZmFDx-`t`#e4^Hg8)Y}#h(|%{#td3aCrw1wHNC~e&Vbj zy7XQ&*aKWU{1$`qrZ3(qdZADt3|faJKA~OT;=3yllhsZ)!gVJ!iQm6&wYRZScVaoG z|D1?d#|vfPhUfUS*WX)6+ReZhiH(q4j-T0!7~a*wxy*S|u!tdGYv8vbM9CMM>2#%! z1ip6aM>z3miXsVMx-1Bi&cfT071;~b$sqGlq$KB4q{JVps9mN37+9GlECE+J$RAUZ z&?($pUH|;mo*6bso$z3z!bcwfyDUhE56a?BdrslKm=~kM<2c$Gqe3{Q`3Sc$O6|HK zAF~pPn&l^qlA zE5C4Aj1ph3Ss>RSAAg`RIS}RH-l5sW(T$3K- z-Y@K#wFwbR4?n~a)N^#|h+{1Fy7qeo>&Q;+OnH6iz6)k>!hiWLjzT|g=Eu>TOzMIj z`zXm4e<#7$bIZaAx`5EG{zc&uYegI{S2&4G`(y^_pX;9Gd1iqQ&jV}21F-<*#qW}yOF~sX7&2STbU@qVgqUxnbjZSz`|gJvf(10 zycTiHA{j*gJ%{grIe`D216z-6sQal1)`}-2nc1KH^o0~U#e(&}_tPt023Aq+`#PpP zXv9NvA%`|Eyl{=QZ{0d!?34DcE!2=qwqgMyF*GNbtg48cAR#J>9jL#LA~=qpNh4A*^xeSV4X zHtH)^QM*EVgHc+=XllTg$-q*Bx`=t%Yj!a>HbDx_)k$PH&kMe=vJ8W|IOBNz^ zxs$a8B9`ua5lCjj(;|gRO89sMQKZ##G=r&PJIV&wKr?In5z^BanzeiqK2pW3`+PTr zfl;t~l-_$W^At_8!h3VFIp6VfI|Fk*_?vbChMi9DKjA+C!mf82uS4iJ**k4^f(5A0 z)=G>cl~Me3Z8v2fNCEiJj(`1=J1yC{fAGD|Y|>(R1zAIh-#l z9V&|EeJk>i#mL5Z4dssZ;?m<99sx9?ngcqbeE}9zbfGZqK-_Q=hUwL4llv8FB}+0t zNxxIIZl_l(HB(!hc7c#*0%Cxi7-lJ6Wd<&lxt5mLByQs+^PyJ372Du?semA$=18eP(8=%ha}z%!v~@}#0H zCN~Wi2^qv_WvuIuF*a2o#0t_VbSDaBfSzsyDVji-A~13QacU)x$jz2l->=_praS0X zJ)A3!ECuFkoLkz_0ozfvO4m*=(hytTfN35-d;~;BE{$Zz zQw&n)Dt0C47%=99#ZB>~?5YyMz7D)1&MZuQ5*hv%2Ok9b6#WHZTL(Q4e zM541j#s{V)({=ieU-|D8i-T&^;0i-yiwe-RFbl<%;@NO7qc4?0wY zN*Hg5Y5I*D00BT%Kmai5b`AhhRf&EZK?{aUBxK=Rk9e}RjZeYe;$ALPJc=JJ#d?H- zp$DYqB@8Hu?DqG-TNN|!CuA$(O+O)jCnG{UD&pw$sKHc|*DvpvBNhqB-1Sd|s7m)!-SD?G z{irUYa>1MzmFrQ346$nTf78n2x3-y=E~^Q_y=p_+aT~f0H7D!A?Q~YL&`e0XH||ng zKts11f4TwNB(mP^_!0S&B$)A)EH7-El?_<3;lielMzxgF;$Mz47TK1cx zA`xr-O#Z`B&DZb`e#mBgZI@nxfLg|BWSYThvac4msb6^{TMF=6NtsmFRM~8}7q5kN zJCM=Dkq9XX=)lhjQeJ}try@sD408c=n}HARJDvkL>i1pYSlMCqm}Rj?V`dX}V$rb5 zFL(XuH87s8C811m@ulB#28<{QWm7)j4i`Qt?A|5)rl_&MDJs(+ib}S->Hi7+brm(h z-H4)Dnxi-MO?7pm%I(Re7{?N$Ys5iwyn(MtHjMtmtQjDx3IW< zUZ-*+m~2C~csmOKdMM6*-kex&sUl)Po=f0+Q^d|ORPW%NvdgW!<<%n(6?hlO@XT)e zci`(cr25bF<{uQ5noNGM$#q7A7(BbPz z{dff?fTBioWEdfOe%gyI;=>x}U3NQ&+EBWY^p^rglS~AmZumq~605FShSZkSMOD{| zuR3JzGfxxAFM)&x9LUYbW_qKYUbYW;`{XiqP@cZ>J?D0jW0uus1IKY)j$>6(t#`x= z&+&sT#_(cg11|n`g_3f9O8zu2ogEM|pXnf#?w~as{iKrenaMg9K*`{V8>wxVNw6iCF$IlHTJ zUp}ikZXKixGEQBVkpnx@XK78LwY7Q>;XHb&{iyAPb^-OvfjJ5pCt$ zkHJ%Cg~PnFn_^@(6HR<;-~1+k09+k!`f5rdg?UVqNjTkdw!Fq|TJg&dvas3^S>+g76f5!V?Gul6+ z{$FCWzbE{k&+`8Y|FN<%{VSuL=lhrNAIzOg>$ps$$cx`N z-`b`?d>&b8OIcA-WBY{rGU|UMAPCBDsIa%X z|Es>$>2+`uv6Jgq693~}fTqq{Rf$o&+0Dsbk=jl0eb@b)NY1*EV)#l_y&gZ07i90Z zVtVqd8zvfoZV^OYFhfg3&E?^Kef)+e*s5rdv1zxIm__j6*9@v%=?imIt=rBAlu>t)cuWa^P592`(S7m+_uFEhK+?62}z7OxY zWj!v{=0A&(@?)+a-w%6j-=7Kfe15fFMz6>Me}L|dZrkd8GEPw3phlv4UE}!)bZGc= zx|QbR@sKn4;CsYpmQs|ODCe=9=|8+c`1^bw-Slcxb|A5b^D(N^?N?Qa+f8*QHQOlr1(3|Ty zgd$Dvny@e?;uo#GeFL=O9SjPrUp>$3?d@m`6ONOh=wrQwhp%_WPKNd?E$BnpAIT0Q zX2F!7JGZW=<;PXnA8icDS05I0XY<{Tb-hr)3{jN7thp3LIp-ZMbaA;fZ~Pra!Qad)VR z)D32AaNHd$Nav3`xtgk+-^q4kdmiS5Jfro{oY!W_KMd-`vL=H|uzvvVG>z1DYe4_3 zp`vBgtuUqriRdeWSS?`1^fp-8<-d4dvxj9evJB;!nS;1>T8#D6S$Bsa6}oCc811Sv z}X*pAtD(~J9yo+nkZZRo6d|G?A;p1<{?hLkfPiMIYQRD`gnVQdm4gxHovpSpN7VL z2ZaZz_n(i30XYYIN46k^zC=+{$lx*Qvyk!W&pq3yfTLeynGE;HOoWsRO2jWxp}or^ zq}}(w!Y!cXU44=(34~9#Vy8dP)*n;Mok+NokD0&p$0c^Zd__x8qT*M-0o~T=t?ck- z^eojX>0T>btwyxTsoV{Qe@L52%!21udnjQ(l#joXHm#1xDU)+DY&9QyBN;)S{>-v> zH7heXcXW|Pemw`rh243;YtgXv)4QL*d%E_Cn>!wPUC{Sp842BUi-ogj<-LvGxi|_c zK;cB|dMC*!!6`7{6n?##%@WZejz;JN0e!|tL{wMS=gXKLbp@{HiqlN+VTQ?8oqC#@ z;=Zz7Y0I5Lb>^)}4U@%rw;3>D0z11F-8CYkCSd+wHKO*jJz8qX(Q*dIN4zI^{dMLE z*wZ~Vv=M18?Y3%MnMf!4smPYPQz0jZ1l<R9zMa*&JUe-cW(-0vEe;Ik%4HIPj zN|?wc;5CnD%H#@|pa^cKT^u z9@PBa#Kz)QNay8tkMt~()%xxHJgq%~wUSC=W*(DEk6i+t;eao(_PvFR_af>|5}0wt zdY3F-^y%Qwob+N1Gf=Wx|*1LNn{Xi))I<{N* z2ElC{?C_7UTfGIKpMIpc1uCN$8r1GpR{JP+n-XyllJOtf@PHBAYbH1=>)jn0Pz84_ z4dir9IPik_0=MPFlSHAqeGkd|T#}X5sbO>3??zAB5v6R1exBBhSE88!y#GRq*53_;n4hwyfLSV@~U(q_HlFhduiV7(5;EKUlt= zjb}hYsrTAJb#T0B7K+9jtIf&XrDWQ1g0&~T=5uO^XK47QN6pXwunzYvqO2H5uOs>4#DsFWX%D>GyeBvlg9AIAKf@ z&uYnYEn1%?0%^JxS_)}I@|AQgnhei1B$UwmHRJ!I?i_<7eV=|GV`FSKHaE6y+sVco z+qP}nwr$(CZ6_!D!*fv2|5Tlq=fzZY)y(vL&rDx^-P51DznxX7ZR3z>#Wn&P=Mi18 z+wq>JQbSol(!{V|Mx*9*b_ea}IDGsvWS~cBNC_0)>5j+oP^>PS%-h6f?cv_|u&wXA+=7KEC$G}U0MKe*-!0F7aYcmc3E%EK}@jsYKcWsy97B3-bsa4Oj67gyq4$+rFJBt+GFMz z9phy=u}__|`RjZsiG{1aS`Y(_puP`l4Nmkrv3&qJ0hHYXBVc9y(EK}@;B5!|Z^`6R zJUCQ}jS~uSigx+!m~KZG!Z*acg8yZH{BfbBucp$qjeQ2+=H&YrCgq}RJUjL}?b(mE zd7NmJmK>wp5Z?+0X5edP4bIMH zMrCo|MxCmz=`yqE{oy<;>hk*OLfZ7Fl)ePWkkqx-Q*n8^ZJwCoK=Q&JY7!*|3qqEVe;GE;-W+GS|&$_K`htT>R9dir6K$Be64u9gtRiX{mg^Pev z$_pvCwGF9y{77%}YZ0Mmd>>rJcDXJIkdWq#T)iL%=YZlu;k`^ilB#+c&zfybqd_fQ zlPW~AK+|PX-NAbk|6TJdRhw{waEVf=r^kwTx3apW6)PA#@Zc+52eKpq&u!?sj1EVUq2 zs53>E_3IhW*|`{`Xu(-9(Rjq&O2R`p^JC=m`h$J|PB>1@%0gGB|30@j!P!-D)Yxgh z|EZ8Wzj4y+j$ml~5vb9KMEy9ad+4#T@kxU5rI+mcJz{kz!;f{WavwlIW!L|BatE=> zE@*Vu#Ts_$!e*3Q^j_k|c&|}ZrU~=BB^5QTbY=5#e(Be?=j+PcKp9B;(&&22?s`xB zzLYHjS2^2Sf2mxa7XIyq&DNn!wJBwo$tF-zE3kR;2L|5vZqpyV`T))KD2Y0Yvjgr< z(LiQudX|QD4L}QVYjoQ2B#_R6;7q@)+FCF^2#t!b>D))BLLJndA7AA5Qe$d%Y#G3I z1g<_h%q%|6C%N6;E46&NbM1(qT2oB>rcjhWW=~$TmXnA5KxAC~`)mj{a9`%M8d2R) zJpBchKdQk7?^B%^7VUc`ufJ3DTRXkCfps_F#3;lblw4yn<;vj1!~6)-#7UEmm1je< zob{UW&{M(z7le6R!6EO-9B^rj7F%QLue=m<(Eexg> z{Hh@9#^Cq*h#$hkmiG;#?j#`-(?=(GGM(gI?pFX2I>vOUk`FlT?t}#t7B>WAk5)L@budB#9F&HU8&;g z`1SmVQsOi@F8!v+w5B68X~0(DL+Sh_ym;MW$|=OYqfRaCTRDt{1;QXqs3&gCr9#6T zagF`JtHN#-U5pDK)W)rA-@7j6aL_9q$oC^>DVS;>Z4noWo#IVGvr9>#A`dbMl1%=6 zE2*95jbslhgc!XD=-#9nHVS|cGa~=1e@z8%LDvt_RkZZEPF*~EUl@qnw!d6hZuvK#_;ZIA?=el=3rrONM#qT(+>-!x7XijH^y z1DHIo@92<8+HuOTFf9rYLIwyXdICp}T6NicbB1mTMGx)G&9l^Ix+jNFcM_^9-MFD}$5 z&6Ve(ER;lJ?(lk}@=0$x@<{*hiB%IRkV?WrY?O31yoBh4nBcI?1}CW_53Eh87jq=0Bq}18_Gz@S8bh5%S2AN8R*Cyl%1>{CEsip;q zAN0~{BkOJWpGIZf{X!xg44oNJZ2Yt~` zlde zjMV65%9MF=Ujqys%2#uOm+Ogq%k5O@qR*fxzgpK$V*Wsv$jlG&QK6VVDn#rM<{xsn zzsMjDNWuV|zf>2$-u~6O_I$uCXU0ShnAr@Vx{dhNxfU`XO(XCZbdjqYPXb8)2f7sK zl#(%X`$!xd2&3vwPJ^qxiS(3e{METO<}CJ4=NfX*n}{*b!*{YT<`NTW013PyYhLG@ zzclpq1jNE*{a55nNHVQA>m?WBw@#U>0~*oQgtiAY_#P0wcHR7iT&zaNLV+GPj7Eo! z6Kv9xzs<}|QKc5*@{7+Blf0^23+^#64njVqJ@#v8*{vh!;LRC{tD2C-F|GOSFyf|ScHfF#8! z)Wl!FrRfW}05W3!0WLBH6*7C-tZe1>#N=vkAWy1$Ng6P~VCk&DQqhmo{et091xuP< z!D)Wwu(16Wz^{!04CWSF`QB&SV1FhSb{W9Khq}3@0s3Tx-5!ev=9iKE)E@eRE$UMy zdTI&-Y6$$O9*EO@R!~2g)j)r?%RpVU-ztKfiPI>9O5kGPhHL!{hAM(nt)t*C;3nLZUg0-_p1*Zcg7#N6Uj=(S&R|@FAi>q za@O?7d2u2lc$*C6G;)Lc%`x~#bnsNbHDqX~*KR-`NjKAPTRY?gf2I}s&s`rdl+d=P zD?)LH58~O)c)orrYnT3b3+bo*A}x!0xQSjEF}g<6CNc;CXHzdo0NZ7VJ%9Su#H{cF zqT(mEVRXOx)gsG?kem@5e{0*Bs}SBO(YaxuwGtJ($~lww9n+JeFcmqB?U&QADs_q- ztXl`db6^<#3tCQYlFu(czlJ|`KBJ(F-w+Kdb9KpHLLN1zA)9y@4jw(dRGIF?$%Ghj1h*mP(R1$Dl1XMA+;{Wqm=hCgNK z|6GUto3_yY&v}JRER6rxd4+3ogOv{ zO!ltoapwz^3*$Ze`!>n)VX8q@`k5gyB}5wDaG+ZIf{Fut%r&lV7PhNz&!=3PX`tJ7 z+!L$wE~bs+FTMIZQid-Ti36q1vhn9|{(6wp1gWIUK(zb{m`3go8(*r4>Ko-BcD1d7 ztB`3GCtB@uEfy=o`W(<3k_eFnsNkwjmh`r`OY-IbF_QQ(lKS~JBBXv11wH(vY~WGw zv7SCaoJ&c%09+g>*|(uy3*1B62;Sxwz4(L} zg2np$`0hKX%`X#B6E=rnh8#x_QHsU~gwis&La9qgLqoD-%!`fvii#8q^IUO;D)1{H zm>lRM+gzkMhU9(d-vg3hDFr!z@zw5T7-5hvZ@qYNLlIOlz~w%(e1B%&g&@8Zxm5ba z{0?`MA!0Cr#1a5Rps?;rdXU8h!RRWS&S^TWYkhtjHKSI)qv)Xlr_8_|8`jPXyvoYL zDqz}Eoh6B+<@g1F(32&MYnq;w_pF-UE$8wL@O3_#N2TH2Me5IlE<)ucYvh?BmjW;$BAkY%>eM0%8 z4XP?`n`TGjoaejy^Gsz2?q}!M7(fmzro#VjHT;1w{|5+S{Rix@{sVSc{{cI!|9~CV zf4~mw-(ZK9hURaw^JV;vcD{_i+0K{oH!S)x{&xCh{N?rk756aw)xsH9V}GW9er(?z&VIu8r)WaoyRAOGZc1r!EcK^-K6FwShPCaVB$`Q3 zJ)4!=iq|p52XSIcdwOMNN)u5t1t7)}pN{T`4Ktn5VwPAB{gxndHtW(#B=OLactY)5 zP{>x-&}gIY&$|^4pKPYs06RQ?J_gZG*fF!S_)&Spk^b?9R#W4IB+iTA{tb;PDSuAe zJXv6^0IM`w6w;ZNxIazC#~hZxC{U5^-s26rk8^17awEM=1_@$(I<$bMMz{1RLG^Esb(p!d@Cqtv6^*c158M}!#pDRt||0g1*owH*XpxmMT| z>`990DNj05TtSet@g!%1|9#}!I`?ckq-5sjP z?hOiu`@PnoW9McXmeqQit~I3L;f8<_Xn-)I6PnM1$AdkP#E6Py-V{S(fN&aVoDoLH zVb3FKK|h$lNRb&pHX0xr&<)r-<*effY8dHVPaO>Tv-OaE=+v@uP30E#{J=|EOe4q- zykW81q;2Obb-YaZg8EnJ!Mdc2+Q9W#LqQ3gdcQ?qnsMlzGbDoKRSXmdJyv5+rbTyt zbiNtXGOsQrL+m)B!ERH>aR#I4deI~&)C4Iy&Yz}I7;c;l9V>(v|xlRVybPD31)U}~lrjLVEDOVE`gVtXsOAy~!`i{;rhh)x{S zG!r6lYr&V)z5@mKYiPBD5p)-`-ES3&HSy77%K2}&R~0jOwA9;Cq4&JLDc4y0cK#~g ziv+h?va?RzE;SpQH^R|mOen5ph*=ToMM9PPi*!X8BzoR^mafzKxeUuERZH~QG=E7X z7-$`#DU%UBkn|K1VU04G;q7p>cE{BQ(U79#jDJ)Bcxx(M{mNgZ0Wwt{+AZOF9dCZ_ zxFML^iB-o52QTir*$;YsQ`+hNy3=z<*FnPSk=XKV$AJJp-XNNl&T%I4ZhD4u?4gV? zhloHl_9xg)M|p7h42#a(T6%<7^iZUGCw0?!RRx=ZZzXvQyX>%=(*T*0l<`t@`D&3H zY}jpCbCO{RB^piz>+PG%_J+@8gmF)dEoAHTv~_hSQP;T1>DO&7;smdw5U)9El1wg-(H?RVa^?LEcd1Hk;ux*1_}PJB*P+hm z!;cC3E$x>b&o`Wgx~v$kM75my`b#MeFveO(Rv=Xp{J<+UZ_qcW@Ns`+0 z0~E@+1Cz3&M9E%m2V-l&yv`)2o=Cb@iPU4=7Mu(@QGe)-BA&r80kX>Qi5{Mc?$TSa z8IilGwPk;}^ra>4p|U?=ES(Zgc5wr8QAEM&O&g_Z^Q=a>bA+Fb;cZ7?*Kio$!E3-U z+0~UFpGL!YaEf%&1N~s~mCdlGec3U8S3a|qZb=`%2(;{YKW%LM?U>pUf4siEwb{w( zeqDd|bSld!5kyT?PGPr|>1Fl}&&Bnla~4N*f?cYf>_9&tux(UZ+i5e02s9MDq6`|m zb?HS$+qv_G2OLRJM=9p)YrqsP?P{Ii zE~wX;!E*(;o?``A(>@fOz(L+q<%FW1&f%$T;3vtP)44x-71USU8)o#X@%|E(nc>g8u||1{x{Je&d`5JvtklVz8Uv*1zDpxtTjie1s+VqLJk3?Zp4DLR%e2-xntscw= z6j#LCn4h{pf&K{E4C;N0cppSp8$fln1N>n=`VdkoK0>=Mz#3T5u(vxfGZ6s!Q(U|T z3&*f_0mkOM7SIQ$J1jS36JQT)qI6gA>AET*faId+m-rMDPJQlw+y?j zdoF$1dFGNhp>8Hg)}{V4Wld>gB+%|^gDXsrrcrHb^IT)|ZK(?}l@Ng=7QX`=a&#Wy zbMa??xx>~_5vi-+o?!tlOcXC+_MBm5JJF!ij2C;7cKMkv=@20)u?BtpILTM*y7xi7 zEsUNk!gU-g!ay{qxh&#^zIeMO2K(bR3D#SlB4N z$-Q#N@mo;NTz%VL`falOCRO0?Lnl@5HwPcXYfow2^wUKqlECRAR(OAwd5G$yFX+`l zafnI#RDKP-<5I_UjByidQ<;16R`l+)Bm#l!6k-ozvs^2SPh9@pMxO*Ep%hUu3zinG zN4DCyhreBWM9v3>(YP&8u~;$;G_aj$tm_vDB`N1vel^4ugHtdo(Vc=K1 znesxMUtSUkUuDk8>z5OL)*xoUOn7ShecX-~qNk{uOsqa-iYA_gvTN+MO_Bizq-m9N zT=YsT{T@f#c>>tkg*RjH=^G>PYcR83@3&arDSotoYCVB)McAC{6<&s4qLo4lDJyf2 zc;Lwa$BjxHk-q4yZgihXUn`uuO|`w+{gr}IE6OE8UW)kz8YF4j|c*rUyI zeK7VdhnRR}lw>5x@OLG48q2B@I>-R?{>`pjv!?-G%1SLo8I(*tF5=p?~W5%LYERXWq!K~Db^bM^E11DWM*KAc1PZtL+eF%sQo@`Y{&UV_~ zB``+HPlear%30$}TswY>-h#XK+S5;X?by~vChD7m4YYSOKjU{#>9aCkjvr|2A|eG7 zdOADOot#+vJZ0c^^zW}usf#K}E)?pLDGnra$MqXKP3n?`W85ModL1OJTzMQ)4ML7!AGU~@e`zdzfAKjuH% zgya!b6S~=vk^1c50-{M2Z>1MzG0WpIPzs6;UFEtL6X$+iecDjx#f&apeey0=XWMd^ zyk(9q%q(Z>LpsiZEkEKT-Q`FBOFX3(-9>u|Jonl%LcC`G{6#@Qz9Wjkn9Mv`374`| z2#&L^y`VS{!nFPe$;NY=f~D2izTB#6c;w{hcV}oisCo?Y*7A1^&SIp`z}8q`K)2wi zS-z~}_pjd1+w;qhs&pNKPRk!X$_rW12M<5;o1Je~18Vkk&8koFIzA2tJzo}anDAYV zhFd#l2BX=BQi&?ahNo-=%d~^vYRa^UqAG{fsh{k$WVoy*JrD001-|WSa8UT1RY0{e zmyM)-TOBL#Zs>RJ(LDFFu?rtulWo!E9?w;`kgTw+x>`ZNAC%80chLYo_m^;*i8G=Wvk0t zhoyudW6Dgnq%^{DNBET&1P9sIhrl0u+rZ{ov4J!)rgmOl0p^5KiYtX)$0-0cl%!em$De3^C| z%X}4r$LCdTnT|$MMOJSQ?X6{;iODlTpYJnrq#|z{z&x>b6~oTX7%w@T?o+pprm`mr z_l}n2tV44L<|pkSkm!-As<3HzU>f0clCQ4wxQ}VCq)pxYMD!>#4~+QUfjn3Dg5p-| z%!fnCs=B@%`a}Rj#dwuQnZq7#1oaTXd#>nzs6;SUq4t!}cjt_|9GlT|sil}{K@YE) zZw_niL`%I{V*^WUZT#@87X~z6C}wqE0FB9F{lxb8d_|tvoJK!Af343eOK9WLS&$kxMGXI&fG~P8O@c%g6=yA zVsxb8*@ctJ_{9C)Z1HqG_6;`ODPN$~IT-YcpQEh02vQW3T){_F1xB*K+mAh{6j&eK zK94VDVo07Ir<34xXP*9V)nN1RD*6>rD7-K^>epr@$HatIX8OkPj_~o`xNAW6h@7*? zYPVvkWf|89ZST+$P8K^qJflPdIADF=fln#AbURDon43dM8L5 zH!!?N0QV)J8w#RyAh@MLQ%oIrfXNfA)N=5)m$LYSv3%5GmhWc<=-n|hvwY|ynEMLe zgn~(kT*v{CbEYVaSjvMbc7DO|qe!CSkc{aI1AVU}qev8L07(=WSgPp3p^35TPgh^+l$zb@Y zV$37<*?0!PMeJKVkm@W1|3=gZJy(*QR5WIUHxEyUL-Gn9QaiLa#TZWy06;rWZ89_w z><~sv0M;zJE-a(x5H&Ko_?bm)?y1bf_)ppOwcm}#@XatAQK_yBVrNWMRww{9oNTNu zlBOZ6G<^{3 ziW$9_!ueM(7@7kv=$sPGsba}GqHMR`MKy?L37Opbri3kWMR(vqeZ-E)@_5h4K(!7t z07tNiQl{;eK;=b)IX&an^pv_EjnHLaS|EsG7UBeY;E7`7h{EH}TxkH=j0uwvIsH+@ zbuntf5`?3MS8gHr(^vztC?n(ia>cQ|Yf1xe<&M7XBUso18Nu&II{^19=j{JVaKs;2^Rp~+=7PLgKRgcTd@}pOm12Uj7?oIbCed+&|1{Zt^%q}0~ zD-lR}V{D*~k{&lSjD>kIFgk@wi1@Q>W~QOnZl#WVssE)f6@op7xtpNw48yao_RYYDXR1>2CH|*Y8*2nFDSGY?gNQY@6{j*= zA_OZ3Kc)xXU0ijOP1Rt=U(7egM;(aca9T@xDNjJkIOa!2Y8 z7jC>l_EUwz zMT%eLu(N(q6v3V!NZU`KYle{8JTUo{l+R=%49F!M_X39H<;a5S8D1QxN3qTgz!4MM z=w61eciR$Tvh@1J4$9iugxf^j*(>flZ%RSL8E5oQbG#E)NSV@oPJGNFL4q9w69Bvk zuyeSpjb#Gn;);O$cn#!E;LaGcIZO{DDm_=Iv zF}=2gC~^&rg32z;@a3}^L=Z@s*?;C428Ggl&4A1+mGW{7$(4C0AIO%gx(Skx#3SeZ z+GYA-1}z#6CZC}&OsrkHjM|d}lOj~Ygt`!31A}@a*GN07(qt|FlNqozBTh|5dhmh1 zL1~^^-BoW1l*^QeT5_)!MB8GJyts~mUr?;nPa?ZefYaZ<>%24y|Hv4B4df=D1;_do z^`q&5a|`)~9?{*Qw~Y5Bn}L2nly2t9c%!_a_xN0TZ3BZyJ*`8@Dw~^F46+H=*c&Am zjFETGYdRBv)G%BQ+h5cIsyiNCj zZ-(=;P(;l!D$L8$nl`o8=JlSGMt=sg=Ht*jG)8SU>GYUp&#$hdBSc^6{VY?tiXw{sU8JnEzD(WTK_{15@b! zWAlpAUohpJ9ICx8@N8njBT?Im|4RXoUqjyLScj+_Nmdmx0b0`2T{t0aK-&n)8`p)V zmcC)EgIW5P7-ZbbUmF!&beaxWWSX`RSkSY`A3jNdJQ)Ol7-nT#ptulc781?pwpWx^ zK?sIqd}=3K=<_^ZKQU2PG&5dh(*r&edxbE;S&QjDs|D*enVsacz--2DW?Xu@iB2V$3)PwujC9FGLQ{&)}rJB_gBw4yEfS{?H#J+tF4+8 za$_Y7ay}nCkp8!Eq=d0^E-I-RLjtCISvo2WzkkLa=IqH5sZB#%i%m0K>;5!;R3sX@ zod{Kz%jHp%UM#>filpX%=?2J9(!aB~2}*2XvNvv}EY|fFk(xG-VPyIVDtOQ~Vw)&9 z#dJU`B$740{D3M4R6gTJrbpc1RAcm?a#E=Q6ulS`W!ys}Oz4pLA zI|%SCNlHsyN?gHf4|JR33rp$nb9WLJjYSS8Rp&&X5H(*VH$eAg*Cxh&`p@+MkM;mxrC^(mNQ!y{pp&ig#DD{NLubM3I^Xb z&%!w%BQ90o__)0c)XJP=!1-#M!LV;-kp6YL9FPk$%i;Rt?K+bh1G7b+1WQlGq3!iv zIS?lp4x@~KjPgT}*yDDVSJ7BblS%0NY_v*x9n5gku5>0`=f}m@M2mAvPc{?ofFwcbS8k9*$2RBqp&oTrReL zP@3xg;j&bcWayReiS@r>En@cz&lmCv&kN@sPWiWZN4W4KI z!bVhZ5(ro|TZ`I;NpB}|Zlw&bqYTGDx91O7jp^*iLrY7VNQq{*Az*Sc@1yv*yLIgR ze4Z3GAesF1|BWF%H=#UJb0-@7wOzRqpXG1mpB;6u?s=j$9%?icx<$H=BuU;eBRY&2 z7*u4I)~R7#quW+&C45Zezs(pkZ5+sP8KwZ2L%2=mSMW(cRdfQHKc5%BrHGC7fuNtN*xor4&NExXpPty{U~E{d1dwsMlg&y1Yv}HqJw5}7 zhjbs}=b$L~;$Vwtv;)371g*?begM1RcQ#RR(l3N$>A@giYvgm&XYHu&`ScOk`EGUI zAiy7L%p{*V+F6q1%;?ymERK7w=Hffb{lTLuFuoH-KSI9*cE^{@?vZWMULPUX_{sSu zs&7q@srtP?YdDvbiNlG0Vm2Vq;}|Tx-4Y>o*t1l)G($R#SH&80D_VVhGM7YS1_hn# zR)&*NDEvTwrd~Ng#D*%PgDtagqI9m)PPcL`L%Q3ebw^fqmC|6;SA3o^L&2D{Q6>Ja z5q|I+$znO^{!GGHk5SFH@^yySIDAL`u<%$(;=Z7#eQnI*LCiR%AdEth`)?;CNR`tf z?moKbK}hzSr(kKWNH*MZbrtAbH;dEsOohFB8lpj>M1?>*D|y5DK1@EqD@(a0fS2RV zVNRwTa%Vnj@efp=%reH2KLyjJu-?qL#{hHuWa*jTGl_w-5?M^;R0Y9`S?0gA$4O9h zXel(qPTe{;`2$F4p0bDn;LvBT9Iae^Qz8(XwjcVi7#jh~8E9oPWlr;ipzai|CRV0D zL@Bhr@jpt4CenM~QrkEX5fu7Gf~P^}`ygD068cPl9U||n^#*lh8HZea zGw@vW!QI+;#2)Yp40b}i1qk6{%mw^lbHQGjwJvcz*!Etw0fMTRA<d zm(kKahm^BHvx9sm!vAfB0YiB846TKDP?k?!4x8@qsLN%WYGBxXkvu*f@uogh#5ZUE!*hz$fBXn zxKd;Hdl*-F#F}6z-nuiCeSn@=oN(vIEZ368DfgK5Msb!XOV7Y| zNihI!Uk^+^C>czdStK-Qfp*T_H~~veDN#Go^3m4|GRUGR5?(p0m(np&RK{MAHOa{A z%#o!vd9vD)%-WXQP7X6|?BP3EQy~irgBPPL$bfzGb9HKB%0w_Yqy)NTR{~So0O8as z9E*m4LD6YZP&c^%bR<)&7dQBH`@JgU9b_}bBo0PSmA-vCgSa@pR#OGp%c2N7K&gfU zmvt}U5JhJRDAE*#didwlBWEM&!D0QjbP-vyZNMf&ULH8!O?nV7S9L1jHFVg%maqk) z_DOhlgrZ4Vcf7ni>-JOLrXt-{ep^TAMq}`%PakK#y_sr#-HaRFc;hEm0mr#jSqfM1 zb*6*$fMx;Z3(pf+-JmHFE9}FYSE#wrUZ`TY*7@Z+Yk<#(sXiKENY$?SkPv1t=yBzz{WQRSZvkNh&18ny!G@Lr*%=5!VslDrV~{kG6N>w-V@9Dqm_@{IVh#C~ zvckW$T*4C<(kHHm`+R$_-^s(k9N zd!gagt0n;|VZ!HH2r+Xi4hIoKypa+l(WrRJkDk~Gkx}soBB|S#dza!R+U`I(?3WMR zz274Cb~fP6i{%+jZ-mTrDh?J2cX_a+bL;(h7H=(Zjyz)8K*j=I;g2Oz7-Vppg$VAW zPuT#whS8ROF>hI;#K%rHodW>$C7K!eL* zpD5at*%X6ekHi^{aNm@D+v0eT%2=MR=U*G!gW(r)jty@Wy3bp+;u)lr-h5~QjEp7k z1x(M$#|U`<^z_Q8=JYzWXl;0d+6mdQnE^FN2A_M}f@7&Wq}wU~EAvuaruzb=Ln{~! zUzv-vgDxfr*g!HoH(_6D^~wb z%j&EVlKb%sLtrgp;Yc;HsG9@VZ{g@!QXoEtFKvY}IuW_h{ba_w<6Woa`}N-OAyX+f)3?7Bevfm6KXv$nC#>{eX*6!-9wzl4PQO_3ej0WP3H zMEc0QDUcL-rk_)s@jbDy3I+gh3I?iBoE&)&WP!c0tbkj?z}gzINqzE^_T4Y%P&rPD zz$<&sdKQz=2u4%hB9duCQ$JOFJB>&p>}$>_sZFquv$rp&@r2AVQ=4r`U?*}Hn<#8| z0NMKblb9Ws%EF^6&vJ~V^s0|4h+#_A!A`jbkiLeNk-k?ASvuBK>ve7|?6uhk1F3zD z=3td>dz&EXbG9ct4$OBz?Q>2|yFuG;SG_>*Hz)DBEvfm6%jj_0O3!m-=cjxXx~s+M zX<&P|J02M*RQp1ftZWj{AlD@WnyvDC-$~OLwZzAD>>}dV?c%h4X_QCFKKV#gVE2HPp)647m>JanjuWf2Qv z8XW3=#NwY8LjhXzubgTKwGKd&ULXNto*Q(fKH&FP91r2FKsA7$`?oG4FUDb?^c;m^0IRwbT1;PgpAk4wb%9I8Eluj-2uEWBF1W5L1H!+eQ$^i@pJQk{j zykh`i8KAfvU2b(<|VGRSZc-O!Sv=L|n?0@pgXl4mJ$ zN@p-xwz9F;rKaS0PGW4lpmlBlEsOsIxfo1vZPuY}HUaqxq3conh4%w3 zGOQDTuxrJ>Lyg3~M_*~Ie;36{V~n>{y^+5AB7I-(GF)lBx@7MsQfGULJ}0}@c}8db z<@oi4&dNiXZrAW; zJgZ^W&{zVi;Z|ktVKygLp;^!)dMtA&iZ!vN!k_)5o)d%5Enu7(_`j}9EG57F$%&we zoI|LT#;XRdERX$h+YX9gn+~m~TubhYQ*0*lL+8M$+iCkcs%gR-^+smSFG@bs6?Ldh zJ+b}xEY`Dyn*r&h#v46Qa% ziwn4zk18+Ono`ngvf#w{8Opzf&UIyiOoe5aQRW)>TjBlZ&x62010C=xRn_ff;esZg5qDb3}GYszI;+ z%xMrvV)%CT%%v0EP8q?apV9<6xo_?&+qu_UZL!Zfv0>FKN)0<^LmgG${)_TBI4+3& z7ty{Gqqq4#&Ty&l1pF6`nODsDb89~0t zWZH`4K>u8$|8n3TL+>A*sY1Cd$ojTIhHv6Z?BnED-xI`t>WwdAqPW4Hcn6UDP&6HD z%{7j*L@kJLx^AdlozB5&}lyW#TX*c`PVGL}bl-r_Txmf8HCbKVfx za~hcoW3yyoAwkT>NrN$zEy=3Rv|IY;uxpR8ubQn$VHr^)fp*xuTX+lj{Qw z>6!yNKVBcX-wp;bUS$j@F>rXP(aPUO&t)b@-9`t<`cwt$39r{5xj#ocKXm$O%(?RT zP)Zl|l#J_^95`-dMj}4A?MI-%LFg zC%LtRYa`FVoiib3Zc4;DwvThn{xzz_>U`(13^&($hGqF1R>zI#68ANGLo-~lVQI0r zDWg!%fu=yWma4%vmi!l-Q|+o$-}3O4M1nc6`u+aOjALlOBXW7-(U*8)qs&W|PrPeM zje_sOEkU8+@l?|ua8TJc=x3w80S|R)+KKaQxIt8Q)vJP3oHKT~`kqq1Osd8u;NX;- zBCDR7{>PlNl>@T>npW!$go7-hJe{1FTjH)8FFc@odC&JoZwOU`H-} zsq_FxSDG4 zp(l^-!kWjFKPx*GECg9S@Lh3bdm&)dtKk7CpDIQ1`2rn;2mO3FQY$1-Zr`^2xA`T; zJzIPylb(HkiElUx+&ETt3v`${Y#8T^@PU6&9HgA(Z=CPUn1QhL(->NA-MMp%T!8-I z_;bCf>h0u#9IFfO*v4@5Q{=9{R&0n?JMkLQ`aN6=UZZoFc)Nbz1iz}b4Gf^RXp)p7 zcm_^<&2->uZ_cBS{e#RGjY~}X@w~aDXG3>qV2behmJDX4`jqg|f540~yg8rO zX=SvkY#*d{OWLxs&Qs0m(!v}l*PjhT_C^5oH)dE$Bb(VO;@ZNlz@G|<{|<|QXK@BvHVEgJKjUE`X7 zb)^yQo}YE4Uhai}6G)|z)k@ag1q;=sFu4{4# z4!H?;T%_ow@xIG?NSHxHhTS%4VWDh*1uLc2p;cQd-UVWurKoM_HLbWG@TMeLXEAeW zS9X8t0(;S=#ryD$!G(+bv&y4{1mQ^Hh;mzY)MkqY?B;YqnHkqd#K*^CH}2Y0{C_&b*B)etBS2^aLH04GN#KYr|QRY;&VTj(N|Z7^0i=9 zmdt)`N>Quf`tBgvu2jnrFYfjcnr69Mb7d>JpU;wO(ydy6t!jNkR7)DDb`Ycc{ovNt z=SY@PaDfo5v2iZWjVEv_=s70iP@!OJZi3Voy-gznXD0!QU?FJV>X?tnMw~dI)ycH|bEX&Etu@KxSkc#Mb(%`1$(3 z5uCRu-Gwjvw#2%{y5-dvG*)r%L2dLMD4f3TN7>8yEl4bA-LC)pIo$GYRBjvoS{1HaH(sq=r0gYL}`al}w!>fnn`%;=GwyF{&8uBuWl$&9BW9BQm>DC+_a@X@;E@wU6wxiwAq1OEgPh-W_1dN-k>7#1jZwqYA(js% z$XCD@wls<$n5Mr+7bZP7x!@3b7TghOrUJxGB#hVt@9VUYEEqt*9#R5rv|)bjc3UnP zCJH8S^DOc6Ch}kwecYN@+*c$#ZM7T)bw-;5Jx@Gi-)pzJ$k@N!w?BA{nb8RMd4#E= zj?GG~JWVYYbY^@LamNeJm^|AV@746>wKzkIp6Y}>Z0x@_CFZQHhOSC@@0 zb=kIUd+NRO?})*@6EX8`zMeSeIT@L`^Vzw7Yp-R!{+bksH&0!pw%-lP`FWo1HiJz@ zKFK(YXd%Hr=HjolO{dQ!$srU?Lej>CTnGZ82#g)M@r<}tFmJ9vrK9mnsMUWelKyf9 z`WYW$XYB?nE`I2YcM%6Wuk3xz$Hq6fr<;Q*q|#`!>@gisdw zG`p5sFEz1^QjY=^TnNqqlRL#Dac5-RNIc0yS)mHfQoLwbL3|P!u3n$wKuh}OsaK-D zq;XkbWHHHWEAMmHdSYqRS$tWd{Lt)vl)K2PDb2B2VYf*72F*iqQN+kub`4q9=j1h# zej;46ttwrUhLyu#O-<%)h-uMd;pw4k<${zWKyt)?Basd?=HfjvmSbEjA%Q8MV^q9J zWIcdp=}03viB@p1ji2;;&0vaohL`iki?Wz}CmQwRG-4&)vW20Np{J-#=bcf;YQ*T` z6#G<~vQs$zUJ8-6S(J{zpNn{9rhX|-(t^>K?kC#wSt?tjM`)+RwdYiz*I&wxt z7tI<47*~C4AxW}evS06SJ)fU&M$BX4FF1Iw+vSkz_~);S!ilfl_su=+czy_z#ty^1 zjii$;jZCF&dvb#7by~s2=d8 z&3Od~P>4tKy_eqyMvSkHRZ}D{=Eb-UXykCF_omME>IPf@JqL_mFC@MYKO&xHK4ASC z2816091k*(vnP}oI`|!i`8PZ6>5HTDWDk|I_e+b%UAg3G=jmDV$kWv3lXuITV0mV{ zZx5aEg3Wv-Ez6a{QnB+!S&A)BEL&uS^{ch~1DA5mnnLh`1xjZV0j6N`Tz8q2#ttG2 zvJJ+l(nEu*n^x@&_-p z8rTuz4>WlT!5H9>V`J!_0G?g(CfA>pHIK%*fnMrtctduXB^OhZpSsurainhdhXmlf z9!KLl&Muqwy>r-JNwgxO`t`S+?qV9XBYxW#1pViCJHzaD7V8K7z_9lBlM%pM%pEn$ zB_*o1F^|r!4Kyj`Q51H zj2dP=0Nj9eQ@dp~uhtvuQG^gqJNLVn4i2995>8$r8aw0?*v3FKmPIfzfx>Z@BlX+y zfzJF6C;IG4R2yX=b8-{M*~-6D%gb(`Vj(^au8l~yG##vAlYwF?@%ZSYI8-2c2l??R zgTb+Pv8jT~0bmteyVvJ+i}j$zY}+jA6P?je1W*jWPp%}tCu83_T;=J92Szv0uRGIW|a zC!%*StMw|x4+wiEhS^3l+gG=gUaCI)W`2ih&C24LLUEu{J>6K}N0yUIi(clUgo?>B zsC;i6wNTDJ;t*L29G5<1?l#l;7@tEwIXtoi^;o**Q|0t=qLb$uX=^?uX=^?uX=^?uX=^?uX=^) zuX=^)uX=^)uX=^)uX=^)uP%n^UzPu_Wi0>t)Bm4jEdLzve}44+myCs#iGk^Vl(AfV z2XvCOL|=WN9Ig0Kwac;fqT`QnA{i~kWJ|IBLVKI`Zs!`>9S54^IlrP4m;avYDwdXX zEWwTB8HOv9=m;qk*$iJof4OU+`{zc$uakKbzChw|+E~P_y#E+8;&f z;`==qKgsu7he7c{F7NJ4YP1-c20EhcRAl#W==QX}*%tL>#x)3HdIcE~qB;Ot-d*DP z_Pi~0X^&rCeL3b|$c-arGsU^Yp&A;9*+0dWLLr9$MUHW(r)~Ls?q0s7Z|L1AXh{)F zoD0l1m^5)wUZYyh-s~Qw}Uv$rA11akDg!+!5}IN`d%xE z6yMU=79&COh4`@>DM>Pwq3A_02lXf>Nc&rqE0aaEshSzwlL$Sw6W4t5-eoE4#Cj1s z5HHNmvybG53*jCc-ldh}PeH1xCP^vstH!tMn@d&Sx4oq+-@A{=--su^KfJo%Vr!#r zR?@a%6e4}ECozM9mA;^!$9cNnrZz%(p`lT46BsQ&5F&JaKlW_D9y%0}!6-4^dP|@_ zLEjypTWaZBYp;5le*2B094z7S%phdgAK_TUu(;DG6YOpU%I#8u67)2@P~|f(9A#VN z&+4rhtPrjnV6nPd_;!n2ojX}d-hK*Mf50k#EsqP?gtOK67?8q)B-xKujR)gB= zs=X@qpDly_!Zdg&KgC}XT+mz;FFXBnP_`|jnZQug2#F<0{tV%l&3Ti<8 zhf85h#F36PvjVejModszJ42kSfuDuiMW#RJ`vv6}h^w*+t+JDyuTf9&r!;Oz*2dlR z<)d~Y+Rqr%@l~B1<9KC5?RU_wsn$#IGciH?`Ot~dFh`h2=$s>ceg4;!)5R(8KNsLH zA$C70yz-tUXQ!r4JE(nX#y9$}u0ZL!?#Q>;FkpRRzyKD6L5E%GVKaQ{6ex@)jG1?s zZprxPgRqjO8@T|REB3x{DaNN&(Do9lMR`>p4nlc9E?x29+xhU$F3q+2dj{KzJ_$M& zdAg{M@X}2icH*67Ba*3T4QD^)P_KRp!{!>1p3^ZJ;+_jf;C&2=zIolqclW%L>mc}=?FrNYRG^V zy>)Sgyq?**yjcfCHqQO*96YILU<|Tqt~lLgBHZ`OIy681i9j}5k1#}#9vGYl)T&Xw z1EzwV!|Zyyy-;D7gKXy`16tG23@LLY@&EC3+URdwH6k$2_!ND=0oT^$8KD)@DH;031E z1&Pcm)4613cft=kapDw`Fh)dnl=u~$&2U8FX6lD5Ku>5gM7N|dqh5GmN+5P7Ec$^U za|uYF+43}oA82}t#xV0>Rokn6WOi)i!7?j31=fsugQG^hW`L2-#ctDfc=R5OKo{s_ z$94LkIZVyD+d`d?P_z%ljFt~1D-4+ z{Te==(j-tx2*n7F7#?`Zo}SuoD5Ly3_3L4KS< z=e5}Iha=<73}gus1V*x2JOl37gda=hnY9X<>Ll=e?DkV2%b8cGnAcH}7jEABc{+vg z)mnOOhWnWBa@y6ZpG@~_LzLyQWF5<)7&u8mvX-q@s-O1t>j${_pp+0~G~8+%Yha3g zAxfj=Qw*{-P!9qePVh+9cTUy>NU?0HViBRQB~{NQPAj}Qb$Cl#FeA83bkasM)8?&_ z_WWqTaSK$5+N5b;f$b!bA5tQHyJqG(1X+DB2!Q39*0To3+-y?ZJF}JJF% z8K4ZbabsDs1X8a9bR-MB={?t>9~!o4@XM0DB+-N1HX~V;p^W9%4FkGZWaSU_oYA|` zVeVY(99qf_B$a7Hn}~Fv^Ft=d?3~d7k8{%nS&lQ$d!)y#(HaN2)UtFE6gWEQ937D| z8@h%;HzD(TH_;Jks2d&gOPr=%n=LGaGogw-b)y8m?5O zrYZ^QGSAM2fdU8HKV`q<#K)#b*k!Q-m1Q-Ep`NZWKypG)0kiC%y{L@f#Eu0@i0mix%0SNhdq}9bywHethAKF zLIsncervJRJv(^SI6`L}eX+vK1Twq0S7)HX!qv3@ottMag!JmpUJ!oM=%7jHYjCJs1kj{v0RHDKMqeH$oUicXkCzhKC_`Tj!-sbpM%W`CW z0ygSH;`>wgq!<6|c^A3HW24~!pVUfE)p@DQ62n^wm;6vo@UM~mddWWj{AWb#;|@g~ zb23Py4E3RzHm&3ZYND>VkdbC;4Zh#`9AIefDez1niiRejyx-@N{Rmy94+ku12nx9{ zzzZ@uZR$`Ca)OQA?bjbGTg|==1;n0OhS`t-!fF03ze_S7uy?;}Vo5DXsmy>giR9m< z{@Lsnt%2Zlp%CjBs((VFCMCaDT{8q`dxTI5y-f+aHWD&+^;A0GwtBu=o_ct5d$TlE zuma;xZ=Ex|7+)Keh+B#&<* zL-N=1q)`aG9)xfn&K`(zO7YHWBdObwjv;meC*75E12E#zXj@|`cjklpZK%N zO;>Ia9jW{{R<(Ev&a3SZYsqSmNYu0#;bl*_W+zd}6N*ynadA4W4K(G~317em}w3(AORPt~Vyw4)52T>UF?Vf~{F!@M z98Nlt8KTk)iJC!}K-m=JA7oDxki?kxTLJEy=}u`orMz ziM_UcRD%a?DOp6;^g}aRPdYoOLtsuGC8PmsAT3z{SxE(bx4K80*4)(AGgd17+cs`2 z`z;7Vm>xF)8IHTod1u1TpR=P3@-&*glWv==o-FQrKk1>~;R0>y+};9Xn1*t{UkN>wNWaRsySe*xB{CPt%Jq zxnTWH|JDfcN`oD^sFH!?wsy_8s`IeU2;Y%EGSEqL^GEk8PoKZ~`UtiCJix+Ebf?7~ zK4<-2?EaIhsuVO62_0*J?S;Cm)3`h}jUKF9fTL)zG|2u` zd6Xc^n5>Cpt8qyNij3*NMtoZe!crcyb~-338)yLb)|j!`ebz_)xJcBYQk`=S&<61n zm6hRJ%25c`5k6sM9pO(H8!}|FHx_=VPe(0Q`eaU%VeW27!-hUHZ4Hb;(i5Dy0F{r9 zADl*?qZ56&oILAta4a1$40LiNUT5l^86?8wFm*S}_V8@_)LlxxfqD;IOG&q?jldW| zRU;xu+h(=%qmIG}|0bEE0L8-!T*WiAJMR}^aGKVh#$=!8cxyoTbwx_ly}@N1@bW`S z=S+sVPj+qC$`FG4)~l-nBydlmWz-_8WlPzQ?1x?{$ViAnByY=jU@8nX9Czj^Q&n#{tI5h{uAqvHXoi(bZZdT7wtL509N5# z5#~k0gQoktJNoCP*0*HP3^sAlwK`i`TWqoN=|(>xCvRl=&5$^a?^Phg>FSewv8RHP zurmu&%;750E?{|ke2&-~!-MeRB;_i+mYtnuV*QXjM9pIN_n73Xj3EjdbLROm!hNoT zh^Ze?+@#fHDopG%&mS*2S!NMu?oPM5I=qhsgLat4t~`3{qWYa0H;SDtrg<;A++)f; zd(GJiEvfmm(e#IItP>l4fjv)|jKSx(20Yn&okk^fhzEyK`ZSWFmy0CEX4213qN24t zCk`zGdmPlT;9u};;U>;5^6TFY($Aw3%xm?L0%+-Z`6<%tRWUTuMVV{(wP>sTFkk|2 z?F2!HOO=WpYUC5$oC7rL!cod*Yg#@ymj>z*1L$T=3@%rlTch$LW*upQYYW)&d9Izk zL#EOI1)+r|8N#85DzR6z3Is1Fsiki8B2hCKnUg#2Dp-P-nRd-VMT67!TC2NX87Xj1 zs)^w|>v}I()p$gkgYKNc4dI26D?hYvP9SY{wO1~aVyZ~DW;F8bcbv0TuWbN_L$4MK zRx(b(!=Ty=({$4dw^Pmfh8D29JSt>eqhEve`ztY3gX-kQX1d$$2jx=WPxN-iFwtlz zg+tqJEKtu=J|5$39;m$L251C(Q?z&w8;zpM*Gc&|;JJaRT?QLbPaaUunw(@-z@Ths zDx?=JtV))WwPmvR~cnB-MPh-Q!;Oxbm)2~@e%7U2drF@9Y68n>0 z?h1uJXKihq*{Oy3Tpq*F$v3aIiNKgXGHgET@H@u?ChYAi#!XY<`uyi4RfC<;J^RP- zj2jl6u#p{%SBExHfKxKeSx!6srXX+@UAEQmY>)~R`UP9E&qis86GvI4v}r=ZqC^U7%hwr*6?)Y(P#7k2HpP;6i z+?${V7Y5YjL~GtG*6xD$mf!-xlMxql&z@gkl`SA3Anw!txXIe9MO$~w0G zlm>KPA$={*FnbHRstBK3csrGR$ZkQz$R` z9wk+CPD?ypC<@17Q`Aumk zmu>;A$#C#Iq?Gm!A0}^Kyb*Yc#?J0%4C!cBFR%wMbbwg1RuNu3ActZEOS^I?*&@GD z2>;dWAb5y}EJ$P@rUkD>^RR<~%&Y(zZ`^Mku0~9U!KXSG-10{x-MnOs>f-3H7>~xq z-tUV#N?=T!Oss6VT(!0UHyr}Jg+d}si2T7{{ruaOj8u`0h~+h&BuQ%lSfom43+) zMLKi1EFe(5K+iQG)ZU*aG4L$IP@>#6nIgS(9>U3V_-iW;B`!UfjfAON6=azvXfaYD z$d{&7Yyar>#X8XT1q{Q?;>jCB5&j`b8a|o=H!krOJ0+U18`B06+*V2`ff0&EW=D$DAtjNLY)iMVngf>z@<)LX*~LhiP~k2_I3|$G z2Ll)@OUaLlVcD2caQ6|BlQE4d9veVA_&_XPUjBEPd;iq&pqmyFB#XC@twddr4J$>f zj%2q5Nx0^y0c+Eci6CB)1#S}wL#C2L<+MnW+(Zd#=8Bj!G|7w$r?TOjF;pImc5?-JlKQ3Z^}d5hI53TExt>=Y*gIM4Swg#aeX8V>L@+eytTt`oL#! zbYOSvgb|{vK`^+3w-sxn6J(q&0YPzC@Ap6DZ&guF zDH;?ZQbFJe8dkvJ^KSSf#V|x1FPBnv+3a9xQRb1U_CaP8-q-}+HX))#q(sAdjWI+V zh>xr>ddmwN93fxl=VsXP_0RxKLwjN$ejij#`)lk8f)%7vNY?MHFMS&46Z4p{ME5@C zVJPDBY=hB#*`u>4pu5-BO~13{@uLY}U@ubzdb)>iW7o5rbR`%j$jvr`y)fX~o7O!_ zl-n$i6Bh|Udz`u)=`Ag;DIG2`3CZqj2sj0=Fw4bFnRzUSlhlB7RvAc|;+y9A!a9UU z38ysnZ1R`XpPjar^Z*OWvThiRWM?()M+3HDe|WreswvHr7S@jtNxkX4i4!c8ezWlOfJ&XSbncEc;|`{ib~4;-d9wa@tJRs>t(F>4wsk*>Jx}-R+7? zSYJ;56rblmyiErh<9Ao6x?NoLuQvn65(DJAF($UVgU*r%hL=i z?-=ddAgIa&hu95c_x|QBKh!dA{W@D2s*{XhQ*hTCB+3{lCRe~E2WJN}HlLeMSY~<}Pj(Ngnb|mK>_H{}gGl!HcIXi_)l;)c<<~V@fcLaAD7FRt63Do+J>N4y@QkB% zT~&7#wPPN0#;(QNvOPZc5;1$fMwUhKki{{a0@R|M^jz2?wRRECYT^$Xoy2+&D+Nmi zOc!@00?o?BG-(UuM*W$_vWfQ7F3V+;6AS019QqmLR`FlLHr1;KMFRp38f>}tw3Xd7 zPoyo9y!$H45=3kCs%BQDWDHCCA%RJl5HnXQK(15{kP4eEC9N)Lm^IKZS=ptm&j6n#Io=~JtGpR=;z{ZGa}PIWgjc_zw~{eB_DY(i z4z$g%r}4mJAu4i@ZfW5;dVCnuTl6KeX#rqiv13ip{pOl(+jKClQ*FN6Woz1&V z`0-l3<&G9t{WUo3#(94sp2Fqdo;W)%H{m>}sy3E%VJ})c-hEuxHJa}0Ra+*mP{A6v zP&x49P+ykb%F-MuP*@8U)0OW!1fR7W%xh& z0$?*he^7)@(W|uoDyD_{bycbjX3+p?O?BIZ%HpMpUZ8JKxa#p23*|W#&P&Z?+ z;H0As%gMe)yR#I`znmPJ7Z#f4XW$2;l?6|ZQ&V(P+ep(%mCz!;YR_# zz9b(<#-F}f%=bfDl>>Hnr^N|hEAPyyP3JP2|lAu7$&hgbf96oR`xL;a&3z>R^h{>Z~+n?R1_AP#pC=q&SdGq zU>`A?(A=|~!^JKxUVrMF&kuc|3x{Lftl+xX&?wYFK?5Rkm2}`mk3l_uZhqF?hC!BB zE3;`tcqu_i zLcxev*+C}Z&Gu^E(<|d0+^B$FOf`ycUa5detVQwc-pc}l0W<(n#r~T+ndKjv`M>f| zroR}J=`RLl`inuC{$kL7`HU;zGte{t#i0M)!}y<1{$kL7c@O;SJAVNy^WVzMe=9Tp zt<3zl^1lx0pI@>3t<3Tlu(JHE%<}(a5Afd${(r<(|8>Cs`8o5~9)O93@qgs16WW@w z)GhWtTe=KWVC#n;KtI6afYtp1*;8oxo1=b?Pv#gBr6KW63V!-jM6|?mZ#a60W-3!- z+umi`)T>otMH;p6P`qBHW_;3dbQL8T+LewSmEz^jBX+&7(t+4~nJ1%NXy5MaH>f+< zalXtQLAd&i@PK)@^O#$w7&Wq)py4)Y<$k_LmVOaJR(*$R7W96HYUV{IWiOuGPxbJA zoK~SZzrOj}s$Mi`1Tc&aCPqdo_)pLA^4cUGHE4dj?R2~x%J#Uu#+2F3xbIG%(j{D< zUFACM5icAl%u?irO%JxFRr7j(y_~4(em%hTyi7ciA)&gye$LHpbt{bK@R~iKd}v06 zU+ca~n19>|Zhne;E8taay-l2RmrM-9ec8W$w#aUI$!5>;6zR#@>1(vqv2m6O7gyEu zPUF=UW#2d zlyC_R7w08ZJi6;nnzeONC9`6X(`-(HZV;b%ey_Hu_mo8Fe48Kk9!=1+is(~gi1dBm zIotZUCM$4-c<))3{$PrK5C7CQb24Nb*cXFoBS5QfHnO@a$ZFzjAd-&9wsiv3zfGf{ zW2M{$+0EF{rZqEib&os^_VT=bbaEH?8BB8DjzDI3b>L$aPwQP}MrP}mTFwSsS^;A} zqLEv|8Ks>>yKM&BD}$xFzB7}21`_KNJLD&v>DB%7Bb^W?#-)BNLNI#$UB9GZqp)vcKQg|hVfy1U z)AsB2qIx=ADB$SC7C-X0%7N5ZS=9z`JOJb{LA>g`udKmUxwCD=v8S$`JZQmW?wNN@ z%86@x*LwexFQs#%>5ET|!0G+o%VU*iNIlk5TWnxXNyvLgGnU(D9*IgTpElLFZROpE zys*owkvI$@MttG96|r4vny^4hHML6eJ(F4r*TDOZCggTSm~;{dqmM=;AS5ddC%Y-o zu4)c?T-A}&Yi=oT1pXF6o-{`eB@eau8N%lX5xrEayuJ7)Mti5_Z#wMA=^n~l!bs_E z$Nad1acv#mA7WBE0ujH)OA6Gn+lY8~Z0W%i2SYvRxNTOQD7u!EGt-GKjiVCR*I2-X zk~mx_4Ay)yv+|YAM^=a@9z&u^Mma!tfnRb-$_-}0eMqv}^9BEa*<+17u108NU~d-q z*iQfg*!+1plV{uZ2p72wMU8HrzyR>})2ZY2Q`{JE#A=9~`%noEc2k(1AuPz|sp;68 z&OM8Y-Hb(zSIm6p*+(ulc`dxULWv)w65qUupibY7GLrH2s+Dm#tPw(k-vVx8Co}V#(zE4m~x0q-pv-TKm*$7(B8y znFQV$0b`y|R;bQkuvIPV18qg@fu?$4^~6{EL@$b6n|$ zKxQ5Ck;p!o&`~0Uwxb`|j=TnF@IkmUW9=&cj47l9Za`m*BTBB$=Vt%;PBV5|>E;H( zqWQ$VIQwY!L7nP5SJzeYJU%z7zoyz<4!N;#L<5?#8guO;$Ei4kmK?<(%7aapw_far zw7I6=M2;@mqzKU`7%-QzSJ@Fs+!`MB4E-Mhjq@OYD1DA8#U{* zVs(db#5PJta#hMNO-XRafuj|58wpZQj>ZoRGlr&axmO3Sv$6t26~}oKcEo3DHjs{% zE77e%jw>$ZO5pKCANj7<(YPM2E?rmYO!vF&J*5#3FlHg zR~_fs=B1YN0{8IPPf~!UlBO}q7)61eUl1&Z??rI^e09j)-n2Kfx;D$48=h4yL@0~h zb<{bMIQ+O({iB84XZTW?)3NK^a2m1^1|2EFt(O%~DNAIMD8)gBaKf&6#0R^4I$X^( zdNLkDC)Kqf38SKG6Rn)?vZu6aiD{X!daTZZgQ7KWj~aTG=qO})s{uZMBVMTpii60R zpO+Ca67h&ihTMo`uQUa5)isO?UfTTP zZAA$)5hXgJcLtBcb@P-VK@XMkzi*l#n1HZi18-bcWLEn!F; z&kg2?-L_DNq5c&l(U0maMvHv})kCO$GRxoTcwpExppQcbhUcv3b5 z`)3DuK?h~`-x2R*O2KlfKph}s^e>mh6GN^06zAtC%(apBE@MY}T34>Shj(g)ePRs< zGi#j!4yQ*C`yONv&B?Ou>+KWe-G>r1Rb1A_TdY{`0wEW6!@L5+MB@QVF4V(=$=Ncj z!6hZRxy&bB`6r%#!W5k_#P-Fbl7zLuXRqbtYpzj)59E7K@PxiimIqU`SQ?L&bh|)b zzpW8n0lImNdx%MH!LQ*Z%wYMsq)2|)1r$35dG?4J_7+I<;4vC6i}>Dtd}lJNPo(T~ zJMJc$jaU2jxwov?%XW0}jau7+UD}v#w#qaWS1Fdb`WB4mm*tLc#WxP8Dj;>>NVrxF z#RMN)+pIpU-HVupe0$D(U?xn`U`)?(giq{;9(QA&fko$6u5av<0@0>7f7+5@JbK4N zxyWlL(c7=xQKlwKPqmzZo^gXcNnd4uK)IrCs_@}JLOrvBQ*j?pWn7)ln%kaiI&z<_ zFL4e(V)Ao}+FZ;PmWA?^Ua*OBR1Ga()}NKe%G8DOY?Xb42WAuT)(g(78(YRAJ)R z&@xbD-&X|J_Pp%qem*>58FkD?RE7vdg;3y%cJ8*V6KU^}NImsZ!h*&S3uqJv3O)R6 zrua$&$gODds!_SZ2&)mQ&?*iv1Zu9hd1w&6?bKF)Bt{JD=@Xbzx6)%Td@rizOCZn3h=G8nhT0M*@*Gj9Y?jcWyc<)&AX!Uz=0xTU$O}m z_g{-0^aeMu%u?dH@MvzyP_GMdy)369@cW%RzF6%FTQ<%j16k~<2Uy| z_C#DKnb$c0?T$*hP~9(x_LPc=#(1I-Ae zxr$p~-a-+%@87b+5jehzPLYs{$#4s9Zg;N!dAyP7O6%o>tBnb-JXs&i00V#1n7niB z(v1T-#X3=W$)eb@OFUl1=_>;UjX;-c+?SGuNTF$&GAul14zp>B#+eJT2f<)hGog`L zg|+C^RZ1;=BkL33-9oa~0g}#P!2_a~pd%GB{Q2D_V1&QsE2CQFZQ|piQy*5Tk#t!``-K*c*<3i~YSB^Wxqw zXK*0H@VfHuhVtwLKJsMc(oXv`hRzA+*y4}zn?p0DTg?K8x*vw^J_+3$ewZRS(Q zYvyA`=!nwgs7S+VqVNR~P-9Xrt@jV3QBgDRCdH z$xK}l&afMPzFCH4*Py1mi)6;If;$G_4csO5fx(U!a|H8ql023@S7)N4plcA~;@*A( z81JKP((Q`7nVr39;>z#_lywg8AtE3~4Dk336n#2a9Owxc`VNdA?8k7$LN2mV6)Z-t z%TpK1Z6>HH_(<=V#0H&PmNQG62F+#nVO)PkO(qEeJyLjp9U|GL;8TV>7@2P59ie3} zor;`SFS?$>vYESJfefrYW;aPP4vCNo_(1kZN(-k^~q6+$po;YC%)_g zV3FlMNZK202?CFOh+W>uTqHr!-WVST$0u^*l{}vb+^0gA6E%s-frWKgT^WZ%MD(k{ zeNkD|CMm>E)*a~bPsOU*3~d7vWIN<@Q600_VuQ_83KCK$VDImN8>EsL3mJP(eM>|JRBI_?9zqbyFbnwInMCI zzF2Qp6ECb{FjlGlYI8N4ySx~FN2OL6C(Z@t6|p%WIMZ@J#GjmtqOCxi$&ZH+yMl=Q zumF+N=T^JJCn|Gmm|d*$&?PS5FxDvE1d<+GFg*HCF+k~I&Gukj5#gV*lSH4Wwc>pd zaL#SRG0KSUnj_Kd=h+P1^VZ}SO_Vh5mqSC3JWT^IXLM=AzWc?X;jbdlJMhP9Y)^|! zotn08-rLfkVlYvRwzhL#Vq0A|6L?-EnBk7p1C z0eTQ8GZ&TT=RV#=6tO5P&@yf1V=y!gVC;|x%tPIDq@=6(BUNCoSpI9Qm)q=pdmngI z1Y=`ujgdEonPD?|4v6~JF!6Z6(EydQzIgwMmYuj4-SYk7anUDAUB< zg$~|#e!WIzsBQkZ7bsw#eX>%Xu18Y^A8>;Q<&dB~iM9JW)CUYV=a~p70 z1(s!9*qtPBBp+YoPx%T1pnDjn#Z>>PSD+@p9|DnK?K>T$+@~Mu51<~gn4IiQBUh?t zV{Z4RYCIySjuP*YcS0*=yQ?M1q5`gFGqm{!)}#c-&sfAZq~ci}Znnkuau%rVwtq0W z1flI3Zg0|ku3p}6tGtXHQ6~y95RMX`w7T-N-${{^;Ov#UA+9R?XkeT8U*%rvc+0$o z4oJ)eC8ApGvx;iXZ0!a3U*JU#GOz#6IYN_cElkWB7$r%etT(4LrGN4id4K%WUW>gN zQXy}sP9N6Q4^wc|lAoUdi@`fcPUjG|u~Go5?dp^iUQ@^TX}cgX)FzJc)7OkoxiPXo zD1Z?^W|V$MoB7uu!H^gpCGaD7vcE2nMR+QbRpB9U1Q6^2Fg!D$o)Snff7=~>A-lm*H0mNIQEwtl}O=0hT+oK(4|_h{6H*$rs8SAc8-w%*cZ7(3`t zkw~NrJ6x9QnOqJRtghi@>wl(PwJ{rczjJp$i0}P%b?vN{U}T-3$xvSCdS0|*2RUP$ zu91tVCl7M3WoU}%Z#&?+_Dkd|z&}wdoygmnBrjj+*Vo=U?`C694q{W?(VTf-eQQoP znvuV^@4zo|4csKX-l<*2ZEU-uelp>WXFr0kY&_LS*V+Y%5+ z<%E~q&xbjn+FP=4v`5rKbqSAbJW4zIVZm%7+xzsHui%2yU@pzW{K48bKAq@w=fp(C z!)8FT&%wOLkmC0YM5@r|gnT}pbRP0N`Zd^BW^IG#<%!44M0xKs5-*kQJG}H1%_GJ5 z^olKs9$N1W(2#hDhWInVmS0~({^c9K;i)Ulb_Z1jVL=oVfdmA z?3XxL@B-9^Rf@Fxo}i+z9gtAiz*a`$^3(>pJt-IfVDCd^_p5xGP#AmS6UZAlyRgoG zN`AR_COrz3Y~C=4?fWWGKn89aMg}Ubz57@rhoF%5ONI=+Q&Tjav&()RAZu*kQ($Hf zk66&IML*H4bZD02(npi4GY!UeD$U%U3eD%ZaZ*GdA=s%1Gf~0RR-3y-Co;PC*XmZA zpM&*QM7TlaA?Nk(T; z(PmZHiu4XX$-Hy&+eAywnoT#<DDkjt98&Z(}Y`t=J`IFwQTN@6A-ZcGBIy(b^z${*_7cnG2&9E}qJ^6LSH92gvlv~=*XZP)vrA6@wp!DmRWCL;2!C4al-f(Uvv}DE7JFASk z#-4y!BsWIRd@i}o_LZtT(0+mnogh;-29Wn5%U^h+Lw@9 zi`GZwsh>Cd%!%U@w;-z+xHAg7IQQZ@mZ@tj@fk*BJgH?Gh$!xUPHAwNZ!RN23EbqM znFp8TMg}ZRLVZ&BlPDZQS!x&?cW#RFWMvhRL$<8&+w z{5S8``4L<;+`qPyBuV3S`P3vcgr6m(MdJ%qB&fx25Aj5`DWE`RMJQ9z)WxjWADBi^ zi*8X_$+*!3vQQ>=5T!A&(@8Qs?!I!4`EAoZA&oIx!&a#=d7U@a!L=!Y99z%4GR zU}Y#(*~Y2uE|YGvvQU&%mM8Q*gODibDFAdxXejN<1@LR5o^-MQb0uCS9Ia z7MVO$D&Bd^2o{2^lX9GEr;;A8sf6Y&jvN*GMOT3R?qx=aWDE~=xpE)As+YVj^lf+C z4n`2^1{GD8VC}M=9 zcq9zj-$!ga*l2drtl{uPBxQ8zQ|@q81PVMv8~_i@F3OwO0pyu7$Z^!plJpN^+Q7NRief zrG$70@l&rzZX7x;VztD)S~N0-<5pym681}2a>deuL~?=}g*ze3q@=O4SmSQf(xW7* zw2ZKY#xhAQUCp3Hb{UWTRw4NmvTwBz`vASXW;q5$4e`K@B=Q}JN+cwIR9iK3_$O@gEr*51A_ZYLu*-E5s6Ev0V0`xW}sp7n%swG0_O_} zVUyd%;OP!2XRQFcZ^7Y!=XS8o6cIj2^`O+-tX|t9BFcQi-2s}9Kx6eH$qK77gN zZ#+D6*+0&;l}Qp*w?fw6f(!KTBOl)X=Gw|3WpgKt9BS3c+Dy-e6%tNIR2rCqeg(a)$(|sk z^(YVu5<~@Y)-yE*s2Uwz4P}LP8I)Amm87VLtkn`;Qb(O^fu!eP+>hN5wZWzir2#e8 zuEt2;@pLEgRa=wUt7b$NI9-TVHN3!9keoPV!7&v<+VZiO>K1 ze?LatCLQygX(a zZ35S#5KW29UPQSuLG}hVwRZ}>#rnQ(==yy3w~U9w7&@zTvoYLTT4x>Xum?HIkXlWx zLo|xns~ZKh%bU!i)+31pZUxe4SG6ZP)9n`B?X$|qYtu|q%%DfFMEuW7UqIm%)#85# zr~l!;{~3S&?>p)l8UN2a>eFT{vACgozfk&hy1D0@i8WJ($(=Uz0)3z}lKX~m6V|F> z#x4ae8N1JGzxMCV6kFvV>-vo0c8s#8ntf78IJU#1*|sS#q~t&t7=j3mh}4+#JEydW ztrdz0^8truY0MNIs1@js=el*jBRnDpz%WJu_{rc?2*U|_y?d;}ilPv^2o7iI0`j%M z9ys}Wy?L`4gS3Vs`+|@MfBIfdekWY3rrNG|Y_z+WD)(4r&VC-1TrF)d9o3|MOt|P* zK4yA$)MUavcxczAL|Zo97@B1%S4;B|8Nk)^ALxeoVStoSvMNdos)!_ps>| z@kMI;U2~>Mw;D`5-f*}X;y4H6$z{1N_(XKsf$}{of@FE4#P4;> zQrsh_$YE`a1*Cb)$Q2`d{OuJWcLa*2l0`XR2>&?eJ?GK;I6vss5u`tbZL~r&(Xj_E z4%@&8fd|AzE1zLrdRYL^9qrGXD!_ef>_Xtt7e4hMxRKH98Yq&@+Yi&z1W4M!p!Wwk z92}%;K5eI3O)J%Jj~Yzx6O$jBuGyQgI#V5)mA5Vc0!MMOqrfK&uJZO`SbTbk9+GXv zP%>23@372qD~D@luK?26jdQ|xr|$>nR;|1@BcR-vOi*#+ajz@q2oIhI07Ak31_4b*L&X-GJ5PBO@V}%lTs|2ko~I$jw`3 znE8@F;e`v2fM$HDKK`d^`Hu?YziUR={z^R9{z^R9{z^R9{z^R9{z^R9|JKm6 z|CM;K|CM;K|CM;K|E-~C{~MY8Z)Enrk=g%7X8%{@|81T9f2c_QU($p8^G^Q#2k~#6 zJtr&Y|EUM*|5u&8!{s5(L@iLGdnZs2h$Hc+J@InQVs!x_B8!@L}G8|TgbcmPMKQQueoj$rd88=%ZT ztCIr_U6p+;w=8OEqWtCsC-KSdkI$V9&dmFM2hLcw1&(e{lX}#KKlF6|novnyW;2VL zXlD=8a`g7mdpz3tcK2oa`+i@(juJk#DUkVbOH**xu5 zesmaH&v*DI6*r)f(9DSV$j4boFdH}x1Lxaa77z|>{17;1N=}uZhySA^%;Bh{Uws4N z`O2T5*M1sL-JDr&K?=sYcyd3C;h%ni5MYh!R^IXYcxSoJ!0gT_OXj^HG)+!7w7;W{ zqf4dDlsi(eP*E{gBJ>T3#6T^L=XU5mF4;`kO0EM-C99)LABw){()B95YOC@H=hI?u zcF0ZeXFIB;TVT9^FW}|o)DnQglWNdF6)eOD{)D9oKjBd}`RVpD%H;axkW)ho4&tV- z!{61})iNkhZuS(I&G(iK@ZvkAQFcJ)WEtW%4`e~djSnKZM6M$$8hEwJ{K`~$PZ5J% zj4@7qCa2X?x^d#~CB%1Ybe*RLqO%4}YDEY+jDcOZL{;g#Or23Ed82?3vrPRsW-*R} zQjqH4E5-gWH({R=o&_5|;MwX3;?YlqIQYTXk!;PZOV}IfY@L2zNxV($jpJhxaIcwag1SM^2m-xT@8Wv|EYHw^ztr{529xRjm8H z`q`bGfNTU%xaS07P-s4oir1zq=*pemofyC|H9UaB02($Jln<27FPXzg28=Ib;m6UB zeiVcZwF04xQVv(R=RbGUE*tn&B#L2%wZe#?U?2rTFDn^#$trIbg}^>ed@tPuQ2%pHM!HHN7e$jlCHmW2E9KideTOf%V)*8MRY+ zR36wUY@B^0TRoJS+VS>Nnf>V?Y*W?8*p`Gm`oW3zIKKzARzb4#+cZE5yN*;MDgrtX z+Tq@uIl)N(NST9{i}%nuTfu;@Fd`CD=i>Ni!wOqwnQEM5=fj#|pc%;d>5183E2ZB}o8Gop5Tx3ptTk=k$Gl zDDwgq^47ZG&!7``Zei zqefwN8N#X%CMp=XqR@}q`ner|ixCymS;%W-_RZ+s!wj?_J3rN8Wp3$D9F!(|j{olJ z+$c023vdP!`vVc)XdPbum_^6aIeScloPQxQbGqIfVnD_!i6+y7{NT6m$ zIP%>EXpDT`wPw$zJ{mnv7HZN%`w#YSbiYLF-%baNx4eAAf7SfHe!nP}#4FNeXBopk zMVACJezUO!!-Fwi;v6};YD~q6gO_*Ewu!Mm`pC&3@(t1M!)Bo~$7tw19fa}95s_HK zhT&*py)FbvIiDDP?YC%3n!PH+?ZJZVhBW$C>|Pvq-3zTBQGb;dXOAhx4d;R&CWCU3 zsUf3p4#L+SazIvx{O9WsfaD$MQTm{|vMbdPZ%*ok`;Pf)cAJsW4=GLd4`=7>HbQ`p z0-OydWbr9f^vt^f~LF2&jx9C&~e^ z-bMA0-_OVQVFNjQRm?eQ+Of#h*G*n{{#rVuWXAd!56rA98;H_k+hEbSwWtRa2i_#} z&Ddf;OUy3Sc5fAYHuK%rKLX8PiM9JqesRNDaFQN|StL4n@X$-FIur||m}bj*@!dZZ zPs|V~u}W&4p%l5&v+dbq7q!4iskcni?73M@2(>#d7R;cC4brKGF|rkKaBAFf{1Iez z;82QBqUp5%)O{IKI6p0Wo?W=?sld51_2Z)PWoJZEvN;#}eZOa27ZeDqjJ=o`>4t(Z zP=`4_RmbTK4!&8QcKXf!(sKxN3wTY|p#~%`X8zaT_cjSMh;-)7ielUK(Qanm%PFYi z){gRJ?~K2d2?(o}w$$2Cw)GaA)qVfA_Cjb>Qt@j0-eV-pF3BuRVakZ#bWs*YkeU#; z!lG1vxS%z`vd4v8M6AS~C*+=qF4OWhLP!Wh$4;IUf^feiWooVr4V?r*v^_%z;jSzn zR$W$;FOMCxCypJ&A_2r1%A5MFAs2H+R^fZFkVF$J6g0+#pgvlqk@AL zWDqq^a$aaHrFG`cgON~~>M~oYXoSc~YC5uq)|tOq2t3S?$uUpgphH+Eq8L&OPHk_UEO53OrwD8n+&2 zVvX4|UD{)`YCM|d=86CkOF~I+oR71pD;1I>rU1lU#xi~Z343vYbW@4pTfguXSHm3p zUmCV}4!Z!=-4?S}BJa>Rmn#vrq$*GJ7yD92gSw$GLujkTU{xhj_VGffjZF$=-rLL1 z-NDO`d!C{8D zKaZAQJ#4|Ts|Z85%-2!fLUQ(;c>f0Zo?t-?u{NgqDvl+Hv>6LNFju`;9VWvgW;}=P|XDt;*7Xw9xa-PM- z!$fZnu#(||7ny&PY;J(b1+YhxmlRIn*3zzR!3l5bA2c`HXmIj24hWfV)|KNVv$wOK z7(8V;ysp8lic|N6Qdl! zIl;A&IwQvU(uc^vYV^hbzSqGH^+`3>ButK$SeXp zk-q050YrG282s4ESfzV7fh1z*c7eKp@}@#sECu|nLLC$wXK6cn5_Oy3fe}eb`RLAe zhrdt0#X#Nf`-=wrHo2MA5z9L#t+7Tsj&lg29cO-Week19U` zbZUvbome&r#8OQPLQs^|TMRYnO$<8!hwv5^1Ov zPU)(NI8OO4leF*a6^CZ~VxXA$#ua%nbt=mbF&f}KK&T5sJ=ws~ttVct8a;FkD6nX# z_TKRG-sj3a6`T)jT}JEUWK1irlu|Qh`wlkUG2g_CBYWCtxs1qgAs@Mz>kM#ncF>ak z?*(B^4Aj4{^M$6o41w8|<#iAtctY}0z&t8_nWJ$1G&#zaPN-fq@;)~L1u$Eq-u8#M z?}`|IWpCc`WR7{MuCaeC#>&D5{8q@iPqVRgC1~)Yrt3lveQ0aD zuf_1RZWL2`@mjUTsQJW&%)MF`e)su;I}6E2sSMA8!D97*U+B3F750Xq>9aw<-(fwKjtNlKGpnE}nXZ;&X*;go;nb(e^z)&~)-#UHI(&Dcs3Pd8bv`tgzNRbDGQE zw{v39)#(gld=Hi*=|Znvpu+=xztPc5&;wgy&OM3f%S+$4gVoKCKXG4T70&#P_StZi z+P8?cqq2I7l;qSzInSt_Q#+rR6yMibv6sL_^Pqs9#R>PFmhH}>n+*A$HK$F!Gb>N8 zA6X>6q3B!Dkwd73fe`XVGBpbDb@2dE%kx|8*%1!Hr~ zK)%FhK~X@DZs@E&fjN z&qfGs@K;B|tE3!KyNWc@Hy@g_g?d1`eBx!SEV1$vh83EXqWr@t<%r(Vl8GU&1 z+=Id9p?7?4uljyIJmO%HRb9qSPC+&lNCp3Tux0}-O9zy?kx(zumyQ$z&ijoTK7z-F;@4Wk*!Du^gXM%W@n%BpX1xqV@K7{m;~E zs-ee(095$)_cw4%cwrtfXq!8sRgiyji0w>(zoLZY*8<+aFntFh@H+e{)E5|bJ|KR3 z&E%*MP1Tzf6{n(yWy#XS-8x3%w@ptV?p*n~elL#PLd`w3>?q%}DDd&@)(P+(2oCeP zCqVGsvh%k^{}igJy5DVWdr$CGx-8##9Y1d`9N+ba#Uw=MMzp0F`(w1ZjOVIy*Lp_U z{yMAE)<3?X_1J3Xk3e9d5W1d?Pk(8>WOQbm-RGUf5Mw8^)4qZ+_|A`YJS5M7-8N10 zI@8pB0}tCwM%lPY<&j;5a{>^?euc4*=%HxmnFq1Odpy!A)6+HdI#%OtdlnlsCqfrA zY;2O5KJS%0Y}-St9Y%?Ug?A6oPG{tefrVdYoTHc26DA^KN3vj}Gjw)WbLTE=pxeR* z!TcJ$-_?~1zDeqZ>O%N%zhP||Tz3oku+d?*k>>^Cs9X9CKohv2_sDiv}|bz#ScYM?Tws?*Ifz=kWBwu}u1ST9%`S8|j3I5yxo8*{2n2CdC2eljl>rlyEk~y=ELAz2M z!niN6TzU)BU*SQaOc7F_s_eN1y2_g(5~6vSG&b=z+gEz`fK4fWFh!A?d4gkyy*BjC zCg(L+@`7D{0Cg<-5kR?^lC6W*xjRTZ_q!LR`oWqVxaifoj-%g}VB`5IDHS#*@9E1; z-MG(ZDU=?hr5~u@UXK;L-yc~o&y;sQ$$46bmq7lPpsAK~`K1p4KF7rdoky%@h&&7I zU2g6Y&^US@u<&m6aoNXu*lP(-^uTWE)^H!zB5-`-+;W5>71?djI7aMj&?r0LmC<}5 zXVuE6t8cEp^fPm)0zn7%Tef0bh1kVQQ#*Rg%vX;Dze`&-F*>E`!_7VL02723pZ$|5 zod)F}ZJ|Zi_%a_;vqax@-)Lv%3f!_2a+|e`8Yrn%w%JUvA7vw^1Pb$q?zY*$3>G098@^I6JQc9P z2WEgj22Y!uH}ID`h(cqV_l~c)t=ip~t(^$JnQ&n07U5o9foEFOTX^YbS{npUsY>n=wFRf~PkS`;T4U6doY=p+EvbVAwvcpoE4N~cz!^AJ zCWsrYw)%4ivkA@p%%Dr!8lAZxe_5)f5ZihNC`{NBqqam!rzKwY>|tbOLqg{ifDK`|BtR{e z6UPZB*Kd*2FmqONmTrm1gw#aL>4J$L3`hw=`sqb877yi6b}U{A+rR0nFQ$H%B$&a; z)AC|TKawpI)v813A2(r7S0btH#xP`xnL$aH9V=0@PwvI2rRuk2*ESLk+gi>oj(d*> z@6%6-C)}2CWlQ_{+KZX?Ov^b=5NgUSN#lxV&J3-hRXe@qG%qX#og+tLxgJSwx+nv& zIn!@U{EWej;3c4v5H=SEeldL?w>(6SEDBPzqX|XD)_|7525l6aD}Gao0nZ=soAeo7 zK*^e)1~{`>y)=viGrCi1_0R`@*ei!LiEGGrS?vGq7)naB28FNOsFx@ zYI2U+1-?UxhqO1n&_(W{x+h|~kdvjyV#uEMHmAXD*~77r9un>l)hiECjfO`2F_ zy~iZktVFSKYnRjum)t4EI0juUClOgGCDG6-cdl64QQG>?v>cpkm>QXtF$MUJ^ll@TC zuI3R$O36iU4eFI4hhGg6qJrqL8BAcB`Sq_17 zs8bXvR3cGqvdyi<-YdaOND`t zJ8%Oks}Y!{1FvWBO+u^PhT=$hQ5l1$l%Mn=n>mhFWpgm-o`KbFE#ZFNk_V-JB_jw> z^8SWL*p`_l*QN%)PzpBCR8L1kP>!nyhOy>)6h_H@%s#2=$Su?nX>D1{?nVuDe4uEL zFE))q<1AW6L+Id(jHs27neAee+hA9z9+bmRrDZh$3pE_r$gq;zYJc_IuVCkbuFlCg zIQTNaov*?HEXWQ z0R^Kt+XTuTWCYq?{&@_QKUJ4nq(!5u6IAHlc;#GXUp^ler|k^Fuv@E0wasJvzk?u1 zgy)G?35n`2|9&ij$*+}yidiE~u?nPNntT0G*w46FYxkU(F%-ec3|eH>Ye{Tp7IHZd zx!zJjqU^yFwacfn(E~Ie{dIIF5*?!_dw}-@h9ts1Wot&6CIk|#7rx6j-|6%Dc=-t? zR=cr#-J@2}q9Wef;H3f6-SRDEZKTTM3Pr!|in;K9H*9w$%kwDZvLU9vEMt`ayR~;4<77?OAZG7M5qK}zPm+&FTmW9t|LrpaF zE;?R~y8+-M0cOExj!22(6GAFPN(k}Vl)|*~+(W_*BQK2l#n$<}%7uCL&n7Z3Oz^2c zj;Qt|(0}SXp(O^suN7z9f+i;#{Q|g}PVBqc@ayQL#l)nqWc+w2;YOGJs^K5>!)4yL{wFq; z^&K@>8899R3{G(-ym1B0h6VPN-GS$i2alKt7XZ&igH5XszW^0Br}>VbkRuf*9VV#| zU(8YUtbRhaA<+J&S*%M2%*1JvJlLS*D`kD0${)pDCbI8}s`sum1hIA)SQlx0;Af_= z556OThws#*q(LI``5=A=v-(5@%RK>^`9$QhOk{PTtc2AF2$^mSGJy=1uDJs$T_d3; zvOxFYs0AvtDWZ}|y}99KH+~`G-j7%2uJ0|&X``;|RS~A|Dv7e~hs081eT<^PwWOt# zi4^^3;#4a18gvCa1x}2?)tVnP)aB8DINto8-k(_z-=fW6Ib?&6L?XLIRY-fdO3C6> zf@6e_j!otqYpt+_`Q;YspYZ4kLw5D`vPAI}oB|{QQ1DWQE>|jc~SkRSfgtr^!+^wY6GE`*{VkB93NgRfj4Ow3SxIant9%#P(Y9BMX$~>oC(}6 zrbs^27x#dQ^SNFJO8c{zOLk=W=xrLDPt?c^Cng)IaY9xMyej%IP{}z)P41Kq(~^te zuwdoWf&q(ISCfshbVc+v%P|9vdXV0#eR{be#zC?NFJXj=coIx zlZ#`H&S(2MpPE5L0z_W`$K=7a(D>!iWxk7_!1a3h+^DeTr^N@S-RE9|kJ8Kjc4st! z58&wmv|f^npq;BHxU!;WfD(hEDv`v)yMyiFS!fl$V`rCql%oE5HmN9Jweo5|3ns6V zyt$(2;BY)Us|T+xRrt7o&D$`lzT1j~@2Xc`?{m9IfFLQ8_Y)&c3Hisw^e4#stH}CI z+(%Z^+DkUvQlDh7{!m9^CWYrnaUVnmT8YR{1cREn{30X?aN3=4_jF~UdE+~>(jwzF zw*z->!i%0gz`9?NBuz5`)r*JYms@ZkgWRA_T#3{(nn3f9v~%k?l%53iTRVQUAN@0`YlB5 zDgM}A@#2;9#ys2a!sxe7Rz395>-XD|IlJ3V-F?6r>eYoO*6KD)jC*IDMdi)XgMfcs zw6!0-Pry7COek$R@ z-=$c-+_6OkGUVzpSHHGce=#O>6IR0SBbMYC-@c&KufGyj4rSN108_9;El(1PGRvC4 ztSp^wS(wWX4nMo|#ErN9{BvWPrV4?>1;k^g?GOl1o&a52f$wYixv<|hSpXdOkWZ0< z6HthIHqMJ(r$1FC8*|{?fLGKKg*DC&1LGc?AmAsxGuz6)gNOEvN_cnL3--wfOqZzQ!J)0E{TCCfTPGw;av*leXZiF2Ot)--L zO4+hJ9h6Dd4y|~~x$>vB&y$#ovM=*K-vr#Ig*QjP_h%kF$wm|mmFuhU$JEbiKJ&h0 z2%PCOPQ-fk6TBkW6-wf8*GNw68^6W{l79LU7mrKkeSeup_`Mx#xbDthbVjHT%Qf?& zWkz9n)qR5j4(N0yNk)}HRral!h#CHwc{OdNzY){gR;S3~Uva~%(q@$KI}O@|;pjWR zIjqbknag>Uw~vva&s80Oq6ryhND|qNKw6hWeD_J7Q+>^;7tRP^*ML<$*Z!ViBi-_I znpM=zpPLOi35}29%QJox-luDLT2cU6B5Gbkcp&cIh`a;QuvHO-EV;9Wk<|HG5>%Ac$uT%Arz}=NxzJpVd zubbI(`{MDzpC7wtnT9z%yePo-1;`;!PY^7wUvFgH{!Hf&p8XHk^c1&Kr+JC0`D<`7 z{;6clhp~N$1~h3Og78gLnogs=z`5N$E3u%o>FY(zmz)nUa<}CAv5*Y$ zJ`=S%k7h&qFu~N-6dmpA_#FA}A**^rx@1sgj%*_&8ZC}PopoPpCQ-j_!VrNbd&8Gw zBN9DYnDrfyNG$|r1@`}MJ7-;Wc~Kw$}lD&T2OQBNLd7djG7SF^aDiOQ_$W5?UvSrp)(qEm= z6qWls&R(m|@(q}ql+X_m8fsxim`edy0W^?Z=7%O=04%@JN5Ug5e__Af2_AZ=PQ256 z!(a~13c8c@vdN$vT#8w#^MH7XZ>#CJE)Hhy6+c2Y({l;qho-6c`y0|(Ya8~!Ii`oUCgCLV7S@xD*u8)N`;cmSVrl$Or4M@a=v9z2TeGWXKfpMZ zI-g=lzgELnq2BXlQQ*D{koa=q_cxg)icgGom!DcSik7uG`57xZxt8JcU`U6V2<^6A zyZJXVBucC$nxHp})3Z}q(Fw;lB80y>ur3azrSh0pC=rT7nV`1X`3{loD#XKelumCp z4$=K&eDBUduLuoQt~j8(0^=j+s$^YzQn3>j8=8%n8f+7?Igiap-zRso0>@P&XC?BM z??*^a`ng3n84b+MIq98`@FMkCCmy5F9qqs{+$)H*q`8l@$M(z5PAU`ec%)pR(M`)j zf1OcewEH|s1-nIPpkJL|)GdjTblN?FfbTd|52@CB2I)%ZVE<^Di{F`fmkitZxR3c- zpT=L4=-dPQukhu`(>_gX=Wm&BmL#}_Wk7quzd9bgAAeo)9&Qqg8##%l9Tx+|lW1Py z1eQh?pE6O3JeIU6-G|cuhwMhZqr=EkNBpasi&bMIxQqX9M?klQ>hBSkZAUp19<1$f zo>S*nPH+9>`oOiclqm~x4B;GPuB|FYIRfep5Y%CO$iNZess-L5o4Og1CbLs$zC=B!wofZk}WB;`cUX?HdhvW#G)NPfHfzj&l2WV_^( zLR{+?O`Srl$&(MgOE4**Cs+x6*K0sZ0$J-uszdC39^EB5Bo;gtQnkkPR$0DS& zG+wWg2-di^501<3%v!%p8u+c?UQP96S^@V&fcr z0WNB-eofUDFu!vuE+Nra2^{9$fbBe?(1gtVJB4n4^93Fx_~uR{d2DX`$n_tPQm$a< z<~;w*J3w@Ae3e7??)x(5w)ptho7i=??tu^YHNizx2Fn3%MQhs^BrA&ZqQ2V>)@O5( zAqxd)?^!m)xD6srE2}=g&WYPvJ*VfF$?pdT9y(kRa%m1jYk9uEZS}NvxLMJu7JTIL zv(VS2Am-Qq{wj$iyrpF;0_E|MrV=7v|II1(f?_5WN8F|1Kt~m%22{HNp)4rwrR|q! zc?Dprp@Ouppkyii25L9ZA#F7CrYUsXTg=r9(9)0SvB&dv$*lTwx~>gJZGBlpxqdIcYWz#lhBZPd#S6AWKTuku}#qkvLf zTTOJD&gG-R7M_%NzEGYOgMdqHH2jyQpB`o`4#m0@ zyolJ0D&ATj&9m;x*%w`Y6hyq;W5_|iOan!t?&6T~EyA(fbHs_ENjW3XBvEzA>_ZoX)aiE-t`LfjJX?2}~!!wjVT&hJC)c9+Ap6h<2H^7@QXo2NAP%v*U&YZ7cSKDW( zUE7?+t`T>%1=1%K!N;?X@bnsJC;KP(Z!m{3NNXjrNv^!J*?9 z2f+K-sBQknW|2~T#zk7t?&Y?hlW1_bo;Mrl6+cK_InYj%mkFa|jKi#O?nWkv)vYi$IMko}Y zj%|hIYDw0%Nu=_6(437q87V{o`N?bXnk-=Ss$#9*hwj719tM4*uivIF#>6()Hh_j_ z$wS4d8uDyEd{_Mpu~kyvh1{{a@!aroZFZks-8xmLu%)5M93x@duwUXFR{y>p|Jy zFQ$CVLinkC!z2FHj%0Z^&8h^gq75WrdO}ZJUKqeFN7b>5VR{HYap(`BdSQ!(aisk$ z*4B8)yVZU#@g;xM*?0{>B>AOju$K}a$^2%!&ARIQOiVE3rf~Ww@bP--^EvJwP`WWE z-^e#@&z#M z(h?Nv9_mHV8_3d_K6$^qO9wCGh19xe@iC^ckY3x=f;a!o<25jxewemWQ913|&)n~s zQjLX+&I}5)(qqXKR!TCVS>zp!5}J`YZ1uV?@KTp!3++eb*OG|JHrf=R_5j3dUbTL2lZSeIkL;!hDbTrX3x{;^{j{?E z?r3x?ZF8C-p{_<1D zI+~dBepHLl!YQQkzIS^*>jZqEB}p|V%!-PuV7Ce|fs9L6`ZXV8IQ~ z(6piqp1l#svAYmXJ21ErxYwTrU^|=nP0_h~))TrSR- z#i0M43&06LmNI?@?h^_M$gfPf&fIrJcs(dUc*lInsWv$!u#`nhuZRg(SsJv?y$JvUTMR z4i+&ZPP>fV)D_`(b46YwMFJ|uV|Jg%v=%yf5gux@2h}sA9BtyvC1B7GMH=%4@EI1# z8U$keTLtJM!r!@zpC+aXsF728>i=Ip*r-*q1mXKC67u&(L`Pa@*?a2`OM zTjw6)r(OFU;_qNc*Q2YUxZ(26vUezmX^bfmdxD~VIxrfl1>lbNcMUvKaXt7$dJnWQ2Tx$!89-KJ8~}kf;hOnZoGT! zM0|JxIOtUQ>U}s#S7amX@fOu=(evQyG%v`>^EU1lsaGneJ`DwGU!n0uJ3or#>C1n! zXCv3Up-jpEbnE1d9NFs8OVepzDe-0B_01dC3{4zg-4ZR1+Kv8M!OrrfCc}@sF^)Sd z+G|mx3r1=-ZO)FViMMRKBKXCSJ$dWmrPp2#p9u0phO2r_8w!M`M>EG<>?M($--9G& zPm#ZHYS+ZaE)8<+`FoSJI5yE02^#3lpybW|u^^~CaiW9xf)6RVO!HoqGIK(KaVpfN zUBnn|{}eetzc!s(ccI8<%H-6vOKh@2A-x&hiyHSLO1%_DaW=0qH*bLnCqwKVlt2ZN2t0mN8%)L9kfX5M{a7e}FJLvEPB=NdI-sTG-LFHU7> zQ0X-~#~Wv5a~vHSjcl0KLftZrtdW8tz6r!8+Ba?GV>B}rx~n4ZF{YZGJ!w-WUm^*q zaMe_^_<$otI?)AE4Z*s(L@$)`sh`g`q*{11a_5nbQc#`tqlgZp!N^v9j!k_81ZgIx z79FE0$+>Xq zKdQ;3K7Xo6^#kDsM{}Zcrb-AI2}O1j;Ozs_z-2*)mW@HT4T=xX{%jcrwq@39-*idK z75@_5Z1zYDr=c@tN-Q2wBaD$JRkxhMPRYObl2j_Z%7vx3R!T{tAsca{K09Rpk|_Ks za8K`xGYLzK|0TNTFOSFXNdfT#Mh#}8#GWgaB%p*HO0L`g?f2;B;10#yGj2S}j$9 zA*DaBmS6l*mAYV#7bS&+NUv%h^fbH529HU?wosrQIqJN&He|ZYUdnL9^p*F#a4wj7 z(XTp7v0jF5m4xjg74~0*AEJ?g*^l$a0nUa4c&+?QIOXw@B97Dz!Li!Z$tWehZ|bo} z$m?qiY@0p5gCLaHeEO!m(B)?ewIx{6e}ct(X@E*nNfL&YgdmsZbD@?FJ_4a;A}{9V zFW)9=;u?@EN01b#5R2QHN0Usm++&MVo?Bk-1nIoDEKiPHus(M1KtcnMyuH~;CNz< zfogo7^68!Z!34$m*5&+{W@6>GxMk?oAH~KA$+z#$1GPg1R;hT4Eg{d&6;@Iu&SExZ z7pZ$rJqbMI!PpwgazXi8BQ9}f^pcHN=fqy61+J1iHvZsAkqRxOdJWW$k}ah5eIYdG zWA-VS$jzgB$%VkSKsRZ=l-ztcb~?k zpqyYHM6r|-8nt+A);9~|rw%QyCbb$@k3=Drfw!l1-Iex=P%4tFaJTJ8*@obs?BVQW z2HZt5Z$<+IrQVpFCPJ9Iy(&m)D9KK57~X=^wMwKbpXq(Tb3Ra(`V%SkTIQ3ae}(fZ z7Q1!S`02=f2^9*|agq3jEbi1#WJ4&N637%!R3)qV%gN&KrOCLIdAR}#5}nxkvx(`3 zu}dtDmeXb?7M!D6))u@fv{QmA5-p<(pWavjiep?_R1PzRPq%(#R?6If%ZvtO;lcx( zU<fdL^0DX2 zi9X!|6f`$Ixuzxj_8>6)SYz=~-LFmt!^!QPXzm+$K@_$%+KVt4hF2D9!<&R5-h8iV zZrdWdTX9%iI=dLC9ylysKTOY(Ro7XP8Wo$9Zs#ogEC-s~;K>J98OU!h+`;`3L0wiX z!%W|jc#Tx}t#3jFKDVoUpRyuNo0+y)BD7tYWReyu_VO2Ff3%+>zn=?(cwbXzd?`l! zFG+XOMVywA^HS`z=v=4f_TOIckh=Ag+P#II9S>!9h1`8xQVD%NKf{53NdHgt^&dd` z@2TK_$`+XaOSZtq#{Q3Nf#u)I7St52(3rkt3&47J-NR#~zhv@pRj!37q4-1dq2e3ZQ5wN`S9Y>)#jK&*nEF=S@gYFIJK=md)J?+8unO5cz3TiAB?h76W+zy zTMI!e=|{>n9ge!vkoi@jMSG*sV>c8<>WjmHkfL+BnblFvG>gdId$KH9h*A5?m#v^MLB=>j5RmF0 zwx$u|6hGeIF`0gtJ^TAQ~U-Z2!iAhu#}zj1??Qw@>ls{0a_C z{iX5NMv_t#U7r`MtKmu++V*3$CxEbJMM@+@w+b8Swb1u&*L+SDc_@?x3n$e)n`l{X z@`F=S$oqXKi1Wx{vj*5XGmy=&6t+;C9ubME8U_zwnOP>SOfFn!FDs zEv9#Vr|p%bJMqy$$##Wl1g=!39(fW3O~Gm~3*`#kJ1t+rUx5tuGCmjeg+R#%mJuk> z`>6AO8jSxy`u{Ek;QY(`Isfv0&cD2$^Dpn`{LA|}|MGs$zr3I8U%dZ+OZWey8NmNT zbpKxu{O{-S-zt1oX2$=M?$3X@GSD=}`7BmV)%rVsRpAc+T~`_r3bi>n2K4Ek1?K+> ztDe&6YDIi~Y%EnLji|WDO7`L%JO%X_lDDo=H~v-@ZY@Rd?d|oe5}&N7DA5t_!u{F( z={TqG=y)}mu<2u#T7IQ|50`%(}0 z1J?Y{NRhE01dg@}FbWk<#q4$Gr^nN|r2NU#%&QDTI+5k*zGpjkz)Y1MZU-oL9U|3Ip2UBY%%AiM{qXs2Lr<1@qiDqkUc}7$xV^jG==;9yw)t_@ znCGhe)d}Fb_jG%+Q)MJ0@dlV5pFdSis+q-$K6WBD>}rwu1I~AnENXup);DHf4@-b4 zIotUq{*>$5>DMV&m}k?uCgK6r`E%>7M4;Q-BX2|0Ib7YrOqTRMgIbv`w)gNA%ZF;> zkK9Za{#!J>JE7O2PfnkwUg8v;ER@J{a`MmJ&5n>K9Bc^pErYF)^<7C7X7O1B(HE@^t>5GN+BV`1}$|@_n{o*tr^+_ zX;jn|Gjh2nPsl`tNL#3ruzjabs=2=;z%Ae{ybmU=NFIvl96xX1r+U5rz6S4K7Ff?u4ga$@@fBgiQO6wcViMCMYdOYe7lT%_g=utEP~PrC1tyQ*Yo*& zMHELRUo>5VHpB2DH_Cm2EMI)tr(*Ce(7iwT!B8e|aZB7%)6Kbzg{S}47Bz8x6vbZF zu6SH0<=7ylu%AWyzFxpgODq~*PFq}~vt(lmXTvGD4$LeejQ7gWiFFQP$Hr06ZC z;0;U=`;>GAr8f3+)to$C(?S81gA&Rkza}NHj}KF=dY;anG0u^;{tmr8-Fe|##huF? zaqH~%DbXqw1WO?Bod0OU0qK%?D=yett0Uglg59*b*)(xBLuh9pa=5e(L@n5l7Ht=c zkWTVkX1vuc3fZx*^C&IB+k9Njcy$cw^`Br}`SQrt!bV+t!6UrOX@7RS8yAmsG~&AS z{n@Hct}Z)1{}Gpz35BM+05hK6&hLq{7OfXwxxAOSz+`#^MMlwU)ql*Hyi>hH1-t5u zYurNR>9<|zUKSWfJMFu+i>ubPY}hg0$8R{WX%cirh@rZ9L$jZ@c+5AsGnLW*l=J}^ zH`#5-GlLYDEcS#yA!&`R2fzPKP7n}|?%eKRjy7mr(^use$p5ecM&hu0hDMxsG`*SY z>d2MX?9C;?OQv94Ve6l#DzR@8fmNtzS~t5mJvx;g9XM#W2FBhYkFv1k97qwZZzmrR z#aZ6e-OjKGY>S5x<$_P=Tct zknRvahY~mrGDBNZ6im3697U&W4D1}7P;x7~XEf>C<;DL;-8n@`@~zvxtIM`++qP{R zUAFD&vTfV8ZQHKuvVH5n&+c>2!`Tn_@jk>DF>;LjGBR?-ipcf*=A4gksA+>1T9LCE z?v^EcXdNZ==*@60c??Z832LTjJ|-;3z)j<73&tqnarD$ty0Z>VGv%9N)%!aTjlKOR zG6Y9X8p>-bhok=U=T!Ev=uVuhB0qnV4M%3BgochY29UD_`ys-Vq=w`Daq2Xzyd3bW zBRlg!F=nG%0zo`?Jq6%WC6udTY?viE@_@c?1Zey1y$!V8LR;O*P4T4_kRZFN$Ih9p zcRtaq*T-2ShH-^ks0qcfn}?go%Z6@4+7;sz-*Y<(1Gu9y+*aku(4BxT3$#>8UNn z2L#D;Qc9)+Z7J*3u(0@c(VijLV7J29UNu@)IhdwSx2tUDraqRy%tS~S9e2#%a$c)S z?L91_5|ifQDytYoz~>XGXLJ_nseuH6HU=#MH{)amC_KVD_@syf=4ze~lwNT%-S9Zc zYibL+cK;NP9Mg8yX8V$ATv&>AQr_z~TBlHR0%x{fey}=Uu*@acd|X5AE32=a8pFeV z!}xI+=LR2s6o8G5aGQ)5{p()-te~3>L0Uer6}3deJg5_7$I~&#UgcBW;8dxx_tl)6AmhdCbk3a-E{NIN zA~|<13IRv_Vuz-(`=qsPz7AfxgcG}lk~{4_iAACX1?I0Ng{(#VF$vB%$6+Z^Wo@~2 zYp2SSM)MFS!sn%~c#gW&bXo!47vy}djV4_ye%+7J)_B`&{mX>R2|Y}n>DMz6%?;J! zojF$eaBD4_{?pW(Zc?^=DZOzsTT4!^KobtC3?Wbks}JauHiH;863xM%k3D!%m-k0n zC$Tv)nxY{s5k1CQB0bz&_-pZch0?*sLb6qWS{~GC=6}==t~2S;)z^=qMk5fRSZtst0Jj1 zOR+}wG-IoUl-DRJ%)#R(+~a^M<+}iuQwEevafPFo{lWR#!fx;xN1xPEXivcx;X9h<|M_^=@$tPe4plJw*Cak2s zQ%SfCZ{3+R=>$W4=ayXtKlvMCdmAm@D<=M0^;bAF@af5U*N78WYTWMvlGKAM+v~i7rnEViLVs*-@~?%#vlDnkVHB(u!DQ>^R`wd!zT=RqjU_OjY(ht(jM412z~dMz_OlI0#is7iDYxxNO-X{AUI-+9Qf%Rb|1h*2FbbqS&t?V5$;W5IsAje}Y7du9Kr@>n)zp zaY0iV(aFqi`=X1Kwkcpg^+X)yi?8(GQ)1+>9y^)3=gyPJm7)SuJ>>be_rXt!&oJ+c zn~yKW@>4g-NFr;s)(>oZI2m|cGqNefmAiv&d&=-i$e?zTmMlQUH|pIA@GVEz)qRPv zS%=udIgz?e0+-*!uY%B6*EI<~i>z=lCQpPyuNa7qqQcdFxb z*y|RaOi-(oSP9$Q1(=Q}DOPDZKD#U>nhNdIpG94E(XbPoHVZm_;*iqpZ}qLL1weYM z_-Fo$vOWJh|1F`dem9_eK-;VWlaqF<^uPH{!d}s*+!k@SkS@7QgNSbuInAN-I)nr& zZtvMldjX_LwplKZ|I)Ex9^i6jV|!BBaYF$csYf%^4i|KJJ_HGc`q^^V7yNslCu4Ak zE>U}V0i64A7fAsH`c)?7C|=lV)iv{iN|lh%>ASg(a|E#8g4;^(<4A%P23Fy zXb=|*4k(?lXvHXi{wHh}9$6B`l=3%1zVe_qLR-?N5+bbhH^MXrD@4(`qq(>@LcP;Z zFtv%;tqh=k|2IMog3atLvstD6DFmM@N1xY#Z2ShwR&$qD-fZ#)PAPnkXvu@ejz1l> z4-WOX7i$2y>ugsVZ2N9pEeoF6z^gh8W82O@lZ>~{t&{i0%V^e9;{JK8s4vZ9(b#i6 z>q8f@YMcRCU~X6HAKDYjH>$|gJkxV@D*I-#`+gK@AuS(sjN$C+yE2xI1)oLZyS zil7^yE8~`*Y@R=9fLWixJnq~))d$7K!qLxZ&Y1|OOPbn*iwo&^uzWHNN0sm0sX0co%%to8o1hs zeituilTD=xGlYJ{=8G>|vBmcm@O7^2$e)vw)BCa{;ui*A156Bv5RS(LWZ(j5ex1Ea z72k3hdk-KJPeGDmN^^!{d07B{O~6TDOGlCz^w960OKTS(L@c5i0Jzpa|814i8s&P? zYFd3~8aw_LmH5Q+8lR1S&0V89H8PFyf^#$}wm8krPvjE2#dcb6d}M_^oYby$pQZ3{ zHXS`cxy<}qxL70$Xbpb8AU`SDn>C8dUVM5?Y#j4Fb~aL>TaFK9e@!QVsb4M4+^g>( z7~Pstra4L%KsFwLk%lDn4U7VxKJ4a6b3ryZNTyE(NQ?NAX#@%-`JxpgCSjlz$NGZX zj@uC&X0pJ_p99Dexhtek&q~5y1&D@ttIZC3cj?!v*6}n#w2N7GZtUa9o2ZZn=z-R! z4=yZr(cVmL^W%lg$D|PYy65>tvUPc-MY!+hjNbF6*^Kz&s!ZT|->59|xy8_?1@7kV z{ruX{5zZp*wxeCAwGU3}cEtRGE~6FH_I1~3>%(%8fxTl?HKr%)t1{$=SCz_zc@Ve} z+(cow50JInhC zH`>0Pstr<=%ClfhH$;t4J^2sjvCI@@tf#`*qpRP}&eCA}3^ZX^yVdfrmc{)Bvmz)) z$bY1P*POyH9$!X>X+55j)lTzVrJbf!RvRhQ+*D9~M4d8MSavrPAFZ3xYj+##9XniQ z8kEhP{VPMqbzk3$yZtY-9h@|pdfw3T7Oz~L*3OGNIiUM7XHt*tVpIDphJeE<;HvyaTt>kgv6&0QsT?3*bJr0_x zG! z=i4Qkdt6U%zExa}Mwlc)8Se6%VfzDXboM@VH4IVuRQA@d!(Tlkv4Lb<^XS$%L=05+ zf_*zKVC8*}6du=Oguyxv7@XKsCrB;XQF*sjg8`3Kw2SZmR1EjU`^$hjxJJm>QYbCp zZeyXdOMAX7uQ}F!PoG+%9S=H9E9{LES6=Yct5O~dfYVwFOWnFcl8*W;ovIrWq_hyAB?#Dc#zfG-<{W9;}f!vQG{1osqpK>qK6 z6weqjUdUhU0cAshY_?+yB6_Wm;;BU5pd7c=q%aOEuXGc*)I%(s2izdi$2&vJjZgBM zv;x8~OVwZv2co8ObaaljVi7^jWb^fy>hS_4fqnH1~WM zIi*VF4Pvb!ogX;KUHU<)S^Gn(QC)X3gR{&Xu(X_vI{9ig3maw%hHG^>;A(N10W_-j zhP|Rc_Bt%#VNBlW#DhX?plz8Sj3h%7xaNNk_@~jRK2PPZTHfLc*TR(Pp=D!(XX{*O zrx$iwg+r*g6u_3v{2fQvUGB1W*?!4WG|-*Or_i-vw{xN?zw8rpYVH@Xpg-~fsf=b8 z@v<|Jc7EMG)ecwzy4Tafe@-v#H}RAZTe1LJQuyv|W#%h8$C086;RVR| zbi<#`TAIBR1NV(DzoUFtF9rwDEY1rcCGLT`jjW+6$$US7ya4>FE5FOh;-^iUU zq8;H!4>x8s!h-`r65F?_NT;UMm{3F~2gx(%>dY3=hqBZS+cT?kilJAuY@`-h1o$Hn zKraEM#MbD|1U6E*?Sx1cBI#7`o{r6G#Wj-`o zsJG+-6*|1DFv4+0p$(J_j0|9@(UbyA8TC{34^#pKXl6SEa9}Sv1{TFrF{3eawvctd zo>m6f5`BII7|4|5XKYzhrDf)00TX*G>HR2zCfU|N!YJ71zIO#g*sx*3+6Ycd?%e@$ zaiUo33JP{l!^$-Uf@E6~dDA(5RlPF}R(Z@)qFpyni&(o8(nplH%TxS6?C}1m;kGdE z(4gj{Bs9n^#c`k`h(y2-8t5#t0^0W9wqOVW)e*RzA{dAev`ae@2rB`K$wD0RqmBv4 z2=f7i@FK6g_EEq+``U1ZAgG9AXsP)6V4|>1k^CYdhH_0{VA_VkNpSl_0pP>6L=JhW zS`1>qRmS|72;umk%uP_Ho~A!rMLKU%-J`{K7^rB2?FbNqBNWp}wu44#y}Dqq_{70! z;t43Rb~BU*?78FuNM*%$*!IZ+e&L5Sge&O+2_Fqf@d5uR^sSF23A0)+N`;J|Atu2{TZ~NdaPdWRBs02{4ZUgD2D#FoWf<9kP zib(ewB28vu(Q~k*>BjFd6eZ2#WjD+OE9{(m-V~SHJ3{kFbOwWg`u#^uA(FC}9dSjs@2eUz+Cp&WwDAohv!de2?F zsD@PxDRmXTJN!)f!&+B$u62&7P=z|k#^?RPP^a|6L+A&6G2??OfL?IrwIK6M&KA=9 zun;e=(zc5_`%IXY8RaY(P;PJ}nv*E$kq)K}W*r8xl`K|ak2EHja7N{uLqhqxL!;)c zi zyw_x*W19GNB!X>=3|Q+d66SU!j%5y7p!D!J8dBK=jnqC%(_Q)L9{VOjn=~^vr1=5h zR8)G9_`E&hZhxW&nw%f&qE1OINsD`t(=MCx9Glg%Il80k4)|T|2ThA;*rm5{sZ?dX zg>zg|>C~lmUXanwRIuKS-X&j9pRP9(VL}VN8H2&hcYgsA12#(kFI4JZe$f9Jt^5}v zWo4xOH)CO9WBewhZ2u9ECdgWB(7_FMhvg(c!hN7mMid~RG+pEdQ3q`X3kbkAsjf0R zS=J}zuFLAW8Jd!r$z15q2i&BS5}9~=*UfH0P)9tHMX<)>`Js^Z`gf)WBKpbpK?07% zL-fUDDvhLfn%KFOCcUhdls|wzysU^eRw!&XDt_2!EAV!xn5!0lsEw7iD`vm0=nQv7 zOK+CZpzfeBcz$? z+W;g(B%72ZoIMkYsr{JQ^F7Oe^8m+t|C(kC#V|f;y}eC4S{myUXvpj|722Qg>TZ** zun&Xu4tP|Ht~!JfYEbvkpJ4+OBqI?3--ycjF^fJ4m9hqvGH3YO_hBvuHUgG_fC|`* z3(?rz==eLc01iWO6RL~@>uuozM!1`|EE-*|HvB4F--o$!OOXG|Q73|aj%|jo?>pz} ziVukL^x(sVsUhC-cczb6z^^NC3|?TgAIHP#UjN$&`X8AA{MObsjt-jibnJii$LxQV z&Fp_kC;MO0$^Msgvi~KW?0-oo`(M(@{%_JrPxo(SGd+p*wi|Y)w z0(N6#{Ix7V2Z48t@58G+NTB}bH0uIAlN(Yfe37O5l%zb&X}@swsAPBA2Kt@WBj28e z{B{53xStlZQXxn84Y>CrdR91f$KkhVas~wdv0gNBMbyvDWSd|8Qev>)%o zA$g8p3t+A@y}!_Y3>h*4;SK`&o9N#WPZtl z^#Q=<>!<88Rq{tLh=QTr(M=~IhNFJKu%w_!$OCB501o-mFE;2j?I~qTY>;6Gpj|4{ z%h}`Ggz5b3*ZFwcdG#gx2Ob! zgR1}`URZn681mUfc>|BHEJ{`Fg&*USyRX@@J=O-D7aPH3IqB%~v`5wli_#1M5RzmbT>c(MN(iQA9`T zm0kF<&$|8bd~9K6e((y+#-$p?Ek^%i*;ZVO5akDB?pC-$(KgrDxmsJHj_5}M*Mfys zXZGdpui7mVtIR;A!W4*JC3KGJCVol!$5HMWr13?NRcIYTfN8pMs4q|4H9Q{}1l zj^KO!5Ahnl7OFK*@L#+B3>?De)*O)GAUH2JCW*n_EOoK<0eH;K%G_2C2!HSds@S$f zA8Iu`oatyHJj^k*8*MbMjan2gOs1^SFYD>%6qyC`G9p_rca2#jU8wG#*;m(*Ij4RpCQ4j24K zGiW?jmwIFBucbn&`6qp~-bg>2UlD0q`K>DQ#=Acq$vAmeIbS1MXRA>P2H_2C)vW_o^hB?fDJlD`)`#)Pn&xT*{;qeNDu)Pd^bp>O{GVaRvAJo?ARl3 zquMU+g??%NSIV zvG0M6uO8ecc~~6BIn7@)Vvp^mPwBWT@ZwW`L&(Z+OR6bKHV_2b(-_UA*)tI3s(F6B zzvX*{oqFOtA!pf#$2Hq_AwL(-_JG50FX8=qM_I)abUBrs$7^W=h3oeNuzlicr!XE< zK<8t;U4?;j*;1@76)usq%#%#IWT_PIojX;-VLQSko@j24Wi~~`Q)|gpAp=a?u ze9%Lv{O>$iWEq*gxlw7?W1S{8qHkTFS8Ju^5u}L6XrBx&sl)owJWri0CvVI;gz)Mw zxn}!yv~@b;DJxK(<0ioDItAAmt^8}XbA!-dyusRtI7+4Q<#ocg!_)=fuOJ+UO@LYU z>j2>ec1)!Fv?iWHW9#av_UpaPQU(9@3t4k!z2~)BHA!5h41GkjUikYjPgoTqyZ%CQ zjBtRY{P6?^D2_UB1iZyBt1i;cB2`lJGgOi?<+>`VZZNkuj>il*4%ZBXVH>MO3PUs; zk%CHp%rl5w%JtZLtn?rKj+aX?C8ZR_Ay&r+0s5s(fNLYvlgYg++4&@#==$DZfikvF zWQEJz#U{!7n%R|5kRm&PY75N;pkmruaN~X8{&$RQlizra+tn~+DBS|&u z_)UxZre7Sg?^<6UfZNmM%4%6d;8hS#5zuPWd(4%QS=a%w7dn0ePE=d5E-TCi=vX5- zc^;}nQq#4l_%O_p(H_-R#}`;C;91qQlfJwwo`NR)4-e~`;Ly}C<-pQhz~zSBV$-(5Y!w-P zSZ`Wb^jo8d$;t$5P%3D4GuNd`K`(>6fp_wp1e3!8d5cq%)dM&cIjV9Z+e^Tm0exZs z$fqiL8sh*!v^`L=w8*S@%8?r07MII;h0BP&D7d_vHH7UYLy>EA!W@vGTsz9o zzmps=s===%Ng{?Nf=eMP5YzE|B^`v(H4*f1&m z0}8293z(lQkHB7l$828ALR-g`hm)~+^)kTZU_!->%@Hk$`qeG!7NmuxqO`HbO^4uv z@cB-3V?D`48s)XBYrB!c^rnotgL)!E;z{bA6LNg*4*xzSqzFp6TNyzD$7u`wi( z_DgXkjjSHh@$_qJ&^%#%M*ptSTOi)}!xykjI6SlP_z#ho97D&IHld(HaL+ofP{?jZ zjRYQZ<*jxq8}lMw2=TPg(YJRK5Y|xF=HA(i;EapoRlZG~SXVup$pX4JKxY)i>*;sv zH8)GWec?ERZWJ4>Msm;2l&)=^0I+A3vecrA1~t5o0RtV~2u;nAH@qzec5#E0-uaU5 zYT^4v5dC+Ug8*6#0~GTJ25_pdN2TDr2-X%4$sII-K>%yA7eFZyjbq*5~n}G5vO=;I&%~J9b6n#Cq z``9w2g^cN%?T>5r=Voa8=4;(r&|XKS>&N;#_gZ`1_Ol9AfxM8Q@NO$RLuaKO)s->x z8Mg;;O`XZKWk#sd+i`q`X|Q(`rkZD)hmF=&yrz;Q!CEg@0Zu^AY6pkEiZzD{wsg5JcjvQvnz@nUJy)|^-q4SOIUkdC6Xg@Njc z<`#L+r^qoIVYWMZpaZQ@90?il6&M0g`2TZ<+2E9-o_krlcst2dK2 zD0|(SO8^Qw-lN{bnX2|n>-AbUeP)y`cO4-MC&Jo_dg~kw(aZ>#j$T2C7PT2ek(u z3h{OJmhCEeHX4WB$k6gdQ1-f*`*&f9&u zd=P9GsNB7i%cj#E3OJGrsDO?OIr>Kw`IC}N8arpoBk8W`5C)q~y+|rt%6ftcVCBkc z`OzM=}y4k9K~R@+esBIZ(3Vidw3V)T-+tTHZfgDEXc#iy zbgk>f2>br{yNkPN_Gl=$L~#v^-`KTh-6V)<(zZ+ADf-Xo+jl&!UU|2H;6V|Vr$Vm? zBw<&&M{I-Z@R7N*z@>EGvS$P14n%!@jB!fbiPQ{&Sy+#HsP2zx2yaSyv5f?Q`hh?W zf910 z;)v|Zv5Ks;?Bk&Cg)` zsvG-o=Ov%?a_>%Q`BP1NdtkP1v#d*RbROYuMWAe*O0Q0we9NHs19vCdRB*wF6M!^u zZ>~tdA3(gmp^6)k!cuf^&Y6gZNxg}!L1&KCO7xb{YB;?h;z9qrg+XZv`OgKo97dFH z;igy%BMk;7gGTaw*Caz;EWGcQ_l;PcZTBLTtkhtE2o9$&$AwPs7|Fw$m2o*`#XeLV zmTex1Xf$L6%z@t7+r!V{3&avS`f~z1TgEX{5kjYPgvprq8V)fo_HW@i!V`sPn{HEz zfg-f{Hs7H>^UtJ^MKHC4l6-b>=d}ZUX8*)-AeSy-LqVZ(`>wkhjGKa>T~8+4aa6Vn zlKE14E9)ah43W*ixoONVwrti*+!Y3%(v^w9$@xs@jG-PaDNQV$fe)EK8gDgfvYsfU zWxUbL0ynH5H-3j%dZ)kDY@ga!J@sfW79hN_@ZGQIYy3fFVdi`&Z&Y26-O8S$wmgLV zaeQWDhA*to{F;Y~RSJOcsRZc;8Xr}Yaw=SLHOCPp4%(U<{E}-Qw{-K_A`$tLs)Z{i zk#>y9W&`OB>o$%`>n|V=Wbr+{9N^o1y8;PFV_hyV)ar*0Vf+W(X!VV|OE-*nWcLE$ zYF|pTmupu@X5+UXzopKtSkrf{SeW`GVIpTXg%PeX^x*eeucg(LI8H|MjfoiUS?Z{nE z1!t|2RXPG(E&$e*u3``_%OxYpT97CN%CNbZyl{P!682Le*)WYdBVI^lmHkh7tp{2P z5Bqwd)tZY+V(1n{Z~4D&31+inX<7!Tby|K_tr;7}K&aVqEv2{e^FzcYA!wmzG!@y% z=!fDAD&FRIRM^BPEYSRJv%iMvsPVq^Zb8y))o;|=^i0-9ss8`rG-BHEJ9JmB;=)xg*kohM8?)B>uL@o<#18BV2KmJES3f{5-8p)1Ea?n+m&W77<1GM6d(=>F zGAoV2&Hn&jKhFS3M7DqjwG2yg8FiA4v&DjI52*$xTumIPX3@q2%_!K8*PSBl#?2Gi ziz)7izY{Hzxl#=1EjV5vE++THzO=&40`zD<*9t2n&`HS5+qfEPCH>25JUvb|H(eT{ zDLJlOBXsY`f+byppuQJWfjL?OFyMcM5h)9wEL! zGjW9CqN&0oHg&KxNC;7LXSHJXI|$qixgWj(`; zx_RzS`YdzI!Z?api;y2tGKz?;0H?G10ozZh;En}5EPf4%XhJcgQ@cP(EOwB5<|rf2 z=C0w`i1wM51jY{myTEGp9}5VBv9CW~R4Yas+2U?0^@q4OBfV>M9?i`|_rSJvHU1ep z=?0>zZHxgQv-ER{%46uQq{cFy3D&6r^&4A(MCnCIhb1f@?$Z@-KH*X_Wngr(bi*A=nm-s=!mi{(R$Usr=(PJ#{X1 z^&%lNCE@QJ@kS`u3TD;*WCYFcX5ciDCKJnRYV81;Cu-e&3z?Oc1$(BG zTQY?vl?ryuWID3|$;~0ZU0Gg}?Q6Ih^S!dOf?V}9G$gkyCePLrE7axg zMie&r_FP`fY-l-cZZtLl-*M#SqaC6=)6iy0HCqZy{fdDZj2$K~$5)@Pn@@U7*d}To!XmA+iuWh^=}O?<9};-S=j$&J=z*U|;~RBqPhZbksNjJ@lVT z6hsA7egaV}lD7c|ES)m!4KMjg3Hf|y&np=t%#6qLsz;kvs;TkzYE9DCygE>V%e>4- z=Im5U4%$tuN7AayxMfx4XU2vaW}fJnqQ>h`<#|}{jMeL{shUuQcR+#hmvGrC$94^CI2gWfVgL=o!(^YL<=h?!9le~=m=~msn$sbF?pEtsaXM|% zoKvJ=Fd#vtvE=f;en3XAarY`D6w1*p9_O07*XE*X)*UfLo1Pyp8rN2Z#D}LFGiom{ zj(`cU#c6H?fuS)2C%NVN-*H$g4u^_?W5+LT&Fn@uX-Iqs*-LXVsja9_|xsyR_m48b{cRFul5$L~Qzyxq? z=%FVcYDezNGa(-!(rEuhIWVK68tF#Qok+iL7=iPg2~RSZg4=xLpY}4nC0Y_c z0l7y?Nyd;?O<}=Bz}oda>Q%)j#5hXEtu>6 zxceQ{q;|R80;YFE(ET`%3@HEKE{*@;%Kw+V)6@N%s?*c`o2t{({hO-O)BT&Of8+V@ zYf1r+o}T_MRj2<;)#?9Ib^5Hk)y|67^^4`a8PC_9kIdKOWdX&D5h-SV*lC4Q zMg#O{%U!$dcartjTlTjm*5%g)sfYK|%{}h+RK44)%;fgmw)puEpS|XK1>7#lbKXhZ z#Yb89bJ9Xy&!_BT7az8dOYHwL3-A9gv+!yXV{N)mF^f49i=+FF(OY7k+j*GYW2+mY zcG4_qfBp3S5U{grusiuqnvnPSN6kcT?!Mu}e!@Mu*Vy2TT6o+YTUmwb&2?wC4fus9 z=@rE4P47fAO}Soff~^bd`eA%^YIP9oX_e4=d8%tzG2|y^E1b*B zIY^8j&ur||k`_)FVW*qx*N9K;pl3q+6bf~c4c@u9)Q?Owo@2$nVNC7V@&NY{0 zX54J0-W>+ENW@<@a8~_7DBOrZ+ocT78qy09J^Cr$9z(=&a|4pf&Pz*#$yLKd;`a zVFhA1fd}akAF|*87p19P!pJzf_V-UoUm0b;t?KPFht}yl+J28Jz%`&h>thD%JWghR zJ-6e2e)d<+&Mh=o()t*lUh%kyk4u!_b}NtmhP?$iD zRcG`04TI+3m#{fGuSb4o7FA2WYSCOtXBKA;A?U8?#l!ng?uWZw@3@HqLlF;B9Jv{t z0eKJ54l~516=c{K!HdDioX5DC5yc?B4^-P^1ooteM+{ITBs9B)9f0qCnt-3XX^?jEP4ov$1;{NP1WaqRDYq~8uX1tNNKQ*p}RiJoFO)7sUvB-UZX&t8wW+e0+6kxP1|=NW^Agh@r)T%9=}aIz@!6T&R2n zJ*o(|G`B5;#4E?%Vs3ED%%VYfTiH+UodGt!y_>(+vw7DAVRme5SR4~#12XljYKojP z4i$!c!=g-~mLztRha=Zo#Hd#8&{7V!ohyQ!9YevDA)hQ^cg<7SRvN&Z&r8*UaJEMA z#_9I%H#%kNs|VYd+^>4K3a{cmod=H|dXWWJ18}9bBm*dihRQhlcOZ8D*O?_2e|Rb2C7L7Umj`;;8+t@>EQYMk-lXf?qxu19#yULARDoGhu$T# zQ{ED(5Z9n5!0X?3rk`r=-~2-$1Joyv+_c<|57Q?Zac3s${CD$`U?ko*Q^8dj&rN$I zGcKA1G2W7)1cf*J)u~8%wcL;!5W#!}J;>$4yGnwTg_6~kWMg9BJI*Z*%@0;vn&7fa zm)>76{ zF>N`$jj1_+g(H_Pda6)m;@lrRyKFts|4k$s8s@=fc1Eq94mqj= zMmZjMt~4jbJ@U7I=?_mjWWfJBHcCz1ITw~qV}4>HO1Uz|)Bk>r8I2L*OVoQ%=(AC^ z70JDK^o7_xR>(F-+vqK-V__jJ#h904%xbkV98uU}t$1r-^H zxxOLUjtJH_X+oryKPm`0Fmz&q679=UsVhYv61dbRtYO43B6ojukxfuHEbGl-iwGfd zRPyd2S4msFqD<%73np+mgp{y%ZZ5eh{jq0#31Zvh#;1HajFDM73h`}LuAc{Gn?VNH zBFo3`1va&54!E)YkKcoBNyWIS_MD4M0zNk;$!ogOGXkQqA*zR4o~4rlRkVUcj(h-A zB54*b_HSG^sr$zL7DcL(f)bIr)G~_g#*Qk7Brbx=EC}Vfp_EyY6PCG zKfQR5HBT1EUE1m11M>O`9ETa;-VKUVh2%hS6Q)HOs))dRv4oFNoYmsQ5Ni!ie7#cm zQ6}a+>8m{$?Lh#KGZOk1GZOTwQI10}OW~S1PW+ldfDpkDb`45^TNu&I&fiw>Z!0Nu zD)W(vG6xxA2sW%FP||EBMOl%1z2#HpGMt$#3=Ie|TL=WR#QX zrg~SHs+cYFOZ%xdWh&s9+Tqcj&{cluSP#3ed2Se}_nxiTrXrhbRZ}xRuN*HYh5l+s z73tUv!*5lmegUdiy3z;v^V1>PM9TWSLkClPn1lMd4ox5TEYqWOx44hNc*>RVz$QyS5ncKlmZ@ z27gY{e2!e<;Es5&zc&10IK)YcD*?WpgHh{Gr5&9+>Y9K~D5Z8IJ+W2DY^SJ!2*Et6 z4V1R&mU@Ss&jc8@8-8(f1iE}?3Fl%;taZV0f-J_3>TmSe>l>4=uoU_*B7fNYi(5Yf z9NIgnfbSiFV6u50-#0iC9BBB4(raJ;3jr*vWnWfJe`e?UfcM;szQ>%4y+lwVC5S_~ zW~F>^U@K-AvJ~2ZV|^#!oyrF_!{l#hA1xfIChd`s;I6=t_Us%FwGwPd@~5gMHlqdx`z4#6w?T&L^&P|{*G?xj^mzmJ(ACwR z1$I}xvT!6bgfb z)+3M*U`g-V4$$n@9=;Y_*1%0FqK19Fr##(vdwZmCw_9YRFKjo_MeWw~75*4hfcG}P z?EoDRj8W(0mZZtYmo8z+#;_jXf!Q&}TpMiI@30(-UD;(zF zdfKgV7`DRzB{7Nlael2rCNssE73XTFgyoCoPLJP|pyLg2PgbPb)wAU*TQbM6GmuT7 z*XJPKu%22+uDkCPB|*2v`iI_vK+jncT*a z4%$K%BSRLIla}z^2sk8dtLeTiv!NjejAd?32OvR(RKF4b4|Q)99apbziP|y6%y!Jo z%*@Qp7&9|t;+UD4?U7E-%>5gX_QovjbPc)rOqVR+#==^8?{=k8Q8Rt0(AN3%RqgLvlcGdmw7 zsC(>3TdA$%CBumJ1f`v2q7@o{Thgl6*7MSr2U43|I}KjSu9nsh%m;%H{6P$!BwWsk zkyOBbUZM^M=0#qCG&$)OD7+fc`}HiP2D!W(jM322HW0b1eeFE=Q|Sc*>S8wCgc075 zs!=Vu!n(*)vyA$UCGB)~k2jlW3Q3MaS!Nt3i@})Our|2UFA{&tFn1N!DEH?ti^z#h zcf3+Q%t%2XFLo$kyQK)(OdG~$a9E~_zza90O+CZ|FkoqL{DNn9Kqp_yr=UJ251}F^%w5OnrULe2HR_Y+{ff0 zBx;|Xy9~UMhFo(aiO%GqCCAGhI9kko5vp-!8k7sh%0>DddQJIJ>VfR%{D5uSkt|Pf zzC8)iblqp8ndRn|IoeENjw?F}v;qjALVvJZeA(6q$ri0b|6GVRY=D*?jdT@0M`Pcv z(hy)8d1W!?Gos&a-Nox4vbd6WGroR9n^yoq6@i6b5M?(NH*cXP49-EcCb!cFPGGv+&JiSv$i(xP z>4%$l05H<+b#RLZBlxgDWT93%)zET~#2ZXNgJm7)2%sXX8b3v0g&pg1<|c5@4w=so z%~W_v1o|nnMQnXcOGxFVP**>ju8q5!cDBA92@5&V+Get6O5cM+2|7^BkzQ#P*NMv8 zU~jyr{DwCZU#vf*`XEn?7yeKWH%vjclWaC+W zltsk{QLsh7K+u87_FEP~*NQ#RFc-v+w64g8^u!=0!5=r5fy5Z@FwuL$K7+0Nx19iZ zPuBd`dryWc2Iz#PQ3GEs0L_fC6#%wHWl*oT^?Med5f5wo>WV}J1RSa>6|+r;)Jy{} ze@7%V#+pIKlLP8l2?d-*b&4}b{4$y~w=XUm7fgVUOH%W6g_=`19cQNz`pXa9*(caO zU#bZ@g%<57dcl{aEA(_dvkiKTa{eE-mDyCs>?JP5qouYAkM~g9ecGpWz=cgM(yjs# z#TkIeR}ywO+|{_t9gNLTPTt_+`6dKh_Jv5XN0YHnx314&;FCx1v-SkMM|bjyMtPNz zp7jJXL3b6c%W-aXs0!%FgLjHLm60WF>c-=HO%&wg2b( z>i*BQ#NeOn%S###&cw@h3bCNJOH8p8DqdV|8QN%oE445?5PlzxyA*`BqX~ zt~(%kH){k?m=jKYnS4H9$fCwes9;ODke=)lzD8-=hnE*3=yY!GYj9L%&HCW?{Wvk2 z{Gh!$J=sv>_3?&K;hmY5xkYn3sJ1e8+|#@vgjx2+9(9I_+d~n8;+2gLxNJCOB0-e= z6zsX)+cR?8lIYgKH*jjCOA3HO_X4bW?XNl)qb)b5`|ujKjK~L5Yeia7VIU_9>^)I5 zSLFZh+R)}acxk6Ob>HG+)N_)EVOj5~CEBZDm4}jE%DNf}H(l}F}Sft{hs%}Y?2a0I)ThgM%T#jjx4el8bmXk}NS?&uQ>?~Vsl)I5 zCg>ZrD8Ji0&Cs>D-PIE>FCD-y8s|Q*;laq4Kqaoc^oMUZnds*3MN+;}A?UBM8jRIz zds0#g;MB+_B$aQf#*VVoB)QosDScprt7A`Y_EacV9mH35i>L{a4yN2h0*Eb*xjkba zg^H9=n?ufh)m;<9P?*rUFuIYZQ`Ba@_qD@NgkpkM(E{Bf5bmu~&C&`U4z%>>r=xC$ z4LXUz22|1gg_M8Px_KG-_oQMOo6&XbzQ^fmG%L}~qJl71p?W-ES8*C8bN1R$piRulv2)G~x;6GN z^&>cExlG*ak6L$WF#D%kH;x2F2vJCJ3nJl6IOO!zdbhA?UmdymJ@@bZPlevOS8)o| z$!Vd~I}yXsK&{iwlh_7HhNeW!X^Zt*7T=9+i=F#|MY@u*rIx#o&4NZGGO$)p zXp52(nn1bOFS!@1PT@|dIt*QXEjcHxGqR``YvwT4UJ$5LGggZd=1l0Z-QlT_IsERC zI6)8?avVA@&Va~!*ZPjs=M^%a>xXV=10|Q+Id7w&0BHS2+ssnm@JqWUTN-rrx7(c? zi|(~iwQiq8*?uVk#r+?>?jMLOHr^u>@Z?e|)D9ciIC9&;sN+6{jU;@bD@i>)VMaAHo`q6>S;0Q_`q^Dw2`(KUXF4dr&8AN?(~CRL47%iQePS=|{AfA5Q-f?6!;0 zZ7#pk{M2dJqL}|CbLAi3PO+a{9?x!;H`**}tz3To9gD%pVof!9zpGq(VW=D}EuEj5 zy3lY3!&2kUyO}L*-HSINR%l6GRZ)LqqVq9%JsgyR11UAntEMMdqiXM2Q9|N~6JY|D zk-=ietsvxmI>hwsk^2o@^L8G#mPx6R!PU@5!m<6)J$)&bqI>?Rd0o?Qdoc-wc0r7e z_9t?zmD#ez5DCk2&0W$LUl446GLsr@H9u$ux6FrI*Wj(Cv`?_#4xi4>L{xO~v7a9> z@O5J%cs+KGNXQ+l&)vR=DLy;Zp4#@;@aL4)-39?CPcSLkzG`u0;^kk-F!yA1c}vIl zem2M#J5zRsaA_wfdF**;*P@tUJ3LZd+Y~j`1)TGyK5Iu27X*I4w3VcNP*Ww^Y1acq zds2*N(qAdGU@Ko)MqJ0asJQCPp$6% zd=x!N#uAGGA@Jj$qv&T|5||14;VEk`dMjho)oJQF5+-zLoPqD?!#Qwrgj_va3MgV< zexZ&m8dRVD7}G4EcdB(6oz#ag4Y{pe->*;_@2?j01E_J@7S*Jn8G;CvMyXbu7-ADJ~ z#KL}+rbHy!5t)gt*!;LzH?Z_8C1M4w^YoGwmWd{in%w00NsC5hX{$R|r_K3UQ2buu zcju$U^|Lf3p%)w0Qr`4cx%d69vD$+3&M>1a{2~!7B2UCfG(Dh8B#sbw5;vSSzLJ|D z5xs40od&+a;MImtHKpO4ugj&RlGmS35r7Z8{x@)uH7P%gHqD`MT7PRraquk1k@#}b z!Z?%<(wuGJc&V|PamZ?6Af;saIdcb&7zaR5kJF?Q=-lR)l0q3pc_`h}F_a+5kXgyl zq-+E{HVpx3-kB-9FPDcIaG`cz1Ntt>QDKfj2>Pw+V+%-8=>&d8X$pvvFqo$C5O>Yh z`E4D>o72HoTj+ygb%UCtfQu0W2I#}P?cs1q7lfE`#9?HQszt?Xqgcf#IcawWO8Eu& zRbht~Xsvnx3&Fyb45T%X+%vl-Wp6V6C_E+YI};zaDg?R`afzc}BXnFC$xi`J+5F^N zXka9GVz$wXem&r_t=%gX&TwfptYFtLBAD&70*LU#q~CEp0}LCK<)JsuAAaN|%i{LS zs%Fb*7^(%dAcvwTJIIZ)DFLWhbc}PnClYoxYFfJTWeoL(51a=-!${Bo0>tMg^btAB|-L z0c}aSWT6Bz7i7=leCc$zLNK7ugM3V6XDLykrFs=tcR?3;9q$dppeYVvasY^z$EWV+ zDu1g`s$jfk)O1G@zW0q@JUjp*#>owmbk#6#V$%|mq1|nV-t0EW{BIyH;wI{`>h8jJ z0yHVGS)_4Dbu>$<;j61lAo`mGvF>2xlTvQ@-S7~p23VXnV2`d6ARl6GT4U>)Z%wgN z*-bH8I~PB$)8{!T-IQ?-We747Znm~2;XjD1b-Xm1i={5!0(@5UTlkQ$M3N7a+V)ux zL!2QaKRjPoYf;ADSWz3JL6u~c2`ob(C^;^Xvx?p}+Na(oOEP0?RsHcgU*7pT_*6iT zHdB0%$yixgZcz{Lq|CEQ45~c9h15$f!cE~T)!_Pzf0Jn!m?*Vl*)2qhdu&V3MlNcR z%tyE`f1Um))SPcxxLpzMzW19YMB=M{51&*aHjT)I4%1MoiyVd~*&g*V5@0=f!8v9ko$GXN#jd)S zgFSK5rivP+Tn}926o(j|&4pVjo~P4|QOt&mZTn3uc~q=0Hg3cB3D5I9%=)aV&c0JO zZb;40Z$Ysw)1DkMstuIs4V^;NU{rr=0J0BRx8XWoUNFH#Mc_lqM8}Nr4hiNut{`P) zo@I9kO(b!733a=7l$U3(R-vI#94r1b-LcJuP{|6x!&_>L5!ul5S~7BZN)dd1-Eyq+8OuReSnrU8eOtrTFac4J7!~gmA7;x4K!|PoBpo zb8Vgbe-H+hK%2u=F3EiOv7Dgg9tbTC7j(`>X7X~4_{_Xxo^YNtt0zs3++dZ?5>I>c z#7LUE7?cjrktEG4&@G!eP*a`AO?zO6{f?nhFU*WwGgTB4b5$ijWY{hmgu?R(Kq-Wh zJ(mxwrY-8vhYw>*xdjcYve%FTBVz#)2m=SFwX>rHTFnL0V` z9lYhtBXfpkIaSZe5;o}UOr9FwuhXyw`bM@UrRBULzTTjr<)`aL8>nPjqi)hQ}isI-qy^oWJJk;*{6e# z8VZYpf@-nP{^PN1Qeh|WUff>txUJ1q!%D=YEtL=pSnG6MnpIW6`8JHy^R9L5-lh|Z zYb5ZO<&8p}ACHN15ho)v-do8&(G&a%;}fgt@dBKoE*Wo9mXGqod^{L3m3x0IsDskn z+VBo_#Y&Y`R-yI4OaiP`qKW+5S6$<$f~5`Jtp4Rb08AvSr-?mlg^nCA-x7aER3(n- zwpdSZ>@eJFcoQsh-Vp3w_6fyt5#GHx+9riuyP8|hbYo!o4}$_)fS*R!hVVQ!oLzc9 zFt@1~KYTZL1Zr0;tr%ETC`dI$-c78}9yJ_*+6p7?;Ymt*+X=qaOq#d^ZB;IFniW@J zxytP;K|Ad(OuBqwNPd;etR>kyI3W8twdHuxB*^_)Q}V>@tGZ-J0dcwW#MKygV0zsG zN0PZVO+RK|hTd=;tCJINfZqZ^q-Nn|4w$$-CCqh@X3(8Ld2K&6tyUuaF|GTlWf}P) zM{c&;r_nBj*9vy_*ZZTgHrJy}LMB~U&{Sc#r#C@>d_cyCE7E=kfmejGz;qQ+TXAkN zph;_bZe{^kkb%AUhs10uzSS=&qaY=8eOY!^5F3o0a-srOh1vR-Yxad}Ms@XCry=eg z>a}tqVpnDYS)TN=bct@$UriA)@%-|+GeU4sEVF7NYh8?~JxWpDKqAL`>uKQcKs@^1 zK!ps`(VQ*2%K@294EYoVIlpoRzpFr9X=LRMh@Jf;6#wiL4-rjqFlgcx;u3RQy>A2B z@zop1jxk^;vwrzhFoJ89y-t+PVWH;P{tV;7m&vb3cd{MFGCp!ueW|18r9@&YMHJ2B z9v0XwqvsRU_HBnV8&#JRqO_z*+G}>M)qZ9+uY(*^3bm<4ri4T;f}IgrF~1b{;0tS! z>qp}B=!1gFG1|Th^GnDpRZ=LRf4m~NIf%va!~$)aCccCBC~4o0^0NrZLF*QNT*i|c1?8nCCdLtqQ0 zX`-Bb@@h!KO-bQj08zUREww&V>qtyIXR%Nv*#o1u7F1sm>-g`nTDhZv)ZOhc1Yb2z zHo%w;ueFB`nkd9zVZH}C_58Lte$MS2Oh8G_Rla%jzya1B_ElXr@p(TR+*vS$m=&Q_a_A!%vs*gsmHwD#F zjH<$gq1}uS{kXRP&}0iXDmNuuUqSeUl!sn2a&S0XXV*33XJT)x?{A65Rq?@u>X4r< zCpsE;2xNqrj345+GjC)AH$_o1Z-~3t_iJJy6mke`+jIG6XC9a**TVj`AF@^GOy$5O zlzo5Y90gD34(7ZE7OByltH$Jf1W_Jm15&$z?dlGI2!+CVEq(%@6Psi+IkOLBB5~FQ zRA$)f|9sfcC^QOhKfU(avE!K_!!%rZHKZnP>rMypjNiWv6nUfN5wECPC9)<<|ZL{yaH%PCiTNZMh$1^G!n9cGjNb| z`vttZa9q&`$kxfqzTJRk>Anc~@ppuN4Qj6rAhhJYW6R7R&hEq#nne2w>5GO)`@t>= zU3U_qtD5eY%@HXe>~j09idK={&=as9N)K|iR$bcr)!9!Yb2mQCFw7} zhy(;;Nbr00&x>5*ntUQiDY2Y%7mFT{>YM0yNKSN~N?HWps~T^R8qxuqB>wuWj)tpj z54Y3Y0%qs0hp(YUJD7=rNS7u;PY!d{T(IA~xwVbAyn@&eA_0^_FIz zsrP4^)qkd$;=x|~+!!iN7>icCTPA@_->_7wXD))=Tp&v_ z1BED)5Oy3Ne*!v0)Ae>${Lwc85#iqSBEk+qajDn5V2ZwUFkfbEH;h3wwW$+4SSn^3OlKF(&KyQesc25b9_`|%;`mvhEcBP47%Ry zodz{>8N|yZBN1Nsw}&ik3nInu2M`&y!;DSD%GL&Nh7=F-&9>JR86k80`$BSIH$?cV zIGwGZoRX_AJQRV590KoO{0*vjfnEJ8jTs6?4AH&_rryTy?&tJDas^8gaZ~Yz{0yIv ze0Dym6SqdO|Io3J9MUwT`AHj(~4K>Nx2rh3AVWTz(Chlg3skHsnRzif|=#*d(|iZdNS`&F}YkDbz`x} zt}YQdmndE8D==tu9vLIUVJwg&^#n#(7X_>);g*w7De$d6ok?XoGY&ufbs*85z{@HY zek)CqT^JcGWl$O{=j#9~BhZH$(W` zZg$=+^tM`hv~pGqGBD%MFD7pfu zgjGjf3Xf{F!BxCQG`74hW8l$ZV!8UPHG8lggHD{gml)cQoVTKbRc5`wRB5}olo%Uz%`-A?Zejq51b8gb!2H{) zSFbfZ91Nhx5Fb9Cx!$wWmudcTs%7QBKGvuRGw(T;nbFPTuu>^;f=<DE-uJjE{tuTS%T4QNmM5&GuY2YM*q-X+VxEP;Eb9x#F6>21y zoieW{$O6B=Sab-Fl4t=UVS2X8Kr+V$mVP|W+(5ls0A659_=f@_A}%U~fs*I}NxSU< zEy7c*W|4oZ6!Zln_xHx-$^aT}HW$OKj5ac#-90-Z`?_V;=?B#aDiyv%W5{MrhAtAG zD(EX=KAOS2xXDZr-F+A6K{7`gk+D3#VPhP>d%4w(pJB|;_=K$^_+h4lXE}LE*M^Ou>6nZkx(9qQ|D#um^`u&=Zlv4_MD^DFIjim3+ zBX}M>i;EV;=usz4&zm+FL$MkcW}yY2Nxozh(9ODOujL=HDb4nR)v8WlM|iI!bA(U0 z2ZQovbdH`H8EX9qLtwo<-fswth%x7$4P$9Mjcu<&t~hskyLAAGs5-c5Q^l$j_?8f1 z2X=Y4?v(QUCV4+1-uN-v>HF|@0m$IPrtAe{y69w}g2yX zo5g2|z!-PtU$VY*Q5M0y+`YJNe4IRdyza?*89>aW>tM-ycV0i4=V86d#1E+jh?Haf z+z(q=K?z-m=mO@#%nTDs-&yT*5fQtPCqD$=F2aJs<3XjE(2aP_vC;RIXM0Vh5Ym|^ zoXAQIss8h>BEW_qwl4p_J0t@t@ePZG<@t29iWbb1_)m!ABMl;-we4MoDm-^? z3bWU(NxiG+>e9r6(L^FC4pE^FEe)fwEAFZE19`r2geV7QYVUcA@JjbyJmQLs{BjYBx7IltXelOMpNO93+^G`fk&96}(*?R9Isv22sByMg`l#4?6M zPuH;U=35a^QdYyNP^P&klMhM`3<=aVj&6@nIf<6oPv~Q1cSM71q>Gh&1&QY(Ql!ST z8ktcY)#w2qV_qV34?3Ve6=a@ZB)wpRgU@zEU(3E)dYNP2kzMB-X%2C?C+u627%*x{ z2WjV-r4Y-InF*i`b z)*rq)puszV&hHhVg|`?MieQ=#r@D4RVy#Y2thL#~>bLk5Kj=bYlT!cfP%dBh% z7FX08XCkk1tot=5#xfRgP#TRXdsk+|IUc-AQqfGmonZ!d@JLI}C`H>?Xi!Qq^24~N ztV*YJ98I{`GP07-*aXV-5feSq!mj_(F_lGPd#i$qGGk97HJbk?p;JeG%vZ*bEUgL( z{_Gs06Bu~X*y?0N<4vNrNWFq(KkAT!)ZL4K^7`+OeNZR*`z~d}vA@X{VH~>+HJDZB z1ow*iVhF-mv6I0Ay8en}Ie#h0v$4t1Ioi1|XC4j0c5mxTNhSa5NiR`wK zg~P{$_SA)gc7Ia=lQ2NmcB;dg|BMwAUqlRAah`SFOq?B z*^Mo2kL_Qdk+HUroeR_xSK+ackg--A<`K%{q2ef&k#VUvZ!RDYA?uAsenW*7pQf1? zAjHg}k{R*I?q^Qeg0#Y>j2mB(hA5RTsIX3*xpZ6?%mrI* zJizCYATbk+3UBo+Y+WTz8Z%t<$lyPxJsU55hU_dV8il=(Quq25o`fU(QzqbhE#sAj zML}5^A!GEM5uUiFEO@N;Gkwo=B)d_}4z@mf@a778Pg^`gBz>H5I1$aFXr#t8XXNhC z+zY#)%_98)$EcnWw)qh&&|G>r(H&TIrFQJej`)6MDD&FrtQCZ%1B#L(W8~${Z{$y} zZ|l&EUtEP+N+@`R)}wk0YgM8?4INMwE=3+a=H4&zBgnvuc_ehG7fQC|z6%N5QzEugOyJ~^hbYnrbcp#oNyrmYX@62}FoSCZ+4P1@BRSO>ZJ-n`P2M?v5+!+3x65>|`8PWET8&Sy zZ`Yf7DDzM5fZX~I1#|5eMF>7}4e{!soo|QX3?gM_IAmt&#*xNF<``PGL^0udNgiZn zFbbTeeXc=Pi2^-$z>)pu23Q*o?OXZbr}jpxUke|(p>|^Cf6&n&b$~Sf*bPTy!lCR= zWtD2LkacKVyIcYwSX&xPq-IH;_SAI}vof5)N<`IIR4B%WH?4Z!L#;7FPS>fkoMAjtOUh-k+%)JP`hfRU zxMS_{;&}V=DN@$&;6%~s@57f%6TTtMa7^3z%5rAo4tPz-wVPVcQ(>`d3aHvtyABPs zcFCDO%RN${ySe%37Ps?|wNyzHg{e(gjzr}=SGBsR(RV?$rC-#FiF?P@aA+3>$%Vei ziI?OUml8;n)R>;oVE~k%dytuyXWF|Wz8Pr9gj9Zt1tfZp7Scy2x&7e}^vmF12>M@0 z_StC7(d4v22aGzmMv@lE4qnsJ7vu3k?yuX)CWx{guLDNR_McvGA~~}_YftaHnbbxHWSP@hM9}^ajYx`WvZ-8RXFS3Ea5r;VV=_qQ8$*Y$DXNaGok-^z&p2l$lj4g6YqunFeeKo3~wi*(cxg|E?slgZx+FdMMNhD(= zAKs1a*8C;o{Jp+Jx4pt6_Tk5;x7JS>adL1hQOdyNLobH8Gh#F;Uj%qnMqTY{`O3&G zeRq&dIJ9s0QT;tN*2`)S{=$mXtY0hEQ2O!hn=!zDb>qCF!;(@w^c#KUE)|(Tkf2Ot zLy_dq?2^Bp;P%yRpSp0qdq_)~UzJ|Q)Lgy;yJ68oe11>Ls=>!VB)C)c z?4h&X;NDnzeq8Y$eZdl4oL<(w) zlMVFEsXGw#G!`;E5f1P$f7fv&l{u>Nun}#)X#HGT>duci{7fEzCg4Xh?J&!M!suoS zB7&dkCrDw-fq#PWl~~`MG6G2#Sp+>)Kpi(EMaT|vycHk{1pPDEyPBpy#9d9KXgGmPbuSUx&pytS$O<)DD{sQ^?U z19zs%s_Z@26Hix(~v&&nWlIDC_d_zKL5x=*99geM^ z`P#AxQDaKpz4Bse^rDr#hgOyt8m@5ncHR!Wis z+?CU}`DHLeGdD@^C7|n!ulzc+ZFvO>U`A=F!7tO+1z7Lm&S7iMV42ilcbBzGDOJv4t#NpXQgN z$@kY*z1QuXVgLRNUS7c4o!0NuH;D3%H~e(rM>_A)y7yNC+mC$QyLUO43o>h7-^a<> zK|O%?L(EFP_oir1fO&b(fLT^je(>i;5X<>2#E#3O#aoCiDd|mC{>*ay(+kB-juSVpu3eR4T4BzkdEU%_LveJ9= zGp36>8oB0|w3R)*bHEgBrlajC=zTiNThr(wD!NO*+!Roy*K*0Yh`@`rA5 z^b-Bn-qudKWT!2dJ~~B3Bk!B#mQ^GCgHSI^jN?=--2rESTH+ILx#gPP^y&%W2JAlk z3*TAk@~@5n_q(G+`j4uM;fd#8vRs|(8@}`=ddfC(5WHzxMj{^1dSWxgI&)qL+y`pj}GpJw;e{*W zp5U?|@InqX3uOKzh0|cCw+N?W_Wd}x*6yjB06TnEqdJ-+p=DTv?q{f!s}!no7#{Il1;!7!SwT(7F0}U z9fW;W?2mJv}2;WcWq6qt5n8eDuqxj&fn;qpFDTZ_?|CGM=?MD8 zb+<=#roLZsxM7GnzlM;74o&YmJ#VybgrPSZ{7#cKDtVMg{}ur}I?$i6jAy8FGl^2w zrUAo2o`z7Ey?qu7qc9tcB}b&7rr>a}g;Y;egn#ZfHFW~ct)wJr_9ax8t_7TW^HY7e zmyOMY&k0kmBk!FIq$NSkWcUHd$)HXc|&ppPzSxN>2PT#MOl?^-W+?zzUP2Gl`AP4V9?c!^-P);c@KSCEogafr=GZ zRFf+)tK?J8YmS_SeMQsZye<6rZ{J7JL0hVy2~6oTv)QmuST#6&TAs>tIrGS&L9({?fmos|Ki&r^B$dIx%IbHHM9Ppu$cw+#MeE-xzb;Vy^k^s70 zp>@hd1a{8p`-W6K!T}cP$IMzSU}}qSz@aW=h-MormfoZ*T~S1a?jAD0ATN+U)Th9< z=~7+Lrhk{$HxRrlH_SWjcjETq7FvM8 zT>RLhsE&3WePq>@#{rk0P>y4?4Sun9`Lu>ZMr4T&48~?g7baZx!h|unW<0AQdAoDX zn`=&;v-SkGno|`N$WShR>?_0muH_=3LcO040oe+ECFFPZmNMx_WYe96LUC@!w!dEn zexwWI*5A7Zof;9&;=#rY+)tZ5n7H_T9@8c>z>9Jg%v%Zmet~1Fo&`kW{?ob)JeFqK z(cNxta1V0eG|OUn!EF}28J@^K-V~1&yeVt2>l?)I2}3(qB`GF7wFwjwbK7msBr|qO z;!lk)2`9ELnFI(DM(G2^i&KPWje`k^agDqc${}l{6#ByHxw!D5d9D&fvKWuCjv_Ky zUq$A6gvmEKyOUAv6kk{op->{uk#o8>_zUexHfNiV><*E$gAX@tG1UY;Gfn=hJ%8^= zx-kd#mzrI-!cft;+k1McH{YX?v;Yt!6n^$h7f&vJ6J$+`^H`Z9m9`$f-S3U)?V|8+ zjZPHLFXAHWy^TLG1;pr^_TJ8!$TcTq!7NxR3TjPPq#{EFhOlFjZud$@Z-1&G!^0x4 z{t7%IpEFMr%7mE(%Ppc>p&$(XQ)b`)VS(sVm)hDLk8vzy41uTL8AoCkFh*YuIS4bW z{cUeF!d@|TXTZ&ANUU!7Bp`m<3W6H|%R2Mbu;CZ~Zumhs-W9)e>^ORzWskof&SyjY zc$|{VXJ`IA)XDXEs1rwCM=Er|lT8D;IPn1$ClP{t1$f&G0-3iBNFKC)J^q1!D|x6b z4@VyvFabyU8?v!t&>H^YUP;38#$x(dGuaZdOdr0grlC5tQTHfCb%i%-inKEennpqf zuka^%t7s|gN#zbsp*6lF2)2-}5Yfc1{iIcZ6AW?>TDC(ylq(dnMHs(C`o#Ww3vKeF41LN<8{%`O(o;P6 zc)07G1*p-K>;t$Fz(_O{HmVIKu-VkAd~dg}-tk=xyYcBlv1M;-Gel6)v4&p)mnR5e zvlxGyGhQCCU!XL$pOdnJ(eh)$+R>`3+CtPgs_&sMINa zCO%W&^aSajj^d|bHS)6L2mB|~2K~CtdIY!}jjxr!ISy(B%~n#?!!i%>>h<}HhYeoF zhTi?U2S8=<9K3PUC=1q!EO=J@AhS60p`onG`sKJZPwj$Wma5`$`X(d3=eqPxyj;#q zl!j`HMZH^0#Qv@ba(7#C2i{;>M;9fn=K9>9s{KjlilRV{iHXX%&3z{Hyc^6D#(u%P zn3HP~vW4Vq1h8I#xb*it0Xk^ZSgD)LPJWqS+NJ9Sa9YU?cw5jzg4F-$fej5NT`CTI zG@Il;WBT)-^BeZww#~Dy4p#?_tpuT@xY^HY5z}l_uLbr}iha*?K;|pNDi&HT$N`5b;R;QG%KYe9h{X zaG5pbcJvGcMcC#ALnkuu53|3LW72G!)gkk0!lMW%rd{*0qKGo)^)%u^2_Z*flsD5a zVHNnxn@3`uOjG3WM-VO!a_NzAePztaY0mrejkjs!1&YgjiRFuWmP((a4-uS)gU?%s zL;(jY`aT6$#bXBXvrds}`81+l9w3TD^XHEL>gIp%n0)#r#kCH^s%Lc>*xzQ*mYtg~ znY&}nA>3=}jb>F1#Mo~*|G;fcyl8c0&!c{xC)_{j!&>5e;NAvPt2;m4 ziGjI^?qy*N!?erq8DYHo%2p!S4#c@|Bm_Sz!WX(7ep`_@flq~pps}JF!ip9Q1MsFB6 zw8M5q=$+e2rtjWuXQuq(bgD)`~^+RI+fkU@5WtbFEhZMr9byU6n zeiZnT1@v1w3^CjC2D|Vwz^T6yH)Zm}N7Z>WBH4te)SM86QK*6K>--_{A|OKXi)hU8 z#*%-AdJp#JP5b?Fxx}X_tgRQJ0$@X{PtwFc9Gp2U>Ky$2yDu`7MZ)3rDB zPP;#k=t=6e`Q~@gp?*Jd;iQpl^9g*mug?3mcIutctZwCvmS4^6KCwUE*mw5U1Pv=6 z(I?}j?~67nR!|O6^m}Zj@7(UIgKI+VbDj;k=nAEH3|@?bES|JW!_FFR04BXmY#N9A zyjRX(Dv@EhQt!0ARgjqNJnDt5FCeWnX)v8T%3L!PTQV9EJ$KfZwA={1AUa=0)vj0C zWyITI&t!&}wcZ^CFGluMY0VkUSzYJfZM>;@Edv-_A$IH4q&2x ziOdFy%G-HK#*de6Yw_#cp6|X{G%LT~1cmDDW{11{K5XsGKnztF4+KjJ=w)pr|k0ru711QLH<;%I8ejP3S(6x z#rCTy^%`EA+^VL5m3|t2&IFQ*hA)*5W1{dB)49Y@AYR!WW>&=10-?TGa7f+Q1W5<) z;MTg(iA1v>WlF8iZMGEzX6_xs-xLU_X3_64+(2L=zg~5+z8TwupJHl&u=BwirE5#I z=H7nQ3|2usLm^`hF9-e3Ds`y6DvFWKqv;{djnUBm{SMwVTRsW8bX1GvkP zj?Ro-6h2^5=B6fEn*!*~Xh`Q)(A>PF%mF{xubP+Crz>ECb7_EhmwWtO$3a80`@1%b zprPB$Q@~0GE9oN-%|lB_3ew5f6$F|8YaM*hg@z`Cwuilq9aJO*^*P^LY@Sm5`{ZUfb!s$V^OMaL zWyxP6rn4k3Ii3`End@OK*eTWIayCT1zX*?3&+Qc1mA&zo=K*hbku#4X7?(|<&=zj` zQ9eHQI4{hgBZqJ8g^@Uu>J7b~rCa0|;Q_u%(kxsPvW0+VzKCeI+1RhgBcN+B6n^VZ zg&BDb&(dWEBW9x0$-6j$=VkW2_k*mG+ z8!EjggJkimXsWSRP$j*tRGLiJ!rq{0csv!WcUh4#4Qq;oczD$z?-7#Xze5EXeD5F3 z&(k?;d?|^C|CH;nvuQQc!J&OnlPMJz(~JGE_C7DUE-bN8DcRmSw#|i~-vldtX!_bY z+bO!9O_bW0gMJe1Rc!tByyRQU%F2p={m4GUIg;v)eDVVE6=FRFVPXScZx>Xr;rjEG zFj}`McjWLbsc4QGs#*c!;>bzhH;B$z%gV$#dg@bMC8AVJcBxDlNz4^T9%ITo8g!H=>h^D^gP9mOUa^ywq+eQD2x_63_>|3{e z(^+YomA37yw4GUL+qP}1(zb2ewryJ{Yp?S^yX|||dbs!PJVa~J+Kd)4V$Oj%=C6Of z?}oqy3WN!;gF6>*FQY2jOo_}D!-( z7V?&w#>AQ+=WSY@aX0Ry1dTyO!rHC2%1n3fcv%u}R4h%97_#S|td@WKVVNY@7~?#j zmnGRWfz*MPH6m?BE{F3MfLEY)IflQn=@s2ik;;6@{28#`{j=?o2X_@z08O|8arB}2 zhfR@#sGr)JM;--*u$j-5X4LqUck}x(NEoEsJWO+5x#IWkK9h7667qlF5_+gPWYbsD zCny0i!=$h07s0BljXN(C)8euQ0*qWcu^7nr*9f1r`1bPeD(F zZ$iwe!(D8-*S2aaF~f7^9|k<(#zFVxAMHd%o{e=%F2-n|3<234U!=(Oc((JO5Lc}s z$ibTg-o+owxbt2jy4_|Mc>?KN^WR$w&H)I}3lZ!F@7{l=-sl1;Q6m%H0q$fyXzOH_ zoDl8u_a&flrGl*bJ+OkRoxF=}H*DShs-OU_tC=BeI7gSErz6UqFjjp`ad`D|`I5nW z%00o(BDhvA3k7#{EEA?loO3T@bN3Ps_NHPB)9m-4tR=guH`fZj3dQ`?6F&3zm(eDP zdns)Vu_liX{jWLVC7wlu_uzc1XThkpgFB2R9;`yE&%q%W?d+VdgPGXqDUTT7BSB~0 zNq#L=k=u#Ggl7|C5rJ5@d3IOsG{SBVOm^=V@i`kH9iAHcGDvwX1RB0fs(nCr?xXgd zkz1qlZxK+YOxoUBtj6vQzYw_fce0KY23r>=HYy%=i&X#1hVI_qyLA)&E05r7lZm;A zrb5CFntUmCJP%R~ll#-ny#Raot8$;K7eiRZbO9q<1MRcLHIXs_?NE9tyXg28w$b=g zb~qE3$suB*RA!9oyHw#76pL0yUmcbZ{}o9a6+I$WWL#H)x}L)9mEY3eZi&DMOEH+wHgT>30S?O_f}dYHrKIZ!Ltb=Xf#YQ5)k7VYJD0|Y z`xRB08k$C99JGr8<-HP4c+$a0^~j%d_H8h_S1(~bdB4=Jgt9=LS{mIPb=e|uC~5lK z%Q~W33vGp5_A9X0Dn8B36DSeCWERQb>>j?~!|@tLGQ`8Emkrw;F^hL=J4fDTJ1|X- zC%E08q_v|b+D~6#&ADeuvfWE1T(enQ?(^9ME{>^lXZU*TGxf0^98c#Us$-*6e%cx% z;?;<;h@UjnI?XKJS}oB!Ux)H{XDv39R?N5i)K(UM$?{%!<|nQ>o*|=Q`hiJ}01Z)? zReOv&r}e#91+g6zYd;>M?&(MU5a~=~fLya$v>geeI35u>Yr7ylbDmw3dYC)0OY+PH zDfCdlfh<@$uzM|KUn$`Di2M9Jo6PW{W}o=>oA`7WtJs%K&@LTHqK$ZVqZZ)CJP#mV zIFr=k4~o^uPM;l}w6Wh!7LwM8q)txom~9?WO7{@kZxiS!Z?O3(`rtu>rJ^uQzqI8b@XnQ_iw@rrdz6r#717_=v1wNc-a}^d(M)N;YZasbOr9kKATp zN71Sh#1}<3(z!R5$I$Img8JKRf&uYb{!r6!T7xElb2IMz1;K8^j;n|=nQ7Ms8IwY~ z&&G|X+TtLN*M%19vYEZ_=ltMiqt`wBlAu-szDDMl)!5b{0QCo@2lFcHzU^bWCwK21BgVta z7axMBVM%Gm8#9#79VzJ6AYy+T3Q?6LF0DZu-WzKJ*deO8QB|8tCNhMiE!^!Taa8S? z&Gk4M^)kJiBLZwp*sf)(C5Tn46&J*PneI}!*0X8Y&WCT;Dl|tc=oF0_p9t)R^|{>D zj}(-9C%ZvwJ&n}WEdA>?K}!qqY{fE@rnRe-t1(firBe5uu88G@k9tSOtW+1u-T)-z z&SJ-sX16k4m{giGJd2vp?==9VS1lnH6B1-Cj1+%nvbbR2!t&E0UQA7CsfQ$9w84=X zv$M)oGy&j@DSmOo#6?7u5yMLyEk1NtyPxg(Wm=L%oD_Av?hL7}hay#wplH|a2YG=R zdFU(YIA|zt=v1vqa**|oY@A0l9=TIiV#t&Rq-ss5C_Z^IbFB)?Zqkgq(Dr8|7mrhu1hom4#W5?B3Qev*5n!Mg^XwL!IzGr35NU~Lib~zet6m^tnw%*UH1@|S z%=}4m8u=wct$Zc;AoiUs;ab>lPCWWED%7OlFuyqteu!3XJ=ukt0>t*P@s{Xu?Hv`R zU~9m3q@tw>XI~z~5b2p_!rGkah*(DXN+>=5u+xlq!5iVJhMlf7QawxJ+W$`=ayZvL zUs1#4u8>4}Hrp7sL~#iyq4otOXc5utF=FmvoQDxkxR_sn<+obIN+8l&?AzZNEz7M& zxH)u+RF|t714KC0dWsvLxb^V!K2WD+F%D%u?(P81>sNWjBJq-k%06=8C*sP$Jn4Sx zl9G5}7?)fLTxXb%r`X{ipMu{w@Z7_u_ZpZ|L8KD##B!KQVl~_rM6sC?%9)o>GXsj~;2)5+E1%C=}vt(NVU&ph00il$O8Py}BDO zqyn>~nb9afWOmjTYhK3n4*p&sPwSc2?( zKXcfBiA0zfY5zBnWn^Og)`&3wM~R4hk2o+r{70e>8aLC30ZF`|0l)PxArln-o9ed0 zhUQBeE4S$?R&yuoeFS>6>;bD459na;46mk<+*$kR7%)g@c>dGnQ|vFD`7h+xuIW!w+ z*9z7eC4_3CnO+^|$Z9Q|R=`ANG0*t%-AY(1VbsO=dLWq8W`9avRrUICp6OH1)Gd(V zXWz5<()>jcP;ali9q*A7 z@&ass&P-lx9^83k?hH$CkR@KV12Okx4>k_{LIb7S!)N|omRE8NV?8!4ShYSOVRwCH z+nK3@>ttHkFCg6VTXKx;9xyZ|AOD1m#gpeNZ)`93*?5l6J#UrQM^&jF^n=}*0kM*8 z!1t#+$Y7qfk$mI^tSYaU-D~dao!mS8f|ahg(5g*5heVS51Nm8UJl}Zzf&4p(onlt`3FKOx$`maBoum+~@dB@`^0H+gtL7+$EWp28C5F-uI8^ z&!^z3t-h3cIP&E@HabT|JG#{(a#Eb!4SGx@6_GsLB~|IOBHX>#l83fQ(+5Sb_M^(X zSH=7}O>7?PiP=@nPY<}eGiy&CnE4B!&29ZYWfl&}Q~shv`=U92dS_8Kl%a-wy&ml}#f;glur&?G67~2l zX`UkY{p(ZI7rn)Tm~{gM=)pMi&z&OLu8)%`{50}y@0yn*5T5>CZE$bkckZ4o5zs!L zn*(DMAOB zCyejr1VL_Mg`St?wI4Tkp>kel-48nA7@b&(?Yy0bRwtu#OtZ-g4e2?Ooh}nD@rXiLpvP4b5nU zqo{|B9Kzj`7E;E&UU_?MX1@-=TA#&I_FKN=r|`z$PcWwhDnTX(sLmP;T1!$m^{ns+ z%d`fI*@&;8u~D_xTE+(uwrj=$&4<>HPh}Yt+|omjxtwwF<$w!+Py%M~w<%7N``q~m z;vh4%rW3;!A`*`Kh&wfJ3QB5VfR@oOkrit&_C;aYbhbWG+i(jhKvya-t+FtlzeC(p z4H4QLW1-SyOYp-j5n_~~Umz2&KKFHE(G1#S-0-|g%ZZ!GZN9As6U|w{;Af!ctTox= z{p$CRt89g{!#F2^#*1g^{2{fzy)U!X4H?3YQQUVc-?M!89U|Yw*VMyq{c!UI%RBAD zsxfnG6R12H)V32J23~H(2R+w&K<^KKZ(=hE{6!b56%BU8C20dT;u6XUcO$^Ks%XU* z*aP7~*9>TVN=pW*fbb3jMmordo*oz^O%gz43uVBU1+_{BTTI913kSx!ZF%qa9q?S+ z?u@a{SGW--M)y9!(V03RhH+Kjj2WO`!)6`!@Pb*wma=qb5XmeD)1-dTol`Ad!dzvR zDDP-pJ(}VA2><*9_8Lg!_ltoP%ZVD~h^?iz0PL$u>?GJf2m#YvaTu`++rbCJhHpb$ z1Dx@so2-2HmKoBjoT970;zI1v$Gy5R_r@<5W&#$(8;5&r$Klxy;0=^iJXI=KsC8~c zZ2B?K*XK=^26%mtI>Zrydek+UFotP0!y3<}z~CnefdB2z#BL=KY+fjf+%jf;_D+?~ zwm(Hw-Ul==9@>n$tL=~Yx|KINwStH3V;^!Xk+S;j5Qr^k$l?q>gBLybyE?O3)#QVSe#z+_ZfRS7>JW> zasod^`W7A}qe&oK)lRjRKVp}VpQA5sGK!qt;f$G-(6w0>t%9!fx0EyDfHRW<=|I_$ zA`tO5tXq9MHR1|2EZ?Z9kq2|N=oVOHg)7a4l>gWecL77Vh2Ra1b+57WI=nk4uk0AK zxYtXAGtCBJ<&JdJ4TBhj_63PhX#(Y+*3skHp{U=BsRx&|uM^HYX$CF>+M_1RA3em3 zl#&Lwm~!IAS{76cT5TixukIk>SZUG*HOCi1YdAtI^~BxI z0Pw0(OV2puJM4`M13O@Lv@Ynp^>Wu3(^~MQ^YAbKoG&0d9br0);XbT#jaHQFE|CJf z=LECC6Joq;e;u7!cfNkEZd1$D2$aI&VdjF2b+L(mFy&=y0?8CP%-SPrdwtA#f9$k@ zX6;s!`85dFIk{z`_aWKurUym$1kQQp2hyf{DpA!Gs^qxvOs$q_woGP*WsBz3T(oKD zi79GM!>~$5ztJ^#4b>*PHisg>d-;|EXcwLS_%=Dm~g&w0pS{wiM3`C0U zw}#y2ipb&8imQc!S1V3sSDn*{?R4mFhZj_})PDW2po|2!;V3t+t1YFuaHc2#FqVEu zUt6yId$Z(BJpRScN|DrF=zQFh`_|L1g#AvmYKJgyeQTZQb)C(|U2BfUB~l~~im;wY z#S&$;T1~$}L+wC5#UZG27Ar|PaEZDCl1|(_?#^8}eo3P2vfQ+_Ow=r|ki5;k6f@VW z`X(w4{z<2IqCi4Df=s7>Q$wcS(JXxE!Yp}B#xm;sBy%>Y;%& z=P5%a5I@cdhDM>WeKRn@HPjA!3Wil}aP_3ho>7)MpF*Me6u566hZ#f5!-nneKysU~ zd5OFblj+jj@hrZB#abU)aE(q-Mt{Kh9L=$PkY!g+JPxWLyVM@8OKHgv6S>K^#&Xa| z8e2nrRcTberk>Y$ZMUx0a3yzm5Brv_ujeiA=RFmD<})|LbSUQxHC7h9OLoJhaKa6a zJFPAIC1KC?#pcW3trGF*q$eCSxp2QD!?C=s7S6(0!}wS!s8~-0=C}v?)b}{r7C_^l zbOMx9_gS4qmGRKb_Ij=b79Wo-Q|$a8`j!AA6cp;|)2MFb*Nr+@dPK3q*M1o=Nikh~ z7vHHGmvN&^I%1>ge=oQC%0f#LVLZ8{~Hn%==E7~?vAn>%dI8zzvKskHCRX@r=TQ(F63u8 zL-*pBf4G53e_YB#t=xRBh(i^OPPz}<$)jKF_Vs|5gO2jN%{ag4ke-c?7rpp^U|5oH zW%oLZX}nefT6YS{pIeFCl6od%N8fA0l6JeBr}t+JHC3WpB7-Y7(}qfXG5?>b(b=`y zSJGMcH=?1QthLGm-LOkCR2~e<242pr6Js(@N~?bUsbf=H6~Da|Lr5bnx3>;iW>lO$ zw`P|5*0y#z@on?Yj#PGF>SVLOnFXdzNFcjTtPl~3b@QMWVqW(14JIg|sjl)iy;SKF z^))mQIV2Go$-=z&^^%;b1d-0)SFEn19il}$3{)pi!Wcl4EtH<7V7OgpO_HcMHmVW3 zh{-$TfFO@s`Nm#H|3p7P(-J*GcQ0r-s?n$b;reZ3;rXq)`_N_jd}3@GO1N2cxfa_o zZ`}ab1g^?RaB%NwB_iNfMRbwJApsTpXpCcbu_gLgM)9;jE*U=l%w}1fqQHtLM#FxMPj+LjS zZTSL2#WhxseVS$@!ZhW_Za2|BiBheKx_&()=`R}>cey;r|EU}My%aIQTNzwsU_J`G zLkWnXUv7sO3?EM*s4W{!X6u0f&C2v+fI8BgNwVbBuiJlC?}gl!(^MTfTLFaF#BAmT zsTf)tC}~Hco15l`9pXIq1u}g;oZ$~`&vgc6mhUz8W$~K0)%{M5linwt6zRAkMJi8c zz_}LLH@WdNHeBkGtRdcvdC!2_ZY9w8IajAbI14p&w*1`ivt64e9PjOQHp58B!j~}N zVgOCij!?_VTqw9v18=_kx4ts;(yK>0?Wg%3w+d z=n7%bXYM~lF*Rk%b#Dd4aP$Cjh^ZI$|Vi?eF=) zP%O^0f)Tn0ES`qJ93Qnrc5KW@=i4@qgd6J4Og{MzDpZx`3-KMdg*!NR1GR0%FsPrA z(rxJj+VFj^l3;QK_jdWW-TiC-w40J9$zZj@`b!glJ)j3b8ArggBIeg&k(N>M4*jN_ z4i$>|zJ>Y7j$luQ{0P_7nAQ>wfS0GvIET~xAdMw5f1C^&f1Hv6M9d1`UWW@n?ej3$i13eZXp>X|H)Q$3mWF zpu&F1hu>}{JN{t!SZtc&07GcgTzl@CjB6SABL}h!q^Z-%SzoFzX<} z)x31uC$9|~XfT8y?5qwj9n0%4n9bpA8W&%)r7-9*z%}Z6nP6r>75d_KpO z9R)XaEb2+@$bPggej)}35av7bVCCjvtPW*dXO$k)TZ>lUZR(3@PdI0N5e<5dQl+@U z`^+}n73Z>~y{*d2qi*OS8oBUCX7Q4IRUyQ4#K6;g9~6_QPrI?_GJa%%j8qaIZ< zpcOD$e``b%v8TT0#`IQ|sy6FV+gHSEYsO;r8^7Oha1fDF`-`+E+l>p?RAb}qEI9R> zF#p?N28#R99h}i5ZUi*mDuQQaWXWyoebmh;(g=uoVD^bW(Kht;9##Q}=(bKZ&n`Gw zm?_Kpwun4KUN+q$W@LQTDXq=)*T{V*Xq0vb1xVxh z?{SGJ!>q0tZCQM6*$VoNoL9R--Gj34-P*i{FRjPq*<(@EudFBcj7OzRCZ4OUheTY} z*`~N)QOvzyIIH9n9pByzkQh@cnfk`{k&8Cy+&y(1*A*lU^7RA>1}m_ zvWSpEnS8{0?`t()0-}#)wP4`B)$bnshr4IWu63lrUJvfn< zXDAa0&yM!~LF9B3@5ZjrfSB{BZz_1UYA_7R0M+@p+0arD%(1)exY#1|)6za<3%QaPjneMfW%+Szj(bp!G&5PM&@WNxGe7vA~h zI9s3@RK7fKZW#)v_jJTJTyNb!5ziN5Ecn^nFiNXE57lepF=UA|DHV8Yx&H`x5*G>; zucogisL}@o6XMxDK?SzLv4k2O#dDz{5<#68FI_k(*1|On$+*5gy?_xc(LdUEK`@-( zg1_lG-pU2IvOH=T36CIe8&15>sFedTtrp9Qe-YeVK)lTgxuJyvlHXHo8)-2?#xgg*Kvrc#@d<@?-3+4y6G zSpOUy7YC#n(F6EP@QgCH2u3+qB|rUk2odRs?N0J0nrWaW10-z}mwb6JG9-h7_U^#B z!;xYMD7Ws79YU|Yy<_Ivlxde5a241Z4x%Ih5m(lADo&yt{T2*(!B1YBaF}j^V^Muz ze~9GWFfa^(>``!kKiK;?ev05Df$ridwiTUTSE}F`+#Hf*FgxEGDiZ-C`ugmlMSy5H zB3Uyg%q-J;mym-#SB40rG&)0%e6g3waW9NJ!x#WHahp_Z)z}|REUTIv!FRTLlh}_qP{H?pbNc8I+fsBX z$;uqnx)B`)^gkm+70Zs*7zJ3k*J_VaG z#FEr(<7(oiMxG;z5!p~w2FA?lNr=($>RQO&i)uXx_$TX-iFFP{Bd1M?{}xolRLu#M z#U~GDj`5*uZX;3J(#<>So(PuZt#L6z!L&c`5*!jEqmK(MmiKL)0@CDQHT4<~%K zsA|1SIEEfT;5h`4RYMjTh1u7xAywZKy{$>1+m5Of=KT$;&RQU33sN6-i_w z3m6+RCoHy3;?udq#rAp|Dv#^J|!ctKdkzh+$FB%LRV(^73DvrEZ&b4i2SP+m;=g&>isSTQsQJu~_NO z7S==r)UjBGJ<*tA(HWR;4od3p4hA#Zmran6{zOff>->l)Pzg~mw+TuF#{Xg&b_N{LvrjLGeni8v0Y zG(vg2l$X;_CsKm*!gXFYp|yTFYH2Fg3EZPk41l_zmlf>>6|=2BWixq@xdtC<;ldJ6$C^u)-wvB4_+;t} zxH^_a_urwszqIW?)2Dwy*#9onXQulLVd?*4q5gW3ocS6Z{7_ez4((c>bZfi=X(ZzC zCM1r(lm2uK_?l8$^*l@H-L&UxMtn814$EV8WWP@Hn>yG@(N{(QdYmm7y@3D~rl4^y zoW2hUJ2o)GF+uI0*J((KX+&-h@*R53Pc$d(ff(l*4UOfNPS(f0hk}pmc{EPz zAj74om$3o5`!v=?9;)Dh#-Kv?`m49u&7@A+GDCAtsZN}@C8;IYvr-I}MlHvN3jG5p zW9|HeLUHGtOijr1%PV=!d$9rc(u^kFud+Xd7A%i7W@W*(jmdYKpH^ADh3Xy6VV?^Y zMq8W53A`9ZJC3G7Q|L$_2t7J%q@w4kqAGuUJq+ZTe@;t(=vg;D&{f`8vroC{R&smzw26m`R)Ic5;OlpiJAYQ#4P_%VwQg>G0Q)cnB^Zz%<>N< zX8A9=`~SH_{l9+n|0X8FEDQiTVbPc{CC0&D(p}3pP1U7v8KXG2ae+ zbPQpz4?fTM_$7P}dww_gCy&xWt>)!P=0%1&s-SXOL)k|$MVpqBW7a0+^NW1nSKOS! zcY%5nujlGVvx36?eLcz#4e$EV_(z(T>Lq%am9qVb&pCi5qtVG!^vC3kMI-TV9=y2Y znLc(2r+xkj%l7*~fx*WghNcuC@S6vleno#*?{XZAU3|SxCDwQ0Xj3LsN$=^hj;~22F^V zhn>J`(7!Xcs|)tb$rivpnHZI#H^$l!U7~1@wrB0pJBKObtnaL8h2#i8KG#B)bkKq` zdB5M2Rx$OR(Gcf2=vZ`vq<=+!!sET@eBHC|^7@*CbH6C``2xIdf4k!>u#g{B2VL&1 za-W9O;YsR(%{&Mm(MxH=9*GveVv9r`y<-4We z+ah4PHwj?>n?}Lw<0dsQCIAaQrMO;Pz2+9sD>@>S9R2w|dyaFEDd`Btd{CZWRX`Ol zmi@U&_ic~b!}|%>W(OsHcy+|QA~%rRq61V2+z*ZD-4Aj~Ep6^oyY1?76{W8`tvL^; z3QP7h6B4cX66z>~vXU-fl)pPtL!v-Z(_W?d7|ELTkit&ohH(|H#zM@`7RwLk)r+NNV_fjfFgAoRt3HX{518D%x0=ps$_x6_1kp*tGipyQ?qHrQU`yj{<3xvbu zyT^rX@kP055R2gKQLvMj^Kz``8dW4Ol|@U-z-hNKFRnN?;=;lWwxh&FJ3YubJ#ncG z$!5$_YgJ4-YIr*6=S084GFe?;2Su#!wyPfrYaI#SKV4sUb^rqLoSNn+A|B&ZNZt|! zZh3yiTX%ka_|294R#C<~8+T)c)D~Z3IzgxY?S%9Wl4&cAzJd;yBPYrt0?`G4-5UrJ z^h=`o#%nYzN4NF_6SD}qv-$CDPP#W9uzYP92o}~o|Iu!6pEL_&_2z7Pj!!07fJm=z z-ygV+d}sA_ge|BM1Kgw!Zs_t_dde_>_4FVjLt*Tl=i(Cp5W%ex9*^9i)=p`J&wviW z@s>^sZ<-GuWCt3yn8f;q7uwQ>Z=IbF(WQriBm}yFe*3C7B-0P?+K$&EvKP!B-<8X1 z;O{6YdV<2m{j=QNRl-@j-=7n@ctGoF^1R-)E(z0S9PdN+2$e?I1D3T;?Zj2@DeOb_ z+Kl;(D*|ZOO$1)3a3tsBGY*mNcoYn?ot{~)Z?g6aSn)?pfCM1swk78n#@k}@vlw99 zy(nNUe5_j_O+dy=BdcT0h-7_7ME6Ni;270=N{uVa#%0Pz+Y`N=6DB zMOe2li?U!}ex{EAoeB6GV?sPyr_3uv$w}N6mj?A?VtCb0lyJMme7VqeMXJYmo+Q*H z<8ARX6OP}E)6bUeq=i@Lkn}UHCH+N}3_A7$O4`E>K1H?0+)GTROnoriw#1XHUGmI9 z$vMJ?!#=Ig?oEjUe#?LP4rBMpj>oK_Qv6{~x)1kB&e)O|yB#HD$KiGm6k-Xs{W}*4 z`nEF1YIG4Kc?Jp5CO$BkcpEiWSnA>+0+p%Q&}67eKqf97w)4C;D~@8V(tkkfd=5fq z2xjnNTYA(GfVFkNAVVnJW7EK8AG?CISnFCD*(~6@bjl9^iT`T_;Ps<$rDWH|XwJTM z@1D;p(RLB*Pju8qX?Diw;Sv=WLuHPA+Vn=<>8w(PDoP0Q;f$w3_iFadv{MXjQTGcS z81}QA8=t+*b_i(*CkXa35Bt<~V>noG3@$|SEa8sl->X0Qef3Xb??rC_Uv+~?;=xTB z*=2g@>L=!lnVN=f^NOi;`YC#KMA1TX+5R80fPVo|He+vUSt&HQ&r|NIW?Z z8=vidVmZwl{UqFR+3&K5Ok3d%VX15bCo=IUm=7>xk;chWTcvkuwajT7tGjgaIh366 zeZAw%AzzMYQ{ZJ3fzo6SOl3r9BNfTi(q!5jx1(5{~t1g!;)Gt-i*T?&`Q6mZxZI zS44wuSrE0>u|`>BJMaxg)isHWBCj{h4M-v<*2mUQF?g+%dtv+Mvke)RKqgVHA>Y?7fdLXuG1yXB1_&ed01U%kLkv7||3 zYxO+DtM^$%y0W@^*~2izzoVJvff7Ecs+kT{w-&Z6F-JVqrTmHEd00DRu9(%>a3tKz zO-q2nXdL&ZP&Z^5_!4a#6)x8zRtJ4Ld$F%o(g>iA(OFk*4D;!-`aW{`-ep|oA}fze zH#TKZHa`zgLw}e`An1m80&P0Z1tCu4aGg~3VJ;3-Q`q{Q{U=!{i#@iYBHK6;n5X$Oy#K8PK@$nuaLmNXQrl0tAN!gh=?XSB$u&<>N*Xw26)&YJhEYzqn)wl7 zt+Gz^p_B3NIKu~DPII4o3i`F->b!PQJYDJ#0jPj}XN5y21L+E~JMH-Jl10 z!aeyy($;Nm$$$GI-VZpcBz1SCmDv7tHle^-6{A^#B~SDl<#T~N;T_XuIdIJax~#T7 zQexf9fFye3s1g)8sl?jpJ6#btf*EsiNWVw^KllV0dawrf`AneginC$RmchZ$fH{UH zYf6X|pyIs+f-u*OeFqVmm_%Okg+$!)g~fW^GnfYOMI&K3mVj@mzW$peJdB6aJO~SGi#>_hMten7aPhsi=z*-_B84=kD$A(nMdG954&8ley9*bR3AY>@ z44K2qW=p-DBC0QR7d6<<#WxSJXwcbqUyq64a?{PPXBM#W!>@?FqWyvA=pf>UE}jW5 zR_|F?I)aM!BwN?z7zXaSmf!Y-CH~M5c-y00kV4tMNnNH$)#Zq#O0;taNA{(w!(K;l zUguFqu!0)5Hh39lDzsN!TSiLPp9pI%^miX}xf%BA7Y;od$jwbbsg_He2mHtS#)2^wHF1!|HD%XPy$mMc$sK`fXZw8=~%2WbbJ5}i?PmIox! z^cYYh-s`PFVPenY`yQ2 z^@;3RM~>9nu^7+)Oz7RLx6y}_pL$3|vA{M&?sWCJSUEY`r-y2_raIyN91M_ReXaA_ zA@QJpI-jQPP0t@HFTyKk<78tGMavX2Q^sAJPS@e$hcNw0Rl|5Mg zwNQbM1Ar7xBG`q{QX9}GB*=}- zCtX!Gs4oEF&Nju*8wBKyX{|k56{F&eh}NK12w8hfnFSE85~_Aiz@_d|$%}!AP()w! z)oY~b_nE?TqOM>zMY@wqOlb}Zo(E2@aedp%vBZgki2T$RV5+N_^yPpS46_lA9 z13#`=9SAtXgCiTiofuo`88iwvTsjF264Q*+Ka%JXjdd>)Q`>Ldrr2r61(1CQNxLNq75X>5O-x`tqa>|BQb@TTgp{JWsJt^HllIxdzm9JJlAOt?)j z9Om`i(!Lk8?<3y}T2YgsxRLL4|GKnwnJSD-T?K{o(wgRg?#t%qsemX}r)_@pu51dN z|AD7Cr{bjF2YBqtB5cXPp~HOv&?x07#rBTh-7^knbWv`s)i&t&g27Z0;M@Xq4&wq} z3PAY#j#3BgiexZ?eFw+_+p8icYOTjhJX0-vL?_X~Kxe32Kn9o?#|x0n%MggAD%M6M zD@?~E&Bll2+~yqis$WCcB~N2=IkkTLL`rLh?t2buR&uG z+qXG#z`ZICnu^B>TF)%QY9+8ddlJN0kBHk*7J#MJ8?nhiF6gTr)(YP@F+N3C2`##l zXd_b`Q==$&7f!#bsc5f9au&opzDwf0ye*XE-0mM&=6~(O$tMW;8FdXuFBv7>O3YvxHFDM-&6VZSU#Y;TnnsJ zVv3D{Su`!&9G&mAOb8nC&siUm=}J^eU&S8ZzD}k?2vCXuwFueXsh35r_WGjAr!LP$4sv+?U9bk0_7BdA;LQHO-)dcA1@(nVx9x>j~#j?29yJ*(j%Z0m29u!O<2et z%tf3vGa5slxjBY5N0IuEa$*hJ^KGcRG0}Fi%~Q1-SYw%HTX6)r`UG<+=16t)cgWnL zCB#dj)}lcf=J_PKX<9bU>E5k)n|fB#ml-A#BuRu z;8Ety4Oh4z97}TMf`$#sT_V{?khQRT5(%oon`lCr*q5hOVMQh3q6E=zzWSL_0pJP= zBT<-06zOY!_4?phHZH3I(gSw2%ZC+d@_~o$5cxwa)gasFW@u1^fEpg|-K?~O5jH}a zc!*a(y5|lW=i-JF=S)k_5B>MuBk@pzN8w3(+^xez4Kn{BJvciaN zH}4iBwr2*_hBIk_2ptZJ^ML|X_|(O+gk3S09b>RS-(l*L-3WN-JH%V-A$6EGn2c2l zI@zZV6wZrUR0~k;$_eY$gt9L{;%dASuoV0r2r{Q4Lts)zW{%U2^FgPgM@XX1&7k;& z6mLFVu4*uC4J&03r(DhcZ- zAqHBZ!SIcmU*WNu=R)&1^)&F{3}3+1#;VEbN+^&K+_K5BGv5i>3=QHE{+g$L2FIqW zy9Ria?bYc?U^6$CrtmUbNkQh{_0^NLbnM8%MO4roWda8p*gw@!X&8AWB9lPVknVI7 zT8S`ZiqXY!e^QH)H~tilOd?_(0t3Go-i|X-Y8O_P&mQ+I^OMav5>N{pD=!d_tVezj zO}t}5rwvtp25f#MiYF?nH7{K=EKx0~b@ICz_IRRrAb(VwIm90Tu`ejiw~2v&ix)i& zuSZn`BDWu7i+xw_098_Rme-hPVqFE*hRm}-Y?as>`cZnDn_1og5U;p^2G{!vRUNJ5 z+hZc?Ni!%DA*t|lOn}h=lh&I{h50iNEQCH4voeK`RZ+3W0IW5c0Eu~#tV&E72?IhM z2HW$Br`l73sc@pg%~Yw;1~?P#7gshqNC3g+Gn`VwpT+z_&(!J!W>-*+KIhfPb^rXx zpu;bqA_z;R9ciEOmB{M_R)1Er#c1V9u+d~Tfl2OPX9JyHBiyR}l#y?ZB3wV%~ z%#8)2?tkkaL7V9oAMBR-@`Nm?`debQH5Hz?H$I5jENJgBa9U`T@nBN9!qcc%pk_sy zAJ_BCDOE|O<#vRxf&ExHZK9t&Znmv)vuap8D?fCgfD>kxth@c|Z=qv!k^l9O0aq#r8ZnQ+44TR? z#p}B!#Tq)A*g`Mdo-PrNJI$8_X_HYXW^xsq23fSPBoG*p&`j=PHi1_LTm!FCcZQOm zYd%Sf26%eSPlEz`7eK7WigWYEQeKxrBzgwm0`tCeeCvaNtHIC>k7DRi9le85y%@_E-eXyZAj|GgKjf{DPM+09; z6a%z`WIaS@E#2v*e#O6KcWsJ&dt7Rq#zR`_B(uj$vAG{&_s2vshVVlh%@c6+r5^!F z_0pjk)b_VrgXd#m8K_C0gzl%a^ERQiHa_kxsK4#J$({=_Uc6cj(q0vsqHC+Wx20V^ zGBbU2c=9G(+G7OGUUIBaKG*ow62Lin>fS1-&MsZo#@!{j zI|O%!;BLX)-Q7L71b250?(PuW3GVK$d*JvxUc83 zx_iiuoV_k%nZ=NX^AB*4h3@$tBmB((NHobv@v>X$rhM)E#N5QG<)pK6wY4gnExk*y z)#hboA@`aroW3-nXmoLly!Gewn$|(7ybzu{|=3KequC^qM>q@KA5s58c;m; z_nCDvg8PMFs;5Kel`g6F5v)sU?l%65dNw7d6`Z^NY2D?0^n z%7RmtxyP3c7hQtef_vYWZ15Gnaw^Pxt<^RTDs(Tnm#!{4!1(9%-{YTa?tiJaW&0sw zWQM4>KGLKdxU&i~=_ux5&xa8Cr@h5@b=LME0E z8o79kwg5L&GO$&0h!Nr_*`%gpu{Xyg*zszXs>esi$5lpKsWV%fVk0xe_G#yuq(k4w z_HaX{6gMeV7wv{^PyXmfun+@&Z2)KBolh+tgrP*=$Ky>C|LbdUhl^6TZ;g7T;;82% zJ)0*;cFEapyCn872e@p%24&|(q+t0pbcN{Vq@UQsjG8=2^9NHXJk0LeF&IO!s&m>tUDW9=_%){hh%XQvKA{{CL%|;mP=tbW zXm(yoV5!AW-Z-FWetE?VzzW;N4ObR+RR(YvWe+<5chcR9~ z=ISwB*Uf`>pJaZsN$NoP>Z#eSUc$(+_({G}2JE0ZAH^xgp#2`g40t6whAxydE3h7P zBPFOXv<1Sc8BEev^PN7I3IO0jO{Frb~> zAk+DF*mcYuqiEl3TB(e9Q!^^U2~1!d;7+7_R8fIs;gU9%z?Mj*zjcMl5GQz?gZawz zqzYYagBkLAc9n{+X_!(C_rp55P-o_6K9jsso8ZE%Bzc4u3ua<}O+NvJzS5zao#s2QOGMnO zL|ekncNZ*{;aqnLmF59DR`mp? zi4I^7>SR=U$4O!;-xfZdH!*z&xM;{?A<=Brv08$)d}`o$(8k8B1j{s$)gukcIq%re zUBqlW^&-2GRizqo{eAz^`ucOD1bNcG{>y$qBs8$K~7kiEZjHLD+7*9Wn*cpN_SbrG0(?Ssr#F*U7FY-93xv=R`-Ja;XaV@h>+X2`gCsyTtXPS8~} zt30Qw9sQ_1ec{;Eo$HF7hQ;`p$YAi?uEE~znzD*+oW1@P`E5aC?djR|e1#fI+Z{PQ zIR_pP#CnM#yb37@YHSitL(dqLlijq&tpT?QlFpdU2TD^5mrm6xZV~p%Qr7r8BAPe* zFDt#i$9}PMnbY=3|I3xsJFSDH_Ug$sG*B-jw%uTo>>JUSCxmSAzvPN}xCA+k4{fcnn1EAcO2bwnCUgEpvd2)A%YQHqj!UQ4vgJ@q)QjPN-n$}F4X%}yk>JvT>qnSLUNtZ;ov zbU<=b3OY{xR_e|1Np!n(6wY-2r2DPz9wqvunKFyOEWiENH0=xCIGf6d1|Efo`tZ1U zQww77^<2K*U1B!lOTWQ!-;Hf#vU7huQU~@hd<6admLflWhn(x-Y>7@Qhxw@P%k83h zrI+IRPbG=T7!aSGd8aMfRE(ZvRPT0Z0E{Hm{?)Tyn@nRv{g!qJxe!K2;~NsP8`*`` z)HsbcmBZ$;kD(WBovPr$bio6$r~^_4E*+_c=@8R+#CLNFG}|jJOP{MfJ8o?;)YY4q zx=#d06xk-`p6TZyno(CLvgb`Ij2-S_N#Y}VN?)@QdL7{+JT#MnbpuXovq)>srwNL zz#LBPqA4%?IP{H$N$4?+!i4v;rQ={--GS@|~}vPdKY*5x<{Gv4@jaP8-6 zDY8hCtg*|)ps&9NbBulM-v6YCoX6CdNpimm`Nt(Q=v_m)*X5oN*bNP6mo#KX5 z6oaRJ>gZIGHV$n(|JHVrc$O%~n~3hu??RyN+U||( znii7jGI4Ic=Xu<=S!QyBL1P*YOpGv9mv0s?jJvsZ(<;Sxx^&RVv|hpMhH*M3$yLr< ztRK}R;i>mMvs>H0A#!E*N^T*`xvz31kl8ARS8|~P*7s0D@qv@)!d*+$u_PNV+eoE! zaegv+LIeLy_g=<2JC_j|v=<{jM?DI7XZDFPDy%sk%7$CpOnQi4-EaY3)k2zc8M|OA z8u(a3gUT+(LimL&A3bm@xRn2KyZ%lW+#bN#^~-{-we z@-{}_!N9;(M8rl(>;<@@y{R9vPJ~?9r0-a9NkOXc>Jl6D4=h1O7W*|LHeCWY>R3{K zdrm8dVdX)(1n~@?Z-j0JzaZg#7(rL#TyI7VARwKASSOSeTz!TPfUj6~OHU+pAs_(M zJgf!b=5ZdvK0O{t+U>=UT11PuU`xsxg*GjJp~8`_>jL!n-TXILue?UnuLY zji$7Ss6V`)z)QArK9@9BY*toEU2Gl=j>n_~4jU|FunM=ItKCmB7P`cbu5eNS?tm96 zY7E0TH+W!Wtif%SKGsj43f*QTFW#ZNWVd;8cJ$kGV880#rl75p7+3*brbFr={0Szo zNfSH00b5?JXTxrRaL^I|%KNrMj8m!Z#`{7&&ChW0x4H=>QjJ73KmZ>I_w zN8Pp<8z{H3vTNV*SqBf}@rG<&h&Y$gx0CdDmOio&>5#={ttn8Jv&Od<#%7Fr-v85) zV?h+n2J{MJ#IC!Vx>N-}f5WjmUT zfO!0x(AmhTHV}yTVA8g^X=O+mIHC%Ajmsvnk{}_Hd)LtMx3{xorG_xF-x$*%n0gza`rR34oT)kkm2qYN6 zY^Hh-)6ldmS2jrX0;!$HV^)mNwsuzmq%?uX4p;0_`Kx-z*bucr&mZ@^4Eimh1jj<; zShY*g3$8q-6D6fG*-DhWSxXtkYMtZ2d*UQvsOyJ~&6>kgEngU@0g!kMa;~n6EXmjs zZB=8YVAv-pew2hm^cAhKZi~DNL?SRFLFE$QB?boggyzu50Delp@vqz{>2YvEu_urz zEqRc0HG0qk+vxDo=-9SjRfmIro~~#tglnKv=Jwb4)5q&l*2uTdqhBI;%9U^whJM~| zn}9R_x^*)#?Z%Y=AXP-DA%#YEk4j^{hEL)1)AYJwQbd0mIxj_z&cL)!`V5)NEU=km zwXNYVMtuNu0H!Y3rP2=oRbau;;F#i(FR|VGxetW_>A5sw8C|MVUYa>Q^h|+JUO0K= zYZr4r#3qqb0dlwA7r*a707#|W1A>C#!Hk7(_OJ%34sL6JA!`ZjyS+sGb!N&N)BX(us2LzXcQ7&*#jFi4 z!c}>mVsc~RfWQUrIWec)390;n!okE20*nVV7mylNK-npzGR<6pNk_CVe;x8Vcu2nS zliXvLkY`}RicJdusUW4ovxN@uz>u-w@X#0lmY5#*!0jVh@jg`X$4#)rTcq|gA%#g6D!anpDq~dnc0Q3(? zWdK_oGfyDS0iHylfD<(b)x%F>UH0{?f%iI26IYPjF@gl{Z$<_Dv||ui+NqpdE-XtP zcZ&(q4@3c%3VyhYm`rmAYX36rD%v8S;PZfJkpP+) zScck&j?m7)-GFQ-${Pal3=ulcatpLaKICU6nASoqG9^J2c(ziIk*OJ$EkJtSDa{!M zv3w=N0-#g!^h1LchSb4+j|mLdbEx>vnk*dJ-)o#T3G!X-2bT<=d@1orGy1UFD3k*5h-Jq>sKSy@Rtk*MCWA1d918w zdGv)0!|Tw83XkW64OCYe-yLEN13DF*6~#&W-$~HC%I*bvqU#<#7+ks}A8t~*`f%Ow_ zxT&cTR*uNL%;-~{lxh_a0tC2Vnz0RxwA6-`p;U1EVTT6I;E6buAc;C9;1BCh)TpOY zOsW(q0xkkmNVA8?$3mZI|3Xs=pemx^$!19UN3aC+{TxQ-y9xT!D*V$1vntJZv}G0r zcB}R+wf2Lea?|q7Ur&qLK%^!Hk;tvF`K|lZ)7b_*lk4FzYgug#ix};948~Wfm-Z#3 zVJBu=-y&O-@4WvaQ;a&sX- zZr&~gN+tQ)8`{}wphD!F9F9E;AEEJR%oCXh%XOn$)HN?PN7)%?m&*$Q1KmtW75%9L z0$qO?p@Sbdc7mGGeHRd$L+eO``lwNda2M%k8fB|X+3bpFrTWh{Y#ET)>W5qapcJxF zT1|J@{;QLo^FD`twi`BFZqfGV-%JVwwA+tQ2{CMcizJaF_ZLDil5{9b z9>ly`XnER6f718NW7s|Q^JYCdt%YM8_n&0mmJ)cJi22M3YU}zX5U7>7qW=oPt$oy5 zyepg->>J=tkg0n|H2Ex~`|q;S-ypz$4(k5aNV5J@Bgx9f@taOz`;RjMlmC@YAzhQ; zlE?>ZZ4w;HIl^>0?Qxl3_*o-!#$%Q3Q_Lo1khC>~Os{vtzg&CwvDKCV6dLpiXczpt zhZxG#>XQOkCcQhKd1n+l6az%vc6=}(A9VHk0JG4$VYTleP^$=vERN*^qBt}$}eb&4%sEm$Q5Dy@<5 z8%Qmo6gULT1EYJOtE1*7^Ec)^G^3Xfl-GPVIBkB}XjOg+0coG>A@OBEMXSfrMhLeH z2Q#AuMOH&gl6SB`cKC)Fx6U!iX;PVZ@9xA%s+B=f^T0#opJ1zo0^Q4r;yHHo z3EI{~JOwK5olw7hZSSXnxG=kz!G-&m-szcRFv9WNrSwm@qnq8LB$3ckG-!T42m|Z4 zVBozo)ZoW0{4;?^&@ks!hh0K7?B0jLhAqvlcH7Ztju+XiEqqYv#Y(nEx`m@}D6-#~*Bk<4+vV@h6Vw z_!Gx-{E6c^{>1Sdf8uzKKXE+gA0USFPtec#XJyX6R{n1X^nYE(|D=Ha_XYpw`~L5M z9$;u>`PYE{|1dN{fQk=Vz%M7c7NR@#AfA#_^&B$(xDNd2Bq6S*FE95D=S36KkXL#F zc-)MPwA_`C0`opPr*8oR5y^fJM9kpheZ9>|I^0|IA+mdsD{nWuh(mH4_aI*9R5 z2z>K?gy`FACZuf~CNJy6Zeh<@qf6Pf| zDWyw}lYJ7Xpc@>pdfOV3L*)M$$o6?D*L`zi(6bey) ze|u#F7#ekc;_;i`yk2!7@V`HA{URupS%I`6)k;~Qwu(gfW*JU&ZZ6Zgf}I$ns?Jwf z&W|@gpPkpGv*kQO=6zS3VIy(AqIB$(xv)cv&}Fac2_RO)$?UKjUAo$ipa-gjKrf$4I{8- zTgd0(K=*ZjvWwrW3G7|>GW+A@A=ht1Z+=`%y10BLoYh^CeA4Txdt5%AS+<` zt!Tq6{bX4w2W43$49jsyw3NCN&dsypko8X!;cOoPC6l91thNennjv#EE#;*{#G@~+K?|P>YB-Hl!GtWXS)_V<5ljb|es~Z6={Q8u61a@o(b~g?&qMJA z-Q5K5jIQD+Dn&vh<&f`C0J4lh&ap8FV943BZC5_W@-^Bnxx5_J#kiz1q)(AWpyT>+ z-v{rj?20dmfi0Ww%%rwSaY@*D7$yfJst9gYnq2Z|NWc}Z;yukQDbeTk;@BOlwCL7f zt+;oiESb{<%t=O(%_Qb2U#F{bQDKV0IMVimT$KdF`^sYZS!Apb(~6Xnp1+63k7y`f z=)rJN%2KLPY@21Fu513oG1W09K*6MURp7t}F|+$nD{s}u2g_QeVO)}gJ(^8s?R1;I zxVK?5@_xs8QNY^Kp9|y6P0N_ z9P-1gY*>zMS4bnVP3gpVePa*^k$Uy4%+eE+VUW8_+88G6%}%T1J`wAr}7 zAH`VonMGbCCmEoUlXc?X%3h#8%KNKic+*|7zHljH++G8bo~saRpw6b20*0x$IRF&~ z0odLN3UwU^um^J33OmLKoOUvXqrx|MQ-qZ6pMq(6yt>MS78OxY^Qe}|Exrt~ixyPN zsR|J2Zs|#zo9Kz%Xld)dm$+Ar;L+FFN`P3Xzn29%Ojct|8wqa0f7vAZ8p^qP3sFtb zU^wt1T<|te8s=bjJd%``nA#Adae^ok>dkTeHMmSK<(h-3AghyCXCz~D-6bZ_Z0Zoo zr61u*+C_w9PQ=)jcR9zV<%2@P33nvEADZI{USvgbdlcASEO|jWK@?^m#o2H;pt(q4 z7$A7rMN-UE1Pb2;bIODRdWZ1n-G@uLZpJWi<=a5&*S34!+9=LEZz4QOO5eOYy+ZOzLh z&NCwl%@3A#v*lI9jax~2=)?jgoh5jKsoP%q<}K% z{>nUoS3z-FP}{-0!R4^Hz)HF?qY0ygh8y54tJy#HxjHwf2fW`sX)z@H+dz>NOH>7} zy%<(s3693x^f&Sjhjqh)?w z;iI^)?djTt_-H6h(M^~9=#NS5r|*2b>3aS3fTPog&J^dfZ?RkChRpary zI%E`_>+k$kqp(9u0urBwqR4J@RvgR=_C4xkv@p+7X7O3=;~aAts4na!wKc;#srU*Z z%7uf_`4RpbtJ($MvYD#qSq&T-DdTo6y#s1$GckfI?%-w_kCa22ScH`kwK-RDy;cQxt;{ zoBL))L{uxJEFC*d3jr1Ox{Jzh{jJ<@{jIa6Bnh0Hl_6QujxsQ02Qb2Z^EN_EV+MsA zix(0ombIkE1}-bokzD5o2aF~|`B4nN*Tcoe+exQC+E2GY?9&+!Mjmbyo|$8#tTOvz z{ffAV+$7EHPePnB(sfDPIu&_A8-wa&nZ*c^RKmOx8I~jHXPLaYIeVe`NhEyr2vi8* zBJc8JHM}KzNloFHm1{=mNtOzL*D7QY5iwj=?|*u79%Qfy0ZuwqOk{nWd-E4dF=4|_ zAZ6nwvSzN*Wv?!?ccs~P#*2ksqdFv2Rp!0rPlGyyXa-B3_(ZZ<-uU*$tq08$1B3+% zy@z;I(`xbKBq@zRbhx|Es`2Ugr`deZkHF{S%uU2|LsI;N865%W#BjWR>}QW z;iRjvotNL@OtQv9`)8giD~AM&8+rg{1=i=xefxTA;qy!sM3yXjqWH9?@26wpjvi8S zBx^@;ZUGB8!!%ih4P4P*OXov6wt;@l5G4qk(|R0B_wmRDaxdUW9wg=hlX+T5brMpQ zvu^LoRBA5?)wE$Y*BLRi=42fh&?}ThAF8R_f$$(b0mQEMBN_n3k^gH^B|tx#Qw$K~ z9w@svO__zihcuJ1?@RwS44u8&uYnSraZdj8M&^@)HxjtL;O~ea79Hq1E(ue>Vok?* z*W@-ly(?`^pLjHGCc&k55>tQhlo_3fw+ZV7S7xPZn>3%Mc1t!fE*7OzF#UwM>EByW z3y!x2c=}F5^K0eYRCxg|T(l=4WhdZ;m`!GtE(&=G@ zg9mP8SlV&@$owH#Tec-4l(DQIdPYV4Ed`?8n0T{sn)yM%08N-tXYO8 zFy{?`Kye~uZE9IF&NaprSE+t-W|tK5e5yJicOllj{UqI zi=J{5z1y*0Ldlj?m6~i0TPaOktUk=(zY9){pAj?=<+_AdE>0#-HXKc?FHZ^~N9rJ^ zS=ka@_&Un)+Y+$DzWt0o*z!pDx;qOh7bS*MHxil+&7P2B0Z?9(F9(ahg3CmVW0Y*s z?xtSH%!2l2WJi|)BhCqVanIDXb9VX#wjg8`H99@McH^9mZdLnV(=|KzS;l^;s2gZ- zX=dM!JTzmF$F5yYy6kM=A!IuC{1EyauP0bnMZZ^A`;{Ud2r@%`&T=nWR18V?Og)U zYCp4Hg`H&$(QwCH57NP!xyzf7uC}43p_$irexHK#k~M>f?jb8A(;;V3r#)xNg&sAm z0&`RA<;va447A9cg0qt}gNTG47Z59B5GUFf+Xhw_vF%Toii8mQ!faGWyR}HpBEO+3 zV@5vyY${=~V@%AsofXl8-z3ln&uYYvm)?*Hbwj}u5Pn2JLHz0-CKhXil#af=Ciy#+OBwqdSsCoEwJ=N zbQ3=olO_C*T(v4~aNa#w3_Y!ia^}TQRQP!sh^1?q>PHvS13WCpzcgMl0F4(XuK{&w z9wn&Q9TpnJ92@~Wz~JRRs5$#x2LoWRe`rxEm@a>TIY-mjyhia1zutSVKYOWneN>Xq zKv(s|E&DYQOK!Tn@TUJR*-`NmX0^LqEKU`7y*%?dZC|CM{AP1+0RBcIx{mG>6XyT1wB@COhgf)=G6Sq@`1paFHr`>Q3#ZC0+_w4d3gWX2Ztm|`N zAsFFk)9HPX0zuOl48M4S6MrcE#ZL;~Gp@#ENNhnfQEa;zZy?-A8w3yqXT7;{^2rXM zZ7LxYwRzG}e2ll@8@%V+Jyj~IpV=}b3{9#!SH2Q2B|3Jt|6rDL*;6F1O1P@iZmB3u zY|jVMT} zm|V#1?3s$4HpXZeW!{{FqVYc&M#(%lh|* z7|M%^cJeLeF%X9N|j~1IE!{*vyyQzgy4Bf@V`^yUZpZt-amSdeXL7Ge@^mj>{wMZ3st{L543Bq zJ0LTEB}T=|C(DePrZ0-}resr8YvKfv7D_n%l7 z45^51z6LQiAIHKXs2%Vfoz-~L%O^DjCb}SkBU`tqL>Vyg_KS>MArgKi;LX;OYv$z3 zO2W;AI3>W0ZN^@26h~f7S9EId3(S%(1V&Q=5K7|U-MGmW_b;Rjlz*oC!f6* zbY!>82K@9#bdAT)F~1t)Rw~n*t%e4h{emlP8PJwT(xQ(xjFa|>4O~VF#kD#NZ995{ zRSzKjmOW&k4VtbeZ)e3jawf7Kbw9X-H1iUfP3vzPtItr+w1Oqey79R-(KypUd)&)< z2n*OgWusk{39W;qwM}n~imn9RI1K%TwRNU!_;lcLDU~L+%n{OdfX>UcKL94QjLXW< z5apP?OGZeAjEi)D;dWW>BoqmC;~5uEr>Enf<1e8@slvfX)EpKfNIeqa z0JE@+y$P+!xLMauMQX?N9e97rNCq6I68h9D6CdfKl7j?}7Q%rr!y5Vm&QrkT>m#}j zB*->6Z5!5|7q8!nj@wkSt|gNNDrseHh3Diifp06)Ufx@C8yFXqJ54KP86}1fjEz|$ zEo>W0rYgOdjybBSjUTw03y4|9lY~X|76oH66W)l^cuGK&Xva;RsSMu_4#M^#A2qGW z`@1wvA`ZZ%tgzMN)hMF<2A7b9RFC8KW4nkv8^MBRk%qWzBm`Yjpa6b8yOF zBgcn|7ldlslvPu9(cPj1zX^x_;;F^%f8yQie00hgu9hh~CjhuQ%>k}X^BkdEJ|o4H zBcGk&<$-XQ@KA)`Ut(}p8-xG(ajX+VAMjb068>@o1IwLkjk^OH6rdwNysIcR6`H5@ z?ddjD%u0Q(qDS7eKdBw>HSL=5hT$!3N48veD|kwLfBi;1_a=PgUv)U;Ev)bWob5zl zH|3oJ)r$C_vl5_ zbB0~H7q+>xmT@#S<)ZO%jvbGHg^(WSDU#gg=hQ&Bn;d$YDwlf6!-4tf=1S$9V&&c& zH*d=)mTaFEkFN(*C#N@qaJvP-F^0SDL76mAlwA@)%Cc$hR$=DX9ba8y4; z+%uf765_Zd#YuW?YoS<=*T}k6t)qW=;v2;jX>{;eUz6u|j==+YS8qkJi&SSiecTW3 z6t1y<_;u#m7Q^Cb)-0y4tL}KNhCe*fdb5)ruX%+R5@0wXImY}TbD77y!RoPyxpC+Kz6m^dPbSvZ# zzYUV|#nmncsw~hYB$H2Gpavl-0Q>0d>`ufbHHlSGAM?-2XJ%hFWHO@u1ED!E|JN<0)GV;83>7w+Oz!7Dv zh`Fs-Sp`t>1AgMZ|whc`*hY2(#hnw;jP z7&$W&o zkH3UUlV7iUEi9jusvC^Vodz~25nmIun#u~hZI5^pUINQc!MFGsb)7~CYOlR?+pORd zKvaK*fIRI>BB>!S5R15_z9g|DN=e}FVWfk%OBZ=@Rcb@IzQQ9;#>mgu+of54m(n@U zFDTkZ`+E4)U7INN4%8l>>>?S)AMCXGqMeB4i%=gidDWJaruPJ{zLy@r^kTKA7h-Pf zQ(ovubEW^4?vBmj$QCi0LNB-?$u{31CMmA&IzoT1WbqY((%lj-xkN(|-QCYBC8a3s zn2cHSJqOJysV)CU*!)~v&74hfI6f3WuGbda^;NG8Fc#EvBv@;?;Y@?Zy(|Icf#Z*# zk%vMW-Bp^mW;;R3L_sB4N}>)XJIo1<*P^gLjnr0k8xh0!>h=psqLfD#Kasq>g=t)2 z2I)qu(~N_D5Ig()OseE=l2w^&@QPvrz?P#oUT#-Qy$#B!PQQary+GP~kiV?}3 z0Cy5cS<5Px{cUk9LpWZ_zeW671d+sqF|h>jl{!WjVGh55^}4p%K|-@=Azn*#br;bkf58kwS$O4u+}y4E97I;Iva2NhU#^3jS&X-t!NTMN<>@RT;` zGG+L-SeO{^-QW*8WrXki`|P4k|L`-0H=2<}wEb^>MnKH3kz+O~I$@$jm%cow$eJLY zMf*kKRP{3 z3uBuN(`y19IqE=HsQu*)pqh~&`?=Y4k-{WUnJG+IcHj<4QF2}pp)4H=qruNFK`BMwlwfF=1V;Y$7$(9a-uZ=0LsCP+zM-GO3G z^~5bL#O4$glERgEWgNp7qdYtQFZ_&I%E@iZh)H8QGE@?{TQ82kEuR}k%mLiGi&evP za2qNxGg!+2k0C(MNcJMXM^L~m)wNrZrf>;I@xlb%y4QLqO(VH@Nm41q#B1(xU_^kU zBTT2=clx-_`m^{#TS=;cS%X_@XjdL3Yle}taX3wim~>6Cx|~N!qBYnSV@rv)Qi>^i zuk!!N&R8j4_~nHx;&=0c_AKr#zCo=6b)I6&6KyXQr8aWrGCEFX#uL(XFLu5_+>n^cU$O$r=ZS`Jb0N7ZpN#1n#KB4aA!mFsk?f%g<7*8nX(=Fc4Kau#)YtSgtobFs zqZ!9#eLmnwzW~L4<^E|9G#%KtTK;jL9X2s;VY|qiNUf^D2)v=6`xN00x~5ShS?fmI zORMqizpyjL?q^opEB`w?x=8C*Yg z37gCqkPKYHOF; zKc1{VG{yKyUA0!2H@GTMru}N26`wr6InKJ0{xxs^oCX@>mtkydH)!0p*|Oy@8EY#4 zwld7CiWyQ?^N7b9wN}_)*kUl|{oSeNdN8W{cQKP)Cu=pCU2TA%k@2^nF{`wlCXxGk zXnh7~e!|gRH6_EgE9Ga~j)-A9!3>TmX_^8+wnnxWKQg=Vu^-d*^xkb6w4WKuy# zg45}wg@@fM%`=~fcxiTF9EorkHo+ZE5sIpI9XSA z$(%r5G$x4gK|MpnMn~&DEpF0@zWYVF?TnWfST3^T<~qJyGv8s9!Plwaw}6?I+)qCqQp?(NkUY3;vKU&_jDZd5)g zuDXiJT|D0p^g_N^@Uhz_)$YoThP!8`Z%Ki`TOo!rSP&W^8D-QrArqAXsoW4f&wqZn zlW%NMbKMw(ch%_n(6xcv}XE72$9#zM($>(Wxq{xqBMsn)t?by#26oHDR}U81Vdcc5%~K z_N)D8UkY~yEs9Jo;UrhyO%GLWA$0tWgk-7{h;Vc`!!S6R2OR_P_$T|?l*|NcBNs4= zUrA3%ETD!4A~R=~P7LqgmYC&|z&U9lgMlQ!we6EY#Sq(xe zJmUn01Sg8pc4Q;%Eiel}r$WV%n2h9W>?4KV!mnO-)c~U<--3n6JJo{HMzX3*-*65vg zt`1Fl4lM?^SNph`OvOr&rw&jVzMj*$5pVFrIZTR2?LEl4kSR?!6j{D?XW*`qI{0>q zUb+&5C2_T*Hn?1Al$)6ka*G6`8OnxctNB$l1ijx}zR5V6mAPSf*0h^9wH2xb*)0=ao;Vz+ zSmR?)WOR(G&;y@FUQl(J2Cn5KvBw+ZU)B`{G?ZrxR{j9x!Vk7uf>RX7R-=SWcH#_*Kf*Trwqzh}%vrV~nq2hKurs1Ly}lXba{c?T z^gM&y%L!i-H*#hF{_4_{srPeIY7ugbx6O6jk#6lQ%e@kFey?=Gu90#(vym+AN6a{t z>M&~XQsb0W1XY|cmJq9alnxx7#9@;s?FY+M?9gog%hs}vE|u}Qh|4HVeK!lW(uI4*h!sHp3%LKBJQXgmIni zJU3IDO8(-Z20ViG&C@^?`d4vO{zptR6kmiz7>Y&XNow>9@g%Id%dCF8$Fd(v+R@^* zGmLTv=4E;js%N56tQ2BYbIp{hj>;Ik8Wja;fqN4etXfgQuOzF zd#b7MbuI>}s=5-AU@v*!xfv&~>Ktf~)f#CZ*Yb$(gqwPAtoaQ_MM!4iYn zwp7V?r$%gXf4^59T_6l$ADJ-TFd?Z#FkPIRN9N&D+xg?&6`d>QF>6JqBH9RUwBX~! zwd-XKkrXZBWHI!>M+; zBiB8R8b!pA;49MfX;s_`?0lV5zSpW?&?&ksf{|$tek|BX`tm*!Bo(!`@nz`h>XVC^ zqtsB<_wP12m)OPY9*x?$moWKNhe4L7&dDK6x+Y(5n|?f8*SCmn#dkD|TP$P8K_b_e zWM25bjxX}Rn;RY!F866!#T;H5HW0|=|8$XSP(CX*xM}{`SVp@Ro}69Y(MoS@J(+E3 zeaAJ!Nsb&ufNb}Wdme&8_`s`E+T?-tW#{e3TBXgoVYz8MgzAO$WS?V)uEi8t`=}#t zRpYOV>IatfL?3N@k!lWX2r*GiEj)y0_S7Lpj?*b=&?C`<0((N~FEz(tn|@f{sVNB< z^Ti22vsOIO85{FrYo5oFc3RBZ55^Vpna9PiElIY~fUq1|;nOAk;GfPH(5GlQv;FmR zmpF{azt8)*Z#mC#>xCD^t-?oLWtosLN*+s`@-cbA2u#NYmuA z;@By>p~5p+C(h4wbU_TK!_;B3U&h~(F&b349`2yH&8IZ)Qv%4!D&)#X>1Ue65MAzo zpGRz!T0M(Vpk<_F*)ApX!+fTfQ!0S@eigl@o=Zir@yQ>KX=ar|4a-3eF|&V50R`NB z@bgmpOeE(G@0(cu1Po~)H!4j-|*ee4v)uBhg zE4QW5W8ueVn);3d#upkFBjTuHTZQ|~ShXjVJU2h%093lp8@;|ybda*A+LA(O-NpNu zJq|WiFZM&4iWq+3xyV}LbAs2Uv#e2eLNL$^ZC$g69o`mMWNsPC>9W}0$?s6|?^%K= zjM2Tc#4&|t>S|%KK1aYv%JqH%xtjc1A8`^CQ2PZp5q(?8Sua9poY1?Z;s<|81qViu z{7$ik8DFfc;`BOkUP%R#m@(^C$HUV0<{Vp>D^+=EYHof?FPfnnJ9@CTn}7H<;kWrM z1aRph+Kt6XnQ7&_3LQu zaBTbME|IqIxVO;*Gwdwx?Kx>|XV3{*4My)N;80dO{x3$S12LU`q3)wL+!W>%Ya4FHYRG71;sim#t znAyiD;RIvA+a4h`{r*x|2IeQC@N|a5ygsA^WsOAFU}I>AH?{q=Qf!nzS1W9BB=j&F zx=^m=m&%G*VcUu}D?w45O1vz{gYl>vxrqj#4{$Mbz;ix`w`D=P0^(o_OeW=d1FZT- zavSq)x=AEb0Xt-Hl@#^}=Ma|$&MO)nB3kFc%>E1LAQ33RTdHC3w5OH5okjXa+gCU? zX8if+CQieJtGXbl*~pGE17S>*(~&E_s!}?})0=1Vj3PSOpycv&bMkSt&M#}L_4}J~ z+FGGpr-epc7;n$c5Tq0IEFlR{U5G3vRQFC$wx3xZ1>$y%0&NuW{g-Sd*KZ1V0*Gw= zd&3Wr5x?y_QywB^Lxb=6b5O@XU*tv7BGiaI%e(9O%DcPCR@DU);E9so-6MgG12a$~ z1bGhS*7W3C%XV3X0c!+?qh3*1NJP3*T;Qd?!kk@QFY`70Jksk4k>EVYj6CL5p2jel}pMGDt-t&F-J!yV#+Io_241s`M zmA>scV$HXmpy2j=RjBo6pJS2VF-h)syefIs{82VtnQwP}yl^%g)4j}^a&G-K#%yPc zgFCpaz$oF#)@2-bB;0QdY<_kOsTwt zh0P$>EF=)arp~y!k%*EzQFqrG6}G;*&?85$eO%p{2`$Q4-uM=R!Q&a7r?@4e(X!J&_UyU+tXbCxui4So(H6^x-W(RG z%R?x9I{*ma_s!~9B>hmetXXkK|Ebm7T8L>V;rSjF!-|)+ghT>DK{vxNUQegZhDA>D zgmf24TVArHeT|0;u%RfV1H5_`AV&3(Bd}aVY`}lnW=|qt&e7n?lOh!gXsYq)t}y7V zF$S$~wKca>bmrM6VymR<885vn6_^}|4-Livot=jnJNR_F&R@wsfH*4AnZ5|f+?@t1 zSgM;sQ@473?jEEtS;($6n*_d{DsU$-&ZigwLT?kz1_)!>JFcUy8%E&uqP6!OWC@ee z)mdW+RiWKm!sKHOKL$6AFrbLxT#M$blYu#%=&{&(!E2u>hKeee^v9kP0pf7H`u6xK zFer6Kz?eL|+p)ALw<%1Stul|aQiHoGUbR^V#|SLH)}&o#GZ`y;yG)tp9Mg`Xq&yvY zR{m6&n`u8wLoUtr@Sl|dtJp`JNCw;`>wnOn00rJvcDPiQ>v4669@bleZ>e2k-xE|` z%N#(p+6feRr?zC#_o232<5x%Ajnx3AktVlXBj9~^NWa_mu#^)xUqbECNe2gsnXgo9 z6k~mxi34YusgEe$9=2N_FS5gzn@7f#NdKkd6M4XbdUZ>feeNaIk33zAa>QmR38Kx> zUhj2V9$D6Q@3R+K_LFp~g#=cW3GCB-TJhG)Bl{6n=_fshO=yBOehh0+rla7dJxy7@ zGsG8mkd@G2SS$BAuInN*)uFc~!*i5OAzi;S`7_x*>-B090QMTQx+Vji&1JyP|0E0d z(fRfLmnjYf*$`#pF%EYm-jU!@bxB$pGu#U*pzJLGH>GGr@UY-2T8Di_j8_e62Wcd? zl=N4UWDb@6MJM0OkqzugCmh>>eFWvsjt#oC9ka6&8sqb`3plE%^qB*QKee19wH8rN z;Z6i9&eJ1X4Tu{BG)?N`p6#`P&VF1SF5Q(;pYPSNYIkpOGR6+tnN7oHgWs7k#7*ng zu6^gOZAW%)H9-d596ha8rCa(Jcnu1lh+4K2-{kcOY(c#{FiDaa6nd^nLi&JRm%6`Iafu zbM&1UgA{=G-$9t>uKHDQmhhtHoZ^QUP!=I`ZwWYzEx3E`w?FPt3IX%+g!$m#jHZK` z*H9oBIV^I`jdG8L>nOF#(=TXtcdGH#s45M%KLeBmxjumkP)Zl0tF{EeMt3 zv(%&|_CHm_xpMMOk61n9(ywsEjPPjGA278b0k5Ys-$CIfPiS|MwC9DyLGOD(@zUb8 z8bqJt(WU<(=|z%v#FmD0(euI~yF;j$R&24^!TRx8J`CfP15!dK zp%G5Wt>$Nn;1ghLRPO4s^06GLeq}MBKfNYrvTB6cF$j;24(_ttF(Sgw)4;T%Hy+iB zr$KgqQ^LXa!tJydZa#g%G`Nu8sYMfevo=DyrtKNKAja^1OkrzljaFl7P2?G$nl%^@ zf@Z4?Y2TbrO!0*+HPFYOi5xmiQW>2f^x(x`)+A~dWIiF8)%gRrWE(m&v6Qv)Q`Phb z+b67|!e5Kl^*YL!zXPGi$#*eWYGr++FuN-0qX;%~0{Z&9_NF*5ZiF4rXK(2W>yt23 zmZ_*_{g(D6ty%vTTs+@Zbj`EvcXwcSOvUs|Xh*5GyrlUw$AyhaMpr|`IFX#qRin25 z`3PQL%h2moPS07c&8mnjr4;kK^qQ;iZyc*v#z}#?*(hv#WCDYv$n1s-f&noI1;T*quZ}3lG$8Rd?`S#PE)rRob&^Bfcm-Xj-E-9BN5`FW zSg*UlG@SOnd$CI;O|NizKw4ue?`#Ep;?4}fIvy$odO>j24{TgZz6kQdeDHVxp+$e{ zElUTY0dc2@IVYP&WRIiF1nf9-hR~GOIopFj?78{TM^D;ty9ja;gqw+FR{05WeKRRcIXL&?4 zeKJJ1!qr1kX)iHlPe}%_2n*XA+NkKrvEMGP$ESg*Ibv1)}VB0o1F2&ei;0x9dwOR`UiId2iFf)Z-;1<>H!nLR|zpkVgACl}EzNOVHu=R$5em4JVgF-Y1 z=2h5t4lg2u?%;piaMhcJCTu?6{9_im0>=0(y`|P$jA(G#V7v|{i5B^`)E;)d{#<~43I$49fw_Lp2R4>n< zdLtM|E+=ZaO*%MZo#{b3DwH4NdfwJo0QVgCA@`_TBT61KgX-u7k{+X9pH&qHQRN32 z6dP3O^b7j_Y%QXiei@9`+pcGF>jS|)Uz^3VNdbwaydNK#yQ)OO8Xb#-xSf@6+z+CA z<*+&93(-czU|idy$YYQ0c#`6wIk0jIjnMIg;H{ZGVkk~mS%OHI!j!!GVlaHh{Zbx$ zh|Q^%3(%rFKVuYpK)pF{IRvsLt=n^EFoG5Tngr#0KL1r3{9S;5C_B}D=OPo?xYZCb z|F0uO;!#eU(;Ihzt9U$M--jx;QAAhqEc0Bf){8X6=_>AzC$ct}@}zSsOko z;m$aLUf<7)N_xnIJ{V=Q^F$L4tnyplP>Az<_}qeae%~Fu^!%B?5Q~9hSvd*cV4u@4 z{d&`l*Y+f4(HCp8KQC=E4TRMvhugJ>fc8bJo3ql!HN$zopm8uqCGw57CBg$tHq| z&>y<93J)jbR~n){hu8DRbxz=y-`Cg4?)8@d^vA}I%9n>&mFH-ZvF_V17mg0)nm4cX zK}e)z#Tq8Dn9j-sC;}Q~Sc^2SdpGj=Jafx7ZgI}E3U-j%xEt7~`sMy0{3Q=DM5ZP+ z;uF``kG#c-H=0_>O1my%JB}#J-IBw0B^r=>_fq3FzE*K<_;;j*p$nxrO`7f+t!7wp zKPp(4qvLh_Si(X%ba5ue<04`OJ26}y97|YN3LU~mj%KL5=u1qc)K{eIrzQWRdso|N z?5=Q+_(v|n{$+_T!p=hY#P}oOS8o-!$1g3L>b zbTLOAhef&#n>ay|mBq=CMc!OW$9~Mv#CNr>Bv}m)l8w1?u=Rx8-8wjc81-20!t zbdz)}OZ<1rEr3001KT9o>__opjfh^NVh_m2l5yk@rAdf0#BcG51=WUilJmlpDUaM! zZNU!`hle~PVbyO0*KQDYm7=gI?6q?D!_W3Ar948o^fIZ5)FsGntDWFZ6ml@ZVPl%N z>1LADotgnuDWA&es$j5=sEvY0=DRtEr-Wy8M9zi7$lo z1p`{L&ETT3DYs>e^qz!SM)Y^=$rG7|q$z+3apxvNTkV1@&wys0=KgJ@U3Y5kGbx$4 zKdVKCf+R8P-HVLwaj4#kW=g_9;t(4IvN{V^$?(0cd^|AY?(iPmEd}!4Cr(6zhysXBHd26}kEw53NN~M>nrTX_O`yIMpvjAvfI{hz^~doU-FT37reI zRe)s0^+m>k@^#usH!i>X#D>!ENnacDsM30{6cIZI-po|#;fIZoX6S9cwZjTI>zy{s z$M%iVMoTQ?Fw(AtjQ_zOP#Y#OSqk)ryRD-|D$uCj7;VglhT)qBC0JzS->ppA}&mguVfq$a^Y?bb?_X=)@G`)qy= z4;LX9kf-%PDIyk#?=VnECT4*SQy#LY6c0~qyAeX9eD)NSSh^@L5*KSst&m6Bbvrb9c5U(>QE0>vkAs=TN(xyto&QC3^T1-S%LEL{O34ced5(>f} z-&9T)^v>AM&yVaNr)^_-=?40XV-2_^#5Pjhc{oVp_Lm_9Iijo#gb0s{7NlhG{Zv2yI39HeCtNHt&EZH^XIaSH4W(5*Uovh}| z&@EBm^;0$#f(-}CbQveh;aM`hsK*Q4Pmxun??!cO66ElM^%NKvZU??!3~4Sjqe5XbkEan#`bnPh+(~AW0fp;B zJ11U{Ylv%`C9Ug_c=?5Hq_Aic2Ji{JKg8r3D_IWX`CO;hbs!I?DRr|;|8|7@3$lKW z`pXdl_i|jz<;R#ej}|DCS!<^I3P>l2$2IX!g612 zJG8FHudb3Wlo!95)*Z_Vl$7N2yp5h1^=F3{o;#C(hOFBFhq^yYeND-S0pr6`A>oM# zK@5NEZ-r{(>BWHf`H{EbYZ*&}#PL6Fcv;3Gp&&z(2KzsPaffqoIh?$wb*!M#Z5@>; z9ZX;7t+^Qeel;X_A0THayeDG&tf_-~# zkO?ZCl;F!%+r^iF!;Y4d(}A|7o{!Cn*M}*pE+dp@DDcllbRJQ9zg79*)G=9rijkCd zNO-GtVVM-*r0DHT1VOP|WzjNO2EUe{=!!Kz?$LRi5y{8+X#`O!UJ{`#eh*Yb`k!-x z@^GP}*6tCP?~(!2*Gs*_MIgdkZYlwYIE5ZYpw-@@^Y8+u#|SJ`vBW%OM@$@PEj&M6 zJ=FKuxGermpWMag+Eqef0Hi{Qv&7XRB+c-P=j3+4?mAe#06L`yS|0XKMg%c zH4Hc%QX-&4Wj6!GUF`j;<}9dv>h)KLO^aS8@}3pg@H`?Mr)w{E@7IPychVk(Xmpvq zJKuwAbDia;aGl_~5G25A8Az~?8#z5wCwm`*KGQ7=oaYE2p5yS^QD;b8E=LNMzPWSN zxX>v!*>Qc!8le<_cMiN`!@NQJ0SZ6|j{oxCjq1P59RHgggpvL~o)1R)|9Cza>Hqb7 zF#PNJVEEVb!SJu=gW+G#2gARf4~Bm|9}NF-lQ1&;duE2e&;0+^1@aFe_?Ptr%!1liaJ(jdIYKU9xymNFIWZeV)x4G68jrX)E?l&olIVIT5HCUKHf>{V6>A7wM7Bi|5T-O5*<3L|hl|Kna_^s^gP0uH?>;g`lM(XUvpbcE5|1?{J?;95 z&4PJca_UJtTP61yP>(M}U3ljWpVE~#4>vj8zh@3&dbmEHMa)C2D=#3BvQ{>s3%xPT zn4WxoPrdm3ULbj*L>>Q>km^x1*OAaxU-b5%S$w#OHyP(c4L{1_wtd+f=c;L%{Hzk| zp~X%;_b5Ah_h+ew{8Bfa>*lt|v%G<7$t4=mZSkI?1T{!Q**u3T&zCJsBP{D`x-OEp zP{Dpz^x;d|(JbH``m5U#gj-cPj5?8<}sYu(Vo7@b=l7b zyzajdjnTzBcW|4X&2h^*J7xuQ3i#lq;pG$@A0Hp`y@J5VJd zMkD)_bk$@OYZwp35)q$NUZmO9%GaCYcf36Fb(IyUlWrv_i$AFw{y9#j==iOl{f&ZH z3va^UsYY0-^mG#Ph(apw#RvGC12N}bioo79cB2*UQC{40zLf7seCL+lJxnSIbXDGs zYNhm4>p&gza-oKeU7>DssuowSP^2qB_@o|kL?CF0d{EeLse*?8({eeB>_O6oSV}UH zpC1>_DXu;^jak=T($p6i&Cxzo0@m2pWQ#eZa?ARar z9)MfV0-%IIx|n9|)DYN3)8aXka-9kodGw(EUkXAg0(#TbmDhg2(xVCt2BnCq^vr`x zF3bY@$I&N_%0gZ@-ndSc#k<@N7})-1JQbtay;wD zS|v70%8f0{14$%_`p4~9HHK}{!7+XJ^cwV>eBn)3`%6tBvCsvQ^AJw{OzJW`BOvMJ zLUP#3ILpQgCdAx-c50J3>3=vv*kYR$41eE)wp;smkM=SFi(veN!2$|qHmdTbfSU^Wi$uAusGhIm)nsMSN5ojIHUT zB}Nmi{7g%grZ~3ZE7rgz>isIS4ic%8VPPTSC%veJ(1&2aCXR%UBlwoI_Ma+=!}Z;Q zTe9(?A)Te#th;gV?N-W>m<4&)6{p`rV_^{I)@&b^eKIIdSP;zX`{nxIfR@U?Z&1BR zZ|*4}J?uLuU)FK^?DNLdkC0t2wOEd;aUYdiZZLIIY9v$u+6#mg)PL=daYs+LIoU`a z7bRr_W;;t*G{{ z83}2Fjf>^{$ti0)*<-TU8dl~_Cn(`4%}qmMcL+MFa2bPbMw*e<^?SIE%6Ou%bQi4!D+ zcN`m|{K2b6(#t<55ETmhPFex{58>dS+2c`#h?+Y2OA+%ysdAos9JfVW&tQo^2IDbB zJ>6_Dh)08?B{_e-jLo^LM9CZ~nzhbe>!Q;3^$xIV-TU=}x6Rcz0OF~WFPT;@lvOZOv$PHdjGaT% z3Jcae(x4mWQ7E<7z=M!F)pr1d-Bn7K=-d7>HWcs=oW%k=bN%?GixwC4RY|MUEm3QQ zyv`ghnS-yGt+;x%SxN7!g@!#ea?xjJZb(Dn(>DTbw0vfPrNgTBMl~4RnIP(5q5QVu z@oMX!-Ra@w_zs@G*9@mKkZ$O8^y|#{`yowXYn9Nx}_A^b2jwh zSBVZ_+VmyDiIGSVlz4dWnFKN_(GQdTe)4a^Oly@yde?C7J>vQ=lM=XDq-HSNd80T@ zaV?DbyD+J)VU&koD+xd$|6GGP@V8gzqkGh{(k7AMJ&ICkX2U)`l_z41W$2*7E(Api zM;xFotm3NhvG)*=V&6`oC9-&L{_bU!F&*@ZR>_VB`R(huTCi+_uSWOH@G`Pz#2+8E zv!|^!@9W2BeNm?N|6dzA=fq@9mXctVPkmmsy=;ne{*psH-5va zf9GH`{x0{~cA}^wf=>)XB*=~aT9qwQbYShn`W2Tup2FUr(QPn}-C`?|+#fivRyP5p znN#`G=kB`+FF)8R`L!?XQpg7}h@=OD zx#yMrniFd!_@i^|wYj6IDb>!-pQ2o$sB-C{1EQj$9J1_;yL|aReUn6Txcd;wOkh>J zYN+`$6^_4+#6)I4kR8vZzCG8ISWGA1xN?vX_aJpc%GF#CPt`zPD*^f*l${12i1+&u zt?a1Co`O}uJ`1E$5O!2V_))eqv33pFamXVROy_$_bs(Z z0R;z)3w|g72Pg&-&KaK<*7-XPV1jXh{*xFJFn3Qk3USgDdY$$`4#J}Ya6&v8r zD>s4ul@5mFPSgFGaN}g05;Jl$DkjlHoRTs+$A?R=(h&nA=Dtr6(gY(XR>QhT z*RfgFem5x?*rFds!B#zGCjsxBV7~+-g9Cy~?8X2MIQd@-aS&`A4kxdSc+|pwVjZ8@ zCgM(~HCM-@FUJ+jS3HQO@Mo>0Y_`T>7J4^;y4Yo#Hbw5UPNO}Efnh_dhNQgHX_4oP zQSoGS&QnqL=oX#EnbFDqI6)BwRD(5m4DA_UwxxXSHo){i?Qxw737lUzB*kR+8oCIk zG{s@rFHG~&9KCsB1_RiP+nR36bP|TJy9s~$}d?kG>*Z~CO>a3iXJbNt=PAV6PVy9s4kpJGr=Yn zOcKnq<%4U=q5;Wosra7~(z{4>?S7z=0uS$;lfvXtnHy#)JKTInf>+uZxs@;YoTpWcZ6 zI{O^ePrkeS_-9+FqlQj$bNJ0?PEVBHxd=el)s{lXo@zEyPI?#I7w;V zVR-V!yXJhBVSQ8(9R@(Rx6-+sz(nmPILfY3guPvJvTM3CtT8u_`MXm!XF^i~4^(b) z7KGi+Xe`q3#P?1IS|Nf7Qd5(+-Z47$^Bfj~6WNg~+n6D(1i{1_a0#bK9qD#WV?tWdLQlZ3{qOUJAz)l-`g^}ywT8Z$^86>q%fRdU zB{p)(59u5L_i>L`L*=Otu`C)HTJ(Wu)T2BMm4MhHPc8D;s{3wsC~=o`xp&gd#yS#M z%tzFPSfR+-bKZk6`=ZGaPTvmE_%gjMt0X%5vw~JNB=M>`!hH!bN zQqEU`k7q`D$()PfYCrdMdOi+%K9BO_V``k9E{9z&6hHAtR5?isT@3ye9d$la}z4mSH-tcbl z-mc+M?0FT5w$g8D_lAULELtJq@Un{j7Arq-e*dls;QGpVZMylR`Q{)~mIG(`_?jSY z7ItK6A@vYK<{FHXthm5IE8T70mllgkWx_EP#|KK%ypVi&ru){wi1K2$w}2#3I;IY3 z;*We2^VwRqM95JxAQK{A-F!IDP&fRP*1bDRGlte90Y{qRt!dx2e-5kqV+8UB2=-NQTR+ws%T zhAfs1YdD3fVHeHFiHOil%2ER^_Os}aTBU!cW1J~{h&s#5Ud`OVa{AF{Y6BoKT7rYx z_)!0N*5M?%Kso93d0BY+x1zOvl6ez$;2|yzhshDzKtMrpnBuYG*qsP!%n?Yu9-ZD6 z%UEDMFF8iW(HXg+J_CyhbyLP~!VOB$_*RY1_~E4=SMfI->9ET7RuUE@Hc6WMxF=|y zdfpUe&fzWXMx6)iNN}0)hKO!Is*joB_L!7#jIf(D_u~YCvWWxI<*nlrIOWCWKbVg( zrLQCzZKM;AQ(BLHg*Fg!WO6A;k41~SQ7$GE!ljZ)LS8h@TWJTjAC>|S4Aye+x=%6N z7y2jeipQ@G2&f2hjwPIhfVo`~ zK`<$RM&`3u9<%w>RXw2$62)7&?d;7d9UTasn{_tt%6&{6|-= z78lR|f^ZP76uCDihT-ckCVsQ#lfUGoLda?}tk*|C5Ri|bie1b^k5A0N$otjKm}mbj zD|ZT+Rp98U+qV!&8eTgW9+w}X!_YVrgH(5|#SQ8dR*6peWMTx{Y$U#bJwwa3 zL-_(bo1UlRs31l5BoB8=L*I(G=2@tpXZaMrh?TTS-{x2w2}VnnSov0!UA|RikCjEu ztH|Z)Z^XcNb7V)!=&AbSeQ>dsMaLtPF|n50gMLrSA}6uq3MeW{+&o7yv1dYY>2_k5 zkzgpCLEDt?=E%e4g`#O6*(7=TGa`+OQYth`_W4DJQH$(!K})oA;Wi*vJ%(|Iio#M3 z9flEY#ud)__k*4>m7NNgP4RsM;bG_EQet)l1kpPArF3)ZpHsSW$IbJ^_ZyF>MnyY9 zc4Gx?EjX|8=tfAVwC?QAMPLP*J}=gGzEuZ)PIA2TbaF^>8ZCx%pr zyx=n$ga?>mZKSYn(mRSd8f)GyShR4O(=B+@j|=Xv2{k;M(+x_Z;>+Ev6ss_-u@DS1 zc9g@6N2*A_h2{GHQ&?7e@^Y|I?l=mVpf2J!RAsc>cth)kO;&1Trx-$#7qfP1{#KTy za@6JGxnw|6K-Ur@pE{X-{YjnFa6Zf*WK(~vfYL`vxt7QHi!?yuozA9j$Y<-2acxW^ z=kS6O5^=;3Dz*#px2{YqCUtDO98ch){Nq7TYT1#>b||>F&UFu#_3~ov#S;?ko^WPT z^lZIWeYB&#-^F0aT5FL=!c7Izr7)(e2%4j(5$((e(v6W70&nh->s(IzBPUXlV_09X>EEI5>PHmW1IOm{fb zh~C=w7wGT?fjxAllfYqG@*|aq$bKrX#NFFt7kh_!K0B>L(z)L6Pwtaq4~oI!@e{AU z2}cTE*19j$3{vX~bz=3;G}H#hr8cdkHl!g|6#XVzNS$Do*3-;7*+c;4i(UUmi>~Bh z*E1sj)-Ia_?{DARk`eNqOSF^7%v_j@0c(@VlF?@I{eCO8!O9)2RSr#Wf5e++r}{iX zH>22|8TEq;xE~k=3wf|^8(0*;r1`Egh!nf5JFLNTi0ZQt?sQk_c|_PxtrG4WJYLLQ zU)W5&VX*5)NO0(+^m;JAV~O!Pt}}%Voo<|NnT!?B$ekb&u`!-}Mnzg>J2x$k^i*K{ zE_{@@<6~P&6AXvy^C?B9A1;h`;T=DJlh7a7&ciUtJD62MM`K)YTq7m$s%%I*wq1oR zT`Zz)ycTPZJc;3bxK91bSnE&C;uhW#6~akszfpvVL>`JF6&-C{QJ8t7bM+Oh4!{r* zwWEeqzU`+96|>XrY@_~?r5@hykAS<`XlnCTJM%+jH(Ntrl(i)u2XmRd zy?)ERB?E3*>G9T)fzz?1OO%-UE_3_!#){)lanI1JAy#j5g?A1&rC6r+%S>8zv3rb1 zv`77buVJs;{J8wiycSFKU5Oe^2RzimVZm9pI6aVi@GsC~SGULCxGULCxGULCx zGULCxGULCxGULCxGUNXzmcT#FB>w-TBLDRZ{LfM1KPoZ{8$0X&sv=+EY(!JD-FbEE zXA>12dC-r#@J#z=`zR;FOMx_Xw*bIqeLokB z9kUX!Y%DJ9VX(Z{m2G-<;f!F>19I}Jc zlmYmK7K4`q=kqR4QIU9$`xOS~!|VNdw099Rs%u4dqBQ@OI$&rIz76OjRhs}O45WwS z2~wNm2;AQYkO5Dc0!1&)zXR~_y&0JTn-1*9aGb)8YVYqulqR$RGaTRF&{nMwr$X_B zyX0QA^jJ8Gz?v2y_IjpRcD}5iwKt$QhnirvL|Tz6X^o>N6MHYYzNQarMnRaV6_-q( zEC@k#Bd1$#d`IXG&murEG+!a@fxq*-2Q5p$2D?5wf_x3JCnFjnV3xivscqb;Te^?Y~jLh_IMBlZIWaeWI;m&X93= z-r?7%nEd+7{>Z)Qz?&IjPu(Ec;nC|82wgxh2Bsr50(3w;IIxs>o51783BUuNtQ1OoU&EBi#&ccf1{5_o-0Ju-66*3-l$?vswXg@p~1Sduz}){H%{0 zKUelXIy}2CUGd6<(XL}2P$dXzAF&&H(VTZ3K;r9U;D+_^dPyUkbo{|TBjl^Sh`7#v zGyQ=@G(ufi#bUB*OfXAefjFzXK!A{B818-vccQj1EucF}$>y>1(C~%`?s?-cp$jUS zETv5b%1hhlY`jaVpLp#~e;H9+&^ZQtGLhgot+oZCN&ArBQpN=P9*OM91|ZAcYVCCQ z*K)hg2sc{o%v){(>hNKLC;@d+>c23rH_P%ks8Zs#6D{gSpsj+(BHx4>Il`PP6M{Gi z^oC2;2X>k$Z1^DM?Fuiqngo@jTr1rCXxn1t;SkeAmz_!)sqaW}-v#kJ&wv!Cn9 zOK_}A$ouC0dVu~)DMC(WRJ&n zAPUcEOMpbE;&wm{4zpH&Q8C=Dv?rb%qj}s$2eTJ?aTg{KwL!r*xp71s@!6t% z;j)fl+Sd(t0Q~(zyXJSm*X6wTm5FziO(FWNtr_^Q$+C{jbI~m|;8rMpkfyd!d_x9g z{TCuYcylf&dUF8T5n{BI_5^EMYH&}@su_P2*zU5K2`gDSAXpa!KT-1EE#7NYExEsD zmo+cnSokN~={*615*dbT{aZJOt0e6FnrRp#lCVNm;2mC9co)#>A$w4pFx$Nd&CyB>sd!brcxsXl0U&kLJwzlLe7$kv%lU zfc0%$@Om2A`PxUrivjhOI+HHdz2(9{8iKpkz94{jpQD18wZvn?Qv_yktvljHKKvx|Zl%_f zm!1L0RkhF*KJ4XQFn@*%opV)=W;gyT5-q8LD}mQxhxDb|%D+j!k)CHAcnCWAyM5{M zKxJCw0-z^|ZEF1-E+vj-E|jUNFNXdE2mOUuhVR1h5&o`p-+q%5b+4U$czVPhc3{^W zed8W!E}B@lug(wHK0Di84ifB^^eBVBVzBaK?FA_6q9&N@zcJVgYsEftIg3$YdamHX zwI<49Y+LS!3ZQp|aRyx{#&`2PHu|-Mo7LK6$c72*;3}CNwmh?pa_jOnw8^1gvAdlk zKPA#5fGjg%F<-C)+k6-4-~6x`a4xYc*Rg>rrbTm^(SD>HGx}!ShwlaELv4aOAQVC$ z1J3&;!Bbm-In;qBoIqOU#7Aq=c?rkoWe5P#A(LgCzbm^8lo^vH@U|fFFRUKxl<&CKJW5oDt&l z3zWpPg!}a|rW)*Qkuq!T0m!|Y9r$8a5<^B>O2T`y5tL-Wydjb6On{NFV}qt#|3X&F zqpAfQ=iyaNd7e8%B)vRBY7jn0m7WKb@& zvQ^R?W}mLsVyEZt)WPs|dixkWlY7$mwX6^=1|$XOUF6g@vwnoXhYCk(8vH91*(MKG z+klOvcb7%-rhQ#N1U$okXW5cNs4 z@^MO(q&v6lj@!{n4mHPA7Cn^%u+q$bbY7rGCowZroR?)!x@Nh0q9XRSMn&wug*gxE zyKCr73hdiR50aWTk{YB?APfn6@)G&R|fHaiufa=YY^pbSp zq%;!KeNMOy7j3g2g8a!h3Spm7k`s6miQd5c;k-VP8p+dblpz@_<+-cuv#nS*u zfSY;-?K-gvXPoukt#NP(YV4FaJk;yO%`}oTao0NBcT!#W2#Xc(-kF5^lr+fI?$x`7wS>*GKW3_O zNoF}r{uIcc*hd_*UoJ6WmX4{&(+v|d(j`xsH>d`GazeIJLZTp1Wf=@!8`DC(&P_5k zes(#cU#eNg4IMem{FYs=bt)#SGMIlyzx`PYLMASvQa^mN)HwB>##__knPAyUxi$gy zIO&m<4Zcv*ee02FXw5*l_1U*SP;DJG7quh7H~r~@@?iLWbcwnHVso7Bdh#+;1xp;Rm8$nzWP!n>gm%6{k zrP}(zn+eRinY#mfUHDy$7id5)t9=*aTByVY@z2GejJ?MPA2^8dnNA5VPF(t4e^wv2 zCZ7>hPCH^7?Z8CSnXrUf=>(Wcr$X1DgzX%txhLnD+@AY(p)lloPE>KFLvtLio zB3pr+3%-FgAkd@qX%ej?+WLOZQ&_qE`^1{+n*cVX_#&6fgm($3WM^@tV2D|^3Mw$H zCQRovfBi>_s#$>&4OqKT?i~6ji;O)lIP8c6;0qpqfZTy%TrhTUz#gA-Ok-Df?-DJO z(#&i_=rT=PiJV9t9aF-3Jc)0g9A_#=hcid*^&%xK-KlQf`w$j5ew;1cuvvB!0I=>(F{8cE<0x6O5rLq&6mK>^zGRpIusM zYmwfV?yjlq^HLM{8B$`N z?1dId?Y+{fZ|tGp7WGCh#DkF{@H!^HdjQTS2KpIiGTtO}hg!e;=K|vvnn@WLqwOjH z>{!lp`7F6}yqlq6gK0VHa`T}nDKcHDX6@Sey6nV}it5lMGvKsbxa1t)9Pnj+;ogdj zFig=!dnJlfW((SRuX~z@e={_TAm)JOHI)3NCHpHl6iWXFx_z0HDl7;=J-(uO{3f?l z!s`>8=ruE-x`pmqX03V)rx`UQ=)^AL2g;u+7#}=shjeQ& zh$B*7>&k;f7{}RUIVHmhoBO4-CWM{hG60CqF~6EM~@ZUz*j?J%KwtxSMw? zjhr4I&POLKUEZ9%pDcAUy;ZHJZI;}X+#bNq{*gVvT5 z`)vHU>8PzSNY*3Lei55c%79KcF{_)mwTM|0dm{p8DhFi}f~d-*O~zK4<2+Gu6HON7 zgMmB>AG_#XKVJkvgzF41qM28OwFe+J1$Ac%AJx8ukaV193~1m#Cf z$oo|Z(oehae^B>M(UpGfwr_0PM#Z)(NyWBp+g8Q4om6bwwr$%L?fk#Bvd-CiukWHRI&g2wUe$N zQW$9T{A$s(YlB=xOAMx##+dqyMq!fd?z8__?vm%9w)2Kv+^8&BJ8?w0f{H5nxsu+4 zN>Vy=NS08zb#{V6%|lUxgf@_q&eZ8`ev`b+B@iP|ND6YH4AQZlRaEmZ-csrcAO%V{ zUv2@#QDdaAiFmnWtb1LA)Ckln#G$~!aGqv)kjI?UI5Beb)TmlPeRo^K-rt|(l{J9V z8=MB9nUG2m6YFk_g{)7^Cv^1?y=Wz>s?XrUSu>w=qWUFl#Uk zS0-v}88=oiH)MVONqs2iu3s0*u>j@j!EDc*E?;ik$HJQM+r>5%YlTjYAI6yy5Gi7( zY(}WPC?Z#_Ze+XD)RZi~ezz1@ip7TmuJ7`Ss zPW(S3LP+|49vOd!Ee(^|h5W?^SkUFoEh!-Pkq4pNqW6{Puq^#6NnQ^5h12BTAc#`a@prI1qNGi4h$*&@ z7othp{lY9LW{_`*HI2b#&G$t{p_#k%Wg7p+?i(=Z`Er>@-sw^_T8l@%K{QVNvvfwu z(l6I*#`A`0?^`MqMKM+ewEJ5E_Twn7qTb+1CW(?WlvtqN^dXKI?f=zyUPglDSqMea zmtF)({;IkYbU=b7G{iPTkkuI)Y(X6%Zh|NYN4ibnKT_kqs0l=f1f86kUHD7C=dj;% zT~0UFusu6C7X>j+RJ_JX&YUD}9SHlpo;ZML=8sS$w^)zir3PvQ6fu6M$5-k3bU%neA*YxgIpHID zY!O{rLk^NDV^ak3icMxyj<|hsXn5M;ueNOoy#y)!%igi~)qP=`+jG#A0!}YGa&8~M z#~NwfX>9rI@H=FlIoaXcX`IYO&N*uJH;`ww{uE7E70DK}OiJn4rFjtQRfQ9-Zv(;ok2{i@9ZkD4lWY2)| z$k#l^#@;g1v-sZ%FkJ!%iz=mwa>uZE9eYX`=MwZPn376azT3hu`9tdDYVB&GMf{~M z!V7_EXQu8<<_L6x-(M`CdivkS; z_7c5mK;9p@bXKEBTD|l^kd9Ir2s4=VW>w-Qbt_LKO99@CwJB9~r7r7>$T?c=p!5-O z;1znM>88E-n6UI*fW}J)2{K@=x!%{Xf0u$TX8!iXd^glOKwHw#tx) zGt46gt2+^}&n$*;Rl0q=Bb`Q6EwSi!Mqu%kuyv8`iMXASxNUAKPnHK2j+fV?M9|QR zT$cwG1RShgD_?WBX}Pa0b2cVp*a84>Y*=X0&$m7=*Z4eNaWN)5wv@-(p7O}lET zB99xQ4d?fK<}$pm=2@TmerZK`U8d)DS*;R|N?~bh`5&-_2f24qzj&jz4wo$-T%n1^ z3Bv!th!ip?C8!py1)0MF!A|&?d=;c=vZ@SeKOahew;N(O7}(`tmt5166~&4wgpHWR zRDlwDB(xBeCeqavxXzCAHov(XTbyX4C_ZaRUF3QooMaPxV=lhG>-5KnilrY$LMSKS z$%xJA;XqsTpVzI2?_Kdfo%E2Wo|aJAJ+U43f7(Q!>g6O49V5WM2L)3&1RMFQa2npF z#{D<|7>>S#E^GCK`c5h`eJeBl|4Sc_+fHNZ|hsLPWApAc_EA z_bZ=_5 zdg=Xj>%7wyUdRkzzS={MK9O2163$#){0N0LW-q#IzeJ=%d@^3k%Tcl{dRFgUuDL&; zp=q4*Xg*(k$TqWb=m9SJvZtKKy%X>Sde%PFuxYZdee&h_ic2S%-m^y7IC*~Tb)*#| zg4FHp@pY>6??<%9MUn64K#{=|K?;;NzTYM~?cS$;NDJ{|y7OD}9HD>t>oGrYMp_Pf z+1*Fqtb16-Hs!77dmJliHKgRYNe=g0P5b_sEDmnLqPqZ2vLP(OUKdn(@G z8wLSR9rcYIT~IZ8UJ|NT{>R$SC$1)UGkF9%>HU2C^elpti|dY%A^>0zuC^GI)E11! z(`Y~M^uuRSJ5cClu(Fi{{ZVk<4OWTeE!HQ=-1V_LcGby^F697#$b6kH0HS~>QH2R+ zgdJ|0SHJ6kq~m%B^yaUc-fbmUK$EO+(l>Ax`A%S#o&cRVOo-}N<8wZbfOERqnP*84 zGoEwD8!>ull~xa^e_mp_c}TIke?Gk#5CQlAy4r8$3uP2dhQx@7ULz!M6 zLW$iEOW;6YCFp^EVW{BuhzMRH%L8@JND1Nnd&cz1xRp$7 zxx|9N39MlDZyuX3Zy?KcdLW5*_ddMN&*8olnEa4X!>w_U#y**8E89tpj?bsdwY6j1 ze)~G(I4uB9FGJXglAxtIE(NsAdRnNoT@Y4qpr3%h?1@GBr6bp&4^2|lXRe(3@tV(5 zw?!)P$C#LT;H2WN$V@3}0sKIr!EU4TStYcr*8OO1i8YSK1NOnC1QudjqAs%CyZzAG z2=}I9)w3A{mJR%}8xCsDQU(SmtuCM2-EcL$(`lMurg&_72~RjYN`tF%QY}A-KhuL$ z(jNTSn~OQT%i;mS5UJ%+{kq!E;EJVv%L3_{8g#B;_QlSQ4M^Pn-d%M)-`?4v>Hjhg z7mULtV;MfYrHd-aHYPSrrpE$CO@Y5zLErkkZPKCpT~5`<{+L37SR@LH=={TK_=t-d z+Q)muTU3~FG3PyG+LTyX$qWKnf&M!5=sDKtLQZ!=m9oA-cCkd$w+3!W12dFbk|Slt zlwto7E$#t9GUl2~H8ponYJJ8YPFV#s2_3lnCO&KiE!}=lql0+4-X#`4Rc zOJ4+Mm2LdOJ!YI{4kb){#!Ht-TYAVU8-(cxrK zYi5(n`5aPEdGs-}p~h<+HxNGO_NG?ur$wY@!$8J&88}j>i`rB4=eO}X`!I1Hqjs+h zS3L>g8s@q`1w*KY!F4Hm4ukyKo^&ry;C9UePd5|Uyd9lLVBnY$Ud`T8u85d4c(!xO zEC>@Yuq?RsS}?X>>n?S7X2KlIxMO$^XE@qRJ4I-`K|LFx9te60QvWlV%;o{PxcCmP)zJEqyz>+?vf?Ew(?rn{L!c)@mTmCx3qk zj9V_o0|Gi%QBT`zlR6~az2(e5)R5RrpSevMdEm(__@&Ls;+G!jUH-7AjAfVKv`2AU z;C4yhF|g1!^^kT=y87)|b{NHyjN`zmC)^Q=Ag3Px$oiL}Cy-sdnF)hAoj;oExjrCE zU@H#}=(JAY5E;h)jyt4~0x&psv6mAAd27)u+)*&>NYN0`LSa=~tz@Wv=lN}tg~feEU&>clZFT$1Iyl@mc7Cc86gJ}=RyvQpw0 zt-hL3BT3x20~-yj33V6!tNGMh)tPDXtd(|vbjAS|YC7>*_tC|*!sgv8rfN7=0Bqyw8eg`b(*IzDVB~)=0@(pt-*1%$srUs3K=@7Z4)6~sz%DN; zis}UW4UVKu?4&O6eeMf^Wp1ciUpi_Zov&ZUzt6fOSv(Y)GP2q_N}Y}CsWdd}9mlpm zeJ}SfO8R>8%Z=I0ZM#v)t_7S;aebwJAuA5w0$gBG_s9o;yDCvKXsdJur_JjKgv{%t zc-kg5o6Y3bW7t5K!;$FybOTjAt_)p|YL7mnMQdu{HmtMaD)`Iyx%^&^yoOSuQFn(D;{aS^isd_pQ|+~k31h%) zOD+2K--`)I1F56w2CG#%gF>+XhXnOtcPXiSAtI=ZAW&%+KII1&^MW7EN06pK)+>g?IniKBG(}1}a|I6YYzOoX?#reX; zefzm>Z_Y>IB#>+KyY{lKg4^T_!}J1+^7q6+d3{%QmjYpjtX7`yLbI@r64bW|@lpll zzvZE%C5~}f$%LEM#12meNRsk4`w#jC-fg)@^bH@|4{`$5kE>Fz)@TzRs6Q=R;k}#$ zevx0044*R}?-D|`l(-^XX{)BZ{bqv1Bb(pRqkoFe6ib1#JAnIMZ!QxsgJ3PdZtu2aW_=I8fw^#?&3HbQfe$V6 zTr;WLNwVQwaeFJ))mgyJS=2hdp>V06Tv~;0_cO+&K0)=PG8NK@ZmO3;V(5qIeCX8J zV35)4N~q0AKOH+S1Y9xBO|dXOouuhTo&{o$AnVm+bR4`1FJ0zm2Gia0((}R0FLE+_ z_Eq+?;!Behy^1cTMqzv>nfzaXjnL^C?JR(KBM#7VlFQey5>fGAGbjYl{M9jUwVIb> z^B`9s>1iWOQ<8EB>aTR~y;Cj`5Q-);0Q(BcT~=noBtk@NgDMOFS>qSxHQ~@NP{hfR zn&5cE#W|nr$MD=~&Yr*v5TcbKG)cdZbmw}*OD#&6!{pkepUa?#4dsZR-DRax1u_A7h65}N9)edak^?SYPsbFBEFIpp-+qRO zX?@7{tk=_Cf36`nu4ly%S;zYsG~-;YEUY1Ee_nfV1I93L!XN@Ifh1828iQS8;YbG4 zev)y469k`BVI}6+^+McEzyU#E z8SlCqgoPbATL5h($f|4~F9r&V8Jtx>qXc)}qcmR4h#{^Ph=q@Yn=o%!W{T0?^Vs{x zFLqXaI+1*HgsdnJHY` zrcw_RJd`OUlIfa!uhQw-INob5XXwAHC zpEqJ!i)+opw`Ol7CpC#jN-)|VDBMgq2f;GK`BM?xFAkcom0-&)1IA0^o?IUYEK`($ zd0JF5m8(}fA>zb-4G`8~0|{=BHzxFi$b?tCb8__zS)zG`s@t+j)yj0Q730k2`igI^$Ebh3WL1HziX0IR>pw(j>(M=k1l4f{47KSmq)`BF~$EuW95!O1bT~!8ME>HI)M^0#_Vmha=l-24=2#?=s zucbIhVJ3%Nm|G{6PeYDUBgF;zvc*|wx^$zp+MI9l@WRxTZL`S}YC{=aCsU=u`nWHU zs$#$Mpa$t0)iudCvQ-9oH%b9lL&J7t`-=3-Th0Brj$9_CJ#9f^v4NN@(JAtM7c{R3 z>P+DihPNc-cvFilJH3i-tu?sD&Q0I!w7Z%Vl$N0ZJ}S%DC8Gt^(71OQ!;xDhWhtQ$ zx4kqZviCW5E=`7~&4d3($~pmPU2qZlRSH-a>k9rklZIAn>$DaYMs6{P~t|g zEkg?f++xd|fWyJC449?+P_~!e%hlgk*UG*^aNAI02b+2Fm+wV+1-S4rCGR%dPgh(` zpSW&AuT6X5169Wlz+R$#TpO+gB<{4>He|X%fav{3<2Ur%#ZZRJ&NjAcdRM&#CubNM zVKJks@KVq?Z^r$L|4EagT`qOmj8sD>?VkE7@1Y-!#XVPKD%7wM1#quvD3>Zrk&quH zF9Hnifp)SH=rpaO5UO-2g^Its4TL?zuLeYX>>4m#|_ICrm^Ygn?o}L}gJZ8p>yhBnJ1_~T4@E_9Z z0W4b8%Q5I@F&eLt31K0WbAi%rQrvn1{T9`>owOSMCIw+Q(=RL_9j+pT16?oCxu7{5 zQCVSBaarE%Sp_ zlxf^@*GP6UMeXyRM51bN;bcWlISEl_p^*OjZP6gaPk2oO(C&t3X65Nr*@0mw3SjSY zs~e+Xu1CPSS9$JBATk0Na$HIF=t2lW4srWZ0<_~Xf7SvtL0ET7)aqw?5c|lIo79q_ z-J12^eYQW5iy|b_0dL78z@-hu{{aV z9)9rDtoCP^gSPWfa{Q5^P;S`4q7nxgLlcg?Pi7_nlaLHF3qLLnn-vlbqhhvD#vGRr zR7fpAO@~uV1<9*WGpp8Wh=~LKF~?qSEgryztC;u&mE=-IAA=Hrx8RkGh@|xW_Mimi zuvbXoVy~O+9S92t)8cf!dsPXqV%txJ1Ei)Cw>QCG;onqaQnLZ3G%3|`!(xaj22Mqr ze?^fToc@xppGe{7%jHVhzvy@IyFyG}|8J-g|MJ4PoA`a;8$|L7U;@@l>@CoW%K3;g zU)*)8Y48_Ra;`?vU@QFP4YGE`SWi8=GtF{F3Vg>r#fU3j^cPi{O-Rr`%bPb9w}-Z@o{NH! z4pk;KHzWofTyLWMf%=Qr@QW%b|Ct{apTRD*&*I#pn1O1FIE$A|%LtpFuMW4C-=@?c zKaO5^shZ^)(4j(tW0a&<{__iptEcN&Hd}~M$M6d)4X0=fhTb==(v-}$$M577wan1| zle3Di)|zH#-4nK{eE^b_XVF=QT%+seRR#v@AbeW7)7VSMoa7)cH1}sT81VW99q?AYtjQSlNqtY+3G~k|G4IAw_-y9h`*c}

B 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

Pt)xA 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

f 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 %|OBt__ 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 ocaqxDQ?<2M@3^fnif{6$^PvJx|4G $@ + @[ -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)" + +clean: + git clean -fdX + +FORCE: ; diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/README.md b/lib/openzeppelin-contracts-v5.0.0/certora/README.md new file mode 100644 index 0000000..cd85ba3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/README.md @@ -0,0 +1,60 @@ +# Running the certora verification tool + +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). + +## 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 Certora Verification Tool proves specs for contracts, which are defined by the `./specs.json` file along with their pre-configured options. + +The verification script `./run.js` is used to submit verification jobs to the Certora Verification service. + +You can run it from the root of the repository with the following command: + +```bash +node certora/run.js [[CONTRACT_NAME:]SPEC_NAME] [OPTIONS...] +``` + +Where: + +- `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. + +> **Note** +> A single spec may be configured to run for multiple contracts, whereas a single contract may run multiple specs. + +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. + +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: + +```bash +make -C certora apply +``` + +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 +``` diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/diff/access_manager_AccessManager.sol.patch b/lib/openzeppelin-contracts-v5.0.0/certora/diff/access_manager_AccessManager.sol.patch new file mode 100644 index 0000000..29ff923 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/diff/access_manager_AccessManager.sol.patch @@ -0,0 +1,97 @@ +--- access/manager/AccessManager.sol 2023-10-05 12:17:09.694051809 -0300 ++++ access/manager/AccessManager.sol 2023-10-05 12:26:18.498688718 -0300 +@@ -6,7 +6,6 @@ + import {IAccessManaged} from "./IAccessManaged.sol"; + import {Address} from "../../utils/Address.sol"; + import {Context} from "../../utils/Context.sol"; +-import {Multicall} from "../../utils/Multicall.sol"; + import {Math} from "../../utils/math/Math.sol"; + import {Time} from "../../utils/types/Time.sol"; + +@@ -57,7 +56,8 @@ + * mindful of the danger associated with functions such as {{Ownable-renounceOwnership}} or + * {{AccessControl-renounceRole}}. + */ +-contract AccessManager is Context, Multicall, IAccessManager { ++// NOTE: The FV version of this contract doesn't include Multicall because CVL HAVOCs on any `delegatecall`. ++contract AccessManager is Context, IAccessManager { + using Time for *; + + // Structure that stores the details for a target contract. +@@ -105,7 +105,7 @@ + + // Used to identify operations that are currently being executed via {execute}. + // This should be transient storage when supported by the EVM. +- bytes32 private _executionId; ++ bytes32 internal _executionId; // private → internal for FV + + /** + * @dev Check that the caller is authorized to perform the operation, following the restrictions encoded in +@@ -253,6 +253,11 @@ + _setGrantDelay(roleId, newDelay); + } + ++ // Exposed for FV ++ function _getTargetAdminDelayFull(address target) internal view virtual returns (uint32, uint32, uint48) { ++ return _targets[target].adminDelay.getFull(); ++ } ++ + /** + * @dev Internal version of {grantRole} without access control. Returns true if the role was newly granted. + * +@@ -287,6 +292,11 @@ + return newMember; + } + ++ // Exposed for FV ++ function _getRoleGrantDelayFull(uint64 roleId) internal view virtual returns (uint32, uint32, uint48) { ++ return _roles[roleId].grantDelay.getFull(); ++ } ++ + /** + * @dev Internal version of {revokeRole} without access control. This logic is also used by {renounceRole}. + * Returns true if the role was previously granted. +@@ -586,7 +596,7 @@ + /** + * @dev Check if the current call is authorized according to admin logic. + */ +- function _checkAuthorized() private { ++ function _checkAuthorized() internal virtual { // private → internal virtual for FV + address caller = _msgSender(); + (bool immediate, uint32 delay) = _canCallSelf(caller, _msgData()); + if (!immediate) { +@@ -609,7 +619,7 @@ + */ + function _getAdminRestrictions( + bytes calldata data +- ) private view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) { ++ ) internal view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) { // private → internal for FV + if (data.length < 4) { + return (false, 0, 0); + } +@@ -662,7 +672,7 @@ + address caller, + address target, + bytes calldata data +- ) private view returns (bool immediate, uint32 delay) { ++ ) internal view returns (bool immediate, uint32 delay) { // private → internal for FV + if (target == address(this)) { + return _canCallSelf(caller, data); + } else { +@@ -716,14 +726,14 @@ + /** + * @dev Extracts the selector from calldata. Panics if data is not at least 4 bytes + */ +- function _checkSelector(bytes calldata data) private pure returns (bytes4) { ++ function _checkSelector(bytes calldata data) internal pure returns (bytes4) { // private → internal for FV + return bytes4(data[0:4]); + } + + /** + * @dev Hashing function for execute protection + */ +- function _hashExecutionId(address target, bytes4 selector) private pure returns (bytes32) { ++ function _hashExecutionId(address target, bytes4 selector) internal pure returns (bytes32) { // private → internal for FV + return keccak256(abi.encode(target, selector)); + } + } diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol new file mode 100644 index 0000000..e96883f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessControlDefaultAdminRules} from "../patched/access/extensions/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/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/AccessControlHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/AccessControlHarness.sol new file mode 100644 index 0000000..e862d3e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/AccessControlHarness.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessControl} from "../patched/access/AccessControl.sol"; + +contract AccessControlHarness is AccessControl {} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/DoubleEndedQueueHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/DoubleEndedQueueHarness.sol new file mode 100644 index 0000000..d684c73 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/DoubleEndedQueueHarness.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {DoubleEndedQueue} from "../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 (uint128) { + return _deque._begin; + } + + function end() external view returns (uint128) { + 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/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20FlashMintHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20FlashMintHarness.sol new file mode 100644 index 0000000..2f989b2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20FlashMintHarness.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +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/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20PermitHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20PermitHarness.sol new file mode 100644 index 0000000..08113f4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20PermitHarness.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20Permit, ERC20} from "../patched/token/ERC20/extensions/ERC20Permit.sol"; + +contract ERC20PermitHarness is ERC20Permit { + constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20WrapperHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20WrapperHarness.sol new file mode 100644 index 0000000..ca183ad --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC20WrapperHarness.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20Permit} from "../patched/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Wrapper, IERC20, ERC20} from "../patched/token/ERC20/extensions/ERC20Wrapper.sol"; + +contract ERC20WrapperHarness is ERC20Permit, ERC20Wrapper { + constructor( + IERC20 _underlying, + string memory _name, + string memory _symbol + ) ERC20(_name, _symbol) ERC20Permit(_name) ERC20Wrapper(_underlying) {} + + function underlyingTotalSupply() public view returns (uint256) { + return underlying().totalSupply(); + } + + 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); + } + + function decimals() public view override(ERC20Wrapper, ERC20) returns (uint8) { + return super.decimals(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC3156FlashBorrowerHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC3156FlashBorrowerHarness.sol new file mode 100644 index 0000000..1c76da2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC3156FlashBorrowerHarness.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +import {IERC3156FlashBorrower} from "../patched/interfaces/IERC3156FlashBorrower.sol"; + +pragma solidity ^0.8.20; + +contract ERC3156FlashBorrowerHarness is IERC3156FlashBorrower { + bytes32 somethingToReturn; + + function onFlashLoan(address, address, uint256, uint256, bytes calldata) external view override returns (bytes32) { + return somethingToReturn; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC721Harness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC721Harness.sol new file mode 100644 index 0000000..69c4c20 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC721Harness.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721} from "../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 unsafeOwnerOf(uint256 tokenId) external view returns (address) { + return _ownerOf(tokenId); + } + + function unsafeGetApproved(uint256 tokenId) external view returns (address) { + return _getApproved(tokenId); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC721ReceiverHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC721ReceiverHarness.sol new file mode 100644 index 0000000..3843ef4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/ERC721ReceiverHarness.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +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/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/EnumerableMapHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/EnumerableMapHarness.sol new file mode 100644 index 0000000..5c2f322 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/EnumerableMapHarness.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {EnumerableMap} from "../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/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/EnumerableSetHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/EnumerableSetHarness.sol new file mode 100644 index 0000000..3d18b18 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/EnumerableSetHarness.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {EnumerableSet} from "../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/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/InitializableHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/InitializableHarness.sol new file mode 100644 index 0000000..743d677 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/InitializableHarness.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Initializable} from "../patched/proxy/utils/Initializable.sol"; + +contract InitializableHarness is Initializable { + function initialize() public initializer {} + function reinitialize(uint64 n) public reinitializer(n) {} + function disable() public { _disableInitializers(); } + + function nested_init_init() public initializer { initialize(); } + function nested_init_reinit(uint64 m) public initializer { reinitialize(m); } + function nested_reinit_init(uint64 n) public reinitializer(n) { initialize(); } + function nested_reinit_reinit(uint64 n, uint64 m) public reinitializer(n) { reinitialize(m); } + + function version() public view returns (uint64) { + return _getInitializedVersion(); + } + + function initializing() public view returns (bool) { + return _isInitializing(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/Ownable2StepHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/Ownable2StepHarness.sol new file mode 100644 index 0000000..09a5faa --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/Ownable2StepHarness.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable2Step, Ownable} from "../patched/access/Ownable2Step.sol"; + +contract Ownable2StepHarness is Ownable2Step { + constructor(address initialOwner) Ownable(initialOwner) {} + + function restricted() external onlyOwner {} +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/OwnableHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/OwnableHarness.sol new file mode 100644 index 0000000..79b4b1b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/OwnableHarness.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable} from "../patched/access/Ownable.sol"; + +contract OwnableHarness is Ownable { + constructor(address initialOwner) Ownable(initialOwner) {} + + function restricted() external onlyOwner {} +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/PausableHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/PausableHarness.sol new file mode 100644 index 0000000..5977b92 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/PausableHarness.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Pausable} from "../patched/utils/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/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/TimelockControllerHarness.sol b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/TimelockControllerHarness.sol new file mode 100644 index 0000000..95ae406 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/harnesses/TimelockControllerHarness.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {TimelockController} from "../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/lib/openzeppelin-contracts-v5.0.0/certora/reports/2021-10.pdf b/lib/openzeppelin-contracts-v5.0.0/certora/reports/2021-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..22df9c61e6a9f74b29f90b6e36bd3d04f99756f5 GIT binary patch literal 92882 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 aXJ@ZxYwu)>@+&A9#pUoWT@sTO$NL{da>MEX literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/reports/2022-03.pdf b/lib/openzeppelin-contracts-v5.0.0/certora/reports/2022-03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b6ff81d1812c808e2f683c1e5fe10abf71ba5438 GIT binary patch literal 199401 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

E02esqZ$^2gTs{2 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 literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/reports/2022-05.pdf b/lib/openzeppelin-contracts-v5.0.0/certora/reports/2022-05.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f24a44910c4fba449300987456b5f440e7f99511 GIT binary patch literal 132223 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%0D7|ieYKPVYBX59b!U}f9eB5UvK%HwkWL{dR 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 UVZ$VVhf9Eu51oMlq$-2{KaJIBBLDyZ literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/run.js b/lib/openzeppelin-contracts-v5.0.0/certora/run.js new file mode 100755 index 0000000..7b65534 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/run.js @@ -0,0 +1,160 @@ +#!/usr/bin/env node + +// USAGE: +// 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 proc = require('child_process'); +const { PassThrough } = require('stream'); +const events = require('events'); + +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, + }, + verbose: { + alias: 'v', + type: 'count', + default: 0, + }, + 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); +} + +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; + } +} + +if (process.exitCode) { + process.exit(process.exitCode); +} + +for (const { spec, contract, files, options = [] } of specs) { + limit( + runCertora, + spec, + contract, + files, + [...options, ...argv.options].flatMap(opt => opt.split(' ')), + ); +} + +// 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]; + if (argv.verbose) { + console.log('Running:', args.join(' ')); + } + 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 job id, print the output link + stream.on('data', function logStatusUrl(data) { + 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); + } + }); + + // 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:\/\/prover.certora.com\/output\/\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:', + url ? `[link](${url?.replace('/output/', '/jobStatus/')})` : 'error', + url ? `[link](${url})` : 'error', + ), + ); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs.json b/lib/openzeppelin-contracts-v5.0.0/certora/specs.json new file mode 100644 index 0000000..3e5acb5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs.json @@ -0,0 +1,86 @@ +[ + { + "spec": "Pausable", + "contract": "PausableHarness", + "files": ["certora/harnesses/PausableHarness.sol"] + }, + { + "spec": "AccessControl", + "contract": "AccessControlHarness", + "files": ["certora/harnesses/AccessControlHarness.sol"] + }, + { + "spec": "AccessControlDefaultAdminRules", + "contract": "AccessControlDefaultAdminRulesHarness", + "files": ["certora/harnesses/AccessControlDefaultAdminRulesHarness.sol"] + }, + { + "spec": "DoubleEndedQueue", + "contract": "DoubleEndedQueueHarness", + "files": ["certora/harnesses/DoubleEndedQueueHarness.sol"] + }, + { + "spec": "Ownable", + "contract": "OwnableHarness", + "files": ["certora/harnesses/OwnableHarness.sol"] + }, + { + "spec": "Ownable2Step", + "contract": "Ownable2StepHarness", + "files": ["certora/harnesses/Ownable2StepHarness.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"] + }, + { + "spec": "ERC20Wrapper", + "contract": "ERC20WrapperHarness", + "files": [ + "certora/harnesses/ERC20PermitHarness.sol", + "certora/harnesses/ERC20WrapperHarness.sol" + ], + "options": [ + "--link ERC20WrapperHarness:_underlying=ERC20PermitHarness", + "--optimistic_loop" + ] + }, + { + "spec": "ERC721", + "contract": "ERC721Harness", + "files": ["certora/harnesses/ERC721Harness.sol", "certora/harnesses/ERC721ReceiverHarness.sol"], + "options": ["--optimistic_loop"] + }, + { + "spec": "Initializable", + "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", + "files": ["certora/harnesses/TimelockControllerHarness.sol"], + "options": ["--optimistic_hashing", "--optimistic_loop"] + } +] diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/AccessControl.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/AccessControl.spec new file mode 100644 index 0000000..70b0672 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/AccessControl.spec @@ -0,0 +1,119 @@ +import "helpers/helpers.spec"; +import "methods/IAccessControl.spec"; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Identify entrypoints: only grantRole, revokeRole and renounceRole can alter permissions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyGrantCanGrant(env e, method f, bytes32 role, address account) { + calldataarg args; + + bool hasRoleBefore = hasRole(role, account); + f(e, args); + bool hasRoleAfter = hasRole(role, account); + + assert ( + !hasRoleBefore && + hasRoleAfter + ) => ( + f.selector == sig:grantRole(bytes32, address).selector + ); + + assert ( + hasRoleBefore && + !hasRoleAfter + ) => ( + f.selector == sig:revokeRole(bytes32, address).selector || + f.selector == sig:renounceRole(bytes32, address).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: grantRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule grantRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + grantRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> isCallerAdmin; + + // effect + assert success => hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: revokeRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule revokeRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + revokeRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> isCallerAdmin; + + // effect + assert success => !hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: renounceRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule renounceRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + renounceRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> account == e.msg.sender; + + // effect + assert success => !hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/AccessControlDefaultAdminRules.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/AccessControlDefaultAdminRules.spec new file mode 100644 index 0000000..2f5bb9d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/AccessControlDefaultAdminRules.spec @@ -0,0 +1,464 @@ +import "helpers/helpers.spec"; +import "methods/IAccessControlDefaultAdminRules.spec"; +import "methods/IAccessControl.spec"; +import "AccessControl.spec"; + +use rule onlyGrantCanGrant filtered { + f -> f.selector != sig:acceptDefaultAdminTransfer().selector +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Definitions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition timeSanity(env e) returns bool = + e.block.timestamp > 0 && e.block.timestamp + defaultAdminDelay(e) < max_uint48; + +definition delayChangeWaitSanity(env e, uint48 newDelay) returns bool = + e.block.timestamp + delayChangeWait_(e, newDelay) < max_uint48; + +definition isSet(uint48 schedule) returns bool = + schedule != 0; + +definition hasPassed(env e, uint48 schedule) returns bool = + assert_uint256(schedule) < e.block.timestamp; + +definition increasingDelaySchedule(env e, uint48 newDelay) returns mathint = + e.block.timestamp + min(newDelay, defaultAdminDelayIncreaseWait()); + +definition decreasingDelaySchedule(env e, uint48 newDelay) returns mathint = + e.block.timestamp + defaultAdminDelay(e) - newDelay; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: defaultAdmin holds the DEFAULT_ADMIN_ROLE │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant defaultAdminConsistency(address account) + (account == defaultAdmin() && account != 0) <=> hasRole(DEFAULT_ADMIN_ROLE(), account) + { + preserved with (env e) { + require nonzerosender(e); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 + { + preserved { + requireInvariant defaultAdminConsistency(account); + requireInvariant defaultAdminConsistency(another); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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); + address adminBefore = defaultAdmin(); + address pendingAdminBefore = pendingDefaultAdmin_(); + uint48 scheduleBefore = pendingDefaultAdminSchedule_(); + + renounceRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + address adminAfter = defaultAdmin(); + address pendingAdminAfter = pendingDefaultAdmin_(); + uint48 scheduleAfter = pendingDefaultAdminSchedule_(); + + // liveness + assert success <=> ( + account == e.msg.sender && + ( + role != DEFAULT_ADMIN_ROLE() || + account != adminBefore || + ( + 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"; + + assert success => ( + ( + role == DEFAULT_ADMIN_ROLE() && + account == adminBefore + ) ? ( + adminAfter == 0 && + pendingAdminAfter == 0 && + scheduleAfter == 0 + ) : ( + adminAfter == adminBefore && + pendingAdminAfter == pendingAdminBefore && + scheduleAfter == scheduleBefore + ) + ), + "renouncing default admin role cleans state iff called by previous admin"; + + // 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) { + address adminBefore = defaultAdmin(); + f(e, args); + address adminAfter = defaultAdmin(); + + assert adminBefore != adminAfter => ( + f.selector == sig:acceptDefaultAdminTransfer().selector || + f.selector == sig:renounceRole(bytes32,address).selector + ), + "default admin is only affected by accepting an admin transfer or renoucing"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pendingDefaultAdmin is only affected by beginning, completing (accept or renounce), or canceling an admin │ +│ transfer │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noPendingDefaultAdminChange(env e, method f, calldataarg args) { + address pendingAdminBefore = pendingDefaultAdmin_(); + uint48 scheduleBefore = pendingDefaultAdminSchedule_(); + f(e, args); + address pendingAdminAfter = pendingDefaultAdmin_(); + uint48 scheduleAfter = pendingDefaultAdminSchedule_(); + + assert ( + pendingAdminBefore != pendingAdminAfter || + scheduleBefore != scheduleAfter + ) => ( + f.selector == sig:beginDefaultAdminTransfer(address).selector || + f.selector == sig:acceptDefaultAdminTransfer().selector || + f.selector == sig:cancelDefaultAdminTransfer().selector || + f.selector == sig:renounceRole(bytes32,address).selector + ), + "pending admin and its schedule is only affected by beginning, completing, or cancelling an admin transfer"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 == sig:changeDefaultAdminDelay(uint48).selector || + f.selector == sig: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 timeSanity(e); + require nonpayable(e); + require nonzerosender(e); + requireInvariant defaultAdminConsistency(e.msg.sender); + + 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 => to_mathint(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(); + + // change can only happen towards the newAdmin, with the delay + assert adminAfter != adminBefore => ( + adminAfter == newAdmin && + to_mathint(e2.block.timestamp) >= e1.block.timestamp + delayBefore + ), + "The admin can only change after the enforced delay and to the previously scheduled new admin"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: acceptDefaultAdminTransfer updates defaultAdmin resetting the pending admin and its schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule acceptDefaultAdminTransfer(env e) { + require nonpayable(e); + + address pendingAdminBefore = pendingDefaultAdmin_(); + uint48 scheduleBefore = pendingDefaultAdminSchedule_(); + + acceptDefaultAdminTransfer@withrevert(e); + bool success = !lastReverted; + + // liveness + assert success <=> ( + e.msg.sender == pendingAdminBefore && + isSet(scheduleBefore) && + hasPassed(e, scheduleBefore) + ), + "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); + require nonzerosender(e); + requireInvariant defaultAdminConsistency(e.msg.sender); + + 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 timeSanity(e); + require nonpayable(e); + require nonzerosender(e); + require delayChangeWaitSanity(e, newDelay); + requireInvariant defaultAdminConsistency(e.msg.sender); + + 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 => ( + assert_uint256(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 != delayBefore => ( + delayAfter == newDelay && + to_mathint(e2.block.timestamp) >= delayWait + ), + "A delay can only change after the 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 => to_mathint(pendingDelaySchedule_(e)) == increasingDelaySchedule(e, newDelay), + "Delay wait is the minimum between the new delay and a threshold when the delay is increased"; + assert newDelay <= oldDelay => to_mathint(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); + require nonzerosender(e); + requireInvariant defaultAdminConsistency(e.msg.sender); + + 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"; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/DoubleEndedQueue.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/DoubleEndedQueue.spec new file mode 100644 index 0000000..3b71bb4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/DoubleEndedQueue.spec @@ -0,0 +1,300 @@ +import "helpers/helpers.spec"; + +methods { + function pushFront(bytes32) external envfree; + function pushBack(bytes32) external envfree; + function popFront() external returns (bytes32) envfree; + function popBack() external returns (bytes32) envfree; + function clear() external envfree; + + // exposed for FV + function begin() external returns (uint128) envfree; + function end() external returns (uint128) envfree; + + // view + function length() external returns (uint256) envfree; + function empty() external returns (bool) envfree; + function front() external returns (bytes32) envfree; + function back() external returns (bytes32) envfree; + function at_(uint256) external returns (bytes32) envfree; // at is a reserved word +} + +definition full() returns bool = length() == max_uint128; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: empty() is length 0 and no element exists │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant emptiness() + empty() <=> length() == 0 + filtered { f -> !f.isView } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: front points to the first index and back points to the last one │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant queueFront() + at_(0) == front() + filtered { f -> !f.isView } + +invariant queueBack() + at_(require_uint256(length() - 1)) == back() + filtered { f -> !f.isView } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: pushFront adds an element at the beginning of the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushFront(bytes32 value) { + uint256 lengthBefore = length(); + bool fullBefore = full(); + + pushFront@withrevert(value); + bool success = !lastReverted; + + // liveness + assert success <=> !fullBefore, "never revert if not previously full"; + + // effect + assert success => front() == value, "front set to value"; + assert success => to_mathint(length()) == lengthBefore + 1, "queue extended"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pushFront preserves the previous values in the queue with a +1 offset │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushFrontConsistency(uint256 index) { + bytes32 beforeAt = at_(index); + + bytes32 value; + pushFront(value); + + // try to read value + bytes32 afterAt = at_@withrevert(require_uint256(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) { + uint256 lengthBefore = length(); + bool fullBefore = full(); + + pushBack@withrevert(value); + bool success = !lastReverted; + + // liveness + assert success <=> !fullBefore, "never revert if not previously full"; + + // effect + assert success => back() == value, "back set to value"; + assert success => to_mathint(length()) == lengthBefore + 1, "queue increased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pushBack preserves the previous values in the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushBackConsistency(uint256 index) { + 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 { + 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 => to_mathint(length()) == lengthBefore - 1, "queue decreased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: at(x) is preserved and offset to at(x - 1) after calling popFront | +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule popFrontConsistency(uint256 index) { + // 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(require_uint256(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 { + 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 => to_mathint(length()) == lengthBefore - 1, "queue decreased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: at(x) is preserved after calling popBack | +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule popBackConsistency(uint256 index) { + // Read (any) value that is not the back (this asserts the value exists / the queue is long enough) + require to_mathint(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 onlyEmptyOrFullRevert(env e) { + require nonpayable(e); + + method f; + calldataarg args; + + bool emptyBefore = empty(); + bool fullBefore = full(); + + f@withrevert(e, args); + + assert lastReverted => ( + (f.selector == sig:front().selector && emptyBefore) || + (f.selector == sig:back().selector && emptyBefore) || + (f.selector == sig:popFront().selector && emptyBefore) || + (f.selector == sig:popBack().selector && emptyBefore) || + (f.selector == sig:pushFront(bytes32).selector && fullBefore ) || + (f.selector == sig:pushBack(bytes32).selector && fullBefore ) || + f.selector == sig: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) { + 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) { + method f; + calldataarg args; + + uint256 lengthBefore = length(); + f(e, args); + uint256 lengthAfter = length(); + + assert lengthAfter != lengthBefore => ( + (f.selector == sig:pushFront(bytes32).selector && to_mathint(lengthAfter) == lengthBefore + 1) || + (f.selector == sig:pushBack(bytes32).selector && to_mathint(lengthAfter) == lengthBefore + 1) || + (f.selector == sig:popBack().selector && to_mathint(lengthAfter) == lengthBefore - 1) || + (f.selector == sig:popFront().selector && to_mathint(lengthAfter) == lengthBefore - 1) || + (f.selector == sig: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) { + 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 == sig:clear().selector ) || + (f.selector == sig:popBack().selector && index == length()) || + (f.selector == sig:popFront().selector && index == length()) + ), "indexes of the queue are only removed by clear or pop"; + + assert atAfterSuccess && atAfter != atBefore => ( + f.selector == sig:popFront().selector || + f.selector == sig:pushFront(bytes32).selector + ), "values of the queue are only changed by popFront or pushFront"; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20.spec new file mode 100644 index 0000000..21a0335 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20.spec @@ -0,0 +1,352 @@ +import "helpers/helpers.spec"; +import "methods/IERC20.spec"; +import "methods/IERC2612.spec"; + +methods { + // exposed for FV + function mint(address,uint256) external; + function burn(address,uint256) external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mathint sumOfBalances { + init_state axiom sumOfBalances == 0; +} + +// Because `balance` has a uint256 type, any balance addition in CVL1 behaved as a `require_uint256()` casting, +// leaving out the possibility of overflow. This is not the case in CVL2 where casting became more explicit. +// A counterexample in CVL2 is having an initial state where Alice initial balance is larger than totalSupply, which +// overflows Alice's balance when receiving a transfer. This is not possible unless the contract is deployed into an +// already used address (or upgraded from corrupted state). +// We restrict such behavior by making sure no balance is greater than the sum of balances. +hook Sload uint256 balance _balances[KEY address addr] STORAGE { + require sumOfBalances >= to_mathint(balance); +} + +hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) STORAGE { + sumOfBalances = sumOfBalances - oldValue + newValue; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: totalSupply is the sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant totalSupplyIsSumOfBalances() + to_mathint(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 == sig:mint(address,uint256).selector; + assert totalSupplyAfter < totalSupplyBefore => f.selector == sig: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 == sig:burn(address,uint256).selector || + e.msg.sender == account || + balanceBefore - balanceAfter <= to_mathint(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 == sig:approve(address,uint256).selector && e.msg.sender == holder) || + (f.selector == sig:permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector) + ); + + assert ( + allowanceAfter < allowanceBefore + ) => ( + (f.selector == sig:transferFrom(address,address,uint256).selector && e.msg.sender == spender) || + (f.selector == sig:approve(address,uint256).selector && e.msg.sender == holder ) || + (f.selector == sig:permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 to_mathint(balanceOf(to)) == toBalanceBefore + amount; + assert to_mathint(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 to_mathint(balanceOf(from)) == fromBalanceBefore - amount; + assert to_mathint(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 to_mathint(balanceOf(holder)) == holderBalanceBefore - (holder == recipient ? 0 : amount); + assert to_mathint(balanceOf(recipient)) == recipientBalanceBefore + (holder == recipient ? 0 : amount); + + // no other balance is modified + assert balanceOf(other) != otherBalanceBefore => (other == holder || other == recipient); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 to_mathint(allowance(holder, spender)) == (allowanceBefore == max_uint256 ? max_uint256 : allowanceBefore - amount); + + // balances of holder and recipient are updated + assert to_mathint(balanceOf(holder)) == holderBalanceBefore - (holder == recipient ? 0 : amount); + assert to_mathint(balanceOf(recipient)) == recipientBalanceBefore + (holder == recipient ? 0 : amount); + + // no other balance is modified + assert balanceOf(other) != otherBalanceBefore => (other == holder || other == recipient); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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: 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 to_mathint(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/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20FlashMint.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20FlashMint.spec new file mode 100644 index 0000000..5c87f0d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20FlashMint.spec @@ -0,0 +1,55 @@ +import "helpers/helpers.spec"; +import "methods/IERC20.spec"; +import "methods/IERC3156FlashLender.spec"; +import "methods/IERC3156FlashBorrower.spec"; + +methods { + // non standard ERC3156 functions + function flashFeeReceiver() external returns (address) envfree; + + // function summaries below + function _._update(address from, address to, uint256 amount) internal => specUpdate(from, to, amount) expect void ALL; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost: track mint and burns in the CVL │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mapping(address => mathint) trackedMintAmount; +ghost mapping(address => mathint) trackedBurnAmount; +ghost mapping(address => mapping(address => mathint)) trackedTransferedAmount; + +function specUpdate(address from, address to, uint256 amount) { + if (from == 0 && to == 0) { assert(false); } // defensive + + if (from == 0) { + trackedMintAmount[to] = amount; + } else if (to == 0) { + trackedBurnAmount[from] = amount; + } else { + trackedTransferedAmount[from][to] = amount; + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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] == to_mathint(amount); + assert trackedBurnAmount[receiver] == amount + to_mathint(recipient == 0 ? fees : 0); + assert (fees > 0 && recipient != 0) => trackedTransferedAmount[receiver][recipient] == to_mathint(fees); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20Wrapper.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20Wrapper.spec new file mode 100644 index 0000000..04e6704 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC20Wrapper.spec @@ -0,0 +1,198 @@ +import "helpers/helpers.spec"; +import "ERC20.spec"; + +methods { + function underlying() external returns(address) envfree; + function underlyingTotalSupply() external returns(uint256) envfree; + function underlyingBalanceOf(address) external returns(uint256) envfree; + function underlyingAllowanceToThis(address) external returns(uint256) envfree; + + function depositFor(address, uint256) external returns(bool); + function withdrawTo(address, uint256) external returns(bool); + function recover(address) external returns(uint256); +} + +use invariant totalSupplyIsSumOfBalances; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helper: consequence of `totalSupplyIsSumOfBalances` applied to underlying │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition underlyingBalancesLowerThanUnderlyingSupply(address a) returns bool = + underlyingBalanceOf(a) <= underlyingTotalSupply(); + +definition sumOfUnderlyingBalancesLowerThanUnderlyingSupply(address a, address b) returns bool = + a != b => underlyingBalanceOf(a) + underlyingBalanceOf(b) <= to_mathint(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 != currentContract && // invalid receiver + receiver != 0 && // invalid receiver + amount <= senderUnderlyingBalanceBefore && // deposit doesn't exceed balance + amount <= senderUnderlyingAllowanceBefore // deposit doesn't exceed allowance + ); + + // effects + assert success => ( + to_mathint(balanceOf(receiver)) == balanceBefore + amount && + to_mathint(totalSupply()) == supplyBefore + amount && + to_mathint(underlyingBalanceOf(currentContract)) == wrapperUnderlyingBalanceBefore + amount && + to_mathint(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 != currentContract && // invalid receiver + receiver != 0 && // invalid receiver + amount <= balanceBefore // withdraw doesn't exceed balance + ); + + // effects + assert success => ( + to_mathint(balanceOf(sender)) == balanceBefore - amount && + to_mathint(totalSupply()) == supplyBefore - amount && + to_mathint(underlyingBalanceOf(currentContract)) == wrapperUnderlyingBalanceBefore - (currentContract != receiver ? amount : 0) && + to_mathint(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; + + mathint 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 => ( + to_mathint(balanceOf(receiver)) == balanceBefore + value && + to_mathint(totalSupply()) == supplyBefore + value && + totalSupply() == underlyingBalanceOf(currentContract) + ); + + // no side effect + assert underlyingBalanceOf(other) == otherUnderlyingBalanceBefore; + assert balanceOf(other) != otherBalanceBefore => other == receiver; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC721.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC721.spec new file mode 100644 index 0000000..bad4c47 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/ERC721.spec @@ -0,0 +1,679 @@ +import "helpers/helpers.spec"; +import "methods/IERC721.spec"; +import "methods/IERC721Receiver.spec"; + +methods { + // exposed for FV + function mint(address,uint256) external; + function safeMint(address,uint256) external; + function safeMint(address,uint256,bytes) external; + function burn(uint256) external; + + function unsafeOwnerOf(uint256) external returns (address) envfree; + function unsafeGetApproved(uint256) external returns (address) envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ + +definition authSanity(env e) returns bool = e.msg.sender != 0; + +// Could be broken in theory, but not in practice +definition balanceLimited(address account) returns bool = balanceOf(account) < max_uint256; + +function helperTransferWithRevert(env e, method f, address from, address to, uint256 tokenId) { + if (f.selector == sig:transferFrom(address,address,uint256).selector) { + transferFrom@withrevert(e, from, to, tokenId); + } else if (f.selector == sig:safeTransferFrom(address,address,uint256).selector) { + safeTransferFrom@withrevert(e, from, to, tokenId); + } else if (f.selector == sig: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 == sig:mint(address,uint256).selector) { + mint@withrevert(e, to, tokenId); + } else if (f.selector == sig:safeMint(address,uint256).selector) { + safeMint@withrevert(e, to, tokenId); + } else if (f.selector == sig:safeMint(address,uint256,bytes).selector) { + bytes params; + require params.length < 0xffff; + safeMint@withrevert(e, to, tokenId, params); + } else { + require false; + } +} + +function helperSoundFnCall(env e, method f) { + if (f.selector == sig:mint(address,uint256).selector) { + address to; uint256 tokenId; + require balanceLimited(to); + requireInvariant notMintedUnset(tokenId); + mint(e, to, tokenId); + } else if (f.selector == sig:safeMint(address,uint256).selector) { + address to; uint256 tokenId; + require balanceLimited(to); + requireInvariant notMintedUnset(tokenId); + safeMint(e, to, tokenId); + } else if (f.selector == sig:safeMint(address,uint256,bytes).selector) { + address to; uint256 tokenId; bytes data; + require data.length < 0xffff; + require balanceLimited(to); + requireInvariant notMintedUnset(tokenId); + safeMint(e, to, tokenId, data); + } else if (f.selector == sig:burn(uint256).selector) { + uint256 tokenId; + requireInvariant ownerHasBalance(tokenId); + requireInvariant notMintedUnset(tokenId); + burn(e, tokenId); + } else if (f.selector == sig:transferFrom(address,address,uint256).selector) { + address from; address to; uint256 tokenId; + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant notMintedUnset(tokenId); + transferFrom(e, from, to, tokenId); + } else if (f.selector == sig:safeTransferFrom(address,address,uint256).selector) { + address from; address to; uint256 tokenId; + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant notMintedUnset(tokenId); + safeTransferFrom(e, from, to, tokenId); + } else if (f.selector == sig:safeTransferFrom(address,address,uint256,bytes).selector) { + address from; address to; uint256 tokenId; bytes data; + require data.length < 0xffff; + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant notMintedUnset(tokenId); + safeTransferFrom(e, from, to, tokenId, data); + } else { + calldataarg args; + f(e, args); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: ownership count │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mathint _ownedTotal { + init_state axiom _ownedTotal == 0; +} + +ghost mapping(address => mathint) _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_mathint(newOwner != 0 ? 1 : 0); + _ownedByUser[oldOwner] = _ownedByUser[oldOwner] - to_mathint(oldOwner != 0 ? 1 : 0); + _ownedTotal = _ownedTotal + to_mathint(newOwner != 0 ? 1 : 0) - to_mathint(oldOwner != 0 ? 1 : 0); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mathint _supply { + init_state axiom _supply == 0; +} + +ghost mapping(address => mathint) _balances { + init_state axiom forall address a. _balances[a] == 0; +} + +hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) STORAGE { + _supply = _supply - oldValue + newValue; +} + +// TODO: This used to not be necessary. We should try to remove it. In order to do so, we will probably need to add +// many "preserved" directive that require the "balanceOfConsistency" invariant on the accounts involved. +hook Sload uint256 value _balances[KEY address user] STORAGE { + require _balances[user] == to_mathint(value); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: number of owned tokens is the sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant ownedTotalIsSumOfBalances() + _ownedTotal == _supply + { + preserved mint(address to, uint256 tokenId) with (env e) { + require balanceLimited(to); + } + preserved safeMint(address to, uint256 tokenId) with (env e) { + require balanceLimited(to); + } + preserved safeMint(address to, uint256 tokenId, bytes data) with (env e) { + require balanceLimited(to); + } + preserved burn(uint256 tokenId) with (env e) { + requireInvariant ownerHasBalance(tokenId); + requireInvariant balanceOfConsistency(ownerOf(tokenId)); + } + preserved transferFrom(address from, address to, uint256 tokenId) with (env e) { + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant balanceOfConsistency(from); + requireInvariant balanceOfConsistency(to); + } + preserved safeTransferFrom(address from, address to, uint256 tokenId) with (env e) { + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant balanceOfConsistency(from); + requireInvariant balanceOfConsistency(to); + } + preserved safeTransferFrom(address from, address to, uint256 tokenId, bytes data) with (env e) { + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant balanceOfConsistency(from); + requireInvariant balanceOfConsistency(to); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: balanceOf is the number of tokens owned │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant balanceOfConsistency(address user) + to_mathint(balanceOf(user)) == _ownedByUser[user] && + to_mathint(balanceOf(user)) == _balances[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)); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: balance of address(0) is 0 │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule zeroAddressBalanceRevert() { + balanceOf@withrevert(0); + assert lastReverted; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: address(0) has no authorized operator │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant zeroAddressHasNoApprovedOperator(address a) + !isApprovedForAll(0, a) + { + preserved with (env e) { + require nonzerosender(e); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: tokens that do not exist are not owned and not approved │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant notMintedUnset(uint256 tokenId) + unsafeOwnerOf(tokenId) == 0 => unsafeGetApproved(tokenId) == 0; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: unsafeOwnerOf and unsafeGetApproved don't revert + ownerOf and getApproved revert if token does not exist │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule notMintedRevert(uint256 tokenId) { + requireInvariant notMintedUnset(tokenId); + + address _owner = unsafeOwnerOf@withrevert(tokenId); + assert !lastReverted; + + address _approved = unsafeGetApproved@withrevert(tokenId); + assert !lastReverted; + + address owner = ownerOf@withrevert(tokenId); + assert lastReverted <=> _owner == 0; + assert !lastReverted => _owner == owner; + + address approved = getApproved@withrevert(tokenId); + assert lastReverted <=> _owner == 0; + assert !lastReverted => _approved == approved; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: total supply can only change through mint and burn │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule supplyChange(env e) { + require nonzerosender(e); + requireInvariant zeroAddressHasNoApprovedOperator(e.msg.sender); + + mathint supplyBefore = _supply; + method f; helperSoundFnCall(e, f); + mathint supplyAfter = _supply; + + assert supplyAfter > supplyBefore => ( + supplyAfter == supplyBefore + 1 && + ( + f.selector == sig:mint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256,bytes).selector + ) + ); + assert supplyAfter < supplyBefore => ( + supplyAfter == supplyBefore - 1 && + f.selector == sig: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); + + mathint balanceBefore = balanceOf(account); + method f; helperSoundFnCall(e, f); + mathint 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 == sig:transferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256,bytes).selector || + f.selector == sig:mint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256,bytes).selector || + f.selector == sig:burn(uint256).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: ownership can only change through mint, burn or transfers. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule ownershipChange(env e, uint256 tokenId) { + require nonzerosender(e); + requireInvariant zeroAddressHasNoApprovedOperator(e.msg.sender); + + address ownerBefore = unsafeOwnerOf(tokenId); + method f; helperSoundFnCall(e, f); + address ownerAfter = unsafeOwnerOf(tokenId); + + assert ownerBefore == 0 && ownerAfter != 0 => ( + f.selector == sig:mint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256,bytes).selector + ); + + assert ownerBefore != 0 && ownerAfter == 0 => ( + f.selector == sig:burn(uint256).selector + ); + + assert (ownerBefore != ownerAfter && ownerBefore != 0 && ownerAfter != 0) => ( + f.selector == sig:transferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256).selector || + f.selector == sig: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; helperSoundFnCall(e, f); + address approvalAfter = unsafeGetApproved(tokenId); + + // approve can set any value, other functions reset + assert approvalBefore != approvalAfter => ( + f.selector == sig:approve(address,uint256).selector || + ( + ( + f.selector == sig:transferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256,bytes).selector || + f.selector == sig: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; helperSoundFnCall(e, f); + bool approvedForAllAfter = isApprovedForAll(owner, spender); + + assert approvedForAllBefore != approvedForAllAfter => f.selector == sig:setApprovalForAll(address,bool).selector; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: transferFrom behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule transferFrom(env e, address from, address to, uint256 tokenId) { + require nonpayable(e); + require authSanity(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 => ( + to_mathint(balanceOf(from)) == balanceOfFromBefore - assert_uint256(from != to ? 1 : 0) && + to_mathint(balanceOf(to)) == balanceOfToBefore + assert_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 == sig:safeTransferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256,bytes).selector +} { + require nonpayable(e); + require authSanity(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 => ( + to_mathint(balanceOf(from)) == balanceOfFromBefore - assert_uint256(from != to ? 1: 0) && + to_mathint(balanceOf(to)) == balanceOfToBefore + assert_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); + + mathint supplyBefore = _supply; + 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 => ( + _supply == supplyBefore + 1 && + to_mathint(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 == sig:safeMint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256,bytes).selector +} { + require nonpayable(e); + requireInvariant notMintedUnset(tokenId); + + uint256 otherTokenId; + address otherAccount; + + require balanceLimited(to); + + mathint supplyBefore = _supply; + 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 => ( + _supply == supplyBefore + 1 && + to_mathint(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); + + mathint supplyBefore = _supply; + 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 => ( + _supply == supplyBefore - 1 && + to_mathint(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); + require authSanity(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 == 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 <=> operator != 0; + + // effect + assert success => isApprovedForAll(owner, operator) == approved; + + // no side effect + assert isApprovedForAll(otherOwner, otherOperator) != otherIsApprovedForAllBefore => ( + otherOwner == owner && + otherOperator == operator + ); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/EnumerableMap.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/EnumerableMap.spec new file mode 100644 index 0000000..7b50303 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/EnumerableMap.spec @@ -0,0 +1,333 @@ +import "helpers/helpers.spec"; + +methods { + // library + function set(bytes32,bytes32) external returns (bool) envfree; + function remove(bytes32) external returns (bool) envfree; + function contains(bytes32) external returns (bool) envfree; + function length() external returns (uint256) envfree; + function key_at(uint256) external returns (bytes32) envfree; + function value_at(uint256) external returns (bytes32) envfree; + function tryGet_contains(bytes32) external returns (bool) envfree; + function tryGet_value(bytes32) external returns (bytes32) envfree; + function get(bytes32) external returns (bytes32) envfree; + + // FV + function _indexOf(bytes32) external returns (uint256) envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition sanity() returns bool = + 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) == to_bytes32(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(require_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, require_uint256(length() - 1)); + requireInvariant atUniqueness(index2, require_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() => to_mathint(_indexOf(key_at(index))) == index + 1 + { + preserved remove(bytes32 key) { + requireInvariant consistencyIndex(require_uint256(length() - 1)); + } + } + +invariant consistencyKey(bytes32 key) + contains(key) => ( + _indexOf(key) > 0 && + _indexOf(key) <= length() && + key_at(require_uint256(_indexOf(key) - 1)) == key + ) + { + preserved remove(bytes32 otherKey) { + requireInvariant consistencyKey(otherKey); + requireInvariant atUniqueness( + require_uint256(_indexOf(key) - 1), + require_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 == sig:set(bytes32,bytes32).selector && to_mathint(lengthAfter) == lengthBefore + 1) || + (f.selector == sig:remove(bytes32).selector && to_mathint(lengthAfter) == lengthBefore - 1) + ); + + assert containsBefore != containsAfter => ( + (f.selector == sig:set(bytes32,bytes32).selector && containsAfter) || + (f.selector == sig:remove(bytes32).selector && !containsAfter) + ); + + assert valueBefore != valueAfter => ( + (f.selector == sig:set(bytes32,bytes32).selector && containsAfter) || + (f.selector == sig:remove(bytes32).selector && !containsAfter && valueAfter == to_bytes32(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 == to_bytes32(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 to_mathint(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 to_mathint(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 = require_uint256(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/lib/openzeppelin-contracts-v5.0.0/certora/specs/EnumerableSet.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/EnumerableSet.spec new file mode 100644 index 0000000..3db5158 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/EnumerableSet.spec @@ -0,0 +1,246 @@ +import "helpers/helpers.spec"; + +methods { + // library + function add(bytes32) external returns (bool) envfree; + function remove(bytes32) external returns (bool) envfree; + function contains(bytes32) external returns (bool) envfree; + function length() external returns (uint256) envfree; + function at_(uint256) external returns (bytes32) envfree; + + // FV + function _indexOf(bytes32) external returns (uint256) envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition sanity() returns bool = + length() < max_uint256; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: All indexed keys are contained │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant indexedContained(uint256 index) + index < length() => contains(at_(index)) + { + preserved { + requireInvariant consistencyIndex(index); + requireInvariant consistencyIndex(require_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, require_uint256(length() - 1)); + requireInvariant atUniqueness(index2, require_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)) == require_uint256(index + 1) + { + preserved remove(bytes32 key) { + requireInvariant consistencyIndex(require_uint256(length() - 1)); + } + } + +invariant consistencyKey(bytes32 key) + contains(key) => ( + _indexOf(key) > 0 && + _indexOf(key) <= length() && + at_(require_uint256(_indexOf(key) - 1)) == key + ) + { + preserved remove(bytes32 otherKey) { + requireInvariant consistencyKey(otherKey); + requireInvariant atUniqueness( + require_uint256(_indexOf(key) - 1), + require_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 == sig:add(bytes32).selector && lengthAfter == require_uint256(lengthBefore + 1)) || + (f.selector == sig:remove(bytes32).selector && lengthAfter == require_uint256(lengthBefore - 1)) + ); + + assert containsBefore != containsAfter => ( + (f.selector == sig:add(bytes32).selector && containsAfter) || + (f.selector == sig: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() == require_uint256(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() == require_uint256(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 = require_uint256(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 + ); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/Initializable.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/Initializable.spec new file mode 100644 index 0000000..07c2930 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/Initializable.spec @@ -0,0 +1,165 @@ +import "helpers/helpers.spec"; + +methods { + // initialize, reinitialize, disable + function initialize() external envfree; + function reinitialize(uint64) external envfree; + function disable() external envfree; + + function nested_init_init() external envfree; + function nested_init_reinit(uint64) external envfree; + function nested_reinit_init(uint64) external envfree; + function nested_reinit_reinit(uint64,uint64) external envfree; + + // view + function version() external returns uint64 envfree; + function initializing() external returns bool envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Definitions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition isUninitialized() returns bool = version() == 0; +definition isInitialized() returns bool = version() > 0; +definition isDisabled() returns bool = version() == max_uint64; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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) { + uint64 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(); + + uint64 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(uint64 m) { + nested_init_reinit@withrevert(m); + assert lastReverted, "nested initializers"; +} + +rule cannotNestInitializers_reinit_init(uint64 n) { + nested_reinit_init@withrevert(n); + assert lastReverted, "nested initializers"; +} + +rule cannotNestInitializers_reinit_reinit(uint64 n, uint64 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(); + + uint64 versionBefore = version(); + + uint64 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"; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/Ownable.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/Ownable.spec new file mode 100644 index 0000000..0d50813 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/Ownable.spec @@ -0,0 +1,77 @@ +import "helpers/helpers.spec"; +import "methods/IOwnable.spec"; + +methods { + function restricted() external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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) { + address oldCurrent = owner(); + + method f; 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 == sig:transferOwnership(address).selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && f.selector == sig:renounceOwnership().selector) + ); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/Ownable2Step.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/Ownable2Step.spec new file mode 100644 index 0000000..d13c6d3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/Ownable2Step.spec @@ -0,0 +1,108 @@ +import "helpers/helpers.spec"; +import "methods/IOwnable2Step.spec"; + +methods { + function restricted() external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 == sig:acceptOwnership().selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == sig:renounceOwnership().selector) + ); + + // If pending changes, must be either acceptance or reset + assert oldPending != newPending => ( + (e.msg.sender == oldCurrent && newCurrent == oldCurrent && f.selector == sig:transferOwnership(address).selector) || + (e.msg.sender == oldPending && newCurrent == oldPending && newPending == 0 && f.selector == sig:acceptOwnership().selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == sig:renounceOwnership().selector) + ); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/Pausable.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/Pausable.spec new file mode 100644 index 0000000..a7aff9c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/Pausable.spec @@ -0,0 +1,96 @@ +import "helpers/helpers.spec"; + +methods { + function paused() external returns (bool) envfree; + function pause() external; + function unpause() external; + function onlyWhenPaused() external; + function onlyWhenNotPaused() external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 == sig:unpause().selector) || + (pausedAfter && f.selector == sig:pause().selector) + ), "contract's paused status can only be changed by _pause() or _unpause()"; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/TimelockController.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/TimelockController.spec new file mode 100644 index 0000000..5123768 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/TimelockController.spec @@ -0,0 +1,274 @@ +import "helpers/helpers.spec"; +import "methods/IAccessControl.spec"; + +methods { + function PROPOSER_ROLE() external returns (bytes32) envfree; + function EXECUTOR_ROLE() external returns (bytes32) envfree; + function CANCELLER_ROLE() external returns (bytes32) envfree; + function isOperation(bytes32) external returns (bool); + function isOperationPending(bytes32) external returns (bool); + function isOperationReady(bytes32) external returns (bool); + function isOperationDone(bytes32) external returns (bool); + function getTimestamp(bytes32) external returns (uint256) envfree; + function getMinDelay() external returns (uint256) envfree; + + function hashOperation(address, uint256, bytes, bytes32, bytes32) external returns(bytes32) envfree; + function hashOperationBatch(address[], uint256[], bytes[], bytes32, bytes32) external returns(bytes32) envfree; + + function schedule(address, uint256, bytes, bytes32, bytes32, uint256) external; + function scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256) external; + function execute(address, uint256, bytes, bytes32, bytes32) external; + function executeBatch(address[], uint256[], bytes[], bytes32, bytes32) external; + function cancel(bytes32) external; + + function updateDelay(uint256) external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +// Uniformly handle scheduling of batched and non-batched operations. +function helperScheduleWithRevert(env e, method f, bytes32 id, uint256 delay) { + if (f.selector == sig: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 == sig: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 == sig: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 == sig: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(env e, bytes32 id) returns bool = !isOperation(e, id); +definition isPending(env e, bytes32 id) returns bool = isOperationPending(e, id); +definition isDone(env e, bytes32 id) returns bool = isOperationDone(e, id); +definition state(env e, bytes32 id) returns uint8 = (isUnset(e, id) ? UNSET() : 0) | (isPending(e, id) ? PENDING() : 0) | (isDone(e, id) ? DONE() : 0); + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariants: consistency of accessors │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant isOperationCheck(env e, bytes32 id) + isOperation(e, id) <=> getTimestamp(id) > 0 + filtered { f -> !f.isView } + +invariant isOperationPendingCheck(env e, bytes32 id) + isOperationPending(e, id) <=> getTimestamp(id) > DONE_TIMESTAMP() + filtered { f -> !f.isView } + +invariant isOperationDoneCheck(env e, bytes32 id) + isOperationDone(e, id) <=> getTimestamp(id) == DONE_TIMESTAMP() + filtered { f -> !f.isView } + +invariant isOperationReadyCheck(env e, bytes32 id) + isOperationReady(e, id) <=> (isOperationPending(e, 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(e, id) <=> (!isPending(e, id) && !isDone(e, id) )) && + (isPending(e, id) <=> (!isUnset(e, id) && !isDone(e, id) )) && + (isDone(e, id) <=> (!isUnset(e, id) && !isPending(e, id))) && + // Check that the state helper behaves as expected: + (isUnset(e, id) <=> state(e, id) == UNSET() ) && + (isPending(e, id) <=> state(e, id) == PENDING() ) && + (isDone(e, id) <=> state(e, id) == DONE() ) && + // Check substate + isOperationReady(e, id) => isPending(e, 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(e, id); + f(e, args); + uint8 stateAfter = state(e, id); + + // Cannot jump from UNSET to DONE + assert stateBefore == UNSET() => stateAfter != DONE(); + + // UNSET → PENDING: schedule or scheduleBatch + assert stateBefore == UNSET() && stateAfter == PENDING() => ( + f.selector == sig:schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector || + f.selector == sig:scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256).selector + ); + + // PENDING → UNSET: cancel + assert stateBefore == PENDING() && stateAfter == UNSET() => ( + f.selector == sig:cancel(bytes32).selector + ); + + // PENDING → DONE: execute or executeBatch + assert stateBefore == PENDING() && stateAfter == DONE() => ( + f.selector == sig:execute(address, uint256, bytes, bytes32, bytes32).selector || + f.selector == sig: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 == sig: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 == sig:schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector || + f.selector == sig: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(e, 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(e, id) == PENDING(), "State transition violation"; + assert success => getTimestamp(id) == require_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 == sig:execute(address, uint256, bytes, bytes32, bytes32).selector || + f.selector == sig:executeBatch(address[], uint256[], bytes[], bytes32, bytes32).selector +} { + bytes32 otherId; uint256 otherTimestamp = getTimestamp(otherId); + + uint8 stateBefore = state(e, id); + bool isOperationReadyBefore = isOperationReady(e, id); + bool isExecutorOrOpen = hasRole(EXECUTOR_ROLE(), e.msg.sender) || hasRole(EXECUTOR_ROLE(), 0); + bool predecessorDependency = predecessor == to_bytes32(0) || isDone(e, 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(e, 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(e, 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(e, id) == UNSET(), "State transition violation"; + + // no side effect + assert otherTimestamp != getTimestamp(otherId) => id == otherId, "Other proposal affected"; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/helpers/helpers.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/helpers/helpers.spec new file mode 100644 index 0000000..a6c1e23 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/helpers/helpers.spec @@ -0,0 +1,7 @@ +// environment +definition nonpayable(env e) returns bool = e.msg.value == 0; +definition nonzerosender(env e) returns bool = e.msg.sender != 0; + +// math +definition min(mathint a, mathint b) returns mathint = a < b ? a : b; +definition max(mathint a, mathint b) returns mathint = a > b ? a : b; diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IAccessControl.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IAccessControl.spec new file mode 100644 index 0000000..5c395b0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IAccessControl.spec @@ -0,0 +1,8 @@ +methods { + function DEFAULT_ADMIN_ROLE() external returns (bytes32) envfree; + function hasRole(bytes32, address) external returns(bool) envfree; + function getRoleAdmin(bytes32) external returns(bytes32) envfree; + function grantRole(bytes32, address) external; + function revokeRole(bytes32, address) external; + function renounceRole(bytes32, address) external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IAccessControlDefaultAdminRules.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IAccessControlDefaultAdminRules.spec new file mode 100644 index 0000000..d02db18 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IAccessControlDefaultAdminRules.spec @@ -0,0 +1,36 @@ +import "./IERC5313.spec"; + +methods { + // === View == + + // Default Admin + function defaultAdmin() external returns(address) envfree; + function pendingDefaultAdmin() external returns(address, uint48) envfree; + + // Default Admin Delay + function defaultAdminDelay() external returns(uint48); + function pendingDefaultAdminDelay() external returns(uint48, uint48); + function defaultAdminDelayIncreaseWait() external returns(uint48) envfree; + + // === Mutations == + + // Default Admin + function beginDefaultAdminTransfer(address) external; + function cancelDefaultAdminTransfer() external; + function acceptDefaultAdminTransfer() external; + + // Default Admin Delay + function changeDefaultAdminDelay(uint48) external; + function rollbackDefaultAdminDelay() external; + + // == FV == + + // Default Admin + function pendingDefaultAdmin_() external returns (address) envfree; + function pendingDefaultAdminSchedule_() external returns (uint48) envfree; + + // Default Admin Delay + function pendingDelay_() external returns (uint48); + function pendingDelaySchedule_() external returns (uint48); + function delayChangeWait_(uint48) external returns (uint48); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC20.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC20.spec new file mode 100644 index 0000000..100901a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC20.spec @@ -0,0 +1,11 @@ +methods { + function name() external returns (string) envfree; + function symbol() external returns (string) envfree; + function decimals() external returns (uint8) envfree; + function totalSupply() external returns (uint256) envfree; + function balanceOf(address) external returns (uint256) envfree; + function allowance(address,address) external returns (uint256) envfree; + function approve(address,uint256) external returns (bool); + function transfer(address,uint256) external returns (bool); + function transferFrom(address,address,uint256) external returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC2612.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC2612.spec new file mode 100644 index 0000000..4ecc17b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC2612.spec @@ -0,0 +1,5 @@ +methods { + function permit(address,address,uint256,uint256,uint8,bytes32,bytes32) external; + function nonces(address) external returns (uint256) envfree; + function DOMAIN_SEPARATOR() external returns (bytes32) envfree; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC3156FlashBorrower.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC3156FlashBorrower.spec new file mode 100644 index 0000000..733c168 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC3156FlashBorrower.spec @@ -0,0 +1,3 @@ +methods { + function _.onFlashLoan(address,address,uint256,uint256,bytes) external => DISPATCHER(true); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC3156FlashLender.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC3156FlashLender.spec new file mode 100644 index 0000000..66ed14c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC3156FlashLender.spec @@ -0,0 +1,5 @@ +methods { + function maxFlashLoan(address) external returns (uint256) envfree; + function flashFee(address,uint256) external returns (uint256) envfree; + function flashLoan(address,address,uint256,bytes) external returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC5313.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC5313.spec new file mode 100644 index 0000000..f1d469f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC5313.spec @@ -0,0 +1,3 @@ +methods { + function owner() external returns (address) envfree; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC721.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC721.spec new file mode 100644 index 0000000..34ff50b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC721.spec @@ -0,0 +1,17 @@ +methods { + // IERC721 + function balanceOf(address) external returns (uint256) envfree; + function ownerOf(uint256) external returns (address) envfree; + function getApproved(uint256) external returns (address) envfree; + function isApprovedForAll(address,address) external returns (bool) envfree; + function safeTransferFrom(address,address,uint256,bytes) external; + function safeTransferFrom(address,address,uint256) external; + function transferFrom(address,address,uint256) external; + function approve(address,uint256) external; + function setApprovalForAll(address,bool) external; + + // IERC721Metadata + function name() external returns (string); + function symbol() external returns (string); + function tokenURI(uint256) external returns (string); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC721Receiver.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC721Receiver.spec new file mode 100644 index 0000000..e6bdf42 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IERC721Receiver.spec @@ -0,0 +1,3 @@ +methods { + function _.onERC721Received(address,address,uint256,bytes) external => DISPATCHER(true); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IOwnable.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IOwnable.spec new file mode 100644 index 0000000..4d7c925 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IOwnable.spec @@ -0,0 +1,5 @@ +methods { + function owner() external returns (address) envfree; + function transferOwnership(address) external; + function renounceOwnership() external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IOwnable2Step.spec b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IOwnable2Step.spec new file mode 100644 index 0000000..e6a9957 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/certora/specs/methods/IOwnable2Step.spec @@ -0,0 +1,7 @@ +methods { + function owner() external returns (address) envfree; + function pendingOwner() external returns (address) envfree; + function transferOwnership(address) external; + function acceptOwnership() external; + function renounceOwnership() external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/AccessControl.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/AccessControl.sol new file mode 100644 index 0000000..3e3341e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/AccessControl.sol @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) + +pragma solidity ^0.8.20; + +import {IAccessControl} from "./IAccessControl.sol"; +import {Context} from "../utils/Context.sol"; +import {ERC165} from "../utils/introspection/ERC165.sol"; + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * 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)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * 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. We recommend using {AccessControlDefaultAdminRules} + * to enforce additional security measures for this role. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address account => bool) hasRole; + bytes32 adminRole; + } + + mapping(bytes32 role => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with an {AccessControlUnauthorizedAccount} error including the required role. + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual returns (bool) { + return _roles[role].hasRole[account]; + } + + /** + * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` + * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` + * is missing `role`. + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert AccessControlUnauthorizedAccount(account, role); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `callerConfirmation`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address callerConfirmation) public virtual { + if (callerConfirmation != _msgSender()) { + revert AccessControlBadConfirmation(); + } + + _revokeRole(role, callerConfirmation); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual returns (bool) { + if (!hasRole(role, account)) { + _roles[role].hasRole[account] = true; + emit RoleGranted(role, account, _msgSender()); + return true; + } else { + return false; + } + } + + /** + * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { + if (hasRole(role, account)) { + _roles[role].hasRole[account] = false; + emit RoleRevoked(role, account, _msgSender()); + return true; + } else { + return false; + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/IAccessControl.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/IAccessControl.sol new file mode 100644 index 0000000..2ac89ca --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/IAccessControl.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) + +pragma solidity ^0.8.20; + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev The `account` is missing a role. + */ + error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); + + /** + * @dev The caller of a function is not the expected one. + * + * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. + */ + error AccessControlBadConfirmation(); + + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `callerConfirmation`. + */ + function renounceRole(bytes32 role, address callerConfirmation) external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/Ownable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/Ownable.sol new file mode 100644 index 0000000..bd96f66 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/Ownable.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is set to the address provided by the deployer. This can + * later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + /** + * @dev The caller account is not authorized to perform an operation. + */ + error OwnableUnauthorizedAccount(address account); + + /** + * @dev The owner is not a valid owner account. (eg. `address(0)`) + */ + error OwnableInvalidOwner(address owner); + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the address provided by the deployer as the initial owner. + */ + constructor(address initialOwner) { + if (initialOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(initialOwner); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + if (owner() != _msgSender()) { + revert OwnableUnauthorizedAccount(_msgSender()); + } + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + if (newOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/Ownable2Step.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/Ownable2Step.sol new file mode 100644 index 0000000..f0427e2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/Ownable2Step.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) + +pragma solidity ^0.8.20; + +import {Ownable} from "./Ownable.sol"; + +/** + * @dev Contract module which provides access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is specified at deployment time in the constructor for `Ownable`. This + * can later be changed with {transferOwnership} and {acceptOwnership}. + * + * This module is used through inheritance. It will make available all functions + * from parent (Ownable). + */ +abstract contract Ownable2Step is Ownable { + address private _pendingOwner; + + event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Returns the address of the pending owner. + */ + function pendingOwner() public view virtual returns (address) { + return _pendingOwner; + } + + /** + * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual override onlyOwner { + _pendingOwner = newOwner; + emit OwnershipTransferStarted(owner(), newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual override { + delete _pendingOwner; + super._transferOwnership(newOwner); + } + + /** + * @dev The new owner accepts the ownership transfer. + */ + function acceptOwnership() public virtual { + address sender = _msgSender(); + if (pendingOwner() != sender) { + revert OwnableUnauthorizedAccount(sender); + } + _transferOwnership(sender); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/access/README.adoc new file mode 100644 index 0000000..ba9c02f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/README.adoc @@ -0,0 +1,43 @@ += Access Control + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access + +This directory provides ways to restrict who can access the functions of a contract or when they can do it. + +- {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. +- {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. + +== Core + +{{Ownable}} + +{{Ownable2Step}} + +{{IAccessControl}} + +{{AccessControl}} + +== Extensions + +{{IAccessControlEnumerable}} + +{{AccessControlEnumerable}} + +{{IAccessControlDefaultAdminRules}} + +{{AccessControlDefaultAdminRules}} + +== AccessManager + +{{IAuthority}} + +{{IAccessManager}} + +{{AccessManager}} + +{{IAccessManaged}} + +{{AccessManaged}} + +{{AuthorityUtils}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/AccessControlDefaultAdminRules.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/AccessControlDefaultAdminRules.sol new file mode 100644 index 0000000..ef71a64 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/AccessControlDefaultAdminRules.sol @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlDefaultAdminRules.sol) + +pragma solidity ^0.8.20; + +import {IAccessControlDefaultAdminRules} from "./IAccessControlDefaultAdminRules.sol"; +import {AccessControl, IAccessControl} from "../AccessControl.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {IERC5313} from "../../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. + * * 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: + * + * ```solidity + * contract MyToken is AccessControlDefaultAdminRules { + * constructor() AccessControlDefaultAdminRules( + * 3 days, + * msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder + * ) {} + * } + * ``` + */ +abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl { + // pending admin pair read/written together frequently + address private _pendingDefaultAdmin; + uint48 private _pendingDefaultAdminSchedule; // 0 == unset + + 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} and {defaultAdmin} address. + */ + constructor(uint48 initialDelay, address initialDefaultAdmin) { + if (initialDefaultAdmin == address(0)) { + revert AccessControlInvalidDefaultAdmin(address(0)); + } + _currentDelay = initialDelay; + _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC5313-owner}. + */ + function owner() public view virtual returns (address) { + return defaultAdmin(); + } + + /// + /// Override AccessControl role management + /// + + /** + * @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE) { + revert AccessControlEnforcedDefaultAdminRules(); + } + super.grantRole(role, account); + } + + /** + * @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE) { + revert AccessControlEnforcedDefaultAdminRules(); + } + super.revokeRole(role, account); + } + + /** + * @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 renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { + (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin(); + if (newDefaultAdmin != address(0) || !_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) { + revert AccessControlEnforcedDefaultAdminDelay(schedule); + } + delete _pendingDefaultAdminSchedule; + } + super.renounceRole(role, account); + } + + /** + * @dev See {AccessControl-_grantRole}. + * + * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the + * role has been previously renounced. + * + * 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 returns (bool) { + if (role == DEFAULT_ADMIN_ROLE) { + if (defaultAdmin() != address(0)) { + revert AccessControlEnforcedDefaultAdminRules(); + } + _currentDefaultAdmin = account; + } + return super._grantRole(role, account); + } + + /** + * @dev See {AccessControl-_revokeRole}. + */ + function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) { + if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { + delete _currentDefaultAdmin; + } + return super._revokeRole(role, account); + } + + /** + * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override { + if (role == DEFAULT_ADMIN_ROLE) { + revert AccessControlEnforcedDefaultAdminRules(); + } + super._setRoleAdmin(role, adminRole); + } + + /// + /// AccessControlDefaultAdminRules accessors + /// + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdmin() public view virtual returns (address) { + return _currentDefaultAdmin; + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + 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(); + if (_msgSender() != newDefaultAdmin) { + // Enforce newDefaultAdmin explicit acceptance. + revert AccessControlInvalidDefaultAdmin(_msgSender()); + } + _acceptDefaultAdminTransfer(); + } + + /** + * @dev See {acceptDefaultAdminTransfer}. + * + * Internal function without access restriction. + */ + function _acceptDefaultAdminTransfer() internal virtual { + (address newAdmin, uint48 schedule) = pendingDefaultAdmin(); + if (!_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) { + revert AccessControlEnforcedDefaultAdminDelay(schedule); + } + _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/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/AccessControlEnumerable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/AccessControlEnumerable.sol new file mode 100644 index 0000000..151de05 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/AccessControlEnumerable.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol) + +pragma solidity ^0.8.20; + +import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol"; +import {AccessControl} from "../AccessControl.sol"; +import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol"; + +/** + * @dev Extension of {AccessControl} that allows enumerating the members of each role. + */ +abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { + using EnumerableSet for EnumerableSet.AddressSet; + + mapping(bytes32 role => EnumerableSet.AddressSet) private _roleMembers; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) { + return _roleMembers[role].at(index); + } + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) { + return _roleMembers[role].length(); + } + + /** + * @dev Overload {AccessControl-_grantRole} to track enumerable memberships + */ + function _grantRole(bytes32 role, address account) internal virtual override returns (bool) { + bool granted = super._grantRole(role, account); + if (granted) { + _roleMembers[role].add(account); + } + return granted; + } + + /** + * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships + */ + function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) { + bool revoked = super._revokeRole(role, account); + if (revoked) { + _roleMembers[role].remove(account); + } + return revoked; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/IAccessControlDefaultAdminRules.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/IAccessControlDefaultAdminRules.sol new file mode 100644 index 0000000..73531fa --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/IAccessControlDefaultAdminRules.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlDefaultAdminRules.sol) + +pragma solidity ^0.8.20; + +import {IAccessControl} from "../IAccessControl.sol"; + +/** + * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection. + */ +interface IAccessControlDefaultAdminRules is IAccessControl { + /** + * @dev The new default admin is not a valid default admin. + */ + error AccessControlInvalidDefaultAdmin(address defaultAdmin); + + /** + * @dev At least one of the following rules was violated: + * + * - The `DEFAULT_ADMIN_ROLE` must only be managed by itself. + * - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time. + * - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps. + */ + error AccessControlEnforcedDefaultAdminRules(); + + /** + * @dev The delay for transferring the default admin delay is enforced and + * the operation must wait until `schedule`. + * + * NOTE: `schedule` can be 0 indicating there's no transfer scheduled. + */ + error AccessControlEnforcedDefaultAdminDelay(uint48 schedule); + + /** + * @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 DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule); + + /** + * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule. + */ + 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. + */ + function defaultAdmin() external view returns (address); + + /** + * @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 newAdmin, uint48 acceptSchedule); + + /** + * @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 defaultAdminDelay() external view returns (uint48); + + /** + * @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 {defaultAdmin}. + * + * Emits a DefaultAdminRoleChangeStarted event. + */ + function beginDefaultAdminTransfer(address newAdmin) external; + + /** + * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. + * + * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function. + * + * Requirements: + * + * - 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 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: + * + * - Only can be called by the current {defaultAdmin}. + * + * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event. + */ + 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/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/IAccessControlEnumerable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/IAccessControlEnumerable.sol new file mode 100644 index 0000000..a39d051 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/extensions/IAccessControlEnumerable.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol) + +pragma solidity ^0.8.20; + +import {IAccessControl} from "../IAccessControl.sol"; + +/** + * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. + */ +interface IAccessControlEnumerable is IAccessControl { + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) external view returns (address); + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AccessManaged.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AccessManaged.sol new file mode 100644 index 0000000..b5f4524 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AccessManaged.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManaged.sol) + +pragma solidity ^0.8.20; + +import {IAuthority} from "./IAuthority.sol"; +import {AuthorityUtils} from "./AuthorityUtils.sol"; +import {IAccessManager} from "./IAccessManager.sol"; +import {IAccessManaged} from "./IAccessManaged.sol"; +import {Context} from "../../utils/Context.sol"; + +/** + * @dev This contract module makes available a {restricted} modifier. Functions decorated with this modifier will be + * permissioned according to an "authority": a contract like {AccessManager} that follows the {IAuthority} interface, + * implementing a policy that allows certain callers to access certain functions. + * + * IMPORTANT: The `restricted` modifier should never be used on `internal` functions, judiciously used in `public` + * functions, and ideally only used in `external` functions. See {restricted}. + */ +abstract contract AccessManaged is Context, IAccessManaged { + address private _authority; + + bool private _consumingSchedule; + + /** + * @dev Initializes the contract connected to an initial authority. + */ + constructor(address initialAuthority) { + _setAuthority(initialAuthority); + } + + /** + * @dev Restricts access to a function as defined by the connected Authority for this contract and the + * caller and selector of the function that entered the contract. + * + * [IMPORTANT] + * ==== + * In general, this modifier should only be used on `external` functions. It is okay to use it on `public` + * functions that are used as external entry points and are not called internally. Unless you know what you're + * doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security + * implications! This is because the permissions are determined by the function that entered the contract, i.e. the + * function at the bottom of the call stack, and not the function where the modifier is visible in the source code. + * ==== + * + * [WARNING] + * ==== + * Avoid adding this modifier to the https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function[`receive()`] + * function or the https://docs.soliditylang.org/en/v0.8.20/contracts.html#fallback-function[`fallback()`]. These + * functions are the only execution paths where a function selector cannot be unambiguosly determined from the calldata + * since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()` function + * if no calldata is provided. (See {_checkCanCall}). + * + * The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length. + * ==== + */ + modifier restricted() { + _checkCanCall(_msgSender(), _msgData()); + _; + } + + /// @inheritdoc IAccessManaged + function authority() public view virtual returns (address) { + return _authority; + } + + /// @inheritdoc IAccessManaged + function setAuthority(address newAuthority) public virtual { + address caller = _msgSender(); + if (caller != authority()) { + revert AccessManagedUnauthorized(caller); + } + if (newAuthority.code.length == 0) { + revert AccessManagedInvalidAuthority(newAuthority); + } + _setAuthority(newAuthority); + } + + /// @inheritdoc IAccessManaged + function isConsumingScheduledOp() public view returns (bytes4) { + return _consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0); + } + + /** + * @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the + * permissions set by the current authority. + */ + function _setAuthority(address newAuthority) internal virtual { + _authority = newAuthority; + emit AuthorityUpdated(newAuthority); + } + + /** + * @dev Reverts if the caller is not allowed to call the function identified by a selector. Panics if the calldata + * is less than 4 bytes long. + */ + function _checkCanCall(address caller, bytes calldata data) internal virtual { + (bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay( + authority(), + caller, + address(this), + bytes4(data[0:4]) + ); + if (!immediate) { + if (delay > 0) { + _consumingSchedule = true; + IAccessManager(authority()).consumeScheduledOp(caller, data); + _consumingSchedule = false; + } else { + revert AccessManagedUnauthorized(caller); + } + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AccessManager.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AccessManager.sol new file mode 100644 index 0000000..1e4afa4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AccessManager.sol @@ -0,0 +1,730 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManager.sol) + +pragma solidity ^0.8.20; + +import {IAccessManager} from "./IAccessManager.sol"; +import {IAccessManaged} from "./IAccessManaged.sol"; +import {Address} from "../../utils/Address.sol"; +import {Context} from "../../utils/Context.sol"; +import {Multicall} from "../../utils/Multicall.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {Time} from "../../utils/types/Time.sol"; + +/** + * @dev AccessManager is a central contract to store the permissions of a system. + * + * A smart contract under the control of an AccessManager instance is known as a target, and will inherit from the + * {AccessManaged} contract, be connected to this contract as its manager and implement the {AccessManaged-restricted} + * modifier on a set of functions selected to be permissioned. Note that any function without this setup won't be + * effectively restricted. + * + * The restriction rules for such functions are defined in terms of "roles" identified by an `uint64` and scoped + * by target (`address`) and function selectors (`bytes4`). These roles are stored in this contract and can be + * configured by admins (`ADMIN_ROLE` members) after a delay (see {getTargetAdminDelay}). + * + * For each target contract, admins can configure the following without any delay: + * + * * The target's {AccessManaged-authority} via {updateAuthority}. + * * Close or open a target via {setTargetClosed} keeping the permissions intact. + * * The roles that are allowed (or disallowed) to call a given function (identified by its selector) through {setTargetFunctionRole}. + * + * By default every address is member of the `PUBLIC_ROLE` and every target function is restricted to the `ADMIN_ROLE` until configured otherwise. + * Additionally, each role has the following configuration options restricted to this manager's admins: + * + * * A role's admin role via {setRoleAdmin} who can grant or revoke roles. + * * A role's guardian role via {setRoleGuardian} who's allowed to cancel operations. + * * A delay in which a role takes effect after being granted through {setGrantDelay}. + * * A delay of any target's admin action via {setTargetAdminDelay}. + * * A role label for discoverability purposes with {labelRole}. + * + * Any account can be added and removed into any number of these roles by using the {grantRole} and {revokeRole} functions + * restricted to each role's admin (see {getRoleAdmin}). + * + * Since all the permissions of the managed system can be modified by the admins of this instance, it is expected that + * they will be highly secured (e.g., a multisig or a well-configured DAO). + * + * NOTE: This contract implements a form of the {IAuthority} interface, but {canCall} has additional return data so it + * doesn't inherit `IAuthority`. It is however compatible with the `IAuthority` interface since the first 32 bytes of + * the return data are a boolean as expected by that interface. + * + * NOTE: Systems that implement other access control mechanisms (for example using {Ownable}) can be paired with an + * {AccessManager} by transferring permissions (ownership in the case of {Ownable}) directly to the {AccessManager}. + * Users will be able to interact with these contracts through the {execute} function, following the access rules + * registered in the {AccessManager}. Keep in mind that in that context, the msg.sender seen by restricted functions + * will be {AccessManager} itself. + * + * WARNING: When granting permissions over an {Ownable} or {AccessControl} contract to an {AccessManager}, be very + * mindful of the danger associated with functions such as {{Ownable-renounceOwnership}} or + * {{AccessControl-renounceRole}}. + */ +contract AccessManager is Context, Multicall, IAccessManager { + using Time for *; + + // Structure that stores the details for a target contract. + struct TargetConfig { + mapping(bytes4 selector => uint64 roleId) allowedRoles; + Time.Delay adminDelay; + bool closed; + } + + // Structure that stores the details for a role/account pair. This structures fit into a single slot. + struct Access { + // Timepoint at which the user gets the permission. + // If this is either 0 or in the future, then the role permission is not available. + uint48 since; + // Delay for execution. Only applies to restricted() / execute() calls. + Time.Delay delay; + } + + // Structure that stores the details of a role. + struct Role { + // Members of the role. + mapping(address user => Access access) members; + // Admin who can grant or revoke permissions. + uint64 admin; + // Guardian who can cancel operations targeting functions that need this role. + uint64 guardian; + // Delay in which the role takes effect after being granted. + Time.Delay grantDelay; + } + + // Structure that stores the details for a scheduled operation. This structure fits into a single slot. + struct Schedule { + // Moment at which the operation can be executed. + uint48 timepoint; + // Operation nonce to allow third-party contracts to identify the operation. + uint32 nonce; + } + + uint64 public constant ADMIN_ROLE = type(uint64).min; // 0 + uint64 public constant PUBLIC_ROLE = type(uint64).max; // 2**64-1 + + mapping(address target => TargetConfig mode) private _targets; + mapping(uint64 roleId => Role) private _roles; + mapping(bytes32 operationId => Schedule) private _schedules; + + // Used to identify operations that are currently being executed via {execute}. + // This should be transient storage when supported by the EVM. + bytes32 private _executionId; + + /** + * @dev Check that the caller is authorized to perform the operation, following the restrictions encoded in + * {_getAdminRestrictions}. + */ + modifier onlyAuthorized() { + _checkAuthorized(); + _; + } + + constructor(address initialAdmin) { + if (initialAdmin == address(0)) { + revert AccessManagerInvalidInitialAdmin(address(0)); + } + + // admin is active immediately and without any execution delay. + _grantRole(ADMIN_ROLE, initialAdmin, 0, 0); + } + + // =================================================== GETTERS ==================================================== + /// @inheritdoc IAccessManager + function canCall( + address caller, + address target, + bytes4 selector + ) public view virtual returns (bool immediate, uint32 delay) { + if (isTargetClosed(target)) { + return (false, 0); + } else if (caller == address(this)) { + // Caller is AccessManager, this means the call was sent through {execute} and it already checked + // permissions. We verify that the call "identifier", which is set during {execute}, is correct. + return (_isExecuting(target, selector), 0); + } else { + uint64 roleId = getTargetFunctionRole(target, selector); + (bool isMember, uint32 currentDelay) = hasRole(roleId, caller); + return isMember ? (currentDelay == 0, currentDelay) : (false, 0); + } + } + + /// @inheritdoc IAccessManager + function expiration() public view virtual returns (uint32) { + return 1 weeks; + } + + /// @inheritdoc IAccessManager + function minSetback() public view virtual returns (uint32) { + return 5 days; + } + + /// @inheritdoc IAccessManager + function isTargetClosed(address target) public view virtual returns (bool) { + return _targets[target].closed; + } + + /// @inheritdoc IAccessManager + function getTargetFunctionRole(address target, bytes4 selector) public view virtual returns (uint64) { + return _targets[target].allowedRoles[selector]; + } + + /// @inheritdoc IAccessManager + function getTargetAdminDelay(address target) public view virtual returns (uint32) { + return _targets[target].adminDelay.get(); + } + + /// @inheritdoc IAccessManager + function getRoleAdmin(uint64 roleId) public view virtual returns (uint64) { + return _roles[roleId].admin; + } + + /// @inheritdoc IAccessManager + function getRoleGuardian(uint64 roleId) public view virtual returns (uint64) { + return _roles[roleId].guardian; + } + + /// @inheritdoc IAccessManager + function getRoleGrantDelay(uint64 roleId) public view virtual returns (uint32) { + return _roles[roleId].grantDelay.get(); + } + + /// @inheritdoc IAccessManager + function getAccess( + uint64 roleId, + address account + ) public view virtual returns (uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect) { + Access storage access = _roles[roleId].members[account]; + + since = access.since; + (currentDelay, pendingDelay, effect) = access.delay.getFull(); + + return (since, currentDelay, pendingDelay, effect); + } + + /// @inheritdoc IAccessManager + function hasRole( + uint64 roleId, + address account + ) public view virtual returns (bool isMember, uint32 executionDelay) { + if (roleId == PUBLIC_ROLE) { + return (true, 0); + } else { + (uint48 hasRoleSince, uint32 currentDelay, , ) = getAccess(roleId, account); + return (hasRoleSince != 0 && hasRoleSince <= Time.timestamp(), currentDelay); + } + } + + // =============================================== ROLE MANAGEMENT =============================================== + /// @inheritdoc IAccessManager + function labelRole(uint64 roleId, string calldata label) public virtual onlyAuthorized { + if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + emit RoleLabel(roleId, label); + } + + /// @inheritdoc IAccessManager + function grantRole(uint64 roleId, address account, uint32 executionDelay) public virtual onlyAuthorized { + _grantRole(roleId, account, getRoleGrantDelay(roleId), executionDelay); + } + + /// @inheritdoc IAccessManager + function revokeRole(uint64 roleId, address account) public virtual onlyAuthorized { + _revokeRole(roleId, account); + } + + /// @inheritdoc IAccessManager + function renounceRole(uint64 roleId, address callerConfirmation) public virtual { + if (callerConfirmation != _msgSender()) { + revert AccessManagerBadConfirmation(); + } + _revokeRole(roleId, callerConfirmation); + } + + /// @inheritdoc IAccessManager + function setRoleAdmin(uint64 roleId, uint64 admin) public virtual onlyAuthorized { + _setRoleAdmin(roleId, admin); + } + + /// @inheritdoc IAccessManager + function setRoleGuardian(uint64 roleId, uint64 guardian) public virtual onlyAuthorized { + _setRoleGuardian(roleId, guardian); + } + + /// @inheritdoc IAccessManager + function setGrantDelay(uint64 roleId, uint32 newDelay) public virtual onlyAuthorized { + _setGrantDelay(roleId, newDelay); + } + + /** + * @dev Internal version of {grantRole} without access control. Returns true if the role was newly granted. + * + * Emits a {RoleGranted} event. + */ + function _grantRole( + uint64 roleId, + address account, + uint32 grantDelay, + uint32 executionDelay + ) internal virtual returns (bool) { + if (roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + bool newMember = _roles[roleId].members[account].since == 0; + uint48 since; + + if (newMember) { + since = Time.timestamp() + grantDelay; + _roles[roleId].members[account] = Access({since: since, delay: executionDelay.toDelay()}); + } else { + // No setback here. Value can be reset by doing revoke + grant, effectively allowing the admin to perform + // any change to the execution delay within the duration of the role admin delay. + (_roles[roleId].members[account].delay, since) = _roles[roleId].members[account].delay.withUpdate( + executionDelay, + 0 + ); + } + + emit RoleGranted(roleId, account, executionDelay, since, newMember); + return newMember; + } + + /** + * @dev Internal version of {revokeRole} without access control. This logic is also used by {renounceRole}. + * Returns true if the role was previously granted. + * + * Emits a {RoleRevoked} event if the account had the role. + */ + function _revokeRole(uint64 roleId, address account) internal virtual returns (bool) { + if (roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + if (_roles[roleId].members[account].since == 0) { + return false; + } + + delete _roles[roleId].members[account]; + + emit RoleRevoked(roleId, account); + return true; + } + + /** + * @dev Internal version of {setRoleAdmin} without access control. + * + * Emits a {RoleAdminChanged} event. + * + * NOTE: Setting the admin role as the `PUBLIC_ROLE` is allowed, but it will effectively allow + * anyone to set grant or revoke such role. + */ + function _setRoleAdmin(uint64 roleId, uint64 admin) internal virtual { + if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + _roles[roleId].admin = admin; + + emit RoleAdminChanged(roleId, admin); + } + + /** + * @dev Internal version of {setRoleGuardian} without access control. + * + * Emits a {RoleGuardianChanged} event. + * + * NOTE: Setting the guardian role as the `PUBLIC_ROLE` is allowed, but it will effectively allow + * anyone to cancel any scheduled operation for such role. + */ + function _setRoleGuardian(uint64 roleId, uint64 guardian) internal virtual { + if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + _roles[roleId].guardian = guardian; + + emit RoleGuardianChanged(roleId, guardian); + } + + /** + * @dev Internal version of {setGrantDelay} without access control. + * + * Emits a {RoleGrantDelayChanged} event. + */ + function _setGrantDelay(uint64 roleId, uint32 newDelay) internal virtual { + if (roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + uint48 effect; + (_roles[roleId].grantDelay, effect) = _roles[roleId].grantDelay.withUpdate(newDelay, minSetback()); + + emit RoleGrantDelayChanged(roleId, newDelay, effect); + } + + // ============================================= FUNCTION MANAGEMENT ============================================== + /// @inheritdoc IAccessManager + function setTargetFunctionRole( + address target, + bytes4[] calldata selectors, + uint64 roleId + ) public virtual onlyAuthorized { + for (uint256 i = 0; i < selectors.length; ++i) { + _setTargetFunctionRole(target, selectors[i], roleId); + } + } + + /** + * @dev Internal version of {setTargetFunctionRole} without access control. + * + * Emits a {TargetFunctionRoleUpdated} event. + */ + function _setTargetFunctionRole(address target, bytes4 selector, uint64 roleId) internal virtual { + _targets[target].allowedRoles[selector] = roleId; + emit TargetFunctionRoleUpdated(target, selector, roleId); + } + + /// @inheritdoc IAccessManager + function setTargetAdminDelay(address target, uint32 newDelay) public virtual onlyAuthorized { + _setTargetAdminDelay(target, newDelay); + } + + /** + * @dev Internal version of {setTargetAdminDelay} without access control. + * + * Emits a {TargetAdminDelayUpdated} event. + */ + function _setTargetAdminDelay(address target, uint32 newDelay) internal virtual { + uint48 effect; + (_targets[target].adminDelay, effect) = _targets[target].adminDelay.withUpdate(newDelay, minSetback()); + + emit TargetAdminDelayUpdated(target, newDelay, effect); + } + + // =============================================== MODE MANAGEMENT ================================================ + /// @inheritdoc IAccessManager + function setTargetClosed(address target, bool closed) public virtual onlyAuthorized { + _setTargetClosed(target, closed); + } + + /** + * @dev Set the closed flag for a contract. This is an internal setter with no access restrictions. + * + * Emits a {TargetClosed} event. + */ + function _setTargetClosed(address target, bool closed) internal virtual { + if (target == address(this)) { + revert AccessManagerLockedAccount(target); + } + _targets[target].closed = closed; + emit TargetClosed(target, closed); + } + + // ============================================== DELAYED OPERATIONS ============================================== + /// @inheritdoc IAccessManager + function getSchedule(bytes32 id) public view virtual returns (uint48) { + uint48 timepoint = _schedules[id].timepoint; + return _isExpired(timepoint) ? 0 : timepoint; + } + + /// @inheritdoc IAccessManager + function getNonce(bytes32 id) public view virtual returns (uint32) { + return _schedules[id].nonce; + } + + /// @inheritdoc IAccessManager + function schedule( + address target, + bytes calldata data, + uint48 when + ) public virtual returns (bytes32 operationId, uint32 nonce) { + address caller = _msgSender(); + + // Fetch restrictions that apply to the caller on the targeted function + (, uint32 setback) = _canCallExtended(caller, target, data); + + uint48 minWhen = Time.timestamp() + setback; + + // if call with delay is not authorized, or if requested timing is too soon + if (setback == 0 || (when > 0 && when < minWhen)) { + revert AccessManagerUnauthorizedCall(caller, target, _checkSelector(data)); + } + + // Reuse variable due to stack too deep + when = uint48(Math.max(when, minWhen)); // cast is safe: both inputs are uint48 + + // If caller is authorised, schedule operation + operationId = hashOperation(caller, target, data); + + _checkNotScheduled(operationId); + + unchecked { + // It's not feasible to overflow the nonce in less than 1000 years + nonce = _schedules[operationId].nonce + 1; + } + _schedules[operationId].timepoint = when; + _schedules[operationId].nonce = nonce; + emit OperationScheduled(operationId, nonce, when, caller, target, data); + + // Using named return values because otherwise we get stack too deep + } + + /** + * @dev Reverts if the operation is currently scheduled and has not expired. + * (Note: This function was introduced due to stack too deep errors in schedule.) + */ + function _checkNotScheduled(bytes32 operationId) private view { + uint48 prevTimepoint = _schedules[operationId].timepoint; + if (prevTimepoint != 0 && !_isExpired(prevTimepoint)) { + revert AccessManagerAlreadyScheduled(operationId); + } + } + + /// @inheritdoc IAccessManager + // Reentrancy is not an issue because permissions are checked on msg.sender. Additionally, + // _consumeScheduledOp guarantees a scheduled operation is only executed once. + // slither-disable-next-line reentrancy-no-eth + function execute(address target, bytes calldata data) public payable virtual returns (uint32) { + address caller = _msgSender(); + + // Fetch restrictions that apply to the caller on the targeted function + (bool immediate, uint32 setback) = _canCallExtended(caller, target, data); + + // If caller is not authorised, revert + if (!immediate && setback == 0) { + revert AccessManagerUnauthorizedCall(caller, target, _checkSelector(data)); + } + + bytes32 operationId = hashOperation(caller, target, data); + uint32 nonce; + + // If caller is authorised, check operation was scheduled early enough + // Consume an available schedule even if there is no currently enforced delay + if (setback != 0 || getSchedule(operationId) != 0) { + nonce = _consumeScheduledOp(operationId); + } + + // Mark the target and selector as authorised + bytes32 executionIdBefore = _executionId; + _executionId = _hashExecutionId(target, _checkSelector(data)); + + // Perform call + Address.functionCallWithValue(target, data, msg.value); + + // Reset execute identifier + _executionId = executionIdBefore; + + return nonce; + } + + /// @inheritdoc IAccessManager + function cancel(address caller, address target, bytes calldata data) public virtual returns (uint32) { + address msgsender = _msgSender(); + bytes4 selector = _checkSelector(data); + + bytes32 operationId = hashOperation(caller, target, data); + if (_schedules[operationId].timepoint == 0) { + revert AccessManagerNotScheduled(operationId); + } else if (caller != msgsender) { + // calls can only be canceled by the account that scheduled them, a global admin, or by a guardian of the required role. + (bool isAdmin, ) = hasRole(ADMIN_ROLE, msgsender); + (bool isGuardian, ) = hasRole(getRoleGuardian(getTargetFunctionRole(target, selector)), msgsender); + if (!isAdmin && !isGuardian) { + revert AccessManagerUnauthorizedCancel(msgsender, caller, target, selector); + } + } + + delete _schedules[operationId].timepoint; // reset the timepoint, keep the nonce + uint32 nonce = _schedules[operationId].nonce; + emit OperationCanceled(operationId, nonce); + + return nonce; + } + + /// @inheritdoc IAccessManager + function consumeScheduledOp(address caller, bytes calldata data) public virtual { + address target = _msgSender(); + if (IAccessManaged(target).isConsumingScheduledOp() != IAccessManaged.isConsumingScheduledOp.selector) { + revert AccessManagerUnauthorizedConsume(target); + } + _consumeScheduledOp(hashOperation(caller, target, data)); + } + + /** + * @dev Internal variant of {consumeScheduledOp} that operates on bytes32 operationId. + * + * Returns the nonce of the scheduled operation that is consumed. + */ + function _consumeScheduledOp(bytes32 operationId) internal virtual returns (uint32) { + uint48 timepoint = _schedules[operationId].timepoint; + uint32 nonce = _schedules[operationId].nonce; + + if (timepoint == 0) { + revert AccessManagerNotScheduled(operationId); + } else if (timepoint > Time.timestamp()) { + revert AccessManagerNotReady(operationId); + } else if (_isExpired(timepoint)) { + revert AccessManagerExpired(operationId); + } + + delete _schedules[operationId].timepoint; // reset the timepoint, keep the nonce + emit OperationExecuted(operationId, nonce); + + return nonce; + } + + /// @inheritdoc IAccessManager + function hashOperation(address caller, address target, bytes calldata data) public view virtual returns (bytes32) { + return keccak256(abi.encode(caller, target, data)); + } + + // ==================================================== OTHERS ==================================================== + /// @inheritdoc IAccessManager + function updateAuthority(address target, address newAuthority) public virtual onlyAuthorized { + IAccessManaged(target).setAuthority(newAuthority); + } + + // ================================================= ADMIN LOGIC ================================================== + /** + * @dev Check if the current call is authorized according to admin logic. + */ + function _checkAuthorized() private { + address caller = _msgSender(); + (bool immediate, uint32 delay) = _canCallSelf(caller, _msgData()); + if (!immediate) { + if (delay == 0) { + (, uint64 requiredRole, ) = _getAdminRestrictions(_msgData()); + revert AccessManagerUnauthorizedAccount(caller, requiredRole); + } else { + _consumeScheduledOp(hashOperation(caller, address(this), _msgData())); + } + } + } + + /** + * @dev Get the admin restrictions of a given function call based on the function and arguments involved. + * + * Returns: + * - bool restricted: does this data match a restricted operation + * - uint64: which role is this operation restricted to + * - uint32: minimum delay to enforce for that operation (max between operation's delay and admin's execution delay) + */ + function _getAdminRestrictions( + bytes calldata data + ) private view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) { + if (data.length < 4) { + return (false, 0, 0); + } + + bytes4 selector = _checkSelector(data); + + // Restricted to ADMIN with no delay beside any execution delay the caller may have + if ( + selector == this.labelRole.selector || + selector == this.setRoleAdmin.selector || + selector == this.setRoleGuardian.selector || + selector == this.setGrantDelay.selector || + selector == this.setTargetAdminDelay.selector + ) { + return (true, ADMIN_ROLE, 0); + } + + // Restricted to ADMIN with the admin delay corresponding to the target + if ( + selector == this.updateAuthority.selector || + selector == this.setTargetClosed.selector || + selector == this.setTargetFunctionRole.selector + ) { + // First argument is a target. + address target = abi.decode(data[0x04:0x24], (address)); + uint32 delay = getTargetAdminDelay(target); + return (true, ADMIN_ROLE, delay); + } + + // Restricted to that role's admin with no delay beside any execution delay the caller may have. + if (selector == this.grantRole.selector || selector == this.revokeRole.selector) { + // First argument is a roleId. + uint64 roleId = abi.decode(data[0x04:0x24], (uint64)); + return (true, getRoleAdmin(roleId), 0); + } + + return (false, 0, 0); + } + + // =================================================== HELPERS ==================================================== + /** + * @dev An extended version of {canCall} for internal usage that checks {_canCallSelf} + * when the target is this contract. + * + * Returns: + * - bool immediate: whether the operation can be executed immediately (with no delay) + * - uint32 delay: the execution delay + */ + function _canCallExtended( + address caller, + address target, + bytes calldata data + ) private view returns (bool immediate, uint32 delay) { + if (target == address(this)) { + return _canCallSelf(caller, data); + } else { + return data.length < 4 ? (false, 0) : canCall(caller, target, _checkSelector(data)); + } + } + + /** + * @dev A version of {canCall} that checks for admin restrictions in this contract. + */ + function _canCallSelf(address caller, bytes calldata data) private view returns (bool immediate, uint32 delay) { + if (data.length < 4) { + return (false, 0); + } + + if (caller == address(this)) { + // Caller is AccessManager, this means the call was sent through {execute} and it already checked + // permissions. We verify that the call "identifier", which is set during {execute}, is correct. + return (_isExecuting(address(this), _checkSelector(data)), 0); + } + + (bool enabled, uint64 roleId, uint32 operationDelay) = _getAdminRestrictions(data); + if (!enabled) { + return (false, 0); + } + + (bool inRole, uint32 executionDelay) = hasRole(roleId, caller); + if (!inRole) { + return (false, 0); + } + + // downcast is safe because both options are uint32 + delay = uint32(Math.max(operationDelay, executionDelay)); + return (delay == 0, delay); + } + + /** + * @dev Returns true if a call with `target` and `selector` is being executed via {executed}. + */ + function _isExecuting(address target, bytes4 selector) private view returns (bool) { + return _executionId == _hashExecutionId(target, selector); + } + + /** + * @dev Returns true if a schedule timepoint is past its expiration deadline. + */ + function _isExpired(uint48 timepoint) private view returns (bool) { + return timepoint + expiration() <= Time.timestamp(); + } + + /** + * @dev Extracts the selector from calldata. Panics if data is not at least 4 bytes + */ + function _checkSelector(bytes calldata data) private pure returns (bytes4) { + return bytes4(data[0:4]); + } + + /** + * @dev Hashing function for execute protection + */ + function _hashExecutionId(address target, bytes4 selector) private pure returns (bytes32) { + return keccak256(abi.encode(target, selector)); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AuthorityUtils.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AuthorityUtils.sol new file mode 100644 index 0000000..fb3018c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/AuthorityUtils.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AuthorityUtils.sol) + +pragma solidity ^0.8.20; + +import {IAuthority} from "./IAuthority.sol"; + +library AuthorityUtils { + /** + * @dev Since `AccessManager` implements an extended IAuthority interface, invoking `canCall` with backwards compatibility + * for the preexisting `IAuthority` interface requires special care to avoid reverting on insufficient return data. + * This helper function takes care of invoking `canCall` in a backwards compatible way without reverting. + */ + function canCallWithDelay( + address authority, + address caller, + address target, + bytes4 selector + ) internal view returns (bool immediate, uint32 delay) { + (bool success, bytes memory data) = authority.staticcall( + abi.encodeCall(IAuthority.canCall, (caller, target, selector)) + ); + if (success) { + if (data.length >= 0x40) { + (immediate, delay) = abi.decode(data, (bool, uint32)); + } else if (data.length >= 0x20) { + immediate = abi.decode(data, (bool)); + } + } + return (immediate, delay); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAccessManaged.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAccessManaged.sol new file mode 100644 index 0000000..95206bd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAccessManaged.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManaged.sol) + +pragma solidity ^0.8.20; + +interface IAccessManaged { + /** + * @dev Authority that manages this contract was updated. + */ + event AuthorityUpdated(address authority); + + error AccessManagedUnauthorized(address caller); + error AccessManagedRequiredDelay(address caller, uint32 delay); + error AccessManagedInvalidAuthority(address authority); + + /** + * @dev Returns the current authority. + */ + function authority() external view returns (address); + + /** + * @dev Transfers control to a new authority. The caller must be the current authority. + */ + function setAuthority(address) external; + + /** + * @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is + * being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs + * attacker controlled calls. + */ + function isConsumingScheduledOp() external view returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAccessManager.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAccessManager.sol new file mode 100644 index 0000000..3a6dc73 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAccessManager.sol @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManager.sol) + +pragma solidity ^0.8.20; + +import {IAccessManaged} from "./IAccessManaged.sol"; +import {Time} from "../../utils/types/Time.sol"; + +interface IAccessManager { + /** + * @dev A delayed operation was scheduled. + */ + event OperationScheduled( + bytes32 indexed operationId, + uint32 indexed nonce, + uint48 schedule, + address caller, + address target, + bytes data + ); + + /** + * @dev A scheduled operation was executed. + */ + event OperationExecuted(bytes32 indexed operationId, uint32 indexed nonce); + + /** + * @dev A scheduled operation was canceled. + */ + event OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce); + + /** + * @dev Informational labelling for a roleId. + */ + event RoleLabel(uint64 indexed roleId, string label); + + /** + * @dev Emitted when `account` is granted `roleId`. + * + * NOTE: The meaning of the `since` argument depends on the `newMember` argument. + * If the role is granted to a new member, the `since` argument indicates when the account becomes a member of the role, + * otherwise it indicates the execution delay for this account and roleId is updated. + */ + event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember); + + /** + * @dev Emitted when `account` membership or `roleId` is revoked. Unlike granting, revoking is instantaneous. + */ + event RoleRevoked(uint64 indexed roleId, address indexed account); + + /** + * @dev Role acting as admin over a given `roleId` is updated. + */ + event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin); + + /** + * @dev Role acting as guardian over a given `roleId` is updated. + */ + event RoleGuardianChanged(uint64 indexed roleId, uint64 indexed guardian); + + /** + * @dev Grant delay for a given `roleId` will be updated to `delay` when `since` is reached. + */ + event RoleGrantDelayChanged(uint64 indexed roleId, uint32 delay, uint48 since); + + /** + * @dev Target mode is updated (true = closed, false = open). + */ + event TargetClosed(address indexed target, bool closed); + + /** + * @dev Role required to invoke `selector` on `target` is updated to `roleId`. + */ + event TargetFunctionRoleUpdated(address indexed target, bytes4 selector, uint64 indexed roleId); + + /** + * @dev Admin delay for a given `target` will be updated to `delay` when `since` is reached. + */ + event TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since); + + error AccessManagerAlreadyScheduled(bytes32 operationId); + error AccessManagerNotScheduled(bytes32 operationId); + error AccessManagerNotReady(bytes32 operationId); + error AccessManagerExpired(bytes32 operationId); + error AccessManagerLockedAccount(address account); + error AccessManagerLockedRole(uint64 roleId); + error AccessManagerBadConfirmation(); + error AccessManagerUnauthorizedAccount(address msgsender, uint64 roleId); + error AccessManagerUnauthorizedCall(address caller, address target, bytes4 selector); + error AccessManagerUnauthorizedConsume(address target); + error AccessManagerUnauthorizedCancel(address msgsender, address caller, address target, bytes4 selector); + error AccessManagerInvalidInitialAdmin(address initialAdmin); + + /** + * @dev Check if an address (`caller`) is authorised to call a given function on a given contract directly (with + * no restriction). Additionally, it returns the delay needed to perform the call indirectly through the {schedule} + * & {execute} workflow. + * + * This function is usually called by the targeted contract to control immediate execution of restricted functions. + * Therefore we only return true if the call can be performed without any delay. If the call is subject to a + * previously set delay (not zero), then the function should return false and the caller should schedule the operation + * for future execution. + * + * If `immediate` is true, the delay can be disregarded and the operation can be immediately executed, otherwise + * the operation can be executed if and only if delay is greater than 0. + * + * NOTE: The IAuthority interface does not include the `uint32` delay. This is an extension of that interface that + * is backward compatible. Some contracts may thus ignore the second return argument. In that case they will fail + * to identify the indirect workflow, and will consider calls that require a delay to be forbidden. + * + * NOTE: This function does not report the permissions of this manager itself. These are defined by the + * {_canCallSelf} function instead. + */ + function canCall( + address caller, + address target, + bytes4 selector + ) external view returns (bool allowed, uint32 delay); + + /** + * @dev Expiration delay for scheduled proposals. Defaults to 1 week. + * + * IMPORTANT: Avoid overriding the expiration with 0. Otherwise every contract proposal will be expired immediately, + * disabling any scheduling usage. + */ + function expiration() external view returns (uint32); + + /** + * @dev Minimum setback for all delay updates, with the exception of execution delays. It + * can be increased without setback (and reset via {revokeRole} in the case event of an + * accidental increase). Defaults to 5 days. + */ + function minSetback() external view returns (uint32); + + /** + * @dev Get whether the contract is closed disabling any access. Otherwise role permissions are applied. + */ + function isTargetClosed(address target) external view returns (bool); + + /** + * @dev Get the role required to call a function. + */ + function getTargetFunctionRole(address target, bytes4 selector) external view returns (uint64); + + /** + * @dev Get the admin delay for a target contract. Changes to contract configuration are subject to this delay. + */ + function getTargetAdminDelay(address target) external view returns (uint32); + + /** + * @dev Get the id of the role that acts as an admin for the given role. + * + * The admin permission is required to grant the role, revoke the role and update the execution delay to execute + * an operation that is restricted to this role. + */ + function getRoleAdmin(uint64 roleId) external view returns (uint64); + + /** + * @dev Get the role that acts as a guardian for a given role. + * + * The guardian permission allows canceling operations that have been scheduled under the role. + */ + function getRoleGuardian(uint64 roleId) external view returns (uint64); + + /** + * @dev Get the role current grant delay. + * + * Its value may change at any point without an event emitted following a call to {setGrantDelay}. + * Changes to this value, including effect timepoint are notified in advance by the {RoleGrantDelayChanged} event. + */ + function getRoleGrantDelay(uint64 roleId) external view returns (uint32); + + /** + * @dev Get the access details for a given account for a given role. These details include the timepoint at which + * membership becomes active, and the delay applied to all operation by this user that requires this permission + * level. + * + * Returns: + * [0] Timestamp at which the account membership becomes valid. 0 means role is not granted. + * [1] Current execution delay for the account. + * [2] Pending execution delay for the account. + * [3] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled. + */ + function getAccess(uint64 roleId, address account) external view returns (uint48, uint32, uint32, uint48); + + /** + * @dev Check if a given account currently has the permission level corresponding to a given role. Note that this + * permission might be associated with an execution delay. {getAccess} can provide more details. + */ + function hasRole(uint64 roleId, address account) external view returns (bool, uint32); + + /** + * @dev Give a label to a role, for improved role discoverability by UIs. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {RoleLabel} event. + */ + function labelRole(uint64 roleId, string calldata label) external; + + /** + * @dev Add `account` to `roleId`, or change its execution delay. + * + * This gives the account the authorization to call any function that is restricted to this role. An optional + * execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation + * that is restricted to members of this role. The user will only be able to execute the operation after the delay has + * passed, before it has expired. During this period, admin and guardians can cancel the operation (see {cancel}). + * + * If the account has already been granted this role, the execution delay will be updated. This update is not + * immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is + * called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any + * operation executed in the 3 hours that follows this update was indeed scheduled before this update. + * + * Requirements: + * + * - the caller must be an admin for the role (see {getRoleAdmin}) + * - granted role must not be the `PUBLIC_ROLE` + * + * Emits a {RoleGranted} event. + */ + function grantRole(uint64 roleId, address account, uint32 executionDelay) external; + + /** + * @dev Remove an account from a role, with immediate effect. If the account does not have the role, this call has + * no effect. + * + * Requirements: + * + * - the caller must be an admin for the role (see {getRoleAdmin}) + * - revoked role must not be the `PUBLIC_ROLE` + * + * Emits a {RoleRevoked} event if the account had the role. + */ + function revokeRole(uint64 roleId, address account) external; + + /** + * @dev Renounce role permissions for the calling account with immediate effect. If the sender is not in + * the role this call has no effect. + * + * Requirements: + * + * - the caller must be `callerConfirmation`. + * + * Emits a {RoleRevoked} event if the account had the role. + */ + function renounceRole(uint64 roleId, address callerConfirmation) external; + + /** + * @dev Change admin role for a given role. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {RoleAdminChanged} event + */ + function setRoleAdmin(uint64 roleId, uint64 admin) external; + + /** + * @dev Change guardian role for a given role. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {RoleGuardianChanged} event + */ + function setRoleGuardian(uint64 roleId, uint64 guardian) external; + + /** + * @dev Update the delay for granting a `roleId`. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {RoleGrantDelayChanged} event. + */ + function setGrantDelay(uint64 roleId, uint32 newDelay) external; + + /** + * @dev Set the role required to call functions identified by the `selectors` in the `target` contract. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {TargetFunctionRoleUpdated} event per selector. + */ + function setTargetFunctionRole(address target, bytes4[] calldata selectors, uint64 roleId) external; + + /** + * @dev Set the delay for changing the configuration of a given target contract. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {TargetAdminDelayUpdated} event. + */ + function setTargetAdminDelay(address target, uint32 newDelay) external; + + /** + * @dev Set the closed flag for a contract. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {TargetClosed} event. + */ + function setTargetClosed(address target, bool closed) external; + + /** + * @dev Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the + * operation is not yet scheduled, has expired, was executed, or was canceled. + */ + function getSchedule(bytes32 id) external view returns (uint48); + + /** + * @dev Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never + * been scheduled. + */ + function getNonce(bytes32 id) external view returns (uint32); + + /** + * @dev Schedule a delayed operation for future execution, and return the operation identifier. It is possible to + * choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays + * required for the caller. The special value zero will automatically set the earliest possible time. + * + * Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when + * the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this + * scheduled operation from other occurrences of the same `operationId` in invocations of {execute} and {cancel}. + * + * Emits a {OperationScheduled} event. + * + * NOTE: It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If + * this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target + * contract if it is using standard Solidity ABI encoding. + */ + function schedule(address target, bytes calldata data, uint48 when) external returns (bytes32, uint32); + + /** + * @dev Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the + * execution delay is 0. + * + * Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the + * operation wasn't previously scheduled (if the caller doesn't have an execution delay). + * + * Emits an {OperationExecuted} event only if the call was scheduled and delayed. + */ + function execute(address target, bytes calldata data) external payable returns (uint32); + + /** + * @dev Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled + * operation that is cancelled. + * + * Requirements: + * + * - the caller must be the proposer, a guardian of the targeted function, or a global admin + * + * Emits a {OperationCanceled} event. + */ + function cancel(address caller, address target, bytes calldata data) external returns (uint32); + + /** + * @dev Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed + * (emit an {OperationExecuted} event and clean the state). Otherwise, throw an error. + * + * This is useful for contract that want to enforce that calls targeting them were scheduled on the manager, + * with all the verifications that it implies. + * + * Emit a {OperationExecuted} event. + */ + function consumeScheduledOp(address caller, bytes calldata data) external; + + /** + * @dev Hashing function for delayed operations. + */ + function hashOperation(address caller, address target, bytes calldata data) external view returns (bytes32); + + /** + * @dev Changes the authority of a target managed by this manager instance. + * + * Requirements: + * + * - the caller must be a global admin + */ + function updateAuthority(address target, address newAuthority) external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAuthority.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAuthority.sol new file mode 100644 index 0000000..e2d3898 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/access/manager/IAuthority.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAuthority.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Standard interface for permissioning originally defined in Dappsys. + */ +interface IAuthority { + /** + * @dev Returns true if the caller can invoke on a target the function identified by a function selector. + */ + function canCall(address caller, address target, bytes4 selector) external view returns (bool allowed); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/finance/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/finance/README.adoc new file mode 100644 index 0000000..ac7e4f0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/finance/README.adoc @@ -0,0 +1,14 @@ += Finance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/finance + +This directory includes primitives for financial systems: + +- {VestingWallet} handles the vesting of Ether and ERC20 tokens for a given beneficiary. Custody of multiple tokens can + be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting + schedule. + +== Contracts + +{{VestingWallet}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/finance/VestingWallet.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/finance/VestingWallet.sol new file mode 100644 index 0000000..5abb7cd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/finance/VestingWallet.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (finance/VestingWallet.sol) +pragma solidity ^0.8.20; + +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol"; +import {Address} from "../utils/Address.sol"; +import {Context} from "../utils/Context.sol"; +import {Ownable} from "../access/Ownable.sol"; + +/** + * @dev A vesting wallet is an ownable contract that can receive native currency and ERC20 tokens, and release these + * assets to the wallet owner, also referred to as "beneficiary", according to a vesting schedule. + * + * Any assets 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. + * + * By setting the duration to 0, one can configure this contract to behave like an asset timelock that hold tokens for + * a beneficiary until a specified time. + * + * NOTE: Since the wallet is {Ownable}, and ownership can be transferred, it is possible to sell unvested tokens. + * Preventing this in a smart contract is difficult, considering that: 1) a beneficiary address could be a + * counterfactually deployed contract, 2) there is likely to be a migration path for EOAs to become contracts in the + * near future. + * + * NOTE: When using this contract with any token whose balance is adjusted automatically (i.e. a rebase token), make + * sure to account the supply/balance adjustment in the vesting schedule to ensure the vested amount is as intended. + */ +contract VestingWallet is Context, Ownable { + event EtherReleased(uint256 amount); + event ERC20Released(address indexed token, uint256 amount); + + uint256 private _released; + mapping(address token => uint256) private _erc20Released; + uint64 private immutable _start; + uint64 private immutable _duration; + + /** + * @dev Sets the sender as the initial owner, the beneficiary as the pending owner, the start timestamp and the + * vesting duration of the vesting wallet. + */ + constructor(address beneficiary, uint64 startTimestamp, uint64 durationSeconds) payable Ownable(beneficiary) { + _start = startTimestamp; + _duration = durationSeconds; + } + + /** + * @dev The contract should be able to receive Eth. + */ + receive() external payable virtual {} + + /** + * @dev Getter for the start timestamp. + */ + function start() public view virtual returns (uint256) { + return _start; + } + + /** + * @dev Getter for the vesting duration. + */ + function duration() public view virtual returns (uint256) { + return _duration; + } + + /** + * @dev Getter for the end timestamp. + */ + function end() public view virtual returns (uint256) { + return start() + duration(); + } + + /** + * @dev Amount of eth already released + */ + function released() public view virtual returns (uint256) { + return _released; + } + + /** + * @dev Amount of token already released + */ + function released(address token) public view virtual returns (uint256) { + return _erc20Released[token]; + } + + /** + * @dev Getter for the amount of releasable eth. + */ + function releasable() public view virtual returns (uint256) { + return vestedAmount(uint64(block.timestamp)) - released(); + } + + /** + * @dev Getter for the amount of releasable `token` tokens. `token` should be the address of an + * IERC20 contract. + */ + function releasable(address token) public view virtual returns (uint256) { + return vestedAmount(token, uint64(block.timestamp)) - released(token); + } + + /** + * @dev Release the native token (ether) that have already vested. + * + * Emits a {EtherReleased} event. + */ + function release() public virtual { + uint256 amount = releasable(); + _released += amount; + emit EtherReleased(amount); + Address.sendValue(payable(owner()), amount); + } + + /** + * @dev Release the tokens that have already vested. + * + * Emits a {ERC20Released} event. + */ + function release(address token) public virtual { + uint256 amount = releasable(token); + _erc20Released[token] += amount; + emit ERC20Released(token, amount); + SafeERC20.safeTransfer(IERC20(token), owner(), amount); + } + + /** + * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve. + */ + function vestedAmount(uint64 timestamp) public view virtual returns (uint256) { + return _vestingSchedule(address(this).balance + released(), timestamp); + } + + /** + * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve. + */ + function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) { + return _vestingSchedule(IERC20(token).balanceOf(address(this)) + released(token), timestamp); + } + + /** + * @dev Virtual implementation of the vesting formula. This returns the amount vested, as a function of time, for + * an asset given its total historical allocation. + */ + function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) { + if (timestamp < start()) { + return 0; + } else if (timestamp >= end()) { + return totalAllocation; + } else { + return (totalAllocation * (timestamp - start())) / duration(); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/Governor.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/Governor.sol new file mode 100644 index 0000000..830c9d8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/Governor.sol @@ -0,0 +1,850 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/Governor.sol) + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; +import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; +import {SignatureChecker} from "../utils/cryptography/SignatureChecker.sol"; +import {IERC165, ERC165} from "../utils/introspection/ERC165.sol"; +import {SafeCast} from "../utils/math/SafeCast.sol"; +import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; +import {Address} from "../utils/Address.sol"; +import {Context} from "../utils/Context.sol"; +import {Nonces} from "../utils/Nonces.sol"; +import {IGovernor, IERC6372} from "./IGovernor.sol"; + +/** + * @dev Core of the governance system, designed to be extended through 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} + * - Additionally, {votingPeriod} must also be implemented + */ +abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC721Receiver, IERC1155Receiver { + using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; + + bytes32 public constant BALLOT_TYPEHASH = + keccak256("Ballot(uint256 proposalId,uint8 support,address voter,uint256 nonce)"); + bytes32 public constant EXTENDED_BALLOT_TYPEHASH = + keccak256( + "ExtendedBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason,bytes params)" + ); + + struct ProposalCore { + address proposer; + uint48 voteStart; + uint32 voteDuration; + bool executed; + bool canceled; + uint48 etaSeconds; + } + + bytes32 private constant ALL_PROPOSAL_STATES_BITMAP = bytes32((2 ** (uint8(type(ProposalState).max) + 1)) - 1); + string private _name; + + mapping(uint256 proposalId => ProposalCore) private _proposals; + + // This queue keeps track of the governor operating on itself. Calls to functions protected by the {onlyGovernance} + // modifier needs to be whitelisted in this queue. Whitelisting is set in {execute}, consumed by the + // {onlyGovernance} modifier and eventually reset after {_executeOperations} completes. This ensures that the + // execution of {onlyGovernance} protected calls can only be achieved through successful proposals. + DoubleEndedQueue.Bytes32Deque private _governanceCall; + + /** + * @dev Restricts a function so it can only be executed through governance proposals. For example, governance + * parameter setters in {GovernorSettings} are protected using this modifier. + * + * The governance executing address may be different from the Governor's own address, for example it could be a + * timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these + * functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus, + * for example, additional timelock proposers are not able to change governance parameters without going through the + * governance protocol (since v4.6). + */ + modifier onlyGovernance() { + _checkGovernance(); + _; + } + + /** + * @dev Sets the value for {name} and {version} + */ + constructor(string memory name_) EIP712(name_, version()) { + _name = name_; + } + + /** + * @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract) + */ + receive() external payable virtual { + if (_executor() != address(this)) { + revert GovernorDisabledDeposit(); + } + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return + interfaceId == type(IGovernor).interfaceId || + interfaceId == type(IERC1155Receiver).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IGovernor-name}. + */ + function name() public view virtual returns (string memory) { + return _name; + } + + /** + * @dev See {IGovernor-version}. + */ + function version() public view virtual returns (string memory) { + return "1"; + } + + /** + * @dev See {IGovernor-hashProposal}. + * + * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array + * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id + * can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in + * advance, before the proposal is submitted. + * + * Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the + * same proposal (with same operation and same description) will have the same id if submitted on multiple governors + * across multiple networks. This also means that in order to execute the same operation twice (on the same + * governor) the proposer will have to change the description in order to avoid proposal id conflicts. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public pure virtual returns (uint256) { + return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash))); + } + + /** + * @dev See {IGovernor-state}. + */ + function state(uint256 proposalId) public view virtual returns (ProposalState) { + // We read the struct fields into the stack at once so Solidity emits a single SLOAD + ProposalCore storage proposal = _proposals[proposalId]; + bool proposalExecuted = proposal.executed; + bool proposalCanceled = proposal.canceled; + + if (proposalExecuted) { + return ProposalState.Executed; + } + + if (proposalCanceled) { + return ProposalState.Canceled; + } + + uint256 snapshot = proposalSnapshot(proposalId); + + if (snapshot == 0) { + revert GovernorNonexistentProposal(proposalId); + } + + uint256 currentTimepoint = clock(); + + if (snapshot >= currentTimepoint) { + return ProposalState.Pending; + } + + uint256 deadline = proposalDeadline(proposalId); + + if (deadline >= currentTimepoint) { + return ProposalState.Active; + } else if (!_quorumReached(proposalId) || !_voteSucceeded(proposalId)) { + return ProposalState.Defeated; + } else if (proposalEta(proposalId) == 0) { + return ProposalState.Succeeded; + } else { + return ProposalState.Queued; + } + } + + /** + * @dev See {IGovernor-proposalThreshold}. + */ + function proposalThreshold() public view virtual returns (uint256) { + return 0; + } + + /** + * @dev See {IGovernor-proposalSnapshot}. + */ + function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].voteStart; + } + + /** + * @dev See {IGovernor-proposalDeadline}. + */ + function proposalDeadline(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].voteStart + _proposals[proposalId].voteDuration; + } + + /** + * @dev See {IGovernor-proposalProposer}. + */ + function proposalProposer(uint256 proposalId) public view virtual returns (address) { + return _proposals[proposalId].proposer; + } + + /** + * @dev See {IGovernor-proposalEta}. + */ + function proposalEta(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].etaSeconds; + } + + /** + * @dev See {IGovernor-proposalNeedsQueuing}. + */ + function proposalNeedsQueuing(uint256) public view virtual returns (bool) { + return false; + } + + /** + * @dev Reverts if the `msg.sender` is not the executor. In case the executor is not this contract + * itself, the function reverts if `msg.data` is not whitelisted as a result of an {execute} + * operation. See {onlyGovernance}. + */ + function _checkGovernance() internal virtual { + if (_executor() != _msgSender()) { + revert GovernorOnlyExecutor(_msgSender()); + } + if (_executor() != address(this)) { + bytes32 msgDataHash = keccak256(_msgData()); + // loop until popping the expected operation - throw if deque is empty (operation not authorized) + while (_governanceCall.popFront() != msgDataHash) {} + } + } + + /** + * @dev Amount of votes already cast passes the threshold limit. + */ + function _quorumReached(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Is the proposal successful or not. + */ + function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`. + */ + 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`. + * + * Note: Support is generic and can represent various things depending on the voting system used. + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal virtual; + + /** + * @dev Default additional encoded parameters used by castVote methods that don't include them + * + * Note: Should be overridden by specific implementations to use an appropriate value, the + * meaning of the additional params, in the context of that implementation + */ + function _defaultParams() internal view virtual returns (bytes memory) { + return ""; + } + + /** + * @dev See {IGovernor-propose}. This function has opt-in frontrunning protection, described in {_isValidDescriptionForProposer}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual returns (uint256) { + address proposer = _msgSender(); + + // check description restriction + if (!_isValidDescriptionForProposer(proposer, description)) { + revert GovernorRestrictedProposer(proposer); + } + + // check proposal threshold + uint256 proposerVotes = getVotes(proposer, clock() - 1); + uint256 votesThreshold = proposalThreshold(); + if (proposerVotes < votesThreshold) { + revert GovernorInsufficientProposerVotes(proposer, proposerVotes, votesThreshold); + } + + return _propose(targets, values, calldatas, description, proposer); + } + + /** + * @dev Internal propose mechanism. Can be overridden to add more logic on proposal creation. + * + * Emits a {IGovernor-ProposalCreated} event. + */ + function _propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description, + address proposer + ) internal virtual returns (uint256 proposalId) { + proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description))); + + if (targets.length != values.length || targets.length != calldatas.length || targets.length == 0) { + revert GovernorInvalidProposalLength(targets.length, calldatas.length, values.length); + } + if (_proposals[proposalId].voteStart != 0) { + revert GovernorUnexpectedProposalState(proposalId, state(proposalId), bytes32(0)); + } + + uint256 snapshot = clock() + votingDelay(); + uint256 duration = votingPeriod(); + + ProposalCore storage proposal = _proposals[proposalId]; + proposal.proposer = proposer; + proposal.voteStart = SafeCast.toUint48(snapshot); + proposal.voteDuration = SafeCast.toUint32(duration); + + emit ProposalCreated( + proposalId, + proposer, + targets, + values, + new string[](targets.length), + calldatas, + snapshot, + snapshot + duration, + description + ); + + // Using a named return variable to avoid stack too deep errors + } + + /** + * @dev See {IGovernor-queue}. + */ + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Succeeded)); + + uint48 etaSeconds = _queueOperations(proposalId, targets, values, calldatas, descriptionHash); + + if (etaSeconds != 0) { + _proposals[proposalId].etaSeconds = etaSeconds; + emit ProposalQueued(proposalId, etaSeconds); + } else { + revert GovernorQueueNotImplemented(); + } + + return proposalId; + } + + /** + * @dev Internal queuing mechanism. Can be overridden (without a super call) to modify the way queuing is + * performed (for example adding a vault/timelock). + * + * This is empty by default, and must be overridden to implement queuing. + * + * This function returns a timestamp that describes the expected ETA for execution. If the returned value is 0 + * (which is the default value), the core will consider queueing did not succeed, and the public {queue} function + * will revert. + * + * NOTE: Calling this function directly will NOT check the current state of the proposal, or emit the + * `ProposalQueued` event. Queuing a proposal should be done using {queue}. + */ + function _queueOperations( + uint256 /*proposalId*/, + address[] memory /*targets*/, + uint256[] memory /*values*/, + bytes[] memory /*calldatas*/, + bytes32 /*descriptionHash*/ + ) internal virtual returns (uint48) { + return 0; + } + + /** + * @dev See {IGovernor-execute}. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + _validateStateBitmap( + proposalId, + _encodeStateBitmap(ProposalState.Succeeded) | _encodeStateBitmap(ProposalState.Queued) + ); + + // mark as executed before calls to avoid reentrancy + _proposals[proposalId].executed = true; + + // before execute: register governance call in queue. + if (_executor() != address(this)) { + for (uint256 i = 0; i < targets.length; ++i) { + if (targets[i] == address(this)) { + _governanceCall.pushBack(keccak256(calldatas[i])); + } + } + } + + _executeOperations(proposalId, targets, values, calldatas, descriptionHash); + + // after execute: cleanup governance call queue. + if (_executor() != address(this) && !_governanceCall.empty()) { + _governanceCall.clear(); + } + + emit ProposalExecuted(proposalId); + + return proposalId; + } + + /** + * @dev Internal execution mechanism. Can be overridden (without a super call) to modify the way execution is + * performed (for example adding a vault/timelock). + * + * NOTE: Calling this function directly will NOT check the current state of the proposal, set the executed flag to + * true or emit the `ProposalExecuted` event. Executing a proposal should be done using {execute} or {_execute}. + */ + function _executeOperations( + uint256 /* proposalId */, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual { + for (uint256 i = 0; i < targets.length; ++i) { + (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); + Address.verifyCallResult(success, returndata); + } + } + + /** + * @dev See {IGovernor-cancel}. + */ + function cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256) { + // The proposalId will be recomputed in the `_cancel` call further down. However we need the value before we + // do the internal call, because we need to check the proposal state BEFORE the internal `_cancel` call + // changes it. The `hashProposal` duplication has a cost that is limited, and that we accept. + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + // public cancel restrictions (on top of existing _cancel restrictions). + _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Pending)); + if (_msgSender() != proposalProposer(proposalId)) { + revert GovernorOnlyProposer(_msgSender()); + } + + return _cancel(targets, values, calldatas, descriptionHash); + } + + /** + * @dev Internal cancel mechanism with minimal restrictions. A proposal can be cancelled in any state other than + * Canceled, Expired, or Executed. Once cancelled a proposal can't be re-submitted. + * + * Emits a {IGovernor-ProposalCanceled} event. + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + _validateStateBitmap( + proposalId, + ALL_PROPOSAL_STATES_BITMAP ^ + _encodeStateBitmap(ProposalState.Canceled) ^ + _encodeStateBitmap(ProposalState.Expired) ^ + _encodeStateBitmap(ProposalState.Executed) + ); + + _proposals[proposalId].canceled = true; + emit ProposalCanceled(proposalId); + + return proposalId; + } + + /** + * @dev See {IGovernor-getVotes}. + */ + function getVotes(address account, uint256 timepoint) public view virtual returns (uint256) { + return _getVotes(account, timepoint, _defaultParams()); + } + + /** + * @dev See {IGovernor-getVotesWithParams}. + */ + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) public view virtual returns (uint256) { + return _getVotes(account, timepoint, params); + } + + /** + * @dev See {IGovernor-castVote}. + */ + function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, ""); + } + + /** + * @dev See {IGovernor-castVoteWithReason}. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParams}. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) public virtual returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev See {IGovernor-castVoteBySig}. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + address voter, + bytes memory signature + ) public virtual returns (uint256) { + bool valid = SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter)))), + signature + ); + + if (!valid) { + revert GovernorInvalidSignature(voter); + } + + return _castVote(proposalId, voter, support, ""); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + address voter, + string calldata reason, + bytes memory params, + bytes memory signature + ) public virtual returns (uint256) { + bool valid = SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4( + keccak256( + abi.encode( + EXTENDED_BALLOT_TYPEHASH, + proposalId, + support, + voter, + _useNonce(voter), + keccak256(bytes(reason)), + keccak256(params) + ) + ) + ), + signature + ); + + if (!valid) { + revert GovernorInvalidSignature(voter); + } + + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams(). + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason + ) internal virtual returns (uint256) { + return _castVote(proposalId, account, support, reason, _defaultParams()); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual returns (uint256) { + _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Active)); + + uint256 weight = _getVotes(account, proposalSnapshot(proposalId), params); + _countVote(proposalId, account, support, weight, params); + + if (params.length == 0) { + emit VoteCast(account, proposalId, support, weight, reason); + } else { + emit VoteCastWithParams(account, proposalId, support, weight, reason, params); + } + + return weight; + } + + /** + * @dev Relays a transaction or function call to an arbitrary target. In cases where the governance executor + * is some contract other than the governor itself, like when using a timelock, this function can be invoked + * in a governance proposal to recover tokens or Ether that was sent to the governor contract by mistake. + * Note that if the executor is simply the governor itself, use of `relay` is redundant. + */ + function relay(address target, uint256 value, bytes calldata data) external payable virtual onlyGovernance { + (bool success, bytes memory returndata) = target.call{value: value}(data); + Address.verifyCallResult(success, returndata); + } + + /** + * @dev Address through which the governor executes action. Will be overloaded by module that execute actions + * through another contract such as a timelock. + */ + function _executor() internal view virtual returns (address) { + return address(this); + } + + /** + * @dev See {IERC721Receiver-onERC721Received}. + * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { + if (_executor() != address(this)) { + revert GovernorDisabledDeposit(); + } + return this.onERC721Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155Received}. + * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). + */ + function onERC1155Received(address, address, uint256, uint256, bytes memory) public virtual returns (bytes4) { + if (_executor() != address(this)) { + revert GovernorDisabledDeposit(); + } + return this.onERC1155Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155BatchReceived}. + * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). + */ + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual returns (bytes4) { + if (_executor() != address(this)) { + revert GovernorDisabledDeposit(); + } + return this.onERC1155BatchReceived.selector; + } + + /** + * @dev Encodes a `ProposalState` into a `bytes32` representation where each bit enabled corresponds to + * the underlying position in the `ProposalState` enum. For example: + * + * 0x000...10000 + * ^^^^^^------ ... + * ^----- Succeeded + * ^---- Defeated + * ^--- Canceled + * ^-- Active + * ^- Pending + */ + function _encodeStateBitmap(ProposalState proposalState) internal pure returns (bytes32) { + return bytes32(1 << uint8(proposalState)); + } + + /** + * @dev Check that the current state of a proposal matches the requirements described by the `allowedStates` bitmap. + * This bitmap should be built using `_encodeStateBitmap`. + * + * If requirements are not met, reverts with a {GovernorUnexpectedProposalState} error. + */ + function _validateStateBitmap(uint256 proposalId, bytes32 allowedStates) private view returns (ProposalState) { + ProposalState currentState = state(proposalId); + if (_encodeStateBitmap(currentState) & allowedStates == bytes32(0)) { + revert GovernorUnexpectedProposalState(proposalId, currentState, allowedStates); + } + return currentState; + } + + /* + * @dev Check if the proposer is authorized to submit a proposal with the given description. + * + * If the proposal description ends with `#proposer=0x???`, where `0x???` is an address written as a hex string + * (case insensitive), then the submission of this proposal will only be authorized to said address. + * + * This is used for frontrunning protection. By adding this pattern at the end of their proposal, one can ensure + * that no other address can submit the same proposal. An attacker would have to either remove or change that part, + * which would result in a different proposal id. + * + * If the description does not match this pattern, it is unrestricted and anyone can submit it. This includes: + * - If the `0x???` part is not a valid hex string. + * - If the `0x???` part is a valid hex string, but does not contain exactly 40 hex digits. + * - If it ends with the expected suffix followed by newlines or other whitespace. + * - If it ends with some other similar suffix, e.g. `#other=abc`. + * - If it does not end with any such suffix. + */ + function _isValidDescriptionForProposer( + address proposer, + string memory description + ) internal view virtual returns (bool) { + uint256 len = bytes(description).length; + + // Length is too short to contain a valid proposer suffix + if (len < 52) { + return true; + } + + // Extract what would be the `#proposer=0x` marker beginning the suffix + bytes12 marker; + assembly { + // - Start of the string contents in memory = description + 32 + // - First character of the marker = len - 52 + // - Length of "#proposer=0x0000000000000000000000000000000000000000" = 52 + // - We read the memory word starting at the first character of the marker: + // - (description + 32) + (len - 52) = description + (len - 20) + // - Note: Solidity will ignore anything past the first 12 bytes + marker := mload(add(description, sub(len, 20))) + } + + // If the marker is not found, there is no proposer suffix to check + if (marker != bytes12("#proposer=0x")) { + return true; + } + + // Parse the 40 characters following the marker as uint160 + uint160 recovered = 0; + for (uint256 i = len - 40; i < len; ++i) { + (bool isHex, uint8 value) = _tryHexToUint(bytes(description)[i]); + // If any of the characters is not a hex digit, ignore the suffix entirely + if (!isHex) { + return true; + } + recovered = (recovered << 4) | value; + } + + return recovered == uint160(proposer); + } + + /** + * @dev Try to parse a character from a string as a hex value. Returns `(true, value)` if the char is in + * `[0-9a-fA-F]` and `(false, 0)` otherwise. Value is guaranteed to be in the range `0 <= value < 16` + */ + function _tryHexToUint(bytes1 char) private pure returns (bool, uint8) { + uint8 c = uint8(char); + unchecked { + // Case 0-9 + if (47 < c && c < 58) { + return (true, c - 48); + } + // Case A-F + else if (64 < c && c < 71) { + return (true, c - 55); + } + // Case a-f + else if (96 < c && c < 103) { + return (true, c - 87); + } + // Else: not a hex char + else { + return (false, 0); + } + } + } + + /** + * @inheritdoc IERC6372 + */ + function clock() public view virtual returns (uint48); + + /** + * @inheritdoc IERC6372 + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual returns (string memory); + + /** + * @inheritdoc IGovernor + */ + function votingDelay() public view virtual returns (uint256); + + /** + * @inheritdoc IGovernor + */ + function votingPeriod() public view virtual returns (uint256); + + /** + * @inheritdoc IGovernor + */ + function quorum(uint256 timepoint) public view virtual returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/IGovernor.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/IGovernor.sol new file mode 100644 index 0000000..6cde0e8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/IGovernor.sol @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/IGovernor.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../interfaces/IERC165.sol"; +import {IERC6372} from "../interfaces/IERC6372.sol"; + +/** + * @dev Interface of the {Governor} core. + */ +interface IGovernor is IERC165, IERC6372 { + enum ProposalState { + Pending, + Active, + Canceled, + Defeated, + Succeeded, + Queued, + Expired, + Executed + } + + /** + * @dev Empty proposal or a mismatch between the parameters length for a proposal call. + */ + error GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values); + + /** + * @dev The vote was already cast. + */ + error GovernorAlreadyCastVote(address voter); + + /** + * @dev Token deposits are disabled in this contract. + */ + error GovernorDisabledDeposit(); + + /** + * @dev The `account` is not a proposer. + */ + error GovernorOnlyProposer(address account); + + /** + * @dev The `account` is not the governance executor. + */ + error GovernorOnlyExecutor(address account); + + /** + * @dev The `proposalId` doesn't exist. + */ + error GovernorNonexistentProposal(uint256 proposalId); + + /** + * @dev The current state of a proposal is not the required for performing an operation. + * The `expectedStates` is a bitmap with the bits enabled for each ProposalState enum position + * counting from right to left. + * + * NOTE: If `expectedState` is `bytes32(0)`, the proposal is expected to not be in any state (i.e. not exist). + * This is the case when a proposal that is expected to be unset is already initiated (the proposal is duplicated). + * + * See {Governor-_encodeStateBitmap}. + */ + error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates); + + /** + * @dev The voting period set is not a valid period. + */ + error GovernorInvalidVotingPeriod(uint256 votingPeriod); + + /** + * @dev The `proposer` does not have the required votes to create a proposal. + */ + error GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold); + + /** + * @dev The `proposer` is not allowed to create a proposal. + */ + error GovernorRestrictedProposer(address proposer); + + /** + * @dev The vote type used is not valid for the corresponding counting module. + */ + error GovernorInvalidVoteType(); + + /** + * @dev Queue operation is not implemented for this governor. Execute should be called directly. + */ + error GovernorQueueNotImplemented(); + + /** + * @dev The proposal hasn't been queued yet. + */ + error GovernorNotQueuedProposal(uint256 proposalId); + + /** + * @dev The proposal has already been queued. + */ + error GovernorAlreadyQueuedProposal(uint256 proposalId); + + /** + * @dev The provided signature is not valid for the expected `voter`. + * If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}. + */ + error GovernorInvalidSignature(address voter); + + /** + * @dev Emitted when a proposal is created. + */ + event ProposalCreated( + uint256 proposalId, + address proposer, + address[] targets, + uint256[] values, + string[] signatures, + bytes[] calldatas, + uint256 voteStart, + uint256 voteEnd, + string description + ); + + /** + * @dev Emitted when a proposal is queued. + */ + event ProposalQueued(uint256 proposalId, uint256 etaSeconds); + + /** + * @dev Emitted when a proposal is executed. + */ + event ProposalExecuted(uint256 proposalId); + + /** + * @dev Emitted when a proposal is canceled. + */ + event ProposalCanceled(uint256 proposalId); + + /** + * @dev Emitted when a vote is cast without params. + * + * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. + */ + event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason); + + /** + * @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 interpepretation also depends on the voting module used. + */ + event VoteCastWithParams( + address indexed voter, + uint256 proposalId, + uint8 support, + uint256 weight, + string reason, + bytes params + ); + + /** + * @notice module:core + * @dev Name of the governor instance (used in building the ERC712 domain separator). + */ + function name() external view returns (string memory); + + /** + * @notice module:core + * @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1" + */ + function version() external view 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 + * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of + * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`. + * + * There are 2 standard keys: `support` and `quorum`. + * + * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`. + * - `quorum=bravo` means that only For votes are counted towards quorum. + * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum. + * + * If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique + * name that describes the behavior. For example: + * + * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain. + * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote. + * + * NOTE: The string can be decoded by the standard + * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`] + * JavaScript class. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() external view returns (string memory); + + /** + * @notice module:core + * @dev Hashing function used to (re)build the proposal id from the proposal details.. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external pure returns (uint256); + + /** + * @notice module:core + * @dev Current state of a proposal, following Compound's convention + */ + function state(uint256 proposalId) external view returns (ProposalState); + + /** + * @notice module:core + * @dev The number of votes required in order for a voter to become a proposer. + */ + function proposalThreshold() external view returns (uint256); + + /** + * @notice module:core + * @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) external view returns (uint256); + + /** + * @notice module:core + * @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) external view returns (uint256); + + /** + * @notice module:core + * @dev The account that created a proposal. + */ + function proposalProposer(uint256 proposalId) external view returns (address); + + /** + * @notice module:core + * @dev The time when a queued proposal becomes executable ("ETA"). Unlike {proposalSnapshot} and + * {proposalDeadline}, this doesn't use the governor clock, and instead relies on the executor's clock which may be + * different. In most cases this will be a timestamp. + */ + function proposalEta(uint256 proposalId) external view returns (uint256); + + /** + * @notice module:core + * @dev Whether a proposal needs to be queued before execution. + */ + function proposalNeedsQueuing(uint256 proposalId) external view returns (bool); + + /** + * @notice module:user-config + * @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. + * + * NOTE: While this interface returns a uint256, timepoints are stored as uint48 following the ERC-6372 clock type. + * Consequently this value must fit in a uint48 (when added to the current clock). See {IERC6372-clock}. + */ + function votingDelay() external view returns (uint256); + + /** + * @notice module:user-config + * @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 + * duration compared to the voting delay. + * + * NOTE: This value is stored when the proposal is submitted so that possible changes to the value do not affect + * proposals that have already been submitted. The type used to save it is a uint32. Consequently, while this + * interface returns a uint256, the value it returns should fit in a uint32. + */ + function votingPeriod() external view returns (uint256); + + /** + * @notice module:user-config + * @dev Minimum number of cast voted required for a proposal to be successful. + * + * 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 timepoint) external view returns (uint256); + + /** + * @notice module:reputation + * @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 timepoint) external view returns (uint256); + + /** + * @notice module:reputation + * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters. + */ + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) external view returns (uint256); + + /** + * @notice module:voting + * @dev Returns whether `account` has cast a vote on `proposalId`. + */ + function hasVoted(uint256 proposalId, address account) external view returns (bool); + + /** + * @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. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) external returns (uint256 proposalId); + + /** + * @dev Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing + * is not necessary, this function may revert. + * Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached. + * + * Emits a {ProposalQueued} event. + */ + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external returns (uint256 proposalId); + + /** + * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the + * deadline to be reached. Depending on the governor it might also be required that the proposal was queued and + * that some delay passed. + * + * Emits a {ProposalExecuted} event. + * + * NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external payable returns (uint256 proposalId); + + /** + * @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( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external returns (uint256 proposalId); + + /** + * @dev Cast a vote + * + * Emits a {VoteCast} event. + */ + function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance); + + /** + * @dev Cast a vote with a reason + * + * Emits a {VoteCast} event. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) external returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) external returns (uint256 balance); + + /** + * @dev Cast a vote using the voter's signature, including ERC-1271 signature support. + * + * Emits a {VoteCast} event. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + address voter, + bytes memory signature + ) external returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters using the voter's signature, + * including ERC-1271 signature support. + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + address voter, + string calldata reason, + bytes memory params, + bytes memory signature + ) external returns (uint256 balance); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/README.adoc new file mode 100644 index 0000000..5b38c4d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/README.adoc @@ -0,0 +1,167 @@ += Governance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/governance + +This directory includes primitives for on-chain governance. + +== Governor + +This modular system of Governor contracts allows the deployment on-chain voting protocols similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo] and beyond, through the ability to easily customize multiple aspects of the protocol. + +[TIP] +==== +For a guided experience, set up your Governor contract using https://wizard.openzeppelin.com/#governor[Contracts Wizard]. + +For a written walkthrough, check out our guide on xref:ROOT:governance.adoc[How to set up on-chain governance]. +==== + +* {Governor}: The core contract that contains all the logic and primitives. It is abstract and requires choosing one of each of the modules below, or custom ones. + +Votes modules determine the source of voting power, and sometimes quorum number. + +* {GovernorVotes}: Extracts voting weight from an {ERC20Votes}, or since v4.5 an {ERC721Votes} token. + +* {GovernorVotesQuorumFraction}: Combines with `GovernorVotes` to set the quorum as a fraction of the total token supply. + +Counting modules determine valid voting options. + +* {GovernorCountingSimple}: Simple voting mechanism with 3 voting options: Against, For and Abstain. + +Timelock extensions add a delay for governance decisions to be executed. The workflow is extended to require a `queue` step before execution. With these modules, proposals are executed by the external timelock contract, thus it is the timelock that has to hold the assets that are being governed. + +* {GovernorTimelockControl}: Connects with an instance of {TimelockController}. Allows multiple proposers and executors, in addition to the Governor itself. + +* {GovernorTimelockCompound}: Connects with an instance of Compound's https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[`Timelock`] contract. + +Other extensions can customize the behavior or interface in multiple ways. + +* {GovernorStorage}: Stores the proposal details onchain and provides enumerability of the proposals. This can be useful for some L2 chains where storage is cheap compared to calldata. + +* {GovernorSettings}: Manages some of the settings (voting delay, voting period duration, and proposal threshold) in a way that can be updated through a governance proposal, without requiring an upgrade. + +* {GovernorPreventLateQuorum}: Ensures there is a minimum voting period after quorum is reached as a security protection against large voters. + +In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications: + +* <>: 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. + +=== Core + +{{IGovernor}} + +{{Governor}} + +=== Modules + +{{GovernorCountingSimple}} + +{{GovernorVotes}} + +{{GovernorVotesQuorumFraction}} + +=== Extensions + +{{GovernorTimelockControl}} + +{{GovernorTimelockCompound}} + +{{GovernorSettings}} + +{{GovernorPreventLateQuorum}} + +{{GovernorStorage}} + +== Utils + +{{Votes}} + +== Timelock + +In a governance system, the {TimelockController} contract is in charge of introducing a delay between a proposal and its execution. It can be used with or without a {Governor}. + +{{TimelockController}} + +[[timelock-terminology]] +==== Terminology + +* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content. +* *Operation status:* +** *Unset:* An operation that is not part of the timelock mechanism. +** *Waiting:* An operation that has been scheduled, before the timer expires. +** *Ready:* An operation that has been scheduled, after the timer expires. +** *Pending:* An operation that is either waiting or ready. +** *Done:* An operation that has been executed. +* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations. +* *Role*: +** *Admin:* An address (smart contract or EOA) that is in charge of granting the roles of Proposer and Executor. +** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations. +** *Executor:* An address (smart contract or EOA) that is in charge of executing operations once the timelock has expired. This role can be given to the zero address to allow anyone to execute operations. + +[[timelock-operation]] +==== Operation structure + +Operation executed by the xref:api:governance.adoc#TimelockController[`TimelockController`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations. + +Both operations contain: + +* *Target*, the address of the smart contract that the timelock should operate on. +* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction. +* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encoded using web3js as follows: + +```javascript +const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI() +``` + +* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency. +* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value. + +In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length. + +[[timelock-operation-lifecycle]] +==== Operation lifecycle + +Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle: + +`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done` + +* By calling xref:api:governance.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:governance.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:governance.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method. +* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed. +* By calling xref:api:governance.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:governance.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed. +* xref:api:governance.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled. + +Operations status can be queried using the functions: + +* xref:api:governance.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`] +* xref:api:governance.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`] +* xref:api:governance.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`] + +[[timelock-roles]] +==== Roles + +[[timelock-admin]] +===== Admin + +The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, the admin role can be granted to any address (in addition to the timelock itself). After further configuration and testing, this optional admin should renounce its role such that all further maintenance operations have to go through the timelock process. + +[[timelock-proposer]] +===== Proposer + +The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO. + +WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers. + +This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1` + +[[timelock-executor]] +===== Executor + +The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executors can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers. Alternatively, it is possible to allow _any_ address to execute a proposal once the timelock has expired by granting the executor role to the zero address. + +This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63` + +WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management. diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/TimelockController.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/TimelockController.sol new file mode 100644 index 0000000..349d940 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/TimelockController.sol @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/TimelockController.sol) + +pragma solidity ^0.8.20; + +import {AccessControl} from "../access/AccessControl.sol"; +import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol"; +import {Address} from "../utils/Address.sol"; + +/** + * @dev Contract module which acts as a timelocked controller. When set as the + * owner of an `Ownable` smart contract, it enforces a timelock on all + * `onlyOwner` maintenance operations. This gives time for users of the + * controlled contract to exit before a potentially dangerous maintenance + * operation is applied. + * + * By default, this contract is self administered, meaning administration tasks + * have to go through the timelock process. The proposer (resp executor) role + * is in charge of proposing (resp executing) operations. A common use case is + * to position this {TimelockController} as the owner of a smart contract, with + * a multisig or a DAO as the sole proposer. + */ +contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { + bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); + bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); + bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); + uint256 internal constant _DONE_TIMESTAMP = uint256(1); + + mapping(bytes32 id => uint256) private _timestamps; + uint256 private _minDelay; + + enum OperationState { + Unset, + Waiting, + Ready, + Done + } + + /** + * @dev Mismatch between the parameters length for an operation call. + */ + error TimelockInvalidOperationLength(uint256 targets, uint256 payloads, uint256 values); + + /** + * @dev The schedule operation doesn't meet the minimum delay. + */ + error TimelockInsufficientDelay(uint256 delay, uint256 minDelay); + + /** + * @dev The current state of an operation is not as required. + * The `expectedStates` is a bitmap with the bits enabled for each OperationState enum position + * counting from right to left. + * + * See {_encodeStateBitmap}. + */ + error TimelockUnexpectedOperationState(bytes32 operationId, bytes32 expectedStates); + + /** + * @dev The predecessor to an operation not yet done. + */ + error TimelockUnexecutedPredecessor(bytes32 predecessorId); + + /** + * @dev The caller account is not authorized. + */ + error TimelockUnauthorizedCaller(address caller); + + /** + * @dev Emitted when a call is scheduled as part of operation `id`. + */ + event CallScheduled( + bytes32 indexed id, + uint256 indexed index, + address target, + uint256 value, + bytes data, + bytes32 predecessor, + uint256 delay + ); + + /** + * @dev Emitted when a call is performed as part of operation `id`. + */ + 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. + */ + event Cancelled(bytes32 indexed id); + + /** + * @dev Emitted when the minimum delay for future operations is modified. + */ + event MinDelayChange(uint256 oldDuration, uint256 newDuration); + + /** + * @dev Initializes the contract with the following parameters: + * + * - `minDelay`: initial minimum delay in seconds for operations + * - `proposers`: accounts to be granted proposer and canceller roles + * - `executors`: accounts to be granted executor role + * - `admin`: optional account to be granted admin role; disable with zero address + * + * IMPORTANT: The optional admin can aid with initial configuration of roles after deployment + * without being subject to delay, but this role should be subsequently renounced in favor of + * administration through timelocked proposals. Previous versions of this contract would assign + * this admin to the deployer automatically and should be renounced as well. + */ + constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) { + // self administration + _grantRole(DEFAULT_ADMIN_ROLE, address(this)); + + // optional admin + if (admin != address(0)) { + _grantRole(DEFAULT_ADMIN_ROLE, admin); + } + + // register proposers and cancellers + for (uint256 i = 0; i < proposers.length; ++i) { + _grantRole(PROPOSER_ROLE, proposers[i]); + _grantRole(CANCELLER_ROLE, proposers[i]); + } + + // register executors + for (uint256 i = 0; i < executors.length; ++i) { + _grantRole(EXECUTOR_ROLE, executors[i]); + } + + _minDelay = minDelay; + emit MinDelayChange(0, minDelay); + } + + /** + * @dev Modifier to make a function callable only by a certain role. In + * addition to checking the sender's role, `address(0)` 's role is also + * considered. Granting a role to `address(0)` is equivalent to enabling + * this role for everyone. + */ + modifier onlyRoleOrOpenRole(bytes32 role) { + if (!hasRole(role, address(0))) { + _checkRole(role, _msgSender()); + } + _; + } + + /** + * @dev Contract might receive/hold ETH as part of the maintenance process. + */ + receive() external payable {} + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(AccessControl, ERC1155Holder) returns (bool) { + return super.supportsInterface(interfaceId); + } + + /** + * @dev Returns whether an id corresponds to a registered operation. This + * includes both Waiting, Ready, and Done operations. + */ + function isOperation(bytes32 id) public view returns (bool) { + return getOperationState(id) != OperationState.Unset; + } + + /** + * @dev Returns whether an operation is pending or not. Note that a "pending" operation may also be "ready". + */ + function isOperationPending(bytes32 id) public view returns (bool) { + OperationState state = getOperationState(id); + return state == OperationState.Waiting || state == OperationState.Ready; + } + + /** + * @dev Returns whether an operation is ready for execution. Note that a "ready" operation is also "pending". + */ + function isOperationReady(bytes32 id) public view returns (bool) { + return getOperationState(id) == OperationState.Ready; + } + + /** + * @dev Returns whether an operation is done or not. + */ + function isOperationDone(bytes32 id) public view returns (bool) { + return getOperationState(id) == OperationState.Done; + } + + /** + * @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) { + return _timestamps[id]; + } + + /** + * @dev Returns operation state. + */ + function getOperationState(bytes32 id) public view virtual returns (OperationState) { + uint256 timestamp = getTimestamp(id); + if (timestamp == 0) { + return OperationState.Unset; + } else if (timestamp == _DONE_TIMESTAMP) { + return OperationState.Done; + } else if (timestamp > block.timestamp) { + return OperationState.Waiting; + } else { + return OperationState.Ready; + } + } + + /** + * @dev Returns the minimum delay in seconds for an operation to become valid. + * + * This value can be changed by executing an operation that calls `updateDelay`. + */ + function getMinDelay() public view virtual returns (uint256) { + return _minDelay; + } + + /** + * @dev Returns the identifier of an operation containing a single + * transaction. + */ + function hashOperation( + address target, + uint256 value, + bytes calldata data, + bytes32 predecessor, + bytes32 salt + ) public pure virtual returns (bytes32) { + return keccak256(abi.encode(target, value, data, predecessor, salt)); + } + + /** + * @dev Returns the identifier of an operation containing a batch of + * transactions. + */ + function hashOperationBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt + ) public pure virtual returns (bytes32) { + return keccak256(abi.encode(targets, values, payloads, predecessor, salt)); + } + + /** + * @dev Schedule an operation containing a single transaction. + * + * Emits {CallSalt} if salt is nonzero, and {CallScheduled}. + * + * Requirements: + * + * - the caller must have the 'proposer' role. + */ + function schedule( + address target, + uint256 value, + bytes calldata data, + bytes32 predecessor, + bytes32 salt, + uint256 delay + ) public virtual onlyRole(PROPOSER_ROLE) { + 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 {CallSalt} if salt is nonzero, and one {CallScheduled} event per transaction in the batch. + * + * Requirements: + * + * - the caller must have the 'proposer' role. + */ + function scheduleBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt, + uint256 delay + ) public virtual onlyRole(PROPOSER_ROLE) { + if (targets.length != values.length || targets.length != payloads.length) { + revert TimelockInvalidOperationLength(targets.length, payloads.length, values.length); + } + + bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + _schedule(id, delay); + 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); + } + } + + /** + * @dev Schedule an operation that is to become valid after a given delay. + */ + function _schedule(bytes32 id, uint256 delay) private { + if (isOperation(id)) { + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Unset)); + } + uint256 minDelay = getMinDelay(); + if (delay < minDelay) { + revert TimelockInsufficientDelay(delay, minDelay); + } + _timestamps[id] = block.timestamp + delay; + } + + /** + * @dev Cancel an operation. + * + * Requirements: + * + * - the caller must have the 'canceller' role. + */ + function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) { + if (!isOperationPending(id)) { + revert TimelockUnexpectedOperationState( + id, + _encodeStateBitmap(OperationState.Waiting) | _encodeStateBitmap(OperationState.Ready) + ); + } + delete _timestamps[id]; + + emit Cancelled(id); + } + + /** + * @dev Execute an (ready) operation containing a single transaction. + * + * Emits a {CallExecuted} event. + * + * Requirements: + * + * - the caller must have the 'executor' role. + */ + // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, + // thus any modifications to the operation during reentrancy should be caught. + // slither-disable-next-line reentrancy-eth + function execute( + address target, + uint256 value, + bytes calldata payload, + bytes32 predecessor, + bytes32 salt + ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { + bytes32 id = hashOperation(target, value, payload, predecessor, salt); + + _beforeCall(id, predecessor); + _execute(target, value, payload); + emit CallExecuted(id, 0, target, value, payload); + _afterCall(id); + } + + /** + * @dev Execute an (ready) operation containing a batch of transactions. + * + * Emits one {CallExecuted} event per transaction in the batch. + * + * Requirements: + * + * - the caller must have the 'executor' role. + */ + // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, + // thus any modifications to the operation during reentrancy should be caught. + // slither-disable-next-line reentrancy-eth + function executeBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt + ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { + if (targets.length != values.length || targets.length != payloads.length) { + revert TimelockInvalidOperationLength(targets.length, payloads.length, values.length); + } + + bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + + _beforeCall(id, predecessor); + for (uint256 i = 0; i < targets.length; ++i) { + address target = targets[i]; + uint256 value = values[i]; + bytes calldata payload = payloads[i]; + _execute(target, value, payload); + emit CallExecuted(id, i, target, value, payload); + } + _afterCall(id); + } + + /** + * @dev Execute an operation's call. + */ + function _execute(address target, uint256 value, bytes calldata data) internal virtual { + (bool success, bytes memory returndata) = target.call{value: value}(data); + Address.verifyCallResult(success, returndata); + } + + /** + * @dev Checks before execution of an operation's calls. + */ + function _beforeCall(bytes32 id, bytes32 predecessor) private view { + if (!isOperationReady(id)) { + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready)); + } + if (predecessor != bytes32(0) && !isOperationDone(predecessor)) { + revert TimelockUnexecutedPredecessor(predecessor); + } + } + + /** + * @dev Checks after execution of an operation's calls. + */ + function _afterCall(bytes32 id) private { + if (!isOperationReady(id)) { + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready)); + } + _timestamps[id] = _DONE_TIMESTAMP; + } + + /** + * @dev Changes the minimum timelock duration for future operations. + * + * Emits a {MinDelayChange} event. + * + * Requirements: + * + * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing + * an operation where the timelock is the target and the data is the ABI-encoded call to this function. + */ + function updateDelay(uint256 newDelay) external virtual { + address sender = _msgSender(); + if (sender != address(this)) { + revert TimelockUnauthorizedCaller(sender); + } + emit MinDelayChange(_minDelay, newDelay); + _minDelay = newDelay; + } + + /** + * @dev Encodes a `OperationState` into a `bytes32` representation where each bit enabled corresponds to + * the underlying position in the `OperationState` enum. For example: + * + * 0x000...1000 + * ^^^^^^----- ... + * ^---- Done + * ^--- Ready + * ^-- Waiting + * ^- Unset + */ + function _encodeStateBitmap(OperationState operationState) internal pure returns (bytes32) { + return bytes32(1 << uint8(operationState)); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorCountingSimple.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorCountingSimple.sol new file mode 100644 index 0000000..ac9c22a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorCountingSimple.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorCountingSimple.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} for simple, 3 options, vote counting. + */ +abstract contract GovernorCountingSimple is Governor { + /** + * @dev Supported vote types. Matches Governor Bravo ordering. + */ + enum VoteType { + Against, + For, + Abstain + } + + struct ProposalVote { + uint256 againstVotes; + uint256 forVotes; + uint256 abstainVotes; + mapping(address voter => bool) hasVoted; + } + + mapping(uint256 proposalId => ProposalVote) private _proposalVotes; + + /** + * @dev See {IGovernor-COUNTING_MODE}. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo&quorum=for,abstain"; + } + + /** + * @dev See {IGovernor-hasVoted}. + */ + function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { + return _proposalVotes[proposalId].hasVoted[account]; + } + + /** + * @dev Accessor to the internal vote counts. + */ + function proposalVotes( + uint256 proposalId + ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + return (proposalVote.againstVotes, proposalVote.forVotes, proposalVote.abstainVotes); + } + + /** + * @dev See {Governor-_quorumReached}. + */ + function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + return quorum(proposalSnapshot(proposalId)) <= proposalVote.forVotes + proposalVote.abstainVotes; + } + + /** + * @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) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + return proposalVote.forVotes > proposalVote.againstVotes; + } + + /** + * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo). + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory // params + ) internal virtual override { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + if (proposalVote.hasVoted[account]) { + revert GovernorAlreadyCastVote(account); + } + proposalVote.hasVoted[account] = true; + + if (support == uint8(VoteType.Against)) { + proposalVote.againstVotes += weight; + } else if (support == uint8(VoteType.For)) { + proposalVote.forVotes += weight; + } else if (support == uint8(VoteType.Abstain)) { + proposalVote.abstainVotes += weight; + } else { + revert GovernorInvalidVoteType(); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorPreventLateQuorum.sol new file mode 100644 index 0000000..ff80af6 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorPreventLateQuorum.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; +import {Math} from "../../utils/math/Math.sol"; + +/** + * @dev A module that ensures there is a minimum voting period after quorum is reached. This prevents a large voter from + * swaying a vote and triggering quorum at the last minute, by ensuring there is always time for other voters to react + * 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 specified time has passed (the "vote extension" parameter). This parameter can be set through a governance + * proposal. + */ +abstract contract GovernorPreventLateQuorum is Governor { + uint48 private _voteExtension; + + mapping(uint256 proposalId => uint48) 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); + + /// @dev Emitted when the {lateQuorumVoteExtension} parameter is changed. + event LateQuorumVoteExtensionSet(uint64 oldVoteExtension, uint64 newVoteExtension); + + /** + * @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(uint48 initialVoteExtension) { + _setLateQuorumVoteExtension(initialVoteExtension); + } + + /** + * @dev Returns the proposal deadline, which may have been extended beyond that set at proposal creation, if the + * 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]); + } + + /** + * @dev Casts a vote and detects if it caused quorum to be reached, potentially extending the voting period. See + * {Governor-_castVote}. + * + * May emit a {ProposalExtended} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual override returns (uint256) { + uint256 result = super._castVote(proposalId, account, support, reason, params); + + if (_extendedDeadlines[proposalId] == 0 && _quorumReached(proposalId)) { + uint48 extendedDeadline = clock() + lateQuorumVoteExtension(); + + if (extendedDeadline > proposalDeadline(proposalId)) { + emit ProposalExtended(proposalId, extendedDeadline); + } + + _extendedDeadlines[proposalId] = extendedDeadline; + } + + return result; + } + + /** + * @dev Returns the current value of the vote extension parameter: the number of blocks that are required to pass + * from the time a proposal reaches quorum until its voting period ends. + */ + function lateQuorumVoteExtension() public view virtual returns (uint48) { + return _voteExtension; + } + + /** + * @dev Changes the {lateQuorumVoteExtension}. This operation can only be performed by the governance executor, + * generally through a governance proposal. + * + * Emits a {LateQuorumVoteExtensionSet} event. + */ + function setLateQuorumVoteExtension(uint48 newVoteExtension) public virtual onlyGovernance { + _setLateQuorumVoteExtension(newVoteExtension); + } + + /** + * @dev Changes the {lateQuorumVoteExtension}. This is an internal function that can be exposed in a public function + * like {setLateQuorumVoteExtension} if another access control mechanism is needed. + * + * Emits a {LateQuorumVoteExtensionSet} event. + */ + function _setLateQuorumVoteExtension(uint48 newVoteExtension) internal virtual { + emit LateQuorumVoteExtensionSet(_voteExtension, newVoteExtension); + _voteExtension = newVoteExtension; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorSettings.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorSettings.sol new file mode 100644 index 0000000..7347ee2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorSettings.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorSettings.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} for settings updatable through governance. + */ +abstract contract GovernorSettings is Governor { + // amount of token + uint256 private _proposalThreshold; + // timepoint: limited to uint48 in core (same as clock() type) + uint48 private _votingDelay; + // duration: limited to uint32 in core + uint32 private _votingPeriod; + + event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay); + event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod); + event ProposalThresholdSet(uint256 oldProposalThreshold, uint256 newProposalThreshold); + + /** + * @dev Initialize the governance parameters. + */ + constructor(uint48 initialVotingDelay, uint32 initialVotingPeriod, uint256 initialProposalThreshold) { + _setVotingDelay(initialVotingDelay); + _setVotingPeriod(initialVotingPeriod); + _setProposalThreshold(initialProposalThreshold); + } + + /** + * @dev See {IGovernor-votingDelay}. + */ + function votingDelay() public view virtual override returns (uint256) { + return _votingDelay; + } + + /** + * @dev See {IGovernor-votingPeriod}. + */ + function votingPeriod() public view virtual override returns (uint256) { + return _votingPeriod; + } + + /** + * @dev See {Governor-proposalThreshold}. + */ + function proposalThreshold() public view virtual override returns (uint256) { + return _proposalThreshold; + } + + /** + * @dev Update the voting delay. This operation can only be performed through a governance proposal. + * + * Emits a {VotingDelaySet} event. + */ + function setVotingDelay(uint48 newVotingDelay) public virtual onlyGovernance { + _setVotingDelay(newVotingDelay); + } + + /** + * @dev Update the voting period. This operation can only be performed through a governance proposal. + * + * Emits a {VotingPeriodSet} event. + */ + function setVotingPeriod(uint32 newVotingPeriod) public virtual onlyGovernance { + _setVotingPeriod(newVotingPeriod); + } + + /** + * @dev Update the proposal threshold. This operation can only be performed through a governance proposal. + * + * Emits a {ProposalThresholdSet} event. + */ + function setProposalThreshold(uint256 newProposalThreshold) public virtual onlyGovernance { + _setProposalThreshold(newProposalThreshold); + } + + /** + * @dev Internal setter for the voting delay. + * + * Emits a {VotingDelaySet} event. + */ + function _setVotingDelay(uint48 newVotingDelay) internal virtual { + emit VotingDelaySet(_votingDelay, newVotingDelay); + _votingDelay = newVotingDelay; + } + + /** + * @dev Internal setter for the voting period. + * + * Emits a {VotingPeriodSet} event. + */ + function _setVotingPeriod(uint32 newVotingPeriod) internal virtual { + if (newVotingPeriod == 0) { + revert GovernorInvalidVotingPeriod(0); + } + emit VotingPeriodSet(_votingPeriod, newVotingPeriod); + _votingPeriod = newVotingPeriod; + } + + /** + * @dev Internal setter for the proposal threshold. + * + * Emits a {ProposalThresholdSet} event. + */ + function _setProposalThreshold(uint256 newProposalThreshold) internal virtual { + emit ProposalThresholdSet(_proposalThreshold, newProposalThreshold); + _proposalThreshold = newProposalThreshold; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorStorage.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorStorage.sol new file mode 100644 index 0000000..2547b55 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorStorage.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorStorage.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} that implements storage of proposal details. This modules also provides primitives for + * the enumerability of proposals. + * + * Use cases for this module include: + * - UIs that explore the proposal state without relying on event indexing. + * - Using only the proposalId as an argument in the {Governor-queue} and {Governor-execute} functions for L2 chains + * where storage is cheap compared to calldata. + */ +abstract contract GovernorStorage is Governor { + struct ProposalDetails { + address[] targets; + uint256[] values; + bytes[] calldatas; + bytes32 descriptionHash; + } + + uint256[] private _proposalIds; + mapping(uint256 proposalId => ProposalDetails) private _proposalDetails; + + /** + * @dev Hook into the proposing mechanism + */ + function _propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description, + address proposer + ) internal virtual override returns (uint256) { + uint256 proposalId = super._propose(targets, values, calldatas, description, proposer); + + // store + _proposalIds.push(proposalId); + _proposalDetails[proposalId] = ProposalDetails({ + targets: targets, + values: values, + calldatas: calldatas, + descriptionHash: keccak256(bytes(description)) + }); + + return proposalId; + } + + /** + * @dev Version of {IGovernorTimelock-queue} with only `proposalId` as an argument. + */ + function queue(uint256 proposalId) public virtual { + // here, using storage is more efficient than memory + ProposalDetails storage details = _proposalDetails[proposalId]; + queue(details.targets, details.values, details.calldatas, details.descriptionHash); + } + + /** + * @dev Version of {IGovernor-execute} with only `proposalId` as an argument. + */ + function execute(uint256 proposalId) public payable virtual { + // here, using storage is more efficient than memory + ProposalDetails storage details = _proposalDetails[proposalId]; + execute(details.targets, details.values, details.calldatas, details.descriptionHash); + } + + /** + * @dev ProposalId version of {IGovernor-cancel}. + */ + function cancel(uint256 proposalId) public virtual { + // here, using storage is more efficient than memory + ProposalDetails storage details = _proposalDetails[proposalId]; + cancel(details.targets, details.values, details.calldatas, details.descriptionHash); + } + + /** + * @dev Returns the number of stored proposals. + */ + function proposalCount() public view virtual returns (uint256) { + return _proposalIds.length; + } + + /** + * @dev Returns the details of a proposalId. Reverts if `proposalId` is not a known proposal. + */ + function proposalDetails( + uint256 proposalId + ) public view virtual returns (address[] memory, uint256[] memory, bytes[] memory, bytes32) { + // here, using memory is more efficient than storage + ProposalDetails memory details = _proposalDetails[proposalId]; + if (details.descriptionHash == 0) { + revert GovernorNonexistentProposal(proposalId); + } + return (details.targets, details.values, details.calldatas, details.descriptionHash); + } + + /** + * @dev Returns the details (including the proposalId) of a proposal given its sequential index. + */ + function proposalDetailsAt( + uint256 index + ) public view virtual returns (uint256, address[] memory, uint256[] memory, bytes[] memory, bytes32) { + uint256 proposalId = _proposalIds[index]; + ( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) = proposalDetails(proposalId); + return (proposalId, targets, values, calldatas, descriptionHash); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockAccess.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockAccess.sol new file mode 100644 index 0000000..a2373a4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockAccess.sol @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorTimelockAccess.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; +import {AuthorityUtils} from "../../access/manager/AuthorityUtils.sol"; +import {IAccessManager} from "../../access/manager/IAccessManager.sol"; +import {Address} from "../../utils/Address.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Time} from "../../utils/types/Time.sol"; + +/** + * @dev This module connects a {Governor} instance to an {AccessManager} instance, allowing the governor to make calls + * that are delay-restricted by the manager using the normal {queue} workflow. An optional base delay is applied to + * operations that are not delayed externally by the manager. Execution of a proposal will be delayed as much as + * necessary to meet the required delays of all of its operations. + * + * This extension allows the governor to hold and use its own assets and permissions, unlike {GovernorTimelockControl} + * and {GovernorTimelockCompound}, where the timelock is a separate contract that must be the one to hold assets and + * permissions. Operations that are delay-restricted by the manager, however, will be executed through the + * {AccessManager-execute} function. + * + * ==== Security Considerations + * + * Some operations may be cancelable in the `AccessManager` by the admin or a set of guardians, depending on the + * restricted function being invoked. Since proposals are atomic, the cancellation by a guardian of a single operation + * in a proposal will cause all of the proposal to become unable to execute. Consider proposing cancellable operations + * separately. + * + * By default, function calls will be routed through the associated `AccessManager` whenever it claims the target + * function to be restricted by it. However, admins may configure the manager to make that claim for functions that a + * governor would want to call directly (e.g., token transfers) in an attempt to deny it access to those functions. To + * mitigate this attack vector, the governor is able to ignore the restrictions claimed by the `AccessManager` using + * {setAccessManagerIgnored}. While permanent denial of service is mitigated, temporary DoS may still be technically + * possible. All of the governor's own functions (e.g., {setBaseDelaySeconds}) ignore the `AccessManager` by default. + */ +abstract contract GovernorTimelockAccess is Governor { + // An execution plan is produced at the moment a proposal is created, in order to fix at that point the exact + // execution semantics of the proposal, namely whether a call will go through {AccessManager-execute}. + struct ExecutionPlan { + uint16 length; + uint32 delay; + // We use mappings instead of arrays because it allows us to pack values in storage more tightly without + // storing the length redundantly. + // We pack 8 operations' data in each bucket. Each uint32 value is set to 1 upon proposal creation if it has + // to be scheduled and executed through the manager. Upon queuing, the value is set to nonce + 2, where the + // nonce is received from the manager when scheduling the operation. + mapping(uint256 operationBucket => uint32[8]) managerData; + } + + // The meaning of the "toggle" set to true depends on the target contract. + // If target == address(this), the manager is ignored by default, and a true toggle means it won't be ignored. + // For all other target contracts, the manager is used by default, and a true toggle means it will be ignored. + mapping(address target => mapping(bytes4 selector => bool)) private _ignoreToggle; + + mapping(uint256 proposalId => ExecutionPlan) private _executionPlan; + + uint32 private _baseDelay; + + IAccessManager private immutable _manager; + + error GovernorUnmetDelay(uint256 proposalId, uint256 neededTimestamp); + error GovernorMismatchedNonce(uint256 proposalId, uint256 expectedNonce, uint256 actualNonce); + error GovernorLockedIgnore(); + + event BaseDelaySet(uint32 oldBaseDelaySeconds, uint32 newBaseDelaySeconds); + event AccessManagerIgnoredSet(address target, bytes4 selector, bool ignored); + + /** + * @dev Initialize the governor with an {AccessManager} and initial base delay. + */ + constructor(address manager, uint32 initialBaseDelay) { + _manager = IAccessManager(manager); + _setBaseDelaySeconds(initialBaseDelay); + } + + /** + * @dev Returns the {AccessManager} instance associated to this governor. + */ + function accessManager() public view virtual returns (IAccessManager) { + return _manager; + } + + /** + * @dev Base delay that will be applied to all function calls. Some may be further delayed by their associated + * `AccessManager` authority; in this case the final delay will be the maximum of the base delay and the one + * demanded by the authority. + * + * NOTE: Execution delays are processed by the `AccessManager` contracts, and according to that contract are + * expressed in seconds. Therefore, the base delay is also in seconds, regardless of the governor's clock mode. + */ + function baseDelaySeconds() public view virtual returns (uint32) { + return _baseDelay; + } + + /** + * @dev Change the value of {baseDelaySeconds}. This operation can only be invoked through a governance proposal. + */ + function setBaseDelaySeconds(uint32 newBaseDelay) public virtual onlyGovernance { + _setBaseDelaySeconds(newBaseDelay); + } + + /** + * @dev Change the value of {baseDelaySeconds}. Internal function without access control. + */ + function _setBaseDelaySeconds(uint32 newBaseDelay) internal virtual { + emit BaseDelaySet(_baseDelay, newBaseDelay); + _baseDelay = newBaseDelay; + } + + /** + * @dev Check if restrictions from the associated {AccessManager} are ignored for a target function. Returns true + * when the target function will be invoked directly regardless of `AccessManager` settings for the function. + * See {setAccessManagerIgnored} and Security Considerations above. + */ + function isAccessManagerIgnored(address target, bytes4 selector) public view virtual returns (bool) { + bool isGovernor = target == address(this); + return _ignoreToggle[target][selector] != isGovernor; // equivalent to: isGovernor ? !toggle : toggle + } + + /** + * @dev Configure whether restrictions from the associated {AccessManager} are ignored for a target function. + * See Security Considerations above. + */ + function setAccessManagerIgnored( + address target, + bytes4[] calldata selectors, + bool ignored + ) public virtual onlyGovernance { + for (uint256 i = 0; i < selectors.length; ++i) { + _setAccessManagerIgnored(target, selectors[i], ignored); + } + } + + /** + * @dev Internal version of {setAccessManagerIgnored} without access restriction. + */ + function _setAccessManagerIgnored(address target, bytes4 selector, bool ignored) internal virtual { + bool isGovernor = target == address(this); + if (isGovernor && selector == this.setAccessManagerIgnored.selector) { + revert GovernorLockedIgnore(); + } + _ignoreToggle[target][selector] = ignored != isGovernor; // equivalent to: isGovernor ? !ignored : ignored + emit AccessManagerIgnoredSet(target, selector, ignored); + } + + /** + * @dev Public accessor to check the execution plan, including the number of seconds that the proposal will be + * delayed since queuing, an array indicating which of the proposal actions will be executed indirectly through + * the associated {AccessManager}, and another indicating which will be scheduled in {queue}. Note that + * those that must be scheduled are cancellable by `AccessManager` guardians. + */ + function proposalExecutionPlan( + uint256 proposalId + ) public view returns (uint32 delay, bool[] memory indirect, bool[] memory withDelay) { + ExecutionPlan storage plan = _executionPlan[proposalId]; + + uint32 length = plan.length; + delay = plan.delay; + indirect = new bool[](length); + withDelay = new bool[](length); + for (uint256 i = 0; i < length; ++i) { + (indirect[i], withDelay[i], ) = _getManagerData(plan, i); + } + + return (delay, indirect, withDelay); + } + + /** + * @dev See {IGovernor-proposalNeedsQueuing}. + */ + function proposalNeedsQueuing(uint256 proposalId) public view virtual override returns (bool) { + return _executionPlan[proposalId].delay > 0; + } + + /** + * @dev See {IGovernor-propose} + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual override returns (uint256) { + uint256 proposalId = super.propose(targets, values, calldatas, description); + + uint32 neededDelay = baseDelaySeconds(); + + ExecutionPlan storage plan = _executionPlan[proposalId]; + plan.length = SafeCast.toUint16(targets.length); + + for (uint256 i = 0; i < targets.length; ++i) { + if (calldatas[i].length < 4) { + continue; + } + address target = targets[i]; + bytes4 selector = bytes4(calldatas[i]); + (bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay( + address(_manager), + address(this), + target, + selector + ); + if ((immediate || delay > 0) && !isAccessManagerIgnored(target, selector)) { + _setManagerData(plan, i, !immediate, 0); + // downcast is safe because both arguments are uint32 + neededDelay = uint32(Math.max(delay, neededDelay)); + } + } + + plan.delay = neededDelay; + + return proposalId; + } + + /** + * @dev Mechanism to queue a proposal, potentially scheduling some of its operations in the AccessManager. + * + * NOTE: The execution delay is chosen based on the delay information retrieved in {propose}. This value may be + * off if the delay was updated since proposal creation. In this case, the proposal needs to be recreated. + */ + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory /* values */, + bytes[] memory calldatas, + bytes32 /* descriptionHash */ + ) internal virtual override returns (uint48) { + ExecutionPlan storage plan = _executionPlan[proposalId]; + uint48 etaSeconds = Time.timestamp() + plan.delay; + + for (uint256 i = 0; i < targets.length; ++i) { + (, bool withDelay, ) = _getManagerData(plan, i); + if (withDelay) { + (, uint32 nonce) = _manager.schedule(targets[i], calldatas[i], etaSeconds); + _setManagerData(plan, i, true, nonce); + } + } + + return etaSeconds; + } + + /** + * @dev Mechanism to execute a proposal, potentially going through {AccessManager-execute} for delayed operations. + */ + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /* descriptionHash */ + ) internal virtual override { + uint48 etaSeconds = SafeCast.toUint48(proposalEta(proposalId)); + if (block.timestamp < etaSeconds) { + revert GovernorUnmetDelay(proposalId, etaSeconds); + } + + ExecutionPlan storage plan = _executionPlan[proposalId]; + + for (uint256 i = 0; i < targets.length; ++i) { + (bool controlled, bool withDelay, uint32 nonce) = _getManagerData(plan, i); + if (controlled) { + uint32 executedNonce = _manager.execute{value: values[i]}(targets[i], calldatas[i]); + if (withDelay && executedNonce != nonce) { + revert GovernorMismatchedNonce(proposalId, nonce, executedNonce); + } + } else { + (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); + Address.verifyCallResult(success, returndata); + } + } + } + + /** + * @dev See {IGovernor-_cancel} + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + uint48 etaSeconds = SafeCast.toUint48(proposalEta(proposalId)); + + ExecutionPlan storage plan = _executionPlan[proposalId]; + + // If the proposal has been scheduled it will have an ETA and we may have to externally cancel + if (etaSeconds != 0) { + for (uint256 i = 0; i < targets.length; ++i) { + (, bool withDelay, uint32 nonce) = _getManagerData(plan, i); + // Only attempt to cancel if the execution plan included a delay + if (withDelay) { + bytes32 operationId = _manager.hashOperation(address(this), targets[i], calldatas[i]); + // Check first if the current operation nonce is the one that we observed previously. It could + // already have been cancelled and rescheduled. We don't want to cancel unless it is exactly the + // instance that we previously scheduled. + if (nonce == _manager.getNonce(operationId)) { + // It is important that all calls have an opportunity to be cancelled. We chose to ignore + // potential failures of some of the cancel operations to give the other operations a chance to + // be properly cancelled. In particular cancel might fail if the operation was already cancelled + // by guardians previously. We don't match on the revert reason to avoid encoding assumptions + // about specific errors. + try _manager.cancel(address(this), targets[i], calldatas[i]) {} catch {} + } + } + } + } + + return proposalId; + } + + /** + * @dev Returns whether the operation at an index is delayed by the manager, and its scheduling nonce once queued. + */ + function _getManagerData( + ExecutionPlan storage plan, + uint256 index + ) private view returns (bool controlled, bool withDelay, uint32 nonce) { + (uint256 bucket, uint256 subindex) = _getManagerDataIndices(index); + uint32 value = plan.managerData[bucket][subindex]; + unchecked { + return (value > 0, value > 1, value > 1 ? value - 2 : 0); + } + } + + /** + * @dev Marks an operation at an index as permissioned by the manager, potentially delayed, and + * when delayed sets its scheduling nonce. + */ + function _setManagerData(ExecutionPlan storage plan, uint256 index, bool withDelay, uint32 nonce) private { + (uint256 bucket, uint256 subindex) = _getManagerDataIndices(index); + plan.managerData[bucket][subindex] = withDelay ? nonce + 2 : 1; + } + + /** + * @dev Returns bucket and subindex for reading manager data from the packed array mapping. + */ + function _getManagerDataIndices(uint256 index) private pure returns (uint256 bucket, uint256 subindex) { + bucket = index >> 3; // index / 8 + subindex = index & 7; // index % 8 + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockCompound.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockCompound.sol new file mode 100644 index 0000000..117df01 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorTimelockCompound.sol) + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../Governor.sol"; +import {ICompoundTimelock} from "../../vendor/compound/ICompoundTimelock.sol"; +import {Address} from "../../utils/Address.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; + +/** + * @dev Extension of {Governor} that binds the execution process to a Compound Timelock. This adds a delay, enforced by + * the external timelock to all successful proposal (in addition to the voting duration). The {Governor} needs to be + * the admin of the timelock for any operation to be performed. A public, unrestricted, + * {GovernorTimelockCompound-__acceptAdmin} is available to accept ownership of the timelock. + * + * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * inaccessible. + */ +abstract contract GovernorTimelockCompound is Governor { + ICompoundTimelock private _timelock; + + /** + * @dev Emitted when the timelock controller used for proposal execution is modified. + */ + event TimelockChange(address oldTimelock, address newTimelock); + + /** + * @dev Set the timelock. + */ + constructor(ICompoundTimelock timelockAddress) { + _updateTimelock(timelockAddress); + } + + /** + * @dev Overridden version of the {Governor-state} function with added support for the `Expired` state. + */ + function state(uint256 proposalId) public view virtual override returns (ProposalState) { + ProposalState currentState = super.state(proposalId); + + return + (currentState == ProposalState.Queued && + block.timestamp >= proposalEta(proposalId) + _timelock.GRACE_PERIOD()) + ? ProposalState.Expired + : currentState; + } + + /** + * @dev Public accessor to check the address of the timelock + */ + function timelock() public view virtual returns (address) { + return address(_timelock); + } + + /** + * @dev See {IGovernor-proposalNeedsQueuing}. + */ + function proposalNeedsQueuing(uint256) public view virtual override returns (bool) { + return true; + } + + /** + * @dev Function to queue a proposal to the timelock. + */ + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual override returns (uint48) { + uint48 etaSeconds = SafeCast.toUint48(block.timestamp + _timelock.delay()); + + for (uint256 i = 0; i < targets.length; ++i) { + if ( + _timelock.queuedTransactions(keccak256(abi.encode(targets[i], values[i], "", calldatas[i], etaSeconds))) + ) { + revert GovernorAlreadyQueuedProposal(proposalId); + } + _timelock.queueTransaction(targets[i], values[i], "", calldatas[i], etaSeconds); + } + + return etaSeconds; + } + + /** + * @dev Overridden version of the {Governor-_executeOperations} function that run the already queued proposal + * through the timelock. + */ + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual override { + uint256 etaSeconds = proposalEta(proposalId); + if (etaSeconds == 0) { + revert GovernorNotQueuedProposal(proposalId); + } + Address.sendValue(payable(_timelock), msg.value); + for (uint256 i = 0; i < targets.length; ++i) { + _timelock.executeTransaction(targets[i], values[i], "", calldatas[i], etaSeconds); + } + } + + /** + * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it has already + * been queued. + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + uint256 etaSeconds = proposalEta(proposalId); + if (etaSeconds > 0) { + // do external call later + for (uint256 i = 0; i < targets.length; ++i) { + _timelock.cancelTransaction(targets[i], values[i], "", calldatas[i], etaSeconds); + } + } + + return proposalId; + } + + /** + * @dev Address through which the governor executes action. In this case, the timelock. + */ + function _executor() internal view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Accept admin right over the timelock. + */ + // solhint-disable-next-line private-vars-leading-underscore + function __acceptAdmin() public { + _timelock.acceptAdmin(); + } + + /** + * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates + * must be proposed, scheduled, and executed through governance proposals. + * + * For security reasons, the timelock must be handed over to another admin before setting up a new one. The two + * operations (hand over the timelock) and do the update can be batched in a single proposal. + * + * Note that if the timelock admin has been handed over in a previous operation, we refuse updates made through the + * timelock if admin of the timelock has already been accepted and the operation is executed outside the scope of + * governance. + + * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. + */ + function updateTimelock(ICompoundTimelock newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(ICompoundTimelock newTimelock) private { + emit TimelockChange(address(_timelock), address(newTimelock)); + _timelock = newTimelock; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockControl.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockControl.sol new file mode 100644 index 0000000..53503cc --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorTimelockControl.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorTimelockControl.sol) + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../Governor.sol"; +import {TimelockController} from "../TimelockController.sol"; +import {IERC165} from "../../interfaces/IERC165.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; + +/** + * @dev Extension of {Governor} that binds the execution process to an instance of {TimelockController}. This adds a + * delay, enforced by the {TimelockController} to all successful proposal (in addition to the voting duration). The + * {Governor} needs the proposer (and ideally the executor) roles for the {Governor} to work properly. + * + * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * inaccessible from a proposal, unless executed via {Governor-relay}. + * + * WARNING: Setting up the TimelockController to have additional proposers or cancellers besides the governor is very + * risky, as it grants them the ability to: 1) execute operations as the timelock, and thus possibly performing + * operations or accessing funds that are expected to only be accessible through a vote, and 2) block governance + * proposals that have been approved by the voters, effectively executing a Denial of Service attack. + * + * NOTE: `AccessManager` does not support scheduling more than one operation with the same target and calldata at + * the same time. See {AccessManager-schedule} for a workaround. + */ +abstract contract GovernorTimelockControl is Governor { + TimelockController private _timelock; + mapping(uint256 proposalId => bytes32) private _timelockIds; + + /** + * @dev Emitted when the timelock controller used for proposal execution is modified. + */ + event TimelockChange(address oldTimelock, address newTimelock); + + /** + * @dev Set the timelock. + */ + constructor(TimelockController timelockAddress) { + _updateTimelock(timelockAddress); + } + + /** + * @dev Overridden version of the {Governor-state} function that considers the status reported by the timelock. + */ + function state(uint256 proposalId) public view virtual override returns (ProposalState) { + ProposalState currentState = super.state(proposalId); + + if (currentState != ProposalState.Queued) { + return currentState; + } + + bytes32 queueid = _timelockIds[proposalId]; + if (_timelock.isOperationPending(queueid)) { + return ProposalState.Queued; + } else if (_timelock.isOperationDone(queueid)) { + // This can happen if the proposal is executed directly on the timelock. + return ProposalState.Executed; + } else { + // This can happen if the proposal is canceled directly on the timelock. + return ProposalState.Canceled; + } + } + + /** + * @dev Public accessor to check the address of the timelock + */ + function timelock() public view virtual returns (address) { + return address(_timelock); + } + + /** + * @dev See {IGovernor-proposalNeedsQueuing}. + */ + function proposalNeedsQueuing(uint256) public view virtual override returns (bool) { + return true; + } + + /** + * @dev Function to queue a proposal to the timelock. + */ + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint48) { + uint256 delay = _timelock.getMinDelay(); + + bytes32 salt = _timelockSalt(descriptionHash); + _timelockIds[proposalId] = _timelock.hashOperationBatch(targets, values, calldatas, 0, salt); + _timelock.scheduleBatch(targets, values, calldatas, 0, salt, delay); + + return SafeCast.toUint48(block.timestamp + delay); + } + + /** + * @dev Overridden version of the {Governor-_executeOperations} function that runs the already queued proposal + * through the timelock. + */ + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override { + // execute + _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, _timelockSalt(descriptionHash)); + // cleanup for refund + delete _timelockIds[proposalId]; + } + + /** + * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it has already + * been queued. + */ + // This function can reenter through the external call to the timelock, but we assume the timelock is trusted and + // well behaved (according to TimelockController) and this will not happen. + // slither-disable-next-line reentrancy-no-eth + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + bytes32 timelockId = _timelockIds[proposalId]; + if (timelockId != 0) { + // cancel + _timelock.cancel(timelockId); + // cleanup + delete _timelockIds[proposalId]; + } + + return proposalId; + } + + /** + * @dev Address through which the governor executes action. In this case, the timelock. + */ + function _executor() internal view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates + * must be proposed, scheduled, and executed through governance proposals. + * + * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. + */ + function updateTimelock(TimelockController newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(TimelockController newTimelock) private { + emit TimelockChange(address(_timelock), address(newTimelock)); + _timelock = newTimelock; + } + + /** + * @dev Computes the {TimelockController} operation salt. + * + * It is computed with the governor address itself to avoid collisions across governor instances using the + * same timelock. + */ + function _timelockSalt(bytes32 descriptionHash) private view returns (bytes32) { + return bytes20(address(this)) ^ descriptionHash; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorVotes.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorVotes.sol new file mode 100644 index 0000000..ec32ba4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorVotes.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorVotes.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; +import {IVotes} from "../utils/IVotes.sol"; +import {IERC5805} from "../../interfaces/IERC5805.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Time} from "../../utils/types/Time.sol"; + +/** + * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} + * token. + */ +abstract contract GovernorVotes is Governor { + IERC5805 private immutable _token; + + constructor(IVotes tokenAddress) { + _token = IERC5805(address(tokenAddress)); + } + + /** + * @dev The token that voting power is sourced from. + */ + function token() public view virtual returns (IERC5805) { + return _token; + } + + /** + * @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 Time.blockNumber(); + } + } + + /** + * @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 timepoint, + bytes memory /*params*/ + ) internal view virtual override returns (uint256) { + return token().getPastVotes(account, timepoint); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorVotesQuorumFraction.sol new file mode 100644 index 0000000..85a1f98 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorVotesQuorumFraction.sol) + +pragma solidity ^0.8.20; + +import {GovernorVotes} from "./GovernorVotes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; + +/** + * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a + * fraction of the total supply. + */ +abstract contract GovernorVotesQuorumFraction is GovernorVotes { + using Checkpoints for Checkpoints.Trace208; + + Checkpoints.Trace208 private _quorumNumeratorHistory; + + event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator); + + /** + * @dev The quorum set is not a valid fraction. + */ + error GovernorInvalidQuorumFraction(uint256 quorumNumerator, uint256 quorumDenominator); + + /** + * @dev Initialize quorum as a fraction of the token's total supply. + * + * The fraction is specified as `numerator / denominator`. By default the denominator is 100, so quorum is + * specified as a percent: a numerator of 10 corresponds to quorum being 10% of total supply. The denominator can be + * customized by overriding {quorumDenominator}. + */ + constructor(uint256 quorumNumeratorValue) { + _updateQuorumNumerator(quorumNumeratorValue); + } + + /** + * @dev Returns the current quorum numerator. See {quorumDenominator}. + */ + function quorumNumerator() public view virtual returns (uint256) { + return _quorumNumeratorHistory.latest(); + } + + /** + * @dev Returns the quorum numerator at a specific timepoint. See {quorumDenominator}. + */ + function quorumNumerator(uint256 timepoint) public view virtual returns (uint256) { + uint256 length = _quorumNumeratorHistory._checkpoints.length; + + // Optimistic search, check the latest checkpoint + Checkpoints.Checkpoint208 storage latest = _quorumNumeratorHistory._checkpoints[length - 1]; + uint48 latestKey = latest._key; + uint208 latestValue = latest._value; + if (latestKey <= timepoint) { + return latestValue; + } + + // Otherwise, do the binary search + return _quorumNumeratorHistory.upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @dev Returns the quorum denominator. Defaults to 100, but may be overridden. + */ + function quorumDenominator() public view virtual returns (uint256) { + return 100; + } + + /** + * @dev Returns the quorum for a timepoint, in terms of number of votes: `supply * numerator / denominator`. + */ + function quorum(uint256 timepoint) public view virtual override returns (uint256) { + return (token().getPastTotalSupply(timepoint) * quorumNumerator(timepoint)) / quorumDenominator(); + } + + /** + * @dev Changes the quorum numerator. + * + * Emits a {QuorumNumeratorUpdated} event. + * + * Requirements: + * + * - Must be called through a governance proposal. + * - New numerator must be smaller or equal to the denominator. + */ + function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance { + _updateQuorumNumerator(newQuorumNumerator); + } + + /** + * @dev Changes the quorum numerator. + * + * Emits a {QuorumNumeratorUpdated} event. + * + * Requirements: + * + * - New numerator must be smaller or equal to the denominator. + */ + function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual { + uint256 denominator = quorumDenominator(); + if (newQuorumNumerator > denominator) { + revert GovernorInvalidQuorumFraction(newQuorumNumerator, denominator); + } + + uint256 oldQuorumNumerator = quorumNumerator(); + _quorumNumeratorHistory.push(clock(), SafeCast.toUint208(newQuorumNumerator)); + + emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/utils/IVotes.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/utils/IVotes.sol new file mode 100644 index 0000000..7ba012e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/utils/IVotes.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol) +pragma solidity ^0.8.20; + +/** + * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. + */ +interface IVotes { + /** + * @dev The signature used has expired. + */ + error VotesExpiredSignature(uint256 expiry); + + /** + * @dev Emitted when an account changes their delegate. + */ + event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); + + /** + * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units. + */ + event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes); + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) external view returns (uint256); + + /** + * @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 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 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 + * vote. + */ + function getPastTotalSupply(uint256 timepoint) external view returns (uint256); + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) external view returns (address); + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) external; + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/governance/utils/Votes.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/utils/Votes.sol new file mode 100644 index 0000000..9f96676 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/governance/utils/Votes.sol @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/Votes.sol) +pragma solidity ^0.8.20; + +import {IERC5805} from "../../interfaces/IERC5805.sol"; +import {Context} from "../../utils/Context.sol"; +import {Nonces} from "../../utils/Nonces.sol"; +import {EIP712} from "../../utils/cryptography/EIP712.sol"; +import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {ECDSA} from "../../utils/cryptography/ECDSA.sol"; +import {Time} from "../../utils/types/Time.sol"; + +/** + * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be + * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of + * "representative" that will pool delegated voting units from different accounts and can then use it to vote in + * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to + * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative. + * + * This contract is often combined with a token contract such that voting units correspond to token units. For an + * example, see {ERC721Votes}. + * + * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed + * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the + * cost of this history tracking optional. + * + * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return + * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the + * previous example, it would be included in {ERC721-_update}). + */ +abstract contract Votes is Context, EIP712, Nonces, IERC5805 { + using Checkpoints for Checkpoints.Trace208; + + bytes32 private constant DELEGATION_TYPEHASH = + keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); + + mapping(address account => address) private _delegatee; + + mapping(address delegatee => Checkpoints.Trace208) private _delegateCheckpoints; + + Checkpoints.Trace208 private _totalCheckpoints; + + /** + * @dev The clock was incorrectly modified. + */ + error ERC6372InconsistentClock(); + + /** + * @dev Lookup to future votes is not available. + */ + error ERC5805FutureLookup(uint256 timepoint, uint48 clock); + + /** + * @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 returns (uint48) { + return Time.blockNumber(); + } + + /** + * @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 returns (string memory) { + // Check that the clock was not modified + if (clock() != Time.blockNumber()) { + revert ERC6372InconsistentClock(); + } + return "mode=blocknumber&from=default"; + } + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) public view virtual returns (uint256) { + return _delegateCheckpoints[account].latest(); + } + + /** + * @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 at the end of the corresponding block. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastVotes(address account, uint256 timepoint) public view virtual returns (uint256) { + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) { + revert ERC5805FutureLookup(timepoint, currentTimepoint); + } + return _delegateCheckpoints[account].upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @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 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 + * vote. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) { + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) { + revert ERC5805FutureLookup(timepoint, currentTimepoint); + } + return _totalCheckpoints.upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @dev Returns the current total supply of votes. + */ + function _getTotalSupply() internal view virtual returns (uint256) { + return _totalCheckpoints.latest(); + } + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) public view virtual returns (address) { + return _delegatee[account]; + } + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) public virtual { + address account = _msgSender(); + _delegate(account, delegatee); + } + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig( + address delegatee, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + if (block.timestamp > expiry) { + revert VotesExpiredSignature(expiry); + } + address signer = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))), + v, + r, + s + ); + _useCheckedNonce(signer, nonce); + _delegate(signer, delegatee); + } + + /** + * @dev Delegate all of `account`'s voting units to `delegatee`. + * + * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. + */ + function _delegate(address account, address delegatee) internal virtual { + address oldDelegate = delegates(account); + _delegatee[account] = delegatee; + + emit DelegateChanged(account, oldDelegate, delegatee); + _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account)); + } + + /** + * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to` + * should be zero. Total supply of voting units will be adjusted with mints and burns. + */ + function _transferVotingUnits(address from, address to, uint256 amount) internal virtual { + if (from == address(0)) { + _push(_totalCheckpoints, _add, SafeCast.toUint208(amount)); + } + if (to == address(0)) { + _push(_totalCheckpoints, _subtract, SafeCast.toUint208(amount)); + } + _moveDelegateVotes(delegates(from), delegates(to), amount); + } + + /** + * @dev Moves delegated votes from one delegate to another. + */ + function _moveDelegateVotes(address from, address to, uint256 amount) private { + if (from != to && amount > 0) { + if (from != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[from], + _subtract, + SafeCast.toUint208(amount) + ); + emit DelegateVotesChanged(from, oldValue, newValue); + } + if (to != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[to], + _add, + SafeCast.toUint208(amount) + ); + emit DelegateVotesChanged(to, oldValue, newValue); + } + } + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function _numCheckpoints(address account) internal view virtual returns (uint32) { + return SafeCast.toUint32(_delegateCheckpoints[account].length()); + } + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function _checkpoints( + address account, + uint32 pos + ) internal view virtual returns (Checkpoints.Checkpoint208 memory) { + return _delegateCheckpoints[account].at(pos); + } + + function _push( + Checkpoints.Trace208 storage store, + function(uint208, uint208) view returns (uint208) op, + uint208 delta + ) private returns (uint208, uint208) { + return store.push(clock(), op(store.latest(), delta)); + } + + function _add(uint208 a, uint208 b) private pure returns (uint208) { + return a + b; + } + + function _subtract(uint208 a, uint208 b) private pure returns (uint208) { + return a - b; + } + + /** + * @dev Must return the voting units held by an account. + */ + function _getVotingUnits(address) internal view virtual returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155.sol new file mode 100644 index 0000000..bb502b1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1155.sol) + +pragma solidity ^0.8.20; + +import {IERC1155} from "../token/ERC1155/IERC1155.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155MetadataURI.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155MetadataURI.sol new file mode 100644 index 0000000..dac0bab --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155MetadataURI.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1155MetadataURI.sol) + +pragma solidity ^0.8.20; + +import {IERC1155MetadataURI} from "../token/ERC1155/extensions/IERC1155MetadataURI.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155Receiver.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155Receiver.sol new file mode 100644 index 0000000..6bb7c96 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1155Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1155Receiver.sol) + +pragma solidity ^0.8.20; + +import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1271.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1271.sol new file mode 100644 index 0000000..a56057b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1271.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC1271 standard signature validation method for + * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. + */ +interface IERC1271 { + /** + * @dev Should return whether the signature provided is valid for the provided data + * @param hash Hash of the data to be signed + * @param signature Signature byte array associated with _data + */ + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363.sol new file mode 100644 index 0000000..8b02aba --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "./IERC20.sol"; +import {IERC165} from "./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. + * 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)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) + */ + + /** + * @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 amount uint256 The amount of tokens to be transferred + * @return true unless throwing + */ + 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 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 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 amount uint256 The amount of tokens to be transferred + * @return true unless throwing + */ + 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 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 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 amount uint256 The amount of tokens to be spent + */ + 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 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 amount, bytes memory data) external returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363Receiver.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363Receiver.sol new file mode 100644 index 0000000..64d669d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363Receiver.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363Receiver.sol) + +pragma solidity ^0.8.20; + +/** + * @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. + * 0x88a7ca5c === bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)")) + */ + + /** + * @notice Handle the receipt of ERC1363 tokens + * @dev Any ERC1363 smart contract calls this function on the recipient + * after a `transfer` or a `transferFrom`. This function MAY throw to revert and reject the + * transfer. Return of other than the magic value MUST result in the + * transaction being reverted. + * 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 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 + */ + function onTransferReceived( + address operator, + address from, + uint256 amount, + bytes memory data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363Spender.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363Spender.sol new file mode 100644 index 0000000..f221541 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1363Spender.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363Spender.sol) + +pragma solidity ^0.8.20; + +/** + * @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. + * 0x7b04a2d0 === bytes4(keccak256("onApprovalReceived(address,uint256,bytes)")) + */ + + /** + * @notice Handle the approval of ERC1363 tokens + * @dev Any ERC1363 smart contract calls this function on the recipient + * after an `approve`. This function MAY throw to revert and reject the + * approval. Return of other than the magic value MUST result in the + * transaction being reverted. + * Note: the token contract address is always the message sender. + * @param owner address The address which called `approveAndCall` function + * @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 + */ + function onApprovalReceived(address owner, uint256 amount, bytes memory data) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC165.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC165.sol new file mode 100644 index 0000000..944dd0d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC165.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../utils/introspection/IERC165.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1820Implementer.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1820Implementer.sol new file mode 100644 index 0000000..38e8a4e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1820Implementer.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1820Implementer.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface for an ERC1820 implementer, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[EIP]. + * Used by contracts that will be registered as implementers in the + * {IERC1820Registry}. + */ +interface IERC1820Implementer { + /** + * @dev Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract + * implements `interfaceHash` for `account`. + * + * See {IERC1820Registry-setInterfaceImplementer}. + */ + function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1820Registry.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1820Registry.sol new file mode 100644 index 0000000..bf0140a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1820Registry.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1820Registry.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the global ERC1820 Registry, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register + * implementers for interfaces in this registry, as well as query support. + * + * Implementers may be shared by multiple accounts, and can also implement more + * than a single interface for each account. Contracts can implement interfaces + * for themselves, but externally-owned accounts (EOA) must delegate this to a + * contract. + * + * {IERC165} interfaces can also be queried via the registry. + * + * For an in-depth explanation and source code analysis, see the EIP text. + */ +interface IERC1820Registry { + event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer); + + event ManagerChanged(address indexed account, address indexed newManager); + + /** + * @dev Sets `newManager` as the manager for `account`. A manager of an + * account is able to set interface implementers for it. + * + * By default, each account is its own manager. Passing a value of `0x0` in + * `newManager` will reset the manager to this initial state. + * + * Emits a {ManagerChanged} event. + * + * Requirements: + * + * - the caller must be the current manager for `account`. + */ + function setManager(address account, address newManager) external; + + /** + * @dev Returns the manager for `account`. + * + * See {setManager}. + */ + function getManager(address account) external view returns (address); + + /** + * @dev Sets the `implementer` contract as ``account``'s implementer for + * `interfaceHash`. + * + * `account` being the zero address is an alias for the caller's address. + * The zero address can also be used in `implementer` to remove an old one. + * + * See {interfaceHash} to learn how these are created. + * + * Emits an {InterfaceImplementerSet} event. + * + * Requirements: + * + * - the caller must be the current manager for `account`. + * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not + * end in 28 zeroes). + * - `implementer` must implement {IERC1820Implementer} and return true when + * queried for support, unless `implementer` is the caller. See + * {IERC1820Implementer-canImplementInterfaceForAddress}. + */ + function setInterfaceImplementer(address account, bytes32 _interfaceHash, address implementer) external; + + /** + * @dev Returns the implementer of `interfaceHash` for `account`. If no such + * implementer is registered, returns the zero address. + * + * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28 + * zeroes), `account` will be queried for support of it. + * + * `account` being the zero address is an alias for the caller's address. + */ + function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address); + + /** + * @dev Returns the interface hash for an `interfaceName`, as defined in the + * corresponding + * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP]. + */ + function interfaceHash(string calldata interfaceName) external pure returns (bytes32); + + /** + * @notice Updates the cache with whether the contract implements an ERC165 interface or not. + * @param account Address of the contract for which to update the cache. + * @param interfaceId ERC165 interface for which to update the cache. + */ + function updateERC165Cache(address account, bytes4 interfaceId) external; + + /** + * @notice Checks whether a contract implements an ERC165 interface or not. + * If the result is not cached a direct lookup on the contract address is performed. + * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling + * {updateERC165Cache} with the contract address. + * @param account Address of the contract to check. + * @param interfaceId ERC165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); + + /** + * @notice Checks whether a contract implements an ERC165 interface or not without using or updating the cache. + * @param account Address of the contract to check. + * @param interfaceId ERC165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1967.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1967.sol new file mode 100644 index 0000000..d285ec8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC1967.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) + +pragma solidity ^0.8.20; + +/** + * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. + */ +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/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC20.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC20.sol new file mode 100644 index 0000000..21d5a41 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC20.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../token/ERC20/IERC20.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC20Metadata.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC20Metadata.sol new file mode 100644 index 0000000..b7bc691 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC20Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2309.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2309.sol new file mode 100644 index 0000000..aa00f34 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2309.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2309.sol) + +pragma solidity ^0.8.20; + +/** + * @dev ERC-2309: ERC-721 Consecutive Transfer Extension. + */ +interface IERC2309 { + /** + * @dev Emitted when the tokens from `fromTokenId` to `toTokenId` are transferred from `fromAddress` to `toAddress`. + */ + event ConsecutiveTransfer( + uint256 indexed fromTokenId, + uint256 toTokenId, + address indexed fromAddress, + address indexed toAddress + ); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2612.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2612.sol new file mode 100644 index 0000000..c0427bb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2612.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2612.sol) + +pragma solidity ^0.8.20; + +import {IERC20Permit} from "../token/ERC20/extensions/IERC20Permit.sol"; + +interface IERC2612 is IERC20Permit {} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2981.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2981.sol new file mode 100644 index 0000000..9e7871d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC2981.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2981.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../utils/introspection/IERC165.sol"; + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156.sol new file mode 100644 index 0000000..0f48bf3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156.sol) + +pragma solidity ^0.8.20; + +import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "./IERC3156FlashLender.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156FlashBorrower.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156FlashBorrower.sol new file mode 100644 index 0000000..53e17ea --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156FlashBorrower.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156FlashBorrower.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC3156 FlashBorrower, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + */ +interface IERC3156FlashBorrower { + /** + * @dev Receive a flash loan. + * @param initiator The initiator of the loan. + * @param token The loan currency. + * @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 "ERC3156FlashBorrower.onFlashLoan" + */ + function onFlashLoan( + address initiator, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) external returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156FlashLender.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156FlashLender.sol new file mode 100644 index 0000000..cfae3c0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC3156FlashLender.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156FlashLender.sol) + +pragma solidity ^0.8.20; + +import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; + +/** + * @dev Interface of the ERC3156 FlashLender, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + */ +interface IERC3156FlashLender { + /** + * @dev The amount of currency available to be lended. + * @param token The loan currency. + * @return The amount of `token` that can be borrowed. + */ + function maxFlashLoan(address token) external view returns (uint256); + + /** + * @dev The fee to be charged for a given loan. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @return The amount of `token` to be charged for the loan, on top of the returned principal. + */ + function flashFee(address token, uint256 amount) external view returns (uint256); + + /** + * @dev Initiate a flash loan. + * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @param data Arbitrary data structure, intended to contain user-defined parameters. + */ + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 amount, + bytes calldata data + ) external returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC4626.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC4626.sol new file mode 100644 index 0000000..cfff53b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC4626.sol @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; + +/** + * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in + * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. + */ +interface IERC4626 is IERC20, IERC20Metadata { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, + address indexed receiver, + address indexed owner, + uint256 assets, + uint256 shares + ); + + /** + * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + * + * - MUST be an ERC-20 token contract. + * - MUST NOT revert. + */ + function asset() external view returns (address assetTokenAddress); + + /** + * @dev Returns the total amount of the underlying asset that is “managed” by Vault. + * + * - SHOULD include any compounding that occurs from yield. + * - MUST be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT revert. + */ + function totalAssets() external view returns (uint256 totalManagedAssets); + + /** + * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + * scenario where all the conditions are met. + * + * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + * - MUST NOT revert. + * + * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + * from. + */ + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + * scenario where all the conditions are met. + * + * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + * - MUST NOT revert. + * + * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + * from. + */ + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + * through a deposit call. + * + * - MUST return a limited value if receiver is subject to some deposit limit. + * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + * - MUST NOT revert. + */ + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + * current on-chain conditions. + * + * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + * in the same transaction. + * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + * deposit would be accepted, regardless if the user has enough tokens approved, etc. + * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by depositing. + */ + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + * + * - MUST emit the Deposit event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * deposit execution, and are accounted for during deposit. + * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + * approving enough underlying tokens to the Vault contract, etc). + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + */ + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /** + * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + * - MUST return a limited value if receiver is subject to some mint limit. + * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + * - MUST NOT revert. + */ + function maxMint(address receiver) external view returns (uint256 maxShares); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + * current on-chain conditions. + * + * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + * same transaction. + * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + * would be accepted, regardless if the user has enough tokens approved, etc. + * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by minting. + */ + function previewMint(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + * + * - MUST emit the Deposit event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + * execution, and are accounted for during mint. + * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + * approving enough underlying tokens to the Vault contract, etc). + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + */ + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /** + * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + * Vault, through a withdraw call. + * + * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + * - MUST NOT revert. + */ + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + * given current on-chain conditions. + * + * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + * called + * in the same transaction. + * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + * the withdrawal would be accepted, regardless if the user has enough shares, etc. + * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by depositing. + */ + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. + * + * - MUST emit the Withdraw event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * withdraw execution, and are accounted for during withdraw. + * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + * not having enough shares, etc). + * + * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + * Those methods should be performed separately. + */ + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /** + * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + * through a redeem call. + * + * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + * - MUST NOT revert. + */ + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + * given current on-chain conditions. + * + * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + * same transaction. + * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + * redemption would be accepted, regardless if the user has enough shares, etc. + * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by redeeming. + */ + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. + * + * - MUST emit the Withdraw event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * redeem execution, and are accounted for during redeem. + * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + * not having enough shares, etc). + * + * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + * Those methods should be performed separately. + */ + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC4906.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC4906.sol new file mode 100644 index 0000000..bc008e3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC4906.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "./IERC165.sol"; +import {IERC721} from "./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/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5267.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5267.sol new file mode 100644 index 0000000..47a9fd5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5267.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) + +pragma solidity ^0.8.20; + +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/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5313.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5313.sol new file mode 100644 index 0000000..62f8d75 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5313.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5313.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface for the Light Contract Ownership Standard. + * + * A standardized minimal interface required to identify an account that controls a contract + */ +interface IERC5313 { + /** + * @dev Gets the address of the owner. + */ + function owner() external view returns (address); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5805.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5805.sol new file mode 100644 index 0000000..a89e22d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC5805.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol) + +pragma solidity ^0.8.20; + +import {IVotes} from "../governance/utils/IVotes.sol"; +import {IERC6372} from "./IERC6372.sol"; + +interface IERC5805 is IERC6372, IVotes {} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC6372.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC6372.sol new file mode 100644 index 0000000..7d2ea4a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC6372.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol) + +pragma solidity ^0.8.20; + +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/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721.sol new file mode 100644 index 0000000..0ea735b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "../token/ERC721/IERC721.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Enumerable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Enumerable.sol new file mode 100644 index 0000000..d83a056 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Enumerable.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Enumerable.sol) + +pragma solidity ^0.8.20; + +import {IERC721Enumerable} from "../token/ERC721/extensions/IERC721Enumerable.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Metadata.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Metadata.sol new file mode 100644 index 0000000..d79dd68 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC721Metadata} from "../token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Receiver.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Receiver.sol new file mode 100644 index 0000000..6b2a5aa --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC721Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Receiver.sol) + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777.sol new file mode 100644 index 0000000..56dfbef --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC777.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC777Token standard as defined in the EIP. + * + * This contract uses the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let + * token holders and recipients react to token movements by using setting implementers + * for the associated interfaces in said registry. See {IERC1820Registry} and + * {IERC1820Implementer}. + */ +interface IERC777 { + /** + * @dev Emitted when `amount` tokens are created by `operator` and assigned to `to`. + * + * Note that some additional user `data` and `operatorData` can be logged in the event. + */ + event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); + + /** + * @dev Emitted when `operator` destroys `amount` tokens from `account`. + * + * Note that some additional user `data` and `operatorData` can be logged in the event. + */ + event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); + + /** + * @dev Emitted when `operator` is made operator for `tokenHolder`. + */ + event AuthorizedOperator(address indexed operator, address indexed tokenHolder); + + /** + * @dev Emitted when `operator` is revoked its operator status for `tokenHolder`. + */ + event RevokedOperator(address indexed operator, address indexed tokenHolder); + + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the smallest part of the token that is not divisible. This + * means all token operations (creation, movement and destruction) must have + * amounts that are a multiple of this number. + * + * For most token contracts, this value will equal 1. + */ + function granularity() external view returns (uint256); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by an account (`owner`). + */ + function balanceOf(address owner) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * If send or receive hooks are registered for the caller and `recipient`, + * the corresponding functions will be called with `data` and empty + * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. + * + * Emits a {Sent} event. + * + * Requirements + * + * - the caller must have at least `amount` tokens. + * - `recipient` cannot be the zero address. + * - if `recipient` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function send(address recipient, uint256 amount, bytes calldata data) external; + + /** + * @dev Destroys `amount` tokens from the caller's account, reducing the + * total supply. + * + * If a send hook is registered for the caller, the corresponding function + * will be called with `data` and empty `operatorData`. See {IERC777Sender}. + * + * Emits a {Burned} event. + * + * Requirements + * + * - the caller must have at least `amount` tokens. + */ + function burn(uint256 amount, bytes calldata data) external; + + /** + * @dev Returns true if an account is an operator of `tokenHolder`. + * Operators can send and burn tokens on behalf of their owners. All + * accounts are their own operator. + * + * See {operatorSend} and {operatorBurn}. + */ + function isOperatorFor(address operator, address tokenHolder) external view returns (bool); + + /** + * @dev Make an account an operator of the caller. + * + * See {isOperatorFor}. + * + * Emits an {AuthorizedOperator} event. + * + * Requirements + * + * - `operator` cannot be calling address. + */ + function authorizeOperator(address operator) external; + + /** + * @dev Revoke an account's operator status for the caller. + * + * See {isOperatorFor} and {defaultOperators}. + * + * Emits a {RevokedOperator} event. + * + * Requirements + * + * - `operator` cannot be calling address. + */ + function revokeOperator(address operator) external; + + /** + * @dev Returns the list of default operators. These accounts are operators + * for all token holders, even if {authorizeOperator} was never called on + * them. + * + * This list is immutable, but individual holders may revoke these via + * {revokeOperator}, in which case {isOperatorFor} will return false. + */ + function defaultOperators() external view returns (address[] memory); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must + * be an operator of `sender`. + * + * If send or receive hooks are registered for `sender` and `recipient`, + * the corresponding functions will be called with `data` and + * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. + * + * Emits a {Sent} event. + * + * Requirements + * + * - `sender` cannot be the zero address. + * - `sender` must have at least `amount` tokens. + * - the caller must be an operator for `sender`. + * - `recipient` cannot be the zero address. + * - if `recipient` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function operatorSend( + address sender, + address recipient, + uint256 amount, + bytes calldata data, + bytes calldata operatorData + ) external; + + /** + * @dev Destroys `amount` tokens from `account`, reducing the total supply. + * The caller must be an operator of `account`. + * + * If a send hook is registered for `account`, the corresponding function + * will be called with `data` and `operatorData`. See {IERC777Sender}. + * + * Emits a {Burned} event. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + * - the caller must be an operator for `account`. + */ + function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external; + + event Sent( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777Recipient.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777Recipient.sol new file mode 100644 index 0000000..6378e14 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777Recipient.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC777Recipient.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. + * + * Accounts can be notified of {IERC777} tokens being sent to them by having a + * contract implement this interface (contract holders can be their own + * implementer) and registering it on the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. + * + * See {IERC1820Registry} and {IERC1820Implementer}. + */ +interface IERC777Recipient { + /** + * @dev Called by an {IERC777} token contract whenever tokens are being + * moved or created into a registered account (`to`). The type of operation + * is conveyed by `from` being the zero address or not. + * + * This call occurs _after_ the token contract's state is updated, so + * {IERC777-balanceOf}, etc., can be used to query the post-operation state. + * + * This function may revert to prevent the operation from being executed. + */ + function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777Sender.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777Sender.sol new file mode 100644 index 0000000..5c0ec0b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/IERC777Sender.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC777Sender.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC777TokensSender standard as defined in the EIP. + * + * {IERC777} Token holders can be notified of operations performed on their + * tokens by having a contract implement this interface (contract holders can be + * their own implementer) and registering it on the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. + * + * See {IERC1820Registry} and {IERC1820Implementer}. + */ +interface IERC777Sender { + /** + * @dev Called by an {IERC777} token contract whenever a registered holder's + * (`from`) tokens are about to be moved or destroyed. The type of operation + * is conveyed by `to` being the zero address or not. + * + * This call occurs _before_ the token contract's state is updated, so + * {IERC777-balanceOf}, etc., can be used to query the pre-operation state. + * + * This function may revert to prevent the operation from being executed. + */ + function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/README.adoc new file mode 100644 index 0000000..379a24a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/README.adoc @@ -0,0 +1,82 @@ += Interfaces + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/interfaces + +== List of standardized interfaces +These interfaces are available as `.sol` files, and also as compiler `.json` ABI files (through the npm package). These +are useful to interact with third party contracts that implement them. + +- {IERC20} +- {IERC20Errors} +- {IERC20Metadata} +- {IERC165} +- {IERC721} +- {IERC721Receiver} +- {IERC721Enumerable} +- {IERC721Metadata} +- {IERC721Errors} +- {IERC777} +- {IERC777Recipient} +- {IERC777Sender} +- {IERC1155} +- {IERC1155Receiver} +- {IERC1155MetadataURI} +- {IERC1155Errors} +- {IERC1271} +- {IERC1363} +- {IERC1363Receiver} +- {IERC1363Spender} +- {IERC1820Implementer} +- {IERC1820Registry} +- {IERC1822Proxiable} +- {IERC2612} +- {IERC2981} +- {IERC3156FlashLender} +- {IERC3156FlashBorrower} +- {IERC4626} +- {IERC4906} +- {IERC5267} +- {IERC5313} +- {IERC5805} +- {IERC6372} + +== Detailed ABI + +{{IERC20Errors}} + +{{IERC721Errors}} + +{{IERC1155Errors}} + +{{IERC1271}} + +{{IERC1363}} + +{{IERC1363Receiver}} + +{{IERC1363Spender}} + +{{IERC1820Implementer}} + +{{IERC1820Registry}} + +{{IERC1822Proxiable}} + +{{IERC2612}} + +{{IERC2981}} + +{{IERC3156FlashLender}} + +{{IERC3156FlashBorrower}} + +{{IERC4626}} + +{{IERC5313}} + +{{IERC5267}} + +{{IERC5805}} + +{{IERC6372}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/draft-IERC1822.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/draft-IERC1822.sol new file mode 100644 index 0000000..4d0f0f8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/draft-IERC1822.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol) + +pragma solidity ^0.8.20; + +/** + * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified + * proxy whose upgrades are fully controlled by the current implementation. + */ +interface IERC1822Proxiable { + /** + * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation + * address. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. + */ + function proxiableUUID() external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/draft-IERC6093.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/draft-IERC6093.sol new file mode 100644 index 0000000..f6990e6 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/interfaces/draft-IERC6093.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) +pragma solidity ^0.8.20; + +/** + * @dev Standard ERC20 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. + */ +interface IERC20Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC20InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC20InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. + * @param spender Address that may be allowed to operate on tokens without being their owner. + * @param allowance Amount of tokens a `spender` is allowed to operate with. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC20InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `spender` to be approved. Used in approvals. + * @param spender Address that may be allowed to operate on tokens without being their owner. + */ + error ERC20InvalidSpender(address spender); +} + +/** + * @dev Standard ERC721 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. + */ +interface IERC721Errors { + /** + * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. + * Used in balance queries. + * @param owner Address of the current owner of a token. + */ + error ERC721InvalidOwner(address owner); + + /** + * @dev Indicates a `tokenId` whose `owner` is the zero address. + * @param tokenId Identifier number of a token. + */ + error ERC721NonexistentToken(uint256 tokenId); + + /** + * @dev Indicates an error related to the ownership over a particular token. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param tokenId Identifier number of a token. + * @param owner Address of the current owner of a token. + */ + error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC721InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC721InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`’s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param tokenId Identifier number of a token. + */ + error ERC721InsufficientApproval(address operator, uint256 tokenId); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC721InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC721InvalidOperator(address operator); +} + +/** + * @dev Standard ERC1155 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. + */ +interface IERC1155Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + * @param tokenId Identifier number of a token. + */ + error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC1155InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC1155InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`’s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param owner Address of the current owner of a token. + */ + error ERC1155MissingApprovalForAll(address operator, address owner); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC1155InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC1155InvalidOperator(address operator); + + /** + * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. + * Used in batch transfers. + * @param idsLength Length of the array of token identifiers + * @param valuesLength Length of the array of token amounts + */ + error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/ERC2771Context.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/ERC2771Context.sol new file mode 100644 index 0000000..ab9546b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/ERC2771Context.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (metatx/ERC2771Context.sol) + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +/** + * @dev Context variant with ERC2771 support. + * + * WARNING: Avoid using this pattern in contracts that rely in a specific calldata length as they'll + * be affected by any forwarder whose `msg.data` is suffixed with the `from` address according to the ERC2771 + * specification adding the address size in bytes (20) to the calldata size. An example of an unexpected + * behavior could be an unintended fallback (or another function) invocation while trying to invoke the `receive` + * function only accessible if `msg.data.length == 0`. + */ +abstract contract ERC2771Context is Context { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _trustedForwarder; + + /** + * @dev Initializes the contract with a trusted forwarder, which will be able to + * invoke functions on this contract on behalf of other accounts. + * + * NOTE: The trusted forwarder can be replaced by overriding {trustedForwarder}. + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address trustedForwarder_) { + _trustedForwarder = trustedForwarder_; + } + + /** + * @dev Returns the address of the trusted forwarder. + */ + function trustedForwarder() public view virtual returns (address) { + return _trustedForwarder; + } + + /** + * @dev Indicates whether any particular address is the trusted forwarder. + */ + function isTrustedForwarder(address forwarder) public view virtual returns (bool) { + return forwarder == trustedForwarder(); + } + + /** + * @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever + * a call is not performed by the trusted forwarder or the calldata length is less than + * 20 bytes (an address length). + */ + function _msgSender() internal view virtual override returns (address sender) { + if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { + // The assembly code is more direct than the Solidity version using `abi.decode`. + /// @solidity memory-safe-assembly + assembly { + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + } else { + return super._msgSender(); + } + } + + /** + * @dev Override for `msg.data`. Defaults to the original `msg.data` whenever + * a call is not performed by the trusted forwarder or the calldata length is less than + * 20 bytes (an address length). + */ + function _msgData() internal view virtual override returns (bytes calldata) { + if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { + return msg.data[:msg.data.length - 20]; + } else { + return super._msgData(); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/ERC2771Forwarder.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/ERC2771Forwarder.sol new file mode 100644 index 0000000..4815c1a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/ERC2771Forwarder.sol @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (metatx/ERC2771Forwarder.sol) + +pragma solidity ^0.8.20; + +import {ERC2771Context} from "./ERC2771Context.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; +import {Nonces} from "../utils/Nonces.sol"; +import {Address} from "../utils/Address.sol"; + +/** + * @dev A forwarder compatible with ERC2771 contracts. See {ERC2771Context}. + * + * This forwarder operates on forward requests that include: + * + * * `from`: An address to operate on behalf of. It is required to be equal to the request signer. + * * `to`: The address that should be called. + * * `value`: The amount of native token to attach with the requested call. + * * `gas`: The amount of gas limit that will be forwarded with the requested call. + * * `nonce`: A unique transaction ordering identifier to avoid replayability and request invalidation. + * * `deadline`: A timestamp after which the request is not executable anymore. + * * `data`: Encoded `msg.data` to send with the requested call. + * + * Relayers are able to submit batches if they are processing a high volume of requests. With high + * throughput, relayers may run into limitations of the chain such as limits on the number of + * transactions in the mempool. In these cases the recommendation is to distribute the load among + * multiple accounts. + * + * NOTE: Batching requests includes an optional refund for unused `msg.value` that is achieved by + * performing a call with empty calldata. While this is within the bounds of ERC-2771 compliance, + * if the refund receiver happens to consider the forwarder a trusted forwarder, it MUST properly + * handle `msg.data.length == 0`. `ERC2771Context` in OpenZeppelin Contracts versions prior to 4.9.3 + * do not handle this properly. + * + * ==== Security Considerations + * + * If a relayer submits a forward request, it should be willing to pay up to 100% of the gas amount + * specified in the request. This contract does not implement any kind of retribution for this gas, + * and it is assumed that there is an out of band incentive for relayers to pay for execution on + * behalf of signers. Often, the relayer is operated by a project that will consider it a user + * acquisition cost. + * + * By offering to pay for gas, relayers are at risk of having that gas used by an attacker toward + * some other purpose that is not aligned with the expected out of band incentives. If you operate a + * relayer, consider whitelisting target contracts and function selectors. When relaying ERC-721 or + * ERC-1155 transfers specifically, consider rejecting the use of the `data` field, since it can be + * used to execute arbitrary code. + */ +contract ERC2771Forwarder is EIP712, Nonces { + using ECDSA for bytes32; + + struct ForwardRequestData { + address from; + address to; + uint256 value; + uint256 gas; + uint48 deadline; + bytes data; + bytes signature; + } + + bytes32 internal constant _FORWARD_REQUEST_TYPEHASH = + keccak256( + "ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,uint48 deadline,bytes data)" + ); + + /** + * @dev Emitted when a `ForwardRequest` is executed. + * + * NOTE: An unsuccessful forward request could be due to an invalid signature, an expired deadline, + * or simply a revert in the requested call. The contract guarantees that the relayer is not able to force + * the requested call to run out of gas. + */ + event ExecutedForwardRequest(address indexed signer, uint256 nonce, bool success); + + /** + * @dev The request `from` doesn't match with the recovered `signer`. + */ + error ERC2771ForwarderInvalidSigner(address signer, address from); + + /** + * @dev The `requestedValue` doesn't match with the available `msgValue`. + */ + error ERC2771ForwarderMismatchedValue(uint256 requestedValue, uint256 msgValue); + + /** + * @dev The request `deadline` has expired. + */ + error ERC2771ForwarderExpiredRequest(uint48 deadline); + + /** + * @dev The request target doesn't trust the `forwarder`. + */ + error ERC2771UntrustfulTarget(address target, address forwarder); + + /** + * @dev See {EIP712-constructor}. + */ + constructor(string memory name) EIP712(name, "1") {} + + /** + * @dev Returns `true` if a request is valid for a provided `signature` at the current block timestamp. + * + * A transaction is considered valid when the target trusts this forwarder, the request hasn't expired + * (deadline is not met), and the signer matches the `from` parameter of the signed request. + * + * NOTE: A request may return false here but it won't cause {executeBatch} to revert if a refund + * receiver is provided. + */ + function verify(ForwardRequestData calldata request) public view virtual returns (bool) { + (bool isTrustedForwarder, bool active, bool signerMatch, ) = _validate(request); + return isTrustedForwarder && active && signerMatch; + } + + /** + * @dev Executes a `request` on behalf of `signature`'s signer using the ERC-2771 protocol. The gas + * provided to the requested call may not be exactly the amount requested, but the call will not run + * out of gas. Will revert if the request is invalid or the call reverts, in this case the nonce is not consumed. + * + * Requirements: + * + * - The request value should be equal to the provided `msg.value`. + * - The request should be valid according to {verify}. + */ + function execute(ForwardRequestData calldata request) public payable virtual { + // We make sure that msg.value and request.value match exactly. + // If the request is invalid or the call reverts, this whole function + // will revert, ensuring value isn't stuck. + if (msg.value != request.value) { + revert ERC2771ForwarderMismatchedValue(request.value, msg.value); + } + + if (!_execute(request, true)) { + revert Address.FailedInnerCall(); + } + } + + /** + * @dev Batch version of {execute} with optional refunding and atomic execution. + * + * In case a batch contains at least one invalid request (see {verify}), the + * request will be skipped and the `refundReceiver` parameter will receive back the + * unused requested value at the end of the execution. This is done to prevent reverting + * the entire batch when a request is invalid or has already been submitted. + * + * If the `refundReceiver` is the `address(0)`, this function will revert when at least + * one of the requests was not valid instead of skipping it. This could be useful if + * a batch is required to get executed atomically (at least at the top-level). For example, + * refunding (and thus atomicity) can be opt-out if the relayer is using a service that avoids + * including reverted transactions. + * + * Requirements: + * + * - The sum of the requests' values should be equal to the provided `msg.value`. + * - All of the requests should be valid (see {verify}) when `refundReceiver` is the zero address. + * + * NOTE: Setting a zero `refundReceiver` guarantees an all-or-nothing requests execution only for + * the first-level forwarded calls. In case a forwarded request calls to a contract with another + * subcall, the second-level call may revert without the top-level call reverting. + */ + function executeBatch( + ForwardRequestData[] calldata requests, + address payable refundReceiver + ) public payable virtual { + bool atomic = refundReceiver == address(0); + + uint256 requestsValue; + uint256 refundValue; + + for (uint256 i; i < requests.length; ++i) { + requestsValue += requests[i].value; + bool success = _execute(requests[i], atomic); + if (!success) { + refundValue += requests[i].value; + } + } + + // The batch should revert if there's a mismatched msg.value provided + // to avoid request value tampering + if (requestsValue != msg.value) { + revert ERC2771ForwarderMismatchedValue(requestsValue, msg.value); + } + + // Some requests with value were invalid (possibly due to frontrunning). + // To avoid leaving ETH in the contract this value is refunded. + if (refundValue != 0) { + // We know refundReceiver != address(0) && requestsValue == msg.value + // meaning we can ensure refundValue is not taken from the original contract's balance + // and refundReceiver is a known account. + Address.sendValue(refundReceiver, refundValue); + } + } + + /** + * @dev Validates if the provided request can be executed at current block timestamp with + * the given `request.signature` on behalf of `request.signer`. + */ + function _validate( + ForwardRequestData calldata request + ) internal view virtual returns (bool isTrustedForwarder, bool active, bool signerMatch, address signer) { + (bool isValid, address recovered) = _recoverForwardRequestSigner(request); + + return ( + _isTrustedByTarget(request.to), + request.deadline >= block.timestamp, + isValid && recovered == request.from, + recovered + ); + } + + /** + * @dev Returns a tuple with the recovered the signer of an EIP712 forward request message hash + * and a boolean indicating if the signature is valid. + * + * NOTE: The signature is considered valid if {ECDSA-tryRecover} indicates no recover error for it. + */ + function _recoverForwardRequestSigner( + ForwardRequestData calldata request + ) internal view virtual returns (bool, address) { + (address recovered, ECDSA.RecoverError err, ) = _hashTypedDataV4( + keccak256( + abi.encode( + _FORWARD_REQUEST_TYPEHASH, + request.from, + request.to, + request.value, + request.gas, + nonces(request.from), + request.deadline, + keccak256(request.data) + ) + ) + ).tryRecover(request.signature); + + return (err == ECDSA.RecoverError.NoError, recovered); + } + + /** + * @dev Validates and executes a signed request returning the request call `success` value. + * + * Internal function without msg.value validation. + * + * Requirements: + * + * - The caller must have provided enough gas to forward with the call. + * - The request must be valid (see {verify}) if the `requireValidRequest` is true. + * + * Emits an {ExecutedForwardRequest} event. + * + * IMPORTANT: Using this function doesn't check that all the `msg.value` was sent, potentially + * leaving value stuck in the contract. + */ + function _execute( + ForwardRequestData calldata request, + bool requireValidRequest + ) internal virtual returns (bool success) { + (bool isTrustedForwarder, bool active, bool signerMatch, address signer) = _validate(request); + + // Need to explicitly specify if a revert is required since non-reverting is default for + // batches and reversion is opt-in since it could be useful in some scenarios + if (requireValidRequest) { + if (!isTrustedForwarder) { + revert ERC2771UntrustfulTarget(request.to, address(this)); + } + + if (!active) { + revert ERC2771ForwarderExpiredRequest(request.deadline); + } + + if (!signerMatch) { + revert ERC2771ForwarderInvalidSigner(signer, request.from); + } + } + + // Ignore an invalid request because requireValidRequest = false + if (isTrustedForwarder && signerMatch && active) { + // Nonce should be used before the call to prevent reusing by reentrancy + uint256 currentNonce = _useNonce(signer); + + uint256 reqGas = request.gas; + address to = request.to; + uint256 value = request.value; + bytes memory data = abi.encodePacked(request.data, request.from); + + uint256 gasLeft; + + assembly { + success := call(reqGas, to, value, add(data, 0x20), mload(data), 0, 0) + gasLeft := gas() + } + + _checkForwardedGas(gasLeft, request); + + emit ExecutedForwardRequest(signer, currentNonce, success); + } + } + + /** + * @dev Returns whether the target trusts this forwarder. + * + * This function performs a static call to the target contract calling the + * {ERC2771Context-isTrustedForwarder} function. + */ + function _isTrustedByTarget(address target) private view returns (bool) { + bytes memory encodedParams = abi.encodeCall(ERC2771Context.isTrustedForwarder, (address(this))); + + bool success; + uint256 returnSize; + uint256 returnValue; + /// @solidity memory-safe-assembly + assembly { + // Perform the staticcal and save the result in the scratch space. + // | Location | Content | Content (Hex) | + // |-----------|----------|--------------------------------------------------------------------| + // | | | result ↓ | + // | 0x00:0x1F | selector | 0x0000000000000000000000000000000000000000000000000000000000000001 | + success := staticcall(gas(), target, add(encodedParams, 0x20), mload(encodedParams), 0, 0x20) + returnSize := returndatasize() + returnValue := mload(0) + } + + return success && returnSize >= 0x20 && returnValue > 0; + } + + /** + * @dev Checks if the requested gas was correctly forwarded to the callee. + * + * As a consequence of https://eips.ethereum.org/EIPS/eip-150[EIP-150]: + * - At most `gasleft() - floor(gasleft() / 64)` is forwarded to the callee. + * - At least `floor(gasleft() / 64)` is kept in the caller. + * + * It reverts consuming all the available gas if the forwarded gas is not the requested gas. + * + * IMPORTANT: The `gasLeft` parameter should be measured exactly at the end of the forwarded call. + * Any gas consumed in between will make room for bypassing this check. + */ + function _checkForwardedGas(uint256 gasLeft, ForwardRequestData calldata request) private pure { + // To avoid insufficient gas griefing attacks, as referenced in https://ronan.eth.limo/blog/ethereum-gas-dangers/ + // + // A malicious relayer can attempt to shrink the gas forwarded so that the underlying call reverts out-of-gas + // but the forwarding itself still succeeds. In order to make sure that the subcall received sufficient gas, + // we will inspect gasleft() after the forwarding. + // + // Let X be the gas available before the subcall, such that the subcall gets at most X * 63 / 64. + // We can't know X after CALL dynamic costs, but we want it to be such that X * 63 / 64 >= req.gas. + // Let Y be the gas used in the subcall. gasleft() measured immediately after the subcall will be gasleft() = X - Y. + // If the subcall ran out of gas, then Y = X * 63 / 64 and gasleft() = X - Y = X / 64. + // Under this assumption req.gas / 63 > gasleft() is true is true if and only if + // req.gas / 63 > X / 64, or equivalently req.gas > X * 63 / 64. + // This means that if the subcall runs out of gas we are able to detect that insufficient gas was passed. + // + // We will now also see that req.gas / 63 > gasleft() implies that req.gas >= X * 63 / 64. + // The contract guarantees Y <= req.gas, thus gasleft() = X - Y >= X - req.gas. + // - req.gas / 63 > gasleft() + // - req.gas / 63 >= X - req.gas + // - req.gas >= X * 63 / 64 + // In other words if req.gas < X * 63 / 64 then req.gas / 63 <= gasleft(), thus if the relayer behaves honestly + // the forwarding does not revert. + if (gasLeft < request.gas / 63) { + // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since + // neither revert or assert consume all gas since Solidity 0.8.20 + // https://docs.soliditylang.org/en/v0.8.20/control-structures.html#panic-via-assert-and-error-via-require + /// @solidity memory-safe-assembly + assembly { + invalid() + } + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/README.adoc new file mode 100644 index 0000000..9f25802 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/metatx/README.adoc @@ -0,0 +1,12 @@ += Meta Transactions + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx + +== Core + +{{ERC2771Context}} + +== Utils + +{{ERC2771Forwarder}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/AccessManagedTarget.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/AccessManagedTarget.sol new file mode 100644 index 0000000..673feed --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/AccessManagedTarget.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {AccessManaged} from "../access/manager/AccessManaged.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; + +abstract contract AccessManagedTarget is AccessManaged { + event CalledRestricted(address caller); + event CalledUnrestricted(address caller); + event CalledFallback(address caller); + + function fnRestricted() public restricted { + emit CalledRestricted(msg.sender); + } + + function fnUnrestricted() public { + emit CalledUnrestricted(msg.sender); + } + + function setIsConsumingScheduledOp(bool isConsuming, bytes32 slot) external { + // Memory layout is 0x....<_consumingSchedule (boolean)> + bytes32 mask = bytes32(uint256(1 << 160)); + if (isConsuming) { + StorageSlot.getBytes32Slot(slot).value |= mask; + } else { + StorageSlot.getBytes32Slot(slot).value &= ~mask; + } + } + + fallback() external { + emit CalledFallback(msg.sender); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ArraysMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ArraysMock.sol new file mode 100644 index 0000000..a00def2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ArraysMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Arrays} from "../utils/Arrays.sol"; + +contract Uint256ArraysMock { + using Arrays for uint256[]; + + uint256[] private _array; + + constructor(uint256[] memory array) { + _array = array; + } + + function findUpperBound(uint256 element) external view returns (uint256) { + return _array.findUpperBound(element); + } + + function unsafeAccess(uint256 pos) external view returns (uint256) { + return _array.unsafeAccess(pos).value; + } +} + +contract AddressArraysMock { + using Arrays for address[]; + + address[] private _array; + + constructor(address[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (address) { + return _array.unsafeAccess(pos).value; + } +} + +contract Bytes32ArraysMock { + using Arrays for bytes32[]; + + bytes32[] private _array; + + constructor(bytes32[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (bytes32) { + return _array.unsafeAccess(pos).value; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/AuthorityMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/AuthorityMock.sol new file mode 100644 index 0000000..bf2434b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/AuthorityMock.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IAccessManaged} from "../access/manager/IAccessManaged.sol"; +import {IAuthority} from "../access/manager/IAuthority.sol"; + +contract NotAuthorityMock is IAuthority { + function canCall(address /* caller */, address /* target */, bytes4 /* selector */) external pure returns (bool) { + revert("AuthorityNoDelayMock: not implemented"); + } +} + +contract AuthorityNoDelayMock is IAuthority { + bool _immediate; + + function canCall( + address /* caller */, + address /* target */, + bytes4 /* selector */ + ) external view returns (bool immediate) { + return _immediate; + } + + function _setImmediate(bool immediate) external { + _immediate = immediate; + } +} + +contract AuthorityDelayMock { + bool _immediate; + uint32 _delay; + + function canCall( + address /* caller */, + address /* target */, + bytes4 /* selector */ + ) external view returns (bool immediate, uint32 delay) { + return (_immediate, _delay); + } + + function _setImmediate(bool immediate) external { + _immediate = immediate; + } + + function _setDelay(uint32 delay) external { + _delay = delay; + } +} + +contract AuthorityNoResponse { + function canCall(address /* caller */, address /* target */, bytes4 /* selector */) external view {} +} + +contract AuthoritiyObserveIsConsuming { + event ConsumeScheduledOpCalled(address caller, bytes data, bytes4 isConsuming); + + function canCall( + address /* caller */, + address /* target */, + bytes4 /* selector */ + ) external pure returns (bool immediate, uint32 delay) { + return (false, 1); + } + + function consumeScheduledOp(address caller, bytes memory data) public { + emit ConsumeScheduledOpCalled(caller, data, IAccessManaged(msg.sender).isConsumingScheduledOp()); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/CallReceiverMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/CallReceiverMock.sol new file mode 100644 index 0000000..e371c7d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/CallReceiverMock.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract CallReceiverMock { + event MockFunctionCalled(); + event MockFunctionCalledWithArgs(uint256 a, uint256 b); + + uint256[] private _array; + + function mockFunction() public payable returns (string memory) { + emit MockFunctionCalled(); + + return "0x1234"; + } + + function mockFunctionEmptyReturn() public payable { + emit MockFunctionCalled(); + } + + function mockFunctionWithArgs(uint256 a, uint256 b) public payable returns (string memory) { + emit MockFunctionCalledWithArgs(a, b); + + return "0x1234"; + } + + function mockFunctionNonPayable() public returns (string memory) { + emit MockFunctionCalled(); + + return "0x1234"; + } + + function mockStaticFunction() public pure returns (string memory) { + return "0x1234"; + } + + function mockFunctionRevertsNoReason() public payable { + revert(); + } + + function mockFunctionRevertsReason() public payable { + revert("CallReceiverMock: reverting"); + } + + function mockFunctionThrows() public payable { + assert(false); + } + + function mockFunctionOutOfGas() public payable { + for (uint256 i = 0; ; ++i) { + _array.push(i); + } + } + + function mockFunctionWritesStorage(bytes32 slot, bytes32 value) public returns (string memory) { + assembly { + sstore(slot, value) + } + return "0x1234"; + } +} + +contract CallReceiverMockTrustingForwarder is CallReceiverMock { + address private _trustedForwarder; + + constructor(address trustedForwarder_) { + _trustedForwarder = trustedForwarder_; + } + + function isTrustedForwarder(address forwarder) public view virtual returns (bool) { + return forwarder == _trustedForwarder; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ContextMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ContextMock.sol new file mode 100644 index 0000000..199b2a9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ContextMock.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +contract ContextMock is Context { + event Sender(address sender); + + function msgSender() public { + emit Sender(_msgSender()); + } + + event Data(bytes data, uint256 integerValue, string stringValue); + + function msgData(uint256 integerValue, string memory stringValue) public { + emit Data(_msgData(), integerValue, stringValue); + } + + event DataShort(bytes data); + + function msgDataShort() public { + emit DataShort(_msgData()); + } +} + +contract ContextMockCaller { + function callSender(ContextMock context) public { + context.msgSender(); + } + + function callData(ContextMock context, uint256 integerValue, string memory stringValue) public { + context.msgData(integerValue, stringValue); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/DummyImplementation.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/DummyImplementation.sol new file mode 100644 index 0000000..4925c89 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/DummyImplementation.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; + +abstract contract Impl { + function version() public pure virtual returns (string memory); +} + +contract DummyImplementation { + uint256 public value; + string public text; + uint256[] public values; + + function initializeNonPayable() public { + value = 10; + } + + function initializePayable() public payable { + value = 100; + } + + function initializeNonPayableWithValue(uint256 _value) public { + value = _value; + } + + function initializePayableWithValue(uint256 _value) public payable { + value = _value; + } + + function initialize(uint256 _value, string memory _text, uint256[] memory _values) public { + value = _value; + text = _text; + values = _values; + } + + function get() public pure returns (bool) { + return true; + } + + function version() public pure virtual returns (string memory) { + return "V1"; + } + + function reverts() public pure { + require(false, "DummyImplementation reverted"); + } + + // Use for forcing an unsafe TransparentUpgradeableProxy admin override + function unsafeOverrideAdmin(address newAdmin) public { + StorageSlot.getAddressSlot(ERC1967Utils.ADMIN_SLOT).value = newAdmin; + } +} + +contract DummyImplementationV2 is DummyImplementation { + function migrate(uint256 newVal) public payable { + value = newVal; + } + + function version() public pure override returns (string memory) { + return "V2"; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/EIP712Verifier.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/EIP712Verifier.sol new file mode 100644 index 0000000..fe32a21 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/EIP712Verifier.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; + +abstract contract EIP712Verifier is EIP712 { + function verify(bytes memory signature, address signer, address mailTo, string memory mailContents) external view { + bytes32 digest = _hashTypedDataV4( + keccak256(abi.encode(keccak256("Mail(address to,string contents)"), mailTo, keccak256(bytes(mailContents)))) + ); + address recoveredSigner = ECDSA.recover(digest, signature); + require(recoveredSigner == signer); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC1271WalletMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC1271WalletMock.sol new file mode 100644 index 0000000..cba7d47 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC1271WalletMock.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Ownable} from "../access/Ownable.sol"; +import {IERC1271} from "../interfaces/IERC1271.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; + +contract ERC1271WalletMock is Ownable, IERC1271 { + constructor(address originalOwner) Ownable(originalOwner) {} + + function isValidSignature(bytes32 hash, bytes memory signature) public view returns (bytes4 magicValue) { + return ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0); + } +} + +contract ERC1271MaliciousMock is IERC1271 { + function isValidSignature(bytes32, bytes memory) public pure returns (bytes4) { + assembly { + mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0, 32) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165InterfacesSupported.sol new file mode 100644 index 0000000..4010b21 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165InterfacesSupported.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * https://eips.ethereum.org/EIPS/eip-214#specification + * From the specification: + * > Any attempts to make state-changing operations inside an execution instance with STATIC set to true will instead + * throw an exception. + * > These operations include [...], LOG0, LOG1, LOG2, [...] + * + * therefore, because this contract is staticcall'd we need to not emit events (which is how solidity-coverage works) + * solidity-coverage ignores the /mocks folder, so we duplicate its implementation here to avoid instrumenting it + */ +contract SupportsInterfaceWithLookupMock is IERC165 { + /* + * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 + */ + bytes4 public constant INTERFACE_ID_ERC165 = 0x01ffc9a7; + + /** + * @dev A mapping of interface id to whether or not it's supported. + */ + mapping(bytes4 interfaceId => bool) private _supportedInterfaces; + + /** + * @dev A contract implementing SupportsInterfaceWithLookup + * implement ERC165 itself. + */ + constructor() { + _registerInterface(INTERFACE_ID_ERC165); + } + + /** + * @dev Implement supportsInterface(bytes4) using a lookup table. + */ + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + return _supportedInterfaces[interfaceId]; + } + + /** + * @dev Private method for registering an interface. + */ + function _registerInterface(bytes4 interfaceId) internal { + require(interfaceId != 0xffffffff, "ERC165InterfacesSupported: invalid interface id"); + _supportedInterfaces[interfaceId] = true; + } +} + +contract ERC165InterfacesSupported is SupportsInterfaceWithLookupMock { + constructor(bytes4[] memory interfaceIds) { + for (uint256 i = 0; i < interfaceIds.length; i++) { + _registerInterface(interfaceIds[i]); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165MaliciousData.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165MaliciousData.sol new file mode 100644 index 0000000..3542756 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165MaliciousData.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ERC165MaliciousData { + function supportsInterface(bytes4) public pure returns (bool) { + assembly { + mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0, 32) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165MissingData.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165MissingData.sol new file mode 100644 index 0000000..fec4339 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165MissingData.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ERC165MissingData { + function supportsInterface(bytes4 interfaceId) public view {} // missing return +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165NotSupported.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165NotSupported.sol new file mode 100644 index 0000000..78ef9c8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165NotSupported.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ERC165NotSupported {} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165ReturnBomb.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165ReturnBomb.sol new file mode 100644 index 0000000..4bfacfd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC165/ERC165ReturnBomb.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +contract ERC165ReturnBombMock is IERC165 { + function supportsInterface(bytes4 interfaceId) public pure override returns (bool) { + if (interfaceId == type(IERC165).interfaceId) { + assembly { + mstore(0, 1) + } + } + assembly { + return(0, 101500) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC2771ContextMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC2771ContextMock.sol new file mode 100644 index 0000000..22b9203 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC2771ContextMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ContextMock} from "./ContextMock.sol"; +import {Context} from "../utils/Context.sol"; +import {ERC2771Context} from "../metatx/ERC2771Context.sol"; + +// By inheriting from ERC2771Context, Context's internal functions are overridden automatically +contract ERC2771ContextMock is ContextMock, ERC2771Context { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address trustedForwarder) ERC2771Context(trustedForwarder) { + emit Sender(_msgSender()); // _msgSender() should be accessible during construction + } + + function _msgSender() internal view override(Context, ERC2771Context) returns (address) { + return ERC2771Context._msgSender(); + } + + function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) { + return ERC2771Context._msgData(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC3156FlashBorrowerMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC3156FlashBorrowerMock.sol new file mode 100644 index 0000000..261fea1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ERC3156FlashBorrowerMock.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {IERC3156FlashBorrower} from "../interfaces/IERC3156.sol"; +import {Address} from "../utils/Address.sol"; + +/** + * @dev WARNING: this IERC3156FlashBorrower mock implementation is for testing purposes ONLY. + * Writing a secure flash lock borrower is not an easy task, and should be done with the utmost care. + * This is not an example of how it should be done, and no pattern present in this mock should be considered secure. + * Following best practices, always have your contract properly audited before using them to manipulate important funds on + * live networks. + */ +contract ERC3156FlashBorrowerMock is IERC3156FlashBorrower { + bytes32 internal constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + bool immutable _enableApprove; + bool immutable _enableReturn; + + event BalanceOf(address token, address account, uint256 value); + event TotalSupply(address token, uint256 value); + + constructor(bool enableReturn, bool enableApprove) { + _enableApprove = enableApprove; + _enableReturn = enableReturn; + } + + function onFlashLoan( + address /*initiator*/, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) public returns (bytes32) { + require(msg.sender == token); + + emit BalanceOf(token, address(this), IERC20(token).balanceOf(address(this))); + emit TotalSupply(token, IERC20(token).totalSupply()); + + if (data.length > 0) { + // WARNING: This code is for testing purposes only! Do not use. + Address.functionCall(token, data); + } + + if (_enableApprove) { + IERC20(token).approve(token, amount + fee); + } + + return _enableReturn ? _RETURN_VALUE : bytes32(0); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/EtherReceiverMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/EtherReceiverMock.sol new file mode 100644 index 0000000..1b1c936 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/EtherReceiverMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract EtherReceiverMock { + bool private _acceptEther; + + function setAcceptEther(bool acceptEther) public { + _acceptEther = acceptEther; + } + + receive() external payable { + if (!_acceptEther) { + revert(); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/InitializableMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/InitializableMock.sol new file mode 100644 index 0000000..7f76caa --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/InitializableMock.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "../proxy/utils/Initializable.sol"; + +/** + * @title InitializableMock + * @dev This contract is a mock to test initializable functionality + */ +contract InitializableMock is Initializable { + bool public initializerRan; + bool public onlyInitializingRan; + uint256 public x; + + function isInitializing() public view returns (bool) { + return _isInitializing(); + } + + function initialize() public initializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyInitializing { + onlyInitializingRan = true; + } + + function initializerNested() public initializer { + initialize(); + } + + function onlyInitializingNested() public initializer { + initializeOnlyInitializing(); + } + + function initializeWithX(uint256 _x) public payable initializer { + x = _x; + } + + function nonInitializable(uint256 _x) public payable { + x = _x; + } + + function fail() public pure { + require(false, "InitializableMock forced failure"); + } +} + +contract ConstructorInitializableMock is Initializable { + bool public initializerRan; + bool public onlyInitializingRan; + + constructor() initializer { + initialize(); + initializeOnlyInitializing(); + } + + function initialize() public initializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyInitializing { + onlyInitializingRan = true; + } +} + +contract ChildConstructorInitializableMock is ConstructorInitializableMock { + bool public childInitializerRan; + + constructor() initializer { + childInitialize(); + } + + function childInitialize() public initializer { + childInitializerRan = true; + } +} + +contract ReinitializerMock is Initializable { + uint256 public counter; + + function getInitializedVersion() public view returns (uint64) { + return _getInitializedVersion(); + } + + function initialize() public initializer { + doStuff(); + } + + function reinitialize(uint64 i) public reinitializer(i) { + doStuff(); + } + + function nestedReinitialize(uint64 i, uint64 j) public reinitializer(i) { + reinitialize(j); + } + + function chainReinitialize(uint64 i, uint64 j) public { + reinitialize(i); + reinitialize(j); + } + + function disableInitializers() public { + _disableInitializers(); + } + + function doStuff() public onlyInitializing { + counter++; + } +} + +contract DisableNew is Initializable { + constructor() { + _disableInitializers(); + } +} + +contract DisableOld is Initializable { + constructor() initializer {} +} + +contract DisableBad1 is DisableNew, DisableOld {} + +contract DisableBad2 is Initializable { + constructor() initializer { + _disableInitializers(); + } +} + +contract DisableOk is DisableOld, DisableNew {} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/MulticallTest.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/MulticallTest.sol new file mode 100644 index 0000000..74be7d8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/MulticallTest.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20MulticallMock} from "./token/ERC20MulticallMock.sol"; + +contract MulticallTest { + function checkReturnValues( + ERC20MulticallMock multicallToken, + address[] calldata recipients, + uint256[] calldata amounts + ) external { + bytes[] memory calls = new bytes[](recipients.length); + for (uint256 i = 0; i < recipients.length; i++) { + calls[i] = abi.encodeCall(multicallToken.transfer, (recipients[i], amounts[i])); + } + + bytes[] memory results = multicallToken.multicall(calls); + for (uint256 i = 0; i < results.length; i++) { + require(abi.decode(results[i], (bool))); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/MultipleInheritanceInitializableMocks.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/MultipleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..51030ac --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/MultipleInheritanceInitializableMocks.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "../proxy/utils/Initializable.sol"; + +// Sample contracts showing upgradeability with multiple inheritance. +// Child contract inherits from Father and Mother contracts, and Father extends from Gramps. +// +// Human +// / \ +// | Gramps +// | | +// Mother Father +// | | +// -- Child -- + +/** + * Sample base initializable contract that is a human + */ +contract SampleHuman is Initializable { + bool public isHuman; + + function initialize() public initializer { + __SampleHuman_init(); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleHuman_init() internal onlyInitializing { + __SampleHuman_init_unchained(); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleHuman_init_unchained() internal onlyInitializing { + isHuman = true; + } +} + +/** + * Sample base initializable contract that defines a field mother + */ +contract SampleMother is Initializable, SampleHuman { + uint256 public mother; + + function initialize(uint256 value) public initializer { + __SampleMother_init(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleMother_init(uint256 value) internal onlyInitializing { + __SampleHuman_init(); + __SampleMother_init_unchained(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleMother_init_unchained(uint256 value) internal onlyInitializing { + mother = value; + } +} + +/** + * Sample base initializable contract that defines a field gramps + */ +contract SampleGramps is Initializable, SampleHuman { + string public gramps; + + function initialize(string memory value) public initializer { + __SampleGramps_init(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleGramps_init(string memory value) internal onlyInitializing { + __SampleHuman_init(); + __SampleGramps_init_unchained(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleGramps_init_unchained(string memory value) internal onlyInitializing { + gramps = value; + } +} + +/** + * Sample base initializable contract that defines a field father and extends from gramps + */ +contract SampleFather is Initializable, SampleGramps { + uint256 public father; + + function initialize(string memory _gramps, uint256 _father) public initializer { + __SampleFather_init(_gramps, _father); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleFather_init(string memory _gramps, uint256 _father) internal onlyInitializing { + __SampleGramps_init(_gramps); + __SampleFather_init_unchained(_father); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleFather_init_unchained(uint256 _father) internal onlyInitializing { + father = _father; + } +} + +/** + * Child extends from mother, father (gramps) + */ +contract SampleChild is Initializable, SampleMother, SampleFather { + uint256 public child; + + function initialize(uint256 _mother, string memory _gramps, uint256 _father, uint256 _child) public initializer { + __SampleChild_init(_mother, _gramps, _father, _child); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleChild_init( + uint256 _mother, + string memory _gramps, + uint256 _father, + uint256 _child + ) internal onlyInitializing { + __SampleMother_init(_mother); + __SampleFather_init(_gramps, _father); + __SampleChild_init_unchained(_child); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleChild_init_unchained(uint256 _child) internal onlyInitializing { + child = _child; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/PausableMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/PausableMock.sol new file mode 100644 index 0000000..fa701e2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/PausableMock.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Pausable} from "../utils/Pausable.sol"; + +contract PausableMock is Pausable { + bool public drasticMeasureTaken; + uint256 public count; + + constructor() { + drasticMeasureTaken = false; + count = 0; + } + + function normalProcess() external whenNotPaused { + count++; + } + + function drasticMeasure() external whenPaused { + drasticMeasureTaken = true; + } + + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ReentrancyAttack.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ReentrancyAttack.sol new file mode 100644 index 0000000..3df2d1c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ReentrancyAttack.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +contract ReentrancyAttack is Context { + function callSender(bytes calldata data) public { + (bool success, ) = _msgSender().call(data); + require(success, "ReentrancyAttack: failed call"); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ReentrancyMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ReentrancyMock.sol new file mode 100644 index 0000000..39e2d5e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/ReentrancyMock.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ReentrancyGuard} from "../utils/ReentrancyGuard.sol"; +import {ReentrancyAttack} from "./ReentrancyAttack.sol"; + +contract ReentrancyMock is ReentrancyGuard { + uint256 public counter; + + constructor() { + counter = 0; + } + + function callback() external nonReentrant { + _count(); + } + + function countLocalRecursive(uint256 n) public nonReentrant { + if (n > 0) { + _count(); + countLocalRecursive(n - 1); + } + } + + function countThisRecursive(uint256 n) public nonReentrant { + if (n > 0) { + _count(); + (bool success, ) = address(this).call(abi.encodeCall(this.countThisRecursive, (n - 1))); + require(success, "ReentrancyMock: failed call"); + } + } + + function countAndCall(ReentrancyAttack attacker) public nonReentrant { + _count(); + attacker.callSender(abi.encodeCall(this.callback, ())); + } + + function _count() private { + counter += 1; + } + + function guardedCheckEntered() public nonReentrant { + require(_reentrancyGuardEntered()); + } + + function unguardedCheckNotEntered() public view { + require(!_reentrancyGuardEntered()); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/RegressionImplementation.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/RegressionImplementation.sol new file mode 100644 index 0000000..19b9706 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/RegressionImplementation.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "../proxy/utils/Initializable.sol"; + +contract Implementation1 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } +} + +contract Implementation2 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } +} + +contract Implementation3 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue(uint256 _number) public view returns (uint256) { + return _value + _number; + } +} + +contract Implementation4 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } + + fallback() external { + _value = 1; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/SingleInheritanceInitializableMocks.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/SingleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..0bd3c61 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/SingleInheritanceInitializableMocks.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "../proxy/utils/Initializable.sol"; + +/** + * @title MigratableMockV1 + * @dev This contract is a mock to test initializable functionality through migrations + */ +contract MigratableMockV1 is Initializable { + uint256 public x; + + function initialize(uint256 value) public payable initializer { + x = value; + } +} + +/** + * @title MigratableMockV2 + * @dev This contract is a mock to test migratable functionality with params + */ +contract MigratableMockV2 is MigratableMockV1 { + bool internal _migratedV2; + uint256 public y; + + function migrate(uint256 value, uint256 anotherValue) public payable { + require(!_migratedV2); + x = value; + y = anotherValue; + _migratedV2 = true; + } +} + +/** + * @title MigratableMockV3 + * @dev This contract is a mock to test migratable functionality without params + */ +contract MigratableMockV3 is MigratableMockV2 { + bool internal _migratedV3; + + function migrate() public payable { + require(!_migratedV3); + uint256 oldX = x; + x = y; + y = oldX; + _migratedV3 = true; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/Stateless.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/Stateless.sol new file mode 100644 index 0000000..56f5b4c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/Stateless.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +// We keep these imports and a dummy contract just to we can run the test suite after transpilation. + +import {Address} from "../utils/Address.sol"; +import {Arrays} from "../utils/Arrays.sol"; +import {AuthorityUtils} from "../access/manager/AuthorityUtils.sol"; +import {Base64} from "../utils/Base64.sol"; +import {BitMaps} from "../utils/structs/BitMaps.sol"; +import {Checkpoints} from "../utils/structs/Checkpoints.sol"; +import {Clones} from "../proxy/Clones.sol"; +import {Create2} from "../utils/Create2.sol"; +import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EnumerableMap} from "../utils/structs/EnumerableMap.sol"; +import {EnumerableSet} from "../utils/structs/EnumerableSet.sol"; +import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC165} from "../utils/introspection/ERC165.sol"; +import {ERC165Checker} from "../utils/introspection/ERC165Checker.sol"; +import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol"; +import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol"; +import {Math} from "../utils/math/Math.sol"; +import {MerkleProof} from "../utils/cryptography/MerkleProof.sol"; +import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol"; +import {SafeCast} from "../utils/math/SafeCast.sol"; +import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol"; +import {ShortStrings} from "../utils/ShortStrings.sol"; +import {SignatureChecker} from "../utils/cryptography/SignatureChecker.sol"; +import {SignedMath} from "../utils/math/SignedMath.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; +import {Strings} from "../utils/Strings.sol"; +import {Time} from "../utils/types/Time.sol"; + +contract Dummy1234 {} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/StorageSlotMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/StorageSlotMock.sol new file mode 100644 index 0000000..dbdad7a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/StorageSlotMock.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {StorageSlot} from "../utils/StorageSlot.sol"; + +contract StorageSlotMock { + using StorageSlot for *; + + function setBoolean(bytes32 slot, bool value) public { + slot.getBooleanSlot().value = value; + } + + function setAddress(bytes32 slot, address value) public { + slot.getAddressSlot().value = value; + } + + function setBytes32(bytes32 slot, bytes32 value) public { + slot.getBytes32Slot().value = value; + } + + function setUint256(bytes32 slot, uint256 value) public { + slot.getUint256Slot().value = value; + } + + function getBoolean(bytes32 slot) public view returns (bool) { + return slot.getBooleanSlot().value; + } + + function getAddress(bytes32 slot) public view returns (address) { + return slot.getAddressSlot().value; + } + + function getBytes32(bytes32 slot) public view returns (bytes32) { + return slot.getBytes32Slot().value; + } + + function getUint256(bytes32 slot) public view returns (uint256) { + return slot.getUint256Slot().value; + } + + mapping(uint256 key => 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 key => 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/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/TimelockReentrant.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/TimelockReentrant.sol new file mode 100644 index 0000000..aab676a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/TimelockReentrant.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Address} from "../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/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/UpgradeableBeaconMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/UpgradeableBeaconMock.sol new file mode 100644 index 0000000..354ac02 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/UpgradeableBeaconMock.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IBeacon} from "../proxy/beacon/IBeacon.sol"; + +contract UpgradeableBeaconMock is IBeacon { + address public implementation; + + constructor(address impl) { + implementation = impl; + } +} + +interface IProxyExposed { + // solhint-disable-next-line func-name-mixedcase + function $getBeacon() external view returns (address); +} + +contract UpgradeableBeaconReentrantMock is IBeacon { + error BeaconProxyBeaconSlotAddress(address beacon); + + function implementation() external view override returns (address) { + // Revert with the beacon seen in the proxy at the moment of calling to check if it's + // set before the call. + revert BeaconProxyBeaconSlotAddress(IProxyExposed(msg.sender).$getBeacon()); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/VotesMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/VotesMock.sol new file mode 100644 index 0000000..e28d6b5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/VotesMock.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Votes} from "../governance/utils/Votes.sol"; + +abstract contract VotesMock is Votes { + mapping(address voter => uint256) private _votingUnits; + + function getTotalSupply() public view returns (uint256) { + return _getTotalSupply(); + } + + function delegate(address account, address newDelegation) public { + return _delegate(account, newDelegation); + } + + function _getVotingUnits(address account) internal view override returns (uint256) { + return _votingUnits[account]; + } + + function _mint(address account, uint256 votes) internal { + _votingUnits[account] += votes; + _transferVotingUnits(address(0), account, votes); + } + + function _burn(address account, uint256 votes) internal { + _votingUnits[account] += votes; + _transferVotingUnits(account, address(0), votes); + } +} + +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/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/compound/CompTimelock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/compound/CompTimelock.sol new file mode 100644 index 0000000..c72ed08 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/compound/CompTimelock.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: BSD-3-Clause +// solhint-disable private-vars-leading-underscore +/** + * Copyright 2020 Compound Labs, Inc. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +pragma solidity ^0.8.20; + +contract CompTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + + uint256 public constant GRACE_PERIOD = 14 days; + uint256 public constant MINIMUM_DELAY = 2 days; + uint256 public constant MAXIMUM_DELAY = 30 days; + + address public admin; + address public pendingAdmin; + uint256 public delay; + + mapping(bytes32 => bool) public queuedTransactions; + + constructor(address admin_, uint256 delay_) { + require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay."); + require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); + + admin = admin_; + delay = delay_; + } + + receive() external payable {} + + function setDelay(uint256 delay_) public { + require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock."); + require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay."); + require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); + delay = delay_; + + emit NewDelay(delay); + } + + function acceptAdmin() public { + require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin."); + admin = msg.sender; + pendingAdmin = address(0); + + emit NewAdmin(admin); + } + + function setPendingAdmin(address pendingAdmin_) public { + require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock."); + pendingAdmin = pendingAdmin_; + + emit NewPendingAdmin(pendingAdmin); + } + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public returns (bytes32) { + require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin."); + require( + eta >= getBlockTimestamp() + delay, + "Timelock::queueTransaction: Estimated execution block must satisfy delay." + ); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + queuedTransactions[txHash] = true; + + emit QueueTransaction(txHash, target, value, signature, data, eta); + return txHash; + } + + function cancelTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public { + require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin."); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + queuedTransactions[txHash] = false; + + emit CancelTransaction(txHash, target, value, signature, data, eta); + } + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public payable returns (bytes memory) { + require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin."); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued."); + require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock."); + require(getBlockTimestamp() <= eta + GRACE_PERIOD, "Timelock::executeTransaction: Transaction is stale."); + + queuedTransactions[txHash] = false; + + bytes memory callData; + + if (bytes(signature).length == 0) { + callData = data; + } else { + callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data); + } + + // solium-disable-next-line security/no-call-value + (bool success, bytes memory returnData) = target.call{value: value}(callData); + require(success, "Timelock::executeTransaction: Transaction execution reverted."); + + emit ExecuteTransaction(txHash, target, value, signature, data, eta); + + return returnData; + } + + function getBlockTimestamp() internal view returns (uint256) { + // solium-disable-next-line security/no-block-members + return block.timestamp; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorMock.sol new file mode 100644 index 0000000..69668d2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorMock.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorMock is GovernorSettings, GovernorVotesQuorumFraction, GovernorCountingSimple { + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol new file mode 100644 index 0000000..fde0863 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorPreventLateQuorum} from "../../governance/extensions/GovernorPreventLateQuorum.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorPreventLateQuorumMock is + GovernorSettings, + GovernorVotes, + GovernorCountingSimple, + GovernorPreventLateQuorum +{ + uint256 private _quorum; + + constructor(uint256 quorum_) { + _quorum = quorum_; + } + + function quorum(uint256) public view override returns (uint256) { + return _quorum; + } + + function proposalDeadline( + uint256 proposalId + ) public view override(Governor, GovernorPreventLateQuorum) returns (uint256) { + return super.proposalDeadline(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal override(Governor, GovernorPreventLateQuorum) returns (uint256) { + return super._castVote(proposalId, account, support, reason, params); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorStorageMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorStorageMock.sol new file mode 100644 index 0000000..88c6bf9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorStorageMock.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockControl} from "../../governance/extensions/GovernorTimelockControl.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import {GovernorStorage} from "../../governance/extensions/GovernorStorage.sol"; + +abstract contract GovernorStorageMock is + GovernorSettings, + GovernorTimelockControl, + GovernorVotesQuorumFraction, + GovernorCountingSimple, + GovernorStorage +{ + function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalNeedsQueuing( + uint256 proposalId + ) public view virtual override(Governor, GovernorTimelockControl) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } + + function _propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description, + address proposer + ) internal virtual override(Governor, GovernorStorage) returns (uint256) { + return super._propose(targets, values, calldatas, description, proposer); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockControl) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockControl) { + super._executeOperations(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(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockAccessMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockAccessMock.sol new file mode 100644 index 0000000..3d1bbee --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockAccessMock.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockAccess} from "../../governance/extensions/GovernorTimelockAccess.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockAccessMock is + GovernorSettings, + GovernorTimelockAccess, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function nonGovernanceFunction() external {} + + function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalNeedsQueuing( + uint256 proposalId + ) public view virtual override(Governor, GovernorTimelockAccess) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } + + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public override(Governor, GovernorTimelockAccess) returns (uint256) { + return super.propose(targets, values, calldatas, description); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockAccess) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockAccess) { + super._executeOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockAccess) returns (uint256) { + return super._cancel(targets, values, calldatas, descriptionHash); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockCompoundMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockCompoundMock.sol new file mode 100644 index 0000000..03ef625 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockCompoundMock.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockCompound} from "../../governance/extensions/GovernorTimelockCompound.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockCompoundMock is + GovernorSettings, + GovernorTimelockCompound, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state( + uint256 proposalId + ) public view override(Governor, GovernorTimelockCompound) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalNeedsQueuing( + uint256 proposalId + ) public view virtual override(Governor, GovernorTimelockCompound) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockCompound) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockCompound) { + super._executeOperations(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(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockControlMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockControlMock.sol new file mode 100644 index 0000000..edaccc0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorTimelockControlMock.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockControl} from "../../governance/extensions/GovernorTimelockControl.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockControlMock is + GovernorSettings, + GovernorTimelockControl, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalNeedsQueuing( + uint256 proposalId + ) public view virtual override(Governor, GovernorTimelockControl) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockControl) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockControl) { + super._executeOperations(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 nonGovernanceFunction() external {} +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorVoteMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorVoteMock.sol new file mode 100644 index 0000000..e6949b5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorVoteMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorVoteMocks is GovernorVotes, GovernorCountingSimple { + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorWithParamsMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorWithParamsMock.sol new file mode 100644 index 0000000..d535f81 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/governance/GovernorWithParamsMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorWithParamsMock is GovernorVotes, GovernorCountingSimple { + event CountParams(uint256 uintParam, string strParam); + + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } + + function _getVotes( + address account, + uint256 blockNumber, + bytes memory params + ) internal view override(Governor, GovernorVotes) returns (uint256) { + uint256 reduction = 0; + // If the user provides parameters, we reduce the voting weight by the amount of the integer param + if (params.length > 0) { + (reduction, ) = abi.decode(params, (uint256, string)); + } + // reverts on overflow + return super._getVotes(account, blockNumber, params) - reduction; + } + + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal override(Governor, GovernorCountingSimple) { + if (params.length > 0) { + (uint256 _uintParam, string memory _strParam) = abi.decode(params, (uint256, string)); + emit CountParams(_uintParam, _strParam); + } + return super._countVote(proposalId, account, support, weight, params); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/BadBeacon.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/BadBeacon.sol new file mode 100644 index 0000000..f3153a8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/BadBeacon.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract BadBeaconNoImpl {} + +contract BadBeaconNotContract { + function implementation() external pure returns (address) { + return address(0x1); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/ClashingImplementation.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/ClashingImplementation.sol new file mode 100644 index 0000000..43d5a34 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/ClashingImplementation.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +/** + * @dev Implementation contract with a payable changeAdmin(address) function made to clash with + * TransparentUpgradeableProxy's to test correct functioning of the Transparent Proxy feature. + */ +contract ClashingImplementation { + event ClashingImplementationCall(); + + function upgradeToAndCall(address, bytes calldata) external payable { + emit ClashingImplementationCall(); + } + + function delegatedFunction() external pure returns (bool) { + return true; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/UUPSUpgradeableMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/UUPSUpgradeableMock.sol new file mode 100644 index 0000000..a5f2d4a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/proxy/UUPSUpgradeableMock.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {UUPSUpgradeable} from "../../proxy/utils/UUPSUpgradeable.sol"; +import {ERC1967Utils} from "../../proxy/ERC1967/ERC1967Utils.sol"; + +contract NonUpgradeableMock { + uint256 internal _counter; + + function current() external view returns (uint256) { + return _counter; + } + + function increment() external { + ++_counter; + } +} + +contract UUPSUpgradeableMock is NonUpgradeableMock, UUPSUpgradeable { + // Not having any checks in this function is dangerous! Do not do this outside tests! + function _authorizeUpgrade(address) internal override {} +} + +contract UUPSUpgradeableUnsafeMock is UUPSUpgradeableMock { + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { + ERC1967Utils.upgradeToAndCall(newImplementation, data); + } +} + +contract UUPSUnsupportedProxiableUUID is UUPSUpgradeableMock { + function proxiableUUID() external pure override returns (bytes32) { + return keccak256("invalid UUID"); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC1155ReceiverMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC1155ReceiverMock.sol new file mode 100644 index 0000000..2a85d1d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC1155ReceiverMock.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC1155Receiver} from "../../token/ERC1155/IERC1155Receiver.sol"; +import {ERC165} from "../../utils/introspection/ERC165.sol"; + +contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { + enum RevertType { + None, + RevertWithoutMessage, + RevertWithMessage, + RevertWithCustomError, + Panic + } + + bytes4 private immutable _recRetval; + bytes4 private immutable _batRetval; + RevertType private immutable _error; + + event Received(address operator, address from, uint256 id, uint256 value, bytes data, uint256 gas); + event BatchReceived(address operator, address from, uint256[] ids, uint256[] values, bytes data, uint256 gas); + error CustomError(bytes4); + + constructor(bytes4 recRetval, bytes4 batRetval, RevertType error) { + _recRetval = recRetval; + _batRetval = batRetval; + _error = error; + } + + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4) { + if (_error == RevertType.RevertWithoutMessage) { + revert(); + } else if (_error == RevertType.RevertWithMessage) { + revert("ERC1155ReceiverMock: reverting on receive"); + } else if (_error == RevertType.RevertWithCustomError) { + revert CustomError(_recRetval); + } else if (_error == RevertType.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + + emit Received(operator, from, id, value, data, gasleft()); + return _recRetval; + } + + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4) { + if (_error == RevertType.RevertWithoutMessage) { + revert(); + } else if (_error == RevertType.RevertWithMessage) { + revert("ERC1155ReceiverMock: reverting on batch receive"); + } else if (_error == RevertType.RevertWithCustomError) { + revert CustomError(_recRetval); + } else if (_error == RevertType.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + + emit BatchReceived(operator, from, ids, values, data, gasleft()); + return _batRetval; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ApprovalMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ApprovalMock.sol new file mode 100644 index 0000000..ff33a36 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ApprovalMock.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20ApprovalMock is ERC20 { + function _approve(address owner, address spender, uint256 amount, bool) internal virtual override { + super._approve(owner, spender, amount, true); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20DecimalsMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20DecimalsMock.sol new file mode 100644 index 0000000..a26e1f5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20DecimalsMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20DecimalsMock is ERC20 { + uint8 private immutable _decimals; + + constructor(uint8 decimals_) { + _decimals = decimals_; + } + + function decimals() public view override returns (uint8) { + return _decimals; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ExcessDecimalsMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ExcessDecimalsMock.sol new file mode 100644 index 0000000..4627efd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ExcessDecimalsMock.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ERC20ExcessDecimalsMock { + function decimals() public pure returns (uint256) { + return type(uint256).max; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20FlashMintMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20FlashMintMock.sol new file mode 100644 index 0000000..508573c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20FlashMintMock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20FlashMint} from "../../token/ERC20/extensions/ERC20FlashMint.sol"; + +abstract contract ERC20FlashMintMock is ERC20FlashMint { + uint256 _flashFeeAmount; + address _flashFeeReceiverAddress; + + function setFlashFee(uint256 amount) public { + _flashFeeAmount = amount; + } + + function _flashFee(address, uint256) internal view override returns (uint256) { + return _flashFeeAmount; + } + + function setFlashFeeReceiver(address receiver) public { + _flashFeeReceiverAddress = receiver; + } + + function _flashFeeReceiver() internal view override returns (address) { + return _flashFeeReceiverAddress; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ForceApproveMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ForceApproveMock.sol new file mode 100644 index 0000000..36c0f57 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ForceApproveMock.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +// contract that replicate USDT (0xdac17f958d2ee523a2206206994597c13d831ec7) approval behavior +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/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20Mock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20Mock.sol new file mode 100644 index 0000000..39ab129 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20Mock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +contract ERC20Mock is ERC20 { + constructor() ERC20("ERC20Mock", "E20M") {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20MulticallMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20MulticallMock.sol new file mode 100644 index 0000000..dce3e70 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20MulticallMock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; +import {Multicall} from "../../utils/Multicall.sol"; + +abstract contract ERC20MulticallMock is ERC20, Multicall {} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20NoReturnMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20NoReturnMock.sol new file mode 100644 index 0000000..2129537 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20NoReturnMock.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20NoReturnMock is ERC20 { + function transfer(address to, uint256 amount) public override returns (bool) { + super.transfer(to, amount); + assembly { + return(0, 0) + } + } + + 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/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20Reentrant.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20Reentrant.sol new file mode 100644 index 0000000..813913f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20Reentrant.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; +import {Address} from "../../utils/Address.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 _update(address from, address to, uint256 amount) internal override { + if (_reenterType == Type.Before) { + _reenterType = Type.No; + functionCall(_reenterTarget, _reenterData); + } + super._update(from, to, amount); + if (_reenterType == Type.After) { + _reenterType = Type.No; + functionCall(_reenterTarget, _reenterData); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ReturnFalseMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ReturnFalseMock.sol new file mode 100644 index 0000000..94bff32 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20ReturnFalseMock.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20ReturnFalseMock is ERC20 { + function transfer(address, uint256) public pure override returns (bool) { + return false; + } + + function transferFrom(address, address, uint256) public pure override returns (bool) { + return false; + } + + function approve(address, uint256) public pure override returns (bool) { + return false; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20VotesLegacyMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20VotesLegacyMock.sol new file mode 100644 index 0000000..3246fd4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC20VotesLegacyMock.sol @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20Permit} from "../../token/ERC20/extensions/ERC20Permit.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {IVotes} from "../../governance/utils/IVotes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {ECDSA} from "../../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 account => address) private _delegatee; + mapping(address delegatee => 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 returns (address) { + return _delegatee[account]; + } + + /** + * @dev Gets the current votes balance for `account` + */ + function getVotes(address account) public view virtual 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 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 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 { + _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 { + 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 Move voting power when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _update(address from, address to, uint256 amount) internal virtual override { + super._update(from, to, amount); + + if (from == address(0)) { + require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes"); + _writeCheckpoint(_totalSupplyCheckpoints, _add, amount); + } + + if (to == address(0)) { + _writeCheckpoint(_totalSupplyCheckpoints, _subtract, 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); + _delegatee[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/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626LimitsMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626LimitsMock.sol new file mode 100644 index 0000000..a845365 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626LimitsMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; + +abstract contract ERC4626LimitsMock is ERC4626 { + uint256 _maxDeposit; + uint256 _maxMint; + + constructor() { + _maxDeposit = 100 ether; + _maxMint = 100 ether; + } + + function maxDeposit(address) public view override returns (uint256) { + return _maxDeposit; + } + + function maxMint(address) public view override returns (uint256) { + return _maxMint; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626Mock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626Mock.sol new file mode 100644 index 0000000..22ac5e8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626Mock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC20, ERC20} from "../../token/ERC20/ERC20.sol"; +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; + +contract ERC4626Mock is ERC4626 { + constructor(address underlying) ERC20("ERC4626Mock", "E4626M") ERC4626(IERC20(underlying)) {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626OffsetMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626OffsetMock.sol new file mode 100644 index 0000000..3dde095 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4626OffsetMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC4626} from "../../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/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4646FeesMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4646FeesMock.sol new file mode 100644 index 0000000..368b078 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC4646FeesMock.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC4626Fees} from "../docs/ERC4626Fees.sol"; + +abstract contract ERC4626FeesMock is ERC4626Fees { + uint256 private immutable _entryFeeBasisPointValue; + address private immutable _entryFeeRecipientValue; + uint256 private immutable _exitFeeBasisPointValue; + address private immutable _exitFeeRecipientValue; + + constructor( + uint256 entryFeeBasisPoints, + address entryFeeRecipient, + uint256 exitFeeBasisPoints, + address exitFeeRecipient + ) { + _entryFeeBasisPointValue = entryFeeBasisPoints; + _entryFeeRecipientValue = entryFeeRecipient; + _exitFeeBasisPointValue = exitFeeBasisPoints; + _exitFeeRecipientValue = exitFeeRecipient; + } + + function _entryFeeBasisPoints() internal view virtual override returns (uint256) { + return _entryFeeBasisPointValue; + } + + function _entryFeeRecipient() internal view virtual override returns (address) { + return _entryFeeRecipientValue; + } + + function _exitFeeBasisPoints() internal view virtual override returns (uint256) { + return _exitFeeBasisPointValue; + } + + function _exitFeeRecipient() internal view virtual override returns (address) { + return _exitFeeRecipientValue; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol new file mode 100644 index 0000000..7732ae4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721} from "../../token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import {ERC721Enumerable} from "../../token/ERC721/extensions/ERC721Enumerable.sol"; + +contract ERC721ConsecutiveEnumerableMock is ERC721Consecutive, ERC721Enumerable { + constructor( + string memory name, + string memory symbol, + address[] memory receivers, + uint96[] memory amounts + ) ERC721(name, symbol) { + for (uint256 i = 0; i < receivers.length; ++i) { + _mintConsecutive(receivers[i], amounts[i]); + } + } + + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC721, ERC721Enumerable) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) { + return super._ownerOf(tokenId); + } + + function _update( + address to, + uint256 tokenId, + address auth + ) internal virtual override(ERC721Consecutive, ERC721Enumerable) returns (address) { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 amount) internal virtual override(ERC721, ERC721Enumerable) { + super._increaseBalance(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ConsecutiveMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ConsecutiveMock.sol new file mode 100644 index 0000000..1098647 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ConsecutiveMock.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721} from "../../token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import {ERC721Pausable} from "../../token/ERC721/extensions/ERC721Pausable.sol"; +import {ERC721Votes} from "../../token/ERC721/extensions/ERC721Votes.sol"; +import {EIP712} from "../../utils/cryptography/EIP712.sol"; + +/** + * @title ERC721ConsecutiveMock + */ +contract ERC721ConsecutiveMock is ERC721Consecutive, ERC721Pausable, ERC721Votes { + uint96 private immutable _offset; + + constructor( + string memory name, + string memory symbol, + uint96 offset, + address[] memory delegates, + address[] memory receivers, + uint96[] memory amounts + ) ERC721(name, symbol) EIP712(name, "1") { + _offset = offset; + + for (uint256 i = 0; i < delegates.length; ++i) { + _delegate(delegates[i], delegates[i]); + } + + for (uint256 i = 0; i < receivers.length; ++i) { + _mintConsecutive(receivers[i], amounts[i]); + } + } + + function _firstConsecutiveId() internal view virtual override returns (uint96) { + return _offset; + } + + function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) { + return super._ownerOf(tokenId); + } + + function _update( + address to, + uint256 tokenId, + address auth + ) internal virtual override(ERC721Consecutive, ERC721Pausable, ERC721Votes) returns (address) { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 amount) internal virtual override(ERC721, ERC721Votes) { + super._increaseBalance(account, amount); + } +} + +contract ERC721ConsecutiveNoConstructorMintMock is ERC721Consecutive { + constructor(string memory name, string memory symbol) ERC721(name, symbol) { + _mint(msg.sender, 0); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ReceiverMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ReceiverMock.sol new file mode 100644 index 0000000..14120f5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721ReceiverMock.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../../token/ERC721/IERC721Receiver.sol"; + +contract ERC721ReceiverMock is IERC721Receiver { + enum RevertType { + None, + RevertWithoutMessage, + RevertWithMessage, + RevertWithCustomError, + Panic + } + + bytes4 private immutable _retval; + RevertType private immutable _error; + + event Received(address operator, address from, uint256 tokenId, bytes data, uint256 gas); + error CustomError(bytes4); + + constructor(bytes4 retval, RevertType error) { + _retval = retval; + _error = error; + } + + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes memory data + ) public returns (bytes4) { + if (_error == RevertType.RevertWithoutMessage) { + revert(); + } else if (_error == RevertType.RevertWithMessage) { + revert("ERC721ReceiverMock: reverting"); + } else if (_error == RevertType.RevertWithCustomError) { + revert CustomError(_retval); + } else if (_error == RevertType.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + + emit Received(operator, from, tokenId, data, gasleft()); + return _retval; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721URIStorageMock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721URIStorageMock.sol new file mode 100644 index 0000000..254435e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/ERC721URIStorageMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721URIStorage} from "../../token/ERC721/extensions/ERC721URIStorage.sol"; + +abstract contract ERC721URIStorageMock is ERC721URIStorage { + string private _baseTokenURI; + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + function setBaseURI(string calldata newBaseTokenURI) public { + _baseTokenURI = newBaseTokenURI; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/VotesTimestamp.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/VotesTimestamp.sol new file mode 100644 index 0000000..78fdfae --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/mocks/token/VotesTimestamp.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20Votes} from "../../token/ERC20/extensions/ERC20Votes.sol"; +import {ERC721Votes} from "../../token/ERC721/extensions/ERC721Votes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.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 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/lib/openzeppelin-contracts-v5.0.0/contracts/package.json b/lib/openzeppelin-contracts-v5.0.0/contracts/package.json new file mode 100644 index 0000000..be3e741 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/package.json @@ -0,0 +1,32 @@ +{ + "name": "@openzeppelin/contracts", + "description": "Secure Smart Contract library for Solidity", + "version": "5.0.0", + "files": [ + "**/*.sol", + "/build/contracts/*.json", + "!/mocks/**/*" + ], + "scripts": { + "prepack": "bash ../scripts/prepack.sh", + "prepare-docs": "cd ..; npm run prepare-docs" + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "security", + "zeppelin" + ], + "author": "OpenZeppelin Community ", + "license": "MIT", + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, + "homepage": "https://openzeppelin.com/contracts/" +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/Clones.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/Clones.sol new file mode 100644 index 0000000..95e467d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/Clones.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol) + +pragma solidity ^0.8.20; + +/** + * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for + * deploying minimal proxy contracts, also known as "clones". + * + * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies + * > a minimal bytecode implementation that delegates all calls to a known, fixed address. + * + * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` + * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the + * deterministic method. + */ +library Clones { + /** + * @dev A clone instance deployment failed. + */ + error ERC1167FailedCreateClone(); + + /** + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. + * + * This function uses the create opcode, which should never revert. + */ + function clone(address implementation) internal returns (address instance) { + /// @solidity memory-safe-assembly + assembly { + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create(0, 0x09, 0x37) + } + if (instance == address(0)) { + revert ERC1167FailedCreateClone(); + } + } + + /** + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. + * + * This function uses the create2 opcode and a `salt` to deterministically deploy + * the clone. Using the same `implementation` and `salt` multiple time will revert, since + * the clones cannot be deployed twice at the same address. + */ + function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { + /// @solidity memory-safe-assembly + assembly { + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create2(0, 0x09, 0x37, salt) + } + if (instance == address(0)) { + revert ERC1167FailedCreateClone(); + } + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt, + address deployer + ) internal pure returns (address predicted) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(add(ptr, 0x38), deployer) + mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) + mstore(add(ptr, 0x14), implementation) + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) + mstore(add(ptr, 0x58), salt) + mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) + predicted := keccak256(add(ptr, 0x43), 0x55) + } + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt + ) internal view returns (address predicted) { + return predictDeterministicAddress(implementation, salt, address(this)); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/ERC1967/ERC1967Proxy.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/ERC1967/ERC1967Proxy.sol new file mode 100644 index 0000000..0fa61b5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/ERC1967/ERC1967Proxy.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol) + +pragma solidity ^0.8.20; + +import {Proxy} from "../Proxy.sol"; +import {ERC1967Utils} from "./ERC1967Utils.sol"; + +/** + * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an + * implementation address that can be changed. This address is stored in storage in the location specified by + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the + * implementation behind the proxy. + */ +contract ERC1967Proxy is Proxy { + /** + * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`. + * + * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an + * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. + * + * Requirements: + * + * - If `data` is empty, `msg.value` must be zero. + */ + constructor(address implementation, bytes memory _data) payable { + ERC1967Utils.upgradeToAndCall(implementation, _data); + } + + /** + * @dev Returns the current implementation address. + * + * 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() internal view virtual override returns (address) { + return ERC1967Utils.getImplementation(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/ERC1967/ERC1967Utils.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/ERC1967/ERC1967Utils.sol new file mode 100644 index 0000000..e55bae2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/ERC1967/ERC1967Utils.sol @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) + +pragma solidity ^0.8.20; + +import {IBeacon} from "../beacon/IBeacon.sol"; +import {Address} from "../../utils/Address.sol"; +import {StorageSlot} from "../../utils/StorageSlot.sol"; + +/** + * @dev This abstract contract provides getters and event emitting update functions for + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. + */ +library ERC1967Utils { + // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. + // This will be fixed in Solidity 0.8.21. At that point we should remove these events. + /** + * @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); + + /** + * @dev Storage slot with the address of the current implementation. + * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. + */ + // solhint-disable-next-line private-vars-leading-underscore + bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + /** + * @dev The `implementation` of the proxy is invalid. + */ + error ERC1967InvalidImplementation(address implementation); + + /** + * @dev The `admin` of the proxy is invalid. + */ + error ERC1967InvalidAdmin(address admin); + + /** + * @dev The `beacon` of the proxy is invalid. + */ + error ERC1967InvalidBeacon(address beacon); + + /** + * @dev An upgrade function sees `msg.value > 0` that may be lost. + */ + error ERC1967NonPayable(); + + /** + * @dev Returns the current implementation address. + */ + function getImplementation() internal view returns (address) { + return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 implementation slot. + */ + function _setImplementation(address newImplementation) private { + if (newImplementation.code.length == 0) { + revert ERC1967InvalidImplementation(newImplementation); + } + StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; + } + + /** + * @dev Performs implementation upgrade with additional setup call if data is nonempty. + * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected + * to avoid stuck value in the contract. + * + * Emits an {IERC1967-Upgraded} event. + */ + function upgradeToAndCall(address newImplementation, bytes memory data) internal { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + + if (data.length > 0) { + Address.functionDelegateCall(newImplementation, data); + } else { + _checkNonPayable(); + } + } + + /** + * @dev Storage slot with the admin of the contract. + * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. + */ + // solhint-disable-next-line private-vars-leading-underscore + bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + /** + * @dev Returns the current admin. + * + * 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 getAdmin() internal view returns (address) { + return StorageSlot.getAddressSlot(ADMIN_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 admin slot. + */ + function _setAdmin(address newAdmin) private { + if (newAdmin == address(0)) { + revert ERC1967InvalidAdmin(address(0)); + } + StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; + } + + /** + * @dev Changes the admin of the proxy. + * + * Emits an {IERC1967-AdminChanged} event. + */ + function changeAdmin(address newAdmin) internal { + emit AdminChanged(getAdmin(), newAdmin); + _setAdmin(newAdmin); + } + + /** + * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. + * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. + */ + // solhint-disable-next-line private-vars-leading-underscore + bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + + /** + * @dev Returns the current beacon. + */ + function getBeacon() internal view returns (address) { + return StorageSlot.getAddressSlot(BEACON_SLOT).value; + } + + /** + * @dev Stores a new beacon in the EIP1967 beacon slot. + */ + function _setBeacon(address newBeacon) private { + if (newBeacon.code.length == 0) { + revert ERC1967InvalidBeacon(newBeacon); + } + + StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; + + address beaconImplementation = IBeacon(newBeacon).implementation(); + if (beaconImplementation.code.length == 0) { + revert ERC1967InvalidImplementation(beaconImplementation); + } + } + + /** + * @dev Change the beacon and trigger a setup call if data is nonempty. + * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected + * to avoid stuck value in the contract. + * + * Emits an {IERC1967-BeaconUpgraded} event. + * + * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since + * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for + * efficiency. + */ + function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { + _setBeacon(newBeacon); + emit BeaconUpgraded(newBeacon); + + if (data.length > 0) { + Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); + } else { + _checkNonPayable(); + } + } + + /** + * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract + * if an upgrade doesn't perform an initialization call. + */ + function _checkNonPayable() private { + if (msg.value > 0) { + revert ERC1967NonPayable(); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/Proxy.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/Proxy.sol new file mode 100644 index 0000000..0e73651 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/Proxy.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol) + +pragma solidity ^0.8.20; + +/** + * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM + * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to + * be specified by overriding the virtual {_implementation} function. + * + * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a + * different contract through the {_delegate} function. + * + * The success and return data of the delegated call will be returned back to the caller of the proxy. + */ +abstract contract Proxy { + /** + * @dev Delegates the current call to `implementation`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _delegate(address implementation) internal virtual { + assembly { + // Copy msg.data. We take full control of memory in this inline assembly + // block because it will not return to Solidity code. We overwrite the + // Solidity scratch pad at memory position 0. + calldatacopy(0, 0, calldatasize()) + + // Call the implementation. + // out and outsize are 0 because we don't know the size yet. + let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) + + // Copy the returned data. + returndatacopy(0, 0, returndatasize()) + + switch result + // delegatecall returns 0 on error. + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + + /** + * @dev This is a virtual function that should be overridden so it returns the address to which the fallback + * function and {_fallback} should delegate. + */ + function _implementation() internal view virtual returns (address); + + /** + * @dev Delegates the current call to the address returned by `_implementation()`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _fallback() internal virtual { + _delegate(_implementation()); + } + + /** + * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other + * function in the contract matches the call data. + */ + fallback() external payable virtual { + _fallback(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/README.adoc new file mode 100644 index 0000000..3c4a78d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/README.adoc @@ -0,0 +1,87 @@ += Proxies + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/proxy + +This is a low-level set of contracts implementing different proxy patterns with and without upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page. + +Most of the proxies below are built on an abstract base contract. + +- {Proxy}: Abstract contract implementing the core delegation functionality. + +In order to avoid clashes with the storage variables of the implementation contract behind a proxy, we use https://eips.ethereum.org/EIPS/eip-1967[EIP1967] storage slots. + +- {ERC1967Utils}: Internal functions to get and set the storage slots defined in EIP1967. +- {ERC1967Proxy}: A proxy using EIP1967 storage slots. Not upgradeable by default. + +There are two alternative ways to add upgradeability to an ERC1967 proxy. Their differences are explained below in <>. + +- {TransparentUpgradeableProxy}: A proxy with a built-in immutable admin and upgrade interface. +- {UUPSUpgradeable}: An upgradeability mechanism to be included in the implementation contract. + +CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Truffle and Hardhat. + +A different family of proxies are beacon proxies. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. + +- {BeaconProxy}: A proxy that retrieves its implementation from a beacon contract. +- {UpgradeableBeacon}: A beacon contract with a built in admin that can upgrade the {BeaconProxy} pointing to it. + +In this pattern, the proxy contract doesn't hold the implementation address in storage like an ERC1967 proxy. Instead, the address is stored in a separate beacon contract. The `upgrade` operations are sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded. + +Outside the realm of upgradeability, proxies can also be useful to make cheap contract clones, such as those created by an on-chain factory contract that creates many instances of the same contract. These instances are designed to be both cheap to deploy, and cheap to call. + +- {Clones}: A library that can deploy cheap minimal non-upgradeable proxies. + +[[transparent-vs-uups]] +== Transparent vs UUPS Proxies + +The original proxies included in OpenZeppelin followed the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[Transparent Proxy Pattern]. While this pattern is still provided, our recommendation is now shifting towards UUPS proxies, which are both lightweight and versatile. The name UUPS comes from https://eips.ethereum.org/EIPS/eip-1822[EIP1822], which first documented the pattern. + +While both of these share the same interface for upgrades, in UUPS proxies the upgrade is handled by the implementation, and can eventually be removed. Transparent proxies, on the other hand, include the upgrade and admin logic in the proxy itself. This means {TransparentUpgradeableProxy} is more expensive to deploy than what is possible with UUPS proxies. + +UUPS proxies are implemented using an {ERC1967Proxy}. Note that this proxy is not by itself upgradeable. It is the role of the implementation to include, alongside the contract's logic, all the code necessary to update the implementation's address that is stored at a specific slot in the proxy's storage space. This is where the {UUPSUpgradeable} contract comes in. Inheriting from it (and overriding the {xref-UUPSUpgradeable-_authorizeUpgrade-address-}[`_authorizeUpgrade`] function with the relevant access control mechanism) will turn your contract into a UUPS compliant implementation. + +Note that since both proxies use the same storage slot for the implementation address, using a UUPS compliant implementation with a {TransparentUpgradeableProxy} might allow non-admins to perform upgrade operations. + +By default, the upgrade functionality included in {UUPSUpgradeable} contains a security mechanism that will prevent any upgrades to a non UUPS compliant implementation. This prevents upgrades to an implementation contract that wouldn't contain the necessary upgrade mechanism, as it would lock the upgradeability of the proxy forever. This security mechanism can be bypassed by either of: + +- Adding a flag mechanism in the implementation that will disable the upgrade function when triggered. +- Upgrading to an implementation that features an upgrade mechanism without the additional security check, and then upgrading again to another implementation without the upgrade mechanism. + +The current implementation of this security mechanism uses https://eips.ethereum.org/EIPS/eip-1822[EIP1822] to detect the storage slot used by the implementation. A previous implementation, now deprecated, relied on a rollback check. It is possible to upgrade from a contract using the old mechanism to a new one. The inverse is however not possible, as old implementations (before version 4.5) did not include the `ERC1822` interface. + +== Core + +{{Proxy}} + +== ERC1967 + +{{IERC1967}} + +{{ERC1967Proxy}} + +{{ERC1967Utils}} + +== Transparent Proxy + +{{TransparentUpgradeableProxy}} + +{{ProxyAdmin}} + +== Beacon + +{{BeaconProxy}} + +{{IBeacon}} + +{{UpgradeableBeacon}} + +== Minimal Clones + +{{Clones}} + +== Utils + +{{Initializable}} + +{{UUPSUpgradeable}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/BeaconProxy.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/BeaconProxy.sol new file mode 100644 index 0000000..05e26e5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/BeaconProxy.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/BeaconProxy.sol) + +pragma solidity ^0.8.20; + +import {IBeacon} from "./IBeacon.sol"; +import {Proxy} from "../Proxy.sol"; +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; + +/** + * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. + * + * The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an + * immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] so that it can be accessed externally. + * + * CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust + * the beacon to not upgrade the implementation maliciously. + * + * IMPORTANT: Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in + * an inconsistent state where the beacon storage slot does not match the beacon address. + */ +contract BeaconProxy is Proxy { + // An immutable address for the beacon to avoid unnecessary SLOADs before each delegate call. + address private immutable _beacon; + + /** + * @dev Initializes the proxy with `beacon`. + * + * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This + * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity + * constructor. + * + * Requirements: + * + * - `beacon` must be a contract with the interface {IBeacon}. + * - If `data` is empty, `msg.value` must be zero. + */ + constructor(address beacon, bytes memory data) payable { + ERC1967Utils.upgradeBeaconToAndCall(beacon, data); + _beacon = beacon; + } + + /** + * @dev Returns the current implementation address of the associated beacon. + */ + function _implementation() internal view virtual override returns (address) { + return IBeacon(_getBeacon()).implementation(); + } + + /** + * @dev Returns the beacon. + */ + function _getBeacon() internal view virtual returns (address) { + return _beacon; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/IBeacon.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/IBeacon.sol new file mode 100644 index 0000000..36a3c76 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/IBeacon.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) + +pragma solidity ^0.8.20; + +/** + * @dev This is the interface that {BeaconProxy} expects of its beacon. + */ +interface IBeacon { + /** + * @dev Must return an address that can be used as a delegate call target. + * + * {UpgradeableBeacon} will check that this address is a contract. + */ + function implementation() external view returns (address); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/UpgradeableBeacon.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/UpgradeableBeacon.sol new file mode 100644 index 0000000..8db9bd2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/beacon/UpgradeableBeacon.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/UpgradeableBeacon.sol) + +pragma solidity ^0.8.20; + +import {IBeacon} from "./IBeacon.sol"; +import {Ownable} from "../../access/Ownable.sol"; + +/** + * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their + * implementation contract, which is where they will delegate all function calls. + * + * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. + */ +contract UpgradeableBeacon is IBeacon, Ownable { + address private _implementation; + + /** + * @dev The `implementation` of the beacon is invalid. + */ + error BeaconInvalidImplementation(address implementation); + + /** + * @dev Emitted when the implementation returned by the beacon is changed. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon. + */ + constructor(address implementation_, address initialOwner) Ownable(initialOwner) { + _setImplementation(implementation_); + } + + /** + * @dev Returns the current implementation address. + */ + function implementation() public view virtual returns (address) { + return _implementation; + } + + /** + * @dev Upgrades the beacon to a new implementation. + * + * Emits an {Upgraded} event. + * + * Requirements: + * + * - msg.sender must be the owner of the contract. + * - `newImplementation` must be a contract. + */ + function upgradeTo(address newImplementation) public virtual onlyOwner { + _setImplementation(newImplementation); + } + + /** + * @dev Sets the implementation contract address for this beacon + * + * Requirements: + * + * - `newImplementation` must be a contract. + */ + function _setImplementation(address newImplementation) private { + if (newImplementation.code.length == 0) { + revert BeaconInvalidImplementation(newImplementation); + } + _implementation = newImplementation; + emit Upgraded(newImplementation); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/transparent/ProxyAdmin.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/transparent/ProxyAdmin.sol new file mode 100644 index 0000000..dab55ef --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/transparent/ProxyAdmin.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol) + +pragma solidity ^0.8.20; + +import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol"; +import {Ownable} from "../../access/Ownable.sol"; + +/** + * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an + * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. + */ +contract ProxyAdmin is Ownable { + /** + * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)` + * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, + * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string. + * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must + * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function + * during an upgrade. + */ + string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; + + /** + * @dev Sets the initial owner who can perform upgrades. + */ + constructor(address initialOwner) Ownable(initialOwner) {} + + /** + * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. + * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + * - If `data` is empty, `msg.value` must be zero. + */ + function upgradeAndCall( + ITransparentUpgradeableProxy proxy, + address implementation, + bytes memory data + ) public payable virtual onlyOwner { + proxy.upgradeToAndCall{value: msg.value}(implementation, data); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol new file mode 100644 index 0000000..b2021c7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol) + +pragma solidity ^0.8.20; + +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; +import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol"; +import {IERC1967} from "../../interfaces/IERC1967.sol"; +import {ProxyAdmin} from "./ProxyAdmin.sol"; + +/** + * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy} + * does not implement this interface directly, and its upgradeability mechanism is 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 upgradeToAndCall(address, bytes calldata) external payable; +} + +/** + * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance. + * + * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector + * clashing], which can potentially be used in an attack, this contract uses the + * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two + * things that go hand in hand: + * + * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if + * that call matches the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself. + * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to + * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating + * the proxy admin cannot fallback to the target implementation. + * + * These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a + * dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to + * call a function from the proxy implementation. For this reason, the proxy deploys an instance of {ProxyAdmin} and + * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative + * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership. + * + * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not + * inherit from that interface, and instead `upgradeToAndCall` is 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. + * + * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a + * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract. + * + * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an + * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be + * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an + * undesirable state where the admin slot is different from the actual admin. + * + * 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 `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency. + */ +contract TransparentUpgradeableProxy is ERC1967Proxy { + // An immutable address for the admin to avoid unnecessary SLOADs before each call + // at the expense of removing the ability to change the admin once it's set. + // This is acceptable if the admin is always a ProxyAdmin instance or similar contract + // with its own ability to transfer the permissions to another account. + address private immutable _admin; + + /** + * @dev The proxy caller is the current admin, and can't fallback to the proxy target. + */ + error ProxyDeniedAdminAccess(); + + /** + * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`, + * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in + * {ERC1967Proxy-constructor}. + */ + constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) { + _admin = address(new ProxyAdmin(initialOwner)); + // Set the storage value and emit an event for ERC-1967 compatibility + ERC1967Utils.changeAdmin(_proxyAdmin()); + } + + /** + * @dev Returns the admin of this proxy. + */ + function _proxyAdmin() internal virtual returns (address) { + return _admin; + } + + /** + * @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 == _proxyAdmin()) { + if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) { + revert ProxyDeniedAdminAccess(); + } else { + _dispatchUpgradeToAndCall(); + } + } else { + super._fallback(); + } + } + + /** + * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}. + * + * Requirements: + * + * - If `data` is empty, `msg.value` must be zero. + */ + function _dispatchUpgradeToAndCall() private { + (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes)); + ERC1967Utils.upgradeToAndCall(newImplementation, data); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/utils/Initializable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/utils/Initializable.sol new file mode 100644 index 0000000..b3d82b5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/utils/Initializable.sol @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) + +pragma solidity ^0.8.20; + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * 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"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Storage of the initializable contract. + * + * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions + * when using with upgradeable contracts. + * + * @custom:storage-location erc7201:openzeppelin.storage.Initializable + */ + struct InitializableStorage { + /** + * @dev Indicates that the contract has been initialized. + */ + uint64 _initialized; + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool _initializing; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; + + /** + * @dev The contract is already initialized. + */ + error InvalidInitialization(); + + /** + * @dev The contract is not initializing. + */ + error NotInitializing(); + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint64 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any + * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in + * production. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + // Cache values to avoid duplicated sloads + bool isTopLevelCall = !$._initializing; + uint64 initialized = $._initialized; + + // Allowed calls: + // - initialSetup: the contract is not in the initializing state and no previous version was + // initialized + // - construction: the contract is initialized at version 1 (no reininitialization) and the + // current contract is just being deployed + bool initialSetup = initialized == 0 && isTopLevelCall; + bool construction = initialized == 1 && address(this).code.length == 0; + + if (!initialSetup && !construction) { + revert InvalidInitialization(); + } + $._initialized = 1; + if (isTopLevelCall) { + $._initializing = true; + } + _; + if (isTopLevelCall) { + $._initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint64 version) { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing || $._initialized >= version) { + revert InvalidInitialization(); + } + $._initialized = version; + $._initializing = true; + _; + $._initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + _checkInitializing(); + _; + } + + /** + * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. + */ + function _checkInitializing() internal view virtual { + if (!_isInitializing()) { + revert NotInitializing(); + } + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing) { + revert InvalidInitialization(); + } + if ($._initialized != type(uint64).max) { + $._initialized = type(uint64).max; + emit Initialized(type(uint64).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint64) { + return _getInitializableStorage()._initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _getInitializableStorage()._initializing; + } + + /** + * @dev Returns a pointer to the storage namespace. + */ + // solhint-disable-next-line var-name-mixedcase + function _getInitializableStorage() private pure returns (InitializableStorage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/utils/UUPSUpgradeable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/utils/UUPSUpgradeable.sol new file mode 100644 index 0000000..8a4e693 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/proxy/utils/UUPSUpgradeable.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol) + +pragma solidity ^0.8.20; + +import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol"; +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; + +/** + * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an + * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. + * + * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is + * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing + * `UUPSUpgradeable` with a custom implementation of upgrades. + * + * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. + */ +abstract contract UUPSUpgradeable is IERC1822Proxiable { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable __self = address(this); + + /** + * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` + * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, + * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. + * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must + * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function + * during an upgrade. + */ + string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; + + /** + * @dev The call is from an unauthorized context. + */ + error UUPSUnauthorizedCallContext(); + + /** + * @dev The storage `slot` is unsupported as a UUID. + */ + error UUPSUnsupportedProxiableUUID(bytes32 slot); + + /** + * @dev Check that the execution is being performed through a delegatecall call and that the execution context is + * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case + * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a + * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to + * fail. + */ + modifier onlyProxy() { + _checkProxy(); + _; + } + + /** + * @dev Check that the execution is not being performed through a delegate call. This allows a function to be + * callable on the implementing contract but not through proxies. + */ + modifier notDelegated() { + _checkNotDelegated(); + _; + } + + /** + * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the + * implementation. It is used to validate the implementation's compatibility when performing an upgrade. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. + */ + function proxiableUUID() external view virtual notDelegated returns (bytes32) { + return ERC1967Utils.IMPLEMENTATION_SLOT; + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call + * encoded in `data`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, data); + } + + /** + * @dev Reverts if the execution is not performed via delegatecall or the execution + * context is not of a proxy with an ERC1967-compliant implementation pointing to self. + * See {_onlyProxy}. + */ + function _checkProxy() internal view virtual { + if ( + address(this) == __self || // Must be called through delegatecall + ERC1967Utils.getImplementation() != __self // Must be called through an active proxy + ) { + revert UUPSUnauthorizedCallContext(); + } + } + + /** + * @dev Reverts if the execution is performed via delegatecall. + * See {notDelegated}. + */ + function _checkNotDelegated() internal view virtual { + if (address(this) != __self) { + // Must not be called through delegatecall + revert UUPSUnauthorizedCallContext(); + } + } + + /** + * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by + * {upgradeToAndCall}. + * + * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. + * + * ```solidity + * function _authorizeUpgrade(address) internal onlyOwner {} + * ``` + */ + function _authorizeUpgrade(address newImplementation) internal virtual; + + /** + * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. + * + * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value + * is expected to be the implementation slot in ERC1967. + * + * Emits an {IERC1967-Upgraded} event. + */ + function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { + try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { + if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { + revert UUPSUnsupportedProxiableUUID(slot); + } + ERC1967Utils.upgradeToAndCall(newImplementation, data); + } catch { + // The implementation is not UUPS + revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/ERC1155.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/ERC1155.sol new file mode 100644 index 0000000..316f329 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/ERC1155.sol @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol) + +pragma solidity ^0.8.20; + +import {IERC1155} from "./IERC1155.sol"; +import {IERC1155Receiver} from "./IERC1155Receiver.sol"; +import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol"; +import {Context} from "../../utils/Context.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; +import {Arrays} from "../../utils/Arrays.sol"; +import {IERC1155Errors} from "../../interfaces/draft-IERC6093.sol"; + +/** + * @dev Implementation of the basic standard multi-token. + * See https://eips.ethereum.org/EIPS/eip-1155 + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + */ +abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors { + using Arrays for uint256[]; + using Arrays for address[]; + + mapping(uint256 id => mapping(address account => uint256)) private _balances; + + mapping(address account => mapping(address operator => bool)) private _operatorApprovals; + + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json + string private _uri; + + /** + * @dev See {_setURI}. + */ + constructor(string memory uri_) { + _setURI(uri_); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC1155).interfaceId || + interfaceId == type(IERC1155MetadataURI).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function uri(uint256 /* id */) public view virtual returns (string memory) { + return _uri; + } + + /** + * @dev See {IERC1155-balanceOf}. + */ + function balanceOf(address account, uint256 id) public view virtual returns (uint256) { + return _balances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] memory accounts, + uint256[] memory ids + ) public view virtual returns (uint256[] memory) { + if (accounts.length != ids.length) { + revert ERC1155InvalidArrayLength(ids.length, accounts.length); + } + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i)); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) public view virtual returns (bool) { + return _operatorApprovals[account][operator]; + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual { + address sender = _msgSender(); + if (from != sender && !isApprovedForAll(from, sender)) { + revert ERC1155MissingApprovalForAll(sender, from); + } + _safeTransferFrom(from, to, id, value, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) public virtual { + address sender = _msgSender(); + if (from != sender && !isApprovedForAll(from, sender)) { + revert ERC1155MissingApprovalForAll(sender, from); + } + _safeBatchTransferFrom(from, to, ids, values, data); + } + + /** + * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from` + * (or `to`) is the zero address. + * + * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received} + * or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value. + * - `ids` and `values` must have the same length. + * + * NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead. + */ + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual { + if (ids.length != values.length) { + revert ERC1155InvalidArrayLength(ids.length, values.length); + } + + address operator = _msgSender(); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids.unsafeMemoryAccess(i); + uint256 value = values.unsafeMemoryAccess(i); + + if (from != address(0)) { + uint256 fromBalance = _balances[id][from]; + if (fromBalance < value) { + revert ERC1155InsufficientBalance(from, fromBalance, value, id); + } + unchecked { + // Overflow not possible: value <= fromBalance + _balances[id][from] = fromBalance - value; + } + } + + if (to != address(0)) { + _balances[id][to] += value; + } + } + + if (ids.length == 1) { + uint256 id = ids.unsafeMemoryAccess(0); + uint256 value = values.unsafeMemoryAccess(0); + emit TransferSingle(operator, from, to, id, value); + } else { + emit TransferBatch(operator, from, to, ids, values); + } + } + + /** + * @dev Version of {_update} that performs the token acceptance check by calling + * {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it + * contains code (eg. is a smart contract at the moment of execution). + * + * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any + * update to the contract state after this function would break the check-effect-interaction pattern. Consider + * overriding {_update} instead. + */ + function _updateWithAcceptanceCheck( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) internal virtual { + _update(from, to, ids, values); + if (to != address(0)) { + address operator = _msgSender(); + if (ids.length == 1) { + uint256 id = ids.unsafeMemoryAccess(0); + uint256 value = values.unsafeMemoryAccess(0); + _doSafeTransferAcceptanceCheck(operator, from, to, id, value, data); + } else { + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data); + } + } + } + + /** + * @dev Transfers a `value` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `value` amount. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(from, to, ids, values, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + * - `ids` and `values` must have the same length. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + _updateWithAcceptanceCheck(from, to, ids, values, data); + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the values in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setURI(string memory newuri) internal virtual { + _uri = newuri; + } + + /** + * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint(address to, uint256 id, uint256 value, bytes memory data) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(address(0), to, ids, values, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `values` must have the same length. + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + _updateWithAcceptanceCheck(address(0), to, ids, values, data); + } + + /** + * @dev Destroys a `value` amount of tokens of type `id` from `from` + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `value` amount of tokens of type `id`. + */ + function _burn(address from, uint256 id, uint256 value) internal { + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(from, address(0), ids, values, ""); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `value` amount of tokens of type `id`. + * - `ids` and `values` must have the same length. + */ + function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal { + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + _updateWithAcceptanceCheck(from, address(0), ids, values, ""); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the zero address. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + if (operator == address(0)) { + revert ERC1155InvalidOperator(address(0)); + } + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address + * if it contains code at the moment of execution. + */ + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 value, + bytes memory data + ) private { + if (to.code.length > 0) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + // Tokens rejected + revert ERC1155InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-ERC1155Receiver implementer + revert ERC1155InvalidReceiver(to); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + } + + /** + * @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address + * if it contains code at the moment of execution. + */ + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) private { + if (to.code.length > 0) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns ( + bytes4 response + ) { + if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + // Tokens rejected + revert ERC1155InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-ERC1155Receiver implementer + revert ERC1155InvalidReceiver(to); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + } + + /** + * @dev Creates an array in memory with only one value for each of the elements provided. + */ + function _asSingletonArrays( + uint256 element1, + uint256 element2 + ) private pure returns (uint256[] memory array1, uint256[] memory array2) { + /// @solidity memory-safe-assembly + assembly { + // Load the free memory pointer + array1 := mload(0x40) + // Set array length to 1 + mstore(array1, 1) + // Store the single element at the next word after the length (where content starts) + mstore(add(array1, 0x20), element1) + + // Repeat for next array locating it right after the first array + array2 := add(array1, 0x40) + mstore(array2, 1) + mstore(add(array2, 0x20), element2) + + // Update the free memory pointer by pointing after the second array + mstore(0x40, add(array2, 0x40)) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/IERC1155.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/IERC1155.sol new file mode 100644 index 0000000..a014946 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/IERC1155.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC1155 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-1155[EIP]. + */ +interface IERC1155 is IERC165 { + /** + * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`. + */ + event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); + + /** + * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all + * transfers. + */ + event TransferBatch( + address indexed operator, + address indexed from, + address indexed to, + uint256[] ids, + uint256[] values + ); + + /** + * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to + * `approved`. + */ + event ApprovalForAll(address indexed account, address indexed operator, bool approved); + + /** + * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. + * + * If an {URI} event was emitted for `id`, the standard + * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value + * returned by {IERC1155MetadataURI-uri}. + */ + event URI(string value, uint256 indexed id); + + /** + * @dev Returns the value of tokens of token type `id` owned by `account`. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) external view returns (uint256); + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] calldata accounts, + uint256[] calldata ids + ) external view returns (uint256[] memory); + + /** + * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the caller. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address account, address operator) external view returns (bool); + + /** + * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. + * + * WARNING: This function can potentially allow a reentrancy attack when transferring tokens + * to an untrusted contract, when invoking {onERC1155Received} on the receiver. + * Ensure to follow the checks-effects-interactions pattern and consider employing + * reentrancy guards when interacting with untrusted contracts. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. + * - `from` must have a balance of tokens of type `id` of at least `value` amount. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external; + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. + * + * + * WARNING: This function can potentially allow a reentrancy attack when transferring tokens + * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver. + * Ensure to follow the checks-effects-interactions pattern and consider employing + * reentrancy guards when interacting with untrusted contracts. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `values` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/IERC1155Receiver.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/IERC1155Receiver.sol new file mode 100644 index 0000000..0f6e2bf --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/IERC1155Receiver.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * @dev Interface that must be implemented by smart contracts in order to receive + * ERC-1155 token transfers. + */ +interface IERC1155Receiver is IERC165 { + /** + * @dev Handles the receipt of a single ERC1155 token type. This function is + * called at the end of a `safeTransferFrom` after the balance has been updated. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + * (i.e. 0xf23a6e61, or its own function selector). + * + * @param operator The address which initiated the transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param id The ID of the token being transferred + * @param value The amount of tokens being transferred + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4); + + /** + * @dev Handles the receipt of a multiple ERC1155 token types. This function + * is called at the end of a `safeBatchTransferFrom` after the balances have + * been updated. + * + * NOTE: To accept the transfer(s), this must return + * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + * (i.e. 0xbc197c81, or its own function selector). + * + * @param operator The address which initiated the batch transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param ids An array containing ids of each token being transferred (order and length must match values array) + * @param values An array containing amounts of each token being transferred (order and length must match ids array) + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/README.adoc new file mode 100644 index 0000000..1a56358 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/README.adoc @@ -0,0 +1,41 @@ += ERC 1155 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc1155 + +This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-1155[ERC1155 Multi Token Standard]. + +The EIP consists of three interfaces which fulfill different roles, found here as {IERC1155}, {IERC1155MetadataURI} and {IERC1155Receiver}. + +{ERC1155} implements the mandatory {IERC1155} interface, as well as the optional extension {IERC1155MetadataURI}, by relying on the substitution mechanism to use the same URI for all token types, dramatically reducing gas costs. + +Additionally there are multiple custom extensions, including: + +* designation of addresses that can pause token transfers for all users ({ERC1155Pausable}). +* destruction of own tokens ({ERC1155Burnable}). + +NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC1155 (such as <>) and expose them as external functions in the way they prefer. + +== Core + +{{IERC1155}} + +{{IERC1155MetadataURI}} + +{{ERC1155}} + +{{IERC1155Receiver}} + +== Extensions + +{{ERC1155Pausable}} + +{{ERC1155Burnable}} + +{{ERC1155Supply}} + +{{ERC1155URIStorage}} + +== Utilities + +{{ERC1155Holder}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Burnable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Burnable.sol new file mode 100644 index 0000000..fd6ad61 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Burnable.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Burnable.sol) + +pragma solidity ^0.8.20; + +import {ERC1155} from "../ERC1155.sol"; + +/** + * @dev Extension of {ERC1155} that allows token holders to destroy both their + * own tokens and those that they have been approved to use. + */ +abstract contract ERC1155Burnable is ERC1155 { + function burn(address account, uint256 id, uint256 value) public virtual { + if (account != _msgSender() && !isApprovedForAll(account, _msgSender())) { + revert ERC1155MissingApprovalForAll(_msgSender(), account); + } + + _burn(account, id, value); + } + + function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual { + if (account != _msgSender() && !isApprovedForAll(account, _msgSender())) { + revert ERC1155MissingApprovalForAll(_msgSender(), account); + } + + _burnBatch(account, ids, values); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Pausable.sol new file mode 100644 index 0000000..529a465 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC1155} from "../ERC1155.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC1155 token with pausable token transfers, minting and burning. + * + * 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 pause mechanism of the contract unreachable, and thus unusable. + */ +abstract contract ERC1155Pausable is ERC1155, Pausable { + /** + * @dev See {ERC1155-_update}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _update( + address from, + address to, + uint256[] memory ids, + uint256[] memory values + ) internal virtual override whenNotPaused { + super._update(from, to, ids, values); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Supply.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Supply.sol new file mode 100644 index 0000000..cef11b4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155Supply.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Supply.sol) + +pragma solidity ^0.8.20; + +import {ERC1155} from "../ERC1155.sol"; + +/** + * @dev Extension of ERC1155 that adds tracking of total supply per id. + * + * Useful for scenarios where Fungible and Non-fungible tokens have to be + * clearly identified. Note: While a totalSupply of 1 might mean the + * corresponding is an NFT, there is no guarantees that no other token with the + * same id are not going to be minted. + * + * NOTE: This contract implies a global limit of 2**256 - 1 to the number of tokens + * that can be minted. + * + * CAUTION: This extension should not be added in an upgrade to an already deployed contract. + */ +abstract contract ERC1155Supply is ERC1155 { + mapping(uint256 id => uint256) private _totalSupply; + uint256 private _totalSupplyAll; + + /** + * @dev Total value of tokens in with a given id. + */ + function totalSupply(uint256 id) public view virtual returns (uint256) { + return _totalSupply[id]; + } + + /** + * @dev Total value of tokens. + */ + function totalSupply() public view virtual returns (uint256) { + return _totalSupplyAll; + } + + /** + * @dev Indicates whether any token exist with a given id, or not. + */ + function exists(uint256 id) public view virtual returns (bool) { + return totalSupply(id) > 0; + } + + /** + * @dev See {ERC1155-_update}. + */ + function _update( + address from, + address to, + uint256[] memory ids, + uint256[] memory values + ) internal virtual override { + super._update(from, to, ids, values); + + if (from == address(0)) { + uint256 totalMintValue = 0; + for (uint256 i = 0; i < ids.length; ++i) { + uint256 value = values[i]; + // Overflow check required: The rest of the code assumes that totalSupply never overflows + _totalSupply[ids[i]] += value; + totalMintValue += value; + } + // Overflow check required: The rest of the code assumes that totalSupplyAll never overflows + _totalSupplyAll += totalMintValue; + } + + if (to == address(0)) { + uint256 totalBurnValue = 0; + for (uint256 i = 0; i < ids.length; ++i) { + uint256 value = values[i]; + + unchecked { + // Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i]) + _totalSupply[ids[i]] -= value; + // Overflow not possible: sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll + totalBurnValue += value; + } + } + unchecked { + // Overflow not possible: totalBurnValue = sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll + _totalSupplyAll -= totalBurnValue; + } + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol new file mode 100644 index 0000000..c2a5bdc --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155URIStorage.sol) + +pragma solidity ^0.8.20; + +import {Strings} from "../../../utils/Strings.sol"; +import {ERC1155} from "../ERC1155.sol"; + +/** + * @dev ERC1155 token with storage based token URI management. + * Inspired by the ERC721URIStorage extension + */ +abstract contract ERC1155URIStorage is ERC1155 { + using Strings for uint256; + + // Optional base URI + string private _baseURI = ""; + + // Optional mapping for token URIs + mapping(uint256 tokenId => string) private _tokenURIs; + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the concatenation of the `_baseURI` + * and the token-specific uri if the latter is set + * + * This enables the following behaviors: + * + * - if `_tokenURIs[tokenId]` is set, then the result is the concatenation + * of `_baseURI` and `_tokenURIs[tokenId]` (keep in mind that `_baseURI` + * is empty per default); + * + * - if `_tokenURIs[tokenId]` is NOT set then we fallback to `super.uri()` + * which in most cases will contain `ERC1155._uri`; + * + * - if `_tokenURIs[tokenId]` is NOT set, and if the parents do not have a + * uri value set, then the result is empty. + */ + function uri(uint256 tokenId) public view virtual override returns (string memory) { + string memory tokenURI = _tokenURIs[tokenId]; + + // If token URI is set, concatenate base URI and tokenURI (via string.concat). + return bytes(tokenURI).length > 0 ? string.concat(_baseURI, tokenURI) : super.uri(tokenId); + } + + /** + * @dev Sets `tokenURI` as the tokenURI of `tokenId`. + */ + function _setURI(uint256 tokenId, string memory tokenURI) internal virtual { + _tokenURIs[tokenId] = tokenURI; + emit URI(uri(tokenId), tokenId); + } + + /** + * @dev Sets `baseURI` as the `_baseURI` for all tokens + */ + function _setBaseURI(string memory baseURI) internal virtual { + _baseURI = baseURI; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol new file mode 100644 index 0000000..e3fb74d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol) + +pragma solidity ^0.8.20; + +import {IERC1155} from "../IERC1155.sol"; + +/** + * @dev Interface of the optional ERC1155MetadataExtension interface, as defined + * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. + */ +interface IERC1155MetadataURI is IERC1155 { + /** + * @dev Returns the URI for token type `id`. + * + * If the `\{id\}` substring is present in the URI, it must be replaced by + * clients with the actual token type ID. + */ + function uri(uint256 id) external view returns (string memory); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/utils/ERC1155Holder.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/utils/ERC1155Holder.sol new file mode 100644 index 0000000..b108cdb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol) + +pragma solidity ^0.8.20; + +import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; +import {IERC1155Receiver} from "../IERC1155Receiver.sol"; + +/** + * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC1155 tokens. + * + * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be + * stuck. + */ +abstract contract ERC1155Holder is ERC165, IERC1155Receiver { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); + } + + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/ERC20.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/ERC20.sol new file mode 100644 index 0000000..1fde527 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/ERC20.sol @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "./IERC20.sol"; +import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; +import {Context} from "../../utils/Context.sol"; +import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + */ +abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { + mapping(address account => uint256) private _balances; + + mapping(address account => mapping(address spender => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `value`. + */ + function transfer(address to, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, value); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, value); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `value`. + * - the caller must have allowance for ``from``'s tokens of at least + * `value`. + */ + function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, value); + _transfer(from, to, value); + return true; + } + + /** + * @dev Moves a `value` amount of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _transfer(address from, address to, uint256 value) internal { + if (from == address(0)) { + revert ERC20InvalidSender(address(0)); + } + if (to == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(from, to, value); + } + + /** + * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding + * this function. + * + * Emits a {Transfer} event. + */ + function _update(address from, address to, uint256 value) internal virtual { + if (from == address(0)) { + // Overflow check required: The rest of the code assumes that totalSupply never overflows + _totalSupply += value; + } else { + uint256 fromBalance = _balances[from]; + if (fromBalance < value) { + revert ERC20InsufficientBalance(from, fromBalance, value); + } + unchecked { + // Overflow not possible: value <= fromBalance <= totalSupply. + _balances[from] = fromBalance - value; + } + } + + if (to == address(0)) { + unchecked { + // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. + _totalSupply -= value; + } + } else { + unchecked { + // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. + _balances[to] += value; + } + } + + emit Transfer(from, to, value); + } + + /** + * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). + * Relies on the `_update` mechanism + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _mint(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(address(0), account, value); + } + + /** + * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead + */ + function _burn(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidSender(address(0)); + } + _update(account, address(0), value); + } + + /** + * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + * + * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. + */ + function _approve(address owner, address spender, uint256 value) internal { + _approve(owner, spender, value, true); + } + + /** + * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. + * + * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by + * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any + * `Approval` event during `transferFrom` operations. + * + * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to + * true using the following override: + * ``` + * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { + * super._approve(owner, spender, value, true); + * } + * ``` + * + * Requirements are the same as {_approve}. + */ + function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { + if (owner == address(0)) { + revert ERC20InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC20InvalidSpender(address(0)); + } + _allowances[owner][spender] = value; + if (emitEvent) { + emit Approval(owner, spender, value); + } + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `value`. + * + * Does not update the allowance value in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Does not emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 value) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + if (currentAllowance < value) { + revert ERC20InsufficientAllowance(spender, currentAllowance, value); + } + unchecked { + _approve(owner, spender, currentAllowance - value, false); + } + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/IERC20.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/IERC20.sol new file mode 100644 index 0000000..db01cf4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/IERC20.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the value of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the value of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves a `value` amount of tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 value) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 value) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the + * allowance mechanism. `value` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 value) external returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/README.adoc new file mode 100644 index 0000000..2c50880 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/README.adoc @@ -0,0 +1,67 @@ += ERC 20 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc20 + +This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-20[ERC20 Token Standard]. + +TIP: For an overview of ERC20 tokens and a walk through on how to create a token contract read our xref:ROOT:erc20.adoc[ERC20 guide]. + +There are a few core contracts that implement the behavior specified in the EIP: + +* {IERC20}: the interface all ERC20 implementations should conform to. +* {IERC20Metadata}: the extended ERC20 interface including the <>, <> and <> functions. +* {ERC20}: the implementation of the ERC20 interface, including the <>, <> and <> optional standard extension to the base interface. + +Additionally there are multiple custom extensions, including: + +* {ERC20Permit}: gasless approval of tokens (standardized as ERC2612). +* {ERC20Burnable}: destruction of own tokens. +* {ERC20Capped}: enforcement of a cap to the total supply when minting tokens. +* {ERC20Pausable}: ability to pause token transfers. +* {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC3156). +* {ERC20Votes}: support for voting and vote delegation. +* {ERC20Wrapper}: wrapper to create an ERC20 backed by another ERC20, with deposit and withdraw methods. Useful in conjunction with {ERC20Votes}. +* {ERC4626}: tokenized vault that manages shares (represented as ERC20) that are backed by assets (another ERC20). + +Finally, there are some utilities to interact with ERC20 contracts in various ways: + +* {SafeERC20}: a wrapper around the interface that eliminates the need to handle boolean return values. + +Other utilities that support ERC20 assets can be found in codebase: + +* ERC20 tokens can be timelocked (held tokens for a beneficiary until a specified time) or vested (released following a given schedule) using a {VestingWallet}. + +NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC20 (such as <>) and expose them as external functions in the way they prefer. + +== Core + +{{IERC20}} + +{{IERC20Metadata}} + +{{ERC20}} + +== Extensions + +{{IERC20Permit}} + +{{ERC20Permit}} + +{{ERC20Burnable}} + +{{ERC20Capped}} + +{{ERC20Pausable}} + +{{ERC20Votes}} + +{{ERC20Wrapper}} + +{{ERC20FlashMint}} + +{{ERC4626}} + +== Utilities + +{{SafeERC20}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Burnable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Burnable.sol new file mode 100644 index 0000000..4d482d8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {Context} from "../../../utils/Context.sol"; + +/** + * @dev Extension of {ERC20} that allows token holders to destroy both their own + * tokens and those that they have an allowance for, in a way that can be + * recognized off-chain (via event analysis). + */ +abstract contract ERC20Burnable is Context, ERC20 { + /** + * @dev Destroys a `value` amount of tokens from the caller. + * + * See {ERC20-_burn}. + */ + function burn(uint256 value) public virtual { + _burn(_msgSender(), value); + } + + /** + * @dev Destroys a `value` amount of tokens from `account`, deducting from + * the caller's allowance. + * + * See {ERC20-_burn} and {ERC20-allowance}. + * + * Requirements: + * + * - the caller must have allowance for ``accounts``'s tokens of at least + * `value`. + */ + function burnFrom(address account, uint256 value) public virtual { + _spendAllowance(account, _msgSender(), value); + _burn(account, value); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Capped.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Capped.sol new file mode 100644 index 0000000..56bafb3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Capped.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; + +/** + * @dev Extension of {ERC20} that adds a cap to the supply of tokens. + */ +abstract contract ERC20Capped is ERC20 { + uint256 private immutable _cap; + + /** + * @dev Total supply cap has been exceeded. + */ + error ERC20ExceededCap(uint256 increasedSupply, uint256 cap); + + /** + * @dev The supplied cap is not a valid cap. + */ + error ERC20InvalidCap(uint256 cap); + + /** + * @dev Sets the value of the `cap`. This value is immutable, it can only be + * set once during construction. + */ + constructor(uint256 cap_) { + if (cap_ == 0) { + revert ERC20InvalidCap(0); + } + _cap = cap_; + } + + /** + * @dev Returns the cap on the token's total supply. + */ + function cap() public view virtual returns (uint256) { + return _cap; + } + + /** + * @dev See {ERC20-_update}. + */ + function _update(address from, address to, uint256 value) internal virtual override { + super._update(from, to, value); + + if (from == address(0)) { + uint256 maxSupply = cap(); + uint256 supply = totalSupply(); + if (supply > maxSupply) { + revert ERC20ExceededCap(supply, maxSupply); + } + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20FlashMint.sol new file mode 100644 index 0000000..0e89312 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20FlashMint.sol) + +pragma solidity ^0.8.20; + +import {IERC3156FlashBorrower} from "../../../interfaces/IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "../../../interfaces/IERC3156FlashLender.sol"; +import {ERC20} from "../ERC20.sol"; + +/** + * @dev Implementation of the ERC3156 Flash loans extension, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + * + * Adds the {flashLoan} method, which provides flash loan support at the token + * level. By default there is no fee, but this can be changed by overriding {flashFee}. + * + * NOTE: When this extension is used along with the {ERC20Capped} or {ERC20Votes} extensions, + * {maxFlashLoan} will not correctly reflect the maximum that can be flash minted. We recommend + * overriding {maxFlashLoan} so that it correctly reflects the supply cap. + */ +abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { + bytes32 private constant RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + /** + * @dev The loan token is not valid. + */ + error ERC3156UnsupportedToken(address token); + + /** + * @dev The requested loan exceeds the max loan value for `token`. + */ + error ERC3156ExceededMaxLoan(uint256 maxLoan); + + /** + * @dev The receiver of a flashloan is not a valid {onFlashLoan} implementer. + */ + error ERC3156InvalidReceiver(address receiver); + + /** + * @dev Returns the maximum amount of tokens available for loan. + * @param token The address of the token that is requested. + * @return The amount of token that can be loaned. + * + * NOTE: This function does not consider any form of supply cap, so in case + * it's used in a token with a cap like {ERC20Capped}, make sure to override this + * function to integrate the cap instead of `type(uint256).max`. + */ + function maxFlashLoan(address token) public view virtual returns (uint256) { + return token == address(this) ? type(uint256).max - totalSupply() : 0; + } + + /** + * @dev Returns the fee applied when doing flash loans. This function calls + * the {_flashFee} function which returns the fee applied when doing flash + * loans. + * @param token The token to be flash loaned. + * @param value The amount of tokens to be loaned. + * @return The fees applied to the corresponding flash loan. + */ + function flashFee(address token, uint256 value) public view virtual returns (uint256) { + if (token != address(this)) { + revert ERC3156UnsupportedToken(token); + } + return _flashFee(token, value); + } + + /** + * @dev Returns the fee applied when doing flash loans. By default this + * implementation has 0 fees. This function can be overloaded to make + * the flash loan mechanism deflationary. + * @param token The token to be flash loaned. + * @param value The amount of tokens to be loaned. + * @return The fees applied to the corresponding flash loan. + */ + function _flashFee(address token, uint256 value) internal view virtual returns (uint256) { + // silence warning about unused variable without the addition of bytecode. + token; + value; + return 0; + } + + /** + * @dev Returns the receiver address of the flash fee. By default this + * implementation returns the address(0) which means the fee amount will be burnt. + * This function can be overloaded to change the fee receiver. + * @return The address for which the flash fee will be sent to. + */ + function _flashFeeReceiver() internal view virtual returns (address) { + return address(0); + } + + /** + * @dev Performs a flash loan. New tokens are minted and sent to the + * `receiver`, who is required to implement the {IERC3156FlashBorrower} + * interface. By the end of the flash loan, the receiver is expected to own + * value + fee tokens and have them approved back to the token contract itself so + * they can be burned. + * @param receiver The receiver of the flash loan. Should implement the + * {IERC3156FlashBorrower-onFlashLoan} interface. + * @param token The token to be flash loaned. Only `address(this)` is + * supported. + * @param value The amount of tokens to be loaned. + * @param data An arbitrary datafield that is passed to the receiver. + * @return `true` if the flash loan was successful. + */ + // This function can reenter, but it doesn't pose a risk because it always preserves the property that the amount + // minted at the beginning is always recovered and burned at the end, or else the entire function will revert. + // slither-disable-next-line reentrancy-no-eth + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 value, + bytes calldata data + ) public virtual returns (bool) { + uint256 maxLoan = maxFlashLoan(token); + if (value > maxLoan) { + revert ERC3156ExceededMaxLoan(maxLoan); + } + uint256 fee = flashFee(token, value); + _mint(address(receiver), value); + if (receiver.onFlashLoan(_msgSender(), token, value, fee, data) != RETURN_VALUE) { + revert ERC3156InvalidReceiver(address(receiver)); + } + address flashFeeReceiver = _flashFeeReceiver(); + _spendAllowance(address(receiver), address(this), value + fee); + if (fee == 0 || flashFeeReceiver == address(0)) { + _burn(address(receiver), value + fee); + } else { + _burn(address(receiver), value); + _transfer(address(receiver), flashFeeReceiver, fee); + } + return true; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Pausable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Pausable.sol new file mode 100644 index 0000000..8fe832b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC20 token with pausable token transfers, minting and burning. + * + * 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 pause mechanism of the contract unreachable, and thus unusable. + */ +abstract contract ERC20Pausable is ERC20, Pausable { + /** + * @dev See {ERC20-_update}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _update(address from, address to, uint256 value) internal virtual override whenNotPaused { + super._update(from, to, value); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Permit.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Permit.sol new file mode 100644 index 0000000..36667ad --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Permit.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol) + +pragma solidity ^0.8.20; + +import {IERC20Permit} from "./IERC20Permit.sol"; +import {ERC20} from "../ERC20.sol"; +import {ECDSA} from "../../../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../../../utils/cryptography/EIP712.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; + +/** + * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + */ +abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces { + bytes32 private constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + /** + * @dev Permit deadline has expired. + */ + error ERC2612ExpiredSignature(uint256 deadline); + + /** + * @dev Mismatched signature. + */ + error ERC2612InvalidSigner(address signer, address owner); + + /** + * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. + * + * It's a good idea to use the same `name` that is defined as the ERC20 token name. + */ + constructor(string memory name) EIP712(name, "1") {} + + /** + * @inheritdoc IERC20Permit + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + if (block.timestamp > deadline) { + revert ERC2612ExpiredSignature(deadline); + } + + bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); + + bytes32 hash = _hashTypedDataV4(structHash); + + address signer = ECDSA.recover(hash, v, r, s); + if (signer != owner) { + revert ERC2612InvalidSigner(signer, owner); + } + + _approve(owner, spender, value); + } + + /** + * @inheritdoc IERC20Permit + */ + function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) { + return super.nonces(owner); + } + + /** + * @inheritdoc IERC20Permit + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view virtual returns (bytes32) { + return _domainSeparatorV4(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Votes.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Votes.sol new file mode 100644 index 0000000..6aa6ed0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Votes.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {Votes} from "../../../governance/utils/Votes.sol"; +import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; + +/** + * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's, + * and supports token supply up to 2^208^ - 1, while COMP is limited to 2^96^ - 1. + * + * NOTE: This contract does not provide interface compatibility with Compound's COMP token. + * + * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either + * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting + * power can be queried through the public accessors {getVotes} and {getPastVotes}. + * + * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it + * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. + */ +abstract contract ERC20Votes is ERC20, Votes { + /** + * @dev Total supply cap has been exceeded, introducing a risk of votes overflowing. + */ + error ERC20ExceededSafeSupply(uint256 increasedSupply, uint256 cap); + + /** + * @dev Maximum token supply. Defaults to `type(uint208).max` (2^208^ - 1). + * + * This maximum is enforced in {_update}. It limits the total supply of the token, which is otherwise a uint256, + * so that checkpoints can be stored in the Trace208 structure used by {{Votes}}. Increasing this value will not + * remove the underlying limitation, and will cause {_update} to fail because of a math overflow in + * {_transferVotingUnits}. An override could be used to further restrict the total supply (to a lower value) if + * additional logic requires it. When resolving override conflicts on this function, the minimum should be + * returned. + */ + function _maxSupply() internal view virtual returns (uint256) { + return type(uint208).max; + } + + /** + * @dev Move voting power when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _update(address from, address to, uint256 value) internal virtual override { + super._update(from, to, value); + if (from == address(0)) { + uint256 supply = totalSupply(); + uint256 cap = _maxSupply(); + if (supply > cap) { + revert ERC20ExceededSafeSupply(supply, cap); + } + } + _transferVotingUnits(from, to, value); + } + + /** + * @dev Returns the voting units of an `account`. + * + * WARNING: Overriding this function may compromise the internal vote accounting. + * `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change. + */ + function _getVotingUnits(address account) internal view virtual override returns (uint256) { + return balanceOf(account); + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function numCheckpoints(address account) public view virtual returns (uint32) { + return _numCheckpoints(account); + } + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoints.Checkpoint208 memory) { + return _checkpoints(account, pos); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Wrapper.sol new file mode 100644 index 0000000..6144880 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Wrapper.sol) + +pragma solidity ^0.8.20; + +import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol"; +import {SafeERC20} from "../utils/SafeERC20.sol"; + +/** + * @dev Extension of the ERC20 token contract to support token wrapping. + * + * Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful + * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC20Votes} will allow the + * wrapping of an existing "basic" ERC20 into a governance token. + */ +abstract contract ERC20Wrapper is ERC20 { + IERC20 private immutable _underlying; + + /** + * @dev The underlying token couldn't be wrapped. + */ + error ERC20InvalidUnderlying(address token); + + constructor(IERC20 underlyingToken) { + if (underlyingToken == this) { + revert ERC20InvalidUnderlying(address(this)); + } + _underlying = underlyingToken; + } + + /** + * @dev See {ERC20-decimals}. + */ + function decimals() public view virtual override returns (uint8) { + 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 value) public virtual returns (bool) { + address sender = _msgSender(); + if (sender == address(this)) { + revert ERC20InvalidSender(address(this)); + } + if (account == address(this)) { + revert ERC20InvalidReceiver(account); + } + SafeERC20.safeTransferFrom(_underlying, sender, address(this), value); + _mint(account, value); + return true; + } + + /** + * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens. + */ + function withdrawTo(address account, uint256 value) public virtual returns (bool) { + if (account == address(this)) { + revert ERC20InvalidReceiver(account); + } + _burn(_msgSender(), value); + SafeERC20.safeTransfer(_underlying, account, value); + return true; + } + + /** + * @dev Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake. Internal + * 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(); + _mint(account, value); + return value; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC4626.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC4626.sol new file mode 100644 index 0000000..ec60872 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/ERC4626.sol @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC4626.sol) + +pragma solidity ^0.8.20; + +import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol"; +import {SafeERC20} from "../utils/SafeERC20.sol"; +import {IERC4626} from "../../../interfaces/IERC4626.sol"; +import {Math} from "../../../utils/math/Math.sol"; + +/** + * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in + * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626]. + * + * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for + * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends + * 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] + * ==== + * 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 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]. + * ==== + */ +abstract contract ERC4626 is ERC20, IERC4626 { + using Math for uint256; + + IERC20 private immutable _asset; + uint8 private immutable _underlyingDecimals; + + /** + * @dev Attempted to deposit more assets than the max amount for `receiver`. + */ + error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max); + + /** + * @dev Attempted to mint more shares than the max amount for `receiver`. + */ + error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max); + + /** + * @dev Attempted to withdraw more assets than the max amount for `receiver`. + */ + error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max); + + /** + * @dev Attempted to redeem more shares than the max amount for `receiver`. + */ + error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max); + + /** + * @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_); + _underlyingDecimals = success ? assetDecimals : 18; + _asset = asset_; + } + + /** + * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way. + */ + function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool, uint8) { + (bool success, bytes memory encodedDecimals) = address(asset_).staticcall( + abi.encodeCall(IERC20Metadata.decimals, ()) + ); + if (success && encodedDecimals.length >= 32) { + uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256)); + if (returnedDecimals <= type(uint8).max) { + return (true, uint8(returnedDecimals)); + } + } + return (false, 0); + } + + /** + * @dev Decimals are 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) { + return _underlyingDecimals + _decimalsOffset(); + } + + /** @dev See {IERC4626-asset}. */ + function asset() public view virtual returns (address) { + return address(_asset); + } + + /** @dev See {IERC4626-totalAssets}. */ + function totalAssets() public view virtual returns (uint256) { + return _asset.balanceOf(address(this)); + } + + /** @dev See {IERC4626-convertToShares}. */ + function convertToShares(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Floor); + } + + /** @dev See {IERC4626-convertToAssets}. */ + function convertToAssets(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Floor); + } + + /** @dev See {IERC4626-maxDeposit}. */ + function maxDeposit(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4626-maxMint}. */ + function maxMint(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4626-maxWithdraw}. */ + function maxWithdraw(address owner) public view virtual returns (uint256) { + return _convertToAssets(balanceOf(owner), Math.Rounding.Floor); + } + + /** @dev See {IERC4626-maxRedeem}. */ + function maxRedeem(address owner) public view virtual returns (uint256) { + return balanceOf(owner); + } + + /** @dev See {IERC4626-previewDeposit}. */ + function previewDeposit(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Floor); + } + + /** @dev See {IERC4626-previewMint}. */ + function previewMint(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Ceil); + } + + /** @dev See {IERC4626-previewWithdraw}. */ + function previewWithdraw(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Ceil); + } + + /** @dev See {IERC4626-previewRedeem}. */ + function previewRedeem(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Floor); + } + + /** @dev See {IERC4626-deposit}. */ + function deposit(uint256 assets, address receiver) public virtual returns (uint256) { + uint256 maxAssets = maxDeposit(receiver); + if (assets > maxAssets) { + revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets); + } + + uint256 shares = previewDeposit(assets); + _deposit(_msgSender(), receiver, assets, shares); + + return shares; + } + + /** @dev See {IERC4626-mint}. + * + * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero. + * In this case, the shares will be minted without requiring any assets to be deposited. + */ + function mint(uint256 shares, address receiver) public virtual returns (uint256) { + uint256 maxShares = maxMint(receiver); + if (shares > maxShares) { + revert ERC4626ExceededMaxMint(receiver, shares, maxShares); + } + + uint256 assets = previewMint(shares); + _deposit(_msgSender(), receiver, assets, shares); + + return assets; + } + + /** @dev See {IERC4626-withdraw}. */ + function withdraw(uint256 assets, address receiver, address owner) public virtual returns (uint256) { + uint256 maxAssets = maxWithdraw(owner); + if (assets > maxAssets) { + revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets); + } + + uint256 shares = previewWithdraw(assets); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return shares; + } + + /** @dev See {IERC4626-redeem}. */ + function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) { + uint256 maxShares = maxRedeem(owner); + if (shares > maxShares) { + revert ERC4626ExceededMaxRedeem(owner, shares, maxShares); + } + + uint256 assets = previewRedeem(shares); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return assets; + } + + /** + * @dev Internal conversion function (from assets to shares) with support for rounding direction. + */ + function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) { + 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) { + return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding); + } + + /** + * @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 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. + // + // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the + // assets are transferred and before the shares are minted, which is a valid state. + // slither-disable-next-line reentrancy-no-eth + SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); + _mint(receiver, shares); + + emit Deposit(caller, receiver, assets, shares); + } + + /** + * @dev Withdraw/redeem common workflow. + */ + function _withdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) internal virtual { + if (caller != owner) { + _spendAllowance(owner, caller, shares); + } + + // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the + // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, + // calls the vault, which is assumed not malicious. + // + // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the + // shares are burned and after the assets are transferred, which is a valid state. + _burn(owner, shares); + SafeERC20.safeTransfer(_asset, receiver, assets); + + emit Withdraw(caller, receiver, owner, assets, shares); + } + + function _decimalsOffset() internal view virtual returns (uint8) { + return 0; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/IERC20Metadata.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/IERC20Metadata.sol new file mode 100644 index 0000000..1a38cba --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/IERC20Metadata.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../IERC20.sol"; + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/IERC20Permit.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/IERC20Permit.sol new file mode 100644 index 0000000..5af4810 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/extensions/IERC20Permit.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + * + * ==== Security Considerations + * + * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature + * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be + * considered as an intention to spend the allowance in any specific way. The second is that because permits have + * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should + * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be + * generally recommended is: + * + * ```solidity + * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { + * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} + * doThing(..., value); + * } + * + * function doThing(..., uint256 value) public { + * token.safeTransferFrom(msg.sender, address(this), value); + * ... + * } + * ``` + * + * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of + * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also + * {SafeERC20-safeTransferFrom}). + * + * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so + * contracts should have entry points that don't rely on permit. + */ +interface IERC20Permit { + /** + * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, + * given ``owner``'s signed approval. + * + * IMPORTANT: The same issues {IERC20-approve} has related to transaction + * ordering also apply here. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `deadline` must be a timestamp in the future. + * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` + * over the EIP712-formatted function arguments. + * - the signature must use ``owner``'s current nonce (see {nonces}). + * + * For more information on the signature format, see the + * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP + * section]. + * + * CAUTION: See Security Considerations above. + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @dev Returns the current nonce for `owner`. This value must be + * included whenever a signature is generated for {permit}. + * + * Every successful call to {permit} increases ``owner``'s nonce by one. This + * prevents a signature from being used multiple times. + */ + function nonces(address owner) external view returns (uint256); + + /** + * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/utils/SafeERC20.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/utils/SafeERC20.sol new file mode 100644 index 0000000..bb65709 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC20/utils/SafeERC20.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../IERC20.sol"; +import {IERC20Permit} from "../extensions/IERC20Permit.sol"; +import {Address} from "../../../utils/Address.sol"; + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using Address for address; + + /** + * @dev An operation with an ERC20 token failed. + */ + error SafeERC20FailedOperation(address token); + + /** + * @dev Indicates a failed `decreaseAllowance` request. + */ + error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); + + /** + * @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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 oldAllowance = token.allowance(address(this), spender); + forceApprove(token, spender, oldAllowance + value); + } + + /** + * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no + * value, non-reverting calls are assumed to be successful. + */ + function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { + unchecked { + uint256 currentAllowance = token.allowance(address(this), spender); + if (currentAllowance < requestedDecrease) { + revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); + } + forceApprove(token, spender, currentAllowance - requestedDecrease); + } + } + + /** + * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, + * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval + * to be set to zero before setting it to a non-zero value, such as USDT. + */ + function forceApprove(IERC20 token, address spender, uint256 value) internal { + bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); + + if (!_callOptionalReturnBool(token, approvalCall)) { + _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); + _callOptionalReturn(token, approvalCall); + } + } + + /** + * @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). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data); + if (returndata.length != 0 && !abi.decode(returndata, (bool))) { + revert SafeERC20FailedOperation(address(token)); + } + } + + /** + * @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(token).code.length > 0; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/ERC721.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/ERC721.sol new file mode 100644 index 0000000..98a80e5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/ERC721.sol @@ -0,0 +1,483 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "./IERC721.sol"; +import {IERC721Receiver} from "./IERC721Receiver.sol"; +import {IERC721Metadata} from "./extensions/IERC721Metadata.sol"; +import {Context} from "../../utils/Context.sol"; +import {Strings} from "../../utils/Strings.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; +import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors { + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + mapping(uint256 tokenId => address) private _owners; + + mapping(address owner => uint256) private _balances; + + mapping(uint256 tokenId => address) private _tokenApprovals; + + mapping(address owner => mapping(address operator => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual returns (uint256) { + if (owner == address(0)) { + revert ERC721InvalidOwner(address(0)); + } + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual returns (address) { + return _requireOwned(tokenId); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual returns (string memory) { + _requireOwned(tokenId); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : ""; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual { + _approve(to, tokenId, _msgSender()); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual returns (address) { + _requireOwned(tokenId); + + return _getApproved(tokenId); + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual { + if (to == address(0)) { + revert ERC721InvalidReceiver(address(0)); + } + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + address previousOwner = _update(to, tokenId, _msgSender()); + if (previousOwner != from) { + revert ERC721IncorrectOwner(from, tokenId, previousOwner); + } + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual { + transferFrom(from, to, tokenId); + _checkOnERC721Received(from, to, tokenId, data); + } + + /** + * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + * + * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the + * core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances + * consistent with ownership. The invariant to preserve is 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`. + */ + function _ownerOf(uint256 tokenId) internal view virtual returns (address) { + return _owners[tokenId]; + } + + /** + * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. + */ + function _getApproved(uint256 tokenId) internal view virtual returns (address) { + return _tokenApprovals[tokenId]; + } + + /** + * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in + * particular (ignoring whether it is owned by `owner`). + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + */ + function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) { + return + spender != address(0) && + (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender); + } + + /** + * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. + * Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets + * the `spender` for the specific `tokenId`. + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + */ + function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual { + if (!_isAuthorized(owner, spender, tokenId)) { + if (owner == address(0)) { + revert ERC721NonexistentToken(tokenId); + } else { + revert ERC721InsufficientApproval(spender, tokenId); + } + } + } + + /** + * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. + * + * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that + * a uint256 would ever overflow from increments when these increments are bounded to uint128 values. + * + * WARNING: Increasing an account's balance using this function tends to be paired with an override of the + * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership + * remain consistent with one another. + */ + function _increaseBalance(address account, uint128 value) internal virtual { + unchecked { + _balances[account] += value; + } + } + + /** + * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner + * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that + * `auth` is either the owner of the token, or approved to operate on the token (by the owner). + * + * Emits a {Transfer} event. + * + * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}. + */ + function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) { + address from = _ownerOf(tokenId); + + // Perform (optional) operator check + if (auth != address(0)) { + _checkAuthorized(from, auth, tokenId); + } + + // Execute the update + if (from != address(0)) { + // Clear approval. No need to re-authorize or emit the Approval event + _approve(address(0), tokenId, address(0), false); + + unchecked { + _balances[from] -= 1; + } + } + + if (to != address(0)) { + unchecked { + _balances[to] += 1; + } + } + + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + + return from; + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal { + if (to == address(0)) { + revert ERC721InvalidReceiver(address(0)); + } + address previousOwner = _update(to, tokenId, address(0)); + if (previousOwner != address(0)) { + revert ERC721InvalidSender(address(0)); + } + } + + /** + * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { + _mint(to, tokenId); + _checkOnERC721Received(address(0), to, tokenId, data); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This is an internal function that does not check if the sender is authorized to operate on the token. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal { + address previousOwner = _update(address(0), tokenId, address(0)); + if (previousOwner == address(0)) { + revert ERC721NonexistentToken(tokenId); + } + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal { + if (to == address(0)) { + revert ERC721InvalidReceiver(address(0)); + } + address previousOwner = _update(to, tokenId, address(0)); + if (previousOwner == address(0)) { + revert ERC721NonexistentToken(tokenId); + } else if (previousOwner != from) { + revert ERC721IncorrectOwner(from, tokenId, previousOwner); + } + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients + * are aware of the ERC721 standard to prevent tokens from being forever locked. + * + * `data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is like {safeTransferFrom} in the sense that it invokes + * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `tokenId` token must exist and be owned by `from`. + * - `to` cannot be the zero address. + * - `from` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId) internal { + _safeTransfer(from, to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { + _transfer(from, to, tokenId); + _checkOnERC721Received(from, to, tokenId, data); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is + * either the owner of the token, or approved to operate on all tokens held by this owner. + * + * Emits an {Approval} event. + * + * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. + */ + function _approve(address to, uint256 tokenId, address auth) internal { + _approve(to, tokenId, auth, true); + } + + /** + * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not + * emitted in the context of transfers. + */ + function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual { + // Avoid reading the owner unless necessary + if (emitEvent || auth != address(0)) { + address owner = _requireOwned(tokenId); + + // We do not use _isAuthorized because single-token approvals should not be able to call approve + if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) { + revert ERC721InvalidApprover(auth); + } + + if (emitEvent) { + emit Approval(owner, to, tokenId); + } + } + + _tokenApprovals[tokenId] = to; + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Requirements: + * - operator can't be the address zero. + * + * Emits an {ApprovalForAll} event. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + if (operator == address(0)) { + revert ERC721InvalidOperator(operator); + } + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). + * Returns the owner. + * + * Overrides to ownership logic should be done to {_ownerOf}. + */ + function _requireOwned(uint256 tokenId) internal view returns (address) { + address owner = _ownerOf(tokenId); + if (owner == address(0)) { + revert ERC721NonexistentToken(tokenId); + } + return owner; + } + + /** + * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the + * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param data bytes optional data to send along with the call + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private { + if (to.code.length > 0) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { + if (retval != IERC721Receiver.onERC721Received.selector) { + revert ERC721InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + revert ERC721InvalidReceiver(to); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/IERC721.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/IERC721.sol new file mode 100644 index 0000000..12f3236 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/IERC721.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon + * a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or + * {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon + * a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the address zero. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/IERC721Receiver.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/IERC721Receiver.sol new file mode 100644 index 0000000..f9dc133 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/IERC721Receiver.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) + +pragma solidity ^0.8.20; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be + * reverted. + * + * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/README.adoc new file mode 100644 index 0000000..40ae919 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/README.adoc @@ -0,0 +1,67 @@ += ERC 721 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc721 + +This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-721[ERC721 Non-Fungible Token Standard]. + +TIP: For a walk through on how to create an ERC721 token read our xref:ROOT:erc721.adoc[ERC721 guide]. + +The EIP specifies four interfaces: + +* {IERC721}: Core functionality required in all compliant implementation. +* {IERC721Metadata}: Optional extension that adds name, symbol, and token URI, almost always included. +* {IERC721Enumerable}: Optional extension that allows enumerating the tokens on chain, often not included since it requires large gas overhead. +* {IERC721Receiver}: An interface that must be implemented by contracts if they want to accept tokens through `safeTransferFrom`. + +OpenZeppelin Contracts provides implementations of all four interfaces: + +* {ERC721}: The core and metadata extensions, with a base URI mechanism. +* {ERC721Enumerable}: The enumerable extension. +* {ERC721Holder}: A bare bones implementation of the receiver interface. + +Additionally there are a few of other extensions: + +* {ERC721Consecutive}: An implementation of https://eips.ethereum.org/EIPS/eip-2309[ERC2309] for minting batchs of tokens during construction, in accordance with ERC721. +* {ERC721URIStorage}: A more flexible but more expensive way of storing metadata. +* {ERC721Votes}: Support for voting and vote delegation. +* {ERC721Royalty}: A way to signal royalty information following ERC2981. +* {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. + +== Core + +{{IERC721}} + +{{IERC721Metadata}} + +{{IERC721Enumerable}} + +{{ERC721}} + +{{ERC721Enumerable}} + +{{IERC721Receiver}} + +== Extensions + +{{ERC721Pausable}} + +{{ERC721Burnable}} + +{{ERC721Consecutive}} + +{{ERC721URIStorage}} + +{{ERC721Votes}} + +{{ERC721Royalty}} + +{{ERC721Wrapper}} + +== Utilities + +{{ERC721Holder}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Burnable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Burnable.sol new file mode 100644 index 0000000..2a150af --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Burnable.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Burnable.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Context} from "../../../utils/Context.sol"; + +/** + * @title ERC721 Burnable Token + * @dev ERC721 Token that can be burned (destroyed). + */ +abstract contract ERC721Burnable is Context, ERC721 { + /** + * @dev Burns `tokenId`. See {ERC721-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) public virtual { + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + _update(address(0), tokenId, _msgSender()); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Consecutive.sol new file mode 100644 index 0000000..0d6cbc7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Consecutive.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {IERC2309} from "../../../interfaces/IERC2309.sol"; +import {BitMaps} from "../../../utils/structs/BitMaps.sol"; +import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; + +/** + * @dev Implementation of the ERC2309 "Consecutive Transfer Extension" as defined in + * https://eips.ethereum.org/EIPS/eip-2309[EIP-2309]. + * + * This extension allows the minting of large batches of tokens, during contract construction only. For upgradeable + * contracts this implies that batch minting is only available during proxy deployment, and not in subsequent upgrades. + * These batches are limited to 5000 tokens at a time by default to accommodate off-chain indexers. + * + * Using this extension removes the ability to mint single tokens during contract construction. This ability is + * regained after construction. During construction, only batch minting is allowed. + * + * IMPORTANT: This extension does not call the {_update} function for tokens minted in batch. Any logic added to this + * function through overrides will not be triggered when token are minted in batch. You may want to also override + * {_increaseBalance} or {_mintConsecutive} to account for these mints. + * + * IMPORTANT: When overriding {_mintConsecutive}, be careful about call ordering. {ownerOf} may return invalid + * values during the {_mintConsecutive} execution if the super call is not called first. To be safe, execute the + * super call before your custom logic. + */ +abstract contract ERC721Consecutive is IERC2309, ERC721 { + using BitMaps for BitMaps.BitMap; + using Checkpoints for Checkpoints.Trace160; + + Checkpoints.Trace160 private _sequentialOwnership; + BitMaps.BitMap private _sequentialBurn; + + /** + * @dev Batch mint is restricted to the constructor. + * Any batch mint not emitting the {IERC721-Transfer} event outside of the constructor + * is non-ERC721 compliant. + */ + error ERC721ForbiddenBatchMint(); + + /** + * @dev Exceeds the max amount of mints per batch. + */ + error ERC721ExceededMaxBatchMint(uint256 batchSize, uint256 maxBatch); + + /** + * @dev Individual minting is not allowed. + */ + error ERC721ForbiddenMint(); + + /** + * @dev Batch burn is not supported. + */ + error ERC721ForbiddenBatchBurn(); + + /** + * @dev Maximum size of a batch of consecutive tokens. This is designed to limit stress on off-chain indexing + * services that have to record one entry per token, and have protections against "unreasonably large" batches of + * tokens. + * + * NOTE: Overriding the default value of 5000 will not cause on-chain issues, but may result in the asset not being + * correctly supported by off-chain indexing services (including marketplaces). + */ + function _maxBatchSize() internal view virtual returns (uint96) { + return 5000; + } + + /** + * @dev See {ERC721-_ownerOf}. Override that checks the sequential ownership structure for tokens that have + * been minted as part of a batch, and not yet transferred. + */ + function _ownerOf(uint256 tokenId) internal view virtual override returns (address) { + address owner = super._ownerOf(tokenId); + + // If token is owned by the core, or beyond consecutive range, return base value + if (owner != address(0) || tokenId > type(uint96).max || tokenId < _firstConsecutiveId()) { + return owner; + } + + // Otherwise, check the token was not burned, and fetch ownership from the anchors + // Note: no need for safe cast, we know that tokenId <= type(uint96).max + return _sequentialBurn.get(tokenId) ? address(0) : address(_sequentialOwnership.lowerLookup(uint96(tokenId))); + } + + /** + * @dev Mint a batch of tokens of length `batchSize` for `to`. Returns the token id of the first token minted in the + * batch; if `batchSize` is 0, returns the number of consecutive ids minted so far. + * + * Requirements: + * + * - `batchSize` must not be greater than {_maxBatchSize}. + * - The function is called in the constructor of the contract (directly or indirectly). + * + * CAUTION: Does not emit a `Transfer` event. This is ERC721 compliant as long as it is done inside of the + * constructor, which is enforced by this function. + * + * CAUTION: Does not invoke `onERC721Received` on the receiver. + * + * Emits a {IERC2309-ConsecutiveTransfer} event. + */ + function _mintConsecutive(address to, uint96 batchSize) internal virtual returns (uint96) { + uint96 next = _nextConsecutiveId(); + + // minting a batch of size 0 is a no-op + if (batchSize > 0) { + if (address(this).code.length > 0) { + revert ERC721ForbiddenBatchMint(); + } + if (to == address(0)) { + revert ERC721InvalidReceiver(address(0)); + } + + uint256 maxBatchSize = _maxBatchSize(); + if (batchSize > maxBatchSize) { + revert ERC721ExceededMaxBatchMint(batchSize, maxBatchSize); + } + + // push an ownership checkpoint & emit event + uint96 last = next + 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`. + _increaseBalance(to, batchSize); + + emit ConsecutiveTransfer(next, last, address(0), to); + } + + return next; + } + + /** + * @dev See {ERC721-_update}. Override version that restricts normal minting to after construction. + * + * WARNING: Using {ERC721Consecutive} prevents minting during construction in favor of {_mintConsecutive}. + * After construction, {_mintConsecutive} is no longer available and minting through {_update} becomes available. + */ + function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) { + address previousOwner = super._update(to, tokenId, auth); + + // only mint after construction + if (previousOwner == address(0) && address(this).code.length == 0) { + revert ERC721ForbiddenMint(); + } + + // record burn + if ( + to == address(0) && // if we burn + tokenId < _nextConsecutiveId() && // and the tokenId was minted in a batch + !_sequentialBurn.get(tokenId) // and the token was never marked as burnt + ) { + _sequentialBurn.set(tokenId); + } + + return previousOwner; + } + + /** + * @dev Used to offset the first token id in {_nextConsecutiveId} + */ + function _firstConsecutiveId() internal view virtual returns (uint96) { + return 0; + } + + /** + * @dev Returns the next tokenId to mint using {_mintConsecutive}. It will return {_firstConsecutiveId} + * if no consecutive tokenId has been minted before. + */ + function _nextConsecutiveId() private view returns (uint96) { + (bool exists, uint96 latestId, ) = _sequentialOwnership.latestCheckpoint(); + return exists ? latestId + 1 : _firstConsecutiveId(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Enumerable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Enumerable.sol new file mode 100644 index 0000000..cbf3e03 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Enumerable.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {IERC721Enumerable} from "./IERC721Enumerable.sol"; +import {IERC165} from "../../../utils/introspection/ERC165.sol"; + +/** + * @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability + * of all the token ids in the contract as well as all token ids owned by each account. + * + * CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`, + * interfere with enumerability and should not be used together with `ERC721Enumerable`. + */ +abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { + mapping(address owner => mapping(uint256 index => uint256)) private _ownedTokens; + mapping(uint256 tokenId => uint256) private _ownedTokensIndex; + + uint256[] private _allTokens; + mapping(uint256 tokenId => uint256) private _allTokensIndex; + + /** + * @dev An `owner`'s token query was out of bounds for `index`. + * + * NOTE: The owner being `address(0)` indicates a global out of bounds index. + */ + error ERC721OutOfBoundsIndex(address owner, uint256 index); + + /** + * @dev Batch mint is not allowed. + */ + error ERC721EnumerableForbiddenBatchMint(); + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) { + if (index >= balanceOf(owner)) { + revert ERC721OutOfBoundsIndex(owner, index); + } + return _ownedTokens[owner][index]; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual returns (uint256) { + return _allTokens.length; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual returns (uint256) { + if (index >= totalSupply()) { + revert ERC721OutOfBoundsIndex(address(0), index); + } + return _allTokens[index]; + } + + /** + * @dev See {ERC721-_update}. + */ + function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) { + address previousOwner = super._update(to, tokenId, auth); + + if (previousOwner == address(0)) { + _addTokenToAllTokensEnumeration(tokenId); + } else if (previousOwner != to) { + _removeTokenFromOwnerEnumeration(previousOwner, tokenId); + } + if (to == address(0)) { + _removeTokenFromAllTokensEnumeration(tokenId); + } else if (previousOwner != to) { + _addTokenToOwnerEnumeration(to, tokenId); + } + + return previousOwner; + } + + /** + * @dev Private function to add a token to this extension's ownership-tracking data structures. + * @param to address representing the new owner of the given token ID + * @param tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + uint256 length = balanceOf(to) - 1; + _ownedTokens[to][length] = tokenId; + _ownedTokensIndex[tokenId] = length; + } + + /** + * @dev Private function to add a token to this extension's token tracking data structures. + * @param tokenId uint256 ID of the token to be added to the tokens list + */ + function _addTokenToAllTokensEnumeration(uint256 tokenId) private { + _allTokensIndex[tokenId] = _allTokens.length; + _allTokens.push(tokenId); + } + + /** + * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that + * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for + * gas optimizations e.g. when performing a transfer operation (avoiding double writes). + * This has O(1) time complexity, but alters the order of the _ownedTokens array. + * @param from address representing the previous owner of the given token ID + * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { + // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = balanceOf(from); + uint256 tokenIndex = _ownedTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + + _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + } + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[tokenId]; + delete _ownedTokens[from][lastTokenIndex]; + } + + /** + * @dev Private function to remove a token from this extension's token tracking data structures. + * This has O(1) time complexity, but alters the order of the _allTokens array. + * @param tokenId uint256 ID of the token to be removed from the tokens list + */ + function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { + // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = _allTokens.length - 1; + uint256 tokenIndex = _allTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so + // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding + // an 'if' statement (like in _removeTokenFromOwnerEnumeration) + uint256 lastTokenId = _allTokens[lastTokenIndex]; + + _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + + // This also deletes the contents at the last position of the array + delete _allTokensIndex[tokenId]; + _allTokens.pop(); + } + + /** + * See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch + */ + function _increaseBalance(address account, uint128 amount) internal virtual override { + if (amount > 0) { + revert ERC721EnumerableForbiddenBatchMint(); + } + super._increaseBalance(account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Pausable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Pausable.sol new file mode 100644 index 0000000..0b34fd9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC721 token with pausable token transfers, minting and burning. + * + * 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 pause mechanism of the contract unreachable, and thus unusable. + */ +abstract contract ERC721Pausable is ERC721, Pausable { + /** + * @dev See {ERC721-_update}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _update( + address to, + uint256 tokenId, + address auth + ) internal virtual override whenNotPaused returns (address) { + return super._update(to, tokenId, auth); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Royalty.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Royalty.sol new file mode 100644 index 0000000..be98ec7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Royalty.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Royalty.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {ERC2981} from "../../common/ERC2981.sol"; + +/** + * @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment + * information. + * + * Royalty information can be specified globally for all token ids via {ERC2981-_setDefaultRoyalty}, and/or individually + * for specific token ids via {ERC2981-_setTokenRoyalty}. The latter takes precedence over the first. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + */ +abstract contract ERC721Royalty is ERC2981, ERC721 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) { + return super.supportsInterface(interfaceId); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721URIStorage.sol new file mode 100644 index 0000000..2584cb5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721URIStorage.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721URIStorage.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Strings} from "../../../utils/Strings.sol"; +import {IERC4906} from "../../../interfaces/IERC4906.sol"; +import {IERC165} from "../../../interfaces/IERC165.sol"; + +/** + * @dev ERC721 token with storage based token URI management. + */ +abstract contract ERC721URIStorage is IERC4906, ERC721 { + using Strings for uint256; + + // Interface ID as defined in ERC-4906. This does not correspond to a traditional interface ID as ERC-4906 only + // defines events and does not include any external function. + bytes4 private constant ERC4906_INTERFACE_ID = bytes4(0x49064906); + + // Optional mapping for token URIs + mapping(uint256 tokenId => string) private _tokenURIs; + + /** + * @dev See {IERC165-supportsInterface} + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { + return interfaceId == ERC4906_INTERFACE_ID || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + _requireOwned(tokenId); + + string memory _tokenURI = _tokenURIs[tokenId]; + string memory base = _baseURI(); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + // If both are set, concatenate the baseURI and tokenURI (via string.concat). + if (bytes(_tokenURI).length > 0) { + return string.concat(base, _tokenURI); + } + + return super.tokenURI(tokenId); + } + + /** + * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. + * + * Emits {MetadataUpdate}. + */ + function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { + _tokenURIs[tokenId] = _tokenURI; + emit MetadataUpdate(tokenId); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Votes.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Votes.sol new file mode 100644 index 0000000..5628715 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Votes.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Votes.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Votes} from "../../../governance/utils/Votes.sol"; + +/** + * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts + * as 1 vote unit. + * + * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost + * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of + * the votes in governance decisions, or they can delegate to themselves to be their own representative. + */ +abstract contract ERC721Votes is ERC721, Votes { + /** + * @dev See {ERC721-_update}. Adjusts votes when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) { + address previousOwner = super._update(to, tokenId, auth); + + _transferVotingUnits(previousOwner, to, 1); + + return previousOwner; + } + + /** + * @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); + } + + /** + * @dev See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch. + */ + function _increaseBalance(address account, uint128 amount) internal virtual override { + super._increaseBalance(account, amount); + _transferVotingUnits(address(0), account, amount); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Wrapper.sol new file mode 100644 index 0000000..e091bdd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Wrapper.sol) + +pragma solidity ^0.8.20; + +import {IERC721, ERC721} from "../ERC721.sol"; +import {IERC721Receiver} from "../IERC721Receiver.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. + */ +abstract contract ERC721Wrapper is ERC721, IERC721Receiver { + IERC721 private immutable _underlying; + + /** + * @dev The received ERC721 token couldn't be wrapped. + */ + error ERC721UnsupportedToken(address token); + + 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) { + uint256 length = tokenIds.length; + for (uint256 i = 0; i < length; ++i) { + 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; + } + + /** + * @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]; + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + _update(address(0), tokenId, _msgSender()); + // 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 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 from, uint256 tokenId, bytes memory) public virtual returns (bytes4) { + if (address(underlying()) != _msgSender()) { + revert ERC721UnsupportedToken(_msgSender()); + } + _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) { + address owner = underlying().ownerOf(tokenId); + if (owner != address(this)) { + revert ERC721IncorrectOwner(address(this), tokenId, owner); + } + _safeMint(account, tokenId); + return tokenId; + } + + /** + * @dev Returns the underlying token. + */ + function underlying() public view virtual returns (IERC721) { + return _underlying; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/IERC721Enumerable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/IERC721Enumerable.sol new file mode 100644 index 0000000..7a09cc6 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/IERC721Enumerable.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/IERC721Metadata.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/IERC721Metadata.sol new file mode 100644 index 0000000..e9e00fa --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/extensions/IERC721Metadata.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/utils/ERC721Holder.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/utils/ERC721Holder.sol new file mode 100644 index 0000000..6bb23ac --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/ERC721/utils/ERC721Holder.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol) + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../IERC721Receiver.sol"; + +/** + * @dev Implementation of the {IERC721Receiver} interface. + * + * Accepts all token transfers. + * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or + * {IERC721-setApprovalForAll}. + */ +abstract contract ERC721Holder is IERC721Receiver { + /** + * @dev See {IERC721Receiver-onERC721Received}. + * + * Always returns `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { + return this.onERC721Received.selector; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/common/ERC2981.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/token/common/ERC2981.sol new file mode 100644 index 0000000..fce0251 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/common/ERC2981.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/common/ERC2981.sol) + +pragma solidity ^0.8.20; + +import {IERC2981} from "../../interfaces/IERC2981.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. + * + * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for + * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. + * + * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the + * fee is specified in basis points by default. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + */ +abstract contract ERC2981 is IERC2981, ERC165 { + struct RoyaltyInfo { + address receiver; + uint96 royaltyFraction; + } + + RoyaltyInfo private _defaultRoyaltyInfo; + mapping(uint256 tokenId => RoyaltyInfo) private _tokenRoyaltyInfo; + + /** + * @dev The default royalty set is invalid (eg. (numerator / denominator) >= 1). + */ + error ERC2981InvalidDefaultRoyalty(uint256 numerator, uint256 denominator); + + /** + * @dev The default royalty receiver is invalid. + */ + error ERC2981InvalidDefaultRoyaltyReceiver(address receiver); + + /** + * @dev The royalty set for an specific `tokenId` is invalid (eg. (numerator / denominator) >= 1). + */ + error ERC2981InvalidTokenRoyalty(uint256 tokenId, uint256 numerator, uint256 denominator); + + /** + * @dev The royalty receiver for `tokenId` is invalid. + */ + error ERC2981InvalidTokenRoyaltyReceiver(uint256 tokenId, address receiver); + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @inheritdoc IERC2981 + */ + function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address, uint256) { + RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId]; + + if (royalty.receiver == address(0)) { + royalty = _defaultRoyaltyInfo; + } + + uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator(); + + return (royalty.receiver, royaltyAmount); + } + + /** + * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a + * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an + * override. + */ + function _feeDenominator() internal pure virtual returns (uint96) { + return 10000; + } + + /** + * @dev Sets the royalty information that all ids in this contract will default to. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { + uint256 denominator = _feeDenominator(); + if (feeNumerator > denominator) { + // Royalty fee will exceed the sale price + revert ERC2981InvalidDefaultRoyalty(feeNumerator, denominator); + } + if (receiver == address(0)) { + revert ERC2981InvalidDefaultRoyaltyReceiver(address(0)); + } + + _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Removes default royalty information. + */ + function _deleteDefaultRoyalty() internal virtual { + delete _defaultRoyaltyInfo; + } + + /** + * @dev Sets the royalty information for a specific token id, overriding the global default. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { + uint256 denominator = _feeDenominator(); + if (feeNumerator > denominator) { + // Royalty fee will exceed the sale price + revert ERC2981InvalidTokenRoyalty(tokenId, feeNumerator, denominator); + } + if (receiver == address(0)) { + revert ERC2981InvalidTokenRoyaltyReceiver(tokenId, address(0)); + } + + _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Resets royalty information for the token id back to the global default. + */ + function _resetTokenRoyalty(uint256 tokenId) internal virtual { + delete _tokenRoyaltyInfo[tokenId]; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/token/common/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/token/common/README.adoc new file mode 100644 index 0000000..af61674 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/token/common/README.adoc @@ -0,0 +1,10 @@ += Common (Tokens) + +Functionality that is common to multiple token standards. + +* {ERC2981}: NFT Royalties compatible with both ERC721 and ERC1155. +** For ERC721 consider {ERC721Royalty} which clears the royalty information from storage on burn. + +== Contracts + +{{ERC2981}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Address.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Address.sol new file mode 100644 index 0000000..b7e3059 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Address.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev The ETH balance of the account is not enough to perform the operation. + */ + error AddressInsufficientBalance(address account); + + /** + * @dev There's no code at `target` (it is not a contract). + */ + error AddressEmptyCode(address target); + + /** + * @dev A call to an address target failed. The target may have reverted. + */ + error FailedInnerCall(); + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + if (address(this).balance < amount) { + revert AddressInsufficientBalance(address(this)); + } + + (bool success, ) = recipient.call{value: amount}(""); + if (!success) { + revert FailedInnerCall(); + } + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason or custom error, it is bubbled + * up by this function (like regular Solidity function calls). However, if + * the call reverted with no returned reason, this function reverts with a + * {FailedInnerCall} error. + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + if (address(this).balance < value) { + revert AddressInsufficientBalance(address(this)); + } + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target + * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an + * unsuccessful call. + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata + ) internal view returns (bytes memory) { + if (!success) { + _revert(returndata); + } else { + // only check if target is a contract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + if (returndata.length == 0 && target.code.length == 0) { + revert AddressEmptyCode(target); + } + return returndata; + } + } + + /** + * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the + * revert reason or with a default {FailedInnerCall} error. + */ + function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { + if (!success) { + _revert(returndata); + } else { + return returndata; + } + } + + /** + * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. + */ + function _revert(bytes memory returndata) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert FailedInnerCall(); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Arrays.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Arrays.sol new file mode 100644 index 0000000..aaab3ce --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Arrays.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol) + +pragma solidity ^0.8.20; + +import {StorageSlot} from "./StorageSlot.sol"; +import {Math} from "./math/Math.sol"; + +/** + * @dev Collection of functions related to array types. + */ +library Arrays { + using StorageSlot for bytes32; + + /** + * @dev Searches a sorted `array` and returns the first index that contains + * a value greater or equal to `element`. If no such index exists (i.e. all + * values in the array are strictly less than `element`), the array length is + * returned. Time complexity O(log n). + * + * `array` is expected to be sorted in ascending order, and to contain no + * repeated elements. + */ + function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { + uint256 low = 0; + uint256 high = array.length; + + if (high == 0) { + return 0; + } + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds towards zero (it does integer division with truncation). + if (unsafeAccess(array, mid).value > element) { + high = mid; + } else { + low = mid + 1; + } + } + + // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. + if (low > 0 && unsafeAccess(array, low - 1).value == element) { + return low - 1; + } else { + return low; + } + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getAddressSlot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getBytes32Slot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getUint256Slot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Base64.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Base64.sol new file mode 100644 index 0000000..f8547d1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Base64.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Base64.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + /// @solidity memory-safe-assembly + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Context.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Context.sol new file mode 100644 index 0000000..9037dcd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Context.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Create2.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Create2.sol new file mode 100644 index 0000000..ad1cd5f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Create2.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Create2.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. + * `CREATE2` can be used to compute in advance the address where a smart + * contract will be deployed, which allows for interesting new mechanisms known + * as 'counterfactual interactions'. + * + * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more + * information. + */ +library Create2 { + /** + * @dev Not enough balance for performing a CREATE2 deploy. + */ + error Create2InsufficientBalance(uint256 balance, uint256 needed); + + /** + * @dev There's no code to deploy. + */ + error Create2EmptyBytecode(); + + /** + * @dev The deployment failed. + */ + error Create2FailedDeployment(); + + /** + * @dev Deploys a contract using `CREATE2`. The address where the contract + * will be deployed can be known in advance via {computeAddress}. + * + * The bytecode for a contract can be obtained from Solidity with + * `type(contractName).creationCode`. + * + * Requirements: + * + * - `bytecode` must not be empty. + * - `salt` must have not been used for `bytecode` already. + * - the factory must have a balance of at least `amount`. + * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. + */ + function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { + if (address(this).balance < amount) { + revert Create2InsufficientBalance(address(this).balance, amount); + } + if (bytecode.length == 0) { + revert Create2EmptyBytecode(); + } + /// @solidity memory-safe-assembly + assembly { + addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) + } + if (addr == address(0)) { + revert Create2FailedDeployment(); + } + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the + * `bytecodeHash` or `salt` will result in a new destination address. + */ + function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { + return computeAddress(salt, bytecodeHash, address(this)); + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at + * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. + */ + function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) // Get free memory pointer + + // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | + // |-------------------|---------------------------------------------------------------------------| + // | bytecodeHash | CCCCCCCCCCCCC...CC | + // | salt | BBBBBBBBBBBBB...BB | + // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | + // | 0xFF | FF | + // |-------------------|---------------------------------------------------------------------------| + // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | + // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | + + mstore(add(ptr, 0x40), bytecodeHash) + mstore(add(ptr, 0x20), salt) + mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes + let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff + mstore8(start, 0xff) + addr := keccak256(start, 85) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Multicall.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Multicall.sol new file mode 100644 index 0000000..2d925a9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Multicall.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Multicall.sol) + +pragma solidity ^0.8.20; + +import {Address} from "./Address.sol"; + +/** + * @dev Provides a function to batch together multiple calls in a single external call. + */ +abstract contract Multicall { + /** + * @dev Receives and executes a batch of function calls on this contract. + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { + results = new bytes[](data.length); + for (uint256 i = 0; i < data.length; i++) { + results[i] = Address.functionDelegateCall(address(this), data[i]); + } + return results; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Nonces.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Nonces.sol new file mode 100644 index 0000000..37451ff --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Nonces.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) +pragma solidity ^0.8.20; + +/** + * @dev Provides tracking nonces for addresses. Nonces will only increment. + */ +abstract contract Nonces { + /** + * @dev The nonce used for an `account` is not the expected current nonce. + */ + error InvalidAccountNonce(address account, uint256 currentNonce); + + mapping(address account => uint256) private _nonces; + + /** + * @dev Returns the next unused nonce for an address. + */ + function nonces(address owner) public view virtual returns (uint256) { + return _nonces[owner]; + } + + /** + * @dev Consumes a nonce. + * + * Returns the current value and increments nonce. + */ + function _useNonce(address owner) internal virtual returns (uint256) { + // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be + // decremented or reset. This guarantees that the nonce never overflows. + unchecked { + // It is important to do x++ and not ++x here. + return _nonces[owner]++; + } + } + + /** + * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. + */ + function _useCheckedNonce(address owner, uint256 nonce) internal virtual { + uint256 current = _useNonce(owner); + if (nonce != current) { + revert InvalidAccountNonce(owner, current); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Pausable.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Pausable.sol new file mode 100644 index 0000000..312f1cb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Pausable.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +/** + * @dev Contract module which allows children to implement an emergency stop + * mechanism that can be triggered by an authorized account. + * + * This module is used through inheritance. It will make available the + * modifiers `whenNotPaused` and `whenPaused`, which can be applied to + * the functions of your contract. Note that they will not be pausable by + * simply including this module, only once the modifiers are put in place. + */ +abstract contract Pausable is Context { + bool private _paused; + + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); + + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); + + /** + * @dev The operation failed because the contract is paused. + */ + error EnforcedPause(); + + /** + * @dev The operation failed because the contract is not paused. + */ + error ExpectedPause(); + + /** + * @dev Initializes the contract in unpaused state. + */ + constructor() { + _paused = false; + } + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + _requireNotPaused(); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + * + * Requirements: + * + * - The contract must be paused. + */ + modifier whenPaused() { + _requirePaused(); + _; + } + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** + * @dev Throws if the contract is paused. + */ + function _requireNotPaused() internal view virtual { + if (paused()) { + revert EnforcedPause(); + } + } + + /** + * @dev Throws if the contract is not paused. + */ + function _requirePaused() internal view virtual { + if (!paused()) { + revert ExpectedPause(); + } + } + + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(_msgSender()); + } + + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(_msgSender()); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/README.adoc b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/README.adoc new file mode 100644 index 0000000..d88b001 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/README.adoc @@ -0,0 +1,88 @@ += Utilities + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils + +Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives. + + * {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions. + * {Pausable}: A common emergency response mechanism that can pause functionality while a remediation is pending. + * {SafeCast}: Checked downcasting functions to avoid silent truncation. + * {Math}, {SignedMath}: Implementation of various arithmetic functions. + * {Multicall}: Simple way to batch together multiple calls in a single external call. + * {Create2}: Wrapper around the https://blog.openzeppelin.com/getting-the-most-out-of-create2/[`CREATE2` EVM opcode] for safe use without having to deal with low-level assembly. + * {EnumerableMap}: A type like Solidity's https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`], but with key-value _enumeration_: this will let you know how many entries a mapping has, and iterate over them (which is not possible with `mapping`). + * {EnumerableSet}: Like {EnumerableMap}, but for https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets]. Can be used to store privileged accounts, issued IDs, etc. + +[NOTE] +==== +Because Solidity does not support generic types, {EnumerableMap} and {EnumerableSet} are specialized to a limited number of key-value types. +==== + +== Math + +{{Math}} + +{{SignedMath}} + +{{SafeCast}} + +== Cryptography + +{{ECDSA}} + +{{MessageHashUtils}} + +{{SignatureChecker}} + +{{MerkleProof}} + +{{EIP712}} + +== Security + +{{ReentrancyGuard}} + +{{Pausable}} + +== Introspection + +This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[type introspection] of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_. + +Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors. + +{{IERC165}} + +{{ERC165}} + +{{ERC165Checker}} + +== Data Structures + +{{BitMaps}} + +{{EnumerableMap}} + +{{EnumerableSet}} + +{{DoubleEndedQueue}} + +{{Checkpoints}} + +== Libraries + +{{Create2}} + +{{Address}} + +{{Arrays}} + +{{Base64}} + +{{Strings}} + +{{ShortStrings}} + +{{StorageSlot}} + +{{Multicall}} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/ReentrancyGuard.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/ReentrancyGuard.sol new file mode 100644 index 0000000..291d92f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/ReentrancyGuard.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant NOT_ENTERED = 1; + uint256 private constant ENTERED = 2; + + uint256 private _status; + + /** + * @dev Unauthorized reentrant call. + */ + error ReentrancyGuardReentrantCall(); + + constructor() { + _status = NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + _nonReentrantBefore(); + _; + _nonReentrantAfter(); + } + + function _nonReentrantBefore() private { + // On the first call to nonReentrant, _status will be NOT_ENTERED + if (_status == ENTERED) { + revert ReentrancyGuardReentrantCall(); + } + + // Any calls to nonReentrant after this point will fail + _status = ENTERED; + } + + function _nonReentrantAfter() private { + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = NOT_ENTERED; + } + + /** + * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a + * `nonReentrant` function in the call stack. + */ + function _reentrancyGuardEntered() internal view returns (bool) { + return _status == ENTERED; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/ShortStrings.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/ShortStrings.sol new file mode 100644 index 0000000..fdfe774 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/ShortStrings.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol) + +pragma solidity ^0.8.20; + +import {StorageSlot} from "./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 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: + * + * ```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 { + // Used as an identifier for strings longer than 31 bytes. + bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; + + error StringTooLong(string str); + error InvalidShortString(); + + /** + * @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 = byteLength(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 byteLength(ShortString sstr) internal pure returns (uint256) { + uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; + if (result > 31) { + revert InvalidShortString(); + } + return result; + } + + /** + * @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(FALLBACK_SENTINEL); + } + } + + /** + * @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 (ShortString.unwrap(value) != FALLBACK_SENTINEL) { + return toString(value); + } else { + 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/lib/openzeppelin-contracts-v5.0.0/contracts/utils/StorageSlot.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/StorageSlot.sol new file mode 100644 index 0000000..0841832 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/StorageSlot.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) +// This file was procedurally generated from scripts/generate/templates/StorageSlot.js. + +pragma solidity ^0.8.20; + +/** + * @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(newImplementation.code.length > 0); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * ``` + */ +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + struct StringSlot { + string value; + } + + struct BytesSlot { + bytes value; + } + + /** + * @dev Returns an `AddressSlot` with member `value` located at `slot`. + */ + function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + 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/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Strings.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Strings.sol new file mode 100644 index 0000000..b2c0a40 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/Strings.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) + +pragma solidity ^0.8.20; + +import {Math} from "./math/Math.sol"; +import {SignedMath} from "./math/SignedMath.sol"; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant HEX_DIGITS = "0123456789abcdef"; + uint8 private constant ADDRESS_LENGTH = 20; + + /** + * @dev The `value` string doesn't fit in the specified `length`. + */ + error StringsInsufficientHexLength(uint256 value, uint256 length); + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toStringSigned(int256 value) internal pure returns (string memory) { + return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + uint256 localValue = value; + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = HEX_DIGITS[localValue & 0xf]; + localValue >>= 4; + } + if (localValue != 0) { + revert StringsInsufficientHexLength(value, length); + } + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal + * representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/ECDSA.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/ECDSA.sol new file mode 100644 index 0000000..04b3e5e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/ECDSA.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. + * + * These functions can be used to verify that a message was signed by the holder + * of the private keys of a given address. + */ +library ECDSA { + enum RecoverError { + NoError, + InvalidSignature, + InvalidSignatureLength, + InvalidSignatureS + } + + /** + * @dev The signature derives the `address(0)`. + */ + error ECDSAInvalidSignature(); + + /** + * @dev The signature has an invalid length. + */ + error ECDSAInvalidSignatureLength(uint256 length); + + /** + * @dev The signature has an S value that is in the upper half order. + */ + error ECDSAInvalidSignatureS(bytes32 s); + + /** + * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not + * return address(0) without also returning an error description. Errors are documented using an enum (error type) + * and a bytes32 providing additional information about the error. + * + * If no error is returned, then the address can be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + * + * Documentation for signature generation: + * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] + * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] + */ + function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { + if (signature.length == 65) { + bytes32 r; + bytes32 s; + uint8 v; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + /// @solidity memory-safe-assembly + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + return tryRecover(hash, v, r, s); + } else { + return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature`. This address can then be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + */ + function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. + * + * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] + */ + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { + unchecked { + bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + // We do not check for an overflow here since the shift operation results in 0 or 1. + uint8 v = uint8((uint256(vs) >> 255) + 27); + return tryRecover(hash, v, r, s); + } + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. + */ + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function tryRecover( + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s + ) internal pure returns (address, RecoverError, bytes32) { + // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature + // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines + // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most + // signatures from current libraries generate a unique signature with an s-value in the lower half order. + // + // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value + // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or + // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept + // these malleable signatures as well. + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + return (address(0), RecoverError.InvalidSignatureS, s); + } + + // If the signature is valid (and not malleable), return the signer address + address signer = ecrecover(hash, v, r, s); + if (signer == address(0)) { + return (address(0), RecoverError.InvalidSignature, bytes32(0)); + } + + return (signer, RecoverError.NoError, bytes32(0)); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. + */ + function _throwError(RecoverError error, bytes32 errorArg) private pure { + if (error == RecoverError.NoError) { + return; // no error: do nothing + } else if (error == RecoverError.InvalidSignature) { + revert ECDSAInvalidSignature(); + } else if (error == RecoverError.InvalidSignatureLength) { + revert ECDSAInvalidSignatureLength(uint256(errorArg)); + } else if (error == RecoverError.InvalidSignatureS) { + revert ECDSAInvalidSignatureS(errorArg); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/EIP712.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/EIP712.sol new file mode 100644 index 0000000..8e548cd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/EIP712.sol @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) + +pragma solidity ^0.8.20; + +import {MessageHashUtils} from "./MessageHashUtils.sol"; +import {ShortStrings, ShortString} from "../ShortStrings.sol"; +import {IERC5267} from "../../interfaces/IERC5267.sol"; + +/** + * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. + * + * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose + * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract + * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to + * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. + * + * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding + * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA + * ({_hashTypedDataV4}). + * + * The implementation of the domain separator was designed to be as efficient as possible while still properly updating + * the chain id to protect against replay attacks on an eventual fork of the chain. + * + * 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. + * + * @custom:oz-upgrades-unsafe-allow state-variable-immutable + */ +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; + + bytes32 private immutable _hashedName; + bytes32 private immutable _hashedVersion; + + ShortString private immutable _name; + ShortString private immutable _version; + string private _nameFallback; + string private _versionFallback; + + /** + * @dev Initializes the domain separator and parameter caches. + * + * The meaning of `name` and `version` is specified in + * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: + * + * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. + * - `version`: the current major version of the signing domain. + * + * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart + * 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); + } + + /** + * @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(); + } + } + + function _buildDomainSeparator() private view returns (bytes32) { + return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); + } + + /** + * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this + * function returns the hash of the fully encoded EIP712 message for this domain. + * + * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: + * + * ```solidity + * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( + * keccak256("Mail(address to,string contents)"), + * mailTo, + * keccak256(bytes(mailContents)) + * ))); + * address signer = ECDSA.recover(digest, signature); + * ``` + */ + function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { + return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); + } + + /** + * @dev See {IERC-5267}. + */ + function eip712Domain() + public + view + virtual + returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ) + { + return ( + hex"0f", // 01111 + _EIP712Name(), + _EIP712Version(), + block.chainid, + address(this), + bytes32(0), + new uint256[](0) + ); + } + + /** + * @dev The name parameter for the EIP712 domain. + * + * NOTE: By default this function reads _name which is an immutable value. + * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). + */ + // solhint-disable-next-line func-name-mixedcase + function _EIP712Name() internal view returns (string memory) { + return _name.toStringWithFallback(_nameFallback); + } + + /** + * @dev The version parameter for the EIP712 domain. + * + * NOTE: By default this function reads _version which is an immutable value. + * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). + */ + // solhint-disable-next-line func-name-mixedcase + function _EIP712Version() internal view returns (string memory) { + return _version.toStringWithFallback(_versionFallback); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/MerkleProof.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/MerkleProof.sol new file mode 100644 index 0000000..525f5da --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/MerkleProof.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.20; + +/** + * @dev These functions deal with verification of Merkle Tree proofs. + * + * The tree and the proofs can be generated using our + * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. + * You will find a quickstart guide in the readme. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the Merkle tree could be reinterpreted as a leaf value. + * OpenZeppelin's JavaScript library generates Merkle trees that are safe + * against this attack out of the box. + */ +library MerkleProof { + /** + *@dev The multiproof provided is not valid. + */ + error MerkleProofInvalidMultiproof(); + + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Calldata version of {verify} + */ + function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProofCalldata(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = _hashPair(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @dev Calldata version of {processProof} + */ + function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = _hashPair(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by + * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + */ + function multiProofVerify( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProof(proof, proofFlags, leaves) == root; + } + + /** + * @dev Calldata version of {multiProofVerify} + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + */ + function multiProofVerifyCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProofCalldata(proof, proofFlags, leaves) == root; + } + + /** + * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction + * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another + * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false + * respectively. + * + * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree + * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the + * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). + */ + function processMultiProof( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32[] memory leaves + ) internal pure returns (bytes32 merkleRoot) { + // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by + // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the + // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of + // the Merkle tree. + uint256 leavesLen = leaves.length; + uint256 proofLen = proof.length; + uint256 totalHashes = proofFlags.length; + + // Check proof validity. + if (leavesLen + proofLen != totalHashes + 1) { + revert MerkleProofInvalidMultiproof(); + } + + // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using + // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". + bytes32[] memory hashes = new bytes32[](totalHashes); + uint256 leafPos = 0; + uint256 hashPos = 0; + uint256 proofPos = 0; + // At each step, we compute the next hash using two values: + // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we + // get the next hash. + // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the + // `proof` array. + for (uint256 i = 0; i < totalHashes; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = _hashPair(a, b); + } + + if (totalHashes > 0) { + if (proofPos != proofLen) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[totalHashes - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @dev Calldata version of {processMultiProof}. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + */ + function processMultiProofCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32[] memory leaves + ) internal pure returns (bytes32 merkleRoot) { + // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by + // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the + // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of + // the Merkle tree. + uint256 leavesLen = leaves.length; + uint256 proofLen = proof.length; + uint256 totalHashes = proofFlags.length; + + // Check proof validity. + if (leavesLen + proofLen != totalHashes + 1) { + revert MerkleProofInvalidMultiproof(); + } + + // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using + // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". + bytes32[] memory hashes = new bytes32[](totalHashes); + uint256 leafPos = 0; + uint256 hashPos = 0; + uint256 proofPos = 0; + // At each step, we compute the next hash using two values: + // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we + // get the next hash. + // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the + // `proof` array. + for (uint256 i = 0; i < totalHashes; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = _hashPair(a, b); + } + + if (totalHashes > 0) { + if (proofPos != proofLen) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[totalHashes - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @dev Sorts the pair (a, b) and hashes the result. + */ + function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { + return a < b ? _efficientHash(a, b) : _efficientHash(b, a); + } + + /** + * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory. + */ + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/MessageHashUtils.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/MessageHashUtils.sol new file mode 100644 index 0000000..8836693 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/MessageHashUtils.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) + +pragma solidity ^0.8.20; + +import {Strings} from "../Strings.sol"; + +/** + * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. + * + * The library provides methods for generating a hash of a message that conforms to the + * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] + * specifications. + */ +library MessageHashUtils { + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x45` (`personal_sign` messages). + * + * The digest is calculated by prefixing a bytes32 `messageHash` with + * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the + * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. + * + * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with + * keccak256, although any bytes32 value can be safely used because the final digest will + * be re-hashed. + * + * See {ECDSA-recover}. + */ + function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash + mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix + digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) + } + } + + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x45` (`personal_sign` messages). + * + * The digest is calculated by prefixing an arbitrary `message` with + * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the + * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. + * + * See {ECDSA-recover}. + */ + function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { + return + keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); + } + + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x00` (data with intended validator). + * + * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended + * `validator` address. Then hashing the result. + * + * See {ECDSA-recover}. + */ + function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(hex"19_00", validator, data)); + } + + /** + * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). + * + * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with + * `\x19\x01` and hashing the result. It corresponds to the hash signed by the + * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. + * + * See {ECDSA-recover}. + */ + function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(ptr, hex"19_01") + mstore(add(ptr, 0x02), domainSeparator) + mstore(add(ptr, 0x22), structHash) + digest := keccak256(ptr, 0x42) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/SignatureChecker.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/SignatureChecker.sol new file mode 100644 index 0000000..59a2c6d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/cryptography/SignatureChecker.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol) + +pragma solidity ^0.8.20; + +import {ECDSA} from "./ECDSA.sol"; +import {IERC1271} from "../../interfaces/IERC1271.sol"; + +/** + * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA + * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like + * Argent and Safe Wallet (previously Gnosis Safe). + */ +library SignatureChecker { + /** + * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the + * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. + * + * 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 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + (address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature); + 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.encodeCall(IERC1271.isValidSignature, (hash, signature)) + ); + return (success && + result.length >= 32 && + abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/ERC165.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/ERC165.sol new file mode 100644 index 0000000..1e77b60 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/ERC165Checker.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/ERC165Checker.sol new file mode 100644 index 0000000..7b52241 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/ERC165Checker.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "./IERC165.sol"; + +/** + * @dev Library used to query support of an interface declared via {IERC165}. + * + * Note that these functions return the actual result of the query: they do not + * `revert` if an interface is not supported. It is up to the caller to decide + * what to do in these cases. + */ +library ERC165Checker { + // As per the EIP-165 spec, no interface should ever match 0xffffffff + bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff; + + /** + * @dev Returns true if `account` supports the {IERC165} interface. + */ + function supportsERC165(address account) internal view returns (bool) { + // Any contract that implements ERC165 must explicitly indicate support of + // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid + return + supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && + !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID); + } + + /** + * @dev Returns true if `account` supports the interface defined by + * `interfaceId`. Support for {IERC165} itself is queried automatically. + * + * See {IERC165-supportsInterface}. + */ + function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { + // query support of both ERC165 as per the spec and support of _interfaceId + return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); + } + + /** + * @dev Returns a boolean array where each value corresponds to the + * interfaces passed in and whether they're supported or not. This allows + * you to batch check interfaces for a contract where your expectation + * is that some interfaces may not be supported. + * + * See {IERC165-supportsInterface}. + */ + function getSupportedInterfaces( + address account, + bytes4[] memory interfaceIds + ) internal view returns (bool[] memory) { + // an array of booleans corresponding to interfaceIds and whether they're supported or not + bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); + + // query support of ERC165 itself + if (supportsERC165(account)) { + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); + } + } + + return interfaceIdsSupported; + } + + /** + * @dev Returns true if `account` supports all the interfaces defined in + * `interfaceIds`. Support for {IERC165} itself is queried automatically. + * + * Batch-querying can lead to gas savings by skipping repeated checks for + * {IERC165} support. + * + * See {IERC165-supportsInterface}. + */ + function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { + // query support of ERC165 itself + if (!supportsERC165(account)) { + return false; + } + + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { + return false; + } + } + + // all interfaces supported + return true; + } + + /** + * @notice Query if a contract implements an interface, does not check ERC165 support + * @param account The address of the contract to query for support of an interface + * @param interfaceId The interface identifier, as specified in ERC-165 + * @return true if the contract at account indicates support of the interface with + * identifier interfaceId, false otherwise + * @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) { + // prepare call + bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId)); + + // perform static call + bool success; + uint256 returnSize; + uint256 returnValue; + assembly { + success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) + returnSize := returndatasize() + returnValue := mload(0x00) + } + + return success && returnSize >= 0x20 && returnValue > 0; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/IERC165.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/IERC165.sol new file mode 100644 index 0000000..c09f31f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/introspection/IERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/Math.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/Math.sol new file mode 100644 index 0000000..9681524 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/Math.sol @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + /** + * @dev Muldiv operation overflow. + */ + error MathOverflowedMulDiv(); + + enum Rounding { + Floor, // Toward negative infinity + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero + } + + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an overflow flag. + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds towards infinity instead + * of rounding towards zero. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + if (b == 0) { + // Guarantee the same behavior as in a regular Solidity division. + return a / b; + } + + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0. + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by + * Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0 = x * y; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // 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; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + if (denominator <= prod1) { + revert MathOverflowedMulDiv(); + } + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. + // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. + + uint256 twos = denominator & (0 - denominator); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded + * towards zero. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256 of a positive value rounded towards zero. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); + } + } + + /** + * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. + */ + function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { + return uint8(rounding) % 2 == 1; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/SafeCast.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/SafeCast.sol new file mode 100644 index 0000000..0ed458b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/SafeCast.sol @@ -0,0 +1,1153 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) +// This file was procedurally generated from scripts/generate/templates/SafeCast.js. + +pragma solidity ^0.8.20; + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. `SafeCast` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeCast { + /** + * @dev Value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + + /** + * @dev An int value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedIntToUint(int256 value); + + /** + * @dev Value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); + + /** + * @dev An uint value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedUintToInt(uint256 value); + + /** + * @dev Returns the downcasted uint248 from uint256, reverting on + * overflow (when the input is greater than largest uint248). + * + * Counterpart to Solidity's `uint248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toUint248(uint256 value) internal pure returns (uint248) { + if (value > type(uint248).max) { + revert SafeCastOverflowedUintDowncast(248, value); + } + return uint248(value); + } + + /** + * @dev Returns the downcasted uint240 from uint256, reverting on + * overflow (when the input is greater than largest uint240). + * + * Counterpart to Solidity's `uint240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toUint240(uint256 value) internal pure returns (uint240) { + if (value > type(uint240).max) { + revert SafeCastOverflowedUintDowncast(240, value); + } + return uint240(value); + } + + /** + * @dev Returns the downcasted uint232 from uint256, reverting on + * overflow (when the input is greater than largest uint232). + * + * Counterpart to Solidity's `uint232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toUint232(uint256 value) internal pure returns (uint232) { + if (value > type(uint232).max) { + revert SafeCastOverflowedUintDowncast(232, value); + } + return uint232(value); + } + + /** + * @dev Returns the downcasted uint224 from uint256, reverting on + * overflow (when the input is greater than largest uint224). + * + * Counterpart to Solidity's `uint224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toUint224(uint256 value) internal pure returns (uint224) { + if (value > type(uint224).max) { + revert SafeCastOverflowedUintDowncast(224, value); + } + return uint224(value); + } + + /** + * @dev Returns the downcasted uint216 from uint256, reverting on + * overflow (when the input is greater than largest uint216). + * + * Counterpart to Solidity's `uint216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toUint216(uint256 value) internal pure returns (uint216) { + if (value > type(uint216).max) { + revert SafeCastOverflowedUintDowncast(216, value); + } + return uint216(value); + } + + /** + * @dev Returns the downcasted uint208 from uint256, reverting on + * overflow (when the input is greater than largest uint208). + * + * Counterpart to Solidity's `uint208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toUint208(uint256 value) internal pure returns (uint208) { + if (value > type(uint208).max) { + revert SafeCastOverflowedUintDowncast(208, value); + } + return uint208(value); + } + + /** + * @dev Returns the downcasted uint200 from uint256, reverting on + * overflow (when the input is greater than largest uint200). + * + * Counterpart to Solidity's `uint200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toUint200(uint256 value) internal pure returns (uint200) { + if (value > type(uint200).max) { + revert SafeCastOverflowedUintDowncast(200, value); + } + return uint200(value); + } + + /** + * @dev Returns the downcasted uint192 from uint256, reverting on + * overflow (when the input is greater than largest uint192). + * + * Counterpart to Solidity's `uint192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toUint192(uint256 value) internal pure returns (uint192) { + if (value > type(uint192).max) { + revert SafeCastOverflowedUintDowncast(192, value); + } + return uint192(value); + } + + /** + * @dev Returns the downcasted uint184 from uint256, reverting on + * overflow (when the input is greater than largest uint184). + * + * Counterpart to Solidity's `uint184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toUint184(uint256 value) internal pure returns (uint184) { + if (value > type(uint184).max) { + revert SafeCastOverflowedUintDowncast(184, value); + } + return uint184(value); + } + + /** + * @dev Returns the downcasted uint176 from uint256, reverting on + * overflow (when the input is greater than largest uint176). + * + * Counterpart to Solidity's `uint176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toUint176(uint256 value) internal pure returns (uint176) { + if (value > type(uint176).max) { + revert SafeCastOverflowedUintDowncast(176, value); + } + return uint176(value); + } + + /** + * @dev Returns the downcasted uint168 from uint256, reverting on + * overflow (when the input is greater than largest uint168). + * + * Counterpart to Solidity's `uint168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toUint168(uint256 value) internal pure returns (uint168) { + if (value > type(uint168).max) { + revert SafeCastOverflowedUintDowncast(168, value); + } + return uint168(value); + } + + /** + * @dev Returns the downcasted uint160 from uint256, reverting on + * overflow (when the input is greater than largest uint160). + * + * Counterpart to Solidity's `uint160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toUint160(uint256 value) internal pure returns (uint160) { + if (value > type(uint160).max) { + revert SafeCastOverflowedUintDowncast(160, value); + } + return uint160(value); + } + + /** + * @dev Returns the downcasted uint152 from uint256, reverting on + * overflow (when the input is greater than largest uint152). + * + * Counterpart to Solidity's `uint152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toUint152(uint256 value) internal pure returns (uint152) { + if (value > type(uint152).max) { + revert SafeCastOverflowedUintDowncast(152, value); + } + return uint152(value); + } + + /** + * @dev Returns the downcasted uint144 from uint256, reverting on + * overflow (when the input is greater than largest uint144). + * + * Counterpart to Solidity's `uint144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toUint144(uint256 value) internal pure returns (uint144) { + if (value > type(uint144).max) { + revert SafeCastOverflowedUintDowncast(144, value); + } + return uint144(value); + } + + /** + * @dev Returns the downcasted uint136 from uint256, reverting on + * overflow (when the input is greater than largest uint136). + * + * Counterpart to Solidity's `uint136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toUint136(uint256 value) internal pure returns (uint136) { + if (value > type(uint136).max) { + revert SafeCastOverflowedUintDowncast(136, value); + } + return uint136(value); + } + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toUint128(uint256 value) internal pure returns (uint128) { + if (value > type(uint128).max) { + revert SafeCastOverflowedUintDowncast(128, value); + } + return uint128(value); + } + + /** + * @dev Returns the downcasted uint120 from uint256, reverting on + * overflow (when the input is greater than largest uint120). + * + * Counterpart to Solidity's `uint120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toUint120(uint256 value) internal pure returns (uint120) { + if (value > type(uint120).max) { + revert SafeCastOverflowedUintDowncast(120, value); + } + return uint120(value); + } + + /** + * @dev Returns the downcasted uint112 from uint256, reverting on + * overflow (when the input is greater than largest uint112). + * + * Counterpart to Solidity's `uint112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toUint112(uint256 value) internal pure returns (uint112) { + if (value > type(uint112).max) { + revert SafeCastOverflowedUintDowncast(112, value); + } + return uint112(value); + } + + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toUint104(uint256 value) internal pure returns (uint104) { + if (value > type(uint104).max) { + revert SafeCastOverflowedUintDowncast(104, value); + } + return uint104(value); + } + + /** + * @dev Returns the downcasted uint96 from uint256, reverting on + * overflow (when the input is greater than largest uint96). + * + * Counterpart to Solidity's `uint96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toUint96(uint256 value) internal pure returns (uint96) { + if (value > type(uint96).max) { + revert SafeCastOverflowedUintDowncast(96, value); + } + return uint96(value); + } + + /** + * @dev Returns the downcasted uint88 from uint256, reverting on + * overflow (when the input is greater than largest uint88). + * + * Counterpart to Solidity's `uint88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toUint88(uint256 value) internal pure returns (uint88) { + if (value > type(uint88).max) { + revert SafeCastOverflowedUintDowncast(88, value); + } + return uint88(value); + } + + /** + * @dev Returns the downcasted uint80 from uint256, reverting on + * overflow (when the input is greater than largest uint80). + * + * Counterpart to Solidity's `uint80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toUint80(uint256 value) internal pure returns (uint80) { + if (value > type(uint80).max) { + revert SafeCastOverflowedUintDowncast(80, value); + } + return uint80(value); + } + + /** + * @dev Returns the downcasted uint72 from uint256, reverting on + * overflow (when the input is greater than largest uint72). + * + * Counterpart to Solidity's `uint72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toUint72(uint256 value) internal pure returns (uint72) { + if (value > type(uint72).max) { + revert SafeCastOverflowedUintDowncast(72, value); + } + return uint72(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toUint64(uint256 value) internal pure returns (uint64) { + if (value > type(uint64).max) { + revert SafeCastOverflowedUintDowncast(64, value); + } + return uint64(value); + } + + /** + * @dev Returns the downcasted uint56 from uint256, reverting on + * overflow (when the input is greater than largest uint56). + * + * Counterpart to Solidity's `uint56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toUint56(uint256 value) internal pure returns (uint56) { + if (value > type(uint56).max) { + revert SafeCastOverflowedUintDowncast(56, value); + } + return uint56(value); + } + + /** + * @dev Returns the downcasted uint48 from uint256, reverting on + * overflow (when the input is greater than largest uint48). + * + * Counterpart to Solidity's `uint48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toUint48(uint256 value) internal pure returns (uint48) { + if (value > type(uint48).max) { + revert SafeCastOverflowedUintDowncast(48, value); + } + return uint48(value); + } + + /** + * @dev Returns the downcasted uint40 from uint256, reverting on + * overflow (when the input is greater than largest uint40). + * + * Counterpart to Solidity's `uint40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toUint40(uint256 value) internal pure returns (uint40) { + if (value > type(uint40).max) { + revert SafeCastOverflowedUintDowncast(40, value); + } + return uint40(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toUint32(uint256 value) internal pure returns (uint32) { + if (value > type(uint32).max) { + revert SafeCastOverflowedUintDowncast(32, value); + } + return uint32(value); + } + + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toUint24(uint256 value) internal pure returns (uint24) { + if (value > type(uint24).max) { + revert SafeCastOverflowedUintDowncast(24, value); + } + return uint24(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toUint16(uint256 value) internal pure returns (uint16) { + if (value > type(uint16).max) { + revert SafeCastOverflowedUintDowncast(16, value); + } + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toUint8(uint256 value) internal pure returns (uint8) { + if (value > type(uint8).max) { + revert SafeCastOverflowedUintDowncast(8, value); + } + return uint8(value); + } + + /** + * @dev Converts a signed int256 into an unsigned uint256. + * + * Requirements: + * + * - input must be greater than or equal to 0. + */ + function toUint256(int256 value) internal pure returns (uint256) { + if (value < 0) { + revert SafeCastOverflowedIntToUint(value); + } + return uint256(value); + } + + /** + * @dev Returns the downcasted int248 from int256, reverting on + * overflow (when the input is less than smallest int248 or + * greater than largest int248). + * + * Counterpart to Solidity's `int248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toInt248(int256 value) internal pure returns (int248 downcasted) { + downcasted = int248(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(248, value); + } + } + + /** + * @dev Returns the downcasted int240 from int256, reverting on + * overflow (when the input is less than smallest int240 or + * greater than largest int240). + * + * Counterpart to Solidity's `int240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toInt240(int256 value) internal pure returns (int240 downcasted) { + downcasted = int240(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(240, value); + } + } + + /** + * @dev Returns the downcasted int232 from int256, reverting on + * overflow (when the input is less than smallest int232 or + * greater than largest int232). + * + * Counterpart to Solidity's `int232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toInt232(int256 value) internal pure returns (int232 downcasted) { + downcasted = int232(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(232, value); + } + } + + /** + * @dev Returns the downcasted int224 from int256, reverting on + * overflow (when the input is less than smallest int224 or + * greater than largest int224). + * + * Counterpart to Solidity's `int224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toInt224(int256 value) internal pure returns (int224 downcasted) { + downcasted = int224(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(224, value); + } + } + + /** + * @dev Returns the downcasted int216 from int256, reverting on + * overflow (when the input is less than smallest int216 or + * greater than largest int216). + * + * Counterpart to Solidity's `int216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toInt216(int256 value) internal pure returns (int216 downcasted) { + downcasted = int216(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(216, value); + } + } + + /** + * @dev Returns the downcasted int208 from int256, reverting on + * overflow (when the input is less than smallest int208 or + * greater than largest int208). + * + * Counterpart to Solidity's `int208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toInt208(int256 value) internal pure returns (int208 downcasted) { + downcasted = int208(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(208, value); + } + } + + /** + * @dev Returns the downcasted int200 from int256, reverting on + * overflow (when the input is less than smallest int200 or + * greater than largest int200). + * + * Counterpart to Solidity's `int200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toInt200(int256 value) internal pure returns (int200 downcasted) { + downcasted = int200(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(200, value); + } + } + + /** + * @dev Returns the downcasted int192 from int256, reverting on + * overflow (when the input is less than smallest int192 or + * greater than largest int192). + * + * Counterpart to Solidity's `int192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toInt192(int256 value) internal pure returns (int192 downcasted) { + downcasted = int192(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(192, value); + } + } + + /** + * @dev Returns the downcasted int184 from int256, reverting on + * overflow (when the input is less than smallest int184 or + * greater than largest int184). + * + * Counterpart to Solidity's `int184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toInt184(int256 value) internal pure returns (int184 downcasted) { + downcasted = int184(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(184, value); + } + } + + /** + * @dev Returns the downcasted int176 from int256, reverting on + * overflow (when the input is less than smallest int176 or + * greater than largest int176). + * + * Counterpart to Solidity's `int176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toInt176(int256 value) internal pure returns (int176 downcasted) { + downcasted = int176(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(176, value); + } + } + + /** + * @dev Returns the downcasted int168 from int256, reverting on + * overflow (when the input is less than smallest int168 or + * greater than largest int168). + * + * Counterpart to Solidity's `int168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toInt168(int256 value) internal pure returns (int168 downcasted) { + downcasted = int168(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(168, value); + } + } + + /** + * @dev Returns the downcasted int160 from int256, reverting on + * overflow (when the input is less than smallest int160 or + * greater than largest int160). + * + * Counterpart to Solidity's `int160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toInt160(int256 value) internal pure returns (int160 downcasted) { + downcasted = int160(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(160, value); + } + } + + /** + * @dev Returns the downcasted int152 from int256, reverting on + * overflow (when the input is less than smallest int152 or + * greater than largest int152). + * + * Counterpart to Solidity's `int152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toInt152(int256 value) internal pure returns (int152 downcasted) { + downcasted = int152(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(152, value); + } + } + + /** + * @dev Returns the downcasted int144 from int256, reverting on + * overflow (when the input is less than smallest int144 or + * greater than largest int144). + * + * Counterpart to Solidity's `int144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toInt144(int256 value) internal pure returns (int144 downcasted) { + downcasted = int144(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(144, value); + } + } + + /** + * @dev Returns the downcasted int136 from int256, reverting on + * overflow (when the input is less than smallest int136 or + * greater than largest int136). + * + * Counterpart to Solidity's `int136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toInt136(int256 value) internal pure returns (int136 downcasted) { + downcasted = int136(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(136, value); + } + } + + /** + * @dev Returns the downcasted int128 from int256, reverting on + * overflow (when the input is less than smallest int128 or + * greater than largest int128). + * + * Counterpart to Solidity's `int128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toInt128(int256 value) internal pure returns (int128 downcasted) { + downcasted = int128(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(128, value); + } + } + + /** + * @dev Returns the downcasted int120 from int256, reverting on + * overflow (when the input is less than smallest int120 or + * greater than largest int120). + * + * Counterpart to Solidity's `int120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toInt120(int256 value) internal pure returns (int120 downcasted) { + downcasted = int120(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(120, value); + } + } + + /** + * @dev Returns the downcasted int112 from int256, reverting on + * overflow (when the input is less than smallest int112 or + * greater than largest int112). + * + * Counterpart to Solidity's `int112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toInt112(int256 value) internal pure returns (int112 downcasted) { + downcasted = int112(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(112, value); + } + } + + /** + * @dev Returns the downcasted int104 from int256, reverting on + * overflow (when the input is less than smallest int104 or + * greater than largest int104). + * + * Counterpart to Solidity's `int104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toInt104(int256 value) internal pure returns (int104 downcasted) { + downcasted = int104(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(104, value); + } + } + + /** + * @dev Returns the downcasted int96 from int256, reverting on + * overflow (when the input is less than smallest int96 or + * greater than largest int96). + * + * Counterpart to Solidity's `int96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toInt96(int256 value) internal pure returns (int96 downcasted) { + downcasted = int96(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(96, value); + } + } + + /** + * @dev Returns the downcasted int88 from int256, reverting on + * overflow (when the input is less than smallest int88 or + * greater than largest int88). + * + * Counterpart to Solidity's `int88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toInt88(int256 value) internal pure returns (int88 downcasted) { + downcasted = int88(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(88, value); + } + } + + /** + * @dev Returns the downcasted int80 from int256, reverting on + * overflow (when the input is less than smallest int80 or + * greater than largest int80). + * + * Counterpart to Solidity's `int80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toInt80(int256 value) internal pure returns (int80 downcasted) { + downcasted = int80(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(80, value); + } + } + + /** + * @dev Returns the downcasted int72 from int256, reverting on + * overflow (when the input is less than smallest int72 or + * greater than largest int72). + * + * Counterpart to Solidity's `int72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toInt72(int256 value) internal pure returns (int72 downcasted) { + downcasted = int72(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(72, value); + } + } + + /** + * @dev Returns the downcasted int64 from int256, reverting on + * overflow (when the input is less than smallest int64 or + * greater than largest int64). + * + * Counterpart to Solidity's `int64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toInt64(int256 value) internal pure returns (int64 downcasted) { + downcasted = int64(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(64, value); + } + } + + /** + * @dev Returns the downcasted int56 from int256, reverting on + * overflow (when the input is less than smallest int56 or + * greater than largest int56). + * + * Counterpart to Solidity's `int56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toInt56(int256 value) internal pure returns (int56 downcasted) { + downcasted = int56(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(56, value); + } + } + + /** + * @dev Returns the downcasted int48 from int256, reverting on + * overflow (when the input is less than smallest int48 or + * greater than largest int48). + * + * Counterpart to Solidity's `int48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toInt48(int256 value) internal pure returns (int48 downcasted) { + downcasted = int48(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(48, value); + } + } + + /** + * @dev Returns the downcasted int40 from int256, reverting on + * overflow (when the input is less than smallest int40 or + * greater than largest int40). + * + * Counterpart to Solidity's `int40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toInt40(int256 value) internal pure returns (int40 downcasted) { + downcasted = int40(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(40, value); + } + } + + /** + * @dev Returns the downcasted int32 from int256, reverting on + * overflow (when the input is less than smallest int32 or + * greater than largest int32). + * + * Counterpart to Solidity's `int32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toInt32(int256 value) internal pure returns (int32 downcasted) { + downcasted = int32(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(32, value); + } + } + + /** + * @dev Returns the downcasted int24 from int256, reverting on + * overflow (when the input is less than smallest int24 or + * greater than largest int24). + * + * Counterpart to Solidity's `int24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toInt24(int256 value) internal pure returns (int24 downcasted) { + downcasted = int24(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(24, value); + } + } + + /** + * @dev Returns the downcasted int16 from int256, reverting on + * overflow (when the input is less than smallest int16 or + * greater than largest int16). + * + * Counterpart to Solidity's `int16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toInt16(int256 value) internal pure returns (int16 downcasted) { + downcasted = int16(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(16, value); + } + } + + /** + * @dev Returns the downcasted int8 from int256, reverting on + * overflow (when the input is less than smallest int8 or + * greater than largest int8). + * + * Counterpart to Solidity's `int8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toInt8(int256 value) internal pure returns (int8 downcasted) { + downcasted = int8(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(8, value); + } + } + + /** + * @dev Converts an unsigned uint256 into a signed int256. + * + * Requirements: + * + * - input must be less than or equal to maxInt256. + */ + function toInt256(uint256 value) internal pure returns (int256) { + // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive + if (value > uint256(type(int256).max)) { + revert SafeCastOverflowedUintToInt(value); + } + return int256(value); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/SignedMath.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/SignedMath.sol new file mode 100644 index 0000000..66a6151 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/math/SignedMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/BitMaps.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/BitMaps.sol new file mode 100644 index 0000000..40cceb9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/BitMaps.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/BitMaps.sol) +pragma solidity ^0.8.20; + +/** + * @dev Library for managing uint256 to bool mapping in a compact and efficient way, provided the keys are sequential. + * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. + * + * BitMaps pack 256 booleans across each bit of a single 256-bit slot of `uint256` type. + * Hence booleans corresponding to 256 _sequential_ indices would only consume a single slot, + * unlike the regular `bool` which would consume an entire slot for a single value. + * + * This results in gas savings in two ways: + * + * - Setting a zero value to non-zero only once every 256 times + * - Accessing the same warm slot for every 256 _sequential_ indices + */ +library BitMaps { + struct BitMap { + mapping(uint256 bucket => uint256) _data; + } + + /** + * @dev Returns whether the bit at `index` is set. + */ + function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + return bitmap._data[bucket] & mask != 0; + } + + /** + * @dev Sets the bit at `index` to the boolean `value`. + */ + function setTo(BitMap storage bitmap, uint256 index, bool value) internal { + if (value) { + set(bitmap, index); + } else { + unset(bitmap, index); + } + } + + /** + * @dev Sets the bit at `index`. + */ + function set(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] |= mask; + } + + /** + * @dev Unsets the bit at `index`. + */ + function unset(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] &= ~mask; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/Checkpoints.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/Checkpoints.sol new file mode 100644 index 0000000..6561b0d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/Checkpoints.sol @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol) +// This file was procedurally generated from scripts/generate/templates/Checkpoints.js. + +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; + +/** + * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + */ +library Checkpoints { + /** + * @dev A value was attempted to be inserted on a past checkpoint. + */ + error CheckpointUnorderedInsertion(); + + struct Trace224 { + Checkpoint224[] _checkpoints; + } + + struct Checkpoint224 { + uint32 _key; + uint224 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the + * library. + */ + function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the 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; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @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; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @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). + */ + 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. + */ + function latest(Trace224 storage self) internal view returns (uint224) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace224 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint224 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint224({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint224({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the 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. + */ + function _upperBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint224[] storage self, + uint256 pos + ) private pure returns (Checkpoint224 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace208 { + Checkpoint208[] _checkpoints; + } + + struct Checkpoint208 { + uint48 _key; + uint208 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the + * library. + */ + function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) { + return _insert(self._checkpoints, key, value); + } + + /** + * @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(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + */ + function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the 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). + */ + function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) { + 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. + */ + function latest(Trace208 storage self) internal view returns (uint208) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint208 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace208 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint208 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint208({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint208({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @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. + */ + function _upperBinaryLookup( + Checkpoint208[] storage self, + uint48 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint208[] storage self, + uint48 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint208[] storage self, + uint256 pos + ) private pure returns (Checkpoint208 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace160 { + Checkpoint160[] _checkpoints; + } + + struct Checkpoint160 { + uint96 _key; + uint160 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the + * library. + */ + function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the 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; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @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; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @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). + */ + 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. + */ + function latest(Trace160 storage self) internal view returns (uint160) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace160 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint160 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint160({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint160({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the 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. + */ + function _upperBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint160[] storage self, + uint256 pos + ) private pure returns (Checkpoint160 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/DoubleEndedQueue.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/DoubleEndedQueue.sol new file mode 100644 index 0000000..218a2fb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/DoubleEndedQueue.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol) +pragma solidity ^0.8.20; + +/** + * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of + * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and + * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that + * the existing queue contents are left in storage. + * + * 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; + * ``` + */ +library DoubleEndedQueue { + /** + * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty. + */ + error QueueEmpty(); + + /** + * @dev A push operation couldn't be completed due to the queue being full. + */ + error QueueFull(); + + /** + * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds. + */ + error QueueOutOfBounds(); + + /** + * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access. + * + * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to + * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and + * lead to unexpected behavior. + * + * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around. + */ + struct Bytes32Deque { + uint128 _begin; + uint128 _end; + mapping(uint128 index => bytes32) _data; + } + + /** + * @dev Inserts an item at the end of the queue. + * + * Reverts with {QueueFull} if the queue is full. + */ + function pushBack(Bytes32Deque storage deque, bytes32 value) internal { + unchecked { + uint128 backIndex = deque._end; + if (backIndex + 1 == deque._begin) revert QueueFull(); + deque._data[backIndex] = value; + deque._end = backIndex + 1; + } + } + + /** + * @dev Removes the item at the end of the queue and returns it. + * + * Reverts with {QueueEmpty} if the queue is empty. + */ + function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) { + unchecked { + uint128 backIndex = deque._end; + if (backIndex == deque._begin) revert QueueEmpty(); + --backIndex; + value = deque._data[backIndex]; + delete deque._data[backIndex]; + deque._end = backIndex; + } + } + + /** + * @dev Inserts an item at the beginning of the queue. + * + * Reverts with {QueueFull} if the queue is full. + */ + function pushFront(Bytes32Deque storage deque, bytes32 value) internal { + unchecked { + uint128 frontIndex = deque._begin - 1; + if (frontIndex == deque._end) revert QueueFull(); + deque._data[frontIndex] = value; + deque._begin = frontIndex; + } + } + + /** + * @dev Removes the item at the beginning of the queue and returns it. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) { + unchecked { + uint128 frontIndex = deque._begin; + if (frontIndex == deque._end) revert QueueEmpty(); + value = deque._data[frontIndex]; + delete deque._data[frontIndex]; + deque._begin = frontIndex + 1; + } + } + + /** + * @dev Returns the item at the beginning of the queue. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function front(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) revert QueueEmpty(); + return deque._data[deque._begin]; + } + + /** + * @dev Returns the item at the end of the queue. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function back(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) revert QueueEmpty(); + unchecked { + return deque._data[deque._end - 1]; + } + } + + /** + * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at + * `length(deque) - 1`. + * + * Reverts with `QueueOutOfBounds` if the index is out of bounds. + */ + function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) { + if (index >= length(deque)) revert QueueOutOfBounds(); + // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128 + unchecked { + return deque._data[deque._begin + uint128(index)]; + } + } + + /** + * @dev Resets the queue back to being empty. + * + * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses + * out on potential gas refunds. + */ + function clear(Bytes32Deque storage deque) internal { + deque._begin = 0; + deque._end = 0; + } + + /** + * @dev Returns the number of items in the queue. + */ + function length(Bytes32Deque storage deque) internal view returns (uint256) { + unchecked { + return uint256(deque._end - deque._begin); + } + } + + /** + * @dev Returns true if the queue is empty. + */ + function empty(Bytes32Deque storage deque) internal view returns (bool) { + return deque._end == deque._begin; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/EnumerableMap.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/EnumerableMap.sol new file mode 100644 index 0000000..929ae7c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/EnumerableMap.sol @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. + +pragma solidity ^0.8.20; + +import {EnumerableSet} from "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * ``` + * + * The following map types are supported: + * + * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 + * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 + * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 + * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 + * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +library EnumerableMap { + using EnumerableSet for EnumerableSet.Bytes32Set; + + // To implement this library for multiple types with as little code repetition as possible, we write it in + // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions, + // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map. + // This means that we can only create new EnumerableMaps for types that fit in bytes32. + + /** + * @dev Query for a nonexistent map key. + */ + error EnumerableMapNonexistentKey(bytes32 key); + + struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 key => bytes32) _values; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + if (value == 0 && !contains(map, key)) { + revert EnumerableMapNonexistentKey(key); + } + return value; + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { + return map._keys.values(); + } + + // UintToUintMap + + struct UintToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(key))); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintToAddressMap + + struct UintToAddressMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToAddressMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), address(uint160(uint256(value)))); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, address(uint160(uint256(value)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(key))))); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressToUintMap + + struct AddressToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { + return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(AddressToUintMap storage map, address key) internal returns (bool) { + return remove(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(AddressToUintMap storage map, address key) internal view returns (bool) { + return contains(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(AddressToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (address(uint160(uint256(key))), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(AddressToUintMap storage map, address key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(uint256(uint160(key))))); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(AddressToUintMap storage map) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // Bytes32ToUintMap + + struct Bytes32ToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { + return set(map._inner, key, bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { + return remove(map._inner, key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { + return contains(map._inner, key); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(Bytes32ToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (key, uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, key); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { + return uint256(get(map._inner, key)); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { + bytes32[] memory store = keys(map._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/EnumerableSet.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/EnumerableSet.sol new file mode 100644 index 0000000..4c7fc5e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/structs/EnumerableSet.sol @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. + +pragma solidity ^0.8.20; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + // Position is the index of the value in the `values` array plus 1. + // Position 0 is used to mean a value is not in the set. + mapping(bytes32 value => uint256) _positions; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._positions[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We cache the value's position to prevent multiple reads from the same storage slot + uint256 position = set._positions[value]; + + if (position != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 valueIndex = position - 1; + uint256 lastIndex = set._values.length - 1; + + if (valueIndex != lastIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the lastValue to the index where the value to delete is + set._values[valueIndex] = lastValue; + // Update the tracked position of the lastValue (that was just moved) + set._positions[lastValue] = position; + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the tracked position for the deleted slot + delete set._positions[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._positions[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { + bytes32[] memory store = _values(set._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(AddressSet storage set) internal view returns (address[] memory) { + bytes32[] memory store = _values(set._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(UintSet storage set) internal view returns (uint256[] memory) { + bytes32[] memory store = _values(set._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/utils/types/Time.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/types/Time.sol new file mode 100644 index 0000000..9faef31 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/utils/types/Time.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol) + +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; +import {SafeCast} from "../math/SafeCast.sol"; + +/** + * @dev This library provides helpers for manipulating time-related objects. + * + * It uses the following types: + * - `uint48` for timepoints + * - `uint32` for durations + * + * While the library doesn't provide specific types for timepoints and duration, it does provide: + * - a `Delay` type to represent duration that can be programmed to change value automatically at a given point + * - additional helper functions + */ +library Time { + using Time for *; + + /** + * @dev Get the block timestamp as a Timepoint. + */ + function timestamp() internal view returns (uint48) { + return SafeCast.toUint48(block.timestamp); + } + + /** + * @dev Get the block number as a Timepoint. + */ + function blockNumber() internal view returns (uint48) { + return SafeCast.toUint48(block.number); + } + + // ==================================================== Delay ===================================================== + /** + * @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the + * future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value. + * This allows updating the delay applied to some operation while keeping some guarantees. + * + * In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for + * some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set + * the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should + * still apply for some time. + * + * + * The `Delay` type is 112 bits long, and packs the following: + * + * ``` + * | [uint48]: effect date (timepoint) + * | | [uint32]: value before (duration) + * ↓ ↓ ↓ [uint32]: value after (duration) + * 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC + * ``` + * + * NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently + * supported. + */ + type Delay is uint112; + + /** + * @dev Wrap a duration into a Delay to add the one-step "update in the future" feature + */ + function toDelay(uint32 duration) internal pure returns (Delay) { + return Delay.wrap(duration); + } + + /** + * @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled + * change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered. + */ + function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) { + (uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack(); + return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect); + } + + /** + * @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the + * effect timepoint is 0, then the pending value should not be considered. + */ + function getFull(Delay self) internal view returns (uint32, uint32, uint48) { + return _getFullAt(self, timestamp()); + } + + /** + * @dev Get the current value. + */ + function get(Delay self) internal view returns (uint32) { + (uint32 delay, , ) = self.getFull(); + return delay; + } + + /** + * @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to + * enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the + * new delay becomes effective. + */ + function withUpdate( + Delay self, + uint32 newValue, + uint32 minSetback + ) internal view returns (Delay updatedDelay, uint48 effect) { + uint32 value = self.get(); + uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0)); + effect = timestamp() + setback; + return (pack(value, newValue, effect), effect); + } + + /** + * @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint). + */ + function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) { + uint112 raw = Delay.unwrap(self); + + valueAfter = uint32(raw); + valueBefore = uint32(raw >> 32); + effect = uint48(raw >> 64); + + return (valueBefore, valueAfter, effect); + } + + /** + * @dev pack the components into a Delay object. + */ + function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) { + return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter)); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/vendor/compound/ICompoundTimelock.sol b/lib/openzeppelin-contracts-v5.0.0/contracts/vendor/compound/ICompoundTimelock.sol new file mode 100644 index 0000000..320eea1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/vendor/compound/ICompoundTimelock.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (vendor/compound/ICompoundTimelock.sol) + +pragma solidity ^0.8.20; + +/** + * https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[Compound timelock] interface + */ +interface ICompoundTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + + receive() external payable; + + // solhint-disable-next-line func-name-mixedcase + function GRACE_PERIOD() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function MINIMUM_DELAY() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function MAXIMUM_DELAY() external view returns (uint256); + + function admin() external view returns (address); + + function pendingAdmin() external view returns (address); + + function delay() external view returns (uint256); + + function queuedTransactions(bytes32) external view returns (bool); + + function setDelay(uint256) external; + + function acceptAdmin() external; + + function setPendingAdmin(address) external; + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external returns (bytes32); + + function cancelTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external; + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external payable returns (bytes memory); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/contracts/vendor/compound/LICENSE b/lib/openzeppelin-contracts-v5.0.0/contracts/vendor/compound/LICENSE new file mode 100644 index 0000000..7da2324 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/contracts/vendor/compound/LICENSE @@ -0,0 +1,11 @@ +Copyright 2020 Compound Labs, Inc. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/lib/openzeppelin-contracts-v5.0.0/foundry.toml b/lib/openzeppelin-contracts-v5.0.0/foundry.toml new file mode 100644 index 0000000..859f210 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/foundry.toml @@ -0,0 +1,10 @@ +[profile.default] +src = 'contracts' +out = 'out' +libs = ['node_modules', 'lib'] +test = 'test' +cache_path = 'cache_forge' + +[fuzz] +runs = 10000 +max_test_rejects = 150000 diff --git a/lib/openzeppelin-contracts-v5.0.0/hardhat.config.js b/lib/openzeppelin-contracts-v5.0.0/hardhat.config.js new file mode 100644 index 0000000..4d5ab94 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/hardhat.config.js @@ -0,0 +1,131 @@ +/// ENVVAR +// - CI: output gas report to file instead of stdout +// - COVERAGE: enable coverage report +// - ENABLE_GAS_REPORT: enable gas report +// - COMPILE_MODE: production modes enables optimizations (default: development) +// - COMPILE_VERSION: compiler version (default: 0.8.20) +// - COINMARKETCAP: coinmarkercat api key for USD value in gas report + +const fs = require('fs'); +const path = require('path'); +const proc = require('child_process'); + +const argv = require('yargs/yargs')() + .env('') + .options({ + coverage: { + type: 'boolean', + default: false, + }, + gas: { + alias: 'enableGasReport', + type: 'boolean', + default: false, + }, + gasReport: { + alias: 'enableGasReportPath', + type: 'string', + implies: 'gas', + default: undefined, + }, + mode: { + alias: 'compileMode', + type: 'string', + choices: ['production', 'development'], + default: 'development', + }, + ir: { + alias: 'enableIR', + type: 'boolean', + default: false, + }, + foundry: { + alias: 'hasFoundry', + type: 'boolean', + default: hasFoundry(), + }, + compiler: { + alias: 'compileVersion', + type: 'string', + default: '0.8.20', + }, + coinmarketcap: { + alias: 'coinmarketcapApiKey', + type: 'string', + }, + }).argv; + +require('@nomiclabs/hardhat-truffle5'); +require('hardhat-ignore-warnings'); +require('hardhat-exposed'); +require('solidity-docgen'); +argv.foundry && require('@nomicfoundation/hardhat-foundry'); + +if (argv.foundry && argv.coverage) { + throw Error('Coverage analysis is incompatible with Foundry. Disable with `FOUNDRY=false` in the environment'); +} + +for (const f of fs.readdirSync(path.join(__dirname, 'hardhat'))) { + require(path.join(__dirname, 'hardhat', f)); +} + +const withOptimizations = argv.gas || argv.compileMode === 'production'; + +/** + * @type import('hardhat/config').HardhatUserConfig + */ +module.exports = { + solidity: { + version: argv.compiler, + settings: { + optimizer: { + enabled: withOptimizations, + runs: 200, + }, + viaIR: withOptimizations && argv.ir, + outputSelection: { '*': { '*': ['storageLayout'] } }, + }, + }, + warnings: { + 'contracts-exposed/**/*': { + 'code-size': 'off', + 'initcode-size': 'off', + }, + '*': { + 'code-size': withOptimizations, + 'unused-param': !argv.coverage, // coverage causes unused-param warnings + default: 'error', + }, + }, + networks: { + hardhat: { + blockGasLimit: 10000000, + allowUnlimitedContractSize: !withOptimizations, + }, + }, + exposed: { + imports: true, + initializers: true, + exclude: ['vendor/**/*'], + }, + docgen: require('./docs/config'), +}; + +if (argv.gas) { + require('hardhat-gas-reporter'); + module.exports.gasReporter = { + showMethodSig: true, + currency: 'USD', + outputFile: argv.gasReport, + coinmarketcap: argv.coinmarketcap, + }; +} + +if (argv.coverage) { + require('solidity-coverage'); + module.exports.networks.hardhat.initialBaseFeePerGas = 0; +} + +function hasFoundry() { + return proc.spawnSync('forge', ['-V'], { stdio: 'ignore' }).error === undefined; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/hardhat/env-artifacts.js b/lib/openzeppelin-contracts-v5.0.0/hardhat/env-artifacts.js new file mode 100644 index 0000000..fbbea2e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/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/lib/openzeppelin-contracts-v5.0.0/hardhat/env-contract.js b/lib/openzeppelin-contracts-v5.0.0/hardhat/env-contract.js new file mode 100644 index 0000000..c615249 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/hardhat/env-contract.js @@ -0,0 +1,25 @@ +extendEnvironment(env => { + const { contract } = env; + + env.contract = function (name, body) { + const { takeSnapshot } = require('@nomicfoundation/hardhat-network-helpers'); + + contract(name, accounts => { + // reset the state of the chain in between contract test suites + let snapshot; + + before(async function () { + snapshot = await takeSnapshot(); + }); + + after(async function () { + await snapshot.restore(); + }); + + // remove the default account from the accounts list used in tests, in order + // to protect tests against accidentally passing due to the contract + // deployer being used subsequently as function caller + body(accounts.slice(1)); + }); + }; +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/hardhat/ignore-unreachable-warnings.js b/lib/openzeppelin-contracts-v5.0.0/hardhat/ignore-unreachable-warnings.js new file mode 100644 index 0000000..8e3e343 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/hardhat/ignore-unreachable-warnings.js @@ -0,0 +1,45 @@ +// Warnings about unreachable code are emitted with a source location that corresponds to the unreachable code. +// We have some testing contracts that purposely cause unreachable code, but said code is in the library contracts, and +// with hardhat-ignore-warnings we are not able to selectively ignore them without potentially ignoring relevant +// warnings that we don't want to miss. +// Thus, we need to handle these warnings separately. We force Hardhat to compile them in a separate compilation job and +// then ignore the warnings about unreachable code that come from that compilation job. + +const { task } = require('hardhat/config'); +const { + TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, + TASK_COMPILE_SOLIDITY_COMPILE, +} = require('hardhat/builtin-tasks/task-names'); + +const marker = Symbol('unreachable'); +const markedCache = new WeakMap(); + +task(TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, async (params, _, runSuper) => { + const job = await runSuper(params); + // If the file is in the unreachable directory, we make a copy of the config and mark it, which will cause it to get + // compiled separately (along with the other marked files). + if (params.file.sourceName.startsWith('contracts/mocks/') && /\bunreachable\b/.test(params.file.sourceName)) { + const originalConfig = job.solidityConfig; + let markedConfig = markedCache.get(originalConfig); + if (markedConfig === undefined) { + markedConfig = { ...originalConfig, [marker]: true }; + markedCache.set(originalConfig, markedConfig); + } + job.solidityConfig = markedConfig; + } + return job; +}); + +const W_UNREACHABLE_CODE = '5740'; + +task(TASK_COMPILE_SOLIDITY_COMPILE, async (params, _, runSuper) => { + const marked = params.compilationJob.solidityConfig[marker]; + const result = await runSuper(params); + if (marked) { + result.output = { + ...result.output, + errors: result.output.errors?.filter(e => e.severity !== 'warning' || e.errorCode !== W_UNREACHABLE_CODE), + }; + } + return result; +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/hardhat/skip-foundry-tests.js b/lib/openzeppelin-contracts-v5.0.0/hardhat/skip-foundry-tests.js new file mode 100644 index 0000000..965ba37 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/hardhat/skip-foundry-tests.js @@ -0,0 +1,6 @@ +const { subtask } = require('hardhat/config'); +const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require('hardhat/builtin-tasks/task-names'); + +subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, __, runSuper) => + (await runSuper()).filter(path => !path.endsWith('.t.sol')), +); diff --git a/lib/openzeppelin-contracts-v5.0.0/hardhat/task-test-get-files.js b/lib/openzeppelin-contracts-v5.0.0/hardhat/task-test-get-files.js new file mode 100644 index 0000000..108f40a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/hardhat/task-test-get-files.js @@ -0,0 +1,25 @@ +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 (args, hre, runSuper) => { + const path = require('path'); + const { promises: fs } = require('fs'); + + const hasProxies = await fs + .access(path.join(hre.config.paths.sources, 'proxy/Proxy.sol')) + .then(() => true) + .catch(() => false); + + const ignoredIfProxy = [ + '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(hre.config.paths.tests, p)); + + return (await runSuper(args)).filter(file => hasProxies || !ignoredIfProxy.includes(file)); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/ERC4626.prop.sol b/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/ERC4626.prop.sol new file mode 100644 index 0000000..c34512b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/ERC4626.prop.sol @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "forge-std/Test.sol"; + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC20} from "forge-std/interfaces/IERC20.sol"; +interface IERC20 { + event Transfer(address indexed from, address indexed to, uint value); + event Approval(address indexed owner, address indexed spender, uint value); + function totalSupply() external view returns (uint); + function balanceOf(address account) external view returns (uint); + function transfer(address to, uint amount) external returns (bool); + function allowance(address owner, address spender) external view returns (uint); + function approve(address spender, uint amount) external returns (bool); + function transferFrom(address from, address to, uint amount) external returns (bool); +} + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC4626} from "forge-std/interfaces/IERC4626.sol"; +interface IERC4626 is IERC20 { + event Deposit(address indexed caller, address indexed owner, uint assets, uint shares); + event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint assets, uint shares); + function asset() external view returns (address assetTokenAddress); + function totalAssets() external view returns (uint totalManagedAssets); + function convertToShares(uint assets) external view returns (uint shares); + function convertToAssets(uint shares) external view returns (uint assets); + function maxDeposit(address receiver) external view returns (uint maxAssets); + function previewDeposit(uint assets) external view returns (uint shares); + function deposit(uint assets, address receiver) external returns (uint shares); + function maxMint(address receiver) external view returns (uint maxShares); + function previewMint(uint shares) external view returns (uint assets); + function mint(uint shares, address receiver) external returns (uint assets); + function maxWithdraw(address owner) external view returns (uint maxAssets); + function previewWithdraw(uint assets) external view returns (uint shares); + function withdraw(uint assets, address receiver, address owner) external returns (uint shares); + function maxRedeem(address owner) external view returns (uint maxShares); + function previewRedeem(uint shares) external view returns (uint assets); + function redeem(uint shares, address receiver, address owner) external returns (uint assets); +} + +abstract contract ERC4626Prop is Test { + uint internal _delta_; + + address internal _underlying_; + address internal _vault_; + + bool internal _vaultMayBeEmpty; + bool internal _unlimitedAmount; + + // + // asset + // + + // asset + // "MUST NOT revert." + function prop_asset(address caller) public { + vm.prank(caller); IERC4626(_vault_).asset(); + } + + // totalAssets + // "MUST NOT revert." + function prop_totalAssets(address caller) public { + vm.prank(caller); IERC4626(_vault_).totalAssets(); + } + + // + // convert + // + + // convertToShares + // "MUST NOT show any variations depending on the caller." + function prop_convertToShares(address caller1, address caller2, uint assets) public { + vm.prank(caller1); uint res1 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // convertToAssets + // "MUST NOT show any variations depending on the caller." + function prop_convertToAssets(address caller1, address caller2, uint shares) public { + vm.prank(caller1); uint res1 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // + // deposit + // + + // maxDeposit + // "MUST NOT revert." + function prop_maxDeposit(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxDeposit(receiver); + } + + // previewDeposit + // "MUST return as close to and no more than the exact amount of Vault + // shares that would be minted in a deposit call in the same transaction. + // I.e. deposit should return the same or more shares as previewDeposit if + // called in the same transaction." + function prop_previewDeposit(address caller, address receiver, address other, uint assets) public { + vm.prank(other); uint sharesPreview = vault_previewDeposit(assets); // "MAY revert due to other conditions that would also cause deposit to revert." + vm.prank(caller); uint sharesActual = vault_deposit(assets, receiver); + assertApproxGeAbs(sharesActual, sharesPreview, _delta_); + } + + // deposit + function prop_deposit(address caller, address receiver, uint assets) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint shares = vault_deposit(assets, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // mint + // + + // maxMint + // "MUST NOT revert." + function prop_maxMint(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxMint(receiver); + } + + // previewMint + // "MUST return as close to and no fewer than the exact amount of assets + // that would be deposited in a mint call in the same transaction. I.e. mint + // should return the same or fewer assets as previewMint if called in the + // same transaction." + function prop_previewMint(address caller, address receiver, address other, uint shares) public { + vm.prank(other); uint assetsPreview = vault_previewMint(shares); + vm.prank(caller); uint assetsActual = vault_mint(shares, receiver); + assertApproxLeAbs(assetsActual, assetsPreview, _delta_); + } + + // mint + function prop_mint(address caller, address receiver, uint shares) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint assets = vault_mint(shares, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // withdraw + // + + // maxWithdraw + // "MUST NOT revert." + // NOTE: some implementations failed due to arithmetic overflow + function prop_maxWithdraw(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxWithdraw(owner); + } + + // previewWithdraw + // "MUST return as close to and no fewer than the exact amount of Vault + // shares that would be burned in a withdraw call in the same transaction. + // I.e. withdraw should return the same or fewer shares as previewWithdraw + // if called in the same transaction." + function prop_previewWithdraw(address caller, address receiver, address owner, address other, uint assets) public { + vm.prank(other); uint preview = vault_previewWithdraw(assets); + vm.prank(caller); uint actual = vault_withdraw(assets, receiver, owner); + assertApproxLeAbs(actual, preview, _delta_); + } + + // withdraw + function prop_withdraw(address caller, address receiver, address owner, uint assets) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint shares = vault_withdraw(assets, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // redeem + // + + // maxRedeem + // "MUST NOT revert." + function prop_maxRedeem(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxRedeem(owner); + } + + // previewRedeem + // "MUST return as close to and no more than the exact amount of assets that + // would be withdrawn in a redeem call in the same transaction. I.e. redeem + // should return the same or more assets as previewRedeem if called in the + // same transaction." + function prop_previewRedeem(address caller, address receiver, address owner, address other, uint shares) public { + vm.prank(other); uint preview = vault_previewRedeem(shares); + vm.prank(caller); uint actual = vault_redeem(shares, receiver, owner); + assertApproxGeAbs(actual, preview, _delta_); + } + + // redeem + function prop_redeem(address caller, address receiver, address owner, uint shares) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint assets = vault_redeem(shares, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // round trip properties + // + + // redeem(deposit(a)) <= a + function prop_RT_deposit_redeem(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares = vault_deposit(assets, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets, _delta_); + } + + // s = deposit(a) + // s' = withdraw(a) + // s' >= s + function prop_RT_deposit_withdraw(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares1 = vault_deposit(assets, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares1, _delta_); + } + + // deposit(redeem(s)) <= s + function prop_RT_redeem_deposit(address caller, uint shares) public { + vm.prank(caller); uint assets = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares, _delta_); + } + + // a = redeem(s) + // a' = mint(s) + // a' >= a + function prop_RT_redeem_mint(address caller, uint shares) public { + vm.prank(caller); uint assets1 = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets1, _delta_); + } + + // withdraw(mint(s)) >= s + function prop_RT_mint_withdraw(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets = vault_mint(shares, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares, _delta_); + } + + // a = mint(s) + // a' = redeem(s) + // a' <= a + function prop_RT_mint_redeem(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets1 = vault_mint(shares, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets1, _delta_); + } + + // mint(withdraw(a)) >= a + function prop_RT_withdraw_mint(address caller, uint assets) public { + vm.prank(caller); uint shares = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets, _delta_); + } + + // s = withdraw(a) + // s' = deposit(a) + // s' <= s + function prop_RT_withdraw_deposit(address caller, uint assets) public { + vm.prank(caller); uint shares1 = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares1, _delta_); + } + + // + // utils + // + + function vault_convertToShares(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToShares.selector, assets)); + } + function vault_convertToAssets(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToAssets.selector, shares)); + } + + function vault_maxDeposit(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxDeposit.selector, receiver)); + } + function vault_maxMint(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxMint.selector, receiver)); + } + function vault_maxWithdraw(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxWithdraw.selector, owner)); + } + function vault_maxRedeem(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxRedeem.selector, owner)); + } + + function vault_previewDeposit(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewDeposit.selector, assets)); + } + function vault_previewMint(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewMint.selector, shares)); + } + function vault_previewWithdraw(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewWithdraw.selector, assets)); + } + function vault_previewRedeem(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewRedeem.selector, shares)); + } + + function vault_deposit(uint assets, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.deposit.selector, assets, receiver)); + } + function vault_mint(uint shares, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.mint.selector, shares, receiver)); + } + function vault_withdraw(uint assets, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.withdraw.selector, assets, receiver, owner)); + } + function vault_redeem(uint shares, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.redeem.selector, shares, receiver, owner)); + } + + function _call_vault(bytes memory data) internal returns (uint) { + (bool success, bytes memory retdata) = _vault_.call(data); + if (success) return abi.decode(retdata, (uint)); + vm.assume(false); // if reverted, discard the current fuzz inputs, and let the fuzzer to start a new fuzz run + return 0; // silence warning + } + + function assertApproxGeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a >= b)) { + uint dt = b - a; + if (dt > maxDelta) { + emit log ("Error: a >=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } + + function assertApproxLeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a <= b)) { + uint dt = a - b; + if (dt > maxDelta) { + emit log ("Error: a <=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/ERC4626.test.sol b/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/ERC4626.test.sol new file mode 100644 index 0000000..6254a05 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/ERC4626.test.sol @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "./ERC4626.prop.sol"; + +interface IMockERC20 is IERC20 { + function mint(address to, uint value) external; + function burn(address from, uint value) external; +} + +abstract contract ERC4626Test is ERC4626Prop { + function setUp() public virtual; + + uint constant N = 4; + + struct Init { + address[N] user; + uint[N] share; + uint[N] asset; + int yield; + } + + // setup initial vault state as follows: + // + // totalAssets == sum(init.share) + init.yield + // totalShares == sum(init.share) + // + // init.user[i]'s assets == init.asset[i] + // init.user[i]'s shares == init.share[i] + function setUpVault(Init memory init) public virtual { + // setup initial shares and assets for individual users + for (uint i = 0; i < N; i++) { + address user = init.user[i]; + vm.assume(_isEOA(user)); + // shares + uint shares = init.share[i]; + try IMockERC20(_underlying_).mint(user, shares) {} catch { vm.assume(false); } + _approve(_underlying_, user, _vault_, shares); + vm.prank(user); try IERC4626(_vault_).deposit(shares, user) {} catch { vm.assume(false); } + // assets + uint assets = init.asset[i]; + try IMockERC20(_underlying_).mint(user, assets) {} catch { vm.assume(false); } + } + + // setup initial yield for vault + setUpYield(init); + } + + // setup initial yield + function setUpYield(Init memory init) public virtual { + if (init.yield >= 0) { // gain + uint gain = uint(init.yield); + try IMockERC20(_underlying_).mint(_vault_, gain) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } else { // loss + vm.assume(init.yield > type(int).min); // avoid overflow in conversion + uint loss = uint(-1 * init.yield); + try IMockERC20(_underlying_).burn(_vault_, loss) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } + } + + // + // asset + // + + function test_asset(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_asset(caller); + } + + function test_totalAssets(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_totalAssets(caller); + } + + // + // convert + // + + function test_convertToShares(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToShares(caller1, caller2, assets); + } + + function test_convertToAssets(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToAssets(caller1, caller2, shares); + } + + // + // deposit + // + + function test_maxDeposit(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxDeposit(caller, receiver); + } + + function test_previewDeposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewDeposit(caller, receiver, other, assets); + } + + function test_deposit(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_deposit(caller, receiver, assets); + } + + // + // mint + // + + function test_maxMint(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxMint(caller, receiver); + } + + function test_previewMint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewMint(caller, receiver, other, shares); + } + + function test_mint(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_mint(caller, receiver, shares); + } + + // + // withdraw + // + + function test_maxWithdraw(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxWithdraw(caller, owner); + } + + function test_previewWithdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewWithdraw(caller, receiver, owner, other, assets); + } + + function test_withdraw(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, allowance); + prop_withdraw(caller, receiver, owner, assets); + } + + function testFail_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + vm.assume(caller != owner); + vm.assume(assets > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); uint shares = IERC4626(_vault_).withdraw(assets, receiver, owner); + assertGt(shares, 0); // this assert is expected to fail + } + + // + // redeem + // + + function test_maxRedeem(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxRedeem(caller, owner); + } + + function test_previewRedeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewRedeem(caller, receiver, owner, other, shares); + } + + function test_redeem(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, allowance); + prop_redeem(caller, receiver, owner, shares); + } + + function testFail_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + vm.assume(caller != owner); + vm.assume(shares > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); IERC4626(_vault_).redeem(shares, receiver, owner); + } + + // + // round trip tests + // + + function test_RT_deposit_redeem(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_redeem(caller, assets); + } + + function test_RT_deposit_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_withdraw(caller, assets); + } + + function test_RT_redeem_deposit(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_deposit(caller, shares); + } + + function test_RT_redeem_mint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_mint(caller, shares); + } + + function test_RT_mint_withdraw(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_withdraw(caller, shares); + } + + function test_RT_mint_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_redeem(caller, shares); + } + + function test_RT_withdraw_mint(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_mint(caller, assets); + } + + function test_RT_withdraw_deposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_deposit(caller, assets); + } + + // + // utils + // + + function _isContract(address account) internal view returns (bool) { return account.code.length > 0; } + function _isEOA (address account) internal view returns (bool) { return account.code.length == 0; } + + function _approve(address token, address owner, address spender, uint amount) internal { + vm.prank(owner); _safeApprove(token, spender, 0); + vm.prank(owner); _safeApprove(token, spender, amount); + } + + function _safeApprove(address token, address spender, uint amount) internal { + (bool success, bytes memory retdata) = token.call(abi.encodeWithSelector(IERC20.approve.selector, spender, amount)); + vm.assume(success); + if (retdata.length > 0) vm.assume(abi.decode(retdata, (bool))); + } + + function _max_deposit(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_underlying_).balanceOf(from); + } + + function _max_mint(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToShares(IERC20(_underlying_).balanceOf(from)); + } + + function _max_withdraw(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToAssets(IERC20(_vault_).balanceOf(from)); // may be different from maxWithdraw(from) + } + + function _max_redeem(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_vault_).balanceOf(from); // may be different from maxRedeem(from) + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/LICENSE b/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/README.md b/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/README.md new file mode 100644 index 0000000..651e443 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/erc4626-tests/README.md @@ -0,0 +1,116 @@ +# ERC4626 Property Tests + +Foundry (dapptools-style) property-based tests for [ERC4626] standard conformance. + +[ERC4626]: + +You can read our post on "_[Generalized property tests for ERC4626 vaults][post]_." + +[post]: + +## Overview + +#### What is it? +- Test suites for checking if the given ERC4626 implementation satisfies the **standard requirements**. +- Dapptools-style **property-based tests** for fuzzing or symbolic execution testing. +- Tests that are **independent** from implementation details, thus applicable for any ERC4626 vaults. + +#### What isn’t it? +- It does NOT test implementation-specific details, e.g., how to generate and distribute yields, how to compute the share price, etc. + +#### Testing properties: + +- **Round-trip properties**: no one can make a free profit by depositing and immediately withdrawing back and forth. + +- **Functional correctness**: the `deposit()`, `mint()`, `withdraw()`, and `redeem()` functions update the balance and allowance properly. + +- The `preview{Deposit,Redeem}()` functions **MUST NOT over-estimate** the exact amount.[^1] + +[^1]: That is, the `deposit()` and `redeem()` functions “MUST return the same or more amounts as their preview function if called in the same transaction.” + +- The `preview{Mint,Withdraw}()` functions **MUST NOT under-estimate** the exact amount.[^2] + +[^2]: That is, the `mint()` and `withdraw()` functions “MUST return the same or fewer amounts as their preview function if called in the same transaction.” + +- The `convertTo{Shares,Assets}` functions “**MUST NOT show any variations** depending on the caller.” + +- The `asset()`, `totalAssets()`, and `max{Deposit,Mint,Withdraw,Redeem}()` functions “**MUST NOT revert**.” + +## Usage + +**Step 0**: Install [foundry] and add [forge-std] in your vault repo: +```bash +$ curl -L https://foundry.paradigm.xyz | bash + +$ cd /path/to/your-erc4626-vault +$ forge install foundry-rs/forge-std +``` + +[foundry]: +[forge-std]: + +**Step 1**: Add this [erc4626-tests] as a dependency to your vault: +```bash +$ cd /path/to/your-erc4626-vault +$ forge install a16z/erc4626-tests +``` + +[erc4626-tests]: + +**Step 2**: Extend the abstract test contract [`ERC4626Test`](ERC4626.test.sol) with your own custom vault setup method, for example: + +```solidity +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "erc4626-tests/ERC4626.test.sol"; + +import { ERC20Mock } from "/path/to/mocks/ERC20Mock.sol"; +import { ERC4626Mock } from "/path/to/mocks/ERC4626Mock.sol"; + +contract ERC4626StdTest is ERC4626Test { + function setUp() public override { + _underlying_ = address(new ERC20Mock("Mock ERC20", "MERC20", 18)); + _vault_ = address(new ERC4626Mock(ERC20Mock(__underlying__), "Mock ERC4626", "MERC4626")); + _delta_ = 0; + _vaultMayBeEmpty = false; + _unlimitedAmount = false; + } +} +``` + +Specifically, set the state variables as follows: +- `_vault_`: the address of your ERC4626 vault. +- `_underlying_`: the address of the underlying asset of your vault. Note that the default `setupVault()` and `setupYield()` methods of `ERC4626Test` assume that it implements `mint(address to, uint value)` and `burn(address from, uint value)`. You can override the setup methods with your own if such `mint()` and `burn()` are not implemented. +- `_delta_`: the maximum approximation error size to be passed to [`assertApproxEqAbs()`]. It must be given as an absolute value (not a percentage) in the smallest unit (e.g., Wei or Satoshi). Note that all the tests are expected to pass with `__delta__ == 0` as long as your vault follows the [preferred rounding direction] as specified in the standard. If your vault doesn't follow the preferred rounding direction, you can set `__delta__` to a reasonable size of rounding errors where the adversarial profit of exploiting such rounding errors stays sufficiently small compared to the gas cost. (You can read our [post] for more about the adversarial profit.) +- `_vaultMayBeEmpty`: when set to false, fuzz inputs that empties the vault are ignored. +- `_unlimitedAmount`: when set to false, fuzz inputs are restricted to the currently available amount from the caller. Limiting the amount can speed up fuzzing, but may miss some edge cases. + +[`assertApproxEqAbs()`]: + +[preferred rounding direction]: + +**Step 3**: Run `forge test` + +``` +$ forge test +``` + +## Examples + +Below are examples of adding these property tests to existing ERC4626 vaults: +- [OpenZeppelin ERC4626] [[diff](https://github.com/daejunpark/openzeppelin-contracts/pull/1/files)] +- [Solmate ERC4626] [[diff](https://github.com/daejunpark/solmate/pull/1/files)] +- [Revenue Distribution Token] [[diff](https://github.com/daejunpark/revenue-distribution-token/pull/1/files)] +- [Yield Daddy ERC4626 wrappers] [[diff](https://github.com/daejunpark/yield-daddy/pull/1/files)][^bug] + +[OpenZeppelin ERC4626]: +[Solmate ERC4626]: +[Revenue Distribution Token]: +[Yield Daddy ERC4626 wrappers]: + +[^bug]: Our property tests indeed revealed an [issue](https://github.com/timeless-fi/yield-daddy/issues/7) in their eToken testing mock contract. The tests passed after it is [fixed](https://github.com/daejunpark/yield-daddy/commit/721cf4bd766805fd409455434aa5fd1a9b2df25c). + +## Disclaimer + +_These smart contracts are being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the user interface or the smart contracts. They have not been audited and as such there can be no assurance they will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. THE SMART CONTRACTS CONTAINED HEREIN ARE FURNISHED AS IS, WHERE IS, WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY, NON-INFRINGEMENT OR FITNESS FOR ANY PARTICULAR PURPOSE. Further, use of any of these smart contracts may be restricted or prohibited under applicable law, including securities laws, and it is therefore strongly advised for you to contact a reputable attorney in any jurisdiction where these smart contracts may be accessible for any questions or concerns with respect thereto. Further, no information provided in this repo should be construed as investment advice or legal advice for any particular facts or circumstances, and is not meant to replace competent counsel. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See a16z.com/disclosures for more info._ diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.github/workflows/ci.yml b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..96b2336 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + # Backwards compatibility checks. + - name: Check compatibility with 0.8.0 + if: always() + run: forge build --skip test --use solc:0.8.0 + + - name: Check compatibility with 0.7.6 + if: always() + run: forge build --skip test --use solc:0.7.6 + + - name: Check compatibility with 0.7.0 + if: always() + run: forge build --skip test --use solc:0.7.0 + + - name: Check compatibility with 0.6.12 + if: always() + run: forge build --skip test --use solc:0.6.12 + + - name: Check compatibility with 0.6.2 + if: always() + run: forge build --skip test --use solc:0.6.2 + + # via-ir compilation time checks. + - name: Measure compilation time of Test with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTest.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of TestBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTestBase.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of Script with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScript.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of ScriptBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScriptBase.sol --use solc:0.8.17 --via-ir + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Run tests + run: forge test -vvv + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Check formatting + run: forge fmt --check diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.gitignore b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.gitmodules b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.gitmodules new file mode 100644 index 0000000..e124719 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ds-test"] + path = lib/ds-test + url = https://github.com/dapphub/ds-test diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/LICENSE-APACHE b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/LICENSE-APACHE @@ -0,0 +1,203 @@ +Copyright Contributors to Forge Standard Library + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/LICENSE-MIT b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright Contributors to Forge Standard Library + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER +DEALINGS IN THE SOFTWARE.R diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/README.md b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/README.md new file mode 100644 index 0000000..8494a7d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/README.md @@ -0,0 +1,250 @@ +# Forge Standard Library • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml) + +Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes. + +**Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).** + +## Install + +```bash +forge install foundry-rs/forge-std +``` + +## Contracts +### stdError + +This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors. + +See the contract itself for all error codes. + +#### Example usage + +```solidity + +import "forge-std/Test.sol"; + +contract TestContract is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } +} + +contract ErrorsTest { + function arithmeticError(uint256 a) public { + uint256 a = a - 100; + } +} +``` + +### stdStorage + +This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`). + +This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth. + +I.e.: +```solidity +struct T { + // depth 0 + uint256 a; + // depth 1 + uint256 b; +} +``` + +#### Example usage + +```solidity +import "forge-std/Test.sol"; + +contract TestContract is Test { + using stdStorage for StdStorage; + + Storage test; + + function setUp() public { + test = new Storage(); + } + + function testFindExists() public { + // Lets say we want to find the slot for the public + // variable `exists`. We just pass in the function selector + // to the `find` command + uint256 slot = stdstore.target(address(test)).sig("exists()").find(); + assertEq(slot, 0); + } + + function testWriteExists() public { + // Lets say we want to write to the slot for the public + // variable `exists`. We just pass in the function selector + // to the `checked_write` command + stdstore.target(address(test)).sig("exists()").checked_write(100); + assertEq(test.exists(), 100); + } + + // It supports arbitrary storage layouts, like assembly based storage locations + function testFindHidden() public { + // `hidden` is a random hash of a bytes, iteration through slots would + // not find it. Our mechanism does + // Also, you can use the selector instead of a string + uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find(); + assertEq(slot, uint256(keccak256("my.random.var"))); + } + + // If targeting a mapping, you have to pass in the keys necessary to perform the find + // i.e.: + function testFindMapping() public { + uint256 slot = stdstore + .target(address(test)) + .sig(test.map_addr.selector) + .with_key(address(this)) + .find(); + // in the `Storage` constructor, we wrote that this address' value was 1 in the map + // so when we load the slot, we expect it to be 1 + assertEq(uint(vm.load(address(test), bytes32(slot))), 1); + } + + // If the target is a struct, you can specify the field depth: + function testFindStruct() public { + // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc. + uint256 slot_for_a_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(0) + .find(); + + uint256 slot_for_b_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(1) + .find(); + + assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1); + assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2); + } +} + +// A complex storage contract +contract Storage { + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + constructor() { + map_addr[msg.sender] = 1; + } + + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + // mapping(address => Packed) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basicStruct = UnpackedStruct({ + a: 1, + b: 2 + }); + + function hidden() public view returns (bytes32 t) { + // an extremely hidden storage slot + bytes32 slot = keccak256("my.random.var"); + assembly { + t := sload(slot) + } + } +} +``` + +### stdCheats + +This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you. + + +#### Example usage: +```solidity + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +// Inherit the stdCheats +contract StdCheatsTest is Test { + Bar test; + function setUp() public { + test = new Bar(); + } + + function testHoax() public { + // we call `hoax`, which gives the target address + // eth and then calls `prank` + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + + // overloaded to allow you to specify how much eth to + // initialize the address with + hoax(address(1337), 1); + test.bar{value: 1}(address(1337)); + } + + function testStartHoax() public { + // we call `startHoax`, which gives the target address + // eth and then calls `startPrank` + // + // it is also overloaded so that you can specify an eth amount + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } +} + +contract Bar { + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } +} +``` + +### Std Assertions + +Expand upon the assertion functions from the `DSTest` library. + +### `console.log` + +Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log). +It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console2.sol"; +... +console2.log(someValue); +``` + +If you need compatibility with Hardhat, you must use the standard `console.sol` instead. +Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console.sol"; +... +console.log(someValue); +``` + +## License + +Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/foundry.toml b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/foundry.toml new file mode 100644 index 0000000..cca8301 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/foundry.toml @@ -0,0 +1,21 @@ +[profile.default] +fs_permissions = [{ access = "read-write", path = "./"}] + +[rpc_endpoints] +# The RPC URLs are modified versions of the default for testing initialization. +mainnet = "https://mainnet.infura.io/v3/7a8769b798b642f6933f2ed52042bd70" # Different API key. +optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash. +arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash. +needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}" + +[fmt] +# These are all the `forge fmt` defaults. +line_length = 120 +tab_width = 4 +bracket_spacing = false +int_types = 'long' +multiline_func_header = 'attributes_first' +quote_style = 'double' +number_underscore = 'preserve' +single_line_statement_blocks = 'preserve' +ignore = ["src/console.sol", "src/console2.sol"] \ No newline at end of file diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/.gitignore b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/.gitignore new file mode 100644 index 0000000..63f0b2c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/.gitignore @@ -0,0 +1,3 @@ +/.dapple +/build +/out diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/LICENSE b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/Makefile b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/Makefile new file mode 100644 index 0000000..661dac4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/Makefile @@ -0,0 +1,14 @@ +all:; dapp build + +test: + -dapp --use solc:0.4.23 build + -dapp --use solc:0.4.26 build + -dapp --use solc:0.5.17 build + -dapp --use solc:0.6.12 build + -dapp --use solc:0.7.5 build + +demo: + DAPP_SRC=demo dapp --use solc:0.7.5 build + -hevm dapp-test --verbose 3 + +.PHONY: test demo diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/default.nix b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/default.nix new file mode 100644 index 0000000..cf65419 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/default.nix @@ -0,0 +1,4 @@ +{ solidityPackage, dappsys }: solidityPackage { + name = "ds-test"; + src = ./src; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/demo/demo.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/demo/demo.sol new file mode 100644 index 0000000..f3bb48e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/demo/demo.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import "../src/test.sol"; + +contract DemoTest is DSTest { + function test_this() public pure { + require(true); + } + function test_logs() public { + emit log("-- log(string)"); + emit log("a string"); + + emit log("-- log_named_uint(string, uint)"); + emit log_named_uint("uint", 512); + + emit log("-- log_named_int(string, int)"); + emit log_named_int("int", -512); + + emit log("-- log_named_address(string, address)"); + emit log_named_address("address", address(this)); + + emit log("-- log_named_bytes32(string, bytes32)"); + emit log_named_bytes32("bytes32", "a string"); + + emit log("-- log_named_bytes(string, bytes)"); + emit log_named_bytes("bytes", hex"cafefe"); + + emit log("-- log_named_string(string, string)"); + emit log_named_string("string", "a string"); + + emit log("-- log_named_decimal_uint(string, uint, uint)"); + emit log_named_decimal_uint("decimal uint", 1.0e18, 18); + + emit log("-- log_named_decimal_int(string, int, uint)"); + emit log_named_decimal_int("decimal int", -1.0e18, 18); + } + event log_old_named_uint(bytes32,uint); + function test_old_logs() public { + emit log_old_named_uint("key", 500); + emit log_named_bytes32("bkey", "val"); + } + function test_trace() public view { + this.echo("string 1", "string 2"); + } + function test_multiline() public { + emit log("a multiline\\nstring"); + emit log("a multiline string"); + emit log_bytes("a string"); + emit log_bytes("a multiline\nstring"); + emit log_bytes("a multiline\\nstring"); + emit logs(hex"0000"); + emit log_named_bytes("0x0000", hex"0000"); + emit logs(hex"ff"); + } + function echo(string memory s1, string memory s2) public pure + returns (string memory, string memory) + { + return (s1, s2); + } + + function prove_this(uint x) public { + emit log_named_uint("sym x", x); + assertGt(x + 1, 0); + } + + function test_logn() public { + assembly { + log0(0x01, 0x02) + log1(0x01, 0x02, 0x03) + log2(0x01, 0x02, 0x03, 0x04) + log3(0x01, 0x02, 0x03, 0x04, 0x05) + } + } + + event MyEvent(uint, uint indexed, uint, uint indexed); + function test_events() public { + emit MyEvent(1, 2, 3, 4); + } + + function test_asserts() public { + string memory err = "this test has failed!"; + emit log("## assertTrue(bool)\n"); + assertTrue(false); + emit log("\n"); + assertTrue(false, err); + + emit log("\n## assertEq(address,address)\n"); + assertEq(address(this), msg.sender); + emit log("\n"); + assertEq(address(this), msg.sender, err); + + emit log("\n## assertEq32(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(uint,uint)\n"); + assertEq(uint(0), 1); + emit log("\n"); + assertEq(uint(0), 1, err); + + emit log("\n## assertEq(int,int)\n"); + assertEq(-1, -2); + emit log("\n"); + assertEq(-1, -2, err); + + emit log("\n## assertEqDecimal(int,int,uint)\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertEqDecimal(uint,uint,uint)\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGt(uint,uint)\n"); + assertGt(uint(0), 0); + emit log("\n"); + assertGt(uint(0), 0, err); + + emit log("\n## assertGt(int,int)\n"); + assertGt(-1, -1); + emit log("\n"); + assertGt(-1, -1, err); + + emit log("\n## assertGtDecimal(int,int,uint)\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGtDecimal(uint,uint,uint)\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGe(uint,uint)\n"); + assertGe(uint(0), 1); + emit log("\n"); + assertGe(uint(0), 1, err); + + emit log("\n## assertGe(int,int)\n"); + assertGe(-1, 0); + emit log("\n"); + assertGe(-1, 0, err); + + emit log("\n## assertGeDecimal(int,int,uint)\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGeDecimal(uint,uint,uint)\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertLt(uint,uint)\n"); + assertLt(uint(0), 0); + emit log("\n"); + assertLt(uint(0), 0, err); + + emit log("\n## assertLt(int,int)\n"); + assertLt(-1, -1); + emit log("\n"); + assertLt(-1, -1, err); + + emit log("\n## assertLtDecimal(int,int,uint)\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLtDecimal(uint,uint,uint)\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertLe(uint,uint)\n"); + assertLe(uint(1), 0); + emit log("\n"); + assertLe(uint(1), 0, err); + + emit log("\n## assertLe(int,int)\n"); + assertLe(0, -1); + emit log("\n"); + assertLe(0, -1, err); + + emit log("\n## assertLeDecimal(int,int,uint)\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLeDecimal(uint,uint,uint)\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertEq(string,string)\n"); + string memory s1 = "string 1"; + string memory s2 = "string 2"; + assertEq(s1, s2); + emit log("\n"); + assertEq(s1, s2, err); + + emit log("\n## assertEq0(bytes,bytes)\n"); + assertEq0(hex"abcdef01", hex"abcdef02"); + emit log("\n"); + assertEq0(hex"abcdef01", hex"abcdef02", err); + } +} + +contract DemoTestWithSetUp { + function setUp() public { + } + function test_pass() public pure { + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/package.json b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/package.json new file mode 100644 index 0000000..4802ada --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "ds-test", + "version": "1.0.0", + "description": "Assertions, equality checks and other test helpers ", + "bugs": "https://github.com/dapphub/ds-test/issues", + "license": "GPL-3.0", + "author": "Contributors to ds-test", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/dapphub/ds-test.git" + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/src/test.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/src/test.sol new file mode 100644 index 0000000..515a3bd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/lib/ds-test/src/test.sol @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.5.0; + +contract DSTest { + event log (string); + event logs (bytes); + + event log_address (address); + event log_bytes32 (bytes32); + event log_int (int); + event log_uint (uint); + event log_bytes (bytes); + event log_string (string); + + event log_named_address (string key, address val); + event log_named_bytes32 (string key, bytes32 val); + event log_named_decimal_int (string key, int val, uint decimals); + event log_named_decimal_uint (string key, uint val, uint decimals); + event log_named_int (string key, int val); + event log_named_uint (string key, uint val); + event log_named_bytes (string key, bytes val); + event log_named_string (string key, string val); + + bool public IS_TEST = true; + bool private _failed; + + address constant HEVM_ADDRESS = + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); + + modifier mayRevert() { _; } + modifier testopts(string memory) { _; } + + function failed() public returns (bool) { + if (_failed) { + return _failed; + } else { + bool globalFailed = false; + if (hasHEVMContext()) { + (, bytes memory retdata) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("load(address,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed")) + ) + ); + globalFailed = abi.decode(retdata, (bool)); + } + return globalFailed; + } + } + + function fail() internal { + if (hasHEVMContext()) { + (bool status, ) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("store(address,bytes32,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) + ) + ); + status; // Silence compiler warnings + } + _failed = true; + } + + function hasHEVMContext() internal view returns (bool) { + uint256 hevmCodeSize = 0; + assembly { + hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) + } + return hevmCodeSize > 0; + } + + modifier logs_gas() { + uint startGas = gasleft(); + _; + uint endGas = gasleft(); + emit log_named_uint("gas", startGas - endGas); + } + + function assertTrue(bool condition) internal { + if (!condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertTrue(bool condition, string memory err) internal { + if (!condition) { + emit log_named_string("Error", err); + assertTrue(condition); + } + } + + function assertEq(address a, address b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [address]"); + emit log_named_address(" Expected", b); + emit log_named_address(" Actual", a); + fail(); + } + } + function assertEq(address a, address b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes32 a, bytes32 b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [bytes32]"); + emit log_named_bytes32(" Expected", b); + emit log_named_bytes32(" Actual", a); + fail(); + } + } + function assertEq(bytes32 a, bytes32 b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + function assertEq32(bytes32 a, bytes32 b) internal { + assertEq(a, b); + } + function assertEq32(bytes32 a, bytes32 b, string memory err) internal { + assertEq(a, b, err); + } + + function assertEq(int a, int b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + function assertEq(int a, int b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEq(uint a, uint b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + function assertEq(uint a, uint b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEqDecimal(int a, int b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal int]"); + emit log_named_decimal_int(" Expected", b, decimals); + emit log_named_decimal_int(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + function assertEqDecimal(uint a, uint b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Expected", b, decimals); + emit log_named_decimal_uint(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + + function assertGt(uint a, uint b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGt(uint a, uint b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGt(int a, int b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGt(int a, int b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGtDecimal(int a, int b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + function assertGtDecimal(uint a, uint b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + + function assertGe(uint a, uint b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGe(uint a, uint b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGe(int a, int b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGe(int a, int b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGeDecimal(int a, int b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + function assertGeDecimal(uint a, uint b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertLt(uint a, uint b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLt(uint a, uint b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLt(int a, int b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLt(int a, int b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLtDecimal(int a, int b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + function assertLtDecimal(uint a, uint b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + + function assertLe(uint a, uint b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLe(uint a, uint b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLe(int a, int b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLe(int a, int b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLeDecimal(int a, int b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + function assertLeDecimal(uint a, uint b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log("Error: a == b not satisfied [string]"); + emit log_named_string(" Expected", b); + emit log_named_string(" Actual", a); + fail(); + } + } + function assertEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { + ok = true; + if (a.length == b.length) { + for (uint i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + ok = false; + } + } + } else { + ok = false; + } + } + function assertEq0(bytes memory a, bytes memory b) internal { + if (!checkEq0(a, b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + function assertEq0(bytes memory a, bytes memory b, string memory err) internal { + if (!checkEq0(a, b)) { + emit log_named_string("Error", err); + assertEq0(a, b); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/package.json b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/package.json new file mode 100644 index 0000000..a000ac8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.2.0", + "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", + "homepage": "https://book.getfoundry.sh/forge/forge-std", + "bugs": "https://github.com/foundry-rs/forge-std/issues", + "license": "(Apache-2.0 OR MIT)", + "author": "Contributors to Forge Standard Library", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/foundry-rs/forge-std.git" + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Base.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..e0d8b05 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Base.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {StdStorage} from "./StdStorage.sol"; +import {Vm, VmSafe} from "./Vm.sol"; + +abstract contract CommonBase { + // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. + address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + // console.sol and console2.sol work by executing a staticcall to this address. + address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; + // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38. + address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))); + // Address of the test contract, deployed by the DEFAULT_SENDER. + address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; + + uint256 internal constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + Vm internal constant vm = Vm(VM_ADDRESS); + StdStorage internal stdstore; +} + +abstract contract TestBase is CommonBase {} + +abstract contract ScriptBase is CommonBase { + // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Script.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..bffccad --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Script.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Standard Library's default Script. + +// 🧩 MODULES +import {ScriptBase} from "./Base.sol"; +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheatsSafe} from "./StdCheats.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorageSafe} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {VmSafe} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {ScriptBase} from "./Base.sol"; + +// ⭐️ SCRIPT +abstract contract Script is StdChains, StdCheatsSafe, StdUtils, ScriptBase { + // Note: IS_SCRIPT() must return true. + bool public IS_SCRIPT = true; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdAssertions.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..733dbba --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {DSTest} from "ds-test/test.sol"; +import {stdMath} from "./StdMath.sol"; + +abstract contract StdAssertions is DSTest { + event log_array(uint256[] val); + event log_array(int256[] val); + event log_array(address[] val); + event log_named_array(string key, uint256[] val); + event log_named_array(string key, int256[] val); + event log_named_array(string key, address[] val); + + function fail(string memory err) internal virtual { + emit log_named_string("Error", err); + fail(); + } + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); + } + + function assertEq(bool a, bool b) internal virtual { + if (a != b) { + emit log("Error: a == b not satisfied [bool]"); + emit log_named_string(" Expected", b ? "true" : "false"); + emit log_named_string(" Actual", a ? "true" : "false"); + fail(); + } + } + + function assertEq(bool a, bool b, string memory err) internal virtual { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes memory a, bytes memory b) internal virtual { + assertEq0(a, b); + } + + function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { + assertEq0(a, b, err); + } + + function assertEq(uint256[] memory a, uint256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [uint[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(int256[] memory a, int256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [int[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(address[] memory a, address[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [address[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + // Legacy helper + function assertEqUint(uint256 a, uint256 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdChains.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..68755bf --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdChains.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +/** + * StdChains provides information about EVM compatible chains that can be used in scripts/tests. + * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are + * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of + * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the + * alias used in this contract, which can be found as the first argument to the + * `setChainWithDefaultRpcUrl` call in the `initialize` function. + * + * There are two main ways to use this contract: + * 1. Set a chain with `setChain(string memory chainAlias, Chain memory chain)` + * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. + * + * The first time either of those are used, chains are initialized with the default set of RPC URLs. + * This is done in `initialize`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in + * `defaultRpcUrls`. + * + * The `setChain` function is straightforward, and it simply saves off the given chain data. + * + * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say + * we want to retrieve `mainnet`'s RPC URL: + * - If you haven't set any mainnet chain info with `setChain` and you haven't specified that + * chain in `foundry.toml`, the default data and RPC URL will be returned. + * - If you have set a mainnet RPC URL in `foundry.toml` it will return that, if valid (e.g. if + * a URL is given or if an environment variable is given and that environment variable exists). + * Otherwise, the default data is returned. + * - If you specified data with `setChain` it will return that. + * + * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> defaults. + */ +abstract contract StdChains { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private initialized; + + struct Chain { + // The chain name. + string name; + // The chain's Chain ID. + uint256 chainId; + // A default RPC endpoint for this chain. + // NOTE: This default RPC URL is included for convenience to facilitate quick tests and + // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy + // usage as you will be throttled and this is a disservice to others who need this endpoint. + string rpcUrl; + } + + // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data. + mapping(string => Chain) private chains; + // Maps from the chain's alias to it's default RPC URL. + mapping(string => string) private defaultRpcUrls; + // Maps from a chain ID to it's alias. + mapping(uint256 => string) private idToAlias; + + // The RPC URL will be fetched from config or defaultRpcUrls if possible. + function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) { + require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string."); + + initialize(); + chain = chains[chainAlias]; + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + function getChain(uint256 chainId) internal virtual returns (Chain memory chain) { + require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0."); + initialize(); + string memory chainAlias = idToAlias[chainId]; + + chain = chains[chainAlias]; + + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, Chain memory chain) internal virtual { + require( + bytes(chainAlias).length != 0, "StdChains setChain(string,Chain): Chain alias cannot be the empty string." + ); + + require(chain.chainId != 0, "StdChains setChain(string,Chain): Chain ID cannot be 0."); + + initialize(); + string memory foundAlias = idToAlias[chain.chainId]; + + require( + bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)), + string( + abi.encodePacked( + "StdChains setChain(string,Chain): Chain ID ", + vm.toString(chain.chainId), + " already used by \"", + foundAlias, + "\"." + ) + ) + ); + + uint256 oldChainId = chains[chainAlias].chainId; + delete idToAlias[oldChainId]; + + chains[chainAlias] = chain; + idToAlias[chain.chainId] = chainAlias; + } + + // lookup rpcUrl, in descending order of priority: + // current -> config (foundry.toml) -> default + function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) + private + view + returns (Chain memory) + { + if (bytes(chain.rpcUrl).length == 0) { + try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) { + chain.rpcUrl = configRpcUrl; + } catch (bytes memory err) { + chain.rpcUrl = defaultRpcUrls[chainAlias]; + // distinguish 'not found' from 'cannot read' + bytes memory notFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + if (keccak256(notFoundError) != keccak256(err) || bytes(chain.rpcUrl).length == 0) { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, err), mload(err)) + } + } + } + } + return chain; + } + + function initialize() private { + if (initialized) return; + + initialized = true; + + // If adding an RPC here, make sure to test the default RPC URL in `testRpcs` + setChainWithDefaultRpcUrl("anvil", Chain("Anvil", 31337, "http://127.0.0.1:8545")); + setChainWithDefaultRpcUrl( + "mainnet", Chain("Mainnet", 1, "https://mainnet.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl( + "goerli", Chain("Goerli", 5, "https://goerli.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl( + "sepolia", Chain("Sepolia", 11155111, "https://sepolia.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl("optimism", Chain("Optimism", 10, "https://mainnet.optimism.io")); + setChainWithDefaultRpcUrl("optimism_goerli", Chain("Optimism Goerli", 420, "https://goerli.optimism.io")); + setChainWithDefaultRpcUrl("arbitrum_one", Chain("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl( + "arbitrum_one_goerli", Chain("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc") + ); + setChainWithDefaultRpcUrl("arbitrum_nova", Chain("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl("polygon", Chain("Polygon", 137, "https://polygon-rpc.com")); + setChainWithDefaultRpcUrl("polygon_mumbai", Chain("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com")); + setChainWithDefaultRpcUrl("avalanche", Chain("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc")); + setChainWithDefaultRpcUrl( + "avalanche_fuji", Chain("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc") + ); + setChainWithDefaultRpcUrl("bnb_smart_chain", Chain("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org")); + setChainWithDefaultRpcUrl("bnb_smart_chain_testnet", Chain("BNB Smart Chain Testnet", 97, "https://data-seed-prebsc-1-s1.binance.org:8545"));// forgefmt: disable-line + setChainWithDefaultRpcUrl("gnosis_chain", Chain("Gnosis Chain", 100, "https://rpc.gnosischain.com")); + } + + // set chain info, with priority to chainAlias' rpc url in foundry.toml + function setChainWithDefaultRpcUrl(string memory chainAlias, Chain memory chain) private { + string memory rpcUrl = chain.rpcUrl; + defaultRpcUrls[chainAlias] = rpcUrl; + chain.rpcUrl = ""; + setChain(chainAlias, chain); + chain.rpcUrl = rpcUrl; // restore argument + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdCheats.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..f7204a5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdCheats.sol @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {Vm} from "./Vm.sol"; + +abstract contract StdCheatsSafe { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private gasMeteringOff; + + // Data structures to parse Transaction objects from the broadcast artifact + // that conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawTx1559 { + string[] arguments; + address contractAddress; + string contractName; + // json value name = function + string functionSig; + bytes32 hash; + // json value name = tx + RawTx1559Detail txDetail; + // json value name = type + string opcode; + } + + struct RawTx1559Detail { + AccessList[] accessList; + bytes data; + address from; + bytes gas; + bytes nonce; + address to; + bytes txType; + bytes value; + } + + struct Tx1559 { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + bytes32 hash; + Tx1559Detail txDetail; + string opcode; + } + + struct Tx1559Detail { + AccessList[] accessList; + bytes data; + address from; + uint256 gas; + uint256 nonce; + address to; + uint256 txType; + uint256 value; + } + + // Data structures to parse Transaction objects from the broadcast artifact + // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct TxLegacy { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + string hash; + string opcode; + TxDetailLegacy transaction; + } + + struct TxDetailLegacy { + AccessList[] accessList; + uint256 chainId; + bytes data; + address from; + uint256 gas; + uint256 gasPrice; + bytes32 hash; + uint256 nonce; + bytes1 opcode; + bytes32 r; + bytes32 s; + uint256 txType; + address to; + uint8 v; + uint256 value; + } + + struct AccessList { + address accessAddress; + bytes32[] storageKeys; + } + + // Data structures to parse Receipt objects from the broadcast artifact. + // The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawReceipt { + bytes32 blockHash; + bytes blockNumber; + address contractAddress; + bytes cumulativeGasUsed; + bytes effectiveGasPrice; + address from; + bytes gasUsed; + RawReceiptLog[] logs; + bytes logsBloom; + bytes status; + address to; + bytes32 transactionHash; + bytes transactionIndex; + } + + struct Receipt { + bytes32 blockHash; + uint256 blockNumber; + address contractAddress; + uint256 cumulativeGasUsed; + uint256 effectiveGasPrice; + address from; + uint256 gasUsed; + ReceiptLog[] logs; + bytes logsBloom; + uint256 status; + address to; + bytes32 transactionHash; + uint256 transactionIndex; + } + + // Data structures to parse the entire broadcast artifact, assuming the + // transactions conform to EIP1559. + + struct EIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + Receipt[] receipts; + uint256 timestamp; + Tx1559[] transactions; + TxReturn[] txReturns; + } + + struct RawEIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + RawReceipt[] receipts; + TxReturn[] txReturns; + uint256 timestamp; + RawTx1559[] transactions; + } + + struct RawReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + bytes blockNumber; + bytes data; + bytes logIndex; + bool removed; + bytes32[] topics; + bytes32 transactionHash; + bytes transactionIndex; + bytes transactionLogIndex; + } + + struct ReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + uint256 blockNumber; + bytes data; + uint256 logIndex; + bytes32[] topics; + uint256 transactionIndex; + uint256 transactionLogIndex; + bool removed; + } + + struct TxReturn { + string internalType; + string value; + } + + function assumeNoPrecompiles(address addr) internal virtual { + // Assembly required since `block.chainid` was introduced in 0.8.0. + uint256 chainId; + assembly { + chainId := chainid() + } + assumeNoPrecompiles(addr, chainId); + } + + function assumeNoPrecompiles(address addr, uint256 chainId) internal virtual { + // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific + // address), but the same rationale for excluding them applies so we include those too. + + // These should be present on all EVM-compatible chains. + vm.assume(addr < address(0x1) || addr > address(0x9)); + + // forgefmt: disable-start + if (chainId == 10 || chainId == 420) { + // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21 + vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800)); + } else if (chainId == 42161 || chainId == 421613) { + // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains + vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068)); + } else if (chainId == 43114 || chainId == 43113) { + // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59 + vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff)); + vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF)); + vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff)); + } + // forgefmt: disable-end + } + + function readEIP1559ScriptArtifact(string memory path) + internal + view + virtual + returns (EIP1559ScriptArtifact memory) + { + string memory data = vm.readFile(path); + bytes memory parsedData = vm.parseJson(data); + RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact)); + EIP1559ScriptArtifact memory artifact; + artifact.libraries = rawArtifact.libraries; + artifact.path = rawArtifact.path; + artifact.timestamp = rawArtifact.timestamp; + artifact.pending = rawArtifact.pending; + artifact.txReturns = rawArtifact.txReturns; + artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts); + artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions); + return artifact; + } + + function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) { + Tx1559[] memory txs = new Tx1559[](rawTxs.length); + for (uint256 i; i < rawTxs.length; i++) { + txs[i] = rawToConvertedEIPTx1559(rawTxs[i]); + } + return txs; + } + + function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) { + Tx1559 memory transaction; + transaction.arguments = rawTx.arguments; + transaction.contractName = rawTx.contractName; + transaction.functionSig = rawTx.functionSig; + transaction.hash = rawTx.hash; + transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail); + transaction.opcode = rawTx.opcode; + return transaction; + } + + function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail) + internal + pure + virtual + returns (Tx1559Detail memory) + { + Tx1559Detail memory txDetail; + txDetail.data = rawDetail.data; + txDetail.from = rawDetail.from; + txDetail.to = rawDetail.to; + txDetail.nonce = _bytesToUint(rawDetail.nonce); + txDetail.txType = _bytesToUint(rawDetail.txType); + txDetail.value = _bytesToUint(rawDetail.value); + txDetail.gas = _bytesToUint(rawDetail.gas); + txDetail.accessList = rawDetail.accessList; + return txDetail; + } + + function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions"); + RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[])); + return rawToConvertedEIPTx1559s(rawTxs); + } + + function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559)); + return rawToConvertedEIPTx1559(rawTx); + } + + // Analogous to readTransactions, but for receipts. + function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts"); + RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[])); + return rawToConvertedReceipts(rawReceipts); + } + + function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt)); + return rawToConvertedReceipt(rawReceipt); + } + + function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) { + Receipt[] memory receipts = new Receipt[](rawReceipts.length); + for (uint256 i; i < rawReceipts.length; i++) { + receipts[i] = rawToConvertedReceipt(rawReceipts[i]); + } + return receipts; + } + + function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) { + Receipt memory receipt; + receipt.blockHash = rawReceipt.blockHash; + receipt.to = rawReceipt.to; + receipt.from = rawReceipt.from; + receipt.contractAddress = rawReceipt.contractAddress; + receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice); + receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed); + receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed); + receipt.status = _bytesToUint(rawReceipt.status); + receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex); + receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber); + receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs); + receipt.logsBloom = rawReceipt.logsBloom; + receipt.transactionHash = rawReceipt.transactionHash; + return receipt; + } + + function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs) + internal + pure + virtual + returns (ReceiptLog[] memory) + { + ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length); + for (uint256 i; i < rawLogs.length; i++) { + logs[i].logAddress = rawLogs[i].logAddress; + logs[i].blockHash = rawLogs[i].blockHash; + logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber); + logs[i].data = rawLogs[i].data; + logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex); + logs[i].topics = rawLogs[i].topics; + logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex); + logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex); + logs[i].removed = rawLogs[i].removed; + } + return logs; + } + + // Deploy a contract by fetching the contract bytecode from + // the artifacts directory + // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))` + function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed."); + } + + function deployCode(string memory what) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string): Deployment failed."); + } + + /// @dev deploy contract with value on construction + function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed."); + } + + function deployCode(string memory what, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed."); + } + + // creates a labeled address and the corresponding private key + function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) { + privateKey = uint256(keccak256(abi.encodePacked(name))); + addr = vm.addr(privateKey); + vm.label(addr, name); + } + + // creates a labeled address + function makeAddr(string memory name) internal virtual returns (address addr) { + (addr,) = makeAddrAndKey(name); + } + + function deriveRememberKey(string memory mnemonic, uint32 index) + internal + virtual + returns (address who, uint256 privateKey) + { + privateKey = vm.deriveKey(mnemonic, index); + who = vm.rememberKey(privateKey); + } + + function _bytesToUint(bytes memory b) private pure returns (uint256) { + require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function isFork() internal virtual returns (bool status) { + try vm.activeFork() { + status = true; + } catch (bytes memory) {} + } + + modifier skipWhenForking() { + if (!isFork()) { + _; + } + } + + modifier skipWhenNotForking() { + if (isFork()) { + _; + } + } + + modifier noGasMetering() { + vm.pauseGasMetering(); + // To prevent turning gas monitoring back on with nested functions that use this modifier, + // we check if gasMetering started in the off position. If it did, we don't want to turn + // it back on until we exit the top level function that used the modifier + // + // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well. + // funcA will have `gasStartedOff` as false, funcB will have it as true, + // so we only turn metering back on at the end of the funcA + bool gasStartedOff = gasMeteringOff; + gasMeteringOff = true; + + _; + + // if gas metering was on when this modifier was called, turn it back on at the end + if (!gasStartedOff) { + gasMeteringOff = false; + vm.resumeGasMetering(); + } + } +} + +// Wrappers around cheatcodes to avoid footguns +abstract contract StdCheats is StdCheatsSafe { + using stdStorage for StdStorage; + + StdStorage private stdstore; + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + // Skip forward or rewind time by the specified number of seconds + function skip(uint256 time) internal virtual { + vm.warp(block.timestamp + time); + } + + function rewind(uint256 time) internal virtual { + vm.warp(block.timestamp - time); + } + + // Setup a prank from an address that has some ether + function hoax(address who) internal virtual { + vm.deal(who, 1 << 128); + vm.prank(who); + } + + function hoax(address who, uint256 give) internal virtual { + vm.deal(who, give); + vm.prank(who); + } + + function hoax(address who, address origin) internal virtual { + vm.deal(who, 1 << 128); + vm.prank(who, origin); + } + + function hoax(address who, address origin, uint256 give) internal virtual { + vm.deal(who, give); + vm.prank(who, origin); + } + + // Start perpetual prank from an address that has some ether + function startHoax(address who) internal virtual { + vm.deal(who, 1 << 128); + vm.startPrank(who); + } + + function startHoax(address who, uint256 give) internal virtual { + vm.deal(who, give); + vm.startPrank(who); + } + + // Start perpetual prank from an address that has some ether + // tx.origin is set to the origin parameter + function startHoax(address who, address origin) internal virtual { + vm.deal(who, 1 << 128); + vm.startPrank(who, origin); + } + + function startHoax(address who, address origin, uint256 give) internal virtual { + vm.deal(who, give); + vm.startPrank(who, origin); + } + + function changePrank(address who) internal virtual { + vm.stopPrank(); + vm.startPrank(who); + } + + // The same as Vm's `deal` + // Use the alternative signature for ERC20 tokens + function deal(address to, uint256 give) internal virtual { + vm.deal(to, give); + } + + // Set the balance of an account for any ERC20 token + // Use the alternative signature to update `totalSupply` + function deal(address token, address to, uint256 give) internal virtual { + deal(token, to, give, false); + } + + function deal(address token, address to, uint256 give, bool adjust) internal virtual { + // get current balance + (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to)); + uint256 prevBal = abi.decode(balData, (uint256)); + + // update balance + stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give); + + // update total supply + if (adjust) { + (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd)); + uint256 totSup = abi.decode(totSupData, (uint256)); + if (give < prevBal) { + totSup -= (prevBal - give); + } else { + totSup += (give - prevBal); + } + stdstore.target(token).sig(0x18160ddd).checked_write(totSup); + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdError.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdError.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test +pragma solidity >=0.6.2 <0.9.0; + +library stdError { + bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); + bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); + bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); + bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); + bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); + bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); + bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); + bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); + bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdJson.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..2dee471 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdJson.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +// Helpers for parsing and writing JSON files +// To parse: +// ``` +// using stdJson for string; +// string memory json = vm.readFile("some_peth"); +// json.parseUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "deploymentArtifact"; +// Contract contract = new Contract(); +// json.serialize("contractAddress", address(contract)); +// json = json.serialize("deploymentTimes", uint(1)); +// // store the stringified JSON to the 'json' variable we have been using as a key +// // as we won't need it any longer +// string memory json2 = "finalArtifact"; +// string memory final = json2.serialize("depArtifact", json); +// final.write(""); +// ``` + +library stdJson { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) { + return vm.parseJson(json, key); + } + + function readUint(string memory json, string memory key) internal pure returns (uint256) { + return abi.decode(vm.parseJson(json, key), (uint256)); + } + + function readUintArray(string memory json, string memory key) internal pure returns (uint256[] memory) { + return abi.decode(vm.parseJson(json, key), (uint256[])); + } + + function readInt(string memory json, string memory key) internal pure returns (int256) { + return abi.decode(vm.parseJson(json, key), (int256)); + } + + function readIntArray(string memory json, string memory key) internal pure returns (int256[] memory) { + return abi.decode(vm.parseJson(json, key), (int256[])); + } + + function readBytes32(string memory json, string memory key) internal pure returns (bytes32) { + return abi.decode(vm.parseJson(json, key), (bytes32)); + } + + function readBytes32Array(string memory json, string memory key) internal pure returns (bytes32[] memory) { + return abi.decode(vm.parseJson(json, key), (bytes32[])); + } + + function readString(string memory json, string memory key) internal pure returns (string memory) { + return abi.decode(vm.parseJson(json, key), (string)); + } + + function readStringArray(string memory json, string memory key) internal pure returns (string[] memory) { + return abi.decode(vm.parseJson(json, key), (string[])); + } + + function readAddress(string memory json, string memory key) internal pure returns (address) { + return abi.decode(vm.parseJson(json, key), (address)); + } + + function readAddressArray(string memory json, string memory key) internal pure returns (address[] memory) { + return abi.decode(vm.parseJson(json, key), (address[])); + } + + function readBool(string memory json, string memory key) internal pure returns (bool) { + return abi.decode(vm.parseJson(json, key), (bool)); + } + + function readBoolArray(string memory json, string memory key) internal pure returns (bool[] memory) { + return abi.decode(vm.parseJson(json, key), (bool[])); + } + + function readBytes(string memory json, string memory key) internal pure returns (bytes memory) { + return abi.decode(vm.parseJson(json, key), (bytes)); + } + + function readBytesArray(string memory json, string memory key) internal pure returns (bytes[] memory) { + return abi.decode(vm.parseJson(json, key), (bytes[])); + } + + function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bool[] memory value) + internal + returns (string memory) + { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256[] memory value) + internal + returns (string memory) + { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256[] memory value) + internal + returns (string memory) + { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address[] memory value) + internal + returns (string memory) + { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string[] memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function write(string memory jsonKey, string memory path) internal { + vm.writeJson(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeJson(jsonKey, path, valueKey); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdMath.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +library stdMath { + int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; + + function abs(int256 a) internal pure returns (uint256) { + // Required or it will fail when `a = type(int256).min` + if (a == INT256_MIN) { + return 57896044618658097711785492504343953926634992332820282019728792003956564819968; + } + + return uint256(a > 0 ? a : -a); + } + + function delta(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a - b : b - a; + } + + function delta(int256 a, int256 b) internal pure returns (uint256) { + // a and b are of the same sign + // this works thanks to two's complement, the left-most bit is the sign bit + if ((a ^ b) > -1) { + return delta(abs(a), abs(b)); + } + + // a and b are of opposite signs + return abs(a) + abs(b); + } + + function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + + return absDelta * 1e18 / b; + } + + function percentDelta(int256 a, int256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + uint256 absB = abs(b); + + return absDelta * 1e18 / absB; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdStorage.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..b0bfc00 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; + mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; +} + +library stdStorageSafe { + event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot); + event WARNING_UninitedSlot(address who, uint256 slot); + + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against + // slot complexity: + // if flat, will be bytes32(uint256(uint)); + // if map, will be keccak256(abi.encode(key, uint(slot))); + // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot))))); + // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); + function find(StdStorage storage self) internal returns (uint256) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + vm.record(); + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + (bytes32[] memory reads,) = vm.accesses(address(who)); + if (reads.length == 1) { + bytes32 curr = vm.load(who, reads[0]); + if (curr == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[0])); + } + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + } else if (reads.length > 1) { + for (uint256 i = 0; i < reads.length; i++) { + bytes32 prev = vm.load(who, reads[i]); + if (prev == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[i])); + } + // store + vm.store(who, reads[i], bytes32(hex"1337")); + bool success; + bytes memory rdat; + { + (success, rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + if (success && fdat == bytes32(hex"1337")) { + // we found which of the slots is the actual one + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + vm.store(who, reads[i], prev); + break; + } + vm.store(who, reads[i], prev); + } + } else { + require(false, "stdStorage find(StdStorage): No storage use detected for target."); + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], + "stdStorage find(StdStorage): Slot(s) not found." + ); + + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + self._target = _target; + return self; + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + self._sig = _sig; + return self; + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + self._sig = sigs(_sig); + return self; + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + self._keys.push(bytes32(uint256(uint160(who)))); + return self; + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + self._keys.push(bytes32(amt)); + return self; + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + self._keys.push(key); + return self; + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + self._depth = _depth; + return self; + } + + function read(StdStorage storage self) private returns (bytes memory) { + address t = self._target; + uint256 s = find(self); + return abi.encode(vm.load(t, bytes32(s))); + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return abi.decode(read(self), (bytes32)); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + int256 v = read_int(self); + if (v == 0) return false; + if (v == 1) return true; + revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + } + + function read_address(StdStorage storage self) internal returns (address) { + return abi.decode(read(self), (address)); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return abi.decode(read(self), (uint256)); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return abi.decode(read(self), (int256)); + } + + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} + +library stdStorage { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return stdStorageSafe.sigs(sigStr); + } + + function find(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.find(self); + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + return stdStorageSafe.target(self, _target); + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, who); + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, amt); + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, key); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function checked_write(StdStorage storage self, address who) internal { + checked_write(self, bytes32(uint256(uint160(who)))); + } + + function checked_write(StdStorage storage self, uint256 amt) internal { + checked_write(self, bytes32(amt)); + } + + function checked_write(StdStorage storage self, bool write) internal { + bytes32 t; + /// @solidity memory-safe-assembly + assembly { + t := write + } + checked_write(self, t); + } + + function checked_write(StdStorage storage self, bytes32 set) internal { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + find(self); + } + bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]); + + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + bytes32 curr = vm.load(who, slot); + + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + vm.store(who, slot, set); + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return stdStorageSafe.read_bytes32(self); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + return stdStorageSafe.read_bool(self); + } + + function read_address(StdStorage storage self) internal returns (address) { + return stdStorageSafe.read_address(self); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.read_uint(self); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return stdStorageSafe.read_int(self); + } + + // Private function so needs to be copied over + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + // Private function so needs to be copied over + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdUtils.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..a283e75 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// TODO Remove import. +import {VmSafe} from "./Vm.sol"; + +abstract contract StdUtils { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; + + uint256 private constant INT256_MIN_ABS = + 57896044618658097711785492504343953926634992332820282019728792003956564819968; + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { + require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); + // If x is between min and max, return x directly. This is to ensure that dictionary values + // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 + if (x >= min && x <= max) return x; + + uint256 size = max - min + 1; + + // If the value is 0, 1, 2, 3, warp that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. + // This helps ensure coverage of the min/max values. + if (x <= 3 && size > x) return min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); + + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. + if (x > max) { + uint256 diff = x - max; + uint256 rem = diff % size; + if (rem == 0) return max; + result = min + rem - 1; + } else if (x < min) { + uint256 diff = min - x; + uint256 rem = diff % size; + if (rem == 0) return min; + result = max - rem + 1; + } + } + + function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log("Bound Result", result); + } + + function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) { + require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min."); + + // Shifting all int256 values to uint256 to use _bound function. The range of two types are: + // int256 : -(2**255) ~ (2**255 - 1) + // uint256: 0 ~ (2**256 - 1) + // So, add 2**255, INT256_MIN_ABS to the integer values. + // + // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow. + // So, use `~uint256(x) + 1` instead. + uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS); + uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS); + uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS); + + uint256 y = _bound(_x, _min, _max); + + // To move it back to int256 value, subtract INT256_MIN_ABS at here. + result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS); + console2_log("Bound result", vm.toString(result)); + } + + /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce + /// @notice adapated from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) + function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { + // forgefmt: disable-start + // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0. + // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it. + if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80)))); + if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce)))); + + // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length. + if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce)))); + if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce)))); + if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce)))); + // forgefmt: disable-end + + // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp + // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) + // We assume nobody can have a nonce large enough to require more than 32 bytes. + return addressFromLast20Bytes( + keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))) + ); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash))); + } + + function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { + require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { + return address(uint160(uint256(bytesValue))); + } + + // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere. + + function console2_log(string memory p0, uint256 p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + status; + } + + function console2_log(string memory p0, string memory p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1)); + status; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Test.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..6c26230 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Test.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Standard Library's default Test + +// 🧩 MODULES +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdAssertions} from "./StdAssertions.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheats} from "./StdCheats.sol"; +import {stdError} from "./StdError.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; +import {DSTest} from "ds-test/test.sol"; + +// ⭐️ TEST +abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdUtils, TestBase { +// Note: IS_TEST() must return true. +// Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76. +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Vm.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..6ebde70 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/Vm.sol @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// Cheatcodes are marked as view/pure/none using the following rules: +// 0. A call's observable behaviour includes its return value, logs, reverts and state writes, +// 1. If you can influence a later call's observable behaviour, you're neither `view` nor `pure (you are modifying some state be it the EVM, interpreter, filesystem, etc), +// 2. Otherwise if you can be influenced by an earlier call, or if reading some state, you're `view`, +// 3. Otherwise you're `pure`. + +interface VmSafe { + struct Log { + bytes32[] topics; + bytes data; + address emitter; + } + + struct Rpc { + string key; + string url; + } + + struct FsMetadata { + bool isDir; + bool isSymlink; + uint256 length; + bool readOnly; + uint256 modified; + uint256 accessed; + uint256 created; + } + + // Loads a storage slot from an address + function load(address target, bytes32 slot) external view returns (bytes32 data); + // Signs data + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + // Gets the address for a given private key + function addr(uint256 privateKey) external pure returns (address addr); + // Gets the nonce of an account + function getNonce(address account) external view returns (uint64 nonce); + // Performs a foreign function call via the terminal + function ffi(string[] calldata commandInput) external returns (bytes memory result); + // Sets environment variables + function setEnv(string calldata name, string calldata value) external; + // Reads environment variables, (name) => (value) + function envBool(string calldata name) external view returns (bool value); + function envUint(string calldata name) external view returns (uint256 value); + function envInt(string calldata name) external view returns (int256 value); + function envAddress(string calldata name) external view returns (address value); + function envBytes32(string calldata name) external view returns (bytes32 value); + function envString(string calldata name) external view returns (string memory value); + function envBytes(string calldata name) external view returns (bytes memory value); + // Reads environment variables as arrays + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + // Read environment variables with default value + function envOr(string calldata name, bool defaultValue) external returns (bool value); + function envOr(string calldata name, uint256 defaultValue) external returns (uint256 value); + function envOr(string calldata name, int256 defaultValue) external returns (int256 value); + function envOr(string calldata name, address defaultValue) external returns (address value); + function envOr(string calldata name, bytes32 defaultValue) external returns (bytes32 value); + function envOr(string calldata name, string calldata defaultValue) external returns (string memory value); + function envOr(string calldata name, bytes calldata defaultValue) external returns (bytes memory value); + // Read environment variables as arrays with default value + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + returns (bool[] memory value); + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + returns (uint256[] memory value); + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + returns (int256[] memory value); + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + returns (address[] memory value); + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + returns (bytes32[] memory value); + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + returns (string[] memory value); + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + returns (bytes[] memory value); + // Records all storage reads and writes + function record() external; + // Gets all accessed reads and write slot from a recording session, for a given address + function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots); + // Gets the _creation_ bytecode from an artifact file. Takes in the relative path to the json file + function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode); + // Gets the _deployed_ bytecode from an artifact file. Takes in the relative path to the json file + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + // Labels an address in call traces + function label(address account, string calldata newLabel) external; + // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain + function broadcast() external; + // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain + function broadcast(address signer) external; + // Has the next call (at this call depth only) create a transaction with the private key provided as the sender that can later be signed and sent onchain + function broadcast(uint256 privateKey) external; + // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain + function startBroadcast() external; + // Has all subsequent calls (at this call depth only) create transactions with the address provided that can later be signed and sent onchain + function startBroadcast(address signer) external; + // Has all subsequent calls (at this call depth only) create transactions with the private key provided that can later be signed and sent onchain + function startBroadcast(uint256 privateKey) external; + // Stops collecting onchain transactions + function stopBroadcast() external; + // Reads the entire content of file to string + function readFile(string calldata path) external view returns (string memory data); + // Reads the entire content of file as binary. Path is relative to the project root. + function readFileBinary(string calldata path) external view returns (bytes memory data); + // Get the path of the current project root + function projectRoot() external view returns (string memory path); + // Get the metadata for a file/directory + function fsMetadata(string calldata fileOrDir) external returns (FsMetadata memory metadata); + // Reads next line of file to string + function readLine(string calldata path) external view returns (string memory line); + // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does. + function writeFile(string calldata path, string calldata data) external; + // Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does. + // Path is relative to the project root. + function writeFileBinary(string calldata path, bytes calldata data) external; + // Writes line to file, creating a file if it does not exist. + function writeLine(string calldata path, string calldata data) external; + // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine. + function closeFile(string calldata path) external; + // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases: + // - Path points to a directory. + // - The file doesn't exist. + // - The user lacks permissions to remove the file. + function removeFile(string calldata path) external; + // Convert values to a string + function toString(address value) external pure returns (string memory stringifiedValue); + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + function toString(bool value) external pure returns (string memory stringifiedValue); + function toString(uint256 value) external pure returns (string memory stringifiedValue); + function toString(int256 value) external pure returns (string memory stringifiedValue); + // Convert values from a string + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + // Record all the transaction logs + function recordLogs() external; + // Gets all the recorded logs + function getRecordedLogs() external returns (Log[] memory logs); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index} + function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at {derivationPath}{index} + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index) + external + pure + returns (uint256 privateKey); + // Adds a private key to the local forge wallet and returns the address + function rememberKey(uint256 privateKey) external returns (address addr); + // + // parseJson + // + // ---- + // In case the returned value is a JSON object, it's encoded as a ABI-encoded tuple. As JSON objects + // don't have the notion of ordered, but tuples do, they JSON object is encoded with it's fields ordered in + // ALPHABETICAL order. That means that in order to successfully decode the tuple, we need to define a tuple that + // encodes the fields in the same order, which is alphabetical. In the case of Solidity structs, they are encoded + // as tuples, with the attributes in the order in which they are defined. + // For example: json = { 'a': 1, 'b': 0xa4tb......3xs} + // a: uint256 + // b: address + // To decode that json, we need to define a struct or a tuple as follows: + // struct json = { uint256 a; address b; } + // If we defined a json struct with the opposite order, meaning placing the address b first, it would try to + // decode the tuple in that order, and thus fail. + // ---- + // Given a string of JSON, return it as ABI-encoded + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + // Serialize a key and value to a JSON object stored in-memory that can be later written to a file + // It returns the stringified version of the specific JSON file up to that moment. + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + // + // writeJson + // + // ---- + // Write a serialized JSON object to a file. If the file exists, it will be overwritten. + // Let's assume we want to write the following JSON to a file: + // + // { "boolean": true, "number": 342, "object": { "title": "finally json serialization" } } + // + // ``` + // string memory json1 = "some key"; + // vm.serializeBool(json1, "boolean", true); + // vm.serializeBool(json1, "number", uint256(342)); + // json2 = "some other key"; + // string memory output = vm.serializeString(json2, "title", "finally json serialization"); + // string memory finalJson = vm.serialize(json1, "object", output); + // vm.writeJson(finalJson, "./output/example.json"); + // ``` + // The critical insight is that every invocation of serialization will return the stringified version of the JSON + // up to that point. That means we can construct arbitrary JSON objects and then use the return stringified version + // to serialize them as values to another JSON object. + // + // json1 and json2 are simply keys used by the backend to keep track of the objects. So vm.serializeJson(json1,..) + // will find the object in-memory that is keyed by "some key". + function writeJson(string calldata json, string calldata path) external; + // Write a serialized JSON object to an **existing** JSON file, replacing a value with key = + // This is useful to replace a specific value of a JSON file, without having to parse the entire thing + function writeJson(string calldata json, string calldata path, string calldata valueKey) external; + // Returns the RPC url for the given alias + function rpcUrl(string calldata rpcAlias) external view returns (string memory json); + // Returns all rpc urls and their aliases `[alias, url][]` + function rpcUrls() external view returns (string[2][] memory urls); + // Returns all rpc urls and their aliases as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + // If the condition is false, discard this run's fuzz inputs and generate new ones. + function assume(bool condition) external pure; + // Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + // Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; +} + +interface Vm is VmSafe { + // Sets block.timestamp + function warp(uint256 newTimestamp) external; + // Sets block.height + function roll(uint256 newHeight) external; + // Sets block.basefee + function fee(uint256 newBasefee) external; + // Sets block.difficulty + function difficulty(uint256 newDifficulty) external; + // Sets block.chainid + function chainId(uint256 newChainId) external; + // Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) external; + // Sets the nonce of an account; must be higher than the current nonce of the account + function setNonce(address account, uint64 newNonce) external; + // Sets the *next* call's msg.sender to be the input address + function prank(address msgSender) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called + function startPrank(address msgSender) external; + // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input + function prank(address msgSender, address txOrigin) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input + function startPrank(address msgSender, address txOrigin) external; + // Resets subsequent calls' msg.sender to be `address(this)` + function stopPrank() external; + // Sets an address' balance + function deal(address account, uint256 newBalance) external; + // Sets an address' code + function etch(address target, bytes calldata newRuntimeBytecode) external; + // Expects an error on next call + function expectRevert(bytes calldata revertData) external; + function expectRevert(bytes4 revertData) external; + function expectRevert() external; + // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + // Call this function, then emit an event, then call a function. Internally after the call, we check if + // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external; + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) + external; + // Mocks a call to an address, returning specified data. + // Calldata can either be strict or a partial match, e.g. if you only + // pass a Solidity selector to the expected calldata, then the entire Solidity + // function will be mocked. + function mockCall(address callee, bytes calldata data, bytes calldata returnData) external; + // Mocks a call to an address with a specific msg.value, returning specified data. + // Calldata match takes precedence over msg.value in case of ambiguity. + function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external; + // Clears all mocked calls + function clearMockedCalls() external; + // Expects a call to an address with the specified calldata. + // Calldata can either be a strict or a partial match + function expectCall(address callee, bytes calldata data) external; + // Expects a call to an address with the specified msg.value and calldata + function expectCall(address callee, uint256 msgValue, bytes calldata data) external; + // Sets block.coinbase + function coinbase(address newCoinbase) external; + // Snapshot the current state of the evm. + // Returns the id of the snapshot that was created. + // To revert a snapshot use `revertTo` + function snapshot() external returns (uint256 snapshotId); + // Revert the state of the EVM to a previous snapshot + // Takes the snapshot id to revert to. + // This deletes the snapshot and all snapshots taken after the given snapshot id. + function revertTo(uint256 snapshotId) external returns (bool success); + // Creates a new fork with the given endpoint and block and returns the identifier of the fork + function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork + function createFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before the transaction, + // and returns the identifier of the fork + function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates _and_ also selects new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before + // the transaction, returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active. + function selectFork(uint256 forkId) external; + /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + // Updates the currently active fork to given block number + // This is similar to `roll` but for the currently active fork + function rollFork(uint256 blockNumber) external; + // Updates the currently active fork to given transaction + // this will `rollFork` with the number of the block the transaction was mined in and replays all transaction mined before it in the block + function rollFork(bytes32 txHash) external; + // Updates the given fork to given block number + function rollFork(uint256 forkId, uint256 blockNumber) external; + // Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block + function rollFork(uint256 forkId, bytes32 txHash) external; + // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup + // Meaning, changes made to the state of this account will be kept when switching forks + function makePersistent(address account) external; + function makePersistent(address account0, address account1) external; + function makePersistent(address account0, address account1, address account2) external; + function makePersistent(address[] calldata accounts) external; + // Revokes persistent status from the address, previously added via `makePersistent` + function revokePersistent(address account) external; + function revokePersistent(address[] calldata accounts) external; + // Returns true if the account is marked as persistent + function isPersistent(address account) external view returns (bool persistent); + // In forking mode, explicitly grant the given address cheatcode access + function allowCheatcodes(address account) external; + // Fetches the given transaction from the active fork and executes it on the current state + function transact(bytes32 txHash) external; + // Fetches the given transaction from the given fork and executes it on the current state + function transact(uint256 forkId, bytes32 txHash) external; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/console.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/console.sol new file mode 100644 index 0000000..ad57e53 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/console.sol @@ -0,0 +1,1533 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/console2.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..8596233 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/console2.sol @@ -0,0 +1,1546 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +/// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should +/// use `int256` and `uint256`. This modified version fixes that. This version is recommended +/// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in +/// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`. +/// Reference: https://github.com/NomicFoundation/hardhat/issues/2178 +library console2 { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function logUint(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function log(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint256 p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); + } + + function log(uint256 p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); + } + + function log(uint256 p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); + } + + function log(uint256 p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); + } + + function log(string memory p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function log(string memory p0, int256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint256 p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC1155.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..f7dd2b4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC1155.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-1155 Multi Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-1155 +/// Note: The ERC-165 identifier for this interface is 0xd9b67a26. +interface IERC1155 is IERC165 { + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_id` argument MUST be the token type being transferred. + /// - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferSingle( + address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value + ); + + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_ids` argument MUST be the list of tokens being transferred. + /// - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferBatch( + address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values + ); + + /// @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled). + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. + /// The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". + event URI(string _value, uint256 indexed _id); + + /// @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + /// - MUST revert on any other error. + /// - MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + /// - After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _id ID of the token type + /// @param _value Transfer amount + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; + + /// @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if length of `_ids` is not the same as length of `_values`. + /// - MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + /// - MUST revert on any other error. + /// - MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + /// - Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + /// - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _ids IDs of each token type (order and length must match _values array) + /// @param _values Transfer amounts per token type (order and length must match _ids array) + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + function safeBatchTransferFrom( + address _from, + address _to, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data + ) external; + + /// @notice Get the balance of an account's tokens. + /// @param _owner The address of the token holder + /// @param _id ID of the token + /// @return The _owner's balance of the token type requested + function balanceOf(address _owner, uint256 _id) external view returns (uint256); + + /// @notice Get the balance of multiple account/token pairs + /// @param _owners The addresses of the token holders + /// @param _ids ID of the tokens + /// @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair) + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) + external + view + returns (uint256[] memory); + + /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + /// @dev MUST emit the ApprovalForAll event on success. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Queries the approval status of an operator for a given owner. + /// @param _owner The owner of the tokens + /// @param _operator Address of authorized operator + /// @return True if the operator is approved, false if not + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC165.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC165.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +interface IERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC20.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC20.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +/// @dev Interface of the ERC20 standard as defined in the EIP. +/// @dev This includes the optional name, symbol, and decimals metadata. +interface IERC20 { + /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` + /// is the new allowance. + event Approval(address indexed owner, address indexed spender, uint256 value); + + /// @notice Returns the amount of tokens in existence. + function totalSupply() external view returns (uint256); + + /// @notice Returns the amount of tokens owned by `account`. + function balanceOf(address account) external view returns (uint256); + + /// @notice Moves `amount` tokens from the caller's account to `to`. + function transfer(address to, uint256 amount) external returns (bool); + + /// @notice Returns the remaining number of tokens that `spender` is allowed + /// to spend on behalf of `owner` + function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. + /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. + /// `amount` is then deducted from the caller's allowance. + function transferFrom(address from, address to, uint256 amount) external returns (bool); + + /// @notice Returns the name of the token. + function name() external view returns (string memory); + + /// @notice Returns the symbol of the token. + function symbol() external view returns (string memory); + + /// @notice Returns the decimals places of the token. + function decimals() external view returns (uint8); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC4626.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..bfe3a11 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC4626.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC20.sol"; + +/// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in +/// https://eips.ethereum.org/EIPS/eip-4626 +interface IERC4626 is IERC20 { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares + ); + + /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + /// @dev + /// - MUST be an ERC-20 token contract. + /// - MUST NOT revert. + function asset() external view returns (address assetTokenAddress); + + /// @notice Returns the total amount of the underlying asset that is “managed” by Vault. + /// @dev + /// - SHOULD include any compounding that occurs from yield. + /// - MUST be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT revert. + function totalAssets() external view returns (uint256 totalManagedAssets); + + /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + /// through a deposit call. + /// @dev + /// - MUST return a limited value if receiver is subject to some deposit limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + /// - MUST NOT revert. + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + /// call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + /// in the same transaction. + /// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + /// deposit would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// deposit execution, and are accounted for during deposit. + /// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + /// @dev + /// - MUST return a limited value if receiver is subject to some mint limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + /// - MUST NOT revert. + function maxMint(address receiver) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + /// in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + /// same transaction. + /// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + /// would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by minting. + function previewMint(uint256 shares) external view returns (uint256 assets); + + /// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + /// execution, and are accounted for during mint. + /// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + /// Vault, through a withdraw call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST NOT revert. + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + /// call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + /// called + /// in the same transaction. + /// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + /// the withdrawal would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// withdraw execution, and are accounted for during withdraw. + /// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + /// through a redeem call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + /// - MUST NOT revert. + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + /// in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + /// same transaction. + /// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + /// redemption would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by redeeming. + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// redeem execution, and are accounted for during redeem. + /// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC721.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..0a16f45 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/src/interfaces/IERC721.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-721 Non-Fungible Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. +interface IERC721 is IERC165 { + /// @dev This emits when ownership of any NFT changes by any mechanism. + /// This event emits when NFTs are created (`from` == 0) and destroyed + /// (`to` == 0). Exception: during contract creation, any number of NFTs + /// may be created and assigned without emitting Transfer. At the time of + /// any transfer, the approved address for that NFT (if any) is reset to none. + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + + /// @dev This emits when the approved address for an NFT is changed or + /// reaffirmed. The zero address indicates there is no approved address. + /// When a Transfer event emits, this also indicates that the approved + /// address for that NFT (if any) is reset to none. + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + /// @dev This emits when an operator is enabled or disabled for an owner. + /// The operator can manage all NFTs of the owner. + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @notice Count all NFTs assigned to an owner + /// @dev NFTs assigned to the zero address are considered invalid, and this + /// function throws for queries about the zero address. + /// @param _owner An address for whom to query the balance + /// @return The number of NFTs owned by `_owner`, possibly zero + function balanceOf(address _owner) external view returns (uint256); + + /// @notice Find the owner of an NFT + /// @dev NFTs assigned to zero address are considered invalid, and queries + /// about them do throw. + /// @param _tokenId The identifier for an NFT + /// @return The address of the owner of the NFT + function ownerOf(uint256 _tokenId) external view returns (address); + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. When transfer is complete, this function + /// checks if `_to` is a smart contract (code size > 0). If so, it calls + /// `onERC721Received` on `_to` and throws if the return value is not + /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + /// @param data Additional data with no specified format, sent in call to `_to` + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev This works identically to the other function with an extra data parameter, + /// except this function just sets data to "". + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE + /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE + /// THEY MAY BE PERMANENTLY LOST + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Change or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param _approved The new approved NFT controller + /// @param _tokenId The NFT to approve + function approve(address _approved, uint256 _tokenId) external payable; + + /// @notice Enable or disable approval for a third party ("operator") to manage + /// all of `msg.sender`'s assets + /// @dev Emits the ApprovalForAll event. The contract MUST allow + /// multiple operators per owner. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Get the approved address for a single NFT + /// @dev Throws if `_tokenId` is not a valid NFT. + /// @param _tokenId The NFT to find the approved address for + /// @return The approved address for this NFT, or the zero address if there is none + function getApproved(uint256 _tokenId) external view returns (address); + + /// @notice Query if an address is an authorized operator for another address + /// @param _owner The address that owns the NFTs + /// @param _operator The address that acts on behalf of the owner + /// @return True if `_operator` is an approved operator for `_owner`, false otherwise + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} + +/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02. +interface IERC721TokenReceiver { + /// @notice Handle the receipt of an NFT + /// @dev The ERC721 smart contract calls this function on the recipient + /// after a `transfer`. This function MAY throw to revert and reject the + /// transfer. Return of other than the magic value MUST result in the + /// transaction being reverted. + /// Note: the contract address is always the message sender. + /// @param _operator The address which called `safeTransferFrom` function + /// @param _from The address which previously owned the token + /// @param _tokenId The NFT identifier which is being transferred + /// @param _data Additional data with no specified format + /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + /// unless throwing + function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) + external + returns (bytes4); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x5b5e139f. +interface IERC721Metadata is IERC721 { + /// @notice A descriptive name for a collection of NFTs in this contract + function name() external view returns (string memory _name); + + /// @notice An abbreviated name for NFTs in this contract + function symbol() external view returns (string memory _symbol); + + /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. + /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC + /// 3986. The URI may point to a JSON file that conforms to the "ERC721 + /// Metadata JSON Schema". + function tokenURI(uint256 _tokenId) external view returns (string memory); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x780e9d63. +interface IERC721Enumerable is IERC721 { + /// @notice Count NFTs tracked by this contract + /// @return A count of valid NFTs tracked by this contract, where each one of + /// them has an assigned and queryable owner not equal to the zero address + function totalSupply() external view returns (uint256); + + /// @notice Enumerate valid NFTs + /// @dev Throws if `_index` >= `totalSupply()`. + /// @param _index A counter less than `totalSupply()` + /// @return The token identifier for the `_index`th NFT, + /// (sort order not specified) + function tokenByIndex(uint256 _index) external view returns (uint256); + + /// @notice Enumerate NFTs assigned to an owner + /// @dev Throws if `_index` >= `balanceOf(_owner)` or if + /// `_owner` is the zero address, representing invalid NFTs. + /// @param _owner An address where we are interested in NFTs owned by them + /// @param _index A counter less than `balanceOf(_owner)` + /// @return The token identifier for the `_index`th NFT assigned to `_owner`, + /// (sort order not specified) + function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdAssertions.t.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..4d5827d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdAssertionsTest is Test { + string constant CUSTOM_ERROR = "guh!"; + + bool constant EXPECT_PASS = false; + bool constant EXPECT_FAIL = true; + + TestTest t = new TestTest(); + + /*////////////////////////////////////////////////////////////////////////// + FAIL(STRING) + //////////////////////////////////////////////////////////////////////////*/ + + function testShouldFail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._fail(CUSTOM_ERROR); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_FALSE + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertFalse_Pass() external { + t._assertFalse(false, EXPECT_PASS); + } + + function testAssertFalse_Fail() external { + vm.expectEmit(false, false, false, true); + emit log("Error: Assertion Failed"); + t._assertFalse(true, EXPECT_FAIL); + } + + function testAssertFalse_Err_Pass() external { + t._assertFalse(false, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertFalse_Err_Fail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertFalse(true, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BOOL) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bool_Pass(bool a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bool_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bool]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BoolErr_Pass(bool a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BoolErr_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BYTES) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bytes_Pass(bytes calldata a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bytes_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bytes]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BytesErr_Pass(bytes calldata a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BytesErr_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(ARRAY) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_UintArr_Pass(uint256 e0, uint256 e1, uint256 e2) public { + uint256[] memory a = new uint256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + uint256[] memory b = new uint256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_IntArr_Pass(int256 e0, int256 e1, int256 e2) public { + int256[] memory a = new int256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + int256[] memory b = new int256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_AddressArr_Pass(address e0, address e1, address e2) public { + address[] memory a = new address[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + address[] memory b = new address[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_UintArr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_UintArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEqUint() public { + assertEqUint(uint8(1), uint128(1)); + assertEqUint(uint64(2), uint64(2)); + } + + function testFailAssertEqUint() public { + assertEqUint(uint64(1), uint96(2)); + assertEqUint(uint160(3), uint160(4)); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Int_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Int_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_IntErr_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_IntErr_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } +} + +contract TestTest is Test { + modifier expectFailure(bool expectFail) { + bool preState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + _; + bool postState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + + if (preState == true) { + return; + } + + if (expectFail) { + require(postState == true, "expected failure not triggered"); + + // unwind the expected failure + vm.store(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x00))); + } else { + require(postState == false, "unexpected failure was triggered"); + } + } + + function _fail(string memory err) external expectFailure(true) { + fail(err); + } + + function _assertFalse(bool data, bool expectFail) external expectFailure(expectFail) { + assertFalse(data); + } + + function _assertFalse(bool data, string memory err, bool expectFail) external expectFailure(expectFail) { + assertFalse(data, err); + } + + function _assertEq(bool a, bool b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bool a, bool b, string memory err, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b, err); + } + + function _assertEq(bytes memory a, bytes memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bytes memory a, bytes memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(int256[] memory a, int256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(address[] memory a, address[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(int256[] memory a, int256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(address[] memory a, address[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdChains.t.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..3657510 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdChainsTest is Test { + function testChainRpcInitialization() public { + // RPCs specified in `foundry.toml` should be updated. + assertEq(getChain(1).rpcUrl, "https://mainnet.infura.io/v3/7a8769b798b642f6933f2ed52042bd70"); + assertEq(getChain("optimism_goerli").rpcUrl, "https://goerli.optimism.io/"); + assertEq(getChain("arbitrum_one_goerli").rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/"); + + // Other RPCs should remain unchanged. + assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545"); + assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/6770454bc6ea42c58aac12978531b93f"); + } + + function testRpc(string memory rpcAlias) internal { + string memory rpcUrl = getChain(rpcAlias).rpcUrl; + vm.createSelectFork(rpcUrl); + } + + // Ensure we can connect to the default RPC URL for each chain. + function testRpcs() public { + testRpc("mainnet"); + testRpc("goerli"); + testRpc("sepolia"); + testRpc("optimism"); + testRpc("optimism_goerli"); + testRpc("arbitrum_one"); + testRpc("arbitrum_one_goerli"); + testRpc("arbitrum_nova"); + testRpc("polygon"); + testRpc("polygon_mumbai"); + testRpc("avalanche"); + testRpc("avalanche_fuji"); + testRpc("bnb_smart_chain"); + testRpc("bnb_smart_chain_testnet"); + testRpc("gnosis_chain"); + } + + function testChainNoDefault() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found."); + getChain("does_not_exist"); + } + + function testSetChainFirstFails() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain ID 31337 already used by \"anvil\"."); + setChain("anvil2", Chain("Anvil", 31337, "URL")); + } + + function testChainBubbleUp() public { + setChain("needs_undefined_env_var", Chain("", 123456789, "")); + vm.expectRevert( + "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found" + ); + getChain("needs_undefined_env_var"); + } + + function testCannotSetChain_ChainIdExists() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + + vm.expectRevert('StdChains setChain(string,Chain): Chain ID 123456789 already used by "custom_chain".'); + + setChain("another_custom_chain", Chain("", 123456789, "")); + } + + function testSetChain() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + Chain memory customChain = getChain("custom_chain"); + assertEq(customChain.name, "Custom Chain"); + assertEq(customChain.chainId, 123456789); + assertEq(customChain.rpcUrl, "https://custom.chain/"); + Chain memory chainById = getChain(123456789); + assertEq(chainById.name, customChain.name); + assertEq(chainById.chainId, customChain.chainId); + assertEq(chainById.rpcUrl, customChain.rpcUrl); + } + + function testSetNoEmptyAlias() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain alias cannot be the empty string."); + setChain("", Chain("", 123456789, "")); + } + + function testSetNoChainId0() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain ID cannot be 0."); + setChain("alias", Chain("", 0, "")); + } + + function testGetNoChainId0() public { + vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0."); + getChain(0); + } + + function testGetNoEmptyAlias() public { + vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string."); + getChain(""); + } + + function testChainIdNotFound() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found."); + getChain("no_such_alias"); + } + + function testChainAliasNotFound() public { + vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found."); + getChain(321); + } + + function testSetChain_ExistingOne() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + assertEq(getChain(123456789).chainId, 123456789); + + setChain("custom_chain", Chain("Modified Chain", 999999999, "https://modified.chain/")); + vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); + getChain(123456789); + + Chain memory modifiedChain = getChain(999999999); + assertEq(modifiedChain.name, "Modified Chain"); + assertEq(modifiedChain.chainId, 999999999); + assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdCheats.t.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..2eab3c3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdCheats.sol"; +import "../src/Test.sol"; +import "../src/StdJson.sol"; + +contract StdCheatsTest is Test { + Bar test; + + using stdJson for string; + + function setUp() public { + test = new Bar(); + } + + function testSkip() public { + vm.warp(100); + skip(25); + assertEq(block.timestamp, 125); + } + + function testRewind() public { + vm.warp(100); + rewind(25); + assertEq(block.timestamp, 75); + } + + function testHoax() public { + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + } + + function testHoaxOrigin() public { + hoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + } + + function testHoaxDifferentAddresses() public { + hoax(address(1337), address(7331)); + test.origin{value: 100}(address(1337), address(7331)); + } + + function testStartHoax() public { + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testStartHoaxOrigin() public { + startHoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + test.origin{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testChangePrank() public { + vm.startPrank(address(1337)); + test.bar(address(1337)); + changePrank(address(0xdead)); + test.bar(address(0xdead)); + changePrank(address(1337)); + test.bar(address(1337)); + vm.stopPrank(); + } + + function testMakeAddrEquivalence() public { + (address addr,) = makeAddrAndKey("1337"); + assertEq(makeAddr("1337"), addr); + } + + function testMakeAddrSigning() public { + (address addr, uint256 key) = makeAddrAndKey("1337"); + bytes32 hash = keccak256("some_message"); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash); + assertEq(ecrecover(hash, v, r, s), addr); + } + + function testDeal() public { + deal(address(this), 1 ether); + assertEq(address(this).balance, 1 ether); + } + + function testDealToken() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18); + assertEq(barToken.balanceOf(address(this)), 10000e18); + } + + function testDealTokenAdjustTS() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18, true); + assertEq(barToken.balanceOf(address(this)), 10000e18); + assertEq(barToken.totalSupply(), 20000e18); + deal(bar, address(this), 0, true); + assertEq(barToken.balanceOf(address(this)), 0); + assertEq(barToken.totalSupply(), 10000e18); + } + + function testDeployCode() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes("")); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar"); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeVal() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes(""), 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + function testDeployCodeValNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar", 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + // We need this so we can call "this.deployCode" rather than "deployCode" directly + function deployCodeHelper(string memory what) external { + deployCode(what); + } + + function testDeployCodeFail() public { + vm.expectRevert(bytes("StdCheats deployCode(string): Deployment failed.")); + this.deployCodeHelper("StdCheats.t.sol:RevertingContract"); + } + + function getCode(address who) internal view returns (bytes memory o_code) { + /// @solidity memory-safe-assembly + assembly { + // retrieve the size of the code, this needs assembly + let size := extcodesize(who) + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + o_code := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(o_code, size) + // actually retrieve the code, this needs assembly + extcodecopy(who, add(o_code, 0x20), 0, size) + } + } + + function testDeriveRememberKey() public { + string memory mnemonic = "test test test test test test test test test test test junk"; + + (address deployer, uint256 privateKey) = deriveRememberKey(mnemonic, 0); + assertEq(deployer, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); + } + + function testBytesToUint() public { + assertEq(3, bytesToUint_test(hex"03")); + assertEq(2, bytesToUint_test(hex"02")); + assertEq(255, bytesToUint_test(hex"ff")); + assertEq(29625, bytesToUint_test(hex"73b9")); + } + + function testParseJsonTxDetail() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + string memory json = vm.readFile(path); + bytes memory transactionDetails = json.parseRaw(".transactions[0].tx"); + RawTx1559Detail memory rawTxDetail = abi.decode(transactionDetails, (RawTx1559Detail)); + Tx1559Detail memory txDetail = rawToConvertedEIP1559Detail(rawTxDetail); + assertEq(txDetail.from, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(txDetail.to, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512); + assertEq( + txDetail.data, + hex"23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004" + ); + assertEq(txDetail.nonce, 3); + assertEq(txDetail.txType, 2); + assertEq(txDetail.gas, 29625); + assertEq(txDetail.value, 0); + } + + function testReadEIP1559Transaction() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 0; + Tx1559 memory transaction = readTx1559(path, index); + transaction; + } + + function testReadEIP1559Transactions() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Tx1559[] memory transactions = readTx1559s(path); + transactions; + } + + function testReadReceipt() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 5; + Receipt memory receipt = readReceipt(path, index); + assertEq( + receipt.logsBloom, + hex"00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100" + ); + } + + function testReadReceipts() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Receipt[] memory receipts = readReceipts(path); + receipts; + } + + function testGasMeteringModifier() public { + uint256 gas_start_normal = gasleft(); + addInLoop(); + uint256 gas_used_normal = gas_start_normal - gasleft(); + + uint256 gas_start_single = gasleft(); + addInLoopNoGas(); + uint256 gas_used_single = gas_start_single - gasleft(); + + uint256 gas_start_double = gasleft(); + addInLoopNoGasNoGas(); + uint256 gas_used_double = gas_start_double - gasleft(); + + emit log_named_uint("Normal gas", gas_used_normal); + emit log_named_uint("Single modifier gas", gas_used_single); + emit log_named_uint("Double modifier gas", gas_used_double); + assertTrue(gas_used_double + gas_used_single < gas_used_normal); + } + + function addInLoop() internal pure returns (uint256) { + uint256 b; + for (uint256 i; i < 10000; i++) { + b += i; + } + return b; + } + + function addInLoopNoGas() internal noGasMetering returns (uint256) { + return addInLoop(); + } + + function addInLoopNoGasNoGas() internal noGasMetering returns (uint256) { + return addInLoopNoGas(); + } + + function bytesToUint_test(bytes memory b) private pure returns (uint256) { + uint256 number; + for (uint256 i = 0; i < b.length; i++) { + number = number + uint256(uint8(b[i])) * (2 ** (8 * (b.length - (i + 1)))); + } + return number; + } + + function testAssumeNoPrecompiles(address addr) external { + assumeNoPrecompiles(addr, getChain("optimism_goerli").chainId); + assertTrue( + addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) + || addr > address(0x4200000000000000000000000000000000000800) + ); + } +} + +contract Bar { + constructor() payable { + /// `DEAL` STDCHEAT + totalSupply = 10000e18; + balanceOf[address(this)] = totalSupply; + } + + /// `HOAX` STDCHEATS + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } + + function origin(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedSender, "!prank"); + } + + function origin(address expectedSender, address expectedOrigin) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedOrigin, "!prank"); + } + + /// `DEAL` STDCHEAT + mapping(address => uint256) public balanceOf; + uint256 public totalSupply; +} + +contract RevertingContract { + constructor() { + revert(); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdError.t.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..ccd3efa --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdError.sol"; +import "../src/Test.sol"; + +contract StdErrorsTest is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectAssertion() public { + vm.expectRevert(stdError.assertionError); + test.assertionError(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } + + function testExpectDiv() public { + vm.expectRevert(stdError.divisionError); + test.divError(0); + } + + function testExpectMod() public { + vm.expectRevert(stdError.divisionError); + test.modError(0); + } + + function testExpectEnum() public { + vm.expectRevert(stdError.enumConversionError); + test.enumConversion(1); + } + + function testExpectEncodeStg() public { + vm.expectRevert(stdError.encodeStorageError); + test.encodeStgError(); + } + + function testExpectPop() public { + vm.expectRevert(stdError.popError); + test.pop(); + } + + function testExpectOOB() public { + vm.expectRevert(stdError.indexOOBError); + test.indexOOBError(1); + } + + function testExpectMem() public { + vm.expectRevert(stdError.memOverflowError); + test.mem(); + } + + function testExpectIntern() public { + vm.expectRevert(stdError.zeroVarError); + test.intern(); + } +} + +contract ErrorsTest { + enum T {T1} + + uint256[] public someArr; + bytes someBytes; + + function assertionError() public pure { + assert(false); + } + + function arithmeticError(uint256 a) public pure { + a -= 100; + } + + function divError(uint256 a) public pure { + 100 / a; + } + + function modError(uint256 a) public pure { + 100 % a; + } + + function enumConversion(uint256 a) public pure { + T(a); + } + + function encodeStgError() public { + /// @solidity memory-safe-assembly + assembly { + sstore(someBytes.slot, 1) + } + keccak256(someBytes); + } + + function pop() public { + someArr.pop(); + } + + function indexOOBError(uint256 a) public pure { + uint256[] memory t = new uint256[](0); + t[a]; + } + + function mem() public pure { + uint256 l = 2 ** 256 / 32; + new uint256[](l); + } + + function intern() public returns (uint256) { + function(uint256) internal returns (uint256) x; + x(2); + return 7; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdMath.t.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..95037ea --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdMath.t.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdMath.sol"; +import "../src/Test.sol"; + +contract StdMathTest is Test { + function testGetAbs() external { + assertEq(stdMath.abs(-50), 50); + assertEq(stdMath.abs(50), 50); + assertEq(stdMath.abs(-1337), 1337); + assertEq(stdMath.abs(0), 0); + + assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1); + assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1)); + } + + function testGetAbs_Fuzz(int256 a) external { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function testGetDelta_Uint() external { + assertEq(stdMath.delta(uint256(0), uint256(0)), 0); + assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337); + assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max); + assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max); + assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max); + + assertEq(stdMath.delta(0, uint256(0)), 0); + assertEq(stdMath.delta(1337, uint256(0)), 1337); + assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max); + assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max); + assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max); + + assertEq(stdMath.delta(1337, uint256(1337)), 0); + assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0); + assertEq(stdMath.delta(5000, uint256(1250)), 3750); + } + + function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external { + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetDelta_Int() external { + assertEq(stdMath.delta(int256(0), int256(0)), 0); + assertEq(stdMath.delta(int256(0), int256(1337)), 1337); + assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1); + assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1); + assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1); + + assertEq(stdMath.delta(0, int256(0)), 0); + assertEq(stdMath.delta(1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1); + assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1); + assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1); + + assertEq(stdMath.delta(-0, int256(0)), 0); + assertEq(stdMath.delta(-1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(int256(0), -0), 0); + assertEq(stdMath.delta(int256(0), -1337), 1337); + assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(1337, int256(1337)), 0); + assertEq(stdMath.delta(type(int256).max, type(int256).max), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).min), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max); + assertEq(stdMath.delta(5000, int256(1250)), 3750); + } + + function testGetDelta_Int_Fuzz(int256 a, int256 b) external { + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetPercentDelta_Uint() external { + assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); + assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); + assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); + assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(uint256(1), 0); + } + + function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external { + vm.assume(b != 0); + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / b; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + function testGetPercentDelta_Int() external { + assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); + assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, int256(1337)), 0); + assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); + assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); + + assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, int256(2500)), 0); + assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(int256(1), 0); + } + + function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external { + vm.assume(b != 0); + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / absB; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function getAbs(int256 a) private pure returns (uint256) { + if (a < 0) { + return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); + } + + return uint256(a); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdStorage.t.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..d4c563a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdStorage.sol"; +import "../src/Test.sol"; + +contract StdStorageTest is Test { + using stdStorage for StdStorage; + + StorageTest internal test; + + function setUp() public { + test = new StorageTest(); + } + + function testStorageHidden() public { + assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find()); + } + + function testStorageObvious() public { + assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find()); + } + + function testStorageCheckedWriteHidden() public { + stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100); + assertEq(uint256(test.hidden()), 100); + } + + function testStorageCheckedWriteObvious() public { + stdstore.target(address(test)).sig(test.exists.selector).checked_write(100); + assertEq(test.exists(), 100); + } + + function testStorageMapStructA() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot); + } + + function testStorageMapStructB() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot); + } + + function testStorageDeepMap() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key( + address(this) + ).find(); + assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(5)))))), slot); + } + + function testStorageCheckedWriteDeepMap() public { + stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(address(this)) + .checked_write(100); + assertEq(100, test.deep_map(address(this), address(this))); + } + + function testStorageDeepMapStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(0).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 0), + bytes32(slot) + ); + } + + function testStorageDeepMapStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(1).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 1), + bytes32(slot) + ); + } + + function testStorageCheckedWriteDeepMapStructA() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(100, a); + assertEq(0, b); + } + + function testStorageCheckedWriteDeepMapStructB() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(0, a); + assertEq(100, b); + } + + function testStorageCheckedWriteMapStructA() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 100); + assertEq(b, 0); + } + + function testStorageCheckedWriteMapStructB() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 0); + assertEq(b, 100); + } + + function testStorageStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find(); + assertEq(uint256(7), slot); + } + + function testStorageStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find(); + assertEq(uint256(7) + 1, slot); + } + + function testStorageCheckedWriteStructA() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 100); + assertEq(b, 1337); + } + + function testStorageCheckedWriteStructB() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 1337); + assertEq(b, 100); + } + + function testStorageMapAddrFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find(); + assertEq(uint256(keccak256(abi.encode(address(this), uint256(1)))), slot); + } + + function testStorageMapUintFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find(); + assertEq(uint256(keccak256(abi.encode(100, uint256(2)))), slot); + } + + function testStorageCheckedWriteMapUint() public { + stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100); + assertEq(100, test.map_uint(100)); + } + + function testStorageCheckedWriteMapAddr() public { + stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100); + assertEq(100, test.map_addr(address(this))); + } + + function testStorageCheckedWriteMapBool() public { + stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true); + assertTrue(test.map_bool(address(this))); + } + + function testFailStorageCheckedWriteMapPacked() public { + // expect PackedSlot error but not external call so cant expectRevert + stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))) + .checked_write(100); + } + + function testStorageCheckedWriteMapPackedSuccess() public { + uint256 full = test.map_packed(address(1337)); + // keep upper 128, set lower 128 to 1337 + full = (full & (uint256((1 << 128) - 1) << 128)) | 1337; + stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write( + full + ); + assertEq(1337, test.read_struct_lower(address(1337))); + } + + function testFailStorageConst() public { + // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()")))); + stdstore.target(address(test)).sig("const()").find(); + } + + function testFailStorageNativePack() public { + stdstore.target(address(test)).sig(test.tA.selector).find(); + stdstore.target(address(test)).sig(test.tB.selector).find(); + + // these both would fail + stdstore.target(address(test)).sig(test.tC.selector).find(); + stdstore.target(address(test)).sig(test.tD.selector).find(); + } + + function testStorageReadBytes32() public { + bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32(); + assertEq(val, hex"1337"); + } + + function testStorageReadBool_False() public { + bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool(); + assertEq(val, false); + } + + function testStorageReadBool_True() public { + bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool(); + assertEq(val, true); + } + + function testStorageReadBool_Revert() public { + vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + this.readNonBoolValue(); + } + + function readNonBoolValue() public { + stdstore.target(address(test)).sig(test.tE.selector).read_bool(); + } + + function testStorageReadAddress() public { + address val = stdstore.target(address(test)).sig(test.tF.selector).read_address(); + assertEq(val, address(1337)); + } + + function testStorageReadUint() public { + uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint(); + assertEq(val, 1); + } + + function testStorageReadInt() public { + int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int(); + assertEq(val, type(int256).min); + } +} + +contract StorageTest { + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + mapping(uint256 => uint256) public map_uint; + mapping(address => uint256) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basic; + + uint248 public tA; + bool public tB; + + bool public tC = false; + uint248 public tD = 1; + + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + mapping(address => bool) public map_bool; + + bytes32 public tE = hex"1337"; + address public tF = address(1337); + int256 public tG = type(int256).min; + bool public tH = true; + + constructor() { + basic = UnpackedStruct({a: 1337, b: 1337}); + + uint256 two = (1 << 128) | 1; + map_packed[msg.sender] = two; + map_packed[address(uint160(1337))] = 1 << 128; + } + + function read_struct_upper(address who) public view returns (uint256) { + return map_packed[who] >> 128; + } + + function read_struct_lower(address who) public view returns (uint256) { + return map_packed[who] & ((1 << 128) - 1); + } + + function hidden() public view returns (bytes32 t) { + bytes32 slot = keccak256("my.random.var"); + /// @solidity memory-safe-assembly + assembly { + t := sload(slot) + } + } + + function const() public pure returns (bytes32 t) { + t = bytes32(hex"1337"); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdUtils.t.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..f53a71b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/StdUtils.t.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdUtilsTest is Test { + function testBound() public { + assertEq(bound(uint256(5), 0, 4), 0); + assertEq(bound(uint256(0), 69, 69), 69); + assertEq(bound(uint256(0), 68, 69), 68); + assertEq(bound(uint256(10), 150, 190), 174); + assertEq(bound(uint256(300), 2800, 3200), 3107); + assertEq(bound(uint256(9999), 1337, 6666), 4669); + } + + function testBound_WithinRange() public { + assertEq(bound(uint256(51), 50, 150), 51); + assertEq(bound(uint256(51), 50, 150), bound(bound(uint256(51), 50, 150), 50, 150)); + assertEq(bound(uint256(149), 50, 150), 149); + assertEq(bound(uint256(149), 50, 150), bound(bound(uint256(149), 50, 150), 50, 150)); + } + + function testBound_EdgeCoverage() public { + assertEq(bound(uint256(0), 50, 150), 50); + assertEq(bound(uint256(1), 50, 150), 51); + assertEq(bound(uint256(2), 50, 150), 52); + assertEq(bound(uint256(3), 50, 150), 53); + assertEq(bound(type(uint256).max, 50, 150), 150); + assertEq(bound(type(uint256).max - 1, 50, 150), 149); + assertEq(bound(type(uint256).max - 2, 50, 150), 148); + assertEq(bound(type(uint256).max - 3, 50, 150), 147); + } + + function testBound_DistributionIsEven(uint256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, UINT256_MAX / 2, UINT256_MAX / 2 + size); + uint256 max = min + size - 1; + uint256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + i, min, max); + assertEq(result, min + (i - 1) % size); + // x < min + result = bound(min - i, min, max); + assertEq(result, max - (i - 1) % size); + } + } + + function testBound(uint256 num, uint256 min, uint256 max) public { + if (min > max) (min, max) = (max, min); + + uint256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundUint256Max() public { + assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1); + assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max); + } + + function testCannotBoundMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(uint256(5), 100, 10); + } + + function testCannotBoundMaxLessThanMin(uint256 num, uint256 min, uint256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(num, min, max); + } + + function testBoundInt() public { + assertEq(bound(-3, 0, 4), 2); + assertEq(bound(0, -69, -69), -69); + assertEq(bound(0, -69, -68), -68); + assertEq(bound(-10, 150, 190), 154); + assertEq(bound(-300, 2800, 3200), 2908); + assertEq(bound(9999, -1337, 6666), 1995); + } + + function testBoundInt_WithinRange() public { + assertEq(bound(51, -50, 150), 51); + assertEq(bound(51, -50, 150), bound(bound(51, -50, 150), -50, 150)); + assertEq(bound(149, -50, 150), 149); + assertEq(bound(149, -50, 150), bound(bound(149, -50, 150), -50, 150)); + } + + function testBoundInt_EdgeCoverage() public { + assertEq(bound(type(int256).min, -50, 150), -50); + assertEq(bound(type(int256).min + 1, -50, 150), -49); + assertEq(bound(type(int256).min + 2, -50, 150), -48); + assertEq(bound(type(int256).min + 3, -50, 150), -47); + assertEq(bound(type(int256).min, 10, 150), 10); + assertEq(bound(type(int256).min + 1, 10, 150), 11); + assertEq(bound(type(int256).min + 2, 10, 150), 12); + assertEq(bound(type(int256).min + 3, 10, 150), 13); + + assertEq(bound(type(int256).max, -50, 150), 150); + assertEq(bound(type(int256).max - 1, -50, 150), 149); + assertEq(bound(type(int256).max - 2, -50, 150), 148); + assertEq(bound(type(int256).max - 3, -50, 150), 147); + assertEq(bound(type(int256).max, -50, -10), -10); + assertEq(bound(type(int256).max - 1, -50, -10), -11); + assertEq(bound(type(int256).max - 2, -50, -10), -12); + assertEq(bound(type(int256).max - 3, -50, -10), -13); + } + + function testBoundInt_DistributionIsEven(int256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, -int256(size / 2), int256(size - size / 2)); + int256 max = min + int256(size) - 1; + int256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + int256(i), min, max); + assertEq(result, min + int256((i - 1) % size)); + // x < min + result = bound(min - int256(i), min, max); + assertEq(result, max - int256((i - 1) % size)); + } + } + + function testBoundInt(int256 num, int256 min, int256 max) public { + if (min > max) (min, max) = (max, min); + + int256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundIntInt256Max() public { + assertEq(bound(0, type(int256).max - 1, type(int256).max), type(int256).max - 1); + assertEq(bound(1, type(int256).max - 1, type(int256).max), type(int256).max); + } + + function testBoundIntInt256Min() public { + assertEq(bound(0, type(int256).min, type(int256).min + 1), type(int256).min); + assertEq(bound(1, type(int256).min, type(int256).min + 1), type(int256).min + 1); + } + + function testCannotBoundIntMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(-5, 100, 10); + } + + function testCannotBoundIntMaxLessThanMin(int256 num, int256 min, int256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(num, min, max); + } + + function testGenerateCreateAddress() external { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + function testGenerateCreate2Address() external { + bytes32 salt = bytes32(uint256(31415)); + bytes32 initcodeHash = keccak256(abi.encode(0x6080)); + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + address create2Address = computeCreate2Address(salt, initcodeHash, deployer); + assertEq(create2Address, 0xB147a5d25748fda14b463EB04B111027C290f4d3); + } + + function testBytesToUint() external { + bytes memory maxUint = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + bytes memory two = hex"02"; + bytes memory millionEther = hex"d3c21bcecceda1000000"; + + assertEq(bytesToUint(maxUint), type(uint256).max); + assertEq(bytesToUint(two), 2); + assertEq(bytesToUint(millionEther), 1_000_000 ether); + } + + function testCannotConvertGT32Bytes() external { + bytes memory thirty3Bytes = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + vm.expectRevert("StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + bytesToUint(thirty3Bytes); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationScript.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..e205cff --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationScript.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScript is Script {} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationScriptBase.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..ce8e0e9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationScriptBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScriptBase is ScriptBase {} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationTest.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..9beeafe --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationTest.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTest is Test {} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationTestBase.sol b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..e993535 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/compilation/CompilationTestBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTestBase is TestBase {} diff --git a/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/fixtures/broadcast.log.json b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/fixtures/broadcast.log.json new file mode 100644 index 0000000..0a0200b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/lib/forge-std/test/fixtures/broadcast.log.json @@ -0,0 +1,187 @@ +{ + "transactions": [ + { + "hash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "function": "multiple_arguments(uint256,address,uint256[]):(uint256)", + "arguments": ["1", "0000000000000000000000000000000000001337", "[3,4]"], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "gas": "0x73b9", + "value": "0x0", + "data": "0x23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004", + "nonce": "0x3", + "accessList": [] + } + }, + { + "hash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "function": "inc():(uint256)", + "arguments": [], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "gas": "0xdcb2", + "value": "0x0", + "data": "0x371303c0", + "nonce": "0x4", + "accessList": [] + } + }, + { + "hash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "function": "t(uint256):(uint256)", + "arguments": ["1"], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "gas": "0x8599", + "value": "0x0", + "data": "0xafe29f710000000000000000000000000000000000000000000000000000000000000001", + "nonce": "0x5", + "accessList": [] + } + } + ], + "receipts": [ + { + "transactionHash": "0x481dc86e40bba90403c76f8e144aa9ff04c1da2164299d0298573835f0991181", + "transactionIndex": "0x0", + "blockHash": "0xef0730448490304e5403be0fa8f8ce64f118e9adcca60c07a2ae1ab921d748af", + "blockNumber": "0x1", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": null, + "cumulativeGasUsed": "0x13f3a", + "gasUsed": "0x13f3a", + "contractAddress": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x6a187183545b8a9e7f1790e847139379bf5622baff2cb43acf3f5c79470af782", + "transactionIndex": "0x0", + "blockHash": "0xf3acb96a90071640c2a8c067ae4e16aad87e634ea8d8bbbb5b352fba86ba0148", + "blockNumber": "0x2", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": null, + "cumulativeGasUsed": "0x45d80", + "gasUsed": "0x45d80", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x064ad173b4867bdef2fb60060bbdaf01735fbf10414541ea857772974e74ea9d", + "transactionIndex": "0x0", + "blockHash": "0x8373d02109d3ee06a0225f23da4c161c656ccc48fe0fcee931d325508ae73e58", + "blockNumber": "0x3", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "cumulativeGasUsed": "0x45feb", + "gasUsed": "0x45feb", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", + "transactionIndex": "0x0", + "blockHash": "0x16712fae5c0e18f75045f84363fb6b4d9a9fe25e660c4ce286833a533c97f629", + "blockNumber": "0x4", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "cumulativeGasUsed": "0x5905", + "gasUsed": "0x5905", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", + "transactionIndex": "0x0", + "blockHash": "0x156b88c3eb9a1244ba00a1834f3f70de735b39e3e59006dd03af4fe7d5480c11", + "blockNumber": "0x5", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "cumulativeGasUsed": "0xa9c4", + "gasUsed": "0xa9c4", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "transactionIndex": "0x0", + "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", + "blockNumber": "0x6", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "cumulativeGasUsed": "0x66c5", + "gasUsed": "0x66c5", + "contractAddress": null, + "logs": [ + { + "address": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "topics": [ + "0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000", + "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", + "blockNumber": "0x6", + "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "transactionIndex": "0x1", + "logIndex": "0x0", + "transactionLogIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x11fbb10230c168ca1e36a7e5c69a6dbcd04fd9e64ede39d10a83e36ee8065c16", + "transactionIndex": "0x0", + "blockHash": "0xf1e0ed2eda4e923626ec74621006ed50b3fc27580dc7b4cf68a07ca77420e29c", + "blockNumber": "0x7", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x0000000000000000000000000000000000001337", + "cumulativeGasUsed": "0x5208", + "gasUsed": "0x5208", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + } + ], + "libraries": [ + "src/Broadcast.t.sol:F:0x5fbdb2315678afecb367f032d93f642f64180aa3" + ], + "pending": [], + "path": "broadcast/Broadcast.t.sol/31337/run-latest.json", + "returns": {}, + "timestamp": 1655140035 +} diff --git a/lib/openzeppelin-contracts-v5.0.0/logo.svg b/lib/openzeppelin-contracts-v5.0.0/logo.svg new file mode 100644 index 0000000..f1e14c2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/lib/openzeppelin-contracts-v5.0.0/netlify.toml b/lib/openzeppelin-contracts-v5.0.0/netlify.toml new file mode 100644 index 0000000..0447f41 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/netlify.toml @@ -0,0 +1,3 @@ +[build] +command = "npm run docs" +publish = "build/site" diff --git a/lib/openzeppelin-contracts-v5.0.0/package-lock.json b/lib/openzeppelin-contracts-v5.0.0/package-lock.json new file mode 100644 index 0000000..0f4f9f5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/package-lock.json @@ -0,0 +1,16544 @@ +{ + "name": "openzeppelin-solidity", + "version": "4.9.2", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openzeppelin-solidity", + "version": "4.9.2", + "license": "MIT", + "devDependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@nomicfoundation/hardhat-foundry": "^1.1.1", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-truffle5": "^2.0.5", + "@nomiclabs/hardhat-web3": "^2.0.0", + "@openzeppelin/docs-utils": "^0.1.5", + "@openzeppelin/test-helpers": "^0.5.13", + "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", + "@openzeppelin/upgrades-core": "^1.20.6", + "array.prototype.at": "^1.1.1", + "chai": "^4.2.0", + "eslint": "^8.30.0", + "eslint-config-prettier": "^9.0.0", + "eth-sig-util": "^3.0.0", + "ethereumjs-util": "^7.0.7", + "ethereumjs-wallet": "^1.0.1", + "glob": "^10.3.5", + "graphlib": "^2.1.8", + "hardhat": "^2.9.1", + "hardhat-exposed": "^0.3.13", + "hardhat-gas-reporter": "^1.0.9", + "hardhat-ignore-warnings": "^0.2.0", + "keccak256": "^1.0.2", + "lodash.startcase": "^4.4.0", + "lodash.zip": "^4.2.0", + "merkletreejs": "^0.2.13", + "micromatch": "^4.0.2", + "p-limit": "^3.1.0", + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.1.0", + "rimraf": "^5.0.1", + "semver": "^7.3.5", + "solhint": "^3.3.6", + "solhint-plugin-openzeppelin": "file:scripts/solhint-custom", + "solidity-ast": "^0.4.50", + "solidity-coverage": "^0.8.5", + "solidity-docgen": "^0.6.0-beta.29", + "undici": "^5.22.1", + "web3": "^1.3.0", + "yargs": "^17.0.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "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.4", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.4.tgz", + "integrity": "sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/config": "^2.3.1", + "@changesets/get-version-range-type": "^0.3.2", + "@changesets/git": "^2.0.0", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/apply-release-plan/node_modules/prettier": { + "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" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@changesets/assemble-release-plan": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.4.tgz", + "integrity": "sha512-xJkWX+1/CUaOUWTguXEbCDTyWJFECEhmdtbkjhn5GVBGxdP/JwaHBIU9sW3FR6gD07UwZ7ovpiPclQZs+j+mvg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.6", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/changelog-git": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.1.14.tgz", + "integrity": "sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1" + } + }, + "node_modules/@changesets/changelog-github": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.4.8.tgz", + "integrity": "sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw==", + "dev": true, + "dependencies": { + "@changesets/get-github-info": "^0.5.2", + "@changesets/types": "^5.2.1", + "dotenv": "^8.1.0" + } + }, + "node_modules/@changesets/cli": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.2.tgz", + "integrity": "sha512-dnWrJTmRR8bCHikJHl9b9HW3gXACCehz4OasrXpMp7sx97ECuBGGNjJhjPhdZNCvMy9mn4BWdplI323IbqsRig==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/apply-release-plan": "^6.1.4", + "@changesets/assemble-release-plan": "^5.2.4", + "@changesets/changelog-git": "^0.1.14", + "@changesets/config": "^2.3.1", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.6", + "@changesets/get-release-plan": "^3.0.17", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@changesets/write": "^0.2.3", + "@manypkg/get-packages": "^1.1.3", + "@types/is-ci": "^3.0.0", + "@types/semver": "^7.5.0", + "ansi-colors": "^4.1.3", + "chalk": "^2.1.0", + "enquirer": "^2.3.0", + "external-editor": "^3.1.0", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "is-ci": "^3.0.1", + "meow": "^6.0.0", + "outdent": "^0.5.0", + "p-limit": "^2.2.0", + "preferred-pm": "^3.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "spawndamnit": "^2.0.0", + "term-size": "^2.1.0", + "tty-table": "^4.1.5" + }, + "bin": { + "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/config": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.1.tgz", + "integrity": "sha512-PQXaJl82CfIXddUOppj4zWu+987GCw2M+eQcOepxN5s+kvnsZOwjEJO3DH9eVy+OP6Pg/KFEWdsECFEYTtbg6w==", + "dev": true, + "dependencies": { + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.6", + "@changesets/logger": "^0.0.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.2" + } + }, + "node_modules/@changesets/errors": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.1.4.tgz", + "integrity": "sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==", + "dev": true, + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.6.tgz", + "integrity": "sha512-Q/sLgBANmkvUm09GgRsAvEtY3p1/5OCzgBE5vX3vgb5CvW0j7CEljocx5oPXeQSNph6FXulJlXV3Re/v3K3P3Q==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "semver": "^7.5.3" + } + }, + "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", + "integrity": "sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==", + "dev": true, + "dependencies": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.17.tgz", + "integrity": "sha512-6IwKTubNEgoOZwDontYc2x2cWXfr6IKxP3IhKeK+WjyD6y3M4Gl/jdQvBw+m/5zWILSOCAaGLu2ZF6Q+WiPniw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/assemble-release-plan": "^5.2.4", + "@changesets/config": "^2.3.1", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz", + "integrity": "sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==", + "dev": true + }, + "node_modules/@changesets/git": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-2.0.0.tgz", + "integrity": "sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.2", + "spawndamnit": "^2.0.0" + } + }, + "node_modules/@changesets/logger": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.0.5.tgz", + "integrity": "sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==", + "dev": true, + "dependencies": { + "chalk": "^2.1.0" + } + }, + "node_modules/@changesets/parse": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.16.tgz", + "integrity": "sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1", + "js-yaml": "^3.13.1" + } + }, + "node_modules/@changesets/pre": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-1.0.14.tgz", + "integrity": "sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.5.9.tgz", + "integrity": "sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/parse": "^0.3.16", + "@changesets/types": "^5.2.1", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0" + } + }, + "node_modules/@changesets/types": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz", + "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==", + "dev": true + }, + "node_modules/@changesets/write": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.2.3.tgz", + "integrity": "sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/types": "^5.2.1", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "prettier": "^2.7.1" + } + }, + "node_modules/@changesets/write/node_modules/prettier": { + "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" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dev": true, + "dependencies": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + } + }, + "node_modules/@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true, + "dependencies": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + } + }, + "node_modules/@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + } + }, + "node_modules/@ensdomains/ensjs/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/@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true + }, + "node_modules/@eslint-community/eslint-utils": { + "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" + }, + "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.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/js": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", + "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", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "dev": true, + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "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/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "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/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bignumber/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/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "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/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "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/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "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" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "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/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "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/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/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key/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/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "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/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "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/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^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/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "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/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "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/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@frangio/servbot": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@frangio/servbot/-/servbot-0.2.5.tgz", + "integrity": "sha512-ogja4iAPZ1VwM5MU3C1ZhB88358F0PGbmSTGOkIZwOyLaDoMHIqOVCnavHjR7DV5h+oAI4Z4KDqlam3myQUrmg==", + "dev": true, + "engines": { + "node": ">=12.x", + "pnpm": "7.5.1" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "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", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "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", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/secp256k1": { + "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": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz", + "integrity": "sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "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": "7.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz", + "integrity": "sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-ethash": "3.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz", + "integrity": "sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.2", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz", + "integrity": "sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz", + "integrity": "sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==", + "dev": true, + "dependencies": { + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz", + "integrity": "sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz", + "integrity": "sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "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": "6.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz", + "integrity": "sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@types/readable-stream": "^2.3.13", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz", + "integrity": "sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==", + "dev": true, + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz", + "integrity": "sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==", + "dev": true, + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "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": { + "@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.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz", + "integrity": "sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/hardhat-foundry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-foundry/-/hardhat-foundry-1.1.1.tgz", + "integrity": "sha512-cXGCBHAiXas9Pg9MhMOpBVQCkWRYoRFG7GJJAph+sdQsfd22iRs5U5Vs9XmpGEQd1yEvYISQZMeE68Nxj65iUQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "peerDependencies": { + "hardhat": "^2.17.2" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.9.tgz", + "integrity": "sha512-OXWCv0cHpwLUO2u7bFxBna6dQtCC2Gg/aN/KtJLO7gmuuA28vgmVKYFRCDUqrbjujzgfwQ2aKyZ9Y3vSmDqS7Q==", + "dev": true, + "dependencies": { + "ethereumjs-util": "^7.1.4" + }, + "peerDependencies": { + "hardhat": "^2.9.5" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "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.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.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" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomiclabs/hardhat-truffle5": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-truffle5/-/hardhat-truffle5-2.0.7.tgz", + "integrity": "sha512-Pw8451IUZp1bTp0QqCHCYfCHs66sCnyxPcaorapu9mfOV9xnZsVaFdtutnhNEiXdiZwbed7LFKpRsde4BjFwig==", + "dev": true, + "dependencies": { + "@nomiclabs/truffle-contract": "^4.2.23", + "@types/chai": "^4.2.0", + "chai": "^4.2.0", + "ethereumjs-util": "^7.1.4", + "fs-extra": "^7.0.1" + }, + "peerDependencies": { + "@nomiclabs/hardhat-web3": "^2.0.0", + "hardhat": "^2.6.4", + "web3": "^1.0.0-beta.36" + } + }, + "node_modules/@nomiclabs/hardhat-web3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-web3/-/hardhat-web3-2.0.0.tgz", + "integrity": "sha512-zt4xN+D+fKl3wW2YlTX3k9APR3XZgPkxJYf36AcliJn3oujnKEVRZaHu0PhgLjO+gR+F/kiYayo9fgd2L8970Q==", + "dev": true, + "dependencies": { + "@types/bignumber.js": "^5.0.0" + }, + "peerDependencies": { + "hardhat": "^2.0.0", + "web3": "^1.0.0-beta.36" + } + }, + "node_modules/@nomiclabs/truffle-contract": { + "version": "4.5.10", + "resolved": "https://registry.npmjs.org/@nomiclabs/truffle-contract/-/truffle-contract-4.5.10.tgz", + "integrity": "sha512-nF/6InFV+0hUvutyFgsdOMCoYlr//2fJbRER4itxYtQtc4/O1biTwZIKRu+5l2J5Sq6LU2WX7vZHtDgQdhWxIQ==", + "dev": true, + "dependencies": { + "@ensdomains/ensjs": "^2.0.1", + "@truffle/blockchain-utils": "^0.1.3", + "@truffle/contract-schema": "^3.4.7", + "@truffle/debug-utils": "^6.0.22", + "@truffle/error": "^0.1.0", + "@truffle/interface-adapter": "^0.5.16", + "bignumber.js": "^7.2.1", + "ethereum-ens": "^0.8.0", + "ethers": "^4.0.0-beta.1", + "source-map-support": "^0.5.19" + }, + "peerDependencies": { + "web3": "^1.2.1", + "web3-core-helpers": "^1.2.1", + "web3-core-promievent": "^1.2.1", + "web3-eth-abi": "^1.2.1", + "web3-utils": "^1.2.1" + } + }, + "node_modules/@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@openzeppelin/docs-utils": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@openzeppelin/docs-utils/-/docs-utils-0.1.5.tgz", + "integrity": "sha512-GfqXArKmdq8rv+hsP+g8uS1VEkvMIzWs31dCONffzmqFwJ+MOsaNQNZNXQnLRgUkzk8i5mTNDjJuxDy+aBZImQ==", + "dev": true, + "dependencies": { + "@frangio/servbot": "^0.2.5", + "chalk": "^3.0.0", + "chokidar": "^3.5.3", + "env-paths": "^2.2.0", + "find-up": "^4.1.0", + "is-port-reachable": "^3.0.0", + "js-yaml": "^3.13.1", + "lodash.startcase": "^4.4.0", + "minimist": "^1.2.0" + }, + "bin": { + "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", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dev": true, + "dependencies": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "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.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler": { + "version": "0.3.32", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.3.32.tgz", + "integrity": "sha512-ypgj6MXXcDG0dOuMwENXt0H4atCtCsPgpDgWZYewb2egfUCMpj6d2GO4pcNZgdn1zYsmUHfm5ZA/Nga/8qkdKA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0", + "compare-versions": "^6.0.0", + "ethereum-cryptography": "^2.0.0", + "lodash": "^4.17.20", + "minimatch": "^9.0.0", + "minimist": "^1.2.5", + "solidity-ast": "^0.4.51" + }, + "bin": { + "upgrade-safe-transpiler": "dist/cli.js" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/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/@openzeppelin/upgrade-safe-transpiler/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/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/@openzeppelin/upgrade-safe-transpiler/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/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/@openzeppelin/upgrades-core": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.29.0.tgz", + "integrity": "sha512-csZvAMNqUJjMDNBPbaXcV9Nlo4oagMD/HkOBHTpYbBTpnmUhwPVHOMv+Rl0RatBdLHuGc6hw88h80k5PWkEeWw==", + "dev": true, + "dependencies": { + "cbor": "^9.0.0", + "chalk": "^4.1.0", + "compare-versions": "^6.0.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.0.3", + "minimist": "^1.2.7", + "proper-lockfile": "^4.1.1", + "solidity-ast": "^0.4.26" + }, + "bin": { + "openzeppelin-upgrades-core": "dist/cli/cli.js" + } + }, + "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": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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/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": ">=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/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@scure/base": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.3.tgz", + "integrity": "sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==", + "dev": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@truffle/abi-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.3.tgz", + "integrity": "sha512-AWhs01HCShaVKjml7Z4AbVREr/u4oiWxCcoR7Cktm0mEvtT04pvnxW5xB/cI4znRkrbPdFQlFt67kgrAjesYkw==", + "dev": true, + "dependencies": { + "change-case": "3.0.2", + "fast-check": "3.1.1", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "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.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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.9", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.9.tgz", + "integrity": "sha512-RHfumgbIVo68Rv9ofDYfynjnYZIfP/f1vZy4RoqkfYAO+fqfc58PDRzB1WAGq2U6GPuOnipOJxQhnqNnffORZg==", + "dev": true, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/codec": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.17.3.tgz", + "integrity": "sha512-Ko/+dsnntNyrJa57jUD9u4qx9nQby+H4GsUO6yjiCPSX0TQnEHK08XWqBSg0WdmCH2+h0y1nr2CXSx8gbZapxg==", + "dev": true, + "dependencies": { + "@truffle/abi-utils": "^1.0.3", + "@truffle/compile-common": "^0.9.8", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "^7.5.4", + "utf8": "^3.0.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/codec/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/codec/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/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/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/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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/compile-common": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.8.tgz", + "integrity": "sha512-DTpiyo32t/YhLI1spn84D3MHYHrnoVqO+Gp7ZHrYNwDs86mAxtNiH5lsVzSb8cPgiqlvNsRCU9nm9R0YmKMTBQ==", + "dev": true, + "dependencies": { + "@truffle/error": "^0.2.2", + "colors": "1.4.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/compile-common/node_modules/@truffle/error": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.2.tgz", + "integrity": "sha512-TqbzJ0O8DHh34cu8gDujnYl4dUl6o2DE4PR6iokbybvnIm/L2xl6+Gv1VC+YJS45xfH83Yo3/Zyg/9Oq8/xZWg==", + "dev": true, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract": { + "version": "4.6.31", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.31.tgz", + "integrity": "sha512-s+oHDpXASnZosiCdzu+X1Tx5mUJUs1L1CYXIcgRmzMghzqJkaUFmR6NpNo7nJYliYbO+O9/aW8oCKqQ7rCHfmQ==", + "dev": true, + "dependencies": { + "@ensdomains/ensjs": "^2.1.0", + "@truffle/blockchain-utils": "^0.1.9", + "@truffle/contract-schema": "^3.4.16", + "@truffle/debug-utils": "^6.0.57", + "@truffle/error": "^0.2.2", + "@truffle/interface-adapter": "^0.5.37", + "bignumber.js": "^7.2.1", + "debug": "^4.3.1", + "ethers": "^4.0.32", + "web3": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract-schema": { + "version": "3.4.16", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.16.tgz", + "integrity": "sha512-g0WNYR/J327DqtJPI70ubS19K1Fth/1wxt2jFqLsPmz5cGZVjCwuhiie+LfBde4/Mc9QR8G+L3wtmT5cyoBxAg==", + "dev": true, + "dependencies": { + "ajv": "^6.10.0", + "debug": "^4.3.1" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract/node_modules/@truffle/error": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.2.tgz", + "integrity": "sha512-TqbzJ0O8DHh34cu8gDujnYl4dUl6o2DE4PR6iokbybvnIm/L2xl6+Gv1VC+YJS45xfH83Yo3/Zyg/9Oq8/xZWg==", + "dev": true, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "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": { + "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.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/contract/node_modules/web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "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.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-abi": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz", + "integrity": "sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "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.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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.57", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.57.tgz", + "integrity": "sha512-Q6oI7zLaeNLB69ixjwZk2UZEWBY6b2OD1sjLMGDKBGR7GaHYiw96GLR2PFgPH1uwEeLmV4N78LYaQCrDsHbNeA==", + "dev": true, + "dependencies": { + "@truffle/codec": "^0.17.3", + "@trufflesuite/chromafi": "^3.0.0", + "bn.js": "^5.1.3", + "chalk": "^2.4.2", + "debug": "^4.3.1", + "highlightjs-solidity": "^2.0.6" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/debug-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/error": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.1.1.tgz", + "integrity": "sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter": { + "version": "0.5.37", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.37.tgz", + "integrity": "sha512-lPH9MDgU+7sNDlJSClwyOwPCfuOimqsCx0HfGkznL3mcFRymc1pukAR1k17zn7ErHqBwJjiKAZ6Ri72KkS+IWw==", + "dev": true, + "dependencies": { + "bn.js": "^5.1.3", + "ethers": "^4.0.32", + "web3": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "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/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "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.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-abi": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz", + "integrity": "sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "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.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dev": true, + "dependencies": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "strip-indent": "^2.0.0" + } + }, + "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, + "engines": { + "node": ">=4" + } + }, + "node_modules/@types/bignumber.js": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bignumber.js/-/bignumber.js-5.0.0.tgz", + "integrity": "sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==", + "deprecated": "This is a stub types definition for bignumber.js (https://github.com/MikeMcl/bignumber.js/). bignumber.js provides its own type definitions, so you don't need @types/bignumber.js installed!", + "dev": true, + "dependencies": { + "bignumber.js": "*" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-dkpZu0szUtn9UXTmw+e0AJFd4D2XAxDnsCLdc05SfqpqzPEBft8eQr8uaFitfo/dUUOZERaLec2hHMG87A4Dxg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==", + "dev": true + }, + "node_modules/@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", + "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", + "dev": true + }, + "node_modules/@types/is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.1.0" + } + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "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/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.8", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "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", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true + }, + "node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/abstract-level/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", + "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "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/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/antlr4": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.1.tgz", + "integrity": "sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.at": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.at/-/array.prototype.at-1.1.2.tgz", + "integrity": "sha512-TPj626jUZMc2Qbld8uXKZrXM/lSStx2KfbIyF70Ui9RgdgibpTWC6WGCuff6qQ7xYzqXtir60WAHrfmknkF3Vw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.3.tgz", + "integrity": "sha512-kcBubumjciBg4JKp5KTKtI7ec7tRefPk88yjkWJwaVKYd9QfTaxcsOxoMNKd7iBr447zCfDV0z1kOF47umv42g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "dev": true + }, + "node_modules/astral-regex": { + "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": ">=8" + } + }, + "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/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/axios": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/bigint-crypto-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz", + "integrity": "sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "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/body-parser": { + "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.5", + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "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", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/breakword": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/breakword/-/breakword-1.0.6.tgz", + "integrity": "sha512-yjxDAYyK/pBvws9H4xKYpLDpYKEH6CzrBPAuXq3x18I+c/2MkVtT3qAr7Oloi6Dss9qNhPVueAAVU1CSeNDIXw==", + "dev": true, + "dependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "node_modules/browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-reverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==", + "dev": true + }, + "node_modules/buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/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/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", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cbor": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.1.tgz", + "integrity": "sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==", + "dev": true, + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/chai": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.8.tgz", + "integrity": "sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "dev": true, + "peerDependencies": { + "bn.js": "^4.11.0", + "chai": "^4.0.0" + } + }, + "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/change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/ci-info": { + "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", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/cids/node_modules/multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "dev": true + }, + "node_modules/classic-level": { + "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.2.2", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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/cliui/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "node_modules/commander": { + "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" + } + }, + "node_modules/compare-versions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "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", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-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/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, + "dependencies": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "dependencies": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "node_modules/content-type": { + "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" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-addr-codec": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.8.tgz", + "integrity": "sha512-GqAK90iLLgP3FvhNmHbpT3wR6dEdaM8hZyZtLX29SPardh3OA13RFLHDR6sntGCgRWOfiHqW6sIyohpNqOtV/g==", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, + "node_modules/crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", + "dev": true + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "dev": true, + "dependencies": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + }, + "engines": { + "node": ">= 0.1.90" + } + }, + "node_modules/csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "dev": true + }, + "node_modules/csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "node_modules/csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", + "dev": true + }, + "node_modules/death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", + "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "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.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/enquirer/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/enquirer/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/entities": { + "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" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", + "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.1", + "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.5", + "is-array-buffer": "^3.0.2", + "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.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/escodegen/node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/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/escodegen/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/escodegen/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/eslint": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "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": { + "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": ">=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", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/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/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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "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", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "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.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "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" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dev": true, + "dependencies": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "node_modules/eth-ens-namehash/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/eth-gas-reporter": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", + "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.14.0", + "axios": "^1.5.1", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^5.7.2", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^10.2.0", + "req-cwd": "^2.0.0", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "peerDependencies": { + "@codechecks/client": "^0.1.0" + }, + "peerDependenciesMeta": { + "@codechecks/client": { + "optional": true + } + } + }, + "node_modules/eth-gas-reporter/node_modules/@noble/hashes": { + "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": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/eth-gas-reporter/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { + "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.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/eth-gas-reporter/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/eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/eth-lib/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/eth-lib/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/eth-sig-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-3.0.1.tgz", + "integrity": "sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==", + "deprecated": "Deprecated in favor of '@metamask/eth-sig-util'", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^5.1.1", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.0" + } + }, + "node_modules/eth-sig-util/node_modules/ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "dependencies": { + "js-sha3": "^0.8.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereum-ens": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ethereum-ens/-/ethereum-ens-0.8.0.tgz", + "integrity": "sha512-a8cBTF4AWw1Q1Y37V1LSCS9pRY4Mh3f8vCg5cbXCCEJ3eno1hbI/+Ccv9SZLISYpqQhaglP3Bxb/34lS4Qf7Bg==", + "dev": true, + "dependencies": { + "bluebird": "^3.4.7", + "eth-ens-namehash": "^2.0.0", + "js-sha3": "^0.5.7", + "pako": "^1.0.4", + "underscore": "^1.8.3", + "web3": "^1.0.0-beta.34" + } + }, + "node_modules/ethereum-ens/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethereumjs-util/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/ethereumjs-wallet": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz", + "integrity": "sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==", + "dev": true, + "dependencies": { + "aes-js": "^3.1.2", + "bs58check": "^2.1.2", + "ethereum-cryptography": "^0.1.3", + "ethereumjs-util": "^7.1.2", + "randombytes": "^2.1.0", + "scrypt-js": "^3.0.1", + "utf8": "^3.0.0", + "uuid": "^8.3.2" + } + }, + "node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/ethers/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/ethers/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/ethers/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/ethers/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "node_modules/ethers/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "node_modules/ethers/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true + }, + "node_modules/ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-abi/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-abi/node_modules/js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==", + "dev": true + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "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", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "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", + "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", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dev": true, + "dependencies": { + "pure-rand": "^5.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "dev": true, + "dependencies": { + "flatted": "^3.2.7", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flat-cache/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/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "dev": true + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + }, + "bin": { + "testrpc-sc": "index.js" + } + }, + "node_modules/glob": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.5.tgz", + "integrity": "sha512-bYUpUD7XDEHI4Q2O5a7PXGvyw4deKR70kHiDxzQbe925wbZknhOzUt2xBgTkYL6RBcVeXYuD9iNYeqoWbBZQnA==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/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_modules/globals": { + "version": "13.22.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", + "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "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/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "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": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/hardhat": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.17.3.tgz", + "integrity": "sha512-SFZoYVXW1bWJZrIIKXOA+IgcctfuKXDwENywiYNT2dM3YQc4fXNaTbuk/vpPzHIF50upByx4zW5EqczKYQubsA==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@nomicfoundation/ethereumjs-vm": "7.0.2", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat-exposed": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.13.tgz", + "integrity": "sha512-hY2qCYSi2wD2ChZ0WP0oEPS4zlZ2vGaLOVXvfosGcy6mNeQ+pWsxTge35tTumCHwCzk/dYxLZq+KW0Z5t08yDA==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.4", + "solidity-ast": "^0.4.52" + }, + "peerDependencies": { + "hardhat": "^2.3.0" + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "dependencies": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + }, + "peerDependencies": { + "hardhat": "^2.0.2" + } + }, + "node_modules/hardhat-ignore-warnings": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.9.tgz", + "integrity": "sha512-q1oj6/ixiAx+lgIyGLBajVCSC7qUtAoK7LS9Nr8UVHYo8Iuh5naBiVGo4RDJ6wxbDGYBkeSukUGZrMqzC2DWwA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + } + }, + "node_modules/hardhat-ignore-warnings/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/hardhat-ignore-warnings/node_modules/minimatch": { + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hardhat/node_modules/@noble/hashes": { + "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": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/hardhat/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/hardhat/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "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": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "node_modules/hardhat/node_modules/ethereum-cryptography": { + "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.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/hardhat/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/hardhat/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/hardhat/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/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/hardhat/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/hardhat/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/hardhat/node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "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", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-solidity": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/htmlparser2": { + "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", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-cache-semantics": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "dev": true + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "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", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-id": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz", + "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "dependencies": { + "punycode": "2.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "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", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "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.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "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.2.0", + "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", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/is-port-reachable": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-3.1.0.tgz", + "integrity": "sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.3.tgz", + "integrity": "sha512-R2bUw+kVZFS/h1AZqBKrSgDmdmjApzgY0AlCPumopFiAlbUxE2gf+SCuBzQ0cP5hHmUmFYF5yw55T97Th5Kstg==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-sdsl": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", + "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "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", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keccak256": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz", + "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0", + "buffer": "^6.0.3", + "keccak": "^3.0.2" + } + }, + "node_modules/keccak256/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/keccak256/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "dependencies": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/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/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", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "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", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "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/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", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, + "node_modules/lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.2" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/meow": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", + "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/merkletreejs": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.2.32.tgz", + "integrity": "sha512-TostQBiwYRIwSE5++jGmacu3ODcKAgqb0Y/pnIohXS7sWxh1gCkSptbmF1a43faehRDpcHf7J/kv0Ml2D/zblQ==", + "dev": true, + "dependencies": { + "bignumber.js": "^9.0.1", + "buffer-reverse": "^1.0.1", + "crypto-js": "^3.1.9-1", + "treeify": "^1.1.0", + "web3-utils": "^1.3.4" + }, + "engines": { + "node": ">= 7.6.0" + } + }, + "node_modules/merkletreejs/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "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" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mixme": { + "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" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", + "dev": true, + "dependencies": { + "mkdirp": "*" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "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", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "dev": true + }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "varint": "^5.0.0" + } + }, + "node_modules/multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "node_modules/multihashes/node_modules/multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/nano-base32": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==", + "dev": true + }, + "node_modules/nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-macros": { + "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": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "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/node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-interval-tree": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-2.1.2.tgz", + "integrity": "sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==", + "dev": true, + "dependencies": { + "shallowequal": "^1.1.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "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/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "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" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "node_modules/oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dev": true, + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-filter/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "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", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "dev": true + }, + "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/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "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.1.2", + "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.1.2.tgz", + "integrity": "sha512-nk7dKrcW8hfCZ4H6klWcdRknBOXWzNQByJ0oJyX97BOupsYD+FzLS4hflgEu/uPUEHZCuRfMxzCBsuWd7OzT8Q==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0", + "find-yarn-workspace-root2": "1.2.16", + "path-exists": "^4.0.0", + "which-pm": "2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/preferred-pm/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/preferred-pm/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-solidity": { + "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.16.0", + "semver": "^7.3.8", + "solidity-comments-extractor": "^0.0.7" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "prettier": ">=2.3.0 || >=3.0.0-alpha.0" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", + "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "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", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/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/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/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/read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/readable-stream": { + "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", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "dependencies": { + "req-from": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from/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" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "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/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/responselike/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", + "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", + "dev": true, + "dependencies": { + "glob": "^10.2.5" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/rlp/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/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/sc-istanbul/node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "node_modules/sc-istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sc-istanbul/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_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "dependencies": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dev": true, + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/sha3/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/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/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dev": true, + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "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": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-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/slice-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/slice-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/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", + "integrity": "sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==", + "dev": true, + "dependencies": { + "array.prototype.flat": "^1.2.3", + "breakword": "^1.0.5", + "grapheme-splitter": "^1.0.4", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^15.1.0" + }, + "bin": { + "smartwrap": "src/terminal-adapter.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/smartwrap/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, + "engines": { + "node": ">=8" + } + }, + "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": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/smartwrap/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "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": ">=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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/smartwrap/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dev": true, + "dependencies": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + }, + "bin": { + "solcjs": "solcjs" + } + }, + "node_modules/solc/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "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" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/solc/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/solc/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "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", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "node_modules/solc/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solc/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "node_modules/solc/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/solc/node_modules/yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "dependencies": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "node_modules/solc/node_modules/yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + }, + "node_modules/solhint": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.6.2.tgz", + "integrity": "sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.16.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": "^7.5.2", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" + }, + "bin": { + "solhint": "solhint.js" + }, + "optionalDependencies": { + "prettier": "^2.8.3" + } + }, + "node_modules/solhint-plugin-openzeppelin": { + "resolved": "scripts/solhint-custom", + "link": true + }, + "node_modules/solhint/node_modules/@solidity-parser/parser": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", + "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint/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/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/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/solhint/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/solhint/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/solhint/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/solhint/node_modules/glob": { + "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", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/solhint/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/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/solhint/node_modules/minimatch": { + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solhint/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint/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/solidity-ast": { + "version": "0.4.52", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.52.tgz", + "integrity": "sha512-iOya9BSiB9jhM8Vf40n8lGELGzwrUc57rl5BhfNtJ5cvAaMvRcNlHeAMNvqJJyjoUnczqRbHqdivEqK89du3Cw==", + "dev": true, + "dependencies": { + "array.prototype.findlast": "^1.2.2" + } + }, + "node_modules/solidity-comments": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments/-/solidity-comments-0.0.2.tgz", + "integrity": "sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "solidity-comments-darwin-arm64": "0.0.2", + "solidity-comments-darwin-x64": "0.0.2", + "solidity-comments-freebsd-x64": "0.0.2", + "solidity-comments-linux-arm64-gnu": "0.0.2", + "solidity-comments-linux-arm64-musl": "0.0.2", + "solidity-comments-linux-x64-gnu": "0.0.2", + "solidity-comments-linux-x64-musl": "0.0.2", + "solidity-comments-win32-arm64-msvc": "0.0.2", + "solidity-comments-win32-ia32-msvc": "0.0.2", + "solidity-comments-win32-x64-msvc": "0.0.2" + } + }, + "node_modules/solidity-comments-darwin-arm64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-arm64/-/solidity-comments-darwin-arm64-0.0.2.tgz", + "integrity": "sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-darwin-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-x64/-/solidity-comments-darwin-x64-0.0.2.tgz", + "integrity": "sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "node_modules/solidity-comments-freebsd-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-freebsd-x64/-/solidity-comments-freebsd-x64-0.0.2.tgz", + "integrity": "sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-gnu/-/solidity-comments-linux-arm64-gnu-0.0.2.tgz", + "integrity": "sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-musl/-/solidity-comments-linux-arm64-musl-0.0.2.tgz", + "integrity": "sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-gnu/-/solidity-comments-linux-x64-gnu-0.0.2.tgz", + "integrity": "sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-musl/-/solidity-comments-linux-x64-musl-0.0.2.tgz", + "integrity": "sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-arm64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-arm64-msvc/-/solidity-comments-win32-arm64-msvc-0.0.2.tgz", + "integrity": "sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-ia32-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-ia32-msvc/-/solidity-comments-win32-ia32-msvc-0.0.2.tgz", + "integrity": "sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-x64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-x64-msvc/-/solidity-comments-win32-x64-msvc-0.0.2.tgz", + "integrity": "sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-coverage": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.5.tgz", + "integrity": "sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.16.0", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "10.2.0", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "bin": { + "solidity-coverage": "plugins/bin.js" + }, + "peerDependencies": { + "hardhat": "^2.11.0" + } + }, + "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", + "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/solidity-coverage/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/solidity-coverage/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/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": ">=8" + } + }, + "node_modules/solidity-docgen": { + "version": "0.6.0-beta.36", + "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.6.0-beta.36.tgz", + "integrity": "sha512-f/I5G2iJgU1h0XrrjRD0hHMr7C10u276vYvm//rw1TzFcYQ4xTOyAoi9oNAHRU0JU4mY9eTuxdVc2zahdMuhaQ==", + "dev": true, + "dependencies": { + "handlebars": "^4.7.7", + "solidity-ast": "^0.4.38" + }, + "peerDependencies": { + "hardhat": "^2.8.0" + } + }, + "node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz", + "integrity": "sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/spawndamnit/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/spawndamnit/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/spawndamnit/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==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit/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/spawndamnit/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_modules/spawndamnit/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/spdx-correct": { + "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", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.15.tgz", + "integrity": "sha512-lpT8hSQp9jAKp9mhtBU4Xjon8LPGBvLIuBiSVhMEtmLecTh2mO0tlqrAMp47tBXzMr13NJMQ2lf7RpQGLJ3HsQ==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "dev": true, + "dependencies": { + "mixme": "^0.5.1" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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/string-width-cjs/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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, + "engines": { + "node": ">=8" + } + }, + "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/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "node_modules/swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + } + }, + "node_modules/swarm-js/node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swarm-js/node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/swarm-js/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/swarm-js/node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/swarm-js/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "dependencies": { + "get-port": "^3.1.0" + } + }, + "node_modules/table": { + "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": "^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": ">=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": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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": "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "deprecated": "testrpc has been renamed to ganache-cli, please use this package from now on.", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tough-cookie/node_modules/punycode": { + "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" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "node_modules/tty-table": { + "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.3", + "kleur": "^4.1.5", + "smartwrap": "^2.0.2", + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.1", + "yargs": "^17.7.1" + }, + "bin": { + "tty-table": "adapters/terminal-adapter.js" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/tty-table/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, + "engines": { + "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", + "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/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", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "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", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/undici": { + "version": "5.25.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.25.1.tgz", + "integrity": "sha512-nTw6b2G2OqP6btYPyghCgV4hSwjJlL/78FMJatVLCa3otj6PCOQSt6dVtYt82OtNqFz8XsnJ+vsXLADPXjPhqw==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, + "node_modules/upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "dev": true + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web3": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.2.tgz", + "integrity": "sha512-DAtZ3a3ruPziE80uZ3Ob0YDZxt6Vk2un/F5BcBrxO70owJ9Z1Y2+loZmbh1MoAmoLGjA/SUSHeUtid3fYmBaog==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.2", + "web3-core": "1.10.2", + "web3-eth": "1.10.2", + "web3-eth-personal": "1.10.2", + "web3-net": "1.10.2", + "web3-shh": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.2.tgz", + "integrity": "sha512-vLOfDCj6198Qc7esDrCKeFA/M3ZLbowsaHQ0hIL4NmIHoq7lU8aSRTa5AI+JBh8cKN1gVryJsuW2ZCc5bM4I4Q==", + "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/web3-core": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.2.tgz", + "integrity": "sha512-qTn2UmtE8tvwMRsC5pXVdHxrQ4uZ6jiLgF5DRUVtdi7dPUmX18Dp9uxKfIfhGcA011EAn8P6+X7r3pvi2YRxBw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-core-requestmanager": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.0.tgz", + "integrity": "sha512-pIxAzFDS5vnbXvfvLSpaA1tfRykAe9adw43YCKsEYQwH0gCLL0kMLkaCX3q+Q8EVmAh+e1jWL/nl9U0de1+++g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers/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/web3-core-helpers/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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/web3-core-method": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.2.tgz", + "integrity": "sha512-gG6ES+LOuo01MJHML4gnEt702M8lcPGMYZoX8UjZzmEebGrPYOY9XccpCrsFgCeKgQzM12SVnlwwpMod1+lcLg==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.2", + "web3-core-promievent": "1.10.2", + "web3-core-subscriptions": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/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/web3-core-method/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-core-promievent": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.2.tgz", + "integrity": "sha512-Qkkb1dCDOU8dZeORkcwJBQRAX+mdsjx8LqFBB+P4W9QgwMqyJ6LXda+y1XgyeEVeKEmY1RCeTq9Y94q1v62Sfw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-promievent": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.0.tgz", + "integrity": "sha512-68N7k5LWL5R38xRaKFrTFT2pm2jBNFaM4GioS00YjAKXRQ3KjmhijOMG3TICz6Aa5+6GDWYelDNx21YAeZ4YTg==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.2.tgz", + "integrity": "sha512-nlLeNJUu6fR+ZbJr2k9Du/nN3VWwB4AJPY4r6nxUODAmykgJq57T21cLP/BEk6mbiFQYGE9TrrPhh4qWxQEtAw==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.2", + "web3-providers-http": "1.10.2", + "web3-providers-ipc": "1.10.2", + "web3-providers-ws": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager/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/web3-core-requestmanager/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.2.tgz", + "integrity": "sha512-MiWcKjz4tco793EPPPLc/YOJmYUV3zAfxeQH/UVTfBejMfnNvmfwKa2SBKfPIvKQHz/xI5bV2TF15uvJEucU7w==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/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/web3-core-subscriptions/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/web3-core/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/web3-core/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.2.tgz", + "integrity": "sha512-s38rhrntyhGShmXC4R/aQtfkpcmev9c7iZwgb9CDIBFo7K8nrEJvqIOyajeZTxnDIiGzTJmrHxiKSadii5qTRg==", + "dev": true, + "dependencies": { + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-core-subscriptions": "1.10.2", + "web3-eth-abi": "1.10.2", + "web3-eth-accounts": "1.10.2", + "web3-eth-contract": "1.10.2", + "web3-eth-ens": "1.10.2", + "web3-eth-iban": "1.10.2", + "web3-eth-personal": "1.10.2", + "web3-net": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.2.tgz", + "integrity": "sha512-pY4fQUio7W7ZRSLf+vsYkaxJqaT/jHcALZjIxy+uBQaYAJ3t6zpQqMZkJB3Dw7HUODRJ1yI0NPEFGTnkYf/17A==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.2.tgz", + "integrity": "sha512-6/HhCBYAXN/f553/SyxS9gY62NbLgpD1zJpENcvRTDpJN3Znvli1cmpl5Q3ZIUJkvHnG//48EWfWh0cbb3fbKQ==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "@ethereumjs/util": "^8.1.0", + "eth-lib": "0.2.8", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/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/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/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/web3-eth-contract": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.2.tgz", + "integrity": "sha512-CZLKPQRmupP/+OZ5A/CBwWWkBiz5B/foOpARz0upMh1yjb0dEud4YzRW2gJaeNu0eGxDLsWVaXhUimJVGYprQw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-core-promievent": "1.10.2", + "web3-core-subscriptions": "1.10.2", + "web3-eth-abi": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/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/web3-eth-contract/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-core-promievent": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.2.tgz", + "integrity": "sha512-Qkkb1dCDOU8dZeORkcwJBQRAX+mdsjx8LqFBB+P4W9QgwMqyJ6LXda+y1XgyeEVeKEmY1RCeTq9Y94q1v62Sfw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.2.tgz", + "integrity": "sha512-kTQ42UdNHy4BQJHgWe97bHNMkc3zCMBKKY7t636XOMxdI/lkRdIjdE5nQzt97VjQvSVasgIWYKRAtd8aRaiZiQ==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-promievent": "1.10.2", + "web3-eth-abi": "1.10.2", + "web3-eth-contract": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/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/web3-eth-ens/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-core-promievent": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.2.tgz", + "integrity": "sha512-Qkkb1dCDOU8dZeORkcwJBQRAX+mdsjx8LqFBB+P4W9QgwMqyJ6LXda+y1XgyeEVeKEmY1RCeTq9Y94q1v62Sfw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-iban": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.0.tgz", + "integrity": "sha512-0l+SP3IGhInw7Q20LY3IVafYEuufo4Dn75jAHT7c2aDJsIolvf2Lc6ugHkBajlwUneGfbRQs/ccYPQ9JeMUbrg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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/web3-eth-iban/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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/web3-eth-personal": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.2.tgz", + "integrity": "sha512-+vEbJsPUJc5J683y0c2aN645vXC+gPVlFVCQu4IjPvXzJrAtUfz26+IZ6AUOth4fDJPT0f1uSLS5W2yrUdw9BQ==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-net": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/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/web3-eth-personal/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/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/web3-eth/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-net": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.2.tgz", + "integrity": "sha512-w9i1t2z7dItagfskhaCKwpp6W3ylUR88gs68u820y5f8yfK5EbPmHc6c2lD8X9ZrTnmDoeOpIRCN/RFPtZCp+g==", + "dev": true, + "dependencies": { + "web3-core": "1.10.2", + "web3-core-method": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.2.tgz", + "integrity": "sha512-G8abKtpkyKGpRVKvfjIF3I4O/epHP7mxXWN8mNMQLkQj1cjMFiZBZ13f+qI77lNJN7QOf6+LtNdKrhsTGU72TA==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.5", + "cross-fetch": "^4.0.0", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http/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/web3-providers-http/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.2.tgz", + "integrity": "sha512-lWbn6c+SgvhLymU8u4Ea/WOVC0Gqs7OJUvauejWz+iLycxeF0xFNyXnHVAi42ZJDPVI3vnfZotafoxcNNL7Sug==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc/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/web3-providers-ipc/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.2.tgz", + "integrity": "sha512-3nYSiP6grI5GvpkSoehctSywfCTodU21VY8bUtXyFHK/IVfDooNtMpd5lVIMvXVAlaxwwrCfjebokaJtKH2Iag==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.2", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/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/web3-providers-ws/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-shh": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.2.tgz", + "integrity": "sha512-UP0Kc3pHv9uULFu0+LOVfPwKBSJ6B+sJ5KflF7NyBk6TvNRxlpF3hUhuaVDCjjB/dDUR6T0EQeg25FA2uzJbag==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.2", + "web3-core-method": "1.10.2", + "web3-core-subscriptions": "1.10.2", + "web3-net": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.2.tgz", + "integrity": "sha512-TdApdzdse5YR+5GCX/b/vQnhhbj1KSAtfrDtRW7YS0kcWp1gkJsN62gw6GzCaNTeXookB7UrLtmDUuMv65qgow==", + "dev": true, + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "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/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/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dev": true, + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", + "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", + "dev": true, + "dependencies": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8.15" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true, + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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-cjs/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-cjs/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-cjs/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/wrap-ansi-cjs/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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, + "engines": { + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "dependencies": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "node_modules/xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "dependencies": { + "xhr-request": "^1.1.0" + } + }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "dev": true, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "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", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "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/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": ">=6" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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/yargs/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "scripts/solhint-custom": { + "name": "solhint-plugin-openzeppelin", + "version": "0.0.0", + "dev": true + } + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/package.json b/lib/openzeppelin-contracts-v5.0.0/package.json new file mode 100644 index 0000000..c7e92ef --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/package.json @@ -0,0 +1,96 @@ +{ + "name": "openzeppelin-solidity", + "description": "Secure Smart Contract library for Solidity", + "version": "5.0.0", + "private": true, + "files": [ + "/contracts/**/*.sol", + "!/contracts/mocks/**/*" + ], + "scripts": { + "compile": "hardhat compile", + "coverage": "env COVERAGE=true FOUNDRY=false hardhat coverage", + "docs": "npm run prepare-docs && oz-docs", + "docs:watch": "oz-docs watch contracts docs/templates docs/config.js", + "prepare-docs": "scripts/prepare-docs.sh", + "lint": "npm run lint:js && npm run lint:sol", + "lint:fix": "npm run lint:js:fix && npm run lint:sol:fix", + "lint:js": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --check && eslint --ignore-path .gitignore .", + "lint:js:fix": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --write && eslint --ignore-path .gitignore . --fix", + "lint:sol": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --check && solhint '{contracts,test}/**/*.sol'", + "lint:sol:fix": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write", + "clean": "hardhat clean && rimraf build contracts/build", + "prepack": "scripts/prepack.sh", + "generate": "scripts/generate/run.js", + "release": "scripts/release/release.sh", + "version": "scripts/release/version.sh", + "test": "hardhat test", + "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 ." + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "security", + "zeppelin" + ], + "author": "OpenZeppelin Community ", + "license": "MIT", + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, + "homepage": "https://openzeppelin.com/contracts/", + "devDependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@nomicfoundation/hardhat-foundry": "^1.1.1", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-truffle5": "^2.0.5", + "@nomiclabs/hardhat-web3": "^2.0.0", + "@openzeppelin/docs-utils": "^0.1.5", + "@openzeppelin/test-helpers": "^0.5.13", + "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", + "@openzeppelin/upgrades-core": "^1.20.6", + "array.prototype.at": "^1.1.1", + "chai": "^4.2.0", + "eslint": "^8.30.0", + "eslint-config-prettier": "^9.0.0", + "eth-sig-util": "^3.0.0", + "ethereumjs-util": "^7.0.7", + "ethereumjs-wallet": "^1.0.1", + "glob": "^10.3.5", + "graphlib": "^2.1.8", + "hardhat": "^2.9.1", + "hardhat-exposed": "^0.3.13", + "hardhat-gas-reporter": "^1.0.9", + "hardhat-ignore-warnings": "^0.2.0", + "keccak256": "^1.0.2", + "lodash.startcase": "^4.4.0", + "lodash.zip": "^4.2.0", + "merkletreejs": "^0.2.13", + "micromatch": "^4.0.2", + "p-limit": "^3.1.0", + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.1.0", + "rimraf": "^5.0.1", + "semver": "^7.3.5", + "solhint": "^3.3.6", + "solhint-plugin-openzeppelin": "file:scripts/solhint-custom", + "solidity-ast": "^0.4.50", + "solidity-coverage": "^0.8.5", + "solidity-docgen": "^0.6.0-beta.29", + "undici": "^5.22.1", + "web3": "^1.3.0", + "yargs": "^17.0.0" + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/remappings.txt b/lib/openzeppelin-contracts-v5.0.0/remappings.txt new file mode 100644 index 0000000..304d138 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/remappings.txt @@ -0,0 +1 @@ +@openzeppelin/contracts/=contracts/ diff --git a/lib/openzeppelin-contracts-v5.0.0/renovate.json b/lib/openzeppelin-contracts-v5.0.0/renovate.json new file mode 100644 index 0000000..c0b97d8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/renovate.json @@ -0,0 +1,4 @@ +{ + "extends": ["github>OpenZeppelin/configs"], + "labels": ["ignore-changeset"] +} diff --git a/lib/openzeppelin-contracts-v5.0.0/requirements.txt b/lib/openzeppelin-contracts-v5.0.0/requirements.txt new file mode 100644 index 0000000..fd0ec30 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/requirements.txt @@ -0,0 +1 @@ +certora-cli==4.8.0 diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/checks/compare-layout.js b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/compare-layout.js new file mode 100644 index 0000000..4368b77 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/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(`Storage layout incompatilibity found in ${name}:`); + console.log(report.explain()); + process.exitCode = 1; + } + } else { + console.log(`WARNING: ${name} is missing from the current branch`); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/checks/compareGasReports.js b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/compareGasReports.js new file mode 100755 index 0000000..160c8cc --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/compareGasReports.js @@ -0,0 +1,243 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const chalk = require('chalk'); +const { argv } = require('yargs') + .env() + .options({ + style: { + type: 'string', + choices: ['shell', 'markdown'], + default: 'shell', + }, + hideEqual: { + type: 'boolean', + default: true, + }, + strictTesting: { + type: 'boolean', + default: false, + }, + }); + +// Deduce base tx cost from the percentage denominator +const BASE_TX_COST = 21000; + +// Utilities +function sum(...args) { + return args.reduce((a, b) => a + b, 0); +} + +function average(...args) { + return sum(...args) / args.length; +} + +function variation(current, previous, offset = 0) { + return { + value: current, + delta: current - previous, + prcnt: (100 * (current - previous)) / (previous - offset), + }; +} + +// Report class +class Report { + // Read report file + static load(filepath) { + return JSON.parse(fs.readFileSync(filepath, 'utf8')); + } + + // Compare two reports + 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'); + } + + const deployments = update.info.deployments + .map(contract => + Object.assign(contract, { previousVersion: ref.info.deployments.find(({ name }) => name === contract.name) }), + ) + .filter(contract => contract.gasData?.length && contract.previousVersion?.gasData?.length) + .flatMap(contract => [ + { + contract: contract.name, + method: '[bytecode length]', + avg: variation(contract.bytecode.length / 2 - 1, contract.previousVersion.bytecode.length / 2 - 1), + }, + { + contract: contract.name, + method: '[construction cost]', + avg: variation( + ...[contract.gasData, contract.previousVersion.gasData].map(x => Math.round(average(...x))), + BASE_TX_COST, + ), + }, + ]) + .sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`)); + + const methods = Object.keys(update.info.methods) + .filter(key => ref.info.methods[key]) + .filter(key => update.info.methods[key].numberOfCalls > 0) + .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, + min: variation(...[update, ref].map(x => Math.min(...x.info.methods[key].gasData)), BASE_TX_COST), + max: variation(...[update, ref].map(x => Math.max(...x.info.methods[key].gasData)), BASE_TX_COST), + avg: variation(...[update, ref].map(x => Math.round(average(...x.info.methods[key].gasData))), BASE_TX_COST), + })) + .sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`)); + + return [] + .concat(deployments, methods) + .filter(row => !opts.hideEqual || row.min?.delta || row.max?.delta || row.avg?.delta); + } +} + +// Display +function center(text, length) { + return text.padStart((text.length + length) / 2).padEnd(length); +} + +function plusSign(num) { + return num > 0 ? '+' : ''; +} + +function formatCellShell(cell) { + const format = chalk[cell?.delta > 0 ? 'red' : cell?.delta < 0 ? 'green' : 'reset']; + return [ + format((!isFinite(cell?.value) ? '-' : cell.value.toString()).padStart(8)), + format((!isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString()).padStart(8)), + format((!isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%').padStart(8)), + ]; +} + +function formatCmpShell(rows) { + const contractLength = Math.max(8, ...rows.map(({ contract }) => contract.length)); + const methodLength = Math.max(7, ...rows.map(({ method }) => method.length)); + + const COLS = [ + { txt: '', length: 0 }, + { txt: 'Contract', length: contractLength }, + { txt: 'Method', length: methodLength }, + { txt: 'Min', length: 30 }, + { txt: 'Max', length: 30 }, + { txt: 'Avg', length: 30 }, + { txt: '', length: 0 }, + ]; + const HEADER = COLS.map(entry => chalk.bold(center(entry.txt, entry.length || 0))) + .join(' | ') + .trim(); + const SEPARATOR = COLS.map(({ length }) => (length > 0 ? '-'.repeat(length + 2) : '')) + .join('|') + .trim(); + + return [ + '', + HEADER, + ...rows.map(entry => + [ + '', + chalk.grey(entry.contract.padEnd(contractLength)), + entry.method.padEnd(methodLength), + ...formatCellShell(entry.min), + ...formatCellShell(entry.max), + ...formatCellShell(entry.avg), + '', + ] + .join(' | ') + .trim(), + ), + '', + ] + .join(`\n${SEPARATOR}\n`) + .trim(); +} + +function alignPattern(align) { + switch (align) { + case 'left': + case undefined: + return ':-'; + case 'right': + return '-:'; + case 'center': + return ':-:'; + } +} + +function trend(value) { + return value > 0 ? ':x:' : value < 0 ? ':heavy_check_mark:' : ':heavy_minus_sign:'; +} + +function formatCellMarkdown(cell) { + return [ + !isFinite(cell?.value) ? '-' : cell.value.toString(), + !isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString(), + !isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%' + trend(cell.delta), + ]; +} + +function formatCmpMarkdown(rows) { + const COLS = [ + { txt: '' }, + { txt: 'Contract', align: 'left' }, + { txt: 'Method', align: 'left' }, + { txt: 'Min', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: 'Max', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: 'Avg', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: '' }, + ]; + const HEADER = COLS.map(entry => entry.txt) + .join(' | ') + .trim(); + const SEPARATOR = COLS.map(entry => (entry.txt ? alignPattern(entry.align) : '')) + .join('|') + .trim(); + + return [ + '# Changes to gas costs', + '', + HEADER, + SEPARATOR, + rows + .map(entry => + [ + '', + entry.contract, + entry.method, + ...formatCellMarkdown(entry.min), + ...formatCellMarkdown(entry.max), + ...formatCellMarkdown(entry.avg), + '', + ] + .join(' | ') + .trim(), + ) + .join('\n'), + '', + ] + .join('\n') + .trim(); +} + +// MAIN +const report = Report.compare(Report.load(argv._[0]), Report.load(argv._[1]), argv); + +switch (argv.style) { + case 'markdown': + console.log(formatCmpMarkdown(report)); + break; + case 'shell': + default: + console.log(formatCmpShell(report)); + break; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/checks/extract-layout.js b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/extract-layout.js new file mode 100644 index 0000000..d0b9965 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/extract-layout.js @@ -0,0 +1,38 @@ +const fs = require('fs'); +const { findAll, astDereferencer, srcDecoder } = require('solidity-ast/utils'); +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 = srcDecoder(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)))); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/checks/generation.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/generation.sh new file mode 100755 index 0000000..00d609f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/generation.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +npm run generate +git diff -R --exit-code diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/checks/inheritance-ordering.js b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/inheritance-ordering.js new file mode 100755 index 0000000..72aa37e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/checks/inheritance-ordering.js @@ -0,0 +1,54 @@ +#!/usr/bin/env node + +const path = require('path'); +const graphlib = require('graphlib'); +const { findAll } = require('solidity-ast/utils'); +const { _: artifacts } = require('yargs').argv; + +for (const artifact of artifacts) { + const { output: solcOutput } = require(path.resolve(__dirname, '../..', artifact)); + + const graph = new graphlib.Graph({ directed: true }); + const names = {}; + const linearized = []; + + for (const source in solcOutput.contracts) { + if (['contracts-exposed/', 'contracts/mocks/'].some(pattern => source.startsWith(pattern))) { + continue; + } + + for (const contractDef of findAll('ContractDefinition', solcOutput.sources[source].ast)) { + names[contractDef.id] = contractDef.name; + linearized.push(contractDef.linearizedBaseContracts); + + contractDef.linearizedBaseContracts.forEach((c1, i, contracts) => + contracts.slice(i + 1).forEach(c2 => { + graph.setEdge(c1, c2); + }), + ); + } + } + + /// graphlib.alg.findCycles will not find minimal cycles. + /// We are only interested int cycles of lengths 2 (needs proof) + graph.nodes().forEach((x, i, nodes) => + nodes + .slice(i + 1) + .filter(y => graph.hasEdge(x, y) && graph.hasEdge(y, x)) + .forEach(y => { + console.log(`Conflict between ${names[x]} and ${names[y]} detected in the following dependency chains:`); + linearized + .filter(chain => chain.includes(parseInt(x)) && chain.includes(parseInt(y))) + .forEach(chain => { + const comp = chain.indexOf(parseInt(x)) < chain.indexOf(parseInt(y)) ? '>' : '<'; + console.log(`- ${names[x]} ${comp} ${names[y]} in ${names[chain.find(Boolean)]}`); + // console.log(`- ${names[x]} ${comp} ${names[y]}: ${chain.reverse().map(id => names[id]).join(', ')}`); + }); + process.exitCode = 1; + }), + ); +} + +if (!process.exitCode) { + console.log('Contract ordering is consistent.'); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/gen-nav.js b/lib/openzeppelin-contracts-v5.0.0/scripts/gen-nav.js new file mode 100644 index 0000000..de3d0da --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/gen-nav.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node + +const path = require('path'); +const glob = require('glob'); +const startCase = require('lodash.startcase'); + +const baseDir = process.argv[2]; + +const files = glob.sync(baseDir + '/**/*.adoc').map(f => path.relative(baseDir, f)); + +console.log('.API'); + +function getPageTitle(directory) { + switch (directory) { + case 'metatx': + return 'Meta Transactions'; + case 'common': + return 'Common (Tokens)'; + default: + return startCase(directory); + } +} + +const links = files.map(file => { + const doc = file.replace(baseDir, ''); + const title = path.parse(file).name; + + return { + xref: `* xref:${doc}[${getPageTitle(title)}]`, + title, + }; +}); + +// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20') +const sortedLinks = links.sort(function (a, b) { + return a.title.toLowerCase().localeCompare(b.title.toLowerCase(), undefined, { numeric: true }); +}); + +for (const link of sortedLinks) { + console.log(link.xref); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/format-lines.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/format-lines.js new file mode 100644 index 0000000..fa3d6b1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/format-lines.js @@ -0,0 +1,16 @@ +function formatLines(...lines) { + return [...indentEach(0, lines)].join('\n') + '\n'; +} + +function* indentEach(indent, lines) { + for (const line of lines) { + if (Array.isArray(line)) { + yield* indentEach(indent + 1, line); + } else { + const padding = ' '.repeat(indent); + yield* line.split('\n').map(subline => (subline === '' ? '' : padding + subline)); + } + } +} + +module.exports = formatLines; diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/run.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/run.js new file mode 100755 index 0000000..5358945 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/run.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node + +const cp = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const format = require('./format-lines'); + +function getVersion(path) { + try { + return fs.readFileSync(path, 'utf8').match(/\/\/ OpenZeppelin Contracts \(last updated v[^)]+\)/)[0]; + } catch (err) { + return null; + } +} + +function generateFromTemplate(file, template, outputPrefix = '') { + const script = path.relative(path.join(__dirname, '../..'), __filename); + const input = path.join(path.dirname(script), template); + const output = path.join(outputPrefix, file); + const version = getVersion(output); + const content = format( + '// SPDX-License-Identifier: MIT', + ...(version ? [version + ` (${file})`] : []), + `// This file was procedurally generated from ${input}.`, + '', + require(template), + ); + + 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/structs/Checkpoints.sol': './templates/Checkpoints.js', + 'utils/StorageSlot.sol': './templates/StorageSlot.js', +})) { + generateFromTemplate(file, template, './contracts/'); +} + +// Tests +for (const [file, template] of Object.entries({ + 'utils/structs/Checkpoints.t.sol': './templates/Checkpoints.t.js', +})) { + generateFromTemplate(file, template, './test/'); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.js new file mode 100644 index 0000000..321a774 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.js @@ -0,0 +1,247 @@ +const format = require('../format-lines'); +const { OPTS } = require('./Checkpoints.opts.js'); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; + +/** + * @dev This library defines the \`Trace*\` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type \`Checkpoints.Trace*\` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + */ +`; + +const errors = `\ + /** + * @dev A value was attempted to be inserted on a past checkpoint. + */ + error CheckpointUnorderedInsertion(); +`; + +const template = opts => `\ +struct ${opts.historyTypeName} { + ${opts.checkpointTypeName}[] ${opts.checkpointFieldName}; +} + +struct ${opts.checkpointTypeName} { + ${opts.keyTypeName} ${opts.keyFieldName}; + ${opts.valueTypeName} ${opts.valueFieldName}; +} + +/** + * @dev Pushes a (\`key\`, \`value\`) pair into a ${opts.historyTypeName} so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept \`key\` as a user input, since an arbitrary \`type(${opts.keyTypeName}).max\` key set will disable the + * library. + */ +function push( + ${opts.historyTypeName} storage self, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) internal returns (${opts.valueTypeName}, ${opts.valueTypeName}) { + return _insert(self.${opts.checkpointFieldName}, key, value); +} + +/** + * @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; + uint256 pos = _lowerBinaryLookup(self.${opts.checkpointFieldName}, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos).${opts.valueFieldName}; +} + +/** + * @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; + 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 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). + */ +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}; +} + +/** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ +function latest(${opts.historyTypeName} storage self) internal view returns (${opts.valueTypeName}) { + uint256 pos = self.${opts.checkpointFieldName}.length; + return pos == 0 ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1).${opts.valueFieldName}; +} + +/** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ +function latestCheckpoint(${opts.historyTypeName} storage self) + internal + view + returns ( + bool exists, + ${opts.keyTypeName} ${opts.keyFieldName}, + ${opts.valueTypeName} ${opts.valueFieldName} + ) +{ + uint256 pos = self.${opts.checkpointFieldName}.length; + if (pos == 0) { + return (false, 0, 0); + } else { + ${opts.checkpointTypeName} memory ckpt = _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1); + return (true, ckpt.${opts.keyFieldName}, ckpt.${opts.valueFieldName}); + } +} + +/** + * @dev Returns the number of checkpoint. + */ +function length(${opts.historyTypeName} storage self) internal view returns (uint256) { + return self.${opts.checkpointFieldName}.length; +} + +/** + * @dev Returns checkpoint at given position. + */ +function at(${opts.historyTypeName} storage self, uint32 pos) internal view returns (${opts.checkpointTypeName} memory) { + return self.${opts.checkpointFieldName}[pos]; +} + +/** + * @dev Pushes a (\`key\`, \`value\`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ +function _insert( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) private returns (${opts.valueTypeName}, ${opts.valueTypeName}) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + ${opts.checkpointTypeName} memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if(last.${opts.keyFieldName} > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last.${opts.keyFieldName} == key) { + _unsafeAccess(self, pos - 1).${opts.valueFieldName} = value; + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + } + return (last.${opts.valueFieldName}, value); + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + return (0, value); + } +} + +/** + * @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. + */ +function _upperBinaryLookup( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + uint256 low, + uint256 high +) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid).${opts.keyFieldName} > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; +} + +/** + * @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. + */ +function _lowerBinaryLookup( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + uint256 low, + uint256 high +) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid).${opts.keyFieldName} < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; +} + +/** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ +function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos) + private + pure + returns (${opts.checkpointTypeName} storage result) +{ + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } +} +`; +/* eslint-enable max-len */ + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library Checkpoints {', + errors, + OPTS.flatMap(opts => template(opts)), + '}', +); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.opts.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.opts.js new file mode 100644 index 0000000..08b7b91 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.opts.js @@ -0,0 +1,17 @@ +// OPTIONS +const VALUE_SIZES = [224, 208, 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 = { + VALUE_SIZES, + OPTS: VALUE_SIZES.map(size => defaultOpts(size)), +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.t.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.t.js new file mode 100644 index 0000000..d21beb5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/Checkpoints.t.js @@ -0,0 +1,146 @@ +const format = require('../format-lines'); +const { capitalize } = require('../../helpers'); +const { OPTS } = require('./Checkpoints.opts.js'); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {SafeCast} from "../../../contracts/utils/math/SafeCast.sol"; +import {Checkpoints} from "../../../contracts/utils/structs/Checkpoints.sol"; +`; + +/* eslint-disable max-len */ +const template = 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); +} + +// 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]; + if (lastKey > 0) { + 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); +} +`; + +// GENERATE +module.exports = format( + header, + ...OPTS.flatMap(opts => [`contract Checkpoints${opts.historyTypeName}Test is Test {`, [template(opts)], '}']), +); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/EnumerableMap.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/EnumerableMap.js new file mode 100644 index 0000000..7dbe6ca --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/EnumerableMap.js @@ -0,0 +1,283 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); + +const TYPES = [ + { name: 'UintToUintMap', keyType: 'uint256', valueType: 'uint256' }, + { name: 'UintToAddressMap', keyType: 'uint256', valueType: 'address' }, + { name: 'AddressToUintMap', keyType: 'address', valueType: 'uint256' }, + { name: 'Bytes32ToUintMap', keyType: 'bytes32', valueType: 'uint256' }, +]; + +/* eslint-disable max-len */ +const header = `\ +pragma solidity ^0.8.20; + +import {EnumerableSet} from "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[\`mapping\`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * \`\`\` + * + * The following map types are supported: + * + * - \`uint256 -> address\` (\`UintToAddressMap\`) since v3.0.0 + * - \`address -> uint256\` (\`AddressToUintMap\`) since v4.6.0 + * - \`bytes32 -> bytes32\` (\`Bytes32ToBytes32Map\`) since v4.6.0 + * - \`uint256 -> uint256\` (\`UintToUintMap\`) since v4.7.0 + * - \`bytes32 -> uint256\` (\`Bytes32ToUintMap\`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +`; +/* eslint-enable max-len */ + +const defaultMap = () => `\ +// To implement this library for multiple types with as little code repetition as possible, we write it in +// terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions, +// and user-facing implementations such as \`UintToAddressMap\` are just wrappers around the underlying Map. +// This means that we can only create new EnumerableMaps for types that fit in bytes32. + +/** + * @dev Query for a nonexistent map key. + */ +error EnumerableMapNonexistentKey(bytes32 key); + +struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 key => bytes32) _values; +} + +/** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ +function set( + Bytes32ToBytes32Map storage map, + bytes32 key, + bytes32 value +) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); +} + +/** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ +function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); +} + +/** + * @dev Returns the number of key-value pairs in the map. O(1). + */ +function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); +} + +/** + * @dev Returns the key-value pair stored at position \`index\` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); +} + +/** + * @dev Tries to returns the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + if(value == 0 && !contains(map, key)) { + revert EnumerableMapNonexistentKey(key); + } + return value; +} + +/** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { + return map._keys.values(); +} +`; + +const customMap = ({ name, keyType, valueType }) => `\ +// ${name} + +struct ${name} { + Bytes32ToBytes32Map _inner; +} + +/** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ +function set( + ${name} storage map, + ${keyType} key, + ${valueType} value +) internal returns (bool) { + return set(map._inner, ${toBytes32(keyType, 'key')}, ${toBytes32(valueType, 'value')}); +} + +/** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ +function remove(${name} storage map, ${keyType} key) internal returns (bool) { + return remove(map._inner, ${toBytes32(keyType, 'key')}); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(${name} storage map, ${keyType} key) internal view returns (bool) { + return contains(map._inner, ${toBytes32(keyType, 'key')}); +} + +/** + * @dev Returns the number of elements in the map. O(1). + */ +function length(${name} storage map) internal view returns (uint256) { + return length(map._inner); +} + +/** + * @dev Returns the element stored at position \`index\` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(${name} storage map, uint256 index) internal view returns (${keyType}, ${valueType}) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (${fromBytes32(keyType, 'key')}, ${fromBytes32(valueType, 'value')}); +} + +/** + * @dev Tries to returns the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(${name} storage map, ${keyType} key) internal view returns (bool, ${valueType}) { + (bool success, bytes32 value) = tryGet(map._inner, ${toBytes32(keyType, 'key')}); + return (success, ${fromBytes32(valueType, 'value')}); +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(${name} storage map, ${keyType} key) internal view returns (${valueType}) { + return ${fromBytes32(valueType, `get(map._inner, ${toBytes32(keyType, 'key')})`)}; +} + +/** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function keys(${name} storage map) internal view returns (${keyType}[] memory) { + bytes32[] memory store = keys(map._inner); + ${keyType}[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableMap {', + [ + 'using EnumerableSet for EnumerableSet.Bytes32Set;', + '', + defaultMap(), + TYPES.map(details => customMap(details).trimEnd()).join('\n\n'), + ], + '}', +); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/EnumerableSet.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/EnumerableSet.js new file mode 100644 index 0000000..cb9bffb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/EnumerableSet.js @@ -0,0 +1,250 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); + +const TYPES = [ + { name: 'Bytes32Set', type: 'bytes32' }, + { name: 'AddressSet', type: 'address' }, + { name: 'UintSet', type: 'uint256' }, +]; + +/* eslint-disable max-len */ +const header = `\ +pragma solidity ^0.8.20; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * \`\`\` + * + * As of v3.3.0, sets of type \`bytes32\` (\`Bytes32Set\`), \`address\` (\`AddressSet\`) + * and \`uint256\` (\`UintSet\`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +`; +/* eslint-enable max-len */ + +const defaultSet = () => `\ +// To implement this library for multiple types with as little code +// repetition as possible, we write it in terms of a generic Set type with +// bytes32 values. +// The Set implementation uses private functions, and user-facing +// implementations (such as AddressSet) are just wrappers around the +// underlying Set. +// This means that we can only create new EnumerableSets for types that fit +// in bytes32. + +struct Set { + // Storage of set values + bytes32[] _values; + // Position is the index of the value in the \`values\` array plus 1. + // Position 0 is used to mean a value is not in the set. + mapping(bytes32 value => uint256) _positions; +} + +/** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ +function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._positions[value] = set._values.length; + return true; + } else { + return false; + } +} + +/** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ +function _remove(Set storage set, bytes32 value) private returns (bool) { + // We cache the value's position to prevent multiple reads from the same storage slot + uint256 position = set._positions[value]; + + if (position != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 valueIndex = position - 1; + uint256 lastIndex = set._values.length - 1; + + if (valueIndex != lastIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the lastValue to the index where the value to delete is + set._values[valueIndex] = lastValue; + // Update the tracked position of the lastValue (that was just moved) + set._positions[lastValue] = position; + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the tracked position for the deleted slot + delete set._positions[value]; + + return true; + } else { + return false; + } +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._positions[value] != 0; +} + +/** + * @dev Returns the number of values on the set. O(1). + */ +function _length(Set storage set) private view returns (uint256) { + return set._values.length; +} + +/** + * @dev Returns the value stored at position \`index\` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; +} + +/** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; +} +`; + +const customSet = ({ name, type }) => `\ +// ${name} + +struct ${name} { + Set _inner; +} + +/** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ +function add(${name} storage set, ${type} value) internal returns (bool) { + return _add(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ +function remove(${name} storage set, ${type} value) internal returns (bool) { + return _remove(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function contains(${name} storage set, ${type} value) internal view returns (bool) { + return _contains(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Returns the number of values in the set. O(1). + */ +function length(${name} storage set) internal view returns (uint256) { + return _length(set._inner); +} + +/** + * @dev Returns the value stored at position \`index\` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(${name} storage set, uint256 index) internal view returns (${type}) { + return ${fromBytes32(type, '_at(set._inner, index)')}; +} + +/** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function values(${name} storage set) internal view returns (${type}[] memory) { + bytes32[] memory store = _values(set._inner); + ${type}[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableSet {', + [defaultSet(), TYPES.map(details => customSet(details).trimEnd()).join('\n\n')], + '}', +); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/SafeCast.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/SafeCast.js new file mode 100644 index 0000000..f1954a7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/SafeCast.js @@ -0,0 +1,126 @@ +const format = require('../format-lines'); +const { range } = require('../../helpers'); + +const LENGTHS = range(8, 256, 8).reverse(); // 248 → 8 (in steps of 8) + +const header = `\ +pragma solidity ^0.8.20; + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. \`SafeCast\` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +`; + +const errors = `\ + /** + * @dev Value doesn't fit in an uint of \`bits\` size. + */ + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + + /** + * @dev An int value doesn't fit in an uint of \`bits\` size. + */ + error SafeCastOverflowedIntToUint(int256 value); + + /** + * @dev Value doesn't fit in an int of \`bits\` size. + */ + error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); + + /** + * @dev An uint value doesn't fit in an int of \`bits\` size. + */ + error SafeCastOverflowedUintToInt(uint256 value); +`; + +const toUintDownCast = length => `\ +/** + * @dev Returns the downcasted uint${length} from uint256, reverting on + * overflow (when the input is greater than largest uint${length}). + * + * Counterpart to Solidity's \`uint${length}\` operator. + * + * Requirements: + * + * - input must fit into ${length} bits + */ +function toUint${length}(uint256 value) internal pure returns (uint${length}) { + if (value > type(uint${length}).max) { + revert SafeCastOverflowedUintDowncast(${length}, value); + } + return uint${length}(value); +} +`; + +/* eslint-disable max-len */ +const toIntDownCast = length => `\ +/** + * @dev Returns the downcasted int${length} from int256, reverting on + * overflow (when the input is less than smallest int${length} or + * greater than largest int${length}). + * + * Counterpart to Solidity's \`int${length}\` operator. + * + * Requirements: + * + * - input must fit into ${length} bits + */ +function toInt${length}(int256 value) internal pure returns (int${length} downcasted) { + downcasted = int${length}(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(${length}, value); + } +} +`; +/* eslint-enable max-len */ + +const toInt = length => `\ +/** + * @dev Converts an unsigned uint${length} into a signed int${length}. + * + * Requirements: + * + * - input must be less than or equal to maxInt${length}. + */ +function toInt${length}(uint${length} value) internal pure returns (int${length}) { + // Note: Unsafe cast below is okay because \`type(int${length}).max\` is guaranteed to be positive + if (value > uint${length}(type(int${length}).max)) { + revert SafeCastOverflowedUintToInt(value); + } + return int${length}(value); +} +`; + +const toUint = length => `\ +/** + * @dev Converts a signed int${length} into an unsigned uint${length}. + * + * Requirements: + * + * - input must be greater than or equal to 0. + */ +function toUint${length}(int${length} value) internal pure returns (uint${length}) { + if (value < 0) { + revert SafeCastOverflowedIntToUint(value); + } + return uint${length}(value); +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library SafeCast {', + errors, + [...LENGTHS.map(toUintDownCast), toUint(256), ...LENGTHS.map(toIntDownCast), toInt(256)], + '}', +); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/StorageSlot.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/StorageSlot.js new file mode 100644 index 0000000..1c90b5e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/StorageSlot.js @@ -0,0 +1,78 @@ +const format = require('../format-lines'); +const { capitalize } = require('../../helpers'); + +const TYPES = [ + { type: 'address', isValueType: true }, + { type: 'bool', isValueType: true, name: 'Boolean' }, + { type: 'bytes32', isValueType: true }, + { type: 'uint256', isValueType: true }, + { type: 'string', isValueType: false }, + { type: 'bytes', isValueType: false }, +].map(type => Object.assign(type, { struct: (type.name ?? capitalize(type.type)) + 'Slot' })); + +const header = `\ +pragma solidity ^0.8.20; + +/** + * @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(newImplementation.code.length > 0); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * \`\`\` + */ +`; + +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/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/conversion.js b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/conversion.js new file mode 100644 index 0000000..9221f7c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/generate/templates/conversion.js @@ -0,0 +1,30 @@ +function toBytes32(type, value) { + switch (type) { + case 'bytes32': + return value; + case 'uint256': + return `bytes32(${value})`; + case 'address': + return `bytes32(uint256(uint160(${value})))`; + default: + throw new Error(`Conversion from ${type} to bytes32 not supported`); + } +} + +function fromBytes32(type, value) { + switch (type) { + case 'bytes32': + return value; + case 'uint256': + return `uint256(${value})`; + case 'address': + return `address(uint160(uint256(${value})))`; + default: + throw new Error(`Conversion from bytes32 to ${type} not supported`); + } +} + +module.exports = { + toBytes32, + fromBytes32, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/git-user-config.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/git-user-config.sh new file mode 100644 index 0000000..e7b81c3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/git-user-config.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail -x + +git config user.name 'github-actions' +git config user.email '41898282+github-actions[bot]@users.noreply.github.com' diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/helpers.js b/lib/openzeppelin-contracts-v5.0.0/scripts/helpers.js new file mode 100644 index 0000000..fb9aad4 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/helpers.js @@ -0,0 +1,37 @@ +function chunk(array, size = 1) { + return Array.range(Math.ceil(array.length / size)).map(i => array.slice(i * size, i * size + size)); +} + +function range(start, stop = undefined, step = 1) { + if (!stop) { + stop = start; + start = 0; + } + return start < stop + ? Array(Math.ceil((stop - start) / step)) + .fill() + .map((_, i) => start + i * step) + : []; +} + +function unique(array, op = x => x) { + return array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i); +} + +function zip(...args) { + return Array(Math.max(...args.map(arg => arg.length))) + .fill(null) + .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/lib/openzeppelin-contracts-v5.0.0/scripts/prepack.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/prepack.sh new file mode 100755 index 0000000..6af1032 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/prepack.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -euo pipefail +shopt -s globstar + +# cross platform `mkdir -p` +mkdirp() { + node -e "fs.mkdirSync('$1', { recursive: true })" +} + +# cd to the root of the repo +cd "$(git rev-parse --show-toplevel)" + +npm run clean + +env COMPILE_MODE=production npm run compile + +mkdirp contracts/build/contracts +cp artifacts/contracts/**/*.json contracts/build/contracts +rm contracts/build/contracts/*.dbg.json +node scripts/remove-ignored-artifacts.js + +cp README.md contracts/ diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/prepare-docs.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/prepare-docs.sh new file mode 100755 index 0000000..d1317b0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/prepare-docs.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail +shopt -s globstar + +OUTDIR="$(node -p 'require("./docs/config.js").outputDir')" + +if [ ! -d node_modules ]; then + npm ci +fi + +rm -rf "$OUTDIR" + +hardhat docgen + +# copy examples and adjust imports +examples_source_dir="contracts/mocks/docs" +examples_target_dir="docs/modules/api/examples" + +for f in "$examples_source_dir"/**/*.sol; do + name="${f/#"$examples_source_dir/"/}" + mkdir -p "$examples_target_dir/$(dirname "$name")" + sed -Ee '/^import/s|"(\.\./)+|"@openzeppelin/contracts/|' "$f" > "$examples_target_dir/$name" +done + +node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc" diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/format-changelog.js b/lib/openzeppelin-contracts-v5.0.0/scripts/release/format-changelog.js new file mode 100755 index 0000000..b8bcc8c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/format-changelog.js @@ -0,0 +1,33 @@ +#!/usr/bin/env node + +// Adjusts the format of the changelog that changesets generates. +// This is run automatically when npm version is run. + +const fs = require('fs'); +const changelog = fs.readFileSync('CHANGELOG.md', 'utf8'); + +// Groups: +// - 1: Pull Request Number and URL +// - 2: Changeset entry +const RELEASE_LINE_REGEX = /^- (\[#.*?\]\(.*?\))?.*?! - (.*)$/gm; + +// Captures vX.Y.Z or vX.Y.Z-rc.W +const VERSION_TITLE_REGEX = /^## (\d+\.\d+\.\d+(-rc\.\d+)?)$/gm; + +const isPrerelease = process.env.PRERELEASE === 'true'; + +const formatted = changelog + // Remove titles + .replace(/^### Major Changes\n\n/gm, '') + .replace(/^### Minor Changes\n\n/gm, '') + .replace(/^### Patch Changes\n\n/gm, '') + // Remove extra whitespace between items + .replace(/^(- \[.*\n)\n(?=-)/gm, '$1') + // Format each release line + .replace(RELEASE_LINE_REGEX, (_, pr, entry) => (pr ? `- ${entry} (${pr})` : `- ${entry}`)) + // Add date to new version + .replace(VERSION_TITLE_REGEX, `\n## $1 (${new Date().toISOString().split('T')[0]})`) + // Conditionally allow vX.Y.Z.rc-.W sections only in prerelease + .replace(/^## \d\.\d\.\d-rc\S+[^]+?(?=^#)/gm, section => (isPrerelease ? section : '')); + +fs.writeFileSync('CHANGELOG.md', formatted); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/synchronize-versions.js b/lib/openzeppelin-contracts-v5.0.0/scripts/release/synchronize-versions.js new file mode 100755 index 0000000..15aa259 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/synchronize-versions.js @@ -0,0 +1,15 @@ +#!/usr/bin/env node + +// Synchronizes the version in contracts/package.json with the one in package.json. +// This is run automatically when npm version is run. + +const fs = require('fs'); + +setVersion('package.json', 'contracts/package.json'); + +function setVersion(from, to) { + const fromJson = JSON.parse(fs.readFileSync(from)); + const toJson = JSON.parse(fs.readFileSync(to)); + toJson.version = fromJson.version; + fs.writeFileSync(to, JSON.stringify(toJson, null, 2) + '\n'); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/update-comment.js b/lib/openzeppelin-contracts-v5.0.0/scripts/release/update-comment.js new file mode 100755 index 0000000..9d6df26 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/update-comment.js @@ -0,0 +1,34 @@ +#!/usr/bin/env node +const fs = require('fs'); +const proc = require('child_process'); +const semver = require('semver'); +const run = (cmd, ...args) => proc.execFileSync(cmd, args, { encoding: 'utf8' }).trim(); + +const gitStatus = run('git', 'status', '--porcelain', '-uno', 'contracts/**/*.sol'); +if (gitStatus.length > 0) { + console.error('Contracts directory is not clean'); + process.exit(1); +} + +const { version } = require('../../package.json'); + +// Get latest tag according to semver. +const [tag] = run('git', 'tag') + .split(/\r?\n/) + .filter(semver.coerce) // check version can be processed + .filter(v => semver.satisfies(v, `< ${version}`)) // ignores prereleases unless currently a prerelease + .sort(semver.rcompare); + +// Ordering tag → HEAD is important here. +const files = run('git', 'diff', tag, 'HEAD', '--name-only', 'contracts/**/*.sol') + .split(/\r?\n/) + .filter(file => file && !file.match(/mock/i) && fs.existsSync(file)); + +for (const file of files) { + const current = fs.readFileSync(file, 'utf8'); + const updated = current.replace( + /(\/\/ SPDX-License-Identifier:.*)$(\n\/\/ OpenZeppelin Contracts .*$)?/m, + `$1\n// OpenZeppelin Contracts (last updated v${version}) (${file.replace('contracts/', '')})`, + ); + fs.writeFileSync(file, updated); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/version.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/release/version.sh new file mode 100755 index 0000000..7b0ddea --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/version.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euo pipefail + +changeset version + +scripts/release/format-changelog.js +scripts/release/synchronize-versions.js +scripts/release/update-comment.js + +oz-docs update-version diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/exit-prerelease.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/exit-prerelease.sh new file mode 100644 index 0000000..bcf9b9a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/exit-prerelease.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +npx changeset pre exit rc +git add . +git commit -m "Exit release candidate" +git push origin diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/github-release.js b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/github-release.js new file mode 100644 index 0000000..f213106 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/github-release.js @@ -0,0 +1,48 @@ +const { readFileSync } = require('fs'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ github, context }) => { + const changelog = readFileSync('CHANGELOG.md', 'utf8'); + + await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `v${version}`, + target_commitish: github.ref_name, + body: extractSection(changelog, version), + prerelease: process.env.PRERELEASE === 'true', + }); +}; + +// From https://github.com/frangio/extract-changelog/blob/master/src/utils/word-regexp.ts +function makeWordRegExp(word) { + const start = word.length > 0 && /\b/.test(word[0]) ? '\\b' : ''; + const end = word.length > 0 && /\b/.test(word[word.length - 1]) ? '\\b' : ''; + return new RegExp(start + [...word].map(c => (/[a-z0-9]/i.test(c) ? c : '\\' + c)).join('') + end); +} + +// From https://github.com/frangio/extract-changelog/blob/master/src/core.ts +function extractSection(document, wantedHeading) { + // ATX Headings as defined in GitHub Flavored Markdown (https://github.github.com/gfm/#atx-headings) + const heading = /^ {0,3}(?#{1,6})(?: [ \t\v\f]*(?.*?)[ \t\v\f]*)?(?:[\n\r]+|$)/gm; + + const wantedHeadingRe = makeWordRegExp(wantedHeading); + + let start, end; + + for (const m of document.matchAll(heading)) { + if (!start) { + if (m.groups.text.search(wantedHeadingRe) === 0) { + start = m; + } + } else if (m.groups.lead.length <= start.groups.lead.length) { + end = m; + break; + } + } + + if (start) { + return document.slice(start.index + start[0].length, end?.index); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/integrity-check.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/integrity-check.sh new file mode 100644 index 0000000..86e99f9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/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/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/pack.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/pack.sh new file mode 100644 index 0000000..ce30712 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/pack.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +dist_tag() { + PACKAGE_JSON_NAME="$(jq -r .name ./package.json)" + LATEST_NPM_VERSION="$(npm info "$PACKAGE_JSON_NAME" version)" + PACKAGE_JSON_VERSION="$(jq -r .version ./package.json)" + + if [ "$PRERELEASE" = "true" ]; then + echo "next" + elif npx semver -r ">$LATEST_NPM_VERSION" "$PACKAGE_JSON_VERSION" > /dev/null; then + echo "latest" + else + # This is a patch for an older version + # npm can't publish without a tag + echo "tmp" + fi +} + +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/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/publish.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/publish.sh new file mode 100644 index 0000000..e490e5d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/publish.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +PACKAGE_JSON_NAME="$(tar xfO "$TARBALL" package/package.json | jq -r .name)" +PACKAGE_JSON_VERSION="$(tar xfO "$TARBALL" package/package.json | jq -r .version)" + +# Intentionally escape $ to avoid interpolation and writing the token to disk +echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > .npmrc + +# Actual publish +npm publish "$TARBALL" --tag "$TAG" + +# Clean up tags +delete_tag() { + npm dist-tag rm "$PACKAGE_JSON_NAME" "$1" +} + +if [ "$TAG" = tmp ]; then + delete_tag "$TAG" +elif [ "$TAG" = latest ]; then + # Delete the next tag if it exists and is a prerelease for what is currently being published + if npm dist-tag ls "$PACKAGE_JSON_NAME" | grep -q "next: $PACKAGE_JSON_VERSION"; then + delete_tag next + fi +fi diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/rerun.js b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/rerun.js new file mode 100644 index 0000000..f48ce6e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/rerun.js @@ -0,0 +1,7 @@ +module.exports = ({ github, context }) => + github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release-cycle.yml', + ref: process.env.REF || process.env.GITHUB_REF_NAME, + }); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/set-changesets-pr-title.js b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/set-changesets-pr-title.js new file mode 100644 index 0000000..59b03b2 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/set-changesets-pr-title.js @@ -0,0 +1,17 @@ +const { coerce, inc, rsort } = require('semver'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ core }) => { + // Variables not in the context + const refName = process.env.GITHUB_REF_NAME; + + // Compare package.json version's next patch vs. first version patch + // A recently opened branch will give the next patch for the previous minor + // So, we get the max against the patch 0 of the release branch's version + const branchPatch0 = coerce(refName.replace('release-v', '')).version; + const packageJsonNextPatch = inc(version, 'patch'); + const [nextVersion] = rsort([branchPatch0, packageJsonNextPatch], false); + + core.exportVariable('TITLE', `Release v${nextVersion}`); +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/start.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/start.sh new file mode 100644 index 0000000..7683ec5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/start.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Set changeset status location +# This is needed because `changeset status --output` only works with relative routes +CHANGESETS_STATUS_JSON="$(realpath --relative-to=. "$RUNNER_TEMP/status.json")" + +# Save changeset status to temp file +npx changeset status --output="$CHANGESETS_STATUS_JSON" + +# Defensive assertion. SHOULD NOT BE REACHED +if [ "$(jq '.releases | length' "$CHANGESETS_STATUS_JSON")" != 1 ]; then + echo "::error file=$CHANGESETS_STATUS_JSON::The status doesn't contain only 1 release" + exit 1; +fi; + +# Create branch +BRANCH_SUFFIX="$(jq -r '.releases[0].newVersion | gsub("\\.\\d+$"; "")' $CHANGESETS_STATUS_JSON)" +RELEASE_BRANCH="release-v$BRANCH_SUFFIX" +git checkout -b "$RELEASE_BRANCH" + +# Output branch +echo "branch=$RELEASE_BRANCH" >> $GITHUB_OUTPUT + +# Enter in prerelease state +npx changeset pre enter rc +git add . +git commit -m "Start release candidate" + +# Push 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 diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/state.js b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/state.js new file mode 100644 index 0000000..914e8de --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/release/workflow/state.js @@ -0,0 +1,112 @@ +const { readPreState } = require('@changesets/pre'); +const { default: readChangesets } = require('@changesets/read'); +const { join } = require('path'); +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 }); + + function setOutput(key, value) { + core.info(`State ${key} = ${value}`); + core.setOutput(key, value); + } + + // Jobs to trigger + setOutput('start', shouldRunStart(state)); + setOutput('promote', shouldRunPromote(state)); + setOutput('changesets', shouldRunChangesets(state)); + setOutput('publish', shouldRunPublish(state)); + setOutput('merge', shouldRunMerge(state)); + + // Global Variables + setOutput('is_prerelease', state.prerelease); +}; + +function shouldRunStart({ isMaster, isWorkflowDispatch, botRun }) { + return isMaster && isWorkflowDispatch && !botRun; +} + +function shouldRunPromote({ isReleaseBranch, isWorkflowDispatch, botRun }) { + return isReleaseBranch && isWorkflowDispatch && !botRun; +} + +function shouldRunChangesets({ isReleaseBranch, isPush, isWorkflowDispatch, botRun }) { + return (isReleaseBranch && isPush) || (isReleaseBranch && isWorkflowDispatch && botRun); +} + +function shouldRunPublish({ isReleaseBranch, isPush, hasPendingChangesets, isPublishedOnNpm }) { + return isReleaseBranch && isPush && !hasPendingChangesets && !isPublishedOnNpm; +} + +function shouldRunMerge({ + isReleaseBranch, + isPush, + prerelease, + isCurrentFinalVersion, + hasPendingChangesets, + prBackExists, +}) { + return isReleaseBranch && isPush && !prerelease && isCurrentFinalVersion && !hasPendingChangesets && !prBackExists; +} + +async function getState({ github, context, core }) { + // Variables not in the context + const refName = process.env.GITHUB_REF_NAME; + const botRun = process.env.TRIGGERING_ACTOR === 'github-actions[bot]'; + + const { changesets, preState } = await readChangesetState(); + + // Static vars + const state = { + refName, + hasPendingChangesets: changesets.length > 0, + prerelease: preState?.mode === 'pre', + isMaster: refName === 'master', + isReleaseBranch: refName.startsWith('release-v'), + isWorkflowDispatch: context.eventName === 'workflow_dispatch', + isPush: context.eventName === 'push', + isCurrentFinalVersion: !version.includes('-rc.'), + botRun, + }; + + // Async vars + const { data: prs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: `${context.repo.owner}:merge/${state.refName}`, + base: 'master', + state: 'open', + }); + + 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}`); + + return state; +} + +// From https://github.com/changesets/action/blob/v1.4.1/src/readChangesetState.ts +async function readChangesetState(cwd = process.cwd()) { + const preState = await readPreState(cwd); + const isInPreMode = preState !== undefined && preState.mode === 'pre'; + + let changesets = await readChangesets(cwd); + + if (isInPreMode) { + changesets = changesets.filter(x => !preState.changesets.includes(x.id)); + } + + return { + preState: isInPreMode ? preState : undefined, + changesets, + }; +} + +async function isPublishedOnNpm(package, version) { + const res = await fetch(`https://registry.npmjs.com/${package}/${version}`); + return res.ok; +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/remove-ignored-artifacts.js b/lib/openzeppelin-contracts-v5.0.0/scripts/remove-ignored-artifacts.js new file mode 100644 index 0000000..e156032 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/remove-ignored-artifacts.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node + +// This script removes the build artifacts of ignored contracts. + +const fs = require('fs'); +const path = require('path'); +const match = require('micromatch'); + +function readJSON(path) { + return JSON.parse(fs.readFileSync(path)); +} + +const pkgFiles = readJSON('package.json').files; + +// Get only negated patterns. +const ignorePatterns = pkgFiles + .filter(pat => pat.startsWith('!')) + // Remove the negation part. Makes micromatch usage more intuitive. + .map(pat => pat.slice(1)); + +const ignorePatternsSubtrees = ignorePatterns + // Add **/* to ignore all files contained in the directories. + .concat(ignorePatterns.map(pat => path.join(pat, '**/*'))) + .map(p => p.replace(/^\//, '')); + +const artifactsDir = 'contracts/build/contracts'; +const buildinfo = 'artifacts/build-info'; +const filenames = fs.readdirSync(buildinfo); + +let n = 0; + +for (const filename of filenames) { + const solcOutput = readJSON(path.join(buildinfo, filename)).output; + for (const sourcePath in solcOutput.contracts) { + const ignore = match.any(sourcePath, ignorePatternsSubtrees); + if (ignore) { + for (const contract in solcOutput.contracts[sourcePath]) { + fs.unlinkSync(path.join(artifactsDir, contract + '.json')); + n += 1; + } + } + } +} + +console.error(`Removed ${n} mock artifacts`); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/solhint-custom/index.js b/lib/openzeppelin-contracts-v5.0.0/scripts/solhint-custom/index.js new file mode 100644 index 0000000..9625027 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/solhint-custom/index.js @@ -0,0 +1,84 @@ +const path = require('path'); +const minimatch = require('minimatch'); + +// Files matching these patterns will be ignored unless a rule has `static global = true` +const ignore = ['contracts/mocks/**/*', 'test/**/*']; + +class Base { + constructor(reporter, config, source, fileName) { + this.reporter = reporter; + this.ignored = this.constructor.global || ignore.some(p => minimatch(path.normalize(fileName), p)); + this.ruleId = this.constructor.ruleId; + if (this.ruleId === undefined) { + throw Error('missing ruleId static property'); + } + } + + error(node, message) { + if (!this.ignored) { + this.reporter.error(node, this.ruleId, message); + } + } +} + +module.exports = [ + class extends Base { + static ruleId = 'interface-names'; + + ContractDefinition(node) { + if (node.kind === 'interface' && !/^I[A-Z]/.test(node.name)) { + this.error(node, 'Interface names should have a capital I prefix'); + } + } + }, + + class extends Base { + static ruleId = 'private-variables'; + + VariableDeclaration(node) { + const constantOrImmutable = node.isDeclaredConst || node.isImmutable; + if (node.isStateVar && !constantOrImmutable && node.visibility !== 'private') { + this.error(node, 'State variables must be private'); + } + } + }, + + class extends Base { + static ruleId = 'leading-underscore'; + + VariableDeclaration(node) { + if (node.isDeclaredConst) { + // TODO: expand visibility and fix + if (node.visibility === 'private' && /^_/.test(node.name)) { + this.error(node, 'Constant variables should not have leading underscore'); + } + } else if (node.visibility === 'private' && !/^_/.test(node.name)) { + this.error(node, 'Non-constant private variables must have leading underscore'); + } + } + + FunctionDefinition(node) { + if (node.visibility === 'private' || (node.visibility === 'internal' && node.parent.kind !== 'library')) { + if (!/^_/.test(node.name)) { + this.error(node, 'Private and internal functions must have leading underscore'); + } + } + if (node.visibility === 'internal' && node.parent.kind === 'library') { + if (/^_/.test(node.name)) { + this.error(node, 'Library internal functions should not have leading underscore'); + } + } + } + }, + + // TODO: re-enable and fix + // class extends Base { + // static ruleId = 'no-external-virtual'; + // + // FunctionDefinition(node) { + // if (node.visibility == 'external' && node.isVirtual) { + // this.error(node, 'Functions should not be external and virtual'); + // } + // } + // }, +]; diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/solhint-custom/package.json b/lib/openzeppelin-contracts-v5.0.0/scripts/solhint-custom/package.json new file mode 100644 index 0000000..075eb92 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/solhint-custom/package.json @@ -0,0 +1,5 @@ +{ + "name": "solhint-plugin-openzeppelin", + "version": "0.0.0", + "private": true +} diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/update-docs-branch.js b/lib/openzeppelin-contracts-v5.0.0/scripts/update-docs-branch.js new file mode 100644 index 0000000..324ba0c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/update-docs-branch.js @@ -0,0 +1,65 @@ +const proc = require('child_process'); +const read = cmd => proc.execSync(cmd, { encoding: 'utf8' }).trim(); +const run = cmd => { + proc.execSync(cmd, { stdio: 'inherit' }); +}; +const tryRead = cmd => { + try { + return read(cmd); + } catch (e) { + return undefined; + } +}; + +const releaseBranchRegex = /^release-v(?(?\d+)\.(?\d+)(?:\.(?\d+))?)$/; + +const currentBranch = read('git rev-parse --abbrev-ref HEAD'); +const match = currentBranch.match(releaseBranchRegex); + +if (!match) { + console.error('Not currently on a release branch'); + process.exit(1); +} + +const pkgVersion = require('../package.json').version; + +if (pkgVersion.includes('-') && !pkgVersion.includes('.0.0-')) { + console.error('Refusing to update docs: non-major prerelease detected'); + process.exit(0); +} + +const current = match.groups; +const docsBranch = `docs-v${current.major}.x`; + +// Fetch remotes and find the docs branch if it exists +run('git fetch --all --no-tags'); +const matchingDocsBranches = tryRead(`git rev-parse --glob='*/${docsBranch}'`); + +if (!matchingDocsBranches) { + // Create the branch + run(`git checkout --orphan ${docsBranch}`); +} else { + const [publishedRef, ...others] = new Set(matchingDocsBranches.split('\n')); + if (others.length > 0) { + console.error( + `Found conflicting ${docsBranch} branches.\n` + + 'Either local branch is outdated or there are multiple matching remote branches.', + ); + process.exit(1); + } + const publishedVersion = JSON.parse(read(`git show ${publishedRef}:package.json`)).version; + const publishedMinor = publishedVersion.match(/\d+\.(?\d+)\.\d+/).groups.minor; + if (current.minor < publishedMinor) { + console.error('Refusing to update docs: newer version is published'); + process.exit(0); + } + + run('git checkout --quiet --detach'); + run(`git reset --soft ${publishedRef}`); + run(`git checkout ${docsBranch}`); +} + +run('npm run prepare-docs'); +run('git add -f docs'); // --force needed because generated docs files are gitignored +run('git commit -m "Update docs"'); +run(`git checkout ${currentBranch}`); diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/README.md b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/README.md new file mode 100644 index 0000000..2309f9e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/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/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/patch-apply.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/patch-apply.sh new file mode 100755 index 0000000..d9e1758 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/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/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/patch-save.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/patch-save.sh new file mode 100755 index 0000000..111e6f1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/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/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/transpile-onto.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/transpile-onto.sh new file mode 100644 index 0000000..b8508f0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/transpile-onto.sh @@ -0,0 +1,54 @@ +#!/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)" +start_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 + +# abort if there are no changes to commit at this point +if git diff --quiet --cached; then + exit +fi + +if [[ -v SUBMODULE_REMOTE ]]; then + lib=lib/openzeppelin-contracts + git submodule add -b "${base#origin/}" "$SUBMODULE_REMOTE" "$lib" + git -C "$lib" checkout "$commit" + git add "$lib" +fi + +git commit -m "Transpile $commit" + +# return to original branch +git checkout "$start_branch" diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/transpile.sh b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/transpile.sh new file mode 100644 index 0000000..ebc8c32 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/transpile.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -euo pipefail -x + +VERSION="$(jq -r .version contracts/package.json)" +DIRNAME="$(dirname -- "${BASH_SOURCE[0]}")" + +bash "$DIRNAME/patch-apply.sh" +sed -i'' -e "s//$VERSION/g" "contracts/package.json" +git add contracts/package.json + +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 +# -n: use namespaces +# -N: exclude from namespaces transformation +# -q: partial transpilation using @openzeppelin/contracts as peer project +npx @openzeppelin/upgrade-safe-transpiler -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/ERC1967Utils.sol' \ + -x '!contracts/proxy/utils/UUPSUpgradeable.sol' \ + -x '!contracts/proxy/beacon/IBeacon.sol' \ + -p 'contracts/**/presets/**/*' \ + -n \ + -N 'contracts/mocks/**/*' \ + -q '@openzeppelin/' + +# delete compilation artifacts of vanilla code +npm run clean diff --git a/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/upgradeable.patch b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/upgradeable.patch new file mode 100644 index 0000000..522f82c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/scripts/upgradeable/upgradeable.patch @@ -0,0 +1,360 @@ +diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md +deleted file mode 100644 +index 2797a0889..000000000 +--- 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 4018cef29..d343a53d8 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 ff596b0c3..000000000 +--- 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 549891e3f..a6b24078e 100644 +--- a/README.md ++++ b/README.md +@@ -23,6 +23,9 @@ + > [!IMPORTANT] + > OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, for example, it is unsafe to upgrade from 4.9.3 to 5.0.0. Learn more at [Backwards Compatibility](https://docs.openzeppelin.com/contracts/backwards-compatibility). + +++> [!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/upgradeable). +++ + ## Overview + + ### Installation +@@ -30,7 +33,7 @@ + #### Hardhat, Truffle (npm) + + ``` +-$ npm install @openzeppelin/contracts ++$ npm install @openzeppelin/contracts-upgradeable + ``` + + #### Foundry (git) +@@ -42,10 +45,10 @@ $ npm install @openzeppelin/contracts + > Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch. + + ``` +-$ forge install OpenZeppelin/openzeppelin-contracts ++$ forge install OpenZeppelin/openzeppelin-contracts-upgradeable + ``` + +-Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.` ++Add `@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/` in `remappings.txt.` + + ### Usage + +@@ -54,10 +57,11 @@ Once installed, you can use the contracts in the library by importing them: + ```solidity + pragma solidity ^0.8.20; + +-import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; ++import {ERC721Upgradeable} from "@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/package.json b/contracts/package.json +index 9017953ca..f51c1d38b 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.9.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", +@@ -28,5 +28,8 @@ + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, +- "homepage": "https://openzeppelin.com/contracts/" ++ "homepage": "https://openzeppelin.com/contracts/", ++ "peerDependencies": { ++ "@openzeppelin/contracts": "" ++ } + } +diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol +index 644f6f531..ab8ba05ff 100644 +--- a/contracts/utils/cryptography/EIP712.sol ++++ b/contracts/utils/cryptography/EIP712.sol +@@ -4,7 +4,6 @@ + pragma solidity ^0.8.20; + + import {MessageHashUtils} from "./MessageHashUtils.sol"; +-import {ShortStrings, ShortString} from "../ShortStrings.sol"; + import {IERC5267} from "../../interfaces/IERC5267.sol"; + + /** +@@ -28,28 +27,18 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; + * 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. +- * +- * @custom:oz-upgrades-unsafe-allow state-variable-immutable + */ + 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. +@@ -64,29 +53,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))); + } + + /** +@@ -125,6 +108,10 @@ 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 + _EIP712Name(), +@@ -139,22 +126,62 @@ abstract contract EIP712 is IERC5267 { + /** + * @dev The name parameter for the EIP712 domain. + * +- * NOTE: By default this function reads _name which is an immutable value. +- * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). ++ * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs ++ * are a concern. + */ +- // solhint-disable-next-line func-name-mixedcase +- function _EIP712Name() internal view returns (string memory) { +- return _name.toStringWithFallback(_nameFallback); ++ function _EIP712Name() internal view virtual returns (string memory) { ++ return _name; + } + + /** + * @dev The version parameter for the EIP712 domain. + * +- * NOTE: By default this function reads _version which is an immutable value. +- * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). ++ * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs ++ * are a concern. + */ +- // solhint-disable-next-line func-name-mixedcase +- function _EIP712Version() internal view returns (string memory) { +- return _version.toStringWithFallback(_versionFallback); ++ function _EIP712Version() internal view virtual 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 3a1617c09..97e59c2d9 100644 +--- a/package.json ++++ b/package.json +@@ -32,7 +32,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/remappings.txt b/remappings.txt +index 304d1386a..a1cd63bee 100644 +--- a/remappings.txt ++++ b/remappings.txt +@@ -1 +1,2 @@ +-@openzeppelin/contracts/=contracts/ ++@openzeppelin/contracts-upgradeable/=contracts/ ++@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ +diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js +index faf01f1a3..b25171a56 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/lib/openzeppelin-contracts-v5.0.0/slither.config.json b/lib/openzeppelin-contracts-v5.0.0/slither.config.json new file mode 100644 index 0000000..069da1f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/slither.config.json @@ -0,0 +1,5 @@ +{ + "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" +} diff --git a/lib/openzeppelin-contracts-v5.0.0/solhint.config.js b/lib/openzeppelin-contracts-v5.0.0/solhint.config.js new file mode 100644 index 0000000..123ff91 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/solhint.config.js @@ -0,0 +1,20 @@ +const customRules = require('./scripts/solhint-custom'); + +const rules = [ + 'no-unused-vars', + 'const-name-snakecase', + 'contract-name-camelcase', + 'event-name-camelcase', + 'func-name-mixedcase', + 'func-param-name-mixedcase', + 'modifier-name-mixedcase', + 'var-name-mixedcase', + 'imports-on-top', + 'no-global-import', + ...customRules.map(r => `openzeppelin/${r.ruleId}`), +]; + +module.exports = { + plugins: ['openzeppelin'], + rules: Object.fromEntries(rules.map(r => [r, 'error'])), +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/TESTING.md b/lib/openzeppelin-contracts-v5.0.0/test/TESTING.md new file mode 100644 index 0000000..a5ee932 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/TESTING.md @@ -0,0 +1,3 @@ +## Testing + +Unit test are critical to OpenZeppelin Contracts. They help ensure code quality and mitigate against security vulnerabilities. The directory structure within the `/test` directory corresponds to the `/contracts` directory. diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/AccessControl.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/access/AccessControl.behavior.js new file mode 100644 index 0000000..cc3e8d6 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/AccessControl.behavior.js @@ -0,0 +1,909 @@ +const { expectEvent, constants, BN } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../helpers/customError'); +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(admin, authorized, other, otherAdmin) { + shouldSupportInterfaces(['AccessControl']); + + describe('default admin', function () { + it('deployer has default admin role', async function () { + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin)).to.equal(true); + }); + + it("other roles's admin is the default admin role", async function () { + expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + it("default admin role's admin is itself", async function () { + expect(await this.accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + }); + + describe('granting', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('non-admin cannot grant role to other accounts', async function () { + await expectRevertCustomError( + this.accessControl.grantRole(ROLE, authorized, { from: other }), + 'AccessControlUnauthorizedAccount', + [other, DEFAULT_ADMIN_ROLE], + ); + }); + + it('accounts can be granted a role multiple times', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleGranted'); + }); + }); + + describe('revoking', function () { + it('roles that are not had can be revoked', async function () { + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + + context('with granted role', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('admin can revoke role', async function () { + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: admin }); + + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + }); + + it('non-admin cannot revoke role', async function () { + await expectRevertCustomError( + this.accessControl.revokeRole(ROLE, authorized, { from: other }), + 'AccessControlUnauthorizedAccount', + [other, DEFAULT_ADMIN_ROLE], + ); + }); + + it('a role can be revoked multiple times', async function () { + await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + }); + }); + + describe('renouncing', function () { + it('roles that are not had can be renounced', async function () { + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + + context('with granted role', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('bearer can renounce role', async function () { + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: authorized }); + + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + }); + + it('only the sender can renounce their roles', async function () { + await expectRevertCustomError( + this.accessControl.renounceRole(ROLE, authorized, { from: admin }), + 'AccessControlBadConfirmation', + [], + ); + }); + + it('a role can be renounced multiple times', async function () { + await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + }); + }); + + describe('setting role admin', function () { + beforeEach(async function () { + const receipt = await this.accessControl.$_setRoleAdmin(ROLE, OTHER_ROLE); + expectEvent(receipt, 'RoleAdminChanged', { + role: ROLE, + previousAdminRole: DEFAULT_ADMIN_ROLE, + newAdminRole: OTHER_ROLE, + }); + + await this.accessControl.grantRole(OTHER_ROLE, otherAdmin, { from: admin }); + }); + + it("a role's admin role can be changed", async function () { + expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(OTHER_ROLE); + }); + + it('the new admin can grant roles', async function () { + const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin }); + expectEvent(receipt, 'RoleGranted', { account: authorized, role: ROLE, sender: otherAdmin }); + }); + + it('the new admin can revoke roles', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin }); + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: otherAdmin }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: otherAdmin }); + }); + + it("a role's previous admins no longer grant roles", async function () { + await expectRevertCustomError( + this.accessControl.grantRole(ROLE, authorized, { from: admin }), + 'AccessControlUnauthorizedAccount', + [admin.toLowerCase(), OTHER_ROLE], + ); + }); + + it("a role's previous admins no longer revoke roles", async function () { + await expectRevertCustomError( + this.accessControl.revokeRole(ROLE, authorized, { from: admin }), + 'AccessControlUnauthorizedAccount', + [admin.toLowerCase(), OTHER_ROLE], + ); + }); + }); + + describe('onlyRole modifier', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('do not revert if sender has role', async function () { + await this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: authorized }); + }); + + it("revert if sender doesn't have role #1", async function () { + await expectRevertCustomError( + this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: other }), + 'AccessControlUnauthorizedAccount', + [other, ROLE], + ); + }); + + it("revert if sender doesn't have role #2", async function () { + await expectRevertCustomError( + this.accessControl.methods['$_checkRole(bytes32)'](OTHER_ROLE, { from: authorized }), + 'AccessControlUnauthorizedAccount', + [authorized.toLowerCase(), OTHER_ROLE], + ); + }); + }); + + describe('internal functions', function () { + describe('_grantRole', function () { + it('return true if the account does not have the role', async function () { + const receipt = await this.accessControl.$_grantRole(ROLE, authorized); + expectEvent(receipt, 'return$_grantRole', { ret0: true }); + }); + + it('return false if the account has the role', async function () { + await this.accessControl.$_grantRole(ROLE, authorized); + + const receipt = await this.accessControl.$_grantRole(ROLE, authorized); + expectEvent(receipt, 'return$_grantRole', { ret0: false }); + }); + }); + + describe('_revokeRole', function () { + it('return true if the account has the role', async function () { + await this.accessControl.$_grantRole(ROLE, authorized); + + const receipt = await this.accessControl.$_revokeRole(ROLE, authorized); + expectEvent(receipt, 'return$_revokeRole', { ret0: true }); + }); + + it('return false if the account does not have the role', async function () { + const receipt = await this.accessControl.$_revokeRole(ROLE, authorized); + expectEvent(receipt, 'return$_revokeRole', { ret0: false }); + }); + }); + }); +} + +function shouldBehaveLikeAccessControlEnumerable(admin, authorized, other, otherAdmin, otherAuthorized) { + shouldSupportInterfaces(['AccessControlEnumerable']); + + describe('enumerating', function () { + it('role bearers can be enumerated', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + await this.accessControl.grantRole(ROLE, other, { from: admin }); + await this.accessControl.grantRole(ROLE, otherAuthorized, { from: admin }); + await this.accessControl.revokeRole(ROLE, other, { from: admin }); + + const memberCount = await this.accessControl.getRoleMemberCount(ROLE); + expect(memberCount).to.bignumber.equal('2'); + + const bearers = []; + for (let i = 0; i < memberCount; ++i) { + bearers.push(await this.accessControl.getRoleMember(ROLE, i)); + } + + expect(bearers).to.have.members([authorized, otherAuthorized]); + }); + it('role enumeration should be in sync after renounceRole call', async function () { + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('0'); + await this.accessControl.grantRole(ROLE, admin, { from: admin }); + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('1'); + await this.accessControl.renounceRole(ROLE, admin, { from: admin }); + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('0'); + }); + }); +} + +function shouldBehaveLikeAccessControlDefaultAdminRules(delay, defaultAdmin, newDefaultAdmin, other) { + shouldSupportInterfaces(['AccessControlDefaultAdminRules']); + + 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 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); + 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 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); + }); + }); + }); + + 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); + }); + } + }); + }); + + 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 () { + await expectRevertCustomError( + this.accessControl.grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), + 'AccessControlEnforcedDefaultAdminRules', + [], + ); + }); + + it('should revert if revoking default admin role', async function () { + await expectRevertCustomError( + this.accessControl.revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), + 'AccessControlEnforcedDefaultAdminRules', + [], + ); + }); + + it("should revert if defaultAdmin's admin is changed", async function () { + await expectRevertCustomError( + this.accessControl.$_setRoleAdmin(DEFAULT_ADMIN_ROLE, OTHER_ROLE), + 'AccessControlEnforcedDefaultAdminRules', + [], + ); + }); + + it('should not grant the default admin role twice', async function () { + await expectRevertCustomError( + this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin), + 'AccessControlEnforcedDefaultAdminRules', + [], + ); + }); + + describe('begins a default admin transfer', function () { + let receipt; + let acceptSchedule; + + it('reverts if called by non default admin accounts', async function () { + await expectRevertCustomError( + this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: other }), + 'AccessControlUnauthorizedAccount', + [other, 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 }); + + expectEvent.notEmitted(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 acceptSchedule; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + acceptSchedule = web3.utils.toBN(await time.latest()).add(delay); + }); + + it('should revert if caller is not pending default admin', async function () { + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + await expectRevertCustomError( + this.accessControl.acceptDefaultAdminTransfer({ from: other }), + 'AccessControlInvalidDefaultAdmin', + [other], + ); + }); + + describe('when caller is pending default admin and delay has passed', function () { + beforeEach(async function () { + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + }); + + it('accepts a transfer and changes default admin', async function () { + const receipt = await this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }); + + // 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 schedule + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(constants.ZERO_ADDRESS); + expect(schedule).to.be.bignumber.equal(ZERO); + }); + }); + + 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 expectRevertCustomError( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + 'AccessControlEnforcedDefaultAdminDelay', + [acceptSchedule], + ); + }); + } + }); + }); + + describe('cancels a default admin transfer', function () { + it('reverts if called by non default admin accounts', async function () { + await expectRevertCustomError( + this.accessControl.cancelDefaultAdminTransfer({ from: other }), + 'AccessControlUnauthorizedAccount', + [other, 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 expectRevertCustomError( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + 'AccessControlInvalidDefaultAdmin', + [newDefaultAdmin], + ); + }); + }); + + 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); + + expectEvent.notEmitted(receipt, 'DefaultAdminTransferCanceled'); + }); + }); + }); + + describe('renounces admin', function () { + let expectedSchedule; + let delayPassed; + let delayNotPassed; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(constants.ZERO_ADDRESS, { from: defaultAdmin }); + 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 () { + await time.setNextBlockTimestamp(delayPassed); + await expectRevertCustomError( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from: defaultAdmin }), + 'AccessControlBadConfirmation', + [], + ); + }); + + 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); + + // 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, defaultAdmin, { from: defaultAdmin }); + + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.false; + expect(await this.accessControl.defaultAdmin()).to.be.equal(constants.ZERO_ADDRESS); + expectEvent(receipt, 'RoleRevoked', { + role: DEFAULT_ADMIN_ROLE, + 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 () { + await time.setNextBlockTimestamp(delayPassed); + await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }); + + const grantRoleReceipt = await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, other); + expectEvent(grantRoleReceipt, 'RoleGranted', { + role: DEFAULT_ADMIN_ROLE, + account: other, + }); + }); + + describe('schedule not passed', function () { + 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 expectRevertCustomError( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), + 'AccessControlEnforcedDefaultAdminDelay', + [expectedSchedule], + ); + }); + } + }); + }); + + describe('changes delay', function () { + it('reverts if called by non default admin accounts', async function () { + await expectRevertCustomError( + this.accessControl.changeDefaultAdminDelay(time.duration.hours(4), { + from: other, + }), + 'AccessControlUnauthorizedAccount', + [other, 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 ? expectEvent.notEmitted : expectEvent; + eventMatcher(receipt, 'DefaultAdminDelayChangeCanceled'); + }); + } + }); + }); + } + }); + + describe('rollbacks a delay change', function () { + it('reverts if called by non default admin accounts', async function () { + await expectRevertCustomError( + this.accessControl.rollbackDefaultAdminDelay({ from: other }), + 'AccessControlUnauthorizedAccount', + [other, 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 }); + }); + + 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 ? expectEvent.notEmitted : 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); + }); + }); + }); +} + +module.exports = { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, + shouldBehaveLikeAccessControlDefaultAdminRules, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/AccessControl.test.js b/lib/openzeppelin-contracts-v5.0.0/test/access/AccessControl.test.js new file mode 100644 index 0000000..14463b5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/AccessControl.test.js @@ -0,0 +1,12 @@ +const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js'); + +const AccessControl = artifacts.require('$AccessControl'); + +contract('AccessControl', function (accounts) { + beforeEach(async function () { + this.accessControl = await AccessControl.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl(...accounts); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/Ownable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/access/Ownable.test.js new file mode 100644 index 0000000..f85daec --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/Ownable.test.js @@ -0,0 +1,72 @@ +const { constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const Ownable = artifacts.require('$Ownable'); + +contract('Ownable', function (accounts) { + const [owner, other] = accounts; + + beforeEach(async function () { + this.ownable = await Ownable.new(owner); + }); + + it('rejects zero address for initialOwner', async function () { + await expectRevertCustomError(Ownable.new(constants.ZERO_ADDRESS), 'OwnableInvalidOwner', [constants.ZERO_ADDRESS]); + }); + + it('has an owner', async function () { + expect(await this.ownable.owner()).to.equal(owner); + }); + + describe('transfer ownership', function () { + it('changes owner after transfer', async function () { + const receipt = await this.ownable.transferOwnership(other, { from: owner }); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(other); + }); + + it('prevents non-owners from transferring', async function () { + await expectRevertCustomError( + this.ownable.transferOwnership(other, { from: other }), + 'OwnableUnauthorizedAccount', + [other], + ); + }); + + it('guards ownership against stuck state', async function () { + await expectRevertCustomError( + this.ownable.transferOwnership(ZERO_ADDRESS, { from: owner }), + 'OwnableInvalidOwner', + [ZERO_ADDRESS], + ); + }); + }); + + describe('renounce ownership', function () { + it('loses ownership after renouncement', async function () { + const receipt = await this.ownable.renounceOwnership({ from: owner }); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(ZERO_ADDRESS); + }); + + it('prevents non-owners from renouncement', async function () { + await expectRevertCustomError(this.ownable.renounceOwnership({ from: other }), 'OwnableUnauthorizedAccount', [ + other, + ]); + }); + + 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/lib/openzeppelin-contracts-v5.0.0/test/access/Ownable2Step.test.js b/lib/openzeppelin-contracts-v5.0.0/test/access/Ownable2Step.test.js new file mode 100644 index 0000000..bdbac48 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/Ownable2Step.test.js @@ -0,0 +1,70 @@ +const { constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const Ownable2Step = artifacts.require('$Ownable2Step'); + +contract('Ownable2Step', function (accounts) { + const [owner, accountA, accountB] = accounts; + + beforeEach(async function () { + this.ownable2Step = await Ownable2Step.new(owner); + }); + + describe('transfer ownership', function () { + it('starting a transfer does not change owner', async function () { + const receipt = await this.ownable2Step.transferOwnership(accountA, { from: owner }); + expectEvent(receipt, 'OwnershipTransferStarted', { previousOwner: owner, newOwner: accountA }); + expect(await this.ownable2Step.owner()).to.equal(owner); + expect(await this.ownable2Step.pendingOwner()).to.equal(accountA); + }); + + it('changes owner after transfer', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + const receipt = await this.ownable2Step.acceptOwnership({ from: accountA }); + expectEvent(receipt, 'OwnershipTransferred', { previousOwner: owner, newOwner: accountA }); + expect(await this.ownable2Step.owner()).to.equal(accountA); + 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 expectRevertCustomError( + this.ownable2Step.acceptOwnership({ from: accountB }), + 'OwnableUnauthorizedAccount', + [accountB], + ); + }); + }); + + describe('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 ... + // without it is difficult to cleanly renounce with the two step process + // see: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620#discussion_r957930388 + expect(await this.ownable2Step.owner()).to.equal(ZERO_ADDRESS); + }); + + it('pending owner resets after renouncing ownership', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + expect(await this.ownable2Step.pendingOwner()).to.equal(accountA); + await this.ownable2Step.renounceOwnership({ from: owner }); + expect(await this.ownable2Step.pendingOwner()).to.equal(ZERO_ADDRESS); + await expectRevertCustomError( + this.ownable2Step.acceptOwnership({ from: accountA }), + 'OwnableUnauthorizedAccount', + [accountA], + ); + }); + + it('allows to recover access using the internal _transferOwnership', async function () { + await this.ownable2Step.renounceOwnership({ from: owner }); + const receipt = await this.ownable2Step.$_transferOwnership(accountA); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable2Step.owner()).to.equal(accountA); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/extensions/AccessControlDefaultAdminRules.test.js b/lib/openzeppelin-contracts-v5.0.0/test/access/extensions/AccessControlDefaultAdminRules.test.js new file mode 100644 index 0000000..af34143 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/extensions/AccessControlDefaultAdminRules.test.js @@ -0,0 +1,26 @@ +const { time, constants, expectRevert } = 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.hours(10)); + + beforeEach(async function () { + 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), + 'AccessControlInvalidDefaultAdmin', + [constants.ZERO_ADDRESS], + ); + }); + + shouldBehaveLikeAccessControl(...accounts); + shouldBehaveLikeAccessControlDefaultAdminRules(delay, ...accounts); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/extensions/AccessControlEnumerable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/access/extensions/AccessControlEnumerable.test.js new file mode 100644 index 0000000..7dfb0bc --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/extensions/AccessControlEnumerable.test.js @@ -0,0 +1,17 @@ +const { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, +} = require('../AccessControl.behavior.js'); + +const AccessControlEnumerable = artifacts.require('$AccessControlEnumerable'); + +contract('AccessControlEnumerable', function (accounts) { + beforeEach(async function () { + this.accessControl = await AccessControlEnumerable.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl(...accounts); + shouldBehaveLikeAccessControlEnumerable(...accounts); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManaged.test.js b/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManaged.test.js new file mode 100644 index 0000000..9e94af6 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManaged.test.js @@ -0,0 +1,142 @@ +const { expectEvent, time, expectRevert } = require('@openzeppelin/test-helpers'); +const { selector } = require('../../helpers/methods'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { + time: { setNextBlockTimestamp }, +} = require('@nomicfoundation/hardhat-network-helpers'); +const { impersonate } = require('../../helpers/account'); + +const AccessManaged = artifacts.require('$AccessManagedTarget'); +const AccessManager = artifacts.require('$AccessManager'); + +const AuthoritiyObserveIsConsuming = artifacts.require('$AuthoritiyObserveIsConsuming'); + +contract('AccessManaged', function (accounts) { + const [admin, roleMember, other] = accounts; + + beforeEach(async function () { + this.authority = await AccessManager.new(admin); + this.managed = await AccessManaged.new(this.authority.address); + }); + + it('sets authority and emits AuthorityUpdated event during construction', async function () { + await expectEvent.inConstruction(this.managed, 'AuthorityUpdated', { + authority: this.authority.address, + }); + expect(await this.managed.authority()).to.eq(this.authority.address); + }); + + describe('restricted modifier', function () { + const method = 'fnRestricted()'; + + beforeEach(async function () { + this.selector = selector(method); + this.role = web3.utils.toBN(42); + await this.authority.$_setTargetFunctionRole(this.managed.address, this.selector, this.role); + await this.authority.$_grantRole(this.role, roleMember, 0, 0); + }); + + it('succeeds when role is granted without execution delay', async function () { + await this.managed.methods[method]({ from: roleMember }); + }); + + it('reverts when role is not granted', async function () { + await expectRevertCustomError(this.managed.methods[method]({ from: other }), 'AccessManagedUnauthorized', [ + other, + ]); + }); + + it('panics in short calldata', async function () { + // We avoid adding the `restricted` modifier to the fallback function because other tests may depend on it + // being accessible without restrictions. We check for the internal `_checkCanCall` instead. + await expectRevert.unspecified(this.managed.$_checkCanCall(other, '0x1234')); + }); + + describe('when role is granted with execution delay', function () { + beforeEach(async function () { + const executionDelay = web3.utils.toBN(911); + await this.authority.$_grantRole(this.role, roleMember, 0, executionDelay); + }); + + it('reverts if the operation is not scheduled', async function () { + const calldata = await this.managed.contract.methods[method]().encodeABI(); + const opId = await this.authority.hashOperation(roleMember, this.managed.address, calldata); + + await expectRevertCustomError(this.managed.methods[method]({ from: roleMember }), 'AccessManagerNotScheduled', [ + opId, + ]); + }); + + it('succeeds if the operation is scheduled', async function () { + // Arguments + const delay = time.duration.hours(12); + const calldata = await this.managed.contract.methods[method]().encodeABI(); + + // Schedule + const timestamp = await time.latest(); + const scheduledAt = timestamp.addn(1); + const when = scheduledAt.add(delay); + await setNextBlockTimestamp(scheduledAt); + await this.authority.schedule(this.managed.address, calldata, when, { + from: roleMember, + }); + + // Set execution date + await setNextBlockTimestamp(when); + + // Shouldn't revert + await this.managed.methods[method]({ from: roleMember }); + }); + }); + }); + + describe('setAuthority', function () { + beforeEach(async function () { + this.newAuthority = await AccessManager.new(admin); + }); + + it('reverts if the caller is not the authority', async function () { + await expectRevertCustomError(this.managed.setAuthority(other, { from: other }), 'AccessManagedUnauthorized', [ + other, + ]); + }); + + it('reverts if the new authority is not a valid authority', async function () { + await impersonate(this.authority.address); + await expectRevertCustomError( + this.managed.setAuthority(other, { from: this.authority.address }), + 'AccessManagedInvalidAuthority', + [other], + ); + }); + + it('sets authority and emits AuthorityUpdated event', async function () { + await impersonate(this.authority.address); + const { receipt } = await this.managed.setAuthority(this.newAuthority.address, { from: this.authority.address }); + await expectEvent(receipt, 'AuthorityUpdated', { + authority: this.newAuthority.address, + }); + expect(await this.managed.authority()).to.eq(this.newAuthority.address); + }); + }); + + describe('isConsumingScheduledOp', function () { + beforeEach(async function () { + this.authority = await AuthoritiyObserveIsConsuming.new(); + this.managed = await AccessManaged.new(this.authority.address); + }); + + it('returns bytes4(0) when not consuming operation', async function () { + expect(await this.managed.isConsumingScheduledOp()).to.eq('0x00000000'); + }); + + it('returns isConsumingScheduledOp selector when consuming operation', async function () { + const receipt = await this.managed.fnRestricted({ from: other }); + await expectEvent.inTransaction(receipt.tx, this.authority, 'ConsumeScheduledOpCalled', { + caller: other, + data: this.managed.contract.methods.fnRestricted().encodeABI(), + isConsuming: selector('isConsumingScheduledOp()'), + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManager.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManager.behavior.js new file mode 100644 index 0000000..d528ffb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManager.behavior.js @@ -0,0 +1,711 @@ +const { time } = require('@openzeppelin/test-helpers'); +const { + time: { setNextBlockTimestamp }, + setStorageAt, + mine, +} = require('@nomicfoundation/hardhat-network-helpers'); +const { impersonate } = require('../../helpers/account'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { EXPIRATION, EXECUTION_ID_STORAGE_SLOT } = require('../../helpers/access-manager'); + +// ============ COMMON PATHS ============ + +const COMMON_IS_EXECUTING_PATH = { + executing() { + it('succeeds', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + }, + notExecuting() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.role.id], + ); + }); + }, +}; + +const COMMON_GET_ACCESS_PATH = { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.role.id], + ); + }); + }, + afterGrantDelay: undefined, // Diverges if there's an operation delay or not + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.role.id], + ); + }); + }, + afterGrantDelay() { + it('succeeds called directly', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + + it('succeeds via execute', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay: undefined, // Diverges if there's an operation to schedule or not + callerHasNoExecutionDelay() { + it('succeeds called directly', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + + it('succeeds via execute', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.role.id], + ); + }); + }, +}; + +const COMMON_SCHEDULABLE_PATH = { + scheduled: { + before() { + it('reverts as AccessManagerNotReady', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerNotReady', + [this.operationId], + ); + }); + }, + after() { + it('succeeds called directly', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + + it('succeeds via execute', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + expired() { + it('reverts as AccessManagerExpired', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerExpired', + [this.operationId], + ); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerNotScheduled', + [this.operationId], + ); + }); + }, +}; + +const COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY = { + scheduled: { + before() { + it.skip('is not reachable without a delay'); + }, + after() { + it.skip('is not reachable without a delay'); + }, + expired() { + it.skip('is not reachable without a delay'); + }, + }, + notScheduled() { + it('succeeds', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, +}; + +// ============ MODE HELPERS ============ + +/** + * @requires this.{manager,target} + */ +function shouldBehaveLikeClosable({ closed, open }) { + describe('when the manager is closed', function () { + beforeEach('close', async function () { + await this.manager.$_setTargetClosed(this.target.address, true); + }); + + closed(); + }); + + describe('when the manager is open', function () { + beforeEach('open', async function () { + await this.manager.$_setTargetClosed(this.target.address, false); + }); + + open(); + }); +} + +// ============ DELAY HELPERS ============ + +/** + * @requires this.{delay} + */ +function shouldBehaveLikeDelay(type, { before, after }) { + beforeEach('define timestamp when delay takes effect', async function () { + const timestamp = await time.latest(); + this.delayEffect = timestamp.add(this.delay); + }); + + describe(`when ${type} delay has not taken effect yet`, function () { + beforeEach(`set next block timestamp before ${type} takes effect`, async function () { + await setNextBlockTimestamp(this.delayEffect.subn(1)); + }); + + before(); + }); + + describe(`when ${type} delay has taken effect`, function () { + beforeEach(`set next block timestamp when ${type} takes effect`, async function () { + await setNextBlockTimestamp(this.delayEffect); + }); + + after(); + }); +} + +// ============ OPERATION HELPERS ============ + +/** + * @requires this.{manager,scheduleIn,caller,target,calldata} + */ +function shouldBehaveLikeSchedulableOperation({ scheduled: { before, after, expired }, notScheduled }) { + describe('when operation is scheduled', function () { + beforeEach('schedule operation', async function () { + await impersonate(this.caller); // May be a contract + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.scheduleIn, + }); + this.operationId = operationId; + }); + + describe('when operation is not ready for execution', function () { + beforeEach('set next block time before operation is ready', async function () { + this.scheduledAt = await time.latest(); + const schedule = await this.manager.getSchedule(this.operationId); + await setNextBlockTimestamp(schedule.subn(1)); + }); + + before(); + }); + + describe('when operation is ready for execution', function () { + beforeEach('set next block time when operation is ready for execution', async function () { + this.scheduledAt = await time.latest(); + const schedule = await this.manager.getSchedule(this.operationId); + await setNextBlockTimestamp(schedule); + }); + + after(); + }); + + describe('when operation has expired', function () { + beforeEach('set next block time when operation expired', async function () { + this.scheduledAt = await time.latest(); + const schedule = await this.manager.getSchedule(this.operationId); + await setNextBlockTimestamp(schedule.add(EXPIRATION)); + }); + + expired(); + }); + }); + + describe('when operation is not scheduled', function () { + beforeEach('set expected operationId', async function () { + this.operationId = await this.manager.hashOperation(this.caller, this.target.address, this.calldata); + + // Assert operation is not scheduled + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + notScheduled(); + }); +} + +/** + * @requires this.{manager,roles,target,calldata} + */ +function shouldBehaveLikeARestrictedOperation({ callerIsNotTheManager, callerIsTheManager }) { + describe('when the call comes from the manager (msg.sender == manager)', function () { + beforeEach('define caller as manager', async function () { + this.caller = this.manager.address; + await impersonate(this.caller); + }); + + shouldBehaveLikeCanCallExecuting(callerIsTheManager); + }); + + describe('when the call does not come from the manager (msg.sender != manager)', function () { + beforeEach('define non manager caller', function () { + this.caller = this.roles.SOME.members[0]; + }); + + callerIsNotTheManager(); + }); +} + +/** + * @requires this.{manager,roles,executionDelay,operationDelay,target} + */ +function shouldBehaveLikeDelayedOperation() { + describe('with operation delay', function () { + describe('when operation delay is greater than execution delay', function () { + beforeEach('set operation delay', async function () { + this.operationDelay = this.executionDelay.add(time.duration.hours(1)); + await this.manager.$_setTargetAdminDelay(this.target.address, this.operationDelay); + this.scheduleIn = this.operationDelay; // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }); + + describe('when operation delay is shorter than execution delay', function () { + beforeEach('set operation delay', async function () { + this.operationDelay = this.executionDelay.sub(time.duration.hours(1)); + await this.manager.$_setTargetAdminDelay(this.target.address, this.operationDelay); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }); + }); + + describe('without operation delay', function () { + beforeEach('set operation delay', async function () { + this.operationDelay = web3.utils.toBN(0); + await this.manager.$_setTargetAdminDelay(this.target.address, this.operationDelay); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }); +} + +// ============ METHOD HELPERS ============ + +/** + * @requires this.{manager,roles,role,target,calldata} + */ +function shouldBehaveLikeCanCall({ + closed, + open: { + callerIsTheManager, + callerIsNotTheManager: { publicRoleIsRequired, specificRoleIsRequired }, + }, +}) { + shouldBehaveLikeClosable({ + closed, + open() { + shouldBehaveLikeARestrictedOperation({ + callerIsTheManager, + callerIsNotTheManager() { + shouldBehaveLikeHasRole({ + publicRoleIsRequired, + specificRoleIsRequired, + }); + }, + }); + }, + }); +} + +/** + * @requires this.{target,calldata} + */ +function shouldBehaveLikeCanCallExecuting({ executing, notExecuting }) { + describe('when _executionId is in storage for target and selector', function () { + beforeEach('set _executionId flag from calldata and target', async function () { + const executionId = await web3.utils.keccak256( + web3.eth.abi.encodeParameters(['address', 'bytes4'], [this.target.address, this.calldata.substring(0, 10)]), + ); + await setStorageAt(this.manager.address, EXECUTION_ID_STORAGE_SLOT, executionId); + }); + + executing(); + }); + + describe('when _executionId does not match target and selector', notExecuting); +} + +/** + * @requires this.{target,calldata,roles,role} + */ +function shouldBehaveLikeHasRole({ publicRoleIsRequired, specificRoleIsRequired }) { + describe('when the function requires the caller to be granted with the PUBLIC_ROLE', function () { + beforeEach('set target function role as PUBLIC_ROLE', async function () { + this.role = this.roles.PUBLIC; + await this.manager.$_setTargetFunctionRole(this.target.address, this.calldata.substring(0, 10), this.role.id, { + from: this.roles.ADMIN.members[0], + }); + }); + + publicRoleIsRequired(); + }); + + describe('when the function requires the caller to be granted with a role other than PUBLIC_ROLE', function () { + beforeEach('set target function role as PUBLIC_ROLE', async function () { + await this.manager.$_setTargetFunctionRole(this.target.address, this.calldata.substring(0, 10), this.role.id, { + from: this.roles.ADMIN.members[0], + }); + }); + + shouldBehaveLikeGetAccess(specificRoleIsRequired); + }); +} + +/** + * @requires this.{manager,role,caller} + */ +function shouldBehaveLikeGetAccess({ + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + // Because both grant and execution delay are set within the same $_grantRole call + // it's not possible to create a set of tests that diverge between grant and execution delay. + // Therefore, the shouldBehaveLikeDelay arguments are renamed for clarity: + // before => beforeGrantDelay + // after => afterGrantDelay + callerHasAnExecutionDelay: { beforeGrantDelay: case1, afterGrantDelay: case2 }, + callerHasNoExecutionDelay: { beforeGrantDelay: case3, afterGrantDelay: case4 }, + }, + roleGrantingIsNotDelayed: { callerHasAnExecutionDelay: case5, callerHasNoExecutionDelay: case6 }, + }, + requiredRoleIsNotGranted, +}) { + describe('when the required role is granted to the caller', function () { + describe('when role granting is delayed', function () { + beforeEach('define delay', function () { + this.grantDelay = time.duration.minutes(3); + this.delay = this.grantDelay; // For shouldBehaveLikeDelay + }); + + describe('when caller has an execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = time.duration.hours(10); + this.delay = this.grantDelay; + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + shouldBehaveLikeDelay('grant', { before: case1, after: case2 }); + }); + + describe('when caller has no execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = web3.utils.toBN(0); + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + shouldBehaveLikeDelay('grant', { before: case3, after: case4 }); + }); + }); + + describe('when role granting is not delayed', function () { + beforeEach('define delay', function () { + this.grantDelay = web3.utils.toBN(0); + }); + + describe('when caller has an execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = time.duration.hours(10); + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + case5(); + }); + + describe('when caller has no execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = web3.utils.toBN(0); + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + case6(); + }); + }); + }); + + describe('when role is not granted', function () { + // Because this helper can be composed with other helpers, it's possible + // that role has been set already by another helper. + // Although this is highly unlikely, we check for it here to avoid false positives. + beforeEach('assert role is unset', async function () { + const { since } = await this.manager.getAccess(this.role.id, this.caller); + expect(since).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + requiredRoleIsNotGranted(); + }); +} + +// ============ ADMIN OPERATION HELPERS ============ + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeDelayedAdminOperation() { + const getAccessPath = COMMON_GET_ACCESS_PATH; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = function () { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + shouldBehaveLikeDelayedOperation(); + }; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeDelayedOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + shouldBehaveLikeARestrictedOperation({ + callerIsTheManager: COMMON_IS_EXECUTING_PATH, + callerIsNotTheManager() { + shouldBehaveLikeHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [ + this.caller, + this.roles.ADMIN.id, // Although PUBLIC is required, target function role doesn't apply to admin ops + ], + ); + }); + }, + specificRoleIsRequired: getAccessPath, + }); + }, + }); +} + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeNotDelayedAdminOperation() { + const getAccessPath = COMMON_GET_ACCESS_PATH; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = function () { + beforeEach('set execution delay', async function () { + await mine(); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + shouldBehaveLikeARestrictedOperation({ + callerIsTheManager: COMMON_IS_EXECUTING_PATH, + callerIsNotTheManager() { + shouldBehaveLikeHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.roles.ADMIN.id], // Although PUBLIC_ROLE is required, admin ops are not subject to target function roles + ); + }); + }, + specificRoleIsRequired: getAccessPath, + }); + }, + }); +} + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeRoleAdminOperation(roleAdmin) { + const getAccessPath = COMMON_GET_ACCESS_PATH; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = function () { + beforeEach('set operation delay', async function () { + await mine(); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + shouldBehaveLikeARestrictedOperation({ + callerIsTheManager: COMMON_IS_EXECUTING_PATH, + callerIsNotTheManager() { + shouldBehaveLikeHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, roleAdmin], // Role admin ops require the role's admin + ); + }); + }, + specificRoleIsRequired: getAccessPath, + }); + }, + }); +} + +// ============ RESTRICTED OPERATION HELPERS ============ + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeAManagedRestrictedOperation() { + function revertUnauthorized() { + it('reverts as AccessManagedUnauthorized', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagedUnauthorized', + [this.caller], + ); + }); + } + + const getAccessPath = COMMON_GET_ACCESS_PATH; + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.beforeGrantDelay = + revertUnauthorized; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasNoExecutionDelay.beforeGrantDelay = + revertUnauthorized; + getAccessPath.requiredRoleIsNotGranted = revertUnauthorized; + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = function () { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('consume previously set grant delay', async function () { + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + + const isExecutingPath = COMMON_IS_EXECUTING_PATH; + isExecutingPath.notExecuting = revertUnauthorized; + + shouldBehaveLikeCanCall({ + closed: revertUnauthorized, + open: { + callerIsTheManager: isExecutingPath, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('succeeds called directly', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + + it('succeeds via execute', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + specificRoleIsRequired: getAccessPath, + }, + }, + }); +} + +// ============ HELPERS ============ + +/** + * @requires this.{manager, caller, target, calldata} + */ +async function scheduleOperation(manager, { caller, target, calldata, delay }) { + const timestamp = await time.latest(); + const scheduledAt = timestamp.addn(1); + await setNextBlockTimestamp(scheduledAt); // Fix next block timestamp for predictability + const { receipt } = await manager.schedule(target, calldata, scheduledAt.add(delay), { + from: caller, + }); + + return { + receipt, + scheduledAt, + operationId: await manager.hashOperation(caller, target, calldata), + }; +} + +module.exports = { + // COMMON PATHS + COMMON_SCHEDULABLE_PATH, + COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY, + // MODE HELPERS + shouldBehaveLikeClosable, + // DELAY HELPERS + shouldBehaveLikeDelay, + // OPERATION HELPERS + shouldBehaveLikeSchedulableOperation, + // METHOD HELPERS + shouldBehaveLikeCanCall, + shouldBehaveLikeGetAccess, + shouldBehaveLikeHasRole, + // ADMIN OPERATION HELPERS + shouldBehaveLikeDelayedAdminOperation, + shouldBehaveLikeNotDelayedAdminOperation, + shouldBehaveLikeRoleAdminOperation, + // RESTRICTED OPERATION HELPERS + shouldBehaveLikeAManagedRestrictedOperation, + // HELPERS + scheduleOperation, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManager.test.js b/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManager.test.js new file mode 100644 index 0000000..705af1a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AccessManager.test.js @@ -0,0 +1,2683 @@ +const { web3 } = require('hardhat'); +const { constants, expectEvent, time, expectRevert } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { selector } = require('../../helpers/methods'); +const { clockFromReceipt } = require('../../helpers/time'); +const { + buildBaseRoles, + formatAccess, + EXPIRATION, + MINSETBACK, + EXECUTION_ID_STORAGE_SLOT, + CONSUMING_SCHEDULE_STORAGE_SLOT, +} = require('../../helpers/access-manager'); +const { + // COMMON PATHS + COMMON_SCHEDULABLE_PATH, + COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY, + // MODE HELPERS + shouldBehaveLikeClosable, + // DELAY HELPERS + shouldBehaveLikeDelay, + // OPERATION HELPERS + shouldBehaveLikeSchedulableOperation, + // METHOD HELPERS + shouldBehaveLikeCanCall, + shouldBehaveLikeGetAccess, + shouldBehaveLikeHasRole, + // ADMIN OPERATION HELPERS + shouldBehaveLikeDelayedAdminOperation, + shouldBehaveLikeNotDelayedAdminOperation, + shouldBehaveLikeRoleAdminOperation, + // RESTRICTED OPERATION HELPERS + shouldBehaveLikeAManagedRestrictedOperation, + // HELPERS + scheduleOperation, +} = require('./AccessManager.behavior'); +const { default: Wallet } = require('ethereumjs-wallet'); +const { + mine, + time: { setNextBlockTimestamp }, + getStorageAt, +} = require('@nomicfoundation/hardhat-network-helpers'); +const { MAX_UINT48 } = require('../../helpers/constants'); +const { impersonate } = require('../../helpers/account'); + +const AccessManager = artifacts.require('$AccessManager'); +const AccessManagedTarget = artifacts.require('$AccessManagedTarget'); +const Ownable = artifacts.require('$Ownable'); + +const someAddress = Wallet.generate().getChecksumAddressString(); + +contract('AccessManager', function (accounts) { + const [admin, manager, guardian, member, user, other] = accounts; + + beforeEach(async function () { + this.roles = buildBaseRoles(); + + // Add members + this.roles.ADMIN.members = [admin]; + this.roles.SOME_ADMIN.members = [manager]; + this.roles.SOME_GUARDIAN.members = [guardian]; + this.roles.SOME.members = [member]; + this.roles.PUBLIC.members = [admin, manager, guardian, member, user, other]; + + this.manager = await AccessManager.new(admin); + this.target = await AccessManagedTarget.new(this.manager.address); + + for (const { id: roleId, admin, guardian, members } of Object.values(this.roles)) { + if (roleId === this.roles.PUBLIC.id) continue; // Every address belong to public and is locked + if (roleId === this.roles.ADMIN.id) continue; // Admin set during construction and is locked + + // Set admin role avoiding default + if (admin.id !== this.roles.ADMIN.id) { + await this.manager.$_setRoleAdmin(roleId, admin.id); + } + + // Set guardian role avoiding default + if (guardian.id !== this.roles.ADMIN.id) { + await this.manager.$_setRoleGuardian(roleId, guardian.id); + } + + // Grant role to members + for (const member of members) { + await this.manager.$_grantRole(roleId, member, 0, 0); + } + } + }); + + describe('during construction', function () { + it('grants admin role to initialAdmin', async function () { + const manager = await AccessManager.new(other); + expect(await manager.hasRole(this.roles.ADMIN.id, other).then(formatAccess)).to.be.deep.equal([true, '0']); + }); + + it('rejects zero address for initialAdmin', async function () { + await expectRevertCustomError(AccessManager.new(constants.ZERO_ADDRESS), 'AccessManagerInvalidInitialAdmin', [ + constants.ZERO_ADDRESS, + ]); + }); + + it('initializes setup roles correctly', async function () { + for (const { id: roleId, admin, guardian, members } of Object.values(this.roles)) { + expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(admin.id); + expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(guardian.id); + + for (const user of this.roles.PUBLIC.members) { + expect(await this.manager.hasRole(roleId, user).then(formatAccess)).to.be.deep.equal([ + members.includes(user), + '0', + ]); + } + } + }); + }); + + describe('getters', function () { + describe('#canCall', function () { + beforeEach('set calldata', function () { + this.calldata = '0x12345678'; + this.role = { id: web3.utils.toBN(379204) }; + }); + + shouldBehaveLikeCanCall({ + closed() { + it('should return false and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + someAddress, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + open: { + callerIsTheManager: { + executing() { + it('should return true and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(true); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + notExecuting() { + it('should return false and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('should return true and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(true); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation({ + scheduled: { + before() { + beforeEach('consume previously set delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + after() { + beforeEach('consume previously set delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + expired() { + beforeEach('consume previously set delay', async function () { + // Consume previously set delay + await mine(); + }); + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + }, + notScheduled() { + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return true and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(true); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + callerHasNoExecutionDelay() { + it('should return true and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(true); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + }, + }, + }, + }); + }); + + describe('#expiration', function () { + it('has a 7 days default expiration', async function () { + expect(await this.manager.expiration()).to.be.bignumber.equal(EXPIRATION); + }); + }); + + describe('#minSetback', function () { + it('has a 5 days default minimum setback', async function () { + expect(await this.manager.minSetback()).to.be.bignumber.equal(MINSETBACK); + }); + }); + + describe('#isTargetClosed', function () { + shouldBehaveLikeClosable({ + closed() { + it('returns true', async function () { + expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(true); + }); + }, + open() { + it('returns false', async function () { + expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(false); + }); + }, + }); + }); + + describe('#getTargetFunctionRole', function () { + const methodSelector = selector('something(address,bytes)'); + + it('returns the target function role', async function () { + const roleId = web3.utils.toBN(21498); + await this.manager.$_setTargetFunctionRole(this.target.address, methodSelector, roleId); + + expect(await this.manager.getTargetFunctionRole(this.target.address, methodSelector)).to.be.bignumber.equal( + roleId, + ); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getTargetFunctionRole(this.target.address, methodSelector)).to.be.bignumber.equal( + this.roles.ADMIN.id, + ); + }); + }); + + describe('#getTargetAdminDelay', function () { + describe('when the target admin delay is setup', function () { + beforeEach('set target admin delay', async function () { + this.oldDelay = await this.manager.getTargetAdminDelay(this.target.address); + this.newDelay = time.duration.days(10); + + await this.manager.$_setTargetAdminDelay(this.target.address, this.newDelay); + this.delay = MINSETBACK; // For shouldBehaveLikeDelay + }); + + shouldBehaveLikeDelay('effect', { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns the old target admin delay', async function () { + expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal(this.oldDelay); + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns the new target admin delay', async function () { + expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal(this.newDelay); + }); + }, + }); + }); + + it('returns the 0 if not set', async function () { + expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal('0'); + }); + }); + + describe('#getRoleAdmin', function () { + const roleId = web3.utils.toBN(5234907); + + it('returns the role admin', async function () { + const adminId = web3.utils.toBN(789433); + + await this.manager.$_setRoleAdmin(roleId, adminId); + + expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(adminId); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(this.roles.ADMIN.id); + }); + }); + + describe('#getRoleGuardian', function () { + const roleId = web3.utils.toBN(5234907); + + it('returns the role guardian', async function () { + const guardianId = web3.utils.toBN(789433); + + await this.manager.$_setRoleGuardian(roleId, guardianId); + + expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(guardianId); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(this.roles.ADMIN.id); + }); + }); + + describe('#getRoleGrantDelay', function () { + const roleId = web3.utils.toBN(9248439); + + describe('when the grant admin delay is setup', function () { + beforeEach('set grant admin delay', async function () { + this.oldDelay = await this.manager.getRoleGrantDelay(roleId); + this.newDelay = time.duration.days(11); + + await this.manager.$_setGrantDelay(roleId, this.newDelay); + this.delay = MINSETBACK; // For shouldBehaveLikeDelay + }); + + shouldBehaveLikeDelay('grant', { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns the old role grant delay', async function () { + expect(await this.manager.getRoleGrantDelay(roleId)).to.be.bignumber.equal(this.oldDelay); + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns the new role grant delay', async function () { + expect(await this.manager.getRoleGrantDelay(roleId)).to.be.bignumber.equal(this.newDelay); + }); + }, + }); + }); + + it('returns 0 if delay is not set', async function () { + expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal('0'); + }); + }); + + describe('#getAccess', function () { + beforeEach('set role', function () { + this.role = { id: web3.utils.toBN(9452) }; + this.caller = user; + }); + + shouldBehaveLikeGetAccess({ + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('role is not in effect and execution delay is set', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Not in effect yet + expect(await time.latest()).to.be.bignumber.lt(access[0]); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('access has role in effect and execution delay is set', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + + expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await time.latest()).to.be.bignumber.equal(access[0]); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('access has role not in effect without execution delay', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Not in effect yet + expect(await time.latest()).to.be.bignumber.lt(access[0]); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('role is in effect without execution delay', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await time.latest()).to.be.bignumber.equal(access[0]); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('access has role in effect and execution delay is set', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(await time.latest()); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await time.latest()).to.be.bignumber.equal(access[0]); + }); + }, + callerHasNoExecutionDelay() { + it('access has role in effect without execution delay', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(await time.latest()); // inEffectSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await time.latest()).to.be.bignumber.equal(access[0]); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('has empty access', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal('0'); // inEffectSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + }); + }, + }); + }); + + describe('#hasRole', function () { + beforeEach('setup shouldBehaveLikeHasRole', function () { + this.role = { id: web3.utils.toBN(49832) }; + this.calldata = '0x1234'; + this.caller = user; + }); + + shouldBehaveLikeHasRole({ + publicRoleIsRequired() { + it('has PUBLIC role', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not have role but execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.false; + expect(executionDelay).to.be.bignumber.eq(this.executionDelay); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('has role and execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq(this.executionDelay); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not have role nor execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.false; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('has role and no execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('has role and execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq(this.executionDelay); + }); + }, + callerHasNoExecutionDelay() { + it('has role and no execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('has no role and no execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.false; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + }, + }); + }); + + describe('#getSchedule', function () { + beforeEach('set role and calldata', async function () { + const method = 'fnRestricted()'; + this.caller = user; + this.role = { id: web3.utils.toBN(493590) }; + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = await this.target.contract.methods[method]().encodeABI(); + this.scheduleIn = time.duration.days(10); // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation({ + scheduled: { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns schedule in the future', async function () { + const schedule = await this.manager.getSchedule(this.operationId); + expect(schedule).to.be.bignumber.equal(this.scheduledAt.add(this.scheduleIn)); + expect(schedule).to.be.bignumber.gt(await time.latest()); + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns schedule', async function () { + const schedule = await this.manager.getSchedule(this.operationId); + expect(schedule).to.be.bignumber.equal(this.scheduledAt.add(this.scheduleIn)); + expect(schedule).to.be.bignumber.eq(await time.latest()); + }); + }, + expired() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns 0', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0'); + }); + }, + }, + notScheduled() { + it('defaults to 0', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0'); + }); + }, + }); + }); + + describe('#getNonce', function () { + describe('when operation is scheduled', function () { + beforeEach('schedule operation', async function () { + const method = 'fnRestricted()'; + this.caller = user; + this.role = { id: web3.utils.toBN(4209043) }; + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = await this.target.contract.methods[method]().encodeABI(); + this.delay = time.duration.days(10); + + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + this.operationId = operationId; + }); + + it('returns nonce', async function () { + expect(await this.manager.getNonce(this.operationId)).to.be.bignumber.equal('1'); + }); + }); + + describe('when is not scheduled', function () { + it('returns default 0', async function () { + expect(await this.manager.getNonce(web3.utils.keccak256('operation'))).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('#hashOperation', function () { + it('returns an operationId', async function () { + const calldata = '0x123543'; + const address = someAddress; + + const args = [user, address, calldata]; + + expect(await this.manager.hashOperation(...args)).to.be.bignumber.eq( + await web3.utils.keccak256(web3.eth.abi.encodeParameters(['address', 'address', 'bytes'], args)), + ); + }); + }); + }); + + describe('admin operations', function () { + beforeEach('set required role', function () { + this.role = this.roles.ADMIN; + }); + + describe('subject to a delay', function () { + describe('#labelRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'labelRole(uint64,string)'; + const args = [123443, 'TEST']; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it('emits an event with the label', async function () { + expectEvent(await this.manager.labelRole(this.roles.SOME.id, 'Some label', { from: admin }), 'RoleLabel', { + roleId: this.roles.SOME.id, + label: 'Some label', + }); + }); + + it('updates label on a second call', async function () { + await this.manager.labelRole(this.roles.SOME.id, 'Some label', { from: admin }); + + expectEvent(await this.manager.labelRole(this.roles.SOME.id, 'Updated label', { from: admin }), 'RoleLabel', { + roleId: this.roles.SOME.id, + label: 'Updated label', + }); + }); + + it('reverts labeling PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.labelRole(this.roles.PUBLIC.id, 'Some label', { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + it('reverts labeling ADMIN_ROLE', async function () { + await expectRevertCustomError( + this.manager.labelRole(this.roles.ADMIN.id, 'Some label', { from: admin }), + 'AccessManagerLockedRole', + [this.roles.ADMIN.id], + ); + }); + }); + + describe('#setRoleAdmin', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setRoleAdmin(uint64,uint64)'; + const args = [93445, 84532]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it("sets any role's admin if called by an admin", async function () { + expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.SOME_ADMIN.id); + + const { receipt } = await this.manager.setRoleAdmin(this.roles.SOME.id, this.roles.ADMIN.id, { from: admin }); + expectEvent(receipt, 'RoleAdminChanged', { roleId: this.roles.SOME.id, admin: this.roles.ADMIN.id }); + + expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.ADMIN.id); + }); + + it('reverts setting PUBLIC_ROLE admin', async function () { + await expectRevertCustomError( + this.manager.setRoleAdmin(this.roles.PUBLIC.id, this.roles.ADMIN.id, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + it('reverts setting ADMIN_ROLE admin', async function () { + await expectRevertCustomError( + this.manager.setRoleAdmin(this.roles.ADMIN.id, this.roles.ADMIN.id, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.ADMIN.id], + ); + }); + }); + + describe('#setRoleGuardian', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setRoleGuardian(uint64,uint64)'; + const args = [93445, 84532]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it("sets any role's guardian if called by an admin", async function () { + expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.be.bignumber.equal( + this.roles.SOME_GUARDIAN.id, + ); + + const { receipt } = await this.manager.setRoleGuardian(this.roles.SOME.id, this.roles.ADMIN.id, { + from: admin, + }); + expectEvent(receipt, 'RoleGuardianChanged', { roleId: this.roles.SOME.id, guardian: this.roles.ADMIN.id }); + + expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.ADMIN.id); + }); + + it('reverts setting PUBLIC_ROLE admin', async function () { + await expectRevertCustomError( + this.manager.setRoleGuardian(this.roles.PUBLIC.id, this.roles.ADMIN.id, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + it('reverts setting ADMIN_ROLE admin', async function () { + await expectRevertCustomError( + this.manager.setRoleGuardian(this.roles.ADMIN.id, this.roles.ADMIN.id, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.ADMIN.id], + ); + }); + }); + + describe('#setGrantDelay', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setGrantDelay(uint64,uint32)'; + const args = [984910, time.duration.days(2)]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it('reverts setting grant delay for the PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.setGrantDelay(this.roles.PUBLIC.id, web3.utils.toBN(69), { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + describe('when increasing the delay', function () { + const oldDelay = web3.utils.toBN(10); + const newDelay = web3.utils.toBN(100); + + beforeEach('sets old delay', async function () { + this.role = this.roles.SOME; + await this.manager.$_setGrantDelay(this.role.id, oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + }); + + it('increases the delay after minsetback', async function () { + const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'RoleGrantDelayChanged', { + roleId: this.role.id, + delay: newDelay, + since: timestamp.add(MINSETBACK), + }); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay); + }); + }); + + describe('when reducing the delay', function () { + const oldDelay = time.duration.days(10); + + beforeEach('sets old delay', async function () { + this.role = this.roles.SOME; + await this.manager.$_setGrantDelay(this.role.id, oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + }); + + describe('when the delay difference is shorter than minimum setback', function () { + const newDelay = oldDelay.subn(1); + + it('increases the delay after minsetback', async function () { + const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'RoleGrantDelayChanged', { + roleId: this.role.id, + delay: newDelay, + since: timestamp.add(MINSETBACK), + }); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay); + }); + }); + + describe('when the delay difference is longer than minimum setback', function () { + const newDelay = web3.utils.toBN(1); + + beforeEach('assert delay difference is higher than minsetback', function () { + expect(oldDelay.sub(newDelay)).to.be.bignumber.gt(MINSETBACK); + }); + + it('increases the delay after delay difference', async function () { + const setback = oldDelay.sub(newDelay); + const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'RoleGrantDelayChanged', { + roleId: this.role.id, + delay: newDelay, + since: timestamp.add(setback), + }); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + await time.increase(setback); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay); + }); + }); + }); + }); + + describe('#setTargetAdminDelay', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setTargetAdminDelay(address,uint32)'; + const args = [someAddress, time.duration.days(3)]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + describe('when increasing the delay', function () { + const oldDelay = time.duration.days(10); + const newDelay = time.duration.days(11); + const target = someAddress; + + beforeEach('sets old delay', async function () { + await this.manager.$_setTargetAdminDelay(target, oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + }); + + it('increases the delay after minsetback', async function () { + const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'TargetAdminDelayUpdated', { + target, + delay: newDelay, + since: timestamp.add(MINSETBACK), + }); + + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay); + }); + }); + + describe('when reducing the delay', function () { + const oldDelay = time.duration.days(10); + const target = someAddress; + + beforeEach('sets old delay', async function () { + await this.manager.$_setTargetAdminDelay(target, oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + }); + + describe('when the delay difference is shorter than minimum setback', function () { + const newDelay = oldDelay.subn(1); + + it('increases the delay after minsetback', async function () { + const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'TargetAdminDelayUpdated', { + target, + delay: newDelay, + since: timestamp.add(MINSETBACK), + }); + + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay); + }); + }); + + describe('when the delay difference is longer than minimum setback', function () { + const newDelay = web3.utils.toBN(1); + + beforeEach('assert delay difference is higher than minsetback', function () { + expect(oldDelay.sub(newDelay)).to.be.bignumber.gt(MINSETBACK); + }); + + it('increases the delay after delay difference', async function () { + const setback = oldDelay.sub(newDelay); + const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'TargetAdminDelayUpdated', { + target, + delay: newDelay, + since: timestamp.add(setback), + }); + + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + await time.increase(setback); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay); + }); + }); + }); + }); + }); + + describe('not subject to a delay', function () { + describe('#updateAuthority', function () { + beforeEach('create a target and a new authority', async function () { + this.newAuthority = await AccessManager.new(admin); + this.newManagedTarget = await AccessManagedTarget.new(this.manager.address); + }); + + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'updateAuthority(address,address)'; + const args = [this.newManagedTarget.address, this.newAuthority.address]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeNotDelayedAdminOperation(); + }); + + it('changes the authority', async function () { + expect(await this.newManagedTarget.authority()).to.be.equal(this.manager.address); + + const { tx } = await this.manager.updateAuthority(this.newManagedTarget.address, this.newAuthority.address, { + from: admin, + }); + + // Managed contract is responsible of notifying the change through an event + await expectEvent.inTransaction(tx, this.newManagedTarget, 'AuthorityUpdated', { + authority: this.newAuthority.address, + }); + + expect(await this.newManagedTarget.authority()).to.be.equal(this.newAuthority.address); + }); + }); + + describe('#setTargetClosed', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setTargetClosed(address,bool)'; + const args = [someAddress, true]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeNotDelayedAdminOperation(); + }); + + it('closes and opens a target', async function () { + const close = await this.manager.setTargetClosed(this.target.address, true, { from: admin }); + expectEvent(close.receipt, 'TargetClosed', { target: this.target.address, closed: true }); + + expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(true); + + const open = await this.manager.setTargetClosed(this.target.address, false, { from: admin }); + expectEvent(open.receipt, 'TargetClosed', { target: this.target.address, closed: false }); + expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(false); + }); + + it('reverts if closing the manager', async function () { + await expectRevertCustomError( + this.manager.setTargetClosed(this.manager.address, true, { from: admin }), + 'AccessManagerLockedAccount', + [this.manager.address], + ); + }); + }); + + describe('#setTargetFunctionRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setTargetFunctionRole(address,bytes4[],uint64)'; + const args = [someAddress, ['0x12345678'], 443342]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeNotDelayedAdminOperation(); + }); + + const sigs = ['someFunction()', 'someOtherFunction(uint256)', 'oneMoreFunction(address,uint8)'].map(selector); + + it('sets function roles', async function () { + for (const sig of sigs) { + expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal( + this.roles.ADMIN.id, + ); + } + + const { receipt: receipt1 } = await this.manager.setTargetFunctionRole( + this.target.address, + sigs, + this.roles.SOME.id, + { + from: admin, + }, + ); + + for (const sig of sigs) { + expectEvent(receipt1, 'TargetFunctionRoleUpdated', { + target: this.target.address, + selector: sig, + roleId: this.roles.SOME.id, + }); + expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal( + this.roles.SOME.id, + ); + } + + const { receipt: receipt2 } = await this.manager.setTargetFunctionRole( + this.target.address, + [sigs[1]], + this.roles.SOME_ADMIN.id, + { + from: admin, + }, + ); + expectEvent(receipt2, 'TargetFunctionRoleUpdated', { + target: this.target.address, + selector: sigs[1], + roleId: this.roles.SOME_ADMIN.id, + }); + + for (const sig of sigs) { + expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal( + sig == sigs[1] ? this.roles.SOME_ADMIN.id : this.roles.SOME.id, + ); + } + }); + }); + + describe('role admin operations', function () { + const ANOTHER_ADMIN = web3.utils.toBN(0xdeadc0de1); + const ANOTHER_ROLE = web3.utils.toBN(0xdeadc0de2); + + beforeEach('set required role', async function () { + // Make admin a member of ANOTHER_ADMIN + await this.manager.$_grantRole(ANOTHER_ADMIN, admin, 0, 0); + await this.manager.$_setRoleAdmin(ANOTHER_ROLE, ANOTHER_ADMIN); + + this.role = { id: ANOTHER_ADMIN }; + this.user = user; + await this.manager.$_grantRole(this.role.id, this.user, 0, 0); + }); + + describe('#grantRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'grantRole(uint64,address,uint32)'; + const args = [ANOTHER_ROLE, someAddress, 0]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeRoleAdminOperation(ANOTHER_ADMIN); + }); + + it('reverts when granting PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.grantRole(this.roles.PUBLIC.id, user, 0, { + from: admin, + }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + describe('when the user is not a role member', function () { + describe('with grant delay', function () { + beforeEach('set grant delay and grant role', async function () { + // Delay granting + this.grantDelay = time.duration.weeks(2); + await this.manager.$_setGrantDelay(ANOTHER_ROLE, this.grantDelay); + await time.increase(MINSETBACK); + + // Grant role + this.executionDelay = time.duration.days(3); + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.executionDelay, { + from: admin, + }); + + this.receipt = receipt; + this.delay = this.grantDelay; // For shouldBehaveLikeDelay + }); + + shouldBehaveLikeDelay('grant', { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not grant role to the user yet', async function () { + const timestamp = await clockFromReceipt.timestamp(this.receipt).then(web3.utils.toBN); + expectEvent(this.receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp.add(this.grantDelay), + delay: this.executionDelay, + newMember: true, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(timestamp.add(this.grantDelay)); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Not in effect yet + const currentTimestamp = await time.latest(); + expect(currentTimestamp).to.be.a.bignumber.lt(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + false, + this.executionDelay.toString(), + ]); + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('grants role to the user', async function () { + const timestamp = await clockFromReceipt.timestamp(this.receipt).then(web3.utils.toBN); + expectEvent(this.receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp.add(this.grantDelay), + delay: this.executionDelay, + newMember: true, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(timestamp.add(this.grantDelay)); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + const currentTimestamp = await time.latest(); + expect(currentTimestamp).to.be.a.bignumber.equal(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.executionDelay.toString(), + ]); + }); + }, + }); + }); + + describe('without grant delay', function () { + beforeEach('set granting delay', async function () { + // Delay granting + this.grantDelay = 0; + await this.manager.$_setGrantDelay(ANOTHER_ROLE, this.grantDelay); + await time.increase(MINSETBACK); + }); + + it('immediately grants the role to the user', async function () { + this.executionDelay = time.duration.days(6); + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.executionDelay, { + from: admin, + }); + + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp, + delay: this.executionDelay, + newMember: true, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(timestamp); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + const currentTimestamp = await time.latest(); + expect(currentTimestamp).to.be.a.bignumber.equal(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.executionDelay.toString(), + ]); + }); + }); + }); + + describe('when the user is already a role member', function () { + beforeEach('make user role member', async function () { + this.previousExecutionDelay = time.duration.days(6); + await this.manager.$_grantRole(ANOTHER_ROLE, this.user, 0, this.previousExecutionDelay); + this.oldAccess = await this.manager.getAccess(ANOTHER_ROLE, user); + }); + + describe('with grant delay', function () { + beforeEach('set granting delay', async function () { + // Delay granting + const grantDelay = time.duration.weeks(2); + await this.manager.$_setGrantDelay(ANOTHER_ROLE, grantDelay); + await time.increase(MINSETBACK); + }); + + describe('when increasing the execution delay', function () { + beforeEach('set increased new execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + + this.newExecutionDelay = this.previousExecutionDelay.add(time.duration.days(4)); + }); + + it('emits event and immediately changes the execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, { + from: admin, + }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + + expectEvent(receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp, + delay: this.newExecutionDelay, + newMember: false, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.newExecutionDelay.toString(), + ]); + }); + }); + + describe('when decreasing the execution delay', function () { + beforeEach('decrease execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + + this.newExecutionDelay = this.previousExecutionDelay.sub(time.duration.days(4)); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, { + from: admin, + }); + this.grantTimestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + + this.receipt = receipt; + this.delay = this.previousExecutionDelay.sub(this.newExecutionDelay); // For shouldBehaveLikeDelay + }); + + it('emits event', function () { + expectEvent(this.receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: this.grantTimestamp.add(this.delay), + delay: this.newExecutionDelay, + newMember: false, + }); + }); + + shouldBehaveLikeDelay('execution delay effect', { + before() { + beforeEach('consume effect delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not change the execution delay yet', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.previousExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal(this.newExecutionDelay); // pendingDelay + expect(access[3]).to.be.bignumber.equal(this.grantTimestamp.add(this.delay)); // pendingDelayEffect + + // Not in effect yet + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + }); + }, + after() { + beforeEach('consume effect delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('changes the execution delay', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.newExecutionDelay.toString(), + ]); + }); + }, + }); + }); + }); + + describe('without grant delay', function () { + beforeEach('set granting delay', async function () { + // Delay granting + const grantDelay = 0; + await this.manager.$_setGrantDelay(ANOTHER_ROLE, grantDelay); + await time.increase(MINSETBACK); + }); + + describe('when increasing the execution delay', function () { + beforeEach('set increased new execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + + this.newExecutionDelay = this.previousExecutionDelay.add(time.duration.days(4)); + }); + + it('emits event and immediately changes the execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, { + from: admin, + }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + + expectEvent(receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp, + delay: this.newExecutionDelay, + newMember: false, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.newExecutionDelay.toString(), + ]); + }); + }); + + describe('when decreasing the execution delay', function () { + beforeEach('decrease execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + + this.newExecutionDelay = this.previousExecutionDelay.sub(time.duration.days(4)); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, { + from: admin, + }); + this.grantTimestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + + this.receipt = receipt; + this.delay = this.previousExecutionDelay.sub(this.newExecutionDelay); // For shouldBehaveLikeDelay + }); + + it('emits event', function () { + expectEvent(this.receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: this.grantTimestamp.add(this.delay), + delay: this.newExecutionDelay, + newMember: false, + }); + }); + + shouldBehaveLikeDelay('execution delay effect', { + before() { + beforeEach('consume effect delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not change the execution delay yet', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.previousExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal(this.newExecutionDelay); // pendingDelay + expect(access[3]).to.be.bignumber.equal(this.grantTimestamp.add(this.delay)); // pendingDelayEffect + + // Not in effect yet + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + }); + }, + after() { + beforeEach('consume effect delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('changes the execution delay', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.newExecutionDelay.toString(), + ]); + }); + }, + }); + }); + }); + }); + }); + + describe('#revokeRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', async function () { + const method = 'revokeRole(uint64,address)'; + const args = [ANOTHER_ROLE, someAddress]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + + // Need to be set before revoking + await this.manager.$_grantRole(...args, 0, 0); + }); + + shouldBehaveLikeRoleAdminOperation(ANOTHER_ADMIN); + }); + + describe('when role has been granted', function () { + beforeEach('grant role with grant delay', async function () { + this.grantDelay = time.duration.weeks(1); + await this.manager.$_grantRole(ANOTHER_ROLE, user, this.grantDelay, 0); + + this.delay = this.grantDelay; // For shouldBehaveLikeDelay + }); + + shouldBehaveLikeDelay('grant', { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('revokes a granted role that will take effect in the future', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + const { receipt } = await this.manager.revokeRole(ANOTHER_ROLE, user, { from: admin }); + expectEvent(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user }); + + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // effect + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('revokes a granted role that already took effect', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + '0', + ]); + + const { receipt } = await this.manager.revokeRole(ANOTHER_ROLE, user, { from: admin }); + expectEvent(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user }); + + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // effect + }); + }, + }); + }); + + describe('when role has not been granted', function () { + it('has no effect', async function () { + expect(await this.manager.hasRole(this.roles.SOME.id, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + const { receipt } = await this.manager.revokeRole(this.roles.SOME.id, user, { from: manager }); + expectEvent.notEmitted(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user }); + expect(await this.manager.hasRole(this.roles.SOME.id, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + }); + }); + + it('reverts revoking PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.revokeRole(this.roles.PUBLIC.id, user, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + }); + }); + + describe('self role operations', function () { + describe('#renounceRole', function () { + beforeEach('grant role', async function () { + this.role = { id: web3.utils.toBN(783164) }; + this.caller = user; + await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); + }); + + it('renounces a role', async function () { + expect(await this.manager.hasRole(this.role.id, this.caller).then(formatAccess)).to.be.deep.equal([ + true, + '0', + ]); + const { receipt } = await this.manager.renounceRole(this.role.id, this.caller, { + from: this.caller, + }); + expectEvent(receipt, 'RoleRevoked', { + roleId: this.role.id, + account: this.caller, + }); + expect(await this.manager.hasRole(this.role.id, this.caller).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + }); + + it('reverts if renouncing the PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.renounceRole(this.roles.PUBLIC.id, this.caller, { + from: this.caller, + }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + it('reverts if renouncing with bad caller confirmation', async function () { + await expectRevertCustomError( + this.manager.renounceRole(this.role.id, someAddress, { + from: this.caller, + }), + 'AccessManagerBadConfirmation', + [], + ); + }); + }); + }); + }); + }); + + describe('access managed target operations', function () { + describe('when calling a restricted target function', function () { + const method = 'fnRestricted()'; + + beforeEach('set required role', function () { + this.role = { id: web3.utils.toBN(3597243) }; + this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + }); + + describe('restrictions', function () { + beforeEach('set method and args', function () { + this.calldata = this.target.contract.methods[method]().encodeABI(); + this.caller = user; + }); + + shouldBehaveLikeAManagedRestrictedOperation(); + }); + + it('succeeds called by a role member', async function () { + await this.manager.$_grantRole(this.role.id, user, 0, 0); + + const { receipt } = await this.target.methods[method]({ + data: this.calldata, + from: user, + }); + expectEvent(receipt, 'CalledRestricted', { + caller: user, + }); + }); + }); + + describe('when calling a non-restricted target function', function () { + const method = 'fnUnrestricted()'; + + beforeEach('set required role', async function () { + this.role = { id: web3.utils.toBN(879435) }; + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + }); + + it('succeeds called by anyone', async function () { + const { receipt } = await this.target.methods[method]({ + data: this.calldata, + from: user, + }); + expectEvent(receipt, 'CalledUnrestricted', { + caller: user, + }); + }); + }); + }); + + describe('#schedule', function () { + const method = 'fnRestricted()'; + + beforeEach('set target function role', async function () { + this.role = { id: web3.utils.toBN(498305) }; + this.caller = user; + + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = this.target.contract.methods[method]().encodeABI(); + this.delay = time.duration.weeks(2); + }); + + describe('restrictions', function () { + shouldBehaveLikeCanCall({ + closed() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + open: { + callerIsTheManager: { + executing() { + it.skip('is not reachable because schedule is not restrictable'); + }, + notExecuting() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + afterGrantDelay() { + it('succeeds', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + afterGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('succeeds', async function () { + await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + }); + }, + callerHasNoExecutionDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + }, + }, + }); + }); + + it('schedules an operation at the specified execution date if it is larger than caller execution delay', async function () { + const { operationId, scheduledAt, receipt } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal(scheduledAt.add(this.delay)); + expectEvent(receipt, 'OperationScheduled', { + operationId, + nonce: '1', + schedule: scheduledAt.add(this.delay), + target: this.target.address, + data: this.calldata, + }); + }); + + it('schedules an operation at the minimum execution date if no specified execution date (when == 0)', async function () { + const executionDelay = await time.duration.hours(72); + await this.manager.$_grantRole(this.role.id, this.caller, 0, executionDelay); + + const timestamp = await time.latest(); + const scheduledAt = timestamp.addn(1); + await setNextBlockTimestamp(scheduledAt); + const { receipt } = await this.manager.schedule(this.target.address, this.calldata, 0, { + from: this.caller, + }); + + const operationId = await this.manager.hashOperation(this.caller, this.target.address, this.calldata); + + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal(scheduledAt.add(executionDelay)); + expectEvent(receipt, 'OperationScheduled', { + operationId, + nonce: '1', + schedule: scheduledAt.add(executionDelay), + target: this.target.address, + data: this.calldata, + }); + }); + + it('increases the nonce of an operation scheduled more than once', async function () { + // Setup and check initial nonce + const expectedOperationId = await web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address', 'address', 'bytes'], + [this.caller, this.target.address, this.calldata], + ), + ); + expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('0'); + + // Schedule + const op1 = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + expectEvent(op1.receipt, 'OperationScheduled', { + operationId: op1.operationId, + nonce: '1', + schedule: op1.scheduledAt.add(this.delay), + target: this.target.address, + data: this.calldata, + }); + expect(expectedOperationId).to.eq(op1.operationId); + + // Consume + await time.increase(this.delay); + await this.manager.$_consumeScheduledOp(expectedOperationId); + + // Check nonce + expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('1'); + + // Schedule again + const op2 = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + expectEvent(op2.receipt, 'OperationScheduled', { + operationId: op2.operationId, + nonce: '2', + schedule: op2.scheduledAt.add(this.delay), + target: this.target.address, + data: this.calldata, + }); + expect(expectedOperationId).to.eq(op2.operationId); + + // Check final nonce + expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('2'); + }); + + it('reverts if the specified execution date is before the current timestamp + caller execution delay', async function () { + const executionDelay = time.duration.weeks(1).add(this.delay); + await this.manager.$_grantRole(this.role.id, this.caller, 0, executionDelay); + + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + + it('reverts if an operation is already schedule', async function () { + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerAlreadyScheduled', + [operationId], + ); + }); + + it('panics scheduling calldata with less than 4 bytes', async function () { + const calldata = '0x1234'; // 2 bytes + + // Managed contract + await expectRevert.unspecified( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: calldata, + delay: this.delay, + }), + ); + + // Manager contract + await expectRevert.unspecified( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.manager.address, + calldata: calldata, + delay: this.delay, + }), + ); + }); + + it('reverts scheduling an unknown operation to the manager', async function () { + const calldata = '0x12345678'; + + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.manager.address, + calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.manager.address, calldata], + ); + }); + }); + + describe('#execute', function () { + const method = 'fnRestricted()'; + + beforeEach('set target function role', async function () { + this.role = { id: web3.utils.toBN(9825430) }; + this.caller = user; + + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); + + this.calldata = this.target.contract.methods[method]().encodeABI(); + }); + + describe('restrictions', function () { + shouldBehaveLikeCanCall({ + closed() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + open: { + callerIsTheManager: { + executing() { + it('succeeds', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + notExecuting() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + afterGrantDelay() { + beforeEach('define schedule delay', async function () { + // Consume previously set delay + await mine(); + this.scheduleIn = time.duration.days(21); + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + afterGrantDelay() { + beforeEach('define schedule delay', async function () { + // Consume previously set delay + await mine(); + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + beforeEach('define schedule delay', async function () { + this.scheduleIn = time.duration.days(15); + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }, + callerHasNoExecutionDelay() { + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + }, + }, + }); + }); + + it('executes with a delay consuming the scheduled operation', async function () { + const delay = time.duration.hours(4); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // Execution delay is needed so the operation is consumed + + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay, + }); + await time.increase(delay); + const { receipt } = await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + expectEvent(receipt, 'OperationExecuted', { + operationId, + nonce: '1', + }); + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal('0'); + }); + + it('executes with no delay consuming a scheduled operation', async function () { + const delay = time.duration.hours(4); + + // give caller an execution delay + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); + + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay, + }); + + // remove the execution delay + await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); + + await time.increase(delay); + const { receipt } = await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + expectEvent(receipt, 'OperationExecuted', { + operationId, + nonce: '1', + }); + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal('0'); + }); + + it('keeps the original _executionId after finishing the call', async function () { + const executionIdBefore = await getStorageAt(this.manager.address, EXECUTION_ID_STORAGE_SLOT); + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + const executionIdAfter = await getStorageAt(this.manager.address, EXECUTION_ID_STORAGE_SLOT); + expect(executionIdBefore).to.be.bignumber.equal(executionIdAfter); + }); + + it('reverts executing twice', async function () { + const delay = time.duration.hours(2); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // Execution delay is needed so the operation is consumed + + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay, + }); + await time.increase(delay); + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerNotScheduled', + [operationId], + ); + }); + }); + + describe('#consumeScheduledOp', function () { + beforeEach('define scheduling parameters', async function () { + const method = 'fnRestricted()'; + this.caller = this.target.address; + this.calldata = this.target.contract.methods[method]().encodeABI(); + this.role = { id: web3.utils.toBN(9834983) }; + + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.scheduleIn = time.duration.hours(10); // For shouldBehaveLikeSchedulableOperation + }); + + describe('when caller is not consuming scheduled operation', function () { + beforeEach('set consuming false', async function () { + await this.target.setIsConsumingScheduledOp(false, `0x${CONSUMING_SCHEDULE_STORAGE_SLOT.toString(16)}`); + }); + + it('reverts as AccessManagerUnauthorizedConsume', async function () { + await impersonate(this.caller); + await expectRevertCustomError( + this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedConsume', + [this.caller], + ); + }); + }); + + describe('when caller is consuming scheduled operation', function () { + beforeEach('set consuming true', async function () { + await this.target.setIsConsumingScheduledOp(true, `0x${CONSUMING_SCHEDULE_STORAGE_SLOT.toString(16)}`); + }); + + shouldBehaveLikeSchedulableOperation({ + scheduled: { + before() { + it('reverts as AccessManagerNotReady', async function () { + await impersonate(this.caller); + await expectRevertCustomError( + this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }), + 'AccessManagerNotReady', + [this.operationId], + ); + }); + }, + after() { + it('consumes the scheduled operation and resets timepoint', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal( + this.scheduledAt.add(this.scheduleIn), + ); + await impersonate(this.caller); + const { receipt } = await this.manager.consumeScheduledOp(this.caller, this.calldata, { + from: this.caller, + }); + expectEvent(receipt, 'OperationExecuted', { + operationId: this.operationId, + nonce: '1', + }); + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0'); + }); + }, + expired() { + it('reverts as AccessManagerExpired', async function () { + await impersonate(this.caller); + await expectRevertCustomError( + this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }), + 'AccessManagerExpired', + [this.operationId], + ); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await impersonate(this.caller); + await expectRevertCustomError( + this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }), + 'AccessManagerNotScheduled', + [this.operationId], + ); + }); + }, + }); + }); + }); + + describe('#cancelScheduledOp', function () { + const method = 'fnRestricted()'; + + beforeEach('setup scheduling', async function () { + this.caller = this.roles.SOME.members[0]; + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.roles.SOME.id); + await this.manager.$_grantRole(this.roles.SOME.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = await this.target.contract.methods[method]().encodeABI(); + this.scheduleIn = time.duration.days(10); // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation({ + scheduled: { + before() { + describe('when caller is the scheduler', function () { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller }); + }); + }); + + describe('when caller is an admin', function () { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { + from: this.roles.ADMIN.members[0], + }); + }); + }); + + describe('when caller is the role guardian', function () { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { + from: this.roles.SOME_GUARDIAN.members[0], + }); + }); + }); + + describe('when caller is any other account', function () { + it('reverts as AccessManagerUnauthorizedCancel', async function () { + await expectRevertCustomError( + this.manager.cancel(this.caller, this.target.address, this.calldata, { from: other }), + 'AccessManagerUnauthorizedCancel', + [other, this.caller, this.target.address, selector(method)], + ); + }); + }); + }, + after() { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller }); + }); + }, + expired() { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller }); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await expectRevertCustomError( + this.manager.cancel(this.caller, this.target.address, this.calldata), + 'AccessManagerNotScheduled', + [this.operationId], + ); + }); + }, + }); + + it('cancels an operation and resets schedule', async function () { + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.scheduleIn, + }); + const { receipt } = await this.manager.cancel(this.caller, this.target.address, this.calldata, { + from: this.caller, + }); + expectEvent(receipt, 'OperationCanceled', { + operationId, + nonce: '1', + }); + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.eq('0'); + }); + }); + + describe('with Ownable target contract', function () { + const roleId = web3.utils.toBN(1); + + beforeEach(async function () { + this.ownable = await Ownable.new(this.manager.address); + + // add user to role + await this.manager.$_grantRole(roleId, user, 0, 0); + }); + + it('initial state', async function () { + expect(await this.ownable.owner()).to.be.equal(this.manager.address); + }); + + describe('Contract is closed', function () { + beforeEach(async function () { + await this.manager.$_setTargetClosed(this.ownable.address, true); + }); + + it('directly call: reverts', async function () { + await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [user]); + }); + + it('relayed call (with role): reverts', async function () { + await expectRevertCustomError( + this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user }), + 'AccessManagerUnauthorizedCall', + [user, this.ownable.address, selector('$_checkOwner()')], + ); + }); + + it('relayed call (without role): reverts', async function () { + await expectRevertCustomError( + this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }), + 'AccessManagerUnauthorizedCall', + [other, this.ownable.address, selector('$_checkOwner()')], + ); + }); + }); + + describe('Contract is managed', function () { + describe('function is open to specific role', function () { + beforeEach(async function () { + await this.manager.$_setTargetFunctionRole(this.ownable.address, selector('$_checkOwner()'), roleId); + }); + + it('directly call: reverts', async function () { + await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [ + user, + ]); + }); + + it('relayed call (with role): success', async function () { + await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user }); + }); + + it('relayed call (without role): reverts', async function () { + await expectRevertCustomError( + this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }), + 'AccessManagerUnauthorizedCall', + [other, this.ownable.address, selector('$_checkOwner()')], + ); + }); + }); + + describe('function is open to public role', function () { + beforeEach(async function () { + await this.manager.$_setTargetFunctionRole( + this.ownable.address, + selector('$_checkOwner()'), + this.roles.PUBLIC.id, + ); + }); + + it('directly call: reverts', async function () { + await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [ + user, + ]); + }); + + it('relayed call (with role): success', async function () { + await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user }); + }); + + it('relayed call (without role): success', async function () { + await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AuthorityUtils.test.js b/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AuthorityUtils.test.js new file mode 100644 index 0000000..346be03 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/access/manager/AuthorityUtils.test.js @@ -0,0 +1,91 @@ +require('@openzeppelin/test-helpers'); + +const AuthorityUtils = artifacts.require('$AuthorityUtils'); +const NotAuthorityMock = artifacts.require('NotAuthorityMock'); +const AuthorityNoDelayMock = artifacts.require('AuthorityNoDelayMock'); +const AuthorityDelayMock = artifacts.require('AuthorityDelayMock'); +const AuthorityNoResponse = artifacts.require('AuthorityNoResponse'); + +contract('AuthorityUtils', function (accounts) { + const [user, other] = accounts; + + beforeEach(async function () { + this.mock = await AuthorityUtils.new(); + }); + + describe('canCallWithDelay', function () { + describe('when authority does not have a canCall function', function () { + beforeEach(async function () { + this.authority = await NotAuthorityMock.new(); + }); + + it('returns (immediate = 0, delay = 0)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority.address, + user, + other, + '0x12345678', + ); + expect(immediate).to.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }); + + describe('when authority has no delay', function () { + beforeEach(async function () { + this.authority = await AuthorityNoDelayMock.new(); + this.immediate = true; + await this.authority._setImmediate(this.immediate); + }); + + it('returns (immediate, delay = 0)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority.address, + user, + other, + '0x12345678', + ); + expect(immediate).to.equal(this.immediate); + expect(delay).to.be.bignumber.equal('0'); + }); + }); + + describe('when authority replies with a delay', function () { + beforeEach(async function () { + this.authority = await AuthorityDelayMock.new(); + this.immediate = true; + this.delay = web3.utils.toBN(42); + await this.authority._setImmediate(this.immediate); + await this.authority._setDelay(this.delay); + }); + + it('returns (immediate, delay)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority.address, + user, + other, + '0x12345678', + ); + expect(immediate).to.equal(this.immediate); + expect(delay).to.be.bignumber.equal(this.delay); + }); + }); + + describe('when authority replies with empty data', function () { + beforeEach(async function () { + this.authority = await AuthorityNoResponse.new(); + }); + + it('returns (immediate = 0, delay = 0)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority.address, + user, + other, + '0x12345678', + ); + expect(immediate).to.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/finance/VestingWallet.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/finance/VestingWallet.behavior.js new file mode 100644 index 0000000..afd4c04 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/finance/VestingWallet.behavior.js @@ -0,0 +1,59 @@ +const { time } = require('@nomicfoundation/hardhat-network-helpers'); +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +function releasedEvent(token, amount) { + return token ? ['ERC20Released', { token: token.address, amount }] : ['EtherReleased', { amount }]; +} + +function shouldBehaveLikeVesting(beneficiary) { + it('check vesting schedule', async function () { + const [vestedAmount, releasable, ...args] = this.token + ? ['vestedAmount(address,uint64)', 'releasable(address)', this.token.address] + : ['vestedAmount(uint64)', 'releasable()']; + + for (const timestamp of this.schedule) { + await time.increaseTo(timestamp); + const vesting = this.vestingFn(timestamp); + + expect(await this.mock.methods[vestedAmount](...args, timestamp)).to.be.bignumber.equal(vesting); + + expect(await this.mock.methods[releasable](...args)).to.be.bignumber.equal(vesting); + } + }); + + it('execute vesting schedule', async function () { + const [release, ...args] = this.token ? ['release(address)', this.token.address] : ['release()']; + + let released = web3.utils.toBN(0); + const before = await this.getBalance(beneficiary); + + { + const receipt = await this.mock.methods[release](...args); + + await expectEvent.inTransaction(receipt.tx, this.mock, ...releasedEvent(this.token, '0')); + + await this.checkRelease(receipt, beneficiary, '0'); + + expect(await this.getBalance(beneficiary)).to.be.bignumber.equal(before); + } + + for (const timestamp of this.schedule) { + await time.setNextBlockTimestamp(timestamp); + const vested = this.vestingFn(timestamp); + + const receipt = await this.mock.methods[release](...args); + await expectEvent.inTransaction(receipt.tx, this.mock, ...releasedEvent(this.token, vested.sub(released))); + + await this.checkRelease(receipt, beneficiary, vested.sub(released)); + + expect(await this.getBalance(beneficiary)).to.be.bignumber.equal(before.add(vested)); + + released = vested; + } + }); +} + +module.exports = { + shouldBehaveLikeVesting, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/finance/VestingWallet.test.js b/lib/openzeppelin-contracts-v5.0.0/test/finance/VestingWallet.test.js new file mode 100644 index 0000000..918e563 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/finance/VestingWallet.test.js @@ -0,0 +1,69 @@ +const { constants, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { web3 } = require('@openzeppelin/test-helpers/src/setup'); +const { expect } = require('chai'); +const { BNmin } = require('../helpers/math'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const VestingWallet = artifacts.require('VestingWallet'); +const ERC20 = artifacts.require('$ERC20'); + +const { shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); + +contract('VestingWallet', function (accounts) { + const [sender, beneficiary] = accounts; + + const amount = web3.utils.toBN(web3.utils.toWei('100')); + const duration = web3.utils.toBN(4 * 365 * 86400); // 4 years + + beforeEach(async function () { + this.start = (await time.latest()).addn(3600); // in 1 hour + this.mock = await VestingWallet.new(beneficiary, this.start, duration); + }); + + it('rejects zero address for beneficiary', async function () { + await expectRevertCustomError( + VestingWallet.new(constants.ZERO_ADDRESS, this.start, duration), + 'OwnableInvalidOwner', + [constants.ZERO_ADDRESS], + ); + }); + + it('check vesting contract', async function () { + expect(await this.mock.owner()).to.be.equal(beneficiary); + expect(await this.mock.start()).to.be.bignumber.equal(this.start); + expect(await this.mock.duration()).to.be.bignumber.equal(duration); + expect(await this.mock.end()).to.be.bignumber.equal(this.start.add(duration)); + }); + + describe('vesting schedule', function () { + beforeEach(async function () { + this.schedule = Array(64) + .fill() + .map((_, i) => web3.utils.toBN(i).mul(duration).divn(60).add(this.start)); + this.vestingFn = timestamp => BNmin(amount, amount.mul(timestamp.sub(this.start)).div(duration)); + }); + + describe('Eth vesting', function () { + beforeEach(async function () { + await web3.eth.sendTransaction({ from: sender, to: this.mock.address, value: amount }); + this.getBalance = account => web3.eth.getBalance(account).then(web3.utils.toBN); + this.checkRelease = () => {}; + }); + + shouldBehaveLikeVesting(beneficiary); + }); + + describe('ERC20 vesting', function () { + beforeEach(async function () { + this.token = await ERC20.new('Name', 'Symbol'); + this.getBalance = account => this.token.balanceOf(account); + this.checkRelease = (receipt, to, value) => + expectEvent.inTransaction(receipt.tx, this.token, 'Transfer', { from: this.mock.address, to, value }); + + await this.token.$_mint(this.mock.address, amount); + }); + + shouldBehaveLikeVesting(beneficiary); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/Governor.t.sol b/lib/openzeppelin-contracts-v5.0.0/test/governance/Governor.t.sol new file mode 100644 index 0000000..f631245 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/Governor.t.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {Governor} from "@openzeppelin/contracts/governance/Governor.sol"; + +contract GovernorInternalTest is Test, Governor { + constructor() Governor("") {} + + function testValidDescriptionForProposer(string memory description, address proposer, bool includeProposer) public { + if (includeProposer) { + description = string.concat(description, "#proposer=", Strings.toHexString(proposer)); + } + assertTrue(_isValidDescriptionForProposer(proposer, description)); + } + + function testInvalidDescriptionForProposer( + string memory description, + address commitProposer, + address actualProposer + ) public { + vm.assume(commitProposer != actualProposer); + description = string.concat(description, "#proposer=", Strings.toHexString(commitProposer)); + assertFalse(_isValidDescriptionForProposer(actualProposer, description)); + } + + // We don't need to truly implement implement the missing functions because we are just testing + // internal helpers. + + function clock() public pure override returns (uint48) {} + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public pure override returns (string memory) {} + + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) {} + + function votingDelay() public pure virtual override returns (uint256) {} + + function votingPeriod() public pure virtual override returns (uint256) {} + + function quorum(uint256) public pure virtual override returns (uint256) {} + + function hasVoted(uint256, address) public pure virtual override returns (bool) {} + + function _quorumReached(uint256) internal pure virtual override returns (bool) {} + + function _voteSucceeded(uint256) internal pure virtual override returns (bool) {} + + function _getVotes(address, uint256, bytes memory) internal pure virtual override returns (uint256) {} + + function _countVote(uint256, address, uint8, uint256, bytes memory) internal virtual override {} +} diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/Governor.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/Governor.test.js new file mode 100644 index 0000000..45cceba --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/Governor.test.js @@ -0,0 +1,1024 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const Enums = require('../helpers/enums'); +const { getDomain, domainType } = require('../helpers/eip712'); +const { GovernorHelper, proposalStatesToBitMap } = require('../helpers/governance'); +const { clockFromReceipt } = require('../helpers/time'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); +const { shouldBehaveLikeEIP6372 } = require('./utils/EIP6372.behavior'); +const { ZERO_BYTES32 } = require('@openzeppelin/test-helpers/src/constants'); + +const Governor = artifacts.require('$GovernorMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); +const ERC721 = artifacts.require('$ERC721'); +const ERC1155 = artifacts.require('$ERC1155'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); + +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 name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.chainId = await web3.eth.getChainId(); + try { + this.token = await Token.new(tokenName, tokenSymbol, tokenName, version); + } catch { + // ERC20VotesLegacyMock has a different construction that uses version='1' by default. + 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, mode); + + 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 }); + + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + '', + ); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver', 'Governor']); + 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('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'); + + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal('0'); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(false); + + // 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, + 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(); + + 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.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'), + }); + + await this.helper.waitForDeadline(); + + const txExecute = await this.helper.execute(); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + + 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.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.proposalEta(this.proposal.id)).to.be.bignumber.equal('0'); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(false); + }); + + 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('vote with signature', function () { + const sign = privateKey => async (contract, message) => { + const domain = await getDomain(contract); + return ethSigUtil.signTypedMessage(privateKey, { + data: { + primaryType: 'Ballot', + types: { + EIP712Domain: domainType(domain), + Ballot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + ], + }, + domain, + message, + }, + }); + }; + + afterEach('no other votes are cast for proposalId', async function () { + 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); + }); + + it('votes with an EOA signature', async function () { + const voterBySig = Wallet.generate(); + const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); + + await this.token.delegate(voterBySigAddress, { from: voter1 }); + + const nonce = await this.mock.nonces(voterBySigAddress); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + expectEvent( + await this.helper.vote({ + support: Enums.VoteType.For, + voter: voterBySigAddress, + nonce, + signature: sign(voterBySig.getPrivateKey()), + }), + 'VoteCast', + { + voter: voterBySigAddress, + support: Enums.VoteType.For, + }, + ); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, voterBySigAddress)).to.be.equal(true); + expect(await this.mock.nonces(voterBySigAddress)).to.be.bignumber.equal(nonce.addn(1)); + }); + + it('votes with a valid EIP-1271 signature', async function () { + const ERC1271WalletOwner = Wallet.generate(); + ERC1271WalletOwner.address = web3.utils.toChecksumAddress(ERC1271WalletOwner.getAddressString()); + + const wallet = await ERC1271WalletMock.new(ERC1271WalletOwner.address); + + await this.token.delegate(wallet.address, { from: voter1 }); + + const nonce = await this.mock.nonces(wallet.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + expectEvent( + await this.helper.vote({ + support: Enums.VoteType.For, + voter: wallet.address, + nonce, + signature: sign(ERC1271WalletOwner.getPrivateKey()), + }), + 'VoteCast', + { + voter: wallet.address, + support: Enums.VoteType.For, + }, + ); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, wallet.address)).to.be.equal(true); + expect(await this.mock.nonces(wallet.address)).to.be.bignumber.equal(nonce.addn(1)); + }); + + afterEach('no other votes are cast', async function () { + 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); + }); + }); + + describe('should revert', function () { + describe('on propose', function () { + it('if proposal already exists', async function () { + await this.helper.propose(); + await expectRevertCustomError(this.helper.propose(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Pending, + ZERO_BYTES32, + ]); + }); + + it('if proposer has below threshold votes', async function () { + const votes = web3.utils.toWei('10'); + const threshold = web3.utils.toWei('1000'); + await this.mock.$_setProposalThreshold(threshold); + await expectRevertCustomError(this.helper.propose({ from: voter1 }), 'GovernorInsufficientProposerVotes', [ + voter1, + votes, + threshold, + ]); + }); + }); + + describe('on vote', function () { + it('if proposal does not exist', async function () { + await expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorNonexistentProposal', + [this.proposal.id], + ); + }); + + it('if voting has not started', async function () { + await this.helper.propose(); + await expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorUnexpectedProposalState', + [this.proposal.id, Enums.ProposalState.Pending, proposalStatesToBitMap([Enums.ProposalState.Active])], + ); + }); + + it('if support value is invalid', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await expectRevertCustomError( + this.helper.vote({ support: web3.utils.toBN('255') }), + 'GovernorInvalidVoteType', + [], + ); + }); + + 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 expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorAlreadyCastVote', + [voter1], + ); + }); + + it('if voting is over', async function () { + await this.helper.propose(); + await this.helper.waitForDeadline(); + await expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorUnexpectedProposalState', + [this.proposal.id, Enums.ProposalState.Defeated, proposalStatesToBitMap([Enums.ProposalState.Active])], + ); + }); + }); + + describe('on vote by signature', function () { + beforeEach(async function () { + this.voterBySig = Wallet.generate(); + this.voterBySig.address = web3.utils.toChecksumAddress(this.voterBySig.getAddressString()); + + this.data = (contract, message) => + getDomain(contract).then(domain => ({ + primaryType: 'Ballot', + types: { + EIP712Domain: domainType(domain), + Ballot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + ], + }, + domain, + message, + })); + + this.signature = (contract, message) => + this.data(contract, message).then(data => + ethSigUtil.signTypedMessage(this.voterBySig.getPrivateKey(), { data }), + ); + + await this.token.delegate(this.voterBySig.address, { from: voter1 }); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + }); + + it('if signature does not match signer', async function () { + const nonce = await this.mock.nonces(this.voterBySig.address); + + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + signature: async (...params) => { + const sig = await this.signature(...params); + const tamperedSig = web3.utils.hexToBytes(sig); + tamperedSig[42] ^= 0xff; + return web3.utils.bytesToHex(tamperedSig); + }, + }; + + await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSignature', [voteParams.voter]); + }); + + it('if vote nonce is incorrect', async function () { + const nonce = await this.mock.nonces(this.voterBySig.address); + + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce: nonce.addn(1), + signature: this.signature, + }; + + await expectRevertCustomError( + this.helper.vote(voteParams), + // The signature check implies the nonce can't be tampered without changing the signer + 'GovernorInvalidSignature', + [voteParams.voter], + ); + }); + }); + + describe('on queue', function () { + it('always', async function () { + await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await expectRevertCustomError(this.helper.queue(), 'GovernorQueueNotImplemented', []); + }); + }); + + describe('on execute', function () { + it('if proposal does not exist', async function () { + await expectRevertCustomError(this.helper.execute(), 'GovernorNonexistentProposal', [this.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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('if receiver revert without reason', async function () { + 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 expectRevertCustomError(this.helper.execute(), 'FailedInnerCall', []); + }); + + it('if receiver revert with reason', async function () { + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + }); + }); + + describe('state', function () { + it('Unset', async function () { + await expectRevertCustomError(this.mock.state(this.proposal.id), 'GovernorNonexistentProposal', [ + this.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 expectRevertCustomError(this.helper.cancel('internal'), 'GovernorNonexistentProposal', [ + this.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 expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorUnexpectedProposalState', + [this.proposal.id, Enums.ProposalState.Canceled, proposalStatesToBitMap([Enums.ProposalState.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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.cancel('internal'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap( + [Enums.ProposalState.Canceled, Enums.ProposalState.Expired, Enums.ProposalState.Executed], + { inverted: true }, + ), + ]); + }); + }); + + describe('public', function () { + it('before proposal', async function () { + await expectRevertCustomError(this.helper.cancel('external'), 'GovernorNonexistentProposal', [ + this.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 expectRevertCustomError(this.helper.cancel('external', { from: owner }), 'GovernorOnlyProposer', [ + owner, + ]); + }); + + it('after vote started', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(1); // snapshot + 1 block + + await expectRevertCustomError(this.helper.cancel('external'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Pending]), + ]); + }); + + it('after vote', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + + await expectRevertCustomError(this.helper.cancel('external'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Pending]), + ]); + }); + + 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 expectRevertCustomError(this.helper.cancel('external'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Succeeded, + proposalStatesToBitMap([Enums.ProposalState.Pending]), + ]); + }); + + 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 expectRevertCustomError(this.helper.cancel('external'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Pending]), + ]); + }); + }); + }); + + describe('proposal length', function () { + it('empty', async function () { + this.helper.setProposal([], ''); + await expectRevertCustomError(this.helper.propose(), 'GovernorInvalidProposalLength', [0, 0, 0]); + }); + + it('mismatch #1', async function () { + this.helper.setProposal( + { + targets: [], + values: [web3.utils.toWei('0')], + data: [this.receiver.contract.methods.mockFunction().encodeABI()], + }, + '', + ); + await expectRevertCustomError(this.helper.propose(), 'GovernorInvalidProposalLength', [0, 1, 1]); + }); + + it('mismatch #2', async function () { + this.helper.setProposal( + { + targets: [this.receiver.address], + values: [], + data: [this.receiver.contract.methods.mockFunction().encodeABI()], + }, + '', + ); + await expectRevertCustomError(this.helper.propose(), 'GovernorInvalidProposalLength', [1, 1, 0]); + }); + + it('mismatch #3', async function () { + this.helper.setProposal( + { + targets: [this.receiver.address], + values: [web3.utils.toWei('0')], + data: [], + }, + '', + ); + await expectRevertCustomError(this.helper.propose(), 'GovernorInvalidProposalLength', [1, 0, 1]); + }); + }); + + describe('frontrun protection using description suffix', function () { + describe('without protection', function () { + describe('without suffix', function () { + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + + describe('with different suffix', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#wrong-suffix=${proposer}`, + ); + }); + + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + + describe('with proposer suffix but bad address part', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#proposer=0x3C44CdDdB6a900fa2b585dd299e03d12FA429XYZ`, // XYZ are not a valid hex char + ); + }); + + it('propose can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + }); + + describe('with protection via proposer suffix', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#proposer=${proposer}`, + ); + }); + + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else cannot propose', async function () { + await expectRevertCustomError(this.helper.propose({ from: voter1 }), 'GovernorRestrictedProposer', [ + voter1, + ]); + }); + }); + }); + + describe('onlyGovernance updates', function () { + it('setVotingDelay is protected', async function () { + await expectRevertCustomError(this.mock.setVotingDelay('0', { from: owner }), 'GovernorOnlyExecutor', [ + owner, + ]); + }); + + it('setVotingPeriod is protected', async function () { + await expectRevertCustomError(this.mock.setVotingPeriod('32', { from: owner }), 'GovernorOnlyExecutor', [ + owner, + ]); + }); + + it('setProposalThreshold is protected', async function () { + await expectRevertCustomError( + this.mock.setProposalThreshold('1000000000000000000', { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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 () { + const votingPeriod = 0; + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.setVotingPeriod(votingPeriod).encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + await expectRevertCustomError(this.helper.execute(), 'GovernorInvalidVotingPeriod', [votingPeriod]); + }); + + 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 }, + ); + }); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/TimelockController.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/TimelockController.test.js new file mode 100644 index 0000000..ce051e7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/TimelockController.test.js @@ -0,0 +1,1286 @@ +const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS, ZERO_BYTES32 } = constants; +const { proposalStatesToBitMap } = require('../helpers/governance'); + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../helpers/customError'); +const { OperationState } = require('../helpers/enums'); + +const TimelockController = artifacts.require('TimelockController'); +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); + +const salt = '0x025e7b0be353a74631ad648c667493c0e1cd31caa4cc2d3520fdc171ea0cc726'; // a random value + +function genOperation(target, value, data, predecessor, salt) { + const id = web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address', 'uint256', 'bytes', 'uint256', 'bytes32'], + [target, value, data, predecessor, salt], + ), + ); + return { id, target, value, data, predecessor, salt }; +} + +function genOperationBatch(targets, values, payloads, predecessor, salt) { + const id = web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address[]', 'uint256[]', 'bytes[]', 'uint256', 'bytes32'], + [targets, values, payloads, predecessor, salt], + ), + ); + return { id, targets, values, payloads, predecessor, salt }; +} + +contract('TimelockController', function (accounts) { + const [, admin, proposer, canceller, executor, other] = accounts; + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + beforeEach(async function () { + // Deploy new timelock + this.mock = await TimelockController.new(MINDELAY, [proposer], [executor], admin); + + expect(await this.mock.hasRole(CANCELLER_ROLE, proposer)).to.be.equal(true); + await this.mock.revokeRole(CANCELLER_ROLE, proposer, { from: admin }); + await this.mock.grantRole(CANCELLER_ROLE, canceller, { from: admin }); + + // Mocks + this.callreceivermock = await CallReceiverMock.new({ from: admin }); + this.implementation2 = await Implementation2.new({ from: admin }); + }); + + shouldSupportInterfaces(['ERC1155Receiver']); + + it('initial state', async function () { + expect(await this.mock.getMinDelay()).to.be.bignumber.equal(MINDELAY); + + expect(await this.mock.DEFAULT_ADMIN_ROLE()).to.be.equal(DEFAULT_ADMIN_ROLE); + expect(await this.mock.PROPOSER_ROLE()).to.be.equal(PROPOSER_ROLE); + expect(await this.mock.EXECUTOR_ROLE()).to.be.equal(EXECUTOR_ROLE); + expect(await this.mock.CANCELLER_ROLE()).to.be.equal(CANCELLER_ROLE); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, proposer))), + ).to.be.deep.equal([true, false, false]); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, canceller))), + ).to.be.deep.equal([false, true, false]); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, executor))), + ).to.be.deep.equal([false, false, true]); + }); + + it('optional admin', async function () { + const mock = await TimelockController.new(MINDELAY, [proposer], [executor], ZERO_ADDRESS, { from: other }); + + expect(await mock.hasRole(DEFAULT_ADMIN_ROLE, admin)).to.be.equal(false); + expect(await mock.hasRole(DEFAULT_ADMIN_ROLE, mock.address)).to.be.equal(true); + }); + + describe('methods', function () { + describe('operation hashing', function () { + it('hashOperation', async function () { + this.operation = genOperation( + '0x29cebefe301c6ce1bb36b58654fea275e1cacc83', + '0xf94fdd6e21da21d2', + '0xa3bc5104', + '0xba41db3be0a9929145cfe480bd0f1f003689104d275ae912099f925df424ef94', + '0x60d9109846ab510ed75c15f979ae366a8a2ace11d34ba9788c13ac296db50e6e', + ); + expect( + await this.mock.hashOperation( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ).to.be.equal(this.operation.id); + }); + + it('hashOperationBatch', async function () { + this.operation = genOperationBatch( + Array(8).fill('0x2d5f21620e56531c1d59c2df9b8e95d129571f71'), + Array(8).fill('0x2b993cfce932ccee'), + Array(8).fill('0xcf51966b'), + '0xce8f45069cc71d25f71ba05062de1a3974f9849b004de64a70998bca9d29c2e7', + '0x8952d74c110f72bfe5accdf828c74d53a7dfb71235dfa8a1e8c75d8576b372ff', + ); + expect( + await this.mock.hashOperationBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ).to.be.equal(this.operation.id); + }); + }); + describe('simple', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperation( + '0x31754f590B97fD975Eb86938f18Cc304E264D2F2', + 0, + '0x3bf92ccc', + ZERO_BYTES32, + salt, + ); + }); + + it('proposer can schedule', async function () { + const receipt = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + expectEvent(receipt, 'CallScheduled', { + id: this.operation.id, + index: web3.utils.toBN(0), + target: this.operation.target, + value: web3.utils.toBN(this.operation.value), + data: this.operation.data, + 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); + + expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( + web3.utils.toBN(block.timestamp).add(MINDELAY), + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + + await expectRevertCustomError( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Unset)], + ); + }); + + it('prevent non-proposer from committing', async function () { + await expectRevertCustomError( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: other }, + ), + `AccessControlUnauthorizedAccount`, + [other, PROPOSER_ROLE], + ); + }); + + it('enforce minimum delay', async function () { + await expectRevertCustomError( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1, + { from: proposer }, + ), + 'TimelockInsufficientDelay', + [MINDELAY, MINDELAY - 1], + ); + }); + + 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 () { + beforeEach(async function () { + this.operation = genOperation( + '0xAe22104DCD970750610E6FE15E623468A98b15f7', + 0, + '0x13e414de', + ZERO_BYTES32, + '0xc1059ed2dc130227aa1d1d539ac94c641306905c020436c636e19e3fab56fc7f', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expectRevertCustomError( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + ({ receipt: this.receipt, logs: this.logs } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('revert if execution comes too early 1/2', async function () { + await expectRevertCustomError( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + it('revert if execution comes too early 2/2', async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp - 5); // -1 is too tight, test sometime fails + + await expectRevertCustomError( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + describe('on time', function () { + beforeEach(async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp); + }); + + it('executor can reveal', async function () { + const receipt = await this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ); + expectEvent(receipt, 'CallExecuted', { + id: this.operation.id, + index: web3.utils.toBN(0), + target: this.operation.target, + value: web3.utils.toBN(this.operation.value), + data: this.operation.data, + }); + }); + + it('prevent non-executor from revealing', async function () { + await expectRevertCustomError( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: other }, + ), + `AccessControlUnauthorizedAccount`, + [other, 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 expectRevertCustomError( + this.mock.execute( + reentrantOperation.target, + reentrantOperation.value, + reentrantOperation.data, + reentrantOperation.predecessor, + reentrantOperation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [reentrantOperation.id, proposalStatesToBitMap(OperationState.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, + }); + }); + }); + }); + }); + }); + + describe('batch', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0xEd912250835c812D4516BBD80BdaEA1bB63a293C'), + Array(8).fill(0), + Array(8).fill('0x2fcb7a88'), + ZERO_BYTES32, + '0x6cf9d042ade5de78bed9ffd075eb4b2a4f6b1736932c2dc8af517d6e066f51f5', + ); + }); + + it('proposer can schedule', async function () { + const receipt = await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + for (const i in this.operation.targets) { + expectEvent(receipt, 'CallScheduled', { + id: this.operation.id, + index: web3.utils.toBN(i), + target: this.operation.targets[i], + value: web3.utils.toBN(this.operation.values[i]), + data: this.operation.payloads[i], + 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); + + expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( + web3.utils.toBN(block.timestamp).add(MINDELAY), + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Unset)], + ); + }); + + it('length of batch parameter must match #1', async function () { + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockInvalidOperationLength', + [this.operation.targets.length, this.operation.payloads.length, 0], + ); + }); + + it('length of batch parameter must match #1', async function () { + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockInvalidOperationLength', + [this.operation.targets.length, 0, this.operation.payloads.length], + ); + }); + + it('prevent non-proposer from committing', async function () { + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: other }, + ), + `AccessControlUnauthorizedAccount`, + [other, PROPOSER_ROLE], + ); + }); + + it('enforce minimum delay', async function () { + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1, + { from: proposer }, + ), + 'TimelockInsufficientDelay', + [MINDELAY, MINDELAY - 1], + ); + }); + }); + + describe('execute', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0x76E53CcEb05131Ef5248553bEBDb8F70536830b1'), + Array(8).fill(0), + Array(8).fill('0x58a60f63'), + ZERO_BYTES32, + '0x9545eeabc7a7586689191f78a5532443698538e54211b5bd4d7dc0fc0102b5c7', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + ({ receipt: this.receipt, logs: this.logs } = await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('revert if execution comes too early 1/2', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + it('revert if execution comes too early 2/2', async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp - 5); // -1 is to tight, test sometime fails + + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + describe('on time', function () { + beforeEach(async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp); + }); + + it('executor can reveal', async function () { + const receipt = await this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ); + for (const i in this.operation.targets) { + expectEvent(receipt, 'CallExecuted', { + id: this.operation.id, + index: web3.utils.toBN(i), + target: this.operation.targets[i], + value: web3.utils.toBN(this.operation.values[i]), + data: this.operation.payloads[i], + }); + } + }); + + it('prevent non-executor from revealing', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: other }, + ), + `AccessControlUnauthorizedAccount`, + [other, EXECUTOR_ROLE], + ); + }); + + it('length mismatch #1', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + [], + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockInvalidOperationLength', + [0, this.operation.payloads.length, this.operation.values.length], + ); + }); + + it('length mismatch #2', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockInvalidOperationLength', + [this.operation.targets.length, this.operation.payloads.length, 0], + ); + }); + + it('length mismatch #3', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockInvalidOperationLength', + [this.operation.targets.length, 0, this.operation.values.length], + ); + }); + + 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 expectRevertCustomError( + this.mock.executeBatch( + reentrantBatchOperation.targets, + reentrantBatchOperation.values, + reentrantBatchOperation.payloads, + reentrantBatchOperation.predecessor, + reentrantBatchOperation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [reentrantBatchOperation.id, proposalStatesToBitMap(OperationState.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], + }); + } + }); + }); + }); + + it('partial execution', async function () { + const operation = genOperationBatch( + [this.callreceivermock.address, this.callreceivermock.address, this.callreceivermock.address], + [0, 0, 0], + [ + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + ], + ZERO_BYTES32, + '0x8ac04aa0d6d66b8812fb41d39638d37af0a9ab11da507afd65c509f8ed079d3e', + ); + + await this.mock.scheduleBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevertCustomError( + this.mock.executeBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + { from: executor }, + ), + 'FailedInnerCall', + [], + ); + }); + }); + }); + + describe('cancel', function () { + beforeEach(async function () { + this.operation = genOperation( + '0xC6837c44AA376dbe1d2709F13879E040CAb653ca', + 0, + '0x296e58dd', + ZERO_BYTES32, + '0xa2485763600634800df9fc9646fb2c112cf98649c55f63dd1d9c7d13a64399d9', + ); + ({ receipt: this.receipt, logs: this.logs } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('canceller can cancel', async function () { + const receipt = await this.mock.cancel(this.operation.id, { from: canceller }); + expectEvent(receipt, 'Cancelled', { id: this.operation.id }); + }); + + it('cannot cancel invalid operation', async function () { + await expectRevertCustomError( + this.mock.cancel(constants.ZERO_BYTES32, { from: canceller }), + 'TimelockUnexpectedOperationState', + [constants.ZERO_BYTES32, proposalStatesToBitMap([OperationState.Waiting, OperationState.Ready])], + ); + }); + + it('prevent non-canceller from canceling', async function () { + await expectRevertCustomError( + this.mock.cancel(this.operation.id, { from: other }), + `AccessControlUnauthorizedAccount`, + [other, CANCELLER_ROLE], + ); + }); + }); + }); + + describe('maintenance', function () { + it('prevent unauthorized maintenance', async function () { + await expectRevertCustomError(this.mock.updateDelay(0, { from: other }), 'TimelockUnauthorizedCaller', [other]); + }); + + it('timelock scheduled maintenance', async function () { + const newDelay = time.duration.hours(6); + const operation = genOperation( + this.mock.address, + 0, + this.mock.contract.methods.updateDelay(newDelay.toString()).encodeABI(), + ZERO_BYTES32, + '0xf8e775b2c5f4d66fb5c7fa800f35ef518c262b6014b3c0aee6ea21bff157f108', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + const receipt = await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor }, + ); + expectEvent(receipt, 'MinDelayChange', { newDuration: newDelay.toString(), oldDuration: MINDELAY }); + + expect(await this.mock.getMinDelay()).to.be.bignumber.equal(newDelay); + }); + }); + + describe('dependency', function () { + beforeEach(async function () { + this.operation1 = genOperation( + '0xdE66bD4c97304200A95aE0AadA32d6d01A867E39', + 0, + '0x01dc731a', + ZERO_BYTES32, + '0x64e932133c7677402ead2926f86205e2ca4686aebecf5a8077627092b9bb2feb', + ); + this.operation2 = genOperation( + '0x3c7944a3F1ee7fc8c5A5134ba7c79D11c3A1FCa3', + 0, + '0x8f531849', + this.operation1.id, + '0x036e1311cac523f9548e6461e29fb1f8f9196b91910a41711ea22f5de48df07d', + ); + await this.mock.schedule( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + MINDELAY, + { from: proposer }, + ); + await this.mock.schedule( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + }); + + it('cannot execute before dependency', async function () { + await expectRevertCustomError( + this.mock.execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + { from: executor }, + ), + 'TimelockUnexecutedPredecessor', + [this.operation1.id], + ); + }); + + it('can execute after dependency', async function () { + await this.mock.execute( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + { from: executor }, + ); + await this.mock.execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + { from: executor }, + ); + }); + }); + + describe('usage scenario', function () { + this.timeout(10000); + + it('call', async function () { + const operation = genOperation( + this.implementation2.address, + 0, + this.implementation2.contract.methods.setValue(42).encodeABI(), + ZERO_BYTES32, + '0x8043596363daefc89977b25f9d9b4d06c3910959ef0c4d213557a903e1b555e2', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor }, + ); + + expect(await this.implementation2.getValue()).to.be.bignumber.equal(web3.utils.toBN(42)); + }); + + it('call reverting', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + ZERO_BYTES32, + '0xb1b1b276fdf1a28d1e00537ea73b04d56639128b08063c1a2f70a52e38cba693', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevertCustomError( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'FailedInnerCall', + [], + ); + }); + + it('call throw', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(), + ZERO_BYTES32, + '0xe5ca79f295fc8327ee8a765fe19afb58f4a0cbc5053642bfdd7e73bc68e0fc67', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + // Targeted function reverts with a panic code (0x1) + the timelock bubble the panic code + await expectRevert.unspecified( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + ); + }); + + it('call out of gas', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionOutOfGas().encodeABI(), + ZERO_BYTES32, + '0xf3274ce7c394c5b629d5215723563a744b817e1730cca5587c567099a14578fd', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevertCustomError( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + gas: '100000', + }), + 'FailedInnerCall', + [], + ); + }); + + it('call payable with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + ZERO_BYTES32, + '0x5ab73cd33477dcd36c1e05e28362719d0ed59a7b9ff14939de63a43073dc1f44', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor, value: 1 }, + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(1)); + }); + + it('call nonpayable with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunctionNonPayable().encodeABI(), + ZERO_BYTES32, + '0xb78edbd920c7867f187e5aa6294ae5a656cfbf0dea1ccdca3751b740d0f2bdf8', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await expectRevertCustomError( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'FailedInnerCall', + [], + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + it('call reverting with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + ZERO_BYTES32, + '0xdedb4563ef0095db01d81d3f2decf57cf83e4a72aa792af14c43a792b56f4de6', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await expectRevertCustomError( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'FailedInnerCall', + [], + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + }); + + 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(other, tokenId); + }); + + it('can receive an ERC721 safeTransfer', async function () { + await this.token.safeTransferFrom(other, this.mock.address, tokenId, { from: other }); + }); + }); + + 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(other, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it('can receive ERC1155 safeTransfer', async function () { + await this.token.safeTransferFrom( + other, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: other }, + ); + }); + + it('can receive ERC1155 safeBatchTransfer', async function () { + await this.token.safeBatchTransferFrom( + other, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: other }, + ); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorERC721.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorERC721.test.js new file mode 100644 index 0000000..22265cc --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorERC721.test.js @@ -0,0 +1,116 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper } = require('../../helpers/governance'); + +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; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockNFToken'; + const tokenSymbol = 'MTKN'; + 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'); + + 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, version); + this.mock = await Governor.new(name, this.token.address); + this.receiver = await CallReceiver.new(); + + this.helper = new GovernorHelper(this.mock, mode); + + 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 }); + + // 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('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: 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/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorPreventLateQuorum.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorPreventLateQuorum.test.js new file mode 100644 index 0000000..17ae05a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorPreventLateQuorum.test.js @@ -0,0 +1,195 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper } = require('../../helpers/governance'); +const { clockFromReceipt } = require('../../helpers/time'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +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; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + 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'); + + 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, version); + 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, mode); + + 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 }); + + // 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 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 expectRevertCustomError( + this.mock.setLateQuorumVoteExtension(0, { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorStorage.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorStorage.test.js new file mode 100644 index 0000000..99a9788 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorStorage.test.js @@ -0,0 +1,150 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../../helpers/customError'); +const Enums = require('../../helpers/enums'); +const { GovernorHelper, timelockSalt } = require('../../helpers/governance'); + +const Timelock = artifacts.require('TimelockController'); +const Governor = artifacts.require('$GovernorStorageMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); + +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + +contract('GovernorStorage', function (accounts) { + const [owner, voter1, voter2, voter3, voter4] = accounts; + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, version); + 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, mode); + + 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(DEFAULT_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 }); + + // 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', + timelockSalt(this.mock.address, this.proposal.shortProposal[3]), + ); + }); + + describe('proposal indexing', function () { + it('before propose', async function () { + expect(await this.mock.proposalCount()).to.be.bignumber.equal('0'); + + // panic code 0x32 (out-of-bound) + await expectRevert.unspecified(this.mock.proposalDetailsAt(0)); + + await expectRevertCustomError(this.mock.proposalDetails(this.proposal.id), 'GovernorNonexistentProposal', [ + this.proposal.id, + ]); + }); + + it('after propose', async function () { + await this.helper.propose(); + + expect(await this.mock.proposalCount()).to.be.bignumber.equal('1'); + + const proposalDetailsAt0 = await this.mock.proposalDetailsAt(0); + expect(proposalDetailsAt0[0]).to.be.bignumber.equal(this.proposal.id); + expect(proposalDetailsAt0[1]).to.be.deep.equal(this.proposal.targets); + expect(proposalDetailsAt0[2].map(x => x.toString())).to.be.deep.equal(this.proposal.values); + expect(proposalDetailsAt0[3]).to.be.deep.equal(this.proposal.fulldata); + expect(proposalDetailsAt0[4]).to.be.equal(this.proposal.descriptionHash); + + const proposalDetailsForId = await this.mock.proposalDetails(this.proposal.id); + expect(proposalDetailsForId[0]).to.be.deep.equal(this.proposal.targets); + expect(proposalDetailsForId[1].map(x => x.toString())).to.be.deep.equal(this.proposal.values); + expect(proposalDetailsForId[2]).to.be.deep.equal(this.proposal.fulldata); + expect(proposalDetailsForId[3]).to.be.equal(this.proposal.descriptionHash); + }); + }); + + it('queue and execute by id', 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.mock.queue(this.proposal.id); + await this.helper.waitForEta(); + const txExecute = await this.mock.execute(this.proposal.id); + + 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'); + }); + + it('cancel by id', async function () { + await this.helper.propose(); + const txCancel = await this.mock.cancel(this.proposal.id); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: this.proposal.id }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockAccess.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockAccess.test.js new file mode 100644 index 0000000..68df99e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockAccess.test.js @@ -0,0 +1,777 @@ +const { expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper, proposalStatesToBitMap } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { clockFromReceipt } = require('../../helpers/time'); +const { selector } = require('../../helpers/methods'); + +const AccessManager = artifacts.require('$AccessManager'); +const Governor = artifacts.require('$GovernorTimelockAccessMock'); +const AccessManagedTarget = artifacts.require('$AccessManagedTarget'); + +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + +const hashOperation = (caller, target, data) => + web3.utils.keccak256(web3.eth.abi.encodeParameters(['address', 'address', 'bytes'], [caller, target, data])); + +contract('GovernorTimelockAccess', function (accounts) { + const [admin, voter1, voter2, voter3, voter4, other] = accounts; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.token = await Token.new(tokenName, tokenSymbol, tokenName, version); + this.manager = await AccessManager.new(admin); + this.mock = await Governor.new( + name, + votingDelay, + votingPeriod, + 0, // proposal threshold + this.manager.address, + 0, // base delay + this.token.address, + 0, // quorum + ); + this.receiver = await AccessManagedTarget.new(this.manager.address); + + this.helper = new GovernorHelper(this.mock, mode); + + await web3.eth.sendTransaction({ from: admin, to: this.mock.address, value }); + + await this.token.$_mint(admin, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: admin }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: admin }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: admin }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: admin }); + + // default proposals + this.restricted = {}; + this.restricted.selector = this.receiver.contract.methods.fnRestricted().encodeABI(); + this.restricted.operation = { + target: this.receiver.address, + value: '0', + data: this.restricted.selector, + }; + this.restricted.operationId = hashOperation( + this.mock.address, + this.restricted.operation.target, + this.restricted.operation.data, + ); + + this.unrestricted = {}; + this.unrestricted.selector = this.receiver.contract.methods.fnUnrestricted().encodeABI(); + this.unrestricted.operation = { + target: this.receiver.address, + value: '0', + data: this.unrestricted.selector, + }; + this.unrestricted.operationId = hashOperation( + this.mock.address, + this.unrestricted.operation.target, + this.unrestricted.operation.data, + ); + + this.fallback = {}; + this.fallback.operation = { + target: this.receiver.address, + value: '0', + data: '0x1234', + }; + this.fallback.operationId = hashOperation( + this.mock.address, + this.fallback.operation.target, + this.fallback.operation.data, + ); + }); + + it('accepts ether transfers', async function () { + await web3.eth.sendTransaction({ from: admin, 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.accessManager()).to.be.equal(this.manager.address); + }); + + it('sets base delay (seconds)', async function () { + const baseDelay = time.duration.hours(10); + + // Only through governance + await expectRevertCustomError( + this.mock.setBaseDelaySeconds(baseDelay, { from: voter1 }), + 'GovernorOnlyExecutor', + [voter1], + ); + + this.proposal = await this.helper.setProposal( + [ + { + target: this.mock.address, + value: '0', + data: this.mock.contract.methods.setBaseDelaySeconds(baseDelay).encodeABI(), + }, + ], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + const receipt = await this.helper.execute(); + + expectEvent(receipt, 'BaseDelaySet', { + oldBaseDelaySeconds: '0', + newBaseDelaySeconds: baseDelay, + }); + + expect(await this.mock.baseDelaySeconds()).to.be.bignumber.eq(baseDelay); + }); + + it('sets access manager ignored', async function () { + const selectors = ['0x12345678', '0x87654321', '0xabcdef01']; + + // Only through governance + await expectRevertCustomError( + this.mock.setAccessManagerIgnored(other, selectors, true, { from: voter1 }), + 'GovernorOnlyExecutor', + [voter1], + ); + + // Ignore + const helperIgnore = new GovernorHelper(this.mock, mode); + await helperIgnore.setProposal( + [ + { + target: this.mock.address, + value: '0', + data: this.mock.contract.methods.setAccessManagerIgnored(other, selectors, true).encodeABI(), + }, + ], + 'descr', + ); + + await helperIgnore.propose(); + await helperIgnore.waitForSnapshot(); + await helperIgnore.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await helperIgnore.waitForDeadline(); + const ignoreReceipt = await helperIgnore.execute(); + + for (const selector of selectors) { + expectEvent(ignoreReceipt, 'AccessManagerIgnoredSet', { + target: other, + selector, + ignored: true, + }); + expect(await this.mock.isAccessManagerIgnored(other, selector)).to.be.true; + } + + // Unignore + const helperUnignore = new GovernorHelper(this.mock, mode); + await helperUnignore.setProposal( + [ + { + target: this.mock.address, + value: '0', + data: this.mock.contract.methods.setAccessManagerIgnored(other, selectors, false).encodeABI(), + }, + ], + 'descr', + ); + + await helperUnignore.propose(); + await helperUnignore.waitForSnapshot(); + await helperUnignore.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await helperUnignore.waitForDeadline(); + const unignoreReceipt = await helperUnignore.execute(); + + for (const selector of selectors) { + expectEvent(unignoreReceipt, 'AccessManagerIgnoredSet', { + target: other, + selector, + ignored: false, + }); + expect(await this.mock.isAccessManagerIgnored(other, selector)).to.be.false; + } + }); + + it('sets access manager ignored when target is the governor', async function () { + const other = this.mock.address; + const selectors = ['0x12345678', '0x87654321', '0xabcdef01']; + + await this.helper.setProposal( + [ + { + target: this.mock.address, + value: '0', + data: this.mock.contract.methods.setAccessManagerIgnored(other, selectors, true).encodeABI(), + }, + ], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + const receipt = await this.helper.execute(); + + for (const selector of selectors) { + expectEvent(receipt, 'AccessManagerIgnoredSet', { + target: other, + selector, + ignored: true, + }); + expect(await this.mock.isAccessManagerIgnored(other, selector)).to.be.true; + } + }); + + describe('base delay only', function () { + for (const [delay, queue] of [ + [0, true], + [0, false], + [1000, true], + ]) { + it(`delay ${delay}, ${queue ? 'with' : 'without'} queuing`, async function () { + await this.mock.$_setBaseDelaySeconds(delay); + + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([false]); + expect(withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + if (await this.mock.proposalNeedsQueuing(this.proposal.id)) { + const txQueue = await this.helper.queue(); + expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id }); + } + if (delay > 0) { + await this.helper.waitForEta(); + } + const txExecute = await this.helper.execute(); + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + expectEvent.inTransaction(txExecute, this.receiver, 'CalledUnrestricted'); + }); + } + }); + + it('reverts when an operation is executed before eta', async function () { + const delay = time.duration.hours(2); + await this.mock.$_setBaseDelaySeconds(delay); + + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(true); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([false]); + expect(withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await expectRevertCustomError(this.helper.execute(), 'GovernorUnmetDelay', [ + this.proposal.id, + await this.mock.proposalEta(this.proposal.id), + ]); + }); + + it('reverts with a proposal including multiple operations but one of those was cancelled in the manager', async function () { + const delay = time.duration.hours(2); + const roleId = '1'; + + await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, { + from: admin, + }); + await this.manager.grantRole(roleId, this.mock.address, delay, { from: admin }); + + // Set proposals + const original = new GovernorHelper(this.mock, mode); + await original.setProposal([this.restricted.operation, this.unrestricted.operation], 'descr'); + + // Go through all the governance process + await original.propose(); + expect(await this.mock.proposalNeedsQueuing(original.currentProposal.id)).to.be.eq(true); + const { + delay: planDelay, + indirect, + withDelay, + } = await this.mock.proposalExecutionPlan(original.currentProposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([true, false]); + expect(withDelay).to.deep.eq([true, false]); + await original.waitForSnapshot(); + await original.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await original.waitForDeadline(); + await original.queue(); + await original.waitForEta(); + + // Suddenly cancel one of the proposed operations in the manager + await this.manager.cancel(this.mock.address, this.restricted.operation.target, this.restricted.operation.data, { + from: admin, + }); + + // Reschedule the same operation in a different proposal to avoid "AccessManagerNotScheduled" error + const rescheduled = new GovernorHelper(this.mock, mode); + await rescheduled.setProposal([this.restricted.operation], 'descr'); + await rescheduled.propose(); + await rescheduled.waitForSnapshot(); + await rescheduled.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await rescheduled.waitForDeadline(); + await rescheduled.queue(); // This will schedule it again in the manager + await rescheduled.waitForEta(); + + // Attempt to execute + await expectRevertCustomError(original.execute(), 'GovernorMismatchedNonce', [ + original.currentProposal.id, + 1, + 2, + ]); + }); + + it('single operation with access manager delay', async function () { + const delay = 1000; + const roleId = '1'; + + await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, { + from: admin, + }); + await this.manager.grantRole(roleId, this.mock.address, delay, { from: admin }); + + this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(true); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([true]); + expect(withDelay).to.deep.eq([true]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + 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.manager, 'OperationScheduled', { + operationId: this.restricted.operationId, + nonce: '1', + schedule: web3.utils.toBN(await clockFromReceipt.timestamp(txQueue.receipt)).addn(delay), + caller: this.mock.address, + target: this.restricted.operation.target, + data: this.restricted.operation.data, + }); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txExecute.tx, this.manager, 'OperationExecuted', { + operationId: this.restricted.operationId, + nonce: '1', + }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'CalledRestricted'); + }); + + it('bundle of varied operations', async function () { + const managerDelay = 1000; + const roleId = '1'; + + const baseDelay = managerDelay * 2; + + await this.mock.$_setBaseDelaySeconds(baseDelay); + + await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, { + from: admin, + }); + await this.manager.grantRole(roleId, this.mock.address, managerDelay, { from: admin }); + + this.proposal = await this.helper.setProposal( + [this.restricted.operation, this.unrestricted.operation, this.fallback.operation], + 'descr', + ); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(true); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(baseDelay)); + expect(indirect).to.deep.eq([true, false, false]); + expect(withDelay).to.deep.eq([true, false, false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + 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.manager, 'OperationScheduled', { + operationId: this.restricted.operationId, + nonce: '1', + schedule: web3.utils.toBN(await clockFromReceipt.timestamp(txQueue.receipt)).addn(baseDelay), + caller: this.mock.address, + target: this.restricted.operation.target, + data: this.restricted.operation.data, + }); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txExecute.tx, this.manager, 'OperationExecuted', { + operationId: this.restricted.operationId, + nonce: '1', + }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'CalledRestricted'); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'CalledUnrestricted'); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'CalledFallback'); + }); + + describe('cancel', function () { + const delay = 1000; + const roleId = '1'; + + beforeEach(async function () { + await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, { + from: admin, + }); + await this.manager.grantRole(roleId, this.mock.address, delay, { from: admin }); + }); + + it('cancels restricted with delay after queue (internal)', async function () { + this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(true); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([true]); + expect(withDelay).to.deep.eq([true]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + const txCancel = await this.helper.cancel('internal'); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txCancel.tx, this.manager, 'OperationCanceled', { + operationId: this.restricted.operationId, + nonce: '1', + }); + + await this.helper.waitForEta(); + await expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('cancels restricted with queueing if the same operation is part of a more recent proposal (internal)', async function () { + // Set proposals + const original = new GovernorHelper(this.mock, mode); + await original.setProposal([this.restricted.operation], 'descr'); + + // Go through all the governance process + await original.propose(); + expect(await this.mock.proposalNeedsQueuing(original.currentProposal.id)).to.be.eq(true); + const { + delay: planDelay, + indirect, + withDelay, + } = await this.mock.proposalExecutionPlan(original.currentProposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([true]); + expect(withDelay).to.deep.eq([true]); + await original.waitForSnapshot(); + await original.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await original.waitForDeadline(); + await original.queue(); + + // Cancel the operation in the manager + await this.manager.cancel( + this.mock.address, + this.restricted.operation.target, + this.restricted.operation.data, + { from: admin }, + ); + + // Another proposal is added with the same operation + const rescheduled = new GovernorHelper(this.mock, mode); + await rescheduled.setProposal([this.restricted.operation], 'another descr'); + + // Queue the new proposal + await rescheduled.propose(); + await rescheduled.waitForSnapshot(); + await rescheduled.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await rescheduled.waitForDeadline(); + await rescheduled.queue(); // This will schedule it again in the manager + + // Cancel + const eta = await this.mock.proposalEta(rescheduled.currentProposal.id); + const txCancel = await original.cancel('internal'); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: original.currentProposal.id }); + + await time.increase(eta); // waitForEta() + await expectRevertCustomError(original.execute(), 'GovernorUnexpectedProposalState', [ + original.currentProposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('cancels unrestricted with queueing (internal)', async function () { + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(indirect).to.deep.eq([false]); + expect(withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + const eta = await this.mock.proposalEta(this.proposal.id); + const txCancel = await this.helper.cancel('internal'); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: this.proposal.id }); + + await time.increase(eta); // waitForEta() + await expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('cancels unrestricted without queueing (internal)', async function () { + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(indirect).to.deep.eq([false]); + expect(withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + // await this.helper.queue(); + + // const eta = await this.mock.proposalEta(this.proposal.id); + const txCancel = await this.helper.cancel('internal'); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: this.proposal.id }); + + // await time.increase(eta); // waitForEta() + await expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('cancels calls already canceled by guardian', async function () { + const operationA = { target: this.receiver.address, data: this.restricted.selector + '00' }; + const operationB = { target: this.receiver.address, data: this.restricted.selector + '01' }; + const operationC = { target: this.receiver.address, data: this.restricted.selector + '02' }; + const operationAId = hashOperation(this.mock.address, operationA.target, operationA.data); + const operationBId = hashOperation(this.mock.address, operationB.target, operationB.data); + + const proposal1 = new GovernorHelper(this.mock, mode); + const proposal2 = new GovernorHelper(this.mock, mode); + proposal1.setProposal([operationA, operationB], 'proposal A+B'); + proposal2.setProposal([operationA, operationC], 'proposal A+C'); + + for (const p of [proposal1, proposal2]) { + await p.propose(); + await p.waitForSnapshot(); + await p.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await p.waitForDeadline(); + } + + // Can queue the first proposal + await proposal1.queue(); + + // Cannot queue the second proposal: operation A already scheduled with delay + await expectRevertCustomError(proposal2.queue(), 'AccessManagerAlreadyScheduled', [operationAId]); + + // Admin cancels operation B on the manager + await this.manager.cancel(this.mock.address, operationB.target, operationB.data, { from: admin }); + + // Still cannot queue the second proposal: operation A already scheduled with delay + await expectRevertCustomError(proposal2.queue(), 'AccessManagerAlreadyScheduled', [operationAId]); + + await proposal1.waitForEta(); + + // Cannot execute first proposal: operation B has been canceled + await expectRevertCustomError(proposal1.execute(), 'AccessManagerNotScheduled', [operationBId]); + + // Cancel the first proposal to release operation A + await proposal1.cancel('internal'); + + // can finally queue the second proposal + await proposal2.queue(); + + await proposal2.waitForEta(); + + // Can execute second proposal + await proposal2.execute(); + }); + }); + + describe('ignore AccessManager', function () { + it('defaults', async function () { + expect(await this.mock.isAccessManagerIgnored(this.receiver.address, this.restricted.selector)).to.equal( + false, + ); + expect(await this.mock.isAccessManagerIgnored(this.mock.address, '0x12341234')).to.equal(true); + }); + + it('internal setter', async function () { + const p1 = { target: this.receiver.address, selector: this.restricted.selector, ignored: true }; + const tx1 = await this.mock.$_setAccessManagerIgnored(p1.target, p1.selector, p1.ignored); + expect(await this.mock.isAccessManagerIgnored(p1.target, p1.selector)).to.equal(p1.ignored); + expectEvent(tx1, 'AccessManagerIgnoredSet', p1); + + const p2 = { target: this.mock.address, selector: '0x12341234', ignored: false }; + const tx2 = await this.mock.$_setAccessManagerIgnored(p2.target, p2.selector, p2.ignored); + expect(await this.mock.isAccessManagerIgnored(p2.target, p2.selector)).to.equal(p2.ignored); + expectEvent(tx2, 'AccessManagerIgnoredSet', p2); + }); + + it('external setter', async function () { + const setAccessManagerIgnored = (...args) => + this.mock.contract.methods.setAccessManagerIgnored(...args).encodeABI(); + + await this.helper.setProposal( + [ + { + target: this.mock.address, + data: setAccessManagerIgnored( + this.receiver.address, + [this.restricted.selector, this.unrestricted.selector], + true, + ), + value: '0', + }, + { + target: this.mock.address, + data: setAccessManagerIgnored(this.mock.address, ['0x12341234', '0x67896789'], false), + value: '0', + }, + ], + 'descr', + ); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(indirect).to.deep.eq([]); // Governor operations ignore access manager + expect(withDelay).to.deep.eq([]); // Governor operations ignore access manager + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + const tx = await this.helper.execute(); + + expectEvent(tx, 'AccessManagerIgnoredSet'); + + expect(await this.mock.isAccessManagerIgnored(this.receiver.address, this.restricted.selector)).to.equal( + true, + ); + expect(await this.mock.isAccessManagerIgnored(this.receiver.address, this.unrestricted.selector)).to.equal( + true, + ); + + expect(await this.mock.isAccessManagerIgnored(this.mock.address, '0x12341234')).to.equal(false); + expect(await this.mock.isAccessManagerIgnored(this.mock.address, '0x67896789')).to.equal(false); + }); + + it('locked function', async function () { + const setAccessManagerIgnored = selector('setAccessManagerIgnored(address,bytes4[],bool)'); + await expectRevertCustomError( + this.mock.$_setAccessManagerIgnored(this.mock.address, setAccessManagerIgnored, true), + 'GovernorLockedIgnore', + [], + ); + await this.mock.$_setAccessManagerIgnored(this.receiver.address, setAccessManagerIgnored, true); + }); + + it('ignores access manager', async function () { + const amount = 100; + + const target = this.token.address; + const data = this.token.contract.methods.transfer(voter4, amount).encodeABI(); + const selector = data.slice(0, 10); + await this.token.$_mint(this.mock.address, amount); + + const roleId = '1'; + await this.manager.setTargetFunctionRole(target, [selector], roleId, { from: admin }); + await this.manager.grantRole(roleId, this.mock.address, 0, { from: admin }); + + const proposal = await this.helper.setProposal([{ target, data, value: '0' }], '1'); + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const plan = await this.mock.proposalExecutionPlan(proposal.id); + expect(plan.delay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(plan.indirect).to.deep.eq([true]); + expect(plan.withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await expectRevertCustomError(this.helper.execute(), 'ERC20InsufficientBalance', [ + this.manager.address, + 0, + amount, + ]); + + await this.mock.$_setAccessManagerIgnored(target, selector, true); + + const proposalIgnored = await this.helper.setProposal([{ target, data, value: '0' }], '2'); + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const planIgnored = await this.mock.proposalExecutionPlan(proposalIgnored.id); + expect(planIgnored.delay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(planIgnored.indirect).to.deep.eq([false]); + expect(planIgnored.withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + const tx = await this.helper.execute(); + expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.mock.address }); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockCompound.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockCompound.test.js new file mode 100644 index 0000000..e9d6f83 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockCompound.test.js @@ -0,0 +1,441 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper, proposalStatesToBitMap } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { computeCreateAddress } = require('../../helpers/create'); +const { clockFromReceipt } = require('../../helpers/time'); + +const Timelock = artifacts.require('CompTimelock'); +const Governor = artifacts.require('$GovernorTimelockCompoundMock'); +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' }, +]; + +contract('GovernorTimelockCompound', function (accounts) { + const [owner, voter1, voter2, voter3, voter4, other] = accounts; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + const defaultDelay = 2 * 86400; + + 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, version); + + // Need to predict governance address to set it as timelock admin with a delayed transfer + const nonce = await web3.eth.getTransactionCount(deployer); + const predictGovernor = computeCreateAddress(deployer, nonce + 1); + + this.timelock = await Timelock.new(predictGovernor, defaultDelay); + 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, 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.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + }, + ], + '', + ); + }); + + 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 () { + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal('0'); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(true); + + 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 = web3.utils.toBN(await clockFromReceipt.timestamp(txQueue.receipt)).addn(defaultDelay); + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal(eta); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(true); + + 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 expectRevertCustomError(this.helper.queue(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Queued, + proposalStatesToBitMap([Enums.ProposalState.Succeeded]), + ]); + }); + + 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(), + }; + const { id } = 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 expectRevertCustomError(this.helper.queue(), 'GovernorAlreadyQueuedProposal', [id]); + await expectRevertCustomError(this.helper.execute(), 'GovernorNotQueuedProposal', [id]); + }); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorNotQueuedProposal', [this.proposal.id]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Expired, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + }); + + describe('on 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't receive an ERC721 safeTransfer", async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(owner, this.mock.address, tokenId, { from: owner }), + 'GovernorDisabledDeposit', + [], + ); + }); + }); + + 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't receive ERC1155 safeTransfer", async function () { + await expectRevertCustomError( + this.token.safeTransferFrom( + owner, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: owner }, + ), + 'GovernorDisabledDeposit', + [], + ); + }); + + it("can't receive ERC1155 safeBatchTransfer", async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + owner, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: owner }, + ), + 'GovernorDisabledDeposit', + [], + ); + }); + }); + }); + }); + + 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 expectRevertCustomError(this.helper.queue(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + }); + + describe('onlyGovernance', function () { + describe('relay', function () { + beforeEach(async function () { + await this.token.$_mint(this.mock.address, 1); + }); + + it('is protected', async function () { + await expectRevertCustomError( + this.mock.relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI(), { + from: owner, + }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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 expectRevertCustomError( + this.mock.updateTimelock(this.newTimelock.address, { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockControl.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockControl.test.js new file mode 100644 index 0000000..ec03d61 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorTimelockControl.test.js @@ -0,0 +1,515 @@ +const { constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper, proposalStatesToBitMap, timelockSalt } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { clockFromReceipt } = require('../../helpers/time'); + +const Timelock = artifacts.require('TimelockController'); +const Governor = artifacts.require('$GovernorTimelockControlMock'); +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' }, +]; + +contract('GovernorTimelockControl', function (accounts) { + const [owner, voter1, voter2, voter3, voter4, other] = accounts; + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + const delay = 3600; + + 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, version); + this.timelock = await Timelock.new(delay, [], [], 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, mode); + + 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 }); + + // 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(DEFAULT_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 }); + + // 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', + timelockSalt(this.mock.address, this.proposal.shortProposal[3]), + ); + }); + + 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 () { + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal('0'); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(true); + + 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 eta = web3.utils.toBN(await clockFromReceipt.timestamp(txQueue.receipt)).addn(delay); + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal(eta); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(true); + + 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 expectRevertCustomError(this.helper.queue(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Queued, + proposalStatesToBitMap([Enums.ProposalState.Succeeded]), + ]); + }); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'TimelockUnexpectedOperationState', [ + this.proposal.timelockid, + proposalStatesToBitMap(Enums.OperationState.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 expectRevertCustomError(this.helper.execute(), 'TimelockUnexpectedOperationState', [ + this.proposal.timelockid, + proposalStatesToBitMap(Enums.OperationState.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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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', + timelockSalt(this.mock.address, this.proposal.shortProposal[3]), + ); + + await expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + }); + }); + + 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 expectRevertCustomError(this.helper.queue(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError( + this.mock.relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI(), { + from: owner, + }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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 () { + const target = this.mock.address; + const value = web3.utils.toWei('0'); + const data = this.mock.contract.methods.relay(constants.ZERO_ADDRESS, 0, '0x').encodeABI(); + const predecessor = constants.ZERO_BYTES32; + const salt = constants.ZERO_BYTES32; + + await this.timelock.schedule(target, value, data, predecessor, salt, delay, { from: owner }); + + await time.increase(delay); + + await expectRevertCustomError( + this.timelock.execute(target, value, data, predecessor, salt, { from: owner }), + 'QueueEmpty', // Bubbled up from Governor + [], + ); + }); + }); + + describe('updateTimelock', function () { + beforeEach(async function () { + this.newTimelock = await Timelock.new( + delay, + [this.mock.address], + [this.mock.address], + constants.ZERO_ADDRESS, + ); + }); + + it('is protected', async function () { + await expectRevertCustomError( + this.mock.updateTimelock(this.newTimelock.address, { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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); + }); + }); + + describe('on 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't receive an ERC721 safeTransfer", async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(owner, this.mock.address, tokenId, { from: owner }), + 'GovernorDisabledDeposit', + [], + ); + }); + }); + + 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't receive ERC1155 safeTransfer", async function () { + await expectRevertCustomError( + this.token.safeTransferFrom( + owner, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: owner }, + ), + 'GovernorDisabledDeposit', + [], + ); + }); + + it("can't receive ERC1155 safeBatchTransfer", async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + owner, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: owner }, + ), + 'GovernorDisabledDeposit', + [], + ); + }); + }); + }); + }); + + 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/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorVotesQuorumFraction.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorVotesQuorumFraction.test.js new file mode 100644 index 0000000..ece9c78 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorVotesQuorumFraction.test.js @@ -0,0 +1,167 @@ +const { expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper, proposalStatesToBitMap } = require('../../helpers/governance'); +const { clock } = require('../../helpers/time'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +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; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + 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'); + + 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, version); + this.mock = await Governor.new(name, votingDelay, votingPeriod, 0, this.token.address, ratio); + this.receiver = await CallReceiver.new(); + + this.helper = new GovernorHelper(this.mock, mode); + + 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 }); + + // 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 clock[mode]().then(timepoint => this.mock.quorum(timepoint - 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Defeated, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + describe('onlyGovernance updates', function () { + it('updateQuorumNumerator is protected', async function () { + await expectRevertCustomError( + this.mock.updateQuorumNumerator(newRatio, { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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 () { + const quorumNumerator = 101; + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.updateQuorumNumerator(quorumNumerator).encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + const quorumDenominator = await this.mock.quorumDenominator(); + + await expectRevertCustomError(this.helper.execute(), 'GovernorInvalidQuorumFraction', [ + quorumNumerator, + quorumDenominator, + ]); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorWithParams.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorWithParams.test.js new file mode 100644 index 0000000..35da3a0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/extensions/GovernorWithParams.test.js @@ -0,0 +1,277 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const Enums = require('../../helpers/enums'); +const { getDomain, domainType } = require('../../helpers/eip712'); +const { GovernorHelper } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const Governor = artifacts.require('$GovernorWithParamsMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); + +const rawParams = { + 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; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, version); + this.mock = await Governor.new(name, this.token.address); + this.receiver = await CallReceiver.new(); + + this.helper = new GovernorHelper(this.mock, mode); + + 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 }); + + // 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('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); + }); + + it('Voting with params is properly supported', async function () { + await this.helper.propose({ from: proposer }); + 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, + }, + { 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); + }); + + describe('voting by signature', function () { + beforeEach(async function () { + this.voterBySig = Wallet.generate(); + this.voterBySig.address = web3.utils.toChecksumAddress(this.voterBySig.getAddressString()); + + this.data = (contract, message) => + getDomain(contract).then(domain => ({ + primaryType: 'ExtendedBallot', + types: { + EIP712Domain: domainType(domain), + ExtendedBallot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { name: 'reason', type: 'string' }, + { name: 'params', type: 'bytes' }, + ], + }, + domain, + message, + })); + + this.sign = privateKey => async (contract, message) => + ethSigUtil.signTypedMessage(privateKey, { data: await this.data(contract, message) }); + }); + + it('supports EOA signatures', async function () { + await this.token.delegate(this.voterBySig.address, { from: voter2 }); + + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); + + const nonce = await this.mock.nonces(this.voterBySig.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + const tx = await this.helper.vote({ + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + reason: 'no particular reason', + params: encodedParams, + signature: this.sign(this.voterBySig.getPrivateKey()), + }); + + expectEvent(tx, 'CountParams', { ...rawParams }); + expectEvent(tx, 'VoteCastWithParams', { + voter: this.voterBySig.address, + 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); + expect(await this.mock.nonces(this.voterBySig.address)).to.be.bignumber.equal(nonce.addn(1)); + }); + + it('supports EIP-1271 signature signatures', async function () { + const ERC1271WalletOwner = Wallet.generate(); + ERC1271WalletOwner.address = web3.utils.toChecksumAddress(ERC1271WalletOwner.getAddressString()); + + const wallet = await ERC1271WalletMock.new(ERC1271WalletOwner.address); + + await this.token.delegate(wallet.address, { from: voter2 }); + + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); + + const nonce = await this.mock.nonces(wallet.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + const tx = await this.helper.vote({ + support: Enums.VoteType.For, + voter: wallet.address, + nonce, + reason: 'no particular reason', + params: encodedParams, + signature: this.sign(ERC1271WalletOwner.getPrivateKey()), + }); + + expectEvent(tx, 'CountParams', { ...rawParams }); + expectEvent(tx, 'VoteCastWithParams', { + voter: wallet.address, + 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); + expect(await this.mock.nonces(wallet.address)).to.be.bignumber.equal(nonce.addn(1)); + }); + + it('reverts if signature does not match signer', async function () { + await this.token.delegate(this.voterBySig.address, { from: voter2 }); + + const nonce = await this.mock.nonces(this.voterBySig.address); + + const signature = this.sign(this.voterBySig.getPrivateKey()); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + signature: async (...params) => { + const sig = await signature(...params); + const tamperedSig = web3.utils.hexToBytes(sig); + tamperedSig[42] ^= 0xff; + return web3.utils.bytesToHex(tamperedSig); + }, + reason: 'no particular reason', + params: encodedParams, + }; + + await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSignature', [voteParams.voter]); + }); + + it('reverts if vote nonce is incorrect', async function () { + await this.token.delegate(this.voterBySig.address, { from: voter2 }); + + const nonce = await this.mock.nonces(this.voterBySig.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce: nonce.addn(1), + signature: this.sign(this.voterBySig.getPrivateKey()), + reason: 'no particular reason', + params: encodedParams, + }; + + await expectRevertCustomError( + this.helper.vote(voteParams), + // The signature check implies the nonce can't be tampered without changing the signer + 'GovernorInvalidSignature', + [voteParams.voter], + ); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/utils/EIP6372.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/utils/EIP6372.behavior.js new file mode 100644 index 0000000..022ec35 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/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/lib/openzeppelin-contracts-v5.0.0/test/governance/utils/Votes.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/utils/Votes.behavior.js new file mode 100644 index 0000000..5836cc3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/utils/Votes.behavior.js @@ -0,0 +1,360 @@ +const { constants, expectEvent, time } = require('@openzeppelin/test-helpers'); + +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +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 } = require('../../helpers/eip712'); +const { clockFromReceipt } = require('../../helpers/time'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const Delegation = [ + { name: 'delegatee', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { name: 'expiry', type: 'uint256' }, +]; + +const buildAndSignDelegation = (contract, message, pk) => + getDomain(contract) + .then(domain => ({ + primaryType: 'Delegation', + types: { EIP712Domain: domainType(domain), Delegation }, + domain, + message, + })) + .then(data => fromRpcSig(ethSigUtil.signTypedMessage(pk, { data }))); + +function shouldBehaveLikeVotes(accounts, tokens, { mode = 'blocknumber', fungible = true }) { + shouldBehaveLikeEIP6372(mode); + + const getWeight = token => web3.utils.toBN(fungible ? token : 1); + + describe('run votes workflow', function () { + it('initial nonce is 0', async function () { + expect(await this.votes.nonces(accounts[0])).to.be.bignumber.equal('0'); + }); + + describe('delegation with signature', function () { + const token = tokens[0]; + + it('delegation without tokens', async function () { + expect(await this.votes.delegates(accounts[1])).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.votes.delegate(accounts[1], { from: accounts[1] }); + expectEvent(receipt, 'DelegateChanged', { + delegator: accounts[1], + fromDelegate: ZERO_ADDRESS, + toDelegate: accounts[1], + }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[1]); + }); + + it('delegation with tokens', async function () { + await this.votes.$_mint(accounts[1], token); + const weight = getWeight(token); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.votes.delegate(accounts[1], { from: accounts[1] }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: accounts[1], + fromDelegate: ZERO_ADDRESS, + toDelegate: accounts[1], + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: accounts[1], + previousVotes: '0', + newVotes: weight, + }); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[1]); + expect(await this.votes.getVotes(accounts[1])).to.be.bignumber.equal(weight); + expect(await this.votes.getPastVotes(accounts[1], timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(accounts[1], timepoint)).to.be.bignumber.equal(weight); + }); + + it('delegation update', async function () { + await this.votes.delegate(accounts[1], { from: accounts[1] }); + await this.votes.$_mint(accounts[1], token); + const weight = getWeight(token); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[1]); + expect(await this.votes.getVotes(accounts[1])).to.be.bignumber.equal(weight); + expect(await this.votes.getVotes(accounts[2])).to.be.bignumber.equal('0'); + + const { receipt } = await this.votes.delegate(accounts[2], { from: accounts[1] }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: accounts[1], + fromDelegate: accounts[1], + toDelegate: accounts[2], + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: accounts[1], + previousVotes: weight, + newVotes: '0', + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: accounts[2], + previousVotes: '0', + newVotes: weight, + }); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[2]); + expect(await this.votes.getVotes(accounts[1])).to.be.bignumber.equal('0'); + expect(await this.votes.getVotes(accounts[2])).to.be.bignumber.equal(weight); + + expect(await this.votes.getPastVotes(accounts[1], timepoint - 1)).to.be.bignumber.equal(weight); + expect(await this.votes.getPastVotes(accounts[2], timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(accounts[1], timepoint)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(accounts[2], timepoint)).to.be.bignumber.equal(weight); + }); + + describe('with signature', function () { + const delegator = Wallet.generate(); + const [delegatee, other] = accounts; + const nonce = 0; + delegator.address = web3.utils.toChecksumAddress(delegator.getAddressString()); + + it('accept signed delegation', async function () { + await this.votes.$_mint(delegator.address, token); + const weight = getWeight(token); + + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + expect(await this.votes.delegates(delegator.address)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.votes.delegateBySig(delegatee, nonce, MAX_UINT256, v, r, s); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: delegator.address, + fromDelegate: ZERO_ADDRESS, + toDelegate: delegatee, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: delegatee, + previousVotes: '0', + newVotes: weight, + }); + + expect(await this.votes.delegates(delegator.address)).to.be.equal(delegatee); + expect(await this.votes.getVotes(delegator.address)).to.be.bignumber.equal('0'); + expect(await this.votes.getVotes(delegatee)).to.be.bignumber.equal(weight); + expect(await this.votes.getPastVotes(delegatee, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(delegatee, timepoint)).to.be.bignumber.equal(weight); + }); + + it('rejects reused signature', async function () { + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + await this.votes.delegateBySig(delegatee, nonce, MAX_UINT256, v, r, s); + + await expectRevertCustomError( + this.votes.delegateBySig(delegatee, nonce, MAX_UINT256, v, r, s), + 'InvalidAccountNonce', + [delegator.address, nonce + 1], + ); + }); + + it('rejects bad delegatee', async function () { + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + const receipt = await this.votes.delegateBySig(other, nonce, MAX_UINT256, v, r, s); + const { args } = receipt.logs.find(({ event }) => event === 'DelegateChanged'); + expect(args.delegator).to.not.be.equal(delegator.address); + expect(args.fromDelegate).to.be.equal(ZERO_ADDRESS); + expect(args.toDelegate).to.be.equal(other); + }); + + it('rejects bad nonce', async function () { + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce: nonce + 1, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + await expectRevertCustomError( + this.votes.delegateBySig(delegatee, nonce + 1, MAX_UINT256, v, r, s), + 'InvalidAccountNonce', + [delegator.address, 0], + ); + }); + + it('rejects expired permit', async function () { + const expiry = (await time.latest()) - time.duration.weeks(1); + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce, + expiry, + }, + delegator.getPrivateKey(), + ); + + await expectRevertCustomError( + this.votes.delegateBySig(delegatee, nonce, expiry, v, r, s), + 'VotesExpiredSignature', + [expiry], + ); + }); + }); + }); + + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.votes.delegate(accounts[1], { from: accounts[1] }); + }); + + it('reverts if block number >= current block', async function () { + const timepoint = 5e10; + const clock = await this.votes.clock(); + await expectRevertCustomError(this.votes.getPastTotalSupply(timepoint), 'ERC5805FutureLookup', [ + timepoint, + clock, + ]); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastTotalSupply(0)).to.be.bignumber.equal('0'); + }); + + it('returns the correct checkpointed total supply', async function () { + const weight = tokens.map(token => getWeight(token)); + + // t0 = mint #0 + const t0 = await this.votes.$_mint(accounts[1], tokens[0]); + await time.advanceBlock(); + // t1 = mint #1 + const t1 = await this.votes.$_mint(accounts[1], tokens[1]); + await time.advanceBlock(); + // t2 = burn #1 + const t2 = await this.votes.$_burn(...(fungible ? [accounts[1]] : []), tokens[1]); + await time.advanceBlock(); + // t3 = mint #2 + const t3 = await this.votes.$_mint(accounts[1], tokens[2]); + await time.advanceBlock(); + // t4 = burn #0 + const t4 = await this.votes.$_burn(...(fungible ? [accounts[1]] : []), tokens[0]); + await time.advanceBlock(); + // t5 = burn #2 + const t5 = await this.votes.$_burn(...(fungible ? [accounts[1]] : []), tokens[2]); + await time.advanceBlock(); + + t0.timepoint = await clockFromReceipt[mode](t0.receipt); + 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(t0.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(t0.timepoint)).to.be.bignumber.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t0.timepoint + 1)).to.be.bignumber.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t1.timepoint)).to.be.bignumber.equal(weight[0].add(weight[1])); + expect(await this.votes.getPastTotalSupply(t1.timepoint + 1)).to.be.bignumber.equal(weight[0].add(weight[1])); + expect(await this.votes.getPastTotalSupply(t2.timepoint)).to.be.bignumber.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t2.timepoint + 1)).to.be.bignumber.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t3.timepoint)).to.be.bignumber.equal(weight[0].add(weight[2])); + expect(await this.votes.getPastTotalSupply(t3.timepoint + 1)).to.be.bignumber.equal(weight[0].add(weight[2])); + expect(await this.votes.getPastTotalSupply(t4.timepoint)).to.be.bignumber.equal(weight[2]); + expect(await this.votes.getPastTotalSupply(t4.timepoint + 1)).to.be.bignumber.equal(weight[2]); + expect(await this.votes.getPastTotalSupply(t5.timepoint)).to.be.bignumber.equal('0'); + await expectRevertCustomError(this.votes.getPastTotalSupply(t5.timepoint + 1), 'ERC5805FutureLookup', [ + t5.timepoint + 1, // timepoint + t5.timepoint + 1, // clock + ]); + }); + }); + + // The following tests are an 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.votes.$_mint(accounts[1], tokens[0]); + await this.votes.$_mint(accounts[1], tokens[1]); + await this.votes.$_mint(accounts[1], tokens[2]); + }); + + describe('getPastVotes', function () { + it('reverts if block number >= current block', async function () { + const clock = await this.votes.clock(); + const timepoint = 5e10; // far in the future + await expectRevertCustomError(this.votes.getPastVotes(accounts[2], timepoint), 'ERC5805FutureLookup', [ + timepoint, + clock, + ]); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastVotes(accounts[2], 0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const { receipt } = await this.votes.delegate(accounts[2], { from: accounts[1] }); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + const latest = await this.votes.getVotes(accounts[2]); + expect(await this.votes.getPastVotes(accounts[2], timepoint)).to.be.bignumber.equal(latest); + expect(await this.votes.getPastVotes(accounts[2], timepoint + 1)).to.be.bignumber.equal(latest); + }); + + it('returns zero if < first checkpoint block', async function () { + await time.advanceBlock(); + const { receipt } = await this.votes.delegate(accounts[2], { from: accounts[1] }); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.votes.getPastVotes(accounts[2], timepoint - 1)).to.be.bignumber.equal('0'); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeVotes, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/governance/utils/Votes.test.js b/lib/openzeppelin-contracts-v5.0.0/test/governance/utils/Votes.test.js new file mode 100644 index 0000000..b2b80f9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/governance/utils/Votes.test.js @@ -0,0 +1,92 @@ +const { constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { clockFromReceipt } = require('../../helpers/time'); +const { BNsum } = require('../../helpers/math'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +require('array.prototype.at/auto'); + +const { shouldBehaveLikeVotes } = require('./Votes.behavior'); + +const MODES = { + blocknumber: artifacts.require('$VotesMock'), + timestamp: artifacts.require('$VotesTimestampMock'), +}; + +contract('Votes', function (accounts) { + const [account1, account2, account3] = accounts; + const amounts = { + [account1]: web3.utils.toBN('10000000000000000000000000'), + [account2]: web3.utils.toBN('10'), + [account3]: web3.utils.toBN('20'), + }; + + const name = 'My Vote'; + const version = '1'; + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.votes = await artifact.new(name, version); + }); + + shouldBehaveLikeVotes(accounts, Object.values(amounts), { mode, fungible: true }); + + 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.txs = []; + for (const [account, amount] of Object.entries(amounts)) { + this.txs.push(await this.votes.$_mint(account, amount)); + } + }); + + it('reverts if block number >= current block', async function () { + const lastTxTimepoint = await clockFromReceipt[mode](this.txs.at(-1).receipt); + const clock = await this.votes.clock(); + await expectRevertCustomError(this.votes.getPastTotalSupply(lastTxTimepoint + 1), 'ERC5805FutureLookup', [ + lastTxTimepoint + 1, + clock, + ]); + }); + + it('delegates', async function () { + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal('0'); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal('0'); + expect(await this.votes.delegates(account1)).to.be.equal(constants.ZERO_ADDRESS); + expect(await this.votes.delegates(account2)).to.be.equal(constants.ZERO_ADDRESS); + + await this.votes.delegate(account1, account1); + + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(amounts[account1]); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal('0'); + expect(await this.votes.delegates(account1)).to.be.equal(account1); + expect(await this.votes.delegates(account2)).to.be.equal(constants.ZERO_ADDRESS); + + await this.votes.delegate(account2, account1); + + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(amounts[account1].add(amounts[account2])); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal('0'); + expect(await this.votes.delegates(account1)).to.be.equal(account1); + expect(await this.votes.delegates(account2)).to.be.equal(account1); + }); + + it('cross delegates', async function () { + await this.votes.delegate(account1, account2); + await this.votes.delegate(account2, account1); + + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(amounts[account2]); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(amounts[account1]); + }); + + it('returns total amount of votes', async function () { + const totalSupply = BNsum(...Object.values(amounts)); + expect(await this.votes.getTotalSupply()).to.be.bignumber.equal(totalSupply); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/access-manager.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/access-manager.js new file mode 100644 index 0000000..7dfc4c3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/access-manager.js @@ -0,0 +1,69 @@ +const { time } = require('@openzeppelin/test-helpers'); +const { MAX_UINT64 } = require('./constants'); +const { artifacts } = require('hardhat'); + +function buildBaseRoles() { + const roles = { + ADMIN: { + id: web3.utils.toBN(0), + }, + SOME_ADMIN: { + id: web3.utils.toBN(17), + }, + SOME_GUARDIAN: { + id: web3.utils.toBN(35), + }, + SOME: { + id: web3.utils.toBN(42), + }, + PUBLIC: { + id: MAX_UINT64, + }, + }; + + // Names + Object.entries(roles).forEach(([name, role]) => (role.name = name)); + + // Defaults + for (const role of Object.keys(roles)) { + roles[role].admin = roles.ADMIN; + roles[role].guardian = roles.ADMIN; + } + + // Admins + roles.SOME.admin = roles.SOME_ADMIN; + + // Guardians + roles.SOME.guardian = roles.SOME_GUARDIAN; + + return roles; +} + +const formatAccess = access => [access[0], access[1].toString()]; + +const MINSETBACK = time.duration.days(5); +const EXPIRATION = time.duration.weeks(1); + +let EXECUTION_ID_STORAGE_SLOT = 3n; +let CONSUMING_SCHEDULE_STORAGE_SLOT = 0n; +try { + // Try to get the artifact paths, will throw if it doesn't exist + artifacts._getArtifactPathSync('AccessManagerUpgradeable'); + artifacts._getArtifactPathSync('AccessManagedUpgradeable'); + + // ERC-7201 namespace location for AccessManager + EXECUTION_ID_STORAGE_SLOT += 0x40c6c8c28789853c7efd823ab20824bbd71718a8a5915e855f6f288c9a26ad00n; + // ERC-7201 namespace location for AccessManaged + CONSUMING_SCHEDULE_STORAGE_SLOT += 0xf3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a00n; +} catch (_) { + // eslint-disable-next-line no-empty +} + +module.exports = { + buildBaseRoles, + formatAccess, + MINSETBACK, + EXPIRATION, + EXECUTION_ID_STORAGE_SLOT, + CONSUMING_SCHEDULE_STORAGE_SLOT, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/account.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/account.js new file mode 100644 index 0000000..1b01a72 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/account.js @@ -0,0 +1,14 @@ +const { web3 } = require('hardhat'); +const { impersonateAccount, setBalance } = require('@nomicfoundation/hardhat-network-helpers'); + +// Hardhat default balance +const DEFAULT_BALANCE = web3.utils.toBN('10000000000000000000000'); + +async function impersonate(account, balance = DEFAULT_BALANCE) { + await impersonateAccount(account); + await setBalance(account, balance); +} + +module.exports = { + impersonate, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/chainid.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/chainid.js new file mode 100644 index 0000000..58757eb --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/chainid.js @@ -0,0 +1,10 @@ +const hre = require('hardhat'); + +async function getChainId() { + const chainIdHex = await hre.network.provider.send('eth_chainId', []); + return new hre.web3.utils.BN(chainIdHex, 'hex'); +} + +module.exports = { + getChainId, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/constants.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/constants.js new file mode 100644 index 0000000..0f4d028 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/constants.js @@ -0,0 +1,7 @@ +const MAX_UINT48 = web3.utils.toBN(1).shln(48).subn(1).toString(); +const MAX_UINT64 = web3.utils.toBN(1).shln(64).subn(1).toString(); + +module.exports = { + MAX_UINT48, + MAX_UINT64, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/create.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/create.js new file mode 100644 index 0000000..98a0d4c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/create.js @@ -0,0 +1,22 @@ +const RLP = require('rlp'); + +function computeCreateAddress(deployer, nonce) { + return web3.utils.toChecksumAddress(web3.utils.sha3(RLP.encode([deployer.address ?? deployer, nonce])).slice(-40)); +} + +function computeCreate2Address(saltHex, bytecode, deployer) { + return web3.utils.toChecksumAddress( + web3.utils + .sha3( + `0x${['ff', deployer.address ?? deployer, saltHex, web3.utils.soliditySha3(bytecode)] + .map(x => x.replace(/0x/, '')) + .join('')}`, + ) + .slice(-40), + ); +} + +module.exports = { + computeCreateAddress, + computeCreate2Address, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/customError.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/customError.js new file mode 100644 index 0000000..ea5c368 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/customError.js @@ -0,0 +1,43 @@ +const { expect } = require('chai'); + +/** Revert handler that supports custom errors. */ +async function expectRevertCustomError(promise, expectedErrorName, args) { + if (!Array.isArray(args)) { + expect.fail('Expected 3rd array parameter for error arguments'); + } + + await promise.then( + () => expect.fail("Expected promise to throw but it didn't"), + ({ message }) => { + // The revert message for custom errors looks like: + // VM Exception while processing transaction: + // reverted with custom error 'InvalidAccountNonce("0x70997970C51812dc3A010C7d01b50e0d17dc79C8", 0)' + + // Attempt to parse as a custom error + const match = message.match(/custom error '(?\w+)\((?.*)\)'/); + if (!match) { + expect.fail(`Could not parse as custom error. ${message}`); + } + // Extract the error name and parameters + const errorName = match.groups.name; + const argMatches = [...match.groups.args.matchAll(/-?\w+/g)]; + + // Assert error name + expect(errorName).to.be.equal( + expectedErrorName, + `Unexpected custom error name (with found args: [${argMatches.map(([a]) => a)}])`, + ); + + // Coerce to string for comparison since `arg` can be either a number or hex. + const sanitizedExpected = args.map(arg => arg.toString().toLowerCase()); + const sanitizedActual = argMatches.map(([arg]) => arg.toString().toLowerCase()); + + // Assert argument equality + expect(sanitizedActual).to.have.members(sanitizedExpected, `Unexpected ${errorName} arguments`); + }, + ); +} + +module.exports = { + expectRevertCustomError, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/eip712.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/eip712.js new file mode 100644 index 0000000..b12a623 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/eip712.js @@ -0,0 +1,67 @@ +const ethSigUtil = require('eth-sig-util'); +const keccak256 = require('keccak256'); + +const EIP712Domain = [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + { name: 'salt', type: 'bytes32' }, +]; + +const Permit = [ + { name: 'owner', type: 'address' }, + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint256' }, +]; + +function bufferToHexString(buffer) { + return '0x' + buffer.toString('hex'); +} + +function hexStringToBuffer(hexstr) { + return Buffer.from(hexstr.replace(/^0x/, ''), 'hex'); +} + +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', domain, { EIP712Domain: domainType(domain) }), + ); +} + +function hashTypedData(domain, structHash) { + return bufferToHexString( + keccak256(Buffer.concat(['0x1901', domainSeparator(domain), structHash].map(str => hexStringToBuffer(str)))), + ); +} + +module.exports = { + Permit, + getDomain, + domainType, + domainSeparator, + hashTypedData, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/enums.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/enums.js new file mode 100644 index 0000000..6280e0f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/enums.js @@ -0,0 +1,11 @@ +function Enum(...options) { + return Object.fromEntries(options.map((key, i) => [key, web3.utils.toBN(i)])); +} + +module.exports = { + Enum, + ProposalState: Enum('Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'), + VoteType: Enum('Against', 'For', 'Abstain'), + Rounding: Enum('Floor', 'Ceil', 'Trunc', 'Expand'), + OperationState: Enum('Unset', 'Waiting', 'Ready', 'Done'), +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/erc1967.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/erc1967.js new file mode 100644 index 0000000..4ad92c5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/erc1967.js @@ -0,0 +1,43 @@ +const { getStorageAt, setStorageAt } = require('@nomicfoundation/hardhat-network-helpers'); + +const ImplementationLabel = 'eip1967.proxy.implementation'; +const AdminLabel = 'eip1967.proxy.admin'; +const BeaconLabel = 'eip1967.proxy.beacon'; + +function labelToSlot(label) { + return '0x' + web3.utils.toBN(web3.utils.keccak256(label)).subn(1).toString(16); +} + +function getSlot(address, slot) { + return getStorageAt( + web3.utils.isAddress(address) ? address : address.address, + web3.utils.isHex(slot) ? slot : labelToSlot(slot), + ); +} + +function setSlot(address, slot, value) { + const hexValue = web3.utils.isHex(value) ? value : web3.utils.toHex(value); + + return setStorageAt( + web3.utils.isAddress(address) ? address : address.address, + web3.utils.isHex(slot) ? slot : labelToSlot(slot), + web3.utils.padLeft(hexValue, 64), + ); +} + +async function getAddressInSlot(address, slot) { + const slotValue = await getSlot(address, slot); + return web3.utils.toChecksumAddress(slotValue.substring(slotValue.length - 40)); +} + +module.exports = { + ImplementationLabel, + AdminLabel, + BeaconLabel, + ImplementationSlot: labelToSlot(ImplementationLabel), + AdminSlot: labelToSlot(AdminLabel), + BeaconSlot: labelToSlot(BeaconLabel), + setSlot, + getSlot, + getAddressInSlot, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/governance.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/governance.js new file mode 100644 index 0000000..fc4e300 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/governance.js @@ -0,0 +1,253 @@ +const { web3 } = require('hardhat'); +const { forward } = require('../helpers/time'); +const { ProposalState } = require('./enums'); + +function zip(...args) { + return Array(Math.max(...args.map(array => array.length))) + .fill() + .map((_, i) => args.map(array => array[i])); +} + +function concatHex(...args) { + return web3.utils.bytesToHex([].concat(...args.map(h => web3.utils.hexToBytes(h || '0x')))); +} + +function concatOpts(args, opts = null) { + return opts ? args.concat(opts) : args; +} + +const timelockSalt = (address, descriptionHash) => + '0x' + web3.utils.toBN(address).shln(96).xor(web3.utils.toBN(descriptionHash)).toString(16, 64); + +class GovernorHelper { + constructor(governor, mode = 'blocknumber') { + this.governor = governor; + this.mode = mode; + } + + delegate(delegation = {}, opts = null) { + return Promise.all([ + delegation.token.delegate(delegation.to, { from: delegation.to }), + delegation.value && delegation.token.transfer(...concatOpts([delegation.to, delegation.value]), opts), + delegation.tokenId && + delegation.token + .ownerOf(delegation.tokenId) + .then(owner => + delegation.token.transferFrom(...concatOpts([owner, delegation.to, delegation.tokenId], opts)), + ), + ]); + } + + propose(opts = null) { + const proposal = this.currentProposal; + + return this.governor.methods[ + proposal.useCompatibilityInterface + ? 'propose(address[],uint256[],string[],bytes[],string)' + : 'propose(address[],uint256[],bytes[],string)' + ](...concatOpts(proposal.fullProposal, opts)); + } + + queue(opts = null) { + const proposal = this.currentProposal; + + return proposal.useCompatibilityInterface + ? this.governor.methods['queue(uint256)'](...concatOpts([proposal.id], opts)) + : this.governor.methods['queue(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } + + execute(opts = null) { + const proposal = this.currentProposal; + + return proposal.useCompatibilityInterface + ? this.governor.methods['execute(uint256)'](...concatOpts([proposal.id], opts)) + : this.governor.methods['execute(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } + + cancel(visibility = 'external', opts = null) { + const proposal = this.currentProposal; + + switch (visibility) { + case 'external': + 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), + ); + default: + throw new Error(`unsupported visibility "${visibility}"`); + } + } + + vote(vote = {}, opts = null) { + const proposal = this.currentProposal; + + return vote.signature + ? // if signature, and either params or reason → + vote.params || vote.reason + ? this.sign(vote).then(signature => + this.governor.castVoteWithReasonAndParamsBySig( + ...concatOpts( + [proposal.id, vote.support, vote.voter, vote.reason || '', vote.params || '', signature], + opts, + ), + ), + ) + : this.sign(vote).then(signature => + this.governor.castVoteBySig(...concatOpts([proposal.id, vote.support, vote.voter, signature], opts)), + ) + : vote.params + ? // otherwise if params + this.governor.castVoteWithReasonAndParams( + ...concatOpts([proposal.id, vote.support, vote.reason || '', vote.params], opts), + ) + : vote.reason + ? // otherwise if reason + this.governor.castVoteWithReason(...concatOpts([proposal.id, vote.support, vote.reason], opts)) + : this.governor.castVote(...concatOpts([proposal.id, vote.support], opts)); + } + + sign(vote = {}) { + return vote.signature(this.governor, this.forgeMessage(vote)); + } + + forgeMessage(vote = {}) { + const proposal = this.currentProposal; + + const message = { proposalId: proposal.id, support: vote.support, voter: vote.voter, nonce: vote.nonce }; + + if (vote.params || vote.reason) { + message.reason = vote.reason || ''; + message.params = vote.params || ''; + } + + return message; + } + + async waitForSnapshot(offset = 0) { + const proposal = this.currentProposal; + const timepoint = await this.governor.proposalSnapshot(proposal.id); + return forward[this.mode](timepoint.addn(offset)); + } + + async waitForDeadline(offset = 0) { + const proposal = this.currentProposal; + const timepoint = await this.governor.proposalDeadline(proposal.id); + return forward[this.mode](timepoint.addn(offset)); + } + + async waitForEta(offset = 0) { + const proposal = this.currentProposal; + const timestamp = await this.governor.proposalEta(proposal.id); + return forward.timestamp(timestamp.addn(offset)); + } + + /** + * Specify a proposal either as + * 1) an array of objects [{ target, value, data, signature? }] + * 2) an object of arrays { targets: [], values: [], data: [], signatures?: [] } + */ + setProposal(actions, description) { + let targets, values, signatures, data, useCompatibilityInterface; + + if (Array.isArray(actions)) { + useCompatibilityInterface = actions.some(a => 'signature' in a); + targets = actions.map(a => a.target); + values = actions.map(a => a.value || '0'); + signatures = actions.map(a => a.signature || ''); + data = actions.map(a => a.data || '0x'); + } else { + useCompatibilityInterface = Array.isArray(actions.signatures); + ({ targets, values, signatures = [], data } = actions); + } + + const fulldata = zip( + signatures.map(s => s && web3.eth.abi.encodeFunctionSignature(s)), + data, + ).map(hexs => concatHex(...hexs)); + + const descriptionHash = web3.utils.keccak256(description); + + // condensed version for queueing end executing + const shortProposal = [targets, values, fulldata, descriptionHash]; + + // full version for proposing + const fullProposal = [targets, values, ...(useCompatibilityInterface ? [signatures] : []), data, description]; + + // proposal id + const id = web3.utils.toBN( + web3.utils.keccak256( + web3.eth.abi.encodeParameters(['address[]', 'uint256[]', 'bytes[]', 'bytes32'], shortProposal), + ), + ); + + this.currentProposal = { + id, + targets, + values, + signatures, + data, + fulldata, + description, + descriptionHash, + shortProposal, + fullProposal, + useCompatibilityInterface, + }; + + return this.currentProposal; + } +} + +/** + * Encodes a list ProposalStates into a bytes32 representation where each bit enabled corresponds to + * the underlying position in the `ProposalState` enum. For example: + * + * 0x000...10000 + * ^^^^^^------ ... + * ^----- Succeeded + * ^---- Defeated + * ^--- Canceled + * ^-- Active + * ^- Pending + */ +function proposalStatesToBitMap(proposalStates, options = {}) { + if (!Array.isArray(proposalStates)) { + proposalStates = [proposalStates]; + } + const statesCount = Object.keys(ProposalState).length; + let result = 0; + + const uniqueProposalStates = new Set(proposalStates.map(bn => bn.toNumber())); // Remove duplicates + for (const state of uniqueProposalStates) { + if (state < 0 || state >= statesCount) { + expect.fail(`ProposalState ${state} out of possible states (0...${statesCount}-1)`); + } else { + result |= 1 << state; + } + } + + if (options.inverted) { + const mask = 2 ** statesCount - 1; + result = result ^ mask; + } + + const hex = web3.utils.numberToHex(result); + return web3.utils.padLeft(hex, 64); +} + +module.exports = { + GovernorHelper, + proposalStatesToBitMap, + timelockSalt, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/iterate.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/iterate.js new file mode 100644 index 0000000..7f6e0e6 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/iterate.js @@ -0,0 +1,16 @@ +// Map values in an object +const mapValues = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)])); + +// Array of number or bigint +const max = (...values) => values.slice(1).reduce((x, y) => (x > y ? x : y), values[0]); +const min = (...values) => values.slice(1).reduce((x, y) => (x < y ? x : y), values[0]); + +// Cartesian product of a list of arrays +const product = (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]); + +module.exports = { + mapValues, + max, + min, + product, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/math.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/math.js new file mode 100644 index 0000000..2bc654c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/math.js @@ -0,0 +1,11 @@ +module.exports = { + // sum of integer / bignumber + sum: (...args) => args.reduce((acc, n) => acc + n, 0), + BNsum: (...args) => args.reduce((acc, n) => acc.add(n), web3.utils.toBN(0)), + // min of integer / bignumber + min: (...args) => args.slice(1).reduce((x, y) => (x < y ? x : y), args[0]), + BNmin: (...args) => args.slice(1).reduce((x, y) => (x.lt(y) ? x : y), args[0]), + // max of integer / bignumber + max: (...args) => args.slice(1).reduce((x, y) => (x > y ? x : y), args[0]), + BNmax: (...args) => args.slice(1).reduce((x, y) => (x.gt(y) ? x : y), args[0]), +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/methods.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/methods.js new file mode 100644 index 0000000..cb30d87 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/methods.js @@ -0,0 +1,5 @@ +const { soliditySha3 } = require('web3-utils'); + +module.exports = { + selector: signature => soliditySha3(signature).substring(0, 10), +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/sign.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/sign.js new file mode 100644 index 0000000..d537116 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/sign.js @@ -0,0 +1,63 @@ +function toEthSignedMessageHash(messageHex) { + const messageBuffer = Buffer.from(messageHex.substring(2), 'hex'); + const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`); + 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 + * @param contract TruffleContract + * @param signer address + * @param redeemer address + * @param methodName string + * @param methodArgs any[] + */ +const getSignFor = + (contract, signer) => + (redeemer, methodName, methodArgs = []) => { + const parts = [contract.address, redeemer]; + + const REAL_SIGNATURE_SIZE = 2 * 65; // 65 bytes in hexadecimal string length + const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length + const DUMMY_SIGNATURE = `0x${web3.utils.padLeft('', REAL_SIGNATURE_SIZE)}`; + + // if we have a method, add it to the parts that we're signing + if (methodName) { + if (methodArgs.length > 0) { + parts.push( + contract.contract.methods[methodName](...methodArgs.concat([DUMMY_SIGNATURE])) + .encodeABI() + .slice(0, -1 * PADDED_SIGNATURE_SIZE), + ); + } else { + const abi = contract.abi.find(abi => abi.name === methodName); + parts.push(abi.signature); + } + } + + // return the signature of the "Ethereum Signed Message" hash of the hash of `parts` + const messageHex = web3.utils.soliditySha3(...parts); + return web3.eth.sign(messageHex, signer); + }; + +module.exports = { + toEthSignedMessageHash, + toDataWithIntendedValidatorHash, + getSignFor, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/time.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/time.js new file mode 100644 index 0000000..30df8dc --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/time.js @@ -0,0 +1,17 @@ +const ozHelpers = require('@openzeppelin/test-helpers'); +const helpers = require('@nomicfoundation/hardhat-network-helpers'); + +module.exports = { + clock: { + 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: ozHelpers.time.advanceBlockTo, + timestamp: helpers.time.increaseTo, + }, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/helpers/txpool.js b/lib/openzeppelin-contracts-v5.0.0/test/helpers/txpool.js new file mode 100644 index 0000000..ecdba54 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/helpers/txpool.js @@ -0,0 +1,38 @@ +const { network } = require('hardhat'); +const { promisify } = require('util'); + +const queue = promisify(setImmediate); + +async function countPendingTransactions() { + return parseInt(await network.provider.send('eth_getBlockTransactionCountByNumber', ['pending'])); +} + +async function batchInBlock(txs) { + try { + // disable auto-mining + await network.provider.send('evm_setAutomine', [false]); + // send all transactions + const promises = txs.map(fn => fn()); + // wait for node to have all pending transactions + while (txs.length > (await countPendingTransactions())) { + await queue(); + } + // mine one block + await network.provider.send('evm_mine'); + // fetch receipts + const receipts = await Promise.all(promises); + // Sanity check, all tx should be in the same block + const minedBlocks = new Set(receipts.map(({ receipt }) => receipt.blockNumber)); + expect(minedBlocks.size).to.equal(1); + + return receipts; + } finally { + // enable auto-mining + await network.provider.send('evm_setAutomine', [true]); + } +} + +module.exports = { + countPendingTransactions, + batchInBlock, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Context.test.js b/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Context.test.js new file mode 100644 index 0000000..b0ebccc --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Context.test.js @@ -0,0 +1,134 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); +const { MAX_UINT48 } = require('../helpers/constants'); + +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC2771ContextMock = artifacts.require('ERC2771ContextMock'); +const ERC2771Forwarder = artifacts.require('ERC2771Forwarder'); +const ContextMockCaller = artifacts.require('ContextMockCaller'); + +const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior'); + +contract('ERC2771Context', function (accounts) { + const [, trustedForwarder] = accounts; + + beforeEach(async function () { + this.forwarder = await ERC2771Forwarder.new('ERC2771Forwarder'); + this.recipient = await ERC2771ContextMock.new(this.forwarder.address); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint48' }, + { name: 'data', type: 'bytes' }, + ], + }; + }); + + it('recognize trusted forwarder', async function () { + expect(await this.recipient.isTrustedForwarder(this.forwarder.address)).to.equal(true); + }); + + it('returns the trusted forwarder', async function () { + expect(await this.recipient.trustedForwarder()).to.equal(this.forwarder.address); + }); + + context('when called directly', function () { + beforeEach(async function () { + this.context = this.recipient; // The Context behavior expects the contract in this.context + this.caller = await ContextMockCaller.new(); + }); + + shouldBehaveLikeRegularContext(...accounts); + }); + + context('when receiving a relayed call', function () { + beforeEach(async function () { + this.wallet = Wallet.generate(); + this.sender = web3.utils.toChecksumAddress(this.wallet.getAddressString()); + this.data = { + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + }; + }); + + describe('msgSender', function () { + it('returns the relayed transaction original sender', async function () { + const data = this.recipient.contract.methods.msgSender().encodeABI(); + + const req = { + from: this.sender, + to: this.recipient.address, + value: '0', + gas: '100000', + nonce: (await this.forwarder.nonces(this.sender)).toString(), + deadline: MAX_UINT48, + data, + }; + + req.signature = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { + data: { ...this.data, message: req }, + }); + expect(await this.forwarder.verify(req)).to.equal(true); + + const { tx } = await this.forwarder.execute(req); + await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Sender', { sender: this.sender }); + }); + + it('returns the original sender when calldata length is less than 20 bytes (address length)', async function () { + // The forwarder doesn't produce calls with calldata length less than 20 bytes + const recipient = await ERC2771ContextMock.new(trustedForwarder); + + const { receipt } = await recipient.msgSender({ from: trustedForwarder }); + + await expectEvent(receipt, 'Sender', { sender: trustedForwarder }); + }); + }); + + describe('msgData', function () { + it('returns the relayed transaction original data', async function () { + const integerValue = '42'; + const stringValue = 'OpenZeppelin'; + const data = this.recipient.contract.methods.msgData(integerValue, stringValue).encodeABI(); + + const req = { + from: this.sender, + to: this.recipient.address, + value: '0', + gas: '100000', + nonce: (await this.forwarder.nonces(this.sender)).toString(), + deadline: MAX_UINT48, + data, + }; + + req.signature = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { + data: { ...this.data, message: req }, + }); + expect(await this.forwarder.verify(req)).to.equal(true); + + const { tx } = await this.forwarder.execute(req); + await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Data', { data, integerValue, stringValue }); + }); + }); + + it('returns the full original data when calldata length is less than 20 bytes (address length)', async function () { + // The forwarder doesn't produce calls with calldata length less than 20 bytes + const recipient = await ERC2771ContextMock.new(trustedForwarder); + + const { receipt } = await recipient.msgDataShort({ from: trustedForwarder }); + + const data = recipient.contract.methods.msgDataShort().encodeABI(); + await expectEvent(receipt, 'DataShort', { data }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Forwarder.t.sol b/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Forwarder.t.sol new file mode 100644 index 0000000..d69b475 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Forwarder.t.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {ERC2771Forwarder} from "@openzeppelin/contracts/metatx/ERC2771Forwarder.sol"; +import {CallReceiverMockTrustingForwarder, CallReceiverMock} from "@openzeppelin/contracts/mocks/CallReceiverMock.sol"; + +struct ForwardRequest { + address from; + address to; + uint256 value; + uint256 gas; + uint256 nonce; + uint48 deadline; + bytes data; +} + +contract ERC2771ForwarderMock is ERC2771Forwarder { + constructor(string memory name) ERC2771Forwarder(name) {} + + function structHash(ForwardRequest calldata request) external view returns (bytes32) { + return + _hashTypedDataV4( + keccak256( + abi.encode( + _FORWARD_REQUEST_TYPEHASH, + request.from, + request.to, + request.value, + request.gas, + request.nonce, + request.deadline, + keccak256(request.data) + ) + ) + ); + } +} + +contract ERC2771ForwarderTest is Test { + ERC2771ForwarderMock internal _erc2771Forwarder; + CallReceiverMockTrustingForwarder internal _receiver; + + uint256 internal _signerPrivateKey; + uint256 internal _relayerPrivateKey; + + address internal _signer; + address internal _relayer; + + uint256 internal constant _MAX_ETHER = 10_000_000; // To avoid overflow + + function setUp() public { + _erc2771Forwarder = new ERC2771ForwarderMock("ERC2771Forwarder"); + _receiver = new CallReceiverMockTrustingForwarder(address(_erc2771Forwarder)); + + _signerPrivateKey = 0xA11CE; + _relayerPrivateKey = 0xB0B; + + _signer = vm.addr(_signerPrivateKey); + _relayer = vm.addr(_relayerPrivateKey); + } + + function _forgeRequestData( + uint256 value, + uint256 nonce, + uint48 deadline, + bytes memory data + ) private view returns (ERC2771Forwarder.ForwardRequestData memory) { + ForwardRequest memory request = ForwardRequest({ + from: _signer, + to: address(_receiver), + value: value, + gas: 30000, + nonce: nonce, + deadline: deadline, + data: data + }); + + bytes32 digest = _erc2771Forwarder.structHash(request); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPrivateKey, digest); + bytes memory signature = abi.encodePacked(r, s, v); + + return + ERC2771Forwarder.ForwardRequestData({ + from: request.from, + to: request.to, + value: request.value, + gas: request.gas, + deadline: request.deadline, + data: request.data, + signature: signature + }); + } + + function testExecuteAvoidsETHStuck(uint256 initialBalance, uint256 value, bool targetReverts) public { + initialBalance = bound(initialBalance, 0, _MAX_ETHER); + value = bound(value, 0, _MAX_ETHER); + + vm.deal(address(_erc2771Forwarder), initialBalance); + + uint256 nonce = _erc2771Forwarder.nonces(_signer); + + vm.deal(address(this), value); + + ERC2771Forwarder.ForwardRequestData memory requestData = _forgeRequestData({ + value: value, + nonce: nonce, + deadline: uint48(block.timestamp + 1), + data: targetReverts + ? abi.encodeCall(CallReceiverMock.mockFunctionRevertsNoReason, ()) + : abi.encodeCall(CallReceiverMock.mockFunction, ()) + }); + + if (targetReverts) { + vm.expectRevert(); + } + + _erc2771Forwarder.execute{value: value}(requestData); + assertEq(address(_erc2771Forwarder).balance, initialBalance); + } + + function testExecuteBatchAvoidsETHStuck(uint256 initialBalance, uint256 batchSize, uint256 value) public { + batchSize = bound(batchSize, 1, 10); + initialBalance = bound(initialBalance, 0, _MAX_ETHER); + value = bound(value, 0, _MAX_ETHER); + + vm.deal(address(_erc2771Forwarder), initialBalance); + uint256 nonce = _erc2771Forwarder.nonces(_signer); + + ERC2771Forwarder.ForwardRequestData[] memory batchRequestDatas = new ERC2771Forwarder.ForwardRequestData[]( + batchSize + ); + + uint256 expectedRefund; + + for (uint256 i = 0; i < batchSize; ++i) { + bytes memory data; + bool succeed = uint256(keccak256(abi.encodePacked(initialBalance, i))) % 2 == 0; + + if (succeed) { + data = abi.encodeCall(CallReceiverMock.mockFunction, ()); + } else { + expectedRefund += value; + data = abi.encodeCall(CallReceiverMock.mockFunctionRevertsNoReason, ()); + } + + batchRequestDatas[i] = _forgeRequestData({ + value: value, + nonce: nonce + i, + deadline: uint48(block.timestamp + 1), + data: data + }); + } + + address payable refundReceiver = payable(address(0xebe)); + uint256 totalValue = value * batchSize; + + vm.deal(address(this), totalValue); + _erc2771Forwarder.executeBatch{value: totalValue}(batchRequestDatas, refundReceiver); + + assertEq(address(_erc2771Forwarder).balance, initialBalance); + assertEq(refundReceiver.balance, expectedRefund); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Forwarder.test.js b/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Forwarder.test.js new file mode 100644 index 0000000..0e09988 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/metatx/ERC2771Forwarder.test.js @@ -0,0 +1,541 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { constants, expectRevert, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC2771Forwarder = artifacts.require('ERC2771Forwarder'); +const CallReceiverMockTrustingForwarder = artifacts.require('CallReceiverMockTrustingForwarder'); + +contract('ERC2771Forwarder', function (accounts) { + const [, refundReceiver, another] = accounts; + + const tamperedValues = { + from: another, + value: web3.utils.toWei('0.5'), + data: '0x1742', + }; + + beforeEach(async function () { + this.forwarder = await ERC2771Forwarder.new('ERC2771Forwarder'); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint48' }, + { name: 'data', type: 'bytes' }, + ], + }; + + this.alice = Wallet.generate(); + this.alice.address = web3.utils.toChecksumAddress(this.alice.getAddressString()); + + this.timestamp = await time.latest(); + this.receiver = await CallReceiverMockTrustingForwarder.new(this.forwarder.address); + this.request = { + from: this.alice.address, + to: this.receiver.address, + value: '0', + gas: '100000', + data: this.receiver.contract.methods.mockFunction().encodeABI(), + deadline: this.timestamp.toNumber() + 60, // 1 minute + }; + this.requestData = { + ...this.request, + nonce: (await this.forwarder.nonces(this.alice.address)).toString(), + }; + + this.forgeData = request => ({ + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + message: { ...this.requestData, ...request }, + }); + this.sign = (privateKey, request) => + ethSigUtil.signTypedMessage(privateKey, { + data: this.forgeData(request), + }); + this.estimateRequest = request => + web3.eth.estimateGas({ + from: this.forwarder.address, + to: request.to, + data: web3.utils.encodePacked({ value: request.data, type: 'bytes' }, { value: request.from, type: 'address' }), + value: request.value, + gas: request.gas, + }); + + this.requestData.signature = this.sign(this.alice.getPrivateKey()); + }); + + context('verify', function () { + context('with valid signature', function () { + it('returns true without altering the nonce', async function () { + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + expect(await this.forwarder.verify(this.requestData)).to.be.equal(true); + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + }); + }); + + context('with tampered values', function () { + for (const [key, value] of Object.entries(tamperedValues)) { + it(`returns false with tampered ${key}`, async function () { + expect(await this.forwarder.verify(this.forgeData({ [key]: value }).message)).to.be.equal(false); + }); + } + + it('returns false with an untrustful to', async function () { + expect(await this.forwarder.verify(this.forgeData({ to: another }).message)).to.be.equal(false); + }); + + it('returns false with tampered signature', async function () { + const tamperedsign = web3.utils.hexToBytes(this.requestData.signature); + tamperedsign[42] ^= 0xff; + this.requestData.signature = web3.utils.bytesToHex(tamperedsign); + expect(await this.forwarder.verify(this.requestData)).to.be.equal(false); + }); + + it('returns false with valid signature for non-current nonce', async function () { + const req = { + ...this.requestData, + nonce: this.requestData.nonce + 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + expect(await this.forwarder.verify(req)).to.be.equal(false); + }); + + it('returns false with valid signature for expired deadline', async function () { + const req = { + ...this.requestData, + deadline: this.timestamp - 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + expect(await this.forwarder.verify(req)).to.be.equal(false); + }); + }); + }); + + context('execute', function () { + context('with valid requests', function () { + beforeEach(async function () { + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + }); + + it('emits an event and consumes nonce for a successful request', async function () { + const receipt = await this.forwarder.execute(this.requestData); + await expectEvent.inTransaction(receipt.tx, this.receiver, 'MockFunctionCalled'); + await expectEvent.inTransaction(receipt.tx, this.forwarder, 'ExecutedForwardRequest', { + signer: this.requestData.from, + nonce: web3.utils.toBN(this.requestData.nonce), + success: true, + }); + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce + 1), + ); + }); + + it('reverts with an unsuccessful request', async function () { + const req = { + ...this.requestData, + data: this.receiver.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'FailedInnerCall', []); + }); + }); + + context('with tampered request', function () { + for (const [key, value] of Object.entries(tamperedValues)) { + it(`reverts with tampered ${key}`, async function () { + const data = this.forgeData({ [key]: value }); + await expectRevertCustomError( + this.forwarder.execute(data.message, { + value: key == 'value' ? value : 0, // To avoid MismatchedValue error + }), + 'ERC2771ForwarderInvalidSigner', + [ethSigUtil.recoverTypedSignature({ data, sig: this.requestData.signature }), data.message.from], + ); + }); + } + + it('reverts with an untrustful to', async function () { + const data = this.forgeData({ to: another }); + await expectRevertCustomError(this.forwarder.execute(data.message), 'ERC2771UntrustfulTarget', [ + data.message.to, + this.forwarder.address, + ]); + }); + + it('reverts with tampered signature', async function () { + const tamperedSig = web3.utils.hexToBytes(this.requestData.signature); + tamperedSig[42] ^= 0xff; + this.requestData.signature = web3.utils.bytesToHex(tamperedSig); + await expectRevertCustomError(this.forwarder.execute(this.requestData), 'ERC2771ForwarderInvalidSigner', [ + ethSigUtil.recoverTypedSignature({ data: this.forgeData(), sig: tamperedSig }), + this.requestData.from, + ]); + }); + + it('reverts with valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestData); + + // And then fail due to an already used nonce + await expectRevertCustomError(this.forwarder.execute(this.requestData), 'ERC2771ForwarderInvalidSigner', [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData({ ...this.requestData, nonce: this.requestData.nonce + 1 }), + sig: this.requestData.signature, + }), + this.requestData.from, + ]); + }); + + it('reverts with valid signature for expired deadline', async function () { + const req = { + ...this.requestData, + deadline: this.timestamp - 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'ERC2771ForwarderExpiredRequest', [ + this.timestamp - 1, + ]); + }); + + it('reverts with valid signature but mismatched value', async function () { + const value = 100; + const req = { + ...this.requestData, + value, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'ERC2771ForwarderMismatchedValue', [0, value]); + }); + }); + + it('bubbles out of gas', async function () { + this.requestData.data = this.receiver.contract.methods.mockFunctionOutOfGas().encodeABI(); + this.requestData.gas = 1_000_000; + this.requestData.signature = this.sign(this.alice.getPrivateKey()); + + const gasAvailable = 100_000; + await expectRevert.assertion(this.forwarder.execute(this.requestData, { gas: gasAvailable })); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + expect(gasUsed).to.be.equal(gasAvailable); + }); + + it('bubbles out of gas forced by the relayer', async function () { + // If there's an incentive behind executing requests, a malicious relayer could grief + // the forwarder by executing requests and providing a top-level call gas limit that + // is too low to successfully finish the request after the 63/64 rule. + + // We set the baseline to the gas limit consumed by a successful request if it was executed + // normally. Note this includes the 21000 buffer that also the relayer will be charged to + // start a request execution. + const estimate = await this.estimateRequest(this.request); + + // Because the relayer call consumes gas until the `CALL` opcode, the gas left after failing + // the subcall won't enough to finish the top level call (after testing), so we add a + // moderated buffer. + const gasAvailable = estimate + 2_000; + + // The subcall out of gas should be caught by the contract and then bubbled up consuming + // the available gas with an `invalid` opcode. + await expectRevert.outOfGas(this.forwarder.execute(this.requestData, { gas: gasAvailable })); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + // We assert that indeed the gas was totally consumed. + expect(gasUsed).to.be.equal(gasAvailable); + }); + }); + + context('executeBatch', function () { + const batchValue = requestDatas => requestDatas.reduce((value, request) => value + Number(request.value), 0); + + beforeEach(async function () { + this.bob = Wallet.generate(); + this.bob.address = web3.utils.toChecksumAddress(this.bob.getAddressString()); + + this.eve = Wallet.generate(); + this.eve.address = web3.utils.toChecksumAddress(this.eve.getAddressString()); + + this.signers = [this.alice, this.bob, this.eve]; + + this.requestDatas = await Promise.all( + this.signers.map(async ({ address }) => ({ + ...this.requestData, + from: address, + nonce: (await this.forwarder.nonces(address)).toString(), + value: web3.utils.toWei('10', 'gwei'), + })), + ); + + this.requestDatas = this.requestDatas.map((requestData, i) => ({ + ...requestData, + signature: this.sign(this.signers[i].getPrivateKey(), requestData), + })); + + this.msgValue = batchValue(this.requestDatas); + + this.gasUntil = async reqIdx => { + const gas = 0; + const estimations = await Promise.all( + new Array(reqIdx + 1).fill().map((_, idx) => this.estimateRequest(this.requestDatas[idx])), + ); + return estimations.reduce((acc, estimation) => acc + estimation, gas); + }; + }); + + context('with valid requests', function () { + beforeEach(async function () { + for (const request of this.requestDatas) { + expect(await this.forwarder.verify(request)).to.be.equal(true); + } + + this.receipt = await this.forwarder.executeBatch(this.requestDatas, another, { value: this.msgValue }); + }); + + it('emits events', async function () { + for (const request of this.requestDatas) { + await expectEvent.inTransaction(this.receipt.tx, this.receiver, 'MockFunctionCalled'); + await expectEvent.inTransaction(this.receipt.tx, this.forwarder, 'ExecutedForwardRequest', { + signer: request.from, + nonce: web3.utils.toBN(request.nonce), + success: true, + }); + } + }); + + it('increase nonces', async function () { + for (const request of this.requestDatas) { + expect(await this.forwarder.nonces(request.from)).to.be.bignumber.eq(web3.utils.toBN(request.nonce + 1)); + } + }); + }); + + context('with tampered requests', function () { + beforeEach(async function () { + this.idx = 1; // Tampered idx + }); + + it('reverts with mismatched value', async function () { + this.requestDatas[this.idx].value = 100; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, another, { value: this.msgValue }), + 'ERC2771ForwarderMismatchedValue', + [batchValue(this.requestDatas), this.msgValue], + ); + }); + + context('when the refund receiver is the zero address', function () { + beforeEach(function () { + this.refundReceiver = constants.ZERO_ADDRESS; + }); + + for (const [key, value] of Object.entries(tamperedValues)) { + it(`reverts with at least one tampered request ${key}`, async function () { + const data = this.forgeData({ ...this.requestDatas[this.idx], [key]: value }); + + this.requestDatas[this.idx] = data.message; + + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ data, sig: this.requestDatas[this.idx].signature }), + data.message.from, + ], + ); + }); + } + + it('reverts with at least one untrustful to', async function () { + const data = this.forgeData({ ...this.requestDatas[this.idx], to: another }); + + this.requestDatas[this.idx] = data.message; + + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771UntrustfulTarget', + [this.requestDatas[this.idx].to, this.forwarder.address], + ); + }); + + it('reverts with at least one tampered request signature', async function () { + const tamperedSig = web3.utils.hexToBytes(this.requestDatas[this.idx].signature); + tamperedSig[42] ^= 0xff; + + this.requestDatas[this.idx].signature = web3.utils.bytesToHex(tamperedSig); + + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData(this.requestDatas[this.idx]), + sig: this.requestDatas[this.idx].signature, + }), + this.requestDatas[this.idx].from, + ], + ); + }); + + it('reverts with at least one valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestDatas[this.idx], { value: this.requestDatas[this.idx].value }); + + // And then fail due to an already used nonce + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData({ ...this.requestDatas[this.idx], nonce: this.requestDatas[this.idx].nonce + 1 }), + sig: this.requestDatas[this.idx].signature, + }), + this.requestDatas[this.idx].from, + ], + ); + }); + + it('reverts with at least one valid signature for expired deadline', async function () { + this.requestDatas[this.idx].deadline = this.timestamp.toNumber() - 1; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderExpiredRequest', + [this.timestamp.toNumber() - 1], + ); + }); + }); + + context('when the refund receiver is a known address', function () { + beforeEach(async function () { + this.refundReceiver = refundReceiver; + this.initialRefundReceiverBalance = web3.utils.toBN(await web3.eth.getBalance(this.refundReceiver)); + this.initialTamperedRequestNonce = await this.forwarder.nonces(this.requestDatas[this.idx].from); + }); + + for (const [key, value] of Object.entries(tamperedValues)) { + it(`ignores a request with tampered ${key} and refunds its value`, async function () { + const data = this.forgeData({ ...this.requestDatas[this.idx], [key]: value }); + + this.requestDatas[this.idx] = data.message; + + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: batchValue(this.requestDatas), + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + } + + it('ignores a request with a valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestDatas[this.idx], { value: this.requestDatas[this.idx].value }); + this.initialTamperedRequestNonce++; // Should be already incremented by the individual `execute` + + // And then ignore the same request in a batch due to an already used nonce + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: this.msgValue, + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + + it('ignores a request with a valid signature for expired deadline', async function () { + this.requestDatas[this.idx].deadline = this.timestamp.toNumber() - 1; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: this.msgValue, + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + + afterEach(async function () { + // The invalid request value was refunded + expect(await web3.eth.getBalance(this.refundReceiver)).to.be.bignumber.equal( + this.initialRefundReceiverBalance.add(web3.utils.toBN(this.requestDatas[this.idx].value)), + ); + + // The invalid request from's nonce was not incremented + expect(await this.forwarder.nonces(this.requestDatas[this.idx].from)).to.be.bignumber.eq( + web3.utils.toBN(this.initialTamperedRequestNonce), + ); + }); + }); + + it('bubbles out of gas', async function () { + this.requestDatas[this.idx].data = this.receiver.contract.methods.mockFunctionOutOfGas().encodeABI(); + this.requestDatas[this.idx].gas = 1_000_000; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + + const gasAvailable = 300_000; + await expectRevert.assertion( + this.forwarder.executeBatch(this.requestDatas, constants.ZERO_ADDRESS, { + gas: gasAvailable, + value: this.requestDatas.reduce((acc, { value }) => acc + Number(value), 0), + }), + ); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + expect(gasUsed).to.be.equal(gasAvailable); + }); + + it('bubbles out of gas forced by the relayer', async function () { + // Similarly to the single execute, a malicious relayer could grief requests. + + // We estimate until the selected request as if they were executed normally + const estimate = await this.gasUntil(this.requestDatas, this.idx); + + // We add a Buffer to account for all the gas that's used before the selected call. + // Note is slightly bigger because the selected request is not the index 0 and it affects + // the buffer needed. + const gasAvailable = estimate + 10_000; + + // The subcall out of gas should be caught by the contract and then bubbled up consuming + // the available gas with an `invalid` opcode. + await expectRevert.outOfGas( + this.forwarder.executeBatch(this.requestDatas, constants.ZERO_ADDRESS, { gas: gasAvailable }), + ); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + // We assert that indeed the gas was totally consumed. + expect(gasUsed).to.be.equal(gasAvailable); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/Clones.behaviour.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/Clones.behaviour.js new file mode 100644 index 0000000..b5fd3c5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/Clones.behaviour.js @@ -0,0 +1,136 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const DummyImplementation = artifacts.require('DummyImplementation'); + +module.exports = function shouldBehaveLikeClone(createClone) { + before('deploy implementation', async function () { + this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('initializes the proxy', async function () { + const dummy = new DummyImplementation(this.proxy); + expect(await dummy.value()).to.be.bignumber.equal(value.toString()); + }); + + it('has expected balance', async function () { + expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString()); + }); + }; + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createClone(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100; + const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods + .initializeNonPayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createClone(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42; + const initializeData = new DummyImplementation('').contract.methods + .initializePayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/Clones.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/Clones.test.js new file mode 100644 index 0000000..0862778 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/Clones.test.js @@ -0,0 +1,62 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { computeCreate2Address } = require('../helpers/create'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const shouldBehaveLikeClone = require('./Clones.behaviour'); + +const Clones = artifacts.require('$Clones'); + +contract('Clones', function (accounts) { + const [deployer] = accounts; + + describe('clone', function () { + shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { + const factory = await Clones.new(); + const receipt = await factory.$clone(implementation); + const address = receipt.logs.find(({ event }) => event === 'return$clone').args.instance; + await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); + return { address }; + }); + }); + + describe('cloneDeterministic', function () { + shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + const receipt = await factory.$cloneDeterministic(implementation, salt); + const address = receipt.logs.find(({ event }) => event === 'return$cloneDeterministic').args.instance; + await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); + return { address }; + }); + + it('address already used', async function () { + const implementation = web3.utils.randomHex(20); + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + // deploy once + expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic'); + // deploy twice + await expectRevertCustomError(factory.$cloneDeterministic(implementation, salt), 'ERC1167FailedCreateClone', []); + }); + + it('address prediction', async function () { + const implementation = web3.utils.randomHex(20); + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + const predicted = await factory.$predictDeterministicAddress(implementation, salt); + + const creationCode = [ + '0x3d602d80600a3d3981f3363d3d373d3d3d363d73', + implementation.replace(/0x/, '').toLowerCase(), + '5af43d82803e903d91602b57fd5bf3', + ].join(''); + + expect(computeCreate2Address(salt, creationCode, factory.address)).to.be.equal(predicted); + + expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic', { + instance: predicted, + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/ERC1967/ERC1967Proxy.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/ERC1967/ERC1967Proxy.test.js new file mode 100644 index 0000000..81cc435 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/ERC1967/ERC1967Proxy.test.js @@ -0,0 +1,12 @@ +const shouldBehaveLikeProxy = require('../Proxy.behaviour'); + +const ERC1967Proxy = artifacts.require('ERC1967Proxy'); + +contract('ERC1967Proxy', function (accounts) { + // `undefined`, `null` and other false-ish opts will not be forwarded. + const createProxy = async function (implementation, initData, opts) { + return ERC1967Proxy.new(implementation, initData, ...[opts].filter(Boolean)); + }; + + shouldBehaveLikeProxy(createProxy, accounts); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/ERC1967/ERC1967Utils.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/ERC1967/ERC1967Utils.test.js new file mode 100644 index 0000000..975b08d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/ERC1967/ERC1967Utils.test.js @@ -0,0 +1,172 @@ +const { expectEvent, constants } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { getAddressInSlot, setSlot, ImplementationSlot, AdminSlot, BeaconSlot } = require('../../helpers/erc1967'); + +const { ZERO_ADDRESS } = constants; + +const ERC1967Utils = artifacts.require('$ERC1967Utils'); + +const V1 = artifacts.require('DummyImplementation'); +const V2 = artifacts.require('CallReceiverMock'); +const UpgradeableBeaconMock = artifacts.require('UpgradeableBeaconMock'); +const UpgradeableBeaconReentrantMock = artifacts.require('UpgradeableBeaconReentrantMock'); + +contract('ERC1967Utils', function (accounts) { + const [, admin, anotherAccount] = accounts; + const EMPTY_DATA = '0x'; + + beforeEach('setup', async function () { + this.utils = await ERC1967Utils.new(); + this.v1 = await V1.new(); + this.v2 = await V2.new(); + }); + + describe('IMPLEMENTATION_SLOT', function () { + beforeEach('set v1 implementation', async function () { + await setSlot(this.utils, ImplementationSlot, this.v1.address); + }); + + describe('getImplementation', function () { + it('returns current implementation and matches implementation slot value', async function () { + expect(await this.utils.$getImplementation()).to.equal(this.v1.address); + expect(await getAddressInSlot(this.utils.address, ImplementationSlot)).to.equal(this.v1.address); + }); + }); + + describe('upgradeToAndCall', function () { + it('sets implementation in storage and emits event', async function () { + const newImplementation = this.v2.address; + const receipt = await this.utils.$upgradeToAndCall(newImplementation, EMPTY_DATA); + + expect(await getAddressInSlot(this.utils.address, ImplementationSlot)).to.equal(newImplementation); + expectEvent(receipt, 'Upgraded', { implementation: newImplementation }); + }); + + it('reverts when implementation does not contain code', async function () { + await expectRevertCustomError( + this.utils.$upgradeToAndCall(anotherAccount, EMPTY_DATA), + 'ERC1967InvalidImplementation', + [anotherAccount], + ); + }); + + describe('when data is empty', function () { + it('reverts when value is sent', async function () { + await expectRevertCustomError( + this.utils.$upgradeToAndCall(this.v2.address, EMPTY_DATA, { value: 1 }), + 'ERC1967NonPayable', + [], + ); + }); + }); + + describe('when data is not empty', function () { + it('delegates a call to the new implementation', async function () { + const initializeData = this.v2.contract.methods.mockFunction().encodeABI(); + const receipt = await this.utils.$upgradeToAndCall(this.v2.address, initializeData); + await expectEvent.inTransaction(receipt.tx, await V2.at(this.utils.address), 'MockFunctionCalled'); + }); + }); + }); + }); + + describe('ADMIN_SLOT', function () { + beforeEach('set admin', async function () { + await setSlot(this.utils, AdminSlot, admin); + }); + + describe('getAdmin', function () { + it('returns current admin and matches admin slot value', async function () { + expect(await this.utils.$getAdmin()).to.equal(admin); + expect(await getAddressInSlot(this.utils.address, AdminSlot)).to.equal(admin); + }); + }); + + describe('changeAdmin', function () { + it('sets admin in storage and emits event', async function () { + const newAdmin = anotherAccount; + const receipt = await this.utils.$changeAdmin(newAdmin); + + expect(await getAddressInSlot(this.utils.address, AdminSlot)).to.equal(newAdmin); + expectEvent(receipt, 'AdminChanged', { previousAdmin: admin, newAdmin: newAdmin }); + }); + + it('reverts when setting the address zero as admin', async function () { + await expectRevertCustomError(this.utils.$changeAdmin(ZERO_ADDRESS), 'ERC1967InvalidAdmin', [ZERO_ADDRESS]); + }); + }); + }); + + describe('BEACON_SLOT', function () { + beforeEach('set beacon', async function () { + this.beacon = await UpgradeableBeaconMock.new(this.v1.address); + await setSlot(this.utils, BeaconSlot, this.beacon.address); + }); + + describe('getBeacon', function () { + it('returns current beacon and matches beacon slot value', async function () { + expect(await this.utils.$getBeacon()).to.equal(this.beacon.address); + expect(await getAddressInSlot(this.utils.address, BeaconSlot)).to.equal(this.beacon.address); + }); + }); + + describe('upgradeBeaconToAndCall', function () { + it('sets beacon in storage and emits event', async function () { + const newBeacon = await UpgradeableBeaconMock.new(this.v2.address); + const receipt = await this.utils.$upgradeBeaconToAndCall(newBeacon.address, EMPTY_DATA); + + expect(await getAddressInSlot(this.utils.address, BeaconSlot)).to.equal(newBeacon.address); + expectEvent(receipt, 'BeaconUpgraded', { beacon: newBeacon.address }); + }); + + it('reverts when beacon does not contain code', async function () { + await expectRevertCustomError( + this.utils.$upgradeBeaconToAndCall(anotherAccount, EMPTY_DATA), + 'ERC1967InvalidBeacon', + [anotherAccount], + ); + }); + + it("reverts when beacon's implementation does not contain code", async function () { + const newBeacon = await UpgradeableBeaconMock.new(anotherAccount); + + await expectRevertCustomError( + this.utils.$upgradeBeaconToAndCall(newBeacon.address, EMPTY_DATA), + 'ERC1967InvalidImplementation', + [anotherAccount], + ); + }); + + describe('when data is empty', function () { + it('reverts when value is sent', async function () { + const newBeacon = await UpgradeableBeaconMock.new(this.v2.address); + await expectRevertCustomError( + this.utils.$upgradeBeaconToAndCall(newBeacon.address, EMPTY_DATA, { value: 1 }), + 'ERC1967NonPayable', + [], + ); + }); + }); + + describe('when data is not empty', function () { + it('delegates a call to the new implementation', async function () { + const initializeData = this.v2.contract.methods.mockFunction().encodeABI(); + const newBeacon = await UpgradeableBeaconMock.new(this.v2.address); + const receipt = await this.utils.$upgradeBeaconToAndCall(newBeacon.address, initializeData); + await expectEvent.inTransaction(receipt.tx, await V2.at(this.utils.address), 'MockFunctionCalled'); + }); + }); + + describe('reentrant beacon implementation() call', function () { + it('sees the new beacon implementation', async function () { + const newBeacon = await UpgradeableBeaconReentrantMock.new(); + await expectRevertCustomError( + this.utils.$upgradeBeaconToAndCall(newBeacon.address, '0x'), + 'BeaconProxyBeaconSlotAddress', + [newBeacon.address], + ); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/Proxy.behaviour.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/Proxy.behaviour.js new file mode 100644 index 0000000..acce6d1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/Proxy.behaviour.js @@ -0,0 +1,182 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { getSlot, ImplementationSlot } = require('../helpers/erc1967'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const DummyImplementation = artifacts.require('DummyImplementation'); + +module.exports = function shouldBehaveLikeProxy(createProxy, accounts) { + it('cannot be initialized with a non-contract address', async function () { + const nonContractAddress = accounts[0]; + const initializeData = Buffer.from(''); + await expectRevert.unspecified(createProxy(nonContractAddress, initializeData)); + }); + + before('deploy implementation', async function () { + this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('sets the implementation address', async function () { + const implementationSlot = await getSlot(this.proxy, ImplementationSlot); + const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40)); + expect(implementationAddress).to.be.equal(this.implementation); + }); + + it('initializes the proxy', async function () { + const dummy = new DummyImplementation(this.proxy); + expect(await dummy.value()).to.be.bignumber.equal(value.toString()); + }); + + it('has expected balance', async function () { + expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString()); + }); + }; + + describe('without initialization', function () { + const initializeData = Buffer.from(''); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ value: 0, balance: 0 }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevertCustomError( + createProxy(this.implementation, initializeData, { value }), + 'ERC1967NonPayable', + [], + ); + }); + }); + }); + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createProxy(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100; + const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods + .initializeNonPayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createProxy(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42; + const initializeData = new DummyImplementation('').contract.methods + .initializePayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + + describe('reverting initialization', function () { + const initializeData = new DummyImplementation('').contract.methods.reverts().encodeABI(); + + it('reverts', async function () { + await expectRevert(createProxy(this.implementation, initializeData), 'DummyImplementation reverted'); + }); + }); + }); +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/beacon/BeaconProxy.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/beacon/BeaconProxy.test.js new file mode 100644 index 0000000..d583d0f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/beacon/BeaconProxy.test.js @@ -0,0 +1,152 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { getSlot, BeaconSlot } = require('../../helpers/erc1967'); + +const { expectRevertCustomError } = require('../../helpers/customError'); + +const { expect } = require('chai'); + +const UpgradeableBeacon = artifacts.require('UpgradeableBeacon'); +const BeaconProxy = artifacts.require('BeaconProxy'); +const DummyImplementation = artifacts.require('DummyImplementation'); +const DummyImplementationV2 = artifacts.require('DummyImplementationV2'); +const BadBeaconNoImpl = artifacts.require('BadBeaconNoImpl'); +const BadBeaconNotContract = artifacts.require('BadBeaconNotContract'); + +contract('BeaconProxy', function (accounts) { + const [upgradeableBeaconAdmin, anotherAccount] = accounts; + + describe('bad beacon is not accepted', async function () { + it('non-contract beacon', async function () { + await expectRevertCustomError(BeaconProxy.new(anotherAccount, '0x'), 'ERC1967InvalidBeacon', [anotherAccount]); + }); + + it('non-compliant beacon', async function () { + const beacon = await BadBeaconNoImpl.new(); + await expectRevert.unspecified(BeaconProxy.new(beacon.address, '0x')); + }); + + it('non-contract implementation', async function () { + const beacon = await BadBeaconNotContract.new(); + const implementation = await beacon.implementation(); + await expectRevertCustomError(BeaconProxy.new(beacon.address, '0x'), 'ERC1967InvalidImplementation', [ + implementation, + ]); + }); + }); + + before('deploy implementation', async function () { + this.implementationV0 = await DummyImplementation.new(); + this.implementationV1 = await DummyImplementationV2.new(); + }); + + describe('initialization', function () { + before(function () { + this.assertInitialized = async ({ value, balance }) => { + const beaconSlot = await getSlot(this.proxy, BeaconSlot); + const beaconAddress = web3.utils.toChecksumAddress(beaconSlot.substr(-40)); + expect(beaconAddress).to.equal(this.beacon.address); + + const dummy = new DummyImplementation(this.proxy.address); + expect(await dummy.value()).to.bignumber.eq(value); + + expect(await web3.eth.getBalance(this.proxy.address)).to.bignumber.eq(balance); + }; + }); + + beforeEach('deploy beacon', async function () { + this.beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin); + }); + + it('no initialization', async function () { + const data = Buffer.from(''); + this.proxy = await BeaconProxy.new(this.beacon.address, data); + await this.assertInitialized({ value: '0', balance: '0' }); + }); + + it('non-payable initialization', async function () { + const value = '55'; + const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); + this.proxy = await BeaconProxy.new(this.beacon.address, data); + await this.assertInitialized({ value, balance: '0' }); + }); + + it('payable initialization', async function () { + const value = '55'; + const data = this.implementationV0.contract.methods.initializePayableWithValue(value).encodeABI(); + const balance = '100'; + this.proxy = await BeaconProxy.new(this.beacon.address, data, { value: balance }); + await this.assertInitialized({ value, balance }); + }); + + it('reverting initialization due to value', async function () { + const data = Buffer.from(''); + await expectRevertCustomError( + BeaconProxy.new(this.beacon.address, data, { value: '1' }), + 'ERC1967NonPayable', + [], + ); + }); + + it('reverting initialization function', async function () { + const data = this.implementationV0.contract.methods.reverts().encodeABI(); + await expectRevert(BeaconProxy.new(this.beacon.address, data), 'DummyImplementation reverted'); + }); + }); + + it('upgrade a proxy by upgrading its beacon', async function () { + const beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin); + + const value = '10'; + const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); + const proxy = await BeaconProxy.new(beacon.address, data); + + const dummy = new DummyImplementation(proxy.address); + + // test initial values + expect(await dummy.value()).to.bignumber.eq(value); + + // test initial version + expect(await dummy.version()).to.eq('V1'); + + // upgrade beacon + await beacon.upgradeTo(this.implementationV1.address, { from: upgradeableBeaconAdmin }); + + // test upgraded version + expect(await dummy.version()).to.eq('V2'); + }); + + it('upgrade 2 proxies by upgrading shared beacon', async function () { + const value1 = '10'; + const value2 = '42'; + + const beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin); + + const proxy1InitializeData = this.implementationV0.contract.methods + .initializeNonPayableWithValue(value1) + .encodeABI(); + const proxy1 = await BeaconProxy.new(beacon.address, proxy1InitializeData); + + const proxy2InitializeData = this.implementationV0.contract.methods + .initializeNonPayableWithValue(value2) + .encodeABI(); + const proxy2 = await BeaconProxy.new(beacon.address, proxy2InitializeData); + + const dummy1 = new DummyImplementation(proxy1.address); + const dummy2 = new DummyImplementation(proxy2.address); + + // test initial values + expect(await dummy1.value()).to.bignumber.eq(value1); + expect(await dummy2.value()).to.bignumber.eq(value2); + + // test initial version + expect(await dummy1.version()).to.eq('V1'); + expect(await dummy2.version()).to.eq('V1'); + + // upgrade beacon + await beacon.upgradeTo(this.implementationV1.address, { from: upgradeableBeaconAdmin }); + + // test upgraded version + expect(await dummy1.version()).to.eq('V2'); + expect(await dummy2.version()).to.eq('V2'); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/beacon/UpgradeableBeacon.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/beacon/UpgradeableBeacon.test.js new file mode 100644 index 0000000..0737f6f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/beacon/UpgradeableBeacon.test.js @@ -0,0 +1,54 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../../helpers/customError'); + +const UpgradeableBeacon = artifacts.require('UpgradeableBeacon'); +const Implementation1 = artifacts.require('Implementation1'); +const Implementation2 = artifacts.require('Implementation2'); + +contract('UpgradeableBeacon', function (accounts) { + const [owner, other] = accounts; + + it('cannot be created with non-contract implementation', async function () { + await expectRevertCustomError(UpgradeableBeacon.new(other, owner), 'BeaconInvalidImplementation', [other]); + }); + + context('once deployed', async function () { + beforeEach('deploying beacon', async function () { + this.v1 = await Implementation1.new(); + this.beacon = await UpgradeableBeacon.new(this.v1.address, owner); + }); + + it('emits Upgraded event to the first implementation', async function () { + const beacon = await UpgradeableBeacon.new(this.v1.address, owner); + await expectEvent.inTransaction(beacon.contract.transactionHash, beacon, 'Upgraded', { + implementation: this.v1.address, + }); + }); + + it('returns implementation', async function () { + expect(await this.beacon.implementation()).to.equal(this.v1.address); + }); + + it('can be upgraded by the owner', async function () { + const v2 = await Implementation2.new(); + const receipt = await this.beacon.upgradeTo(v2.address, { from: owner }); + expectEvent(receipt, 'Upgraded', { implementation: v2.address }); + expect(await this.beacon.implementation()).to.equal(v2.address); + }); + + it('cannot be upgraded to a non-contract', async function () { + await expectRevertCustomError(this.beacon.upgradeTo(other, { from: owner }), 'BeaconInvalidImplementation', [ + other, + ]); + }); + + it('cannot be upgraded by other account', async function () { + const v2 = await Implementation2.new(); + await expectRevertCustomError(this.beacon.upgradeTo(v2.address, { from: other }), 'OwnableUnauthorizedAccount', [ + other, + ]); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/ProxyAdmin.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/ProxyAdmin.test.js new file mode 100644 index 0000000..4d1a54f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/ProxyAdmin.test.js @@ -0,0 +1,103 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +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'); + +const { getAddressInSlot, ImplementationSlot } = require('../../helpers/erc1967'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { computeCreateAddress } = require('../../helpers/create'); + +contract('ProxyAdmin', function (accounts) { + const [proxyAdminOwner, anotherAccount] = accounts; + + before('set implementations', async function () { + this.implementationV1 = await ImplV1.new(); + this.implementationV2 = await ImplV2.new(); + }); + + beforeEach(async function () { + const initializeData = Buffer.from(''); + const proxy = await TransparentUpgradeableProxy.new(this.implementationV1.address, proxyAdminOwner, initializeData); + + const proxyNonce = await web3.eth.getTransactionCount(proxy.address); + const proxyAdminAddress = computeCreateAddress(proxy.address, proxyNonce - 1); // Nonce already used + this.proxyAdmin = await ProxyAdmin.at(proxyAdminAddress); + + this.proxy = await ITransparentUpgradeableProxy.at(proxy.address); + }); + + it('has an owner', async function () { + expect(await this.proxyAdmin.owner()).to.equal(proxyAdminOwner); + }); + + it('has an interface version', async function () { + expect(await this.proxyAdmin.UPGRADE_INTERFACE_VERSION()).to.equal('5.0.0'); + }); + + describe('without data', function () { + context('with unauthorized account', function () { + it('fails to upgrade', async function () { + await expectRevertCustomError( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, '0x', { + from: anotherAccount, + }), + 'OwnableUnauthorizedAccount', + [anotherAccount], + ); + }); + }); + + context('with authorized account', function () { + it('upgrades implementation', async function () { + await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, '0x', { + from: proxyAdminOwner, + }); + + const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementationAddress).to.be.equal(this.implementationV2.address); + }); + }); + }); + + describe('with data', function () { + context('with unauthorized account', function () { + it('fails to upgrade', async function () { + const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI(); + await expectRevertCustomError( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: anotherAccount, + }), + 'OwnableUnauthorizedAccount', + [anotherAccount], + ); + }); + }); + + context('with authorized account', function () { + context('with invalid callData', function () { + it('fails to upgrade', async function () { + const callData = '0x12345678'; + await expectRevert.unspecified( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: proxyAdminOwner, + }), + ); + }); + }); + + context('with valid callData', function () { + it('upgrades implementation', async function () { + const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI(); + await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: proxyAdminOwner, + }); + const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementationAddress).to.be.equal(this.implementationV2.address); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js new file mode 100644 index 0000000..103af7f --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -0,0 +1,413 @@ +const { BN, expectRevert, expectEvent, constants } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { getAddressInSlot, ImplementationSlot, AdminSlot } = require('../../helpers/erc1967'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const { expect } = require('chai'); +const { web3 } = require('hardhat'); +const { computeCreateAddress } = require('../../helpers/create'); +const { impersonate } = require('../../helpers/account'); + +const Implementation1 = artifacts.require('Implementation1'); +const Implementation2 = artifacts.require('Implementation2'); +const Implementation3 = artifacts.require('Implementation3'); +const Implementation4 = artifacts.require('Implementation4'); +const MigratableMockV1 = artifacts.require('MigratableMockV1'); +const MigratableMockV2 = artifacts.require('MigratableMockV2'); +const MigratableMockV3 = artifacts.require('MigratableMockV3'); +const InitializableMock = artifacts.require('InitializableMock'); +const DummyImplementation = artifacts.require('DummyImplementation'); +const ClashingImplementation = artifacts.require('ClashingImplementation'); +const Ownable = artifacts.require('Ownable'); + +module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProxy, initialOwner, accounts) { + const [anotherAccount] = accounts; + + async function createProxyWithImpersonatedProxyAdmin(logic, initData, opts = undefined) { + const proxy = await createProxy(logic, initData, opts); + + // Expect proxy admin to be the first and only contract created by the proxy + const proxyAdminAddress = computeCreateAddress(proxy.address, 1); + await impersonate(proxyAdminAddress); + + return { + proxy, + proxyAdminAddress, + }; + } + + before(async function () { + this.implementationV0 = (await DummyImplementation.new()).address; + this.implementationV1 = (await DummyImplementation.new()).address; + }); + + beforeEach(async function () { + const initializeData = Buffer.from(''); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + this.implementationV0, + initializeData, + ); + this.proxy = proxy; + this.proxyAdminAddress = proxyAdminAddress; + }); + + describe('implementation', function () { + it('returns the current implementation address', async function () { + const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementationAddress).to.be.equal(this.implementationV0); + }); + + it('delegates to the implementation', async function () { + const dummy = new DummyImplementation(this.proxy.address); + const value = await dummy.get(); + + expect(value).to.equal(true); + }); + }); + + describe('proxy admin', function () { + it('emits AdminChanged event during construction', async function () { + await expectEvent.inConstruction(this.proxy, 'AdminChanged', { + previousAdmin: ZERO_ADDRESS, + newAdmin: this.proxyAdminAddress, + }); + }); + + it('sets the proxy admin in storage with the correct initial owner', async function () { + expect(await getAddressInSlot(this.proxy, AdminSlot)).to.be.equal(this.proxyAdminAddress); + const proxyAdmin = await Ownable.at(this.proxyAdminAddress); + expect(await proxyAdmin.owner()).to.be.equal(initialOwner); + }); + + it('can overwrite the admin by the implementation', async function () { + const dummy = new DummyImplementation(this.proxy.address); + await dummy.unsafeOverrideAdmin(anotherAccount); + const ERC1967AdminSlotValue = await getAddressInSlot(this.proxy, AdminSlot); + expect(ERC1967AdminSlotValue).to.be.equal(anotherAccount); + + // Still allows previous admin to execute admin operations + expect(ERC1967AdminSlotValue).to.not.equal(this.proxyAdminAddress); + expectEvent( + await this.proxy.upgradeToAndCall(this.implementationV1, '0x', { from: this.proxyAdminAddress }), + 'Upgraded', + { + implementation: this.implementationV1, + }, + ); + }); + }); + + describe('upgradeToAndCall', function () { + describe('without migrations', function () { + beforeEach(async function () { + this.behavior = await InitializableMock.new(); + }); + + describe('when the call does not fail', function () { + const initializeData = new InitializableMock('').contract.methods['initializeWithX(uint256)'](42).encodeABI(); + + describe('when the sender is the admin', function () { + const value = 1e5; + + beforeEach(async function () { + this.receipt = await this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { + from: this.proxyAdminAddress, + value, + }); + }); + + it('upgrades to the requested implementation', async function () { + const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementationAddress).to.be.equal(this.behavior.address); + }); + + it('emits an event', function () { + expectEvent(this.receipt, 'Upgraded', { implementation: this.behavior.address }); + }); + + it('calls the initializer function', async function () { + const migratable = new InitializableMock(this.proxy.address); + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + }); + + it('sends given value to the proxy', async function () { + const balance = await web3.eth.getBalance(this.proxy.address); + expect(balance.toString()).to.be.bignumber.equal(value.toString()); + }); + + it('uses the storage of the proxy', async function () { + // storage layout should look as follows: + // - 0: Initializable storage ++ initializerRan ++ onlyInitializingRan + // - 1: x + const storedValue = await web3.eth.getStorageAt(this.proxy.address, 1); + expect(parseInt(storedValue)).to.eq(42); + }); + }); + + describe('when the sender is not the admin', function () { + it('reverts', async function () { + await expectRevert.unspecified( + this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from: anotherAccount }), + ); + }); + }); + }); + + describe('when the call does fail', function () { + const initializeData = new InitializableMock('').contract.methods.fail().encodeABI(); + + it('reverts', async function () { + await expectRevert.unspecified( + this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from: this.proxyAdminAddress }), + ); + }); + }); + }); + + describe('with migrations', function () { + describe('when the sender is the admin', function () { + const value = 1e5; + + describe('when upgrading to V1', function () { + const v1MigrationData = new MigratableMockV1('').contract.methods.initialize(42).encodeABI(); + + beforeEach(async function () { + this.behaviorV1 = await MigratableMockV1.new(); + this.balancePreviousV1 = new BN(await web3.eth.getBalance(this.proxy.address)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV1.address, v1MigrationData, { + from: this.proxyAdminAddress, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementation).to.be.equal(this.behaviorV1.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV1.address }); + }); + + it("calls the 'initialize' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV1(this.proxy.address); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + + const balance = await web3.eth.getBalance(this.proxy.address); + expect(new BN(balance)).to.be.bignumber.equal(this.balancePreviousV1.addn(value)); + }); + + describe('when upgrading to V2', function () { + const v2MigrationData = new MigratableMockV2('').contract.methods.migrate(10, 42).encodeABI(); + + beforeEach(async function () { + this.behaviorV2 = await MigratableMockV2.new(); + this.balancePreviousV2 = new BN(await web3.eth.getBalance(this.proxy.address)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV2.address, v2MigrationData, { + from: this.proxyAdminAddress, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementation).to.be.equal(this.behaviorV2.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV2.address }); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV2(this.proxy.address); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('10'); + + const y = await migratable.y(); + expect(y).to.be.bignumber.equal('42'); + + const balance = new BN(await web3.eth.getBalance(this.proxy.address)); + expect(balance).to.be.bignumber.equal(this.balancePreviousV2.addn(value)); + }); + + describe('when upgrading to V3', function () { + const v3MigrationData = new MigratableMockV3('').contract.methods['migrate()']().encodeABI(); + + beforeEach(async function () { + this.behaviorV3 = await MigratableMockV3.new(); + this.balancePreviousV3 = new BN(await web3.eth.getBalance(this.proxy.address)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV3.address, v3MigrationData, { + from: this.proxyAdminAddress, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementation).to.be.equal(this.behaviorV3.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV3.address }); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV3(this.proxy.address); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + + const y = await migratable.y(); + expect(y).to.be.bignumber.equal('10'); + + const balance = new BN(await web3.eth.getBalance(this.proxy.address)); + expect(balance).to.be.bignumber.equal(this.balancePreviousV3.addn(value)); + }); + }); + }); + }); + }); + + describe('when the sender is not the admin', function () { + const from = anotherAccount; + + it('reverts', async function () { + const behaviorV1 = await MigratableMockV1.new(); + const v1MigrationData = new MigratableMockV1('').contract.methods.initialize(42).encodeABI(); + await expectRevert.unspecified(this.proxy.upgradeToAndCall(behaviorV1.address, v1MigrationData, { from })); + }); + }); + }); + }); + + describe('transparent proxy', function () { + beforeEach('creating proxy', async function () { + const initializeData = Buffer.from(''); + this.clashingImplV0 = (await ClashingImplementation.new()).address; + this.clashingImplV1 = (await ClashingImplementation.new()).address; + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + this.clashingImplV0, + initializeData, + ); + this.proxy = proxy; + this.proxyAdminAddress = proxyAdminAddress; + this.clashing = new ClashingImplementation(this.proxy.address); + }); + + it('proxy admin cannot call delegated functions', async function () { + await expectRevertCustomError( + this.clashing.delegatedFunction({ from: this.proxyAdminAddress }), + 'ProxyDeniedAdminAccess', + [], + ); + }); + + describe('when function names clash', function () { + it('executes the proxy function if the sender is the admin', async function () { + const receipt = await this.proxy.upgradeToAndCall(this.clashingImplV1, '0x', { + from: this.proxyAdminAddress, + }); + expectEvent(receipt, 'Upgraded', { implementation: this.clashingImplV1 }); + }); + + it('delegates the call to implementation when sender is not the admin', async function () { + const receipt = await this.proxy.upgradeToAndCall(this.clashingImplV1, '0x', { + from: anotherAccount, + }); + expectEvent.notEmitted(receipt, 'Upgraded'); + expectEvent.inTransaction(receipt.tx, this.clashing, 'ClashingImplementationCall'); + }); + }); + }); + + describe('regression', () => { + const initializeData = Buffer.from(''); + + it('should add new function', async () => { + const instance1 = await Implementation1.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance1.address, + initializeData, + ); + + const proxyInstance1 = new Implementation1(proxy.address); + await proxyInstance1.setValue(42); + + const instance2 = await Implementation2.new(); + await proxy.upgradeToAndCall(instance2.address, '0x', { from: proxyAdminAddress }); + + const proxyInstance2 = new Implementation2(proxy.address); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('42'); + }); + + it('should remove function', async () => { + const instance2 = await Implementation2.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance2.address, + initializeData, + ); + + const proxyInstance2 = new Implementation2(proxy.address); + await proxyInstance2.setValue(42); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('42'); + + const instance1 = await Implementation1.new(); + await proxy.upgradeToAndCall(instance1.address, '0x', { from: proxyAdminAddress }); + + const proxyInstance1 = new Implementation2(proxy.address); + await expectRevert.unspecified(proxyInstance1.getValue()); + }); + + it('should change function signature', async () => { + const instance1 = await Implementation1.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance1.address, + initializeData, + ); + + const proxyInstance1 = new Implementation1(proxy.address); + await proxyInstance1.setValue(42); + + const instance3 = await Implementation3.new(); + await proxy.upgradeToAndCall(instance3.address, '0x', { from: proxyAdminAddress }); + const proxyInstance3 = new Implementation3(proxy.address); + + const res = await proxyInstance3.getValue(8); + expect(res.toString()).to.eq('50'); + }); + + it('should add fallback function', async () => { + const initializeData = Buffer.from(''); + const instance1 = await Implementation1.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance1.address, + initializeData, + ); + + const instance4 = await Implementation4.new(); + await proxy.upgradeToAndCall(instance4.address, '0x', { from: proxyAdminAddress }); + const proxyInstance4 = new Implementation4(proxy.address); + + const data = '0x'; + await web3.eth.sendTransaction({ to: proxy.address, from: anotherAccount, data }); + + const res = await proxyInstance4.getValue(); + expect(res.toString()).to.eq('1'); + }); + + it('should remove fallback function', async () => { + const instance4 = await Implementation4.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance4.address, + initializeData, + ); + + const instance2 = await Implementation2.new(); + await proxy.upgradeToAndCall(instance2.address, '0x', { from: proxyAdminAddress }); + + const data = '0x'; + await expectRevert.unspecified(web3.eth.sendTransaction({ to: proxy.address, from: anotherAccount, data })); + + const proxyInstance2 = new Implementation2(proxy.address); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('0'); + }); + }); +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/TransparentUpgradeableProxy.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/TransparentUpgradeableProxy.test.js new file mode 100644 index 0000000..f45e392 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/transparent/TransparentUpgradeableProxy.test.js @@ -0,0 +1,24 @@ +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 [owner, ...otherAccounts] = accounts; + + // `undefined`, `null` and other false-ish opts will not be forwarded. + const createProxy = async function (logic, initData, opts = undefined) { + const { address, transactionHash } = await TransparentUpgradeableProxy.new( + logic, + owner, + initData, + ...[opts].filter(Boolean), + ); + const instance = await ITransparentUpgradeableProxy.at(address); + return { ...instance, transactionHash }; + }; + + shouldBehaveLikeProxy(createProxy, otherAccounts); + shouldBehaveLikeTransparentUpgradeableProxy(createProxy, owner, otherAccounts); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/utils/Initializable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/utils/Initializable.test.js new file mode 100644 index 0000000..b9ff3b0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/utils/Initializable.test.js @@ -0,0 +1,220 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { MAX_UINT64 } = require('../../helpers/constants'); + +const InitializableMock = artifacts.require('InitializableMock'); +const ConstructorInitializableMock = artifacts.require('ConstructorInitializableMock'); +const ChildConstructorInitializableMock = artifacts.require('ChildConstructorInitializableMock'); +const ReinitializerMock = artifacts.require('ReinitializerMock'); +const SampleChild = artifacts.require('SampleChild'); +const DisableBad1 = artifacts.require('DisableBad1'); +const DisableBad2 = artifacts.require('DisableBad2'); +const DisableOk = artifacts.require('DisableOk'); + +contract('Initializable', function () { + describe('basic testing without inheritance', function () { + beforeEach('deploying', async function () { + this.contract = await InitializableMock.new(); + }); + + describe('before initialize', function () { + it('initializer has not run', async function () { + expect(await this.contract.initializerRan()).to.equal(false); + }); + + it('_initializing returns false before initialization', async function () { + expect(await this.contract.isInitializing()).to.equal(false); + }); + }); + + describe('after initialize', function () { + beforeEach('initializing', async function () { + await this.contract.initialize(); + }); + + it('initializer has run', async function () { + expect(await this.contract.initializerRan()).to.equal(true); + }); + + it('_initializing returns false after initialization', async function () { + expect(await this.contract.isInitializing()).to.equal(false); + }); + + it('initializer does not run again', async function () { + await expectRevertCustomError(this.contract.initialize(), 'InvalidInitialization', []); + }); + }); + + describe('nested under an initializer', function () { + it('initializer modifier reverts', async function () { + await expectRevertCustomError(this.contract.initializerNested(), 'InvalidInitialization', []); + }); + + it('onlyInitializing modifier succeeds', async function () { + await this.contract.onlyInitializingNested(); + expect(await this.contract.onlyInitializingRan()).to.equal(true); + }); + }); + + it('cannot call onlyInitializable function outside the scope of an initializable function', async function () { + await expectRevertCustomError(this.contract.initializeOnlyInitializing(), 'NotInitializing', []); + }); + }); + + it('nested initializer can run during construction', async function () { + const contract2 = await ConstructorInitializableMock.new(); + expect(await contract2.initializerRan()).to.equal(true); + expect(await contract2.onlyInitializingRan()).to.equal(true); + }); + + it('multiple constructor levels can be initializers', async function () { + const contract2 = await ChildConstructorInitializableMock.new(); + expect(await contract2.initializerRan()).to.equal(true); + expect(await contract2.childInitializerRan()).to.equal(true); + expect(await contract2.onlyInitializingRan()).to.equal(true); + }); + + describe('reinitialization', function () { + beforeEach('deploying', async function () { + this.contract = await ReinitializerMock.new(); + }); + + it('can reinitialize', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.initialize(); + expect(await this.contract.counter()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(2); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + await this.contract.reinitialize(3); + expect(await this.contract.counter()).to.be.bignumber.equal('3'); + }); + + it('can jump multiple steps', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.initialize(); + expect(await this.contract.counter()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(128); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + }); + + it('cannot nest reinitializers', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await expectRevertCustomError(this.contract.nestedReinitialize(2, 2), 'InvalidInitialization', []); + await expectRevertCustomError(this.contract.nestedReinitialize(2, 3), 'InvalidInitialization', []); + await expectRevertCustomError(this.contract.nestedReinitialize(3, 2), 'InvalidInitialization', []); + }); + + it('can chain reinitializers', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.chainReinitialize(2, 3); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + }); + + it('_getInitializedVersion returns right version', async function () { + await this.contract.initialize(); + expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(12); + expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('12'); + }); + + describe('contract locking', function () { + it('prevents initialization', async function () { + await this.contract.disableInitializers(); + await expectRevertCustomError(this.contract.initialize(), 'InvalidInitialization', []); + }); + + it('prevents re-initialization', async function () { + await this.contract.disableInitializers(); + await expectRevertCustomError(this.contract.reinitialize(255), 'InvalidInitialization', []); + }); + + it('can lock contract after initialization', async function () { + await this.contract.initialize(); + await this.contract.disableInitializers(); + await expectRevertCustomError(this.contract.reinitialize(255), 'InvalidInitialization', []); + }); + }); + }); + + describe('events', function () { + it('constructor initialization emits event', async function () { + const contract = await ConstructorInitializableMock.new(); + + await expectEvent.inTransaction(contract.transactionHash, contract, 'Initialized', { version: '1' }); + }); + + it('initialization emits event', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.initialize(); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1); + expectEvent(receipt, 'Initialized', { version: '1' }); + }); + + it('reinitialization emits event', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.reinitialize(128); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1); + expectEvent(receipt, 'Initialized', { version: '128' }); + }); + + it('chained reinitialization emits multiple events', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.chainReinitialize(2, 3); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(2); + expectEvent(receipt, 'Initialized', { version: '2' }); + expectEvent(receipt, 'Initialized', { version: '3' }); + }); + }); + + describe('complex testing with inheritance', function () { + const mother = '12'; + const gramps = '56'; + const father = '34'; + const child = '78'; + + beforeEach('deploying', async function () { + this.contract = await SampleChild.new(); + }); + + beforeEach('initializing', async function () { + await this.contract.initialize(mother, gramps, father, child); + }); + + it('initializes human', async function () { + expect(await this.contract.isHuman()).to.be.equal(true); + }); + + it('initializes mother', async function () { + expect(await this.contract.mother()).to.be.bignumber.equal(mother); + }); + + it('initializes gramps', async function () { + expect(await this.contract.gramps()).to.be.bignumber.equal(gramps); + }); + + it('initializes father', async function () { + expect(await this.contract.father()).to.be.bignumber.equal(father); + }); + + it('initializes child', async function () { + expect(await this.contract.child()).to.be.bignumber.equal(child); + }); + }); + + describe('disabling initialization', function () { + it('old and new patterns in bad sequence', async function () { + await expectRevertCustomError(DisableBad1.new(), 'InvalidInitialization', []); + await expectRevertCustomError(DisableBad2.new(), 'InvalidInitialization', []); + }); + + it('old and new patterns in good sequence', async function () { + const ok = await DisableOk.new(); + await expectEvent.inConstruction(ok, 'Initialized', { version: '1' }); + await expectEvent.inConstruction(ok, 'Initialized', { version: MAX_UINT64 }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/proxy/utils/UUPSUpgradeable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/proxy/utils/UUPSUpgradeable.test.js new file mode 100644 index 0000000..0baa905 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/proxy/utils/UUPSUpgradeable.test.js @@ -0,0 +1,131 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { getAddressInSlot, ImplementationSlot } = require('../../helpers/erc1967'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const ERC1967Proxy = artifacts.require('ERC1967Proxy'); +const UUPSUpgradeableMock = artifacts.require('UUPSUpgradeableMock'); +const UUPSUpgradeableUnsafeMock = artifacts.require('UUPSUpgradeableUnsafeMock'); +const NonUpgradeableMock = artifacts.require('NonUpgradeableMock'); +const UUPSUnsupportedProxiableUUID = artifacts.require('UUPSUnsupportedProxiableUUID'); +const Clones = artifacts.require('$Clones'); + +contract('UUPSUpgradeable', function () { + before(async function () { + this.implInitial = await UUPSUpgradeableMock.new(); + this.implUpgradeOk = await UUPSUpgradeableMock.new(); + this.implUpgradeUnsafe = await UUPSUpgradeableUnsafeMock.new(); + this.implUpgradeNonUUPS = await NonUpgradeableMock.new(); + this.implUnsupportedUUID = await UUPSUnsupportedProxiableUUID.new(); + // Used for testing non ERC1967 compliant proxies (clones are proxies that don't use the ERC1967 implementation slot) + this.cloneFactory = await Clones.new(); + }); + + beforeEach(async function () { + const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x'); + this.instance = await UUPSUpgradeableMock.at(address); + }); + + it('has an interface version', async function () { + expect(await this.instance.UPGRADE_INTERFACE_VERSION()).to.equal('5.0.0'); + }); + + it('upgrade to upgradeable implementation', async function () { + const { receipt } = await this.instance.upgradeToAndCall(this.implUpgradeOk.address, '0x'); + expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address }); + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.be.equal(this.implUpgradeOk.address); + }); + + it('upgrade to upgradeable implementation with call', async function () { + expect(await this.instance.current()).to.be.bignumber.equal('0'); + + const { receipt } = await this.instance.upgradeToAndCall( + this.implUpgradeOk.address, + this.implUpgradeOk.contract.methods.increment().encodeABI(), + ); + expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address }); + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.be.equal(this.implUpgradeOk.address); + + expect(await this.instance.current()).to.be.bignumber.equal('1'); + }); + + it('calling upgradeTo on the implementation reverts', async function () { + await expectRevertCustomError( + this.implInitial.upgradeToAndCall(this.implUpgradeOk.address, '0x'), + 'UUPSUnauthorizedCallContext', + [], + ); + }); + + it('calling upgradeToAndCall on the implementation reverts', async function () { + await expectRevertCustomError( + this.implInitial.upgradeToAndCall( + this.implUpgradeOk.address, + this.implUpgradeOk.contract.methods.increment().encodeABI(), + ), + 'UUPSUnauthorizedCallContext', + [], + ); + }); + + it('calling upgradeTo from a contract that is not an ERC1967 proxy (with the right implementation) reverts', async function () { + const receipt = await this.cloneFactory.$clone(this.implUpgradeOk.address); + const instance = await UUPSUpgradeableMock.at( + receipt.logs.find(({ event }) => event === 'return$clone').args.instance, + ); + + await expectRevertCustomError( + instance.upgradeToAndCall(this.implUpgradeUnsafe.address, '0x'), + 'UUPSUnauthorizedCallContext', + [], + ); + }); + + it('calling upgradeToAndCall from a contract that is not an ERC1967 proxy (with the right implementation) reverts', async function () { + const receipt = await this.cloneFactory.$clone(this.implUpgradeOk.address); + const instance = await UUPSUpgradeableMock.at( + receipt.logs.find(({ event }) => event === 'return$clone').args.instance, + ); + + await expectRevertCustomError( + instance.upgradeToAndCall(this.implUpgradeUnsafe.address, '0x'), + 'UUPSUnauthorizedCallContext', + [], + ); + }); + + it('rejects upgrading to an unsupported UUID', async function () { + await expectRevertCustomError( + this.instance.upgradeToAndCall(this.implUnsupportedUUID.address, '0x'), + 'UUPSUnsupportedProxiableUUID', + [web3.utils.keccak256('invalid UUID')], + ); + }); + + it('upgrade to and unsafe upgradeable implementation', async function () { + const { receipt } = await this.instance.upgradeToAndCall(this.implUpgradeUnsafe.address, '0x'); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeUnsafe.address }); + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.be.equal(this.implUpgradeUnsafe.address); + }); + + // delegate to a non existing upgradeTo function causes a low level revert + it('reject upgrade to non uups implementation', async function () { + await expectRevertCustomError( + this.instance.upgradeToAndCall(this.implUpgradeNonUUPS.address, '0x'), + 'ERC1967InvalidImplementation', + [this.implUpgradeNonUUPS.address], + ); + }); + + it('reject proxy address as implementation', async function () { + const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x'); + const otherInstance = await UUPSUpgradeableMock.at(address); + + await expectRevertCustomError( + this.instance.upgradeToAndCall(otherInstance.address, '0x'), + 'ERC1967InvalidImplementation', + [otherInstance.address], + ); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/ERC1155.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/ERC1155.behavior.js new file mode 100644 index 0000000..8df30a8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/ERC1155.behavior.js @@ -0,0 +1,905 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { Enum } = require('../../helpers/enums'); + +const ERC1155ReceiverMock = artifacts.require('ERC1155ReceiverMock'); +const RevertType = Enum('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'); + +function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, multiTokenHolder, recipient, proxy]) { + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); + + const firstTokenValue = new BN(1000); + const secondTokenValue = new BN(2000); + + const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; + const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; + + describe('like an ERC1155', function () { + describe('balanceOf', function () { + it('should return 0 when queried about the zero address', async function () { + expect(await this.token.balanceOf(ZERO_ADDRESS, firstTokenId)).to.be.bignumber.equal('0'); + }); + + context("when accounts don't own tokens", function () { + it('returns zero for given addresses', async function () { + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + }); + }); + + context('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstTokenValue, '0x', { + from: minter, + }); + await this.token.$_mint(secondTokenHolder, secondTokenId, secondTokenValue, '0x', { + from: minter, + }); + }); + + it('returns the amount of tokens owned by the given addresses', async function () { + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal(firstTokenValue); + + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal(secondTokenValue); + + expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('balanceOfBatch', function () { + it("reverts when input arrays don't match up", async function () { + const accounts1 = [firstTokenHolder, secondTokenHolder, firstTokenHolder, secondTokenHolder]; + const ids1 = [firstTokenId, secondTokenId, unknownTokenId]; + await expectRevertCustomError(this.token.balanceOfBatch(accounts1, ids1), 'ERC1155InvalidArrayLength', [ + accounts1.length, + ids1.length, + ]); + + const accounts2 = [firstTokenHolder, secondTokenHolder]; + const ids2 = [firstTokenId, secondTokenId, unknownTokenId]; + await expectRevertCustomError(this.token.balanceOfBatch(accounts2, ids2), 'ERC1155InvalidArrayLength', [ + accounts2.length, + ids2.length, + ]); + }); + + it('should return 0 as the balance when one of the addresses is the zero address', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, ZERO_ADDRESS], + [firstTokenId, secondTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal('0'); + expect(result[1]).to.be.a.bignumber.equal('0'); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + + context("when accounts don't own tokens", function () { + it('returns zeros for each account', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [firstTokenId, secondTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal('0'); + expect(result[1]).to.be.a.bignumber.equal('0'); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + }); + + context('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstTokenValue, '0x', { + from: minter, + }); + await this.token.$_mint(secondTokenHolder, secondTokenId, secondTokenValue, '0x', { + from: minter, + }); + }); + + it('returns amounts owned by each account in order passed', async function () { + const result = await this.token.balanceOfBatch( + [secondTokenHolder, firstTokenHolder, firstTokenHolder], + [secondTokenId, firstTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal(secondTokenValue); + expect(result[1]).to.be.a.bignumber.equal(firstTokenValue); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + + it('returns multiple times the balance of the same address when asked', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [firstTokenId, secondTokenId, firstTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal(result[2]); + expect(result[0]).to.be.a.bignumber.equal(firstTokenValue); + expect(result[1]).to.be.a.bignumber.equal(secondTokenValue); + expect(result[2]).to.be.a.bignumber.equal(firstTokenValue); + }); + }); + }); + + describe('setApprovalForAll', function () { + let receipt; + beforeEach(async function () { + receipt = await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + }); + + it('sets approval status which can be queried via isApprovedForAll', async function () { + expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(true); + }); + + it('emits an ApprovalForAll log', function () { + expectEvent(receipt, 'ApprovalForAll', { account: multiTokenHolder, operator: proxy, approved: true }); + }); + + it('can unset approval for an operator', async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(false); + }); + + it('reverts if attempting to approve zero address as an operator', async function () { + await expectRevertCustomError( + this.token.setApprovalForAll(constants.ZERO_ADDRESS, true, { from: multiTokenHolder }), + 'ERC1155InvalidOperator', + [constants.ZERO_ADDRESS], + ); + }); + }); + + describe('safeTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstTokenValue, '0x', { + from: minter, + }); + await this.token.$_mint(multiTokenHolder, secondTokenId, secondTokenValue, '0x', { + from: minter, + }); + }); + + it('reverts when transferring more than balance', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstTokenValue.addn(1), '0x', { + from: multiTokenHolder, + }), + 'ERC1155InsufficientBalance', + [multiTokenHolder, firstTokenValue, firstTokenValue.addn(1), firstTokenId], + ); + }); + + it('reverts when transferring to zero address', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(multiTokenHolder, ZERO_ADDRESS, firstTokenId, firstTokenValue, '0x', { + from: multiTokenHolder, + }), + 'ERC1155InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + + function transferWasSuccessful({ operator, from, id, value }) { + it('debits transferred balance from sender', async function () { + const newBalance = await this.token.balanceOf(from, id); + expect(newBalance).to.be.a.bignumber.equal('0'); + }); + + it('credits transferred balance to receiver', async function () { + const newBalance = await this.token.balanceOf(this.toWhom, id); + expect(newBalance).to.be.a.bignumber.equal(value); + }); + + it('emits a TransferSingle log', function () { + expectEvent(this.transferLogs, 'TransferSingle', { + operator, + from, + to: this.toWhom, + id, + value, + }); + }); + } + + context('when called by the multiTokenHolder', async function () { + beforeEach(async function () { + this.toWhom = recipient; + this.transferLogs = await this.token.safeTransferFrom( + multiTokenHolder, + recipient, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ); + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + }); + + it('preserves existing balances which are not transferred by multiTokenHolder', async function () { + const balance1 = await this.token.balanceOf(multiTokenHolder, secondTokenId); + expect(balance1).to.be.a.bignumber.equal(secondTokenValue); + + const balance2 = await this.token.balanceOf(recipient, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + + context('when called by an operator on behalf of the multiTokenHolder', function () { + context('when operator is not approved by multiTokenHolder', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstTokenValue, '0x', { + from: proxy, + }), + 'ERC1155MissingApprovalForAll', + [proxy, multiTokenHolder], + ); + }); + }); + + context('when operator is approved by multiTokenHolder', function () { + beforeEach(async function () { + this.toWhom = recipient; + await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.transferLogs = await this.token.safeTransferFrom( + multiTokenHolder, + recipient, + firstTokenId, + firstTokenValue, + '0x', + { + from: proxy, + }, + ); + }); + + transferWasSuccessful.call(this, { + operator: proxy, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + }); + + it("preserves operator's balances not involved in the transfer", async function () { + const balance1 = await this.token.balanceOf(proxy, firstTokenId); + expect(balance1).to.be.a.bignumber.equal('0'); + + const balance2 = await this.token.balanceOf(proxy, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + }); + + context('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.None, + ); + }); + + context('without data', function () { + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + data: null, + }); + }); + }); + + context('with data', function () { + const data = '0xf00dd00d'; + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + data, + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + data, + }); + }); + }); + }); + + context('to a receiver contract returning unexpected value', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new('0x00c0ffee', RECEIVER_BATCH_MAGIC_VALUE, RevertType.None); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstTokenValue, '0x', { + from: multiTokenHolder, + }), + 'ERC1155InvalidReceiver', + [this.receiver.address], + ); + }); + }); + + context('to a receiver contract that reverts', function () { + context('with a revert string', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithMessage, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + 'ERC1155ReceiverMock: reverting on receive', + ); + }); + }); + + context('without a revert string', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + 'ERC1155InvalidReceiver', + [this.receiver.address], + ); + }); + }); + + context('with a custom error', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + 'CustomError', + [RECEIVER_SINGLE_MAGIC_VALUE], + ); + }); + }); + + context('with a panic', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.Panic, + ); + }); + + it('reverts', async function () { + await expectRevert.unspecified( + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + ); + }); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + await expectRevert.unspecified( + this.token.safeTransferFrom( + multiTokenHolder, + invalidReceiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + ); + }); + }); + }); + + describe('safeBatchTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstTokenValue, '0x', { + from: minter, + }); + await this.token.$_mint(multiTokenHolder, secondTokenId, secondTokenValue, '0x', { + from: minter, + }); + }); + + it('reverts when transferring value more than any of balances', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue.addn(1)], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155InsufficientBalance', + [multiTokenHolder, secondTokenValue, secondTokenValue.addn(1), secondTokenId], + ); + }); + + it("reverts when ids array length doesn't match values array length", async function () { + const ids1 = [firstTokenId]; + const tokenValues1 = [firstTokenValue, secondTokenValue]; + + await expectRevertCustomError( + this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids1, tokenValues1, '0x', { + from: multiTokenHolder, + }), + 'ERC1155InvalidArrayLength', + [ids1.length, tokenValues1.length], + ); + + const ids2 = [firstTokenId, secondTokenId]; + const tokenValues2 = [firstTokenValue]; + await expectRevertCustomError( + this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids2, tokenValues2, '0x', { + from: multiTokenHolder, + }), + 'ERC1155InvalidArrayLength', + [ids2.length, tokenValues2.length], + ); + }); + + it('reverts when transferring to zero address', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + ZERO_ADDRESS, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + + it('reverts when transferring from zero address', async function () { + await expectRevertCustomError( + this.token.$_safeBatchTransferFrom(ZERO_ADDRESS, multiTokenHolder, [firstTokenId], [firstTokenValue], '0x'), + 'ERC1155InvalidSender', + [ZERO_ADDRESS], + ); + }); + + function batchTransferWasSuccessful({ operator, from, ids, values }) { + it('debits transferred balances from sender', async function () { + const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(from), ids); + for (const newBalance of newBalances) { + expect(newBalance).to.be.a.bignumber.equal('0'); + } + }); + + it('credits transferred balances to receiver', async function () { + const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(this.toWhom), ids); + for (let i = 0; i < newBalances.length; i++) { + expect(newBalances[i]).to.be.a.bignumber.equal(values[i]); + } + }); + + it('emits a TransferBatch log', function () { + expectEvent(this.transferLogs, 'TransferBatch', { + operator, + from, + to: this.toWhom, + // ids, + // values, + }); + }); + } + + context('when called by the multiTokenHolder', async function () { + beforeEach(async function () { + this.toWhom = recipient; + this.transferLogs = await this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ); + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + }); + }); + + context('when called by an operator on behalf of the multiTokenHolder', function () { + context('when operator is not approved by multiTokenHolder', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: proxy }, + ), + 'ERC1155MissingApprovalForAll', + [proxy, multiTokenHolder], + ); + }); + }); + + context('when operator is approved by multiTokenHolder', function () { + beforeEach(async function () { + this.toWhom = recipient; + await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.transferLogs = await this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: proxy }, + ); + }); + + batchTransferWasSuccessful.call(this, { + operator: proxy, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + }); + + it("preserves operator's balances not involved in the transfer", async function () { + const balance1 = await this.token.balanceOf(proxy, firstTokenId); + expect(balance1).to.be.a.bignumber.equal('0'); + const balance2 = await this.token.balanceOf(proxy, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + }); + + context('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.None, + ); + }); + + context('without data', function () { + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + }); + + it('calls onERC1155BatchReceived', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstTokenValue, secondTokenValue], + data: null, + }); + }); + }); + + context('with data', function () { + const data = '0xf00dd00d'; + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + data, + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstTokenValue, secondTokenValue], + data, + }); + }); + }); + }); + + context('to a receiver contract returning unexpected value', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_SINGLE_MAGIC_VALUE, + RevertType.None, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155InvalidReceiver', + [this.receiver.address], + ); + }); + }); + + context('to a receiver contract that reverts', function () { + context('with a revert string', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithMessage, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155ReceiverMock: reverting on batch receive', + ); + }); + }); + + context('without a revert string', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155InvalidReceiver', + [this.receiver.address], + ); + }); + }); + + context('with a custom error', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'CustomError', + [RECEIVER_SINGLE_MAGIC_VALUE], + ); + }); + }); + + context('with a panic', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.Panic, + ); + }); + + it('reverts', async function () { + await expectRevert.unspecified( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + ); + }); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + await expectRevert.unspecified( + this.token.safeBatchTransferFrom( + multiTokenHolder, + invalidReceiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + ); + }); + }); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155']); + }); +} + +module.exports = { + shouldBehaveLikeERC1155, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/ERC1155.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/ERC1155.test.js new file mode 100644 index 0000000..58d747a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/ERC1155.test.js @@ -0,0 +1,252 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../../helpers/customError'); + +const { shouldBehaveLikeERC1155 } = require('./ERC1155.behavior'); +const ERC1155Mock = artifacts.require('$ERC1155'); + +contract('ERC1155', function (accounts) { + const [operator, tokenHolder, tokenBatchHolder, ...otherAccounts] = accounts; + + const initialURI = 'https://token-cdn-domain/{id}.json'; + + beforeEach(async function () { + this.token = await ERC1155Mock.new(initialURI); + }); + + shouldBehaveLikeERC1155(otherAccounts); + + describe('internal functions', function () { + const tokenId = new BN(1990); + const mintValue = new BN(9001); + const burnValue = new BN(3000); + + const tokenBatchIds = [new BN(2000), new BN(2010), new BN(2020)]; + const mintValues = [new BN(5000), new BN(10000), new BN(42195)]; + const burnValues = [new BN(5000), new BN(9001), new BN(195)]; + + const data = '0x12345678'; + + describe('_mint', function () { + it('reverts with a zero destination address', async function () { + await expectRevertCustomError( + this.token.$_mint(ZERO_ADDRESS, tokenId, mintValue, data), + 'ERC1155InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(tokenHolder, tokenId, mintValue, data, { from: operator }); + }); + + it('emits a TransferSingle event', function () { + expectEvent(this.receipt, 'TransferSingle', { + operator, + from: ZERO_ADDRESS, + to: tokenHolder, + id: tokenId, + value: mintValue, + }); + }); + + it('credits the minted token value', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintValue); + }); + }); + }); + + describe('_mintBatch', function () { + it('reverts with a zero destination address', async function () { + await expectRevertCustomError( + this.token.$_mintBatch(ZERO_ADDRESS, tokenBatchIds, mintValues, data), + 'ERC1155InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + + it('reverts if length of inputs do not match', async function () { + await expectRevertCustomError( + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues.slice(1), data), + 'ERC1155InvalidArrayLength', + [tokenBatchIds.length, mintValues.length - 1], + ); + + await expectRevertCustomError( + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds.slice(1), mintValues, data), + 'ERC1155InvalidArrayLength', + [tokenBatchIds.length - 1, mintValues.length], + ); + }); + + context('with minted batch of tokens', function () { + beforeEach(async function () { + this.receipt = await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues, data, { + from: operator, + }); + }); + + it('emits a TransferBatch event', function () { + expectEvent(this.receipt, 'TransferBatch', { + operator, + from: ZERO_ADDRESS, + to: tokenBatchHolder, + }); + }); + + it('credits the minted batch of tokens', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds, + ); + + for (let i = 0; i < holderBatchBalances.length; i++) { + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintValues[i]); + } + }); + }); + }); + + describe('_burn', function () { + it("reverts when burning the zero account's tokens", async function () { + await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, tokenId, mintValue), 'ERC1155InvalidSender', [ + ZERO_ADDRESS, + ]); + }); + + it('reverts when burning a non-existent token id', async function () { + await expectRevertCustomError( + this.token.$_burn(tokenHolder, tokenId, mintValue), + 'ERC1155InsufficientBalance', + [tokenHolder, 0, mintValue, tokenId], + ); + }); + + it('reverts when burning more than available tokens', async function () { + await this.token.$_mint(tokenHolder, tokenId, mintValue, data, { from: operator }); + + await expectRevertCustomError( + this.token.$_burn(tokenHolder, tokenId, mintValue.addn(1)), + 'ERC1155InsufficientBalance', + [tokenHolder, mintValue, mintValue.addn(1), tokenId], + ); + }); + + context('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mint(tokenHolder, tokenId, mintValue, data); + this.receipt = await this.token.$_burn(tokenHolder, tokenId, burnValue, { from: operator }); + }); + + it('emits a TransferSingle event', function () { + expectEvent(this.receipt, 'TransferSingle', { + operator, + from: tokenHolder, + to: ZERO_ADDRESS, + id: tokenId, + value: burnValue, + }); + }); + + it('accounts for both minting and burning', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintValue.sub(burnValue)); + }); + }); + }); + + describe('_burnBatch', function () { + it("reverts when burning the zero account's tokens", async function () { + await expectRevertCustomError( + this.token.$_burnBatch(ZERO_ADDRESS, tokenBatchIds, burnValues), + 'ERC1155InvalidSender', + [ZERO_ADDRESS], + ); + }); + + it('reverts if length of inputs do not match', async function () { + await expectRevertCustomError( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues.slice(1)), + 'ERC1155InvalidArrayLength', + [tokenBatchIds.length, burnValues.length - 1], + ); + + await expectRevertCustomError( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds.slice(1), burnValues), + 'ERC1155InvalidArrayLength', + [tokenBatchIds.length - 1, burnValues.length], + ); + }); + + it('reverts when burning a non-existent token id', async function () { + await expectRevertCustomError( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues), + 'ERC1155InsufficientBalance', + [tokenBatchHolder, 0, tokenBatchIds[0], burnValues[0]], + ); + }); + + context('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues, data); + this.receipt = await this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues, { from: operator }); + }); + + it('emits a TransferBatch event', function () { + expectEvent(this.receipt, 'TransferBatch', { + operator, + from: tokenBatchHolder, + to: ZERO_ADDRESS, + // ids: tokenBatchIds, + // values: burnValues, + }); + }); + + it('accounts for both minting and burning', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds, + ); + + for (let i = 0; i < holderBatchBalances.length; i++) { + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintValues[i].sub(burnValues[i])); + } + }); + }); + }); + }); + + describe('ERC1155MetadataURI', function () { + const firstTokenID = new BN('42'); + const secondTokenID = new BN('1337'); + + it('emits no URI event in constructor', async function () { + await expectEvent.notEmitted.inConstruction(this.token, 'URI'); + }); + + it('sets the initial URI for all token types', async function () { + expect(await this.token.uri(firstTokenID)).to.be.equal(initialURI); + expect(await this.token.uri(secondTokenID)).to.be.equal(initialURI); + }); + + describe('_setURI', function () { + const newURI = 'https://token-cdn-domain/{locale}/{id}.json'; + + it('emits no URI event', async function () { + const receipt = await this.token.$_setURI(newURI); + + expectEvent.notEmitted(receipt, 'URI'); + }); + + it('sets the new URI for all token types', async function () { + await this.token.$_setURI(newURI); + + expect(await this.token.uri(firstTokenID)).to.be.equal(newURI); + expect(await this.token.uri(secondTokenID)).to.be.equal(newURI); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Burnable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Burnable.test.js new file mode 100644 index 0000000..fc94db0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Burnable.test.js @@ -0,0 +1,71 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC1155Burnable = artifacts.require('$ERC1155Burnable'); + +contract('ERC1155Burnable', function (accounts) { + const [holder, operator, other] = accounts; + + const uri = 'https://token.com'; + + const tokenIds = [new BN('42'), new BN('1137')]; + const values = [new BN('3000'), new BN('9902')]; + + beforeEach(async function () { + this.token = await ERC1155Burnable.new(uri); + + await this.token.$_mint(holder, tokenIds[0], values[0], '0x'); + await this.token.$_mint(holder, tokenIds[1], values[1], '0x'); + }); + + describe('burn', function () { + it('holder can burn their tokens', async function () { + await this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: holder }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: operator }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expectRevertCustomError( + this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: other }), + 'ERC1155MissingApprovalForAll', + [other, holder], + ); + }); + }); + + describe('burnBatch', function () { + it('holder can burn their tokens', async function () { + await this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: holder }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: operator }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expectRevertCustomError( + this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: other }), + 'ERC1155MissingApprovalForAll', + [other, holder], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Pausable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Pausable.test.js new file mode 100644 index 0000000..248ea56 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Pausable.test.js @@ -0,0 +1,113 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC1155Pausable = artifacts.require('$ERC1155Pausable'); + +contract('ERC1155Pausable', function (accounts) { + const [holder, operator, receiver, other] = accounts; + + const uri = 'https://token.com'; + + beforeEach(async function () { + this.token = await ERC1155Pausable.new(uri); + }); + + context('when token is paused', function () { + const firstTokenId = new BN('37'); + const firstTokenValue = new BN('42'); + + const secondTokenId = new BN('19842'); + const secondTokenValue = new BN('23'); + + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); + + await this.token.$_pause(); + }); + + it('reverts when trying to safeTransferFrom from holder', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenValue, '0x', { from: holder }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeTransferFrom from operator', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenValue, '0x', { from: operator }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeBatchTransferFrom from holder', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenValue], '0x', { from: holder }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeBatchTransferFrom from operator', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenValue], '0x', { + from: operator, + }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to mint', async function () { + await expectRevertCustomError( + this.token.$_mint(holder, secondTokenId, secondTokenValue, '0x'), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to mintBatch', async function () { + await expectRevertCustomError( + this.token.$_mintBatch(holder, [secondTokenId], [secondTokenValue], '0x'), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to burn', async function () { + await expectRevertCustomError(this.token.$_burn(holder, firstTokenId, firstTokenValue), 'EnforcedPause', []); + }); + + it('reverts when trying to burnBatch', async function () { + await expectRevertCustomError( + this.token.$_burnBatch(holder, [firstTokenId], [firstTokenValue]), + 'EnforcedPause', + [], + ); + }); + + describe('setApprovalForAll', function () { + it('approves an operator', async function () { + await this.token.setApprovalForAll(other, true, { from: holder }); + expect(await this.token.isApprovedForAll(holder, other)).to.equal(true); + }); + }); + + describe('balanceOf', function () { + it('returns the token value owned by the given address', async function () { + const balance = await this.token.balanceOf(holder, firstTokenId); + expect(balance).to.be.bignumber.equal(firstTokenValue); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(holder, operator)).to.equal(true); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Supply.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Supply.test.js new file mode 100644 index 0000000..bf86920 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155Supply.test.js @@ -0,0 +1,116 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const { ZERO_ADDRESS } = constants; + +const ERC1155Supply = artifacts.require('$ERC1155Supply'); + +contract('ERC1155Supply', function (accounts) { + const [holder] = accounts; + + const uri = 'https://token.com'; + + const firstTokenId = new BN('37'); + const firstTokenValue = new BN('42'); + + const secondTokenId = new BN('19842'); + const secondTokenValue = new BN('23'); + + beforeEach(async function () { + this.token = await ERC1155Supply.new(uri); + }); + + context('before mint', function () { + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + }); + }); + + context('after mint', function () { + context('single', function () { + beforeEach(async function () { + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(true); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenValue); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal(firstTokenValue); + }); + }); + + context('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue], '0x'); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(true); + expect(await this.token.exists(secondTokenId)).to.be.equal(true); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenValue); + expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal(secondTokenValue); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal( + firstTokenValue.add(secondTokenValue), + ); + }); + }); + }); + + context('after burn', function () { + context('single', function () { + beforeEach(async function () { + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_burn(holder, firstTokenId, firstTokenValue); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + }); + }); + + context('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue], '0x'); + await this.token.$_burnBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue]); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + expect(await this.token.exists(secondTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + }); + }); + }); + + context('other', function () { + it('supply unaffected by no-op', async function () { + this.token.safeTransferFrom(ZERO_ADDRESS, ZERO_ADDRESS, firstTokenId, firstTokenValue, '0x', { + from: ZERO_ADDRESS, + }); + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155URIStorage.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155URIStorage.test.js new file mode 100644 index 0000000..58ac67b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/extensions/ERC1155URIStorage.test.js @@ -0,0 +1,66 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { artifacts } = require('hardhat'); + +const ERC1155URIStorage = artifacts.require('$ERC1155URIStorage'); + +contract(['ERC1155URIStorage'], function (accounts) { + const [holder] = accounts; + + const erc1155Uri = 'https://token.com/nfts/'; + const baseUri = 'https://token.com/'; + + const tokenId = new BN('1'); + const value = new BN('3000'); + + describe('with base uri set', function () { + beforeEach(async function () { + this.token = await ERC1155URIStorage.new(erc1155Uri); + await this.token.$_setBaseURI(baseUri); + + await this.token.$_mint(holder, tokenId, value, '0x'); + }); + + it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(erc1155Uri); + }); + + it('can request the token uri, returning the concatenated uri if a token uri was set', async function () { + const tokenUri = '1234/'; + const receipt = await this.token.$_setURI(tokenId, tokenUri); + + const receivedTokenUri = await this.token.uri(tokenId); + + const expectedUri = `${baseUri}${tokenUri}`; + expect(receivedTokenUri).to.be.equal(expectedUri); + expectEvent(receipt, 'URI', { value: expectedUri, id: tokenId }); + }); + }); + + describe('with base uri set to the empty string', function () { + beforeEach(async function () { + this.token = await ERC1155URIStorage.new(''); + + await this.token.$_mint(holder, tokenId, value, '0x'); + }); + + it('can request the token uri, returning an empty string if no token uri was set', async function () { + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(''); + }); + + it('can request the token uri, returning the token uri if a token uri was set', async function () { + const tokenUri = 'ipfs://1234/'; + const receipt = await this.token.$_setURI(tokenId, tokenUri); + + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(tokenUri); + expectEvent(receipt, 'URI', { value: tokenUri, id: tokenId }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/utils/ERC1155Holder.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/utils/ERC1155Holder.test.js new file mode 100644 index 0000000..ee818ea --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC1155/utils/ERC1155Holder.test.js @@ -0,0 +1,64 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const ERC1155Holder = artifacts.require('$ERC1155Holder'); +const ERC1155 = artifacts.require('$ERC1155'); + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +contract('ERC1155Holder', function (accounts) { + const [creator] = accounts; + const uri = 'https://token-cdn-domain/{id}.json'; + const multiTokenIds = [new BN(1), new BN(2), new BN(3)]; + const multiTokenValues = [new BN(1000), new BN(2000), new BN(3000)]; + const transferData = '0x12345678'; + + beforeEach(async function () { + this.multiToken = await ERC1155.new(uri); + this.holder = await ERC1155Holder.new(); + await this.multiToken.$_mintBatch(creator, multiTokenIds, multiTokenValues, '0x'); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver']); + + it('receives ERC1155 tokens from a single ID', async function () { + await this.multiToken.safeTransferFrom( + creator, + this.holder.address, + multiTokenIds[0], + multiTokenValues[0], + transferData, + { from: creator }, + ); + + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[0])).to.be.bignumber.equal( + multiTokenValues[0], + ); + + for (let i = 1; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + } + }); + + it('receives ERC1155 tokens from a multiple IDs', async function () { + for (let i = 0; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + } + + await this.multiToken.safeBatchTransferFrom( + creator, + this.holder.address, + multiTokenIds, + multiTokenValues, + transferData, + { from: creator }, + ); + + for (let i = 0; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal( + multiTokenValues[i], + ); + } + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/ERC20.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/ERC20.behavior.js new file mode 100644 index 0000000..b6f8617 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/ERC20.behavior.js @@ -0,0 +1,340 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS, MAX_UINT256 } = constants; + +const { expectRevertCustomError } = require('../../helpers/customError'); + +function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { + const [initialHolder, recipient, anotherAccount] = accounts; + const { forcedApproval } = opts; + + describe('total supply', function () { + it('returns the total token value', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + }); + + describe('balanceOf', function () { + describe('when the requested account has no tokens', function () { + it('returns zero', async function () { + expect(await this.token.balanceOf(anotherAccount)).to.be.bignumber.equal('0'); + }); + }); + + describe('when the requested account has some tokens', function () { + it('returns the total token value', async function () { + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(initialSupply); + }); + }); + }); + + describe('transfer', function () { + shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, value) { + return this.token.transfer(to, value, { from }); + }); + }); + + describe('transfer from', function () { + const spender = recipient; + + describe('when the token owner is not the zero address', function () { + const tokenOwner = initialHolder; + + describe('when the recipient is not the zero address', function () { + const to = anotherAccount; + + describe('when the spender has enough allowance', function () { + beforeEach(async function () { + await this.token.approve(spender, initialSupply, { from: initialHolder }); + }); + + describe('when the token owner has enough balance', function () { + const value = initialSupply; + + it('transfers the requested value', async function () { + await this.token.transferFrom(tokenOwner, to, value, { from: spender }); + + expect(await this.token.balanceOf(tokenOwner)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(value); + }); + + it('decreases the spender allowance', async function () { + await this.token.transferFrom(tokenOwner, to, value, { from: spender }); + + expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal('0'); + }); + + it('emits a transfer event', async function () { + expectEvent(await this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'Transfer', { + from: tokenOwner, + to: to, + value: value, + }); + }); + + if (forcedApproval) { + it('emits an approval event', async function () { + expectEvent(await this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'Approval', { + owner: tokenOwner, + spender: spender, + value: await this.token.allowance(tokenOwner, spender), + }); + }); + } else { + it('does not emit an approval event', async function () { + expectEvent.notEmitted( + await this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'Approval', + ); + }); + } + }); + + describe('when the token owner does not have enough balance', function () { + const value = initialSupply; + + beforeEach('reducing balance', async function () { + await this.token.transfer(to, 1, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InsufficientBalance', + [tokenOwner, value - 1, value], + ); + }); + }); + }); + + describe('when the spender does not have enough allowance', function () { + const allowance = initialSupply.subn(1); + + beforeEach(async function () { + await this.token.approve(spender, allowance, { from: tokenOwner }); + }); + + describe('when the token owner has enough balance', function () { + const value = initialSupply; + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InsufficientAllowance', + [spender, allowance, value], + ); + }); + }); + + describe('when the token owner does not have enough balance', function () { + const value = allowance; + + beforeEach('reducing balance', async function () { + await this.token.transfer(to, 2, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InsufficientBalance', + [tokenOwner, value - 1, value], + ); + }); + }); + }); + + describe('when the spender has unlimited allowance', function () { + beforeEach(async function () { + await this.token.approve(spender, MAX_UINT256, { from: initialHolder }); + }); + + it('does not decrease the spender allowance', async function () { + await this.token.transferFrom(tokenOwner, to, 1, { from: spender }); + + expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal(MAX_UINT256); + }); + + it('does not emit an approval event', async function () { + expectEvent.notEmitted(await this.token.transferFrom(tokenOwner, to, 1, { from: spender }), 'Approval'); + }); + }); + }); + + describe('when the recipient is the zero address', function () { + const value = initialSupply; + const to = ZERO_ADDRESS; + + beforeEach(async function () { + await this.token.approve(spender, value, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + }); + }); + + describe('when the token owner is the zero address', function () { + const value = 0; + const tokenOwner = ZERO_ADDRESS; + const to = recipient; + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InvalidApprover', + [ZERO_ADDRESS], + ); + }); + }); + }); + + describe('approve', function () { + shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, value) { + return this.token.approve(spender, value, { from: owner }); + }); + }); +} + +function shouldBehaveLikeERC20Transfer(from, to, balance, transfer) { + describe('when the recipient is not the zero address', function () { + describe('when the sender does not have enough balance', function () { + const value = balance.addn(1); + + it('reverts', async function () { + await expectRevertCustomError(transfer.call(this, from, to, value), 'ERC20InsufficientBalance', [ + from, + balance, + value, + ]); + }); + }); + + describe('when the sender transfers all balance', function () { + const value = balance; + + it('transfers the requested value', async function () { + await transfer.call(this, from, to, value); + + expect(await this.token.balanceOf(from)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(value); + }); + + it('emits a transfer event', async function () { + expectEvent(await transfer.call(this, from, to, value), 'Transfer', { from, to, value: value }); + }); + }); + + describe('when the sender transfers zero tokens', function () { + const value = new BN('0'); + + it('transfers the requested value', async function () { + await transfer.call(this, from, to, value); + + expect(await this.token.balanceOf(from)).to.be.bignumber.equal(balance); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal('0'); + }); + + it('emits a transfer event', async function () { + expectEvent(await transfer.call(this, from, to, value), 'Transfer', { from, to, value: value }); + }); + }); + }); + + describe('when the recipient is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError(transfer.call(this, from, ZERO_ADDRESS, balance), 'ERC20InvalidReceiver', [ + ZERO_ADDRESS, + ]); + }); + }); +} + +function shouldBehaveLikeERC20Approve(owner, spender, supply, approve) { + describe('when the spender is not the zero address', function () { + describe('when the sender has enough balance', function () { + const value = supply; + + it('emits an approval event', async function () { + expectEvent(await approve.call(this, owner, spender, value), 'Approval', { + owner: owner, + spender: spender, + value: value, + }); + }); + + describe('when there was no approved value before', function () { + it('approves the requested value', async function () { + await approve.call(this, owner, spender, value); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + }); + + describe('when the spender had an approved value', function () { + beforeEach(async function () { + await approve.call(this, owner, spender, new BN(1)); + }); + + it('approves the requested value and replaces the previous one', async function () { + await approve.call(this, owner, spender, value); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + }); + }); + + describe('when the sender does not have enough balance', function () { + const value = supply.addn(1); + + it('emits an approval event', async function () { + expectEvent(await approve.call(this, owner, spender, value), 'Approval', { + owner: owner, + spender: spender, + value: value, + }); + }); + + describe('when there was no approved value before', function () { + it('approves the requested value', async function () { + await approve.call(this, owner, spender, value); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + }); + + describe('when the spender had an approved value', function () { + beforeEach(async function () { + await approve.call(this, owner, spender, new BN(1)); + }); + + it('approves the requested value and replaces the previous one', async function () { + await approve.call(this, owner, spender, value); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + }); + }); + }); + + describe('when the spender is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError(approve.call(this, owner, ZERO_ADDRESS, supply), `ERC20InvalidSpender`, [ + ZERO_ADDRESS, + ]); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/ERC20.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/ERC20.test.js new file mode 100644 index 0000000..2191fd8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/ERC20.test.js @@ -0,0 +1,202 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +} = require('./ERC20.behavior'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const TOKENS = [ + { Token: artifacts.require('$ERC20') }, + { Token: artifacts.require('$ERC20ApprovalMock'), forcedApproval: true }, +]; + +contract('ERC20', function (accounts) { + const [initialHolder, recipient] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + const initialSupply = new BN(100); + + for (const { Token, forcedApproval } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.token = await Token.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + shouldBehaveLikeERC20(initialSupply, accounts, { forcedApproval }); + + it('has a name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('has 18 decimals', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('18'); + }); + + describe('_mint', function () { + const value = new BN(50); + it('rejects a null account', async function () { + await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, value), 'ERC20InvalidReceiver', [ZERO_ADDRESS]); + }); + + it('rejects overflow', async function () { + const maxUint256 = new BN('2').pow(new BN(256)).subn(1); + await expectRevert( + this.token.$_mint(recipient, maxUint256), + 'reverted with panic code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block)', + ); + }); + + describe('for a non zero account', function () { + beforeEach('minting', async function () { + this.receipt = await this.token.$_mint(recipient, value); + }); + + it('increments totalSupply', async function () { + const expectedSupply = initialSupply.add(value); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + + it('increments recipient balance', async function () { + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); + }); + + it('emits Transfer event', async function () { + const event = expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: recipient }); + + expect(event.args.value).to.be.bignumber.equal(value); + }); + }); + }); + + describe('_burn', function () { + it('rejects a null account', async function () { + await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, new BN(1)), 'ERC20InvalidSender', [ + ZERO_ADDRESS, + ]); + }); + + describe('for a non zero account', function () { + it('rejects burning more than balance', async function () { + await expectRevertCustomError( + this.token.$_burn(initialHolder, initialSupply.addn(1)), + 'ERC20InsufficientBalance', + [initialHolder, initialSupply, initialSupply.addn(1)], + ); + }); + + const describeBurn = function (description, value) { + describe(description, function () { + beforeEach('burning', async function () { + this.receipt = await this.token.$_burn(initialHolder, value); + }); + + it('decrements totalSupply', async function () { + const expectedSupply = initialSupply.sub(value); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + + it('decrements initialHolder balance', async function () { + const expectedBalance = initialSupply.sub(value); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(expectedBalance); + }); + + it('emits Transfer event', async function () { + const event = expectEvent(this.receipt, 'Transfer', { from: initialHolder, to: ZERO_ADDRESS }); + + expect(event.args.value).to.be.bignumber.equal(value); + }); + }); + }; + + describeBurn('for entire balance', initialSupply); + describeBurn('for less value than balance', initialSupply.subn(1)); + }); + }); + + describe('_update', function () { + const value = new BN(1); + + it('from is the zero address', async function () { + const balanceBefore = await this.token.balanceOf(initialHolder); + const totalSupply = await this.token.totalSupply(); + + expectEvent(await this.token.$_update(ZERO_ADDRESS, initialHolder, value), 'Transfer', { + from: ZERO_ADDRESS, + to: initialHolder, + value: value, + }); + expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.add(value)); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.add(value)); + }); + + it('to is the zero address', async function () { + const balanceBefore = await this.token.balanceOf(initialHolder); + const totalSupply = await this.token.totalSupply(); + + expectEvent(await this.token.$_update(initialHolder, ZERO_ADDRESS, value), 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: value, + }); + expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.sub(value)); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.sub(value)); + }); + + it('from and to are the zero address', async function () { + const totalSupply = await this.token.totalSupply(); + + await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, value); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply); + expectEvent(await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, value), 'Transfer', { + from: ZERO_ADDRESS, + to: ZERO_ADDRESS, + value: value, + }); + }); + }); + + describe('_transfer', function () { + shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, value) { + return this.token.$_transfer(from, to, value); + }); + + describe('when the sender is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.$_transfer(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20InvalidSender', + [ZERO_ADDRESS], + ); + }); + }); + }); + + describe('_approve', function () { + shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, value) { + return this.token.$_approve(owner, spender, value); + }); + + describe('when the owner is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.$_approve(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20InvalidApprover', + [ZERO_ADDRESS], + ); + }); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Burnable.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Burnable.behavior.js new file mode 100644 index 0000000..937491b --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Burnable.behavior.js @@ -0,0 +1,116 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +function shouldBehaveLikeERC20Burnable(owner, initialBalance, [burner]) { + describe('burn', function () { + describe('when the given value is not greater than balance of the sender', function () { + context('for a zero value', function () { + shouldBurn(new BN(0)); + }); + + context('for a non-zero value', function () { + shouldBurn(new BN(100)); + }); + + function shouldBurn(value) { + beforeEach(async function () { + this.receipt = await this.token.burn(value, { from: owner }); + }); + + it('burns the requested value', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(value)); + }); + + it('emits a transfer event', async function () { + expectEvent(this.receipt, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + value: value, + }); + }); + } + }); + + describe('when the given value is greater than the balance of the sender', function () { + const value = initialBalance.addn(1); + + it('reverts', async function () { + await expectRevertCustomError(this.token.burn(value, { from: owner }), 'ERC20InsufficientBalance', [ + owner, + initialBalance, + value, + ]); + }); + }); + }); + + describe('burnFrom', function () { + describe('on success', function () { + context('for a zero value', function () { + shouldBurnFrom(new BN(0)); + }); + + context('for a non-zero value', function () { + shouldBurnFrom(new BN(100)); + }); + + function shouldBurnFrom(value) { + const originalAllowance = value.muln(3); + + beforeEach(async function () { + await this.token.approve(burner, originalAllowance, { from: owner }); + this.receipt = await this.token.burnFrom(owner, value, { from: burner }); + }); + + it('burns the requested value', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(value)); + }); + + it('decrements allowance', async function () { + expect(await this.token.allowance(owner, burner)).to.be.bignumber.equal(originalAllowance.sub(value)); + }); + + it('emits a transfer event', async function () { + expectEvent(this.receipt, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + value: value, + }); + }); + } + }); + + describe('when the given value is greater than the balance of the sender', function () { + const value = initialBalance.addn(1); + + it('reverts', async function () { + await this.token.approve(burner, value, { from: owner }); + await expectRevertCustomError(this.token.burnFrom(owner, value, { from: burner }), 'ERC20InsufficientBalance', [ + owner, + initialBalance, + value, + ]); + }); + }); + + describe('when the given value is greater than the allowance', function () { + const allowance = new BN(100); + + it('reverts', async function () { + await this.token.approve(burner, allowance, { from: owner }); + await expectRevertCustomError( + this.token.burnFrom(owner, allowance.addn(1), { from: burner }), + 'ERC20InsufficientAllowance', + [burner, allowance, allowance.addn(1)], + ); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20Burnable, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Burnable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Burnable.test.js new file mode 100644 index 0000000..00acc81 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Burnable.test.js @@ -0,0 +1,20 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { shouldBehaveLikeERC20Burnable } = require('./ERC20Burnable.behavior'); +const ERC20Burnable = artifacts.require('$ERC20Burnable'); + +contract('ERC20Burnable', function (accounts) { + const [owner, ...otherAccounts] = accounts; + + const initialBalance = new BN(1000); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Burnable.new(name, symbol, { from: owner }); + await this.token.$_mint(owner, initialBalance); + }); + + shouldBehaveLikeERC20Burnable(owner, initialBalance, otherAccounts); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Capped.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Capped.behavior.js new file mode 100644 index 0000000..5af5c3d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Capped.behavior.js @@ -0,0 +1,31 @@ +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +function shouldBehaveLikeERC20Capped(accounts, cap) { + describe('capped token', function () { + const user = accounts[0]; + + it('starts with the correct cap', async function () { + expect(await this.token.cap()).to.be.bignumber.equal(cap); + }); + + it('mints when value is less than cap', async function () { + await this.token.$_mint(user, cap.subn(1)); + expect(await this.token.totalSupply()).to.be.bignumber.equal(cap.subn(1)); + }); + + it('fails to mint if the value exceeds the cap', async function () { + await this.token.$_mint(user, cap.subn(1)); + await expectRevertCustomError(this.token.$_mint(user, 2), 'ERC20ExceededCap', [cap.addn(1), cap]); + }); + + it('fails to mint after cap is reached', async function () { + await this.token.$_mint(user, cap); + await expectRevertCustomError(this.token.$_mint(user, 1), 'ERC20ExceededCap', [cap.addn(1), cap]); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20Capped, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Capped.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Capped.test.js new file mode 100644 index 0000000..1f4a2be --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Capped.test.js @@ -0,0 +1,24 @@ +const { ether } = require('@openzeppelin/test-helpers'); +const { shouldBehaveLikeERC20Capped } = require('./ERC20Capped.behavior'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC20Capped = artifacts.require('$ERC20Capped'); + +contract('ERC20Capped', function (accounts) { + const cap = ether('1000'); + + const name = 'My Token'; + const symbol = 'MTKN'; + + it('requires a non-zero cap', async function () { + await expectRevertCustomError(ERC20Capped.new(name, symbol, 0), 'ERC20InvalidCap', [0]); + }); + + context('once deployed', async function () { + beforeEach(async function () { + this.token = await ERC20Capped.new(name, symbol, cap); + }); + + shouldBehaveLikeERC20Capped(accounts, cap); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20FlashMint.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20FlashMint.test.js new file mode 100644 index 0000000..13d5b3e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20FlashMint.test.js @@ -0,0 +1,210 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const ERC20FlashMintMock = artifacts.require('$ERC20FlashMintMock'); +const ERC3156FlashBorrowerMock = artifacts.require('ERC3156FlashBorrowerMock'); + +contract('ERC20FlashMint', function (accounts) { + const [initialHolder, other, anotherAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + const loanValue = new BN(10000000000000); + + beforeEach(async function () { + this.token = await ERC20FlashMintMock.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + describe('maxFlashLoan', function () { + it('token match', async function () { + expect(await this.token.maxFlashLoan(this.token.address)).to.be.bignumber.equal(MAX_UINT256.sub(initialSupply)); + }); + + it('token mismatch', async function () { + expect(await this.token.maxFlashLoan(ZERO_ADDRESS)).to.be.bignumber.equal('0'); + }); + }); + + describe('flashFee', function () { + it('token match', async function () { + expect(await this.token.flashFee(this.token.address, loanValue)).to.be.bignumber.equal('0'); + }); + + it('token mismatch', async function () { + await expectRevertCustomError(this.token.flashFee(ZERO_ADDRESS, loanValue), 'ERC3156UnsupportedToken', [ + ZERO_ADDRESS, + ]); + }); + }); + + describe('flashFeeReceiver', function () { + it('default receiver', async function () { + expect(await this.token.$_flashFeeReceiver()).to.be.eq(ZERO_ADDRESS); + }); + }); + + describe('flashLoan', function () { + it('success', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const { tx } = await this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver.address, + value: loanValue, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: receiver.address, + to: ZERO_ADDRESS, + value: loanValue, + }); + await expectEvent.inTransaction(tx, receiver, 'BalanceOf', { + token: this.token.address, + account: receiver.address, + value: loanValue, + }); + await expectEvent.inTransaction(tx, receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(loanValue), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + expect(await this.token.balanceOf(receiver.address)).to.be.bignumber.equal('0'); + expect(await this.token.allowance(receiver.address, this.token.address)).to.be.bignumber.equal('0'); + }); + + it('missing return value', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(false, true); + await expectRevertCustomError( + this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'), + 'ERC3156InvalidReceiver', + [receiver.address], + ); + }); + + it('missing approval', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, false); + await expectRevertCustomError( + this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'), + 'ERC20InsufficientAllowance', + [this.token.address, 0, loanValue], + ); + }); + + it('unavailable funds', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const data = this.token.contract.methods.transfer(other, 10).encodeABI(); + await expectRevertCustomError( + this.token.flashLoan(receiver.address, this.token.address, loanValue, data), + 'ERC20InsufficientBalance', + [receiver.address, loanValue - 10, loanValue], + ); + }); + + it('more than maxFlashLoan', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const data = this.token.contract.methods.transfer(other, 10).encodeABI(); + // _mint overflow reverts using a panic code. No reason string. + await expectRevert.unspecified(this.token.flashLoan(receiver.address, this.token.address, MAX_UINT256, data)); + }); + + describe('custom flash fee & custom fee receiver', function () { + const receiverInitialBalance = new BN(200000); + const flashFee = new BN(5000); + + beforeEach('init receiver balance & set flash fee', async function () { + this.receiver = await ERC3156FlashBorrowerMock.new(true, true); + const receipt = await this.token.$_mint(this.receiver.address, receiverInitialBalance); + await expectEvent(receipt, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: receiverInitialBalance, + }); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal(receiverInitialBalance); + + await this.token.setFlashFee(flashFee); + expect(await this.token.flashFee(this.token.address, loanValue)).to.be.bignumber.equal(flashFee); + }); + + it('default flash fee receiver', async function () { + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanValue, '0x'); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: loanValue, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: ZERO_ADDRESS, + value: loanValue.add(flashFee), + }); + await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { + token: this.token.address, + account: this.receiver.address, + value: receiverInitialBalance.add(loanValue), + }); + await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(receiverInitialBalance).add(loanValue), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal( + initialSupply.add(receiverInitialBalance).sub(flashFee), + ); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal( + receiverInitialBalance.sub(flashFee), + ); + expect(await this.token.balanceOf(await this.token.$_flashFeeReceiver())).to.be.bignumber.equal('0'); + expect(await this.token.allowance(this.receiver.address, this.token.address)).to.be.bignumber.equal('0'); + }); + + it('custom flash fee receiver', async function () { + const flashFeeReceiverAddress = anotherAccount; + await this.token.setFlashFeeReceiver(flashFeeReceiverAddress); + expect(await this.token.$_flashFeeReceiver()).to.be.eq(flashFeeReceiverAddress); + + expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal('0'); + + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanValue, '0x'); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: loanValue, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: ZERO_ADDRESS, + value: loanValue, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: flashFeeReceiverAddress, + value: flashFee, + }); + await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { + token: this.token.address, + account: this.receiver.address, + value: receiverInitialBalance.add(loanValue), + }); + await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(receiverInitialBalance).add(loanValue), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply.add(receiverInitialBalance)); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal( + receiverInitialBalance.sub(flashFee), + ); + expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal(flashFee); + expect(await this.token.allowance(this.receiver.address, flashFeeReceiverAddress)).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Pausable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Pausable.test.js new file mode 100644 index 0000000..92c90b9 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Pausable.test.js @@ -0,0 +1,136 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC20Pausable = artifacts.require('$ERC20Pausable'); + +contract('ERC20Pausable', function (accounts) { + const [holder, recipient, anotherAccount] = accounts; + + const initialSupply = new BN(100); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Pausable.new(name, symbol); + await this.token.$_mint(holder, initialSupply); + }); + + describe('pausable token', function () { + describe('transfer', function () { + it('allows to transfer when unpaused', async function () { + await this.token.transfer(recipient, initialSupply, { from: holder }); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.transfer(recipient, initialSupply, { from: holder }); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); + }); + + it('reverts when trying to transfer when paused', async function () { + await this.token.$_pause(); + + await expectRevertCustomError( + this.token.transfer(recipient, initialSupply, { from: holder }), + 'EnforcedPause', + [], + ); + }); + }); + + describe('transfer from', function () { + const allowance = new BN(40); + + beforeEach(async function () { + await this.token.approve(anotherAccount, allowance, { from: holder }); + }); + + it('allows to transfer from when unpaused', async function () { + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); + }); + + it('reverts when trying to transfer from when paused', async function () { + await this.token.$_pause(); + + await expectRevertCustomError( + this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }), + 'EnforcedPause', + [], + ); + }); + }); + + describe('mint', function () { + const value = new BN('42'); + + it('allows to mint when unpaused', async function () { + await this.token.$_mint(recipient, value); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); + }); + + it('allows to mint when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.$_mint(recipient, value); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); + }); + + it('reverts when trying to mint when paused', async function () { + await this.token.$_pause(); + + await expectRevertCustomError(this.token.$_mint(recipient, value), 'EnforcedPause', []); + }); + }); + + describe('burn', function () { + const value = new BN('42'); + + it('allows to burn when unpaused', async function () { + await this.token.$_burn(holder, value); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(value)); + }); + + it('allows to burn when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.$_burn(holder, value); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(value)); + }); + + it('reverts when trying to burn when paused', async function () { + await this.token.$_pause(); + + await expectRevertCustomError(this.token.$_burn(holder, value), 'EnforcedPause', []); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Permit.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Permit.test.js new file mode 100644 index 0000000..388716d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Permit.test.js @@ -0,0 +1,118 @@ +/* eslint-disable */ + +const { BN, constants, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256 } = constants; + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const ERC20Permit = artifacts.require('$ERC20Permit'); + +const { Permit, getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { getChainId } = require('../../../helpers/chainid'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +contract('ERC20Permit', function (accounts) { + const [initialHolder, spender] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.chainId = await getChainId(); + + this.token = await ERC20Permit.new(name, symbol, name); + await this.token.$_mint(initialHolder, initialSupply); + }); + + it('initial nonce is 0', async function () { + expect(await this.token.nonces(initialHolder)).to.be.bignumber.equal('0'); + }); + + it('domain separator', async function () { + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); + }); + + describe('permit', function () { + const wallet = Wallet.generate(); + + const owner = wallet.getAddressString(); + const value = new BN(42); + const nonce = 0; + const maxDeadline = MAX_UINT256; + + 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 { 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); + + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + + it('rejects reused signature', async function () { + const sig = await buildData(this.token).then(data => + ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data }), + ); + const { r, s, v } = fromRpcSig(sig); + + await this.token.permit(owner, spender, value, maxDeadline, v, r, s); + + const domain = await getDomain(this.token); + const typedMessage = { + primaryType: 'Permit', + types: { EIP712Domain: domainType(domain), Permit }, + domain, + message: { owner, spender, value, nonce: nonce + 1, deadline: maxDeadline }, + }; + + await expectRevertCustomError( + this.token.permit(owner, spender, value, maxDeadline, v, r, s), + 'ERC2612InvalidSigner', + [ethSigUtil.recoverTypedSignature({ data: typedMessage, sig }), owner], + ); + }); + + it('rejects other signature', async function () { + const otherWallet = Wallet.generate(); + + const { v, r, s } = await buildData(this.token) + .then(data => ethSigUtil.signTypedMessage(otherWallet.getPrivateKey(), { data })) + .then(fromRpcSig); + + await expectRevertCustomError( + this.token.permit(owner, spender, value, maxDeadline, v, r, s), + 'ERC2612InvalidSigner', + [await otherWallet.getAddressString(), owner], + ); + }); + + it('rejects expired permit', async function () { + const deadline = (await time.latest()) - time.duration.weeks(1); + + const { v, r, s } = await buildData(this.token, deadline) + .then(data => ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data })) + .then(fromRpcSig); + + await expectRevertCustomError( + this.token.permit(owner, spender, value, deadline, v, r, s), + 'ERC2612ExpiredSignature', + [deadline], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Votes.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Votes.test.js new file mode 100644 index 0000000..faf1a15 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Votes.test.js @@ -0,0 +1,593 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { batchInBlock } = require('../../../helpers/txpool'); +const { getDomain, domainType } = require('../../../helpers/eip712'); +const { clock, clockFromReceipt } = require('../../../helpers/time'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const Delegation = [ + { name: 'delegatee', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { 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'); + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.token = await artifact.new(name, symbol, name, version); + this.votes = this.token; + }); + + // includes EIP6372 behavior check + shouldBehaveLikeVotes(accounts, [1, 17, 42], { mode, fungible: true }); + + it('initial nonce is 0', async function () { + expect(await this.token.nonces(holder)).to.be.bignumber.equal('0'); + }); + + it('minting restriction', async function () { + const value = web3.utils.toBN(1).shln(208); + await expectRevertCustomError(this.token.$_mint(holder, value), 'ERC20ExceededSafeSupply', [ + value, + value.subn(1), + ]); + }); + + 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 timepoint = await clock[mode](); + expect(await this.token.numCheckpoints(holder)).to.be.bignumber.equal('6'); + // recent + expect(await this.token.getPastVotes(holder, timepoint - 1)).to.be.bignumber.equal('5'); + // non-recent + expect(await this.token.getPastVotes(holder, timepoint - 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, + previousVotes: '0', + newVotes: 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); + }); + }); + + 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, + })); + + 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, + previousVotes: '0', + newVotes: 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 expectRevertCustomError( + this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s), + 'InvalidAccountNonce', + [delegatorAddress, nonce + 1], + ); + }); + + 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 sig = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })); + const { r, s, v } = fromRpcSig(sig); + + const domain = await getDomain(this.token); + const typedMessage = { + primaryType: 'Delegation', + types: { EIP712Domain: domainType(domain), Delegation }, + domain, + message: { delegatee: delegatorAddress, nonce: nonce + 1, expiry: MAX_UINT256 }, + }; + + await expectRevertCustomError( + this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), + 'InvalidAccountNonce', + [ethSigUtil.recoverTypedSignature({ data: typedMessage, sig }), 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 expectRevertCustomError( + this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), + 'VotesExpiredSignature', + [expiry], + ); + }); + }); + }); + + 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 }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: holder, + fromDelegate: holder, + toDelegate: holderDelegatee, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousVotes: supply, + newVotes: '0', + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holderDelegatee, + previousVotes: '0', + newVotes: 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); + }); + }); + + 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, + previousVotes: supply, + newVotes: 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, previousVotes: '0', newVotes: '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, + previousVotes: supply, + newVotes: supply.subn(1), + }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousVotes: '0', newVotes: '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); + }); + }); + + // 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 }); + 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: 200000 }), + () => this.token.transfer(other2, 10, { from: recipient, gas: 200000 }), + () => this.token.transfer(other2, 10, { from: recipient, gas: 200000 }), + ]); + 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 () { + const clock = await this.token.clock(); + await expectRevertCustomError(this.token.getPastVotes(other1, 5e10), 'ERC5805FutureLookup', [5e10, clock]); + }); + + 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', + ); + }); + }); + }); + + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.token.delegate(holder, { from: holder }); + }); + + it('reverts if block number >= current block', async function () { + const clock = await this.token.clock(); + await expectRevertCustomError(this.token.getPastTotalSupply(5e10), 'ERC5805FutureLookup', [5e10, clock]); + }); + + 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', + ); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Wrapper.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Wrapper.test.js new file mode 100644 index 0000000..c54a9e0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC20Wrapper.test.js @@ -0,0 +1,211 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS, MAX_UINT256 } = constants; + +const { shouldBehaveLikeERC20 } = require('../ERC20.behavior'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const NotAnERC20 = artifacts.require('CallReceiverMock'); +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); +const ERC20Wrapper = artifacts.require('$ERC20Wrapper'); + +contract('ERC20Wrapper', function (accounts) { + const [initialHolder, receiver] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.underlying = await ERC20Decimals.new(name, symbol, 9); + await this.underlying.$_mint(initialHolder, initialSupply); + + this.token = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, this.underlying.address); + }); + + afterEach(async function () { + expect(await this.underlying.balanceOf(this.token.address)).to.be.bignumber.equal(await this.token.totalSupply()); + }); + + 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 the same decimals as the underlying token', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('9'); + }); + + it('decimals default back to 18 if token has no metadata', async function () { + const noDecimals = await NotAnERC20.new(); + const otherToken = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, noDecimals.address); + expect(await otherToken.decimals()).to.be.bignumber.equal('18'); + }); + + it('has underlying', async function () { + expect(await this.token.underlying()).to.be.bignumber.equal(this.underlying.address); + }); + + describe('deposit', function () { + it('valid', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + const { tx } = await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: initialHolder, + value: initialSupply, + }); + }); + + it('missing approval', async function () { + await expectRevertCustomError( + this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }), + 'ERC20InsufficientAllowance', + [this.token.address, 0, initialSupply], + ); + }); + + it('missing balance', async function () { + await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder }); + await expectRevertCustomError( + this.token.depositFor(initialHolder, MAX_UINT256, { from: initialHolder }), + 'ERC20InsufficientBalance', + [initialHolder, initialSupply, MAX_UINT256], + ); + }); + + it('to other account', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + const { tx } = await this.token.depositFor(receiver, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver, + value: initialSupply, + }); + }); + + it('reverts minting to the wrapper contract', async function () { + await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder }); + await expectRevertCustomError( + this.token.depositFor(this.token.address, MAX_UINT256, { from: initialHolder }), + 'ERC20InvalidReceiver', + [this.token.address], + ); + }); + }); + + describe('withdraw', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + }); + + it('missing balance', async function () { + await expectRevertCustomError( + this.token.withdrawTo(initialHolder, MAX_UINT256, { from: initialHolder }), + 'ERC20InsufficientBalance', + [initialHolder, initialSupply, MAX_UINT256], + ); + }); + + it('valid', async function () { + const value = new BN(42); + + const { tx } = await this.token.withdrawTo(initialHolder, value, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + value: value, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: value, + }); + }); + + it('entire balance', async function () { + const { tx } = await this.token.withdrawTo(initialHolder, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: initialSupply, + }); + }); + + it('to other account', async function () { + const { tx } = await this.token.withdrawTo(receiver, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: receiver, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: initialSupply, + }); + }); + + it('reverts withdrawing to the wrapper contract', async function () { + expectRevertCustomError( + this.token.withdrawTo(this.token.address, initialSupply, { from: initialHolder }), + 'ERC20InvalidReceiver', + [this.token.address], + ); + }); + }); + + describe('recover', function () { + it('nothing to recover', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + + const { tx } = await this.token.$_recover(receiver); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver, + value: '0', + }); + }); + + it('something to recover', async function () { + await this.underlying.transfer(this.token.address, initialSupply, { from: initialHolder }); + + const { tx } = await this.token.$_recover(receiver); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver, + value: initialSupply, + }); + }); + }); + + describe('erc20 behaviour', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + }); + + shouldBehaveLikeERC20(initialSupply, accounts); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC4626.t.sol b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC4626.t.sol new file mode 100644 index 0000000..72b0dac --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC4626.t.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC4626Test} from "erc4626-tests/ERC4626.test.sol"; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; + +import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol"; +import {ERC4626Mock} from "@openzeppelin/contracts/mocks/token/ERC4626Mock.sol"; +import {ERC4626OffsetMock} from "@openzeppelin/contracts/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(_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/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC4626.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC4626.test.js new file mode 100644 index 0000000..fa66785 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/extensions/ERC4626.test.js @@ -0,0 +1,1109 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { Enum } = require('../../../helpers/enums'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); +const ERC4626 = artifacts.require('$ERC4626'); +const ERC4626LimitsMock = artifacts.require('$ERC4626LimitsMock'); +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; + + const name = 'My Token'; + const symbol = 'MTKN'; + 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)) { + const token = await ERC20Decimals.new('', '', decimals); + const vault = await ERC4626.new('', '', token.address); + expect(await vault.decimals()).to.be.bignumber.equal(decimals); + } + }); + + 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)', + ); + } + }); + + describe('reentrancy', async function () { + const reenterType = Enum('No', 'Before', 'After'); + + const value = web3.utils.toBN(1000000000000000000); + const reenterValue = 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, value); + await token.$_mint(other, value); + 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, reenterValue); + + // Schedules a reentrancy from the token contract + await token.scheduleReenter( + reenterType.Before, + vault.address, + vault.contract.methods.deposit(reenterValue, holder).encodeABI(), + ); + + // Initial share price + const sharesForDeposit = await vault.previewDeposit(value, { from: holder }); + const sharesForReenter = await vault.previewDeposit(reenterValue, { from: holder }); + + // Deposit normally, reentering before the internal `_update` + const receipt = await vault.deposit(value, holder, { from: holder }); + + // Main deposit event + await expectEvent(receipt, 'Deposit', { + sender: holder, + owner: holder, + assets: value, + shares: sharesForDeposit, + }); + // Reentrant deposit event → uses the same price + await expectEvent(receipt, 'Deposit', { + sender: token.address, + owner: holder, + assets: reenterValue, + shares: sharesForReenter, + }); + + // Assert prices is kept + const sharesAfter = await vault.previewDeposit(value, { 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 `value` share, token.address gets `reenterValue` shares + await vault.deposit(value, holder, { from: holder }); + await vault.deposit(reenterValue, token.address, { from: other }); + + // Schedules a reentrancy from the token contract + await token.scheduleReenter( + reenterType.After, + vault.address, + vault.contract.methods.withdraw(reenterValue, holder, token.address).encodeABI(), + ); + + // Initial share price + const sharesForWithdraw = await vault.previewWithdraw(value, { from: holder }); + const sharesForReenter = await vault.previewWithdraw(reenterValue, { from: holder }); + + // Do withdraw normally, triggering the _afterTokenTransfer hook + const receipt = await vault.withdraw(value, holder, holder, { from: holder }); + + // Main withdraw event + await expectEvent(receipt, 'Withdraw', { + sender: holder, + receiver: holder, + owner: holder, + assets: value, + shares: sharesForWithdraw, + }); + // Reentrant withdraw event → uses the same price + await expectEvent(receipt, 'Withdraw', { + sender: token.address, + receiver: holder, + owner: token.address, + assets: reenterValue, + shares: sharesForReenter, + }); + + // Assert price is kept + const sharesAfter = await vault.previewWithdraw(value, { 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 value 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, reenterValue).encodeABI(), + ); + + // Price before + const sharesBefore = await vault.previewDeposit(value); + + // Deposit, reentering before the internal `_update` + const receipt = await vault.deposit(value, holder, { from: holder }); + + // Price is as previewed + await expectEvent(receipt, 'Deposit', { + sender: holder, + owner: holder, + assets: value, + shares: sharesBefore, + }); + + // Price was modified during reentrancy + const sharesAfter = await vault.previewDeposit(value); + 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 value of assets) + it('share price change during reentracy does not affect withdraw', async function () { + await vault.deposit(value, other, { from: other }); + await vault.deposit(value, 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, reenterValue).encodeABI(), + ); + + // Price before + const sharesBefore = await vault.previewWithdraw(value); + + // Withdraw, triggering the _afterTokenTransfer hook + const receipt = await vault.withdraw(value, holder, holder, { from: holder }); + + // Price is as previewed + await expectEvent(receipt, 'Withdraw', { + sender: holder, + receiver: holder, + owner: holder, + assets: value, + shares: sharesBefore, + }); + + // Price was modified during reentrancy + const sharesAfter = await vault.previewWithdraw(value); + expect(sharesAfter).to.be.bignumber.gt(sharesBefore); + }); + }); + + describe('limits', async function () { + beforeEach(async function () { + this.token = await ERC20Decimals.new(name, symbol, decimals); + this.vault = await ERC4626LimitsMock.new(name + ' Vault', symbol + 'V', this.token.address); + }); + + it('reverts on deposit() above max deposit', async function () { + const maxDeposit = await this.vault.maxDeposit(holder); + await expectRevertCustomError(this.vault.deposit(maxDeposit.addn(1), recipient), 'ERC4626ExceededMaxDeposit', [ + recipient, + maxDeposit.addn(1), + maxDeposit, + ]); + }); + + it('reverts on mint() above max mint', async function () { + const maxMint = await this.vault.maxMint(holder); + await expectRevertCustomError(this.vault.mint(maxMint.addn(1), recipient), 'ERC4626ExceededMaxMint', [ + recipient, + maxMint.addn(1), + maxMint, + ]); + }); + + it('reverts on withdraw() above max withdraw', async function () { + const maxWithdraw = await this.vault.maxWithdraw(holder); + await expectRevertCustomError( + this.vault.withdraw(maxWithdraw.addn(1), recipient, holder), + 'ERC4626ExceededMaxWithdraw', + [holder, maxWithdraw.addn(1), maxWithdraw], + ); + }); + + it('reverts on redeem() above max redeem', async function () { + const maxRedeem = await this.vault.maxRedeem(holder); + await expectRevertCustomError( + this.vault.redeem(maxRedeem.addn(1), recipient, holder), + 'ERC4626ExceededMaxRedeem', + [holder, maxRedeem.addn(1), maxRedeem], + ); + }); + }); + + 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); + + const virtualAssets = web3.utils.toBN(1); + const virtualShares = web3.utils.toBN(10).pow(offset); + + 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 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 }); + }); + + 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), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: parseToken(1), + shares: 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), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: parseToken(1), + shares: 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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: depositAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: expectedAssets, + shares: 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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: depositAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: expectedAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: withdrawAssets, + shares: expectedShares, + }); + }); + + it('withdraw with approval', async function () { + const assets = await this.vault.previewWithdraw(parseToken(1)); + await expectRevertCustomError( + this.vault.withdraw(parseToken(1), recipient, holder, { from: other }), + 'ERC20InsufficientAllowance', + [other, 0, assets], + ); + + await this.vault.withdraw(parseToken(1), recipient, holder, { from: spender }); + }); + + it('redeem', 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 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: expectedAssets, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: redeemShares, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: expectedAssets, + shares: redeemShares, + }); + }); + + it('redeem with approval', async function () { + await expectRevertCustomError( + this.vault.redeem(parseShare(100), recipient, holder, { from: other }), + 'ERC20InsufficientAllowance', + [other, 0, parseShare(100)], + ); + + await this.vault.redeem(parseShare(100), recipient, holder, { from: spender }); + }); + }); + }); + } + + describe('ERC4626Fees', function () { + const feeBasisPoints = web3.utils.toBN(5e3); + const valueWithoutFees = web3.utils.toBN(10000); + const fees = valueWithoutFees.mul(feeBasisPoints).divn(1e4); + const valueWithFees = valueWithoutFees.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, + feeBasisPoints, + 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(valueWithFees)).to.be.bignumber.equal(valueWithoutFees); + ({ tx: this.tx } = await this.vault.deposit(valueWithFees, recipient, { from: holder })); + }); + + it('mint', async function () { + expect(await this.vault.previewMint(valueWithoutFees)).to.be.bignumber.equal(valueWithFees); + ({ tx: this.tx } = await this.vault.mint(valueWithoutFees, recipient, { from: holder })); + }); + + afterEach(async function () { + // get total + await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: valueWithFees, + }); + + // 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: valueWithoutFees, + }); + + // deposit event + await expectEvent.inTransaction(this.tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: valueWithFees, + shares: valueWithoutFees, + }); + }); + }); + + 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(valueWithFees)).to.be.bignumber.equal(valueWithoutFees); + ({ tx: this.tx } = await this.vault.redeem(valueWithFees, recipient, holder, { from: holder })); + }); + + it('withdraw', async function () { + expect(await this.vault.previewWithdraw(valueWithoutFees)).to.be.bignumber.equal(valueWithFees); + ({ tx: this.tx } = await this.vault.withdraw(valueWithoutFees, recipient, holder, { from: holder })); + }); + + afterEach(async function () { + // withdraw principal + await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: valueWithoutFees, + }); + + // 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: valueWithFees, + }); + + // withdraw event + await expectEvent.inTransaction(this.tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: valueWithoutFees, + shares: valueWithFees, + }); + }); + }); + }); + + /// 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 () { + // test designed with both asset using similar decimals + this.token = await ERC20Decimals.new(name, symbol, 18); + this.vault = await ERC4626.new(name + ' Vault', symbol + 'V', this.token.address); + + await this.token.$_mint(user1, 4000); + await this.token.$_mint(user2, 7001); + await this.token.approve(this.vault.address, 4000, { from: user1 }); + await this.token.approve(this.vault.address, 7001, { from: user2 }); + + // 1. Alice mints 2000 shares (costs 2000 tokens) + { + const { tx } = await this.vault.mint(2000, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user1, + to: this.vault.address, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + value: '2000', + }); + + expect(await this.vault.previewDeposit(2000)).to.be.bignumber.equal('2000'); + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('2000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('0'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '2000', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('2000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('2000'); + } + + // 2. Bob deposits 4000 tokens (mints 4000 shares) + { + const { tx } = await this.vault.mint(4000, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user2, + to: this.vault.address, + value: '4000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + value: '4000', + }); + + expect(await this.vault.previewDeposit(4000)).to.be.bignumber.equal('4000'); + 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('2000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('4000'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '6000', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('6000'); + } + + // 3. Vault mutates by +3000 tokens (simulated yield returned from strategy) + await this.token.$_mint(this.vault.address, 3000); + + 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('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.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '6000', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('9000'); + + // 4. Alice deposits 2000 tokens (mints 1333 shares) + { + const { tx } = await this.vault.deposit(2000, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user1, + to: this.vault.address, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + value: '1333', + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333'); + 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('4999'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('6000'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '7333', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('7333'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('11000'); + } + + // 5. Bob mints 2000 shares (costs 3001 assets) + // NOTE: Bob's assets spent got rounded towards infinity + // NOTE: Alices's vault assets got rounded towards infinity + { + const { tx } = await this.vault.mint(2000, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user2, + to: this.vault.address, + value: '3000', // used to be 3001 + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + value: '2000', + }); + + 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('4999'); // used to be 5000 + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('9000'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '9333', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('9333'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('14000'); // used to be 14001 + } + + // 6. Vault mutates by +3000 tokens + // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000. + await this.token.$_mint(this.vault.address, 3000); + + 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('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.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '9333', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('9333'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('17000'); // used to be 17001 + + // 7. Alice redeem 1333 shares (2428 assets) + { + const { tx } = await this.vault.redeem(1333, user1, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + value: '1333', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user1, + value: '2427', // used to be 2428 + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + 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('3643'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('10929'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '8000', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('8000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('14573'); + } + + // 8. Bob withdraws 2929 assets (1608 shares) + { + const { tx } = await this.vault.withdraw(2929, user2, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user2, + to: constants.ZERO_ADDRESS, + value: '1608', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user2, + value: '2929', + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + 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('3643'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('8000'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '6392', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6392'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('11644'); + } + + // 9. Alice withdraws 3643 assets (2000 shares) + // NOTE: Bob's assets have been rounded back towards infinity + { + const { tx } = await this.vault.withdraw(3643, user1, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user1, + value: '3643', + }); + + 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('8000'); // used to be 8001 + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '4392', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('4392'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('8001'); + } + + // 10. Bob redeem 4392 shares (8001 tokens) + { + const { tx } = await this.vault.redeem(4392, user2, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user2, + to: constants.ZERO_ADDRESS, + value: '4392', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user2, + value: '8000', // used to be 8001 + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('0'); + expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0'); + 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.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '0', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('0'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('1'); // used to be 0 + } + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/utils/SafeERC20.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/utils/SafeERC20.test.js new file mode 100644 index 0000000..4ff27f1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC20/utils/SafeERC20.test.js @@ -0,0 +1,240 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const SafeERC20 = artifacts.require('$SafeERC20'); +const ERC20ReturnFalseMock = artifacts.require('$ERC20ReturnFalseMock'); +const ERC20ReturnTrueMock = artifacts.require('$ERC20'); // default implementation returns true +const ERC20NoReturnMock = artifacts.require('$ERC20NoReturnMock'); +const ERC20ForceApproveMock = artifacts.require('$ERC20ForceApproveMock'); + +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const name = 'ERC20Mock'; +const symbol = 'ERC20Mock'; + +contract('SafeERC20', function (accounts) { + const [hasNoCode, receiver, spender] = accounts; + + before(async function () { + this.mock = await SafeERC20.new(); + }); + + describe('with address that has no contract code', function () { + beforeEach(async function () { + this.token = { address: hasNoCode }; + }); + + it('reverts on transfer', async function () { + await expectRevertCustomError(this.mock.$safeTransfer(this.token.address, receiver, 0), 'AddressEmptyCode', [ + this.token.address, + ]); + }); + + it('reverts on transferFrom', async function () { + await expectRevertCustomError( + this.mock.$safeTransferFrom(this.token.address, this.mock.address, receiver, 0), + 'AddressEmptyCode', + [this.token.address], + ); + }); + + it('reverts on increaseAllowance', async function () { + // Call to 'token.allowance' does not return any data, resulting in a decoding error (revert without reason) + await expectRevert.unspecified(this.mock.$safeIncreaseAllowance(this.token.address, spender, 0)); + }); + + it('reverts on decreaseAllowance', async function () { + // Call to 'token.allowance' does not return any data, resulting in a decoding error (revert without reason) + await expectRevert.unspecified(this.mock.$safeDecreaseAllowance(this.token.address, spender, 0)); + }); + + it('reverts on forceApprove', async function () { + await expectRevertCustomError(this.mock.$forceApprove(this.token.address, spender, 0), 'AddressEmptyCode', [ + this.token.address, + ]); + }); + }); + + describe('with token that returns false on all calls', function () { + beforeEach(async function () { + this.token = await ERC20ReturnFalseMock.new(name, symbol); + }); + + it('reverts on transfer', async function () { + await expectRevertCustomError( + this.mock.$safeTransfer(this.token.address, receiver, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + + it('reverts on transferFrom', async function () { + await expectRevertCustomError( + this.mock.$safeTransferFrom(this.token.address, this.mock.address, receiver, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + + it('reverts on increaseAllowance', async function () { + await expectRevertCustomError( + this.mock.$safeIncreaseAllowance(this.token.address, spender, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + + it('reverts on decreaseAllowance', async function () { + await expectRevertCustomError( + this.mock.$safeDecreaseAllowance(this.token.address, spender, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + + it('reverts on forceApprove', async function () { + await expectRevertCustomError( + this.mock.$forceApprove(this.token.address, spender, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + }); + + describe('with token that returns true on all calls', function () { + beforeEach(async function () { + this.token = await ERC20ReturnTrueMock.new(name, symbol); + }); + + shouldOnlyRevertOnErrors(accounts); + }); + + describe('with token that returns no boolean values', function () { + beforeEach(async function () { + this.token = await ERC20NoReturnMock.new(name, symbol); + }); + + shouldOnlyRevertOnErrors(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('safeIncreaseAllowance works', async function () { + await this.mock.$safeIncreaseAllowance(this.token.address, spender, 10); + expect(this.token.allowance(this.mock.address, spender, 90)); + }); + + it('safeDecreaseAllowance works', async function () { + await this.mock.$safeDecreaseAllowance(this.token.address, spender, 10); + expect(this.token.allowance(this.mock.address, spender, 110)); + }); + + it('forceApprove works', async function () { + await this.mock.$forceApprove(this.token.address, spender, 200); + expect(this.token.allowance(this.mock.address, spender, 200)); + }); + }); + }); +}); + +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 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.$_approve(this.mock.address, spender, 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, 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 expectRevertCustomError( + this.mock.$safeDecreaseAllowance(this.token.address, spender, 10), + 'SafeERC20FailedDecreaseAllowance', + [spender, 0, 10], + ); + }); + }); + + context('with non-zero allowance', function () { + beforeEach(async function () { + await this.token.$_approve(this.mock.address, spender, 100); + }); + + 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, 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, 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 expectRevertCustomError( + this.mock.$safeDecreaseAllowance(this.token.address, spender, 200), + 'SafeERC20FailedDecreaseAllowance', + [spender, 100, 200], + ); + }); + }); + }); +} diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721.behavior.js new file mode 100644 index 0000000..10f8482 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721.behavior.js @@ -0,0 +1,978 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { Enum } = require('../../helpers/enums'); + +const ERC721ReceiverMock = artifacts.require('ERC721ReceiverMock'); +const NonERC721ReceiverMock = artifacts.require('CallReceiverMock'); + +const RevertType = Enum('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'); + +const firstTokenId = new BN('5042'); +const secondTokenId = new BN('79217'); +const nonExistentTokenId = new BN('13'); +const fourthTokenId = new BN(4); +const baseURI = 'https://api.example.com/v1/'; + +const RECEIVER_MAGIC_VALUE = '0x150b7a02'; + +function shouldBehaveLikeERC721(owner, newOwner, approved, anotherApproved, operator, other) { + shouldSupportInterfaces(['ERC165', 'ERC721']); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + this.toWhom = other; // default to other for toWhom in context-dependent tests + }); + + describe('balanceOf', function () { + context('when the given address owns some tokens', function () { + it('returns the amount of tokens owned by the given address', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('2'); + }); + }); + + context('when the given address does not own any tokens', function () { + it('returns 0', async function () { + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('0'); + }); + }); + + context('when querying the zero address', function () { + it('throws', async function () { + await expectRevertCustomError(this.token.balanceOf(ZERO_ADDRESS), 'ERC721InvalidOwner', [ZERO_ADDRESS]); + }); + }); + }); + + describe('ownerOf', function () { + context('when the given token ID was tracked by this token', function () { + const tokenId = firstTokenId; + + it('returns the owner of the given token ID', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owner); + }); + }); + + context('when the given token ID was not tracked by this token', function () { + const tokenId = nonExistentTokenId; + + it('reverts', async function () { + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + }); + }); + }); + + describe('transfers', function () { + const tokenId = firstTokenId; + const data = '0x42'; + + let receipt = null; + + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + await this.token.setApprovalForAll(operator, true, { from: owner }); + }); + + const transferWasSuccessful = function ({ owner, tokenId }) { + it('transfers the ownership of the given token ID to the given address', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(this.toWhom); + }); + + it('emits a Transfer event', async function () { + expectEvent(receipt, 'Transfer', { from: owner, to: this.toWhom, tokenId: tokenId }); + }); + + it('clears the approval for the token ID with no event', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + expectEvent.notEmitted(receipt, 'Approval'); + }); + + it('adjusts owners balances', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('adjusts owners tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + + expect(await this.token.tokenOfOwnerByIndex(this.toWhom, 0)).to.be.bignumber.equal(tokenId); + + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.not.equal(tokenId); + }); + }; + + const shouldTransferTokensByUsers = function (transferFunction, opts = {}) { + context('when called by the owner', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: owner }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the approved individual', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: approved }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the operator', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: operator }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the owner without an approved user', function () { + beforeEach(async function () { + await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: operator }); + }); + transferWasSuccessful({ owner, tokenId, approved: null }); + }); + + context('when sent to the owner', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, owner, tokenId, { from: owner }); + }); + + it('keeps ownership of the token', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owner); + }); + + it('clears the approval for the token ID', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + + it('emits only a transfer event', async function () { + expectEvent(receipt, 'Transfer', { + from: owner, + to: owner, + tokenId: tokenId, + }); + }); + + it('keeps the owner balance', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('2'); + }); + + it('keeps same tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenOfOwnerByIndex(owner, i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + }); + + context('when the address of the previous owner is incorrect', function () { + it('reverts', async function () { + await expectRevertCustomError( + transferFunction.call(this, other, other, tokenId, { from: owner }), + 'ERC721IncorrectOwner', + [other, tokenId, owner], + ); + }); + }); + + context('when the sender is not authorized for the token id', function () { + if (opts.unrestricted) { + it('does not revert', async function () { + await transferFunction.call(this, owner, other, tokenId, { from: other }); + }); + } else { + it('reverts', async function () { + await expectRevertCustomError( + transferFunction.call(this, owner, other, tokenId, { from: other }), + 'ERC721InsufficientApproval', + [other, tokenId], + ); + }); + } + }); + + context('when the given token ID does not exist', function () { + it('reverts', async function () { + await expectRevertCustomError( + transferFunction.call(this, owner, other, nonExistentTokenId, { from: owner }), + 'ERC721NonexistentToken', + [nonExistentTokenId], + ); + }); + }); + + context('when the address to transfer the token to is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError( + transferFunction.call(this, owner, ZERO_ADDRESS, tokenId, { from: owner }), + 'ERC721InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + }); + }; + + const shouldTransferSafely = function (transferFun, data, opts = {}) { + describe('to a user account', function () { + shouldTransferTokensByUsers(transferFun, opts); + }); + + describe('to a valid receiver contract', function () { + beforeEach(async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.None); + this.toWhom = this.receiver.address; + }); + + shouldTransferTokensByUsers(transferFun, opts); + + it('calls onERC721Received', async function () { + const receipt = await transferFun.call(this, owner, this.receiver.address, tokenId, { from: owner }); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + operator: owner, + from: owner, + tokenId: tokenId, + data: data, + }); + }); + + it('calls onERC721Received from approved', async function () { + const receipt = await transferFun.call(this, owner, this.receiver.address, tokenId, { from: approved }); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + operator: approved, + from: owner, + tokenId: tokenId, + data: data, + }); + }); + + describe('with an invalid token id', function () { + it('reverts', async function () { + await expectRevertCustomError( + transferFun.call(this, owner, this.receiver.address, nonExistentTokenId, { from: owner }), + 'ERC721NonexistentToken', + [nonExistentTokenId], + ); + }); + }); + }); + }; + + for (const { fnName, opts } of [ + { fnName: 'transferFrom', opts: {} }, + { fnName: '$_transfer', opts: { unrestricted: true } }, + ]) { + describe(`via ${fnName}`, function () { + shouldTransferTokensByUsers(function (from, to, tokenId, opts) { + return this.token[fnName](from, to, tokenId, opts); + }, opts); + }); + } + + for (const { fnName, opts } of [ + { fnName: 'safeTransferFrom', opts: {} }, + { fnName: '$_safeTransfer', opts: { unrestricted: true } }, + ]) { + describe(`via ${fnName}`, function () { + const safeTransferFromWithData = function (from, to, tokenId, opts) { + return this.token.methods[fnName + '(address,address,uint256,bytes)'](from, to, tokenId, data, opts); + }; + + const safeTransferFromWithoutData = function (from, to, tokenId, opts) { + return this.token.methods[fnName + '(address,address,uint256)'](from, to, tokenId, opts); + }; + + describe('with data', function () { + shouldTransferSafely(safeTransferFromWithData, data, opts); + }); + + describe('without data', function () { + shouldTransferSafely(safeTransferFromWithoutData, null, opts); + }); + + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ERC721ReceiverMock.new('0x42', RevertType.None); + await expectRevertCustomError( + this.token.methods[fnName + '(address,address,uint256)'](owner, invalidReceiver.address, tokenId, { + from: owner, + }), + 'ERC721InvalidReceiver', + [invalidReceiver.address], + ); + }); + }); + + describe('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithMessage, + ); + await expectRevert( + this.token.methods[fnName + '(address,address,uint256)'](owner, revertingReceiver.address, tokenId, { + from: owner, + }), + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + describe('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ); + await expectRevertCustomError( + this.token.methods[fnName + '(address,address,uint256)'](owner, revertingReceiver.address, tokenId, { + from: owner, + }), + 'ERC721InvalidReceiver', + [revertingReceiver.address], + ); + }); + }); + + describe('to a receiver contract that reverts with custom error', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ); + await expectRevertCustomError( + this.token.methods[fnName + '(address,address,uint256)'](owner, revertingReceiver.address, tokenId, { + from: owner, + }), + 'CustomError', + [RECEIVER_MAGIC_VALUE], + ); + }); + }); + + describe('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.Panic); + await expectRevert.unspecified( + this.token.methods[fnName + '(address,address,uint256)'](owner, revertingReceiver.address, tokenId, { + from: owner, + }), + ); + }); + }); + + describe('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await NonERC721ReceiverMock.new(); + await expectRevertCustomError( + this.token.methods[fnName + '(address,address,uint256)'](owner, nonReceiver.address, tokenId, { + from: owner, + }), + 'ERC721InvalidReceiver', + [nonReceiver.address], + ); + }); + }); + }); + } + }); + + describe('safe mint', function () { + const tokenId = fourthTokenId; + const data = '0x42'; + + describe('via safeMint', function () { + // regular minting is tested in ERC721Mintable.test.js and others + it('calls onERC721Received — with data', async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.None); + const receipt = await this.token.$_safeMint(this.receiver.address, tokenId, data); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + from: ZERO_ADDRESS, + tokenId: tokenId, + data: data, + }); + }); + + it('calls onERC721Received — without data', async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.None); + const receipt = await this.token.$_safeMint(this.receiver.address, tokenId); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + from: ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + + context('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ERC721ReceiverMock.new('0x42', RevertType.None); + await expectRevertCustomError( + this.token.$_safeMint(invalidReceiver.address, tokenId), + 'ERC721InvalidReceiver', + [invalidReceiver.address], + ); + }); + }); + + context('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.RevertWithMessage); + await expectRevert( + this.token.$_safeMint(revertingReceiver.address, tokenId), + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + context('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ); + await expectRevertCustomError( + this.token.$_safeMint(revertingReceiver.address, tokenId), + 'ERC721InvalidReceiver', + [revertingReceiver.address], + ); + }); + }); + + context('to a receiver contract that reverts with custom error', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ); + await expectRevertCustomError(this.token.$_safeMint(revertingReceiver.address, tokenId), 'CustomError', [ + RECEIVER_MAGIC_VALUE, + ]); + }); + }); + + context('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.Panic); + await expectRevert.unspecified(this.token.$_safeMint(revertingReceiver.address, tokenId)); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await NonERC721ReceiverMock.new(); + await expectRevertCustomError( + this.token.$_safeMint(nonReceiver.address, tokenId), + 'ERC721InvalidReceiver', + [nonReceiver.address], + ); + }); + }); + }); + }); + + describe('approve', function () { + const tokenId = firstTokenId; + + let receipt = null; + + const itClearsApproval = function () { + it('clears approval for the token', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + }; + + const itApproves = function (address) { + it('sets the approval for the target address', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(address); + }); + }; + + const itEmitsApprovalEvent = function (address) { + it('emits an approval event', async function () { + expectEvent(receipt, 'Approval', { + owner: owner, + approved: address, + tokenId: tokenId, + }); + }); + }; + + context('when clearing approval', function () { + context('when there was no prior approval', function () { + beforeEach(async function () { + receipt = await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + }); + + itClearsApproval(); + itEmitsApprovalEvent(ZERO_ADDRESS); + }); + + context('when there was a prior approval', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + }); + + itClearsApproval(); + itEmitsApprovalEvent(ZERO_ADDRESS); + }); + }); + + context('when approving a non-zero address', function () { + context('when there was no prior approval', function () { + beforeEach(async function () { + receipt = await this.token.approve(approved, tokenId, { from: owner }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when there was a prior approval to the same address', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.approve(approved, tokenId, { from: owner }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when there was a prior approval to a different address', function () { + beforeEach(async function () { + await this.token.approve(anotherApproved, tokenId, { from: owner }); + receipt = await this.token.approve(anotherApproved, tokenId, { from: owner }); + }); + + itApproves(anotherApproved); + itEmitsApprovalEvent(anotherApproved); + }); + }); + + context('when the sender does not own the given token ID', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.approve(approved, tokenId, { from: other }), + 'ERC721InvalidApprover', + [other], + ); + }); + }); + + context('when the sender is approved for the given token ID', function () { + it('reverts', async function () { + await this.token.approve(approved, tokenId, { from: owner }); + await expectRevertCustomError( + this.token.approve(anotherApproved, tokenId, { from: approved }), + 'ERC721InvalidApprover', + [approved], + ); + }); + }); + + context('when the sender is an operator', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + receipt = await this.token.approve(approved, tokenId, { from: operator }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when the given token ID does not exist', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.approve(approved, nonExistentTokenId, { from: operator }), + 'ERC721NonexistentToken', + [nonExistentTokenId], + ); + }); + }); + }); + + describe('setApprovalForAll', function () { + context('when the operator willing to approve is not the owner', function () { + context('when there is no operator approval set by the sender', function () { + it('approves the operator', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + }); + + context('when the operator was set as not approved', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, false, { from: owner }); + }); + + it('approves the operator', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + + it('can unset the operator approval', async function () { + await this.token.setApprovalForAll(operator, false, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); + + context('when the operator was already approved', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + }); + + it('keeps the approval to the given address', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + }); + }); + + context('when the operator is address zero', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.setApprovalForAll(constants.ZERO_ADDRESS, true, { from: owner }), + 'ERC721InvalidOperator', + [constants.ZERO_ADDRESS], + ); + }); + }); + }); + + describe('getApproved', async function () { + context('when token is not minted', async function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.getApproved(nonExistentTokenId), 'ERC721NonexistentToken', [ + nonExistentTokenId, + ]); + }); + }); + + context('when token has been minted ', async function () { + it('should return the zero address', async function () { + expect(await this.token.getApproved(firstTokenId)).to.be.equal(ZERO_ADDRESS); + }); + + context('when account has been approved', async function () { + beforeEach(async function () { + await this.token.approve(approved, firstTokenId, { from: owner }); + }); + + it('returns approved account', async function () { + expect(await this.token.getApproved(firstTokenId)).to.be.equal(approved); + }); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, firstTokenId), 'ERC721InvalidReceiver', [ + ZERO_ADDRESS, + ]); + }); + + context('with minted token', async function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(owner, firstTokenId); + }); + + it('emits a Transfer event', function () { + expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: owner, tokenId: firstTokenId }); + }); + + it('creates the token', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + expect(await this.token.ownerOf(firstTokenId)).to.equal(owner); + }); + + it('reverts when adding a token id that already exists', async function () { + await expectRevertCustomError(this.token.$_mint(owner, firstTokenId), 'ERC721InvalidSender', [ZERO_ADDRESS]); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expectRevertCustomError(this.token.$_burn(nonExistentTokenId), 'ERC721NonexistentToken', [ + nonExistentTokenId, + ]); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + context('with burnt token', function () { + beforeEach(async function () { + this.receipt = await this.token.$_burn(firstTokenId); + }); + + it('emits a Transfer event', function () { + expectEvent(this.receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, tokenId: firstTokenId }); + }); + + it('deletes the token', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + await expectRevertCustomError(this.token.ownerOf(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + + it('reverts when burning a token id that has been deleted', async function () { + await expectRevertCustomError(this.token.$_burn(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Enumerable(owner, newOwner, approved, anotherApproved, operator, other) { + shouldSupportInterfaces(['ERC721Enumerable']); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + this.toWhom = other; // default to other for toWhom in context-dependent tests + }); + + describe('totalSupply', function () { + it('returns total token supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal('2'); + }); + }); + + describe('tokenOfOwnerByIndex', function () { + describe('when the given index is lower than the amount of tokens owned by the given address', function () { + it('returns the token ID placed at the given index', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(firstTokenId); + }); + }); + + describe('when the index is greater than or equal to the total tokens owned by the given address', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.tokenOfOwnerByIndex(owner, 2), 'ERC721OutOfBoundsIndex', [owner, 2]); + }); + }); + + describe('when the given address does not own any token', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.tokenOfOwnerByIndex(other, 0), 'ERC721OutOfBoundsIndex', [other, 0]); + }); + }); + + describe('after transferring all tokens to another user', function () { + beforeEach(async function () { + await this.token.transferFrom(owner, other, firstTokenId, { from: owner }); + await this.token.transferFrom(owner, other, secondTokenId, { from: owner }); + }); + + it('returns correct token IDs for target', async function () { + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('2'); + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenOfOwnerByIndex(other, i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + + it('returns empty collection for original owner', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('0'); + await expectRevertCustomError(this.token.tokenOfOwnerByIndex(owner, 0), 'ERC721OutOfBoundsIndex', [owner, 0]); + }); + }); + }); + + describe('tokenByIndex', function () { + it('returns all tokens', async function () { + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenByIndex(i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + + it('reverts if index is greater than supply', async function () { + await expectRevertCustomError(this.token.tokenByIndex(2), 'ERC721OutOfBoundsIndex', [ZERO_ADDRESS, 2]); + }); + + [firstTokenId, secondTokenId].forEach(function (tokenId) { + it(`returns all tokens after burning token ${tokenId} and minting new tokens`, async function () { + const newTokenId = new BN(300); + const anotherNewTokenId = new BN(400); + + await this.token.$_burn(tokenId); + await this.token.$_mint(newOwner, newTokenId); + await this.token.$_mint(newOwner, anotherNewTokenId); + + expect(await this.token.totalSupply()).to.be.bignumber.equal('3'); + + const tokensListed = await Promise.all([0, 1, 2].map(i => this.token.tokenByIndex(i))); + const expectedTokens = [firstTokenId, secondTokenId, newTokenId, anotherNewTokenId].filter( + x => x !== tokenId, + ); + expect(tokensListed.map(t => t.toNumber())).to.have.members(expectedTokens.map(t => t.toNumber())); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, firstTokenId), 'ERC721InvalidReceiver', [ + ZERO_ADDRESS, + ]); + }); + + context('with minted token', async function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(owner, firstTokenId); + }); + + it('adjusts owner tokens by index', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(firstTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0)).to.be.bignumber.equal(firstTokenId); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expectRevertCustomError(this.token.$_burn(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + context('with burnt token', function () { + beforeEach(async function () { + this.receipt = await this.token.$_burn(firstTokenId); + }); + + it('removes that token from the token list of the owner', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(secondTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0)).to.be.bignumber.equal(secondTokenId); + }); + + it('burns all tokens', async function () { + await this.token.$_burn(secondTokenId, { from: owner }); + expect(await this.token.totalSupply()).to.be.bignumber.equal('0'); + await expectRevertCustomError(this.token.tokenByIndex(0), 'ERC721OutOfBoundsIndex', [ZERO_ADDRESS, 0]); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Metadata(name, symbol, owner) { + shouldSupportInterfaces(['ERC721Metadata']); + + describe('metadata', function () { + it('has a name', async function () { + expect(await this.token.name()).to.be.equal(name); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.be.equal(symbol); + }); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + }); + + it('return empty string by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expectRevertCustomError(this.token.tokenURI(nonExistentTokenId), 'ERC721NonexistentToken', [ + nonExistentTokenId, + ]); + }); + + describe('base URI', function () { + beforeEach(function () { + if (this.token.setBaseURI === undefined) { + this.skip(); + } + }); + + it('base URI can be set', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.baseURI()).to.equal(baseURI); + }); + + it('base URI is added as a prefix to the token URI', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + firstTokenId.toString()); + }); + + it('token URI can be changed by changing the base URI', async function () { + await this.token.setBaseURI(baseURI); + const newBaseURI = 'https://api.example.com/v2/'; + await this.token.setBaseURI(newBaseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + firstTokenId.toString()); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Enumerable, + shouldBehaveLikeERC721Metadata, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721.test.js new file mode 100644 index 0000000..372dd50 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721.test.js @@ -0,0 +1,15 @@ +const { shouldBehaveLikeERC721, shouldBehaveLikeERC721Metadata } = require('./ERC721.behavior'); + +const ERC721 = artifacts.require('$ERC721'); + +contract('ERC721', function (accounts) { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721.new(name, symbol); + }); + + shouldBehaveLikeERC721(...accounts); + shouldBehaveLikeERC721Metadata(name, symbol, ...accounts); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721Enumerable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721Enumerable.test.js new file mode 100644 index 0000000..31c28d1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/ERC721Enumerable.test.js @@ -0,0 +1,20 @@ +const { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Metadata, + shouldBehaveLikeERC721Enumerable, +} = require('./ERC721.behavior'); + +const ERC721Enumerable = artifacts.require('$ERC721Enumerable'); + +contract('ERC721Enumerable', function (accounts) { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Enumerable.new(name, symbol); + }); + + shouldBehaveLikeERC721(...accounts); + shouldBehaveLikeERC721Metadata(name, symbol, ...accounts); + shouldBehaveLikeERC721Enumerable(...accounts); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Burnable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Burnable.test.js new file mode 100644 index 0000000..df059e0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Burnable.test.js @@ -0,0 +1,82 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC721Burnable = artifacts.require('$ERC721Burnable'); + +contract('ERC721Burnable', function (accounts) { + const [owner, approved, another] = accounts; + + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Burnable.new(name, symbol); + }); + + describe('like a burnable ERC721', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + describe('burn', function () { + const tokenId = firstTokenId; + let receipt = null; + + describe('when successful', function () { + beforeEach(async function () { + receipt = await this.token.burn(tokenId, { from: owner }); + }); + + it('burns the given token ID and adjusts the balance of the owner', async function () { + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('emits a burn event', async function () { + expectEvent(receipt, 'Transfer', { + from: owner, + to: constants.ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + }); + + describe('when there is a previous approval burned', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.burn(tokenId, { from: owner }); + }); + + context('getApproved', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.getApproved(tokenId), 'ERC721NonexistentToken', [tokenId]); + }); + }); + }); + + describe('when there is no previous approval burned', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.burn(tokenId, { from: another }), 'ERC721InsufficientApproval', [ + another, + tokenId, + ]); + }); + }); + + describe('when the given token ID was not tracked by this contract', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.burn(unknownTokenId, { from: owner }), 'ERC721NonexistentToken', [ + unknownTokenId, + ]); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Consecutive.t.sol b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Consecutive.t.sol new file mode 100644 index 0000000..eca15e7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Consecutive.t.sol @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +// solhint-disable func-name-mixedcase + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Consecutive.sol"; +import {Test, StdUtils} from "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 { + uint96 private immutable _offset; + uint256 public totalMinted = 0; + + constructor(address[] memory receivers, uint256[] memory batches, uint256 startingId) ERC721("", "") { + _offset = uint96(startingId); + 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); + } + + function _firstConsecutiveId() internal view virtual override returns (uint96) { + return _offset; + } +} + +contract ERC721ConsecutiveTest is Test { + function test_balance(address receiver, uint256[] calldata batches, uint96 startingId) public { + vm.assume(receiver != address(0)); + + uint256 startingTokenId = bound(startingId, 0, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingTokenId); + + assertEq(token.balanceOf(receiver), token.totalMinted()); + } + + function test_ownership( + address receiver, + uint256[] calldata batches, + uint256[2] calldata unboundedTokenId, + uint96 startingId + ) public { + vm.assume(receiver != address(0)); + + uint256 startingTokenId = bound(startingId, 0, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingTokenId); + + if (token.totalMinted() > 0) { + uint256 validTokenId = bound( + unboundedTokenId[0], + startingTokenId, + startingTokenId + token.totalMinted() - 1 + ); + assertEq(token.ownerOf(validTokenId), receiver); + } + + uint256 invalidTokenId = bound( + unboundedTokenId[1], + startingTokenId + token.totalMinted(), + startingTokenId + token.totalMinted() + 1 + ); + vm.expectRevert(); + token.ownerOf(invalidTokenId); + } + + function test_burn( + address receiver, + uint256[] calldata batches, + uint256 unboundedTokenId, + uint96 startingId + ) public { + vm.assume(receiver != address(0)); + + uint256 startingTokenId = bound(startingId, 0, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingTokenId); + + // 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, startingTokenId, startingTokenId + 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, + uint96 startingId + ) public { + vm.assume(accounts[0] != address(0)); + vm.assume(accounts[1] != address(0)); + vm.assume(accounts[0] != accounts[1]); + + uint256 startingTokenId = bound(startingId, 1, 5000); + + 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], startingTokenId, 5000); + batches[1] = bound(unboundedBatches[1], startingTokenId, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(receivers, batches, startingTokenId); + + uint256 tokenId0 = bound(unboundedTokenId[0], startingTokenId, batches[0]); + uint256 tokenId1 = bound(unboundedTokenId[1], startingTokenId, batches[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]); + } + + function test_start_consecutive_id( + address receiver, + uint256[2] calldata unboundedBatches, + uint256[2] calldata unboundedTokenId, + uint96 startingId + ) public { + vm.assume(receiver != address(0)); + + uint256 startingTokenId = bound(startingId, 1, 5000); + + // We assume _maxBatchSize is 5000 (the default). This test will break otherwise. + uint256[] memory batches = new uint256[](2); + batches[0] = bound(unboundedBatches[0], startingTokenId, 5000); + batches[1] = bound(unboundedBatches[1], startingTokenId, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingTokenId); + + uint256 tokenId0 = bound(unboundedTokenId[0], startingTokenId, batches[0]); + uint256 tokenId1 = bound(unboundedTokenId[1], startingTokenId, batches[1]); + + assertEq(token.ownerOf(tokenId0), receiver); + assertEq(token.ownerOf(tokenId1), receiver); + assertEq(token.balanceOf(receiver), batches[0] + batches[1]); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Consecutive.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Consecutive.test.js new file mode 100644 index 0000000..d9e33af --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Consecutive.test.js @@ -0,0 +1,221 @@ +const { constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { sum } = require('../../../helpers/math'); +const { expectRevertCustomError } = require('../../../helpers/customError'); +const { ZERO_ADDRESS } = require('@openzeppelin/test-helpers/src/constants'); + +const ERC721ConsecutiveMock = artifacts.require('$ERC721ConsecutiveMock'); +const ERC721ConsecutiveEnumerableMock = artifacts.require('$ERC721ConsecutiveEnumerableMock'); +const ERC721ConsecutiveNoConstructorMintMock = artifacts.require('$ERC721ConsecutiveNoConstructorMintMock'); + +contract('ERC721Consecutive', function (accounts) { + const [user1, user2, user3, receiver] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const batches = [ + { receiver: user1, amount: 0 }, + { receiver: user1, amount: 1 }, + { receiver: user1, amount: 2 }, + { receiver: user2, amount: 5 }, + { receiver: user3, amount: 0 }, + { receiver: user1, amount: 7 }, + ]; + const delegates = [user1, user3]; + + for (const offset of [0, 1, 42]) { + describe(`with offset ${offset}`, function () { + beforeEach(async function () { + this.token = await ERC721ConsecutiveMock.new( + name, + symbol, + offset, + delegates, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ); + }); + + describe('minting during construction', function () { + it('events are emitted at construction', async function () { + let first = offset; + + for (const batch of batches) { + if (batch.amount > 0) { + await expectEvent.inConstruction(this.token, 'ConsecutiveTransfer', { + fromTokenId: web3.utils.toBN(first), + toTokenId: web3.utils.toBN(first + batch.amount - 1), + fromAddress: constants.ZERO_ADDRESS, + toAddress: batch.receiver, + }); + } else { + // expectEvent.notEmitted.inConstruction only looks at event name, and doesn't check the parameters + } + first += batch.amount; + } + }); + + it('ownership is set', async function () { + const owners = [ + ...Array(offset).fill(constants.ZERO_ADDRESS), + ...batches.flatMap(({ receiver, amount }) => Array(amount).fill(receiver)), + ]; + + for (const tokenId in owners) { + if (owners[tokenId] != constants.ZERO_ADDRESS) { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owners[tokenId]); + } + } + }); + + it('balance & voting power are set', async function () { + for (const account of accounts) { + const balance = sum(...batches.filter(({ receiver }) => receiver === account).map(({ amount }) => amount)); + + expect(await this.token.balanceOf(account)).to.be.bignumber.equal(web3.utils.toBN(balance)); + + // If not delegated at construction, check before + do delegation + if (!delegates.includes(account)) { + expect(await this.token.getVotes(account)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await this.token.delegate(account, { from: account }); + } + + // At this point all accounts should have delegated + expect(await this.token.getVotes(account)).to.be.bignumber.equal(web3.utils.toBN(balance)); + } + }); + + it('reverts on consecutive minting to the zero address', async function () { + await expectRevertCustomError( + ERC721ConsecutiveMock.new(name, symbol, offset, delegates, [ZERO_ADDRESS], [10]), + 'ERC721InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + }); + + describe('minting after construction', function () { + it('consecutive minting is not possible after construction', async function () { + await expectRevertCustomError(this.token.$_mintConsecutive(user1, 10), 'ERC721ForbiddenBatchMint', []); + }); + + it('simple minting is possible after construction', async function () { + const tokenId = sum(...batches.map(b => b.amount)) + offset; + + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + + expectEvent(await this.token.$_mint(user1, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + tokenId: tokenId.toString(), + }); + }); + + it('cannot mint a token that has been batched minted', async function () { + const tokenId = sum(...batches.map(b => b.amount)) + offset - 1; + + expect(await this.token.ownerOf(tokenId)).to.be.not.equal(constants.ZERO_ADDRESS); + + await expectRevertCustomError(this.token.$_mint(user1, tokenId), 'ERC721InvalidSender', [ZERO_ADDRESS]); + }); + }); + + describe('ERC721 behavior', function () { + const tokenId = web3.utils.toBN(offset + 1); + + it('core takes over ownership on transfer', async function () { + await this.token.transferFrom(user1, receiver, tokenId, { from: user1 }); + + expect(await this.token.ownerOf(tokenId)).to.be.equal(receiver); + }); + + it('tokens can be burned and re-minted #1', async function () { + expectEvent(await this.token.$_burn(tokenId, { from: user1 }), 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + tokenId, + }); + + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + + expectEvent(await this.token.$_mint(user2, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + tokenId, + }); + + expect(await this.token.ownerOf(tokenId)).to.be.equal(user2); + }); + + it('tokens can be burned and re-minted #2', async function () { + const tokenId = web3.utils.toBN(sum(...batches.map(({ amount }) => amount)) + offset); + + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + + // mint + await this.token.$_mint(user1, tokenId); + + expect(await this.token.ownerOf(tokenId), user1); + + // burn + expectEvent(await this.token.$_burn(tokenId, { from: user1 }), 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + tokenId, + }); + + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + + // re-mint + expectEvent(await this.token.$_mint(user2, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + tokenId, + }); + + expect(await this.token.ownerOf(tokenId), user2); + }); + }); + }); + } + + describe('invalid use', function () { + it('cannot mint a batch larger than 5000', async function () { + await expectRevertCustomError( + ERC721ConsecutiveMock.new(name, symbol, 0, [], [user1], ['5001']), + 'ERC721ExceededMaxBatchMint', + [5000, 5001], + ); + }); + + it('cannot use single minting during construction', async function () { + await expectRevertCustomError( + ERC721ConsecutiveNoConstructorMintMock.new(name, symbol), + 'ERC721ForbiddenMint', + [], + ); + }); + + it('cannot use single minting during construction', async function () { + await expectRevertCustomError( + ERC721ConsecutiveNoConstructorMintMock.new(name, symbol), + 'ERC721ForbiddenMint', + [], + ); + }); + + it('consecutive mint not compatible with enumerability', async function () { + await expectRevertCustomError( + ERC721ConsecutiveEnumerableMock.new( + name, + symbol, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ), + 'ERC721EnumerableForbiddenBatchMint', + [], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Pausable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Pausable.test.js new file mode 100644 index 0000000..5d77149 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Pausable.test.js @@ -0,0 +1,90 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC721Pausable = artifacts.require('$ERC721Pausable'); + +contract('ERC721Pausable', function (accounts) { + const [owner, receiver, operator] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Pausable.new(name, symbol); + }); + + context('when token is paused', function () { + const firstTokenId = new BN(1); + const secondTokenId = new BN(1337); + + const mockData = '0x42'; + + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId, { from: owner }); + await this.token.$_pause(); + }); + + it('reverts when trying to transferFrom', async function () { + await expectRevertCustomError( + this.token.transferFrom(owner, receiver, firstTokenId, { from: owner }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeTransferFrom', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(owner, receiver, firstTokenId, { from: owner }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeTransferFrom with data', async function () { + await expectRevertCustomError( + this.token.methods['safeTransferFrom(address,address,uint256,bytes)'](owner, receiver, firstTokenId, mockData, { + from: owner, + }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to mint', async function () { + await expectRevertCustomError(this.token.$_mint(receiver, secondTokenId), 'EnforcedPause', []); + }); + + it('reverts when trying to burn', async function () { + await expectRevertCustomError(this.token.$_burn(firstTokenId), 'EnforcedPause', []); + }); + + describe('getApproved', function () { + it('returns approved address', async function () { + const approvedAccount = await this.token.getApproved(firstTokenId); + expect(approvedAccount).to.equal(constants.ZERO_ADDRESS); + }); + }); + + describe('balanceOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const balance = await this.token.balanceOf(owner); + expect(balance).to.be.bignumber.equal('1'); + }); + }); + + describe('ownerOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const ownerOfToken = await this.token.ownerOf(firstTokenId); + expect(ownerOfToken).to.equal(owner); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Royalty.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Royalty.test.js new file mode 100644 index 0000000..78cba98 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Royalty.test.js @@ -0,0 +1,47 @@ +require('@openzeppelin/test-helpers'); + +const { shouldBehaveLikeERC2981 } = require('../../common/ERC2981.behavior'); + +const ERC721Royalty = artifacts.require('$ERC721Royalty'); + +contract('ERC721Royalty', function (accounts) { + const [account1, account2, recipient] = accounts; + const tokenId1 = web3.utils.toBN('1'); + const tokenId2 = web3.utils.toBN('2'); + const royalty = web3.utils.toBN('200'); + const salePrice = web3.utils.toBN('1000'); + + beforeEach(async function () { + this.token = await ERC721Royalty.new('My Token', 'TKN'); + + await this.token.$_mint(account1, tokenId1); + await this.token.$_mint(account1, tokenId2); + this.account1 = account1; + this.account2 = account2; + this.tokenId1 = tokenId1; + this.tokenId2 = tokenId2; + this.salePrice = salePrice; + }); + + describe('token specific functions', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(tokenId1, recipient, royalty); + }); + + it('royalty information are kept during burn and re-mint', async function () { + await this.token.$_burn(tokenId1); + + const tokenInfoA = await this.token.royaltyInfo(tokenId1, salePrice); + expect(tokenInfoA[0]).to.be.equal(recipient); + expect(tokenInfoA[1]).to.be.bignumber.equal(salePrice.mul(royalty).divn(1e4)); + + await this.token.$_mint(account2, tokenId1); + + const tokenInfoB = await this.token.royaltyInfo(tokenId1, salePrice); + expect(tokenInfoB[0]).to.be.equal(recipient); + expect(tokenInfoB[1]).to.be.bignumber.equal(salePrice.mul(royalty).divn(1e4)); + }); + }); + + shouldBehaveLikeERC2981(); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721URIStorage.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721URIStorage.test.js new file mode 100644 index 0000000..8c882fa --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721URIStorage.test.js @@ -0,0 +1,114 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC721URIStorageMock = artifacts.require('$ERC721URIStorageMock'); + +contract('ERC721URIStorage', function (accounts) { + const [owner] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + const firstTokenId = new BN('5042'); + const nonExistentTokenId = new BN('13'); + + beforeEach(async function () { + this.token = await ERC721URIStorageMock.new(name, symbol); + }); + + shouldSupportInterfaces(['0x49064906']); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + }); + + const baseURI = 'https://api.example.com/v1/'; + const sampleUri = 'mock://mytoken'; + + it('it is empty by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expectRevertCustomError(this.token.tokenURI(nonExistentTokenId), 'ERC721NonexistentToken', [ + nonExistentTokenId, + ]); + }); + + it('can be set for a token id', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + 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('setting the uri for non existent token id is allowed', async function () { + expectEvent(await this.token.$_setTokenURI(nonExistentTokenId, sampleUri), 'MetadataUpdate', { + _tokenId: nonExistentTokenId, + }); + + // value will be accessible after mint + await this.token.$_mint(owner, nonExistentTokenId); + expect(await this.token.tokenURI(nonExistentTokenId)).to.be.equal(sampleUri); + }); + + it('base URI can be set', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.$_baseURI()).to.equal(baseURI); + }); + + it('base URI is added as a prefix to the token URI', async function () { + await this.token.setBaseURI(baseURI); + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + sampleUri); + }); + + it('token URI can be changed by changing the base URI', async function () { + await this.token.setBaseURI(baseURI); + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + const newBaseURI = 'https://api.example.com/v2/'; + await this.token.setBaseURI(newBaseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + sampleUri); + }); + + it('tokenId is appended to base URI for tokens with no URI', async function () { + await this.token.setBaseURI(baseURI); + + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + firstTokenId); + }); + + it('tokens without URI can be burnt ', async function () { + await this.token.$_burn(firstTokenId); + + await expectRevertCustomError(this.token.tokenURI(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + + it('tokens with URI can be burnt ', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + await this.token.$_burn(firstTokenId); + + await expectRevertCustomError(this.token.tokenURI(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + + it('tokens URI is kept if token is burnt and reminted ', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + await this.token.$_burn(firstTokenId); + await expectRevertCustomError(this.token.tokenURI(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + + await this.token.$_mint(owner, firstTokenId); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(sampleUri); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Votes.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Votes.test.js new file mode 100644 index 0000000..45020ba --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Votes.test.js @@ -0,0 +1,183 @@ +/* eslint-disable */ + +const { expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { clock, clockFromReceipt } = require('../../../helpers/time'); + +const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); + +const MODES = { + blocknumber: artifacts.require('$ERC721Votes'), + // no timestamp mode for ERC721Votes yet +}; + +contract('ERC721Votes', function (accounts) { + const [account1, account2, other1, other2] = accounts; + + const name = 'My Vote'; + const symbol = 'MTKN'; + const version = '1'; + const tokens = ['10000000000000000000000000', '10', '20', '30'].map(n => web3.utils.toBN(n)); + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.votes = await artifact.new(name, symbol, name, version); + }); + + // includes EIP6372 behavior check + shouldBehaveLikeVotes(accounts, tokens, { mode, fungible: false }); + + describe('balanceOf', function () { + beforeEach(async function () { + await this.votes.$_mint(account1, tokens[0]); + await this.votes.$_mint(account1, tokens[1]); + await this.votes.$_mint(account1, tokens[2]); + await this.votes.$_mint(account1, tokens[3]); + }); + + it('grants to initial account', async function () { + expect(await this.votes.balanceOf(account1)).to.be.bignumber.equal('4'); + }); + }); + + describe('transfers', function () { + beforeEach(async function () { + await this.votes.$_mint(account1, tokens[0]); + }); + + it('no delegation', async function () { + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('sender delegation', async function () { + await this.votes.delegate(account1, { from: account1 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousVotes: '1', newVotes: '0' }); + + 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.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('receiver delegation', async function () { + await this.votes.delegate(account2, { from: account2 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousVotes: '0', newVotes: '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.account1Votes = '0'; + this.account2Votes = '1'; + }); + + it('full delegation', async function () { + await this.votes.delegate(account1, { from: account1 }); + await this.votes.delegate(account2, { from: account2 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousVotes: '1', newVotes: '0' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousVotes: '0', newVotes: '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.account1Votes = '0'; + this.account2Votes = '1'; + }); + + it('returns the same total supply on transfers', async function () { + await this.votes.delegate(account1, { from: account1 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + const timepoint = await clockFromReceipt[mode](receipt); + + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.votes.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal('1'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + await this.votes.$_mint(account1, tokens[1]); + await this.votes.$_mint(account1, tokens[2]); + await this.votes.$_mint(account1, tokens[3]); + + const total = await this.votes.balanceOf(account1); + + const t1 = await this.votes.delegate(other1, { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.votes.transferFrom(account1, other2, tokens[0], { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.votes.transferFrom(account1, other2, tokens[2], { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.votes.transferFrom(other2, account1, tokens[2], { 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.votes.getPastVotes(other1, t1.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(other1, t1.timepoint)).to.be.bignumber.equal(total); + expect(await this.votes.getPastVotes(other1, t1.timepoint + 1)).to.be.bignumber.equal(total); + expect(await this.votes.getPastVotes(other1, t2.timepoint)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t2.timepoint + 1)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t3.timepoint)).to.be.bignumber.equal('2'); + expect(await this.votes.getPastVotes(other1, t3.timepoint + 1)).to.be.bignumber.equal('2'); + expect(await this.votes.getPastVotes(other1, t4.timepoint)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t4.timepoint + 1)).to.be.bignumber.equal('3'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + afterEach(async function () { + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(this.account1Votes); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(this.account2Votes); + + // 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.votes.getPastVotes(account1, timepoint)).to.be.bignumber.equal(this.account1Votes); + expect(await this.votes.getPastVotes(account2, timepoint)).to.be.bignumber.equal(this.account2Votes); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Wrapper.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Wrapper.test.js new file mode 100644 index 0000000..6839977 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -0,0 +1,289 @@ +const { BN, expectEvent, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { shouldBehaveLikeERC721 } = require('../ERC721.behavior'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +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 expectRevertCustomError( + this.token.depositFor(initialHolder, [firstTokenId], { from: initialHolder }), + 'ERC721InsufficientApproval', + [this.token.address, firstTokenId], + ); + }); + }); + + 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 expectRevertCustomError( + this.token.withdrawTo(initialHolder, [firstTokenId], { from: anotherAccount }), + 'ERC721InsufficientApproval', + [anotherAccount, firstTokenId], + ); + }); + + 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.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 () { + 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 () { + it('only allows calls from underlying', async function () { + await expectRevertCustomError( + this.token.onERC721Received( + initialHolder, + this.token.address, + firstTokenId, + anotherAccount, // Correct data + { from: anotherAccount }, + ), + 'ERC721UnsupportedToken', + [anotherAccount], + ); + }); + + it('mints a token to from', 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 () { + const owner = await this.underlying.ownerOf(firstTokenId); + await expectRevertCustomError(this.token.$_recover(initialHolder, firstTokenId), 'ERC721IncorrectOwner', [ + this.token.address, + firstTokenId, + owner, + ]); + }); + }); + + describe('ERC712 behavior', function () { + shouldBehaveLikeERC721(...accounts); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/utils/ERC721Holder.test.js b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/utils/ERC721Holder.test.js new file mode 100644 index 0000000..4aa2b79 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/ERC721/utils/ERC721Holder.test.js @@ -0,0 +1,22 @@ +const { expect } = require('chai'); + +const ERC721Holder = artifacts.require('$ERC721Holder'); +const ERC721 = artifacts.require('$ERC721'); + +contract('ERC721Holder', function (accounts) { + const [owner] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const tokenId = web3.utils.toBN(1); + + it('receives an ERC721 token', async function () { + const token = await ERC721.new(name, symbol); + await token.$_mint(owner, tokenId); + + const receiver = await ERC721Holder.new(); + await token.safeTransferFrom(owner, receiver.address, tokenId, { from: owner }); + + expect(await token.ownerOf(tokenId)).to.be.equal(receiver.address); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/token/common/ERC2981.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/token/common/ERC2981.behavior.js new file mode 100644 index 0000000..15efa23 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/token/common/ERC2981.behavior.js @@ -0,0 +1,169 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +function shouldBehaveLikeERC2981() { + const royaltyFraction = new BN('10'); + + shouldSupportInterfaces(['ERC2981']); + + describe('default royalty', function () { + beforeEach(async function () { + await this.token.$_setDefaultRoyalty(this.account1, royaltyFraction); + }); + + it('checks royalty is set', async function () { + const royalty = new BN((this.salePrice * royaltyFraction) / 10000); + + const initInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(initInfo[0]).to.be.equal(this.account1); + expect(initInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('updates royalty amount', async function () { + const newPercentage = new BN('25'); + + // Updated royalty check + await this.token.$_setDefaultRoyalty(this.account1, newPercentage); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + const newInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(newInfo[0]).to.be.equal(this.account1); + expect(newInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('holds same royalty value for different tokens', async function () { + const newPercentage = new BN('20'); + await this.token.$_setDefaultRoyalty(this.account1, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + + expect(token1Info[1]).to.be.bignumber.equal(token2Info[1]); + }); + + it('Remove royalty information', async function () { + const newValue = new BN('0'); + await this.token.$_deleteDefaultRoyalty(); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Test royalty info is still persistent across all tokens + expect(token1Info[0]).to.be.bignumber.equal(token2Info[0]); + expect(token1Info[1]).to.be.bignumber.equal(token2Info[1]); + // Test information was deleted + expect(token1Info[0]).to.be.equal(ZERO_ADDRESS); + expect(token1Info[1]).to.be.bignumber.equal(newValue); + }); + + it('reverts if invalid parameters', async function () { + const royaltyDenominator = await this.token.$_feeDenominator(); + await expectRevertCustomError( + this.token.$_setDefaultRoyalty(ZERO_ADDRESS, royaltyFraction), + 'ERC2981InvalidDefaultRoyaltyReceiver', + [ZERO_ADDRESS], + ); + + const anotherRoyaltyFraction = new BN('11000'); + await expectRevertCustomError( + this.token.$_setDefaultRoyalty(this.account1, anotherRoyaltyFraction), + 'ERC2981InvalidDefaultRoyalty', + [anotherRoyaltyFraction, royaltyDenominator], + ); + }); + }); + + describe('token based royalty', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, royaltyFraction); + }); + + it('updates royalty amount', async function () { + const newPercentage = new BN('25'); + let royalty = new BN((this.salePrice * royaltyFraction) / 10000); + // Initial royalty check + const initInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(initInfo[0]).to.be.equal(this.account1); + expect(initInfo[1]).to.be.bignumber.equal(royalty); + + // Updated royalty check + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, newPercentage); + royalty = new BN((this.salePrice * newPercentage) / 10000); + const newInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(newInfo[0]).to.be.equal(this.account1); + expect(newInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('holds different values for different tokens', async function () { + const newPercentage = new BN('20'); + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + + // must be different even at the same this.salePrice + expect(token1Info[1]).to.not.be.equal(token2Info.royaltyFraction); + }); + + it('reverts if invalid parameters', async function () { + const royaltyDenominator = await this.token.$_feeDenominator(); + await expectRevertCustomError( + this.token.$_setTokenRoyalty(this.tokenId1, ZERO_ADDRESS, royaltyFraction), + 'ERC2981InvalidTokenRoyaltyReceiver', + [this.tokenId1.toString(), ZERO_ADDRESS], + ); + + const anotherRoyaltyFraction = new BN('11000'); + await expectRevertCustomError( + this.token.$_setTokenRoyalty(this.tokenId1, this.account1, anotherRoyaltyFraction), + 'ERC2981InvalidTokenRoyalty', + [this.tokenId1.toString(), anotherRoyaltyFraction, royaltyDenominator], + ); + }); + + it('can reset token after setting royalty', async function () { + const newPercentage = new BN('30'); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + await this.token.$_setTokenRoyalty(this.tokenId1, this.account2, newPercentage); + + const tokenInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + // Tokens must have own information + expect(tokenInfo[1]).to.be.bignumber.equal(royalty); + expect(tokenInfo[0]).to.be.equal(this.account2); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, new BN('0')); + const result = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Token must not share default information + expect(result[0]).to.be.equal(this.account1); + expect(result[1]).to.be.bignumber.equal(new BN('0')); + }); + + it('can hold default and token royalty information', async function () { + const newPercentage = new BN('30'); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account2, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Tokens must not have same values + expect(token1Info[1]).to.not.be.bignumber.equal(token2Info[1]); + expect(token1Info[0]).to.not.be.equal(token2Info[0]); + + // Updated token must have new values + expect(token2Info[0]).to.be.equal(this.account2); + expect(token2Info[1]).to.be.bignumber.equal(royalty); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC2981, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Address.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Address.test.js new file mode 100644 index 0000000..57453ab --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Address.test.js @@ -0,0 +1,340 @@ +const { balance, constants, ether, expectRevert, send, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const Address = artifacts.require('$Address'); +const EtherReceiver = artifacts.require('EtherReceiverMock'); +const CallReceiverMock = artifacts.require('CallReceiverMock'); + +contract('Address', function (accounts) { + const [recipient, other] = accounts; + + beforeEach(async function () { + this.mock = await Address.new(); + }); + + describe('sendValue', function () { + beforeEach(async function () { + this.recipientTracker = await balance.tracker(recipient); + }); + + context('when sender contract has no funds', function () { + it('sends 0 wei', async function () { + await this.mock.$sendValue(other, 0); + + expect(await this.recipientTracker.delta()).to.be.bignumber.equal('0'); + }); + + it('reverts when sending non-zero amounts', async function () { + await expectRevertCustomError(this.mock.$sendValue(other, 1), 'AddressInsufficientBalance', [ + this.mock.address, + ]); + }); + }); + + context('when sender contract has funds', function () { + const funds = ether('1'); + beforeEach(async function () { + await send.ether(other, this.mock.address, funds); + }); + + it('sends 0 wei', async function () { + await this.mock.$sendValue(recipient, 0); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal('0'); + }); + + it('sends non-zero amounts', async function () { + await this.mock.$sendValue(recipient, funds.subn(1)); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal(funds.subn(1)); + }); + + it('sends the whole balance', async function () { + await this.mock.$sendValue(recipient, funds); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal(funds); + expect(await balance.current(this.mock.address)).to.be.bignumber.equal('0'); + }); + + it('reverts when sending more than the balance', async function () { + await expectRevertCustomError(this.mock.$sendValue(recipient, funds.addn(1)), 'AddressInsufficientBalance', [ + this.mock.address, + ]); + }); + + context('with contract recipient', function () { + beforeEach(async function () { + this.target = await EtherReceiver.new(); + }); + + it('sends funds', async function () { + const tracker = await balance.tracker(this.target.address); + + await this.target.setAcceptEther(true); + await this.mock.$sendValue(this.target.address, funds); + + expect(await tracker.delta()).to.be.bignumber.equal(funds); + }); + + it('reverts on recipient revert', async function () { + await this.target.setAcceptEther(false); + await expectRevertCustomError(this.mock.$sendValue(this.target.address, funds), 'FailedInnerCall', []); + }); + }); + }); + }); + + describe('functionCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + context('with valid contract receiver', function () { + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const receipt = await this.mock.$functionCall(this.target.address, abiEncodedCall); + + expectEvent(receipt, 'return$functionCall', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + 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(); + + await expectRevertCustomError( + this.mock.$functionCall(this.target.address, abiEncodedCall), + 'FailedInnerCall', + [], + ); + }); + + it('reverts when the called function reverts, bubbling up the revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert(this.mock.$functionCall(this.target.address, abiEncodedCall), 'CallReceiverMock: reverting'); + }); + + it('reverts when the called function runs out of gas', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionOutOfGas().encodeABI(); + + await expectRevertCustomError( + this.mock.$functionCall(this.target.address, abiEncodedCall, { gas: '120000' }), + 'FailedInnerCall', + [], + ); + }); + + it('reverts when the called function throws', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionThrows().encodeABI(); + + await expectRevert.unspecified(this.mock.$functionCall(this.target.address, abiEncodedCall)); + }); + + it('reverts when function does not exist', async function () { + const abiEncodedCall = web3.eth.abi.encodeFunctionCall( + { + name: 'mockFunctionDoesNotExist', + type: 'function', + inputs: [], + }, + [], + ); + + await expectRevertCustomError( + this.mock.$functionCall(this.target.address, abiEncodedCall), + 'FailedInnerCall', + [], + ); + }); + }); + + context('with non-contract receiver', function () { + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError(this.mock.$functionCall(recipient, abiEncodedCall), 'AddressEmptyCode', [ + recipient, + ]); + }); + }); + }); + + describe('functionCallWithValue', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + context('with zero value', function () { + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, 0); + expectEvent(receipt, 'return$functionCallWithValue', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + }); + }); + + context('with non-zero value', function () { + const amount = ether('1.2'); + + it('reverts if insufficient sender balance', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError( + this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount), + 'AddressInsufficientBalance', + [this.mock.address], + ); + }); + + it('calls the requested function with existing value', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const tracker = await balance.tracker(this.target.address); + + await send.ether(other, this.mock.address, amount); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount); + expectEvent(receipt, 'return$functionCallWithValue', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + + expect(await tracker.delta()).to.be.bignumber.equal(amount); + }); + + it('calls the requested function with transaction funds', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const tracker = await balance.tracker(this.target.address); + + expect(await balance.current(this.mock.address)).to.be.bignumber.equal('0'); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount, { + from: other, + value: amount, + }); + expectEvent(receipt, 'return$functionCallWithValue', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + + expect(await tracker.delta()).to.be.bignumber.equal(amount); + }); + + it('reverts when calling non-payable functions', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionNonPayable().encodeABI(); + + await send.ether(other, this.mock.address, amount); + await expectRevertCustomError( + this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount), + 'FailedInnerCall', + [], + ); + }); + }); + }); + + describe('functionStaticCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockStaticFunction().encodeABI(); + + expect(await this.mock.$functionStaticCall(this.target.address, abiEncodedCall)).to.be.equal( + web3.eth.abi.encodeParameters(['string'], ['0x1234']), + ); + }); + + it('reverts on a non-static function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError( + this.mock.$functionStaticCall(this.target.address, abiEncodedCall), + 'FailedInnerCall', + [], + ); + }); + + it('bubbles up revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert( + this.mock.$functionStaticCall(this.target.address, abiEncodedCall), + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError(this.mock.$functionStaticCall(recipient, abiEncodedCall), 'AddressEmptyCode', [ + recipient, + ]); + }); + }); + + describe('functionDelegateCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + it('delegate calls the requested function', async function () { + // pseudorandom values + const slot = '0x93e4c53af435ddf777c3de84bb9a953a777788500e229a468ea1036496ab66a0'; + const value = '0x6a465d1c49869f71fb65562bcbd7e08c8044074927f0297127203f2a9924ff5b'; + + const abiEncodedCall = this.target.contract.methods.mockFunctionWritesStorage(slot, value).encodeABI(); + + expect(await web3.eth.getStorageAt(this.mock.address, slot)).to.be.equal(constants.ZERO_BYTES32); + + expectEvent( + await this.mock.$functionDelegateCall(this.target.address, abiEncodedCall), + 'return$functionDelegateCall', + { ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']) }, + ); + + expect(await web3.eth.getStorageAt(this.mock.address, slot)).to.be.equal(value); + }); + + it('bubbles up revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert( + this.mock.$functionDelegateCall(this.target.address, abiEncodedCall), + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError(this.mock.$functionDelegateCall(recipient, abiEncodedCall), 'AddressEmptyCode', [ + recipient, + ]); + }); + }); + + describe('verifyCallResult', function () { + it('returns returndata on success', async function () { + const returndata = '0x123abc'; + expect(await this.mock.$verifyCallResult(true, returndata)).to.equal(returndata); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Arrays.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Arrays.test.js new file mode 100644 index 0000000..d939d59 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Arrays.test.js @@ -0,0 +1,123 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const AddressArraysMock = artifacts.require('AddressArraysMock'); +const Bytes32ArraysMock = artifacts.require('Bytes32ArraysMock'); +const Uint256ArraysMock = artifacts.require('Uint256ArraysMock'); + +contract('Arrays', function () { + describe('findUpperBound', function () { + context('Even number of elements', function () { + const EVEN_ELEMENTS_ARRAY = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(EVEN_ELEMENTS_ARRAY); + }); + + it('returns correct index for the basic case', async function () { + expect(await this.arrays.findUpperBound(16)).to.be.bignumber.equal('5'); + }); + + it('returns 0 for the first element', async function () { + expect(await this.arrays.findUpperBound(11)).to.be.bignumber.equal('0'); + }); + + it('returns index of the last element', async function () { + expect(await this.arrays.findUpperBound(20)).to.be.bignumber.equal('9'); + }); + + it('returns first index after last element if searched value is over the upper boundary', async function () { + expect(await this.arrays.findUpperBound(32)).to.be.bignumber.equal('10'); + }); + + it('returns 0 for the element under the lower boundary', async function () { + expect(await this.arrays.findUpperBound(2)).to.be.bignumber.equal('0'); + }); + }); + + context('Odd number of elements', function () { + const ODD_ELEMENTS_ARRAY = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(ODD_ELEMENTS_ARRAY); + }); + + it('returns correct index for the basic case', async function () { + expect(await this.arrays.findUpperBound(16)).to.be.bignumber.equal('5'); + }); + + it('returns 0 for the first element', async function () { + expect(await this.arrays.findUpperBound(11)).to.be.bignumber.equal('0'); + }); + + it('returns index of the last element', async function () { + expect(await this.arrays.findUpperBound(21)).to.be.bignumber.equal('10'); + }); + + it('returns first index after last element if searched value is over the upper boundary', async function () { + expect(await this.arrays.findUpperBound(32)).to.be.bignumber.equal('11'); + }); + + it('returns 0 for the element under the lower boundary', async function () { + expect(await this.arrays.findUpperBound(2)).to.be.bignumber.equal('0'); + }); + }); + + context('Array with gap', function () { + const WITH_GAP_ARRAY = [11, 12, 13, 14, 15, 20, 21, 22, 23, 24]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(WITH_GAP_ARRAY); + }); + + it('returns index of first element in next filled range', async function () { + expect(await this.arrays.findUpperBound(17)).to.be.bignumber.equal('5'); + }); + }); + + context('Empty array', function () { + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new([]); + }); + + it('always returns 0 for empty array', async function () { + expect(await this.arrays.findUpperBound(10)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('unsafeAccess', function () { + for (const { type, artifact, elements } of [ + { + type: 'address', + artifact: AddressArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(20)), + }, + { + type: 'bytes32', + artifact: Bytes32ArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(32)), + }, + { + type: 'uint256', + artifact: Uint256ArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(32)), + }, + ]) { + it(type, async function () { + const contract = await artifact.new(elements); + + for (const i in elements) { + expect(await contract.unsafeAccess(i)).to.be.bignumber.equal(elements[i]); + } + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Base64.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Base64.test.js new file mode 100644 index 0000000..dfff0b0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Base64.test.js @@ -0,0 +1,33 @@ +const { expect } = require('chai'); + +const Base64 = artifacts.require('$Base64'); + +contract('Strings', function () { + beforeEach(async function () { + this.base64 = await Base64.new(); + }); + + describe('from bytes - base64', function () { + it('converts to base64 encoded string with double padding', async function () { + const TEST_MESSAGE = 'test'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdA=='); + }); + + it('converts to base64 encoded string with single padding', async function () { + const TEST_MESSAGE = 'test1'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdDE='); + }); + + it('converts to base64 encoded string without padding', async function () { + const TEST_MESSAGE = 'test12'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdDEy'); + }); + + it('empty bytes', async function () { + expect(await this.base64.$encode([])).to.equal(''); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Context.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Context.behavior.js new file mode 100644 index 0000000..08f7558 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Context.behavior.js @@ -0,0 +1,42 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); + +const ContextMock = artifacts.require('ContextMock'); + +function shouldBehaveLikeRegularContext(sender) { + describe('msgSender', function () { + it('returns the transaction sender when called from an EOA', async function () { + const receipt = await this.context.msgSender({ from: sender }); + expectEvent(receipt, 'Sender', { sender }); + }); + + it('returns the transaction sender when from another contract', async function () { + const { tx } = await this.caller.callSender(this.context.address, { from: sender }); + await expectEvent.inTransaction(tx, ContextMock, 'Sender', { sender: this.caller.address }); + }); + }); + + describe('msgData', function () { + const integerValue = new BN('42'); + const stringValue = 'OpenZeppelin'; + + let callData; + + beforeEach(async function () { + callData = this.context.contract.methods.msgData(integerValue.toString(), stringValue).encodeABI(); + }); + + it('returns the transaction data when called from an EOA', async function () { + const receipt = await this.context.msgData(integerValue, stringValue); + expectEvent(receipt, 'Data', { data: callData, integerValue, stringValue }); + }); + + it('returns the transaction sender when from another contract', async function () { + const { tx } = await this.caller.callData(this.context.address, integerValue, stringValue); + await expectEvent.inTransaction(tx, ContextMock, 'Data', { data: callData, integerValue, stringValue }); + }); + }); +} + +module.exports = { + shouldBehaveLikeRegularContext, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Context.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Context.test.js new file mode 100644 index 0000000..f372f74 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Context.test.js @@ -0,0 +1,17 @@ +require('@openzeppelin/test-helpers'); + +const ContextMock = artifacts.require('ContextMock'); +const ContextMockCaller = artifacts.require('ContextMockCaller'); + +const { shouldBehaveLikeRegularContext } = require('./Context.behavior'); + +contract('Context', function (accounts) { + const [sender] = accounts; + + beforeEach(async function () { + this.context = await ContextMock.new(); + this.caller = await ContextMockCaller.new(); + }); + + shouldBehaveLikeRegularContext(sender); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Create2.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Create2.test.js new file mode 100644 index 0000000..336ab1a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Create2.test.js @@ -0,0 +1,102 @@ +const { balance, ether, expectEvent, expectRevert, send } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { computeCreate2Address } = require('../helpers/create'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const Create2 = artifacts.require('$Create2'); +const VestingWallet = artifacts.require('VestingWallet'); +// This should be a contract that: +// - has no constructor arguments +// - has no immutable variable populated during construction +const ConstructorLessContract = Create2; + +contract('Create2', function (accounts) { + const [deployerAccount, other] = accounts; + + const salt = 'salt message'; + const saltHex = web3.utils.soliditySha3(salt); + + const encodedParams = web3.eth.abi.encodeParameters(['address', 'uint64', 'uint64'], [other, 0, 0]).slice(2); + + const constructorByteCode = `${VestingWallet.bytecode}${encodedParams}`; + + beforeEach(async function () { + this.factory = await Create2.new(); + }); + describe('computeAddress', function () { + it('computes the correct contract address', async function () { + const onChainComputed = await this.factory.$computeAddress(saltHex, web3.utils.keccak256(constructorByteCode)); + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + expect(onChainComputed).to.equal(offChainComputed); + }); + + it('computes the correct contract address with deployer', async function () { + const onChainComputed = await this.factory.$computeAddress( + saltHex, + web3.utils.keccak256(constructorByteCode), + deployerAccount, + ); + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, deployerAccount); + expect(onChainComputed).to.equal(offChainComputed); + }); + }); + + describe('deploy', function () { + it('deploys a contract without constructor', async function () { + const offChainComputed = computeCreate2Address(saltHex, ConstructorLessContract.bytecode, this.factory.address); + + expectEvent(await this.factory.$deploy(0, saltHex, ConstructorLessContract.bytecode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(ConstructorLessContract.bytecode).to.include((await web3.eth.getCode(offChainComputed)).slice(2)); + }); + + it('deploys a contract with constructor arguments', async function () { + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + + expectEvent(await this.factory.$deploy(0, saltHex, constructorByteCode), 'return$deploy', { + addr: offChainComputed, + }); + + const instance = await VestingWallet.at(offChainComputed); + + expect(await instance.owner()).to.be.equal(other); + }); + + it('deploys a contract with funds deposited in the factory', async function () { + const deposit = ether('2'); + await send.ether(deployerAccount, this.factory.address, deposit); + expect(await balance.current(this.factory.address)).to.be.bignumber.equal(deposit); + + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + + expectEvent(await this.factory.$deploy(deposit, saltHex, constructorByteCode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(await balance.current(offChainComputed)).to.be.bignumber.equal(deposit); + }); + + it('fails deploying a contract in an existent address', async function () { + expectEvent(await this.factory.$deploy(0, saltHex, constructorByteCode), 'return$deploy'); + + // TODO: Make sure it actually throws "Create2FailedDeployment". + // For some unknown reason, the revert reason sometimes return: + // `revert with unrecognized return data or custom error` + await expectRevert.unspecified(this.factory.$deploy(0, saltHex, constructorByteCode)); + }); + + it('fails deploying a contract if the bytecode length is zero', async function () { + await expectRevertCustomError(this.factory.$deploy(0, saltHex, '0x'), 'Create2EmptyBytecode', []); + }); + + it('fails deploying a contract if factory contract does not have sufficient balance', async function () { + await expectRevertCustomError( + this.factory.$deploy(1, saltHex, constructorByteCode), + 'Create2InsufficientBalance', + [0, 1], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Multicall.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Multicall.test.js new file mode 100644 index 0000000..65443cd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Multicall.test.js @@ -0,0 +1,69 @@ +const { BN } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const ERC20MulticallMock = artifacts.require('$ERC20MulticallMock'); + +contract('Multicall', function (accounts) { + const [deployer, alice, bob] = accounts; + const amount = 12000; + + beforeEach(async function () { + this.multicallToken = await ERC20MulticallMock.new('name', 'symbol'); + await this.multicallToken.$_mint(deployer, amount); + }); + + it('batches function calls', async function () { + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + expect(await this.multicallToken.balanceOf(bob)).to.be.bignumber.equal(new BN('0')); + + await this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount / 2).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount / 3).encodeABI(), + ], + { from: deployer }, + ); + + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN(amount / 2)); + expect(await this.multicallToken.balanceOf(bob)).to.be.bignumber.equal(new BN(amount / 3)); + }); + + it('returns an array with the result of each call', async function () { + const MulticallTest = artifacts.require('MulticallTest'); + const multicallTest = await MulticallTest.new({ from: deployer }); + await this.multicallToken.transfer(multicallTest.address, amount, { from: deployer }); + expect(await this.multicallToken.balanceOf(multicallTest.address)).to.be.bignumber.equal(new BN(amount)); + + const recipients = [alice, bob]; + const amounts = [amount / 2, amount / 3].map(n => new BN(n)); + + await multicallTest.checkReturnValues(this.multicallToken.address, recipients, amounts); + }); + + it('reverts previous calls', async function () { + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + + const call = this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount).encodeABI(), + ], + { from: deployer }, + ); + + await expectRevertCustomError(call, 'ERC20InsufficientBalance', [deployer, 0, amount]); + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + }); + + it('bubbles up revert reasons', async function () { + const call = this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount).encodeABI(), + ], + { from: deployer }, + ); + + await expectRevertCustomError(call, 'ERC20InsufficientBalance', [deployer, 0, amount]); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Nonces.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Nonces.test.js new file mode 100644 index 0000000..67a3087 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Nonces.test.js @@ -0,0 +1,71 @@ +const expectEvent = require('@openzeppelin/test-helpers/src/expectEvent'); +const { expectRevertCustomError } = require('../helpers/customError'); + +require('@openzeppelin/test-helpers'); + +const Nonces = artifacts.require('$Nonces'); + +contract('Nonces', function (accounts) { + const [sender, other] = accounts; + + beforeEach(async function () { + this.nonces = await Nonces.new(); + }); + + it('gets a nonce', async function () { + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('0'); + }); + + describe('_useNonce', function () { + it('increments a nonce', async function () { + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('0'); + + const { receipt } = await this.nonces.$_useNonce(sender); + expectEvent(receipt, 'return$_useNonce', ['0']); + + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('1'); + }); + + it("increments only sender's nonce", async function () { + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('0'); + expect(await this.nonces.nonces(other)).to.be.bignumber.equal('0'); + + await this.nonces.$_useNonce(sender); + + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('1'); + expect(await this.nonces.nonces(other)).to.be.bignumber.equal('0'); + }); + }); + + describe('_useCheckedNonce', function () { + it('increments a nonce', async function () { + const currentNonce = await this.nonces.nonces(sender); + expect(currentNonce).to.be.bignumber.equal('0'); + + await this.nonces.$_useCheckedNonce(sender, currentNonce); + + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('1'); + }); + + it("increments only sender's nonce", async function () { + const currentNonce = await this.nonces.nonces(sender); + + expect(currentNonce).to.be.bignumber.equal('0'); + expect(await this.nonces.nonces(other)).to.be.bignumber.equal('0'); + + await this.nonces.$_useCheckedNonce(sender, currentNonce); + + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('1'); + expect(await this.nonces.nonces(other)).to.be.bignumber.equal('0'); + }); + + it('reverts when nonce is not the expected', async function () { + const currentNonce = await this.nonces.nonces(sender); + await expectRevertCustomError( + this.nonces.$_useCheckedNonce(sender, currentNonce.addn(1)), + 'InvalidAccountNonce', + [sender, currentNonce], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Pausable.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Pausable.test.js new file mode 100644 index 0000000..e60a62c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Pausable.test.js @@ -0,0 +1,86 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../helpers/customError'); + +const PausableMock = artifacts.require('PausableMock'); + +contract('Pausable', function (accounts) { + const [pauser] = accounts; + + beforeEach(async function () { + this.pausable = await PausableMock.new(); + }); + + context('when unpaused', function () { + beforeEach(async function () { + expect(await this.pausable.paused()).to.equal(false); + }); + + it('can perform normal process in non-pause', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('cannot take drastic measure in non-pause', async function () { + await expectRevertCustomError(this.pausable.drasticMeasure(), 'ExpectedPause', []); + expect(await this.pausable.drasticMeasureTaken()).to.equal(false); + }); + + context('when paused', function () { + beforeEach(async function () { + this.receipt = await this.pausable.pause({ from: pauser }); + }); + + it('emits a Paused event', function () { + expectEvent(this.receipt, 'Paused', { account: pauser }); + }); + + it('cannot perform normal process in pause', async function () { + await expectRevertCustomError(this.pausable.normalProcess(), 'EnforcedPause', []); + }); + + it('can take a drastic measure in a pause', async function () { + await this.pausable.drasticMeasure(); + expect(await this.pausable.drasticMeasureTaken()).to.equal(true); + }); + + it('reverts when re-pausing', async function () { + await expectRevertCustomError(this.pausable.pause(), 'EnforcedPause', []); + }); + + describe('unpausing', function () { + it('is unpausable by the pauser', async function () { + await this.pausable.unpause(); + expect(await this.pausable.paused()).to.equal(false); + }); + + context('when unpaused', function () { + beforeEach(async function () { + this.receipt = await this.pausable.unpause({ from: pauser }); + }); + + it('emits an Unpaused event', function () { + expectEvent(this.receipt, 'Unpaused', { account: pauser }); + }); + + it('should resume allowing normal process', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('should prevent drastic measure', async function () { + await expectRevertCustomError(this.pausable.drasticMeasure(), 'ExpectedPause', []); + }); + + it('reverts when re-unpausing', async function () { + await expectRevertCustomError(this.pausable.unpause(), 'ExpectedPause', []); + }); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/ReentrancyGuard.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/ReentrancyGuard.test.js new file mode 100644 index 0000000..15355c0 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/ReentrancyGuard.test.js @@ -0,0 +1,44 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../helpers/customError'); + +const ReentrancyMock = artifacts.require('ReentrancyMock'); +const ReentrancyAttack = artifacts.require('ReentrancyAttack'); + +contract('ReentrancyGuard', function () { + beforeEach(async function () { + this.reentrancyMock = await ReentrancyMock.new(); + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('0'); + }); + + it('nonReentrant function can be called', async function () { + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('0'); + await this.reentrancyMock.callback(); + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('1'); + }); + + it('does not allow remote callback', async function () { + const attacker = await ReentrancyAttack.new(); + await expectRevert(this.reentrancyMock.countAndCall(attacker.address), 'ReentrancyAttack: failed call', []); + }); + + it('_reentrancyGuardEntered should be true when guarded', async function () { + await this.reentrancyMock.guardedCheckEntered(); + }); + + it('_reentrancyGuardEntered should be false when unguarded', async function () { + await this.reentrancyMock.unguardedCheckNotEntered(); + }); + + // The following are more side-effects than intended behavior: + // I put them here as documentation, and to monitor any changes + // in the side-effects. + it('does not allow local recursion', async function () { + await expectRevertCustomError(this.reentrancyMock.countLocalRecursive(10), 'ReentrancyGuardReentrantCall', []); + }); + + it('does not allow indirect local recursion', async function () { + await expectRevert(this.reentrancyMock.countThisRecursive(10), 'ReentrancyMock: failed call', []); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/ShortStrings.t.sol b/lib/openzeppelin-contracts-v5.0.0/test/utils/ShortStrings.t.sol new file mode 100644 index 0000000..b854d27 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/ShortStrings.t.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {ShortStrings, ShortString} from "@openzeppelin/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; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/ShortStrings.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/ShortStrings.test.js new file mode 100644 index 0000000..189281d --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/ShortStrings.test.js @@ -0,0 +1,55 @@ +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const ShortStrings = artifacts.require('$ShortStrings'); + +function length(sstr) { + return parseInt(sstr.slice(64), 16); +} + +function decode(sstr) { + return web3.utils.toUtf8(sstr).slice(0, length(sstr)); +} + +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.$byteLength(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; + + const promise = this.mock.$toString(ret0); + if (str.length < 32) { + expect(await promise).to.be.equal(str); + } else { + 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); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/StorageSlot.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/StorageSlot.test.js new file mode 100644 index 0000000..846512e --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/StorageSlot.test.js @@ -0,0 +1,210 @@ +const { constants, BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const StorageSlotMock = artifacts.require('StorageSlotMock'); + +const slot = web3.utils.keccak256('some.storage.slot'); +const otherSlot = web3.utils.keccak256('some.other.storage.slot'); + +contract('StorageSlot', function (accounts) { + beforeEach(async function () { + this.store = await StorageSlotMock.new(); + }); + + describe('boolean storage slot', function () { + beforeEach(async function () { + this.value = true; + }); + + it('set', async function () { + await this.store.setBoolean(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBoolean(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBoolean(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBoolean(otherSlot)).to.be.equal(false); + }); + }); + }); + + describe('address storage slot', function () { + beforeEach(async function () { + this.value = accounts[1]; + }); + + it('set', async function () { + await this.store.setAddress(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setAddress(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getAddress(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getAddress(otherSlot)).to.be.equal(constants.ZERO_ADDRESS); + }); + }); + }); + + describe('bytes32 storage slot', function () { + beforeEach(async function () { + this.value = web3.utils.keccak256('some byte32 value'); + }); + + it('set', async function () { + await this.store.setBytes32(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBytes32(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBytes32(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBytes32(otherSlot)).to.be.equal(constants.ZERO_BYTES32); + }); + }); + }); + + describe('uint256 storage slot', function () { + beforeEach(async function () { + this.value = new BN(1742); + }); + + it('set', async function () { + await this.store.setUint256(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setUint256(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getUint256(slot)).to.be.bignumber.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getUint256(otherSlot)).to.be.bignumber.equal('0'); + }); + }); + }); + + 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); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/Strings.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/Strings.test.js new file mode 100644 index 0000000..2435fc7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/Strings.test.js @@ -0,0 +1,153 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { expect } = require('chai'); + +const Strings = artifacts.require('$Strings'); + +contract('Strings', function () { + before(async function () { + this.strings = await Strings.new(); + }); + + describe('toString', function () { + const values = [ + '0', + '7', + '10', + '99', + '100', + '101', + '123', + '4132', + '12345', + '1234567', + '1234567890', + '123456789012345', + '12345678901234567890', + '123456789012345678901234567890', + '1234567890123456789012345678901234567890', + '12345678901234567890123456789012345678901234567890', + '123456789012345678901234567890123456789012345678901234567890', + '1234567890123456789012345678901234567890123456789012345678901234567890', + ]; + + describe('uint256', function () { + it('converts MAX_UINT256', async function () { + const value = constants.MAX_UINT256; + expect(await this.strings.methods['$toString(uint256)'](value)).to.equal(value.toString(10)); + }); + + for (const value of values) { + it(`converts ${value}`, async function () { + expect(await this.strings.methods['$toString(uint256)'](value)).to.equal(value); + }); + } + }); + + describe('int256', function () { + it('converts MAX_INT256', async function () { + const value = constants.MAX_INT256; + expect(await this.strings.methods['$toStringSigned(int256)'](value)).to.equal(value.toString(10)); + }); + + it('converts MIN_INT256', async function () { + const value = constants.MIN_INT256; + expect(await this.strings.methods['$toStringSigned(int256)'](value)).to.equal(value.toString(10)); + }); + + for (const value of values) { + it(`convert ${value}`, async function () { + expect(await this.strings.methods['$toStringSigned(int256)'](value)).to.equal(value); + }); + + it(`convert negative ${value}`, async function () { + const negated = new BN(value).neg(); + expect(await this.strings.methods['$toStringSigned(int256)'](negated)).to.equal(negated.toString(10)); + }); + } + }); + }); + + describe('toHexString', function () { + it('converts 0', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](0)).to.equal('0x00'); + }); + + it('converts a positive number', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](0x4132)).to.equal('0x4132'); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](constants.MAX_UINT256)).to.equal( + web3.utils.toHex(constants.MAX_UINT256), + ); + }); + }); + + describe('toHexString fixed', function () { + it('converts a positive number (long)', async function () { + expect(await this.strings.methods['$toHexString(uint256,uint256)'](0x4132, 32)).to.equal( + '0x0000000000000000000000000000000000000000000000000000000000004132', + ); + }); + + it('converts a positive number (short)', async function () { + const length = 1; + await expectRevertCustomError( + this.strings.methods['$toHexString(uint256,uint256)'](0x4132, length), + `StringsInsufficientHexLength`, + [0x4132, length], + ); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.strings.methods['$toHexString(uint256,uint256)'](constants.MAX_UINT256, 32)).to.equal( + web3.utils.toHex(constants.MAX_UINT256), + ); + }); + }); + + describe('toHexString address', function () { + it('converts a random address', async function () { + const addr = '0xa9036907dccae6a1e0033479b12e837e5cf5a02f'; + expect(await this.strings.methods['$toHexString(address)'](addr)).to.equal(addr); + }); + + it('converts an address with leading zeros', async function () { + const addr = '0x0000e0ca771e21bd00057f54a68c30d400000000'; + expect(await this.strings.methods['$toHexString(address)'](addr)).to.equal(addr); + }); + }); + + describe('equal', function () { + it('compares two empty strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('', '')).to.equal(true); + }); + + it('compares two equal strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'a')).to.equal(true); + }); + + it('compares two different strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'b')).to.equal(false); + }); + + it('compares two different strings of different lengths', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'aa')).to.equal(false); + expect(await this.strings.methods['$equal(string,string)']('aa', 'a')).to.equal(false); + }); + + it('compares two different large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(200) + 'b'; + expect(await this.strings.methods['$equal(string,string)'](str1, str2)).to.equal(false); + }); + + it('compares two equal large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(201); + expect(await this.strings.methods['$equal(string,string)'](str1, str2)).to.equal(true); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/ECDSA.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/ECDSA.test.js new file mode 100644 index 0000000..f164ef1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/ECDSA.test.js @@ -0,0 +1,245 @@ +require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { toEthSignedMessageHash } = require('../../helpers/sign'); + +const { expect } = require('chai'); + +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'); + +function to2098Format(signature) { + const long = web3.utils.hexToBytes(signature); + if (long.length !== 65) { + throw new Error('invalid signature length (expected long format)'); + } + if (long[32] >> 7 === 1) { + throw new Error("invalid signature 's' value"); + } + const short = long.slice(0, 64); + short[32] |= long[64] % 27 << 7; // set the first bit of the 32nd byte to the v parity bit + return web3.utils.bytesToHex(short); +} + +function split(signature) { + const raw = web3.utils.hexToBytes(signature); + switch (raw.length) { + case 64: + return [ + web3.utils.bytesToHex(raw.slice(0, 32)), // r + web3.utils.bytesToHex(raw.slice(32, 64)), // vs + ]; + case 65: + return [ + raw[64], // v + web3.utils.bytesToHex(raw.slice(0, 32)), // r + web3.utils.bytesToHex(raw.slice(32, 64)), // s + ]; + default: + expect.fail('Invalid signature length, cannot split'); + } +} + +contract('ECDSA', function (accounts) { + const [other] = accounts; + + beforeEach(async function () { + this.ecdsa = await ECDSA.new(); + }); + + context('recover with invalid signature', function () { + it('with short signature', async function () { + await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, '0x1234'), 'ECDSAInvalidSignatureLength', [2]); + }); + + it('with long signature', async function () { + await expectRevertCustomError( + // eslint-disable-next-line max-len + this.ecdsa.$recover( + TEST_MESSAGE, + '0x01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789', + ), + 'ECDSAInvalidSignatureLength', + [85], + ); + }); + }); + + context('recover with valid signature', function () { + context('using web3.eth.sign', function () { + it('returns signer address with correct signature', async function () { + // Create the signature + const signature = await web3.eth.sign(TEST_MESSAGE, other); + + // Recover the signer address from the generated message and signature. + expect(await this.ecdsa.$recover(toEthSignedMessageHash(TEST_MESSAGE), signature)).to.equal(other); + }); + + it('returns signer address with correct signature for arbitrary length message', async function () { + // Create the signature + const signature = await web3.eth.sign(NON_HASH_MESSAGE, other); + + // Recover the signer address from the generated message and signature. + expect(await this.ecdsa.$recover(toEthSignedMessageHash(NON_HASH_MESSAGE), signature)).to.equal(other); + }); + + it('returns a different address', async function () { + const signature = await web3.eth.sign(TEST_MESSAGE, other); + expect(await this.ecdsa.$recover(WRONG_MESSAGE, signature)).to.not.equal(other); + }); + + it('reverts with invalid signature', async function () { + // eslint-disable-next-line max-len + const signature = + '0x332ce75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e01c'; + await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []); + }); + }); + + context('with v=27 signature', function () { + // Signature generated outside ganache with method web3.eth.sign(signer, message) + const signer = '0x2cc1166f6212628A0deEf2B33BEFB2187D35b86c'; + // eslint-disable-next-line max-len + const signatureWithoutV = + '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892'; + + it('works with correct v value', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '1c'; // 28 = 1c. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.not.equal(signer); + }); + + it('reverts wrong v values', async function () { + for (const v of ['00', '01']) { + const signature = signatureWithoutV + v; + await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []); + + await expectRevertCustomError( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + 'ECDSAInvalidSignature', + [], + ); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + await expectRevertCustomError( + this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)), + 'ECDSAInvalidSignatureLength', + [64], + ); + }); + }); + + context('with v=28 signature', function () { + const signer = '0x1E318623aB09Fe6de3C9b8672098464Aeda9100E'; + // eslint-disable-next-line max-len + const signatureWithoutV = + '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0'; + + it('works with correct v value', async function () { + const v = '1c'; // 28 = 1c. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.not.equal(signer); + }); + + it('reverts invalid v values', async function () { + for (const v of ['00', '01']) { + const signature = signatureWithoutV + v; + await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []); + + await expectRevertCustomError( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + 'ECDSAInvalidSignature', + [], + ); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '1c'; // 27 = 1b. + const signature = signatureWithoutV + v; + await expectRevertCustomError( + this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)), + 'ECDSAInvalidSignatureLength', + [64], + ); + }); + }); + + it('reverts with high-s value signature', async function () { + const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'; + // eslint-disable-next-line max-len + const highSSignature = + '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b'; + const [r, v, s] = split(highSSignature); + await expectRevertCustomError(this.ecdsa.$recover(message, highSSignature), 'ECDSAInvalidSignatureS', [s]); + await expectRevertCustomError( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, r, v, s), + 'ECDSAInvalidSignatureS', + [s], + ); + expect(() => to2098Format(highSSignature)).to.throw("invalid signature 's' value"); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/EIP712.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/EIP712.test.js new file mode 100644 index 0000000..faf01f1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/EIP712.test.js @@ -0,0 +1,111 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { getDomain, domainType, domainSeparator, hashTypedData } = require('../../helpers/eip712'); +const { getChainId } = require('../../helpers/chainid'); +const { mapValues } = require('../../helpers/iterate'); + +const EIP712Verifier = artifacts.require('$EIP712Verifier'); +const Clones = artifacts.require('$Clones'); + +contract('EIP712', function (accounts) { + const [mailTo] = accounts; + + const shortName = 'A Name'; + const shortVersion = '1'; + + const longName = 'A'.repeat(40); + const longVersion = 'B'.repeat(40); + + const cases = [ + ['short', shortName, shortVersion], + ['long', longName, longVersion], + ]; + + 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); + + 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 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 () { + 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('name', async function () { + expect(await this.eip712.$_EIP712Name()).to.be.equal(name); + }); + + it('version', async function () { + expect(await this.eip712.$_EIP712Version()).to.be.equal(version); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/MerkleProof.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/MerkleProof.test.js new file mode 100644 index 0000000..5b87bc5 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/MerkleProof.test.js @@ -0,0 +1,207 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { MerkleTree } = require('merkletreejs'); +const keccak256 = require('keccak256'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const MerkleProof = artifacts.require('$MerkleProof'); + +contract('MerkleProof', function () { + beforeEach(async function () { + this.merkleProof = await MerkleProof.new(); + }); + + describe('verify', function () { + it('returns true for a valid Merkle proof', async function () { + const elements = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''); + const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true }); + + const root = merkleTree.getHexRoot(); + + const leaf = keccak256(elements[0]); + + const proof = merkleTree.getHexProof(leaf); + + expect(await this.merkleProof.$verify(proof, root, leaf)).to.equal(true); + expect(await this.merkleProof.$verifyCalldata(proof, root, leaf)).to.equal(true); + + // For demonstration, it is also possible to create valid proofs for certain 64-byte values *not* in elements: + const noSuchLeaf = keccak256( + Buffer.concat([keccak256(elements[0]), keccak256(elements[1])].sort(Buffer.compare)), + ); + expect(await this.merkleProof.$verify(proof.slice(1), root, noSuchLeaf)).to.equal(true); + expect(await this.merkleProof.$verifyCalldata(proof.slice(1), root, noSuchLeaf)).to.equal(true); + }); + + it('returns false for an invalid Merkle proof', async function () { + const correctElements = ['a', 'b', 'c']; + const correctMerkleTree = new MerkleTree(correctElements, keccak256, { hashLeaves: true, sortPairs: true }); + + const correctRoot = correctMerkleTree.getHexRoot(); + + const correctLeaf = keccak256(correctElements[0]); + + const badElements = ['d', 'e', 'f']; + const badMerkleTree = new MerkleTree(badElements); + + const badProof = badMerkleTree.getHexProof(badElements[0]); + + expect(await this.merkleProof.$verify(badProof, correctRoot, correctLeaf)).to.equal(false); + expect(await this.merkleProof.$verifyCalldata(badProof, correctRoot, correctLeaf)).to.equal(false); + }); + + it('returns false for a Merkle proof of invalid length', async function () { + const elements = ['a', 'b', 'c']; + const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true }); + + const root = merkleTree.getHexRoot(); + + const leaf = keccak256(elements[0]); + + const proof = merkleTree.getHexProof(leaf); + const badProof = proof.slice(0, proof.length - 5); + + expect(await this.merkleProof.$verify(badProof, root, leaf)).to.equal(false); + expect(await this.merkleProof.$verifyCalldata(badProof, root, leaf)).to.equal(false); + }); + }); + + describe('multiProofVerify', function () { + it('returns true for a valid Merkle multi proof', async function () { + const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const proofLeaves = ['b', 'f', 'd'].map(keccak256).sort(Buffer.compare); + const proof = merkleTree.getMultiProof(proofLeaves); + const proofFlags = merkleTree.getProofFlags(proofLeaves, proof); + + expect(await this.merkleProof.$multiProofVerify(proof, proofFlags, root, proofLeaves)).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata(proof, proofFlags, root, proofLeaves)).to.equal(true); + }); + + it('returns false for an invalid Merkle multi proof', async function () { + const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const badProofLeaves = ['g', 'h', 'i'].map(keccak256).sort(Buffer.compare); + const badMerkleTree = new MerkleTree(badProofLeaves); + const badProof = badMerkleTree.getMultiProof(badProofLeaves); + const badProofFlags = badMerkleTree.getProofFlags(badProofLeaves, badProof); + + expect(await this.merkleProof.$multiProofVerify(badProof, badProofFlags, root, badProofLeaves)).to.equal(false); + expect(await this.merkleProof.$multiProofVerifyCalldata(badProof, badProofFlags, root, badProofLeaves)).to.equal( + false, + ); + }); + + it('revert with invalid multi proof #1', async function () { + const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const badLeaf = keccak256('e'); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + + await expectRevertCustomError( + this.merkleProof.$multiProofVerify( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false], + root, + [leaves[0], badLeaf], // A, E + ), + 'MerkleProofInvalidMultiproof', + [], + ); + await expectRevertCustomError( + this.merkleProof.$multiProofVerifyCalldata( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false], + root, + [leaves[0], badLeaf], // A, E + ), + 'MerkleProofInvalidMultiproof', + [], + ); + }); + + it('revert with invalid multi proof #2', async function () { + const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const badLeaf = keccak256('e'); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + + await expectRevert( + this.merkleProof.$multiProofVerify( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false, false], + root, + [badLeaf, leaves[0]], // A, E + ), + 'reverted with panic code 0x32', + ); + + await expectRevert( + this.merkleProof.$multiProofVerifyCalldata( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false, false], + root, + [badLeaf, leaves[0]], // A, E + ), + 'reverted with panic code 0x32', + ); + }); + + it('limit case: works for tree containing a single leaf', async function () { + const leaves = ['a'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const proofLeaves = ['a'].map(keccak256).sort(Buffer.compare); + const proof = merkleTree.getMultiProof(proofLeaves); + const proofFlags = merkleTree.getProofFlags(proofLeaves, proof); + + expect(await this.merkleProof.$multiProofVerify(proof, proofFlags, root, proofLeaves)).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata(proof, proofFlags, root, proofLeaves)).to.equal(true); + }); + + it('limit case: can prove empty leaves', async function () { + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + expect(await this.merkleProof.$multiProofVerify([root], [], root, [])).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata([root], [], root, [])).to.equal(true); + }); + + it('reverts processing manipulated proofs with a zero-value node at depth 1', async function () { + // Create a merkle tree that contains a zero leaf at depth 1 + const leaves = [keccak256('real leaf'), Buffer.alloc(32, 0)]; + const merkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true }); + + const root = merkleTree.getRoot(); + + // Now we can pass any **malicious** fake leaves as valid! + const maliciousLeaves = ['malicious', 'leaves'].map(keccak256).sort(Buffer.compare); + const maliciousProof = [leaves[0], leaves[0]]; + const maliciousProofFlags = [true, true, false]; + + await expectRevertCustomError( + this.merkleProof.$multiProofVerify(maliciousProof, maliciousProofFlags, root, maliciousLeaves), + 'MerkleProofInvalidMultiproof', + [], + ); + + await expectRevertCustomError( + this.merkleProof.$multiProofVerifyCalldata(maliciousProof, maliciousProofFlags, root, maliciousLeaves), + 'MerkleProofInvalidMultiproof', + [], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/MessageHashUtils.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/MessageHashUtils.test.js new file mode 100644 index 0000000..b38e945 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/MessageHashUtils.test.js @@ -0,0 +1,55 @@ +require('@openzeppelin/test-helpers'); +const { toEthSignedMessageHash, toDataWithIntendedValidatorHash } = require('../../helpers/sign'); +const { domainSeparator, hashTypedData } = require('../../helpers/eip712'); + +const { expect } = require('chai'); + +const MessageHashUtils = artifacts.require('$MessageHashUtils'); + +contract('MessageHashUtils', function () { + beforeEach(async function () { + this.messageHashUtils = await MessageHashUtils.new(); + + this.message = '0x' + Buffer.from('abcd').toString('hex'); + this.messageHash = web3.utils.sha3(this.message); + this.verifyingAddress = web3.utils.toChecksumAddress(web3.utils.randomHex(20)); + }); + + context('toEthSignedMessageHash', function () { + it('prefixes bytes32 data correctly', async function () { + expect(await this.messageHashUtils.methods['$toEthSignedMessageHash(bytes32)'](this.messageHash)).to.equal( + toEthSignedMessageHash(this.messageHash), + ); + }); + + it('prefixes dynamic length data correctly', async function () { + expect(await this.messageHashUtils.methods['$toEthSignedMessageHash(bytes)'](this.message)).to.equal( + toEthSignedMessageHash(this.message), + ); + }); + }); + + context('toDataWithIntendedValidatorHash', function () { + it('returns the digest correctly', async function () { + expect( + await this.messageHashUtils.$toDataWithIntendedValidatorHash(this.verifyingAddress, this.message), + ).to.equal(toDataWithIntendedValidatorHash(this.verifyingAddress, this.message)); + }); + }); + + context('toTypedDataHash', function () { + it('returns the digest correctly', async function () { + const domain = { + name: 'Test', + version: 1, + chainId: 1, + verifyingContract: this.verifyingAddress, + }; + const structhash = web3.utils.randomHex(32); + const expectedDomainSeparator = await domainSeparator(domain); + expect(await this.messageHashUtils.$toTypedDataHash(expectedDomainSeparator, structhash)).to.equal( + hashTypedData(domain, structhash), + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/SignatureChecker.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/SignatureChecker.test.js new file mode 100644 index 0000000..ba8b100 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/cryptography/SignatureChecker.test.js @@ -0,0 +1,87 @@ +const { toEthSignedMessageHash } = require('../../helpers/sign'); + +const { expect } = require('chai'); + +const SignatureChecker = artifacts.require('$SignatureChecker'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); +const ERC1271MaliciousMock = artifacts.require('ERC1271MaliciousMock'); + +const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin'); +const WRONG_MESSAGE = web3.utils.sha3('Nope'); + +contract('SignatureChecker (ERC1271)', function (accounts) { + const [signer, other] = accounts; + + before('deploying', async function () { + this.signaturechecker = await SignatureChecker.new(); + this.wallet = await ERC1271WalletMock.new(signer); + this.malicious = await ERC1271MaliciousMock.new(); + this.signature = await web3.eth.sign(TEST_MESSAGE, signer); + }); + + context('EOA account', function () { + it('with matching signer and signature', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(TEST_MESSAGE), this.signature), + ).to.equal(true); + }); + + it('with invalid signer', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(other, toEthSignedMessageHash(TEST_MESSAGE), this.signature), + ).to.equal(false); + }); + + it('with invalid signature', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(WRONG_MESSAGE), this.signature), + ).to.equal(false); + }); + }); + + context('ERC1271 wallet', function () { + 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[`$${signature}`]( + this.signaturechecker.address, + toEthSignedMessageHash(TEST_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[`$${signature}`]( + this.malicious.address, + toEthSignedMessageHash(TEST_MESSAGE), + this.signature, + ), + ).to.equal(false); + }); + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/ERC165.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/ERC165.test.js new file mode 100644 index 0000000..6d531c1 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/ERC165.test.js @@ -0,0 +1,11 @@ +const { shouldSupportInterfaces } = require('./SupportsInterface.behavior'); + +const ERC165 = artifacts.require('$ERC165'); + +contract('ERC165', function () { + beforeEach(async function () { + this.mock = await ERC165.new(); + }); + + shouldSupportInterfaces(['ERC165']); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/ERC165Checker.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/ERC165Checker.test.js new file mode 100644 index 0000000..caa2201 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/ERC165Checker.test.js @@ -0,0 +1,300 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC165Checker = artifacts.require('$ERC165Checker'); +const ERC165MissingData = artifacts.require('ERC165MissingData'); +const ERC165MaliciousData = artifacts.require('ERC165MaliciousData'); +const ERC165NotSupported = artifacts.require('ERC165NotSupported'); +const ERC165InterfacesSupported = artifacts.require('ERC165InterfacesSupported'); +const ERC165ReturnBombMock = artifacts.require('ERC165ReturnBombMock'); + +const DUMMY_ID = '0xdeadbeef'; +const DUMMY_ID_2 = '0xcafebabe'; +const DUMMY_ID_3 = '0xdecafbad'; +const DUMMY_UNSUPPORTED_ID = '0xbaddcafe'; +const DUMMY_UNSUPPORTED_ID_2 = '0xbaadcafe'; +const DUMMY_ACCOUNT = '0x1111111111111111111111111111111111111111'; + +contract('ERC165Checker', function () { + beforeEach(async function () { + this.mock = await ERC165Checker.new(); + }); + + context('ERC165 missing return data', function () { + beforeEach(async function () { + this.target = await ERC165MissingData.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 malicious return data', function () { + beforeEach(async function () { + this.target = await ERC165MaliciousData.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + }); + + context('ERC165 not supported', function () { + beforeEach(async function () { + this.target = await ERC165NotSupported.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 supported', function () { + beforeEach(async function () { + this.target = await ERC165InterfacesSupported.new([]); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 and single interface supported', function () { + beforeEach(async function () { + this.target = await ERC165InterfacesSupported.new([DUMMY_ID]); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('supports mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + + it('supports mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(true); + }); + + it('supports mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(true); + }); + + it('supports mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + }); + + context('ERC165 and many interfaces supported', function () { + beforeEach(async function () { + this.supportedInterfaces = [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3]; + this.target = await ERC165InterfacesSupported.new(this.supportedInterfaces); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('supports each interfaceId via supportsInterface', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.$supportsInterface(this.target.address, interfaceId); + expect(supported).to.equal(true); + } + }); + + it('supports all interfaceIds via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, this.supportedInterfaces); + expect(supported).to.equal(true); + }); + + it('supports none of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + const supported = await this.mock.$supportsAllInterfaces(this.target.address, interfaceIdsToTest); + expect(supported).to.equal(false); + }); + + it('supports not all of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + const supported = await this.mock.$supportsAllInterfaces(this.target.address, interfaceIdsToTest); + expect(supported).to.equal(false); + }); + + it('supports all interfaceIds via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, this.supportedInterfaces); + expect(supported.length).to.equal(3); + expect(supported[0]).to.equal(true); + expect(supported[1]).to.equal(true); + expect(supported[2]).to.equal(true); + }); + + it('supports none of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + const supported = await this.mock.$getSupportedInterfaces(this.target.address, interfaceIdsToTest); + expect(supported.length).to.equal(2); + expect(supported[0]).to.equal(false); + expect(supported[1]).to.equal(false); + }); + + it('supports not all of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + const supported = await this.mock.$getSupportedInterfaces(this.target.address, interfaceIdsToTest); + expect(supported.length).to.equal(4); + expect(supported[0]).to.equal(true); + expect(supported[1]).to.equal(true); + expect(supported[2]).to.equal(true); + expect(supported[3]).to.equal(false); + }); + + it('supports each interfaceId via supportsERC165InterfaceUnchecked', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, interfaceId); + expect(supported).to.equal(true); + } + }); + }); + + context('account address does not support ERC165', function () { + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(DUMMY_ACCOUNT); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + it('Return bomb resistance', async function () { + this.target = await ERC165ReturnBombMock.new(); + + const tx1 = await this.mock.$supportsInterface.sendTransaction(this.target.address, DUMMY_ID); + expect(tx1.receipt.gasUsed).to.be.lessThan(120000); // 3*30k + 21k + some margin + + const tx2 = await this.mock.$getSupportedInterfaces.sendTransaction(this.target.address, [ + DUMMY_ID, + DUMMY_ID_2, + DUMMY_ID_3, + DUMMY_UNSUPPORTED_ID, + DUMMY_UNSUPPORTED_ID_2, + ]); + expect(tx2.receipt.gasUsed).to.be.lessThan(250000); // (2+5)*30k + 21k + some margin + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/SupportsInterface.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/SupportsInterface.behavior.js new file mode 100644 index 0000000..49a30e7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/introspection/SupportsInterface.behavior.js @@ -0,0 +1,144 @@ +const { makeInterfaceId } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const INVALID_ID = '0xffffffff'; +const INTERFACES = { + ERC165: ['supportsInterface(bytes4)'], + ERC721: [ + 'balanceOf(address)', + 'ownerOf(uint256)', + 'approve(address,uint256)', + 'getApproved(uint256)', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'transferFrom(address,address,uint256)', + 'safeTransferFrom(address,address,uint256)', + 'safeTransferFrom(address,address,uint256,bytes)', + ], + ERC721Enumerable: ['totalSupply()', 'tokenOfOwnerByIndex(address,uint256)', 'tokenByIndex(uint256)'], + ERC721Metadata: ['name()', 'symbol()', 'tokenURI(uint256)'], + ERC1155: [ + 'balanceOf(address,uint256)', + 'balanceOfBatch(address[],uint256[])', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'safeTransferFrom(address,address,uint256,uint256,bytes)', + 'safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)', + ], + ERC1155Receiver: [ + 'onERC1155Received(address,address,uint256,uint256,bytes)', + 'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)', + ], + AccessControl: [ + 'hasRole(bytes32,address)', + 'getRoleAdmin(bytes32)', + 'grantRole(bytes32,address)', + 'revokeRole(bytes32,address)', + 'renounceRole(bytes32,address)', + ], + AccessControlEnumerable: ['getRoleMember(bytes32,uint256)', 'getRoleMemberCount(bytes32)'], + AccessControlDefaultAdminRules: [ + 'defaultAdminDelay()', + 'pendingDefaultAdminDelay()', + 'defaultAdmin()', + 'pendingDefaultAdmin()', + 'defaultAdminDelayIncreaseWait()', + 'changeDefaultAdminDelay(uint48)', + 'rollbackDefaultAdminDelay()', + 'beginDefaultAdminTransfer(address)', + 'acceptDefaultAdminTransfer()', + 'cancelDefaultAdminTransfer()', + ], + Governor: [ + 'name()', + 'version()', + 'COUNTING_MODE()', + 'hashProposal(address[],uint256[],bytes[],bytes32)', + 'state(uint256)', + 'proposalThreshold()', + 'proposalSnapshot(uint256)', + 'proposalDeadline(uint256)', + 'proposalProposer(uint256)', + 'proposalEta(uint256)', + 'proposalNeedsQueuing(uint256)', + 'votingDelay()', + 'votingPeriod()', + 'quorum(uint256)', + 'getVotes(address,uint256)', + 'getVotesWithParams(address,uint256,bytes)', + 'hasVoted(uint256,address)', + 'propose(address[],uint256[],bytes[],string)', + 'queue(address[],uint256[],bytes[],bytes32)', + 'execute(address[],uint256[],bytes[],bytes32)', + 'cancel(address[],uint256[],bytes[],bytes32)', + 'castVote(uint256,uint8)', + 'castVoteWithReason(uint256,uint8,string)', + 'castVoteWithReasonAndParams(uint256,uint8,string,bytes)', + 'castVoteBySig(uint256,uint8,address,bytes)', + 'castVoteWithReasonAndParamsBySig(uint256,uint8,address,string,bytes,bytes)', + ], + ERC2981: ['royaltyInfo(uint256,uint256)'], +}; + +const INTERFACE_IDS = {}; +const FN_SIGNATURES = {}; +for (const k of Object.getOwnPropertyNames(INTERFACES)) { + INTERFACE_IDS[k] = makeInterfaceId.ERC165(INTERFACES[k]); + for (const fnName of INTERFACES[k]) { + // the interface id of a single function is equivalent to its function signature + FN_SIGNATURES[fnName] = makeInterfaceId.ERC165([fnName]); + } +} + +function shouldSupportInterfaces(interfaces = []) { + describe('ERC165', function () { + beforeEach(function () { + this.contractUnderTest = this.mock || this.token || this.holder || this.accessControl; + }); + + describe('when the interfaceId is supported', function () { + it('uses less than 30k gas', async function () { + for (const k of interfaces) { + const interfaceId = INTERFACE_IDS[k] ?? k; + expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.be.lte(30000); + } + }); + + it('returns true', async function () { + for (const k of interfaces) { + const interfaceId = INTERFACE_IDS[k] ?? k; + expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true, `does not support ${k}`); + } + }); + }); + + describe('when the interfaceId is not supported', function () { + it('uses less thank 30k', async function () { + expect(await this.contractUnderTest.supportsInterface.estimateGas(INVALID_ID)).to.be.lte(30000); + }); + + it('returns false', async function () { + expect(await this.contractUnderTest.supportsInterface(INVALID_ID)).to.be.equal(false, `supports ${INVALID_ID}`); + }); + }); + + 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, + `did not find ${fnName}`, + ); + } + } + }); + }); +} + +module.exports = { + shouldSupportInterfaces, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/math/Math.t.sol b/lib/openzeppelin-contracts-v5.0.0/test/utils/math/Math.t.sol new file mode 100644 index 0000000..0b497a8 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/math/Math.t.sol @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; + +contract MathTest is Test { + // CEILDIV + function testCeilDiv(uint256 a, uint256 b) public { + vm.assume(b > 0); + + uint256 result = Math.ceilDiv(a, b); + + if (result == 0) { + assertEq(a, 0); + } else { + uint256 maxdiv = UINT256_MAX / b; + bool overflow = maxdiv * b < a; + assertTrue(a > b * (result - 1)); + assertTrue(overflow ? result == maxdiv + 1 : a <= b * result); + } + } + + // SQRT + function testSqrt(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.sqrt(input, rounding); + + // square of result is bigger than input + if (_squareBigger(result, input)) { + assertTrue(Math.unsignedRoundsUp(rounding)); + assertTrue(_squareSmaller(result - 1, input)); + } + // square of result is smaller than input + else if (_squareSmaller(result, input)) { + assertFalse(Math.unsignedRoundsUp(rounding)); + assertTrue(_squareBigger(result + 1, input)); + } + // input is perfect square + else { + assertEq(result * result, input); + } + } + + function _squareBigger(uint256 value, uint256 ref) private pure returns (bool) { + (bool noOverflow, uint256 square) = Math.tryMul(value, value); + return !noOverflow || square > ref; + } + + function _squareSmaller(uint256 value, uint256 ref) private pure returns (bool) { + return value * value < ref; + } + + // LOG2 + function testLog2(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log2(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf2Bigger(result, input)) { + assertTrue(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf2Smaller(result - 1, input)); + } else if (_powerOf2Smaller(result, input)) { + assertFalse(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf2Bigger(result + 1, input)); + } else { + assertEq(2 ** result, input); + } + } + + function _powerOf2Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 256 || 2 ** value > ref; // 2**256 overflows uint256 + } + + function _powerOf2Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 2 ** value < ref; + } + + // LOG10 + function testLog10(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log10(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf10Bigger(result, input)) { + assertTrue(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf10Smaller(result - 1, input)); + } else if (_powerOf10Smaller(result, input)) { + assertFalse(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf10Bigger(result + 1, input)); + } else { + assertEq(10 ** result, input); + } + } + + function _powerOf10Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 78 || 10 ** value > ref; // 10**78 overflows uint256 + } + + function _powerOf10Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 10 ** value < ref; + } + + // LOG256 + function testLog256(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log256(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf256Bigger(result, input)) { + assertTrue(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf256Smaller(result - 1, input)); + } else if (_powerOf256Smaller(result, input)) { + assertFalse(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf256Bigger(result + 1, input)); + } else { + assertEq(256 ** result, input); + } + } + + function _powerOf256Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 32 || 256 ** value > ref; // 256**32 overflows uint256 + } + + function _powerOf256Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 256 ** value < ref; + } + + // MULDIV + function testMulDiv(uint256 x, uint256 y, uint256 d) public { + // Full precision for x * y + (uint256 xyHi, uint256 xyLo) = _mulHighLow(x, y); + + // Assume result won't overflow (see {testMulDivDomain}) + // This also checks that `d` is positive + vm.assume(xyHi < d); + + // Perform muldiv + uint256 q = Math.mulDiv(x, y, d); + + // Full precision for q * d + (uint256 qdHi, uint256 qdLo) = _mulHighLow(q, d); + // Add remainder of x * y / d (computed as rem = (x * y % d)) + (uint256 qdRemLo, uint256 c) = _addCarry(qdLo, _mulmod(x, y, d)); + uint256 qdRemHi = qdHi + c; + + // Full precision check that x * y = q * d + rem + assertEq(xyHi, qdRemHi); + assertEq(xyLo, qdRemLo); + } + + function testMulDivDomain(uint256 x, uint256 y, uint256 d) public { + (uint256 xyHi, ) = _mulHighLow(x, y); + + // Violate {testMulDiv} assumption (covers d is 0 and result overflow) + vm.assume(xyHi >= d); + + // we are outside the scope of {testMulDiv}, we expect muldiv to revert + try this.muldiv(x, y, d) returns (uint256) { + fail(); + } catch {} + } + + // External call + function muldiv(uint256 x, uint256 y, uint256 d) external pure returns (uint256) { + return Math.mulDiv(x, y, d); + } + + // Helpers + function _asRounding(uint8 r) private pure returns (Math.Rounding) { + vm.assume(r < uint8(type(Math.Rounding).max)); + return Math.Rounding(r); + } + + function _mulmod(uint256 x, uint256 y, uint256 z) private pure returns (uint256 r) { + assembly { + r := mulmod(x, y, z) + } + } + + function _mulHighLow(uint256 x, uint256 y) private pure returns (uint256 high, uint256 low) { + (uint256 x0, uint256 x1) = (x & type(uint128).max, x >> 128); + (uint256 y0, uint256 y1) = (y & type(uint128).max, y >> 128); + + // Karatsuba algorithm + // https://en.wikipedia.org/wiki/Karatsuba_algorithm + uint256 z2 = x1 * y1; + uint256 z1a = x1 * y0; + uint256 z1b = x0 * y1; + uint256 z0 = x0 * y0; + + uint256 carry = ((z1a & type(uint128).max) + (z1b & type(uint128).max) + (z0 >> 128)) >> 128; + + high = z2 + (z1a >> 128) + (z1b >> 128) + carry; + + unchecked { + low = x * y; + } + } + + function _addCarry(uint256 x, uint256 y) private pure returns (uint256 res, uint256 carry) { + unchecked { + res = x + y; + } + carry = res < x ? 1 : 0; + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/math/Math.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/math/Math.test.js new file mode 100644 index 0000000..7d4a58c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/math/Math.test.js @@ -0,0 +1,469 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256 } = constants; +const { Rounding } = require('../../helpers/enums.js'); +const { expectRevertCustomError } = require('../../helpers/customError.js'); + +const Math = artifacts.require('$Math'); + +const RoundingDown = [Rounding.Floor, Rounding.Trunc]; +const RoundingUp = [Rounding.Ceil, Rounding.Expand]; + +function expectStruct(value, expected) { + for (const key in expected) { + if (BN.isBN(value[key])) { + expect(value[key]).to.be.bignumber.equal(expected[key]); + } else { + expect(value[key]).to.be.equal(expected[key]); + } + } +} + +async function testCommutativeIterable(fn, lhs, rhs, expected, ...extra) { + expectStruct(await fn(lhs, rhs, ...extra), expected); + expectStruct(await fn(rhs, lhs, ...extra), expected); +} + +contract('Math', function () { + const min = new BN('1234'); + const max = new BN('5678'); + const MAX_UINT256_SUB1 = MAX_UINT256.sub(new BN('1')); + const MAX_UINT256_SUB2 = MAX_UINT256.sub(new BN('2')); + + beforeEach(async function () { + this.math = await Math.new(); + }); + + describe('tryAdd', function () { + it('adds correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + await testCommutativeIterable(this.math.$tryAdd, a, b, [true, a.add(b)]); + }); + + it('reverts on addition overflow', async function () { + const a = MAX_UINT256; + const b = new BN('1'); + + await testCommutativeIterable(this.math.$tryAdd, a, b, [false, '0']); + }); + }); + + describe('trySub', function () { + it('subtracts correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + expectStruct(await this.math.$trySub(a, b), [true, a.sub(b)]); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + expectStruct(await this.math.$trySub(a, b), [false, '0']); + }); + }); + + describe('tryMul', function () { + it('multiplies correctly', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await testCommutativeIterable(this.math.$tryMul, a, b, [true, a.mul(b)]); + }); + + it('multiplies by zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + await testCommutativeIterable(this.math.$tryMul, a, b, [true, a.mul(b)]); + }); + + it('reverts on multiplication overflow', async function () { + const a = MAX_UINT256; + const b = new BN('2'); + + await testCommutativeIterable(this.math.$tryMul, a, b, [false, '0']); + }); + }); + + describe('tryDiv', function () { + it('divides correctly', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('reverts on division by zero', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + expectStruct(await this.math.$tryDiv(a, b), [false, '0']); + }); + }); + + describe('tryMod', function () { + describe('modulos correctly', async function () { + it('when the dividend is smaller than the divisor', async function () { + const a = new BN('284'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = new BN('17034'); // 17034 == 5678 * 3 + const b = new BN('5678'); + + expectStruct(await this.math.$tryMod(a, b), [true, a.mod(b)]); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + expectStruct(await this.math.$tryMod(a, b), [false, '0']); + }); + }); + + describe('max', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$max(max, min)).to.be.bignumber.equal(max); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$max(min, max)).to.be.bignumber.equal(max); + }); + }); + + describe('min', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$min(min, max)).to.be.bignumber.equal(min); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$min(max, min)).to.be.bignumber.equal(min); + }); + }); + + describe('average', function () { + function bnAverage(a, b) { + return a.add(b).divn(2); + } + + it('is correctly calculated with two odd numbers', async function () { + const a = new BN('57417'); + const b = new BN('95431'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with two even numbers', async function () { + const a = new BN('42304'); + const b = new BN('84346'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with one even and one odd number', async function () { + const a = new BN('57417'); + const b = new BN('84346'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with two max uint256 numbers', async function () { + const a = MAX_UINT256; + expect(await this.math.$average(a, a)).to.be.bignumber.equal(bnAverage(a, a)); + }); + }); + + describe('ceilDiv', function () { + it('reverts on zero division', async function () { + const a = new BN('2'); + const b = new BN('0'); + // It's unspecified because it's a low level 0 division error + await expectRevert.unspecified(this.math.$ceilDiv(a, b)); + }); + + it('does not round up a zero result', async function () { + const a = new BN('0'); + const b = new BN('2'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('0'); + }); + + it('does not round up on exact division', async function () { + const a = new BN('10'); + const b = new BN('5'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('2'); + }); + + it('rounds up on division with remainders', async function () { + const a = new BN('42'); + const b = new BN('13'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('4'); + }); + + it('does not overflow', async function () { + const b = new BN('2'); + const result = new BN('1').shln(255); + expect(await this.math.$ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(result); + }); + + it('correctly computes max uint256 divided by 1', async function () { + const b = new BN('1'); + expect(await this.math.$ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(MAX_UINT256); + }); + }); + + describe('muldiv', function () { + it('divide by 0', async function () { + await expectRevert.unspecified(this.math.$mulDiv(1, 1, 0, Rounding.Floor)); + }); + + it('reverts with result higher than 2 ^ 256', async function () { + await expectRevertCustomError(this.math.$mulDiv(5, MAX_UINT256, 2, Rounding.Floor), 'MathOverflowedMulDiv', []); + }); + + describe('does round down', async function () { + it('small values', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$mulDiv('3', '4', '5', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$mulDiv('3', '5', '5', rounding)).to.be.bignumber.equal('3'); + } + }); + + it('large values', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$mulDiv(new BN('42'), MAX_UINT256_SUB1, MAX_UINT256, rounding)).to.be.bignumber.equal( + new BN('41'), + ); + + expect(await this.math.$mulDiv(new BN('17'), MAX_UINT256, MAX_UINT256, rounding)).to.be.bignumber.equal( + new BN('17'), + ); + + expect( + await this.math.$mulDiv(MAX_UINT256_SUB1, MAX_UINT256_SUB1, MAX_UINT256, rounding), + ).to.be.bignumber.equal(MAX_UINT256_SUB2); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256_SUB1, MAX_UINT256, rounding)).to.be.bignumber.equal( + MAX_UINT256_SUB1, + ); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256, MAX_UINT256, rounding)).to.be.bignumber.equal( + MAX_UINT256, + ); + } + }); + }); + + describe('does round up', async function () { + it('small values', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$mulDiv('3', '4', '5', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$mulDiv('3', '5', '5', rounding)).to.be.bignumber.equal('3'); + } + }); + + it('large values', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$mulDiv(new BN('42'), MAX_UINT256_SUB1, MAX_UINT256, rounding)).to.be.bignumber.equal( + new BN('42'), + ); + + expect(await this.math.$mulDiv(new BN('17'), MAX_UINT256, MAX_UINT256, rounding)).to.be.bignumber.equal( + new BN('17'), + ); + + expect( + await this.math.$mulDiv(MAX_UINT256_SUB1, MAX_UINT256_SUB1, MAX_UINT256, rounding), + ).to.be.bignumber.equal(MAX_UINT256_SUB1); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256_SUB1, MAX_UINT256, rounding)).to.be.bignumber.equal( + MAX_UINT256_SUB1, + ); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256, MAX_UINT256, rounding)).to.be.bignumber.equal( + MAX_UINT256, + ); + } + }); + }); + }); + + describe('sqrt', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$sqrt('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$sqrt('1', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('3', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('4', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('144', rounding)).to.be.bignumber.equal('12'); + expect(await this.math.$sqrt('999999', rounding)).to.be.bignumber.equal('999'); + expect(await this.math.$sqrt('1000000', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000001', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1002000', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1002001', rounding)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt(MAX_UINT256, rounding)).to.be.bignumber.equal( + '340282366920938463463374607431768211455', + ); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$sqrt('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$sqrt('1', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('2', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('3', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('4', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('144', rounding)).to.be.bignumber.equal('12'); + expect(await this.math.$sqrt('999999', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000000', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000001', rounding)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt('1002000', rounding)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt('1002001', rounding)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt(MAX_UINT256, rounding)).to.be.bignumber.equal( + '340282366920938463463374607431768211456', + ); + } + }); + }); + + describe('log', function () { + describe('log2', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.methods['$log2(uint256,uint8)']('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('3', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('4', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('5', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('6', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('7', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('8', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('9', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)'](MAX_UINT256, rounding)).to.be.bignumber.equal('255'); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.methods['$log2(uint256,uint8)']('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('3', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('4', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('5', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('6', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('7', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('8', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('9', rounding)).to.be.bignumber.equal('4'); + expect(await this.math.methods['$log2(uint256,uint8)'](MAX_UINT256, rounding)).to.be.bignumber.equal('256'); + } + }); + }); + + describe('log10', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$log10('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('2', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('9', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('10', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('11', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('99', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('100', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('101', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('999', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('1000', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1001', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10(MAX_UINT256, rounding)).to.be.bignumber.equal('77'); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$log10('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('9', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('10', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('11', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('99', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('100', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('101', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('999', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1000', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1001', rounding)).to.be.bignumber.equal('4'); + expect(await this.math.$log10(MAX_UINT256, rounding)).to.be.bignumber.equal('78'); + } + }); + }); + + describe('log256', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$log256('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('2', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('255', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('256', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('257', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('65535', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('65536', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65537', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256(MAX_UINT256, rounding)).to.be.bignumber.equal('31'); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$log256('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('255', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('256', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('257', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65535', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65536', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65537', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log256(MAX_UINT256, rounding)).to.be.bignumber.equal('32'); + } + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/math/SafeCast.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/math/SafeCast.test.js new file mode 100644 index 0000000..4b8ec5a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/math/SafeCast.test.js @@ -0,0 +1,161 @@ +const { BN } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { range } = require('../../../scripts/helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const SafeCast = artifacts.require('$SafeCast'); + +contract('SafeCast', async function () { + beforeEach(async function () { + this.safeCast = await SafeCast.new(); + }); + + function testToUint(bits) { + describe(`toUint${bits}`, () => { + const maxValue = new BN('2').pow(new BN(bits)).subn(1); + + it('downcasts 0', async function () { + expect(await this.safeCast[`$toUint${bits}`](0)).to.be.bignumber.equal('0'); + }); + + it('downcasts 1', async function () { + expect(await this.safeCast[`$toUint${bits}`](1)).to.be.bignumber.equal('1'); + }); + + it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () { + expect(await this.safeCast[`$toUint${bits}`](maxValue)).to.be.bignumber.equal(maxValue); + }); + + it(`reverts when downcasting 2^${bits} (${maxValue.addn(1)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toUint${bits}`](maxValue.addn(1)), + `SafeCastOverflowedUintDowncast`, + [bits, maxValue.addn(1)], + ); + }); + + it(`reverts when downcasting 2^${bits} + 1 (${maxValue.addn(2)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toUint${bits}`](maxValue.addn(2)), + `SafeCastOverflowedUintDowncast`, + [bits, maxValue.addn(2)], + ); + }); + }); + } + + range(8, 256, 8).forEach(bits => testToUint(bits)); + + describe('toUint256', () => { + const maxInt256 = new BN('2').pow(new BN(255)).subn(1); + const minInt256 = new BN('2').pow(new BN(255)).neg(); + + it('casts 0', async function () { + expect(await this.safeCast.$toUint256(0)).to.be.bignumber.equal('0'); + }); + + it('casts 1', async function () { + expect(await this.safeCast.$toUint256(1)).to.be.bignumber.equal('1'); + }); + + it(`casts INT256_MAX (${maxInt256})`, async function () { + expect(await this.safeCast.$toUint256(maxInt256)).to.be.bignumber.equal(maxInt256); + }); + + it('reverts when casting -1', async function () { + await expectRevertCustomError(this.safeCast.$toUint256(-1), `SafeCastOverflowedIntToUint`, [-1]); + }); + + it(`reverts when casting INT256_MIN (${minInt256})`, async function () { + await expectRevertCustomError(this.safeCast.$toUint256(minInt256), `SafeCastOverflowedIntToUint`, [minInt256]); + }); + }); + + function testToInt(bits) { + describe(`toInt${bits}`, () => { + const minValue = new BN('-2').pow(new BN(bits - 1)); + const maxValue = new BN('2').pow(new BN(bits - 1)).subn(1); + + it('downcasts 0', async function () { + expect(await this.safeCast[`$toInt${bits}`](0)).to.be.bignumber.equal('0'); + }); + + it('downcasts 1', async function () { + expect(await this.safeCast[`$toInt${bits}`](1)).to.be.bignumber.equal('1'); + }); + + it('downcasts -1', async function () { + expect(await this.safeCast[`$toInt${bits}`](-1)).to.be.bignumber.equal('-1'); + }); + + it(`downcasts -2^${bits - 1} (${minValue})`, async function () { + expect(await this.safeCast[`$toInt${bits}`](minValue)).to.be.bignumber.equal(minValue); + }); + + it(`downcasts 2^${bits - 1} - 1 (${maxValue})`, async function () { + expect(await this.safeCast[`$toInt${bits}`](maxValue)).to.be.bignumber.equal(maxValue); + }); + + it(`reverts when downcasting -2^${bits - 1} - 1 (${minValue.subn(1)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toInt${bits}`](minValue.subn(1)), + `SafeCastOverflowedIntDowncast`, + [bits, minValue.subn(1)], + ); + }); + + it(`reverts when downcasting -2^${bits - 1} - 2 (${minValue.subn(2)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toInt${bits}`](minValue.subn(2)), + `SafeCastOverflowedIntDowncast`, + [bits, minValue.subn(2)], + ); + }); + + it(`reverts when downcasting 2^${bits - 1} (${maxValue.addn(1)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toInt${bits}`](maxValue.addn(1)), + `SafeCastOverflowedIntDowncast`, + [bits, maxValue.addn(1)], + ); + }); + + it(`reverts when downcasting 2^${bits - 1} + 1 (${maxValue.addn(2)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toInt${bits}`](maxValue.addn(2)), + `SafeCastOverflowedIntDowncast`, + [bits, maxValue.addn(2)], + ); + }); + }); + } + + range(8, 256, 8).forEach(bits => testToInt(bits)); + + describe('toInt256', () => { + const maxUint256 = new BN('2').pow(new BN(256)).subn(1); + const maxInt256 = new BN('2').pow(new BN(255)).subn(1); + + it('casts 0', async function () { + expect(await this.safeCast.$toInt256(0)).to.be.bignumber.equal('0'); + }); + + it('casts 1', async function () { + expect(await this.safeCast.$toInt256(1)).to.be.bignumber.equal('1'); + }); + + it(`casts INT256_MAX (${maxInt256})`, async function () { + expect(await this.safeCast.$toInt256(maxInt256)).to.be.bignumber.equal(maxInt256); + }); + + it(`reverts when casting INT256_MAX + 1 (${maxInt256.addn(1)})`, async function () { + await expectRevertCustomError(this.safeCast.$toInt256(maxInt256.addn(1)), 'SafeCastOverflowedUintToInt', [ + maxInt256.addn(1), + ]); + }); + + it(`reverts when casting UINT256_MAX (${maxUint256})`, async function () { + await expectRevertCustomError(this.safeCast.$toInt256(maxUint256), 'SafeCastOverflowedUintToInt', [maxUint256]); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/math/SignedMath.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/math/SignedMath.test.js new file mode 100644 index 0000000..c014e22 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/math/SignedMath.test.js @@ -0,0 +1,95 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MIN_INT256, MAX_INT256 } = constants; + +const SignedMath = artifacts.require('$SignedMath'); + +contract('SignedMath', function () { + const min = new BN('-1234'); + const max = new BN('5678'); + + beforeEach(async function () { + this.math = await SignedMath.new(); + }); + + describe('max', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$max(max, min)).to.be.bignumber.equal(max); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$max(min, max)).to.be.bignumber.equal(max); + }); + }); + + describe('min', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$min(min, max)).to.be.bignumber.equal(min); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$min(max, min)).to.be.bignumber.equal(min); + }); + }); + + describe('average', function () { + function bnAverage(a, b) { + return a.add(b).divn(2); + } + + it('is correctly calculated with various input', async function () { + const valuesX = [ + new BN('0'), + new BN('3'), + new BN('-3'), + new BN('4'), + new BN('-4'), + new BN('57417'), + new BN('-57417'), + new BN('42304'), + new BN('-42304'), + MIN_INT256, + MAX_INT256, + ]; + + const valuesY = [ + new BN('0'), + new BN('5'), + new BN('-5'), + new BN('2'), + new BN('-2'), + new BN('57417'), + new BN('-57417'), + new BN('42304'), + new BN('-42304'), + MIN_INT256, + MAX_INT256, + ]; + + for (const x of valuesX) { + for (const y of valuesY) { + expect(await this.math.$average(x, y)).to.be.bignumber.equal( + bnAverage(x, y), + `Bad result for average(${x}, ${y})`, + ); + } + } + }); + }); + + describe('abs', function () { + for (const n of [ + MIN_INT256, + MIN_INT256.addn(1), + new BN('-1'), + new BN('0'), + new BN('1'), + MAX_INT256.subn(1), + MAX_INT256, + ]) { + it(`correctly computes the absolute value of ${n}`, async function () { + expect(await this.math.$abs(n)).to.be.bignumber.equal(n.abs()); + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/BitMap.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/BitMap.test.js new file mode 100644 index 0000000..8a1470c --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/BitMap.test.js @@ -0,0 +1,145 @@ +const { BN } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const BitMap = artifacts.require('$BitMaps'); + +contract('BitMap', function () { + const keyA = new BN('7891'); + const keyB = new BN('451'); + const keyC = new BN('9592328'); + + beforeEach(async function () { + this.bitmap = await BitMap.new(); + }); + + it('starts empty', async function () { + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + describe('setTo', function () { + it('set a key to true', async function () { + await this.bitmap.$setTo(0, keyA, true); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('set a key to false', async function () { + await this.bitmap.$setTo(0, keyA, true); + await this.bitmap.$setTo(0, keyA, false); + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('set several consecutive keys', async function () { + await this.bitmap.$setTo(0, keyA.addn(0), true); + await this.bitmap.$setTo(0, keyA.addn(1), true); + await this.bitmap.$setTo(0, keyA.addn(2), true); + await this.bitmap.$setTo(0, keyA.addn(3), true); + await this.bitmap.$setTo(0, keyA.addn(4), true); + await this.bitmap.$setTo(0, keyA.addn(2), false); + await this.bitmap.$setTo(0, keyA.addn(4), false); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + }); + + describe('set', function () { + it('adds a key', async function () { + await this.bitmap.$set(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('adds several keys', async function () { + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(true); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('adds several consecutive keys', async function () { + await this.bitmap.$set(0, keyA.addn(0)); + await this.bitmap.$set(0, keyA.addn(1)); + await this.bitmap.$set(0, keyA.addn(3)); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + }); + + describe('unset', function () { + it('removes added keys', async function () { + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + await this.bitmap.$unset(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(true); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('removes consecutive added keys', async function () { + await this.bitmap.$set(0, keyA.addn(0)); + await this.bitmap.$set(0, keyA.addn(1)); + await this.bitmap.$set(0, keyA.addn(3)); + await this.bitmap.$unset(0, keyA.addn(1)); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + + it('adds and removes multiple keys', async function () { + // [] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyC); + + // [A, C] + + await this.bitmap.$unset(0, keyA); + await this.bitmap.$unset(0, keyB); + + // [C] + + await this.bitmap.$set(0, keyB); + + // [C, B] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$unset(0, keyC); + + // [A, B] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + + // [A, B] + + await this.bitmap.$set(0, keyC); + await this.bitmap.$unset(0, keyA); + + // [B, C] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$unset(0, keyB); + + // [A, C] + + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(true); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/Checkpoints.t.sol b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/Checkpoints.t.sol new file mode 100644 index 0000000..7bdbcfd --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/Checkpoints.t.sol @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: MIT +// This file was procedurally generated from scripts/generate/templates/Checkpoints.t.js. + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {SafeCast} from "../../../contracts/utils/math/SafeCast.sol"; +import {Checkpoints} from "../../../contracts/utils/structs/Checkpoints.sol"; + +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]; + if (lastKey > 0) { + 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 CheckpointsTrace208Test is Test { + using Checkpoints for Checkpoints.Trace208; + + // 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.Trace208 internal _ckpts; + + // helpers + function _boundUint48(uint48 x, uint48 min, uint48 max) internal view returns (uint48) { + return SafeCast.toUint48(bound(uint256(x), uint256(min), uint256(max))); + } + + function _prepareKeys(uint48[] memory keys, uint48 maxSpread) internal view { + uint48 lastKey = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint48 key = _boundUint48(keys[i], lastKey, lastKey + maxSpread); + keys[i] = key; + lastKey = key; + } + } + + function _assertLatestCheckpoint(bool exist, uint48 key, uint208 value) internal { + (bool _exist, uint48 _key, uint208 _value) = _ckpts.latestCheckpoint(); + assertEq(_exist, exist); + assertEq(_key, key); + assertEq(_value, value); + } + + // tests + function testPush(uint48[] memory keys, uint208[] memory values, uint48 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) { + uint48 key = keys[i]; + uint208 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) { + uint48 lastKey = keys[keys.length - 1]; + if (lastKey > 0) { + pastKey = _boundUint48(pastKey, 0, lastKey - 1); + + vm.expectRevert(); + this.push(pastKey, values[keys.length % values.length]); + } + } + } + + // used to test reverts + function push(uint48 key, uint208 value) external { + _ckpts.push(key, value); + } + + function testLookup(uint48[] memory keys, uint208[] memory values, uint48 lookup) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + uint48 lastKey = keys.length == 0 ? 0 : keys[keys.length - 1]; + lookup = _boundUint48(lookup, 0, lastKey + _KEY_MAX_GAP); + + uint208 upper = 0; + uint208 lower = 0; + uint48 lowerKey = type(uint48).max; + for (uint256 i = 0; i < keys.length; ++i) { + uint48 key = keys[i]; + uint208 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]; + if (lastKey > 0) { + 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); + } +} diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/Checkpoints.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/Checkpoints.test.js new file mode 100644 index 0000000..936ac56 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/Checkpoints.test.js @@ -0,0 +1,158 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const { VALUE_SIZES } = require('../../../scripts/generate/templates/Checkpoints.opts.js'); +const { expectRevertCustomError } = require('../../helpers/customError.js'); +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const $Checkpoints = artifacts.require('$Checkpoints'); + +// The library name may be 'Checkpoints' or 'CheckpointsUpgradeable' +const libraryName = $Checkpoints._json.contractName.replace(/^\$/, ''); + +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(); + }); + + for (const length of VALUE_SIZES) { + describe(`Trace${length}`, function () { + beforeEach(async function () { + this.methods = { + at: (...args) => this.mock.methods[`$at_${libraryName}_Trace${length}(uint256,uint32)`](0, ...args), + 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('without checkpoints', function () { + it('at zero reverts', async function () { + // Reverts with array out of bound access, which is unspecified + await expectRevert.unspecified(this.methods.at(0)); + }); + + it('returns zero as latest value', async function () { + expect(await this.methods.latest()).to.be.bignumber.equal('0'); + + const ckpt = await this.methods.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 this.methods.lowerLookup(0)).to.be.bignumber.equal('0'); + expect(await this.methods.upperLookup(0)).to.be.bignumber.equal('0'); + expect(await this.methods.upperLookupRecent(0)).to.be.bignumber.equal('0'); + }); + }); + + describe('with checkpoints', function () { + beforeEach('pushing checkpoints', async function () { + this.checkpoints = [ + { key: '2', value: '17' }, + { key: '3', value: '42' }, + { key: '5', value: '101' }, + { key: '7', value: '23' }, + { key: '11', value: '99' }, + ]; + for (const { key, value } of this.checkpoints) { + await this.methods.push(key, value); + } + }); + + it('at keys', async function () { + for (const [index, { key, value }] of this.checkpoints.entries()) { + const at = await this.methods.at(index); + expect(at._value).to.be.bignumber.equal(value); + expect(at._key).to.be.bignumber.equal(key); + } + }); + + it('length', async function () { + expect(await this.methods.length()).to.be.bignumber.equal(this.checkpoints.length.toString()); + }); + + it('returns latest value', async function () { + expect(await this.methods.latest()).to.be.bignumber.equal(last(this.checkpoints).value); + + const ckpt = await this.methods.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 expectRevertCustomError( + this.methods.push(last(this.checkpoints).key - 1, '0'), + 'CheckpointUnorderedInsertion', + [], + ); + }); + + it('can update last value', async function () { + const newValue = '42'; + + // check length before the update + expect(await this.methods.length()).to.be.bignumber.equal(this.checkpoints.length.toString()); + + // update last key + await this.methods.push(last(this.checkpoints).key, newValue); + expect(await this.methods.latest()).to.be.bignumber.equal(newValue); + + // check that length did not change + expect(await this.methods.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 this.methods.lowerLookup(i)).to.be.bignumber.equal(value); + } + }); + + 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 this.methods.upperLookup(i)).to.be.bignumber.equal(value); + expect(await this.methods.upperLookupRecent(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 this.methods.push(key, value); + } + + for (let i = 0; i < 25; ++i) { + const value = last(allCheckpoints.filter(x => i >= x.key))?.value || '0'; + expect(await this.methods.upperLookup(i)).to.be.bignumber.equal(value); + expect(await this.methods.upperLookupRecent(i)).to.be.bignumber.equal(value); + } + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/DoubleEndedQueue.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/DoubleEndedQueue.test.js new file mode 100644 index 0000000..cbf37d7 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/DoubleEndedQueue.test.js @@ -0,0 +1,99 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const DoubleEndedQueue = artifacts.require('$DoubleEndedQueue'); + +/** Rebuild the content of the deque as a JS array. */ +const getContent = deque => + deque.$length(0).then(bn => + Promise.all( + Array(bn.toNumber()) + .fill() + .map((_, i) => deque.$at(0, i)), + ), + ); + +contract('DoubleEndedQueue', function () { + const bytesA = '0xdeadbeef'.padEnd(66, '0'); + const bytesB = '0x0123456789'.padEnd(66, '0'); + const bytesC = '0x42424242'.padEnd(66, '0'); + const bytesD = '0x171717'.padEnd(66, '0'); + + beforeEach(async function () { + this.deque = await DoubleEndedQueue.new(); + }); + + describe('when empty', function () { + it('getters', async function () { + expect(await this.deque.$empty(0)).to.be.equal(true); + expect(await getContent(this.deque)).to.have.ordered.members([]); + }); + + it('reverts on accesses', async function () { + await expectRevertCustomError(this.deque.$popBack(0), 'QueueEmpty', []); + await expectRevertCustomError(this.deque.$popFront(0), 'QueueEmpty', []); + await expectRevertCustomError(this.deque.$back(0), 'QueueEmpty', []); + await expectRevertCustomError(this.deque.$front(0), 'QueueEmpty', []); + }); + }); + + describe('when not empty', function () { + beforeEach(async function () { + await this.deque.$pushBack(0, bytesB); + await this.deque.$pushFront(0, bytesA); + await this.deque.$pushBack(0, bytesC); + this.content = [bytesA, bytesB, bytesC]; + }); + + it('getters', async function () { + expect(await this.deque.$empty(0)).to.be.equal(false); + expect(await this.deque.$length(0)).to.be.bignumber.equal(this.content.length.toString()); + expect(await this.deque.$front(0)).to.be.equal(this.content[0]); + expect(await this.deque.$back(0)).to.be.equal(this.content[this.content.length - 1]); + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('out of bounds access', async function () { + await expectRevertCustomError(this.deque.$at(0, this.content.length), 'QueueOutOfBounds', []); + }); + + describe('push', function () { + it('front', async function () { + await this.deque.$pushFront(0, bytesD); + this.content.unshift(bytesD); // add element at the beginning + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('back', async function () { + await this.deque.$pushBack(0, bytesD); + this.content.push(bytesD); // add element at the end + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + }); + + describe('pop', function () { + it('front', async function () { + const value = this.content.shift(); // remove first element + expectEvent(await this.deque.$popFront(0), 'return$popFront', { value }); + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('back', async function () { + const value = this.content.pop(); // remove last element + expectEvent(await this.deque.$popBack(0), 'return$popBack', { value }); + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + }); + + it('clear', async function () { + await this.deque.$clear(0); + + expect(await this.deque.$empty(0)).to.be.equal(true); + expect(await getContent(this.deque)).to.have.ordered.members([]); + }); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableMap.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableMap.behavior.js new file mode 100644 index 0000000..67b19e3 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableMap.behavior.js @@ -0,0 +1,178 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const zip = require('lodash.zip'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +function shouldBehaveLikeMap(keys, values, zeroValue, methods, events) { + const [keyA, keyB, keyC] = keys; + const [valueA, valueB, valueC] = values; + + async function expectMembersMatch(map, keys, values) { + expect(keys.length).to.equal(values.length); + + await Promise.all(keys.map(async key => expect(await methods.contains(map, key)).to.equal(true))); + + expect(await methods.length(map)).to.bignumber.equal(keys.length.toString()); + + expect((await Promise.all(keys.map(key => methods.get(map, key)))).map(k => k.toString())).to.have.same.members( + values.map(value => value.toString()), + ); + + // To compare key-value pairs, we zip keys and values, and convert BNs to + // strings to workaround Chai limitations when dealing with nested arrays + expect( + await Promise.all( + [...Array(keys.length).keys()].map(async index => { + const entry = await methods.at(map, index); + return [entry[0].toString(), entry[1].toString()]; + }), + ), + ).to.have.same.deep.members( + zip( + keys.map(k => k.toString()), + values.map(v => v.toString()), + ), + ); + + // This also checks that both arrays have the same length + expect((await methods.keys(map)).map(k => k.toString())).to.have.same.members(keys.map(key => key.toString())); + } + + it('starts empty', async function () { + expect(await methods.contains(this.map, keyA)).to.equal(false); + + await expectMembersMatch(this.map, [], []); + }); + + describe('set', function () { + it('adds a key', async function () { + const receipt = await methods.set(this.map, keyA, valueA); + expectEvent(receipt, events.setReturn, { ret0: true }); + + await expectMembersMatch(this.map, [keyA], [valueA]); + }); + + it('adds several keys', async function () { + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyB, valueB); + + await expectMembersMatch(this.map, [keyA, keyB], [valueA, valueB]); + expect(await methods.contains(this.map, keyC)).to.equal(false); + }); + + it('returns false when adding keys already in the set', async function () { + await methods.set(this.map, keyA, valueA); + + const receipt = await methods.set(this.map, keyA, valueA); + expectEvent(receipt, events.setReturn, { ret0: false }); + + await expectMembersMatch(this.map, [keyA], [valueA]); + }); + + it('updates values for keys already in the set', async function () { + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyA, valueB); + + await expectMembersMatch(this.map, [keyA], [valueB]); + }); + }); + + describe('remove', function () { + it('removes added keys', async function () { + await methods.set(this.map, keyA, valueA); + + const receipt = await methods.remove(this.map, keyA); + expectEvent(receipt, events.removeReturn, { ret0: true }); + + expect(await methods.contains(this.map, keyA)).to.equal(false); + await expectMembersMatch(this.map, [], []); + }); + + it('returns false when removing keys not in the set', async function () { + const receipt = await methods.remove(this.map, keyA); + expectEvent(receipt, events.removeReturn, { ret0: false }); + + expect(await methods.contains(this.map, keyA)).to.equal(false); + }); + + it('adds and removes multiple keys', async function () { + // [] + + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyC, valueC); + + // [A, C] + + await methods.remove(this.map, keyA); + await methods.remove(this.map, keyB); + + // [C] + + await methods.set(this.map, keyB, valueB); + + // [C, B] + + await methods.set(this.map, keyA, valueA); + await methods.remove(this.map, keyC); + + // [A, B] + + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyB, valueB); + + // [A, B] + + await methods.set(this.map, keyC, valueC); + await methods.remove(this.map, keyA); + + // [B, C] + + await methods.set(this.map, keyA, valueA); + await methods.remove(this.map, keyB); + + // [A, C] + + await expectMembersMatch(this.map, [keyA, keyC], [valueA, valueC]); + + expect(await methods.contains(this.map, keyA)).to.equal(true); + expect(await methods.contains(this.map, keyB)).to.equal(false); + expect(await methods.contains(this.map, keyC)).to.equal(true); + }); + }); + + describe('read', function () { + beforeEach(async function () { + await methods.set(this.map, keyA, valueA); + }); + + describe('get', function () { + it('existing value', async function () { + expect(await methods.get(this.map, keyA).then(r => r.toString())).to.be.equal(valueA.toString()); + }); + it('missing value', async function () { + const key = web3.utils.toHex(keyB); + await expectRevertCustomError(methods.get(this.map, keyB), 'EnumerableMapNonexistentKey', [ + key.length == 66 ? key : web3.utils.padLeft(key, 64, '0'), + ]); + }); + }); + + describe('tryGet', function () { + it('existing value', async function () { + const result = await methods.tryGet(this.map, keyA); + expect(result['0']).to.be.equal(true); + expect(result['1'].toString()).to.be.equal(valueA.toString()); + }); + it('missing value', async function () { + const result = await methods.tryGet(this.map, keyB); + expect(result['0']).to.be.equal(false); + expect(result['1'].toString()).to.be.equal(zeroValue.toString()); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeMap, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableMap.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableMap.test.js new file mode 100644 index 0000000..545e12a --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableMap.test.js @@ -0,0 +1,149 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { mapValues } = require('../../helpers/iterate'); + +const EnumerableMap = artifacts.require('$EnumerableMap'); + +const { shouldBehaveLikeMap } = require('./EnumerableMap.behavior'); + +const getMethods = ms => { + return mapValues( + ms, + m => + (self, ...args) => + self.methods[m](0, ...args), + ); +}; + +// 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; + + const keyA = new BN('7891'); + const keyB = new BN('451'); + const keyC = new BN('9592328'); + + const bytesA = '0xdeadbeef'.padEnd(66, '0'); + const bytesB = '0x0123456789'.padEnd(66, '0'); + const bytesC = '0x42424242'.padEnd(66, '0'); + + beforeEach(async function () { + this.map = await EnumerableMap.new(); + }); + + // AddressToUintMap + describe('AddressToUintMap', function () { + shouldBehaveLikeMap( + [accountA, accountB, accountC], + [keyA, keyB, keyC], + new BN('0'), + getMethods({ + set: '$set(uint256,address,uint256)', + get: '$get(uint256,address)', + tryGet: '$tryGet(uint256,address)', + remove: '$remove(uint256,address)', + length: `$length_${library}_AddressToUintMap(uint256)`, + at: `$at_${library}_AddressToUintMap(uint256,uint256)`, + contains: '$contains(uint256,address)', + keys: `$keys_${library}_AddressToUintMap(uint256)`, + }), + { + setReturn: `return$set_${library}_AddressToUintMap_address_uint256`, + removeReturn: `return$remove_${library}_AddressToUintMap_address`, + }, + ); + }); + + // UintToAddressMap + describe('UintToAddressMap', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC], + [accountA, accountB, accountC], + constants.ZERO_ADDRESS, + getMethods({ + set: '$set(uint256,uint256,address)', + get: `$get_${library}_UintToAddressMap(uint256,uint256)`, + 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_${library}_UintToAddressMap_uint256_address`, + removeReturn: `return$remove_${library}_UintToAddressMap_uint256`, + }, + ); + }); + + // Bytes32ToBytes32Map + describe('Bytes32ToBytes32Map', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC].map(k => '0x' + k.toString(16).padEnd(64, '0')), + [bytesA, bytesB, bytesC], + constants.ZERO_BYTES32, + getMethods({ + set: '$set(uint256,bytes32,bytes32)', + get: `$get_${library}_Bytes32ToBytes32Map(uint256,bytes32)`, + 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_${library}_Bytes32ToBytes32Map_bytes32_bytes32`, + removeReturn: `return$remove_${library}_Bytes32ToBytes32Map_bytes32`, + }, + ); + }); + + // UintToUintMap + describe('UintToUintMap', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC], + [keyA, keyB, keyC].map(k => k.add(new BN('1332'))), + new BN('0'), + getMethods({ + set: '$set(uint256,uint256,uint256)', + get: `$get_${library}_UintToUintMap(uint256,uint256)`, + 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_${library}_UintToUintMap_uint256_uint256`, + removeReturn: `return$remove_${library}_UintToUintMap_uint256`, + }, + ); + }); + + // Bytes32ToUintMap + describe('Bytes32ToUintMap', function () { + shouldBehaveLikeMap( + [bytesA, bytesB, bytesC], + [keyA, keyB, keyC], + new BN('0'), + getMethods({ + set: '$set(uint256,bytes32,uint256)', + get: `$get_${library}_Bytes32ToUintMap(uint256,bytes32)`, + 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_${library}_Bytes32ToUintMap_bytes32_uint256`, + removeReturn: `return$remove_${library}_Bytes32ToUintMap_bytes32`, + }, + ); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableSet.behavior.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableSet.behavior.js new file mode 100644 index 0000000..f80eb81 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableSet.behavior.js @@ -0,0 +1,129 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +function shouldBehaveLikeSet(values, methods, events) { + const [valueA, valueB, valueC] = values; + + async function expectMembersMatch(set, values) { + const contains = await Promise.all(values.map(value => methods.contains(set, value))); + expect(contains.every(Boolean)).to.be.equal(true); + + const length = await methods.length(set); + expect(length).to.bignumber.equal(values.length.toString()); + + // To compare values we convert to strings to workaround Chai + // limitations when dealing with nested arrays (required for BNs) + const indexedValues = await Promise.all( + Array(values.length) + .fill() + .map((_, index) => methods.at(set, index)), + ); + expect(indexedValues.map(v => v.toString())).to.have.same.members(values.map(v => v.toString())); + + const returnedValues = await methods.values(set); + expect(returnedValues.map(v => v.toString())).to.have.same.members(values.map(v => v.toString())); + } + + it('starts empty', async function () { + expect(await methods.contains(this.set, valueA)).to.equal(false); + + await expectMembersMatch(this.set, []); + }); + + describe('add', function () { + it('adds a value', async function () { + const receipt = await methods.add(this.set, valueA); + expectEvent(receipt, events.addReturn, { ret0: true }); + + await expectMembersMatch(this.set, [valueA]); + }); + + it('adds several values', async function () { + await methods.add(this.set, valueA); + await methods.add(this.set, valueB); + + await expectMembersMatch(this.set, [valueA, valueB]); + expect(await methods.contains(this.set, valueC)).to.equal(false); + }); + + it('returns false when adding values already in the set', async function () { + await methods.add(this.set, valueA); + + const receipt = await methods.add(this.set, valueA); + expectEvent(receipt, events.addReturn, { ret0: false }); + + await expectMembersMatch(this.set, [valueA]); + }); + }); + + describe('at', function () { + it('reverts when retrieving non-existent elements', async function () { + await expectRevert.unspecified(methods.at(this.set, 0)); + }); + }); + + describe('remove', function () { + it('removes added values', async function () { + await methods.add(this.set, valueA); + + const receipt = await methods.remove(this.set, valueA); + expectEvent(receipt, events.removeReturn, { ret0: true }); + + expect(await methods.contains(this.set, valueA)).to.equal(false); + await expectMembersMatch(this.set, []); + }); + + it('returns false when removing values not in the set', async function () { + const receipt = await methods.remove(this.set, valueA); + expectEvent(receipt, events.removeReturn, { ret0: false }); + + expect(await methods.contains(this.set, valueA)).to.equal(false); + }); + + it('adds and removes multiple values', async function () { + // [] + + await methods.add(this.set, valueA); + await methods.add(this.set, valueC); + + // [A, C] + + await methods.remove(this.set, valueA); + await methods.remove(this.set, valueB); + + // [C] + + await methods.add(this.set, valueB); + + // [C, B] + + await methods.add(this.set, valueA); + await methods.remove(this.set, valueC); + + // [A, B] + + await methods.add(this.set, valueA); + await methods.add(this.set, valueB); + + // [A, B] + + await methods.add(this.set, valueC); + await methods.remove(this.set, valueA); + + // [B, C] + + await methods.add(this.set, valueA); + await methods.remove(this.set, valueB); + + // [A, C] + + await expectMembersMatch(this.set, [valueA, valueC]); + + expect(await methods.contains(this.set, valueB)).to.equal(false); + }); + }); +} + +module.exports = { + shouldBehaveLikeSet, +}; diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableSet.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableSet.test.js new file mode 100644 index 0000000..a184025 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/structs/EnumerableSet.test.js @@ -0,0 +1,79 @@ +const EnumerableSet = artifacts.require('$EnumerableSet'); +const { mapValues } = require('../../helpers/iterate'); + +const { shouldBehaveLikeSet } = require('./EnumerableSet.behavior'); + +const getMethods = ms => { + return mapValues( + ms, + m => + (self, ...args) => + self.methods[m](0, ...args), + ); +}; + +// 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(); + }); + + // Bytes32Set + describe('EnumerableBytes32Set', function () { + shouldBehaveLikeSet( + ['0xdeadbeef', '0x0123456789', '0x42424242'].map(e => e.padEnd(66, '0')), + getMethods({ + add: '$add(uint256,bytes32)', + remove: '$remove(uint256,bytes32)', + contains: '$contains(uint256,bytes32)', + length: `$length_${library}_Bytes32Set(uint256)`, + at: `$at_${library}_Bytes32Set(uint256,uint256)`, + values: `$values_${library}_Bytes32Set(uint256)`, + }), + { + addReturn: `return$add_${library}_Bytes32Set_bytes32`, + removeReturn: `return$remove_${library}_Bytes32Set_bytes32`, + }, + ); + }); + + // AddressSet + describe('EnumerableAddressSet', function () { + shouldBehaveLikeSet( + accounts, + getMethods({ + add: '$add(uint256,address)', + remove: '$remove(uint256,address)', + contains: '$contains(uint256,address)', + length: `$length_${library}_AddressSet(uint256)`, + at: `$at_${library}_AddressSet(uint256,uint256)`, + values: `$values_${library}_AddressSet(uint256)`, + }), + { + addReturn: `return$add_${library}_AddressSet_address`, + removeReturn: `return$remove_${library}_AddressSet_address`, + }, + ); + }); + + // UintSet + describe('EnumerableUintSet', function () { + shouldBehaveLikeSet( + [1234, 5678, 9101112].map(e => web3.utils.toBN(e)), + getMethods({ + add: '$add(uint256,uint256)', + remove: '$remove(uint256,uint256)', + contains: '$contains(uint256,uint256)', + length: `$length_${library}_UintSet(uint256)`, + at: `$at_${library}_UintSet(uint256,uint256)`, + values: `$values_${library}_UintSet(uint256)`, + }), + { + addReturn: `return$add_${library}_UintSet_uint256`, + removeReturn: `return$remove_${library}_UintSet_uint256`, + }, + ); + }); +}); diff --git a/lib/openzeppelin-contracts-v5.0.0/test/utils/types/Time.test.js b/lib/openzeppelin-contracts-v5.0.0/test/utils/types/Time.test.js new file mode 100644 index 0000000..6149117 --- /dev/null +++ b/lib/openzeppelin-contracts-v5.0.0/test/utils/types/Time.test.js @@ -0,0 +1,140 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { clock } = require('../../helpers/time'); +const { product, max } = require('../../helpers/iterate'); + +const Time = artifacts.require('$Time'); + +const MAX_UINT32 = 1n << (32n - 1n); +const MAX_UINT48 = 1n << (48n - 1n); +const SOME_VALUES = [0n, 1n, 2n, 15n, 16n, 17n, 42n]; + +const asUint = (value, size) => { + if (typeof value != 'bigint') { + value = BigInt(value); + } + // chai does not support bigint :/ + if (value < 0 || value >= 1n << BigInt(size)) { + throw new Error(`value is not a valid uint${size}`); + } + return value; +}; + +const unpackDelay = delay => ({ + valueBefore: (asUint(delay, 112) >> 32n) % (1n << 32n), + valueAfter: (asUint(delay, 112) >> 0n) % (1n << 32n), + effect: (asUint(delay, 112) >> 64n) % (1n << 48n), +}); + +const packDelay = ({ valueBefore, valueAfter = 0n, effect = 0n }) => + (asUint(valueAfter, 32) << 0n) + (asUint(valueBefore, 32) << 32n) + (asUint(effect, 48) << 64n); + +const effectSamplesForTimepoint = timepoint => [ + 0n, + timepoint, + ...product([-1n, 1n], [1n, 2n, 17n, 42n]) + .map(([sign, shift]) => timepoint + sign * shift) + .filter(effect => effect > 0n && effect <= MAX_UINT48), + MAX_UINT48, +]; + +contract('Time', function () { + beforeEach(async function () { + this.mock = await Time.new(); + }); + + describe('clocks', function () { + it('timestamp', async function () { + expect(await this.mock.$timestamp()).to.be.bignumber.equal(web3.utils.toBN(await clock.timestamp())); + }); + + it('block number', async function () { + expect(await this.mock.$blockNumber()).to.be.bignumber.equal(web3.utils.toBN(await clock.blocknumber())); + }); + }); + + describe('Delay', function () { + describe('packing and unpacking', function () { + const valueBefore = 17n; + const valueAfter = 42n; + const effect = 69n; + const delay = 1272825341158973505578n; + + it('pack', async function () { + const packed = await this.mock.$pack(valueBefore, valueAfter, effect); + expect(packed).to.be.bignumber.equal(delay.toString()); + + const packed2 = packDelay({ valueBefore, valueAfter, effect }); + expect(packed2).to.be.equal(delay); + }); + + it('unpack', async function () { + const unpacked = await this.mock.$unpack(delay); + expect(unpacked[0]).to.be.bignumber.equal(valueBefore.toString()); + expect(unpacked[1]).to.be.bignumber.equal(valueAfter.toString()); + expect(unpacked[2]).to.be.bignumber.equal(effect.toString()); + + const unpacked2 = unpackDelay(delay); + expect(unpacked2).to.be.deep.equal({ valueBefore, valueAfter, effect }); + }); + }); + + it('toDelay', async function () { + for (const value of [...SOME_VALUES, MAX_UINT32]) { + const delay = await this.mock.$toDelay(value).then(unpackDelay); + expect(delay).to.be.deep.equal({ valueBefore: 0n, valueAfter: value, effect: 0n }); + } + }); + + it('get & getFull', async function () { + const timepoint = await clock.timestamp().then(BigInt); + const valueBefore = 24194n; + const valueAfter = 4214143n; + + for (const effect of effectSamplesForTimepoint(timepoint)) { + const isPast = effect <= timepoint; + + const delay = packDelay({ valueBefore, valueAfter, effect }); + + expect(await this.mock.$get(delay)).to.be.bignumber.equal(String(isPast ? valueAfter : valueBefore)); + + const result = await this.mock.$getFull(delay); + expect(result[0]).to.be.bignumber.equal(String(isPast ? valueAfter : valueBefore)); + expect(result[1]).to.be.bignumber.equal(String(isPast ? 0n : valueAfter)); + expect(result[2]).to.be.bignumber.equal(String(isPast ? 0n : effect)); + } + }); + + it('withUpdate', async function () { + const timepoint = await clock.timestamp().then(BigInt); + const valueBefore = 24194n; + const valueAfter = 4214143n; + const newvalueAfter = 94716n; + + for (const effect of effectSamplesForTimepoint(timepoint)) + for (const minSetback of [...SOME_VALUES, MAX_UINT32]) { + const isPast = effect <= timepoint; + const expectedvalueBefore = isPast ? valueAfter : valueBefore; + const expectedSetback = max(minSetback, expectedvalueBefore - newvalueAfter, 0n); + + const result = await this.mock.$withUpdate( + packDelay({ valueBefore, valueAfter, effect }), + newvalueAfter, + minSetback, + ); + + expect(result[0]).to.be.bignumber.equal( + String( + packDelay({ + valueBefore: expectedvalueBefore, + valueAfter: newvalueAfter, + effect: timepoint + expectedSetback, + }), + ), + ); + expect(result[1]).to.be.bignumber.equal(String(timepoint + expectedSetback)); + } + }); + }); +}); diff --git a/lib/openzeppelin-contracts/.changeset/config.json b/lib/openzeppelin-contracts/.changeset/config.json new file mode 100644 index 0000000..66794fa --- /dev/null +++ b/lib/openzeppelin-contracts/.changeset/config.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", + "changelog": [ + "@changesets/changelog-github", + { + "repo": "OpenZeppelin/openzeppelin-contracts" + } + ], + "commit": false, + "access": "public", + "baseBranch": "master" +} diff --git a/lib/openzeppelin-contracts/.codecov.yml b/lib/openzeppelin-contracts/.codecov.yml new file mode 100644 index 0000000..9455306 --- /dev/null +++ b/lib/openzeppelin-contracts/.codecov.yml @@ -0,0 +1,12 @@ +comment: off +github_checks: + annotations: false +coverage: + status: + patch: + default: + target: 95% + only_pulls: true + project: + default: + threshold: 1% diff --git a/lib/openzeppelin-contracts/.editorconfig b/lib/openzeppelin-contracts/.editorconfig new file mode 100644 index 0000000..f162e8d --- /dev/null +++ b/lib/openzeppelin-contracts/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = false +max_line_length = 120 + +[*.sol] +indent_size = 4 + +[*.js] +indent_size = 2 + +[*.{adoc,md}] +max_line_length = 0 diff --git a/lib/openzeppelin-contracts/.eslintrc b/lib/openzeppelin-contracts/.eslintrc new file mode 100644 index 0000000..a5418c5 --- /dev/null +++ b/lib/openzeppelin-contracts/.eslintrc @@ -0,0 +1,20 @@ +{ + "root": true, + "extends" : [ + "eslint:recommended", + "prettier", + ], + "env": { + "es2022": true, + "browser": true, + "node": true, + "mocha": true, + }, + "globals" : { + "artifacts": "readonly", + "contract": "readonly", + "web3": "readonly", + "extendEnvironment": "readonly", + "expect": "readonly", + } +} diff --git a/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md b/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..2797a08 --- /dev/null +++ b/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,21 @@ +--- +name: Bug report +about: Report a bug in OpenZeppelin Contracts + +--- + + + + + +**💻 Environment** + + + +**📝 Details** + + + +**🔢 Code to reproduce bug** + + diff --git a/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml b/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..4018cef --- /dev/null +++ b/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: + - name: Questions & Support Requests + url: https://forum.openzeppelin.com/c/support/contracts/18 + about: Ask in the OpenZeppelin Forum diff --git a/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md b/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..ff596b0 --- /dev/null +++ b/lib/openzeppelin-contracts/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,14 @@ +--- +name: Feature request +about: Suggest an idea for OpenZeppelin Contracts + +--- + +**🧐 Motivation** + + +**📝 Details** + + + + diff --git a/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md b/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2394518 --- /dev/null +++ b/lib/openzeppelin-contracts/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,20 @@ + + + + + +Fixes #???? + + + + + +#### PR Checklist + + + + + +- [ ] Tests +- [ ] Documentation +- [ ] Changeset entry (run `npx changeset add`) diff --git a/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml b/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml new file mode 100644 index 0000000..e38c48e --- /dev/null +++ b/lib/openzeppelin-contracts/.github/actions/gas-compare/action.yml @@ -0,0 +1,49 @@ +name: Compare gas costs +inputs: + token: + description: github token + required: true + report: + description: report to read from + required: false + default: gasReporterOutput.json + out_report: + description: report to read + required: false + default: ${{ github.ref_name }}.gasreport.json + ref_report: + description: report to read from + required: false + default: ${{ github.base_ref }}.gasreport.json + +runs: + using: composite + steps: + - name: Download reference report + 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 gasreport + env: + GITHUB_TOKEN: ${{ inputs.token }} + shell: bash + continue-on-error: true + id: reference + - name: Compare reports + if: steps.reference.outcome == 'success' && github.event_name == 'pull_request' + run: | + node scripts/checks/compareGasReports.js ${{ inputs.report }} ${{ inputs.ref_report }} >> $GITHUB_STEP_SUMMARY + env: + STYLE: markdown + shell: bash + - name: Rename report for upload + if: github.event_name != 'pull_request' + run: | + mv ${{ inputs.report }} ${{ inputs.out_report }} + shell: bash + - name: Save report + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: gasreport + path: ${{ inputs.out_report }} diff --git a/lib/openzeppelin-contracts/.github/actions/setup/action.yml b/lib/openzeppelin-contracts/.github/actions/setup/action.yml new file mode 100644 index 0000000..cab1188 --- /dev/null +++ b/lib/openzeppelin-contracts/.github/actions/setup/action.yml @@ -0,0 +1,21 @@ +name: Setup + +runs: + using: composite + steps: + - uses: actions/setup-node@v3 + with: + node-version: 16.x + - uses: actions/cache@v3 + id: cache + with: + path: '**/node_modules' + key: npm-v3-${{ hashFiles('**/package-lock.json') }} + - name: Install dependencies + run: npm ci + shell: bash + if: steps.cache.outputs.cache-hit != 'true' + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly diff --git a/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml b/lib/openzeppelin-contracts/.github/actions/storage-layout/action.yml new file mode 100644 index 0000000..fdfd5a2 --- /dev/null +++ b/lib/openzeppelin-contracts/.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 }} + 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/lib/openzeppelin-contracts/.github/workflows/actionlint.yml b/lib/openzeppelin-contracts/.github/workflows/actionlint.yml new file mode 100644 index 0000000..3e42c8a --- /dev/null +++ b/lib/openzeppelin-contracts/.github/workflows/actionlint.yml @@ -0,0 +1,18 @@ +name: lint workflows + +on: + pull_request: + paths: + - '.github/**/*.ya?ml' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Add problem matchers + run: | + # https://github.com/rhysd/actionlint/blob/3a2f2c7/docs/usage.md#problem-matchers + curl -LO https://raw.githubusercontent.com/rhysd/actionlint/main/.github/actionlint-matcher.json + echo "::add-matcher::actionlint-matcher.json" + - uses: docker://rhysd/actionlint:latest diff --git a/lib/openzeppelin-contracts/.github/workflows/changeset.yml b/lib/openzeppelin-contracts/.github/workflows/changeset.yml new file mode 100644 index 0000000..efc5c53 --- /dev/null +++ b/lib/openzeppelin-contracts/.github/workflows/changeset.yml @@ -0,0 +1,28 @@ +name: changeset + +on: + pull_request: + branches: + - master + types: + - opened + - synchronize + - labeled + - unlabeled + +concurrency: + group: changeset-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + if: ${{ !contains(github.event.pull_request.labels.*.name, 'ignore-changeset') }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Include history so Changesets finds merge-base + - name: Set up environment + uses: ./.github/actions/setup + - name: Check changeset + run: npx changeset status --since=origin/${{ github.base_ref }} diff --git a/lib/openzeppelin-contracts/.github/workflows/checks.yml b/lib/openzeppelin-contracts/.github/workflows/checks.yml new file mode 100644 index 0000000..5b32bdb --- /dev/null +++ b/lib/openzeppelin-contracts/.github/workflows/checks.yml @@ -0,0 +1,118 @@ +name: checks + +on: + push: + branches: + - master + - next-v* + - release-v* + pull_request: {} + workflow_dispatch: {} + +concurrency: + group: checks-${{ github.ref }} + cancel-in-progress: true + +env: + NODE_OPTIONS: --max_old_space_size=5120 + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: npm run lint + + tests: + runs-on: ubuntu-latest + env: + FORCE_COLOR: 1 + GAS: true + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - name: Run tests and generate gas report + run: npm run test + - name: Check linearisation of the inheritance graph + run: npm run test:inheritance + - name: Check proceduraly generated contracts are up-to-date + run: npm run test:generation + - name: Compare gas costs + uses: ./.github/actions/gas-compare + if: github.base_ref == 'master' + with: + token: ${{ github.token }} + + tests-upgradeable: + runs-on: ubuntu-latest + env: + FORCE_COLOR: 1 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Include history so patch conflicts are resolved automatically + - name: Set up environment + uses: ./.github/actions/setup + - name: Copy non-upgradeable contracts as dependency + run: | + mkdir -p lib/openzeppelin-contracts + cp -rnT contracts lib/openzeppelin-contracts/contracts + - name: Transpile to upgradeable + run: bash scripts/upgradeable/transpile.sh + - name: Run tests + run: npm run test + - name: Check linearisation of the inheritance graph + run: npm run test:inheritance + - name: Check storage layout + uses: ./.github/actions/storage-layout + if: github.base_ref == 'master' + continue-on-error: ${{ contains(github.event.pull_request.labels.*.name, 'breaking change') }} + with: + token: ${{ github.token }} + + tests-foundry: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Set up environment + uses: ./.github/actions/setup + - name: Run tests + run: forge test -vv + + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: npm run coverage + - uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + + slither: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: rm foundry.toml + - uses: crytic/slither-action@v0.3.0 + with: + node-version: 18.15 + + codespell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run CodeSpell + uses: codespell-project/actions-codespell@v2.0 + with: + check_hidden: true + check_filenames: true + skip: package-lock.json,*.pdf diff --git a/lib/openzeppelin-contracts/.github/workflows/docs.yml b/lib/openzeppelin-contracts/.github/workflows/docs.yml new file mode 100644 index 0000000..04b8131 --- /dev/null +++ b/lib/openzeppelin-contracts/.github/workflows/docs.yml @@ -0,0 +1,19 @@ +name: Build Docs + +on: + push: + branches: [release-v*] + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - run: node scripts/update-docs-branch.js + - run: git push --all origin diff --git a/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml b/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml new file mode 100644 index 0000000..6b4ca2c --- /dev/null +++ b/lib/openzeppelin-contracts/.github/workflows/formal-verification.yml @@ -0,0 +1,68 @@ +name: formal verification + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + workflow_dispatch: {} + +env: + PIP_VERSION: '3.10' + JAVA_VERSION: '11' + SOLC_VERSION: '0.8.20' + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + apply-diff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - 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@v4 + 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: + 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 ${{ steps.arguments.outputs.result }} >> "$GITHUB_STEP_SUMMARY" + env: + CERTORAKEY: ${{ secrets.CERTORAKEY }} diff --git a/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml b/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml new file mode 100644 index 0000000..12da449 --- /dev/null +++ b/lib/openzeppelin-contracts/.github/workflows/release-cycle.yml @@ -0,0 +1,214 @@ +# 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: + push: + branches: + - release-v* + workflow_dispatch: {} + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + state: + name: Check state + permissions: + pull-requests: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - id: state + name: Get state + uses: actions/github-script@v6 + env: + TRIGGERING_ACTOR: ${{ github.triggering_actor }} + with: + result-encoding: string + script: await require('./scripts/release/workflow/state.js')({ github, context, core }) + outputs: + # Job Flags + start: ${{ steps.state.outputs.start }} + changesets: ${{ steps.state.outputs.changesets }} + promote: ${{ steps.state.outputs.promote }} + publish: ${{ steps.state.outputs.publish }} + merge: ${{ steps.state.outputs.merge }} + + # Global variables + is_prerelease: ${{ steps.state.outputs.is_prerelease }} + + start: + needs: state + name: Start new release candidate + permissions: + contents: write + actions: write + if: needs.state.outputs.start == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - id: start + name: Create branch with release candidate + run: bash scripts/release/workflow/start.sh + - name: Re-run workflow + uses: actions/github-script@v6 + env: + REF: ${{ steps.start.outputs.branch }} + with: + script: await require('./scripts/release/workflow/rerun.js')({ github, context }) + + promote: + needs: state + name: Promote to final release + permissions: + contents: write + actions: write + if: needs.state.outputs.promote == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Exit prerelease state + if: needs.state.outputs.is_prerelease == 'true' + run: bash scripts/release/workflow/exit-prerelease.sh + - name: Re-run workflow + uses: actions/github-script@v6 + with: + script: await require('./scripts/release/workflow/rerun.js')({ github, context }) + + changesets: + needs: state + name: Update PR to release + permissions: + contents: write + pull-requests: write + if: needs.state.outputs.changesets == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # To get all tags + - name: Set up environment + uses: ./.github/actions/setup + - name: Set release title + uses: actions/github-script@v6 + with: + result-encoding: string + script: await require('./scripts/release/workflow/set-changesets-pr-title.js')({ core }) + - name: Create PR + uses: changesets/action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRERELEASE: ${{ needs.state.outputs.is_prerelease }} + with: + version: npm run version + title: ${{ env.TITLE }} + commit: ${{ env.TITLE }} + body: | # Wait for support on this https://github.com/changesets/action/pull/250 + This is an automated PR for releasing ${{ github.repository }} + Check [CHANGELOG.md](${{ github.repository }}/CHANGELOG.md) + + publish: + needs: state + name: Publish to npm + environment: npm + permissions: + contents: write + if: needs.state.outputs.publish == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up environment + uses: ./.github/actions/setup + - id: pack + name: Pack + 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: Publish + run: bash scripts/release/workflow/publish.sh + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + TARBALL: ${{ steps.pack.outputs.tarball }} + TAG: ${{ steps.pack.outputs.tag }} + - name: Create Github Release + uses: actions/github-script@v6 + env: + 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@v4 + - 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 + name: Create PR back to master + permissions: + contents: write + pull-requests: write + if: needs.state.outputs.merge == 'true' + runs-on: ubuntu-latest + env: + MERGE_BRANCH: merge/${{ github.ref_name }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # All branches + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Create branch to merge + run: | + git checkout -B "$MERGE_BRANCH" "$GITHUB_REF_NAME" + git push -f origin "$MERGE_BRANCH" + - name: Create PR back to master + uses: actions/github-script@v6 + with: + script: | + await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head: process.env.MERGE_BRANCH, + base: 'master', + title: '${{ format('Merge {0} branch', github.ref_name) }}' + }); diff --git a/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml b/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml new file mode 100644 index 0000000..46bf15a --- /dev/null +++ b/lib/openzeppelin-contracts/.github/workflows/upgradeable.yml @@ -0,0 +1,34 @@ +name: transpile upgradeable + +on: + push: + branches: + - master + - release-v* + +jobs: + transpile: + environment: push-upgradeable + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + repository: OpenZeppelin/openzeppelin-contracts-upgradeable + fetch-depth: 0 + token: ${{ secrets.GH_TOKEN_UPGRADEABLE }} + - name: Fetch current non-upgradeable branch + run: | + git fetch "$REMOTE" master # Fetch default branch first for patch to apply cleanly + git fetch "$REMOTE" "$REF" + git checkout FETCH_HEAD + env: + REF: ${{ github.ref }} + REMOTE: https://github.com/${{ github.repository }}.git + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Transpile to upgradeable + run: bash scripts/upgradeable/transpile-onto.sh ${{ github.ref_name }} origin/${{ github.ref_name }} + env: + SUBMODULE_REMOTE: https://github.com/${{ github.repository }}.git + - run: git push origin ${{ github.ref_name }} diff --git a/lib/openzeppelin-contracts/.gitignore b/lib/openzeppelin-contracts/.gitignore new file mode 100644 index 0000000..a6caa9f --- /dev/null +++ b/lib/openzeppelin-contracts/.gitignore @@ -0,0 +1,72 @@ +*.swp +*.swo + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +allFiredEvents +scTopics + +# Coverage directory used by tools like istanbul +coverage +coverage.json +coverageEnv + +# node-waf configuration +.lock-wscript + +# Dependency directory +node_modules + +# Debug log from npm +npm-debug.log + +# local env variables +.env + +# truffle build directory +build/ + +# macOS +.DS_Store + +# truffle +.node-xmlhttprequest-* + +# IntelliJ IDE +.idea + +# docs artifacts +docs/modules/api + +# only used to package @openzeppelin/contracts +contracts/build/ +contracts/README.md + +# temporary artifact from solidity-coverage +allFiredEvents +.coverage_artifacts +.coverage_cache +.coverage_contracts + +# hardat-exposed +contracts-exposed + +# Hardhat +/cache +/artifacts + +# Foundry +/out +/cache_forge + +# Certora +.certora* +.last_confs +certora_* +.zip-output-url.txt diff --git a/lib/openzeppelin-contracts/.gitmodules b/lib/openzeppelin-contracts/.gitmodules new file mode 100644 index 0000000..08a09bb --- /dev/null +++ b/lib/openzeppelin-contracts/.gitmodules @@ -0,0 +1,7 @@ +[submodule "lib/forge-std"] + branch = v1 + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "lib/erc4626-tests"] + path = lib/erc4626-tests + url = https://github.com/a16z/erc4626-tests.git diff --git a/lib/openzeppelin-contracts/.mocharc.js b/lib/openzeppelin-contracts/.mocharc.js new file mode 100644 index 0000000..920662d --- /dev/null +++ b/lib/openzeppelin-contracts/.mocharc.js @@ -0,0 +1,4 @@ +module.exports = { + require: 'hardhat/register', + timeout: 4000, +}; diff --git a/lib/openzeppelin-contracts/.prettierrc b/lib/openzeppelin-contracts/.prettierrc new file mode 100644 index 0000000..39c004c --- /dev/null +++ b/lib/openzeppelin-contracts/.prettierrc @@ -0,0 +1,15 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all", + "arrowParens": "avoid", + "overrides": [ + { + "files": "*.sol", + "options": { + "singleQuote": false + } + } + ], + "plugins": ["prettier-plugin-solidity"] +} diff --git a/lib/openzeppelin-contracts/.solcover.js b/lib/openzeppelin-contracts/.solcover.js new file mode 100644 index 0000000..e0dea5e --- /dev/null +++ b/lib/openzeppelin-contracts/.solcover.js @@ -0,0 +1,13 @@ +module.exports = { + norpc: true, + testCommand: 'npm test', + compileCommand: 'npm run compile', + skipFiles: ['mocks'], + providerOptions: { + default_balance_ether: '10000000000000000000000000', + }, + mocha: { + fgrep: '[skip-on-coverage]', + invert: true, + }, +}; diff --git a/lib/openzeppelin-contracts/CHANGELOG.md b/lib/openzeppelin-contracts/CHANGELOG.md new file mode 100644 index 0000000..9575afb --- /dev/null +++ b/lib/openzeppelin-contracts/CHANGELOG.md @@ -0,0 +1,972 @@ +# Changelog + +## 5.0.0 (2023-10-05) + +### Additions Summary + +The following contracts and libraries were added: + +- `AccessManager`: A consolidated system for managing access control in complex systems. + - `AccessManaged`: A module for connecting a contract to an authority in charge of its access control. + - `GovernorTimelockAccess`: An adapter for time-locking governance proposals using an `AccessManager`. + - `AuthorityUtils`: A library of utilities for interacting with authority contracts. +- `GovernorStorage`: A Governor module that stores proposal details in storage. +- `ERC2771Forwarder`: An ERC2771 forwarder for meta transactions. +- `ERC1967Utils`: A library with ERC1967 events, errors and getters. +- `Nonces`: An abstraction for managing account nonces. +- `MessageHashUtils`: A library for producing digests for ECDSA operations. +- `Time`: A library with helpers for manipulating time-related objects. + +### Removals Summary + +The following contracts, libraries, and functions were removed: + +- `Address.isContract` (because of its ambiguous nature and potential for misuse) +- `Checkpoints.History` +- `Counters` +- `ERC20Snapshot` +- `ERC20VotesComp` +- `ERC165Storage` (in favor of inheritance based approach) +- `ERC777` +- `ERC1820Implementer` +- `GovernorVotesComp` +- `GovernorProposalThreshold` (deprecated since 4.4) +- `PaymentSplitter` +- `PullPayment` +- `SafeMath` +- `SignedSafeMath` +- `Timers` +- `TokenTimelock` (in favor of `VestingWallet`) +- All escrow contracts (`Escrow`, `ConditionalEscrow` and `RefundEscrow`) +- All cross-chain contracts, including `AccessControlCrossChain` and all the vendored bridge interfaces +- All presets in favor of [OpenZeppelin Contracts Wizard](https://wizard.openzeppelin.com/) + +These removals were implemented in the following PRs: [#3637](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3637), [#3880](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3880), [#3945](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3945), [#4258](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4258), [#4276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4276), [#4289](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4289) + +### Changes by category + +#### General + +- Replaced revert strings and require statements with custom errors. ([#4261](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4261)) +- Bumped minimum compiler version required to 0.8.20 ([#4288](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4288)) +- Use of `abi.encodeCall` in place of `abi.encodeWithSelector` and `abi.encodeWithSignature` for improved type-checking of parameters ([#4293](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4293)) +- Replaced some uses of `abi.encodePacked` with clearer alternatives (e.g. `bytes.concat`, `string.concat`). ([#4504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4504)) ([#4296](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4296)) +- Overrides are now used internally for a number of functions that were previously hardcoded to their default implementation in certain locations: `ERC1155Supply.totalSupply`, `ERC721.ownerOf`, `ERC721.balanceOf` and `ERC721.totalSupply` in `ERC721Enumerable`, `ERC20.totalSupply` in `ERC20FlashMint`, and `ERC1967._getImplementation` in `ERC1967Proxy`. ([#4299](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4299)) +- Removed the `override` specifier from functions that only override a single interface function. ([#4315](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4315)) +- Switched to using explicit Solidity import statements. Some previously available symbols may now have to be separately imported. ([#4399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4399)) +- `Governor`, `Initializable`, and `UUPSUpgradeable`: Use internal functions in modifiers to optimize bytecode size. ([#4472](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4472)) +- Upgradeable contracts now use namespaced storage (EIP-7201). ([#4534](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4534)) +- Upgradeable contracts no longer transpile interfaces and libraries. ([#4628](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4628)) + +#### Access + +- `Ownable`: Added an `initialOwner` parameter to the constructor, making the ownership initialization explicit. ([#4267](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4267)) +- `Ownable`: Prevent using address(0) as the initial owner. ([#4531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4531)) +- `AccessControl`: Added a boolean return value to the internal `_grantRole` and `_revokeRole` functions indicating whether the role was granted or revoked. ([#4241](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4241)) +- `access`: Moved `AccessControl` extensions to a dedicated directory. ([#4359](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4359)) +- `AccessManager`: Added a new contract for managing access control of complex systems in a consolidated location. ([#4121](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4121)) +- `AccessManager`, `AccessManaged`, `GovernorTimelockAccess`: Ensure that calldata shorter than 4 bytes is not padded to 4 bytes. ([#4624](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4624)) +- `AccessManager`: Use named return parameters in functions that return multiple values. ([#4624](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4624)) +- `AccessManager`: Make `schedule` and `execute` more conservative when delay is 0. ([#4644](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4644)) + +#### Finance + +- `VestingWallet`: Fixed revert during 1 second time window when duration is 0. ([#4502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4502)) +- `VestingWallet`: Use `Ownable` instead of an immutable `beneficiary`. ([#4508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4508)) + +#### Governance + +- `Governor`: Optimized use of storage for proposal data ([#4268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4268)) +- `Governor`: Added validation in ERC1155 and ERC721 receiver hooks to ensure Governor is the executor. ([#4314](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4314)) +- `Governor`: Refactored internals to implement common queuing logic in the core module of the Governor. Added `queue` and `_queueOperations` functions that act at different levels. Modules that implement queuing via timelocks are expected to override `_queueOperations` to implement the timelock-specific logic. Added `_executeOperations` as the equivalent for execution. ([#4360](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4360)) +- `Governor`: Added `voter` and `nonce` parameters in signed ballots, to avoid forging signatures for random addresses, prevent signature replay, and allow invalidating signatures. Add `voter` as a new parameter in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. ([#4378](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4378)) +- `Governor`: Added support for casting votes with ERC-1271 signatures by using a `bytes memory signature` instead of `r`, `s` and `v` arguments in the `castVoteBySig` and `castVoteWithReasonAndParamsBySig` functions. ([#4418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4418)) +- `Governor`: Added a mechanism to restrict the address of the proposer using a suffix in the description. +- `GovernorStorage`: Added a new governor extension that stores the proposal details in storage, with an interface that operates on `proposalId`, as well as proposal enumerability. This replaces the old `GovernorCompatibilityBravo` module. ([#4360](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4360)) +- `GovernorTimelockAccess`: Added a module to connect a governor with an instance of `AccessManager`, allowing the governor to make calls that are delay-restricted by the manager using the normal `queue` workflow. ([#4523](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4523)) +- `GovernorTimelockControl`: Clean up timelock id on execution for gas refund. ([#4118](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4118)) +- `GovernorTimelockControl`: Added the Governor instance address as part of the TimelockController operation `salt` to avoid operation id collisions between governors using the same TimelockController. ([#4432](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4432)) +- `TimelockController`: Changed the role architecture to use `DEFAULT_ADMIN_ROLE` as the admin for all roles, instead of the bespoke `TIMELOCK_ADMIN_ROLE` that was used previously. This aligns with the general recommendation for `AccessControl` and makes the addition of new roles easier. Accordingly, the `admin` parameter and timelock will now be granted `DEFAULT_ADMIN_ROLE` instead of `TIMELOCK_ADMIN_ROLE`. ([#3799](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3799)) +- `TimelockController`: Added a state getter that returns an `OperationState` enum. ([#4358](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4358)) +- `Votes`: Use Trace208 for checkpoints. This enables EIP-6372 clock support for keys but reduces the max supported voting power to uint208. ([#4539](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4539)) + +#### Metatx + +- `ERC2771Forwarder`: Added `deadline` for expiring transactions, batching, and more secure handling of `msg.value`. ([#4346](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4346)) +- `ERC2771Context`: Return the forwarder address whenever the `msg.data` of a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes), as specified by ERC-2771. ([#4481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4481)) +- `ERC2771Context`: Prevent revert in `_msgData()` when a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes). Return the full calldata in that case. ([#4484](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4484)) + +#### Proxy + +- `ProxyAdmin`: Removed `getProxyAdmin` and `getProxyImplementation` getters. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820)) +- `TransparentUpgradeableProxy`: Removed `admin` and `implementation` getters, which were only callable by the proxy owner and thus not very useful. ([#3820](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3820)) +- `ERC1967Utils`: Refactored the `ERC1967Upgrade` abstract contract as a library. ([#4325](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4325)) +- `TransparentUpgradeableProxy`: Admin is now stored in an immutable variable (set during construction) to avoid unnecessary storage reads on every proxy call. This removed the ability to ever change the admin. Transfer of the upgrade capability is exclusively handled through the ownership of the `ProxyAdmin`. ([#4354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4354)) +- Moved the logic to validate ERC-1822 during an upgrade from `ERC1967Utils` to `UUPSUpgradeable`. ([#4356](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4356)) +- `UUPSUpgradeable`, `TransparentUpgradeableProxy` and `ProxyAdmin`: Removed `upgradeTo` and `upgrade` functions, and made `upgradeToAndCall` and `upgradeAndCall` ignore the data argument if it is empty. It is no longer possible to invoke the receive function (or send value with empty data) along with an upgrade. ([#4382](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4382)) +- `BeaconProxy`: Reject value in initialization unless a payable function is explicitly invoked. ([#4382](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4382)) +- `Proxy`: Removed redundant `receive` function. ([#4434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4434)) +- `BeaconProxy`: Use an immutable variable to store the address of the beacon. It is no longer possible for a `BeaconProxy` to upgrade by changing to another beacon. ([#4435](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4435)) +- `Initializable`: Use the namespaced storage pattern to avoid putting critical variables in slot 0. Allow reinitializer versions greater than 256. ([#4460](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4460)) +- `Initializable`: Use intermediate variables to improve readability. ([#4576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4576)) + +#### Token + +- `ERC20`, `ERC721`, `ERC1155`: Deleted `_beforeTokenTransfer` and `_afterTokenTransfer` hooks, added a new internal `_update` function for customizations, and refactored all extensions using those hooks to use `_update` instead. ([#3838](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3838), [#3876](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3876), [#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4377)) +- `ERC20`: Removed `Approval` event previously emitted in `transferFrom` to indicate that part of the allowance was consumed. With this change, allowances are no longer reconstructible from events. See the code for guidelines on how to re-enable this event if needed. ([#4370](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4370)) +- `ERC20`: Removed the non-standard `increaseAllowance` and `decreaseAllowance` functions. ([#4585](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4585)) +- `ERC20Votes`: Changed internal vote accounting to reusable `Votes` module previously used by `ERC721Votes`. Removed implicit `ERC20Permit` inheritance. Note that the `DOMAIN_SEPARATOR` getter was previously guaranteed to be available for `ERC20Votes` contracts, but is no longer available unless `ERC20Permit` is explicitly used; ERC-5267 support is included in `ERC20Votes` with `EIP712` and is recommended as an alternative. ([#3816](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3816)) +- `SafeERC20`: Refactored `safeDecreaseAllowance` and `safeIncreaseAllowance` to support USDT-like tokens. ([#4260](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4260)) +- `SafeERC20`: Removed `safePermit` in favor of documentation-only `permit` recommendations. Based on recommendations from @trust1995 ([#4582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4582)) +- `ERC721`: `_approve` no longer allows approving the owner of the tokenId. ([#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/4377)) `_setApprovalForAll` no longer allows setting address(0) as an operator. ([#4377](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4377)) +- `ERC721`: Renamed `_requireMinted` to `_requireOwned` and added a return value with the current owner. Implemented `ownerOf` in terms of `_requireOwned`. ([#4566](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4566)) +- `ERC721Consecutive`: Added a `_firstConsecutiveId` internal function that can be overridden to change the id of the first token minted through `_mintConsecutive`. ([#4097](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4097)) +- `ERC721URIStorage`: Allow setting the token URI prior to minting. ([#4559](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4559)) +- `ERC721URIStorage`, `ERC721Royalty`: Stop resetting token-specific URI and royalties when burning. ([#4561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4561)) +- `ERC1155`: Optimized array allocation. ([#4196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4196)) +- `ERC1155`: Removed check for address zero in `balanceOf`. ([#4263](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4263)) +- `ERC1155`: Optimized array accesses by skipping bounds checking when unnecessary. ([#4300](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4300)) +- `ERC1155`: Bubble errors triggered in the `onERC1155Received` and `onERC1155BatchReceived` hooks. ([#4314](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4314)) +- `ERC1155Supply`: Added a `totalSupply()` function that returns the total amount of token circulating, this change will restrict the total tokens minted across all ids to 2**256-1 . ([#3962](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3962)) +- `ERC1155Receiver`: Removed in favor of `ERC1155Holder`. ([#4450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4450)) + +#### Utils + +- `Address`: Removed the ability to customize error messages. A common custom error is always used if the underlying revert reason cannot be bubbled up. ([#4502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4502)) +- `Arrays`: Added `unsafeMemoryAccess` helpers to read from a memory array without checking the length. ([#4300](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4300)) +- `Arrays`: Optimized `findUpperBound` by removing redundant SLOAD. ([#4442](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4442)) +- `Checkpoints`: Library moved from `utils` to `utils/structs` ([#4275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4275)) +- `DoubleEndedQueue`: Refactored internal structure to use `uint128` instead of `int128`. This has no effect on the library interface. ([#4150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4150)) +- `ECDSA`: Use unchecked arithmetic for the `tryRecover` function that receives the `r` and `vs` short-signature fields separately. ([#4301](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4301)) +- `EIP712`: Added internal getters for the name and version strings ([#4303](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4303)) +- `Math`: Makes `ceilDiv` to revert on 0 division even if the numerator is 0 ([#4348](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4348)) +- `Math`: Optimized stack operations in `mulDiv`. ([#4494](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4494)) +- `Math`: Renamed members of `Rounding` enum, and added a new rounding mode for "away from zero". ([#4455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4455)) +- `MerkleProof`: Use custom error to report invalid multiproof instead of reverting with overflow panic. ([#4564](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4564)) +- `MessageHashUtils`: Added a new library for creating message digest to be used along with signing or recovery such as ECDSA or ERC-1271. These functions are moved from the `ECDSA` library. ([#4430](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4430)) +- `Nonces`: Added a new contract to keep track of user nonces. Used for signatures in `ERC20Permit`, `ERC20Votes`, and `ERC721Votes`. ([#3816](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3816)) +- `ReentrancyGuard`, `Pausable`: Moved to `utils` directory. ([#4551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4551)) +- `Strings`: Renamed `toString(int256)` to `toStringSigned(int256)`. ([#4330](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4330)) +- Optimized `Strings.equal` ([#4262](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4262)) + +### How to migrate from 4.x + +#### ERC20, ERC721, and ERC1155 + +These breaking changes will require modifications to ERC20, ERC721, and ERC1155 contracts, since the `_afterTokenTransfer` and `_beforeTokenTransfer` functions were removed. Thus, any customization made through those hooks should now be done overriding the new `_update` function instead. + +Minting and burning are implemented by `_update` and customizations should be done by overriding this function as well. `_transfer`, `_mint` and `_burn` are no longer virtual (meaning they are not overridable) to guard against possible inconsistencies. + +For example, a contract using `ERC20`'s `_beforeTokenTransfer` hook would have to be changed in the following way. + +```diff +-function _beforeTokenTransfer( ++function _update( + address from, + address to, + uint256 amount + ) internal virtual override { +- super._beforeTokenTransfer(from, to, amount); + require(!condition(), "ERC20: wrong condition"); ++ super._update(from, to, amount); + } +``` + +#### More about ERC721 + +In the case of `ERC721`, the `_update` function does not include a `from` parameter, as the sender is implicitly the previous owner of the `tokenId`. The address of this previous owner is returned by the `_update` function, so it can be used for a posteriori checks. In addition to `to` and `tokenId`, a third parameter (`auth`) is present in this function. This parameter enabled an optional check that the caller/spender is approved to do the transfer. This check cannot be performed after the transfer (because the transfer resets the approval), and doing it before `_update` would require a duplicate call to `_ownerOf`. + +In this logic of removing hidden SLOADs, the `_isApprovedOrOwner` function was removed in favor of a new `_isAuthorized` function. Overrides that used to target the `_isApprovedOrOwner` should now be performed on the `_isAuthorized` function. Calls to `_isApprovedOrOwner` that preceded a call to `_transfer`, `_burn` or `_approve` should be removed in favor of using the `auth` argument in `_update` and `_approve`. This is showcased in `ERC721Burnable.burn` and in `ERC721Wrapper.withdrawTo`. + +The `_exists` function was removed. Calls to this function can be replaced by `_ownerOf(tokenId) != address(0)`. + +#### ERC165Storage + +Users that were registering EIP-165 interfaces with `_registerInterface` from `ERC165Storage` should instead do so so by overriding the `supportsInterface` function as seen below: + +```solidity +function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); +} +``` + +#### Adapting Governor modules + +Custom Governor modules that override internal functions may require modifications if migrated to v5. In particular, the new internal functions `_queueOperations` and `_executeOperations` may need to be used. If assistance with this migration is needed reach out via the [OpenZeppelin Support Forum](https://forum.openzeppelin.com/c/support/contracts/18). + +#### ECDSA and MessageHashUtils + +The `ECDSA` library is now focused on signer recovery. Previously it also included utility methods for producing digests to be used with signing or recovery. These utilities have been moved to the `MessageHashUtils` library and should be imported if needed: + +```diff + import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; ++import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; + + contract Verifier { + using ECDSA for bytes32; ++ using MessageHashUtils for bytes32; + + function _verify(bytes32 data, bytes memory signature, address account) internal pure returns (bool) { + return data + .toEthSignedMessageHash() + .recover(signature) == account; + } + } +``` + +#### Interfaces and libraries in upgradeable contracts + +The upgradeable version of the contracts library used to include a variant suffixed with `Upgradeable` for every contract. These variants, which are produced automatically, mainly include changes for dealing with storage that don't apply to libraries and interfaces. + +The upgradeable library no longer includes upgradeable variants for libraries and interfaces. Projects migrating to 5.0 should replace their library and interface imports with their corresponding non-upgradeable version: + +```diff + // Libraries +-import {AddressUpgradeable} from '@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol'; ++import {Address} from '@openzeppelin/contracts/utils/Address.sol'; + + // Interfaces +-import {IERC20Upgradeable} from '@openzeppelin/contracts-upgradeable/interfaces/IERC20.sol'; ++import {IERC20} from '@openzeppelin/contracts/interfaces/IERC20.sol'; +``` + +#### Offchain Considerations + +Some changes may affect offchain systems if they rely on assumptions that are changed along with these new breaking changes. These cases are: + +##### Relying on revert strings for processing errors + +A concrete example is AccessControl, where it was previously advised to catch revert reasons using the following regex: + +``` +/^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/ +``` + +Instead, contracts now revert with custom errors. Systems that interact with smart contracts outside of the network should consider reliance on revert strings and possibly support the new custom errors. + +##### Relying on storage locations for retrieving data + +After 5.0, the storage location of some variables were changed. This is the case for `Initializable` and all the upgradeable contracts since they now use namespaced storaged locations. Any system relying on storage locations for retrieving data or detecting capabilities should be updated to support these new locations. + +## 4.9.2 (2023-06-16) + +- `MerkleProof`: Fix a bug in `processMultiProof` and `processMultiProofCalldata` that allows proving arbitrary leaves if the tree contains a node with value 0 at depth 1. + +## 4.9.1 (2023-06-07) + +- `Governor`: Add a mechanism to restrict the address of the proposer using a suffix in the description. + +## 4.9.0 (2023-05-23) + +- `ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714)) +- `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. ([#3863](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3863)) +- `EnumerableMap`: add a `keys()` function that returns an array containing all the keys. ([#3920](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3920)) +- `Governor`: add a public `cancel(uint256)` function. ([#3983](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3983)) +- `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. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934)) +- `Strings`: add `equal` method. ([#3774](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3774)) +- `IERC5313`: Add an interface for EIP-5313 that is now final. ([#4013](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4013)) +- `IERC4906`: Add an interface for ERC-4906 that is now Final. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012)) +- `StorageSlot`: Add support for `string` and `bytes`. ([#4008](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4008)) +- `Votes`, `ERC20Votes`, `ERC721Votes`: support timestamp checkpointing using EIP-6372. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934)) +- `ERC4626`: Add mitigation to the inflation attack through virtual shares and assets. ([#3979](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3979)) +- `Strings`: add `toString` method for signed integers. ([#3773](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3773)) +- `ERC20Wrapper`: Make the `underlying` variable private and add a public accessor. ([#4029](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4029)) +- `EIP712`: add EIP-5267 support for better domain discovery. ([#3969](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3969)) +- `AccessControlDefaultAdminRules`: Add an extension of `AccessControl` with additional security rules for the `DEFAULT_ADMIN_ROLE`. ([#4009](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4009)) +- `SignatureChecker`: Add `isValidERC1271SignatureNow` for checking a signature directly against a smart contract using ERC-1271. ([#3932](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3932)) +- `SafeERC20`: Add a `forceApprove` function to improve compatibility with tokens behaving like USDT. ([#4067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4067)) +- `ERC1967Upgrade`: removed contract-wide `oz-upgrades-unsafe-allow delegatecall` annotation, replaced by granular annotation in `UUPSUpgradeable`. ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971)) +- `ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitly forbidden. ([#4100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4100)) +- `ECDSA`: optimize bytes32 computation by using assembly instead of `abi.encodePacked`. ([#3853](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3853)) +- `ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012)) +- `ShortStrings`: Added a library for handling short strings in a gas efficient way, with fallback to storage for longer strings. ([#4023](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4023)) +- `SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers. ([#4038](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4038)) +- `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`). ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971)) +- `Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. ([#3787](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3787)) +- `Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. ([#3960](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3960)) +- `UUPSUpgradeable.sol`: Change visibility to the functions `upgradeTo ` and `upgradeToAndCall ` from `external` to `public`. ([#3959](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3959)) +- `TimelockController`: Add the `CallSalt` event to emit on operation schedule. ([#4001](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4001)) +- Reformatted codebase with latest version of Prettier Solidity. ([#3898](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3898)) +- `Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) +- `ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748)) +- `Multicall`: annotate `multicall` function as upgrade safe to not raise a flag for its delegatecall. ([#3961](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3961)) +- `ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality ([#4007](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4007)) +- `ECDSA`: Add a function `toDataWithIntendedValidatorHash` that encodes data with version 0x00 following EIP-191. ([#4063](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4063)) +- `MerkleProof`: optimize by using unchecked arithmetic. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) + +### 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)) +- `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.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`. + +### 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)) + +## 4.8.0 (2022-11-08) + +- `TimelockController`: Added a new `admin` constructor parameter that is assigned the admin role instead of the deployer account. ([#3722](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3722)) +- `Initializable`: add internal functions `_getInitializedVersion` and `_isInitializing` ([#3598](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3598)) +- `ERC165Checker`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339)) +- `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468)) +- `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469)) +- `Governor`: make the `relay` function payable, and add support for EOA payments. ([#3730](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3730)) +- `GovernorCompatibilityBravo`: remove unused `using` statements. ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506)) +- `ERC20`: optimize `_transfer`, `_mint` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) +- `ERC20Votes`, `ERC721Votes`: optimize `getPastVotes` for looking up recent checkpoints. ([#3673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3673)) +- `ERC20FlashMint`: add an internal `_flashFee` function for overriding. ([#3551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3551)) +- `ERC4626`: use the same `decimals()` as the underlying asset by default (if available). ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639)) +- `ERC4626`: add internal `_initialConvertToShares` and `_initialConvertToAssets` functions to customize empty vaults behavior. ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639)) +- `ERC721`: optimize transfers by making approval clearing implicit instead of emitting an event. ([#3481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3481)) +- `ERC721`: optimize burn by making approval clearing implicit instead of emitting an event. ([#3538](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3538)) +- `ERC721`: Fix balance accounting when a custom `_beforeTokenTransfer` hook results in a transfer of the token under consideration. ([#3611](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3611)) +- `ERC721`: use unchecked arithmetic for balance updates. ([#3524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3524)) +- `ERC721Consecutive`: Implementation of EIP-2309 that allows batch minting of ERC721 tokens during construction. ([#3311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3311)) +- `ReentrancyGuard`: Reduce code size impact of the modifier by using internal functions. ([#3515](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3515)) +- `SafeCast`: optimize downcasting of signed integers. ([#3565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3565)) +- `ECDSA`: Remove redundant check on the `v` value. ([#3591](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3591)) +- `VestingWallet`: add `releasable` getters. ([#3580](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3580)) +- `VestingWallet`: remove unused library `Math.sol`. ([#3605](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3605)) +- `VestingWallet`: make constructor payable. ([#3665](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3665)) +- `Create2`: optimize address computation by using assembly instead of `abi.encodePacked`. ([#3600](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3600)) +- `Clones`: optimized the assembly to use only the scratch space during deployments, and optimized `predictDeterministicAddress` to use fewer operations. ([#3640](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3640)) +- `Checkpoints`: Use procedural generation to support multiple key/value lengths. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Checkpoints`: Add new lookup mechanisms. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Arrays`: Add `unsafeAccess` functions that allow reading and writing to an element in a storage array bypassing Solidity's "out-of-bounds" check. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Strings`: optimize `toString`. ([#3573](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3573)) +- `Ownable2Step`: extension of `Ownable` that makes the ownership transfers a two step process. ([#3620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620)) +- `Math` and `SignedMath`: optimize function `max` by using `>` instead of `>=`. ([#3679](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3679)) +- `Math`: Add `log2`, `log10` and `log256`. ([#3670](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3670)) +- Arbitrum: Update the vendored arbitrum contracts to match the nitro upgrade. ([#3692](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3692)) + +### Breaking changes + +- `ERC721`: In order to add support for batch minting via `ERC721Consecutive` it was necessary to make a minor breaking change in the internal interface of `ERC721`. Namely, the hooks `_beforeTokenTransfer` and `_afterTokenTransfer` have one additional argument that may need to be added to overrides: + +```diff + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId, ++ uint256 batchSize + ) internal virtual override +``` + +- `ERC4626`: Conversion from shares to assets (and vice-versa) in an empty vault used to consider the possible mismatch between the underlying asset's and the vault's decimals. This initial conversion rate is now set to 1-to-1 irrespective of decimals, which are meant for usability purposes only. The vault now uses the assets decimals by default, so off-chain the numbers should appear the same. Developers overriding the vault decimals to a value that does not match the underlying asset may want to override the `_initialConvertToShares` and `_initialConvertToAssets` to replicate the previous behavior. + +- `TimelockController`: During deployment, the TimelockController used to grant the `TIMELOCK_ADMIN_ROLE` to the deployer and to the timelock itself. The deployer was then expected to renounce this role once configuration of the timelock is over. Failing to renounce that role allows the deployer to change the timelock permissions (but not to bypass the delay for any time-locked actions). The role is no longer given to the deployer by default. A new parameter `admin` can be set to a non-zero address to grant the admin role during construction (to the deployer or any other address). Just like previously, this admin role should be renounced after configuration. If this param is given `address(0)`, the role is not allocated and doesn't need to be revoked. In any case, the timelock itself continues to have this role. + +### Deprecations + +- `EIP712`: Added the file `EIP712.sol` and deprecated `draft-EIP712.sol` since the EIP is no longer a Draft. Developers are encouraged to update their imports. ([#3621](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3621)) + +```diff +-import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; ++import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +``` + +- `ERC721Votes`: Added the file `ERC721Votes.sol` and deprecated `draft-ERC721Votes.sol` since it no longer depends on a Draft EIP (EIP-712). Developers are encouraged to update their imports. ([#3699](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3699)) + +```diff +-import "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol"; ++import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol"; +``` + +### ERC-721 Compatibility Note + +ERC-721 integrators that interpret contract state from events should make sure that they implement the clearing of approval that is implicit in every transfer according to the EIP. Previous versions of OpenZeppelin Contracts emitted an explicit `Approval` event even though it was not required by the specification, and this is no longer the case. + +With the new `ERC721Consecutive` extension, the internal workings of `ERC721` are slightly changed. Custom extensions to ERC721 should be reviewed to ensure they remain correct. The internal functions that should be considered are `_ownerOf` (new), `_beforeTokenTransfer`, and `_afterTokenTransfer`. + +### ERC-4626 Upgrade Note + +Existing `ERC4626` contracts that are upgraded to 4.8 must initialize a new variable that holds the vault token decimals. The recommended way to do this is to use a [reinitializer]: + +[reinitializer]: https://docs.openzeppelin.com/contracts/4.x/api/proxy#Initializable-reinitializer-uint8- + +```solidity +function migrateToV48() public reinitializer(2) { + __ERC4626_init(IERC20Upgradeable(asset())); +} +``` + +## 4.7.3 (2022-08-10) + +### Breaking changes + +- `ECDSA`: `recover(bytes32,bytes)` and `tryRecover(bytes32,bytes)` no longer accept compact signatures to prevent malleability. Compact signature support remains available using `recover(bytes32,bytes32,bytes32)` and `tryRecover(bytes32,bytes32,bytes32)`. + +## 4.7.2 (2022-07-25) + +- `LibArbitrumL2`, `CrossChainEnabledArbitrumL2`: Fixed detection of cross-chain calls for EOAs. Previously, calls from EOAs would be classified as cross-chain calls. ([#3578](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3578)) +- `GovernorVotesQuorumFraction`: Fixed quorum updates so they do not affect past proposals that failed due to lack of quorum. ([#3561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3561)) +- `ERC165Checker`: Added protection against large returndata. ([#3587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3587)) + +## 4.7.1 (2022-07-18) + +- `SignatureChecker`: Fix an issue that causes `isValidSignatureNow` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552)) +- `ERC165Checker`: Fix an issue that causes `supportsInterface` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552)) + +## 4.7.0 (2022-06-29) + +- `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317)) +- `CrossChainEnabledPolygonChild`: replace the `require` statement with the custom error `NotCrossChainCall`. ([#3380](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3380)) +- `ERC20FlashMint`: Add customizable flash fee receiver. ([#3327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3327)) +- `ERC4626`: add an extension of `ERC20` that implements the ERC4626 Tokenized Vault Standard. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171)) +- `SafeERC20`: add `safePermit` as mitigation against phantom permit functions. ([#3280](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3280)) +- `Math`: add a `mulDiv` function that can round the result either up or down. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171)) +- `Math`: Add a `sqrt` function to compute square roots of integers, rounding either up or down. ([#3242](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3242)) +- `Strings`: add a new overloaded function `toHexString` that converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. ([#3403](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3403)) +- `EnumerableMap`: add new `UintToUintMap` map type. ([#3338](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3338)) +- `EnumerableMap`: add new `Bytes32ToUintMap` map type. ([#3416](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3416)) +- `SafeCast`: add support for many more types, using procedural code generation. ([#3245](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3245)) +- `MerkleProof`: add `multiProofVerify` to prove multiple values are part of a Merkle tree. ([#3276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3276)) +- `MerkleProof`: add calldata versions of the functions to avoid copying input arrays to memory and save gas. ([#3200](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3200)) +- `ERC721`, `ERC1155`: simplified revert reasons. ([#3254](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3254), ([#3438](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3438))) +- `ERC721`: removed redundant require statement. ([#3434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3434)) +- `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350)) +- `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450)) +- `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) + +### Breaking changes + +- `Initializable`: functions decorated with the modifier `reinitializer(1)` may no longer invoke each other. + +## 4.6.0 (2022-04-26) + +- `crosschain`: Add a new set of contracts for cross-chain applications. `CrossChainEnabled` is a base contract with instantiations for several chains and bridges, and `AccessControlCrossChain` is an extension of access control that allows cross-chain operation. ([#3183](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3183)) +- `AccessControl`: add a virtual `_checkRole(bytes32)` function that can be overridden to alter the `onlyRole` modifier behavior. ([#3137](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3137)) +- `EnumerableMap`: add new `AddressToUintMap` map type. ([#3150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3150)) +- `EnumerableMap`: add new `Bytes32ToBytes32Map` map type. ([#3192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3192)) +- `ERC20FlashMint`: support infinite allowance when paying back a flash loan. ([#3226](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3226)) +- `ERC20Wrapper`: the `decimals()` function now tries to fetch the value from the underlying token instance. If that calls revert, then the default value is used. ([#3259](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3259)) +- `draft-ERC20Permit`: replace `immutable` with `constant` for `_PERMIT_TYPEHASH` since the `keccak256` of string literals is treated specially and the hash is evaluated at compile time. ([#3196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3196)) +- `ERC1155`: Add a `_afterTokenTransfer` hook for improved extensibility. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166)) +- `ERC1155URIStorage`: add a new extension that implements a `_setURI` behavior similar to ERC721's `_setTokenURI`. ([#3210](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3210)) +- `DoubleEndedQueue`: a new data structure that supports efficient push and pop to both front and back, useful for FIFO and LIFO queues. ([#3153](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3153)) +- `Governor`: improved security of `onlyGovernance` modifier when using an external executor contract (e.g. a timelock) that can operate without necessarily going through the governance protocol. ([#3147](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3147)) +- `Governor`: Add a way to parameterize votes. This can be used to implement voting systems such as fractionalized voting, ERC721 based voting, or any number of other systems. The `params` argument added to `_countVote` method, and included in the newly added `_getVotes` method, can be used by counting and voting modules respectively for such purposes. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: rewording of revert reason for consistency. ([#3275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3275)) +- `Governor`: fix an inconsistency in data locations that could lead to invalid bytecode being produced. ([#3295](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3295)) +- `Governor`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by governors. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230)) +- `TimelockController`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by timelocks. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230)) +- `TimelockController`: Add a separate canceller role for the ability to cancel. ([#3165](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3165)) +- `Initializable`: add a reinitializer modifier that enables the initialization of new modules, added to already initialized contracts through upgradeability. ([#3232](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3232)) +- `Initializable`: add an Initialized event that tracks initialized version numbers. ([#3294](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3294)) +- `ERC2981`: make `royaltyInfo` public to allow super call in overrides. ([#3305](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3305)) + +### Upgradeability notice + +- `TimelockController`: **(Action needed)** The upgrade from <4.6 to >=4.6 introduces a new `CANCELLER_ROLE` that requires set up to be assignable. After the upgrade, only addresses with this role will have the ability to cancel. Proposers will no longer be able to cancel. Assigning cancellers can be done by an admin (including the timelock itself) once the role admin is set up. To do this, we recommend upgrading to the `TimelockControllerWith46MigrationUpgradeable` contract and then calling the `migrateTo46` function. + +### Breaking changes + +- `Governor`: Adds internal virtual `_getVotes` method that must be implemented; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing voting module extension, rename `getVotes` to `_getVotes` and add a `bytes memory` argument. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: Adds `params` parameter to internal virtual `_countVote` method; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing counting module extension, add a `bytes memory` argument to `_countVote`. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: Does not emit `VoteCast` event when params data is non-empty; instead emits `VoteCastWithParams` event. To fix this on an integration that consumes the `VoteCast` event, also fetch/monitor `VoteCastWithParams` events. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Votes`: The internal virtual function `_getVotingUnits` was made `view` (which was accidentally missing). Any overrides should now be updated so they are `view` as well. + +## 4.5.0 (2022-02-09) + +- `ERC2981`: add implementation of the royalty standard, and the respective extensions for `ERC721` and `ERC1155`. ([#3012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3012)) +- `GovernorTimelockControl`: improve the `state()` function to have it reflect cases where a proposal has been canceled directly on the timelock. ([#2977](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2977)) +- Preset contracts are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com). ([#2986](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2986)) +- `Governor`: add a relay function to help recover assets sent to a governor that is not its own executor (e.g. when using a timelock). ([#2926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2926)) +- `GovernorPreventLateQuorum`: add new module to ensure a minimum voting duration is available after the quorum is reached. ([#2973](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2973)) +- `ERC721`: improved revert reason when transferring from wrong owner. ([#2975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2975)) +- `Votes`: Added a base contract for vote tracking with delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944)) +- `ERC721Votes`: Added an extension of ERC721 enabled with vote tracking and delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944)) +- `ERC2771Context`: use immutable storage to store the forwarder address, no longer an issue since Solidity >=0.8.8 allows reading immutable variables in the constructor. ([#2917](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2917)) +- `Base64`: add a library to parse bytes into base64 strings using `encode(bytes memory)` function, and provide examples to show how to use to build URL-safe `tokenURIs`. ([#2884](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2884)) +- `ERC20`: reduce allowance before triggering transfer. ([#3056](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3056)) +- `ERC20`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085)) +- `ERC20`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `ERC20Burnable`: do not update allowance on `burnFrom` when allowance is `type(uint256).max`. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `ERC777`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085)) +- `ERC777`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `SignedMath`: a new signed version of the Math library with `max`, `min`, and `average`. ([#2686](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2686)) +- `SignedMath`: add an `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984)) +- `ERC1967Upgrade`: Refactor the secure upgrade to use `ERC1822` instead of the previous rollback mechanism. This reduces code complexity and attack surface with similar security guarantees. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021)) +- `UUPSUpgradeable`: Add `ERC1822` compliance to support the updated secure upgrade mechanism. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021)) +- Some more functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. + +### Breaking changes + +- `ERC1967Upgrade`: The function `_upgradeToAndCallSecure` was renamed to `_upgradeToAndCallUUPS`, along with the change in security mechanism described above. +- `Address`: The Solidity pragma is increased from `^0.8.0` to `^0.8.1`. This is required by the `account.code.length` syntax that replaces inline assembly. This may require users to bump their compiler version from `0.8.0` to `0.8.1` or later. Note that other parts of the code already include stricter requirements. + +## 4.4.2 (2022-01-11) + +### Bugfixes + +- `GovernorCompatibilityBravo`: Fix error in the encoding of calldata for proposals submitted through the compatibility interface with explicit signatures. ([#3100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3100)) + +## 4.4.1 (2021-12-14) + +- `Initializable`: change the existing `initializer` modifier and add a new `onlyInitializing` modifier to prevent reentrancy risk. ([#3006](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3006)) + +### Breaking change + +It is no longer possible to call an `initializer`-protected function from within another `initializer` function outside the context of a constructor. Projects using OpenZeppelin upgradeable proxies should continue to work as is, since in the common case the initializer is invoked in the constructor directly. If this is not the case for you, the suggested change is to use the new `onlyInitializing` modifier in the following way: + +```diff + contract A { +- function initialize() public initializer { ... } ++ function initialize() internal onlyInitializing { ... } + } + contract B is A { + function initialize() public initializer { + A.initialize(); + } + } +``` + +## 4.4.0 (2021-11-25) + +- `Ownable`: add an internal `_transferOwnership(address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControl`: add internal `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControl`: mark `_setupRole(bytes32,address)` as deprecated in favor of `_grantRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControlEnumerable`: hook into `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2946](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2946)) +- `EIP712`: cache `address(this)` to immutable storage to avoid potential issues if a vanilla contract is used in a delegatecall context. ([#2852](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2852)) +- Add internal `_setApprovalForAll` to `ERC721` and `ERC1155`. ([#2834](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2834)) +- `Governor`: shift vote start and end by one block to better match Compound's GovernorBravo and prevent voting at the Governor level if the voting snapshot is not ready. ([#2892](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2892)) +- `GovernorCompatibilityBravo`: consider quorum an inclusive rather than exclusive minimum to match Compound's GovernorBravo. ([#2974](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2974)) +- `GovernorSettings`: a new governor module that manages voting settings updatable through governance actions. ([#2904](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2904)) +- `PaymentSplitter`: now supports ERC20 assets in addition to Ether. ([#2858](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2858)) +- `ECDSA`: add a variant of `toEthSignedMessageHash` for arbitrary length message hashing. ([#2865](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2865)) +- `MerkleProof`: add a `processProof` function that returns the rebuilt root hash given a leaf and a proof. ([#2841](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2841)) +- `VestingWallet`: new contract that handles the vesting of Ether and ERC20 tokens following a customizable vesting schedule. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2748)) +- `Governor`: enable receiving Ether when a Timelock contract is not used. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849)) +- `GovernorTimelockCompound`: fix ability to use Ether stored in the Timelock contract. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849)) + +## 4.3.3 (2021-11-08) + +- `ERC1155Supply`: Handle `totalSupply` changes by hooking into `_beforeTokenTransfer` to ensure consistency of balances and supply during `IERC1155Receiver.onERC1155Received` calls. + +## 4.3.2 (2021-09-14) + +- `UUPSUpgradeable`: Add modifiers to prevent `upgradeTo` and `upgradeToAndCall` being executed on any contract that is not the active ERC1967 proxy. This prevents these functions being called on implementation contracts or minimal ERC1167 clones, in particular. + +## 4.3.1 (2021-08-26) + +- `TimelockController`: Add additional isOperationReady check. + +## 4.3.0 (2021-08-17) + +- `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754)) +- `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768)) +- `Governor`: added a modular system of `Governor` contracts based on `GovernorAlpha` and `GovernorBravo`. ([#2672](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2672)) +- Add an `interfaces` folder containing solidity interfaces to final ERCs. ([#2517](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2517)) +- `ECDSA`: add `tryRecover` functions that will not throw if the signature is invalid, and will return an error flag instead. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661)) +- `SignatureChecker`: Reduce gas usage of the `isValidSignatureNow` function for the "signature by EOA" case. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661)) + +## 4.2.0 (2021-06-30) + +- `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632)) +- `ERC20VotesComp`: Variant of `ERC20Votes` that is compatible with Compound's `Comp` token interface but restricts supply to `uint96`. ([#2706](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2706)) +- `ERC20Wrapper`: add a new extension of the `ERC20` token which wraps an underlying token. Deposit and withdraw guarantee that the total supply is backed by a corresponding amount of underlying token. ([#2633](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2633)) +- Enumerables: Improve gas cost of removal in `EnumerableSet` and `EnumerableMap`. +- Enumerables: Improve gas cost of lookup in `EnumerableSet` and `EnumerableMap`. +- `Counter`: add a reset method. ([#2678](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2678)) +- Tokens: Wrap definitely safe subtractions in `unchecked` blocks. +- `Math`: Add a `ceilDiv` method for performing ceiling division. +- `ERC1155Supply`: add a new `ERC1155` extension that keeps track of the totalSupply of each tokenId. ([#2593](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2593)) +- `BitMaps`: add a new `BitMaps` library that provides a storage efficient datastructure for `uint256` to `bool` mapping with contiguous keys. ([#2710](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2710)) + +### Breaking Changes + +- `ERC20FlashMint` is no longer a Draft ERC. ([#2673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2673))) + +**How to update:** Change your import paths by removing the `draft-` prefix from `@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20FlashMint.sol`. + +> See [Releases and Stability: Drafts](https://docs.openzeppelin.com/contracts/4.x/releases-stability#drafts). + +## 4.1.0 (2021-04-29) + +- `IERC20Metadata`: add a new extended interface that includes the optional `name()`, `symbol()` and `decimals()` functions. ([#2561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2561)) +- `ERC777`: make reception acquirement optional in `_mint`. ([#2552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2552)) +- `ERC20Permit`: add a `_useNonce` to enable further usage of ERC712 signatures. ([#2565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2565)) +- `ERC20FlashMint`: add an implementation of the ERC3156 extension for flash-minting ERC20 tokens. ([#2543](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2543)) +- `SignatureChecker`: add a signature verification library that supports both EOA and ERC1271 compliant contracts as signers. ([#2532](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2532)) +- `Multicall`: add abstract contract with `multicall(bytes[] calldata data)` function to bundle multiple calls together ([#2608](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2608)) +- `ECDSA`: add support for ERC2098 short-signatures. ([#2582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2582)) +- `AccessControl`: add an `onlyRole` modifier to restrict specific function to callers bearing a specific role. ([#2609](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2609)) +- `StorageSlot`: add a library for reading and writing primitive types to specific storage slots. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542)) +- UUPS Proxies: add `UUPSUpgradeable` to implement the UUPS proxy pattern together with `EIP1967Proxy`. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542)) + +### Breaking changes + +This release includes two small breaking changes in `TimelockController`. + +1. The `onlyRole` modifier in this contract was designed to let anyone through if the role was granted to `address(0)`, + allowing the possibility to to make a role "open", which can be used for `EXECUTOR_ROLE`. This modifier is now + replaced by `AccessControl.onlyRole`, which does not have this ability. The previous behavior was moved to the + modifier `TimelockController.onlyRoleOrOpenRole`. +2. It was possible to make `PROPOSER_ROLE` an open role (as described in the previous item) if it was granted to + `address(0)`. This would affect the `schedule`, `scheduleBatch`, and `cancel` operations in `TimelockController`. + This ability was removed as it does not make sense to open up the `PROPOSER_ROLE` in the same way that it does for + `EXECUTOR_ROLE`. + +## 4.0.0 (2021-03-23) + +- Now targeting the 0.8.x line of Solidity compilers. For 0.6.x (resp 0.7.x) support, use version 3.4.0 (resp 3.4.0-solc-0.7) of OpenZeppelin. +- `Context`: making `_msgData` return `bytes calldata` instead of `bytes memory` ([#2492](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2492)) +- `ERC20`: removed the `_setDecimals` function and the storage slot associated to decimals. ([#2502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2502)) +- `Strings`: addition of a `toHexString` function. ([#2504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2504)) +- `EnumerableMap`: change implementation to optimize for `key → value` lookups instead of enumeration. ([#2518](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2518)) +- `GSN`: deprecate GSNv1 support in favor of upcoming support for GSNv2. ([#2521](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2521)) +- `ERC165`: remove uses of storage in the base ERC165 implementation. ERC165 based contracts now use storage-less virtual functions. Old behavior remains available in the `ERC165Storage` extension. ([#2505](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2505)) +- `Initializable`: make initializer check stricter during construction. ([#2531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2531)) +- `ERC721`: remove enumerability of tokens from the base implementation. This feature is now provided separately through the `ERC721Enumerable` extension. ([#2511](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2511)) +- `AccessControl`: removed enumerability by default for a more lightweight contract. It is now opt-in through `AccessControlEnumerable`. ([#2512](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2512)) +- Meta Transactions: add `ERC2771Context` and a `MinimalForwarder` for meta-transactions. ([#2508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2508)) +- Overall reorganization of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503)) +- `ERC20Capped`: optimize gas usage by enforcing the check directly in `_mint`. ([#2524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2524)) +- Rename `UpgradeableProxy` to `ERC1967Proxy`. ([#2547](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2547)) +- `ERC777`: optimize the gas costs of the constructor. ([#2551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2551)) +- `ERC721URIStorage`: add a new extension that implements the `_setTokenURI` behavior as it was available in 3.4.0. ([#2555](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2555)) +- `AccessControl`: added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562)) +- `ERC1155`: make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576)) + +### Bug fixes for beta releases + +- `AccessControlEnumerable`: Fixed `renounceRole` not updating enumerable set of addresses for a role. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572)) + +### How to upgrade from 3.x + +Since this version has moved a few contracts to different directories, users upgrading from a previous version will need to adjust their import statements. To make this easier, the package includes a script that will migrate import statements automatically. After upgrading to the latest version of the package, run: + +``` +npx openzeppelin-contracts-migrate-imports +``` + +Make sure you're using git or another version control system to be able to recover from any potential error in our script. + +### How to upgrade from 4.0-beta.x + +Some further changes have been done between the different beta iterations. Transitions made during this period are configured in the `migrate-imports` script. Consequently, you can upgrade from any previous 4.0-beta.x version using the same script as described in the _How to upgrade from 3.x_ section. + +## 3.4.2 (2021-07-24) + +- `TimelockController`: Add additional isOperationReady check. + +## 3.4.1 (2021-03-03) + +- `ERC721`: made `_approve` an internal function (was private). + +## 3.4.0 (2021-02-02) + +- `BeaconProxy`: added new kind of proxy that allows simultaneous atomic upgrades. ([#2411](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2411)) +- `EIP712`: added helpers to verify EIP712 typed data signatures on chain. ([#2418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2418)) +- `ERC20Permit`: added an implementation of the ERC20 permit extension for gasless token approvals. ([#2237](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237)) +- Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399)) +- `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) +- `Clones`: added a library for deploying EIP 1167 minimal proxies. ([#2449](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2449)) +- `Context`: moved from `contracts/GSN` to `contracts/utils`. ([#2453](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2453)) +- `PaymentSplitter`: replace usage of `.transfer()` with `Address.sendValue` for improved compatibility with smart wallets. ([#2455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2455)) +- `UpgradeableProxy`: bubble revert reasons from initialization calls. ([#2454](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2454)) +- `SafeMath`: fix a memory allocation issue by adding new `SafeMath.tryOp(uint,uint)→(bool,uint)` functions. `SafeMath.op(uint,uint,string)→uint` are now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462)) +- `EnumerableMap`: fix a memory allocation issue by adding new `EnumerableMap.tryGet(uint)→(bool,address)` functions. `EnumerableMap.get(uint)→string` is now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462)) +- `ERC165Checker`: added batch `getSupportedInterfaces`. ([#2469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2469)) +- `RefundEscrow`: `beneficiaryWithdraw` will forward all available gas to the beneficiary. ([#2480](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2480)) +- Many view and pure functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. + +### Security Fixes + +- `ERC777`: fix potential reentrancy issues for custom extensions to `ERC777`. ([#2483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483)) + +If you're using our implementation of ERC777 from version 3.3.0 or earlier, and you define a custom `_beforeTokenTransfer` function that writes to a storage variable, you may be vulnerable to a reentrancy attack. If you're affected and would like assistance please write to security@openzeppelin.com. [Read more in the pull request.](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483) + +## 3.3.0 (2020-11-26) + +- Now supports both Solidity 0.6 and 0.7. Compiling with solc 0.7 will result in warnings. Install the `solc-0.7` tag to compile without warnings. +- `Address`: added `functionStaticCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) +- `TimelockController`: added a contract to augment access control schemes with a delay. ([#2354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2354)) +- `EnumerableSet`: added `Bytes32Set`, for sets of `bytes32`. ([#2395](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2395)) + +## 3.2.2-solc-0.7 (2020-10-28) + +- Resolve warnings introduced by Solidity 0.7.4. ([#2396](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2396)) + +## 3.2.1-solc-0.7 (2020-09-15) + +- `ERC777`: Remove a warning about function state visibility in Solidity 0.7. ([#2327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2327)) + +## 3.2.0 (2020-09-10) + +### New features + +- Proxies: added the proxy contracts from OpenZeppelin SDK. ([#2335](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2335)) + +#### Proxy changes with respect to OpenZeppelin SDK + +Aside from upgrading them from Solidity 0.5 to 0.6, we've changed a few minor things from the proxy contracts as they were found in OpenZeppelin SDK. + +- `UpgradeabilityProxy` was renamed to `UpgradeableProxy`. +- `AdminUpgradeabilityProxy` was renamed to `TransparentUpgradeableProxy`. +- `Proxy._willFallback` was renamed to `Proxy._beforeFallback`. +- `UpgradeabilityProxy._setImplementation` and `AdminUpgradeabilityProxy._setAdmin` were made private. + +### Improvements + +- `Address.isContract`: switched from `extcodehash` to `extcodesize` for less gas usage. ([#2311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2311)) + +### Breaking changes + +- `ERC20Snapshot`: switched to using `_beforeTokenTransfer` hook instead of overriding ERC20 operations. ([#2312](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2312)) + +This small change in the way we implemented `ERC20Snapshot` may affect users who are combining this contract with +other ERC20 flavors, since it no longer overrides `_transfer`, `_mint`, and `_burn`. This can result in having to remove Solidity `override(...)` specifiers in derived contracts for these functions, and to instead have to add it for `_beforeTokenTransfer`. See [Using Hooks](https://docs.openzeppelin.com/contracts/3.x/extending-contracts#using-hooks) in the documentation. + +## 3.1.0 (2020-06-23) + +### New features + +- `SafeCast`: added functions to downcast signed integers (e.g. `toInt32`), improving usability of `SignedSafeMath`. ([#2243](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2243)) +- `functionCall`: new helpers that replicate Solidity's function call semantics, reducing the need to rely on `call`. ([#2264](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2264)) +- `ERC1155`: added support for a base implementation, non-standard extensions and a preset contract. ([#2014](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2014), [#2230](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2230)) + +### Improvements + +- `ReentrancyGuard`: reduced overhead of using the `nonReentrant` modifier. ([#2171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2171)) +- `AccessControl`: added a `RoleAdminChanged` event to `_setAdminRole`. ([#2214](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2214)) +- Made all `public` functions in the token preset contracts `virtual`. ([#2257](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2257)) + +### Deprecations + +- `SafeERC20`: deprecated `safeApprove`. ([#2268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2268)) + +## 3.0.2 (2020-06-08) + +### Improvements + +- Added SPX license identifier to all contracts. ([#2235](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2235)) + +## 3.0.1 (2020-04-27) + +### Bugfixes + +- `ERC777`: fixed the `_approve` internal function not validating some of their arguments for non-zero addresses. ([#2213](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2213)) + +## 3.0.0 (2020-04-20) + +### New features + +- `AccessControl`: new contract for managing permissions in a system, replacement for `Ownable` and `Roles`. ([#2112](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2112)) +- `SafeCast`: new functions to convert to and from signed and unsigned values: `toUint256` and `toInt256`. ([#2123](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2123)) +- `EnumerableMap`: a new data structure for key-value pairs (like `mapping`) that can be iterated over. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) + +### Breaking changes + +- `ERC721`: `burn(owner, tokenId)` was removed, use `burn(tokenId)` instead. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `ERC721`: `_checkOnERC721Received` was removed. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `ERC721`: `_transferFrom` and `_safeTransferFrom` were renamed to `_transfer` and `_safeTransfer`. ([#2162](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2162)) +- `Ownable`: removed `_transferOwnership`. ([#2162](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2162)) +- `PullPayment`, `Escrow`: `withdrawWithGas` was removed. The old `withdraw` function now forwards all gas. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `Roles` was removed, use `AccessControl` as a replacement. ([#2112](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2112)) +- `ECDSA`: when receiving an invalid signature, `recover` now reverts instead of returning the zero address. ([#2114](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2114)) +- `Create2`: added an `amount` argument to `deploy` for contracts with `payable` constructors. ([#2117](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2117)) +- `Pausable`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Strings`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Counters`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `SignedSafeMath`: moved to the `math` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `ERC20Snapshot`: moved to the `token/ERC20` directory. `snapshot` was changed into an `internal` function. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Ownable`: moved to the `access` directory. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Ownable`: removed `isOwner`. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Secondary`: removed from the library, use `Ownable` instead. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Escrow`, `ConditionalEscrow`, `RefundEscrow`: these now use `Ownable` instead of `Secondary`, their external API changed accordingly. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `ERC20`: removed `_burnFrom`. ([#2119](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2119)) +- `Address`: removed `toPayable`, use `payable(address)` instead. ([#2133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2133)) +- `ERC777`: `_send`, `_mint` and `_burn` now use the caller as the operator. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134)) +- `ERC777`: removed `_callsTokensToSend` and `_callTokensReceived`. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134)) +- `EnumerableSet`: renamed `get` to `at`. ([#2151](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2151)) +- `ERC165Checker`: functions no longer have a leading underscore. ([#2150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2150)) +- `ERC721Metadata`, `ERC721Enumerable`: these contracts were removed, and their functionality merged into `ERC721`. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) +- `ERC721`: added a constructor for `name` and `symbol`. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) +- `ERC20Detailed`: this contract was removed and its functionality merged into `ERC20`. ([#2161](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2161)) +- `ERC20`: added a constructor for `name` and `symbol`. `decimals` now defaults to 18. ([#2161](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2161)) +- `Strings`: renamed `fromUint256` to `toString` ([#2188](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2188)) + +## 2.5.1 (2020-04-24) + +### Bugfixes + +- `ERC777`: fixed the `_send` and `_approve` internal functions not validating some of their arguments for non-zero addresses. ([#2212](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2212)) + +## 2.5.0 (2020-02-04) + +### New features + +- `SafeCast.toUintXX`: new library for integer downcasting, which allows for safe operation on smaller types (e.g. `uint32`) when combined with `SafeMath`. ([#1926](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1926)) +- `ERC721Metadata`: added `baseURI`, which can be used for dramatic gas savings when all token URIs share a prefix (e.g. `http://api.myapp.com/tokens/`). ([#1970](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1970)) +- `EnumerableSet`: new library for storing enumerable sets of values. Only `AddressSet` is supported in this release. ([#2061](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/2061)) +- `Create2`: simple library to make usage of the `CREATE2` opcode easier. ([#1744](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1744)) + +### Improvements + +- `ERC777`: `_burn` is now internal, providing more flexibility and making it easier to create tokens that deflate. ([#1908](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1908)) +- `ReentrancyGuard`: greatly improved gas efficiency by using the net gas metering mechanism introduced in the Istanbul hardfork. ([#1992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1992), [#1996](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1996)) +- `ERC777`: improve extensibility by making `_send` and related functions `internal`. ([#2027](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2027)) +- `ERC721`: improved revert reason when transferring tokens to a non-recipient contract. ([#2018](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018)) + +### Breaking changes + +- `ERC165Checker` now requires a minimum Solidity compiler version of 0.5.10. ([#1829](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1829)) + +## 2.4.0 (2019-10-29) + +### New features + +- `Address.toPayable`: added a helper to convert between address types without having to resort to low-level casting. ([#1773](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1773)) +- Facilities to make metatransaction-enabled contracts through the Gas Station Network. ([#1844](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1844)) +- `Address.sendValue`: added a replacement to Solidity's `transfer`, removing the fixed gas stipend. ([#1962](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1962)) +- Added replacement for functions that don't forward all gas (which have been deprecated): ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976)) + - `PullPayment.withdrawPaymentsWithGas(address payable payee)` + - `Escrow.withdrawWithGas(address payable payee)` +- `SafeMath`: added support for custom error messages to `sub`, `div` and `mod` functions. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828)) + +### Improvements + +- `Address.isContract`: switched from `extcodesize` to `extcodehash` for less gas usage. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) +- `ERC20` and `ERC777` updated to throw custom errors on subtraction overflows. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828)) + +### Deprecations + +- Deprecated functions that don't forward all gas: ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976)) + - `PullPayment.withdrawPayments(address payable payee)` + - `Escrow.withdraw(address payable payee)` + +### Breaking changes + +- `Address` now requires a minimum Solidity compiler version of 0.5.5. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) +- `SignatureBouncer` has been removed from drafts, both to avoid confusions with the GSN and `GSNRecipientSignature` (previously called `GSNBouncerSignature`) and because the API was not very clear. ([#1879](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1879)) + +### How to upgrade from 2.4.0-beta + +The final 2.4.0 release includes a refactor of the GSN contracts that will be a breaking change for 2.4.0-beta users. + +- The default empty implementations of `_preRelayedCall` and `_postRelayedCall` were removed and must now be explicitly implemented always in custom recipients. If your custom recipient didn't include an implementation, you can provide an empty one. +- `GSNRecipient`, `GSNBouncerBase`, and `GSNContext` were all merged into `GSNRecipient`. +- `GSNBouncerSignature` and `GSNBouncerERC20Fee` were renamed to `GSNRecipientSignature` and `GSNRecipientERC20Fee`. +- It is no longer necessary to inherit from `GSNRecipient` when using `GSNRecipientSignature` and `GSNRecipientERC20Fee`. + +For example, a contract using `GSNBouncerSignature` would have to be changed in the following way. + +```diff +-contract MyDapp is GSNRecipient, GSNBouncerSignature { ++contract MyDapp is GSNRecipientSignature { +``` + +Refer to the table below to adjust your inheritance list. + +| 2.4.0-beta | 2.4.0 | +| ----------------------------------- | ----------------------- | +| `GSNRecipient, GSNBouncerSignature` | `GSNRecipientSignature` | +| `GSNRecipient, GSNBouncerERC20Fee` | `GSNRecipientERC20Fee` | +| `GSNBouncerBase` | `GSNRecipient` | + +## 2.3.0 (2019-05-27) + +### New features + +- `ERC1820`: added support for interacting with the [ERC1820](https://eips.ethereum.org/EIPS/eip-1820) registry contract (`IERC1820Registry`), as well as base contracts that can be registered as implementers there. ([#1677](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1677)) +- `ERC777`: support for the [ERC777 token](https://eips.ethereum.org/EIPS/eip-777), which has multiple improvements over `ERC20` (but is backwards compatible with it) such as built-in burning, a more straightforward permission system, and optional sender and receiver hooks on transfer (mandatory for contracts!). ([#1684](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1684)) +- All contracts now have revert reason strings, which give insight into error conditions, and help debug failing transactions. ([#1704](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1704)) + +### Improvements + +- Reverted the Solidity version bump done in v2.2.0, setting the minimum compiler version to v0.5.0, to prevent unexpected build breakage. Users are encouraged however to stay on top of new compiler releases, which usually include bugfixes. ([#1729](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1729)) + +### Bugfixes + +- `PostDeliveryCrowdsale`: some validations where skipped when paired with other crowdsale flavors, such as `AllowanceCrowdsale`, or `MintableCrowdsale` and `ERC20Capped`, which could cause buyers to not be able to claim their purchased tokens. ([#1721](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1721)) +- `ERC20._transfer`: the `from` argument was allowed to be the zero address, so it was possible to internally trigger a transfer of 0 tokens from the zero address. This address is not a valid destinatary of transfers, nor can it give or receive allowance, so this behavior was inconsistent. It now reverts. ([#1752](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1752)) + +## 2.2.0 (2019-03-14) + +### New features + +- `ERC20Snapshot`: create snapshots on demand of the token balances and total supply, to later retrieve and e.g. calculate dividends at a past time. ([#1617](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1617)) +- `SafeERC20`: `ERC20` contracts with no return value (i.e. that revert on failure) are now supported. ([#1655](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1655)) +- `ERC20`: added internal `_approve(address owner, address spender, uint256 value)`, allowing derived contracts to set the allowance of arbitrary accounts. ([#1609](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1609)) +- `ERC20Metadata`: added internal `_setTokenURI(string memory tokenURI)`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618)) +- `TimedCrowdsale`: added internal `_extendTime(uint256 newClosingTime)` as well as `TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime)` event allowing to extend the crowdsale, as long as it hasn't already closed. + +### Improvements + +- Upgraded the minimum compiler version to v0.5.2: this removes many Solidity warnings that were false positives. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606)) +- `ECDSA`: `recover` no longer accepts malleable signatures (those using upper-range values for `s`, or 0/1 for `v`). ([#1622](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1622)) +- `ERC721`'s transfers are now more gas efficient due to removal of unnecessary `SafeMath` calls. ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610)) +- Fixed variable shadowing issues. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606)) + +### Bugfixes + +- (minor) `SafeERC20`: `safeApprove` wasn't properly checking for a zero allowance when attempting to set a non-zero allowance. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647)) + +### Breaking changes in drafts + +- `TokenMetadata` has been renamed to `ERC20Metadata`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618)) +- The library `Counter` has been renamed to `Counters` and its API has been improved. See an example in `ERC721`, lines [17](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L17) and [204](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L204). ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610)) + +## 2.1.3 (2019-02-26) + +- Backported `SafeERC20.safeApprove` bugfix. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647)) + +## 2.1.2 (2019-01-17) + +- Removed most of the test suite from the npm package, except `PublicRole.behavior.js`, which may be useful to users testing their own `Roles`. + +## 2.1.1 (2019-01-04) + +- Version bump to avoid conflict in the npm registry. + +## 2.1.0 (2019-01-04) + +### New features + +- Now targeting the 0.5.x line of Solidity compilers. For 0.4.24 support, use version 2.0 of OpenZeppelin. +- `WhitelistCrowdsale`: a crowdsale where only whitelisted accounts (`WhitelistedRole`) can purchase tokens. Adding or removing accounts from the whitelist is done by whitelist admins (`WhitelistAdminRole`). Similar to the pre-2.0 `WhitelistedCrowdsale`. ([#1525](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1525), [#1589](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1589)) +- `RefundablePostDeliveryCrowdsale`: replacement for `RefundableCrowdsale` (deprecated, see below) where tokens are only granted once the crowdsale ends (if it meets its goal). ([#1543](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1543)) +- `PausableCrowdsale`: allows for pausers (`PauserRole`) to pause token purchases. Other crowdsale operations (e.g. withdrawals and refunds, if applicable) are not affected. ([#832](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/832)) +- `ERC20`: `transferFrom` and `_burnFrom ` now emit `Approval` events, to represent the token's state comprehensively through events. ([#1524](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1524)) +- `ERC721`: added `_burn(uint256 tokenId)`, replacing the similar deprecated function (see below). ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) +- `ERC721`: added `_tokensOfOwner(address owner)`, allowing to internally retrieve the array of an account's owned tokens. ([#1522](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1522)) +- Crowdsales: all constructors are now `public`, meaning it is not necessary to extend these contracts in order to deploy them. The exception is `FinalizableCrowdsale`, since it is meaningless unless extended. ([#1564](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1564)) +- `SignedSafeMath`: added overflow-safe operations for signed integers (`int256`). ([#1559](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1559), [#1588](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1588)) + +### Improvements + +- The compiler version required by `Array` was behind the rest of the library so it was updated to `v0.4.24`. ([#1553](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1553)) +- Now conforming to a 4-space indentation code style. ([1508](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1508)) +- `ERC20`: more gas efficient due to removed redundant `require`s. ([#1409](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1409)) +- `ERC721`: fixed a bug that prevented internal data structures from being properly cleaned, missing potential gas refunds. ([#1539](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1539) and [#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549)) +- `ERC721`: general gas savings on `transferFrom`, `_mint` and `_burn`, due to redundant `require`s and `SSTORE`s. ([#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549)) + +### Bugfixes + +### Breaking changes + +### Deprecations + +- `ERC721._burn(address owner, uint256 tokenId)`: due to the `owner` parameter being unnecessary. ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) +- `RefundableCrowdsale`: due to trading abuse potential on crowdsales that miss their goal. ([#1543](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1543)) diff --git a/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md b/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..cd7770d --- /dev/null +++ b/lib/openzeppelin-contracts/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at contact@openzeppelin.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/lib/openzeppelin-contracts/CONTRIBUTING.md b/lib/openzeppelin-contracts/CONTRIBUTING.md new file mode 100644 index 0000000..1a44cc2 --- /dev/null +++ b/lib/openzeppelin-contracts/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing Guidelines + +There are many ways to contribute to OpenZeppelin Contracts. + +## Troubleshooting + +You can help other users in the community to solve their smart contract issues in the [OpenZeppelin Forum]. + +[OpenZeppelin Forum]: https://forum.openzeppelin.com/ + +## Opening an issue + +You can [open an issue] to suggest a feature or report a minor bug. For serious bugs please do not open an issue, instead refer to our [security policy] for appropriate steps. + +If you believe your issue may be due to user error and not a problem in the library, consider instead posting a question on the [OpenZeppelin Forum]. + +Before opening an issue, be sure to search through the existing open and closed issues, and consider posting a comment in one of those instead. + +When requesting a new feature, include as many details as you can, especially around the use cases that motivate it. Features are prioritized according to the impact they may have on the ecosystem, so we appreciate information showing that the impact could be high. + +[security policy]: https://github.com/OpenZeppelin/openzeppelin-contracts/security +[open an issue]: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/new/choose + +## Submitting a pull request + +If you would like to contribute code or documentation you may do so by forking the repository and submitting a pull request. + +Any non-trivial code contribution must be first discussed with the maintainers in an issue (see [Opening an issue](#opening-an-issue)). Only very minor changes are accepted without prior discussion. + +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/lib/openzeppelin-contracts/GUIDELINES.md b/lib/openzeppelin-contracts/GUIDELINES.md new file mode 100644 index 0000000..4b7f5e7 --- /dev/null +++ b/lib/openzeppelin-contracts/GUIDELINES.md @@ -0,0 +1,148 @@ +# Engineering Guidelines + +## Testing + +Code must be thoroughly tested with quality unit tests. + +We defer to the [Moloch Testing Guide](https://github.com/MolochVentures/moloch/tree/master/test#readme) for specific recommendations, though not all of it is relevant here. Note the introduction: + +> Tests should be written, not only to verify correctness of the target code, but to be comprehensively reviewed by other programmers. Therefore, for mission critical Solidity code, the quality of the tests are just as important (if not more so) than the code itself, and should be written with the highest standards of clarity and elegance. + +Every addition or change to the code must come with relevant and comprehensive tests. + +Refactors should avoid simultaneous changes to tests. + +Flaky tests are not acceptable. + +The test suite should run automatically for every change in the repository, and in pull requests tests must pass before merging. + +The test suite coverage must be kept as close to 100% as possible, enforced in pull requests. + +In some cases unit tests may be insufficient and complementary techniques should be used: + +1. Property-based tests (aka. fuzzing) for math-heavy code. +2. Formal verification for state machines. + +## Code style + +Solidity code should be written in a consistent format enforced by a linter, following the official [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html). See below for further [Solidity Conventions](#solidity-conventions). + +The code should be simple and straightforward, prioritizing readability and understandability. Consistency and predictability should be maintained across the codebase. In particular, this applies to naming, which should be systematic, clear, and concise. + +Sometimes these guidelines may be broken if doing so brings significant efficiency gains, but explanatory comments should be added. + +Modularity should be pursued, but not at the cost of the above priorities. + +## Documentation + +For contributors, project guidelines and processes must be documented publicly. + +For users, features must be abundantly documented. Documentation should include answers to common questions, solutions to common problems, and recommendations for critical decisions that the user may face. + +All changes to the core codebase (excluding tests, auxiliary scripts, etc.) must be documented in a changelog, except for purely cosmetic or documentation changes. + +## Peer review + +All changes must be submitted through pull requests and go through peer code review. + +The review must be approached by the reviewer in a similar way as if it was an audit of the code in question (but importantly it is not a substitute for and should not be considered an audit). + +Reviewers should enforce code and project guidelines. + +External contributions must be reviewed separately by multiple maintainers. + +## Automation + +Automation should be used as much as possible to reduce the possibility of human error and forgetfulness. + +Automations that make use of sensitive credentials must use secure secret management, and must be strengthened against attacks such as [those on GitHub Actions worklows](https://github.com/nikitastupin/pwnhub). + +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. + +* All state variables should be private. + + Changes to state should be accompanied by events, and in some cases it is not correct to arbitrarily set state. Encapsulating variables as private and only allowing modification via setters enables us to ensure that events and other rules are followed reliably and prevents this kind of user error. + +* Internal or private state variables or functions should have an underscore prefix. + + ```solidity + contract TestContract { + uint256 private _privateVar; + uint256 internal _internalVar; + function _testInternal() internal { ... } + function _testPrivate() private { ... } + } + ``` + +* Functions should be declared virtual, with few exceptions listed below. The + contract logic should be written considering that these functions may be + overridden by developers, e.g. getting a value using an internal getter rather + than reading directly from a state variable. + + If function A is an "alias" of function B, i.e. it invokes function B without + significant additional logic, then function A should not be virtual so that + any user overrides are implemented on B, preventing inconsistencies. + +* Events should generally be emitted immediately after the state change that they + represent, and should be named in the past tense. Some exceptions may be made for gas + efficiency if the result doesn't affect observable ordering of events. + + ```solidity + function _burn(address who, uint256 value) internal { + super._burn(who, value); + emit TokensBurned(who, value); + } + ``` + + Some standards (e.g. ERC20) use present tense, and in those cases the + standard specification is used. + +* Interface names should have a capital I prefix. + + ```solidity + interface IERC777 { + ``` + +* Contracts not intended to be used standalone should be marked abstract + so they are required to be inherited to other contracts. + + ```solidity + abstract contract AccessControl is ..., { + ``` + +* Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted. + +* Custom errors should be declared following the [EIP-6093](https://eips.ethereum.org/EIPS/eip-6093) rationale whenever reasonable. Also, consider the following: + + * The domain prefix should be picked in the following order: + 1. Use `ERC` if the error is a violation of an ERC specification. + 2. Use the name of the underlying component where it belongs (eg. `Governor`, `ECDSA`, or `Timelock`). + + * The location of custom errors should be decided in the following order: + 1. Take the errors from their underlying ERCs if they're already defined. + 2. Declare the errors in the underlying interface/library if the error makes sense in its context. + 3. Declare the error in the implementation if the underlying interface/library is not suitable to do so (eg. interface/library already specified in an ERC). + 4. Declare the error in an extension if the error only happens in such extension or child contracts. + + * Custom error names should not be declared twice along the library to avoid duplicated identifier declarations when inheriting from multiple contracts. diff --git a/lib/openzeppelin-contracts/LICENSE b/lib/openzeppelin-contracts/LICENSE new file mode 100644 index 0000000..817249a --- /dev/null +++ b/lib/openzeppelin-contracts/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016-2023 zOS Global Limited and contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/openzeppelin-contracts/README.md b/lib/openzeppelin-contracts/README.md new file mode 100644 index 0000000..9ca4157 --- /dev/null +++ b/lib/openzeppelin-contracts/README.md @@ -0,0 +1,107 @@ +# OpenZeppelin + +[![NPM Package](https://img.shields.io/npm/v/@openzeppelin/contracts.svg)](https://www.npmjs.org/package/@openzeppelin/contracts) +[![Coverage Status](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts/graph/badge.svg)](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts) +[![GitPOAPs](https://public-api.gitpoap.io/v1/repo/OpenZeppelin/openzeppelin-contracts/badge)](https://www.gitpoap.io/gh/OpenZeppelin/openzeppelin-contracts) +[![Docs](https://img.shields.io/badge/docs-%F0%9F%93%84-yellow)](https://docs.openzeppelin.com/contracts) +[![Forum](https://img.shields.io/badge/forum-%F0%9F%92%AC-yellow)](https://docs.openzeppelin.com/contracts) + +**A library for secure smart contract development.** Build on a solid foundation of community-vetted code. + + * Implementations of standards like [ERC20](https://docs.openzeppelin.com/contracts/erc20) and [ERC721](https://docs.openzeppelin.com/contracts/erc721). + * Flexible [role-based permissioning](https://docs.openzeppelin.com/contracts/access-control) scheme. + * Reusable [Solidity components](https://docs.openzeppelin.com/contracts/utilities) to build custom contracts and complex decentralized systems. + +:mage: **Not sure how to get started?** Check out [Contracts Wizard](https://wizard.openzeppelin.com/) — an interactive smart contract generator. + +:building_construction: **Want to scale your decentralized application?** Check out [OpenZeppelin Defender](https://openzeppelin.com/defender) — a secure platform for automating and monitoring your operations. + +> [!IMPORTANT] +> OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, for example, it is unsafe to upgrade from 4.9.3 to 5.0.0. Learn more at [Backwards Compatibility](https://docs.openzeppelin.com/contracts/backwards-compatibility). + +## Overview + +### Installation + +#### Hardhat, Truffle (npm) + +``` +$ npm install @openzeppelin/contracts +``` + +#### Foundry (git) + +> [!WARNING] +> When installing via git, it is a common error to use the `master` branch. This is a development branch that should be avoided in favor of tagged releases. The release process involves security measures that the `master` branch does not guarantee. + +> [!WARNING] +> Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch. + +``` +$ forge install OpenZeppelin/openzeppelin-contracts +``` + +Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.` + +### Usage + +Once installed, you can use the contracts in the library by importing them: + +```solidity +pragma solidity ^0.8.20; + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; + +contract MyCollectible is ERC721 { + constructor() ERC721("MyCollectible", "MCO") { + } +} +``` + +_If you're new to smart contract development, head to [Developing Smart Contracts](https://docs.openzeppelin.com/learn/developing-smart-contracts) to learn about creating a new project and compiling your contracts._ + +To keep your system secure, you should **always** use the installed code as-is, and neither copy-paste it from online sources nor modify it yourself. The library is designed so that only the contracts and functions you use are deployed, so you don't need to worry about it needlessly increasing gas costs. + +## Learn More + +The guides in the [documentation site](https://docs.openzeppelin.com/contracts) will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides: + +* [Access Control](https://docs.openzeppelin.com/contracts/access-control): decide who can perform each of the actions on your system. +* [Tokens](https://docs.openzeppelin.com/contracts/tokens): create tradeable assets or collectives, and distribute them via [Crowdsales](https://docs.openzeppelin.com/contracts/crowdsales). +* [Utilities](https://docs.openzeppelin.com/contracts/utilities): generic useful tools including non-overflowing math, signature verification, and trustless paying systems. + +The [full API](https://docs.openzeppelin.com/contracts/api/token/ERC20) is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts's development in the [community forum](https://forum.openzeppelin.com). + +Finally, you may want to take a look at the [guides on our blog](https://blog.openzeppelin.com/), which cover several common use cases and good practices. The following articles provide great background reading, though please note that some of the referenced tools have changed, as the tooling in the ecosystem continues to rapidly evolve. + +* [The Hitchhiker’s Guide to Smart Contracts in Ethereum](https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05) will help you get an overview of the various tools available for smart contract development, and help you set up your environment. +* [A Gentle Introduction to Ethereum Programming, Part 1](https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094) provides very useful information on an introductory level, including many basic concepts from the Ethereum platform. +* For a more in-depth dive, you may read the guide [Designing the Architecture for Your Ethereum Application](https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317), which discusses how to better structure your application and its relationship to the real world. + +## Security + +This project is maintained by [OpenZeppelin](https://openzeppelin.com) with the goal of providing a secure and reliable library of smart contract components for the ecosystem. We address security through risk management in various areas such as engineering and open source best practices, scoping and API design, multi-layered review processes, and incident response preparedness. + +The [OpenZeppelin Contracts Security Center](https://contracts.openzeppelin.com/security) contains more details about the secure development process. + +The security policy is detailed in [`SECURITY.md`](./SECURITY.md) as well, and specifies how you can report security vulnerabilities, which versions will receive security patches, and how to stay informed about them. We run a [bug bounty program on Immunefi](https://immunefi.com/bounty/openzeppelin) to reward the responsible disclosure of vulnerabilities. + +The engineering guidelines we follow to promote project quality can be found in [`GUIDELINES.md`](./GUIDELINES.md). + +Past audits can be found in [`audits/`](./audits). + +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. + +## Contribute + +OpenZeppelin Contracts exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the [contribution guide](CONTRIBUTING.md)! + +## License + +OpenZeppelin Contracts is released under the [MIT License](LICENSE). + +## Legal + +Your use of this Project is governed by the terms found at www.openzeppelin.com/tos (the "Terms"). diff --git a/lib/openzeppelin-contracts/RELEASING.md b/lib/openzeppelin-contracts/RELEASING.md new file mode 100644 index 0000000..06dd218 --- /dev/null +++ b/lib/openzeppelin-contracts/RELEASING.md @@ -0,0 +1,45 @@ +# Releasing + +OpenZeppelin Contracts uses a fully automated release process that takes care of compiling, packaging, and publishing the library, all of which is carried out in a clean CI environment (GitHub Actions), implemented in the ([`release-cycle`](.github/workflows/release-cycle.yml)) workflow. This helps to reduce the potential for human error and inconsistencies, and ensures that the release process is ongoing and reliable. + +## Changesets + +[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. + +## Branching model + +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. + +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" + + checkout master + commit id: "Feature C" + commit id: "Fix A" + + checkout release-vX.Y + cherry-pick id: "Fix A" tag: "" + commit id: "Release vX.Y.0-rc.1" + commit id: "Release vX.Y.0" + + 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" +``` diff --git a/lib/openzeppelin-contracts/SECURITY.md b/lib/openzeppelin-contracts/SECURITY.md new file mode 100644 index 0000000..e9a5148 --- /dev/null +++ b/lib/openzeppelin-contracts/SECURITY.md @@ -0,0 +1,42 @@ +# Security Policy + +Security vulnerabilities should be disclosed to the project maintainers through [Immunefi], or alternatively by email to security@openzeppelin.com. + +[Immunefi]: https://immunefi.com/bounty/openzeppelin + +## Bug Bounty + +Responsible disclosure of security vulnerabilities is rewarded through a bug bounty program on [Immunefi]. + +There is a bonus reward for issues introduced in release candidates that are reported before making it into a stable release. + +## Security Patches + +Security vulnerabilities will be patched as soon as responsibly possible, and published as an advisory on this repository (see [advisories]) and on the affected npm packages. + +[advisories]: https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories + +Projects that build on OpenZeppelin Contracts are encouraged to clearly state, in their source code and websites, how to be contacted about security issues in the event that a direct notification is considered necessary. We recommend including it in the NatSpec for the contract as `/// @custom:security-contact security@example.com`. + +Additionally, we recommend installing the library through npm and setting up vulnerability alerts such as [Dependabot]. + +[Dependabot]: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-supply-chain-security#what-is-dependabot + +### Supported Versions + +Security patches will be released for the latest minor of a given major release. For example, if an issue is found in versions >=4.6.0 and the latest is 4.8.0, the patch will be released only in version 4.8.1. + +Only critical severity bug fixes will be backported to past major releases. + +| Version | Critical security fixes | Other security fixes | +| ------- | ----------------------- | -------------------- | +| 4.x | :white_check_mark: | :white_check_mark: | +| 3.4 | :white_check_mark: | :x: | +| 2.5 | :white_check_mark: | :x: | +| < 2.0 | :x: | :x: | + +Note as well that the Solidity language itself only guarantees security updates for the latest release. + +## Legal + +Smart contracts are a nascent technology and carry a high level of technical risk and uncertainty. OpenZeppelin Contracts is made available under the MIT License, which disclaims all warranties in relation to the project and which limits the liability of those that contribute and maintain the project, including OpenZeppelin. Your use of the project is also governed by the terms found at www.openzeppelin.com/tos (the "Terms"). As set out in the Terms, you are solely responsible for any use of OpenZeppelin Contracts and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an on-going duty by any contributor, including OpenZeppelin, to correct any flaws or alert you to all or any of the potential risks of utilizing the project. diff --git a/lib/openzeppelin-contracts/audits/2017-03.md b/lib/openzeppelin-contracts/audits/2017-03.md new file mode 100644 index 0000000..4cd6dbf --- /dev/null +++ b/lib/openzeppelin-contracts/audits/2017-03.md @@ -0,0 +1,292 @@ +# OpenZeppelin Audit + +NOTE ON 2021-07-19: This report makes reference to Zeppelin, OpenZeppelin, OpenZeppelin Contracts, the OpenZeppelin team, and OpenZeppelin library. Many of these things have since been renamed and know that this audit applies to what is currently called the OpenZeppelin Contracts which are maintained by the OpenZeppelin Contracts Community. + +March, 2017 +Authored by Dennis Peterson and Peter Vessenes + +# Introduction + +Zeppelin requested that New Alchemy perform an audit of the contracts in their OpenZeppelin library. The OpenZeppelin contracts are a set of contracts intended to be a safe building block for a variety of uses by parties that may not be as sophisticated as the OpenZeppelin team. It is a design goal that the contracts be deployable safely and "as-is". + +The contracts are hosted at: + +https://github.com/OpenZeppelin/zeppelin-solidity + +All the contracts in the "contracts" folder are in scope. + +The git commit hash we evaluated is: +9c5975a706b076b7000e8179f8101e0c61024c87 + +# Disclaimer + +The audit makes no statements or warrantees about utility of the code, safety of the code, suitability of the business model, regulatory regime for the business model, or any other statements about fitness of the contracts to purpose, or their bugfree status. The audit documentation is for discussion purposes only. + +# Executive Summary + +Overall the OpenZeppelin codebase is of reasonably high quality -- it is clean, modular and follows best practices throughout. + +It is still in flux as a codebase, and needs better documentation per file as to expected behavior and future plans. It probably needs more comprehensive and aggressive tests written by people less nice than the current OpenZeppelin team. + +We identified two critical errors and one moderate issue, and would not recommend this commit hash for public use until these bugs are remedied. + +The repository includes a set of Truffle unit tests, a requirement and best practice for smart contracts like these; we recommend these be bulked up. + +# Discussion + +## Big Picture: Is This A Worthwhile Project? + +As soon as a developer touches OpenZeppelin contracts, they will modify something, leaving them in an un-audited state. We do not recommend developers deploy any unaudited code to the Blockchain if it will handle money, information or other things of value. + +> "In accordance with Unix philosophy, Perl gives you enough rope to hang yourself" +> --Larry Wall + +We think this is an incredibly worthwhile project -- aided by the high code quality. Creating a framework that can be easily extended helps increase the average code quality on the Blockchain by charting a course for developers and encouraging containment of modifications to certain sections. + +> "Rust: The language that makes you take the safety off before shooting yourself in the foot" +> -- (@mbrubeck) + +We think much more could be done here, and recommend the OpenZeppelin team keep at this and keep focusing on the design goal of removing rope and adding safety. + +## Solidity Version Updates Recommended + +Most of the code uses Solidity 0.4.11, but some files under `Ownership` are marked 0.4.0. These should be updated. + +Solidity 0.4.10 will add several features which could be useful in these contracts: + +- `assert(condition)`, which throws if the condition is false + +- `revert()`, which rolls back without consuming all remaining gas. + +- `address.transfer(value)`, which is like `send` but automatically propagates exceptions, and supports `.gas()`. See https://github.com/ethereum/solidity/issues/610 for more on this. + +## Error Handling: Throw vs Return False +Solidity standards allow two ways to handle an error -- either calling `throw` or returning `false`. Both have benefits. In particular, a `throw` guarantees a complete wipe of the call stack (up to the preceding external call), whereas `false` allows a function to continue. + +In general we prefer `throw` in our code audits, because it is simpler -- it's less for an engineer to keep track of. Returning `false` and using logic to check results can quickly become a poorly-tracked state machine, and this sort of complexity can cause errors. + +In the OpenZeppelin contracts, both styles are used in different parts of the codebase. `SimpleToken` transfers throw upon failure, while the full ERC20 token returns `false`. Some modifiers `throw`, others just wrap the function body in a conditional, effectively allowing the function to return false if the condition is not met. + +We don't love this, and would usually recommend you stick with one style or the other throughout the codebase. + +In at least one case, these different techniques are combined cleverly (see the Multisig comments, line 65). As a set of contracts intended for general use, we recommend you either strive for more consistency or document explicit design criteria that govern which techniques are used where. + +Note that it may be impossible to use either one in all situations. For example, SafeMath functions pretty much have to throw upon failure, but ERC20 specifies returning booleans. Therefore we make no particular recommendations, but simply point out inconsistencies to consider. + +# Critical Issues + +## Stuck Ether in Crowdsale contract +CrowdsaleToken.sol has no provision for withdrawing the raised ether. We *strongly* recommend a standard `withdraw` function be added. There is no scenario in which someone should deploy this contract as is, whether for testing or live. + +## Recursive Call in MultisigWallet +Line 45 of `MultisigWallet.sol` checks if the amount being sent by `execute` is under a daily limit. + +This function can only be called by the "Owner". As a first angle of attack, it's worth asking what will happen if the multisig wallet owners reset the daily limit by approving a call to `resetSpentToday`. + +If a chain of calls can be constructed in which the owner confirms the `resetSpentToday` function and then withdraws through `execute` in a recursive call, the contract can be drained. In fact, this could be done without a recursive call, just through repeated `execute` calls alternating with the `confirm` calls. + +We are still working through the confirmation protocol in `Shareable.sol`, but we are not convinced that this is impossible, in fact it looks possible. The flexibility any shared owner has in being able to revoke confirmation later is another worrisome angle of approach even if some simple patches are included. + +This bug has a number of causes that need to be addressed: + +1. `resetSpentToday` and `confirm` together do not limit the days on which the function can be called or (it appears) the number of times it can be called. +1. Once a call has been confirmed and `execute`d it appears that it can be re-executed. This is not good. +3. `confirmandCheck` doesn't seem to have logic about whether or not the function in question has been called. +4. Even if it did, `revoke` would need updates and logic to deal with revocation requests after a function call had been completed. + +We do not recommend using the MultisigWallet until these issues are fixed. + +# Moderate to Minor Issues + +## PullPayment +PullPayment.sol needs some work. It has no explicit provision for cancelling a payment. This would be desirable in a number of scenarios; consider a payee losing their wallet, or giving a griefing address, or just an address that requires more than the default gas offered by `send`. + +`asyncSend` has no overflow checking. This is a bad plan. We recommend overflow and underflow checking at the layer closest to the data manipulation. + +`asyncSend` allows more balance to be queued up for sending than the contract holds. This is probably a bad idea, or at the very least should be called something different. If the intent is to allow this, it should have provisions for dealing with race conditions between competing `withdrawPayments` calls. + +It would be nice to see how many payments are pending. This would imply a bit of a rewrite; we recommend this contract get some design time, and that developers don't rely on it in its current state. + +## Shareable Contract + +We do not believe the `Shareable.sol` contract is ready for primetime. It is missing functions, and as written may be vulnerable to a reordering attack -- an attack in which a miner or other party "racing" with a smart contract participant inserts their own information into a list or mapping. + +The confirmation and revocation code needs to be looked over with a very careful eye imagining extraordinarily bad behavior by shared owners before this contract can be called safe. + +No sanity checks on the initial constructor's `required` argument are worrisome as well. + +# Line by Line Comments + +## Lifecycle + +### Killable + +Very simple, allows owner to call selfdestruct, sending funds to owner. No issues. However, note that `selfdestruct` should typically not be used; it is common that a developer may want to access data in a former contract, and they may not understand that `selfdestruct` limits access to the contract. We recommend better documentation about this dynamic, and an alternate function name for `kill` like `completelyDestroy` while `kill` would perhaps merely send funds to the owner. + +Also note that a killable function allows the owner to take funds regardless of other logic. This may be desirable or undesirable depending on the circumstances. Perhaps `Killable` should have a different name as well. + +### Migrations + +I presume that the goal of this contract is to allow and annotate a migration to a new smart contract address. We are not clear here how this would be accomplished by the code; we'd like to review with the OpenZeppelin team. + +### Pausable + +We like these pauses! Note that these allow significant griefing potential by owners, and that this might not be obvious to participants in smart contracts using the OpenZeppelin framework. We would recommend that additional sample logic be added to for instance the TokenContract showing safer use of the pause and resume functions. In particular, we would recommend a timelock after which anyone could unpause the contract. + +The modifiers use the pattern `if(bool){_;}`. This is fine for functions that return false upon failure, but could be problematic for functions expected to throw upon failure. See our comments above on standardizing on `throw` or `return(false)`. + +## Ownership + +### Ownable + +Line 19: Modifier throws if doesn't meet condition, in contrast to some other inheritable modifiers (e.g. in Pausable) that use `if(bool){_;}`. + +### Claimable + +Inherits from Ownable but the existing owner sets a pendingOwner who has to claim ownership. + +Line 17: Another modifier that throws. + +### DelayedClaimable + +Is there any reason to descend from Ownable directly, instead of just Claimable, which descends from Ownable? If not, descending from both just adds confusion. + +### Contactable + +Allows owner to set a public string of contract information. No issues. + +### Shareable + +This needs some work. Doesn't check if `_required <= len(_owners)` for instance, that would be a bummer. What if _required were like `MAX - 1`? + +I have a general concern about the difference between `owners`, `_owners`, and `owner` in `Ownable.sol`. I recommend "Owners" be renamed. In general we do not recomment single character differences in variable names, although a preceding underscore is not uncommon in Solidity code. + +Line 34: "this contract only has six types of events"...actually only two. + +Line 61: Why is `ownerIndex` keyed by addresses hashed to `uint`s? Why not use the addresses directly, so `ownerIndex` is less obscure, and so there's stronger typing? + +Line 62: Do not love `++i) ... owners[2+ i]`. Makes me do math, which is not what I want to do. I want to not have to do math. + +There should probably be a function for adding a new operation, so the developer doesn't have to work directly with the internal data. (This would make the multisig contract even shorter.) + +There's a `revoke` function but not a `propose` function that we can see. + +Beware reordering. If `propose` allows the user to choose a bytes string for their proposal, bad things(TM) will happen as currently written. + + +### Multisig + +Just an interface. Note it allows changing an owner address, but not changing the number of owners. This is somewhat limiting but also simplifies implementation. + +## Payment + +### PullPayment + +Safe from reentrance attack since ether send is at the end, plus it uses `.send()` rather than `.call.value()`. + +There's an argument to be made that `.call.value()` is a better option *if* you're sure that it will be done after all state updates, since `.send` will fail if the recipient has an expensive fallback function. However, in the context of a function meant to be embedded in other contracts, it's probably better to use `.send`. One possible compromise is to add a function which allows only the owner to send ether via `.call.value`. + +If you don't use `call.value` you should implement a `cancel` function in case some value is pending here. + +Line 14: +Doesn't use safeAdd. Although it appears that payout amounts can only be increased, in fact the payer could lower the payout as much as desired via overflow. Also, the payer could add a large non-overflowing amount, causing the payment to exceed the contract balance and therefore fail when withdraw is attempted. + +Recommendation: track the sum of non-withdrawn asyncSends, and don't allow a new one which exceeds the leftover balance. If it's ever desirable to make payments revocable, it should be done explicitly. + +## Tokens + +### ERC20 + +Standard ERC20 interface only. + +There's a security hole in the standard, reported at Edcon: `approve` does not protect against race conditions and simply replaces the current value. An approved spender could wait for the owner to call `approve` again, then attempt to spend the old limit before the new limit is applied. If successful, this attacker could successfully spend the sum of both limits. + +This could be fixed by either (1) including the old limit as a parameter, so the update will fail if some gets spent, or (2) using the value parameter as a delta instead of replacement value. + +This is not fixable while adhering to the current full ERC20 standard, though it would be possible to add a "secureApprove" function. The impact isn't extreme since at least you can only be attacked by addresses you approved. Also, users could mitigate this by always setting spending limits to zero and checking for spends, before setting the new limit. + +Edcon slides: +https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view + +### ERC20Basic + +Simpler interface skipping the Approve function. Note this departs from ERC20 in another way: transfer throws instead of returning false. + +### BasicToken + +Uses `SafeSub` and `SafeMath`, so transfer `throw`s instead of returning false. This complies with ERC20Basic but not the actual ERC20 standard. + +### StandardToken + +Implementation of full ERC20 token. + +Transfer() and transferFrom() use SafeMath functions, which will cause them to throw instead of returning false. Not a security issue but departs from standard. + +### SimpleToken + +Sample instantiation of StandardToken. Note that in this sample, decimals is 18 and supply only 10,000, so the supply is a small fraction of a single nominal token. + +### CrowdsaleToken + +StandardToken which mints tokens at a fixed price when sent ether. + +There's no provision for owner withdrawing the ether. As a sample for crowdsales it should be Ownable and allow the owner to withdraw ether, rather than stranding the ether in the contract. + +Note: an alternative pattern is a mint() function which is only callable from a separate crowdsale contract, so any sort of rules can be added without modifying the token itself. + +### VestedToken + +Lines 23, 27: +Functions `transfer()` and `transferFrom()` have a modifier canTransfer which throws if not enough tokens are available. However, transfer() returns a boolean success. Inconsistent treatment of failure conditions may cause problems for other contracts using the token. (Note that transferableTokens() relies on safeSub(), so will also throw if there's insufficient balance.) + +Line 64: +Delete not actually necessary since the value is overwritten in the next line anyway. + +## Root level + +### Bounty + +Avoids potential race condition by having each researcher deploy a separate contract for attack; if a research manages to break his associated contract, other researchers can't immediately claim the reward, they have to reproduce the attack in their own contracts. + +A developer could subvert this intent by implementing `deployContract()` to always return the same address. However, this would break the `researchers` mapping, updating the researcher address associated with the contract. This could be prevented by blocking rewrites in `researchers`. + +### DayLimit + +The modifier `limitedDaily` calls `underLimit`, which both checks that the spend is below the daily limit, and adds the input value to the daily spend. This is fine if all functions throw upon failure. However, not all OpenZeppelin functions do this; there are functions that returns false, and modifiers that wrap the function body in `if (bool) {_;}`. In these cases, `_value` will be added to `spentToday`, but ether may not actually be sent because other preconditions were not met. (However in the OpenZeppelin multisig this is not a problem.) + +Lines 4, 11: +Comment claims that `DayLimit` is multiowned, and Shareable is imported, but DayLimit does not actually inherit from Shareable. The intent may be for child contracts to inherit from Shareable (as Multisig does); in this case the import should be removed and the comment altered. + +Line 46: +Manual overflow check instead of using safeAdd. Since this is called from a function that throws upon failure anyway, there's no real downside to using safeAdd. + +### LimitBalance + +No issues. + +### MultisigWallet + +Lines 28, 76, 80: +`kill`, `setDailyLimit`, and `resetSpentToday` only happen with multisig approval, and hashes for these actions are logged by Shareable. However, they should probably post their own events for easy reading. + +Line 45: +This call to underLimit will reduce the daily limit, and then either throw or return 0. So in this case there's no danger that the limit will be reduced without the operation going through. + +Line 65: +Shareable's onlyManyOwners will take the user's confirmation, and execute the function body if and only if enough users have confirmed. Whole thing throws if the send fails, which will roll back the confirmation. Confirm returns false if not enough have confirmed yet, true if the whole thing succeeds, and throws only in the exceptional circumstance that the designated transaction unexpectedly fails. Elegant design. + +Line 68: +Throw here is good but note this function can fail either by returning false or by throwing. + +Line 92: +A bit odd to split `clearPending()` between this contract and Shareable. However this does allow contracts inheriting from Shareable to use custom structs for pending transactions. + + +### SafeMath + +Another interesting comment from the same Edcon presentation was that the overflow behavior of Solidity is undocumented, so in theory, source code that relies on it could break with a future revision. + +However, compiled code should be fine, and in the unlikely event that the compiler is revised in this way, there should be plenty of warning. (But this is an argument for keeping overflow checks isolated in SafeMath.) + +Aside from that small caveat, these are fine. + diff --git a/lib/openzeppelin-contracts/audits/2018-10.pdf b/lib/openzeppelin-contracts/audits/2018-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d5bf12741c8a6d44ed597de7204fde72d91dec35 GIT binary patch literal 1000527 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%0AXGSxD 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%0Ds@WxhHVsCq?&%C$272odl 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

{23QAMhgmDFwY9!) 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

%X-{jq)zF)pGEGKPHkt7x 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

@!c9KnY4NvNgEvnPA? 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

QsKH{N_IQtXo9hrt1|lnPuADU$b1Mf#WXL540@w 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%0DQ_tNgAAku*dN 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

fwy2<7q zDUf=Nh}CM0fE@!qOXtsLFjQ>$FZ2yw)|OeY5B{dg9ZVSOX9Cpw#z`7!j7aa6(6{a$4FhsBu72G5Gt3ar2e+Aijb6l&EFnK zgbkye>R;w7rO=AxuAv~#+b(Q)j+Y#7Nn#15O)!WjhFJ*}vDBRwPW>2EYH(nfeo!Zs zP>e)wKb@f2;oB4uV%v|fqUSmpTAMbtW&7L?cX91cn|dOtrX8qUXNP$Ynz=hWo;#yF zeTFVdpOqs}-XfM|7RKBO^#dvUB!<69j0Pv*DFGL^*?2Xg4WcIZ81Ze(rMDXv=B5gr z<9w|<*ww7#S7KM{6vkIj!s}wu^RAU+} z_+K98!d36qresKVe%TT&ENQq3Sg+fC`0q?GZUKkR?AYGfa}DTY*=Qf_l#vck<3kiw z)H!4f1H7PuBOsy~O!MjSBzK9$Qk%vRJ3`)gI9gz7WnCOjxn86hH5G zgD2-V=1O-9F}V6$>;W)YiiN_{+hFUvN-Wr1Z;}-~3CYu48b8G4sV%T5_<6e;?41i< zjxjYG61gXMT!-zH)h1a@ zzc@*6>iAi^b8nC5UC}~_MsyT}^^(~wsL=@x7|M-zzxr9lm%+QP@EdH+{C$fX`+;Q( z6QV%O;N3e8@LmWGzhK^LA0Q5QC4-Bno^1V-xPGwh2!?h-RL=3UU`*a$N(Myz9YXbe zGV-Jy;QRF*wM$$KEGL|k|4~5yvx}Jma+ZO|rC!)gkGV|_;9cFr$DKk)>BWN~(;Eu9o zomyAR7ZTY?Mw9i78#mq71J%i>vEvcO@L4c;SS7$}G0MR95G$TbzhB=wK7TeZ^v?q7 ziLHMk4zvAQPw@rFW*L67mPFv?af}v=)9%L|y^|wk-!-aR|Llg~K39@`R9^xSxPBM= z%b2T` zPo$0~?@P|iQG+?;Gs3Zeo zXbX#;hntIv%fKX0ES1%mVtNWu);V)bS{0CYn#r{ph#h?w# z6aK&5lWm|BG){A;kL3ay6mvhXy9Cy3k{vbYCUbt;C6TYg5`sON*TKz6$DWUL*^*E{x;lj@bJ z`4&lWklridPA3CY5l%c%$^n1Pm&%PAQplvCa{3Hib?3gz27P1s91=R+^1+6H6s zX}R-IsHye2ggRzPgJVhe%bq-+OzFo;e9%7PGPj1Aleg=h9i%k;OnTRh-aB0J;p<7I zw8+$Jd~qD@_#kGO7hC21FO8qv#;DYxlStWbP@_fqy&$j#>utVouc?l14i?Wu0^zp8s}gvot|7hnFNC zNiTi`YloFI@S9Z0z=e9|Zi9c5kfAEH;n^;ShS75#=|_e?dpF__yh8mH z@lHAhs3jbuCqTWS2G)ou-vDLCDK&o^B(jY&xUPFgnaQZU-r>t&d!_}x_}*z9Py%dJ zo~*7^s3fb$Hh);$S4u^*)^*L&3AJx#kqJWrpA%fu8vwaoV>(@ZVbbi9->7^y3+t`j zOdyK|8R>PHS>NTy{V24#@~TB{Ai*l~%)=y%p0F5LwJi!m{hd_H>zP%|P&@OPnn{(p z)I&0*F`{<3ibJlFcSRyTh*HXKypRwbS9wdOry13AL+CQ-QzNa5dJR*(3EzXU-09Q2 z$F+?M%r#y(sagSlaDIZ#Eb7m`f~_?_>%~Z)9B&#@`Qs7Z=aw|SF4b$MV9zTjxm^UQ&3@=GE<<&7(JLN9}mZ)$p_t0B4G1_N`E7X0ysF_!kS!O6?rx z)DQcdDb-YS_Km5JRCsx{yrWTQgN%2B{gCK!8Y`28OY9u+Ko1@@IW}nN?#MruYBeF; vmz$7%8{kQOm<9x(L!%4$|Fbnt&IXRo?v5s=upAsL9Bk~cBqSnoqOku9foUHh literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf b/lib/openzeppelin-contracts/audits/2022-10-Checkpoints.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7e0d08387ad3be0a3e74201566eca3167aead1c2 GIT binary patch literal 155606 zcmcFr2V4}%(iagF6c8myMiCTn7j~CjSjiwDIp-`nrzJ-NK@m8KN|Y=a$r%wzB1!Th zK{ApgXZ!~6PVS!Gd%W-7@8>$rbamCgs=8~sr>lov=8iB30%pgh{~8ybgbSf%rM0?e zip#}?%c9_HZ9vN+qibYfhsz>vqHjm5PKyBQRDOpncLf$SXtUJ0;cJ4M27%U6g?Z z!0*>g*dXj+7=i!A4$yw@;eRm{ z9LWYovi{J~(h6l@2h!CCx-y`pt~ubaBYS_>`R54!irxws7cSq&1xU}>K+nwD3b39X z$lT(@(#TE^;CN{Aqapkk zCH^Yj&fdZTkaF1IXz2f&1}NQo<^~`uLlDr-4*J+(r#^}u|E8tArM(?sY-?K+2cSQJ z4DBuT{^%Y@0p>3ZU`Pa@8WM^;7^<4Ing^r%=->A+bD-hxV_e7yB_e;&Q4dG1E(FYa zSkTj@g&Z_u;s5=PApg;wgPSVS_e_DFen@Eof&-%$!O9AUK_O5!Bn*aN<)DSI9mRnp=^wFZON+bt`1d4;!PZ#keEsozv=+hj z(EIrK<7sT`*kLL}NfZg)7_`m~>>06;Wy9R4i>)VY zH(4oeIP}!Dj4X@Gzp?txb4)&KtBtD#N>J(HH1 zMJb~O&;1_Tp4Tg!W0*J8y;GE*=wQt772`w8^S1dCX&p~3YI>N?Q=>mizv5o?MW7?2fpRQ_nRMMuN+Uc>+eV4mg>VCb_LU3q!TI zlnM=?j9EJ!Et>h(vln(Bf7#uTD4WKJh8y2ho2{F!jbnO?c%RstfH80G5~*Qd%dc@M zc%3$Oufwc^gm{lk?4p&ed}q!F{sjNB>iAHB`#EQBTD*mKu+tK)RY=rkZ-xIxbJ~p! zl~f6x^?le*$ajz6Om=pDhIDgK1nI-R37Ydl&h)|}j}c#3aKf)^E9;^gg?fn#@n5Lr zbkA>>*B523F?)WRRUTW##qt)?8`!4!Agd={q?unoZsCgPZZh9+v$J=1T++)mGVU=S zEtusAwDeG4eDVJBEctR|2dwm45BEFr_mve6^E6+CAzlaL;d|%)J~9r%@$Vz!#}wsY z$k_rh=J#i{q=CMPu7H&j5TXx;790r&L)qbQAU<%gLBJdwNOlAp5GH^L$x&#cJ)EiF zvd9_OS=rm_0Z;YAmXN~RgVyibCnlq8^d*LPGeuZQ0uSM_Vi5RfLD_Dw<;PK%t>3x(0%+x2b;@n ze=^@1KU%W!3HQuR%DFa{#67Ffl7QD6O0m^$uG<6heJ*(G!!v#vG*a5%I`(6~Jp%P0 z)I1z$HfFJHX>GBp!lsHnn`&yyz-`-LcX4Xb;~P

2ojH?x0tMLX1p#1!i~6c>Ik8Oj z%qxS4m=ed7GA$OUIx5ZcN7xCb^iXC>%iMvFrpwfu)aSfAn#5xD%>2LxvvlunUyLaa zt7ss>ve8QJ@0fKvVIo9sv;?yu#ONncir#>IAf0vw1un zk%GEuEU3Wet*Lk(iJE+4W>HeVz{YPf6d5)}?IhRA&1%$)Th=4#Q2kln=mFSEwA^~X zz(5rsML3pz_^hd3acZ0gfhHg1YKmUj-QK^ld;-XMk$dUg5PlDyhFUkME%e*aJFc zJ&Q-*EBqi9>mp+D!Lm5aZ4qyMYMP)oXII>VCN=rdOJvd-JfxGB|slUCL(((|@ zR4+~CyhZYju6m%t9NK$117uRv-qF81pf#wpjPBnp_pJ!HG%$$#YG(Vu-ES-AX^i>3 zL5Irs?9v$ePpEk{_R+t!)jy5*@VL>bvJlD2{diG_^CWi41kBe%56i=Za(>w}4y!)48P^Z@42>8zR zKjUWGB{29(7l1O>Il|>@M^Me#o zo&!n4VngJ>^;EA|?BU;@6j#|0-vZr>+K2jfInl-}leXG#o$qFE=bmDlNZ&Ar2WOb4 zm#k5grfYC**H| z0gSC;cs?tjr8?%#y3LF!uKC*7Y4xT7k1(rkN}^K{ymkAt;$9k+oA2J!%Pg!Aa%?Q* zx2fk9-ENR(H`kp8^@{B|iXx`Hztd?J59 z=9Y5BIJkWP?i}ck;xBQQG?=iwAyhk*yTLJ^oJ8QyDlg{JrZth2RAsfKCicbXh4FjQ zEhP@f7R$fg+S<~{>e!uqM0HDLr@p1N_YnMU*J@O|-pnn9M1NBea zpqqug9P$WX#+ctRZu-4=#`p#Wq1xfyzZ3yw{zkxet_Na|6gR8Abu$K)V!OzmqQgupt*RBV;(Dqpjkxf>-M~( z^b*qCf}n#TQMVZ}EtM)c>$x&0(v^GfvDKV(Y*qCm*1#3ScxrAvVk5VDH>%CHzsY-T zK}w_N@=pEM*>SufMfRoeGP=)#f-Ww0q?^pj{uN;>XH`T#e&H=O*vFi>#Bc9) z$Cx5KS*ous65(ua#h5K3YFg7`Q=YJsdTPv3pauoM~@(^uof5kbALbwx`zliuiQF zJ5Ii0cmKp_HWh(h3+b8Fglnigo?EdgQ(oCSh>We)*o_&iL1wdI`DMyIu2W}G{lyN? zsBi`|gQT&F7K7QNEbaTMEP^>d_UY~veReJUf;-^Ys*Ydyc0Hz++1f1(-VYRp}K4!E4s3YLzbd&JQqfJ2Y^b59^lIVY+!r->+zS zcFtwU9v@r&;o_ocE!frj?S^Av{5Un#&9k?o*pTY7*|7bUkB*!B*>vD%gq^~=X2UT{Pn^^_rX3+%)O*EjxDeeC zKC)AeKI7_upX*LaK}Uf(P%PPIVM#DN3?I0HR06n`W_x1@44fJ8am{s4Ek)A+^eLu# zbr=9e{}pEhbiE=m;MtUgUK?jmXA()#qOsn1b1?SHhXK#jy%rbABLj%f0^)V_^vlhA zs+y~;3OlzP`z@YQ&g>2tK2v{%+SjbFBGEf%p*MbKYS`|x6+V~B4!E|y@qTOdRGuyi zP(S&g@#V_m$HO+|Y!r0Lx4(fwR(4<7(2gbu;Z}gcbogHCiq-5#1Ra1*fr5?{ph&iI zZr^f5g6KN792s>f0$QuZiy*cDqswyByXE60lJVz?7WMVU?*dYv_1Bw!-P4r&^igVR zm>zuv*}1i$Q0JPuvUrbXp8L%3Fn!;ZQh*zdK|U#~n`eX$&E*)+ftxm<+n3OXNaw#= zD3SD3O}+J)MeWC=1_Ih~2C+$&f8C4O>8l5rmIBrUfGjlCKRF_p-sNOJ1lkI+um@Pj z-nLCxS=6w2ssS|ZEg*5h&@_J<4U{7g5fdXjt_$@Suf=#ynd^;M-%BHOmo(zavdZK&2aDZmv@dz@=k0(^jv z^egsb$^xD(Z5P|09|-KNmd}SA&~z60_f~gy9o!#$ZP740oK~Opd2P|8iwS5NRwh)j z&uyWFnd6yie!#&Zzr#>;9~MX_G;$x_vOzyFh^RUD6Yw3!{v zj?3ecXd8*nErjQb@h4?-q{z;@dM3JyL_Qp)&=Ln1E+Fo!_%AQ_rg+r*ivIta z$A1NPfcQqi5$Zo9ruxn!sMCXVf1iZrmA?vA-~PJm zc9UtM5XPY`lP=F#Vs7Tj&NLC1yOk*+uo%7XEow~eX^l%jIODf<3&`X-HQNh{wSV=_M=LfrRjhh8L9!@kDHiAfl5Kzps= z!W}OM>}vwehZLvgFWh+)en^CYCi6Q7IwU$>06T005S=kLI&AZw5&?@cioa)buKfty zfvlG?NBC}of0R#%6iuvN=e zF*=C*mJ!Rz4$Y4~b6A z&(S{$KO{PZK57FHVHD&aw)szqmO19<|DMfh<0Ei@tTXMcNBF2Bew0s$l}pO?XWINT zD*poOxD9&X(5Qbl(9ft(sLik41N4di#DP8gY>$ASm%~oyMYW^fDfGOwpfT{9F2Mul z!Fh+XYDuP|r{8DNj$#PmdSLR~oi(~a?nFW^V0y4V6!{`q?Wc1#z<)y}MTMR0ZgIenQ4% zug`(#NM6Pe`nN;x5vmE_;^U+vi8nZ;@Ny8oCD43GbZY*o%A@c@A|QSpwgHHM_;uLk zKP3WQv;_P;8!Y1^aDc4y?X5@ns3LxpPly#5%sh@U?BUEJNY^=K0fNF9x3;D`qe2B?(-azNlAi8d* zFysz}-@u#ng|$}Ixzl>o#WX{$AIW+r{`;;O3Ne;3hL=CyX67dXVXD;SY;ZY@VzYaz1Q1i zEz;~=^u&x`1@xozqewcQn2Li;oUu>E7@g0G&qW7kdP}JjWPt1tBnLZBQ5g^R@|N+Z zt<|vb3A@Ad)X&F!q)rDJ#DNOtIRVD*vntitD69N&R}qWMf_{OWAz2GXyGQ0>z)sD* zq_ADC^H``CAk-XIcX+VT`NAr~!q?CSm%~jbg&sAgmt#M+oEGnQhqH!N=AP}UPjS%# zGY5N7=X;}BNxQ?jfK4*53}9<$>b50S&s)Mlv|2A_K?~hZtgw*9tzKY{OjgFCDV4Yh z0Zj+Vcg#g}L-=l(#Urf64tLNjDtyr@v1VqjWPpVBUh>QF01_}+cX&Y?iD|$EVEaq? zvDz1^LP$BVQM4k42UH(!G)*QsOYO;8h~5}>n+EWwMNrOCJ&I+LpTQ}7t)Ivp^BUfz#DyU08{q463*BS$o z2`n`dmQ0qFl+ntBpOOcwF|}j&x5ved76Zo;=3|p>Z*WglS<0F-J0@!p%QU%XE;9}* z?N+{yo68QgXP%qt>b$RtJyFuYy!6HSrgQk5t)7O*KGTBM%8ca)8SiFxcV63Xlb!al zInvHn?7Zr62;SAPTApT)QoK4TH~q_j<;tVCpIxfvlDwf&h3sL7iV)9dZf1WBnJc5` z;m(n3bz|`@NtgM!8c`)t$o1CrT-ELQoh67GZ*Wjo_5eCaZPQ>VjB`di=i|KLRG7!! zMWt=+I5CY4D=k?r>NZr{TGVQ=JxVRBI~6^sMlhVLUK*&B`E)98X6elri_r?jtxf(W zyCSD?w0+_NX-#UX8&|mrn|iS{spE#yhuaztsUI%RzklWUQG8%8tGPJMF1s>Yc191L z_hP9-LRr#2`Dq*D|Z<`m0gy+XSP4l6k=WXWoYOJR#J(6_!U_8Q#;f zJK5KI=*dmqq(U`>Nk~$cXO@+knGTYeg*_PKXich;`G)8&4 zCQ8ShOUG`?`HRLZGS4U_S>JHiUd#4Y6hc+cW{Z?u%IfLA3mc@&*fD6K{d8S;jYE64 z#a?=0mRTCL{t@PLd&q5No{9UcqG(1-1DRU)Y|RZ)`eO3lfRZ?kGORYg#V&w>=CyheS6vCii1rY-CD1zF!KMEpU}|{AdxJy>Hwt6!(SGA|hML z)zEFc==MEj++mXq_fHH#C6ST0Eh3z{O?FVjNJol<)$$n^JD z9uO*03A;(nt=-+M%WmT7+)k~;n|U=)yn_7N4hrvCgB!VvwF8L*tOtr)HA8w-1VgSzxG4JPRLQ_&Rfl^9-0Q~%lhpW4 zt8af$PJ=?d0v1J*R?m#rp=IY7zIQZmW%bRJ1V) zO!sye%1AHk?M^O#c)jCQdfB_#kTR5F_nr%)O3Z#S-AFN}%AYf6G0I&R);++Ix!6Ob z_3%N4J}=W(ZDSSd_q)OgUk#SR*s*6ZErB6C9mb|%Ru#;c2er}OU>SAeN&x% z5Z5$$q0Y*i#<3oAwxtOE{!@=>osHMSfmE3nXXEEB)2)k*Q{~#!oH%id)6?}MImseTK`hl*$m1t7KJTYLDBbGVH(j&|Utjmn z>DAs`+Gj4FoSn%o>^3N}Z?7=1R}@NC|6)qot?4Bm5P4yHRc^3@*=TLGic&1bc@-YC zF0!$9Z5_$HRz?XP3{ykyFjqM8wytH|mK{&`m^uILQqXIb&kKdCq(L(aWUWD>oqMD= zdP$XUh+dl065km0PA*pd2=_Hvp(;U}I)l}BpuaHbEr4K2CymtXHb}VSA*23vM-Az9)jCK0eq-upt*Wp>Z z`nkG}V0&h6??sDHc}{+`h*MiZE-bjz?1zQzvMWt$8`@Xuf5TOpl=3YNkIw0x(?;&C zeMWWcKNM*TaOx~Hy0^!{ZN1~neu<(a3{)7MCFkjAbYrNW&#cR`e5-A$4Q7$-nWOE= z<2WNZ(aAElYDrnX(fTHmg_L2suhX(};w`1~cyo@t^pxl9RP)A6v{B_8wi|9&=^QQ> z!HaK`+fCG;bK1Usm{!Pj*k4ACdT72Oo{_h|UnL__57BlOlJeZAiTom{@~`=K2MN6Y zgZ#ULd^jM-{$KL%_$`6t>4T#OM|r=8xyy32ki%44TF6lzGUVud0puu+8FF;!0CJQ^ z4mo5@3pvU=h8%H$9;VyULXWr{=HAQELXWsWkGMdOxImA%0NK+A8P(7uF3=+`up=(8 zBQCHbEU+Ukup=(8BQCHbF0dmmup=(8BQ8g&zqCim!?eJWfCE8C`NFhpM_kyBxUd~@ zVLRf&cEpA4hztA(3y{(Hze-phRQrgo&lufd_#sX&^EFk0TDp zjvc^Z2N~#41Uox$!hi$FOFukI0Du;dKTMTYrajDcJUmT7d-GrO$B!jQA9jQj;DNw_ zvkPo6;N%4D{|L}QH#i9(1dxXcMMBvTe*y$$2eMNkPz2=vZ=r*(bOJ!fJjRCn{fNnN zkHH|nA0PRZ$9_K|aNJJ^RcdKsW$D9D{Mp zJO7x%a6b6PIjhEv-VTJ$hsbBi!@RY}Kj~s-N6JUU_Lcs_&HZ}y57C5Q& zPk}fHVkZIt3||;41P=cbh-3cvZ!B>TLQeqVhd1EBc@y@3@dlh7`MY_3<&8g`b~^5q z6NXm^6bVMcVQ}CH@sDFUd^(=MED#tQFjkOI;PG}G%MaiDKkRb&h&}<9V=e-U-ybl? z1`Hey{oQfDa?u}0@Q%6XaEfpO7!U|BW?&FjU>X4bM{)cY(G&_numcm9<2a7F=D)PZ z3B&0zx3Ix}e~KJ;3vk%(-^>R7bmH&0Yfcza4|*#U2qeH!5cofi<)on%m=CdY0Nw$* z$uTU)-1Gmi%LyYa5&~v}K-t-0wD2E7kGlxy(lFM)ov{7OQPksZI$^AZz+qqnf)x%N zu>9ZPIcdQC1s(t;l9d&Sq=o~px7I6;It=B^)tkGYEt$pMBQ9W4G;p!?M+%VSs{?*ia}03_LiH>`>bOJ+>1@a3~ZG=3s>)fK$`QvHggeZ2zF$P8iXVP%sBO z3<}H_j)6GtQeYX%&i1!1{nfGjFn$2WC_MQ&=aB@xOreV_5z();eLR zKjy<9@{juvcvK^fK7;V9(E4{@MmXlj!*@R?39mp{s)YZ$7eArbZe>~0AraKjlb(rIw zR=m>M6%YHPJ@$uJw>?fj4@vY?gbkDM?nGaW2wAg4RQ*=6Gd1JCSmnIa#{P|`W@g`H zyNy{-qXd)HiE!vM>C>g9g@(?(-p(l30!)Dqgx<~GlGN(Ys3N-5Z{}lB0LSKR0k2R}t>5bEn_w9*TF_bt&J+TMQ+O_+*nz8XP6)S2KmlqQFeugt2L%#Jz`u zFKXg5T}hzld)@X8)%7QjRVATUNcmFvcKo#;a`X|8%~nLZgptvIs4Fa4P1DI%5Opdw ziHS`9O2VwIhbrZ>d4bsk0AIh2Zvl2|N4fawe z!k({h4y)N#i!fD*VBHyt3dQzs>XsO+O0H2%8D|rb+85fH^6Q*%DY&psa$|FLbo|X{ z87>J&byM?KmqG{X>-yQw4k&nLmvG$8FJ<-E2ixFSIt;0v8!O>@@}+J=Hl-k{?nX-g zfZ_1XPysz)zwpNoIK7P8du z$~H*FwbSH=&L;|tKC$EO*6G|6&6BaP{-}w3JSCR81-6@{F_Gpz@}(zutA& zsZn+Q-4S2XPL{LPr^n$84d?blo1bzwH^q6lao4}a+Rw+j65=(^lcFw0)*@Jj!wR@5o3x=8-ED>lPjy;-=oTZ)N zrnst@SQ0y{!EDRxZjZXAaGF0$2!7PraEtA9+2ZOaV$*pTBW~f-oLC`vzO{a~yEbX$ zxsmcf3hThyr3PI^QS=~*+wZ=L;}H(#55A!LFbO(+MOA$# z((TFJ4fjqts`y0t)8?W0IWe)MfF!Zf4zuBQpG)`x4p>72`U7n;URFGYx&FRy^i}Pj z2B*40=2k}WG@xDTcaududrGE}(i{Kq^%ZO|L^`gC{xK)0Ox2eg*VR z8&zPd!_y6Zo!#2;`+FkX4@jsZLpt#{q}0@@v&e<4Y`zi)Iuy#@dhptbogjgj^EZtN zbikWzzpm?nG(1 z_vce{i68PW&8(_ll=l*glF)3Vmyxn`q|*yeda9K|?=YEPZ+{imi|9 z#%ufdLIRDnhE!0=ax>=rx4JqGw0G;A+glZ%anjrgO-HQ?HTpa$tdDsX`p(>v{N8Uf z{IyymSG=eoKJJ&yE`7xFBn;#dO}Hpgq_l2*$Cq&7X~7N15`p!6)N7+gBSzC`r0Qw35BZ}AR>8cA}}dj{TMblN!g(^;C>g%V@tTxK+RZyoZgkf@->BvV={ z<84t|YW&A471=$EJF@ww%Op~vObz;J9d@h{Gf%sJ^ELz-NC(x|Bth@)naZIGrRp{e zBG2?vFm{R>TBp59x@F0adT;^18^N0Y4EW5( z99nLB&N#(NTZb$Kv%qernNtwg+N<2mJI(nd(9WDmBx?-_UEqgF)n?idgGn z#Nafw?QRZr_!oFG)0M*NL`IBD?^vC@3f05E3gF&W$v?fvXIyj5tyn1DqNC|Nw%Hqe z5u?V?&~D>}BF5-*vIJ~6eCqnhB4^rr-L}n*Hx)1QlE(NFM2j7@5lZ&f#2pU9i{$`%?|B(L3^sf zDI%0?zB~0IU(W(f^v>DHMVgYy3MY_l)6-9W(IgziSR$bfLNZh`HyiKCjPbncxuwcf zStKYE{LG0eOZ`TyU!gv~D<@HQCP`D7FP&%R7I9a~-3aYvKIzd{UhE5jUnQUWkoT}Q z*?J~wP@}{$&HJc6yR4jEa`I{>XZT3js0UBe4}YJw0e^#C`6i_J>{~>pnj<8=7{N9) zuX`%SpWMO{MX;rIUZ)wK7f#NMGAdExoO#UzVOB)-Ds+<^=HaTv9%^4J<% zJ(jClU&e;C2&GL2nS`ErhRz7+s7cw(J|}({=AEvlPBE^eWlO2qgdy>s`~B&fwzJ_` ztu{z?(&=%G{nuD5(;uuKG!J?}7B&(-7%7T#lx~+3?0xp7v>>Mus(6LOFe19;ZwIcB z?W42`VG4ZP8SFL9-G-7JSs`j+b$fe-4Xs*WV|@!-Z1>z*?Ff%z^KPEiFNh8;SiA0% zmh(Fg*|$iCK3EB@<;)RyOxlnTfSsnc9oNr(*_n*n{nZdGhgT zlScAeV~E>lo!wk|3ob9t5|VAmbGx3#RX$r2fyueQKwqI2bOqctQ_>~47x1j8*(S}U zZ)(%e)!kD01wTzl#+2TxCYM{{h0Y2hPNC5~ByNtvhFiP%?<9O5{%c0i;fFx~JRv^# zYUuy}lU#?1H9yG-`d_8Ez>lxv|8_c!gdBdu^pDT(wWx^)Q5F+c0n_PxjN&biQ*Ws+ za7a=Fz#RIfcJQR zqS=aM#`>g!mC-aFI|f@{Vl-POBEH>{zRuyV zwQQ<)6M{GAuByq{?~~RTx8Euvgx}54V;PWky^UbCcj9rQkJF;wc+JGcEHZ4*JqH|< ztk`cBW*L%-r7aFw*(LYDR&fzIRo}K#t*XDx)@cp#fWA5DNfZzuDx7m|)(XfGO8M@% zYs6nx9Ji@g_Nr#jFNQf1Xrn!~hCGVqqWDo(?lJTJF`#_)Wau|8j1r4zUTg{6EhLU0w*2TAb>**RsdP`*a zw}>k7S7djK`qb_g#s{}ySTd8jqGdmGyu3DS&#y6MM`81V+g3rcWzBui-RkA_%Ge7@ zX!57Yy}czbwv4`3F4zvelcTiXBFYn8m1&%}K$d;d%&!v-01hV6RPF2#cw&|taIWe5 zdhZ3H7dMP@oSYIC?PrU*_PH)O53s5UrGyvkKqN~S zo34%qPQrU(YQ60s;w2)b!~%>UGbRfzTZvM2w)d&i#Hop2Ez)d2hUfip1v3>K&OI?# zzFW&0HgKxB;{J3RF z7{)uvn5XU&x3RcTJvsBayQxx14NVPtp6gm%mpeJf|HAs^G?Hhb>>ZyiK7JH9%4@OM zDp4N6uO5BN_c7NzMxzyf>SvpfTAl|U+E8RqjwVb&AN}as^Yld>=58T*aaW5j54_ap zCX!798iCaHXt{XlR2Q4 zVT3EBW)<358`tqCbozWxd2o(Cqij@r z8}uk?tbygG!H40z0#z72efonYIW+`Mw7_IVL&t^E3i@bei?Z0NzSO5(P4SY3388gv zsV1=ba=)PKTmvNST9Z~qG3z-{<6$>>QB_lPuZOWY#m2hda(}ZY&R$^EH?_ADEFgK0 zeVc(P`BywFL>$W5VtA4)L{dAun-wLLgw_ho-R{rD&5-fYdBr!-(>J4Et$%8mEGe6R z#`G+P-flzWYnc-bC;W=IF6?|a>a^@>pO7aM8#P*YywY0W)|x!GXsPJ;c}zZ%Ehb5o zY^W;ehsY?SF3Nn?xWkhib^42s^rJ=`A>uBF{YYN=^n@5?=?rLh>p{#;%>) z*Tqp`QAIhn=#$Hh>C2VzxjAC+jD*Q+ zw5>*=oSc}kuR@~IA6RgZYhpijh<}GeEhp5y1v3qhJ6quw0{Og;`to~!g(5bPi0?x zz4qn9!(MC9W`H$=+SfH631yS2lnON0JU9{~!Y{Js)C~tI1}&^WC6vN-W=Na$nWi%w z1twn-)E-QS4n^X0K80dQiUYHXcaYzNnd%vqNOZD$h#c%x5-rN^puajwrDSlB5nv$g zoiEdnMc13A-yFSpswd$pfljRD%r*L1w#}iMfJJP?h~gZW3_{rLm|6Ddba1z9@{E+8 zqV_oU_uBfibl1P2N5W+n5bQqh`Y@{}r z&q5>kgW0P9lWJZ@8u5+}H43^X-i#w^6qvf8N|h&<@1D8mGuPFCoy;_W=aqQQ%go{f z>gq)Y5_!d3A?1DDi;^!e*m}r6W>RC6^qb>twTH81AT;y@$|b%~>C_fR+L=#u>ZZX_ zA!nv_>I8iwAt5{i7W9ZI%+r^yPwHN|@-hOHTUR}# z#~}8z`N;oTz4)sd(FIl|tiE^yemala34E&UPFe9+tlx@~MF!(KtyoKZ4m*d^A>_-O zc9?6A*VipK=n}uW6!O(Tj(~M6G<7V$hd_<>Vsrt=>Z>!7f`UzaR9{ThU~B@TY6dA| zg5B+toXiw{3e>Yc!n+C_?GnwUwtRsqw|}EvDRrQ|s^7t6PMneePwU5RQ)Csju;|`C zXR3sr^D8Tm5$>Z8C-_aL;7O6p!{OR2YF=v2CrYn8Zf?|_aer&7y*rp!Fcmn^cYkf4 zs{2!9Pw=A;*B`2w$V$lC2-LA$lQ<=l5yk&b@KJ|=DjoOx_?w-Lc|r9Zs+S;gN~lmw z>)+HE$1WIc_sucCjc?S^M&B2WzS3AT$i15@A&)-*opJc~MuQWZL5g5*;j@zyzf;-6 zS!xCwd?M`@oe$*5C5_rLKMJnBHNFhIvpZn^C1cE`&lhTo21sdU-*n>5wU6PIYi^_8 zHCOUrOWZ5!u2yLJRXP$( zG&vvoR0@kpW$@M8A+(GIaaX-)Se_SI7v`m#9_4iXDU{kzR-P^1Y^Nz643WG#5Rtl9 z=Qb3edh??AyOR1I-=)Yq!s%0*Rs04WO1F8x~jlxl|jC|;A4*76{-O%hC;{N0UnpT0+esY3>Z^e3ER;Se6Frq ziTPCWMQD7r>HJkSp8(>@vqxl|IEtcU?K3c(+K~wmB;bjvA(- z8g1$%tf<9!?#--rCu((VrGAU9^02ejZ3_REmH57QjwB*jYAZ8QD^HXmZ6#_WHD`Z$ zEogXuBFD(xW5sQ|fjL>it$m^U;krLwy>VRkcF3#wERXi}m-EXD!cnfdU+x-md4Rpg zif*`$l?HXes<|!8lW+7-i0`$nL@i38LHEDam3`UE=o{`UP_cRluiN+B9_#hoT&H+l zP0wQe!UGfeQ0YDAwnX(DWx)uQt=1-*=?abK0NZCQ_Ks@`0l%`LxL~r*sU68 zB-Z^`c$n-E^tw@8Q5_(20 zk|)=zqCGhF$}_R=e#ugMK|eJu$w5)L3GecBSB}*^`;_g{mZ-#1W+BA9_BXB#nIwHB zALkqFV(~>f*W};Bp0$~M(F>Dqk_o{Zx4O@hG*=*{jz*$fqr0Xzc=z|qtE=~^oqYFJ zL3=6Pq=V(%#oSxD<(XBB{ZoP)9RmeU;-J;kfzK*$Crt3jjFiK~RFJY{T+t4i~yye$(x-yn>(+&J`I6Fu|>b}#y<+#eky>oH&guR zBM&Srlh_p7Ewj@(TYj0qacY21F+!H%M$Z%C&!NhuS&`TL<)q;;DJ>(f@%zwbxL`3s z-1+5C?=fQEhisbGsm?5aV@i}5f4yF}M8mHImzuGACigO6F;X_6QO+fC#V)KHZ3{2K zMz*bOO)2I;rGjna!-y7~wZWl0Bw_&!8=`nCD_Og*ie%b0ShSY?MTtIFfnsC2kx`MU zAOYFac%u!XBiF)iGiGg8fz<~5Zxk(>!aXSLXx+raJbEC;xKDngcwEVg6uN#dIA!y6 zbfY98J#v1zeVFlDac+V_K~%0tOK?J4XuTf?hBV<_vL%Vnn%iT3svxkE!s_K!=m!z& z^k&M-Q81HftH)<;)nv(R_!6&QerLebOSqWdKv*Yd=gR(8MD!#1=%ssXX!jJiAUpB| zowf}t<{V|^4fy2l#O1F$BRmhuVIC1wIN`kEDYJ@VmY4BD{Q^ERY)i7q$Vo?@2H|z^ zJr*7y_BQ4tO2qhjmHc9au@~W0az5Ut*wF;S4`I$W2$!6*j6T9$%(!&da67y>gloN; z=XCGnc6AL^?qZ03{L-C(y1ua`k%%#c;v_fE9M^0@CrcAzO(R%D?uT4oFw3)awTh!< zFLkbB#8Q|4Cc504o0C)8>|Gv`rfBlGl1I;Aphkc!*E?t6y0`=iKNKY+$&_}6JURqA=rWHO2fa%RmQ{Sd9-!{MQ{S z?=b0aPBDGC8MV;C_oCS6`iPQQKL&n@>f17-2ZUKg+|M3+cxhSlcy;3cc9(A8<8({tgG1LYlEv}whrEp=`ezSy;(jaRRJa^O;QxYA~? ztn^T;7dKKgVKZNQuV+X4jqbF3qG@Lgdfg3JE)HqGQE%qlpIa#Q3G6rGpjW~Wz;yGA?@9D>DRXl3MA?At$2DXFgTJ|_`vhm>ZnJ-GL4U( z$h~cHWn)Q;3q55?6?)arS15T+;*9Y1x388SZR5C*P112RF&HS`GP#o6{$4~|mW)vL z?8M~}XxyydA1->wFIu^l&tlU)c?Hh-+feW>Z)1NWl@-lH;imV)V zTDtR!N{s_Y@>A!=!{8euSq{0M*L?{z@nu8^)WPY z!8T4Y(FNJoxW8b1Ayd_gFX(5`*S`$p9(td| zNm6HLWOey09jDC`1Tye>ypvT&hsw*CqCsi))}1;$t+GUlzNJuYCs5f6T0KYgVdn0< zawcC(vD~|sL|Vz~*^0Ivuv#j(nViUuqJ<>Ww1#57Oy(zJ1VVJ`*)ni*y=!9Hiu^chYi zj4)^IGpnZ)+=oaIQW~ZClqEDDoz7FCbTwoX0(;k_f<+6O0=jBq3-cU0h!SFh#74pi zM|wdEk4+0EcL*u?D?j_Pykd&uO_ooh!ln_8yG-`hg$~*y>mE z!ZT74RHEk!WOF4MlKah#qpMQe4U*TK_w`FZuZb@zu(&f0ae9-p)kdtnRoU{}Ho2y5 zzaQxF&E9s3H=?C6by3+W-rY;#{iXLTA84MWOkG;c+#K7v9G8NrQ=w`*Z)luRBnVrC zHm5e@jJ#o~?X8*!t#Z2_o+h|F?Qnj%oMAYLUt8?nYjHfzi*Owdzp^TaB2BF4=uf93 zI@@lv2bL5{Mw-`?QaEr}6+}HYW~XqRe);lEC{3itHFk~yyx}`Zv~wvh7k7JV95J%{ zOCHv`ocj=|SnI_VU59F|BZm~_+@56E;~s_L4`ZD#Uu+5`cwm*iiR|Pj5jWNVSS8jriiO`^&G}0)fo$yf@|q{|Hs{12i3Li_rnkZ zB)GdE_m-kJ8DY5!pl4|`zoUC&wz zK1$8Ak*gA}k2qq}x8(oG?Mgv6^NO~&tR-cRA~34Nx3W<0EX_|cw3DB&i+?Bn19WkW zl($oBz?7p|r0C{s3RH%BK-Cs{`m87u+#T>!>|FQ!2}U8>0c26MUIIkZMY(zECL5u{ zw?GVKp;ImqSC#N;kdXR(1g;UJUZTfUjV0B=1^kd+W&{Qtms&dAM z8`UV-m2)8)q_kpdE5e_&r@*?TH#VGDdvKiPYC{#R8&Yi##A3h2)Bu)pLhhJWC=bW= zyP(;YjIA;2)gsDk&|{r%jQyv_Bp(W&iLynPe4)*1Hpt458BG0haUGVrYu^tK%i~yl z!OV!Gc5sRWLlrdb6E4hPlyM4!1$HR$7CFdRkADEBnA`Oirx`4Y=^0a&=~lOiOBaWq!SS)9;>__L563JqhQXJRs_}Oi?n{El&i-7C#Uo5t`--Fx)g< z5EIYe>@JO!UK1~#tJW4LLNhmD8N+LbW1H(pCG}fk3*@QDV#$Af%k`8LbCG&%4p5aVGeDfmp3@d@N{AX9I$x1fpqf@B>l71q%RVnVG3y2kzE z##YT@@92Goac^)9{6QjrHkc=yN!`9O57cp8kYy|gZi}la0;}<)NBb!A$eXV(%B9@_ z1RS~b$hGxIkoCyj;`ThKh>O)R$XhCylOhgQZx>uptaD*y=E#XY13$Ecw`X8VPgcl{VbP6 zYRPE#PeY9Q>mml{3&;%OXpS>rwiD_kKvdyQ^>w&AYhXiX%2zDSCgmRK6=a=y+VPuH zvSD*OrY2Spe*_MY)cg%Auyq*0BeOx?sYY&$bfvkLXGQkIX0&j}n0I%ymE^eA`aReN z@n?}LdM@}DU@s8#W4pg%k0_;o8ZpoOhN838p1P85n|Zqv0yeoBVPJ~Et=lwm0_xIM zm)e^6RQXFq^GluCF7*yRiPoo)<)SrCl0sdh94HS9p}GWQd{$*NdVe=Qu+9p|l(N1m z3e4k27Rc9e!?t`;jj2K#ndk7wmSJ65&_u_5toBzfZE}ixqJl(xo2U_=8F_B;#8I~| zYXq~Jykvn`c?G1PgYM;t79VtE_@xqMD1p#IBnt$b+93{4N5_5Rdcn!8_rt8!PK_}o zs^vmUC9i9o&-Unx^321~+XjP(+KR?`Den3rJ`At(`$FO!zAflrL?Y9ZO6rNe7fTk3 zwKYShI(NHY4``T=qQx?RANC;*tDFSu{vyvi@9aGe%X=^Ixw@~E(Ij!ILEfi$VSVKtOKl=xFP}K}Tm|=4k4qPitUfMfc~*N4kI8a|bMFvez?kbf5!PoEgzE zFdMV88S3i;k4_K3!~!rdVlt*T0MP3jvH|FgnAzD4003rVR>nX29sjj$3Ginj>p#L* znAzx={w=wVkrneH+H8p+ug4o|K%C` zyO1!>UY=qsz;_kAu2`BepfjXfmp+!%gZbu3_plx5L{WT{0!Ky%P6yt2XmX;xvG+o+ z?FISuCK2FN%@Cgy)%#eKVj9lvjcIE@rXwJE>&l~goWEu1XpOJJzTbV`&i=AKCRLR} z!EW-EX9{;R#c=hqLWWbTAB#*yyk5^z3RaT3caqHuYLUcU!Mw5_=lvBS2yY^o(7&)jlXm`8DYWa6NCJUAx*=yAQb>FIkDeBOe5G|O^P(^eR}_nZC0-L#9( z!{)S2^xebb<3&MqpR3P)cRwe#7`{kA`Q8lDZsl^=ksW!2|xenF6 z$`j`*c#Y3``G~?oyE1(KKVq@>M6|gFdY7U?IZyRzYGY0g z?dXnX5PIq;&+6={#9nCapvQd1`B0Rgy`aL~^SB^4wt|=-s@JwXfi+`Eh-5QZ^`vBO zQ=}0?Hfn0xBJS5H5Azg-Mi&3p<^d0nM7)zT(ygI#zW02IXY+V3K>2E2#b%w|BIo%% z22om_p7;yhFH>rKznWetGE9}>lg;&)ewX&QO^*`|E2{Hsf&t-f_a6)6o{~_@A5i*LS4@9lL$X)J;QQq z)%_&Ym=u+?WZ7V-!R_*@>2$E@{u$7Aes@$4{p!_HyJ>NqGJ1~w7ScEvlFm5FTUOB+ zsl?r-aQv<}DRQ5#@K`fW84+&uIM?<|?eX<&E|l->XSM`D?BWbJY(ha{Eh6ZsFI;Fj z=j%M`itSfc*E#PAwi-Eq4uSpsQ;u<~XTd`+6x)Tk*xc=sHaw-oaLFXunV`aS7!$#G z@x?89duD}$_rZ9SIH4EGhJurVA6SSo6jPoSh3VO9Io{Q^hSST_ptd$w@k%Tk3HJ4k z+&7|nMnm;k+4z}XaNsxg1xf=OcH}Xa`co(Zn=_ZTeZ#y9z&7YJu0w_ovP5cU@>^ws z*A;@Eo#J!vcPMsG9?+P2CCJ3YsMfotzx{X(B~OADvO31es{hKo&OkNl1~5YMzXD1z>$bo`>U=FS&d+ZIr|H56rmSpSYj5B{anXkH`nf}k^6A1 z4BP0k`c$`orG?}~J?K}Mib14j}(Fu%IJa z-qkaT6dgG>#yF;0RX3l|Jgx?{gB+}a{^i{!1}ZH&h!_BIE$BW2+W38{aPv&W+PK>&wWwo>xlb0)_VISqk$#y0Az!-V`tOOZO5#=MjaXhUxsKLz-qG z^QGx&NTcN1qB-{#$`^;cNLxojLcH*FO-s`h(E}(NtS^Wa)|5opcJ}s7J-P=~eRzX% zyh1YFt|(s?nTsT7Cl~m|iHr;c>O=&Ecz={NMD25Jakw8KQrDT;sBy~1Y8o9)kJ0z| zOw}1wvX2eSF6j+(mLh^l1)V9IJ#NRI?ntYrN=Oqgo2{l=Is^K?pT=JzE5%ZQUmAWm zho&uj@Zj@14Iy5J)NBamrj(Iu_dBJ}@H;g`x5f)vM1+1EWL8{^BCp210KSWAIZH(M zIlndVl>AU9_|)|J*wV)pvL2q<4R<*%GOjGcc+dYdV@0y$D;#va2bmC@v0<~x2f$yx z0p~%mW&b6?a@;Ml5g`gIB*mN*EkMyj5M?2Xt=g-@>1Kjh)qHv_{WO52afsA%iHhxA zX6UYSZ+=nQEU4_f(=~SpHez0rv(&lI@F3p8Is7E3h0U%kM3QL?gh)IxUM0f2EL72^ z&>loC4b&H&3B+!f_~z3J_-ha*$Tp@iA6#6Plr!#9fux0)Y2jT6`4~t?Fs5%q6rTG> z39BUyV-WGD`D9SwFULgCrVzv=yZZ#=+U8b+V(E*t*HYGdR5qRdx<{6Mj`F;>gXnB$ zyh44OonmS0K51dmk3LdN&T=Nco`rCR+~~Wwho-EWh?>EdUJsgauOlNHEKzK&;?#`y z@RWU@X*QGX!W?M)*=~a9O#-DgIHP>Yye`WnTs^Pd0TZA0q4o9PE8I!zw(NRq`Y{h3 z)QC-yB}|}xfl}fE6-9J-mp>TNN@|uOGo4gLQYnff<7XH>mRB2}>qDQmcVaF|bJAe9 ze6dwQrm(a5h{ z%s#dEKSH~}zYmS?9POB3M%vw76b>k7>Jpw*8)=m|^pv*;GUmuSiZ&=j;%_dk62r z;Mo#xmd##P@hB(T1cXriG1Xl*4~?tkjww{Itzs9aP5{TKGsHD*X0_d1*m$>IA35oE zZ|rWbG%XXB8?9nd*GKn&MFAeXbv3Br7Lp4dKK4{&ZC`npXgoj3+FoA2Kx(ARN$E}oD80LAXQZDm& zByhgFHq24RUDqxEaBEyyv{)r%uX`Y4P-cr(<)}oQukW>=52k|}p$E>3Migqg0wBWi zxF($Pd3U_s6hVc3LC+4I;NaaTf6O@$!<{46Mwpl3%;={he8lzOr3^kb3Nd3SkOOiY zdeR_hh_24!=GexK5)shSZY#U#GdAMZTA(4^te{Kqg5)V`X${NW*bwoOyb7UzT{G-uHXn z8qT$ORV2MVZRWF*`<(i!w&g?EKa@4ICuK57R*}TL-hwF&Lz;WVP2Oj`UWlm1M_aGd zW_@Lzw%j!+)`6>^uwr>IMASK5Y?Bw@ZHz%aJ%}yf!?GL;lHmYn{jNBLcFDBqP1y&| zTU(&%S$*aY!6c{O_Ek(Xzw>$f(3hcuoAqAadGDa*nkLIC> zIY&<3>OiUO^W(Ur9RPMDmXUG7N9l{F(4ZT}1v18td661!9ecXA;o~X9KyBRhOYH_a z)j3VmgUFBvwA{J!+OgGh{xv@B{bTRk%`9n?wy`_CJm!H{!#(@=pPb-OR_#PIb__OH zb@1RWTk@zDq>0+!v7KKJU~D^zedTK%0|ZW=9c1=4Z_)3jc0pX>)6b-6=NvO;tXr%X1v3#c0VElr>_i*n12c0YazEO? zTAU?>PlIkKlC3XY1?&tj$G9i1H0$`+?q60(1k^LQSc#ge`xSzAi_J!sRiUHmnl7WU z;d=A6oS5v!%4ma5VDPzM1h_VQ7mK60?TPF-17oNG-clvr6euUUc#=`Y86zY=<|>rEmgTW+ zai+|cHr8D9C@*%51Ch=<|7dB1m;LUSS~U^FW)J^3%nz;?OG|^6Lh+@fV~}a^T#hv% zx=?GY{w(GEED7iMD0^V^TIR|ERwcd-*Q+j_9g;JhRw@4MIFU`DIa=g)VDLrRhc8%l z!g*lYhOt!}JW_!`ptCxKWz2#N0#on18yo@lVED(5GQm0~SUL+3j0++{K8bNZ$yKmq z`1GezN42b(FGBH=b7LjVJ&}k<%VXUGe+Z|NZPC;(?$#t*YflyKSm2vWjCI8YwK_ox z&eC97pm53-3I~dNyn;wYQ8p&>CD3<~JgrN7mgJ4ejG&sRLmAo$qWt1zlx%u5eAzV= z7Oc9ltfm>1>9~`vw+y*H?#$duX)0;d&E{nf2!d9k!McH5+e)Z}Mr#G3+sY4GZYa4X zM#u`Dj_SbGNL<)kFO@A7x0+%lp_&4=(k2=<8n2^7*u@KE0gE6y#AlK6u?s66qH>9l z-vYWQ)ERnMaH`GYC{{nIY?6cL=|XJ#ygG@bADhB*nGMHtLR3=wfTg}t6l;dbG2Bx!P!j7G9!sCJ@x$r~ew0U@jLcIoA{ zuK`?(?dP37(!qwHm8838>_Y>JC3Ob_K?VkJO$P&n(js(=st;m(Bb6Mt_569_?qC~* zA2w33YcxN7YYmrDpwFT5$%8B!0g0^(s!fOn;c}=CYI&d@F12sy`_>}K!RZSWPB~fb z4rT6OHHm$2)V;LjHyg>GZz-D@ZQ|n#>)~Ps`#>4#w!&Ra7`ez}@xrwsI)4VaVIx(k z1o<|niBMRXqq0R5Rtl;aI*gPMICIW7i$$6%Kuj}9t^|t139ec6TQ+4{2Qbes2FR{= z#`_}mG}!s+|FYf$P+;heKwbFfgV$Urg?@12zf$jxuAMI{p%nu+zLw3up!`Uyi^SJ- z;B0Bf-`nLpd_Wx-_%ogk`w_$??aKJM^f7=8=HnMBIBqQd#4JLiOlXc-W|JiF!5K;o z7Hvb=Yu8^>5J(CAEqZ8e;y9+cM(OOj(McRJxYrym1f)G?sP#~(#iQy>(DQ2aWL`?y(uE`8pTIz7j*Jm55whw;=R~93$%h!LPjaf9egtBWQgIxC zvYD2}+I`cwYq+5LDrdNnsNEry#u3xCiq~d4Z48gjdg$yk*{F@dVW(cX++78PIF~w| z;Nx6j;~P`_fXb<=ay_jc*bE--3Cr%zHVIj3D*~PwdQ)>V^0ijqS=g4$UD&Tq0WpNt z9HN8?5@Vk&D(lo`Byd9D08yJ=1HMwMOkmcY=D%(=kDO#G*kq2nie+Mz z=p=tmpx>_GV;MwSr1$w^ar?uh)t)+29uyA^-oiQ8VEdJ!H-)*UVY`DyrqUm(sh^AI zj=U^B#{$nPX-JOSX0VR~IstGLUwA}y$s?L~UdQaPGBO`r0$u{}D3M#XTaR> zNVPwv#Kgux%ft>0GXn-<0b|7ew@(Sc`qwG_li4Hxnux%}!URk$VrK--ixHT8%f`&W z2Fw^{VrBu3?vK@fpNR0kWGgYSGyHW*e>PJ6oeB7zA8x0hi7`@^UC*-%;|gyc9348-w0S3ku@x zVa{CN93Kud^AAv8RNNhP#IHRbta#OT#XJ%{+1!!IOyoz-9>liBg2hH3b~EdeV<*>= zq%pnFWMXb_B<# z&mBID1{D zQQ$kx@R4G=K6Dp!qo21uU9+BhyUg^%j|aDV7sYdPo8IpR+;#l$Ycv78lbCu$z%NWsy3qH#_4li1)6v3m>m!3Qn(oas8=zmjMI^bJncGy_-)R-5)gH zPaig$HBNdkINi<}lh_wNrv!y^=2vyg*Tb`{7|2_Td_3YoZ28VntU4J$Zm<6HT7_^9 zhwS1re=?b}svRbI$zT$>_e9L?v~rxge`rrx{eEyQKjIJJ-P>dM4V7AW3SY#F;4RZI z9Z;8QcKidL#x%*B@Xuv0pD{+~Q24B|EsJYcKc*~LE_p+(j3^@)zD5;v#IPjuuJ&${ z@hdKoU02rM43mOOSi}j{Eq;VPhO;|iJ`M2}kzWL0&sjq~=#;X9d+pvrNLziF9_vKE zei^N3f4WPp5NZg(={9nYxvpofp|xc_cp$VDJJw0gCN{r#yd(k zMq`u76oFxx!hbQ}^_$|Dr1pNyOPZI_L{ld<6YDsnRj1&M=Xi`mYdb&yjJ44$D1CyH z^X0mt?YaB;d=V~PjvnL1`~h6Uu^bpk&^LOg<~_Y~7En2hEA8_>x*4vcD9ve&BlwcW zC)Fy(FdxgLBT&UKgFD|K}Mso!-MU%+>_NQGF&nLNik-J`lw4m0v#d?vTj(K*x5ax`F!Bov z9#OQ;9w0?$7uJezYnNTdbM*w)>*MaCF2!?9+*M?j?3dXj38(DzniFt23?0fWhE+1l zlFYONgCh*7BtLNZc-N+}esR!nJLo&PiO&_fT;n+O)`*^Wm9Un3YeE^wOafou+1_IV zd6dQpXegmTMTeQ4w(_A~dgAEf*sMNjPuwWU#lqVZ+m9q^Bf758$6EwlFzRt!;L@^f zYhL2EKaVy8&6Vhg)7{i%WP$lCudYTPPp1sO+HYi_36!o*1LX1iYp(f^NsDaSyzYl9 z)wxQkBG%7saC%4t0DVXB3hFVoDTbi@Or@9;1#v1!|XK?Br5^0DwDb2xQ zu$cvn@Lj>K;` zT1t5k8NVEm=I4B6VJ(pY0$!_g8ftcIH-CPH9^v=MKYs6FGV7emhs4k2{goi?K~}it z1*NTA#iuSh`$5gu(Mkr)?6b>~zjNG;xB)clnp)RLqRW9>#<#m=&ldIOZI%LarNDP% zqk?4sq_x>p<#o7u5<^3iF;AGBFvYAw&21zMe=eXc&wZF#BGf7GvBn+E+OR^lNo8VV zV@n}JUwrMb?CHR3Hl=L!VBb5l0o2W5~(*R&Vn2R6_p(rr&H2Y1eUFy1qvQCyGF1P zv0o~eS^j84AWa(;@G72@q*VO-ReU)N>J=8qMdS2ZCxiTOh?$2-I`jf+<#+8#%Pn1# zNL-!Uca>lLJy)=dP?}IUXZ77;R&=C@by9A&&~VdgTQiOX|GW@xP!8F2kn9-k$M8d{ zVsI|*Iqhg_iNNbsi%+5+;~5P1!;D3#);Ot7d5ZN7vryzU_^c{AneEV;NobBa(SoCN zML~*n?r||g_{mwQ3#FFu{0y0kNDfEzh#tC8Xmv7-Q{3X!&6l;TNr(D*u;kHf$FIG0 zef`&?MxQ4p3~TNsap_I_a2uZrm9b-txPy;q13oN^`|1fyI7!7bzdAl+ zC?+n+_Q->_W>$O}>*ex;pthX%7%USfQ9SbX0UQ;eBF3zi7)5WPlo*gByESzs$+%Zz z9Xyg6P#O5Bty1PPyKTn~8xjx|9NdX0E@{mZSyOzfPf&5rnCeRH452)*cag}mQ&CAt zKD>atCREpJ$>Cm!^-*IM^pXv9sc7=-^(ZwbqSF>+rK0_cm0jw>KTY=VBVpeB-s#F} z`3EBR_;n{?k_;e_^YmTw&`OE>wxppn1j}3-;g^1oLgR^|YmNPre#lP+X`L8#^`g-l zC2Q2?*=*fYb>4nxN7|xx;iV)lbvEA3lg-3`T%joAU5{MPbEdf@^w=5hkPWG4>ZmXQq zE?Ox|?Trp1Rg{4qN8ui`9nHl$oZ!RrKOpQ~J#eA9x;|>at~^Jkl`MX?`;|6ver5_; zu-{!%gAoUu_2OSv1tqdN7${-^#?92FrEK>kvg;bGUL< z(F{lRIi)6i#}AR7R8~V`PS$nrJ~7KoPW4yQW2{g#&aed& zR4u^m-c$kxCJDCW5U7NTx=g3}P5K8N@RpyMIjLMHw?yQFd{h2b(0*EVa!>pisQTzR{w>A&Ff@c#O`hAotNWaM+mIqa--Vp?2vNaceHZDL2x$( zx{Coq>EdY6Ul2e0ZVO4oRR~b<)xA(Ohjb|<^2hZxn9185=h0H0t?zMqdw)#sVyaow z$io)5r`*T7{RCPwx(1+YV>%OkzkujW)!JS+cAeHgDLadyEC$|fty#}iCghZ+383s!V_bN>cK!mDnu?1iQ1X}= zTCx`f_ZXLfyj)7{pp#e$n4ZB3Snx*x#NUJV%N%}$W)IBN3;t1n(iu<7YS-+-)I1(I1IKwdFAYb-72ElIw6;K>XG3>ubSCRyhsX zJ)njfk@>}hAZC}OOieZTw5c3 zq*W#e8>**++1`B@22^MEQH!oDm>)}!O^FR^<1igT5~YT)b~FK5~^hr*h*=iewYqF0pZ~K4!yBd3?|1a0$~=S zpFa&1$k3Ss;~o$ts+B8D2i4FQmdrVPmU02TA<8`1ufaMurCLyEmF8?96-v6v?*ADl zh>7`9vT~jzM^Nr_zoP_#B#0JvFsZIaRfs>#Wnyp9BHaz``0{xfXv@+0KUqxqL&O#b7XVMBj0zHFr8{ z4d%i$ke5g!zR+>$gGoW;H*A1?k3aNbt%0-!o0+=#NiFySyH%*fJ`SN!s6d(l>hm-P zH8uiGaEMyV%^X9c+^^ES)V`F>C0ybH@jhMq>CY{Mh*Ggb9Nbt`$g2cnC34@_u--K# z_w&EozIIu2*nc#Ej|d1P{q%LCm+;Ab$a29f+U=_~^2g)71Va{T+r#v@VM8s0hTNXP zl3o{qXu15f7Xk|DNoVI|K2f(t3aYE_G$QCqiSMLi6!u@OD!1fo17cvhgXPH5TXtp3 z)O5mBN(Un4*eqVAHW?wc3k7%jC?;B(R@g|nMe!B3*3z&g6v^^G?60UI?9D(os`~MD zh#;n`>+~y9v?A(``**Oj3O98j))NM0^M#L*-R4L5GS8iKk>exUR;h7OAGRwb8DWp{ zh&IEtaD0PJq})O3OTpR2Y7s*+HR;s?OJ#`FUbYI-n*;v!TX3(!gLQWAJLfY5%XDO4%_jqT91jo*ht- zdbXnC`T!Rrs9{0D0Lc%&=xb3lSV^To5wmt4(FNGGSq%I}2O-?E$QVAG9tfMQy=fi- z8;lbL81sevc3Kufc3y%oBM{*?YRjqR-=5S?WJTF3=>auPnM)49k;{i8=x-Rq_5Ccb zj;0YvXc1^p+vS7?qiK=O&WprOW$7%cnMN+L@Nq|mK-vziObD(m(1Mni78}W=uwLSR z@S|1CB2Sr1KF~a;&EAh6i`|&W?e>LivPUws zuR6)6LTaObv=W2sizQEH!23a$Cs(I!isIFHxyhj%o`ho?A_RjL+Wrcpn_~ zn9^5iStKaIuJ#+o#(F28EN%l;U?d7O)ac?>ZYZ`DJ+uoI$kvL?u{fa7Ei|t6#g;i0 z-j}E2Z0+JIlAJ`N3MOZ&OC_%ieOEKwMrIWeX99-g|Mw5-qA% zgB0&PuY;FtyA^vOR=Ab-biD7HHlUHj^E0N(`)U81xn$!3Q%g?`r~QnfT$AP4;3dS^ zUZEtVJqnZrjQobAZPn*mFpou_&sgD$asU z+Rk~}2%Xri$Q^bxd&t(ByNQ*LaXW+O`saVW+%~Vt>AUy_>~+l=8r9KQC@4s8xL-u` zE_X?Y*LJ4OoS1fBeL!@MWj_6TJ^+Yl|Fs6^zl9HA`3-OVV?N-w=o&}_{7nJP@&|uF z!19}(kOvls{q5y%TmdkL{*T4~d9L8!>%jl3Tmd~ZE%V91Eh~Tt*qKBCU}FIm zdi^JnxBp83UM3dyzXH7fq@w&!j0!zHEjtsi^^6VJ$@ixz0qczZw)(#o-~A7!^k>!i ze+33-0M_F%vC#uN3z^t}ol3wWxZh)90b<|m0AN!b5FBR#=D+{3`oDHejO;9b-Aw4972cikNG-&X(s zo56oG> zUKJglEvl(8-jS3tUpoTA4Zl;Pl{C%sU_3qN<@tzLN>Bg_E^OaypLPv@;K06`(d5&e zUPa$9y{RjpV+({H5@Odh=tnrg<0Hth)3DF-k+qZwZMlX10Z=g`F zA=#H4fFGlqOc8W>c|FWLRt1xzSqy5dQ)>y$V~d?Gh>^;M&x5cS?p}X)emaWO8tGnt zyT5sZMp{N#RgCrVg{OriVyS!GD~N-Y*y3%ZQfpJk{~;SjbK9xjOmZIQ0?+Hk=5-tF z^SF1v?)9vT@9pmMG+q&TnR_dH_~rZ6>9!B|%gyWI@=w)W3R*y}`Ky2wiNbApOrI7B zD3}EFMc_t5ydkWY+(K{5Lbbn}m@(K~FMDFF2is4O`nj5Pm@eOb(v&&8rW%&XLMKI6 zu$zc%5b3#?uC3PSUIObloru#yAf3{MKaHl@+bCHX0{2=J>wN3U^O_8El^7bKNrGHM z5zN=bEOGM^EERFC%QP@cXSmWBgQ>bd@X3PG4$vhoaJsN~L{HuHL({n1T_*p2yEVvt z`ayOz?(+5aXZ!m-{(Ej8`q~8iqb`ZJ*1>xXe_O%0HDKuCqp({*Gf;nfGkebAf(*Gc zL)vR-vJL+7)llKnZ_P_`L?PPucNNIYqJsTh6E%T%oO!$b^KPCL?J4)js`9r`iut#`^!lqDLf#8BDRt{g(N2m&Jh4s^D5dxUb2mpxb^}d< zFc8`iw9(8p)eR9>3Yrw#v!g!k(H#9?-oo1Aq0=@4(BO`IdBRR`zj;aXt?;td~~lA9LTsOJBrP*U8!*bVV=v zyb}F#3^Zm=IUx6TAb;D&_kI}u^$rR>H8YC>sD<^YxA_Te692$4ue_zQYB@c&FFM(> zCl%H*k|O4H|BU~3xQy?+-2?}Nt&0=%Tn;~{aWo`=aSFx@VfFFpp&q+3*zJ67#nWMp z$@z09XGXeBjrDrjogQb&NVV17)s;~HOvyf~Qf7XFz&Y42 zc{`OqdZ{O87^^uF(cq?9i5~L2XGOPibjU|TJL}iHANDHNfo_V6Vb2G0xWh% zH?2rlV_y!+f89OE^RyX8Ewb%h2IHMcB}SmH?SuxzxRnIB@xH`)(?Hoce+2b78D*j?{Wptqtxz_3UxE2Xc$&gUC|S_F8bVS$&*GsI ze@9-1Qv~&E(X#2dqXwCD^+KgF>70)s1x91mhPhXkUW%0ZWxD)DMF!p%fwse6*YZb0 ztgTexbj;&(i>ws8>c3rVi>zjCI*hQ^6d}QUWM&+cbL?3gsUbNw(haUqcZJ%4FIhI( zTnDM~BGiVfgOY70TDd#bIaAx;{B4M$+SoUVfEJUKrTP1d(av?K#{atA)Z2T*c2z`tTAG=XLs%Z33v3S^@rT@wV0V*vlBf zLa!+lHP)#M@jG@Vk71vJq6#L*2FS!jagS8{-pd zcE{TU9USP@Mc0rYy-k3CR0PmqXpuE9)9t`x@1ov3BBLCA5lC+0p`Ot}-x8jk)@ocX z#N$t3{^;0j#!F3C`(c#k3&=X5h1LL0_Gr!d#8;~Ea!-5Wa256Eq7K|Vu$17<(wM3Zw^**GAy?vCm#2- zG8Z_3{?}?OIyQLrjLWz>kai$&Ym(3V2vp_pE0%YsdeJA14OQs)Bzql%IXS2udMlU= zedF_Tw3A?X{v0cgL2L;h*saP1xBadfs*YZ5vq!>4>eHLSU+lLGN?L4Wp|>a$E?97P zk#5lPHt~2u8!DQ@M7Syiem`(*yIsEX3XR8cg(08DpeM$bxn(0QCAXu_;(;o?CDm_H zjvMtU{V~y!bHoBNar*>icAk9m6Dn8*^68zo(_W~ARAW+s%rCNcpRQS> zqE4gx?cWhZ|z_57{99twc=W8AAd)EhubMlH3($>wp27_AZ>e zxQy86fPoy|U2+5W*jyrM36jVCy9$aYirfW8&!hpF<~I1vrz#_r^=<<)abfg0iJ`^C zd3DII$<`i{eB+|RV^rRfQm#h;Gbs!jfy;3@&V05(aMM8l&43HB~*-^U3dJ3qoqfEM9Xr>NsJc zY4lfE=yqXrp=m5`KWVlY0!e>F^~vESPvrIz_S6Jg;@Yu_0~QS6kZAn=w(}J{84M!; zR|5FH4x{Y*QR30a=9{Ka8^5>yznt3SQ{buH-46(-AbXz2YT+v!l)4L0(fQnS8EVV?tb#uL{?0sO#1~)^f7MLDdi@)lNm1 z7$ZVKmmf8^8Yq2_{wW+kTO@d8n14STpY?&HQfx&?C&yTZe($$+(B?9o=fnSB(<-gzTZ7Bdp zHbLSGWE@xLDCQ=DItyTHg5M(GzWJ20H2Vvs?t5(03f204nxpr!2hT3gz9H?nNB`_# z!5)Rd^8VXvm7&`?*zvRrO8dOg^{}%va=UhLJnB(+#);Qk(VDEOk?IGjc@?dem!dV% zAWTz$ZiSc@Z^?o1DUM5m$D}>i;_}TLuZH%ahbd>qOW6yT>TY@VTcoAhem|Ysu*f*< z@>@%#&$2_b!#j^N?6_8Nz0a7h4z~l&b9d_%g#X)9;DSW8efpaV8uhCIeo!54xLQn& z3RGy`2``TopPKymVIK0jLJ_Sym0OFJ&za&0w!;g7^Wl5D#`W?Y!rdd@kQK(&)4?w; ziIZTH@*sx6>0sHQ4?#>BfbKQhVF3=7i1kqcfE|zg)GuMyd}7fR0AjyDKjNOka^Kk0 z!DS7aW2CTKOV;_ejN`Ed8&2MBe}(qowcRlOvyS&MKCcuG)8GjO?sdG1s}50nKh)YK z=)*2nv|+)I^>ZgFQQF%3x6^eaH#j$jnC%o=ZydXEvHE*JmSj zJN2vMURxUCx@;)6Mz#E3x1spzw zLKA-Y!qZn@KWb-p+G9*rEv0FR$SLM)%1guXza?%h=VQfi{ew3er$LzM&fa#@UA4&lQ9X3}H9 z2PW5)V`K))pA4*mn@Dh~2+E%ezwV}`R>|ACso@>E&3KALw-T5a(q3rBa zj_M*U$@5GJQHhm`^LuX=76R>+nvAQLWS{`>p*pl0{>E>#QNDXUd53;Wosgf)%tyPS z8Wl5~FNVMUj-|gQ`1E#NgiEXvdV-O$(IWt|p97jxhioGhUrQPQ&(<#NP$=|C;Q|kf zgqDS%WGI>r>bY34hSK~ecuzXM0XmFpHq@^YsQOJ)M-2Ls1o3`6UA=4E@1rxNNAT1AZlXT(;}5I( zi)6ycIm^r<3>yqFh+B%f-D0?0Vdwp)DLIqwtoa+fn5X5I@D=c^&^#)QJ4my~bbS?E zq(4@C5TW9rWTdkDxrwzS^$fEPwu>ZK5Mkpn!kizU(Bj%FVSt9jPKHt+}<=2dD zVEHxHIKsvv&9G-$#g7OF-0{eaSY-{m3zClfkxu^=^>`^*LtHbv@#$=bWiVc1MJ!C> zE=~)L7E6n@Sa_>4e*i?9f^jQ_2pta=m+i>eL_Gg&TANHOd%kGt$QAQebs$oWUE_su zGYL!w_P5P4R8zrP^7u9VrV7QXtdSu*Dd|IbBLl+ROnBphuONYOQo8VRrXp!8sI4)m z?Pz2&?Z>Xk-g3%?Y^wHCoWJMOYx8`tty#pnnsrGwo(-~imO{}_6l(>uY*4O=EYmDa z&=f!y^OaWS(voE|p3-OrIxXw@_#%3^0AOH>Ova5Oh5}5+ua=j?-*OtG>_DE&KL0q< zZ3m!#q%1v{wM7&v0o8;}q$oy}Z;vaQBPYbgG7A-!LhWc&=$KVJZoxt?zsogNsDn7- zOhS_N$8e#QJ((kIAp`&axO)qry0UItI0Q>@3-0dj?gR<$?k>UIf;$NWCj@tQcXxMp zcei(vbbnvc-BzWfsT8G}OWLB*QE4?$)g z_U;SnB@g?|f*J{=1P2J`;BRRYgw%RkBi`q4cJD(9G05{|-s^tg)~TX-vW%ZU^y_y6 zI)4P7RR1xfKJ4E!>R-Lcne4<}!{awgE%=CiD;;g3uOgziPl@<#M*SA>`xRBPbYIsy z<->2CmSr@JUQw*}xPJ8n52kSruF3(TvG+>J`+m8I*`W0Vm?0>>*}&@4v_advr;|`! z1s@Uj(PKPo2eV3aG{ykEmUTaREhlMvDjAV*G+Xw-G)K*K(I%NAtH{OF#00Lg-CJK8qxI zGT=Bqt`_gLSl}VW%^TUI2sb3JC)>|bJ0qVM=jU}jOKBYUDUkw+bk)zRQ?|!n9ljko zs!d7cGNM2>m|s(WX*Fgp*_RQS-cyl*YeMt3E{m3DuYtoYfex45+AdR@n@?dJ63H#) z*1b=$Mkl3qN+S1zloG}jIL9rE!&b5ApxPC9^=Y~1X!puvgOTURw)h=}B009on30TF~+}Ng=QlfsB6MbCGQ>IBQw!;rY z$lG^liTW2x?=R&N7cwfHm*-JgRi}0nImb;Hy@oFKB~}JGEjdp>B4i_$!%LmT3QotQ ze6e=9)%uTB9KG}H9$LV{+Fb|>8cUljC9@uGo>i(}6#iL)!ScT(!C?6>B^WF}Bp3iI z>hJoB9}*0f9}*1K9}*1K9}*1K9}*1K9}*1K@2`vt=#l*PJk}qt!usP?Sbw|<>yK9f z_}+ed2%zun+aCZg^1n6a?)yjipRrzm&NBe(^`p-d(2K?lV3g?@aRCwz0PFP+*KRQU zksJJ*(v6?EK^A~-IU~yt?Z!8MZr1M|dn^Ec^tYq`SkjB(Pg(k#(hYh*vnwqtJtKfR z{?;@68*1pkNjF&87y+lwx1M3v|G%;H8;i`W%cKvWiJ1*)Y3XPU^z;mAbr=i)ou@2% zY;-y-wDgPspKL=tJ%c|Yw?4j8`KUo!$GMglVPe=!Gi1_pF= zOpH2oI)*xW40KF%h6XJ93`~Z)It;Y>^vs4VjC%SE2D*RjWc^+O|5i<51qhkw01_Qs zCT4nSI{NQo9YB5okYJ((R9Pm*ZyJMtwuA>DPWl5>zJEph57Pu7)d6+nn}p|=G_m}C z^q*T){+y=2**#7V01GWEGb0mV5bM9u#J~W65MUC)H;ny1fF^o++CQS{Z|X9BPSd~9 z^h=ul`Dpr!H2tj0`0vOI*;oMuiIEoI*ZLD~=$Qec7DhH^z*ygJ6C2q6;kAkWPo?S4 zTkHQ+4@UQMmH=AS-%8WZSpsNPe;obCmZm>v>2J!O836fU1ZY(O8-GSdz%b|^s9^+r z&(YJ-eG`u{(zE>Iu>=@P@yE*aH#g6}q>1i#*!-L(hJQiq9}A|xNYmflJ+rY)YVC{ZC+q_k7Rlu zeO%CNT0U*jxy0r;dUf*taUrVN(v@=B;&PnA<*AoDvf=t_`TWuGn~=4+!Bx?6vTG=| zQzWH9&EnzOis$Jtv3RoUXf|$gb}CMK_nvpTOoO4zV)Xb>r`|9D)ls$WL;CT!Y34NbBx7#a8wH<$VDszr4gn@4eOB+@Rz!_wkMGa`sz~K^%v> zl1jhfd&lj@K5KHlOy?(r25BYl_;>E(LfUM4_S1&_+5AV7vKr5@83u;k?!XZx;wZ`CAi zI;rX8I__rCk5TsBgA6?4ar?h{bC1sHQmu*zkDavF?>3`I&3;0WlP%Mswx=VG#oSuv z*6KORMYD;|U5=AYSw7SdK8o&oXP8x9*>qYFUq;@0I`9ZSwp0XUw0#<7=Krh^c$H!G zb~@qeU~$nLvCAdsZuZvG*F$9aSwiQj`=TN5UTOTWd<5madwfGs2-AM3p@7Pn!!13) z@$UU7l|6~A2^mSn7LmD91Y%1N!hvMs`dXEE!jZ#A%0-;k?%w;E8X${-cNl94lDMWV z?`7@RB@cu^cjjhZMvT)S8XGm5Boimr(zY}X>*6Q+)~6+ZfY`>rBh$*`;$>IDXMEL( zWOrO<76I=wVos^O4RGf!U!-k;b)`EvHw{agFC472_T*FFTp-pO-)*Y7#IFwNt2;J) zMOafxH|WwDj0=iG(&zV1^lMnEeVEIZ)K?~jcOPm{sN#<$U#9Y^IM9(qJE5YzLY1tn z5*K&wU}4Nxu?=Yxsp@;tY|n}|54ps_ccPW0-RZGFFu#D96bjekqhv~w{zj%Oh85@i zSbmtUfkbb;N@NAAw>kN;CDN5bts&EdGJpfMYJvn4PIIs{h6rCZo`8-!6>VO6wGk`WuFgm6Z!=~g!CMOTD>3Y8%wF!C;FEcc>5JFu z@5S`E8K(}5#UhH)lchuD^op!eTkFZ=9S9yepClB4Hp34|KyokjOo;2HlvUTxzheRx zz~6%cV-2z$J0*W#p_`6hj?fP!63Oo+mnf+rFAkS7b|l$OuAY_|6RI8e$8>g&I+Oz?fN+ZPg*#LQnm=s0?WBSb#bA#y4|r0d)Wgp3UYA zjf(~opYJpP7&8m6QW=+Ji9mD#g z@VMO+nmPk5q_{|A=vNS=5X9L^Ht zn+V`S*1b(3{rtjtB59_Cux3F}+Dd>Kvqax#%)UL)79&12kq3Bl+vip7(WDc6_t8QF zAZ@AzJocM6_eFkwm`NiKDUP^|X<->RiQFk)6d z;HIz^S6WA?*gJ$&7F52H9f-)cZ>=hTH%Fjs+U>Llm`>FYM9Glswwor zv9>5Ls4ga>^bvsfLiPep*BoO!?3REe+m~cKsLMgeL-MPsks%Ct5z*2NedABQs?bYwv6; z*owLLB}WKI)y#0mSG2~)Cge@#EsN0RBZq(qv)++-#@w6H(%CQH6j00SSXks#L7=bei&<-f zoqK@=FHE7g9> zTB4KO4|~k#nhc*IxUn>6v>JLnHwPa+Dm?c+t(EeYJ6+H@EjO1p!!1WW&&FO^@h}O| zO(esARFk^%6I-9PUPVTZZKyVI$_fA{#Q`@F;e5z`3=IQ)$mI!MZCiA`=ZnxQ*ml9b zHiAk@4sto_WWx5~*G z?P0Xv>DF(1Rs&1@Zx;gJAO5c^f**m(>*xaFwKBvN01Su)Jk9psG5sKIzsL0ND<~Gg z4QA#awAD``(f;dQzb69_grtEJAinP(>*ol5xvTUe0y%pN3qVHx{l0+Pk>7~n|MnZ( z7&!bZ6Tf}-U!(X=LjN4aFE?#|i$V|JGWJspKiKTQ7sHQF`+NR>jp4`I{InLo+!6T^ zgD7A`ua&<2cZ;;2Liq_B|DARCo{k?M`L9Fy6D)qA^?rmRY+|WzVrldf8kqhv3`Qn8 z07Abr;(vg{_b`4%w9Qgx2C9E8A-*PXur!3{&nvBRy6(!KXkO;6%M~d`b$sokCch%*y5U48Wiw6| zGP5uNdiVb-b-$m#KN9rgRHCE(5#hfP^yA1M(xqT&Z)>2B``*UHLC4Mj*U;Ybk7)YK z%rUSr1D5go)ZxEa#((ANUzO$0OZQ7L|B(<$D?32(CC25`2b4M!D@z@7Tv1CyD;o=) zZ~y%p;NQoM{5Q{cKDPqqEK zw(3uK1GH{av(f&?nfj57-z(~0)r7yO=zuR(J#%|o0Nj77q~A9_e|rD__>1*h@%sJ! zet-YpO6ku_^K%vdZKJ^SuZ_abr^lb4`+a}$`?AW}>)JWLH^BYw!TF6v{PrT|b_O=M zG{S&X8VDNbS?L1~N*Gug*%{*kd_jL5MP11b?j)};wcW&W+$cd$!|N}ouT30;$Ll38 z03q}?^%a5(E-u_Byr2x;x36%!UMg!F@agmPiNW)MW-3P_i0zc^m3{RZi!Lhh+HoOX zxEc0bO6K)n%f3H;I`%kTbQ$8hz8HAd)#8n&?Y+(GPo2A12U?Bwu&weUi}=MmLkB7G z<1L1HBWm9A>K7}1NA3(@4|SJQ*)ImwfQ-TGVNs*YcBisZfZBHa0z-jhN&%$Ufv~n~0UN>p^79S&*h_wKs9Hwm z8ZuMFgS0v{#teAKLuASQ^&q+25iA#euw?2G+IJ51eiH4eRHM2B4(YQ?72+{`5%Yr& zDyW4sM@zfhJ5O`&syV#^nhE0_;_m4Dk*Ij$+D!v6){!8+8B&jd5$!?U!>#8h_ydIQ zE?CGdx=x81&DhK>B+}6JI7YHjaqD)z9`xpxXjuxHCJuX%Dc_oBFbb#+m8fO%Q2;=^lF-`5kcwiC-7U2?3#SY?9G3Mk!!{YMJgLhXjYW>Wmhvu*xJx%%~Gb#@8 z8b(Y9fZlCWLZ*+HvNcEqL}Dgm>#|y8a_Gbc;?A7}Bu5ny|3NgU9BxWURMdPII5$*{q97F8xk9Zk|Bx3Rrx zawdLe?%dQMuSrxK#nQ*I;cgQqdc>w z%25P8y|v}^N*A_%v`J})4Gh~CEgW1Y&YEq3{q^OfDMN8uQc`^SI--)REl-UQoGqZ( z+SVsEzS&1_MB8Q>WV6d_XzN+4akHhRm3N4~Oz_WTD?_2U24y#vvle$G1`vH26zlAh zr8y;(fD=GGLXeV08&%&Tie(*k602nyvVk2ss{=;0$%X47--DI0R-=By4;8g%Hx z_ENhK%kZ6bOpIVm7@qG1RX**U!EMKjyzc1eSagL}!E}~X?N6sf{wQ*Xls)}4>2)={ zFVH81vk9H^l%?Lp&ha!R`6{cb%F1wuckRTzPE#^{;R=S($!jSpRGOVac;`1nXMcVu zC*JiAdEY0Xx({uMot2rLn9k{9W96XigEi5|Rt-oH&PvO}AOwyhj?M)B*{K2p6| zSaS^N9Kw{rDquJAQYH2ddc{G~t&+tTyS%G`ob;f)XNTrEEqGm5z|PJNUVM&S zFk(n(v)fSE;9u>|13R81Z}Ce6LeD@P;$$WWjbNl+aFDl~y>Lgp7xvc^mIdoJa7aKi znGpRtB61411hO+cQ;h%xBAj}JRB{frB?ks}kS5U!niMk&ORrDw@XkLq^d)}%Ya}Ez z1HX1J8ERMTndTRy@Wfjz^yONV(W=rCnY^GBFVJ5Y1ZnF?k`naDQKm=xok5_TTy^yq)OD zYJot|v3)5dL4a2JqTrIxwU z0~`~=081oq*AcpyHhN{rP*or+nF9@>HRk}E*2#?cBo`-b-@iCyx)Ap;Uy-5gnFYHA>YFn<+IpRKOtjqJw0!@x z;@Wwgcg*8ne5-lAzooQu%_2@A9=_?dDc8@}zf75;!d>mAb6dX|xrr0g9zzgAL#3q> zt{ScquGUoLrpKnkX2NE`W?`*jN?A?0AZvCzdB%gx@>tq#CmL%XRkV{=w98$may|KY zA^ix?C1I5suupZV=wimjZIlueSB^tZ1dnaP=)WwyHPii9SLch^xN#;1iaSCU= zen;aHiAzCheEibV#j!D9NzPOKIP-ccW#oPb?TI-1Im`gD6wiN!UqT1cl)V@7LrLQu zJhS}!_&d7ny!1Y!i3^3BSN56~*Dd8W(#{%>;WY9Ojo6s7K^7XlGcoRgL1p=UqWi>JE*O-P?HNIpLXqZ-_JYIMXb=dF%Gv* zaiWW3K3#M91Ws)lw>wpo3ZPQpK(r~N$3-x6r+~41Eo2tB?Ed(924WD^chL%QBK#G) zlux1c7G$_;JoxI1N+pB66-DMH+FJx>-u~W@nUjNT0{SI8?Yv+r2q)YGCo7*EW_v*) zC&W%z>O|%7>NS`*OzzGFd+$uERZ!RF++DpXpapKor;j*7-Y;6*R22cu47H3-z2Q>o zys8|9P*s3(1f{Sw^C`vB!A?8dm_sn|@4K%RL;4~rV(x;`fTif%GGFV0cr!M)1d#J+t&c^r(b0!MM&!(_Th zI}&($^6ot-2D3)<)}a)SniB1SltZXO=_C}4h;vO?w}^;MxsT_D?oPW;LihmH;jGSv zNWEs&IWswI;;kHrLzQ!to58H$w1@dn3DUYgC3G9>9!%?2rJ9rNz(vxdI#HDaR*rVc zn94S4e-R>HL~1aE!~2>sXLXB&7)DcL-L)JGlEbv+ck8`5aDEyG*ZX)};)Xg5N=g-= z<{c!bI+!M)`(a^xMfNkHT1nY!&PpHn2`RUkIoaQ>8<`>cHa2iT7S=!%nqzgXh|ef? zU6TV3d&pMme$>+h6RulYlR+Dws3w7(k2YRUEo6KBg+y!Jiwe_>j+K_kY&thep*{k0 ziJLWb{G>^v@wPb=!KYT?E3B}QP|G%|-#BfT>gHKyxxa=$i@roS@8$C3Svu(H zGtx=+%W0I7WW&Na9;w8Vou~raDz~|u{S$Ysl-a8DlaF~oy`n0>a#&B0uNuAQzN&W# z_?C4Jme1@I!^rL)^o#J0poL z;BdI+cwA$LL-;tgT*ZT!w8OSjv!<{pOUF`uniw=QL(gpEiXX`HUxcO9_v zREzzG*(PBSEy^|6ON}{7jY&$4NlT5t1_=3|`f8)T_CkXg$4cKA4zgP)I+{BXy&Sr> z1)sge-g_=cjlP0r$%Y;tPBc#OKR$iiUiRv)FxaX@uLZ^}$&qmP@%%I&n9W`IvRL#5Gqd^U(Eq{cw^Z`SGA3;qL90x9ql_ z`aW9)rCF$ZU7d;fR-R?m1g=Q`KLti5Ejy;_q+ zU)j9Y;nWW)d6zeuz@cRZo0cp*w-745W!(f43UOT|5ak6sl+0Qd!J|{`xeO&2sHa*p1iFg?DPgUwA`D9_y zwxRfnlhSgd5JA3KH)m#}y^8YA(RPfL zb9|RO%q8z&dS$V^F6!=>Kv86{myi8k#p`W(Fzlr&%R||AHp#sJDrna=g$ya+Ghrxn zPKS1Cj-%9%DNNK@yMbGGD+=6@uIC`_Q!kP0^9t7A6K;x-Us*S1o`Cqg2+~r>%2jX6 zhlt2V(z~TR5cz0vQ4s9KV)n!bF8Zo%sACo9G>2ZPu{DBxqEj1~Tl3v^?5i3gO<7Xz zYNTYlbj0J*OMIOT^N(if4WxneeHf_44Z^HzZw@lf?9_u^vr4UEO(UFV(umbU`wxJB@uyx;w!mAANmXTQ}rwP=o;?MVN5Q=3|G$nSF9a&Tcl{B%Qax z!;nfjKh-@yJHRyNMLm;%g)1P<N^m%S$jZtZfEPJwkdqF?=H205py0WX7TO^>iwS zL>ri+iW%CzXnwzCcWw!Kzv@sqMWjimZpunRlbFny6w3-T!82D|*;1PdwhgtfRW-+i z&3VCa+fZWUfn>04t4Q7)z67@28M5q?Q)ngjGR_8h>(;{wr~T%KOtaW|x|?Vlm-#7o zrGzxA3D}0PuZo<|OOhZy0t372Y6-2tH!`lQ)Oo^@RUH43X98KKh? zz{ds==rKH5&nwwe9%sQmJ==4y`@GT)o}vq7KVcs1skAzLBq`IW2(9Gn=l~0#V-34t zObD>X*h~>Ek{8(F%&bajOI*<$^xP|tb_~#dOUj&1ij1&gD*43-@rZbAPW?6>KSOJw z*$H>nUD2b{R*FMYep@f+0|jjc^M?gtYYP!jf(fB>CCdArs^`bicK^+7IQL_B{w?5g`3cTL+gk%SRyAUt>2{KqqsPgq$6*f2 zC=OU`d0O3BoS2U;+Uvux4W~yi^_7naZg=+s_W1AH$4-U(h9$5Sj^Z8~=%13aV~Z^7 zTsr$I9roLHE7`ms%a@lMbb5pB`!S<8e94BxDZXgxo_iXmnq8SnDA!n)_Qg_89rPnC zAfHo);P~I_BDrs?P@*#3GlhirW7J!MO)dH>?@<#ImdGxXUUXBq`*b#HiIYRE<18`mcL>bHy#{P&b+%8+S78h3cxr@$$3MmtqRZeY1Br` zw%KiZGmP*kFzz&1!=Ogk4}NQ3cSvc$V+(?^Q~EWzvF|1YAJ5bx6xMYUtj)8!(lWv_ z&T&G$S*G{yklq7~J+ub`qXxL2gMzVCZ~JS$D12l3)(Clh_RB%`yFiCD%{LA7@ZjM6 zO=7tf@a$~!_gHwG-yV*79(8bC$9_mCw}kkoEymE z)X2)Fw_5Fvq_h#iP{ndG+CXnSl_fd}-GZA>$ePxkCULk^(;^KOPw{TOB5$+*K5D(UN&VAEy<1XYz6G1CN_;n$`&g5c`nalA(AerX&iJP<9m-_Zu z=4`RvmkDI4)ui4cRq#CGn#yQoW4VbYw&xfXE-w})haWsH7KW4`oG=x*Yy>E(CHEDU zv>!~4Ci~adSSRr8+Q{rH6b=`N?Aq|`D zHqglrE}>UZ&c!c~hp!@rRFm^7jNg+qRF1#$I(L>dJW)hcp9JBtN*P|sR&?y+85*81 z@nKBv3m5QBaR7YMQuLMo3!gAIYACpmzL_EE?ZfZ zKU+t*!+u%qQrJ8`m;^@e)7yW7>~n2^WQ@E+pU(3<_-K=g$N`d^sX4-j4v{+s8HsCv z8e90x18a7%@|=Fhv+g=n^W_ABmD#M`ZXoN@Oi*Q+J7;>sbHgYxO)g|<(h_yyMjM&dpvCnmn1{;<910lP0urZIVgZQsW%Y|?z=t7 znz)}~j2GMS$?+zM=_n)_jc4)sET`}5{GQ!nW2b;mr_x?dyUIg5i044sN%^B zDaoa3*huktXsa(pPk#E<=PYoWyi_>z=+XN+OfS_i8Pv=%^LKdfg1!8%uv9nu1bx#Z z=Dx@XCo&m|Mh#DPJtm+LYo*+nqptLTo>0Z!(+qc9#>GdklG_5rcA`h<#x4>NioLv zouW(nXGF8pjM2J4ebOy5#TyxLy`5E8E<O-Ki7gHef4dw-~O32)io8 zN@h9D3G7r~6f#_LYm=Ht@WYzzGVpzr<~;Snk_kCbTBIrR9B{zQz@gSM4-aZ{mIbV) z*XD|f;DUMHekAQ!l{IVDWzvM5#d5E^Z)f#iUdbp7E8I6pyykcZmxYV}u@l>>(pI)9 zyNq0Wu-gGjup4H#M#~-wa^9lK4)fRz_d&Nwv>)uqfMw+XZizq>BQ%k0$O739wL_PX zm{uMw&bwAZgsezkxk2KYNjXBThO2s&k29F01ZOxc46G?s=@e$EyPGvc(oWP@P&8DX z^pswexL3aS6K5@d@TO^QG`dNQ;w?$7f(NnMhQ};XM85|cZonp}^E(fc<6iKyc)Px7 zHz2V5RdUTR#a?o`L7DSOeub4d@gZKZzHAvciFgvjCMISa>Oqc<_a6@G^=+oF4*0pniQ6EtM`*# zs+Y21_tNVaC@J$7jxFtsCRsI}RJ9Z>3<`%ek`L{eKo(}HNknJgR03u9Z(f0J&78As z*n-&{SW6D8N=kE+kn&7V&90mi5@lx$9P0E@INqJBV>jog8h)N$X+kPBWndpy?(KL?= z);NNQh)p8QA~Y%!ABz7Z$1fo65PS5=m!Ns`diD;|~XU)e}uX2BmqH8O@+fLz_oOji;N;S9^Dvd;SkxWz-k z!e@DpGi<70Y217f?LCfbwLO37wX->2|6Inb9H4)sBr!=Ndc1}3?y>S6w0*|tAe8G? zwXct_M546J{08Ju_Ka<@tHQO5i-X0YY9f!$t@8Al^=mTG-uTy>W{62ZQW_Sz{4vvs z+BDN7BWBgjqZ%KLQ&L~IGDK&u!M3zZTE4`VvnkiE)&_nb)C0B(Pg?D@&2r@ZAV`bu zguqW*rbNkl#;6~q9omBhvHnUDWZm0c>j|Kc!zRwM1OoagT}Z9)uP!nD z9uO!U`8h{nZr{*ia8_)-c(2~e*BbItHIeEpsbs3>oEPQ<&WVr!g>zw(^gVwD7U$Mx zoOV$UB*Zx`&Fd}TM6W0@O|T`eB)F;f&I-yT&I#)fJs9ZKz@YfgS=N0YByI|0#&x}u zs$YDl5Ndhk{n%3vK@`c*G9S4Nc|^$lp`lpi%38HQ0NnsT#gy_*12`LGlD8Yo6fxf1 z1J{PQHbKh@>=A`$kbXRyH**%&#aNcPNxC z1qyasBwlL5VXk!Jz7_B(F;9Q(%cE$o37tkJAEFSSUtp2O`o64;Uj_rnmhIJt!1PkY z8BlZZHIRa;j<#6D+Lu()tMCPtl=UD?g1FlJLB1@AMK6`$)l`{O#%tb}iJYXmk48)h zkHwSTF~0Jl0~rOuq62Y8(PpLYc%^t8audzkG2Z=gp*|L_NwY7R4NR~0b+_&CyA4h8 z4g+R+u~z+~4925mDE>6ExITCKWbZgp45QKUS>Hh08Z4V2kh8e6TL~-faaAw=EF1V% zb-F0UKFrVXH|!6XiX;t5tw}SkWbY0+G}5|$`Am? zvtLxuQcbV1SFE{scrEav*29pTK(H){HVAuNfL)JR5vj=Pmt}}0WQhCg_aW(qn$T+) z_DIyK8^T*LiXmEeshWH=+fc0y4_tS-O0{T8xI81M4LUxHxP`HbR=e3-BIo%$ ze^a$Y?FbjU(Cc_fU7J|E!_`5mwy8NwJbZ4?iZ3#W%A^=3w>}BNB=eafHc#5JQjF^@ z$XVoECbnWkj>x2*AVEa_qA4t0Z zNZRKq_E6)_R02DkMWyTUNBa!yujv=O_;IZ+f#FjE_E4n*pe{8{(h(!2f=np;tXRc} z7jGYd-Gi_*X^4i<(!2MpT^hc8B|$hR-0QddBsoPU$dk+dE_)v;Srn5IK#DM2Zn_}D zkD4bJZtq|w=Wiom4UV5*zDzDI9sv~;gS^Do$Oy52O*gKqkrlg>=@Q>0OGEOZPPKT1 z!d~y)#B#lbmBoIKS(HF`<*BM!D7@i{FZ?OZDQGxa7(=XnM*{HJlRgwZSklu>pv(2d zCp3<=2#(Oex{o9SC(5>;&@8W55C;VX5+B1dZm=^QE344Nzc4`LT>FLRXql}~%VS+W z1w}Y^ZgZTyoTZ@G8}ulb#8_qNc0}S_qwSKS$21IP8-o(3%}x;YWWGliwcgTQe+4~v zakQV(;c;sCW%jx1=2+Rv!$V82dy1IgE*;Oxld+Hsee_wU!%n#4V9sM%fFrT$elHu6VtzBq;jy>GVV$l!+rr8n`C7lepRTaLZkOqF zp9hw_-->I(FLt>h8&dSq&~6n4C5(gA3WvE0YqCr64(qmF52qU=e~@MHmEJ+1&+rkO z^Im+PUv)Q@wOfhhoh_oS$PlGy2#XSWcIYbx3&E#P!4tWe^;#+@)jf2(S4vwLz`FH? z@s+32B6~n|T@_~QBPHtr$ZTh(U!2I6oJQYrX=kA$1`osq?pvxmx-U!+r6ka>31ewI zWV5Q-$eF37zsbZinhVoA9K8?YDx}Mf;Ih>gc_0?Cv#ooBbpAPT=dst>mbyRA^PrJ+ z-7fX^7(UB`t1~e8em_S(k;)<&GC|+5JM50CoM_9Wn?s7rUe~C>T4a0Vgfk%id@}gt z5{98#Pw0j-K<06BDWShTmZ`XiBKY!)=gu$zTla9lu1WdB0y>>P=2RD4Ip@|%Et61q z&OWoF`J%bRVuNc)`$82F{!vqCQBM;F!F~0m+3_+m+AKEP*YnI&ESxU8=WV#z$J88U zG0PPL?>OiNoGl_j;11w|$ATwLW2rOC-V42;IAA6cmSzwcO{13XGu`LUtu!jPTUOAn z1A9t`SNCvl8XS3|a5CLAajx8Flx7|VYa%iSP6r*$re~L2jrZ?PIHHH^?rEN!D5r2QTbkBB zHqSlR)wR+$iSGYUM#sd+O#92VQYV`kul(fH z{eaFD8!pTc8aUNu59X_$g*D5kQn{8l)wX#xj+K@hmme>a;~TH%02fJDs(@eD+zbR= zp=f+Bd+^&3MND1l($BZv_`)@t^UrBwG1>^mxZXQUM`dqeKLPRB11_v*2^qqE80!;@MLjo;lW6NTx(dG~^xh z*ZTM_iRb4cKsj=d10Ta@%>3VVv}IPeaPAIDj{R$e_xrZltgCNOIR_r5B%0Sl?A6OI{ zY4$536b$=tx)_nV^|&FGKpb$i$N7d#VH%uyw~R0I{E6NcsiPDEed^I`EsEKbsq_Mt zU+9cr+REXS1P!&hpmMix)%{i9tUK9-Wbgz0JiwkYH$v&`#toRwq{XmBT*XRL0*Ja# zLW;(5%svG*c9-tB@O+R?Z9Nr<<~mKESJF3T54aGf=}LvQhrPz>(YOz*_Cz8 z2p_Y%aV=JSnpQjN}Z>dZ{dk#*^5u282`G!iF$`2hSEjMYGKNwMHIcDAV; zL`>kb;H+(qvM;1m{V5uIsGKC#ITlRJW<@Lx*SvY2rg>mXYj` zqSRJcFmh_?`u@hOtZ*Stf+FLL_ztZ)w)KQsIpgh*97uteSbNPF7q zsv==zgMh=wBnkEQZ^gT(?3kiss5K<}E_ovf664&V}xU z>4jl+-K&u$M!&06=Zk_C$U{GHUvNJV9q*H@9TFG>h7R{9u7~cs=9TBPXXxj|rzNki zUd%vKFUVSu;jrQ0ONtc&6hRB~fc0L6y!13p9&wS_FD+E6T(UH=K(kaax^F_W+dFoPcJj4J_$j5ntQ7#`pH~Yt(O{9{4nEc z40y~(7Cbk7Li7`nkj>lVOt{>TjcEQ%+T463YN59uWm(9?f@5T7B_Tb+wjcPXOWvJa zzbhFbYTVS=@+Oqxn7>zr@|`yd$9dj?Q;-*~^j`<}3v+|acW)L zjKDu${<4}kDX8{R` zgtKfCz#aBs%6gJ$2_997iV_sLzE+?lf(Inzuq2`mv?}5Wk)jUL$!Df)BvYZj#$A(j zXY;xhiz7s%JBu#}ifCUOy@MR?8c9Nrh@QeZ_?@10uw(7xl1-17G#Y`wc{!zz zUmxX#O3#gGX-;AV=p?53>B(0n$r9MqbF9}9LV0VrK>jkzVyyyHdE)mSomeL=Fm@># ziMqun2lbO*gNveOACZ{wZOI`qaUHO}u&$9YYV~JQw~FlCVc3IPVZ&QtHadub=D#{5 z7%F9^50OX2%8!>5d!kv^% zD3UjuqT~js{t(EDDX%0Ie8IhVVDV7p*(SMIf+;}MRzDVkhv$$88BaelAQP6uF)_K2 z?c=)aoaHMR?aQAod|Ut$Yu0hjJ>$1ez1!ZzSA|KXhH0`sSEZ?NgEK&JW82aP;?6Fp zUdb9!yMeLT6`q~dRtDjTQ&`AXr@2}(zOgazw%uvsaB5imci!9KHX^t6X|uBHH9 zjU&@}H;y(6!H^xXOGT1L5JCM2QRx|8`IyQBl6uvv#OKQkijW)|PbekZO+}hSMy;l^ z1Ux=a61yjtWY1S8K4%N=;50VEaIIZzSh?(BrTt-y!c{wT!Tlf}qi--`c&fk3NBV`v zp(l{e3d(@io7w1(=ByaSC4tqmsBw4%`(O1&R*PO9y0Dal+wj;6${fMDS8aQ{Lc8$h zkk7R>%foIo(8^y2DQ<7!W_+1eOx0-0WfU3_?88^)L{uJqStVGIZI%jhsRgNlo8gS5 zQNHXY8!NwwwdQBk&@QvA`pUoeib4ysmbktdby8}VL03O5iS|G*Lf4D~gnE85Re^wq z;*EvX1z7^U;2}}jh%2ms2-@7E(`$CJy|7&p#Ojc$8@>6w@Z4;{<3Ke^;i^gl^&9D} z;+ZaIiUT8_Svjg{%sx+L(d5V|yljKRJOw+0G5cjvE7yBh?Pq(tB;>+3bFK!NUH!f3 zLzCoM$F*)EMb9~&u$@=P=cNQ!Oap7ZzKS*EkHZ2a%2_SMT`2~Kqt*p-)y7kzIxvoe ztefbU6JJ;&LMUS5W6M$j4pk!-Z+s>S8l|QK2Wug49=Nr`P z7K#&9XOv~eVUmkl6~=OA&oN#S)|wsYBSWY8cm@7&Toha4)T;& z4unP!AH!u^h|31(lr%`}e{^GPwAspipZPq&DXhB+S`BktPu#41>d z%M!vHu8Z7qSElZ_38W)>*A6E@@ zh?QA*JVT0k&CCo3v0;|yxGfVKh|H3&pb%tg;@xbL1uDCRyl1kGgcn@4{(&a4%^KuX zU7CgIs$ipN;#}$faP|&Nny|t5-n(Ple#W+K?%1|%&+OQ?cWm3XZQFXr$|k8) zs9U9ztmqPSk8-1BHF?p!RtUSxbsprhT~i>TSvZLNStdMJSbYwlW|5wFkb8tD#lnq z-^sWQfte=+Zs`(a&?Ak@p&&Md-!O58vf)g?8bb1VUqHA!wK$r+;~>pDw~-(_&(+`m zoEe{UyU*0}`Rv}m=ehWrP9kcq;wYbyP(ye)gD=74!3_){V7_rirXZ45 z?C-ZgFWeN>W=Cyd>QL(jthDR9PwrMOE3XDedTm+9w6)TgpBhFGFk$?{xI|W}4tqE_ zDYCXv9nYy<-7wm5{r6zv3VOytk|0VO1v8||*@&n%O!BdLaN0z%$VJ|_y~Y%1F=8%$ zVTAt@XX?}YKJIsGY4(_14XIOrt2SL?j~O<0;G()T1ZIGGC!mFXucA4FhL}V%ZaI1x zHnE-M`}_-}kZ`nW@=V(!tjJwf$Q5k-`(Rjvai4eq&z`@fSje)4+0vYbBpUIa}U@grkZY_Rz$yq9nCTM(@oho4RK(%rFUBVM(j z0vW*v-v11t9EC0SlZh1$o1#&Nh;A4$wZhs%P=8wJLkZ1G#5i+Ng=lI-4|M1olZTJ? zDKfOP2a-Pjje3{MPL4)1*=T*5=;mt$Nb(mFOzHC+<+<)0hgikcJX*JvMI_q}(as9o zD;#s0#N18>YNQVg&@(}!95r5GYP<`f8_?V8~c071%hS%iXgzBQK@9yCH2`Wrs z1opNoX!t1bwi=#w-_TtL8`M)HPeZ_ICUdp_Ms8F5zAgr$dd+})x-`aMXthaq^x=rTfym=EM30H;gQSFf&n9!lQrzJ=}aj`So@rk>Z++WF}s`Wj465Q z@W6k^;y7mY1+>lb)r}1L$C~Z=sk@h*)cAB*y)%Yvi>Zs?69BoIJ?3$05PYgE+6XW= zfo%r*B>s-3+i^NEVYTzRbqMnW>3?L_#d=M(&CcGu|0_`!)+$yBqNzSNiKlCu%>u-9 zn?VR`GU+ghAVjmWNUsyKuT~X*QtJw!YndD}{gLD}DU0S8iNUaAj^l|llo->QaApOkl*`-2MV>D^zA{*{)t3vPW?wYge_PC6bBWNQkv zgAsk|^HxZlO7yBzqm{mg2y(fZl6^aAXCH7OFJmH7GG z``amRF)fHHcKqX(WozX-`exNXvxtnwcf)#vTSt2H8u%lk)gXI@oTohbz3ZHqQlO98 z-AG-GO6m6kyZCe!VxpYAZe4@ZkmLd#t5Xf{YST!i-H?T5F6)$fbdphqJrFN^j*X4leE%$W|(b@!@&_6u>+cI{C$3y9o7k`r+cGTl7 z9ng7Zp%$io=IeXkz1QV+6{DMX`JpM!+>@c%5Uq2tVj0q<7Q1zy?D|}MA)!^4Y86|+ zIMO=f1IuC%`A(Pp20c6Y6vHwf6(djN2x3~mASQr_$Wl<8-nmFGp7v%;fusKs|APBo zh!Iq}&!-=~E<^X`A*c4rxGleZI$mks{*Z>Lng&FBp=7gRxI+V?NrslXrN&X#O7*q-AhrJf$g39sj~$u_>4Z^P!> z%`|ZJKcy)&jB}`KT0C27JT~^<@&RB-8KTHFjHNaR$T7R-Qp(DYy=aXOGA?+QZ?gll zucm1ta1z3B6M_qI(SSuMrZ<*yA_*yc%RS+?XB{XdFk)GC6x+{=tt8R}A=0R5iggoW zrlee1Z7C&XeC*vN!G`+ZLjy@GvhAc$GLnl@S8R*fLrkqq?0BQ0hiiUI1r!SuhV?{# z==H30L-ndfps7elIN{fW8VmK&Lx~}6Olz@&?6{i|8lMTy0#4TwH4sM?BJ>VrR} zf5MzqS=lmo$TLbBi#F}s{MH~B;2kr{2G4fy6iJi(gQG=19g;$wRpNhx);_AoD;%-x zuOZ=&+7G3Cr!b^_&M4jJO|F3sS>lK(X=|14IPH@nnQ}Syd>>Iuv7CX~AfJpTesk|& zt-i&F;mW-i@P^0$zTdG1FcxQrtO|w*4HF(e{l5KQ{?5XDle~MA9tz|f{yZ|7CawKI z7-^or{!fbS|Gw}3|5LI32R&!{UliMFPD>3Hi5Azio*31&1y*?JxNW){n7}fkHt=7L zB1n!TWleK16XY@^b^z=c=5VQK$B`kdE!nMJi={H`QFyVW^r7%fQAdzi3-Smvt~B*8 z->yYW^26WEkKKf~J2l>NIo%aA)y|bkO3F!4Way&A&udJ^SNbMPHx#0JGT|@s(Bo3d zH(l#%X-J3C!ebdlRQdahK9SeKQ2cANV^hv((xtAyf+f@HdPz3V#}?Y7^d)=!U3FfbF%lM={0Op<*ha-9`s)|S^8NJX>NG!%3e zyt0FhdE3WYQTs`x#~K;f_&7=z@A7;|&wnY6CETQG@!j2&ynSeEYe7ooA7HMfgiCJF zFCkxQ8H3rEIM@=#EuQbK|#Oev4_*?q=(y-d@9R$ZHWHf zI`g2Lz=>#fqxdL3JgQ{hEh|R7yb>CF6fL5#ETbC3k6)K>Jm?2sfc3U*lY|p?;-OEl zFm&UgPvRfQ+i=9krq8wvUa{9%J?nYt2T? zMJ&{~t=B_2H|s%5n-!q*2**`H(#&6(S@PqDGl**a$_Sf{piGJLfEHH`|BQE&Y0ta` zlNBIj6KP)KW#1&GBroR7HM%l4bhdarh&XR0i69cW%P1Sp49fJ}fI1;btvp8%?Pg?# z;~PnsCnc!Y*Ukv`D96}ebo;J#k|Irso?j`NR%WgV!mqD$lg8?S9&A#jUr;NL;r_3D zUkfDi8vFco90q>k$dr!cI^5HM0VU>s^uUWep*%eV0jMK6;h<-&rTrsjL_712CQFQJ z%wUyd(fy)tH(I+>uCIT6D|0#j9R72S5>AUEgfwNG(@t+LC0Amc*tmq9cs4abHT}r= zUM^ms1@`1#u%W61dQ=l^<6C_wePhA3s`R(=!UY>zx{$$!2}KHty~mffnxoKZPq^hMt&>3pSYH+5-fTn*Wtu>~Q|fu7G1TyNlH$00LFXcNt&q-*$Zn)%>j z&;MX)I^3hQV-EwVP&Q7(Pg8OZhxAzfltV`>dC zHWWN#at%>e&5T}j9D>1mB_<$Ae(WD0} z4saTFF$zhdw!lD!kPIm9^X;eKwcjOCMkZ1ovKNPo&#SXW_!VdZF+qnI9shEQZPDJK zAj$|WKv79ar;^K9E+C&bs4&1bP)ba)9K%1zy+zJQm@lory+C|guC5%*meV(f!R}Z| z<`>81-x@EXEQ)h(qFC^^Q1I}X+Ube+*v|J?1>HjCZvD(CS~q%!aP_j-ka+2}=BBykNuSpxn;OV@;N^ z1ctFlDYCIoFBIZnZv6)mHW7Sj5Uh>hwN1DW-!^Rjr{0vE<3Z#T1Mfh5xGo;%$siep zSJ6bt-xV8ar-J{!ZZC!!>NtS@iBwdsI1g00@=wNsz>CC{Nwd)gq~%Rg2L((~Ifd); zO;X<+&?2O?WA>aHonM)+^w2SKUy=F?4T}{t>7d*YuGt!N2S>*DC7_;R#1$)Ah-|6J zn3wI}Dj#D44#ra35``d`#{S>h3i+u$CxKrii4%X?>?uRRRbH{!aPgbeH-YGiyS5kV zCDtV0Oj(AkkpmzKzi%Ox7uTSd(B_jeFFF7`ezfQaq>4{;uOpwd$Ne!nh{$utGp9%z z#xkYjOYyRZw54;HdQ1YGpLeIVv*Zq@1|xrReNTM0EmVV4Mo}g>)TvJ!ja%bd9q`i% zJWvq3r+I{rmMeMadu#{WBcdP+IEDlY+b@LRKc&IH+NCTAqKyw@A@1w~2`?nr-Y^u_ zVubvl!?LFOop0H;c;-I8T5rWe5S>Dw8#285Xf7z7x!HWN)ysS1^SWTao(QJ8+hbnd z(m(pjaO!vXHD;e*5RL_Xjf@5`e3t zOy}>jcK2yP+m|Sd5P%zUSA&xMospU>W5ztCNLeA9=l*emvCb{UGNuZFQ{bJxbuUqF zmV;@Y=pMC?&IiNy$siZJoC3yf3*?!fXy<%)PU8MX!J zbI|iD7iFvD%wj?^Ri{bOR8xj^?dODRCq%B_vB_bRg~v=z4cX*8CZ*XVr{l*?Azk7% zsjHK?$J0(RT_QUqy)?ZHKbrg$`iTO`0!j9h?nk{7FUPkgsuC`dvE}@amW15N;!4`` z*upgqu(uPPa)L+;aT{xE^IzvdGOMk4Ja)3Xb@u1blc_%+*_ws?&)EI7N1UX8wpw22>kC} z@9%%@gPJ3rS>jTP07a(Sgpdf}VB${Z`_q~Ceda`J1e;>YdGfd5^0mE0>ii1o9|c)rP8 zPS}1uRl46)ZJGXRxx5JyVNWk6SauA>&J}7OPWmezLRVlAP&4-g6NuCTu*zum7emD4 zfPC)YNh;4VXyS4kD#*w<)c@(5cm;{=@qow@n(g-SIYpm@X1Ccd+8grxxY6E6t*LuG zmPPuMYKI-+s2`(CsLh4t^*dkoEsbNyde1~p2YEmKigRrYb`W7-1@}#HZ{2b;zt2gz zOzcWr<$Dwk4Oz~ssQ$6AcXMe*hb;j43t8KyMNdI$-sp+z`I->vs>i~9e8rFdy8e_2 z`$B&j++ze@2;$p*&we{O-Sw!k!*^l;hlQb`iL(87M7G2{naTytRH6<_-VdsIuDl|; z9Cuk(gKfq@%fvwdYuxb}<3Hl~ekIBh5EjHKm}>&=>lH+z+>Yi zDssL#rwD-KuQh5=pTV^#}X2gWvcoN+RblmBM1ikHYuD=nT8G>gwvvU{?C>ZfwoQr$A z8TRzCA02UT>DFt1ccqCc1gWHcG=23Q{PS9X9s<2c*$5o8WK;!K9q(Z9GY8^&U>%N4 zmMZ+h*tIr*HP8U+SlE)MTx4t#a#)5EN=>1yPzEt)Q-_|b3NBHYI#X(2QJMBk5f)q5 zH>0JmHyq1Q%^{Rgtu!eA z2=$MKW-v4y^B zJzt$ArE^JR0@q?3}nU4YgPYP5P_ZmGXryVw4?18|7Z?%^utzZuF-$&gTG! zR{bXq^F886p7%ax1q0qM@^sDr)K_{W|7J-4on&0JJUd##E3oXll6PcFHv4y1Jmw1x z4?W5q;TL3U47#B^6DqE-A=deymX5;S{UavqrzpmQ1zzSY5eYxU1gP{O9Ltue|nSvmO>R1@26v1qNK&Tld<0ELHMInBpnvf1M zhL1r7h5uqD0z*#_3JwoMctFNvEjR>Ikc|9UxkM24%lQ#F{h586d6QE=Ua7p^?r^=W z?r7E9k%1x$USmX-(((JQ3vk}GdJl*%c-FvOE_K)QTj))~O7%AOl*NO9H%*R$cf)2<23Y+d6-s6r!}^J4?~diAO@A6hqKqQmtmW$MqYkAB@MM{2S% zzX7jDHe(JjaZ1>QIO0|fF3A6?LJbL5a6(vuHNQKAm!3C@4rIcW!$dLl&}5T{1;X1i zj&Uo92_g9&ZsYq%D(V65<2lunZOq*|6sbzmMp3=)pT%~lbIFypy^X#FAc_ni2hO}N zV32F}y2YT1p;nREiK>9Bs;`%mNT~qYw^?H(%mMbDAN38j9cBJ7#;rK-Z$8^D`X`Q& zH6V>^wYuD;Hk1T1#@oI{)+K>|uXwOku#rDso_+PLbm?L9j)4A-+8V@86?-s)hz`jp4#Z@d- z6p8X2%Y2=#4F<;Dn*a~{<)-X4IratZkXCxjj@iV0F0d_gvo$Oljigwyv$$+~Psu%s z{a9R6(!tyL#yQn3_7-?nDophpSfK7 z4@o{<)^OU9MC3QHCBX%zW$RZLEryhIM%AXSs;7jeuCnDIH4+Q9C6>rv#&Zo=nb=!K z4lMY7{7?dPp}4D)#kg>Gco?<%xMaEvVV7hF%_XAe8x@yX$QP>wG%s&Me|}L?{h7g5@ztLg3Q> z3*v(&zoeiP$Q|VCvF?tlC!*tx-K7QP4YPkszGfSw3#Vt8i}8vZlmn;N(vJYaV9O!J zP(0{{+SN8q-MvQ8qPbtItz6VgA6iXyhY6vL^_d~`bmCCnfyCZxkiZ@`2#fKWM8MAE zK>+EQ+do27wlODFVN{oo>fz{PPo~1}u25lehj+2!47uNq;`r4_Z~29#af`gl^hy%c ztfA+PlvlOeHV?z|Hy@Cdr z!sWJ{NXsLJ6vIj929wFtrKU1^STWJY2JEtEm;{Ev^^2E9E-FZi%b)#eX5>t&k< zdxj0Sv!`Do6B^%9264fe&Eil`*92=0Ul(hN)PoxxP8&nQ0OX-WjCewJdL;C=K=E4KYH5*iHz(;mF4gg4_^MhgcumyAnQ2!~nRSBj#Y6 z6t5N2LS%gH`?&|Z`1_Cb$^5h7uF_|S;IkHq`|y92r^~nsQs|Z~of8$gz@;i(#Ve8A z8S-dVDUBMOjg42M@ob$Yax=CedheVDn&ej|PyOW!B87-Ba|k(+uHm&XhoA@oYt)oB zKq5>d9%cw_Lkqt~Wa4y!3$lPv9NVOXNT5s^a|ky;n(6B&f@2Ck7O{|wM9YK)xJ98Q zg1Etg8TT6StljzHg3`=vWx`_M^&5dl#krd$DKcmEUmfO9Nit+a8$8_8LwRBrg%KTX z>&=&elB`zG6a)kim=~D;g#}**fdR!*#i^F83m=xMp;dBsX(#AF-1`+#@(HIeLQ|noM{P20oF4bFrb8hZ{id8pA0_X}Pg2cTNBnhZGvi$47P#{txUW9u1yOb= z^*PuL8H9LaNkoyy${3-`ao3?Hku!QU!(QWXTatCjv;;3^byAB7>~_*+SbU^Qz3c0@ z2$Lig2HU;QKI?8EXbTbw-RhXza75#t&!+h9U&{d^Cx}~p(a?Si4>bBYrFkm;U+R(} zf(E=9a&l5n4LK^5a!LTqdGG@dI{Jf0)Lf*|Mf@X}gKQ`PLoNcU&7x_nFRgumWjt%R zzv&;>tfr=cvJw^T!11SJ-g4_rc`&$@V^WYs9GJ@IT-AQ}jJ1}Bhwa(x6SZtdoVQ_srL zQBE7YW@|Vj3V8I>Hc!{@u+g+^cK`CKwXrrp^mzlnd_Pw80zO7H)ga%;ig!s>d!Wav z=R>4$ie~+~XXhx{9nM0wf~|**WSLC$>=l%-=Bz~Sw6QkXrq?st#_27w*SGs?@9YJ8 zE=GxwicGZPTcm|Vg-mCDiL|IWghq%W4-2k432(TrcI6#{v=5sZ>Pz=Ah7lnC*b`$( znu2KMxS@F}3 z<(<0ILyHjaM+AW)o~?2l@u&B~W(TWqRS{cxnVytfDV8Du`Xv2z&5cub$hbW+9Vhe7 z>$zg{QIT4zxLlaJD6(9sBD3{DJbu_`lr-)vRW3eI6I{!!Lvccex$vU2%Fmr9RYxHY0#9SA1hwd~;Ym?a^yH#>4 z?{w(|cEW{?0lXwR!NP__765PYPLg~@JVgQ~V?T68pCbL7j@hho1f|i+qvx-Ey&+}W zSlppIc_|45I7VqX&=LL6fy+jdlC7F_!ilNe%{X4325M=5pvF!hgRZVxi3HiR&DL{nV9h+5fZHV7sblv+3^rA$wiN#gDkz!rxnbkY7=CAxbnG3k|4L87u zUs_Hch0pCSGEiMBAE{Q(b%N=S6VqR)%S^WXQjUD2ts0NYbVtL6pw`DnIoK}8jhgi{?tjP(aN-ATt*4$c^6A|fz+RY zSHwZf)CqQ4$gsq^yw)wJUK7@w`?~++lb}ZdbJ%FJ^amCs$l4r^rf3(qXlNe4Ma=`N zOw0hiqDN`OlP*1X(vP1(O9`6ky){P(?x(*!%?H4(uvFKI{YGQ)M=eSTV7r4bYsasj z{IuRvI7SI`S082MZl#xoXC&>t7a-5!pF__kT{Z)|oNP3=S}1E9m1xTchQb_tge#X?A;{{=chW1-cG8ivH;Jdui{n>N&m-#%Ynf>pzd%6iH4v9cuOovpkIdfe`Y zAvp?eZVasH%-o)`#GgfUw#I=?+u9W`Z8~EyEBGTq8vs{1GWM;?xF;@ie zN-DLwFq{;ew89Z34&LPfuB@|2p?#jvLr>jb#%jvx_#x4rJI(-~M%R&jV$%Ebd{!ZZ z`VZ)kC@yOV0>8~})|GBdOt%P3xMdv)yb+-N`wdU(SXi=a>SF1gvJ`}>u`>`((99AZkR!e~x z@3BTp^_Wh--B9Cmhs;|pZ>Q13-siJ3YuCEXr|X?F=k-Wgp0B;mglhGRjI+?kR{VMl zG&k5F!$U;B1uO-7Rig{Kfun*se*&ErG)8uA7z=fd|wU3k^S#^ z?lkow!c>f_cy^2o4?q#C#buit?f5}PXJJ&Sz3Aslp89)?-*^|J3X@uUc&!0NO!m;y zV;`=<{vC6hISD>DcPK<$0|h*dlp3l*CQ&p87Dx@^dM-4( z+XOOq=%v=>!tu|gEv0UFc1n?xUdE-(V}HP>Y}OWWHoi1cW3yH85wLZlwi+VjuhOs-dfhYD+Cts$y`x(2`}O@5M99j&%aRFFN=TU4-FYwU zJN$2#n%WdMc@z=UdMgC2N6>f0^A8Ts3wLj8d<;KccE26h7oMsJ`R<10CsV7v6Lif5 z8h!RXCe5SNejJMxhPf^Zz3}D?> zTgLYn)cMrJoZFHMChlMq*Ebk{a1O*PkE2O?&)*y3lwswd{--$=zwk|64_HT(b z^V8776Bb;~xZ7j+pNp)8hogD0;A_}|?8nqjCs2hSB2ej0(vQa!{pNu*F`z%>=P8bbTMuMN5l{!|)Qn zkbo+GxrP3=dx`y50J3f^*esHh1Z3X zGv>V}Rjq|BM1WGp?-0#|i?C{-k1`WU-4HWpronppgP`ERn@N;SV`r>(>HuU0+X7BO zu0K(`UH>Pih3?m}E+lRBjSy(>cd*OUj#x-CoJ$Gr4SNQ2Z~IW^^fpp)JXy(3FW_8QeEc3`=CV*b2ZGbzV^Z6Q^GpU`3T^|S z5t_9F*Oimeh|oX$*gumxLd?Ap67M&07##9`rcu2$EcbOji23nSlGJ!^y17+y0??na_pP6 zx!)ZGd_R_3iKV7jEqufOdO}3 z^&LA8=PVqoiuXk*-ontwaHs6((ygwZKo-R}YLjBX^&X9Il8pPHmDNc;??E-O(iKs5 zPTFnJZnRyeG;F2Vz`u-j9_>V}kYcOGsCZfqrORJ7T#miCyMS86y0B?}&tc)w&dJzP zuqqKCVY#ny$Bkshu~a7YcSqMJq(VP zIQ^aLd?NVpC$)GJX0*HccrW419K&Q=KPeeFCvtxI`g?aEBR2V(bCL4kS(G!Ho08*l zLZo7^S4RMwJ6oG$1VE`tc%^U(};S&Ju)ieo^j zmq^aKI<`tFPvu86Bu)t7SIf$0IEBT0Wq2Eyjv(jSML?C_^su~hkd-a17(i9;@w9&s zH`7zp(o$2?>Hv|0?e??N;d24={S&G{bIluw&CmUFzWxq-s(p?f;R7w?^}riJibk1R zs5Y7ZQKmy6x(maASOZ@X2?3ZWfK8DSN}fI_t&Y8=;a6jGP;Fw>6_Y*kbMML%090p- z{G#S3LzQ6H=Lb%V4Gu5H@(Ev*H+wYJQ?g3BwNU+ARQh6C~%I39Cj5`Z40MDW38nda>o^h+RzEMl7p+mI` zp;N!F8j3hDg1x`R&A8XOA1+!UZ>mEndgSN5zbD_0!pCQCM+#a2R^fVc%1p zrJ12cVv@)0ezR0AKhrpysp+h8)FX%AdZmULhcDZy6jIT2c^B6F74b-~bf_y4Ct?or zP43;^yz%>oYdlb zGsyt`q4f^^(PgdY-)`D&W53Srw?H=2%*Ux`k0&2yzA2aM;7Z7}a-K&aVPcpE1q!E< z3K9S9H5@!3+}o3ND`gE=7~XPmS$li8^hVd)m#AL6r!j8 z+J)no&9_0|Jhi9_znFhWL}l1Odp;njFo*{9DPq(V#w7~PcTcV~!ibGOeQKbNAi6B0 zeIfT0&*mbi{vuEu#P^qU?n3`W?zN_Koc!y6`W8=HW>vNqk7rfl(3@O*0xLG)v+oGq z%B2cF>UtGFa11q^-x5Yz-u>_&@1N5_o8ra|M3`j72TId_CQ#}4Vlwz$QInwFUs13_O6EPJr7qRH1 z*!gIYvgYc7o#i#8YQ?oo#_HXN^-Y$?Fy1=8PJN;0D25UF32a8}n&)YrY5Epk0PUCE zO#y>eDwK?W`e5zB>;1OV!)+Dr(QxiP-V?lV&%WAo>_`J}qQ$JGT5M~%Pp@w;oA$9Lg7 zEars(cW;F6*f%WO1)OYtJ!`1jL1l9)JZ9K_+ZM5@N5PFok(M$#AB;r7JkHbnl@hLY z%*Vz*L~{p=OmE6}$djMZkDpy~&-;6K0rmT!Q{J&&PsedvRV@~GVE1&7kch7jSoaCX zPIf`c6@W?2NB9vxzJRAkq`IB@!QwT+V%qsEh+j0WQ>}qc%(j~N>p1nFaPn(XMn=7c zmQI&mv`9sk-|zVHWzKi4SO2V!O0aUR!Rm~11Dnp2@|xSoVt95Hx_D6$H5Cw7Wx^;e z&h%e>;HpX`Pr+V)WEuP9I`{Qn7-_a|9!p8$q0#Fw`R<(!gC&JTCs>+zb?;D4GD{+7u9mf2>x&r5Y6$Y_SV4bSSc+Rxt4v z*7MG*e;)?)57ao$j$)K>rP?CEd^-heKo)rsl8Q173F{X~F8I5x=Ag@xF|y9n*n8{CwR4`MFmytMhR& zN70A6FJq=;-p;n;0!rM_X|&|#4vcQ-Gi1ta3m)0Xc#21bnniPAMrG8W#R`4`dTHiPyUwN zFIia#T};XW8bqM9Fkt-e%zy}M+zFvkoNpMrE7nz)>h;HtB5zC+R{3(0xnN`Y>iL^8 zco4z(0zj5|Lq$xOSXFf&h+S`u#dLBpUspktL;|sFF?Xr5s~!vyQq*(HQc0P-!g9($ z^~C3{@HKbRF48VUfny{^8-qbiBn_8V;F9nTB~rzdu$QkVnVfiRGFa#law;OS>UxVW}m0)S?Rbj>GaNAW%4{|%uxGYJQbG!aBDkGVf2+d))6B@xcB4?3J z*#JI`n!z#xrwqxJ6>7*h!_!@kClo8sCF_=r5Dq9Dv#e+skHH^7|K7S|WR94cZ~Cb| zxcl7}aM9@6Y_N#TKeUM{R9Db#VG$%-NVB@vV`#wI6b1r6eHds012-zZ3JO_X1mN z>j*3{27G9Jj3EOh?z-p}K!{Jz-}sZhwNJ0#{=oD2!P5GeUh%sztv9%g;jS? zp!~3vv@l>NGZA4XwQ^A@?CigroFLnvy0X$iOk&4^er#1N z^&~2c4Svd)Du%sjU2p2=mXadK^mGZTJjnYKY%E3DKA#n@h~pzS+=UJ|ja*?tc*OI^Gs*}#$Gc)d zzLy*HbM*MJ!E+B>abw8M$H9m-Bzn#a`DZt0P4&6)f9rHvw}i6bmyZ$U_&fSvZdbp& zf3HHde+4_tBP z&SZr={2XsT%KU#E<^6v?lgGrw$@;(E$@`aS@zGiK zylr<+J7ORbNI5y6wBRIre0L>ZF? zB?GuB9g@c?Nd1-SOAj6)zf-b$c`9b;0ybL;>t%u0v3=z^-$t9+WFTQ)KE3GO%)jJ3 z`JMVqzRhsCo7F%`K-Gg#Nm)F(mII&iv_E(OTbPR6Ew(R1ddD*D49ExEVW0E1kch$I z_yMnKfZ8o4F2_G*DI~!_Hln;OrbhFRDA1NXKyM1tKaX>yChP8TDURKWLXFAO_Pv}Q#&N@>#pib}WWz1fJ zpS$^^uUflz$QQOLUUkhrbE{RNUFgYIxFc5>ce*CS7FC`@;AfYy2XOS`@iJ8H{no2a z887}r+T?AvTTL+=Lr7wRzaf$AP3|Ud7qiur7Jqa5CuhH#YK{)86S; zuK*XcoBoI`cmn2*A&>8S3`6;Yfh+4EPeE9&YE7Et0TJ=~)9GeMM;du=)+k(y{WtM; z;j4H}<|{f$nZGb{pKopa!KJ47hbFTq8ZE=NWhwNxH46L<)s2W~$kGcE6ei`6{zQoGz0Nav47Yk2;WgE=F0guxUh~G@o&&;0Qjf4^o4!`{5 zd>Z&mj+t>6xjVsA@BW4)mNBcN0I@2TK3V05;*ECN<;TnFf_|5vPWaZJQ?Z=PvBv~G zkQ^=1d=;c-Eu{Y_6RpV_7w1OW#0tfgbXA0wKmvv7?z$pZ0kX+s<*YW``qwhDKqF{E zoCw5M*Z|#3aDG-eYfIy3ok}sKwqV3!B1$x?kZ|q(FeL?RQ?pujLI_2osb2KQd=;wx zF!90Hxv^%gP*-L`?)<*6AtGc}C|Dnha1^d)JE>Qs@bSM?Cn7ZW`D!RJ;)TPzAcWkZ zVjEbk;W(ttVsI#|t5(TcF~R^!IGi&XvNG1dwmpd2gJQsm62A*Lf73#Wd5n`F1D|cQ zQa8eQSELEQLwS={u~H%H9FHnaidx}pKO8e5 z1b$+N5q}dmSW4`@;nIbHLNelD;$1!&dsIz2VmI|{7-gi_r{Sklb$}s>EnI4}7wIE) z;@bS>-lwQy`4Tl9P>#(>%XsIi=AxJcp;9ukq#yxa3%<6(92258%{m4yi;57def^Jb za8I}pF-~8bR;_xu3pGu*G7@(u;w1BDY!Kc5KyQ^^=Ml4(q+;YYW>WB7{~A9t2;=Ye zm5I8b|Bbx2j;m^E+s8pf1Qb-1lm-O>VQ*ps64E6tB~rqsOS(Zq5v5a7k&>3~5JegU z=?0Nf1Oy3*-&%WZj&kC8p5Oa@pTFMoImpbKnS1VuHP?0BYq2*xSmjZ`kkJ6Eir}3D zdGcbJJf5s1=?i(f7I5D6rK;@M@F>???>sc|J>oivIcd7d8w(fb(t=@LnU`3#f=C&z z;IH)D=`b%<{tDA(6*uXL4_44J)7XNChfUrB2AIT1D{~J?a>^#!g7Qo?IKEMW7zTnb zDz)#dUu%`9=g`ERtnW9!nkr+$UCCZg=}p3pj~lBMv|}snK}tL=#vkWmYWQ^0@I6(h zdfTIZ>;7R&Uwz^>OP*DO0j*A|;q81L>etVMFIHY8u}|lxzx=Fer6Itet(5BFehEx= z-+Crm?Nh{(l>+cLuKZufgVl&iZX}A^^xw!ms2SGjZunJGAl=lmpOAZP;Zja zj*!uCmkyW1EfS%ylAPI!-N7WyxJzNotMIJ3WtO(^w)$I|wNoCLDX%)%gREbV=n>Np zmk)mnX_u|8ijCz;_eg6=7az*y;=9GraQ!KaW>AtWKkXLIx!B0Kjt4-~NA04>&-ynD zww6>M=*MZ+#`u)OZJabV*CPjZ;lO}XS8eU5dvtB($)~vWL@WboP|u zUx{M6FVP8BW8Ap(At+0b3h_)dW5A`xm$xZIlS%AZ-I9j?8K>s&a+hmWSQnY>!>%pT zrOD<;Q{69B%1|Cr!HLP%QU<;#O91X&-`OLwaN6*SQ^KJTmBmf;!R8KE z@0C}N@G2~Pn9E3Sgf%P&{DGOx{mRQP>R1TE2Ong5NzOsUaP@~qx4 z+nCGOs%UN0O4TVozzz91wapq^Z4t8(B`8BJX*GP8Q?9~@>En%Y`=_HpXHvvP)JT~n z;2)iDonO|j7J^e%u{-D;{`e{C`Qp{%ukWK^#4qoy*R9=NAg#3C=UQ#qU45N@UyqiL zPiO*1gHwW{Douop)X=-#=uwN$Fq;faz z+%@dp*nTrRYnp!j>BY5hvvL7rOha`I+85zjcX7yRU|y4+b|ImUfDg5t^sM{YfXnjO z--M5j#7A{R^89krT-88fcE0qG6h7UwH0dnqH%u!lyVa`AT2h&~5b>=abeEn;WWQe( zzoODq&7d-S3NS(pJxV&mf zYiaLGJ<>j5wkDvbQK#K%wruT$UbnZ*{o)yAWYW68*=+VKg=l{SvG1;~e|I5=oFB)v z4!q*{^ZtGk)2i=8+{;52to!z>w}sZoJgX1<50HNPrrc*J4u&f}Y-cPI`%85U#!;8p z#uOsy-(Vev`X7p2d>j6gu|C2ZGhv2xagKa`>g`hCiIF9qZV}o`tny(5=eXr?I>v>5 zj6JsgwkVYOxJM!=4Awx zBie`frm+5Hj ze@Z4%qslOqg-lx8?2ST74ExicmW!P}Fa0!wUOGW}B7|Uh$?B~9vywgo#JZ?}wLS8J zy!>$B9X1C3i@|40J<`TnZhTRQRh}-y*}hdJGp&+CKUeBuD28*G(=1*wK%_XrdNAAi z_=9P4jrt|~FJ~Q$-W8IY9dvb%0MLV@ILrpDdG-QnGTb}(@dMEFq$BMW6)uXB} z&=xFocWn`PJU9Q|HndcvWuNM$l`EiXeP69iaycJYn}x#NJVKCJku8>=GAM2j*O^!K ze5%C+PUU>7Tu+_v_UEBT)KPrcyc$VOX>%${o_Kp&@EF1$tLz=!_5v$y`*h_v>j@7! zd3$7=?sT3{7P@J$-hxN=QuG}E#bN(yt#nTJFI5j?p35LO4RLoYgZPmd-kywZTM;Su z#qQ$p6SrR0_Pf--Ab;8!sh{IiLC zeOycB32iz?>D1e^KW+PHlii)a5J!n{yAkC7yj*NRZ#fiK4*uKHWz6Q|)xfJyZcA#* zK1JIw>vI(|6XT)$RNI3{rc1S0PSG?c zX(|g;K7YPfUJHAE|E-;UhM~lerm%W>iZ_oE1=ptOJNyD=3s-!Vz6Zuib^G=?VR}7Z#S6 zvk6a<|IE?mad=l5+thCELCIE^E#31;ejuYd--^6M!dLf0Ojf>)wpP-YoUIt=kiMkL zxyqO!2`%ie5(*2a<6vB&0$iax<7-~_yv5T(S%xubs!xr{x%yn=&3bP6fvM-uPIYpb zW{7Z}{q2(Rg|jIMP0bUcZ=PCnMi&G+CJ@}^QoS_La;>9V((J*iY8Rt7QyP{)G@qm0 zs=q=UYobo#j+l8xO_-T)dlY%CF`i?FU-HrqQ#I9_@2#c?2PG3Z6SO7o zwD(h#_viRXA7nd#b)2n=6puPU#%dmpLzYBisF-Qvdv|(PgV0Nr{+&MTwhm=Al*5UalJ)5 zFgmI@gzcQ}mYHU7lQhb6eSL^QS{EvN9}HBe?_%y^xjP zGj<;RIHUD*rZ(qpzmA%-B`-(#xRTnXE#p&5Z`x};IO|Pp59*XGpCcwBnX5hTT{{>2 z&GMDj_=U3J9h0eN?KH6*Y1Hp6D>$T7Y}p)`n9sb!b?hlojX#UqLKhw@aiU22CNYr2 z)MB7{a?&W=hxJ0(?-%1(7wk`5jpTeG`;Zdn19j}=rL-O-9=(hKEA#fjMGtShI$`X| z6yI-(ja!*hKUG)vfy=iiQ0b1X;^DBUOot1%m}r&b)#<)A-H*udG>*@dBcQyArAqiI z>GAtlx4(~K@G~;-NySB~aIn2y%)sDV`E<%_d3SMiRx(p-)~teOw9L#kE%!c+7U$CR zyPMgF@m?hxxsogD4#O;WW|LT4nyMaC&Nixv4T{5;Z@he5$2R;)UoJ}^MpIZRHp!c= zHwia)@u}0m&Z7mA7Z-b;VAS58x^=L*C!P_RDw2Hh<11OB`1}-m&2zl>j4IQNs?YXl zi0SG9|6*jSRNnS8?+087(QR+}X80T`H`_`FVQt#ctg# z)qRcXn9+N~nl_<=A9h`=6oZ>$b=5|J57nF9?OJbB(~i%66yG#WnnJ1_-R5Ots+Cm@ zt8sHp%jr@~m)*K{*pYL3zb-mdX<6w~uAzbC8!=;g-xETgaq?^P3FdW4wi-G*_Hu^W z8uV&0N-nv>F?A7=MyjW>o}Ub^IsE98oIhp5cRliK^;Cu>8HKayLDeGtUHR>YTiq$% z@iw3IDtb1WsPBC%d#o*Zcv8(?V2l5d&O7F|vZ7j2s_`;goE10CDJfDp<%B?3UlOBk z)H>4~>?vulu^BtE*#j=-Y}|2`^K&HG_tvL7M!*F_p=Yp^jyOf=G9U0E!9Y5WKwIk? z9*dmx4?SA@*Po_>b;z{iR+zsh7?(L15tj`p@#?*_rcM?{9=v{0WLT1J=IDpu;oyv0 zusCh~iY(c>`hY%CKINzBawm(1U3tD4skXXqon`KepFh4Pm5I9}-#_FzY||DlUYQLA z94Bb*E*5;PS%af)WSQcs-;Q-VIV)=9e*H}q>?hGbWMo~r(+ta)3x^vh$8utJ+z)&v zN*{U?vii#&+R%DZ_&-T97m(1vH{ULPOMp8%*`IVx$7=7}jCs=lsfIx?ZaY7os@He( z@YsF-@ye;0r+YfLDHcUc)4c~}vy<3TelBdMSX$)P7-z&TJ>vwH_ zHZ-?pvyZ-=@acdUw}bVEcYC@m+KBbtoBtihd<$FMo!Le!9e zF>!MBiqCJC;t=aSoS{MzRuL>i4EvTcBhx-o32$HUr}}WWB*eE27G;j9(T>JX4+__% z&(8JtB~6UqsKiRV^DPJ0S*JZ%$8;u@TQH|-)Vjrf&CK?EBkX7Q!mBEN@9d1bxBZ?h z36S(prILe5b6e%J*RvZXxGS^-+D*vM7gm`T1^#Q?7RN&eqDq zIpUq`)8Dwpv#&|t9_dup<-`nl?o?IiKW#aBa+9acL|dZl`DVA*J-I=`na^RWJ%Kfa z^0%*X*N7r;kjIhU^tg(IbDo3%$@C4(**ol!S{Yz~mm%e6&!x{f2|wEdOy&THIjT>H9%FX{Y7?;h&Z-_giXK z9q2Iz;~w&VeqP3P{+ZV(qwoiU|KR`REuychL|;i~E-!|^61%p)ey@k{mC>9UUpv*I zi;TAc>~u;7o3RY`OwjFvM8;te13y0r%}%E%t=$SNe3%M8ercXqbZ1uoi5zk@w^`+EEdS2OTQ zT0v5~!c6gPx@tlVflUJ|Q`D}lhMWY?y&$Qb^@`_TKB-COl)mw(r=PuLbi&PDZGNvl zz|bl04wtxln_FtnlIxep9)*O6foAQ`Lt45c_^@EN=gNw@FR6&HVg4OIy#2D(eqHu_ zSZE_=+2rH)pOidjpW>JUu)gg6v0ey=*^)^~=Ru&cTX8Y`&S3^VDRmsR`ibtIJL0393a9DR@ z3qR59oFtxjlA(6`c|cI9q0ZM$XnlNeMln?-MXK472~NWLli&AC6b1_fKA- z#<8?~#~wLPuXAGh@vtO)y-ioa_l?GpH#`l%H_c`bRn~1~91O`LbPuTpvmALT@(4+5 zo;B{?VnN*BH=W(C3!xyiysJ03ly8c6J8xNz=MBF0^Tp0veV0D1UUoO8Pigo3LbG!6 zEvCGWPy?wx&J@j*bpw{qdyK0X-LN@$m%!B1_|xGEarakaC;QD`*vAjVr@x!<3=tGj z7B|22Zgk-3IqjhW(Z#V=#ivHD@~-kD$8Puf}~mUkUqZoM^+r)Qj%UqCck zo#IAMU^V(#dqkyaSf4>~)noJFgO5rU?>5C2F{@Sg;xzNgMzM1$r$zBZq-lW+Z2(Q$Isc2kVWOyujWu90?5l8#nfXdjv4#-L z^;v=Z#pEl|?ak^6DUJcJ>;u`QU;61OIkB?x#ZgpLyKHXMH9tNucXunvG0&oZMNvvn z;<7xWkZ*N>w4xa%e)2K;@uBw95$DM}OvJZLNcV`qNIv&`z}tj|N6zYJH1)>ip%EMG>BO=cjuHKCq1jkDkoS z6UZukA}RMV-V9gEVOf4`%!3+%SjZ2qytsEQnywcfMw-UbS`UQRus2l1_+{8HNsAMo zPP%_yrOP<+u~2*3d>Y)f{BHA)L$a6w+VLyGDP}LLk=o*cTru&{aw9jc(tRxNq4#EOjL3t1U(%O1)SCY>5to@?pYQdyd-?9Aq|KF)z$etxbe;Q`=y94-JrAB(Uw)$Q zP;IU;5U}L?S;X2J|C_@0Ew;gL7BXkcPrg+1@F?WIHuPp<33-2c-9Yb9Ph9F}A6EN? zz_K+O0BHCj8x`S%z2dAKQEX^we+E>Z)w_WbG5|H<&L009#yhB zA*%3?%b(3QCETgAOI9mWBcr$_*i^I&TN>U(vMfYf+v0V9*Gkr6+oVw z7bDt2PO-)7lKhu?sT6O#Pb^E2bXr5)lDDc_CGLv!0G?VTcobmGq;Bd?0b|{btXZw<_TFp^55y zW>-M*Sp$l5^0bV^?Q999$cw{)K{Cv*4ei<~h2x(IcZaH0cIXNp7Tlfe6P~G*n$tDX zy)Ij1I{*eR`xT1+!mp)aysse|Ls`1genC6^7gG z?DZ#3QYT;8X^=UNJ!9PuOBZIB6E<3W1SYAAHpF7QT6zh! zc4>dVC^x?tz`1c5)?#9TrE?a)`}FY4%r!pU_iPV7TW|^@2;Oep+8X1EBi&5HS)zYt zSDfjE%(m&@QpwR4l^>-3k~lG5GOaK5Zufv+BbE6a^>P74hDF!nU5amyzAUWFxAYIq zt0zSc_65{httC4f;Jh99(7SKVkaNxTT-EG@11O>n6clxctA6&mVv z%j?aDnO7mOT?o0`2iw$Ld}ZYB;;XTAK!`&n-g3W-qfJS2T7!lA<`+?yR? zwCrO^={n3$!-j)OhUH-uIo>QIXc@o+E@~fL6!U8SN~6ZuT_LeSV#G)%OWq~pzJ;70 zs$)^toLj(=KhuQgoFKUcZf1!!duOt88NLmgf{IqvIFNnCSjwd0H6%{y_V|JBFWe0VaM9MXD^E ztx`mnWZM+vSPaBlm_9D;5tvS&2?`#ad?YEh+_CKD62PW8$Af+AO6{mV;riV{1()PU zROE@?cWg)mX%n7LJ&L{-sbeu<=jgY==a1_p<#&nirf}!QX@xW#iH_=?+|y4;rgg+! zNX}14_&cBfa}xFqEDLufSvG4+?I;KkT-$6>^hp1HLi^*ZYYTXa!}hZ8Ppzm{ON|ED zju)BMJkYqdqhi8;82SPUeCSP@!h@V7?`XH)E(QT+sru#C{WF(8JTfLJ*y#-~$QNpw zPD>3Os_Vu^91sds8elLC+UZrU60a2a%efM5B}f~7*dK{9dVcSG65o&N3(QE?9s;=% zvi&ojzWeqHW80Jy#f~9_R+?qgG80d_u2d>2H>9qH?+7|Hd$PpNOx!F`*!I3w6kzg6 zmUqd6TD_7mR>13lmWc1yaQt6@;CiR127Weogg^cj}--#`62dkL8Onxpo zp3|&Q_V9q`;?)xqZ@ci3tD`JPYd?}C3Sz3v`f)PRAgownxwoG>r$!T*4?gHNcHP6fSZ%Y< z_m~O=or9{xVyN`z{J>g?KVhp(pM(h7gz16rDaF;tSv5{m#Ju5CUbLQb954XOnq#74q-XKX95W0*kFJ0duyO`n3I(W`O`t3ud6hV!`yQc_#F^76G*hRveb`>sA~ zH{TQ8yO3b)@#T%C*;j>!Vre*WA&Xa<#}DWZesIX-v-aBQD!wy(Iri1Wt-CzcfuP;+ zWsIYki26JDbAb=l*5NyHZTv%_>eZwH9*fpa-CV^_dt*j>>@sMmWx8_GrqR#VxDu)btlErc&(KTS*8Iz7wR&!p>T$hpQw)uk`WffQ! zlCS04R8Q2&xCSrg=umc&z%f}e)szo48LpkT9Gv1+n{THKdZ|?Eji-(kkiXz2!6_Lj z*k?E!Ke)lZ#Ix+hIKlqIRMA{@H_oLVoXd5936Epqao+ z!N(gi8?e-;(_X0+df%V_2t3)AS;E|D5%g1;C%0m9HSROFm8`qC`^lFy*C^et>=qi| z6!S00lDxQ;Be}4@;K`YO>*oa#i`O@q;n`8imx(KszlEua&qy7nE`dW)AhztUuAhMCBTx5jU%OxZ4zA^KlnVBzWK(x;@$nKm%IBj`&AUrGmH7F zTQhG26>4#(y6N=N8O5dk5W{4=S}GM~prpv$)I4f{dDTp*+?2{6N%bL@I}7;3i%yQ* zsivY!dwBaVZAM~UoJ88+VP4c~=`)-Tycm>w^VR;V9}J}@7Q&Ynq852giF0qd8#UtH z{-&|-=hfhn`GX-^GW^o^N$TPgPi5;T?cTaPyn|U9?0ZQc_}c-cM76~9*|0R`TUv;o z$~XGOcItS$`=>)y>P#_kUdv$>pEwx*j@`_uv49_<+f1@|@jK^3zVj@b*b${9JHFF$ zo)2s<*G+xLue-^s0Hp6y6NS(NpHq&REBga`A>ocR?cK-hE~|8U=d{O2m?m%69$I-~ zN~VW4l8m{&Wn!1O z;7<MdEc2-Hx_Vy2KMVMaLwKeR7CmxN)OZXqz-qm63z5x7iB~xPl@a#&b?$djk z0j}9(JPUE3q{A;s*G(;?*XfJQyS}>a;zL(pD_(R$lQtLQG6#$1N0LO=HSG7#*m+MZ zDYD(ej$r3y{&_;vI-H#;_q57k2g&8~k^9}sr=(sHm{zoqu+HEb>Ct>WYrR1AtUlA7 zb+E7Y`quEu+79P9j{VgtLQDcI-Dkpmu{E}71;jl`_yjM$_K@mR_RfB16MJN@DrQ=I z#g(=wgSbb~+xV;W%G(iG1Al{ywK)UdBwWRQdNcga+dLnhn_GK=^hAN>m{%}4eLR^) zL$`_FJ~~I8Y(ple>*ASvh2(OM#8~_?nFW>u))gfl+_+ zK5e-m9HEl`39@V8ib<8BW}QwYi#XmjO&m!#P^r?1ZS-BKR3%4)qzde|JnCZxbV}xcJ}VcA8iLaoCTL#l3eDZcSZ|E4|Pcn)f^hZ zUr2`++qKsZ+85{!&peD&54GDJ$GXI_DKqzl%ukWujGiy_Vy&OaT%rTH#JcFBSs}LLTo(haS`HE%(QP6LvQ`D0!8KP=;S0n3{3GdmKuv5L#3tQa9b~^Si z)Sg@}Z@WL5I;-uH`Rxs7Yk**MQ3IdB-M(1+#m4gUW#-1h$l^x+S30uaJU1JNJ->XV zMivU}{-8Ct-)Of`UQL)U!yCIYH#oaDx%kXZmqo6eVEtBm#9eX=^N3kX8ME)-q~~OP zjfnCJ1DxKrV^GSywZGb=la|0LRdesLTlx#B5O+*ZxgmBbb$CtCMkFR&`e97ryu~M% z?IJdHz4YWk4i7dhxqLB!B7cFySY@EIGrgjV9BXwR}L ztH&-A*WX7nrr(HpKA&`^uN&7!+=EDe@WNV6!nEL*V(E~v8u8lRLdB3RECN=8`pcC8 z(|(`MRYqUF@=fbavQ6admTuX*@SKm|f0EWEjfqTzZez){d{465!#Oiq>MuCS_I~Sb z*}Gc1y+_~dy0@Y~9hl;}9?V9J;S>Zm?`t>=rnIa*iV4$Z_K2GfZK({^IUgLV`$31A zz14Fj$W*{q!dXx=!hIpg^sd%6LsLqGeM&7Ic?z?v_b%n+CLf=d3vOlfo0OPOLiPTF z!YUE&UxG~cw3K(1`3~OL)Gj|^tb89EHqQ=p>w)VobSL6x+occN>zBqiN$flx4zdm45t2^!+F6cUS>6Kgt(?Q5KJ zEqNCYsu;HN7{Ba{GFHy#2R0W=EPiWQYn^l({LWaZ3QPe$W97H&2Hle^t+f^6wQU+C z?n`bs?!X&g5eAo<%pYPu<8?NNyXD?j3$wXVrL$aT{q!_@(4z_yHHjk*_m)B-stEUc9Y1J#fjq6HbiJIB+4C zJ!*9FJkQ0E8%Rsms0#Kc@&P;(5`~pY%dxN1l`d4UmJyHm8(FeMMX~#S4H(IKN*NI0 zg6l-w#7;G}5B zXa1Qp>wIrJTkr#`&rzHwq;;a968R!ha~}9+ql+`w-j>r?-`vA|s}m^fUqQ0w7wCS@ z`_$UG8DTLG%9*R@Y;Nu`%yb4Gk^^<;dk%>L^=|IX2kMFLF}^KmnJb_>xHeN9SpRVQ zePI2A?M%Bp#lSNN*q&oy2mQg7d)zbilDQ(c4iz)7Vf)_C zsrZ~|yr^Dlbm4sRI1Tf((d7FY+S6UM^Tzuot4mS)LACIryxH9knQr)pg37G|x6P82 z>)PF96ra=*B^nmzMEQP8C2ovJbXe;+V1M5_bC~UG_`{h`!TkCwxprr6onF=NsUKr? zL|=SQC1xR>ON;H6r$-kb*oY}tl~yCn89ZYE<@qV9KO>$mE|Kh?K) zpWkKi&5Kn^4(r?S#`{*`zpgNqfKe^W^zBp~Ss`H|wMiDq>puRFYG=F2nL4qImaSH< zAHWB?2ugX~REXsK#JJ*WN54bs`mDycuUCEy|I^^7Z!MD%8X{YWPi8CbW0PTs7OEc> znF)*RAr&_E-M;Ys(q0j}z#B3Ik=m{9EmmX9>$>YgcK%}u6N)QSb#fC7&Jl!R!Zgm| zOxlFDz9-xEWBs;->xdN*9jZcDIYKbB&z_xa73o-Own(cQqGax2Ss`L-CgG{z7W znU&r4p>{VazmAbq%B&cyFl}90F1x*J$Q`>EIIiO(K7`=LtUDI|g#5#Qcj7Jk} z81adFhw@8*t2ajf3w-v!dq6%4F^ z5(QB$DFr1KRWnNq1L(S>ft8u1D-9Fs5;Jhk(!j)?27JFAXe26X<3ghi*k^;mXt;TR zA2=_K4j#LVgMp=)p@_AKC6a~%k6pyx5NYi|!^aJz!G6IE8yw7u8Q4lA%}h)kz?OLI zst!mibsAov08B}vQeZ#8$3r4HX<#r8peq%i(D9xFY9NZXNNaFN;KxHEt&PC%Zh*lM ze>>jaT8YVsgGRxIKu@9u_DC@M=fMNDR9)=>H)O1hZD<4p@Yq$5CT8{ycEDta09_%0 z$xyU2LfV;Go6s=H7y*Mab8rPNsyf=*S|Y8$L889Imt6yxA{g+4;NYRrp@DG%NnQ>Z zkmLlfa&yChEHG^}oP0nQ&c_WTxltvYV0~@`Sf7`V1_6}o(C~19SvVX>@`9CkI1peG ztOPvt1(JMlFv$ldVW_@%;9RIQstPA)9R{otPzUIk2L^Tw;{=WJKxLe$GL%&q7ubdi z=$D5J><|XDIO+z*%?+gCJgD|OU_EZAPXq^$=0rINL+}7;K5%dFfxg3d!Ljpjae!%{ zHsk}C25o_TaH0BvbAUFuIl+2xVA22|xWMti0ZT{y!{MkpfJI&eI6gQWtjCSu2KoZ$ z77mRAXu-w9NyE*{156JG&&$*neAx%vH@*=)j*vVfG#d7%;Uz@eI4P&+7x;D&mDp~{d@I|Ry47#!*W4vn1y@{9|rX@sr`%>*wG zWCikt6B;`gG%rSmP=7qo7|^~LLH!w{$~YmL#*j@;luZ~1WCeKR1Y8GWs2wNdH4^fS z6Y`83nip=UcRt7p57ZwwdR3r#fkQR9pml&jy>me|`Jj2>L7@6Gg4PIu%E4ghnSi_o zCIq!Zpqkv!__!gjxzJuiHVx6UgdQK{3$Qrgh&cHmE09fNI5ZQ`7?4m70qh9?G|+n! zNTKerKkf`eM>{*<3`gCFsQU%H56rBQf849KHnw2RNJeFUFI1^^}kr;$ByJVAh`0v=GeZPcvIz*`Ww2%bd8&L-fz z{Ppcdza08?pg{*5bSkK-s%whM{SSBm9L|S2xVeGu{-;C$4gdd&2*6OI``1JO4put) zI;UR){%r;Ri3l7Y{jo#$|D6Z`69ixiz)}F*Lt`xp8zDU9LQw=h6ds}Q^au-47zbe? z9K`VBSct-39`HIEzj#rEf)l*Xi6R$&gI}l}aeR-!f15HiesS?|{h!4zfN&niFBtm7 zL!i#hKb_&nQQ|n79Y>zy=eyxC%s7r_hR1N|Hw5|bom}wWzXt7Z@0-7zT*q&i|M=uW z-JyRzxd7()=acLA503xk(BGe2ax$XQQW7lENJ}TAgPEa$0@4u)ooq)+=8qy8u#ZW;uzd(fJR8^K9~0Qv$ifqm-GaDjpXG|UUg5%4mC8x%31izsOY8UVAXmMBBq z;E~IRI$D9M;0X2K88@J?e*X>S1c$};q90b&D?K`2jPJSgddO8?!l z4&E-ukM-X}0O(^K2Iu_0d#(dWdHh`G0BAADI?*f_ps-+$2T~1a*2x3$TA&J8hSmaT z-i~JR0NF*ggLpd^n)5=8lp87oBmu}zxzXGeV%z||McIV-DIjuCIjBD_h^_KKEEk~t zs2(6*3&cnCLpZ=&p6;v4!G68*#(yP zzo^OJ|28!E7iRPK@cExJ91yqv!f^f)Hv-~ue0{%vk2ar$zHsPq4DnP*imw+V5dXD%8L}XBrS5AQYfV2dpAE;s= zjX?1>AS4PH2eN+~=tOPLV~hd_jQ(0KG^5}J$Sx3vN5?__Zv{Gm(D|PU#jzv$NH#*p z;-6^3F%bXLVSWsZj}wvOl;uyP;TTOg4vv2!6wtwo4$S?Dq(DH8raH%|z;ViQoCX~S z@#8e%IPp17k&e>@bl?#U;>Tg;I6*^)QqeGaoa!7WMgKW$AE!FU!5{Vu9RGVV9C$eN z>lXW4$@dqq`un5sKL;!D4E{4%q3-nK_x|reqF;{vJy>Z;%Bm@=vWO$i4b&Y~4Xo|u zZLDpM>v5=z1}vljOaD;h+)zFALq<@M!$G|SoVJL6`Ir%WlK2N;!8rjlzW@tp`L6*B z4#ZCXBA__`ZAj#|P$KYkcE6q}{=@kHci{>3Bn^0O1xQBd0U7XM56XgQ1SbFg{-A;E z_hx{o{?!kFSAR7OfEnsJBDy~SvW~m~l1HAPf$Vq7|C9#83DC31|B3$qF#hrod>jZo z6@)IJGQWlb=lWyPfD$ekO8lc{?{Bm<0Gxl)*1&H3b(QI}u;vjEqZK+@HKJ8GT9ZTi0a-cH z!O*Gz3cXa?cX45Ah65t)Ey;)v!zJseRrs2%VK7BwOuTJT>a4F5Jp z{1?LT59stCGX@kc{)I986+VBDKmI$$ASJCJE}`&0kheSlvV#vrkN5&Nz!y09fPgR% z{RQIB|0rMX<8It03-M4&^(G&0HJw+Nr0|^8WrFRsF#CK;dtO-3?x(kT?`%! zymJBXM?nF2KtR)F(Q+!2|ij1Hm^Ml;M!C=s@xjL__01zodf> z52GIopsCprje=^TUkdsYae{n>p-B#!4ndwR04>zZK)_q0=s+$M69@7r z+j#6y*a3LPi+(EyViiCh!bNsy2tXdP_ZvD^k0uaIlpf&oPVJ_fYWf!xtw6RkK-$|qaP~6GP5UC<13P^A>2YV%?otTZ4t&KGp zx(3*RjI{&O&eq1#zyV3)V264y!0c~6q+1*bzC)#CU}t5Idfi9K4hg;mW@87u0E_C+ z(FzDvK%Ss_x2NF*&v$lJc>{Y38sOuLa>ip@$zQ;#nW-CJ2l&U57582P(?oHM$jfPK9o2KArZv zL)(8`Zvn2~z3ztYu(1Sf6C)LH^r&rM#_w&_=T*^u+KyBeaveGC@w?LoI!A4pM1FUg zwe4sk)J&J(1Z_A#Bf$GG04)p#*j4-5(X6l?v&r^{O(|^>;#Bl9DTV(&V9kJ|SqbX> z-KN~?kxiYEs-Bc&^t7A(-oXpLqb0r#>;q_(z$NDYe$*BVXd83Xmhf2Ht4D21Ui{vc z{ErpB3bYMAY76XA$UeBjFD@Om-FW$X+uc8WmIK=QAGOsu))woiE!VL{YWu@yn~^G| zgrm0Z$J%lnwavZx`y$<*J6d1~(`8W^H?*tEJ-<)r=Jsu9!|5|0vq}1gO-XH%YajZc zb=3^}eUX@&j&^~?uSNRt?F%MG0@|uiv8Si!*#n~5{fEK81YuN@qo#|&ed7F9a!U8n zP1G=2<~_Fe{ZREutY?WMZPG3Qsv4ir-m9h2!?AYni9c?`0?KV0LW`C4d~ahy3>Qfe z)Pdo166c45_W`1NySo=SDn9i>?)oftS=TLnDf;687(-;tXBW2v%W&>!19J?vSm$(I z|K*AYf3*Ox^pB73R(rFe3v-jhSQuV?eF2Rjf{9vhK<9cIa+6mE2VAhst6I0sdDUCG)Aq<8Mx#d5DmuaPMiH22he+>Fy>r+;3hUie0yCti zFfc9xr;$jFs?WG=y}~|K4IO9)qmQx1a^ptF9$<_4qUjLrw2vdrK6KNr05kqP*?4@c ze#04c^KHv$lh7@UH4uNTuJm5~2A)n0@p}ZE^}wm3)Zlw|T+jNv?Ncn!tY&1{^^QzM ztk8we2dR~)J0x>mAwqMcisRXjGh=hB8~&eBH&%l=aE`R3zNilOc0%nEeab^Ok~23? zpB?w~s6jRCnLr)du}_j$-k&@NT7M3+(!sd$b9c8lLcm`d<;SDFYgDiIMyoJxy~J@n zRo{9Btk)A-;D{O5;GAwkqzmSK6oAf1<=@{wQ)>_Av)T#Q*Pa0TZPt`4>Y$8P=*rRK6eBK^(qiGY%Q3Y?<`-=Bz&~4A`h1H`!fBClO*!%<&;z>AH)8oaXFvQ6kzn>&kZ zr4y2t^gU3tgYM#kAnW3cTcEiHJ^CBf6Cc*bfXTawqjxy@<$=FSpq4+KQv4#gL_XEc zHJ=7$rx^8?i&CgCR^>%Z8wlZGNrO)LmhpTo_NHzKn@3(dRbA(}0-G^5o+w4e1)vy% zif=aHaMP_{N}pbDdHqzu&j+w~n)!t`8Aq<4mNmTxvm;bXv7f{~FUv@JBrjqogc5M5*{#~Vs#UAZqyZckV`0nQl{H;9T{`TFG7cFbRU6duE?QCWiyL76C#7C1Tc7BUG51<6? zvNujwRs-`sXS$rv@>S)mKg%7iRNbNIm2bQHBp5?%Usq>u1Cx6@Ew4JYgu;x-w=+v;RAFs zwtdH$&1}%j2kVljn8t4GGfa$Rxf|0L1!2JW?t0`^N0lr)Tm`#`?){)orta#0jTsZ; zR;-g{mfaXorJ{YXN=~|34ofX6iz-RC`_euFxWf-*Z}d9wa{=WR>!sG-X3mRVHIzPD z*A7NYv_A>QCZWz}eGaSf&o!>X+Aho3Lg#gFjuh0b;+#<=#L&+#c`3Txiid%rk1zaY zOlw4feCphCO?0(x!8Jbi+60E>+~?e1S;&ig^(JH)cAE6ea7eXwiM4S}Y>npZivn$` z70HWERD7INDw1q^(0jd?Ej`bKSIP3Mmi_oMg1V%rGZ{sRm`D+I*14gl5du%-Zj?*6 zT?b!B`RGc(f^{G^+8R?*>#@Au2e-S&O`DvQit>BgfwALie)XlZ-Wm6mI{ z`X!-HlW5r|*VIf?vNa_=ElD$NQqPH~YwD};BipsN4xp<*>ibP8}Y0xO~TAq1pRYHktWnBFA3o3HgxoN^HjM5s}pO^q> zAdzP~U3$9;ckG0AQD={)G1=<{>y9q%AYIWDCVWmo6!^FN>KP>S2xaXeWIuDoL>eO^ z*sLU1;PRzTkv0#8OYN>#ZeK>uvBooUoISY12@4{Q`JPJ_7Opt{`HefD_sW6bW__2w zawWcPl)wG0z~#;Cj|k!$m6KS-q&R`{pzTX$GL96XC5u`x6k z7wFaPbY&8Zdn2rdKguQqeyxGAzmWAEz8BF-hbqTP^&gD#VgvHoc7~dXY{gT0IlpUvU#~jR>dXHd?5k?~t9bqT= zu4f=%YpB>Px6P@Av7mU_Z`?EW%9>7oQ3^{EMyT}DlXEI^BMsJb13x9(L_?PNuEdH) zDKKblRQBSo2EGNhYfO}(UZVN3lM*cSNs(F;N6e_4S(45~ukp%VCjlzlJMpZn3r7IBXCd8&4^t_V#!VrKY5b*t9M0Rk&i6Ycyd!|xaoZ_{8LQ6a_9_J-pdEDfmCkYKA5m2{P|otr_^} z8iV&mg|IrnXDo}u_IY!T+15+5W%YjE1T3>>4Wt7j)}kcVjXLg)Qg!W~2ke-9N zyc?=|Gcxu?nAoQJa9hX*1WH)9TTHY$((r}Wfsf$|n?HF{XwZxDtNTr>@rV%?agoBd9A(o7Bw1DC_5>e5EVw>J4mGlLg0q&O~^usPT3< zFzTz~r-WX&;Ek-sjZ|&2Ms)Ix)L-#ANldOYTpAnPP()Z4zU^V1M4JCSjWJDL>KkX8 zP@~+8{b_@e0Rq~G?UMS#IFr&I`YGuHUDbp+0L7Ny@G92&pkmTW8K1N$?c*T;-w2Gt$=oNwsoQsW%bkztoO26*Mjw0JL%Hi%4YG+FYY^-5DD@`Tq{nKs9Q6; z%Jwnf^mw)Sm-FGn3b|B^l+PvpWf6J~e%@mpFq29?lEjI0^g z{(eBQ_z2dF^ZI2K1qhJQu(h~V)kx^``HP?Edie$e;4B%clQ_$}MHs!B7Feg@)7jK^ z*`dPEhTb@swHGeGy294gd7AxEn6yW}8?hR-H~cj=m8%MMiQ}}ejvjG?9zn<%nogHj z))5~mT`$pf$VGe-Fnj&gObQUQX#tR2So~Xuju~QrnpBoj0EYIMd@A# zHo(1RXRufozO9LABf{meF*Jh*jlS_S-<>=hP9%CYHpNFKO3RnNIZD=k)s_XbWqM)# zItjH;3c&5}+wnw546zz8un;g^Tk?0R)y0YGgL$_}Dz82A>W$GEG+t_Ozhdg*lxF2t5|9G`f-H)7$sH)1D!ZLMW^h>6p7qJq3F zeAI#e#b zS<5x_7Iz$H1g;AeORWiCpd-FOL_(cqDuv0sTkc!p=y$P=!iQ2+VLr^Vqn^Uy{t^>o zwo6xMN<*w3dOrI#LsIHasM8weO>&GDq*)|7W1ArLtLGJN z85|tb6J6&j04p+1aQ?txtD&uOG1mV=XRNQpCTCDV&!ab_CexRmB?Dtk5zJwrwUcTTDjOo<-QAi(N9^D-WixL z{*M@*E8+d&+u)nkHzO0tL$p|GZ#S5bE8vR*a%&i4z2HVV2#%HR=H@#won5V7B}NLY zN8*cT1b3h&CA5+sYb{09UHG7pnc-L49Dm-%Z#nXqgtwgUdB6F?4xb!YODqIOc2$2# zKW66H^SCMSZ;W!hjpC-xd!}~S3-^;sajf;#h`qwMQz___iah(Bh(9`i?U4rn5~>C8 zZuX9ZlJ)hb2HapfQbK2^2k#;U2)-UmYCu%PXJ}uS5Kh%oSkppy+Wfm@?%3DEO6emO znf7lGE2K*ZN0E-cRUb(2K=l;NG4+Vg8myHa)5C3L`-vp3i^G%DRfKMEJ6my0jbz%A zGF|nM!UQa}*JvWdf$*2p;XY-RB}f$#vO|o)DL)YMvmKr=BIYi@@ZuPs`DzwY{TUI) z`UqKM{T#5zI@14U&Q@rD?Z zf(kQMewM7nVJ?e6PzFchU$GsL8+|CYJ7(rw!i$R%(t=3Z9P8UEI8c0GnW?v@>GJk1 zZ9jR zEVUC7n>#^Xa%jyzFz!}~-cK=dy8yi%S~=-i{-wrQ6|ClsH?xHO-HE$g{BsS>3#WNU zRLl8c*TY|+RyqFAH2#z?`mfMRxjcoD)#Sr8##U*ciMD~1KJH><>hE3_o_E`3ntVV0iY$wivYjQzk#k@ z0iX6o{D@@y2d?O&HaQje)Ndl7QQDsXa25K^vB7F+1xfGaEEfH@`y3pd6!8WJNmWU4 zO)d)cOo%N0vDP6PFtHG%veb4h&w*_%qdF*J)UD4wU(cMrkSbFk!sMZF`-A$W8%dIQDkXzt1cjoZhYDAC*CWy`+>BC<`}~W ztp9(OBOzyUIkB3*X|h15m2!diVynFXg>M5G-N!*$w0CtnB|9VK()??sB%h0Kw2LG5 zsP-m2^6D>zkm<3PY?>$dBizkP&n9s|ORqvLv*N)q(J?nxA3(eECqa_De4sH7bNVr0 z!ok&#YR#$QEb0X@Eiu~10GUR|V@}VAXLN%IEay*X%DuTw-*PEq13@ySrk{Kb;2kiP z4%@9#0M?<0ZOX6xJw`+)jR6`5dO*?SmJ`qcECuzqtX1O!1~r&njZE+h&d4Q2{?w>Wvc#%9E5}}y^l?u;D^!NctDwdF@Q%hx^quT;i>t}{syr~?(*I7=$ zn6L+c@Uv2Pj?Owu0@U_>7o_CvQ(5kawy z=r2H(4vWUTr2S72K1z%5e{HpU!;NS|CV~f~0+6UM6YC{1l~G4#YGyEk+Gn=FS?QVj zLkVZq=BLb0zwn zJ7`9HwhC`5eFW#L#u{eh+6o*n(#%g1IU?CZJ|EjnBu6#~%l@*%K>@L@@6B+YSplIC zs&vo=MyZ<3D%e)dJ*Cgms350lvKjkSU--a%79n)dDgf=;)V*r*v16NKqEq3f?Qls~ zEM|{@$C+x-H6vlnm1C7D1zxV zl(lbVv5fYR@=TzwS{UZGjBD?4&~lmf^)iaj!edmUMp=C|z)yEe-@+Y5Rv!pseDUV4 zZ3Pw%^28oOHqg_=3=cW>Sm!pLkqNh%h?3{a2)Rs_tHrW>FrisRZmGA%EULOoOyd{D zm8H4Mpd;~_V)P@WiWlR1w)r3N&y2(11Od0WaxUyXt8Pu zUc!WVK1WfNs9WLjc!_#tB0okWCFA``n7v?BlA80qriUvhX+WO=fc~}Tdws7K zD0A*D&v!}^YJt}m^5P^+(Wd0Dk-!nv;j#JYpBw4#JC;n!)I8{-#C`qh6NHp-S;w;S z<;DA9c19+ev@EFG86DJM5VwZsil9%;E~q7?ZNI)vkx4n+5aH`n=Exi#uWo#XhU7La4Zrhu z7)xzGJ6+h$fF^#AKGJ1fvx~A395PG3J~|$3CBGsX?3b3)8ZWeGev-XY1(@TJc5X!vE}h+)&$y6XFegwjqzliu)F{ zsX6nh@x4{6&G*V1-9`_@1TG5Gp36vr^)ewl+7Hk6a9Q1%z@{VFt66q%h#DI8MFm)x z)fW;7`SeXbIh;y4m|kk5xWXFXW$hb$Uq4j;Z}&d*QRzVEWc&1u6$;!&j1a8RW)B(a z;jh~qPpAKqm%=r1ewaIez6S$<{_Uqz`x}!*&HSz%>O+P>$G(^!wxKc#myRc=r_rQ= zU)7^XiJlGBce9@(C$}VakceNHLwF>@JhUJls3k+~Yu3sH1gT}&Pf=+;%vW3Og)T%3 zp=DlHVMBDX>kk-EFId`(nY8Us(MA`4>MBltXZTX79Ij3;9)42~Ip7IImtx%#lGv2hDEM5Zo0o%5VnObFh}-~^s*@%Q99cLPe- zjO~YLw40TcZ>>K!BctAzxxn^U8336*FNwIlC55%g zUu!=>)%;3<)F43uAUWWgHY>cBm%m`?HFJv!5Yac{VC6$c2A=xjl>Dly?&YeXj{^Rh zM|oOC5)J2jxDe6|o#uGfs+BU0oEPoGo)W0ner4|mUmLzk@6$Gn)=gl(O63B;L#aYj zpJP=_ch9cPd6)MDOA~fa&6Z=0ui``wU`okm7o80-`m<0KA{u=K3o0F+OVs%rso#mj za~abnxQX~{11nudS}TgLZ&JerAjKc?@rWI@VKFSq-f2z(+xG2T-Z6%~aao@ZqDdf( zLg?(-9dE(AQA5##=_B4HBDtSKu4)`kKOt4X!R!d)dGHW|^)J!Lx&_@(=Rsfkts;?_ z@Y}F@-pY~?7Up>ZeR-U835}=N*opYep8^YdQK4RuxVDVNkCWG>)PbY3#5gcp4<0A( zr-FwlVMWFhZ|p>U2H?PuDcB(SgF%YwR;}cG`5cpFZDZ1OcI#c%$SaJS6;2Pf_^6Za zOU5hT+(leUEM+~~z=h}UPO-%%7=5<5)hk6>uuk35;nPtY3+(@Rg_0z1U+We|-YxeD zU3PLaL4@x!0{nUt?rdXZm&3`?V59W6iKn}( z9+v+0sE>GuqZR|}{4`=tD2fC-z6N(KusR9#*kd|Q8GAD3fPXX4J6d*8QF3!J z`xU1ZH*gLAY;LHCs69IM)`nip?$|{4^0)?StsNQbcNQ%ocqYeBoI$u ze3PG}lmIQH8{ZkxbGIv!YwzfbY0#CT4$BGIs;-uHd&XtSX{yROu_zOA#jGw_390^k zIa=9m*!=V5tpq#hOo7i6C**_yXI6y7K1QUi;o*wHeU3e{_N7~$C-1G#1ns`cnKEw5%34)gM14SRRZuC;?E_ypYYWex))`cxIrsVVw3mO@ zuus%E$zSx5+iYIdOC<~%{I$(c<~#qP(U=;amR%~xfHG)d zyfC=&l`v0{llVkhQGptoaS$w`=0258?98lOSVv5J!>PE}W+qZ=UUOgJyw3?cSDAR) z_J`q>7q42SSl4DzN6|;4t#|XWy{EIh)bU-cPlNJjb>?})*7)Ad!#m5mf`Z5FILo5n z(O$vCFa#>rC`x1skI4WkyR^-le|YQn);PeZ4ZO?|cJj^|t6z~EY#*2W(;$PTBd(@I zwgw7Skby+zPv9)|TBoR`F;V)M)ownr_jH*T4dZnK-F|NyGhgJ1MV5KOZxFJA6VO-` zmWNK0c;?GCTnYT-q5~C&2$F^yG>xAU{_Ir%BgBT*gR-_3@2F*D!M1zo7je>)p@xZ3`O^>_3b!6V?5WWte&Ua^3zIrnWDP+9JudIY=d}1_sICm-MyP1usI(dTG54CR}k-z z#bs$*lu)o>t+A&mG04kKWeMC7b@)&Ifsk z1y(t5+#~WfXMX+qD-c2l2*4uoZYyb@Apa2nS?7&SWbvRs(u6=$ zY0{diVm76Q0^=O+j{>EdA=Sm%OL_ojYJm9h6eL$vGd7U@FO6>r>%O0))x6%@n;4o` zto}ed0ak1ofU(}DTfn*uhNSK!{EYz02AfUUUSfF~acasNM5Ir-2M2ZDb{k087Oi(NBP zL{{3rx{Nh6Rj>c(dWpyJ*Y`jAu*^R_=wlIR`9rw^fyOVfjUOv|eH5OpZ$|yEVZXde9A;wjzyWBD7NcZ9YJAkF9{xlc)ZzDrV3O2oOf~KWtvm`!%sRg7nG1U5S@GGBFM& z>K|f$v_;Uc`9JJNM~LR6YMS@uUxFjZmAAI2z@2OAzlJ4{>L19J{JjSxdCMOz$EE55 zL?WPg;azC_?N729{Ra;)HvSSSL24ZU$qjI!`XA=27fI+ghS~0e1kT0o-`qANI;tu@ zTh?>^%e*X&YQF>4!H;F|$n@XlshlYM>8tywzsbPR9me96@sFnid)5zu*!ZWb^<@6* zX>~=>Zo#h~|4PH**wv2dpSqe{DJ{$D|BU4i_Qu2}oPAXFlR^bhS6 zbR_yGAsPR<`@ZuFv}q;k@IE?GSyT0|n1QVRtI1O7-~L^k0gJW&8U9iXKvm>FstQ*{ z{++5fE9QS=<@IrB=3lAWs*5@M=RVl}OVb8Dfl~BGZ&f`eLF<=;8iy)Oq?41rM>AU~ z{u?XDoPWoP@3`TAnZ*j2<@F!4_B{Wc_Ya)BzxU?5>ym%#vN-nqcUpj$Jbbw0|IuYr zSM_hR9GfSI2mVQ2ko9GkYT5%3_CJdt`aLG5iACtcYa9RT8?1kb`2TzX6!?ZX!2Sn5 ze*QrJf28;WUrhb;8S($?I|u(CZvub;{{R2`D+*$E`Y!*k?;o?@ZndmuEnFu*>LD~EKlpB!Y=alQB3;>$hws!6EdTJ z@G$7a`9;Zb7MR3rKRn6EN`!lJ2sZ$*6y#+qe#zcG2kan#STJc*jpH83jGzrb#jafc zJa7m)35S{*owoi*LEUL8fM`=?AH|!!qU3UN9OFYDV`fJSFUTQ0xM{9=2*1!4H5dyMHyyBOc{7s{e7Sxfg<5ok0 zxBpBi?1X!%pFEoB9}ewl`xCMw@=QqjqwX7I+EkiH-2y_r)TRiJx=G2`zxh1smJ+{& zm$~YB)cpf!(|*Zz6dPz21n(OqH^}xFusfe9x&A=T#|UE)DS}`B4J06g`Zs#y>$qPY zb?S;=`sn@1feQjf@bgDeFpv(N!hh8P)jE&_68`ia8G9xK2gBe|9!N%%p*@zz&^-fe zDoC`xPdpLke{U(P)y&=Gegr1&x2E{GMulYhO&piR}JFMG@Z;B<{E3Fl)D zpl3pu+yfr1bOW?-U&K8I(t>>5-URE>lY8J8;rby}1z!pFZub5)8XL$yLQ*F7Kbk-= zieQ4r)?UK>>u^)$(VlmRnUF#KKb;+bC4Nbi82qPMEb?$Dx9{WOYv7Q>x#7`*0N_WZ zS=8f?+!bjgth_&2>_yHYg@anuwOUIANU*tl{v!d+PqRevbq%#$lph|+l8WZ4G&xUk zpFW^xL!(Wl@c&~OS-!UOPrTSzp3|4No1`0eF-ELJlYkCZZ5nkJbvVVF`@HgG-k0-m)Lsu;l?r)lP2d?!p$=2;*|KwWwgo8N}QYvZW z{h;!#As>b)nj#np{3rRmXz3fpN$8x zfeU}U6O0PHF07OJdeTh0De-C~99mXHV)|!<`L&unQ7zKzsomi%*g?K-xcl`_(1y3m z8jyW=q=!lT5!GVDfaL!;nCC2ej6*5;3Xega%o8R$K0e;%cWblz_1XSh`Q)dMfUiHI ziQmypY;-bnAf*F6N7X-Himg; zjba|+mvJmk6v0qNCUdonaP7P{4l|mpvCrczjN0`&p7Mb1cU1?k@CzMNTM?T{gnPTZ z>j=}{o7<`f^(Jw?;;@{N+Sk5XO%izNSzs0*`4vH0%qC{1WkT(>wBxF++2Ttj9{kLOFp9)lqdtk+h|p{w0+pu_zbfj^1( zr5ZTJng{m2?z{bFkhZdXx}n%^S6I#gb|5glZjG1nwywY*L-#a$B8;ag#_drup=?x2yCD9gvi0m#Yb>W7vD+qjgN2eE`Xb{15^}ewzjKFYQ^lU=9BOp=MH!2Lno>P|gm-~8u zOu|m+?p4Yky*tnp>|m` zJGE{JsI6jx0g(yaw$e0kX=^@9AX|qEoPrS;XBmZt&=+%#vVcHq9Bj{xS|;#)nZz%> zmKwQ*IV`H)Dw%Bre94|c1bH>C#m@gOPx}3fG#vW5i7-Z2zx;ARDnH(W1X$k$?5VG% zYpR$93u9(N^r$_?f)$M^a<6BTje!TJ7vFM~g;|e2Px~)8TGFZ9%Rb?3VR_%h``X;? zXMj69MHgObHn+SQtH0W&kQu|CN@G1ka%5RCUPrEXQT(!v6{VPOzgk@&-SseR9BgZ@ zNUW#uWpiVpr@vmOSIn@RE;s6nVSJt{&m#K0`L_lkg4tL3CfySWv7<|YYE3;J;9(qK zci+qxplI>Kq#kaVtX{GC=5%MQP`#qjrf6t$KA3qU+9O+-t7vM^D&hhi4&)^cwHOFJ z^Ht>8!hEOmI}`Gg*>a*VBGe>2QD;)#^aBk`S;aOM?9(Jg$IL%I)T`ITnwzN_pF6lU zA&Y2y%7nZQxpNY>{AyDB<9F|`_hpBaGA(nTkhwdW6`EU&c!0-efZ20P&s^f>j=O5Y zMiddXrf&TllXUPgpvAJ)qJ;5&# zidg?vb{YCp3+&NV$;)93d4793zHiMzaLu%;v@@YDBJKYWFUH%2Vt=8#jMH8t?1Ww-tYmp6yLnP#dIf zrr<}=>I#+IQSzD6xO-6#T*%Iu3`qN9$sY0x|A~Ri=PK((p3&C=5OJJt*HRggoPHW*qrE>dZ?^aAm%n6*%Dl8H)IC|cTb{O*?)Ziz;yJ2&?)l#{*{UOWCDW2r9)F-$IUaXS2W}Pea>eEgnA_DR z^ZoY2M)N+gow_+C=b<))Cn`QkN)4Xdidic!DlNwQ#}j%Hz-glO)Y=i@&i6hewZ5H0PQ@Ep?elMCWtH>0NLywN}g~#O^Fdk6|y6 z6`N`BXYX?}8e8k=Wk}1hPuYl4il>W+s^d!fQ2k}B&WvqELE72n;G-boIVG5PjG2(( zf{U8aNLT`@IPeFG$fQ$%#MRUxlJT08!SRgq3bp-`EE4^L`&>=336Bm);B7BKm6^3o z6i%&80A~b~#*r(r?B($3fd!|q zfUK_x+JQQl6J)ku+%)b_rB&>;9Wk;?hqC;X3K$T#@o=S_VRC zK3}#?{}eZjM2v3Hyq90U`r_g~p(f&nyj+3nlJW0QE|s3Pf6~=O(9H$m+P9f$iKw|; zs1oMN3UipsrVkf9ro@$luohP0rUna}>af!nfBLEDi-U?+E(@t2bu>=I2q=>Gwex*K z`IOFPZH;n0VB4!Lh*tSknT>(La>oV5L+k$h^_gouc!UO0v9wAIU@&<1Xt}c8-^p^_ zqt-nIO6lp;{8@!`(dxUxYQ1(RL|8IMz*o4t*7FB%zehXL;=M2za;W{zcuA~Q+WX@B z27XGQ7`fL+gtrCI#wI-!Ev|Ec50;V=K$(s*dP!F-dAbY87mU(7wELm&;+JsXhT|%O z1J|E=I!6=>%F<|Mnb`rQuEIn3JSX!{*|F4-Zr%av6~6~hitdSVW&@`SubJ067d;fS zJ(^s5@a!15%`Bz?-Db)OE+jQXRC>E4Y~YP!i!vUhLdxd+!mo};$3g;Ynonx9K@Ba$ zzd8<8f5y4qZjzulVYy}VYt1g+3T-aDq1{_QoLWgM67e6Y#aV=IbDO>)P0FC}`ot%u z3D33%u8G0pz;u+FJKete#XD$x!(J)F9&DRWbVjY5h@Txc8=%l%@mr+PJy|wsNE`i% zgx}W3NoUb0ia0gw9@<;A!FfP$Gj4yr$#!By;N*xe+^L**fb?2$Mkk) zI+oi`Ccu;H{xcKamJH+V(l`F!BOk_TzTKr*mn;l2;4n#PQrN#%t(W z{6+m5JK8?EWA-wnwb-Q4!I9k;hj@X^D?f35yBTD>$XaRm(p)vBH0yksPfaYHUyZ`qezgCKq+!Xmz8S zwiur^b^`d>P0@hBCW*vGEN7onl8%sRozkzGlxv2(Al6?yFu|`>-+zmkBNwFp;4%I7 zD${&#{Rx}L8rnp$QpNu6HADC8%7K;`%6eth`MW(kS&0HQF}e+%Q6#GlgvJ6Y^Lld4 zWrRY#vm_4UA36?_KYu7T{*96%{X#iE#O0>8_EY|JD{?2R zucVz59U?!KXsRW#e57xsxWOmNhM>SHsYf7a*hII+>(dk({%SP$%?1UKDF@UjbA^)9uV5{a#hKm{mh@H<2@!(Do?i<7wegO#RTV^N1|} zJtv}FiAC`RG12$Eo0+jC72da{41F`>^FwfFLM~myW%V)pyVOE6QAYD79tG}CowD|m zoU5S?<;nb0O@jlB#YT*0rJH#-=8oUC#W$*OLVDl!I;{)H8Va1%GaowUlwzz9Z2Rk% z5yx=zr+q%dq@#KflM%&iTU+5jN=^J+LG}naDGRbcC!_Ei3ND9!6vO1QOPrTxNT-pz z?3K=e#~zbIjA3)kD_Qk+=o*$E>h7B9yl}#tK*=4dKV26Hb{gqZy;72ue#@9gZ|}O7 zbW&WAQbvZaMgEL{cb$G`XTn-j?8lVvZxiAl7(JQqXtQ_%L&9ad3o1^2xZmTgO*Zv;pG(NWADguw@v+B%c=vBz2l+t%grTFPKqb|zMsI`Ict?E z=^+HJ5sgtVhUe%M%gU6RUo;*!r@7O7N*t2CL=DE~`Qi{seEha5Dn%;ZwWQ-?1&!=w zq!JB`kHZ$en3&bO8@oyW-F|CD0n3Oi7Lz1T(y%Xq%b&yxmvjVcX?1(*f6=`fs9N zb%O1GhnU!Z?zID-PO{OPWJAX9^g9g96Fa$uIP0H-aAt;oye#0i#W(E{P@wu<*g*L* zR^Mhvv}~I-hplFD=c`Yb^yO91!X$*@^~{%esP>)(t1)t-k*Yw?atvH#L`uw^&#t6Lts(AET9OO(0@(2VweSaP2m%!@7oGz zrqk;be=?r(MKX3fpHK5`Ue}O`=GK|57?7I5&l{Y+&i}euN@a|1&rRRVZd=ePYFfP$ z(I{PeB}Y)3b%T}^r4X#jLBDQJTfQKHfm=D}p{&I~vh{oxL1oM!6S4{~?AhtQhU2Wn z87je4KOyD%RQG!gLJFy^V)GQriht?it#3#)RGWS*1XnLOMw=l2h6<>yxzq53Nm8kK z!oWU*(fn9_bmx}SnehznGHc$HWZpbizuhW}fS6NC_nFCVL%dey_s(@L4amNp8z!OC zjg~~CtivrS&*UmI+hQMe=8*VcrmJJPo>8cBO52O`Gx1+de#8<9Jc^r4(&zU}+f>nI zs|Q#m6;rBmZgsBv9HZ;jmn2Ed!5p zv&Z`6U4=ztnx9NY4g@K6>{;h@D4!^^TVgfMj(PV*RQ`R?#Re8LL|Lf5mk70yQ{(!@ zT+ZBG;YSDWQ+K{@RQDfOC(=ZW6LtfOJOSf)?@x3&FerKZx({B^g}5KU9iC~MUHOK} z-br~z=)_Q*Rpq%}>*7#h_9ZrG`zkD(596)vdM43#ooM%}Zi@(`o1B-TRavMhU9sX1 z9gaK`!%DpsXPObRI<8F`OwBUE^tay_$17r9tfj6xSNff_I_!ZT+eodo>^9&_{|O7$ z+#y4k6wADJS*R@Qy%6pF>Og%W*FMU0w7G1Zm6S4QgNSf-b zr-{$?r4V^V8+p3i$>-FsTPE$A&$N3vRm5UZf9C3UZp{ zK`SDA7zD}MO;hfvi$$JLS;A$Wh_W~>qUP3}I?>JrcerObPTEi$q5uzVKP*}MZHE_U7$-A7M zmyl^WHb9+Ph4#6}CRsU>hSKY9M1dEMb@TkJZ#okhZVj!$UK~{0yL|^o@q^f5IUSI~ z!-Lf%m%`@=`gq9$+LyiY^ic6ZvFkaNQI@@n5Tc+jmkjH?=MGAY=hG(nM(xFv=P(cf zVH2Vs=+YT6g|ro5HKy~bNrhdBpBv&Knv7sEi$xm30lx0b{Ove>P4fUh$sRh-wigv+ zPM_bm&u6X53W#eXN)6#I>@jE3o4o7Zu{{WP zy);-DJwoZ{e0?;WH>B7+9Leio&v4l--`+Xw)|E2(OoWEFD>7*3S(<0sf@XNSZr|Jy zLE_fyOY`Q(XLaZJ#FE$0ZCXXbzIMrh^k}X*sv8*AN&v9dopq z`Tc%dRGng|Fkcq+f8Q7p*h$Jy994FCxk>RG%8|sS)EBq9rq5%BH!Nhu|00EcoE^?A4y<{srU>9nsRvt1_tK=!wA3)C{2fWVN?{s$&RL+$8hH!vUs&}?* zN3~41byuAprapSxz?QeS9-=N4^KnX=C8vv+6vkA$*+I&23;adk)rRmZhGAl3j76@* z8bXC#sO=jpJc3^pdj&epwXd@^NRIvUVr0xE?}#DFCeO$%<0To@%j!SP60kGTYa3aO z=O9Dix~lASk%Xn{)`j^T?xeCcJff;@rbx>22v1$YzRmaEm;I(A=l=P|s?c5W>esz# zQL~xhzSOgcI&GW`8l0!E@e0T}X!#}G5Zls5>)tqupXNwE_}lr?J6$(U zLsVCKZ!IBP*k;%GTv*@V?I;-R51!|{kD$6lmZoBq;grfYD zANGv(TErfYzsTb}sDsd{?c3nnC}`96Fi(lerAuI%-vGS~ai*J1 z(gar<+0gfoJz^NwO1UlO=Je}a2PPd{ohtM?)lDY%Xq1hMJeam11R*uBnTL)KEM>O zVPo}d`XE1PKYO1%!P0gW=O5yvqfvJFIv4>@fzjX8Qa2~G@d-iubvb31U*}0a!t;3 zxa2!2809Sq%JpnfD))dis)w7DXBE4<;8kSf$-a5TQO}fWq(1RFjMs+lz}T0%CgfIZ zj;+FekMXTX*6Pk2XL6(6rbH-HZj{4iqkWDy1zAzwX1uQ~TQFjLe@y7m;q0q!$>dF) z`<)lYGE#L;w7`y3Mo9*4+7Ox&b=&T&hpy>6ekoCt_DD~REjRTG`t^#GPmTtt44WJk zTR&LS=nLi&RTIB$vUDne`(`aCS3C_7&ePP|wOvdo9X|E_5~x8adF~mfG%ZW5q;ne$ z-FIT)@6n}AJuUSX_@bEqOGAh4$pJdse!Ar1cwsLIIlH`t zMV^k&5`|NDShKp#26Q>|EhLqiEhSst^v_RaK4F!$D1!Tb{8~rMHXNj7?4M5_TU_pT zt1duiPj21f;Df+0t0@XZR76>mX6gsxQ*E94a@U^jdgDcG)_mP=TckgA zL7RM`>0FjmuwQuXHjof?>yMFTL?FwM^vPp#f4~_dj>F@~v)VU? zk?^L2f2^(+VZl5_#(I%iQui{%Ddg0ck)=V^V#m*w|Eta$qowz=5$i~cuGbrH*En>o z?mxb1a^W_mpDb3dSeKtkYe&GreUh4(q*ax@itfVGe8YRr2-|*AROMNso>(rh|BIX+ z0MJGddXx($oLmXzFY^3}8VgViqfZSF!8N1RztTm#5gl_vVQAUU=v+@EcY~2f&7W-j zS~nlXhIgKLztS);rr~wRlIom51g1RV>1XcYsNY|o<++<6 zzjf*v@*b3AZBht^aI?V%z4j9nj zO2GPaS0}1Ut9#{NB!n5toPfGPorY0eeB7daM3mH#?$2VR9yOl-aKVP=2Yu! zYlb@hi!hBU&Wqa*hD6Dz#53Hy&ku|eG@ksT*1#G17Lmpc6KISLM|m#FBYSxUmVK_J zWcwOUF{_@Z0&Fd=Xbk`PKY!P_lq`n<5 zWG`Z;Ht4R<&XwpG(v;l=Y7Dw)7hy*{hE$n9s6yaQ9&jAqYx!o;^+ml!F^?a7u%}#Q zE2|i;nb#wt+=Z*ZncjK!*3k4TKF`uw!gzT#^n1oD=c%-<9qTJT>#JYr4av?a!6iYm z`<+w*mNs!vqp->bVu7reZsTbxjY^U4AQsNw(MuL^6Gr`lY`UCzTuK{$89y_)W^B9y z=DEo(ad=}Xy>^TOA{O=<>E69hq{+u`na_<|^?T0`?{m@T%9GVkQ~N0%G&c#|vT3z? zuup|M!Dj^+cAW9NaB#)5bnj|-rYt(j`s>S_Yu_5I+t6Fn;y*1hfPt(>!vuuR?KL!k*&lh|VYnLTEv7 zrzpAZnW}8^ggVDN57yfF>zYTc+^+L=(6522B)CZ(++^_9X?3YgBa$%+vE8kCc?ed5_Zwb! z{f;0M(^{t(J=#OhvU+tV(ehnoi)_8m;GU_gxwRgNus`qGLophOX`>S&O3_<1^+G3k zF3Q@&R-@^bn_7dl1vQP#eXtOC;&y$J=^EyVU36Fw+IuevS93(?5Dv{MwGX4C=Q=fk z8uN3DUxrqUM$}HKp_hVpDzA6=3G58P8I(o=N7lcu0BmShu93~MG(=&WR94ov7Ne1k zd^2~oAv*V%b6+|uE>vm!<(*7V>=TdPSjPV5^P0k z%B(ro{p14PO}-H)GV3YG&Bul9H%d?idjiF8i}mW>0{XAheCrx{E`i%bgtR2Y6(( zDcGfjKe93B`BoyIkQ}ID36ZZbUm2VE?nN;d&~6j|8s;@T2W9NI2ItKsMP$@Bc5q`y zRy(r>&Q2Nx5I%c0i++fZA~er0BB*^nnhR`2l7 zpJznua&y=#f&DonB>zcF2~Fw+ZR5~e9{7E$U3`nn;us8iwoYk@P=(@Dhr%9bJ&hAl4IQvDP_a^TVtZLPqT!3d^X0b24w>Ed{ z-qs9T6e3NSo6%Q&`4eu?$>S>EsEUs^lrOK2I<3Eq>G@iWuo_2OGnyOmVLnM-= zvX;nMbkmELY7r)j{@kH-g4@6bsm_BOWWspuk)VsU1$GF zGJDUOwPwxC&dj~m{S2=()?xY=*8BVFbF;<XdB(3I?8Yw9!V zq%?agsX-wa_K0EEq9R|Ya9=iTAY!zi7pFS%2H=ejGQgqFTiugBKZ&#+I&v%)+bo%-2p2p|qaS zDGapr85xkpX&-$pM%mLy?Ra)a@2*juT)$(9U=iOPhKqaAryR%H;;Zz_s{YQJ8!kK# zI-7tw3y#07Pm5iK4DHhi`_>bg^n{htsm8~)y*FSmc2JCaVcxc~f2$#$n{<<%uPo2g z_`>zcfRjA==B1U_*P}VxNQXN97>-EsmA24E*N;{|0pLmFeEt1QyYFV= z-_~WtHW9fY5~2($q+^GPQ623!a(*02%~SYg!@@=-FiP41KU&AV2s(BIfXuszo!j zYGyUXF(K9yST(RZwZY#2BlTS8CsT>p1G*ZYDMQ!K<{a`{PKfE@1X4R6=C_4uRGpT} z>O1I@s~ipIq1Qg&M{{dq9@p$PsFg089+y2Y*~uC;TB}s`%G$j%TavckP~Wzc(U(P- z1!WzWtRdA`T5RW*2yCpw+GusQ_&qw{_0A~@u_zMw#G3PoXF6>JLwJtG6Y zu@3Ne@7v$!8M$F3@Q>~Kf3d=yEl{Tra&{A*`yAyla^;0w{BVX@>e8Tjt`}is1zuNn z&m|g4d1sKb%lK9qaai}`YX;su1Ifg=I`V4*Wm?90o5U;KkeXDq6=Rd~YtKbywlpgP z28!%m(1CvnR!zn!0$0D`Et5uThomy>Cgbkxg8tE&WJ>9uxnu2`m}HQk@I(CVy9+`& z0L{wPO+#-5B@|LcbK%n9Q$DL}fk#6+^7MiA4#N8j@2%Ut@)$i694@X^%OuBp9(%hV zqVLy$j^)Cqr%H%5#k$^FS^Z0oMXgVFJK=FZBV$O#*CC>B8&4Hx4?H|@Y&@hiXO};U zR_p>T5t!*p$Pi7=iNo$`9Nu02iK6AQFH-LzmcGGmuzJ7)iPX*2VCuXh(jG z6G;&0;tFY9VOw|?t`Gz2NmmofvLQ%9;lcwx?AXk0FiEF}@se1HIn1;lqm`!g8Mkgj zU^Flf-CZ}v4)qgyn%%CCuMh^WW%JThr^ou$%Z7t|3F?LlcxAs>iT{-FiMm!O$er7W zSHNEv5O7@7)L!b8SSg}Z0CbQTb4wm3f)sqs405tUO82r7JlAPcIk|l63lOUwIwGH8|Tlk!>{}@h0Gj&*Ut~vT-vi3atDQR<3oAk(h7>^wCQU3AJ$RH(o_myDDt zYiRpOliLG+H4T@i?87Pv;-B+7dkKXk%}Z{^J7oyqZ9M9TkwO8j4+C>|nOUSv`ehSV zT|C2FwsBu{gIedF;k~Sp^PgAyc^8P@R9maKK%>Oq#!l!(j4{1&U=SYJzz_LeZ#O0UsG#t=59R)$5A^=(j7u0PXy9V1W}=YSE^ zB$rx1#Y|S8mm*7PzTdpFbT{Ymxd;LrotckrPgjEN3Quqy<4+7Q-~RFwag{|Ez7CW8 zvRm#NybUL*%s5!`tQEJFUCb~rt`LMysISs#SXAF7MFk=Pyak{db5#k}d%*XC z8h|CWBYT2TuVl75S;Fn7=%|Jyv(A;Awd!gST6XQ05992j%atxk+C;6@-}*UrwC%PD zgI{?h7!rvndus4EHX23plfAtt-%L2*t!3=gXw{p`vxXnBmu8&4>}4#SP>i?@3}iYN zRV!w&SC5&&lbqnP?S7@7e;|UGlX_*rf@s=&$g{^fsc623ERR0}5C^z?O!4JUm7CgiX($GB5&FU48tO=!z5k~%k`fMnhm0}=k)_MyyRx$jaj;e;- z>g&J?=R7og8FUhFcL||H2&_IH@GC1VXUpN&QXGI{d1duy#vr<fVg`{?*vN zi_xoedBZQ7`T<2jS{y@{h65EzLg$ggFAB==RKU-aH-l>BGJA@q4 z5XDMtvU_!T@wy>MNGg?l7wfF6rgmLY*Urh_pciC1E%)v=DQlt-gai_jQFyQVfOod!xQi?zP|lJRS$91>ua6#6N{qX z*eRMKUI~(S>EN=}iahz?EzOXu3QBj2ipSQn9u4!&l2+Kk`AN--pufNyb!q??O+K44clSO2jn{MtY>F(X*3U|Tv;0hN zJc?Sg43H2bbMhvc#goY&ceM`8@ufNGE0d^Es^K#P(V=gRt(m{WJc3)$A-pxlLu6~2 zA{XCFKeP_{(3~Di@q@`axaL}4Jm1If#^ge^-$Ei_SPx4@*x=gaZJ-262kYVxI`ephI+l#}n{igH`BPxDzv3V_730!!C= zF~U)jzO%@K zN>M+lIp8Nf_(h3vtDqCaEY+XyV`IkrcqB=-?mF%iaVB{6)F5HOS-jvhfD&&DGcTto zlzD|AVn1j3eS7yiO9NP#U#-q_etG&FBM|G%jW>0D71(_ty zHK{9al(~Lxg*%t6c_pao@o%G7Bm}=W##oo-`R?}zc6eN`Lcko}PHD}30NaIptL>2E zEp*9DHoeqC(s;K(%ZuO-_+p<+^EgbK=noM_d7J3yLx&=WV(;W>_N+0Usw`4Z6H&*H zzmWO0J;LGef%UM$Ga}(_2&^*phk3*COHkie1u&V(p!~n5F$bLurj%VfF0a z30rU8_3jU|-vsAr$=-g%;*)oCVTM8$@Gp-O=)K^#KY-I>V) z1)^>``Hl2rR9)!00~1(6r$H!pk4~ePHtLu4>R=J(Rs(>5G@w?D-Gnx1FzIhj2G@XuB*= z>*eaRty?&7@w--^sy)H04d4K?6H5SAzcptxVS9Y%+1FJFF92o?_# zn3{P~zBZ~D;YVHIQy#HD(NnQ)i|V;K%=ZmKGP0Mo1td2bwMJVDO_pcDZBvMom32zb zv#a?OL03tq^3rPLi9IcO;-#HeUW>lea4`)KFzR2vjOCZwxNh4&{k5rJ5N#76EGVY` zgVD91Cip$$T9ECQ`X&(tYYe+n4M9~ThlCvOp!Z~}H+*3( zu=zC^sVFTgArxs_2fcGDtOAZ!`uR zBZfVUb!eHT@0lf=lVdesg2d>LR~fqqv)12&UdI&$lI658VbA?MvB_4;U^1r(e^x8`o(Gac-W>2w!Pji;PgZfouf)m6mU=!f#v=aMDTB%o z0wI>Rp7Tb$&y18iCK)O=asQyII7O`li4I1z7^F-w`Zw9Fla39!7b3~3Xi>FK3B zX%z1S_{!Z+;6RVxT11~-#MSo3SoT}2J+I>adB=l_++1rwZ=#RzoCIl|< zZ__*V`E6KZ(+6=(5bICe>8(a%fwL3hS)jGEH^ODZAzi-u0UAE*@01}d3)yA4&{TcNrn%D-1~Iik6cC*~`GF%#+S>zhx+ z%&Y_2vg!9#UF%Et&NLYHNBW8?TdrA33u>&YKAfmR=9AzLMX&V8&oKDrP%FUY+7GM6 zk2X$am7T>))EexvQGLoqj7@FGrXh*X9vO?@=f!wAyaCBz1D^Gku zil1Y=7rqMCU93XHCR9%8iH4rOO&y-H!J|)x#wSiDlqhXu^?~S(UD#dW_%n>9lpL_q zRWMHS^x@%aNkV&2E5BT9&Ff3o&)-7mdkgH<#Gh2!*Njl~>Gg}Na5RS3UD6fpFy^-# zYD4*g%7)LiUUITR{TrSY}1xk=pdcgnNhqu#U@D z{Jo$*68DM)J}D~H9Imz7VQDnEq5>4#sjmpS2Sx8BTb01w+mckn!xZ6DGEHJwc|K!o zZ+=)o3woR*+Bl6+Z65!wukek*YrS@HE6RklHxU$I(>8 zlA(}mKneCjo@qQ1_rfK8t+;7yfV&B3SsgA_J{%0BBPOh8RAqT<{cI*hgTM9Mg$vZd zOyA+(VA_|^z(SFr5bk#TY)Lw)@ss8+w-StRjP}&%GS$sBM9xe4)UOGCEm~mnzR+vU z!%JtmDC-t*V&jc7KG$KNo8nKt@iI(|)l^zeGE8KIJ^A?4z)_)KetS#uDN4YYI9Z9Z z>TV5FA^}x@0c3N84Alq5AdCx4u8onjM@uKP2sU9gf6Df=1&i;9FsC&vui5i8D*FY> zp38tM3B@PSbPVltaS&h!oc<`(ZB7RiI6>s#>Ybt?G}!d#|0Sqj$H<>ZA4Xil7M|q$ z?BZDKJG(CVUc8e_fpWlJ5ER`}-jNM&ua&ER!ZaV6fKtM0@jZlUWwyLKFlxtp`-vzQ z#$9LUNZIg?ZE^>*QX}L>FJOE-76GZRfFEay7zWpiX(N2S4yfdj6wQD z^u*O|?{40MpK$=}kc^b0S;q*P(xzZF8PAq5!!?S27J~yETazcOSK+tugauTi#2Ppa zVuN-y@6X#f#b-*sPH&9gdOOy!Z_Cf$^AcOhvbue2(2Zn% z{mwU{gP5NYTuMVMAv#{jew>kc3AxyP{z<1NUf~)Zo288%0_^LzY~)ZL@FYnu zRa9$tg&jbKHR&wWHqJJEx40o>f{b$>9;zW!YV-Kv1!}FlX|iMSh5`L;vpyD(M}I6%7{+!K&H?G=eq%-ac%Mp zu;dmGQn$%=Q3(<0lE22`wTVMjGbIlt` zWCP6}ffIzbs>N$}Fe3C-`L-k8dz!uiKQwjbU%VXG9Eh`8Z7?RVG{X^3q;*It4X2Lw20Qv`%fvBTo`#o@jf4p} z@)>zWlR!1A`3PX0BC4R6bv0z6(k%nG4AdO*5}XpQj!KF2Ei=Avs(m_RqZkS` zRi9auYC4WlWbVGFZpo+i&g!16oQWi3tF^Rx65m6>=o7r?=-Tb=H&ZY?xd9M9LwA`r z1vzkqL+CukeLtdBbk{t*a-a4hul=jzmV1^19B-H5XZ~e*JFHirCT+_$&g@yz@SQgw z@pmVEW3_HnS}tf!KGKWK?on^G%|p?f%IH>Xt^3N2>WF`he_@u*W4AU?N~kr-@=zZP}a{pMY5e_}10i9GN_ z2?XSukIy|BhPT<=62RqXt@F>#TG+nV3T!>>!Z%o7deEU6)Jw`#OuR$Jw0}LAa zRDGA-0{O0orSmI)V$+;RodOzQEkv`6o42SSKR1NT=>Y76IxacRW^%SIl+wS^;ayb8hNWN=|w6ula2TU7-F*|M_?`5{FE>Qud@*O5ZNMI zIK8o}iV@scms3lrLT3^#C~7)?`wiEAyW8kgHdS9q)Eu0@Y(S@c#$jWy_G#{o`?n~! zN}WT+iP=U4<;iK&xf`mDgHqXhrF@X^GEV^krsz!AyaO2{bsdo2qkK6T0^II7UXb#v zDEV0#sYK(ombSI*W1%Xdld~lxE{rr4&eCnC7_iVIaZOCD)?AdbU-NY;)xt2XErHcU z|NcoSZ5dXN^9l6*^_Iw`B`RFXUk*Pz$C-vK4UfeHvqU&A9&e^ja?4pHoF{3xs-%TC zqx%*kmw1XIq@>a($*j_i4AW(W&x@YE4`!@XWY^H?=KlK`juzA8>r4V3lgfVDwVq>N z*`m?FN}t9~`>!?Sfs4VOxpQcFs>*gnEq$h@Z{;cEsnw~%Y9GAeoQDiMT`J`g(EqMZ z8`;T}DLSCH;6mS4unegbcg|B@>g7k}Tm@7c`QsZF%Z8s+T;mX8u`}2F)b)=^J=PNj zx{>nrRxFW#Su0X`gSCQG1_HGI$0NSkg);jh$JMMDdGP4Rjp z`4#bI4@w4=WXg5zZXm-HG{bgKLAFFQMoUF`i(W))iu5!-g`jbau}Kirr|wIKsPxwZ zr62clm416pa4l5@`i#=5SwMDTKbV7d2}9*Ey2oSsOB4vt-0%FQp?trz%GOY!pgA!L z1F$_6_YyL%WXTX%e|2j)CchlrE&2>VGd>NOa=kR3#z){kW6Q`wWn!fue-w=I=9P009oZW!x_0SC} zu7e;l$8YD7HHJH%yCw61#A3e70&I62a+7}dnG$F>-U;uf zkCtm8pD$I-^y`S9Wu6rD6x3%#ZNElTm$0|&`uBhL`(fP(fJsM z_WZ~G2OQFfua!PJV=?!yH@Fld_1qb6Z54YBsy zDiz8-b09f?>-Cu0Pj$xIb!j{AR}o7NfuJqQsd8`|+n$3y>QX|5H={1@KCJ}cbEHeu zZyXJLO_Q}BTr_sr8noaYVf$6_we;qY>zLVUIfGcXvk|QYvPe8ODC9d=K;zI|1$~AW zy(QXJ|F2{IO$@p)UVs~8iCCnSme$o#VtZ=y)QKoxO3If5pLCsS4KDt9&Wp@)?hXix z^PDK|72oC@Ll$PxQn&m@+wHIP1pZLK^Xc`W+M6xD-+YcsN65FUZp*Q-{cb%FYAN1U zDpY(W2)Rj}w^mp6s;0Ti;ITi+(nRfK#t`lg(`_o48Cxh+75yB=Ql{~OSgy7bs#Fgz z;AS{2qSl)vGxlwDF^?9<&qRY1w8Uk~ZoB9*BCyVx@v7##C>8ME;JI0y zkhaL`{cz`Qs6`Cw71ZHc+0qVFy^4hKRz@0&p+4>WxYh~X?B`hUWJ1~yY+@N-_A3KX z@MrDw&)09G2#1z#TxAE6%pEKqvq87xEXJv*I=2^9Jwlqj+S{VU0$?gC*jw#f`Sv5k zOfe7R`E`Get|^!56-Rm;cu!y7)hi)U1Ml#TigcrSJJVZlsXP-`&85a|g7Wmr{hZ-q zgZbQ)p)~f0F6JwGll!RZ=K>Z07_GZQc6^H-Gws(`al`rcevJ8i)N*L{%40tbQ}D|C zSf_3446)nujoE=&15gL}gVkj`iO;z4Lx@jR67u-aNZ^$3wO@Z4yT1 zCGzZS(BD~ADnWfluistFVy70fJoa=QIa%Dhz6yo3IcPZlw&=cZtwO^+@E-&52tyhRVy)pByb zkN{@es@=~=V9AW98-dKYpuM++M;37XCKai-fLlN#$v7|J0>beOfB0ke)95c4QGN4(&qC{v??T7j zska(~n%0$95y@%x;m(rEzA#B|`B{lGf*wU~fcUWh~mv->)$ zo)vmoZcOGsX&Vw91u7aY{EU&QaS6xBzsSjDX5OCVoyKgH?Qm|T zIt?9cDjlBn0&w6CDpUa-R3fq0(3e`!o*6WO)R+e3! zs%(mxCB?MrjeQ@$S^5Ew34UB1BT#cVfF{j{pe!}z!Hd`elUoaXkKSFYmh$Q*_TI&c zyF?@@0(jqjOLsTO#J+7ccgZP15;XXnK65l*d>le?*E>p=&{|oXJ01sXJ>qn)%X|^D zRHMTBJnJ=j%TMaPBf1|zQle4FL5y}hjO&BciGWj}SX-K4&D-)ic%&%j@c?@=D7$%k z{}z2NC3R@bq9M*a;A2K^7qyXrcUzn}^u_co=+pX9fCO;b&01AP_*S|{9DwVgHepP?x zX&xUS<8G8~{#8pbwsG6#A`ondR}S|GoW`cQFsB~3Y`(iyz^6n3 z*#xd`7dnBNf<1QbH5tvrdu@HUU9QsT{PgY_NV3~){N=2MEPhWpOTR=wf=ntZX2^(Y z{y_Ouk@Vo8Y{?rwI%jNFD)B5Hu+){`9aCs5HsjBxZ)<-P_a{e`g01C{KD}n=O8w2! zw(ZNN$j-GN2M5H3L1sf#e&ne+(f-u8!tNz4(~m`Y=I+ZX&y!cT&Ed&TzugB_q3+$p zBlD3gC-1yMHj1l;98$z~$zD=~i1{^q#mM(DHT-C`**{^A&6~meqVWuuCTje?ViEXM ze^AIz_509O>Gg;8IhE$6xrWI$*hMRN)J8pSoVs~iRdud<|I*mvY*udoeWwImdY!%h z%to(ge*(^)=-Q;DAh?ci-}XS<-3?wY@aip}=`qTMI1o+64Z2z)vOe`bhMK9G{;4Y% zxC>K*YH(!sP?OQlo4bCu_UOHwh70;o=(N z3ZG%6k?9_@txNqkKKb)Z8m!6Jt17_kJr2v?9_EVy0r3G+;*}6!-;7+b1%JA=V7czn zu32s!i{g$D`3&3d$3=>k&+!J711@Vy-5-~=HE{!f#h(l)Hz=a(4`dru}%)Z%{?uN|mYA3s-&jecHgr#?WHa~6D@ly1?Be_HbzHK!cR*qVx1 zS;#8dXT7}tY8BEoHPGT^=yLf~S@B-G;kzcm3WV5xROkbi1h5 zv*$eZgU>6w(?<)u@!jU@;IX3EsQ!IGI`uf`6&+D==&4uVltyOPxf6q)L#d1S(rSoM zYkCiL3qVT}X5lmCkSN8A=hrsE64Zv?7;#>&Bfg_ICD$)9PZWjb_{;11Ba2pA z7C$!l`uqycy{(4se`oUV)k?YxYvl+oEzO!ZJN2ECrZ)n^Zk!4fpTGGQ-#n>1U0-tR z4qjQ{tWU^llXRF`JWy_h6h|#?f}Ikfq8uct?Zo%@}@rS4Jp5}q;v`u_WNGa*_BORKA@q0a)O<*TE( zpL?7EaV?bL2~X%6ds$baN>O{IKc_sfHL@4K87`r^HgYtfr?FfcNu%s6N$E4a2Qm!-CCm7ygGU9_a-G+rx?6xlS( zG&U{VysGQzVY(m$qnoJC;jZ#GIiXJd3FVL>i7wz!`eH_R;DaQz`{J|KB;E?rMTfYo zhy{bWkDmsXQV@GCOR?Esjy@)?yq{av&z@}L!P~dmOip*w8=!zC&v9P2T^Fm89Ps5; zcTczpR&317Y?o7tJb-HRQLi1Z?@sgCih5>wuJwJ-?UbRlP%ZOoOWIGf;=R6dW5z|f z!hC^GbYoL&M`~7x(ApaS^scdKEO*QxNUY-un;V8{6+1 zEl&dQ(RNsDu3CQnG?<&*kyi=6zS-fN8lO5-A;2jjDw_N}MEPgCduwIg$ZjZIMpZ~$ zuz)usX^%T1mj)BqdQSqKq*W~HyqMeC#i$Z1VfB8Jtfr4s%dJ=(JQVXo-?e&LR92dL zX&+VR-L|@vJ47dDiHa}i8pCxL`a;oGMY9^f+o*TV5IrWrONx^*5jhrvi{9UeM?K$k zxHb96f6&MtcKVv$DdQM0c_VzcLUrF57*6#JtL9!LkY*Qv&RmytCl64zo*@M+Eexq< zXcGXkL0Z|$j`%-m9uELSj#=@gD-fTfPuCmraC_+jG#)EZP>wUA*3aEG*_k z-~%a25NWj751}8h$3rKl%a0frc=-qVXb?Zp`5Swi--dsM0MopYsJ9qiFVoQ62Y!@a zUJ<{2uz`9EP3YvRkGr65(xJsM?iir8K{bYVZdH68!MyN+aUZ-~nBcK=xr60FW_|;0 zS-Q5ft)R(oUKrRo=ko*cCld?6s>EcDk#Yecg9fkJy8XfH_E`Qmf?7fp-jnxCL_!&4 z+h77=w?=O9Qs{ka>Q_fu?1&SgI@=e+o`Eo@c6aBRS8e*AToUdxPhOsFOfVA()rYAS z`mp!Bv4pAE&Hnb$S#&aEoDx327r0jx9pGp?d+==}^0DOYfOMT}$y*y1n^_AQYdz&V zg8t0TA?|N?&`tJCeSE@Ee+!k%U@{03apU|*SYoSLd5XAqS)4DS0x3YVP;F>n$+`nW zWejm^F*NlOhs6L=>cUlwuCf zj->8)8NbPYEF~Eg49h!%@7+4yeI|yl*EK4kdge^X&^6p>sK#r59*It_?ugoQ zfPkQO*5g(6%4psjgPG|aVG8L%Ov$j1@e%+}ALM7Gc)m3*df~j;N90|-E(>niQ3>@( zUN`AvN%M7`R4(rKlc8zK*vGWlk+C~S< zudv8wx-9LYX_T1Osc-44-r098$=FY@+7f-3_1RJm+tnKefrF|mtzzwG3-~@BXWOVx zTSi!&z9`fI>sXFi3%ots!`$Au={%X{!v$=x?@vKQsk3J;ob>5I*=(KLUcaaRmDQWT zM>y$POlVQmyZt|2}DLa4)e& zD=Kwg5g|=fXUgB=)5mkQf6H<4#<1g1218{&f^Q_V>69sb3%U%Nsge9EW4^|1&uee` z#lJh+(yTzxLuyLpvu~QYH+`MjJWoGW%quM&qU((FKM+~9 zULUi`r%t@%N>XEK-BX?>8K-)N%9Sed#3A7rw#iEJGquYmm+(;krG&^Bv;u;cC~{0j_Pkj; z#XHZ8#?i=WP)|ra$Mr_`tGl(1t{%0t-}^^$!J2XYPyo=r7uZEm%Fp_0hBE#RygQ&f zV3+DfB{hEV{ByN&YcU)v^iARd+va?>3w5Wyeey(@*uaYir#9e)hinjQigMCW7)v z84?1#K=Z!N>ieZndR;Aee;bt};88JmC4=OYtMbxqxYt>|OjnlrYZCQK0JvS9qJ!4+ zBzFFOBg6hs?GIbY4-#<%rJ9x`8Bx)?aj3|npROVJLx*jT!7cMYG++F=KQ1EU80Y&}o+!>cDuT;xe_w1=9$S>F zG!z2BXJSIR7#ndv9|9wyd5Qm!DoCuMVBEPUHaPS(g4yV;Ua*pHsNB^kmB_ddJ5JC= z&bR%$#FyI9YiYS2+hwf?j{L{So;@6QUQ3DlcvTq;#xMaz+{v&Zz z4gekubq&Q=IG_(OIpz8%P>LRPTHL*bOCMz4hV8@KKSA`*VP)izb~aGqi03iuDNUnD z%>QUFfWpX}65pCUxj4T1L>gY6hWXc69r&Qu4dv3{x-IAroj@h!mw$8&b2&$CWr&Jk z&=)RlJp@{x^8FK;SFMWdPDyJznvD9P(_MT2N5L?US^)TB-8cweN+$b<&OauDDFj-b-ok&0l`hi=^Ac%TC4{#e2; zSOsa!x@AHZFx5(ZiTST}^O&i}yp3}MoR35y9 zn7sZ@s}Gz%UmP17RHpkroMHI4z)BqcLtu{8en>~)pV7(5q6=Iq&gX8` z%6$y}$Nlgrinhgvoy3c#`x*OVgP89Pl$b4l=F)c~vn@W3`6MRVG;6)QT>k|2&H|Qx zl2T%zP)WEVB$wam|8*dS;7+^UEU&aO3fko5q4^_{CB5m};k!T6BDPR*vVDC~lsz)# zhmNYO!QYwvoyxv(tMB08)a8J4w(h8EN|5q}0;;3IETMnzmbrE13j@@xv?=)Wu0 zC&2&!c*#2C^UQ_Ra&dY&-#_a@Fg+>^Rt`EsK6@-@ej-&DbeCLd=Rnm$Ml>?O-=W!k zvC|Y#o)s|^^{1PEWbm~3l(z8_y>&}4dsv?1ydU!RUw^tZCYLX>XuNEuOgZ{bSJaOK zmQ1y9q$@W1{zu9EiNJ+^e@3#1{YR$qz?0bOsP7X&)_JJD9PRvX^S(+)fwsGW*t}V;eaD}4Mn&8u zza{_C8#_Xa)g-8>dkOo0j4V)ySyZ z|9L8tb~Jb5(JfiZQBgsT$bX!m%%o@un|FcdP`Xb$zvD2%Ob8|F-xa2Rk1qdQ4E}%P zYvQ5hr2Q{n(?4n^H4_&UYm*%&@IN2^{>p`-PI_zaL2H1zos*WEn~#H^pNo(8HLc)l zj@JSLTmpi$Mwmcd4Hq*9S}tAzeva3iT)h0em_WV1KXG%v=H=kz5#-_LL@_{FeYCQ( z_;0mpCRTPX|NWwD;^JiWR|*F|FDL5yD~_G>zu&mHcsO_jcm=rmX$3g>I9~Je@d@($ zkqk0(ws& z;F5q1;g%r3=+=Can$hInH(tn{@uQQ2yKRo_yCi{ojH}3->l3+TaIARD(p{)qY@0a2 z+3zq8aLc$jX*L`tMlBwr#`E}PsEt1#76MLEGi~D~vVi+pv8mf)F0Fj!D5ZZBX7&rxv|-kYuo(*vxDPH_4uJ<3xzeO!QiP?9Q&C3)mQG{==aS?Jn~c_e#^*F8FX z8`kpbpi1KOTTEzKgZRLgyx;iU(c6snR1ce}01a^rut6(qWf>CEk*1hW?!Su%@V@m3NRY@ZaC_n+TQ%m zB{#PcFA$m&+Ko%gWsIu~#OGK*qx9ex@Ge%bHj=+qD*vh`0mU)U*`X+it~26h1}Jva ze(1V+ml6D$zir&$Ga`JsBJ^7=BHp_uYo5i?G44r2luu-#i81_rv1P3q#x730Yz1yz zG$aD=`4WG9-Ws0=|01yk(VG_M9wG{s5*yzS(zfbAy{C2$MTs`LyP&B}ZK>*7Tk%4_ zo(}T<9u0`^SRa+_o1rFC`J{NR9VVK=T2=I(e@tiPeR|##{3@K;1maA04;RaFlYV}O zvcXnv{c8P$BGO2=L6g8~Ij;|fA0X1{4q>%VsYjK<09Yh@aMX#My&_JI@-hQFs#-v& zlEpRBwET0{6u}!>16(a5kz!X{tLYN&q%F9+Q%S1OVxV$L>M&2ynY)L3HTn6wB zU_Cy9CA!Dm`WeJ+ssi52$$*#k^AXWD$K9pKXy1=Gr7O|oW~K@P&0J_9XJfBO)E=!V zG>u!PKcC#i32?>?`blYHNYF9bRZG;rNex#rLrW4-138~XtJ+Qy67F-uO(`V`(ocsLG>#;PYHG2D0EKz;=9k%&mY2Q;H{AZ;;dRusN0c)BS9ABKW!2eR8=|06&K$yq7k=>OUkVEHI&9)VY6r$M}cUtn?o0Z*@4nbRgQw{OI`%k!A)=&1*Wc3vPhb4 zZ+GuZIT76Rw<4eVLecw{Z|2`wHwRX2tvF%Nt(!0-eDAwQGMmoul$@;b-PSbQH(fn` ze$27_ABPm#?OygYXOUy&jiseA1K0Na=5%Awu=rth^#^>MPcN;USpdIjxLWm0!JxsT z8)^e`kCcZv%X;nKI~AN7}L2TX5+Yl4I=}# zlw3dBlCwRe*}eW=G1+ywSF3lecian6Q~&tBqWq^%#=epK{N({luSSpk=-Aj_wsd*( z%9Z##{i5a#J~2p~yPqExFmp}u4|$8Lhr3TLUbrDB@tw8FONQiZXnB47p`jJK-rCXs z_Rou(TQ~1CBJbXErhYZO?$_%Z3x}>u8TZ82?9Y68AT6nK6FmMyi?(e)-+4xr{ z@77`WT2}0C_5O6gsr~IWWUFaDYRC~;u9qjf;0=>)-P1wBw6-s^9X4XMJgYT6?A8|D zdVDz8JbIiw*AWi`$)m@}v{V;N5!UDtZLz~kE-g_H=8ATODkAJz8mzZwhPL(pPh3_; z!W=(qAH&a@gC2Zrx)4m*=GY$72zbK!*is+U2sIIn>R^s1AE5#UC56TrRcRE4Jw)SF zl}jjNQsE<1TJHn(kOA6Bw3ZR3>PHwgFdx@c+Xxeut372f-N1a35X5KVwOlg{m5)=R z`hakT{0BidF`v$mTyE%ChN;0U?rDe6u>S;+$ftr)OyfH8pU|=YU`oew+tEeWVA@yo z)2W7J=nUl=92BtsblpHY>k`|cn+DR)AQb6hPy^+k!5LmFB<3^P;gdLrq=xfe5(DL~ zWY}KGb!4y9trL!C%%#Cl?n;Slqj0=Z_oKu>zM_z8YEDu}Q#Jpngu|Jl3pGIqqH%;d zj8jw9g>iv=%D6;W!UUnJ51^!p8eb;h2&3r2H7-=SP`*^HH%{O%s;&jdLHiM1Q{{3v z+9EzmOvDE#JWMk1<+rfv^eHSKP!HCNzrd04UK_{e)%+RX;&+oeRQ{ z9Z=E84na)R0|ce0rwA(G0PmUig5ug2j1a`fI8kFR;95b=alv7KRff({{=p3b)&<%J z+D|v}S`dq57zEXV0C-X3D-4cmP#8L@L17pOUxZ;2Bv)!EPvM>fVTq8;L_U?mx-{{? zAtB-A*N7%H6*~bYdrifu%rOzkN^L-+?YL(L7MF{a`(fl^hm1ZWc5CN#CjTh*)P zF43STBOlh=UBzsmNul5_(M+bR{sZGwd?sLsnpZ&6r5az# zG_^j6(1=>AK;uNgIwB~-SfKI$_E1-bBXM3rhM#pYH#spop=}_yN2jH^Y~WGrnsH3( foHQFC(t}}tzRQu}YMb3*Cn33CXlTSMk$(RI=GNdS literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf b/lib/openzeppelin-contracts/audits/2022-10-ERC4626.pdf new file mode 100644 index 0000000000000000000000000000000000000000..154fe75212e317a87cfa249b9101a04e789281bd GIT binary patch literal 204184 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 P3ADOAJw3B!^LYOO&o2YP literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts/audits/2023-05-v4.9.pdf b/lib/openzeppelin-contracts/audits/2023-05-v4.9.pdf new file mode 100644 index 0000000000000000000000000000000000000000..21cd7f59307483e93957a3b2c94aa11c0efe40ec GIT binary patch literal 485395 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

DA5c*CxgHUhhcBZ>@bV^8E) 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 z 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

O=UN>c$5c zYIFc`{xKyVf+&jwa~7$}^v6+!e^^1#IjPJPnwdUh1W4XuadTC;`I5zVd4O!M#^H9? zcpZ8>U4xO<`Z3HmEBQqS=>&NoA1DUbY(N%6D`Z3z#X&q7^Zk%@p?r?w_DrsLncHt% zKD@dvue)9C%-E`4zo`KL0_gHgeff`wGyXS-GqEzV(@Ggxn>d=%VDYkb&23a}v#?^P@qG^~ad$l?!T z_A=%Su4YmZ`v;SHLOp&ICKag;$ z-4NOpjtp%&8Hs$}K*burmpuZjKouTBra0%G2SMM*obTwV7=7FQUE!E~AtHYI^9BTQ z|L^M>jVoqhE*$7DFg#C|AT}RUFFyb$z>JBV{9%K^l(nldXe`jzh^@=g9@y#f3}!GE zfW`FLdmn&;_71>5Kt3Ek_+Ai>pPmaA$Cp2;KypyAHA@f|XW2o3lM7W5{R~q%f02*O zz=h;#$N5d<5X^<=(pjWyR5Z3TkVyd}0ZM}qjz_RB5!~^hWT9hm>;-6Y*SHR&Jm(aU z0|{p-5+j!_m}<=_CS^pc={WI>zX&w^^;l4g%$a`mIaOWw!NEV!uNQx|Op#|m{IJ2J zfNkgf2zng>&;T&&ssR?i5B?mV^+NvR@nzj|0O;nh1-J!MgWR1QVFNCRMtu?vjNYce zp#lg6@%@VG1W@?13@`~~~wj`r66&B)aO$jOM{iv4QG`j(JnUKbS=32nmAte{w6 z2hZN&b_l>LpmZpE*;_e0-BGLf1z}(9?^wZ$-y^?W%bJFHDRlrZsSdGSkzUb1U6>(a zoOw)|LhcH{(~`^6&$v}cQ+yy57(d3c8i)X4Hey>GHyOnZ2IvyG#57Mr7jmc$&C+B z%OQ?xMZ5D1UNCbvcYjYE13Hd$RI}#-yL2g6xz4ZRrP7VV6pTHkgYY=ZO@xF6Ww@+B zg&JmYSIMJ5)^{%>P+Ot4G&gzlMw!BOW>(A&XAfHfpgoCDA3VfBCCH)Pv>%|68w-v_ z2Ue+sp-R3wfo$mSTGC%T5bB>~X;fUSfX0d=N@ao@zI5W5nZlX*%C3&<*1&Mp8l!!hm)ab1 zqXK;Wg7nCgP+n(Xjk{q>#`Ras(oO!{{$#gUThVHFGW3_e?UXH+kCAi#XI>V8fV$S} z>lR%{=`@4v+Anfae9h6r<8)$XNoVxT(xV8(P;+3RAp_zDqNTR8hPI0mV&eFwOxI_z zT(J%{Ui-&n!`MpFo45se3@!2PMNt39rJ6;5sJcRxx~vW$Vgt?m`48Y~xN)*zB~GFF=o(IzgR0&U!G(SF2dN`rQ6=`Vv%Knpce}LNVTw=J z-tpvwV8IC=w6FH90>k2mF`&XFV*w6590dA8Mh^g*1Ps*@0V1O?flW3x?KGe=E*eHu znUqNNzUSak`zfsx%=fOmL}4q>t_90kJy1{pXPN@2K&*Ylmt06SbTY3Gz_GZa8;BTU z<9@2UpKKoQ9}ThbPE;4#zrCBD7+=pk7--q6cOEa8q;JTw zSPchfdQh`$XM0Y3<%6lhC{YqX%^Xf`{JN~jG?&|i>b;~PrA~;{n3Is^XzN?kk|fMd zcF59Tw!6srfih(X=hhxPl}Ww6Wt?(qy~hQyI?ls&U*1R5$@ti-Sc2MBYO_{z7$=w4p-m48*c`+LMGy_^5T$7j7M&Bb23S8?2iTTKZsLt z{=3_BS_r-Np>kmU7?z27bIE@I7SN_bSb{RK|DdPiHv0=0ZgsfQADi@offG+mcU zhbaI``igM#ft7Pvnwx`WtOSct8A^Er!OH)3Rt(hS7Y!G5A3h1n`t<{=&d?r|vAgPG z#A=~05h?K$h_~gp%50aKeK_+F#iK(w|G-l*BvFi!0q8*S-?G%pjUuQ`PD^vPf#dbI zw0bLqs%#V3FalG(?!i`7xZTb;qL zFRz;TAnA$oh>qThK*e6i#5N+!*4Ca4A(H~RcG`7PosF9@AUt=xBd1Z7x@113v~A%Q znoGcCgQ0^2WbgP#Ld<7iKn_*CD9r8}9~~k?-IAF+EsL>N_!xPFg)NOUrOBaLTm^Y+ zE&bLx5t}x0El(1auEt2l;hr3FlwsuPdX-=DkvR~xjO8~05<8;f!J@t(XH=9*x2L+q z2wujsLqq4GU$b>5X99WHZkklDW)2-;)~J#d+25@?yzBoE$ZjP*zL$xmHmOnOy(`02 zXM$3Wslkl|Rh?1z;IzO--x&nWmhhO1f7=RodOC(8zzxdGkp1aM>A_GbRJ>plt_I1$ ztLsM>^5AgQ<&Q+9+hbnfk|$<%tqpy@SbGRzHp~WWas@c=+HmNX688Cg;A!AQkxS^AWK zwS%=@2~a}Hr?CFdl@mDu&Y9I05wud5fS$CIp$m(m6%9s*^~4_cxroQdw~cw7pu6j0 zRYC$1V5M>TSV3kTa$(~)pxYx$;Mlwv*0U~rfCi^1R1W1#jfA&2TgbmI9nl=vdY(%Pd! z%_L2FMq?u(yNFh~u&ksuZ@iJKQjD?2@)SDJHiYfw3BvXCMa>}6^WfFi@+lSiTSpg1dk`Y=Ptcy zcOFe!tjf+ki-|dGI!ipnd)iaU!?X=pY@EMq&h=$zaxTtTPYGfVKyWb+-(=ym6*an6 z`7=AsMtR+83-Wy#yjB9cpl$jZQCS0#EY#fRgYgS2Ta%MOYR@l+c1iqL%VT^nF40zJ zo)e7kTML0h47%du*KKI5$a+d@v^}aEC~><;U2v3Q0s|eydk0cyf|yE$W{P>&c<+gt zr#3s|H<3_0A;&0GUBE?^Kt*+Ubi}JoDz)*>8@Q<6 zQ<#T_K3P@y3V@9c|Dfm8Bi!M7fz;bd><{xbSI=9x- zy^Hk-&0n9V<8`@{j$nqdlCZdh`u$+c;_K9+N$1{)AZ7DH)OFs{hl+8ZAxtpfc;Gqbik%gj_bri{z8*L;7B zb*`Y|ZdNXAVW@nKZM|J}k*Kqgyr=Ydv}1%Zw5YlB(;MOW2MKzfzOP@wx?T-jUWISN zDTgv2?oUgmp=o|w@Nk~~5i8fZiUj1e?gHuutb%c>0<(-W7c%@W;2neQh}g~SN6Wqm z!S+54G=!cy-p*kOf;?yQ~*z z4!(}mUjx4TTiD*~AhAmTOCGGS*V2^HSL7K5ay6ou!ImxK9s-{&LM!!ct&i;ju-mB! zHu5L%wv&sVLgS-!IT}9YnPL2`4}hlJ=P9rUJmtaF1SiA_Z|w%DisI9r76Am=CW29_46Li=#*fxC`tuaofG9ES zrh{1Q`&u(pHUNG~?P5*LaLbYfmI#nj1u0_y_;E}!)8*XyR5!a@d$G|v!A3H=iEHsW zlgD!ln#7Ld!;GAm-s+Yy-|82xiOKe(d2=5B6y(j_?lio;)f_Lm-2MEpS+P2wMu&7$ zD@Mx04}soJ!ea)f7V0vN40s?$fxrJGlAB^`;pFNaLhB6TcP08L=D@6g%+j6i&5RIk zd7bk9D#K&`Bd^8u-|<>Z|BJ~I3)4!R`k%`2z#I2)c5B!Ork-^W1MrLpxHkeBT)uP+ zH;_8w;rl+DoVad1AcRplM;B$)7R{%Pvk5ayRrw#W2Hp{6=mTVh&Z(Efg3|+|Oo}og z^e>Is?~9r(g{8LF&(^9t_w?X44s4+>Mlc%-_t26Vz3YRL^6zW`sRKs@*`A&0-?mW` z_hdQ;jp4-{xWb`=r0?t0JM9+8Pdd+@knB9wF(+CNvc>Qv?6-2XJ;3*tbcf;>P*3;>P#LubOuNYf_k z{2r%4xr4F?ur6b_eC2I;2i$v27j#T4<75nN2HT z6wV^wh#Yj+uTAau2a5m;0#oG5&6SU})Mzl9a+F@fOS3uykx^x{tBBBau2`$epO!26 z?YvdJ+M#!Y=+iEh?RH*I&t|nJw1w=%Af3jAyMAv2lWWbJYLBsTW{LJ~m-3yhz%%y6 zSi7_D9CU!p+l@TYX{o&Nq3ZhwpfnwV{69_*=Kp4bFtD-H|DQ{^Rm~iggi*h(mFJ}a z1mO{h{T#sv{tBoFf@c^Tu!a#3)Q389NV_D+u##>O;}h0H64r+jLWbu;hq77w`t!5s zWy-VL;h=2dh+u1}QQX=xymT4IFc?!rts0Ww4u-ZvI6dRR$V(URujbF zP2nrv{Z{&>&N#2QW4#i>{HWQrqZCsGDW0CH=q%dmWsJRV<+=0d(DbTU$uYj+4ZM~v z8T@O9=q?A?*Uw__kpKbjFpE>CpSVX}D90dY*hwHy@`iWX+}67Y1arz z5A`I^QC|tL;*iMP*LLWf*#bxjGxTt&sO#4)Zyb4$-cQ)dJr}BIgT!G^yNVhr^fc5g zL`%f!&PgRihV8U!UuPvCdLFFxN{6zrHV;Flb^G9%@s<*dT$qp7GVZnri51hTz7Rru zZ8R_t!#r3%e9GSHY|9YJ{Mv7Uf*JIF#iXssZ|9b-5FiUQ8+&k4cdyw#b@g z(t(SucqTiuEPSJtt}{Dx&x_NP9iIyEB44kK4Eo1Fu9(hzJ&<4G0OQ@qnNvLYV{t=Q*iJ|omGG*OgX2cMLsecoG%rL#!;k`3@Tq}cn*X3~CifX*-_RY$< zW8h+j@!hS`hrknGuO*|*1L3%ao4G&u($}uN(EEJx&qhOMRfy6Ie|O6eQyeA zAYl1-5NRkuqn&w)V%$YC97BiOi`3cq5zv?-=w`&-IH9%!>XcM*$Q{*zdJY{>wCBE zmfMgmTLwa>5aP1cAt!g3`Zi+j?;M>nx~I7B{t3!h=}QD>W0mwm%s;W&RJQ)nk=0Cq@L@*1QBE?w#7{Ps!$5ZKhrOza9WDSDe9~Mu| zJ40B#Plmd=8a0~>k2+BuGCmK%9&OI8Sv0&WIxTvoq8afCD3$a6%I?)R=a1&vGaP#q zAAuEBX5?jGl}8IzEIl6Ov}5U4cWP04n3Q0brP;@&Vhq)66?Q{+TT3vWBy$4CQ2y71 zT+(XLTH=kVule~TyI3d|d@t~bekS}cfHMfxKso@_WRJue>{PZe&o;tuElnhoXzO%$R!#~m4E>@rnNz` z2I!)!1N@8s&bQB<)w}B@J|b3vjrZr}4=Z5IpCO?f@I+r8uxS5o{7QdVMO|@Fee8tC zCLxSD@vyqU89rWsoB$a=gg}{##i(fj7og6!E22|N&0xLT?P?$vfGgh#Up9T?JfJgT z9Bd4G^lglYxnQ$w*g|NDP<$ym@EN{;bm)!fzIEVIY4G@<#&kB5ET>DzbS?ZOXRT-R zF%Tpdd}M2?Yz{b#7eaIw&IOu)_2mvy!fLRC=v8y232yjp#iM^s% z635=$ulP@c%AUsVcL--wqC^m5petg69ArEJidkcsgiv4XRY2_5eXY@glgER{gfR`Q zfqPEqCZ@n92FS*@8YcVBll?f8^VfselS5pfn;>eT9j;ChZU@P?vN8_6rfNLy4gK+T1i&r_8y|4wbnj03hn+$7c+8Vs z2-Zk|PAfW==;*Io0M$QxIbxf{A^S!uy>vQ}F{sMk!u(WDoQA2g#!`lHrr~mg~vP2k0GSZYnpQ;~m znDP*#jCzri$PJgrf~}7o^HRJ7c2fcQ=NVb27!Ep04Q;o4{xKNTDf4uOhR$+)8k5ax zR#Y`i&Kst(Z1VDgmI(?FRi7$(j)yH@o@MBi_62(z8~+J*YVYdxa*{OfvumB2W!v7a=M5Ez}x)X^BZm-csRVGl&%!i6+yg@^7V^RSFwz^-t++rygz7IYg=D zA{asCn^qqOo~jJU!O}$sVGTIN?5(n)AqxbG1#ESfzr}MU?dC9)(lIsOh8yp$M%}b}|E7fvfQ*n$- z-q|B?BRUOd;cibn?{ z9hY2Z%Q&50VWiaNXD4ChCYwHYL8d#xIpFlv)G102cq ztvNEt-@4z*2uB(7+a9wCxFDJkW%2+*iR^n8)R)u{ne z@}&u#KT!fwp+BH~kVcvRagEOM->uQ<{}J*eKbvF9ouBZeTT^zXL<%uE3nQtzLcR_vdFqrb`0 zx@`PzxV@Bp4jQ=0GYO}h-ld;;PC1&zj!OYHNoJjecRM7MR^lrLY4aJC&y_$HLY4{j z)07Kv5G;vF<9g-Ldl4FW$%_5z|7`CC>?z3MtaiH@O|xKEhcDJM!FlQ6e5HW`veh2n20WPWu$coSYLjek^n z4*90g)Tbp5vsLOOGUe2a0#=B`6i?|Kwsc91U9p+@xM#$SXI2YTAoIc@?>6hpro(jC z$)>|~+sS51QbtA)I92eUurrp7&Wb%&+JCJO=w$1bZ3YgkJ=!2*1^|vzljueU8>{a5 zlA*Y%NejGfRL4Tpy@vTFllE&9tw|*bzY7dSN$lr*=Ytw!B=5}kTtxlArCZy6abEZ2 zR?j3HOHbIdhlFSh8V@53(u)ao6F}pZt)oy*&P%U+G{qj}# z&%DhQ5BJ4cUe~}qP`lf?x^^Y6PM-Y%cOg@|V4hFJH?q98xXiubEzrXUTGQ_3Suo++ zT&E0ZLofnpPY7OEq~3}*`o|H;_fnL4o47$XJEH!`%m-U*=(Dd5qv(vk1z_{LjHB!D zUZSYHK$k#X(Jn`5W8N6;O6d1v9L9??MH)Nwp^S}W6oC$d`W8sm_?j2#wnY2tBcz*w z{Fbgr)*{#$A&#zc!Ed(xe)_MbEr!JNDUq+Jo_v&CMJPOlDB0`&Wb!F`0Vzxz;1hW` zj#DVLU~cc3U`MtIQO^4*h({s<5kjzbTd5IogD&&wRFj2u$PQw|2#HP!i9GJ~oTapB zg-_fI-*q-(F`N0~-yzkpLWpbIw5u6aJ$N{7i(QR`he46qseGAkLaYx09>j98eZ9Mo zZ$9ssoxpu+Kz-n#qC_GKtI^gJCFsR^glD#L&|c{xpYYnq`As+9-`8C(1XY+usmF5; zM>|n{qkZTXrVkw0?9MNnakwV(%Tgw1nf4*mF>sE8xtvgHZhS1j9GJSHhvfwGx9Wv< z1?SdWbEgdC5BcWSKj>9TPQGdM4wnVhMudIZ*N*Mn)+t*bT4f&1D|?hL?H)3=layJS z=XNDy;t=BGKu6hU+4XNSqII$|GE!2}D|^29QV{(F{Hf&wg+l5rveS3S9~755A(jt` z9TAs23d!*4_!CB3j%{Pl#xA3R&GCL|{6-X>bf^GC26Snj#R>EZ#i`^c#DN7c%H3j( zMMyFEmKVOJgL24JiB?&&7}~e+xFV{Kf-Y)z#K8u@!i+c=j^!+d3YFRY3$CCBbf^b^ zyVuZVS&6~gkW09v^3Ul(K5BF7p8&RpIbG4f?7(mK=%Q=Msd7+izcwcaT7{MhU}ART zI;m|&3S2$1XP{n{bVhgB7O#8K-RWmZcUwxmf)t|^-ys#dHP*u4;l>=Iy0Em9MX#xt zl}V-3lKuvVnc0LV=wF;uGuKG40!fOCZ{oC=y){tgpd1M#d1K~rkur69QU>e>Q}V!I zbRold?TcEl-AT97*v~lI`K|UMM5GhXle#XdiJuuh=WI88Rl4e4Y7uMcPa;u1q(~m5 zq%ZDSr>qN4A`hHDbfcLJ-mRR=R%zhtAWsa%FHtVjBqw_7N9{EB_UJdPQY@SOTd=kO z_t0n5mq}l?)a+8WL>$S4F%OSzE?uE|P=tbH6!yD)AJVaFw7zMJntzKb z=DsMe_{1WvucezMQ;7?j@0lwaCsf@syw9q?nMRH;HiARXHCsBFwpgF7Nj6_E?2cGG zg(~aOU>WrT6+NM{o^3byK@v5Eg zD{n;U$>y#?CvNI!>!;t+#3uz8&0?e0LAbCmClO|};pn{1Wy2?*-=#Dkxt^&InK*K4 zGpICAThrBbIj)b@z_G})r;#%u@K{RZtr&ZEH_9;+UFM%T5l~P_oR%n8C>@OK-W=f2 zIBbP%AQ{>vQY=|pL}y?osX4p_A$g|^(rsbc%0BG9NY>MjnU7H7SkhsUkGoC#wcTW_ z(ok!Xqe5)EVZ%CobzWMmPHFzJ{JmD`UUwS?g7p{OLe)m&AcaRIS|>kad39p`z8>(& z<)V9O1g=KrjpPw`1s7&ohy?||tKF#}W{#6F@E@obRjPdCJz2;u@jH4~N5Y*i7M3K+ z`yb}_kJ8qfr@O~!=7WY<;m6w_YR(ArtuAklZ@_U@Wsv_EjoAL1XvDxm|Gx$M*eUZM zI{2U$w{Z1s8k)HZoeucCO>3>kkaZqDDN+`>1o(sg78~zFR7|nmgG|OW40o(-uqv)u z7n9de+`{?(J#&^31k%hT(j$<-{qNkz`yh1zLDx;yn2FpX0&TEIqR6!MzH5aQbYd}*$1tBssAIE?Eejx zjP&eu|HsIFqzd7vw1n~f?V)STCk7y0iW|#_{Ho0p^ z3S1};f2kjQ3}ZR8?s$jNsTSm=gok`^7UiQXJ&_P`w=Awoi7 zzUxCZ32-s%<3Vd_Iw&hx?Pv6UbBH_1+C=zs_PS})JMv~y0=M=uNzdA6(&cCTTuytZ zV~D@`1&q(4(s`M>FtLnFIO|pKj{OL~wo~sIqfRn3ewqjS?cLF7uCl@NrdCH=^^pmPWb$n%oO0zAAI-(P zYh&sO7r4X5SiBiklDQ6%e7N}E0c7i@3mCJ7j`>Ed0meVCYdWG+WtDq$8#tnr>I}ds zX&UBBPU@Zh#Ml05O&l|UbPBLyvtsyooVfR@@ZI4W6*AldJ%jP_vk{aF0WY6|SW`33PRzPnLD%k;(UJG2W3EG%ZqO9`?$DC; zp{`_8)wZ#|J*P=?X?3*$^i(;lNe5~dDypkBoHyBTifmsmL7y>jd{AXaZ9Qnd-HvsO z#WikiB|xO3H}W0I&E`w=3QcAQOKn($9$p|hDig*OC?W?NRYF-BcpM*6UKV|B#$J`z zamw?K@|B#OE4?VRamwr-v0V~#ip0Txa%wRr{s_;D;2igNUZ{B#4QWV8p41qs6meq+_pX}lFKmRtex+%ge0|3yxyOVMyO8nd9)oCf zig3M>4$0O$nZ+TZTY#qu%TXfOR?~H+c?l)@?Flf~pPmkinKQ_cO*a}cxFcm?0hyGE zE4ZVKFVAF$V8}^l{tYdDp&tBvUDI{wkFGMav$G&8frE*xzB?M5S(NJR8;2EX(~MO3 zx$NJuN~51XI+|(u&bX$<$dJgHmQ<2Dptv3q0!w-85l%7S9m9xT{med)mmhkhuUOxz zZLek=#;&w)uj=YWH5PDYwx(5t0!^Db9W7&nHZ2t+b&}}Jq>V|hjcM1;bo%5mE|p<) z^_`;Zy2bAj)lxi(ed@tMOf;}Ssx)?^wssxEx`t-^R*WWlFOt}WVDvD=SdaQ?AW>h=#ow}V zgZ=CxCR@C51K}8{hhMKYn+WYJCaV&~uJjP~2n|;^lLzZI z78-dH%()INY8kAl+dDczxUic4D;0ix>7-&T8Rf7G|d_@qWYpjV{Bdh3Fz z&^!)yAg42kE&z(5+X<@{vACT?X1o|oMtHVpbTF?da#D_R|2R(JZ~vSc^lwet@`(}$ zus%z^E9FO?whl`5i{>Wu63mj*`OlgKT+d$A*J}ce?rO)FYD^#neXIsdN(bsp1Mong z6z7+bG|ZBR40KAo5w7ppR4-*Rd{1*aZZT2|#h4Z}WqhGp_g1k6MkbgO@#dR>5!e^d zX;~lMSDSvfxvRXA8c8x}S(2<;Ww4V{J0p3gxOl)}Y|2V!q85Avok>}X$Xb_D!3I#_ z)>66mcXQgTEg--XZR8GjGs5W=$>c`5GpL1K*5eL#d&pxF{n@VZg>evfFa_PNh0 zy2YoDj4fQ&F4FJC0eb|((~lOzUv`gadY1}0-HdJEMhsK9zzkYj#sDMSfjs8^Ohkj9 z@=dTUjW<@)l-UQ(;|#|=W!nIJTNKas8g7>VJ$COEzT}M#C$EQ&4zEb|4Bbm4XTc8i zjP_KLL%ihw$7Jpc*u{mS*yWeBrs{FV{ORC}L<-XHR3lAhRH}ie9FpEQKAvg`UD{Wv z6WJui987@Tkd1iQx42UUwGfLJJfce@Z!lyDcmiivh>kBfLU(J!o|w&|d@$^$iajtS z7JYjp8nWnW;z^fouz;7E=w+i znWtF*wGeDHq!yN3ns0QZ7Q`xtSzu_QqSnN!j+zxQH`t`diAbO0YUPoUR`yaNOZu$U zo~euMG479SbmivwFhD72zvj))hwG7Nu@2CVYAQW6=T>o=i#TxV;SrNvm~cvwm{(Np z#eJ|zHgS1TIxGJ!4VqdJE%S`XF2oI8U%0*B5cMeIfe?N2X8GcekXV5mEW;qHtl>Gx zX0g*Ty6fq@9yqUiZ;jD0-E7_VHi?t4{%*=vXq>#C-CxV7KX?ix-pY@e6~$i316|FL zi*DUiukoy{vAf9dNUxs6Mom6d+U!Ci6LrD-Fkl`1TC zi{nN2ON*t)#TE4sk!Uii4`V#Ndve>g{Y2cb>hrpD*&s&pC%XeB>PCwCwvDz$rN#^; z%=_*Y?NzzX&eG3-4jgxU}xowTPk9L|> zu+2aM<(0c`guzs{05e;+(~wkC!HGJGrfC~R=bc%{Jvml~wc^*K-!lJl?|i$jRk84m zyBwVQlT615WyRHpe}{^d37ALeDGK7 zArZEc*ZDy@u1}|3LyO)pc8ke$Wl3koPg9N95245xL-U)V)}c?W#f5CvzrgV02|n{- z^Wk(lUYp$seD;dhH*j6h8NK2GpYV;>wuxQXNu*TrP|E=9uUbMRTk`Li2sN|X3cNZW z$+;h}F;%ag&eWFy%kL7XBaFnCoL82Ej*~$c-c6I^wVhfLns;lg$w9DBSqCjW+bth- zN`}xYAA)DJ`Wt%?_oqGfyKoZkF@5%Ye!I8ni6hpHgVcE@&6k{M z!8#9(|GiHqi=uq>SjmW$_{za-)R1@0cn+nT=5dJo+h+91W7*%H8LRYqksbNfdJIe(tbN%#; zz4&miCU3B&o8=q1!o07T8g8=_ns2jX?Ca&*a)u>6!Q!#ew#ZNRg7pAr{Dim*21pxQ zB?yRWkR{v2%Ca-WP1r#Qf}C2$c(iP%uqP zAZ8q9%0vwL-~doCY7VbujCQMeVeNEDh>5o;VJD!<~`0)sOn-VM9C&BmCtOYhJ z^^KdHUwPy}n1JPfoO%B*qelS&8&}Q$nTfxQI4cbk9X&HEGd?3LD-Am{11mF&Hm!)6 zrK6EOt%#+bqmhu2fsLUNt*E_?lPwn)t)L>Ukdd>Qfsul!0IfK_qrH<6tsqQgVdQy3{p))Q1Ltfg4;h*i z%Pm>CDz)eMYWavE%Kqc?{PxM#PxPFofz<8Cgvb8OfSC5p_W1nyuyA)!bB8c3>%%|2 zX^G&u~1e#!ew9{v-fxzW6uKzWW{w4 zaV^Rr82}JICc+bwNvU?_b_EZ5eOxF>V2Y?KTTj;WTs{5p>Y2Kk3bg23UuK!;P~u;A zmv~B|kqak*>O)zrlkgqj?kC0V2jUr_1qvx=%Neys+gV1qQ z#-C3sus+qmhaU}$E=O1t>WNzftYtW3;fE?m$cZtK7$40*OWIf-sm! z$$ab~G0M~{>ZszTw)yrDn*@e)%0IW<2pbA|D&|o(*;9sdks@hTR$30wECwcYJKWM^ z&xAw%GIkm{C>uN}Y@#xK(wMwaWbeK6YAy{^x`f!#pH9mA`q(hp zLm1Won$Tlc^%c}R3B)%4_0LexTGSWIsLLYi;35%TwJi#bW`;|2msHrW^lWqWN|+gy z$EAs4AK|CG@NsJ@_p$#4tQsD{(r!O=VyeG~#l!+=-Ce5|DnlFRzZqTa7OLLU<~`r= za9h-7=_-zLZ>}ut$a=1)FRb75vp&*`@3ef!hKd{&tFVmJGCCNADk^Ar!czDu2XvpX zC+uHlFR3(r|NC(ksl(u-GZRkghtS&E%D=&A^3HW!U~6 z5gu@|L6KICzy2`3TvFc_afkvWU37_{KT2tY&vS)i>K=(n!w?r#V7SQ5E3(6F!8c>} z4>UOxG%U^{mTev%!yyU*d~FKYex3QB$doy?yfK(j@Du_C`wO<+VZs5!;_;|yr`J>* z{l4{y!D-ZS=mHM_^#4WMTL4wIWa+|a0Y%~N6k52uyF=mbZiN+ga4Fo~-Q6jiD%{-; z?(Q61e(vq*?%OjxZ|1#-KVrp-FTa)h?93B8Ggt1NxzaLf5gep0J!~Bn0jvzXY!6BI znjEC-kJ*EL*l)crLN#WYVOx>%_+nV|_6Y76X;E8CK-u&`LPM54~YVGN#4(1G$f5?cYN3w)XPr zcN<)(M2?iWnUeO&M@3K}mC7nPloNSrt>=M>eP)wwXgijk`d`g$^kB$?ana6j%cT@0 zj~CLbZVRiRCuc|Nj|(1kz2Lt(sBfbluQaVc8$}Io&$o52xL!|7o$F1SRNU?gxBCb^ zb>dcl*I>C@zJc{Beo`11&?fRAbId;J} zf7$8!ft`$H0zn_|G0+mCpoan^m6mMO}vt570n0+W8;ct&yq3Dvsc1ee6n(eMtdn;Y-jxN`b;0NnF$ z1lynx{k`?GAiMArpFt23dRm0|za7;6S5X#N7#aVE@WmA!FyGNt@dS7e)7LzfZ%mY3 z&Fb5PXsK9oNMKD!4Spd*^p^6Vaesus4EaJ#Er}wg$X*hH;BjsQEvBd_icU*R0`7m} zdj9O#v zY+u2D(tF9&r}W`dy$5Cwqk9j~?en3*G|!GF1{V>Bl?|VV-1(X5Cp07S{RNky%(T^)Tp2TiKT4*Ud{ACExulDSI_l>U;j4*ny^XPtuO0Vk z$CP}yS}@|o!Xyio&pO$h3&S%Q3{pbi(yVSC&rLM8vc=D|Q;{FP^yoPLiX}%w3w|ZQ z#Jh!W`F(=_Fs7^WI{Dn+_DcTxSi>N4$DAAS1MZddJg{S@+U)8#d(2aLPp1h5%i(C( ztLA%LKgWJ0h1to;%g-aJuz6mRug1b3$EA|E81Cq?qIGsRJZ1Zk(i3up>4f5Z zBG*uj;5i{TbG^{B5IuP6^`UXkR0&EI)Dj@$O*8y0GsJa+Oc9+Sgk-w)o8jYup{&P! zh%e#z;%|-*H?S0+pI>|lhg5>j4YhC*r&5+8#%~yvQ!Ql~ewCZFrcjfd%A##kn2vE} zz9f&o$k>r+QRc^B{!T3FUPb9G6GjHW`S*W^sgfnJ$lOVh8xLk;<|2}3P1LE4YwL(G z)JhkAJvJnB{2ph$T6Fq0qetgnpUz7f>!G{TDqE!_02ovaC?!=-hje{Y7U<#4ziSK4 zFx09tHX8If-Qfp0)IHFG3T8ahAD84Rlmdsq6-*qf!+8~64iPm@$XvOlY{{;}gtD@P zZAMv-rK@G(W)(@v8(A|oa?TaV7XXlpr+#U2OsB5tYt!rp%zTUx2OT?JH10~|>=x-$ z#TIR&&&lLD7G`uFW87bTD$K$`DWI5;>YFo_`UYm(f&%_fv(pHlIRz$d$HguH*P_DP zZRGqo;}hRKdLs+Z1|ETC{CMMB*Rth$xQ6w>Xk>=P1& zvV9=T>56p}%h3{geGp*dOm^nU((D-YTHe>1s#&DpFo$r>wdz^NF$s~mL;sv*7!~m* zpoLC){>Bf#x^Je9Hgmy{$#N=7ah`8GfJzf|SZg!Cxz+u1F4SwzCVH(q25{Fl`bC@4p|?l_vYg<{;02zB{9C*>j+tUPUd>Lhmn-AETt(! zCLx{V@ZwYRuzve`*Ri49_y$VCu^4k3X0&8wPGionC)i}B2-OKCeK9tbmel`bNdFo9 z?IUVvwc(ydJ&eeU_Z51F_GkjjTmhd%%zVBp&(JDz*SZhTr`zY^?fHBo>ptzx%_PRQs_qOXzIOXCi1sNHcms>Myep_>Kxs%D=%^5J zhl+xV6^9##ri8A9qeQgziA$h>Zf81%>GQTo6+$X*UZ5;eDpuVW6U)J{n7Pk)KWq@) zS$9ffu!QxH+!=P_V;Dp_;UB1Wnq#_z<%5F)wS>`xXM~+Z!bQr3@q~4Au>!AhNreZ3 zs`q7U!IakD+iAl!w(hx}-LP&=t? zD665OA*=yNVXGjips!%EvCyzyBsa|O>Hi`3=@=2Mrzm&~sg27e zLIOi>LfS*(V6_AJeiJwt1|mCXihA@WqQsK`NE$*?Q8+|b&>ggUGg0ouSBNepd$&<0 zMBC9X&3a)_vc)_xF1>muP<%w62^=VxX_+aQxtM9{80&cJ*r!q4^-N@T`eKtM^ibU8 zOk4}lEk(ye+nKKB2YE=&qjZQK-p?187!Ke* z>MP;MTZ?{VwNjYvED2ETk|2o2Z3xuLqmxRKmGLVaRWjbB6`>tV+DuYRLL8Y(8p52) z(>Bw_)c97r@~vg0ZoF=2tDe_z$!t2G}*M;v}-qJx5TvDk)4}_o1UAEo3iyw zD|0J95XZ~=yY@}tlyTmGggzc0n^tHRAs+)k@n-q}W2!v=JbVrR#o|VJib1rC@I~*2 za!Oy^2kS-o#%{_-EISG=w6>S5-=ueEAfaDnpoU3~39Ii@I1bKsXbW`_&0Z_E-DpM1 z0~5ypZMY^zJ^P+t3LVq3QC6fo*Is1`k}-eu1NUBVioQ`)Z$`)iB|9%WJ3Bc$&pfU+ ziZ<3VHV^~e{_ z+wes@W2D|!To2k?6?`--jAZ0w!elIURP*rqftGFh2(&Hne&=52zEFn_2d8b!zEu=g zyOkG*=w3d&JL#2W2cB)0zSGEMBG)fx7At})OZOr7KksMnGw$>5hwmTV%%2}FZ7-Ai zqeF>^d~Ba*-N?NG&(HVT+vg!&Jlm22eK(iITWLkKlu$Eg!O+92eQH8p%Kcv(QY0F zVxg@`x(RH~1oFW>p(0W|XW8=_GBU9;aWhddvD6aR($-SM%HYQ>W^nR4yl)KMnhT9b z>l5X3aM|+j)kd{bXs2<|-6|5*-$D!JLDiS?z$>WNln z320QWDl%4%R`OO-R&rLxN6@7`N(>4F+1ymBvZrz#{Gh#A9wqhSwd^AqFJ@5RY_pPp z^b0fSX;!3kKnZ5%_srG|^Yq6V>X{Quk!h_N@dEehDyj6eqQWtG?UecCCTd$R;9kSP zj7vdB(ycde-*Ua+CFNEdxNd1alRq6lT|W~(Q$9m*xL*u^m_N-kOsPRvr>~a<19xS%v)I)M$wrWMribP1CtBI9t&-x{-jDW~&#NfZq^VOgUrlc0I-aU1uG1R?@EvzlMAz|80OLWn^RE@z z_1+_o?<@M}4cOxeVhQ3iQ!Gj(Hh<8)JX)5px(>VnNU%;A@k&GfTQhq7Y$m^>U^ z6q@2}O(upr`8^D8>6V&Js|WQmz4UMQP9*BHhrK^Pfllt~1cqLjpW05c>wHFDX`a5z zOGc4XGEtIJ3KX*za|e%E4!3+U*BBqfR~T32(&bv%b#pS?9i3?5GS?h0%V^|6+OZj0 zO1icgAK|jw^-Q^TA79`S*m;g~BHI@o7iigRscoTZS!$VI30rAh>0ilhsccE!i5e$J z=3#P`uF6FL|qK#Ts4ce)4h-NK4-OYv1o zdr5m>`%Qa$dmOKJ7T-jst6^4*tEQgETB3XW72v9&J=L9KXEni9do9!bZf`aFPI7JA zePX90;m&Lg#yxx2EAh^2ZNlAW=OxpXLV#9)LV!zvri-zQw~Ku})<@4<=C$u3d0#)) zN6y=|Gr?|WVyKJhZT^|(>U>;3`^~`H=k@k^|4M(%hw?4|dG%p^=PkvD^KIfe{^8Ys z(Er}Q!GFbn%fHM&2txfAG_>ch5dT_ew2$2IMHnT}EFY^FG;}7_Yw8T-e)anY!xPfD zwQltJb9`K5xNk5}_|@qj0NsU!&wx$)i7tX(mU@(y_6sdd1=Y^SV03mYLu-@C67Vn|C$vZ_ z9OhN5qZ$XbEGwJ2EBCdRE0VPaGzPS*8|53R=MU%I=f&m==P~Bz=ASCkE2Fit>pBg* zRv)uKXvfL(=M@5)KJ~Are7fjLCREb2!(WCOsOie+jl$Ey=&5nlSnCFrzpE;$PdSUN zp~}>;#Ry-aBy?5agcU! zscrn3_p|C}t(%2|^(A>^?}EaVJ{?V49YL+0fAiJtmbPD4cGKFJwW2sDvYa`a== zbhLB~m2}PtS?WL~fWzT#p?ZRzGEkQ~5x3Au+K#rP@g{1zO=cmPUjwM$+Hun|tuC|v z9^(DG>mf&>KoTMSOZ|;WX%}rBZ6|FdZF9xXin5B_QB@Zq9DVjY8=IxTcYnju)M_cB z?sx<<8I)K_tF7Erd$L(KFq}p2QF{_ucQ?XMx2)V$ePXb5ZaOgXVMJskeO7ljPbB*8Xz@&CAKnC=N2%m6hpf2Cd?fp zoH|LZqC`X2LBDS=OoAq>%q@2d6n00=UwU7+)fSdb?OlFfzV+Qyvapc3mN}oftFEE0 zHLlX8ti8lhV|P$mVOKR#H*rA~Kx3{tUftf}sJUA<+?a@@@~w15?ZIYuB+*XQTjRlf zcOg+g^-jgM1W;mSJr}P!q28ee`ZhP9s;}au?VNM8P-d)JY!g8@oMa%=yt^cA!=Apn z*Q9HKW|O=Gv{eUEECFoNY>Q4mEXy@5+qeSH8dvQ+dT)Q8;w;NFao7?q^4EKrKCRu> zpCT=6 zL61i;H_L7Rv?}^BGvP%*P_RPqnqR`eyC z*5b1fm8oB6G+8ReD^nGnyvDZDI@1!_tgYDRd3CNe#%9Iu6ur^sv5LAS~n4;`!>)M4v}rMc+tYTvbw4SJgSL>FTYky;|sO zeAK_7tIg3UUz)DRQT2I9 zB49;SlWj`6$jP2KW*ELG-IV2Aw_k62Qh0*x!s|iDlc>6Qc*5&~(w3n6tIF)$n4>&THoHc@ZoO8ZwyV~swzvg({5QEHjt;;2u&NX7La%Nw!nU|0;Td&Rcw5x9 zWBt#Em9Z7(Zy3!<9=^-JZMU;__4d}b_;>jCJNLXd5FNXm1~OyEb<9;WnRVk@RSMPB z3zKTWP2D^MEeX)R21Tl>n8vNGQr&)0MyRYW_h_A-nVejiuZV|tj^mEcTE@dAK0&61 zTBwj$P5f4ime*Ks4X|@f*4zT;5JeMZ5rr3}5ygW-`ke9`k(FoiM6lio88Jj0mNGCr z7=9J`CoC_|#YuNP+-X^YM zfH*NLL@o+!q@aZju63)?^FXfnqFvz2AIghTYcLek@pmWMZD!5+d-8-w5t7nsLlhxH z&>rH~P&VG2e9q6W@K{!x5Jm7Q^aicIhY&?0Y`<=NqBP}GDsEj|oSkVpoW?EPKJBeC zo(Ji2oU|GaA^5D?&mu^?tH>hz9%-}+)?Y&u?Q4O<9J#G>HPe9$=@$SrJ-hznF}Dt! zPS&1eGi>XiTC)Zd7GCS1L^BObzeG$8OQHOR4G?Dgn*W0K1pr>hs?Vd+ts3K?QqWEe zzWKKXO+@40RoN15O=!QBn637vInA>Tq#oV{(0AcOJNrf>cr}8XZMXG*rMCSBAfsUj zk$4H+crV;GF1!B=f#ypIrT~@&#tZHSaRCJe2Zjnp1||s>14axk2;mEb79zG{j&i5j z>(%5JU@yoj%=uXd`CAA@h*=0`h*}6cEFpwj$TKa8K=|MU$yNQ|A<)kpCX3+TSx74C zVUKBlbBEWA{~I{+%U#qJb1GAe*c@e06Uq_OFXJ!JxjO~2AD?kgP=+|69(I>jm@EA2 zILW`jC@_c&i7)0T!%N~DY!FC(nPQ^mC{voE-O&4I&;;ed zKBv^f?$P>lg&T~M{2hK7C;46vyGkp}5k5Kg7uae5gr1>KarxB%uh-_g;lBX8MeEOb z`~mq7<&OvZjr05i1PRaaA1ZusoTRQkb0ICVvjrha6qU*K>*Mq+h#HE!CfVQk5M!+oi<>8FjTjV; zj;7j*MwAQAG_P8x0r++@vQ=yr;IZ^%0lTG2A3KR zhiB!zT4|l-izl3&Uzb(hdmh92EJzW116agQzx+OPGD5)wZFD2!WBdPiqz0b-U!~%` z&vT3>b4Gou{RF25CHvb?ijxrzhGMgu3_m3hGTz<*74bjFU}uQG$w12|)uUA2)fg4i zGVXlsWNveqDIs?J!63*bdty99lO8`C&I(*km`Nc%{E}cukbMpz;%tu}fb%O7%+aRc z|3F%QMEun2=f}y24D(^DTM!>R1QOE0fcP(DP5;K~YAJ0_;6Lh81qZu=pCSJhgbJy0I0KMVbfbcrHr&Cw&tTK)VJa5`)J}wGPPiljUTcNk z7IU<1CK2(zha=#c1bkS^5u&$8Aa00940!7E; zpF|)uvVU~;kJNq|^L-7=Uxel$h$iIhV_uv8K~;{B`eY7`#Uuvn!AIQhFbJ&yAV(Ow zwt%Enp^>v3Q`gBl9*ZS{h7&}sZy*1Sh$lF*W|d!X(SU<_*r&w5`Agehu-Oasp{U>n zgt3(T^bg}HVFhPqOgg!5BCVFVq%hUI*mVnxDn_KlqSa zL{Sfze@9pF;%m5bB3}`}J|G4_}dR7@ZBJx zowL3Y)opqoR7nBTl!m`(DvCicEz^rVr$cI*dw~8*lb^G5ag`8U`tAA0lj!mRub);e>{y#Q|@sT5uwfcmfym^ zq5jWq#D91e|C2AV?e`B~VsEFuIW;~6_T6m^v@9Hp^4Lot@ekEaQzlw+y5BgtKX^jQT;2a@1L$5926z;KLO)upe1G57L-34?B7Q1BHfz9-^VF5 zw*MgnwkiKv+HpieYeZ_0@dF|AP=3R0`rC`J3PD9Q3N{Eg2wfl-wY3wtVJq~+;r0H-+5MXv{4WFyFQOa%1?PrC z_qOis z966w}&Gb*0+1(Sd&9v<{%1Ou)H4w3#+3f_5bR9kLyv_9HhIPS+;Er{n^Uh5`^U5l& zLG%72#c{FH?F2c2!292Wc8U!)@M<_Wxo&F+J+zB7-vy|DQX<^HNeMP%qb?*R+zLo} zr%?zGVWYnXO8lK315Yo3{4eZ(lliYS@(5|~6>RN){G#s&>Bbf8PhJT6=s%&KZ}?ws z^4IJBf2ZNQ|HJcc!K{Hdpa&l%_icedBe1Vo)4x36>ZS+=SHk zzmor}O8=*-2!4Tp6$8tKB}NAiB=P+Ug&YPZjPidZbCAK&NqmK&?1RD1kh=+leR-f# z`dz|^yBok}_6X6I4W{8yTwpQ%|K0p81T4njZZ)6g(J01ZE5!?zpU4-x_<`Om4lL0W(%Vi8x$o&nI$iraSs z%pVdKF~#L?-S?>=0e(pUq#z;~7uXJ14CJ5lu=gGt7koCPjP=hh{NMEI-A)h_aJ-Zk z8Qo65!_d?+YPJF~C@VM(`=Dv)H5`5^U_F2Trvm>44TXiQBWV8z;6PpxwC_>ic>ez1 zbx3Jovrst{U~J$eaDroQ1vt^H+p%W6)A(*se@@fyr$6bZZOX8~<+OgpAY|+oZk)ATGI-;!}A;e>?|B@IN&gZq8c{f*-- zZ@Xce1)!WrH(DvoW1zh_iI1Lqw@;Mofz zaO#O_F&tQ_G5)s5#BmYI79L#|YHyJVuu~{zZ80BCX!=&VaDvAiz^a?c+fly2ThD<# zW7<;RETL+@20K;YDt~r(lmJMe;*(Z5KOrn^_9$DUa<E+ z=IVOua$F=|Y2cCOOx(16j!*kKE(8US@^j&%p&FPEq~WDH5(z#sJuFAy(x=F8%?0C! zYDLr0`l^K1s~~d&5%%?JZ8aZqb71;%5z5#NXgku$zJQ zLO(yJ5vP6DBG&p00m~cs&&KrES7Cp=6N~=AG%p`iC^`TpWskSwj1Zr>daI_IUU?^* zId5HgQdS2{U%AEAsxuo(HH~jnPL)ldaOBPlj@Vz);!vbG%zU&tW^|vnFE7*f03cZJ zzyHljNH{C;6MX7C?b>k_x@8s4)O_z-nHy6x(%gbn&)Hi+IIHo;Mn=G5XKl(m+0#Sv zYm=r%?L#F>G*U6x zJ=CD@&NLs~JJcJ;)rz$}K9%Q zDQ;nn?kSq4T9g{f&iVcAWUk{B^MK0u67`E5564L7R-ut0z90(c@uISdIQwa|pNr(B zvqW1?)oZ2L%B{|s8RI91nMLyFYy`(yg|YLD6)d2vHN7og909ZM(r>O3Qrj;ISgn@L zY-}my=C)ZCsCEP6?0`1Y9srZ2wyv@>Q05?#>0N%Uao&Yfsy)V2sy*)v`RJRZOvY$q zKRQv!4k{@HF{6yKUhg;SjPjCbr##0jA1K7e@+gO9$VNr(qzFfe?Oep>N8>NVZW9_A z|H)iAdFsgB9Q8cP$$1MW? zrMK8tlwaCrU4BQ&kyj|Hc&Ik>{supG0@yNFNJ zskP&ZL=?{+VMn1v$_@y9WpsC8kLAC*!6(T!$-|C? z3kCRPxW-;{NKI539w0UAcE{Y&-oV6}Q1mJ(1j};b(8likz*dUoq{yNo7uf^s1%+6X z^bRiP>4gLMj_^i2lB#Kg=>isV z_wsl0>ew*!)u~j=%d*OttmbF$kJuOZbnc8+vq4MmK|>rf>OBXYL^`px1imj$riz#& zWb%Cj?>jUgO+Eb_sDc1CZRzp7(DtjIw?zf?co z^R#K4R9RfXtFgFkKPan`PhZdVYXmBtQ3EzMM_b1dKo&rE4I>IA3eOJ74$BVB4sYvS-NM>R-XgrDxwLku zzK^`GywCip@T~VNw8HTEg%H^X6)8+0yelNQw`Z$*%Wms@i)ahwvgE$lP4-!am;RM5 z3mK+2{(aki1Lv14lsA-#Fz?V<;exMJvLBO43M8qd>m;X?BG762q%M{G6TXm34Jm~s zP!~!aDg`A_nMy4wMJ3SeNs*IG#)&L!Uq&msW^bs%jPQCKVGT)l(Q=C{rL)h%#+D zEoqtXy@gc^mozdFNFF`=S@&~fe7_7@0Zn0fL3yEdLFja&QZcL4Q5=QL>NL7#8LQk; zY*oCdRGf)atcp~8dmKHEQZ=h?+UKzZGpYJQu4x_1tnVG)16cL7h*!VRC16U07p51a z7it%17m`mal`6E#X;G}wuYRUWR+FSD+QKlW@~;6LC|~AOesF=mCTP ziU28qCO{0J3XlWn0z?4H02zQbKmwo+PypyZ3O;@XQhAYi(Rz`1QF~E%(Vxb-$mmPz zOM4Vl7gQH^Omj>(PrFX@A9@_ZSa#jye;0g|;{NhN`$9qxhbYq}-6ho}<0C0ikUyP0 z&2-3c`17XuyD)ByymWEF%yiCo@ka@6ng>&H#Mt-k%UpkpvbaPdF~a0nfloOw0_T{Q zK}I=39-KEmZ#l|i{b0_~VN=F-@hCOvNZ#Qcn_{mts7253fGC7xBtu(M`ne4`1&b@8az|TtPgDyXUq` z>d~%~t<$cPtWz_@CJ%dE*^5F;yLYq; zbtW5Ad2G{K^lo3)HcapVX#XiN+gOWN^Txf7+l_^+%4WI-ZkGb-zB(m zy1KrCzY4#Sxf;2mxhlW1zB<0byGp;(zFNNGxoW%exO%#RxeC6Le;|D@en5LreqecU za!+p8eieRIS|jx#_n|va?27G5?25k|S|1S@eA*@2g}hR@5_&LyzvQq^}~wos^+rs6jhVxgh~HGN+tE0svXbwcj&!!Y#lk6|(C`sus|YTJ+1 zu)~a|KOJiwLmf+*g zJPbqZiks%vNorQC6s%ON@<8m3_lz`Ec3pqgl4$>ePzk3CR zuJJC~uJSI+u9InUo%Vz9gVIvIXQ5~1iE5`}r)sD2E!8@Wz?Y}@#|Uy*VOVI_d>3ms z#!=%z^+E1I_d$d!4`20FC5p<2Y9O&I5pCGlQHiTCL+wK%%do((W?wb4RS0fbQ0b;s zAa1F6DJGj%q@wX0C!3z!SF|}YHcdH2Eb+3VTdqlY8tqaR0N zR`tNVrZQXV>W@c^&OZUQfKWgww{V9nL1~l{gStey@ocSC+mRyAEX}OLk(;wWpb(G< zXaq!ZD|V=zs!*1i$Q8PjE6*@NTCGYtj=nnwy~ltm99P>f zahh{K0v#b7c{=+6@>{>^7SOBNDcPynDcY$fm&nZVgV>!@0d0WbRvq2kDwT5;^-|YT z*YdlP@;SDnjw3DS%vQbCoVDU_D(C7%UpY#V%8*La=Yr=XX6eclPSu;sqRXO7qsy0P zDQ8cQ;*XS%W{y~n>W>gXTp)K4G)N3Y4l)H{fK)+jAZHK)NDf2?vIP-l7gu`d^Si>8k}3)RwwA05O1^w(aaf zZAxv@ZCY*O=_R`5&Q|da^tN^Lm2y)>Rx=HRr`&S0WODQ9a&xR><%emxAgh^19H6Xi z61#SK{@C1}<$^Vb#dRYzFcK(i8{4GOCe^0dCf25^okutK*s$DS3Oof803B_AG%2+y zYZtB-u2!z*SI*B{+*w&SIs*Z=0WR51if#HHg3ASbC42?8^Mvz+Q%x59mHNwNd}Vw^ zd{wqHS(8oH3RVi13f2=A6IMJ8`wjbzSPfW>$qmVk>J93R3k?g691R?e%?-_st_`k@ zcMW%qNDWAhnLr8P0FV+`3^WJs1LZ-3ktHc325KWQzOd*yqTdljF~bS`*L-dYP- z!8Bwy1OO+148YH)HMixr>9=jS!7idaWiO=!Gq2N8);`vh4dAB*F48=e2v+6|J`MG0 z>mzO=?YV1=c0W0O;~hp`X|+$SVcS)3jN_flT~Gkx+lSWB?aDaD($B^&%mDT6OKbRc zRU8xP=X4jCfXX!zyV~Yn?IXJDBoCVQ#5L;bG40dJ%Xz?YJ811g_38+KtGZ|Tz!{*c z*W5hB)9aDtT5{)k4!s87f#sgwLAR!6m!5q0am{dTb1l3h*^L1db)mOMa7eJ*vBCr7 z>F1eWJ_EV&w5z)fxDR+xx>euk?REe?B3<+DwCsvqf7r(oZ6i_uG<$p>@LRd=r7g|bPsfQbWb{lJnHW- z&nwr+*9zD8&u!OC*Ooh6-I6`j-P8f+H&s__yB*6O(QB0oQ^iL!H-svYW}CY(7>vQaDsNo;a8|;>Y#<2 z1rWy#2dMd`8RUB73c9Wy_#QtycTv!yh*=lt(W`c z`;_|>pU-qH_)Oj%3mn1RWZwilPCPO^etxNWEq_gaZF>#&78NLaDm7N|rzGQaV;sc&63h(IQtg=P622}?R1!b~gPfMVQ>>mc49Ye0r8C0-Y6RDf$K z-WqFYf~zUs6l=VL>n`4@Xn>BZmOuD~T{=Q3fAk9nb%b>Oa1G9!c%-8BEDlIKz>q^D zfCXPXf0I=wXxV}}2zwt#B=R~EJ_0^6Ji;u$&w>s3X$?8Tu-|^$Xd87~$vDsTRoST;n{4$|*}(=GKTI@n)vJ6f0R4K*aH< zshCeoUq8)FeyYyJ3!1W)=0cG)G%JLu3($TIgUi=_v-Io>tUgW zVUQ($8{e66v>)oeRbD9Y;dQ&K85BD1UY$h!u$P6O#&0~y9y8hO(2dDdf<%4T)Tv7J zCay3NdS$*&3YnRGLluy@6Pp95VKCaP3F5z6WAK6xo{N=Ez^CIhit}0-ht3Y|LrZ{G}_Swt=W#1z+<&dEWm+e4X`s2*TH=|!hX@(WxbmMO% zmxJPROHH>AsiG5B@GtJWvECFt&2#4hhld*HcSImvF}=Jjg2Mjo!z0X?}#Xh24!}J1WKMH4qpU#SHW$4*Z5@5A76aRlE613ICMdeF9OJS&s_lCg{l2V z#m5)@nQ}_Lta1Lv37L))j*HhereH(F@1;us7)+Qe*(}?AY<5yr))xwf`Uwkxr=s~OLk$8jva%Et z=K^QTRxJzYy#(n?ucv#QS!mc}5-Drl8gFB_usAruK%|%}bKpa<o{BC zm?bO z4`I%SrZjTPSz2J-Ud>36ZL+*pR^Xi9mVuxg=M19(4t_TOTQ0N-uLm#3V=9Ecz;O2> z)r}kG9mClGwn0VHtG49fWs2zl>eY^?08YGnr?*n;;X!1<1RH?2T%RO&=1ibtZDKav zd+xDGQ&#AMLDj%DZLM5(^Hi;tBuv*B+L?J+>4<8>gp5}-%Gh@50=2Hb9#eE z@%YP^sN(mxnr7FlOWx)@k*PaNcNQ2*o-c&cS_lCReuO@N<9h9^@UAhjF}d( z_s?8d%(~3nNv{aI-YADfnZD1yNK$&TR_@;=z=u%8-b-6Q@qy@uw^1zJnW#uT`IUlL zE=fwa?__^7qqb1h_;lG3P^}l8ejm0Wczk54Kjlr%p81lg*sI|A(m_EGCoa$%sIz@X zl#}e5n!>MN%(W`{Kmhlm%tHqUXAAiRlO;>^H3)$^;HU=N`Rjw5AkJ3-3P^gNCqa!z zK@BqKqM*@Ox&2?!*xQh^T+;#p1&JZ^cBmgq`Q5e*QDY7oyDV8=PL_rDO@fC+O}1jQ zh=pjsV`j!v9@2a#ncC8JYIUn>S^)_MF7=IAD7!$p%?h{CPS0H0(Z!9oegPt&WJReq z*if2sc3{ZarRIJKLR|N;K6Ql|H|8T8SsV=fHIPMkPwTaj+S#&?z%LRPZm|0l@vG(+ zqod))hVOYoT4%Z4MW4@Ja~wRRBIL;Qm?9Sr>EnX5nSr#;=av`)N$yC2c z)KAu?iwvuVjQ6undMoMG*Y6U4E=D3K=)+le0zajdinAah%txOytgZem z;y09=h*XG>)a9%BEl4*Z0auDhJC^sxu8>@@(ggK$OGDaJ_N~L`!dWsv<>ZW@Q=m7n zR2%Xot1lr9NWs#^%#uX+y(Z@A!Q`tD&F>uM?WBJ`KtZTz69vqqk3IIx^l8JlhPw zt@SB(UaN8FHymZsgbO?`)2`GUH|}=K5U}yhRl=nLhbt)4Ps&g8qu~}{%iA8lpZuz+ zTpzmDPc=)cKMVbUBj2rNNl==ui_eI7{@~$A|0X=hSh>Vi-m;!jdFZNww6T)+a5yrxr%3$LOBTmy-$iZmAN(0&diExzXB4|lQeT9f zG%T`iBM)4+N}_KGQkO+L##AgZfMc?W;#lSDZ{c>wx@IjIw=bj=1F;~KOh=A*nzm&- zGS@LCQ-0f`;#vRq;2y%2uR#fR5`v^HCpKvcHaS>_8drQGjmbk``Na~Jm+(^4QW?ZF zjCuTGbNi*@XZZOP-nlqKOmB*1pqUJYu=hs)Ix;U1UqvbY;dc-Ye$)(dkcp`;rch+T zGNlFS3&Pe@^%j(r*vo+BDC5l1w#CmJm$3O$2CWgH=$5#{nv95pbdRZ2n#aNWk06kM z{0HRIHDRa5!{hacoA_P@mN{0IL2ux}OG9|Ipn`#}*gPQ~#HYAGF>N2gk@t;^pOHmo{o?1ipCfcCF&w|)wOzZby3gs; zzlU{#uRp|+le`+~F~>w|Qy~ZzxTe7O{%7>#(WaCw21}tT0gtr5I=q$>pCq2}bPT3b zc{3XLcEq^C{Bt#WE489D&iRI-AkE1p!SQh5MtoMP8|CZ58duib&io(dp4KJ9=r!_# zT{lHpFg<8?lP(ngpp1*`Iy3OcTIUw5Y#F>8Lc*fN#>`V` zSeSA{9IZ%xbw+}gZ+sKngQa($nG1+1Ytxavw#gx(xw|ZV;jC0*Cnx4Ss7T`Xh)rLc z56A{VE;vhrQrQsEXAQ%zG()gJH8ukuD^m90v1{HE8~Dm6UuLIhpU=eN#D>#yPwZxP zapSw$w#fwLv_m)H4Uwi8pqX@wK7%i`E+%p0uSWlLl4;}<7i6&?^vG}ShW9+{4yHsG zx6alDMP^vbd6Ni$Wf<8GC0&sZ5#%njO0Xu_ecg;ejbvceNfrz3Ce;|vZEhOZCS@5<({yA3`@5F4p95qa?z!uSy^$mE=fY2QiLCj+nHQw&&lJ_?~jK9QX@tdG4G z`>1!6V9eXHk}Nv7jukYg(?uv=fE-dHK-CsDLykYL72!7cSyC)F&gO$mzc&(~hZ<|} z#r;}bkzs;YyzX*_{1Exo&0_IweYv-I!dI(D5@P}`R;B@O9|4Q4E@FyIFMx53Y_YL>A#X~{P@X)V%>?T?@Kj2|EgtdCE;4F`}- zU;BISNX4?GqaUpvm{hCOy?(T$skqi}Fp zMCrNjBQz6)podn?Uc(@!U2VC@;msb-Fbj)!6xm|4X3%M)yqHB?ucxLJV|}KUFwNTt zv-4AVa%QIW*XbIKi>B$BDGL^IxU&`#SgFJ-g)JLr!~Pt?CkkqKwGVR&t|Iy)M;lu? z{JM8Mk34xU`iSRzwf^b0$Fd8cA9smkjU7Bl8b3aJ)x}?6FT0dXE18i0bmc%XJG4C3 z;McrCoRLBy3yuqQfM!-Trm|{I>HzM8VhSd-zJP4XyqVMjT{)nv9*P8=qR^NS19VQL zIS+))xlHFIuq7L^trJe?HX|&%xj?W45g#y^vLo^YrWXl8HhL43enZ8PvBqr0^ zKc!djw3}{+O#n&WsgXS>2{;HhO`)pu;1<$|8Nvb&_4bAhb$I=%4c zu3hpiyV(-zAdmV&1W5~~m=jG~)O=GkVFF3_5*LH?P_Vg*e#U~@vdIvTs<#|OdPdl@ z9T3!d`>w+sYREJcWlXFeRf45w1UmOcCMRa^R2k~LDCF#NSm2>WSyaKFjaNZHJ52tKBO%7AI%hpM;z!zE(o4;M!pPyLA!|0h>4 z9JV&*+@D2SyvKMvhVk)suosPm^L6~IRyO_vNFTA>{9o8NUyXlAELrXov0sDga_#;f*lKjkFcLKHUr!!H*;b*gmI3TiRJI+!8`)XD28F-f@2cQ zjZ*ykyh$OUt>f)0&y%;OYRetZmzD7e&9Ao|O+T~>IlHSWuEjE^r<+T=>*~eXokvR4 z83)90L>1b>28G_{?aIt<*YR}@5l;<8Khs(k04 z_FwR%7)b<5`|N0NDl9kYU`ldl7d|n`!WL}5Jig}!i=nT#GD+$utCrH0PyFByQ{uGd z*ni)D5r!_sf9<;rtWhZ_^M}%w#|C~xW)**p)#C9TwXhrkjSs`PdQ_9?Z$-6ag9>V! z&@<8={v8@VU>%rpUvP_WtFL5k6N=y;RHZCo5e0VUYF4;x&^Xtc_bt0Zf4s7brH7#M z3&!wz#sDnbo5NNT#LlfMQOsp;nsRPyHF!31a5$$WC1*wxfCt~TcKS`n$&I*HffYUa z7^BTCkf7M}cW^clBDxKhUG2iHiI=BZaMDsEQW_j5$)!H2iYD0OJ`~*zpoB7+n{EQ&!tp8%Zf%5w4G5wCh z&X5ozmd2gzpf|5)4}bN?wPcnYCE9&XwjZdiPPJW!1pF(FjK?ij>s7=awEGHflNl|w zE0>i*7PF=I0efiwR6GfD{RxR2n~P@VEay0dXb^yIJ~vgTjCg6>8H4NMWj_6*k!h-y ztSu930tbTqaHkAuR=#~H=KMk9dOA&IFr=X66oxb~5ve{&j0o7{d>Ag#gC1n$JoITH z5-iCL6ZDK7tV83c)=&8f3vgj!l77N6Gvd62Y_A_M{)#DV{%zD=d(~ZJ`7`aioMl6_ z2tLOZ!fq$r+?n{!5e_`|bZ?_Ct-Qsm=Omg-hTI#;d-YLhNCGJw6bl#TU5hE16_ibm zV0k6>GmtXnc)c5~kY|5(nbD;Dk+z&W*e+0PPM&#*fYjspB)%0m#(~l8;W>1aS!|CW z@w;wcg>5h|wPM*K=Wd||jfYCSK zllq>i{y4453afL(WulCX6N5^P)?fv0_$^b6$E!gWa-}H7365Sl?HFVhR1LK)Q?M=b zOMQp&(dl>5k3fo7sg$7En{7uhrFLO!pmrfQ^ST|WqQF%H$1I38m`NI3+~v{S-Y<(|SEV;XsA}H5QzB+E z_lvj{qLlIQ4^60TucnZy@pJwQTPTtY!N)EBa*7euJ!52K~#)MktIk3=yf>@z& z(s)57RbbwVcND=@VKL&!^T>sc&(!-;O9Ylq=6;U8ntK+ z=kvQ>=~PI4UCTYs@oL4uYbMZBp?Ky(g_kO=Uyy3&!|`tREE1l1Xl z%x;pc5UL~VCUIfu0g+_$P{j^67ZU!)YuiIz%_M+ctzKz3N*iGe z5kip+<4i;hMif)2E6>RV##z*L$&WCK?H3hYER+Ft_!|eUD~;Gj(0{5%$nlv>%6~e2 zqQ63-A>Gvv%TIE9pzi@!4=fH)vh;IwgeS7U`5Ip-@fomvfOXumtHv~Al~b~KFWx9* zgmF_;NAx4agJDi`R03akvw0P>+h15mQRrGPzKlzWZV>Qo!>MYrsHyR0FRAiwEklFP zNhKOrcLtM@Zvh}6m^Cnn5WF9CTi2Pl3<^)QJhqdHlu{Vw2t@tunL!X*bcqXD#FCwS zgQGRZR5+DzNiV{^`#IUX%pA_FSW>|kkP2$V$W3$KV2}58Lebqj+&*aHF2FjaYk+^7 z8Kp6#ZdBb6Zr^koulw@L%^awc667p|;m*pRD}UGuoO;tlpd2*`gX>FFKYDIV81o0G zp9V^_PFm~1VL@o$Aj!lQ` zc~QFTkDD%!cq#5XQK6PEVwN8R5zv-=1xev$K|BxHmfsMaXSmU^_Mq+qqksRyG(uXS zav5w>p$IyqUr^?BzV^NvDzK4d$aOXBd^y0z1=&3YN7~Ae&ZRGa!R7Pwg_p*D;-|VG zG+sqDB~2Cpw40Z1Hv#Duf}*eqN$) z48q*dOnaE{saVlCoGyK5xQR)9o_Ry3x}0{Z?#(8e_QFv#Oco&OAo*-VFE@zxQE{V{ z|E?2|-`Ll3^%HjXo4^kEBs= z9Igz|>xJ?2bz8BG*pc@Wd>J5g=C zD}$TyI2aeThOS{RvaVWgZ|~cacD&;6#%bBH#0Xh(5v3E)5-OIIvxD_t5*fRSx4?;m zjEb2C6qF{7)89>}Uv9-dAnXByy7bt z{p4y2k3@k-o*E?O8fxqIEbFS3P?R*WAnL_1O`T;qPA*|a#>t5xsR+r~)kv7yE!!}E z^I+o|r{4L|X=OXga%q-&ZPllCamQ=jo#{ihu-b{$=`w1Z*d)}R$p^9F7(F#rKkCHe zuKA#?VA1SVEH=v}z%S+V1e9r$3l{-D(hM)v#e>jwozwSe!Jp^0h0z*AFbo>Y1a59DPy6>pY`Fo(IN{d zYTN2*2&0lL&^w{*K!~pC)cPGyPrH`BKxY}`RH%poS%UalRb72oXOqu#yUAi!zkF;g ziZLGc=@D9OPX+|MoXFj5Q=q1er!_ddL@wiSNl#Ukm({wHZYYl(PgoD;9BRD%D1{NfMebtpUWltZ8Cx$N-SGlV8`r3u~zNwe7 zXq=1rqcY0gAlTBinzN!?#5NhDo?@yL*z|L(N>Y4dj@=*F7BFzADCgn3O4F0DlG?xjty(=M*>RNKhny3b~@ z#F^o_Zyu8jRkEVpBRl8cTZ;yQv>0s(-Fsh^^h~rpD3r#7+uqe!^$%aU2v4J&5LGnh z{kFJ?7>bEUZJgVvF@qe<81_2B7pGx_KLWWJeV?A!4ost)y61X+=-G9(o?MhXeXAIE zxR~$$VK;czHP~*mH=VQvl3LgdYTT@=O;uU#hrFH{jp`R-cX)US+Po=PW(&bk*JlGy zRMi18;SsI4B)i|V+OYTQM#K=Ei2XCT?ZRthi))&e0;%6&x+ALPnx(~5FA%4mfR9D&sx`tb?`YX_BXgfzO$!7AvJznlh3HffV5!$ap8l z@@B2`n^kARVQT1tjUv3*X5NR{^LAJQn3It3EcQAg*rXHZ~MRIYxUw4Iq5*QEx zhllTu!ONc0%hmQgx}l~#?I^a4z?zK zK00PV!Dt}SGy9*j)I>3&^|jLWV$mzOLospcYG_6@%A*MeA5~bzLt043JqB&S=~IT2LwqtW9*xy*n_=eptAQm43p#@4C3YNPzY{23bd!UE>9I}q>2j)n=+Y3*YZ8ROCXbqxcnvvEk(-&!L zFz@$v>-UynN7muJO6I|delWk#j%udzvv)YVnY@bY|-Ig&&m zjW3Ic%Os45i;F~cS6`h-)=TM*Ym*T1-(#qd0&7G2I)+rl-<%P9|D((q%A*qG#(l*% zCQeA0m2(75<3?&&&O;N&aj;c1&ygey6@86B5xJbfGbNE$VOcg>txnZd)fUXuAJ_rk zB<6*`#jOEtT8eey)9QtJJLD~+5Ju*Jr-B>ZQu%pxrf$Xt#);aiRcr#^^}f8KQ%sGo-4n%a z9IX9~vD|M%#r$oXZc}Jzbp#bYuJ?i7yLc+L;=~zpu%NhqPsnGEqQ@}AGz;T1o5pQ< zo=cFB5Ae8t$vUwT4VbFLM?k8G`jmt}y*#nR2{>hw>0ZE1!;bo4LROc!ji$w9uN}q$ zPSuQ!UOF+80=lAzX_4`4L_0o^22!+HU-Tf3HbV5n8%DKeE@mxlRwd!hYK&AgsLBCm z{U-AzlQD-=yJ^M^Ug@pDH=(=(5(YZcVG(b@2>MQWWtL z94a)fgc^55Wr!Ev6CsW`nstHSNVX~wS3GOemt6#Dktmx|?k6*K)(H->q@A*C;yWywJ}Ie2+AzCJ7Qzd~v3=***r zR?mzz=1AXBwWp0`?lb0vUCYN@D`_rm17lcU~@hax+5@c}AYQ174ZK}2 zy|)?TCI*Z~jc6V3E?8eVSV1LL@I1>_7(8pNaC_vEOSJDgY&KizoVEy@Ose_rf(&kK z3XSGL1yV2^@rF09h)ArZg~i&G_k-ITt8bnR11Tju7nF^$7*wc_pLu?OSwP8Apaqcl zRgPN+TdIvIgzoq=^E)>=@z$N!%R<6^>v&`8f?JEYMC)9A5?p999Ywr1u*r$eg#G ze&=*6(&(aTn2&n#yn5NJVRXZ9^%6s3=n7(CX(8Qa=@V+R^V=}CgK}KUY-ro|X59FA z%wuK1@&wxCnKXT)Tm~ZQ{x(vRu4lle0VA5F+(pi6uNmedm3+9YzA6M-B)=jFs{9+h zq;EQi)i}lG@;m84@kFa9CF(G-nlFVw4p$FDB)18*p@?0Zk^K9FuqX~i4Z0&c5oQ?; zy*dfgb{F49k$LEPjpp50&{u^uy?Qvp0u(MW*kCVOld<%KOrVJnyifG z7RsAyLv+e4rwXoRIFNq0W@D`EsZyc56iwUhvul%J^q(W2%7|6G;K9p>xDC>4pkH>EGeT?Bp047XginJ`z<1 zAo3xSEpe(p3l%gmo@8owFBt1gkGP*x<-bN3rc-{)TAelTPkGa55E-Xjt2r@D)kh|v z@x!2+RsJT~MqDOlTPEZ{+uv$`i6|3)$#S~y=YVMnEW()2SI;K@2E(WJCc@t(8eU^J zJa4bVIHaOJA#$TL!)bG@zdX*Y=d-TI40B-BfQ~XLtX&6|aRo-ZF&J7Nyw29-iBqkZ?nqK@4m$mfqJWkU= ziAzxdTmEe z8d!NX@;xnGP!?3rR;c71gnl-_@>wj^#3v;TW=ywYX}ag9zR-f-tk_)RgaW{uAV`X- zPYJ%v=#B&Qhv90hotb?T9>~6CxlM7&=(!SJO$seBqM7CoezYI_DCgP{{-K&qiIXfY zCwifS<#1w_rl9t~D3VUlca2>6rbq0CkbXc`S!}<~U8iW&b*wNHsEoTPRnjJwK6~RV zCpy2vQdqy?PTV|EaI@`m?@zh>!3_G=C1AAMUt+Bb&Lq^@aGi>#1$EG_0nSj zk8!Y@qYE?@AzORK{3lVV#!~l}({lN<>3}yQM~Ya%BZ?ZG-Z`yaN7_Tt%c2A}+q5Ze z-1CEJ3-bnplZ}0-@Um5(Yt=H0EuAc-go74=O^7ln<;J=Z0&GYcYyw=>qAnq2_ZPXD z$S`7oI4oM=b7Vgj+#fZOWEC&#Mes9%s*^ga{`Wx^qB0t>I&t^LB7v z0Vw<#j=B`thQce73iT=yD4>?+n^)O@f?#f6uae-+E;9u=d}na}rd`dJZ|?pMs1CP7 z7H(>F^=iIilc#j*BYx2y(3EQ~f5a@H4f$SLvI0^$x(9TznN4QJwr)Bl@xSR`KOMrh zrXL*PC!rn8Newv-q@QLBlu_*q9z(SAtF@$B9;t1qYX|ht%im5$M#vgrRe;f>=#5lK zc1h$B2s~>BoF2UQO<+Xs{%;bzMH1l9aRiE7>m1D{K$aiI)=& z#EW7lrzeHK_vMX6R=B5?t(wbEGm(NiWkj`7$#=i7+Lm{iSLmbu00~napLSE zn5?k}JGlq2%@*x!%2_Sb$`spRJC!MQ8b=}t(#pPanst6WBALYwI!$X>F|*xcWQE8H1m-}vZyAsryg)$?L~5NAmhw@(yXPDC_x|JZ_pmZxiTAd4hyv);)z z*@mQa&B))J+{_PdlX97Y!wZRrP-qp^B^Yzdf3L1b%l%{=n2RpEr|Gp<9wX~>hpmvF zV1LpJ)SuGwC*OSn$App4RzQ{gcV?IK(j0E~~ z)~9$etGiCQ**?&Biz#D4sciASm|6`Xp96o&iP6m>gh5 zA6!Be?}pl+7E_nbAcMuLHvTqU!cXPevku2zP&j3!(LCZXg%yM*1C+mhWR4+MM>lUe z=mD1%f;oAcBxtSVc(f(qdeD`VsrDRkPNYbcElR8tKT~(<#nfFpR-eE0qJ1v4`ZeX= zG&!0b9{R&u7vtork!QpvkpQjFWi2N-We7@e%#v>$tn zbQ9L`SU)+20yR@5Ab4;z_9fu%Hm%dN(f!-;B|3_@hfS!Wr|ND z+S167uP2Xncug{$h+>!Wi%A5KhG2fwL%BJ%itHSvU>hTJ;U0=gQ4Uk&lwk+?MD~yz zjjtpXsFeiaasNHl)-4-q*+!Dv`G!(ceX@a=?wGVBQ&ByfN$Wxs$bhVFO zo%x%~oMWs>l6+=0Z0@l>Jd+v91PFCp$!w>3Sv=VGt^)qi4=hImTM8f%SF~S&^XWB9Kt10ro>43{bC`-$?|4E%oiev)brUAF_ zPlH`Rh5cga24c^m(##(Fo^|{;iAcH#NlYooPapA*WC|KvMk79yV-rKC)cE?q#!?zG z0Vg-$sVxr`lW^L1nu!8K$9;@LXc1VbO}am%=Ka?7)zi>XJLU4hK_c=oPJF+oXhFea z8`ohp(rIe^cvCK7*8ASks}JY|ElVe8 z;tR&rt!jEg501|&DFUA0thN+kJKjuJm@Z`9w~JxxOKY)G47^>_-6ui7boP5+F7|2! zg9#)^9G7+HGm2b!Ba8LW$^&4X$GTb+?%wQ4tG3_REY$Gf1ZZHi`Y)422Y8D_5oNH> zp2j}wOJ0m_L=hQXKv1WYyX;&BxSO1Z_C^w4z`< zRrUmo^_pubzPdf^pD&G$jx8j2%rldqs~DroI1<+MGNtj z+TUpPORzCI@IwUf-U)l=Yx5yJYEzt{PmerM*I`OXvIE1FXmoX%QY=PS({#8KZdhgO zcLH$CVq>V}WcBe@BvfN@iqpz;QKh^q4WmAHx|cs}pR#j~>H41XHB{}6>l7fZfaC|u z3I@dbZ2Da?mNIyo>(<%9Gi5pBol*Glv?RRaUst7>!SYRK2{Ni}72qCOmwJy^Aqq6J zifcORN+qFk86^hF8>X`+seML>ui@0rNi%pU^6jDV>()?pYAOUe zUH>zYuq*;~jDj*jDY&GZ+XYk(63ZF2G-EY$p8#G3rHI&ii<2h`5JDt z`U4XtFqM>-$;d9v1k<|r%Nr|B8*ww8o=@%JgweE)P6Pz+fYNa9oV99W5OcU`&`nkJ zzyx^!9I^f0hF-so{YwIqHG%tq8*rDy5BR0hLx#GG=n}&-cyD5lqn||Sx?i^fNEkAl z^zqk|q6sV?Ns69dO4Lovma%n267DzA%p~sU;Z_%Bb^q?I47_J6$f}FwCrEfEZ!h(U zw;p{oep7~vruI9j7Y^3ZoWWqSk&PVw5}jCtVSKlhNic$-fXFpMeVXSR7b`pgNVxeC zm7kRcx|JKOe2$;=)ywZrk?4|2V+Ckc<2%t#29HQw3(nt#Bsv_IakZyRx}n`3hm+C$ zdK8gWl~9y?d|zK`5&z{rRKjBiy;fp0 zhQyDuqp+c~FXCKS70Vu0JF4%3CYO3*@k}-{6iECDml_5PmDP4EaeIgr{o*8L z+kW0M#>Vu4t&D@S_sg`04}}co)B*7IzB=zDwW-3hHnm)wPP={e7%R70$odnL?-A!v z2@)oX`PX;>Vv&fK@qn2AQTMqTZ@x$)L|j{i(NFnREZk45}pOUihr1zjKnY{-wFm>=OZ!g5`s}9sk_a&JOx2?*}|Ni)eeEHaGM%x#NNjDcc_~#ytAD7|#!bi1Sb{m=2aW)NMxhT(96j%YH5aCT2N_)(8)$q`D~Ehy zXf~UPmg{9T54`MxsWZ}|E&#P}TQ{^pyy~V;PZ4f`MJ-~HR4&-&s8+Z}SShV&RPc-^ zNd2|k$djW2CEr5N?d^Y3z4dM0x}IKivlf=WtpD!&l??qrAQd}^DUj2xECH>*Vnp1! z#_w(o3aw}n8Z}CES5i?il7;<}lFFQEVyb0^f#K-{FH@#0np?L=6-%P3E|IWGx1$xq zGj9Ldct}AyJphBE>TBL&VnI_sOuH~G!fEsr_S&Ukg(O#-e*(0$(TnY}^%CzL7x?X3 zcnIb%ezG`5vqN`bEP-9v69v5Qi;G2FPO;_&m*%gymcun9@J=* zPS(IES=(~lpoR3rJ0^EZiP2YfCu$&*5KZggvFmye9jrZB4z;YD#974bens7|->`MD z@AdQd{hW2cQf|c<+ropi8Qsx6mxDDCs+p>ovhY!atX;d1DO`U}sqwY}6>#!#9+j;K zHjrvNkr#?Z!s^;HtjQvWu@@&ed>e8kk)U0lkmtfc`6vP0El7NL3xj2$mkt$`!vr%u zICG!A+p?w$0P^COaQ-ZVMHv>s=Tdnfso2t{I=t~@?FbVioiziAU3LhY%b?!nCq5UZ zZ(Q_lptNqVhgtMB*PG)yqY<~X=PH%K0~CU}P_p=(`9Xl1aZQ0J_;r8UhxQb>FzQuH04vVM)| zW)#=1x=g5ZLw_2WoE5RTrwGAGih`A3iHM5j&*HPdQ69vIl*7s=X>v2S$uAsG`|5kT zgX7rDDgC~vs3@?3k|04FiUnDF%AzKzg~rh& zp-ZEeUc0smUpH7A+o)1Lho(`P(KX`}#ccV^%&C3EBus`>*6#(cK;n z-D@;4>M5vhXDJzM5$?7;2o=iGW^^kywv7X&n~;@gBWcDh>4PA(1WgkQQS{}URK2JE zumIC3=kz6^+tMj(l+BnHMLy3V$-dPfVQEh6`5mWeHM>SPle}H0*gPM@M!Q6o(A#E% z>=Krue~hwvonTE@B^e#TNjRonNP)~WNi$^{C{`KDYcl-QKIl#NM(T}TXgTw1#2dY# zt$z_#J-}S(;4-)o!;=w*2P@wJ0~>A$X@+9l?}ut>-5;Y57})5pPdR+UCloQe<1O1H z-54~1dV&_kosti`6DR!_veS~AC zir@li77W@yL*lmt0ic^*>n{M0>^$ zK-GjF@F9CXqIHsbiYAo)ea(WWHj*Th&8NlJHT|VSUDPyM4p-+RI&FG(wk3DQq0N+j zQz*&eIuI$slPU}r|M-ed!dn~mHCKK*Q>Pp`j+ckDv7ViXeG2an*$iVte%H{3nS)|f@Tg4@X50e@m>p3~xxVDe{ zcClM6K|BpqF&;~<@f(C1_=jBjMZsE0(9_zIgp-NAU9;QMcD3X0m1-IOjW2o7AB@y; zkavq_*dHkl7w?P#nzh`Ra*~b+0`{Sc=)4rL2M zcW7FLo}5AYCHUN@v~N!FmXp@*hTR$AqKXxd2kPyn-G)~~^N_cOM==%1+e8@~5AkYO#~^pvN@Ro3)cmxkj9#a6W8^#!N*TJJfIF3v1G+nXpbYL40Yq zU5+b5Hh!2fp#^*9?0}Dhugmyz><8iaw)acYTK#E>g3(1}YIQHciRFiD78P?KU;5V$ zU&6U_u8ShkXyB;~KQZX|s-)S)^*Dl0ESbpso*5LjOH>LLvmE*`V!JI!iZ#L-v@hPo z5$i|LcP?qRend|Rr)3!gB^398UH0nU9aBs8&po1zu7L4BdUn-jI^x)IxN^SxDfc7S`EHYHt0L>Y z)6(lIHKwz98h}ykZKmt%c9MVk^+J>t%yV+q339UE8E8+6hjsWcYK4_EnR)EoIKwj2 z!NP5;x6t<)HF1q=dTBTES>4nlbs=Z==9KzjVdV#H-+d3zmKt__$Y-W^AFx34IZm2{Z8iU4`C{)hINVJ7(`*IDwJUH7YSVY2%Q>#6Ph!s~%b{pcZ< z&&a&>lF$1%@Aakj8s`um(&+^!OZXG0r08Rd{hF~v=QDcGz>9~&48qU!@bX6+zR65e z?8c0xh29^t&f#g1Y2Mtij_otU9;5rtE!lbBo{3ANo@PF~!!FG36J~5!v4J`J|9>AN ze{%#1+c5i|z{nT8m~X_w^rzD&j(wQ1{{JVy>whTWc7~R)0OWB&3uh;J6GtIC8+$uj z6I*9|b~+(DYdc3Jdjlhr|ACT=IU0BX$o~+_FFeF0U+r1cK?B(|HC<#HnBBxHpgdVWoKah zKgi`0HU?%U{}*&QotlO5e{2AQ|1T8ttjjGAf0-jJh#R+I{ZNBSk!8kuVy$NCx$*}o zLP3g4k$iGVks@V9K}r%Siez#LiF)Of#x>}mxQhw>G=|Bn9lU0)gKe*zldKb->o&LU z+@5xi>o?w$$*vP#Ko8QrNj(Vs`}UMG7!VLpoZAq|3Nwyij{cSnCkUWpbihysB2KKc zXYk*67{Sr~;3t{17+?&@14EHl?)&EdI49!nJoaMU{x^iF$P2H|(;yS}m+`-&C_U?c zDmUWp&Qdvh|0x_HI9h;rVgqpX(ieKK8(e(@kZGYwa%>f5DQ5_P1N<7H@e-_KTL9_r zApXKUun7ww>ES7IP18Dn0pu}2#kt(%7Jvl0kGr!ldF=f^EUL)#ZlHjEZy<_X*?;Wa z{z-BrC9df)|MBw!WPi`J$o!2b4@Hp|0EF?M2hU)NygsDVj5z-p@K=PU$QAu3?HiCJ z2l$@$KiMAs@e-JSe%aw4Er9)tf)C&UBjP`r4G?Mk`p(}-fl2_T4lMqOegQ;>?pprk z%Kn=oFV6qm1gFS_L-u3+YnC6V&>Iu`Uo1DM09t?NzsPUU3cc_C$Nr5Xm;Hav2#k~2 zBK`Ab2LC8Av<(ZuyUQj1QpnS_@Xv!b{3GOM@2E4#|Gak;8YhGK=Vn;k-B|zMl-&>% zdguSs{SHZyOa4zcpWrx|1^7SRcmzj@!T)qiiNAo!ypH|T-3PGgwCk{d_@8dDkR-Wj zrhf_h3{H}p{K@t&!wA@lybS+KB!CC{f7v5ALJs_=Q&0RQSpRPgJfkV{V*F#}1(d_E z(Ero{#0DYwGXBmUK69Zr5}e^ben2ro&0Ns`OC37Ew@U1PmFaIEcL&wm{Wl+W;xC*3 z3h0KT(7XCyxjo}3@~-?ZYB-8qEvmYIH2~;t@x*2OR|Bwx-n2g9|Ge}9XyJHH`P% zy{8TSPIfqg_zQMs)L*j*1aWs9A^%7Q0LkLs@y~;Bz(J#B(!Yb!eQ5}UvcFaAPrxFD z1YI?9(25P`#u*+7%VkcZyu1u)m(+m+QC> zp{AyCJ`#SM;2nRam@s0m0CX@yW)A^^o2$6#>Y{?^mTmn_>7xIBQx)1D?|+6R`*-H} zA1E2j@6VHGUV9{bSiAM6-t-IckDNgM)>{6uixmV!E?&adw91DOH=O8qMP3Nrzs2WI zj{0YQrKtb?pmO%>6fjZGaF0xXGj^(Atot0(X_dNiM~R{V82B3_PT&v&gug&R`J#AiFFL1z1==;co34m|RJ!K&e(S~+8XpO2!}_Ic<)9Hcp2bGYVzVxF zsq=b}#YgB@VHqwN0WK|OpK_rLIKzb7Mn;veUx|()U021o>*qb2^FCQIXF# z5<4G>ExAJc2?1D!)1`v!8h$Lo`dPvVAyd!y2ee_eC3_j4g`#bmcuP{CI<0AK^tAC1 zrgDG)`IpYADrxxfkB{75ur44zOP)cXy}xM^{Tkn|&Th4`44b|82CSgWRzu`o68Y8S z&I02jwXd)MPKg1zmgqL>3)W!mTfqPBy$ceIqX8Ll&Wc_%9RJU9q4)Q+4hPN2$9uoC zQUiSRxv&+vYAQV%z;axLzAQZ$o+%rW6bt9XCQC8vb2OQf@jK@Hb>xDIWeKoIB4|>m zs)-I3c{@NT$%G+L#OPlQLrMJk!z*V6x}tsmMy1ry$O>>QZlkSoK0ftM$C48yoH_*J zVVSR?`7MYztA|$*HX2N5`r)E)+h5_j8Zfu zDt+6?HU(^){@i;_)|O)ioCC9<6nLwpFB3w=Lh>OyU#+EQ=zws3S3Ucy+kbFr9?bTy zLej*dNF$&_xYF;N9znKyCD^0+-MsKMYw2?WHsf%|uWs&eMe9DZcF;NecE#@Z z$KQ*U8V#NHRWm1BQFO=2zQsc9RjU`a@z1cJK>p%))>AQ0A&Q)*@WQ$eh2BGSHp`Xq zF=la@x-0S)#^m&M4QB`-C|QcGg@0pc*Jw$#vQ#tuZDf^bVXb+TrFKdWMhy9l?nvd=3Fu~7)$8i(Hj9U@+aka-6Ki|`w(xwQr&pFL5 zKOOoOK#l|3eq-rXVgRN~;o=~prUd*W>|zG%58ssoy&)m{QDoayhl`xb{N`wAC#ON) zWENww5M=e*A~|{#z({xV#!&J4}HR#B=D^IA&iiE33T&e5Tu=$QZ8lno6H;|B*BRVq?Y$~-1{FS@?1 z%Y110VNGeB*?|J_Q=ocK=p`$xc&w}zq;EGJ5yA6bwEz6zqm`1-@S`8?LFuXe9TJ_1 z>Z;*)5%xvvpaJfmO@Z5ZYfPnjyX2V#b@-hr7VTp;S}#p5WsHOKmbJ`Gy#c@f!mfB|-e3*^2HIs(t8C$RUM+!Huux?l znv&SKbJW?_9eJVk@~X*9F+E*Z!sz8%F>~O35Tj$kq4T%%mUx+dpvNI$SGj4jHX92N z>XN~$#mMF4GkP0tHa;={w|%GH^04}F&ISgmA-*>AIlg8B$ob(PMOwP3a*V-bX(jGF zAY#oe+(Kz>b_4aa6+&SD*)+``0VUMlw_Fzcv{|?Xd4^Q%CjYVVRa(&5+eRgWSC9C} zgq>5pR)yW1Rx<$|CS&_#>L3cFQ(Vt`6N$5_1T0Kb=sj2Q+!B)jf<~IgYfO}o_1I=2 z(={kkz`#cB`o#7MJ@A5`0Bh{C*^+I>sSCs>Fpkz_X=k5=)M_8j7Eh~ruR#tXtnhT6`11ZPtZkM+q z{2ypc+QnG3QmjIlqD!S|$B8b#-H>13qIb@94bHfGUR}#W#1L|IVBe^X0 zq4Qsy-xa${m2aFN%KWver16>%YwqM0G1-Ei9nU=dcYN8}j)6NLFwTQw%CLX{m(r1< z68Fy@{#FP7u{Ooj$t@lVj{zlo=|j{KNiYHd)o}N{X4#D_!uo3iuAFxNK%|*;R~`5i zgyr0I%iy^uz8Q?3@~ATVKc;r~;nX@`#p&h~uqVj>(l!+Q6&!eG@wa)wWx|b$mJvoo zgdiiskYRIp6YhhK$b=25)Jm^8!HkTcjk0^QU)rzt#J9X`Hwm#9#k#B(Q^oP$k|4`@ zGgdYt=SB%x=rU7PI}a&_AVH(n%X+sjxSD3dg;&XkIEKKGpitT$9+Dh|pZWJkQUIP! zu{Si_8+<1E&w3b7d*R_2Dwd&CDuog?FE8);&0ga`n48U!Z>vwv9f_Y?cYrG1j%}X8 zLA%bdw~%BBUx?6Xt6v}2r0)R4&X*87WQ^1ArJ7XjU&_^A9Xup}X5!NxAJ-pFk(%{i z(`Ns}XKW)W0cdMUCWMsLl8@&A{)z=Emw`~&^B*-V$Z^Ojyg!dn{M_TK`DMwqi!2=h zt*yaV=ub)E-}c)^SGxN*K(1PucSZCZ0Wvl(E;k{!I>SrRvSw5{5ZjdazpSc z=F#5R`4BwWW~I0|x?bJ?RV5NO--@(zcgA7CikDSDHR8-IrUk}y!P}C8$^!2ywfT7V zI?FX}`p(=a!yM&Mj{QWYlKG=Jb|YM2vf)9b({$*iCoGBnc-s_UmrE z>6q<`%6`e|ek>EC#-qatV*waK?R>50Vqk}(JiW(nIazVD3`+|7_s@fOFH)O)QHRsa z&uE{_r=dp7jz~uYuad`VOU`8k%BQa&M+uH*_tT~0Yb)qx-#xLrdd-TR3w2E?6c1Bs zy@-yUCOq@p7ZtVf5C2@c*dsJ;{rokz`$G_QG@26~G1Bd-ii!V+qpOT+v+1^P6)RAn zxV3n2N^xs(rzE%*DDLji;;zB1NN{%z#UZ#m6bY_DgWi01er2t!XXcEanSJ)2fsVKn z*TGJel;M29b6WA-Ttl?y=QnoyYY|U+cH>}NzfZ);#LKnTp_?N&56CVVq59V#n?m0- z#=y#U&|TLUPgt}~+UE^>X~nniNML}D{4Rf;JSJy_l>U(>icC?Ui_m9_dpuE6>Tj>YY_ z{cf%jRCj!M&pNogd7>wS0k3bkkvwuzmMhbeVcs#AMziaE(_Y44-TFy)<4yUG>r5WX zE(2HjzAhjXzbc55xdc%yhW!d@`1?k-RHiXIuR2`*K- zTA7>{EPrVqh$squFkXSQhb@Vmcq88mP(sqA952IyIca|9M*VObpSF=23Wt zIcH>XTdBW)x72!SxnD4D1k?0R-ZGK(mb&(g=>c<`FG|GV8pRCU#6v=l+$j#_)@9dZ zq}5=%1u0c^fsfU!!%MTPjfl3|ERltd zu~D{4Q?~2s-I51ux5Rzfod*19*f*FvTuj+S?7EfX)UBu*XOnn8)To9sSwJNB_cbmv z16guDn8UHTE_9lal2lds3_TO#bG)LYdWjINMOet-@;ha$DzfG=sUTsBMX&K@RNf|Y zyOmUJ1-cGQejgtkSn9uZ$DP9{9&f#Zi$%Fl4Qt+kloh|Rm9RK_9c5lr)@9dxB+~mt zLM#MlIXIZJ*Olp72);C@?7|r;kOV*kBckJ!eUpV)m?#(l>sQaMA|X+^PP7_X1wN*7 z!%;yE)rAXqL9T0(PdkdAd^j2yq$MFfM`&%U9#@=ieH@*$Qc1RlOELwHlV?L+nnoXk`8>Az}O(RunU@ z_xA?`z*(%s`<54Pl6zy;z*QxZ&s98254`_Lw(sXV)wZxCN{1UnIbTMbJO73`iC)cf zvzQn9%sv_Q8e3=d3yAZzlKzLkG}%Q{CgMnBIV7gaa9Q3)Pm^Nga3Ec?|G9{}Y5gEP zXh0Ep7r8d?!^*W3kcQAdviWR=o?)sfHnfraDj_~Q`6=j7`^XEl!HsgEh{1lEc zB!ax<=M7$%Uav`cvwJeJP3wjj5M{#1J^iK$#D|MEDAp+W?<*?(2OE&a}Qsgc=(sYmey08w_Dh~W>C?w^(3WJy-lY=+zfemmkCyl z(&S-*TLWs>3Wg-+hiz$k^?&-|{5n3zKfH0t-5>Pi+Lc`&sRie^IJnn` z84Jc`#|pgM;(nOMsAqSR-CWB~bc9gKr3(Ug*%fb||Lrp*)oh)-uc}+nRPk={I_8;% z+aswmIVN#)6hhba%}kBdZ%fMhmuS^j$6wEP*dlyS{6wE2KDa~n7m{^03ArIk`9(fx zIWr{vi!s8|9Nrm?Ob6D3x8Ty}$lIOw96svetuPAAc0QeZvX!Ehr*aF|z$;(jK}_GS zy9-4MwmGNKb-}P%LbVG+9vph1;lUF!=4juOSEtwdR(HWM%1;XZ@dnAX*9|3J_lEck zxWgH3`oXFj){}(WhyIx?0~h)*&3!2eZ1bDycMUdLpu5jR&=V}H=xVRtw}$kly*kF4e!xl7MJ%gtzGjCsoz^SZ;01G)WiYL zTcfQR{KpuJN!H43SF}}j7N!35P5-(4ak{V$n@f3?K-1O!e3e0Jr0`Zqx?OO<_tT2@ zedoLr^jaUrry-Mq*;j0c&0|B>k!b%Y8*TJ@mN7%;bI7@e4nRuzG|~rhn5#b2l7c>` z@sEIG4s3H(!6;z3!oNTJ2GcK|RgYHFaBeBSZP{Fw#|Np0+s`!Mf22OW867}jF(N! zx2qqTMz)21;C=`D*)HS0jZ=dm&NB5zb@N`@*p)E51i82>r__0FjJdFd81_xcv~#15 zVKLkRi>{p;mW0?p^k=X>n%Il};$hf796mWq8^en&>h&oY-fUj%>6po2ZPb~H1?1`LXv5B?E zdR-9^Np`!;^~}l{(=wf8?JY)SGz0kd?YG~s@wpZ0bBKgo+B96@XmB7aM*i$fi5+B? zW=yMl((KY+B6u?SLBpwA+eU&`gp=ZSB4pXD9h&&m!zycI9%=En%n9>Mc~yIPVTTA? zt=j0NW{|(aNEi#JihHWSi2KuRWG#CRFZn2&0&KbFK(og1@1Zu!i`JxlV@DxatBm;Qa&N_ca6S?Xk!jbnqA@M}rQJDd>nX6ET z>O8b0S;<=diPA^ioaB>jnmn6!O{>c?@fUU$eN(&HB6Ocu0}W1wXc7u7a0y}8Cxt>C zKXAjt0#!{3`ITpE;wtR9=92l7Kp(GNxi9c;;@PqSYGrb)Kr)xL_e9sHeC>8RX+8ST z>;c;g__#GDoPMqjyJ_C`p^aH($kx7l<@saC%;|(a(vRz3RQ&m9fbe`x$Q9aE`+Vfs zDofL^u%eUB3B|UQ&TfEj`!rFm8_U?G2Qo0vFjYs|Q1NIxy->p8(CkLSDAfBbN;Fh- zRoIR*7I3q-|9lC8X}bL?Nv2ljnXPr)CY_?KbqT>+vfqwB5)73(oIZ6+AzZlv%TiF# zj#fGCN@k|nLFIF5@0RXH39R@mldqKzR!aT%;8a99AF^`Yzd7T+a}x5r+YrS!s*Xz1 ztHB&YEbKolWgCCUPChs-(t?vLYtEQUy~PV)^5Yfd!iT6QRN z`AHBeY`aI%Au9JuO2@-t3aJJWpobp5pruhUrS&`UPpg~@_q@UCX{Z=ylQBcf;TUxC zZ!78fw1W3~anXpueMIKT-IXfLy=6XYsOYDq&X@@PmmMBp6{wS2xKHbXm)(OOxA#-wlD{210h%!T(%`y*H=4%II zW+$In0Gck#>q*&VDs&wl+kMYOU#;ctqZWXE@oMs85c6hu+Q)W7@Qa?|jF`U_g&kR) zeCwfR*^TsRCbw>UCo>^ePebKsgD1GMP28XTJAQtjcV2$Zn&a%g1AEOMuWq{3 zW~W18`?}O_)vuj*PRn@h7QkM&4qiUF;!-fpaGqKiP8 z30E0`bxAH~gp!j3U#IKh9X5GW5v6E3CLyz0t1(2Lc;56hD(*`mWv7up;O@lrf8!{) zYEH=a@R!-c4aKADRe$s|g`!XEt`_sS}8MG9Y(O$${;7W;RCYW;lLwd2fdA(g(K zgms04%Di+ut?W6b+H+j7LJrI)X2Fb2(T_4K+;z@JY~TDKTL&wAS?x}{axv`1U{_?j zb5S7e$BNe=2BEnGt00n1ncX=M)(-1ms**2Z{v%ODA*;xUo*KxsUVY z*JsONRM@C6kSvm)_tyMF4p3g-^gx(`yMgErhwxWn1@9=F|C%#Vu@%M2DRY3Kw5bf^ zj=Bapf$jV^i(9+59ngFnB2Jc35w1-)fpx*&-*V*(Pw$rvp~lQbtDRK!x}8;ffh?p~ zN-pnfI)S3YT@&!Pg(hPFwvpAWne~l9@5VChFIj*0c!YgkaA*O=;_JZn)R2Qgd1U!v z5)eu{toe5#;Hf9i>){ur74*KxvBGHK7LawT>rqowc3gh%J(>=F48?(%5-YQ2y7h3R;9sSkQ7d*l@reZmpiR9QQZJix_ags(TM|mqUWQ?kbY*fX+BDrb zktY@S)~zV!1>nmyv)6_EVHEnbHP+q)+Q47%jjjnyE@JWXy>FeLQ*ke1(%y z2N55xhkIJjvB^Mfpj$bir@zH;ZTXf{WT~FCz3X`3Oxx3folr?q<;Lm7PHoERZQicV zYdKbVcM@bu9cHH~_3vc^=;)~{4kD`lYaOGRv&?)}oTuphd$5jVl|Qp5$tcn=j>UF7 zf_MB9VOo_bTzmn?F4cE9hs{%Vl-{v zCHK$y9=S8}2xzT+OR-cQ578A%6?LkEy;qt3rs8fcrfY4Sxwws1#twwqc0?|!8F+qh zr>QX2j&5e8k6H0Qr{8tg2dLjl8225S22x%lOhazJjkvGgJisW*zir4qRFzl1zVT^} zUfS_H*R7Yvl|Yt)BTU74TYHOnF!FRPa`_>o!pM>=&2Ju_HO z5*7CZJ0G(0atK&XU?u7%969!d_N*-;x3M}6e7BE3O(?Q3DVGFb_!4#sh%$ms5V@njAkheO_Js z562O@{|=Rgum4z=@#_+PdBtC|xrO6Za6ct2P`-7^F6j?zVj2OGLJa=l(AKYxS|doG z4vBOa@DTK@ZksS8F}`POzeDYFvpiD?XR={VY+_P2&N_L4Ff7GSvyU7%W`B)fH>c0V z*ekVJ+E+OvwExSwL;R6j@2}sNg*f-ukT8?pYe6zsFG5@2fi@C#>6t)%6s*9WAv(@n zmr8gCiL^$4)*DV-8VIXm&x|kGzbp)QUeMSFPFhD0aAC>VbQSR&0v@NbVL={GX zb;8zg9T3G9rM)|2HZAfYw;_H4%ESG0)XlLNivmkt+M9)M`!%afq*K6eKaI=EUkRli zQVYrstCH6z*14-9W~&{a=He0JW>P5+NL5 z$Y2?tg;S2_YcC{7ycu=e#x-ymPcEYer=31K!iLzw+%ii$34<>_xX5SdP0wOZ{_^{m3V=z>eVf3nh3qI`q7}=K+LJbtVQTuD5CjiWza` z2Dh{eB2m*sgLn=jSnCl>rTSo}$frcPvF50slq;@#4>o#(3+Z>!Bv@+$LJP46XQdor zO)0_zH4oBW6$4o(gdYLfc-7@yg}AH2n+aG{Cz|iYKW%c{nOOxNfjKHl^8Y>$q^b33 z9Yi$RL?^Cpyb_kN*re5nZU@`j33r(F|N0j_GX3}F{UPU#pf)!j-INy{%Sy#p!(@kz z!Ae+ZLKedJ&|qy*f*N@wu==2N>py`c#Cpi z(}s{5tL;J`EDAeGq8rlu_(K66XOL(pU%dQk@2v;dPEdSujpIG&yMw?+Z``R2O=(Ij z&-$I2^61UPVMmfXkxTKWjX(1XPoH&c2$)$~SUsvj&o!65OseC`9JMIdvOfu|$og-m z>Zj>gy2?Wi^;Be47|PiP$=G}M;X?i1L2Buu-&#MH88;%@OUPrxd6k#gPwnPM-xnUA zn7Q_FfuN9>Hoz8%SjV&gAvZ{L0A-mgq{)eOuraP{wn(ihVDgkokF6V5)H7$jSP3bO z2%uD{^!NkJJ{JAZEqijO1T^Dc*kE4zuK9hvkOy<}Jw?=Mu17C2WX4cbf}Ko)ihUuF zQ<|}jrDdEOe8sVt(lT#Ln=3rD{QSecXlo`fsU^4iLuNnO^)p5l--t9REbEAPORwqT zR&<#L@?}lU-r9R`UpIDLoH~7F$w-r?@70*Q-(A>QgD@aQxTJ+Kccg}$bURr>i>Dj< z&YSWy>@SH%OO!xQ`2eQX5Ud{r)upH)VEI>!Hht|An~rEvrd$zHWF1&R3$s9Eu&)Vk zgPc?kO22V|{hn(&6PB?pZ#x^M*lk9N$Mc9EBia=DX%N|YNohP6?R`2Jj*xq*rmx2s zxD~Mu^CMWs&vnV<% z*!z9@jZz1-?h%pf_d=$KwK!!z9L+@+Sjt&#NpfgvPOuf#6;*P&y`|)+V8go!y}mUC z-cX^ToQC0uNf-}yUE~A68x5$7O`FAO8DGaw_NeTBLm72>7L=>q8<5n(<9zvJG;MKR z`FeQv_jj{BqTeC?<#lXM!Httsu{C^uvFk&!O|5lXt~5`eJOV%6=}`^NV6a{Fku|jb zQNXIqh=NY|>Z5%LeiqeAukQeEWcVAF3}s|CZk=bLMn(v^)q-YmpsmluunczB}Y&R%!@V^5o?R543kmW%3dBXz7D#YX>b;p7H>|E{RbX9 zp%Ln`)}T=5B+IVUR4jK#MsyFJAM#a%PMLV> zEGeqH>p|9!U9o)*uX0>Szr2C`tvi(>(_0Rs+^yexh_AWypl+*_}|*GeNRXS}NOl&W*A|aP?ZK2)wt#t{5`MD z?S<^t{r`ZW22itd%QuVqys~It_qKJvt|d++KXNq1@F;6U+QbVd^7nCtKsQ)ce}v1& z00%O@3uas6C!=`bzkeQDFYhu)WrXn%S&BL=bRphUqz)NC55Nu74IWxYZuH%%7qrwz zeKxFc-7hi)=_>P6FxATOAYc5Zu_7LsI7_jfuRc-t@PzAJaIwe4Ato(!+c0L}B`L8ws`7#5&HeLyt9c z%_?k3NyDc3GVSnc;^vT9<3C`0OKR)K=40-_u+Mm4gsKo(A4oL!#Wj)R+XI21G}0jI zYx{-BrC_t?SM+|qPb>T6De}@?YX6+)W}-_j**+A@GcKnfr7K%HZK(4H3|Z%wyJI9#MC-G_{3AvtNh6p{;--sdn9BhUML!U_jDh>9 zUe=^PQY0&XH2mwaC z|7&$GH91&L-zc?B9T`K=npP7QNiwucMZSZf{w0RLINkw0s7*Glh?0?{xgb@B-0YRs>wWE_iPli zm08QwHK-PV%&2bCfXwTjlA{9QzrFb(pk>R{x2Na0P2q+oyiQ4HGEAzYje}g_0LCKLIwg&=y+wiP=i+6H%wrB?0T5vQ`?)>-q*n?{lMKPZ zTQrm*Da^~|S5Pf=0*k(*s&VWiG}(%E3G1ls=0`ur?#`o5AwyP=M7i#U zJ`(Yps=dTho<{m!5LA1)z-sB7ts?XC(;$7tj6%d?U?9V_$oDcjd)1f)T!|Sj+kRG^ z!c$@RvLvfH6TEHj1@|%Ytb*AwviR$2LL?`NB%c-fjOkT)GEAvdPj-1^)epceZaBsa z1gTx;XAg=+)`ybE2q8xxKD$b$73j$N?ZINuCc6LINtKXC9nFT~We<=qoo3SG5dq`_ z9BYW%kkwM%*<$>QBs-u?PDvHR07&z8eA#fF=GJ5 zs+aym+O4{gH1^v3jv_yLipeTt1t@J3pPpCyY|8k|I(6cr&zd2p7pJE4yCg`Ree70m zxH?(zI&z$%s1jGs`1#_4rf#hWr1rJBfWOi`r@Z0AYYu>nMgGg-{^g{PdcdEjG{>DA zS5nK7B$QjZ&@; zbyty^MpIS(1}6|Cd5w{EHl7y=9-nZV$VVSn8`oOZcM!iKy?#}zCg?i;Hl1}DZpR*% zCDD=Ul_Fn#j0@CJm8+D3fGuD}W(G3M8bfx$Ox^U5mc7QN1{;Oc=h1lSyD_2DZCb;- zr~)4;Qx4&G+P4PTFEYf>#V8LL~V3r!)rkJb+Bj@XD&I=y0%o$4@bq^OzZSIEyTa*0UI; zkY(sMt#an>II1H%Cj)LOV;IIJL<=gHgr_z zYOwg&o2fbB%QS@v^UKBM_bJn2=M(cUhw#DzSq9jhlN#H^?)>J`%~LyKQPai%xU1>py?2qMux~WW2qNbAwSzQV#)q8SOwSL z>xdQl_&pfisKCs>{vOxHQdaU;)%@u908f7WQU1Qebp4w*!$)uQ&hWVqFbB-TVV^q= zvAVo+&x=}oDXD%G8?EOR`naNoEy=Hy>~ncQ(p8a#YqKc9B+<}SWPA`kYJ}e7=u^fc zgNb{IJ_*q&@EYRZiP!!dR4yFQ{|P?-H?`{vOZn1!!JtCcJgYYBCp8+UNWWjy3uKgp z75Z44GQOHfmT9_=zl2{2+`ZLJTy+*Jy8KO!yN_9rR}#v&K^Jk7_s_Vi|A&QcLzrKq z=6gOl+B|(A^TLBSRdeL!i_Ukcm!fcTx0qd}?6VsZ3G91fSDq*{o&0KdE?cu2VC}0d zeO4m;5%wwOe{#IfC&P!_u6H4Z?A}i4?Lz?D)k4dI5X3&3L>7y7+8J?zTcE{F@J~F^ zfQkZklQ!BjxPHMN8rs;IFucq=Wu7g2in}(O*waYF(Pji$*f<~*zBJsN!5gTA7ut$h zwP*5(5`wLph5RWIDy%*tej(b`dxTj5^BGHTwCf)pt4?QYwC8NXacpSdI$;fcL zN9-hg*Lm~22aqC;RNLh00>UpXNSr0#@kPE^1)(3{BsMhtF|WFYG^(Cf(Y3 z6?EuGj+aq$04Dvb{$cs0weHx$=Kr)6jlS6f2nmSl#PNxo7I0&h^mFg&ZYG?ZLflWg zuLMdn?*&*MsUDJ0w8pR}l@L@$vPdxE5N#kwwIzMy>@!daNteE>$lppl6_^M^E1|d%^!+ zNmuWDsn{>PXJ60Bd6z*Ssx@+n2xsTo7*L21OJo_s#d&@98P0+%4~>R%{y;?`A7e7< zNquS+PK@;ER;n-6Lp2O<%RB-kKmJ?G65)s7HVPH9#DVgj6F+6YiDUk7oSG>5dZ~km z9pI3j0$8`s%Q)pMCqc0xo@veHcCwE&T7tAD?zEdt_m>TId^h}!gXT-lQVl~m+vfM! zlr781UEe6~%6hj+emOs30tV+%I{UR3NIs(t5I;B_UvR>$S4P_!oettnOHJ4BojGd$ z_4Oz3&~gNw@7j4m);Pw$R&qRCA*&@n_TQSK*IDnL71{~&NoamFFW9&5=Hv$CSa49Y z13Z%rD}C1>J~bwakd{;VnGq<#DZGW+eBX%c7I<-C!uoesdUpr+|>H&Q|j*Bd?i42w{I~{U#YlbFG5Dk{4qeFZstL&c^ccFO$O*%t`{dmxlgHn#rD zt!qGT2<>2z{dcj~HTLxrWJB68F=h7F@TOaul0*8!E{UOb~Dm;`?r`3CAKh;CCZ1pAu!gZ zl3RbNjkuMg=hE9#p-I=Z*MD$c*P;4?KeA^2j)y`UT7a9ubW_>S@5I6rZ*Z;2wmip| z^5CVH6sxBAFIg{%zTve^kFKM9(aOQT#9LGWQ(`3LN-9V73`zKuup;o@1PQ7S41nl2 zm|VLP=`YtWKEhdqzWbARU9Fmz!o!@lvAhzK-+fhh4aq>)xE2Ef4h=J2 zhPo|l0t070IJkPJf&@p~{&&6v!Zh{$Kj<_Nma~K>`(oT6)Jxg4NRJboT#A%_9|u9u z9OWEYaF3x}uo;s=NFu5dmTSgf%8kXU{=le1?}OJOTlEACZ_V0&>H8|$ zFMix0aF#OA+1o-55mue|NExq1aq4)DXP2rS2kDK;bT=--c2T}R*jY`~zVakF5r=g+ z5EK>8AQL4uc<W!~EImH$=jjc8=iivIj zo^9q36o!29yVo0iOZ(6&R=n!kn1|3(hS|-gMJtl=%Mag(Zv3`__e9OzsLBXW58rqw zt+EAG-)p1h_aFPGpCA1GbXIb{+|KDwyWmdl_{V#deCTJ_mrM7)YW%usJLu4P)~UY# zm(c<|bLz0ot5fvDhS@LIccLzYwlU0I6~S_S8cR6!KO*qRv9l!gJ}WT5FI*}@EWnyx zNEr6S%2(Og6TVre*IwZukG+c4Zhp3%M;1~Dx8W?&AY~M^zuFEU&76D{Y8!8xaa7h4 zGDE_-vV?lRszSdso3s1VgOki18m-0=Rg_lzrL#WdWQapem2asOLds$rSzecePh{P> zk1P3l6|inG*~d*v#I2DLSdtl?>VZt9Jc@<-uyGzz1!Z%57v;Ji6#6{==TJTZhE+m3hzOL zv8M^E;R_RIzO~zFwc&WnOUt32DGU6B5%*D0vQ8GPs* zF8geHljf77w)x@t8le9>NaptEN~IWP$J_97l8G>WM_zreXd;MO9WQ=EudoWMtQ-;@ z7YC;Q%?3B%LV+5*2DbmtcFW3BD2IE-p#bI+t^SbdS#jB$3kIsR_uQ%JWFk=_7P>~V z)+eBG*D1QG#xh$)DY!Lpfhz8u$>W+WC#S0f05YR@Pjf}%dteGdqqoXk3wZqM!3?|3 zlMGd1+)O00#>t(q50dI}lnckv0YM`SMvmVd;Mvc2#J;pY*GS{IvlS9?EKc3vK&+i* zhmfEDN4y4y#`ti&$EwVA(J~{*CTr|^D;LlziegPQXO*OxOrw{WxgV=q@P7Yc`OH$q zK$N);t*D#D^WfM2wN!F`?n&4 zStJfW{APo9H0v9y{-E4(^U=tLR(SE4YQJ*@ zg4R|^vtesBRHffUI5Lq}Sw`aVspg+%0WfEYSgtwtf2H+;%D&sh>GCD+^820M7WykJ zLwCVGr;K8W^i)zqxSpy^JYR35VY|@9MN@3`AqB}PAT(I$$Q`lw*s3PuUj9f>Kq(Zo zgn%TVqAVPEpPlqY8`k+6QNiwSKN?|4jVwlT96!s!K;J^V&&$=>3JgSgc1>Fi+=K>g z1E$!-iHyyY>;PwA z;^8S?=ikEhaCDTRmNgwR%=XHJ=sWq6O8YDC#P9RdCjp{cZugCXs)x){g4pbH8_n@R zF?%92=&9Vd97M%XTC{21(W@1fhFwp;d#v`y1c##bKK{N#Jy8)WkIW@}*TMgBXS(@c zMtYlMC_oL1v2AG$s2SfM7-QR`7lr!j768}{fn&ewo^m?CrP^4UBZV`2W*=0^Aiu2y zsgH09*5u`u$B=p5fWuJ7b;rdV_A0%W-pd@rY$TBi(U#}1zLn74XVlIyJg^TV)@X(n zQd|)tL-NHX^YcEPamR>Gu#*X~1c(pCBd}#u>|mYLEUxiB;y9}dN{5v&-^(XSgaeSp zQVs9mAo-FT8zI>qua-{@+w;ALv=Hmo&ima-c>n}+aXqGRJke4fK;Mw+S3i-0P(LZE zup;lkO}7%L?Pw0akD00q!HjvwguGHXT9V%Pa02V@bFAv|+7;M0%0C7pjaEevdRhS@J!_}oS{u#ejV2w$0!$-o+))?WKR^;Lmu!JhfcZwgeD z>`FR@OiaY($mFP0DZ?87`^LEf9(TG`%*UtQs!N|Z%#toSr8Vb5JCL^ssS$H7P+A}4 z3;l2gsMGhy(<_q+zo@>)Cct82tnbnCk4Zyl3vsv+x!X&VD`@{OSR2{8tIMwbY*PQN zlRO_nXOh)Nv1cI8-Mb-34H6gK-ctw%#~!|szYw%hnsHO~{A)X=d{30}$xx8Pz zI7&~!H>8YYUAv}ZRKE+I?8cNvDPnmoJlTo9df)Zd! zGNrdrkTV~ILsO;Z@yG-WVhoIeAU;iT-6B$dP8I(?%hvcEJ1wcJ$kS$4)Gh*Yl3<4H zAJ@^9U!i%tqP<0t@XY+KKk3QAq?Gr^iUrIFQ5=ASx%f}u6-5iWz~;M0iz&H((fuMA z0P5*^@SN+d!8{%u4}&E$8=3VgQoyo$s+d+;*QHJo90(r2tN2_OfB#uvmfGm5eWEu0 zize}&Brq1w{8J=~LT3fK;~#JC^IQlpo{I~}+O*m!w^viF(DV)$)?)-ISuAdTEuPE?50%W4%7OSg^5HrPqD5JTb>QE=9FJ4;C73v zZ(3(Q0|}1*N3^+&#wVAX%-&3S^Y64MSZJ;9UAMPf_`qoPry)_)R|}w?@WtaeYO?$lldLyG&2rzvU~N5Ba9P+ac0pE%B@RvW8YHzr_Ft4X zF@0mo_cgc!|2js=si6|pEV2K^muo-j7raEy&fpjn3-PYk&nN=4#I-YvGTxM%8Vg^e zx(Oxf8rPBK|NchDeUf*Kwp$i;{EW97R=FR0KTI9PEr;x_}Ydb97!yOP<742PPw<@2QH^+m_E;_0%ooZr&bHCslLBnQAA` zhEg+oA+-z&>nnPQ!c74P!J;0d^3v75M1yT-tz$HGj^~6rw+wl+plm20$Mp}f?d@oA zjGv#Rka1(>R2Ts?m*9S_=o6Z#KIj1~2SIgS@ z-dPY-Q#$JduWFj?;BzZrPXm-fZVq~H!KXxAlQKazARG|TYc~BI4=s$z%<3KvM!1SikdT{4!*$a z%Go-O{9&bje+`@&B1Pza^Y)C@maF2lIwP<@UjIG$iA@~wr^ZKfD(3miE|)^2w)i{G z#Kib);z_C-=g=iVC1m*#X|yd%?6Le|4NkAYy9G;_xi8$%XS9dh z$1K*#>c+BMO{lMuMB=hQz@=QjTgRTNX*0cOE#BP0Mi6{^=rmzG05|$_(MU^m^}F+= zuC(^K3lZMb)VNch49z+a7vBo!O;*+CZZMPcvIx!{@7^+9HfGRzzua!;<48s#Unt=H z{LWb8!#?j8ujBeTQhd|xUu?rkzcvu%iVqZv6<7tp4{0k_sw!S})K8h*_7~Y|C?qq6 z;AEU;Pu|qPT)wuXXA(<^+6!#42_;aj8(+oAbXr6Cn`BeA165Iv4#yN|H${*8OZSCn zpuD=6bme0oO=bkvH6w2AN*}pA-Zxw~%M0QT8STIBpIaK?quNDHIF_~_hih3Q8+d9W z4Mb7D4*%Y3hVH@GS3Mb!*7$o^2DdOJ4ix=a<2vA8Jc?j!{lQgcIN8j>{1pr2Al`hM zlCt+;O~oUm-K(oJO7wSwvhutAF0MlR2||XL7YTe?J(Jr?720Ky9;e>(_fO4=NYunT zd!i)XZ9mBJ)?Tm5!ujq}?>0kzdFOsjceBfQZ9-QOdrlMc2d&M0QYD~>31Il9zguQ{ zpB6KHw9!CaBJ`C*&P=NZQCP=DoEl!+@*c8tWkvcOy2*vS;X8_pR&0gX2yuO zcWa8(V_SwSavaB`<9sW@Vs8d%FV8)vB)i>OZ1mDdG3#s1c$)6V6sC(U2MaHsW={G_ zD+)?7Y30rLL=D_oum4F=XU?Nak^Ek4j=X_)ZPy+@-Apnq{p)8G!1BH^5ji9NepWjS zhAmVZ`RgogEcDWZ)0bwSZmRzMaN?|hpQA2+c_b^noZHKCL|M(s?#d}4oL+-um|u-M~> z(vw9jYP-qnYS5xdFC8oB6hEScYNPCL#!rQOEWa6wl85 zi$5+YDL0gJ#zBp&hpOW!ZB+A=hccjkoznJS+047S_sF~sje>X9WC(J@qee?_(az`w zsjHvY9Nybu+XkYp<%dSf=M21;l+E= zr#MjSLcV_m=@S1oJ>=&NX`9&bh*z(e8=&ZtW25l+>-Q;KH+$E1M45t&_F>@ftX%~W z8^NG|Zu*Zo`|k@VI~j*Jgzg(RD~=OZstlKEAqtwdLjr(G<1E33L%KTqXJDGdC2d5k zhQ8xR2%o)+#RE29v8zJLQ>&3m%(H&6M%I$6Rh`>QHF*F}l*sdn<_;8f#Zptu+TrEJ za@``b95MU$9e=aUe!}cC)$n=ec$I#U@-g$#eWAWebp$o?ceB-R+*^16O(udK%BoAf zibals#2|Mc+E!iAyN;}E+hnDBNuNTe-Kq9lgW7hKHsL8ONgck^*F7>g<{#M8!CcX9Mxxe?&L@FQY}+xvS-s#%@}|#CmIE8KGM_OS|95Rek|Te0%Z;A_GA%w4f&70n zu^l`AOSdTFizGV1B6J+OGu;lrI5yjji7gfMOWf`jQE5^OQF#Pfn|* z?PyU(9jx`oJoSbXw=9TX6IFmAJc>C+y~^Di_eq>|r__qM=Q*16Db2V)-i^Q0ggR#cHIV*nRGAtqLV)*ONhTll> z!pSR4xN#%)4N0x|OQVmr>m6DFy*uO0AQY#~ zvo8O~*q6XV*+%UTDI|NPvL{Kh?`yWGB$a(9k)0UEzJzE&WlMHmDSH~k*cBm+WE;zn zWF4}NWi0=D##C=_ec$)*_j|g>Ip@00bYUhM299L-bCu(oc zC~Qb&Cf#b)U*WEAHAvlU)@i#wpJQWuCEWG->aFOA+HHlwgOYs0yxFlR)VFk1jw?mA zR_WI*yltKatHDguY|?e5qbp~iYa!+)v_&YdkUlCqzUZV$f`Op$JOhQX7oIx)2^+wVOtkV|sGk~fZR&(M#iR-{ULU$hN~Xrx+^uheSF6y26+N}3Yc=Lw4%eS_vsKM#X$`)aUpKqGI$+pF zKAUe|fJ>XFbTDk5|BT{~^FUm=Ed7n%r517?=7}njI;SjQwFE99feA!jg@LY|y5Czr z6P-kzz{D{Mn&IB|Yp9L14ut8f(oU;qeIzEcVvQ?2yH6GC%Fj?c6pMJ17ni{2%u*YI zC_FL9mrq^sOv2=~sTGFD3Hmle;u1E6ovKId%T>WNjDYR9m(56U@Y7(`^RHtCTlz2N z-Ih$Umo73u&sk@cpV63=Io{7VzVDTWEgfx}X7D<^0Jg8N79k?|@#%7#W`zd1QRh;A z!Ag<>azw2c^9nVyGwG&vy0%ta#ki+e-YqcrzND|D*-V>*=@lhk_2sFgGhFdY)zBy% z%`3BN$LytOr6opZoSIH_vY|`@#QipDH%%YDV?ICqr0Z^6dyR~4aha<^HOamgTo-+0 zBPIEzS#0IIL-cy>lJembOM&7&$r}2mi8)b5pMJiq?d|n$tVVPsU4irUHrCA5u%-B<+aKsx z;9}r4Wuf26O3v=Kx`s)z4yIs)jlTB^#ht3yYefAwjSqAcuSZ3y&4zX)(&|O z%0EGJFC%gHip62Ga%%qsar9f2?bUw`GB z5u_^=j>uYDbrsb<#URkmbK%-ci4xzD$$9~q^Sx{K(m9KQGcQ-mHL3>+IG)VF^jj z`A8wDFX*Fb5Be%5L@+q&BByi3o4v&!24L+{iLpiNR403+gg#`AF{SHlF85TOI0|jZ z*&ug6r5Gxz>zv@2!*YNqgs~Yd)Flklwzeq0nWt8=S<}Ewp*^a9;R|PfM?M z%6qKaDMQx+=y~*)dondi&1}`Yx+FvUQ9Wn6+1XXk=JthE&G4+Pqh5 zk^0_3wCA~uOi`MtYld5&FMCd5Lfc>udSNK0)xaL@*Wk90x3w`>W|BN`6iEwyktuVxxNLc^oU%tdX*QiR zxxPN_uW#rYM$1hnB%dV%zm`tj0C!3}m0fkaf(@W;sS?0dQ~AsWqMl1+Ue+pjnCmV` zJNW#e)AibPEXAwbyHX19CMKDg;hu?2{&|N*@D1o|WMP-zR87kpvEc%Z#{F4)P|rT! z$Q|FFiiy;x(tTf2(Q^BSuD`yzqP*IqJ zvnx_(bE;9}I2t};%OPa;HSeL^ly!=k)yt{P^5*8#YmDaPmRf@}UnCK3;8TCbiyQai zpyuIRdE78TNc{fYyw#d`@nWVC*C(kDhK&augWAx~CNNNRblT%Z$GEYZgQG@iJ(Z%g z^LA4SNp6O1CrT3rg>bdFJguV(692qu`s^uPJlWqrQ^YI>$<~u#`?~aPu1~^A-aFO% zYfEm{J2j5mT7?0%@$=8^#BrORJT%}^7|QXBtVBdNB&Obz`KrX5y;F(!l=aCtd3X6n zO1$W{nKOqlcnEkCNYE_Q;bWMSIw$jNEPTE@cJ3JxV92_5?k4&9Sq(|1G0?+fXEGh8bN>NNWTAIb;mF&MeP`t? zZr!qBW5DHEM{F6D)#+C3F5C?4+%WrQbh$#$mI%vC(+2XZF(7Fx=LxP;Ynd z>Qx5nSBGEq-0fh-Pj^p`eKU3LNK(_1IWL_fo*a)6d630^P_SnAXm$^W#;bR0gVS>q zB?|dxeaRB88Bv#sXyk=;MAaF2yy=ryzrco`2b?=I*HvM$`cY_BiBKGc$6PjxhSOD@ zH@xDNhPYFapA^NJsFOcG{1in)-dah^HiY;--9sAKZt7CHBF5#Gyu{nHCA%}mx?34? zpOumdzAG2PKF3SWQy#x_iC5FUpNSVe+@Y1M$H1F*LpM$H4t*p0zK$dJPX=|zYQ0kS zXZ?p$_MYh(f3hfTg=~Se&hvMz%*(`IUsK!SH@8^|k>~dKawJtXv1r1fmYwQ&SYmAS z${TtTUh`@HSWoEGgp4QMjoE?y(*iqB4cpX9qn4#^F@Z!(kqUJ(b*1|{mRCkexrfCi z+gjKs>c}N4KU68-PmdLR?z;ir#fbY@g=awmm>-`zq70b?u>CU2n=K+aQ1tLqQ%lH-B2`+V zptiJeG5B7)u^3-dp!qi!s=zI2U6~WUJ-eq5%OoG0F=vqVtQ0w4kiA=zn0`n7(1T@} zawnEf?~qcrdYC)>T&+#t4s=IUC8J8RjjC^kX$RbAerSXI`1Lzr$|3efwzGYA$y?3+zLV`K zNevN~lR{4?lsZ0D)DolF>K$ zoC6la&A!}|fBlV3kK0&LHDYIDwy1Uo<>=~Mhy!AexGzpbI_OgcynN-*SNMDl(RGBw ztp%NKxSFf05*<`pmTy#QzlzS}+f+IwwNSFDo2N%POz-ElIs+a}n^L{=2X`Hu{gi24 zjjB)cvT-p(U=!GHt(CU7;2jSN+`Y3l$NVs_J zTDoHJmLXUJIq^6SyD(Vpf{W+heXhl)dP5;Q_Qrnu&u8>&hP*FPQZ6ong_3BpSuYQk zdSZ-RJWqb(OEwX&xB-^e#QzKZ_-F;}48tW`?t(7!9}JvlDhvB?M7sto-S>)-{n5K; z1oz6m!7_rMhW68;C!k?qWQY7549A5@Of0jvqfheO%qs8RW;6?LskY)c2B;E*}?q z*%$(cj0>>Wbm&A>BtCmhnW2-l)$&eH^gvMY&=vG|a{X>eh};+ZZ=W1qu*K~N$6q^B zgVF3e+RaJ{)=E_*bB$RlojQB;Ky**{4yRqWtjv*ac7o@W>yxGT)!a-6z-+t3{>#IC zre1a)01`y;?c~I)`xBF6=WtGXTm?H9B|m+=gLlX^c(=kvMDJP_AL?hFH!qs&s$w{chkx;nFH<{1yNlH>Kt#m@f_Z>x6TUhwLnzT;Nx20*e|$=opbuj&6N>6=r-fdQY>I!_{kYpeddm+uAQ{p#6TbP+p~qAa zsWeOH^Zbm^%Zhl%$@?*8H4h}1Q>VKFcL#QhRz>yzmeQ9t)Q&RHhS;>cd$WrUGJIc6 zOAwVQvBbxqVpspmdXlCpp(WSXdClvupJ?FlUXC8xolJK5evJuas5^Ro zg87=R%CWJ&`wLu72#Wzqb2!w9I*~ar_1W92Pl#Sq#un zrSIKeO?I;;8bs6x=ORLEh#cXxo5Ov`*HGTQeb{!#!&3AK06-BBoL)rzVO?piE%8ma_#6_wP6xwz&B5k>`S(v?xx+r#@;M)_o}KX#7&zoc$Nso zs@R1{FHOsS!}U8+3D!1oB8Le&$!=!*Ntzb%9b#_w{pOV@l$DvGhzFdc=b6y((lkCM zVP<}0{jALm742ZWUG?PE)-|ZL>Gl48tY1`upoO_9-b|y`s$W`EBh=vg_1b7&l-9Ec zgla{EZ`54hzY<2@OPh9}rgGF&#gagB)~B`ab!n4OgESU|lct?Iz88Pv3HatwqsKk^ zj_|^nfVHbZNymgIX5F$!gp^z7j;zl-Kv3_owAk{R ze-Uc83>9;9s(VN#*9#U{hqwmCFUcEUbw8Hj7$B^EOqZCk>msjtd$>n9{pAI&V9OQZ zy@aY<;M3x!X&SCjm)b*q;;o+#?_IEJmo}UovSlC8MSXjQ=-N0)tX>M-BeQa3+mdW; zX)}oFe$n%Tgl09+->8|?EC?%~&aTrBxuVI5uQ39O1ydRFaui%IN2W;x?N=oBQvUNs zYoqDebHrlLqdNVjvR!G+=$!zG@_r2xu zA<1tvHq4~@VuU)%gqzu1h>^*ft@>*uE)7z~MUR4*h(_i0SV5aB3ejIaU>+I<7wzpR zP#5-{7j2s0b6CxJI-0DeazA0!eTWG~($W$38Qo(Q)B}gVpS<(-6`}E&%Kfn}wsu7g zAGo>IpROGuY+?X;OAn?ozM6G5e8}$W3Stu9e74sHnb1ocH=F1rMtg3~%+={<5i`aK z84mkLR#9<MRWi7Y}Ec-uIjJpGFctJHn zAlb3c%br}by^j?#>Azg@4@)oG0Y!rh1_Yan&xxkvc0IdPUOm%{DwZD}w(V`>@zs#? zM$IROhrZ0scG1-*zGr@azI3nQad<2(5cY^tIDX-X_Hnei3t5fNX&=JND#ZQn+LGz! zn^#Z#^gmL0UH89mIP$BCApZ697$ZDEFzs~(Gy8rUzkb3VBZ{iX*rMB}(OFUx*J|tZ zQwl{66RvtFWp4^>9(Ag7Tx#qIJ&9nZ-Tb|V5d5=K=!}6NI`4%@jc(RH^S!+vf*x^H z`|%(3VQ-@3-)9_^Tfuy=8vj~qfgGszyYu3xr5^j&58}dm2|o<*q8pi*DZpJxG;&AR zbGi0TAcgd7z4L(h1x;{klaH59-NQ3Uh>Y(R_?N{)GII+s>q%pkm=1%bOv=c`n3BR#|q=R|Q(f0T5 z_OGdq<|P$L>~%NxpjWZ+*h0g-yI!LyK}^@BVJc(w0)XY%VPu=|QCQk3aFe@}Vud_pS|ibl_9b5=1wTO^)}x81yGD_!af#gi>R zi=6))GTa)-eeA(#>K$+@J$|0bDIGyHGdPvm3*o2fv&d3-kt)9hYu&)usfuc~yl zUWxi~^|)sy2nPJ~3X7)sxW4y1QVeJ0MF&wG60h~O7|o;UJGS?v%Y6^_jM$$yPAwid z85+bC)~mXFQGwXhn{hYn{{iQ+>)j7|=@%Z|m}wF`B%bQgvJ|A>B?nW8wrSV3V{G+%SL$iKNRhb3 z?PJdtU*%-V5if#5%U9?_;=`ifFSO{rX!!oXS_Y)r`xjxfOMZz?0rl72nZ$nW&h(e9 zlzwcNB=WCqkS^Xgd938{j)N|2VdsJLJlj#&J`68eEB2{MdA40(P}l9VVrQFJmKJ1D z#bGpO9xeDcx_>PVoUd*>g}#B@Ct^6M*}%~Ij}q7E$@kfu=ho3&?Do^cW2=u-a-mls0{?GV0JdTA%BSFKiy?_rH?N zM^vRe+i>@Dr2qVRXNg&jJcRpf@9~KW?eU2U?eU2U?eU2U z?eU2U?eU2U?eU2U?eU2U?eU2U?eU2U5&49Pe8NONVIrR}kx!V&CrsoMCh`dr`Gkpl z!bCn1BA*D6PlU)PLgW)6@`(`nM2LJML_QHBp9qmpl*lJa6| z;5D#woPq-W1p~ju9bPVRtGoaC#Z*{AN?ht+yUL-eQ_NkyUW^|`&uUM3L)<@59N2|K zl6qR;EMLohzghYEq3{;Rt6UpPD0BY+d7wX<)gj>o4;+{T4onR@iRNxnrP#%R6sdtFRNu_){9s)RHJE$a^&m$e6)$I&){#%+^!0pl)%>(UdFJJ|Jg=>iw|g~j&1pqs+t$v)mrpqp7BW2BZ^3Cpd2L+e3-M+@o-E|b?qW2q~N4|zAiuE@0 z-LcNV?Fq~0;n_Pb7%q*RM2B zEWWq@=MH;($pBxi0j+Oak6P!(@)yIlnnT!Fu?gJm$mOM{BW0GRF`|9W^I? zQo<`w!qDThD<%EU=epzROg)Wbtc`A~@fgR*@l$0^dK;AAIm?{6Z0}HVb&l$z=i%qy z>}=RYxQ*$J?_g09ZzsKz7zU-rZ5(dAxbKwQMN?qx<8fxB+q$#tG)^p&)1XYoB2tMt zCtt#%T+W#}%c%~v^L{its?WoutBLo0)2u`^)rny1vPGlQvid@mQGM+++z}lfRq=Oh zn0W@g`0YMAj{hTLu_m0sY4AeEBH_->G&eYjgZgDSYT0>QeBip6FaTMjyP6WqP4sV} zkrc^&*@Z1NnM&e<9#w_7R)vWh&9ha4w&Ta_97HhtomgZ|P|qE4k0d&hXM;-Ry>G** z`(v>m%dY0`^F%Wa%4o9|w<)|X5FH58^uCSQl0yZR$^;dA7d7_uGW$1G^(@+3t6IV% z^<~!zYzM!V0>Mp^nF%sxm@^O6ECeLX3cm3tc6n6I4?Zf>Or7;IEdyhRgxOlv>m!#W zOfbpu{Y{rV-lAR|p{{dW9jP?7YnJG+ZR|N1lj4;8nnqt%Aw4n%D`VnxD0AVRL}tMy zBYiP4%xtl^@byxWN}7J_3xo3fAj{RWw&SN{Uth)Yci4{i3)t|L6ebqj=WX^*>SXlLHk-5%f25d}Ydm zLG5;yVXzakLBmXXUdG}s4khP6?~LktPYHt2K0wIhO>u*-(QJ?@@F$&nBc8~#vR{pR zEh=7wdu{8*(>Iy!1`Dx6LvON6zg-sW>x!~8e%)wS6DaZ2b!}lIHB<$zA*HO*KySnl zg?#E7;Yq1(dr3+e5vo%BA3OOJ#~1}a!L16TRJQ<81Q<=1z)w3OlnZ`}CBw9VMCziH zD)A?7ygS@B!8J5~&&@qXhaqGG210rmC3!!A{O?gf6Ug?94xnj}NX!xm{;T*0&a zlS^#_$#2=C3+CnHYe)R6M80+%494uljnKy{Z4FoNBEHZfm9|J^BF-yo5C%n!Eqa5W zMn&>Pb=&*34l)nUgNLAjI~15Nv~_!kJ?BpcKfw8QeSgAw6V$ zACxXIG@dX7(R_(UG6V*BF2dT?_Q;7Gd!bzLJp>qnLe_u$w1-E$$oj=0umfTF3pu_r zdLu$Drrpdm~C*P&5(1ZO2?$E-<$HmH(6VVQh`HnTU z0dtG7)>=>P3qqEs{me#Z+y~LE^?eg2X=?=v3(Go!Ar1@v3bot*3Pq-~MQIBiY~w;j z6`$P}Cvq%5EzHY$>2HEl2O2RAu1Wkr4hB+O>pHA zLie0M9oz(eI`=kscH>b$9O)q|T=0KDYghI`9|r`{e2PXs#SftRO?o3R2yBCA_Z~U- zc3qd$XW<2KgOAL&DzWX_ZIel({_b1h9I|VZEo8S+^f`-KnmW}_#C;ENr^EN3!b>Zg{rny zZhLqdUS+F_V4|KHy})Q>CYAvlmA+kMdk6rGv|Y=j&a~F<)^ej5^=$i!o9^D4OEwgWk)S2x=x6L{ontIN0huD)x(UvAl5*4oxN znpRpk?sgD0IqtIHKa!AE8fZTKP{9iKQIKV4ahC5*bJ!idC5ya7ry{v+oC;Ds*9dQSw=`e7aZf(m^T0{yiFj*! z21=wg`^=evfxh96WQSFLisXAv@~z5>Ndcx;$L}KB9&0=wn@U|4njb%?UQQXq?kX{tE#5>nVxKb=k|L#vzB*yVJx`slhVRIAP6eLao(S}X>t z&%iR={lvYY%PG6WpNo%W*oqC?*v9$YHmo^*U`n8r>@t;{CzGss|JV^W1m>OaoYlSN z`I3Uhn~3Ag!`5#|t%t{6BOGH8mxIjuEcvKpJrg|G<{W~X=Vw|cl1E<;=9XHT@OaG? zo*t2y|K4vJZ&&Qj4hXxOrs3rjruVv{f*qku+Mi~h_P<6vn|kF-$};>$m)1MHdHyCt z%gSLn&jiPwMxD{uh_7GNm@_n2`V)^t&EJ{`A#sKBFrHq8)LZ1S&CuO4FXu(P3b>5* z(6WBn%qvx?NiL8xPCj*~2rLwdXnWgl=M~aCFJiP|k=L%aR<)pF2$XgrbZK?1u0AT8 z$v{^6j(C={Q9AXgWO~3#pUhqgjda%b3u&PM(qAmgbXWQo9vC|?JMUdOW0~o(R%Nhy z&30H`(EBB~JoE5r2zmF=_kQ_=9y%kK{;f3NVd7)AF@kk2%Y3Eo9d;L0vKyA~953dF z&!>XwxC#(S)xvu z{^PMGXS6B=P;8U+G)*8~w4VGaBiJBiKfk@Q@rF=Cm`Sja)Y$5<(rE{B!4dHNmNvgh57T5r%Ly))&01o8hAygo5kB_~U)f%^GJ_~v(Y}zSIkrM8d?E#}+jR)0xvb^pV zDnN8A(5}Wds=-hNeiw`9uMW!S)OV`Ea!2-I5#2UD`2Q=h)352A2oLS?|2y#<^PGd_ zyl*9+f#slPgSY2(s>$bIgXAoDvj{a67UA$k#;R7f-TGNE+H`q<8aM0_un@L6tj9`y z95?*Rhqiy=YD+G_OEH6u(mjRFExxWqB9wGRU=-)H2P z%sdVJ1dPn$Jcco9mew zZt}GoMy-CbyNFtmG!;2kwBP%L94qBn=oQLHM0cP^6VonLw$wf!ViFYr`G z4?E=)lKqnHsyc(w_LCrB3hp8NNGh{JFyW)pRS1!nY!{-*T&JQ>!8f@m!RP6U;X4uFv3QZVhu3G4KM)zB$B>>a8&KhDrza9}r->E@Qh=!||H z9H>bu66iC*P~>yMLDuD81NNl(3m6bY00N2vaA20hAW|Qh?%JmP1mX$Ex)jVQGQ@u! znSks!74rZn@sUZ{w*7wr6BYcFP0S2o{YJ$J-#e6`AamWG<;?Q%a~ zcWmfQ+-%93T2y&f%*NWY?5soYv57th?=4)uJ>9R>ayW6jj43OeOEUP%-23mxH9OMW zK006TsCyA6o76ku^X)--W9(pb;E@*`sK&#pzR#3x!+0aGLi@YquW%MO;4OD;X|*W| zfQ5|^qs(_j2}-L?H)nY;<4+WbsSM{O(<7khFn`3%TOPbCe}x1}p^bNDf+X-?Nq_}7 zmEhsLp??yr35C@i{2K}{4WNquio)Gu4C=kbNP%rRO^1omq%(@qi@@LOVFv_{0O+x0MvURU`b+ZTk{c=I6J zS7*EG-YmZ>YRrQ5-p!tshV2@I_mL$j6#Rpf$a>F{a7P|x1cq$XLYCgBj4{JnmPDri zYG^!0)pp=&5Dl;ld!8(IEKl| zqBNq2e^m+!wiv+IO_2T{e|ZXo<#!Q;{!KrRBKD{A&Sl&7I}dEr#t(NXH1lSNH}hut zM`^3#SaL$K(pTx{+>=kDCZ)LH-=r?UI|+fY$me^(nIMR)mnA0xABb^JW-!_d{uKxq z@BU!>S0Jg(M`B9gBz4$Jhi9QI*kk&c5(;$H1D15FRCo1q>Gmet3F-D%wW$NvJM!OR zuBYxpi-+5_n(^cgC-8s84XZp#0^7aZb^pfd8*iUIzw1W zn3eeuobVE6#qha%$W~{Hg1G}oPGGq$Nv7wyZ|d+D2*uMUzLJ_^M6VI-H#cd4*FfhUjIzGh5z^d1OY9e1wW+!|8?_2)StbgJTo)m|t5Ke`^&yFE>ZS<6v@qtl|0mFHR0t-e9koA1vBo^vmWxyxEp z>jFO8q`iH0#WYP}@bzqtsKMni(v0O7Bp#)xEh+P8s>rQ|j3ORpK@lGr0gg(_;)X4$ z?WTPS==O(-vlIUQsL1`BI@u0yk-S4xcBm1W3g_C8yvI~sY;K$=6#-?wugdUnlZbgv zrr;w4i>mL33$|e<5m-VDy%8r;*03AxhlQi#E?F*~lti&W>2>vSy@2|c^?s^8V5HFO36)42# zB8o^&W;AG#PFHceYRf$ts^>;C^*EW)s6{#>F4?@BQ<|svsk<_tG&%HQ2W7$6WaMT1 zz=8x0IL~CCt4T__x7yHl`4ZD_67~xyHUO^*2_kbiJ+(5A5wKVpA4oqjR zUEk}~O-lYF8n&+t6v+vLGUCC0*K4ms;~#Ltbsbid1^f zV01PfdE<2u4PhVz=NUkV3>xoAWnLO6Yv7{@!6@Bx!Pz&9reFRy7l;HzbvN+o_Cx>3 zYWkj3>Nlc)Wi7l(dF}|+RQjKkX5B!a0YO+FG}aLYjd6@-f9iNzB4-ijLs9E*Qc@4| z*ZI(I9ovbnOqKT>tbX?(;Zs?g8`HwX;FjCaHulqS5?kYToQBKV@}!?j^`vac%r`5u z*0ahQdh|vm2a!tn;Q>-055jWmNCtNv1;63`DGvN_!M5eBA~_fmbjjlLNuiH*L*w&L z!fzc(4?E z$R7-x1P8Xl3cPD;2JhOM!TYT!@UD$j!!}L!Xk8a~RaTP5`W9yblFfM*W*YyvDH;(v zXX=7lW$#%+^L%uO8hw}-h<2mvKKh)uN5aCQs@$e@3eKXcNKXC)=|)G%Pfm}l z2Nu}~viJ~+snI`B(h;GaWW9A4798=%)xTP4)80sGYZiZ_12IzqfgnH7;(X52~O&dXnwi?;DCIsw98SkQI=O z(Wv@z$UCra*}LUq%;{j;BFTGwbLCE6y-p`)+>-`HS8GHHjJG|v+|u&d-XygJceJ^i znMHl}{q#IWAJBA936%b1OCk6R)rZ;);sfozsLTI!p9&Az+Wnt0gAHgkC-WEKF)q8 zZbfo}lN05{t^BVfdrnnAVEYFFv^!3bt7*=b4;_w^}QPyCove zCQxD~M1oW*uGq%4h3Zutnz|;yXfz>`p(_A>9kzvH-4g50CXleU{ufmMz-9vbq(F=w z0USg_K;gmZcsjuZ%6zwt=TW~~_mY5IWPe8iKi2JdT?RoR5PAT5CV>*4izs64@X`9z z1_mSEbD8pC7vMR?p?U`&+G<(SV|dS{$2FYn*EUe~J*Z)uT^xZue6%aI;Ur4iK$$P> z0u;o|@t(^7F~IVB3$6r)v^m{(1&Ku|9dTMDCX6NMudkjLGiIdvW#`sSGoQ^z72?Mj~U}7K4V@qQiYmk+)`paO#9(I*5 zwO%IgD0H1Ndbr{_En_~yU9|Zv9hN z5plF&{#;o3ZC13e$N@>TXREM$e_*+1W%5W1P5v!-HB3;$eQ|fGFK~U?JkYyX6qBg1 zGMA3FnV3jn9Di3Dke9$TtDw6qmEgHv;VtVs;W4z?nQ~r!;G$%G*~oc^xRZovtoZU_4W-M~P$*kMDi2R-Z3DHbVv8yq{w&TxYb75g8$|JiZ zENE#D*J-d8&A!cy)V?hKa`KK67m{YJ>}0oro*EB~jU;8(i+}v1L=P9cw=Nh;CysxAzRn&{7Pqq6c$CWObY6FwGgT)F9oLucXBJuYqc3??rQsT;9&a0 z$Ub=|Zc%XWkAG5ESxbAXA^t|2xP7yh#*qFQ+(3sNxEo0)JTJwl3-Yn&YyWM&2s)=Q zH%TfA)9^f2c4X5fU)Dm216{DExjW{cDl<84&BF^?GP)>D$>&NkF{wwHi}ZMo!0+79 zm}vG;V{Y~o)^7?eTde%(pv)ySaK9(FN&I!B_Jwih+;FGlS2X=9j~P%0@?YK1^U8Tm z)9-H?wx-i)l2>Cm=2RLqt9VTkCG0-XTU9M6dbMH&^Zrf9sge`I3w?~Yz6wRo)0S&% z@>}GZi~H%jnt$|aj*+|9BIY+^Jls@MZeFUvv1xq}-Em*4jB z0*Es{)my8Mojx?$>-P}Z@YT&+4Y`@&YxW3(L4{f7S)thqZWB-X1=P}v!>V41_?4l> zrKN}1u?B0Vnx%!+m|@5Awg3_3ytGHi8J>O6DIPBPW(x&o`xb;|`&Ovl`QsTqS_h_( zT57hdF{a&J@QSSQ>r=9tN$qBR2UaI0bQdW~1J^0`qgSmPZ`an|s4D8pqs|z+7~5Q) zGd->TIB(k1S%1yGSrxwUECS0KgG33_V`NWf;-W5DVDJ{kt{N)_BVh3dF_JzEMvye`JBk*WK(E-R|CCDX0KVhOd%}Nqf#?dN`PT_?nZ0(@2$nMgJ~NYb z!hdomTabtUl#{h2%D3_bt=-n^{6=hue@*JpNgLK^_D-38#0Yn!d1o5tilFb8&7Mh5 z*{6LxrR|%Mn!X~ND@_>6nv}MU$gd^;489Z(d%J8CUoFUaHsJQniou0Z5k*co>0xC) zMKFtgjiLY&hGa{JNRgch)eBO#-G3&Ch6GH^r_&jc986aM7TRkR`H=lc&OcBGuTfw~ z4hG?4_T#~%Q*;Cr07GN|9Toy6+^-c*AN$QpOacarzoPJd+G`LNfgm4J!Pl6wn0a95An^Imq*H{Wh~G_9E$eP6jF`mox;r>0tNH2G3#Y+6)l#qyH}^QqsLXs9MO zup%Kz4o!{2beEI&V;$F>OxMjjngt65i)t4VBv#rWW=~r5{5i9i+{OpgA zOZ5;|KOyBdaxOT|0z#v3EMp>s-bmqCdI+tW?S@5YJnez0(GYr+zYu8~`9A3PKTrUS zpgk}OVgL$&No3aXC_Fd_Pd7}?RqR*nAhY?Km6!w!27g5X2S^DaCny9$4T(LTq^V@MMB)qF}h>*iPN}HY=x#;L)1z)VcaX zy-ABKBT7-Q#HyLNijA`Z@}$abTpVyYQbqFUAmkDS1%{0zC`4V+)|)IeUL7(uN>69R zMv^f>50UXA3-yc+s#~Ifu*&@x#Sg&q^bjc!6HfpK(GXC0a5|oDje_D_^yu@b->rK| zKrXVsqk!Kt8d6tJPzZ!Vpx-Gd@VSU05bBB+-emvHMPPN+1O)-HARL1HN$|7Md3rhn zqO?CM1)75=K;6|MK{VAOp?XD!GJ5#-O(FSIY*$<9P`=g>79VSh0<+`FdHM&C8T$8- zGjW`7AM3*Deh{({$5|{OQS%~epQpMcxg$=P{9{ys-9}B@yBfbClJSKZ?V)U(Kmv59 zec=vErR9818x^b6WcB081V#(&eNo(J-yWsGkeJnmOAn*^BlEDwSc=_CI<{8b%>pY^ z9O0b_(gD=nSWKn4yE|G!`p)*#a;Z)moIe#M%NLdqLvQ!7#9>E=!^B?KfdQQDn>b+@funYYdy12Va8k7|6$16+0KcHmW zLZe7d7?crn5ZA}7q49GZ@LS~RA%r1=TNcdNkY|{B(ixQOLn?XF8I^<}pR$6fAN)WF zZli$^88kd0G9PG^HSke{V3aj^Ft=>s^qK$W0+E2Ij=%tc{*l$x6C(8+(Z8|^$Woje zAerL$jWP@us`oZfGu$<;?%*0_fh#+bbBG7t;IGU_7!-j6$u`euFs6{M@>a{15KcQq zH_vD^rjT)DejgZuj}U(Pi(h_-+?4{)nua{MM#B1ob=yJa9xfD1NJ+wK!@vXIJIJBW zE+r$M6Al(IZk>qI8)F^LZ`cmcZ}87WEUcNbuV5PWIQ{$HXpc6X9#YY7v?``ta~;06 zIkhT>#cggrlwq7fcNa$OH+{2GChvt4E}BzPMaW0kmXlNR`_gqe)1Isx3?YjrSm-fW zjtpzslPC;6=A!LDNW?srH9+mlL%rKj3@nA?04Z*1j9}Efo zSCTzvgs1OgyQJ^3aP*6Q62uM?IW5cHe3GgK{7y&v^w8gKY ze~WpH1gQRBMgI#0ghB!8++M4GL(w7Y2~PUCKe|RF0O4e~$OH5k$rEJIVzz~88+nDD zXR8L>8(32&o9xB$UM|1BzPWc^mU`t>wPf?}538&;DbiVqRLbCSX#D<5wuX;`XpWxBuvTI)I(jNS1X#*BD9=$b zAnX4?m2gmEj-Cp_#~9+llv5T26abUT06I^qr*$P9MboywS&2!&VDVQJ-e1l^!a`7p z7ph1O6oOp*L=nc1$^Oi>$J&Q4=o}%Og!L!Ek4k~qV4^glh<{ZI3N|3rO_2V(AH{zW z@*fcd@~RhE|9gK(KyyJ02-16eFM^x+-sgrZ&pI>4hD;yzn(F{l8Hv5a-e$R+zosn+ zcS#POJtj-lO}GJ&p#YI}-cLR79lJ!=%_Ii%_cg3+i|X5!>xE1^u4Ykut+;~kn_?@= z($ji|S^{aQcar;Or{8LtrP1YW)M-51QSfRQ-dBiLjMDyAgsxx{EGjvl^Chj(2|K?v zv+R%ZN$#B0Z!d2~^e(LS4)pQxwh6lMtYf}+b#H90N(49iRE_(h9h)@JNyw#YN`5pm zvVQF}+|NZBu|PdK>dRwSZa$9-h-G1%d^pz0yR0EdQsSI$F7~p<_FR&lWcL`?VSsAzLK+n6$|u6 zIJS(^1rnJ#-_YI~bzAfrgas?F?11KiW91dY{iBhs$rJ@2DUqD+C*ilRlIeXTn|drw zZ#L#IkCb)z7!e+2K6g^+2R!ON07F=T#rK=4h4oeN(f)5% zK0>%67>fUj!uxN7yGsbU@F~+(_Hq$LphS5{|I9^T%>f_nVh|Vbxjgj!j-13DX+88|8Mu^N!DK zKzK6S0Z)CjdCpXa{GAh+zI}DDN4TVDAG;w&qbB(b>!E!z$JRpQ?`YXd&Xce_@>Ono z%L9Mpt4KbciWHfr}u+9``aP{-FoJ;&MV@G%51IaCOb!h=azfdz3# z%i{Q2A5`o&D=`TeivNnj`U* zvP;_V^=&5H8aq}nQB731G;+i8gnQx0lFcl3kY}KLajmvy%U?M7cF0&Cf@$ge)-1ci zcG?>C(0K*albtb_-Hj#(t<%>reBgV3c~x;jvo>5`7tGNHjmDKbXA9zXu;I&$%{lF> zhqb4}?OIt=do9aL>|0mucJ28B{p!2AqB{L{3aTB$XLbjR@_SL(O6{JBq_C!P^oSpJ zdTbZvvfCA~vzD_lmUiCXArI&4-dwxj-Gf$0Y&!19_l(TMiML?FFWE7zr067nqo+b) zVN>IBj#a%5G(gDbqTX$4@rP%y53%1jvXue6S1 z_I=d$kHbqT__VZv6B#t>zx;K1Ol;nXyEEGa{m;_!MoPOK%hqgCbLDD>V6RwAWB~KP z09z3zCLddRzE6B5+Z^}QKi4E-OSCsTa92#CWWYy%kJ5D1vWZcg&m5 zRg0N~Jd0Mbf4?5eY}(I2|8o?1vvL8g{oH__XwAop*ej%Px6^BqG4TwX>ZI9vbw9>Q$G?yX4J<7; z8RL?MlI?o zYy6Vujkb+Txg-AdQR~>FtHus#FXk}aec@RC!D;T4T9-V# zq&Yva()u;O!kxv$!0L?yGpRSYqFQR7xbsG1_{^ItQ#I^lhbn~1!?Le5wvT%|f#sNk z9cxStW=QJJ;B5LNu04of>fh0;pP2YmaqrId%w}Pa`|7X_e@jAszI|3n!0_a_d%1Kx z%2_+Dm<`dqczM$K&HtnBJ;R#X+HPStDhd|t(os>|iVBiN5h+`A2Wg_96g3nn(whOK z%Lc?k5s|9G#t4XD5Rl$QrAY}@2}MO9bg21Ki{u4=3T}d_rz(| znylQknNI3`dRcP9<#DfZk8OS84Q2h&s+`-2ISV=RMv`-i0)>^A8?-CWW!YsdxWw0^ z%)7F~Tco)gPAhkr&HDx+{7_|D zUE2-CU9*RGhi5I^-voaD4auJZQhc5m~pP^A~Pky8_MUV>`2Sr?1E=4KCjg^whT8CTk0`TLVp z^+coLH$AJzro^{NB`>gUmz5Fn>$86oyxBEHTtu@I4iS?BO7l!n#lv8GdUinOo zzOUDi2$p&tNr@^Rt;Qd>a{nB`=W--Y`JhL!%Y554k9x-vLHrksbs`?=uY{ft-9M5_ z$;_$HJ!$p%ZPVudxvR-J3$wkEM{`EIH(%YC0VPJ*R2qwU_SvUF49y%o=Se~rLjX-)T>*xm(cc$~Z^IKXkTp-s{*Irhfh*6_J} z@zBu`gh28Od}2!Ln6abv!MmNB4l~vbwQk<{4(tA|-99t#r#8A~#g*plG#s)!&-Z7C zdsM;Nj)(GCd=|g`O}V(smmH4O_5D=yLgMlD?N*_p*=^hUf7M>*IzE8tF!6b1GI%p; zHfX9V+n{py)sSmgpK{v?xmBOHTl07oJ`d%ObMySJ^XFh<$2A`(tAOdzCjBR$o1C)V z2xZ3#aJ3nveHKSudZm%_vG{71h62%j)YEg9&45-q&L&(e!F2e(a-GYu)@OBsA;nf% zxf+M@HUUoQ`1%NJ0DkVZuALXIH2Ft%%lO?np7fNV@#gNC*Ve=NY`d9supR(T~gMzcjSZ=iBVQ+rQJn8CVVGz60eTjXjypPB{-tPZi|9qEeY{MWu zEQH*!$_qJ0eIwi@MJ~~DLd4yk6Ou?`)6f;vU0EcKD!$~H38RvQ1gKLpa!=>~ewiQ`gY zi*0uxDRHrLdyb2PeiYPZ6Pnkow9&SV))5xnotJCvzUS>E?>rVBU|J$n_OCBT=EuX^ z_uSuOQFWj|%_8DrV}%Rod5EpiQ4!{9tgyrP8GO2?^1S|QepFG^^XFfK5SDAUD}B4C zXz6fC{ZMGC`Q_#t6+t?Am(8=^w;q>9$xn5B<<)C^VSi#fzgT#r!5y6@RS`nQn|mBP zA*$4RO$omJFGiAbF_{%6ViOI%M+WkO zb^rXDV)R#!R=I@P{%j|8efNYZb+^XIW8yn+3CmxP?TtF4c2sWX{$|yL6E7?@-pQd~ zvkA=HwoHCu6cg9oE6{9gH5T*r57Y+nB#)ij*>-}SfDAgqtK|vG{Tr& zPH0!;+5{Ev%730*cDw2SOx9tOD2~6#PkFEy(# z!g*~y`u5l#tGOBtgSa2CsRfXf!ln)f@$&AP-oYI^KT#_t?L*qMK&ktgtSRjiO8ya* zkoU@@t=p_Hhvyn%8hj{U@7%QDC`a6dIrUadU9c$gX7U9EX@iG#X%qReV-#Y4?u3hs zKyRJm%l_fI(ihX#&2K7_HGSALxuZ^R_4A!T-qQIl_@V4C12)wt4>5~Km9-<46$ylM zR|K5@GL-7l`o=->IPdS^)`;{V7Km&0vm4x*v*E~UJhIcgU9eZ@c#2cTD5tb$)gbpj zwVhV4Mu-0?OFSOBPw(idT~-JFc|*)7O#fDa6yI($CgpYfn4GWA?u|)#S4|FA`cn#I zw7z%BHnfw=QR)r1)IJRM+Ks&YdIoXIFd{?rHfLg*MUBlT*9`8=(^o#Yi;CW}!lQ)a ztBMbA+RuIB?EyC&Y4V4J@`wJd>XCB0%vHW;q?e3jDZJ(Q%RIGMM{Lb%Qv;P7Q)+ta zpWKlR=OYr{{gkuug|{R_&yHy} zOGUGDRTdnM?Rs={+lhg9k06E3pHEAU3<_EWJIAzUlvKUx7XOd%|2B*{9Skbbj=)Bm6P$0Gm(LM zI=x>*5!-?TFmL!Yw$zPso!5a!!R1S9>P)BbK*o>i^ImIUY zWcG(bXk{k%H@PlFa6q};GKp(L=cOLAvzMh3Gs5)z)*pDP)2@E~>+D_h2lG(e+1|`b zg3WEqMq;jIc-lN%r(<3@Et!?`e|cK1VsD2}#o`(JXK7Q>$0scRKe>>F#Nl&fQ)g z-|5WqxTM^gJf=GzTy<8+iRaCOcD4R%Nf#wF?+Q(l0-uSRLkfHdbx@qFSD)=40PE9`w%Xj{O`=f5% zw_I`ieWe+eUo5>0(U-hr#m2t%o_T@Y+}`9sNkle(kPNZ@Sag|QRr2JZJ)Wn_C+<%sBqc;f4+VmPv|;!?)9HOyUzbUX0u)Melrb-Dyo& zR2n3l{(P$x*Zk4|rJ^T*|QuXL-zSBI`gCnB3j&xLdB*`nU|g{X~TImr7w54(3M{F*R`Lw^le zt!Qc1#M8Oqywczkh1Hzjj=ny-S2_OC(TrpGn<;uXtn}k|U6}~{Hi11h@71+SLx-R6 ze8BS~V)ji<^f}ig&OlDhKNDi?MlJR#70z=zlVm&;+9KK1c(V88KU5)&pH%jgACk@M zlzGQNYIZOTDmXLNa7AGXtK_^n$Hb>v@t8>bDVi+yA=hF8(}`8Tt!qq`w%tNn+hd>N-dm&u#Wjf3-}jyJ z?`qR7DoX7&alX=eCalEbl=GRkb?=PRwr3t|3zMqix`VOJm+T8@RFxT+EbDoiG|9c1 zn@?2Rn?G(t*1^fE{TJ^vYM)#4-9FY@EL!w^T1~O%29c(it7{JuDk#IxGhb`&i+F$G z=X7?}xOqT>7r&iJMxm#uLq>g2-orD2orCQId!JV2f0?~}_sEfO)$fD7PcsYBlk`cm z=x&`ka&-4)bL3TyXX;JT2Ye#e9r%pgLonPM9B`>597$^26FrvNJ2yRGiNCMoFFE;q zui$RUs;BcOP0Rn46)Z*n%`C=4g^Ht&QuR(1!V~rfV^8B`c*9}XZ{4jQY#>-hKw=LdLXUH*Xdhf^F1T{-1`=?td zv0rv~_-y#Ku$Ft(FZ})5l{bIX{%P>d-`_Vudo$A;duXlI#D3E%jD9O9A+dNTcwAZn z+z2B6({13#`eM$v;yc!U(apzfo-0&|U8DM!BRcaRKbebs;(A(^``+i~daW*h-}j^< zMj_>d!-LDW9$49}N#k#k#7o_Ha?7K^WpC6ayt7GFOn9^ko>;L%w#i&;%=g_6H5(5J z^+Q3{F6(ohT>d%i`{C@C&hvF<0qZYcetA^q!>#a(U!4r}rV1j7h}T}~TrOAJL=qEj zE)=p!Y7GaSpB3V$vt%#6>Th75P6cKO>MT8{W za*p1tZ4W{cZaF6jx157pC?en%iU_!cA_8uqh=5xtBH$K^2)KnJ0&by*fLkac;1-Gq zxP>ADZlQ>PTPPyn7K#YCg(3oOp@@K6C?en%iU_!cA_8uqh=5xtBH$K^2)KnJ0&by* zfLkac;1-GqxP>ADZlQ>PTPPyn7K#YCg(3oOp@@K6C?en%iU_!cA_8uqh=5xtBH$K^ z2)KnJ0&bxQiPKvELU0R32yUSW!7UUaxP>AFw@`%O7K#wuLJ@*nC_-=xMF?)82*E8B zA-IJi1h-Ix;1-Gy+(Hq8TPQ+s3q=TSp$Ne(6d|~UA_TWkgy0s65Zpo$f?Fs;a0^8U zZlMUlEfgWRg(3vEP=w$XiV)mF5rSJNLU0R32yUSW!7UUaxP>AFw@`%O7K#wuLJ@*n zC_-=xMF?)82*E8BA-IJi1h-Ix;1-Gy+(Hq8TPQ+s3q=TSp$Ne(6d`&G#XS(bKOlI2 zK=A&6;Qax?`vZda2L$gA@H7ebn${i&-X9RWKOlI2K=A&6;Qax?`vZda2L$gA2;LtM zygwj#e?aj5fZ+WB!TSS(_Xh;;4+!2L5WGJicz;0f{(#{90m1tNg7*gm?+*yx9}v7h zAb5X3@cw|{{Q<%I1A_Ml1n&=szCZpCTT#;f@A>~vD@v-||9sT2big1ZDZw~TxY<$H zg$m_UD@i1JcyXeHzWjJFrzGL~fnDyFJ$u}0zGlDUAASV9eD1~m!EQC;#@F=mJEr{$ z`WG!lg(UH}JWjv5HmJM*e)?AHzxRv9gTG4WQ}Sk^P&2BTT+)ec9w3%_&D+P=zVRq24rR1qWFfXPRevCK2eiA zo=EP(zW>!mc_S)eDAez1-R>kk+LP2Hv>@e7?3)-ry^!CRTT2$>%B6ht=9%jCXpS0{ zE0Lq5fxlT2)oK^u5*ZrLmpiV3@3F@>l*-%1%xBvV%v#5bwOjriYac89>U}b@#>D=fLiM&qP@x+orP?{m+W zk&m|^)HfH+8f9Xi`{j=98VUts zCLY;w>*fe0Pc*fACqcgrNvC|k?K$l&zWnNADSbp)VoG9J7 zj;`*D;9tU{^sXtgOF>R@j0d`bI0$v`n(L775ldF{xDMu?b2-^Hkm@lSXWyLCb!0Nz zqXcxKlBsGRllmm{)P6SzHB6qBDguT%_Y>Jf1z>0h?o0=PaRbfy#q0&jM7i7xIA;ei zOAC@~G-i)bmo}e#(0$L*IJ_P@zw5g-Q7#8pVHODjJ|VemKM4zU^*R*1an+e42zLBP z_yb(}XQez{fxi*SMczxW8&l(xpYCbu>Wp#|I9jVrObiyhP33E_opz9~1xh?^?JHb? zl6d@&1e7h25Et18^_UYovoE*(b`V6r3Kl%((kYL^6O40u#|CBN<{xy+7bIJQ zdVskux4F-}vTKyX?J_m0&i1GHXGbE`)p7M|NMUkHups-%vACqELGSF|F-sdvV3vSu z?&JBEq$aRfykf};Jr6_25@<7YVSl6)qrgwfGVjUlzd%k1p z5`Z5acW(5(UWtq5fRsD;NM2#_AMx|1;HO?GsPLpOuW%FM92x5vIyT|0h_VMcvm;-x zRd)3j2Md~?922xBHhX3Cj?F$g@ig6Ma&zmAtXhxn=8E@*Df<(x!`~%#-R$j3M%$++ zqbIfOpIce;y5cF_%~_6WJtf`){mNEt=@WT2hk7F4y}El@^LvS{C7u{HfxJw_?0;?8 z=KlGLRqnxCy}L`Ki*E=BR(ESYEKGj*Cc<8^fq%*8#;6>dF9ejcDo^!WVUl<|CrNpCg>53I`Q4A)pfo zT#REu*zf1QtjrkGyY6%yeZZAHymOgw+iCGnj;{TlLesHRUSyI}i4?Z5uDws{=aX^r z%o9z6AwJRWwh^07oli6BujHTH7Hi1w);5qv_UF8_Dhiv5DU}~Udnia3dwpC@swwmK zy4@p`j6Zr+bn3P|UnioBTtKlg>u%O?h#u$BD7g;J#WjY}5W3HUO_^rEefLmeLBPcx zKF%R97YAHOX2gS@FxERNR zbW098tjustL-ZgDCguIAi9qq=(RM5o?(b#?4+D;XUiSIjv2WU||L`cUfU(t3PIcGAPK+2s9V z9tDRsPf1{^YlB3@zs? zNQ#kWiG5~7g<(=Q8Pj9XQ2Ra6pt_<>7@UXKjD@O?I9`-&^Lizch3zZEl)ewc&%0+- z61^Xq$)oBjj?`LY9>G*+`iIbwXzex`njuJ}cAG2<60MbpKB7jb$^ue8rNH0b?K0sKI_A{b#qOItdlC>$I4NYe9|m_4ao{8W4fvpJ zNG8<*5rPU=sUNi=Z*q;nr)cD0OOI10#zU{;hw+2nF>s$*rwh#Pv;R(weeFha$&L%! z<<3fh`;F6FLg;S!&JMzP7 zQ0p__d3#SgrSwWG&(zf3!^ESb1L-y%hStHk(hsV?$OSPQS@Z*Y}tLnJ~ zT}Qu`UJV?_x)k2do$^|kN?4WmChDP-aEaHilqod%K~rwRgxSxV&A;?=W2#2m4Aj{Z z@r9q;R{hz<&J{I#&G}Nnra{mZA+h)_cNhDh?FWY#0lRc;XlEB8q4-rdey8hzmt}8? zlm>t2)8^ahQMI1=c_)*L*VsAcHcmD5I7ZgGT`Z`p5sMmjyWo26acYjWMBKP*GJdto zrkG77vz5c6p4zVUazu6`S;JQ0*TwNUqE06oq>}^XJ0#slLfhx$@=qpf^d%V}0WH_M zW3_JQxys|NcM0Boi5rkqkV{RK&sM2VY`DUnOzNE}I5Jc}sL~K=!s}HyYn|EI;%8Mb zTWQV5U)VF*A(YMshN2N3;pSK%ZxkqX-<4P|KAQ3r z7X`e>cDs(hG43_v-c5WIU+?wJNvG5#UPd$Y#YcjNPf<=-`3TyhD2G_`xWN8H+`4+= z>`$F}_pa@SF$1$VQMXBQvRy*ywO(4px;%5UcG8Qn#|k|Kuks(1+p>Ywjr}4RU+rT&Qw5sc@#b z=;)Vx`CSvgyf)nI_--keep=ZzMN#&FwyhOuQjSxw1V54!S7PhqbfKYLk%!~HhGX+A zxv0}Sb%d{PUimb3fE=*NA&L|)w#B`KCuG<9L#Pe@kFaZ%kXe779lX5f`E3#a`F!Zbvv30o6FGhnL2{8 zR~-gE^v)u~g?ThW_M^WqBIv}!a@v4H;KV~53(^hQ@30id$e<$K5L59J4;#a%WTt>( z2{mN^xkfZ~4B?A9MU^F@`Bey2RNfs1i02+ObXWo5>o-t`dE=@Oj!*A5GF zh_CJuHrQOX9f`nvwn#$TLfQpVu{1GkM4UPLyu|0%{rcX&F!@*{1bV>KQ`}KucPILbnVy||jy9tGaW=2KS zMzxFXc1;md-0pJnSWk{A(Nh0M&aYgB@O@HEqw(Q5#Q|r-F_Nc&VhSn_J7he14a&Zc zYdNN*Oh=ar*Ynd1NbSP)0xalKA-DSIK6J}5;NsR`Lf6o($JpR}1`{0t7rS;L|8N>A zD9Pn`Y{%b(7mLWkYPVksb+A>|YBz=jVLSf*vJ}V2pdxI?dn2pe2^cEbdqA;-qD+9? za+*4Z@I{@vqu0cAnc3a3`ggj%Qq7voqED*Jxf%8c5K`i}R6m#B@u6Ao-Z77z&P z@eiR1WJ0MfTVpNdYNjO8lWEmAQT5Rz1PufMN-bI;_g zyK?WbY@Z}8#iE)#TYLQtDc)yeiDd0&AMy{;_9@Nz=;T!APnFynLMD(`P$Q0p&@;!` zlxYUs^l>E?1YGRRmFoq(f`ALjjJQ!=L1pxO1`~{ct9<%+r7VdXGiVZ&6uMP*ei6kg zd@!O7{6iEzSg@ef(5*5{af}QqN)0_8t$-vDsAR`unNYtTkSk78#}K}#v$c|2T}T*B z6Amh7LO>@FxERNRbcKW+R%YBt%L+YSFwgBbXtGi`umM@ow0aUSRDsmWU_=-)S+k;4 z`l|e9Ekc}Usj~j3#f_RhM!nH%5JY!(d6zdon;J7Nd4dJEfJsvBjc%?v=Y*zHUp0S9 zs^}eU-~3^g;xue3=6r9~!v3MV$Mk5v<4bc(H_wf2CB4_(7p86x&K>5LR9Drlc#f7- zM>dNeLTw6f@~AKs2bWgb2nR8{i>1{$bt_Dv-?&xBH-(q81XH=KCLXlH7k`fM+Itodiaer^B^TBg24-v$vgz(ZDkonU zp#K|^-)K7x9wUsSHM4*_Ve3=Z+`FBFX;Whff#A6!B=ZMmjP(9k?(UkmQpI`dr7qm% z>FH4clUkuQZ-+5^etp%+?wf1;hm^3cy<&5T{Kx6Ox!3==Q5NoKZt4T}>9u2$T9?hYUTR!33k!2T-)qq~7(t zmQcWR+>VDz%1cQ5EU!9k(0Ji2uLd(h?|jI{h+{#(#jbspQ-DT>WJZF+f9~J3O!%VC z0!|gbL;C|lXu?6oObBE|FRKTxk#Knb+TUb^I`4Xj)ZJ?-9`JmHa8P684yr&<&mr`V zhd>|$2@b34D-xo#+g#p9)us!qAHfeFN-b@XY<=SW;Poten(XLKo)Ww}I5+pNkyvt~ zrY=$ZsATM$7K+AlHbdjv;(er|411=rqcP3+4O9Y zU9vi+-JqGo3v%q&^W&vMoZB`EOK=7J+7z#tA`E>V50pBfUtH!c(b=k)vO5mjZ(M8y&HRIF*`TCM zN0-Fb^V1ASZL#$NEa;LLw|em&bjt?d;?`h7M(EZJY;ZnG7yh- zKSg-4h%AQI`lV0@TV#jUVptH?{nVGGI7S8)VcpA(hSnxvsAT1UVhIJ90J-HfbqwK) zI(3VU#Ap6#yg(IBt(Xb5Pz5f=u^`mUKV>U3-e%OhmlIxs*HeEZ9N2&?AQ05!A3_tz zgi;N*$Sg0FzAC?23z;^3n%c$1RSuMh#hm64pkI0Fa0&h)nA1EcFpj3%W!pZJJsZVb z6-OPL*k?^CiU*zn~;8iCBfR1Og2e%QtedlR)dT_Sp6;}<~=Xt-FNdK%B zahmjW^`E1IKYs*_H`wnV8ZIqX6q+yD9I(*W5dLEz75&Ix6s3~a6yeXOu?>qp@KtqO zC9iz{S5;lw2pP`oo{sYuy{eLj`;A+)_~2J|mS8HE?lwCJkb7*yIvn__q)eXxHb&5x zao_?dndWD>|7S{8dGr~Nff?Vz>N&R6ktw~+| z`b6vN{!Q5kCBi431oUXodG{V3WAT&1kFZa-sI6b1a3Nxu&_}{h=?P3i=t4Ylf6`Hzaah~I`rtd5sZcPxTA%ZG$O$g0^Q9=5%AmG|4 z!n0NO;a1=ZVn)Xc9&Yue=QEgK1YCY9Nbp-}VPtp^w}!+%^!`NzRo^M64b}@(-@&mU zU5R}TOL2@0D$

&uA=()A&${K3d1zHWJ6254Xdjgnm9RgW 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

B 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

Pt)xA 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

f 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 %|OBt__ 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 ocaqxDQ?<2M@3^fnif{6$^PvJx|4G $@ + @[ -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)" + +clean: + git clean -fdX + +FORCE: ; diff --git a/lib/openzeppelin-contracts/certora/README.md b/lib/openzeppelin-contracts/certora/README.md new file mode 100644 index 0000000..cd85ba3 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/README.md @@ -0,0 +1,60 @@ +# Running the certora verification tool + +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). + +## 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 Certora Verification Tool proves specs for contracts, which are defined by the `./specs.json` file along with their pre-configured options. + +The verification script `./run.js` is used to submit verification jobs to the Certora Verification service. + +You can run it from the root of the repository with the following command: + +```bash +node certora/run.js [[CONTRACT_NAME:]SPEC_NAME] [OPTIONS...] +``` + +Where: + +- `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. + +> **Note** +> A single spec may be configured to run for multiple contracts, whereas a single contract may run multiple specs. + +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. + +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: + +```bash +make -C certora apply +``` + +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 +``` diff --git a/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch b/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch new file mode 100644 index 0000000..29ff923 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/diff/access_manager_AccessManager.sol.patch @@ -0,0 +1,97 @@ +--- access/manager/AccessManager.sol 2023-10-05 12:17:09.694051809 -0300 ++++ access/manager/AccessManager.sol 2023-10-05 12:26:18.498688718 -0300 +@@ -6,7 +6,6 @@ + import {IAccessManaged} from "./IAccessManaged.sol"; + import {Address} from "../../utils/Address.sol"; + import {Context} from "../../utils/Context.sol"; +-import {Multicall} from "../../utils/Multicall.sol"; + import {Math} from "../../utils/math/Math.sol"; + import {Time} from "../../utils/types/Time.sol"; + +@@ -57,7 +56,8 @@ + * mindful of the danger associated with functions such as {{Ownable-renounceOwnership}} or + * {{AccessControl-renounceRole}}. + */ +-contract AccessManager is Context, Multicall, IAccessManager { ++// NOTE: The FV version of this contract doesn't include Multicall because CVL HAVOCs on any `delegatecall`. ++contract AccessManager is Context, IAccessManager { + using Time for *; + + // Structure that stores the details for a target contract. +@@ -105,7 +105,7 @@ + + // Used to identify operations that are currently being executed via {execute}. + // This should be transient storage when supported by the EVM. +- bytes32 private _executionId; ++ bytes32 internal _executionId; // private → internal for FV + + /** + * @dev Check that the caller is authorized to perform the operation, following the restrictions encoded in +@@ -253,6 +253,11 @@ + _setGrantDelay(roleId, newDelay); + } + ++ // Exposed for FV ++ function _getTargetAdminDelayFull(address target) internal view virtual returns (uint32, uint32, uint48) { ++ return _targets[target].adminDelay.getFull(); ++ } ++ + /** + * @dev Internal version of {grantRole} without access control. Returns true if the role was newly granted. + * +@@ -287,6 +292,11 @@ + return newMember; + } + ++ // Exposed for FV ++ function _getRoleGrantDelayFull(uint64 roleId) internal view virtual returns (uint32, uint32, uint48) { ++ return _roles[roleId].grantDelay.getFull(); ++ } ++ + /** + * @dev Internal version of {revokeRole} without access control. This logic is also used by {renounceRole}. + * Returns true if the role was previously granted. +@@ -586,7 +596,7 @@ + /** + * @dev Check if the current call is authorized according to admin logic. + */ +- function _checkAuthorized() private { ++ function _checkAuthorized() internal virtual { // private → internal virtual for FV + address caller = _msgSender(); + (bool immediate, uint32 delay) = _canCallSelf(caller, _msgData()); + if (!immediate) { +@@ -609,7 +619,7 @@ + */ + function _getAdminRestrictions( + bytes calldata data +- ) private view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) { ++ ) internal view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) { // private → internal for FV + if (data.length < 4) { + return (false, 0, 0); + } +@@ -662,7 +672,7 @@ + address caller, + address target, + bytes calldata data +- ) private view returns (bool immediate, uint32 delay) { ++ ) internal view returns (bool immediate, uint32 delay) { // private → internal for FV + if (target == address(this)) { + return _canCallSelf(caller, data); + } else { +@@ -716,14 +726,14 @@ + /** + * @dev Extracts the selector from calldata. Panics if data is not at least 4 bytes + */ +- function _checkSelector(bytes calldata data) private pure returns (bytes4) { ++ function _checkSelector(bytes calldata data) internal pure returns (bytes4) { // private → internal for FV + return bytes4(data[0:4]); + } + + /** + * @dev Hashing function for execute protection + */ +- function _hashExecutionId(address target, bytes4 selector) private pure returns (bytes32) { ++ function _hashExecutionId(address target, bytes4 selector) internal pure returns (bytes32) { // private → internal for FV + return keccak256(abi.encode(target, selector)); + } + } diff --git a/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol new file mode 100644 index 0000000..e96883f --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/AccessControlDefaultAdminRulesHarness.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessControlDefaultAdminRules} from "../patched/access/extensions/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/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol new file mode 100644 index 0000000..e862d3e --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/AccessControlHarness.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {AccessControl} from "../patched/access/AccessControl.sol"; + +contract AccessControlHarness is AccessControl {} diff --git a/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol new file mode 100644 index 0000000..d684c73 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/DoubleEndedQueueHarness.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {DoubleEndedQueue} from "../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 (uint128) { + return _deque._begin; + } + + function end() external view returns (uint128) { + 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/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol new file mode 100644 index 0000000..2f989b2 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/ERC20FlashMintHarness.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +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/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol new file mode 100644 index 0000000..08113f4 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/ERC20PermitHarness.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20Permit, ERC20} from "../patched/token/ERC20/extensions/ERC20Permit.sol"; + +contract ERC20PermitHarness is ERC20Permit { + constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol new file mode 100644 index 0000000..ca183ad --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/ERC20WrapperHarness.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20Permit} from "../patched/token/ERC20/extensions/ERC20Permit.sol"; +import {ERC20Wrapper, IERC20, ERC20} from "../patched/token/ERC20/extensions/ERC20Wrapper.sol"; + +contract ERC20WrapperHarness is ERC20Permit, ERC20Wrapper { + constructor( + IERC20 _underlying, + string memory _name, + string memory _symbol + ) ERC20(_name, _symbol) ERC20Permit(_name) ERC20Wrapper(_underlying) {} + + function underlyingTotalSupply() public view returns (uint256) { + return underlying().totalSupply(); + } + + 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); + } + + function decimals() public view override(ERC20Wrapper, ERC20) returns (uint8) { + return super.decimals(); + } +} diff --git a/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol new file mode 100644 index 0000000..1c76da2 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/ERC3156FlashBorrowerHarness.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +import {IERC3156FlashBorrower} from "../patched/interfaces/IERC3156FlashBorrower.sol"; + +pragma solidity ^0.8.20; + +contract ERC3156FlashBorrowerHarness is IERC3156FlashBorrower { + bytes32 somethingToReturn; + + function onFlashLoan(address, address, uint256, uint256, bytes calldata) external view override returns (bytes32) { + return somethingToReturn; + } +} diff --git a/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol b/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol new file mode 100644 index 0000000..69c4c20 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/ERC721Harness.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721} from "../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 unsafeOwnerOf(uint256 tokenId) external view returns (address) { + return _ownerOf(tokenId); + } + + function unsafeGetApproved(uint256 tokenId) external view returns (address) { + return _getApproved(tokenId); + } +} diff --git a/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol new file mode 100644 index 0000000..3843ef4 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/ERC721ReceiverHarness.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +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/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol new file mode 100644 index 0000000..5c2f322 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/EnumerableMapHarness.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {EnumerableMap} from "../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/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol new file mode 100644 index 0000000..3d18b18 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/EnumerableSetHarness.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {EnumerableSet} from "../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/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol new file mode 100644 index 0000000..743d677 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/InitializableHarness.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Initializable} from "../patched/proxy/utils/Initializable.sol"; + +contract InitializableHarness is Initializable { + function initialize() public initializer {} + function reinitialize(uint64 n) public reinitializer(n) {} + function disable() public { _disableInitializers(); } + + function nested_init_init() public initializer { initialize(); } + function nested_init_reinit(uint64 m) public initializer { reinitialize(m); } + function nested_reinit_init(uint64 n) public reinitializer(n) { initialize(); } + function nested_reinit_reinit(uint64 n, uint64 m) public reinitializer(n) { reinitialize(m); } + + function version() public view returns (uint64) { + return _getInitializedVersion(); + } + + function initializing() public view returns (bool) { + return _isInitializing(); + } +} diff --git a/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol new file mode 100644 index 0000000..09a5faa --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/Ownable2StepHarness.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable2Step, Ownable} from "../patched/access/Ownable2Step.sol"; + +contract Ownable2StepHarness is Ownable2Step { + constructor(address initialOwner) Ownable(initialOwner) {} + + function restricted() external onlyOwner {} +} diff --git a/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol new file mode 100644 index 0000000..79b4b1b --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/OwnableHarness.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Ownable} from "../patched/access/Ownable.sol"; + +contract OwnableHarness is Ownable { + constructor(address initialOwner) Ownable(initialOwner) {} + + function restricted() external onlyOwner {} +} diff --git a/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol new file mode 100644 index 0000000..5977b92 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/PausableHarness.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Pausable} from "../patched/utils/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/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol b/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol new file mode 100644 index 0000000..95ae406 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/harnesses/TimelockControllerHarness.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {TimelockController} from "../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/lib/openzeppelin-contracts/certora/reports/2021-10.pdf b/lib/openzeppelin-contracts/certora/reports/2021-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..22df9c61e6a9f74b29f90b6e36bd3d04f99756f5 GIT binary patch literal 92882 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 aXJ@ZxYwu)>@+&A9#pUoWT@sTO$NL{da>MEX literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts/certora/reports/2022-03.pdf b/lib/openzeppelin-contracts/certora/reports/2022-03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b6ff81d1812c808e2f683c1e5fe10abf71ba5438 GIT binary patch literal 199401 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

E02esqZ$^2gTs{2 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 literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts/certora/reports/2022-05.pdf b/lib/openzeppelin-contracts/certora/reports/2022-05.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f24a44910c4fba449300987456b5f440e7f99511 GIT binary patch literal 132223 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%0D7|ieYKPVYBX59b!U}f9eB5UvK%HwkWL{dR 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 UVZ$VVhf9Eu51oMlq$-2{KaJIBBLDyZ literal 0 HcmV?d00001 diff --git a/lib/openzeppelin-contracts/certora/run.js b/lib/openzeppelin-contracts/certora/run.js new file mode 100755 index 0000000..7b65534 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/run.js @@ -0,0 +1,160 @@ +#!/usr/bin/env node + +// USAGE: +// 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 proc = require('child_process'); +const { PassThrough } = require('stream'); +const events = require('events'); + +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, + }, + verbose: { + alias: 'v', + type: 'count', + default: 0, + }, + 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); +} + +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; + } +} + +if (process.exitCode) { + process.exit(process.exitCode); +} + +for (const { spec, contract, files, options = [] } of specs) { + limit( + runCertora, + spec, + contract, + files, + [...options, ...argv.options].flatMap(opt => opt.split(' ')), + ); +} + +// 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]; + if (argv.verbose) { + console.log('Running:', args.join(' ')); + } + 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 job id, print the output link + stream.on('data', function logStatusUrl(data) { + 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); + } + }); + + // 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:\/\/prover.certora.com\/output\/\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:', + url ? `[link](${url?.replace('/output/', '/jobStatus/')})` : 'error', + url ? `[link](${url})` : 'error', + ), + ); +} diff --git a/lib/openzeppelin-contracts/certora/specs.json b/lib/openzeppelin-contracts/certora/specs.json new file mode 100644 index 0000000..3e5acb5 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs.json @@ -0,0 +1,86 @@ +[ + { + "spec": "Pausable", + "contract": "PausableHarness", + "files": ["certora/harnesses/PausableHarness.sol"] + }, + { + "spec": "AccessControl", + "contract": "AccessControlHarness", + "files": ["certora/harnesses/AccessControlHarness.sol"] + }, + { + "spec": "AccessControlDefaultAdminRules", + "contract": "AccessControlDefaultAdminRulesHarness", + "files": ["certora/harnesses/AccessControlDefaultAdminRulesHarness.sol"] + }, + { + "spec": "DoubleEndedQueue", + "contract": "DoubleEndedQueueHarness", + "files": ["certora/harnesses/DoubleEndedQueueHarness.sol"] + }, + { + "spec": "Ownable", + "contract": "OwnableHarness", + "files": ["certora/harnesses/OwnableHarness.sol"] + }, + { + "spec": "Ownable2Step", + "contract": "Ownable2StepHarness", + "files": ["certora/harnesses/Ownable2StepHarness.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"] + }, + { + "spec": "ERC20Wrapper", + "contract": "ERC20WrapperHarness", + "files": [ + "certora/harnesses/ERC20PermitHarness.sol", + "certora/harnesses/ERC20WrapperHarness.sol" + ], + "options": [ + "--link ERC20WrapperHarness:_underlying=ERC20PermitHarness", + "--optimistic_loop" + ] + }, + { + "spec": "ERC721", + "contract": "ERC721Harness", + "files": ["certora/harnesses/ERC721Harness.sol", "certora/harnesses/ERC721ReceiverHarness.sol"], + "options": ["--optimistic_loop"] + }, + { + "spec": "Initializable", + "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", + "files": ["certora/harnesses/TimelockControllerHarness.sol"], + "options": ["--optimistic_hashing", "--optimistic_loop"] + } +] diff --git a/lib/openzeppelin-contracts/certora/specs/AccessControl.spec b/lib/openzeppelin-contracts/certora/specs/AccessControl.spec new file mode 100644 index 0000000..70b0672 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/AccessControl.spec @@ -0,0 +1,119 @@ +import "helpers/helpers.spec"; +import "methods/IAccessControl.spec"; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Identify entrypoints: only grantRole, revokeRole and renounceRole can alter permissions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule onlyGrantCanGrant(env e, method f, bytes32 role, address account) { + calldataarg args; + + bool hasRoleBefore = hasRole(role, account); + f(e, args); + bool hasRoleAfter = hasRole(role, account); + + assert ( + !hasRoleBefore && + hasRoleAfter + ) => ( + f.selector == sig:grantRole(bytes32, address).selector + ); + + assert ( + hasRoleBefore && + !hasRoleAfter + ) => ( + f.selector == sig:revokeRole(bytes32, address).selector || + f.selector == sig:renounceRole(bytes32, address).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: grantRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule grantRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + grantRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> isCallerAdmin; + + // effect + assert success => hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: revokeRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule revokeRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender); + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + revokeRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> isCallerAdmin; + + // effect + assert success => !hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: renounceRole only affects the specified user/role combo │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule renounceRoleEffect(env e, bytes32 role) { + require nonpayable(e); + + bytes32 otherRole; + address account; + address otherAccount; + + bool hasOtherRoleBefore = hasRole(otherRole, otherAccount); + + renounceRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + + // liveness + assert success <=> account == e.msg.sender; + + // effect + assert success => !hasRole(role, account); + + // no side effect + assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount); +} diff --git a/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec b/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec new file mode 100644 index 0000000..2f5bb9d --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/AccessControlDefaultAdminRules.spec @@ -0,0 +1,464 @@ +import "helpers/helpers.spec"; +import "methods/IAccessControlDefaultAdminRules.spec"; +import "methods/IAccessControl.spec"; +import "AccessControl.spec"; + +use rule onlyGrantCanGrant filtered { + f -> f.selector != sig:acceptDefaultAdminTransfer().selector +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Definitions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition timeSanity(env e) returns bool = + e.block.timestamp > 0 && e.block.timestamp + defaultAdminDelay(e) < max_uint48; + +definition delayChangeWaitSanity(env e, uint48 newDelay) returns bool = + e.block.timestamp + delayChangeWait_(e, newDelay) < max_uint48; + +definition isSet(uint48 schedule) returns bool = + schedule != 0; + +definition hasPassed(env e, uint48 schedule) returns bool = + assert_uint256(schedule) < e.block.timestamp; + +definition increasingDelaySchedule(env e, uint48 newDelay) returns mathint = + e.block.timestamp + min(newDelay, defaultAdminDelayIncreaseWait()); + +definition decreasingDelaySchedule(env e, uint48 newDelay) returns mathint = + e.block.timestamp + defaultAdminDelay(e) - newDelay; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: defaultAdmin holds the DEFAULT_ADMIN_ROLE │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant defaultAdminConsistency(address account) + (account == defaultAdmin() && account != 0) <=> hasRole(DEFAULT_ADMIN_ROLE(), account) + { + preserved with (env e) { + require nonzerosender(e); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 + { + preserved { + requireInvariant defaultAdminConsistency(account); + requireInvariant defaultAdminConsistency(another); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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); + address adminBefore = defaultAdmin(); + address pendingAdminBefore = pendingDefaultAdmin_(); + uint48 scheduleBefore = pendingDefaultAdminSchedule_(); + + renounceRole@withrevert(e, role, account); + bool success = !lastReverted; + + bool hasOtherRoleAfter = hasRole(otherRole, otherAccount); + address adminAfter = defaultAdmin(); + address pendingAdminAfter = pendingDefaultAdmin_(); + uint48 scheduleAfter = pendingDefaultAdminSchedule_(); + + // liveness + assert success <=> ( + account == e.msg.sender && + ( + role != DEFAULT_ADMIN_ROLE() || + account != adminBefore || + ( + 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"; + + assert success => ( + ( + role == DEFAULT_ADMIN_ROLE() && + account == adminBefore + ) ? ( + adminAfter == 0 && + pendingAdminAfter == 0 && + scheduleAfter == 0 + ) : ( + adminAfter == adminBefore && + pendingAdminAfter == pendingAdminBefore && + scheduleAfter == scheduleBefore + ) + ), + "renouncing default admin role cleans state iff called by previous admin"; + + // 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) { + address adminBefore = defaultAdmin(); + f(e, args); + address adminAfter = defaultAdmin(); + + assert adminBefore != adminAfter => ( + f.selector == sig:acceptDefaultAdminTransfer().selector || + f.selector == sig:renounceRole(bytes32,address).selector + ), + "default admin is only affected by accepting an admin transfer or renoucing"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pendingDefaultAdmin is only affected by beginning, completing (accept or renounce), or canceling an admin │ +│ transfer │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule noPendingDefaultAdminChange(env e, method f, calldataarg args) { + address pendingAdminBefore = pendingDefaultAdmin_(); + uint48 scheduleBefore = pendingDefaultAdminSchedule_(); + f(e, args); + address pendingAdminAfter = pendingDefaultAdmin_(); + uint48 scheduleAfter = pendingDefaultAdminSchedule_(); + + assert ( + pendingAdminBefore != pendingAdminAfter || + scheduleBefore != scheduleAfter + ) => ( + f.selector == sig:beginDefaultAdminTransfer(address).selector || + f.selector == sig:acceptDefaultAdminTransfer().selector || + f.selector == sig:cancelDefaultAdminTransfer().selector || + f.selector == sig:renounceRole(bytes32,address).selector + ), + "pending admin and its schedule is only affected by beginning, completing, or cancelling an admin transfer"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 == sig:changeDefaultAdminDelay(uint48).selector || + f.selector == sig: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 timeSanity(e); + require nonpayable(e); + require nonzerosender(e); + requireInvariant defaultAdminConsistency(e.msg.sender); + + 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 => to_mathint(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(); + + // change can only happen towards the newAdmin, with the delay + assert adminAfter != adminBefore => ( + adminAfter == newAdmin && + to_mathint(e2.block.timestamp) >= e1.block.timestamp + delayBefore + ), + "The admin can only change after the enforced delay and to the previously scheduled new admin"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: acceptDefaultAdminTransfer updates defaultAdmin resetting the pending admin and its schedule │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule acceptDefaultAdminTransfer(env e) { + require nonpayable(e); + + address pendingAdminBefore = pendingDefaultAdmin_(); + uint48 scheduleBefore = pendingDefaultAdminSchedule_(); + + acceptDefaultAdminTransfer@withrevert(e); + bool success = !lastReverted; + + // liveness + assert success <=> ( + e.msg.sender == pendingAdminBefore && + isSet(scheduleBefore) && + hasPassed(e, scheduleBefore) + ), + "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); + require nonzerosender(e); + requireInvariant defaultAdminConsistency(e.msg.sender); + + 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 timeSanity(e); + require nonpayable(e); + require nonzerosender(e); + require delayChangeWaitSanity(e, newDelay); + requireInvariant defaultAdminConsistency(e.msg.sender); + + 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 => ( + assert_uint256(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 != delayBefore => ( + delayAfter == newDelay && + to_mathint(e2.block.timestamp) >= delayWait + ), + "A delay can only change after the 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 => to_mathint(pendingDelaySchedule_(e)) == increasingDelaySchedule(e, newDelay), + "Delay wait is the minimum between the new delay and a threshold when the delay is increased"; + assert newDelay <= oldDelay => to_mathint(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); + require nonzerosender(e); + requireInvariant defaultAdminConsistency(e.msg.sender); + + 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"; +} diff --git a/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec b/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec new file mode 100644 index 0000000..3b71bb4 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/DoubleEndedQueue.spec @@ -0,0 +1,300 @@ +import "helpers/helpers.spec"; + +methods { + function pushFront(bytes32) external envfree; + function pushBack(bytes32) external envfree; + function popFront() external returns (bytes32) envfree; + function popBack() external returns (bytes32) envfree; + function clear() external envfree; + + // exposed for FV + function begin() external returns (uint128) envfree; + function end() external returns (uint128) envfree; + + // view + function length() external returns (uint256) envfree; + function empty() external returns (bool) envfree; + function front() external returns (bytes32) envfree; + function back() external returns (bytes32) envfree; + function at_(uint256) external returns (bytes32) envfree; // at is a reserved word +} + +definition full() returns bool = length() == max_uint128; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: empty() is length 0 and no element exists │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant emptiness() + empty() <=> length() == 0 + filtered { f -> !f.isView } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: front points to the first index and back points to the last one │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant queueFront() + at_(0) == front() + filtered { f -> !f.isView } + +invariant queueBack() + at_(require_uint256(length() - 1)) == back() + filtered { f -> !f.isView } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Function correctness: pushFront adds an element at the beginning of the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushFront(bytes32 value) { + uint256 lengthBefore = length(); + bool fullBefore = full(); + + pushFront@withrevert(value); + bool success = !lastReverted; + + // liveness + assert success <=> !fullBefore, "never revert if not previously full"; + + // effect + assert success => front() == value, "front set to value"; + assert success => to_mathint(length()) == lengthBefore + 1, "queue extended"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pushFront preserves the previous values in the queue with a +1 offset │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushFrontConsistency(uint256 index) { + bytes32 beforeAt = at_(index); + + bytes32 value; + pushFront(value); + + // try to read value + bytes32 afterAt = at_@withrevert(require_uint256(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) { + uint256 lengthBefore = length(); + bool fullBefore = full(); + + pushBack@withrevert(value); + bool success = !lastReverted; + + // liveness + assert success <=> !fullBefore, "never revert if not previously full"; + + // effect + assert success => back() == value, "back set to value"; + assert success => to_mathint(length()) == lengthBefore + 1, "queue increased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: pushBack preserves the previous values in the queue │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule pushBackConsistency(uint256 index) { + 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 { + 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 => to_mathint(length()) == lengthBefore - 1, "queue decreased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: at(x) is preserved and offset to at(x - 1) after calling popFront | +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule popFrontConsistency(uint256 index) { + // 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(require_uint256(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 { + 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 => to_mathint(length()) == lengthBefore - 1, "queue decreased"; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: at(x) is preserved after calling popBack | +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule popBackConsistency(uint256 index) { + // Read (any) value that is not the back (this asserts the value exists / the queue is long enough) + require to_mathint(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 onlyEmptyOrFullRevert(env e) { + require nonpayable(e); + + method f; + calldataarg args; + + bool emptyBefore = empty(); + bool fullBefore = full(); + + f@withrevert(e, args); + + assert lastReverted => ( + (f.selector == sig:front().selector && emptyBefore) || + (f.selector == sig:back().selector && emptyBefore) || + (f.selector == sig:popFront().selector && emptyBefore) || + (f.selector == sig:popBack().selector && emptyBefore) || + (f.selector == sig:pushFront(bytes32).selector && fullBefore ) || + (f.selector == sig:pushBack(bytes32).selector && fullBefore ) || + f.selector == sig: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) { + 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) { + method f; + calldataarg args; + + uint256 lengthBefore = length(); + f(e, args); + uint256 lengthAfter = length(); + + assert lengthAfter != lengthBefore => ( + (f.selector == sig:pushFront(bytes32).selector && to_mathint(lengthAfter) == lengthBefore + 1) || + (f.selector == sig:pushBack(bytes32).selector && to_mathint(lengthAfter) == lengthBefore + 1) || + (f.selector == sig:popBack().selector && to_mathint(lengthAfter) == lengthBefore - 1) || + (f.selector == sig:popFront().selector && to_mathint(lengthAfter) == lengthBefore - 1) || + (f.selector == sig: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) { + 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 == sig:clear().selector ) || + (f.selector == sig:popBack().selector && index == length()) || + (f.selector == sig:popFront().selector && index == length()) + ), "indexes of the queue are only removed by clear or pop"; + + assert atAfterSuccess && atAfter != atBefore => ( + f.selector == sig:popFront().selector || + f.selector == sig:pushFront(bytes32).selector + ), "values of the queue are only changed by popFront or pushFront"; +} diff --git a/lib/openzeppelin-contracts/certora/specs/ERC20.spec b/lib/openzeppelin-contracts/certora/specs/ERC20.spec new file mode 100644 index 0000000..21a0335 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/ERC20.spec @@ -0,0 +1,352 @@ +import "helpers/helpers.spec"; +import "methods/IERC20.spec"; +import "methods/IERC2612.spec"; + +methods { + // exposed for FV + function mint(address,uint256) external; + function burn(address,uint256) external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mathint sumOfBalances { + init_state axiom sumOfBalances == 0; +} + +// Because `balance` has a uint256 type, any balance addition in CVL1 behaved as a `require_uint256()` casting, +// leaving out the possibility of overflow. This is not the case in CVL2 where casting became more explicit. +// A counterexample in CVL2 is having an initial state where Alice initial balance is larger than totalSupply, which +// overflows Alice's balance when receiving a transfer. This is not possible unless the contract is deployed into an +// already used address (or upgraded from corrupted state). +// We restrict such behavior by making sure no balance is greater than the sum of balances. +hook Sload uint256 balance _balances[KEY address addr] STORAGE { + require sumOfBalances >= to_mathint(balance); +} + +hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) STORAGE { + sumOfBalances = sumOfBalances - oldValue + newValue; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: totalSupply is the sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant totalSupplyIsSumOfBalances() + to_mathint(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 == sig:mint(address,uint256).selector; + assert totalSupplyAfter < totalSupplyBefore => f.selector == sig: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 == sig:burn(address,uint256).selector || + e.msg.sender == account || + balanceBefore - balanceAfter <= to_mathint(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 == sig:approve(address,uint256).selector && e.msg.sender == holder) || + (f.selector == sig:permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector) + ); + + assert ( + allowanceAfter < allowanceBefore + ) => ( + (f.selector == sig:transferFrom(address,address,uint256).selector && e.msg.sender == spender) || + (f.selector == sig:approve(address,uint256).selector && e.msg.sender == holder ) || + (f.selector == sig:permit(address,address,uint256,uint256,uint8,bytes32,bytes32).selector) + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 to_mathint(balanceOf(to)) == toBalanceBefore + amount; + assert to_mathint(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 to_mathint(balanceOf(from)) == fromBalanceBefore - amount; + assert to_mathint(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 to_mathint(balanceOf(holder)) == holderBalanceBefore - (holder == recipient ? 0 : amount); + assert to_mathint(balanceOf(recipient)) == recipientBalanceBefore + (holder == recipient ? 0 : amount); + + // no other balance is modified + assert balanceOf(other) != otherBalanceBefore => (other == holder || other == recipient); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 to_mathint(allowance(holder, spender)) == (allowanceBefore == max_uint256 ? max_uint256 : allowanceBefore - amount); + + // balances of holder and recipient are updated + assert to_mathint(balanceOf(holder)) == holderBalanceBefore - (holder == recipient ? 0 : amount); + assert to_mathint(balanceOf(recipient)) == recipientBalanceBefore + (holder == recipient ? 0 : amount); + + // no other balance is modified + assert balanceOf(other) != otherBalanceBefore => (other == holder || other == recipient); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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: 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 to_mathint(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/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec b/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec new file mode 100644 index 0000000..5c87f0d --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/ERC20FlashMint.spec @@ -0,0 +1,55 @@ +import "helpers/helpers.spec"; +import "methods/IERC20.spec"; +import "methods/IERC3156FlashLender.spec"; +import "methods/IERC3156FlashBorrower.spec"; + +methods { + // non standard ERC3156 functions + function flashFeeReceiver() external returns (address) envfree; + + // function summaries below + function _._update(address from, address to, uint256 amount) internal => specUpdate(from, to, amount) expect void ALL; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost: track mint and burns in the CVL │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mapping(address => mathint) trackedMintAmount; +ghost mapping(address => mathint) trackedBurnAmount; +ghost mapping(address => mapping(address => mathint)) trackedTransferedAmount; + +function specUpdate(address from, address to, uint256 amount) { + if (from == 0 && to == 0) { assert(false); } // defensive + + if (from == 0) { + trackedMintAmount[to] = amount; + } else if (to == 0) { + trackedBurnAmount[from] = amount; + } else { + trackedTransferedAmount[from][to] = amount; + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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] == to_mathint(amount); + assert trackedBurnAmount[receiver] == amount + to_mathint(recipient == 0 ? fees : 0); + assert (fees > 0 && recipient != 0) => trackedTransferedAmount[receiver][recipient] == to_mathint(fees); +} diff --git a/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec b/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec new file mode 100644 index 0000000..04e6704 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/ERC20Wrapper.spec @@ -0,0 +1,198 @@ +import "helpers/helpers.spec"; +import "ERC20.spec"; + +methods { + function underlying() external returns(address) envfree; + function underlyingTotalSupply() external returns(uint256) envfree; + function underlyingBalanceOf(address) external returns(uint256) envfree; + function underlyingAllowanceToThis(address) external returns(uint256) envfree; + + function depositFor(address, uint256) external returns(bool); + function withdrawTo(address, uint256) external returns(bool); + function recover(address) external returns(uint256); +} + +use invariant totalSupplyIsSumOfBalances; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helper: consequence of `totalSupplyIsSumOfBalances` applied to underlying │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition underlyingBalancesLowerThanUnderlyingSupply(address a) returns bool = + underlyingBalanceOf(a) <= underlyingTotalSupply(); + +definition sumOfUnderlyingBalancesLowerThanUnderlyingSupply(address a, address b) returns bool = + a != b => underlyingBalanceOf(a) + underlyingBalanceOf(b) <= to_mathint(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 != currentContract && // invalid receiver + receiver != 0 && // invalid receiver + amount <= senderUnderlyingBalanceBefore && // deposit doesn't exceed balance + amount <= senderUnderlyingAllowanceBefore // deposit doesn't exceed allowance + ); + + // effects + assert success => ( + to_mathint(balanceOf(receiver)) == balanceBefore + amount && + to_mathint(totalSupply()) == supplyBefore + amount && + to_mathint(underlyingBalanceOf(currentContract)) == wrapperUnderlyingBalanceBefore + amount && + to_mathint(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 != currentContract && // invalid receiver + receiver != 0 && // invalid receiver + amount <= balanceBefore // withdraw doesn't exceed balance + ); + + // effects + assert success => ( + to_mathint(balanceOf(sender)) == balanceBefore - amount && + to_mathint(totalSupply()) == supplyBefore - amount && + to_mathint(underlyingBalanceOf(currentContract)) == wrapperUnderlyingBalanceBefore - (currentContract != receiver ? amount : 0) && + to_mathint(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; + + mathint 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 => ( + to_mathint(balanceOf(receiver)) == balanceBefore + value && + to_mathint(totalSupply()) == supplyBefore + value && + totalSupply() == underlyingBalanceOf(currentContract) + ); + + // no side effect + assert underlyingBalanceOf(other) == otherUnderlyingBalanceBefore; + assert balanceOf(other) != otherBalanceBefore => other == receiver; +} diff --git a/lib/openzeppelin-contracts/certora/specs/ERC721.spec b/lib/openzeppelin-contracts/certora/specs/ERC721.spec new file mode 100644 index 0000000..bad4c47 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/ERC721.spec @@ -0,0 +1,679 @@ +import "helpers/helpers.spec"; +import "methods/IERC721.spec"; +import "methods/IERC721Receiver.spec"; + +methods { + // exposed for FV + function mint(address,uint256) external; + function safeMint(address,uint256) external; + function safeMint(address,uint256,bytes) external; + function burn(uint256) external; + + function unsafeOwnerOf(uint256) external returns (address) envfree; + function unsafeGetApproved(uint256) external returns (address) envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ + +definition authSanity(env e) returns bool = e.msg.sender != 0; + +// Could be broken in theory, but not in practice +definition balanceLimited(address account) returns bool = balanceOf(account) < max_uint256; + +function helperTransferWithRevert(env e, method f, address from, address to, uint256 tokenId) { + if (f.selector == sig:transferFrom(address,address,uint256).selector) { + transferFrom@withrevert(e, from, to, tokenId); + } else if (f.selector == sig:safeTransferFrom(address,address,uint256).selector) { + safeTransferFrom@withrevert(e, from, to, tokenId); + } else if (f.selector == sig: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 == sig:mint(address,uint256).selector) { + mint@withrevert(e, to, tokenId); + } else if (f.selector == sig:safeMint(address,uint256).selector) { + safeMint@withrevert(e, to, tokenId); + } else if (f.selector == sig:safeMint(address,uint256,bytes).selector) { + bytes params; + require params.length < 0xffff; + safeMint@withrevert(e, to, tokenId, params); + } else { + require false; + } +} + +function helperSoundFnCall(env e, method f) { + if (f.selector == sig:mint(address,uint256).selector) { + address to; uint256 tokenId; + require balanceLimited(to); + requireInvariant notMintedUnset(tokenId); + mint(e, to, tokenId); + } else if (f.selector == sig:safeMint(address,uint256).selector) { + address to; uint256 tokenId; + require balanceLimited(to); + requireInvariant notMintedUnset(tokenId); + safeMint(e, to, tokenId); + } else if (f.selector == sig:safeMint(address,uint256,bytes).selector) { + address to; uint256 tokenId; bytes data; + require data.length < 0xffff; + require balanceLimited(to); + requireInvariant notMintedUnset(tokenId); + safeMint(e, to, tokenId, data); + } else if (f.selector == sig:burn(uint256).selector) { + uint256 tokenId; + requireInvariant ownerHasBalance(tokenId); + requireInvariant notMintedUnset(tokenId); + burn(e, tokenId); + } else if (f.selector == sig:transferFrom(address,address,uint256).selector) { + address from; address to; uint256 tokenId; + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant notMintedUnset(tokenId); + transferFrom(e, from, to, tokenId); + } else if (f.selector == sig:safeTransferFrom(address,address,uint256).selector) { + address from; address to; uint256 tokenId; + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant notMintedUnset(tokenId); + safeTransferFrom(e, from, to, tokenId); + } else if (f.selector == sig:safeTransferFrom(address,address,uint256,bytes).selector) { + address from; address to; uint256 tokenId; bytes data; + require data.length < 0xffff; + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant notMintedUnset(tokenId); + safeTransferFrom(e, from, to, tokenId, data); + } else { + calldataarg args; + f(e, args); + } +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: ownership count │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mathint _ownedTotal { + init_state axiom _ownedTotal == 0; +} + +ghost mapping(address => mathint) _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_mathint(newOwner != 0 ? 1 : 0); + _ownedByUser[oldOwner] = _ownedByUser[oldOwner] - to_mathint(oldOwner != 0 ? 1 : 0); + _ownedTotal = _ownedTotal + to_mathint(newOwner != 0 ? 1 : 0) - to_mathint(oldOwner != 0 ? 1 : 0); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Ghost & hooks: sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +ghost mathint _supply { + init_state axiom _supply == 0; +} + +ghost mapping(address => mathint) _balances { + init_state axiom forall address a. _balances[a] == 0; +} + +hook Sstore _balances[KEY address addr] uint256 newValue (uint256 oldValue) STORAGE { + _supply = _supply - oldValue + newValue; +} + +// TODO: This used to not be necessary. We should try to remove it. In order to do so, we will probably need to add +// many "preserved" directive that require the "balanceOfConsistency" invariant on the accounts involved. +hook Sload uint256 value _balances[KEY address user] STORAGE { + require _balances[user] == to_mathint(value); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: number of owned tokens is the sum of all balances │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant ownedTotalIsSumOfBalances() + _ownedTotal == _supply + { + preserved mint(address to, uint256 tokenId) with (env e) { + require balanceLimited(to); + } + preserved safeMint(address to, uint256 tokenId) with (env e) { + require balanceLimited(to); + } + preserved safeMint(address to, uint256 tokenId, bytes data) with (env e) { + require balanceLimited(to); + } + preserved burn(uint256 tokenId) with (env e) { + requireInvariant ownerHasBalance(tokenId); + requireInvariant balanceOfConsistency(ownerOf(tokenId)); + } + preserved transferFrom(address from, address to, uint256 tokenId) with (env e) { + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant balanceOfConsistency(from); + requireInvariant balanceOfConsistency(to); + } + preserved safeTransferFrom(address from, address to, uint256 tokenId) with (env e) { + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant balanceOfConsistency(from); + requireInvariant balanceOfConsistency(to); + } + preserved safeTransferFrom(address from, address to, uint256 tokenId, bytes data) with (env e) { + require balanceLimited(to); + requireInvariant ownerHasBalance(tokenId); + requireInvariant balanceOfConsistency(from); + requireInvariant balanceOfConsistency(to); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: balanceOf is the number of tokens owned │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant balanceOfConsistency(address user) + to_mathint(balanceOf(user)) == _ownedByUser[user] && + to_mathint(balanceOf(user)) == _balances[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)); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: balance of address(0) is 0 │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule zeroAddressBalanceRevert() { + balanceOf@withrevert(0); + assert lastReverted; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: address(0) has no authorized operator │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant zeroAddressHasNoApprovedOperator(address a) + !isApprovedForAll(0, a) + { + preserved with (env e) { + require nonzerosender(e); + } + } + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: tokens that do not exist are not owned and not approved │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant notMintedUnset(uint256 tokenId) + unsafeOwnerOf(tokenId) == 0 => unsafeGetApproved(tokenId) == 0; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: unsafeOwnerOf and unsafeGetApproved don't revert + ownerOf and getApproved revert if token does not exist │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule notMintedRevert(uint256 tokenId) { + requireInvariant notMintedUnset(tokenId); + + address _owner = unsafeOwnerOf@withrevert(tokenId); + assert !lastReverted; + + address _approved = unsafeGetApproved@withrevert(tokenId); + assert !lastReverted; + + address owner = ownerOf@withrevert(tokenId); + assert lastReverted <=> _owner == 0; + assert !lastReverted => _owner == owner; + + address approved = getApproved@withrevert(tokenId); + assert lastReverted <=> _owner == 0; + assert !lastReverted => _approved == approved; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: total supply can only change through mint and burn │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule supplyChange(env e) { + require nonzerosender(e); + requireInvariant zeroAddressHasNoApprovedOperator(e.msg.sender); + + mathint supplyBefore = _supply; + method f; helperSoundFnCall(e, f); + mathint supplyAfter = _supply; + + assert supplyAfter > supplyBefore => ( + supplyAfter == supplyBefore + 1 && + ( + f.selector == sig:mint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256,bytes).selector + ) + ); + assert supplyAfter < supplyBefore => ( + supplyAfter == supplyBefore - 1 && + f.selector == sig: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); + + mathint balanceBefore = balanceOf(account); + method f; helperSoundFnCall(e, f); + mathint 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 == sig:transferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256,bytes).selector || + f.selector == sig:mint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256,bytes).selector || + f.selector == sig:burn(uint256).selector + ); +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rules: ownership can only change through mint, burn or transfers. │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule ownershipChange(env e, uint256 tokenId) { + require nonzerosender(e); + requireInvariant zeroAddressHasNoApprovedOperator(e.msg.sender); + + address ownerBefore = unsafeOwnerOf(tokenId); + method f; helperSoundFnCall(e, f); + address ownerAfter = unsafeOwnerOf(tokenId); + + assert ownerBefore == 0 && ownerAfter != 0 => ( + f.selector == sig:mint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256,bytes).selector + ); + + assert ownerBefore != 0 && ownerAfter == 0 => ( + f.selector == sig:burn(uint256).selector + ); + + assert (ownerBefore != ownerAfter && ownerBefore != 0 && ownerAfter != 0) => ( + f.selector == sig:transferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256).selector || + f.selector == sig: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; helperSoundFnCall(e, f); + address approvalAfter = unsafeGetApproved(tokenId); + + // approve can set any value, other functions reset + assert approvalBefore != approvalAfter => ( + f.selector == sig:approve(address,uint256).selector || + ( + ( + f.selector == sig:transferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256,bytes).selector || + f.selector == sig: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; helperSoundFnCall(e, f); + bool approvedForAllAfter = isApprovedForAll(owner, spender); + + assert approvedForAllBefore != approvedForAllAfter => f.selector == sig:setApprovalForAll(address,bool).selector; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Rule: transferFrom behavior and side effects │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +rule transferFrom(env e, address from, address to, uint256 tokenId) { + require nonpayable(e); + require authSanity(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 => ( + to_mathint(balanceOf(from)) == balanceOfFromBefore - assert_uint256(from != to ? 1 : 0) && + to_mathint(balanceOf(to)) == balanceOfToBefore + assert_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 == sig:safeTransferFrom(address,address,uint256).selector || + f.selector == sig:safeTransferFrom(address,address,uint256,bytes).selector +} { + require nonpayable(e); + require authSanity(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 => ( + to_mathint(balanceOf(from)) == balanceOfFromBefore - assert_uint256(from != to ? 1: 0) && + to_mathint(balanceOf(to)) == balanceOfToBefore + assert_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); + + mathint supplyBefore = _supply; + 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 => ( + _supply == supplyBefore + 1 && + to_mathint(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 == sig:safeMint(address,uint256).selector || + f.selector == sig:safeMint(address,uint256,bytes).selector +} { + require nonpayable(e); + requireInvariant notMintedUnset(tokenId); + + uint256 otherTokenId; + address otherAccount; + + require balanceLimited(to); + + mathint supplyBefore = _supply; + 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 => ( + _supply == supplyBefore + 1 && + to_mathint(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); + + mathint supplyBefore = _supply; + 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 => ( + _supply == supplyBefore - 1 && + to_mathint(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); + require authSanity(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 == 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 <=> operator != 0; + + // effect + assert success => isApprovedForAll(owner, operator) == approved; + + // no side effect + assert isApprovedForAll(otherOwner, otherOperator) != otherIsApprovedForAllBefore => ( + otherOwner == owner && + otherOperator == operator + ); +} diff --git a/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec b/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec new file mode 100644 index 0000000..7b50303 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/EnumerableMap.spec @@ -0,0 +1,333 @@ +import "helpers/helpers.spec"; + +methods { + // library + function set(bytes32,bytes32) external returns (bool) envfree; + function remove(bytes32) external returns (bool) envfree; + function contains(bytes32) external returns (bool) envfree; + function length() external returns (uint256) envfree; + function key_at(uint256) external returns (bytes32) envfree; + function value_at(uint256) external returns (bytes32) envfree; + function tryGet_contains(bytes32) external returns (bool) envfree; + function tryGet_value(bytes32) external returns (bytes32) envfree; + function get(bytes32) external returns (bytes32) envfree; + + // FV + function _indexOf(bytes32) external returns (uint256) envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition sanity() returns bool = + 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) == to_bytes32(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(require_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, require_uint256(length() - 1)); + requireInvariant atUniqueness(index2, require_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() => to_mathint(_indexOf(key_at(index))) == index + 1 + { + preserved remove(bytes32 key) { + requireInvariant consistencyIndex(require_uint256(length() - 1)); + } + } + +invariant consistencyKey(bytes32 key) + contains(key) => ( + _indexOf(key) > 0 && + _indexOf(key) <= length() && + key_at(require_uint256(_indexOf(key) - 1)) == key + ) + { + preserved remove(bytes32 otherKey) { + requireInvariant consistencyKey(otherKey); + requireInvariant atUniqueness( + require_uint256(_indexOf(key) - 1), + require_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 == sig:set(bytes32,bytes32).selector && to_mathint(lengthAfter) == lengthBefore + 1) || + (f.selector == sig:remove(bytes32).selector && to_mathint(lengthAfter) == lengthBefore - 1) + ); + + assert containsBefore != containsAfter => ( + (f.selector == sig:set(bytes32,bytes32).selector && containsAfter) || + (f.selector == sig:remove(bytes32).selector && !containsAfter) + ); + + assert valueBefore != valueAfter => ( + (f.selector == sig:set(bytes32,bytes32).selector && containsAfter) || + (f.selector == sig:remove(bytes32).selector && !containsAfter && valueAfter == to_bytes32(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 == to_bytes32(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 to_mathint(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 to_mathint(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 = require_uint256(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/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec b/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec new file mode 100644 index 0000000..3db5158 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/EnumerableSet.spec @@ -0,0 +1,246 @@ +import "helpers/helpers.spec"; + +methods { + // library + function add(bytes32) external returns (bool) envfree; + function remove(bytes32) external returns (bool) envfree; + function contains(bytes32) external returns (bool) envfree; + function length() external returns (uint256) envfree; + function at_(uint256) external returns (bytes32) envfree; + + // FV + function _indexOf(bytes32) external returns (uint256) envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition sanity() returns bool = + length() < max_uint256; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariant: All indexed keys are contained │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant indexedContained(uint256 index) + index < length() => contains(at_(index)) + { + preserved { + requireInvariant consistencyIndex(index); + requireInvariant consistencyIndex(require_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, require_uint256(length() - 1)); + requireInvariant atUniqueness(index2, require_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)) == require_uint256(index + 1) + { + preserved remove(bytes32 key) { + requireInvariant consistencyIndex(require_uint256(length() - 1)); + } + } + +invariant consistencyKey(bytes32 key) + contains(key) => ( + _indexOf(key) > 0 && + _indexOf(key) <= length() && + at_(require_uint256(_indexOf(key) - 1)) == key + ) + { + preserved remove(bytes32 otherKey) { + requireInvariant consistencyKey(otherKey); + requireInvariant atUniqueness( + require_uint256(_indexOf(key) - 1), + require_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 == sig:add(bytes32).selector && lengthAfter == require_uint256(lengthBefore + 1)) || + (f.selector == sig:remove(bytes32).selector && lengthAfter == require_uint256(lengthBefore - 1)) + ); + + assert containsBefore != containsAfter => ( + (f.selector == sig:add(bytes32).selector && containsAfter) || + (f.selector == sig: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() == require_uint256(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() == require_uint256(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 = require_uint256(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 + ); +} diff --git a/lib/openzeppelin-contracts/certora/specs/Initializable.spec b/lib/openzeppelin-contracts/certora/specs/Initializable.spec new file mode 100644 index 0000000..07c2930 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/Initializable.spec @@ -0,0 +1,165 @@ +import "helpers/helpers.spec"; + +methods { + // initialize, reinitialize, disable + function initialize() external envfree; + function reinitialize(uint64) external envfree; + function disable() external envfree; + + function nested_init_init() external envfree; + function nested_init_reinit(uint64) external envfree; + function nested_reinit_init(uint64) external envfree; + function nested_reinit_reinit(uint64,uint64) external envfree; + + // view + function version() external returns uint64 envfree; + function initializing() external returns bool envfree; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Definitions │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +definition isUninitialized() returns bool = version() == 0; +definition isInitialized() returns bool = version() > 0; +definition isDisabled() returns bool = version() == max_uint64; + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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) { + uint64 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(); + + uint64 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(uint64 m) { + nested_init_reinit@withrevert(m); + assert lastReverted, "nested initializers"; +} + +rule cannotNestInitializers_reinit_init(uint64 n) { + nested_reinit_init@withrevert(n); + assert lastReverted, "nested initializers"; +} + +rule cannotNestInitializers_reinit_reinit(uint64 n, uint64 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(); + + uint64 versionBefore = version(); + + uint64 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"; +} diff --git a/lib/openzeppelin-contracts/certora/specs/Ownable.spec b/lib/openzeppelin-contracts/certora/specs/Ownable.spec new file mode 100644 index 0000000..0d50813 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/Ownable.spec @@ -0,0 +1,77 @@ +import "helpers/helpers.spec"; +import "methods/IOwnable.spec"; + +methods { + function restricted() external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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) { + address oldCurrent = owner(); + + method f; 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 == sig:transferOwnership(address).selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && f.selector == sig:renounceOwnership().selector) + ); +} diff --git a/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec b/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec new file mode 100644 index 0000000..d13c6d3 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/Ownable2Step.spec @@ -0,0 +1,108 @@ +import "helpers/helpers.spec"; +import "methods/IOwnable2Step.spec"; + +methods { + function restricted() external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 == sig:acceptOwnership().selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == sig:renounceOwnership().selector) + ); + + // If pending changes, must be either acceptance or reset + assert oldPending != newPending => ( + (e.msg.sender == oldCurrent && newCurrent == oldCurrent && f.selector == sig:transferOwnership(address).selector) || + (e.msg.sender == oldPending && newCurrent == oldPending && newPending == 0 && f.selector == sig:acceptOwnership().selector) || + (e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == sig:renounceOwnership().selector) + ); +} diff --git a/lib/openzeppelin-contracts/certora/specs/Pausable.spec b/lib/openzeppelin-contracts/certora/specs/Pausable.spec new file mode 100644 index 0000000..a7aff9c --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/Pausable.spec @@ -0,0 +1,96 @@ +import "helpers/helpers.spec"; + +methods { + function paused() external returns (bool) envfree; + function pause() external; + function unpause() external; + function onlyWhenPaused() external; + function onlyWhenNotPaused() external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ 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 == sig:unpause().selector) || + (pausedAfter && f.selector == sig:pause().selector) + ), "contract's paused status can only be changed by _pause() or _unpause()"; +} diff --git a/lib/openzeppelin-contracts/certora/specs/TimelockController.spec b/lib/openzeppelin-contracts/certora/specs/TimelockController.spec new file mode 100644 index 0000000..5123768 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/TimelockController.spec @@ -0,0 +1,274 @@ +import "helpers/helpers.spec"; +import "methods/IAccessControl.spec"; + +methods { + function PROPOSER_ROLE() external returns (bytes32) envfree; + function EXECUTOR_ROLE() external returns (bytes32) envfree; + function CANCELLER_ROLE() external returns (bytes32) envfree; + function isOperation(bytes32) external returns (bool); + function isOperationPending(bytes32) external returns (bool); + function isOperationReady(bytes32) external returns (bool); + function isOperationDone(bytes32) external returns (bool); + function getTimestamp(bytes32) external returns (uint256) envfree; + function getMinDelay() external returns (uint256) envfree; + + function hashOperation(address, uint256, bytes, bytes32, bytes32) external returns(bytes32) envfree; + function hashOperationBatch(address[], uint256[], bytes[], bytes32, bytes32) external returns(bytes32) envfree; + + function schedule(address, uint256, bytes, bytes32, bytes32, uint256) external; + function scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256) external; + function execute(address, uint256, bytes, bytes32, bytes32) external; + function executeBatch(address[], uint256[], bytes[], bytes32, bytes32) external; + function cancel(bytes32) external; + + function updateDelay(uint256) external; +} + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Helpers │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +// Uniformly handle scheduling of batched and non-batched operations. +function helperScheduleWithRevert(env e, method f, bytes32 id, uint256 delay) { + if (f.selector == sig: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 == sig: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 == sig: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 == sig: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(env e, bytes32 id) returns bool = !isOperation(e, id); +definition isPending(env e, bytes32 id) returns bool = isOperationPending(e, id); +definition isDone(env e, bytes32 id) returns bool = isOperationDone(e, id); +definition state(env e, bytes32 id) returns uint8 = (isUnset(e, id) ? UNSET() : 0) | (isPending(e, id) ? PENDING() : 0) | (isDone(e, id) ? DONE() : 0); + +/* +┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ +│ Invariants: consistency of accessors │ +└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ +*/ +invariant isOperationCheck(env e, bytes32 id) + isOperation(e, id) <=> getTimestamp(id) > 0 + filtered { f -> !f.isView } + +invariant isOperationPendingCheck(env e, bytes32 id) + isOperationPending(e, id) <=> getTimestamp(id) > DONE_TIMESTAMP() + filtered { f -> !f.isView } + +invariant isOperationDoneCheck(env e, bytes32 id) + isOperationDone(e, id) <=> getTimestamp(id) == DONE_TIMESTAMP() + filtered { f -> !f.isView } + +invariant isOperationReadyCheck(env e, bytes32 id) + isOperationReady(e, id) <=> (isOperationPending(e, 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(e, id) <=> (!isPending(e, id) && !isDone(e, id) )) && + (isPending(e, id) <=> (!isUnset(e, id) && !isDone(e, id) )) && + (isDone(e, id) <=> (!isUnset(e, id) && !isPending(e, id))) && + // Check that the state helper behaves as expected: + (isUnset(e, id) <=> state(e, id) == UNSET() ) && + (isPending(e, id) <=> state(e, id) == PENDING() ) && + (isDone(e, id) <=> state(e, id) == DONE() ) && + // Check substate + isOperationReady(e, id) => isPending(e, 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(e, id); + f(e, args); + uint8 stateAfter = state(e, id); + + // Cannot jump from UNSET to DONE + assert stateBefore == UNSET() => stateAfter != DONE(); + + // UNSET → PENDING: schedule or scheduleBatch + assert stateBefore == UNSET() && stateAfter == PENDING() => ( + f.selector == sig:schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector || + f.selector == sig:scheduleBatch(address[], uint256[], bytes[], bytes32, bytes32, uint256).selector + ); + + // PENDING → UNSET: cancel + assert stateBefore == PENDING() && stateAfter == UNSET() => ( + f.selector == sig:cancel(bytes32).selector + ); + + // PENDING → DONE: execute or executeBatch + assert stateBefore == PENDING() && stateAfter == DONE() => ( + f.selector == sig:execute(address, uint256, bytes, bytes32, bytes32).selector || + f.selector == sig: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 == sig: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 == sig:schedule(address, uint256, bytes, bytes32, bytes32, uint256).selector || + f.selector == sig: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(e, 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(e, id) == PENDING(), "State transition violation"; + assert success => getTimestamp(id) == require_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 == sig:execute(address, uint256, bytes, bytes32, bytes32).selector || + f.selector == sig:executeBatch(address[], uint256[], bytes[], bytes32, bytes32).selector +} { + bytes32 otherId; uint256 otherTimestamp = getTimestamp(otherId); + + uint8 stateBefore = state(e, id); + bool isOperationReadyBefore = isOperationReady(e, id); + bool isExecutorOrOpen = hasRole(EXECUTOR_ROLE(), e.msg.sender) || hasRole(EXECUTOR_ROLE(), 0); + bool predecessorDependency = predecessor == to_bytes32(0) || isDone(e, 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(e, 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(e, 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(e, id) == UNSET(), "State transition violation"; + + // no side effect + assert otherTimestamp != getTimestamp(otherId) => id == otherId, "Other proposal affected"; +} diff --git a/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec b/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec new file mode 100644 index 0000000..a6c1e23 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/helpers/helpers.spec @@ -0,0 +1,7 @@ +// environment +definition nonpayable(env e) returns bool = e.msg.value == 0; +definition nonzerosender(env e) returns bool = e.msg.sender != 0; + +// math +definition min(mathint a, mathint b) returns mathint = a < b ? a : b; +definition max(mathint a, mathint b) returns mathint = a > b ? a : b; diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec b/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec new file mode 100644 index 0000000..5c395b0 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IAccessControl.spec @@ -0,0 +1,8 @@ +methods { + function DEFAULT_ADMIN_ROLE() external returns (bytes32) envfree; + function hasRole(bytes32, address) external returns(bool) envfree; + function getRoleAdmin(bytes32) external returns(bytes32) envfree; + function grantRole(bytes32, address) external; + function revokeRole(bytes32, address) external; + function renounceRole(bytes32, address) external; +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec b/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec new file mode 100644 index 0000000..d02db18 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IAccessControlDefaultAdminRules.spec @@ -0,0 +1,36 @@ +import "./IERC5313.spec"; + +methods { + // === View == + + // Default Admin + function defaultAdmin() external returns(address) envfree; + function pendingDefaultAdmin() external returns(address, uint48) envfree; + + // Default Admin Delay + function defaultAdminDelay() external returns(uint48); + function pendingDefaultAdminDelay() external returns(uint48, uint48); + function defaultAdminDelayIncreaseWait() external returns(uint48) envfree; + + // === Mutations == + + // Default Admin + function beginDefaultAdminTransfer(address) external; + function cancelDefaultAdminTransfer() external; + function acceptDefaultAdminTransfer() external; + + // Default Admin Delay + function changeDefaultAdminDelay(uint48) external; + function rollbackDefaultAdminDelay() external; + + // == FV == + + // Default Admin + function pendingDefaultAdmin_() external returns (address) envfree; + function pendingDefaultAdminSchedule_() external returns (uint48) envfree; + + // Default Admin Delay + function pendingDelay_() external returns (uint48); + function pendingDelaySchedule_() external returns (uint48); + function delayChangeWait_(uint48) external returns (uint48); +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec b/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec new file mode 100644 index 0000000..100901a --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IERC20.spec @@ -0,0 +1,11 @@ +methods { + function name() external returns (string) envfree; + function symbol() external returns (string) envfree; + function decimals() external returns (uint8) envfree; + function totalSupply() external returns (uint256) envfree; + function balanceOf(address) external returns (uint256) envfree; + function allowance(address,address) external returns (uint256) envfree; + function approve(address,uint256) external returns (bool); + function transfer(address,uint256) external returns (bool); + function transferFrom(address,address,uint256) external returns (bool); +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec b/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec new file mode 100644 index 0000000..4ecc17b --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IERC2612.spec @@ -0,0 +1,5 @@ +methods { + function permit(address,address,uint256,uint256,uint8,bytes32,bytes32) external; + function nonces(address) external returns (uint256) envfree; + function DOMAIN_SEPARATOR() external returns (bytes32) envfree; +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec b/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec new file mode 100644 index 0000000..733c168 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashBorrower.spec @@ -0,0 +1,3 @@ +methods { + function _.onFlashLoan(address,address,uint256,uint256,bytes) external => DISPATCHER(true); +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec b/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec new file mode 100644 index 0000000..66ed14c --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IERC3156FlashLender.spec @@ -0,0 +1,5 @@ +methods { + function maxFlashLoan(address) external returns (uint256) envfree; + function flashFee(address,uint256) external returns (uint256) envfree; + function flashLoan(address,address,uint256,bytes) external returns (bool); +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec b/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec new file mode 100644 index 0000000..f1d469f --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IERC5313.spec @@ -0,0 +1,3 @@ +methods { + function owner() external returns (address) envfree; +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec b/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec new file mode 100644 index 0000000..34ff50b --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IERC721.spec @@ -0,0 +1,17 @@ +methods { + // IERC721 + function balanceOf(address) external returns (uint256) envfree; + function ownerOf(uint256) external returns (address) envfree; + function getApproved(uint256) external returns (address) envfree; + function isApprovedForAll(address,address) external returns (bool) envfree; + function safeTransferFrom(address,address,uint256,bytes) external; + function safeTransferFrom(address,address,uint256) external; + function transferFrom(address,address,uint256) external; + function approve(address,uint256) external; + function setApprovalForAll(address,bool) external; + + // IERC721Metadata + function name() external returns (string); + function symbol() external returns (string); + function tokenURI(uint256) external returns (string); +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec b/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec new file mode 100644 index 0000000..e6bdf42 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IERC721Receiver.spec @@ -0,0 +1,3 @@ +methods { + function _.onERC721Received(address,address,uint256,bytes) external => DISPATCHER(true); +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec b/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec new file mode 100644 index 0000000..4d7c925 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IOwnable.spec @@ -0,0 +1,5 @@ +methods { + function owner() external returns (address) envfree; + function transferOwnership(address) external; + function renounceOwnership() external; +} diff --git a/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec b/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec new file mode 100644 index 0000000..e6a9957 --- /dev/null +++ b/lib/openzeppelin-contracts/certora/specs/methods/IOwnable2Step.spec @@ -0,0 +1,7 @@ +methods { + function owner() external returns (address) envfree; + function pendingOwner() external returns (address) envfree; + function transferOwnership(address) external; + function acceptOwnership() external; + function renounceOwnership() external; +} diff --git a/lib/openzeppelin-contracts/contracts/access/AccessControl.sol b/lib/openzeppelin-contracts/contracts/access/AccessControl.sol new file mode 100644 index 0000000..3e3341e --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/AccessControl.sol @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol) + +pragma solidity ^0.8.20; + +import {IAccessControl} from "./IAccessControl.sol"; +import {Context} from "../utils/Context.sol"; +import {ERC165} from "../utils/introspection/ERC165.sol"; + +/** + * @dev Contract module that allows children to implement role-based access + * control mechanisms. This is a lightweight version that doesn't allow enumerating role + * members except through off-chain means by accessing the contract event logs. Some + * applications may benefit from on-chain enumerability, for those cases see + * {AccessControlEnumerable}. + * + * Roles are referred to by their `bytes32` identifier. These should be exposed + * 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)); + * ... + * } + * ``` + * + * Roles can be granted and revoked dynamically via the {grantRole} and + * {revokeRole} functions. Each role has an associated admin role, and only + * accounts that have a role's admin role can call {grantRole} and {revokeRole}. + * + * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means + * that only accounts with this role will be able to grant or revoke other + * roles. More complex role relationships can be created by using + * {_setRoleAdmin}. + * + * 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. We recommend using {AccessControlDefaultAdminRules} + * to enforce additional security measures for this role. + */ +abstract contract AccessControl is Context, IAccessControl, ERC165 { + struct RoleData { + mapping(address account => bool) hasRole; + bytes32 adminRole; + } + + mapping(bytes32 role => RoleData) private _roles; + + bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00; + + /** + * @dev Modifier that checks that an account has a specific role. Reverts + * with an {AccessControlUnauthorizedAccount} error including the required role. + */ + modifier onlyRole(bytes32 role) { + _checkRole(role); + _; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) public view virtual returns (bool) { + return _roles[role].hasRole[account]; + } + + /** + * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()` + * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier. + */ + function _checkRole(bytes32 role) internal view virtual { + _checkRole(role, _msgSender()); + } + + /** + * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account` + * is missing `role`. + */ + function _checkRole(bytes32 role, address account) internal view virtual { + if (!hasRole(role, account)) { + revert AccessControlUnauthorizedAccount(account, role); + } + } + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) { + return _roles[role].adminRole; + } + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleGranted} event. + */ + function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { + _grantRole(role, account); + } + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + * + * May emit a {RoleRevoked} event. + */ + function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) { + _revokeRole(role, account); + } + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been revoked `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `callerConfirmation`. + * + * May emit a {RoleRevoked} event. + */ + function renounceRole(bytes32 role, address callerConfirmation) public virtual { + if (callerConfirmation != _msgSender()) { + revert AccessControlBadConfirmation(); + } + + _revokeRole(role, callerConfirmation); + } + + /** + * @dev Sets `adminRole` as ``role``'s admin role. + * + * Emits a {RoleAdminChanged} event. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual { + bytes32 previousAdminRole = getRoleAdmin(role); + _roles[role].adminRole = adminRole; + emit RoleAdminChanged(role, previousAdminRole, adminRole); + } + + /** + * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted. + * + * Internal function without access restriction. + * + * May emit a {RoleGranted} event. + */ + function _grantRole(bytes32 role, address account) internal virtual returns (bool) { + if (!hasRole(role, account)) { + _roles[role].hasRole[account] = true; + emit RoleGranted(role, account, _msgSender()); + return true; + } else { + return false; + } + } + + /** + * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked. + * + * Internal function without access restriction. + * + * May emit a {RoleRevoked} event. + */ + function _revokeRole(bytes32 role, address account) internal virtual returns (bool) { + if (hasRole(role, account)) { + _roles[role].hasRole[account] = false; + emit RoleRevoked(role, account, _msgSender()); + return true; + } else { + return false; + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol b/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol new file mode 100644 index 0000000..2ac89ca --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/IAccessControl.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol) + +pragma solidity ^0.8.20; + +/** + * @dev External interface of AccessControl declared to support ERC165 detection. + */ +interface IAccessControl { + /** + * @dev The `account` is missing a role. + */ + error AccessControlUnauthorizedAccount(address account, bytes32 neededRole); + + /** + * @dev The caller of a function is not the expected one. + * + * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}. + */ + error AccessControlBadConfirmation(); + + /** + * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole` + * + * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite + * {RoleAdminChanged} not being emitted signaling this. + */ + event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole); + + /** + * @dev Emitted when `account` is granted `role`. + * + * `sender` is the account that originated the contract call, an admin role + * bearer except when using {AccessControl-_setupRole}. + */ + event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Emitted when `account` is revoked `role`. + * + * `sender` is the account that originated the contract call: + * - if using `revokeRole`, it is the admin role bearer + * - if using `renounceRole`, it is the role bearer (i.e. `account`) + */ + event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender); + + /** + * @dev Returns `true` if `account` has been granted `role`. + */ + function hasRole(bytes32 role, address account) external view returns (bool); + + /** + * @dev Returns the admin role that controls `role`. See {grantRole} and + * {revokeRole}. + * + * To change a role's admin, use {AccessControl-_setRoleAdmin}. + */ + function getRoleAdmin(bytes32 role) external view returns (bytes32); + + /** + * @dev Grants `role` to `account`. + * + * If `account` had not been already granted `role`, emits a {RoleGranted} + * event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function grantRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from `account`. + * + * If `account` had been granted `role`, emits a {RoleRevoked} event. + * + * Requirements: + * + * - the caller must have ``role``'s admin role. + */ + function revokeRole(bytes32 role, address account) external; + + /** + * @dev Revokes `role` from the calling account. + * + * Roles are often managed via {grantRole} and {revokeRole}: this function's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * If the calling account had been granted `role`, emits a {RoleRevoked} + * event. + * + * Requirements: + * + * - the caller must be `callerConfirmation`. + */ + function renounceRole(bytes32 role, address callerConfirmation) external; +} diff --git a/lib/openzeppelin-contracts/contracts/access/Ownable.sol b/lib/openzeppelin-contracts/contracts/access/Ownable.sol new file mode 100644 index 0000000..bd96f66 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/Ownable.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +/** + * @dev Contract module which provides a basic access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is set to the address provided by the deployer. This can + * later be changed with {transferOwnership}. + * + * This module is used through inheritance. It will make available the modifier + * `onlyOwner`, which can be applied to your functions to restrict their use to + * the owner. + */ +abstract contract Ownable is Context { + address private _owner; + + /** + * @dev The caller account is not authorized to perform an operation. + */ + error OwnableUnauthorizedAccount(address account); + + /** + * @dev The owner is not a valid owner account. (eg. `address(0)`) + */ + error OwnableInvalidOwner(address owner); + + event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Initializes the contract setting the address provided by the deployer as the initial owner. + */ + constructor(address initialOwner) { + if (initialOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(initialOwner); + } + + /** + * @dev Throws if called by any account other than the owner. + */ + modifier onlyOwner() { + _checkOwner(); + _; + } + + /** + * @dev Returns the address of the current owner. + */ + function owner() public view virtual returns (address) { + return _owner; + } + + /** + * @dev Throws if the sender is not the owner. + */ + function _checkOwner() internal view virtual { + if (owner() != _msgSender()) { + revert OwnableUnauthorizedAccount(_msgSender()); + } + } + + /** + * @dev Leaves the contract without owner. It will not be possible to call + * `onlyOwner` functions. Can only be called by the current owner. + * + * NOTE: Renouncing ownership will leave the contract without an owner, + * thereby disabling any functionality that is only available to the owner. + */ + function renounceOwnership() public virtual onlyOwner { + _transferOwnership(address(0)); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual onlyOwner { + if (newOwner == address(0)) { + revert OwnableInvalidOwner(address(0)); + } + _transferOwnership(newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`). + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual { + address oldOwner = _owner; + _owner = newOwner; + emit OwnershipTransferred(oldOwner, newOwner); + } +} diff --git a/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol b/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol new file mode 100644 index 0000000..f0427e2 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/Ownable2Step.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) + +pragma solidity ^0.8.20; + +import {Ownable} from "./Ownable.sol"; + +/** + * @dev Contract module which provides access control mechanism, where + * there is an account (an owner) that can be granted exclusive access to + * specific functions. + * + * The initial owner is specified at deployment time in the constructor for `Ownable`. This + * can later be changed with {transferOwnership} and {acceptOwnership}. + * + * This module is used through inheritance. It will make available all functions + * from parent (Ownable). + */ +abstract contract Ownable2Step is Ownable { + address private _pendingOwner; + + event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); + + /** + * @dev Returns the address of the pending owner. + */ + function pendingOwner() public view virtual returns (address) { + return _pendingOwner; + } + + /** + * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. + * Can only be called by the current owner. + */ + function transferOwnership(address newOwner) public virtual override onlyOwner { + _pendingOwner = newOwner; + emit OwnershipTransferStarted(owner(), newOwner); + } + + /** + * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. + * Internal function without access restriction. + */ + function _transferOwnership(address newOwner) internal virtual override { + delete _pendingOwner; + super._transferOwnership(newOwner); + } + + /** + * @dev The new owner accepts the ownership transfer. + */ + function acceptOwnership() public virtual { + address sender = _msgSender(); + if (pendingOwner() != sender) { + revert OwnableUnauthorizedAccount(sender); + } + _transferOwnership(sender); + } +} diff --git a/lib/openzeppelin-contracts/contracts/access/README.adoc b/lib/openzeppelin-contracts/contracts/access/README.adoc new file mode 100644 index 0000000..ba9c02f --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/README.adoc @@ -0,0 +1,43 @@ += Access Control + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access + +This directory provides ways to restrict who can access the functions of a contract or when they can do it. + +- {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. +- {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. + +== Core + +{{Ownable}} + +{{Ownable2Step}} + +{{IAccessControl}} + +{{AccessControl}} + +== Extensions + +{{IAccessControlEnumerable}} + +{{AccessControlEnumerable}} + +{{IAccessControlDefaultAdminRules}} + +{{AccessControlDefaultAdminRules}} + +== AccessManager + +{{IAuthority}} + +{{IAccessManager}} + +{{AccessManager}} + +{{IAccessManaged}} + +{{AccessManaged}} + +{{AuthorityUtils}} diff --git a/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol b/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol new file mode 100644 index 0000000..ef71a64 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sol @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlDefaultAdminRules.sol) + +pragma solidity ^0.8.20; + +import {IAccessControlDefaultAdminRules} from "./IAccessControlDefaultAdminRules.sol"; +import {AccessControl, IAccessControl} from "../AccessControl.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {IERC5313} from "../../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. + * * 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: + * + * ```solidity + * contract MyToken is AccessControlDefaultAdminRules { + * constructor() AccessControlDefaultAdminRules( + * 3 days, + * msg.sender // Explicit initial `DEFAULT_ADMIN_ROLE` holder + * ) {} + * } + * ``` + */ +abstract contract AccessControlDefaultAdminRules is IAccessControlDefaultAdminRules, IERC5313, AccessControl { + // pending admin pair read/written together frequently + address private _pendingDefaultAdmin; + uint48 private _pendingDefaultAdminSchedule; // 0 == unset + + 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} and {defaultAdmin} address. + */ + constructor(uint48 initialDelay, address initialDefaultAdmin) { + if (initialDefaultAdmin == address(0)) { + revert AccessControlInvalidDefaultAdmin(address(0)); + } + _currentDelay = initialDelay; + _grantRole(DEFAULT_ADMIN_ROLE, initialDefaultAdmin); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlDefaultAdminRules).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC5313-owner}. + */ + function owner() public view virtual returns (address) { + return defaultAdmin(); + } + + /// + /// Override AccessControl role management + /// + + /** + * @dev See {AccessControl-grantRole}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function grantRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE) { + revert AccessControlEnforcedDefaultAdminRules(); + } + super.grantRole(role, account); + } + + /** + * @dev See {AccessControl-revokeRole}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function revokeRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE) { + revert AccessControlEnforcedDefaultAdminRules(); + } + super.revokeRole(role, account); + } + + /** + * @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 renounceRole(bytes32 role, address account) public virtual override(AccessControl, IAccessControl) { + if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { + (address newDefaultAdmin, uint48 schedule) = pendingDefaultAdmin(); + if (newDefaultAdmin != address(0) || !_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) { + revert AccessControlEnforcedDefaultAdminDelay(schedule); + } + delete _pendingDefaultAdminSchedule; + } + super.renounceRole(role, account); + } + + /** + * @dev See {AccessControl-_grantRole}. + * + * For `DEFAULT_ADMIN_ROLE`, it only allows granting if there isn't already a {defaultAdmin} or if the + * role has been previously renounced. + * + * 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 returns (bool) { + if (role == DEFAULT_ADMIN_ROLE) { + if (defaultAdmin() != address(0)) { + revert AccessControlEnforcedDefaultAdminRules(); + } + _currentDefaultAdmin = account; + } + return super._grantRole(role, account); + } + + /** + * @dev See {AccessControl-_revokeRole}. + */ + function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) { + if (role == DEFAULT_ADMIN_ROLE && account == defaultAdmin()) { + delete _currentDefaultAdmin; + } + return super._revokeRole(role, account); + } + + /** + * @dev See {AccessControl-_setRoleAdmin}. Reverts for `DEFAULT_ADMIN_ROLE`. + */ + function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual override { + if (role == DEFAULT_ADMIN_ROLE) { + revert AccessControlEnforcedDefaultAdminRules(); + } + super._setRoleAdmin(role, adminRole); + } + + /// + /// AccessControlDefaultAdminRules accessors + /// + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + function defaultAdmin() public view virtual returns (address) { + return _currentDefaultAdmin; + } + + /** + * @inheritdoc IAccessControlDefaultAdminRules + */ + 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(); + if (_msgSender() != newDefaultAdmin) { + // Enforce newDefaultAdmin explicit acceptance. + revert AccessControlInvalidDefaultAdmin(_msgSender()); + } + _acceptDefaultAdminTransfer(); + } + + /** + * @dev See {acceptDefaultAdminTransfer}. + * + * Internal function without access restriction. + */ + function _acceptDefaultAdminTransfer() internal virtual { + (address newAdmin, uint48 schedule) = pendingDefaultAdmin(); + if (!_isScheduleSet(schedule) || !_hasSchedulePassed(schedule)) { + revert AccessControlEnforcedDefaultAdminDelay(schedule); + } + _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/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol b/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol new file mode 100644 index 0000000..151de05 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/AccessControlEnumerable.sol) + +pragma solidity ^0.8.20; + +import {IAccessControlEnumerable} from "./IAccessControlEnumerable.sol"; +import {AccessControl} from "../AccessControl.sol"; +import {EnumerableSet} from "../../utils/structs/EnumerableSet.sol"; + +/** + * @dev Extension of {AccessControl} that allows enumerating the members of each role. + */ +abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl { + using EnumerableSet for EnumerableSet.AddressSet; + + mapping(bytes32 role => EnumerableSet.AddressSet) private _roleMembers; + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) public view virtual returns (address) { + return _roleMembers[role].at(index); + } + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) public view virtual returns (uint256) { + return _roleMembers[role].length(); + } + + /** + * @dev Overload {AccessControl-_grantRole} to track enumerable memberships + */ + function _grantRole(bytes32 role, address account) internal virtual override returns (bool) { + bool granted = super._grantRole(role, account); + if (granted) { + _roleMembers[role].add(account); + } + return granted; + } + + /** + * @dev Overload {AccessControl-_revokeRole} to track enumerable memberships + */ + function _revokeRole(bytes32 role, address account) internal virtual override returns (bool) { + bool revoked = super._revokeRole(role, account); + if (revoked) { + _roleMembers[role].remove(account); + } + return revoked; + } +} diff --git a/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol b/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol new file mode 100644 index 0000000..73531fa --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlDefaultAdminRules.sol) + +pragma solidity ^0.8.20; + +import {IAccessControl} from "../IAccessControl.sol"; + +/** + * @dev External interface of AccessControlDefaultAdminRules declared to support ERC165 detection. + */ +interface IAccessControlDefaultAdminRules is IAccessControl { + /** + * @dev The new default admin is not a valid default admin. + */ + error AccessControlInvalidDefaultAdmin(address defaultAdmin); + + /** + * @dev At least one of the following rules was violated: + * + * - The `DEFAULT_ADMIN_ROLE` must only be managed by itself. + * - The `DEFAULT_ADMIN_ROLE` must only be held by one account at the time. + * - Any `DEFAULT_ADMIN_ROLE` transfer must be in two delayed steps. + */ + error AccessControlEnforcedDefaultAdminRules(); + + /** + * @dev The delay for transferring the default admin delay is enforced and + * the operation must wait until `schedule`. + * + * NOTE: `schedule` can be 0 indicating there's no transfer scheduled. + */ + error AccessControlEnforcedDefaultAdminDelay(uint48 schedule); + + /** + * @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 DefaultAdminTransferScheduled(address indexed newAdmin, uint48 acceptSchedule); + + /** + * @dev Emitted when a {pendingDefaultAdmin} is reset if it was never accepted, regardless of its schedule. + */ + 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. + */ + function defaultAdmin() external view returns (address); + + /** + * @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 newAdmin, uint48 acceptSchedule); + + /** + * @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 defaultAdminDelay() external view returns (uint48); + + /** + * @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 {defaultAdmin}. + * + * Emits a DefaultAdminRoleChangeStarted event. + */ + function beginDefaultAdminTransfer(address newAdmin) external; + + /** + * @dev Cancels a {defaultAdmin} transfer previously started with {beginDefaultAdminTransfer}. + * + * A {pendingDefaultAdmin} not yet accepted can also be cancelled with this function. + * + * Requirements: + * + * - 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 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: + * + * - Only can be called by the current {defaultAdmin}. + * + * Emits a DefaultAdminDelayChangeScheduled event and may emit a DefaultAdminDelayChangeCanceled event. + */ + 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/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol b/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol new file mode 100644 index 0000000..a39d051 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/extensions/IAccessControlEnumerable.sol) + +pragma solidity ^0.8.20; + +import {IAccessControl} from "../IAccessControl.sol"; + +/** + * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. + */ +interface IAccessControlEnumerable is IAccessControl { + /** + * @dev Returns one of the accounts that have `role`. `index` must be a + * value between 0 and {getRoleMemberCount}, non-inclusive. + * + * Role bearers are not sorted in any particular way, and their ordering may + * change at any point. + * + * WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure + * you perform all queries on the same block. See the following + * https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post] + * for more information. + */ + function getRoleMember(bytes32 role, uint256 index) external view returns (address); + + /** + * @dev Returns the number of accounts that have `role`. Can be used + * together with {getRoleMember} to enumerate all bearers of a role. + */ + function getRoleMemberCount(bytes32 role) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol b/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol new file mode 100644 index 0000000..b5f4524 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManaged.sol) + +pragma solidity ^0.8.20; + +import {IAuthority} from "./IAuthority.sol"; +import {AuthorityUtils} from "./AuthorityUtils.sol"; +import {IAccessManager} from "./IAccessManager.sol"; +import {IAccessManaged} from "./IAccessManaged.sol"; +import {Context} from "../../utils/Context.sol"; + +/** + * @dev This contract module makes available a {restricted} modifier. Functions decorated with this modifier will be + * permissioned according to an "authority": a contract like {AccessManager} that follows the {IAuthority} interface, + * implementing a policy that allows certain callers to access certain functions. + * + * IMPORTANT: The `restricted` modifier should never be used on `internal` functions, judiciously used in `public` + * functions, and ideally only used in `external` functions. See {restricted}. + */ +abstract contract AccessManaged is Context, IAccessManaged { + address private _authority; + + bool private _consumingSchedule; + + /** + * @dev Initializes the contract connected to an initial authority. + */ + constructor(address initialAuthority) { + _setAuthority(initialAuthority); + } + + /** + * @dev Restricts access to a function as defined by the connected Authority for this contract and the + * caller and selector of the function that entered the contract. + * + * [IMPORTANT] + * ==== + * In general, this modifier should only be used on `external` functions. It is okay to use it on `public` + * functions that are used as external entry points and are not called internally. Unless you know what you're + * doing, it should never be used on `internal` functions. Failure to follow these rules can have critical security + * implications! This is because the permissions are determined by the function that entered the contract, i.e. the + * function at the bottom of the call stack, and not the function where the modifier is visible in the source code. + * ==== + * + * [WARNING] + * ==== + * Avoid adding this modifier to the https://docs.soliditylang.org/en/v0.8.20/contracts.html#receive-ether-function[`receive()`] + * function or the https://docs.soliditylang.org/en/v0.8.20/contracts.html#fallback-function[`fallback()`]. These + * functions are the only execution paths where a function selector cannot be unambiguosly determined from the calldata + * since the selector defaults to `0x00000000` in the `receive()` function and similarly in the `fallback()` function + * if no calldata is provided. (See {_checkCanCall}). + * + * The `receive()` function will always panic whereas the `fallback()` may panic depending on the calldata length. + * ==== + */ + modifier restricted() { + _checkCanCall(_msgSender(), _msgData()); + _; + } + + /// @inheritdoc IAccessManaged + function authority() public view virtual returns (address) { + return _authority; + } + + /// @inheritdoc IAccessManaged + function setAuthority(address newAuthority) public virtual { + address caller = _msgSender(); + if (caller != authority()) { + revert AccessManagedUnauthorized(caller); + } + if (newAuthority.code.length == 0) { + revert AccessManagedInvalidAuthority(newAuthority); + } + _setAuthority(newAuthority); + } + + /// @inheritdoc IAccessManaged + function isConsumingScheduledOp() public view returns (bytes4) { + return _consumingSchedule ? this.isConsumingScheduledOp.selector : bytes4(0); + } + + /** + * @dev Transfers control to a new authority. Internal function with no access restriction. Allows bypassing the + * permissions set by the current authority. + */ + function _setAuthority(address newAuthority) internal virtual { + _authority = newAuthority; + emit AuthorityUpdated(newAuthority); + } + + /** + * @dev Reverts if the caller is not allowed to call the function identified by a selector. Panics if the calldata + * is less than 4 bytes long. + */ + function _checkCanCall(address caller, bytes calldata data) internal virtual { + (bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay( + authority(), + caller, + address(this), + bytes4(data[0:4]) + ); + if (!immediate) { + if (delay > 0) { + _consumingSchedule = true; + IAccessManager(authority()).consumeScheduledOp(caller, data); + _consumingSchedule = false; + } else { + revert AccessManagedUnauthorized(caller); + } + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol b/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol new file mode 100644 index 0000000..1e4afa4 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/manager/AccessManager.sol @@ -0,0 +1,730 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AccessManager.sol) + +pragma solidity ^0.8.20; + +import {IAccessManager} from "./IAccessManager.sol"; +import {IAccessManaged} from "./IAccessManaged.sol"; +import {Address} from "../../utils/Address.sol"; +import {Context} from "../../utils/Context.sol"; +import {Multicall} from "../../utils/Multicall.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {Time} from "../../utils/types/Time.sol"; + +/** + * @dev AccessManager is a central contract to store the permissions of a system. + * + * A smart contract under the control of an AccessManager instance is known as a target, and will inherit from the + * {AccessManaged} contract, be connected to this contract as its manager and implement the {AccessManaged-restricted} + * modifier on a set of functions selected to be permissioned. Note that any function without this setup won't be + * effectively restricted. + * + * The restriction rules for such functions are defined in terms of "roles" identified by an `uint64` and scoped + * by target (`address`) and function selectors (`bytes4`). These roles are stored in this contract and can be + * configured by admins (`ADMIN_ROLE` members) after a delay (see {getTargetAdminDelay}). + * + * For each target contract, admins can configure the following without any delay: + * + * * The target's {AccessManaged-authority} via {updateAuthority}. + * * Close or open a target via {setTargetClosed} keeping the permissions intact. + * * The roles that are allowed (or disallowed) to call a given function (identified by its selector) through {setTargetFunctionRole}. + * + * By default every address is member of the `PUBLIC_ROLE` and every target function is restricted to the `ADMIN_ROLE` until configured otherwise. + * Additionally, each role has the following configuration options restricted to this manager's admins: + * + * * A role's admin role via {setRoleAdmin} who can grant or revoke roles. + * * A role's guardian role via {setRoleGuardian} who's allowed to cancel operations. + * * A delay in which a role takes effect after being granted through {setGrantDelay}. + * * A delay of any target's admin action via {setTargetAdminDelay}. + * * A role label for discoverability purposes with {labelRole}. + * + * Any account can be added and removed into any number of these roles by using the {grantRole} and {revokeRole} functions + * restricted to each role's admin (see {getRoleAdmin}). + * + * Since all the permissions of the managed system can be modified by the admins of this instance, it is expected that + * they will be highly secured (e.g., a multisig or a well-configured DAO). + * + * NOTE: This contract implements a form of the {IAuthority} interface, but {canCall} has additional return data so it + * doesn't inherit `IAuthority`. It is however compatible with the `IAuthority` interface since the first 32 bytes of + * the return data are a boolean as expected by that interface. + * + * NOTE: Systems that implement other access control mechanisms (for example using {Ownable}) can be paired with an + * {AccessManager} by transferring permissions (ownership in the case of {Ownable}) directly to the {AccessManager}. + * Users will be able to interact with these contracts through the {execute} function, following the access rules + * registered in the {AccessManager}. Keep in mind that in that context, the msg.sender seen by restricted functions + * will be {AccessManager} itself. + * + * WARNING: When granting permissions over an {Ownable} or {AccessControl} contract to an {AccessManager}, be very + * mindful of the danger associated with functions such as {{Ownable-renounceOwnership}} or + * {{AccessControl-renounceRole}}. + */ +contract AccessManager is Context, Multicall, IAccessManager { + using Time for *; + + // Structure that stores the details for a target contract. + struct TargetConfig { + mapping(bytes4 selector => uint64 roleId) allowedRoles; + Time.Delay adminDelay; + bool closed; + } + + // Structure that stores the details for a role/account pair. This structures fit into a single slot. + struct Access { + // Timepoint at which the user gets the permission. + // If this is either 0 or in the future, then the role permission is not available. + uint48 since; + // Delay for execution. Only applies to restricted() / execute() calls. + Time.Delay delay; + } + + // Structure that stores the details of a role. + struct Role { + // Members of the role. + mapping(address user => Access access) members; + // Admin who can grant or revoke permissions. + uint64 admin; + // Guardian who can cancel operations targeting functions that need this role. + uint64 guardian; + // Delay in which the role takes effect after being granted. + Time.Delay grantDelay; + } + + // Structure that stores the details for a scheduled operation. This structure fits into a single slot. + struct Schedule { + // Moment at which the operation can be executed. + uint48 timepoint; + // Operation nonce to allow third-party contracts to identify the operation. + uint32 nonce; + } + + uint64 public constant ADMIN_ROLE = type(uint64).min; // 0 + uint64 public constant PUBLIC_ROLE = type(uint64).max; // 2**64-1 + + mapping(address target => TargetConfig mode) private _targets; + mapping(uint64 roleId => Role) private _roles; + mapping(bytes32 operationId => Schedule) private _schedules; + + // Used to identify operations that are currently being executed via {execute}. + // This should be transient storage when supported by the EVM. + bytes32 private _executionId; + + /** + * @dev Check that the caller is authorized to perform the operation, following the restrictions encoded in + * {_getAdminRestrictions}. + */ + modifier onlyAuthorized() { + _checkAuthorized(); + _; + } + + constructor(address initialAdmin) { + if (initialAdmin == address(0)) { + revert AccessManagerInvalidInitialAdmin(address(0)); + } + + // admin is active immediately and without any execution delay. + _grantRole(ADMIN_ROLE, initialAdmin, 0, 0); + } + + // =================================================== GETTERS ==================================================== + /// @inheritdoc IAccessManager + function canCall( + address caller, + address target, + bytes4 selector + ) public view virtual returns (bool immediate, uint32 delay) { + if (isTargetClosed(target)) { + return (false, 0); + } else if (caller == address(this)) { + // Caller is AccessManager, this means the call was sent through {execute} and it already checked + // permissions. We verify that the call "identifier", which is set during {execute}, is correct. + return (_isExecuting(target, selector), 0); + } else { + uint64 roleId = getTargetFunctionRole(target, selector); + (bool isMember, uint32 currentDelay) = hasRole(roleId, caller); + return isMember ? (currentDelay == 0, currentDelay) : (false, 0); + } + } + + /// @inheritdoc IAccessManager + function expiration() public view virtual returns (uint32) { + return 1 weeks; + } + + /// @inheritdoc IAccessManager + function minSetback() public view virtual returns (uint32) { + return 5 days; + } + + /// @inheritdoc IAccessManager + function isTargetClosed(address target) public view virtual returns (bool) { + return _targets[target].closed; + } + + /// @inheritdoc IAccessManager + function getTargetFunctionRole(address target, bytes4 selector) public view virtual returns (uint64) { + return _targets[target].allowedRoles[selector]; + } + + /// @inheritdoc IAccessManager + function getTargetAdminDelay(address target) public view virtual returns (uint32) { + return _targets[target].adminDelay.get(); + } + + /// @inheritdoc IAccessManager + function getRoleAdmin(uint64 roleId) public view virtual returns (uint64) { + return _roles[roleId].admin; + } + + /// @inheritdoc IAccessManager + function getRoleGuardian(uint64 roleId) public view virtual returns (uint64) { + return _roles[roleId].guardian; + } + + /// @inheritdoc IAccessManager + function getRoleGrantDelay(uint64 roleId) public view virtual returns (uint32) { + return _roles[roleId].grantDelay.get(); + } + + /// @inheritdoc IAccessManager + function getAccess( + uint64 roleId, + address account + ) public view virtual returns (uint48 since, uint32 currentDelay, uint32 pendingDelay, uint48 effect) { + Access storage access = _roles[roleId].members[account]; + + since = access.since; + (currentDelay, pendingDelay, effect) = access.delay.getFull(); + + return (since, currentDelay, pendingDelay, effect); + } + + /// @inheritdoc IAccessManager + function hasRole( + uint64 roleId, + address account + ) public view virtual returns (bool isMember, uint32 executionDelay) { + if (roleId == PUBLIC_ROLE) { + return (true, 0); + } else { + (uint48 hasRoleSince, uint32 currentDelay, , ) = getAccess(roleId, account); + return (hasRoleSince != 0 && hasRoleSince <= Time.timestamp(), currentDelay); + } + } + + // =============================================== ROLE MANAGEMENT =============================================== + /// @inheritdoc IAccessManager + function labelRole(uint64 roleId, string calldata label) public virtual onlyAuthorized { + if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + emit RoleLabel(roleId, label); + } + + /// @inheritdoc IAccessManager + function grantRole(uint64 roleId, address account, uint32 executionDelay) public virtual onlyAuthorized { + _grantRole(roleId, account, getRoleGrantDelay(roleId), executionDelay); + } + + /// @inheritdoc IAccessManager + function revokeRole(uint64 roleId, address account) public virtual onlyAuthorized { + _revokeRole(roleId, account); + } + + /// @inheritdoc IAccessManager + function renounceRole(uint64 roleId, address callerConfirmation) public virtual { + if (callerConfirmation != _msgSender()) { + revert AccessManagerBadConfirmation(); + } + _revokeRole(roleId, callerConfirmation); + } + + /// @inheritdoc IAccessManager + function setRoleAdmin(uint64 roleId, uint64 admin) public virtual onlyAuthorized { + _setRoleAdmin(roleId, admin); + } + + /// @inheritdoc IAccessManager + function setRoleGuardian(uint64 roleId, uint64 guardian) public virtual onlyAuthorized { + _setRoleGuardian(roleId, guardian); + } + + /// @inheritdoc IAccessManager + function setGrantDelay(uint64 roleId, uint32 newDelay) public virtual onlyAuthorized { + _setGrantDelay(roleId, newDelay); + } + + /** + * @dev Internal version of {grantRole} without access control. Returns true if the role was newly granted. + * + * Emits a {RoleGranted} event. + */ + function _grantRole( + uint64 roleId, + address account, + uint32 grantDelay, + uint32 executionDelay + ) internal virtual returns (bool) { + if (roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + bool newMember = _roles[roleId].members[account].since == 0; + uint48 since; + + if (newMember) { + since = Time.timestamp() + grantDelay; + _roles[roleId].members[account] = Access({since: since, delay: executionDelay.toDelay()}); + } else { + // No setback here. Value can be reset by doing revoke + grant, effectively allowing the admin to perform + // any change to the execution delay within the duration of the role admin delay. + (_roles[roleId].members[account].delay, since) = _roles[roleId].members[account].delay.withUpdate( + executionDelay, + 0 + ); + } + + emit RoleGranted(roleId, account, executionDelay, since, newMember); + return newMember; + } + + /** + * @dev Internal version of {revokeRole} without access control. This logic is also used by {renounceRole}. + * Returns true if the role was previously granted. + * + * Emits a {RoleRevoked} event if the account had the role. + */ + function _revokeRole(uint64 roleId, address account) internal virtual returns (bool) { + if (roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + if (_roles[roleId].members[account].since == 0) { + return false; + } + + delete _roles[roleId].members[account]; + + emit RoleRevoked(roleId, account); + return true; + } + + /** + * @dev Internal version of {setRoleAdmin} without access control. + * + * Emits a {RoleAdminChanged} event. + * + * NOTE: Setting the admin role as the `PUBLIC_ROLE` is allowed, but it will effectively allow + * anyone to set grant or revoke such role. + */ + function _setRoleAdmin(uint64 roleId, uint64 admin) internal virtual { + if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + _roles[roleId].admin = admin; + + emit RoleAdminChanged(roleId, admin); + } + + /** + * @dev Internal version of {setRoleGuardian} without access control. + * + * Emits a {RoleGuardianChanged} event. + * + * NOTE: Setting the guardian role as the `PUBLIC_ROLE` is allowed, but it will effectively allow + * anyone to cancel any scheduled operation for such role. + */ + function _setRoleGuardian(uint64 roleId, uint64 guardian) internal virtual { + if (roleId == ADMIN_ROLE || roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + _roles[roleId].guardian = guardian; + + emit RoleGuardianChanged(roleId, guardian); + } + + /** + * @dev Internal version of {setGrantDelay} without access control. + * + * Emits a {RoleGrantDelayChanged} event. + */ + function _setGrantDelay(uint64 roleId, uint32 newDelay) internal virtual { + if (roleId == PUBLIC_ROLE) { + revert AccessManagerLockedRole(roleId); + } + + uint48 effect; + (_roles[roleId].grantDelay, effect) = _roles[roleId].grantDelay.withUpdate(newDelay, minSetback()); + + emit RoleGrantDelayChanged(roleId, newDelay, effect); + } + + // ============================================= FUNCTION MANAGEMENT ============================================== + /// @inheritdoc IAccessManager + function setTargetFunctionRole( + address target, + bytes4[] calldata selectors, + uint64 roleId + ) public virtual onlyAuthorized { + for (uint256 i = 0; i < selectors.length; ++i) { + _setTargetFunctionRole(target, selectors[i], roleId); + } + } + + /** + * @dev Internal version of {setTargetFunctionRole} without access control. + * + * Emits a {TargetFunctionRoleUpdated} event. + */ + function _setTargetFunctionRole(address target, bytes4 selector, uint64 roleId) internal virtual { + _targets[target].allowedRoles[selector] = roleId; + emit TargetFunctionRoleUpdated(target, selector, roleId); + } + + /// @inheritdoc IAccessManager + function setTargetAdminDelay(address target, uint32 newDelay) public virtual onlyAuthorized { + _setTargetAdminDelay(target, newDelay); + } + + /** + * @dev Internal version of {setTargetAdminDelay} without access control. + * + * Emits a {TargetAdminDelayUpdated} event. + */ + function _setTargetAdminDelay(address target, uint32 newDelay) internal virtual { + uint48 effect; + (_targets[target].adminDelay, effect) = _targets[target].adminDelay.withUpdate(newDelay, minSetback()); + + emit TargetAdminDelayUpdated(target, newDelay, effect); + } + + // =============================================== MODE MANAGEMENT ================================================ + /// @inheritdoc IAccessManager + function setTargetClosed(address target, bool closed) public virtual onlyAuthorized { + _setTargetClosed(target, closed); + } + + /** + * @dev Set the closed flag for a contract. This is an internal setter with no access restrictions. + * + * Emits a {TargetClosed} event. + */ + function _setTargetClosed(address target, bool closed) internal virtual { + if (target == address(this)) { + revert AccessManagerLockedAccount(target); + } + _targets[target].closed = closed; + emit TargetClosed(target, closed); + } + + // ============================================== DELAYED OPERATIONS ============================================== + /// @inheritdoc IAccessManager + function getSchedule(bytes32 id) public view virtual returns (uint48) { + uint48 timepoint = _schedules[id].timepoint; + return _isExpired(timepoint) ? 0 : timepoint; + } + + /// @inheritdoc IAccessManager + function getNonce(bytes32 id) public view virtual returns (uint32) { + return _schedules[id].nonce; + } + + /// @inheritdoc IAccessManager + function schedule( + address target, + bytes calldata data, + uint48 when + ) public virtual returns (bytes32 operationId, uint32 nonce) { + address caller = _msgSender(); + + // Fetch restrictions that apply to the caller on the targeted function + (, uint32 setback) = _canCallExtended(caller, target, data); + + uint48 minWhen = Time.timestamp() + setback; + + // if call with delay is not authorized, or if requested timing is too soon + if (setback == 0 || (when > 0 && when < minWhen)) { + revert AccessManagerUnauthorizedCall(caller, target, _checkSelector(data)); + } + + // Reuse variable due to stack too deep + when = uint48(Math.max(when, minWhen)); // cast is safe: both inputs are uint48 + + // If caller is authorised, schedule operation + operationId = hashOperation(caller, target, data); + + _checkNotScheduled(operationId); + + unchecked { + // It's not feasible to overflow the nonce in less than 1000 years + nonce = _schedules[operationId].nonce + 1; + } + _schedules[operationId].timepoint = when; + _schedules[operationId].nonce = nonce; + emit OperationScheduled(operationId, nonce, when, caller, target, data); + + // Using named return values because otherwise we get stack too deep + } + + /** + * @dev Reverts if the operation is currently scheduled and has not expired. + * (Note: This function was introduced due to stack too deep errors in schedule.) + */ + function _checkNotScheduled(bytes32 operationId) private view { + uint48 prevTimepoint = _schedules[operationId].timepoint; + if (prevTimepoint != 0 && !_isExpired(prevTimepoint)) { + revert AccessManagerAlreadyScheduled(operationId); + } + } + + /// @inheritdoc IAccessManager + // Reentrancy is not an issue because permissions are checked on msg.sender. Additionally, + // _consumeScheduledOp guarantees a scheduled operation is only executed once. + // slither-disable-next-line reentrancy-no-eth + function execute(address target, bytes calldata data) public payable virtual returns (uint32) { + address caller = _msgSender(); + + // Fetch restrictions that apply to the caller on the targeted function + (bool immediate, uint32 setback) = _canCallExtended(caller, target, data); + + // If caller is not authorised, revert + if (!immediate && setback == 0) { + revert AccessManagerUnauthorizedCall(caller, target, _checkSelector(data)); + } + + bytes32 operationId = hashOperation(caller, target, data); + uint32 nonce; + + // If caller is authorised, check operation was scheduled early enough + // Consume an available schedule even if there is no currently enforced delay + if (setback != 0 || getSchedule(operationId) != 0) { + nonce = _consumeScheduledOp(operationId); + } + + // Mark the target and selector as authorised + bytes32 executionIdBefore = _executionId; + _executionId = _hashExecutionId(target, _checkSelector(data)); + + // Perform call + Address.functionCallWithValue(target, data, msg.value); + + // Reset execute identifier + _executionId = executionIdBefore; + + return nonce; + } + + /// @inheritdoc IAccessManager + function cancel(address caller, address target, bytes calldata data) public virtual returns (uint32) { + address msgsender = _msgSender(); + bytes4 selector = _checkSelector(data); + + bytes32 operationId = hashOperation(caller, target, data); + if (_schedules[operationId].timepoint == 0) { + revert AccessManagerNotScheduled(operationId); + } else if (caller != msgsender) { + // calls can only be canceled by the account that scheduled them, a global admin, or by a guardian of the required role. + (bool isAdmin, ) = hasRole(ADMIN_ROLE, msgsender); + (bool isGuardian, ) = hasRole(getRoleGuardian(getTargetFunctionRole(target, selector)), msgsender); + if (!isAdmin && !isGuardian) { + revert AccessManagerUnauthorizedCancel(msgsender, caller, target, selector); + } + } + + delete _schedules[operationId].timepoint; // reset the timepoint, keep the nonce + uint32 nonce = _schedules[operationId].nonce; + emit OperationCanceled(operationId, nonce); + + return nonce; + } + + /// @inheritdoc IAccessManager + function consumeScheduledOp(address caller, bytes calldata data) public virtual { + address target = _msgSender(); + if (IAccessManaged(target).isConsumingScheduledOp() != IAccessManaged.isConsumingScheduledOp.selector) { + revert AccessManagerUnauthorizedConsume(target); + } + _consumeScheduledOp(hashOperation(caller, target, data)); + } + + /** + * @dev Internal variant of {consumeScheduledOp} that operates on bytes32 operationId. + * + * Returns the nonce of the scheduled operation that is consumed. + */ + function _consumeScheduledOp(bytes32 operationId) internal virtual returns (uint32) { + uint48 timepoint = _schedules[operationId].timepoint; + uint32 nonce = _schedules[operationId].nonce; + + if (timepoint == 0) { + revert AccessManagerNotScheduled(operationId); + } else if (timepoint > Time.timestamp()) { + revert AccessManagerNotReady(operationId); + } else if (_isExpired(timepoint)) { + revert AccessManagerExpired(operationId); + } + + delete _schedules[operationId].timepoint; // reset the timepoint, keep the nonce + emit OperationExecuted(operationId, nonce); + + return nonce; + } + + /// @inheritdoc IAccessManager + function hashOperation(address caller, address target, bytes calldata data) public view virtual returns (bytes32) { + return keccak256(abi.encode(caller, target, data)); + } + + // ==================================================== OTHERS ==================================================== + /// @inheritdoc IAccessManager + function updateAuthority(address target, address newAuthority) public virtual onlyAuthorized { + IAccessManaged(target).setAuthority(newAuthority); + } + + // ================================================= ADMIN LOGIC ================================================== + /** + * @dev Check if the current call is authorized according to admin logic. + */ + function _checkAuthorized() private { + address caller = _msgSender(); + (bool immediate, uint32 delay) = _canCallSelf(caller, _msgData()); + if (!immediate) { + if (delay == 0) { + (, uint64 requiredRole, ) = _getAdminRestrictions(_msgData()); + revert AccessManagerUnauthorizedAccount(caller, requiredRole); + } else { + _consumeScheduledOp(hashOperation(caller, address(this), _msgData())); + } + } + } + + /** + * @dev Get the admin restrictions of a given function call based on the function and arguments involved. + * + * Returns: + * - bool restricted: does this data match a restricted operation + * - uint64: which role is this operation restricted to + * - uint32: minimum delay to enforce for that operation (max between operation's delay and admin's execution delay) + */ + function _getAdminRestrictions( + bytes calldata data + ) private view returns (bool restricted, uint64 roleAdminId, uint32 executionDelay) { + if (data.length < 4) { + return (false, 0, 0); + } + + bytes4 selector = _checkSelector(data); + + // Restricted to ADMIN with no delay beside any execution delay the caller may have + if ( + selector == this.labelRole.selector || + selector == this.setRoleAdmin.selector || + selector == this.setRoleGuardian.selector || + selector == this.setGrantDelay.selector || + selector == this.setTargetAdminDelay.selector + ) { + return (true, ADMIN_ROLE, 0); + } + + // Restricted to ADMIN with the admin delay corresponding to the target + if ( + selector == this.updateAuthority.selector || + selector == this.setTargetClosed.selector || + selector == this.setTargetFunctionRole.selector + ) { + // First argument is a target. + address target = abi.decode(data[0x04:0x24], (address)); + uint32 delay = getTargetAdminDelay(target); + return (true, ADMIN_ROLE, delay); + } + + // Restricted to that role's admin with no delay beside any execution delay the caller may have. + if (selector == this.grantRole.selector || selector == this.revokeRole.selector) { + // First argument is a roleId. + uint64 roleId = abi.decode(data[0x04:0x24], (uint64)); + return (true, getRoleAdmin(roleId), 0); + } + + return (false, 0, 0); + } + + // =================================================== HELPERS ==================================================== + /** + * @dev An extended version of {canCall} for internal usage that checks {_canCallSelf} + * when the target is this contract. + * + * Returns: + * - bool immediate: whether the operation can be executed immediately (with no delay) + * - uint32 delay: the execution delay + */ + function _canCallExtended( + address caller, + address target, + bytes calldata data + ) private view returns (bool immediate, uint32 delay) { + if (target == address(this)) { + return _canCallSelf(caller, data); + } else { + return data.length < 4 ? (false, 0) : canCall(caller, target, _checkSelector(data)); + } + } + + /** + * @dev A version of {canCall} that checks for admin restrictions in this contract. + */ + function _canCallSelf(address caller, bytes calldata data) private view returns (bool immediate, uint32 delay) { + if (data.length < 4) { + return (false, 0); + } + + if (caller == address(this)) { + // Caller is AccessManager, this means the call was sent through {execute} and it already checked + // permissions. We verify that the call "identifier", which is set during {execute}, is correct. + return (_isExecuting(address(this), _checkSelector(data)), 0); + } + + (bool enabled, uint64 roleId, uint32 operationDelay) = _getAdminRestrictions(data); + if (!enabled) { + return (false, 0); + } + + (bool inRole, uint32 executionDelay) = hasRole(roleId, caller); + if (!inRole) { + return (false, 0); + } + + // downcast is safe because both options are uint32 + delay = uint32(Math.max(operationDelay, executionDelay)); + return (delay == 0, delay); + } + + /** + * @dev Returns true if a call with `target` and `selector` is being executed via {executed}. + */ + function _isExecuting(address target, bytes4 selector) private view returns (bool) { + return _executionId == _hashExecutionId(target, selector); + } + + /** + * @dev Returns true if a schedule timepoint is past its expiration deadline. + */ + function _isExpired(uint48 timepoint) private view returns (bool) { + return timepoint + expiration() <= Time.timestamp(); + } + + /** + * @dev Extracts the selector from calldata. Panics if data is not at least 4 bytes + */ + function _checkSelector(bytes calldata data) private pure returns (bytes4) { + return bytes4(data[0:4]); + } + + /** + * @dev Hashing function for execute protection + */ + function _hashExecutionId(address target, bytes4 selector) private pure returns (bytes32) { + return keccak256(abi.encode(target, selector)); + } +} diff --git a/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol b/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol new file mode 100644 index 0000000..fb3018c --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/AuthorityUtils.sol) + +pragma solidity ^0.8.20; + +import {IAuthority} from "./IAuthority.sol"; + +library AuthorityUtils { + /** + * @dev Since `AccessManager` implements an extended IAuthority interface, invoking `canCall` with backwards compatibility + * for the preexisting `IAuthority` interface requires special care to avoid reverting on insufficient return data. + * This helper function takes care of invoking `canCall` in a backwards compatible way without reverting. + */ + function canCallWithDelay( + address authority, + address caller, + address target, + bytes4 selector + ) internal view returns (bool immediate, uint32 delay) { + (bool success, bytes memory data) = authority.staticcall( + abi.encodeCall(IAuthority.canCall, (caller, target, selector)) + ); + if (success) { + if (data.length >= 0x40) { + (immediate, delay) = abi.decode(data, (bool, uint32)); + } else if (data.length >= 0x20) { + immediate = abi.decode(data, (bool)); + } + } + return (immediate, delay); + } +} diff --git a/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol b/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol new file mode 100644 index 0000000..95206bd --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManaged.sol) + +pragma solidity ^0.8.20; + +interface IAccessManaged { + /** + * @dev Authority that manages this contract was updated. + */ + event AuthorityUpdated(address authority); + + error AccessManagedUnauthorized(address caller); + error AccessManagedRequiredDelay(address caller, uint32 delay); + error AccessManagedInvalidAuthority(address authority); + + /** + * @dev Returns the current authority. + */ + function authority() external view returns (address); + + /** + * @dev Transfers control to a new authority. The caller must be the current authority. + */ + function setAuthority(address) external; + + /** + * @dev Returns true only in the context of a delayed restricted call, at the moment that the scheduled operation is + * being consumed. Prevents denial of service for delayed restricted calls in the case that the contract performs + * attacker controlled calls. + */ + function isConsumingScheduledOp() external view returns (bytes4); +} diff --git a/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol b/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol new file mode 100644 index 0000000..3a6dc73 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sol @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAccessManager.sol) + +pragma solidity ^0.8.20; + +import {IAccessManaged} from "./IAccessManaged.sol"; +import {Time} from "../../utils/types/Time.sol"; + +interface IAccessManager { + /** + * @dev A delayed operation was scheduled. + */ + event OperationScheduled( + bytes32 indexed operationId, + uint32 indexed nonce, + uint48 schedule, + address caller, + address target, + bytes data + ); + + /** + * @dev A scheduled operation was executed. + */ + event OperationExecuted(bytes32 indexed operationId, uint32 indexed nonce); + + /** + * @dev A scheduled operation was canceled. + */ + event OperationCanceled(bytes32 indexed operationId, uint32 indexed nonce); + + /** + * @dev Informational labelling for a roleId. + */ + event RoleLabel(uint64 indexed roleId, string label); + + /** + * @dev Emitted when `account` is granted `roleId`. + * + * NOTE: The meaning of the `since` argument depends on the `newMember` argument. + * If the role is granted to a new member, the `since` argument indicates when the account becomes a member of the role, + * otherwise it indicates the execution delay for this account and roleId is updated. + */ + event RoleGranted(uint64 indexed roleId, address indexed account, uint32 delay, uint48 since, bool newMember); + + /** + * @dev Emitted when `account` membership or `roleId` is revoked. Unlike granting, revoking is instantaneous. + */ + event RoleRevoked(uint64 indexed roleId, address indexed account); + + /** + * @dev Role acting as admin over a given `roleId` is updated. + */ + event RoleAdminChanged(uint64 indexed roleId, uint64 indexed admin); + + /** + * @dev Role acting as guardian over a given `roleId` is updated. + */ + event RoleGuardianChanged(uint64 indexed roleId, uint64 indexed guardian); + + /** + * @dev Grant delay for a given `roleId` will be updated to `delay` when `since` is reached. + */ + event RoleGrantDelayChanged(uint64 indexed roleId, uint32 delay, uint48 since); + + /** + * @dev Target mode is updated (true = closed, false = open). + */ + event TargetClosed(address indexed target, bool closed); + + /** + * @dev Role required to invoke `selector` on `target` is updated to `roleId`. + */ + event TargetFunctionRoleUpdated(address indexed target, bytes4 selector, uint64 indexed roleId); + + /** + * @dev Admin delay for a given `target` will be updated to `delay` when `since` is reached. + */ + event TargetAdminDelayUpdated(address indexed target, uint32 delay, uint48 since); + + error AccessManagerAlreadyScheduled(bytes32 operationId); + error AccessManagerNotScheduled(bytes32 operationId); + error AccessManagerNotReady(bytes32 operationId); + error AccessManagerExpired(bytes32 operationId); + error AccessManagerLockedAccount(address account); + error AccessManagerLockedRole(uint64 roleId); + error AccessManagerBadConfirmation(); + error AccessManagerUnauthorizedAccount(address msgsender, uint64 roleId); + error AccessManagerUnauthorizedCall(address caller, address target, bytes4 selector); + error AccessManagerUnauthorizedConsume(address target); + error AccessManagerUnauthorizedCancel(address msgsender, address caller, address target, bytes4 selector); + error AccessManagerInvalidInitialAdmin(address initialAdmin); + + /** + * @dev Check if an address (`caller`) is authorised to call a given function on a given contract directly (with + * no restriction). Additionally, it returns the delay needed to perform the call indirectly through the {schedule} + * & {execute} workflow. + * + * This function is usually called by the targeted contract to control immediate execution of restricted functions. + * Therefore we only return true if the call can be performed without any delay. If the call is subject to a + * previously set delay (not zero), then the function should return false and the caller should schedule the operation + * for future execution. + * + * If `immediate` is true, the delay can be disregarded and the operation can be immediately executed, otherwise + * the operation can be executed if and only if delay is greater than 0. + * + * NOTE: The IAuthority interface does not include the `uint32` delay. This is an extension of that interface that + * is backward compatible. Some contracts may thus ignore the second return argument. In that case they will fail + * to identify the indirect workflow, and will consider calls that require a delay to be forbidden. + * + * NOTE: This function does not report the permissions of this manager itself. These are defined by the + * {_canCallSelf} function instead. + */ + function canCall( + address caller, + address target, + bytes4 selector + ) external view returns (bool allowed, uint32 delay); + + /** + * @dev Expiration delay for scheduled proposals. Defaults to 1 week. + * + * IMPORTANT: Avoid overriding the expiration with 0. Otherwise every contract proposal will be expired immediately, + * disabling any scheduling usage. + */ + function expiration() external view returns (uint32); + + /** + * @dev Minimum setback for all delay updates, with the exception of execution delays. It + * can be increased without setback (and reset via {revokeRole} in the case event of an + * accidental increase). Defaults to 5 days. + */ + function minSetback() external view returns (uint32); + + /** + * @dev Get whether the contract is closed disabling any access. Otherwise role permissions are applied. + */ + function isTargetClosed(address target) external view returns (bool); + + /** + * @dev Get the role required to call a function. + */ + function getTargetFunctionRole(address target, bytes4 selector) external view returns (uint64); + + /** + * @dev Get the admin delay for a target contract. Changes to contract configuration are subject to this delay. + */ + function getTargetAdminDelay(address target) external view returns (uint32); + + /** + * @dev Get the id of the role that acts as an admin for the given role. + * + * The admin permission is required to grant the role, revoke the role and update the execution delay to execute + * an operation that is restricted to this role. + */ + function getRoleAdmin(uint64 roleId) external view returns (uint64); + + /** + * @dev Get the role that acts as a guardian for a given role. + * + * The guardian permission allows canceling operations that have been scheduled under the role. + */ + function getRoleGuardian(uint64 roleId) external view returns (uint64); + + /** + * @dev Get the role current grant delay. + * + * Its value may change at any point without an event emitted following a call to {setGrantDelay}. + * Changes to this value, including effect timepoint are notified in advance by the {RoleGrantDelayChanged} event. + */ + function getRoleGrantDelay(uint64 roleId) external view returns (uint32); + + /** + * @dev Get the access details for a given account for a given role. These details include the timepoint at which + * membership becomes active, and the delay applied to all operation by this user that requires this permission + * level. + * + * Returns: + * [0] Timestamp at which the account membership becomes valid. 0 means role is not granted. + * [1] Current execution delay for the account. + * [2] Pending execution delay for the account. + * [3] Timestamp at which the pending execution delay will become active. 0 means no delay update is scheduled. + */ + function getAccess(uint64 roleId, address account) external view returns (uint48, uint32, uint32, uint48); + + /** + * @dev Check if a given account currently has the permission level corresponding to a given role. Note that this + * permission might be associated with an execution delay. {getAccess} can provide more details. + */ + function hasRole(uint64 roleId, address account) external view returns (bool, uint32); + + /** + * @dev Give a label to a role, for improved role discoverability by UIs. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {RoleLabel} event. + */ + function labelRole(uint64 roleId, string calldata label) external; + + /** + * @dev Add `account` to `roleId`, or change its execution delay. + * + * This gives the account the authorization to call any function that is restricted to this role. An optional + * execution delay (in seconds) can be set. If that delay is non 0, the user is required to schedule any operation + * that is restricted to members of this role. The user will only be able to execute the operation after the delay has + * passed, before it has expired. During this period, admin and guardians can cancel the operation (see {cancel}). + * + * If the account has already been granted this role, the execution delay will be updated. This update is not + * immediate and follows the delay rules. For example, if a user currently has a delay of 3 hours, and this is + * called to reduce that delay to 1 hour, the new delay will take some time to take effect, enforcing that any + * operation executed in the 3 hours that follows this update was indeed scheduled before this update. + * + * Requirements: + * + * - the caller must be an admin for the role (see {getRoleAdmin}) + * - granted role must not be the `PUBLIC_ROLE` + * + * Emits a {RoleGranted} event. + */ + function grantRole(uint64 roleId, address account, uint32 executionDelay) external; + + /** + * @dev Remove an account from a role, with immediate effect. If the account does not have the role, this call has + * no effect. + * + * Requirements: + * + * - the caller must be an admin for the role (see {getRoleAdmin}) + * - revoked role must not be the `PUBLIC_ROLE` + * + * Emits a {RoleRevoked} event if the account had the role. + */ + function revokeRole(uint64 roleId, address account) external; + + /** + * @dev Renounce role permissions for the calling account with immediate effect. If the sender is not in + * the role this call has no effect. + * + * Requirements: + * + * - the caller must be `callerConfirmation`. + * + * Emits a {RoleRevoked} event if the account had the role. + */ + function renounceRole(uint64 roleId, address callerConfirmation) external; + + /** + * @dev Change admin role for a given role. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {RoleAdminChanged} event + */ + function setRoleAdmin(uint64 roleId, uint64 admin) external; + + /** + * @dev Change guardian role for a given role. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {RoleGuardianChanged} event + */ + function setRoleGuardian(uint64 roleId, uint64 guardian) external; + + /** + * @dev Update the delay for granting a `roleId`. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {RoleGrantDelayChanged} event. + */ + function setGrantDelay(uint64 roleId, uint32 newDelay) external; + + /** + * @dev Set the role required to call functions identified by the `selectors` in the `target` contract. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {TargetFunctionRoleUpdated} event per selector. + */ + function setTargetFunctionRole(address target, bytes4[] calldata selectors, uint64 roleId) external; + + /** + * @dev Set the delay for changing the configuration of a given target contract. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {TargetAdminDelayUpdated} event. + */ + function setTargetAdminDelay(address target, uint32 newDelay) external; + + /** + * @dev Set the closed flag for a contract. + * + * Requirements: + * + * - the caller must be a global admin + * + * Emits a {TargetClosed} event. + */ + function setTargetClosed(address target, bool closed) external; + + /** + * @dev Return the timepoint at which a scheduled operation will be ready for execution. This returns 0 if the + * operation is not yet scheduled, has expired, was executed, or was canceled. + */ + function getSchedule(bytes32 id) external view returns (uint48); + + /** + * @dev Return the nonce for the latest scheduled operation with a given id. Returns 0 if the operation has never + * been scheduled. + */ + function getNonce(bytes32 id) external view returns (uint32); + + /** + * @dev Schedule a delayed operation for future execution, and return the operation identifier. It is possible to + * choose the timestamp at which the operation becomes executable as long as it satisfies the execution delays + * required for the caller. The special value zero will automatically set the earliest possible time. + * + * Returns the `operationId` that was scheduled. Since this value is a hash of the parameters, it can reoccur when + * the same parameters are used; if this is relevant, the returned `nonce` can be used to uniquely identify this + * scheduled operation from other occurrences of the same `operationId` in invocations of {execute} and {cancel}. + * + * Emits a {OperationScheduled} event. + * + * NOTE: It is not possible to concurrently schedule more than one operation with the same `target` and `data`. If + * this is necessary, a random byte can be appended to `data` to act as a salt that will be ignored by the target + * contract if it is using standard Solidity ABI encoding. + */ + function schedule(address target, bytes calldata data, uint48 when) external returns (bytes32, uint32); + + /** + * @dev Execute a function that is delay restricted, provided it was properly scheduled beforehand, or the + * execution delay is 0. + * + * Returns the nonce that identifies the previously scheduled operation that is executed, or 0 if the + * operation wasn't previously scheduled (if the caller doesn't have an execution delay). + * + * Emits an {OperationExecuted} event only if the call was scheduled and delayed. + */ + function execute(address target, bytes calldata data) external payable returns (uint32); + + /** + * @dev Cancel a scheduled (delayed) operation. Returns the nonce that identifies the previously scheduled + * operation that is cancelled. + * + * Requirements: + * + * - the caller must be the proposer, a guardian of the targeted function, or a global admin + * + * Emits a {OperationCanceled} event. + */ + function cancel(address caller, address target, bytes calldata data) external returns (uint32); + + /** + * @dev Consume a scheduled operation targeting the caller. If such an operation exists, mark it as consumed + * (emit an {OperationExecuted} event and clean the state). Otherwise, throw an error. + * + * This is useful for contract that want to enforce that calls targeting them were scheduled on the manager, + * with all the verifications that it implies. + * + * Emit a {OperationExecuted} event. + */ + function consumeScheduledOp(address caller, bytes calldata data) external; + + /** + * @dev Hashing function for delayed operations. + */ + function hashOperation(address caller, address target, bytes calldata data) external view returns (bytes32); + + /** + * @dev Changes the authority of a target managed by this manager instance. + * + * Requirements: + * + * - the caller must be a global admin + */ + function updateAuthority(address target, address newAuthority) external; +} diff --git a/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol b/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol new file mode 100644 index 0000000..e2d3898 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/access/manager/IAuthority.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (access/manager/IAuthority.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Standard interface for permissioning originally defined in Dappsys. + */ +interface IAuthority { + /** + * @dev Returns true if the caller can invoke on a target the function identified by a function selector. + */ + function canCall(address caller, address target, bytes4 selector) external view returns (bool allowed); +} diff --git a/lib/openzeppelin-contracts/contracts/finance/README.adoc b/lib/openzeppelin-contracts/contracts/finance/README.adoc new file mode 100644 index 0000000..ac7e4f0 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/finance/README.adoc @@ -0,0 +1,14 @@ += Finance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/finance + +This directory includes primitives for financial systems: + +- {VestingWallet} handles the vesting of Ether and ERC20 tokens for a given beneficiary. Custody of multiple tokens can + be given to this contract, which will release the token to the beneficiary following a given, customizable, vesting + schedule. + +== Contracts + +{{VestingWallet}} diff --git a/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol b/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol new file mode 100644 index 0000000..5abb7cd --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/finance/VestingWallet.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (finance/VestingWallet.sol) +pragma solidity ^0.8.20; + +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol"; +import {Address} from "../utils/Address.sol"; +import {Context} from "../utils/Context.sol"; +import {Ownable} from "../access/Ownable.sol"; + +/** + * @dev A vesting wallet is an ownable contract that can receive native currency and ERC20 tokens, and release these + * assets to the wallet owner, also referred to as "beneficiary", according to a vesting schedule. + * + * Any assets 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. + * + * By setting the duration to 0, one can configure this contract to behave like an asset timelock that hold tokens for + * a beneficiary until a specified time. + * + * NOTE: Since the wallet is {Ownable}, and ownership can be transferred, it is possible to sell unvested tokens. + * Preventing this in a smart contract is difficult, considering that: 1) a beneficiary address could be a + * counterfactually deployed contract, 2) there is likely to be a migration path for EOAs to become contracts in the + * near future. + * + * NOTE: When using this contract with any token whose balance is adjusted automatically (i.e. a rebase token), make + * sure to account the supply/balance adjustment in the vesting schedule to ensure the vested amount is as intended. + */ +contract VestingWallet is Context, Ownable { + event EtherReleased(uint256 amount); + event ERC20Released(address indexed token, uint256 amount); + + uint256 private _released; + mapping(address token => uint256) private _erc20Released; + uint64 private immutable _start; + uint64 private immutable _duration; + + /** + * @dev Sets the sender as the initial owner, the beneficiary as the pending owner, the start timestamp and the + * vesting duration of the vesting wallet. + */ + constructor(address beneficiary, uint64 startTimestamp, uint64 durationSeconds) payable Ownable(beneficiary) { + _start = startTimestamp; + _duration = durationSeconds; + } + + /** + * @dev The contract should be able to receive Eth. + */ + receive() external payable virtual {} + + /** + * @dev Getter for the start timestamp. + */ + function start() public view virtual returns (uint256) { + return _start; + } + + /** + * @dev Getter for the vesting duration. + */ + function duration() public view virtual returns (uint256) { + return _duration; + } + + /** + * @dev Getter for the end timestamp. + */ + function end() public view virtual returns (uint256) { + return start() + duration(); + } + + /** + * @dev Amount of eth already released + */ + function released() public view virtual returns (uint256) { + return _released; + } + + /** + * @dev Amount of token already released + */ + function released(address token) public view virtual returns (uint256) { + return _erc20Released[token]; + } + + /** + * @dev Getter for the amount of releasable eth. + */ + function releasable() public view virtual returns (uint256) { + return vestedAmount(uint64(block.timestamp)) - released(); + } + + /** + * @dev Getter for the amount of releasable `token` tokens. `token` should be the address of an + * IERC20 contract. + */ + function releasable(address token) public view virtual returns (uint256) { + return vestedAmount(token, uint64(block.timestamp)) - released(token); + } + + /** + * @dev Release the native token (ether) that have already vested. + * + * Emits a {EtherReleased} event. + */ + function release() public virtual { + uint256 amount = releasable(); + _released += amount; + emit EtherReleased(amount); + Address.sendValue(payable(owner()), amount); + } + + /** + * @dev Release the tokens that have already vested. + * + * Emits a {ERC20Released} event. + */ + function release(address token) public virtual { + uint256 amount = releasable(token); + _erc20Released[token] += amount; + emit ERC20Released(token, amount); + SafeERC20.safeTransfer(IERC20(token), owner(), amount); + } + + /** + * @dev Calculates the amount of ether that has already vested. Default implementation is a linear vesting curve. + */ + function vestedAmount(uint64 timestamp) public view virtual returns (uint256) { + return _vestingSchedule(address(this).balance + released(), timestamp); + } + + /** + * @dev Calculates the amount of tokens that has already vested. Default implementation is a linear vesting curve. + */ + function vestedAmount(address token, uint64 timestamp) public view virtual returns (uint256) { + return _vestingSchedule(IERC20(token).balanceOf(address(this)) + released(token), timestamp); + } + + /** + * @dev Virtual implementation of the vesting formula. This returns the amount vested, as a function of time, for + * an asset given its total historical allocation. + */ + function _vestingSchedule(uint256 totalAllocation, uint64 timestamp) internal view virtual returns (uint256) { + if (timestamp < start()) { + return 0; + } else if (timestamp >= end()) { + return totalAllocation; + } else { + return (totalAllocation * (timestamp - start())) / duration(); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/Governor.sol b/lib/openzeppelin-contracts/contracts/governance/Governor.sol new file mode 100644 index 0000000..830c9d8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/Governor.sol @@ -0,0 +1,850 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/Governor.sol) + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; +import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; +import {SignatureChecker} from "../utils/cryptography/SignatureChecker.sol"; +import {IERC165, ERC165} from "../utils/introspection/ERC165.sol"; +import {SafeCast} from "../utils/math/SafeCast.sol"; +import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; +import {Address} from "../utils/Address.sol"; +import {Context} from "../utils/Context.sol"; +import {Nonces} from "../utils/Nonces.sol"; +import {IGovernor, IERC6372} from "./IGovernor.sol"; + +/** + * @dev Core of the governance system, designed to be extended through 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} + * - Additionally, {votingPeriod} must also be implemented + */ +abstract contract Governor is Context, ERC165, EIP712, Nonces, IGovernor, IERC721Receiver, IERC1155Receiver { + using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque; + + bytes32 public constant BALLOT_TYPEHASH = + keccak256("Ballot(uint256 proposalId,uint8 support,address voter,uint256 nonce)"); + bytes32 public constant EXTENDED_BALLOT_TYPEHASH = + keccak256( + "ExtendedBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason,bytes params)" + ); + + struct ProposalCore { + address proposer; + uint48 voteStart; + uint32 voteDuration; + bool executed; + bool canceled; + uint48 etaSeconds; + } + + bytes32 private constant ALL_PROPOSAL_STATES_BITMAP = bytes32((2 ** (uint8(type(ProposalState).max) + 1)) - 1); + string private _name; + + mapping(uint256 proposalId => ProposalCore) private _proposals; + + // This queue keeps track of the governor operating on itself. Calls to functions protected by the {onlyGovernance} + // modifier needs to be whitelisted in this queue. Whitelisting is set in {execute}, consumed by the + // {onlyGovernance} modifier and eventually reset after {_executeOperations} completes. This ensures that the + // execution of {onlyGovernance} protected calls can only be achieved through successful proposals. + DoubleEndedQueue.Bytes32Deque private _governanceCall; + + /** + * @dev Restricts a function so it can only be executed through governance proposals. For example, governance + * parameter setters in {GovernorSettings} are protected using this modifier. + * + * The governance executing address may be different from the Governor's own address, for example it could be a + * timelock. This can be customized by modules by overriding {_executor}. The executor is only able to invoke these + * functions during the execution of the governor's {execute} function, and not under any other circumstances. Thus, + * for example, additional timelock proposers are not able to change governance parameters without going through the + * governance protocol (since v4.6). + */ + modifier onlyGovernance() { + _checkGovernance(); + _; + } + + /** + * @dev Sets the value for {name} and {version} + */ + constructor(string memory name_) EIP712(name_, version()) { + _name = name_; + } + + /** + * @dev Function to receive ETH that will be handled by the governor (disabled if executor is a third party contract) + */ + receive() external payable virtual { + if (_executor() != address(this)) { + revert GovernorDisabledDeposit(); + } + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return + interfaceId == type(IGovernor).interfaceId || + interfaceId == type(IERC1155Receiver).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IGovernor-name}. + */ + function name() public view virtual returns (string memory) { + return _name; + } + + /** + * @dev See {IGovernor-version}. + */ + function version() public view virtual returns (string memory) { + return "1"; + } + + /** + * @dev See {IGovernor-hashProposal}. + * + * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array + * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id + * can be produced from the proposal data which is part of the {ProposalCreated} event. It can even be computed in + * advance, before the proposal is submitted. + * + * Note that the chainId and the governor address are not part of the proposal id computation. Consequently, the + * same proposal (with same operation and same description) will have the same id if submitted on multiple governors + * across multiple networks. This also means that in order to execute the same operation twice (on the same + * governor) the proposer will have to change the description in order to avoid proposal id conflicts. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public pure virtual returns (uint256) { + return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash))); + } + + /** + * @dev See {IGovernor-state}. + */ + function state(uint256 proposalId) public view virtual returns (ProposalState) { + // We read the struct fields into the stack at once so Solidity emits a single SLOAD + ProposalCore storage proposal = _proposals[proposalId]; + bool proposalExecuted = proposal.executed; + bool proposalCanceled = proposal.canceled; + + if (proposalExecuted) { + return ProposalState.Executed; + } + + if (proposalCanceled) { + return ProposalState.Canceled; + } + + uint256 snapshot = proposalSnapshot(proposalId); + + if (snapshot == 0) { + revert GovernorNonexistentProposal(proposalId); + } + + uint256 currentTimepoint = clock(); + + if (snapshot >= currentTimepoint) { + return ProposalState.Pending; + } + + uint256 deadline = proposalDeadline(proposalId); + + if (deadline >= currentTimepoint) { + return ProposalState.Active; + } else if (!_quorumReached(proposalId) || !_voteSucceeded(proposalId)) { + return ProposalState.Defeated; + } else if (proposalEta(proposalId) == 0) { + return ProposalState.Succeeded; + } else { + return ProposalState.Queued; + } + } + + /** + * @dev See {IGovernor-proposalThreshold}. + */ + function proposalThreshold() public view virtual returns (uint256) { + return 0; + } + + /** + * @dev See {IGovernor-proposalSnapshot}. + */ + function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].voteStart; + } + + /** + * @dev See {IGovernor-proposalDeadline}. + */ + function proposalDeadline(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].voteStart + _proposals[proposalId].voteDuration; + } + + /** + * @dev See {IGovernor-proposalProposer}. + */ + function proposalProposer(uint256 proposalId) public view virtual returns (address) { + return _proposals[proposalId].proposer; + } + + /** + * @dev See {IGovernor-proposalEta}. + */ + function proposalEta(uint256 proposalId) public view virtual returns (uint256) { + return _proposals[proposalId].etaSeconds; + } + + /** + * @dev See {IGovernor-proposalNeedsQueuing}. + */ + function proposalNeedsQueuing(uint256) public view virtual returns (bool) { + return false; + } + + /** + * @dev Reverts if the `msg.sender` is not the executor. In case the executor is not this contract + * itself, the function reverts if `msg.data` is not whitelisted as a result of an {execute} + * operation. See {onlyGovernance}. + */ + function _checkGovernance() internal virtual { + if (_executor() != _msgSender()) { + revert GovernorOnlyExecutor(_msgSender()); + } + if (_executor() != address(this)) { + bytes32 msgDataHash = keccak256(_msgData()); + // loop until popping the expected operation - throw if deque is empty (operation not authorized) + while (_governanceCall.popFront() != msgDataHash) {} + } + } + + /** + * @dev Amount of votes already cast passes the threshold limit. + */ + function _quorumReached(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Is the proposal successful or not. + */ + function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool); + + /** + * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`. + */ + 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`. + * + * Note: Support is generic and can represent various things depending on the voting system used. + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal virtual; + + /** + * @dev Default additional encoded parameters used by castVote methods that don't include them + * + * Note: Should be overridden by specific implementations to use an appropriate value, the + * meaning of the additional params, in the context of that implementation + */ + function _defaultParams() internal view virtual returns (bytes memory) { + return ""; + } + + /** + * @dev See {IGovernor-propose}. This function has opt-in frontrunning protection, described in {_isValidDescriptionForProposer}. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual returns (uint256) { + address proposer = _msgSender(); + + // check description restriction + if (!_isValidDescriptionForProposer(proposer, description)) { + revert GovernorRestrictedProposer(proposer); + } + + // check proposal threshold + uint256 proposerVotes = getVotes(proposer, clock() - 1); + uint256 votesThreshold = proposalThreshold(); + if (proposerVotes < votesThreshold) { + revert GovernorInsufficientProposerVotes(proposer, proposerVotes, votesThreshold); + } + + return _propose(targets, values, calldatas, description, proposer); + } + + /** + * @dev Internal propose mechanism. Can be overridden to add more logic on proposal creation. + * + * Emits a {IGovernor-ProposalCreated} event. + */ + function _propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description, + address proposer + ) internal virtual returns (uint256 proposalId) { + proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description))); + + if (targets.length != values.length || targets.length != calldatas.length || targets.length == 0) { + revert GovernorInvalidProposalLength(targets.length, calldatas.length, values.length); + } + if (_proposals[proposalId].voteStart != 0) { + revert GovernorUnexpectedProposalState(proposalId, state(proposalId), bytes32(0)); + } + + uint256 snapshot = clock() + votingDelay(); + uint256 duration = votingPeriod(); + + ProposalCore storage proposal = _proposals[proposalId]; + proposal.proposer = proposer; + proposal.voteStart = SafeCast.toUint48(snapshot); + proposal.voteDuration = SafeCast.toUint32(duration); + + emit ProposalCreated( + proposalId, + proposer, + targets, + values, + new string[](targets.length), + calldatas, + snapshot, + snapshot + duration, + description + ); + + // Using a named return variable to avoid stack too deep errors + } + + /** + * @dev See {IGovernor-queue}. + */ + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Succeeded)); + + uint48 etaSeconds = _queueOperations(proposalId, targets, values, calldatas, descriptionHash); + + if (etaSeconds != 0) { + _proposals[proposalId].etaSeconds = etaSeconds; + emit ProposalQueued(proposalId, etaSeconds); + } else { + revert GovernorQueueNotImplemented(); + } + + return proposalId; + } + + /** + * @dev Internal queuing mechanism. Can be overridden (without a super call) to modify the way queuing is + * performed (for example adding a vault/timelock). + * + * This is empty by default, and must be overridden to implement queuing. + * + * This function returns a timestamp that describes the expected ETA for execution. If the returned value is 0 + * (which is the default value), the core will consider queueing did not succeed, and the public {queue} function + * will revert. + * + * NOTE: Calling this function directly will NOT check the current state of the proposal, or emit the + * `ProposalQueued` event. Queuing a proposal should be done using {queue}. + */ + function _queueOperations( + uint256 /*proposalId*/, + address[] memory /*targets*/, + uint256[] memory /*values*/, + bytes[] memory /*calldatas*/, + bytes32 /*descriptionHash*/ + ) internal virtual returns (uint48) { + return 0; + } + + /** + * @dev See {IGovernor-execute}. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public payable virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + _validateStateBitmap( + proposalId, + _encodeStateBitmap(ProposalState.Succeeded) | _encodeStateBitmap(ProposalState.Queued) + ); + + // mark as executed before calls to avoid reentrancy + _proposals[proposalId].executed = true; + + // before execute: register governance call in queue. + if (_executor() != address(this)) { + for (uint256 i = 0; i < targets.length; ++i) { + if (targets[i] == address(this)) { + _governanceCall.pushBack(keccak256(calldatas[i])); + } + } + } + + _executeOperations(proposalId, targets, values, calldatas, descriptionHash); + + // after execute: cleanup governance call queue. + if (_executor() != address(this) && !_governanceCall.empty()) { + _governanceCall.clear(); + } + + emit ProposalExecuted(proposalId); + + return proposalId; + } + + /** + * @dev Internal execution mechanism. Can be overridden (without a super call) to modify the way execution is + * performed (for example adding a vault/timelock). + * + * NOTE: Calling this function directly will NOT check the current state of the proposal, set the executed flag to + * true or emit the `ProposalExecuted` event. Executing a proposal should be done using {execute} or {_execute}. + */ + function _executeOperations( + uint256 /* proposalId */, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual { + for (uint256 i = 0; i < targets.length; ++i) { + (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); + Address.verifyCallResult(success, returndata); + } + } + + /** + * @dev See {IGovernor-cancel}. + */ + function cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) public virtual returns (uint256) { + // The proposalId will be recomputed in the `_cancel` call further down. However we need the value before we + // do the internal call, because we need to check the proposal state BEFORE the internal `_cancel` call + // changes it. The `hashProposal` duplication has a cost that is limited, and that we accept. + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + // public cancel restrictions (on top of existing _cancel restrictions). + _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Pending)); + if (_msgSender() != proposalProposer(proposalId)) { + revert GovernorOnlyProposer(_msgSender()); + } + + return _cancel(targets, values, calldatas, descriptionHash); + } + + /** + * @dev Internal cancel mechanism with minimal restrictions. A proposal can be cancelled in any state other than + * Canceled, Expired, or Executed. Once cancelled a proposal can't be re-submitted. + * + * Emits a {IGovernor-ProposalCanceled} event. + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual returns (uint256) { + uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash); + + _validateStateBitmap( + proposalId, + ALL_PROPOSAL_STATES_BITMAP ^ + _encodeStateBitmap(ProposalState.Canceled) ^ + _encodeStateBitmap(ProposalState.Expired) ^ + _encodeStateBitmap(ProposalState.Executed) + ); + + _proposals[proposalId].canceled = true; + emit ProposalCanceled(proposalId); + + return proposalId; + } + + /** + * @dev See {IGovernor-getVotes}. + */ + function getVotes(address account, uint256 timepoint) public view virtual returns (uint256) { + return _getVotes(account, timepoint, _defaultParams()); + } + + /** + * @dev See {IGovernor-getVotesWithParams}. + */ + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) public view virtual returns (uint256) { + return _getVotes(account, timepoint, params); + } + + /** + * @dev See {IGovernor-castVote}. + */ + function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, ""); + } + + /** + * @dev See {IGovernor-castVoteWithReason}. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) public virtual returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParams}. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) public virtual returns (uint256) { + address voter = _msgSender(); + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev See {IGovernor-castVoteBySig}. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + address voter, + bytes memory signature + ) public virtual returns (uint256) { + bool valid = SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4(keccak256(abi.encode(BALLOT_TYPEHASH, proposalId, support, voter, _useNonce(voter)))), + signature + ); + + if (!valid) { + revert GovernorInvalidSignature(voter); + } + + return _castVote(proposalId, voter, support, ""); + } + + /** + * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + address voter, + string calldata reason, + bytes memory params, + bytes memory signature + ) public virtual returns (uint256) { + bool valid = SignatureChecker.isValidSignatureNow( + voter, + _hashTypedDataV4( + keccak256( + abi.encode( + EXTENDED_BALLOT_TYPEHASH, + proposalId, + support, + voter, + _useNonce(voter), + keccak256(bytes(reason)), + keccak256(params) + ) + ) + ), + signature + ); + + if (!valid) { + revert GovernorInvalidSignature(voter); + } + + return _castVote(proposalId, voter, support, reason, params); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams(). + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason + ) internal virtual returns (uint256) { + return _castVote(proposalId, account, support, reason, _defaultParams()); + } + + /** + * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve + * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. + * + * Emits a {IGovernor-VoteCast} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual returns (uint256) { + _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Active)); + + uint256 weight = _getVotes(account, proposalSnapshot(proposalId), params); + _countVote(proposalId, account, support, weight, params); + + if (params.length == 0) { + emit VoteCast(account, proposalId, support, weight, reason); + } else { + emit VoteCastWithParams(account, proposalId, support, weight, reason, params); + } + + return weight; + } + + /** + * @dev Relays a transaction or function call to an arbitrary target. In cases where the governance executor + * is some contract other than the governor itself, like when using a timelock, this function can be invoked + * in a governance proposal to recover tokens or Ether that was sent to the governor contract by mistake. + * Note that if the executor is simply the governor itself, use of `relay` is redundant. + */ + function relay(address target, uint256 value, bytes calldata data) external payable virtual onlyGovernance { + (bool success, bytes memory returndata) = target.call{value: value}(data); + Address.verifyCallResult(success, returndata); + } + + /** + * @dev Address through which the governor executes action. Will be overloaded by module that execute actions + * through another contract such as a timelock. + */ + function _executor() internal view virtual returns (address) { + return address(this); + } + + /** + * @dev See {IERC721Receiver-onERC721Received}. + * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { + if (_executor() != address(this)) { + revert GovernorDisabledDeposit(); + } + return this.onERC721Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155Received}. + * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). + */ + function onERC1155Received(address, address, uint256, uint256, bytes memory) public virtual returns (bytes4) { + if (_executor() != address(this)) { + revert GovernorDisabledDeposit(); + } + return this.onERC1155Received.selector; + } + + /** + * @dev See {IERC1155Receiver-onERC1155BatchReceived}. + * Receiving tokens is disabled if the governance executor is other than the governor itself (eg. when using with a timelock). + */ + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual returns (bytes4) { + if (_executor() != address(this)) { + revert GovernorDisabledDeposit(); + } + return this.onERC1155BatchReceived.selector; + } + + /** + * @dev Encodes a `ProposalState` into a `bytes32` representation where each bit enabled corresponds to + * the underlying position in the `ProposalState` enum. For example: + * + * 0x000...10000 + * ^^^^^^------ ... + * ^----- Succeeded + * ^---- Defeated + * ^--- Canceled + * ^-- Active + * ^- Pending + */ + function _encodeStateBitmap(ProposalState proposalState) internal pure returns (bytes32) { + return bytes32(1 << uint8(proposalState)); + } + + /** + * @dev Check that the current state of a proposal matches the requirements described by the `allowedStates` bitmap. + * This bitmap should be built using `_encodeStateBitmap`. + * + * If requirements are not met, reverts with a {GovernorUnexpectedProposalState} error. + */ + function _validateStateBitmap(uint256 proposalId, bytes32 allowedStates) private view returns (ProposalState) { + ProposalState currentState = state(proposalId); + if (_encodeStateBitmap(currentState) & allowedStates == bytes32(0)) { + revert GovernorUnexpectedProposalState(proposalId, currentState, allowedStates); + } + return currentState; + } + + /* + * @dev Check if the proposer is authorized to submit a proposal with the given description. + * + * If the proposal description ends with `#proposer=0x???`, where `0x???` is an address written as a hex string + * (case insensitive), then the submission of this proposal will only be authorized to said address. + * + * This is used for frontrunning protection. By adding this pattern at the end of their proposal, one can ensure + * that no other address can submit the same proposal. An attacker would have to either remove or change that part, + * which would result in a different proposal id. + * + * If the description does not match this pattern, it is unrestricted and anyone can submit it. This includes: + * - If the `0x???` part is not a valid hex string. + * - If the `0x???` part is a valid hex string, but does not contain exactly 40 hex digits. + * - If it ends with the expected suffix followed by newlines or other whitespace. + * - If it ends with some other similar suffix, e.g. `#other=abc`. + * - If it does not end with any such suffix. + */ + function _isValidDescriptionForProposer( + address proposer, + string memory description + ) internal view virtual returns (bool) { + uint256 len = bytes(description).length; + + // Length is too short to contain a valid proposer suffix + if (len < 52) { + return true; + } + + // Extract what would be the `#proposer=0x` marker beginning the suffix + bytes12 marker; + assembly { + // - Start of the string contents in memory = description + 32 + // - First character of the marker = len - 52 + // - Length of "#proposer=0x0000000000000000000000000000000000000000" = 52 + // - We read the memory word starting at the first character of the marker: + // - (description + 32) + (len - 52) = description + (len - 20) + // - Note: Solidity will ignore anything past the first 12 bytes + marker := mload(add(description, sub(len, 20))) + } + + // If the marker is not found, there is no proposer suffix to check + if (marker != bytes12("#proposer=0x")) { + return true; + } + + // Parse the 40 characters following the marker as uint160 + uint160 recovered = 0; + for (uint256 i = len - 40; i < len; ++i) { + (bool isHex, uint8 value) = _tryHexToUint(bytes(description)[i]); + // If any of the characters is not a hex digit, ignore the suffix entirely + if (!isHex) { + return true; + } + recovered = (recovered << 4) | value; + } + + return recovered == uint160(proposer); + } + + /** + * @dev Try to parse a character from a string as a hex value. Returns `(true, value)` if the char is in + * `[0-9a-fA-F]` and `(false, 0)` otherwise. Value is guaranteed to be in the range `0 <= value < 16` + */ + function _tryHexToUint(bytes1 char) private pure returns (bool, uint8) { + uint8 c = uint8(char); + unchecked { + // Case 0-9 + if (47 < c && c < 58) { + return (true, c - 48); + } + // Case A-F + else if (64 < c && c < 71) { + return (true, c - 55); + } + // Case a-f + else if (96 < c && c < 103) { + return (true, c - 87); + } + // Else: not a hex char + else { + return (false, 0); + } + } + } + + /** + * @inheritdoc IERC6372 + */ + function clock() public view virtual returns (uint48); + + /** + * @inheritdoc IERC6372 + */ + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public view virtual returns (string memory); + + /** + * @inheritdoc IGovernor + */ + function votingDelay() public view virtual returns (uint256); + + /** + * @inheritdoc IGovernor + */ + function votingPeriod() public view virtual returns (uint256); + + /** + * @inheritdoc IGovernor + */ + function quorum(uint256 timepoint) public view virtual returns (uint256); +} diff --git a/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol b/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol new file mode 100644 index 0000000..6cde0e8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/IGovernor.sol @@ -0,0 +1,427 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/IGovernor.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../interfaces/IERC165.sol"; +import {IERC6372} from "../interfaces/IERC6372.sol"; + +/** + * @dev Interface of the {Governor} core. + */ +interface IGovernor is IERC165, IERC6372 { + enum ProposalState { + Pending, + Active, + Canceled, + Defeated, + Succeeded, + Queued, + Expired, + Executed + } + + /** + * @dev Empty proposal or a mismatch between the parameters length for a proposal call. + */ + error GovernorInvalidProposalLength(uint256 targets, uint256 calldatas, uint256 values); + + /** + * @dev The vote was already cast. + */ + error GovernorAlreadyCastVote(address voter); + + /** + * @dev Token deposits are disabled in this contract. + */ + error GovernorDisabledDeposit(); + + /** + * @dev The `account` is not a proposer. + */ + error GovernorOnlyProposer(address account); + + /** + * @dev The `account` is not the governance executor. + */ + error GovernorOnlyExecutor(address account); + + /** + * @dev The `proposalId` doesn't exist. + */ + error GovernorNonexistentProposal(uint256 proposalId); + + /** + * @dev The current state of a proposal is not the required for performing an operation. + * The `expectedStates` is a bitmap with the bits enabled for each ProposalState enum position + * counting from right to left. + * + * NOTE: If `expectedState` is `bytes32(0)`, the proposal is expected to not be in any state (i.e. not exist). + * This is the case when a proposal that is expected to be unset is already initiated (the proposal is duplicated). + * + * See {Governor-_encodeStateBitmap}. + */ + error GovernorUnexpectedProposalState(uint256 proposalId, ProposalState current, bytes32 expectedStates); + + /** + * @dev The voting period set is not a valid period. + */ + error GovernorInvalidVotingPeriod(uint256 votingPeriod); + + /** + * @dev The `proposer` does not have the required votes to create a proposal. + */ + error GovernorInsufficientProposerVotes(address proposer, uint256 votes, uint256 threshold); + + /** + * @dev The `proposer` is not allowed to create a proposal. + */ + error GovernorRestrictedProposer(address proposer); + + /** + * @dev The vote type used is not valid for the corresponding counting module. + */ + error GovernorInvalidVoteType(); + + /** + * @dev Queue operation is not implemented for this governor. Execute should be called directly. + */ + error GovernorQueueNotImplemented(); + + /** + * @dev The proposal hasn't been queued yet. + */ + error GovernorNotQueuedProposal(uint256 proposalId); + + /** + * @dev The proposal has already been queued. + */ + error GovernorAlreadyQueuedProposal(uint256 proposalId); + + /** + * @dev The provided signature is not valid for the expected `voter`. + * If the `voter` is a contract, the signature is not valid using {IERC1271-isValidSignature}. + */ + error GovernorInvalidSignature(address voter); + + /** + * @dev Emitted when a proposal is created. + */ + event ProposalCreated( + uint256 proposalId, + address proposer, + address[] targets, + uint256[] values, + string[] signatures, + bytes[] calldatas, + uint256 voteStart, + uint256 voteEnd, + string description + ); + + /** + * @dev Emitted when a proposal is queued. + */ + event ProposalQueued(uint256 proposalId, uint256 etaSeconds); + + /** + * @dev Emitted when a proposal is executed. + */ + event ProposalExecuted(uint256 proposalId); + + /** + * @dev Emitted when a proposal is canceled. + */ + event ProposalCanceled(uint256 proposalId); + + /** + * @dev Emitted when a vote is cast without params. + * + * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used. + */ + event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason); + + /** + * @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 interpepretation also depends on the voting module used. + */ + event VoteCastWithParams( + address indexed voter, + uint256 proposalId, + uint8 support, + uint256 weight, + string reason, + bytes params + ); + + /** + * @notice module:core + * @dev Name of the governor instance (used in building the ERC712 domain separator). + */ + function name() external view returns (string memory); + + /** + * @notice module:core + * @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1" + */ + function version() external view 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 + * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of + * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`. + * + * There are 2 standard keys: `support` and `quorum`. + * + * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`. + * - `quorum=bravo` means that only For votes are counted towards quorum. + * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum. + * + * If a counting module makes use of encoded `params`, it should include this under a `params` key with a unique + * name that describes the behavior. For example: + * + * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain. + * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote. + * + * NOTE: The string can be decoded by the standard + * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`] + * JavaScript class. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() external view returns (string memory); + + /** + * @notice module:core + * @dev Hashing function used to (re)build the proposal id from the proposal details.. + */ + function hashProposal( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external pure returns (uint256); + + /** + * @notice module:core + * @dev Current state of a proposal, following Compound's convention + */ + function state(uint256 proposalId) external view returns (ProposalState); + + /** + * @notice module:core + * @dev The number of votes required in order for a voter to become a proposer. + */ + function proposalThreshold() external view returns (uint256); + + /** + * @notice module:core + * @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) external view returns (uint256); + + /** + * @notice module:core + * @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) external view returns (uint256); + + /** + * @notice module:core + * @dev The account that created a proposal. + */ + function proposalProposer(uint256 proposalId) external view returns (address); + + /** + * @notice module:core + * @dev The time when a queued proposal becomes executable ("ETA"). Unlike {proposalSnapshot} and + * {proposalDeadline}, this doesn't use the governor clock, and instead relies on the executor's clock which may be + * different. In most cases this will be a timestamp. + */ + function proposalEta(uint256 proposalId) external view returns (uint256); + + /** + * @notice module:core + * @dev Whether a proposal needs to be queued before execution. + */ + function proposalNeedsQueuing(uint256 proposalId) external view returns (bool); + + /** + * @notice module:user-config + * @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. + * + * NOTE: While this interface returns a uint256, timepoints are stored as uint48 following the ERC-6372 clock type. + * Consequently this value must fit in a uint48 (when added to the current clock). See {IERC6372-clock}. + */ + function votingDelay() external view returns (uint256); + + /** + * @notice module:user-config + * @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 + * duration compared to the voting delay. + * + * NOTE: This value is stored when the proposal is submitted so that possible changes to the value do not affect + * proposals that have already been submitted. The type used to save it is a uint32. Consequently, while this + * interface returns a uint256, the value it returns should fit in a uint32. + */ + function votingPeriod() external view returns (uint256); + + /** + * @notice module:user-config + * @dev Minimum number of cast voted required for a proposal to be successful. + * + * 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 timepoint) external view returns (uint256); + + /** + * @notice module:reputation + * @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 timepoint) external view returns (uint256); + + /** + * @notice module:reputation + * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters. + */ + function getVotesWithParams( + address account, + uint256 timepoint, + bytes memory params + ) external view returns (uint256); + + /** + * @notice module:voting + * @dev Returns whether `account` has cast a vote on `proposalId`. + */ + function hasVoted(uint256 proposalId, address account) external view returns (bool); + + /** + * @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. + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) external returns (uint256 proposalId); + + /** + * @dev Queue a proposal. Some governors require this step to be performed before execution can happen. If queuing + * is not necessary, this function may revert. + * Queuing a proposal requires the quorum to be reached, the vote to be successful, and the deadline to be reached. + * + * Emits a {ProposalQueued} event. + */ + function queue( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external returns (uint256 proposalId); + + /** + * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the + * deadline to be reached. Depending on the governor it might also be required that the proposal was queued and + * that some delay passed. + * + * Emits a {ProposalExecuted} event. + * + * NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock. + */ + function execute( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external payable returns (uint256 proposalId); + + /** + * @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( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) external returns (uint256 proposalId); + + /** + * @dev Cast a vote + * + * Emits a {VoteCast} event. + */ + function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance); + + /** + * @dev Cast a vote with a reason + * + * Emits a {VoteCast} event. + */ + function castVoteWithReason( + uint256 proposalId, + uint8 support, + string calldata reason + ) external returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParams( + uint256 proposalId, + uint8 support, + string calldata reason, + bytes memory params + ) external returns (uint256 balance); + + /** + * @dev Cast a vote using the voter's signature, including ERC-1271 signature support. + * + * Emits a {VoteCast} event. + */ + function castVoteBySig( + uint256 proposalId, + uint8 support, + address voter, + bytes memory signature + ) external returns (uint256 balance); + + /** + * @dev Cast a vote with a reason and additional encoded parameters using the voter's signature, + * including ERC-1271 signature support. + * + * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params. + */ + function castVoteWithReasonAndParamsBySig( + uint256 proposalId, + uint8 support, + address voter, + string calldata reason, + bytes memory params, + bytes memory signature + ) external returns (uint256 balance); +} diff --git a/lib/openzeppelin-contracts/contracts/governance/README.adoc b/lib/openzeppelin-contracts/contracts/governance/README.adoc new file mode 100644 index 0000000..5b38c4d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/README.adoc @@ -0,0 +1,167 @@ += Governance + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/governance + +This directory includes primitives for on-chain governance. + +== Governor + +This modular system of Governor contracts allows the deployment on-chain voting protocols similar to https://compound.finance/docs/governance[Compound's Governor Alpha & Bravo] and beyond, through the ability to easily customize multiple aspects of the protocol. + +[TIP] +==== +For a guided experience, set up your Governor contract using https://wizard.openzeppelin.com/#governor[Contracts Wizard]. + +For a written walkthrough, check out our guide on xref:ROOT:governance.adoc[How to set up on-chain governance]. +==== + +* {Governor}: The core contract that contains all the logic and primitives. It is abstract and requires choosing one of each of the modules below, or custom ones. + +Votes modules determine the source of voting power, and sometimes quorum number. + +* {GovernorVotes}: Extracts voting weight from an {ERC20Votes}, or since v4.5 an {ERC721Votes} token. + +* {GovernorVotesQuorumFraction}: Combines with `GovernorVotes` to set the quorum as a fraction of the total token supply. + +Counting modules determine valid voting options. + +* {GovernorCountingSimple}: Simple voting mechanism with 3 voting options: Against, For and Abstain. + +Timelock extensions add a delay for governance decisions to be executed. The workflow is extended to require a `queue` step before execution. With these modules, proposals are executed by the external timelock contract, thus it is the timelock that has to hold the assets that are being governed. + +* {GovernorTimelockControl}: Connects with an instance of {TimelockController}. Allows multiple proposers and executors, in addition to the Governor itself. + +* {GovernorTimelockCompound}: Connects with an instance of Compound's https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[`Timelock`] contract. + +Other extensions can customize the behavior or interface in multiple ways. + +* {GovernorStorage}: Stores the proposal details onchain and provides enumerability of the proposals. This can be useful for some L2 chains where storage is cheap compared to calldata. + +* {GovernorSettings}: Manages some of the settings (voting delay, voting period duration, and proposal threshold) in a way that can be updated through a governance proposal, without requiring an upgrade. + +* {GovernorPreventLateQuorum}: Ensures there is a minimum voting period after quorum is reached as a security protection against large voters. + +In addition to modules and extensions, the core contract requires a few virtual functions to be implemented to your particular specifications: + +* <>: 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. + +=== Core + +{{IGovernor}} + +{{Governor}} + +=== Modules + +{{GovernorCountingSimple}} + +{{GovernorVotes}} + +{{GovernorVotesQuorumFraction}} + +=== Extensions + +{{GovernorTimelockControl}} + +{{GovernorTimelockCompound}} + +{{GovernorSettings}} + +{{GovernorPreventLateQuorum}} + +{{GovernorStorage}} + +== Utils + +{{Votes}} + +== Timelock + +In a governance system, the {TimelockController} contract is in charge of introducing a delay between a proposal and its execution. It can be used with or without a {Governor}. + +{{TimelockController}} + +[[timelock-terminology]] +==== Terminology + +* *Operation:* A transaction (or a set of transactions) that is the subject of the timelock. It has to be scheduled by a proposer and executed by an executor. The timelock enforces a minimum delay between the proposition and the execution (see xref:access-control.adoc#operation_lifecycle[operation lifecycle]). If the operation contains multiple transactions (batch mode), they are executed atomically. Operations are identified by the hash of their content. +* *Operation status:* +** *Unset:* An operation that is not part of the timelock mechanism. +** *Waiting:* An operation that has been scheduled, before the timer expires. +** *Ready:* An operation that has been scheduled, after the timer expires. +** *Pending:* An operation that is either waiting or ready. +** *Done:* An operation that has been executed. +* *Predecessor*: An (optional) dependency between operations. An operation can depend on another operation (its predecessor), forcing the execution order of these two operations. +* *Role*: +** *Admin:* An address (smart contract or EOA) that is in charge of granting the roles of Proposer and Executor. +** *Proposer:* An address (smart contract or EOA) that is in charge of scheduling (and cancelling) operations. +** *Executor:* An address (smart contract or EOA) that is in charge of executing operations once the timelock has expired. This role can be given to the zero address to allow anyone to execute operations. + +[[timelock-operation]] +==== Operation structure + +Operation executed by the xref:api:governance.adoc#TimelockController[`TimelockController`] can contain one or multiple subsequent calls. Depending on whether you need to multiple calls to be executed atomically, you can either use simple or batched operations. + +Both operations contain: + +* *Target*, the address of the smart contract that the timelock should operate on. +* *Value*, in wei, that should be sent with the transaction. Most of the time this will be 0. Ether can be deposited before-end or passed along when executing the transaction. +* *Data*, containing the encoded function selector and parameters of the call. This can be produced using a number of tools. For example, a maintenance operation granting role `ROLE` to `ACCOUNT` can be encoded using web3js as follows: + +```javascript +const data = timelock.contract.methods.grantRole(ROLE, ACCOUNT).encodeABI() +``` + +* *Predecessor*, that specifies a dependency between operations. This dependency is optional. Use `bytes32(0)` if the operation does not have any dependency. +* *Salt*, used to disambiguate two otherwise identical operations. This can be any random value. + +In the case of batched operations, `target`, `value` and `data` are specified as arrays, which must be of the same length. + +[[timelock-operation-lifecycle]] +==== Operation lifecycle + +Timelocked operations are identified by a unique id (their hash) and follow a specific lifecycle: + +`Unset` -> `Pending` -> `Pending` + `Ready` -> `Done` + +* By calling xref:api:governance.adoc#TimelockController-schedule-address-uint256-bytes-bytes32-bytes32-uint256-[`schedule`] (or xref:api:governance.adoc#TimelockController-scheduleBatch-address---uint256---bytes---bytes32-bytes32-uint256-[`scheduleBatch`]), a proposer moves the operation from the `Unset` to the `Pending` state. This starts a timer that must be longer than the minimum delay. The timer expires at a timestamp accessible through the xref:api:governance.adoc#TimelockController-getTimestamp-bytes32-[`getTimestamp`] method. +* Once the timer expires, the operation automatically gets the `Ready` state. At this point, it can be executed. +* By calling xref:api:governance.adoc#TimelockController-TimelockController-execute-address-uint256-bytes-bytes32-bytes32-[`execute`] (or xref:api:governance.adoc#TimelockController-executeBatch-address---uint256---bytes---bytes32-bytes32-[`executeBatch`]), an executor triggers the operation's underlying transactions and moves it to the `Done` state. If the operation has a predecessor, it has to be in the `Done` state for this transition to succeed. +* xref:api:governance.adoc#TimelockController-TimelockController-cancel-bytes32-[`cancel`] allows proposers to cancel any `Pending` operation. This resets the operation to the `Unset` state. It is thus possible for a proposer to re-schedule an operation that has been cancelled. In this case, the timer restarts when the operation is re-scheduled. + +Operations status can be queried using the functions: + +* xref:api:governance.adoc#TimelockController-isOperationPending-bytes32-[`isOperationPending(bytes32)`] +* xref:api:governance.adoc#TimelockController-isOperationReady-bytes32-[`isOperationReady(bytes32)`] +* xref:api:governance.adoc#TimelockController-isOperationDone-bytes32-[`isOperationDone(bytes32)`] + +[[timelock-roles]] +==== Roles + +[[timelock-admin]] +===== Admin + +The admins are in charge of managing proposers and executors. For the timelock to be self-governed, this role should only be given to the timelock itself. Upon deployment, the admin role can be granted to any address (in addition to the timelock itself). After further configuration and testing, this optional admin should renounce its role such that all further maintenance operations have to go through the timelock process. + +[[timelock-proposer]] +===== Proposer + +The proposers are in charge of scheduling (and cancelling) operations. This is a critical role, that should be given to governing entities. This could be an EOA, a multisig, or a DAO. + +WARNING: *Proposer fight:* Having multiple proposers, while providing redundancy in case one becomes unavailable, can be dangerous. As proposer have their say on all operations, they could cancel operations they disagree with, including operations to remove them for the proposers. + +This role is identified by the *PROPOSER_ROLE* value: `0xb09aa5aeb3702cfd50b6b62bc4532604938f21248a27a1d5ca736082b6819cc1` + +[[timelock-executor]] +===== Executor + +The executors are in charge of executing the operations scheduled by the proposers once the timelock expires. Logic dictates that multisig or DAO that are proposers should also be executors in order to guarantee operations that have been scheduled will eventually be executed. However, having additional executors can reduce the cost (the executing transaction does not require validation by the multisig or DAO that proposed it), while ensuring whoever is in charge of execution cannot trigger actions that have not been scheduled by the proposers. Alternatively, it is possible to allow _any_ address to execute a proposal once the timelock has expired by granting the executor role to the zero address. + +This role is identified by the *EXECUTOR_ROLE* value: `0xd8aa0f3194971a2a116679f7c2090f6939c8d4e01a2a8d7e41d55e5351469e63` + +WARNING: A live contract without at least one proposer and one executor is locked. Make sure these roles are filled by reliable entities before the deployer renounces its administrative rights in favour of the timelock contract itself. See the {AccessControl} documentation to learn more about role management. diff --git a/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol b/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol new file mode 100644 index 0000000..349d940 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/TimelockController.sol @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/TimelockController.sol) + +pragma solidity ^0.8.20; + +import {AccessControl} from "../access/AccessControl.sol"; +import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol"; +import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol"; +import {Address} from "../utils/Address.sol"; + +/** + * @dev Contract module which acts as a timelocked controller. When set as the + * owner of an `Ownable` smart contract, it enforces a timelock on all + * `onlyOwner` maintenance operations. This gives time for users of the + * controlled contract to exit before a potentially dangerous maintenance + * operation is applied. + * + * By default, this contract is self administered, meaning administration tasks + * have to go through the timelock process. The proposer (resp executor) role + * is in charge of proposing (resp executing) operations. A common use case is + * to position this {TimelockController} as the owner of a smart contract, with + * a multisig or a DAO as the sole proposer. + */ +contract TimelockController is AccessControl, ERC721Holder, ERC1155Holder { + bytes32 public constant PROPOSER_ROLE = keccak256("PROPOSER_ROLE"); + bytes32 public constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); + bytes32 public constant CANCELLER_ROLE = keccak256("CANCELLER_ROLE"); + uint256 internal constant _DONE_TIMESTAMP = uint256(1); + + mapping(bytes32 id => uint256) private _timestamps; + uint256 private _minDelay; + + enum OperationState { + Unset, + Waiting, + Ready, + Done + } + + /** + * @dev Mismatch between the parameters length for an operation call. + */ + error TimelockInvalidOperationLength(uint256 targets, uint256 payloads, uint256 values); + + /** + * @dev The schedule operation doesn't meet the minimum delay. + */ + error TimelockInsufficientDelay(uint256 delay, uint256 minDelay); + + /** + * @dev The current state of an operation is not as required. + * The `expectedStates` is a bitmap with the bits enabled for each OperationState enum position + * counting from right to left. + * + * See {_encodeStateBitmap}. + */ + error TimelockUnexpectedOperationState(bytes32 operationId, bytes32 expectedStates); + + /** + * @dev The predecessor to an operation not yet done. + */ + error TimelockUnexecutedPredecessor(bytes32 predecessorId); + + /** + * @dev The caller account is not authorized. + */ + error TimelockUnauthorizedCaller(address caller); + + /** + * @dev Emitted when a call is scheduled as part of operation `id`. + */ + event CallScheduled( + bytes32 indexed id, + uint256 indexed index, + address target, + uint256 value, + bytes data, + bytes32 predecessor, + uint256 delay + ); + + /** + * @dev Emitted when a call is performed as part of operation `id`. + */ + 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. + */ + event Cancelled(bytes32 indexed id); + + /** + * @dev Emitted when the minimum delay for future operations is modified. + */ + event MinDelayChange(uint256 oldDuration, uint256 newDuration); + + /** + * @dev Initializes the contract with the following parameters: + * + * - `minDelay`: initial minimum delay in seconds for operations + * - `proposers`: accounts to be granted proposer and canceller roles + * - `executors`: accounts to be granted executor role + * - `admin`: optional account to be granted admin role; disable with zero address + * + * IMPORTANT: The optional admin can aid with initial configuration of roles after deployment + * without being subject to delay, but this role should be subsequently renounced in favor of + * administration through timelocked proposals. Previous versions of this contract would assign + * this admin to the deployer automatically and should be renounced as well. + */ + constructor(uint256 minDelay, address[] memory proposers, address[] memory executors, address admin) { + // self administration + _grantRole(DEFAULT_ADMIN_ROLE, address(this)); + + // optional admin + if (admin != address(0)) { + _grantRole(DEFAULT_ADMIN_ROLE, admin); + } + + // register proposers and cancellers + for (uint256 i = 0; i < proposers.length; ++i) { + _grantRole(PROPOSER_ROLE, proposers[i]); + _grantRole(CANCELLER_ROLE, proposers[i]); + } + + // register executors + for (uint256 i = 0; i < executors.length; ++i) { + _grantRole(EXECUTOR_ROLE, executors[i]); + } + + _minDelay = minDelay; + emit MinDelayChange(0, minDelay); + } + + /** + * @dev Modifier to make a function callable only by a certain role. In + * addition to checking the sender's role, `address(0)` 's role is also + * considered. Granting a role to `address(0)` is equivalent to enabling + * this role for everyone. + */ + modifier onlyRoleOrOpenRole(bytes32 role) { + if (!hasRole(role, address(0))) { + _checkRole(role, _msgSender()); + } + _; + } + + /** + * @dev Contract might receive/hold ETH as part of the maintenance process. + */ + receive() external payable {} + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(AccessControl, ERC1155Holder) returns (bool) { + return super.supportsInterface(interfaceId); + } + + /** + * @dev Returns whether an id corresponds to a registered operation. This + * includes both Waiting, Ready, and Done operations. + */ + function isOperation(bytes32 id) public view returns (bool) { + return getOperationState(id) != OperationState.Unset; + } + + /** + * @dev Returns whether an operation is pending or not. Note that a "pending" operation may also be "ready". + */ + function isOperationPending(bytes32 id) public view returns (bool) { + OperationState state = getOperationState(id); + return state == OperationState.Waiting || state == OperationState.Ready; + } + + /** + * @dev Returns whether an operation is ready for execution. Note that a "ready" operation is also "pending". + */ + function isOperationReady(bytes32 id) public view returns (bool) { + return getOperationState(id) == OperationState.Ready; + } + + /** + * @dev Returns whether an operation is done or not. + */ + function isOperationDone(bytes32 id) public view returns (bool) { + return getOperationState(id) == OperationState.Done; + } + + /** + * @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) { + return _timestamps[id]; + } + + /** + * @dev Returns operation state. + */ + function getOperationState(bytes32 id) public view virtual returns (OperationState) { + uint256 timestamp = getTimestamp(id); + if (timestamp == 0) { + return OperationState.Unset; + } else if (timestamp == _DONE_TIMESTAMP) { + return OperationState.Done; + } else if (timestamp > block.timestamp) { + return OperationState.Waiting; + } else { + return OperationState.Ready; + } + } + + /** + * @dev Returns the minimum delay in seconds for an operation to become valid. + * + * This value can be changed by executing an operation that calls `updateDelay`. + */ + function getMinDelay() public view virtual returns (uint256) { + return _minDelay; + } + + /** + * @dev Returns the identifier of an operation containing a single + * transaction. + */ + function hashOperation( + address target, + uint256 value, + bytes calldata data, + bytes32 predecessor, + bytes32 salt + ) public pure virtual returns (bytes32) { + return keccak256(abi.encode(target, value, data, predecessor, salt)); + } + + /** + * @dev Returns the identifier of an operation containing a batch of + * transactions. + */ + function hashOperationBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt + ) public pure virtual returns (bytes32) { + return keccak256(abi.encode(targets, values, payloads, predecessor, salt)); + } + + /** + * @dev Schedule an operation containing a single transaction. + * + * Emits {CallSalt} if salt is nonzero, and {CallScheduled}. + * + * Requirements: + * + * - the caller must have the 'proposer' role. + */ + function schedule( + address target, + uint256 value, + bytes calldata data, + bytes32 predecessor, + bytes32 salt, + uint256 delay + ) public virtual onlyRole(PROPOSER_ROLE) { + 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 {CallSalt} if salt is nonzero, and one {CallScheduled} event per transaction in the batch. + * + * Requirements: + * + * - the caller must have the 'proposer' role. + */ + function scheduleBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt, + uint256 delay + ) public virtual onlyRole(PROPOSER_ROLE) { + if (targets.length != values.length || targets.length != payloads.length) { + revert TimelockInvalidOperationLength(targets.length, payloads.length, values.length); + } + + bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + _schedule(id, delay); + 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); + } + } + + /** + * @dev Schedule an operation that is to become valid after a given delay. + */ + function _schedule(bytes32 id, uint256 delay) private { + if (isOperation(id)) { + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Unset)); + } + uint256 minDelay = getMinDelay(); + if (delay < minDelay) { + revert TimelockInsufficientDelay(delay, minDelay); + } + _timestamps[id] = block.timestamp + delay; + } + + /** + * @dev Cancel an operation. + * + * Requirements: + * + * - the caller must have the 'canceller' role. + */ + function cancel(bytes32 id) public virtual onlyRole(CANCELLER_ROLE) { + if (!isOperationPending(id)) { + revert TimelockUnexpectedOperationState( + id, + _encodeStateBitmap(OperationState.Waiting) | _encodeStateBitmap(OperationState.Ready) + ); + } + delete _timestamps[id]; + + emit Cancelled(id); + } + + /** + * @dev Execute an (ready) operation containing a single transaction. + * + * Emits a {CallExecuted} event. + * + * Requirements: + * + * - the caller must have the 'executor' role. + */ + // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, + // thus any modifications to the operation during reentrancy should be caught. + // slither-disable-next-line reentrancy-eth + function execute( + address target, + uint256 value, + bytes calldata payload, + bytes32 predecessor, + bytes32 salt + ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { + bytes32 id = hashOperation(target, value, payload, predecessor, salt); + + _beforeCall(id, predecessor); + _execute(target, value, payload); + emit CallExecuted(id, 0, target, value, payload); + _afterCall(id); + } + + /** + * @dev Execute an (ready) operation containing a batch of transactions. + * + * Emits one {CallExecuted} event per transaction in the batch. + * + * Requirements: + * + * - the caller must have the 'executor' role. + */ + // This function can reenter, but it doesn't pose a risk because _afterCall checks that the proposal is pending, + // thus any modifications to the operation during reentrancy should be caught. + // slither-disable-next-line reentrancy-eth + function executeBatch( + address[] calldata targets, + uint256[] calldata values, + bytes[] calldata payloads, + bytes32 predecessor, + bytes32 salt + ) public payable virtual onlyRoleOrOpenRole(EXECUTOR_ROLE) { + if (targets.length != values.length || targets.length != payloads.length) { + revert TimelockInvalidOperationLength(targets.length, payloads.length, values.length); + } + + bytes32 id = hashOperationBatch(targets, values, payloads, predecessor, salt); + + _beforeCall(id, predecessor); + for (uint256 i = 0; i < targets.length; ++i) { + address target = targets[i]; + uint256 value = values[i]; + bytes calldata payload = payloads[i]; + _execute(target, value, payload); + emit CallExecuted(id, i, target, value, payload); + } + _afterCall(id); + } + + /** + * @dev Execute an operation's call. + */ + function _execute(address target, uint256 value, bytes calldata data) internal virtual { + (bool success, bytes memory returndata) = target.call{value: value}(data); + Address.verifyCallResult(success, returndata); + } + + /** + * @dev Checks before execution of an operation's calls. + */ + function _beforeCall(bytes32 id, bytes32 predecessor) private view { + if (!isOperationReady(id)) { + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready)); + } + if (predecessor != bytes32(0) && !isOperationDone(predecessor)) { + revert TimelockUnexecutedPredecessor(predecessor); + } + } + + /** + * @dev Checks after execution of an operation's calls. + */ + function _afterCall(bytes32 id) private { + if (!isOperationReady(id)) { + revert TimelockUnexpectedOperationState(id, _encodeStateBitmap(OperationState.Ready)); + } + _timestamps[id] = _DONE_TIMESTAMP; + } + + /** + * @dev Changes the minimum timelock duration for future operations. + * + * Emits a {MinDelayChange} event. + * + * Requirements: + * + * - the caller must be the timelock itself. This can only be achieved by scheduling and later executing + * an operation where the timelock is the target and the data is the ABI-encoded call to this function. + */ + function updateDelay(uint256 newDelay) external virtual { + address sender = _msgSender(); + if (sender != address(this)) { + revert TimelockUnauthorizedCaller(sender); + } + emit MinDelayChange(_minDelay, newDelay); + _minDelay = newDelay; + } + + /** + * @dev Encodes a `OperationState` into a `bytes32` representation where each bit enabled corresponds to + * the underlying position in the `OperationState` enum. For example: + * + * 0x000...1000 + * ^^^^^^----- ... + * ^---- Done + * ^--- Ready + * ^-- Waiting + * ^- Unset + */ + function _encodeStateBitmap(OperationState operationState) internal pure returns (bytes32) { + return bytes32(1 << uint8(operationState)); + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol new file mode 100644 index 0000000..ac9c22a --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorCountingSimple.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} for simple, 3 options, vote counting. + */ +abstract contract GovernorCountingSimple is Governor { + /** + * @dev Supported vote types. Matches Governor Bravo ordering. + */ + enum VoteType { + Against, + For, + Abstain + } + + struct ProposalVote { + uint256 againstVotes; + uint256 forVotes; + uint256 abstainVotes; + mapping(address voter => bool) hasVoted; + } + + mapping(uint256 proposalId => ProposalVote) private _proposalVotes; + + /** + * @dev See {IGovernor-COUNTING_MODE}. + */ + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) { + return "support=bravo&quorum=for,abstain"; + } + + /** + * @dev See {IGovernor-hasVoted}. + */ + function hasVoted(uint256 proposalId, address account) public view virtual override returns (bool) { + return _proposalVotes[proposalId].hasVoted[account]; + } + + /** + * @dev Accessor to the internal vote counts. + */ + function proposalVotes( + uint256 proposalId + ) public view virtual returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + return (proposalVote.againstVotes, proposalVote.forVotes, proposalVote.abstainVotes); + } + + /** + * @dev See {Governor-_quorumReached}. + */ + function _quorumReached(uint256 proposalId) internal view virtual override returns (bool) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + return quorum(proposalSnapshot(proposalId)) <= proposalVote.forVotes + proposalVote.abstainVotes; + } + + /** + * @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) { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + return proposalVote.forVotes > proposalVote.againstVotes; + } + + /** + * @dev See {Governor-_countVote}. In this module, the support follows the `VoteType` enum (from Governor Bravo). + */ + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory // params + ) internal virtual override { + ProposalVote storage proposalVote = _proposalVotes[proposalId]; + + if (proposalVote.hasVoted[account]) { + revert GovernorAlreadyCastVote(account); + } + proposalVote.hasVoted[account] = true; + + if (support == uint8(VoteType.Against)) { + proposalVote.againstVotes += weight; + } else if (support == uint8(VoteType.For)) { + proposalVote.forVotes += weight; + } else if (support == uint8(VoteType.Abstain)) { + proposalVote.abstainVotes += weight; + } else { + revert GovernorInvalidVoteType(); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol new file mode 100644 index 0000000..ff80af6 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorPreventLateQuorum.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; +import {Math} from "../../utils/math/Math.sol"; + +/** + * @dev A module that ensures there is a minimum voting period after quorum is reached. This prevents a large voter from + * swaying a vote and triggering quorum at the last minute, by ensuring there is always time for other voters to react + * 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 specified time has passed (the "vote extension" parameter). This parameter can be set through a governance + * proposal. + */ +abstract contract GovernorPreventLateQuorum is Governor { + uint48 private _voteExtension; + + mapping(uint256 proposalId => uint48) 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); + + /// @dev Emitted when the {lateQuorumVoteExtension} parameter is changed. + event LateQuorumVoteExtensionSet(uint64 oldVoteExtension, uint64 newVoteExtension); + + /** + * @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(uint48 initialVoteExtension) { + _setLateQuorumVoteExtension(initialVoteExtension); + } + + /** + * @dev Returns the proposal deadline, which may have been extended beyond that set at proposal creation, if the + * 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]); + } + + /** + * @dev Casts a vote and detects if it caused quorum to be reached, potentially extending the voting period. See + * {Governor-_castVote}. + * + * May emit a {ProposalExtended} event. + */ + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal virtual override returns (uint256) { + uint256 result = super._castVote(proposalId, account, support, reason, params); + + if (_extendedDeadlines[proposalId] == 0 && _quorumReached(proposalId)) { + uint48 extendedDeadline = clock() + lateQuorumVoteExtension(); + + if (extendedDeadline > proposalDeadline(proposalId)) { + emit ProposalExtended(proposalId, extendedDeadline); + } + + _extendedDeadlines[proposalId] = extendedDeadline; + } + + return result; + } + + /** + * @dev Returns the current value of the vote extension parameter: the number of blocks that are required to pass + * from the time a proposal reaches quorum until its voting period ends. + */ + function lateQuorumVoteExtension() public view virtual returns (uint48) { + return _voteExtension; + } + + /** + * @dev Changes the {lateQuorumVoteExtension}. This operation can only be performed by the governance executor, + * generally through a governance proposal. + * + * Emits a {LateQuorumVoteExtensionSet} event. + */ + function setLateQuorumVoteExtension(uint48 newVoteExtension) public virtual onlyGovernance { + _setLateQuorumVoteExtension(newVoteExtension); + } + + /** + * @dev Changes the {lateQuorumVoteExtension}. This is an internal function that can be exposed in a public function + * like {setLateQuorumVoteExtension} if another access control mechanism is needed. + * + * Emits a {LateQuorumVoteExtensionSet} event. + */ + function _setLateQuorumVoteExtension(uint48 newVoteExtension) internal virtual { + emit LateQuorumVoteExtensionSet(_voteExtension, newVoteExtension); + _voteExtension = newVoteExtension; + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol new file mode 100644 index 0000000..7347ee2 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorSettings.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} for settings updatable through governance. + */ +abstract contract GovernorSettings is Governor { + // amount of token + uint256 private _proposalThreshold; + // timepoint: limited to uint48 in core (same as clock() type) + uint48 private _votingDelay; + // duration: limited to uint32 in core + uint32 private _votingPeriod; + + event VotingDelaySet(uint256 oldVotingDelay, uint256 newVotingDelay); + event VotingPeriodSet(uint256 oldVotingPeriod, uint256 newVotingPeriod); + event ProposalThresholdSet(uint256 oldProposalThreshold, uint256 newProposalThreshold); + + /** + * @dev Initialize the governance parameters. + */ + constructor(uint48 initialVotingDelay, uint32 initialVotingPeriod, uint256 initialProposalThreshold) { + _setVotingDelay(initialVotingDelay); + _setVotingPeriod(initialVotingPeriod); + _setProposalThreshold(initialProposalThreshold); + } + + /** + * @dev See {IGovernor-votingDelay}. + */ + function votingDelay() public view virtual override returns (uint256) { + return _votingDelay; + } + + /** + * @dev See {IGovernor-votingPeriod}. + */ + function votingPeriod() public view virtual override returns (uint256) { + return _votingPeriod; + } + + /** + * @dev See {Governor-proposalThreshold}. + */ + function proposalThreshold() public view virtual override returns (uint256) { + return _proposalThreshold; + } + + /** + * @dev Update the voting delay. This operation can only be performed through a governance proposal. + * + * Emits a {VotingDelaySet} event. + */ + function setVotingDelay(uint48 newVotingDelay) public virtual onlyGovernance { + _setVotingDelay(newVotingDelay); + } + + /** + * @dev Update the voting period. This operation can only be performed through a governance proposal. + * + * Emits a {VotingPeriodSet} event. + */ + function setVotingPeriod(uint32 newVotingPeriod) public virtual onlyGovernance { + _setVotingPeriod(newVotingPeriod); + } + + /** + * @dev Update the proposal threshold. This operation can only be performed through a governance proposal. + * + * Emits a {ProposalThresholdSet} event. + */ + function setProposalThreshold(uint256 newProposalThreshold) public virtual onlyGovernance { + _setProposalThreshold(newProposalThreshold); + } + + /** + * @dev Internal setter for the voting delay. + * + * Emits a {VotingDelaySet} event. + */ + function _setVotingDelay(uint48 newVotingDelay) internal virtual { + emit VotingDelaySet(_votingDelay, newVotingDelay); + _votingDelay = newVotingDelay; + } + + /** + * @dev Internal setter for the voting period. + * + * Emits a {VotingPeriodSet} event. + */ + function _setVotingPeriod(uint32 newVotingPeriod) internal virtual { + if (newVotingPeriod == 0) { + revert GovernorInvalidVotingPeriod(0); + } + emit VotingPeriodSet(_votingPeriod, newVotingPeriod); + _votingPeriod = newVotingPeriod; + } + + /** + * @dev Internal setter for the proposal threshold. + * + * Emits a {ProposalThresholdSet} event. + */ + function _setProposalThreshold(uint256 newProposalThreshold) internal virtual { + emit ProposalThresholdSet(_proposalThreshold, newProposalThreshold); + _proposalThreshold = newProposalThreshold; + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol new file mode 100644 index 0000000..2547b55 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorStorage.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; + +/** + * @dev Extension of {Governor} that implements storage of proposal details. This modules also provides primitives for + * the enumerability of proposals. + * + * Use cases for this module include: + * - UIs that explore the proposal state without relying on event indexing. + * - Using only the proposalId as an argument in the {Governor-queue} and {Governor-execute} functions for L2 chains + * where storage is cheap compared to calldata. + */ +abstract contract GovernorStorage is Governor { + struct ProposalDetails { + address[] targets; + uint256[] values; + bytes[] calldatas; + bytes32 descriptionHash; + } + + uint256[] private _proposalIds; + mapping(uint256 proposalId => ProposalDetails) private _proposalDetails; + + /** + * @dev Hook into the proposing mechanism + */ + function _propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description, + address proposer + ) internal virtual override returns (uint256) { + uint256 proposalId = super._propose(targets, values, calldatas, description, proposer); + + // store + _proposalIds.push(proposalId); + _proposalDetails[proposalId] = ProposalDetails({ + targets: targets, + values: values, + calldatas: calldatas, + descriptionHash: keccak256(bytes(description)) + }); + + return proposalId; + } + + /** + * @dev Version of {IGovernorTimelock-queue} with only `proposalId` as an argument. + */ + function queue(uint256 proposalId) public virtual { + // here, using storage is more efficient than memory + ProposalDetails storage details = _proposalDetails[proposalId]; + queue(details.targets, details.values, details.calldatas, details.descriptionHash); + } + + /** + * @dev Version of {IGovernor-execute} with only `proposalId` as an argument. + */ + function execute(uint256 proposalId) public payable virtual { + // here, using storage is more efficient than memory + ProposalDetails storage details = _proposalDetails[proposalId]; + execute(details.targets, details.values, details.calldatas, details.descriptionHash); + } + + /** + * @dev ProposalId version of {IGovernor-cancel}. + */ + function cancel(uint256 proposalId) public virtual { + // here, using storage is more efficient than memory + ProposalDetails storage details = _proposalDetails[proposalId]; + cancel(details.targets, details.values, details.calldatas, details.descriptionHash); + } + + /** + * @dev Returns the number of stored proposals. + */ + function proposalCount() public view virtual returns (uint256) { + return _proposalIds.length; + } + + /** + * @dev Returns the details of a proposalId. Reverts if `proposalId` is not a known proposal. + */ + function proposalDetails( + uint256 proposalId + ) public view virtual returns (address[] memory, uint256[] memory, bytes[] memory, bytes32) { + // here, using memory is more efficient than storage + ProposalDetails memory details = _proposalDetails[proposalId]; + if (details.descriptionHash == 0) { + revert GovernorNonexistentProposal(proposalId); + } + return (details.targets, details.values, details.calldatas, details.descriptionHash); + } + + /** + * @dev Returns the details (including the proposalId) of a proposal given its sequential index. + */ + function proposalDetailsAt( + uint256 index + ) public view virtual returns (uint256, address[] memory, uint256[] memory, bytes[] memory, bytes32) { + uint256 proposalId = _proposalIds[index]; + ( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) = proposalDetails(proposalId); + return (proposalId, targets, values, calldatas, descriptionHash); + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol new file mode 100644 index 0000000..a2373a4 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sol @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorTimelockAccess.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; +import {AuthorityUtils} from "../../access/manager/AuthorityUtils.sol"; +import {IAccessManager} from "../../access/manager/IAccessManager.sol"; +import {Address} from "../../utils/Address.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Time} from "../../utils/types/Time.sol"; + +/** + * @dev This module connects a {Governor} instance to an {AccessManager} instance, allowing the governor to make calls + * that are delay-restricted by the manager using the normal {queue} workflow. An optional base delay is applied to + * operations that are not delayed externally by the manager. Execution of a proposal will be delayed as much as + * necessary to meet the required delays of all of its operations. + * + * This extension allows the governor to hold and use its own assets and permissions, unlike {GovernorTimelockControl} + * and {GovernorTimelockCompound}, where the timelock is a separate contract that must be the one to hold assets and + * permissions. Operations that are delay-restricted by the manager, however, will be executed through the + * {AccessManager-execute} function. + * + * ==== Security Considerations + * + * Some operations may be cancelable in the `AccessManager` by the admin or a set of guardians, depending on the + * restricted function being invoked. Since proposals are atomic, the cancellation by a guardian of a single operation + * in a proposal will cause all of the proposal to become unable to execute. Consider proposing cancellable operations + * separately. + * + * By default, function calls will be routed through the associated `AccessManager` whenever it claims the target + * function to be restricted by it. However, admins may configure the manager to make that claim for functions that a + * governor would want to call directly (e.g., token transfers) in an attempt to deny it access to those functions. To + * mitigate this attack vector, the governor is able to ignore the restrictions claimed by the `AccessManager` using + * {setAccessManagerIgnored}. While permanent denial of service is mitigated, temporary DoS may still be technically + * possible. All of the governor's own functions (e.g., {setBaseDelaySeconds}) ignore the `AccessManager` by default. + */ +abstract contract GovernorTimelockAccess is Governor { + // An execution plan is produced at the moment a proposal is created, in order to fix at that point the exact + // execution semantics of the proposal, namely whether a call will go through {AccessManager-execute}. + struct ExecutionPlan { + uint16 length; + uint32 delay; + // We use mappings instead of arrays because it allows us to pack values in storage more tightly without + // storing the length redundantly. + // We pack 8 operations' data in each bucket. Each uint32 value is set to 1 upon proposal creation if it has + // to be scheduled and executed through the manager. Upon queuing, the value is set to nonce + 2, where the + // nonce is received from the manager when scheduling the operation. + mapping(uint256 operationBucket => uint32[8]) managerData; + } + + // The meaning of the "toggle" set to true depends on the target contract. + // If target == address(this), the manager is ignored by default, and a true toggle means it won't be ignored. + // For all other target contracts, the manager is used by default, and a true toggle means it will be ignored. + mapping(address target => mapping(bytes4 selector => bool)) private _ignoreToggle; + + mapping(uint256 proposalId => ExecutionPlan) private _executionPlan; + + uint32 private _baseDelay; + + IAccessManager private immutable _manager; + + error GovernorUnmetDelay(uint256 proposalId, uint256 neededTimestamp); + error GovernorMismatchedNonce(uint256 proposalId, uint256 expectedNonce, uint256 actualNonce); + error GovernorLockedIgnore(); + + event BaseDelaySet(uint32 oldBaseDelaySeconds, uint32 newBaseDelaySeconds); + event AccessManagerIgnoredSet(address target, bytes4 selector, bool ignored); + + /** + * @dev Initialize the governor with an {AccessManager} and initial base delay. + */ + constructor(address manager, uint32 initialBaseDelay) { + _manager = IAccessManager(manager); + _setBaseDelaySeconds(initialBaseDelay); + } + + /** + * @dev Returns the {AccessManager} instance associated to this governor. + */ + function accessManager() public view virtual returns (IAccessManager) { + return _manager; + } + + /** + * @dev Base delay that will be applied to all function calls. Some may be further delayed by their associated + * `AccessManager` authority; in this case the final delay will be the maximum of the base delay and the one + * demanded by the authority. + * + * NOTE: Execution delays are processed by the `AccessManager` contracts, and according to that contract are + * expressed in seconds. Therefore, the base delay is also in seconds, regardless of the governor's clock mode. + */ + function baseDelaySeconds() public view virtual returns (uint32) { + return _baseDelay; + } + + /** + * @dev Change the value of {baseDelaySeconds}. This operation can only be invoked through a governance proposal. + */ + function setBaseDelaySeconds(uint32 newBaseDelay) public virtual onlyGovernance { + _setBaseDelaySeconds(newBaseDelay); + } + + /** + * @dev Change the value of {baseDelaySeconds}. Internal function without access control. + */ + function _setBaseDelaySeconds(uint32 newBaseDelay) internal virtual { + emit BaseDelaySet(_baseDelay, newBaseDelay); + _baseDelay = newBaseDelay; + } + + /** + * @dev Check if restrictions from the associated {AccessManager} are ignored for a target function. Returns true + * when the target function will be invoked directly regardless of `AccessManager` settings for the function. + * See {setAccessManagerIgnored} and Security Considerations above. + */ + function isAccessManagerIgnored(address target, bytes4 selector) public view virtual returns (bool) { + bool isGovernor = target == address(this); + return _ignoreToggle[target][selector] != isGovernor; // equivalent to: isGovernor ? !toggle : toggle + } + + /** + * @dev Configure whether restrictions from the associated {AccessManager} are ignored for a target function. + * See Security Considerations above. + */ + function setAccessManagerIgnored( + address target, + bytes4[] calldata selectors, + bool ignored + ) public virtual onlyGovernance { + for (uint256 i = 0; i < selectors.length; ++i) { + _setAccessManagerIgnored(target, selectors[i], ignored); + } + } + + /** + * @dev Internal version of {setAccessManagerIgnored} without access restriction. + */ + function _setAccessManagerIgnored(address target, bytes4 selector, bool ignored) internal virtual { + bool isGovernor = target == address(this); + if (isGovernor && selector == this.setAccessManagerIgnored.selector) { + revert GovernorLockedIgnore(); + } + _ignoreToggle[target][selector] = ignored != isGovernor; // equivalent to: isGovernor ? !ignored : ignored + emit AccessManagerIgnoredSet(target, selector, ignored); + } + + /** + * @dev Public accessor to check the execution plan, including the number of seconds that the proposal will be + * delayed since queuing, an array indicating which of the proposal actions will be executed indirectly through + * the associated {AccessManager}, and another indicating which will be scheduled in {queue}. Note that + * those that must be scheduled are cancellable by `AccessManager` guardians. + */ + function proposalExecutionPlan( + uint256 proposalId + ) public view returns (uint32 delay, bool[] memory indirect, bool[] memory withDelay) { + ExecutionPlan storage plan = _executionPlan[proposalId]; + + uint32 length = plan.length; + delay = plan.delay; + indirect = new bool[](length); + withDelay = new bool[](length); + for (uint256 i = 0; i < length; ++i) { + (indirect[i], withDelay[i], ) = _getManagerData(plan, i); + } + + return (delay, indirect, withDelay); + } + + /** + * @dev See {IGovernor-proposalNeedsQueuing}. + */ + function proposalNeedsQueuing(uint256 proposalId) public view virtual override returns (bool) { + return _executionPlan[proposalId].delay > 0; + } + + /** + * @dev See {IGovernor-propose} + */ + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public virtual override returns (uint256) { + uint256 proposalId = super.propose(targets, values, calldatas, description); + + uint32 neededDelay = baseDelaySeconds(); + + ExecutionPlan storage plan = _executionPlan[proposalId]; + plan.length = SafeCast.toUint16(targets.length); + + for (uint256 i = 0; i < targets.length; ++i) { + if (calldatas[i].length < 4) { + continue; + } + address target = targets[i]; + bytes4 selector = bytes4(calldatas[i]); + (bool immediate, uint32 delay) = AuthorityUtils.canCallWithDelay( + address(_manager), + address(this), + target, + selector + ); + if ((immediate || delay > 0) && !isAccessManagerIgnored(target, selector)) { + _setManagerData(plan, i, !immediate, 0); + // downcast is safe because both arguments are uint32 + neededDelay = uint32(Math.max(delay, neededDelay)); + } + } + + plan.delay = neededDelay; + + return proposalId; + } + + /** + * @dev Mechanism to queue a proposal, potentially scheduling some of its operations in the AccessManager. + * + * NOTE: The execution delay is chosen based on the delay information retrieved in {propose}. This value may be + * off if the delay was updated since proposal creation. In this case, the proposal needs to be recreated. + */ + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory /* values */, + bytes[] memory calldatas, + bytes32 /* descriptionHash */ + ) internal virtual override returns (uint48) { + ExecutionPlan storage plan = _executionPlan[proposalId]; + uint48 etaSeconds = Time.timestamp() + plan.delay; + + for (uint256 i = 0; i < targets.length; ++i) { + (, bool withDelay, ) = _getManagerData(plan, i); + if (withDelay) { + (, uint32 nonce) = _manager.schedule(targets[i], calldatas[i], etaSeconds); + _setManagerData(plan, i, true, nonce); + } + } + + return etaSeconds; + } + + /** + * @dev Mechanism to execute a proposal, potentially going through {AccessManager-execute} for delayed operations. + */ + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /* descriptionHash */ + ) internal virtual override { + uint48 etaSeconds = SafeCast.toUint48(proposalEta(proposalId)); + if (block.timestamp < etaSeconds) { + revert GovernorUnmetDelay(proposalId, etaSeconds); + } + + ExecutionPlan storage plan = _executionPlan[proposalId]; + + for (uint256 i = 0; i < targets.length; ++i) { + (bool controlled, bool withDelay, uint32 nonce) = _getManagerData(plan, i); + if (controlled) { + uint32 executedNonce = _manager.execute{value: values[i]}(targets[i], calldatas[i]); + if (withDelay && executedNonce != nonce) { + revert GovernorMismatchedNonce(proposalId, nonce, executedNonce); + } + } else { + (bool success, bytes memory returndata) = targets[i].call{value: values[i]}(calldatas[i]); + Address.verifyCallResult(success, returndata); + } + } + } + + /** + * @dev See {IGovernor-_cancel} + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + uint48 etaSeconds = SafeCast.toUint48(proposalEta(proposalId)); + + ExecutionPlan storage plan = _executionPlan[proposalId]; + + // If the proposal has been scheduled it will have an ETA and we may have to externally cancel + if (etaSeconds != 0) { + for (uint256 i = 0; i < targets.length; ++i) { + (, bool withDelay, uint32 nonce) = _getManagerData(plan, i); + // Only attempt to cancel if the execution plan included a delay + if (withDelay) { + bytes32 operationId = _manager.hashOperation(address(this), targets[i], calldatas[i]); + // Check first if the current operation nonce is the one that we observed previously. It could + // already have been cancelled and rescheduled. We don't want to cancel unless it is exactly the + // instance that we previously scheduled. + if (nonce == _manager.getNonce(operationId)) { + // It is important that all calls have an opportunity to be cancelled. We chose to ignore + // potential failures of some of the cancel operations to give the other operations a chance to + // be properly cancelled. In particular cancel might fail if the operation was already cancelled + // by guardians previously. We don't match on the revert reason to avoid encoding assumptions + // about specific errors. + try _manager.cancel(address(this), targets[i], calldatas[i]) {} catch {} + } + } + } + } + + return proposalId; + } + + /** + * @dev Returns whether the operation at an index is delayed by the manager, and its scheduling nonce once queued. + */ + function _getManagerData( + ExecutionPlan storage plan, + uint256 index + ) private view returns (bool controlled, bool withDelay, uint32 nonce) { + (uint256 bucket, uint256 subindex) = _getManagerDataIndices(index); + uint32 value = plan.managerData[bucket][subindex]; + unchecked { + return (value > 0, value > 1, value > 1 ? value - 2 : 0); + } + } + + /** + * @dev Marks an operation at an index as permissioned by the manager, potentially delayed, and + * when delayed sets its scheduling nonce. + */ + function _setManagerData(ExecutionPlan storage plan, uint256 index, bool withDelay, uint32 nonce) private { + (uint256 bucket, uint256 subindex) = _getManagerDataIndices(index); + plan.managerData[bucket][subindex] = withDelay ? nonce + 2 : 1; + } + + /** + * @dev Returns bucket and subindex for reading manager data from the packed array mapping. + */ + function _getManagerDataIndices(uint256 index) private pure returns (uint256 bucket, uint256 subindex) { + bucket = index >> 3; // index / 8 + subindex = index & 7; // index % 8 + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol new file mode 100644 index 0000000..117df01 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sol @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorTimelockCompound.sol) + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../Governor.sol"; +import {ICompoundTimelock} from "../../vendor/compound/ICompoundTimelock.sol"; +import {Address} from "../../utils/Address.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; + +/** + * @dev Extension of {Governor} that binds the execution process to a Compound Timelock. This adds a delay, enforced by + * the external timelock to all successful proposal (in addition to the voting duration). The {Governor} needs to be + * the admin of the timelock for any operation to be performed. A public, unrestricted, + * {GovernorTimelockCompound-__acceptAdmin} is available to accept ownership of the timelock. + * + * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * inaccessible. + */ +abstract contract GovernorTimelockCompound is Governor { + ICompoundTimelock private _timelock; + + /** + * @dev Emitted when the timelock controller used for proposal execution is modified. + */ + event TimelockChange(address oldTimelock, address newTimelock); + + /** + * @dev Set the timelock. + */ + constructor(ICompoundTimelock timelockAddress) { + _updateTimelock(timelockAddress); + } + + /** + * @dev Overridden version of the {Governor-state} function with added support for the `Expired` state. + */ + function state(uint256 proposalId) public view virtual override returns (ProposalState) { + ProposalState currentState = super.state(proposalId); + + return + (currentState == ProposalState.Queued && + block.timestamp >= proposalEta(proposalId) + _timelock.GRACE_PERIOD()) + ? ProposalState.Expired + : currentState; + } + + /** + * @dev Public accessor to check the address of the timelock + */ + function timelock() public view virtual returns (address) { + return address(_timelock); + } + + /** + * @dev See {IGovernor-proposalNeedsQueuing}. + */ + function proposalNeedsQueuing(uint256) public view virtual override returns (bool) { + return true; + } + + /** + * @dev Function to queue a proposal to the timelock. + */ + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual override returns (uint48) { + uint48 etaSeconds = SafeCast.toUint48(block.timestamp + _timelock.delay()); + + for (uint256 i = 0; i < targets.length; ++i) { + if ( + _timelock.queuedTransactions(keccak256(abi.encode(targets[i], values[i], "", calldatas[i], etaSeconds))) + ) { + revert GovernorAlreadyQueuedProposal(proposalId); + } + _timelock.queueTransaction(targets[i], values[i], "", calldatas[i], etaSeconds); + } + + return etaSeconds; + } + + /** + * @dev Overridden version of the {Governor-_executeOperations} function that run the already queued proposal + * through the timelock. + */ + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 /*descriptionHash*/ + ) internal virtual override { + uint256 etaSeconds = proposalEta(proposalId); + if (etaSeconds == 0) { + revert GovernorNotQueuedProposal(proposalId); + } + Address.sendValue(payable(_timelock), msg.value); + for (uint256 i = 0; i < targets.length; ++i) { + _timelock.executeTransaction(targets[i], values[i], "", calldatas[i], etaSeconds); + } + } + + /** + * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it has already + * been queued. + */ + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + uint256 etaSeconds = proposalEta(proposalId); + if (etaSeconds > 0) { + // do external call later + for (uint256 i = 0; i < targets.length; ++i) { + _timelock.cancelTransaction(targets[i], values[i], "", calldatas[i], etaSeconds); + } + } + + return proposalId; + } + + /** + * @dev Address through which the governor executes action. In this case, the timelock. + */ + function _executor() internal view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Accept admin right over the timelock. + */ + // solhint-disable-next-line private-vars-leading-underscore + function __acceptAdmin() public { + _timelock.acceptAdmin(); + } + + /** + * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates + * must be proposed, scheduled, and executed through governance proposals. + * + * For security reasons, the timelock must be handed over to another admin before setting up a new one. The two + * operations (hand over the timelock) and do the update can be batched in a single proposal. + * + * Note that if the timelock admin has been handed over in a previous operation, we refuse updates made through the + * timelock if admin of the timelock has already been accepted and the operation is executed outside the scope of + * governance. + + * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. + */ + function updateTimelock(ICompoundTimelock newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(ICompoundTimelock newTimelock) private { + emit TimelockChange(address(_timelock), address(newTimelock)); + _timelock = newTimelock; + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol new file mode 100644 index 0000000..53503cc --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sol @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorTimelockControl.sol) + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../Governor.sol"; +import {TimelockController} from "../TimelockController.sol"; +import {IERC165} from "../../interfaces/IERC165.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; + +/** + * @dev Extension of {Governor} that binds the execution process to an instance of {TimelockController}. This adds a + * delay, enforced by the {TimelockController} to all successful proposal (in addition to the voting duration). The + * {Governor} needs the proposer (and ideally the executor) roles for the {Governor} to work properly. + * + * Using this model means the proposal will be operated by the {TimelockController} and not by the {Governor}. Thus, + * the assets and permissions must be attached to the {TimelockController}. Any asset sent to the {Governor} will be + * inaccessible from a proposal, unless executed via {Governor-relay}. + * + * WARNING: Setting up the TimelockController to have additional proposers or cancellers besides the governor is very + * risky, as it grants them the ability to: 1) execute operations as the timelock, and thus possibly performing + * operations or accessing funds that are expected to only be accessible through a vote, and 2) block governance + * proposals that have been approved by the voters, effectively executing a Denial of Service attack. + * + * NOTE: `AccessManager` does not support scheduling more than one operation with the same target and calldata at + * the same time. See {AccessManager-schedule} for a workaround. + */ +abstract contract GovernorTimelockControl is Governor { + TimelockController private _timelock; + mapping(uint256 proposalId => bytes32) private _timelockIds; + + /** + * @dev Emitted when the timelock controller used for proposal execution is modified. + */ + event TimelockChange(address oldTimelock, address newTimelock); + + /** + * @dev Set the timelock. + */ + constructor(TimelockController timelockAddress) { + _updateTimelock(timelockAddress); + } + + /** + * @dev Overridden version of the {Governor-state} function that considers the status reported by the timelock. + */ + function state(uint256 proposalId) public view virtual override returns (ProposalState) { + ProposalState currentState = super.state(proposalId); + + if (currentState != ProposalState.Queued) { + return currentState; + } + + bytes32 queueid = _timelockIds[proposalId]; + if (_timelock.isOperationPending(queueid)) { + return ProposalState.Queued; + } else if (_timelock.isOperationDone(queueid)) { + // This can happen if the proposal is executed directly on the timelock. + return ProposalState.Executed; + } else { + // This can happen if the proposal is canceled directly on the timelock. + return ProposalState.Canceled; + } + } + + /** + * @dev Public accessor to check the address of the timelock + */ + function timelock() public view virtual returns (address) { + return address(_timelock); + } + + /** + * @dev See {IGovernor-proposalNeedsQueuing}. + */ + function proposalNeedsQueuing(uint256) public view virtual override returns (bool) { + return true; + } + + /** + * @dev Function to queue a proposal to the timelock. + */ + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint48) { + uint256 delay = _timelock.getMinDelay(); + + bytes32 salt = _timelockSalt(descriptionHash); + _timelockIds[proposalId] = _timelock.hashOperationBatch(targets, values, calldatas, 0, salt); + _timelock.scheduleBatch(targets, values, calldatas, 0, salt, delay); + + return SafeCast.toUint48(block.timestamp + delay); + } + + /** + * @dev Overridden version of the {Governor-_executeOperations} function that runs the already queued proposal + * through the timelock. + */ + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override { + // execute + _timelock.executeBatch{value: msg.value}(targets, values, calldatas, 0, _timelockSalt(descriptionHash)); + // cleanup for refund + delete _timelockIds[proposalId]; + } + + /** + * @dev Overridden version of the {Governor-_cancel} function to cancel the timelocked proposal if it has already + * been queued. + */ + // This function can reenter through the external call to the timelock, but we assume the timelock is trusted and + // well behaved (according to TimelockController) and this will not happen. + // slither-disable-next-line reentrancy-no-eth + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal virtual override returns (uint256) { + uint256 proposalId = super._cancel(targets, values, calldatas, descriptionHash); + + bytes32 timelockId = _timelockIds[proposalId]; + if (timelockId != 0) { + // cancel + _timelock.cancel(timelockId); + // cleanup + delete _timelockIds[proposalId]; + } + + return proposalId; + } + + /** + * @dev Address through which the governor executes action. In this case, the timelock. + */ + function _executor() internal view virtual override returns (address) { + return address(_timelock); + } + + /** + * @dev Public endpoint to update the underlying timelock instance. Restricted to the timelock itself, so updates + * must be proposed, scheduled, and executed through governance proposals. + * + * CAUTION: It is not recommended to change the timelock while there are other queued governance proposals. + */ + function updateTimelock(TimelockController newTimelock) external virtual onlyGovernance { + _updateTimelock(newTimelock); + } + + function _updateTimelock(TimelockController newTimelock) private { + emit TimelockChange(address(_timelock), address(newTimelock)); + _timelock = newTimelock; + } + + /** + * @dev Computes the {TimelockController} operation salt. + * + * It is computed with the governor address itself to avoid collisions across governor instances using the + * same timelock. + */ + function _timelockSalt(bytes32 descriptionHash) private view returns (bytes32) { + return bytes20(address(this)) ^ descriptionHash; + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol new file mode 100644 index 0000000..ec32ba4 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorVotes.sol) + +pragma solidity ^0.8.20; + +import {Governor} from "../Governor.sol"; +import {IVotes} from "../utils/IVotes.sol"; +import {IERC5805} from "../../interfaces/IERC5805.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Time} from "../../utils/types/Time.sol"; + +/** + * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token, or since v4.5 an {ERC721Votes} + * token. + */ +abstract contract GovernorVotes is Governor { + IERC5805 private immutable _token; + + constructor(IVotes tokenAddress) { + _token = IERC5805(address(tokenAddress)); + } + + /** + * @dev The token that voting power is sourced from. + */ + function token() public view virtual returns (IERC5805) { + return _token; + } + + /** + * @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 Time.blockNumber(); + } + } + + /** + * @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 timepoint, + bytes memory /*params*/ + ) internal view virtual override returns (uint256) { + return token().getPastVotes(account, timepoint); + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol new file mode 100644 index 0000000..85a1f98 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/extensions/GovernorVotesQuorumFraction.sol) + +pragma solidity ^0.8.20; + +import {GovernorVotes} from "./GovernorVotes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; + +/** + * @dev Extension of {Governor} for voting weight extraction from an {ERC20Votes} token and a quorum expressed as a + * fraction of the total supply. + */ +abstract contract GovernorVotesQuorumFraction is GovernorVotes { + using Checkpoints for Checkpoints.Trace208; + + Checkpoints.Trace208 private _quorumNumeratorHistory; + + event QuorumNumeratorUpdated(uint256 oldQuorumNumerator, uint256 newQuorumNumerator); + + /** + * @dev The quorum set is not a valid fraction. + */ + error GovernorInvalidQuorumFraction(uint256 quorumNumerator, uint256 quorumDenominator); + + /** + * @dev Initialize quorum as a fraction of the token's total supply. + * + * The fraction is specified as `numerator / denominator`. By default the denominator is 100, so quorum is + * specified as a percent: a numerator of 10 corresponds to quorum being 10% of total supply. The denominator can be + * customized by overriding {quorumDenominator}. + */ + constructor(uint256 quorumNumeratorValue) { + _updateQuorumNumerator(quorumNumeratorValue); + } + + /** + * @dev Returns the current quorum numerator. See {quorumDenominator}. + */ + function quorumNumerator() public view virtual returns (uint256) { + return _quorumNumeratorHistory.latest(); + } + + /** + * @dev Returns the quorum numerator at a specific timepoint. See {quorumDenominator}. + */ + function quorumNumerator(uint256 timepoint) public view virtual returns (uint256) { + uint256 length = _quorumNumeratorHistory._checkpoints.length; + + // Optimistic search, check the latest checkpoint + Checkpoints.Checkpoint208 storage latest = _quorumNumeratorHistory._checkpoints[length - 1]; + uint48 latestKey = latest._key; + uint208 latestValue = latest._value; + if (latestKey <= timepoint) { + return latestValue; + } + + // Otherwise, do the binary search + return _quorumNumeratorHistory.upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @dev Returns the quorum denominator. Defaults to 100, but may be overridden. + */ + function quorumDenominator() public view virtual returns (uint256) { + return 100; + } + + /** + * @dev Returns the quorum for a timepoint, in terms of number of votes: `supply * numerator / denominator`. + */ + function quorum(uint256 timepoint) public view virtual override returns (uint256) { + return (token().getPastTotalSupply(timepoint) * quorumNumerator(timepoint)) / quorumDenominator(); + } + + /** + * @dev Changes the quorum numerator. + * + * Emits a {QuorumNumeratorUpdated} event. + * + * Requirements: + * + * - Must be called through a governance proposal. + * - New numerator must be smaller or equal to the denominator. + */ + function updateQuorumNumerator(uint256 newQuorumNumerator) external virtual onlyGovernance { + _updateQuorumNumerator(newQuorumNumerator); + } + + /** + * @dev Changes the quorum numerator. + * + * Emits a {QuorumNumeratorUpdated} event. + * + * Requirements: + * + * - New numerator must be smaller or equal to the denominator. + */ + function _updateQuorumNumerator(uint256 newQuorumNumerator) internal virtual { + uint256 denominator = quorumDenominator(); + if (newQuorumNumerator > denominator) { + revert GovernorInvalidQuorumFraction(newQuorumNumerator, denominator); + } + + uint256 oldQuorumNumerator = quorumNumerator(); + _quorumNumeratorHistory.push(clock(), SafeCast.toUint208(newQuorumNumerator)); + + emit QuorumNumeratorUpdated(oldQuorumNumerator, newQuorumNumerator); + } +} diff --git a/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol b/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol new file mode 100644 index 0000000..7ba012e --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/utils/IVotes.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/IVotes.sol) +pragma solidity ^0.8.20; + +/** + * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts. + */ +interface IVotes { + /** + * @dev The signature used has expired. + */ + error VotesExpiredSignature(uint256 expiry); + + /** + * @dev Emitted when an account changes their delegate. + */ + event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate); + + /** + * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units. + */ + event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes); + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) external view returns (uint256); + + /** + * @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 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 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 + * vote. + */ + function getPastTotalSupply(uint256 timepoint) external view returns (uint256); + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) external view returns (address); + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) external; + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external; +} diff --git a/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol b/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol new file mode 100644 index 0000000..9f96676 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/governance/utils/Votes.sol @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (governance/utils/Votes.sol) +pragma solidity ^0.8.20; + +import {IERC5805} from "../../interfaces/IERC5805.sol"; +import {Context} from "../../utils/Context.sol"; +import {Nonces} from "../../utils/Nonces.sol"; +import {EIP712} from "../../utils/cryptography/EIP712.sol"; +import {Checkpoints} from "../../utils/structs/Checkpoints.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {ECDSA} from "../../utils/cryptography/ECDSA.sol"; +import {Time} from "../../utils/types/Time.sol"; + +/** + * @dev This is a base abstract contract that tracks voting units, which are a measure of voting power that can be + * transferred, and provides a system of vote delegation, where an account can delegate its voting units to a sort of + * "representative" that will pool delegated voting units from different accounts and can then use it to vote in + * decisions. In fact, voting units _must_ be delegated in order to count as actual votes, and an account has to + * delegate those votes to itself if it wishes to participate in decisions and does not have a trusted representative. + * + * This contract is often combined with a token contract such that voting units correspond to token units. For an + * example, see {ERC721Votes}. + * + * The full history of delegate votes is tracked on-chain so that governance protocols can consider votes as distributed + * at a particular block number to protect against flash loans and double voting. The opt-in delegate system makes the + * cost of this history tracking optional. + * + * When using this module the derived contract must implement {_getVotingUnits} (for example, make it return + * {ERC721-balanceOf}), and can use {_transferVotingUnits} to track a change in the distribution of those units (in the + * previous example, it would be included in {ERC721-_update}). + */ +abstract contract Votes is Context, EIP712, Nonces, IERC5805 { + using Checkpoints for Checkpoints.Trace208; + + bytes32 private constant DELEGATION_TYPEHASH = + keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); + + mapping(address account => address) private _delegatee; + + mapping(address delegatee => Checkpoints.Trace208) private _delegateCheckpoints; + + Checkpoints.Trace208 private _totalCheckpoints; + + /** + * @dev The clock was incorrectly modified. + */ + error ERC6372InconsistentClock(); + + /** + * @dev Lookup to future votes is not available. + */ + error ERC5805FutureLookup(uint256 timepoint, uint48 clock); + + /** + * @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 returns (uint48) { + return Time.blockNumber(); + } + + /** + * @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 returns (string memory) { + // Check that the clock was not modified + if (clock() != Time.blockNumber()) { + revert ERC6372InconsistentClock(); + } + return "mode=blocknumber&from=default"; + } + + /** + * @dev Returns the current amount of votes that `account` has. + */ + function getVotes(address account) public view virtual returns (uint256) { + return _delegateCheckpoints[account].latest(); + } + + /** + * @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 at the end of the corresponding block. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastVotes(address account, uint256 timepoint) public view virtual returns (uint256) { + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) { + revert ERC5805FutureLookup(timepoint, currentTimepoint); + } + return _delegateCheckpoints[account].upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @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 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 + * vote. + * + * Requirements: + * + * - `timepoint` must be in the past. If operating using block numbers, the block must be already mined. + */ + function getPastTotalSupply(uint256 timepoint) public view virtual returns (uint256) { + uint48 currentTimepoint = clock(); + if (timepoint >= currentTimepoint) { + revert ERC5805FutureLookup(timepoint, currentTimepoint); + } + return _totalCheckpoints.upperLookupRecent(SafeCast.toUint48(timepoint)); + } + + /** + * @dev Returns the current total supply of votes. + */ + function _getTotalSupply() internal view virtual returns (uint256) { + return _totalCheckpoints.latest(); + } + + /** + * @dev Returns the delegate that `account` has chosen. + */ + function delegates(address account) public view virtual returns (address) { + return _delegatee[account]; + } + + /** + * @dev Delegates votes from the sender to `delegatee`. + */ + function delegate(address delegatee) public virtual { + address account = _msgSender(); + _delegate(account, delegatee); + } + + /** + * @dev Delegates votes from signer to `delegatee`. + */ + function delegateBySig( + address delegatee, + uint256 nonce, + uint256 expiry, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + if (block.timestamp > expiry) { + revert VotesExpiredSignature(expiry); + } + address signer = ECDSA.recover( + _hashTypedDataV4(keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry))), + v, + r, + s + ); + _useCheckedNonce(signer, nonce); + _delegate(signer, delegatee); + } + + /** + * @dev Delegate all of `account`'s voting units to `delegatee`. + * + * Emits events {IVotes-DelegateChanged} and {IVotes-DelegateVotesChanged}. + */ + function _delegate(address account, address delegatee) internal virtual { + address oldDelegate = delegates(account); + _delegatee[account] = delegatee; + + emit DelegateChanged(account, oldDelegate, delegatee); + _moveDelegateVotes(oldDelegate, delegatee, _getVotingUnits(account)); + } + + /** + * @dev Transfers, mints, or burns voting units. To register a mint, `from` should be zero. To register a burn, `to` + * should be zero. Total supply of voting units will be adjusted with mints and burns. + */ + function _transferVotingUnits(address from, address to, uint256 amount) internal virtual { + if (from == address(0)) { + _push(_totalCheckpoints, _add, SafeCast.toUint208(amount)); + } + if (to == address(0)) { + _push(_totalCheckpoints, _subtract, SafeCast.toUint208(amount)); + } + _moveDelegateVotes(delegates(from), delegates(to), amount); + } + + /** + * @dev Moves delegated votes from one delegate to another. + */ + function _moveDelegateVotes(address from, address to, uint256 amount) private { + if (from != to && amount > 0) { + if (from != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[from], + _subtract, + SafeCast.toUint208(amount) + ); + emit DelegateVotesChanged(from, oldValue, newValue); + } + if (to != address(0)) { + (uint256 oldValue, uint256 newValue) = _push( + _delegateCheckpoints[to], + _add, + SafeCast.toUint208(amount) + ); + emit DelegateVotesChanged(to, oldValue, newValue); + } + } + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function _numCheckpoints(address account) internal view virtual returns (uint32) { + return SafeCast.toUint32(_delegateCheckpoints[account].length()); + } + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function _checkpoints( + address account, + uint32 pos + ) internal view virtual returns (Checkpoints.Checkpoint208 memory) { + return _delegateCheckpoints[account].at(pos); + } + + function _push( + Checkpoints.Trace208 storage store, + function(uint208, uint208) view returns (uint208) op, + uint208 delta + ) private returns (uint208, uint208) { + return store.push(clock(), op(store.latest(), delta)); + } + + function _add(uint208 a, uint208 b) private pure returns (uint208) { + return a + b; + } + + function _subtract(uint208 a, uint208 b) private pure returns (uint208) { + return a - b; + } + + /** + * @dev Must return the voting units held by an account. + */ + function _getVotingUnits(address) internal view virtual returns (uint256); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol new file mode 100644 index 0000000..bb502b1 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1155.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1155.sol) + +pragma solidity ^0.8.20; + +import {IERC1155} from "../token/ERC1155/IERC1155.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol new file mode 100644 index 0000000..dac0bab --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1155MetadataURI.sol) + +pragma solidity ^0.8.20; + +import {IERC1155MetadataURI} from "../token/ERC1155/extensions/IERC1155MetadataURI.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol new file mode 100644 index 0000000..6bb7c96 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1155Receiver.sol) + +pragma solidity ^0.8.20; + +import {IERC1155Receiver} from "../token/ERC1155/IERC1155Receiver.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol new file mode 100644 index 0000000..a56057b --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1271.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1271.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC1271 standard signature validation method for + * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271]. + */ +interface IERC1271 { + /** + * @dev Should return whether the signature provided is valid for the provided data + * @param hash Hash of the data to be signed + * @param signature Signature byte array associated with _data + */ + function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol new file mode 100644 index 0000000..8b02aba --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1363.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "./IERC20.sol"; +import {IERC165} from "./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. + * 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)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256)')) ^ + * bytes4(keccak256('approveAndCall(address,uint256,bytes)')) + */ + + /** + * @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 amount uint256 The amount of tokens to be transferred + * @return true unless throwing + */ + 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 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 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 amount uint256 The amount of tokens to be transferred + * @return true unless throwing + */ + 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 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 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 amount uint256 The amount of tokens to be spent + */ + 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 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 amount, bytes memory data) external returns (bool); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol new file mode 100644 index 0000000..64d669d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363Receiver.sol) + +pragma solidity ^0.8.20; + +/** + * @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. + * 0x88a7ca5c === bytes4(keccak256("onTransferReceived(address,address,uint256,bytes)")) + */ + + /** + * @notice Handle the receipt of ERC1363 tokens + * @dev Any ERC1363 smart contract calls this function on the recipient + * after a `transfer` or a `transferFrom`. This function MAY throw to revert and reject the + * transfer. Return of other than the magic value MUST result in the + * transaction being reverted. + * 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 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 + */ + function onTransferReceived( + address operator, + address from, + uint256 amount, + bytes memory data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol new file mode 100644 index 0000000..f221541 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1363Spender.sol) + +pragma solidity ^0.8.20; + +/** + * @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. + * 0x7b04a2d0 === bytes4(keccak256("onApprovalReceived(address,uint256,bytes)")) + */ + + /** + * @notice Handle the approval of ERC1363 tokens + * @dev Any ERC1363 smart contract calls this function on the recipient + * after an `approve`. This function MAY throw to revert and reject the + * approval. Return of other than the magic value MUST result in the + * transaction being reverted. + * Note: the token contract address is always the message sender. + * @param owner address The address which called `approveAndCall` function + * @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 + */ + function onApprovalReceived(address owner, uint256 amount, bytes memory data) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol new file mode 100644 index 0000000..944dd0d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../utils/introspection/IERC165.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol new file mode 100644 index 0000000..38e8a4e --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1820Implementer.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface for an ERC1820 implementer, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[EIP]. + * Used by contracts that will be registered as implementers in the + * {IERC1820Registry}. + */ +interface IERC1820Implementer { + /** + * @dev Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract + * implements `interfaceHash` for `account`. + * + * See {IERC1820Registry-setInterfaceImplementer}. + */ + function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol new file mode 100644 index 0000000..bf0140a --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1820Registry.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the global ERC1820 Registry, as defined in the + * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register + * implementers for interfaces in this registry, as well as query support. + * + * Implementers may be shared by multiple accounts, and can also implement more + * than a single interface for each account. Contracts can implement interfaces + * for themselves, but externally-owned accounts (EOA) must delegate this to a + * contract. + * + * {IERC165} interfaces can also be queried via the registry. + * + * For an in-depth explanation and source code analysis, see the EIP text. + */ +interface IERC1820Registry { + event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer); + + event ManagerChanged(address indexed account, address indexed newManager); + + /** + * @dev Sets `newManager` as the manager for `account`. A manager of an + * account is able to set interface implementers for it. + * + * By default, each account is its own manager. Passing a value of `0x0` in + * `newManager` will reset the manager to this initial state. + * + * Emits a {ManagerChanged} event. + * + * Requirements: + * + * - the caller must be the current manager for `account`. + */ + function setManager(address account, address newManager) external; + + /** + * @dev Returns the manager for `account`. + * + * See {setManager}. + */ + function getManager(address account) external view returns (address); + + /** + * @dev Sets the `implementer` contract as ``account``'s implementer for + * `interfaceHash`. + * + * `account` being the zero address is an alias for the caller's address. + * The zero address can also be used in `implementer` to remove an old one. + * + * See {interfaceHash} to learn how these are created. + * + * Emits an {InterfaceImplementerSet} event. + * + * Requirements: + * + * - the caller must be the current manager for `account`. + * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not + * end in 28 zeroes). + * - `implementer` must implement {IERC1820Implementer} and return true when + * queried for support, unless `implementer` is the caller. See + * {IERC1820Implementer-canImplementInterfaceForAddress}. + */ + function setInterfaceImplementer(address account, bytes32 _interfaceHash, address implementer) external; + + /** + * @dev Returns the implementer of `interfaceHash` for `account`. If no such + * implementer is registered, returns the zero address. + * + * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28 + * zeroes), `account` will be queried for support of it. + * + * `account` being the zero address is an alias for the caller's address. + */ + function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address); + + /** + * @dev Returns the interface hash for an `interfaceName`, as defined in the + * corresponding + * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP]. + */ + function interfaceHash(string calldata interfaceName) external pure returns (bytes32); + + /** + * @notice Updates the cache with whether the contract implements an ERC165 interface or not. + * @param account Address of the contract for which to update the cache. + * @param interfaceId ERC165 interface for which to update the cache. + */ + function updateERC165Cache(address account, bytes4 interfaceId) external; + + /** + * @notice Checks whether a contract implements an ERC165 interface or not. + * If the result is not cached a direct lookup on the contract address is performed. + * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling + * {updateERC165Cache} with the contract address. + * @param account Address of the contract to check. + * @param interfaceId ERC165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool); + + /** + * @notice Checks whether a contract implements an ERC165 interface or not without using or updating the cache. + * @param account Address of the contract to check. + * @param interfaceId ERC165 interface to check. + * @return True if `account` implements `interfaceId`, false otherwise. + */ + function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol new file mode 100644 index 0000000..d285ec8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC1967.sol) + +pragma solidity ^0.8.20; + +/** + * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. + */ +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/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol new file mode 100644 index 0000000..21d5a41 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC20.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../token/ERC20/IERC20.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol new file mode 100644 index 0000000..b7bc691 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol new file mode 100644 index 0000000..aa00f34 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC2309.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2309.sol) + +pragma solidity ^0.8.20; + +/** + * @dev ERC-2309: ERC-721 Consecutive Transfer Extension. + */ +interface IERC2309 { + /** + * @dev Emitted when the tokens from `fromTokenId` to `toTokenId` are transferred from `fromAddress` to `toAddress`. + */ + event ConsecutiveTransfer( + uint256 indexed fromTokenId, + uint256 toTokenId, + address indexed fromAddress, + address indexed toAddress + ); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol new file mode 100644 index 0000000..c0427bb --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC2612.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2612.sol) + +pragma solidity ^0.8.20; + +import {IERC20Permit} from "../token/ERC20/extensions/IERC20Permit.sol"; + +interface IERC2612 is IERC20Permit {} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol new file mode 100644 index 0000000..9e7871d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC2981.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC2981.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../utils/introspection/IERC165.sol"; + +/** + * @dev Interface for the NFT Royalty Standard. + * + * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal + * support for royalty payments across all NFT marketplaces and ecosystem participants. + */ +interface IERC2981 is IERC165 { + /** + * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of + * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. + */ + function royaltyInfo( + uint256 tokenId, + uint256 salePrice + ) external view returns (address receiver, uint256 royaltyAmount); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol new file mode 100644 index 0000000..0f48bf3 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC3156.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156.sol) + +pragma solidity ^0.8.20; + +import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "./IERC3156FlashLender.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol new file mode 100644 index 0000000..53e17ea --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156FlashBorrower.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC3156 FlashBorrower, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + */ +interface IERC3156FlashBorrower { + /** + * @dev Receive a flash loan. + * @param initiator The initiator of the loan. + * @param token The loan currency. + * @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 "ERC3156FlashBorrower.onFlashLoan" + */ + function onFlashLoan( + address initiator, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) external returns (bytes32); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol new file mode 100644 index 0000000..cfae3c0 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC3156FlashLender.sol) + +pragma solidity ^0.8.20; + +import {IERC3156FlashBorrower} from "./IERC3156FlashBorrower.sol"; + +/** + * @dev Interface of the ERC3156 FlashLender, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + */ +interface IERC3156FlashLender { + /** + * @dev The amount of currency available to be lended. + * @param token The loan currency. + * @return The amount of `token` that can be borrowed. + */ + function maxFlashLoan(address token) external view returns (uint256); + + /** + * @dev The fee to be charged for a given loan. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @return The amount of `token` to be charged for the loan, on top of the returned principal. + */ + function flashFee(address token, uint256 amount) external view returns (uint256); + + /** + * @dev Initiate a flash loan. + * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. + * @param token The loan currency. + * @param amount The amount of tokens lent. + * @param data Arbitrary data structure, intended to contain user-defined parameters. + */ + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 amount, + bytes calldata data + ) external returns (bool); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol new file mode 100644 index 0000000..cfff53b --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol"; + +/** + * @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in + * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626]. + */ +interface IERC4626 is IERC20, IERC20Metadata { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, + address indexed receiver, + address indexed owner, + uint256 assets, + uint256 shares + ); + + /** + * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + * + * - MUST be an ERC-20 token contract. + * - MUST NOT revert. + */ + function asset() external view returns (address assetTokenAddress); + + /** + * @dev Returns the total amount of the underlying asset that is “managed” by Vault. + * + * - SHOULD include any compounding that occurs from yield. + * - MUST be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT revert. + */ + function totalAssets() external view returns (uint256 totalManagedAssets); + + /** + * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + * scenario where all the conditions are met. + * + * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + * - MUST NOT revert. + * + * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + * from. + */ + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + * scenario where all the conditions are met. + * + * - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + * - MUST NOT show any variations depending on the caller. + * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + * - MUST NOT revert. + * + * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + * from. + */ + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + * through a deposit call. + * + * - MUST return a limited value if receiver is subject to some deposit limit. + * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + * - MUST NOT revert. + */ + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + * current on-chain conditions. + * + * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + * call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + * in the same transaction. + * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + * deposit would be accepted, regardless if the user has enough tokens approved, etc. + * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by depositing. + */ + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + * + * - MUST emit the Deposit event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * deposit execution, and are accounted for during deposit. + * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + * approving enough underlying tokens to the Vault contract, etc). + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + */ + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /** + * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + * - MUST return a limited value if receiver is subject to some mint limit. + * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + * - MUST NOT revert. + */ + function maxMint(address receiver) external view returns (uint256 maxShares); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + * current on-chain conditions. + * + * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + * in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + * same transaction. + * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + * would be accepted, regardless if the user has enough tokens approved, etc. + * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by minting. + */ + function previewMint(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + * + * - MUST emit the Deposit event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + * execution, and are accounted for during mint. + * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + * approving enough underlying tokens to the Vault contract, etc). + * + * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + */ + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /** + * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + * Vault, through a withdraw call. + * + * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + * - MUST NOT revert. + */ + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + * given current on-chain conditions. + * + * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + * call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + * called + * in the same transaction. + * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + * the withdrawal would be accepted, regardless if the user has enough shares, etc. + * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by depositing. + */ + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /** + * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver. + * + * - MUST emit the Withdraw event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * withdraw execution, and are accounted for during withdraw. + * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + * not having enough shares, etc). + * + * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + * Those methods should be performed separately. + */ + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /** + * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + * through a redeem call. + * + * - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + * - MUST NOT revert. + */ + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /** + * @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + * given current on-chain conditions. + * + * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + * in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + * same transaction. + * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + * redemption would be accepted, regardless if the user has enough shares, etc. + * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + * - MUST NOT revert. + * + * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + * share price or some other type of condition, meaning the depositor will lose assets by redeeming. + */ + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /** + * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver. + * + * - MUST emit the Withdraw event. + * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + * redeem execution, and are accounted for during redeem. + * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + * not having enough shares, etc). + * + * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + * Those methods should be performed separately. + */ + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol new file mode 100644 index 0000000..bc008e3 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC4906.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4906.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "./IERC165.sol"; +import {IERC721} from "./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/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol new file mode 100644 index 0000000..47a9fd5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC5267.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5267.sol) + +pragma solidity ^0.8.20; + +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/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol new file mode 100644 index 0000000..62f8d75 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC5313.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5313.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface for the Light Contract Ownership Standard. + * + * A standardized minimal interface required to identify an account that controls a contract + */ +interface IERC5313 { + /** + * @dev Gets the address of the owner. + */ + function owner() external view returns (address); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol new file mode 100644 index 0000000..a89e22d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC5805.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC5805.sol) + +pragma solidity ^0.8.20; + +import {IVotes} from "../governance/utils/IVotes.sol"; +import {IERC6372} from "./IERC6372.sol"; + +interface IERC5805 is IERC6372, IVotes {} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol new file mode 100644 index 0000000..7d2ea4a --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC6372.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC6372.sol) + +pragma solidity ^0.8.20; + +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/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol new file mode 100644 index 0000000..0ea735b --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC721.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "../token/ERC721/IERC721.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol new file mode 100644 index 0000000..d83a056 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Enumerable.sol) + +pragma solidity ^0.8.20; + +import {IERC721Enumerable} from "../token/ERC721/extensions/IERC721Enumerable.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol new file mode 100644 index 0000000..d79dd68 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC721Metadata} from "../token/ERC721/extensions/IERC721Metadata.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol new file mode 100644 index 0000000..6b2a5aa --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC721Receiver.sol) + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../token/ERC721/IERC721Receiver.sol"; diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol new file mode 100644 index 0000000..56dfbef --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC777.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC777.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC777Token standard as defined in the EIP. + * + * This contract uses the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 registry standard] to let + * token holders and recipients react to token movements by using setting implementers + * for the associated interfaces in said registry. See {IERC1820Registry} and + * {IERC1820Implementer}. + */ +interface IERC777 { + /** + * @dev Emitted when `amount` tokens are created by `operator` and assigned to `to`. + * + * Note that some additional user `data` and `operatorData` can be logged in the event. + */ + event Minted(address indexed operator, address indexed to, uint256 amount, bytes data, bytes operatorData); + + /** + * @dev Emitted when `operator` destroys `amount` tokens from `account`. + * + * Note that some additional user `data` and `operatorData` can be logged in the event. + */ + event Burned(address indexed operator, address indexed from, uint256 amount, bytes data, bytes operatorData); + + /** + * @dev Emitted when `operator` is made operator for `tokenHolder`. + */ + event AuthorizedOperator(address indexed operator, address indexed tokenHolder); + + /** + * @dev Emitted when `operator` is revoked its operator status for `tokenHolder`. + */ + event RevokedOperator(address indexed operator, address indexed tokenHolder); + + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the smallest part of the token that is not divisible. This + * means all token operations (creation, movement and destruction) must have + * amounts that are a multiple of this number. + * + * For most token contracts, this value will equal 1. + */ + function granularity() external view returns (uint256); + + /** + * @dev Returns the amount of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the amount of tokens owned by an account (`owner`). + */ + function balanceOf(address owner) external view returns (uint256); + + /** + * @dev Moves `amount` tokens from the caller's account to `recipient`. + * + * If send or receive hooks are registered for the caller and `recipient`, + * the corresponding functions will be called with `data` and empty + * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. + * + * Emits a {Sent} event. + * + * Requirements + * + * - the caller must have at least `amount` tokens. + * - `recipient` cannot be the zero address. + * - if `recipient` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function send(address recipient, uint256 amount, bytes calldata data) external; + + /** + * @dev Destroys `amount` tokens from the caller's account, reducing the + * total supply. + * + * If a send hook is registered for the caller, the corresponding function + * will be called with `data` and empty `operatorData`. See {IERC777Sender}. + * + * Emits a {Burned} event. + * + * Requirements + * + * - the caller must have at least `amount` tokens. + */ + function burn(uint256 amount, bytes calldata data) external; + + /** + * @dev Returns true if an account is an operator of `tokenHolder`. + * Operators can send and burn tokens on behalf of their owners. All + * accounts are their own operator. + * + * See {operatorSend} and {operatorBurn}. + */ + function isOperatorFor(address operator, address tokenHolder) external view returns (bool); + + /** + * @dev Make an account an operator of the caller. + * + * See {isOperatorFor}. + * + * Emits an {AuthorizedOperator} event. + * + * Requirements + * + * - `operator` cannot be calling address. + */ + function authorizeOperator(address operator) external; + + /** + * @dev Revoke an account's operator status for the caller. + * + * See {isOperatorFor} and {defaultOperators}. + * + * Emits a {RevokedOperator} event. + * + * Requirements + * + * - `operator` cannot be calling address. + */ + function revokeOperator(address operator) external; + + /** + * @dev Returns the list of default operators. These accounts are operators + * for all token holders, even if {authorizeOperator} was never called on + * them. + * + * This list is immutable, but individual holders may revoke these via + * {revokeOperator}, in which case {isOperatorFor} will return false. + */ + function defaultOperators() external view returns (address[] memory); + + /** + * @dev Moves `amount` tokens from `sender` to `recipient`. The caller must + * be an operator of `sender`. + * + * If send or receive hooks are registered for `sender` and `recipient`, + * the corresponding functions will be called with `data` and + * `operatorData`. See {IERC777Sender} and {IERC777Recipient}. + * + * Emits a {Sent} event. + * + * Requirements + * + * - `sender` cannot be the zero address. + * - `sender` must have at least `amount` tokens. + * - the caller must be an operator for `sender`. + * - `recipient` cannot be the zero address. + * - if `recipient` is a contract, it must implement the {IERC777Recipient} + * interface. + */ + function operatorSend( + address sender, + address recipient, + uint256 amount, + bytes calldata data, + bytes calldata operatorData + ) external; + + /** + * @dev Destroys `amount` tokens from `account`, reducing the total supply. + * The caller must be an operator of `account`. + * + * If a send hook is registered for `account`, the corresponding function + * will be called with `data` and `operatorData`. See {IERC777Sender}. + * + * Emits a {Burned} event. + * + * Requirements + * + * - `account` cannot be the zero address. + * - `account` must have at least `amount` tokens. + * - the caller must be an operator for `account`. + */ + function operatorBurn(address account, uint256 amount, bytes calldata data, bytes calldata operatorData) external; + + event Sent( + address indexed operator, + address indexed from, + address indexed to, + uint256 amount, + bytes data, + bytes operatorData + ); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol new file mode 100644 index 0000000..6378e14 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC777Recipient.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC777TokensRecipient standard as defined in the EIP. + * + * Accounts can be notified of {IERC777} tokens being sent to them by having a + * contract implement this interface (contract holders can be their own + * implementer) and registering it on the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. + * + * See {IERC1820Registry} and {IERC1820Implementer}. + */ +interface IERC777Recipient { + /** + * @dev Called by an {IERC777} token contract whenever tokens are being + * moved or created into a registered account (`to`). The type of operation + * is conveyed by `from` being the zero address or not. + * + * This call occurs _after_ the token contract's state is updated, so + * {IERC777-balanceOf}, etc., can be used to query the post-operation state. + * + * This function may revert to prevent the operation from being executed. + */ + function tokensReceived( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external; +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol b/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol new file mode 100644 index 0000000..5c0ec0b --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC777Sender.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC777TokensSender standard as defined in the EIP. + * + * {IERC777} Token holders can be notified of operations performed on their + * tokens by having a contract implement this interface (contract holders can be + * their own implementer) and registering it on the + * https://eips.ethereum.org/EIPS/eip-1820[ERC1820 global registry]. + * + * See {IERC1820Registry} and {IERC1820Implementer}. + */ +interface IERC777Sender { + /** + * @dev Called by an {IERC777} token contract whenever a registered holder's + * (`from`) tokens are about to be moved or destroyed. The type of operation + * is conveyed by `to` being the zero address or not. + * + * This call occurs _before_ the token contract's state is updated, so + * {IERC777-balanceOf}, etc., can be used to query the pre-operation state. + * + * This function may revert to prevent the operation from being executed. + */ + function tokensToSend( + address operator, + address from, + address to, + uint256 amount, + bytes calldata userData, + bytes calldata operatorData + ) external; +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/README.adoc b/lib/openzeppelin-contracts/contracts/interfaces/README.adoc new file mode 100644 index 0000000..379a24a --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/README.adoc @@ -0,0 +1,82 @@ += Interfaces + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/interfaces + +== List of standardized interfaces +These interfaces are available as `.sol` files, and also as compiler `.json` ABI files (through the npm package). These +are useful to interact with third party contracts that implement them. + +- {IERC20} +- {IERC20Errors} +- {IERC20Metadata} +- {IERC165} +- {IERC721} +- {IERC721Receiver} +- {IERC721Enumerable} +- {IERC721Metadata} +- {IERC721Errors} +- {IERC777} +- {IERC777Recipient} +- {IERC777Sender} +- {IERC1155} +- {IERC1155Receiver} +- {IERC1155MetadataURI} +- {IERC1155Errors} +- {IERC1271} +- {IERC1363} +- {IERC1363Receiver} +- {IERC1363Spender} +- {IERC1820Implementer} +- {IERC1820Registry} +- {IERC1822Proxiable} +- {IERC2612} +- {IERC2981} +- {IERC3156FlashLender} +- {IERC3156FlashBorrower} +- {IERC4626} +- {IERC4906} +- {IERC5267} +- {IERC5313} +- {IERC5805} +- {IERC6372} + +== Detailed ABI + +{{IERC20Errors}} + +{{IERC721Errors}} + +{{IERC1155Errors}} + +{{IERC1271}} + +{{IERC1363}} + +{{IERC1363Receiver}} + +{{IERC1363Spender}} + +{{IERC1820Implementer}} + +{{IERC1820Registry}} + +{{IERC1822Proxiable}} + +{{IERC2612}} + +{{IERC2981}} + +{{IERC3156FlashLender}} + +{{IERC3156FlashBorrower}} + +{{IERC4626}} + +{{IERC5313}} + +{{IERC5267}} + +{{IERC5805}} + +{{IERC6372}} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol b/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol new file mode 100644 index 0000000..4d0f0f8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC1822.sol) + +pragma solidity ^0.8.20; + +/** + * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified + * proxy whose upgrades are fully controlled by the current implementation. + */ +interface IERC1822Proxiable { + /** + * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation + * address. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. + */ + function proxiableUUID() external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol b/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol new file mode 100644 index 0000000..f6990e6 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sol @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol) +pragma solidity ^0.8.20; + +/** + * @dev Standard ERC20 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens. + */ +interface IERC20Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC20InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC20InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers. + * @param spender Address that may be allowed to operate on tokens without being their owner. + * @param allowance Amount of tokens a `spender` is allowed to operate with. + * @param needed Minimum amount required to perform a transfer. + */ + error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC20InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `spender` to be approved. Used in approvals. + * @param spender Address that may be allowed to operate on tokens without being their owner. + */ + error ERC20InvalidSpender(address spender); +} + +/** + * @dev Standard ERC721 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens. + */ +interface IERC721Errors { + /** + * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20. + * Used in balance queries. + * @param owner Address of the current owner of a token. + */ + error ERC721InvalidOwner(address owner); + + /** + * @dev Indicates a `tokenId` whose `owner` is the zero address. + * @param tokenId Identifier number of a token. + */ + error ERC721NonexistentToken(uint256 tokenId); + + /** + * @dev Indicates an error related to the ownership over a particular token. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param tokenId Identifier number of a token. + * @param owner Address of the current owner of a token. + */ + error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC721InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC721InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`’s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param tokenId Identifier number of a token. + */ + error ERC721InsufficientApproval(address operator, uint256 tokenId); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC721InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC721InvalidOperator(address operator); +} + +/** + * @dev Standard ERC1155 Errors + * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens. + */ +interface IERC1155Errors { + /** + * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + * @param balance Current balance for the interacting account. + * @param needed Minimum amount required to perform a transfer. + * @param tokenId Identifier number of a token. + */ + error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId); + + /** + * @dev Indicates a failure with the token `sender`. Used in transfers. + * @param sender Address whose tokens are being transferred. + */ + error ERC1155InvalidSender(address sender); + + /** + * @dev Indicates a failure with the token `receiver`. Used in transfers. + * @param receiver Address to which tokens are being transferred. + */ + error ERC1155InvalidReceiver(address receiver); + + /** + * @dev Indicates a failure with the `operator`’s approval. Used in transfers. + * @param operator Address that may be allowed to operate on tokens without being their owner. + * @param owner Address of the current owner of a token. + */ + error ERC1155MissingApprovalForAll(address operator, address owner); + + /** + * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals. + * @param approver Address initiating an approval operation. + */ + error ERC1155InvalidApprover(address approver); + + /** + * @dev Indicates a failure with the `operator` to be approved. Used in approvals. + * @param operator Address that may be allowed to operate on tokens without being their owner. + */ + error ERC1155InvalidOperator(address operator); + + /** + * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation. + * Used in batch transfers. + * @param idsLength Length of the array of token identifiers + * @param valuesLength Length of the array of token amounts + */ + error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength); +} diff --git a/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol b/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol new file mode 100644 index 0000000..ab9546b --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (metatx/ERC2771Context.sol) + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +/** + * @dev Context variant with ERC2771 support. + * + * WARNING: Avoid using this pattern in contracts that rely in a specific calldata length as they'll + * be affected by any forwarder whose `msg.data` is suffixed with the `from` address according to the ERC2771 + * specification adding the address size in bytes (20) to the calldata size. An example of an unexpected + * behavior could be an unintended fallback (or another function) invocation while trying to invoke the `receive` + * function only accessible if `msg.data.length == 0`. + */ +abstract contract ERC2771Context is Context { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable _trustedForwarder; + + /** + * @dev Initializes the contract with a trusted forwarder, which will be able to + * invoke functions on this contract on behalf of other accounts. + * + * NOTE: The trusted forwarder can be replaced by overriding {trustedForwarder}. + */ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address trustedForwarder_) { + _trustedForwarder = trustedForwarder_; + } + + /** + * @dev Returns the address of the trusted forwarder. + */ + function trustedForwarder() public view virtual returns (address) { + return _trustedForwarder; + } + + /** + * @dev Indicates whether any particular address is the trusted forwarder. + */ + function isTrustedForwarder(address forwarder) public view virtual returns (bool) { + return forwarder == trustedForwarder(); + } + + /** + * @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever + * a call is not performed by the trusted forwarder or the calldata length is less than + * 20 bytes (an address length). + */ + function _msgSender() internal view virtual override returns (address sender) { + if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { + // The assembly code is more direct than the Solidity version using `abi.decode`. + /// @solidity memory-safe-assembly + assembly { + sender := shr(96, calldataload(sub(calldatasize(), 20))) + } + } else { + return super._msgSender(); + } + } + + /** + * @dev Override for `msg.data`. Defaults to the original `msg.data` whenever + * a call is not performed by the trusted forwarder or the calldata length is less than + * 20 bytes (an address length). + */ + function _msgData() internal view virtual override returns (bytes calldata) { + if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { + return msg.data[:msg.data.length - 20]; + } else { + return super._msgData(); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol b/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol new file mode 100644 index 0000000..4815c1a --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sol @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (metatx/ERC2771Forwarder.sol) + +pragma solidity ^0.8.20; + +import {ERC2771Context} from "./ERC2771Context.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; +import {Nonces} from "../utils/Nonces.sol"; +import {Address} from "../utils/Address.sol"; + +/** + * @dev A forwarder compatible with ERC2771 contracts. See {ERC2771Context}. + * + * This forwarder operates on forward requests that include: + * + * * `from`: An address to operate on behalf of. It is required to be equal to the request signer. + * * `to`: The address that should be called. + * * `value`: The amount of native token to attach with the requested call. + * * `gas`: The amount of gas limit that will be forwarded with the requested call. + * * `nonce`: A unique transaction ordering identifier to avoid replayability and request invalidation. + * * `deadline`: A timestamp after which the request is not executable anymore. + * * `data`: Encoded `msg.data` to send with the requested call. + * + * Relayers are able to submit batches if they are processing a high volume of requests. With high + * throughput, relayers may run into limitations of the chain such as limits on the number of + * transactions in the mempool. In these cases the recommendation is to distribute the load among + * multiple accounts. + * + * NOTE: Batching requests includes an optional refund for unused `msg.value` that is achieved by + * performing a call with empty calldata. While this is within the bounds of ERC-2771 compliance, + * if the refund receiver happens to consider the forwarder a trusted forwarder, it MUST properly + * handle `msg.data.length == 0`. `ERC2771Context` in OpenZeppelin Contracts versions prior to 4.9.3 + * do not handle this properly. + * + * ==== Security Considerations + * + * If a relayer submits a forward request, it should be willing to pay up to 100% of the gas amount + * specified in the request. This contract does not implement any kind of retribution for this gas, + * and it is assumed that there is an out of band incentive for relayers to pay for execution on + * behalf of signers. Often, the relayer is operated by a project that will consider it a user + * acquisition cost. + * + * By offering to pay for gas, relayers are at risk of having that gas used by an attacker toward + * some other purpose that is not aligned with the expected out of band incentives. If you operate a + * relayer, consider whitelisting target contracts and function selectors. When relaying ERC-721 or + * ERC-1155 transfers specifically, consider rejecting the use of the `data` field, since it can be + * used to execute arbitrary code. + */ +contract ERC2771Forwarder is EIP712, Nonces { + using ECDSA for bytes32; + + struct ForwardRequestData { + address from; + address to; + uint256 value; + uint256 gas; + uint48 deadline; + bytes data; + bytes signature; + } + + bytes32 internal constant _FORWARD_REQUEST_TYPEHASH = + keccak256( + "ForwardRequest(address from,address to,uint256 value,uint256 gas,uint256 nonce,uint48 deadline,bytes data)" + ); + + /** + * @dev Emitted when a `ForwardRequest` is executed. + * + * NOTE: An unsuccessful forward request could be due to an invalid signature, an expired deadline, + * or simply a revert in the requested call. The contract guarantees that the relayer is not able to force + * the requested call to run out of gas. + */ + event ExecutedForwardRequest(address indexed signer, uint256 nonce, bool success); + + /** + * @dev The request `from` doesn't match with the recovered `signer`. + */ + error ERC2771ForwarderInvalidSigner(address signer, address from); + + /** + * @dev The `requestedValue` doesn't match with the available `msgValue`. + */ + error ERC2771ForwarderMismatchedValue(uint256 requestedValue, uint256 msgValue); + + /** + * @dev The request `deadline` has expired. + */ + error ERC2771ForwarderExpiredRequest(uint48 deadline); + + /** + * @dev The request target doesn't trust the `forwarder`. + */ + error ERC2771UntrustfulTarget(address target, address forwarder); + + /** + * @dev See {EIP712-constructor}. + */ + constructor(string memory name) EIP712(name, "1") {} + + /** + * @dev Returns `true` if a request is valid for a provided `signature` at the current block timestamp. + * + * A transaction is considered valid when the target trusts this forwarder, the request hasn't expired + * (deadline is not met), and the signer matches the `from` parameter of the signed request. + * + * NOTE: A request may return false here but it won't cause {executeBatch} to revert if a refund + * receiver is provided. + */ + function verify(ForwardRequestData calldata request) public view virtual returns (bool) { + (bool isTrustedForwarder, bool active, bool signerMatch, ) = _validate(request); + return isTrustedForwarder && active && signerMatch; + } + + /** + * @dev Executes a `request` on behalf of `signature`'s signer using the ERC-2771 protocol. The gas + * provided to the requested call may not be exactly the amount requested, but the call will not run + * out of gas. Will revert if the request is invalid or the call reverts, in this case the nonce is not consumed. + * + * Requirements: + * + * - The request value should be equal to the provided `msg.value`. + * - The request should be valid according to {verify}. + */ + function execute(ForwardRequestData calldata request) public payable virtual { + // We make sure that msg.value and request.value match exactly. + // If the request is invalid or the call reverts, this whole function + // will revert, ensuring value isn't stuck. + if (msg.value != request.value) { + revert ERC2771ForwarderMismatchedValue(request.value, msg.value); + } + + if (!_execute(request, true)) { + revert Address.FailedInnerCall(); + } + } + + /** + * @dev Batch version of {execute} with optional refunding and atomic execution. + * + * In case a batch contains at least one invalid request (see {verify}), the + * request will be skipped and the `refundReceiver` parameter will receive back the + * unused requested value at the end of the execution. This is done to prevent reverting + * the entire batch when a request is invalid or has already been submitted. + * + * If the `refundReceiver` is the `address(0)`, this function will revert when at least + * one of the requests was not valid instead of skipping it. This could be useful if + * a batch is required to get executed atomically (at least at the top-level). For example, + * refunding (and thus atomicity) can be opt-out if the relayer is using a service that avoids + * including reverted transactions. + * + * Requirements: + * + * - The sum of the requests' values should be equal to the provided `msg.value`. + * - All of the requests should be valid (see {verify}) when `refundReceiver` is the zero address. + * + * NOTE: Setting a zero `refundReceiver` guarantees an all-or-nothing requests execution only for + * the first-level forwarded calls. In case a forwarded request calls to a contract with another + * subcall, the second-level call may revert without the top-level call reverting. + */ + function executeBatch( + ForwardRequestData[] calldata requests, + address payable refundReceiver + ) public payable virtual { + bool atomic = refundReceiver == address(0); + + uint256 requestsValue; + uint256 refundValue; + + for (uint256 i; i < requests.length; ++i) { + requestsValue += requests[i].value; + bool success = _execute(requests[i], atomic); + if (!success) { + refundValue += requests[i].value; + } + } + + // The batch should revert if there's a mismatched msg.value provided + // to avoid request value tampering + if (requestsValue != msg.value) { + revert ERC2771ForwarderMismatchedValue(requestsValue, msg.value); + } + + // Some requests with value were invalid (possibly due to frontrunning). + // To avoid leaving ETH in the contract this value is refunded. + if (refundValue != 0) { + // We know refundReceiver != address(0) && requestsValue == msg.value + // meaning we can ensure refundValue is not taken from the original contract's balance + // and refundReceiver is a known account. + Address.sendValue(refundReceiver, refundValue); + } + } + + /** + * @dev Validates if the provided request can be executed at current block timestamp with + * the given `request.signature` on behalf of `request.signer`. + */ + function _validate( + ForwardRequestData calldata request + ) internal view virtual returns (bool isTrustedForwarder, bool active, bool signerMatch, address signer) { + (bool isValid, address recovered) = _recoverForwardRequestSigner(request); + + return ( + _isTrustedByTarget(request.to), + request.deadline >= block.timestamp, + isValid && recovered == request.from, + recovered + ); + } + + /** + * @dev Returns a tuple with the recovered the signer of an EIP712 forward request message hash + * and a boolean indicating if the signature is valid. + * + * NOTE: The signature is considered valid if {ECDSA-tryRecover} indicates no recover error for it. + */ + function _recoverForwardRequestSigner( + ForwardRequestData calldata request + ) internal view virtual returns (bool, address) { + (address recovered, ECDSA.RecoverError err, ) = _hashTypedDataV4( + keccak256( + abi.encode( + _FORWARD_REQUEST_TYPEHASH, + request.from, + request.to, + request.value, + request.gas, + nonces(request.from), + request.deadline, + keccak256(request.data) + ) + ) + ).tryRecover(request.signature); + + return (err == ECDSA.RecoverError.NoError, recovered); + } + + /** + * @dev Validates and executes a signed request returning the request call `success` value. + * + * Internal function without msg.value validation. + * + * Requirements: + * + * - The caller must have provided enough gas to forward with the call. + * - The request must be valid (see {verify}) if the `requireValidRequest` is true. + * + * Emits an {ExecutedForwardRequest} event. + * + * IMPORTANT: Using this function doesn't check that all the `msg.value` was sent, potentially + * leaving value stuck in the contract. + */ + function _execute( + ForwardRequestData calldata request, + bool requireValidRequest + ) internal virtual returns (bool success) { + (bool isTrustedForwarder, bool active, bool signerMatch, address signer) = _validate(request); + + // Need to explicitly specify if a revert is required since non-reverting is default for + // batches and reversion is opt-in since it could be useful in some scenarios + if (requireValidRequest) { + if (!isTrustedForwarder) { + revert ERC2771UntrustfulTarget(request.to, address(this)); + } + + if (!active) { + revert ERC2771ForwarderExpiredRequest(request.deadline); + } + + if (!signerMatch) { + revert ERC2771ForwarderInvalidSigner(signer, request.from); + } + } + + // Ignore an invalid request because requireValidRequest = false + if (isTrustedForwarder && signerMatch && active) { + // Nonce should be used before the call to prevent reusing by reentrancy + uint256 currentNonce = _useNonce(signer); + + uint256 reqGas = request.gas; + address to = request.to; + uint256 value = request.value; + bytes memory data = abi.encodePacked(request.data, request.from); + + uint256 gasLeft; + + assembly { + success := call(reqGas, to, value, add(data, 0x20), mload(data), 0, 0) + gasLeft := gas() + } + + _checkForwardedGas(gasLeft, request); + + emit ExecutedForwardRequest(signer, currentNonce, success); + } + } + + /** + * @dev Returns whether the target trusts this forwarder. + * + * This function performs a static call to the target contract calling the + * {ERC2771Context-isTrustedForwarder} function. + */ + function _isTrustedByTarget(address target) private view returns (bool) { + bytes memory encodedParams = abi.encodeCall(ERC2771Context.isTrustedForwarder, (address(this))); + + bool success; + uint256 returnSize; + uint256 returnValue; + /// @solidity memory-safe-assembly + assembly { + // Perform the staticcal and save the result in the scratch space. + // | Location | Content | Content (Hex) | + // |-----------|----------|--------------------------------------------------------------------| + // | | | result ↓ | + // | 0x00:0x1F | selector | 0x0000000000000000000000000000000000000000000000000000000000000001 | + success := staticcall(gas(), target, add(encodedParams, 0x20), mload(encodedParams), 0, 0x20) + returnSize := returndatasize() + returnValue := mload(0) + } + + return success && returnSize >= 0x20 && returnValue > 0; + } + + /** + * @dev Checks if the requested gas was correctly forwarded to the callee. + * + * As a consequence of https://eips.ethereum.org/EIPS/eip-150[EIP-150]: + * - At most `gasleft() - floor(gasleft() / 64)` is forwarded to the callee. + * - At least `floor(gasleft() / 64)` is kept in the caller. + * + * It reverts consuming all the available gas if the forwarded gas is not the requested gas. + * + * IMPORTANT: The `gasLeft` parameter should be measured exactly at the end of the forwarded call. + * Any gas consumed in between will make room for bypassing this check. + */ + function _checkForwardedGas(uint256 gasLeft, ForwardRequestData calldata request) private pure { + // To avoid insufficient gas griefing attacks, as referenced in https://ronan.eth.limo/blog/ethereum-gas-dangers/ + // + // A malicious relayer can attempt to shrink the gas forwarded so that the underlying call reverts out-of-gas + // but the forwarding itself still succeeds. In order to make sure that the subcall received sufficient gas, + // we will inspect gasleft() after the forwarding. + // + // Let X be the gas available before the subcall, such that the subcall gets at most X * 63 / 64. + // We can't know X after CALL dynamic costs, but we want it to be such that X * 63 / 64 >= req.gas. + // Let Y be the gas used in the subcall. gasleft() measured immediately after the subcall will be gasleft() = X - Y. + // If the subcall ran out of gas, then Y = X * 63 / 64 and gasleft() = X - Y = X / 64. + // Under this assumption req.gas / 63 > gasleft() is true is true if and only if + // req.gas / 63 > X / 64, or equivalently req.gas > X * 63 / 64. + // This means that if the subcall runs out of gas we are able to detect that insufficient gas was passed. + // + // We will now also see that req.gas / 63 > gasleft() implies that req.gas >= X * 63 / 64. + // The contract guarantees Y <= req.gas, thus gasleft() = X - Y >= X - req.gas. + // - req.gas / 63 > gasleft() + // - req.gas / 63 >= X - req.gas + // - req.gas >= X * 63 / 64 + // In other words if req.gas < X * 63 / 64 then req.gas / 63 <= gasleft(), thus if the relayer behaves honestly + // the forwarding does not revert. + if (gasLeft < request.gas / 63) { + // We explicitly trigger invalid opcode to consume all gas and bubble-up the effects, since + // neither revert or assert consume all gas since Solidity 0.8.20 + // https://docs.soliditylang.org/en/v0.8.20/control-structures.html#panic-via-assert-and-error-via-require + /// @solidity memory-safe-assembly + assembly { + invalid() + } + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/metatx/README.adoc b/lib/openzeppelin-contracts/contracts/metatx/README.adoc new file mode 100644 index 0000000..9f25802 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/metatx/README.adoc @@ -0,0 +1,12 @@ += Meta Transactions + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/metatx + +== Core + +{{ERC2771Context}} + +== Utils + +{{ERC2771Forwarder}} diff --git a/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol b/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol new file mode 100644 index 0000000..673feed --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {AccessManaged} from "../access/manager/AccessManaged.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; + +abstract contract AccessManagedTarget is AccessManaged { + event CalledRestricted(address caller); + event CalledUnrestricted(address caller); + event CalledFallback(address caller); + + function fnRestricted() public restricted { + emit CalledRestricted(msg.sender); + } + + function fnUnrestricted() public { + emit CalledUnrestricted(msg.sender); + } + + function setIsConsumingScheduledOp(bool isConsuming, bytes32 slot) external { + // Memory layout is 0x....<_consumingSchedule (boolean)> + bytes32 mask = bytes32(uint256(1 << 160)); + if (isConsuming) { + StorageSlot.getBytes32Slot(slot).value |= mask; + } else { + StorageSlot.getBytes32Slot(slot).value &= ~mask; + } + } + + fallback() external { + emit CalledFallback(msg.sender); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol b/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol new file mode 100644 index 0000000..a00def2 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ArraysMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Arrays} from "../utils/Arrays.sol"; + +contract Uint256ArraysMock { + using Arrays for uint256[]; + + uint256[] private _array; + + constructor(uint256[] memory array) { + _array = array; + } + + function findUpperBound(uint256 element) external view returns (uint256) { + return _array.findUpperBound(element); + } + + function unsafeAccess(uint256 pos) external view returns (uint256) { + return _array.unsafeAccess(pos).value; + } +} + +contract AddressArraysMock { + using Arrays for address[]; + + address[] private _array; + + constructor(address[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (address) { + return _array.unsafeAccess(pos).value; + } +} + +contract Bytes32ArraysMock { + using Arrays for bytes32[]; + + bytes32[] private _array; + + constructor(bytes32[] memory array) { + _array = array; + } + + function unsafeAccess(uint256 pos) external view returns (bytes32) { + return _array.unsafeAccess(pos).value; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol b/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol new file mode 100644 index 0000000..bf2434b --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IAccessManaged} from "../access/manager/IAccessManaged.sol"; +import {IAuthority} from "../access/manager/IAuthority.sol"; + +contract NotAuthorityMock is IAuthority { + function canCall(address /* caller */, address /* target */, bytes4 /* selector */) external pure returns (bool) { + revert("AuthorityNoDelayMock: not implemented"); + } +} + +contract AuthorityNoDelayMock is IAuthority { + bool _immediate; + + function canCall( + address /* caller */, + address /* target */, + bytes4 /* selector */ + ) external view returns (bool immediate) { + return _immediate; + } + + function _setImmediate(bool immediate) external { + _immediate = immediate; + } +} + +contract AuthorityDelayMock { + bool _immediate; + uint32 _delay; + + function canCall( + address /* caller */, + address /* target */, + bytes4 /* selector */ + ) external view returns (bool immediate, uint32 delay) { + return (_immediate, _delay); + } + + function _setImmediate(bool immediate) external { + _immediate = immediate; + } + + function _setDelay(uint32 delay) external { + _delay = delay; + } +} + +contract AuthorityNoResponse { + function canCall(address /* caller */, address /* target */, bytes4 /* selector */) external view {} +} + +contract AuthoritiyObserveIsConsuming { + event ConsumeScheduledOpCalled(address caller, bytes data, bytes4 isConsuming); + + function canCall( + address /* caller */, + address /* target */, + bytes4 /* selector */ + ) external pure returns (bool immediate, uint32 delay) { + return (false, 1); + } + + function consumeScheduledOp(address caller, bytes memory data) public { + emit ConsumeScheduledOpCalled(caller, data, IAccessManaged(msg.sender).isConsumingScheduledOp()); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol b/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol new file mode 100644 index 0000000..e371c7d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract CallReceiverMock { + event MockFunctionCalled(); + event MockFunctionCalledWithArgs(uint256 a, uint256 b); + + uint256[] private _array; + + function mockFunction() public payable returns (string memory) { + emit MockFunctionCalled(); + + return "0x1234"; + } + + function mockFunctionEmptyReturn() public payable { + emit MockFunctionCalled(); + } + + function mockFunctionWithArgs(uint256 a, uint256 b) public payable returns (string memory) { + emit MockFunctionCalledWithArgs(a, b); + + return "0x1234"; + } + + function mockFunctionNonPayable() public returns (string memory) { + emit MockFunctionCalled(); + + return "0x1234"; + } + + function mockStaticFunction() public pure returns (string memory) { + return "0x1234"; + } + + function mockFunctionRevertsNoReason() public payable { + revert(); + } + + function mockFunctionRevertsReason() public payable { + revert("CallReceiverMock: reverting"); + } + + function mockFunctionThrows() public payable { + assert(false); + } + + function mockFunctionOutOfGas() public payable { + for (uint256 i = 0; ; ++i) { + _array.push(i); + } + } + + function mockFunctionWritesStorage(bytes32 slot, bytes32 value) public returns (string memory) { + assembly { + sstore(slot, value) + } + return "0x1234"; + } +} + +contract CallReceiverMockTrustingForwarder is CallReceiverMock { + address private _trustedForwarder; + + constructor(address trustedForwarder_) { + _trustedForwarder = trustedForwarder_; + } + + function isTrustedForwarder(address forwarder) public view virtual returns (bool) { + return forwarder == _trustedForwarder; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol b/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol new file mode 100644 index 0000000..199b2a9 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ContextMock.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +contract ContextMock is Context { + event Sender(address sender); + + function msgSender() public { + emit Sender(_msgSender()); + } + + event Data(bytes data, uint256 integerValue, string stringValue); + + function msgData(uint256 integerValue, string memory stringValue) public { + emit Data(_msgData(), integerValue, stringValue); + } + + event DataShort(bytes data); + + function msgDataShort() public { + emit DataShort(_msgData()); + } +} + +contract ContextMockCaller { + function callSender(ContextMock context) public { + context.msgSender(); + } + + function callData(ContextMock context, uint256 integerValue, string memory stringValue) public { + context.msgData(integerValue, stringValue); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol b/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol new file mode 100644 index 0000000..4925c89 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; + +abstract contract Impl { + function version() public pure virtual returns (string memory); +} + +contract DummyImplementation { + uint256 public value; + string public text; + uint256[] public values; + + function initializeNonPayable() public { + value = 10; + } + + function initializePayable() public payable { + value = 100; + } + + function initializeNonPayableWithValue(uint256 _value) public { + value = _value; + } + + function initializePayableWithValue(uint256 _value) public payable { + value = _value; + } + + function initialize(uint256 _value, string memory _text, uint256[] memory _values) public { + value = _value; + text = _text; + values = _values; + } + + function get() public pure returns (bool) { + return true; + } + + function version() public pure virtual returns (string memory) { + return "V1"; + } + + function reverts() public pure { + require(false, "DummyImplementation reverted"); + } + + // Use for forcing an unsafe TransparentUpgradeableProxy admin override + function unsafeOverrideAdmin(address newAdmin) public { + StorageSlot.getAddressSlot(ERC1967Utils.ADMIN_SLOT).value = newAdmin; + } +} + +contract DummyImplementationV2 is DummyImplementation { + function migrate(uint256 newVal) public payable { + value = newVal; + } + + function version() public pure override returns (string memory) { + return "V2"; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol b/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol new file mode 100644 index 0000000..fe32a21 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../utils/cryptography/EIP712.sol"; + +abstract contract EIP712Verifier is EIP712 { + function verify(bytes memory signature, address signer, address mailTo, string memory mailContents) external view { + bytes32 digest = _hashTypedDataV4( + keccak256(abi.encode(keccak256("Mail(address to,string contents)"), mailTo, keccak256(bytes(mailContents)))) + ); + address recoveredSigner = ECDSA.recover(digest, signature); + require(recoveredSigner == signer); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol b/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol new file mode 100644 index 0000000..cba7d47 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Ownable} from "../access/Ownable.sol"; +import {IERC1271} from "../interfaces/IERC1271.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; + +contract ERC1271WalletMock is Ownable, IERC1271 { + constructor(address originalOwner) Ownable(originalOwner) {} + + function isValidSignature(bytes32 hash, bytes memory signature) public view returns (bytes4 magicValue) { + return ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0); + } +} + +contract ERC1271MaliciousMock is IERC1271 { + function isValidSignature(bytes32, bytes memory) public pure returns (bytes4) { + assembly { + mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0, 32) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol new file mode 100644 index 0000000..4010b21 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165InterfacesSupported.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * https://eips.ethereum.org/EIPS/eip-214#specification + * From the specification: + * > Any attempts to make state-changing operations inside an execution instance with STATIC set to true will instead + * throw an exception. + * > These operations include [...], LOG0, LOG1, LOG2, [...] + * + * therefore, because this contract is staticcall'd we need to not emit events (which is how solidity-coverage works) + * solidity-coverage ignores the /mocks folder, so we duplicate its implementation here to avoid instrumenting it + */ +contract SupportsInterfaceWithLookupMock is IERC165 { + /* + * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7 + */ + bytes4 public constant INTERFACE_ID_ERC165 = 0x01ffc9a7; + + /** + * @dev A mapping of interface id to whether or not it's supported. + */ + mapping(bytes4 interfaceId => bool) private _supportedInterfaces; + + /** + * @dev A contract implementing SupportsInterfaceWithLookup + * implement ERC165 itself. + */ + constructor() { + _registerInterface(INTERFACE_ID_ERC165); + } + + /** + * @dev Implement supportsInterface(bytes4) using a lookup table. + */ + function supportsInterface(bytes4 interfaceId) public view override returns (bool) { + return _supportedInterfaces[interfaceId]; + } + + /** + * @dev Private method for registering an interface. + */ + function _registerInterface(bytes4 interfaceId) internal { + require(interfaceId != 0xffffffff, "ERC165InterfacesSupported: invalid interface id"); + _supportedInterfaces[interfaceId] = true; + } +} + +contract ERC165InterfacesSupported is SupportsInterfaceWithLookupMock { + constructor(bytes4[] memory interfaceIds) { + for (uint256 i = 0; i < interfaceIds.length; i++) { + _registerInterface(interfaceIds[i]); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol new file mode 100644 index 0000000..3542756 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MaliciousData.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ERC165MaliciousData { + function supportsInterface(bytes4) public pure returns (bool) { + assembly { + mstore(0, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) + return(0, 32) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol new file mode 100644 index 0000000..fec4339 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165MissingData.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ERC165MissingData { + function supportsInterface(bytes4 interfaceId) public view {} // missing return +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol new file mode 100644 index 0000000..78ef9c8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165NotSupported.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ERC165NotSupported {} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol new file mode 100644 index 0000000..4bfacfd --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ERC165/ERC165ReturnBomb.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +contract ERC165ReturnBombMock is IERC165 { + function supportsInterface(bytes4 interfaceId) public pure override returns (bool) { + if (interfaceId == type(IERC165).interfaceId) { + assembly { + mstore(0, 1) + } + } + assembly { + return(0, 101500) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol b/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol new file mode 100644 index 0000000..22b9203 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ContextMock} from "./ContextMock.sol"; +import {Context} from "../utils/Context.sol"; +import {ERC2771Context} from "../metatx/ERC2771Context.sol"; + +// By inheriting from ERC2771Context, Context's internal functions are overridden automatically +contract ERC2771ContextMock is ContextMock, ERC2771Context { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor(address trustedForwarder) ERC2771Context(trustedForwarder) { + emit Sender(_msgSender()); // _msgSender() should be accessible during construction + } + + function _msgSender() internal view override(Context, ERC2771Context) returns (address) { + return ERC2771Context._msgSender(); + } + + function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) { + return ERC2771Context._msgData(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol b/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol new file mode 100644 index 0000000..261fea1 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC20} from "../token/ERC20/IERC20.sol"; +import {IERC3156FlashBorrower} from "../interfaces/IERC3156.sol"; +import {Address} from "../utils/Address.sol"; + +/** + * @dev WARNING: this IERC3156FlashBorrower mock implementation is for testing purposes ONLY. + * Writing a secure flash lock borrower is not an easy task, and should be done with the utmost care. + * This is not an example of how it should be done, and no pattern present in this mock should be considered secure. + * Following best practices, always have your contract properly audited before using them to manipulate important funds on + * live networks. + */ +contract ERC3156FlashBorrowerMock is IERC3156FlashBorrower { + bytes32 internal constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + bool immutable _enableApprove; + bool immutable _enableReturn; + + event BalanceOf(address token, address account, uint256 value); + event TotalSupply(address token, uint256 value); + + constructor(bool enableReturn, bool enableApprove) { + _enableApprove = enableApprove; + _enableReturn = enableReturn; + } + + function onFlashLoan( + address /*initiator*/, + address token, + uint256 amount, + uint256 fee, + bytes calldata data + ) public returns (bytes32) { + require(msg.sender == token); + + emit BalanceOf(token, address(this), IERC20(token).balanceOf(address(this))); + emit TotalSupply(token, IERC20(token).totalSupply()); + + if (data.length > 0) { + // WARNING: This code is for testing purposes only! Do not use. + Address.functionCall(token, data); + } + + if (_enableApprove) { + IERC20(token).approve(token, amount + fee); + } + + return _enableReturn ? _RETURN_VALUE : bytes32(0); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol b/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol new file mode 100644 index 0000000..1b1c936 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract EtherReceiverMock { + bool private _acceptEther; + + function setAcceptEther(bool acceptEther) public { + _acceptEther = acceptEther; + } + + receive() external payable { + if (!_acceptEther) { + revert(); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol b/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol new file mode 100644 index 0000000..7f76caa --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/InitializableMock.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "../proxy/utils/Initializable.sol"; + +/** + * @title InitializableMock + * @dev This contract is a mock to test initializable functionality + */ +contract InitializableMock is Initializable { + bool public initializerRan; + bool public onlyInitializingRan; + uint256 public x; + + function isInitializing() public view returns (bool) { + return _isInitializing(); + } + + function initialize() public initializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyInitializing { + onlyInitializingRan = true; + } + + function initializerNested() public initializer { + initialize(); + } + + function onlyInitializingNested() public initializer { + initializeOnlyInitializing(); + } + + function initializeWithX(uint256 _x) public payable initializer { + x = _x; + } + + function nonInitializable(uint256 _x) public payable { + x = _x; + } + + function fail() public pure { + require(false, "InitializableMock forced failure"); + } +} + +contract ConstructorInitializableMock is Initializable { + bool public initializerRan; + bool public onlyInitializingRan; + + constructor() initializer { + initialize(); + initializeOnlyInitializing(); + } + + function initialize() public initializer { + initializerRan = true; + } + + function initializeOnlyInitializing() public onlyInitializing { + onlyInitializingRan = true; + } +} + +contract ChildConstructorInitializableMock is ConstructorInitializableMock { + bool public childInitializerRan; + + constructor() initializer { + childInitialize(); + } + + function childInitialize() public initializer { + childInitializerRan = true; + } +} + +contract ReinitializerMock is Initializable { + uint256 public counter; + + function getInitializedVersion() public view returns (uint64) { + return _getInitializedVersion(); + } + + function initialize() public initializer { + doStuff(); + } + + function reinitialize(uint64 i) public reinitializer(i) { + doStuff(); + } + + function nestedReinitialize(uint64 i, uint64 j) public reinitializer(i) { + reinitialize(j); + } + + function chainReinitialize(uint64 i, uint64 j) public { + reinitialize(i); + reinitialize(j); + } + + function disableInitializers() public { + _disableInitializers(); + } + + function doStuff() public onlyInitializing { + counter++; + } +} + +contract DisableNew is Initializable { + constructor() { + _disableInitializers(); + } +} + +contract DisableOld is Initializable { + constructor() initializer {} +} + +contract DisableBad1 is DisableNew, DisableOld {} + +contract DisableBad2 is Initializable { + constructor() initializer { + _disableInitializers(); + } +} + +contract DisableOk is DisableOld, DisableNew {} diff --git a/lib/openzeppelin-contracts/contracts/mocks/MulticallTest.sol b/lib/openzeppelin-contracts/contracts/mocks/MulticallTest.sol new file mode 100644 index 0000000..74be7d8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/MulticallTest.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20MulticallMock} from "./token/ERC20MulticallMock.sol"; + +contract MulticallTest { + function checkReturnValues( + ERC20MulticallMock multicallToken, + address[] calldata recipients, + uint256[] calldata amounts + ) external { + bytes[] memory calls = new bytes[](recipients.length); + for (uint256 i = 0; i < recipients.length; i++) { + calls[i] = abi.encodeCall(multicallToken.transfer, (recipients[i], amounts[i])); + } + + bytes[] memory results = multicallToken.multicall(calls); + for (uint256 i = 0; i < results.length; i++) { + require(abi.decode(results[i], (bool))); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol b/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..51030ac --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "../proxy/utils/Initializable.sol"; + +// Sample contracts showing upgradeability with multiple inheritance. +// Child contract inherits from Father and Mother contracts, and Father extends from Gramps. +// +// Human +// / \ +// | Gramps +// | | +// Mother Father +// | | +// -- Child -- + +/** + * Sample base initializable contract that is a human + */ +contract SampleHuman is Initializable { + bool public isHuman; + + function initialize() public initializer { + __SampleHuman_init(); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleHuman_init() internal onlyInitializing { + __SampleHuman_init_unchained(); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleHuman_init_unchained() internal onlyInitializing { + isHuman = true; + } +} + +/** + * Sample base initializable contract that defines a field mother + */ +contract SampleMother is Initializable, SampleHuman { + uint256 public mother; + + function initialize(uint256 value) public initializer { + __SampleMother_init(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleMother_init(uint256 value) internal onlyInitializing { + __SampleHuman_init(); + __SampleMother_init_unchained(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleMother_init_unchained(uint256 value) internal onlyInitializing { + mother = value; + } +} + +/** + * Sample base initializable contract that defines a field gramps + */ +contract SampleGramps is Initializable, SampleHuman { + string public gramps; + + function initialize(string memory value) public initializer { + __SampleGramps_init(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleGramps_init(string memory value) internal onlyInitializing { + __SampleHuman_init(); + __SampleGramps_init_unchained(value); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleGramps_init_unchained(string memory value) internal onlyInitializing { + gramps = value; + } +} + +/** + * Sample base initializable contract that defines a field father and extends from gramps + */ +contract SampleFather is Initializable, SampleGramps { + uint256 public father; + + function initialize(string memory _gramps, uint256 _father) public initializer { + __SampleFather_init(_gramps, _father); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleFather_init(string memory _gramps, uint256 _father) internal onlyInitializing { + __SampleGramps_init(_gramps); + __SampleFather_init_unchained(_father); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleFather_init_unchained(uint256 _father) internal onlyInitializing { + father = _father; + } +} + +/** + * Child extends from mother, father (gramps) + */ +contract SampleChild is Initializable, SampleMother, SampleFather { + uint256 public child; + + function initialize(uint256 _mother, string memory _gramps, uint256 _father, uint256 _child) public initializer { + __SampleChild_init(_mother, _gramps, _father, _child); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleChild_init( + uint256 _mother, + string memory _gramps, + uint256 _father, + uint256 _child + ) internal onlyInitializing { + __SampleMother_init(_mother); + __SampleFather_init(_gramps, _father); + __SampleChild_init_unchained(_child); + } + + // solhint-disable-next-line func-name-mixedcase + function __SampleChild_init_unchained(uint256 _child) internal onlyInitializing { + child = _child; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol b/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol new file mode 100644 index 0000000..fa701e2 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/PausableMock.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Pausable} from "../utils/Pausable.sol"; + +contract PausableMock is Pausable { + bool public drasticMeasureTaken; + uint256 public count; + + constructor() { + drasticMeasureTaken = false; + count = 0; + } + + function normalProcess() external whenNotPaused { + count++; + } + + function drasticMeasure() external whenPaused { + drasticMeasureTaken = true; + } + + function pause() external { + _pause(); + } + + function unpause() external { + _unpause(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol b/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol new file mode 100644 index 0000000..3df2d1c --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +contract ReentrancyAttack is Context { + function callSender(bytes calldata data) public { + (bool success, ) = _msgSender().call(data); + require(success, "ReentrancyAttack: failed call"); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol b/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol new file mode 100644 index 0000000..39e2d5e --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ReentrancyGuard} from "../utils/ReentrancyGuard.sol"; +import {ReentrancyAttack} from "./ReentrancyAttack.sol"; + +contract ReentrancyMock is ReentrancyGuard { + uint256 public counter; + + constructor() { + counter = 0; + } + + function callback() external nonReentrant { + _count(); + } + + function countLocalRecursive(uint256 n) public nonReentrant { + if (n > 0) { + _count(); + countLocalRecursive(n - 1); + } + } + + function countThisRecursive(uint256 n) public nonReentrant { + if (n > 0) { + _count(); + (bool success, ) = address(this).call(abi.encodeCall(this.countThisRecursive, (n - 1))); + require(success, "ReentrancyMock: failed call"); + } + } + + function countAndCall(ReentrancyAttack attacker) public nonReentrant { + _count(); + attacker.callSender(abi.encodeCall(this.callback, ())); + } + + function _count() private { + counter += 1; + } + + function guardedCheckEntered() public nonReentrant { + require(_reentrancyGuardEntered()); + } + + function unguardedCheckNotEntered() public view { + require(!_reentrancyGuardEntered()); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol b/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol new file mode 100644 index 0000000..19b9706 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "../proxy/utils/Initializable.sol"; + +contract Implementation1 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } +} + +contract Implementation2 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } +} + +contract Implementation3 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue(uint256 _number) public view returns (uint256) { + return _value + _number; + } +} + +contract Implementation4 is Initializable { + uint256 internal _value; + + function initialize() public initializer {} + + function setValue(uint256 _number) public { + _value = _number; + } + + function getValue() public view returns (uint256) { + return _value; + } + + fallback() external { + _value = 1; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol b/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol new file mode 100644 index 0000000..0bd3c61 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Initializable} from "../proxy/utils/Initializable.sol"; + +/** + * @title MigratableMockV1 + * @dev This contract is a mock to test initializable functionality through migrations + */ +contract MigratableMockV1 is Initializable { + uint256 public x; + + function initialize(uint256 value) public payable initializer { + x = value; + } +} + +/** + * @title MigratableMockV2 + * @dev This contract is a mock to test migratable functionality with params + */ +contract MigratableMockV2 is MigratableMockV1 { + bool internal _migratedV2; + uint256 public y; + + function migrate(uint256 value, uint256 anotherValue) public payable { + require(!_migratedV2); + x = value; + y = anotherValue; + _migratedV2 = true; + } +} + +/** + * @title MigratableMockV3 + * @dev This contract is a mock to test migratable functionality without params + */ +contract MigratableMockV3 is MigratableMockV2 { + bool internal _migratedV3; + + function migrate() public payable { + require(!_migratedV3); + uint256 oldX = x; + x = y; + y = oldX; + _migratedV3 = true; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol b/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol new file mode 100644 index 0000000..56f5b4c --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/Stateless.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +// We keep these imports and a dummy contract just to we can run the test suite after transpilation. + +import {Address} from "../utils/Address.sol"; +import {Arrays} from "../utils/Arrays.sol"; +import {AuthorityUtils} from "../access/manager/AuthorityUtils.sol"; +import {Base64} from "../utils/Base64.sol"; +import {BitMaps} from "../utils/structs/BitMaps.sol"; +import {Checkpoints} from "../utils/structs/Checkpoints.sol"; +import {Clones} from "../proxy/Clones.sol"; +import {Create2} from "../utils/Create2.sol"; +import {DoubleEndedQueue} from "../utils/structs/DoubleEndedQueue.sol"; +import {ECDSA} from "../utils/cryptography/ECDSA.sol"; +import {EnumerableMap} from "../utils/structs/EnumerableMap.sol"; +import {EnumerableSet} from "../utils/structs/EnumerableSet.sol"; +import {ERC1155Holder} from "../token/ERC1155/utils/ERC1155Holder.sol"; +import {ERC165} from "../utils/introspection/ERC165.sol"; +import {ERC165Checker} from "../utils/introspection/ERC165Checker.sol"; +import {ERC1967Utils} from "../proxy/ERC1967/ERC1967Utils.sol"; +import {ERC721Holder} from "../token/ERC721/utils/ERC721Holder.sol"; +import {Math} from "../utils/math/Math.sol"; +import {MerkleProof} from "../utils/cryptography/MerkleProof.sol"; +import {MessageHashUtils} from "../utils/cryptography/MessageHashUtils.sol"; +import {SafeCast} from "../utils/math/SafeCast.sol"; +import {SafeERC20} from "../token/ERC20/utils/SafeERC20.sol"; +import {ShortStrings} from "../utils/ShortStrings.sol"; +import {SignatureChecker} from "../utils/cryptography/SignatureChecker.sol"; +import {SignedMath} from "../utils/math/SignedMath.sol"; +import {StorageSlot} from "../utils/StorageSlot.sol"; +import {Strings} from "../utils/Strings.sol"; +import {Time} from "../utils/types/Time.sol"; + +contract Dummy1234 {} diff --git a/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol b/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol new file mode 100644 index 0000000..dbdad7a --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {StorageSlot} from "../utils/StorageSlot.sol"; + +contract StorageSlotMock { + using StorageSlot for *; + + function setBoolean(bytes32 slot, bool value) public { + slot.getBooleanSlot().value = value; + } + + function setAddress(bytes32 slot, address value) public { + slot.getAddressSlot().value = value; + } + + function setBytes32(bytes32 slot, bytes32 value) public { + slot.getBytes32Slot().value = value; + } + + function setUint256(bytes32 slot, uint256 value) public { + slot.getUint256Slot().value = value; + } + + function getBoolean(bytes32 slot) public view returns (bool) { + return slot.getBooleanSlot().value; + } + + function getAddress(bytes32 slot) public view returns (address) { + return slot.getAddressSlot().value; + } + + function getBytes32(bytes32 slot) public view returns (bytes32) { + return slot.getBytes32Slot().value; + } + + function getUint256(bytes32 slot) public view returns (uint256) { + return slot.getUint256Slot().value; + } + + mapping(uint256 key => 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 key => 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/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol b/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol new file mode 100644 index 0000000..aab676a --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Address} from "../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/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol b/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol new file mode 100644 index 0000000..354ac02 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IBeacon} from "../proxy/beacon/IBeacon.sol"; + +contract UpgradeableBeaconMock is IBeacon { + address public implementation; + + constructor(address impl) { + implementation = impl; + } +} + +interface IProxyExposed { + // solhint-disable-next-line func-name-mixedcase + function $getBeacon() external view returns (address); +} + +contract UpgradeableBeaconReentrantMock is IBeacon { + error BeaconProxyBeaconSlotAddress(address beacon); + + function implementation() external view override returns (address) { + // Revert with the beacon seen in the proxy at the moment of calling to check if it's + // set before the call. + revert BeaconProxyBeaconSlotAddress(IProxyExposed(msg.sender).$getBeacon()); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol b/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol new file mode 100644 index 0000000..e28d6b5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/VotesMock.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Votes} from "../governance/utils/Votes.sol"; + +abstract contract VotesMock is Votes { + mapping(address voter => uint256) private _votingUnits; + + function getTotalSupply() public view returns (uint256) { + return _getTotalSupply(); + } + + function delegate(address account, address newDelegation) public { + return _delegate(account, newDelegation); + } + + function _getVotingUnits(address account) internal view override returns (uint256) { + return _votingUnits[account]; + } + + function _mint(address account, uint256 votes) internal { + _votingUnits[account] += votes; + _transferVotingUnits(address(0), account, votes); + } + + function _burn(address account, uint256 votes) internal { + _votingUnits[account] += votes; + _transferVotingUnits(account, address(0), votes); + } +} + +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/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol b/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol new file mode 100644 index 0000000..c72ed08 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: BSD-3-Clause +// solhint-disable private-vars-leading-underscore +/** + * Copyright 2020 Compound Labs, Inc. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +pragma solidity ^0.8.20; + +contract CompTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + + uint256 public constant GRACE_PERIOD = 14 days; + uint256 public constant MINIMUM_DELAY = 2 days; + uint256 public constant MAXIMUM_DELAY = 30 days; + + address public admin; + address public pendingAdmin; + uint256 public delay; + + mapping(bytes32 => bool) public queuedTransactions; + + constructor(address admin_, uint256 delay_) { + require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay."); + require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); + + admin = admin_; + delay = delay_; + } + + receive() external payable {} + + function setDelay(uint256 delay_) public { + require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock."); + require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay."); + require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay."); + delay = delay_; + + emit NewDelay(delay); + } + + function acceptAdmin() public { + require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin."); + admin = msg.sender; + pendingAdmin = address(0); + + emit NewAdmin(admin); + } + + function setPendingAdmin(address pendingAdmin_) public { + require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock."); + pendingAdmin = pendingAdmin_; + + emit NewPendingAdmin(pendingAdmin); + } + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public returns (bytes32) { + require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin."); + require( + eta >= getBlockTimestamp() + delay, + "Timelock::queueTransaction: Estimated execution block must satisfy delay." + ); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + queuedTransactions[txHash] = true; + + emit QueueTransaction(txHash, target, value, signature, data, eta); + return txHash; + } + + function cancelTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public { + require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin."); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + queuedTransactions[txHash] = false; + + emit CancelTransaction(txHash, target, value, signature, data, eta); + } + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) public payable returns (bytes memory) { + require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin."); + + bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta)); + require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued."); + require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock."); + require(getBlockTimestamp() <= eta + GRACE_PERIOD, "Timelock::executeTransaction: Transaction is stale."); + + queuedTransactions[txHash] = false; + + bytes memory callData; + + if (bytes(signature).length == 0) { + callData = data; + } else { + callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data); + } + + // solium-disable-next-line security/no-call-value + (bool success, bytes memory returnData) = target.call{value: value}(callData); + require(success, "Timelock::executeTransaction: Transaction execution reverted."); + + emit ExecuteTransaction(txHash, target, value, signature, data, eta); + + return returnData; + } + + function getBlockTimestamp() internal view returns (uint256) { + // solium-disable-next-line security/no-block-members + return block.timestamp; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol new file mode 100644 index 0000000..69668d2 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorMock is GovernorSettings, GovernorVotesQuorumFraction, GovernorCountingSimple { + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol new file mode 100644 index 0000000..fde0863 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorPreventLateQuorum} from "../../governance/extensions/GovernorPreventLateQuorum.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorPreventLateQuorumMock is + GovernorSettings, + GovernorVotes, + GovernorCountingSimple, + GovernorPreventLateQuorum +{ + uint256 private _quorum; + + constructor(uint256 quorum_) { + _quorum = quorum_; + } + + function quorum(uint256) public view override returns (uint256) { + return _quorum; + } + + function proposalDeadline( + uint256 proposalId + ) public view override(Governor, GovernorPreventLateQuorum) returns (uint256) { + return super.proposalDeadline(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function _castVote( + uint256 proposalId, + address account, + uint8 support, + string memory reason, + bytes memory params + ) internal override(Governor, GovernorPreventLateQuorum) returns (uint256) { + return super._castVote(proposalId, account, support, reason, params); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol new file mode 100644 index 0000000..88c6bf9 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.19; + +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockControl} from "../../governance/extensions/GovernorTimelockControl.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; +import {GovernorStorage} from "../../governance/extensions/GovernorStorage.sol"; + +abstract contract GovernorStorageMock is + GovernorSettings, + GovernorTimelockControl, + GovernorVotesQuorumFraction, + GovernorCountingSimple, + GovernorStorage +{ + function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalNeedsQueuing( + uint256 proposalId + ) public view virtual override(Governor, GovernorTimelockControl) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } + + function _propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description, + address proposer + ) internal virtual override(Governor, GovernorStorage) returns (uint256) { + return super._propose(targets, values, calldatas, description, proposer); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockControl) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockControl) { + super._executeOperations(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(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol new file mode 100644 index 0000000..3d1bbee --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockAccess} from "../../governance/extensions/GovernorTimelockAccess.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockAccessMock is + GovernorSettings, + GovernorTimelockAccess, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function nonGovernanceFunction() external {} + + function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalNeedsQueuing( + uint256 proposalId + ) public view virtual override(Governor, GovernorTimelockAccess) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } + + function propose( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + string memory description + ) public override(Governor, GovernorTimelockAccess) returns (uint256) { + return super.propose(targets, values, calldatas, description); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockAccess) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockAccess) { + super._executeOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _cancel( + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockAccess) returns (uint256) { + return super._cancel(targets, values, calldatas, descriptionHash); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol new file mode 100644 index 0000000..03ef625 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockCompound} from "../../governance/extensions/GovernorTimelockCompound.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockCompoundMock is + GovernorSettings, + GovernorTimelockCompound, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state( + uint256 proposalId + ) public view override(Governor, GovernorTimelockCompound) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalNeedsQueuing( + uint256 proposalId + ) public view virtual override(Governor, GovernorTimelockCompound) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockCompound) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockCompound) { + super._executeOperations(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(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol new file mode 100644 index 0000000..edaccc0 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IGovernor, Governor} from "../../governance/Governor.sol"; +import {GovernorTimelockControl} from "../../governance/extensions/GovernorTimelockControl.sol"; +import {GovernorSettings} from "../../governance/extensions/GovernorSettings.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotesQuorumFraction} from "../../governance/extensions/GovernorVotesQuorumFraction.sol"; + +abstract contract GovernorTimelockControlMock is + GovernorSettings, + GovernorTimelockControl, + GovernorVotesQuorumFraction, + GovernorCountingSimple +{ + function quorum(uint256 blockNumber) public view override(Governor, GovernorVotesQuorumFraction) returns (uint256) { + return super.quorum(blockNumber); + } + + function state(uint256 proposalId) public view override(Governor, GovernorTimelockControl) returns (ProposalState) { + return super.state(proposalId); + } + + function proposalThreshold() public view override(Governor, GovernorSettings) returns (uint256) { + return super.proposalThreshold(); + } + + function proposalNeedsQueuing( + uint256 proposalId + ) public view virtual override(Governor, GovernorTimelockControl) returns (bool) { + return super.proposalNeedsQueuing(proposalId); + } + + function _queueOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockControl) returns (uint48) { + return super._queueOperations(proposalId, targets, values, calldatas, descriptionHash); + } + + function _executeOperations( + uint256 proposalId, + address[] memory targets, + uint256[] memory values, + bytes[] memory calldatas, + bytes32 descriptionHash + ) internal override(Governor, GovernorTimelockControl) { + super._executeOperations(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 nonGovernanceFunction() external {} +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol new file mode 100644 index 0000000..e6949b5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorVoteMocks is GovernorVotes, GovernorCountingSimple { + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol new file mode 100644 index 0000000..d535f81 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Governor} from "../../governance/Governor.sol"; +import {GovernorCountingSimple} from "../../governance/extensions/GovernorCountingSimple.sol"; +import {GovernorVotes} from "../../governance/extensions/GovernorVotes.sol"; + +abstract contract GovernorWithParamsMock is GovernorVotes, GovernorCountingSimple { + event CountParams(uint256 uintParam, string strParam); + + function quorum(uint256) public pure override returns (uint256) { + return 0; + } + + function votingDelay() public pure override returns (uint256) { + return 4; + } + + function votingPeriod() public pure override returns (uint256) { + return 16; + } + + function _getVotes( + address account, + uint256 blockNumber, + bytes memory params + ) internal view override(Governor, GovernorVotes) returns (uint256) { + uint256 reduction = 0; + // If the user provides parameters, we reduce the voting weight by the amount of the integer param + if (params.length > 0) { + (reduction, ) = abi.decode(params, (uint256, string)); + } + // reverts on overflow + return super._getVotes(account, blockNumber, params) - reduction; + } + + function _countVote( + uint256 proposalId, + address account, + uint8 support, + uint256 weight, + bytes memory params + ) internal override(Governor, GovernorCountingSimple) { + if (params.length > 0) { + (uint256 _uintParam, string memory _strParam) = abi.decode(params, (uint256, string)); + emit CountParams(_uintParam, _strParam); + } + return super._countVote(proposalId, account, support, weight, params); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol b/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol new file mode 100644 index 0000000..f3153a8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract BadBeaconNoImpl {} + +contract BadBeaconNotContract { + function implementation() external pure returns (address) { + return address(0x1); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol b/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol new file mode 100644 index 0000000..43d5a34 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +/** + * @dev Implementation contract with a payable changeAdmin(address) function made to clash with + * TransparentUpgradeableProxy's to test correct functioning of the Transparent Proxy feature. + */ +contract ClashingImplementation { + event ClashingImplementationCall(); + + function upgradeToAndCall(address, bytes calldata) external payable { + emit ClashingImplementationCall(); + } + + function delegatedFunction() external pure returns (bool) { + return true; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol b/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol new file mode 100644 index 0000000..a5f2d4a --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {UUPSUpgradeable} from "../../proxy/utils/UUPSUpgradeable.sol"; +import {ERC1967Utils} from "../../proxy/ERC1967/ERC1967Utils.sol"; + +contract NonUpgradeableMock { + uint256 internal _counter; + + function current() external view returns (uint256) { + return _counter; + } + + function increment() external { + ++_counter; + } +} + +contract UUPSUpgradeableMock is NonUpgradeableMock, UUPSUpgradeable { + // Not having any checks in this function is dangerous! Do not do this outside tests! + function _authorizeUpgrade(address) internal override {} +} + +contract UUPSUpgradeableUnsafeMock is UUPSUpgradeableMock { + function upgradeToAndCall(address newImplementation, bytes memory data) public payable override { + ERC1967Utils.upgradeToAndCall(newImplementation, data); + } +} + +contract UUPSUnsupportedProxiableUUID is UUPSUpgradeableMock { + function proxiableUUID() external pure override returns (bytes32) { + return keccak256("invalid UUID"); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol new file mode 100644 index 0000000..2a85d1d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC1155Receiver} from "../../token/ERC1155/IERC1155Receiver.sol"; +import {ERC165} from "../../utils/introspection/ERC165.sol"; + +contract ERC1155ReceiverMock is ERC165, IERC1155Receiver { + enum RevertType { + None, + RevertWithoutMessage, + RevertWithMessage, + RevertWithCustomError, + Panic + } + + bytes4 private immutable _recRetval; + bytes4 private immutable _batRetval; + RevertType private immutable _error; + + event Received(address operator, address from, uint256 id, uint256 value, bytes data, uint256 gas); + event BatchReceived(address operator, address from, uint256[] ids, uint256[] values, bytes data, uint256 gas); + error CustomError(bytes4); + + constructor(bytes4 recRetval, bytes4 batRetval, RevertType error) { + _recRetval = recRetval; + _batRetval = batRetval; + _error = error; + } + + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4) { + if (_error == RevertType.RevertWithoutMessage) { + revert(); + } else if (_error == RevertType.RevertWithMessage) { + revert("ERC1155ReceiverMock: reverting on receive"); + } else if (_error == RevertType.RevertWithCustomError) { + revert CustomError(_recRetval); + } else if (_error == RevertType.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + + emit Received(operator, from, id, value, data, gasleft()); + return _recRetval; + } + + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4) { + if (_error == RevertType.RevertWithoutMessage) { + revert(); + } else if (_error == RevertType.RevertWithMessage) { + revert("ERC1155ReceiverMock: reverting on batch receive"); + } else if (_error == RevertType.RevertWithCustomError) { + revert CustomError(_recRetval); + } else if (_error == RevertType.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + + emit BatchReceived(operator, from, ids, values, data, gasleft()); + return _batRetval; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol new file mode 100644 index 0000000..ff33a36 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20ApprovalMock is ERC20 { + function _approve(address owner, address spender, uint256 amount, bool) internal virtual override { + super._approve(owner, spender, amount, true); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol new file mode 100644 index 0000000..a26e1f5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20DecimalsMock is ERC20 { + uint8 private immutable _decimals; + + constructor(uint8 decimals_) { + _decimals = decimals_; + } + + function decimals() public view override returns (uint8) { + return _decimals; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol new file mode 100644 index 0000000..4627efd --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract ERC20ExcessDecimalsMock { + function decimals() public pure returns (uint256) { + return type(uint256).max; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol new file mode 100644 index 0000000..508573c --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20FlashMint} from "../../token/ERC20/extensions/ERC20FlashMint.sol"; + +abstract contract ERC20FlashMintMock is ERC20FlashMint { + uint256 _flashFeeAmount; + address _flashFeeReceiverAddress; + + function setFlashFee(uint256 amount) public { + _flashFeeAmount = amount; + } + + function _flashFee(address, uint256) internal view override returns (uint256) { + return _flashFeeAmount; + } + + function setFlashFeeReceiver(address receiver) public { + _flashFeeReceiverAddress = receiver; + } + + function _flashFeeReceiver() internal view override returns (address) { + return _flashFeeReceiverAddress; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol new file mode 100644 index 0000000..36c0f57 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +// contract that replicate USDT (0xdac17f958d2ee523a2206206994597c13d831ec7) approval behavior +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/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol new file mode 100644 index 0000000..39ab129 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +contract ERC20Mock is ERC20 { + constructor() ERC20("ERC20Mock", "E20M") {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol new file mode 100644 index 0000000..dce3e70 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; +import {Multicall} from "../../utils/Multicall.sol"; + +abstract contract ERC20MulticallMock is ERC20, Multicall {} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol new file mode 100644 index 0000000..2129537 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20NoReturnMock is ERC20 { + function transfer(address to, uint256 amount) public override returns (bool) { + super.transfer(to, amount); + assembly { + return(0, 0) + } + } + + 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/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol new file mode 100644 index 0000000..813913f --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; +import {Address} from "../../utils/Address.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 _update(address from, address to, uint256 amount) internal override { + if (_reenterType == Type.Before) { + _reenterType = Type.No; + functionCall(_reenterTarget, _reenterData); + } + super._update(from, to, amount); + if (_reenterType == Type.After) { + _reenterType = Type.No; + functionCall(_reenterTarget, _reenterData); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol new file mode 100644 index 0000000..94bff32 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20} from "../../token/ERC20/ERC20.sol"; + +abstract contract ERC20ReturnFalseMock is ERC20 { + function transfer(address, uint256) public pure override returns (bool) { + return false; + } + + function transferFrom(address, address, uint256) public pure override returns (bool) { + return false; + } + + function approve(address, uint256) public pure override returns (bool) { + return false; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol new file mode 100644 index 0000000..3246fd4 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sol @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20Permit} from "../../token/ERC20/extensions/ERC20Permit.sol"; +import {Math} from "../../utils/math/Math.sol"; +import {IVotes} from "../../governance/utils/IVotes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.sol"; +import {ECDSA} from "../../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 account => address) private _delegatee; + mapping(address delegatee => 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 returns (address) { + return _delegatee[account]; + } + + /** + * @dev Gets the current votes balance for `account` + */ + function getVotes(address account) public view virtual 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 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 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 { + _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 { + 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 Move voting power when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _update(address from, address to, uint256 amount) internal virtual override { + super._update(from, to, amount); + + if (from == address(0)) { + require(totalSupply() <= _maxSupply(), "ERC20Votes: total supply risks overflowing votes"); + _writeCheckpoint(_totalSupplyCheckpoints, _add, amount); + } + + if (to == address(0)) { + _writeCheckpoint(_totalSupplyCheckpoints, _subtract, 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); + _delegatee[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/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol new file mode 100644 index 0000000..a845365 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; + +abstract contract ERC4626LimitsMock is ERC4626 { + uint256 _maxDeposit; + uint256 _maxMint; + + constructor() { + _maxDeposit = 100 ether; + _maxMint = 100 ether; + } + + function maxDeposit(address) public view override returns (uint256) { + return _maxDeposit; + } + + function maxMint(address) public view override returns (uint256) { + return _maxMint; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol new file mode 100644 index 0000000..22ac5e8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {IERC20, ERC20} from "../../token/ERC20/ERC20.sol"; +import {ERC4626} from "../../token/ERC20/extensions/ERC4626.sol"; + +contract ERC4626Mock is ERC4626 { + constructor(address underlying) ERC20("ERC4626Mock", "E4626M") ERC4626(IERC20(underlying)) {} + + function mint(address account, uint256 amount) external { + _mint(account, amount); + } + + function burn(address account, uint256 amount) external { + _burn(account, amount); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol new file mode 100644 index 0000000..3dde095 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC4626} from "../../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/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol new file mode 100644 index 0000000..368b078 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC4626Fees} from "../docs/ERC4626Fees.sol"; + +abstract contract ERC4626FeesMock is ERC4626Fees { + uint256 private immutable _entryFeeBasisPointValue; + address private immutable _entryFeeRecipientValue; + uint256 private immutable _exitFeeBasisPointValue; + address private immutable _exitFeeRecipientValue; + + constructor( + uint256 entryFeeBasisPoints, + address entryFeeRecipient, + uint256 exitFeeBasisPoints, + address exitFeeRecipient + ) { + _entryFeeBasisPointValue = entryFeeBasisPoints; + _entryFeeRecipientValue = entryFeeRecipient; + _exitFeeBasisPointValue = exitFeeBasisPoints; + _exitFeeRecipientValue = exitFeeRecipient; + } + + function _entryFeeBasisPoints() internal view virtual override returns (uint256) { + return _entryFeeBasisPointValue; + } + + function _entryFeeRecipient() internal view virtual override returns (address) { + return _entryFeeRecipientValue; + } + + function _exitFeeBasisPoints() internal view virtual override returns (uint256) { + return _exitFeeBasisPointValue; + } + + function _exitFeeRecipient() internal view virtual override returns (address) { + return _exitFeeRecipientValue; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol new file mode 100644 index 0000000..7732ae4 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721} from "../../token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import {ERC721Enumerable} from "../../token/ERC721/extensions/ERC721Enumerable.sol"; + +contract ERC721ConsecutiveEnumerableMock is ERC721Consecutive, ERC721Enumerable { + constructor( + string memory name, + string memory symbol, + address[] memory receivers, + uint96[] memory amounts + ) ERC721(name, symbol) { + for (uint256 i = 0; i < receivers.length; ++i) { + _mintConsecutive(receivers[i], amounts[i]); + } + } + + function supportsInterface( + bytes4 interfaceId + ) public view virtual override(ERC721, ERC721Enumerable) returns (bool) { + return super.supportsInterface(interfaceId); + } + + function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) { + return super._ownerOf(tokenId); + } + + function _update( + address to, + uint256 tokenId, + address auth + ) internal virtual override(ERC721Consecutive, ERC721Enumerable) returns (address) { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 amount) internal virtual override(ERC721, ERC721Enumerable) { + super._increaseBalance(account, amount); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol new file mode 100644 index 0000000..1098647 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721} from "../../token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "../../token/ERC721/extensions/ERC721Consecutive.sol"; +import {ERC721Pausable} from "../../token/ERC721/extensions/ERC721Pausable.sol"; +import {ERC721Votes} from "../../token/ERC721/extensions/ERC721Votes.sol"; +import {EIP712} from "../../utils/cryptography/EIP712.sol"; + +/** + * @title ERC721ConsecutiveMock + */ +contract ERC721ConsecutiveMock is ERC721Consecutive, ERC721Pausable, ERC721Votes { + uint96 private immutable _offset; + + constructor( + string memory name, + string memory symbol, + uint96 offset, + address[] memory delegates, + address[] memory receivers, + uint96[] memory amounts + ) ERC721(name, symbol) EIP712(name, "1") { + _offset = offset; + + for (uint256 i = 0; i < delegates.length; ++i) { + _delegate(delegates[i], delegates[i]); + } + + for (uint256 i = 0; i < receivers.length; ++i) { + _mintConsecutive(receivers[i], amounts[i]); + } + } + + function _firstConsecutiveId() internal view virtual override returns (uint96) { + return _offset; + } + + function _ownerOf(uint256 tokenId) internal view virtual override(ERC721, ERC721Consecutive) returns (address) { + return super._ownerOf(tokenId); + } + + function _update( + address to, + uint256 tokenId, + address auth + ) internal virtual override(ERC721Consecutive, ERC721Pausable, ERC721Votes) returns (address) { + return super._update(to, tokenId, auth); + } + + function _increaseBalance(address account, uint128 amount) internal virtual override(ERC721, ERC721Votes) { + super._increaseBalance(account, amount); + } +} + +contract ERC721ConsecutiveNoConstructorMintMock is ERC721Consecutive { + constructor(string memory name, string memory symbol) ERC721(name, symbol) { + _mint(msg.sender, 0); + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol new file mode 100644 index 0000000..14120f5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../../token/ERC721/IERC721Receiver.sol"; + +contract ERC721ReceiverMock is IERC721Receiver { + enum RevertType { + None, + RevertWithoutMessage, + RevertWithMessage, + RevertWithCustomError, + Panic + } + + bytes4 private immutable _retval; + RevertType private immutable _error; + + event Received(address operator, address from, uint256 tokenId, bytes data, uint256 gas); + error CustomError(bytes4); + + constructor(bytes4 retval, RevertType error) { + _retval = retval; + _error = error; + } + + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes memory data + ) public returns (bytes4) { + if (_error == RevertType.RevertWithoutMessage) { + revert(); + } else if (_error == RevertType.RevertWithMessage) { + revert("ERC721ReceiverMock: reverting"); + } else if (_error == RevertType.RevertWithCustomError) { + revert CustomError(_retval); + } else if (_error == RevertType.Panic) { + uint256 a = uint256(0) / uint256(0); + a; + } + + emit Received(operator, from, tokenId, data, gasleft()); + return _retval; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol b/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol new file mode 100644 index 0000000..254435e --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC721URIStorage} from "../../token/ERC721/extensions/ERC721URIStorage.sol"; + +abstract contract ERC721URIStorageMock is ERC721URIStorage { + string private _baseTokenURI; + + function _baseURI() internal view virtual override returns (string memory) { + return _baseTokenURI; + } + + function setBaseURI(string calldata newBaseTokenURI) public { + _baseTokenURI = newBaseTokenURI; + } +} diff --git a/lib/openzeppelin-contracts/contracts/mocks/token/VotesTimestamp.sol b/lib/openzeppelin-contracts/contracts/mocks/token/VotesTimestamp.sol new file mode 100644 index 0000000..78fdfae --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/mocks/token/VotesTimestamp.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {ERC20Votes} from "../../token/ERC20/extensions/ERC20Votes.sol"; +import {ERC721Votes} from "../../token/ERC721/extensions/ERC721Votes.sol"; +import {SafeCast} from "../../utils/math/SafeCast.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 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/lib/openzeppelin-contracts/contracts/package.json b/lib/openzeppelin-contracts/contracts/package.json new file mode 100644 index 0000000..be3e741 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/package.json @@ -0,0 +1,32 @@ +{ + "name": "@openzeppelin/contracts", + "description": "Secure Smart Contract library for Solidity", + "version": "5.0.0", + "files": [ + "**/*.sol", + "/build/contracts/*.json", + "!/mocks/**/*" + ], + "scripts": { + "prepack": "bash ../scripts/prepack.sh", + "prepare-docs": "cd ..; npm run prepare-docs" + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "security", + "zeppelin" + ], + "author": "OpenZeppelin Community ", + "license": "MIT", + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, + "homepage": "https://openzeppelin.com/contracts/" +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/Clones.sol b/lib/openzeppelin-contracts/contracts/proxy/Clones.sol new file mode 100644 index 0000000..95e467d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/Clones.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol) + +pragma solidity ^0.8.20; + +/** + * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for + * deploying minimal proxy contracts, also known as "clones". + * + * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies + * > a minimal bytecode implementation that delegates all calls to a known, fixed address. + * + * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` + * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the + * deterministic method. + */ +library Clones { + /** + * @dev A clone instance deployment failed. + */ + error ERC1167FailedCreateClone(); + + /** + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. + * + * This function uses the create opcode, which should never revert. + */ + function clone(address implementation) internal returns (address instance) { + /// @solidity memory-safe-assembly + assembly { + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create(0, 0x09, 0x37) + } + if (instance == address(0)) { + revert ERC1167FailedCreateClone(); + } + } + + /** + * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. + * + * This function uses the create2 opcode and a `salt` to deterministically deploy + * the clone. Using the same `implementation` and `salt` multiple time will revert, since + * the clones cannot be deployed twice at the same address. + */ + function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { + /// @solidity memory-safe-assembly + assembly { + // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes + // of the `implementation` address with the bytecode before the address. + mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) + // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. + mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) + instance := create2(0, 0x09, 0x37, salt) + } + if (instance == address(0)) { + revert ERC1167FailedCreateClone(); + } + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt, + address deployer + ) internal pure returns (address predicted) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(add(ptr, 0x38), deployer) + mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) + mstore(add(ptr, 0x14), implementation) + mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) + mstore(add(ptr, 0x58), salt) + mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) + predicted := keccak256(add(ptr, 0x43), 0x55) + } + } + + /** + * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes32 salt + ) internal view returns (address predicted) { + return predictDeterministicAddress(implementation, salt, address(this)); + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol b/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol new file mode 100644 index 0000000..0fa61b5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Proxy.sol) + +pragma solidity ^0.8.20; + +import {Proxy} from "../Proxy.sol"; +import {ERC1967Utils} from "./ERC1967Utils.sol"; + +/** + * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an + * implementation address that can be changed. This address is stored in storage in the location specified by + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the + * implementation behind the proxy. + */ +contract ERC1967Proxy is Proxy { + /** + * @dev Initializes the upgradeable proxy with an initial implementation specified by `implementation`. + * + * If `_data` is nonempty, it's used as data in a delegate call to `implementation`. This will typically be an + * encoded function call, and allows initializing the storage of the proxy like a Solidity constructor. + * + * Requirements: + * + * - If `data` is empty, `msg.value` must be zero. + */ + constructor(address implementation, bytes memory _data) payable { + ERC1967Utils.upgradeToAndCall(implementation, _data); + } + + /** + * @dev Returns the current implementation address. + * + * 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() internal view virtual override returns (address) { + return ERC1967Utils.getImplementation(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol b/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol new file mode 100644 index 0000000..e55bae2 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sol @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/ERC1967/ERC1967Utils.sol) + +pragma solidity ^0.8.20; + +import {IBeacon} from "../beacon/IBeacon.sol"; +import {Address} from "../../utils/Address.sol"; +import {StorageSlot} from "../../utils/StorageSlot.sol"; + +/** + * @dev This abstract contract provides getters and event emitting update functions for + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. + */ +library ERC1967Utils { + // We re-declare ERC-1967 events here because they can't be used directly from IERC1967. + // This will be fixed in Solidity 0.8.21. At that point we should remove these events. + /** + * @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); + + /** + * @dev Storage slot with the address of the current implementation. + * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. + */ + // solhint-disable-next-line private-vars-leading-underscore + bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + /** + * @dev The `implementation` of the proxy is invalid. + */ + error ERC1967InvalidImplementation(address implementation); + + /** + * @dev The `admin` of the proxy is invalid. + */ + error ERC1967InvalidAdmin(address admin); + + /** + * @dev The `beacon` of the proxy is invalid. + */ + error ERC1967InvalidBeacon(address beacon); + + /** + * @dev An upgrade function sees `msg.value > 0` that may be lost. + */ + error ERC1967NonPayable(); + + /** + * @dev Returns the current implementation address. + */ + function getImplementation() internal view returns (address) { + return StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 implementation slot. + */ + function _setImplementation(address newImplementation) private { + if (newImplementation.code.length == 0) { + revert ERC1967InvalidImplementation(newImplementation); + } + StorageSlot.getAddressSlot(IMPLEMENTATION_SLOT).value = newImplementation; + } + + /** + * @dev Performs implementation upgrade with additional setup call if data is nonempty. + * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected + * to avoid stuck value in the contract. + * + * Emits an {IERC1967-Upgraded} event. + */ + function upgradeToAndCall(address newImplementation, bytes memory data) internal { + _setImplementation(newImplementation); + emit Upgraded(newImplementation); + + if (data.length > 0) { + Address.functionDelegateCall(newImplementation, data); + } else { + _checkNonPayable(); + } + } + + /** + * @dev Storage slot with the admin of the contract. + * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. + */ + // solhint-disable-next-line private-vars-leading-underscore + bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + /** + * @dev Returns the current admin. + * + * 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 getAdmin() internal view returns (address) { + return StorageSlot.getAddressSlot(ADMIN_SLOT).value; + } + + /** + * @dev Stores a new address in the EIP1967 admin slot. + */ + function _setAdmin(address newAdmin) private { + if (newAdmin == address(0)) { + revert ERC1967InvalidAdmin(address(0)); + } + StorageSlot.getAddressSlot(ADMIN_SLOT).value = newAdmin; + } + + /** + * @dev Changes the admin of the proxy. + * + * Emits an {IERC1967-AdminChanged} event. + */ + function changeAdmin(address newAdmin) internal { + emit AdminChanged(getAdmin(), newAdmin); + _setAdmin(newAdmin); + } + + /** + * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. + * This is the keccak-256 hash of "eip1967.proxy.beacon" subtracted by 1. + */ + // solhint-disable-next-line private-vars-leading-underscore + bytes32 internal constant BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; + + /** + * @dev Returns the current beacon. + */ + function getBeacon() internal view returns (address) { + return StorageSlot.getAddressSlot(BEACON_SLOT).value; + } + + /** + * @dev Stores a new beacon in the EIP1967 beacon slot. + */ + function _setBeacon(address newBeacon) private { + if (newBeacon.code.length == 0) { + revert ERC1967InvalidBeacon(newBeacon); + } + + StorageSlot.getAddressSlot(BEACON_SLOT).value = newBeacon; + + address beaconImplementation = IBeacon(newBeacon).implementation(); + if (beaconImplementation.code.length == 0) { + revert ERC1967InvalidImplementation(beaconImplementation); + } + } + + /** + * @dev Change the beacon and trigger a setup call if data is nonempty. + * This function is payable only if the setup call is performed, otherwise `msg.value` is rejected + * to avoid stuck value in the contract. + * + * Emits an {IERC1967-BeaconUpgraded} event. + * + * CAUTION: Invoking this function has no effect on an instance of {BeaconProxy} since v5, since + * it uses an immutable beacon without looking at the value of the ERC-1967 beacon slot for + * efficiency. + */ + function upgradeBeaconToAndCall(address newBeacon, bytes memory data) internal { + _setBeacon(newBeacon); + emit BeaconUpgraded(newBeacon); + + if (data.length > 0) { + Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); + } else { + _checkNonPayable(); + } + } + + /** + * @dev Reverts if `msg.value` is not zero. It can be used to avoid `msg.value` stuck in the contract + * if an upgrade doesn't perform an initialization call. + */ + function _checkNonPayable() private { + if (msg.value > 0) { + revert ERC1967NonPayable(); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol b/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol new file mode 100644 index 0000000..0e73651 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Proxy.sol) + +pragma solidity ^0.8.20; + +/** + * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM + * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to + * be specified by overriding the virtual {_implementation} function. + * + * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a + * different contract through the {_delegate} function. + * + * The success and return data of the delegated call will be returned back to the caller of the proxy. + */ +abstract contract Proxy { + /** + * @dev Delegates the current call to `implementation`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _delegate(address implementation) internal virtual { + assembly { + // Copy msg.data. We take full control of memory in this inline assembly + // block because it will not return to Solidity code. We overwrite the + // Solidity scratch pad at memory position 0. + calldatacopy(0, 0, calldatasize()) + + // Call the implementation. + // out and outsize are 0 because we don't know the size yet. + let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0) + + // Copy the returned data. + returndatacopy(0, 0, returndatasize()) + + switch result + // delegatecall returns 0 on error. + case 0 { + revert(0, returndatasize()) + } + default { + return(0, returndatasize()) + } + } + } + + /** + * @dev This is a virtual function that should be overridden so it returns the address to which the fallback + * function and {_fallback} should delegate. + */ + function _implementation() internal view virtual returns (address); + + /** + * @dev Delegates the current call to the address returned by `_implementation()`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _fallback() internal virtual { + _delegate(_implementation()); + } + + /** + * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other + * function in the contract matches the call data. + */ + fallback() external payable virtual { + _fallback(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/README.adoc b/lib/openzeppelin-contracts/contracts/proxy/README.adoc new file mode 100644 index 0000000..3c4a78d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/README.adoc @@ -0,0 +1,87 @@ += Proxies + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/proxy + +This is a low-level set of contracts implementing different proxy patterns with and without upgradeability. For an in-depth overview of this pattern check out the xref:upgrades-plugins::proxies.adoc[Proxy Upgrade Pattern] page. + +Most of the proxies below are built on an abstract base contract. + +- {Proxy}: Abstract contract implementing the core delegation functionality. + +In order to avoid clashes with the storage variables of the implementation contract behind a proxy, we use https://eips.ethereum.org/EIPS/eip-1967[EIP1967] storage slots. + +- {ERC1967Utils}: Internal functions to get and set the storage slots defined in EIP1967. +- {ERC1967Proxy}: A proxy using EIP1967 storage slots. Not upgradeable by default. + +There are two alternative ways to add upgradeability to an ERC1967 proxy. Their differences are explained below in <>. + +- {TransparentUpgradeableProxy}: A proxy with a built-in immutable admin and upgrade interface. +- {UUPSUpgradeable}: An upgradeability mechanism to be included in the implementation contract. + +CAUTION: Using upgradeable proxies correctly and securely is a difficult task that requires deep knowledge of the proxy pattern, Solidity, and the EVM. Unless you want a lot of low level control, we recommend using the xref:upgrades-plugins::index.adoc[OpenZeppelin Upgrades Plugins] for Truffle and Hardhat. + +A different family of proxies are beacon proxies. This pattern, popularized by Dharma, allows multiple proxies to be upgraded to a different implementation in a single transaction. + +- {BeaconProxy}: A proxy that retrieves its implementation from a beacon contract. +- {UpgradeableBeacon}: A beacon contract with a built in admin that can upgrade the {BeaconProxy} pointing to it. + +In this pattern, the proxy contract doesn't hold the implementation address in storage like an ERC1967 proxy. Instead, the address is stored in a separate beacon contract. The `upgrade` operations are sent to the beacon instead of to the proxy contract, and all proxies that follow that beacon are automatically upgraded. + +Outside the realm of upgradeability, proxies can also be useful to make cheap contract clones, such as those created by an on-chain factory contract that creates many instances of the same contract. These instances are designed to be both cheap to deploy, and cheap to call. + +- {Clones}: A library that can deploy cheap minimal non-upgradeable proxies. + +[[transparent-vs-uups]] +== Transparent vs UUPS Proxies + +The original proxies included in OpenZeppelin followed the https://blog.openzeppelin.com/the-transparent-proxy-pattern/[Transparent Proxy Pattern]. While this pattern is still provided, our recommendation is now shifting towards UUPS proxies, which are both lightweight and versatile. The name UUPS comes from https://eips.ethereum.org/EIPS/eip-1822[EIP1822], which first documented the pattern. + +While both of these share the same interface for upgrades, in UUPS proxies the upgrade is handled by the implementation, and can eventually be removed. Transparent proxies, on the other hand, include the upgrade and admin logic in the proxy itself. This means {TransparentUpgradeableProxy} is more expensive to deploy than what is possible with UUPS proxies. + +UUPS proxies are implemented using an {ERC1967Proxy}. Note that this proxy is not by itself upgradeable. It is the role of the implementation to include, alongside the contract's logic, all the code necessary to update the implementation's address that is stored at a specific slot in the proxy's storage space. This is where the {UUPSUpgradeable} contract comes in. Inheriting from it (and overriding the {xref-UUPSUpgradeable-_authorizeUpgrade-address-}[`_authorizeUpgrade`] function with the relevant access control mechanism) will turn your contract into a UUPS compliant implementation. + +Note that since both proxies use the same storage slot for the implementation address, using a UUPS compliant implementation with a {TransparentUpgradeableProxy} might allow non-admins to perform upgrade operations. + +By default, the upgrade functionality included in {UUPSUpgradeable} contains a security mechanism that will prevent any upgrades to a non UUPS compliant implementation. This prevents upgrades to an implementation contract that wouldn't contain the necessary upgrade mechanism, as it would lock the upgradeability of the proxy forever. This security mechanism can be bypassed by either of: + +- Adding a flag mechanism in the implementation that will disable the upgrade function when triggered. +- Upgrading to an implementation that features an upgrade mechanism without the additional security check, and then upgrading again to another implementation without the upgrade mechanism. + +The current implementation of this security mechanism uses https://eips.ethereum.org/EIPS/eip-1822[EIP1822] to detect the storage slot used by the implementation. A previous implementation, now deprecated, relied on a rollback check. It is possible to upgrade from a contract using the old mechanism to a new one. The inverse is however not possible, as old implementations (before version 4.5) did not include the `ERC1822` interface. + +== Core + +{{Proxy}} + +== ERC1967 + +{{IERC1967}} + +{{ERC1967Proxy}} + +{{ERC1967Utils}} + +== Transparent Proxy + +{{TransparentUpgradeableProxy}} + +{{ProxyAdmin}} + +== Beacon + +{{BeaconProxy}} + +{{IBeacon}} + +{{UpgradeableBeacon}} + +== Minimal Clones + +{{Clones}} + +== Utils + +{{Initializable}} + +{{UUPSUpgradeable}} diff --git a/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol b/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol new file mode 100644 index 0000000..05e26e5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/BeaconProxy.sol) + +pragma solidity ^0.8.20; + +import {IBeacon} from "./IBeacon.sol"; +import {Proxy} from "../Proxy.sol"; +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; + +/** + * @dev This contract implements a proxy that gets the implementation address for each call from an {UpgradeableBeacon}. + * + * The beacon address can only be set once during construction, and cannot be changed afterwards. It is stored in an + * immutable variable to avoid unnecessary storage reads, and also in the beacon storage slot specified by + * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] so that it can be accessed externally. + * + * CAUTION: Since the beacon address can never be changed, you must ensure that you either control the beacon, or trust + * the beacon to not upgrade the implementation maliciously. + * + * IMPORTANT: Do not use the implementation logic to modify the beacon storage slot. Doing so would leave the proxy in + * an inconsistent state where the beacon storage slot does not match the beacon address. + */ +contract BeaconProxy is Proxy { + // An immutable address for the beacon to avoid unnecessary SLOADs before each delegate call. + address private immutable _beacon; + + /** + * @dev Initializes the proxy with `beacon`. + * + * If `data` is nonempty, it's used as data in a delegate call to the implementation returned by the beacon. This + * will typically be an encoded function call, and allows initializing the storage of the proxy like a Solidity + * constructor. + * + * Requirements: + * + * - `beacon` must be a contract with the interface {IBeacon}. + * - If `data` is empty, `msg.value` must be zero. + */ + constructor(address beacon, bytes memory data) payable { + ERC1967Utils.upgradeBeaconToAndCall(beacon, data); + _beacon = beacon; + } + + /** + * @dev Returns the current implementation address of the associated beacon. + */ + function _implementation() internal view virtual override returns (address) { + return IBeacon(_getBeacon()).implementation(); + } + + /** + * @dev Returns the beacon. + */ + function _getBeacon() internal view virtual returns (address) { + return _beacon; + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol b/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol new file mode 100644 index 0000000..36a3c76 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/IBeacon.sol) + +pragma solidity ^0.8.20; + +/** + * @dev This is the interface that {BeaconProxy} expects of its beacon. + */ +interface IBeacon { + /** + * @dev Must return an address that can be used as a delegate call target. + * + * {UpgradeableBeacon} will check that this address is a contract. + */ + function implementation() external view returns (address); +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol b/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol new file mode 100644 index 0000000..8db9bd2 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/beacon/UpgradeableBeacon.sol) + +pragma solidity ^0.8.20; + +import {IBeacon} from "./IBeacon.sol"; +import {Ownable} from "../../access/Ownable.sol"; + +/** + * @dev This contract is used in conjunction with one or more instances of {BeaconProxy} to determine their + * implementation contract, which is where they will delegate all function calls. + * + * An owner is able to change the implementation the beacon points to, thus upgrading the proxies that use this beacon. + */ +contract UpgradeableBeacon is IBeacon, Ownable { + address private _implementation; + + /** + * @dev The `implementation` of the beacon is invalid. + */ + error BeaconInvalidImplementation(address implementation); + + /** + * @dev Emitted when the implementation returned by the beacon is changed. + */ + event Upgraded(address indexed implementation); + + /** + * @dev Sets the address of the initial implementation, and the initial owner who can upgrade the beacon. + */ + constructor(address implementation_, address initialOwner) Ownable(initialOwner) { + _setImplementation(implementation_); + } + + /** + * @dev Returns the current implementation address. + */ + function implementation() public view virtual returns (address) { + return _implementation; + } + + /** + * @dev Upgrades the beacon to a new implementation. + * + * Emits an {Upgraded} event. + * + * Requirements: + * + * - msg.sender must be the owner of the contract. + * - `newImplementation` must be a contract. + */ + function upgradeTo(address newImplementation) public virtual onlyOwner { + _setImplementation(newImplementation); + } + + /** + * @dev Sets the implementation contract address for this beacon + * + * Requirements: + * + * - `newImplementation` must be a contract. + */ + function _setImplementation(address newImplementation) private { + if (newImplementation.code.length == 0) { + revert BeaconInvalidImplementation(newImplementation); + } + _implementation = newImplementation; + emit Upgraded(newImplementation); + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol b/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol new file mode 100644 index 0000000..dab55ef --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/ProxyAdmin.sol) + +pragma solidity ^0.8.20; + +import {ITransparentUpgradeableProxy} from "./TransparentUpgradeableProxy.sol"; +import {Ownable} from "../../access/Ownable.sol"; + +/** + * @dev This is an auxiliary contract meant to be assigned as the admin of a {TransparentUpgradeableProxy}. For an + * explanation of why you would want to use this see the documentation for {TransparentUpgradeableProxy}. + */ +contract ProxyAdmin is Ownable { + /** + * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgrade(address)` + * and `upgradeAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, + * while `upgradeAndCall` will invoke the `receive` function if the second argument is the empty byte string. + * If the getter returns `"5.0.0"`, only `upgradeAndCall(address,bytes)` is present, and the second argument must + * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function + * during an upgrade. + */ + string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; + + /** + * @dev Sets the initial owner who can perform upgrades. + */ + constructor(address initialOwner) Ownable(initialOwner) {} + + /** + * @dev Upgrades `proxy` to `implementation` and calls a function on the new implementation. + * See {TransparentUpgradeableProxy-_dispatchUpgradeToAndCall}. + * + * Requirements: + * + * - This contract must be the admin of `proxy`. + * - If `data` is empty, `msg.value` must be zero. + */ + function upgradeAndCall( + ITransparentUpgradeableProxy proxy, + address implementation, + bytes memory data + ) public payable virtual onlyOwner { + proxy.upgradeToAndCall{value: msg.value}(implementation, data); + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol b/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol new file mode 100644 index 0000000..b2021c7 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sol @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/transparent/TransparentUpgradeableProxy.sol) + +pragma solidity ^0.8.20; + +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; +import {ERC1967Proxy} from "../ERC1967/ERC1967Proxy.sol"; +import {IERC1967} from "../../interfaces/IERC1967.sol"; +import {ProxyAdmin} from "./ProxyAdmin.sol"; + +/** + * @dev Interface for {TransparentUpgradeableProxy}. In order to implement transparency, {TransparentUpgradeableProxy} + * does not implement this interface directly, and its upgradeability mechanism is 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 upgradeToAndCall(address, bytes calldata) external payable; +} + +/** + * @dev This contract implements a proxy that is upgradeable through an associated {ProxyAdmin} instance. + * + * To avoid https://medium.com/nomic-labs-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357[proxy selector + * clashing], which can potentially be used in an attack, this contract uses the + * https://blog.openzeppelin.com/the-transparent-proxy-pattern/[transparent proxy pattern]. This pattern implies two + * things that go hand in hand: + * + * 1. If any account other than the admin calls the proxy, the call will be forwarded to the implementation, even if + * that call matches the {ITransparentUpgradeableProxy-upgradeToAndCall} function exposed by the proxy itself. + * 2. If the admin calls the proxy, it can call the `upgradeToAndCall` function but any other call won't be forwarded to + * the implementation. If the admin tries to call a function on the implementation it will fail with an error indicating + * the proxy admin cannot fallback to the target implementation. + * + * These properties mean that the admin account can only be used for upgrading the proxy, so it's best if it's a + * dedicated account that is not used for anything else. This will avoid headaches due to sudden errors when trying to + * call a function from the proxy implementation. For this reason, the proxy deploys an instance of {ProxyAdmin} and + * allows upgrades only if they come through it. You should think of the `ProxyAdmin` instance as the administrative + * interface of the proxy, including the ability to change who can trigger upgrades by transferring ownership. + * + * NOTE: The real interface of this proxy is that defined in `ITransparentUpgradeableProxy`. This contract does not + * inherit from that interface, and instead `upgradeToAndCall` is 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. + * + * NOTE: This proxy does not inherit from {Context} deliberately. The {ProxyAdmin} of this contract won't send a + * meta-transaction in any way, and any other meta-transaction setup should be made in the implementation contract. + * + * IMPORTANT: This contract avoids unnecessary storage reads by setting the admin only during construction as an + * immutable variable, preventing any changes thereafter. However, the admin slot defined in ERC-1967 can still be + * overwritten by the implementation logic pointed to by this proxy. In such cases, the contract may end up in an + * undesirable state where the admin slot is different from the actual admin. + * + * 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 `upgradeToAndCall` function inaccessible, preventing upgradeability and compromising transparency. + */ +contract TransparentUpgradeableProxy is ERC1967Proxy { + // An immutable address for the admin to avoid unnecessary SLOADs before each call + // at the expense of removing the ability to change the admin once it's set. + // This is acceptable if the admin is always a ProxyAdmin instance or similar contract + // with its own ability to transfer the permissions to another account. + address private immutable _admin; + + /** + * @dev The proxy caller is the current admin, and can't fallback to the proxy target. + */ + error ProxyDeniedAdminAccess(); + + /** + * @dev Initializes an upgradeable proxy managed by an instance of a {ProxyAdmin} with an `initialOwner`, + * backed by the implementation at `_logic`, and optionally initialized with `_data` as explained in + * {ERC1967Proxy-constructor}. + */ + constructor(address _logic, address initialOwner, bytes memory _data) payable ERC1967Proxy(_logic, _data) { + _admin = address(new ProxyAdmin(initialOwner)); + // Set the storage value and emit an event for ERC-1967 compatibility + ERC1967Utils.changeAdmin(_proxyAdmin()); + } + + /** + * @dev Returns the admin of this proxy. + */ + function _proxyAdmin() internal virtual returns (address) { + return _admin; + } + + /** + * @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 == _proxyAdmin()) { + if (msg.sig != ITransparentUpgradeableProxy.upgradeToAndCall.selector) { + revert ProxyDeniedAdminAccess(); + } else { + _dispatchUpgradeToAndCall(); + } + } else { + super._fallback(); + } + } + + /** + * @dev Upgrade the implementation of the proxy. See {ERC1967Utils-upgradeToAndCall}. + * + * Requirements: + * + * - If `data` is empty, `msg.value` must be zero. + */ + function _dispatchUpgradeToAndCall() private { + (address newImplementation, bytes memory data) = abi.decode(msg.data[4:], (address, bytes)); + ERC1967Utils.upgradeToAndCall(newImplementation, data); + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol b/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol new file mode 100644 index 0000000..b3d82b5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sol @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol) + +pragma solidity ^0.8.20; + +/** + * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed + * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an + * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer + * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. + * + * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be + * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in + * case an upgrade adds a module that needs to be initialized. + * + * 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"); + * } + * } + * ``` + * + * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as + * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. + * + * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure + * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. + * + * [CAUTION] + * ==== + * Avoid leaving a contract uninitialized. + * + * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation + * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke + * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: + * + * [.hljs-theme-light.nopadding] + * ``` + * /// @custom:oz-upgrades-unsafe-allow constructor + * constructor() { + * _disableInitializers(); + * } + * ``` + * ==== + */ +abstract contract Initializable { + /** + * @dev Storage of the initializable contract. + * + * It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions + * when using with upgradeable contracts. + * + * @custom:storage-location erc7201:openzeppelin.storage.Initializable + */ + struct InitializableStorage { + /** + * @dev Indicates that the contract has been initialized. + */ + uint64 _initialized; + /** + * @dev Indicates that the contract is in the process of being initialized. + */ + bool _initializing; + } + + // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff)) + bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00; + + /** + * @dev The contract is already initialized. + */ + error InvalidInitialization(); + + /** + * @dev The contract is not initializing. + */ + error NotInitializing(); + + /** + * @dev Triggered when the contract has been initialized or reinitialized. + */ + event Initialized(uint64 version); + + /** + * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, + * `onlyInitializing` functions can be used to initialize parent contracts. + * + * Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any + * number of times. This behavior in the constructor can be useful during testing and is not expected to be used in + * production. + * + * Emits an {Initialized} event. + */ + modifier initializer() { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + // Cache values to avoid duplicated sloads + bool isTopLevelCall = !$._initializing; + uint64 initialized = $._initialized; + + // Allowed calls: + // - initialSetup: the contract is not in the initializing state and no previous version was + // initialized + // - construction: the contract is initialized at version 1 (no reininitialization) and the + // current contract is just being deployed + bool initialSetup = initialized == 0 && isTopLevelCall; + bool construction = initialized == 1 && address(this).code.length == 0; + + if (!initialSetup && !construction) { + revert InvalidInitialization(); + } + $._initialized = 1; + if (isTopLevelCall) { + $._initializing = true; + } + _; + if (isTopLevelCall) { + $._initializing = false; + emit Initialized(1); + } + } + + /** + * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the + * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be + * used to initialize parent contracts. + * + * A reinitializer may be used after the original initialization step. This is essential to configure modules that + * are added through upgrades and that require initialization. + * + * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` + * cannot be nested. If one is invoked in the context of another, execution will revert. + * + * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in + * a contract, executing them in the right order is up to the developer or operator. + * + * WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization. + * + * Emits an {Initialized} event. + */ + modifier reinitializer(uint64 version) { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing || $._initialized >= version) { + revert InvalidInitialization(); + } + $._initialized = version; + $._initializing = true; + _; + $._initializing = false; + emit Initialized(version); + } + + /** + * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the + * {initializer} and {reinitializer} modifiers, directly or indirectly. + */ + modifier onlyInitializing() { + _checkInitializing(); + _; + } + + /** + * @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}. + */ + function _checkInitializing() internal view virtual { + if (!_isInitializing()) { + revert NotInitializing(); + } + } + + /** + * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. + * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized + * to any version. It is recommended to use this to lock implementation contracts that are designed to be called + * through proxies. + * + * Emits an {Initialized} event the first time it is successfully executed. + */ + function _disableInitializers() internal virtual { + // solhint-disable-next-line var-name-mixedcase + InitializableStorage storage $ = _getInitializableStorage(); + + if ($._initializing) { + revert InvalidInitialization(); + } + if ($._initialized != type(uint64).max) { + $._initialized = type(uint64).max; + emit Initialized(type(uint64).max); + } + } + + /** + * @dev Returns the highest version that has been initialized. See {reinitializer}. + */ + function _getInitializedVersion() internal view returns (uint64) { + return _getInitializableStorage()._initialized; + } + + /** + * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. + */ + function _isInitializing() internal view returns (bool) { + return _getInitializableStorage()._initializing; + } + + /** + * @dev Returns a pointer to the storage namespace. + */ + // solhint-disable-next-line var-name-mixedcase + function _getInitializableStorage() private pure returns (InitializableStorage storage $) { + assembly { + $.slot := INITIALIZABLE_STORAGE + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol b/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol new file mode 100644 index 0000000..8a4e693 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/UUPSUpgradeable.sol) + +pragma solidity ^0.8.20; + +import {IERC1822Proxiable} from "../../interfaces/draft-IERC1822.sol"; +import {ERC1967Utils} from "../ERC1967/ERC1967Utils.sol"; + +/** + * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an + * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. + * + * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is + * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing + * `UUPSUpgradeable` with a custom implementation of upgrades. + * + * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. + */ +abstract contract UUPSUpgradeable is IERC1822Proxiable { + /// @custom:oz-upgrades-unsafe-allow state-variable-immutable + address private immutable __self = address(this); + + /** + * @dev The version of the upgrade interface of the contract. If this getter is missing, both `upgradeTo(address)` + * and `upgradeToAndCall(address,bytes)` are present, and `upgradeTo` must be used if no function should be called, + * while `upgradeToAndCall` will invoke the `receive` function if the second argument is the empty byte string. + * If the getter returns `"5.0.0"`, only `upgradeToAndCall(address,bytes)` is present, and the second argument must + * be the empty byte string if no function should be called, making it impossible to invoke the `receive` function + * during an upgrade. + */ + string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; + + /** + * @dev The call is from an unauthorized context. + */ + error UUPSUnauthorizedCallContext(); + + /** + * @dev The storage `slot` is unsupported as a UUID. + */ + error UUPSUnsupportedProxiableUUID(bytes32 slot); + + /** + * @dev Check that the execution is being performed through a delegatecall call and that the execution context is + * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case + * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a + * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to + * fail. + */ + modifier onlyProxy() { + _checkProxy(); + _; + } + + /** + * @dev Check that the execution is not being performed through a delegate call. This allows a function to be + * callable on the implementing contract but not through proxies. + */ + modifier notDelegated() { + _checkNotDelegated(); + _; + } + + /** + * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the + * implementation. It is used to validate the implementation's compatibility when performing an upgrade. + * + * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks + * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this + * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. + */ + function proxiableUUID() external view virtual notDelegated returns (bytes32) { + return ERC1967Utils.IMPLEMENTATION_SLOT; + } + + /** + * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call + * encoded in `data`. + * + * Calls {_authorizeUpgrade}. + * + * Emits an {Upgraded} event. + * + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy { + _authorizeUpgrade(newImplementation); + _upgradeToAndCallUUPS(newImplementation, data); + } + + /** + * @dev Reverts if the execution is not performed via delegatecall or the execution + * context is not of a proxy with an ERC1967-compliant implementation pointing to self. + * See {_onlyProxy}. + */ + function _checkProxy() internal view virtual { + if ( + address(this) == __self || // Must be called through delegatecall + ERC1967Utils.getImplementation() != __self // Must be called through an active proxy + ) { + revert UUPSUnauthorizedCallContext(); + } + } + + /** + * @dev Reverts if the execution is performed via delegatecall. + * See {notDelegated}. + */ + function _checkNotDelegated() internal view virtual { + if (address(this) != __self) { + // Must not be called through delegatecall + revert UUPSUnauthorizedCallContext(); + } + } + + /** + * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by + * {upgradeToAndCall}. + * + * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. + * + * ```solidity + * function _authorizeUpgrade(address) internal onlyOwner {} + * ``` + */ + function _authorizeUpgrade(address newImplementation) internal virtual; + + /** + * @dev Performs an implementation upgrade with a security check for UUPS proxies, and additional setup call. + * + * As a security check, {proxiableUUID} is invoked in the new implementation, and the return value + * is expected to be the implementation slot in ERC1967. + * + * Emits an {IERC1967-Upgraded} event. + */ + function _upgradeToAndCallUUPS(address newImplementation, bytes memory data) private { + try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { + if (slot != ERC1967Utils.IMPLEMENTATION_SLOT) { + revert UUPSUnsupportedProxiableUUID(slot); + } + ERC1967Utils.upgradeToAndCall(newImplementation, data); + } catch { + // The implementation is not UUPS + revert ERC1967Utils.ERC1967InvalidImplementation(newImplementation); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol new file mode 100644 index 0000000..316f329 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sol @@ -0,0 +1,468 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/ERC1155.sol) + +pragma solidity ^0.8.20; + +import {IERC1155} from "./IERC1155.sol"; +import {IERC1155Receiver} from "./IERC1155Receiver.sol"; +import {IERC1155MetadataURI} from "./extensions/IERC1155MetadataURI.sol"; +import {Context} from "../../utils/Context.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; +import {Arrays} from "../../utils/Arrays.sol"; +import {IERC1155Errors} from "../../interfaces/draft-IERC6093.sol"; + +/** + * @dev Implementation of the basic standard multi-token. + * See https://eips.ethereum.org/EIPS/eip-1155 + * Originally based on code by Enjin: https://github.com/enjin/erc-1155 + */ +abstract contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI, IERC1155Errors { + using Arrays for uint256[]; + using Arrays for address[]; + + mapping(uint256 id => mapping(address account => uint256)) private _balances; + + mapping(address account => mapping(address operator => bool)) private _operatorApprovals; + + // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json + string private _uri; + + /** + * @dev See {_setURI}. + */ + constructor(string memory uri_) { + _setURI(uri_); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC1155).interfaceId || + interfaceId == type(IERC1155MetadataURI).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function uri(uint256 /* id */) public view virtual returns (string memory) { + return _uri; + } + + /** + * @dev See {IERC1155-balanceOf}. + */ + function balanceOf(address account, uint256 id) public view virtual returns (uint256) { + return _balances[id][account]; + } + + /** + * @dev See {IERC1155-balanceOfBatch}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] memory accounts, + uint256[] memory ids + ) public view virtual returns (uint256[] memory) { + if (accounts.length != ids.length) { + revert ERC1155InvalidArrayLength(ids.length, accounts.length); + } + + uint256[] memory batchBalances = new uint256[](accounts.length); + + for (uint256 i = 0; i < accounts.length; ++i) { + batchBalances[i] = balanceOf(accounts.unsafeMemoryAccess(i), ids.unsafeMemoryAccess(i)); + } + + return batchBalances; + } + + /** + * @dev See {IERC1155-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC1155-isApprovedForAll}. + */ + function isApprovedForAll(address account, address operator) public view virtual returns (bool) { + return _operatorApprovals[account][operator]; + } + + /** + * @dev See {IERC1155-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) public virtual { + address sender = _msgSender(); + if (from != sender && !isApprovedForAll(from, sender)) { + revert ERC1155MissingApprovalForAll(sender, from); + } + _safeTransferFrom(from, to, id, value, data); + } + + /** + * @dev See {IERC1155-safeBatchTransferFrom}. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) public virtual { + address sender = _msgSender(); + if (from != sender && !isApprovedForAll(from, sender)) { + revert ERC1155MissingApprovalForAll(sender, from); + } + _safeBatchTransferFrom(from, to, ids, values, data); + } + + /** + * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. Will mint (or burn) if `from` + * (or `to`) is the zero address. + * + * Emits a {TransferSingle} event if the arrays contain one element, and {TransferBatch} otherwise. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement either {IERC1155Receiver-onERC1155Received} + * or {IERC1155Receiver-onERC1155BatchReceived} and return the acceptance magic value. + * - `ids` and `values` must have the same length. + * + * NOTE: The ERC-1155 acceptance check is not performed in this function. See {_updateWithAcceptanceCheck} instead. + */ + function _update(address from, address to, uint256[] memory ids, uint256[] memory values) internal virtual { + if (ids.length != values.length) { + revert ERC1155InvalidArrayLength(ids.length, values.length); + } + + address operator = _msgSender(); + + for (uint256 i = 0; i < ids.length; ++i) { + uint256 id = ids.unsafeMemoryAccess(i); + uint256 value = values.unsafeMemoryAccess(i); + + if (from != address(0)) { + uint256 fromBalance = _balances[id][from]; + if (fromBalance < value) { + revert ERC1155InsufficientBalance(from, fromBalance, value, id); + } + unchecked { + // Overflow not possible: value <= fromBalance + _balances[id][from] = fromBalance - value; + } + } + + if (to != address(0)) { + _balances[id][to] += value; + } + } + + if (ids.length == 1) { + uint256 id = ids.unsafeMemoryAccess(0); + uint256 value = values.unsafeMemoryAccess(0); + emit TransferSingle(operator, from, to, id, value); + } else { + emit TransferBatch(operator, from, to, ids, values); + } + } + + /** + * @dev Version of {_update} that performs the token acceptance check by calling + * {IERC1155Receiver-onERC1155Received} or {IERC1155Receiver-onERC1155BatchReceived} on the receiver address if it + * contains code (eg. is a smart contract at the moment of execution). + * + * IMPORTANT: Overriding this function is discouraged because it poses a reentrancy risk from the receiver. So any + * update to the contract state after this function would break the check-effect-interaction pattern. Consider + * overriding {_update} instead. + */ + function _updateWithAcceptanceCheck( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) internal virtual { + _update(from, to, ids, values); + if (to != address(0)) { + address operator = _msgSender(); + if (ids.length == 1) { + uint256 id = ids.unsafeMemoryAccess(0); + uint256 value = values.unsafeMemoryAccess(0); + _doSafeTransferAcceptanceCheck(operator, from, to, id, value, data); + } else { + _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, values, data); + } + } + } + + /** + * @dev Transfers a `value` tokens of token type `id` from `from` to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `from` must have a balance of tokens of type `id` of at least `value` amount. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes memory data) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(from, to, ids, values, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + * - `ids` and `values` must have the same length. + */ + function _safeBatchTransferFrom( + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + _updateWithAcceptanceCheck(from, to, ids, values, data); + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism + * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the values in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * See {uri}. + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setURI(string memory newuri) internal virtual { + _uri = newuri; + } + + /** + * @dev Creates a `value` amount of tokens of type `id`, and assigns them to `to`. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function _mint(address to, uint256 id, uint256 value, bytes memory data) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(address(0), to, ids, values, data); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `values` must have the same length. + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function _mintBatch(address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal { + if (to == address(0)) { + revert ERC1155InvalidReceiver(address(0)); + } + _updateWithAcceptanceCheck(address(0), to, ids, values, data); + } + + /** + * @dev Destroys a `value` amount of tokens of type `id` from `from` + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `value` amount of tokens of type `id`. + */ + function _burn(address from, uint256 id, uint256 value) internal { + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + (uint256[] memory ids, uint256[] memory values) = _asSingletonArrays(id, value); + _updateWithAcceptanceCheck(from, address(0), ids, values, ""); + } + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `from` must have at least `value` amount of tokens of type `id`. + * - `ids` and `values` must have the same length. + */ + function _burnBatch(address from, uint256[] memory ids, uint256[] memory values) internal { + if (from == address(0)) { + revert ERC1155InvalidSender(address(0)); + } + _updateWithAcceptanceCheck(from, address(0), ids, values, ""); + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the zero address. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + if (operator == address(0)) { + revert ERC1155InvalidOperator(address(0)); + } + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Performs an acceptance check by calling {IERC1155-onERC1155Received} on the `to` address + * if it contains code at the moment of execution. + */ + function _doSafeTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256 id, + uint256 value, + bytes memory data + ) private { + if (to.code.length > 0) { + try IERC1155Receiver(to).onERC1155Received(operator, from, id, value, data) returns (bytes4 response) { + if (response != IERC1155Receiver.onERC1155Received.selector) { + // Tokens rejected + revert ERC1155InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-ERC1155Receiver implementer + revert ERC1155InvalidReceiver(to); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + } + + /** + * @dev Performs a batch acceptance check by calling {IERC1155-onERC1155BatchReceived} on the `to` address + * if it contains code at the moment of execution. + */ + function _doSafeBatchTransferAcceptanceCheck( + address operator, + address from, + address to, + uint256[] memory ids, + uint256[] memory values, + bytes memory data + ) private { + if (to.code.length > 0) { + try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, values, data) returns ( + bytes4 response + ) { + if (response != IERC1155Receiver.onERC1155BatchReceived.selector) { + // Tokens rejected + revert ERC1155InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + // non-ERC1155Receiver implementer + revert ERC1155InvalidReceiver(to); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + } + + /** + * @dev Creates an array in memory with only one value for each of the elements provided. + */ + function _asSingletonArrays( + uint256 element1, + uint256 element2 + ) private pure returns (uint256[] memory array1, uint256[] memory array2) { + /// @solidity memory-safe-assembly + assembly { + // Load the free memory pointer + array1 := mload(0x40) + // Set array length to 1 + mstore(array1, 1) + // Store the single element at the next word after the length (where content starts) + mstore(add(array1, 0x20), element1) + + // Repeat for next array locating it right after the first array + array2 := add(array1, 0x40) + mstore(array2, 1) + mstore(add(array2, 0x20), element2) + + // Update the free memory pointer by pointing after the second array + mstore(0x40, add(array2, 0x40)) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol new file mode 100644 index 0000000..a014946 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC1155 compliant contract, as defined in the + * https://eips.ethereum.org/EIPS/eip-1155[EIP]. + */ +interface IERC1155 is IERC165 { + /** + * @dev Emitted when `value` amount of tokens of type `id` are transferred from `from` to `to` by `operator`. + */ + event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); + + /** + * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all + * transfers. + */ + event TransferBatch( + address indexed operator, + address indexed from, + address indexed to, + uint256[] ids, + uint256[] values + ); + + /** + * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to + * `approved`. + */ + event ApprovalForAll(address indexed account, address indexed operator, bool approved); + + /** + * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. + * + * If an {URI} event was emitted for `id`, the standard + * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value + * returned by {IERC1155MetadataURI-uri}. + */ + event URI(string value, uint256 indexed id); + + /** + * @dev Returns the value of tokens of token type `id` owned by `account`. + * + * Requirements: + * + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) external view returns (uint256); + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}. + * + * Requirements: + * + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBatch( + address[] calldata accounts, + uint256[] calldata ids + ) external view returns (uint256[] memory); + + /** + * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`, + * + * Emits an {ApprovalForAll} event. + * + * Requirements: + * + * - `operator` cannot be the caller. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns true if `operator` is approved to transfer ``account``'s tokens. + * + * See {setApprovalForAll}. + */ + function isApprovedForAll(address account, address operator) external view returns (bool); + + /** + * @dev Transfers a `value` amount of tokens of type `id` from `from` to `to`. + * + * WARNING: This function can potentially allow a reentrancy attack when transferring tokens + * to an untrusted contract, when invoking {onERC1155Received} on the receiver. + * Ensure to follow the checks-effects-interactions pattern and consider employing + * reentrancy guards when interacting with untrusted contracts. + * + * Emits a {TransferSingle} event. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}. + * - `from` must have a balance of tokens of type `id` of at least `value` amount. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the + * acceptance magic value. + */ + function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external; + + /** + * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}. + * + * + * WARNING: This function can potentially allow a reentrancy attack when transferring tokens + * to an untrusted contract, when invoking {onERC1155BatchReceived} on the receiver. + * Ensure to follow the checks-effects-interactions pattern and consider employing + * reentrancy guards when interacting with untrusted contracts. + * + * Emits a {TransferBatch} event. + * + * Requirements: + * + * - `ids` and `values` must have the same length. + * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the + * acceptance magic value. + */ + function safeBatchTransferFrom( + address from, + address to, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external; +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol new file mode 100644 index 0000000..0f6e2bf --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * @dev Interface that must be implemented by smart contracts in order to receive + * ERC-1155 token transfers. + */ +interface IERC1155Receiver is IERC165 { + /** + * @dev Handles the receipt of a single ERC1155 token type. This function is + * called at the end of a `safeTransferFrom` after the balance has been updated. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + * (i.e. 0xf23a6e61, or its own function selector). + * + * @param operator The address which initiated the transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param id The ID of the token being transferred + * @param value The amount of tokens being transferred + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4); + + /** + * @dev Handles the receipt of a multiple ERC1155 token types. This function + * is called at the end of a `safeBatchTransferFrom` after the balances have + * been updated. + * + * NOTE: To accept the transfer(s), this must return + * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + * (i.e. 0xbc197c81, or its own function selector). + * + * @param operator The address which initiated the batch transfer (i.e. msg.sender) + * @param from The address which previously owned the token + * @param ids An array containing ids of each token being transferred (order and length must match values array) + * @param values An array containing amounts of each token being transferred (order and length must match ids array) + * @param data Additional data with no specified format + * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc b/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc new file mode 100644 index 0000000..1a56358 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/README.adoc @@ -0,0 +1,41 @@ += ERC 1155 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc1155 + +This set of interfaces and contracts are all related to the https://eips.ethereum.org/EIPS/eip-1155[ERC1155 Multi Token Standard]. + +The EIP consists of three interfaces which fulfill different roles, found here as {IERC1155}, {IERC1155MetadataURI} and {IERC1155Receiver}. + +{ERC1155} implements the mandatory {IERC1155} interface, as well as the optional extension {IERC1155MetadataURI}, by relying on the substitution mechanism to use the same URI for all token types, dramatically reducing gas costs. + +Additionally there are multiple custom extensions, including: + +* designation of addresses that can pause token transfers for all users ({ERC1155Pausable}). +* destruction of own tokens ({ERC1155Burnable}). + +NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC1155 (such as <>) and expose them as external functions in the way they prefer. + +== Core + +{{IERC1155}} + +{{IERC1155MetadataURI}} + +{{ERC1155}} + +{{IERC1155Receiver}} + +== Extensions + +{{ERC1155Pausable}} + +{{ERC1155Burnable}} + +{{ERC1155Supply}} + +{{ERC1155URIStorage}} + +== Utilities + +{{ERC1155Holder}} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol new file mode 100644 index 0000000..fd6ad61 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Burnable.sol) + +pragma solidity ^0.8.20; + +import {ERC1155} from "../ERC1155.sol"; + +/** + * @dev Extension of {ERC1155} that allows token holders to destroy both their + * own tokens and those that they have been approved to use. + */ +abstract contract ERC1155Burnable is ERC1155 { + function burn(address account, uint256 id, uint256 value) public virtual { + if (account != _msgSender() && !isApprovedForAll(account, _msgSender())) { + revert ERC1155MissingApprovalForAll(_msgSender(), account); + } + + _burn(account, id, value); + } + + function burnBatch(address account, uint256[] memory ids, uint256[] memory values) public virtual { + if (account != _msgSender() && !isApprovedForAll(account, _msgSender())) { + revert ERC1155MissingApprovalForAll(_msgSender(), account); + } + + _burnBatch(account, ids, values); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol new file mode 100644 index 0000000..529a465 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC1155} from "../ERC1155.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC1155 token with pausable token transfers, minting and burning. + * + * 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 pause mechanism of the contract unreachable, and thus unusable. + */ +abstract contract ERC1155Pausable is ERC1155, Pausable { + /** + * @dev See {ERC1155-_update}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _update( + address from, + address to, + uint256[] memory ids, + uint256[] memory values + ) internal virtual override whenNotPaused { + super._update(from, to, ids, values); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol new file mode 100644 index 0000000..cef11b4 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155Supply.sol) + +pragma solidity ^0.8.20; + +import {ERC1155} from "../ERC1155.sol"; + +/** + * @dev Extension of ERC1155 that adds tracking of total supply per id. + * + * Useful for scenarios where Fungible and Non-fungible tokens have to be + * clearly identified. Note: While a totalSupply of 1 might mean the + * corresponding is an NFT, there is no guarantees that no other token with the + * same id are not going to be minted. + * + * NOTE: This contract implies a global limit of 2**256 - 1 to the number of tokens + * that can be minted. + * + * CAUTION: This extension should not be added in an upgrade to an already deployed contract. + */ +abstract contract ERC1155Supply is ERC1155 { + mapping(uint256 id => uint256) private _totalSupply; + uint256 private _totalSupplyAll; + + /** + * @dev Total value of tokens in with a given id. + */ + function totalSupply(uint256 id) public view virtual returns (uint256) { + return _totalSupply[id]; + } + + /** + * @dev Total value of tokens. + */ + function totalSupply() public view virtual returns (uint256) { + return _totalSupplyAll; + } + + /** + * @dev Indicates whether any token exist with a given id, or not. + */ + function exists(uint256 id) public view virtual returns (bool) { + return totalSupply(id) > 0; + } + + /** + * @dev See {ERC1155-_update}. + */ + function _update( + address from, + address to, + uint256[] memory ids, + uint256[] memory values + ) internal virtual override { + super._update(from, to, ids, values); + + if (from == address(0)) { + uint256 totalMintValue = 0; + for (uint256 i = 0; i < ids.length; ++i) { + uint256 value = values[i]; + // Overflow check required: The rest of the code assumes that totalSupply never overflows + _totalSupply[ids[i]] += value; + totalMintValue += value; + } + // Overflow check required: The rest of the code assumes that totalSupplyAll never overflows + _totalSupplyAll += totalMintValue; + } + + if (to == address(0)) { + uint256 totalBurnValue = 0; + for (uint256 i = 0; i < ids.length; ++i) { + uint256 value = values[i]; + + unchecked { + // Overflow not possible: values[i] <= balanceOf(from, ids[i]) <= totalSupply(ids[i]) + _totalSupply[ids[i]] -= value; + // Overflow not possible: sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll + totalBurnValue += value; + } + } + unchecked { + // Overflow not possible: totalBurnValue = sum_i(values[i]) <= sum_i(totalSupply(ids[i])) <= totalSupplyAll + _totalSupplyAll -= totalBurnValue; + } + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol new file mode 100644 index 0000000..c2a5bdc --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/ERC1155URIStorage.sol) + +pragma solidity ^0.8.20; + +import {Strings} from "../../../utils/Strings.sol"; +import {ERC1155} from "../ERC1155.sol"; + +/** + * @dev ERC1155 token with storage based token URI management. + * Inspired by the ERC721URIStorage extension + */ +abstract contract ERC1155URIStorage is ERC1155 { + using Strings for uint256; + + // Optional base URI + string private _baseURI = ""; + + // Optional mapping for token URIs + mapping(uint256 tokenId => string) private _tokenURIs; + + /** + * @dev See {IERC1155MetadataURI-uri}. + * + * This implementation returns the concatenation of the `_baseURI` + * and the token-specific uri if the latter is set + * + * This enables the following behaviors: + * + * - if `_tokenURIs[tokenId]` is set, then the result is the concatenation + * of `_baseURI` and `_tokenURIs[tokenId]` (keep in mind that `_baseURI` + * is empty per default); + * + * - if `_tokenURIs[tokenId]` is NOT set then we fallback to `super.uri()` + * which in most cases will contain `ERC1155._uri`; + * + * - if `_tokenURIs[tokenId]` is NOT set, and if the parents do not have a + * uri value set, then the result is empty. + */ + function uri(uint256 tokenId) public view virtual override returns (string memory) { + string memory tokenURI = _tokenURIs[tokenId]; + + // If token URI is set, concatenate base URI and tokenURI (via string.concat). + return bytes(tokenURI).length > 0 ? string.concat(_baseURI, tokenURI) : super.uri(tokenId); + } + + /** + * @dev Sets `tokenURI` as the tokenURI of `tokenId`. + */ + function _setURI(uint256 tokenId, string memory tokenURI) internal virtual { + _tokenURIs[tokenId] = tokenURI; + emit URI(uri(tokenId), tokenId); + } + + /** + * @dev Sets `baseURI` as the `_baseURI` for all tokens + */ + function _setBaseURI(string memory baseURI) internal virtual { + _baseURI = baseURI; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol new file mode 100644 index 0000000..e3fb74d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/extensions/IERC1155MetadataURI.sol) + +pragma solidity ^0.8.20; + +import {IERC1155} from "../IERC1155.sol"; + +/** + * @dev Interface of the optional ERC1155MetadataExtension interface, as defined + * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP]. + */ +interface IERC1155MetadataURI is IERC1155 { + /** + * @dev Returns the URI for token type `id`. + * + * If the `\{id\}` substring is present in the URI, it must be replaced by + * clients with the actual token type ID. + */ + function uri(uint256 id) external view returns (string memory); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol b/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol new file mode 100644 index 0000000..b108cdb --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/utils/ERC1155Holder.sol) + +pragma solidity ^0.8.20; + +import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol"; +import {IERC1155Receiver} from "../IERC1155Receiver.sol"; + +/** + * @dev Simple implementation of `IERC1155Receiver` that will allow a contract to hold ERC1155 tokens. + * + * IMPORTANT: When inheriting this contract, you must include a way to use the received tokens, otherwise they will be + * stuck. + */ +abstract contract ERC1155Holder is ERC165, IERC1155Receiver { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC1155Receiver).interfaceId || super.supportsInterface(interfaceId); + } + + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol new file mode 100644 index 0000000..1fde527 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "./IERC20.sol"; +import {IERC20Metadata} from "./extensions/IERC20Metadata.sol"; +import {Context} from "../../utils/Context.sol"; +import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol"; + +/** + * @dev Implementation of the {IERC20} interface. + * + * This implementation is agnostic to the way tokens are created. This means + * that a supply mechanism has to be added in a derived contract using {_mint}. + * + * TIP: For a detailed writeup see our guide + * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How + * to implement supply mechanisms]. + * + * The default value of {decimals} is 18. To change this, you should override + * this function so it returns a different value. + * + * We have followed general OpenZeppelin Contracts guidelines: functions revert + * instead returning `false` on failure. This behavior is nonetheless + * conventional and does not conflict with the expectations of ERC20 + * applications. + * + * Additionally, an {Approval} event is emitted on calls to {transferFrom}. + * This allows applications to reconstruct the allowance for all accounts just + * by listening to said events. Other implementations of the EIP may not emit + * these events, as it isn't required by the specification. + */ +abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors { + mapping(address account => uint256) private _balances; + + mapping(address account => mapping(address spender => uint256)) private _allowances; + + uint256 private _totalSupply; + + string private _name; + string private _symbol; + + /** + * @dev Sets the values for {name} and {symbol}. + * + * All two of these values are immutable: they can only be set once during + * construction. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev Returns the name of the token. + */ + function name() public view virtual returns (string memory) { + return _name; + } + + /** + * @dev Returns the symbol of the token, usually a shorter version of the + * name. + */ + function symbol() public view virtual returns (string memory) { + return _symbol; + } + + /** + * @dev Returns the number of decimals used to get its user representation. + * For example, if `decimals` equals `2`, a balance of `505` tokens should + * be displayed to a user as `5.05` (`505 / 10 ** 2`). + * + * Tokens usually opt for a value of 18, imitating the relationship between + * Ether and Wei. This is the default value returned by this function, unless + * it's overridden. + * + * NOTE: This information is only used for _display_ purposes: it in + * no way affects any of the arithmetic of the contract, including + * {IERC20-balanceOf} and {IERC20-transfer}. + */ + function decimals() public view virtual returns (uint8) { + return 18; + } + + /** + * @dev See {IERC20-totalSupply}. + */ + function totalSupply() public view virtual returns (uint256) { + return _totalSupply; + } + + /** + * @dev See {IERC20-balanceOf}. + */ + function balanceOf(address account) public view virtual returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {IERC20-transfer}. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - the caller must have a balance of at least `value`. + */ + function transfer(address to, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _transfer(owner, to, value); + return true; + } + + /** + * @dev See {IERC20-allowance}. + */ + function allowance(address owner, address spender) public view virtual returns (uint256) { + return _allowances[owner][spender]; + } + + /** + * @dev See {IERC20-approve}. + * + * NOTE: If `value` is the maximum `uint256`, the allowance is not updated on + * `transferFrom`. This is semantically equivalent to an infinite approval. + * + * Requirements: + * + * - `spender` cannot be the zero address. + */ + function approve(address spender, uint256 value) public virtual returns (bool) { + address owner = _msgSender(); + _approve(owner, spender, value); + return true; + } + + /** + * @dev See {IERC20-transferFrom}. + * + * Emits an {Approval} event indicating the updated allowance. This is not + * required by the EIP. See the note at the beginning of {ERC20}. + * + * NOTE: Does not update the allowance if the current allowance + * is the maximum `uint256`. + * + * Requirements: + * + * - `from` and `to` cannot be the zero address. + * - `from` must have a balance of at least `value`. + * - the caller must have allowance for ``from``'s tokens of at least + * `value`. + */ + function transferFrom(address from, address to, uint256 value) public virtual returns (bool) { + address spender = _msgSender(); + _spendAllowance(from, spender, value); + _transfer(from, to, value); + return true; + } + + /** + * @dev Moves a `value` amount of tokens from `from` to `to`. + * + * This internal function is equivalent to {transfer}, and can be used to + * e.g. implement automatic token fees, slashing mechanisms, etc. + * + * Emits a {Transfer} event. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _transfer(address from, address to, uint256 value) internal { + if (from == address(0)) { + revert ERC20InvalidSender(address(0)); + } + if (to == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(from, to, value); + } + + /** + * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding + * this function. + * + * Emits a {Transfer} event. + */ + function _update(address from, address to, uint256 value) internal virtual { + if (from == address(0)) { + // Overflow check required: The rest of the code assumes that totalSupply never overflows + _totalSupply += value; + } else { + uint256 fromBalance = _balances[from]; + if (fromBalance < value) { + revert ERC20InsufficientBalance(from, fromBalance, value); + } + unchecked { + // Overflow not possible: value <= fromBalance <= totalSupply. + _balances[from] = fromBalance - value; + } + } + + if (to == address(0)) { + unchecked { + // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply. + _totalSupply -= value; + } + } else { + unchecked { + // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256. + _balances[to] += value; + } + } + + emit Transfer(from, to, value); + } + + /** + * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0). + * Relies on the `_update` mechanism + * + * Emits a {Transfer} event with `from` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead. + */ + function _mint(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidReceiver(address(0)); + } + _update(address(0), account, value); + } + + /** + * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply. + * Relies on the `_update` mechanism. + * + * Emits a {Transfer} event with `to` set to the zero address. + * + * NOTE: This function is not virtual, {_update} should be overridden instead + */ + function _burn(address account, uint256 value) internal { + if (account == address(0)) { + revert ERC20InvalidSender(address(0)); + } + _update(account, address(0), value); + } + + /** + * @dev Sets `value` as the allowance of `spender` over the `owner` s tokens. + * + * This internal function is equivalent to `approve`, and can be used to + * e.g. set automatic allowances for certain subsystems, etc. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `owner` cannot be the zero address. + * - `spender` cannot be the zero address. + * + * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. + */ + function _approve(address owner, address spender, uint256 value) internal { + _approve(owner, spender, value, true); + } + + /** + * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event. + * + * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by + * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any + * `Approval` event during `transferFrom` operations. + * + * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to + * true using the following override: + * ``` + * function _approve(address owner, address spender, uint256 value, bool) internal virtual override { + * super._approve(owner, spender, value, true); + * } + * ``` + * + * Requirements are the same as {_approve}. + */ + function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual { + if (owner == address(0)) { + revert ERC20InvalidApprover(address(0)); + } + if (spender == address(0)) { + revert ERC20InvalidSpender(address(0)); + } + _allowances[owner][spender] = value; + if (emitEvent) { + emit Approval(owner, spender, value); + } + } + + /** + * @dev Updates `owner` s allowance for `spender` based on spent `value`. + * + * Does not update the allowance value in case of infinite allowance. + * Revert if not enough allowance is available. + * + * Does not emit an {Approval} event. + */ + function _spendAllowance(address owner, address spender, uint256 value) internal virtual { + uint256 currentAllowance = allowance(owner, spender); + if (currentAllowance != type(uint256).max) { + if (currentAllowance < value) { + revert ERC20InsufficientAllowance(spender, currentAllowance, value); + } + unchecked { + _approve(owner, spender, currentAllowance - value, false); + } + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol new file mode 100644 index 0000000..db01cf4 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC20 standard as defined in the EIP. + */ +interface IERC20 { + /** + * @dev Emitted when `value` tokens are moved from one account (`from`) to + * another (`to`). + * + * Note that `value` may be zero. + */ + event Transfer(address indexed from, address indexed to, uint256 value); + + /** + * @dev Emitted when the allowance of a `spender` for an `owner` is set by + * a call to {approve}. `value` is the new allowance. + */ + event Approval(address indexed owner, address indexed spender, uint256 value); + + /** + * @dev Returns the value of tokens in existence. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns the value of tokens owned by `account`. + */ + function balanceOf(address account) external view returns (uint256); + + /** + * @dev Moves a `value` amount of tokens from the caller's account to `to`. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transfer(address to, uint256 value) external returns (bool); + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + */ + function allowance(address owner, address spender) external view returns (uint256); + + /** + * @dev Sets a `value` amount of tokens as the allowance of `spender` over the + * caller's tokens. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * IMPORTANT: Beware that changing an allowance with this method brings the risk + * that someone may use both the old and the new allowance by unfortunate + * transaction ordering. One possible solution to mitigate this race + * condition is to first reduce the spender's allowance to 0 and set the + * desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * + * Emits an {Approval} event. + */ + function approve(address spender, uint256 value) external returns (bool); + + /** + * @dev Moves a `value` amount of tokens from `from` to `to` using the + * allowance mechanism. `value` is then deducted from the caller's + * allowance. + * + * Returns a boolean value indicating whether the operation succeeded. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 value) external returns (bool); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc b/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc new file mode 100644 index 0000000..2c50880 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/README.adoc @@ -0,0 +1,67 @@ += ERC 20 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc20 + +This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-20[ERC20 Token Standard]. + +TIP: For an overview of ERC20 tokens and a walk through on how to create a token contract read our xref:ROOT:erc20.adoc[ERC20 guide]. + +There are a few core contracts that implement the behavior specified in the EIP: + +* {IERC20}: the interface all ERC20 implementations should conform to. +* {IERC20Metadata}: the extended ERC20 interface including the <>, <> and <> functions. +* {ERC20}: the implementation of the ERC20 interface, including the <>, <> and <> optional standard extension to the base interface. + +Additionally there are multiple custom extensions, including: + +* {ERC20Permit}: gasless approval of tokens (standardized as ERC2612). +* {ERC20Burnable}: destruction of own tokens. +* {ERC20Capped}: enforcement of a cap to the total supply when minting tokens. +* {ERC20Pausable}: ability to pause token transfers. +* {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC3156). +* {ERC20Votes}: support for voting and vote delegation. +* {ERC20Wrapper}: wrapper to create an ERC20 backed by another ERC20, with deposit and withdraw methods. Useful in conjunction with {ERC20Votes}. +* {ERC4626}: tokenized vault that manages shares (represented as ERC20) that are backed by assets (another ERC20). + +Finally, there are some utilities to interact with ERC20 contracts in various ways: + +* {SafeERC20}: a wrapper around the interface that eliminates the need to handle boolean return values. + +Other utilities that support ERC20 assets can be found in codebase: + +* ERC20 tokens can be timelocked (held tokens for a beneficiary until a specified time) or vested (released following a given schedule) using a {VestingWallet}. + +NOTE: This core set of contracts is designed to be unopinionated, allowing developers to access the internal functions in ERC20 (such as <>) and expose them as external functions in the way they prefer. + +== Core + +{{IERC20}} + +{{IERC20Metadata}} + +{{ERC20}} + +== Extensions + +{{IERC20Permit}} + +{{ERC20Permit}} + +{{ERC20Burnable}} + +{{ERC20Capped}} + +{{ERC20Pausable}} + +{{ERC20Votes}} + +{{ERC20Wrapper}} + +{{ERC20FlashMint}} + +{{ERC4626}} + +== Utilities + +{{SafeERC20}} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol new file mode 100644 index 0000000..4d482d8 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {Context} from "../../../utils/Context.sol"; + +/** + * @dev Extension of {ERC20} that allows token holders to destroy both their own + * tokens and those that they have an allowance for, in a way that can be + * recognized off-chain (via event analysis). + */ +abstract contract ERC20Burnable is Context, ERC20 { + /** + * @dev Destroys a `value` amount of tokens from the caller. + * + * See {ERC20-_burn}. + */ + function burn(uint256 value) public virtual { + _burn(_msgSender(), value); + } + + /** + * @dev Destroys a `value` amount of tokens from `account`, deducting from + * the caller's allowance. + * + * See {ERC20-_burn} and {ERC20-allowance}. + * + * Requirements: + * + * - the caller must have allowance for ``accounts``'s tokens of at least + * `value`. + */ + function burnFrom(address account, uint256 value) public virtual { + _spendAllowance(account, _msgSender(), value); + _burn(account, value); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol new file mode 100644 index 0000000..56bafb3 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Capped.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; + +/** + * @dev Extension of {ERC20} that adds a cap to the supply of tokens. + */ +abstract contract ERC20Capped is ERC20 { + uint256 private immutable _cap; + + /** + * @dev Total supply cap has been exceeded. + */ + error ERC20ExceededCap(uint256 increasedSupply, uint256 cap); + + /** + * @dev The supplied cap is not a valid cap. + */ + error ERC20InvalidCap(uint256 cap); + + /** + * @dev Sets the value of the `cap`. This value is immutable, it can only be + * set once during construction. + */ + constructor(uint256 cap_) { + if (cap_ == 0) { + revert ERC20InvalidCap(0); + } + _cap = cap_; + } + + /** + * @dev Returns the cap on the token's total supply. + */ + function cap() public view virtual returns (uint256) { + return _cap; + } + + /** + * @dev See {ERC20-_update}. + */ + function _update(address from, address to, uint256 value) internal virtual override { + super._update(from, to, value); + + if (from == address(0)) { + uint256 maxSupply = cap(); + uint256 supply = totalSupply(); + if (supply > maxSupply) { + revert ERC20ExceededCap(supply, maxSupply); + } + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol new file mode 100644 index 0000000..0e89312 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20FlashMint.sol) + +pragma solidity ^0.8.20; + +import {IERC3156FlashBorrower} from "../../../interfaces/IERC3156FlashBorrower.sol"; +import {IERC3156FlashLender} from "../../../interfaces/IERC3156FlashLender.sol"; +import {ERC20} from "../ERC20.sol"; + +/** + * @dev Implementation of the ERC3156 Flash loans extension, as defined in + * https://eips.ethereum.org/EIPS/eip-3156[ERC-3156]. + * + * Adds the {flashLoan} method, which provides flash loan support at the token + * level. By default there is no fee, but this can be changed by overriding {flashFee}. + * + * NOTE: When this extension is used along with the {ERC20Capped} or {ERC20Votes} extensions, + * {maxFlashLoan} will not correctly reflect the maximum that can be flash minted. We recommend + * overriding {maxFlashLoan} so that it correctly reflects the supply cap. + */ +abstract contract ERC20FlashMint is ERC20, IERC3156FlashLender { + bytes32 private constant RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan"); + + /** + * @dev The loan token is not valid. + */ + error ERC3156UnsupportedToken(address token); + + /** + * @dev The requested loan exceeds the max loan value for `token`. + */ + error ERC3156ExceededMaxLoan(uint256 maxLoan); + + /** + * @dev The receiver of a flashloan is not a valid {onFlashLoan} implementer. + */ + error ERC3156InvalidReceiver(address receiver); + + /** + * @dev Returns the maximum amount of tokens available for loan. + * @param token The address of the token that is requested. + * @return The amount of token that can be loaned. + * + * NOTE: This function does not consider any form of supply cap, so in case + * it's used in a token with a cap like {ERC20Capped}, make sure to override this + * function to integrate the cap instead of `type(uint256).max`. + */ + function maxFlashLoan(address token) public view virtual returns (uint256) { + return token == address(this) ? type(uint256).max - totalSupply() : 0; + } + + /** + * @dev Returns the fee applied when doing flash loans. This function calls + * the {_flashFee} function which returns the fee applied when doing flash + * loans. + * @param token The token to be flash loaned. + * @param value The amount of tokens to be loaned. + * @return The fees applied to the corresponding flash loan. + */ + function flashFee(address token, uint256 value) public view virtual returns (uint256) { + if (token != address(this)) { + revert ERC3156UnsupportedToken(token); + } + return _flashFee(token, value); + } + + /** + * @dev Returns the fee applied when doing flash loans. By default this + * implementation has 0 fees. This function can be overloaded to make + * the flash loan mechanism deflationary. + * @param token The token to be flash loaned. + * @param value The amount of tokens to be loaned. + * @return The fees applied to the corresponding flash loan. + */ + function _flashFee(address token, uint256 value) internal view virtual returns (uint256) { + // silence warning about unused variable without the addition of bytecode. + token; + value; + return 0; + } + + /** + * @dev Returns the receiver address of the flash fee. By default this + * implementation returns the address(0) which means the fee amount will be burnt. + * This function can be overloaded to change the fee receiver. + * @return The address for which the flash fee will be sent to. + */ + function _flashFeeReceiver() internal view virtual returns (address) { + return address(0); + } + + /** + * @dev Performs a flash loan. New tokens are minted and sent to the + * `receiver`, who is required to implement the {IERC3156FlashBorrower} + * interface. By the end of the flash loan, the receiver is expected to own + * value + fee tokens and have them approved back to the token contract itself so + * they can be burned. + * @param receiver The receiver of the flash loan. Should implement the + * {IERC3156FlashBorrower-onFlashLoan} interface. + * @param token The token to be flash loaned. Only `address(this)` is + * supported. + * @param value The amount of tokens to be loaned. + * @param data An arbitrary datafield that is passed to the receiver. + * @return `true` if the flash loan was successful. + */ + // This function can reenter, but it doesn't pose a risk because it always preserves the property that the amount + // minted at the beginning is always recovered and burned at the end, or else the entire function will revert. + // slither-disable-next-line reentrancy-no-eth + function flashLoan( + IERC3156FlashBorrower receiver, + address token, + uint256 value, + bytes calldata data + ) public virtual returns (bool) { + uint256 maxLoan = maxFlashLoan(token); + if (value > maxLoan) { + revert ERC3156ExceededMaxLoan(maxLoan); + } + uint256 fee = flashFee(token, value); + _mint(address(receiver), value); + if (receiver.onFlashLoan(_msgSender(), token, value, fee, data) != RETURN_VALUE) { + revert ERC3156InvalidReceiver(address(receiver)); + } + address flashFeeReceiver = _flashFeeReceiver(); + _spendAllowance(address(receiver), address(this), value + fee); + if (fee == 0 || flashFeeReceiver == address(0)) { + _burn(address(receiver), value + fee); + } else { + _burn(address(receiver), value); + _transfer(address(receiver), flashFeeReceiver, fee); + } + return true; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol new file mode 100644 index 0000000..8fe832b --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC20 token with pausable token transfers, minting and burning. + * + * 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 pause mechanism of the contract unreachable, and thus unusable. + */ +abstract contract ERC20Pausable is ERC20, Pausable { + /** + * @dev See {ERC20-_update}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _update(address from, address to, uint256 value) internal virtual override whenNotPaused { + super._update(from, to, value); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol new file mode 100644 index 0000000..36667ad --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol) + +pragma solidity ^0.8.20; + +import {IERC20Permit} from "./IERC20Permit.sol"; +import {ERC20} from "../ERC20.sol"; +import {ECDSA} from "../../../utils/cryptography/ECDSA.sol"; +import {EIP712} from "../../../utils/cryptography/EIP712.sol"; +import {Nonces} from "../../../utils/Nonces.sol"; + +/** + * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + */ +abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces { + bytes32 private constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + /** + * @dev Permit deadline has expired. + */ + error ERC2612ExpiredSignature(uint256 deadline); + + /** + * @dev Mismatched signature. + */ + error ERC2612InvalidSigner(address signer, address owner); + + /** + * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`. + * + * It's a good idea to use the same `name` that is defined as the ERC20 token name. + */ + constructor(string memory name) EIP712(name, "1") {} + + /** + * @inheritdoc IERC20Permit + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + if (block.timestamp > deadline) { + revert ERC2612ExpiredSignature(deadline); + } + + bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline)); + + bytes32 hash = _hashTypedDataV4(structHash); + + address signer = ECDSA.recover(hash, v, r, s); + if (signer != owner) { + revert ERC2612InvalidSigner(signer, owner); + } + + _approve(owner, spender, value); + } + + /** + * @inheritdoc IERC20Permit + */ + function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) { + return super.nonces(owner); + } + + /** + * @inheritdoc IERC20Permit + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view virtual returns (bytes32) { + return _domainSeparatorV4(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol new file mode 100644 index 0000000..6aa6ed0 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Votes.sol) + +pragma solidity ^0.8.20; + +import {ERC20} from "../ERC20.sol"; +import {Votes} from "../../../governance/utils/Votes.sol"; +import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; + +/** + * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's, + * and supports token supply up to 2^208^ - 1, while COMP is limited to 2^96^ - 1. + * + * NOTE: This contract does not provide interface compatibility with Compound's COMP token. + * + * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either + * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting + * power can be queried through the public accessors {getVotes} and {getPastVotes}. + * + * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it + * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked. + */ +abstract contract ERC20Votes is ERC20, Votes { + /** + * @dev Total supply cap has been exceeded, introducing a risk of votes overflowing. + */ + error ERC20ExceededSafeSupply(uint256 increasedSupply, uint256 cap); + + /** + * @dev Maximum token supply. Defaults to `type(uint208).max` (2^208^ - 1). + * + * This maximum is enforced in {_update}. It limits the total supply of the token, which is otherwise a uint256, + * so that checkpoints can be stored in the Trace208 structure used by {{Votes}}. Increasing this value will not + * remove the underlying limitation, and will cause {_update} to fail because of a math overflow in + * {_transferVotingUnits}. An override could be used to further restrict the total supply (to a lower value) if + * additional logic requires it. When resolving override conflicts on this function, the minimum should be + * returned. + */ + function _maxSupply() internal view virtual returns (uint256) { + return type(uint208).max; + } + + /** + * @dev Move voting power when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _update(address from, address to, uint256 value) internal virtual override { + super._update(from, to, value); + if (from == address(0)) { + uint256 supply = totalSupply(); + uint256 cap = _maxSupply(); + if (supply > cap) { + revert ERC20ExceededSafeSupply(supply, cap); + } + } + _transferVotingUnits(from, to, value); + } + + /** + * @dev Returns the voting units of an `account`. + * + * WARNING: Overriding this function may compromise the internal vote accounting. + * `ERC20Votes` assumes tokens map to voting units 1:1 and this is not easy to change. + */ + function _getVotingUnits(address account) internal view virtual override returns (uint256) { + return balanceOf(account); + } + + /** + * @dev Get number of checkpoints for `account`. + */ + function numCheckpoints(address account) public view virtual returns (uint32) { + return _numCheckpoints(account); + } + + /** + * @dev Get the `pos`-th checkpoint for `account`. + */ + function checkpoints(address account, uint32 pos) public view virtual returns (Checkpoints.Checkpoint208 memory) { + return _checkpoints(account, pos); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol new file mode 100644 index 0000000..6144880 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Wrapper.sol) + +pragma solidity ^0.8.20; + +import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol"; +import {SafeERC20} from "../utils/SafeERC20.sol"; + +/** + * @dev Extension of the ERC20 token contract to support token wrapping. + * + * Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful + * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC20Votes} will allow the + * wrapping of an existing "basic" ERC20 into a governance token. + */ +abstract contract ERC20Wrapper is ERC20 { + IERC20 private immutable _underlying; + + /** + * @dev The underlying token couldn't be wrapped. + */ + error ERC20InvalidUnderlying(address token); + + constructor(IERC20 underlyingToken) { + if (underlyingToken == this) { + revert ERC20InvalidUnderlying(address(this)); + } + _underlying = underlyingToken; + } + + /** + * @dev See {ERC20-decimals}. + */ + function decimals() public view virtual override returns (uint8) { + 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 value) public virtual returns (bool) { + address sender = _msgSender(); + if (sender == address(this)) { + revert ERC20InvalidSender(address(this)); + } + if (account == address(this)) { + revert ERC20InvalidReceiver(account); + } + SafeERC20.safeTransferFrom(_underlying, sender, address(this), value); + _mint(account, value); + return true; + } + + /** + * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens. + */ + function withdrawTo(address account, uint256 value) public virtual returns (bool) { + if (account == address(this)) { + revert ERC20InvalidReceiver(account); + } + _burn(_msgSender(), value); + SafeERC20.safeTransfer(_underlying, account, value); + return true; + } + + /** + * @dev Mint wrapped token to cover any underlyingTokens that would have been transferred by mistake. Internal + * 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(); + _mint(account, value); + return value; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol new file mode 100644 index 0000000..ec60872 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC4626.sol) + +pragma solidity ^0.8.20; + +import {IERC20, IERC20Metadata, ERC20} from "../ERC20.sol"; +import {SafeERC20} from "../utils/SafeERC20.sol"; +import {IERC4626} from "../../../interfaces/IERC4626.sol"; +import {Math} from "../../../utils/math/Math.sol"; + +/** + * @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in + * https://eips.ethereum.org/EIPS/eip-4626[EIP-4626]. + * + * This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for + * underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends + * 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] + * ==== + * 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 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]. + * ==== + */ +abstract contract ERC4626 is ERC20, IERC4626 { + using Math for uint256; + + IERC20 private immutable _asset; + uint8 private immutable _underlyingDecimals; + + /** + * @dev Attempted to deposit more assets than the max amount for `receiver`. + */ + error ERC4626ExceededMaxDeposit(address receiver, uint256 assets, uint256 max); + + /** + * @dev Attempted to mint more shares than the max amount for `receiver`. + */ + error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max); + + /** + * @dev Attempted to withdraw more assets than the max amount for `receiver`. + */ + error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max); + + /** + * @dev Attempted to redeem more shares than the max amount for `receiver`. + */ + error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max); + + /** + * @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_); + _underlyingDecimals = success ? assetDecimals : 18; + _asset = asset_; + } + + /** + * @dev Attempts to fetch the asset decimals. A return value of false indicates that the attempt failed in some way. + */ + function _tryGetAssetDecimals(IERC20 asset_) private view returns (bool, uint8) { + (bool success, bytes memory encodedDecimals) = address(asset_).staticcall( + abi.encodeCall(IERC20Metadata.decimals, ()) + ); + if (success && encodedDecimals.length >= 32) { + uint256 returnedDecimals = abi.decode(encodedDecimals, (uint256)); + if (returnedDecimals <= type(uint8).max) { + return (true, uint8(returnedDecimals)); + } + } + return (false, 0); + } + + /** + * @dev Decimals are 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) { + return _underlyingDecimals + _decimalsOffset(); + } + + /** @dev See {IERC4626-asset}. */ + function asset() public view virtual returns (address) { + return address(_asset); + } + + /** @dev See {IERC4626-totalAssets}. */ + function totalAssets() public view virtual returns (uint256) { + return _asset.balanceOf(address(this)); + } + + /** @dev See {IERC4626-convertToShares}. */ + function convertToShares(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Floor); + } + + /** @dev See {IERC4626-convertToAssets}. */ + function convertToAssets(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Floor); + } + + /** @dev See {IERC4626-maxDeposit}. */ + function maxDeposit(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4626-maxMint}. */ + function maxMint(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + /** @dev See {IERC4626-maxWithdraw}. */ + function maxWithdraw(address owner) public view virtual returns (uint256) { + return _convertToAssets(balanceOf(owner), Math.Rounding.Floor); + } + + /** @dev See {IERC4626-maxRedeem}. */ + function maxRedeem(address owner) public view virtual returns (uint256) { + return balanceOf(owner); + } + + /** @dev See {IERC4626-previewDeposit}. */ + function previewDeposit(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Floor); + } + + /** @dev See {IERC4626-previewMint}. */ + function previewMint(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Ceil); + } + + /** @dev See {IERC4626-previewWithdraw}. */ + function previewWithdraw(uint256 assets) public view virtual returns (uint256) { + return _convertToShares(assets, Math.Rounding.Ceil); + } + + /** @dev See {IERC4626-previewRedeem}. */ + function previewRedeem(uint256 shares) public view virtual returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Floor); + } + + /** @dev See {IERC4626-deposit}. */ + function deposit(uint256 assets, address receiver) public virtual returns (uint256) { + uint256 maxAssets = maxDeposit(receiver); + if (assets > maxAssets) { + revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets); + } + + uint256 shares = previewDeposit(assets); + _deposit(_msgSender(), receiver, assets, shares); + + return shares; + } + + /** @dev See {IERC4626-mint}. + * + * As opposed to {deposit}, minting is allowed even if the vault is in a state where the price of a share is zero. + * In this case, the shares will be minted without requiring any assets to be deposited. + */ + function mint(uint256 shares, address receiver) public virtual returns (uint256) { + uint256 maxShares = maxMint(receiver); + if (shares > maxShares) { + revert ERC4626ExceededMaxMint(receiver, shares, maxShares); + } + + uint256 assets = previewMint(shares); + _deposit(_msgSender(), receiver, assets, shares); + + return assets; + } + + /** @dev See {IERC4626-withdraw}. */ + function withdraw(uint256 assets, address receiver, address owner) public virtual returns (uint256) { + uint256 maxAssets = maxWithdraw(owner); + if (assets > maxAssets) { + revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets); + } + + uint256 shares = previewWithdraw(assets); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return shares; + } + + /** @dev See {IERC4626-redeem}. */ + function redeem(uint256 shares, address receiver, address owner) public virtual returns (uint256) { + uint256 maxShares = maxRedeem(owner); + if (shares > maxShares) { + revert ERC4626ExceededMaxRedeem(owner, shares, maxShares); + } + + uint256 assets = previewRedeem(shares); + _withdraw(_msgSender(), receiver, owner, assets, shares); + + return assets; + } + + /** + * @dev Internal conversion function (from assets to shares) with support for rounding direction. + */ + function _convertToShares(uint256 assets, Math.Rounding rounding) internal view virtual returns (uint256) { + 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) { + return shares.mulDiv(totalAssets() + 1, totalSupply() + 10 ** _decimalsOffset(), rounding); + } + + /** + * @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 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. + // + // Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the + // assets are transferred and before the shares are minted, which is a valid state. + // slither-disable-next-line reentrancy-no-eth + SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); + _mint(receiver, shares); + + emit Deposit(caller, receiver, assets, shares); + } + + /** + * @dev Withdraw/redeem common workflow. + */ + function _withdraw( + address caller, + address receiver, + address owner, + uint256 assets, + uint256 shares + ) internal virtual { + if (caller != owner) { + _spendAllowance(owner, caller, shares); + } + + // If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the + // `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer, + // calls the vault, which is assumed not malicious. + // + // Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the + // shares are burned and after the assets are transferred, which is a valid state. + _burn(owner, shares); + SafeERC20.safeTransfer(_asset, receiver, assets); + + emit Withdraw(caller, receiver, owner, assets, shares); + } + + function _decimalsOffset() internal view virtual returns (uint8) { + return 0; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol new file mode 100644 index 0000000..1a38cba --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../IERC20.sol"; + +/** + * @dev Interface for the optional metadata functions from the ERC20 standard. + */ +interface IERC20Metadata is IERC20 { + /** + * @dev Returns the name of the token. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the symbol of the token. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the decimals places of the token. + */ + function decimals() external view returns (uint8); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol new file mode 100644 index 0000000..5af4810 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in + * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. + * + * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by + * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't + * need to send a transaction, and thus is not required to hold Ether at all. + * + * ==== Security Considerations + * + * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature + * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be + * considered as an intention to spend the allowance in any specific way. The second is that because permits have + * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should + * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be + * generally recommended is: + * + * ```solidity + * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public { + * try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {} + * doThing(..., value); + * } + * + * function doThing(..., uint256 value) public { + * token.safeTransferFrom(msg.sender, address(this), value); + * ... + * } + * ``` + * + * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of + * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also + * {SafeERC20-safeTransferFrom}). + * + * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so + * contracts should have entry points that don't rely on permit. + */ +interface IERC20Permit { + /** + * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, + * given ``owner``'s signed approval. + * + * IMPORTANT: The same issues {IERC20-approve} has related to transaction + * ordering also apply here. + * + * Emits an {Approval} event. + * + * Requirements: + * + * - `spender` cannot be the zero address. + * - `deadline` must be a timestamp in the future. + * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` + * over the EIP712-formatted function arguments. + * - the signature must use ``owner``'s current nonce (see {nonces}). + * + * For more information on the signature format, see the + * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP + * section]. + * + * CAUTION: See Security Considerations above. + */ + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) external; + + /** + * @dev Returns the current nonce for `owner`. This value must be + * included whenever a signature is generated for {permit}. + * + * Every successful call to {permit} increases ``owner``'s nonce by one. This + * prevents a signature from being used multiple times. + */ + function nonces(address owner) external view returns (uint256); + + /** + * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. + */ + // solhint-disable-next-line func-name-mixedcase + function DOMAIN_SEPARATOR() external view returns (bytes32); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol b/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol new file mode 100644 index 0000000..bb65709 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol) + +pragma solidity ^0.8.20; + +import {IERC20} from "../IERC20.sol"; +import {IERC20Permit} from "../extensions/IERC20Permit.sol"; +import {Address} from "../../../utils/Address.sol"; + +/** + * @title SafeERC20 + * @dev Wrappers around ERC20 operations that throw on failure (when the token + * contract returns false). Tokens that return no value (and instead revert or + * throw on failure) are also supported, non-reverting calls are assumed to be + * successful. + * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, + * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. + */ +library SafeERC20 { + using Address for address; + + /** + * @dev An operation with an ERC20 token failed. + */ + error SafeERC20FailedOperation(address token); + + /** + * @dev Indicates a failed `decreaseAllowance` request. + */ + error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease); + + /** + * @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.encodeCall(token.transfer, (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.encodeCall(token.transferFrom, (from, to, 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 oldAllowance = token.allowance(address(this), spender); + forceApprove(token, spender, oldAllowance + value); + } + + /** + * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no + * value, non-reverting calls are assumed to be successful. + */ + function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal { + unchecked { + uint256 currentAllowance = token.allowance(address(this), spender); + if (currentAllowance < requestedDecrease) { + revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease); + } + forceApprove(token, spender, currentAllowance - requestedDecrease); + } + } + + /** + * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value, + * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval + * to be set to zero before setting it to a non-zero value, such as USDT. + */ + function forceApprove(IERC20 token, address spender, uint256 value) internal { + bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value)); + + if (!_callOptionalReturnBool(token, approvalCall)) { + _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0))); + _callOptionalReturn(token, approvalCall); + } + } + + /** + * @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). + */ + function _callOptionalReturn(IERC20 token, bytes memory data) private { + // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since + // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that + // the target address contains contract code and also asserts for success in the low-level call. + + bytes memory returndata = address(token).functionCall(data); + if (returndata.length != 0 && !abi.decode(returndata, (bool))) { + revert SafeERC20FailedOperation(address(token)); + } + } + + /** + * @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(token).code.length > 0; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol new file mode 100644 index 0000000..98a80e5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sol @@ -0,0 +1,483 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "./IERC721.sol"; +import {IERC721Receiver} from "./IERC721Receiver.sol"; +import {IERC721Metadata} from "./extensions/IERC721Metadata.sol"; +import {Context} from "../../utils/Context.sol"; +import {Strings} from "../../utils/Strings.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; +import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol"; + +/** + * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including + * the Metadata extension, but not including the Enumerable extension, which is available separately as + * {ERC721Enumerable}. + */ +abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors { + using Strings for uint256; + + // Token name + string private _name; + + // Token symbol + string private _symbol; + + mapping(uint256 tokenId => address) private _owners; + + mapping(address owner => uint256) private _balances; + + mapping(uint256 tokenId => address) private _tokenApprovals; + + mapping(address owner => mapping(address operator => bool)) private _operatorApprovals; + + /** + * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection. + */ + constructor(string memory name_, string memory symbol_) { + _name = name_; + _symbol = symbol_; + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return + interfaceId == type(IERC721).interfaceId || + interfaceId == type(IERC721Metadata).interfaceId || + super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721-balanceOf}. + */ + function balanceOf(address owner) public view virtual returns (uint256) { + if (owner == address(0)) { + revert ERC721InvalidOwner(address(0)); + } + return _balances[owner]; + } + + /** + * @dev See {IERC721-ownerOf}. + */ + function ownerOf(uint256 tokenId) public view virtual returns (address) { + return _requireOwned(tokenId); + } + + /** + * @dev See {IERC721Metadata-name}. + */ + function name() public view virtual returns (string memory) { + return _name; + } + + /** + * @dev See {IERC721Metadata-symbol}. + */ + function symbol() public view virtual returns (string memory) { + return _symbol; + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual returns (string memory) { + _requireOwned(tokenId); + + string memory baseURI = _baseURI(); + return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : ""; + } + + /** + * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each + * token will be the concatenation of the `baseURI` and the `tokenId`. Empty + * by default, can be overridden in child contracts. + */ + function _baseURI() internal view virtual returns (string memory) { + return ""; + } + + /** + * @dev See {IERC721-approve}. + */ + function approve(address to, uint256 tokenId) public virtual { + _approve(to, tokenId, _msgSender()); + } + + /** + * @dev See {IERC721-getApproved}. + */ + function getApproved(uint256 tokenId) public view virtual returns (address) { + _requireOwned(tokenId); + + return _getApproved(tokenId); + } + + /** + * @dev See {IERC721-setApprovalForAll}. + */ + function setApprovalForAll(address operator, bool approved) public virtual { + _setApprovalForAll(_msgSender(), operator, approved); + } + + /** + * @dev See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner, address operator) public view virtual returns (bool) { + return _operatorApprovals[owner][operator]; + } + + /** + * @dev See {IERC721-transferFrom}. + */ + function transferFrom(address from, address to, uint256 tokenId) public virtual { + if (to == address(0)) { + revert ERC721InvalidReceiver(address(0)); + } + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + address previousOwner = _update(to, tokenId, _msgSender()); + if (previousOwner != from) { + revert ERC721IncorrectOwner(from, tokenId, previousOwner); + } + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) public { + safeTransferFrom(from, to, tokenId, ""); + } + + /** + * @dev See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual { + transferFrom(from, to, tokenId); + _checkOnERC721Received(from, to, tokenId, data); + } + + /** + * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist + * + * IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the + * core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances + * consistent with ownership. The invariant to preserve is 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`. + */ + function _ownerOf(uint256 tokenId) internal view virtual returns (address) { + return _owners[tokenId]; + } + + /** + * @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted. + */ + function _getApproved(uint256 tokenId) internal view virtual returns (address) { + return _tokenApprovals[tokenId]; + } + + /** + * @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in + * particular (ignoring whether it is owned by `owner`). + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + */ + function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) { + return + spender != address(0) && + (owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender); + } + + /** + * @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner. + * Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets + * the `spender` for the specific `tokenId`. + * + * WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this + * assumption. + */ + function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual { + if (!_isAuthorized(owner, spender, tokenId)) { + if (owner == address(0)) { + revert ERC721NonexistentToken(tokenId); + } else { + revert ERC721InsufficientApproval(spender, tokenId); + } + } + } + + /** + * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override. + * + * NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that + * a uint256 would ever overflow from increments when these increments are bounded to uint128 values. + * + * WARNING: Increasing an account's balance using this function tends to be paired with an override of the + * {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership + * remain consistent with one another. + */ + function _increaseBalance(address account, uint128 value) internal virtual { + unchecked { + _balances[account] += value; + } + } + + /** + * @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner + * (or `to`) is the zero address. Returns the owner of the `tokenId` before the update. + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that + * `auth` is either the owner of the token, or approved to operate on the token (by the owner). + * + * Emits a {Transfer} event. + * + * NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}. + */ + function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) { + address from = _ownerOf(tokenId); + + // Perform (optional) operator check + if (auth != address(0)) { + _checkAuthorized(from, auth, tokenId); + } + + // Execute the update + if (from != address(0)) { + // Clear approval. No need to re-authorize or emit the Approval event + _approve(address(0), tokenId, address(0), false); + + unchecked { + _balances[from] -= 1; + } + } + + if (to != address(0)) { + unchecked { + _balances[to] += 1; + } + } + + _owners[tokenId] = to; + + emit Transfer(from, to, tokenId); + + return from; + } + + /** + * @dev Mints `tokenId` and transfers it to `to`. + * + * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible + * + * Requirements: + * + * - `tokenId` must not exist. + * - `to` cannot be the zero address. + * + * Emits a {Transfer} event. + */ + function _mint(address to, uint256 tokenId) internal { + if (to == address(0)) { + revert ERC721InvalidReceiver(address(0)); + } + address previousOwner = _update(to, tokenId, address(0)); + if (previousOwner != address(0)) { + revert ERC721InvalidSender(address(0)); + } + } + + /** + * @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance. + * + * Requirements: + * + * - `tokenId` must not exist. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeMint(address to, uint256 tokenId) internal { + _safeMint(to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual { + _mint(to, tokenId); + _checkOnERC721Received(address(0), to, tokenId, data); + } + + /** + * @dev Destroys `tokenId`. + * The approval is cleared when the token is burned. + * This is an internal function that does not check if the sender is authorized to operate on the token. + * + * Requirements: + * + * - `tokenId` must exist. + * + * Emits a {Transfer} event. + */ + function _burn(uint256 tokenId) internal { + address previousOwner = _update(address(0), tokenId, address(0)); + if (previousOwner == address(0)) { + revert ERC721NonexistentToken(tokenId); + } + } + + /** + * @dev Transfers `tokenId` from `from` to `to`. + * As opposed to {transferFrom}, this imposes no restrictions on msg.sender. + * + * Requirements: + * + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * + * Emits a {Transfer} event. + */ + function _transfer(address from, address to, uint256 tokenId) internal { + if (to == address(0)) { + revert ERC721InvalidReceiver(address(0)); + } + address previousOwner = _update(to, tokenId, address(0)); + if (previousOwner == address(0)) { + revert ERC721NonexistentToken(tokenId); + } else if (previousOwner != from) { + revert ERC721IncorrectOwner(from, tokenId, previousOwner); + } + } + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients + * are aware of the ERC721 standard to prevent tokens from being forever locked. + * + * `data` is additional data, it has no specified format and it is sent in call to `to`. + * + * This internal function is like {safeTransferFrom} in the sense that it invokes + * {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g. + * implement alternative mechanisms to perform token transfer, such as signature-based. + * + * Requirements: + * + * - `tokenId` token must exist and be owned by `from`. + * - `to` cannot be the zero address. + * - `from` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. + * + * Emits a {Transfer} event. + */ + function _safeTransfer(address from, address to, uint256 tokenId) internal { + _safeTransfer(from, to, tokenId, ""); + } + + /** + * @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is + * forwarded in {IERC721Receiver-onERC721Received} to contract recipients. + */ + function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual { + _transfer(from, to, tokenId); + _checkOnERC721Received(from, to, tokenId, data); + } + + /** + * @dev Approve `to` to operate on `tokenId` + * + * The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is + * either the owner of the token, or approved to operate on all tokens held by this owner. + * + * Emits an {Approval} event. + * + * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument. + */ + function _approve(address to, uint256 tokenId, address auth) internal { + _approve(to, tokenId, auth, true); + } + + /** + * @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not + * emitted in the context of transfers. + */ + function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual { + // Avoid reading the owner unless necessary + if (emitEvent || auth != address(0)) { + address owner = _requireOwned(tokenId); + + // We do not use _isAuthorized because single-token approvals should not be able to call approve + if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) { + revert ERC721InvalidApprover(auth); + } + + if (emitEvent) { + emit Approval(owner, to, tokenId); + } + } + + _tokenApprovals[tokenId] = to; + } + + /** + * @dev Approve `operator` to operate on all of `owner` tokens + * + * Requirements: + * - operator can't be the address zero. + * + * Emits an {ApprovalForAll} event. + */ + function _setApprovalForAll(address owner, address operator, bool approved) internal virtual { + if (operator == address(0)) { + revert ERC721InvalidOperator(operator); + } + _operatorApprovals[owner][operator] = approved; + emit ApprovalForAll(owner, operator, approved); + } + + /** + * @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned). + * Returns the owner. + * + * Overrides to ownership logic should be done to {_ownerOf}. + */ + function _requireOwned(uint256 tokenId) internal view returns (address) { + address owner = _ownerOf(tokenId); + if (owner == address(0)) { + revert ERC721NonexistentToken(tokenId); + } + return owner; + } + + /** + * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the + * recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract. + * + * @param from address representing the previous owner of the given token ID + * @param to target address that will receive the tokens + * @param tokenId uint256 ID of the token to be transferred + * @param data bytes optional data to send along with the call + */ + function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private { + if (to.code.length > 0) { + try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) { + if (retval != IERC721Receiver.onERC721Received.selector) { + revert ERC721InvalidReceiver(to); + } + } catch (bytes memory reason) { + if (reason.length == 0) { + revert ERC721InvalidReceiver(to); + } else { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, reason), mload(reason)) + } + } + } + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol new file mode 100644 index 0000000..12f3236 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "../../utils/introspection/IERC165.sol"; + +/** + * @dev Required interface of an ERC721 compliant contract. + */ +interface IERC721 is IERC165 { + /** + * @dev Emitted when `tokenId` token is transferred from `from` to `to`. + */ + event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. + */ + event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); + + /** + * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. + */ + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /** + * @dev Returns the number of tokens in ``owner``'s account. + */ + function balanceOf(address owner) external view returns (uint256 balance); + + /** + * @dev Returns the owner of the `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function ownerOf(uint256 tokenId) external view returns (address owner); + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon + * a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; + + /** + * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients + * are aware of the ERC721 protocol to prevent tokens from being forever locked. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must exist and be owned by `from`. + * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or + * {setApprovalForAll}. + * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon + * a safe transfer. + * + * Emits a {Transfer} event. + */ + function safeTransferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Transfers `tokenId` token from `from` to `to`. + * + * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 + * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must + * understand this adds an external call which potentially creates a reentrancy vulnerability. + * + * Requirements: + * + * - `from` cannot be the zero address. + * - `to` cannot be the zero address. + * - `tokenId` token must be owned by `from`. + * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * + * Emits a {Transfer} event. + */ + function transferFrom(address from, address to, uint256 tokenId) external; + + /** + * @dev Gives permission to `to` to transfer `tokenId` token to another account. + * The approval is cleared when the token is transferred. + * + * Only a single account can be approved at a time, so approving the zero address clears previous approvals. + * + * Requirements: + * + * - The caller must own the token or be an approved operator. + * - `tokenId` must exist. + * + * Emits an {Approval} event. + */ + function approve(address to, uint256 tokenId) external; + + /** + * @dev Approve or remove `operator` as an operator for the caller. + * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. + * + * Requirements: + * + * - The `operator` cannot be the address zero. + * + * Emits an {ApprovalForAll} event. + */ + function setApprovalForAll(address operator, bool approved) external; + + /** + * @dev Returns the account approved for `tokenId` token. + * + * Requirements: + * + * - `tokenId` must exist. + */ + function getApproved(uint256 tokenId) external view returns (address operator); + + /** + * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. + * + * See {setApprovalForAll} + */ + function isApprovedForAll(address owner, address operator) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol new file mode 100644 index 0000000..f9dc133 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol) + +pragma solidity ^0.8.20; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be + * reverted. + * + * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc b/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc new file mode 100644 index 0000000..40ae919 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/README.adoc @@ -0,0 +1,67 @@ += ERC 721 + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/token/erc721 + +This set of interfaces, contracts, and utilities are all related to the https://eips.ethereum.org/EIPS/eip-721[ERC721 Non-Fungible Token Standard]. + +TIP: For a walk through on how to create an ERC721 token read our xref:ROOT:erc721.adoc[ERC721 guide]. + +The EIP specifies four interfaces: + +* {IERC721}: Core functionality required in all compliant implementation. +* {IERC721Metadata}: Optional extension that adds name, symbol, and token URI, almost always included. +* {IERC721Enumerable}: Optional extension that allows enumerating the tokens on chain, often not included since it requires large gas overhead. +* {IERC721Receiver}: An interface that must be implemented by contracts if they want to accept tokens through `safeTransferFrom`. + +OpenZeppelin Contracts provides implementations of all four interfaces: + +* {ERC721}: The core and metadata extensions, with a base URI mechanism. +* {ERC721Enumerable}: The enumerable extension. +* {ERC721Holder}: A bare bones implementation of the receiver interface. + +Additionally there are a few of other extensions: + +* {ERC721Consecutive}: An implementation of https://eips.ethereum.org/EIPS/eip-2309[ERC2309] for minting batchs of tokens during construction, in accordance with ERC721. +* {ERC721URIStorage}: A more flexible but more expensive way of storing metadata. +* {ERC721Votes}: Support for voting and vote delegation. +* {ERC721Royalty}: A way to signal royalty information following ERC2981. +* {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. + +== Core + +{{IERC721}} + +{{IERC721Metadata}} + +{{IERC721Enumerable}} + +{{ERC721}} + +{{ERC721Enumerable}} + +{{IERC721Receiver}} + +== Extensions + +{{ERC721Pausable}} + +{{ERC721Burnable}} + +{{ERC721Consecutive}} + +{{ERC721URIStorage}} + +{{ERC721Votes}} + +{{ERC721Royalty}} + +{{ERC721Wrapper}} + +== Utilities + +{{ERC721Holder}} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol new file mode 100644 index 0000000..2a150af --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Burnable.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Context} from "../../../utils/Context.sol"; + +/** + * @title ERC721 Burnable Token + * @dev ERC721 Token that can be burned (destroyed). + */ +abstract contract ERC721Burnable is Context, ERC721 { + /** + * @dev Burns `tokenId`. See {ERC721-_burn}. + * + * Requirements: + * + * - The caller must own `tokenId` or be an approved operator. + */ + function burn(uint256 tokenId) public virtual { + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + _update(address(0), tokenId, _msgSender()); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol new file mode 100644 index 0000000..0d6cbc7 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sol @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Consecutive.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {IERC2309} from "../../../interfaces/IERC2309.sol"; +import {BitMaps} from "../../../utils/structs/BitMaps.sol"; +import {Checkpoints} from "../../../utils/structs/Checkpoints.sol"; + +/** + * @dev Implementation of the ERC2309 "Consecutive Transfer Extension" as defined in + * https://eips.ethereum.org/EIPS/eip-2309[EIP-2309]. + * + * This extension allows the minting of large batches of tokens, during contract construction only. For upgradeable + * contracts this implies that batch minting is only available during proxy deployment, and not in subsequent upgrades. + * These batches are limited to 5000 tokens at a time by default to accommodate off-chain indexers. + * + * Using this extension removes the ability to mint single tokens during contract construction. This ability is + * regained after construction. During construction, only batch minting is allowed. + * + * IMPORTANT: This extension does not call the {_update} function for tokens minted in batch. Any logic added to this + * function through overrides will not be triggered when token are minted in batch. You may want to also override + * {_increaseBalance} or {_mintConsecutive} to account for these mints. + * + * IMPORTANT: When overriding {_mintConsecutive}, be careful about call ordering. {ownerOf} may return invalid + * values during the {_mintConsecutive} execution if the super call is not called first. To be safe, execute the + * super call before your custom logic. + */ +abstract contract ERC721Consecutive is IERC2309, ERC721 { + using BitMaps for BitMaps.BitMap; + using Checkpoints for Checkpoints.Trace160; + + Checkpoints.Trace160 private _sequentialOwnership; + BitMaps.BitMap private _sequentialBurn; + + /** + * @dev Batch mint is restricted to the constructor. + * Any batch mint not emitting the {IERC721-Transfer} event outside of the constructor + * is non-ERC721 compliant. + */ + error ERC721ForbiddenBatchMint(); + + /** + * @dev Exceeds the max amount of mints per batch. + */ + error ERC721ExceededMaxBatchMint(uint256 batchSize, uint256 maxBatch); + + /** + * @dev Individual minting is not allowed. + */ + error ERC721ForbiddenMint(); + + /** + * @dev Batch burn is not supported. + */ + error ERC721ForbiddenBatchBurn(); + + /** + * @dev Maximum size of a batch of consecutive tokens. This is designed to limit stress on off-chain indexing + * services that have to record one entry per token, and have protections against "unreasonably large" batches of + * tokens. + * + * NOTE: Overriding the default value of 5000 will not cause on-chain issues, but may result in the asset not being + * correctly supported by off-chain indexing services (including marketplaces). + */ + function _maxBatchSize() internal view virtual returns (uint96) { + return 5000; + } + + /** + * @dev See {ERC721-_ownerOf}. Override that checks the sequential ownership structure for tokens that have + * been minted as part of a batch, and not yet transferred. + */ + function _ownerOf(uint256 tokenId) internal view virtual override returns (address) { + address owner = super._ownerOf(tokenId); + + // If token is owned by the core, or beyond consecutive range, return base value + if (owner != address(0) || tokenId > type(uint96).max || tokenId < _firstConsecutiveId()) { + return owner; + } + + // Otherwise, check the token was not burned, and fetch ownership from the anchors + // Note: no need for safe cast, we know that tokenId <= type(uint96).max + return _sequentialBurn.get(tokenId) ? address(0) : address(_sequentialOwnership.lowerLookup(uint96(tokenId))); + } + + /** + * @dev Mint a batch of tokens of length `batchSize` for `to`. Returns the token id of the first token minted in the + * batch; if `batchSize` is 0, returns the number of consecutive ids minted so far. + * + * Requirements: + * + * - `batchSize` must not be greater than {_maxBatchSize}. + * - The function is called in the constructor of the contract (directly or indirectly). + * + * CAUTION: Does not emit a `Transfer` event. This is ERC721 compliant as long as it is done inside of the + * constructor, which is enforced by this function. + * + * CAUTION: Does not invoke `onERC721Received` on the receiver. + * + * Emits a {IERC2309-ConsecutiveTransfer} event. + */ + function _mintConsecutive(address to, uint96 batchSize) internal virtual returns (uint96) { + uint96 next = _nextConsecutiveId(); + + // minting a batch of size 0 is a no-op + if (batchSize > 0) { + if (address(this).code.length > 0) { + revert ERC721ForbiddenBatchMint(); + } + if (to == address(0)) { + revert ERC721InvalidReceiver(address(0)); + } + + uint256 maxBatchSize = _maxBatchSize(); + if (batchSize > maxBatchSize) { + revert ERC721ExceededMaxBatchMint(batchSize, maxBatchSize); + } + + // push an ownership checkpoint & emit event + uint96 last = next + 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`. + _increaseBalance(to, batchSize); + + emit ConsecutiveTransfer(next, last, address(0), to); + } + + return next; + } + + /** + * @dev See {ERC721-_update}. Override version that restricts normal minting to after construction. + * + * WARNING: Using {ERC721Consecutive} prevents minting during construction in favor of {_mintConsecutive}. + * After construction, {_mintConsecutive} is no longer available and minting through {_update} becomes available. + */ + function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) { + address previousOwner = super._update(to, tokenId, auth); + + // only mint after construction + if (previousOwner == address(0) && address(this).code.length == 0) { + revert ERC721ForbiddenMint(); + } + + // record burn + if ( + to == address(0) && // if we burn + tokenId < _nextConsecutiveId() && // and the tokenId was minted in a batch + !_sequentialBurn.get(tokenId) // and the token was never marked as burnt + ) { + _sequentialBurn.set(tokenId); + } + + return previousOwner; + } + + /** + * @dev Used to offset the first token id in {_nextConsecutiveId} + */ + function _firstConsecutiveId() internal view virtual returns (uint96) { + return 0; + } + + /** + * @dev Returns the next tokenId to mint using {_mintConsecutive}. It will return {_firstConsecutiveId} + * if no consecutive tokenId has been minted before. + */ + function _nextConsecutiveId() private view returns (uint96) { + (bool exists, uint96 latestId, ) = _sequentialOwnership.latestCheckpoint(); + return exists ? latestId + 1 : _firstConsecutiveId(); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol new file mode 100644 index 0000000..cbf3e03 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {IERC721Enumerable} from "./IERC721Enumerable.sol"; +import {IERC165} from "../../../utils/introspection/ERC165.sol"; + +/** + * @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability + * of all the token ids in the contract as well as all token ids owned by each account. + * + * CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`, + * interfere with enumerability and should not be used together with `ERC721Enumerable`. + */ +abstract contract ERC721Enumerable is ERC721, IERC721Enumerable { + mapping(address owner => mapping(uint256 index => uint256)) private _ownedTokens; + mapping(uint256 tokenId => uint256) private _ownedTokensIndex; + + uint256[] private _allTokens; + mapping(uint256 tokenId => uint256) private _allTokensIndex; + + /** + * @dev An `owner`'s token query was out of bounds for `index`. + * + * NOTE: The owner being `address(0)` indicates a global out of bounds index. + */ + error ERC721OutOfBoundsIndex(address owner, uint256 index); + + /** + * @dev Batch mint is not allowed. + */ + error ERC721EnumerableForbiddenBatchMint(); + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) { + return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) { + if (index >= balanceOf(owner)) { + revert ERC721OutOfBoundsIndex(owner, index); + } + return _ownedTokens[owner][index]; + } + + /** + * @dev See {IERC721Enumerable-totalSupply}. + */ + function totalSupply() public view virtual returns (uint256) { + return _allTokens.length; + } + + /** + * @dev See {IERC721Enumerable-tokenByIndex}. + */ + function tokenByIndex(uint256 index) public view virtual returns (uint256) { + if (index >= totalSupply()) { + revert ERC721OutOfBoundsIndex(address(0), index); + } + return _allTokens[index]; + } + + /** + * @dev See {ERC721-_update}. + */ + function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) { + address previousOwner = super._update(to, tokenId, auth); + + if (previousOwner == address(0)) { + _addTokenToAllTokensEnumeration(tokenId); + } else if (previousOwner != to) { + _removeTokenFromOwnerEnumeration(previousOwner, tokenId); + } + if (to == address(0)) { + _removeTokenFromAllTokensEnumeration(tokenId); + } else if (previousOwner != to) { + _addTokenToOwnerEnumeration(to, tokenId); + } + + return previousOwner; + } + + /** + * @dev Private function to add a token to this extension's ownership-tracking data structures. + * @param to address representing the new owner of the given token ID + * @param tokenId uint256 ID of the token to be added to the tokens list of the given address + */ + function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { + uint256 length = balanceOf(to) - 1; + _ownedTokens[to][length] = tokenId; + _ownedTokensIndex[tokenId] = length; + } + + /** + * @dev Private function to add a token to this extension's token tracking data structures. + * @param tokenId uint256 ID of the token to be added to the tokens list + */ + function _addTokenToAllTokensEnumeration(uint256 tokenId) private { + _allTokensIndex[tokenId] = _allTokens.length; + _allTokens.push(tokenId); + } + + /** + * @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that + * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for + * gas optimizations e.g. when performing a transfer operation (avoiding double writes). + * This has O(1) time complexity, but alters the order of the _ownedTokens array. + * @param from address representing the previous owner of the given token ID + * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address + */ + function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { + // To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = balanceOf(from); + uint256 tokenIndex = _ownedTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary + if (tokenIndex != lastTokenIndex) { + uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; + + _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + } + + // This also deletes the contents at the last position of the array + delete _ownedTokensIndex[tokenId]; + delete _ownedTokens[from][lastTokenIndex]; + } + + /** + * @dev Private function to remove a token from this extension's token tracking data structures. + * This has O(1) time complexity, but alters the order of the _allTokens array. + * @param tokenId uint256 ID of the token to be removed from the tokens list + */ + function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { + // To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and + // then delete the last slot (swap and pop). + + uint256 lastTokenIndex = _allTokens.length - 1; + uint256 tokenIndex = _allTokensIndex[tokenId]; + + // When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so + // rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding + // an 'if' statement (like in _removeTokenFromOwnerEnumeration) + uint256 lastTokenId = _allTokens[lastTokenIndex]; + + _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token + _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index + + // This also deletes the contents at the last position of the array + delete _allTokensIndex[tokenId]; + _allTokens.pop(); + } + + /** + * See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch + */ + function _increaseBalance(address account, uint128 amount) internal virtual override { + if (amount > 0) { + revert ERC721EnumerableForbiddenBatchMint(); + } + super._increaseBalance(account, amount); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol new file mode 100644 index 0000000..0b34fd9 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Pausable.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Pausable} from "../../../utils/Pausable.sol"; + +/** + * @dev ERC721 token with pausable token transfers, minting and burning. + * + * 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 pause mechanism of the contract unreachable, and thus unusable. + */ +abstract contract ERC721Pausable is ERC721, Pausable { + /** + * @dev See {ERC721-_update}. + * + * Requirements: + * + * - the contract must not be paused. + */ + function _update( + address to, + uint256 tokenId, + address auth + ) internal virtual override whenNotPaused returns (address) { + return super._update(to, tokenId, auth); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol new file mode 100644 index 0000000..be98ec7 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Royalty.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {ERC2981} from "../../common/ERC2981.sol"; + +/** + * @dev Extension of ERC721 with the ERC2981 NFT Royalty Standard, a standardized way to retrieve royalty payment + * information. + * + * Royalty information can be specified globally for all token ids via {ERC2981-_setDefaultRoyalty}, and/or individually + * for specific token ids via {ERC2981-_setTokenRoyalty}. The latter takes precedence over the first. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + */ +abstract contract ERC721Royalty is ERC2981, ERC721 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981) returns (bool) { + return super.supportsInterface(interfaceId); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol new file mode 100644 index 0000000..2584cb5 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721URIStorage.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Strings} from "../../../utils/Strings.sol"; +import {IERC4906} from "../../../interfaces/IERC4906.sol"; +import {IERC165} from "../../../interfaces/IERC165.sol"; + +/** + * @dev ERC721 token with storage based token URI management. + */ +abstract contract ERC721URIStorage is IERC4906, ERC721 { + using Strings for uint256; + + // Interface ID as defined in ERC-4906. This does not correspond to a traditional interface ID as ERC-4906 only + // defines events and does not include any external function. + bytes4 private constant ERC4906_INTERFACE_ID = bytes4(0x49064906); + + // Optional mapping for token URIs + mapping(uint256 tokenId => string) private _tokenURIs; + + /** + * @dev See {IERC165-supportsInterface} + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) { + return interfaceId == ERC4906_INTERFACE_ID || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC721Metadata-tokenURI}. + */ + function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { + _requireOwned(tokenId); + + string memory _tokenURI = _tokenURIs[tokenId]; + string memory base = _baseURI(); + + // If there is no base URI, return the token URI. + if (bytes(base).length == 0) { + return _tokenURI; + } + // If both are set, concatenate the baseURI and tokenURI (via string.concat). + if (bytes(_tokenURI).length > 0) { + return string.concat(base, _tokenURI); + } + + return super.tokenURI(tokenId); + } + + /** + * @dev Sets `_tokenURI` as the tokenURI of `tokenId`. + * + * Emits {MetadataUpdate}. + */ + function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual { + _tokenURIs[tokenId] = _tokenURI; + emit MetadataUpdate(tokenId); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol new file mode 100644 index 0000000..5628715 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Votes.sol) + +pragma solidity ^0.8.20; + +import {ERC721} from "../ERC721.sol"; +import {Votes} from "../../../governance/utils/Votes.sol"; + +/** + * @dev Extension of ERC721 to support voting and delegation as implemented by {Votes}, where each individual NFT counts + * as 1 vote unit. + * + * Tokens do not count as votes until they are delegated, because votes must be tracked which incurs an additional cost + * on every transfer. Token holders can either delegate to a trusted representative who will decide how to make use of + * the votes in governance decisions, or they can delegate to themselves to be their own representative. + */ +abstract contract ERC721Votes is ERC721, Votes { + /** + * @dev See {ERC721-_update}. Adjusts votes when tokens are transferred. + * + * Emits a {IVotes-DelegateVotesChanged} event. + */ + function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) { + address previousOwner = super._update(to, tokenId, auth); + + _transferVotingUnits(previousOwner, to, 1); + + return previousOwner; + } + + /** + * @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); + } + + /** + * @dev See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch. + */ + function _increaseBalance(address account, uint128 amount) internal virtual override { + super._increaseBalance(account, amount); + _transferVotingUnits(address(0), account, amount); + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol new file mode 100644 index 0000000..e091bdd --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Wrapper.sol) + +pragma solidity ^0.8.20; + +import {IERC721, ERC721} from "../ERC721.sol"; +import {IERC721Receiver} from "../IERC721Receiver.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. + */ +abstract contract ERC721Wrapper is ERC721, IERC721Receiver { + IERC721 private immutable _underlying; + + /** + * @dev The received ERC721 token couldn't be wrapped. + */ + error ERC721UnsupportedToken(address token); + + 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) { + uint256 length = tokenIds.length; + for (uint256 i = 0; i < length; ++i) { + 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; + } + + /** + * @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]; + // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists + // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. + _update(address(0), tokenId, _msgSender()); + // 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 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 from, uint256 tokenId, bytes memory) public virtual returns (bytes4) { + if (address(underlying()) != _msgSender()) { + revert ERC721UnsupportedToken(_msgSender()); + } + _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) { + address owner = underlying().ownerOf(tokenId); + if (owner != address(this)) { + revert ERC721IncorrectOwner(address(this), tokenId, owner); + } + _safeMint(account, tokenId); + return tokenId; + } + + /** + * @dev Returns the underlying token. + */ + function underlying() public view virtual returns (IERC721) { + return _underlying; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol new file mode 100644 index 0000000..7a09cc6 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Enumerable is IERC721 { + /** + * @dev Returns the total amount of tokens stored by the contract. + */ + function totalSupply() external view returns (uint256); + + /** + * @dev Returns a token ID owned by `owner` at a given `index` of its token list. + * Use along with {balanceOf} to enumerate all of ``owner``'s tokens. + */ + function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256); + + /** + * @dev Returns a token ID at a given `index` of all the tokens stored by the contract. + * Use along with {totalSupply} to enumerate all tokens. + */ + function tokenByIndex(uint256 index) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol new file mode 100644 index 0000000..e9e00fa --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) + +pragma solidity ^0.8.20; + +import {IERC721} from "../IERC721.sol"; + +/** + * @title ERC-721 Non-Fungible Token Standard, optional metadata extension + * @dev See https://eips.ethereum.org/EIPS/eip-721 + */ +interface IERC721Metadata is IERC721 { + /** + * @dev Returns the token collection name. + */ + function name() external view returns (string memory); + + /** + * @dev Returns the token collection symbol. + */ + function symbol() external view returns (string memory); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. + */ + function tokenURI(uint256 tokenId) external view returns (string memory); +} diff --git a/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol b/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol new file mode 100644 index 0000000..6bb23ac --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol) + +pragma solidity ^0.8.20; + +import {IERC721Receiver} from "../IERC721Receiver.sol"; + +/** + * @dev Implementation of the {IERC721Receiver} interface. + * + * Accepts all token transfers. + * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or + * {IERC721-setApprovalForAll}. + */ +abstract contract ERC721Holder is IERC721Receiver { + /** + * @dev See {IERC721Receiver-onERC721Received}. + * + * Always returns `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) { + return this.onERC721Received.selector; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol b/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol new file mode 100644 index 0000000..fce0251 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (token/common/ERC2981.sol) + +pragma solidity ^0.8.20; + +import {IERC2981} from "../../interfaces/IERC2981.sol"; +import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol"; + +/** + * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. + * + * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for + * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. + * + * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the + * fee is specified in basis points by default. + * + * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See + * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to + * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. + */ +abstract contract ERC2981 is IERC2981, ERC165 { + struct RoyaltyInfo { + address receiver; + uint96 royaltyFraction; + } + + RoyaltyInfo private _defaultRoyaltyInfo; + mapping(uint256 tokenId => RoyaltyInfo) private _tokenRoyaltyInfo; + + /** + * @dev The default royalty set is invalid (eg. (numerator / denominator) >= 1). + */ + error ERC2981InvalidDefaultRoyalty(uint256 numerator, uint256 denominator); + + /** + * @dev The default royalty receiver is invalid. + */ + error ERC2981InvalidDefaultRoyaltyReceiver(address receiver); + + /** + * @dev The royalty set for an specific `tokenId` is invalid (eg. (numerator / denominator) >= 1). + */ + error ERC2981InvalidTokenRoyalty(uint256 tokenId, uint256 numerator, uint256 denominator); + + /** + * @dev The royalty receiver for `tokenId` is invalid. + */ + error ERC2981InvalidTokenRoyaltyReceiver(uint256 tokenId, address receiver); + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { + return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @inheritdoc IERC2981 + */ + function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address, uint256) { + RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId]; + + if (royalty.receiver == address(0)) { + royalty = _defaultRoyaltyInfo; + } + + uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator(); + + return (royalty.receiver, royaltyAmount); + } + + /** + * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a + * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an + * override. + */ + function _feeDenominator() internal pure virtual returns (uint96) { + return 10000; + } + + /** + * @dev Sets the royalty information that all ids in this contract will default to. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { + uint256 denominator = _feeDenominator(); + if (feeNumerator > denominator) { + // Royalty fee will exceed the sale price + revert ERC2981InvalidDefaultRoyalty(feeNumerator, denominator); + } + if (receiver == address(0)) { + revert ERC2981InvalidDefaultRoyaltyReceiver(address(0)); + } + + _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Removes default royalty information. + */ + function _deleteDefaultRoyalty() internal virtual { + delete _defaultRoyaltyInfo; + } + + /** + * @dev Sets the royalty information for a specific token id, overriding the global default. + * + * Requirements: + * + * - `receiver` cannot be the zero address. + * - `feeNumerator` cannot be greater than the fee denominator. + */ + function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { + uint256 denominator = _feeDenominator(); + if (feeNumerator > denominator) { + // Royalty fee will exceed the sale price + revert ERC2981InvalidTokenRoyalty(tokenId, feeNumerator, denominator); + } + if (receiver == address(0)) { + revert ERC2981InvalidTokenRoyaltyReceiver(tokenId, address(0)); + } + + _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); + } + + /** + * @dev Resets royalty information for the token id back to the global default. + */ + function _resetTokenRoyalty(uint256 tokenId) internal virtual { + delete _tokenRoyaltyInfo[tokenId]; + } +} diff --git a/lib/openzeppelin-contracts/contracts/token/common/README.adoc b/lib/openzeppelin-contracts/contracts/token/common/README.adoc new file mode 100644 index 0000000..af61674 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/token/common/README.adoc @@ -0,0 +1,10 @@ += Common (Tokens) + +Functionality that is common to multiple token standards. + +* {ERC2981}: NFT Royalties compatible with both ERC721 and ERC1155. +** For ERC721 consider {ERC721Royalty} which clears the royalty information from storage on burn. + +== Contracts + +{{ERC2981}} diff --git a/lib/openzeppelin-contracts/contracts/utils/Address.sol b/lib/openzeppelin-contracts/contracts/utils/Address.sol new file mode 100644 index 0000000..b7e3059 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Address.sol @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev The ETH balance of the account is not enough to perform the operation. + */ + error AddressInsufficientBalance(address account); + + /** + * @dev There's no code at `target` (it is not a contract). + */ + error AddressEmptyCode(address target); + + /** + * @dev A call to an address target failed. The target may have reverted. + */ + error FailedInnerCall(); + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + if (address(this).balance < amount) { + revert AddressInsufficientBalance(address(this)); + } + + (bool success, ) = recipient.call{value: amount}(""); + if (!success) { + revert FailedInnerCall(); + } + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason or custom error, it is bubbled + * up by this function (like regular Solidity function calls). However, if + * the call reverted with no returned reason, this function reverts with a + * {FailedInnerCall} error. + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + */ + function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { + if (address(this).balance < value) { + revert AddressInsufficientBalance(address(this)); + } + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target + * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an + * unsuccessful call. + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata + ) internal view returns (bytes memory) { + if (!success) { + _revert(returndata); + } else { + // only check if target is a contract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + if (returndata.length == 0 && target.code.length == 0) { + revert AddressEmptyCode(target); + } + return returndata; + } + } + + /** + * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the + * revert reason or with a default {FailedInnerCall} error. + */ + function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { + if (!success) { + _revert(returndata); + } else { + return returndata; + } + } + + /** + * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}. + */ + function _revert(bytes memory returndata) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert FailedInnerCall(); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/Arrays.sol b/lib/openzeppelin-contracts/contracts/utils/Arrays.sol new file mode 100644 index 0000000..aaab3ce --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Arrays.sol @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Arrays.sol) + +pragma solidity ^0.8.20; + +import {StorageSlot} from "./StorageSlot.sol"; +import {Math} from "./math/Math.sol"; + +/** + * @dev Collection of functions related to array types. + */ +library Arrays { + using StorageSlot for bytes32; + + /** + * @dev Searches a sorted `array` and returns the first index that contains + * a value greater or equal to `element`. If no such index exists (i.e. all + * values in the array are strictly less than `element`), the array length is + * returned. Time complexity O(log n). + * + * `array` is expected to be sorted in ascending order, and to contain no + * repeated elements. + */ + function findUpperBound(uint256[] storage array, uint256 element) internal view returns (uint256) { + uint256 low = 0; + uint256 high = array.length; + + if (high == 0) { + return 0; + } + + while (low < high) { + uint256 mid = Math.average(low, high); + + // Note that mid will always be strictly less than high (i.e. it will be a valid array index) + // because Math.average rounds towards zero (it does integer division with truncation). + if (unsafeAccess(array, mid).value > element) { + high = mid; + } else { + low = mid + 1; + } + } + + // At this point `low` is the exclusive upper bound. We will return the inclusive upper bound. + if (low > 0 && unsafeAccess(array, low - 1).value == element) { + return low - 1; + } else { + return low; + } + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(address[] storage arr, uint256 pos) internal pure returns (StorageSlot.AddressSlot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getAddressSlot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(bytes32[] storage arr, uint256 pos) internal pure returns (StorageSlot.Bytes32Slot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getBytes32Slot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeAccess(uint256[] storage arr, uint256 pos) internal pure returns (StorageSlot.Uint256Slot storage) { + bytes32 slot; + // We use assembly to calculate the storage slot of the element at index `pos` of the dynamic array `arr` + // following https://docs.soliditylang.org/en/v0.8.20/internals/layout_in_storage.html#mappings-and-dynamic-arrays. + + /// @solidity memory-safe-assembly + assembly { + mstore(0, arr.slot) + slot := add(keccak256(0, 0x20), pos) + } + return slot.getUint256Slot(); + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeMemoryAccess(uint256[] memory arr, uint256 pos) internal pure returns (uint256 res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } + } + + /** + * @dev Access an array in an "unsafe" way. Skips solidity "index-out-of-range" check. + * + * WARNING: Only use if you are certain `pos` is lower than the array length. + */ + function unsafeMemoryAccess(address[] memory arr, uint256 pos) internal pure returns (address res) { + assembly { + res := mload(add(add(arr, 0x20), mul(pos, 0x20))) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/Base64.sol b/lib/openzeppelin-contracts/contracts/utils/Base64.sol new file mode 100644 index 0000000..f8547d1 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Base64.sol @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Base64.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Provides a set of functions to operate with Base64 strings. + */ +library Base64 { + /** + * @dev Base64 Encoding/Decoding Table + */ + string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** + * @dev Converts a `bytes` to its Bytes64 `string` representation. + */ + function encode(bytes memory data) internal pure returns (string memory) { + /** + * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence + * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol + */ + if (data.length == 0) return ""; + + // Loads the table into memory + string memory table = _TABLE; + + // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter + // and split into 4 numbers of 6 bits. + // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up + // - `data.length + 2` -> Round up + // - `/ 3` -> Number of 3-bytes chunks + // - `4 *` -> 4 characters for each chunk + string memory result = new string(4 * ((data.length + 2) / 3)); + + /// @solidity memory-safe-assembly + assembly { + // Prepare the lookup table (skip the first "length" byte) + let tablePtr := add(table, 1) + + // Prepare result pointer, jump over length + let resultPtr := add(result, 32) + + // Run over the input, 3 bytes at a time + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + + } { + // Advance 3 bytes + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + + // To write each character, shift the 3 bytes (18 bits) chunk + // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) + // and apply logical AND with 0x3F which is the number of + // the previous character in the ASCII table prior to the Base64 Table + // The result is then added to the table to get the character to write, + // and finally write it in the result pointer but with a left shift + // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits + + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) // Advance + } + + // When data `bytes` is not exactly 3 bytes long + // it is padded with `=` characters at the end + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/Context.sol b/lib/openzeppelin-contracts/contracts/utils/Context.sol new file mode 100644 index 0000000..9037dcd --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Context.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Context.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/Create2.sol b/lib/openzeppelin-contracts/contracts/utils/Create2.sol new file mode 100644 index 0000000..ad1cd5f --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Create2.sol @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Create2.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Helper to make usage of the `CREATE2` EVM opcode easier and safer. + * `CREATE2` can be used to compute in advance the address where a smart + * contract will be deployed, which allows for interesting new mechanisms known + * as 'counterfactual interactions'. + * + * See the https://eips.ethereum.org/EIPS/eip-1014#motivation[EIP] for more + * information. + */ +library Create2 { + /** + * @dev Not enough balance for performing a CREATE2 deploy. + */ + error Create2InsufficientBalance(uint256 balance, uint256 needed); + + /** + * @dev There's no code to deploy. + */ + error Create2EmptyBytecode(); + + /** + * @dev The deployment failed. + */ + error Create2FailedDeployment(); + + /** + * @dev Deploys a contract using `CREATE2`. The address where the contract + * will be deployed can be known in advance via {computeAddress}. + * + * The bytecode for a contract can be obtained from Solidity with + * `type(contractName).creationCode`. + * + * Requirements: + * + * - `bytecode` must not be empty. + * - `salt` must have not been used for `bytecode` already. + * - the factory must have a balance of at least `amount`. + * - if `amount` is non-zero, `bytecode` must have a `payable` constructor. + */ + function deploy(uint256 amount, bytes32 salt, bytes memory bytecode) internal returns (address addr) { + if (address(this).balance < amount) { + revert Create2InsufficientBalance(address(this).balance, amount); + } + if (bytecode.length == 0) { + revert Create2EmptyBytecode(); + } + /// @solidity memory-safe-assembly + assembly { + addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt) + } + if (addr == address(0)) { + revert Create2FailedDeployment(); + } + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy}. Any change in the + * `bytecodeHash` or `salt` will result in a new destination address. + */ + function computeAddress(bytes32 salt, bytes32 bytecodeHash) internal view returns (address) { + return computeAddress(salt, bytecodeHash, address(this)); + } + + /** + * @dev Returns the address where a contract will be stored if deployed via {deploy} from a contract located at + * `deployer`. If `deployer` is this contract's address, returns the same value as {computeAddress}. + */ + function computeAddress(bytes32 salt, bytes32 bytecodeHash, address deployer) internal pure returns (address addr) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) // Get free memory pointer + + // | | ↓ ptr ... ↓ ptr + 0x0B (start) ... ↓ ptr + 0x20 ... ↓ ptr + 0x40 ... | + // |-------------------|---------------------------------------------------------------------------| + // | bytecodeHash | CCCCCCCCCCCCC...CC | + // | salt | BBBBBBBBBBBBB...BB | + // | deployer | 000000...0000AAAAAAAAAAAAAAAAAAA...AA | + // | 0xFF | FF | + // |-------------------|---------------------------------------------------------------------------| + // | memory | 000000...00FFAAAAAAAAAAAAAAAAAAA...AABBBBBBBBBBBBB...BBCCCCCCCCCCCCC...CC | + // | keccak(start, 85) | ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ | + + mstore(add(ptr, 0x40), bytecodeHash) + mstore(add(ptr, 0x20), salt) + mstore(ptr, deployer) // Right-aligned with 12 preceding garbage bytes + let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff + mstore8(start, 0xff) + addr := keccak256(start, 85) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/Multicall.sol b/lib/openzeppelin-contracts/contracts/utils/Multicall.sol new file mode 100644 index 0000000..2d925a9 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Multicall.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Multicall.sol) + +pragma solidity ^0.8.20; + +import {Address} from "./Address.sol"; + +/** + * @dev Provides a function to batch together multiple calls in a single external call. + */ +abstract contract Multicall { + /** + * @dev Receives and executes a batch of function calls on this contract. + * @custom:oz-upgrades-unsafe-allow-reachable delegatecall + */ + function multicall(bytes[] calldata data) external virtual returns (bytes[] memory results) { + results = new bytes[](data.length); + for (uint256 i = 0; i < data.length; i++) { + results[i] = Address.functionDelegateCall(address(this), data[i]); + } + return results; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/Nonces.sol b/lib/openzeppelin-contracts/contracts/utils/Nonces.sol new file mode 100644 index 0000000..37451ff --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Nonces.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Nonces.sol) +pragma solidity ^0.8.20; + +/** + * @dev Provides tracking nonces for addresses. Nonces will only increment. + */ +abstract contract Nonces { + /** + * @dev The nonce used for an `account` is not the expected current nonce. + */ + error InvalidAccountNonce(address account, uint256 currentNonce); + + mapping(address account => uint256) private _nonces; + + /** + * @dev Returns the next unused nonce for an address. + */ + function nonces(address owner) public view virtual returns (uint256) { + return _nonces[owner]; + } + + /** + * @dev Consumes a nonce. + * + * Returns the current value and increments nonce. + */ + function _useNonce(address owner) internal virtual returns (uint256) { + // For each account, the nonce has an initial value of 0, can only be incremented by one, and cannot be + // decremented or reset. This guarantees that the nonce never overflows. + unchecked { + // It is important to do x++ and not ++x here. + return _nonces[owner]++; + } + } + + /** + * @dev Same as {_useNonce} but checking that `nonce` is the next valid for `owner`. + */ + function _useCheckedNonce(address owner, uint256 nonce) internal virtual { + uint256 current = _useNonce(owner); + if (nonce != current) { + revert InvalidAccountNonce(owner, current); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/Pausable.sol b/lib/openzeppelin-contracts/contracts/utils/Pausable.sol new file mode 100644 index 0000000..312f1cb --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Pausable.sol @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol) + +pragma solidity ^0.8.20; + +import {Context} from "../utils/Context.sol"; + +/** + * @dev Contract module which allows children to implement an emergency stop + * mechanism that can be triggered by an authorized account. + * + * This module is used through inheritance. It will make available the + * modifiers `whenNotPaused` and `whenPaused`, which can be applied to + * the functions of your contract. Note that they will not be pausable by + * simply including this module, only once the modifiers are put in place. + */ +abstract contract Pausable is Context { + bool private _paused; + + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); + + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); + + /** + * @dev The operation failed because the contract is paused. + */ + error EnforcedPause(); + + /** + * @dev The operation failed because the contract is not paused. + */ + error ExpectedPause(); + + /** + * @dev Initializes the contract in unpaused state. + */ + constructor() { + _paused = false; + } + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + _requireNotPaused(); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + * + * Requirements: + * + * - The contract must be paused. + */ + modifier whenPaused() { + _requirePaused(); + _; + } + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** + * @dev Throws if the contract is paused. + */ + function _requireNotPaused() internal view virtual { + if (paused()) { + revert EnforcedPause(); + } + } + + /** + * @dev Throws if the contract is not paused. + */ + function _requirePaused() internal view virtual { + if (!paused()) { + revert ExpectedPause(); + } + } + + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(_msgSender()); + } + + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(_msgSender()); + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/README.adoc b/lib/openzeppelin-contracts/contracts/utils/README.adoc new file mode 100644 index 0000000..d88b001 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/README.adoc @@ -0,0 +1,88 @@ += Utilities + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/utils + +Miscellaneous contracts and libraries containing utility functions you can use to improve security, work with new data types, or safely use low-level primitives. + + * {ReentrancyGuard}: A modifier that can prevent reentrancy during certain functions. + * {Pausable}: A common emergency response mechanism that can pause functionality while a remediation is pending. + * {SafeCast}: Checked downcasting functions to avoid silent truncation. + * {Math}, {SignedMath}: Implementation of various arithmetic functions. + * {Multicall}: Simple way to batch together multiple calls in a single external call. + * {Create2}: Wrapper around the https://blog.openzeppelin.com/getting-the-most-out-of-create2/[`CREATE2` EVM opcode] for safe use without having to deal with low-level assembly. + * {EnumerableMap}: A type like Solidity's https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`], but with key-value _enumeration_: this will let you know how many entries a mapping has, and iterate over them (which is not possible with `mapping`). + * {EnumerableSet}: Like {EnumerableMap}, but for https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets]. Can be used to store privileged accounts, issued IDs, etc. + +[NOTE] +==== +Because Solidity does not support generic types, {EnumerableMap} and {EnumerableSet} are specialized to a limited number of key-value types. +==== + +== Math + +{{Math}} + +{{SignedMath}} + +{{SafeCast}} + +== Cryptography + +{{ECDSA}} + +{{MessageHashUtils}} + +{{SignatureChecker}} + +{{MerkleProof}} + +{{EIP712}} + +== Security + +{{ReentrancyGuard}} + +{{Pausable}} + +== Introspection + +This set of interfaces and contracts deal with https://en.wikipedia.org/wiki/Type_introspection[type introspection] of contracts, that is, examining which functions can be called on them. This is usually referred to as a contract's _interface_. + +Ethereum contracts have no native concept of an interface, so applications must usually simply trust they are not making an incorrect call. For trusted setups this is a non-issue, but often unknown and untrusted third-party addresses need to be interacted with. There may even not be any direct calls to them! (e.g. `ERC20` tokens may be sent to a contract that lacks a way to transfer them out of it, locking them forever). In these cases, a contract _declaring_ its interface can be very helpful in preventing errors. + +{{IERC165}} + +{{ERC165}} + +{{ERC165Checker}} + +== Data Structures + +{{BitMaps}} + +{{EnumerableMap}} + +{{EnumerableSet}} + +{{DoubleEndedQueue}} + +{{Checkpoints}} + +== Libraries + +{{Create2}} + +{{Address}} + +{{Arrays}} + +{{Base64}} + +{{Strings}} + +{{ShortStrings}} + +{{StorageSlot}} + +{{Multicall}} diff --git a/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol b/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol new file mode 100644 index 0000000..291d92f --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Contract module that helps prevent reentrant calls to a function. + * + * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier + * available, which can be applied to functions to make sure there are no nested + * (reentrant) calls to them. + * + * Note that because there is a single `nonReentrant` guard, functions marked as + * `nonReentrant` may not call one another. This can be worked around by making + * those functions `private`, and then adding `external` `nonReentrant` entry + * points to them. + * + * TIP: If you would like to learn more about reentrancy and alternative ways + * to protect against it, check out our blog post + * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. + */ +abstract contract ReentrancyGuard { + // Booleans are more expensive than uint256 or any type that takes up a full + // word because each write operation emits an extra SLOAD to first read the + // slot's contents, replace the bits taken up by the boolean, and then write + // back. This is the compiler's defense against contract upgrades and + // pointer aliasing, and it cannot be disabled. + + // The values being non-zero value makes deployment a bit more expensive, + // but in exchange the refund on every call to nonReentrant will be lower in + // amount. Since refunds are capped to a percentage of the total + // transaction's gas, it is best to keep them low in cases like this one, to + // increase the likelihood of the full refund coming into effect. + uint256 private constant NOT_ENTERED = 1; + uint256 private constant ENTERED = 2; + + uint256 private _status; + + /** + * @dev Unauthorized reentrant call. + */ + error ReentrancyGuardReentrantCall(); + + constructor() { + _status = NOT_ENTERED; + } + + /** + * @dev Prevents a contract from calling itself, directly or indirectly. + * Calling a `nonReentrant` function from another `nonReentrant` + * function is not supported. It is possible to prevent this from happening + * by making the `nonReentrant` function external, and making it call a + * `private` function that does the actual work. + */ + modifier nonReentrant() { + _nonReentrantBefore(); + _; + _nonReentrantAfter(); + } + + function _nonReentrantBefore() private { + // On the first call to nonReentrant, _status will be NOT_ENTERED + if (_status == ENTERED) { + revert ReentrancyGuardReentrantCall(); + } + + // Any calls to nonReentrant after this point will fail + _status = ENTERED; + } + + function _nonReentrantAfter() private { + // By storing the original value once again, a refund is triggered (see + // https://eips.ethereum.org/EIPS/eip-2200) + _status = NOT_ENTERED; + } + + /** + * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a + * `nonReentrant` function in the call stack. + */ + function _reentrancyGuardEntered() internal view returns (bool) { + return _status == ENTERED; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol b/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol new file mode 100644 index 0000000..fdfe774 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/ShortStrings.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/ShortStrings.sol) + +pragma solidity ^0.8.20; + +import {StorageSlot} from "./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 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: + * + * ```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 { + // Used as an identifier for strings longer than 31 bytes. + bytes32 private constant FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF; + + error StringTooLong(string str); + error InvalidShortString(); + + /** + * @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 = byteLength(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 byteLength(ShortString sstr) internal pure returns (uint256) { + uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF; + if (result > 31) { + revert InvalidShortString(); + } + return result; + } + + /** + * @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(FALLBACK_SENTINEL); + } + } + + /** + * @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 (ShortString.unwrap(value) != FALLBACK_SENTINEL) { + return toString(value); + } else { + 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/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol b/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol new file mode 100644 index 0000000..0841832 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/StorageSlot.sol) +// This file was procedurally generated from scripts/generate/templates/StorageSlot.js. + +pragma solidity ^0.8.20; + +/** + * @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(newImplementation.code.length > 0); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * ``` + */ +library StorageSlot { + struct AddressSlot { + address value; + } + + struct BooleanSlot { + bool value; + } + + struct Bytes32Slot { + bytes32 value; + } + + struct Uint256Slot { + uint256 value; + } + + struct StringSlot { + string value; + } + + struct BytesSlot { + bytes value; + } + + /** + * @dev Returns an `AddressSlot` with member `value` located at `slot`. + */ + function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `BooleanSlot` with member `value` located at `slot`. + */ + function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. + */ + function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + r.slot := slot + } + } + + /** + * @dev Returns an `Uint256Slot` with member `value` located at `slot`. + */ + function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { + /// @solidity memory-safe-assembly + assembly { + 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/lib/openzeppelin-contracts/contracts/utils/Strings.sol b/lib/openzeppelin-contracts/contracts/utils/Strings.sol new file mode 100644 index 0000000..b2c0a40 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/Strings.sol @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol) + +pragma solidity ^0.8.20; + +import {Math} from "./math/Math.sol"; +import {SignedMath} from "./math/SignedMath.sol"; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant HEX_DIGITS = "0123456789abcdef"; + uint8 private constant ADDRESS_LENGTH = 20; + + /** + * @dev The `value` string doesn't fit in the specified `length`. + */ + error StringsInsufficientHexLength(uint256 value, uint256 length); + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), HEX_DIGITS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `int256` to its ASCII `string` decimal representation. + */ + function toStringSigned(int256 value) internal pure returns (string memory) { + return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value))); + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + uint256 localValue = value; + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = HEX_DIGITS[localValue & 0xf]; + localValue >>= 4; + } + if (localValue != 0) { + revert StringsInsufficientHexLength(value, length); + } + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal + * representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH); + } + + /** + * @dev Returns true if the two strings are equal. + */ + function equal(string memory a, string memory b) internal pure returns (bool) { + return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b)); + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol b/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol new file mode 100644 index 0000000..04b3e5e --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/ECDSA.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations. + * + * These functions can be used to verify that a message was signed by the holder + * of the private keys of a given address. + */ +library ECDSA { + enum RecoverError { + NoError, + InvalidSignature, + InvalidSignatureLength, + InvalidSignatureS + } + + /** + * @dev The signature derives the `address(0)`. + */ + error ECDSAInvalidSignature(); + + /** + * @dev The signature has an invalid length. + */ + error ECDSAInvalidSignatureLength(uint256 length); + + /** + * @dev The signature has an S value that is in the upper half order. + */ + error ECDSAInvalidSignatureS(bytes32 s); + + /** + * @dev Returns the address that signed a hashed message (`hash`) with `signature` or an error. This will not + * return address(0) without also returning an error description. Errors are documented using an enum (error type) + * and a bytes32 providing additional information about the error. + * + * If no error is returned, then the address can be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + * + * Documentation for signature generation: + * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js] + * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers] + */ + function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) { + if (signature.length == 65) { + bytes32 r; + bytes32 s; + uint8 v; + // ecrecover takes the signature parameters, and the only way to get them + // currently is to use assembly. + /// @solidity memory-safe-assembly + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := byte(0, mload(add(signature, 0x60))) + } + return tryRecover(hash, v, r, s); + } else { + return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length)); + } + } + + /** + * @dev Returns the address that signed a hashed message (`hash`) with + * `signature`. This address can then be used for verification purposes. + * + * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures: + * this function rejects them by requiring the `s` value to be in the lower + * half order, and the `v` value to be either 27 or 28. + * + * IMPORTANT: `hash` _must_ be the result of a hash operation for the + * verification to be secure: it is possible to craft signatures that + * recover to arbitrary addresses for non-hashed data. A safe way to ensure + * this is by receiving a hash of the original message (which may otherwise + * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it. + */ + function recover(bytes32 hash, bytes memory signature) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately. + * + * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures] + */ + function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) { + unchecked { + bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff); + // We do not check for an overflow here since the shift operation results in 0 or 1. + uint8 v = uint8((uint256(vs) >> 255) + 27); + return tryRecover(hash, v, r, s); + } + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately. + */ + function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Overload of {ECDSA-tryRecover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function tryRecover( + bytes32 hash, + uint8 v, + bytes32 r, + bytes32 s + ) internal pure returns (address, RecoverError, bytes32) { + // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature + // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines + // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most + // signatures from current libraries generate a unique signature with an s-value in the lower half order. + // + // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value + // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or + // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept + // these malleable signatures as well. + if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) { + return (address(0), RecoverError.InvalidSignatureS, s); + } + + // If the signature is valid (and not malleable), return the signer address + address signer = ecrecover(hash, v, r, s); + if (signer == address(0)) { + return (address(0), RecoverError.InvalidSignature, bytes32(0)); + } + + return (signer, RecoverError.NoError, bytes32(0)); + } + + /** + * @dev Overload of {ECDSA-recover} that receives the `v`, + * `r` and `s` signature fields separately. + */ + function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) { + (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s); + _throwError(error, errorArg); + return recovered; + } + + /** + * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided. + */ + function _throwError(RecoverError error, bytes32 errorArg) private pure { + if (error == RecoverError.NoError) { + return; // no error: do nothing + } else if (error == RecoverError.InvalidSignature) { + revert ECDSAInvalidSignature(); + } else if (error == RecoverError.InvalidSignatureLength) { + revert ECDSAInvalidSignatureLength(uint256(errorArg)); + } else if (error == RecoverError.InvalidSignatureS) { + revert ECDSAInvalidSignatureS(errorArg); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol b/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol new file mode 100644 index 0000000..8e548cd --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sol @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/EIP712.sol) + +pragma solidity ^0.8.20; + +import {MessageHashUtils} from "./MessageHashUtils.sol"; +import {ShortStrings, ShortString} from "../ShortStrings.sol"; +import {IERC5267} from "../../interfaces/IERC5267.sol"; + +/** + * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data. + * + * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose + * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract + * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to + * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`. + * + * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding + * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA + * ({_hashTypedDataV4}). + * + * The implementation of the domain separator was designed to be as efficient as possible while still properly updating + * the chain id to protect against replay attacks on an eventual fork of the chain. + * + * 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. + * + * @custom:oz-upgrades-unsafe-allow state-variable-immutable + */ +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; + + bytes32 private immutable _hashedName; + bytes32 private immutable _hashedVersion; + + ShortString private immutable _name; + ShortString private immutable _version; + string private _nameFallback; + string private _versionFallback; + + /** + * @dev Initializes the domain separator and parameter caches. + * + * The meaning of `name` and `version` is specified in + * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]: + * + * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol. + * - `version`: the current major version of the signing domain. + * + * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart + * 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); + } + + /** + * @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(); + } + } + + function _buildDomainSeparator() private view returns (bytes32) { + return keccak256(abi.encode(TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this))); + } + + /** + * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this + * function returns the hash of the fully encoded EIP712 message for this domain. + * + * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example: + * + * ```solidity + * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode( + * keccak256("Mail(address to,string contents)"), + * mailTo, + * keccak256(bytes(mailContents)) + * ))); + * address signer = ECDSA.recover(digest, signature); + * ``` + */ + function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) { + return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash); + } + + /** + * @dev See {IERC-5267}. + */ + function eip712Domain() + public + view + virtual + returns ( + bytes1 fields, + string memory name, + string memory version, + uint256 chainId, + address verifyingContract, + bytes32 salt, + uint256[] memory extensions + ) + { + return ( + hex"0f", // 01111 + _EIP712Name(), + _EIP712Version(), + block.chainid, + address(this), + bytes32(0), + new uint256[](0) + ); + } + + /** + * @dev The name parameter for the EIP712 domain. + * + * NOTE: By default this function reads _name which is an immutable value. + * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). + */ + // solhint-disable-next-line func-name-mixedcase + function _EIP712Name() internal view returns (string memory) { + return _name.toStringWithFallback(_nameFallback); + } + + /** + * @dev The version parameter for the EIP712 domain. + * + * NOTE: By default this function reads _version which is an immutable value. + * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). + */ + // solhint-disable-next-line func-name-mixedcase + function _EIP712Version() internal view returns (string memory) { + return _version.toStringWithFallback(_versionFallback); + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol b/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol new file mode 100644 index 0000000..525f5da --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol) + +pragma solidity ^0.8.20; + +/** + * @dev These functions deal with verification of Merkle Tree proofs. + * + * The tree and the proofs can be generated using our + * https://github.com/OpenZeppelin/merkle-tree[JavaScript library]. + * You will find a quickstart guide in the readme. + * + * WARNING: You should avoid using leaf values that are 64 bytes long prior to + * hashing, or use a hash function other than keccak256 for hashing leaves. + * This is because the concatenation of a sorted pair of internal nodes in + * the Merkle tree could be reinterpreted as a leaf value. + * OpenZeppelin's JavaScript library generates Merkle trees that are safe + * against this attack out of the box. + */ +library MerkleProof { + /** + *@dev The multiproof provided is not valid. + */ + error MerkleProofInvalidMultiproof(); + + /** + * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree + * defined by `root`. For this, a `proof` must be provided, containing + * sibling hashes on the branch from the leaf to the root of the tree. Each + * pair of leaves and each pair of pre-images are assumed to be sorted. + */ + function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProof(proof, leaf) == root; + } + + /** + * @dev Calldata version of {verify} + */ + function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) { + return processProofCalldata(proof, leaf) == root; + } + + /** + * @dev Returns the rebuilt hash obtained by traversing a Merkle tree up + * from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt + * hash matches the root of the tree. When processing the proof, the pairs + * of leafs & pre-images are assumed to be sorted. + */ + function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = _hashPair(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @dev Calldata version of {processProof} + */ + function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) { + bytes32 computedHash = leaf; + for (uint256 i = 0; i < proof.length; i++) { + computedHash = _hashPair(computedHash, proof[i]); + } + return computedHash; + } + + /** + * @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by + * `root`, according to `proof` and `proofFlags` as described in {processMultiProof}. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + */ + function multiProofVerify( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProof(proof, proofFlags, leaves) == root; + } + + /** + * @dev Calldata version of {multiProofVerify} + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + */ + function multiProofVerifyCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32 root, + bytes32[] memory leaves + ) internal pure returns (bool) { + return processMultiProofCalldata(proof, proofFlags, leaves) == root; + } + + /** + * @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction + * proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another + * leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false + * respectively. + * + * CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree + * is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the + * tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer). + */ + function processMultiProof( + bytes32[] memory proof, + bool[] memory proofFlags, + bytes32[] memory leaves + ) internal pure returns (bytes32 merkleRoot) { + // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by + // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the + // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of + // the Merkle tree. + uint256 leavesLen = leaves.length; + uint256 proofLen = proof.length; + uint256 totalHashes = proofFlags.length; + + // Check proof validity. + if (leavesLen + proofLen != totalHashes + 1) { + revert MerkleProofInvalidMultiproof(); + } + + // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using + // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". + bytes32[] memory hashes = new bytes32[](totalHashes); + uint256 leafPos = 0; + uint256 hashPos = 0; + uint256 proofPos = 0; + // At each step, we compute the next hash using two values: + // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we + // get the next hash. + // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the + // `proof` array. + for (uint256 i = 0; i < totalHashes; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = _hashPair(a, b); + } + + if (totalHashes > 0) { + if (proofPos != proofLen) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[totalHashes - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @dev Calldata version of {processMultiProof}. + * + * CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details. + */ + function processMultiProofCalldata( + bytes32[] calldata proof, + bool[] calldata proofFlags, + bytes32[] memory leaves + ) internal pure returns (bytes32 merkleRoot) { + // This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by + // consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the + // `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of + // the Merkle tree. + uint256 leavesLen = leaves.length; + uint256 proofLen = proof.length; + uint256 totalHashes = proofFlags.length; + + // Check proof validity. + if (leavesLen + proofLen != totalHashes + 1) { + revert MerkleProofInvalidMultiproof(); + } + + // The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using + // `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop". + bytes32[] memory hashes = new bytes32[](totalHashes); + uint256 leafPos = 0; + uint256 hashPos = 0; + uint256 proofPos = 0; + // At each step, we compute the next hash using two values: + // - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we + // get the next hash. + // - depending on the flag, either another value from the "main queue" (merging branches) or an element from the + // `proof` array. + for (uint256 i = 0; i < totalHashes; i++) { + bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]; + bytes32 b = proofFlags[i] + ? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++]) + : proof[proofPos++]; + hashes[i] = _hashPair(a, b); + } + + if (totalHashes > 0) { + if (proofPos != proofLen) { + revert MerkleProofInvalidMultiproof(); + } + unchecked { + return hashes[totalHashes - 1]; + } + } else if (leavesLen > 0) { + return leaves[0]; + } else { + return proof[0]; + } + } + + /** + * @dev Sorts the pair (a, b) and hashes the result. + */ + function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) { + return a < b ? _efficientHash(a, b) : _efficientHash(b, a); + } + + /** + * @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory. + */ + function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, a) + mstore(0x20, b) + value := keccak256(0x00, 0x40) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol b/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol new file mode 100644 index 0000000..8836693 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MessageHashUtils.sol) + +pragma solidity ^0.8.20; + +import {Strings} from "../Strings.sol"; + +/** + * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing. + * + * The library provides methods for generating a hash of a message that conforms to the + * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712] + * specifications. + */ +library MessageHashUtils { + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x45` (`personal_sign` messages). + * + * The digest is calculated by prefixing a bytes32 `messageHash` with + * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the + * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. + * + * NOTE: The `messageHash` parameter is intended to be the result of hashing a raw message with + * keccak256, although any bytes32 value can be safely used because the final digest will + * be re-hashed. + * + * See {ECDSA-recover}. + */ + function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) { + /// @solidity memory-safe-assembly + assembly { + mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash + mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix + digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20) + } + } + + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x45` (`personal_sign` messages). + * + * The digest is calculated by prefixing an arbitrary `message` with + * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the + * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method. + * + * See {ECDSA-recover}. + */ + function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32) { + return + keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message)); + } + + /** + * @dev Returns the keccak256 digest of an EIP-191 signed data with version + * `0x00` (data with intended validator). + * + * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended + * `validator` address. Then hashing the result. + * + * See {ECDSA-recover}. + */ + function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(hex"19_00", validator, data)); + } + + /** + * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`). + * + * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with + * `\x19\x01` and hashing the result. It corresponds to the hash signed by the + * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712. + * + * See {ECDSA-recover}. + */ + function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) { + /// @solidity memory-safe-assembly + assembly { + let ptr := mload(0x40) + mstore(ptr, hex"19_01") + mstore(add(ptr, 0x02), domainSeparator) + mstore(add(ptr, 0x22), structHash) + digest := keccak256(ptr, 0x42) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol b/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol new file mode 100644 index 0000000..59a2c6d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/SignatureChecker.sol) + +pragma solidity ^0.8.20; + +import {ECDSA} from "./ECDSA.sol"; +import {IERC1271} from "../../interfaces/IERC1271.sol"; + +/** + * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA + * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like + * Argent and Safe Wallet (previously Gnosis Safe). + */ +library SignatureChecker { + /** + * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the + * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`. + * + * 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 isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) { + (address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature); + 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.encodeCall(IERC1271.isValidSignature, (hash, signature)) + ); + return (success && + result.length >= 32 && + abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector)); + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol b/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol new file mode 100644 index 0000000..1e77b60 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol b/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol new file mode 100644 index 0000000..7b52241 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165Checker.sol) + +pragma solidity ^0.8.20; + +import {IERC165} from "./IERC165.sol"; + +/** + * @dev Library used to query support of an interface declared via {IERC165}. + * + * Note that these functions return the actual result of the query: they do not + * `revert` if an interface is not supported. It is up to the caller to decide + * what to do in these cases. + */ +library ERC165Checker { + // As per the EIP-165 spec, no interface should ever match 0xffffffff + bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff; + + /** + * @dev Returns true if `account` supports the {IERC165} interface. + */ + function supportsERC165(address account) internal view returns (bool) { + // Any contract that implements ERC165 must explicitly indicate support of + // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid + return + supportsERC165InterfaceUnchecked(account, type(IERC165).interfaceId) && + !supportsERC165InterfaceUnchecked(account, INTERFACE_ID_INVALID); + } + + /** + * @dev Returns true if `account` supports the interface defined by + * `interfaceId`. Support for {IERC165} itself is queried automatically. + * + * See {IERC165-supportsInterface}. + */ + function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { + // query support of both ERC165 as per the spec and support of _interfaceId + return supportsERC165(account) && supportsERC165InterfaceUnchecked(account, interfaceId); + } + + /** + * @dev Returns a boolean array where each value corresponds to the + * interfaces passed in and whether they're supported or not. This allows + * you to batch check interfaces for a contract where your expectation + * is that some interfaces may not be supported. + * + * See {IERC165-supportsInterface}. + */ + function getSupportedInterfaces( + address account, + bytes4[] memory interfaceIds + ) internal view returns (bool[] memory) { + // an array of booleans corresponding to interfaceIds and whether they're supported or not + bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); + + // query support of ERC165 itself + if (supportsERC165(account)) { + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + interfaceIdsSupported[i] = supportsERC165InterfaceUnchecked(account, interfaceIds[i]); + } + } + + return interfaceIdsSupported; + } + + /** + * @dev Returns true if `account` supports all the interfaces defined in + * `interfaceIds`. Support for {IERC165} itself is queried automatically. + * + * Batch-querying can lead to gas savings by skipping repeated checks for + * {IERC165} support. + * + * See {IERC165-supportsInterface}. + */ + function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { + // query support of ERC165 itself + if (!supportsERC165(account)) { + return false; + } + + // query support of each interface in interfaceIds + for (uint256 i = 0; i < interfaceIds.length; i++) { + if (!supportsERC165InterfaceUnchecked(account, interfaceIds[i])) { + return false; + } + } + + // all interfaces supported + return true; + } + + /** + * @notice Query if a contract implements an interface, does not check ERC165 support + * @param account The address of the contract to query for support of an interface + * @param interfaceId The interface identifier, as specified in ERC-165 + * @return true if the contract at account indicates support of the interface with + * identifier interfaceId, false otherwise + * @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) { + // prepare call + bytes memory encodedParams = abi.encodeCall(IERC165.supportsInterface, (interfaceId)); + + // perform static call + bool success; + uint256 returnSize; + uint256 returnValue; + assembly { + success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20) + returnSize := returndatasize() + returnValue := mload(0x00) + } + + return success && returnSize >= 0x20 && returnValue > 0; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol b/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol new file mode 100644 index 0000000..c09f31f --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts/contracts/utils/math/Math.sol b/lib/openzeppelin-contracts/contracts/utils/math/Math.sol new file mode 100644 index 0000000..9681524 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/math/Math.sol @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + /** + * @dev Muldiv operation overflow. + */ + error MathOverflowedMulDiv(); + + enum Rounding { + Floor, // Toward negative infinity + Ceil, // Toward positive infinity + Trunc, // Toward zero + Expand // Away from zero + } + + /** + * @dev Returns the addition of two unsigned integers, with an overflow flag. + */ + function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + uint256 c = a + b; + if (c < a) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the subtraction of two unsigned integers, with an overflow flag. + */ + function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b > a) return (false, 0); + return (true, a - b); + } + } + + /** + * @dev Returns the multiplication of two unsigned integers, with an overflow flag. + */ + function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + // Gas optimization: this is cheaper than requiring 'a' not being zero, but the + // benefit is lost if 'b' is also tested. + // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 + if (a == 0) return (true, 0); + uint256 c = a * b; + if (c / a != b) return (false, 0); + return (true, c); + } + } + + /** + * @dev Returns the division of two unsigned integers, with a division by zero flag. + */ + function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a / b); + } + } + + /** + * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag. + */ + function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) { + unchecked { + if (b == 0) return (false, 0); + return (true, a % b); + } + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds towards infinity instead + * of rounding towards zero. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + if (b == 0) { + // Guarantee the same behavior as in a regular Solidity division. + return a / b; + } + + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or + * denominator == 0. + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by + * Uniswap Labs also under MIT license. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0 = x * y; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // 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; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + if (denominator <= prod1) { + revert MathOverflowedMulDiv(); + } + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. + // Always >= 1. See https://cs.stackexchange.com/q/138556/92363. + + uint256 twos = denominator & (0 - denominator); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also + // works in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded + * towards zero. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10 of a positive value rounded towards zero. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10 ** 64) { + value /= 10 ** 64; + result += 64; + } + if (value >= 10 ** 32) { + value /= 10 ** 32; + result += 32; + } + if (value >= 10 ** 16) { + value /= 10 ** 16; + result += 16; + } + if (value >= 10 ** 8) { + value /= 10 ** 8; + result += 8; + } + if (value >= 10 ** 4) { + value /= 10 ** 4; + result += 4; + } + if (value >= 10 ** 2) { + value /= 10 ** 2; + result += 2; + } + if (value >= 10 ** 1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256 of a positive value rounded towards zero. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 256, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0); + } + } + + /** + * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers. + */ + function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) { + return uint8(rounding) % 2 == 1; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol b/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol new file mode 100644 index 0000000..0ed458b --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/math/SafeCast.sol @@ -0,0 +1,1153 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol) +// This file was procedurally generated from scripts/generate/templates/SafeCast.js. + +pragma solidity ^0.8.20; + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. `SafeCast` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +library SafeCast { + /** + * @dev Value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + + /** + * @dev An int value doesn't fit in an uint of `bits` size. + */ + error SafeCastOverflowedIntToUint(int256 value); + + /** + * @dev Value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); + + /** + * @dev An uint value doesn't fit in an int of `bits` size. + */ + error SafeCastOverflowedUintToInt(uint256 value); + + /** + * @dev Returns the downcasted uint248 from uint256, reverting on + * overflow (when the input is greater than largest uint248). + * + * Counterpart to Solidity's `uint248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toUint248(uint256 value) internal pure returns (uint248) { + if (value > type(uint248).max) { + revert SafeCastOverflowedUintDowncast(248, value); + } + return uint248(value); + } + + /** + * @dev Returns the downcasted uint240 from uint256, reverting on + * overflow (when the input is greater than largest uint240). + * + * Counterpart to Solidity's `uint240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toUint240(uint256 value) internal pure returns (uint240) { + if (value > type(uint240).max) { + revert SafeCastOverflowedUintDowncast(240, value); + } + return uint240(value); + } + + /** + * @dev Returns the downcasted uint232 from uint256, reverting on + * overflow (when the input is greater than largest uint232). + * + * Counterpart to Solidity's `uint232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toUint232(uint256 value) internal pure returns (uint232) { + if (value > type(uint232).max) { + revert SafeCastOverflowedUintDowncast(232, value); + } + return uint232(value); + } + + /** + * @dev Returns the downcasted uint224 from uint256, reverting on + * overflow (when the input is greater than largest uint224). + * + * Counterpart to Solidity's `uint224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toUint224(uint256 value) internal pure returns (uint224) { + if (value > type(uint224).max) { + revert SafeCastOverflowedUintDowncast(224, value); + } + return uint224(value); + } + + /** + * @dev Returns the downcasted uint216 from uint256, reverting on + * overflow (when the input is greater than largest uint216). + * + * Counterpart to Solidity's `uint216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toUint216(uint256 value) internal pure returns (uint216) { + if (value > type(uint216).max) { + revert SafeCastOverflowedUintDowncast(216, value); + } + return uint216(value); + } + + /** + * @dev Returns the downcasted uint208 from uint256, reverting on + * overflow (when the input is greater than largest uint208). + * + * Counterpart to Solidity's `uint208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toUint208(uint256 value) internal pure returns (uint208) { + if (value > type(uint208).max) { + revert SafeCastOverflowedUintDowncast(208, value); + } + return uint208(value); + } + + /** + * @dev Returns the downcasted uint200 from uint256, reverting on + * overflow (when the input is greater than largest uint200). + * + * Counterpart to Solidity's `uint200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toUint200(uint256 value) internal pure returns (uint200) { + if (value > type(uint200).max) { + revert SafeCastOverflowedUintDowncast(200, value); + } + return uint200(value); + } + + /** + * @dev Returns the downcasted uint192 from uint256, reverting on + * overflow (when the input is greater than largest uint192). + * + * Counterpart to Solidity's `uint192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toUint192(uint256 value) internal pure returns (uint192) { + if (value > type(uint192).max) { + revert SafeCastOverflowedUintDowncast(192, value); + } + return uint192(value); + } + + /** + * @dev Returns the downcasted uint184 from uint256, reverting on + * overflow (when the input is greater than largest uint184). + * + * Counterpart to Solidity's `uint184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toUint184(uint256 value) internal pure returns (uint184) { + if (value > type(uint184).max) { + revert SafeCastOverflowedUintDowncast(184, value); + } + return uint184(value); + } + + /** + * @dev Returns the downcasted uint176 from uint256, reverting on + * overflow (when the input is greater than largest uint176). + * + * Counterpart to Solidity's `uint176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toUint176(uint256 value) internal pure returns (uint176) { + if (value > type(uint176).max) { + revert SafeCastOverflowedUintDowncast(176, value); + } + return uint176(value); + } + + /** + * @dev Returns the downcasted uint168 from uint256, reverting on + * overflow (when the input is greater than largest uint168). + * + * Counterpart to Solidity's `uint168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toUint168(uint256 value) internal pure returns (uint168) { + if (value > type(uint168).max) { + revert SafeCastOverflowedUintDowncast(168, value); + } + return uint168(value); + } + + /** + * @dev Returns the downcasted uint160 from uint256, reverting on + * overflow (when the input is greater than largest uint160). + * + * Counterpart to Solidity's `uint160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toUint160(uint256 value) internal pure returns (uint160) { + if (value > type(uint160).max) { + revert SafeCastOverflowedUintDowncast(160, value); + } + return uint160(value); + } + + /** + * @dev Returns the downcasted uint152 from uint256, reverting on + * overflow (when the input is greater than largest uint152). + * + * Counterpart to Solidity's `uint152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toUint152(uint256 value) internal pure returns (uint152) { + if (value > type(uint152).max) { + revert SafeCastOverflowedUintDowncast(152, value); + } + return uint152(value); + } + + /** + * @dev Returns the downcasted uint144 from uint256, reverting on + * overflow (when the input is greater than largest uint144). + * + * Counterpart to Solidity's `uint144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toUint144(uint256 value) internal pure returns (uint144) { + if (value > type(uint144).max) { + revert SafeCastOverflowedUintDowncast(144, value); + } + return uint144(value); + } + + /** + * @dev Returns the downcasted uint136 from uint256, reverting on + * overflow (when the input is greater than largest uint136). + * + * Counterpart to Solidity's `uint136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toUint136(uint256 value) internal pure returns (uint136) { + if (value > type(uint136).max) { + revert SafeCastOverflowedUintDowncast(136, value); + } + return uint136(value); + } + + /** + * @dev Returns the downcasted uint128 from uint256, reverting on + * overflow (when the input is greater than largest uint128). + * + * Counterpart to Solidity's `uint128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toUint128(uint256 value) internal pure returns (uint128) { + if (value > type(uint128).max) { + revert SafeCastOverflowedUintDowncast(128, value); + } + return uint128(value); + } + + /** + * @dev Returns the downcasted uint120 from uint256, reverting on + * overflow (when the input is greater than largest uint120). + * + * Counterpart to Solidity's `uint120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toUint120(uint256 value) internal pure returns (uint120) { + if (value > type(uint120).max) { + revert SafeCastOverflowedUintDowncast(120, value); + } + return uint120(value); + } + + /** + * @dev Returns the downcasted uint112 from uint256, reverting on + * overflow (when the input is greater than largest uint112). + * + * Counterpart to Solidity's `uint112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toUint112(uint256 value) internal pure returns (uint112) { + if (value > type(uint112).max) { + revert SafeCastOverflowedUintDowncast(112, value); + } + return uint112(value); + } + + /** + * @dev Returns the downcasted uint104 from uint256, reverting on + * overflow (when the input is greater than largest uint104). + * + * Counterpart to Solidity's `uint104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toUint104(uint256 value) internal pure returns (uint104) { + if (value > type(uint104).max) { + revert SafeCastOverflowedUintDowncast(104, value); + } + return uint104(value); + } + + /** + * @dev Returns the downcasted uint96 from uint256, reverting on + * overflow (when the input is greater than largest uint96). + * + * Counterpart to Solidity's `uint96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toUint96(uint256 value) internal pure returns (uint96) { + if (value > type(uint96).max) { + revert SafeCastOverflowedUintDowncast(96, value); + } + return uint96(value); + } + + /** + * @dev Returns the downcasted uint88 from uint256, reverting on + * overflow (when the input is greater than largest uint88). + * + * Counterpart to Solidity's `uint88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toUint88(uint256 value) internal pure returns (uint88) { + if (value > type(uint88).max) { + revert SafeCastOverflowedUintDowncast(88, value); + } + return uint88(value); + } + + /** + * @dev Returns the downcasted uint80 from uint256, reverting on + * overflow (when the input is greater than largest uint80). + * + * Counterpart to Solidity's `uint80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toUint80(uint256 value) internal pure returns (uint80) { + if (value > type(uint80).max) { + revert SafeCastOverflowedUintDowncast(80, value); + } + return uint80(value); + } + + /** + * @dev Returns the downcasted uint72 from uint256, reverting on + * overflow (when the input is greater than largest uint72). + * + * Counterpart to Solidity's `uint72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toUint72(uint256 value) internal pure returns (uint72) { + if (value > type(uint72).max) { + revert SafeCastOverflowedUintDowncast(72, value); + } + return uint72(value); + } + + /** + * @dev Returns the downcasted uint64 from uint256, reverting on + * overflow (when the input is greater than largest uint64). + * + * Counterpart to Solidity's `uint64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toUint64(uint256 value) internal pure returns (uint64) { + if (value > type(uint64).max) { + revert SafeCastOverflowedUintDowncast(64, value); + } + return uint64(value); + } + + /** + * @dev Returns the downcasted uint56 from uint256, reverting on + * overflow (when the input is greater than largest uint56). + * + * Counterpart to Solidity's `uint56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toUint56(uint256 value) internal pure returns (uint56) { + if (value > type(uint56).max) { + revert SafeCastOverflowedUintDowncast(56, value); + } + return uint56(value); + } + + /** + * @dev Returns the downcasted uint48 from uint256, reverting on + * overflow (when the input is greater than largest uint48). + * + * Counterpart to Solidity's `uint48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toUint48(uint256 value) internal pure returns (uint48) { + if (value > type(uint48).max) { + revert SafeCastOverflowedUintDowncast(48, value); + } + return uint48(value); + } + + /** + * @dev Returns the downcasted uint40 from uint256, reverting on + * overflow (when the input is greater than largest uint40). + * + * Counterpart to Solidity's `uint40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toUint40(uint256 value) internal pure returns (uint40) { + if (value > type(uint40).max) { + revert SafeCastOverflowedUintDowncast(40, value); + } + return uint40(value); + } + + /** + * @dev Returns the downcasted uint32 from uint256, reverting on + * overflow (when the input is greater than largest uint32). + * + * Counterpart to Solidity's `uint32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toUint32(uint256 value) internal pure returns (uint32) { + if (value > type(uint32).max) { + revert SafeCastOverflowedUintDowncast(32, value); + } + return uint32(value); + } + + /** + * @dev Returns the downcasted uint24 from uint256, reverting on + * overflow (when the input is greater than largest uint24). + * + * Counterpart to Solidity's `uint24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toUint24(uint256 value) internal pure returns (uint24) { + if (value > type(uint24).max) { + revert SafeCastOverflowedUintDowncast(24, value); + } + return uint24(value); + } + + /** + * @dev Returns the downcasted uint16 from uint256, reverting on + * overflow (when the input is greater than largest uint16). + * + * Counterpart to Solidity's `uint16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toUint16(uint256 value) internal pure returns (uint16) { + if (value > type(uint16).max) { + revert SafeCastOverflowedUintDowncast(16, value); + } + return uint16(value); + } + + /** + * @dev Returns the downcasted uint8 from uint256, reverting on + * overflow (when the input is greater than largest uint8). + * + * Counterpart to Solidity's `uint8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toUint8(uint256 value) internal pure returns (uint8) { + if (value > type(uint8).max) { + revert SafeCastOverflowedUintDowncast(8, value); + } + return uint8(value); + } + + /** + * @dev Converts a signed int256 into an unsigned uint256. + * + * Requirements: + * + * - input must be greater than or equal to 0. + */ + function toUint256(int256 value) internal pure returns (uint256) { + if (value < 0) { + revert SafeCastOverflowedIntToUint(value); + } + return uint256(value); + } + + /** + * @dev Returns the downcasted int248 from int256, reverting on + * overflow (when the input is less than smallest int248 or + * greater than largest int248). + * + * Counterpart to Solidity's `int248` operator. + * + * Requirements: + * + * - input must fit into 248 bits + */ + function toInt248(int256 value) internal pure returns (int248 downcasted) { + downcasted = int248(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(248, value); + } + } + + /** + * @dev Returns the downcasted int240 from int256, reverting on + * overflow (when the input is less than smallest int240 or + * greater than largest int240). + * + * Counterpart to Solidity's `int240` operator. + * + * Requirements: + * + * - input must fit into 240 bits + */ + function toInt240(int256 value) internal pure returns (int240 downcasted) { + downcasted = int240(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(240, value); + } + } + + /** + * @dev Returns the downcasted int232 from int256, reverting on + * overflow (when the input is less than smallest int232 or + * greater than largest int232). + * + * Counterpart to Solidity's `int232` operator. + * + * Requirements: + * + * - input must fit into 232 bits + */ + function toInt232(int256 value) internal pure returns (int232 downcasted) { + downcasted = int232(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(232, value); + } + } + + /** + * @dev Returns the downcasted int224 from int256, reverting on + * overflow (when the input is less than smallest int224 or + * greater than largest int224). + * + * Counterpart to Solidity's `int224` operator. + * + * Requirements: + * + * - input must fit into 224 bits + */ + function toInt224(int256 value) internal pure returns (int224 downcasted) { + downcasted = int224(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(224, value); + } + } + + /** + * @dev Returns the downcasted int216 from int256, reverting on + * overflow (when the input is less than smallest int216 or + * greater than largest int216). + * + * Counterpart to Solidity's `int216` operator. + * + * Requirements: + * + * - input must fit into 216 bits + */ + function toInt216(int256 value) internal pure returns (int216 downcasted) { + downcasted = int216(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(216, value); + } + } + + /** + * @dev Returns the downcasted int208 from int256, reverting on + * overflow (when the input is less than smallest int208 or + * greater than largest int208). + * + * Counterpart to Solidity's `int208` operator. + * + * Requirements: + * + * - input must fit into 208 bits + */ + function toInt208(int256 value) internal pure returns (int208 downcasted) { + downcasted = int208(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(208, value); + } + } + + /** + * @dev Returns the downcasted int200 from int256, reverting on + * overflow (when the input is less than smallest int200 or + * greater than largest int200). + * + * Counterpart to Solidity's `int200` operator. + * + * Requirements: + * + * - input must fit into 200 bits + */ + function toInt200(int256 value) internal pure returns (int200 downcasted) { + downcasted = int200(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(200, value); + } + } + + /** + * @dev Returns the downcasted int192 from int256, reverting on + * overflow (when the input is less than smallest int192 or + * greater than largest int192). + * + * Counterpart to Solidity's `int192` operator. + * + * Requirements: + * + * - input must fit into 192 bits + */ + function toInt192(int256 value) internal pure returns (int192 downcasted) { + downcasted = int192(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(192, value); + } + } + + /** + * @dev Returns the downcasted int184 from int256, reverting on + * overflow (when the input is less than smallest int184 or + * greater than largest int184). + * + * Counterpart to Solidity's `int184` operator. + * + * Requirements: + * + * - input must fit into 184 bits + */ + function toInt184(int256 value) internal pure returns (int184 downcasted) { + downcasted = int184(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(184, value); + } + } + + /** + * @dev Returns the downcasted int176 from int256, reverting on + * overflow (when the input is less than smallest int176 or + * greater than largest int176). + * + * Counterpart to Solidity's `int176` operator. + * + * Requirements: + * + * - input must fit into 176 bits + */ + function toInt176(int256 value) internal pure returns (int176 downcasted) { + downcasted = int176(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(176, value); + } + } + + /** + * @dev Returns the downcasted int168 from int256, reverting on + * overflow (when the input is less than smallest int168 or + * greater than largest int168). + * + * Counterpart to Solidity's `int168` operator. + * + * Requirements: + * + * - input must fit into 168 bits + */ + function toInt168(int256 value) internal pure returns (int168 downcasted) { + downcasted = int168(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(168, value); + } + } + + /** + * @dev Returns the downcasted int160 from int256, reverting on + * overflow (when the input is less than smallest int160 or + * greater than largest int160). + * + * Counterpart to Solidity's `int160` operator. + * + * Requirements: + * + * - input must fit into 160 bits + */ + function toInt160(int256 value) internal pure returns (int160 downcasted) { + downcasted = int160(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(160, value); + } + } + + /** + * @dev Returns the downcasted int152 from int256, reverting on + * overflow (when the input is less than smallest int152 or + * greater than largest int152). + * + * Counterpart to Solidity's `int152` operator. + * + * Requirements: + * + * - input must fit into 152 bits + */ + function toInt152(int256 value) internal pure returns (int152 downcasted) { + downcasted = int152(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(152, value); + } + } + + /** + * @dev Returns the downcasted int144 from int256, reverting on + * overflow (when the input is less than smallest int144 or + * greater than largest int144). + * + * Counterpart to Solidity's `int144` operator. + * + * Requirements: + * + * - input must fit into 144 bits + */ + function toInt144(int256 value) internal pure returns (int144 downcasted) { + downcasted = int144(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(144, value); + } + } + + /** + * @dev Returns the downcasted int136 from int256, reverting on + * overflow (when the input is less than smallest int136 or + * greater than largest int136). + * + * Counterpart to Solidity's `int136` operator. + * + * Requirements: + * + * - input must fit into 136 bits + */ + function toInt136(int256 value) internal pure returns (int136 downcasted) { + downcasted = int136(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(136, value); + } + } + + /** + * @dev Returns the downcasted int128 from int256, reverting on + * overflow (when the input is less than smallest int128 or + * greater than largest int128). + * + * Counterpart to Solidity's `int128` operator. + * + * Requirements: + * + * - input must fit into 128 bits + */ + function toInt128(int256 value) internal pure returns (int128 downcasted) { + downcasted = int128(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(128, value); + } + } + + /** + * @dev Returns the downcasted int120 from int256, reverting on + * overflow (when the input is less than smallest int120 or + * greater than largest int120). + * + * Counterpart to Solidity's `int120` operator. + * + * Requirements: + * + * - input must fit into 120 bits + */ + function toInt120(int256 value) internal pure returns (int120 downcasted) { + downcasted = int120(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(120, value); + } + } + + /** + * @dev Returns the downcasted int112 from int256, reverting on + * overflow (when the input is less than smallest int112 or + * greater than largest int112). + * + * Counterpart to Solidity's `int112` operator. + * + * Requirements: + * + * - input must fit into 112 bits + */ + function toInt112(int256 value) internal pure returns (int112 downcasted) { + downcasted = int112(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(112, value); + } + } + + /** + * @dev Returns the downcasted int104 from int256, reverting on + * overflow (when the input is less than smallest int104 or + * greater than largest int104). + * + * Counterpart to Solidity's `int104` operator. + * + * Requirements: + * + * - input must fit into 104 bits + */ + function toInt104(int256 value) internal pure returns (int104 downcasted) { + downcasted = int104(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(104, value); + } + } + + /** + * @dev Returns the downcasted int96 from int256, reverting on + * overflow (when the input is less than smallest int96 or + * greater than largest int96). + * + * Counterpart to Solidity's `int96` operator. + * + * Requirements: + * + * - input must fit into 96 bits + */ + function toInt96(int256 value) internal pure returns (int96 downcasted) { + downcasted = int96(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(96, value); + } + } + + /** + * @dev Returns the downcasted int88 from int256, reverting on + * overflow (when the input is less than smallest int88 or + * greater than largest int88). + * + * Counterpart to Solidity's `int88` operator. + * + * Requirements: + * + * - input must fit into 88 bits + */ + function toInt88(int256 value) internal pure returns (int88 downcasted) { + downcasted = int88(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(88, value); + } + } + + /** + * @dev Returns the downcasted int80 from int256, reverting on + * overflow (when the input is less than smallest int80 or + * greater than largest int80). + * + * Counterpart to Solidity's `int80` operator. + * + * Requirements: + * + * - input must fit into 80 bits + */ + function toInt80(int256 value) internal pure returns (int80 downcasted) { + downcasted = int80(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(80, value); + } + } + + /** + * @dev Returns the downcasted int72 from int256, reverting on + * overflow (when the input is less than smallest int72 or + * greater than largest int72). + * + * Counterpart to Solidity's `int72` operator. + * + * Requirements: + * + * - input must fit into 72 bits + */ + function toInt72(int256 value) internal pure returns (int72 downcasted) { + downcasted = int72(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(72, value); + } + } + + /** + * @dev Returns the downcasted int64 from int256, reverting on + * overflow (when the input is less than smallest int64 or + * greater than largest int64). + * + * Counterpart to Solidity's `int64` operator. + * + * Requirements: + * + * - input must fit into 64 bits + */ + function toInt64(int256 value) internal pure returns (int64 downcasted) { + downcasted = int64(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(64, value); + } + } + + /** + * @dev Returns the downcasted int56 from int256, reverting on + * overflow (when the input is less than smallest int56 or + * greater than largest int56). + * + * Counterpart to Solidity's `int56` operator. + * + * Requirements: + * + * - input must fit into 56 bits + */ + function toInt56(int256 value) internal pure returns (int56 downcasted) { + downcasted = int56(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(56, value); + } + } + + /** + * @dev Returns the downcasted int48 from int256, reverting on + * overflow (when the input is less than smallest int48 or + * greater than largest int48). + * + * Counterpart to Solidity's `int48` operator. + * + * Requirements: + * + * - input must fit into 48 bits + */ + function toInt48(int256 value) internal pure returns (int48 downcasted) { + downcasted = int48(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(48, value); + } + } + + /** + * @dev Returns the downcasted int40 from int256, reverting on + * overflow (when the input is less than smallest int40 or + * greater than largest int40). + * + * Counterpart to Solidity's `int40` operator. + * + * Requirements: + * + * - input must fit into 40 bits + */ + function toInt40(int256 value) internal pure returns (int40 downcasted) { + downcasted = int40(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(40, value); + } + } + + /** + * @dev Returns the downcasted int32 from int256, reverting on + * overflow (when the input is less than smallest int32 or + * greater than largest int32). + * + * Counterpart to Solidity's `int32` operator. + * + * Requirements: + * + * - input must fit into 32 bits + */ + function toInt32(int256 value) internal pure returns (int32 downcasted) { + downcasted = int32(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(32, value); + } + } + + /** + * @dev Returns the downcasted int24 from int256, reverting on + * overflow (when the input is less than smallest int24 or + * greater than largest int24). + * + * Counterpart to Solidity's `int24` operator. + * + * Requirements: + * + * - input must fit into 24 bits + */ + function toInt24(int256 value) internal pure returns (int24 downcasted) { + downcasted = int24(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(24, value); + } + } + + /** + * @dev Returns the downcasted int16 from int256, reverting on + * overflow (when the input is less than smallest int16 or + * greater than largest int16). + * + * Counterpart to Solidity's `int16` operator. + * + * Requirements: + * + * - input must fit into 16 bits + */ + function toInt16(int256 value) internal pure returns (int16 downcasted) { + downcasted = int16(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(16, value); + } + } + + /** + * @dev Returns the downcasted int8 from int256, reverting on + * overflow (when the input is less than smallest int8 or + * greater than largest int8). + * + * Counterpart to Solidity's `int8` operator. + * + * Requirements: + * + * - input must fit into 8 bits + */ + function toInt8(int256 value) internal pure returns (int8 downcasted) { + downcasted = int8(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(8, value); + } + } + + /** + * @dev Converts an unsigned uint256 into a signed int256. + * + * Requirements: + * + * - input must be less than or equal to maxInt256. + */ + function toInt256(uint256 value) internal pure returns (int256) { + // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive + if (value > uint256(type(int256).max)) { + revert SafeCastOverflowedUintToInt(value); + } + return int256(value); + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol b/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol new file mode 100644 index 0000000..66a6151 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/math/SignedMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol) + +pragma solidity ^0.8.20; + +/** + * @dev Standard signed math utilities missing in the Solidity language. + */ +library SignedMath { + /** + * @dev Returns the largest of two signed numbers. + */ + function max(int256 a, int256 b) internal pure returns (int256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two signed numbers. + */ + function min(int256 a, int256 b) internal pure returns (int256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two signed numbers without overflow. + * The result is rounded towards zero. + */ + function average(int256 a, int256 b) internal pure returns (int256) { + // Formula from the book "Hacker's Delight" + int256 x = (a & b) + ((a ^ b) >> 1); + return x + (int256(uint256(x) >> 255) & (a ^ b)); + } + + /** + * @dev Returns the absolute unsigned value of a signed value. + */ + function abs(int256 n) internal pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol b/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol new file mode 100644 index 0000000..40cceb9 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/BitMaps.sol) +pragma solidity ^0.8.20; + +/** + * @dev Library for managing uint256 to bool mapping in a compact and efficient way, provided the keys are sequential. + * Largely inspired by Uniswap's https://github.com/Uniswap/merkle-distributor/blob/master/contracts/MerkleDistributor.sol[merkle-distributor]. + * + * BitMaps pack 256 booleans across each bit of a single 256-bit slot of `uint256` type. + * Hence booleans corresponding to 256 _sequential_ indices would only consume a single slot, + * unlike the regular `bool` which would consume an entire slot for a single value. + * + * This results in gas savings in two ways: + * + * - Setting a zero value to non-zero only once every 256 times + * - Accessing the same warm slot for every 256 _sequential_ indices + */ +library BitMaps { + struct BitMap { + mapping(uint256 bucket => uint256) _data; + } + + /** + * @dev Returns whether the bit at `index` is set. + */ + function get(BitMap storage bitmap, uint256 index) internal view returns (bool) { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + return bitmap._data[bucket] & mask != 0; + } + + /** + * @dev Sets the bit at `index` to the boolean `value`. + */ + function setTo(BitMap storage bitmap, uint256 index, bool value) internal { + if (value) { + set(bitmap, index); + } else { + unset(bitmap, index); + } + } + + /** + * @dev Sets the bit at `index`. + */ + function set(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] |= mask; + } + + /** + * @dev Unsets the bit at `index`. + */ + function unset(BitMap storage bitmap, uint256 index) internal { + uint256 bucket = index >> 8; + uint256 mask = 1 << (index & 0xff); + bitmap._data[bucket] &= ~mask; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol b/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol new file mode 100644 index 0000000..6561b0d --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sol @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol) +// This file was procedurally generated from scripts/generate/templates/Checkpoints.js. + +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; + +/** + * @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + */ +library Checkpoints { + /** + * @dev A value was attempted to be inserted on a past checkpoint. + */ + error CheckpointUnorderedInsertion(); + + struct Trace224 { + Checkpoint224[] _checkpoints; + } + + struct Checkpoint224 { + uint32 _key; + uint224 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the + * library. + */ + function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the 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; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @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; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @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). + */ + 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. + */ + function latest(Trace224 storage self) internal view returns (uint224) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace224 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint224 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint224({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint224({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the 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. + */ + function _upperBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint224[] storage self, + uint32 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint224[] storage self, + uint256 pos + ) private pure returns (Checkpoint224 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace208 { + Checkpoint208[] _checkpoints; + } + + struct Checkpoint208 { + uint48 _key; + uint208 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the + * library. + */ + function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) { + return _insert(self._checkpoints, key, value); + } + + /** + * @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(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero + * if there is none. + */ + function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) { + uint256 len = self._checkpoints.length; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns the value in the 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). + */ + function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) { + 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. + */ + function latest(Trace208 storage self) internal view returns (uint208) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint208 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace208 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint208 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint208({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint208({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @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. + */ + function _upperBinaryLookup( + Checkpoint208[] storage self, + uint48 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint208[] storage self, + uint48 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint208[] storage self, + uint256 pos + ) private pure returns (Checkpoint208 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } + + struct Trace160 { + Checkpoint160[] _checkpoints; + } + + struct Checkpoint160 { + uint96 _key; + uint160 _value; + } + + /** + * @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the + * library. + */ + function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) { + return _insert(self._checkpoints, key, value); + } + + /** + * @dev Returns the value in the 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; + uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value; + } + + /** + * @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; + uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len); + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @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). + */ + 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. + */ + function latest(Trace160 storage self) internal view returns (uint160) { + uint256 pos = self._checkpoints.length; + return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value; + } + + /** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ + function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) { + uint256 pos = self._checkpoints.length; + if (pos == 0) { + return (false, 0, 0); + } else { + Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1); + return (true, ckpt._key, ckpt._value); + } + } + + /** + * @dev Returns the number of checkpoint. + */ + function length(Trace160 storage self) internal view returns (uint256) { + return self._checkpoints.length; + } + + /** + * @dev Returns checkpoint at given position. + */ + function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) { + return self._checkpoints[pos]; + } + + /** + * @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ + function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + Checkpoint160 memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if (last._key > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last._key == key) { + _unsafeAccess(self, pos - 1)._value = value; + } else { + self.push(Checkpoint160({_key: key, _value: value})); + } + return (last._value, value); + } else { + self.push(Checkpoint160({_key: key, _value: value})); + return (0, value); + } + } + + /** + * @dev Return the index of the 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. + */ + function _upperBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; + } + + /** + * @dev Return the index of the 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. + */ + function _lowerBinaryLookup( + Checkpoint160[] storage self, + uint96 key, + uint256 low, + uint256 high + ) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid)._key < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; + } + + /** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ + function _unsafeAccess( + Checkpoint160[] storage self, + uint256 pos + ) private pure returns (Checkpoint160 storage result) { + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol b/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol new file mode 100644 index 0000000..218a2fb --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/DoubleEndedQueue.sol) +pragma solidity ^0.8.20; + +/** + * @dev A sequence of items with the ability to efficiently push and pop items (i.e. insert and remove) on both ends of + * the sequence (called front and back). Among other access patterns, it can be used to implement efficient LIFO and + * FIFO queues. Storage use is optimized, and all operations are O(1) constant time. This includes {clear}, given that + * the existing queue contents are left in storage. + * + * 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; + * ``` + */ +library DoubleEndedQueue { + /** + * @dev An operation (e.g. {front}) couldn't be completed due to the queue being empty. + */ + error QueueEmpty(); + + /** + * @dev A push operation couldn't be completed due to the queue being full. + */ + error QueueFull(); + + /** + * @dev An operation (e.g. {at}) couldn't be completed due to an index being out of bounds. + */ + error QueueOutOfBounds(); + + /** + * @dev Indices are 128 bits so begin and end are packed in a single storage slot for efficient access. + * + * Struct members have an underscore prefix indicating that they are "private" and should not be read or written to + * directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and + * lead to unexpected behavior. + * + * The first item is at data[begin] and the last item is at data[end - 1]. This range can wrap around. + */ + struct Bytes32Deque { + uint128 _begin; + uint128 _end; + mapping(uint128 index => bytes32) _data; + } + + /** + * @dev Inserts an item at the end of the queue. + * + * Reverts with {QueueFull} if the queue is full. + */ + function pushBack(Bytes32Deque storage deque, bytes32 value) internal { + unchecked { + uint128 backIndex = deque._end; + if (backIndex + 1 == deque._begin) revert QueueFull(); + deque._data[backIndex] = value; + deque._end = backIndex + 1; + } + } + + /** + * @dev Removes the item at the end of the queue and returns it. + * + * Reverts with {QueueEmpty} if the queue is empty. + */ + function popBack(Bytes32Deque storage deque) internal returns (bytes32 value) { + unchecked { + uint128 backIndex = deque._end; + if (backIndex == deque._begin) revert QueueEmpty(); + --backIndex; + value = deque._data[backIndex]; + delete deque._data[backIndex]; + deque._end = backIndex; + } + } + + /** + * @dev Inserts an item at the beginning of the queue. + * + * Reverts with {QueueFull} if the queue is full. + */ + function pushFront(Bytes32Deque storage deque, bytes32 value) internal { + unchecked { + uint128 frontIndex = deque._begin - 1; + if (frontIndex == deque._end) revert QueueFull(); + deque._data[frontIndex] = value; + deque._begin = frontIndex; + } + } + + /** + * @dev Removes the item at the beginning of the queue and returns it. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function popFront(Bytes32Deque storage deque) internal returns (bytes32 value) { + unchecked { + uint128 frontIndex = deque._begin; + if (frontIndex == deque._end) revert QueueEmpty(); + value = deque._data[frontIndex]; + delete deque._data[frontIndex]; + deque._begin = frontIndex + 1; + } + } + + /** + * @dev Returns the item at the beginning of the queue. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function front(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) revert QueueEmpty(); + return deque._data[deque._begin]; + } + + /** + * @dev Returns the item at the end of the queue. + * + * Reverts with `QueueEmpty` if the queue is empty. + */ + function back(Bytes32Deque storage deque) internal view returns (bytes32 value) { + if (empty(deque)) revert QueueEmpty(); + unchecked { + return deque._data[deque._end - 1]; + } + } + + /** + * @dev Return the item at a position in the queue given by `index`, with the first item at 0 and last item at + * `length(deque) - 1`. + * + * Reverts with `QueueOutOfBounds` if the index is out of bounds. + */ + function at(Bytes32Deque storage deque, uint256 index) internal view returns (bytes32 value) { + if (index >= length(deque)) revert QueueOutOfBounds(); + // By construction, length is a uint128, so the check above ensures that index can be safely downcast to uint128 + unchecked { + return deque._data[deque._begin + uint128(index)]; + } + } + + /** + * @dev Resets the queue back to being empty. + * + * NOTE: The current items are left behind in storage. This does not affect the functioning of the queue, but misses + * out on potential gas refunds. + */ + function clear(Bytes32Deque storage deque) internal { + deque._begin = 0; + deque._end = 0; + } + + /** + * @dev Returns the number of items in the queue. + */ + function length(Bytes32Deque storage deque) internal view returns (uint256) { + unchecked { + return uint256(deque._end - deque._begin); + } + } + + /** + * @dev Returns true if the queue is empty. + */ + function empty(Bytes32Deque storage deque) internal view returns (bool) { + return deque._end == deque._begin; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol b/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol new file mode 100644 index 0000000..929ae7c --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol @@ -0,0 +1,533 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableMap.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js. + +pragma solidity ^0.8.20; + +import {EnumerableSet} from "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * ``` + * + * The following map types are supported: + * + * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0 + * - `address -> uint256` (`AddressToUintMap`) since v4.6.0 + * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0 + * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0 + * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +library EnumerableMap { + using EnumerableSet for EnumerableSet.Bytes32Set; + + // To implement this library for multiple types with as little code repetition as possible, we write it in + // terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions, + // and user-facing implementations such as `UintToAddressMap` are just wrappers around the underlying Map. + // This means that we can only create new EnumerableMaps for types that fit in bytes32. + + /** + * @dev Query for a nonexistent map key. + */ + error EnumerableMapNonexistentKey(bytes32 key); + + struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 key => bytes32) _values; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(Bytes32ToBytes32Map storage map, bytes32 key, bytes32 value) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); + } + + /** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); + } + + /** + * @dev Returns the number of key-value pairs in the map. O(1). + */ + function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); + } + + /** + * @dev Returns the key-value pair stored at position `index` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + if (value == 0 && !contains(map, key)) { + revert EnumerableMapNonexistentKey(key); + } + return value; + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { + return map._keys.values(); + } + + // UintToUintMap + + struct UintToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToUintMap storage map, uint256 key, uint256 value) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToUintMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(key))); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(UintToUintMap storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintToAddressMap + + struct UintToAddressMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(UintToAddressMap storage map, uint256 key, address value) internal returns (bool) { + return set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) { + return remove(map._inner, bytes32(key)); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) { + return contains(map._inner, bytes32(key)); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(UintToAddressMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (uint256(key), address(uint160(uint256(value)))); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(key)); + return (success, address(uint160(uint256(value)))); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(UintToAddressMap storage map, uint256 key) internal view returns (address) { + return address(uint160(uint256(get(map._inner, bytes32(key))))); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(UintToAddressMap storage map) internal view returns (uint256[] memory) { + bytes32[] memory store = keys(map._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressToUintMap + + struct AddressToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(AddressToUintMap storage map, address key, uint256 value) internal returns (bool) { + return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(AddressToUintMap storage map, address key) internal returns (bool) { + return remove(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(AddressToUintMap storage map, address key) internal view returns (bool) { + return contains(map._inner, bytes32(uint256(uint160(key)))); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(AddressToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (address(uint160(uint256(key))), uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key)))); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(AddressToUintMap storage map, address key) internal view returns (uint256) { + return uint256(get(map._inner, bytes32(uint256(uint160(key))))); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(AddressToUintMap storage map) internal view returns (address[] memory) { + bytes32[] memory store = keys(map._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // Bytes32ToUintMap + + struct Bytes32ToUintMap { + Bytes32ToBytes32Map _inner; + } + + /** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ + function set(Bytes32ToUintMap storage map, bytes32 key, uint256 value) internal returns (bool) { + return set(map._inner, key, bytes32(value)); + } + + /** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ + function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) { + return remove(map._inner, key); + } + + /** + * @dev Returns true if the key is in the map. O(1). + */ + function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) { + return contains(map._inner, key); + } + + /** + * @dev Returns the number of elements in the map. O(1). + */ + function length(Bytes32ToUintMap storage map) internal view returns (uint256) { + return length(map._inner); + } + + /** + * @dev Returns the element stored at position `index` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (key, uint256(value)); + } + + /** + * @dev Tries to returns the value associated with `key`. O(1). + * Does not revert if `key` is not in the map. + */ + function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) { + (bool success, bytes32 value) = tryGet(map._inner, key); + return (success, uint256(value)); + } + + /** + * @dev Returns the value associated with `key`. O(1). + * + * Requirements: + * + * - `key` must be in the map. + */ + function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) { + return uint256(get(map._inner, key)); + } + + /** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function keys(Bytes32ToUintMap storage map) internal view returns (bytes32[] memory) { + bytes32[] memory store = keys(map._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol b/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol new file mode 100644 index 0000000..4c7fc5e --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol) +// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. + +pragma solidity ^0.8.20; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * ``` + * + * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) + * and `uint256` (`UintSet`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +library EnumerableSet { + // To implement this library for multiple types with as little code + // repetition as possible, we write it in terms of a generic Set type with + // bytes32 values. + // The Set implementation uses private functions, and user-facing + // implementations (such as AddressSet) are just wrappers around the + // underlying Set. + // This means that we can only create new EnumerableSets for types that fit + // in bytes32. + + struct Set { + // Storage of set values + bytes32[] _values; + // Position is the index of the value in the `values` array plus 1. + // Position 0 is used to mean a value is not in the set. + mapping(bytes32 value => uint256) _positions; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._positions[value] = set._values.length; + return true; + } else { + return false; + } + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function _remove(Set storage set, bytes32 value) private returns (bool) { + // We cache the value's position to prevent multiple reads from the same storage slot + uint256 position = set._positions[value]; + + if (position != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 valueIndex = position - 1; + uint256 lastIndex = set._values.length - 1; + + if (valueIndex != lastIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the lastValue to the index where the value to delete is + set._values[valueIndex] = lastValue; + // Update the tracked position of the lastValue (that was just moved) + set._positions[lastValue] = position; + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the tracked position for the deleted slot + delete set._positions[value]; + + return true; + } else { + return false; + } + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._positions[value] != 0; + } + + /** + * @dev Returns the number of values on the set. O(1). + */ + function _length(Set storage set) private view returns (uint256) { + return set._values.length; + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; + } + + // Bytes32Set + + struct Bytes32Set { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _add(set._inner, value); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { + return _remove(set._inner, value); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { + return _contains(set._inner, value); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(Bytes32Set storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { + return _at(set._inner, index); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { + bytes32[] memory store = _values(set._inner); + bytes32[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // AddressSet + + struct AddressSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(AddressSet storage set, address value) internal returns (bool) { + return _add(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(AddressSet storage set, address value) internal returns (bool) { + return _remove(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(AddressSet storage set, address value) internal view returns (bool) { + return _contains(set._inner, bytes32(uint256(uint160(value)))); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(AddressSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(AddressSet storage set, uint256 index) internal view returns (address) { + return address(uint160(uint256(_at(set._inner, index)))); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(AddressSet storage set) internal view returns (address[] memory) { + bytes32[] memory store = _values(set._inner); + address[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } + + // UintSet + + struct UintSet { + Set _inner; + } + + /** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ + function add(UintSet storage set, uint256 value) internal returns (bool) { + return _add(set._inner, bytes32(value)); + } + + /** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ + function remove(UintSet storage set, uint256 value) internal returns (bool) { + return _remove(set._inner, bytes32(value)); + } + + /** + * @dev Returns true if the value is in the set. O(1). + */ + function contains(UintSet storage set, uint256 value) internal view returns (bool) { + return _contains(set._inner, bytes32(value)); + } + + /** + * @dev Returns the number of values in the set. O(1). + */ + function length(UintSet storage set) internal view returns (uint256) { + return _length(set._inner); + } + + /** + * @dev Returns the value stored at position `index` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - `index` must be strictly less than {length}. + */ + function at(UintSet storage set, uint256 index) internal view returns (uint256) { + return uint256(_at(set._inner, index)); + } + + /** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ + function values(UintSet storage set) internal view returns (uint256[] memory) { + bytes32[] memory store = _values(set._inner); + uint256[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts/contracts/utils/types/Time.sol b/lib/openzeppelin-contracts/contracts/utils/types/Time.sol new file mode 100644 index 0000000..9faef31 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/utils/types/Time.sol @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (utils/types/Time.sol) + +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; +import {SafeCast} from "../math/SafeCast.sol"; + +/** + * @dev This library provides helpers for manipulating time-related objects. + * + * It uses the following types: + * - `uint48` for timepoints + * - `uint32` for durations + * + * While the library doesn't provide specific types for timepoints and duration, it does provide: + * - a `Delay` type to represent duration that can be programmed to change value automatically at a given point + * - additional helper functions + */ +library Time { + using Time for *; + + /** + * @dev Get the block timestamp as a Timepoint. + */ + function timestamp() internal view returns (uint48) { + return SafeCast.toUint48(block.timestamp); + } + + /** + * @dev Get the block number as a Timepoint. + */ + function blockNumber() internal view returns (uint48) { + return SafeCast.toUint48(block.number); + } + + // ==================================================== Delay ===================================================== + /** + * @dev A `Delay` is a uint32 duration that can be programmed to change value automatically at a given point in the + * future. The "effect" timepoint describes when the transitions happens from the "old" value to the "new" value. + * This allows updating the delay applied to some operation while keeping some guarantees. + * + * In particular, the {update} function guarantees that if the delay is reduced, the old delay still applies for + * some time. For example if the delay is currently 7 days to do an upgrade, the admin should not be able to set + * the delay to 0 and upgrade immediately. If the admin wants to reduce the delay, the old delay (7 days) should + * still apply for some time. + * + * + * The `Delay` type is 112 bits long, and packs the following: + * + * ``` + * | [uint48]: effect date (timepoint) + * | | [uint32]: value before (duration) + * ↓ ↓ ↓ [uint32]: value after (duration) + * 0xAAAAAAAAAAAABBBBBBBBCCCCCCCC + * ``` + * + * NOTE: The {get} and {withUpdate} functions operate using timestamps. Block number based delays are not currently + * supported. + */ + type Delay is uint112; + + /** + * @dev Wrap a duration into a Delay to add the one-step "update in the future" feature + */ + function toDelay(uint32 duration) internal pure returns (Delay) { + return Delay.wrap(duration); + } + + /** + * @dev Get the value at a given timepoint plus the pending value and effect timepoint if there is a scheduled + * change after this timepoint. If the effect timepoint is 0, then the pending value should not be considered. + */ + function _getFullAt(Delay self, uint48 timepoint) private pure returns (uint32, uint32, uint48) { + (uint32 valueBefore, uint32 valueAfter, uint48 effect) = self.unpack(); + return effect <= timepoint ? (valueAfter, 0, 0) : (valueBefore, valueAfter, effect); + } + + /** + * @dev Get the current value plus the pending value and effect timepoint if there is a scheduled change. If the + * effect timepoint is 0, then the pending value should not be considered. + */ + function getFull(Delay self) internal view returns (uint32, uint32, uint48) { + return _getFullAt(self, timestamp()); + } + + /** + * @dev Get the current value. + */ + function get(Delay self) internal view returns (uint32) { + (uint32 delay, , ) = self.getFull(); + return delay; + } + + /** + * @dev Update a Delay object so that it takes a new duration after a timepoint that is automatically computed to + * enforce the old delay at the moment of the update. Returns the updated Delay object and the timestamp when the + * new delay becomes effective. + */ + function withUpdate( + Delay self, + uint32 newValue, + uint32 minSetback + ) internal view returns (Delay updatedDelay, uint48 effect) { + uint32 value = self.get(); + uint32 setback = uint32(Math.max(minSetback, value > newValue ? value - newValue : 0)); + effect = timestamp() + setback; + return (pack(value, newValue, effect), effect); + } + + /** + * @dev Split a delay into its components: valueBefore, valueAfter and effect (transition timepoint). + */ + function unpack(Delay self) internal pure returns (uint32 valueBefore, uint32 valueAfter, uint48 effect) { + uint112 raw = Delay.unwrap(self); + + valueAfter = uint32(raw); + valueBefore = uint32(raw >> 32); + effect = uint48(raw >> 64); + + return (valueBefore, valueAfter, effect); + } + + /** + * @dev pack the components into a Delay object. + */ + function pack(uint32 valueBefore, uint32 valueAfter, uint48 effect) internal pure returns (Delay) { + return Delay.wrap((uint112(effect) << 64) | (uint112(valueBefore) << 32) | uint112(valueAfter)); + } +} diff --git a/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol b/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol new file mode 100644 index 0000000..320eea1 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.0.0) (vendor/compound/ICompoundTimelock.sol) + +pragma solidity ^0.8.20; + +/** + * https://github.com/compound-finance/compound-protocol/blob/master/contracts/Timelock.sol[Compound timelock] interface + */ +interface ICompoundTimelock { + event NewAdmin(address indexed newAdmin); + event NewPendingAdmin(address indexed newPendingAdmin); + event NewDelay(uint256 indexed newDelay); + event CancelTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event ExecuteTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + event QueueTransaction( + bytes32 indexed txHash, + address indexed target, + uint256 value, + string signature, + bytes data, + uint256 eta + ); + + receive() external payable; + + // solhint-disable-next-line func-name-mixedcase + function GRACE_PERIOD() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function MINIMUM_DELAY() external view returns (uint256); + + // solhint-disable-next-line func-name-mixedcase + function MAXIMUM_DELAY() external view returns (uint256); + + function admin() external view returns (address); + + function pendingAdmin() external view returns (address); + + function delay() external view returns (uint256); + + function queuedTransactions(bytes32) external view returns (bool); + + function setDelay(uint256) external; + + function acceptAdmin() external; + + function setPendingAdmin(address) external; + + function queueTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external returns (bytes32); + + function cancelTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external; + + function executeTransaction( + address target, + uint256 value, + string memory signature, + bytes memory data, + uint256 eta + ) external payable returns (bytes memory); +} diff --git a/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE b/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE new file mode 100644 index 0000000..7da2324 --- /dev/null +++ b/lib/openzeppelin-contracts/contracts/vendor/compound/LICENSE @@ -0,0 +1,11 @@ +Copyright 2020 Compound Labs, Inc. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/lib/openzeppelin-contracts/foundry.toml b/lib/openzeppelin-contracts/foundry.toml new file mode 100644 index 0000000..859f210 --- /dev/null +++ b/lib/openzeppelin-contracts/foundry.toml @@ -0,0 +1,10 @@ +[profile.default] +src = 'contracts' +out = 'out' +libs = ['node_modules', 'lib'] +test = 'test' +cache_path = 'cache_forge' + +[fuzz] +runs = 10000 +max_test_rejects = 150000 diff --git a/lib/openzeppelin-contracts/hardhat.config.js b/lib/openzeppelin-contracts/hardhat.config.js new file mode 100644 index 0000000..4d5ab94 --- /dev/null +++ b/lib/openzeppelin-contracts/hardhat.config.js @@ -0,0 +1,131 @@ +/// ENVVAR +// - CI: output gas report to file instead of stdout +// - COVERAGE: enable coverage report +// - ENABLE_GAS_REPORT: enable gas report +// - COMPILE_MODE: production modes enables optimizations (default: development) +// - COMPILE_VERSION: compiler version (default: 0.8.20) +// - COINMARKETCAP: coinmarkercat api key for USD value in gas report + +const fs = require('fs'); +const path = require('path'); +const proc = require('child_process'); + +const argv = require('yargs/yargs')() + .env('') + .options({ + coverage: { + type: 'boolean', + default: false, + }, + gas: { + alias: 'enableGasReport', + type: 'boolean', + default: false, + }, + gasReport: { + alias: 'enableGasReportPath', + type: 'string', + implies: 'gas', + default: undefined, + }, + mode: { + alias: 'compileMode', + type: 'string', + choices: ['production', 'development'], + default: 'development', + }, + ir: { + alias: 'enableIR', + type: 'boolean', + default: false, + }, + foundry: { + alias: 'hasFoundry', + type: 'boolean', + default: hasFoundry(), + }, + compiler: { + alias: 'compileVersion', + type: 'string', + default: '0.8.20', + }, + coinmarketcap: { + alias: 'coinmarketcapApiKey', + type: 'string', + }, + }).argv; + +require('@nomiclabs/hardhat-truffle5'); +require('hardhat-ignore-warnings'); +require('hardhat-exposed'); +require('solidity-docgen'); +argv.foundry && require('@nomicfoundation/hardhat-foundry'); + +if (argv.foundry && argv.coverage) { + throw Error('Coverage analysis is incompatible with Foundry. Disable with `FOUNDRY=false` in the environment'); +} + +for (const f of fs.readdirSync(path.join(__dirname, 'hardhat'))) { + require(path.join(__dirname, 'hardhat', f)); +} + +const withOptimizations = argv.gas || argv.compileMode === 'production'; + +/** + * @type import('hardhat/config').HardhatUserConfig + */ +module.exports = { + solidity: { + version: argv.compiler, + settings: { + optimizer: { + enabled: withOptimizations, + runs: 200, + }, + viaIR: withOptimizations && argv.ir, + outputSelection: { '*': { '*': ['storageLayout'] } }, + }, + }, + warnings: { + 'contracts-exposed/**/*': { + 'code-size': 'off', + 'initcode-size': 'off', + }, + '*': { + 'code-size': withOptimizations, + 'unused-param': !argv.coverage, // coverage causes unused-param warnings + default: 'error', + }, + }, + networks: { + hardhat: { + blockGasLimit: 10000000, + allowUnlimitedContractSize: !withOptimizations, + }, + }, + exposed: { + imports: true, + initializers: true, + exclude: ['vendor/**/*'], + }, + docgen: require('./docs/config'), +}; + +if (argv.gas) { + require('hardhat-gas-reporter'); + module.exports.gasReporter = { + showMethodSig: true, + currency: 'USD', + outputFile: argv.gasReport, + coinmarketcap: argv.coinmarketcap, + }; +} + +if (argv.coverage) { + require('solidity-coverage'); + module.exports.networks.hardhat.initialBaseFeePerGas = 0; +} + +function hasFoundry() { + return proc.spawnSync('forge', ['-V'], { stdio: 'ignore' }).error === undefined; +} diff --git a/lib/openzeppelin-contracts/hardhat/env-artifacts.js b/lib/openzeppelin-contracts/hardhat/env-artifacts.js new file mode 100644 index 0000000..fbbea2e --- /dev/null +++ b/lib/openzeppelin-contracts/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/lib/openzeppelin-contracts/hardhat/env-contract.js b/lib/openzeppelin-contracts/hardhat/env-contract.js new file mode 100644 index 0000000..c615249 --- /dev/null +++ b/lib/openzeppelin-contracts/hardhat/env-contract.js @@ -0,0 +1,25 @@ +extendEnvironment(env => { + const { contract } = env; + + env.contract = function (name, body) { + const { takeSnapshot } = require('@nomicfoundation/hardhat-network-helpers'); + + contract(name, accounts => { + // reset the state of the chain in between contract test suites + let snapshot; + + before(async function () { + snapshot = await takeSnapshot(); + }); + + after(async function () { + await snapshot.restore(); + }); + + // remove the default account from the accounts list used in tests, in order + // to protect tests against accidentally passing due to the contract + // deployer being used subsequently as function caller + body(accounts.slice(1)); + }); + }; +}); diff --git a/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js b/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js new file mode 100644 index 0000000..8e3e343 --- /dev/null +++ b/lib/openzeppelin-contracts/hardhat/ignore-unreachable-warnings.js @@ -0,0 +1,45 @@ +// Warnings about unreachable code are emitted with a source location that corresponds to the unreachable code. +// We have some testing contracts that purposely cause unreachable code, but said code is in the library contracts, and +// with hardhat-ignore-warnings we are not able to selectively ignore them without potentially ignoring relevant +// warnings that we don't want to miss. +// Thus, we need to handle these warnings separately. We force Hardhat to compile them in a separate compilation job and +// then ignore the warnings about unreachable code that come from that compilation job. + +const { task } = require('hardhat/config'); +const { + TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, + TASK_COMPILE_SOLIDITY_COMPILE, +} = require('hardhat/builtin-tasks/task-names'); + +const marker = Symbol('unreachable'); +const markedCache = new WeakMap(); + +task(TASK_COMPILE_SOLIDITY_GET_COMPILATION_JOB_FOR_FILE, async (params, _, runSuper) => { + const job = await runSuper(params); + // If the file is in the unreachable directory, we make a copy of the config and mark it, which will cause it to get + // compiled separately (along with the other marked files). + if (params.file.sourceName.startsWith('contracts/mocks/') && /\bunreachable\b/.test(params.file.sourceName)) { + const originalConfig = job.solidityConfig; + let markedConfig = markedCache.get(originalConfig); + if (markedConfig === undefined) { + markedConfig = { ...originalConfig, [marker]: true }; + markedCache.set(originalConfig, markedConfig); + } + job.solidityConfig = markedConfig; + } + return job; +}); + +const W_UNREACHABLE_CODE = '5740'; + +task(TASK_COMPILE_SOLIDITY_COMPILE, async (params, _, runSuper) => { + const marked = params.compilationJob.solidityConfig[marker]; + const result = await runSuper(params); + if (marked) { + result.output = { + ...result.output, + errors: result.output.errors?.filter(e => e.severity !== 'warning' || e.errorCode !== W_UNREACHABLE_CODE), + }; + } + return result; +}); diff --git a/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js b/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js new file mode 100644 index 0000000..965ba37 --- /dev/null +++ b/lib/openzeppelin-contracts/hardhat/skip-foundry-tests.js @@ -0,0 +1,6 @@ +const { subtask } = require('hardhat/config'); +const { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } = require('hardhat/builtin-tasks/task-names'); + +subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(async (_, __, runSuper) => + (await runSuper()).filter(path => !path.endsWith('.t.sol')), +); diff --git a/lib/openzeppelin-contracts/hardhat/task-test-get-files.js b/lib/openzeppelin-contracts/hardhat/task-test-get-files.js new file mode 100644 index 0000000..108f40a --- /dev/null +++ b/lib/openzeppelin-contracts/hardhat/task-test-get-files.js @@ -0,0 +1,25 @@ +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 (args, hre, runSuper) => { + const path = require('path'); + const { promises: fs } = require('fs'); + + const hasProxies = await fs + .access(path.join(hre.config.paths.sources, 'proxy/Proxy.sol')) + .then(() => true) + .catch(() => false); + + const ignoredIfProxy = [ + '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(hre.config.paths.tests, p)); + + return (await runSuper(args)).filter(file => hasProxies || !ignoredIfProxy.includes(file)); +}); diff --git a/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol b/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol new file mode 100644 index 0000000..c34512b --- /dev/null +++ b/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.prop.sol @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "forge-std/Test.sol"; + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC20} from "forge-std/interfaces/IERC20.sol"; +interface IERC20 { + event Transfer(address indexed from, address indexed to, uint value); + event Approval(address indexed owner, address indexed spender, uint value); + function totalSupply() external view returns (uint); + function balanceOf(address account) external view returns (uint); + function transfer(address to, uint amount) external returns (bool); + function allowance(address owner, address spender) external view returns (uint); + function approve(address spender, uint amount) external returns (bool); + function transferFrom(address from, address to, uint amount) external returns (bool); +} + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC4626} from "forge-std/interfaces/IERC4626.sol"; +interface IERC4626 is IERC20 { + event Deposit(address indexed caller, address indexed owner, uint assets, uint shares); + event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint assets, uint shares); + function asset() external view returns (address assetTokenAddress); + function totalAssets() external view returns (uint totalManagedAssets); + function convertToShares(uint assets) external view returns (uint shares); + function convertToAssets(uint shares) external view returns (uint assets); + function maxDeposit(address receiver) external view returns (uint maxAssets); + function previewDeposit(uint assets) external view returns (uint shares); + function deposit(uint assets, address receiver) external returns (uint shares); + function maxMint(address receiver) external view returns (uint maxShares); + function previewMint(uint shares) external view returns (uint assets); + function mint(uint shares, address receiver) external returns (uint assets); + function maxWithdraw(address owner) external view returns (uint maxAssets); + function previewWithdraw(uint assets) external view returns (uint shares); + function withdraw(uint assets, address receiver, address owner) external returns (uint shares); + function maxRedeem(address owner) external view returns (uint maxShares); + function previewRedeem(uint shares) external view returns (uint assets); + function redeem(uint shares, address receiver, address owner) external returns (uint assets); +} + +abstract contract ERC4626Prop is Test { + uint internal _delta_; + + address internal _underlying_; + address internal _vault_; + + bool internal _vaultMayBeEmpty; + bool internal _unlimitedAmount; + + // + // asset + // + + // asset + // "MUST NOT revert." + function prop_asset(address caller) public { + vm.prank(caller); IERC4626(_vault_).asset(); + } + + // totalAssets + // "MUST NOT revert." + function prop_totalAssets(address caller) public { + vm.prank(caller); IERC4626(_vault_).totalAssets(); + } + + // + // convert + // + + // convertToShares + // "MUST NOT show any variations depending on the caller." + function prop_convertToShares(address caller1, address caller2, uint assets) public { + vm.prank(caller1); uint res1 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // convertToAssets + // "MUST NOT show any variations depending on the caller." + function prop_convertToAssets(address caller1, address caller2, uint shares) public { + vm.prank(caller1); uint res1 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // + // deposit + // + + // maxDeposit + // "MUST NOT revert." + function prop_maxDeposit(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxDeposit(receiver); + } + + // previewDeposit + // "MUST return as close to and no more than the exact amount of Vault + // shares that would be minted in a deposit call in the same transaction. + // I.e. deposit should return the same or more shares as previewDeposit if + // called in the same transaction." + function prop_previewDeposit(address caller, address receiver, address other, uint assets) public { + vm.prank(other); uint sharesPreview = vault_previewDeposit(assets); // "MAY revert due to other conditions that would also cause deposit to revert." + vm.prank(caller); uint sharesActual = vault_deposit(assets, receiver); + assertApproxGeAbs(sharesActual, sharesPreview, _delta_); + } + + // deposit + function prop_deposit(address caller, address receiver, uint assets) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint shares = vault_deposit(assets, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // mint + // + + // maxMint + // "MUST NOT revert." + function prop_maxMint(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxMint(receiver); + } + + // previewMint + // "MUST return as close to and no fewer than the exact amount of assets + // that would be deposited in a mint call in the same transaction. I.e. mint + // should return the same or fewer assets as previewMint if called in the + // same transaction." + function prop_previewMint(address caller, address receiver, address other, uint shares) public { + vm.prank(other); uint assetsPreview = vault_previewMint(shares); + vm.prank(caller); uint assetsActual = vault_mint(shares, receiver); + assertApproxLeAbs(assetsActual, assetsPreview, _delta_); + } + + // mint + function prop_mint(address caller, address receiver, uint shares) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint assets = vault_mint(shares, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // withdraw + // + + // maxWithdraw + // "MUST NOT revert." + // NOTE: some implementations failed due to arithmetic overflow + function prop_maxWithdraw(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxWithdraw(owner); + } + + // previewWithdraw + // "MUST return as close to and no fewer than the exact amount of Vault + // shares that would be burned in a withdraw call in the same transaction. + // I.e. withdraw should return the same or fewer shares as previewWithdraw + // if called in the same transaction." + function prop_previewWithdraw(address caller, address receiver, address owner, address other, uint assets) public { + vm.prank(other); uint preview = vault_previewWithdraw(assets); + vm.prank(caller); uint actual = vault_withdraw(assets, receiver, owner); + assertApproxLeAbs(actual, preview, _delta_); + } + + // withdraw + function prop_withdraw(address caller, address receiver, address owner, uint assets) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint shares = vault_withdraw(assets, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // redeem + // + + // maxRedeem + // "MUST NOT revert." + function prop_maxRedeem(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxRedeem(owner); + } + + // previewRedeem + // "MUST return as close to and no more than the exact amount of assets that + // would be withdrawn in a redeem call in the same transaction. I.e. redeem + // should return the same or more assets as previewRedeem if called in the + // same transaction." + function prop_previewRedeem(address caller, address receiver, address owner, address other, uint shares) public { + vm.prank(other); uint preview = vault_previewRedeem(shares); + vm.prank(caller); uint actual = vault_redeem(shares, receiver, owner); + assertApproxGeAbs(actual, preview, _delta_); + } + + // redeem + function prop_redeem(address caller, address receiver, address owner, uint shares) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint assets = vault_redeem(shares, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // round trip properties + // + + // redeem(deposit(a)) <= a + function prop_RT_deposit_redeem(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares = vault_deposit(assets, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets, _delta_); + } + + // s = deposit(a) + // s' = withdraw(a) + // s' >= s + function prop_RT_deposit_withdraw(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares1 = vault_deposit(assets, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares1, _delta_); + } + + // deposit(redeem(s)) <= s + function prop_RT_redeem_deposit(address caller, uint shares) public { + vm.prank(caller); uint assets = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares, _delta_); + } + + // a = redeem(s) + // a' = mint(s) + // a' >= a + function prop_RT_redeem_mint(address caller, uint shares) public { + vm.prank(caller); uint assets1 = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets1, _delta_); + } + + // withdraw(mint(s)) >= s + function prop_RT_mint_withdraw(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets = vault_mint(shares, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares, _delta_); + } + + // a = mint(s) + // a' = redeem(s) + // a' <= a + function prop_RT_mint_redeem(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets1 = vault_mint(shares, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets1, _delta_); + } + + // mint(withdraw(a)) >= a + function prop_RT_withdraw_mint(address caller, uint assets) public { + vm.prank(caller); uint shares = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets, _delta_); + } + + // s = withdraw(a) + // s' = deposit(a) + // s' <= s + function prop_RT_withdraw_deposit(address caller, uint assets) public { + vm.prank(caller); uint shares1 = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares1, _delta_); + } + + // + // utils + // + + function vault_convertToShares(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToShares.selector, assets)); + } + function vault_convertToAssets(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToAssets.selector, shares)); + } + + function vault_maxDeposit(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxDeposit.selector, receiver)); + } + function vault_maxMint(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxMint.selector, receiver)); + } + function vault_maxWithdraw(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxWithdraw.selector, owner)); + } + function vault_maxRedeem(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxRedeem.selector, owner)); + } + + function vault_previewDeposit(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewDeposit.selector, assets)); + } + function vault_previewMint(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewMint.selector, shares)); + } + function vault_previewWithdraw(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewWithdraw.selector, assets)); + } + function vault_previewRedeem(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewRedeem.selector, shares)); + } + + function vault_deposit(uint assets, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.deposit.selector, assets, receiver)); + } + function vault_mint(uint shares, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.mint.selector, shares, receiver)); + } + function vault_withdraw(uint assets, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.withdraw.selector, assets, receiver, owner)); + } + function vault_redeem(uint shares, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.redeem.selector, shares, receiver, owner)); + } + + function _call_vault(bytes memory data) internal returns (uint) { + (bool success, bytes memory retdata) = _vault_.call(data); + if (success) return abi.decode(retdata, (uint)); + vm.assume(false); // if reverted, discard the current fuzz inputs, and let the fuzzer to start a new fuzz run + return 0; // silence warning + } + + function assertApproxGeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a >= b)) { + uint dt = b - a; + if (dt > maxDelta) { + emit log ("Error: a >=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } + + function assertApproxLeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a <= b)) { + uint dt = a - b; + if (dt > maxDelta) { + emit log ("Error: a <=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } +} diff --git a/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol b/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol new file mode 100644 index 0000000..6254a05 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/erc4626-tests/ERC4626.test.sol @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "./ERC4626.prop.sol"; + +interface IMockERC20 is IERC20 { + function mint(address to, uint value) external; + function burn(address from, uint value) external; +} + +abstract contract ERC4626Test is ERC4626Prop { + function setUp() public virtual; + + uint constant N = 4; + + struct Init { + address[N] user; + uint[N] share; + uint[N] asset; + int yield; + } + + // setup initial vault state as follows: + // + // totalAssets == sum(init.share) + init.yield + // totalShares == sum(init.share) + // + // init.user[i]'s assets == init.asset[i] + // init.user[i]'s shares == init.share[i] + function setUpVault(Init memory init) public virtual { + // setup initial shares and assets for individual users + for (uint i = 0; i < N; i++) { + address user = init.user[i]; + vm.assume(_isEOA(user)); + // shares + uint shares = init.share[i]; + try IMockERC20(_underlying_).mint(user, shares) {} catch { vm.assume(false); } + _approve(_underlying_, user, _vault_, shares); + vm.prank(user); try IERC4626(_vault_).deposit(shares, user) {} catch { vm.assume(false); } + // assets + uint assets = init.asset[i]; + try IMockERC20(_underlying_).mint(user, assets) {} catch { vm.assume(false); } + } + + // setup initial yield for vault + setUpYield(init); + } + + // setup initial yield + function setUpYield(Init memory init) public virtual { + if (init.yield >= 0) { // gain + uint gain = uint(init.yield); + try IMockERC20(_underlying_).mint(_vault_, gain) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } else { // loss + vm.assume(init.yield > type(int).min); // avoid overflow in conversion + uint loss = uint(-1 * init.yield); + try IMockERC20(_underlying_).burn(_vault_, loss) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } + } + + // + // asset + // + + function test_asset(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_asset(caller); + } + + function test_totalAssets(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_totalAssets(caller); + } + + // + // convert + // + + function test_convertToShares(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToShares(caller1, caller2, assets); + } + + function test_convertToAssets(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToAssets(caller1, caller2, shares); + } + + // + // deposit + // + + function test_maxDeposit(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxDeposit(caller, receiver); + } + + function test_previewDeposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewDeposit(caller, receiver, other, assets); + } + + function test_deposit(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_deposit(caller, receiver, assets); + } + + // + // mint + // + + function test_maxMint(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxMint(caller, receiver); + } + + function test_previewMint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewMint(caller, receiver, other, shares); + } + + function test_mint(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_mint(caller, receiver, shares); + } + + // + // withdraw + // + + function test_maxWithdraw(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxWithdraw(caller, owner); + } + + function test_previewWithdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewWithdraw(caller, receiver, owner, other, assets); + } + + function test_withdraw(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, allowance); + prop_withdraw(caller, receiver, owner, assets); + } + + function testFail_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + vm.assume(caller != owner); + vm.assume(assets > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); uint shares = IERC4626(_vault_).withdraw(assets, receiver, owner); + assertGt(shares, 0); // this assert is expected to fail + } + + // + // redeem + // + + function test_maxRedeem(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxRedeem(caller, owner); + } + + function test_previewRedeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewRedeem(caller, receiver, owner, other, shares); + } + + function test_redeem(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, allowance); + prop_redeem(caller, receiver, owner, shares); + } + + function testFail_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + vm.assume(caller != owner); + vm.assume(shares > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); IERC4626(_vault_).redeem(shares, receiver, owner); + } + + // + // round trip tests + // + + function test_RT_deposit_redeem(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_redeem(caller, assets); + } + + function test_RT_deposit_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_withdraw(caller, assets); + } + + function test_RT_redeem_deposit(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_deposit(caller, shares); + } + + function test_RT_redeem_mint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_mint(caller, shares); + } + + function test_RT_mint_withdraw(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_withdraw(caller, shares); + } + + function test_RT_mint_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_redeem(caller, shares); + } + + function test_RT_withdraw_mint(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_mint(caller, assets); + } + + function test_RT_withdraw_deposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_deposit(caller, assets); + } + + // + // utils + // + + function _isContract(address account) internal view returns (bool) { return account.code.length > 0; } + function _isEOA (address account) internal view returns (bool) { return account.code.length == 0; } + + function _approve(address token, address owner, address spender, uint amount) internal { + vm.prank(owner); _safeApprove(token, spender, 0); + vm.prank(owner); _safeApprove(token, spender, amount); + } + + function _safeApprove(address token, address spender, uint amount) internal { + (bool success, bytes memory retdata) = token.call(abi.encodeWithSelector(IERC20.approve.selector, spender, amount)); + vm.assume(success); + if (retdata.length > 0) vm.assume(abi.decode(retdata, (bool))); + } + + function _max_deposit(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_underlying_).balanceOf(from); + } + + function _max_mint(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToShares(IERC20(_underlying_).balanceOf(from)); + } + + function _max_withdraw(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToAssets(IERC20(_vault_).balanceOf(from)); // may be different from maxWithdraw(from) + } + + function _max_redeem(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_vault_).balanceOf(from); // may be different from maxRedeem(from) + } +} diff --git a/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE b/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/lib/openzeppelin-contracts/lib/erc4626-tests/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/lib/openzeppelin-contracts/lib/erc4626-tests/README.md b/lib/openzeppelin-contracts/lib/erc4626-tests/README.md new file mode 100644 index 0000000..651e443 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/erc4626-tests/README.md @@ -0,0 +1,116 @@ +# ERC4626 Property Tests + +Foundry (dapptools-style) property-based tests for [ERC4626] standard conformance. + +[ERC4626]: + +You can read our post on "_[Generalized property tests for ERC4626 vaults][post]_." + +[post]: + +## Overview + +#### What is it? +- Test suites for checking if the given ERC4626 implementation satisfies the **standard requirements**. +- Dapptools-style **property-based tests** for fuzzing or symbolic execution testing. +- Tests that are **independent** from implementation details, thus applicable for any ERC4626 vaults. + +#### What isn’t it? +- It does NOT test implementation-specific details, e.g., how to generate and distribute yields, how to compute the share price, etc. + +#### Testing properties: + +- **Round-trip properties**: no one can make a free profit by depositing and immediately withdrawing back and forth. + +- **Functional correctness**: the `deposit()`, `mint()`, `withdraw()`, and `redeem()` functions update the balance and allowance properly. + +- The `preview{Deposit,Redeem}()` functions **MUST NOT over-estimate** the exact amount.[^1] + +[^1]: That is, the `deposit()` and `redeem()` functions “MUST return the same or more amounts as their preview function if called in the same transaction.” + +- The `preview{Mint,Withdraw}()` functions **MUST NOT under-estimate** the exact amount.[^2] + +[^2]: That is, the `mint()` and `withdraw()` functions “MUST return the same or fewer amounts as their preview function if called in the same transaction.” + +- The `convertTo{Shares,Assets}` functions “**MUST NOT show any variations** depending on the caller.” + +- The `asset()`, `totalAssets()`, and `max{Deposit,Mint,Withdraw,Redeem}()` functions “**MUST NOT revert**.” + +## Usage + +**Step 0**: Install [foundry] and add [forge-std] in your vault repo: +```bash +$ curl -L https://foundry.paradigm.xyz | bash + +$ cd /path/to/your-erc4626-vault +$ forge install foundry-rs/forge-std +``` + +[foundry]: +[forge-std]: + +**Step 1**: Add this [erc4626-tests] as a dependency to your vault: +```bash +$ cd /path/to/your-erc4626-vault +$ forge install a16z/erc4626-tests +``` + +[erc4626-tests]: + +**Step 2**: Extend the abstract test contract [`ERC4626Test`](ERC4626.test.sol) with your own custom vault setup method, for example: + +```solidity +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "erc4626-tests/ERC4626.test.sol"; + +import { ERC20Mock } from "/path/to/mocks/ERC20Mock.sol"; +import { ERC4626Mock } from "/path/to/mocks/ERC4626Mock.sol"; + +contract ERC4626StdTest is ERC4626Test { + function setUp() public override { + _underlying_ = address(new ERC20Mock("Mock ERC20", "MERC20", 18)); + _vault_ = address(new ERC4626Mock(ERC20Mock(__underlying__), "Mock ERC4626", "MERC4626")); + _delta_ = 0; + _vaultMayBeEmpty = false; + _unlimitedAmount = false; + } +} +``` + +Specifically, set the state variables as follows: +- `_vault_`: the address of your ERC4626 vault. +- `_underlying_`: the address of the underlying asset of your vault. Note that the default `setupVault()` and `setupYield()` methods of `ERC4626Test` assume that it implements `mint(address to, uint value)` and `burn(address from, uint value)`. You can override the setup methods with your own if such `mint()` and `burn()` are not implemented. +- `_delta_`: the maximum approximation error size to be passed to [`assertApproxEqAbs()`]. It must be given as an absolute value (not a percentage) in the smallest unit (e.g., Wei or Satoshi). Note that all the tests are expected to pass with `__delta__ == 0` as long as your vault follows the [preferred rounding direction] as specified in the standard. If your vault doesn't follow the preferred rounding direction, you can set `__delta__` to a reasonable size of rounding errors where the adversarial profit of exploiting such rounding errors stays sufficiently small compared to the gas cost. (You can read our [post] for more about the adversarial profit.) +- `_vaultMayBeEmpty`: when set to false, fuzz inputs that empties the vault are ignored. +- `_unlimitedAmount`: when set to false, fuzz inputs are restricted to the currently available amount from the caller. Limiting the amount can speed up fuzzing, but may miss some edge cases. + +[`assertApproxEqAbs()`]: + +[preferred rounding direction]: + +**Step 3**: Run `forge test` + +``` +$ forge test +``` + +## Examples + +Below are examples of adding these property tests to existing ERC4626 vaults: +- [OpenZeppelin ERC4626] [[diff](https://github.com/daejunpark/openzeppelin-contracts/pull/1/files)] +- [Solmate ERC4626] [[diff](https://github.com/daejunpark/solmate/pull/1/files)] +- [Revenue Distribution Token] [[diff](https://github.com/daejunpark/revenue-distribution-token/pull/1/files)] +- [Yield Daddy ERC4626 wrappers] [[diff](https://github.com/daejunpark/yield-daddy/pull/1/files)][^bug] + +[OpenZeppelin ERC4626]: +[Solmate ERC4626]: +[Revenue Distribution Token]: +[Yield Daddy ERC4626 wrappers]: + +[^bug]: Our property tests indeed revealed an [issue](https://github.com/timeless-fi/yield-daddy/issues/7) in their eToken testing mock contract. The tests passed after it is [fixed](https://github.com/daejunpark/yield-daddy/commit/721cf4bd766805fd409455434aa5fd1a9b2df25c). + +## Disclaimer + +_These smart contracts are being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the user interface or the smart contracts. They have not been audited and as such there can be no assurance they will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. THE SMART CONTRACTS CONTAINED HEREIN ARE FURNISHED AS IS, WHERE IS, WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY, NON-INFRINGEMENT OR FITNESS FOR ANY PARTICULAR PURPOSE. Further, use of any of these smart contracts may be restricted or prohibited under applicable law, including securities laws, and it is therefore strongly advised for you to contact a reputable attorney in any jurisdiction where these smart contracts may be accessible for any questions or concerns with respect thereto. Further, no information provided in this repo should be construed as investment advice or legal advice for any particular facts or circumstances, and is not meant to replace competent counsel. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See a16z.com/disclosures for more info._ diff --git a/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml b/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..96b2336 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + # Backwards compatibility checks. + - name: Check compatibility with 0.8.0 + if: always() + run: forge build --skip test --use solc:0.8.0 + + - name: Check compatibility with 0.7.6 + if: always() + run: forge build --skip test --use solc:0.7.6 + + - name: Check compatibility with 0.7.0 + if: always() + run: forge build --skip test --use solc:0.7.0 + + - name: Check compatibility with 0.6.12 + if: always() + run: forge build --skip test --use solc:0.6.12 + + - name: Check compatibility with 0.6.2 + if: always() + run: forge build --skip test --use solc:0.6.2 + + # via-ir compilation time checks. + - name: Measure compilation time of Test with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTest.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of TestBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTestBase.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of Script with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScript.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of ScriptBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScriptBase.sol --use solc:0.8.17 --via-ir + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Run tests + run: forge test -vvv + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Check formatting + run: forge fmt --check diff --git a/lib/openzeppelin-contracts/lib/forge-std/.gitignore b/lib/openzeppelin-contracts/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/lib/openzeppelin-contracts/lib/forge-std/.gitmodules b/lib/openzeppelin-contracts/lib/forge-std/.gitmodules new file mode 100644 index 0000000..e124719 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ds-test"] + path = lib/ds-test + url = https://github.com/dapphub/ds-test diff --git a/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE b/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/LICENSE-APACHE @@ -0,0 +1,203 @@ +Copyright Contributors to Forge Standard Library + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT b/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright Contributors to Forge Standard Library + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER +DEALINGS IN THE SOFTWARE.R diff --git a/lib/openzeppelin-contracts/lib/forge-std/README.md b/lib/openzeppelin-contracts/lib/forge-std/README.md new file mode 100644 index 0000000..8494a7d --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/README.md @@ -0,0 +1,250 @@ +# Forge Standard Library • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml) + +Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes. + +**Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).** + +## Install + +```bash +forge install foundry-rs/forge-std +``` + +## Contracts +### stdError + +This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors. + +See the contract itself for all error codes. + +#### Example usage + +```solidity + +import "forge-std/Test.sol"; + +contract TestContract is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } +} + +contract ErrorsTest { + function arithmeticError(uint256 a) public { + uint256 a = a - 100; + } +} +``` + +### stdStorage + +This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`). + +This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth. + +I.e.: +```solidity +struct T { + // depth 0 + uint256 a; + // depth 1 + uint256 b; +} +``` + +#### Example usage + +```solidity +import "forge-std/Test.sol"; + +contract TestContract is Test { + using stdStorage for StdStorage; + + Storage test; + + function setUp() public { + test = new Storage(); + } + + function testFindExists() public { + // Lets say we want to find the slot for the public + // variable `exists`. We just pass in the function selector + // to the `find` command + uint256 slot = stdstore.target(address(test)).sig("exists()").find(); + assertEq(slot, 0); + } + + function testWriteExists() public { + // Lets say we want to write to the slot for the public + // variable `exists`. We just pass in the function selector + // to the `checked_write` command + stdstore.target(address(test)).sig("exists()").checked_write(100); + assertEq(test.exists(), 100); + } + + // It supports arbitrary storage layouts, like assembly based storage locations + function testFindHidden() public { + // `hidden` is a random hash of a bytes, iteration through slots would + // not find it. Our mechanism does + // Also, you can use the selector instead of a string + uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find(); + assertEq(slot, uint256(keccak256("my.random.var"))); + } + + // If targeting a mapping, you have to pass in the keys necessary to perform the find + // i.e.: + function testFindMapping() public { + uint256 slot = stdstore + .target(address(test)) + .sig(test.map_addr.selector) + .with_key(address(this)) + .find(); + // in the `Storage` constructor, we wrote that this address' value was 1 in the map + // so when we load the slot, we expect it to be 1 + assertEq(uint(vm.load(address(test), bytes32(slot))), 1); + } + + // If the target is a struct, you can specify the field depth: + function testFindStruct() public { + // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc. + uint256 slot_for_a_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(0) + .find(); + + uint256 slot_for_b_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(1) + .find(); + + assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1); + assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2); + } +} + +// A complex storage contract +contract Storage { + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + constructor() { + map_addr[msg.sender] = 1; + } + + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + // mapping(address => Packed) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basicStruct = UnpackedStruct({ + a: 1, + b: 2 + }); + + function hidden() public view returns (bytes32 t) { + // an extremely hidden storage slot + bytes32 slot = keccak256("my.random.var"); + assembly { + t := sload(slot) + } + } +} +``` + +### stdCheats + +This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you. + + +#### Example usage: +```solidity + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +// Inherit the stdCheats +contract StdCheatsTest is Test { + Bar test; + function setUp() public { + test = new Bar(); + } + + function testHoax() public { + // we call `hoax`, which gives the target address + // eth and then calls `prank` + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + + // overloaded to allow you to specify how much eth to + // initialize the address with + hoax(address(1337), 1); + test.bar{value: 1}(address(1337)); + } + + function testStartHoax() public { + // we call `startHoax`, which gives the target address + // eth and then calls `startPrank` + // + // it is also overloaded so that you can specify an eth amount + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } +} + +contract Bar { + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } +} +``` + +### Std Assertions + +Expand upon the assertion functions from the `DSTest` library. + +### `console.log` + +Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log). +It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console2.sol"; +... +console2.log(someValue); +``` + +If you need compatibility with Hardhat, you must use the standard `console.sol` instead. +Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console.sol"; +... +console.log(someValue); +``` + +## License + +Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/lib/openzeppelin-contracts/lib/forge-std/foundry.toml b/lib/openzeppelin-contracts/lib/forge-std/foundry.toml new file mode 100644 index 0000000..cca8301 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/foundry.toml @@ -0,0 +1,21 @@ +[profile.default] +fs_permissions = [{ access = "read-write", path = "./"}] + +[rpc_endpoints] +# The RPC URLs are modified versions of the default for testing initialization. +mainnet = "https://mainnet.infura.io/v3/7a8769b798b642f6933f2ed52042bd70" # Different API key. +optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash. +arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash. +needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}" + +[fmt] +# These are all the `forge fmt` defaults. +line_length = 120 +tab_width = 4 +bracket_spacing = false +int_types = 'long' +multiline_func_header = 'attributes_first' +quote_style = 'double' +number_underscore = 'preserve' +single_line_statement_blocks = 'preserve' +ignore = ["src/console.sol", "src/console2.sol"] \ No newline at end of file diff --git a/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/.gitignore b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/.gitignore new file mode 100644 index 0000000..63f0b2c --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/.gitignore @@ -0,0 +1,3 @@ +/.dapple +/build +/out diff --git a/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/LICENSE b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/Makefile b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/Makefile new file mode 100644 index 0000000..661dac4 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/Makefile @@ -0,0 +1,14 @@ +all:; dapp build + +test: + -dapp --use solc:0.4.23 build + -dapp --use solc:0.4.26 build + -dapp --use solc:0.5.17 build + -dapp --use solc:0.6.12 build + -dapp --use solc:0.7.5 build + +demo: + DAPP_SRC=demo dapp --use solc:0.7.5 build + -hevm dapp-test --verbose 3 + +.PHONY: test demo diff --git a/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/default.nix b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/default.nix new file mode 100644 index 0000000..cf65419 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/default.nix @@ -0,0 +1,4 @@ +{ solidityPackage, dappsys }: solidityPackage { + name = "ds-test"; + src = ./src; +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/demo/demo.sol b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/demo/demo.sol new file mode 100644 index 0000000..f3bb48e --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/demo/demo.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import "../src/test.sol"; + +contract DemoTest is DSTest { + function test_this() public pure { + require(true); + } + function test_logs() public { + emit log("-- log(string)"); + emit log("a string"); + + emit log("-- log_named_uint(string, uint)"); + emit log_named_uint("uint", 512); + + emit log("-- log_named_int(string, int)"); + emit log_named_int("int", -512); + + emit log("-- log_named_address(string, address)"); + emit log_named_address("address", address(this)); + + emit log("-- log_named_bytes32(string, bytes32)"); + emit log_named_bytes32("bytes32", "a string"); + + emit log("-- log_named_bytes(string, bytes)"); + emit log_named_bytes("bytes", hex"cafefe"); + + emit log("-- log_named_string(string, string)"); + emit log_named_string("string", "a string"); + + emit log("-- log_named_decimal_uint(string, uint, uint)"); + emit log_named_decimal_uint("decimal uint", 1.0e18, 18); + + emit log("-- log_named_decimal_int(string, int, uint)"); + emit log_named_decimal_int("decimal int", -1.0e18, 18); + } + event log_old_named_uint(bytes32,uint); + function test_old_logs() public { + emit log_old_named_uint("key", 500); + emit log_named_bytes32("bkey", "val"); + } + function test_trace() public view { + this.echo("string 1", "string 2"); + } + function test_multiline() public { + emit log("a multiline\\nstring"); + emit log("a multiline string"); + emit log_bytes("a string"); + emit log_bytes("a multiline\nstring"); + emit log_bytes("a multiline\\nstring"); + emit logs(hex"0000"); + emit log_named_bytes("0x0000", hex"0000"); + emit logs(hex"ff"); + } + function echo(string memory s1, string memory s2) public pure + returns (string memory, string memory) + { + return (s1, s2); + } + + function prove_this(uint x) public { + emit log_named_uint("sym x", x); + assertGt(x + 1, 0); + } + + function test_logn() public { + assembly { + log0(0x01, 0x02) + log1(0x01, 0x02, 0x03) + log2(0x01, 0x02, 0x03, 0x04) + log3(0x01, 0x02, 0x03, 0x04, 0x05) + } + } + + event MyEvent(uint, uint indexed, uint, uint indexed); + function test_events() public { + emit MyEvent(1, 2, 3, 4); + } + + function test_asserts() public { + string memory err = "this test has failed!"; + emit log("## assertTrue(bool)\n"); + assertTrue(false); + emit log("\n"); + assertTrue(false, err); + + emit log("\n## assertEq(address,address)\n"); + assertEq(address(this), msg.sender); + emit log("\n"); + assertEq(address(this), msg.sender, err); + + emit log("\n## assertEq32(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(uint,uint)\n"); + assertEq(uint(0), 1); + emit log("\n"); + assertEq(uint(0), 1, err); + + emit log("\n## assertEq(int,int)\n"); + assertEq(-1, -2); + emit log("\n"); + assertEq(-1, -2, err); + + emit log("\n## assertEqDecimal(int,int,uint)\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertEqDecimal(uint,uint,uint)\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGt(uint,uint)\n"); + assertGt(uint(0), 0); + emit log("\n"); + assertGt(uint(0), 0, err); + + emit log("\n## assertGt(int,int)\n"); + assertGt(-1, -1); + emit log("\n"); + assertGt(-1, -1, err); + + emit log("\n## assertGtDecimal(int,int,uint)\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGtDecimal(uint,uint,uint)\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGe(uint,uint)\n"); + assertGe(uint(0), 1); + emit log("\n"); + assertGe(uint(0), 1, err); + + emit log("\n## assertGe(int,int)\n"); + assertGe(-1, 0); + emit log("\n"); + assertGe(-1, 0, err); + + emit log("\n## assertGeDecimal(int,int,uint)\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGeDecimal(uint,uint,uint)\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertLt(uint,uint)\n"); + assertLt(uint(0), 0); + emit log("\n"); + assertLt(uint(0), 0, err); + + emit log("\n## assertLt(int,int)\n"); + assertLt(-1, -1); + emit log("\n"); + assertLt(-1, -1, err); + + emit log("\n## assertLtDecimal(int,int,uint)\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLtDecimal(uint,uint,uint)\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertLe(uint,uint)\n"); + assertLe(uint(1), 0); + emit log("\n"); + assertLe(uint(1), 0, err); + + emit log("\n## assertLe(int,int)\n"); + assertLe(0, -1); + emit log("\n"); + assertLe(0, -1, err); + + emit log("\n## assertLeDecimal(int,int,uint)\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLeDecimal(uint,uint,uint)\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertEq(string,string)\n"); + string memory s1 = "string 1"; + string memory s2 = "string 2"; + assertEq(s1, s2); + emit log("\n"); + assertEq(s1, s2, err); + + emit log("\n## assertEq0(bytes,bytes)\n"); + assertEq0(hex"abcdef01", hex"abcdef02"); + emit log("\n"); + assertEq0(hex"abcdef01", hex"abcdef02", err); + } +} + +contract DemoTestWithSetUp { + function setUp() public { + } + function test_pass() public pure { + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/package.json b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/package.json new file mode 100644 index 0000000..4802ada --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "ds-test", + "version": "1.0.0", + "description": "Assertions, equality checks and other test helpers ", + "bugs": "https://github.com/dapphub/ds-test/issues", + "license": "GPL-3.0", + "author": "Contributors to ds-test", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/dapphub/ds-test.git" + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/test.sol b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/test.sol new file mode 100644 index 0000000..515a3bd --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/test.sol @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.5.0; + +contract DSTest { + event log (string); + event logs (bytes); + + event log_address (address); + event log_bytes32 (bytes32); + event log_int (int); + event log_uint (uint); + event log_bytes (bytes); + event log_string (string); + + event log_named_address (string key, address val); + event log_named_bytes32 (string key, bytes32 val); + event log_named_decimal_int (string key, int val, uint decimals); + event log_named_decimal_uint (string key, uint val, uint decimals); + event log_named_int (string key, int val); + event log_named_uint (string key, uint val); + event log_named_bytes (string key, bytes val); + event log_named_string (string key, string val); + + bool public IS_TEST = true; + bool private _failed; + + address constant HEVM_ADDRESS = + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); + + modifier mayRevert() { _; } + modifier testopts(string memory) { _; } + + function failed() public returns (bool) { + if (_failed) { + return _failed; + } else { + bool globalFailed = false; + if (hasHEVMContext()) { + (, bytes memory retdata) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("load(address,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed")) + ) + ); + globalFailed = abi.decode(retdata, (bool)); + } + return globalFailed; + } + } + + function fail() internal { + if (hasHEVMContext()) { + (bool status, ) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("store(address,bytes32,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) + ) + ); + status; // Silence compiler warnings + } + _failed = true; + } + + function hasHEVMContext() internal view returns (bool) { + uint256 hevmCodeSize = 0; + assembly { + hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) + } + return hevmCodeSize > 0; + } + + modifier logs_gas() { + uint startGas = gasleft(); + _; + uint endGas = gasleft(); + emit log_named_uint("gas", startGas - endGas); + } + + function assertTrue(bool condition) internal { + if (!condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertTrue(bool condition, string memory err) internal { + if (!condition) { + emit log_named_string("Error", err); + assertTrue(condition); + } + } + + function assertEq(address a, address b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [address]"); + emit log_named_address(" Expected", b); + emit log_named_address(" Actual", a); + fail(); + } + } + function assertEq(address a, address b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes32 a, bytes32 b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [bytes32]"); + emit log_named_bytes32(" Expected", b); + emit log_named_bytes32(" Actual", a); + fail(); + } + } + function assertEq(bytes32 a, bytes32 b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + function assertEq32(bytes32 a, bytes32 b) internal { + assertEq(a, b); + } + function assertEq32(bytes32 a, bytes32 b, string memory err) internal { + assertEq(a, b, err); + } + + function assertEq(int a, int b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + function assertEq(int a, int b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEq(uint a, uint b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + function assertEq(uint a, uint b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEqDecimal(int a, int b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal int]"); + emit log_named_decimal_int(" Expected", b, decimals); + emit log_named_decimal_int(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + function assertEqDecimal(uint a, uint b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Expected", b, decimals); + emit log_named_decimal_uint(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + + function assertGt(uint a, uint b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGt(uint a, uint b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGt(int a, int b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGt(int a, int b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGtDecimal(int a, int b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + function assertGtDecimal(uint a, uint b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + + function assertGe(uint a, uint b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGe(uint a, uint b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGe(int a, int b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGe(int a, int b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGeDecimal(int a, int b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + function assertGeDecimal(uint a, uint b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertLt(uint a, uint b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLt(uint a, uint b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLt(int a, int b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLt(int a, int b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLtDecimal(int a, int b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + function assertLtDecimal(uint a, uint b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + + function assertLe(uint a, uint b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLe(uint a, uint b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLe(int a, int b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLe(int a, int b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLeDecimal(int a, int b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + function assertLeDecimal(uint a, uint b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log("Error: a == b not satisfied [string]"); + emit log_named_string(" Expected", b); + emit log_named_string(" Actual", a); + fail(); + } + } + function assertEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { + ok = true; + if (a.length == b.length) { + for (uint i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + ok = false; + } + } + } else { + ok = false; + } + } + function assertEq0(bytes memory a, bytes memory b) internal { + if (!checkEq0(a, b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + function assertEq0(bytes memory a, bytes memory b, string memory err) internal { + if (!checkEq0(a, b)) { + emit log_named_string("Error", err); + assertEq0(a, b); + } + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/package.json b/lib/openzeppelin-contracts/lib/forge-std/package.json new file mode 100644 index 0000000..a000ac8 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.2.0", + "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", + "homepage": "https://book.getfoundry.sh/forge/forge-std", + "bugs": "https://github.com/foundry-rs/forge-std/issues", + "license": "(Apache-2.0 OR MIT)", + "author": "Contributors to Forge Standard Library", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/foundry-rs/forge-std.git" + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol b/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..e0d8b05 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/Base.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {StdStorage} from "./StdStorage.sol"; +import {Vm, VmSafe} from "./Vm.sol"; + +abstract contract CommonBase { + // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. + address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + // console.sol and console2.sol work by executing a staticcall to this address. + address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; + // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38. + address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))); + // Address of the test contract, deployed by the DEFAULT_SENDER. + address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; + + uint256 internal constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + Vm internal constant vm = Vm(VM_ADDRESS); + StdStorage internal stdstore; +} + +abstract contract TestBase is CommonBase {} + +abstract contract ScriptBase is CommonBase { + // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol b/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..bffccad --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/Script.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Standard Library's default Script. + +// 🧩 MODULES +import {ScriptBase} from "./Base.sol"; +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheatsSafe} from "./StdCheats.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorageSafe} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {VmSafe} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {ScriptBase} from "./Base.sol"; + +// ⭐️ SCRIPT +abstract contract Script is StdChains, StdCheatsSafe, StdUtils, ScriptBase { + // Note: IS_SCRIPT() must return true. + bool public IS_SCRIPT = true; +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol b/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..733dbba --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {DSTest} from "ds-test/test.sol"; +import {stdMath} from "./StdMath.sol"; + +abstract contract StdAssertions is DSTest { + event log_array(uint256[] val); + event log_array(int256[] val); + event log_array(address[] val); + event log_named_array(string key, uint256[] val); + event log_named_array(string key, int256[] val); + event log_named_array(string key, address[] val); + + function fail(string memory err) internal virtual { + emit log_named_string("Error", err); + fail(); + } + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); + } + + function assertEq(bool a, bool b) internal virtual { + if (a != b) { + emit log("Error: a == b not satisfied [bool]"); + emit log_named_string(" Expected", b ? "true" : "false"); + emit log_named_string(" Actual", a ? "true" : "false"); + fail(); + } + } + + function assertEq(bool a, bool b, string memory err) internal virtual { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes memory a, bytes memory b) internal virtual { + assertEq0(a, b); + } + + function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { + assertEq0(a, b, err); + } + + function assertEq(uint256[] memory a, uint256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [uint[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(int256[] memory a, int256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [int[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(address[] memory a, address[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [address[]]"); + emit log_named_array(" Expected", b); + emit log_named_array(" Actual", a); + fail(); + } + } + + function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + // Legacy helper + function assertEqUint(uint256 a, uint256 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the expected is 0, actual must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol b/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..68755bf --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/StdChains.sol @@ -0,0 +1,189 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +/** + * StdChains provides information about EVM compatible chains that can be used in scripts/tests. + * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are + * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of + * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the + * alias used in this contract, which can be found as the first argument to the + * `setChainWithDefaultRpcUrl` call in the `initialize` function. + * + * There are two main ways to use this contract: + * 1. Set a chain with `setChain(string memory chainAlias, Chain memory chain)` + * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. + * + * The first time either of those are used, chains are initialized with the default set of RPC URLs. + * This is done in `initialize`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in + * `defaultRpcUrls`. + * + * The `setChain` function is straightforward, and it simply saves off the given chain data. + * + * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say + * we want to retrieve `mainnet`'s RPC URL: + * - If you haven't set any mainnet chain info with `setChain` and you haven't specified that + * chain in `foundry.toml`, the default data and RPC URL will be returned. + * - If you have set a mainnet RPC URL in `foundry.toml` it will return that, if valid (e.g. if + * a URL is given or if an environment variable is given and that environment variable exists). + * Otherwise, the default data is returned. + * - If you specified data with `setChain` it will return that. + * + * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> defaults. + */ +abstract contract StdChains { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private initialized; + + struct Chain { + // The chain name. + string name; + // The chain's Chain ID. + uint256 chainId; + // A default RPC endpoint for this chain. + // NOTE: This default RPC URL is included for convenience to facilitate quick tests and + // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy + // usage as you will be throttled and this is a disservice to others who need this endpoint. + string rpcUrl; + } + + // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data. + mapping(string => Chain) private chains; + // Maps from the chain's alias to it's default RPC URL. + mapping(string => string) private defaultRpcUrls; + // Maps from a chain ID to it's alias. + mapping(uint256 => string) private idToAlias; + + // The RPC URL will be fetched from config or defaultRpcUrls if possible. + function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) { + require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string."); + + initialize(); + chain = chains[chainAlias]; + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + function getChain(uint256 chainId) internal virtual returns (Chain memory chain) { + require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0."); + initialize(); + string memory chainAlias = idToAlias[chainId]; + + chain = chains[chainAlias]; + + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, Chain memory chain) internal virtual { + require( + bytes(chainAlias).length != 0, "StdChains setChain(string,Chain): Chain alias cannot be the empty string." + ); + + require(chain.chainId != 0, "StdChains setChain(string,Chain): Chain ID cannot be 0."); + + initialize(); + string memory foundAlias = idToAlias[chain.chainId]; + + require( + bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)), + string( + abi.encodePacked( + "StdChains setChain(string,Chain): Chain ID ", + vm.toString(chain.chainId), + " already used by \"", + foundAlias, + "\"." + ) + ) + ); + + uint256 oldChainId = chains[chainAlias].chainId; + delete idToAlias[oldChainId]; + + chains[chainAlias] = chain; + idToAlias[chain.chainId] = chainAlias; + } + + // lookup rpcUrl, in descending order of priority: + // current -> config (foundry.toml) -> default + function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) + private + view + returns (Chain memory) + { + if (bytes(chain.rpcUrl).length == 0) { + try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) { + chain.rpcUrl = configRpcUrl; + } catch (bytes memory err) { + chain.rpcUrl = defaultRpcUrls[chainAlias]; + // distinguish 'not found' from 'cannot read' + bytes memory notFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + if (keccak256(notFoundError) != keccak256(err) || bytes(chain.rpcUrl).length == 0) { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, err), mload(err)) + } + } + } + } + return chain; + } + + function initialize() private { + if (initialized) return; + + initialized = true; + + // If adding an RPC here, make sure to test the default RPC URL in `testRpcs` + setChainWithDefaultRpcUrl("anvil", Chain("Anvil", 31337, "http://127.0.0.1:8545")); + setChainWithDefaultRpcUrl( + "mainnet", Chain("Mainnet", 1, "https://mainnet.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl( + "goerli", Chain("Goerli", 5, "https://goerli.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl( + "sepolia", Chain("Sepolia", 11155111, "https://sepolia.infura.io/v3/6770454bc6ea42c58aac12978531b93f") + ); + setChainWithDefaultRpcUrl("optimism", Chain("Optimism", 10, "https://mainnet.optimism.io")); + setChainWithDefaultRpcUrl("optimism_goerli", Chain("Optimism Goerli", 420, "https://goerli.optimism.io")); + setChainWithDefaultRpcUrl("arbitrum_one", Chain("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl( + "arbitrum_one_goerli", Chain("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc") + ); + setChainWithDefaultRpcUrl("arbitrum_nova", Chain("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl("polygon", Chain("Polygon", 137, "https://polygon-rpc.com")); + setChainWithDefaultRpcUrl("polygon_mumbai", Chain("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com")); + setChainWithDefaultRpcUrl("avalanche", Chain("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc")); + setChainWithDefaultRpcUrl( + "avalanche_fuji", Chain("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc") + ); + setChainWithDefaultRpcUrl("bnb_smart_chain", Chain("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org")); + setChainWithDefaultRpcUrl("bnb_smart_chain_testnet", Chain("BNB Smart Chain Testnet", 97, "https://data-seed-prebsc-1-s1.binance.org:8545"));// forgefmt: disable-line + setChainWithDefaultRpcUrl("gnosis_chain", Chain("Gnosis Chain", 100, "https://rpc.gnosischain.com")); + } + + // set chain info, with priority to chainAlias' rpc url in foundry.toml + function setChainWithDefaultRpcUrl(string memory chainAlias, Chain memory chain) private { + string memory rpcUrl = chain.rpcUrl; + defaultRpcUrls[chainAlias] = rpcUrl; + chain.rpcUrl = ""; + setChain(chainAlias, chain); + chain.rpcUrl = rpcUrl; // restore argument + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol b/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..f7204a5 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/StdCheats.sol @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {Vm} from "./Vm.sol"; + +abstract contract StdCheatsSafe { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private gasMeteringOff; + + // Data structures to parse Transaction objects from the broadcast artifact + // that conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawTx1559 { + string[] arguments; + address contractAddress; + string contractName; + // json value name = function + string functionSig; + bytes32 hash; + // json value name = tx + RawTx1559Detail txDetail; + // json value name = type + string opcode; + } + + struct RawTx1559Detail { + AccessList[] accessList; + bytes data; + address from; + bytes gas; + bytes nonce; + address to; + bytes txType; + bytes value; + } + + struct Tx1559 { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + bytes32 hash; + Tx1559Detail txDetail; + string opcode; + } + + struct Tx1559Detail { + AccessList[] accessList; + bytes data; + address from; + uint256 gas; + uint256 nonce; + address to; + uint256 txType; + uint256 value; + } + + // Data structures to parse Transaction objects from the broadcast artifact + // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct TxLegacy { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + string hash; + string opcode; + TxDetailLegacy transaction; + } + + struct TxDetailLegacy { + AccessList[] accessList; + uint256 chainId; + bytes data; + address from; + uint256 gas; + uint256 gasPrice; + bytes32 hash; + uint256 nonce; + bytes1 opcode; + bytes32 r; + bytes32 s; + uint256 txType; + address to; + uint8 v; + uint256 value; + } + + struct AccessList { + address accessAddress; + bytes32[] storageKeys; + } + + // Data structures to parse Receipt objects from the broadcast artifact. + // The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawReceipt { + bytes32 blockHash; + bytes blockNumber; + address contractAddress; + bytes cumulativeGasUsed; + bytes effectiveGasPrice; + address from; + bytes gasUsed; + RawReceiptLog[] logs; + bytes logsBloom; + bytes status; + address to; + bytes32 transactionHash; + bytes transactionIndex; + } + + struct Receipt { + bytes32 blockHash; + uint256 blockNumber; + address contractAddress; + uint256 cumulativeGasUsed; + uint256 effectiveGasPrice; + address from; + uint256 gasUsed; + ReceiptLog[] logs; + bytes logsBloom; + uint256 status; + address to; + bytes32 transactionHash; + uint256 transactionIndex; + } + + // Data structures to parse the entire broadcast artifact, assuming the + // transactions conform to EIP1559. + + struct EIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + Receipt[] receipts; + uint256 timestamp; + Tx1559[] transactions; + TxReturn[] txReturns; + } + + struct RawEIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + RawReceipt[] receipts; + TxReturn[] txReturns; + uint256 timestamp; + RawTx1559[] transactions; + } + + struct RawReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + bytes blockNumber; + bytes data; + bytes logIndex; + bool removed; + bytes32[] topics; + bytes32 transactionHash; + bytes transactionIndex; + bytes transactionLogIndex; + } + + struct ReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + uint256 blockNumber; + bytes data; + uint256 logIndex; + bytes32[] topics; + uint256 transactionIndex; + uint256 transactionLogIndex; + bool removed; + } + + struct TxReturn { + string internalType; + string value; + } + + function assumeNoPrecompiles(address addr) internal virtual { + // Assembly required since `block.chainid` was introduced in 0.8.0. + uint256 chainId; + assembly { + chainId := chainid() + } + assumeNoPrecompiles(addr, chainId); + } + + function assumeNoPrecompiles(address addr, uint256 chainId) internal virtual { + // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific + // address), but the same rationale for excluding them applies so we include those too. + + // These should be present on all EVM-compatible chains. + vm.assume(addr < address(0x1) || addr > address(0x9)); + + // forgefmt: disable-start + if (chainId == 10 || chainId == 420) { + // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21 + vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800)); + } else if (chainId == 42161 || chainId == 421613) { + // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains + vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068)); + } else if (chainId == 43114 || chainId == 43113) { + // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59 + vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff)); + vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF)); + vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff)); + } + // forgefmt: disable-end + } + + function readEIP1559ScriptArtifact(string memory path) + internal + view + virtual + returns (EIP1559ScriptArtifact memory) + { + string memory data = vm.readFile(path); + bytes memory parsedData = vm.parseJson(data); + RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact)); + EIP1559ScriptArtifact memory artifact; + artifact.libraries = rawArtifact.libraries; + artifact.path = rawArtifact.path; + artifact.timestamp = rawArtifact.timestamp; + artifact.pending = rawArtifact.pending; + artifact.txReturns = rawArtifact.txReturns; + artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts); + artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions); + return artifact; + } + + function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) { + Tx1559[] memory txs = new Tx1559[](rawTxs.length); + for (uint256 i; i < rawTxs.length; i++) { + txs[i] = rawToConvertedEIPTx1559(rawTxs[i]); + } + return txs; + } + + function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) { + Tx1559 memory transaction; + transaction.arguments = rawTx.arguments; + transaction.contractName = rawTx.contractName; + transaction.functionSig = rawTx.functionSig; + transaction.hash = rawTx.hash; + transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail); + transaction.opcode = rawTx.opcode; + return transaction; + } + + function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail) + internal + pure + virtual + returns (Tx1559Detail memory) + { + Tx1559Detail memory txDetail; + txDetail.data = rawDetail.data; + txDetail.from = rawDetail.from; + txDetail.to = rawDetail.to; + txDetail.nonce = _bytesToUint(rawDetail.nonce); + txDetail.txType = _bytesToUint(rawDetail.txType); + txDetail.value = _bytesToUint(rawDetail.value); + txDetail.gas = _bytesToUint(rawDetail.gas); + txDetail.accessList = rawDetail.accessList; + return txDetail; + } + + function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions"); + RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[])); + return rawToConvertedEIPTx1559s(rawTxs); + } + + function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559)); + return rawToConvertedEIPTx1559(rawTx); + } + + // Analogous to readTransactions, but for receipts. + function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts"); + RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[])); + return rawToConvertedReceipts(rawReceipts); + } + + function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt)); + return rawToConvertedReceipt(rawReceipt); + } + + function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) { + Receipt[] memory receipts = new Receipt[](rawReceipts.length); + for (uint256 i; i < rawReceipts.length; i++) { + receipts[i] = rawToConvertedReceipt(rawReceipts[i]); + } + return receipts; + } + + function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) { + Receipt memory receipt; + receipt.blockHash = rawReceipt.blockHash; + receipt.to = rawReceipt.to; + receipt.from = rawReceipt.from; + receipt.contractAddress = rawReceipt.contractAddress; + receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice); + receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed); + receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed); + receipt.status = _bytesToUint(rawReceipt.status); + receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex); + receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber); + receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs); + receipt.logsBloom = rawReceipt.logsBloom; + receipt.transactionHash = rawReceipt.transactionHash; + return receipt; + } + + function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs) + internal + pure + virtual + returns (ReceiptLog[] memory) + { + ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length); + for (uint256 i; i < rawLogs.length; i++) { + logs[i].logAddress = rawLogs[i].logAddress; + logs[i].blockHash = rawLogs[i].blockHash; + logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber); + logs[i].data = rawLogs[i].data; + logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex); + logs[i].topics = rawLogs[i].topics; + logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex); + logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex); + logs[i].removed = rawLogs[i].removed; + } + return logs; + } + + // Deploy a contract by fetching the contract bytecode from + // the artifacts directory + // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))` + function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed."); + } + + function deployCode(string memory what) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string): Deployment failed."); + } + + /// @dev deploy contract with value on construction + function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed."); + } + + function deployCode(string memory what, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed."); + } + + // creates a labeled address and the corresponding private key + function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) { + privateKey = uint256(keccak256(abi.encodePacked(name))); + addr = vm.addr(privateKey); + vm.label(addr, name); + } + + // creates a labeled address + function makeAddr(string memory name) internal virtual returns (address addr) { + (addr,) = makeAddrAndKey(name); + } + + function deriveRememberKey(string memory mnemonic, uint32 index) + internal + virtual + returns (address who, uint256 privateKey) + { + privateKey = vm.deriveKey(mnemonic, index); + who = vm.rememberKey(privateKey); + } + + function _bytesToUint(bytes memory b) private pure returns (uint256) { + require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function isFork() internal virtual returns (bool status) { + try vm.activeFork() { + status = true; + } catch (bytes memory) {} + } + + modifier skipWhenForking() { + if (!isFork()) { + _; + } + } + + modifier skipWhenNotForking() { + if (isFork()) { + _; + } + } + + modifier noGasMetering() { + vm.pauseGasMetering(); + // To prevent turning gas monitoring back on with nested functions that use this modifier, + // we check if gasMetering started in the off position. If it did, we don't want to turn + // it back on until we exit the top level function that used the modifier + // + // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well. + // funcA will have `gasStartedOff` as false, funcB will have it as true, + // so we only turn metering back on at the end of the funcA + bool gasStartedOff = gasMeteringOff; + gasMeteringOff = true; + + _; + + // if gas metering was on when this modifier was called, turn it back on at the end + if (!gasStartedOff) { + gasMeteringOff = false; + vm.resumeGasMetering(); + } + } +} + +// Wrappers around cheatcodes to avoid footguns +abstract contract StdCheats is StdCheatsSafe { + using stdStorage for StdStorage; + + StdStorage private stdstore; + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + // Skip forward or rewind time by the specified number of seconds + function skip(uint256 time) internal virtual { + vm.warp(block.timestamp + time); + } + + function rewind(uint256 time) internal virtual { + vm.warp(block.timestamp - time); + } + + // Setup a prank from an address that has some ether + function hoax(address who) internal virtual { + vm.deal(who, 1 << 128); + vm.prank(who); + } + + function hoax(address who, uint256 give) internal virtual { + vm.deal(who, give); + vm.prank(who); + } + + function hoax(address who, address origin) internal virtual { + vm.deal(who, 1 << 128); + vm.prank(who, origin); + } + + function hoax(address who, address origin, uint256 give) internal virtual { + vm.deal(who, give); + vm.prank(who, origin); + } + + // Start perpetual prank from an address that has some ether + function startHoax(address who) internal virtual { + vm.deal(who, 1 << 128); + vm.startPrank(who); + } + + function startHoax(address who, uint256 give) internal virtual { + vm.deal(who, give); + vm.startPrank(who); + } + + // Start perpetual prank from an address that has some ether + // tx.origin is set to the origin parameter + function startHoax(address who, address origin) internal virtual { + vm.deal(who, 1 << 128); + vm.startPrank(who, origin); + } + + function startHoax(address who, address origin, uint256 give) internal virtual { + vm.deal(who, give); + vm.startPrank(who, origin); + } + + function changePrank(address who) internal virtual { + vm.stopPrank(); + vm.startPrank(who); + } + + // The same as Vm's `deal` + // Use the alternative signature for ERC20 tokens + function deal(address to, uint256 give) internal virtual { + vm.deal(to, give); + } + + // Set the balance of an account for any ERC20 token + // Use the alternative signature to update `totalSupply` + function deal(address token, address to, uint256 give) internal virtual { + deal(token, to, give, false); + } + + function deal(address token, address to, uint256 give, bool adjust) internal virtual { + // get current balance + (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to)); + uint256 prevBal = abi.decode(balData, (uint256)); + + // update balance + stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give); + + // update total supply + if (adjust) { + (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd)); + uint256 totSup = abi.decode(totSupData, (uint256)); + if (give < prevBal) { + totSup -= (prevBal - give); + } else { + totSup += (give - prevBal); + } + stdstore.target(token).sig(0x18160ddd).checked_write(totSup); + } + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol b/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/StdError.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test +pragma solidity >=0.6.2 <0.9.0; + +library stdError { + bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); + bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); + bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); + bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); + bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); + bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); + bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); + bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); + bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol b/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..2dee471 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/StdJson.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +// Helpers for parsing and writing JSON files +// To parse: +// ``` +// using stdJson for string; +// string memory json = vm.readFile("some_peth"); +// json.parseUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "deploymentArtifact"; +// Contract contract = new Contract(); +// json.serialize("contractAddress", address(contract)); +// json = json.serialize("deploymentTimes", uint(1)); +// // store the stringified JSON to the 'json' variable we have been using as a key +// // as we won't need it any longer +// string memory json2 = "finalArtifact"; +// string memory final = json2.serialize("depArtifact", json); +// final.write(""); +// ``` + +library stdJson { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) { + return vm.parseJson(json, key); + } + + function readUint(string memory json, string memory key) internal pure returns (uint256) { + return abi.decode(vm.parseJson(json, key), (uint256)); + } + + function readUintArray(string memory json, string memory key) internal pure returns (uint256[] memory) { + return abi.decode(vm.parseJson(json, key), (uint256[])); + } + + function readInt(string memory json, string memory key) internal pure returns (int256) { + return abi.decode(vm.parseJson(json, key), (int256)); + } + + function readIntArray(string memory json, string memory key) internal pure returns (int256[] memory) { + return abi.decode(vm.parseJson(json, key), (int256[])); + } + + function readBytes32(string memory json, string memory key) internal pure returns (bytes32) { + return abi.decode(vm.parseJson(json, key), (bytes32)); + } + + function readBytes32Array(string memory json, string memory key) internal pure returns (bytes32[] memory) { + return abi.decode(vm.parseJson(json, key), (bytes32[])); + } + + function readString(string memory json, string memory key) internal pure returns (string memory) { + return abi.decode(vm.parseJson(json, key), (string)); + } + + function readStringArray(string memory json, string memory key) internal pure returns (string[] memory) { + return abi.decode(vm.parseJson(json, key), (string[])); + } + + function readAddress(string memory json, string memory key) internal pure returns (address) { + return abi.decode(vm.parseJson(json, key), (address)); + } + + function readAddressArray(string memory json, string memory key) internal pure returns (address[] memory) { + return abi.decode(vm.parseJson(json, key), (address[])); + } + + function readBool(string memory json, string memory key) internal pure returns (bool) { + return abi.decode(vm.parseJson(json, key), (bool)); + } + + function readBoolArray(string memory json, string memory key) internal pure returns (bool[] memory) { + return abi.decode(vm.parseJson(json, key), (bool[])); + } + + function readBytes(string memory json, string memory key) internal pure returns (bytes memory) { + return abi.decode(vm.parseJson(json, key), (bytes)); + } + + function readBytesArray(string memory json, string memory key) internal pure returns (bytes[] memory) { + return abi.decode(vm.parseJson(json, key), (bytes[])); + } + + function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bool[] memory value) + internal + returns (string memory) + { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256[] memory value) + internal + returns (string memory) + { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256[] memory value) + internal + returns (string memory) + { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address[] memory value) + internal + returns (string memory) + { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string[] memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function write(string memory jsonKey, string memory path) internal { + vm.writeJson(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeJson(jsonKey, path, valueKey); + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol b/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/StdMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +library stdMath { + int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; + + function abs(int256 a) internal pure returns (uint256) { + // Required or it will fail when `a = type(int256).min` + if (a == INT256_MIN) { + return 57896044618658097711785492504343953926634992332820282019728792003956564819968; + } + + return uint256(a > 0 ? a : -a); + } + + function delta(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a - b : b - a; + } + + function delta(int256 a, int256 b) internal pure returns (uint256) { + // a and b are of the same sign + // this works thanks to two's complement, the left-most bit is the sign bit + if ((a ^ b) > -1) { + return delta(abs(a), abs(b)); + } + + // a and b are of opposite signs + return abs(a) + abs(b); + } + + function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + + return absDelta * 1e18 / b; + } + + function percentDelta(int256 a, int256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + uint256 absB = abs(b); + + return absDelta * 1e18 / absB; + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol b/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..b0bfc00 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; + mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; +} + +library stdStorageSafe { + event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot); + event WARNING_UninitedSlot(address who, uint256 slot); + + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against + // slot complexity: + // if flat, will be bytes32(uint256(uint)); + // if map, will be keccak256(abi.encode(key, uint(slot))); + // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot))))); + // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); + function find(StdStorage storage self) internal returns (uint256) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + vm.record(); + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + (bytes32[] memory reads,) = vm.accesses(address(who)); + if (reads.length == 1) { + bytes32 curr = vm.load(who, reads[0]); + if (curr == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[0])); + } + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + } else if (reads.length > 1) { + for (uint256 i = 0; i < reads.length; i++) { + bytes32 prev = vm.load(who, reads[i]); + if (prev == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[i])); + } + // store + vm.store(who, reads[i], bytes32(hex"1337")); + bool success; + bytes memory rdat; + { + (success, rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + if (success && fdat == bytes32(hex"1337")) { + // we found which of the slots is the actual one + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + vm.store(who, reads[i], prev); + break; + } + vm.store(who, reads[i], prev); + } + } else { + require(false, "stdStorage find(StdStorage): No storage use detected for target."); + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], + "stdStorage find(StdStorage): Slot(s) not found." + ); + + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + self._target = _target; + return self; + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + self._sig = _sig; + return self; + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + self._sig = sigs(_sig); + return self; + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + self._keys.push(bytes32(uint256(uint160(who)))); + return self; + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + self._keys.push(bytes32(amt)); + return self; + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + self._keys.push(key); + return self; + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + self._depth = _depth; + return self; + } + + function read(StdStorage storage self) private returns (bytes memory) { + address t = self._target; + uint256 s = find(self); + return abi.encode(vm.load(t, bytes32(s))); + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return abi.decode(read(self), (bytes32)); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + int256 v = read_int(self); + if (v == 0) return false; + if (v == 1) return true; + revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + } + + function read_address(StdStorage storage self) internal returns (address) { + return abi.decode(read(self), (address)); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return abi.decode(read(self), (uint256)); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return abi.decode(read(self), (int256)); + } + + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} + +library stdStorage { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return stdStorageSafe.sigs(sigStr); + } + + function find(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.find(self); + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + return stdStorageSafe.target(self, _target); + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, who); + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, amt); + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, key); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function checked_write(StdStorage storage self, address who) internal { + checked_write(self, bytes32(uint256(uint160(who)))); + } + + function checked_write(StdStorage storage self, uint256 amt) internal { + checked_write(self, bytes32(amt)); + } + + function checked_write(StdStorage storage self, bool write) internal { + bytes32 t; + /// @solidity memory-safe-assembly + assembly { + t := write + } + checked_write(self, t); + } + + function checked_write(StdStorage storage self, bytes32 set) internal { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + find(self); + } + bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]); + + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + bytes32 curr = vm.load(who, slot); + + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + vm.store(who, slot, set); + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return stdStorageSafe.read_bytes32(self); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + return stdStorageSafe.read_bool(self); + } + + function read_address(StdStorage storage self) internal returns (address) { + return stdStorageSafe.read_address(self); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.read_uint(self); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return stdStorageSafe.read_int(self); + } + + // Private function so needs to be copied over + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + // Private function so needs to be copied over + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol b/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..a283e75 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// TODO Remove import. +import {VmSafe} from "./Vm.sol"; + +abstract contract StdUtils { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; + + uint256 private constant INT256_MIN_ABS = + 57896044618658097711785492504343953926634992332820282019728792003956564819968; + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { + require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); + // If x is between min and max, return x directly. This is to ensure that dictionary values + // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 + if (x >= min && x <= max) return x; + + uint256 size = max - min + 1; + + // If the value is 0, 1, 2, 3, warp that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. + // This helps ensure coverage of the min/max values. + if (x <= 3 && size > x) return min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); + + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. + if (x > max) { + uint256 diff = x - max; + uint256 rem = diff % size; + if (rem == 0) return max; + result = min + rem - 1; + } else if (x < min) { + uint256 diff = min - x; + uint256 rem = diff % size; + if (rem == 0) return min; + result = max - rem + 1; + } + } + + function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log("Bound Result", result); + } + + function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) { + require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min."); + + // Shifting all int256 values to uint256 to use _bound function. The range of two types are: + // int256 : -(2**255) ~ (2**255 - 1) + // uint256: 0 ~ (2**256 - 1) + // So, add 2**255, INT256_MIN_ABS to the integer values. + // + // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow. + // So, use `~uint256(x) + 1` instead. + uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS); + uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS); + uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS); + + uint256 y = _bound(_x, _min, _max); + + // To move it back to int256 value, subtract INT256_MIN_ABS at here. + result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS); + console2_log("Bound result", vm.toString(result)); + } + + /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce + /// @notice adapated from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) + function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { + // forgefmt: disable-start + // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0. + // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it. + if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80)))); + if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce)))); + + // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length. + if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce)))); + if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce)))); + if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce)))); + // forgefmt: disable-end + + // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp + // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) + // We assume nobody can have a nonce large enough to require more than 32 bytes. + return addressFromLast20Bytes( + keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))) + ); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash))); + } + + function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { + require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { + return address(uint160(uint256(bytesValue))); + } + + // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere. + + function console2_log(string memory p0, uint256 p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + status; + } + + function console2_log(string memory p0, string memory p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1)); + status; + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol b/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..6c26230 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/Test.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Standard Library's default Test + +// 🧩 MODULES +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {StdAssertions} from "./StdAssertions.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheats} from "./StdCheats.sol"; +import {stdError} from "./StdError.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; +import {DSTest} from "ds-test/test.sol"; + +// ⭐️ TEST +abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdUtils, TestBase { +// Note: IS_TEST() must return true. +// Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76. +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol b/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..6ebde70 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/Vm.sol @@ -0,0 +1,385 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// Cheatcodes are marked as view/pure/none using the following rules: +// 0. A call's observable behaviour includes its return value, logs, reverts and state writes, +// 1. If you can influence a later call's observable behaviour, you're neither `view` nor `pure (you are modifying some state be it the EVM, interpreter, filesystem, etc), +// 2. Otherwise if you can be influenced by an earlier call, or if reading some state, you're `view`, +// 3. Otherwise you're `pure`. + +interface VmSafe { + struct Log { + bytes32[] topics; + bytes data; + address emitter; + } + + struct Rpc { + string key; + string url; + } + + struct FsMetadata { + bool isDir; + bool isSymlink; + uint256 length; + bool readOnly; + uint256 modified; + uint256 accessed; + uint256 created; + } + + // Loads a storage slot from an address + function load(address target, bytes32 slot) external view returns (bytes32 data); + // Signs data + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + // Gets the address for a given private key + function addr(uint256 privateKey) external pure returns (address addr); + // Gets the nonce of an account + function getNonce(address account) external view returns (uint64 nonce); + // Performs a foreign function call via the terminal + function ffi(string[] calldata commandInput) external returns (bytes memory result); + // Sets environment variables + function setEnv(string calldata name, string calldata value) external; + // Reads environment variables, (name) => (value) + function envBool(string calldata name) external view returns (bool value); + function envUint(string calldata name) external view returns (uint256 value); + function envInt(string calldata name) external view returns (int256 value); + function envAddress(string calldata name) external view returns (address value); + function envBytes32(string calldata name) external view returns (bytes32 value); + function envString(string calldata name) external view returns (string memory value); + function envBytes(string calldata name) external view returns (bytes memory value); + // Reads environment variables as arrays + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + // Read environment variables with default value + function envOr(string calldata name, bool defaultValue) external returns (bool value); + function envOr(string calldata name, uint256 defaultValue) external returns (uint256 value); + function envOr(string calldata name, int256 defaultValue) external returns (int256 value); + function envOr(string calldata name, address defaultValue) external returns (address value); + function envOr(string calldata name, bytes32 defaultValue) external returns (bytes32 value); + function envOr(string calldata name, string calldata defaultValue) external returns (string memory value); + function envOr(string calldata name, bytes calldata defaultValue) external returns (bytes memory value); + // Read environment variables as arrays with default value + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + returns (bool[] memory value); + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + returns (uint256[] memory value); + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + returns (int256[] memory value); + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + returns (address[] memory value); + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + returns (bytes32[] memory value); + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + returns (string[] memory value); + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + returns (bytes[] memory value); + // Records all storage reads and writes + function record() external; + // Gets all accessed reads and write slot from a recording session, for a given address + function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots); + // Gets the _creation_ bytecode from an artifact file. Takes in the relative path to the json file + function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode); + // Gets the _deployed_ bytecode from an artifact file. Takes in the relative path to the json file + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + // Labels an address in call traces + function label(address account, string calldata newLabel) external; + // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain + function broadcast() external; + // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain + function broadcast(address signer) external; + // Has the next call (at this call depth only) create a transaction with the private key provided as the sender that can later be signed and sent onchain + function broadcast(uint256 privateKey) external; + // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain + function startBroadcast() external; + // Has all subsequent calls (at this call depth only) create transactions with the address provided that can later be signed and sent onchain + function startBroadcast(address signer) external; + // Has all subsequent calls (at this call depth only) create transactions with the private key provided that can later be signed and sent onchain + function startBroadcast(uint256 privateKey) external; + // Stops collecting onchain transactions + function stopBroadcast() external; + // Reads the entire content of file to string + function readFile(string calldata path) external view returns (string memory data); + // Reads the entire content of file as binary. Path is relative to the project root. + function readFileBinary(string calldata path) external view returns (bytes memory data); + // Get the path of the current project root + function projectRoot() external view returns (string memory path); + // Get the metadata for a file/directory + function fsMetadata(string calldata fileOrDir) external returns (FsMetadata memory metadata); + // Reads next line of file to string + function readLine(string calldata path) external view returns (string memory line); + // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does. + function writeFile(string calldata path, string calldata data) external; + // Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does. + // Path is relative to the project root. + function writeFileBinary(string calldata path, bytes calldata data) external; + // Writes line to file, creating a file if it does not exist. + function writeLine(string calldata path, string calldata data) external; + // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine. + function closeFile(string calldata path) external; + // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases: + // - Path points to a directory. + // - The file doesn't exist. + // - The user lacks permissions to remove the file. + function removeFile(string calldata path) external; + // Convert values to a string + function toString(address value) external pure returns (string memory stringifiedValue); + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + function toString(bool value) external pure returns (string memory stringifiedValue); + function toString(uint256 value) external pure returns (string memory stringifiedValue); + function toString(int256 value) external pure returns (string memory stringifiedValue); + // Convert values from a string + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + // Record all the transaction logs + function recordLogs() external; + // Gets all the recorded logs + function getRecordedLogs() external returns (Log[] memory logs); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index} + function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey); + // Derive a private key from a provided mnenomic string (or mnenomic file path) at {derivationPath}{index} + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index) + external + pure + returns (uint256 privateKey); + // Adds a private key to the local forge wallet and returns the address + function rememberKey(uint256 privateKey) external returns (address addr); + // + // parseJson + // + // ---- + // In case the returned value is a JSON object, it's encoded as a ABI-encoded tuple. As JSON objects + // don't have the notion of ordered, but tuples do, they JSON object is encoded with it's fields ordered in + // ALPHABETICAL order. That means that in order to successfully decode the tuple, we need to define a tuple that + // encodes the fields in the same order, which is alphabetical. In the case of Solidity structs, they are encoded + // as tuples, with the attributes in the order in which they are defined. + // For example: json = { 'a': 1, 'b': 0xa4tb......3xs} + // a: uint256 + // b: address + // To decode that json, we need to define a struct or a tuple as follows: + // struct json = { uint256 a; address b; } + // If we defined a json struct with the opposite order, meaning placing the address b first, it would try to + // decode the tuple in that order, and thus fail. + // ---- + // Given a string of JSON, return it as ABI-encoded + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + // Serialize a key and value to a JSON object stored in-memory that can be later written to a file + // It returns the stringified version of the specific JSON file up to that moment. + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + // + // writeJson + // + // ---- + // Write a serialized JSON object to a file. If the file exists, it will be overwritten. + // Let's assume we want to write the following JSON to a file: + // + // { "boolean": true, "number": 342, "object": { "title": "finally json serialization" } } + // + // ``` + // string memory json1 = "some key"; + // vm.serializeBool(json1, "boolean", true); + // vm.serializeBool(json1, "number", uint256(342)); + // json2 = "some other key"; + // string memory output = vm.serializeString(json2, "title", "finally json serialization"); + // string memory finalJson = vm.serialize(json1, "object", output); + // vm.writeJson(finalJson, "./output/example.json"); + // ``` + // The critical insight is that every invocation of serialization will return the stringified version of the JSON + // up to that point. That means we can construct arbitrary JSON objects and then use the return stringified version + // to serialize them as values to another JSON object. + // + // json1 and json2 are simply keys used by the backend to keep track of the objects. So vm.serializeJson(json1,..) + // will find the object in-memory that is keyed by "some key". + function writeJson(string calldata json, string calldata path) external; + // Write a serialized JSON object to an **existing** JSON file, replacing a value with key = + // This is useful to replace a specific value of a JSON file, without having to parse the entire thing + function writeJson(string calldata json, string calldata path, string calldata valueKey) external; + // Returns the RPC url for the given alias + function rpcUrl(string calldata rpcAlias) external view returns (string memory json); + // Returns all rpc urls and their aliases `[alias, url][]` + function rpcUrls() external view returns (string[2][] memory urls); + // Returns all rpc urls and their aliases as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + // If the condition is false, discard this run's fuzz inputs and generate new ones. + function assume(bool condition) external pure; + // Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + // Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; +} + +interface Vm is VmSafe { + // Sets block.timestamp + function warp(uint256 newTimestamp) external; + // Sets block.height + function roll(uint256 newHeight) external; + // Sets block.basefee + function fee(uint256 newBasefee) external; + // Sets block.difficulty + function difficulty(uint256 newDifficulty) external; + // Sets block.chainid + function chainId(uint256 newChainId) external; + // Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) external; + // Sets the nonce of an account; must be higher than the current nonce of the account + function setNonce(address account, uint64 newNonce) external; + // Sets the *next* call's msg.sender to be the input address + function prank(address msgSender) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called + function startPrank(address msgSender) external; + // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input + function prank(address msgSender, address txOrigin) external; + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input + function startPrank(address msgSender, address txOrigin) external; + // Resets subsequent calls' msg.sender to be `address(this)` + function stopPrank() external; + // Sets an address' balance + function deal(address account, uint256 newBalance) external; + // Sets an address' code + function etch(address target, bytes calldata newRuntimeBytecode) external; + // Expects an error on next call + function expectRevert(bytes calldata revertData) external; + function expectRevert(bytes4 revertData) external; + function expectRevert() external; + // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + // Call this function, then emit an event, then call a function. Internally after the call, we check if + // logs were emitted in the expected order with the expected topics and data (as specified by the booleans) + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external; + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) + external; + // Mocks a call to an address, returning specified data. + // Calldata can either be strict or a partial match, e.g. if you only + // pass a Solidity selector to the expected calldata, then the entire Solidity + // function will be mocked. + function mockCall(address callee, bytes calldata data, bytes calldata returnData) external; + // Mocks a call to an address with a specific msg.value, returning specified data. + // Calldata match takes precedence over msg.value in case of ambiguity. + function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external; + // Clears all mocked calls + function clearMockedCalls() external; + // Expects a call to an address with the specified calldata. + // Calldata can either be a strict or a partial match + function expectCall(address callee, bytes calldata data) external; + // Expects a call to an address with the specified msg.value and calldata + function expectCall(address callee, uint256 msgValue, bytes calldata data) external; + // Sets block.coinbase + function coinbase(address newCoinbase) external; + // Snapshot the current state of the evm. + // Returns the id of the snapshot that was created. + // To revert a snapshot use `revertTo` + function snapshot() external returns (uint256 snapshotId); + // Revert the state of the EVM to a previous snapshot + // Takes the snapshot id to revert to. + // This deletes the snapshot and all snapshots taken after the given snapshot id. + function revertTo(uint256 snapshotId) external returns (bool success); + // Creates a new fork with the given endpoint and block and returns the identifier of the fork + function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork + function createFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Creates a new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before the transaction, + // and returns the identifier of the fork + function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + // Creates _and_ also selects new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before + // the transaction, returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + // Creates _and_ also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId); + // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active. + function selectFork(uint256 forkId) external; + /// Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + // Updates the currently active fork to given block number + // This is similar to `roll` but for the currently active fork + function rollFork(uint256 blockNumber) external; + // Updates the currently active fork to given transaction + // this will `rollFork` with the number of the block the transaction was mined in and replays all transaction mined before it in the block + function rollFork(bytes32 txHash) external; + // Updates the given fork to given block number + function rollFork(uint256 forkId, uint256 blockNumber) external; + // Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block + function rollFork(uint256 forkId, bytes32 txHash) external; + // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup + // Meaning, changes made to the state of this account will be kept when switching forks + function makePersistent(address account) external; + function makePersistent(address account0, address account1) external; + function makePersistent(address account0, address account1, address account2) external; + function makePersistent(address[] calldata accounts) external; + // Revokes persistent status from the address, previously added via `makePersistent` + function revokePersistent(address account) external; + function revokePersistent(address[] calldata accounts) external; + // Returns true if the account is marked as persistent + function isPersistent(address account) external view returns (bool persistent); + // In forking mode, explicitly grant the given address cheatcode access + function allowCheatcodes(address account) external; + // Fetches the given transaction from the active fork and executes it on the current state + function transact(bytes32 txHash) external; + // Fetches the given transaction from the given fork and executes it on the current state + function transact(uint256 forkId, bytes32 txHash) external; +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/console.sol b/lib/openzeppelin-contracts/lib/forge-std/src/console.sol new file mode 100644 index 0000000..ad57e53 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/console.sol @@ -0,0 +1,1533 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol b/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..8596233 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/console2.sol @@ -0,0 +1,1546 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +/// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should +/// use `int256` and `uint256`. This modified version fixes that. This version is recommended +/// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in +/// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`. +/// Reference: https://github.com/NomicFoundation/hardhat/issues/2178 +library console2 { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function logUint(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function log(int256 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint256 p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); + } + + function log(uint256 p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); + } + + function log(uint256 p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); + } + + function log(uint256 p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); + } + + function log(string memory p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function log(string memory p0, int256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint256 p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint256 p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint256 p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint256 p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..f7dd2b4 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC1155.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-1155 Multi Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-1155 +/// Note: The ERC-165 identifier for this interface is 0xd9b67a26. +interface IERC1155 is IERC165 { + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_id` argument MUST be the token type being transferred. + /// - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferSingle( + address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value + ); + + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_ids` argument MUST be the list of tokens being transferred. + /// - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferBatch( + address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values + ); + + /// @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled). + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. + /// The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". + event URI(string _value, uint256 indexed _id); + + /// @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + /// - MUST revert on any other error. + /// - MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + /// - After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _id ID of the token type + /// @param _value Transfer amount + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; + + /// @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if length of `_ids` is not the same as length of `_values`. + /// - MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + /// - MUST revert on any other error. + /// - MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + /// - Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + /// - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _ids IDs of each token type (order and length must match _values array) + /// @param _values Transfer amounts per token type (order and length must match _ids array) + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + function safeBatchTransferFrom( + address _from, + address _to, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data + ) external; + + /// @notice Get the balance of an account's tokens. + /// @param _owner The address of the token holder + /// @param _id ID of the token + /// @return The _owner's balance of the token type requested + function balanceOf(address _owner, uint256 _id) external view returns (uint256); + + /// @notice Get the balance of multiple account/token pairs + /// @param _owners The addresses of the token holders + /// @param _ids ID of the tokens + /// @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair) + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) + external + view + returns (uint256[] memory); + + /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + /// @dev MUST emit the ApprovalForAll event on success. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Queries the approval status of an operator for a given owner. + /// @param _owner The owner of the tokens + /// @param _operator Address of authorized operator + /// @return True if the operator is approved, false if not + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC165.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +interface IERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +/// @dev Interface of the ERC20 standard as defined in the EIP. +/// @dev This includes the optional name, symbol, and decimals metadata. +interface IERC20 { + /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` + /// is the new allowance. + event Approval(address indexed owner, address indexed spender, uint256 value); + + /// @notice Returns the amount of tokens in existence. + function totalSupply() external view returns (uint256); + + /// @notice Returns the amount of tokens owned by `account`. + function balanceOf(address account) external view returns (uint256); + + /// @notice Moves `amount` tokens from the caller's account to `to`. + function transfer(address to, uint256 amount) external returns (bool); + + /// @notice Returns the remaining number of tokens that `spender` is allowed + /// to spend on behalf of `owner` + function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. + /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. + /// `amount` is then deducted from the caller's allowance. + function transferFrom(address from, address to, uint256 amount) external returns (bool); + + /// @notice Returns the name of the token. + function name() external view returns (string memory); + + /// @notice Returns the symbol of the token. + function symbol() external view returns (string memory); + + /// @notice Returns the decimals places of the token. + function decimals() external view returns (uint8); +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..bfe3a11 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC4626.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC20.sol"; + +/// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in +/// https://eips.ethereum.org/EIPS/eip-4626 +interface IERC4626 is IERC20 { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares + ); + + /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + /// @dev + /// - MUST be an ERC-20 token contract. + /// - MUST NOT revert. + function asset() external view returns (address assetTokenAddress); + + /// @notice Returns the total amount of the underlying asset that is “managed” by Vault. + /// @dev + /// - SHOULD include any compounding that occurs from yield. + /// - MUST be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT revert. + function totalAssets() external view returns (uint256 totalManagedAssets); + + /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + /// through a deposit call. + /// @dev + /// - MUST return a limited value if receiver is subject to some deposit limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + /// - MUST NOT revert. + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + /// call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + /// in the same transaction. + /// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + /// deposit would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// deposit execution, and are accounted for during deposit. + /// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + /// @dev + /// - MUST return a limited value if receiver is subject to some mint limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + /// - MUST NOT revert. + function maxMint(address receiver) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + /// in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + /// same transaction. + /// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + /// would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by minting. + function previewMint(uint256 shares) external view returns (uint256 assets); + + /// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + /// execution, and are accounted for during mint. + /// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + /// Vault, through a withdraw call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST NOT revert. + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + /// call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + /// called + /// in the same transaction. + /// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + /// the withdrawal would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// withdraw execution, and are accounted for during withdraw. + /// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + /// through a redeem call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + /// - MUST NOT revert. + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + /// in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + /// same transaction. + /// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + /// redemption would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by redeeming. + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// redeem execution, and are accounted for during redeem. + /// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..0a16f45 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/src/interfaces/IERC721.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-721 Non-Fungible Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. +interface IERC721 is IERC165 { + /// @dev This emits when ownership of any NFT changes by any mechanism. + /// This event emits when NFTs are created (`from` == 0) and destroyed + /// (`to` == 0). Exception: during contract creation, any number of NFTs + /// may be created and assigned without emitting Transfer. At the time of + /// any transfer, the approved address for that NFT (if any) is reset to none. + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + + /// @dev This emits when the approved address for an NFT is changed or + /// reaffirmed. The zero address indicates there is no approved address. + /// When a Transfer event emits, this also indicates that the approved + /// address for that NFT (if any) is reset to none. + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + /// @dev This emits when an operator is enabled or disabled for an owner. + /// The operator can manage all NFTs of the owner. + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @notice Count all NFTs assigned to an owner + /// @dev NFTs assigned to the zero address are considered invalid, and this + /// function throws for queries about the zero address. + /// @param _owner An address for whom to query the balance + /// @return The number of NFTs owned by `_owner`, possibly zero + function balanceOf(address _owner) external view returns (uint256); + + /// @notice Find the owner of an NFT + /// @dev NFTs assigned to zero address are considered invalid, and queries + /// about them do throw. + /// @param _tokenId The identifier for an NFT + /// @return The address of the owner of the NFT + function ownerOf(uint256 _tokenId) external view returns (address); + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. When transfer is complete, this function + /// checks if `_to` is a smart contract (code size > 0). If so, it calls + /// `onERC721Received` on `_to` and throws if the return value is not + /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + /// @param data Additional data with no specified format, sent in call to `_to` + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev This works identically to the other function with an extra data parameter, + /// except this function just sets data to "". + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE + /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE + /// THEY MAY BE PERMANENTLY LOST + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Change or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param _approved The new approved NFT controller + /// @param _tokenId The NFT to approve + function approve(address _approved, uint256 _tokenId) external payable; + + /// @notice Enable or disable approval for a third party ("operator") to manage + /// all of `msg.sender`'s assets + /// @dev Emits the ApprovalForAll event. The contract MUST allow + /// multiple operators per owner. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Get the approved address for a single NFT + /// @dev Throws if `_tokenId` is not a valid NFT. + /// @param _tokenId The NFT to find the approved address for + /// @return The approved address for this NFT, or the zero address if there is none + function getApproved(uint256 _tokenId) external view returns (address); + + /// @notice Query if an address is an authorized operator for another address + /// @param _owner The address that owns the NFTs + /// @param _operator The address that acts on behalf of the owner + /// @return True if `_operator` is an approved operator for `_owner`, false otherwise + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} + +/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02. +interface IERC721TokenReceiver { + /// @notice Handle the receipt of an NFT + /// @dev The ERC721 smart contract calls this function on the recipient + /// after a `transfer`. This function MAY throw to revert and reject the + /// transfer. Return of other than the magic value MUST result in the + /// transaction being reverted. + /// Note: the contract address is always the message sender. + /// @param _operator The address which called `safeTransferFrom` function + /// @param _from The address which previously owned the token + /// @param _tokenId The NFT identifier which is being transferred + /// @param _data Additional data with no specified format + /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + /// unless throwing + function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) + external + returns (bytes4); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x5b5e139f. +interface IERC721Metadata is IERC721 { + /// @notice A descriptive name for a collection of NFTs in this contract + function name() external view returns (string memory _name); + + /// @notice An abbreviated name for NFTs in this contract + function symbol() external view returns (string memory _symbol); + + /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. + /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC + /// 3986. The URI may point to a JSON file that conforms to the "ERC721 + /// Metadata JSON Schema". + function tokenURI(uint256 _tokenId) external view returns (string memory); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x780e9d63. +interface IERC721Enumerable is IERC721 { + /// @notice Count NFTs tracked by this contract + /// @return A count of valid NFTs tracked by this contract, where each one of + /// them has an assigned and queryable owner not equal to the zero address + function totalSupply() external view returns (uint256); + + /// @notice Enumerate valid NFTs + /// @dev Throws if `_index` >= `totalSupply()`. + /// @param _index A counter less than `totalSupply()` + /// @return The token identifier for the `_index`th NFT, + /// (sort order not specified) + function tokenByIndex(uint256 _index) external view returns (uint256); + + /// @notice Enumerate NFTs assigned to an owner + /// @dev Throws if `_index` >= `balanceOf(_owner)` or if + /// `_owner` is the zero address, representing invalid NFTs. + /// @param _owner An address where we are interested in NFTs owned by them + /// @param _index A counter less than `balanceOf(_owner)` + /// @return The token identifier for the `_index`th NFT assigned to `_owner`, + /// (sort order not specified) + function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol b/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..4d5827d --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,587 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdAssertionsTest is Test { + string constant CUSTOM_ERROR = "guh!"; + + bool constant EXPECT_PASS = false; + bool constant EXPECT_FAIL = true; + + TestTest t = new TestTest(); + + /*////////////////////////////////////////////////////////////////////////// + FAIL(STRING) + //////////////////////////////////////////////////////////////////////////*/ + + function testShouldFail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._fail(CUSTOM_ERROR); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_FALSE + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertFalse_Pass() external { + t._assertFalse(false, EXPECT_PASS); + } + + function testAssertFalse_Fail() external { + vm.expectEmit(false, false, false, true); + emit log("Error: Assertion Failed"); + t._assertFalse(true, EXPECT_FAIL); + } + + function testAssertFalse_Err_Pass() external { + t._assertFalse(false, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertFalse_Err_Fail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertFalse(true, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BOOL) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bool_Pass(bool a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bool_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bool]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BoolErr_Pass(bool a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BoolErr_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BYTES) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_Bytes_Pass(bytes calldata a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testAssertEq_Bytes_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bytes]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_BytesErr_Pass(bytes calldata a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertEq_BytesErr_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(ARRAY) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEq_UintArr_Pass(uint256 e0, uint256 e1, uint256 e2) public { + uint256[] memory a = new uint256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + uint256[] memory b = new uint256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_IntArr_Pass(int256 e0, int256 e1, int256 e2) public { + int256[] memory a = new int256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + int256[] memory b = new int256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_AddressArr_Pass(address e0, address e1, address e2) public { + address[] memory a = new address[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + address[] memory b = new address[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testAssertEq_UintArr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_UintArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_IntArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_AddressArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testAssertEq_UintArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_IntArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testAssertEq_AddressArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertEqUint() public { + assertEqUint(uint8(1), uint128(1)); + assertEqUint(uint64(2), uint64(2)); + } + + function testFailAssertEqUint() public { + assertEqUint(uint64(1), uint96(2)); + assertEqUint(uint160(3), uint160(4)); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqAbs_Int_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testAssertApproxEqAbs_Int_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testAssertApproxEqAbs_IntErr_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqAbs_IntErr_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRel_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testAssertApproxEqRel_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testAssertApproxEqRel_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRel_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } +} + +contract TestTest is Test { + modifier expectFailure(bool expectFail) { + bool preState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + _; + bool postState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + + if (preState == true) { + return; + } + + if (expectFail) { + require(postState == true, "expected failure not triggered"); + + // unwind the expected failure + vm.store(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x00))); + } else { + require(postState == false, "unexpected failure was triggered"); + } + } + + function _fail(string memory err) external expectFailure(true) { + fail(err); + } + + function _assertFalse(bool data, bool expectFail) external expectFailure(expectFail) { + assertFalse(data); + } + + function _assertFalse(bool data, string memory err, bool expectFail) external expectFailure(expectFail) { + assertFalse(data, err); + } + + function _assertEq(bool a, bool b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bool a, bool b, string memory err, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b, err); + } + + function _assertEq(bytes memory a, bytes memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bytes memory a, bytes memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(int256[] memory a, int256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(address[] memory a, address[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(int256[] memory a, int256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(address[] memory a, address[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol b/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..3657510 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdChainsTest is Test { + function testChainRpcInitialization() public { + // RPCs specified in `foundry.toml` should be updated. + assertEq(getChain(1).rpcUrl, "https://mainnet.infura.io/v3/7a8769b798b642f6933f2ed52042bd70"); + assertEq(getChain("optimism_goerli").rpcUrl, "https://goerli.optimism.io/"); + assertEq(getChain("arbitrum_one_goerli").rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/"); + + // Other RPCs should remain unchanged. + assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545"); + assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/6770454bc6ea42c58aac12978531b93f"); + } + + function testRpc(string memory rpcAlias) internal { + string memory rpcUrl = getChain(rpcAlias).rpcUrl; + vm.createSelectFork(rpcUrl); + } + + // Ensure we can connect to the default RPC URL for each chain. + function testRpcs() public { + testRpc("mainnet"); + testRpc("goerli"); + testRpc("sepolia"); + testRpc("optimism"); + testRpc("optimism_goerli"); + testRpc("arbitrum_one"); + testRpc("arbitrum_one_goerli"); + testRpc("arbitrum_nova"); + testRpc("polygon"); + testRpc("polygon_mumbai"); + testRpc("avalanche"); + testRpc("avalanche_fuji"); + testRpc("bnb_smart_chain"); + testRpc("bnb_smart_chain_testnet"); + testRpc("gnosis_chain"); + } + + function testChainNoDefault() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found."); + getChain("does_not_exist"); + } + + function testSetChainFirstFails() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain ID 31337 already used by \"anvil\"."); + setChain("anvil2", Chain("Anvil", 31337, "URL")); + } + + function testChainBubbleUp() public { + setChain("needs_undefined_env_var", Chain("", 123456789, "")); + vm.expectRevert( + "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found" + ); + getChain("needs_undefined_env_var"); + } + + function testCannotSetChain_ChainIdExists() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + + vm.expectRevert('StdChains setChain(string,Chain): Chain ID 123456789 already used by "custom_chain".'); + + setChain("another_custom_chain", Chain("", 123456789, "")); + } + + function testSetChain() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + Chain memory customChain = getChain("custom_chain"); + assertEq(customChain.name, "Custom Chain"); + assertEq(customChain.chainId, 123456789); + assertEq(customChain.rpcUrl, "https://custom.chain/"); + Chain memory chainById = getChain(123456789); + assertEq(chainById.name, customChain.name); + assertEq(chainById.chainId, customChain.chainId); + assertEq(chainById.rpcUrl, customChain.rpcUrl); + } + + function testSetNoEmptyAlias() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain alias cannot be the empty string."); + setChain("", Chain("", 123456789, "")); + } + + function testSetNoChainId0() public { + vm.expectRevert("StdChains setChain(string,Chain): Chain ID cannot be 0."); + setChain("alias", Chain("", 0, "")); + } + + function testGetNoChainId0() public { + vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0."); + getChain(0); + } + + function testGetNoEmptyAlias() public { + vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string."); + getChain(""); + } + + function testChainIdNotFound() public { + vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found."); + getChain("no_such_alias"); + } + + function testChainAliasNotFound() public { + vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found."); + getChain(321); + } + + function testSetChain_ExistingOne() public { + setChain("custom_chain", Chain("Custom Chain", 123456789, "https://custom.chain/")); + assertEq(getChain(123456789).chainId, 123456789); + + setChain("custom_chain", Chain("Modified Chain", 999999999, "https://modified.chain/")); + vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); + getChain(123456789); + + Chain memory modifiedChain = getChain(999999999); + assertEq(modifiedChain.name, "Modified Chain"); + assertEq(modifiedChain.chainId, 999999999); + assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol b/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..2eab3c3 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdCheats.sol"; +import "../src/Test.sol"; +import "../src/StdJson.sol"; + +contract StdCheatsTest is Test { + Bar test; + + using stdJson for string; + + function setUp() public { + test = new Bar(); + } + + function testSkip() public { + vm.warp(100); + skip(25); + assertEq(block.timestamp, 125); + } + + function testRewind() public { + vm.warp(100); + rewind(25); + assertEq(block.timestamp, 75); + } + + function testHoax() public { + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + } + + function testHoaxOrigin() public { + hoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + } + + function testHoaxDifferentAddresses() public { + hoax(address(1337), address(7331)); + test.origin{value: 100}(address(1337), address(7331)); + } + + function testStartHoax() public { + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testStartHoaxOrigin() public { + startHoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + test.origin{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function testChangePrank() public { + vm.startPrank(address(1337)); + test.bar(address(1337)); + changePrank(address(0xdead)); + test.bar(address(0xdead)); + changePrank(address(1337)); + test.bar(address(1337)); + vm.stopPrank(); + } + + function testMakeAddrEquivalence() public { + (address addr,) = makeAddrAndKey("1337"); + assertEq(makeAddr("1337"), addr); + } + + function testMakeAddrSigning() public { + (address addr, uint256 key) = makeAddrAndKey("1337"); + bytes32 hash = keccak256("some_message"); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash); + assertEq(ecrecover(hash, v, r, s), addr); + } + + function testDeal() public { + deal(address(this), 1 ether); + assertEq(address(this).balance, 1 ether); + } + + function testDealToken() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18); + assertEq(barToken.balanceOf(address(this)), 10000e18); + } + + function testDealTokenAdjustTS() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18, true); + assertEq(barToken.balanceOf(address(this)), 10000e18); + assertEq(barToken.totalSupply(), 20000e18); + deal(bar, address(this), 0, true); + assertEq(barToken.balanceOf(address(this)), 0); + assertEq(barToken.totalSupply(), 10000e18); + } + + function testDeployCode() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes("")); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar"); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function testDeployCodeVal() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes(""), 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + function testDeployCodeValNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar", 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + // We need this so we can call "this.deployCode" rather than "deployCode" directly + function deployCodeHelper(string memory what) external { + deployCode(what); + } + + function testDeployCodeFail() public { + vm.expectRevert(bytes("StdCheats deployCode(string): Deployment failed.")); + this.deployCodeHelper("StdCheats.t.sol:RevertingContract"); + } + + function getCode(address who) internal view returns (bytes memory o_code) { + /// @solidity memory-safe-assembly + assembly { + // retrieve the size of the code, this needs assembly + let size := extcodesize(who) + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + o_code := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(o_code, size) + // actually retrieve the code, this needs assembly + extcodecopy(who, add(o_code, 0x20), 0, size) + } + } + + function testDeriveRememberKey() public { + string memory mnemonic = "test test test test test test test test test test test junk"; + + (address deployer, uint256 privateKey) = deriveRememberKey(mnemonic, 0); + assertEq(deployer, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); + } + + function testBytesToUint() public { + assertEq(3, bytesToUint_test(hex"03")); + assertEq(2, bytesToUint_test(hex"02")); + assertEq(255, bytesToUint_test(hex"ff")); + assertEq(29625, bytesToUint_test(hex"73b9")); + } + + function testParseJsonTxDetail() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + string memory json = vm.readFile(path); + bytes memory transactionDetails = json.parseRaw(".transactions[0].tx"); + RawTx1559Detail memory rawTxDetail = abi.decode(transactionDetails, (RawTx1559Detail)); + Tx1559Detail memory txDetail = rawToConvertedEIP1559Detail(rawTxDetail); + assertEq(txDetail.from, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(txDetail.to, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512); + assertEq( + txDetail.data, + hex"23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004" + ); + assertEq(txDetail.nonce, 3); + assertEq(txDetail.txType, 2); + assertEq(txDetail.gas, 29625); + assertEq(txDetail.value, 0); + } + + function testReadEIP1559Transaction() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 0; + Tx1559 memory transaction = readTx1559(path, index); + transaction; + } + + function testReadEIP1559Transactions() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Tx1559[] memory transactions = readTx1559s(path); + transactions; + } + + function testReadReceipt() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 5; + Receipt memory receipt = readReceipt(path, index); + assertEq( + receipt.logsBloom, + hex"00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100" + ); + } + + function testReadReceipts() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Receipt[] memory receipts = readReceipts(path); + receipts; + } + + function testGasMeteringModifier() public { + uint256 gas_start_normal = gasleft(); + addInLoop(); + uint256 gas_used_normal = gas_start_normal - gasleft(); + + uint256 gas_start_single = gasleft(); + addInLoopNoGas(); + uint256 gas_used_single = gas_start_single - gasleft(); + + uint256 gas_start_double = gasleft(); + addInLoopNoGasNoGas(); + uint256 gas_used_double = gas_start_double - gasleft(); + + emit log_named_uint("Normal gas", gas_used_normal); + emit log_named_uint("Single modifier gas", gas_used_single); + emit log_named_uint("Double modifier gas", gas_used_double); + assertTrue(gas_used_double + gas_used_single < gas_used_normal); + } + + function addInLoop() internal pure returns (uint256) { + uint256 b; + for (uint256 i; i < 10000; i++) { + b += i; + } + return b; + } + + function addInLoopNoGas() internal noGasMetering returns (uint256) { + return addInLoop(); + } + + function addInLoopNoGasNoGas() internal noGasMetering returns (uint256) { + return addInLoopNoGas(); + } + + function bytesToUint_test(bytes memory b) private pure returns (uint256) { + uint256 number; + for (uint256 i = 0; i < b.length; i++) { + number = number + uint256(uint8(b[i])) * (2 ** (8 * (b.length - (i + 1)))); + } + return number; + } + + function testAssumeNoPrecompiles(address addr) external { + assumeNoPrecompiles(addr, getChain("optimism_goerli").chainId); + assertTrue( + addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) + || addr > address(0x4200000000000000000000000000000000000800) + ); + } +} + +contract Bar { + constructor() payable { + /// `DEAL` STDCHEAT + totalSupply = 10000e18; + balanceOf[address(this)] = totalSupply; + } + + /// `HOAX` STDCHEATS + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } + + function origin(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedSender, "!prank"); + } + + function origin(address expectedSender, address expectedOrigin) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedOrigin, "!prank"); + } + + /// `DEAL` STDCHEAT + mapping(address => uint256) public balanceOf; + uint256 public totalSupply; +} + +contract RevertingContract { + constructor() { + revert(); + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol b/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..ccd3efa --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdError.sol"; +import "../src/Test.sol"; + +contract StdErrorsTest is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectAssertion() public { + vm.expectRevert(stdError.assertionError); + test.assertionError(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } + + function testExpectDiv() public { + vm.expectRevert(stdError.divisionError); + test.divError(0); + } + + function testExpectMod() public { + vm.expectRevert(stdError.divisionError); + test.modError(0); + } + + function testExpectEnum() public { + vm.expectRevert(stdError.enumConversionError); + test.enumConversion(1); + } + + function testExpectEncodeStg() public { + vm.expectRevert(stdError.encodeStorageError); + test.encodeStgError(); + } + + function testExpectPop() public { + vm.expectRevert(stdError.popError); + test.pop(); + } + + function testExpectOOB() public { + vm.expectRevert(stdError.indexOOBError); + test.indexOOBError(1); + } + + function testExpectMem() public { + vm.expectRevert(stdError.memOverflowError); + test.mem(); + } + + function testExpectIntern() public { + vm.expectRevert(stdError.zeroVarError); + test.intern(); + } +} + +contract ErrorsTest { + enum T {T1} + + uint256[] public someArr; + bytes someBytes; + + function assertionError() public pure { + assert(false); + } + + function arithmeticError(uint256 a) public pure { + a -= 100; + } + + function divError(uint256 a) public pure { + 100 / a; + } + + function modError(uint256 a) public pure { + 100 % a; + } + + function enumConversion(uint256 a) public pure { + T(a); + } + + function encodeStgError() public { + /// @solidity memory-safe-assembly + assembly { + sstore(someBytes.slot, 1) + } + keccak256(someBytes); + } + + function pop() public { + someArr.pop(); + } + + function indexOOBError(uint256 a) public pure { + uint256[] memory t = new uint256[](0); + t[a]; + } + + function mem() public pure { + uint256 l = 2 ** 256 / 32; + new uint256[](l); + } + + function intern() public returns (uint256) { + function(uint256) internal returns (uint256) x; + x(2); + return 7; + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol b/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..95037ea --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/StdMath.t.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdMath.sol"; +import "../src/Test.sol"; + +contract StdMathTest is Test { + function testGetAbs() external { + assertEq(stdMath.abs(-50), 50); + assertEq(stdMath.abs(50), 50); + assertEq(stdMath.abs(-1337), 1337); + assertEq(stdMath.abs(0), 0); + + assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1); + assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1)); + } + + function testGetAbs_Fuzz(int256 a) external { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function testGetDelta_Uint() external { + assertEq(stdMath.delta(uint256(0), uint256(0)), 0); + assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337); + assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max); + assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max); + assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max); + + assertEq(stdMath.delta(0, uint256(0)), 0); + assertEq(stdMath.delta(1337, uint256(0)), 1337); + assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max); + assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max); + assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max); + + assertEq(stdMath.delta(1337, uint256(1337)), 0); + assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0); + assertEq(stdMath.delta(5000, uint256(1250)), 3750); + } + + function testGetDelta_Uint_Fuzz(uint256 a, uint256 b) external { + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetDelta_Int() external { + assertEq(stdMath.delta(int256(0), int256(0)), 0); + assertEq(stdMath.delta(int256(0), int256(1337)), 1337); + assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1); + assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1); + assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1); + + assertEq(stdMath.delta(0, int256(0)), 0); + assertEq(stdMath.delta(1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1); + assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1); + assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1); + + assertEq(stdMath.delta(-0, int256(0)), 0); + assertEq(stdMath.delta(-1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(int256(0), -0), 0); + assertEq(stdMath.delta(int256(0), -1337), 1337); + assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(1337, int256(1337)), 0); + assertEq(stdMath.delta(type(int256).max, type(int256).max), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).min), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max); + assertEq(stdMath.delta(5000, int256(1250)), 3750); + } + + function testGetDelta_Int_Fuzz(int256 a, int256 b) external { + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function testGetPercentDelta_Uint() external { + assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); + assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); + assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); + assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(uint256(1), 0); + } + + function testGetPercentDelta_Uint_Fuzz(uint192 a, uint192 b) external { + vm.assume(b != 0); + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / b; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + function testGetPercentDelta_Int() external { + assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); + assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, int256(1337)), 0); + assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); + assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); + + assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, int256(2500)), 0); + assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMath.percentDelta(int256(1), 0); + } + + function testGetPercentDelta_Int_Fuzz(int192 a, int192 b) external { + vm.assume(b != 0); + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / absB; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function getAbs(int256 a) private pure returns (uint256) { + if (a < 0) { + return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); + } + + return uint256(a); + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol b/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..d4c563a --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdStorage.sol"; +import "../src/Test.sol"; + +contract StdStorageTest is Test { + using stdStorage for StdStorage; + + StorageTest internal test; + + function setUp() public { + test = new StorageTest(); + } + + function testStorageHidden() public { + assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find()); + } + + function testStorageObvious() public { + assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find()); + } + + function testStorageCheckedWriteHidden() public { + stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100); + assertEq(uint256(test.hidden()), 100); + } + + function testStorageCheckedWriteObvious() public { + stdstore.target(address(test)).sig(test.exists.selector).checked_write(100); + assertEq(test.exists(), 100); + } + + function testStorageMapStructA() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot); + } + + function testStorageMapStructB() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot); + } + + function testStorageDeepMap() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key( + address(this) + ).find(); + assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(5)))))), slot); + } + + function testStorageCheckedWriteDeepMap() public { + stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(address(this)) + .checked_write(100); + assertEq(100, test.deep_map(address(this), address(this))); + } + + function testStorageDeepMapStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(0).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 0), + bytes32(slot) + ); + } + + function testStorageDeepMapStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(1).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 1), + bytes32(slot) + ); + } + + function testStorageCheckedWriteDeepMapStructA() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(100, a); + assertEq(0, b); + } + + function testStorageCheckedWriteDeepMapStructB() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(0, a); + assertEq(100, b); + } + + function testStorageCheckedWriteMapStructA() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 100); + assertEq(b, 0); + } + + function testStorageCheckedWriteMapStructB() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 0); + assertEq(b, 100); + } + + function testStorageStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find(); + assertEq(uint256(7), slot); + } + + function testStorageStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find(); + assertEq(uint256(7) + 1, slot); + } + + function testStorageCheckedWriteStructA() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 100); + assertEq(b, 1337); + } + + function testStorageCheckedWriteStructB() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 1337); + assertEq(b, 100); + } + + function testStorageMapAddrFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find(); + assertEq(uint256(keccak256(abi.encode(address(this), uint256(1)))), slot); + } + + function testStorageMapUintFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find(); + assertEq(uint256(keccak256(abi.encode(100, uint256(2)))), slot); + } + + function testStorageCheckedWriteMapUint() public { + stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100); + assertEq(100, test.map_uint(100)); + } + + function testStorageCheckedWriteMapAddr() public { + stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100); + assertEq(100, test.map_addr(address(this))); + } + + function testStorageCheckedWriteMapBool() public { + stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true); + assertTrue(test.map_bool(address(this))); + } + + function testFailStorageCheckedWriteMapPacked() public { + // expect PackedSlot error but not external call so cant expectRevert + stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))) + .checked_write(100); + } + + function testStorageCheckedWriteMapPackedSuccess() public { + uint256 full = test.map_packed(address(1337)); + // keep upper 128, set lower 128 to 1337 + full = (full & (uint256((1 << 128) - 1) << 128)) | 1337; + stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write( + full + ); + assertEq(1337, test.read_struct_lower(address(1337))); + } + + function testFailStorageConst() public { + // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()")))); + stdstore.target(address(test)).sig("const()").find(); + } + + function testFailStorageNativePack() public { + stdstore.target(address(test)).sig(test.tA.selector).find(); + stdstore.target(address(test)).sig(test.tB.selector).find(); + + // these both would fail + stdstore.target(address(test)).sig(test.tC.selector).find(); + stdstore.target(address(test)).sig(test.tD.selector).find(); + } + + function testStorageReadBytes32() public { + bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32(); + assertEq(val, hex"1337"); + } + + function testStorageReadBool_False() public { + bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool(); + assertEq(val, false); + } + + function testStorageReadBool_True() public { + bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool(); + assertEq(val, true); + } + + function testStorageReadBool_Revert() public { + vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + this.readNonBoolValue(); + } + + function readNonBoolValue() public { + stdstore.target(address(test)).sig(test.tE.selector).read_bool(); + } + + function testStorageReadAddress() public { + address val = stdstore.target(address(test)).sig(test.tF.selector).read_address(); + assertEq(val, address(1337)); + } + + function testStorageReadUint() public { + uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint(); + assertEq(val, 1); + } + + function testStorageReadInt() public { + int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int(); + assertEq(val, type(int256).min); + } +} + +contract StorageTest { + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + mapping(uint256 => uint256) public map_uint; + mapping(address => uint256) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basic; + + uint248 public tA; + bool public tB; + + bool public tC = false; + uint248 public tD = 1; + + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + mapping(address => bool) public map_bool; + + bytes32 public tE = hex"1337"; + address public tF = address(1337); + int256 public tG = type(int256).min; + bool public tH = true; + + constructor() { + basic = UnpackedStruct({a: 1337, b: 1337}); + + uint256 two = (1 << 128) | 1; + map_packed[msg.sender] = two; + map_packed[address(uint160(1337))] = 1 << 128; + } + + function read_struct_upper(address who) public view returns (uint256) { + return map_packed[who] >> 128; + } + + function read_struct_lower(address who) public view returns (uint256) { + return map_packed[who] & ((1 << 128) - 1); + } + + function hidden() public view returns (bytes32 t) { + bytes32 slot = keccak256("my.random.var"); + /// @solidity memory-safe-assembly + assembly { + t := sload(slot) + } + } + + function const() public pure returns (bytes32 t) { + t = bytes32(hex"1337"); + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol b/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..f53a71b --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/StdUtils.t.sol @@ -0,0 +1,191 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdUtilsTest is Test { + function testBound() public { + assertEq(bound(uint256(5), 0, 4), 0); + assertEq(bound(uint256(0), 69, 69), 69); + assertEq(bound(uint256(0), 68, 69), 68); + assertEq(bound(uint256(10), 150, 190), 174); + assertEq(bound(uint256(300), 2800, 3200), 3107); + assertEq(bound(uint256(9999), 1337, 6666), 4669); + } + + function testBound_WithinRange() public { + assertEq(bound(uint256(51), 50, 150), 51); + assertEq(bound(uint256(51), 50, 150), bound(bound(uint256(51), 50, 150), 50, 150)); + assertEq(bound(uint256(149), 50, 150), 149); + assertEq(bound(uint256(149), 50, 150), bound(bound(uint256(149), 50, 150), 50, 150)); + } + + function testBound_EdgeCoverage() public { + assertEq(bound(uint256(0), 50, 150), 50); + assertEq(bound(uint256(1), 50, 150), 51); + assertEq(bound(uint256(2), 50, 150), 52); + assertEq(bound(uint256(3), 50, 150), 53); + assertEq(bound(type(uint256).max, 50, 150), 150); + assertEq(bound(type(uint256).max - 1, 50, 150), 149); + assertEq(bound(type(uint256).max - 2, 50, 150), 148); + assertEq(bound(type(uint256).max - 3, 50, 150), 147); + } + + function testBound_DistributionIsEven(uint256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, UINT256_MAX / 2, UINT256_MAX / 2 + size); + uint256 max = min + size - 1; + uint256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + i, min, max); + assertEq(result, min + (i - 1) % size); + // x < min + result = bound(min - i, min, max); + assertEq(result, max - (i - 1) % size); + } + } + + function testBound(uint256 num, uint256 min, uint256 max) public { + if (min > max) (min, max) = (max, min); + + uint256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundUint256Max() public { + assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1); + assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max); + } + + function testCannotBoundMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(uint256(5), 100, 10); + } + + function testCannotBoundMaxLessThanMin(uint256 num, uint256 min, uint256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + bound(num, min, max); + } + + function testBoundInt() public { + assertEq(bound(-3, 0, 4), 2); + assertEq(bound(0, -69, -69), -69); + assertEq(bound(0, -69, -68), -68); + assertEq(bound(-10, 150, 190), 154); + assertEq(bound(-300, 2800, 3200), 2908); + assertEq(bound(9999, -1337, 6666), 1995); + } + + function testBoundInt_WithinRange() public { + assertEq(bound(51, -50, 150), 51); + assertEq(bound(51, -50, 150), bound(bound(51, -50, 150), -50, 150)); + assertEq(bound(149, -50, 150), 149); + assertEq(bound(149, -50, 150), bound(bound(149, -50, 150), -50, 150)); + } + + function testBoundInt_EdgeCoverage() public { + assertEq(bound(type(int256).min, -50, 150), -50); + assertEq(bound(type(int256).min + 1, -50, 150), -49); + assertEq(bound(type(int256).min + 2, -50, 150), -48); + assertEq(bound(type(int256).min + 3, -50, 150), -47); + assertEq(bound(type(int256).min, 10, 150), 10); + assertEq(bound(type(int256).min + 1, 10, 150), 11); + assertEq(bound(type(int256).min + 2, 10, 150), 12); + assertEq(bound(type(int256).min + 3, 10, 150), 13); + + assertEq(bound(type(int256).max, -50, 150), 150); + assertEq(bound(type(int256).max - 1, -50, 150), 149); + assertEq(bound(type(int256).max - 2, -50, 150), 148); + assertEq(bound(type(int256).max - 3, -50, 150), 147); + assertEq(bound(type(int256).max, -50, -10), -10); + assertEq(bound(type(int256).max - 1, -50, -10), -11); + assertEq(bound(type(int256).max - 2, -50, -10), -12); + assertEq(bound(type(int256).max - 3, -50, -10), -13); + } + + function testBoundInt_DistributionIsEven(int256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, -int256(size / 2), int256(size - size / 2)); + int256 max = min + int256(size) - 1; + int256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + int256(i), min, max); + assertEq(result, min + int256((i - 1) % size)); + // x < min + result = bound(min - int256(i), min, max); + assertEq(result, max - int256((i - 1) % size)); + } + } + + function testBoundInt(int256 num, int256 min, int256 max) public { + if (min > max) (min, max) = (max, min); + + int256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function testBoundIntInt256Max() public { + assertEq(bound(0, type(int256).max - 1, type(int256).max), type(int256).max - 1); + assertEq(bound(1, type(int256).max - 1, type(int256).max), type(int256).max); + } + + function testBoundIntInt256Min() public { + assertEq(bound(0, type(int256).min, type(int256).min + 1), type(int256).min); + assertEq(bound(1, type(int256).min, type(int256).min + 1), type(int256).min + 1); + } + + function testCannotBoundIntMaxLessThanMin() public { + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(-5, 100, 10); + } + + function testCannotBoundIntMaxLessThanMin(int256 num, int256 min, int256 max) public { + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + bound(num, min, max); + } + + function testGenerateCreateAddress() external { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + function testGenerateCreate2Address() external { + bytes32 salt = bytes32(uint256(31415)); + bytes32 initcodeHash = keccak256(abi.encode(0x6080)); + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + address create2Address = computeCreate2Address(salt, initcodeHash, deployer); + assertEq(create2Address, 0xB147a5d25748fda14b463EB04B111027C290f4d3); + } + + function testBytesToUint() external { + bytes memory maxUint = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + bytes memory two = hex"02"; + bytes memory millionEther = hex"d3c21bcecceda1000000"; + + assertEq(bytesToUint(maxUint), type(uint256).max); + assertEq(bytesToUint(two), 2); + assertEq(bytesToUint(millionEther), 1_000_000 ether); + } + + function testCannotConvertGT32Bytes() external { + bytes memory thirty3Bytes = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + vm.expectRevert("StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + bytesToUint(thirty3Bytes); + } +} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol b/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..e205cff --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScript.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScript is Script {} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol b/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..ce8e0e9 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationScriptBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScriptBase is ScriptBase {} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol b/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..9beeafe --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTest.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTest is Test {} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol b/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..e993535 --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/compilation/CompilationTestBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTestBase is TestBase {} diff --git a/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json b/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json new file mode 100644 index 0000000..0a0200b --- /dev/null +++ b/lib/openzeppelin-contracts/lib/forge-std/test/fixtures/broadcast.log.json @@ -0,0 +1,187 @@ +{ + "transactions": [ + { + "hash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "function": "multiple_arguments(uint256,address,uint256[]):(uint256)", + "arguments": ["1", "0000000000000000000000000000000000001337", "[3,4]"], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "gas": "0x73b9", + "value": "0x0", + "data": "0x23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004", + "nonce": "0x3", + "accessList": [] + } + }, + { + "hash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "function": "inc():(uint256)", + "arguments": [], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "gas": "0xdcb2", + "value": "0x0", + "data": "0x371303c0", + "nonce": "0x4", + "accessList": [] + } + }, + { + "hash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "function": "t(uint256):(uint256)", + "arguments": ["1"], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "gas": "0x8599", + "value": "0x0", + "data": "0xafe29f710000000000000000000000000000000000000000000000000000000000000001", + "nonce": "0x5", + "accessList": [] + } + } + ], + "receipts": [ + { + "transactionHash": "0x481dc86e40bba90403c76f8e144aa9ff04c1da2164299d0298573835f0991181", + "transactionIndex": "0x0", + "blockHash": "0xef0730448490304e5403be0fa8f8ce64f118e9adcca60c07a2ae1ab921d748af", + "blockNumber": "0x1", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": null, + "cumulativeGasUsed": "0x13f3a", + "gasUsed": "0x13f3a", + "contractAddress": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x6a187183545b8a9e7f1790e847139379bf5622baff2cb43acf3f5c79470af782", + "transactionIndex": "0x0", + "blockHash": "0xf3acb96a90071640c2a8c067ae4e16aad87e634ea8d8bbbb5b352fba86ba0148", + "blockNumber": "0x2", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": null, + "cumulativeGasUsed": "0x45d80", + "gasUsed": "0x45d80", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x064ad173b4867bdef2fb60060bbdaf01735fbf10414541ea857772974e74ea9d", + "transactionIndex": "0x0", + "blockHash": "0x8373d02109d3ee06a0225f23da4c161c656ccc48fe0fcee931d325508ae73e58", + "blockNumber": "0x3", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "cumulativeGasUsed": "0x45feb", + "gasUsed": "0x45feb", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", + "transactionIndex": "0x0", + "blockHash": "0x16712fae5c0e18f75045f84363fb6b4d9a9fe25e660c4ce286833a533c97f629", + "blockNumber": "0x4", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "cumulativeGasUsed": "0x5905", + "gasUsed": "0x5905", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", + "transactionIndex": "0x0", + "blockHash": "0x156b88c3eb9a1244ba00a1834f3f70de735b39e3e59006dd03af4fe7d5480c11", + "blockNumber": "0x5", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "cumulativeGasUsed": "0xa9c4", + "gasUsed": "0xa9c4", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "transactionIndex": "0x0", + "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", + "blockNumber": "0x6", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "cumulativeGasUsed": "0x66c5", + "gasUsed": "0x66c5", + "contractAddress": null, + "logs": [ + { + "address": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "topics": [ + "0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000", + "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", + "blockNumber": "0x6", + "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "transactionIndex": "0x1", + "logIndex": "0x0", + "transactionLogIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x11fbb10230c168ca1e36a7e5c69a6dbcd04fd9e64ede39d10a83e36ee8065c16", + "transactionIndex": "0x0", + "blockHash": "0xf1e0ed2eda4e923626ec74621006ed50b3fc27580dc7b4cf68a07ca77420e29c", + "blockNumber": "0x7", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x0000000000000000000000000000000000001337", + "cumulativeGasUsed": "0x5208", + "gasUsed": "0x5208", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + } + ], + "libraries": [ + "src/Broadcast.t.sol:F:0x5fbdb2315678afecb367f032d93f642f64180aa3" + ], + "pending": [], + "path": "broadcast/Broadcast.t.sol/31337/run-latest.json", + "returns": {}, + "timestamp": 1655140035 +} diff --git a/lib/openzeppelin-contracts/logo.svg b/lib/openzeppelin-contracts/logo.svg new file mode 100644 index 0000000..f1e14c2 --- /dev/null +++ b/lib/openzeppelin-contracts/logo.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/lib/openzeppelin-contracts/netlify.toml b/lib/openzeppelin-contracts/netlify.toml new file mode 100644 index 0000000..0447f41 --- /dev/null +++ b/lib/openzeppelin-contracts/netlify.toml @@ -0,0 +1,3 @@ +[build] +command = "npm run docs" +publish = "build/site" diff --git a/lib/openzeppelin-contracts/package-lock.json b/lib/openzeppelin-contracts/package-lock.json new file mode 100644 index 0000000..0f4f9f5 --- /dev/null +++ b/lib/openzeppelin-contracts/package-lock.json @@ -0,0 +1,16544 @@ +{ + "name": "openzeppelin-solidity", + "version": "4.9.2", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "openzeppelin-solidity", + "version": "4.9.2", + "license": "MIT", + "devDependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@nomicfoundation/hardhat-foundry": "^1.1.1", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-truffle5": "^2.0.5", + "@nomiclabs/hardhat-web3": "^2.0.0", + "@openzeppelin/docs-utils": "^0.1.5", + "@openzeppelin/test-helpers": "^0.5.13", + "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", + "@openzeppelin/upgrades-core": "^1.20.6", + "array.prototype.at": "^1.1.1", + "chai": "^4.2.0", + "eslint": "^8.30.0", + "eslint-config-prettier": "^9.0.0", + "eth-sig-util": "^3.0.0", + "ethereumjs-util": "^7.0.7", + "ethereumjs-wallet": "^1.0.1", + "glob": "^10.3.5", + "graphlib": "^2.1.8", + "hardhat": "^2.9.1", + "hardhat-exposed": "^0.3.13", + "hardhat-gas-reporter": "^1.0.9", + "hardhat-ignore-warnings": "^0.2.0", + "keccak256": "^1.0.2", + "lodash.startcase": "^4.4.0", + "lodash.zip": "^4.2.0", + "merkletreejs": "^0.2.13", + "micromatch": "^4.0.2", + "p-limit": "^3.1.0", + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.1.0", + "rimraf": "^5.0.1", + "semver": "^7.3.5", + "solhint": "^3.3.6", + "solhint-plugin-openzeppelin": "file:scripts/solhint-custom", + "solidity-ast": "^0.4.50", + "solidity-coverage": "^0.8.5", + "solidity-docgen": "^0.6.0-beta.29", + "undici": "^5.22.1", + "web3": "^1.3.0", + "yargs": "^17.0.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "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.4", + "resolved": "https://registry.npmjs.org/@changesets/apply-release-plan/-/apply-release-plan-6.1.4.tgz", + "integrity": "sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/config": "^2.3.1", + "@changesets/get-version-range-type": "^0.3.2", + "@changesets/git": "^2.0.0", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "detect-indent": "^6.0.0", + "fs-extra": "^7.0.1", + "lodash.startcase": "^4.4.0", + "outdent": "^0.5.0", + "prettier": "^2.7.1", + "resolve-from": "^5.0.0", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/apply-release-plan/node_modules/prettier": { + "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" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@changesets/assemble-release-plan": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@changesets/assemble-release-plan/-/assemble-release-plan-5.2.4.tgz", + "integrity": "sha512-xJkWX+1/CUaOUWTguXEbCDTyWJFECEhmdtbkjhn5GVBGxdP/JwaHBIU9sW3FR6gD07UwZ7ovpiPclQZs+j+mvg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.6", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "semver": "^7.5.3" + } + }, + "node_modules/@changesets/changelog-git": { + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/@changesets/changelog-git/-/changelog-git-0.1.14.tgz", + "integrity": "sha512-+vRfnKtXVWsDDxGctOfzJsPhaCdXRYoe+KyWYoq5X/GqoISREiat0l3L8B0a453B2B4dfHGcZaGyowHbp9BSaA==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1" + } + }, + "node_modules/@changesets/changelog-github": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@changesets/changelog-github/-/changelog-github-0.4.8.tgz", + "integrity": "sha512-jR1DHibkMAb5v/8ym77E4AMNWZKB5NPzw5a5Wtqm1JepAuIF+hrKp2u04NKM14oBZhHglkCfrla9uq8ORnK/dw==", + "dev": true, + "dependencies": { + "@changesets/get-github-info": "^0.5.2", + "@changesets/types": "^5.2.1", + "dotenv": "^8.1.0" + } + }, + "node_modules/@changesets/cli": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/@changesets/cli/-/cli-2.26.2.tgz", + "integrity": "sha512-dnWrJTmRR8bCHikJHl9b9HW3gXACCehz4OasrXpMp7sx97ECuBGGNjJhjPhdZNCvMy9mn4BWdplI323IbqsRig==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/apply-release-plan": "^6.1.4", + "@changesets/assemble-release-plan": "^5.2.4", + "@changesets/changelog-git": "^0.1.14", + "@changesets/config": "^2.3.1", + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.6", + "@changesets/get-release-plan": "^3.0.17", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@changesets/write": "^0.2.3", + "@manypkg/get-packages": "^1.1.3", + "@types/is-ci": "^3.0.0", + "@types/semver": "^7.5.0", + "ansi-colors": "^4.1.3", + "chalk": "^2.1.0", + "enquirer": "^2.3.0", + "external-editor": "^3.1.0", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "is-ci": "^3.0.1", + "meow": "^6.0.0", + "outdent": "^0.5.0", + "p-limit": "^2.2.0", + "preferred-pm": "^3.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "spawndamnit": "^2.0.0", + "term-size": "^2.1.0", + "tty-table": "^4.1.5" + }, + "bin": { + "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/config": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@changesets/config/-/config-2.3.1.tgz", + "integrity": "sha512-PQXaJl82CfIXddUOppj4zWu+987GCw2M+eQcOepxN5s+kvnsZOwjEJO3DH9eVy+OP6Pg/KFEWdsECFEYTtbg6w==", + "dev": true, + "dependencies": { + "@changesets/errors": "^0.1.4", + "@changesets/get-dependents-graph": "^1.3.6", + "@changesets/logger": "^0.0.5", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1", + "micromatch": "^4.0.2" + } + }, + "node_modules/@changesets/errors": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@changesets/errors/-/errors-0.1.4.tgz", + "integrity": "sha512-HAcqPF7snsUJ/QzkWoKfRfXushHTu+K5KZLJWPb34s4eCZShIf8BFO3fwq6KU8+G7L5KdtN2BzQAXOSXEyiY9Q==", + "dev": true, + "dependencies": { + "extendable-error": "^0.1.5" + } + }, + "node_modules/@changesets/get-dependents-graph": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@changesets/get-dependents-graph/-/get-dependents-graph-1.3.6.tgz", + "integrity": "sha512-Q/sLgBANmkvUm09GgRsAvEtY3p1/5OCzgBE5vX3vgb5CvW0j7CEljocx5oPXeQSNph6FXulJlXV3Re/v3K3P3Q==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "semver": "^7.5.3" + } + }, + "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", + "integrity": "sha512-JppheLu7S114aEs157fOZDjFqUDpm7eHdq5E8SSR0gUBTEK0cNSHsrSR5a66xs0z3RWuo46QvA3vawp8BxDHvg==", + "dev": true, + "dependencies": { + "dataloader": "^1.4.0", + "node-fetch": "^2.5.0" + } + }, + "node_modules/@changesets/get-release-plan": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/@changesets/get-release-plan/-/get-release-plan-3.0.17.tgz", + "integrity": "sha512-6IwKTubNEgoOZwDontYc2x2cWXfr6IKxP3IhKeK+WjyD6y3M4Gl/jdQvBw+m/5zWILSOCAaGLu2ZF6Q+WiPniw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/assemble-release-plan": "^5.2.4", + "@changesets/config": "^2.3.1", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3" + } + }, + "node_modules/@changesets/get-version-range-type": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@changesets/get-version-range-type/-/get-version-range-type-0.3.2.tgz", + "integrity": "sha512-SVqwYs5pULYjYT4op21F2pVbcrca4qA/bAA3FmFXKMN7Y+HcO8sbZUTx3TAy2VXulP2FACd1aC7f2nTuqSPbqg==", + "dev": true + }, + "node_modules/@changesets/git": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@changesets/git/-/git-2.0.0.tgz", + "integrity": "sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "is-subdir": "^1.1.1", + "micromatch": "^4.0.2", + "spawndamnit": "^2.0.0" + } + }, + "node_modules/@changesets/logger": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@changesets/logger/-/logger-0.0.5.tgz", + "integrity": "sha512-gJyZHomu8nASHpaANzc6bkQMO9gU/ib20lqew1rVx753FOxffnCrJlGIeQVxNWCqM+o6OOleCo/ivL8UAO5iFw==", + "dev": true, + "dependencies": { + "chalk": "^2.1.0" + } + }, + "node_modules/@changesets/parse": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@changesets/parse/-/parse-0.3.16.tgz", + "integrity": "sha512-127JKNd167ayAuBjUggZBkmDS5fIKsthnr9jr6bdnuUljroiERW7FBTDNnNVyJ4l69PzR57pk6mXQdtJyBCJKg==", + "dev": true, + "dependencies": { + "@changesets/types": "^5.2.1", + "js-yaml": "^3.13.1" + } + }, + "node_modules/@changesets/pre": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@changesets/pre/-/pre-1.0.14.tgz", + "integrity": "sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/errors": "^0.1.4", + "@changesets/types": "^5.2.1", + "@manypkg/get-packages": "^1.1.3", + "fs-extra": "^7.0.1" + } + }, + "node_modules/@changesets/read": { + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/@changesets/read/-/read-0.5.9.tgz", + "integrity": "sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/git": "^2.0.0", + "@changesets/logger": "^0.0.5", + "@changesets/parse": "^0.3.16", + "@changesets/types": "^5.2.1", + "chalk": "^2.1.0", + "fs-extra": "^7.0.1", + "p-filter": "^2.1.0" + } + }, + "node_modules/@changesets/types": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-5.2.1.tgz", + "integrity": "sha512-myLfHbVOqaq9UtUKqR/nZA/OY7xFjQMdfgfqeZIBK4d0hA6pgxArvdv8M+6NUzzBsjWLOtvApv8YHr4qM+Kpfg==", + "dev": true + }, + "node_modules/@changesets/write": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@changesets/write/-/write-0.2.3.tgz", + "integrity": "sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.20.1", + "@changesets/types": "^5.2.1", + "fs-extra": "^7.0.1", + "human-id": "^1.0.2", + "prettier": "^2.7.1" + } + }, + "node_modules/@changesets/write/node_modules/prettier": { + "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" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/@ensdomains/address-encoder": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ensdomains/address-encoder/-/address-encoder-0.1.9.tgz", + "integrity": "sha512-E2d2gP4uxJQnDu2Kfg1tHNspefzbLT8Tyjrm5sEuim32UkU2sm5xL4VXtgc2X33fmPEw9+jUMpGs4veMbf+PYg==", + "dev": true, + "dependencies": { + "bech32": "^1.1.3", + "blakejs": "^1.1.0", + "bn.js": "^4.11.8", + "bs58": "^4.0.1", + "crypto-addr-codec": "^0.1.7", + "nano-base32": "^1.0.1", + "ripemd160": "^2.0.2" + } + }, + "node_modules/@ensdomains/ens": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@ensdomains/ens/-/ens-0.4.5.tgz", + "integrity": "sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true, + "dependencies": { + "bluebird": "^3.5.2", + "eth-ens-namehash": "^2.0.8", + "solc": "^0.4.20", + "testrpc": "0.0.1", + "web3-utils": "^1.0.0-beta.31" + } + }, + "node_modules/@ensdomains/ensjs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@ensdomains/ensjs/-/ensjs-2.1.0.tgz", + "integrity": "sha512-GRbGPT8Z/OJMDuxs75U/jUNEC0tbL0aj7/L/QQznGYKm/tiasp+ndLOaoULy9kKJFC0TBByqfFliEHDgoLhyog==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.4.4", + "@ensdomains/address-encoder": "^0.1.7", + "@ensdomains/ens": "0.4.5", + "@ensdomains/resolver": "0.2.4", + "content-hash": "^2.5.2", + "eth-ens-namehash": "^2.0.8", + "ethers": "^5.0.13", + "js-sha3": "^0.8.0" + } + }, + "node_modules/@ensdomains/ensjs/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/@ensdomains/resolver": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@ensdomains/resolver/-/resolver-0.2.4.tgz", + "integrity": "sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA==", + "deprecated": "Please use @ensdomains/ens-contracts", + "dev": true + }, + "node_modules/@eslint-community/eslint-utils": { + "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" + }, + "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.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/js": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", + "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", + "integrity": "sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg==", + "dev": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.1" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", + "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.3.2.tgz", + "integrity": "sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "^2.5.0", + "ethereumjs-util": "^7.1.2" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "dev": true, + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "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/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "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/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bignumber/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/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "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/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "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/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "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" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "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/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "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/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/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key/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/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "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/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "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/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^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/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "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/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "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/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@frangio/servbot": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@frangio/servbot/-/servbot-0.2.5.tgz", + "integrity": "sha512-ogja4iAPZ1VwM5MU3C1ZhB88358F0PGbmSTGOkIZwOyLaDoMHIqOVCnavHjR7DV5h+oAI4Z4KDqlam3myQUrmg==", + "dev": true, + "engines": { + "node": ">=12.x", + "pnpm": "7.5.1" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@manypkg/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@manypkg/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@types/node": "^12.7.1", + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "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", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@manypkg/get-packages": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@manypkg/get-packages/-/get-packages-1.1.3.tgz", + "integrity": "sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@changesets/types": "^4.0.1", + "@manypkg/find-root": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "^11.0.0", + "read-yaml-file": "^1.1.0" + } + }, + "node_modules/@manypkg/get-packages/node_modules/@changesets/types": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@changesets/types/-/types-4.1.0.tgz", + "integrity": "sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==", + "dev": true + }, + "node_modules/@manypkg/get-packages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "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", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.3.1" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/secp256k1": { + "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": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.2.tgz", + "integrity": "sha512-hSe6CuHI4SsSiWWjHDIzWhSiAVpzMUcDRpWYzN0T9l8/Rz7xNn3elwVOJ/tAyS0LqL6vitUD78Uk7lQDXZun7Q==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "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": "7.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.2.tgz", + "integrity": "sha512-8UUsSXJs+MFfIIAKdh3cG16iNmWzWC/91P40sazNvrqhhdR/RtGDlFk2iFTGbBAZPs2+klZVzhRX8m2wvuvz3w==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-ethash": "3.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-common": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.2.tgz", + "integrity": "sha512-I2WGP3HMGsOoycSdOTSqIaES0ughQTueOsddJ36aYVpI3SN8YSusgRFLwzDJwRFVIYDKx/iJz0sQ5kBHVgdDwg==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-util": "9.0.2", + "crc-32": "^1.2.0" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.2.tgz", + "integrity": "sha512-8PfoOQCcIcO9Pylq0Buijuq/O73tmMVURK0OqdjhwqcGHYC2PwhbajDh7GZ55ekB0Px197ajK3PQhpKoiI/UPg==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.2.tgz", + "integrity": "sha512-rBLcUaUfANJxyOx9HIdMX6uXGin6lANCulIm/pjMgRqfiCRMZie3WKYxTSd8ZE/d+qT+zTedBF4+VHTdTSePmQ==", + "dev": true, + "dependencies": { + "@ethersproject/providers": "^5.7.1", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-rlp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.2.tgz", + "integrity": "sha512-QwmemBc+MMsHJ1P1QvPl8R8p2aPvvVcKBbvHnQOKBpBztEo0omN0eaob6FeZS/e3y9NSe+mfu3nNFBHszqkjTA==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.2.tgz", + "integrity": "sha512-dlKy5dIXLuDubx8Z74sipciZnJTRSV/uHG48RSijhgm1V7eXYFC567xgKtsKiVZB1ViTP9iFL4B6Je0xD6X2OA==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "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": "6.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.2.tgz", + "integrity": "sha512-yw8vg9hBeLYk4YNg5MrSJ5H55TLOv2FSWUTROtDtTMMmDGROsAu+0tBjiNGTnKRi400M6cEzoFfa89Fc5k8NTQ==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@types/readable-stream": "^2.3.13", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.2.tgz", + "integrity": "sha512-T+l4/MmTp7VhJeNloMkM+lPU3YMUaXdcXgTGCf8+ZFvV9NYZTRLFekRwlG6/JMmVfIfbrW+dRRJ9A6H5Q/Z64g==", + "dev": true, + "dependencies": { + "@chainsafe/ssz": "^0.9.2", + "@ethersproject/providers": "^5.7.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.2.tgz", + "integrity": "sha512-4Wu9D3LykbSBWZo8nJCnzVIYGvGCuyiYLIJa9XXNVt1q1jUzHdB+sJvx95VGCpPkCT+IbLecW6yfzy3E1bQrwQ==", + "dev": true, + "dependencies": { + "@chainsafe/ssz": "^0.10.0", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "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": { + "@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.2", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.2.tgz", + "integrity": "sha512-Bj3KZT64j54Tcwr7Qm/0jkeZXJMfdcAtRBedou+Hx0dPOSIgqaIr0vvLwP65TpHbak2DmAq+KJbW2KNtIoFwvA==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/hardhat-foundry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-foundry/-/hardhat-foundry-1.1.1.tgz", + "integrity": "sha512-cXGCBHAiXas9Pg9MhMOpBVQCkWRYoRFG7GJJAph+sdQsfd22iRs5U5Vs9XmpGEQd1yEvYISQZMeE68Nxj65iUQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "peerDependencies": { + "hardhat": "^2.17.2" + } + }, + "node_modules/@nomicfoundation/hardhat-network-helpers": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.9.tgz", + "integrity": "sha512-OXWCv0cHpwLUO2u7bFxBna6dQtCC2Gg/aN/KtJLO7gmuuA28vgmVKYFRCDUqrbjujzgfwQ2aKyZ9Y3vSmDqS7Q==", + "dev": true, + "dependencies": { + "ethereumjs-util": "^7.1.4" + }, + "peerDependencies": { + "hardhat": "^2.9.5" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer": { + "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.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.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" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-darwin-x64": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-freebsd-x64": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-gnu": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-arm64-musl": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-gnu": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-linux-x64-musl": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-arm64-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-ia32-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomicfoundation/solidity-analyzer-win32-x64-msvc": { + "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" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nomiclabs/hardhat-truffle5": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-truffle5/-/hardhat-truffle5-2.0.7.tgz", + "integrity": "sha512-Pw8451IUZp1bTp0QqCHCYfCHs66sCnyxPcaorapu9mfOV9xnZsVaFdtutnhNEiXdiZwbed7LFKpRsde4BjFwig==", + "dev": true, + "dependencies": { + "@nomiclabs/truffle-contract": "^4.2.23", + "@types/chai": "^4.2.0", + "chai": "^4.2.0", + "ethereumjs-util": "^7.1.4", + "fs-extra": "^7.0.1" + }, + "peerDependencies": { + "@nomiclabs/hardhat-web3": "^2.0.0", + "hardhat": "^2.6.4", + "web3": "^1.0.0-beta.36" + } + }, + "node_modules/@nomiclabs/hardhat-web3": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-web3/-/hardhat-web3-2.0.0.tgz", + "integrity": "sha512-zt4xN+D+fKl3wW2YlTX3k9APR3XZgPkxJYf36AcliJn3oujnKEVRZaHu0PhgLjO+gR+F/kiYayo9fgd2L8970Q==", + "dev": true, + "dependencies": { + "@types/bignumber.js": "^5.0.0" + }, + "peerDependencies": { + "hardhat": "^2.0.0", + "web3": "^1.0.0-beta.36" + } + }, + "node_modules/@nomiclabs/truffle-contract": { + "version": "4.5.10", + "resolved": "https://registry.npmjs.org/@nomiclabs/truffle-contract/-/truffle-contract-4.5.10.tgz", + "integrity": "sha512-nF/6InFV+0hUvutyFgsdOMCoYlr//2fJbRER4itxYtQtc4/O1biTwZIKRu+5l2J5Sq6LU2WX7vZHtDgQdhWxIQ==", + "dev": true, + "dependencies": { + "@ensdomains/ensjs": "^2.0.1", + "@truffle/blockchain-utils": "^0.1.3", + "@truffle/contract-schema": "^3.4.7", + "@truffle/debug-utils": "^6.0.22", + "@truffle/error": "^0.1.0", + "@truffle/interface-adapter": "^0.5.16", + "bignumber.js": "^7.2.1", + "ethereum-ens": "^0.8.0", + "ethers": "^4.0.0-beta.1", + "source-map-support": "^0.5.19" + }, + "peerDependencies": { + "web3": "^1.2.1", + "web3-core-helpers": "^1.2.1", + "web3-core-promievent": "^1.2.1", + "web3-eth-abi": "^1.2.1", + "web3-utils": "^1.2.1" + } + }, + "node_modules/@openzeppelin/contract-loader": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz", + "integrity": "sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "fs-extra": "^8.1.0" + } + }, + "node_modules/@openzeppelin/contract-loader/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/@openzeppelin/docs-utils": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@openzeppelin/docs-utils/-/docs-utils-0.1.5.tgz", + "integrity": "sha512-GfqXArKmdq8rv+hsP+g8uS1VEkvMIzWs31dCONffzmqFwJ+MOsaNQNZNXQnLRgUkzk8i5mTNDjJuxDy+aBZImQ==", + "dev": true, + "dependencies": { + "@frangio/servbot": "^0.2.5", + "chalk": "^3.0.0", + "chokidar": "^3.5.3", + "env-paths": "^2.2.0", + "find-up": "^4.1.0", + "is-port-reachable": "^3.0.0", + "js-yaml": "^3.13.1", + "lodash.startcase": "^4.4.0", + "minimist": "^1.2.0" + }, + "bin": { + "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", + "integrity": "sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg==", + "dev": true, + "dependencies": { + "@openzeppelin/contract-loader": "^0.6.2", + "@truffle/contract": "^4.0.35", + "ansi-colors": "^3.2.3", + "chai": "^4.2.0", + "chai-bn": "^0.2.1", + "ethjs-abi": "^0.2.1", + "lodash.flatten": "^4.4.0", + "semver": "^5.6.0", + "web3": "^1.2.5", + "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.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler": { + "version": "0.3.32", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrade-safe-transpiler/-/upgrade-safe-transpiler-0.3.32.tgz", + "integrity": "sha512-ypgj6MXXcDG0dOuMwENXt0H4atCtCsPgpDgWZYewb2egfUCMpj6d2GO4pcNZgdn1zYsmUHfm5ZA/Nga/8qkdKA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0", + "compare-versions": "^6.0.0", + "ethereum-cryptography": "^2.0.0", + "lodash": "^4.17.20", + "minimatch": "^9.0.0", + "minimist": "^1.2.5", + "solidity-ast": "^0.4.51" + }, + "bin": { + "upgrade-safe-transpiler": "dist/cli.js" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/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/@openzeppelin/upgrade-safe-transpiler/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/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/@openzeppelin/upgrade-safe-transpiler/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@openzeppelin/upgrade-safe-transpiler/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/@openzeppelin/upgrades-core": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/upgrades-core/-/upgrades-core-1.29.0.tgz", + "integrity": "sha512-csZvAMNqUJjMDNBPbaXcV9Nlo4oagMD/HkOBHTpYbBTpnmUhwPVHOMv+Rl0RatBdLHuGc6hw88h80k5PWkEeWw==", + "dev": true, + "dependencies": { + "cbor": "^9.0.0", + "chalk": "^4.1.0", + "compare-versions": "^6.0.0", + "debug": "^4.1.1", + "ethereumjs-util": "^7.0.3", + "minimist": "^1.2.7", + "proper-lockfile": "^4.1.1", + "solidity-ast": "^0.4.26" + }, + "bin": { + "openzeppelin-upgrades-core": "dist/cli/cli.js" + } + }, + "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": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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/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": ">=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/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@scure/base": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.3.tgz", + "integrity": "sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==", + "dev": true, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dev": true, + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dev": true, + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@solidity-parser/parser": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", + "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@truffle/abi-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@truffle/abi-utils/-/abi-utils-1.0.3.tgz", + "integrity": "sha512-AWhs01HCShaVKjml7Z4AbVREr/u4oiWxCcoR7Cktm0mEvtT04pvnxW5xB/cI4znRkrbPdFQlFt67kgrAjesYkw==", + "dev": true, + "dependencies": { + "change-case": "3.0.2", + "fast-check": "3.1.1", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "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.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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.9", + "resolved": "https://registry.npmjs.org/@truffle/blockchain-utils/-/blockchain-utils-0.1.9.tgz", + "integrity": "sha512-RHfumgbIVo68Rv9ofDYfynjnYZIfP/f1vZy4RoqkfYAO+fqfc58PDRzB1WAGq2U6GPuOnipOJxQhnqNnffORZg==", + "dev": true, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/codec": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@truffle/codec/-/codec-0.17.3.tgz", + "integrity": "sha512-Ko/+dsnntNyrJa57jUD9u4qx9nQby+H4GsUO6yjiCPSX0TQnEHK08XWqBSg0WdmCH2+h0y1nr2CXSx8gbZapxg==", + "dev": true, + "dependencies": { + "@truffle/abi-utils": "^1.0.3", + "@truffle/compile-common": "^0.9.8", + "big.js": "^6.0.3", + "bn.js": "^5.1.3", + "cbor": "^5.2.0", + "debug": "^4.3.1", + "lodash": "^4.17.21", + "semver": "^7.5.4", + "utf8": "^3.0.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/codec/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/codec/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/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/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/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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/compile-common": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@truffle/compile-common/-/compile-common-0.9.8.tgz", + "integrity": "sha512-DTpiyo32t/YhLI1spn84D3MHYHrnoVqO+Gp7ZHrYNwDs86mAxtNiH5lsVzSb8cPgiqlvNsRCU9nm9R0YmKMTBQ==", + "dev": true, + "dependencies": { + "@truffle/error": "^0.2.2", + "colors": "1.4.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/compile-common/node_modules/@truffle/error": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.2.tgz", + "integrity": "sha512-TqbzJ0O8DHh34cu8gDujnYl4dUl6o2DE4PR6iokbybvnIm/L2xl6+Gv1VC+YJS45xfH83Yo3/Zyg/9Oq8/xZWg==", + "dev": true, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract": { + "version": "4.6.31", + "resolved": "https://registry.npmjs.org/@truffle/contract/-/contract-4.6.31.tgz", + "integrity": "sha512-s+oHDpXASnZosiCdzu+X1Tx5mUJUs1L1CYXIcgRmzMghzqJkaUFmR6NpNo7nJYliYbO+O9/aW8oCKqQ7rCHfmQ==", + "dev": true, + "dependencies": { + "@ensdomains/ensjs": "^2.1.0", + "@truffle/blockchain-utils": "^0.1.9", + "@truffle/contract-schema": "^3.4.16", + "@truffle/debug-utils": "^6.0.57", + "@truffle/error": "^0.2.2", + "@truffle/interface-adapter": "^0.5.37", + "bignumber.js": "^7.2.1", + "debug": "^4.3.1", + "ethers": "^4.0.32", + "web3": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract-schema": { + "version": "3.4.16", + "resolved": "https://registry.npmjs.org/@truffle/contract-schema/-/contract-schema-3.4.16.tgz", + "integrity": "sha512-g0WNYR/J327DqtJPI70ubS19K1Fth/1wxt2jFqLsPmz5cGZVjCwuhiie+LfBde4/Mc9QR8G+L3wtmT5cyoBxAg==", + "dev": true, + "dependencies": { + "ajv": "^6.10.0", + "debug": "^4.3.1" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract/node_modules/@truffle/error": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.2.2.tgz", + "integrity": "sha512-TqbzJ0O8DHh34cu8gDujnYl4dUl6o2DE4PR6iokbybvnIm/L2xl6+Gv1VC+YJS45xfH83Yo3/Zyg/9Oq8/xZWg==", + "dev": true, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/contract/node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "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": { + "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.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/contract/node_modules/web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "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.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-abi": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz", + "integrity": "sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "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.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/contract/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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.57", + "resolved": "https://registry.npmjs.org/@truffle/debug-utils/-/debug-utils-6.0.57.tgz", + "integrity": "sha512-Q6oI7zLaeNLB69ixjwZk2UZEWBY6b2OD1sjLMGDKBGR7GaHYiw96GLR2PFgPH1uwEeLmV4N78LYaQCrDsHbNeA==", + "dev": true, + "dependencies": { + "@truffle/codec": "^0.17.3", + "@trufflesuite/chromafi": "^3.0.0", + "bn.js": "^5.1.3", + "chalk": "^2.4.2", + "debug": "^4.3.1", + "highlightjs-solidity": "^2.0.6" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/debug-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/error": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@truffle/error/-/error-0.1.1.tgz", + "integrity": "sha512-sE7c9IHIGdbK4YayH4BC8i8qMjoAOeg6nUXUDZZp8wlU21/EMpaG+CLx+KqcIPyR+GSWIW3Dm0PXkr2nlggFDA==", + "dev": true + }, + "node_modules/@truffle/interface-adapter": { + "version": "0.5.37", + "resolved": "https://registry.npmjs.org/@truffle/interface-adapter/-/interface-adapter-0.5.37.tgz", + "integrity": "sha512-lPH9MDgU+7sNDlJSClwyOwPCfuOimqsCx0HfGkznL3mcFRymc1pukAR1k17zn7ErHqBwJjiKAZ6Ri72KkS+IWw==", + "dev": true, + "dependencies": { + "bn.js": "^5.1.3", + "ethers": "^4.0.32", + "web3": "1.10.0" + }, + "engines": { + "node": "^16.20 || ^18.16 || >=20" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "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/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.0.tgz", + "integrity": "sha512-YfKY9wSkGcM8seO+daR89oVTcbu18NsVfvOngzqMYGUU0pPSQmE57qQDvQzUeoIOHAnXEBNzrhjQJmm8ER0rng==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.0", + "web3-core": "1.10.0", + "web3-eth": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-shh": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-bzz": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.0.tgz", + "integrity": "sha512-o9IR59io3pDUsXTsps5pO5hW1D5zBmg46iNc2t4j2DkaYHNdDLwk2IP9ukoM2wg47QILfPEJYzhTfkS/CcX0KA==", + "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.10.0", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.0.tgz", + "integrity": "sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-requestmanager": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-method": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.0.tgz", + "integrity": "sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-requestmanager": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz", + "integrity": "sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.0", + "web3-providers-http": "1.10.0", + "web3-providers-ipc": "1.10.0", + "web3-providers-ws": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-core-subscriptions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz", + "integrity": "sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.0.tgz", + "integrity": "sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-accounts": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-eth-ens": "1.10.0", + "web3-eth-iban": "1.10.0", + "web3-eth-personal": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-abi": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz", + "integrity": "sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-accounts": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz", + "integrity": "sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q==", + "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.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-contract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz", + "integrity": "sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-ens": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz", + "integrity": "sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-promievent": "1.10.0", + "web3-eth-abi": "1.10.0", + "web3-eth-contract": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-eth-personal": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz", + "integrity": "sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.0", + "web3-core-helpers": "1.10.0", + "web3-core-method": "1.10.0", + "web3-net": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-net": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.0.tgz", + "integrity": "sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA==", + "dev": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-http": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.0.tgz", + "integrity": "sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.3", + "cross-fetch": "^3.1.4", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ipc": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz", + "integrity": "sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-providers-ws": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz", + "integrity": "sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.0", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-shh": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.0.tgz", + "integrity": "sha512-uNUUuNsO2AjX41GJARV9zJibs11eq6HtOe6Wr0FtRUcj8SN6nHeYIzwstAvJ4fXA53gRqFMTxdntHEt9aXVjpg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.0", + "web3-core-method": "1.10.0", + "web3-core-subscriptions": "1.10.0", + "web3-net": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@truffle/interface-adapter/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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", + "integrity": "sha512-oqWcOqn8nT1bwlPPfidfzS55vqcIDdpfzo3HbU9EnUmcSTX+I8z0UyUFI3tZQjByVJulbzxHxUGS3ZJPwK/GPQ==", + "dev": true, + "dependencies": { + "camelcase": "^4.1.0", + "chalk": "^2.3.2", + "cheerio": "^1.0.0-rc.2", + "detect-indent": "^5.0.0", + "highlight.js": "^10.4.1", + "lodash.merge": "^4.6.2", + "strip-ansi": "^4.0.0", + "strip-indent": "^2.0.0" + } + }, + "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, + "engines": { + "node": ">=4" + } + }, + "node_modules/@types/bignumber.js": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bignumber.js/-/bignumber.js-5.0.0.tgz", + "integrity": "sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==", + "deprecated": "This is a stub types definition for bignumber.js (https://github.com/MikeMcl/bignumber.js/). bignumber.js provides its own type definitions, so you don't need @types/bignumber.js installed!", + "dev": true, + "dependencies": { + "bignumber.js": "*" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-dkpZu0szUtn9UXTmw+e0AJFd4D2XAxDnsCLdc05SfqpqzPEBft8eQr8uaFitfo/dUUOZERaLec2hHMG87A4Dxg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==", + "dev": true + }, + "node_modules/@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", + "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==", + "dev": true + }, + "node_modules/@types/is-ci": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.1.0" + } + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "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/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.8", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "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", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==", + "dev": true + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz", + "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==", + "dev": true + }, + "node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/abstract-level/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/aes-js": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.1.2.tgz", + "integrity": "sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ==", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.4.2" + } + }, + "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/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/antlr4": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.1.tgz", + "integrity": "sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array.prototype.at": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.at/-/array.prototype.at-1.1.2.tgz", + "integrity": "sha512-TPj626jUZMc2Qbld8uXKZrXM/lSStx2KfbIyF70Ui9RgdgibpTWC6WGCuff6qQ7xYzqXtir60WAHrfmknkF3Vw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.3.tgz", + "integrity": "sha512-kcBubumjciBg4JKp5KTKtI7ec7tRefPk88yjkWJwaVKYd9QfTaxcsOxoMNKd7iBr447zCfDV0z1kOF47umv42g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-array-buffer": "^3.0.2", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/ast-parents": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/ast-parents/-/ast-parents-0.0.1.tgz", + "integrity": "sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA==", + "dev": true + }, + "node_modules/astral-regex": { + "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": ">=8" + } + }, + "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/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "dev": true + }, + "node_modules/axios": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "dev": true, + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/big.js": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.1.tgz", + "integrity": "sha512-bCtHMwL9LeDIozFn+oNhhFoq+yQ3BNdnsLSASUxLciOb1vgvpHsIO1dsENiGMgbb4SkP5TrzWzRiLddn8ahVOQ==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "node_modules/bigint-crypto-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz", + "integrity": "sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "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/body-parser": { + "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.5", + "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.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "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", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/breakword": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/breakword/-/breakword-1.0.6.tgz", + "integrity": "sha512-yjxDAYyK/pBvws9H4xKYpLDpYKEH6CzrBPAuXq3x18I+c/2MkVtT3qAr7Oloi6Dss9qNhPVueAAVU1CSeNDIXw==", + "dev": true, + "dependencies": { + "wcwidth": "^1.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "node_modules/browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-reverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==", + "dev": true + }, + "node_modules/buffer-to-arraybuffer": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz", + "integrity": "sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/bufferutil": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz", + "integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable-lookup": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", + "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", + "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/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/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", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cbor": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-9.0.1.tgz", + "integrity": "sha512-/TQOWyamDxvVIv+DY9cOLNuABkoyz8K/F3QE56539pGVYohx0+MEA1f4lChFTX79dBTBS7R1PF6ovH7G+VtBfQ==", + "dev": true, + "dependencies": { + "nofilter": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/chai": { + "version": "4.3.8", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.8.tgz", + "integrity": "sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-bn": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/chai-bn/-/chai-bn-0.2.2.tgz", + "integrity": "sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg==", + "dev": true, + "peerDependencies": { + "bn.js": "^4.11.0", + "chai": "^4.0.0" + } + }, + "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/change-case": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz", + "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "constant-case": "^2.0.0", + "dot-case": "^2.1.0", + "header-case": "^1.0.0", + "is-lower-case": "^1.1.0", + "is-upper-case": "^1.1.0", + "lower-case": "^1.1.1", + "lower-case-first": "^1.0.0", + "no-case": "^2.3.2", + "param-case": "^2.1.0", + "pascal-case": "^2.0.0", + "path-case": "^2.1.0", + "sentence-case": "^2.1.0", + "snake-case": "^2.1.0", + "swap-case": "^1.1.0", + "title-case": "^2.1.0", + "upper-case": "^1.1.1", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dev": true, + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/ci-info": { + "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", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/cids/node_modules/multicodec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.4.tgz", + "integrity": "sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-is": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz", + "integrity": "sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw==", + "dev": true + }, + "node_modules/classic-level": { + "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.2.2", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-table3": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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/cliui/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "node_modules/commander": { + "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" + } + }, + "node_modules/compare-versions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz", + "integrity": "sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "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", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-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/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/constant-case": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz", + "integrity": "sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==", + "dev": true, + "dependencies": { + "snake-case": "^2.1.0", + "upper-case": "^1.1.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-hash": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/content-hash/-/content-hash-2.5.2.tgz", + "integrity": "sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw==", + "dev": true, + "dependencies": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "node_modules/content-type": { + "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" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-addr-codec": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.8.tgz", + "integrity": "sha512-GqAK90iLLgP3FvhNmHbpT3wR6dEdaM8hZyZtLX29SPardh3OA13RFLHDR6sntGCgRWOfiHqW6sIyohpNqOtV/g==", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, + "node_modules/crypto-js": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==", + "dev": true + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/csv": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz", + "integrity": "sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==", + "dev": true, + "dependencies": { + "csv-generate": "^3.4.3", + "csv-parse": "^4.16.3", + "csv-stringify": "^5.6.5", + "stream-transform": "^2.1.3" + }, + "engines": { + "node": ">= 0.1.90" + } + }, + "node_modules/csv-generate": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz", + "integrity": "sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==", + "dev": true + }, + "node_modules/csv-parse": { + "version": "4.16.3", + "resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz", + "integrity": "sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==", + "dev": true + }, + "node_modules/csv-stringify": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz", + "integrity": "sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dataloader": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-1.4.0.tgz", + "integrity": "sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==", + "dev": true + }, + "node_modules/death": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/death/-/death-1.1.0.tgz", + "integrity": "sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", + "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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/detect-port": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.5.1.tgz", + "integrity": "sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==", + "dev": true, + "dependencies": { + "address": "^1.0.1", + "debug": "4" + }, + "bin": { + "detect": "bin/detect-port.js", + "detect-port": "bin/detect-port.js" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/difflib": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/difflib/-/difflib-0.2.4.tgz", + "integrity": "sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==", + "dev": true, + "dependencies": { + "heap": ">= 0.2.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "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.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz", + "integrity": "sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/enquirer/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/enquirer/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/entities": { + "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" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", + "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.1", + "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.5", + "is-array-buffer": "^3.0.2", + "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.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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/escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A==", + "dev": true, + "dependencies": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=0.12.0" + }, + "optionalDependencies": { + "source-map": "~0.2.0" + } + }, + "node_modules/escodegen/node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/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/escodegen/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/escodegen/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/eslint": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "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": { + "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": ">=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", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/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/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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "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", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "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.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "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" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eth-ens-namehash": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz", + "integrity": "sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw==", + "dev": true, + "dependencies": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "node_modules/eth-ens-namehash/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/eth-gas-reporter": { + "version": "0.2.27", + "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz", + "integrity": "sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.14.0", + "axios": "^1.5.1", + "cli-table3": "^0.5.0", + "colors": "1.4.0", + "ethereum-cryptography": "^1.0.3", + "ethers": "^5.7.2", + "fs-readdir-recursive": "^1.1.0", + "lodash": "^4.17.14", + "markdown-table": "^1.1.3", + "mocha": "^10.2.0", + "req-cwd": "^2.0.0", + "sha1": "^1.1.1", + "sync-request": "^6.0.0" + }, + "peerDependencies": { + "@codechecks/client": "^0.1.0" + }, + "peerDependenciesMeta": { + "@codechecks/client": { + "optional": true + } + } + }, + "node_modules/eth-gas-reporter/node_modules/@noble/hashes": { + "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": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/eth-gas-reporter/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/eth-gas-reporter/node_modules/ethereum-cryptography": { + "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.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/eth-gas-reporter/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/eth-lib": { + "version": "0.1.29", + "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.29.tgz", + "integrity": "sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/eth-lib/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/eth-lib/node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/eth-sig-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-3.0.1.tgz", + "integrity": "sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==", + "deprecated": "Deprecated in favor of '@metamask/eth-sig-util'", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^5.1.1", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.0" + } + }, + "node_modules/eth-sig-util/node_modules/ethereumjs-util": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", + "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "^0.1.3", + "rlp": "^2.0.0", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dev": true, + "dependencies": { + "js-sha3": "^0.8.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereum-ens": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/ethereum-ens/-/ethereum-ens-0.8.0.tgz", + "integrity": "sha512-a8cBTF4AWw1Q1Y37V1LSCS9pRY4Mh3f8vCg5cbXCCEJ3eno1hbI/+Ccv9SZLISYpqQhaglP3Bxb/34lS4Qf7Bg==", + "dev": true, + "dependencies": { + "bluebird": "^3.4.7", + "eth-ens-namehash": "^2.0.0", + "js-sha3": "^0.5.7", + "pako": "^1.0.4", + "underscore": "^1.8.3", + "web3": "^1.0.0-beta.34" + } + }, + "node_modules/ethereum-ens/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethereumjs-util/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/ethereumjs-wallet": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-1.0.2.tgz", + "integrity": "sha512-CCWV4RESJgRdHIvFciVQFnCHfqyhXWchTPlkfp28Qc53ufs+doi5I/cV2+xeK9+qEo25XCWfP9MiL+WEPAZfdA==", + "dev": true, + "dependencies": { + "aes-js": "^3.1.2", + "bs58check": "^2.1.2", + "ethereum-cryptography": "^0.1.3", + "ethereumjs-util": "^7.1.2", + "randombytes": "^2.1.0", + "scrypt-js": "^3.0.1", + "utf8": "^3.0.0", + "uuid": "^8.3.2" + } + }, + "node_modules/ethers": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", + "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", + "dev": true, + "dependencies": { + "aes-js": "3.0.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.3", + "js-sha3": "0.5.7", + "scrypt-js": "2.0.4", + "setimmediate": "1.0.4", + "uuid": "2.0.1", + "xmlhttprequest": "1.8.0" + } + }, + "node_modules/ethers/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "dev": true + }, + "node_modules/ethers/node_modules/hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/ethers/node_modules/js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", + "dev": true + }, + "node_modules/ethers/node_modules/scrypt-js": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", + "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", + "dev": true + }, + "node_modules/ethers/node_modules/setimmediate": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", + "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", + "dev": true + }, + "node_modules/ethers/node_modules/uuid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", + "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true + }, + "node_modules/ethjs-abi": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/ethjs-abi/-/ethjs-abi-0.2.1.tgz", + "integrity": "sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "js-sha3": "0.5.5", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-abi/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-abi/node_modules/js-sha3": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.5.tgz", + "integrity": "sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA==", + "dev": true + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", + "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==", + "dev": true + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "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", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "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", + "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", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "dev": true, + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extendable-error": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/extendable-error/-/extendable-error-0.1.7.tgz", + "integrity": "sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-check": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.1.1.tgz", + "integrity": "sha512-3vtXinVyuUKCKFKYcwXhGE6NtGWkqF8Yh3rvMZNzmwz8EPrgoc/v4pDdLHyLnCyCI5MZpZZkDEwFyXyEONOxpA==", + "dev": true, + "dependencies": { + "pure-rand": "^5.0.1" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-yarn-workspace-root2": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root2/-/find-yarn-workspace-root2-1.2.16.tgz", + "integrity": "sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.2", + "pkg-dir": "^4.2.0" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", + "dev": true, + "dependencies": { + "flatted": "^3.2.7", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/flat-cache/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/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.1.tgz", + "integrity": "sha512-EFRDrsMm/kyqbTQocNvRXMLjc7Es2Vk+IQFx/YW7hkUH1eBl4J1fqiP34l74Yt0pFLCNpc06fkbVk00008mzjg==", + "dev": true + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs-readdir-recursive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/ghost-testrpc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", + "integrity": "sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "node-emoji": "^1.10.0" + }, + "bin": { + "testrpc-sc": "index.js" + } + }, + "node_modules/glob": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.5.tgz", + "integrity": "sha512-bYUpUD7XDEHI4Q2O5a7PXGvyw4deKR70kHiDxzQbe925wbZknhOzUt2xBgTkYL6RBcVeXYuD9iNYeqoWbBZQnA==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/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_modules/globals": { + "version": "13.22.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", + "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": { + "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/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-12.1.0.tgz", + "integrity": "sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "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": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/handlebars/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/hardhat": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.17.3.tgz", + "integrity": "sha512-SFZoYVXW1bWJZrIIKXOA+IgcctfuKXDwENywiYNT2dM3YQc4fXNaTbuk/vpPzHIF50upByx4zW5EqczKYQubsA==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.1.2", + "@metamask/eth-sig-util": "^4.0.0", + "@nomicfoundation/ethereumjs-block": "5.0.2", + "@nomicfoundation/ethereumjs-blockchain": "7.0.2", + "@nomicfoundation/ethereumjs-common": "4.0.2", + "@nomicfoundation/ethereumjs-evm": "2.0.2", + "@nomicfoundation/ethereumjs-rlp": "5.0.2", + "@nomicfoundation/ethereumjs-statemanager": "2.0.2", + "@nomicfoundation/ethereumjs-trie": "6.0.2", + "@nomicfoundation/ethereumjs-tx": "5.0.2", + "@nomicfoundation/ethereumjs-util": "9.0.2", + "@nomicfoundation/ethereumjs-vm": "7.0.2", + "@nomicfoundation/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.14.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/bootstrap.js" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/hardhat-exposed": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/hardhat-exposed/-/hardhat-exposed-0.3.13.tgz", + "integrity": "sha512-hY2qCYSi2wD2ChZ0WP0oEPS4zlZ2vGaLOVXvfosGcy6mNeQ+pWsxTge35tTumCHwCzk/dYxLZq+KW0Z5t08yDA==", + "dev": true, + "dependencies": { + "micromatch": "^4.0.4", + "solidity-ast": "^0.4.52" + }, + "peerDependencies": { + "hardhat": "^2.3.0" + } + }, + "node_modules/hardhat-gas-reporter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", + "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", + "dev": true, + "dependencies": { + "array-uniq": "1.0.3", + "eth-gas-reporter": "^0.2.25", + "sha1": "^1.1.1" + }, + "peerDependencies": { + "hardhat": "^2.0.2" + } + }, + "node_modules/hardhat-ignore-warnings": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/hardhat-ignore-warnings/-/hardhat-ignore-warnings-0.2.9.tgz", + "integrity": "sha512-q1oj6/ixiAx+lgIyGLBajVCSC7qUtAoK7LS9Nr8UVHYo8Iuh5naBiVGo4RDJ6wxbDGYBkeSukUGZrMqzC2DWwA==", + "dev": true, + "dependencies": { + "minimatch": "^5.1.0", + "node-interval-tree": "^2.0.1", + "solidity-comments": "^0.0.2" + } + }, + "node_modules/hardhat-ignore-warnings/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/hardhat-ignore-warnings/node_modules/minimatch": { + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hardhat/node_modules/@noble/hashes": { + "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": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/hardhat/node_modules/@scure/bip32": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", + "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@noble/secp256k1": "~1.7.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/hardhat/node_modules/@scure/bip39": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", + "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.2.0", + "@scure/base": "~1.1.0" + } + }, + "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": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "node_modules/hardhat/node_modules/ethereum-cryptography": { + "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.2.0", + "@noble/secp256k1": "1.7.1", + "@scure/bip32": "1.1.5", + "@scure/bip39": "1.1.1" + } + }, + "node_modules/hardhat/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/hardhat/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/hardhat/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hardhat/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/hardhat/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/hardhat/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/hardhat/node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/hardhat/node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "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", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/header-case": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz", + "integrity": "sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.1.3" + } + }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==", + "dev": true + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/highlightjs-solidity": { + "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": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/htmlparser2": { + "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", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", + "dev": true, + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-cache-semantics": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==", + "dev": true + }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dev": true, + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "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", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-id": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/human-id/-/human-id-1.0.2.tgz", + "integrity": "sha512-UNopramDEhHJD+VR+ehk8rOslwSfByxPIZyJRfV739NDhN5LF1fa1MqnzKm2lGTQRjNrjK19Q5fhkgIfjlVUKw==", + "dev": true + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idna-uts46-hx": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz", + "integrity": "sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA==", + "dev": true, + "dependencies": { + "punycode": "2.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "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", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "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.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "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.2.0", + "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", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-lower-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz", + "integrity": "sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/is-port-reachable": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-port-reachable/-/is-port-reachable-3.1.0.tgz", + "integrity": "sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "dev": true, + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-upper-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz", + "integrity": "sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.0" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.3.tgz", + "integrity": "sha512-R2bUw+kVZFS/h1AZqBKrSgDmdmjApzgY0AlCPumopFiAlbUxE2gf+SCuBzQ0cP5hHmUmFYF5yw55T97Th5Kstg==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-sdsl": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", + "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "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", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keccak256": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz", + "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0", + "buffer": "^6.0.3", + "keccak": "^3.0.2" + } + }, + "node_modules/keccak256/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/keccak256/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "dependencies": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/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/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", + "integrity": "sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.13.0", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.startcase": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", + "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", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "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/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", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lower-case": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", + "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", + "dev": true + }, + "node_modules/lower-case-first": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz", + "integrity": "sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.2" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", + "dev": true + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/meow": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-6.1.1.tgz", + "integrity": "sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "^4.0.2", + "normalize-package-data": "^2.5.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.13.1", + "yargs-parser": "^18.1.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/merkletreejs": { + "version": "0.2.32", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.2.32.tgz", + "integrity": "sha512-TostQBiwYRIwSE5++jGmacu3ODcKAgqb0Y/pnIohXS7sWxh1gCkSptbmF1a43faehRDpcHf7J/kv0Ml2D/zblQ==", + "dev": true, + "dependencies": { + "bignumber.js": "^9.0.1", + "buffer-reverse": "^1.0.1", + "crypto-js": "^3.1.9-1", + "treeify": "^1.1.0", + "web3-utils": "^1.3.4" + }, + "engines": { + "node": ">= 7.6.0" + } + }, + "node_modules/merkletreejs/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", + "integrity": "sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==", + "dev": true + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "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" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mixme": { + "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" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-promise": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz", + "integrity": "sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w==", + "deprecated": "This package is broken and no longer maintained. 'mkdirp' itself supports promises now, please switch to that.", + "dev": true, + "dependencies": { + "mkdirp": "*" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/minimatch/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "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", + "integrity": "sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw==", + "dev": true + }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multibase": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/multicodec": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.7.tgz", + "integrity": "sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "varint": "^5.0.0" + } + }, + "node_modules/multihashes": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "node_modules/multihashes/node_modules/multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "deprecated": "This module has been superseded by the multiformats module", + "dev": true, + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/nano-base32": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nano-base32/-/nano-base32-1.0.1.tgz", + "integrity": "sha512-sxEtoTqAPdjWVGv71Q17koMFGsOMSiHsIFEvzOM7cNp8BXB4AnEwmDabm5dorusJf/v1z7QxaZYxUorU9RKaAw==", + "dev": true + }, + "node_modules/nano-json-stream-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz", + "integrity": "sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-macros": { + "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": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", + "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1" + } + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dev": true, + "dependencies": { + "lodash": "^4.17.21" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "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/node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-interval-tree": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/node-interval-tree/-/node-interval-tree-2.1.2.tgz", + "integrity": "sha512-bJ9zMDuNGzVQg1xv0bCPzyEDxHgbrx7/xGj6CDokvizZZmastPsOh0JJLuY8wA5q2SfX1TLNMk7XNV8WxbGxzA==", + "dev": true, + "dependencies": { + "shallowequal": "^1.1.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "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/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dev": true, + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "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" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "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" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "node_modules/oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dev": true, + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/outdent": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/outdent/-/outdent-0.5.0.tgz", + "integrity": "sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==", + "dev": true + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/p-filter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz", + "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==", + "dev": true, + "dependencies": { + "p-map": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-filter/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "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", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/param-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", + "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==", + "dev": true + }, + "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/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dev": true, + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", + "integrity": "sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==", + "dev": true, + "dependencies": { + "camel-case": "^3.0.0", + "upper-case-first": "^1.1.0" + } + }, + "node_modules/path-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz", + "integrity": "sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "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.1.2", + "resolved": "https://registry.npmjs.org/preferred-pm/-/preferred-pm-3.1.2.tgz", + "integrity": "sha512-nk7dKrcW8hfCZ4H6klWcdRknBOXWzNQByJ0oJyX97BOupsYD+FzLS4hflgEu/uPUEHZCuRfMxzCBsuWd7OzT8Q==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0", + "find-yarn-workspace-root2": "1.2.16", + "path-exists": "^4.0.0", + "which-pm": "2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/preferred-pm/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/preferred-pm/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-solidity": { + "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.16.0", + "semver": "^7.3.8", + "solidity-comments-extractor": "^0.0.7" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "prettier": ">=2.3.0 || >=3.0.0-alpha.0" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", + "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-5.0.5.tgz", + "integrity": "sha512-BwQpbqxSCBJVpamI6ydzcKqyFmnd5msMWUGvzXLm1aXvusbbgkbOto/EUPM00hjveJEaJtdbhUjKSzWRhQVkaw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "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", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "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", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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/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/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/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/read-yaml-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-1.1.0.tgz", + "integrity": "sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.5", + "js-yaml": "^3.6.1", + "pify": "^4.0.1", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/readable-stream": { + "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", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/redent/node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/req-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", + "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", + "dev": true, + "dependencies": { + "req-from": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", + "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/req-from/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" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, + "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/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/responselike/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", + "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", + "dev": true, + "dependencies": { + "glob": "^10.2.5" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/rlp/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/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true + }, + "node_modules/safe-array-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sc-istanbul": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sc-istanbul/-/sc-istanbul-0.4.6.tgz", + "integrity": "sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g==", + "dev": true, + "dependencies": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "istanbul": "lib/cli.js" + } + }, + "node_modules/sc-istanbul/node_modules/esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sc-istanbul/node_modules/has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sc-istanbul/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true + }, + "node_modules/sc-istanbul/node_modules/supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "dependencies": { + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/sc-istanbul/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_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/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/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/sentence-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", + "integrity": "sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case-first": "^1.1.2" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/servify": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/servify/-/servify-0.1.12.tgz", + "integrity": "sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw==", + "dev": true, + "dependencies": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha1": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", + "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", + "dev": true, + "dependencies": { + "charenc": ">= 0.0.1", + "crypt": ">= 0.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dev": true, + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/sha3/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/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/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "dev": true, + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "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": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-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/slice-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/slice-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/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", + "integrity": "sha512-vCsKNQxb7PnCNd2wY1WClWifAc2lwqsG8OaswpJkVJsvMGcnEntdTCDajZCkk93Ay1U3t/9puJmb525Rg5MZBA==", + "dev": true, + "dependencies": { + "array.prototype.flat": "^1.2.3", + "breakword": "^1.0.5", + "grapheme-splitter": "^1.0.4", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1", + "yargs": "^15.1.0" + }, + "bin": { + "smartwrap": "src/terminal-adapter.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/smartwrap/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, + "engines": { + "node": ">=8" + } + }, + "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": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/smartwrap/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "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": ">=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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smartwrap/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/smartwrap/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", + "integrity": "sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0" + } + }, + "node_modules/solc": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.26.tgz", + "integrity": "sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA==", + "dev": true, + "dependencies": { + "fs-extra": "^0.30.0", + "memorystream": "^0.3.1", + "require-from-string": "^1.1.0", + "semver": "^5.3.0", + "yargs": "^4.7.1" + }, + "bin": { + "solcjs": "solcjs" + } + }, + "node_modules/solc/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "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" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/solc/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/solc/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "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", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true + }, + "node_modules/solc/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/solc/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/solc/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true + }, + "node_modules/solc/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/solc/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/solc/node_modules/yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "dependencies": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "node_modules/solc/node_modules/yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + }, + "node_modules/solhint": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.6.2.tgz", + "integrity": "sha512-85EeLbmkcPwD+3JR7aEMKsVC9YrRSxd4qkXuMzrlf7+z2Eqdfm1wHWq1ffTuo5aDhoZxp2I9yF3QkxZOxOL7aQ==", + "dev": true, + "dependencies": { + "@solidity-parser/parser": "^0.16.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": "^7.5.2", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" + }, + "bin": { + "solhint": "solhint.js" + }, + "optionalDependencies": { + "prettier": "^2.8.3" + } + }, + "node_modules/solhint-plugin-openzeppelin": { + "resolved": "scripts/solhint-custom", + "link": true + }, + "node_modules/solhint/node_modules/@solidity-parser/parser": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", + "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint/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/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/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/solhint/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/solhint/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/solhint/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/solhint/node_modules/glob": { + "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", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/solhint/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/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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/solhint/node_modules/minimatch": { + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solhint/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint/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/solidity-ast": { + "version": "0.4.52", + "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.52.tgz", + "integrity": "sha512-iOya9BSiB9jhM8Vf40n8lGELGzwrUc57rl5BhfNtJ5cvAaMvRcNlHeAMNvqJJyjoUnczqRbHqdivEqK89du3Cw==", + "dev": true, + "dependencies": { + "array.prototype.findlast": "^1.2.2" + } + }, + "node_modules/solidity-comments": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments/-/solidity-comments-0.0.2.tgz", + "integrity": "sha512-G+aK6qtyUfkn1guS8uzqUeua1dURwPlcOjoTYW/TwmXAcE7z/1+oGCfZUdMSe4ZMKklNbVZNiG5ibnF8gkkFfw==", + "dev": true, + "engines": { + "node": ">= 12" + }, + "optionalDependencies": { + "solidity-comments-darwin-arm64": "0.0.2", + "solidity-comments-darwin-x64": "0.0.2", + "solidity-comments-freebsd-x64": "0.0.2", + "solidity-comments-linux-arm64-gnu": "0.0.2", + "solidity-comments-linux-arm64-musl": "0.0.2", + "solidity-comments-linux-x64-gnu": "0.0.2", + "solidity-comments-linux-x64-musl": "0.0.2", + "solidity-comments-win32-arm64-msvc": "0.0.2", + "solidity-comments-win32-ia32-msvc": "0.0.2", + "solidity-comments-win32-x64-msvc": "0.0.2" + } + }, + "node_modules/solidity-comments-darwin-arm64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-arm64/-/solidity-comments-darwin-arm64-0.0.2.tgz", + "integrity": "sha512-HidWkVLSh7v+Vu0CA7oI21GWP/ZY7ro8g8OmIxE8oTqyMwgMbE8F1yc58Sj682Hj199HCZsjmtn1BE4PCbLiGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-darwin-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-darwin-x64/-/solidity-comments-darwin-x64-0.0.2.tgz", + "integrity": "sha512-Zjs0Ruz6faBTPT6fBecUt6qh4CdloT8Bwoc0+qxRoTn9UhYscmbPQkUgQEbS0FQPysYqVzzxJB4h1Ofbf4wwtA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "node_modules/solidity-comments-freebsd-x64": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-freebsd-x64/-/solidity-comments-freebsd-x64-0.0.2.tgz", + "integrity": "sha512-8Qe4mpjuAxFSwZJVk7B8gAoLCdbtS412bQzBwk63L8dmlHogvE39iT70aAk3RHUddAppT5RMBunlPUCFYJ3ZTw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-gnu/-/solidity-comments-linux-arm64-gnu-0.0.2.tgz", + "integrity": "sha512-spkb0MZZnmrP+Wtq4UxP+nyPAVRe82idOjqndolcNR0S9Xvu4ebwq+LvF4HiUgjTDmeiqYiFZQ8T9KGdLSIoIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-arm64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-arm64-musl/-/solidity-comments-linux-arm64-musl-0.0.2.tgz", + "integrity": "sha512-guCDbHArcjE+JDXYkxx5RZzY1YF6OnAKCo+sTC5fstyW/KGKaQJNPyBNWuwYsQiaEHpvhW1ha537IvlGek8GqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-gnu": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-gnu/-/solidity-comments-linux-x64-gnu-0.0.2.tgz", + "integrity": "sha512-zIqLehBK/g7tvrFmQljrfZXfkEeLt2v6wbe+uFu6kH/qAHZa7ybt8Vc0wYcmjo2U0PeBm15d79ee3AkwbIjFdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-linux-x64-musl": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-linux-x64-musl/-/solidity-comments-linux-x64-musl-0.0.2.tgz", + "integrity": "sha512-R9FeDloVlFGTaVkOlELDVC7+1Tjx5WBPI5L8r0AGOPHK3+jOcRh6sKYpI+VskSPDc3vOO46INkpDgUXrKydlIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-arm64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-arm64-msvc/-/solidity-comments-win32-arm64-msvc-0.0.2.tgz", + "integrity": "sha512-QnWJoCQcJj+rnutULOihN9bixOtYWDdF5Rfz9fpHejL1BtNjdLW1om55XNVHGAHPqBxV4aeQQ6OirKnp9zKsug==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-ia32-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-ia32-msvc/-/solidity-comments-win32-ia32-msvc-0.0.2.tgz", + "integrity": "sha512-vUg4nADtm/NcOtlIymG23NWJUSuMsvX15nU7ynhGBsdKtt8xhdP3C/zA6vjDk8Jg+FXGQL6IHVQ++g/7rSQi0w==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-comments-win32-x64-msvc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/solidity-comments-win32-x64-msvc/-/solidity-comments-win32-x64-msvc-0.0.2.tgz", + "integrity": "sha512-36j+KUF4V/y0t3qatHm/LF5sCUCBx2UndxE1kq5bOzh/s+nQgatuyB+Pd5BfuPQHdWu2KaExYe20FlAa6NL7+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/solidity-coverage": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.5.tgz", + "integrity": "sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.0.9", + "@solidity-parser/parser": "^0.16.0", + "chalk": "^2.4.2", + "death": "^1.1.0", + "detect-port": "^1.3.0", + "difflib": "^0.2.4", + "fs-extra": "^8.1.0", + "ghost-testrpc": "^0.0.2", + "global-modules": "^2.0.0", + "globby": "^10.0.1", + "jsonschema": "^1.2.4", + "lodash": "^4.17.15", + "mocha": "10.2.0", + "node-emoji": "^1.10.0", + "pify": "^4.0.1", + "recursive-readdir": "^2.2.2", + "sc-istanbul": "^0.4.5", + "semver": "^7.3.4", + "shelljs": "^0.8.3", + "web3-utils": "^1.3.6" + }, + "bin": { + "solidity-coverage": "plugins/bin.js" + }, + "peerDependencies": { + "hardhat": "^2.11.0" + } + }, + "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.1.tgz", + "integrity": "sha512-PdhRFNhbTtu3x8Axm0uYpqOy/lODYQK+MlYSgqIsq2L8SFYEHJPHNUiOTAJbDGzNjjr1/n9AcIayxafR/fWmYw==", + "dev": true, + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/solidity-coverage/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/solidity-coverage/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/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": ">=8" + } + }, + "node_modules/solidity-docgen": { + "version": "0.6.0-beta.36", + "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.6.0-beta.36.tgz", + "integrity": "sha512-f/I5G2iJgU1h0XrrjRD0hHMr7C10u276vYvm//rw1TzFcYQ4xTOyAoi9oNAHRU0JU4mY9eTuxdVc2zahdMuhaQ==", + "dev": true, + "dependencies": { + "handlebars": "^4.7.7", + "solidity-ast": "^0.4.38" + }, + "peerDependencies": { + "hardhat": "^2.8.0" + } + }, + "node_modules/source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA==", + "dev": true, + "optional": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawndamnit/-/spawndamnit-2.0.0.tgz", + "integrity": "sha512-j4JKEcncSjFlqIwU5L/rp2N5SIPsdxaRsIv678+TZxZ0SRDJTm8JrxJMjE/XuiEZNEir3S8l0Fa3Ke339WI4qA==", + "dev": true, + "dependencies": { + "cross-spawn": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/spawndamnit/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/spawndamnit/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/spawndamnit/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==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawndamnit/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/spawndamnit/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_modules/spawndamnit/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/spdx-correct": { + "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", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.15.tgz", + "integrity": "sha512-lpT8hSQp9jAKp9mhtBU4Xjon8LPGBvLIuBiSVhMEtmLecTh2mO0tlqrAMp47tBXzMr13NJMQ2lf7RpQGLJ3HsQ==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-transform": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz", + "integrity": "sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==", + "dev": true, + "dependencies": { + "mixme": "^0.5.1" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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/string-width-cjs/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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, + "engines": { + "node": ">=8" + } + }, + "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/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-indent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz", + "integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/swap-case": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz", + "integrity": "sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==", + "dev": true, + "dependencies": { + "lower-case": "^1.1.1", + "upper-case": "^1.1.1" + } + }, + "node_modules/swarm-js": { + "version": "0.1.42", + "resolved": "https://registry.npmjs.org/swarm-js/-/swarm-js-0.1.42.tgz", + "integrity": "sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + } + }, + "node_modules/swarm-js/node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swarm-js/node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/swarm-js/node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/swarm-js/node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/swarm-js/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "engines": { + "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", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "dependencies": { + "get-port": "^3.1.0" + } + }, + "node_modules/table": { + "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": "^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": ">=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": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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": "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", + "dev": true, + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/testrpc": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/testrpc/-/testrpc-0.0.1.tgz", + "integrity": "sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA==", + "deprecated": "testrpc has been renamed to ganache-cli, please use this package from now on.", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/title-case": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz", + "integrity": "sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==", + "dev": true, + "dependencies": { + "no-case": "^2.2.0", + "upper-case": "^1.0.3" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tough-cookie/node_modules/punycode": { + "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" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "node_modules/tty-table": { + "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.3", + "kleur": "^4.1.5", + "smartwrap": "^2.0.2", + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.1", + "yargs": "^17.7.1" + }, + "bin": { + "tty-table": "adapters/terminal-adapter.js" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/tty-table/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, + "engines": { + "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", + "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/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", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "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", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", + "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/undici": { + "version": "5.25.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.25.1.tgz", + "integrity": "sha512-nTw6b2G2OqP6btYPyghCgV4hSwjJlL/78FMJatVLCa3otj6PCOQSt6dVtYt82OtNqFz8XsnJ+vsXLADPXjPhqw==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", + "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", + "dev": true + }, + "node_modules/upper-case-first": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz", + "integrity": "sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==", + "dev": true, + "dependencies": { + "upper-case": "^1.1.1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-set-query": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-set-query/-/url-set-query-1.0.0.tgz", + "integrity": "sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg==", + "dev": true + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==", + "dev": true + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/varint": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/varint/-/varint-5.0.2.tgz", + "integrity": "sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow==", + "dev": true + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web3": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.10.2.tgz", + "integrity": "sha512-DAtZ3a3ruPziE80uZ3Ob0YDZxt6Vk2un/F5BcBrxO70owJ9Z1Y2+loZmbh1MoAmoLGjA/SUSHeUtid3fYmBaog==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-bzz": "1.10.2", + "web3-core": "1.10.2", + "web3-eth": "1.10.2", + "web3-eth-personal": "1.10.2", + "web3-net": "1.10.2", + "web3-shh": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.10.2.tgz", + "integrity": "sha512-vLOfDCj6198Qc7esDrCKeFA/M3ZLbowsaHQ0hIL4NmIHoq7lU8aSRTa5AI+JBh8cKN1gVryJsuW2ZCc5bM4I4Q==", + "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/web3-core": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.10.2.tgz", + "integrity": "sha512-qTn2UmtE8tvwMRsC5pXVdHxrQ4uZ6jiLgF5DRUVtdi7dPUmX18Dp9uxKfIfhGcA011EAn8P6+X7r3pvi2YRxBw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-core-requestmanager": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.0.tgz", + "integrity": "sha512-pIxAzFDS5vnbXvfvLSpaA1tfRykAe9adw43YCKsEYQwH0gCLL0kMLkaCX3q+Q8EVmAh+e1jWL/nl9U0de1+++g==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.0", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers/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/web3-core-helpers/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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/web3-core-method": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.10.2.tgz", + "integrity": "sha512-gG6ES+LOuo01MJHML4gnEt702M8lcPGMYZoX8UjZzmEebGrPYOY9XccpCrsFgCeKgQzM12SVnlwwpMod1+lcLg==", + "dev": true, + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.2", + "web3-core-promievent": "1.10.2", + "web3-core-subscriptions": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/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/web3-core-method/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-core-promievent": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.2.tgz", + "integrity": "sha512-Qkkb1dCDOU8dZeORkcwJBQRAX+mdsjx8LqFBB+P4W9QgwMqyJ6LXda+y1XgyeEVeKEmY1RCeTq9Y94q1v62Sfw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-promievent": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.0.tgz", + "integrity": "sha512-68N7k5LWL5R38xRaKFrTFT2pm2jBNFaM4GioS00YjAKXRQ3KjmhijOMG3TICz6Aa5+6GDWYelDNx21YAeZ4YTg==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.10.2.tgz", + "integrity": "sha512-nlLeNJUu6fR+ZbJr2k9Du/nN3VWwB4AJPY4r6nxUODAmykgJq57T21cLP/BEk6mbiFQYGE9TrrPhh4qWxQEtAw==", + "dev": true, + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.2", + "web3-providers-http": "1.10.2", + "web3-providers-ipc": "1.10.2", + "web3-providers-ws": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager/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/web3-core-requestmanager/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.10.2.tgz", + "integrity": "sha512-MiWcKjz4tco793EPPPLc/YOJmYUV3zAfxeQH/UVTfBejMfnNvmfwKa2SBKfPIvKQHz/xI5bV2TF15uvJEucU7w==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/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/web3-core-subscriptions/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/web3-core/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/web3-core/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.10.2.tgz", + "integrity": "sha512-s38rhrntyhGShmXC4R/aQtfkpcmev9c7iZwgb9CDIBFo7K8nrEJvqIOyajeZTxnDIiGzTJmrHxiKSadii5qTRg==", + "dev": true, + "dependencies": { + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-core-subscriptions": "1.10.2", + "web3-eth-abi": "1.10.2", + "web3-eth-accounts": "1.10.2", + "web3-eth-contract": "1.10.2", + "web3-eth-ens": "1.10.2", + "web3-eth-iban": "1.10.2", + "web3-eth-personal": "1.10.2", + "web3-net": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.10.2.tgz", + "integrity": "sha512-pY4fQUio7W7ZRSLf+vsYkaxJqaT/jHcALZjIxy+uBQaYAJ3t6zpQqMZkJB3Dw7HUODRJ1yI0NPEFGTnkYf/17A==", + "dev": true, + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.10.2.tgz", + "integrity": "sha512-6/HhCBYAXN/f553/SyxS9gY62NbLgpD1zJpENcvRTDpJN3Znvli1cmpl5Q3ZIUJkvHnG//48EWfWh0cbb3fbKQ==", + "dev": true, + "dependencies": { + "@ethereumjs/common": "2.5.0", + "@ethereumjs/tx": "3.3.2", + "@ethereumjs/util": "^8.1.0", + "eth-lib": "0.2.8", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/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/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/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/web3-eth-contract": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.10.2.tgz", + "integrity": "sha512-CZLKPQRmupP/+OZ5A/CBwWWkBiz5B/foOpARz0upMh1yjb0dEud4YzRW2gJaeNu0eGxDLsWVaXhUimJVGYprQw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-core-promievent": "1.10.2", + "web3-core-subscriptions": "1.10.2", + "web3-eth-abi": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/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/web3-eth-contract/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-core-promievent": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.2.tgz", + "integrity": "sha512-Qkkb1dCDOU8dZeORkcwJBQRAX+mdsjx8LqFBB+P4W9QgwMqyJ6LXda+y1XgyeEVeKEmY1RCeTq9Y94q1v62Sfw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-contract/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.10.2.tgz", + "integrity": "sha512-kTQ42UdNHy4BQJHgWe97bHNMkc3zCMBKKY7t636XOMxdI/lkRdIjdE5nQzt97VjQvSVasgIWYKRAtd8aRaiZiQ==", + "dev": true, + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-promievent": "1.10.2", + "web3-eth-abi": "1.10.2", + "web3-eth-contract": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/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/web3-eth-ens/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-core-promievent": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.10.2.tgz", + "integrity": "sha512-Qkkb1dCDOU8dZeORkcwJBQRAX+mdsjx8LqFBB+P4W9QgwMqyJ6LXda+y1XgyeEVeKEmY1RCeTq9Y94q1v62Sfw==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-iban": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.0.tgz", + "integrity": "sha512-0l+SP3IGhInw7Q20LY3IVafYEuufo4Dn75jAHT7c2aDJsIolvf2Lc6ugHkBajlwUneGfbRQs/ccYPQ9JeMUbrg==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "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/web3-eth-iban/node_modules/web3-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.0.tgz", + "integrity": "sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg==", + "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/web3-eth-personal": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.10.2.tgz", + "integrity": "sha512-+vEbJsPUJc5J683y0c2aN645vXC+gPVlFVCQu4IjPvXzJrAtUfz26+IZ6AUOth4fDJPT0f1uSLS5W2yrUdw9BQ==", + "dev": true, + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.2", + "web3-core-helpers": "1.10.2", + "web3-core-method": "1.10.2", + "web3-net": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/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/web3-eth-personal/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/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/web3-eth/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-net": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.10.2.tgz", + "integrity": "sha512-w9i1t2z7dItagfskhaCKwpp6W3ylUR88gs68u820y5f8yfK5EbPmHc6c2lD8X9ZrTnmDoeOpIRCN/RFPtZCp+g==", + "dev": true, + "dependencies": { + "web3-core": "1.10.2", + "web3-core-method": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.10.2.tgz", + "integrity": "sha512-G8abKtpkyKGpRVKvfjIF3I4O/epHP7mxXWN8mNMQLkQj1cjMFiZBZ13f+qI77lNJN7QOf6+LtNdKrhsTGU72TA==", + "dev": true, + "dependencies": { + "abortcontroller-polyfill": "^1.7.5", + "cross-fetch": "^4.0.0", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http/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/web3-providers-http/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.10.2.tgz", + "integrity": "sha512-lWbn6c+SgvhLymU8u4Ea/WOVC0Gqs7OJUvauejWz+iLycxeF0xFNyXnHVAi42ZJDPVI3vnfZotafoxcNNL7Sug==", + "dev": true, + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc/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/web3-providers-ipc/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.10.2.tgz", + "integrity": "sha512-3nYSiP6grI5GvpkSoehctSywfCTodU21VY8bUtXyFHK/IVfDooNtMpd5lVIMvXVAlaxwwrCfjebokaJtKH2Iag==", + "dev": true, + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.2", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/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/web3-providers-ws/node_modules/web3-core-helpers": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.10.2.tgz", + "integrity": "sha512-1JfaNtox6/ZYJHNoI+QVc2ObgwEPeGF+YdxHZQ7aF5605BmlwM1Bk3A8xv6mg64jIRvEq1xX6k9oG6x7p1WgXQ==", + "dev": true, + "dependencies": { + "web3-eth-iban": "1.10.2", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws/node_modules/web3-eth-iban": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.10.2.tgz", + "integrity": "sha512-y8+Ii2XXdyHQMFNL2NWpBnXe+TVJ4ryvPlzNhObRRnIo4O4nLIXS010olLDMayozDzoUlmzCmBZJYc9Eev1g7A==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-shh": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.10.2.tgz", + "integrity": "sha512-UP0Kc3pHv9uULFu0+LOVfPwKBSJ6B+sJ5KflF7NyBk6TvNRxlpF3hUhuaVDCjjB/dDUR6T0EQeg25FA2uzJbag==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "web3-core": "1.10.2", + "web3-core-method": "1.10.2", + "web3-core-subscriptions": "1.10.2", + "web3-net": "1.10.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.2.tgz", + "integrity": "sha512-TdApdzdse5YR+5GCX/b/vQnhhbj1KSAtfrDtRW7YS0kcWp1gkJsN62gw6GzCaNTeXookB7UrLtmDUuMv65qgow==", + "dev": true, + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "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/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/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dev": true, + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dev": true, + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "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": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-2.0.0.tgz", + "integrity": "sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==", + "dev": true, + "dependencies": { + "load-yaml-file": "^0.2.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8.15" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", + "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true, + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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-cjs/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-cjs/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-cjs/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/wrap-ansi-cjs/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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, + "engines": { + "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", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dev": true, + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xhr-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/xhr-request/-/xhr-request-1.1.0.tgz", + "integrity": "sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA==", + "dev": true, + "dependencies": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "node_modules/xhr-request-promise": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz", + "integrity": "sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg==", + "dev": true, + "dependencies": { + "xhr-request": "^1.1.0" + } + }, + "node_modules/xmlhttprequest": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", + "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==", + "dev": true, + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "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", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "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/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": ">=6" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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/yargs/node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "scripts/solhint-custom": { + "name": "solhint-plugin-openzeppelin", + "version": "0.0.0", + "dev": true + } + } +} diff --git a/lib/openzeppelin-contracts/package.json b/lib/openzeppelin-contracts/package.json new file mode 100644 index 0000000..c7e92ef --- /dev/null +++ b/lib/openzeppelin-contracts/package.json @@ -0,0 +1,96 @@ +{ + "name": "openzeppelin-solidity", + "description": "Secure Smart Contract library for Solidity", + "version": "5.0.0", + "private": true, + "files": [ + "/contracts/**/*.sol", + "!/contracts/mocks/**/*" + ], + "scripts": { + "compile": "hardhat compile", + "coverage": "env COVERAGE=true FOUNDRY=false hardhat coverage", + "docs": "npm run prepare-docs && oz-docs", + "docs:watch": "oz-docs watch contracts docs/templates docs/config.js", + "prepare-docs": "scripts/prepare-docs.sh", + "lint": "npm run lint:js && npm run lint:sol", + "lint:fix": "npm run lint:js:fix && npm run lint:sol:fix", + "lint:js": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --check && eslint --ignore-path .gitignore .", + "lint:js:fix": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --write && eslint --ignore-path .gitignore . --fix", + "lint:sol": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --check && solhint '{contracts,test}/**/*.sol'", + "lint:sol:fix": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write", + "clean": "hardhat clean && rimraf build contracts/build", + "prepack": "scripts/prepack.sh", + "generate": "scripts/generate/run.js", + "release": "scripts/release/release.sh", + "version": "scripts/release/version.sh", + "test": "hardhat test", + "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 ." + }, + "repository": { + "type": "git", + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts.git" + }, + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "security", + "zeppelin" + ], + "author": "OpenZeppelin Community ", + "license": "MIT", + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, + "homepage": "https://openzeppelin.com/contracts/", + "devDependencies": { + "@changesets/changelog-github": "^0.4.8", + "@changesets/cli": "^2.26.0", + "@changesets/pre": "^1.0.14", + "@changesets/read": "^0.5.9", + "@nomicfoundation/hardhat-foundry": "^1.1.1", + "@nomicfoundation/hardhat-network-helpers": "^1.0.3", + "@nomiclabs/hardhat-truffle5": "^2.0.5", + "@nomiclabs/hardhat-web3": "^2.0.0", + "@openzeppelin/docs-utils": "^0.1.5", + "@openzeppelin/test-helpers": "^0.5.13", + "@openzeppelin/upgrade-safe-transpiler": "^0.3.32", + "@openzeppelin/upgrades-core": "^1.20.6", + "array.prototype.at": "^1.1.1", + "chai": "^4.2.0", + "eslint": "^8.30.0", + "eslint-config-prettier": "^9.0.0", + "eth-sig-util": "^3.0.0", + "ethereumjs-util": "^7.0.7", + "ethereumjs-wallet": "^1.0.1", + "glob": "^10.3.5", + "graphlib": "^2.1.8", + "hardhat": "^2.9.1", + "hardhat-exposed": "^0.3.13", + "hardhat-gas-reporter": "^1.0.9", + "hardhat-ignore-warnings": "^0.2.0", + "keccak256": "^1.0.2", + "lodash.startcase": "^4.4.0", + "lodash.zip": "^4.2.0", + "merkletreejs": "^0.2.13", + "micromatch": "^4.0.2", + "p-limit": "^3.1.0", + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.1.0", + "rimraf": "^5.0.1", + "semver": "^7.3.5", + "solhint": "^3.3.6", + "solhint-plugin-openzeppelin": "file:scripts/solhint-custom", + "solidity-ast": "^0.4.50", + "solidity-coverage": "^0.8.5", + "solidity-docgen": "^0.6.0-beta.29", + "undici": "^5.22.1", + "web3": "^1.3.0", + "yargs": "^17.0.0" + } +} diff --git a/lib/openzeppelin-contracts/remappings.txt b/lib/openzeppelin-contracts/remappings.txt new file mode 100644 index 0000000..304d138 --- /dev/null +++ b/lib/openzeppelin-contracts/remappings.txt @@ -0,0 +1 @@ +@openzeppelin/contracts/=contracts/ diff --git a/lib/openzeppelin-contracts/renovate.json b/lib/openzeppelin-contracts/renovate.json new file mode 100644 index 0000000..c0b97d8 --- /dev/null +++ b/lib/openzeppelin-contracts/renovate.json @@ -0,0 +1,4 @@ +{ + "extends": ["github>OpenZeppelin/configs"], + "labels": ["ignore-changeset"] +} diff --git a/lib/openzeppelin-contracts/requirements.txt b/lib/openzeppelin-contracts/requirements.txt new file mode 100644 index 0000000..fd0ec30 --- /dev/null +++ b/lib/openzeppelin-contracts/requirements.txt @@ -0,0 +1 @@ +certora-cli==4.8.0 diff --git a/lib/openzeppelin-contracts/scripts/checks/compare-layout.js b/lib/openzeppelin-contracts/scripts/checks/compare-layout.js new file mode 100644 index 0000000..4368b77 --- /dev/null +++ b/lib/openzeppelin-contracts/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(`Storage layout incompatilibity found in ${name}:`); + console.log(report.explain()); + process.exitCode = 1; + } + } else { + console.log(`WARNING: ${name} is missing from the current branch`); + } +} diff --git a/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js b/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js new file mode 100755 index 0000000..160c8cc --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/checks/compareGasReports.js @@ -0,0 +1,243 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const chalk = require('chalk'); +const { argv } = require('yargs') + .env() + .options({ + style: { + type: 'string', + choices: ['shell', 'markdown'], + default: 'shell', + }, + hideEqual: { + type: 'boolean', + default: true, + }, + strictTesting: { + type: 'boolean', + default: false, + }, + }); + +// Deduce base tx cost from the percentage denominator +const BASE_TX_COST = 21000; + +// Utilities +function sum(...args) { + return args.reduce((a, b) => a + b, 0); +} + +function average(...args) { + return sum(...args) / args.length; +} + +function variation(current, previous, offset = 0) { + return { + value: current, + delta: current - previous, + prcnt: (100 * (current - previous)) / (previous - offset), + }; +} + +// Report class +class Report { + // Read report file + static load(filepath) { + return JSON.parse(fs.readFileSync(filepath, 'utf8')); + } + + // Compare two reports + 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'); + } + + const deployments = update.info.deployments + .map(contract => + Object.assign(contract, { previousVersion: ref.info.deployments.find(({ name }) => name === contract.name) }), + ) + .filter(contract => contract.gasData?.length && contract.previousVersion?.gasData?.length) + .flatMap(contract => [ + { + contract: contract.name, + method: '[bytecode length]', + avg: variation(contract.bytecode.length / 2 - 1, contract.previousVersion.bytecode.length / 2 - 1), + }, + { + contract: contract.name, + method: '[construction cost]', + avg: variation( + ...[contract.gasData, contract.previousVersion.gasData].map(x => Math.round(average(...x))), + BASE_TX_COST, + ), + }, + ]) + .sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`)); + + const methods = Object.keys(update.info.methods) + .filter(key => ref.info.methods[key]) + .filter(key => update.info.methods[key].numberOfCalls > 0) + .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, + min: variation(...[update, ref].map(x => Math.min(...x.info.methods[key].gasData)), BASE_TX_COST), + max: variation(...[update, ref].map(x => Math.max(...x.info.methods[key].gasData)), BASE_TX_COST), + avg: variation(...[update, ref].map(x => Math.round(average(...x.info.methods[key].gasData))), BASE_TX_COST), + })) + .sort((a, b) => `${a.contract}:${a.method}`.localeCompare(`${b.contract}:${b.method}`)); + + return [] + .concat(deployments, methods) + .filter(row => !opts.hideEqual || row.min?.delta || row.max?.delta || row.avg?.delta); + } +} + +// Display +function center(text, length) { + return text.padStart((text.length + length) / 2).padEnd(length); +} + +function plusSign(num) { + return num > 0 ? '+' : ''; +} + +function formatCellShell(cell) { + const format = chalk[cell?.delta > 0 ? 'red' : cell?.delta < 0 ? 'green' : 'reset']; + return [ + format((!isFinite(cell?.value) ? '-' : cell.value.toString()).padStart(8)), + format((!isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString()).padStart(8)), + format((!isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%').padStart(8)), + ]; +} + +function formatCmpShell(rows) { + const contractLength = Math.max(8, ...rows.map(({ contract }) => contract.length)); + const methodLength = Math.max(7, ...rows.map(({ method }) => method.length)); + + const COLS = [ + { txt: '', length: 0 }, + { txt: 'Contract', length: contractLength }, + { txt: 'Method', length: methodLength }, + { txt: 'Min', length: 30 }, + { txt: 'Max', length: 30 }, + { txt: 'Avg', length: 30 }, + { txt: '', length: 0 }, + ]; + const HEADER = COLS.map(entry => chalk.bold(center(entry.txt, entry.length || 0))) + .join(' | ') + .trim(); + const SEPARATOR = COLS.map(({ length }) => (length > 0 ? '-'.repeat(length + 2) : '')) + .join('|') + .trim(); + + return [ + '', + HEADER, + ...rows.map(entry => + [ + '', + chalk.grey(entry.contract.padEnd(contractLength)), + entry.method.padEnd(methodLength), + ...formatCellShell(entry.min), + ...formatCellShell(entry.max), + ...formatCellShell(entry.avg), + '', + ] + .join(' | ') + .trim(), + ), + '', + ] + .join(`\n${SEPARATOR}\n`) + .trim(); +} + +function alignPattern(align) { + switch (align) { + case 'left': + case undefined: + return ':-'; + case 'right': + return '-:'; + case 'center': + return ':-:'; + } +} + +function trend(value) { + return value > 0 ? ':x:' : value < 0 ? ':heavy_check_mark:' : ':heavy_minus_sign:'; +} + +function formatCellMarkdown(cell) { + return [ + !isFinite(cell?.value) ? '-' : cell.value.toString(), + !isFinite(cell?.delta) ? '-' : plusSign(cell.delta) + cell.delta.toString(), + !isFinite(cell?.prcnt) ? '-' : plusSign(cell.prcnt) + cell.prcnt.toFixed(2) + '%' + trend(cell.delta), + ]; +} + +function formatCmpMarkdown(rows) { + const COLS = [ + { txt: '' }, + { txt: 'Contract', align: 'left' }, + { txt: 'Method', align: 'left' }, + { txt: 'Min', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: 'Max', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: 'Avg', align: 'right' }, + { txt: '(+/-)', align: 'right' }, + { txt: '%', align: 'right' }, + { txt: '' }, + ]; + const HEADER = COLS.map(entry => entry.txt) + .join(' | ') + .trim(); + const SEPARATOR = COLS.map(entry => (entry.txt ? alignPattern(entry.align) : '')) + .join('|') + .trim(); + + return [ + '# Changes to gas costs', + '', + HEADER, + SEPARATOR, + rows + .map(entry => + [ + '', + entry.contract, + entry.method, + ...formatCellMarkdown(entry.min), + ...formatCellMarkdown(entry.max), + ...formatCellMarkdown(entry.avg), + '', + ] + .join(' | ') + .trim(), + ) + .join('\n'), + '', + ] + .join('\n') + .trim(); +} + +// MAIN +const report = Report.compare(Report.load(argv._[0]), Report.load(argv._[1]), argv); + +switch (argv.style) { + case 'markdown': + console.log(formatCmpMarkdown(report)); + break; + case 'shell': + default: + console.log(formatCmpShell(report)); + break; +} diff --git a/lib/openzeppelin-contracts/scripts/checks/extract-layout.js b/lib/openzeppelin-contracts/scripts/checks/extract-layout.js new file mode 100644 index 0000000..d0b9965 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/checks/extract-layout.js @@ -0,0 +1,38 @@ +const fs = require('fs'); +const { findAll, astDereferencer, srcDecoder } = require('solidity-ast/utils'); +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 = srcDecoder(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)))); diff --git a/lib/openzeppelin-contracts/scripts/checks/generation.sh b/lib/openzeppelin-contracts/scripts/checks/generation.sh new file mode 100755 index 0000000..00d609f --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/checks/generation.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +npm run generate +git diff -R --exit-code diff --git a/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js b/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js new file mode 100755 index 0000000..72aa37e --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/checks/inheritance-ordering.js @@ -0,0 +1,54 @@ +#!/usr/bin/env node + +const path = require('path'); +const graphlib = require('graphlib'); +const { findAll } = require('solidity-ast/utils'); +const { _: artifacts } = require('yargs').argv; + +for (const artifact of artifacts) { + const { output: solcOutput } = require(path.resolve(__dirname, '../..', artifact)); + + const graph = new graphlib.Graph({ directed: true }); + const names = {}; + const linearized = []; + + for (const source in solcOutput.contracts) { + if (['contracts-exposed/', 'contracts/mocks/'].some(pattern => source.startsWith(pattern))) { + continue; + } + + for (const contractDef of findAll('ContractDefinition', solcOutput.sources[source].ast)) { + names[contractDef.id] = contractDef.name; + linearized.push(contractDef.linearizedBaseContracts); + + contractDef.linearizedBaseContracts.forEach((c1, i, contracts) => + contracts.slice(i + 1).forEach(c2 => { + graph.setEdge(c1, c2); + }), + ); + } + } + + /// graphlib.alg.findCycles will not find minimal cycles. + /// We are only interested int cycles of lengths 2 (needs proof) + graph.nodes().forEach((x, i, nodes) => + nodes + .slice(i + 1) + .filter(y => graph.hasEdge(x, y) && graph.hasEdge(y, x)) + .forEach(y => { + console.log(`Conflict between ${names[x]} and ${names[y]} detected in the following dependency chains:`); + linearized + .filter(chain => chain.includes(parseInt(x)) && chain.includes(parseInt(y))) + .forEach(chain => { + const comp = chain.indexOf(parseInt(x)) < chain.indexOf(parseInt(y)) ? '>' : '<'; + console.log(`- ${names[x]} ${comp} ${names[y]} in ${names[chain.find(Boolean)]}`); + // console.log(`- ${names[x]} ${comp} ${names[y]}: ${chain.reverse().map(id => names[id]).join(', ')}`); + }); + process.exitCode = 1; + }), + ); +} + +if (!process.exitCode) { + console.log('Contract ordering is consistent.'); +} diff --git a/lib/openzeppelin-contracts/scripts/gen-nav.js b/lib/openzeppelin-contracts/scripts/gen-nav.js new file mode 100644 index 0000000..de3d0da --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/gen-nav.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node + +const path = require('path'); +const glob = require('glob'); +const startCase = require('lodash.startcase'); + +const baseDir = process.argv[2]; + +const files = glob.sync(baseDir + '/**/*.adoc').map(f => path.relative(baseDir, f)); + +console.log('.API'); + +function getPageTitle(directory) { + switch (directory) { + case 'metatx': + return 'Meta Transactions'; + case 'common': + return 'Common (Tokens)'; + default: + return startCase(directory); + } +} + +const links = files.map(file => { + const doc = file.replace(baseDir, ''); + const title = path.parse(file).name; + + return { + xref: `* xref:${doc}[${getPageTitle(title)}]`, + title, + }; +}); + +// Case-insensitive sort based on titles (so 'token/ERC20' gets sorted as 'erc20') +const sortedLinks = links.sort(function (a, b) { + return a.title.toLowerCase().localeCompare(b.title.toLowerCase(), undefined, { numeric: true }); +}); + +for (const link of sortedLinks) { + console.log(link.xref); +} diff --git a/lib/openzeppelin-contracts/scripts/generate/format-lines.js b/lib/openzeppelin-contracts/scripts/generate/format-lines.js new file mode 100644 index 0000000..fa3d6b1 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/format-lines.js @@ -0,0 +1,16 @@ +function formatLines(...lines) { + return [...indentEach(0, lines)].join('\n') + '\n'; +} + +function* indentEach(indent, lines) { + for (const line of lines) { + if (Array.isArray(line)) { + yield* indentEach(indent + 1, line); + } else { + const padding = ' '.repeat(indent); + yield* line.split('\n').map(subline => (subline === '' ? '' : padding + subline)); + } + } +} + +module.exports = formatLines; diff --git a/lib/openzeppelin-contracts/scripts/generate/run.js b/lib/openzeppelin-contracts/scripts/generate/run.js new file mode 100755 index 0000000..5358945 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/run.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node + +const cp = require('child_process'); +const fs = require('fs'); +const path = require('path'); +const format = require('./format-lines'); + +function getVersion(path) { + try { + return fs.readFileSync(path, 'utf8').match(/\/\/ OpenZeppelin Contracts \(last updated v[^)]+\)/)[0]; + } catch (err) { + return null; + } +} + +function generateFromTemplate(file, template, outputPrefix = '') { + const script = path.relative(path.join(__dirname, '../..'), __filename); + const input = path.join(path.dirname(script), template); + const output = path.join(outputPrefix, file); + const version = getVersion(output); + const content = format( + '// SPDX-License-Identifier: MIT', + ...(version ? [version + ` (${file})`] : []), + `// This file was procedurally generated from ${input}.`, + '', + require(template), + ); + + 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/structs/Checkpoints.sol': './templates/Checkpoints.js', + 'utils/StorageSlot.sol': './templates/StorageSlot.js', +})) { + generateFromTemplate(file, template, './contracts/'); +} + +// Tests +for (const [file, template] of Object.entries({ + 'utils/structs/Checkpoints.t.sol': './templates/Checkpoints.t.js', +})) { + generateFromTemplate(file, template, './test/'); +} diff --git a/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js b/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js new file mode 100644 index 0000000..321a774 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.js @@ -0,0 +1,247 @@ +const format = require('../format-lines'); +const { OPTS } = require('./Checkpoints.opts.js'); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.20; + +import {Math} from "../math/Math.sol"; + +/** + * @dev This library defines the \`Trace*\` struct, for checkpointing values as they change at different points in + * time, and later looking up past values by block number. See {Votes} as an example. + * + * To create a history of checkpoints define a variable type \`Checkpoints.Trace*\` in your contract, and store a new + * checkpoint for the current transaction block using the {push} function. + */ +`; + +const errors = `\ + /** + * @dev A value was attempted to be inserted on a past checkpoint. + */ + error CheckpointUnorderedInsertion(); +`; + +const template = opts => `\ +struct ${opts.historyTypeName} { + ${opts.checkpointTypeName}[] ${opts.checkpointFieldName}; +} + +struct ${opts.checkpointTypeName} { + ${opts.keyTypeName} ${opts.keyFieldName}; + ${opts.valueTypeName} ${opts.valueFieldName}; +} + +/** + * @dev Pushes a (\`key\`, \`value\`) pair into a ${opts.historyTypeName} so that it is stored as the checkpoint. + * + * Returns previous value and new value. + * + * IMPORTANT: Never accept \`key\` as a user input, since an arbitrary \`type(${opts.keyTypeName}).max\` key set will disable the + * library. + */ +function push( + ${opts.historyTypeName} storage self, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) internal returns (${opts.valueTypeName}, ${opts.valueTypeName}) { + return _insert(self.${opts.checkpointFieldName}, key, value); +} + +/** + * @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; + uint256 pos = _lowerBinaryLookup(self.${opts.checkpointFieldName}, key, 0, len); + return pos == len ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos).${opts.valueFieldName}; +} + +/** + * @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; + 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 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). + */ +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}; +} + +/** + * @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints. + */ +function latest(${opts.historyTypeName} storage self) internal view returns (${opts.valueTypeName}) { + uint256 pos = self.${opts.checkpointFieldName}.length; + return pos == 0 ? 0 : _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1).${opts.valueFieldName}; +} + +/** + * @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value + * in the most recent checkpoint. + */ +function latestCheckpoint(${opts.historyTypeName} storage self) + internal + view + returns ( + bool exists, + ${opts.keyTypeName} ${opts.keyFieldName}, + ${opts.valueTypeName} ${opts.valueFieldName} + ) +{ + uint256 pos = self.${opts.checkpointFieldName}.length; + if (pos == 0) { + return (false, 0, 0); + } else { + ${opts.checkpointTypeName} memory ckpt = _unsafeAccess(self.${opts.checkpointFieldName}, pos - 1); + return (true, ckpt.${opts.keyFieldName}, ckpt.${opts.valueFieldName}); + } +} + +/** + * @dev Returns the number of checkpoint. + */ +function length(${opts.historyTypeName} storage self) internal view returns (uint256) { + return self.${opts.checkpointFieldName}.length; +} + +/** + * @dev Returns checkpoint at given position. + */ +function at(${opts.historyTypeName} storage self, uint32 pos) internal view returns (${opts.checkpointTypeName} memory) { + return self.${opts.checkpointFieldName}[pos]; +} + +/** + * @dev Pushes a (\`key\`, \`value\`) pair into an ordered list of checkpoints, either by inserting a new checkpoint, + * or by updating the last one. + */ +function _insert( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + ${opts.valueTypeName} value +) private returns (${opts.valueTypeName}, ${opts.valueTypeName}) { + uint256 pos = self.length; + + if (pos > 0) { + // Copying to memory is important here. + ${opts.checkpointTypeName} memory last = _unsafeAccess(self, pos - 1); + + // Checkpoint keys must be non-decreasing. + if(last.${opts.keyFieldName} > key) { + revert CheckpointUnorderedInsertion(); + } + + // Update or push new checkpoint + if (last.${opts.keyFieldName} == key) { + _unsafeAccess(self, pos - 1).${opts.valueFieldName} = value; + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + } + return (last.${opts.valueFieldName}, value); + } else { + self.push(${opts.checkpointTypeName}({${opts.keyFieldName}: key, ${opts.valueFieldName}: value})); + return (0, value); + } +} + +/** + * @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. + */ +function _upperBinaryLookup( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + uint256 low, + uint256 high +) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid).${opts.keyFieldName} > key) { + high = mid; + } else { + low = mid + 1; + } + } + return high; +} + +/** + * @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. + */ +function _lowerBinaryLookup( + ${opts.checkpointTypeName}[] storage self, + ${opts.keyTypeName} key, + uint256 low, + uint256 high +) private view returns (uint256) { + while (low < high) { + uint256 mid = Math.average(low, high); + if (_unsafeAccess(self, mid).${opts.keyFieldName} < key) { + low = mid + 1; + } else { + high = mid; + } + } + return high; +} + +/** + * @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds. + */ +function _unsafeAccess(${opts.checkpointTypeName}[] storage self, uint256 pos) + private + pure + returns (${opts.checkpointTypeName} storage result) +{ + assembly { + mstore(0, self.slot) + result.slot := add(keccak256(0, 0x20), pos) + } +} +`; +/* eslint-enable max-len */ + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library Checkpoints {', + errors, + OPTS.flatMap(opts => template(opts)), + '}', +); diff --git a/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js b/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js new file mode 100644 index 0000000..08b7b91 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.opts.js @@ -0,0 +1,17 @@ +// OPTIONS +const VALUE_SIZES = [224, 208, 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 = { + VALUE_SIZES, + OPTS: VALUE_SIZES.map(size => defaultOpts(size)), +}; diff --git a/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js b/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js new file mode 100644 index 0000000..d21beb5 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/templates/Checkpoints.t.js @@ -0,0 +1,146 @@ +const format = require('../format-lines'); +const { capitalize } = require('../../helpers'); +const { OPTS } = require('./Checkpoints.opts.js'); + +// TEMPLATE +const header = `\ +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {SafeCast} from "../../../contracts/utils/math/SafeCast.sol"; +import {Checkpoints} from "../../../contracts/utils/structs/Checkpoints.sol"; +`; + +/* eslint-disable max-len */ +const template = 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); +} + +// 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]; + if (lastKey > 0) { + 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); +} +`; + +// GENERATE +module.exports = format( + header, + ...OPTS.flatMap(opts => [`contract Checkpoints${opts.historyTypeName}Test is Test {`, [template(opts)], '}']), +); diff --git a/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js b/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js new file mode 100644 index 0000000..7dbe6ca --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableMap.js @@ -0,0 +1,283 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); + +const TYPES = [ + { name: 'UintToUintMap', keyType: 'uint256', valueType: 'uint256' }, + { name: 'UintToAddressMap', keyType: 'uint256', valueType: 'address' }, + { name: 'AddressToUintMap', keyType: 'address', valueType: 'uint256' }, + { name: 'Bytes32ToUintMap', keyType: 'bytes32', valueType: 'uint256' }, +]; + +/* eslint-disable max-len */ +const header = `\ +pragma solidity ^0.8.20; + +import {EnumerableSet} from "./EnumerableSet.sol"; + +/** + * @dev Library for managing an enumerable variant of Solidity's + * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[\`mapping\`] + * type. + * + * Maps have the following properties: + * + * - Entries are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableMap.UintToAddressMap private myMap; + * } + * \`\`\` + * + * The following map types are supported: + * + * - \`uint256 -> address\` (\`UintToAddressMap\`) since v3.0.0 + * - \`address -> uint256\` (\`AddressToUintMap\`) since v4.6.0 + * - \`bytes32 -> bytes32\` (\`Bytes32ToBytes32Map\`) since v4.6.0 + * - \`uint256 -> uint256\` (\`UintToUintMap\`) since v4.7.0 + * - \`bytes32 -> uint256\` (\`Bytes32ToUintMap\`) since v4.7.0 + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableMap. + * ==== + */ +`; +/* eslint-enable max-len */ + +const defaultMap = () => `\ +// To implement this library for multiple types with as little code repetition as possible, we write it in +// terms of a generic Map type with bytes32 keys and values. The Map implementation uses private functions, +// and user-facing implementations such as \`UintToAddressMap\` are just wrappers around the underlying Map. +// This means that we can only create new EnumerableMaps for types that fit in bytes32. + +/** + * @dev Query for a nonexistent map key. + */ +error EnumerableMapNonexistentKey(bytes32 key); + +struct Bytes32ToBytes32Map { + // Storage of keys + EnumerableSet.Bytes32Set _keys; + mapping(bytes32 key => bytes32) _values; +} + +/** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ +function set( + Bytes32ToBytes32Map storage map, + bytes32 key, + bytes32 value +) internal returns (bool) { + map._values[key] = value; + return map._keys.add(key); +} + +/** + * @dev Removes a key-value pair from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ +function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) { + delete map._values[key]; + return map._keys.remove(key); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) { + return map._keys.contains(key); +} + +/** + * @dev Returns the number of key-value pairs in the map. O(1). + */ +function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) { + return map._keys.length(); +} + +/** + * @dev Returns the key-value pair stored at position \`index\` in the map. O(1). + * + * Note that there are no guarantees on the ordering of entries inside the + * array, and it may change when more entries are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) { + bytes32 key = map._keys.at(index); + return (key, map._values[key]); +} + +/** + * @dev Tries to returns the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) { + bytes32 value = map._values[key]; + if (value == bytes32(0)) { + return (contains(map, key), bytes32(0)); + } else { + return (true, value); + } +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) { + bytes32 value = map._values[key]; + if(value == 0 && !contains(map, key)) { + revert EnumerableMapNonexistentKey(key); + } + return value; +} + +/** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function keys(Bytes32ToBytes32Map storage map) internal view returns (bytes32[] memory) { + return map._keys.values(); +} +`; + +const customMap = ({ name, keyType, valueType }) => `\ +// ${name} + +struct ${name} { + Bytes32ToBytes32Map _inner; +} + +/** + * @dev Adds a key-value pair to a map, or updates the value for an existing + * key. O(1). + * + * Returns true if the key was added to the map, that is if it was not + * already present. + */ +function set( + ${name} storage map, + ${keyType} key, + ${valueType} value +) internal returns (bool) { + return set(map._inner, ${toBytes32(keyType, 'key')}, ${toBytes32(valueType, 'value')}); +} + +/** + * @dev Removes a value from a map. O(1). + * + * Returns true if the key was removed from the map, that is if it was present. + */ +function remove(${name} storage map, ${keyType} key) internal returns (bool) { + return remove(map._inner, ${toBytes32(keyType, 'key')}); +} + +/** + * @dev Returns true if the key is in the map. O(1). + */ +function contains(${name} storage map, ${keyType} key) internal view returns (bool) { + return contains(map._inner, ${toBytes32(keyType, 'key')}); +} + +/** + * @dev Returns the number of elements in the map. O(1). + */ +function length(${name} storage map) internal view returns (uint256) { + return length(map._inner); +} + +/** + * @dev Returns the element stored at position \`index\` in the map. O(1). + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(${name} storage map, uint256 index) internal view returns (${keyType}, ${valueType}) { + (bytes32 key, bytes32 value) = at(map._inner, index); + return (${fromBytes32(keyType, 'key')}, ${fromBytes32(valueType, 'value')}); +} + +/** + * @dev Tries to returns the value associated with \`key\`. O(1). + * Does not revert if \`key\` is not in the map. + */ +function tryGet(${name} storage map, ${keyType} key) internal view returns (bool, ${valueType}) { + (bool success, bytes32 value) = tryGet(map._inner, ${toBytes32(keyType, 'key')}); + return (success, ${fromBytes32(valueType, 'value')}); +} + +/** + * @dev Returns the value associated with \`key\`. O(1). + * + * Requirements: + * + * - \`key\` must be in the map. + */ +function get(${name} storage map, ${keyType} key) internal view returns (${valueType}) { + return ${fromBytes32(valueType, `get(map._inner, ${toBytes32(keyType, 'key')})`)}; +} + +/** + * @dev Return the an array containing all the keys + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the map grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function keys(${name} storage map) internal view returns (${keyType}[] memory) { + bytes32[] memory store = keys(map._inner); + ${keyType}[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableMap {', + [ + 'using EnumerableSet for EnumerableSet.Bytes32Set;', + '', + defaultMap(), + TYPES.map(details => customMap(details).trimEnd()).join('\n\n'), + ], + '}', +); diff --git a/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js b/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js new file mode 100644 index 0000000..cb9bffb --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/templates/EnumerableSet.js @@ -0,0 +1,250 @@ +const format = require('../format-lines'); +const { fromBytes32, toBytes32 } = require('./conversion'); + +const TYPES = [ + { name: 'Bytes32Set', type: 'bytes32' }, + { name: 'AddressSet', type: 'address' }, + { name: 'UintSet', type: 'uint256' }, +]; + +/* eslint-disable max-len */ +const header = `\ +pragma solidity ^0.8.20; + +/** + * @dev Library for managing + * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive + * types. + * + * Sets have the following properties: + * + * - Elements are added, removed, and checked for existence in constant time + * (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; + * + * // Declare a set state variable + * EnumerableSet.AddressSet private mySet; + * } + * \`\`\` + * + * As of v3.3.0, sets of type \`bytes32\` (\`Bytes32Set\`), \`address\` (\`AddressSet\`) + * and \`uint256\` (\`UintSet\`) are supported. + * + * [WARNING] + * ==== + * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure + * unusable. + * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. + * + * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an + * array of EnumerableSet. + * ==== + */ +`; +/* eslint-enable max-len */ + +const defaultSet = () => `\ +// To implement this library for multiple types with as little code +// repetition as possible, we write it in terms of a generic Set type with +// bytes32 values. +// The Set implementation uses private functions, and user-facing +// implementations (such as AddressSet) are just wrappers around the +// underlying Set. +// This means that we can only create new EnumerableSets for types that fit +// in bytes32. + +struct Set { + // Storage of set values + bytes32[] _values; + // Position is the index of the value in the \`values\` array plus 1. + // Position 0 is used to mean a value is not in the set. + mapping(bytes32 value => uint256) _positions; +} + +/** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ +function _add(Set storage set, bytes32 value) private returns (bool) { + if (!_contains(set, value)) { + set._values.push(value); + // The value is stored at length-1, but we add 1 to all indexes + // and use 0 as a sentinel value + set._positions[value] = set._values.length; + return true; + } else { + return false; + } +} + +/** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ +function _remove(Set storage set, bytes32 value) private returns (bool) { + // We cache the value's position to prevent multiple reads from the same storage slot + uint256 position = set._positions[value]; + + if (position != 0) { + // Equivalent to contains(set, value) + // To delete an element from the _values array in O(1), we swap the element to delete with the last one in + // the array, and then remove the last element (sometimes called as 'swap and pop'). + // This modifies the order of the array, as noted in {at}. + + uint256 valueIndex = position - 1; + uint256 lastIndex = set._values.length - 1; + + if (valueIndex != lastIndex) { + bytes32 lastValue = set._values[lastIndex]; + + // Move the lastValue to the index where the value to delete is + set._values[valueIndex] = lastValue; + // Update the tracked position of the lastValue (that was just moved) + set._positions[lastValue] = position; + } + + // Delete the slot where the moved value was stored + set._values.pop(); + + // Delete the tracked position for the deleted slot + delete set._positions[value]; + + return true; + } else { + return false; + } +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function _contains(Set storage set, bytes32 value) private view returns (bool) { + return set._positions[value] != 0; +} + +/** + * @dev Returns the number of values on the set. O(1). + */ +function _length(Set storage set) private view returns (uint256) { + return set._values.length; +} + +/** + * @dev Returns the value stored at position \`index\` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function _at(Set storage set, uint256 index) private view returns (bytes32) { + return set._values[index]; +} + +/** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function _values(Set storage set) private view returns (bytes32[] memory) { + return set._values; +} +`; + +const customSet = ({ name, type }) => `\ +// ${name} + +struct ${name} { + Set _inner; +} + +/** + * @dev Add a value to a set. O(1). + * + * Returns true if the value was added to the set, that is if it was not + * already present. + */ +function add(${name} storage set, ${type} value) internal returns (bool) { + return _add(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Removes a value from a set. O(1). + * + * Returns true if the value was removed from the set, that is if it was + * present. + */ +function remove(${name} storage set, ${type} value) internal returns (bool) { + return _remove(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Returns true if the value is in the set. O(1). + */ +function contains(${name} storage set, ${type} value) internal view returns (bool) { + return _contains(set._inner, ${toBytes32(type, 'value')}); +} + +/** + * @dev Returns the number of values in the set. O(1). + */ +function length(${name} storage set) internal view returns (uint256) { + return _length(set._inner); +} + +/** + * @dev Returns the value stored at position \`index\` in the set. O(1). + * + * Note that there are no guarantees on the ordering of values inside the + * array, and it may change when more values are added or removed. + * + * Requirements: + * + * - \`index\` must be strictly less than {length}. + */ +function at(${name} storage set, uint256 index) internal view returns (${type}) { + return ${fromBytes32(type, '_at(set._inner, index)')}; +} + +/** + * @dev Return the entire set in an array + * + * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed + * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that + * this function has an unbounded cost, and using it as part of a state-changing function may render the function + * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. + */ +function values(${name} storage set) internal view returns (${type}[] memory) { + bytes32[] memory store = _values(set._inner); + ${type}[] memory result; + + /// @solidity memory-safe-assembly + assembly { + result := store + } + + return result; +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library EnumerableSet {', + [defaultSet(), TYPES.map(details => customSet(details).trimEnd()).join('\n\n')], + '}', +); diff --git a/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js b/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js new file mode 100644 index 0000000..f1954a7 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/templates/SafeCast.js @@ -0,0 +1,126 @@ +const format = require('../format-lines'); +const { range } = require('../../helpers'); + +const LENGTHS = range(8, 256, 8).reverse(); // 248 → 8 (in steps of 8) + +const header = `\ +pragma solidity ^0.8.20; + +/** + * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow + * checks. + * + * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can + * easily result in undesired exploitation or bugs, since developers usually + * assume that overflows raise errors. \`SafeCast\` restores this intuition by + * reverting the transaction when such an operation overflows. + * + * Using this library instead of the unchecked operations eliminates an entire + * class of bugs, so it's recommended to use it always. + */ +`; + +const errors = `\ + /** + * @dev Value doesn't fit in an uint of \`bits\` size. + */ + error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value); + + /** + * @dev An int value doesn't fit in an uint of \`bits\` size. + */ + error SafeCastOverflowedIntToUint(int256 value); + + /** + * @dev Value doesn't fit in an int of \`bits\` size. + */ + error SafeCastOverflowedIntDowncast(uint8 bits, int256 value); + + /** + * @dev An uint value doesn't fit in an int of \`bits\` size. + */ + error SafeCastOverflowedUintToInt(uint256 value); +`; + +const toUintDownCast = length => `\ +/** + * @dev Returns the downcasted uint${length} from uint256, reverting on + * overflow (when the input is greater than largest uint${length}). + * + * Counterpart to Solidity's \`uint${length}\` operator. + * + * Requirements: + * + * - input must fit into ${length} bits + */ +function toUint${length}(uint256 value) internal pure returns (uint${length}) { + if (value > type(uint${length}).max) { + revert SafeCastOverflowedUintDowncast(${length}, value); + } + return uint${length}(value); +} +`; + +/* eslint-disable max-len */ +const toIntDownCast = length => `\ +/** + * @dev Returns the downcasted int${length} from int256, reverting on + * overflow (when the input is less than smallest int${length} or + * greater than largest int${length}). + * + * Counterpart to Solidity's \`int${length}\` operator. + * + * Requirements: + * + * - input must fit into ${length} bits + */ +function toInt${length}(int256 value) internal pure returns (int${length} downcasted) { + downcasted = int${length}(value); + if (downcasted != value) { + revert SafeCastOverflowedIntDowncast(${length}, value); + } +} +`; +/* eslint-enable max-len */ + +const toInt = length => `\ +/** + * @dev Converts an unsigned uint${length} into a signed int${length}. + * + * Requirements: + * + * - input must be less than or equal to maxInt${length}. + */ +function toInt${length}(uint${length} value) internal pure returns (int${length}) { + // Note: Unsafe cast below is okay because \`type(int${length}).max\` is guaranteed to be positive + if (value > uint${length}(type(int${length}).max)) { + revert SafeCastOverflowedUintToInt(value); + } + return int${length}(value); +} +`; + +const toUint = length => `\ +/** + * @dev Converts a signed int${length} into an unsigned uint${length}. + * + * Requirements: + * + * - input must be greater than or equal to 0. + */ +function toUint${length}(int${length} value) internal pure returns (uint${length}) { + if (value < 0) { + revert SafeCastOverflowedIntToUint(value); + } + return uint${length}(value); +} +`; + +// GENERATE +module.exports = format( + header.trimEnd(), + 'library SafeCast {', + errors, + [...LENGTHS.map(toUintDownCast), toUint(256), ...LENGTHS.map(toIntDownCast), toInt(256)], + '}', +); diff --git a/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js b/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js new file mode 100644 index 0000000..1c90b5e --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/templates/StorageSlot.js @@ -0,0 +1,78 @@ +const format = require('../format-lines'); +const { capitalize } = require('../../helpers'); + +const TYPES = [ + { type: 'address', isValueType: true }, + { type: 'bool', isValueType: true, name: 'Boolean' }, + { type: 'bytes32', isValueType: true }, + { type: 'uint256', isValueType: true }, + { type: 'string', isValueType: false }, + { type: 'bytes', isValueType: false }, +].map(type => Object.assign(type, { struct: (type.name ?? capitalize(type.type)) + 'Slot' })); + +const header = `\ +pragma solidity ^0.8.20; + +/** + * @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(newImplementation.code.length > 0); + * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; + * } + * } + * \`\`\` + */ +`; + +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/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js b/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js new file mode 100644 index 0000000..9221f7c --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/generate/templates/conversion.js @@ -0,0 +1,30 @@ +function toBytes32(type, value) { + switch (type) { + case 'bytes32': + return value; + case 'uint256': + return `bytes32(${value})`; + case 'address': + return `bytes32(uint256(uint160(${value})))`; + default: + throw new Error(`Conversion from ${type} to bytes32 not supported`); + } +} + +function fromBytes32(type, value) { + switch (type) { + case 'bytes32': + return value; + case 'uint256': + return `uint256(${value})`; + case 'address': + return `address(uint160(uint256(${value})))`; + default: + throw new Error(`Conversion from bytes32 to ${type} not supported`); + } +} + +module.exports = { + toBytes32, + fromBytes32, +}; diff --git a/lib/openzeppelin-contracts/scripts/git-user-config.sh b/lib/openzeppelin-contracts/scripts/git-user-config.sh new file mode 100644 index 0000000..e7b81c3 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/git-user-config.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail -x + +git config user.name 'github-actions' +git config user.email '41898282+github-actions[bot]@users.noreply.github.com' diff --git a/lib/openzeppelin-contracts/scripts/helpers.js b/lib/openzeppelin-contracts/scripts/helpers.js new file mode 100644 index 0000000..fb9aad4 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/helpers.js @@ -0,0 +1,37 @@ +function chunk(array, size = 1) { + return Array.range(Math.ceil(array.length / size)).map(i => array.slice(i * size, i * size + size)); +} + +function range(start, stop = undefined, step = 1) { + if (!stop) { + stop = start; + start = 0; + } + return start < stop + ? Array(Math.ceil((stop - start) / step)) + .fill() + .map((_, i) => start + i * step) + : []; +} + +function unique(array, op = x => x) { + return array.filter((obj, i) => array.findIndex(entry => op(obj) === op(entry)) === i); +} + +function zip(...args) { + return Array(Math.max(...args.map(arg => arg.length))) + .fill(null) + .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/lib/openzeppelin-contracts/scripts/prepack.sh b/lib/openzeppelin-contracts/scripts/prepack.sh new file mode 100755 index 0000000..6af1032 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/prepack.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +set -euo pipefail +shopt -s globstar + +# cross platform `mkdir -p` +mkdirp() { + node -e "fs.mkdirSync('$1', { recursive: true })" +} + +# cd to the root of the repo +cd "$(git rev-parse --show-toplevel)" + +npm run clean + +env COMPILE_MODE=production npm run compile + +mkdirp contracts/build/contracts +cp artifacts/contracts/**/*.json contracts/build/contracts +rm contracts/build/contracts/*.dbg.json +node scripts/remove-ignored-artifacts.js + +cp README.md contracts/ diff --git a/lib/openzeppelin-contracts/scripts/prepare-docs.sh b/lib/openzeppelin-contracts/scripts/prepare-docs.sh new file mode 100755 index 0000000..d1317b0 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/prepare-docs.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail +shopt -s globstar + +OUTDIR="$(node -p 'require("./docs/config.js").outputDir')" + +if [ ! -d node_modules ]; then + npm ci +fi + +rm -rf "$OUTDIR" + +hardhat docgen + +# copy examples and adjust imports +examples_source_dir="contracts/mocks/docs" +examples_target_dir="docs/modules/api/examples" + +for f in "$examples_source_dir"/**/*.sol; do + name="${f/#"$examples_source_dir/"/}" + mkdir -p "$examples_target_dir/$(dirname "$name")" + sed -Ee '/^import/s|"(\.\./)+|"@openzeppelin/contracts/|' "$f" > "$examples_target_dir/$name" +done + +node scripts/gen-nav.js "$OUTDIR" > "$OUTDIR/../nav.adoc" diff --git a/lib/openzeppelin-contracts/scripts/release/format-changelog.js b/lib/openzeppelin-contracts/scripts/release/format-changelog.js new file mode 100755 index 0000000..b8bcc8c --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/format-changelog.js @@ -0,0 +1,33 @@ +#!/usr/bin/env node + +// Adjusts the format of the changelog that changesets generates. +// This is run automatically when npm version is run. + +const fs = require('fs'); +const changelog = fs.readFileSync('CHANGELOG.md', 'utf8'); + +// Groups: +// - 1: Pull Request Number and URL +// - 2: Changeset entry +const RELEASE_LINE_REGEX = /^- (\[#.*?\]\(.*?\))?.*?! - (.*)$/gm; + +// Captures vX.Y.Z or vX.Y.Z-rc.W +const VERSION_TITLE_REGEX = /^## (\d+\.\d+\.\d+(-rc\.\d+)?)$/gm; + +const isPrerelease = process.env.PRERELEASE === 'true'; + +const formatted = changelog + // Remove titles + .replace(/^### Major Changes\n\n/gm, '') + .replace(/^### Minor Changes\n\n/gm, '') + .replace(/^### Patch Changes\n\n/gm, '') + // Remove extra whitespace between items + .replace(/^(- \[.*\n)\n(?=-)/gm, '$1') + // Format each release line + .replace(RELEASE_LINE_REGEX, (_, pr, entry) => (pr ? `- ${entry} (${pr})` : `- ${entry}`)) + // Add date to new version + .replace(VERSION_TITLE_REGEX, `\n## $1 (${new Date().toISOString().split('T')[0]})`) + // Conditionally allow vX.Y.Z.rc-.W sections only in prerelease + .replace(/^## \d\.\d\.\d-rc\S+[^]+?(?=^#)/gm, section => (isPrerelease ? section : '')); + +fs.writeFileSync('CHANGELOG.md', formatted); diff --git a/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js b/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js new file mode 100755 index 0000000..15aa259 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/synchronize-versions.js @@ -0,0 +1,15 @@ +#!/usr/bin/env node + +// Synchronizes the version in contracts/package.json with the one in package.json. +// This is run automatically when npm version is run. + +const fs = require('fs'); + +setVersion('package.json', 'contracts/package.json'); + +function setVersion(from, to) { + const fromJson = JSON.parse(fs.readFileSync(from)); + const toJson = JSON.parse(fs.readFileSync(to)); + toJson.version = fromJson.version; + fs.writeFileSync(to, JSON.stringify(toJson, null, 2) + '\n'); +} diff --git a/lib/openzeppelin-contracts/scripts/release/update-comment.js b/lib/openzeppelin-contracts/scripts/release/update-comment.js new file mode 100755 index 0000000..9d6df26 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/update-comment.js @@ -0,0 +1,34 @@ +#!/usr/bin/env node +const fs = require('fs'); +const proc = require('child_process'); +const semver = require('semver'); +const run = (cmd, ...args) => proc.execFileSync(cmd, args, { encoding: 'utf8' }).trim(); + +const gitStatus = run('git', 'status', '--porcelain', '-uno', 'contracts/**/*.sol'); +if (gitStatus.length > 0) { + console.error('Contracts directory is not clean'); + process.exit(1); +} + +const { version } = require('../../package.json'); + +// Get latest tag according to semver. +const [tag] = run('git', 'tag') + .split(/\r?\n/) + .filter(semver.coerce) // check version can be processed + .filter(v => semver.satisfies(v, `< ${version}`)) // ignores prereleases unless currently a prerelease + .sort(semver.rcompare); + +// Ordering tag → HEAD is important here. +const files = run('git', 'diff', tag, 'HEAD', '--name-only', 'contracts/**/*.sol') + .split(/\r?\n/) + .filter(file => file && !file.match(/mock/i) && fs.existsSync(file)); + +for (const file of files) { + const current = fs.readFileSync(file, 'utf8'); + const updated = current.replace( + /(\/\/ SPDX-License-Identifier:.*)$(\n\/\/ OpenZeppelin Contracts .*$)?/m, + `$1\n// OpenZeppelin Contracts (last updated v${version}) (${file.replace('contracts/', '')})`, + ); + fs.writeFileSync(file, updated); +} diff --git a/lib/openzeppelin-contracts/scripts/release/version.sh b/lib/openzeppelin-contracts/scripts/release/version.sh new file mode 100755 index 0000000..7b0ddea --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/version.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +set -euo pipefail + +changeset version + +scripts/release/format-changelog.js +scripts/release/synchronize-versions.js +scripts/release/update-comment.js + +oz-docs update-version diff --git a/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh b/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh new file mode 100644 index 0000000..bcf9b9a --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/workflow/exit-prerelease.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +npx changeset pre exit rc +git add . +git commit -m "Exit release candidate" +git push origin diff --git a/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js b/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js new file mode 100644 index 0000000..f213106 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/workflow/github-release.js @@ -0,0 +1,48 @@ +const { readFileSync } = require('fs'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ github, context }) => { + const changelog = readFileSync('CHANGELOG.md', 'utf8'); + + await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: `v${version}`, + target_commitish: github.ref_name, + body: extractSection(changelog, version), + prerelease: process.env.PRERELEASE === 'true', + }); +}; + +// From https://github.com/frangio/extract-changelog/blob/master/src/utils/word-regexp.ts +function makeWordRegExp(word) { + const start = word.length > 0 && /\b/.test(word[0]) ? '\\b' : ''; + const end = word.length > 0 && /\b/.test(word[word.length - 1]) ? '\\b' : ''; + return new RegExp(start + [...word].map(c => (/[a-z0-9]/i.test(c) ? c : '\\' + c)).join('') + end); +} + +// From https://github.com/frangio/extract-changelog/blob/master/src/core.ts +function extractSection(document, wantedHeading) { + // ATX Headings as defined in GitHub Flavored Markdown (https://github.github.com/gfm/#atx-headings) + const heading = /^ {0,3}(?#{1,6})(?: [ \t\v\f]*(?.*?)[ \t\v\f]*)?(?:[\n\r]+|$)/gm; + + const wantedHeadingRe = makeWordRegExp(wantedHeading); + + let start, end; + + for (const m of document.matchAll(heading)) { + if (!start) { + if (m.groups.text.search(wantedHeadingRe) === 0) { + start = m; + } + } else if (m.groups.lead.length <= start.groups.lead.length) { + end = m; + break; + } + } + + if (start) { + return document.slice(start.index + start[0].length, end?.index); + } +} diff --git a/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh b/lib/openzeppelin-contracts/scripts/release/workflow/integrity-check.sh new file mode 100644 index 0000000..86e99f9 --- /dev/null +++ b/lib/openzeppelin-contracts/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/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh b/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh new file mode 100644 index 0000000..ce30712 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/workflow/pack.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +dist_tag() { + PACKAGE_JSON_NAME="$(jq -r .name ./package.json)" + LATEST_NPM_VERSION="$(npm info "$PACKAGE_JSON_NAME" version)" + PACKAGE_JSON_VERSION="$(jq -r .version ./package.json)" + + if [ "$PRERELEASE" = "true" ]; then + echo "next" + elif npx semver -r ">$LATEST_NPM_VERSION" "$PACKAGE_JSON_VERSION" > /dev/null; then + echo "latest" + else + # This is a patch for an older version + # npm can't publish without a tag + echo "tmp" + fi +} + +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/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh b/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh new file mode 100644 index 0000000..e490e5d --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/workflow/publish.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash + +set -euo pipefail + +PACKAGE_JSON_NAME="$(tar xfO "$TARBALL" package/package.json | jq -r .name)" +PACKAGE_JSON_VERSION="$(tar xfO "$TARBALL" package/package.json | jq -r .version)" + +# Intentionally escape $ to avoid interpolation and writing the token to disk +echo "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}" > .npmrc + +# Actual publish +npm publish "$TARBALL" --tag "$TAG" + +# Clean up tags +delete_tag() { + npm dist-tag rm "$PACKAGE_JSON_NAME" "$1" +} + +if [ "$TAG" = tmp ]; then + delete_tag "$TAG" +elif [ "$TAG" = latest ]; then + # Delete the next tag if it exists and is a prerelease for what is currently being published + if npm dist-tag ls "$PACKAGE_JSON_NAME" | grep -q "next: $PACKAGE_JSON_VERSION"; then + delete_tag next + fi +fi diff --git a/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js b/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js new file mode 100644 index 0000000..f48ce6e --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/workflow/rerun.js @@ -0,0 +1,7 @@ +module.exports = ({ github, context }) => + github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release-cycle.yml', + ref: process.env.REF || process.env.GITHUB_REF_NAME, + }); diff --git a/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js b/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js new file mode 100644 index 0000000..59b03b2 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/workflow/set-changesets-pr-title.js @@ -0,0 +1,17 @@ +const { coerce, inc, rsort } = require('semver'); +const { join } = require('path'); +const { version } = require(join(__dirname, '../../../package.json')); + +module.exports = async ({ core }) => { + // Variables not in the context + const refName = process.env.GITHUB_REF_NAME; + + // Compare package.json version's next patch vs. first version patch + // A recently opened branch will give the next patch for the previous minor + // So, we get the max against the patch 0 of the release branch's version + const branchPatch0 = coerce(refName.replace('release-v', '')).version; + const packageJsonNextPatch = inc(version, 'patch'); + const [nextVersion] = rsort([branchPatch0, packageJsonNextPatch], false); + + core.exportVariable('TITLE', `Release v${nextVersion}`); +}; diff --git a/lib/openzeppelin-contracts/scripts/release/workflow/start.sh b/lib/openzeppelin-contracts/scripts/release/workflow/start.sh new file mode 100644 index 0000000..7683ec5 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/workflow/start.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Set changeset status location +# This is needed because `changeset status --output` only works with relative routes +CHANGESETS_STATUS_JSON="$(realpath --relative-to=. "$RUNNER_TEMP/status.json")" + +# Save changeset status to temp file +npx changeset status --output="$CHANGESETS_STATUS_JSON" + +# Defensive assertion. SHOULD NOT BE REACHED +if [ "$(jq '.releases | length' "$CHANGESETS_STATUS_JSON")" != 1 ]; then + echo "::error file=$CHANGESETS_STATUS_JSON::The status doesn't contain only 1 release" + exit 1; +fi; + +# Create branch +BRANCH_SUFFIX="$(jq -r '.releases[0].newVersion | gsub("\\.\\d+$"; "")' $CHANGESETS_STATUS_JSON)" +RELEASE_BRANCH="release-v$BRANCH_SUFFIX" +git checkout -b "$RELEASE_BRANCH" + +# Output branch +echo "branch=$RELEASE_BRANCH" >> $GITHUB_OUTPUT + +# Enter in prerelease state +npx changeset pre enter rc +git add . +git commit -m "Start release candidate" + +# Push 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 diff --git a/lib/openzeppelin-contracts/scripts/release/workflow/state.js b/lib/openzeppelin-contracts/scripts/release/workflow/state.js new file mode 100644 index 0000000..914e8de --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/release/workflow/state.js @@ -0,0 +1,112 @@ +const { readPreState } = require('@changesets/pre'); +const { default: readChangesets } = require('@changesets/read'); +const { join } = require('path'); +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 }); + + function setOutput(key, value) { + core.info(`State ${key} = ${value}`); + core.setOutput(key, value); + } + + // Jobs to trigger + setOutput('start', shouldRunStart(state)); + setOutput('promote', shouldRunPromote(state)); + setOutput('changesets', shouldRunChangesets(state)); + setOutput('publish', shouldRunPublish(state)); + setOutput('merge', shouldRunMerge(state)); + + // Global Variables + setOutput('is_prerelease', state.prerelease); +}; + +function shouldRunStart({ isMaster, isWorkflowDispatch, botRun }) { + return isMaster && isWorkflowDispatch && !botRun; +} + +function shouldRunPromote({ isReleaseBranch, isWorkflowDispatch, botRun }) { + return isReleaseBranch && isWorkflowDispatch && !botRun; +} + +function shouldRunChangesets({ isReleaseBranch, isPush, isWorkflowDispatch, botRun }) { + return (isReleaseBranch && isPush) || (isReleaseBranch && isWorkflowDispatch && botRun); +} + +function shouldRunPublish({ isReleaseBranch, isPush, hasPendingChangesets, isPublishedOnNpm }) { + return isReleaseBranch && isPush && !hasPendingChangesets && !isPublishedOnNpm; +} + +function shouldRunMerge({ + isReleaseBranch, + isPush, + prerelease, + isCurrentFinalVersion, + hasPendingChangesets, + prBackExists, +}) { + return isReleaseBranch && isPush && !prerelease && isCurrentFinalVersion && !hasPendingChangesets && !prBackExists; +} + +async function getState({ github, context, core }) { + // Variables not in the context + const refName = process.env.GITHUB_REF_NAME; + const botRun = process.env.TRIGGERING_ACTOR === 'github-actions[bot]'; + + const { changesets, preState } = await readChangesetState(); + + // Static vars + const state = { + refName, + hasPendingChangesets: changesets.length > 0, + prerelease: preState?.mode === 'pre', + isMaster: refName === 'master', + isReleaseBranch: refName.startsWith('release-v'), + isWorkflowDispatch: context.eventName === 'workflow_dispatch', + isPush: context.eventName === 'push', + isCurrentFinalVersion: !version.includes('-rc.'), + botRun, + }; + + // Async vars + const { data: prs } = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + head: `${context.repo.owner}:merge/${state.refName}`, + base: 'master', + state: 'open', + }); + + 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}`); + + return state; +} + +// From https://github.com/changesets/action/blob/v1.4.1/src/readChangesetState.ts +async function readChangesetState(cwd = process.cwd()) { + const preState = await readPreState(cwd); + const isInPreMode = preState !== undefined && preState.mode === 'pre'; + + let changesets = await readChangesets(cwd); + + if (isInPreMode) { + changesets = changesets.filter(x => !preState.changesets.includes(x.id)); + } + + return { + preState: isInPreMode ? preState : undefined, + changesets, + }; +} + +async function isPublishedOnNpm(package, version) { + const res = await fetch(`https://registry.npmjs.com/${package}/${version}`); + return res.ok; +} diff --git a/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js b/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js new file mode 100644 index 0000000..e156032 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/remove-ignored-artifacts.js @@ -0,0 +1,45 @@ +#!/usr/bin/env node + +// This script removes the build artifacts of ignored contracts. + +const fs = require('fs'); +const path = require('path'); +const match = require('micromatch'); + +function readJSON(path) { + return JSON.parse(fs.readFileSync(path)); +} + +const pkgFiles = readJSON('package.json').files; + +// Get only negated patterns. +const ignorePatterns = pkgFiles + .filter(pat => pat.startsWith('!')) + // Remove the negation part. Makes micromatch usage more intuitive. + .map(pat => pat.slice(1)); + +const ignorePatternsSubtrees = ignorePatterns + // Add **/* to ignore all files contained in the directories. + .concat(ignorePatterns.map(pat => path.join(pat, '**/*'))) + .map(p => p.replace(/^\//, '')); + +const artifactsDir = 'contracts/build/contracts'; +const buildinfo = 'artifacts/build-info'; +const filenames = fs.readdirSync(buildinfo); + +let n = 0; + +for (const filename of filenames) { + const solcOutput = readJSON(path.join(buildinfo, filename)).output; + for (const sourcePath in solcOutput.contracts) { + const ignore = match.any(sourcePath, ignorePatternsSubtrees); + if (ignore) { + for (const contract in solcOutput.contracts[sourcePath]) { + fs.unlinkSync(path.join(artifactsDir, contract + '.json')); + n += 1; + } + } + } +} + +console.error(`Removed ${n} mock artifacts`); diff --git a/lib/openzeppelin-contracts/scripts/solhint-custom/index.js b/lib/openzeppelin-contracts/scripts/solhint-custom/index.js new file mode 100644 index 0000000..9625027 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/solhint-custom/index.js @@ -0,0 +1,84 @@ +const path = require('path'); +const minimatch = require('minimatch'); + +// Files matching these patterns will be ignored unless a rule has `static global = true` +const ignore = ['contracts/mocks/**/*', 'test/**/*']; + +class Base { + constructor(reporter, config, source, fileName) { + this.reporter = reporter; + this.ignored = this.constructor.global || ignore.some(p => minimatch(path.normalize(fileName), p)); + this.ruleId = this.constructor.ruleId; + if (this.ruleId === undefined) { + throw Error('missing ruleId static property'); + } + } + + error(node, message) { + if (!this.ignored) { + this.reporter.error(node, this.ruleId, message); + } + } +} + +module.exports = [ + class extends Base { + static ruleId = 'interface-names'; + + ContractDefinition(node) { + if (node.kind === 'interface' && !/^I[A-Z]/.test(node.name)) { + this.error(node, 'Interface names should have a capital I prefix'); + } + } + }, + + class extends Base { + static ruleId = 'private-variables'; + + VariableDeclaration(node) { + const constantOrImmutable = node.isDeclaredConst || node.isImmutable; + if (node.isStateVar && !constantOrImmutable && node.visibility !== 'private') { + this.error(node, 'State variables must be private'); + } + } + }, + + class extends Base { + static ruleId = 'leading-underscore'; + + VariableDeclaration(node) { + if (node.isDeclaredConst) { + // TODO: expand visibility and fix + if (node.visibility === 'private' && /^_/.test(node.name)) { + this.error(node, 'Constant variables should not have leading underscore'); + } + } else if (node.visibility === 'private' && !/^_/.test(node.name)) { + this.error(node, 'Non-constant private variables must have leading underscore'); + } + } + + FunctionDefinition(node) { + if (node.visibility === 'private' || (node.visibility === 'internal' && node.parent.kind !== 'library')) { + if (!/^_/.test(node.name)) { + this.error(node, 'Private and internal functions must have leading underscore'); + } + } + if (node.visibility === 'internal' && node.parent.kind === 'library') { + if (/^_/.test(node.name)) { + this.error(node, 'Library internal functions should not have leading underscore'); + } + } + } + }, + + // TODO: re-enable and fix + // class extends Base { + // static ruleId = 'no-external-virtual'; + // + // FunctionDefinition(node) { + // if (node.visibility == 'external' && node.isVirtual) { + // this.error(node, 'Functions should not be external and virtual'); + // } + // } + // }, +]; diff --git a/lib/openzeppelin-contracts/scripts/solhint-custom/package.json b/lib/openzeppelin-contracts/scripts/solhint-custom/package.json new file mode 100644 index 0000000..075eb92 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/solhint-custom/package.json @@ -0,0 +1,5 @@ +{ + "name": "solhint-plugin-openzeppelin", + "version": "0.0.0", + "private": true +} diff --git a/lib/openzeppelin-contracts/scripts/update-docs-branch.js b/lib/openzeppelin-contracts/scripts/update-docs-branch.js new file mode 100644 index 0000000..324ba0c --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/update-docs-branch.js @@ -0,0 +1,65 @@ +const proc = require('child_process'); +const read = cmd => proc.execSync(cmd, { encoding: 'utf8' }).trim(); +const run = cmd => { + proc.execSync(cmd, { stdio: 'inherit' }); +}; +const tryRead = cmd => { + try { + return read(cmd); + } catch (e) { + return undefined; + } +}; + +const releaseBranchRegex = /^release-v(?(?\d+)\.(?\d+)(?:\.(?\d+))?)$/; + +const currentBranch = read('git rev-parse --abbrev-ref HEAD'); +const match = currentBranch.match(releaseBranchRegex); + +if (!match) { + console.error('Not currently on a release branch'); + process.exit(1); +} + +const pkgVersion = require('../package.json').version; + +if (pkgVersion.includes('-') && !pkgVersion.includes('.0.0-')) { + console.error('Refusing to update docs: non-major prerelease detected'); + process.exit(0); +} + +const current = match.groups; +const docsBranch = `docs-v${current.major}.x`; + +// Fetch remotes and find the docs branch if it exists +run('git fetch --all --no-tags'); +const matchingDocsBranches = tryRead(`git rev-parse --glob='*/${docsBranch}'`); + +if (!matchingDocsBranches) { + // Create the branch + run(`git checkout --orphan ${docsBranch}`); +} else { + const [publishedRef, ...others] = new Set(matchingDocsBranches.split('\n')); + if (others.length > 0) { + console.error( + `Found conflicting ${docsBranch} branches.\n` + + 'Either local branch is outdated or there are multiple matching remote branches.', + ); + process.exit(1); + } + const publishedVersion = JSON.parse(read(`git show ${publishedRef}:package.json`)).version; + const publishedMinor = publishedVersion.match(/\d+\.(?\d+)\.\d+/).groups.minor; + if (current.minor < publishedMinor) { + console.error('Refusing to update docs: newer version is published'); + process.exit(0); + } + + run('git checkout --quiet --detach'); + run(`git reset --soft ${publishedRef}`); + run(`git checkout ${docsBranch}`); +} + +run('npm run prepare-docs'); +run('git add -f docs'); // --force needed because generated docs files are gitignored +run('git commit -m "Update docs"'); +run(`git checkout ${currentBranch}`); diff --git a/lib/openzeppelin-contracts/scripts/upgradeable/README.md b/lib/openzeppelin-contracts/scripts/upgradeable/README.md new file mode 100644 index 0000000..2309f9e --- /dev/null +++ b/lib/openzeppelin-contracts/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/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh b/lib/openzeppelin-contracts/scripts/upgradeable/patch-apply.sh new file mode 100755 index 0000000..d9e1758 --- /dev/null +++ b/lib/openzeppelin-contracts/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/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh b/lib/openzeppelin-contracts/scripts/upgradeable/patch-save.sh new file mode 100755 index 0000000..111e6f1 --- /dev/null +++ b/lib/openzeppelin-contracts/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/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh b/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh new file mode 100644 index 0000000..b8508f0 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/upgradeable/transpile-onto.sh @@ -0,0 +1,54 @@ +#!/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)" +start_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 + +# abort if there are no changes to commit at this point +if git diff --quiet --cached; then + exit +fi + +if [[ -v SUBMODULE_REMOTE ]]; then + lib=lib/openzeppelin-contracts + git submodule add -b "${base#origin/}" "$SUBMODULE_REMOTE" "$lib" + git -C "$lib" checkout "$commit" + git add "$lib" +fi + +git commit -m "Transpile $commit" + +# return to original branch +git checkout "$start_branch" diff --git a/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh b/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh new file mode 100644 index 0000000..ebc8c32 --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/upgradeable/transpile.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +set -euo pipefail -x + +VERSION="$(jq -r .version contracts/package.json)" +DIRNAME="$(dirname -- "${BASH_SOURCE[0]}")" + +bash "$DIRNAME/patch-apply.sh" +sed -i'' -e "s//$VERSION/g" "contracts/package.json" +git add contracts/package.json + +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 +# -n: use namespaces +# -N: exclude from namespaces transformation +# -q: partial transpilation using @openzeppelin/contracts as peer project +npx @openzeppelin/upgrade-safe-transpiler -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/ERC1967Utils.sol' \ + -x '!contracts/proxy/utils/UUPSUpgradeable.sol' \ + -x '!contracts/proxy/beacon/IBeacon.sol' \ + -p 'contracts/**/presets/**/*' \ + -n \ + -N 'contracts/mocks/**/*' \ + -q '@openzeppelin/' + +# delete compilation artifacts of vanilla code +npm run clean diff --git a/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch b/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch new file mode 100644 index 0000000..522f82c --- /dev/null +++ b/lib/openzeppelin-contracts/scripts/upgradeable/upgradeable.patch @@ -0,0 +1,360 @@ +diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md +deleted file mode 100644 +index 2797a0889..000000000 +--- 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 4018cef29..d343a53d8 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 ff596b0c3..000000000 +--- 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 549891e3f..a6b24078e 100644 +--- a/README.md ++++ b/README.md +@@ -23,6 +23,9 @@ + > [!IMPORTANT] + > OpenZeppelin Contracts uses semantic versioning to communicate backwards compatibility of its API and storage layout. For upgradeable contracts, the storage layout of different major versions should be assumed incompatible, for example, it is unsafe to upgrade from 4.9.3 to 5.0.0. Learn more at [Backwards Compatibility](https://docs.openzeppelin.com/contracts/backwards-compatibility). + +++> [!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/upgradeable). +++ + ## Overview + + ### Installation +@@ -30,7 +33,7 @@ + #### Hardhat, Truffle (npm) + + ``` +-$ npm install @openzeppelin/contracts ++$ npm install @openzeppelin/contracts-upgradeable + ``` + + #### Foundry (git) +@@ -42,10 +45,10 @@ $ npm install @openzeppelin/contracts + > Foundry installs the latest version initially, but subsequent `forge update` commands will use the `master` branch. + + ``` +-$ forge install OpenZeppelin/openzeppelin-contracts ++$ forge install OpenZeppelin/openzeppelin-contracts-upgradeable + ``` + +-Add `@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/` in `remappings.txt.` ++Add `@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/` in `remappings.txt.` + + ### Usage + +@@ -54,10 +57,11 @@ Once installed, you can use the contracts in the library by importing them: + ```solidity + pragma solidity ^0.8.20; + +-import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; ++import {ERC721Upgradeable} from "@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/package.json b/contracts/package.json +index 9017953ca..f51c1d38b 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.9.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", +@@ -28,5 +28,8 @@ + "bugs": { + "url": "https://github.com/OpenZeppelin/openzeppelin-contracts/issues" + }, +- "homepage": "https://openzeppelin.com/contracts/" ++ "homepage": "https://openzeppelin.com/contracts/", ++ "peerDependencies": { ++ "@openzeppelin/contracts": "" ++ } + } +diff --git a/contracts/utils/cryptography/EIP712.sol b/contracts/utils/cryptography/EIP712.sol +index 644f6f531..ab8ba05ff 100644 +--- a/contracts/utils/cryptography/EIP712.sol ++++ b/contracts/utils/cryptography/EIP712.sol +@@ -4,7 +4,6 @@ + pragma solidity ^0.8.20; + + import {MessageHashUtils} from "./MessageHashUtils.sol"; +-import {ShortStrings, ShortString} from "../ShortStrings.sol"; + import {IERC5267} from "../../interfaces/IERC5267.sol"; + + /** +@@ -28,28 +27,18 @@ import {IERC5267} from "../../interfaces/IERC5267.sol"; + * 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. +- * +- * @custom:oz-upgrades-unsafe-allow state-variable-immutable + */ + 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. +@@ -64,29 +53,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))); + } + + /** +@@ -125,6 +108,10 @@ 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 + _EIP712Name(), +@@ -139,22 +126,62 @@ abstract contract EIP712 is IERC5267 { + /** + * @dev The name parameter for the EIP712 domain. + * +- * NOTE: By default this function reads _name which is an immutable value. +- * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). ++ * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs ++ * are a concern. + */ +- // solhint-disable-next-line func-name-mixedcase +- function _EIP712Name() internal view returns (string memory) { +- return _name.toStringWithFallback(_nameFallback); ++ function _EIP712Name() internal view virtual returns (string memory) { ++ return _name; + } + + /** + * @dev The version parameter for the EIP712 domain. + * +- * NOTE: By default this function reads _version which is an immutable value. +- * It only reads from storage if necessary (in case the value is too large to fit in a ShortString). ++ * NOTE: This function reads from storage by default, but can be redefined to return a constant value if gas costs ++ * are a concern. + */ +- // solhint-disable-next-line func-name-mixedcase +- function _EIP712Version() internal view returns (string memory) { +- return _version.toStringWithFallback(_versionFallback); ++ function _EIP712Version() internal view virtual 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 3a1617c09..97e59c2d9 100644 +--- a/package.json ++++ b/package.json +@@ -32,7 +32,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/remappings.txt b/remappings.txt +index 304d1386a..a1cd63bee 100644 +--- a/remappings.txt ++++ b/remappings.txt +@@ -1 +1,2 @@ +-@openzeppelin/contracts/=contracts/ ++@openzeppelin/contracts-upgradeable/=contracts/ ++@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/ +diff --git a/test/utils/cryptography/EIP712.test.js b/test/utils/cryptography/EIP712.test.js +index faf01f1a3..b25171a56 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/lib/openzeppelin-contracts/slither.config.json b/lib/openzeppelin-contracts/slither.config.json new file mode 100644 index 0000000..069da1f --- /dev/null +++ b/lib/openzeppelin-contracts/slither.config.json @@ -0,0 +1,5 @@ +{ + "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" +} diff --git a/lib/openzeppelin-contracts/solhint.config.js b/lib/openzeppelin-contracts/solhint.config.js new file mode 100644 index 0000000..123ff91 --- /dev/null +++ b/lib/openzeppelin-contracts/solhint.config.js @@ -0,0 +1,20 @@ +const customRules = require('./scripts/solhint-custom'); + +const rules = [ + 'no-unused-vars', + 'const-name-snakecase', + 'contract-name-camelcase', + 'event-name-camelcase', + 'func-name-mixedcase', + 'func-param-name-mixedcase', + 'modifier-name-mixedcase', + 'var-name-mixedcase', + 'imports-on-top', + 'no-global-import', + ...customRules.map(r => `openzeppelin/${r.ruleId}`), +]; + +module.exports = { + plugins: ['openzeppelin'], + rules: Object.fromEntries(rules.map(r => [r, 'error'])), +}; diff --git a/lib/openzeppelin-contracts/test/TESTING.md b/lib/openzeppelin-contracts/test/TESTING.md new file mode 100644 index 0000000..a5ee932 --- /dev/null +++ b/lib/openzeppelin-contracts/test/TESTING.md @@ -0,0 +1,3 @@ +## Testing + +Unit test are critical to OpenZeppelin Contracts. They help ensure code quality and mitigate against security vulnerabilities. The directory structure within the `/test` directory corresponds to the `/contracts` directory. diff --git a/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js b/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js new file mode 100644 index 0000000..cc3e8d6 --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/AccessControl.behavior.js @@ -0,0 +1,909 @@ +const { expectEvent, constants, BN } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../helpers/customError'); +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(admin, authorized, other, otherAdmin) { + shouldSupportInterfaces(['AccessControl']); + + describe('default admin', function () { + it('deployer has default admin role', async function () { + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin)).to.equal(true); + }); + + it("other roles's admin is the default admin role", async function () { + expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + + it("default admin role's admin is itself", async function () { + expect(await this.accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE); + }); + }); + + describe('granting', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('non-admin cannot grant role to other accounts', async function () { + await expectRevertCustomError( + this.accessControl.grantRole(ROLE, authorized, { from: other }), + 'AccessControlUnauthorizedAccount', + [other, DEFAULT_ADMIN_ROLE], + ); + }); + + it('accounts can be granted a role multiple times', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleGranted'); + }); + }); + + describe('revoking', function () { + it('roles that are not had can be revoked', async function () { + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + + context('with granted role', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('admin can revoke role', async function () { + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: admin }); + + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + }); + + it('non-admin cannot revoke role', async function () { + await expectRevertCustomError( + this.accessControl.revokeRole(ROLE, authorized, { from: other }), + 'AccessControlUnauthorizedAccount', + [other, DEFAULT_ADMIN_ROLE], + ); + }); + + it('a role can be revoked multiple times', async function () { + await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: admin }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + }); + }); + + describe('renouncing', function () { + it('roles that are not had can be renounced', async function () { + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + + context('with granted role', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('bearer can renounce role', async function () { + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: authorized }); + + expect(await this.accessControl.hasRole(ROLE, authorized)).to.equal(false); + }); + + it('only the sender can renounce their roles', async function () { + await expectRevertCustomError( + this.accessControl.renounceRole(ROLE, authorized, { from: admin }), + 'AccessControlBadConfirmation', + [], + ); + }); + + it('a role can be renounced multiple times', async function () { + await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + + const receipt = await this.accessControl.renounceRole(ROLE, authorized, { from: authorized }); + expectEvent.notEmitted(receipt, 'RoleRevoked'); + }); + }); + }); + + describe('setting role admin', function () { + beforeEach(async function () { + const receipt = await this.accessControl.$_setRoleAdmin(ROLE, OTHER_ROLE); + expectEvent(receipt, 'RoleAdminChanged', { + role: ROLE, + previousAdminRole: DEFAULT_ADMIN_ROLE, + newAdminRole: OTHER_ROLE, + }); + + await this.accessControl.grantRole(OTHER_ROLE, otherAdmin, { from: admin }); + }); + + it("a role's admin role can be changed", async function () { + expect(await this.accessControl.getRoleAdmin(ROLE)).to.equal(OTHER_ROLE); + }); + + it('the new admin can grant roles', async function () { + const receipt = await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin }); + expectEvent(receipt, 'RoleGranted', { account: authorized, role: ROLE, sender: otherAdmin }); + }); + + it('the new admin can revoke roles', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: otherAdmin }); + const receipt = await this.accessControl.revokeRole(ROLE, authorized, { from: otherAdmin }); + expectEvent(receipt, 'RoleRevoked', { account: authorized, role: ROLE, sender: otherAdmin }); + }); + + it("a role's previous admins no longer grant roles", async function () { + await expectRevertCustomError( + this.accessControl.grantRole(ROLE, authorized, { from: admin }), + 'AccessControlUnauthorizedAccount', + [admin.toLowerCase(), OTHER_ROLE], + ); + }); + + it("a role's previous admins no longer revoke roles", async function () { + await expectRevertCustomError( + this.accessControl.revokeRole(ROLE, authorized, { from: admin }), + 'AccessControlUnauthorizedAccount', + [admin.toLowerCase(), OTHER_ROLE], + ); + }); + }); + + describe('onlyRole modifier', function () { + beforeEach(async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + }); + + it('do not revert if sender has role', async function () { + await this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: authorized }); + }); + + it("revert if sender doesn't have role #1", async function () { + await expectRevertCustomError( + this.accessControl.methods['$_checkRole(bytes32)'](ROLE, { from: other }), + 'AccessControlUnauthorizedAccount', + [other, ROLE], + ); + }); + + it("revert if sender doesn't have role #2", async function () { + await expectRevertCustomError( + this.accessControl.methods['$_checkRole(bytes32)'](OTHER_ROLE, { from: authorized }), + 'AccessControlUnauthorizedAccount', + [authorized.toLowerCase(), OTHER_ROLE], + ); + }); + }); + + describe('internal functions', function () { + describe('_grantRole', function () { + it('return true if the account does not have the role', async function () { + const receipt = await this.accessControl.$_grantRole(ROLE, authorized); + expectEvent(receipt, 'return$_grantRole', { ret0: true }); + }); + + it('return false if the account has the role', async function () { + await this.accessControl.$_grantRole(ROLE, authorized); + + const receipt = await this.accessControl.$_grantRole(ROLE, authorized); + expectEvent(receipt, 'return$_grantRole', { ret0: false }); + }); + }); + + describe('_revokeRole', function () { + it('return true if the account has the role', async function () { + await this.accessControl.$_grantRole(ROLE, authorized); + + const receipt = await this.accessControl.$_revokeRole(ROLE, authorized); + expectEvent(receipt, 'return$_revokeRole', { ret0: true }); + }); + + it('return false if the account does not have the role', async function () { + const receipt = await this.accessControl.$_revokeRole(ROLE, authorized); + expectEvent(receipt, 'return$_revokeRole', { ret0: false }); + }); + }); + }); +} + +function shouldBehaveLikeAccessControlEnumerable(admin, authorized, other, otherAdmin, otherAuthorized) { + shouldSupportInterfaces(['AccessControlEnumerable']); + + describe('enumerating', function () { + it('role bearers can be enumerated', async function () { + await this.accessControl.grantRole(ROLE, authorized, { from: admin }); + await this.accessControl.grantRole(ROLE, other, { from: admin }); + await this.accessControl.grantRole(ROLE, otherAuthorized, { from: admin }); + await this.accessControl.revokeRole(ROLE, other, { from: admin }); + + const memberCount = await this.accessControl.getRoleMemberCount(ROLE); + expect(memberCount).to.bignumber.equal('2'); + + const bearers = []; + for (let i = 0; i < memberCount; ++i) { + bearers.push(await this.accessControl.getRoleMember(ROLE, i)); + } + + expect(bearers).to.have.members([authorized, otherAuthorized]); + }); + it('role enumeration should be in sync after renounceRole call', async function () { + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('0'); + await this.accessControl.grantRole(ROLE, admin, { from: admin }); + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('1'); + await this.accessControl.renounceRole(ROLE, admin, { from: admin }); + expect(await this.accessControl.getRoleMemberCount(ROLE)).to.bignumber.equal('0'); + }); + }); +} + +function shouldBehaveLikeAccessControlDefaultAdminRules(delay, defaultAdmin, newDefaultAdmin, other) { + shouldSupportInterfaces(['AccessControlDefaultAdminRules']); + + 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 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); + 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 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); + }); + }); + }); + + 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); + }); + } + }); + }); + + 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 () { + await expectRevertCustomError( + this.accessControl.grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), + 'AccessControlEnforcedDefaultAdminRules', + [], + ); + }); + + it('should revert if revoking default admin role', async function () { + await expectRevertCustomError( + this.accessControl.revokeRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), + 'AccessControlEnforcedDefaultAdminRules', + [], + ); + }); + + it("should revert if defaultAdmin's admin is changed", async function () { + await expectRevertCustomError( + this.accessControl.$_setRoleAdmin(DEFAULT_ADMIN_ROLE, OTHER_ROLE), + 'AccessControlEnforcedDefaultAdminRules', + [], + ); + }); + + it('should not grant the default admin role twice', async function () { + await expectRevertCustomError( + this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, defaultAdmin), + 'AccessControlEnforcedDefaultAdminRules', + [], + ); + }); + + describe('begins a default admin transfer', function () { + let receipt; + let acceptSchedule; + + it('reverts if called by non default admin accounts', async function () { + await expectRevertCustomError( + this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: other }), + 'AccessControlUnauthorizedAccount', + [other, 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 }); + + expectEvent.notEmitted(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 acceptSchedule; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(newDefaultAdmin, { from: defaultAdmin }); + acceptSchedule = web3.utils.toBN(await time.latest()).add(delay); + }); + + it('should revert if caller is not pending default admin', async function () { + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + await expectRevertCustomError( + this.accessControl.acceptDefaultAdminTransfer({ from: other }), + 'AccessControlInvalidDefaultAdmin', + [other], + ); + }); + + describe('when caller is pending default admin and delay has passed', function () { + beforeEach(async function () { + await time.setNextBlockTimestamp(acceptSchedule.addn(1)); + }); + + it('accepts a transfer and changes default admin', async function () { + const receipt = await this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }); + + // 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 schedule + const { newAdmin, schedule } = await this.accessControl.pendingDefaultAdmin(); + expect(newAdmin).to.equal(constants.ZERO_ADDRESS); + expect(schedule).to.be.bignumber.equal(ZERO); + }); + }); + + 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 expectRevertCustomError( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + 'AccessControlEnforcedDefaultAdminDelay', + [acceptSchedule], + ); + }); + } + }); + }); + + describe('cancels a default admin transfer', function () { + it('reverts if called by non default admin accounts', async function () { + await expectRevertCustomError( + this.accessControl.cancelDefaultAdminTransfer({ from: other }), + 'AccessControlUnauthorizedAccount', + [other, 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 expectRevertCustomError( + this.accessControl.acceptDefaultAdminTransfer({ from: newDefaultAdmin }), + 'AccessControlInvalidDefaultAdmin', + [newDefaultAdmin], + ); + }); + }); + + 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); + + expectEvent.notEmitted(receipt, 'DefaultAdminTransferCanceled'); + }); + }); + }); + + describe('renounces admin', function () { + let expectedSchedule; + let delayPassed; + let delayNotPassed; + + beforeEach(async function () { + await this.accessControl.beginDefaultAdminTransfer(constants.ZERO_ADDRESS, { from: defaultAdmin }); + 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 () { + await time.setNextBlockTimestamp(delayPassed); + await expectRevertCustomError( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, other, { from: defaultAdmin }), + 'AccessControlBadConfirmation', + [], + ); + }); + + 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); + + // 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, defaultAdmin, { from: defaultAdmin }); + + expect(await this.accessControl.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin)).to.be.false; + expect(await this.accessControl.defaultAdmin()).to.be.equal(constants.ZERO_ADDRESS); + expectEvent(receipt, 'RoleRevoked', { + role: DEFAULT_ADMIN_ROLE, + 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 () { + await time.setNextBlockTimestamp(delayPassed); + await this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }); + + const grantRoleReceipt = await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, other); + expectEvent(grantRoleReceipt, 'RoleGranted', { + role: DEFAULT_ADMIN_ROLE, + account: other, + }); + }); + + describe('schedule not passed', function () { + 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 expectRevertCustomError( + this.accessControl.renounceRole(DEFAULT_ADMIN_ROLE, defaultAdmin, { from: defaultAdmin }), + 'AccessControlEnforcedDefaultAdminDelay', + [expectedSchedule], + ); + }); + } + }); + }); + + describe('changes delay', function () { + it('reverts if called by non default admin accounts', async function () { + await expectRevertCustomError( + this.accessControl.changeDefaultAdminDelay(time.duration.hours(4), { + from: other, + }), + 'AccessControlUnauthorizedAccount', + [other, 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 ? expectEvent.notEmitted : expectEvent; + eventMatcher(receipt, 'DefaultAdminDelayChangeCanceled'); + }); + } + }); + }); + } + }); + + describe('rollbacks a delay change', function () { + it('reverts if called by non default admin accounts', async function () { + await expectRevertCustomError( + this.accessControl.rollbackDefaultAdminDelay({ from: other }), + 'AccessControlUnauthorizedAccount', + [other, 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 }); + }); + + 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 ? expectEvent.notEmitted : 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); + }); + }); + }); +} + +module.exports = { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, + shouldBehaveLikeAccessControlDefaultAdminRules, +}; diff --git a/lib/openzeppelin-contracts/test/access/AccessControl.test.js b/lib/openzeppelin-contracts/test/access/AccessControl.test.js new file mode 100644 index 0000000..14463b5 --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/AccessControl.test.js @@ -0,0 +1,12 @@ +const { DEFAULT_ADMIN_ROLE, shouldBehaveLikeAccessControl } = require('./AccessControl.behavior.js'); + +const AccessControl = artifacts.require('$AccessControl'); + +contract('AccessControl', function (accounts) { + beforeEach(async function () { + this.accessControl = await AccessControl.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl(...accounts); +}); diff --git a/lib/openzeppelin-contracts/test/access/Ownable.test.js b/lib/openzeppelin-contracts/test/access/Ownable.test.js new file mode 100644 index 0000000..f85daec --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/Ownable.test.js @@ -0,0 +1,72 @@ +const { constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const Ownable = artifacts.require('$Ownable'); + +contract('Ownable', function (accounts) { + const [owner, other] = accounts; + + beforeEach(async function () { + this.ownable = await Ownable.new(owner); + }); + + it('rejects zero address for initialOwner', async function () { + await expectRevertCustomError(Ownable.new(constants.ZERO_ADDRESS), 'OwnableInvalidOwner', [constants.ZERO_ADDRESS]); + }); + + it('has an owner', async function () { + expect(await this.ownable.owner()).to.equal(owner); + }); + + describe('transfer ownership', function () { + it('changes owner after transfer', async function () { + const receipt = await this.ownable.transferOwnership(other, { from: owner }); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(other); + }); + + it('prevents non-owners from transferring', async function () { + await expectRevertCustomError( + this.ownable.transferOwnership(other, { from: other }), + 'OwnableUnauthorizedAccount', + [other], + ); + }); + + it('guards ownership against stuck state', async function () { + await expectRevertCustomError( + this.ownable.transferOwnership(ZERO_ADDRESS, { from: owner }), + 'OwnableInvalidOwner', + [ZERO_ADDRESS], + ); + }); + }); + + describe('renounce ownership', function () { + it('loses ownership after renouncement', async function () { + const receipt = await this.ownable.renounceOwnership({ from: owner }); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable.owner()).to.equal(ZERO_ADDRESS); + }); + + it('prevents non-owners from renouncement', async function () { + await expectRevertCustomError(this.ownable.renounceOwnership({ from: other }), 'OwnableUnauthorizedAccount', [ + other, + ]); + }); + + 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/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js b/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js new file mode 100644 index 0000000..bdbac48 --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/Ownable2Step.test.js @@ -0,0 +1,70 @@ +const { constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const Ownable2Step = artifacts.require('$Ownable2Step'); + +contract('Ownable2Step', function (accounts) { + const [owner, accountA, accountB] = accounts; + + beforeEach(async function () { + this.ownable2Step = await Ownable2Step.new(owner); + }); + + describe('transfer ownership', function () { + it('starting a transfer does not change owner', async function () { + const receipt = await this.ownable2Step.transferOwnership(accountA, { from: owner }); + expectEvent(receipt, 'OwnershipTransferStarted', { previousOwner: owner, newOwner: accountA }); + expect(await this.ownable2Step.owner()).to.equal(owner); + expect(await this.ownable2Step.pendingOwner()).to.equal(accountA); + }); + + it('changes owner after transfer', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + const receipt = await this.ownable2Step.acceptOwnership({ from: accountA }); + expectEvent(receipt, 'OwnershipTransferred', { previousOwner: owner, newOwner: accountA }); + expect(await this.ownable2Step.owner()).to.equal(accountA); + 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 expectRevertCustomError( + this.ownable2Step.acceptOwnership({ from: accountB }), + 'OwnableUnauthorizedAccount', + [accountB], + ); + }); + }); + + describe('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 ... + // without it is difficult to cleanly renounce with the two step process + // see: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620#discussion_r957930388 + expect(await this.ownable2Step.owner()).to.equal(ZERO_ADDRESS); + }); + + it('pending owner resets after renouncing ownership', async function () { + await this.ownable2Step.transferOwnership(accountA, { from: owner }); + expect(await this.ownable2Step.pendingOwner()).to.equal(accountA); + await this.ownable2Step.renounceOwnership({ from: owner }); + expect(await this.ownable2Step.pendingOwner()).to.equal(ZERO_ADDRESS); + await expectRevertCustomError( + this.ownable2Step.acceptOwnership({ from: accountA }), + 'OwnableUnauthorizedAccount', + [accountA], + ); + }); + + it('allows to recover access using the internal _transferOwnership', async function () { + await this.ownable2Step.renounceOwnership({ from: owner }); + const receipt = await this.ownable2Step.$_transferOwnership(accountA); + expectEvent(receipt, 'OwnershipTransferred'); + + expect(await this.ownable2Step.owner()).to.equal(accountA); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js b/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js new file mode 100644 index 0000000..af34143 --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/extensions/AccessControlDefaultAdminRules.test.js @@ -0,0 +1,26 @@ +const { time, constants, expectRevert } = 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.hours(10)); + + beforeEach(async function () { + 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), + 'AccessControlInvalidDefaultAdmin', + [constants.ZERO_ADDRESS], + ); + }); + + shouldBehaveLikeAccessControl(...accounts); + shouldBehaveLikeAccessControlDefaultAdminRules(delay, ...accounts); +}); diff --git a/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js b/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js new file mode 100644 index 0000000..7dfb0bc --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/extensions/AccessControlEnumerable.test.js @@ -0,0 +1,17 @@ +const { + DEFAULT_ADMIN_ROLE, + shouldBehaveLikeAccessControl, + shouldBehaveLikeAccessControlEnumerable, +} = require('../AccessControl.behavior.js'); + +const AccessControlEnumerable = artifacts.require('$AccessControlEnumerable'); + +contract('AccessControlEnumerable', function (accounts) { + beforeEach(async function () { + this.accessControl = await AccessControlEnumerable.new({ from: accounts[0] }); + await this.accessControl.$_grantRole(DEFAULT_ADMIN_ROLE, accounts[0]); + }); + + shouldBehaveLikeAccessControl(...accounts); + shouldBehaveLikeAccessControlEnumerable(...accounts); +}); diff --git a/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js b/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js new file mode 100644 index 0000000..9e94af6 --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/manager/AccessManaged.test.js @@ -0,0 +1,142 @@ +const { expectEvent, time, expectRevert } = require('@openzeppelin/test-helpers'); +const { selector } = require('../../helpers/methods'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { + time: { setNextBlockTimestamp }, +} = require('@nomicfoundation/hardhat-network-helpers'); +const { impersonate } = require('../../helpers/account'); + +const AccessManaged = artifacts.require('$AccessManagedTarget'); +const AccessManager = artifacts.require('$AccessManager'); + +const AuthoritiyObserveIsConsuming = artifacts.require('$AuthoritiyObserveIsConsuming'); + +contract('AccessManaged', function (accounts) { + const [admin, roleMember, other] = accounts; + + beforeEach(async function () { + this.authority = await AccessManager.new(admin); + this.managed = await AccessManaged.new(this.authority.address); + }); + + it('sets authority and emits AuthorityUpdated event during construction', async function () { + await expectEvent.inConstruction(this.managed, 'AuthorityUpdated', { + authority: this.authority.address, + }); + expect(await this.managed.authority()).to.eq(this.authority.address); + }); + + describe('restricted modifier', function () { + const method = 'fnRestricted()'; + + beforeEach(async function () { + this.selector = selector(method); + this.role = web3.utils.toBN(42); + await this.authority.$_setTargetFunctionRole(this.managed.address, this.selector, this.role); + await this.authority.$_grantRole(this.role, roleMember, 0, 0); + }); + + it('succeeds when role is granted without execution delay', async function () { + await this.managed.methods[method]({ from: roleMember }); + }); + + it('reverts when role is not granted', async function () { + await expectRevertCustomError(this.managed.methods[method]({ from: other }), 'AccessManagedUnauthorized', [ + other, + ]); + }); + + it('panics in short calldata', async function () { + // We avoid adding the `restricted` modifier to the fallback function because other tests may depend on it + // being accessible without restrictions. We check for the internal `_checkCanCall` instead. + await expectRevert.unspecified(this.managed.$_checkCanCall(other, '0x1234')); + }); + + describe('when role is granted with execution delay', function () { + beforeEach(async function () { + const executionDelay = web3.utils.toBN(911); + await this.authority.$_grantRole(this.role, roleMember, 0, executionDelay); + }); + + it('reverts if the operation is not scheduled', async function () { + const calldata = await this.managed.contract.methods[method]().encodeABI(); + const opId = await this.authority.hashOperation(roleMember, this.managed.address, calldata); + + await expectRevertCustomError(this.managed.methods[method]({ from: roleMember }), 'AccessManagerNotScheduled', [ + opId, + ]); + }); + + it('succeeds if the operation is scheduled', async function () { + // Arguments + const delay = time.duration.hours(12); + const calldata = await this.managed.contract.methods[method]().encodeABI(); + + // Schedule + const timestamp = await time.latest(); + const scheduledAt = timestamp.addn(1); + const when = scheduledAt.add(delay); + await setNextBlockTimestamp(scheduledAt); + await this.authority.schedule(this.managed.address, calldata, when, { + from: roleMember, + }); + + // Set execution date + await setNextBlockTimestamp(when); + + // Shouldn't revert + await this.managed.methods[method]({ from: roleMember }); + }); + }); + }); + + describe('setAuthority', function () { + beforeEach(async function () { + this.newAuthority = await AccessManager.new(admin); + }); + + it('reverts if the caller is not the authority', async function () { + await expectRevertCustomError(this.managed.setAuthority(other, { from: other }), 'AccessManagedUnauthorized', [ + other, + ]); + }); + + it('reverts if the new authority is not a valid authority', async function () { + await impersonate(this.authority.address); + await expectRevertCustomError( + this.managed.setAuthority(other, { from: this.authority.address }), + 'AccessManagedInvalidAuthority', + [other], + ); + }); + + it('sets authority and emits AuthorityUpdated event', async function () { + await impersonate(this.authority.address); + const { receipt } = await this.managed.setAuthority(this.newAuthority.address, { from: this.authority.address }); + await expectEvent(receipt, 'AuthorityUpdated', { + authority: this.newAuthority.address, + }); + expect(await this.managed.authority()).to.eq(this.newAuthority.address); + }); + }); + + describe('isConsumingScheduledOp', function () { + beforeEach(async function () { + this.authority = await AuthoritiyObserveIsConsuming.new(); + this.managed = await AccessManaged.new(this.authority.address); + }); + + it('returns bytes4(0) when not consuming operation', async function () { + expect(await this.managed.isConsumingScheduledOp()).to.eq('0x00000000'); + }); + + it('returns isConsumingScheduledOp selector when consuming operation', async function () { + const receipt = await this.managed.fnRestricted({ from: other }); + await expectEvent.inTransaction(receipt.tx, this.authority, 'ConsumeScheduledOpCalled', { + caller: other, + data: this.managed.contract.methods.fnRestricted().encodeABI(), + isConsuming: selector('isConsumingScheduledOp()'), + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js b/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js new file mode 100644 index 0000000..d528ffb --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/manager/AccessManager.behavior.js @@ -0,0 +1,711 @@ +const { time } = require('@openzeppelin/test-helpers'); +const { + time: { setNextBlockTimestamp }, + setStorageAt, + mine, +} = require('@nomicfoundation/hardhat-network-helpers'); +const { impersonate } = require('../../helpers/account'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { EXPIRATION, EXECUTION_ID_STORAGE_SLOT } = require('../../helpers/access-manager'); + +// ============ COMMON PATHS ============ + +const COMMON_IS_EXECUTING_PATH = { + executing() { + it('succeeds', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + }, + notExecuting() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.role.id], + ); + }); + }, +}; + +const COMMON_GET_ACCESS_PATH = { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.role.id], + ); + }); + }, + afterGrantDelay: undefined, // Diverges if there's an operation delay or not + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.role.id], + ); + }); + }, + afterGrantDelay() { + it('succeeds called directly', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + + it('succeeds via execute', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay: undefined, // Diverges if there's an operation to schedule or not + callerHasNoExecutionDelay() { + it('succeeds called directly', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + + it('succeeds via execute', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.role.id], + ); + }); + }, +}; + +const COMMON_SCHEDULABLE_PATH = { + scheduled: { + before() { + it('reverts as AccessManagerNotReady', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerNotReady', + [this.operationId], + ); + }); + }, + after() { + it('succeeds called directly', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + + it('succeeds via execute', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + expired() { + it('reverts as AccessManagerExpired', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerExpired', + [this.operationId], + ); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerNotScheduled', + [this.operationId], + ); + }); + }, +}; + +const COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY = { + scheduled: { + before() { + it.skip('is not reachable without a delay'); + }, + after() { + it.skip('is not reachable without a delay'); + }, + expired() { + it.skip('is not reachable without a delay'); + }, + }, + notScheduled() { + it('succeeds', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, +}; + +// ============ MODE HELPERS ============ + +/** + * @requires this.{manager,target} + */ +function shouldBehaveLikeClosable({ closed, open }) { + describe('when the manager is closed', function () { + beforeEach('close', async function () { + await this.manager.$_setTargetClosed(this.target.address, true); + }); + + closed(); + }); + + describe('when the manager is open', function () { + beforeEach('open', async function () { + await this.manager.$_setTargetClosed(this.target.address, false); + }); + + open(); + }); +} + +// ============ DELAY HELPERS ============ + +/** + * @requires this.{delay} + */ +function shouldBehaveLikeDelay(type, { before, after }) { + beforeEach('define timestamp when delay takes effect', async function () { + const timestamp = await time.latest(); + this.delayEffect = timestamp.add(this.delay); + }); + + describe(`when ${type} delay has not taken effect yet`, function () { + beforeEach(`set next block timestamp before ${type} takes effect`, async function () { + await setNextBlockTimestamp(this.delayEffect.subn(1)); + }); + + before(); + }); + + describe(`when ${type} delay has taken effect`, function () { + beforeEach(`set next block timestamp when ${type} takes effect`, async function () { + await setNextBlockTimestamp(this.delayEffect); + }); + + after(); + }); +} + +// ============ OPERATION HELPERS ============ + +/** + * @requires this.{manager,scheduleIn,caller,target,calldata} + */ +function shouldBehaveLikeSchedulableOperation({ scheduled: { before, after, expired }, notScheduled }) { + describe('when operation is scheduled', function () { + beforeEach('schedule operation', async function () { + await impersonate(this.caller); // May be a contract + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.scheduleIn, + }); + this.operationId = operationId; + }); + + describe('when operation is not ready for execution', function () { + beforeEach('set next block time before operation is ready', async function () { + this.scheduledAt = await time.latest(); + const schedule = await this.manager.getSchedule(this.operationId); + await setNextBlockTimestamp(schedule.subn(1)); + }); + + before(); + }); + + describe('when operation is ready for execution', function () { + beforeEach('set next block time when operation is ready for execution', async function () { + this.scheduledAt = await time.latest(); + const schedule = await this.manager.getSchedule(this.operationId); + await setNextBlockTimestamp(schedule); + }); + + after(); + }); + + describe('when operation has expired', function () { + beforeEach('set next block time when operation expired', async function () { + this.scheduledAt = await time.latest(); + const schedule = await this.manager.getSchedule(this.operationId); + await setNextBlockTimestamp(schedule.add(EXPIRATION)); + }); + + expired(); + }); + }); + + describe('when operation is not scheduled', function () { + beforeEach('set expected operationId', async function () { + this.operationId = await this.manager.hashOperation(this.caller, this.target.address, this.calldata); + + // Assert operation is not scheduled + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + notScheduled(); + }); +} + +/** + * @requires this.{manager,roles,target,calldata} + */ +function shouldBehaveLikeARestrictedOperation({ callerIsNotTheManager, callerIsTheManager }) { + describe('when the call comes from the manager (msg.sender == manager)', function () { + beforeEach('define caller as manager', async function () { + this.caller = this.manager.address; + await impersonate(this.caller); + }); + + shouldBehaveLikeCanCallExecuting(callerIsTheManager); + }); + + describe('when the call does not come from the manager (msg.sender != manager)', function () { + beforeEach('define non manager caller', function () { + this.caller = this.roles.SOME.members[0]; + }); + + callerIsNotTheManager(); + }); +} + +/** + * @requires this.{manager,roles,executionDelay,operationDelay,target} + */ +function shouldBehaveLikeDelayedOperation() { + describe('with operation delay', function () { + describe('when operation delay is greater than execution delay', function () { + beforeEach('set operation delay', async function () { + this.operationDelay = this.executionDelay.add(time.duration.hours(1)); + await this.manager.$_setTargetAdminDelay(this.target.address, this.operationDelay); + this.scheduleIn = this.operationDelay; // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }); + + describe('when operation delay is shorter than execution delay', function () { + beforeEach('set operation delay', async function () { + this.operationDelay = this.executionDelay.sub(time.duration.hours(1)); + await this.manager.$_setTargetAdminDelay(this.target.address, this.operationDelay); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }); + }); + + describe('without operation delay', function () { + beforeEach('set operation delay', async function () { + this.operationDelay = web3.utils.toBN(0); + await this.manager.$_setTargetAdminDelay(this.target.address, this.operationDelay); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }); +} + +// ============ METHOD HELPERS ============ + +/** + * @requires this.{manager,roles,role,target,calldata} + */ +function shouldBehaveLikeCanCall({ + closed, + open: { + callerIsTheManager, + callerIsNotTheManager: { publicRoleIsRequired, specificRoleIsRequired }, + }, +}) { + shouldBehaveLikeClosable({ + closed, + open() { + shouldBehaveLikeARestrictedOperation({ + callerIsTheManager, + callerIsNotTheManager() { + shouldBehaveLikeHasRole({ + publicRoleIsRequired, + specificRoleIsRequired, + }); + }, + }); + }, + }); +} + +/** + * @requires this.{target,calldata} + */ +function shouldBehaveLikeCanCallExecuting({ executing, notExecuting }) { + describe('when _executionId is in storage for target and selector', function () { + beforeEach('set _executionId flag from calldata and target', async function () { + const executionId = await web3.utils.keccak256( + web3.eth.abi.encodeParameters(['address', 'bytes4'], [this.target.address, this.calldata.substring(0, 10)]), + ); + await setStorageAt(this.manager.address, EXECUTION_ID_STORAGE_SLOT, executionId); + }); + + executing(); + }); + + describe('when _executionId does not match target and selector', notExecuting); +} + +/** + * @requires this.{target,calldata,roles,role} + */ +function shouldBehaveLikeHasRole({ publicRoleIsRequired, specificRoleIsRequired }) { + describe('when the function requires the caller to be granted with the PUBLIC_ROLE', function () { + beforeEach('set target function role as PUBLIC_ROLE', async function () { + this.role = this.roles.PUBLIC; + await this.manager.$_setTargetFunctionRole(this.target.address, this.calldata.substring(0, 10), this.role.id, { + from: this.roles.ADMIN.members[0], + }); + }); + + publicRoleIsRequired(); + }); + + describe('when the function requires the caller to be granted with a role other than PUBLIC_ROLE', function () { + beforeEach('set target function role as PUBLIC_ROLE', async function () { + await this.manager.$_setTargetFunctionRole(this.target.address, this.calldata.substring(0, 10), this.role.id, { + from: this.roles.ADMIN.members[0], + }); + }); + + shouldBehaveLikeGetAccess(specificRoleIsRequired); + }); +} + +/** + * @requires this.{manager,role,caller} + */ +function shouldBehaveLikeGetAccess({ + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + // Because both grant and execution delay are set within the same $_grantRole call + // it's not possible to create a set of tests that diverge between grant and execution delay. + // Therefore, the shouldBehaveLikeDelay arguments are renamed for clarity: + // before => beforeGrantDelay + // after => afterGrantDelay + callerHasAnExecutionDelay: { beforeGrantDelay: case1, afterGrantDelay: case2 }, + callerHasNoExecutionDelay: { beforeGrantDelay: case3, afterGrantDelay: case4 }, + }, + roleGrantingIsNotDelayed: { callerHasAnExecutionDelay: case5, callerHasNoExecutionDelay: case6 }, + }, + requiredRoleIsNotGranted, +}) { + describe('when the required role is granted to the caller', function () { + describe('when role granting is delayed', function () { + beforeEach('define delay', function () { + this.grantDelay = time.duration.minutes(3); + this.delay = this.grantDelay; // For shouldBehaveLikeDelay + }); + + describe('when caller has an execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = time.duration.hours(10); + this.delay = this.grantDelay; + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + shouldBehaveLikeDelay('grant', { before: case1, after: case2 }); + }); + + describe('when caller has no execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = web3.utils.toBN(0); + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + shouldBehaveLikeDelay('grant', { before: case3, after: case4 }); + }); + }); + + describe('when role granting is not delayed', function () { + beforeEach('define delay', function () { + this.grantDelay = web3.utils.toBN(0); + }); + + describe('when caller has an execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = time.duration.hours(10); + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + case5(); + }); + + describe('when caller has no execution delay', function () { + beforeEach('set role and delay', async function () { + this.executionDelay = web3.utils.toBN(0); + await this.manager.$_grantRole(this.role.id, this.caller, this.grantDelay, this.executionDelay); + }); + + case6(); + }); + }); + }); + + describe('when role is not granted', function () { + // Because this helper can be composed with other helpers, it's possible + // that role has been set already by another helper. + // Although this is highly unlikely, we check for it here to avoid false positives. + beforeEach('assert role is unset', async function () { + const { since } = await this.manager.getAccess(this.role.id, this.caller); + expect(since).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + requiredRoleIsNotGranted(); + }); +} + +// ============ ADMIN OPERATION HELPERS ============ + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeDelayedAdminOperation() { + const getAccessPath = COMMON_GET_ACCESS_PATH; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = function () { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + shouldBehaveLikeDelayedOperation(); + }; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeDelayedOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + shouldBehaveLikeARestrictedOperation({ + callerIsTheManager: COMMON_IS_EXECUTING_PATH, + callerIsNotTheManager() { + shouldBehaveLikeHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [ + this.caller, + this.roles.ADMIN.id, // Although PUBLIC is required, target function role doesn't apply to admin ops + ], + ); + }); + }, + specificRoleIsRequired: getAccessPath, + }); + }, + }); +} + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeNotDelayedAdminOperation() { + const getAccessPath = COMMON_GET_ACCESS_PATH; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = function () { + beforeEach('set execution delay', async function () { + await mine(); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + shouldBehaveLikeARestrictedOperation({ + callerIsTheManager: COMMON_IS_EXECUTING_PATH, + callerIsNotTheManager() { + shouldBehaveLikeHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, this.roles.ADMIN.id], // Although PUBLIC_ROLE is required, admin ops are not subject to target function roles + ); + }); + }, + specificRoleIsRequired: getAccessPath, + }); + }, + }); +} + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeRoleAdminOperation(roleAdmin) { + const getAccessPath = COMMON_GET_ACCESS_PATH; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = function () { + beforeEach('set operation delay', async function () { + await mine(); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('set execution delay', async function () { + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + + beforeEach('set target as manager', function () { + this.target = this.manager; + }); + + shouldBehaveLikeARestrictedOperation({ + callerIsTheManager: COMMON_IS_EXECUTING_PATH, + callerIsNotTheManager() { + shouldBehaveLikeHasRole({ + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedAccount', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagerUnauthorizedAccount', + [this.caller, roleAdmin], // Role admin ops require the role's admin + ); + }); + }, + specificRoleIsRequired: getAccessPath, + }); + }, + }); +} + +// ============ RESTRICTED OPERATION HELPERS ============ + +/** + * @requires this.{manager,roles,calldata,role} + */ +function shouldBehaveLikeAManagedRestrictedOperation() { + function revertUnauthorized() { + it('reverts as AccessManagedUnauthorized', async function () { + await expectRevertCustomError( + web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }), + 'AccessManagedUnauthorized', + [this.caller], + ); + }); + } + + const getAccessPath = COMMON_GET_ACCESS_PATH; + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.beforeGrantDelay = + revertUnauthorized; + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasNoExecutionDelay.beforeGrantDelay = + revertUnauthorized; + getAccessPath.requiredRoleIsNotGranted = revertUnauthorized; + + getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = function () { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () { + beforeEach('consume previously set grant delay', async function () { + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }; + + const isExecutingPath = COMMON_IS_EXECUTING_PATH; + isExecutingPath.notExecuting = revertUnauthorized; + + shouldBehaveLikeCanCall({ + closed: revertUnauthorized, + open: { + callerIsTheManager: isExecutingPath, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('succeeds called directly', async function () { + await web3.eth.sendTransaction({ to: this.target.address, data: this.calldata, from: this.caller }); + }); + + it('succeeds via execute', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + specificRoleIsRequired: getAccessPath, + }, + }, + }); +} + +// ============ HELPERS ============ + +/** + * @requires this.{manager, caller, target, calldata} + */ +async function scheduleOperation(manager, { caller, target, calldata, delay }) { + const timestamp = await time.latest(); + const scheduledAt = timestamp.addn(1); + await setNextBlockTimestamp(scheduledAt); // Fix next block timestamp for predictability + const { receipt } = await manager.schedule(target, calldata, scheduledAt.add(delay), { + from: caller, + }); + + return { + receipt, + scheduledAt, + operationId: await manager.hashOperation(caller, target, calldata), + }; +} + +module.exports = { + // COMMON PATHS + COMMON_SCHEDULABLE_PATH, + COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY, + // MODE HELPERS + shouldBehaveLikeClosable, + // DELAY HELPERS + shouldBehaveLikeDelay, + // OPERATION HELPERS + shouldBehaveLikeSchedulableOperation, + // METHOD HELPERS + shouldBehaveLikeCanCall, + shouldBehaveLikeGetAccess, + shouldBehaveLikeHasRole, + // ADMIN OPERATION HELPERS + shouldBehaveLikeDelayedAdminOperation, + shouldBehaveLikeNotDelayedAdminOperation, + shouldBehaveLikeRoleAdminOperation, + // RESTRICTED OPERATION HELPERS + shouldBehaveLikeAManagedRestrictedOperation, + // HELPERS + scheduleOperation, +}; diff --git a/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js b/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js new file mode 100644 index 0000000..705af1a --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/manager/AccessManager.test.js @@ -0,0 +1,2683 @@ +const { web3 } = require('hardhat'); +const { constants, expectEvent, time, expectRevert } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { selector } = require('../../helpers/methods'); +const { clockFromReceipt } = require('../../helpers/time'); +const { + buildBaseRoles, + formatAccess, + EXPIRATION, + MINSETBACK, + EXECUTION_ID_STORAGE_SLOT, + CONSUMING_SCHEDULE_STORAGE_SLOT, +} = require('../../helpers/access-manager'); +const { + // COMMON PATHS + COMMON_SCHEDULABLE_PATH, + COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY, + // MODE HELPERS + shouldBehaveLikeClosable, + // DELAY HELPERS + shouldBehaveLikeDelay, + // OPERATION HELPERS + shouldBehaveLikeSchedulableOperation, + // METHOD HELPERS + shouldBehaveLikeCanCall, + shouldBehaveLikeGetAccess, + shouldBehaveLikeHasRole, + // ADMIN OPERATION HELPERS + shouldBehaveLikeDelayedAdminOperation, + shouldBehaveLikeNotDelayedAdminOperation, + shouldBehaveLikeRoleAdminOperation, + // RESTRICTED OPERATION HELPERS + shouldBehaveLikeAManagedRestrictedOperation, + // HELPERS + scheduleOperation, +} = require('./AccessManager.behavior'); +const { default: Wallet } = require('ethereumjs-wallet'); +const { + mine, + time: { setNextBlockTimestamp }, + getStorageAt, +} = require('@nomicfoundation/hardhat-network-helpers'); +const { MAX_UINT48 } = require('../../helpers/constants'); +const { impersonate } = require('../../helpers/account'); + +const AccessManager = artifacts.require('$AccessManager'); +const AccessManagedTarget = artifacts.require('$AccessManagedTarget'); +const Ownable = artifacts.require('$Ownable'); + +const someAddress = Wallet.generate().getChecksumAddressString(); + +contract('AccessManager', function (accounts) { + const [admin, manager, guardian, member, user, other] = accounts; + + beforeEach(async function () { + this.roles = buildBaseRoles(); + + // Add members + this.roles.ADMIN.members = [admin]; + this.roles.SOME_ADMIN.members = [manager]; + this.roles.SOME_GUARDIAN.members = [guardian]; + this.roles.SOME.members = [member]; + this.roles.PUBLIC.members = [admin, manager, guardian, member, user, other]; + + this.manager = await AccessManager.new(admin); + this.target = await AccessManagedTarget.new(this.manager.address); + + for (const { id: roleId, admin, guardian, members } of Object.values(this.roles)) { + if (roleId === this.roles.PUBLIC.id) continue; // Every address belong to public and is locked + if (roleId === this.roles.ADMIN.id) continue; // Admin set during construction and is locked + + // Set admin role avoiding default + if (admin.id !== this.roles.ADMIN.id) { + await this.manager.$_setRoleAdmin(roleId, admin.id); + } + + // Set guardian role avoiding default + if (guardian.id !== this.roles.ADMIN.id) { + await this.manager.$_setRoleGuardian(roleId, guardian.id); + } + + // Grant role to members + for (const member of members) { + await this.manager.$_grantRole(roleId, member, 0, 0); + } + } + }); + + describe('during construction', function () { + it('grants admin role to initialAdmin', async function () { + const manager = await AccessManager.new(other); + expect(await manager.hasRole(this.roles.ADMIN.id, other).then(formatAccess)).to.be.deep.equal([true, '0']); + }); + + it('rejects zero address for initialAdmin', async function () { + await expectRevertCustomError(AccessManager.new(constants.ZERO_ADDRESS), 'AccessManagerInvalidInitialAdmin', [ + constants.ZERO_ADDRESS, + ]); + }); + + it('initializes setup roles correctly', async function () { + for (const { id: roleId, admin, guardian, members } of Object.values(this.roles)) { + expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(admin.id); + expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(guardian.id); + + for (const user of this.roles.PUBLIC.members) { + expect(await this.manager.hasRole(roleId, user).then(formatAccess)).to.be.deep.equal([ + members.includes(user), + '0', + ]); + } + } + }); + }); + + describe('getters', function () { + describe('#canCall', function () { + beforeEach('set calldata', function () { + this.calldata = '0x12345678'; + this.role = { id: web3.utils.toBN(379204) }; + }); + + shouldBehaveLikeCanCall({ + closed() { + it('should return false and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + someAddress, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + open: { + callerIsTheManager: { + executing() { + it('should return true and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(true); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + notExecuting() { + it('should return false and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('should return true and no delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(true); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation({ + scheduled: { + before() { + beforeEach('consume previously set delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + after() { + beforeEach('consume previously set delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + expired() { + beforeEach('consume previously set delay', async function () { + // Consume previously set delay + await mine(); + }); + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + }, + notScheduled() { + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('should return true and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(true); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('should return false and execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal(this.executionDelay); + }); + }, + callerHasNoExecutionDelay() { + it('should return true and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(true); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('should return false and no execution delay', async function () { + const { immediate, delay } = await this.manager.canCall( + this.caller, + this.target.address, + this.calldata.substring(0, 10), + ); + expect(immediate).to.be.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }, + }, + }, + }, + }); + }); + + describe('#expiration', function () { + it('has a 7 days default expiration', async function () { + expect(await this.manager.expiration()).to.be.bignumber.equal(EXPIRATION); + }); + }); + + describe('#minSetback', function () { + it('has a 5 days default minimum setback', async function () { + expect(await this.manager.minSetback()).to.be.bignumber.equal(MINSETBACK); + }); + }); + + describe('#isTargetClosed', function () { + shouldBehaveLikeClosable({ + closed() { + it('returns true', async function () { + expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(true); + }); + }, + open() { + it('returns false', async function () { + expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(false); + }); + }, + }); + }); + + describe('#getTargetFunctionRole', function () { + const methodSelector = selector('something(address,bytes)'); + + it('returns the target function role', async function () { + const roleId = web3.utils.toBN(21498); + await this.manager.$_setTargetFunctionRole(this.target.address, methodSelector, roleId); + + expect(await this.manager.getTargetFunctionRole(this.target.address, methodSelector)).to.be.bignumber.equal( + roleId, + ); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getTargetFunctionRole(this.target.address, methodSelector)).to.be.bignumber.equal( + this.roles.ADMIN.id, + ); + }); + }); + + describe('#getTargetAdminDelay', function () { + describe('when the target admin delay is setup', function () { + beforeEach('set target admin delay', async function () { + this.oldDelay = await this.manager.getTargetAdminDelay(this.target.address); + this.newDelay = time.duration.days(10); + + await this.manager.$_setTargetAdminDelay(this.target.address, this.newDelay); + this.delay = MINSETBACK; // For shouldBehaveLikeDelay + }); + + shouldBehaveLikeDelay('effect', { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns the old target admin delay', async function () { + expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal(this.oldDelay); + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns the new target admin delay', async function () { + expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal(this.newDelay); + }); + }, + }); + }); + + it('returns the 0 if not set', async function () { + expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal('0'); + }); + }); + + describe('#getRoleAdmin', function () { + const roleId = web3.utils.toBN(5234907); + + it('returns the role admin', async function () { + const adminId = web3.utils.toBN(789433); + + await this.manager.$_setRoleAdmin(roleId, adminId); + + expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(adminId); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(this.roles.ADMIN.id); + }); + }); + + describe('#getRoleGuardian', function () { + const roleId = web3.utils.toBN(5234907); + + it('returns the role guardian', async function () { + const guardianId = web3.utils.toBN(789433); + + await this.manager.$_setRoleGuardian(roleId, guardianId); + + expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(guardianId); + }); + + it('returns the ADMIN role if not set', async function () { + expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(this.roles.ADMIN.id); + }); + }); + + describe('#getRoleGrantDelay', function () { + const roleId = web3.utils.toBN(9248439); + + describe('when the grant admin delay is setup', function () { + beforeEach('set grant admin delay', async function () { + this.oldDelay = await this.manager.getRoleGrantDelay(roleId); + this.newDelay = time.duration.days(11); + + await this.manager.$_setGrantDelay(roleId, this.newDelay); + this.delay = MINSETBACK; // For shouldBehaveLikeDelay + }); + + shouldBehaveLikeDelay('grant', { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns the old role grant delay', async function () { + expect(await this.manager.getRoleGrantDelay(roleId)).to.be.bignumber.equal(this.oldDelay); + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns the new role grant delay', async function () { + expect(await this.manager.getRoleGrantDelay(roleId)).to.be.bignumber.equal(this.newDelay); + }); + }, + }); + }); + + it('returns 0 if delay is not set', async function () { + expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal('0'); + }); + }); + + describe('#getAccess', function () { + beforeEach('set role', function () { + this.role = { id: web3.utils.toBN(9452) }; + this.caller = user; + }); + + shouldBehaveLikeGetAccess({ + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('role is not in effect and execution delay is set', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Not in effect yet + expect(await time.latest()).to.be.bignumber.lt(access[0]); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('access has role in effect and execution delay is set', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + + expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await time.latest()).to.be.bignumber.equal(access[0]); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('access has role not in effect without execution delay', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Not in effect yet + expect(await time.latest()).to.be.bignumber.lt(access[0]); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('role is in effect without execution delay', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await time.latest()).to.be.bignumber.equal(access[0]); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('access has role in effect and execution delay is set', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(await time.latest()); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await time.latest()).to.be.bignumber.equal(access[0]); + }); + }, + callerHasNoExecutionDelay() { + it('access has role in effect without execution delay', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal(await time.latest()); // inEffectSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await time.latest()).to.be.bignumber.equal(access[0]); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('has empty access', async function () { + const access = await this.manager.getAccess(this.role.id, this.caller); + expect(access[0]).to.be.bignumber.equal('0'); // inEffectSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + }); + }, + }); + }); + + describe('#hasRole', function () { + beforeEach('setup shouldBehaveLikeHasRole', function () { + this.role = { id: web3.utils.toBN(49832) }; + this.calldata = '0x1234'; + this.caller = user; + }); + + shouldBehaveLikeHasRole({ + publicRoleIsRequired() { + it('has PUBLIC role', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not have role but execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.false; + expect(executionDelay).to.be.bignumber.eq(this.executionDelay); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('has role and execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq(this.executionDelay); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not have role nor execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.false; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + afterGrantDelay() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('has role and no execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('has role and execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq(this.executionDelay); + }); + }, + callerHasNoExecutionDelay() { + it('has role and no execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.true; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('has no role and no execution delay', async function () { + const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller); + expect(isMember).to.be.false; + expect(executionDelay).to.be.bignumber.eq('0'); + }); + }, + }, + }); + }); + + describe('#getSchedule', function () { + beforeEach('set role and calldata', async function () { + const method = 'fnRestricted()'; + this.caller = user; + this.role = { id: web3.utils.toBN(493590) }; + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = await this.target.contract.methods[method]().encodeABI(); + this.scheduleIn = time.duration.days(10); // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation({ + scheduled: { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns schedule in the future', async function () { + const schedule = await this.manager.getSchedule(this.operationId); + expect(schedule).to.be.bignumber.equal(this.scheduledAt.add(this.scheduleIn)); + expect(schedule).to.be.bignumber.gt(await time.latest()); + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns schedule', async function () { + const schedule = await this.manager.getSchedule(this.operationId); + expect(schedule).to.be.bignumber.equal(this.scheduledAt.add(this.scheduleIn)); + expect(schedule).to.be.bignumber.eq(await time.latest()); + }); + }, + expired() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('returns 0', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0'); + }); + }, + }, + notScheduled() { + it('defaults to 0', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0'); + }); + }, + }); + }); + + describe('#getNonce', function () { + describe('when operation is scheduled', function () { + beforeEach('schedule operation', async function () { + const method = 'fnRestricted()'; + this.caller = user; + this.role = { id: web3.utils.toBN(4209043) }; + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = await this.target.contract.methods[method]().encodeABI(); + this.delay = time.duration.days(10); + + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + this.operationId = operationId; + }); + + it('returns nonce', async function () { + expect(await this.manager.getNonce(this.operationId)).to.be.bignumber.equal('1'); + }); + }); + + describe('when is not scheduled', function () { + it('returns default 0', async function () { + expect(await this.manager.getNonce(web3.utils.keccak256('operation'))).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('#hashOperation', function () { + it('returns an operationId', async function () { + const calldata = '0x123543'; + const address = someAddress; + + const args = [user, address, calldata]; + + expect(await this.manager.hashOperation(...args)).to.be.bignumber.eq( + await web3.utils.keccak256(web3.eth.abi.encodeParameters(['address', 'address', 'bytes'], args)), + ); + }); + }); + }); + + describe('admin operations', function () { + beforeEach('set required role', function () { + this.role = this.roles.ADMIN; + }); + + describe('subject to a delay', function () { + describe('#labelRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'labelRole(uint64,string)'; + const args = [123443, 'TEST']; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it('emits an event with the label', async function () { + expectEvent(await this.manager.labelRole(this.roles.SOME.id, 'Some label', { from: admin }), 'RoleLabel', { + roleId: this.roles.SOME.id, + label: 'Some label', + }); + }); + + it('updates label on a second call', async function () { + await this.manager.labelRole(this.roles.SOME.id, 'Some label', { from: admin }); + + expectEvent(await this.manager.labelRole(this.roles.SOME.id, 'Updated label', { from: admin }), 'RoleLabel', { + roleId: this.roles.SOME.id, + label: 'Updated label', + }); + }); + + it('reverts labeling PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.labelRole(this.roles.PUBLIC.id, 'Some label', { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + it('reverts labeling ADMIN_ROLE', async function () { + await expectRevertCustomError( + this.manager.labelRole(this.roles.ADMIN.id, 'Some label', { from: admin }), + 'AccessManagerLockedRole', + [this.roles.ADMIN.id], + ); + }); + }); + + describe('#setRoleAdmin', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setRoleAdmin(uint64,uint64)'; + const args = [93445, 84532]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it("sets any role's admin if called by an admin", async function () { + expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.SOME_ADMIN.id); + + const { receipt } = await this.manager.setRoleAdmin(this.roles.SOME.id, this.roles.ADMIN.id, { from: admin }); + expectEvent(receipt, 'RoleAdminChanged', { roleId: this.roles.SOME.id, admin: this.roles.ADMIN.id }); + + expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.ADMIN.id); + }); + + it('reverts setting PUBLIC_ROLE admin', async function () { + await expectRevertCustomError( + this.manager.setRoleAdmin(this.roles.PUBLIC.id, this.roles.ADMIN.id, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + it('reverts setting ADMIN_ROLE admin', async function () { + await expectRevertCustomError( + this.manager.setRoleAdmin(this.roles.ADMIN.id, this.roles.ADMIN.id, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.ADMIN.id], + ); + }); + }); + + describe('#setRoleGuardian', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setRoleGuardian(uint64,uint64)'; + const args = [93445, 84532]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it("sets any role's guardian if called by an admin", async function () { + expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.be.bignumber.equal( + this.roles.SOME_GUARDIAN.id, + ); + + const { receipt } = await this.manager.setRoleGuardian(this.roles.SOME.id, this.roles.ADMIN.id, { + from: admin, + }); + expectEvent(receipt, 'RoleGuardianChanged', { roleId: this.roles.SOME.id, guardian: this.roles.ADMIN.id }); + + expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.ADMIN.id); + }); + + it('reverts setting PUBLIC_ROLE admin', async function () { + await expectRevertCustomError( + this.manager.setRoleGuardian(this.roles.PUBLIC.id, this.roles.ADMIN.id, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + it('reverts setting ADMIN_ROLE admin', async function () { + await expectRevertCustomError( + this.manager.setRoleGuardian(this.roles.ADMIN.id, this.roles.ADMIN.id, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.ADMIN.id], + ); + }); + }); + + describe('#setGrantDelay', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setGrantDelay(uint64,uint32)'; + const args = [984910, time.duration.days(2)]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + it('reverts setting grant delay for the PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.setGrantDelay(this.roles.PUBLIC.id, web3.utils.toBN(69), { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + describe('when increasing the delay', function () { + const oldDelay = web3.utils.toBN(10); + const newDelay = web3.utils.toBN(100); + + beforeEach('sets old delay', async function () { + this.role = this.roles.SOME; + await this.manager.$_setGrantDelay(this.role.id, oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + }); + + it('increases the delay after minsetback', async function () { + const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'RoleGrantDelayChanged', { + roleId: this.role.id, + delay: newDelay, + since: timestamp.add(MINSETBACK), + }); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay); + }); + }); + + describe('when reducing the delay', function () { + const oldDelay = time.duration.days(10); + + beforeEach('sets old delay', async function () { + this.role = this.roles.SOME; + await this.manager.$_setGrantDelay(this.role.id, oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + }); + + describe('when the delay difference is shorter than minimum setback', function () { + const newDelay = oldDelay.subn(1); + + it('increases the delay after minsetback', async function () { + const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'RoleGrantDelayChanged', { + roleId: this.role.id, + delay: newDelay, + since: timestamp.add(MINSETBACK), + }); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay); + }); + }); + + describe('when the delay difference is longer than minimum setback', function () { + const newDelay = web3.utils.toBN(1); + + beforeEach('assert delay difference is higher than minsetback', function () { + expect(oldDelay.sub(newDelay)).to.be.bignumber.gt(MINSETBACK); + }); + + it('increases the delay after delay difference', async function () { + const setback = oldDelay.sub(newDelay); + const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'RoleGrantDelayChanged', { + roleId: this.role.id, + delay: newDelay, + since: timestamp.add(setback), + }); + + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay); + await time.increase(setback); + expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay); + }); + }); + }); + }); + + describe('#setTargetAdminDelay', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setTargetAdminDelay(address,uint32)'; + const args = [someAddress, time.duration.days(3)]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeDelayedAdminOperation(); + }); + + describe('when increasing the delay', function () { + const oldDelay = time.duration.days(10); + const newDelay = time.duration.days(11); + const target = someAddress; + + beforeEach('sets old delay', async function () { + await this.manager.$_setTargetAdminDelay(target, oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + }); + + it('increases the delay after minsetback', async function () { + const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'TargetAdminDelayUpdated', { + target, + delay: newDelay, + since: timestamp.add(MINSETBACK), + }); + + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay); + }); + }); + + describe('when reducing the delay', function () { + const oldDelay = time.duration.days(10); + const target = someAddress; + + beforeEach('sets old delay', async function () { + await this.manager.$_setTargetAdminDelay(target, oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + }); + + describe('when the delay difference is shorter than minimum setback', function () { + const newDelay = oldDelay.subn(1); + + it('increases the delay after minsetback', async function () { + const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'TargetAdminDelayUpdated', { + target, + delay: newDelay, + since: timestamp.add(MINSETBACK), + }); + + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + await time.increase(MINSETBACK); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay); + }); + }); + + describe('when the delay difference is longer than minimum setback', function () { + const newDelay = web3.utils.toBN(1); + + beforeEach('assert delay difference is higher than minsetback', function () { + expect(oldDelay.sub(newDelay)).to.be.bignumber.gt(MINSETBACK); + }); + + it('increases the delay after delay difference', async function () { + const setback = oldDelay.sub(newDelay); + const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'TargetAdminDelayUpdated', { + target, + delay: newDelay, + since: timestamp.add(setback), + }); + + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay); + await time.increase(setback); + expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay); + }); + }); + }); + }); + }); + + describe('not subject to a delay', function () { + describe('#updateAuthority', function () { + beforeEach('create a target and a new authority', async function () { + this.newAuthority = await AccessManager.new(admin); + this.newManagedTarget = await AccessManagedTarget.new(this.manager.address); + }); + + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'updateAuthority(address,address)'; + const args = [this.newManagedTarget.address, this.newAuthority.address]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeNotDelayedAdminOperation(); + }); + + it('changes the authority', async function () { + expect(await this.newManagedTarget.authority()).to.be.equal(this.manager.address); + + const { tx } = await this.manager.updateAuthority(this.newManagedTarget.address, this.newAuthority.address, { + from: admin, + }); + + // Managed contract is responsible of notifying the change through an event + await expectEvent.inTransaction(tx, this.newManagedTarget, 'AuthorityUpdated', { + authority: this.newAuthority.address, + }); + + expect(await this.newManagedTarget.authority()).to.be.equal(this.newAuthority.address); + }); + }); + + describe('#setTargetClosed', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setTargetClosed(address,bool)'; + const args = [someAddress, true]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeNotDelayedAdminOperation(); + }); + + it('closes and opens a target', async function () { + const close = await this.manager.setTargetClosed(this.target.address, true, { from: admin }); + expectEvent(close.receipt, 'TargetClosed', { target: this.target.address, closed: true }); + + expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(true); + + const open = await this.manager.setTargetClosed(this.target.address, false, { from: admin }); + expectEvent(open.receipt, 'TargetClosed', { target: this.target.address, closed: false }); + expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(false); + }); + + it('reverts if closing the manager', async function () { + await expectRevertCustomError( + this.manager.setTargetClosed(this.manager.address, true, { from: admin }), + 'AccessManagerLockedAccount', + [this.manager.address], + ); + }); + }); + + describe('#setTargetFunctionRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'setTargetFunctionRole(address,bytes4[],uint64)'; + const args = [someAddress, ['0x12345678'], 443342]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeNotDelayedAdminOperation(); + }); + + const sigs = ['someFunction()', 'someOtherFunction(uint256)', 'oneMoreFunction(address,uint8)'].map(selector); + + it('sets function roles', async function () { + for (const sig of sigs) { + expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal( + this.roles.ADMIN.id, + ); + } + + const { receipt: receipt1 } = await this.manager.setTargetFunctionRole( + this.target.address, + sigs, + this.roles.SOME.id, + { + from: admin, + }, + ); + + for (const sig of sigs) { + expectEvent(receipt1, 'TargetFunctionRoleUpdated', { + target: this.target.address, + selector: sig, + roleId: this.roles.SOME.id, + }); + expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal( + this.roles.SOME.id, + ); + } + + const { receipt: receipt2 } = await this.manager.setTargetFunctionRole( + this.target.address, + [sigs[1]], + this.roles.SOME_ADMIN.id, + { + from: admin, + }, + ); + expectEvent(receipt2, 'TargetFunctionRoleUpdated', { + target: this.target.address, + selector: sigs[1], + roleId: this.roles.SOME_ADMIN.id, + }); + + for (const sig of sigs) { + expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal( + sig == sigs[1] ? this.roles.SOME_ADMIN.id : this.roles.SOME.id, + ); + } + }); + }); + + describe('role admin operations', function () { + const ANOTHER_ADMIN = web3.utils.toBN(0xdeadc0de1); + const ANOTHER_ROLE = web3.utils.toBN(0xdeadc0de2); + + beforeEach('set required role', async function () { + // Make admin a member of ANOTHER_ADMIN + await this.manager.$_grantRole(ANOTHER_ADMIN, admin, 0, 0); + await this.manager.$_setRoleAdmin(ANOTHER_ROLE, ANOTHER_ADMIN); + + this.role = { id: ANOTHER_ADMIN }; + this.user = user; + await this.manager.$_grantRole(this.role.id, this.user, 0, 0); + }); + + describe('#grantRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', function () { + const method = 'grantRole(uint64,address,uint32)'; + const args = [ANOTHER_ROLE, someAddress, 0]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + }); + + shouldBehaveLikeRoleAdminOperation(ANOTHER_ADMIN); + }); + + it('reverts when granting PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.grantRole(this.roles.PUBLIC.id, user, 0, { + from: admin, + }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + describe('when the user is not a role member', function () { + describe('with grant delay', function () { + beforeEach('set grant delay and grant role', async function () { + // Delay granting + this.grantDelay = time.duration.weeks(2); + await this.manager.$_setGrantDelay(ANOTHER_ROLE, this.grantDelay); + await time.increase(MINSETBACK); + + // Grant role + this.executionDelay = time.duration.days(3); + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.executionDelay, { + from: admin, + }); + + this.receipt = receipt; + this.delay = this.grantDelay; // For shouldBehaveLikeDelay + }); + + shouldBehaveLikeDelay('grant', { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not grant role to the user yet', async function () { + const timestamp = await clockFromReceipt.timestamp(this.receipt).then(web3.utils.toBN); + expectEvent(this.receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp.add(this.grantDelay), + delay: this.executionDelay, + newMember: true, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(timestamp.add(this.grantDelay)); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Not in effect yet + const currentTimestamp = await time.latest(); + expect(currentTimestamp).to.be.a.bignumber.lt(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + false, + this.executionDelay.toString(), + ]); + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('grants role to the user', async function () { + const timestamp = await clockFromReceipt.timestamp(this.receipt).then(web3.utils.toBN); + expectEvent(this.receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp.add(this.grantDelay), + delay: this.executionDelay, + newMember: true, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(timestamp.add(this.grantDelay)); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + const currentTimestamp = await time.latest(); + expect(currentTimestamp).to.be.a.bignumber.equal(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.executionDelay.toString(), + ]); + }); + }, + }); + }); + + describe('without grant delay', function () { + beforeEach('set granting delay', async function () { + // Delay granting + this.grantDelay = 0; + await this.manager.$_setGrantDelay(ANOTHER_ROLE, this.grantDelay); + await time.increase(MINSETBACK); + }); + + it('immediately grants the role to the user', async function () { + this.executionDelay = time.duration.days(6); + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.executionDelay, { + from: admin, + }); + + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + expectEvent(receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp, + delay: this.executionDelay, + newMember: true, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(timestamp); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + const currentTimestamp = await time.latest(); + expect(currentTimestamp).to.be.a.bignumber.equal(access[0]); + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.executionDelay.toString(), + ]); + }); + }); + }); + + describe('when the user is already a role member', function () { + beforeEach('make user role member', async function () { + this.previousExecutionDelay = time.duration.days(6); + await this.manager.$_grantRole(ANOTHER_ROLE, this.user, 0, this.previousExecutionDelay); + this.oldAccess = await this.manager.getAccess(ANOTHER_ROLE, user); + }); + + describe('with grant delay', function () { + beforeEach('set granting delay', async function () { + // Delay granting + const grantDelay = time.duration.weeks(2); + await this.manager.$_setGrantDelay(ANOTHER_ROLE, grantDelay); + await time.increase(MINSETBACK); + }); + + describe('when increasing the execution delay', function () { + beforeEach('set increased new execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + + this.newExecutionDelay = this.previousExecutionDelay.add(time.duration.days(4)); + }); + + it('emits event and immediately changes the execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, { + from: admin, + }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + + expectEvent(receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp, + delay: this.newExecutionDelay, + newMember: false, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.newExecutionDelay.toString(), + ]); + }); + }); + + describe('when decreasing the execution delay', function () { + beforeEach('decrease execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + + this.newExecutionDelay = this.previousExecutionDelay.sub(time.duration.days(4)); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, { + from: admin, + }); + this.grantTimestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + + this.receipt = receipt; + this.delay = this.previousExecutionDelay.sub(this.newExecutionDelay); // For shouldBehaveLikeDelay + }); + + it('emits event', function () { + expectEvent(this.receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: this.grantTimestamp.add(this.delay), + delay: this.newExecutionDelay, + newMember: false, + }); + }); + + shouldBehaveLikeDelay('execution delay effect', { + before() { + beforeEach('consume effect delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not change the execution delay yet', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.previousExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal(this.newExecutionDelay); // pendingDelay + expect(access[3]).to.be.bignumber.equal(this.grantTimestamp.add(this.delay)); // pendingDelayEffect + + // Not in effect yet + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + }); + }, + after() { + beforeEach('consume effect delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('changes the execution delay', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.newExecutionDelay.toString(), + ]); + }); + }, + }); + }); + }); + + describe('without grant delay', function () { + beforeEach('set granting delay', async function () { + // Delay granting + const grantDelay = 0; + await this.manager.$_setGrantDelay(ANOTHER_ROLE, grantDelay); + await time.increase(MINSETBACK); + }); + + describe('when increasing the execution delay', function () { + beforeEach('set increased new execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + + this.newExecutionDelay = this.previousExecutionDelay.add(time.duration.days(4)); + }); + + it('emits event and immediately changes the execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, { + from: admin, + }); + const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + + expectEvent(receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: timestamp, + delay: this.newExecutionDelay, + newMember: false, + }); + + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.newExecutionDelay.toString(), + ]); + }); + }); + + describe('when decreasing the execution delay', function () { + beforeEach('decrease execution delay', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + + this.newExecutionDelay = this.previousExecutionDelay.sub(time.duration.days(4)); + const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, { + from: admin, + }); + this.grantTimestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN); + + this.receipt = receipt; + this.delay = this.previousExecutionDelay.sub(this.newExecutionDelay); // For shouldBehaveLikeDelay + }); + + it('emits event', function () { + expectEvent(this.receipt, 'RoleGranted', { + roleId: ANOTHER_ROLE, + account: this.user, + since: this.grantTimestamp.add(this.delay), + delay: this.newExecutionDelay, + newMember: false, + }); + }); + + shouldBehaveLikeDelay('execution delay effect', { + before() { + beforeEach('consume effect delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('does not change the execution delay yet', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.previousExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal(this.newExecutionDelay); // pendingDelay + expect(access[3]).to.be.bignumber.equal(this.grantTimestamp.add(this.delay)); // pendingDelayEffect + + // Not in effect yet + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.previousExecutionDelay.toString(), + ]); + }); + }, + after() { + beforeEach('consume effect delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('changes the execution delay', async function () { + // Access is correctly stored + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + + expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince + expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect + + // Already in effect + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + this.newExecutionDelay.toString(), + ]); + }); + }, + }); + }); + }); + }); + }); + + describe('#revokeRole', function () { + describe('restrictions', function () { + beforeEach('set method and args', async function () { + const method = 'revokeRole(uint64,address)'; + const args = [ANOTHER_ROLE, someAddress]; + this.calldata = this.manager.contract.methods[method](...args).encodeABI(); + + // Need to be set before revoking + await this.manager.$_grantRole(...args, 0, 0); + }); + + shouldBehaveLikeRoleAdminOperation(ANOTHER_ADMIN); + }); + + describe('when role has been granted', function () { + beforeEach('grant role with grant delay', async function () { + this.grantDelay = time.duration.weeks(1); + await this.manager.$_grantRole(ANOTHER_ROLE, user, this.grantDelay, 0); + + this.delay = this.grantDelay; // For shouldBehaveLikeDelay + }); + + shouldBehaveLikeDelay('grant', { + before() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('revokes a granted role that will take effect in the future', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + const { receipt } = await this.manager.revokeRole(ANOTHER_ROLE, user, { from: admin }); + expectEvent(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user }); + + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // effect + }); + }, + after() { + beforeEach('consume previously set grant delay', async function () { + // Consume previously set delay + await mine(); + }); + + it('revokes a granted role that already took effect', async function () { + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + true, + '0', + ]); + + const { receipt } = await this.manager.revokeRole(ANOTHER_ROLE, user, { from: admin }); + expectEvent(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user }); + + expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + + const access = await this.manager.getAccess(ANOTHER_ROLE, user); + expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince + expect(access[1]).to.be.bignumber.equal('0'); // currentDelay + expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay + expect(access[3]).to.be.bignumber.equal('0'); // effect + }); + }, + }); + }); + + describe('when role has not been granted', function () { + it('has no effect', async function () { + expect(await this.manager.hasRole(this.roles.SOME.id, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + const { receipt } = await this.manager.revokeRole(this.roles.SOME.id, user, { from: manager }); + expectEvent.notEmitted(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user }); + expect(await this.manager.hasRole(this.roles.SOME.id, user).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + }); + }); + + it('reverts revoking PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.revokeRole(this.roles.PUBLIC.id, user, { from: admin }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + }); + }); + + describe('self role operations', function () { + describe('#renounceRole', function () { + beforeEach('grant role', async function () { + this.role = { id: web3.utils.toBN(783164) }; + this.caller = user; + await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); + }); + + it('renounces a role', async function () { + expect(await this.manager.hasRole(this.role.id, this.caller).then(formatAccess)).to.be.deep.equal([ + true, + '0', + ]); + const { receipt } = await this.manager.renounceRole(this.role.id, this.caller, { + from: this.caller, + }); + expectEvent(receipt, 'RoleRevoked', { + roleId: this.role.id, + account: this.caller, + }); + expect(await this.manager.hasRole(this.role.id, this.caller).then(formatAccess)).to.be.deep.equal([ + false, + '0', + ]); + }); + + it('reverts if renouncing the PUBLIC_ROLE', async function () { + await expectRevertCustomError( + this.manager.renounceRole(this.roles.PUBLIC.id, this.caller, { + from: this.caller, + }), + 'AccessManagerLockedRole', + [this.roles.PUBLIC.id], + ); + }); + + it('reverts if renouncing with bad caller confirmation', async function () { + await expectRevertCustomError( + this.manager.renounceRole(this.role.id, someAddress, { + from: this.caller, + }), + 'AccessManagerBadConfirmation', + [], + ); + }); + }); + }); + }); + }); + + describe('access managed target operations', function () { + describe('when calling a restricted target function', function () { + const method = 'fnRestricted()'; + + beforeEach('set required role', function () { + this.role = { id: web3.utils.toBN(3597243) }; + this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + }); + + describe('restrictions', function () { + beforeEach('set method and args', function () { + this.calldata = this.target.contract.methods[method]().encodeABI(); + this.caller = user; + }); + + shouldBehaveLikeAManagedRestrictedOperation(); + }); + + it('succeeds called by a role member', async function () { + await this.manager.$_grantRole(this.role.id, user, 0, 0); + + const { receipt } = await this.target.methods[method]({ + data: this.calldata, + from: user, + }); + expectEvent(receipt, 'CalledRestricted', { + caller: user, + }); + }); + }); + + describe('when calling a non-restricted target function', function () { + const method = 'fnUnrestricted()'; + + beforeEach('set required role', async function () { + this.role = { id: web3.utils.toBN(879435) }; + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + }); + + it('succeeds called by anyone', async function () { + const { receipt } = await this.target.methods[method]({ + data: this.calldata, + from: user, + }); + expectEvent(receipt, 'CalledUnrestricted', { + caller: user, + }); + }); + }); + }); + + describe('#schedule', function () { + const method = 'fnRestricted()'; + + beforeEach('set target function role', async function () { + this.role = { id: web3.utils.toBN(498305) }; + this.caller = user; + + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = this.target.contract.methods[method]().encodeABI(); + this.delay = time.duration.weeks(2); + }); + + describe('restrictions', function () { + shouldBehaveLikeCanCall({ + closed() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + open: { + callerIsTheManager: { + executing() { + it.skip('is not reachable because schedule is not restrictable'); + }, + notExecuting() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + afterGrantDelay() { + it('succeeds', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }); + }); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + afterGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + it('succeeds', async function () { + await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + }); + }, + callerHasNoExecutionDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + // scheduleOperation is not used here because it alters the next block timestamp + await expectRevertCustomError( + this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, { + from: this.caller, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + }, + }, + }); + }); + + it('schedules an operation at the specified execution date if it is larger than caller execution delay', async function () { + const { operationId, scheduledAt, receipt } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal(scheduledAt.add(this.delay)); + expectEvent(receipt, 'OperationScheduled', { + operationId, + nonce: '1', + schedule: scheduledAt.add(this.delay), + target: this.target.address, + data: this.calldata, + }); + }); + + it('schedules an operation at the minimum execution date if no specified execution date (when == 0)', async function () { + const executionDelay = await time.duration.hours(72); + await this.manager.$_grantRole(this.role.id, this.caller, 0, executionDelay); + + const timestamp = await time.latest(); + const scheduledAt = timestamp.addn(1); + await setNextBlockTimestamp(scheduledAt); + const { receipt } = await this.manager.schedule(this.target.address, this.calldata, 0, { + from: this.caller, + }); + + const operationId = await this.manager.hashOperation(this.caller, this.target.address, this.calldata); + + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal(scheduledAt.add(executionDelay)); + expectEvent(receipt, 'OperationScheduled', { + operationId, + nonce: '1', + schedule: scheduledAt.add(executionDelay), + target: this.target.address, + data: this.calldata, + }); + }); + + it('increases the nonce of an operation scheduled more than once', async function () { + // Setup and check initial nonce + const expectedOperationId = await web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address', 'address', 'bytes'], + [this.caller, this.target.address, this.calldata], + ), + ); + expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('0'); + + // Schedule + const op1 = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + expectEvent(op1.receipt, 'OperationScheduled', { + operationId: op1.operationId, + nonce: '1', + schedule: op1.scheduledAt.add(this.delay), + target: this.target.address, + data: this.calldata, + }); + expect(expectedOperationId).to.eq(op1.operationId); + + // Consume + await time.increase(this.delay); + await this.manager.$_consumeScheduledOp(expectedOperationId); + + // Check nonce + expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('1'); + + // Schedule again + const op2 = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + expectEvent(op2.receipt, 'OperationScheduled', { + operationId: op2.operationId, + nonce: '2', + schedule: op2.scheduledAt.add(this.delay), + target: this.target.address, + data: this.calldata, + }); + expect(expectedOperationId).to.eq(op2.operationId); + + // Check final nonce + expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('2'); + }); + + it('reverts if the specified execution date is before the current timestamp + caller execution delay', async function () { + const executionDelay = time.duration.weeks(1).add(this.delay); + await this.manager.$_grantRole(this.role.id, this.caller, 0, executionDelay); + + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + + it('reverts if an operation is already schedule', async function () { + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }); + + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.delay, + }), + 'AccessManagerAlreadyScheduled', + [operationId], + ); + }); + + it('panics scheduling calldata with less than 4 bytes', async function () { + const calldata = '0x1234'; // 2 bytes + + // Managed contract + await expectRevert.unspecified( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: calldata, + delay: this.delay, + }), + ); + + // Manager contract + await expectRevert.unspecified( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.manager.address, + calldata: calldata, + delay: this.delay, + }), + ); + }); + + it('reverts scheduling an unknown operation to the manager', async function () { + const calldata = '0x12345678'; + + await expectRevertCustomError( + scheduleOperation(this.manager, { + caller: this.caller, + target: this.manager.address, + calldata, + delay: this.delay, + }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.manager.address, calldata], + ); + }); + }); + + describe('#execute', function () { + const method = 'fnRestricted()'; + + beforeEach('set target function role', async function () { + this.role = { id: web3.utils.toBN(9825430) }; + this.caller = user; + + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); + + this.calldata = this.target.contract.methods[method]().encodeABI(); + }); + + describe('restrictions', function () { + shouldBehaveLikeCanCall({ + closed() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + open: { + callerIsTheManager: { + executing() { + it('succeeds', async function () { + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + }); + }, + notExecuting() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + callerIsNotTheManager: { + publicRoleIsRequired() { + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY); + }, + specificRoleIsRequired: { + requiredRoleIsGranted: { + roleGrantingIsDelayed: { + callerHasAnExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + afterGrantDelay() { + beforeEach('define schedule delay', async function () { + // Consume previously set delay + await mine(); + this.scheduleIn = time.duration.days(21); + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }, + }, + callerHasNoExecutionDelay: { + beforeGrantDelay() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + afterGrantDelay() { + beforeEach('define schedule delay', async function () { + // Consume previously set delay + await mine(); + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY); + }, + }, + }, + roleGrantingIsNotDelayed: { + callerHasAnExecutionDelay() { + beforeEach('define schedule delay', async function () { + this.scheduleIn = time.duration.days(15); + }); + + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH); + }, + callerHasNoExecutionDelay() { + shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY); + }, + }, + }, + requiredRoleIsNotGranted() { + it('reverts as AccessManagerUnauthorizedCall', async function () { + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedCall', + [this.caller, this.target.address, this.calldata.substring(0, 10)], + ); + }); + }, + }, + }, + }, + }); + }); + + it('executes with a delay consuming the scheduled operation', async function () { + const delay = time.duration.hours(4); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // Execution delay is needed so the operation is consumed + + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay, + }); + await time.increase(delay); + const { receipt } = await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + expectEvent(receipt, 'OperationExecuted', { + operationId, + nonce: '1', + }); + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal('0'); + }); + + it('executes with no delay consuming a scheduled operation', async function () { + const delay = time.duration.hours(4); + + // give caller an execution delay + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); + + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay, + }); + + // remove the execution delay + await this.manager.$_grantRole(this.role.id, this.caller, 0, 0); + + await time.increase(delay); + const { receipt } = await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + expectEvent(receipt, 'OperationExecuted', { + operationId, + nonce: '1', + }); + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal('0'); + }); + + it('keeps the original _executionId after finishing the call', async function () { + const executionIdBefore = await getStorageAt(this.manager.address, EXECUTION_ID_STORAGE_SLOT); + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + const executionIdAfter = await getStorageAt(this.manager.address, EXECUTION_ID_STORAGE_SLOT); + expect(executionIdBefore).to.be.bignumber.equal(executionIdAfter); + }); + + it('reverts executing twice', async function () { + const delay = time.duration.hours(2); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // Execution delay is needed so the operation is consumed + + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay, + }); + await time.increase(delay); + await this.manager.execute(this.target.address, this.calldata, { from: this.caller }); + await expectRevertCustomError( + this.manager.execute(this.target.address, this.calldata, { from: this.caller }), + 'AccessManagerNotScheduled', + [operationId], + ); + }); + }); + + describe('#consumeScheduledOp', function () { + beforeEach('define scheduling parameters', async function () { + const method = 'fnRestricted()'; + this.caller = this.target.address; + this.calldata = this.target.contract.methods[method]().encodeABI(); + this.role = { id: web3.utils.toBN(9834983) }; + + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id); + await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay + + this.scheduleIn = time.duration.hours(10); // For shouldBehaveLikeSchedulableOperation + }); + + describe('when caller is not consuming scheduled operation', function () { + beforeEach('set consuming false', async function () { + await this.target.setIsConsumingScheduledOp(false, `0x${CONSUMING_SCHEDULE_STORAGE_SLOT.toString(16)}`); + }); + + it('reverts as AccessManagerUnauthorizedConsume', async function () { + await impersonate(this.caller); + await expectRevertCustomError( + this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }), + 'AccessManagerUnauthorizedConsume', + [this.caller], + ); + }); + }); + + describe('when caller is consuming scheduled operation', function () { + beforeEach('set consuming true', async function () { + await this.target.setIsConsumingScheduledOp(true, `0x${CONSUMING_SCHEDULE_STORAGE_SLOT.toString(16)}`); + }); + + shouldBehaveLikeSchedulableOperation({ + scheduled: { + before() { + it('reverts as AccessManagerNotReady', async function () { + await impersonate(this.caller); + await expectRevertCustomError( + this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }), + 'AccessManagerNotReady', + [this.operationId], + ); + }); + }, + after() { + it('consumes the scheduled operation and resets timepoint', async function () { + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal( + this.scheduledAt.add(this.scheduleIn), + ); + await impersonate(this.caller); + const { receipt } = await this.manager.consumeScheduledOp(this.caller, this.calldata, { + from: this.caller, + }); + expectEvent(receipt, 'OperationExecuted', { + operationId: this.operationId, + nonce: '1', + }); + expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0'); + }); + }, + expired() { + it('reverts as AccessManagerExpired', async function () { + await impersonate(this.caller); + await expectRevertCustomError( + this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }), + 'AccessManagerExpired', + [this.operationId], + ); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await impersonate(this.caller); + await expectRevertCustomError( + this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }), + 'AccessManagerNotScheduled', + [this.operationId], + ); + }); + }, + }); + }); + }); + + describe('#cancelScheduledOp', function () { + const method = 'fnRestricted()'; + + beforeEach('setup scheduling', async function () { + this.caller = this.roles.SOME.members[0]; + await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.roles.SOME.id); + await this.manager.$_grantRole(this.roles.SOME.id, this.caller, 0, 1); // nonzero execution delay + + this.calldata = await this.target.contract.methods[method]().encodeABI(); + this.scheduleIn = time.duration.days(10); // For shouldBehaveLikeSchedulableOperation + }); + + shouldBehaveLikeSchedulableOperation({ + scheduled: { + before() { + describe('when caller is the scheduler', function () { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller }); + }); + }); + + describe('when caller is an admin', function () { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { + from: this.roles.ADMIN.members[0], + }); + }); + }); + + describe('when caller is the role guardian', function () { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { + from: this.roles.SOME_GUARDIAN.members[0], + }); + }); + }); + + describe('when caller is any other account', function () { + it('reverts as AccessManagerUnauthorizedCancel', async function () { + await expectRevertCustomError( + this.manager.cancel(this.caller, this.target.address, this.calldata, { from: other }), + 'AccessManagerUnauthorizedCancel', + [other, this.caller, this.target.address, selector(method)], + ); + }); + }); + }, + after() { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller }); + }); + }, + expired() { + it('succeeds', async function () { + await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller }); + }); + }, + }, + notScheduled() { + it('reverts as AccessManagerNotScheduled', async function () { + await expectRevertCustomError( + this.manager.cancel(this.caller, this.target.address, this.calldata), + 'AccessManagerNotScheduled', + [this.operationId], + ); + }); + }, + }); + + it('cancels an operation and resets schedule', async function () { + const { operationId } = await scheduleOperation(this.manager, { + caller: this.caller, + target: this.target.address, + calldata: this.calldata, + delay: this.scheduleIn, + }); + const { receipt } = await this.manager.cancel(this.caller, this.target.address, this.calldata, { + from: this.caller, + }); + expectEvent(receipt, 'OperationCanceled', { + operationId, + nonce: '1', + }); + expect(await this.manager.getSchedule(operationId)).to.be.bignumber.eq('0'); + }); + }); + + describe('with Ownable target contract', function () { + const roleId = web3.utils.toBN(1); + + beforeEach(async function () { + this.ownable = await Ownable.new(this.manager.address); + + // add user to role + await this.manager.$_grantRole(roleId, user, 0, 0); + }); + + it('initial state', async function () { + expect(await this.ownable.owner()).to.be.equal(this.manager.address); + }); + + describe('Contract is closed', function () { + beforeEach(async function () { + await this.manager.$_setTargetClosed(this.ownable.address, true); + }); + + it('directly call: reverts', async function () { + await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [user]); + }); + + it('relayed call (with role): reverts', async function () { + await expectRevertCustomError( + this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user }), + 'AccessManagerUnauthorizedCall', + [user, this.ownable.address, selector('$_checkOwner()')], + ); + }); + + it('relayed call (without role): reverts', async function () { + await expectRevertCustomError( + this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }), + 'AccessManagerUnauthorizedCall', + [other, this.ownable.address, selector('$_checkOwner()')], + ); + }); + }); + + describe('Contract is managed', function () { + describe('function is open to specific role', function () { + beforeEach(async function () { + await this.manager.$_setTargetFunctionRole(this.ownable.address, selector('$_checkOwner()'), roleId); + }); + + it('directly call: reverts', async function () { + await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [ + user, + ]); + }); + + it('relayed call (with role): success', async function () { + await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user }); + }); + + it('relayed call (without role): reverts', async function () { + await expectRevertCustomError( + this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }), + 'AccessManagerUnauthorizedCall', + [other, this.ownable.address, selector('$_checkOwner()')], + ); + }); + }); + + describe('function is open to public role', function () { + beforeEach(async function () { + await this.manager.$_setTargetFunctionRole( + this.ownable.address, + selector('$_checkOwner()'), + this.roles.PUBLIC.id, + ); + }); + + it('directly call: reverts', async function () { + await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [ + user, + ]); + }); + + it('relayed call (with role): success', async function () { + await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user }); + }); + + it('relayed call (without role): success', async function () { + await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js b/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js new file mode 100644 index 0000000..346be03 --- /dev/null +++ b/lib/openzeppelin-contracts/test/access/manager/AuthorityUtils.test.js @@ -0,0 +1,91 @@ +require('@openzeppelin/test-helpers'); + +const AuthorityUtils = artifacts.require('$AuthorityUtils'); +const NotAuthorityMock = artifacts.require('NotAuthorityMock'); +const AuthorityNoDelayMock = artifacts.require('AuthorityNoDelayMock'); +const AuthorityDelayMock = artifacts.require('AuthorityDelayMock'); +const AuthorityNoResponse = artifacts.require('AuthorityNoResponse'); + +contract('AuthorityUtils', function (accounts) { + const [user, other] = accounts; + + beforeEach(async function () { + this.mock = await AuthorityUtils.new(); + }); + + describe('canCallWithDelay', function () { + describe('when authority does not have a canCall function', function () { + beforeEach(async function () { + this.authority = await NotAuthorityMock.new(); + }); + + it('returns (immediate = 0, delay = 0)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority.address, + user, + other, + '0x12345678', + ); + expect(immediate).to.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }); + + describe('when authority has no delay', function () { + beforeEach(async function () { + this.authority = await AuthorityNoDelayMock.new(); + this.immediate = true; + await this.authority._setImmediate(this.immediate); + }); + + it('returns (immediate, delay = 0)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority.address, + user, + other, + '0x12345678', + ); + expect(immediate).to.equal(this.immediate); + expect(delay).to.be.bignumber.equal('0'); + }); + }); + + describe('when authority replies with a delay', function () { + beforeEach(async function () { + this.authority = await AuthorityDelayMock.new(); + this.immediate = true; + this.delay = web3.utils.toBN(42); + await this.authority._setImmediate(this.immediate); + await this.authority._setDelay(this.delay); + }); + + it('returns (immediate, delay)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority.address, + user, + other, + '0x12345678', + ); + expect(immediate).to.equal(this.immediate); + expect(delay).to.be.bignumber.equal(this.delay); + }); + }); + + describe('when authority replies with empty data', function () { + beforeEach(async function () { + this.authority = await AuthorityNoResponse.new(); + }); + + it('returns (immediate = 0, delay = 0)', async function () { + const { immediate, delay } = await this.mock.$canCallWithDelay( + this.authority.address, + user, + other, + '0x12345678', + ); + expect(immediate).to.equal(false); + expect(delay).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js b/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js new file mode 100644 index 0000000..afd4c04 --- /dev/null +++ b/lib/openzeppelin-contracts/test/finance/VestingWallet.behavior.js @@ -0,0 +1,59 @@ +const { time } = require('@nomicfoundation/hardhat-network-helpers'); +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +function releasedEvent(token, amount) { + return token ? ['ERC20Released', { token: token.address, amount }] : ['EtherReleased', { amount }]; +} + +function shouldBehaveLikeVesting(beneficiary) { + it('check vesting schedule', async function () { + const [vestedAmount, releasable, ...args] = this.token + ? ['vestedAmount(address,uint64)', 'releasable(address)', this.token.address] + : ['vestedAmount(uint64)', 'releasable()']; + + for (const timestamp of this.schedule) { + await time.increaseTo(timestamp); + const vesting = this.vestingFn(timestamp); + + expect(await this.mock.methods[vestedAmount](...args, timestamp)).to.be.bignumber.equal(vesting); + + expect(await this.mock.methods[releasable](...args)).to.be.bignumber.equal(vesting); + } + }); + + it('execute vesting schedule', async function () { + const [release, ...args] = this.token ? ['release(address)', this.token.address] : ['release()']; + + let released = web3.utils.toBN(0); + const before = await this.getBalance(beneficiary); + + { + const receipt = await this.mock.methods[release](...args); + + await expectEvent.inTransaction(receipt.tx, this.mock, ...releasedEvent(this.token, '0')); + + await this.checkRelease(receipt, beneficiary, '0'); + + expect(await this.getBalance(beneficiary)).to.be.bignumber.equal(before); + } + + for (const timestamp of this.schedule) { + await time.setNextBlockTimestamp(timestamp); + const vested = this.vestingFn(timestamp); + + const receipt = await this.mock.methods[release](...args); + await expectEvent.inTransaction(receipt.tx, this.mock, ...releasedEvent(this.token, vested.sub(released))); + + await this.checkRelease(receipt, beneficiary, vested.sub(released)); + + expect(await this.getBalance(beneficiary)).to.be.bignumber.equal(before.add(vested)); + + released = vested; + } + }); +} + +module.exports = { + shouldBehaveLikeVesting, +}; diff --git a/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js b/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js new file mode 100644 index 0000000..918e563 --- /dev/null +++ b/lib/openzeppelin-contracts/test/finance/VestingWallet.test.js @@ -0,0 +1,69 @@ +const { constants, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { web3 } = require('@openzeppelin/test-helpers/src/setup'); +const { expect } = require('chai'); +const { BNmin } = require('../helpers/math'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const VestingWallet = artifacts.require('VestingWallet'); +const ERC20 = artifacts.require('$ERC20'); + +const { shouldBehaveLikeVesting } = require('./VestingWallet.behavior'); + +contract('VestingWallet', function (accounts) { + const [sender, beneficiary] = accounts; + + const amount = web3.utils.toBN(web3.utils.toWei('100')); + const duration = web3.utils.toBN(4 * 365 * 86400); // 4 years + + beforeEach(async function () { + this.start = (await time.latest()).addn(3600); // in 1 hour + this.mock = await VestingWallet.new(beneficiary, this.start, duration); + }); + + it('rejects zero address for beneficiary', async function () { + await expectRevertCustomError( + VestingWallet.new(constants.ZERO_ADDRESS, this.start, duration), + 'OwnableInvalidOwner', + [constants.ZERO_ADDRESS], + ); + }); + + it('check vesting contract', async function () { + expect(await this.mock.owner()).to.be.equal(beneficiary); + expect(await this.mock.start()).to.be.bignumber.equal(this.start); + expect(await this.mock.duration()).to.be.bignumber.equal(duration); + expect(await this.mock.end()).to.be.bignumber.equal(this.start.add(duration)); + }); + + describe('vesting schedule', function () { + beforeEach(async function () { + this.schedule = Array(64) + .fill() + .map((_, i) => web3.utils.toBN(i).mul(duration).divn(60).add(this.start)); + this.vestingFn = timestamp => BNmin(amount, amount.mul(timestamp.sub(this.start)).div(duration)); + }); + + describe('Eth vesting', function () { + beforeEach(async function () { + await web3.eth.sendTransaction({ from: sender, to: this.mock.address, value: amount }); + this.getBalance = account => web3.eth.getBalance(account).then(web3.utils.toBN); + this.checkRelease = () => {}; + }); + + shouldBehaveLikeVesting(beneficiary); + }); + + describe('ERC20 vesting', function () { + beforeEach(async function () { + this.token = await ERC20.new('Name', 'Symbol'); + this.getBalance = account => this.token.balanceOf(account); + this.checkRelease = (receipt, to, value) => + expectEvent.inTransaction(receipt.tx, this.token, 'Transfer', { from: this.mock.address, to, value }); + + await this.token.$_mint(this.mock.address, amount); + }); + + shouldBehaveLikeVesting(beneficiary); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/governance/Governor.t.sol b/lib/openzeppelin-contracts/test/governance/Governor.t.sol new file mode 100644 index 0000000..f631245 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/Governor.t.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {Governor} from "@openzeppelin/contracts/governance/Governor.sol"; + +contract GovernorInternalTest is Test, Governor { + constructor() Governor("") {} + + function testValidDescriptionForProposer(string memory description, address proposer, bool includeProposer) public { + if (includeProposer) { + description = string.concat(description, "#proposer=", Strings.toHexString(proposer)); + } + assertTrue(_isValidDescriptionForProposer(proposer, description)); + } + + function testInvalidDescriptionForProposer( + string memory description, + address commitProposer, + address actualProposer + ) public { + vm.assume(commitProposer != actualProposer); + description = string.concat(description, "#proposer=", Strings.toHexString(commitProposer)); + assertFalse(_isValidDescriptionForProposer(actualProposer, description)); + } + + // We don't need to truly implement implement the missing functions because we are just testing + // internal helpers. + + function clock() public pure override returns (uint48) {} + + // solhint-disable-next-line func-name-mixedcase + function CLOCK_MODE() public pure override returns (string memory) {} + + // solhint-disable-next-line func-name-mixedcase + function COUNTING_MODE() public pure virtual override returns (string memory) {} + + function votingDelay() public pure virtual override returns (uint256) {} + + function votingPeriod() public pure virtual override returns (uint256) {} + + function quorum(uint256) public pure virtual override returns (uint256) {} + + function hasVoted(uint256, address) public pure virtual override returns (bool) {} + + function _quorumReached(uint256) internal pure virtual override returns (bool) {} + + function _voteSucceeded(uint256) internal pure virtual override returns (bool) {} + + function _getVotes(address, uint256, bytes memory) internal pure virtual override returns (uint256) {} + + function _countVote(uint256, address, uint8, uint256, bytes memory) internal virtual override {} +} diff --git a/lib/openzeppelin-contracts/test/governance/Governor.test.js b/lib/openzeppelin-contracts/test/governance/Governor.test.js new file mode 100644 index 0000000..45cceba --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/Governor.test.js @@ -0,0 +1,1024 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const Enums = require('../helpers/enums'); +const { getDomain, domainType } = require('../helpers/eip712'); +const { GovernorHelper, proposalStatesToBitMap } = require('../helpers/governance'); +const { clockFromReceipt } = require('../helpers/time'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); +const { shouldBehaveLikeEIP6372 } = require('./utils/EIP6372.behavior'); +const { ZERO_BYTES32 } = require('@openzeppelin/test-helpers/src/constants'); + +const Governor = artifacts.require('$GovernorMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); +const ERC721 = artifacts.require('$ERC721'); +const ERC1155 = artifacts.require('$ERC1155'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); + +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 name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.chainId = await web3.eth.getChainId(); + try { + this.token = await Token.new(tokenName, tokenSymbol, tokenName, version); + } catch { + // ERC20VotesLegacyMock has a different construction that uses version='1' by default. + 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, mode); + + 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 }); + + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + '', + ); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver', 'Governor']); + 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('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'); + + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal('0'); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(false); + + // 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, + 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(); + + 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.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'), + }); + + await this.helper.waitForDeadline(); + + const txExecute = await this.helper.execute(); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + + 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.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.proposalEta(this.proposal.id)).to.be.bignumber.equal('0'); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(false); + }); + + 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('vote with signature', function () { + const sign = privateKey => async (contract, message) => { + const domain = await getDomain(contract); + return ethSigUtil.signTypedMessage(privateKey, { + data: { + primaryType: 'Ballot', + types: { + EIP712Domain: domainType(domain), + Ballot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + ], + }, + domain, + message, + }, + }); + }; + + afterEach('no other votes are cast for proposalId', async function () { + 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); + }); + + it('votes with an EOA signature', async function () { + const voterBySig = Wallet.generate(); + const voterBySigAddress = web3.utils.toChecksumAddress(voterBySig.getAddressString()); + + await this.token.delegate(voterBySigAddress, { from: voter1 }); + + const nonce = await this.mock.nonces(voterBySigAddress); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + expectEvent( + await this.helper.vote({ + support: Enums.VoteType.For, + voter: voterBySigAddress, + nonce, + signature: sign(voterBySig.getPrivateKey()), + }), + 'VoteCast', + { + voter: voterBySigAddress, + support: Enums.VoteType.For, + }, + ); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, voterBySigAddress)).to.be.equal(true); + expect(await this.mock.nonces(voterBySigAddress)).to.be.bignumber.equal(nonce.addn(1)); + }); + + it('votes with a valid EIP-1271 signature', async function () { + const ERC1271WalletOwner = Wallet.generate(); + ERC1271WalletOwner.address = web3.utils.toChecksumAddress(ERC1271WalletOwner.getAddressString()); + + const wallet = await ERC1271WalletMock.new(ERC1271WalletOwner.address); + + await this.token.delegate(wallet.address, { from: voter1 }); + + const nonce = await this.mock.nonces(wallet.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + expectEvent( + await this.helper.vote({ + support: Enums.VoteType.For, + voter: wallet.address, + nonce, + signature: sign(ERC1271WalletOwner.getPrivateKey()), + }), + 'VoteCast', + { + voter: wallet.address, + support: Enums.VoteType.For, + }, + ); + await this.helper.waitForDeadline(); + await this.helper.execute(); + + // After + expect(await this.mock.hasVoted(this.proposal.id, wallet.address)).to.be.equal(true); + expect(await this.mock.nonces(wallet.address)).to.be.bignumber.equal(nonce.addn(1)); + }); + + afterEach('no other votes are cast', async function () { + 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); + }); + }); + + describe('should revert', function () { + describe('on propose', function () { + it('if proposal already exists', async function () { + await this.helper.propose(); + await expectRevertCustomError(this.helper.propose(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Pending, + ZERO_BYTES32, + ]); + }); + + it('if proposer has below threshold votes', async function () { + const votes = web3.utils.toWei('10'); + const threshold = web3.utils.toWei('1000'); + await this.mock.$_setProposalThreshold(threshold); + await expectRevertCustomError(this.helper.propose({ from: voter1 }), 'GovernorInsufficientProposerVotes', [ + voter1, + votes, + threshold, + ]); + }); + }); + + describe('on vote', function () { + it('if proposal does not exist', async function () { + await expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorNonexistentProposal', + [this.proposal.id], + ); + }); + + it('if voting has not started', async function () { + await this.helper.propose(); + await expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorUnexpectedProposalState', + [this.proposal.id, Enums.ProposalState.Pending, proposalStatesToBitMap([Enums.ProposalState.Active])], + ); + }); + + it('if support value is invalid', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await expectRevertCustomError( + this.helper.vote({ support: web3.utils.toBN('255') }), + 'GovernorInvalidVoteType', + [], + ); + }); + + 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 expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorAlreadyCastVote', + [voter1], + ); + }); + + it('if voting is over', async function () { + await this.helper.propose(); + await this.helper.waitForDeadline(); + await expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorUnexpectedProposalState', + [this.proposal.id, Enums.ProposalState.Defeated, proposalStatesToBitMap([Enums.ProposalState.Active])], + ); + }); + }); + + describe('on vote by signature', function () { + beforeEach(async function () { + this.voterBySig = Wallet.generate(); + this.voterBySig.address = web3.utils.toChecksumAddress(this.voterBySig.getAddressString()); + + this.data = (contract, message) => + getDomain(contract).then(domain => ({ + primaryType: 'Ballot', + types: { + EIP712Domain: domainType(domain), + Ballot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + ], + }, + domain, + message, + })); + + this.signature = (contract, message) => + this.data(contract, message).then(data => + ethSigUtil.signTypedMessage(this.voterBySig.getPrivateKey(), { data }), + ); + + await this.token.delegate(this.voterBySig.address, { from: voter1 }); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + }); + + it('if signature does not match signer', async function () { + const nonce = await this.mock.nonces(this.voterBySig.address); + + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + signature: async (...params) => { + const sig = await this.signature(...params); + const tamperedSig = web3.utils.hexToBytes(sig); + tamperedSig[42] ^= 0xff; + return web3.utils.bytesToHex(tamperedSig); + }, + }; + + await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSignature', [voteParams.voter]); + }); + + it('if vote nonce is incorrect', async function () { + const nonce = await this.mock.nonces(this.voterBySig.address); + + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce: nonce.addn(1), + signature: this.signature, + }; + + await expectRevertCustomError( + this.helper.vote(voteParams), + // The signature check implies the nonce can't be tampered without changing the signer + 'GovernorInvalidSignature', + [voteParams.voter], + ); + }); + }); + + describe('on queue', function () { + it('always', async function () { + await this.helper.propose({ from: proposer }); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await expectRevertCustomError(this.helper.queue(), 'GovernorQueueNotImplemented', []); + }); + }); + + describe('on execute', function () { + it('if proposal does not exist', async function () { + await expectRevertCustomError(this.helper.execute(), 'GovernorNonexistentProposal', [this.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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('if receiver revert without reason', async function () { + 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 expectRevertCustomError(this.helper.execute(), 'FailedInnerCall', []); + }); + + it('if receiver revert with reason', async function () { + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + }); + }); + + describe('state', function () { + it('Unset', async function () { + await expectRevertCustomError(this.mock.state(this.proposal.id), 'GovernorNonexistentProposal', [ + this.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 expectRevertCustomError(this.helper.cancel('internal'), 'GovernorNonexistentProposal', [ + this.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 expectRevertCustomError( + this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }), + 'GovernorUnexpectedProposalState', + [this.proposal.id, Enums.ProposalState.Canceled, proposalStatesToBitMap([Enums.ProposalState.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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.cancel('internal'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap( + [Enums.ProposalState.Canceled, Enums.ProposalState.Expired, Enums.ProposalState.Executed], + { inverted: true }, + ), + ]); + }); + }); + + describe('public', function () { + it('before proposal', async function () { + await expectRevertCustomError(this.helper.cancel('external'), 'GovernorNonexistentProposal', [ + this.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 expectRevertCustomError(this.helper.cancel('external', { from: owner }), 'GovernorOnlyProposer', [ + owner, + ]); + }); + + it('after vote started', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(1); // snapshot + 1 block + + await expectRevertCustomError(this.helper.cancel('external'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Pending]), + ]); + }); + + it('after vote', async function () { + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + + await expectRevertCustomError(this.helper.cancel('external'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Active, + proposalStatesToBitMap([Enums.ProposalState.Pending]), + ]); + }); + + 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 expectRevertCustomError(this.helper.cancel('external'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Succeeded, + proposalStatesToBitMap([Enums.ProposalState.Pending]), + ]); + }); + + 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 expectRevertCustomError(this.helper.cancel('external'), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Pending]), + ]); + }); + }); + }); + + describe('proposal length', function () { + it('empty', async function () { + this.helper.setProposal([], ''); + await expectRevertCustomError(this.helper.propose(), 'GovernorInvalidProposalLength', [0, 0, 0]); + }); + + it('mismatch #1', async function () { + this.helper.setProposal( + { + targets: [], + values: [web3.utils.toWei('0')], + data: [this.receiver.contract.methods.mockFunction().encodeABI()], + }, + '', + ); + await expectRevertCustomError(this.helper.propose(), 'GovernorInvalidProposalLength', [0, 1, 1]); + }); + + it('mismatch #2', async function () { + this.helper.setProposal( + { + targets: [this.receiver.address], + values: [], + data: [this.receiver.contract.methods.mockFunction().encodeABI()], + }, + '', + ); + await expectRevertCustomError(this.helper.propose(), 'GovernorInvalidProposalLength', [1, 1, 0]); + }); + + it('mismatch #3', async function () { + this.helper.setProposal( + { + targets: [this.receiver.address], + values: [web3.utils.toWei('0')], + data: [], + }, + '', + ); + await expectRevertCustomError(this.helper.propose(), 'GovernorInvalidProposalLength', [1, 0, 1]); + }); + }); + + describe('frontrun protection using description suffix', function () { + describe('without protection', function () { + describe('without suffix', function () { + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + + describe('with different suffix', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#wrong-suffix=${proposer}`, + ); + }); + + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + + describe('with proposer suffix but bad address part', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#proposer=0x3C44CdDdB6a900fa2b585dd299e03d12FA429XYZ`, // XYZ are not a valid hex char + ); + }); + + it('propose can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else can propose', async function () { + expectEvent(await this.helper.propose({ from: voter1 }), 'ProposalCreated'); + }); + }); + }); + + describe('with protection via proposer suffix', function () { + beforeEach(async function () { + this.proposal = this.helper.setProposal( + [ + { + target: this.receiver.address, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + value, + }, + ], + `#proposer=${proposer}`, + ); + }); + + it('proposer can propose', async function () { + expectEvent(await this.helper.propose({ from: proposer }), 'ProposalCreated'); + }); + + it('someone else cannot propose', async function () { + await expectRevertCustomError(this.helper.propose({ from: voter1 }), 'GovernorRestrictedProposer', [ + voter1, + ]); + }); + }); + }); + + describe('onlyGovernance updates', function () { + it('setVotingDelay is protected', async function () { + await expectRevertCustomError(this.mock.setVotingDelay('0', { from: owner }), 'GovernorOnlyExecutor', [ + owner, + ]); + }); + + it('setVotingPeriod is protected', async function () { + await expectRevertCustomError(this.mock.setVotingPeriod('32', { from: owner }), 'GovernorOnlyExecutor', [ + owner, + ]); + }); + + it('setProposalThreshold is protected', async function () { + await expectRevertCustomError( + this.mock.setProposalThreshold('1000000000000000000', { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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 () { + const votingPeriod = 0; + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.setVotingPeriod(votingPeriod).encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + await expectRevertCustomError(this.helper.execute(), 'GovernorInvalidVotingPeriod', [votingPeriod]); + }); + + 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 }, + ); + }); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/governance/TimelockController.test.js b/lib/openzeppelin-contracts/test/governance/TimelockController.test.js new file mode 100644 index 0000000..ce051e7 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/TimelockController.test.js @@ -0,0 +1,1286 @@ +const { BN, constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS, ZERO_BYTES32 } = constants; +const { proposalStatesToBitMap } = require('../helpers/governance'); + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../helpers/customError'); +const { OperationState } = require('../helpers/enums'); + +const TimelockController = artifacts.require('TimelockController'); +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); + +const salt = '0x025e7b0be353a74631ad648c667493c0e1cd31caa4cc2d3520fdc171ea0cc726'; // a random value + +function genOperation(target, value, data, predecessor, salt) { + const id = web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address', 'uint256', 'bytes', 'uint256', 'bytes32'], + [target, value, data, predecessor, salt], + ), + ); + return { id, target, value, data, predecessor, salt }; +} + +function genOperationBatch(targets, values, payloads, predecessor, salt) { + const id = web3.utils.keccak256( + web3.eth.abi.encodeParameters( + ['address[]', 'uint256[]', 'bytes[]', 'uint256', 'bytes32'], + [targets, values, payloads, predecessor, salt], + ), + ); + return { id, targets, values, payloads, predecessor, salt }; +} + +contract('TimelockController', function (accounts) { + const [, admin, proposer, canceller, executor, other] = accounts; + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + beforeEach(async function () { + // Deploy new timelock + this.mock = await TimelockController.new(MINDELAY, [proposer], [executor], admin); + + expect(await this.mock.hasRole(CANCELLER_ROLE, proposer)).to.be.equal(true); + await this.mock.revokeRole(CANCELLER_ROLE, proposer, { from: admin }); + await this.mock.grantRole(CANCELLER_ROLE, canceller, { from: admin }); + + // Mocks + this.callreceivermock = await CallReceiverMock.new({ from: admin }); + this.implementation2 = await Implementation2.new({ from: admin }); + }); + + shouldSupportInterfaces(['ERC1155Receiver']); + + it('initial state', async function () { + expect(await this.mock.getMinDelay()).to.be.bignumber.equal(MINDELAY); + + expect(await this.mock.DEFAULT_ADMIN_ROLE()).to.be.equal(DEFAULT_ADMIN_ROLE); + expect(await this.mock.PROPOSER_ROLE()).to.be.equal(PROPOSER_ROLE); + expect(await this.mock.EXECUTOR_ROLE()).to.be.equal(EXECUTOR_ROLE); + expect(await this.mock.CANCELLER_ROLE()).to.be.equal(CANCELLER_ROLE); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, proposer))), + ).to.be.deep.equal([true, false, false]); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, canceller))), + ).to.be.deep.equal([false, true, false]); + + expect( + await Promise.all([PROPOSER_ROLE, CANCELLER_ROLE, EXECUTOR_ROLE].map(role => this.mock.hasRole(role, executor))), + ).to.be.deep.equal([false, false, true]); + }); + + it('optional admin', async function () { + const mock = await TimelockController.new(MINDELAY, [proposer], [executor], ZERO_ADDRESS, { from: other }); + + expect(await mock.hasRole(DEFAULT_ADMIN_ROLE, admin)).to.be.equal(false); + expect(await mock.hasRole(DEFAULT_ADMIN_ROLE, mock.address)).to.be.equal(true); + }); + + describe('methods', function () { + describe('operation hashing', function () { + it('hashOperation', async function () { + this.operation = genOperation( + '0x29cebefe301c6ce1bb36b58654fea275e1cacc83', + '0xf94fdd6e21da21d2', + '0xa3bc5104', + '0xba41db3be0a9929145cfe480bd0f1f003689104d275ae912099f925df424ef94', + '0x60d9109846ab510ed75c15f979ae366a8a2ace11d34ba9788c13ac296db50e6e', + ); + expect( + await this.mock.hashOperation( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + ), + ).to.be.equal(this.operation.id); + }); + + it('hashOperationBatch', async function () { + this.operation = genOperationBatch( + Array(8).fill('0x2d5f21620e56531c1d59c2df9b8e95d129571f71'), + Array(8).fill('0x2b993cfce932ccee'), + Array(8).fill('0xcf51966b'), + '0xce8f45069cc71d25f71ba05062de1a3974f9849b004de64a70998bca9d29c2e7', + '0x8952d74c110f72bfe5accdf828c74d53a7dfb71235dfa8a1e8c75d8576b372ff', + ); + expect( + await this.mock.hashOperationBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + ), + ).to.be.equal(this.operation.id); + }); + }); + describe('simple', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperation( + '0x31754f590B97fD975Eb86938f18Cc304E264D2F2', + 0, + '0x3bf92ccc', + ZERO_BYTES32, + salt, + ); + }); + + it('proposer can schedule', async function () { + const receipt = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + expectEvent(receipt, 'CallScheduled', { + id: this.operation.id, + index: web3.utils.toBN(0), + target: this.operation.target, + value: web3.utils.toBN(this.operation.value), + data: this.operation.data, + 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); + + expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( + web3.utils.toBN(block.timestamp).add(MINDELAY), + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + + await expectRevertCustomError( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Unset)], + ); + }); + + it('prevent non-proposer from committing', async function () { + await expectRevertCustomError( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: other }, + ), + `AccessControlUnauthorizedAccount`, + [other, PROPOSER_ROLE], + ); + }); + + it('enforce minimum delay', async function () { + await expectRevertCustomError( + this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1, + { from: proposer }, + ), + 'TimelockInsufficientDelay', + [MINDELAY, MINDELAY - 1], + ); + }); + + 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 () { + beforeEach(async function () { + this.operation = genOperation( + '0xAe22104DCD970750610E6FE15E623468A98b15f7', + 0, + '0x13e414de', + ZERO_BYTES32, + '0xc1059ed2dc130227aa1d1d539ac94c641306905c020436c636e19e3fab56fc7f', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expectRevertCustomError( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + ({ receipt: this.receipt, logs: this.logs } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('revert if execution comes too early 1/2', async function () { + await expectRevertCustomError( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + it('revert if execution comes too early 2/2', async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp - 5); // -1 is too tight, test sometime fails + + await expectRevertCustomError( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + describe('on time', function () { + beforeEach(async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp); + }); + + it('executor can reveal', async function () { + const receipt = await this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ); + expectEvent(receipt, 'CallExecuted', { + id: this.operation.id, + index: web3.utils.toBN(0), + target: this.operation.target, + value: web3.utils.toBN(this.operation.value), + data: this.operation.data, + }); + }); + + it('prevent non-executor from revealing', async function () { + await expectRevertCustomError( + this.mock.execute( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + { from: other }, + ), + `AccessControlUnauthorizedAccount`, + [other, 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 expectRevertCustomError( + this.mock.execute( + reentrantOperation.target, + reentrantOperation.value, + reentrantOperation.data, + reentrantOperation.predecessor, + reentrantOperation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [reentrantOperation.id, proposalStatesToBitMap(OperationState.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, + }); + }); + }); + }); + }); + }); + + describe('batch', function () { + describe('schedule', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0xEd912250835c812D4516BBD80BdaEA1bB63a293C'), + Array(8).fill(0), + Array(8).fill('0x2fcb7a88'), + ZERO_BYTES32, + '0x6cf9d042ade5de78bed9ffd075eb4b2a4f6b1736932c2dc8af517d6e066f51f5', + ); + }); + + it('proposer can schedule', async function () { + const receipt = await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + for (const i in this.operation.targets) { + expectEvent(receipt, 'CallScheduled', { + id: this.operation.id, + index: web3.utils.toBN(i), + target: this.operation.targets[i], + value: web3.utils.toBN(this.operation.values[i]), + data: this.operation.payloads[i], + 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); + + expect(await this.mock.getTimestamp(this.operation.id)).to.be.bignumber.equal( + web3.utils.toBN(block.timestamp).add(MINDELAY), + ); + }); + + it('prevent overwriting active operation', async function () { + await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ); + + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Unset)], + ); + }); + + it('length of batch parameter must match #1', async function () { + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockInvalidOperationLength', + [this.operation.targets.length, this.operation.payloads.length, 0], + ); + }); + + it('length of batch parameter must match #1', async function () { + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + ), + 'TimelockInvalidOperationLength', + [this.operation.targets.length, 0, this.operation.payloads.length], + ); + }); + + it('prevent non-proposer from committing', async function () { + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: other }, + ), + `AccessControlUnauthorizedAccount`, + [other, PROPOSER_ROLE], + ); + }); + + it('enforce minimum delay', async function () { + await expectRevertCustomError( + this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY - 1, + { from: proposer }, + ), + 'TimelockInsufficientDelay', + [MINDELAY, MINDELAY - 1], + ); + }); + }); + + describe('execute', function () { + beforeEach(async function () { + this.operation = genOperationBatch( + Array(8).fill('0x76E53CcEb05131Ef5248553bEBDb8F70536830b1'), + Array(8).fill(0), + Array(8).fill('0x58a60f63'), + ZERO_BYTES32, + '0x9545eeabc7a7586689191f78a5532443698538e54211b5bd4d7dc0fc0102b5c7', + ); + }); + + it('revert if operation is not scheduled', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + describe('with scheduled operation', function () { + beforeEach(async function () { + ({ receipt: this.receipt, logs: this.logs } = await this.mock.scheduleBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('revert if execution comes too early 1/2', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + it('revert if execution comes too early 2/2', async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp - 5); // -1 is to tight, test sometime fails + + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [this.operation.id, proposalStatesToBitMap(OperationState.Ready)], + ); + }); + + describe('on time', function () { + beforeEach(async function () { + const timestamp = await this.mock.getTimestamp(this.operation.id); + await time.increaseTo(timestamp); + }); + + it('executor can reveal', async function () { + const receipt = await this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ); + for (const i in this.operation.targets) { + expectEvent(receipt, 'CallExecuted', { + id: this.operation.id, + index: web3.utils.toBN(i), + target: this.operation.targets[i], + value: web3.utils.toBN(this.operation.values[i]), + data: this.operation.payloads[i], + }); + } + }); + + it('prevent non-executor from revealing', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: other }, + ), + `AccessControlUnauthorizedAccount`, + [other, EXECUTOR_ROLE], + ); + }); + + it('length mismatch #1', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + [], + this.operation.values, + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockInvalidOperationLength', + [0, this.operation.payloads.length, this.operation.values.length], + ); + }); + + it('length mismatch #2', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + [], + this.operation.payloads, + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockInvalidOperationLength', + [this.operation.targets.length, this.operation.payloads.length, 0], + ); + }); + + it('length mismatch #3', async function () { + await expectRevertCustomError( + this.mock.executeBatch( + this.operation.targets, + this.operation.values, + [], + this.operation.predecessor, + this.operation.salt, + { from: executor }, + ), + 'TimelockInvalidOperationLength', + [this.operation.targets.length, 0, this.operation.values.length], + ); + }); + + 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 expectRevertCustomError( + this.mock.executeBatch( + reentrantBatchOperation.targets, + reentrantBatchOperation.values, + reentrantBatchOperation.payloads, + reentrantBatchOperation.predecessor, + reentrantBatchOperation.salt, + { from: executor }, + ), + 'TimelockUnexpectedOperationState', + [reentrantBatchOperation.id, proposalStatesToBitMap(OperationState.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], + }); + } + }); + }); + }); + + it('partial execution', async function () { + const operation = genOperationBatch( + [this.callreceivermock.address, this.callreceivermock.address, this.callreceivermock.address], + [0, 0, 0], + [ + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + ], + ZERO_BYTES32, + '0x8ac04aa0d6d66b8812fb41d39638d37af0a9ab11da507afd65c509f8ed079d3e', + ); + + await this.mock.scheduleBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevertCustomError( + this.mock.executeBatch( + operation.targets, + operation.values, + operation.payloads, + operation.predecessor, + operation.salt, + { from: executor }, + ), + 'FailedInnerCall', + [], + ); + }); + }); + }); + + describe('cancel', function () { + beforeEach(async function () { + this.operation = genOperation( + '0xC6837c44AA376dbe1d2709F13879E040CAb653ca', + 0, + '0x296e58dd', + ZERO_BYTES32, + '0xa2485763600634800df9fc9646fb2c112cf98649c55f63dd1d9c7d13a64399d9', + ); + ({ receipt: this.receipt, logs: this.logs } = await this.mock.schedule( + this.operation.target, + this.operation.value, + this.operation.data, + this.operation.predecessor, + this.operation.salt, + MINDELAY, + { from: proposer }, + )); + }); + + it('canceller can cancel', async function () { + const receipt = await this.mock.cancel(this.operation.id, { from: canceller }); + expectEvent(receipt, 'Cancelled', { id: this.operation.id }); + }); + + it('cannot cancel invalid operation', async function () { + await expectRevertCustomError( + this.mock.cancel(constants.ZERO_BYTES32, { from: canceller }), + 'TimelockUnexpectedOperationState', + [constants.ZERO_BYTES32, proposalStatesToBitMap([OperationState.Waiting, OperationState.Ready])], + ); + }); + + it('prevent non-canceller from canceling', async function () { + await expectRevertCustomError( + this.mock.cancel(this.operation.id, { from: other }), + `AccessControlUnauthorizedAccount`, + [other, CANCELLER_ROLE], + ); + }); + }); + }); + + describe('maintenance', function () { + it('prevent unauthorized maintenance', async function () { + await expectRevertCustomError(this.mock.updateDelay(0, { from: other }), 'TimelockUnauthorizedCaller', [other]); + }); + + it('timelock scheduled maintenance', async function () { + const newDelay = time.duration.hours(6); + const operation = genOperation( + this.mock.address, + 0, + this.mock.contract.methods.updateDelay(newDelay.toString()).encodeABI(), + ZERO_BYTES32, + '0xf8e775b2c5f4d66fb5c7fa800f35ef518c262b6014b3c0aee6ea21bff157f108', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + const receipt = await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor }, + ); + expectEvent(receipt, 'MinDelayChange', { newDuration: newDelay.toString(), oldDuration: MINDELAY }); + + expect(await this.mock.getMinDelay()).to.be.bignumber.equal(newDelay); + }); + }); + + describe('dependency', function () { + beforeEach(async function () { + this.operation1 = genOperation( + '0xdE66bD4c97304200A95aE0AadA32d6d01A867E39', + 0, + '0x01dc731a', + ZERO_BYTES32, + '0x64e932133c7677402ead2926f86205e2ca4686aebecf5a8077627092b9bb2feb', + ); + this.operation2 = genOperation( + '0x3c7944a3F1ee7fc8c5A5134ba7c79D11c3A1FCa3', + 0, + '0x8f531849', + this.operation1.id, + '0x036e1311cac523f9548e6461e29fb1f8f9196b91910a41711ea22f5de48df07d', + ); + await this.mock.schedule( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + MINDELAY, + { from: proposer }, + ); + await this.mock.schedule( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + }); + + it('cannot execute before dependency', async function () { + await expectRevertCustomError( + this.mock.execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + { from: executor }, + ), + 'TimelockUnexecutedPredecessor', + [this.operation1.id], + ); + }); + + it('can execute after dependency', async function () { + await this.mock.execute( + this.operation1.target, + this.operation1.value, + this.operation1.data, + this.operation1.predecessor, + this.operation1.salt, + { from: executor }, + ); + await this.mock.execute( + this.operation2.target, + this.operation2.value, + this.operation2.data, + this.operation2.predecessor, + this.operation2.salt, + { from: executor }, + ); + }); + }); + + describe('usage scenario', function () { + this.timeout(10000); + + it('call', async function () { + const operation = genOperation( + this.implementation2.address, + 0, + this.implementation2.contract.methods.setValue(42).encodeABI(), + ZERO_BYTES32, + '0x8043596363daefc89977b25f9d9b4d06c3910959ef0c4d213557a903e1b555e2', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor }, + ); + + expect(await this.implementation2.getValue()).to.be.bignumber.equal(web3.utils.toBN(42)); + }); + + it('call reverting', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + ZERO_BYTES32, + '0xb1b1b276fdf1a28d1e00537ea73b04d56639128b08063c1a2f70a52e38cba693', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevertCustomError( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'FailedInnerCall', + [], + ); + }); + + it('call throw', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(), + ZERO_BYTES32, + '0xe5ca79f295fc8327ee8a765fe19afb58f4a0cbc5053642bfdd7e73bc68e0fc67', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + // Targeted function reverts with a panic code (0x1) + the timelock bubble the panic code + await expectRevert.unspecified( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + ); + }); + + it('call out of gas', async function () { + const operation = genOperation( + this.callreceivermock.address, + 0, + this.callreceivermock.contract.methods.mockFunctionOutOfGas().encodeABI(), + ZERO_BYTES32, + '0xf3274ce7c394c5b629d5215723563a744b817e1730cca5587c567099a14578fd', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + await expectRevertCustomError( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + gas: '100000', + }), + 'FailedInnerCall', + [], + ); + }); + + it('call payable with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunction().encodeABI(), + ZERO_BYTES32, + '0x5ab73cd33477dcd36c1e05e28362719d0ed59a7b9ff14939de63a43073dc1f44', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await this.mock.execute( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + { from: executor, value: 1 }, + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(1)); + }); + + it('call nonpayable with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunctionNonPayable().encodeABI(), + ZERO_BYTES32, + '0xb78edbd920c7867f187e5aa6294ae5a656cfbf0dea1ccdca3751b740d0f2bdf8', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await expectRevertCustomError( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'FailedInnerCall', + [], + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + + it('call reverting with eth', async function () { + const operation = genOperation( + this.callreceivermock.address, + 1, + this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + ZERO_BYTES32, + '0xdedb4563ef0095db01d81d3f2decf57cf83e4a72aa792af14c43a792b56f4de6', + ); + + await this.mock.schedule( + operation.target, + operation.value, + operation.data, + operation.predecessor, + operation.salt, + MINDELAY, + { from: proposer }, + ); + await time.increase(MINDELAY); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await expectRevertCustomError( + this.mock.execute(operation.target, operation.value, operation.data, operation.predecessor, operation.salt, { + from: executor, + }), + 'FailedInnerCall', + [], + ); + + expect(await web3.eth.getBalance(this.mock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0)); + }); + }); + + 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(other, tokenId); + }); + + it('can receive an ERC721 safeTransfer', async function () { + await this.token.safeTransferFrom(other, this.mock.address, tokenId, { from: other }); + }); + }); + + 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(other, Object.keys(tokenIds), Object.values(tokenIds), '0x'); + }); + + it('can receive ERC1155 safeTransfer', async function () { + await this.token.safeTransferFrom( + other, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: other }, + ); + }); + + it('can receive ERC1155 safeBatchTransfer', async function () { + await this.token.safeBatchTransferFrom( + other, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: other }, + ); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js b/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js new file mode 100644 index 0000000..22265cc --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/extensions/GovernorERC721.test.js @@ -0,0 +1,116 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper } = require('../../helpers/governance'); + +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; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockNFToken'; + const tokenSymbol = 'MTKN'; + 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'); + + 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, version); + this.mock = await Governor.new(name, this.token.address); + this.receiver = await CallReceiver.new(); + + this.helper = new GovernorHelper(this.mock, mode); + + 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 }); + + // 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('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: 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/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js b/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js new file mode 100644 index 0000000..17ae05a --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/extensions/GovernorPreventLateQuorum.test.js @@ -0,0 +1,195 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper } = require('../../helpers/governance'); +const { clockFromReceipt } = require('../../helpers/time'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +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; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + 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'); + + 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, version); + 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, mode); + + 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 }); + + // 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 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 expectRevertCustomError( + this.mock.setLateQuorumVoteExtension(0, { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js b/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js new file mode 100644 index 0000000..99a9788 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/extensions/GovernorStorage.test.js @@ -0,0 +1,150 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../../helpers/customError'); +const Enums = require('../../helpers/enums'); +const { GovernorHelper, timelockSalt } = require('../../helpers/governance'); + +const Timelock = artifacts.require('TimelockController'); +const Governor = artifacts.require('$GovernorStorageMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); + +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + +contract('GovernorStorage', function (accounts) { + const [owner, voter1, voter2, voter3, voter4] = accounts; + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, version); + 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, mode); + + 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(DEFAULT_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 }); + + // 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', + timelockSalt(this.mock.address, this.proposal.shortProposal[3]), + ); + }); + + describe('proposal indexing', function () { + it('before propose', async function () { + expect(await this.mock.proposalCount()).to.be.bignumber.equal('0'); + + // panic code 0x32 (out-of-bound) + await expectRevert.unspecified(this.mock.proposalDetailsAt(0)); + + await expectRevertCustomError(this.mock.proposalDetails(this.proposal.id), 'GovernorNonexistentProposal', [ + this.proposal.id, + ]); + }); + + it('after propose', async function () { + await this.helper.propose(); + + expect(await this.mock.proposalCount()).to.be.bignumber.equal('1'); + + const proposalDetailsAt0 = await this.mock.proposalDetailsAt(0); + expect(proposalDetailsAt0[0]).to.be.bignumber.equal(this.proposal.id); + expect(proposalDetailsAt0[1]).to.be.deep.equal(this.proposal.targets); + expect(proposalDetailsAt0[2].map(x => x.toString())).to.be.deep.equal(this.proposal.values); + expect(proposalDetailsAt0[3]).to.be.deep.equal(this.proposal.fulldata); + expect(proposalDetailsAt0[4]).to.be.equal(this.proposal.descriptionHash); + + const proposalDetailsForId = await this.mock.proposalDetails(this.proposal.id); + expect(proposalDetailsForId[0]).to.be.deep.equal(this.proposal.targets); + expect(proposalDetailsForId[1].map(x => x.toString())).to.be.deep.equal(this.proposal.values); + expect(proposalDetailsForId[2]).to.be.deep.equal(this.proposal.fulldata); + expect(proposalDetailsForId[3]).to.be.equal(this.proposal.descriptionHash); + }); + }); + + it('queue and execute by id', 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.mock.queue(this.proposal.id); + await this.helper.waitForEta(); + const txExecute = await this.mock.execute(this.proposal.id); + + 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'); + }); + + it('cancel by id', async function () { + await this.helper.propose(); + const txCancel = await this.mock.cancel(this.proposal.id); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: this.proposal.id }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js b/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js new file mode 100644 index 0000000..68df99e --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockAccess.test.js @@ -0,0 +1,777 @@ +const { expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper, proposalStatesToBitMap } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { clockFromReceipt } = require('../../helpers/time'); +const { selector } = require('../../helpers/methods'); + +const AccessManager = artifacts.require('$AccessManager'); +const Governor = artifacts.require('$GovernorTimelockAccessMock'); +const AccessManagedTarget = artifacts.require('$AccessManagedTarget'); + +const TOKENS = [ + { Token: artifacts.require('$ERC20Votes'), mode: 'blocknumber' }, + { Token: artifacts.require('$ERC20VotesTimestampMock'), mode: 'timestamp' }, +]; + +const hashOperation = (caller, target, data) => + web3.utils.keccak256(web3.eth.abi.encodeParameters(['address', 'address', 'bytes'], [caller, target, data])); + +contract('GovernorTimelockAccess', function (accounts) { + const [admin, voter1, voter2, voter3, voter4, other] = accounts; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + for (const { mode, Token } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.token = await Token.new(tokenName, tokenSymbol, tokenName, version); + this.manager = await AccessManager.new(admin); + this.mock = await Governor.new( + name, + votingDelay, + votingPeriod, + 0, // proposal threshold + this.manager.address, + 0, // base delay + this.token.address, + 0, // quorum + ); + this.receiver = await AccessManagedTarget.new(this.manager.address); + + this.helper = new GovernorHelper(this.mock, mode); + + await web3.eth.sendTransaction({ from: admin, to: this.mock.address, value }); + + await this.token.$_mint(admin, tokenSupply); + await this.helper.delegate({ token: this.token, to: voter1, value: web3.utils.toWei('10') }, { from: admin }); + await this.helper.delegate({ token: this.token, to: voter2, value: web3.utils.toWei('7') }, { from: admin }); + await this.helper.delegate({ token: this.token, to: voter3, value: web3.utils.toWei('5') }, { from: admin }); + await this.helper.delegate({ token: this.token, to: voter4, value: web3.utils.toWei('2') }, { from: admin }); + + // default proposals + this.restricted = {}; + this.restricted.selector = this.receiver.contract.methods.fnRestricted().encodeABI(); + this.restricted.operation = { + target: this.receiver.address, + value: '0', + data: this.restricted.selector, + }; + this.restricted.operationId = hashOperation( + this.mock.address, + this.restricted.operation.target, + this.restricted.operation.data, + ); + + this.unrestricted = {}; + this.unrestricted.selector = this.receiver.contract.methods.fnUnrestricted().encodeABI(); + this.unrestricted.operation = { + target: this.receiver.address, + value: '0', + data: this.unrestricted.selector, + }; + this.unrestricted.operationId = hashOperation( + this.mock.address, + this.unrestricted.operation.target, + this.unrestricted.operation.data, + ); + + this.fallback = {}; + this.fallback.operation = { + target: this.receiver.address, + value: '0', + data: '0x1234', + }; + this.fallback.operationId = hashOperation( + this.mock.address, + this.fallback.operation.target, + this.fallback.operation.data, + ); + }); + + it('accepts ether transfers', async function () { + await web3.eth.sendTransaction({ from: admin, 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.accessManager()).to.be.equal(this.manager.address); + }); + + it('sets base delay (seconds)', async function () { + const baseDelay = time.duration.hours(10); + + // Only through governance + await expectRevertCustomError( + this.mock.setBaseDelaySeconds(baseDelay, { from: voter1 }), + 'GovernorOnlyExecutor', + [voter1], + ); + + this.proposal = await this.helper.setProposal( + [ + { + target: this.mock.address, + value: '0', + data: this.mock.contract.methods.setBaseDelaySeconds(baseDelay).encodeABI(), + }, + ], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + const receipt = await this.helper.execute(); + + expectEvent(receipt, 'BaseDelaySet', { + oldBaseDelaySeconds: '0', + newBaseDelaySeconds: baseDelay, + }); + + expect(await this.mock.baseDelaySeconds()).to.be.bignumber.eq(baseDelay); + }); + + it('sets access manager ignored', async function () { + const selectors = ['0x12345678', '0x87654321', '0xabcdef01']; + + // Only through governance + await expectRevertCustomError( + this.mock.setAccessManagerIgnored(other, selectors, true, { from: voter1 }), + 'GovernorOnlyExecutor', + [voter1], + ); + + // Ignore + const helperIgnore = new GovernorHelper(this.mock, mode); + await helperIgnore.setProposal( + [ + { + target: this.mock.address, + value: '0', + data: this.mock.contract.methods.setAccessManagerIgnored(other, selectors, true).encodeABI(), + }, + ], + 'descr', + ); + + await helperIgnore.propose(); + await helperIgnore.waitForSnapshot(); + await helperIgnore.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await helperIgnore.waitForDeadline(); + const ignoreReceipt = await helperIgnore.execute(); + + for (const selector of selectors) { + expectEvent(ignoreReceipt, 'AccessManagerIgnoredSet', { + target: other, + selector, + ignored: true, + }); + expect(await this.mock.isAccessManagerIgnored(other, selector)).to.be.true; + } + + // Unignore + const helperUnignore = new GovernorHelper(this.mock, mode); + await helperUnignore.setProposal( + [ + { + target: this.mock.address, + value: '0', + data: this.mock.contract.methods.setAccessManagerIgnored(other, selectors, false).encodeABI(), + }, + ], + 'descr', + ); + + await helperUnignore.propose(); + await helperUnignore.waitForSnapshot(); + await helperUnignore.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await helperUnignore.waitForDeadline(); + const unignoreReceipt = await helperUnignore.execute(); + + for (const selector of selectors) { + expectEvent(unignoreReceipt, 'AccessManagerIgnoredSet', { + target: other, + selector, + ignored: false, + }); + expect(await this.mock.isAccessManagerIgnored(other, selector)).to.be.false; + } + }); + + it('sets access manager ignored when target is the governor', async function () { + const other = this.mock.address; + const selectors = ['0x12345678', '0x87654321', '0xabcdef01']; + + await this.helper.setProposal( + [ + { + target: this.mock.address, + value: '0', + data: this.mock.contract.methods.setAccessManagerIgnored(other, selectors, true).encodeABI(), + }, + ], + 'descr', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + const receipt = await this.helper.execute(); + + for (const selector of selectors) { + expectEvent(receipt, 'AccessManagerIgnoredSet', { + target: other, + selector, + ignored: true, + }); + expect(await this.mock.isAccessManagerIgnored(other, selector)).to.be.true; + } + }); + + describe('base delay only', function () { + for (const [delay, queue] of [ + [0, true], + [0, false], + [1000, true], + ]) { + it(`delay ${delay}, ${queue ? 'with' : 'without'} queuing`, async function () { + await this.mock.$_setBaseDelaySeconds(delay); + + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([false]); + expect(withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + if (await this.mock.proposalNeedsQueuing(this.proposal.id)) { + const txQueue = await this.helper.queue(); + expectEvent(txQueue, 'ProposalQueued', { proposalId: this.proposal.id }); + } + if (delay > 0) { + await this.helper.waitForEta(); + } + const txExecute = await this.helper.execute(); + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + expectEvent.inTransaction(txExecute, this.receiver, 'CalledUnrestricted'); + }); + } + }); + + it('reverts when an operation is executed before eta', async function () { + const delay = time.duration.hours(2); + await this.mock.$_setBaseDelaySeconds(delay); + + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(true); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([false]); + expect(withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + await expectRevertCustomError(this.helper.execute(), 'GovernorUnmetDelay', [ + this.proposal.id, + await this.mock.proposalEta(this.proposal.id), + ]); + }); + + it('reverts with a proposal including multiple operations but one of those was cancelled in the manager', async function () { + const delay = time.duration.hours(2); + const roleId = '1'; + + await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, { + from: admin, + }); + await this.manager.grantRole(roleId, this.mock.address, delay, { from: admin }); + + // Set proposals + const original = new GovernorHelper(this.mock, mode); + await original.setProposal([this.restricted.operation, this.unrestricted.operation], 'descr'); + + // Go through all the governance process + await original.propose(); + expect(await this.mock.proposalNeedsQueuing(original.currentProposal.id)).to.be.eq(true); + const { + delay: planDelay, + indirect, + withDelay, + } = await this.mock.proposalExecutionPlan(original.currentProposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([true, false]); + expect(withDelay).to.deep.eq([true, false]); + await original.waitForSnapshot(); + await original.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await original.waitForDeadline(); + await original.queue(); + await original.waitForEta(); + + // Suddenly cancel one of the proposed operations in the manager + await this.manager.cancel(this.mock.address, this.restricted.operation.target, this.restricted.operation.data, { + from: admin, + }); + + // Reschedule the same operation in a different proposal to avoid "AccessManagerNotScheduled" error + const rescheduled = new GovernorHelper(this.mock, mode); + await rescheduled.setProposal([this.restricted.operation], 'descr'); + await rescheduled.propose(); + await rescheduled.waitForSnapshot(); + await rescheduled.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await rescheduled.waitForDeadline(); + await rescheduled.queue(); // This will schedule it again in the manager + await rescheduled.waitForEta(); + + // Attempt to execute + await expectRevertCustomError(original.execute(), 'GovernorMismatchedNonce', [ + original.currentProposal.id, + 1, + 2, + ]); + }); + + it('single operation with access manager delay', async function () { + const delay = 1000; + const roleId = '1'; + + await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, { + from: admin, + }); + await this.manager.grantRole(roleId, this.mock.address, delay, { from: admin }); + + this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(true); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([true]); + expect(withDelay).to.deep.eq([true]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + 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.manager, 'OperationScheduled', { + operationId: this.restricted.operationId, + nonce: '1', + schedule: web3.utils.toBN(await clockFromReceipt.timestamp(txQueue.receipt)).addn(delay), + caller: this.mock.address, + target: this.restricted.operation.target, + data: this.restricted.operation.data, + }); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txExecute.tx, this.manager, 'OperationExecuted', { + operationId: this.restricted.operationId, + nonce: '1', + }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'CalledRestricted'); + }); + + it('bundle of varied operations', async function () { + const managerDelay = 1000; + const roleId = '1'; + + const baseDelay = managerDelay * 2; + + await this.mock.$_setBaseDelaySeconds(baseDelay); + + await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, { + from: admin, + }); + await this.manager.grantRole(roleId, this.mock.address, managerDelay, { from: admin }); + + this.proposal = await this.helper.setProposal( + [this.restricted.operation, this.unrestricted.operation, this.fallback.operation], + 'descr', + ); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(true); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(baseDelay)); + expect(indirect).to.deep.eq([true, false, false]); + expect(withDelay).to.deep.eq([true, false, false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + 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.manager, 'OperationScheduled', { + operationId: this.restricted.operationId, + nonce: '1', + schedule: web3.utils.toBN(await clockFromReceipt.timestamp(txQueue.receipt)).addn(baseDelay), + caller: this.mock.address, + target: this.restricted.operation.target, + data: this.restricted.operation.data, + }); + + expectEvent(txExecute, 'ProposalExecuted', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txExecute.tx, this.manager, 'OperationExecuted', { + operationId: this.restricted.operationId, + nonce: '1', + }); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'CalledRestricted'); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'CalledUnrestricted'); + await expectEvent.inTransaction(txExecute.tx, this.receiver, 'CalledFallback'); + }); + + describe('cancel', function () { + const delay = 1000; + const roleId = '1'; + + beforeEach(async function () { + await this.manager.setTargetFunctionRole(this.receiver.address, [this.restricted.selector], roleId, { + from: admin, + }); + await this.manager.grantRole(roleId, this.mock.address, delay, { from: admin }); + }); + + it('cancels restricted with delay after queue (internal)', async function () { + this.proposal = await this.helper.setProposal([this.restricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(true); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([true]); + expect(withDelay).to.deep.eq([true]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + const txCancel = await this.helper.cancel('internal'); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: this.proposal.id }); + await expectEvent.inTransaction(txCancel.tx, this.manager, 'OperationCanceled', { + operationId: this.restricted.operationId, + nonce: '1', + }); + + await this.helper.waitForEta(); + await expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('cancels restricted with queueing if the same operation is part of a more recent proposal (internal)', async function () { + // Set proposals + const original = new GovernorHelper(this.mock, mode); + await original.setProposal([this.restricted.operation], 'descr'); + + // Go through all the governance process + await original.propose(); + expect(await this.mock.proposalNeedsQueuing(original.currentProposal.id)).to.be.eq(true); + const { + delay: planDelay, + indirect, + withDelay, + } = await this.mock.proposalExecutionPlan(original.currentProposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN(delay)); + expect(indirect).to.deep.eq([true]); + expect(withDelay).to.deep.eq([true]); + await original.waitForSnapshot(); + await original.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await original.waitForDeadline(); + await original.queue(); + + // Cancel the operation in the manager + await this.manager.cancel( + this.mock.address, + this.restricted.operation.target, + this.restricted.operation.data, + { from: admin }, + ); + + // Another proposal is added with the same operation + const rescheduled = new GovernorHelper(this.mock, mode); + await rescheduled.setProposal([this.restricted.operation], 'another descr'); + + // Queue the new proposal + await rescheduled.propose(); + await rescheduled.waitForSnapshot(); + await rescheduled.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await rescheduled.waitForDeadline(); + await rescheduled.queue(); // This will schedule it again in the manager + + // Cancel + const eta = await this.mock.proposalEta(rescheduled.currentProposal.id); + const txCancel = await original.cancel('internal'); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: original.currentProposal.id }); + + await time.increase(eta); // waitForEta() + await expectRevertCustomError(original.execute(), 'GovernorUnexpectedProposalState', [ + original.currentProposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('cancels unrestricted with queueing (internal)', async function () { + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(indirect).to.deep.eq([false]); + expect(withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await this.helper.queue(); + + const eta = await this.mock.proposalEta(this.proposal.id); + const txCancel = await this.helper.cancel('internal'); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: this.proposal.id }); + + await time.increase(eta); // waitForEta() + await expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('cancels unrestricted without queueing (internal)', async function () { + this.proposal = await this.helper.setProposal([this.unrestricted.operation], 'descr'); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(indirect).to.deep.eq([false]); + expect(withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + // await this.helper.queue(); + + // const eta = await this.mock.proposalEta(this.proposal.id); + const txCancel = await this.helper.cancel('internal'); + expectEvent(txCancel, 'ProposalCanceled', { proposalId: this.proposal.id }); + + // await time.increase(eta); // waitForEta() + await expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + it('cancels calls already canceled by guardian', async function () { + const operationA = { target: this.receiver.address, data: this.restricted.selector + '00' }; + const operationB = { target: this.receiver.address, data: this.restricted.selector + '01' }; + const operationC = { target: this.receiver.address, data: this.restricted.selector + '02' }; + const operationAId = hashOperation(this.mock.address, operationA.target, operationA.data); + const operationBId = hashOperation(this.mock.address, operationB.target, operationB.data); + + const proposal1 = new GovernorHelper(this.mock, mode); + const proposal2 = new GovernorHelper(this.mock, mode); + proposal1.setProposal([operationA, operationB], 'proposal A+B'); + proposal2.setProposal([operationA, operationC], 'proposal A+C'); + + for (const p of [proposal1, proposal2]) { + await p.propose(); + await p.waitForSnapshot(); + await p.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await p.waitForDeadline(); + } + + // Can queue the first proposal + await proposal1.queue(); + + // Cannot queue the second proposal: operation A already scheduled with delay + await expectRevertCustomError(proposal2.queue(), 'AccessManagerAlreadyScheduled', [operationAId]); + + // Admin cancels operation B on the manager + await this.manager.cancel(this.mock.address, operationB.target, operationB.data, { from: admin }); + + // Still cannot queue the second proposal: operation A already scheduled with delay + await expectRevertCustomError(proposal2.queue(), 'AccessManagerAlreadyScheduled', [operationAId]); + + await proposal1.waitForEta(); + + // Cannot execute first proposal: operation B has been canceled + await expectRevertCustomError(proposal1.execute(), 'AccessManagerNotScheduled', [operationBId]); + + // Cancel the first proposal to release operation A + await proposal1.cancel('internal'); + + // can finally queue the second proposal + await proposal2.queue(); + + await proposal2.waitForEta(); + + // Can execute second proposal + await proposal2.execute(); + }); + }); + + describe('ignore AccessManager', function () { + it('defaults', async function () { + expect(await this.mock.isAccessManagerIgnored(this.receiver.address, this.restricted.selector)).to.equal( + false, + ); + expect(await this.mock.isAccessManagerIgnored(this.mock.address, '0x12341234')).to.equal(true); + }); + + it('internal setter', async function () { + const p1 = { target: this.receiver.address, selector: this.restricted.selector, ignored: true }; + const tx1 = await this.mock.$_setAccessManagerIgnored(p1.target, p1.selector, p1.ignored); + expect(await this.mock.isAccessManagerIgnored(p1.target, p1.selector)).to.equal(p1.ignored); + expectEvent(tx1, 'AccessManagerIgnoredSet', p1); + + const p2 = { target: this.mock.address, selector: '0x12341234', ignored: false }; + const tx2 = await this.mock.$_setAccessManagerIgnored(p2.target, p2.selector, p2.ignored); + expect(await this.mock.isAccessManagerIgnored(p2.target, p2.selector)).to.equal(p2.ignored); + expectEvent(tx2, 'AccessManagerIgnoredSet', p2); + }); + + it('external setter', async function () { + const setAccessManagerIgnored = (...args) => + this.mock.contract.methods.setAccessManagerIgnored(...args).encodeABI(); + + await this.helper.setProposal( + [ + { + target: this.mock.address, + data: setAccessManagerIgnored( + this.receiver.address, + [this.restricted.selector, this.unrestricted.selector], + true, + ), + value: '0', + }, + { + target: this.mock.address, + data: setAccessManagerIgnored(this.mock.address, ['0x12341234', '0x67896789'], false), + value: '0', + }, + ], + 'descr', + ); + + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const { delay: planDelay, indirect, withDelay } = await this.mock.proposalExecutionPlan(this.proposal.id); + expect(planDelay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(indirect).to.deep.eq([]); // Governor operations ignore access manager + expect(withDelay).to.deep.eq([]); // Governor operations ignore access manager + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + const tx = await this.helper.execute(); + + expectEvent(tx, 'AccessManagerIgnoredSet'); + + expect(await this.mock.isAccessManagerIgnored(this.receiver.address, this.restricted.selector)).to.equal( + true, + ); + expect(await this.mock.isAccessManagerIgnored(this.receiver.address, this.unrestricted.selector)).to.equal( + true, + ); + + expect(await this.mock.isAccessManagerIgnored(this.mock.address, '0x12341234')).to.equal(false); + expect(await this.mock.isAccessManagerIgnored(this.mock.address, '0x67896789')).to.equal(false); + }); + + it('locked function', async function () { + const setAccessManagerIgnored = selector('setAccessManagerIgnored(address,bytes4[],bool)'); + await expectRevertCustomError( + this.mock.$_setAccessManagerIgnored(this.mock.address, setAccessManagerIgnored, true), + 'GovernorLockedIgnore', + [], + ); + await this.mock.$_setAccessManagerIgnored(this.receiver.address, setAccessManagerIgnored, true); + }); + + it('ignores access manager', async function () { + const amount = 100; + + const target = this.token.address; + const data = this.token.contract.methods.transfer(voter4, amount).encodeABI(); + const selector = data.slice(0, 10); + await this.token.$_mint(this.mock.address, amount); + + const roleId = '1'; + await this.manager.setTargetFunctionRole(target, [selector], roleId, { from: admin }); + await this.manager.grantRole(roleId, this.mock.address, 0, { from: admin }); + + const proposal = await this.helper.setProposal([{ target, data, value: '0' }], '1'); + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const plan = await this.mock.proposalExecutionPlan(proposal.id); + expect(plan.delay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(plan.indirect).to.deep.eq([true]); + expect(plan.withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + await expectRevertCustomError(this.helper.execute(), 'ERC20InsufficientBalance', [ + this.manager.address, + 0, + amount, + ]); + + await this.mock.$_setAccessManagerIgnored(target, selector, true); + + const proposalIgnored = await this.helper.setProposal([{ target, data, value: '0' }], '2'); + await this.helper.propose(); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.eq(false); + const planIgnored = await this.mock.proposalExecutionPlan(proposalIgnored.id); + expect(planIgnored.delay).to.be.bignumber.eq(web3.utils.toBN('0')); + expect(planIgnored.indirect).to.deep.eq([false]); + expect(planIgnored.withDelay).to.deep.eq([false]); + + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + const tx = await this.helper.execute(); + expectEvent.inTransaction(tx, this.token, 'Transfer', { from: this.mock.address }); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js b/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js new file mode 100644 index 0000000..e9d6f83 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockCompound.test.js @@ -0,0 +1,441 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper, proposalStatesToBitMap } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { computeCreateAddress } = require('../../helpers/create'); +const { clockFromReceipt } = require('../../helpers/time'); + +const Timelock = artifacts.require('CompTimelock'); +const Governor = artifacts.require('$GovernorTimelockCompoundMock'); +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' }, +]; + +contract('GovernorTimelockCompound', function (accounts) { + const [owner, voter1, voter2, voter3, voter4, other] = accounts; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + const defaultDelay = 2 * 86400; + + 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, version); + + // Need to predict governance address to set it as timelock admin with a delayed transfer + const nonce = await web3.eth.getTransactionCount(deployer); + const predictGovernor = computeCreateAddress(deployer, nonce + 1); + + this.timelock = await Timelock.new(predictGovernor, defaultDelay); + 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, 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.receiver.address, + value, + data: this.receiver.contract.methods.mockFunction().encodeABI(), + }, + ], + '', + ); + }); + + 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 () { + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal('0'); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(true); + + 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 = web3.utils.toBN(await clockFromReceipt.timestamp(txQueue.receipt)).addn(defaultDelay); + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal(eta); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(true); + + 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 expectRevertCustomError(this.helper.queue(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Queued, + proposalStatesToBitMap([Enums.ProposalState.Succeeded]), + ]); + }); + + 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(), + }; + const { id } = 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 expectRevertCustomError(this.helper.queue(), 'GovernorAlreadyQueuedProposal', [id]); + await expectRevertCustomError(this.helper.execute(), 'GovernorNotQueuedProposal', [id]); + }); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorNotQueuedProposal', [this.proposal.id]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Expired, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + }); + + describe('on 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't receive an ERC721 safeTransfer", async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(owner, this.mock.address, tokenId, { from: owner }), + 'GovernorDisabledDeposit', + [], + ); + }); + }); + + 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't receive ERC1155 safeTransfer", async function () { + await expectRevertCustomError( + this.token.safeTransferFrom( + owner, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: owner }, + ), + 'GovernorDisabledDeposit', + [], + ); + }); + + it("can't receive ERC1155 safeBatchTransfer", async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + owner, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: owner }, + ), + 'GovernorDisabledDeposit', + [], + ); + }); + }); + }); + }); + + 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 expectRevertCustomError(this.helper.queue(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + }); + + describe('onlyGovernance', function () { + describe('relay', function () { + beforeEach(async function () { + await this.token.$_mint(this.mock.address, 1); + }); + + it('is protected', async function () { + await expectRevertCustomError( + this.mock.relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI(), { + from: owner, + }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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 expectRevertCustomError( + this.mock.updateTimelock(this.newTimelock.address, { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js b/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js new file mode 100644 index 0000000..ec03d61 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/extensions/GovernorTimelockControl.test.js @@ -0,0 +1,515 @@ +const { constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper, proposalStatesToBitMap, timelockSalt } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { clockFromReceipt } = require('../../helpers/time'); + +const Timelock = artifacts.require('TimelockController'); +const Governor = artifacts.require('$GovernorTimelockControlMock'); +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' }, +]; + +contract('GovernorTimelockControl', function (accounts) { + const [owner, voter1, voter2, voter3, voter4, other] = accounts; + + const DEFAULT_ADMIN_ROLE = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const PROPOSER_ROLE = web3.utils.soliditySha3('PROPOSER_ROLE'); + const EXECUTOR_ROLE = web3.utils.soliditySha3('EXECUTOR_ROLE'); + const CANCELLER_ROLE = web3.utils.soliditySha3('CANCELLER_ROLE'); + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + const delay = 3600; + + 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, version); + this.timelock = await Timelock.new(delay, [], [], 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, mode); + + 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 }); + + // 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(DEFAULT_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 }); + + // 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', + timelockSalt(this.mock.address, this.proposal.shortProposal[3]), + ); + }); + + 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 () { + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal('0'); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(true); + + 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 eta = web3.utils.toBN(await clockFromReceipt.timestamp(txQueue.receipt)).addn(delay); + expect(await this.mock.proposalEta(this.proposal.id)).to.be.bignumber.equal(eta); + expect(await this.mock.proposalNeedsQueuing(this.proposal.id)).to.be.equal(true); + + 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 expectRevertCustomError(this.helper.queue(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Queued, + proposalStatesToBitMap([Enums.ProposalState.Succeeded]), + ]); + }); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'TimelockUnexpectedOperationState', [ + this.proposal.timelockid, + proposalStatesToBitMap(Enums.OperationState.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 expectRevertCustomError(this.helper.execute(), 'TimelockUnexpectedOperationState', [ + this.proposal.timelockid, + proposalStatesToBitMap(Enums.OperationState.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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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', + timelockSalt(this.mock.address, this.proposal.shortProposal[3]), + ); + + await expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Executed, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + }); + }); + + 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 expectRevertCustomError(this.helper.queue(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded]), + ]); + }); + + 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Canceled, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + 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 expectRevertCustomError( + this.mock.relay(this.token.address, 0, this.token.contract.methods.transfer(other, 1).encodeABI(), { + from: owner, + }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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 () { + const target = this.mock.address; + const value = web3.utils.toWei('0'); + const data = this.mock.contract.methods.relay(constants.ZERO_ADDRESS, 0, '0x').encodeABI(); + const predecessor = constants.ZERO_BYTES32; + const salt = constants.ZERO_BYTES32; + + await this.timelock.schedule(target, value, data, predecessor, salt, delay, { from: owner }); + + await time.increase(delay); + + await expectRevertCustomError( + this.timelock.execute(target, value, data, predecessor, salt, { from: owner }), + 'QueueEmpty', // Bubbled up from Governor + [], + ); + }); + }); + + describe('updateTimelock', function () { + beforeEach(async function () { + this.newTimelock = await Timelock.new( + delay, + [this.mock.address], + [this.mock.address], + constants.ZERO_ADDRESS, + ); + }); + + it('is protected', async function () { + await expectRevertCustomError( + this.mock.updateTimelock(this.newTimelock.address, { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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); + }); + }); + + describe('on 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't receive an ERC721 safeTransfer", async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(owner, this.mock.address, tokenId, { from: owner }), + 'GovernorDisabledDeposit', + [], + ); + }); + }); + + 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't receive ERC1155 safeTransfer", async function () { + await expectRevertCustomError( + this.token.safeTransferFrom( + owner, + this.mock.address, + ...Object.entries(tokenIds)[0], // id + amount + '0x', + { from: owner }, + ), + 'GovernorDisabledDeposit', + [], + ); + }); + + it("can't receive ERC1155 safeBatchTransfer", async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + owner, + this.mock.address, + Object.keys(tokenIds), + Object.values(tokenIds), + '0x', + { from: owner }, + ), + 'GovernorDisabledDeposit', + [], + ); + }); + }); + }); + }); + + 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/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js b/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js new file mode 100644 index 0000000..ece9c78 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/extensions/GovernorVotesQuorumFraction.test.js @@ -0,0 +1,167 @@ +const { expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const Enums = require('../../helpers/enums'); +const { GovernorHelper, proposalStatesToBitMap } = require('../../helpers/governance'); +const { clock } = require('../../helpers/time'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +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; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + 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'); + + 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, version); + this.mock = await Governor.new(name, votingDelay, votingPeriod, 0, this.token.address, ratio); + this.receiver = await CallReceiver.new(); + + this.helper = new GovernorHelper(this.mock, mode); + + 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 }); + + // 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 clock[mode]().then(timepoint => this.mock.quorum(timepoint - 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 expectRevertCustomError(this.helper.execute(), 'GovernorUnexpectedProposalState', [ + this.proposal.id, + Enums.ProposalState.Defeated, + proposalStatesToBitMap([Enums.ProposalState.Succeeded, Enums.ProposalState.Queued]), + ]); + }); + + describe('onlyGovernance updates', function () { + it('updateQuorumNumerator is protected', async function () { + await expectRevertCustomError( + this.mock.updateQuorumNumerator(newRatio, { from: owner }), + 'GovernorOnlyExecutor', + [owner], + ); + }); + + 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 () { + const quorumNumerator = 101; + this.helper.setProposal( + [ + { + target: this.mock.address, + data: this.mock.contract.methods.updateQuorumNumerator(quorumNumerator).encodeABI(), + }, + ], + '', + ); + + await this.helper.propose(); + await this.helper.waitForSnapshot(); + await this.helper.vote({ support: Enums.VoteType.For }, { from: voter1 }); + await this.helper.waitForDeadline(); + + const quorumDenominator = await this.mock.quorumDenominator(); + + await expectRevertCustomError(this.helper.execute(), 'GovernorInvalidQuorumFraction', [ + quorumNumerator, + quorumDenominator, + ]); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js b/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js new file mode 100644 index 0000000..35da3a0 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/extensions/GovernorWithParams.test.js @@ -0,0 +1,277 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const Enums = require('../../helpers/enums'); +const { getDomain, domainType } = require('../../helpers/eip712'); +const { GovernorHelper } = require('../../helpers/governance'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const Governor = artifacts.require('$GovernorWithParamsMock'); +const CallReceiver = artifacts.require('CallReceiverMock'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); + +const rawParams = { + 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; + + const name = 'OZ-Governor'; + const version = '1'; + const tokenName = 'MockToken'; + const tokenSymbol = 'MTKN'; + const tokenSupply = web3.utils.toWei('100'); + const votingDelay = web3.utils.toBN(4); + const votingPeriod = web3.utils.toBN(16); + const value = web3.utils.toWei('1'); + + 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, version); + this.mock = await Governor.new(name, this.token.address); + this.receiver = await CallReceiver.new(); + + this.helper = new GovernorHelper(this.mock, mode); + + 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 }); + + // 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('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); + }); + + it('Voting with params is properly supported', async function () { + await this.helper.propose({ from: proposer }); + 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, + }, + { 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); + }); + + describe('voting by signature', function () { + beforeEach(async function () { + this.voterBySig = Wallet.generate(); + this.voterBySig.address = web3.utils.toChecksumAddress(this.voterBySig.getAddressString()); + + this.data = (contract, message) => + getDomain(contract).then(domain => ({ + primaryType: 'ExtendedBallot', + types: { + EIP712Domain: domainType(domain), + ExtendedBallot: [ + { name: 'proposalId', type: 'uint256' }, + { name: 'support', type: 'uint8' }, + { name: 'voter', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { name: 'reason', type: 'string' }, + { name: 'params', type: 'bytes' }, + ], + }, + domain, + message, + })); + + this.sign = privateKey => async (contract, message) => + ethSigUtil.signTypedMessage(privateKey, { data: await this.data(contract, message) }); + }); + + it('supports EOA signatures', async function () { + await this.token.delegate(this.voterBySig.address, { from: voter2 }); + + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); + + const nonce = await this.mock.nonces(this.voterBySig.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + const tx = await this.helper.vote({ + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + reason: 'no particular reason', + params: encodedParams, + signature: this.sign(this.voterBySig.getPrivateKey()), + }); + + expectEvent(tx, 'CountParams', { ...rawParams }); + expectEvent(tx, 'VoteCastWithParams', { + voter: this.voterBySig.address, + 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); + expect(await this.mock.nonces(this.voterBySig.address)).to.be.bignumber.equal(nonce.addn(1)); + }); + + it('supports EIP-1271 signature signatures', async function () { + const ERC1271WalletOwner = Wallet.generate(); + ERC1271WalletOwner.address = web3.utils.toChecksumAddress(ERC1271WalletOwner.getAddressString()); + + const wallet = await ERC1271WalletMock.new(ERC1271WalletOwner.address); + + await this.token.delegate(wallet.address, { from: voter2 }); + + const weight = web3.utils.toBN(web3.utils.toWei('7')).sub(rawParams.uintParam); + + const nonce = await this.mock.nonces(wallet.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + const tx = await this.helper.vote({ + support: Enums.VoteType.For, + voter: wallet.address, + nonce, + reason: 'no particular reason', + params: encodedParams, + signature: this.sign(ERC1271WalletOwner.getPrivateKey()), + }); + + expectEvent(tx, 'CountParams', { ...rawParams }); + expectEvent(tx, 'VoteCastWithParams', { + voter: wallet.address, + 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); + expect(await this.mock.nonces(wallet.address)).to.be.bignumber.equal(nonce.addn(1)); + }); + + it('reverts if signature does not match signer', async function () { + await this.token.delegate(this.voterBySig.address, { from: voter2 }); + + const nonce = await this.mock.nonces(this.voterBySig.address); + + const signature = this.sign(this.voterBySig.getPrivateKey()); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce, + signature: async (...params) => { + const sig = await signature(...params); + const tamperedSig = web3.utils.hexToBytes(sig); + tamperedSig[42] ^= 0xff; + return web3.utils.bytesToHex(tamperedSig); + }, + reason: 'no particular reason', + params: encodedParams, + }; + + await expectRevertCustomError(this.helper.vote(voteParams), 'GovernorInvalidSignature', [voteParams.voter]); + }); + + it('reverts if vote nonce is incorrect', async function () { + await this.token.delegate(this.voterBySig.address, { from: voter2 }); + + const nonce = await this.mock.nonces(this.voterBySig.address); + + // Run proposal + await this.helper.propose(); + await this.helper.waitForSnapshot(); + const voteParams = { + support: Enums.VoteType.For, + voter: this.voterBySig.address, + nonce: nonce.addn(1), + signature: this.sign(this.voterBySig.getPrivateKey()), + reason: 'no particular reason', + params: encodedParams, + }; + + await expectRevertCustomError( + this.helper.vote(voteParams), + // The signature check implies the nonce can't be tampered without changing the signer + 'GovernorInvalidSignature', + [voteParams.voter], + ); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/governance/utils/EIP6372.behavior.js b/lib/openzeppelin-contracts/test/governance/utils/EIP6372.behavior.js new file mode 100644 index 0000000..022ec35 --- /dev/null +++ b/lib/openzeppelin-contracts/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/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js b/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js new file mode 100644 index 0000000..5836cc3 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/utils/Votes.behavior.js @@ -0,0 +1,360 @@ +const { constants, expectEvent, time } = require('@openzeppelin/test-helpers'); + +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +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 } = require('../../helpers/eip712'); +const { clockFromReceipt } = require('../../helpers/time'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const Delegation = [ + { name: 'delegatee', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { name: 'expiry', type: 'uint256' }, +]; + +const buildAndSignDelegation = (contract, message, pk) => + getDomain(contract) + .then(domain => ({ + primaryType: 'Delegation', + types: { EIP712Domain: domainType(domain), Delegation }, + domain, + message, + })) + .then(data => fromRpcSig(ethSigUtil.signTypedMessage(pk, { data }))); + +function shouldBehaveLikeVotes(accounts, tokens, { mode = 'blocknumber', fungible = true }) { + shouldBehaveLikeEIP6372(mode); + + const getWeight = token => web3.utils.toBN(fungible ? token : 1); + + describe('run votes workflow', function () { + it('initial nonce is 0', async function () { + expect(await this.votes.nonces(accounts[0])).to.be.bignumber.equal('0'); + }); + + describe('delegation with signature', function () { + const token = tokens[0]; + + it('delegation without tokens', async function () { + expect(await this.votes.delegates(accounts[1])).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.votes.delegate(accounts[1], { from: accounts[1] }); + expectEvent(receipt, 'DelegateChanged', { + delegator: accounts[1], + fromDelegate: ZERO_ADDRESS, + toDelegate: accounts[1], + }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[1]); + }); + + it('delegation with tokens', async function () { + await this.votes.$_mint(accounts[1], token); + const weight = getWeight(token); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.votes.delegate(accounts[1], { from: accounts[1] }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: accounts[1], + fromDelegate: ZERO_ADDRESS, + toDelegate: accounts[1], + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: accounts[1], + previousVotes: '0', + newVotes: weight, + }); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[1]); + expect(await this.votes.getVotes(accounts[1])).to.be.bignumber.equal(weight); + expect(await this.votes.getPastVotes(accounts[1], timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(accounts[1], timepoint)).to.be.bignumber.equal(weight); + }); + + it('delegation update', async function () { + await this.votes.delegate(accounts[1], { from: accounts[1] }); + await this.votes.$_mint(accounts[1], token); + const weight = getWeight(token); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[1]); + expect(await this.votes.getVotes(accounts[1])).to.be.bignumber.equal(weight); + expect(await this.votes.getVotes(accounts[2])).to.be.bignumber.equal('0'); + + const { receipt } = await this.votes.delegate(accounts[2], { from: accounts[1] }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: accounts[1], + fromDelegate: accounts[1], + toDelegate: accounts[2], + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: accounts[1], + previousVotes: weight, + newVotes: '0', + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: accounts[2], + previousVotes: '0', + newVotes: weight, + }); + + expect(await this.votes.delegates(accounts[1])).to.be.equal(accounts[2]); + expect(await this.votes.getVotes(accounts[1])).to.be.bignumber.equal('0'); + expect(await this.votes.getVotes(accounts[2])).to.be.bignumber.equal(weight); + + expect(await this.votes.getPastVotes(accounts[1], timepoint - 1)).to.be.bignumber.equal(weight); + expect(await this.votes.getPastVotes(accounts[2], timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(accounts[1], timepoint)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(accounts[2], timepoint)).to.be.bignumber.equal(weight); + }); + + describe('with signature', function () { + const delegator = Wallet.generate(); + const [delegatee, other] = accounts; + const nonce = 0; + delegator.address = web3.utils.toChecksumAddress(delegator.getAddressString()); + + it('accept signed delegation', async function () { + await this.votes.$_mint(delegator.address, token); + const weight = getWeight(token); + + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + expect(await this.votes.delegates(delegator.address)).to.be.equal(ZERO_ADDRESS); + + const { receipt } = await this.votes.delegateBySig(delegatee, nonce, MAX_UINT256, v, r, s); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: delegator.address, + fromDelegate: ZERO_ADDRESS, + toDelegate: delegatee, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: delegatee, + previousVotes: '0', + newVotes: weight, + }); + + expect(await this.votes.delegates(delegator.address)).to.be.equal(delegatee); + expect(await this.votes.getVotes(delegator.address)).to.be.bignumber.equal('0'); + expect(await this.votes.getVotes(delegatee)).to.be.bignumber.equal(weight); + expect(await this.votes.getPastVotes(delegatee, timepoint - 1)).to.be.bignumber.equal('0'); + await time.advanceBlock(); + expect(await this.votes.getPastVotes(delegatee, timepoint)).to.be.bignumber.equal(weight); + }); + + it('rejects reused signature', async function () { + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + await this.votes.delegateBySig(delegatee, nonce, MAX_UINT256, v, r, s); + + await expectRevertCustomError( + this.votes.delegateBySig(delegatee, nonce, MAX_UINT256, v, r, s), + 'InvalidAccountNonce', + [delegator.address, nonce + 1], + ); + }); + + it('rejects bad delegatee', async function () { + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + const receipt = await this.votes.delegateBySig(other, nonce, MAX_UINT256, v, r, s); + const { args } = receipt.logs.find(({ event }) => event === 'DelegateChanged'); + expect(args.delegator).to.not.be.equal(delegator.address); + expect(args.fromDelegate).to.be.equal(ZERO_ADDRESS); + expect(args.toDelegate).to.be.equal(other); + }); + + it('rejects bad nonce', async function () { + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce: nonce + 1, + expiry: MAX_UINT256, + }, + delegator.getPrivateKey(), + ); + + await expectRevertCustomError( + this.votes.delegateBySig(delegatee, nonce + 1, MAX_UINT256, v, r, s), + 'InvalidAccountNonce', + [delegator.address, 0], + ); + }); + + it('rejects expired permit', async function () { + const expiry = (await time.latest()) - time.duration.weeks(1); + const { v, r, s } = await buildAndSignDelegation( + this.votes, + { + delegatee, + nonce, + expiry, + }, + delegator.getPrivateKey(), + ); + + await expectRevertCustomError( + this.votes.delegateBySig(delegatee, nonce, expiry, v, r, s), + 'VotesExpiredSignature', + [expiry], + ); + }); + }); + }); + + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.votes.delegate(accounts[1], { from: accounts[1] }); + }); + + it('reverts if block number >= current block', async function () { + const timepoint = 5e10; + const clock = await this.votes.clock(); + await expectRevertCustomError(this.votes.getPastTotalSupply(timepoint), 'ERC5805FutureLookup', [ + timepoint, + clock, + ]); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastTotalSupply(0)).to.be.bignumber.equal('0'); + }); + + it('returns the correct checkpointed total supply', async function () { + const weight = tokens.map(token => getWeight(token)); + + // t0 = mint #0 + const t0 = await this.votes.$_mint(accounts[1], tokens[0]); + await time.advanceBlock(); + // t1 = mint #1 + const t1 = await this.votes.$_mint(accounts[1], tokens[1]); + await time.advanceBlock(); + // t2 = burn #1 + const t2 = await this.votes.$_burn(...(fungible ? [accounts[1]] : []), tokens[1]); + await time.advanceBlock(); + // t3 = mint #2 + const t3 = await this.votes.$_mint(accounts[1], tokens[2]); + await time.advanceBlock(); + // t4 = burn #0 + const t4 = await this.votes.$_burn(...(fungible ? [accounts[1]] : []), tokens[0]); + await time.advanceBlock(); + // t5 = burn #2 + const t5 = await this.votes.$_burn(...(fungible ? [accounts[1]] : []), tokens[2]); + await time.advanceBlock(); + + t0.timepoint = await clockFromReceipt[mode](t0.receipt); + 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(t0.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastTotalSupply(t0.timepoint)).to.be.bignumber.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t0.timepoint + 1)).to.be.bignumber.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t1.timepoint)).to.be.bignumber.equal(weight[0].add(weight[1])); + expect(await this.votes.getPastTotalSupply(t1.timepoint + 1)).to.be.bignumber.equal(weight[0].add(weight[1])); + expect(await this.votes.getPastTotalSupply(t2.timepoint)).to.be.bignumber.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t2.timepoint + 1)).to.be.bignumber.equal(weight[0]); + expect(await this.votes.getPastTotalSupply(t3.timepoint)).to.be.bignumber.equal(weight[0].add(weight[2])); + expect(await this.votes.getPastTotalSupply(t3.timepoint + 1)).to.be.bignumber.equal(weight[0].add(weight[2])); + expect(await this.votes.getPastTotalSupply(t4.timepoint)).to.be.bignumber.equal(weight[2]); + expect(await this.votes.getPastTotalSupply(t4.timepoint + 1)).to.be.bignumber.equal(weight[2]); + expect(await this.votes.getPastTotalSupply(t5.timepoint)).to.be.bignumber.equal('0'); + await expectRevertCustomError(this.votes.getPastTotalSupply(t5.timepoint + 1), 'ERC5805FutureLookup', [ + t5.timepoint + 1, // timepoint + t5.timepoint + 1, // clock + ]); + }); + }); + + // The following tests are an 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.votes.$_mint(accounts[1], tokens[0]); + await this.votes.$_mint(accounts[1], tokens[1]); + await this.votes.$_mint(accounts[1], tokens[2]); + }); + + describe('getPastVotes', function () { + it('reverts if block number >= current block', async function () { + const clock = await this.votes.clock(); + const timepoint = 5e10; // far in the future + await expectRevertCustomError(this.votes.getPastVotes(accounts[2], timepoint), 'ERC5805FutureLookup', [ + timepoint, + clock, + ]); + }); + + it('returns 0 if there are no checkpoints', async function () { + expect(await this.votes.getPastVotes(accounts[2], 0)).to.be.bignumber.equal('0'); + }); + + it('returns the latest block if >= last checkpoint block', async function () { + const { receipt } = await this.votes.delegate(accounts[2], { from: accounts[1] }); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + const latest = await this.votes.getVotes(accounts[2]); + expect(await this.votes.getPastVotes(accounts[2], timepoint)).to.be.bignumber.equal(latest); + expect(await this.votes.getPastVotes(accounts[2], timepoint + 1)).to.be.bignumber.equal(latest); + }); + + it('returns zero if < first checkpoint block', async function () { + await time.advanceBlock(); + const { receipt } = await this.votes.delegate(accounts[2], { from: accounts[1] }); + const timepoint = await clockFromReceipt[mode](receipt); + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.votes.getPastVotes(accounts[2], timepoint - 1)).to.be.bignumber.equal('0'); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeVotes, +}; diff --git a/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js b/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js new file mode 100644 index 0000000..b2b80f9 --- /dev/null +++ b/lib/openzeppelin-contracts/test/governance/utils/Votes.test.js @@ -0,0 +1,92 @@ +const { constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { clockFromReceipt } = require('../../helpers/time'); +const { BNsum } = require('../../helpers/math'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +require('array.prototype.at/auto'); + +const { shouldBehaveLikeVotes } = require('./Votes.behavior'); + +const MODES = { + blocknumber: artifacts.require('$VotesMock'), + timestamp: artifacts.require('$VotesTimestampMock'), +}; + +contract('Votes', function (accounts) { + const [account1, account2, account3] = accounts; + const amounts = { + [account1]: web3.utils.toBN('10000000000000000000000000'), + [account2]: web3.utils.toBN('10'), + [account3]: web3.utils.toBN('20'), + }; + + const name = 'My Vote'; + const version = '1'; + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.votes = await artifact.new(name, version); + }); + + shouldBehaveLikeVotes(accounts, Object.values(amounts), { mode, fungible: true }); + + 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.txs = []; + for (const [account, amount] of Object.entries(amounts)) { + this.txs.push(await this.votes.$_mint(account, amount)); + } + }); + + it('reverts if block number >= current block', async function () { + const lastTxTimepoint = await clockFromReceipt[mode](this.txs.at(-1).receipt); + const clock = await this.votes.clock(); + await expectRevertCustomError(this.votes.getPastTotalSupply(lastTxTimepoint + 1), 'ERC5805FutureLookup', [ + lastTxTimepoint + 1, + clock, + ]); + }); + + it('delegates', async function () { + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal('0'); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal('0'); + expect(await this.votes.delegates(account1)).to.be.equal(constants.ZERO_ADDRESS); + expect(await this.votes.delegates(account2)).to.be.equal(constants.ZERO_ADDRESS); + + await this.votes.delegate(account1, account1); + + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(amounts[account1]); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal('0'); + expect(await this.votes.delegates(account1)).to.be.equal(account1); + expect(await this.votes.delegates(account2)).to.be.equal(constants.ZERO_ADDRESS); + + await this.votes.delegate(account2, account1); + + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(amounts[account1].add(amounts[account2])); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal('0'); + expect(await this.votes.delegates(account1)).to.be.equal(account1); + expect(await this.votes.delegates(account2)).to.be.equal(account1); + }); + + it('cross delegates', async function () { + await this.votes.delegate(account1, account2); + await this.votes.delegate(account2, account1); + + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(amounts[account2]); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(amounts[account1]); + }); + + it('returns total amount of votes', async function () { + const totalSupply = BNsum(...Object.values(amounts)); + expect(await this.votes.getTotalSupply()).to.be.bignumber.equal(totalSupply); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/helpers/access-manager.js b/lib/openzeppelin-contracts/test/helpers/access-manager.js new file mode 100644 index 0000000..7dfc4c3 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/access-manager.js @@ -0,0 +1,69 @@ +const { time } = require('@openzeppelin/test-helpers'); +const { MAX_UINT64 } = require('./constants'); +const { artifacts } = require('hardhat'); + +function buildBaseRoles() { + const roles = { + ADMIN: { + id: web3.utils.toBN(0), + }, + SOME_ADMIN: { + id: web3.utils.toBN(17), + }, + SOME_GUARDIAN: { + id: web3.utils.toBN(35), + }, + SOME: { + id: web3.utils.toBN(42), + }, + PUBLIC: { + id: MAX_UINT64, + }, + }; + + // Names + Object.entries(roles).forEach(([name, role]) => (role.name = name)); + + // Defaults + for (const role of Object.keys(roles)) { + roles[role].admin = roles.ADMIN; + roles[role].guardian = roles.ADMIN; + } + + // Admins + roles.SOME.admin = roles.SOME_ADMIN; + + // Guardians + roles.SOME.guardian = roles.SOME_GUARDIAN; + + return roles; +} + +const formatAccess = access => [access[0], access[1].toString()]; + +const MINSETBACK = time.duration.days(5); +const EXPIRATION = time.duration.weeks(1); + +let EXECUTION_ID_STORAGE_SLOT = 3n; +let CONSUMING_SCHEDULE_STORAGE_SLOT = 0n; +try { + // Try to get the artifact paths, will throw if it doesn't exist + artifacts._getArtifactPathSync('AccessManagerUpgradeable'); + artifacts._getArtifactPathSync('AccessManagedUpgradeable'); + + // ERC-7201 namespace location for AccessManager + EXECUTION_ID_STORAGE_SLOT += 0x40c6c8c28789853c7efd823ab20824bbd71718a8a5915e855f6f288c9a26ad00n; + // ERC-7201 namespace location for AccessManaged + CONSUMING_SCHEDULE_STORAGE_SLOT += 0xf3177357ab46d8af007ab3fdb9af81da189e1068fefdc0073dca88a2cab40a00n; +} catch (_) { + // eslint-disable-next-line no-empty +} + +module.exports = { + buildBaseRoles, + formatAccess, + MINSETBACK, + EXPIRATION, + EXECUTION_ID_STORAGE_SLOT, + CONSUMING_SCHEDULE_STORAGE_SLOT, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/account.js b/lib/openzeppelin-contracts/test/helpers/account.js new file mode 100644 index 0000000..1b01a72 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/account.js @@ -0,0 +1,14 @@ +const { web3 } = require('hardhat'); +const { impersonateAccount, setBalance } = require('@nomicfoundation/hardhat-network-helpers'); + +// Hardhat default balance +const DEFAULT_BALANCE = web3.utils.toBN('10000000000000000000000'); + +async function impersonate(account, balance = DEFAULT_BALANCE) { + await impersonateAccount(account); + await setBalance(account, balance); +} + +module.exports = { + impersonate, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/chainid.js b/lib/openzeppelin-contracts/test/helpers/chainid.js new file mode 100644 index 0000000..58757eb --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/chainid.js @@ -0,0 +1,10 @@ +const hre = require('hardhat'); + +async function getChainId() { + const chainIdHex = await hre.network.provider.send('eth_chainId', []); + return new hre.web3.utils.BN(chainIdHex, 'hex'); +} + +module.exports = { + getChainId, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/constants.js b/lib/openzeppelin-contracts/test/helpers/constants.js new file mode 100644 index 0000000..0f4d028 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/constants.js @@ -0,0 +1,7 @@ +const MAX_UINT48 = web3.utils.toBN(1).shln(48).subn(1).toString(); +const MAX_UINT64 = web3.utils.toBN(1).shln(64).subn(1).toString(); + +module.exports = { + MAX_UINT48, + MAX_UINT64, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/create.js b/lib/openzeppelin-contracts/test/helpers/create.js new file mode 100644 index 0000000..98a0d4c --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/create.js @@ -0,0 +1,22 @@ +const RLP = require('rlp'); + +function computeCreateAddress(deployer, nonce) { + return web3.utils.toChecksumAddress(web3.utils.sha3(RLP.encode([deployer.address ?? deployer, nonce])).slice(-40)); +} + +function computeCreate2Address(saltHex, bytecode, deployer) { + return web3.utils.toChecksumAddress( + web3.utils + .sha3( + `0x${['ff', deployer.address ?? deployer, saltHex, web3.utils.soliditySha3(bytecode)] + .map(x => x.replace(/0x/, '')) + .join('')}`, + ) + .slice(-40), + ); +} + +module.exports = { + computeCreateAddress, + computeCreate2Address, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/customError.js b/lib/openzeppelin-contracts/test/helpers/customError.js new file mode 100644 index 0000000..ea5c368 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/customError.js @@ -0,0 +1,43 @@ +const { expect } = require('chai'); + +/** Revert handler that supports custom errors. */ +async function expectRevertCustomError(promise, expectedErrorName, args) { + if (!Array.isArray(args)) { + expect.fail('Expected 3rd array parameter for error arguments'); + } + + await promise.then( + () => expect.fail("Expected promise to throw but it didn't"), + ({ message }) => { + // The revert message for custom errors looks like: + // VM Exception while processing transaction: + // reverted with custom error 'InvalidAccountNonce("0x70997970C51812dc3A010C7d01b50e0d17dc79C8", 0)' + + // Attempt to parse as a custom error + const match = message.match(/custom error '(?\w+)\((?.*)\)'/); + if (!match) { + expect.fail(`Could not parse as custom error. ${message}`); + } + // Extract the error name and parameters + const errorName = match.groups.name; + const argMatches = [...match.groups.args.matchAll(/-?\w+/g)]; + + // Assert error name + expect(errorName).to.be.equal( + expectedErrorName, + `Unexpected custom error name (with found args: [${argMatches.map(([a]) => a)}])`, + ); + + // Coerce to string for comparison since `arg` can be either a number or hex. + const sanitizedExpected = args.map(arg => arg.toString().toLowerCase()); + const sanitizedActual = argMatches.map(([arg]) => arg.toString().toLowerCase()); + + // Assert argument equality + expect(sanitizedActual).to.have.members(sanitizedExpected, `Unexpected ${errorName} arguments`); + }, + ); +} + +module.exports = { + expectRevertCustomError, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/eip712.js b/lib/openzeppelin-contracts/test/helpers/eip712.js new file mode 100644 index 0000000..b12a623 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/eip712.js @@ -0,0 +1,67 @@ +const ethSigUtil = require('eth-sig-util'); +const keccak256 = require('keccak256'); + +const EIP712Domain = [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + { name: 'salt', type: 'bytes32' }, +]; + +const Permit = [ + { name: 'owner', type: 'address' }, + { name: 'spender', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint256' }, +]; + +function bufferToHexString(buffer) { + return '0x' + buffer.toString('hex'); +} + +function hexStringToBuffer(hexstr) { + return Buffer.from(hexstr.replace(/^0x/, ''), 'hex'); +} + +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', domain, { EIP712Domain: domainType(domain) }), + ); +} + +function hashTypedData(domain, structHash) { + return bufferToHexString( + keccak256(Buffer.concat(['0x1901', domainSeparator(domain), structHash].map(str => hexStringToBuffer(str)))), + ); +} + +module.exports = { + Permit, + getDomain, + domainType, + domainSeparator, + hashTypedData, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/enums.js b/lib/openzeppelin-contracts/test/helpers/enums.js new file mode 100644 index 0000000..6280e0f --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/enums.js @@ -0,0 +1,11 @@ +function Enum(...options) { + return Object.fromEntries(options.map((key, i) => [key, web3.utils.toBN(i)])); +} + +module.exports = { + Enum, + ProposalState: Enum('Pending', 'Active', 'Canceled', 'Defeated', 'Succeeded', 'Queued', 'Expired', 'Executed'), + VoteType: Enum('Against', 'For', 'Abstain'), + Rounding: Enum('Floor', 'Ceil', 'Trunc', 'Expand'), + OperationState: Enum('Unset', 'Waiting', 'Ready', 'Done'), +}; diff --git a/lib/openzeppelin-contracts/test/helpers/erc1967.js b/lib/openzeppelin-contracts/test/helpers/erc1967.js new file mode 100644 index 0000000..4ad92c5 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/erc1967.js @@ -0,0 +1,43 @@ +const { getStorageAt, setStorageAt } = require('@nomicfoundation/hardhat-network-helpers'); + +const ImplementationLabel = 'eip1967.proxy.implementation'; +const AdminLabel = 'eip1967.proxy.admin'; +const BeaconLabel = 'eip1967.proxy.beacon'; + +function labelToSlot(label) { + return '0x' + web3.utils.toBN(web3.utils.keccak256(label)).subn(1).toString(16); +} + +function getSlot(address, slot) { + return getStorageAt( + web3.utils.isAddress(address) ? address : address.address, + web3.utils.isHex(slot) ? slot : labelToSlot(slot), + ); +} + +function setSlot(address, slot, value) { + const hexValue = web3.utils.isHex(value) ? value : web3.utils.toHex(value); + + return setStorageAt( + web3.utils.isAddress(address) ? address : address.address, + web3.utils.isHex(slot) ? slot : labelToSlot(slot), + web3.utils.padLeft(hexValue, 64), + ); +} + +async function getAddressInSlot(address, slot) { + const slotValue = await getSlot(address, slot); + return web3.utils.toChecksumAddress(slotValue.substring(slotValue.length - 40)); +} + +module.exports = { + ImplementationLabel, + AdminLabel, + BeaconLabel, + ImplementationSlot: labelToSlot(ImplementationLabel), + AdminSlot: labelToSlot(AdminLabel), + BeaconSlot: labelToSlot(BeaconLabel), + setSlot, + getSlot, + getAddressInSlot, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/governance.js b/lib/openzeppelin-contracts/test/helpers/governance.js new file mode 100644 index 0000000..fc4e300 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/governance.js @@ -0,0 +1,253 @@ +const { web3 } = require('hardhat'); +const { forward } = require('../helpers/time'); +const { ProposalState } = require('./enums'); + +function zip(...args) { + return Array(Math.max(...args.map(array => array.length))) + .fill() + .map((_, i) => args.map(array => array[i])); +} + +function concatHex(...args) { + return web3.utils.bytesToHex([].concat(...args.map(h => web3.utils.hexToBytes(h || '0x')))); +} + +function concatOpts(args, opts = null) { + return opts ? args.concat(opts) : args; +} + +const timelockSalt = (address, descriptionHash) => + '0x' + web3.utils.toBN(address).shln(96).xor(web3.utils.toBN(descriptionHash)).toString(16, 64); + +class GovernorHelper { + constructor(governor, mode = 'blocknumber') { + this.governor = governor; + this.mode = mode; + } + + delegate(delegation = {}, opts = null) { + return Promise.all([ + delegation.token.delegate(delegation.to, { from: delegation.to }), + delegation.value && delegation.token.transfer(...concatOpts([delegation.to, delegation.value]), opts), + delegation.tokenId && + delegation.token + .ownerOf(delegation.tokenId) + .then(owner => + delegation.token.transferFrom(...concatOpts([owner, delegation.to, delegation.tokenId], opts)), + ), + ]); + } + + propose(opts = null) { + const proposal = this.currentProposal; + + return this.governor.methods[ + proposal.useCompatibilityInterface + ? 'propose(address[],uint256[],string[],bytes[],string)' + : 'propose(address[],uint256[],bytes[],string)' + ](...concatOpts(proposal.fullProposal, opts)); + } + + queue(opts = null) { + const proposal = this.currentProposal; + + return proposal.useCompatibilityInterface + ? this.governor.methods['queue(uint256)'](...concatOpts([proposal.id], opts)) + : this.governor.methods['queue(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } + + execute(opts = null) { + const proposal = this.currentProposal; + + return proposal.useCompatibilityInterface + ? this.governor.methods['execute(uint256)'](...concatOpts([proposal.id], opts)) + : this.governor.methods['execute(address[],uint256[],bytes[],bytes32)']( + ...concatOpts(proposal.shortProposal, opts), + ); + } + + cancel(visibility = 'external', opts = null) { + const proposal = this.currentProposal; + + switch (visibility) { + case 'external': + 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), + ); + default: + throw new Error(`unsupported visibility "${visibility}"`); + } + } + + vote(vote = {}, opts = null) { + const proposal = this.currentProposal; + + return vote.signature + ? // if signature, and either params or reason → + vote.params || vote.reason + ? this.sign(vote).then(signature => + this.governor.castVoteWithReasonAndParamsBySig( + ...concatOpts( + [proposal.id, vote.support, vote.voter, vote.reason || '', vote.params || '', signature], + opts, + ), + ), + ) + : this.sign(vote).then(signature => + this.governor.castVoteBySig(...concatOpts([proposal.id, vote.support, vote.voter, signature], opts)), + ) + : vote.params + ? // otherwise if params + this.governor.castVoteWithReasonAndParams( + ...concatOpts([proposal.id, vote.support, vote.reason || '', vote.params], opts), + ) + : vote.reason + ? // otherwise if reason + this.governor.castVoteWithReason(...concatOpts([proposal.id, vote.support, vote.reason], opts)) + : this.governor.castVote(...concatOpts([proposal.id, vote.support], opts)); + } + + sign(vote = {}) { + return vote.signature(this.governor, this.forgeMessage(vote)); + } + + forgeMessage(vote = {}) { + const proposal = this.currentProposal; + + const message = { proposalId: proposal.id, support: vote.support, voter: vote.voter, nonce: vote.nonce }; + + if (vote.params || vote.reason) { + message.reason = vote.reason || ''; + message.params = vote.params || ''; + } + + return message; + } + + async waitForSnapshot(offset = 0) { + const proposal = this.currentProposal; + const timepoint = await this.governor.proposalSnapshot(proposal.id); + return forward[this.mode](timepoint.addn(offset)); + } + + async waitForDeadline(offset = 0) { + const proposal = this.currentProposal; + const timepoint = await this.governor.proposalDeadline(proposal.id); + return forward[this.mode](timepoint.addn(offset)); + } + + async waitForEta(offset = 0) { + const proposal = this.currentProposal; + const timestamp = await this.governor.proposalEta(proposal.id); + return forward.timestamp(timestamp.addn(offset)); + } + + /** + * Specify a proposal either as + * 1) an array of objects [{ target, value, data, signature? }] + * 2) an object of arrays { targets: [], values: [], data: [], signatures?: [] } + */ + setProposal(actions, description) { + let targets, values, signatures, data, useCompatibilityInterface; + + if (Array.isArray(actions)) { + useCompatibilityInterface = actions.some(a => 'signature' in a); + targets = actions.map(a => a.target); + values = actions.map(a => a.value || '0'); + signatures = actions.map(a => a.signature || ''); + data = actions.map(a => a.data || '0x'); + } else { + useCompatibilityInterface = Array.isArray(actions.signatures); + ({ targets, values, signatures = [], data } = actions); + } + + const fulldata = zip( + signatures.map(s => s && web3.eth.abi.encodeFunctionSignature(s)), + data, + ).map(hexs => concatHex(...hexs)); + + const descriptionHash = web3.utils.keccak256(description); + + // condensed version for queueing end executing + const shortProposal = [targets, values, fulldata, descriptionHash]; + + // full version for proposing + const fullProposal = [targets, values, ...(useCompatibilityInterface ? [signatures] : []), data, description]; + + // proposal id + const id = web3.utils.toBN( + web3.utils.keccak256( + web3.eth.abi.encodeParameters(['address[]', 'uint256[]', 'bytes[]', 'bytes32'], shortProposal), + ), + ); + + this.currentProposal = { + id, + targets, + values, + signatures, + data, + fulldata, + description, + descriptionHash, + shortProposal, + fullProposal, + useCompatibilityInterface, + }; + + return this.currentProposal; + } +} + +/** + * Encodes a list ProposalStates into a bytes32 representation where each bit enabled corresponds to + * the underlying position in the `ProposalState` enum. For example: + * + * 0x000...10000 + * ^^^^^^------ ... + * ^----- Succeeded + * ^---- Defeated + * ^--- Canceled + * ^-- Active + * ^- Pending + */ +function proposalStatesToBitMap(proposalStates, options = {}) { + if (!Array.isArray(proposalStates)) { + proposalStates = [proposalStates]; + } + const statesCount = Object.keys(ProposalState).length; + let result = 0; + + const uniqueProposalStates = new Set(proposalStates.map(bn => bn.toNumber())); // Remove duplicates + for (const state of uniqueProposalStates) { + if (state < 0 || state >= statesCount) { + expect.fail(`ProposalState ${state} out of possible states (0...${statesCount}-1)`); + } else { + result |= 1 << state; + } + } + + if (options.inverted) { + const mask = 2 ** statesCount - 1; + result = result ^ mask; + } + + const hex = web3.utils.numberToHex(result); + return web3.utils.padLeft(hex, 64); +} + +module.exports = { + GovernorHelper, + proposalStatesToBitMap, + timelockSalt, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/iterate.js b/lib/openzeppelin-contracts/test/helpers/iterate.js new file mode 100644 index 0000000..7f6e0e6 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/iterate.js @@ -0,0 +1,16 @@ +// Map values in an object +const mapValues = (obj, fn) => Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, fn(v)])); + +// Array of number or bigint +const max = (...values) => values.slice(1).reduce((x, y) => (x > y ? x : y), values[0]); +const min = (...values) => values.slice(1).reduce((x, y) => (x < y ? x : y), values[0]); + +// Cartesian product of a list of arrays +const product = (...arrays) => arrays.reduce((a, b) => a.flatMap(ai => b.map(bi => [...ai, bi])), [[]]); + +module.exports = { + mapValues, + max, + min, + product, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/math.js b/lib/openzeppelin-contracts/test/helpers/math.js new file mode 100644 index 0000000..2bc654c --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/math.js @@ -0,0 +1,11 @@ +module.exports = { + // sum of integer / bignumber + sum: (...args) => args.reduce((acc, n) => acc + n, 0), + BNsum: (...args) => args.reduce((acc, n) => acc.add(n), web3.utils.toBN(0)), + // min of integer / bignumber + min: (...args) => args.slice(1).reduce((x, y) => (x < y ? x : y), args[0]), + BNmin: (...args) => args.slice(1).reduce((x, y) => (x.lt(y) ? x : y), args[0]), + // max of integer / bignumber + max: (...args) => args.slice(1).reduce((x, y) => (x > y ? x : y), args[0]), + BNmax: (...args) => args.slice(1).reduce((x, y) => (x.gt(y) ? x : y), args[0]), +}; diff --git a/lib/openzeppelin-contracts/test/helpers/methods.js b/lib/openzeppelin-contracts/test/helpers/methods.js new file mode 100644 index 0000000..cb30d87 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/methods.js @@ -0,0 +1,5 @@ +const { soliditySha3 } = require('web3-utils'); + +module.exports = { + selector: signature => soliditySha3(signature).substring(0, 10), +}; diff --git a/lib/openzeppelin-contracts/test/helpers/sign.js b/lib/openzeppelin-contracts/test/helpers/sign.js new file mode 100644 index 0000000..d537116 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/sign.js @@ -0,0 +1,63 @@ +function toEthSignedMessageHash(messageHex) { + const messageBuffer = Buffer.from(messageHex.substring(2), 'hex'); + const prefix = Buffer.from(`\u0019Ethereum Signed Message:\n${messageBuffer.length}`); + 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 + * @param contract TruffleContract + * @param signer address + * @param redeemer address + * @param methodName string + * @param methodArgs any[] + */ +const getSignFor = + (contract, signer) => + (redeemer, methodName, methodArgs = []) => { + const parts = [contract.address, redeemer]; + + const REAL_SIGNATURE_SIZE = 2 * 65; // 65 bytes in hexadecimal string length + const PADDED_SIGNATURE_SIZE = 2 * 96; // 96 bytes in hexadecimal string length + const DUMMY_SIGNATURE = `0x${web3.utils.padLeft('', REAL_SIGNATURE_SIZE)}`; + + // if we have a method, add it to the parts that we're signing + if (methodName) { + if (methodArgs.length > 0) { + parts.push( + contract.contract.methods[methodName](...methodArgs.concat([DUMMY_SIGNATURE])) + .encodeABI() + .slice(0, -1 * PADDED_SIGNATURE_SIZE), + ); + } else { + const abi = contract.abi.find(abi => abi.name === methodName); + parts.push(abi.signature); + } + } + + // return the signature of the "Ethereum Signed Message" hash of the hash of `parts` + const messageHex = web3.utils.soliditySha3(...parts); + return web3.eth.sign(messageHex, signer); + }; + +module.exports = { + toEthSignedMessageHash, + toDataWithIntendedValidatorHash, + getSignFor, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/time.js b/lib/openzeppelin-contracts/test/helpers/time.js new file mode 100644 index 0000000..30df8dc --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/time.js @@ -0,0 +1,17 @@ +const ozHelpers = require('@openzeppelin/test-helpers'); +const helpers = require('@nomicfoundation/hardhat-network-helpers'); + +module.exports = { + clock: { + 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: ozHelpers.time.advanceBlockTo, + timestamp: helpers.time.increaseTo, + }, +}; diff --git a/lib/openzeppelin-contracts/test/helpers/txpool.js b/lib/openzeppelin-contracts/test/helpers/txpool.js new file mode 100644 index 0000000..ecdba54 --- /dev/null +++ b/lib/openzeppelin-contracts/test/helpers/txpool.js @@ -0,0 +1,38 @@ +const { network } = require('hardhat'); +const { promisify } = require('util'); + +const queue = promisify(setImmediate); + +async function countPendingTransactions() { + return parseInt(await network.provider.send('eth_getBlockTransactionCountByNumber', ['pending'])); +} + +async function batchInBlock(txs) { + try { + // disable auto-mining + await network.provider.send('evm_setAutomine', [false]); + // send all transactions + const promises = txs.map(fn => fn()); + // wait for node to have all pending transactions + while (txs.length > (await countPendingTransactions())) { + await queue(); + } + // mine one block + await network.provider.send('evm_mine'); + // fetch receipts + const receipts = await Promise.all(promises); + // Sanity check, all tx should be in the same block + const minedBlocks = new Set(receipts.map(({ receipt }) => receipt.blockNumber)); + expect(minedBlocks.size).to.equal(1); + + return receipts; + } finally { + // enable auto-mining + await network.provider.send('evm_setAutomine', [true]); + } +} + +module.exports = { + countPendingTransactions, + batchInBlock, +}; diff --git a/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js b/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js new file mode 100644 index 0000000..b0ebccc --- /dev/null +++ b/lib/openzeppelin-contracts/test/metatx/ERC2771Context.test.js @@ -0,0 +1,134 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); +const { MAX_UINT48 } = require('../helpers/constants'); + +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC2771ContextMock = artifacts.require('ERC2771ContextMock'); +const ERC2771Forwarder = artifacts.require('ERC2771Forwarder'); +const ContextMockCaller = artifacts.require('ContextMockCaller'); + +const { shouldBehaveLikeRegularContext } = require('../utils/Context.behavior'); + +contract('ERC2771Context', function (accounts) { + const [, trustedForwarder] = accounts; + + beforeEach(async function () { + this.forwarder = await ERC2771Forwarder.new('ERC2771Forwarder'); + this.recipient = await ERC2771ContextMock.new(this.forwarder.address); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint48' }, + { name: 'data', type: 'bytes' }, + ], + }; + }); + + it('recognize trusted forwarder', async function () { + expect(await this.recipient.isTrustedForwarder(this.forwarder.address)).to.equal(true); + }); + + it('returns the trusted forwarder', async function () { + expect(await this.recipient.trustedForwarder()).to.equal(this.forwarder.address); + }); + + context('when called directly', function () { + beforeEach(async function () { + this.context = this.recipient; // The Context behavior expects the contract in this.context + this.caller = await ContextMockCaller.new(); + }); + + shouldBehaveLikeRegularContext(...accounts); + }); + + context('when receiving a relayed call', function () { + beforeEach(async function () { + this.wallet = Wallet.generate(); + this.sender = web3.utils.toChecksumAddress(this.wallet.getAddressString()); + this.data = { + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + }; + }); + + describe('msgSender', function () { + it('returns the relayed transaction original sender', async function () { + const data = this.recipient.contract.methods.msgSender().encodeABI(); + + const req = { + from: this.sender, + to: this.recipient.address, + value: '0', + gas: '100000', + nonce: (await this.forwarder.nonces(this.sender)).toString(), + deadline: MAX_UINT48, + data, + }; + + req.signature = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { + data: { ...this.data, message: req }, + }); + expect(await this.forwarder.verify(req)).to.equal(true); + + const { tx } = await this.forwarder.execute(req); + await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Sender', { sender: this.sender }); + }); + + it('returns the original sender when calldata length is less than 20 bytes (address length)', async function () { + // The forwarder doesn't produce calls with calldata length less than 20 bytes + const recipient = await ERC2771ContextMock.new(trustedForwarder); + + const { receipt } = await recipient.msgSender({ from: trustedForwarder }); + + await expectEvent(receipt, 'Sender', { sender: trustedForwarder }); + }); + }); + + describe('msgData', function () { + it('returns the relayed transaction original data', async function () { + const integerValue = '42'; + const stringValue = 'OpenZeppelin'; + const data = this.recipient.contract.methods.msgData(integerValue, stringValue).encodeABI(); + + const req = { + from: this.sender, + to: this.recipient.address, + value: '0', + gas: '100000', + nonce: (await this.forwarder.nonces(this.sender)).toString(), + deadline: MAX_UINT48, + data, + }; + + req.signature = ethSigUtil.signTypedMessage(this.wallet.getPrivateKey(), { + data: { ...this.data, message: req }, + }); + expect(await this.forwarder.verify(req)).to.equal(true); + + const { tx } = await this.forwarder.execute(req); + await expectEvent.inTransaction(tx, ERC2771ContextMock, 'Data', { data, integerValue, stringValue }); + }); + }); + + it('returns the full original data when calldata length is less than 20 bytes (address length)', async function () { + // The forwarder doesn't produce calls with calldata length less than 20 bytes + const recipient = await ERC2771ContextMock.new(trustedForwarder); + + const { receipt } = await recipient.msgDataShort({ from: trustedForwarder }); + + const data = recipient.contract.methods.msgDataShort().encodeABI(); + await expectEvent(receipt, 'DataShort', { data }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol b/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol new file mode 100644 index 0000000..d69b475 --- /dev/null +++ b/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.t.sol @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {ERC2771Forwarder} from "@openzeppelin/contracts/metatx/ERC2771Forwarder.sol"; +import {CallReceiverMockTrustingForwarder, CallReceiverMock} from "@openzeppelin/contracts/mocks/CallReceiverMock.sol"; + +struct ForwardRequest { + address from; + address to; + uint256 value; + uint256 gas; + uint256 nonce; + uint48 deadline; + bytes data; +} + +contract ERC2771ForwarderMock is ERC2771Forwarder { + constructor(string memory name) ERC2771Forwarder(name) {} + + function structHash(ForwardRequest calldata request) external view returns (bytes32) { + return + _hashTypedDataV4( + keccak256( + abi.encode( + _FORWARD_REQUEST_TYPEHASH, + request.from, + request.to, + request.value, + request.gas, + request.nonce, + request.deadline, + keccak256(request.data) + ) + ) + ); + } +} + +contract ERC2771ForwarderTest is Test { + ERC2771ForwarderMock internal _erc2771Forwarder; + CallReceiverMockTrustingForwarder internal _receiver; + + uint256 internal _signerPrivateKey; + uint256 internal _relayerPrivateKey; + + address internal _signer; + address internal _relayer; + + uint256 internal constant _MAX_ETHER = 10_000_000; // To avoid overflow + + function setUp() public { + _erc2771Forwarder = new ERC2771ForwarderMock("ERC2771Forwarder"); + _receiver = new CallReceiverMockTrustingForwarder(address(_erc2771Forwarder)); + + _signerPrivateKey = 0xA11CE; + _relayerPrivateKey = 0xB0B; + + _signer = vm.addr(_signerPrivateKey); + _relayer = vm.addr(_relayerPrivateKey); + } + + function _forgeRequestData( + uint256 value, + uint256 nonce, + uint48 deadline, + bytes memory data + ) private view returns (ERC2771Forwarder.ForwardRequestData memory) { + ForwardRequest memory request = ForwardRequest({ + from: _signer, + to: address(_receiver), + value: value, + gas: 30000, + nonce: nonce, + deadline: deadline, + data: data + }); + + bytes32 digest = _erc2771Forwarder.structHash(request); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(_signerPrivateKey, digest); + bytes memory signature = abi.encodePacked(r, s, v); + + return + ERC2771Forwarder.ForwardRequestData({ + from: request.from, + to: request.to, + value: request.value, + gas: request.gas, + deadline: request.deadline, + data: request.data, + signature: signature + }); + } + + function testExecuteAvoidsETHStuck(uint256 initialBalance, uint256 value, bool targetReverts) public { + initialBalance = bound(initialBalance, 0, _MAX_ETHER); + value = bound(value, 0, _MAX_ETHER); + + vm.deal(address(_erc2771Forwarder), initialBalance); + + uint256 nonce = _erc2771Forwarder.nonces(_signer); + + vm.deal(address(this), value); + + ERC2771Forwarder.ForwardRequestData memory requestData = _forgeRequestData({ + value: value, + nonce: nonce, + deadline: uint48(block.timestamp + 1), + data: targetReverts + ? abi.encodeCall(CallReceiverMock.mockFunctionRevertsNoReason, ()) + : abi.encodeCall(CallReceiverMock.mockFunction, ()) + }); + + if (targetReverts) { + vm.expectRevert(); + } + + _erc2771Forwarder.execute{value: value}(requestData); + assertEq(address(_erc2771Forwarder).balance, initialBalance); + } + + function testExecuteBatchAvoidsETHStuck(uint256 initialBalance, uint256 batchSize, uint256 value) public { + batchSize = bound(batchSize, 1, 10); + initialBalance = bound(initialBalance, 0, _MAX_ETHER); + value = bound(value, 0, _MAX_ETHER); + + vm.deal(address(_erc2771Forwarder), initialBalance); + uint256 nonce = _erc2771Forwarder.nonces(_signer); + + ERC2771Forwarder.ForwardRequestData[] memory batchRequestDatas = new ERC2771Forwarder.ForwardRequestData[]( + batchSize + ); + + uint256 expectedRefund; + + for (uint256 i = 0; i < batchSize; ++i) { + bytes memory data; + bool succeed = uint256(keccak256(abi.encodePacked(initialBalance, i))) % 2 == 0; + + if (succeed) { + data = abi.encodeCall(CallReceiverMock.mockFunction, ()); + } else { + expectedRefund += value; + data = abi.encodeCall(CallReceiverMock.mockFunctionRevertsNoReason, ()); + } + + batchRequestDatas[i] = _forgeRequestData({ + value: value, + nonce: nonce + i, + deadline: uint48(block.timestamp + 1), + data: data + }); + } + + address payable refundReceiver = payable(address(0xebe)); + uint256 totalValue = value * batchSize; + + vm.deal(address(this), totalValue); + _erc2771Forwarder.executeBatch{value: totalValue}(batchRequestDatas, refundReceiver); + + assertEq(address(_erc2771Forwarder).balance, initialBalance); + assertEq(refundReceiver.balance, expectedRefund); + } +} diff --git a/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js b/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js new file mode 100644 index 0000000..0e09988 --- /dev/null +++ b/lib/openzeppelin-contracts/test/metatx/ERC2771Forwarder.test.js @@ -0,0 +1,541 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; +const { getDomain, domainType } = require('../helpers/eip712'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { constants, expectRevert, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const ERC2771Forwarder = artifacts.require('ERC2771Forwarder'); +const CallReceiverMockTrustingForwarder = artifacts.require('CallReceiverMockTrustingForwarder'); + +contract('ERC2771Forwarder', function (accounts) { + const [, refundReceiver, another] = accounts; + + const tamperedValues = { + from: another, + value: web3.utils.toWei('0.5'), + data: '0x1742', + }; + + beforeEach(async function () { + this.forwarder = await ERC2771Forwarder.new('ERC2771Forwarder'); + + this.domain = await getDomain(this.forwarder); + this.types = { + EIP712Domain: domainType(this.domain), + ForwardRequest: [ + { name: 'from', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'gas', type: 'uint256' }, + { name: 'nonce', type: 'uint256' }, + { name: 'deadline', type: 'uint48' }, + { name: 'data', type: 'bytes' }, + ], + }; + + this.alice = Wallet.generate(); + this.alice.address = web3.utils.toChecksumAddress(this.alice.getAddressString()); + + this.timestamp = await time.latest(); + this.receiver = await CallReceiverMockTrustingForwarder.new(this.forwarder.address); + this.request = { + from: this.alice.address, + to: this.receiver.address, + value: '0', + gas: '100000', + data: this.receiver.contract.methods.mockFunction().encodeABI(), + deadline: this.timestamp.toNumber() + 60, // 1 minute + }; + this.requestData = { + ...this.request, + nonce: (await this.forwarder.nonces(this.alice.address)).toString(), + }; + + this.forgeData = request => ({ + types: this.types, + domain: this.domain, + primaryType: 'ForwardRequest', + message: { ...this.requestData, ...request }, + }); + this.sign = (privateKey, request) => + ethSigUtil.signTypedMessage(privateKey, { + data: this.forgeData(request), + }); + this.estimateRequest = request => + web3.eth.estimateGas({ + from: this.forwarder.address, + to: request.to, + data: web3.utils.encodePacked({ value: request.data, type: 'bytes' }, { value: request.from, type: 'address' }), + value: request.value, + gas: request.gas, + }); + + this.requestData.signature = this.sign(this.alice.getPrivateKey()); + }); + + context('verify', function () { + context('with valid signature', function () { + it('returns true without altering the nonce', async function () { + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + expect(await this.forwarder.verify(this.requestData)).to.be.equal(true); + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + }); + }); + + context('with tampered values', function () { + for (const [key, value] of Object.entries(tamperedValues)) { + it(`returns false with tampered ${key}`, async function () { + expect(await this.forwarder.verify(this.forgeData({ [key]: value }).message)).to.be.equal(false); + }); + } + + it('returns false with an untrustful to', async function () { + expect(await this.forwarder.verify(this.forgeData({ to: another }).message)).to.be.equal(false); + }); + + it('returns false with tampered signature', async function () { + const tamperedsign = web3.utils.hexToBytes(this.requestData.signature); + tamperedsign[42] ^= 0xff; + this.requestData.signature = web3.utils.bytesToHex(tamperedsign); + expect(await this.forwarder.verify(this.requestData)).to.be.equal(false); + }); + + it('returns false with valid signature for non-current nonce', async function () { + const req = { + ...this.requestData, + nonce: this.requestData.nonce + 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + expect(await this.forwarder.verify(req)).to.be.equal(false); + }); + + it('returns false with valid signature for expired deadline', async function () { + const req = { + ...this.requestData, + deadline: this.timestamp - 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + expect(await this.forwarder.verify(req)).to.be.equal(false); + }); + }); + }); + + context('execute', function () { + context('with valid requests', function () { + beforeEach(async function () { + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce), + ); + }); + + it('emits an event and consumes nonce for a successful request', async function () { + const receipt = await this.forwarder.execute(this.requestData); + await expectEvent.inTransaction(receipt.tx, this.receiver, 'MockFunctionCalled'); + await expectEvent.inTransaction(receipt.tx, this.forwarder, 'ExecutedForwardRequest', { + signer: this.requestData.from, + nonce: web3.utils.toBN(this.requestData.nonce), + success: true, + }); + expect(await this.forwarder.nonces(this.requestData.from)).to.be.bignumber.equal( + web3.utils.toBN(this.requestData.nonce + 1), + ); + }); + + it('reverts with an unsuccessful request', async function () { + const req = { + ...this.requestData, + data: this.receiver.contract.methods.mockFunctionRevertsNoReason().encodeABI(), + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'FailedInnerCall', []); + }); + }); + + context('with tampered request', function () { + for (const [key, value] of Object.entries(tamperedValues)) { + it(`reverts with tampered ${key}`, async function () { + const data = this.forgeData({ [key]: value }); + await expectRevertCustomError( + this.forwarder.execute(data.message, { + value: key == 'value' ? value : 0, // To avoid MismatchedValue error + }), + 'ERC2771ForwarderInvalidSigner', + [ethSigUtil.recoverTypedSignature({ data, sig: this.requestData.signature }), data.message.from], + ); + }); + } + + it('reverts with an untrustful to', async function () { + const data = this.forgeData({ to: another }); + await expectRevertCustomError(this.forwarder.execute(data.message), 'ERC2771UntrustfulTarget', [ + data.message.to, + this.forwarder.address, + ]); + }); + + it('reverts with tampered signature', async function () { + const tamperedSig = web3.utils.hexToBytes(this.requestData.signature); + tamperedSig[42] ^= 0xff; + this.requestData.signature = web3.utils.bytesToHex(tamperedSig); + await expectRevertCustomError(this.forwarder.execute(this.requestData), 'ERC2771ForwarderInvalidSigner', [ + ethSigUtil.recoverTypedSignature({ data: this.forgeData(), sig: tamperedSig }), + this.requestData.from, + ]); + }); + + it('reverts with valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestData); + + // And then fail due to an already used nonce + await expectRevertCustomError(this.forwarder.execute(this.requestData), 'ERC2771ForwarderInvalidSigner', [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData({ ...this.requestData, nonce: this.requestData.nonce + 1 }), + sig: this.requestData.signature, + }), + this.requestData.from, + ]); + }); + + it('reverts with valid signature for expired deadline', async function () { + const req = { + ...this.requestData, + deadline: this.timestamp - 1, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'ERC2771ForwarderExpiredRequest', [ + this.timestamp - 1, + ]); + }); + + it('reverts with valid signature but mismatched value', async function () { + const value = 100; + const req = { + ...this.requestData, + value, + }; + req.signature = this.sign(this.alice.getPrivateKey(), req); + await expectRevertCustomError(this.forwarder.execute(req), 'ERC2771ForwarderMismatchedValue', [0, value]); + }); + }); + + it('bubbles out of gas', async function () { + this.requestData.data = this.receiver.contract.methods.mockFunctionOutOfGas().encodeABI(); + this.requestData.gas = 1_000_000; + this.requestData.signature = this.sign(this.alice.getPrivateKey()); + + const gasAvailable = 100_000; + await expectRevert.assertion(this.forwarder.execute(this.requestData, { gas: gasAvailable })); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + expect(gasUsed).to.be.equal(gasAvailable); + }); + + it('bubbles out of gas forced by the relayer', async function () { + // If there's an incentive behind executing requests, a malicious relayer could grief + // the forwarder by executing requests and providing a top-level call gas limit that + // is too low to successfully finish the request after the 63/64 rule. + + // We set the baseline to the gas limit consumed by a successful request if it was executed + // normally. Note this includes the 21000 buffer that also the relayer will be charged to + // start a request execution. + const estimate = await this.estimateRequest(this.request); + + // Because the relayer call consumes gas until the `CALL` opcode, the gas left after failing + // the subcall won't enough to finish the top level call (after testing), so we add a + // moderated buffer. + const gasAvailable = estimate + 2_000; + + // The subcall out of gas should be caught by the contract and then bubbled up consuming + // the available gas with an `invalid` opcode. + await expectRevert.outOfGas(this.forwarder.execute(this.requestData, { gas: gasAvailable })); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + // We assert that indeed the gas was totally consumed. + expect(gasUsed).to.be.equal(gasAvailable); + }); + }); + + context('executeBatch', function () { + const batchValue = requestDatas => requestDatas.reduce((value, request) => value + Number(request.value), 0); + + beforeEach(async function () { + this.bob = Wallet.generate(); + this.bob.address = web3.utils.toChecksumAddress(this.bob.getAddressString()); + + this.eve = Wallet.generate(); + this.eve.address = web3.utils.toChecksumAddress(this.eve.getAddressString()); + + this.signers = [this.alice, this.bob, this.eve]; + + this.requestDatas = await Promise.all( + this.signers.map(async ({ address }) => ({ + ...this.requestData, + from: address, + nonce: (await this.forwarder.nonces(address)).toString(), + value: web3.utils.toWei('10', 'gwei'), + })), + ); + + this.requestDatas = this.requestDatas.map((requestData, i) => ({ + ...requestData, + signature: this.sign(this.signers[i].getPrivateKey(), requestData), + })); + + this.msgValue = batchValue(this.requestDatas); + + this.gasUntil = async reqIdx => { + const gas = 0; + const estimations = await Promise.all( + new Array(reqIdx + 1).fill().map((_, idx) => this.estimateRequest(this.requestDatas[idx])), + ); + return estimations.reduce((acc, estimation) => acc + estimation, gas); + }; + }); + + context('with valid requests', function () { + beforeEach(async function () { + for (const request of this.requestDatas) { + expect(await this.forwarder.verify(request)).to.be.equal(true); + } + + this.receipt = await this.forwarder.executeBatch(this.requestDatas, another, { value: this.msgValue }); + }); + + it('emits events', async function () { + for (const request of this.requestDatas) { + await expectEvent.inTransaction(this.receipt.tx, this.receiver, 'MockFunctionCalled'); + await expectEvent.inTransaction(this.receipt.tx, this.forwarder, 'ExecutedForwardRequest', { + signer: request.from, + nonce: web3.utils.toBN(request.nonce), + success: true, + }); + } + }); + + it('increase nonces', async function () { + for (const request of this.requestDatas) { + expect(await this.forwarder.nonces(request.from)).to.be.bignumber.eq(web3.utils.toBN(request.nonce + 1)); + } + }); + }); + + context('with tampered requests', function () { + beforeEach(async function () { + this.idx = 1; // Tampered idx + }); + + it('reverts with mismatched value', async function () { + this.requestDatas[this.idx].value = 100; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, another, { value: this.msgValue }), + 'ERC2771ForwarderMismatchedValue', + [batchValue(this.requestDatas), this.msgValue], + ); + }); + + context('when the refund receiver is the zero address', function () { + beforeEach(function () { + this.refundReceiver = constants.ZERO_ADDRESS; + }); + + for (const [key, value] of Object.entries(tamperedValues)) { + it(`reverts with at least one tampered request ${key}`, async function () { + const data = this.forgeData({ ...this.requestDatas[this.idx], [key]: value }); + + this.requestDatas[this.idx] = data.message; + + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ data, sig: this.requestDatas[this.idx].signature }), + data.message.from, + ], + ); + }); + } + + it('reverts with at least one untrustful to', async function () { + const data = this.forgeData({ ...this.requestDatas[this.idx], to: another }); + + this.requestDatas[this.idx] = data.message; + + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771UntrustfulTarget', + [this.requestDatas[this.idx].to, this.forwarder.address], + ); + }); + + it('reverts with at least one tampered request signature', async function () { + const tamperedSig = web3.utils.hexToBytes(this.requestDatas[this.idx].signature); + tamperedSig[42] ^= 0xff; + + this.requestDatas[this.idx].signature = web3.utils.bytesToHex(tamperedSig); + + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData(this.requestDatas[this.idx]), + sig: this.requestDatas[this.idx].signature, + }), + this.requestDatas[this.idx].from, + ], + ); + }); + + it('reverts with at least one valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestDatas[this.idx], { value: this.requestDatas[this.idx].value }); + + // And then fail due to an already used nonce + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderInvalidSigner', + [ + ethSigUtil.recoverTypedSignature({ + data: this.forgeData({ ...this.requestDatas[this.idx], nonce: this.requestDatas[this.idx].nonce + 1 }), + sig: this.requestDatas[this.idx].signature, + }), + this.requestDatas[this.idx].from, + ], + ); + }); + + it('reverts with at least one valid signature for expired deadline', async function () { + this.requestDatas[this.idx].deadline = this.timestamp.toNumber() - 1; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + await expectRevertCustomError( + this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { value: this.msgValue }), + 'ERC2771ForwarderExpiredRequest', + [this.timestamp.toNumber() - 1], + ); + }); + }); + + context('when the refund receiver is a known address', function () { + beforeEach(async function () { + this.refundReceiver = refundReceiver; + this.initialRefundReceiverBalance = web3.utils.toBN(await web3.eth.getBalance(this.refundReceiver)); + this.initialTamperedRequestNonce = await this.forwarder.nonces(this.requestDatas[this.idx].from); + }); + + for (const [key, value] of Object.entries(tamperedValues)) { + it(`ignores a request with tampered ${key} and refunds its value`, async function () { + const data = this.forgeData({ ...this.requestDatas[this.idx], [key]: value }); + + this.requestDatas[this.idx] = data.message; + + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: batchValue(this.requestDatas), + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + } + + it('ignores a request with a valid signature for non-current nonce', async function () { + // Execute first a request + await this.forwarder.execute(this.requestDatas[this.idx], { value: this.requestDatas[this.idx].value }); + this.initialTamperedRequestNonce++; // Should be already incremented by the individual `execute` + + // And then ignore the same request in a batch due to an already used nonce + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: this.msgValue, + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + + it('ignores a request with a valid signature for expired deadline', async function () { + this.requestDatas[this.idx].deadline = this.timestamp.toNumber() - 1; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + + const receipt = await this.forwarder.executeBatch(this.requestDatas, this.refundReceiver, { + value: this.msgValue, + }); + expect(receipt.logs.filter(({ event }) => event === 'ExecutedForwardRequest').length).to.be.equal(2); + }); + + afterEach(async function () { + // The invalid request value was refunded + expect(await web3.eth.getBalance(this.refundReceiver)).to.be.bignumber.equal( + this.initialRefundReceiverBalance.add(web3.utils.toBN(this.requestDatas[this.idx].value)), + ); + + // The invalid request from's nonce was not incremented + expect(await this.forwarder.nonces(this.requestDatas[this.idx].from)).to.be.bignumber.eq( + web3.utils.toBN(this.initialTamperedRequestNonce), + ); + }); + }); + + it('bubbles out of gas', async function () { + this.requestDatas[this.idx].data = this.receiver.contract.methods.mockFunctionOutOfGas().encodeABI(); + this.requestDatas[this.idx].gas = 1_000_000; + this.requestDatas[this.idx].signature = this.sign( + this.signers[this.idx].getPrivateKey(), + this.requestDatas[this.idx], + ); + + const gasAvailable = 300_000; + await expectRevert.assertion( + this.forwarder.executeBatch(this.requestDatas, constants.ZERO_ADDRESS, { + gas: gasAvailable, + value: this.requestDatas.reduce((acc, { value }) => acc + Number(value), 0), + }), + ); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + expect(gasUsed).to.be.equal(gasAvailable); + }); + + it('bubbles out of gas forced by the relayer', async function () { + // Similarly to the single execute, a malicious relayer could grief requests. + + // We estimate until the selected request as if they were executed normally + const estimate = await this.gasUntil(this.requestDatas, this.idx); + + // We add a Buffer to account for all the gas that's used before the selected call. + // Note is slightly bigger because the selected request is not the index 0 and it affects + // the buffer needed. + const gasAvailable = estimate + 10_000; + + // The subcall out of gas should be caught by the contract and then bubbled up consuming + // the available gas with an `invalid` opcode. + await expectRevert.outOfGas( + this.forwarder.executeBatch(this.requestDatas, constants.ZERO_ADDRESS, { gas: gasAvailable }), + ); + + const { transactions } = await web3.eth.getBlock('latest'); + const { gasUsed } = await web3.eth.getTransactionReceipt(transactions[0]); + + // We assert that indeed the gas was totally consumed. + expect(gasUsed).to.be.equal(gasAvailable); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js b/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js new file mode 100644 index 0000000..b5fd3c5 --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/Clones.behaviour.js @@ -0,0 +1,136 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const DummyImplementation = artifacts.require('DummyImplementation'); + +module.exports = function shouldBehaveLikeClone(createClone) { + before('deploy implementation', async function () { + this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('initializes the proxy', async function () { + const dummy = new DummyImplementation(this.proxy); + expect(await dummy.value()).to.be.bignumber.equal(value.toString()); + }); + + it('has expected balance', async function () { + expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString()); + }); + }; + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createClone(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100; + const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods + .initializeNonPayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createClone(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42; + const initializeData = new DummyImplementation('').contract.methods + .initializePayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createClone(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); +}; diff --git a/lib/openzeppelin-contracts/test/proxy/Clones.test.js b/lib/openzeppelin-contracts/test/proxy/Clones.test.js new file mode 100644 index 0000000..0862778 --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/Clones.test.js @@ -0,0 +1,62 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { computeCreate2Address } = require('../helpers/create'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const shouldBehaveLikeClone = require('./Clones.behaviour'); + +const Clones = artifacts.require('$Clones'); + +contract('Clones', function (accounts) { + const [deployer] = accounts; + + describe('clone', function () { + shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { + const factory = await Clones.new(); + const receipt = await factory.$clone(implementation); + const address = receipt.logs.find(({ event }) => event === 'return$clone').args.instance; + await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); + return { address }; + }); + }); + + describe('cloneDeterministic', function () { + shouldBehaveLikeClone(async (implementation, initData, opts = {}) => { + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + const receipt = await factory.$cloneDeterministic(implementation, salt); + const address = receipt.logs.find(({ event }) => event === 'return$cloneDeterministic').args.instance; + await web3.eth.sendTransaction({ from: deployer, to: address, value: opts.value, data: initData }); + return { address }; + }); + + it('address already used', async function () { + const implementation = web3.utils.randomHex(20); + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + // deploy once + expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic'); + // deploy twice + await expectRevertCustomError(factory.$cloneDeterministic(implementation, salt), 'ERC1167FailedCreateClone', []); + }); + + it('address prediction', async function () { + const implementation = web3.utils.randomHex(20); + const salt = web3.utils.randomHex(32); + const factory = await Clones.new(); + const predicted = await factory.$predictDeterministicAddress(implementation, salt); + + const creationCode = [ + '0x3d602d80600a3d3981f3363d3d373d3d3d363d73', + implementation.replace(/0x/, '').toLowerCase(), + '5af43d82803e903d91602b57fd5bf3', + ].join(''); + + expect(computeCreate2Address(salt, creationCode, factory.address)).to.be.equal(predicted); + + expectEvent(await factory.$cloneDeterministic(implementation, salt), 'return$cloneDeterministic', { + instance: predicted, + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js b/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js new file mode 100644 index 0000000..81cc435 --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Proxy.test.js @@ -0,0 +1,12 @@ +const shouldBehaveLikeProxy = require('../Proxy.behaviour'); + +const ERC1967Proxy = artifacts.require('ERC1967Proxy'); + +contract('ERC1967Proxy', function (accounts) { + // `undefined`, `null` and other false-ish opts will not be forwarded. + const createProxy = async function (implementation, initData, opts) { + return ERC1967Proxy.new(implementation, initData, ...[opts].filter(Boolean)); + }; + + shouldBehaveLikeProxy(createProxy, accounts); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js b/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js new file mode 100644 index 0000000..975b08d --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/ERC1967/ERC1967Utils.test.js @@ -0,0 +1,172 @@ +const { expectEvent, constants } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { getAddressInSlot, setSlot, ImplementationSlot, AdminSlot, BeaconSlot } = require('../../helpers/erc1967'); + +const { ZERO_ADDRESS } = constants; + +const ERC1967Utils = artifacts.require('$ERC1967Utils'); + +const V1 = artifacts.require('DummyImplementation'); +const V2 = artifacts.require('CallReceiverMock'); +const UpgradeableBeaconMock = artifacts.require('UpgradeableBeaconMock'); +const UpgradeableBeaconReentrantMock = artifacts.require('UpgradeableBeaconReentrantMock'); + +contract('ERC1967Utils', function (accounts) { + const [, admin, anotherAccount] = accounts; + const EMPTY_DATA = '0x'; + + beforeEach('setup', async function () { + this.utils = await ERC1967Utils.new(); + this.v1 = await V1.new(); + this.v2 = await V2.new(); + }); + + describe('IMPLEMENTATION_SLOT', function () { + beforeEach('set v1 implementation', async function () { + await setSlot(this.utils, ImplementationSlot, this.v1.address); + }); + + describe('getImplementation', function () { + it('returns current implementation and matches implementation slot value', async function () { + expect(await this.utils.$getImplementation()).to.equal(this.v1.address); + expect(await getAddressInSlot(this.utils.address, ImplementationSlot)).to.equal(this.v1.address); + }); + }); + + describe('upgradeToAndCall', function () { + it('sets implementation in storage and emits event', async function () { + const newImplementation = this.v2.address; + const receipt = await this.utils.$upgradeToAndCall(newImplementation, EMPTY_DATA); + + expect(await getAddressInSlot(this.utils.address, ImplementationSlot)).to.equal(newImplementation); + expectEvent(receipt, 'Upgraded', { implementation: newImplementation }); + }); + + it('reverts when implementation does not contain code', async function () { + await expectRevertCustomError( + this.utils.$upgradeToAndCall(anotherAccount, EMPTY_DATA), + 'ERC1967InvalidImplementation', + [anotherAccount], + ); + }); + + describe('when data is empty', function () { + it('reverts when value is sent', async function () { + await expectRevertCustomError( + this.utils.$upgradeToAndCall(this.v2.address, EMPTY_DATA, { value: 1 }), + 'ERC1967NonPayable', + [], + ); + }); + }); + + describe('when data is not empty', function () { + it('delegates a call to the new implementation', async function () { + const initializeData = this.v2.contract.methods.mockFunction().encodeABI(); + const receipt = await this.utils.$upgradeToAndCall(this.v2.address, initializeData); + await expectEvent.inTransaction(receipt.tx, await V2.at(this.utils.address), 'MockFunctionCalled'); + }); + }); + }); + }); + + describe('ADMIN_SLOT', function () { + beforeEach('set admin', async function () { + await setSlot(this.utils, AdminSlot, admin); + }); + + describe('getAdmin', function () { + it('returns current admin and matches admin slot value', async function () { + expect(await this.utils.$getAdmin()).to.equal(admin); + expect(await getAddressInSlot(this.utils.address, AdminSlot)).to.equal(admin); + }); + }); + + describe('changeAdmin', function () { + it('sets admin in storage and emits event', async function () { + const newAdmin = anotherAccount; + const receipt = await this.utils.$changeAdmin(newAdmin); + + expect(await getAddressInSlot(this.utils.address, AdminSlot)).to.equal(newAdmin); + expectEvent(receipt, 'AdminChanged', { previousAdmin: admin, newAdmin: newAdmin }); + }); + + it('reverts when setting the address zero as admin', async function () { + await expectRevertCustomError(this.utils.$changeAdmin(ZERO_ADDRESS), 'ERC1967InvalidAdmin', [ZERO_ADDRESS]); + }); + }); + }); + + describe('BEACON_SLOT', function () { + beforeEach('set beacon', async function () { + this.beacon = await UpgradeableBeaconMock.new(this.v1.address); + await setSlot(this.utils, BeaconSlot, this.beacon.address); + }); + + describe('getBeacon', function () { + it('returns current beacon and matches beacon slot value', async function () { + expect(await this.utils.$getBeacon()).to.equal(this.beacon.address); + expect(await getAddressInSlot(this.utils.address, BeaconSlot)).to.equal(this.beacon.address); + }); + }); + + describe('upgradeBeaconToAndCall', function () { + it('sets beacon in storage and emits event', async function () { + const newBeacon = await UpgradeableBeaconMock.new(this.v2.address); + const receipt = await this.utils.$upgradeBeaconToAndCall(newBeacon.address, EMPTY_DATA); + + expect(await getAddressInSlot(this.utils.address, BeaconSlot)).to.equal(newBeacon.address); + expectEvent(receipt, 'BeaconUpgraded', { beacon: newBeacon.address }); + }); + + it('reverts when beacon does not contain code', async function () { + await expectRevertCustomError( + this.utils.$upgradeBeaconToAndCall(anotherAccount, EMPTY_DATA), + 'ERC1967InvalidBeacon', + [anotherAccount], + ); + }); + + it("reverts when beacon's implementation does not contain code", async function () { + const newBeacon = await UpgradeableBeaconMock.new(anotherAccount); + + await expectRevertCustomError( + this.utils.$upgradeBeaconToAndCall(newBeacon.address, EMPTY_DATA), + 'ERC1967InvalidImplementation', + [anotherAccount], + ); + }); + + describe('when data is empty', function () { + it('reverts when value is sent', async function () { + const newBeacon = await UpgradeableBeaconMock.new(this.v2.address); + await expectRevertCustomError( + this.utils.$upgradeBeaconToAndCall(newBeacon.address, EMPTY_DATA, { value: 1 }), + 'ERC1967NonPayable', + [], + ); + }); + }); + + describe('when data is not empty', function () { + it('delegates a call to the new implementation', async function () { + const initializeData = this.v2.contract.methods.mockFunction().encodeABI(); + const newBeacon = await UpgradeableBeaconMock.new(this.v2.address); + const receipt = await this.utils.$upgradeBeaconToAndCall(newBeacon.address, initializeData); + await expectEvent.inTransaction(receipt.tx, await V2.at(this.utils.address), 'MockFunctionCalled'); + }); + }); + + describe('reentrant beacon implementation() call', function () { + it('sees the new beacon implementation', async function () { + const newBeacon = await UpgradeableBeaconReentrantMock.new(); + await expectRevertCustomError( + this.utils.$upgradeBeaconToAndCall(newBeacon.address, '0x'), + 'BeaconProxyBeaconSlotAddress', + [newBeacon.address], + ); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js b/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js new file mode 100644 index 0000000..acce6d1 --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/Proxy.behaviour.js @@ -0,0 +1,182 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { getSlot, ImplementationSlot } = require('../helpers/erc1967'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const DummyImplementation = artifacts.require('DummyImplementation'); + +module.exports = function shouldBehaveLikeProxy(createProxy, accounts) { + it('cannot be initialized with a non-contract address', async function () { + const nonContractAddress = accounts[0]; + const initializeData = Buffer.from(''); + await expectRevert.unspecified(createProxy(nonContractAddress, initializeData)); + }); + + before('deploy implementation', async function () { + this.implementation = web3.utils.toChecksumAddress((await DummyImplementation.new()).address); + }); + + const assertProxyInitialization = function ({ value, balance }) { + it('sets the implementation address', async function () { + const implementationSlot = await getSlot(this.proxy, ImplementationSlot); + const implementationAddress = web3.utils.toChecksumAddress(implementationSlot.substr(-40)); + expect(implementationAddress).to.be.equal(this.implementation); + }); + + it('initializes the proxy', async function () { + const dummy = new DummyImplementation(this.proxy); + expect(await dummy.value()).to.be.bignumber.equal(value.toString()); + }); + + it('has expected balance', async function () { + expect(await web3.eth.getBalance(this.proxy)).to.be.bignumber.equal(balance.toString()); + }); + }; + + describe('without initialization', function () { + const initializeData = Buffer.from(''); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ value: 0, balance: 0 }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevertCustomError( + createProxy(this.implementation, initializeData, { value }), + 'ERC1967NonPayable', + [], + ); + }); + }); + }); + + describe('initialization without parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods['initializeNonPayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createProxy(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 100; + const initializeData = new DummyImplementation('').contract.methods['initializePayable()']().encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + }); + + describe('initialization with parameters', function () { + describe('non payable', function () { + const expectedInitializedValue = 10; + const initializeData = new DummyImplementation('').contract.methods + .initializeNonPayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + it('reverts', async function () { + await expectRevert.unspecified(createProxy(this.implementation, initializeData, { value })); + }); + }); + }); + + describe('payable', function () { + const expectedInitializedValue = 42; + const initializeData = new DummyImplementation('').contract.methods + .initializePayableWithValue(expectedInitializedValue) + .encodeABI(); + + describe('when not sending balance', function () { + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData)).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: 0, + }); + }); + + describe('when sending some balance', function () { + const value = 10e5; + + beforeEach('creating proxy', async function () { + this.proxy = (await createProxy(this.implementation, initializeData, { value })).address; + }); + + assertProxyInitialization({ + value: expectedInitializedValue, + balance: value, + }); + }); + }); + + describe('reverting initialization', function () { + const initializeData = new DummyImplementation('').contract.methods.reverts().encodeABI(); + + it('reverts', async function () { + await expectRevert(createProxy(this.implementation, initializeData), 'DummyImplementation reverted'); + }); + }); + }); +}; diff --git a/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js b/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js new file mode 100644 index 0000000..d583d0f --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/beacon/BeaconProxy.test.js @@ -0,0 +1,152 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { getSlot, BeaconSlot } = require('../../helpers/erc1967'); + +const { expectRevertCustomError } = require('../../helpers/customError'); + +const { expect } = require('chai'); + +const UpgradeableBeacon = artifacts.require('UpgradeableBeacon'); +const BeaconProxy = artifacts.require('BeaconProxy'); +const DummyImplementation = artifacts.require('DummyImplementation'); +const DummyImplementationV2 = artifacts.require('DummyImplementationV2'); +const BadBeaconNoImpl = artifacts.require('BadBeaconNoImpl'); +const BadBeaconNotContract = artifacts.require('BadBeaconNotContract'); + +contract('BeaconProxy', function (accounts) { + const [upgradeableBeaconAdmin, anotherAccount] = accounts; + + describe('bad beacon is not accepted', async function () { + it('non-contract beacon', async function () { + await expectRevertCustomError(BeaconProxy.new(anotherAccount, '0x'), 'ERC1967InvalidBeacon', [anotherAccount]); + }); + + it('non-compliant beacon', async function () { + const beacon = await BadBeaconNoImpl.new(); + await expectRevert.unspecified(BeaconProxy.new(beacon.address, '0x')); + }); + + it('non-contract implementation', async function () { + const beacon = await BadBeaconNotContract.new(); + const implementation = await beacon.implementation(); + await expectRevertCustomError(BeaconProxy.new(beacon.address, '0x'), 'ERC1967InvalidImplementation', [ + implementation, + ]); + }); + }); + + before('deploy implementation', async function () { + this.implementationV0 = await DummyImplementation.new(); + this.implementationV1 = await DummyImplementationV2.new(); + }); + + describe('initialization', function () { + before(function () { + this.assertInitialized = async ({ value, balance }) => { + const beaconSlot = await getSlot(this.proxy, BeaconSlot); + const beaconAddress = web3.utils.toChecksumAddress(beaconSlot.substr(-40)); + expect(beaconAddress).to.equal(this.beacon.address); + + const dummy = new DummyImplementation(this.proxy.address); + expect(await dummy.value()).to.bignumber.eq(value); + + expect(await web3.eth.getBalance(this.proxy.address)).to.bignumber.eq(balance); + }; + }); + + beforeEach('deploy beacon', async function () { + this.beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin); + }); + + it('no initialization', async function () { + const data = Buffer.from(''); + this.proxy = await BeaconProxy.new(this.beacon.address, data); + await this.assertInitialized({ value: '0', balance: '0' }); + }); + + it('non-payable initialization', async function () { + const value = '55'; + const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); + this.proxy = await BeaconProxy.new(this.beacon.address, data); + await this.assertInitialized({ value, balance: '0' }); + }); + + it('payable initialization', async function () { + const value = '55'; + const data = this.implementationV0.contract.methods.initializePayableWithValue(value).encodeABI(); + const balance = '100'; + this.proxy = await BeaconProxy.new(this.beacon.address, data, { value: balance }); + await this.assertInitialized({ value, balance }); + }); + + it('reverting initialization due to value', async function () { + const data = Buffer.from(''); + await expectRevertCustomError( + BeaconProxy.new(this.beacon.address, data, { value: '1' }), + 'ERC1967NonPayable', + [], + ); + }); + + it('reverting initialization function', async function () { + const data = this.implementationV0.contract.methods.reverts().encodeABI(); + await expectRevert(BeaconProxy.new(this.beacon.address, data), 'DummyImplementation reverted'); + }); + }); + + it('upgrade a proxy by upgrading its beacon', async function () { + const beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin); + + const value = '10'; + const data = this.implementationV0.contract.methods.initializeNonPayableWithValue(value).encodeABI(); + const proxy = await BeaconProxy.new(beacon.address, data); + + const dummy = new DummyImplementation(proxy.address); + + // test initial values + expect(await dummy.value()).to.bignumber.eq(value); + + // test initial version + expect(await dummy.version()).to.eq('V1'); + + // upgrade beacon + await beacon.upgradeTo(this.implementationV1.address, { from: upgradeableBeaconAdmin }); + + // test upgraded version + expect(await dummy.version()).to.eq('V2'); + }); + + it('upgrade 2 proxies by upgrading shared beacon', async function () { + const value1 = '10'; + const value2 = '42'; + + const beacon = await UpgradeableBeacon.new(this.implementationV0.address, upgradeableBeaconAdmin); + + const proxy1InitializeData = this.implementationV0.contract.methods + .initializeNonPayableWithValue(value1) + .encodeABI(); + const proxy1 = await BeaconProxy.new(beacon.address, proxy1InitializeData); + + const proxy2InitializeData = this.implementationV0.contract.methods + .initializeNonPayableWithValue(value2) + .encodeABI(); + const proxy2 = await BeaconProxy.new(beacon.address, proxy2InitializeData); + + const dummy1 = new DummyImplementation(proxy1.address); + const dummy2 = new DummyImplementation(proxy2.address); + + // test initial values + expect(await dummy1.value()).to.bignumber.eq(value1); + expect(await dummy2.value()).to.bignumber.eq(value2); + + // test initial version + expect(await dummy1.version()).to.eq('V1'); + expect(await dummy2.version()).to.eq('V1'); + + // upgrade beacon + await beacon.upgradeTo(this.implementationV1.address, { from: upgradeableBeaconAdmin }); + + // test upgraded version + expect(await dummy1.version()).to.eq('V2'); + expect(await dummy2.version()).to.eq('V2'); + }); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js b/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js new file mode 100644 index 0000000..0737f6f --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/beacon/UpgradeableBeacon.test.js @@ -0,0 +1,54 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../../helpers/customError'); + +const UpgradeableBeacon = artifacts.require('UpgradeableBeacon'); +const Implementation1 = artifacts.require('Implementation1'); +const Implementation2 = artifacts.require('Implementation2'); + +contract('UpgradeableBeacon', function (accounts) { + const [owner, other] = accounts; + + it('cannot be created with non-contract implementation', async function () { + await expectRevertCustomError(UpgradeableBeacon.new(other, owner), 'BeaconInvalidImplementation', [other]); + }); + + context('once deployed', async function () { + beforeEach('deploying beacon', async function () { + this.v1 = await Implementation1.new(); + this.beacon = await UpgradeableBeacon.new(this.v1.address, owner); + }); + + it('emits Upgraded event to the first implementation', async function () { + const beacon = await UpgradeableBeacon.new(this.v1.address, owner); + await expectEvent.inTransaction(beacon.contract.transactionHash, beacon, 'Upgraded', { + implementation: this.v1.address, + }); + }); + + it('returns implementation', async function () { + expect(await this.beacon.implementation()).to.equal(this.v1.address); + }); + + it('can be upgraded by the owner', async function () { + const v2 = await Implementation2.new(); + const receipt = await this.beacon.upgradeTo(v2.address, { from: owner }); + expectEvent(receipt, 'Upgraded', { implementation: v2.address }); + expect(await this.beacon.implementation()).to.equal(v2.address); + }); + + it('cannot be upgraded to a non-contract', async function () { + await expectRevertCustomError(this.beacon.upgradeTo(other, { from: owner }), 'BeaconInvalidImplementation', [ + other, + ]); + }); + + it('cannot be upgraded by other account', async function () { + const v2 = await Implementation2.new(); + await expectRevertCustomError(this.beacon.upgradeTo(v2.address, { from: other }), 'OwnableUnauthorizedAccount', [ + other, + ]); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js b/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js new file mode 100644 index 0000000..4d1a54f --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/transparent/ProxyAdmin.test.js @@ -0,0 +1,103 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +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'); + +const { getAddressInSlot, ImplementationSlot } = require('../../helpers/erc1967'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { computeCreateAddress } = require('../../helpers/create'); + +contract('ProxyAdmin', function (accounts) { + const [proxyAdminOwner, anotherAccount] = accounts; + + before('set implementations', async function () { + this.implementationV1 = await ImplV1.new(); + this.implementationV2 = await ImplV2.new(); + }); + + beforeEach(async function () { + const initializeData = Buffer.from(''); + const proxy = await TransparentUpgradeableProxy.new(this.implementationV1.address, proxyAdminOwner, initializeData); + + const proxyNonce = await web3.eth.getTransactionCount(proxy.address); + const proxyAdminAddress = computeCreateAddress(proxy.address, proxyNonce - 1); // Nonce already used + this.proxyAdmin = await ProxyAdmin.at(proxyAdminAddress); + + this.proxy = await ITransparentUpgradeableProxy.at(proxy.address); + }); + + it('has an owner', async function () { + expect(await this.proxyAdmin.owner()).to.equal(proxyAdminOwner); + }); + + it('has an interface version', async function () { + expect(await this.proxyAdmin.UPGRADE_INTERFACE_VERSION()).to.equal('5.0.0'); + }); + + describe('without data', function () { + context('with unauthorized account', function () { + it('fails to upgrade', async function () { + await expectRevertCustomError( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, '0x', { + from: anotherAccount, + }), + 'OwnableUnauthorizedAccount', + [anotherAccount], + ); + }); + }); + + context('with authorized account', function () { + it('upgrades implementation', async function () { + await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, '0x', { + from: proxyAdminOwner, + }); + + const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementationAddress).to.be.equal(this.implementationV2.address); + }); + }); + }); + + describe('with data', function () { + context('with unauthorized account', function () { + it('fails to upgrade', async function () { + const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI(); + await expectRevertCustomError( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: anotherAccount, + }), + 'OwnableUnauthorizedAccount', + [anotherAccount], + ); + }); + }); + + context('with authorized account', function () { + context('with invalid callData', function () { + it('fails to upgrade', async function () { + const callData = '0x12345678'; + await expectRevert.unspecified( + this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: proxyAdminOwner, + }), + ); + }); + }); + + context('with valid callData', function () { + it('upgrades implementation', async function () { + const callData = new ImplV1('').contract.methods.initializeNonPayableWithValue(1337).encodeABI(); + await this.proxyAdmin.upgradeAndCall(this.proxy.address, this.implementationV2.address, callData, { + from: proxyAdminOwner, + }); + const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementationAddress).to.be.equal(this.implementationV2.address); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js b/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js new file mode 100644 index 0000000..103af7f --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.behaviour.js @@ -0,0 +1,413 @@ +const { BN, expectRevert, expectEvent, constants } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; +const { getAddressInSlot, ImplementationSlot, AdminSlot } = require('../../helpers/erc1967'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const { expect } = require('chai'); +const { web3 } = require('hardhat'); +const { computeCreateAddress } = require('../../helpers/create'); +const { impersonate } = require('../../helpers/account'); + +const Implementation1 = artifacts.require('Implementation1'); +const Implementation2 = artifacts.require('Implementation2'); +const Implementation3 = artifacts.require('Implementation3'); +const Implementation4 = artifacts.require('Implementation4'); +const MigratableMockV1 = artifacts.require('MigratableMockV1'); +const MigratableMockV2 = artifacts.require('MigratableMockV2'); +const MigratableMockV3 = artifacts.require('MigratableMockV3'); +const InitializableMock = artifacts.require('InitializableMock'); +const DummyImplementation = artifacts.require('DummyImplementation'); +const ClashingImplementation = artifacts.require('ClashingImplementation'); +const Ownable = artifacts.require('Ownable'); + +module.exports = function shouldBehaveLikeTransparentUpgradeableProxy(createProxy, initialOwner, accounts) { + const [anotherAccount] = accounts; + + async function createProxyWithImpersonatedProxyAdmin(logic, initData, opts = undefined) { + const proxy = await createProxy(logic, initData, opts); + + // Expect proxy admin to be the first and only contract created by the proxy + const proxyAdminAddress = computeCreateAddress(proxy.address, 1); + await impersonate(proxyAdminAddress); + + return { + proxy, + proxyAdminAddress, + }; + } + + before(async function () { + this.implementationV0 = (await DummyImplementation.new()).address; + this.implementationV1 = (await DummyImplementation.new()).address; + }); + + beforeEach(async function () { + const initializeData = Buffer.from(''); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + this.implementationV0, + initializeData, + ); + this.proxy = proxy; + this.proxyAdminAddress = proxyAdminAddress; + }); + + describe('implementation', function () { + it('returns the current implementation address', async function () { + const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementationAddress).to.be.equal(this.implementationV0); + }); + + it('delegates to the implementation', async function () { + const dummy = new DummyImplementation(this.proxy.address); + const value = await dummy.get(); + + expect(value).to.equal(true); + }); + }); + + describe('proxy admin', function () { + it('emits AdminChanged event during construction', async function () { + await expectEvent.inConstruction(this.proxy, 'AdminChanged', { + previousAdmin: ZERO_ADDRESS, + newAdmin: this.proxyAdminAddress, + }); + }); + + it('sets the proxy admin in storage with the correct initial owner', async function () { + expect(await getAddressInSlot(this.proxy, AdminSlot)).to.be.equal(this.proxyAdminAddress); + const proxyAdmin = await Ownable.at(this.proxyAdminAddress); + expect(await proxyAdmin.owner()).to.be.equal(initialOwner); + }); + + it('can overwrite the admin by the implementation', async function () { + const dummy = new DummyImplementation(this.proxy.address); + await dummy.unsafeOverrideAdmin(anotherAccount); + const ERC1967AdminSlotValue = await getAddressInSlot(this.proxy, AdminSlot); + expect(ERC1967AdminSlotValue).to.be.equal(anotherAccount); + + // Still allows previous admin to execute admin operations + expect(ERC1967AdminSlotValue).to.not.equal(this.proxyAdminAddress); + expectEvent( + await this.proxy.upgradeToAndCall(this.implementationV1, '0x', { from: this.proxyAdminAddress }), + 'Upgraded', + { + implementation: this.implementationV1, + }, + ); + }); + }); + + describe('upgradeToAndCall', function () { + describe('without migrations', function () { + beforeEach(async function () { + this.behavior = await InitializableMock.new(); + }); + + describe('when the call does not fail', function () { + const initializeData = new InitializableMock('').contract.methods['initializeWithX(uint256)'](42).encodeABI(); + + describe('when the sender is the admin', function () { + const value = 1e5; + + beforeEach(async function () { + this.receipt = await this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { + from: this.proxyAdminAddress, + value, + }); + }); + + it('upgrades to the requested implementation', async function () { + const implementationAddress = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementationAddress).to.be.equal(this.behavior.address); + }); + + it('emits an event', function () { + expectEvent(this.receipt, 'Upgraded', { implementation: this.behavior.address }); + }); + + it('calls the initializer function', async function () { + const migratable = new InitializableMock(this.proxy.address); + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + }); + + it('sends given value to the proxy', async function () { + const balance = await web3.eth.getBalance(this.proxy.address); + expect(balance.toString()).to.be.bignumber.equal(value.toString()); + }); + + it('uses the storage of the proxy', async function () { + // storage layout should look as follows: + // - 0: Initializable storage ++ initializerRan ++ onlyInitializingRan + // - 1: x + const storedValue = await web3.eth.getStorageAt(this.proxy.address, 1); + expect(parseInt(storedValue)).to.eq(42); + }); + }); + + describe('when the sender is not the admin', function () { + it('reverts', async function () { + await expectRevert.unspecified( + this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from: anotherAccount }), + ); + }); + }); + }); + + describe('when the call does fail', function () { + const initializeData = new InitializableMock('').contract.methods.fail().encodeABI(); + + it('reverts', async function () { + await expectRevert.unspecified( + this.proxy.upgradeToAndCall(this.behavior.address, initializeData, { from: this.proxyAdminAddress }), + ); + }); + }); + }); + + describe('with migrations', function () { + describe('when the sender is the admin', function () { + const value = 1e5; + + describe('when upgrading to V1', function () { + const v1MigrationData = new MigratableMockV1('').contract.methods.initialize(42).encodeABI(); + + beforeEach(async function () { + this.behaviorV1 = await MigratableMockV1.new(); + this.balancePreviousV1 = new BN(await web3.eth.getBalance(this.proxy.address)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV1.address, v1MigrationData, { + from: this.proxyAdminAddress, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementation).to.be.equal(this.behaviorV1.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV1.address }); + }); + + it("calls the 'initialize' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV1(this.proxy.address); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + + const balance = await web3.eth.getBalance(this.proxy.address); + expect(new BN(balance)).to.be.bignumber.equal(this.balancePreviousV1.addn(value)); + }); + + describe('when upgrading to V2', function () { + const v2MigrationData = new MigratableMockV2('').contract.methods.migrate(10, 42).encodeABI(); + + beforeEach(async function () { + this.behaviorV2 = await MigratableMockV2.new(); + this.balancePreviousV2 = new BN(await web3.eth.getBalance(this.proxy.address)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV2.address, v2MigrationData, { + from: this.proxyAdminAddress, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementation).to.be.equal(this.behaviorV2.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV2.address }); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV2(this.proxy.address); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('10'); + + const y = await migratable.y(); + expect(y).to.be.bignumber.equal('42'); + + const balance = new BN(await web3.eth.getBalance(this.proxy.address)); + expect(balance).to.be.bignumber.equal(this.balancePreviousV2.addn(value)); + }); + + describe('when upgrading to V3', function () { + const v3MigrationData = new MigratableMockV3('').contract.methods['migrate()']().encodeABI(); + + beforeEach(async function () { + this.behaviorV3 = await MigratableMockV3.new(); + this.balancePreviousV3 = new BN(await web3.eth.getBalance(this.proxy.address)); + this.receipt = await this.proxy.upgradeToAndCall(this.behaviorV3.address, v3MigrationData, { + from: this.proxyAdminAddress, + value, + }); + }); + + it('upgrades to the requested version and emits an event', async function () { + const implementation = await getAddressInSlot(this.proxy, ImplementationSlot); + expect(implementation).to.be.equal(this.behaviorV3.address); + expectEvent(this.receipt, 'Upgraded', { implementation: this.behaviorV3.address }); + }); + + it("calls the 'migrate' function and sends given value to the proxy", async function () { + const migratable = new MigratableMockV3(this.proxy.address); + + const x = await migratable.x(); + expect(x).to.be.bignumber.equal('42'); + + const y = await migratable.y(); + expect(y).to.be.bignumber.equal('10'); + + const balance = new BN(await web3.eth.getBalance(this.proxy.address)); + expect(balance).to.be.bignumber.equal(this.balancePreviousV3.addn(value)); + }); + }); + }); + }); + }); + + describe('when the sender is not the admin', function () { + const from = anotherAccount; + + it('reverts', async function () { + const behaviorV1 = await MigratableMockV1.new(); + const v1MigrationData = new MigratableMockV1('').contract.methods.initialize(42).encodeABI(); + await expectRevert.unspecified(this.proxy.upgradeToAndCall(behaviorV1.address, v1MigrationData, { from })); + }); + }); + }); + }); + + describe('transparent proxy', function () { + beforeEach('creating proxy', async function () { + const initializeData = Buffer.from(''); + this.clashingImplV0 = (await ClashingImplementation.new()).address; + this.clashingImplV1 = (await ClashingImplementation.new()).address; + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + this.clashingImplV0, + initializeData, + ); + this.proxy = proxy; + this.proxyAdminAddress = proxyAdminAddress; + this.clashing = new ClashingImplementation(this.proxy.address); + }); + + it('proxy admin cannot call delegated functions', async function () { + await expectRevertCustomError( + this.clashing.delegatedFunction({ from: this.proxyAdminAddress }), + 'ProxyDeniedAdminAccess', + [], + ); + }); + + describe('when function names clash', function () { + it('executes the proxy function if the sender is the admin', async function () { + const receipt = await this.proxy.upgradeToAndCall(this.clashingImplV1, '0x', { + from: this.proxyAdminAddress, + }); + expectEvent(receipt, 'Upgraded', { implementation: this.clashingImplV1 }); + }); + + it('delegates the call to implementation when sender is not the admin', async function () { + const receipt = await this.proxy.upgradeToAndCall(this.clashingImplV1, '0x', { + from: anotherAccount, + }); + expectEvent.notEmitted(receipt, 'Upgraded'); + expectEvent.inTransaction(receipt.tx, this.clashing, 'ClashingImplementationCall'); + }); + }); + }); + + describe('regression', () => { + const initializeData = Buffer.from(''); + + it('should add new function', async () => { + const instance1 = await Implementation1.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance1.address, + initializeData, + ); + + const proxyInstance1 = new Implementation1(proxy.address); + await proxyInstance1.setValue(42); + + const instance2 = await Implementation2.new(); + await proxy.upgradeToAndCall(instance2.address, '0x', { from: proxyAdminAddress }); + + const proxyInstance2 = new Implementation2(proxy.address); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('42'); + }); + + it('should remove function', async () => { + const instance2 = await Implementation2.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance2.address, + initializeData, + ); + + const proxyInstance2 = new Implementation2(proxy.address); + await proxyInstance2.setValue(42); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('42'); + + const instance1 = await Implementation1.new(); + await proxy.upgradeToAndCall(instance1.address, '0x', { from: proxyAdminAddress }); + + const proxyInstance1 = new Implementation2(proxy.address); + await expectRevert.unspecified(proxyInstance1.getValue()); + }); + + it('should change function signature', async () => { + const instance1 = await Implementation1.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance1.address, + initializeData, + ); + + const proxyInstance1 = new Implementation1(proxy.address); + await proxyInstance1.setValue(42); + + const instance3 = await Implementation3.new(); + await proxy.upgradeToAndCall(instance3.address, '0x', { from: proxyAdminAddress }); + const proxyInstance3 = new Implementation3(proxy.address); + + const res = await proxyInstance3.getValue(8); + expect(res.toString()).to.eq('50'); + }); + + it('should add fallback function', async () => { + const initializeData = Buffer.from(''); + const instance1 = await Implementation1.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance1.address, + initializeData, + ); + + const instance4 = await Implementation4.new(); + await proxy.upgradeToAndCall(instance4.address, '0x', { from: proxyAdminAddress }); + const proxyInstance4 = new Implementation4(proxy.address); + + const data = '0x'; + await web3.eth.sendTransaction({ to: proxy.address, from: anotherAccount, data }); + + const res = await proxyInstance4.getValue(); + expect(res.toString()).to.eq('1'); + }); + + it('should remove fallback function', async () => { + const instance4 = await Implementation4.new(); + const { proxy, proxyAdminAddress } = await createProxyWithImpersonatedProxyAdmin( + instance4.address, + initializeData, + ); + + const instance2 = await Implementation2.new(); + await proxy.upgradeToAndCall(instance2.address, '0x', { from: proxyAdminAddress }); + + const data = '0x'; + await expectRevert.unspecified(web3.eth.sendTransaction({ to: proxy.address, from: anotherAccount, data })); + + const proxyInstance2 = new Implementation2(proxy.address); + const res = await proxyInstance2.getValue(); + expect(res.toString()).to.eq('0'); + }); + }); +}; diff --git a/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js b/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js new file mode 100644 index 0000000..f45e392 --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/transparent/TransparentUpgradeableProxy.test.js @@ -0,0 +1,24 @@ +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 [owner, ...otherAccounts] = accounts; + + // `undefined`, `null` and other false-ish opts will not be forwarded. + const createProxy = async function (logic, initData, opts = undefined) { + const { address, transactionHash } = await TransparentUpgradeableProxy.new( + logic, + owner, + initData, + ...[opts].filter(Boolean), + ); + const instance = await ITransparentUpgradeableProxy.at(address); + return { ...instance, transactionHash }; + }; + + shouldBehaveLikeProxy(createProxy, otherAccounts); + shouldBehaveLikeTransparentUpgradeableProxy(createProxy, owner, otherAccounts); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js b/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js new file mode 100644 index 0000000..b9ff3b0 --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/utils/Initializable.test.js @@ -0,0 +1,220 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { MAX_UINT64 } = require('../../helpers/constants'); + +const InitializableMock = artifacts.require('InitializableMock'); +const ConstructorInitializableMock = artifacts.require('ConstructorInitializableMock'); +const ChildConstructorInitializableMock = artifacts.require('ChildConstructorInitializableMock'); +const ReinitializerMock = artifacts.require('ReinitializerMock'); +const SampleChild = artifacts.require('SampleChild'); +const DisableBad1 = artifacts.require('DisableBad1'); +const DisableBad2 = artifacts.require('DisableBad2'); +const DisableOk = artifacts.require('DisableOk'); + +contract('Initializable', function () { + describe('basic testing without inheritance', function () { + beforeEach('deploying', async function () { + this.contract = await InitializableMock.new(); + }); + + describe('before initialize', function () { + it('initializer has not run', async function () { + expect(await this.contract.initializerRan()).to.equal(false); + }); + + it('_initializing returns false before initialization', async function () { + expect(await this.contract.isInitializing()).to.equal(false); + }); + }); + + describe('after initialize', function () { + beforeEach('initializing', async function () { + await this.contract.initialize(); + }); + + it('initializer has run', async function () { + expect(await this.contract.initializerRan()).to.equal(true); + }); + + it('_initializing returns false after initialization', async function () { + expect(await this.contract.isInitializing()).to.equal(false); + }); + + it('initializer does not run again', async function () { + await expectRevertCustomError(this.contract.initialize(), 'InvalidInitialization', []); + }); + }); + + describe('nested under an initializer', function () { + it('initializer modifier reverts', async function () { + await expectRevertCustomError(this.contract.initializerNested(), 'InvalidInitialization', []); + }); + + it('onlyInitializing modifier succeeds', async function () { + await this.contract.onlyInitializingNested(); + expect(await this.contract.onlyInitializingRan()).to.equal(true); + }); + }); + + it('cannot call onlyInitializable function outside the scope of an initializable function', async function () { + await expectRevertCustomError(this.contract.initializeOnlyInitializing(), 'NotInitializing', []); + }); + }); + + it('nested initializer can run during construction', async function () { + const contract2 = await ConstructorInitializableMock.new(); + expect(await contract2.initializerRan()).to.equal(true); + expect(await contract2.onlyInitializingRan()).to.equal(true); + }); + + it('multiple constructor levels can be initializers', async function () { + const contract2 = await ChildConstructorInitializableMock.new(); + expect(await contract2.initializerRan()).to.equal(true); + expect(await contract2.childInitializerRan()).to.equal(true); + expect(await contract2.onlyInitializingRan()).to.equal(true); + }); + + describe('reinitialization', function () { + beforeEach('deploying', async function () { + this.contract = await ReinitializerMock.new(); + }); + + it('can reinitialize', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.initialize(); + expect(await this.contract.counter()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(2); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + await this.contract.reinitialize(3); + expect(await this.contract.counter()).to.be.bignumber.equal('3'); + }); + + it('can jump multiple steps', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.initialize(); + expect(await this.contract.counter()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(128); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + }); + + it('cannot nest reinitializers', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await expectRevertCustomError(this.contract.nestedReinitialize(2, 2), 'InvalidInitialization', []); + await expectRevertCustomError(this.contract.nestedReinitialize(2, 3), 'InvalidInitialization', []); + await expectRevertCustomError(this.contract.nestedReinitialize(3, 2), 'InvalidInitialization', []); + }); + + it('can chain reinitializers', async function () { + expect(await this.contract.counter()).to.be.bignumber.equal('0'); + await this.contract.chainReinitialize(2, 3); + expect(await this.contract.counter()).to.be.bignumber.equal('2'); + }); + + it('_getInitializedVersion returns right version', async function () { + await this.contract.initialize(); + expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('1'); + await this.contract.reinitialize(12); + expect(await this.contract.getInitializedVersion()).to.be.bignumber.equal('12'); + }); + + describe('contract locking', function () { + it('prevents initialization', async function () { + await this.contract.disableInitializers(); + await expectRevertCustomError(this.contract.initialize(), 'InvalidInitialization', []); + }); + + it('prevents re-initialization', async function () { + await this.contract.disableInitializers(); + await expectRevertCustomError(this.contract.reinitialize(255), 'InvalidInitialization', []); + }); + + it('can lock contract after initialization', async function () { + await this.contract.initialize(); + await this.contract.disableInitializers(); + await expectRevertCustomError(this.contract.reinitialize(255), 'InvalidInitialization', []); + }); + }); + }); + + describe('events', function () { + it('constructor initialization emits event', async function () { + const contract = await ConstructorInitializableMock.new(); + + await expectEvent.inTransaction(contract.transactionHash, contract, 'Initialized', { version: '1' }); + }); + + it('initialization emits event', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.initialize(); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1); + expectEvent(receipt, 'Initialized', { version: '1' }); + }); + + it('reinitialization emits event', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.reinitialize(128); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(1); + expectEvent(receipt, 'Initialized', { version: '128' }); + }); + + it('chained reinitialization emits multiple events', async function () { + const contract = await ReinitializerMock.new(); + + const { receipt } = await contract.chainReinitialize(2, 3); + expect(receipt.logs.filter(({ event }) => event === 'Initialized').length).to.be.equal(2); + expectEvent(receipt, 'Initialized', { version: '2' }); + expectEvent(receipt, 'Initialized', { version: '3' }); + }); + }); + + describe('complex testing with inheritance', function () { + const mother = '12'; + const gramps = '56'; + const father = '34'; + const child = '78'; + + beforeEach('deploying', async function () { + this.contract = await SampleChild.new(); + }); + + beforeEach('initializing', async function () { + await this.contract.initialize(mother, gramps, father, child); + }); + + it('initializes human', async function () { + expect(await this.contract.isHuman()).to.be.equal(true); + }); + + it('initializes mother', async function () { + expect(await this.contract.mother()).to.be.bignumber.equal(mother); + }); + + it('initializes gramps', async function () { + expect(await this.contract.gramps()).to.be.bignumber.equal(gramps); + }); + + it('initializes father', async function () { + expect(await this.contract.father()).to.be.bignumber.equal(father); + }); + + it('initializes child', async function () { + expect(await this.contract.child()).to.be.bignumber.equal(child); + }); + }); + + describe('disabling initialization', function () { + it('old and new patterns in bad sequence', async function () { + await expectRevertCustomError(DisableBad1.new(), 'InvalidInitialization', []); + await expectRevertCustomError(DisableBad2.new(), 'InvalidInitialization', []); + }); + + it('old and new patterns in good sequence', async function () { + const ok = await DisableOk.new(); + await expectEvent.inConstruction(ok, 'Initialized', { version: '1' }); + await expectEvent.inConstruction(ok, 'Initialized', { version: MAX_UINT64 }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js b/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js new file mode 100644 index 0000000..0baa905 --- /dev/null +++ b/lib/openzeppelin-contracts/test/proxy/utils/UUPSUpgradeable.test.js @@ -0,0 +1,131 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { getAddressInSlot, ImplementationSlot } = require('../../helpers/erc1967'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const ERC1967Proxy = artifacts.require('ERC1967Proxy'); +const UUPSUpgradeableMock = artifacts.require('UUPSUpgradeableMock'); +const UUPSUpgradeableUnsafeMock = artifacts.require('UUPSUpgradeableUnsafeMock'); +const NonUpgradeableMock = artifacts.require('NonUpgradeableMock'); +const UUPSUnsupportedProxiableUUID = artifacts.require('UUPSUnsupportedProxiableUUID'); +const Clones = artifacts.require('$Clones'); + +contract('UUPSUpgradeable', function () { + before(async function () { + this.implInitial = await UUPSUpgradeableMock.new(); + this.implUpgradeOk = await UUPSUpgradeableMock.new(); + this.implUpgradeUnsafe = await UUPSUpgradeableUnsafeMock.new(); + this.implUpgradeNonUUPS = await NonUpgradeableMock.new(); + this.implUnsupportedUUID = await UUPSUnsupportedProxiableUUID.new(); + // Used for testing non ERC1967 compliant proxies (clones are proxies that don't use the ERC1967 implementation slot) + this.cloneFactory = await Clones.new(); + }); + + beforeEach(async function () { + const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x'); + this.instance = await UUPSUpgradeableMock.at(address); + }); + + it('has an interface version', async function () { + expect(await this.instance.UPGRADE_INTERFACE_VERSION()).to.equal('5.0.0'); + }); + + it('upgrade to upgradeable implementation', async function () { + const { receipt } = await this.instance.upgradeToAndCall(this.implUpgradeOk.address, '0x'); + expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address }); + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.be.equal(this.implUpgradeOk.address); + }); + + it('upgrade to upgradeable implementation with call', async function () { + expect(await this.instance.current()).to.be.bignumber.equal('0'); + + const { receipt } = await this.instance.upgradeToAndCall( + this.implUpgradeOk.address, + this.implUpgradeOk.contract.methods.increment().encodeABI(), + ); + expect(receipt.logs.filter(({ event }) => event === 'Upgraded').length).to.be.equal(1); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeOk.address }); + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.be.equal(this.implUpgradeOk.address); + + expect(await this.instance.current()).to.be.bignumber.equal('1'); + }); + + it('calling upgradeTo on the implementation reverts', async function () { + await expectRevertCustomError( + this.implInitial.upgradeToAndCall(this.implUpgradeOk.address, '0x'), + 'UUPSUnauthorizedCallContext', + [], + ); + }); + + it('calling upgradeToAndCall on the implementation reverts', async function () { + await expectRevertCustomError( + this.implInitial.upgradeToAndCall( + this.implUpgradeOk.address, + this.implUpgradeOk.contract.methods.increment().encodeABI(), + ), + 'UUPSUnauthorizedCallContext', + [], + ); + }); + + it('calling upgradeTo from a contract that is not an ERC1967 proxy (with the right implementation) reverts', async function () { + const receipt = await this.cloneFactory.$clone(this.implUpgradeOk.address); + const instance = await UUPSUpgradeableMock.at( + receipt.logs.find(({ event }) => event === 'return$clone').args.instance, + ); + + await expectRevertCustomError( + instance.upgradeToAndCall(this.implUpgradeUnsafe.address, '0x'), + 'UUPSUnauthorizedCallContext', + [], + ); + }); + + it('calling upgradeToAndCall from a contract that is not an ERC1967 proxy (with the right implementation) reverts', async function () { + const receipt = await this.cloneFactory.$clone(this.implUpgradeOk.address); + const instance = await UUPSUpgradeableMock.at( + receipt.logs.find(({ event }) => event === 'return$clone').args.instance, + ); + + await expectRevertCustomError( + instance.upgradeToAndCall(this.implUpgradeUnsafe.address, '0x'), + 'UUPSUnauthorizedCallContext', + [], + ); + }); + + it('rejects upgrading to an unsupported UUID', async function () { + await expectRevertCustomError( + this.instance.upgradeToAndCall(this.implUnsupportedUUID.address, '0x'), + 'UUPSUnsupportedProxiableUUID', + [web3.utils.keccak256('invalid UUID')], + ); + }); + + it('upgrade to and unsafe upgradeable implementation', async function () { + const { receipt } = await this.instance.upgradeToAndCall(this.implUpgradeUnsafe.address, '0x'); + expectEvent(receipt, 'Upgraded', { implementation: this.implUpgradeUnsafe.address }); + expect(await getAddressInSlot(this.instance, ImplementationSlot)).to.be.equal(this.implUpgradeUnsafe.address); + }); + + // delegate to a non existing upgradeTo function causes a low level revert + it('reject upgrade to non uups implementation', async function () { + await expectRevertCustomError( + this.instance.upgradeToAndCall(this.implUpgradeNonUUPS.address, '0x'), + 'ERC1967InvalidImplementation', + [this.implUpgradeNonUUPS.address], + ); + }); + + it('reject proxy address as implementation', async function () { + const { address } = await ERC1967Proxy.new(this.implInitial.address, '0x'); + const otherInstance = await UUPSUpgradeableMock.at(address); + + await expectRevertCustomError( + this.instance.upgradeToAndCall(otherInstance.address, '0x'), + 'ERC1967InvalidImplementation', + [otherInstance.address], + ); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js b/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js new file mode 100644 index 0000000..8df30a8 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.behavior.js @@ -0,0 +1,905 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { Enum } = require('../../helpers/enums'); + +const ERC1155ReceiverMock = artifacts.require('ERC1155ReceiverMock'); +const RevertType = Enum('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'); + +function shouldBehaveLikeERC1155([minter, firstTokenHolder, secondTokenHolder, multiTokenHolder, recipient, proxy]) { + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); + + const firstTokenValue = new BN(1000); + const secondTokenValue = new BN(2000); + + const RECEIVER_SINGLE_MAGIC_VALUE = '0xf23a6e61'; + const RECEIVER_BATCH_MAGIC_VALUE = '0xbc197c81'; + + describe('like an ERC1155', function () { + describe('balanceOf', function () { + it('should return 0 when queried about the zero address', async function () { + expect(await this.token.balanceOf(ZERO_ADDRESS, firstTokenId)).to.be.bignumber.equal('0'); + }); + + context("when accounts don't own tokens", function () { + it('returns zero for given addresses', async function () { + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + }); + }); + + context('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstTokenValue, '0x', { + from: minter, + }); + await this.token.$_mint(secondTokenHolder, secondTokenId, secondTokenValue, '0x', { + from: minter, + }); + }); + + it('returns the amount of tokens owned by the given addresses', async function () { + expect(await this.token.balanceOf(firstTokenHolder, firstTokenId)).to.be.bignumber.equal(firstTokenValue); + + expect(await this.token.balanceOf(secondTokenHolder, secondTokenId)).to.be.bignumber.equal(secondTokenValue); + + expect(await this.token.balanceOf(firstTokenHolder, unknownTokenId)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('balanceOfBatch', function () { + it("reverts when input arrays don't match up", async function () { + const accounts1 = [firstTokenHolder, secondTokenHolder, firstTokenHolder, secondTokenHolder]; + const ids1 = [firstTokenId, secondTokenId, unknownTokenId]; + await expectRevertCustomError(this.token.balanceOfBatch(accounts1, ids1), 'ERC1155InvalidArrayLength', [ + accounts1.length, + ids1.length, + ]); + + const accounts2 = [firstTokenHolder, secondTokenHolder]; + const ids2 = [firstTokenId, secondTokenId, unknownTokenId]; + await expectRevertCustomError(this.token.balanceOfBatch(accounts2, ids2), 'ERC1155InvalidArrayLength', [ + accounts2.length, + ids2.length, + ]); + }); + + it('should return 0 as the balance when one of the addresses is the zero address', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, ZERO_ADDRESS], + [firstTokenId, secondTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal('0'); + expect(result[1]).to.be.a.bignumber.equal('0'); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + + context("when accounts don't own tokens", function () { + it('returns zeros for each account', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [firstTokenId, secondTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal('0'); + expect(result[1]).to.be.a.bignumber.equal('0'); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + }); + + context('when accounts own some tokens', function () { + beforeEach(async function () { + await this.token.$_mint(firstTokenHolder, firstTokenId, firstTokenValue, '0x', { + from: minter, + }); + await this.token.$_mint(secondTokenHolder, secondTokenId, secondTokenValue, '0x', { + from: minter, + }); + }); + + it('returns amounts owned by each account in order passed', async function () { + const result = await this.token.balanceOfBatch( + [secondTokenHolder, firstTokenHolder, firstTokenHolder], + [secondTokenId, firstTokenId, unknownTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal(secondTokenValue); + expect(result[1]).to.be.a.bignumber.equal(firstTokenValue); + expect(result[2]).to.be.a.bignumber.equal('0'); + }); + + it('returns multiple times the balance of the same address when asked', async function () { + const result = await this.token.balanceOfBatch( + [firstTokenHolder, secondTokenHolder, firstTokenHolder], + [firstTokenId, secondTokenId, firstTokenId], + ); + expect(result).to.be.an('array'); + expect(result[0]).to.be.a.bignumber.equal(result[2]); + expect(result[0]).to.be.a.bignumber.equal(firstTokenValue); + expect(result[1]).to.be.a.bignumber.equal(secondTokenValue); + expect(result[2]).to.be.a.bignumber.equal(firstTokenValue); + }); + }); + }); + + describe('setApprovalForAll', function () { + let receipt; + beforeEach(async function () { + receipt = await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + }); + + it('sets approval status which can be queried via isApprovedForAll', async function () { + expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(true); + }); + + it('emits an ApprovalForAll log', function () { + expectEvent(receipt, 'ApprovalForAll', { account: multiTokenHolder, operator: proxy, approved: true }); + }); + + it('can unset approval for an operator', async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + expect(await this.token.isApprovedForAll(multiTokenHolder, proxy)).to.be.equal(false); + }); + + it('reverts if attempting to approve zero address as an operator', async function () { + await expectRevertCustomError( + this.token.setApprovalForAll(constants.ZERO_ADDRESS, true, { from: multiTokenHolder }), + 'ERC1155InvalidOperator', + [constants.ZERO_ADDRESS], + ); + }); + }); + + describe('safeTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstTokenValue, '0x', { + from: minter, + }); + await this.token.$_mint(multiTokenHolder, secondTokenId, secondTokenValue, '0x', { + from: minter, + }); + }); + + it('reverts when transferring more than balance', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstTokenValue.addn(1), '0x', { + from: multiTokenHolder, + }), + 'ERC1155InsufficientBalance', + [multiTokenHolder, firstTokenValue, firstTokenValue.addn(1), firstTokenId], + ); + }); + + it('reverts when transferring to zero address', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(multiTokenHolder, ZERO_ADDRESS, firstTokenId, firstTokenValue, '0x', { + from: multiTokenHolder, + }), + 'ERC1155InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + + function transferWasSuccessful({ operator, from, id, value }) { + it('debits transferred balance from sender', async function () { + const newBalance = await this.token.balanceOf(from, id); + expect(newBalance).to.be.a.bignumber.equal('0'); + }); + + it('credits transferred balance to receiver', async function () { + const newBalance = await this.token.balanceOf(this.toWhom, id); + expect(newBalance).to.be.a.bignumber.equal(value); + }); + + it('emits a TransferSingle log', function () { + expectEvent(this.transferLogs, 'TransferSingle', { + operator, + from, + to: this.toWhom, + id, + value, + }); + }); + } + + context('when called by the multiTokenHolder', async function () { + beforeEach(async function () { + this.toWhom = recipient; + this.transferLogs = await this.token.safeTransferFrom( + multiTokenHolder, + recipient, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ); + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + }); + + it('preserves existing balances which are not transferred by multiTokenHolder', async function () { + const balance1 = await this.token.balanceOf(multiTokenHolder, secondTokenId); + expect(balance1).to.be.a.bignumber.equal(secondTokenValue); + + const balance2 = await this.token.balanceOf(recipient, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + + context('when called by an operator on behalf of the multiTokenHolder', function () { + context('when operator is not approved by multiTokenHolder', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(multiTokenHolder, recipient, firstTokenId, firstTokenValue, '0x', { + from: proxy, + }), + 'ERC1155MissingApprovalForAll', + [proxy, multiTokenHolder], + ); + }); + }); + + context('when operator is approved by multiTokenHolder', function () { + beforeEach(async function () { + this.toWhom = recipient; + await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.transferLogs = await this.token.safeTransferFrom( + multiTokenHolder, + recipient, + firstTokenId, + firstTokenValue, + '0x', + { + from: proxy, + }, + ); + }); + + transferWasSuccessful.call(this, { + operator: proxy, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + }); + + it("preserves operator's balances not involved in the transfer", async function () { + const balance1 = await this.token.balanceOf(proxy, firstTokenId); + expect(balance1).to.be.a.bignumber.equal('0'); + + const balance2 = await this.token.balanceOf(proxy, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + }); + + context('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.None, + ); + }); + + context('without data', function () { + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + data: null, + }); + }); + }); + + context('with data', function () { + const data = '0xf00dd00d'; + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + data, + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + transferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'Received', { + operator: multiTokenHolder, + from: multiTokenHolder, + id: firstTokenId, + value: firstTokenValue, + data, + }); + }); + }); + }); + + context('to a receiver contract returning unexpected value', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new('0x00c0ffee', RECEIVER_BATCH_MAGIC_VALUE, RevertType.None); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(multiTokenHolder, this.receiver.address, firstTokenId, firstTokenValue, '0x', { + from: multiTokenHolder, + }), + 'ERC1155InvalidReceiver', + [this.receiver.address], + ); + }); + }); + + context('to a receiver contract that reverts', function () { + context('with a revert string', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithMessage, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + 'ERC1155ReceiverMock: reverting on receive', + ); + }); + }); + + context('without a revert string', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + 'ERC1155InvalidReceiver', + [this.receiver.address], + ); + }); + }); + + context('with a custom error', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + 'CustomError', + [RECEIVER_SINGLE_MAGIC_VALUE], + ); + }); + }); + + context('with a panic', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.Panic, + ); + }); + + it('reverts', async function () { + await expectRevert.unspecified( + this.token.safeTransferFrom( + multiTokenHolder, + this.receiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + ); + }); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + await expectRevert.unspecified( + this.token.safeTransferFrom( + multiTokenHolder, + invalidReceiver.address, + firstTokenId, + firstTokenValue, + '0x', + { + from: multiTokenHolder, + }, + ), + ); + }); + }); + }); + + describe('safeBatchTransferFrom', function () { + beforeEach(async function () { + await this.token.$_mint(multiTokenHolder, firstTokenId, firstTokenValue, '0x', { + from: minter, + }); + await this.token.$_mint(multiTokenHolder, secondTokenId, secondTokenValue, '0x', { + from: minter, + }); + }); + + it('reverts when transferring value more than any of balances', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue.addn(1)], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155InsufficientBalance', + [multiTokenHolder, secondTokenValue, secondTokenValue.addn(1), secondTokenId], + ); + }); + + it("reverts when ids array length doesn't match values array length", async function () { + const ids1 = [firstTokenId]; + const tokenValues1 = [firstTokenValue, secondTokenValue]; + + await expectRevertCustomError( + this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids1, tokenValues1, '0x', { + from: multiTokenHolder, + }), + 'ERC1155InvalidArrayLength', + [ids1.length, tokenValues1.length], + ); + + const ids2 = [firstTokenId, secondTokenId]; + const tokenValues2 = [firstTokenValue]; + await expectRevertCustomError( + this.token.safeBatchTransferFrom(multiTokenHolder, recipient, ids2, tokenValues2, '0x', { + from: multiTokenHolder, + }), + 'ERC1155InvalidArrayLength', + [ids2.length, tokenValues2.length], + ); + }); + + it('reverts when transferring to zero address', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + ZERO_ADDRESS, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + + it('reverts when transferring from zero address', async function () { + await expectRevertCustomError( + this.token.$_safeBatchTransferFrom(ZERO_ADDRESS, multiTokenHolder, [firstTokenId], [firstTokenValue], '0x'), + 'ERC1155InvalidSender', + [ZERO_ADDRESS], + ); + }); + + function batchTransferWasSuccessful({ operator, from, ids, values }) { + it('debits transferred balances from sender', async function () { + const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(from), ids); + for (const newBalance of newBalances) { + expect(newBalance).to.be.a.bignumber.equal('0'); + } + }); + + it('credits transferred balances to receiver', async function () { + const newBalances = await this.token.balanceOfBatch(new Array(ids.length).fill(this.toWhom), ids); + for (let i = 0; i < newBalances.length; i++) { + expect(newBalances[i]).to.be.a.bignumber.equal(values[i]); + } + }); + + it('emits a TransferBatch log', function () { + expectEvent(this.transferLogs, 'TransferBatch', { + operator, + from, + to: this.toWhom, + // ids, + // values, + }); + }); + } + + context('when called by the multiTokenHolder', async function () { + beforeEach(async function () { + this.toWhom = recipient; + this.transferLogs = await this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ); + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + }); + }); + + context('when called by an operator on behalf of the multiTokenHolder', function () { + context('when operator is not approved by multiTokenHolder', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(proxy, false, { from: multiTokenHolder }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: proxy }, + ), + 'ERC1155MissingApprovalForAll', + [proxy, multiTokenHolder], + ); + }); + }); + + context('when operator is approved by multiTokenHolder', function () { + beforeEach(async function () { + this.toWhom = recipient; + await this.token.setApprovalForAll(proxy, true, { from: multiTokenHolder }); + this.transferLogs = await this.token.safeBatchTransferFrom( + multiTokenHolder, + recipient, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: proxy }, + ); + }); + + batchTransferWasSuccessful.call(this, { + operator: proxy, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + }); + + it("preserves operator's balances not involved in the transfer", async function () { + const balance1 = await this.token.balanceOf(proxy, firstTokenId); + expect(balance1).to.be.a.bignumber.equal('0'); + const balance2 = await this.token.balanceOf(proxy, secondTokenId); + expect(balance2).to.be.a.bignumber.equal('0'); + }); + }); + }); + + context('when sending to a valid receiver', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.None, + ); + }); + + context('without data', function () { + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + }); + + it('calls onERC1155BatchReceived', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstTokenValue, secondTokenValue], + data: null, + }); + }); + }); + + context('with data', function () { + const data = '0xf00dd00d'; + beforeEach(async function () { + this.toWhom = this.receiver.address; + this.transferReceipt = await this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + data, + { from: multiTokenHolder }, + ); + this.transferLogs = this.transferReceipt; + }); + + batchTransferWasSuccessful.call(this, { + operator: multiTokenHolder, + from: multiTokenHolder, + ids: [firstTokenId, secondTokenId], + values: [firstTokenValue, secondTokenValue], + }); + + it('calls onERC1155Received', async function () { + await expectEvent.inTransaction(this.transferReceipt.tx, ERC1155ReceiverMock, 'BatchReceived', { + operator: multiTokenHolder, + from: multiTokenHolder, + // ids: [firstTokenId, secondTokenId], + // values: [firstTokenValue, secondTokenValue], + data, + }); + }); + }); + }); + + context('to a receiver contract returning unexpected value', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_SINGLE_MAGIC_VALUE, + RevertType.None, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155InvalidReceiver', + [this.receiver.address], + ); + }); + }); + + context('to a receiver contract that reverts', function () { + context('with a revert string', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithMessage, + ); + }); + + it('reverts', async function () { + await expectRevert( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155ReceiverMock: reverting on batch receive', + ); + }); + }); + + context('without a revert string', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'ERC1155InvalidReceiver', + [this.receiver.address], + ); + }); + }); + + context('with a custom error', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + 'CustomError', + [RECEIVER_SINGLE_MAGIC_VALUE], + ); + }); + }); + + context('with a panic', function () { + beforeEach(async function () { + this.receiver = await ERC1155ReceiverMock.new( + RECEIVER_SINGLE_MAGIC_VALUE, + RECEIVER_BATCH_MAGIC_VALUE, + RevertType.Panic, + ); + }); + + it('reverts', async function () { + await expectRevert.unspecified( + this.token.safeBatchTransferFrom( + multiTokenHolder, + this.receiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + ); + }); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const invalidReceiver = this.token; + await expectRevert.unspecified( + this.token.safeBatchTransferFrom( + multiTokenHolder, + invalidReceiver.address, + [firstTokenId, secondTokenId], + [firstTokenValue, secondTokenValue], + '0x', + { from: multiTokenHolder }, + ), + ); + }); + }); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155']); + }); +} + +module.exports = { + shouldBehaveLikeERC1155, +}; diff --git a/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js b/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js new file mode 100644 index 0000000..58d747a --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC1155/ERC1155.test.js @@ -0,0 +1,252 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../../helpers/customError'); + +const { shouldBehaveLikeERC1155 } = require('./ERC1155.behavior'); +const ERC1155Mock = artifacts.require('$ERC1155'); + +contract('ERC1155', function (accounts) { + const [operator, tokenHolder, tokenBatchHolder, ...otherAccounts] = accounts; + + const initialURI = 'https://token-cdn-domain/{id}.json'; + + beforeEach(async function () { + this.token = await ERC1155Mock.new(initialURI); + }); + + shouldBehaveLikeERC1155(otherAccounts); + + describe('internal functions', function () { + const tokenId = new BN(1990); + const mintValue = new BN(9001); + const burnValue = new BN(3000); + + const tokenBatchIds = [new BN(2000), new BN(2010), new BN(2020)]; + const mintValues = [new BN(5000), new BN(10000), new BN(42195)]; + const burnValues = [new BN(5000), new BN(9001), new BN(195)]; + + const data = '0x12345678'; + + describe('_mint', function () { + it('reverts with a zero destination address', async function () { + await expectRevertCustomError( + this.token.$_mint(ZERO_ADDRESS, tokenId, mintValue, data), + 'ERC1155InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(tokenHolder, tokenId, mintValue, data, { from: operator }); + }); + + it('emits a TransferSingle event', function () { + expectEvent(this.receipt, 'TransferSingle', { + operator, + from: ZERO_ADDRESS, + to: tokenHolder, + id: tokenId, + value: mintValue, + }); + }); + + it('credits the minted token value', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintValue); + }); + }); + }); + + describe('_mintBatch', function () { + it('reverts with a zero destination address', async function () { + await expectRevertCustomError( + this.token.$_mintBatch(ZERO_ADDRESS, tokenBatchIds, mintValues, data), + 'ERC1155InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + + it('reverts if length of inputs do not match', async function () { + await expectRevertCustomError( + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues.slice(1), data), + 'ERC1155InvalidArrayLength', + [tokenBatchIds.length, mintValues.length - 1], + ); + + await expectRevertCustomError( + this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds.slice(1), mintValues, data), + 'ERC1155InvalidArrayLength', + [tokenBatchIds.length - 1, mintValues.length], + ); + }); + + context('with minted batch of tokens', function () { + beforeEach(async function () { + this.receipt = await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues, data, { + from: operator, + }); + }); + + it('emits a TransferBatch event', function () { + expectEvent(this.receipt, 'TransferBatch', { + operator, + from: ZERO_ADDRESS, + to: tokenBatchHolder, + }); + }); + + it('credits the minted batch of tokens', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds, + ); + + for (let i = 0; i < holderBatchBalances.length; i++) { + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintValues[i]); + } + }); + }); + }); + + describe('_burn', function () { + it("reverts when burning the zero account's tokens", async function () { + await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, tokenId, mintValue), 'ERC1155InvalidSender', [ + ZERO_ADDRESS, + ]); + }); + + it('reverts when burning a non-existent token id', async function () { + await expectRevertCustomError( + this.token.$_burn(tokenHolder, tokenId, mintValue), + 'ERC1155InsufficientBalance', + [tokenHolder, 0, mintValue, tokenId], + ); + }); + + it('reverts when burning more than available tokens', async function () { + await this.token.$_mint(tokenHolder, tokenId, mintValue, data, { from: operator }); + + await expectRevertCustomError( + this.token.$_burn(tokenHolder, tokenId, mintValue.addn(1)), + 'ERC1155InsufficientBalance', + [tokenHolder, mintValue, mintValue.addn(1), tokenId], + ); + }); + + context('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mint(tokenHolder, tokenId, mintValue, data); + this.receipt = await this.token.$_burn(tokenHolder, tokenId, burnValue, { from: operator }); + }); + + it('emits a TransferSingle event', function () { + expectEvent(this.receipt, 'TransferSingle', { + operator, + from: tokenHolder, + to: ZERO_ADDRESS, + id: tokenId, + value: burnValue, + }); + }); + + it('accounts for both minting and burning', async function () { + expect(await this.token.balanceOf(tokenHolder, tokenId)).to.be.bignumber.equal(mintValue.sub(burnValue)); + }); + }); + }); + + describe('_burnBatch', function () { + it("reverts when burning the zero account's tokens", async function () { + await expectRevertCustomError( + this.token.$_burnBatch(ZERO_ADDRESS, tokenBatchIds, burnValues), + 'ERC1155InvalidSender', + [ZERO_ADDRESS], + ); + }); + + it('reverts if length of inputs do not match', async function () { + await expectRevertCustomError( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues.slice(1)), + 'ERC1155InvalidArrayLength', + [tokenBatchIds.length, burnValues.length - 1], + ); + + await expectRevertCustomError( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds.slice(1), burnValues), + 'ERC1155InvalidArrayLength', + [tokenBatchIds.length - 1, burnValues.length], + ); + }); + + it('reverts when burning a non-existent token id', async function () { + await expectRevertCustomError( + this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues), + 'ERC1155InsufficientBalance', + [tokenBatchHolder, 0, tokenBatchIds[0], burnValues[0]], + ); + }); + + context('with minted-then-burnt tokens', function () { + beforeEach(async function () { + await this.token.$_mintBatch(tokenBatchHolder, tokenBatchIds, mintValues, data); + this.receipt = await this.token.$_burnBatch(tokenBatchHolder, tokenBatchIds, burnValues, { from: operator }); + }); + + it('emits a TransferBatch event', function () { + expectEvent(this.receipt, 'TransferBatch', { + operator, + from: tokenBatchHolder, + to: ZERO_ADDRESS, + // ids: tokenBatchIds, + // values: burnValues, + }); + }); + + it('accounts for both minting and burning', async function () { + const holderBatchBalances = await this.token.balanceOfBatch( + new Array(tokenBatchIds.length).fill(tokenBatchHolder), + tokenBatchIds, + ); + + for (let i = 0; i < holderBatchBalances.length; i++) { + expect(holderBatchBalances[i]).to.be.bignumber.equal(mintValues[i].sub(burnValues[i])); + } + }); + }); + }); + }); + + describe('ERC1155MetadataURI', function () { + const firstTokenID = new BN('42'); + const secondTokenID = new BN('1337'); + + it('emits no URI event in constructor', async function () { + await expectEvent.notEmitted.inConstruction(this.token, 'URI'); + }); + + it('sets the initial URI for all token types', async function () { + expect(await this.token.uri(firstTokenID)).to.be.equal(initialURI); + expect(await this.token.uri(secondTokenID)).to.be.equal(initialURI); + }); + + describe('_setURI', function () { + const newURI = 'https://token-cdn-domain/{locale}/{id}.json'; + + it('emits no URI event', async function () { + const receipt = await this.token.$_setURI(newURI); + + expectEvent.notEmitted(receipt, 'URI'); + }); + + it('sets the new URI for all token types', async function () { + await this.token.$_setURI(newURI); + + expect(await this.token.uri(firstTokenID)).to.be.equal(newURI); + expect(await this.token.uri(secondTokenID)).to.be.equal(newURI); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js b/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js new file mode 100644 index 0000000..fc94db0 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Burnable.test.js @@ -0,0 +1,71 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC1155Burnable = artifacts.require('$ERC1155Burnable'); + +contract('ERC1155Burnable', function (accounts) { + const [holder, operator, other] = accounts; + + const uri = 'https://token.com'; + + const tokenIds = [new BN('42'), new BN('1137')]; + const values = [new BN('3000'), new BN('9902')]; + + beforeEach(async function () { + this.token = await ERC1155Burnable.new(uri); + + await this.token.$_mint(holder, tokenIds[0], values[0], '0x'); + await this.token.$_mint(holder, tokenIds[1], values[1], '0x'); + }); + + describe('burn', function () { + it('holder can burn their tokens', async function () { + await this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: holder }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: operator }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expectRevertCustomError( + this.token.burn(holder, tokenIds[0], values[0].subn(1), { from: other }), + 'ERC1155MissingApprovalForAll', + [other, holder], + ); + }); + }); + + describe('burnBatch', function () { + it('holder can burn their tokens', async function () { + await this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: holder }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + }); + + it("approved operators can burn the holder's tokens", async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: operator }); + + expect(await this.token.balanceOf(holder, tokenIds[0])).to.be.bignumber.equal('1'); + expect(await this.token.balanceOf(holder, tokenIds[1])).to.be.bignumber.equal('2'); + }); + + it("unapproved accounts cannot burn the holder's tokens", async function () { + await expectRevertCustomError( + this.token.burnBatch(holder, tokenIds, [values[0].subn(1), values[1].subn(2)], { from: other }), + 'ERC1155MissingApprovalForAll', + [other, holder], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js b/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js new file mode 100644 index 0000000..248ea56 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Pausable.test.js @@ -0,0 +1,113 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC1155Pausable = artifacts.require('$ERC1155Pausable'); + +contract('ERC1155Pausable', function (accounts) { + const [holder, operator, receiver, other] = accounts; + + const uri = 'https://token.com'; + + beforeEach(async function () { + this.token = await ERC1155Pausable.new(uri); + }); + + context('when token is paused', function () { + const firstTokenId = new BN('37'); + const firstTokenValue = new BN('42'); + + const secondTokenId = new BN('19842'); + const secondTokenValue = new BN('23'); + + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: holder }); + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); + + await this.token.$_pause(); + }); + + it('reverts when trying to safeTransferFrom from holder', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenValue, '0x', { from: holder }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeTransferFrom from operator', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(holder, receiver, firstTokenId, firstTokenValue, '0x', { from: operator }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeBatchTransferFrom from holder', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenValue], '0x', { from: holder }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeBatchTransferFrom from operator', async function () { + await expectRevertCustomError( + this.token.safeBatchTransferFrom(holder, receiver, [firstTokenId], [firstTokenValue], '0x', { + from: operator, + }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to mint', async function () { + await expectRevertCustomError( + this.token.$_mint(holder, secondTokenId, secondTokenValue, '0x'), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to mintBatch', async function () { + await expectRevertCustomError( + this.token.$_mintBatch(holder, [secondTokenId], [secondTokenValue], '0x'), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to burn', async function () { + await expectRevertCustomError(this.token.$_burn(holder, firstTokenId, firstTokenValue), 'EnforcedPause', []); + }); + + it('reverts when trying to burnBatch', async function () { + await expectRevertCustomError( + this.token.$_burnBatch(holder, [firstTokenId], [firstTokenValue]), + 'EnforcedPause', + [], + ); + }); + + describe('setApprovalForAll', function () { + it('approves an operator', async function () { + await this.token.setApprovalForAll(other, true, { from: holder }); + expect(await this.token.isApprovedForAll(holder, other)).to.equal(true); + }); + }); + + describe('balanceOf', function () { + it('returns the token value owned by the given address', async function () { + const balance = await this.token.balanceOf(holder, firstTokenId); + expect(balance).to.be.bignumber.equal(firstTokenValue); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(holder, operator)).to.equal(true); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js b/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js new file mode 100644 index 0000000..bf86920 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155Supply.test.js @@ -0,0 +1,116 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const { ZERO_ADDRESS } = constants; + +const ERC1155Supply = artifacts.require('$ERC1155Supply'); + +contract('ERC1155Supply', function (accounts) { + const [holder] = accounts; + + const uri = 'https://token.com'; + + const firstTokenId = new BN('37'); + const firstTokenValue = new BN('42'); + + const secondTokenId = new BN('19842'); + const secondTokenValue = new BN('23'); + + beforeEach(async function () { + this.token = await ERC1155Supply.new(uri); + }); + + context('before mint', function () { + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + }); + }); + + context('after mint', function () { + context('single', function () { + beforeEach(async function () { + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(true); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenValue); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal(firstTokenValue); + }); + }); + + context('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue], '0x'); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(true); + expect(await this.token.exists(secondTokenId)).to.be.equal(true); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal(firstTokenValue); + expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal(secondTokenValue); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal( + firstTokenValue.add(secondTokenValue), + ); + }); + }); + }); + + context('after burn', function () { + context('single', function () { + beforeEach(async function () { + await this.token.$_mint(holder, firstTokenId, firstTokenValue, '0x'); + await this.token.$_burn(holder, firstTokenId, firstTokenValue); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + }); + }); + + context('batch', function () { + beforeEach(async function () { + await this.token.$_mintBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue], '0x'); + await this.token.$_burnBatch(holder, [firstTokenId, secondTokenId], [firstTokenValue, secondTokenValue]); + }); + + it('exist', async function () { + expect(await this.token.exists(firstTokenId)).to.be.equal(false); + expect(await this.token.exists(secondTokenId)).to.be.equal(false); + }); + + it('totalSupply', async function () { + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply(uint256)'](secondTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + }); + }); + }); + + context('other', function () { + it('supply unaffected by no-op', async function () { + this.token.safeTransferFrom(ZERO_ADDRESS, ZERO_ADDRESS, firstTokenId, firstTokenValue, '0x', { + from: ZERO_ADDRESS, + }); + expect(await this.token.methods['totalSupply(uint256)'](firstTokenId)).to.be.bignumber.equal('0'); + expect(await this.token.methods['totalSupply()']()).to.be.bignumber.equal('0'); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js b/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js new file mode 100644 index 0000000..58ac67b --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC1155/extensions/ERC1155URIStorage.test.js @@ -0,0 +1,66 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { artifacts } = require('hardhat'); + +const ERC1155URIStorage = artifacts.require('$ERC1155URIStorage'); + +contract(['ERC1155URIStorage'], function (accounts) { + const [holder] = accounts; + + const erc1155Uri = 'https://token.com/nfts/'; + const baseUri = 'https://token.com/'; + + const tokenId = new BN('1'); + const value = new BN('3000'); + + describe('with base uri set', function () { + beforeEach(async function () { + this.token = await ERC1155URIStorage.new(erc1155Uri); + await this.token.$_setBaseURI(baseUri); + + await this.token.$_mint(holder, tokenId, value, '0x'); + }); + + it('can request the token uri, returning the erc1155 uri if no token uri was set', async function () { + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(erc1155Uri); + }); + + it('can request the token uri, returning the concatenated uri if a token uri was set', async function () { + const tokenUri = '1234/'; + const receipt = await this.token.$_setURI(tokenId, tokenUri); + + const receivedTokenUri = await this.token.uri(tokenId); + + const expectedUri = `${baseUri}${tokenUri}`; + expect(receivedTokenUri).to.be.equal(expectedUri); + expectEvent(receipt, 'URI', { value: expectedUri, id: tokenId }); + }); + }); + + describe('with base uri set to the empty string', function () { + beforeEach(async function () { + this.token = await ERC1155URIStorage.new(''); + + await this.token.$_mint(holder, tokenId, value, '0x'); + }); + + it('can request the token uri, returning an empty string if no token uri was set', async function () { + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(''); + }); + + it('can request the token uri, returning the token uri if a token uri was set', async function () { + const tokenUri = 'ipfs://1234/'; + const receipt = await this.token.$_setURI(tokenId, tokenUri); + + const receivedTokenUri = await this.token.uri(tokenId); + + expect(receivedTokenUri).to.be.equal(tokenUri); + expectEvent(receipt, 'URI', { value: tokenUri, id: tokenId }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js b/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js new file mode 100644 index 0000000..ee818ea --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC1155/utils/ERC1155Holder.test.js @@ -0,0 +1,64 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const ERC1155Holder = artifacts.require('$ERC1155Holder'); +const ERC1155 = artifacts.require('$ERC1155'); + +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); + +contract('ERC1155Holder', function (accounts) { + const [creator] = accounts; + const uri = 'https://token-cdn-domain/{id}.json'; + const multiTokenIds = [new BN(1), new BN(2), new BN(3)]; + const multiTokenValues = [new BN(1000), new BN(2000), new BN(3000)]; + const transferData = '0x12345678'; + + beforeEach(async function () { + this.multiToken = await ERC1155.new(uri); + this.holder = await ERC1155Holder.new(); + await this.multiToken.$_mintBatch(creator, multiTokenIds, multiTokenValues, '0x'); + }); + + shouldSupportInterfaces(['ERC165', 'ERC1155Receiver']); + + it('receives ERC1155 tokens from a single ID', async function () { + await this.multiToken.safeTransferFrom( + creator, + this.holder.address, + multiTokenIds[0], + multiTokenValues[0], + transferData, + { from: creator }, + ); + + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[0])).to.be.bignumber.equal( + multiTokenValues[0], + ); + + for (let i = 1; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + } + }); + + it('receives ERC1155 tokens from a multiple IDs', async function () { + for (let i = 0; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal(new BN(0)); + } + + await this.multiToken.safeBatchTransferFrom( + creator, + this.holder.address, + multiTokenIds, + multiTokenValues, + transferData, + { from: creator }, + ); + + for (let i = 0; i < multiTokenIds.length; i++) { + expect(await this.multiToken.balanceOf(this.holder.address, multiTokenIds[i])).to.be.bignumber.equal( + multiTokenValues[i], + ); + } + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js b/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js new file mode 100644 index 0000000..b6f8617 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/ERC20.behavior.js @@ -0,0 +1,340 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS, MAX_UINT256 } = constants; + +const { expectRevertCustomError } = require('../../helpers/customError'); + +function shouldBehaveLikeERC20(initialSupply, accounts, opts = {}) { + const [initialHolder, recipient, anotherAccount] = accounts; + const { forcedApproval } = opts; + + describe('total supply', function () { + it('returns the total token value', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + }); + }); + + describe('balanceOf', function () { + describe('when the requested account has no tokens', function () { + it('returns zero', async function () { + expect(await this.token.balanceOf(anotherAccount)).to.be.bignumber.equal('0'); + }); + }); + + describe('when the requested account has some tokens', function () { + it('returns the total token value', async function () { + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(initialSupply); + }); + }); + }); + + describe('transfer', function () { + shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, value) { + return this.token.transfer(to, value, { from }); + }); + }); + + describe('transfer from', function () { + const spender = recipient; + + describe('when the token owner is not the zero address', function () { + const tokenOwner = initialHolder; + + describe('when the recipient is not the zero address', function () { + const to = anotherAccount; + + describe('when the spender has enough allowance', function () { + beforeEach(async function () { + await this.token.approve(spender, initialSupply, { from: initialHolder }); + }); + + describe('when the token owner has enough balance', function () { + const value = initialSupply; + + it('transfers the requested value', async function () { + await this.token.transferFrom(tokenOwner, to, value, { from: spender }); + + expect(await this.token.balanceOf(tokenOwner)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(value); + }); + + it('decreases the spender allowance', async function () { + await this.token.transferFrom(tokenOwner, to, value, { from: spender }); + + expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal('0'); + }); + + it('emits a transfer event', async function () { + expectEvent(await this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'Transfer', { + from: tokenOwner, + to: to, + value: value, + }); + }); + + if (forcedApproval) { + it('emits an approval event', async function () { + expectEvent(await this.token.transferFrom(tokenOwner, to, value, { from: spender }), 'Approval', { + owner: tokenOwner, + spender: spender, + value: await this.token.allowance(tokenOwner, spender), + }); + }); + } else { + it('does not emit an approval event', async function () { + expectEvent.notEmitted( + await this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'Approval', + ); + }); + } + }); + + describe('when the token owner does not have enough balance', function () { + const value = initialSupply; + + beforeEach('reducing balance', async function () { + await this.token.transfer(to, 1, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InsufficientBalance', + [tokenOwner, value - 1, value], + ); + }); + }); + }); + + describe('when the spender does not have enough allowance', function () { + const allowance = initialSupply.subn(1); + + beforeEach(async function () { + await this.token.approve(spender, allowance, { from: tokenOwner }); + }); + + describe('when the token owner has enough balance', function () { + const value = initialSupply; + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InsufficientAllowance', + [spender, allowance, value], + ); + }); + }); + + describe('when the token owner does not have enough balance', function () { + const value = allowance; + + beforeEach('reducing balance', async function () { + await this.token.transfer(to, 2, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InsufficientBalance', + [tokenOwner, value - 1, value], + ); + }); + }); + }); + + describe('when the spender has unlimited allowance', function () { + beforeEach(async function () { + await this.token.approve(spender, MAX_UINT256, { from: initialHolder }); + }); + + it('does not decrease the spender allowance', async function () { + await this.token.transferFrom(tokenOwner, to, 1, { from: spender }); + + expect(await this.token.allowance(tokenOwner, spender)).to.be.bignumber.equal(MAX_UINT256); + }); + + it('does not emit an approval event', async function () { + expectEvent.notEmitted(await this.token.transferFrom(tokenOwner, to, 1, { from: spender }), 'Approval'); + }); + }); + }); + + describe('when the recipient is the zero address', function () { + const value = initialSupply; + const to = ZERO_ADDRESS; + + beforeEach(async function () { + await this.token.approve(spender, value, { from: tokenOwner }); + }); + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + }); + }); + + describe('when the token owner is the zero address', function () { + const value = 0; + const tokenOwner = ZERO_ADDRESS; + const to = recipient; + + it('reverts', async function () { + await expectRevertCustomError( + this.token.transferFrom(tokenOwner, to, value, { from: spender }), + 'ERC20InvalidApprover', + [ZERO_ADDRESS], + ); + }); + }); + }); + + describe('approve', function () { + shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, value) { + return this.token.approve(spender, value, { from: owner }); + }); + }); +} + +function shouldBehaveLikeERC20Transfer(from, to, balance, transfer) { + describe('when the recipient is not the zero address', function () { + describe('when the sender does not have enough balance', function () { + const value = balance.addn(1); + + it('reverts', async function () { + await expectRevertCustomError(transfer.call(this, from, to, value), 'ERC20InsufficientBalance', [ + from, + balance, + value, + ]); + }); + }); + + describe('when the sender transfers all balance', function () { + const value = balance; + + it('transfers the requested value', async function () { + await transfer.call(this, from, to, value); + + expect(await this.token.balanceOf(from)).to.be.bignumber.equal('0'); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal(value); + }); + + it('emits a transfer event', async function () { + expectEvent(await transfer.call(this, from, to, value), 'Transfer', { from, to, value: value }); + }); + }); + + describe('when the sender transfers zero tokens', function () { + const value = new BN('0'); + + it('transfers the requested value', async function () { + await transfer.call(this, from, to, value); + + expect(await this.token.balanceOf(from)).to.be.bignumber.equal(balance); + + expect(await this.token.balanceOf(to)).to.be.bignumber.equal('0'); + }); + + it('emits a transfer event', async function () { + expectEvent(await transfer.call(this, from, to, value), 'Transfer', { from, to, value: value }); + }); + }); + }); + + describe('when the recipient is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError(transfer.call(this, from, ZERO_ADDRESS, balance), 'ERC20InvalidReceiver', [ + ZERO_ADDRESS, + ]); + }); + }); +} + +function shouldBehaveLikeERC20Approve(owner, spender, supply, approve) { + describe('when the spender is not the zero address', function () { + describe('when the sender has enough balance', function () { + const value = supply; + + it('emits an approval event', async function () { + expectEvent(await approve.call(this, owner, spender, value), 'Approval', { + owner: owner, + spender: spender, + value: value, + }); + }); + + describe('when there was no approved value before', function () { + it('approves the requested value', async function () { + await approve.call(this, owner, spender, value); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + }); + + describe('when the spender had an approved value', function () { + beforeEach(async function () { + await approve.call(this, owner, spender, new BN(1)); + }); + + it('approves the requested value and replaces the previous one', async function () { + await approve.call(this, owner, spender, value); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + }); + }); + + describe('when the sender does not have enough balance', function () { + const value = supply.addn(1); + + it('emits an approval event', async function () { + expectEvent(await approve.call(this, owner, spender, value), 'Approval', { + owner: owner, + spender: spender, + value: value, + }); + }); + + describe('when there was no approved value before', function () { + it('approves the requested value', async function () { + await approve.call(this, owner, spender, value); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + }); + + describe('when the spender had an approved value', function () { + beforeEach(async function () { + await approve.call(this, owner, spender, new BN(1)); + }); + + it('approves the requested value and replaces the previous one', async function () { + await approve.call(this, owner, spender, value); + + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + }); + }); + }); + + describe('when the spender is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError(approve.call(this, owner, ZERO_ADDRESS, supply), `ERC20InvalidSpender`, [ + ZERO_ADDRESS, + ]); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +}; diff --git a/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js b/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js new file mode 100644 index 0000000..2191fd8 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/ERC20.test.js @@ -0,0 +1,202 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { + shouldBehaveLikeERC20, + shouldBehaveLikeERC20Transfer, + shouldBehaveLikeERC20Approve, +} = require('./ERC20.behavior'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const TOKENS = [ + { Token: artifacts.require('$ERC20') }, + { Token: artifacts.require('$ERC20ApprovalMock'), forcedApproval: true }, +]; + +contract('ERC20', function (accounts) { + const [initialHolder, recipient] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + const initialSupply = new BN(100); + + for (const { Token, forcedApproval } of TOKENS) { + describe(`using ${Token._json.contractName}`, function () { + beforeEach(async function () { + this.token = await Token.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + shouldBehaveLikeERC20(initialSupply, accounts, { forcedApproval }); + + it('has a name', async function () { + expect(await this.token.name()).to.equal(name); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.equal(symbol); + }); + + it('has 18 decimals', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('18'); + }); + + describe('_mint', function () { + const value = new BN(50); + it('rejects a null account', async function () { + await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, value), 'ERC20InvalidReceiver', [ZERO_ADDRESS]); + }); + + it('rejects overflow', async function () { + const maxUint256 = new BN('2').pow(new BN(256)).subn(1); + await expectRevert( + this.token.$_mint(recipient, maxUint256), + 'reverted with panic code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block)', + ); + }); + + describe('for a non zero account', function () { + beforeEach('minting', async function () { + this.receipt = await this.token.$_mint(recipient, value); + }); + + it('increments totalSupply', async function () { + const expectedSupply = initialSupply.add(value); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + + it('increments recipient balance', async function () { + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); + }); + + it('emits Transfer event', async function () { + const event = expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: recipient }); + + expect(event.args.value).to.be.bignumber.equal(value); + }); + }); + }); + + describe('_burn', function () { + it('rejects a null account', async function () { + await expectRevertCustomError(this.token.$_burn(ZERO_ADDRESS, new BN(1)), 'ERC20InvalidSender', [ + ZERO_ADDRESS, + ]); + }); + + describe('for a non zero account', function () { + it('rejects burning more than balance', async function () { + await expectRevertCustomError( + this.token.$_burn(initialHolder, initialSupply.addn(1)), + 'ERC20InsufficientBalance', + [initialHolder, initialSupply, initialSupply.addn(1)], + ); + }); + + const describeBurn = function (description, value) { + describe(description, function () { + beforeEach('burning', async function () { + this.receipt = await this.token.$_burn(initialHolder, value); + }); + + it('decrements totalSupply', async function () { + const expectedSupply = initialSupply.sub(value); + expect(await this.token.totalSupply()).to.be.bignumber.equal(expectedSupply); + }); + + it('decrements initialHolder balance', async function () { + const expectedBalance = initialSupply.sub(value); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(expectedBalance); + }); + + it('emits Transfer event', async function () { + const event = expectEvent(this.receipt, 'Transfer', { from: initialHolder, to: ZERO_ADDRESS }); + + expect(event.args.value).to.be.bignumber.equal(value); + }); + }); + }; + + describeBurn('for entire balance', initialSupply); + describeBurn('for less value than balance', initialSupply.subn(1)); + }); + }); + + describe('_update', function () { + const value = new BN(1); + + it('from is the zero address', async function () { + const balanceBefore = await this.token.balanceOf(initialHolder); + const totalSupply = await this.token.totalSupply(); + + expectEvent(await this.token.$_update(ZERO_ADDRESS, initialHolder, value), 'Transfer', { + from: ZERO_ADDRESS, + to: initialHolder, + value: value, + }); + expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.add(value)); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.add(value)); + }); + + it('to is the zero address', async function () { + const balanceBefore = await this.token.balanceOf(initialHolder); + const totalSupply = await this.token.totalSupply(); + + expectEvent(await this.token.$_update(initialHolder, ZERO_ADDRESS, value), 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: value, + }); + expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply.sub(value)); + expect(await this.token.balanceOf(initialHolder)).to.be.bignumber.equal(balanceBefore.sub(value)); + }); + + it('from and to are the zero address', async function () { + const totalSupply = await this.token.totalSupply(); + + await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, value); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(totalSupply); + expectEvent(await this.token.$_update(ZERO_ADDRESS, ZERO_ADDRESS, value), 'Transfer', { + from: ZERO_ADDRESS, + to: ZERO_ADDRESS, + value: value, + }); + }); + }); + + describe('_transfer', function () { + shouldBehaveLikeERC20Transfer(initialHolder, recipient, initialSupply, function (from, to, value) { + return this.token.$_transfer(from, to, value); + }); + + describe('when the sender is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.$_transfer(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20InvalidSender', + [ZERO_ADDRESS], + ); + }); + }); + }); + + describe('_approve', function () { + shouldBehaveLikeERC20Approve(initialHolder, recipient, initialSupply, function (owner, spender, value) { + return this.token.$_approve(owner, spender, value); + }); + + describe('when the owner is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.$_approve(ZERO_ADDRESS, recipient, initialSupply), + 'ERC20InvalidApprover', + [ZERO_ADDRESS], + ); + }); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.behavior.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.behavior.js new file mode 100644 index 0000000..937491b --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.behavior.js @@ -0,0 +1,116 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { ZERO_ADDRESS } = constants; + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +function shouldBehaveLikeERC20Burnable(owner, initialBalance, [burner]) { + describe('burn', function () { + describe('when the given value is not greater than balance of the sender', function () { + context('for a zero value', function () { + shouldBurn(new BN(0)); + }); + + context('for a non-zero value', function () { + shouldBurn(new BN(100)); + }); + + function shouldBurn(value) { + beforeEach(async function () { + this.receipt = await this.token.burn(value, { from: owner }); + }); + + it('burns the requested value', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(value)); + }); + + it('emits a transfer event', async function () { + expectEvent(this.receipt, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + value: value, + }); + }); + } + }); + + describe('when the given value is greater than the balance of the sender', function () { + const value = initialBalance.addn(1); + + it('reverts', async function () { + await expectRevertCustomError(this.token.burn(value, { from: owner }), 'ERC20InsufficientBalance', [ + owner, + initialBalance, + value, + ]); + }); + }); + }); + + describe('burnFrom', function () { + describe('on success', function () { + context('for a zero value', function () { + shouldBurnFrom(new BN(0)); + }); + + context('for a non-zero value', function () { + shouldBurnFrom(new BN(100)); + }); + + function shouldBurnFrom(value) { + const originalAllowance = value.muln(3); + + beforeEach(async function () { + await this.token.approve(burner, originalAllowance, { from: owner }); + this.receipt = await this.token.burnFrom(owner, value, { from: burner }); + }); + + it('burns the requested value', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal(initialBalance.sub(value)); + }); + + it('decrements allowance', async function () { + expect(await this.token.allowance(owner, burner)).to.be.bignumber.equal(originalAllowance.sub(value)); + }); + + it('emits a transfer event', async function () { + expectEvent(this.receipt, 'Transfer', { + from: owner, + to: ZERO_ADDRESS, + value: value, + }); + }); + } + }); + + describe('when the given value is greater than the balance of the sender', function () { + const value = initialBalance.addn(1); + + it('reverts', async function () { + await this.token.approve(burner, value, { from: owner }); + await expectRevertCustomError(this.token.burnFrom(owner, value, { from: burner }), 'ERC20InsufficientBalance', [ + owner, + initialBalance, + value, + ]); + }); + }); + + describe('when the given value is greater than the allowance', function () { + const allowance = new BN(100); + + it('reverts', async function () { + await this.token.approve(burner, allowance, { from: owner }); + await expectRevertCustomError( + this.token.burnFrom(owner, allowance.addn(1), { from: burner }), + 'ERC20InsufficientAllowance', + [burner, allowance, allowance.addn(1)], + ); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20Burnable, +}; diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js new file mode 100644 index 0000000..00acc81 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Burnable.test.js @@ -0,0 +1,20 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { shouldBehaveLikeERC20Burnable } = require('./ERC20Burnable.behavior'); +const ERC20Burnable = artifacts.require('$ERC20Burnable'); + +contract('ERC20Burnable', function (accounts) { + const [owner, ...otherAccounts] = accounts; + + const initialBalance = new BN(1000); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Burnable.new(name, symbol, { from: owner }); + await this.token.$_mint(owner, initialBalance); + }); + + shouldBehaveLikeERC20Burnable(owner, initialBalance, otherAccounts); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.behavior.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.behavior.js new file mode 100644 index 0000000..5af5c3d --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.behavior.js @@ -0,0 +1,31 @@ +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +function shouldBehaveLikeERC20Capped(accounts, cap) { + describe('capped token', function () { + const user = accounts[0]; + + it('starts with the correct cap', async function () { + expect(await this.token.cap()).to.be.bignumber.equal(cap); + }); + + it('mints when value is less than cap', async function () { + await this.token.$_mint(user, cap.subn(1)); + expect(await this.token.totalSupply()).to.be.bignumber.equal(cap.subn(1)); + }); + + it('fails to mint if the value exceeds the cap', async function () { + await this.token.$_mint(user, cap.subn(1)); + await expectRevertCustomError(this.token.$_mint(user, 2), 'ERC20ExceededCap', [cap.addn(1), cap]); + }); + + it('fails to mint after cap is reached', async function () { + await this.token.$_mint(user, cap); + await expectRevertCustomError(this.token.$_mint(user, 1), 'ERC20ExceededCap', [cap.addn(1), cap]); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC20Capped, +}; diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js new file mode 100644 index 0000000..1f4a2be --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Capped.test.js @@ -0,0 +1,24 @@ +const { ether } = require('@openzeppelin/test-helpers'); +const { shouldBehaveLikeERC20Capped } = require('./ERC20Capped.behavior'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC20Capped = artifacts.require('$ERC20Capped'); + +contract('ERC20Capped', function (accounts) { + const cap = ether('1000'); + + const name = 'My Token'; + const symbol = 'MTKN'; + + it('requires a non-zero cap', async function () { + await expectRevertCustomError(ERC20Capped.new(name, symbol, 0), 'ERC20InvalidCap', [0]); + }); + + context('once deployed', async function () { + beforeEach(async function () { + this.token = await ERC20Capped.new(name, symbol, cap); + }); + + shouldBehaveLikeERC20Capped(accounts, cap); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js new file mode 100644 index 0000000..13d5b3e --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20FlashMint.test.js @@ -0,0 +1,210 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const ERC20FlashMintMock = artifacts.require('$ERC20FlashMintMock'); +const ERC3156FlashBorrowerMock = artifacts.require('ERC3156FlashBorrowerMock'); + +contract('ERC20FlashMint', function (accounts) { + const [initialHolder, other, anotherAccount] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + const loanValue = new BN(10000000000000); + + beforeEach(async function () { + this.token = await ERC20FlashMintMock.new(name, symbol); + await this.token.$_mint(initialHolder, initialSupply); + }); + + describe('maxFlashLoan', function () { + it('token match', async function () { + expect(await this.token.maxFlashLoan(this.token.address)).to.be.bignumber.equal(MAX_UINT256.sub(initialSupply)); + }); + + it('token mismatch', async function () { + expect(await this.token.maxFlashLoan(ZERO_ADDRESS)).to.be.bignumber.equal('0'); + }); + }); + + describe('flashFee', function () { + it('token match', async function () { + expect(await this.token.flashFee(this.token.address, loanValue)).to.be.bignumber.equal('0'); + }); + + it('token mismatch', async function () { + await expectRevertCustomError(this.token.flashFee(ZERO_ADDRESS, loanValue), 'ERC3156UnsupportedToken', [ + ZERO_ADDRESS, + ]); + }); + }); + + describe('flashFeeReceiver', function () { + it('default receiver', async function () { + expect(await this.token.$_flashFeeReceiver()).to.be.eq(ZERO_ADDRESS); + }); + }); + + describe('flashLoan', function () { + it('success', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const { tx } = await this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'); + + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver.address, + value: loanValue, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: receiver.address, + to: ZERO_ADDRESS, + value: loanValue, + }); + await expectEvent.inTransaction(tx, receiver, 'BalanceOf', { + token: this.token.address, + account: receiver.address, + value: loanValue, + }); + await expectEvent.inTransaction(tx, receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(loanValue), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply); + expect(await this.token.balanceOf(receiver.address)).to.be.bignumber.equal('0'); + expect(await this.token.allowance(receiver.address, this.token.address)).to.be.bignumber.equal('0'); + }); + + it('missing return value', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(false, true); + await expectRevertCustomError( + this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'), + 'ERC3156InvalidReceiver', + [receiver.address], + ); + }); + + it('missing approval', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, false); + await expectRevertCustomError( + this.token.flashLoan(receiver.address, this.token.address, loanValue, '0x'), + 'ERC20InsufficientAllowance', + [this.token.address, 0, loanValue], + ); + }); + + it('unavailable funds', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const data = this.token.contract.methods.transfer(other, 10).encodeABI(); + await expectRevertCustomError( + this.token.flashLoan(receiver.address, this.token.address, loanValue, data), + 'ERC20InsufficientBalance', + [receiver.address, loanValue - 10, loanValue], + ); + }); + + it('more than maxFlashLoan', async function () { + const receiver = await ERC3156FlashBorrowerMock.new(true, true); + const data = this.token.contract.methods.transfer(other, 10).encodeABI(); + // _mint overflow reverts using a panic code. No reason string. + await expectRevert.unspecified(this.token.flashLoan(receiver.address, this.token.address, MAX_UINT256, data)); + }); + + describe('custom flash fee & custom fee receiver', function () { + const receiverInitialBalance = new BN(200000); + const flashFee = new BN(5000); + + beforeEach('init receiver balance & set flash fee', async function () { + this.receiver = await ERC3156FlashBorrowerMock.new(true, true); + const receipt = await this.token.$_mint(this.receiver.address, receiverInitialBalance); + await expectEvent(receipt, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: receiverInitialBalance, + }); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal(receiverInitialBalance); + + await this.token.setFlashFee(flashFee); + expect(await this.token.flashFee(this.token.address, loanValue)).to.be.bignumber.equal(flashFee); + }); + + it('default flash fee receiver', async function () { + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanValue, '0x'); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: loanValue, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: ZERO_ADDRESS, + value: loanValue.add(flashFee), + }); + await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { + token: this.token.address, + account: this.receiver.address, + value: receiverInitialBalance.add(loanValue), + }); + await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(receiverInitialBalance).add(loanValue), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal( + initialSupply.add(receiverInitialBalance).sub(flashFee), + ); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal( + receiverInitialBalance.sub(flashFee), + ); + expect(await this.token.balanceOf(await this.token.$_flashFeeReceiver())).to.be.bignumber.equal('0'); + expect(await this.token.allowance(this.receiver.address, this.token.address)).to.be.bignumber.equal('0'); + }); + + it('custom flash fee receiver', async function () { + const flashFeeReceiverAddress = anotherAccount; + await this.token.setFlashFeeReceiver(flashFeeReceiverAddress); + expect(await this.token.$_flashFeeReceiver()).to.be.eq(flashFeeReceiverAddress); + + expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal('0'); + + const { tx } = await this.token.flashLoan(this.receiver.address, this.token.address, loanValue, '0x'); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: this.receiver.address, + value: loanValue, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: ZERO_ADDRESS, + value: loanValue, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.receiver.address, + to: flashFeeReceiverAddress, + value: flashFee, + }); + await expectEvent.inTransaction(tx, this.receiver, 'BalanceOf', { + token: this.token.address, + account: this.receiver.address, + value: receiverInitialBalance.add(loanValue), + }); + await expectEvent.inTransaction(tx, this.receiver, 'TotalSupply', { + token: this.token.address, + value: initialSupply.add(receiverInitialBalance).add(loanValue), + }); + + expect(await this.token.totalSupply()).to.be.bignumber.equal(initialSupply.add(receiverInitialBalance)); + expect(await this.token.balanceOf(this.receiver.address)).to.be.bignumber.equal( + receiverInitialBalance.sub(flashFee), + ); + expect(await this.token.balanceOf(flashFeeReceiverAddress)).to.be.bignumber.equal(flashFee); + expect(await this.token.allowance(this.receiver.address, flashFeeReceiverAddress)).to.be.bignumber.equal('0'); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js new file mode 100644 index 0000000..92c90b9 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Pausable.test.js @@ -0,0 +1,136 @@ +const { BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC20Pausable = artifacts.require('$ERC20Pausable'); + +contract('ERC20Pausable', function (accounts) { + const [holder, recipient, anotherAccount] = accounts; + + const initialSupply = new BN(100); + + const name = 'My Token'; + const symbol = 'MTKN'; + + beforeEach(async function () { + this.token = await ERC20Pausable.new(name, symbol); + await this.token.$_mint(holder, initialSupply); + }); + + describe('pausable token', function () { + describe('transfer', function () { + it('allows to transfer when unpaused', async function () { + await this.token.transfer(recipient, initialSupply, { from: holder }); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.transfer(recipient, initialSupply, { from: holder }); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal('0'); + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(initialSupply); + }); + + it('reverts when trying to transfer when paused', async function () { + await this.token.$_pause(); + + await expectRevertCustomError( + this.token.transfer(recipient, initialSupply, { from: holder }), + 'EnforcedPause', + [], + ); + }); + }); + + describe('transfer from', function () { + const allowance = new BN(40); + + beforeEach(async function () { + await this.token.approve(anotherAccount, allowance, { from: holder }); + }); + + it('allows to transfer from when unpaused', async function () { + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); + }); + + it('allows to transfer when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(allowance); + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(allowance)); + }); + + it('reverts when trying to transfer from when paused', async function () { + await this.token.$_pause(); + + await expectRevertCustomError( + this.token.transferFrom(holder, recipient, allowance, { from: anotherAccount }), + 'EnforcedPause', + [], + ); + }); + }); + + describe('mint', function () { + const value = new BN('42'); + + it('allows to mint when unpaused', async function () { + await this.token.$_mint(recipient, value); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); + }); + + it('allows to mint when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.$_mint(recipient, value); + + expect(await this.token.balanceOf(recipient)).to.be.bignumber.equal(value); + }); + + it('reverts when trying to mint when paused', async function () { + await this.token.$_pause(); + + await expectRevertCustomError(this.token.$_mint(recipient, value), 'EnforcedPause', []); + }); + }); + + describe('burn', function () { + const value = new BN('42'); + + it('allows to burn when unpaused', async function () { + await this.token.$_burn(holder, value); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(value)); + }); + + it('allows to burn when paused and then unpaused', async function () { + await this.token.$_pause(); + await this.token.$_unpause(); + + await this.token.$_burn(holder, value); + + expect(await this.token.balanceOf(holder)).to.be.bignumber.equal(initialSupply.sub(value)); + }); + + it('reverts when trying to burn when paused', async function () { + await this.token.$_pause(); + + await expectRevertCustomError(this.token.$_burn(holder, value), 'EnforcedPause', []); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js new file mode 100644 index 0000000..388716d --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Permit.test.js @@ -0,0 +1,118 @@ +/* eslint-disable */ + +const { BN, constants, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256 } = constants; + +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const ERC20Permit = artifacts.require('$ERC20Permit'); + +const { Permit, getDomain, domainType, domainSeparator } = require('../../../helpers/eip712'); +const { getChainId } = require('../../../helpers/chainid'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +contract('ERC20Permit', function (accounts) { + const [initialHolder, spender] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.chainId = await getChainId(); + + this.token = await ERC20Permit.new(name, symbol, name); + await this.token.$_mint(initialHolder, initialSupply); + }); + + it('initial nonce is 0', async function () { + expect(await this.token.nonces(initialHolder)).to.be.bignumber.equal('0'); + }); + + it('domain separator', async function () { + expect(await this.token.DOMAIN_SEPARATOR()).to.equal(await getDomain(this.token).then(domainSeparator)); + }); + + describe('permit', function () { + const wallet = Wallet.generate(); + + const owner = wallet.getAddressString(); + const value = new BN(42); + const nonce = 0; + const maxDeadline = MAX_UINT256; + + 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 { 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); + + expect(await this.token.nonces(owner)).to.be.bignumber.equal('1'); + expect(await this.token.allowance(owner, spender)).to.be.bignumber.equal(value); + }); + + it('rejects reused signature', async function () { + const sig = await buildData(this.token).then(data => + ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data }), + ); + const { r, s, v } = fromRpcSig(sig); + + await this.token.permit(owner, spender, value, maxDeadline, v, r, s); + + const domain = await getDomain(this.token); + const typedMessage = { + primaryType: 'Permit', + types: { EIP712Domain: domainType(domain), Permit }, + domain, + message: { owner, spender, value, nonce: nonce + 1, deadline: maxDeadline }, + }; + + await expectRevertCustomError( + this.token.permit(owner, spender, value, maxDeadline, v, r, s), + 'ERC2612InvalidSigner', + [ethSigUtil.recoverTypedSignature({ data: typedMessage, sig }), owner], + ); + }); + + it('rejects other signature', async function () { + const otherWallet = Wallet.generate(); + + const { v, r, s } = await buildData(this.token) + .then(data => ethSigUtil.signTypedMessage(otherWallet.getPrivateKey(), { data })) + .then(fromRpcSig); + + await expectRevertCustomError( + this.token.permit(owner, spender, value, maxDeadline, v, r, s), + 'ERC2612InvalidSigner', + [await otherWallet.getAddressString(), owner], + ); + }); + + it('rejects expired permit', async function () { + const deadline = (await time.latest()) - time.duration.weeks(1); + + const { v, r, s } = await buildData(this.token, deadline) + .then(data => ethSigUtil.signTypedMessage(wallet.getPrivateKey(), { data })) + .then(fromRpcSig); + + await expectRevertCustomError( + this.token.permit(owner, spender, value, deadline, v, r, s), + 'ERC2612ExpiredSignature', + [deadline], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js new file mode 100644 index 0000000..faf1a15 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Votes.test.js @@ -0,0 +1,593 @@ +/* eslint-disable */ + +const { BN, constants, expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256, ZERO_ADDRESS } = constants; + +const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); +const { fromRpcSig } = require('ethereumjs-util'); +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { batchInBlock } = require('../../../helpers/txpool'); +const { getDomain, domainType } = require('../../../helpers/eip712'); +const { clock, clockFromReceipt } = require('../../../helpers/time'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const Delegation = [ + { name: 'delegatee', type: 'address' }, + { name: 'nonce', type: 'uint256' }, + { 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'); + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.token = await artifact.new(name, symbol, name, version); + this.votes = this.token; + }); + + // includes EIP6372 behavior check + shouldBehaveLikeVotes(accounts, [1, 17, 42], { mode, fungible: true }); + + it('initial nonce is 0', async function () { + expect(await this.token.nonces(holder)).to.be.bignumber.equal('0'); + }); + + it('minting restriction', async function () { + const value = web3.utils.toBN(1).shln(208); + await expectRevertCustomError(this.token.$_mint(holder, value), 'ERC20ExceededSafeSupply', [ + value, + value.subn(1), + ]); + }); + + 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 timepoint = await clock[mode](); + expect(await this.token.numCheckpoints(holder)).to.be.bignumber.equal('6'); + // recent + expect(await this.token.getPastVotes(holder, timepoint - 1)).to.be.bignumber.equal('5'); + // non-recent + expect(await this.token.getPastVotes(holder, timepoint - 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, + previousVotes: '0', + newVotes: 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); + }); + }); + + 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, + })); + + 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, + previousVotes: '0', + newVotes: 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 expectRevertCustomError( + this.token.delegateBySig(delegatorAddress, nonce, MAX_UINT256, v, r, s), + 'InvalidAccountNonce', + [delegatorAddress, nonce + 1], + ); + }); + + 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 sig = await buildData(this.token, { + delegatee: delegatorAddress, + nonce, + expiry: MAX_UINT256, + }).then(data => ethSigUtil.signTypedMessage(delegator.getPrivateKey(), { data })); + const { r, s, v } = fromRpcSig(sig); + + const domain = await getDomain(this.token); + const typedMessage = { + primaryType: 'Delegation', + types: { EIP712Domain: domainType(domain), Delegation }, + domain, + message: { delegatee: delegatorAddress, nonce: nonce + 1, expiry: MAX_UINT256 }, + }; + + await expectRevertCustomError( + this.token.delegateBySig(delegatorAddress, nonce + 1, MAX_UINT256, v, r, s), + 'InvalidAccountNonce', + [ethSigUtil.recoverTypedSignature({ data: typedMessage, sig }), 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 expectRevertCustomError( + this.token.delegateBySig(delegatorAddress, nonce, expiry, v, r, s), + 'VotesExpiredSignature', + [expiry], + ); + }); + }); + }); + + 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 }); + const timepoint = await clockFromReceipt[mode](receipt); + + expectEvent(receipt, 'DelegateChanged', { + delegator: holder, + fromDelegate: holder, + toDelegate: holderDelegatee, + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holder, + previousVotes: supply, + newVotes: '0', + }); + expectEvent(receipt, 'DelegateVotesChanged', { + delegate: holderDelegatee, + previousVotes: '0', + newVotes: 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); + }); + }); + + 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, + previousVotes: supply, + newVotes: 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, previousVotes: '0', newVotes: '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, + previousVotes: supply, + newVotes: supply.subn(1), + }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: recipient, previousVotes: '0', newVotes: '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); + }); + }); + + // 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 }); + 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: 200000 }), + () => this.token.transfer(other2, 10, { from: recipient, gas: 200000 }), + () => this.token.transfer(other2, 10, { from: recipient, gas: 200000 }), + ]); + 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 () { + const clock = await this.token.clock(); + await expectRevertCustomError(this.token.getPastVotes(other1, 5e10), 'ERC5805FutureLookup', [5e10, clock]); + }); + + 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', + ); + }); + }); + }); + + describe('getPastTotalSupply', function () { + beforeEach(async function () { + await this.token.delegate(holder, { from: holder }); + }); + + it('reverts if block number >= current block', async function () { + const clock = await this.token.clock(); + await expectRevertCustomError(this.token.getPastTotalSupply(5e10), 'ERC5805FutureLookup', [5e10, clock]); + }); + + 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', + ); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js new file mode 100644 index 0000000..c54a9e0 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC20Wrapper.test.js @@ -0,0 +1,211 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS, MAX_UINT256 } = constants; + +const { shouldBehaveLikeERC20 } = require('../ERC20.behavior'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const NotAnERC20 = artifacts.require('CallReceiverMock'); +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); +const ERC20Wrapper = artifacts.require('$ERC20Wrapper'); + +contract('ERC20Wrapper', function (accounts) { + const [initialHolder, receiver] = accounts; + + const name = 'My Token'; + const symbol = 'MTKN'; + + const initialSupply = new BN(100); + + beforeEach(async function () { + this.underlying = await ERC20Decimals.new(name, symbol, 9); + await this.underlying.$_mint(initialHolder, initialSupply); + + this.token = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, this.underlying.address); + }); + + afterEach(async function () { + expect(await this.underlying.balanceOf(this.token.address)).to.be.bignumber.equal(await this.token.totalSupply()); + }); + + 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 the same decimals as the underlying token', async function () { + expect(await this.token.decimals()).to.be.bignumber.equal('9'); + }); + + it('decimals default back to 18 if token has no metadata', async function () { + const noDecimals = await NotAnERC20.new(); + const otherToken = await ERC20Wrapper.new(`Wrapped ${name}`, `W${symbol}`, noDecimals.address); + expect(await otherToken.decimals()).to.be.bignumber.equal('18'); + }); + + it('has underlying', async function () { + expect(await this.token.underlying()).to.be.bignumber.equal(this.underlying.address); + }); + + describe('deposit', function () { + it('valid', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + const { tx } = await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: initialHolder, + value: initialSupply, + }); + }); + + it('missing approval', async function () { + await expectRevertCustomError( + this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }), + 'ERC20InsufficientAllowance', + [this.token.address, 0, initialSupply], + ); + }); + + it('missing balance', async function () { + await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder }); + await expectRevertCustomError( + this.token.depositFor(initialHolder, MAX_UINT256, { from: initialHolder }), + 'ERC20InsufficientBalance', + [initialHolder, initialSupply, MAX_UINT256], + ); + }); + + it('to other account', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + const { tx } = await this.token.depositFor(receiver, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: initialHolder, + to: this.token.address, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver, + value: initialSupply, + }); + }); + + it('reverts minting to the wrapper contract', async function () { + await this.underlying.approve(this.token.address, MAX_UINT256, { from: initialHolder }); + await expectRevertCustomError( + this.token.depositFor(this.token.address, MAX_UINT256, { from: initialHolder }), + 'ERC20InvalidReceiver', + [this.token.address], + ); + }); + }); + + describe('withdraw', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + }); + + it('missing balance', async function () { + await expectRevertCustomError( + this.token.withdrawTo(initialHolder, MAX_UINT256, { from: initialHolder }), + 'ERC20InsufficientBalance', + [initialHolder, initialSupply, MAX_UINT256], + ); + }); + + it('valid', async function () { + const value = new BN(42); + + const { tx } = await this.token.withdrawTo(initialHolder, value, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + value: value, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: value, + }); + }); + + it('entire balance', async function () { + const { tx } = await this.token.withdrawTo(initialHolder, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: initialHolder, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: initialSupply, + }); + }); + + it('to other account', async function () { + const { tx } = await this.token.withdrawTo(receiver, initialSupply, { from: initialHolder }); + await expectEvent.inTransaction(tx, this.underlying, 'Transfer', { + from: this.token.address, + to: receiver, + value: initialSupply, + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: initialHolder, + to: ZERO_ADDRESS, + value: initialSupply, + }); + }); + + it('reverts withdrawing to the wrapper contract', async function () { + expectRevertCustomError( + this.token.withdrawTo(this.token.address, initialSupply, { from: initialHolder }), + 'ERC20InvalidReceiver', + [this.token.address], + ); + }); + }); + + describe('recover', function () { + it('nothing to recover', async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + + const { tx } = await this.token.$_recover(receiver); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver, + value: '0', + }); + }); + + it('something to recover', async function () { + await this.underlying.transfer(this.token.address, initialSupply, { from: initialHolder }); + + const { tx } = await this.token.$_recover(receiver); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: ZERO_ADDRESS, + to: receiver, + value: initialSupply, + }); + }); + }); + + describe('erc20 behaviour', function () { + beforeEach(async function () { + await this.underlying.approve(this.token.address, initialSupply, { from: initialHolder }); + await this.token.depositFor(initialHolder, initialSupply, { from: initialHolder }); + }); + + shouldBehaveLikeERC20(initialSupply, accounts); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol new file mode 100644 index 0000000..72b0dac --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.t.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ERC4626Test} from "erc4626-tests/ERC4626.test.sol"; + +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ERC4626} from "@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol"; + +import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol"; +import {ERC4626Mock} from "@openzeppelin/contracts/mocks/token/ERC4626Mock.sol"; +import {ERC4626OffsetMock} from "@openzeppelin/contracts/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(_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/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js new file mode 100644 index 0000000..fa66785 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/extensions/ERC4626.test.js @@ -0,0 +1,1109 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { Enum } = require('../../../helpers/enums'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC20Decimals = artifacts.require('$ERC20DecimalsMock'); +const ERC4626 = artifacts.require('$ERC4626'); +const ERC4626LimitsMock = artifacts.require('$ERC4626LimitsMock'); +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; + + const name = 'My Token'; + const symbol = 'MTKN'; + 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)) { + const token = await ERC20Decimals.new('', '', decimals); + const vault = await ERC4626.new('', '', token.address); + expect(await vault.decimals()).to.be.bignumber.equal(decimals); + } + }); + + 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)', + ); + } + }); + + describe('reentrancy', async function () { + const reenterType = Enum('No', 'Before', 'After'); + + const value = web3.utils.toBN(1000000000000000000); + const reenterValue = 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, value); + await token.$_mint(other, value); + 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, reenterValue); + + // Schedules a reentrancy from the token contract + await token.scheduleReenter( + reenterType.Before, + vault.address, + vault.contract.methods.deposit(reenterValue, holder).encodeABI(), + ); + + // Initial share price + const sharesForDeposit = await vault.previewDeposit(value, { from: holder }); + const sharesForReenter = await vault.previewDeposit(reenterValue, { from: holder }); + + // Deposit normally, reentering before the internal `_update` + const receipt = await vault.deposit(value, holder, { from: holder }); + + // Main deposit event + await expectEvent(receipt, 'Deposit', { + sender: holder, + owner: holder, + assets: value, + shares: sharesForDeposit, + }); + // Reentrant deposit event → uses the same price + await expectEvent(receipt, 'Deposit', { + sender: token.address, + owner: holder, + assets: reenterValue, + shares: sharesForReenter, + }); + + // Assert prices is kept + const sharesAfter = await vault.previewDeposit(value, { 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 `value` share, token.address gets `reenterValue` shares + await vault.deposit(value, holder, { from: holder }); + await vault.deposit(reenterValue, token.address, { from: other }); + + // Schedules a reentrancy from the token contract + await token.scheduleReenter( + reenterType.After, + vault.address, + vault.contract.methods.withdraw(reenterValue, holder, token.address).encodeABI(), + ); + + // Initial share price + const sharesForWithdraw = await vault.previewWithdraw(value, { from: holder }); + const sharesForReenter = await vault.previewWithdraw(reenterValue, { from: holder }); + + // Do withdraw normally, triggering the _afterTokenTransfer hook + const receipt = await vault.withdraw(value, holder, holder, { from: holder }); + + // Main withdraw event + await expectEvent(receipt, 'Withdraw', { + sender: holder, + receiver: holder, + owner: holder, + assets: value, + shares: sharesForWithdraw, + }); + // Reentrant withdraw event → uses the same price + await expectEvent(receipt, 'Withdraw', { + sender: token.address, + receiver: holder, + owner: token.address, + assets: reenterValue, + shares: sharesForReenter, + }); + + // Assert price is kept + const sharesAfter = await vault.previewWithdraw(value, { 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 value 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, reenterValue).encodeABI(), + ); + + // Price before + const sharesBefore = await vault.previewDeposit(value); + + // Deposit, reentering before the internal `_update` + const receipt = await vault.deposit(value, holder, { from: holder }); + + // Price is as previewed + await expectEvent(receipt, 'Deposit', { + sender: holder, + owner: holder, + assets: value, + shares: sharesBefore, + }); + + // Price was modified during reentrancy + const sharesAfter = await vault.previewDeposit(value); + 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 value of assets) + it('share price change during reentracy does not affect withdraw', async function () { + await vault.deposit(value, other, { from: other }); + await vault.deposit(value, 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, reenterValue).encodeABI(), + ); + + // Price before + const sharesBefore = await vault.previewWithdraw(value); + + // Withdraw, triggering the _afterTokenTransfer hook + const receipt = await vault.withdraw(value, holder, holder, { from: holder }); + + // Price is as previewed + await expectEvent(receipt, 'Withdraw', { + sender: holder, + receiver: holder, + owner: holder, + assets: value, + shares: sharesBefore, + }); + + // Price was modified during reentrancy + const sharesAfter = await vault.previewWithdraw(value); + expect(sharesAfter).to.be.bignumber.gt(sharesBefore); + }); + }); + + describe('limits', async function () { + beforeEach(async function () { + this.token = await ERC20Decimals.new(name, symbol, decimals); + this.vault = await ERC4626LimitsMock.new(name + ' Vault', symbol + 'V', this.token.address); + }); + + it('reverts on deposit() above max deposit', async function () { + const maxDeposit = await this.vault.maxDeposit(holder); + await expectRevertCustomError(this.vault.deposit(maxDeposit.addn(1), recipient), 'ERC4626ExceededMaxDeposit', [ + recipient, + maxDeposit.addn(1), + maxDeposit, + ]); + }); + + it('reverts on mint() above max mint', async function () { + const maxMint = await this.vault.maxMint(holder); + await expectRevertCustomError(this.vault.mint(maxMint.addn(1), recipient), 'ERC4626ExceededMaxMint', [ + recipient, + maxMint.addn(1), + maxMint, + ]); + }); + + it('reverts on withdraw() above max withdraw', async function () { + const maxWithdraw = await this.vault.maxWithdraw(holder); + await expectRevertCustomError( + this.vault.withdraw(maxWithdraw.addn(1), recipient, holder), + 'ERC4626ExceededMaxWithdraw', + [holder, maxWithdraw.addn(1), maxWithdraw], + ); + }); + + it('reverts on redeem() above max redeem', async function () { + const maxRedeem = await this.vault.maxRedeem(holder); + await expectRevertCustomError( + this.vault.redeem(maxRedeem.addn(1), recipient, holder), + 'ERC4626ExceededMaxRedeem', + [holder, maxRedeem.addn(1), maxRedeem], + ); + }); + }); + + 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); + + const virtualAssets = web3.utils.toBN(1); + const virtualShares = web3.utils.toBN(10).pow(offset); + + 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 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 }); + }); + + 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), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: parseToken(1), + shares: 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), + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: parseToken(1), + shares: 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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: depositAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: expectedAssets, + shares: 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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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', + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: '0', + shares: '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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: depositAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: expectedAssets, + shares: 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, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: withdrawAssets, + shares: expectedShares, + }); + }); + + it('withdraw with approval', async function () { + const assets = await this.vault.previewWithdraw(parseToken(1)); + await expectRevertCustomError( + this.vault.withdraw(parseToken(1), recipient, holder, { from: other }), + 'ERC20InsufficientAllowance', + [other, 0, assets], + ); + + await this.vault.withdraw(parseToken(1), recipient, holder, { from: spender }); + }); + + it('redeem', 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 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: expectedAssets, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: holder, + to: constants.ZERO_ADDRESS, + value: redeemShares, + }); + + await expectEvent.inTransaction(tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: expectedAssets, + shares: redeemShares, + }); + }); + + it('redeem with approval', async function () { + await expectRevertCustomError( + this.vault.redeem(parseShare(100), recipient, holder, { from: other }), + 'ERC20InsufficientAllowance', + [other, 0, parseShare(100)], + ); + + await this.vault.redeem(parseShare(100), recipient, holder, { from: spender }); + }); + }); + }); + } + + describe('ERC4626Fees', function () { + const feeBasisPoints = web3.utils.toBN(5e3); + const valueWithoutFees = web3.utils.toBN(10000); + const fees = valueWithoutFees.mul(feeBasisPoints).divn(1e4); + const valueWithFees = valueWithoutFees.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, + feeBasisPoints, + 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(valueWithFees)).to.be.bignumber.equal(valueWithoutFees); + ({ tx: this.tx } = await this.vault.deposit(valueWithFees, recipient, { from: holder })); + }); + + it('mint', async function () { + expect(await this.vault.previewMint(valueWithoutFees)).to.be.bignumber.equal(valueWithFees); + ({ tx: this.tx } = await this.vault.mint(valueWithoutFees, recipient, { from: holder })); + }); + + afterEach(async function () { + // get total + await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { + from: holder, + to: this.vault.address, + value: valueWithFees, + }); + + // 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: valueWithoutFees, + }); + + // deposit event + await expectEvent.inTransaction(this.tx, this.vault, 'Deposit', { + sender: holder, + owner: recipient, + assets: valueWithFees, + shares: valueWithoutFees, + }); + }); + }); + + 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(valueWithFees)).to.be.bignumber.equal(valueWithoutFees); + ({ tx: this.tx } = await this.vault.redeem(valueWithFees, recipient, holder, { from: holder })); + }); + + it('withdraw', async function () { + expect(await this.vault.previewWithdraw(valueWithoutFees)).to.be.bignumber.equal(valueWithFees); + ({ tx: this.tx } = await this.vault.withdraw(valueWithoutFees, recipient, holder, { from: holder })); + }); + + afterEach(async function () { + // withdraw principal + await expectEvent.inTransaction(this.tx, this.token, 'Transfer', { + from: this.vault.address, + to: recipient, + value: valueWithoutFees, + }); + + // 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: valueWithFees, + }); + + // withdraw event + await expectEvent.inTransaction(this.tx, this.vault, 'Withdraw', { + sender: holder, + receiver: recipient, + owner: holder, + assets: valueWithoutFees, + shares: valueWithFees, + }); + }); + }); + }); + + /// 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 () { + // test designed with both asset using similar decimals + this.token = await ERC20Decimals.new(name, symbol, 18); + this.vault = await ERC4626.new(name + ' Vault', symbol + 'V', this.token.address); + + await this.token.$_mint(user1, 4000); + await this.token.$_mint(user2, 7001); + await this.token.approve(this.vault.address, 4000, { from: user1 }); + await this.token.approve(this.vault.address, 7001, { from: user2 }); + + // 1. Alice mints 2000 shares (costs 2000 tokens) + { + const { tx } = await this.vault.mint(2000, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user1, + to: this.vault.address, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + value: '2000', + }); + + expect(await this.vault.previewDeposit(2000)).to.be.bignumber.equal('2000'); + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user1))).to.be.bignumber.equal('2000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('0'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '2000', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('2000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('2000'); + } + + // 2. Bob deposits 4000 tokens (mints 4000 shares) + { + const { tx } = await this.vault.mint(4000, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user2, + to: this.vault.address, + value: '4000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + value: '4000', + }); + + expect(await this.vault.previewDeposit(4000)).to.be.bignumber.equal('4000'); + 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('2000'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('4000'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '6000', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('6000'); + } + + // 3. Vault mutates by +3000 tokens (simulated yield returned from strategy) + await this.token.$_mint(this.vault.address, 3000); + + 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('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.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '6000', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('9000'); + + // 4. Alice deposits 2000 tokens (mints 1333 shares) + { + const { tx } = await this.vault.deposit(2000, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user1, + to: this.vault.address, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + value: '1333', + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('3333'); + 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('4999'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('6000'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '7333', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('7333'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('11000'); + } + + // 5. Bob mints 2000 shares (costs 3001 assets) + // NOTE: Bob's assets spent got rounded towards infinity + // NOTE: Alices's vault assets got rounded towards infinity + { + const { tx } = await this.vault.mint(2000, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: user2, + to: this.vault.address, + value: '3000', // used to be 3001 + }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + value: '2000', + }); + + 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('4999'); // used to be 5000 + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('9000'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '9333', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('9333'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('14000'); // used to be 14001 + } + + // 6. Vault mutates by +3000 tokens + // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000. + await this.token.$_mint(this.vault.address, 3000); + + 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('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.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '9333', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('9333'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('17000'); // used to be 17001 + + // 7. Alice redeem 1333 shares (2428 assets) + { + const { tx } = await this.vault.redeem(1333, user1, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + value: '1333', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user1, + value: '2427', // used to be 2428 + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + 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('3643'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('10929'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '8000', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('8000'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('14573'); + } + + // 8. Bob withdraws 2929 assets (1608 shares) + { + const { tx } = await this.vault.withdraw(2929, user2, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user2, + to: constants.ZERO_ADDRESS, + value: '1608', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user2, + value: '2929', + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('2000'); + 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('3643'); + expect(await this.vault.convertToAssets(await this.vault.balanceOf(user2))).to.be.bignumber.equal('8000'); + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '6392', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('6392'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('11644'); + } + + // 9. Alice withdraws 3643 assets (2000 shares) + // NOTE: Bob's assets have been rounded back towards infinity + { + const { tx } = await this.vault.withdraw(3643, user1, user1, { from: user1 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + value: '2000', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user1, + value: '3643', + }); + + 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('8000'); // used to be 8001 + expect(await this.vault.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '4392', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('4392'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('8001'); + } + + // 10. Bob redeem 4392 shares (8001 tokens) + { + const { tx } = await this.vault.redeem(4392, user2, user2, { from: user2 }); + await expectEvent.inTransaction(tx, this.vault, 'Transfer', { + from: user2, + to: constants.ZERO_ADDRESS, + value: '4392', + }); + await expectEvent.inTransaction(tx, this.token, 'Transfer', { + from: this.vault.address, + to: user2, + value: '8000', // used to be 8001 + }); + + expect(await this.vault.balanceOf(user1)).to.be.bignumber.equal('0'); + expect(await this.vault.balanceOf(user2)).to.be.bignumber.equal('0'); + 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.convertToShares(await this.token.balanceOf(this.vault.address))).to.be.bignumber.equal( + '0', + ); + expect(await this.vault.totalSupply()).to.be.bignumber.equal('0'); + expect(await this.vault.totalAssets()).to.be.bignumber.equal('1'); // used to be 0 + } + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js b/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js new file mode 100644 index 0000000..4ff27f1 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC20/utils/SafeERC20.test.js @@ -0,0 +1,240 @@ +const { constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); + +const SafeERC20 = artifacts.require('$SafeERC20'); +const ERC20ReturnFalseMock = artifacts.require('$ERC20ReturnFalseMock'); +const ERC20ReturnTrueMock = artifacts.require('$ERC20'); // default implementation returns true +const ERC20NoReturnMock = artifacts.require('$ERC20NoReturnMock'); +const ERC20ForceApproveMock = artifacts.require('$ERC20ForceApproveMock'); + +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const name = 'ERC20Mock'; +const symbol = 'ERC20Mock'; + +contract('SafeERC20', function (accounts) { + const [hasNoCode, receiver, spender] = accounts; + + before(async function () { + this.mock = await SafeERC20.new(); + }); + + describe('with address that has no contract code', function () { + beforeEach(async function () { + this.token = { address: hasNoCode }; + }); + + it('reverts on transfer', async function () { + await expectRevertCustomError(this.mock.$safeTransfer(this.token.address, receiver, 0), 'AddressEmptyCode', [ + this.token.address, + ]); + }); + + it('reverts on transferFrom', async function () { + await expectRevertCustomError( + this.mock.$safeTransferFrom(this.token.address, this.mock.address, receiver, 0), + 'AddressEmptyCode', + [this.token.address], + ); + }); + + it('reverts on increaseAllowance', async function () { + // Call to 'token.allowance' does not return any data, resulting in a decoding error (revert without reason) + await expectRevert.unspecified(this.mock.$safeIncreaseAllowance(this.token.address, spender, 0)); + }); + + it('reverts on decreaseAllowance', async function () { + // Call to 'token.allowance' does not return any data, resulting in a decoding error (revert without reason) + await expectRevert.unspecified(this.mock.$safeDecreaseAllowance(this.token.address, spender, 0)); + }); + + it('reverts on forceApprove', async function () { + await expectRevertCustomError(this.mock.$forceApprove(this.token.address, spender, 0), 'AddressEmptyCode', [ + this.token.address, + ]); + }); + }); + + describe('with token that returns false on all calls', function () { + beforeEach(async function () { + this.token = await ERC20ReturnFalseMock.new(name, symbol); + }); + + it('reverts on transfer', async function () { + await expectRevertCustomError( + this.mock.$safeTransfer(this.token.address, receiver, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + + it('reverts on transferFrom', async function () { + await expectRevertCustomError( + this.mock.$safeTransferFrom(this.token.address, this.mock.address, receiver, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + + it('reverts on increaseAllowance', async function () { + await expectRevertCustomError( + this.mock.$safeIncreaseAllowance(this.token.address, spender, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + + it('reverts on decreaseAllowance', async function () { + await expectRevertCustomError( + this.mock.$safeDecreaseAllowance(this.token.address, spender, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + + it('reverts on forceApprove', async function () { + await expectRevertCustomError( + this.mock.$forceApprove(this.token.address, spender, 0), + 'SafeERC20FailedOperation', + [this.token.address], + ); + }); + }); + + describe('with token that returns true on all calls', function () { + beforeEach(async function () { + this.token = await ERC20ReturnTrueMock.new(name, symbol); + }); + + shouldOnlyRevertOnErrors(accounts); + }); + + describe('with token that returns no boolean values', function () { + beforeEach(async function () { + this.token = await ERC20NoReturnMock.new(name, symbol); + }); + + shouldOnlyRevertOnErrors(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('safeIncreaseAllowance works', async function () { + await this.mock.$safeIncreaseAllowance(this.token.address, spender, 10); + expect(this.token.allowance(this.mock.address, spender, 90)); + }); + + it('safeDecreaseAllowance works', async function () { + await this.mock.$safeDecreaseAllowance(this.token.address, spender, 10); + expect(this.token.allowance(this.mock.address, spender, 110)); + }); + + it('forceApprove works', async function () { + await this.mock.$forceApprove(this.token.address, spender, 200); + expect(this.token.allowance(this.mock.address, spender, 200)); + }); + }); + }); +}); + +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 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.$_approve(this.mock.address, spender, 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, 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 expectRevertCustomError( + this.mock.$safeDecreaseAllowance(this.token.address, spender, 10), + 'SafeERC20FailedDecreaseAllowance', + [spender, 0, 10], + ); + }); + }); + + context('with non-zero allowance', function () { + beforeEach(async function () { + await this.token.$_approve(this.mock.address, spender, 100); + }); + + 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, 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, 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 expectRevertCustomError( + this.mock.$safeDecreaseAllowance(this.token.address, spender, 200), + 'SafeERC20FailedDecreaseAllowance', + [spender, 100, 200], + ); + }); + }); + }); +} diff --git a/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js b/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js new file mode 100644 index 0000000..10f8482 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/ERC721.behavior.js @@ -0,0 +1,978 @@ +const { BN, constants, expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { Enum } = require('../../helpers/enums'); + +const ERC721ReceiverMock = artifacts.require('ERC721ReceiverMock'); +const NonERC721ReceiverMock = artifacts.require('CallReceiverMock'); + +const RevertType = Enum('None', 'RevertWithoutMessage', 'RevertWithMessage', 'RevertWithCustomError', 'Panic'); + +const firstTokenId = new BN('5042'); +const secondTokenId = new BN('79217'); +const nonExistentTokenId = new BN('13'); +const fourthTokenId = new BN(4); +const baseURI = 'https://api.example.com/v1/'; + +const RECEIVER_MAGIC_VALUE = '0x150b7a02'; + +function shouldBehaveLikeERC721(owner, newOwner, approved, anotherApproved, operator, other) { + shouldSupportInterfaces(['ERC165', 'ERC721']); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + this.toWhom = other; // default to other for toWhom in context-dependent tests + }); + + describe('balanceOf', function () { + context('when the given address owns some tokens', function () { + it('returns the amount of tokens owned by the given address', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('2'); + }); + }); + + context('when the given address does not own any tokens', function () { + it('returns 0', async function () { + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('0'); + }); + }); + + context('when querying the zero address', function () { + it('throws', async function () { + await expectRevertCustomError(this.token.balanceOf(ZERO_ADDRESS), 'ERC721InvalidOwner', [ZERO_ADDRESS]); + }); + }); + }); + + describe('ownerOf', function () { + context('when the given token ID was tracked by this token', function () { + const tokenId = firstTokenId; + + it('returns the owner of the given token ID', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owner); + }); + }); + + context('when the given token ID was not tracked by this token', function () { + const tokenId = nonExistentTokenId; + + it('reverts', async function () { + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + }); + }); + }); + + describe('transfers', function () { + const tokenId = firstTokenId; + const data = '0x42'; + + let receipt = null; + + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + await this.token.setApprovalForAll(operator, true, { from: owner }); + }); + + const transferWasSuccessful = function ({ owner, tokenId }) { + it('transfers the ownership of the given token ID to the given address', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(this.toWhom); + }); + + it('emits a Transfer event', async function () { + expectEvent(receipt, 'Transfer', { from: owner, to: this.toWhom, tokenId: tokenId }); + }); + + it('clears the approval for the token ID with no event', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + expectEvent.notEmitted(receipt, 'Approval'); + }); + + it('adjusts owners balances', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('adjusts owners tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + + expect(await this.token.tokenOfOwnerByIndex(this.toWhom, 0)).to.be.bignumber.equal(tokenId); + + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.not.equal(tokenId); + }); + }; + + const shouldTransferTokensByUsers = function (transferFunction, opts = {}) { + context('when called by the owner', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: owner }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the approved individual', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: approved }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the operator', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: operator }); + }); + transferWasSuccessful({ owner, tokenId, approved }); + }); + + context('when called by the owner without an approved user', function () { + beforeEach(async function () { + await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + receipt = await transferFunction.call(this, owner, this.toWhom, tokenId, { from: operator }); + }); + transferWasSuccessful({ owner, tokenId, approved: null }); + }); + + context('when sent to the owner', function () { + beforeEach(async function () { + receipt = await transferFunction.call(this, owner, owner, tokenId, { from: owner }); + }); + + it('keeps ownership of the token', async function () { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owner); + }); + + it('clears the approval for the token ID', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + + it('emits only a transfer event', async function () { + expectEvent(receipt, 'Transfer', { + from: owner, + to: owner, + tokenId: tokenId, + }); + }); + + it('keeps the owner balance', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('2'); + }); + + it('keeps same tokens by index', async function () { + if (!this.token.tokenOfOwnerByIndex) return; + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenOfOwnerByIndex(owner, i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + }); + + context('when the address of the previous owner is incorrect', function () { + it('reverts', async function () { + await expectRevertCustomError( + transferFunction.call(this, other, other, tokenId, { from: owner }), + 'ERC721IncorrectOwner', + [other, tokenId, owner], + ); + }); + }); + + context('when the sender is not authorized for the token id', function () { + if (opts.unrestricted) { + it('does not revert', async function () { + await transferFunction.call(this, owner, other, tokenId, { from: other }); + }); + } else { + it('reverts', async function () { + await expectRevertCustomError( + transferFunction.call(this, owner, other, tokenId, { from: other }), + 'ERC721InsufficientApproval', + [other, tokenId], + ); + }); + } + }); + + context('when the given token ID does not exist', function () { + it('reverts', async function () { + await expectRevertCustomError( + transferFunction.call(this, owner, other, nonExistentTokenId, { from: owner }), + 'ERC721NonexistentToken', + [nonExistentTokenId], + ); + }); + }); + + context('when the address to transfer the token to is the zero address', function () { + it('reverts', async function () { + await expectRevertCustomError( + transferFunction.call(this, owner, ZERO_ADDRESS, tokenId, { from: owner }), + 'ERC721InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + }); + }; + + const shouldTransferSafely = function (transferFun, data, opts = {}) { + describe('to a user account', function () { + shouldTransferTokensByUsers(transferFun, opts); + }); + + describe('to a valid receiver contract', function () { + beforeEach(async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.None); + this.toWhom = this.receiver.address; + }); + + shouldTransferTokensByUsers(transferFun, opts); + + it('calls onERC721Received', async function () { + const receipt = await transferFun.call(this, owner, this.receiver.address, tokenId, { from: owner }); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + operator: owner, + from: owner, + tokenId: tokenId, + data: data, + }); + }); + + it('calls onERC721Received from approved', async function () { + const receipt = await transferFun.call(this, owner, this.receiver.address, tokenId, { from: approved }); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + operator: approved, + from: owner, + tokenId: tokenId, + data: data, + }); + }); + + describe('with an invalid token id', function () { + it('reverts', async function () { + await expectRevertCustomError( + transferFun.call(this, owner, this.receiver.address, nonExistentTokenId, { from: owner }), + 'ERC721NonexistentToken', + [nonExistentTokenId], + ); + }); + }); + }); + }; + + for (const { fnName, opts } of [ + { fnName: 'transferFrom', opts: {} }, + { fnName: '$_transfer', opts: { unrestricted: true } }, + ]) { + describe(`via ${fnName}`, function () { + shouldTransferTokensByUsers(function (from, to, tokenId, opts) { + return this.token[fnName](from, to, tokenId, opts); + }, opts); + }); + } + + for (const { fnName, opts } of [ + { fnName: 'safeTransferFrom', opts: {} }, + { fnName: '$_safeTransfer', opts: { unrestricted: true } }, + ]) { + describe(`via ${fnName}`, function () { + const safeTransferFromWithData = function (from, to, tokenId, opts) { + return this.token.methods[fnName + '(address,address,uint256,bytes)'](from, to, tokenId, data, opts); + }; + + const safeTransferFromWithoutData = function (from, to, tokenId, opts) { + return this.token.methods[fnName + '(address,address,uint256)'](from, to, tokenId, opts); + }; + + describe('with data', function () { + shouldTransferSafely(safeTransferFromWithData, data, opts); + }); + + describe('without data', function () { + shouldTransferSafely(safeTransferFromWithoutData, null, opts); + }); + + describe('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ERC721ReceiverMock.new('0x42', RevertType.None); + await expectRevertCustomError( + this.token.methods[fnName + '(address,address,uint256)'](owner, invalidReceiver.address, tokenId, { + from: owner, + }), + 'ERC721InvalidReceiver', + [invalidReceiver.address], + ); + }); + }); + + describe('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithMessage, + ); + await expectRevert( + this.token.methods[fnName + '(address,address,uint256)'](owner, revertingReceiver.address, tokenId, { + from: owner, + }), + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + describe('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ); + await expectRevertCustomError( + this.token.methods[fnName + '(address,address,uint256)'](owner, revertingReceiver.address, tokenId, { + from: owner, + }), + 'ERC721InvalidReceiver', + [revertingReceiver.address], + ); + }); + }); + + describe('to a receiver contract that reverts with custom error', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ); + await expectRevertCustomError( + this.token.methods[fnName + '(address,address,uint256)'](owner, revertingReceiver.address, tokenId, { + from: owner, + }), + 'CustomError', + [RECEIVER_MAGIC_VALUE], + ); + }); + }); + + describe('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.Panic); + await expectRevert.unspecified( + this.token.methods[fnName + '(address,address,uint256)'](owner, revertingReceiver.address, tokenId, { + from: owner, + }), + ); + }); + }); + + describe('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await NonERC721ReceiverMock.new(); + await expectRevertCustomError( + this.token.methods[fnName + '(address,address,uint256)'](owner, nonReceiver.address, tokenId, { + from: owner, + }), + 'ERC721InvalidReceiver', + [nonReceiver.address], + ); + }); + }); + }); + } + }); + + describe('safe mint', function () { + const tokenId = fourthTokenId; + const data = '0x42'; + + describe('via safeMint', function () { + // regular minting is tested in ERC721Mintable.test.js and others + it('calls onERC721Received — with data', async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.None); + const receipt = await this.token.$_safeMint(this.receiver.address, tokenId, data); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + from: ZERO_ADDRESS, + tokenId: tokenId, + data: data, + }); + }); + + it('calls onERC721Received — without data', async function () { + this.receiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.None); + const receipt = await this.token.$_safeMint(this.receiver.address, tokenId); + + await expectEvent.inTransaction(receipt.tx, ERC721ReceiverMock, 'Received', { + from: ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + + context('to a receiver contract returning unexpected value', function () { + it('reverts', async function () { + const invalidReceiver = await ERC721ReceiverMock.new('0x42', RevertType.None); + await expectRevertCustomError( + this.token.$_safeMint(invalidReceiver.address, tokenId), + 'ERC721InvalidReceiver', + [invalidReceiver.address], + ); + }); + }); + + context('to a receiver contract that reverts with message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.RevertWithMessage); + await expectRevert( + this.token.$_safeMint(revertingReceiver.address, tokenId), + 'ERC721ReceiverMock: reverting', + ); + }); + }); + + context('to a receiver contract that reverts without message', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithoutMessage, + ); + await expectRevertCustomError( + this.token.$_safeMint(revertingReceiver.address, tokenId), + 'ERC721InvalidReceiver', + [revertingReceiver.address], + ); + }); + }); + + context('to a receiver contract that reverts with custom error', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new( + RECEIVER_MAGIC_VALUE, + RevertType.RevertWithCustomError, + ); + await expectRevertCustomError(this.token.$_safeMint(revertingReceiver.address, tokenId), 'CustomError', [ + RECEIVER_MAGIC_VALUE, + ]); + }); + }); + + context('to a receiver contract that panics', function () { + it('reverts', async function () { + const revertingReceiver = await ERC721ReceiverMock.new(RECEIVER_MAGIC_VALUE, RevertType.Panic); + await expectRevert.unspecified(this.token.$_safeMint(revertingReceiver.address, tokenId)); + }); + }); + + context('to a contract that does not implement the required function', function () { + it('reverts', async function () { + const nonReceiver = await NonERC721ReceiverMock.new(); + await expectRevertCustomError( + this.token.$_safeMint(nonReceiver.address, tokenId), + 'ERC721InvalidReceiver', + [nonReceiver.address], + ); + }); + }); + }); + }); + + describe('approve', function () { + const tokenId = firstTokenId; + + let receipt = null; + + const itClearsApproval = function () { + it('clears approval for the token', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(ZERO_ADDRESS); + }); + }; + + const itApproves = function (address) { + it('sets the approval for the target address', async function () { + expect(await this.token.getApproved(tokenId)).to.be.equal(address); + }); + }; + + const itEmitsApprovalEvent = function (address) { + it('emits an approval event', async function () { + expectEvent(receipt, 'Approval', { + owner: owner, + approved: address, + tokenId: tokenId, + }); + }); + }; + + context('when clearing approval', function () { + context('when there was no prior approval', function () { + beforeEach(async function () { + receipt = await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + }); + + itClearsApproval(); + itEmitsApprovalEvent(ZERO_ADDRESS); + }); + + context('when there was a prior approval', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.approve(ZERO_ADDRESS, tokenId, { from: owner }); + }); + + itClearsApproval(); + itEmitsApprovalEvent(ZERO_ADDRESS); + }); + }); + + context('when approving a non-zero address', function () { + context('when there was no prior approval', function () { + beforeEach(async function () { + receipt = await this.token.approve(approved, tokenId, { from: owner }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when there was a prior approval to the same address', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.approve(approved, tokenId, { from: owner }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when there was a prior approval to a different address', function () { + beforeEach(async function () { + await this.token.approve(anotherApproved, tokenId, { from: owner }); + receipt = await this.token.approve(anotherApproved, tokenId, { from: owner }); + }); + + itApproves(anotherApproved); + itEmitsApprovalEvent(anotherApproved); + }); + }); + + context('when the sender does not own the given token ID', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.approve(approved, tokenId, { from: other }), + 'ERC721InvalidApprover', + [other], + ); + }); + }); + + context('when the sender is approved for the given token ID', function () { + it('reverts', async function () { + await this.token.approve(approved, tokenId, { from: owner }); + await expectRevertCustomError( + this.token.approve(anotherApproved, tokenId, { from: approved }), + 'ERC721InvalidApprover', + [approved], + ); + }); + }); + + context('when the sender is an operator', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + receipt = await this.token.approve(approved, tokenId, { from: operator }); + }); + + itApproves(approved); + itEmitsApprovalEvent(approved); + }); + + context('when the given token ID does not exist', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.approve(approved, nonExistentTokenId, { from: operator }), + 'ERC721NonexistentToken', + [nonExistentTokenId], + ); + }); + }); + }); + + describe('setApprovalForAll', function () { + context('when the operator willing to approve is not the owner', function () { + context('when there is no operator approval set by the sender', function () { + it('approves the operator', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + }); + + context('when the operator was set as not approved', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, false, { from: owner }); + }); + + it('approves the operator', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + + it('can unset the operator approval', async function () { + await this.token.setApprovalForAll(operator, false, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); + + context('when the operator was already approved', function () { + beforeEach(async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + }); + + it('keeps the approval to the given address', async function () { + await this.token.setApprovalForAll(operator, true, { from: owner }); + + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(true); + }); + + it('emits an approval event', async function () { + const receipt = await this.token.setApprovalForAll(operator, true, { from: owner }); + + expectEvent(receipt, 'ApprovalForAll', { + owner: owner, + operator: operator, + approved: true, + }); + }); + }); + }); + + context('when the operator is address zero', function () { + it('reverts', async function () { + await expectRevertCustomError( + this.token.setApprovalForAll(constants.ZERO_ADDRESS, true, { from: owner }), + 'ERC721InvalidOperator', + [constants.ZERO_ADDRESS], + ); + }); + }); + }); + + describe('getApproved', async function () { + context('when token is not minted', async function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.getApproved(nonExistentTokenId), 'ERC721NonexistentToken', [ + nonExistentTokenId, + ]); + }); + }); + + context('when token has been minted ', async function () { + it('should return the zero address', async function () { + expect(await this.token.getApproved(firstTokenId)).to.be.equal(ZERO_ADDRESS); + }); + + context('when account has been approved', async function () { + beforeEach(async function () { + await this.token.approve(approved, firstTokenId, { from: owner }); + }); + + it('returns approved account', async function () { + expect(await this.token.getApproved(firstTokenId)).to.be.equal(approved); + }); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, firstTokenId), 'ERC721InvalidReceiver', [ + ZERO_ADDRESS, + ]); + }); + + context('with minted token', async function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(owner, firstTokenId); + }); + + it('emits a Transfer event', function () { + expectEvent(this.receipt, 'Transfer', { from: ZERO_ADDRESS, to: owner, tokenId: firstTokenId }); + }); + + it('creates the token', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + expect(await this.token.ownerOf(firstTokenId)).to.equal(owner); + }); + + it('reverts when adding a token id that already exists', async function () { + await expectRevertCustomError(this.token.$_mint(owner, firstTokenId), 'ERC721InvalidSender', [ZERO_ADDRESS]); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expectRevertCustomError(this.token.$_burn(nonExistentTokenId), 'ERC721NonexistentToken', [ + nonExistentTokenId, + ]); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + context('with burnt token', function () { + beforeEach(async function () { + this.receipt = await this.token.$_burn(firstTokenId); + }); + + it('emits a Transfer event', function () { + expectEvent(this.receipt, 'Transfer', { from: owner, to: ZERO_ADDRESS, tokenId: firstTokenId }); + }); + + it('deletes the token', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + await expectRevertCustomError(this.token.ownerOf(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + + it('reverts when burning a token id that has been deleted', async function () { + await expectRevertCustomError(this.token.$_burn(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Enumerable(owner, newOwner, approved, anotherApproved, operator, other) { + shouldSupportInterfaces(['ERC721Enumerable']); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + this.toWhom = other; // default to other for toWhom in context-dependent tests + }); + + describe('totalSupply', function () { + it('returns total token supply', async function () { + expect(await this.token.totalSupply()).to.be.bignumber.equal('2'); + }); + }); + + describe('tokenOfOwnerByIndex', function () { + describe('when the given index is lower than the amount of tokens owned by the given address', function () { + it('returns the token ID placed at the given index', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(firstTokenId); + }); + }); + + describe('when the index is greater than or equal to the total tokens owned by the given address', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.tokenOfOwnerByIndex(owner, 2), 'ERC721OutOfBoundsIndex', [owner, 2]); + }); + }); + + describe('when the given address does not own any token', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.tokenOfOwnerByIndex(other, 0), 'ERC721OutOfBoundsIndex', [other, 0]); + }); + }); + + describe('after transferring all tokens to another user', function () { + beforeEach(async function () { + await this.token.transferFrom(owner, other, firstTokenId, { from: owner }); + await this.token.transferFrom(owner, other, secondTokenId, { from: owner }); + }); + + it('returns correct token IDs for target', async function () { + expect(await this.token.balanceOf(other)).to.be.bignumber.equal('2'); + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenOfOwnerByIndex(other, i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + + it('returns empty collection for original owner', async function () { + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('0'); + await expectRevertCustomError(this.token.tokenOfOwnerByIndex(owner, 0), 'ERC721OutOfBoundsIndex', [owner, 0]); + }); + }); + }); + + describe('tokenByIndex', function () { + it('returns all tokens', async function () { + const tokensListed = await Promise.all([0, 1].map(i => this.token.tokenByIndex(i))); + expect(tokensListed.map(t => t.toNumber())).to.have.members([ + firstTokenId.toNumber(), + secondTokenId.toNumber(), + ]); + }); + + it('reverts if index is greater than supply', async function () { + await expectRevertCustomError(this.token.tokenByIndex(2), 'ERC721OutOfBoundsIndex', [ZERO_ADDRESS, 2]); + }); + + [firstTokenId, secondTokenId].forEach(function (tokenId) { + it(`returns all tokens after burning token ${tokenId} and minting new tokens`, async function () { + const newTokenId = new BN(300); + const anotherNewTokenId = new BN(400); + + await this.token.$_burn(tokenId); + await this.token.$_mint(newOwner, newTokenId); + await this.token.$_mint(newOwner, anotherNewTokenId); + + expect(await this.token.totalSupply()).to.be.bignumber.equal('3'); + + const tokensListed = await Promise.all([0, 1, 2].map(i => this.token.tokenByIndex(i))); + const expectedTokens = [firstTokenId, secondTokenId, newTokenId, anotherNewTokenId].filter( + x => x !== tokenId, + ); + expect(tokensListed.map(t => t.toNumber())).to.have.members(expectedTokens.map(t => t.toNumber())); + }); + }); + }); + }); + + describe('_mint(address, uint256)', function () { + it('reverts with a null destination address', async function () { + await expectRevertCustomError(this.token.$_mint(ZERO_ADDRESS, firstTokenId), 'ERC721InvalidReceiver', [ + ZERO_ADDRESS, + ]); + }); + + context('with minted token', async function () { + beforeEach(async function () { + this.receipt = await this.token.$_mint(owner, firstTokenId); + }); + + it('adjusts owner tokens by index', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(firstTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0)).to.be.bignumber.equal(firstTokenId); + }); + }); + }); + + describe('_burn', function () { + it('reverts when burning a non-existent token id', async function () { + await expectRevertCustomError(this.token.$_burn(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + + context('with minted tokens', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + context('with burnt token', function () { + beforeEach(async function () { + this.receipt = await this.token.$_burn(firstTokenId); + }); + + it('removes that token from the token list of the owner', async function () { + expect(await this.token.tokenOfOwnerByIndex(owner, 0)).to.be.bignumber.equal(secondTokenId); + }); + + it('adjusts all tokens list', async function () { + expect(await this.token.tokenByIndex(0)).to.be.bignumber.equal(secondTokenId); + }); + + it('burns all tokens', async function () { + await this.token.$_burn(secondTokenId, { from: owner }); + expect(await this.token.totalSupply()).to.be.bignumber.equal('0'); + await expectRevertCustomError(this.token.tokenByIndex(0), 'ERC721OutOfBoundsIndex', [ZERO_ADDRESS, 0]); + }); + }); + }); + }); +} + +function shouldBehaveLikeERC721Metadata(name, symbol, owner) { + shouldSupportInterfaces(['ERC721Metadata']); + + describe('metadata', function () { + it('has a name', async function () { + expect(await this.token.name()).to.be.equal(name); + }); + + it('has a symbol', async function () { + expect(await this.token.symbol()).to.be.equal(symbol); + }); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + }); + + it('return empty string by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expectRevertCustomError(this.token.tokenURI(nonExistentTokenId), 'ERC721NonexistentToken', [ + nonExistentTokenId, + ]); + }); + + describe('base URI', function () { + beforeEach(function () { + if (this.token.setBaseURI === undefined) { + this.skip(); + } + }); + + it('base URI can be set', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.baseURI()).to.equal(baseURI); + }); + + it('base URI is added as a prefix to the token URI', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + firstTokenId.toString()); + }); + + it('token URI can be changed by changing the base URI', async function () { + await this.token.setBaseURI(baseURI); + const newBaseURI = 'https://api.example.com/v2/'; + await this.token.setBaseURI(newBaseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + firstTokenId.toString()); + }); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Enumerable, + shouldBehaveLikeERC721Metadata, +}; diff --git a/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js b/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js new file mode 100644 index 0000000..372dd50 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/ERC721.test.js @@ -0,0 +1,15 @@ +const { shouldBehaveLikeERC721, shouldBehaveLikeERC721Metadata } = require('./ERC721.behavior'); + +const ERC721 = artifacts.require('$ERC721'); + +contract('ERC721', function (accounts) { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721.new(name, symbol); + }); + + shouldBehaveLikeERC721(...accounts); + shouldBehaveLikeERC721Metadata(name, symbol, ...accounts); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js b/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js new file mode 100644 index 0000000..31c28d1 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/ERC721Enumerable.test.js @@ -0,0 +1,20 @@ +const { + shouldBehaveLikeERC721, + shouldBehaveLikeERC721Metadata, + shouldBehaveLikeERC721Enumerable, +} = require('./ERC721.behavior'); + +const ERC721Enumerable = artifacts.require('$ERC721Enumerable'); + +contract('ERC721Enumerable', function (accounts) { + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Enumerable.new(name, symbol); + }); + + shouldBehaveLikeERC721(...accounts); + shouldBehaveLikeERC721Metadata(name, symbol, ...accounts); + shouldBehaveLikeERC721Enumerable(...accounts); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js new file mode 100644 index 0000000..df059e0 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Burnable.test.js @@ -0,0 +1,82 @@ +const { BN, constants, expectEvent } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC721Burnable = artifacts.require('$ERC721Burnable'); + +contract('ERC721Burnable', function (accounts) { + const [owner, approved, another] = accounts; + + const firstTokenId = new BN(1); + const secondTokenId = new BN(2); + const unknownTokenId = new BN(3); + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Burnable.new(name, symbol); + }); + + describe('like a burnable ERC721', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + await this.token.$_mint(owner, secondTokenId); + }); + + describe('burn', function () { + const tokenId = firstTokenId; + let receipt = null; + + describe('when successful', function () { + beforeEach(async function () { + receipt = await this.token.burn(tokenId, { from: owner }); + }); + + it('burns the given token ID and adjusts the balance of the owner', async function () { + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + expect(await this.token.balanceOf(owner)).to.be.bignumber.equal('1'); + }); + + it('emits a burn event', async function () { + expectEvent(receipt, 'Transfer', { + from: owner, + to: constants.ZERO_ADDRESS, + tokenId: tokenId, + }); + }); + }); + + describe('when there is a previous approval burned', function () { + beforeEach(async function () { + await this.token.approve(approved, tokenId, { from: owner }); + receipt = await this.token.burn(tokenId, { from: owner }); + }); + + context('getApproved', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.getApproved(tokenId), 'ERC721NonexistentToken', [tokenId]); + }); + }); + }); + + describe('when there is no previous approval burned', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.burn(tokenId, { from: another }), 'ERC721InsufficientApproval', [ + another, + tokenId, + ]); + }); + }); + + describe('when the given token ID was not tracked by this contract', function () { + it('reverts', async function () { + await expectRevertCustomError(this.token.burn(unknownTokenId, { from: owner }), 'ERC721NonexistentToken', [ + unknownTokenId, + ]); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol new file mode 100644 index 0000000..eca15e7 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.t.sol @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +// solhint-disable func-name-mixedcase + +import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721Consecutive} from "@openzeppelin/contracts/token/ERC721/extensions/ERC721Consecutive.sol"; +import {Test, StdUtils} from "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 { + uint96 private immutable _offset; + uint256 public totalMinted = 0; + + constructor(address[] memory receivers, uint256[] memory batches, uint256 startingId) ERC721("", "") { + _offset = uint96(startingId); + 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); + } + + function _firstConsecutiveId() internal view virtual override returns (uint96) { + return _offset; + } +} + +contract ERC721ConsecutiveTest is Test { + function test_balance(address receiver, uint256[] calldata batches, uint96 startingId) public { + vm.assume(receiver != address(0)); + + uint256 startingTokenId = bound(startingId, 0, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingTokenId); + + assertEq(token.balanceOf(receiver), token.totalMinted()); + } + + function test_ownership( + address receiver, + uint256[] calldata batches, + uint256[2] calldata unboundedTokenId, + uint96 startingId + ) public { + vm.assume(receiver != address(0)); + + uint256 startingTokenId = bound(startingId, 0, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingTokenId); + + if (token.totalMinted() > 0) { + uint256 validTokenId = bound( + unboundedTokenId[0], + startingTokenId, + startingTokenId + token.totalMinted() - 1 + ); + assertEq(token.ownerOf(validTokenId), receiver); + } + + uint256 invalidTokenId = bound( + unboundedTokenId[1], + startingTokenId + token.totalMinted(), + startingTokenId + token.totalMinted() + 1 + ); + vm.expectRevert(); + token.ownerOf(invalidTokenId); + } + + function test_burn( + address receiver, + uint256[] calldata batches, + uint256 unboundedTokenId, + uint96 startingId + ) public { + vm.assume(receiver != address(0)); + + uint256 startingTokenId = bound(startingId, 0, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingTokenId); + + // 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, startingTokenId, startingTokenId + 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, + uint96 startingId + ) public { + vm.assume(accounts[0] != address(0)); + vm.assume(accounts[1] != address(0)); + vm.assume(accounts[0] != accounts[1]); + + uint256 startingTokenId = bound(startingId, 1, 5000); + + 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], startingTokenId, 5000); + batches[1] = bound(unboundedBatches[1], startingTokenId, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(receivers, batches, startingTokenId); + + uint256 tokenId0 = bound(unboundedTokenId[0], startingTokenId, batches[0]); + uint256 tokenId1 = bound(unboundedTokenId[1], startingTokenId, batches[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]); + } + + function test_start_consecutive_id( + address receiver, + uint256[2] calldata unboundedBatches, + uint256[2] calldata unboundedTokenId, + uint96 startingId + ) public { + vm.assume(receiver != address(0)); + + uint256 startingTokenId = bound(startingId, 1, 5000); + + // We assume _maxBatchSize is 5000 (the default). This test will break otherwise. + uint256[] memory batches = new uint256[](2); + batches[0] = bound(unboundedBatches[0], startingTokenId, 5000); + batches[1] = bound(unboundedBatches[1], startingTokenId, 5000); + + ERC721ConsecutiveTarget token = new ERC721ConsecutiveTarget(toSingleton(receiver), batches, startingTokenId); + + uint256 tokenId0 = bound(unboundedTokenId[0], startingTokenId, batches[0]); + uint256 tokenId1 = bound(unboundedTokenId[1], startingTokenId, batches[1]); + + assertEq(token.ownerOf(tokenId0), receiver); + assertEq(token.ownerOf(tokenId1), receiver); + assertEq(token.balanceOf(receiver), batches[0] + batches[1]); + } +} diff --git a/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js new file mode 100644 index 0000000..d9e33af --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Consecutive.test.js @@ -0,0 +1,221 @@ +const { constants, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { sum } = require('../../../helpers/math'); +const { expectRevertCustomError } = require('../../../helpers/customError'); +const { ZERO_ADDRESS } = require('@openzeppelin/test-helpers/src/constants'); + +const ERC721ConsecutiveMock = artifacts.require('$ERC721ConsecutiveMock'); +const ERC721ConsecutiveEnumerableMock = artifacts.require('$ERC721ConsecutiveEnumerableMock'); +const ERC721ConsecutiveNoConstructorMintMock = artifacts.require('$ERC721ConsecutiveNoConstructorMintMock'); + +contract('ERC721Consecutive', function (accounts) { + const [user1, user2, user3, receiver] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const batches = [ + { receiver: user1, amount: 0 }, + { receiver: user1, amount: 1 }, + { receiver: user1, amount: 2 }, + { receiver: user2, amount: 5 }, + { receiver: user3, amount: 0 }, + { receiver: user1, amount: 7 }, + ]; + const delegates = [user1, user3]; + + for (const offset of [0, 1, 42]) { + describe(`with offset ${offset}`, function () { + beforeEach(async function () { + this.token = await ERC721ConsecutiveMock.new( + name, + symbol, + offset, + delegates, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ); + }); + + describe('minting during construction', function () { + it('events are emitted at construction', async function () { + let first = offset; + + for (const batch of batches) { + if (batch.amount > 0) { + await expectEvent.inConstruction(this.token, 'ConsecutiveTransfer', { + fromTokenId: web3.utils.toBN(first), + toTokenId: web3.utils.toBN(first + batch.amount - 1), + fromAddress: constants.ZERO_ADDRESS, + toAddress: batch.receiver, + }); + } else { + // expectEvent.notEmitted.inConstruction only looks at event name, and doesn't check the parameters + } + first += batch.amount; + } + }); + + it('ownership is set', async function () { + const owners = [ + ...Array(offset).fill(constants.ZERO_ADDRESS), + ...batches.flatMap(({ receiver, amount }) => Array(amount).fill(receiver)), + ]; + + for (const tokenId in owners) { + if (owners[tokenId] != constants.ZERO_ADDRESS) { + expect(await this.token.ownerOf(tokenId)).to.be.equal(owners[tokenId]); + } + } + }); + + it('balance & voting power are set', async function () { + for (const account of accounts) { + const balance = sum(...batches.filter(({ receiver }) => receiver === account).map(({ amount }) => amount)); + + expect(await this.token.balanceOf(account)).to.be.bignumber.equal(web3.utils.toBN(balance)); + + // If not delegated at construction, check before + do delegation + if (!delegates.includes(account)) { + expect(await this.token.getVotes(account)).to.be.bignumber.equal(web3.utils.toBN(0)); + + await this.token.delegate(account, { from: account }); + } + + // At this point all accounts should have delegated + expect(await this.token.getVotes(account)).to.be.bignumber.equal(web3.utils.toBN(balance)); + } + }); + + it('reverts on consecutive minting to the zero address', async function () { + await expectRevertCustomError( + ERC721ConsecutiveMock.new(name, symbol, offset, delegates, [ZERO_ADDRESS], [10]), + 'ERC721InvalidReceiver', + [ZERO_ADDRESS], + ); + }); + }); + + describe('minting after construction', function () { + it('consecutive minting is not possible after construction', async function () { + await expectRevertCustomError(this.token.$_mintConsecutive(user1, 10), 'ERC721ForbiddenBatchMint', []); + }); + + it('simple minting is possible after construction', async function () { + const tokenId = sum(...batches.map(b => b.amount)) + offset; + + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + + expectEvent(await this.token.$_mint(user1, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user1, + tokenId: tokenId.toString(), + }); + }); + + it('cannot mint a token that has been batched minted', async function () { + const tokenId = sum(...batches.map(b => b.amount)) + offset - 1; + + expect(await this.token.ownerOf(tokenId)).to.be.not.equal(constants.ZERO_ADDRESS); + + await expectRevertCustomError(this.token.$_mint(user1, tokenId), 'ERC721InvalidSender', [ZERO_ADDRESS]); + }); + }); + + describe('ERC721 behavior', function () { + const tokenId = web3.utils.toBN(offset + 1); + + it('core takes over ownership on transfer', async function () { + await this.token.transferFrom(user1, receiver, tokenId, { from: user1 }); + + expect(await this.token.ownerOf(tokenId)).to.be.equal(receiver); + }); + + it('tokens can be burned and re-minted #1', async function () { + expectEvent(await this.token.$_burn(tokenId, { from: user1 }), 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + tokenId, + }); + + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + + expectEvent(await this.token.$_mint(user2, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + tokenId, + }); + + expect(await this.token.ownerOf(tokenId)).to.be.equal(user2); + }); + + it('tokens can be burned and re-minted #2', async function () { + const tokenId = web3.utils.toBN(sum(...batches.map(({ amount }) => amount)) + offset); + + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + + // mint + await this.token.$_mint(user1, tokenId); + + expect(await this.token.ownerOf(tokenId), user1); + + // burn + expectEvent(await this.token.$_burn(tokenId, { from: user1 }), 'Transfer', { + from: user1, + to: constants.ZERO_ADDRESS, + tokenId, + }); + + await expectRevertCustomError(this.token.ownerOf(tokenId), 'ERC721NonexistentToken', [tokenId]); + + // re-mint + expectEvent(await this.token.$_mint(user2, tokenId), 'Transfer', { + from: constants.ZERO_ADDRESS, + to: user2, + tokenId, + }); + + expect(await this.token.ownerOf(tokenId), user2); + }); + }); + }); + } + + describe('invalid use', function () { + it('cannot mint a batch larger than 5000', async function () { + await expectRevertCustomError( + ERC721ConsecutiveMock.new(name, symbol, 0, [], [user1], ['5001']), + 'ERC721ExceededMaxBatchMint', + [5000, 5001], + ); + }); + + it('cannot use single minting during construction', async function () { + await expectRevertCustomError( + ERC721ConsecutiveNoConstructorMintMock.new(name, symbol), + 'ERC721ForbiddenMint', + [], + ); + }); + + it('cannot use single minting during construction', async function () { + await expectRevertCustomError( + ERC721ConsecutiveNoConstructorMintMock.new(name, symbol), + 'ERC721ForbiddenMint', + [], + ); + }); + + it('consecutive mint not compatible with enumerability', async function () { + await expectRevertCustomError( + ERC721ConsecutiveEnumerableMock.new( + name, + symbol, + batches.map(({ receiver }) => receiver), + batches.map(({ amount }) => amount), + ), + 'ERC721EnumerableForbiddenBatchMint', + [], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js new file mode 100644 index 0000000..5d77149 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Pausable.test.js @@ -0,0 +1,90 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC721Pausable = artifacts.require('$ERC721Pausable'); + +contract('ERC721Pausable', function (accounts) { + const [owner, receiver, operator] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + beforeEach(async function () { + this.token = await ERC721Pausable.new(name, symbol); + }); + + context('when token is paused', function () { + const firstTokenId = new BN(1); + const secondTokenId = new BN(1337); + + const mockData = '0x42'; + + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId, { from: owner }); + await this.token.$_pause(); + }); + + it('reverts when trying to transferFrom', async function () { + await expectRevertCustomError( + this.token.transferFrom(owner, receiver, firstTokenId, { from: owner }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeTransferFrom', async function () { + await expectRevertCustomError( + this.token.safeTransferFrom(owner, receiver, firstTokenId, { from: owner }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to safeTransferFrom with data', async function () { + await expectRevertCustomError( + this.token.methods['safeTransferFrom(address,address,uint256,bytes)'](owner, receiver, firstTokenId, mockData, { + from: owner, + }), + 'EnforcedPause', + [], + ); + }); + + it('reverts when trying to mint', async function () { + await expectRevertCustomError(this.token.$_mint(receiver, secondTokenId), 'EnforcedPause', []); + }); + + it('reverts when trying to burn', async function () { + await expectRevertCustomError(this.token.$_burn(firstTokenId), 'EnforcedPause', []); + }); + + describe('getApproved', function () { + it('returns approved address', async function () { + const approvedAccount = await this.token.getApproved(firstTokenId); + expect(approvedAccount).to.equal(constants.ZERO_ADDRESS); + }); + }); + + describe('balanceOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const balance = await this.token.balanceOf(owner); + expect(balance).to.be.bignumber.equal('1'); + }); + }); + + describe('ownerOf', function () { + it('returns the amount of tokens owned by the given address', async function () { + const ownerOfToken = await this.token.ownerOf(firstTokenId); + expect(ownerOfToken).to.equal(owner); + }); + }); + + describe('isApprovedForAll', function () { + it('returns the approval of the operator', async function () { + expect(await this.token.isApprovedForAll(owner, operator)).to.equal(false); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js new file mode 100644 index 0000000..78cba98 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Royalty.test.js @@ -0,0 +1,47 @@ +require('@openzeppelin/test-helpers'); + +const { shouldBehaveLikeERC2981 } = require('../../common/ERC2981.behavior'); + +const ERC721Royalty = artifacts.require('$ERC721Royalty'); + +contract('ERC721Royalty', function (accounts) { + const [account1, account2, recipient] = accounts; + const tokenId1 = web3.utils.toBN('1'); + const tokenId2 = web3.utils.toBN('2'); + const royalty = web3.utils.toBN('200'); + const salePrice = web3.utils.toBN('1000'); + + beforeEach(async function () { + this.token = await ERC721Royalty.new('My Token', 'TKN'); + + await this.token.$_mint(account1, tokenId1); + await this.token.$_mint(account1, tokenId2); + this.account1 = account1; + this.account2 = account2; + this.tokenId1 = tokenId1; + this.tokenId2 = tokenId2; + this.salePrice = salePrice; + }); + + describe('token specific functions', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(tokenId1, recipient, royalty); + }); + + it('royalty information are kept during burn and re-mint', async function () { + await this.token.$_burn(tokenId1); + + const tokenInfoA = await this.token.royaltyInfo(tokenId1, salePrice); + expect(tokenInfoA[0]).to.be.equal(recipient); + expect(tokenInfoA[1]).to.be.bignumber.equal(salePrice.mul(royalty).divn(1e4)); + + await this.token.$_mint(account2, tokenId1); + + const tokenInfoB = await this.token.royaltyInfo(tokenId1, salePrice); + expect(tokenInfoB[0]).to.be.equal(recipient); + expect(tokenInfoB[1]).to.be.bignumber.equal(salePrice.mul(royalty).divn(1e4)); + }); + }); + + shouldBehaveLikeERC2981(); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js new file mode 100644 index 0000000..8c882fa --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721URIStorage.test.js @@ -0,0 +1,114 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { shouldSupportInterfaces } = require('../../../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +const ERC721URIStorageMock = artifacts.require('$ERC721URIStorageMock'); + +contract('ERC721URIStorage', function (accounts) { + const [owner] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + + const firstTokenId = new BN('5042'); + const nonExistentTokenId = new BN('13'); + + beforeEach(async function () { + this.token = await ERC721URIStorageMock.new(name, symbol); + }); + + shouldSupportInterfaces(['0x49064906']); + + describe('token URI', function () { + beforeEach(async function () { + await this.token.$_mint(owner, firstTokenId); + }); + + const baseURI = 'https://api.example.com/v1/'; + const sampleUri = 'mock://mytoken'; + + it('it is empty by default', async function () { + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(''); + }); + + it('reverts when queried for non existent token id', async function () { + await expectRevertCustomError(this.token.tokenURI(nonExistentTokenId), 'ERC721NonexistentToken', [ + nonExistentTokenId, + ]); + }); + + it('can be set for a token id', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + 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('setting the uri for non existent token id is allowed', async function () { + expectEvent(await this.token.$_setTokenURI(nonExistentTokenId, sampleUri), 'MetadataUpdate', { + _tokenId: nonExistentTokenId, + }); + + // value will be accessible after mint + await this.token.$_mint(owner, nonExistentTokenId); + expect(await this.token.tokenURI(nonExistentTokenId)).to.be.equal(sampleUri); + }); + + it('base URI can be set', async function () { + await this.token.setBaseURI(baseURI); + expect(await this.token.$_baseURI()).to.equal(baseURI); + }); + + it('base URI is added as a prefix to the token URI', async function () { + await this.token.setBaseURI(baseURI); + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + sampleUri); + }); + + it('token URI can be changed by changing the base URI', async function () { + await this.token.setBaseURI(baseURI); + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + const newBaseURI = 'https://api.example.com/v2/'; + await this.token.setBaseURI(newBaseURI); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(newBaseURI + sampleUri); + }); + + it('tokenId is appended to base URI for tokens with no URI', async function () { + await this.token.setBaseURI(baseURI); + + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(baseURI + firstTokenId); + }); + + it('tokens without URI can be burnt ', async function () { + await this.token.$_burn(firstTokenId); + + await expectRevertCustomError(this.token.tokenURI(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + + it('tokens with URI can be burnt ', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + await this.token.$_burn(firstTokenId); + + await expectRevertCustomError(this.token.tokenURI(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + }); + + it('tokens URI is kept if token is burnt and reminted ', async function () { + await this.token.$_setTokenURI(firstTokenId, sampleUri); + + await this.token.$_burn(firstTokenId); + await expectRevertCustomError(this.token.tokenURI(firstTokenId), 'ERC721NonexistentToken', [firstTokenId]); + + await this.token.$_mint(owner, firstTokenId); + expect(await this.token.tokenURI(firstTokenId)).to.be.equal(sampleUri); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js new file mode 100644 index 0000000..45020ba --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Votes.test.js @@ -0,0 +1,183 @@ +/* eslint-disable */ + +const { expectEvent, time } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { clock, clockFromReceipt } = require('../../../helpers/time'); + +const { shouldBehaveLikeVotes } = require('../../../governance/utils/Votes.behavior'); + +const MODES = { + blocknumber: artifacts.require('$ERC721Votes'), + // no timestamp mode for ERC721Votes yet +}; + +contract('ERC721Votes', function (accounts) { + const [account1, account2, other1, other2] = accounts; + + const name = 'My Vote'; + const symbol = 'MTKN'; + const version = '1'; + const tokens = ['10000000000000000000000000', '10', '20', '30'].map(n => web3.utils.toBN(n)); + + for (const [mode, artifact] of Object.entries(MODES)) { + describe(`vote with ${mode}`, function () { + beforeEach(async function () { + this.votes = await artifact.new(name, symbol, name, version); + }); + + // includes EIP6372 behavior check + shouldBehaveLikeVotes(accounts, tokens, { mode, fungible: false }); + + describe('balanceOf', function () { + beforeEach(async function () { + await this.votes.$_mint(account1, tokens[0]); + await this.votes.$_mint(account1, tokens[1]); + await this.votes.$_mint(account1, tokens[2]); + await this.votes.$_mint(account1, tokens[3]); + }); + + it('grants to initial account', async function () { + expect(await this.votes.balanceOf(account1)).to.be.bignumber.equal('4'); + }); + }); + + describe('transfers', function () { + beforeEach(async function () { + await this.votes.$_mint(account1, tokens[0]); + }); + + it('no delegation', async function () { + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); + expectEvent.notEmitted(receipt, 'DelegateVotesChanged'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('sender delegation', async function () { + await this.votes.delegate(account1, { from: account1 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousVotes: '1', newVotes: '0' }); + + 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.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('receiver delegation', async function () { + await this.votes.delegate(account2, { from: account2 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousVotes: '0', newVotes: '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.account1Votes = '0'; + this.account2Votes = '1'; + }); + + it('full delegation', async function () { + await this.votes.delegate(account1, { from: account1 }); + await this.votes.delegate(account2, { from: account2 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + expectEvent(receipt, 'Transfer', { from: account1, to: account2, tokenId: tokens[0] }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account1, previousVotes: '1', newVotes: '0' }); + expectEvent(receipt, 'DelegateVotesChanged', { delegate: account2, previousVotes: '0', newVotes: '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.account1Votes = '0'; + this.account2Votes = '1'; + }); + + it('returns the same total supply on transfers', async function () { + await this.votes.delegate(account1, { from: account1 }); + + const { receipt } = await this.votes.transferFrom(account1, account2, tokens[0], { from: account1 }); + const timepoint = await clockFromReceipt[mode](receipt); + + await time.advanceBlock(); + await time.advanceBlock(); + + expect(await this.votes.getPastTotalSupply(timepoint - 1)).to.be.bignumber.equal('1'); + expect(await this.votes.getPastTotalSupply(timepoint + 1)).to.be.bignumber.equal('1'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + it('generally returns the voting balance at the appropriate checkpoint', async function () { + await this.votes.$_mint(account1, tokens[1]); + await this.votes.$_mint(account1, tokens[2]); + await this.votes.$_mint(account1, tokens[3]); + + const total = await this.votes.balanceOf(account1); + + const t1 = await this.votes.delegate(other1, { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t2 = await this.votes.transferFrom(account1, other2, tokens[0], { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t3 = await this.votes.transferFrom(account1, other2, tokens[2], { from: account1 }); + await time.advanceBlock(); + await time.advanceBlock(); + const t4 = await this.votes.transferFrom(other2, account1, tokens[2], { 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.votes.getPastVotes(other1, t1.timepoint - 1)).to.be.bignumber.equal('0'); + expect(await this.votes.getPastVotes(other1, t1.timepoint)).to.be.bignumber.equal(total); + expect(await this.votes.getPastVotes(other1, t1.timepoint + 1)).to.be.bignumber.equal(total); + expect(await this.votes.getPastVotes(other1, t2.timepoint)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t2.timepoint + 1)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t3.timepoint)).to.be.bignumber.equal('2'); + expect(await this.votes.getPastVotes(other1, t3.timepoint + 1)).to.be.bignumber.equal('2'); + expect(await this.votes.getPastVotes(other1, t4.timepoint)).to.be.bignumber.equal('3'); + expect(await this.votes.getPastVotes(other1, t4.timepoint + 1)).to.be.bignumber.equal('3'); + + this.account1Votes = '0'; + this.account2Votes = '0'; + }); + + afterEach(async function () { + expect(await this.votes.getVotes(account1)).to.be.bignumber.equal(this.account1Votes); + expect(await this.votes.getVotes(account2)).to.be.bignumber.equal(this.account2Votes); + + // 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.votes.getPastVotes(account1, timepoint)).to.be.bignumber.equal(this.account1Votes); + expect(await this.votes.getPastVotes(account2, timepoint)).to.be.bignumber.equal(this.account2Votes); + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js new file mode 100644 index 0000000..6839977 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/extensions/ERC721Wrapper.test.js @@ -0,0 +1,289 @@ +const { BN, expectEvent, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { shouldBehaveLikeERC721 } = require('../ERC721.behavior'); +const { expectRevertCustomError } = require('../../../helpers/customError'); + +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 expectRevertCustomError( + this.token.depositFor(initialHolder, [firstTokenId], { from: initialHolder }), + 'ERC721InsufficientApproval', + [this.token.address, firstTokenId], + ); + }); + }); + + 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 expectRevertCustomError( + this.token.withdrawTo(initialHolder, [firstTokenId], { from: anotherAccount }), + 'ERC721InsufficientApproval', + [anotherAccount, firstTokenId], + ); + }); + + 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.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 () { + 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 () { + it('only allows calls from underlying', async function () { + await expectRevertCustomError( + this.token.onERC721Received( + initialHolder, + this.token.address, + firstTokenId, + anotherAccount, // Correct data + { from: anotherAccount }, + ), + 'ERC721UnsupportedToken', + [anotherAccount], + ); + }); + + it('mints a token to from', 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 () { + const owner = await this.underlying.ownerOf(firstTokenId); + await expectRevertCustomError(this.token.$_recover(initialHolder, firstTokenId), 'ERC721IncorrectOwner', [ + this.token.address, + firstTokenId, + owner, + ]); + }); + }); + + describe('ERC712 behavior', function () { + shouldBehaveLikeERC721(...accounts); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js b/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js new file mode 100644 index 0000000..4aa2b79 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/ERC721/utils/ERC721Holder.test.js @@ -0,0 +1,22 @@ +const { expect } = require('chai'); + +const ERC721Holder = artifacts.require('$ERC721Holder'); +const ERC721 = artifacts.require('$ERC721'); + +contract('ERC721Holder', function (accounts) { + const [owner] = accounts; + + const name = 'Non Fungible Token'; + const symbol = 'NFT'; + const tokenId = web3.utils.toBN(1); + + it('receives an ERC721 token', async function () { + const token = await ERC721.new(name, symbol); + await token.$_mint(owner, tokenId); + + const receiver = await ERC721Holder.new(); + await token.safeTransferFrom(owner, receiver.address, tokenId, { from: owner }); + + expect(await token.ownerOf(tokenId)).to.be.equal(receiver.address); + }); +}); diff --git a/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js b/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js new file mode 100644 index 0000000..15efa23 --- /dev/null +++ b/lib/openzeppelin-contracts/test/token/common/ERC2981.behavior.js @@ -0,0 +1,169 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { ZERO_ADDRESS } = constants; + +const { shouldSupportInterfaces } = require('../../utils/introspection/SupportsInterface.behavior'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +function shouldBehaveLikeERC2981() { + const royaltyFraction = new BN('10'); + + shouldSupportInterfaces(['ERC2981']); + + describe('default royalty', function () { + beforeEach(async function () { + await this.token.$_setDefaultRoyalty(this.account1, royaltyFraction); + }); + + it('checks royalty is set', async function () { + const royalty = new BN((this.salePrice * royaltyFraction) / 10000); + + const initInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(initInfo[0]).to.be.equal(this.account1); + expect(initInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('updates royalty amount', async function () { + const newPercentage = new BN('25'); + + // Updated royalty check + await this.token.$_setDefaultRoyalty(this.account1, newPercentage); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + const newInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(newInfo[0]).to.be.equal(this.account1); + expect(newInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('holds same royalty value for different tokens', async function () { + const newPercentage = new BN('20'); + await this.token.$_setDefaultRoyalty(this.account1, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + + expect(token1Info[1]).to.be.bignumber.equal(token2Info[1]); + }); + + it('Remove royalty information', async function () { + const newValue = new BN('0'); + await this.token.$_deleteDefaultRoyalty(); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Test royalty info is still persistent across all tokens + expect(token1Info[0]).to.be.bignumber.equal(token2Info[0]); + expect(token1Info[1]).to.be.bignumber.equal(token2Info[1]); + // Test information was deleted + expect(token1Info[0]).to.be.equal(ZERO_ADDRESS); + expect(token1Info[1]).to.be.bignumber.equal(newValue); + }); + + it('reverts if invalid parameters', async function () { + const royaltyDenominator = await this.token.$_feeDenominator(); + await expectRevertCustomError( + this.token.$_setDefaultRoyalty(ZERO_ADDRESS, royaltyFraction), + 'ERC2981InvalidDefaultRoyaltyReceiver', + [ZERO_ADDRESS], + ); + + const anotherRoyaltyFraction = new BN('11000'); + await expectRevertCustomError( + this.token.$_setDefaultRoyalty(this.account1, anotherRoyaltyFraction), + 'ERC2981InvalidDefaultRoyalty', + [anotherRoyaltyFraction, royaltyDenominator], + ); + }); + }); + + describe('token based royalty', function () { + beforeEach(async function () { + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, royaltyFraction); + }); + + it('updates royalty amount', async function () { + const newPercentage = new BN('25'); + let royalty = new BN((this.salePrice * royaltyFraction) / 10000); + // Initial royalty check + const initInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(initInfo[0]).to.be.equal(this.account1); + expect(initInfo[1]).to.be.bignumber.equal(royalty); + + // Updated royalty check + await this.token.$_setTokenRoyalty(this.tokenId1, this.account1, newPercentage); + royalty = new BN((this.salePrice * newPercentage) / 10000); + const newInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + expect(newInfo[0]).to.be.equal(this.account1); + expect(newInfo[1]).to.be.bignumber.equal(royalty); + }); + + it('holds different values for different tokens', async function () { + const newPercentage = new BN('20'); + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + + // must be different even at the same this.salePrice + expect(token1Info[1]).to.not.be.equal(token2Info.royaltyFraction); + }); + + it('reverts if invalid parameters', async function () { + const royaltyDenominator = await this.token.$_feeDenominator(); + await expectRevertCustomError( + this.token.$_setTokenRoyalty(this.tokenId1, ZERO_ADDRESS, royaltyFraction), + 'ERC2981InvalidTokenRoyaltyReceiver', + [this.tokenId1.toString(), ZERO_ADDRESS], + ); + + const anotherRoyaltyFraction = new BN('11000'); + await expectRevertCustomError( + this.token.$_setTokenRoyalty(this.tokenId1, this.account1, anotherRoyaltyFraction), + 'ERC2981InvalidTokenRoyalty', + [this.tokenId1.toString(), anotherRoyaltyFraction, royaltyDenominator], + ); + }); + + it('can reset token after setting royalty', async function () { + const newPercentage = new BN('30'); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + await this.token.$_setTokenRoyalty(this.tokenId1, this.account2, newPercentage); + + const tokenInfo = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + + // Tokens must have own information + expect(tokenInfo[1]).to.be.bignumber.equal(royalty); + expect(tokenInfo[0]).to.be.equal(this.account2); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account1, new BN('0')); + const result = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Token must not share default information + expect(result[0]).to.be.equal(this.account1); + expect(result[1]).to.be.bignumber.equal(new BN('0')); + }); + + it('can hold default and token royalty information', async function () { + const newPercentage = new BN('30'); + const royalty = new BN((this.salePrice * newPercentage) / 10000); + + await this.token.$_setTokenRoyalty(this.tokenId2, this.account2, newPercentage); + + const token1Info = await this.token.royaltyInfo(this.tokenId1, this.salePrice); + const token2Info = await this.token.royaltyInfo(this.tokenId2, this.salePrice); + // Tokens must not have same values + expect(token1Info[1]).to.not.be.bignumber.equal(token2Info[1]); + expect(token1Info[0]).to.not.be.equal(token2Info[0]); + + // Updated token must have new values + expect(token2Info[0]).to.be.equal(this.account2); + expect(token2Info[1]).to.be.bignumber.equal(royalty); + }); + }); +} + +module.exports = { + shouldBehaveLikeERC2981, +}; diff --git a/lib/openzeppelin-contracts/test/utils/Address.test.js b/lib/openzeppelin-contracts/test/utils/Address.test.js new file mode 100644 index 0000000..57453ab --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Address.test.js @@ -0,0 +1,340 @@ +const { balance, constants, ether, expectRevert, send, expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const Address = artifacts.require('$Address'); +const EtherReceiver = artifacts.require('EtherReceiverMock'); +const CallReceiverMock = artifacts.require('CallReceiverMock'); + +contract('Address', function (accounts) { + const [recipient, other] = accounts; + + beforeEach(async function () { + this.mock = await Address.new(); + }); + + describe('sendValue', function () { + beforeEach(async function () { + this.recipientTracker = await balance.tracker(recipient); + }); + + context('when sender contract has no funds', function () { + it('sends 0 wei', async function () { + await this.mock.$sendValue(other, 0); + + expect(await this.recipientTracker.delta()).to.be.bignumber.equal('0'); + }); + + it('reverts when sending non-zero amounts', async function () { + await expectRevertCustomError(this.mock.$sendValue(other, 1), 'AddressInsufficientBalance', [ + this.mock.address, + ]); + }); + }); + + context('when sender contract has funds', function () { + const funds = ether('1'); + beforeEach(async function () { + await send.ether(other, this.mock.address, funds); + }); + + it('sends 0 wei', async function () { + await this.mock.$sendValue(recipient, 0); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal('0'); + }); + + it('sends non-zero amounts', async function () { + await this.mock.$sendValue(recipient, funds.subn(1)); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal(funds.subn(1)); + }); + + it('sends the whole balance', async function () { + await this.mock.$sendValue(recipient, funds); + expect(await this.recipientTracker.delta()).to.be.bignumber.equal(funds); + expect(await balance.current(this.mock.address)).to.be.bignumber.equal('0'); + }); + + it('reverts when sending more than the balance', async function () { + await expectRevertCustomError(this.mock.$sendValue(recipient, funds.addn(1)), 'AddressInsufficientBalance', [ + this.mock.address, + ]); + }); + + context('with contract recipient', function () { + beforeEach(async function () { + this.target = await EtherReceiver.new(); + }); + + it('sends funds', async function () { + const tracker = await balance.tracker(this.target.address); + + await this.target.setAcceptEther(true); + await this.mock.$sendValue(this.target.address, funds); + + expect(await tracker.delta()).to.be.bignumber.equal(funds); + }); + + it('reverts on recipient revert', async function () { + await this.target.setAcceptEther(false); + await expectRevertCustomError(this.mock.$sendValue(this.target.address, funds), 'FailedInnerCall', []); + }); + }); + }); + }); + + describe('functionCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + context('with valid contract receiver', function () { + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const receipt = await this.mock.$functionCall(this.target.address, abiEncodedCall); + + expectEvent(receipt, 'return$functionCall', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + 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(); + + await expectRevertCustomError( + this.mock.$functionCall(this.target.address, abiEncodedCall), + 'FailedInnerCall', + [], + ); + }); + + it('reverts when the called function reverts, bubbling up the revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert(this.mock.$functionCall(this.target.address, abiEncodedCall), 'CallReceiverMock: reverting'); + }); + + it('reverts when the called function runs out of gas', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionOutOfGas().encodeABI(); + + await expectRevertCustomError( + this.mock.$functionCall(this.target.address, abiEncodedCall, { gas: '120000' }), + 'FailedInnerCall', + [], + ); + }); + + it('reverts when the called function throws', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionThrows().encodeABI(); + + await expectRevert.unspecified(this.mock.$functionCall(this.target.address, abiEncodedCall)); + }); + + it('reverts when function does not exist', async function () { + const abiEncodedCall = web3.eth.abi.encodeFunctionCall( + { + name: 'mockFunctionDoesNotExist', + type: 'function', + inputs: [], + }, + [], + ); + + await expectRevertCustomError( + this.mock.$functionCall(this.target.address, abiEncodedCall), + 'FailedInnerCall', + [], + ); + }); + }); + + context('with non-contract receiver', function () { + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError(this.mock.$functionCall(recipient, abiEncodedCall), 'AddressEmptyCode', [ + recipient, + ]); + }); + }); + }); + + describe('functionCallWithValue', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + context('with zero value', function () { + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, 0); + expectEvent(receipt, 'return$functionCallWithValue', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + }); + }); + + context('with non-zero value', function () { + const amount = ether('1.2'); + + it('reverts if insufficient sender balance', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError( + this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount), + 'AddressInsufficientBalance', + [this.mock.address], + ); + }); + + it('calls the requested function with existing value', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const tracker = await balance.tracker(this.target.address); + + await send.ether(other, this.mock.address, amount); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount); + expectEvent(receipt, 'return$functionCallWithValue', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + + expect(await tracker.delta()).to.be.bignumber.equal(amount); + }); + + it('calls the requested function with transaction funds', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + const tracker = await balance.tracker(this.target.address); + + expect(await balance.current(this.mock.address)).to.be.bignumber.equal('0'); + + const receipt = await this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount, { + from: other, + value: amount, + }); + expectEvent(receipt, 'return$functionCallWithValue', { + ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']), + }); + await expectEvent.inTransaction(receipt.tx, CallReceiverMock, 'MockFunctionCalled'); + + expect(await tracker.delta()).to.be.bignumber.equal(amount); + }); + + it('reverts when calling non-payable functions', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionNonPayable().encodeABI(); + + await send.ether(other, this.mock.address, amount); + await expectRevertCustomError( + this.mock.$functionCallWithValue(this.target.address, abiEncodedCall, amount), + 'FailedInnerCall', + [], + ); + }); + }); + }); + + describe('functionStaticCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + it('calls the requested function', async function () { + const abiEncodedCall = this.target.contract.methods.mockStaticFunction().encodeABI(); + + expect(await this.mock.$functionStaticCall(this.target.address, abiEncodedCall)).to.be.equal( + web3.eth.abi.encodeParameters(['string'], ['0x1234']), + ); + }); + + it('reverts on a non-static function', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError( + this.mock.$functionStaticCall(this.target.address, abiEncodedCall), + 'FailedInnerCall', + [], + ); + }); + + it('bubbles up revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert( + this.mock.$functionStaticCall(this.target.address, abiEncodedCall), + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError(this.mock.$functionStaticCall(recipient, abiEncodedCall), 'AddressEmptyCode', [ + recipient, + ]); + }); + }); + + describe('functionDelegateCall', function () { + beforeEach(async function () { + this.target = await CallReceiverMock.new(); + }); + + it('delegate calls the requested function', async function () { + // pseudorandom values + const slot = '0x93e4c53af435ddf777c3de84bb9a953a777788500e229a468ea1036496ab66a0'; + const value = '0x6a465d1c49869f71fb65562bcbd7e08c8044074927f0297127203f2a9924ff5b'; + + const abiEncodedCall = this.target.contract.methods.mockFunctionWritesStorage(slot, value).encodeABI(); + + expect(await web3.eth.getStorageAt(this.mock.address, slot)).to.be.equal(constants.ZERO_BYTES32); + + expectEvent( + await this.mock.$functionDelegateCall(this.target.address, abiEncodedCall), + 'return$functionDelegateCall', + { ret0: web3.eth.abi.encodeParameters(['string'], ['0x1234']) }, + ); + + expect(await web3.eth.getStorageAt(this.mock.address, slot)).to.be.equal(value); + }); + + it('bubbles up revert reason', async function () { + const abiEncodedCall = this.target.contract.methods.mockFunctionRevertsReason().encodeABI(); + + await expectRevert( + this.mock.$functionDelegateCall(this.target.address, abiEncodedCall), + 'CallReceiverMock: reverting', + ); + }); + + it('reverts when address is not a contract', async function () { + const [recipient] = accounts; + const abiEncodedCall = this.target.contract.methods.mockFunction().encodeABI(); + + await expectRevertCustomError(this.mock.$functionDelegateCall(recipient, abiEncodedCall), 'AddressEmptyCode', [ + recipient, + ]); + }); + }); + + describe('verifyCallResult', function () { + it('returns returndata on success', async function () { + const returndata = '0x123abc'; + expect(await this.mock.$verifyCallResult(true, returndata)).to.equal(returndata); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/Arrays.test.js b/lib/openzeppelin-contracts/test/utils/Arrays.test.js new file mode 100644 index 0000000..d939d59 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Arrays.test.js @@ -0,0 +1,123 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const AddressArraysMock = artifacts.require('AddressArraysMock'); +const Bytes32ArraysMock = artifacts.require('Bytes32ArraysMock'); +const Uint256ArraysMock = artifacts.require('Uint256ArraysMock'); + +contract('Arrays', function () { + describe('findUpperBound', function () { + context('Even number of elements', function () { + const EVEN_ELEMENTS_ARRAY = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(EVEN_ELEMENTS_ARRAY); + }); + + it('returns correct index for the basic case', async function () { + expect(await this.arrays.findUpperBound(16)).to.be.bignumber.equal('5'); + }); + + it('returns 0 for the first element', async function () { + expect(await this.arrays.findUpperBound(11)).to.be.bignumber.equal('0'); + }); + + it('returns index of the last element', async function () { + expect(await this.arrays.findUpperBound(20)).to.be.bignumber.equal('9'); + }); + + it('returns first index after last element if searched value is over the upper boundary', async function () { + expect(await this.arrays.findUpperBound(32)).to.be.bignumber.equal('10'); + }); + + it('returns 0 for the element under the lower boundary', async function () { + expect(await this.arrays.findUpperBound(2)).to.be.bignumber.equal('0'); + }); + }); + + context('Odd number of elements', function () { + const ODD_ELEMENTS_ARRAY = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(ODD_ELEMENTS_ARRAY); + }); + + it('returns correct index for the basic case', async function () { + expect(await this.arrays.findUpperBound(16)).to.be.bignumber.equal('5'); + }); + + it('returns 0 for the first element', async function () { + expect(await this.arrays.findUpperBound(11)).to.be.bignumber.equal('0'); + }); + + it('returns index of the last element', async function () { + expect(await this.arrays.findUpperBound(21)).to.be.bignumber.equal('10'); + }); + + it('returns first index after last element if searched value is over the upper boundary', async function () { + expect(await this.arrays.findUpperBound(32)).to.be.bignumber.equal('11'); + }); + + it('returns 0 for the element under the lower boundary', async function () { + expect(await this.arrays.findUpperBound(2)).to.be.bignumber.equal('0'); + }); + }); + + context('Array with gap', function () { + const WITH_GAP_ARRAY = [11, 12, 13, 14, 15, 20, 21, 22, 23, 24]; + + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new(WITH_GAP_ARRAY); + }); + + it('returns index of first element in next filled range', async function () { + expect(await this.arrays.findUpperBound(17)).to.be.bignumber.equal('5'); + }); + }); + + context('Empty array', function () { + beforeEach(async function () { + this.arrays = await Uint256ArraysMock.new([]); + }); + + it('always returns 0 for empty array', async function () { + expect(await this.arrays.findUpperBound(10)).to.be.bignumber.equal('0'); + }); + }); + }); + + describe('unsafeAccess', function () { + for (const { type, artifact, elements } of [ + { + type: 'address', + artifact: AddressArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(20)), + }, + { + type: 'bytes32', + artifact: Bytes32ArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(32)), + }, + { + type: 'uint256', + artifact: Uint256ArraysMock, + elements: Array(10) + .fill() + .map(() => web3.utils.randomHex(32)), + }, + ]) { + it(type, async function () { + const contract = await artifact.new(elements); + + for (const i in elements) { + expect(await contract.unsafeAccess(i)).to.be.bignumber.equal(elements[i]); + } + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/Base64.test.js b/lib/openzeppelin-contracts/test/utils/Base64.test.js new file mode 100644 index 0000000..dfff0b0 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Base64.test.js @@ -0,0 +1,33 @@ +const { expect } = require('chai'); + +const Base64 = artifacts.require('$Base64'); + +contract('Strings', function () { + beforeEach(async function () { + this.base64 = await Base64.new(); + }); + + describe('from bytes - base64', function () { + it('converts to base64 encoded string with double padding', async function () { + const TEST_MESSAGE = 'test'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdA=='); + }); + + it('converts to base64 encoded string with single padding', async function () { + const TEST_MESSAGE = 'test1'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdDE='); + }); + + it('converts to base64 encoded string without padding', async function () { + const TEST_MESSAGE = 'test12'; + const input = web3.utils.asciiToHex(TEST_MESSAGE); + expect(await this.base64.$encode(input)).to.equal('dGVzdDEy'); + }); + + it('empty bytes', async function () { + expect(await this.base64.$encode([])).to.equal(''); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/Context.behavior.js b/lib/openzeppelin-contracts/test/utils/Context.behavior.js new file mode 100644 index 0000000..08f7558 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Context.behavior.js @@ -0,0 +1,42 @@ +const { BN, expectEvent } = require('@openzeppelin/test-helpers'); + +const ContextMock = artifacts.require('ContextMock'); + +function shouldBehaveLikeRegularContext(sender) { + describe('msgSender', function () { + it('returns the transaction sender when called from an EOA', async function () { + const receipt = await this.context.msgSender({ from: sender }); + expectEvent(receipt, 'Sender', { sender }); + }); + + it('returns the transaction sender when from another contract', async function () { + const { tx } = await this.caller.callSender(this.context.address, { from: sender }); + await expectEvent.inTransaction(tx, ContextMock, 'Sender', { sender: this.caller.address }); + }); + }); + + describe('msgData', function () { + const integerValue = new BN('42'); + const stringValue = 'OpenZeppelin'; + + let callData; + + beforeEach(async function () { + callData = this.context.contract.methods.msgData(integerValue.toString(), stringValue).encodeABI(); + }); + + it('returns the transaction data when called from an EOA', async function () { + const receipt = await this.context.msgData(integerValue, stringValue); + expectEvent(receipt, 'Data', { data: callData, integerValue, stringValue }); + }); + + it('returns the transaction sender when from another contract', async function () { + const { tx } = await this.caller.callData(this.context.address, integerValue, stringValue); + await expectEvent.inTransaction(tx, ContextMock, 'Data', { data: callData, integerValue, stringValue }); + }); + }); +} + +module.exports = { + shouldBehaveLikeRegularContext, +}; diff --git a/lib/openzeppelin-contracts/test/utils/Context.test.js b/lib/openzeppelin-contracts/test/utils/Context.test.js new file mode 100644 index 0000000..f372f74 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Context.test.js @@ -0,0 +1,17 @@ +require('@openzeppelin/test-helpers'); + +const ContextMock = artifacts.require('ContextMock'); +const ContextMockCaller = artifacts.require('ContextMockCaller'); + +const { shouldBehaveLikeRegularContext } = require('./Context.behavior'); + +contract('Context', function (accounts) { + const [sender] = accounts; + + beforeEach(async function () { + this.context = await ContextMock.new(); + this.caller = await ContextMockCaller.new(); + }); + + shouldBehaveLikeRegularContext(sender); +}); diff --git a/lib/openzeppelin-contracts/test/utils/Create2.test.js b/lib/openzeppelin-contracts/test/utils/Create2.test.js new file mode 100644 index 0000000..336ab1a --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Create2.test.js @@ -0,0 +1,102 @@ +const { balance, ether, expectEvent, expectRevert, send } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { computeCreate2Address } = require('../helpers/create'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const Create2 = artifacts.require('$Create2'); +const VestingWallet = artifacts.require('VestingWallet'); +// This should be a contract that: +// - has no constructor arguments +// - has no immutable variable populated during construction +const ConstructorLessContract = Create2; + +contract('Create2', function (accounts) { + const [deployerAccount, other] = accounts; + + const salt = 'salt message'; + const saltHex = web3.utils.soliditySha3(salt); + + const encodedParams = web3.eth.abi.encodeParameters(['address', 'uint64', 'uint64'], [other, 0, 0]).slice(2); + + const constructorByteCode = `${VestingWallet.bytecode}${encodedParams}`; + + beforeEach(async function () { + this.factory = await Create2.new(); + }); + describe('computeAddress', function () { + it('computes the correct contract address', async function () { + const onChainComputed = await this.factory.$computeAddress(saltHex, web3.utils.keccak256(constructorByteCode)); + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + expect(onChainComputed).to.equal(offChainComputed); + }); + + it('computes the correct contract address with deployer', async function () { + const onChainComputed = await this.factory.$computeAddress( + saltHex, + web3.utils.keccak256(constructorByteCode), + deployerAccount, + ); + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, deployerAccount); + expect(onChainComputed).to.equal(offChainComputed); + }); + }); + + describe('deploy', function () { + it('deploys a contract without constructor', async function () { + const offChainComputed = computeCreate2Address(saltHex, ConstructorLessContract.bytecode, this.factory.address); + + expectEvent(await this.factory.$deploy(0, saltHex, ConstructorLessContract.bytecode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(ConstructorLessContract.bytecode).to.include((await web3.eth.getCode(offChainComputed)).slice(2)); + }); + + it('deploys a contract with constructor arguments', async function () { + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + + expectEvent(await this.factory.$deploy(0, saltHex, constructorByteCode), 'return$deploy', { + addr: offChainComputed, + }); + + const instance = await VestingWallet.at(offChainComputed); + + expect(await instance.owner()).to.be.equal(other); + }); + + it('deploys a contract with funds deposited in the factory', async function () { + const deposit = ether('2'); + await send.ether(deployerAccount, this.factory.address, deposit); + expect(await balance.current(this.factory.address)).to.be.bignumber.equal(deposit); + + const offChainComputed = computeCreate2Address(saltHex, constructorByteCode, this.factory.address); + + expectEvent(await this.factory.$deploy(deposit, saltHex, constructorByteCode), 'return$deploy', { + addr: offChainComputed, + }); + + expect(await balance.current(offChainComputed)).to.be.bignumber.equal(deposit); + }); + + it('fails deploying a contract in an existent address', async function () { + expectEvent(await this.factory.$deploy(0, saltHex, constructorByteCode), 'return$deploy'); + + // TODO: Make sure it actually throws "Create2FailedDeployment". + // For some unknown reason, the revert reason sometimes return: + // `revert with unrecognized return data or custom error` + await expectRevert.unspecified(this.factory.$deploy(0, saltHex, constructorByteCode)); + }); + + it('fails deploying a contract if the bytecode length is zero', async function () { + await expectRevertCustomError(this.factory.$deploy(0, saltHex, '0x'), 'Create2EmptyBytecode', []); + }); + + it('fails deploying a contract if factory contract does not have sufficient balance', async function () { + await expectRevertCustomError( + this.factory.$deploy(1, saltHex, constructorByteCode), + 'Create2InsufficientBalance', + [0, 1], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/Multicall.test.js b/lib/openzeppelin-contracts/test/utils/Multicall.test.js new file mode 100644 index 0000000..65443cd --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Multicall.test.js @@ -0,0 +1,69 @@ +const { BN } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const ERC20MulticallMock = artifacts.require('$ERC20MulticallMock'); + +contract('Multicall', function (accounts) { + const [deployer, alice, bob] = accounts; + const amount = 12000; + + beforeEach(async function () { + this.multicallToken = await ERC20MulticallMock.new('name', 'symbol'); + await this.multicallToken.$_mint(deployer, amount); + }); + + it('batches function calls', async function () { + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + expect(await this.multicallToken.balanceOf(bob)).to.be.bignumber.equal(new BN('0')); + + await this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount / 2).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount / 3).encodeABI(), + ], + { from: deployer }, + ); + + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN(amount / 2)); + expect(await this.multicallToken.balanceOf(bob)).to.be.bignumber.equal(new BN(amount / 3)); + }); + + it('returns an array with the result of each call', async function () { + const MulticallTest = artifacts.require('MulticallTest'); + const multicallTest = await MulticallTest.new({ from: deployer }); + await this.multicallToken.transfer(multicallTest.address, amount, { from: deployer }); + expect(await this.multicallToken.balanceOf(multicallTest.address)).to.be.bignumber.equal(new BN(amount)); + + const recipients = [alice, bob]; + const amounts = [amount / 2, amount / 3].map(n => new BN(n)); + + await multicallTest.checkReturnValues(this.multicallToken.address, recipients, amounts); + }); + + it('reverts previous calls', async function () { + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + + const call = this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount).encodeABI(), + ], + { from: deployer }, + ); + + await expectRevertCustomError(call, 'ERC20InsufficientBalance', [deployer, 0, amount]); + expect(await this.multicallToken.balanceOf(alice)).to.be.bignumber.equal(new BN('0')); + }); + + it('bubbles up revert reasons', async function () { + const call = this.multicallToken.multicall( + [ + this.multicallToken.contract.methods.transfer(alice, amount).encodeABI(), + this.multicallToken.contract.methods.transfer(bob, amount).encodeABI(), + ], + { from: deployer }, + ); + + await expectRevertCustomError(call, 'ERC20InsufficientBalance', [deployer, 0, amount]); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/Nonces.test.js b/lib/openzeppelin-contracts/test/utils/Nonces.test.js new file mode 100644 index 0000000..67a3087 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Nonces.test.js @@ -0,0 +1,71 @@ +const expectEvent = require('@openzeppelin/test-helpers/src/expectEvent'); +const { expectRevertCustomError } = require('../helpers/customError'); + +require('@openzeppelin/test-helpers'); + +const Nonces = artifacts.require('$Nonces'); + +contract('Nonces', function (accounts) { + const [sender, other] = accounts; + + beforeEach(async function () { + this.nonces = await Nonces.new(); + }); + + it('gets a nonce', async function () { + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('0'); + }); + + describe('_useNonce', function () { + it('increments a nonce', async function () { + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('0'); + + const { receipt } = await this.nonces.$_useNonce(sender); + expectEvent(receipt, 'return$_useNonce', ['0']); + + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('1'); + }); + + it("increments only sender's nonce", async function () { + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('0'); + expect(await this.nonces.nonces(other)).to.be.bignumber.equal('0'); + + await this.nonces.$_useNonce(sender); + + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('1'); + expect(await this.nonces.nonces(other)).to.be.bignumber.equal('0'); + }); + }); + + describe('_useCheckedNonce', function () { + it('increments a nonce', async function () { + const currentNonce = await this.nonces.nonces(sender); + expect(currentNonce).to.be.bignumber.equal('0'); + + await this.nonces.$_useCheckedNonce(sender, currentNonce); + + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('1'); + }); + + it("increments only sender's nonce", async function () { + const currentNonce = await this.nonces.nonces(sender); + + expect(currentNonce).to.be.bignumber.equal('0'); + expect(await this.nonces.nonces(other)).to.be.bignumber.equal('0'); + + await this.nonces.$_useCheckedNonce(sender, currentNonce); + + expect(await this.nonces.nonces(sender)).to.be.bignumber.equal('1'); + expect(await this.nonces.nonces(other)).to.be.bignumber.equal('0'); + }); + + it('reverts when nonce is not the expected', async function () { + const currentNonce = await this.nonces.nonces(sender); + await expectRevertCustomError( + this.nonces.$_useCheckedNonce(sender, currentNonce.addn(1)), + 'InvalidAccountNonce', + [sender, currentNonce], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/Pausable.test.js b/lib/openzeppelin-contracts/test/utils/Pausable.test.js new file mode 100644 index 0000000..e60a62c --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Pausable.test.js @@ -0,0 +1,86 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../helpers/customError'); + +const PausableMock = artifacts.require('PausableMock'); + +contract('Pausable', function (accounts) { + const [pauser] = accounts; + + beforeEach(async function () { + this.pausable = await PausableMock.new(); + }); + + context('when unpaused', function () { + beforeEach(async function () { + expect(await this.pausable.paused()).to.equal(false); + }); + + it('can perform normal process in non-pause', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('cannot take drastic measure in non-pause', async function () { + await expectRevertCustomError(this.pausable.drasticMeasure(), 'ExpectedPause', []); + expect(await this.pausable.drasticMeasureTaken()).to.equal(false); + }); + + context('when paused', function () { + beforeEach(async function () { + this.receipt = await this.pausable.pause({ from: pauser }); + }); + + it('emits a Paused event', function () { + expectEvent(this.receipt, 'Paused', { account: pauser }); + }); + + it('cannot perform normal process in pause', async function () { + await expectRevertCustomError(this.pausable.normalProcess(), 'EnforcedPause', []); + }); + + it('can take a drastic measure in a pause', async function () { + await this.pausable.drasticMeasure(); + expect(await this.pausable.drasticMeasureTaken()).to.equal(true); + }); + + it('reverts when re-pausing', async function () { + await expectRevertCustomError(this.pausable.pause(), 'EnforcedPause', []); + }); + + describe('unpausing', function () { + it('is unpausable by the pauser', async function () { + await this.pausable.unpause(); + expect(await this.pausable.paused()).to.equal(false); + }); + + context('when unpaused', function () { + beforeEach(async function () { + this.receipt = await this.pausable.unpause({ from: pauser }); + }); + + it('emits an Unpaused event', function () { + expectEvent(this.receipt, 'Unpaused', { account: pauser }); + }); + + it('should resume allowing normal process', async function () { + expect(await this.pausable.count()).to.be.bignumber.equal('0'); + await this.pausable.normalProcess(); + expect(await this.pausable.count()).to.be.bignumber.equal('1'); + }); + + it('should prevent drastic measure', async function () { + await expectRevertCustomError(this.pausable.drasticMeasure(), 'ExpectedPause', []); + }); + + it('reverts when re-unpausing', async function () { + await expectRevertCustomError(this.pausable.unpause(), 'ExpectedPause', []); + }); + }); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js b/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js new file mode 100644 index 0000000..15355c0 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/ReentrancyGuard.test.js @@ -0,0 +1,44 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const { expectRevertCustomError } = require('../helpers/customError'); + +const ReentrancyMock = artifacts.require('ReentrancyMock'); +const ReentrancyAttack = artifacts.require('ReentrancyAttack'); + +contract('ReentrancyGuard', function () { + beforeEach(async function () { + this.reentrancyMock = await ReentrancyMock.new(); + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('0'); + }); + + it('nonReentrant function can be called', async function () { + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('0'); + await this.reentrancyMock.callback(); + expect(await this.reentrancyMock.counter()).to.be.bignumber.equal('1'); + }); + + it('does not allow remote callback', async function () { + const attacker = await ReentrancyAttack.new(); + await expectRevert(this.reentrancyMock.countAndCall(attacker.address), 'ReentrancyAttack: failed call', []); + }); + + it('_reentrancyGuardEntered should be true when guarded', async function () { + await this.reentrancyMock.guardedCheckEntered(); + }); + + it('_reentrancyGuardEntered should be false when unguarded', async function () { + await this.reentrancyMock.unguardedCheckNotEntered(); + }); + + // The following are more side-effects than intended behavior: + // I put them here as documentation, and to monitor any changes + // in the side-effects. + it('does not allow local recursion', async function () { + await expectRevertCustomError(this.reentrancyMock.countLocalRecursive(10), 'ReentrancyGuardReentrantCall', []); + }); + + it('does not allow indirect local recursion', async function () { + await expectRevert(this.reentrancyMock.countThisRecursive(10), 'ReentrancyMock: failed call', []); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol b/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol new file mode 100644 index 0000000..b854d27 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/ShortStrings.t.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {ShortStrings, ShortString} from "@openzeppelin/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; + } +} diff --git a/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js b/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js new file mode 100644 index 0000000..189281d --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/ShortStrings.test.js @@ -0,0 +1,55 @@ +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const ShortStrings = artifacts.require('$ShortStrings'); + +function length(sstr) { + return parseInt(sstr.slice(64), 16); +} + +function decode(sstr) { + return web3.utils.toUtf8(sstr).slice(0, length(sstr)); +} + +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.$byteLength(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; + + const promise = this.mock.$toString(ret0); + if (str.length < 32) { + expect(await promise).to.be.equal(str); + } else { + 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); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js b/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js new file mode 100644 index 0000000..846512e --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/StorageSlot.test.js @@ -0,0 +1,210 @@ +const { constants, BN } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const StorageSlotMock = artifacts.require('StorageSlotMock'); + +const slot = web3.utils.keccak256('some.storage.slot'); +const otherSlot = web3.utils.keccak256('some.other.storage.slot'); + +contract('StorageSlot', function (accounts) { + beforeEach(async function () { + this.store = await StorageSlotMock.new(); + }); + + describe('boolean storage slot', function () { + beforeEach(async function () { + this.value = true; + }); + + it('set', async function () { + await this.store.setBoolean(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBoolean(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBoolean(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBoolean(otherSlot)).to.be.equal(false); + }); + }); + }); + + describe('address storage slot', function () { + beforeEach(async function () { + this.value = accounts[1]; + }); + + it('set', async function () { + await this.store.setAddress(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setAddress(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getAddress(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getAddress(otherSlot)).to.be.equal(constants.ZERO_ADDRESS); + }); + }); + }); + + describe('bytes32 storage slot', function () { + beforeEach(async function () { + this.value = web3.utils.keccak256('some byte32 value'); + }); + + it('set', async function () { + await this.store.setBytes32(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setBytes32(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getBytes32(slot)).to.be.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getBytes32(otherSlot)).to.be.equal(constants.ZERO_BYTES32); + }); + }); + }); + + describe('uint256 storage slot', function () { + beforeEach(async function () { + this.value = new BN(1742); + }); + + it('set', async function () { + await this.store.setUint256(slot, this.value); + }); + + describe('get', function () { + beforeEach(async function () { + await this.store.setUint256(slot, this.value); + }); + + it('from right slot', async function () { + expect(await this.store.getUint256(slot)).to.be.bignumber.equal(this.value); + }); + + it('from other slot', async function () { + expect(await this.store.getUint256(otherSlot)).to.be.bignumber.equal('0'); + }); + }); + }); + + 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); + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/Strings.test.js b/lib/openzeppelin-contracts/test/utils/Strings.test.js new file mode 100644 index 0000000..2435fc7 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/Strings.test.js @@ -0,0 +1,153 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../helpers/customError'); + +const { expect } = require('chai'); + +const Strings = artifacts.require('$Strings'); + +contract('Strings', function () { + before(async function () { + this.strings = await Strings.new(); + }); + + describe('toString', function () { + const values = [ + '0', + '7', + '10', + '99', + '100', + '101', + '123', + '4132', + '12345', + '1234567', + '1234567890', + '123456789012345', + '12345678901234567890', + '123456789012345678901234567890', + '1234567890123456789012345678901234567890', + '12345678901234567890123456789012345678901234567890', + '123456789012345678901234567890123456789012345678901234567890', + '1234567890123456789012345678901234567890123456789012345678901234567890', + ]; + + describe('uint256', function () { + it('converts MAX_UINT256', async function () { + const value = constants.MAX_UINT256; + expect(await this.strings.methods['$toString(uint256)'](value)).to.equal(value.toString(10)); + }); + + for (const value of values) { + it(`converts ${value}`, async function () { + expect(await this.strings.methods['$toString(uint256)'](value)).to.equal(value); + }); + } + }); + + describe('int256', function () { + it('converts MAX_INT256', async function () { + const value = constants.MAX_INT256; + expect(await this.strings.methods['$toStringSigned(int256)'](value)).to.equal(value.toString(10)); + }); + + it('converts MIN_INT256', async function () { + const value = constants.MIN_INT256; + expect(await this.strings.methods['$toStringSigned(int256)'](value)).to.equal(value.toString(10)); + }); + + for (const value of values) { + it(`convert ${value}`, async function () { + expect(await this.strings.methods['$toStringSigned(int256)'](value)).to.equal(value); + }); + + it(`convert negative ${value}`, async function () { + const negated = new BN(value).neg(); + expect(await this.strings.methods['$toStringSigned(int256)'](negated)).to.equal(negated.toString(10)); + }); + } + }); + }); + + describe('toHexString', function () { + it('converts 0', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](0)).to.equal('0x00'); + }); + + it('converts a positive number', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](0x4132)).to.equal('0x4132'); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.strings.methods['$toHexString(uint256)'](constants.MAX_UINT256)).to.equal( + web3.utils.toHex(constants.MAX_UINT256), + ); + }); + }); + + describe('toHexString fixed', function () { + it('converts a positive number (long)', async function () { + expect(await this.strings.methods['$toHexString(uint256,uint256)'](0x4132, 32)).to.equal( + '0x0000000000000000000000000000000000000000000000000000000000004132', + ); + }); + + it('converts a positive number (short)', async function () { + const length = 1; + await expectRevertCustomError( + this.strings.methods['$toHexString(uint256,uint256)'](0x4132, length), + `StringsInsufficientHexLength`, + [0x4132, length], + ); + }); + + it('converts MAX_UINT256', async function () { + expect(await this.strings.methods['$toHexString(uint256,uint256)'](constants.MAX_UINT256, 32)).to.equal( + web3.utils.toHex(constants.MAX_UINT256), + ); + }); + }); + + describe('toHexString address', function () { + it('converts a random address', async function () { + const addr = '0xa9036907dccae6a1e0033479b12e837e5cf5a02f'; + expect(await this.strings.methods['$toHexString(address)'](addr)).to.equal(addr); + }); + + it('converts an address with leading zeros', async function () { + const addr = '0x0000e0ca771e21bd00057f54a68c30d400000000'; + expect(await this.strings.methods['$toHexString(address)'](addr)).to.equal(addr); + }); + }); + + describe('equal', function () { + it('compares two empty strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('', '')).to.equal(true); + }); + + it('compares two equal strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'a')).to.equal(true); + }); + + it('compares two different strings', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'b')).to.equal(false); + }); + + it('compares two different strings of different lengths', async function () { + expect(await this.strings.methods['$equal(string,string)']('a', 'aa')).to.equal(false); + expect(await this.strings.methods['$equal(string,string)']('aa', 'a')).to.equal(false); + }); + + it('compares two different large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(200) + 'b'; + expect(await this.strings.methods['$equal(string,string)'](str1, str2)).to.equal(false); + }); + + it('compares two equal large strings', async function () { + const str1 = 'a'.repeat(201); + const str2 = 'a'.repeat(201); + expect(await this.strings.methods['$equal(string,string)'](str1, str2)).to.equal(true); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js b/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js new file mode 100644 index 0000000..f164ef1 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/cryptography/ECDSA.test.js @@ -0,0 +1,245 @@ +require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); +const { toEthSignedMessageHash } = require('../../helpers/sign'); + +const { expect } = require('chai'); + +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'); + +function to2098Format(signature) { + const long = web3.utils.hexToBytes(signature); + if (long.length !== 65) { + throw new Error('invalid signature length (expected long format)'); + } + if (long[32] >> 7 === 1) { + throw new Error("invalid signature 's' value"); + } + const short = long.slice(0, 64); + short[32] |= long[64] % 27 << 7; // set the first bit of the 32nd byte to the v parity bit + return web3.utils.bytesToHex(short); +} + +function split(signature) { + const raw = web3.utils.hexToBytes(signature); + switch (raw.length) { + case 64: + return [ + web3.utils.bytesToHex(raw.slice(0, 32)), // r + web3.utils.bytesToHex(raw.slice(32, 64)), // vs + ]; + case 65: + return [ + raw[64], // v + web3.utils.bytesToHex(raw.slice(0, 32)), // r + web3.utils.bytesToHex(raw.slice(32, 64)), // s + ]; + default: + expect.fail('Invalid signature length, cannot split'); + } +} + +contract('ECDSA', function (accounts) { + const [other] = accounts; + + beforeEach(async function () { + this.ecdsa = await ECDSA.new(); + }); + + context('recover with invalid signature', function () { + it('with short signature', async function () { + await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, '0x1234'), 'ECDSAInvalidSignatureLength', [2]); + }); + + it('with long signature', async function () { + await expectRevertCustomError( + // eslint-disable-next-line max-len + this.ecdsa.$recover( + TEST_MESSAGE, + '0x01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789', + ), + 'ECDSAInvalidSignatureLength', + [85], + ); + }); + }); + + context('recover with valid signature', function () { + context('using web3.eth.sign', function () { + it('returns signer address with correct signature', async function () { + // Create the signature + const signature = await web3.eth.sign(TEST_MESSAGE, other); + + // Recover the signer address from the generated message and signature. + expect(await this.ecdsa.$recover(toEthSignedMessageHash(TEST_MESSAGE), signature)).to.equal(other); + }); + + it('returns signer address with correct signature for arbitrary length message', async function () { + // Create the signature + const signature = await web3.eth.sign(NON_HASH_MESSAGE, other); + + // Recover the signer address from the generated message and signature. + expect(await this.ecdsa.$recover(toEthSignedMessageHash(NON_HASH_MESSAGE), signature)).to.equal(other); + }); + + it('returns a different address', async function () { + const signature = await web3.eth.sign(TEST_MESSAGE, other); + expect(await this.ecdsa.$recover(WRONG_MESSAGE, signature)).to.not.equal(other); + }); + + it('reverts with invalid signature', async function () { + // eslint-disable-next-line max-len + const signature = + '0x332ce75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e01c'; + await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []); + }); + }); + + context('with v=27 signature', function () { + // Signature generated outside ganache with method web3.eth.sign(signer, message) + const signer = '0x2cc1166f6212628A0deEf2B33BEFB2187D35b86c'; + // eslint-disable-next-line max-len + const signatureWithoutV = + '0x5d99b6f7f6d1f73d1a26497f2b1c89b24c0993913f86e9a2d02cd69887d9c94f3c880358579d811b21dd1b7fd9bb01c1d81d10e69f0384e675c32b39643be892'; + + it('works with correct v value', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '1c'; // 28 = 1c. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.not.equal(signer); + }); + + it('reverts wrong v values', async function () { + for (const v of ['00', '01']) { + const signature = signatureWithoutV + v; + await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []); + + await expectRevertCustomError( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + 'ECDSAInvalidSignature', + [], + ); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + await expectRevertCustomError( + this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)), + 'ECDSAInvalidSignatureLength', + [64], + ); + }); + }); + + context('with v=28 signature', function () { + const signer = '0x1E318623aB09Fe6de3C9b8672098464Aeda9100E'; + // eslint-disable-next-line max-len + const signatureWithoutV = + '0x331fe75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e0'; + + it('works with correct v value', async function () { + const v = '1c'; // 28 = 1c. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.equal(signer); + }); + + it('rejects incorrect v value', async function () { + const v = '1b'; // 27 = 1b. + const signature = signatureWithoutV + v; + expect(await this.ecdsa.$recover(TEST_MESSAGE, signature)).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + ).to.not.equal(signer); + + expect( + await this.ecdsa.methods['$recover(bytes32,bytes32,bytes32)']( + TEST_MESSAGE, + ...split(to2098Format(signature)), + ), + ).to.not.equal(signer); + }); + + it('reverts invalid v values', async function () { + for (const v of ['00', '01']) { + const signature = signatureWithoutV + v; + await expectRevertCustomError(this.ecdsa.$recover(TEST_MESSAGE, signature), 'ECDSAInvalidSignature', []); + + await expectRevertCustomError( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, ...split(signature)), + 'ECDSAInvalidSignature', + [], + ); + } + }); + + it('rejects short EIP2098 format', async function () { + const v = '1c'; // 27 = 1b. + const signature = signatureWithoutV + v; + await expectRevertCustomError( + this.ecdsa.$recover(TEST_MESSAGE, to2098Format(signature)), + 'ECDSAInvalidSignatureLength', + [64], + ); + }); + }); + + it('reverts with high-s value signature', async function () { + const message = '0xb94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'; + // eslint-disable-next-line max-len + const highSSignature = + '0xe742ff452d41413616a5bf43fe15dd88294e983d3d36206c2712f39083d638bde0a0fc89be718fbc1033e1d30d78be1c68081562ed2e97af876f286f3453231d1b'; + const [r, v, s] = split(highSSignature); + await expectRevertCustomError(this.ecdsa.$recover(message, highSSignature), 'ECDSAInvalidSignatureS', [s]); + await expectRevertCustomError( + this.ecdsa.methods['$recover(bytes32,uint8,bytes32,bytes32)'](TEST_MESSAGE, r, v, s), + 'ECDSAInvalidSignatureS', + [s], + ); + expect(() => to2098Format(highSSignature)).to.throw("invalid signature 's' value"); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js b/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js new file mode 100644 index 0000000..faf01f1 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/cryptography/EIP712.test.js @@ -0,0 +1,111 @@ +const ethSigUtil = require('eth-sig-util'); +const Wallet = require('ethereumjs-wallet').default; + +const { getDomain, domainType, domainSeparator, hashTypedData } = require('../../helpers/eip712'); +const { getChainId } = require('../../helpers/chainid'); +const { mapValues } = require('../../helpers/iterate'); + +const EIP712Verifier = artifacts.require('$EIP712Verifier'); +const Clones = artifacts.require('$Clones'); + +contract('EIP712', function (accounts) { + const [mailTo] = accounts; + + const shortName = 'A Name'; + const shortVersion = '1'; + + const longName = 'A'.repeat(40); + const longVersion = 'B'.repeat(40); + + const cases = [ + ['short', shortName, shortVersion], + ['long', longName, longVersion], + ]; + + 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); + + 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 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 () { + 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('name', async function () { + expect(await this.eip712.$_EIP712Name()).to.be.equal(name); + }); + + it('version', async function () { + expect(await this.eip712.$_EIP712Version()).to.be.equal(version); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js b/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js new file mode 100644 index 0000000..5b87bc5 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/cryptography/MerkleProof.test.js @@ -0,0 +1,207 @@ +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const { MerkleTree } = require('merkletreejs'); +const keccak256 = require('keccak256'); + +const { expect } = require('chai'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const MerkleProof = artifacts.require('$MerkleProof'); + +contract('MerkleProof', function () { + beforeEach(async function () { + this.merkleProof = await MerkleProof.new(); + }); + + describe('verify', function () { + it('returns true for a valid Merkle proof', async function () { + const elements = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''); + const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true }); + + const root = merkleTree.getHexRoot(); + + const leaf = keccak256(elements[0]); + + const proof = merkleTree.getHexProof(leaf); + + expect(await this.merkleProof.$verify(proof, root, leaf)).to.equal(true); + expect(await this.merkleProof.$verifyCalldata(proof, root, leaf)).to.equal(true); + + // For demonstration, it is also possible to create valid proofs for certain 64-byte values *not* in elements: + const noSuchLeaf = keccak256( + Buffer.concat([keccak256(elements[0]), keccak256(elements[1])].sort(Buffer.compare)), + ); + expect(await this.merkleProof.$verify(proof.slice(1), root, noSuchLeaf)).to.equal(true); + expect(await this.merkleProof.$verifyCalldata(proof.slice(1), root, noSuchLeaf)).to.equal(true); + }); + + it('returns false for an invalid Merkle proof', async function () { + const correctElements = ['a', 'b', 'c']; + const correctMerkleTree = new MerkleTree(correctElements, keccak256, { hashLeaves: true, sortPairs: true }); + + const correctRoot = correctMerkleTree.getHexRoot(); + + const correctLeaf = keccak256(correctElements[0]); + + const badElements = ['d', 'e', 'f']; + const badMerkleTree = new MerkleTree(badElements); + + const badProof = badMerkleTree.getHexProof(badElements[0]); + + expect(await this.merkleProof.$verify(badProof, correctRoot, correctLeaf)).to.equal(false); + expect(await this.merkleProof.$verifyCalldata(badProof, correctRoot, correctLeaf)).to.equal(false); + }); + + it('returns false for a Merkle proof of invalid length', async function () { + const elements = ['a', 'b', 'c']; + const merkleTree = new MerkleTree(elements, keccak256, { hashLeaves: true, sortPairs: true }); + + const root = merkleTree.getHexRoot(); + + const leaf = keccak256(elements[0]); + + const proof = merkleTree.getHexProof(leaf); + const badProof = proof.slice(0, proof.length - 5); + + expect(await this.merkleProof.$verify(badProof, root, leaf)).to.equal(false); + expect(await this.merkleProof.$verifyCalldata(badProof, root, leaf)).to.equal(false); + }); + }); + + describe('multiProofVerify', function () { + it('returns true for a valid Merkle multi proof', async function () { + const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const proofLeaves = ['b', 'f', 'd'].map(keccak256).sort(Buffer.compare); + const proof = merkleTree.getMultiProof(proofLeaves); + const proofFlags = merkleTree.getProofFlags(proofLeaves, proof); + + expect(await this.merkleProof.$multiProofVerify(proof, proofFlags, root, proofLeaves)).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata(proof, proofFlags, root, proofLeaves)).to.equal(true); + }); + + it('returns false for an invalid Merkle multi proof', async function () { + const leaves = ['a', 'b', 'c', 'd', 'e', 'f'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const badProofLeaves = ['g', 'h', 'i'].map(keccak256).sort(Buffer.compare); + const badMerkleTree = new MerkleTree(badProofLeaves); + const badProof = badMerkleTree.getMultiProof(badProofLeaves); + const badProofFlags = badMerkleTree.getProofFlags(badProofLeaves, badProof); + + expect(await this.merkleProof.$multiProofVerify(badProof, badProofFlags, root, badProofLeaves)).to.equal(false); + expect(await this.merkleProof.$multiProofVerifyCalldata(badProof, badProofFlags, root, badProofLeaves)).to.equal( + false, + ); + }); + + it('revert with invalid multi proof #1', async function () { + const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const badLeaf = keccak256('e'); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + + await expectRevertCustomError( + this.merkleProof.$multiProofVerify( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false], + root, + [leaves[0], badLeaf], // A, E + ), + 'MerkleProofInvalidMultiproof', + [], + ); + await expectRevertCustomError( + this.merkleProof.$multiProofVerifyCalldata( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false], + root, + [leaves[0], badLeaf], // A, E + ), + 'MerkleProofInvalidMultiproof', + [], + ); + }); + + it('revert with invalid multi proof #2', async function () { + const fill = Buffer.alloc(32); // This could be anything, we are reconstructing a fake branch + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const badLeaf = keccak256('e'); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + + await expectRevert( + this.merkleProof.$multiProofVerify( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false, false], + root, + [badLeaf, leaves[0]], // A, E + ), + 'reverted with panic code 0x32', + ); + + await expectRevert( + this.merkleProof.$multiProofVerifyCalldata( + [leaves[1], fill, merkleTree.layers[1][1]], + [false, false, false, false], + root, + [badLeaf, leaves[0]], // A, E + ), + 'reverted with panic code 0x32', + ); + }); + + it('limit case: works for tree containing a single leaf', async function () { + const leaves = ['a'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + const proofLeaves = ['a'].map(keccak256).sort(Buffer.compare); + const proof = merkleTree.getMultiProof(proofLeaves); + const proofFlags = merkleTree.getProofFlags(proofLeaves, proof); + + expect(await this.merkleProof.$multiProofVerify(proof, proofFlags, root, proofLeaves)).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata(proof, proofFlags, root, proofLeaves)).to.equal(true); + }); + + it('limit case: can prove empty leaves', async function () { + const leaves = ['a', 'b', 'c', 'd'].map(keccak256).sort(Buffer.compare); + const merkleTree = new MerkleTree(leaves, keccak256, { sort: true }); + + const root = merkleTree.getRoot(); + expect(await this.merkleProof.$multiProofVerify([root], [], root, [])).to.equal(true); + expect(await this.merkleProof.$multiProofVerifyCalldata([root], [], root, [])).to.equal(true); + }); + + it('reverts processing manipulated proofs with a zero-value node at depth 1', async function () { + // Create a merkle tree that contains a zero leaf at depth 1 + const leaves = [keccak256('real leaf'), Buffer.alloc(32, 0)]; + const merkleTree = new MerkleTree(leaves, keccak256, { sortPairs: true }); + + const root = merkleTree.getRoot(); + + // Now we can pass any **malicious** fake leaves as valid! + const maliciousLeaves = ['malicious', 'leaves'].map(keccak256).sort(Buffer.compare); + const maliciousProof = [leaves[0], leaves[0]]; + const maliciousProofFlags = [true, true, false]; + + await expectRevertCustomError( + this.merkleProof.$multiProofVerify(maliciousProof, maliciousProofFlags, root, maliciousLeaves), + 'MerkleProofInvalidMultiproof', + [], + ); + + await expectRevertCustomError( + this.merkleProof.$multiProofVerifyCalldata(maliciousProof, maliciousProofFlags, root, maliciousLeaves), + 'MerkleProofInvalidMultiproof', + [], + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js b/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js new file mode 100644 index 0000000..b38e945 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/cryptography/MessageHashUtils.test.js @@ -0,0 +1,55 @@ +require('@openzeppelin/test-helpers'); +const { toEthSignedMessageHash, toDataWithIntendedValidatorHash } = require('../../helpers/sign'); +const { domainSeparator, hashTypedData } = require('../../helpers/eip712'); + +const { expect } = require('chai'); + +const MessageHashUtils = artifacts.require('$MessageHashUtils'); + +contract('MessageHashUtils', function () { + beforeEach(async function () { + this.messageHashUtils = await MessageHashUtils.new(); + + this.message = '0x' + Buffer.from('abcd').toString('hex'); + this.messageHash = web3.utils.sha3(this.message); + this.verifyingAddress = web3.utils.toChecksumAddress(web3.utils.randomHex(20)); + }); + + context('toEthSignedMessageHash', function () { + it('prefixes bytes32 data correctly', async function () { + expect(await this.messageHashUtils.methods['$toEthSignedMessageHash(bytes32)'](this.messageHash)).to.equal( + toEthSignedMessageHash(this.messageHash), + ); + }); + + it('prefixes dynamic length data correctly', async function () { + expect(await this.messageHashUtils.methods['$toEthSignedMessageHash(bytes)'](this.message)).to.equal( + toEthSignedMessageHash(this.message), + ); + }); + }); + + context('toDataWithIntendedValidatorHash', function () { + it('returns the digest correctly', async function () { + expect( + await this.messageHashUtils.$toDataWithIntendedValidatorHash(this.verifyingAddress, this.message), + ).to.equal(toDataWithIntendedValidatorHash(this.verifyingAddress, this.message)); + }); + }); + + context('toTypedDataHash', function () { + it('returns the digest correctly', async function () { + const domain = { + name: 'Test', + version: 1, + chainId: 1, + verifyingContract: this.verifyingAddress, + }; + const structhash = web3.utils.randomHex(32); + const expectedDomainSeparator = await domainSeparator(domain); + expect(await this.messageHashUtils.$toTypedDataHash(expectedDomainSeparator, structhash)).to.equal( + hashTypedData(domain, structhash), + ); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js b/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js new file mode 100644 index 0000000..ba8b100 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/cryptography/SignatureChecker.test.js @@ -0,0 +1,87 @@ +const { toEthSignedMessageHash } = require('../../helpers/sign'); + +const { expect } = require('chai'); + +const SignatureChecker = artifacts.require('$SignatureChecker'); +const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); +const ERC1271MaliciousMock = artifacts.require('ERC1271MaliciousMock'); + +const TEST_MESSAGE = web3.utils.sha3('OpenZeppelin'); +const WRONG_MESSAGE = web3.utils.sha3('Nope'); + +contract('SignatureChecker (ERC1271)', function (accounts) { + const [signer, other] = accounts; + + before('deploying', async function () { + this.signaturechecker = await SignatureChecker.new(); + this.wallet = await ERC1271WalletMock.new(signer); + this.malicious = await ERC1271MaliciousMock.new(); + this.signature = await web3.eth.sign(TEST_MESSAGE, signer); + }); + + context('EOA account', function () { + it('with matching signer and signature', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(TEST_MESSAGE), this.signature), + ).to.equal(true); + }); + + it('with invalid signer', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(other, toEthSignedMessageHash(TEST_MESSAGE), this.signature), + ).to.equal(false); + }); + + it('with invalid signature', async function () { + expect( + await this.signaturechecker.$isValidSignatureNow(signer, toEthSignedMessageHash(WRONG_MESSAGE), this.signature), + ).to.equal(false); + }); + }); + + context('ERC1271 wallet', function () { + 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[`$${signature}`]( + this.signaturechecker.address, + toEthSignedMessageHash(TEST_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[`$${signature}`]( + this.malicious.address, + toEthSignedMessageHash(TEST_MESSAGE), + this.signature, + ), + ).to.equal(false); + }); + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js b/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js new file mode 100644 index 0000000..6d531c1 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/introspection/ERC165.test.js @@ -0,0 +1,11 @@ +const { shouldSupportInterfaces } = require('./SupportsInterface.behavior'); + +const ERC165 = artifacts.require('$ERC165'); + +contract('ERC165', function () { + beforeEach(async function () { + this.mock = await ERC165.new(); + }); + + shouldSupportInterfaces(['ERC165']); +}); diff --git a/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js b/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js new file mode 100644 index 0000000..caa2201 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/introspection/ERC165Checker.test.js @@ -0,0 +1,300 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const ERC165Checker = artifacts.require('$ERC165Checker'); +const ERC165MissingData = artifacts.require('ERC165MissingData'); +const ERC165MaliciousData = artifacts.require('ERC165MaliciousData'); +const ERC165NotSupported = artifacts.require('ERC165NotSupported'); +const ERC165InterfacesSupported = artifacts.require('ERC165InterfacesSupported'); +const ERC165ReturnBombMock = artifacts.require('ERC165ReturnBombMock'); + +const DUMMY_ID = '0xdeadbeef'; +const DUMMY_ID_2 = '0xcafebabe'; +const DUMMY_ID_3 = '0xdecafbad'; +const DUMMY_UNSUPPORTED_ID = '0xbaddcafe'; +const DUMMY_UNSUPPORTED_ID_2 = '0xbaadcafe'; +const DUMMY_ACCOUNT = '0x1111111111111111111111111111111111111111'; + +contract('ERC165Checker', function () { + beforeEach(async function () { + this.mock = await ERC165Checker.new(); + }); + + context('ERC165 missing return data', function () { + beforeEach(async function () { + this.target = await ERC165MissingData.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 malicious return data', function () { + beforeEach(async function () { + this.target = await ERC165MaliciousData.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + }); + + context('ERC165 not supported', function () { + beforeEach(async function () { + this.target = await ERC165NotSupported.new(); + }); + + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 supported', function () { + beforeEach(async function () { + this.target = await ERC165InterfacesSupported.new([]); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + context('ERC165 and single interface supported', function () { + beforeEach(async function () { + this.target = await ERC165InterfacesSupported.new([DUMMY_ID]); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('supports mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + + it('supports mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, [DUMMY_ID]); + expect(supported).to.equal(true); + }); + + it('supports mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(true); + }); + + it('supports mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, DUMMY_ID); + expect(supported).to.equal(true); + }); + }); + + context('ERC165 and many interfaces supported', function () { + beforeEach(async function () { + this.supportedInterfaces = [DUMMY_ID, DUMMY_ID_2, DUMMY_ID_3]; + this.target = await ERC165InterfacesSupported.new(this.supportedInterfaces); + }); + + it('supports ERC165', async function () { + const supported = await this.mock.$supportsERC165(this.target.address); + expect(supported).to.equal(true); + }); + + it('supports each interfaceId via supportsInterface', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.$supportsInterface(this.target.address, interfaceId); + expect(supported).to.equal(true); + } + }); + + it('supports all interfaceIds via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(this.target.address, this.supportedInterfaces); + expect(supported).to.equal(true); + }); + + it('supports none of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + const supported = await this.mock.$supportsAllInterfaces(this.target.address, interfaceIdsToTest); + expect(supported).to.equal(false); + }); + + it('supports not all of the interfaces queried via supportsAllInterfaces', async function () { + const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + const supported = await this.mock.$supportsAllInterfaces(this.target.address, interfaceIdsToTest); + expect(supported).to.equal(false); + }); + + it('supports all interfaceIds via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(this.target.address, this.supportedInterfaces); + expect(supported.length).to.equal(3); + expect(supported[0]).to.equal(true); + expect(supported[1]).to.equal(true); + expect(supported[2]).to.equal(true); + }); + + it('supports none of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [DUMMY_UNSUPPORTED_ID, DUMMY_UNSUPPORTED_ID_2]; + + const supported = await this.mock.$getSupportedInterfaces(this.target.address, interfaceIdsToTest); + expect(supported.length).to.equal(2); + expect(supported[0]).to.equal(false); + expect(supported[1]).to.equal(false); + }); + + it('supports not all of the interfaces queried via getSupportedInterfaces', async function () { + const interfaceIdsToTest = [...this.supportedInterfaces, DUMMY_UNSUPPORTED_ID]; + + const supported = await this.mock.$getSupportedInterfaces(this.target.address, interfaceIdsToTest); + expect(supported.length).to.equal(4); + expect(supported[0]).to.equal(true); + expect(supported[1]).to.equal(true); + expect(supported[2]).to.equal(true); + expect(supported[3]).to.equal(false); + }); + + it('supports each interfaceId via supportsERC165InterfaceUnchecked', async function () { + for (const interfaceId of this.supportedInterfaces) { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(this.target.address, interfaceId); + expect(supported).to.equal(true); + } + }); + }); + + context('account address does not support ERC165', function () { + it('does not support ERC165', async function () { + const supported = await this.mock.$supportsERC165(DUMMY_ACCOUNT); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsInterface', async function () { + const supported = await this.mock.$supportsInterface(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via supportsAllInterfaces', async function () { + const supported = await this.mock.$supportsAllInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); + expect(supported).to.equal(false); + }); + + it('does not support mock interface via getSupportedInterfaces', async function () { + const supported = await this.mock.$getSupportedInterfaces(DUMMY_ACCOUNT, [DUMMY_ID]); + expect(supported.length).to.equal(1); + expect(supported[0]).to.equal(false); + }); + + it('does not support mock interface via supportsERC165InterfaceUnchecked', async function () { + const supported = await this.mock.$supportsERC165InterfaceUnchecked(DUMMY_ACCOUNT, DUMMY_ID); + expect(supported).to.equal(false); + }); + }); + + it('Return bomb resistance', async function () { + this.target = await ERC165ReturnBombMock.new(); + + const tx1 = await this.mock.$supportsInterface.sendTransaction(this.target.address, DUMMY_ID); + expect(tx1.receipt.gasUsed).to.be.lessThan(120000); // 3*30k + 21k + some margin + + const tx2 = await this.mock.$getSupportedInterfaces.sendTransaction(this.target.address, [ + DUMMY_ID, + DUMMY_ID_2, + DUMMY_ID_3, + DUMMY_UNSUPPORTED_ID, + DUMMY_UNSUPPORTED_ID_2, + ]); + expect(tx2.receipt.gasUsed).to.be.lessThan(250000); // (2+5)*30k + 21k + some margin + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js b/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js new file mode 100644 index 0000000..49a30e7 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/introspection/SupportsInterface.behavior.js @@ -0,0 +1,144 @@ +const { makeInterfaceId } = require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const INVALID_ID = '0xffffffff'; +const INTERFACES = { + ERC165: ['supportsInterface(bytes4)'], + ERC721: [ + 'balanceOf(address)', + 'ownerOf(uint256)', + 'approve(address,uint256)', + 'getApproved(uint256)', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'transferFrom(address,address,uint256)', + 'safeTransferFrom(address,address,uint256)', + 'safeTransferFrom(address,address,uint256,bytes)', + ], + ERC721Enumerable: ['totalSupply()', 'tokenOfOwnerByIndex(address,uint256)', 'tokenByIndex(uint256)'], + ERC721Metadata: ['name()', 'symbol()', 'tokenURI(uint256)'], + ERC1155: [ + 'balanceOf(address,uint256)', + 'balanceOfBatch(address[],uint256[])', + 'setApprovalForAll(address,bool)', + 'isApprovedForAll(address,address)', + 'safeTransferFrom(address,address,uint256,uint256,bytes)', + 'safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)', + ], + ERC1155Receiver: [ + 'onERC1155Received(address,address,uint256,uint256,bytes)', + 'onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)', + ], + AccessControl: [ + 'hasRole(bytes32,address)', + 'getRoleAdmin(bytes32)', + 'grantRole(bytes32,address)', + 'revokeRole(bytes32,address)', + 'renounceRole(bytes32,address)', + ], + AccessControlEnumerable: ['getRoleMember(bytes32,uint256)', 'getRoleMemberCount(bytes32)'], + AccessControlDefaultAdminRules: [ + 'defaultAdminDelay()', + 'pendingDefaultAdminDelay()', + 'defaultAdmin()', + 'pendingDefaultAdmin()', + 'defaultAdminDelayIncreaseWait()', + 'changeDefaultAdminDelay(uint48)', + 'rollbackDefaultAdminDelay()', + 'beginDefaultAdminTransfer(address)', + 'acceptDefaultAdminTransfer()', + 'cancelDefaultAdminTransfer()', + ], + Governor: [ + 'name()', + 'version()', + 'COUNTING_MODE()', + 'hashProposal(address[],uint256[],bytes[],bytes32)', + 'state(uint256)', + 'proposalThreshold()', + 'proposalSnapshot(uint256)', + 'proposalDeadline(uint256)', + 'proposalProposer(uint256)', + 'proposalEta(uint256)', + 'proposalNeedsQueuing(uint256)', + 'votingDelay()', + 'votingPeriod()', + 'quorum(uint256)', + 'getVotes(address,uint256)', + 'getVotesWithParams(address,uint256,bytes)', + 'hasVoted(uint256,address)', + 'propose(address[],uint256[],bytes[],string)', + 'queue(address[],uint256[],bytes[],bytes32)', + 'execute(address[],uint256[],bytes[],bytes32)', + 'cancel(address[],uint256[],bytes[],bytes32)', + 'castVote(uint256,uint8)', + 'castVoteWithReason(uint256,uint8,string)', + 'castVoteWithReasonAndParams(uint256,uint8,string,bytes)', + 'castVoteBySig(uint256,uint8,address,bytes)', + 'castVoteWithReasonAndParamsBySig(uint256,uint8,address,string,bytes,bytes)', + ], + ERC2981: ['royaltyInfo(uint256,uint256)'], +}; + +const INTERFACE_IDS = {}; +const FN_SIGNATURES = {}; +for (const k of Object.getOwnPropertyNames(INTERFACES)) { + INTERFACE_IDS[k] = makeInterfaceId.ERC165(INTERFACES[k]); + for (const fnName of INTERFACES[k]) { + // the interface id of a single function is equivalent to its function signature + FN_SIGNATURES[fnName] = makeInterfaceId.ERC165([fnName]); + } +} + +function shouldSupportInterfaces(interfaces = []) { + describe('ERC165', function () { + beforeEach(function () { + this.contractUnderTest = this.mock || this.token || this.holder || this.accessControl; + }); + + describe('when the interfaceId is supported', function () { + it('uses less than 30k gas', async function () { + for (const k of interfaces) { + const interfaceId = INTERFACE_IDS[k] ?? k; + expect(await this.contractUnderTest.supportsInterface.estimateGas(interfaceId)).to.be.lte(30000); + } + }); + + it('returns true', async function () { + for (const k of interfaces) { + const interfaceId = INTERFACE_IDS[k] ?? k; + expect(await this.contractUnderTest.supportsInterface(interfaceId)).to.equal(true, `does not support ${k}`); + } + }); + }); + + describe('when the interfaceId is not supported', function () { + it('uses less thank 30k', async function () { + expect(await this.contractUnderTest.supportsInterface.estimateGas(INVALID_ID)).to.be.lte(30000); + }); + + it('returns false', async function () { + expect(await this.contractUnderTest.supportsInterface(INVALID_ID)).to.be.equal(false, `supports ${INVALID_ID}`); + }); + }); + + 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, + `did not find ${fnName}`, + ); + } + } + }); + }); +} + +module.exports = { + shouldSupportInterfaces, +}; diff --git a/lib/openzeppelin-contracts/test/utils/math/Math.t.sol b/lib/openzeppelin-contracts/test/utils/math/Math.t.sol new file mode 100644 index 0000000..0b497a8 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/math/Math.t.sol @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; + +import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; + +contract MathTest is Test { + // CEILDIV + function testCeilDiv(uint256 a, uint256 b) public { + vm.assume(b > 0); + + uint256 result = Math.ceilDiv(a, b); + + if (result == 0) { + assertEq(a, 0); + } else { + uint256 maxdiv = UINT256_MAX / b; + bool overflow = maxdiv * b < a; + assertTrue(a > b * (result - 1)); + assertTrue(overflow ? result == maxdiv + 1 : a <= b * result); + } + } + + // SQRT + function testSqrt(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.sqrt(input, rounding); + + // square of result is bigger than input + if (_squareBigger(result, input)) { + assertTrue(Math.unsignedRoundsUp(rounding)); + assertTrue(_squareSmaller(result - 1, input)); + } + // square of result is smaller than input + else if (_squareSmaller(result, input)) { + assertFalse(Math.unsignedRoundsUp(rounding)); + assertTrue(_squareBigger(result + 1, input)); + } + // input is perfect square + else { + assertEq(result * result, input); + } + } + + function _squareBigger(uint256 value, uint256 ref) private pure returns (bool) { + (bool noOverflow, uint256 square) = Math.tryMul(value, value); + return !noOverflow || square > ref; + } + + function _squareSmaller(uint256 value, uint256 ref) private pure returns (bool) { + return value * value < ref; + } + + // LOG2 + function testLog2(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log2(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf2Bigger(result, input)) { + assertTrue(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf2Smaller(result - 1, input)); + } else if (_powerOf2Smaller(result, input)) { + assertFalse(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf2Bigger(result + 1, input)); + } else { + assertEq(2 ** result, input); + } + } + + function _powerOf2Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 256 || 2 ** value > ref; // 2**256 overflows uint256 + } + + function _powerOf2Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 2 ** value < ref; + } + + // LOG10 + function testLog10(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log10(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf10Bigger(result, input)) { + assertTrue(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf10Smaller(result - 1, input)); + } else if (_powerOf10Smaller(result, input)) { + assertFalse(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf10Bigger(result + 1, input)); + } else { + assertEq(10 ** result, input); + } + } + + function _powerOf10Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 78 || 10 ** value > ref; // 10**78 overflows uint256 + } + + function _powerOf10Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 10 ** value < ref; + } + + // LOG256 + function testLog256(uint256 input, uint8 r) public { + Math.Rounding rounding = _asRounding(r); + + uint256 result = Math.log256(input, rounding); + + if (input == 0) { + assertEq(result, 0); + } else if (_powerOf256Bigger(result, input)) { + assertTrue(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf256Smaller(result - 1, input)); + } else if (_powerOf256Smaller(result, input)) { + assertFalse(Math.unsignedRoundsUp(rounding)); + assertTrue(_powerOf256Bigger(result + 1, input)); + } else { + assertEq(256 ** result, input); + } + } + + function _powerOf256Bigger(uint256 value, uint256 ref) private pure returns (bool) { + return value >= 32 || 256 ** value > ref; // 256**32 overflows uint256 + } + + function _powerOf256Smaller(uint256 value, uint256 ref) private pure returns (bool) { + return 256 ** value < ref; + } + + // MULDIV + function testMulDiv(uint256 x, uint256 y, uint256 d) public { + // Full precision for x * y + (uint256 xyHi, uint256 xyLo) = _mulHighLow(x, y); + + // Assume result won't overflow (see {testMulDivDomain}) + // This also checks that `d` is positive + vm.assume(xyHi < d); + + // Perform muldiv + uint256 q = Math.mulDiv(x, y, d); + + // Full precision for q * d + (uint256 qdHi, uint256 qdLo) = _mulHighLow(q, d); + // Add remainder of x * y / d (computed as rem = (x * y % d)) + (uint256 qdRemLo, uint256 c) = _addCarry(qdLo, _mulmod(x, y, d)); + uint256 qdRemHi = qdHi + c; + + // Full precision check that x * y = q * d + rem + assertEq(xyHi, qdRemHi); + assertEq(xyLo, qdRemLo); + } + + function testMulDivDomain(uint256 x, uint256 y, uint256 d) public { + (uint256 xyHi, ) = _mulHighLow(x, y); + + // Violate {testMulDiv} assumption (covers d is 0 and result overflow) + vm.assume(xyHi >= d); + + // we are outside the scope of {testMulDiv}, we expect muldiv to revert + try this.muldiv(x, y, d) returns (uint256) { + fail(); + } catch {} + } + + // External call + function muldiv(uint256 x, uint256 y, uint256 d) external pure returns (uint256) { + return Math.mulDiv(x, y, d); + } + + // Helpers + function _asRounding(uint8 r) private pure returns (Math.Rounding) { + vm.assume(r < uint8(type(Math.Rounding).max)); + return Math.Rounding(r); + } + + function _mulmod(uint256 x, uint256 y, uint256 z) private pure returns (uint256 r) { + assembly { + r := mulmod(x, y, z) + } + } + + function _mulHighLow(uint256 x, uint256 y) private pure returns (uint256 high, uint256 low) { + (uint256 x0, uint256 x1) = (x & type(uint128).max, x >> 128); + (uint256 y0, uint256 y1) = (y & type(uint128).max, y >> 128); + + // Karatsuba algorithm + // https://en.wikipedia.org/wiki/Karatsuba_algorithm + uint256 z2 = x1 * y1; + uint256 z1a = x1 * y0; + uint256 z1b = x0 * y1; + uint256 z0 = x0 * y0; + + uint256 carry = ((z1a & type(uint128).max) + (z1b & type(uint128).max) + (z0 >> 128)) >> 128; + + high = z2 + (z1a >> 128) + (z1b >> 128) + carry; + + unchecked { + low = x * y; + } + } + + function _addCarry(uint256 x, uint256 y) private pure returns (uint256 res, uint256 carry) { + unchecked { + res = x + y; + } + carry = res < x ? 1 : 0; + } +} diff --git a/lib/openzeppelin-contracts/test/utils/math/Math.test.js b/lib/openzeppelin-contracts/test/utils/math/Math.test.js new file mode 100644 index 0000000..7d4a58c --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/math/Math.test.js @@ -0,0 +1,469 @@ +const { BN, constants, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MAX_UINT256 } = constants; +const { Rounding } = require('../../helpers/enums.js'); +const { expectRevertCustomError } = require('../../helpers/customError.js'); + +const Math = artifacts.require('$Math'); + +const RoundingDown = [Rounding.Floor, Rounding.Trunc]; +const RoundingUp = [Rounding.Ceil, Rounding.Expand]; + +function expectStruct(value, expected) { + for (const key in expected) { + if (BN.isBN(value[key])) { + expect(value[key]).to.be.bignumber.equal(expected[key]); + } else { + expect(value[key]).to.be.equal(expected[key]); + } + } +} + +async function testCommutativeIterable(fn, lhs, rhs, expected, ...extra) { + expectStruct(await fn(lhs, rhs, ...extra), expected); + expectStruct(await fn(rhs, lhs, ...extra), expected); +} + +contract('Math', function () { + const min = new BN('1234'); + const max = new BN('5678'); + const MAX_UINT256_SUB1 = MAX_UINT256.sub(new BN('1')); + const MAX_UINT256_SUB2 = MAX_UINT256.sub(new BN('2')); + + beforeEach(async function () { + this.math = await Math.new(); + }); + + describe('tryAdd', function () { + it('adds correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + await testCommutativeIterable(this.math.$tryAdd, a, b, [true, a.add(b)]); + }); + + it('reverts on addition overflow', async function () { + const a = MAX_UINT256; + const b = new BN('1'); + + await testCommutativeIterable(this.math.$tryAdd, a, b, [false, '0']); + }); + }); + + describe('trySub', function () { + it('subtracts correctly', async function () { + const a = new BN('5678'); + const b = new BN('1234'); + + expectStruct(await this.math.$trySub(a, b), [true, a.sub(b)]); + }); + + it('reverts if subtraction result would be negative', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + expectStruct(await this.math.$trySub(a, b), [false, '0']); + }); + }); + + describe('tryMul', function () { + it('multiplies correctly', async function () { + const a = new BN('1234'); + const b = new BN('5678'); + + await testCommutativeIterable(this.math.$tryMul, a, b, [true, a.mul(b)]); + }); + + it('multiplies by zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + await testCommutativeIterable(this.math.$tryMul, a, b, [true, a.mul(b)]); + }); + + it('reverts on multiplication overflow', async function () { + const a = MAX_UINT256; + const b = new BN('2'); + + await testCommutativeIterable(this.math.$tryMul, a, b, [false, '0']); + }); + }); + + describe('tryDiv', function () { + it('divides correctly', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('divides zero correctly', async function () { + const a = new BN('0'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('returns complete number result on non-even division', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryDiv(a, b), [true, a.div(b)]); + }); + + it('reverts on division by zero', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + expectStruct(await this.math.$tryDiv(a, b), [false, '0']); + }); + }); + + describe('tryMod', function () { + describe('modulos correctly', async function () { + it('when the dividend is smaller than the divisor', async function () { + const a = new BN('284'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is equal to the divisor', async function () { + const a = new BN('5678'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is larger than the divisor', async function () { + const a = new BN('7000'); + const b = new BN('5678'); + + expectStruct(await this.math.$tryMod(a, b), [true, a.mod(b)]); + }); + + it('when the dividend is a multiple of the divisor', async function () { + const a = new BN('17034'); // 17034 == 5678 * 3 + const b = new BN('5678'); + + expectStruct(await this.math.$tryMod(a, b), [true, a.mod(b)]); + }); + }); + + it('reverts with a 0 divisor', async function () { + const a = new BN('5678'); + const b = new BN('0'); + + expectStruct(await this.math.$tryMod(a, b), [false, '0']); + }); + }); + + describe('max', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$max(max, min)).to.be.bignumber.equal(max); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$max(min, max)).to.be.bignumber.equal(max); + }); + }); + + describe('min', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$min(min, max)).to.be.bignumber.equal(min); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$min(max, min)).to.be.bignumber.equal(min); + }); + }); + + describe('average', function () { + function bnAverage(a, b) { + return a.add(b).divn(2); + } + + it('is correctly calculated with two odd numbers', async function () { + const a = new BN('57417'); + const b = new BN('95431'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with two even numbers', async function () { + const a = new BN('42304'); + const b = new BN('84346'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with one even and one odd number', async function () { + const a = new BN('57417'); + const b = new BN('84346'); + expect(await this.math.$average(a, b)).to.be.bignumber.equal(bnAverage(a, b)); + }); + + it('is correctly calculated with two max uint256 numbers', async function () { + const a = MAX_UINT256; + expect(await this.math.$average(a, a)).to.be.bignumber.equal(bnAverage(a, a)); + }); + }); + + describe('ceilDiv', function () { + it('reverts on zero division', async function () { + const a = new BN('2'); + const b = new BN('0'); + // It's unspecified because it's a low level 0 division error + await expectRevert.unspecified(this.math.$ceilDiv(a, b)); + }); + + it('does not round up a zero result', async function () { + const a = new BN('0'); + const b = new BN('2'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('0'); + }); + + it('does not round up on exact division', async function () { + const a = new BN('10'); + const b = new BN('5'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('2'); + }); + + it('rounds up on division with remainders', async function () { + const a = new BN('42'); + const b = new BN('13'); + expect(await this.math.$ceilDiv(a, b)).to.be.bignumber.equal('4'); + }); + + it('does not overflow', async function () { + const b = new BN('2'); + const result = new BN('1').shln(255); + expect(await this.math.$ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(result); + }); + + it('correctly computes max uint256 divided by 1', async function () { + const b = new BN('1'); + expect(await this.math.$ceilDiv(MAX_UINT256, b)).to.be.bignumber.equal(MAX_UINT256); + }); + }); + + describe('muldiv', function () { + it('divide by 0', async function () { + await expectRevert.unspecified(this.math.$mulDiv(1, 1, 0, Rounding.Floor)); + }); + + it('reverts with result higher than 2 ^ 256', async function () { + await expectRevertCustomError(this.math.$mulDiv(5, MAX_UINT256, 2, Rounding.Floor), 'MathOverflowedMulDiv', []); + }); + + describe('does round down', async function () { + it('small values', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$mulDiv('3', '4', '5', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$mulDiv('3', '5', '5', rounding)).to.be.bignumber.equal('3'); + } + }); + + it('large values', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$mulDiv(new BN('42'), MAX_UINT256_SUB1, MAX_UINT256, rounding)).to.be.bignumber.equal( + new BN('41'), + ); + + expect(await this.math.$mulDiv(new BN('17'), MAX_UINT256, MAX_UINT256, rounding)).to.be.bignumber.equal( + new BN('17'), + ); + + expect( + await this.math.$mulDiv(MAX_UINT256_SUB1, MAX_UINT256_SUB1, MAX_UINT256, rounding), + ).to.be.bignumber.equal(MAX_UINT256_SUB2); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256_SUB1, MAX_UINT256, rounding)).to.be.bignumber.equal( + MAX_UINT256_SUB1, + ); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256, MAX_UINT256, rounding)).to.be.bignumber.equal( + MAX_UINT256, + ); + } + }); + }); + + describe('does round up', async function () { + it('small values', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$mulDiv('3', '4', '5', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$mulDiv('3', '5', '5', rounding)).to.be.bignumber.equal('3'); + } + }); + + it('large values', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$mulDiv(new BN('42'), MAX_UINT256_SUB1, MAX_UINT256, rounding)).to.be.bignumber.equal( + new BN('42'), + ); + + expect(await this.math.$mulDiv(new BN('17'), MAX_UINT256, MAX_UINT256, rounding)).to.be.bignumber.equal( + new BN('17'), + ); + + expect( + await this.math.$mulDiv(MAX_UINT256_SUB1, MAX_UINT256_SUB1, MAX_UINT256, rounding), + ).to.be.bignumber.equal(MAX_UINT256_SUB1); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256_SUB1, MAX_UINT256, rounding)).to.be.bignumber.equal( + MAX_UINT256_SUB1, + ); + + expect(await this.math.$mulDiv(MAX_UINT256, MAX_UINT256, MAX_UINT256, rounding)).to.be.bignumber.equal( + MAX_UINT256, + ); + } + }); + }); + }); + + describe('sqrt', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$sqrt('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$sqrt('1', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('3', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('4', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('144', rounding)).to.be.bignumber.equal('12'); + expect(await this.math.$sqrt('999999', rounding)).to.be.bignumber.equal('999'); + expect(await this.math.$sqrt('1000000', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000001', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1002000', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1002001', rounding)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt(MAX_UINT256, rounding)).to.be.bignumber.equal( + '340282366920938463463374607431768211455', + ); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$sqrt('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$sqrt('1', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$sqrt('2', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('3', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('4', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$sqrt('144', rounding)).to.be.bignumber.equal('12'); + expect(await this.math.$sqrt('999999', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000000', rounding)).to.be.bignumber.equal('1000'); + expect(await this.math.$sqrt('1000001', rounding)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt('1002000', rounding)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt('1002001', rounding)).to.be.bignumber.equal('1001'); + expect(await this.math.$sqrt(MAX_UINT256, rounding)).to.be.bignumber.equal( + '340282366920938463463374607431768211456', + ); + } + }); + }); + + describe('log', function () { + describe('log2', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.methods['$log2(uint256,uint8)']('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('3', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('4', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('5', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('6', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('7', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('8', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('9', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)'](MAX_UINT256, rounding)).to.be.bignumber.equal('255'); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.methods['$log2(uint256,uint8)']('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.methods['$log2(uint256,uint8)']('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.methods['$log2(uint256,uint8)']('3', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('4', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.methods['$log2(uint256,uint8)']('5', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('6', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('7', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('8', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.methods['$log2(uint256,uint8)']('9', rounding)).to.be.bignumber.equal('4'); + expect(await this.math.methods['$log2(uint256,uint8)'](MAX_UINT256, rounding)).to.be.bignumber.equal('256'); + } + }); + }); + + describe('log10', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$log10('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('2', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('9', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('10', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('11', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('99', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('100', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('101', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('999', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('1000', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1001', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10(MAX_UINT256, rounding)).to.be.bignumber.equal('77'); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$log10('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log10('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('9', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('10', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log10('11', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('99', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('100', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log10('101', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('999', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1000', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log10('1001', rounding)).to.be.bignumber.equal('4'); + expect(await this.math.$log10(MAX_UINT256, rounding)).to.be.bignumber.equal('78'); + } + }); + }); + + describe('log256', function () { + it('rounds down', async function () { + for (const rounding of RoundingDown) { + expect(await this.math.$log256('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('2', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('255', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('256', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('257', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('65535', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('65536', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65537', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256(MAX_UINT256, rounding)).to.be.bignumber.equal('31'); + } + }); + + it('rounds up', async function () { + for (const rounding of RoundingUp) { + expect(await this.math.$log256('0', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('1', rounding)).to.be.bignumber.equal('0'); + expect(await this.math.$log256('2', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('255', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('256', rounding)).to.be.bignumber.equal('1'); + expect(await this.math.$log256('257', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65535', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65536', rounding)).to.be.bignumber.equal('2'); + expect(await this.math.$log256('65537', rounding)).to.be.bignumber.equal('3'); + expect(await this.math.$log256(MAX_UINT256, rounding)).to.be.bignumber.equal('32'); + } + }); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js b/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js new file mode 100644 index 0000000..4b8ec5a --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/math/SafeCast.test.js @@ -0,0 +1,161 @@ +const { BN } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { range } = require('../../../scripts/helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const SafeCast = artifacts.require('$SafeCast'); + +contract('SafeCast', async function () { + beforeEach(async function () { + this.safeCast = await SafeCast.new(); + }); + + function testToUint(bits) { + describe(`toUint${bits}`, () => { + const maxValue = new BN('2').pow(new BN(bits)).subn(1); + + it('downcasts 0', async function () { + expect(await this.safeCast[`$toUint${bits}`](0)).to.be.bignumber.equal('0'); + }); + + it('downcasts 1', async function () { + expect(await this.safeCast[`$toUint${bits}`](1)).to.be.bignumber.equal('1'); + }); + + it(`downcasts 2^${bits} - 1 (${maxValue})`, async function () { + expect(await this.safeCast[`$toUint${bits}`](maxValue)).to.be.bignumber.equal(maxValue); + }); + + it(`reverts when downcasting 2^${bits} (${maxValue.addn(1)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toUint${bits}`](maxValue.addn(1)), + `SafeCastOverflowedUintDowncast`, + [bits, maxValue.addn(1)], + ); + }); + + it(`reverts when downcasting 2^${bits} + 1 (${maxValue.addn(2)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toUint${bits}`](maxValue.addn(2)), + `SafeCastOverflowedUintDowncast`, + [bits, maxValue.addn(2)], + ); + }); + }); + } + + range(8, 256, 8).forEach(bits => testToUint(bits)); + + describe('toUint256', () => { + const maxInt256 = new BN('2').pow(new BN(255)).subn(1); + const minInt256 = new BN('2').pow(new BN(255)).neg(); + + it('casts 0', async function () { + expect(await this.safeCast.$toUint256(0)).to.be.bignumber.equal('0'); + }); + + it('casts 1', async function () { + expect(await this.safeCast.$toUint256(1)).to.be.bignumber.equal('1'); + }); + + it(`casts INT256_MAX (${maxInt256})`, async function () { + expect(await this.safeCast.$toUint256(maxInt256)).to.be.bignumber.equal(maxInt256); + }); + + it('reverts when casting -1', async function () { + await expectRevertCustomError(this.safeCast.$toUint256(-1), `SafeCastOverflowedIntToUint`, [-1]); + }); + + it(`reverts when casting INT256_MIN (${minInt256})`, async function () { + await expectRevertCustomError(this.safeCast.$toUint256(minInt256), `SafeCastOverflowedIntToUint`, [minInt256]); + }); + }); + + function testToInt(bits) { + describe(`toInt${bits}`, () => { + const minValue = new BN('-2').pow(new BN(bits - 1)); + const maxValue = new BN('2').pow(new BN(bits - 1)).subn(1); + + it('downcasts 0', async function () { + expect(await this.safeCast[`$toInt${bits}`](0)).to.be.bignumber.equal('0'); + }); + + it('downcasts 1', async function () { + expect(await this.safeCast[`$toInt${bits}`](1)).to.be.bignumber.equal('1'); + }); + + it('downcasts -1', async function () { + expect(await this.safeCast[`$toInt${bits}`](-1)).to.be.bignumber.equal('-1'); + }); + + it(`downcasts -2^${bits - 1} (${minValue})`, async function () { + expect(await this.safeCast[`$toInt${bits}`](minValue)).to.be.bignumber.equal(minValue); + }); + + it(`downcasts 2^${bits - 1} - 1 (${maxValue})`, async function () { + expect(await this.safeCast[`$toInt${bits}`](maxValue)).to.be.bignumber.equal(maxValue); + }); + + it(`reverts when downcasting -2^${bits - 1} - 1 (${minValue.subn(1)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toInt${bits}`](minValue.subn(1)), + `SafeCastOverflowedIntDowncast`, + [bits, minValue.subn(1)], + ); + }); + + it(`reverts when downcasting -2^${bits - 1} - 2 (${minValue.subn(2)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toInt${bits}`](minValue.subn(2)), + `SafeCastOverflowedIntDowncast`, + [bits, minValue.subn(2)], + ); + }); + + it(`reverts when downcasting 2^${bits - 1} (${maxValue.addn(1)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toInt${bits}`](maxValue.addn(1)), + `SafeCastOverflowedIntDowncast`, + [bits, maxValue.addn(1)], + ); + }); + + it(`reverts when downcasting 2^${bits - 1} + 1 (${maxValue.addn(2)})`, async function () { + await expectRevertCustomError( + this.safeCast[`$toInt${bits}`](maxValue.addn(2)), + `SafeCastOverflowedIntDowncast`, + [bits, maxValue.addn(2)], + ); + }); + }); + } + + range(8, 256, 8).forEach(bits => testToInt(bits)); + + describe('toInt256', () => { + const maxUint256 = new BN('2').pow(new BN(256)).subn(1); + const maxInt256 = new BN('2').pow(new BN(255)).subn(1); + + it('casts 0', async function () { + expect(await this.safeCast.$toInt256(0)).to.be.bignumber.equal('0'); + }); + + it('casts 1', async function () { + expect(await this.safeCast.$toInt256(1)).to.be.bignumber.equal('1'); + }); + + it(`casts INT256_MAX (${maxInt256})`, async function () { + expect(await this.safeCast.$toInt256(maxInt256)).to.be.bignumber.equal(maxInt256); + }); + + it(`reverts when casting INT256_MAX + 1 (${maxInt256.addn(1)})`, async function () { + await expectRevertCustomError(this.safeCast.$toInt256(maxInt256.addn(1)), 'SafeCastOverflowedUintToInt', [ + maxInt256.addn(1), + ]); + }); + + it(`reverts when casting UINT256_MAX (${maxUint256})`, async function () { + await expectRevertCustomError(this.safeCast.$toInt256(maxUint256), 'SafeCastOverflowedUintToInt', [maxUint256]); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js b/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js new file mode 100644 index 0000000..c014e22 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/math/SignedMath.test.js @@ -0,0 +1,95 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); +const { MIN_INT256, MAX_INT256 } = constants; + +const SignedMath = artifacts.require('$SignedMath'); + +contract('SignedMath', function () { + const min = new BN('-1234'); + const max = new BN('5678'); + + beforeEach(async function () { + this.math = await SignedMath.new(); + }); + + describe('max', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$max(max, min)).to.be.bignumber.equal(max); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$max(min, max)).to.be.bignumber.equal(max); + }); + }); + + describe('min', function () { + it('is correctly detected in first argument position', async function () { + expect(await this.math.$min(min, max)).to.be.bignumber.equal(min); + }); + + it('is correctly detected in second argument position', async function () { + expect(await this.math.$min(max, min)).to.be.bignumber.equal(min); + }); + }); + + describe('average', function () { + function bnAverage(a, b) { + return a.add(b).divn(2); + } + + it('is correctly calculated with various input', async function () { + const valuesX = [ + new BN('0'), + new BN('3'), + new BN('-3'), + new BN('4'), + new BN('-4'), + new BN('57417'), + new BN('-57417'), + new BN('42304'), + new BN('-42304'), + MIN_INT256, + MAX_INT256, + ]; + + const valuesY = [ + new BN('0'), + new BN('5'), + new BN('-5'), + new BN('2'), + new BN('-2'), + new BN('57417'), + new BN('-57417'), + new BN('42304'), + new BN('-42304'), + MIN_INT256, + MAX_INT256, + ]; + + for (const x of valuesX) { + for (const y of valuesY) { + expect(await this.math.$average(x, y)).to.be.bignumber.equal( + bnAverage(x, y), + `Bad result for average(${x}, ${y})`, + ); + } + } + }); + }); + + describe('abs', function () { + for (const n of [ + MIN_INT256, + MIN_INT256.addn(1), + new BN('-1'), + new BN('0'), + new BN('1'), + MAX_INT256.subn(1), + MAX_INT256, + ]) { + it(`correctly computes the absolute value of ${n}`, async function () { + expect(await this.math.$abs(n)).to.be.bignumber.equal(n.abs()); + }); + } + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js b/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js new file mode 100644 index 0000000..8a1470c --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/structs/BitMap.test.js @@ -0,0 +1,145 @@ +const { BN } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const BitMap = artifacts.require('$BitMaps'); + +contract('BitMap', function () { + const keyA = new BN('7891'); + const keyB = new BN('451'); + const keyC = new BN('9592328'); + + beforeEach(async function () { + this.bitmap = await BitMap.new(); + }); + + it('starts empty', async function () { + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + describe('setTo', function () { + it('set a key to true', async function () { + await this.bitmap.$setTo(0, keyA, true); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('set a key to false', async function () { + await this.bitmap.$setTo(0, keyA, true); + await this.bitmap.$setTo(0, keyA, false); + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('set several consecutive keys', async function () { + await this.bitmap.$setTo(0, keyA.addn(0), true); + await this.bitmap.$setTo(0, keyA.addn(1), true); + await this.bitmap.$setTo(0, keyA.addn(2), true); + await this.bitmap.$setTo(0, keyA.addn(3), true); + await this.bitmap.$setTo(0, keyA.addn(4), true); + await this.bitmap.$setTo(0, keyA.addn(2), false); + await this.bitmap.$setTo(0, keyA.addn(4), false); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + }); + + describe('set', function () { + it('adds a key', async function () { + await this.bitmap.$set(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('adds several keys', async function () { + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(true); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('adds several consecutive keys', async function () { + await this.bitmap.$set(0, keyA.addn(0)); + await this.bitmap.$set(0, keyA.addn(1)); + await this.bitmap.$set(0, keyA.addn(3)); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + }); + + describe('unset', function () { + it('removes added keys', async function () { + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + await this.bitmap.$unset(0, keyA); + expect(await this.bitmap.$get(0, keyA)).to.equal(false); + expect(await this.bitmap.$get(0, keyB)).to.equal(true); + expect(await this.bitmap.$get(0, keyC)).to.equal(false); + }); + + it('removes consecutive added keys', async function () { + await this.bitmap.$set(0, keyA.addn(0)); + await this.bitmap.$set(0, keyA.addn(1)); + await this.bitmap.$set(0, keyA.addn(3)); + await this.bitmap.$unset(0, keyA.addn(1)); + expect(await this.bitmap.$get(0, keyA.addn(0))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(1))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(2))).to.equal(false); + expect(await this.bitmap.$get(0, keyA.addn(3))).to.equal(true); + expect(await this.bitmap.$get(0, keyA.addn(4))).to.equal(false); + }); + + it('adds and removes multiple keys', async function () { + // [] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyC); + + // [A, C] + + await this.bitmap.$unset(0, keyA); + await this.bitmap.$unset(0, keyB); + + // [C] + + await this.bitmap.$set(0, keyB); + + // [C, B] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$unset(0, keyC); + + // [A, B] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$set(0, keyB); + + // [A, B] + + await this.bitmap.$set(0, keyC); + await this.bitmap.$unset(0, keyA); + + // [B, C] + + await this.bitmap.$set(0, keyA); + await this.bitmap.$unset(0, keyB); + + // [A, C] + + expect(await this.bitmap.$get(0, keyA)).to.equal(true); + expect(await this.bitmap.$get(0, keyB)).to.equal(false); + expect(await this.bitmap.$get(0, keyC)).to.equal(true); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol b/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol new file mode 100644 index 0000000..7bdbcfd --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.t.sol @@ -0,0 +1,332 @@ +// SPDX-License-Identifier: MIT +// This file was procedurally generated from scripts/generate/templates/Checkpoints.t.js. + +pragma solidity ^0.8.20; + +import {Test} from "forge-std/Test.sol"; +import {SafeCast} from "../../../contracts/utils/math/SafeCast.sol"; +import {Checkpoints} from "../../../contracts/utils/structs/Checkpoints.sol"; + +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]; + if (lastKey > 0) { + 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 CheckpointsTrace208Test is Test { + using Checkpoints for Checkpoints.Trace208; + + // 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.Trace208 internal _ckpts; + + // helpers + function _boundUint48(uint48 x, uint48 min, uint48 max) internal view returns (uint48) { + return SafeCast.toUint48(bound(uint256(x), uint256(min), uint256(max))); + } + + function _prepareKeys(uint48[] memory keys, uint48 maxSpread) internal view { + uint48 lastKey = 0; + for (uint256 i = 0; i < keys.length; ++i) { + uint48 key = _boundUint48(keys[i], lastKey, lastKey + maxSpread); + keys[i] = key; + lastKey = key; + } + } + + function _assertLatestCheckpoint(bool exist, uint48 key, uint208 value) internal { + (bool _exist, uint48 _key, uint208 _value) = _ckpts.latestCheckpoint(); + assertEq(_exist, exist); + assertEq(_key, key); + assertEq(_value, value); + } + + // tests + function testPush(uint48[] memory keys, uint208[] memory values, uint48 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) { + uint48 key = keys[i]; + uint208 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) { + uint48 lastKey = keys[keys.length - 1]; + if (lastKey > 0) { + pastKey = _boundUint48(pastKey, 0, lastKey - 1); + + vm.expectRevert(); + this.push(pastKey, values[keys.length % values.length]); + } + } + } + + // used to test reverts + function push(uint48 key, uint208 value) external { + _ckpts.push(key, value); + } + + function testLookup(uint48[] memory keys, uint208[] memory values, uint48 lookup) public { + vm.assume(values.length > 0 && values.length <= keys.length); + _prepareKeys(keys, _KEY_MAX_GAP); + + uint48 lastKey = keys.length == 0 ? 0 : keys[keys.length - 1]; + lookup = _boundUint48(lookup, 0, lastKey + _KEY_MAX_GAP); + + uint208 upper = 0; + uint208 lower = 0; + uint48 lowerKey = type(uint48).max; + for (uint256 i = 0; i < keys.length; ++i) { + uint48 key = keys[i]; + uint208 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]; + if (lastKey > 0) { + 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); + } +} diff --git a/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js b/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js new file mode 100644 index 0000000..936ac56 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/structs/Checkpoints.test.js @@ -0,0 +1,158 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); + +const { VALUE_SIZES } = require('../../../scripts/generate/templates/Checkpoints.opts.js'); +const { expectRevertCustomError } = require('../../helpers/customError.js'); +const { expectRevert } = require('@openzeppelin/test-helpers'); + +const $Checkpoints = artifacts.require('$Checkpoints'); + +// The library name may be 'Checkpoints' or 'CheckpointsUpgradeable' +const libraryName = $Checkpoints._json.contractName.replace(/^\$/, ''); + +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(); + }); + + for (const length of VALUE_SIZES) { + describe(`Trace${length}`, function () { + beforeEach(async function () { + this.methods = { + at: (...args) => this.mock.methods[`$at_${libraryName}_Trace${length}(uint256,uint32)`](0, ...args), + 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('without checkpoints', function () { + it('at zero reverts', async function () { + // Reverts with array out of bound access, which is unspecified + await expectRevert.unspecified(this.methods.at(0)); + }); + + it('returns zero as latest value', async function () { + expect(await this.methods.latest()).to.be.bignumber.equal('0'); + + const ckpt = await this.methods.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 this.methods.lowerLookup(0)).to.be.bignumber.equal('0'); + expect(await this.methods.upperLookup(0)).to.be.bignumber.equal('0'); + expect(await this.methods.upperLookupRecent(0)).to.be.bignumber.equal('0'); + }); + }); + + describe('with checkpoints', function () { + beforeEach('pushing checkpoints', async function () { + this.checkpoints = [ + { key: '2', value: '17' }, + { key: '3', value: '42' }, + { key: '5', value: '101' }, + { key: '7', value: '23' }, + { key: '11', value: '99' }, + ]; + for (const { key, value } of this.checkpoints) { + await this.methods.push(key, value); + } + }); + + it('at keys', async function () { + for (const [index, { key, value }] of this.checkpoints.entries()) { + const at = await this.methods.at(index); + expect(at._value).to.be.bignumber.equal(value); + expect(at._key).to.be.bignumber.equal(key); + } + }); + + it('length', async function () { + expect(await this.methods.length()).to.be.bignumber.equal(this.checkpoints.length.toString()); + }); + + it('returns latest value', async function () { + expect(await this.methods.latest()).to.be.bignumber.equal(last(this.checkpoints).value); + + const ckpt = await this.methods.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 expectRevertCustomError( + this.methods.push(last(this.checkpoints).key - 1, '0'), + 'CheckpointUnorderedInsertion', + [], + ); + }); + + it('can update last value', async function () { + const newValue = '42'; + + // check length before the update + expect(await this.methods.length()).to.be.bignumber.equal(this.checkpoints.length.toString()); + + // update last key + await this.methods.push(last(this.checkpoints).key, newValue); + expect(await this.methods.latest()).to.be.bignumber.equal(newValue); + + // check that length did not change + expect(await this.methods.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 this.methods.lowerLookup(i)).to.be.bignumber.equal(value); + } + }); + + 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 this.methods.upperLookup(i)).to.be.bignumber.equal(value); + expect(await this.methods.upperLookupRecent(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 this.methods.push(key, value); + } + + for (let i = 0; i < 25; ++i) { + const value = last(allCheckpoints.filter(x => i >= x.key))?.value || '0'; + expect(await this.methods.upperLookup(i)).to.be.bignumber.equal(value); + expect(await this.methods.upperLookupRecent(i)).to.be.bignumber.equal(value); + } + }); + }); + }); + } +}); diff --git a/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js b/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js new file mode 100644 index 0000000..cbf37d7 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/structs/DoubleEndedQueue.test.js @@ -0,0 +1,99 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +const DoubleEndedQueue = artifacts.require('$DoubleEndedQueue'); + +/** Rebuild the content of the deque as a JS array. */ +const getContent = deque => + deque.$length(0).then(bn => + Promise.all( + Array(bn.toNumber()) + .fill() + .map((_, i) => deque.$at(0, i)), + ), + ); + +contract('DoubleEndedQueue', function () { + const bytesA = '0xdeadbeef'.padEnd(66, '0'); + const bytesB = '0x0123456789'.padEnd(66, '0'); + const bytesC = '0x42424242'.padEnd(66, '0'); + const bytesD = '0x171717'.padEnd(66, '0'); + + beforeEach(async function () { + this.deque = await DoubleEndedQueue.new(); + }); + + describe('when empty', function () { + it('getters', async function () { + expect(await this.deque.$empty(0)).to.be.equal(true); + expect(await getContent(this.deque)).to.have.ordered.members([]); + }); + + it('reverts on accesses', async function () { + await expectRevertCustomError(this.deque.$popBack(0), 'QueueEmpty', []); + await expectRevertCustomError(this.deque.$popFront(0), 'QueueEmpty', []); + await expectRevertCustomError(this.deque.$back(0), 'QueueEmpty', []); + await expectRevertCustomError(this.deque.$front(0), 'QueueEmpty', []); + }); + }); + + describe('when not empty', function () { + beforeEach(async function () { + await this.deque.$pushBack(0, bytesB); + await this.deque.$pushFront(0, bytesA); + await this.deque.$pushBack(0, bytesC); + this.content = [bytesA, bytesB, bytesC]; + }); + + it('getters', async function () { + expect(await this.deque.$empty(0)).to.be.equal(false); + expect(await this.deque.$length(0)).to.be.bignumber.equal(this.content.length.toString()); + expect(await this.deque.$front(0)).to.be.equal(this.content[0]); + expect(await this.deque.$back(0)).to.be.equal(this.content[this.content.length - 1]); + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('out of bounds access', async function () { + await expectRevertCustomError(this.deque.$at(0, this.content.length), 'QueueOutOfBounds', []); + }); + + describe('push', function () { + it('front', async function () { + await this.deque.$pushFront(0, bytesD); + this.content.unshift(bytesD); // add element at the beginning + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('back', async function () { + await this.deque.$pushBack(0, bytesD); + this.content.push(bytesD); // add element at the end + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + }); + + describe('pop', function () { + it('front', async function () { + const value = this.content.shift(); // remove first element + expectEvent(await this.deque.$popFront(0), 'return$popFront', { value }); + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + + it('back', async function () { + const value = this.content.pop(); // remove last element + expectEvent(await this.deque.$popBack(0), 'return$popBack', { value }); + + expect(await getContent(this.deque)).to.have.ordered.members(this.content); + }); + }); + + it('clear', async function () { + await this.deque.$clear(0); + + expect(await this.deque.$empty(0)).to.be.equal(true); + expect(await getContent(this.deque)).to.have.ordered.members([]); + }); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js b/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js new file mode 100644 index 0000000..67b19e3 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.behavior.js @@ -0,0 +1,178 @@ +const { expectEvent } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +const zip = require('lodash.zip'); +const { expectRevertCustomError } = require('../../helpers/customError'); + +function shouldBehaveLikeMap(keys, values, zeroValue, methods, events) { + const [keyA, keyB, keyC] = keys; + const [valueA, valueB, valueC] = values; + + async function expectMembersMatch(map, keys, values) { + expect(keys.length).to.equal(values.length); + + await Promise.all(keys.map(async key => expect(await methods.contains(map, key)).to.equal(true))); + + expect(await methods.length(map)).to.bignumber.equal(keys.length.toString()); + + expect((await Promise.all(keys.map(key => methods.get(map, key)))).map(k => k.toString())).to.have.same.members( + values.map(value => value.toString()), + ); + + // To compare key-value pairs, we zip keys and values, and convert BNs to + // strings to workaround Chai limitations when dealing with nested arrays + expect( + await Promise.all( + [...Array(keys.length).keys()].map(async index => { + const entry = await methods.at(map, index); + return [entry[0].toString(), entry[1].toString()]; + }), + ), + ).to.have.same.deep.members( + zip( + keys.map(k => k.toString()), + values.map(v => v.toString()), + ), + ); + + // This also checks that both arrays have the same length + expect((await methods.keys(map)).map(k => k.toString())).to.have.same.members(keys.map(key => key.toString())); + } + + it('starts empty', async function () { + expect(await methods.contains(this.map, keyA)).to.equal(false); + + await expectMembersMatch(this.map, [], []); + }); + + describe('set', function () { + it('adds a key', async function () { + const receipt = await methods.set(this.map, keyA, valueA); + expectEvent(receipt, events.setReturn, { ret0: true }); + + await expectMembersMatch(this.map, [keyA], [valueA]); + }); + + it('adds several keys', async function () { + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyB, valueB); + + await expectMembersMatch(this.map, [keyA, keyB], [valueA, valueB]); + expect(await methods.contains(this.map, keyC)).to.equal(false); + }); + + it('returns false when adding keys already in the set', async function () { + await methods.set(this.map, keyA, valueA); + + const receipt = await methods.set(this.map, keyA, valueA); + expectEvent(receipt, events.setReturn, { ret0: false }); + + await expectMembersMatch(this.map, [keyA], [valueA]); + }); + + it('updates values for keys already in the set', async function () { + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyA, valueB); + + await expectMembersMatch(this.map, [keyA], [valueB]); + }); + }); + + describe('remove', function () { + it('removes added keys', async function () { + await methods.set(this.map, keyA, valueA); + + const receipt = await methods.remove(this.map, keyA); + expectEvent(receipt, events.removeReturn, { ret0: true }); + + expect(await methods.contains(this.map, keyA)).to.equal(false); + await expectMembersMatch(this.map, [], []); + }); + + it('returns false when removing keys not in the set', async function () { + const receipt = await methods.remove(this.map, keyA); + expectEvent(receipt, events.removeReturn, { ret0: false }); + + expect(await methods.contains(this.map, keyA)).to.equal(false); + }); + + it('adds and removes multiple keys', async function () { + // [] + + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyC, valueC); + + // [A, C] + + await methods.remove(this.map, keyA); + await methods.remove(this.map, keyB); + + // [C] + + await methods.set(this.map, keyB, valueB); + + // [C, B] + + await methods.set(this.map, keyA, valueA); + await methods.remove(this.map, keyC); + + // [A, B] + + await methods.set(this.map, keyA, valueA); + await methods.set(this.map, keyB, valueB); + + // [A, B] + + await methods.set(this.map, keyC, valueC); + await methods.remove(this.map, keyA); + + // [B, C] + + await methods.set(this.map, keyA, valueA); + await methods.remove(this.map, keyB); + + // [A, C] + + await expectMembersMatch(this.map, [keyA, keyC], [valueA, valueC]); + + expect(await methods.contains(this.map, keyA)).to.equal(true); + expect(await methods.contains(this.map, keyB)).to.equal(false); + expect(await methods.contains(this.map, keyC)).to.equal(true); + }); + }); + + describe('read', function () { + beforeEach(async function () { + await methods.set(this.map, keyA, valueA); + }); + + describe('get', function () { + it('existing value', async function () { + expect(await methods.get(this.map, keyA).then(r => r.toString())).to.be.equal(valueA.toString()); + }); + it('missing value', async function () { + const key = web3.utils.toHex(keyB); + await expectRevertCustomError(methods.get(this.map, keyB), 'EnumerableMapNonexistentKey', [ + key.length == 66 ? key : web3.utils.padLeft(key, 64, '0'), + ]); + }); + }); + + describe('tryGet', function () { + it('existing value', async function () { + const result = await methods.tryGet(this.map, keyA); + expect(result['0']).to.be.equal(true); + expect(result['1'].toString()).to.be.equal(valueA.toString()); + }); + it('missing value', async function () { + const result = await methods.tryGet(this.map, keyB); + expect(result['0']).to.be.equal(false); + expect(result['1'].toString()).to.be.equal(zeroValue.toString()); + }); + }); + }); +} + +module.exports = { + shouldBehaveLikeMap, +}; diff --git a/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js b/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js new file mode 100644 index 0000000..545e12a --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/structs/EnumerableMap.test.js @@ -0,0 +1,149 @@ +const { BN, constants } = require('@openzeppelin/test-helpers'); +const { mapValues } = require('../../helpers/iterate'); + +const EnumerableMap = artifacts.require('$EnumerableMap'); + +const { shouldBehaveLikeMap } = require('./EnumerableMap.behavior'); + +const getMethods = ms => { + return mapValues( + ms, + m => + (self, ...args) => + self.methods[m](0, ...args), + ); +}; + +// 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; + + const keyA = new BN('7891'); + const keyB = new BN('451'); + const keyC = new BN('9592328'); + + const bytesA = '0xdeadbeef'.padEnd(66, '0'); + const bytesB = '0x0123456789'.padEnd(66, '0'); + const bytesC = '0x42424242'.padEnd(66, '0'); + + beforeEach(async function () { + this.map = await EnumerableMap.new(); + }); + + // AddressToUintMap + describe('AddressToUintMap', function () { + shouldBehaveLikeMap( + [accountA, accountB, accountC], + [keyA, keyB, keyC], + new BN('0'), + getMethods({ + set: '$set(uint256,address,uint256)', + get: '$get(uint256,address)', + tryGet: '$tryGet(uint256,address)', + remove: '$remove(uint256,address)', + length: `$length_${library}_AddressToUintMap(uint256)`, + at: `$at_${library}_AddressToUintMap(uint256,uint256)`, + contains: '$contains(uint256,address)', + keys: `$keys_${library}_AddressToUintMap(uint256)`, + }), + { + setReturn: `return$set_${library}_AddressToUintMap_address_uint256`, + removeReturn: `return$remove_${library}_AddressToUintMap_address`, + }, + ); + }); + + // UintToAddressMap + describe('UintToAddressMap', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC], + [accountA, accountB, accountC], + constants.ZERO_ADDRESS, + getMethods({ + set: '$set(uint256,uint256,address)', + get: `$get_${library}_UintToAddressMap(uint256,uint256)`, + 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_${library}_UintToAddressMap_uint256_address`, + removeReturn: `return$remove_${library}_UintToAddressMap_uint256`, + }, + ); + }); + + // Bytes32ToBytes32Map + describe('Bytes32ToBytes32Map', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC].map(k => '0x' + k.toString(16).padEnd(64, '0')), + [bytesA, bytesB, bytesC], + constants.ZERO_BYTES32, + getMethods({ + set: '$set(uint256,bytes32,bytes32)', + get: `$get_${library}_Bytes32ToBytes32Map(uint256,bytes32)`, + 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_${library}_Bytes32ToBytes32Map_bytes32_bytes32`, + removeReturn: `return$remove_${library}_Bytes32ToBytes32Map_bytes32`, + }, + ); + }); + + // UintToUintMap + describe('UintToUintMap', function () { + shouldBehaveLikeMap( + [keyA, keyB, keyC], + [keyA, keyB, keyC].map(k => k.add(new BN('1332'))), + new BN('0'), + getMethods({ + set: '$set(uint256,uint256,uint256)', + get: `$get_${library}_UintToUintMap(uint256,uint256)`, + 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_${library}_UintToUintMap_uint256_uint256`, + removeReturn: `return$remove_${library}_UintToUintMap_uint256`, + }, + ); + }); + + // Bytes32ToUintMap + describe('Bytes32ToUintMap', function () { + shouldBehaveLikeMap( + [bytesA, bytesB, bytesC], + [keyA, keyB, keyC], + new BN('0'), + getMethods({ + set: '$set(uint256,bytes32,uint256)', + get: `$get_${library}_Bytes32ToUintMap(uint256,bytes32)`, + 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_${library}_Bytes32ToUintMap_bytes32_uint256`, + removeReturn: `return$remove_${library}_Bytes32ToUintMap_bytes32`, + }, + ); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js b/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js new file mode 100644 index 0000000..f80eb81 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.behavior.js @@ -0,0 +1,129 @@ +const { expectEvent, expectRevert } = require('@openzeppelin/test-helpers'); +const { expect } = require('chai'); + +function shouldBehaveLikeSet(values, methods, events) { + const [valueA, valueB, valueC] = values; + + async function expectMembersMatch(set, values) { + const contains = await Promise.all(values.map(value => methods.contains(set, value))); + expect(contains.every(Boolean)).to.be.equal(true); + + const length = await methods.length(set); + expect(length).to.bignumber.equal(values.length.toString()); + + // To compare values we convert to strings to workaround Chai + // limitations when dealing with nested arrays (required for BNs) + const indexedValues = await Promise.all( + Array(values.length) + .fill() + .map((_, index) => methods.at(set, index)), + ); + expect(indexedValues.map(v => v.toString())).to.have.same.members(values.map(v => v.toString())); + + const returnedValues = await methods.values(set); + expect(returnedValues.map(v => v.toString())).to.have.same.members(values.map(v => v.toString())); + } + + it('starts empty', async function () { + expect(await methods.contains(this.set, valueA)).to.equal(false); + + await expectMembersMatch(this.set, []); + }); + + describe('add', function () { + it('adds a value', async function () { + const receipt = await methods.add(this.set, valueA); + expectEvent(receipt, events.addReturn, { ret0: true }); + + await expectMembersMatch(this.set, [valueA]); + }); + + it('adds several values', async function () { + await methods.add(this.set, valueA); + await methods.add(this.set, valueB); + + await expectMembersMatch(this.set, [valueA, valueB]); + expect(await methods.contains(this.set, valueC)).to.equal(false); + }); + + it('returns false when adding values already in the set', async function () { + await methods.add(this.set, valueA); + + const receipt = await methods.add(this.set, valueA); + expectEvent(receipt, events.addReturn, { ret0: false }); + + await expectMembersMatch(this.set, [valueA]); + }); + }); + + describe('at', function () { + it('reverts when retrieving non-existent elements', async function () { + await expectRevert.unspecified(methods.at(this.set, 0)); + }); + }); + + describe('remove', function () { + it('removes added values', async function () { + await methods.add(this.set, valueA); + + const receipt = await methods.remove(this.set, valueA); + expectEvent(receipt, events.removeReturn, { ret0: true }); + + expect(await methods.contains(this.set, valueA)).to.equal(false); + await expectMembersMatch(this.set, []); + }); + + it('returns false when removing values not in the set', async function () { + const receipt = await methods.remove(this.set, valueA); + expectEvent(receipt, events.removeReturn, { ret0: false }); + + expect(await methods.contains(this.set, valueA)).to.equal(false); + }); + + it('adds and removes multiple values', async function () { + // [] + + await methods.add(this.set, valueA); + await methods.add(this.set, valueC); + + // [A, C] + + await methods.remove(this.set, valueA); + await methods.remove(this.set, valueB); + + // [C] + + await methods.add(this.set, valueB); + + // [C, B] + + await methods.add(this.set, valueA); + await methods.remove(this.set, valueC); + + // [A, B] + + await methods.add(this.set, valueA); + await methods.add(this.set, valueB); + + // [A, B] + + await methods.add(this.set, valueC); + await methods.remove(this.set, valueA); + + // [B, C] + + await methods.add(this.set, valueA); + await methods.remove(this.set, valueB); + + // [A, C] + + await expectMembersMatch(this.set, [valueA, valueC]); + + expect(await methods.contains(this.set, valueB)).to.equal(false); + }); + }); +} + +module.exports = { + shouldBehaveLikeSet, +}; diff --git a/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js b/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js new file mode 100644 index 0000000..a184025 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/structs/EnumerableSet.test.js @@ -0,0 +1,79 @@ +const EnumerableSet = artifacts.require('$EnumerableSet'); +const { mapValues } = require('../../helpers/iterate'); + +const { shouldBehaveLikeSet } = require('./EnumerableSet.behavior'); + +const getMethods = ms => { + return mapValues( + ms, + m => + (self, ...args) => + self.methods[m](0, ...args), + ); +}; + +// 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(); + }); + + // Bytes32Set + describe('EnumerableBytes32Set', function () { + shouldBehaveLikeSet( + ['0xdeadbeef', '0x0123456789', '0x42424242'].map(e => e.padEnd(66, '0')), + getMethods({ + add: '$add(uint256,bytes32)', + remove: '$remove(uint256,bytes32)', + contains: '$contains(uint256,bytes32)', + length: `$length_${library}_Bytes32Set(uint256)`, + at: `$at_${library}_Bytes32Set(uint256,uint256)`, + values: `$values_${library}_Bytes32Set(uint256)`, + }), + { + addReturn: `return$add_${library}_Bytes32Set_bytes32`, + removeReturn: `return$remove_${library}_Bytes32Set_bytes32`, + }, + ); + }); + + // AddressSet + describe('EnumerableAddressSet', function () { + shouldBehaveLikeSet( + accounts, + getMethods({ + add: '$add(uint256,address)', + remove: '$remove(uint256,address)', + contains: '$contains(uint256,address)', + length: `$length_${library}_AddressSet(uint256)`, + at: `$at_${library}_AddressSet(uint256,uint256)`, + values: `$values_${library}_AddressSet(uint256)`, + }), + { + addReturn: `return$add_${library}_AddressSet_address`, + removeReturn: `return$remove_${library}_AddressSet_address`, + }, + ); + }); + + // UintSet + describe('EnumerableUintSet', function () { + shouldBehaveLikeSet( + [1234, 5678, 9101112].map(e => web3.utils.toBN(e)), + getMethods({ + add: '$add(uint256,uint256)', + remove: '$remove(uint256,uint256)', + contains: '$contains(uint256,uint256)', + length: `$length_${library}_UintSet(uint256)`, + at: `$at_${library}_UintSet(uint256,uint256)`, + values: `$values_${library}_UintSet(uint256)`, + }), + { + addReturn: `return$add_${library}_UintSet_uint256`, + removeReturn: `return$remove_${library}_UintSet_uint256`, + }, + ); + }); +}); diff --git a/lib/openzeppelin-contracts/test/utils/types/Time.test.js b/lib/openzeppelin-contracts/test/utils/types/Time.test.js new file mode 100644 index 0000000..6149117 --- /dev/null +++ b/lib/openzeppelin-contracts/test/utils/types/Time.test.js @@ -0,0 +1,140 @@ +require('@openzeppelin/test-helpers'); + +const { expect } = require('chai'); +const { clock } = require('../../helpers/time'); +const { product, max } = require('../../helpers/iterate'); + +const Time = artifacts.require('$Time'); + +const MAX_UINT32 = 1n << (32n - 1n); +const MAX_UINT48 = 1n << (48n - 1n); +const SOME_VALUES = [0n, 1n, 2n, 15n, 16n, 17n, 42n]; + +const asUint = (value, size) => { + if (typeof value != 'bigint') { + value = BigInt(value); + } + // chai does not support bigint :/ + if (value < 0 || value >= 1n << BigInt(size)) { + throw new Error(`value is not a valid uint${size}`); + } + return value; +}; + +const unpackDelay = delay => ({ + valueBefore: (asUint(delay, 112) >> 32n) % (1n << 32n), + valueAfter: (asUint(delay, 112) >> 0n) % (1n << 32n), + effect: (asUint(delay, 112) >> 64n) % (1n << 48n), +}); + +const packDelay = ({ valueBefore, valueAfter = 0n, effect = 0n }) => + (asUint(valueAfter, 32) << 0n) + (asUint(valueBefore, 32) << 32n) + (asUint(effect, 48) << 64n); + +const effectSamplesForTimepoint = timepoint => [ + 0n, + timepoint, + ...product([-1n, 1n], [1n, 2n, 17n, 42n]) + .map(([sign, shift]) => timepoint + sign * shift) + .filter(effect => effect > 0n && effect <= MAX_UINT48), + MAX_UINT48, +]; + +contract('Time', function () { + beforeEach(async function () { + this.mock = await Time.new(); + }); + + describe('clocks', function () { + it('timestamp', async function () { + expect(await this.mock.$timestamp()).to.be.bignumber.equal(web3.utils.toBN(await clock.timestamp())); + }); + + it('block number', async function () { + expect(await this.mock.$blockNumber()).to.be.bignumber.equal(web3.utils.toBN(await clock.blocknumber())); + }); + }); + + describe('Delay', function () { + describe('packing and unpacking', function () { + const valueBefore = 17n; + const valueAfter = 42n; + const effect = 69n; + const delay = 1272825341158973505578n; + + it('pack', async function () { + const packed = await this.mock.$pack(valueBefore, valueAfter, effect); + expect(packed).to.be.bignumber.equal(delay.toString()); + + const packed2 = packDelay({ valueBefore, valueAfter, effect }); + expect(packed2).to.be.equal(delay); + }); + + it('unpack', async function () { + const unpacked = await this.mock.$unpack(delay); + expect(unpacked[0]).to.be.bignumber.equal(valueBefore.toString()); + expect(unpacked[1]).to.be.bignumber.equal(valueAfter.toString()); + expect(unpacked[2]).to.be.bignumber.equal(effect.toString()); + + const unpacked2 = unpackDelay(delay); + expect(unpacked2).to.be.deep.equal({ valueBefore, valueAfter, effect }); + }); + }); + + it('toDelay', async function () { + for (const value of [...SOME_VALUES, MAX_UINT32]) { + const delay = await this.mock.$toDelay(value).then(unpackDelay); + expect(delay).to.be.deep.equal({ valueBefore: 0n, valueAfter: value, effect: 0n }); + } + }); + + it('get & getFull', async function () { + const timepoint = await clock.timestamp().then(BigInt); + const valueBefore = 24194n; + const valueAfter = 4214143n; + + for (const effect of effectSamplesForTimepoint(timepoint)) { + const isPast = effect <= timepoint; + + const delay = packDelay({ valueBefore, valueAfter, effect }); + + expect(await this.mock.$get(delay)).to.be.bignumber.equal(String(isPast ? valueAfter : valueBefore)); + + const result = await this.mock.$getFull(delay); + expect(result[0]).to.be.bignumber.equal(String(isPast ? valueAfter : valueBefore)); + expect(result[1]).to.be.bignumber.equal(String(isPast ? 0n : valueAfter)); + expect(result[2]).to.be.bignumber.equal(String(isPast ? 0n : effect)); + } + }); + + it('withUpdate', async function () { + const timepoint = await clock.timestamp().then(BigInt); + const valueBefore = 24194n; + const valueAfter = 4214143n; + const newvalueAfter = 94716n; + + for (const effect of effectSamplesForTimepoint(timepoint)) + for (const minSetback of [...SOME_VALUES, MAX_UINT32]) { + const isPast = effect <= timepoint; + const expectedvalueBefore = isPast ? valueAfter : valueBefore; + const expectedSetback = max(minSetback, expectedvalueBefore - newvalueAfter, 0n); + + const result = await this.mock.$withUpdate( + packDelay({ valueBefore, valueAfter, effect }), + newvalueAfter, + minSetback, + ); + + expect(result[0]).to.be.bignumber.equal( + String( + packDelay({ + valueBefore: expectedvalueBefore, + valueAfter: newvalueAfter, + effect: timepoint + expectedSetback, + }), + ), + ); + expect(result[1]).to.be.bignumber.equal(String(timepoint + expectedSetback)); + } + }); + }); +}); diff --git a/lib/solmate/.gas-snapshot b/lib/solmate/.gas-snapshot new file mode 100644 index 0000000..dd63387 --- /dev/null +++ b/lib/solmate/.gas-snapshot @@ -0,0 +1,563 @@ +AuthTest:testCallFunctionAsOwner() (gas: 29784) +AuthTest:testCallFunctionWithPermissiveAuthority() (gas: 124292) +AuthTest:testCallFunctionWithPermissiveAuthority(address) (runs: 256, μ: 129216, ~: 129235) +AuthTest:testFailCallFunctionAsNonOwner() (gas: 15523) +AuthTest:testFailCallFunctionAsNonOwner(address) (runs: 256, μ: 15685, ~: 15685) +AuthTest:testFailCallFunctionAsOwnerWithOutOfOrderAuthority() (gas: 136021) +AuthTest:testFailCallFunctionWithRestrictiveAuthority() (gas: 129144) +AuthTest:testFailCallFunctionWithRestrictiveAuthority(address) (runs: 256, μ: 129329, ~: 129329) +AuthTest:testFailSetAuthorityAsNonOwner() (gas: 18325) +AuthTest:testFailSetAuthorityAsNonOwner(address,address) (runs: 256, μ: 18594, ~: 18594) +AuthTest:testFailSetAuthorityWithRestrictiveAuthority() (gas: 129077) +AuthTest:testFailSetAuthorityWithRestrictiveAuthority(address,address) (runs: 256, μ: 129409, ~: 129409) +AuthTest:testFailTransferOwnershipAsNonOwner() (gas: 15641) +AuthTest:testFailTransferOwnershipAsNonOwner(address,address) (runs: 256, μ: 15922, ~: 15922) +AuthTest:testFailTransferOwnershipAsOwnerWithOutOfOrderAuthority() (gas: 136159) +AuthTest:testFailTransferOwnershipAsOwnerWithOutOfOrderAuthority(address) (runs: 256, μ: 136344, ~: 136344) +AuthTest:testFailTransferOwnershipWithRestrictiveAuthority() (gas: 129338) +AuthTest:testFailTransferOwnershipWithRestrictiveAuthority(address,address) (runs: 256, μ: 129588, ~: 129588) +AuthTest:testSetAuthorityAsOwner() (gas: 32214) +AuthTest:testSetAuthorityAsOwner(address) (runs: 256, μ: 32384, ~: 32384) +AuthTest:testSetAuthorityAsOwnerWithOutOfOrderAuthority() (gas: 226419) +AuthTest:testSetAuthorityWithPermissiveAuthority() (gas: 125962) +AuthTest:testSetAuthorityWithPermissiveAuthority(address,address) (runs: 256, μ: 130958, ~: 131055) +AuthTest:testTransferOwnershipAsOwner() (gas: 15298) +AuthTest:testTransferOwnershipAsOwner(address) (runs: 256, μ: 15469, ~: 15469) +AuthTest:testTransferOwnershipWithPermissiveAuthority() (gas: 127926) +AuthTest:testTransferOwnershipWithPermissiveAuthority(address,address) (runs: 256, μ: 130981, ~: 131000) +Bytes32AddressLibTest:testFillLast12Bytes() (gas: 223) +Bytes32AddressLibTest:testFromLast20Bytes() (gas: 191) +CREATE3Test:testDeployERC20() (gas: 853111) +CREATE3Test:testDeployERC20(bytes32,string,string,uint8) (runs: 256, μ: 923654, ~: 921961) +CREATE3Test:testFailDoubleDeployDifferentBytecode() (gas: 9079256848778914174) +CREATE3Test:testFailDoubleDeployDifferentBytecode(bytes32,bytes,bytes) (runs: 256, μ: 5062195514745832485, ~: 8937393460516727435) +CREATE3Test:testFailDoubleDeploySameBytecode() (gas: 9079256848778906218) +CREATE3Test:testFailDoubleDeploySameBytecode(bytes32,bytes) (runs: 256, μ: 5027837975401088877, ~: 8937393460516728677) +DSTestPlusTest:testBound() (gas: 14214) +DSTestPlusTest:testBound(uint256,uint256,uint256) (runs: 256, μ: 2787, ~: 2793) +DSTestPlusTest:testBrutalizeMemory() (gas: 823) +DSTestPlusTest:testFailBoundMinBiggerThanMax() (gas: 309) +DSTestPlusTest:testFailBoundMinBiggerThanMax(uint256,uint256,uint256) (runs: 256, μ: 460, ~: 462) +DSTestPlusTest:testRelApproxEqBothZeroesPasses() (gas: 425) +ERC1155Test:testApproveAll() (gas: 31009) +ERC1155Test:testApproveAll(address,bool) (runs: 256, μ: 16872, ~: 11440) +ERC1155Test:testBatchBalanceOf() (gas: 157631) +ERC1155Test:testBatchBalanceOf(address[],uint256[],uint256[],bytes) (runs: 256, μ: 3307946, ~: 2596398) +ERC1155Test:testBatchBurn() (gas: 151074) +ERC1155Test:testBatchBurn(address,uint256[],uint256[],uint256[],bytes) (runs: 256, μ: 3425444, ~: 3021348) +ERC1155Test:testBatchMintToEOA() (gas: 137337) +ERC1155Test:testBatchMintToEOA(address,uint256[],uint256[],bytes) (runs: 256, μ: 3261893, ~: 2923515) +ERC1155Test:testBatchMintToERC1155Recipient() (gas: 995703) +ERC1155Test:testBatchMintToERC1155Recipient(uint256[],uint256[],bytes) (runs: 256, μ: 7336290, ~: 6396323) +ERC1155Test:testBurn() (gas: 38598) +ERC1155Test:testBurn(address,uint256,uint256,bytes,uint256) (runs: 256, μ: 40221, ~: 42098) +ERC1155Test:testFailBalanceOfBatchWithArrayMismatch() (gas: 7933) +ERC1155Test:testFailBalanceOfBatchWithArrayMismatch(address[],uint256[]) (runs: 256, μ: 53386, ~: 54066) +ERC1155Test:testFailBatchBurnInsufficientBalance() (gas: 136156) +ERC1155Test:testFailBatchBurnInsufficientBalance(address,uint256[],uint256[],uint256[],bytes) (runs: 256, μ: 1278568, ~: 440335) +ERC1155Test:testFailBatchBurnWithArrayLengthMismatch() (gas: 135542) +ERC1155Test:testFailBatchBurnWithArrayLengthMismatch(address,uint256[],uint256[],uint256[],bytes) (runs: 256, μ: 77137, ~: 78751) +ERC1155Test:testFailBatchMintToNonERC1155Recipient() (gas: 167292) +ERC1155Test:testFailBatchMintToNonERC1155Recipient(uint256[],uint256[],bytes) (runs: 256, μ: 3131966, ~: 2673077) +ERC1155Test:testFailBatchMintToRevertingERC1155Recipient() (gas: 358811) +ERC1155Test:testFailBatchMintToRevertingERC1155Recipient(uint256[],uint256[],bytes) (runs: 256, μ: 3323504, ~: 2864613) +ERC1155Test:testFailBatchMintToWrongReturnDataERC1155Recipient() (gas: 310743) +ERC1155Test:testFailBatchMintToWrongReturnDataERC1155Recipient(uint256[],uint256[],bytes) (runs: 256, μ: 3275462, ~: 2816572) +ERC1155Test:testFailBatchMintToZero() (gas: 131737) +ERC1155Test:testFailBatchMintToZero(uint256[],uint256[],bytes) (runs: 256, μ: 3072466, ~: 2612336) +ERC1155Test:testFailBatchMintWithArrayMismatch() (gas: 9600) +ERC1155Test:testFailBatchMintWithArrayMismatch(address,uint256[],uint256[],bytes) (runs: 256, μ: 69252, ~: 68809) +ERC1155Test:testFailBurnInsufficientBalance() (gas: 34852) +ERC1155Test:testFailBurnInsufficientBalance(address,uint256,uint256,uint256,bytes) (runs: 256, μ: 35951, ~: 38209) +ERC1155Test:testFailMintToNonERC155Recipient() (gas: 68191) +ERC1155Test:testFailMintToNonERC155Recipient(uint256,uint256,bytes) (runs: 256, μ: 68507, ~: 69197) +ERC1155Test:testFailMintToRevertingERC155Recipient() (gas: 259435) +ERC1155Test:testFailMintToRevertingERC155Recipient(uint256,uint256,bytes) (runs: 256, μ: 259682, ~: 260373) +ERC1155Test:testFailMintToWrongReturnDataERC155Recipient() (gas: 259389) +ERC1155Test:testFailMintToWrongReturnDataERC155Recipient(uint256,uint256,bytes) (runs: 256, μ: 259706, ~: 260397) +ERC1155Test:testFailMintToZero() (gas: 33705) +ERC1155Test:testFailMintToZero(uint256,uint256,bytes) (runs: 256, μ: 33815, ~: 34546) +ERC1155Test:testFailSafeBatchTransferFromToNonERC1155Recipient() (gas: 321377) +ERC1155Test:testFailSafeBatchTransferFromToNonERC1155Recipient(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 3490437, ~: 2963551) +ERC1155Test:testFailSafeBatchTransferFromToRevertingERC1155Recipient() (gas: 512956) +ERC1155Test:testFailSafeBatchTransferFromToRevertingERC1155Recipient(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 3681974, ~: 3155082) +ERC1155Test:testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient() (gas: 464847) +ERC1155Test:testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 3633892, ~: 3107003) +ERC1155Test:testFailSafeBatchTransferFromToZero() (gas: 286556) +ERC1155Test:testFailSafeBatchTransferFromToZero(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 3455257, ~: 2928396) +ERC1155Test:testFailSafeBatchTransferFromWithArrayLengthMismatch() (gas: 162674) +ERC1155Test:testFailSafeBatchTransferFromWithArrayLengthMismatch(address,uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 81184, ~: 82042) +ERC1155Test:testFailSafeBatchTransferInsufficientBalance() (gas: 163555) +ERC1155Test:testFailSafeBatchTransferInsufficientBalance(address,uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 1497154, ~: 499517) +ERC1155Test:testFailSafeTransferFromInsufficientBalance() (gas: 63245) +ERC1155Test:testFailSafeTransferFromInsufficientBalance(address,uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 63986, ~: 67405) +ERC1155Test:testFailSafeTransferFromSelfInsufficientBalance() (gas: 34297) +ERC1155Test:testFailSafeTransferFromSelfInsufficientBalance(address,uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 36266, ~: 38512) +ERC1155Test:testFailSafeTransferFromToNonERC155Recipient() (gas: 96510) +ERC1155Test:testFailSafeTransferFromToNonERC155Recipient(uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 96580, ~: 100546) +ERC1155Test:testFailSafeTransferFromToRevertingERC1155Recipient() (gas: 287731) +ERC1155Test:testFailSafeTransferFromToRevertingERC1155Recipient(uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 287750, ~: 291719) +ERC1155Test:testFailSafeTransferFromToWrongReturnDataERC1155Recipient() (gas: 239587) +ERC1155Test:testFailSafeTransferFromToWrongReturnDataERC1155Recipient(uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 239629, ~: 243598) +ERC1155Test:testFailSafeTransferFromToZero() (gas: 62014) +ERC1155Test:testFailSafeTransferFromToZero(uint256,uint256,uint256,bytes,bytes) (runs: 256, μ: 62068, ~: 66037) +ERC1155Test:testMintToEOA() (gas: 34765) +ERC1155Test:testMintToEOA(address,uint256,uint256,bytes) (runs: 256, μ: 35426, ~: 35907) +ERC1155Test:testMintToERC1155Recipient() (gas: 661411) +ERC1155Test:testMintToERC1155Recipient(uint256,uint256,bytes) (runs: 256, μ: 691094, ~: 684374) +ERC1155Test:testSafeBatchTransferFromToEOA() (gas: 297822) +ERC1155Test:testSafeBatchTransferFromToEOA(address,uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 4692589, ~: 3776319) +ERC1155Test:testSafeBatchTransferFromToERC1155Recipient() (gas: 1175327) +ERC1155Test:testSafeBatchTransferFromToERC1155Recipient(uint256[],uint256[],uint256[],bytes,bytes) (runs: 256, μ: 7683519, ~: 6515438) +ERC1155Test:testSafeTransferFromSelf() (gas: 64177) +ERC1155Test:testSafeTransferFromSelf(uint256,uint256,bytes,uint256,address,bytes) (runs: 256, μ: 64824, ~: 68564) +ERC1155Test:testSafeTransferFromToEOA() (gas: 93167) +ERC1155Test:testSafeTransferFromToEOA(uint256,uint256,bytes,uint256,address,bytes) (runs: 256, μ: 93578, ~: 97450) +ERC1155Test:testSafeTransferFromToERC1155Recipient() (gas: 739583) +ERC1155Test:testSafeTransferFromToERC1155Recipient(uint256,uint256,bytes,uint256,bytes) (runs: 256, μ: 769591, ~: 765729) +ERC20Invariants:invariantBalanceSum() (runs: 256, calls: 3840, reverts: 2388) +ERC20Test:invariantMetadata() (runs: 256, calls: 3840, reverts: 2610) +ERC20Test:testApprove() (gas: 31058) +ERC20Test:testApprove(address,uint256) (runs: 256, μ: 30424, ~: 31280) +ERC20Test:testBurn() (gas: 56970) +ERC20Test:testBurn(address,uint256,uint256) (runs: 256, μ: 56678, ~: 59645) +ERC20Test:testFailBurnInsufficientBalance(address,uint256,uint256) (runs: 256, μ: 51897, ~: 55492) +ERC20Test:testFailPermitBadDeadline() (gas: 36935) +ERC20Test:testFailPermitBadDeadline(uint256,address,uint256,uint256) (runs: 256, μ: 32148, ~: 37218) +ERC20Test:testFailPermitBadNonce() (gas: 36874) +ERC20Test:testFailPermitBadNonce(uint256,address,uint256,uint256,uint256) (runs: 256, μ: 31628, ~: 37187) +ERC20Test:testFailPermitPastDeadline() (gas: 11191) +ERC20Test:testFailPermitPastDeadline(uint256,address,uint256,uint256) (runs: 256, μ: 12037, ~: 13101) +ERC20Test:testFailPermitReplay() (gas: 66274) +ERC20Test:testFailPermitReplay(uint256,address,uint256,uint256) (runs: 256, μ: 57071, ~: 66592) +ERC20Test:testFailTransferFromInsufficientAllowance() (gas: 80882) +ERC20Test:testFailTransferFromInsufficientAllowance(address,uint256,uint256) (runs: 256, μ: 79858, ~: 83393) +ERC20Test:testFailTransferFromInsufficientBalance() (gas: 81358) +ERC20Test:testFailTransferFromInsufficientBalance(address,uint256,uint256) (runs: 256, μ: 79359, ~: 83870) +ERC20Test:testFailTransferInsufficientBalance() (gas: 52806) +ERC20Test:testFailTransferInsufficientBalance(address,uint256,uint256) (runs: 256, μ: 51720, ~: 55310) +ERC20Test:testInfiniteApproveTransferFrom() (gas: 89793) +ERC20Test:testMetadata(string,string,uint8) (runs: 256, μ: 869043, ~: 863173) +ERC20Test:testMint() (gas: 53746) +ERC20Test:testMint(address,uint256) (runs: 256, μ: 52214, ~: 53925) +ERC20Test:testPermit() (gas: 63193) +ERC20Test:testPermit(uint248,address,uint256,uint256) (runs: 256, μ: 62584, ~: 63517) +ERC20Test:testTransfer() (gas: 60272) +ERC20Test:testTransfer(address,uint256) (runs: 256, μ: 58773, ~: 60484) +ERC20Test:testTransferFrom() (gas: 83777) +ERC20Test:testTransferFrom(address,uint256,uint256) (runs: 256, μ: 86308, ~: 92841) +ERC4626Test:invariantMetadata() (runs: 256, calls: 3840, reverts: 2901) +ERC4626Test:testFailDepositWithNoApproval() (gas: 13369) +ERC4626Test:testFailDepositWithNotEnoughApproval() (gas: 87005) +ERC4626Test:testFailDepositZero() (gas: 7780) +ERC4626Test:testFailMintWithNoApproval() (gas: 13308) +ERC4626Test:testFailRedeemWithNoShareAmount() (gas: 32342) +ERC4626Test:testFailRedeemWithNotEnoughShareAmount() (gas: 203643) +ERC4626Test:testFailRedeemZero() (gas: 7967) +ERC4626Test:testFailWithdrawWithNoUnderlyingAmount() (gas: 32289) +ERC4626Test:testFailWithdrawWithNotEnoughUnderlyingAmount() (gas: 203607) +ERC4626Test:testMetadata(string,string) (runs: 256, μ: 1503475, ~: 1494729) +ERC4626Test:testMintZero() (gas: 54607) +ERC4626Test:testMultipleMintDepositRedeemWithdraw() (gas: 411804) +ERC4626Test:testSingleDepositWithdraw(uint128) (runs: 256, μ: 201540, ~: 201550) +ERC4626Test:testSingleMintRedeem(uint128) (runs: 256, μ: 201466, ~: 201476) +ERC4626Test:testVaultInteractionsForSomeoneElse() (gas: 286238) +ERC4626Test:testWithdrawZero() (gas: 52468) +ERC6909Test:testApprove() (gas: 31594) +ERC6909Test:testApprove(address,uint256,uint256) (runs: 256, μ: 30905, ~: 31838) +ERC6909Test:testBurn() (gas: 58826) +ERC6909Test:testBurn(address,uint256,uint256) (runs: 256, μ: 41756, ~: 42866) +ERC6909Test:testFailMint() (gas: 53818) +ERC6909Test:testFailTransfer() (gas: 10823) +ERC6909Test:testFailTransfer(address,address,uint256,uint256) (runs: 256, μ: 13203, ~: 13203) +ERC6909Test:testFailTransferFrom() (gas: 10846) +ERC6909Test:testFailTransferFrom(address,address,uint256,uint256) (runs: 256, μ: 13426, ~: 13426) +ERC6909Test:testFailTransferFromNotAuthorized() (gas: 58272) +ERC6909Test:testFailTransferFromNotAuthorized(address,address,uint256,uint256) (runs: 256, μ: 60827, ~: 60827) +ERC6909Test:testMint() (gas: 54775) +ERC6909Test:testMint(address,uint256,uint256) (runs: 256, μ: 53101, ~: 54967) +ERC6909Test:testSetOperator() (gas: 31115) +ERC6909Test:testSetOperator(address,bool) (runs: 256, μ: 17028, ~: 11596) +ERC6909Test:testTransfer() (gas: 83929) +ERC6909Test:testTransfer(address,address,uint256,uint256,uint256) (runs: 256, μ: 82007, ~: 86605) +ERC6909Test:testTransferFromAsOperator() (gas: 109473) +ERC6909Test:testTransferFromAsOperator(address,address,uint256,uint256,uint256) (runs: 256, μ: 107546, ~: 112144) +ERC6909Test:testTransferFromWithApproval() (gas: 114030) +ERC6909Test:testTransferFromWithApproval(address,address,uint256,uint256,uint256) (runs: 256, μ: 111172, ~: 116749) +ERC6909Test:testTransferFromWithInfiniteApproval() (gas: 113593) +ERC6909Test:testTransferFromWithInfiniteApproval(address,address,uint256,uint256,uint256) (runs: 256, μ: 111693, ~: 116291) +ERC721Test:invariantMetadata() (runs: 256, calls: 3840, reverts: 2183) +ERC721Test:testApprove() (gas: 78427) +ERC721Test:testApprove(address,uint256) (runs: 256, μ: 78637, ~: 78637) +ERC721Test:testApproveAll() (gas: 31063) +ERC721Test:testApproveAll(address,bool) (runs: 256, μ: 16970, ~: 11538) +ERC721Test:testApproveBurn() (gas: 65550) +ERC721Test:testApproveBurn(address,uint256) (runs: 256, μ: 65613, ~: 65624) +ERC721Test:testBurn() (gas: 46107) +ERC721Test:testBurn(address,uint256) (runs: 256, μ: 46152, ~: 46163) +ERC721Test:testFailApproveUnAuthorized() (gas: 55598) +ERC721Test:testFailApproveUnAuthorized(address,uint256,address) (runs: 256, μ: 55873, ~: 55873) +ERC721Test:testFailApproveUnMinted() (gas: 10236) +ERC721Test:testFailApproveUnMinted(uint256,address) (runs: 256, μ: 10363, ~: 10363) +ERC721Test:testFailBalanceOfZeroAddress() (gas: 5555) +ERC721Test:testFailBurnUnMinted() (gas: 7857) +ERC721Test:testFailBurnUnMinted(uint256) (runs: 256, μ: 7938, ~: 7938) +ERC721Test:testFailDoubleBurn() (gas: 58943) +ERC721Test:testFailDoubleBurn(uint256,address) (runs: 256, μ: 59174, ~: 59174) +ERC721Test:testFailDoubleMint() (gas: 53286) +ERC721Test:testFailDoubleMint(uint256,address) (runs: 256, μ: 53496, ~: 53496) +ERC721Test:testFailMintToZero() (gas: 5753) +ERC721Test:testFailMintToZero(uint256) (runs: 256, μ: 5835, ~: 5835) +ERC721Test:testFailOwnerOfUnminted() (gas: 7609) +ERC721Test:testFailOwnerOfUnminted(uint256) (runs: 256, μ: 7689, ~: 7689) +ERC721Test:testFailSafeMintToERC721RecipientWithWrongReturnData() (gas: 159076) +ERC721Test:testFailSafeMintToERC721RecipientWithWrongReturnData(uint256) (runs: 256, μ: 159125, ~: 159125) +ERC721Test:testFailSafeMintToERC721RecipientWithWrongReturnDataWithData() (gas: 159831) +ERC721Test:testFailSafeMintToERC721RecipientWithWrongReturnDataWithData(uint256,bytes) (runs: 256, μ: 160231, ~: 160182) +ERC721Test:testFailSafeMintToNonERC721Recipient() (gas: 89210) +ERC721Test:testFailSafeMintToNonERC721Recipient(uint256) (runs: 256, μ: 89279, ~: 89279) +ERC721Test:testFailSafeMintToNonERC721RecipientWithData() (gas: 89995) +ERC721Test:testFailSafeMintToNonERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 90420, ~: 90368) +ERC721Test:testFailSafeMintToRevertingERC721Recipient() (gas: 204743) +ERC721Test:testFailSafeMintToRevertingERC721Recipient(uint256) (runs: 256, μ: 204815, ~: 204815) +ERC721Test:testFailSafeMintToRevertingERC721RecipientWithData() (gas: 205517) +ERC721Test:testFailSafeMintToRevertingERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 205964, ~: 205915) +ERC721Test:testFailSafeTransferFromToERC721RecipientWithWrongReturnData() (gas: 187276) +ERC721Test:testFailSafeTransferFromToERC721RecipientWithWrongReturnData(uint256) (runs: 256, μ: 187360, ~: 187360) +ERC721Test:testFailSafeTransferFromToERC721RecipientWithWrongReturnDataWithData() (gas: 187728) +ERC721Test:testFailSafeTransferFromToERC721RecipientWithWrongReturnDataWithData(uint256,bytes) (runs: 256, μ: 188067, ~: 188063) +ERC721Test:testFailSafeTransferFromToNonERC721Recipient() (gas: 117413) +ERC721Test:testFailSafeTransferFromToNonERC721Recipient(uint256) (runs: 256, μ: 117495, ~: 117495) +ERC721Test:testFailSafeTransferFromToNonERC721RecipientWithData() (gas: 117872) +ERC721Test:testFailSafeTransferFromToNonERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 118280, ~: 118276) +ERC721Test:testFailSafeTransferFromToRevertingERC721Recipient() (gas: 233009) +ERC721Test:testFailSafeTransferFromToRevertingERC721Recipient(uint256) (runs: 256, μ: 233050, ~: 233050) +ERC721Test:testFailSafeTransferFromToRevertingERC721RecipientWithData() (gas: 233396) +ERC721Test:testFailSafeTransferFromToRevertingERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 233823, ~: 233819) +ERC721Test:testFailTransferFromNotOwner() (gas: 57872) +ERC721Test:testFailTransferFromNotOwner(address,address,uint256) (runs: 256, μ: 57515, ~: 58162) +ERC721Test:testFailTransferFromToZero() (gas: 53381) +ERC721Test:testFailTransferFromToZero(uint256) (runs: 256, μ: 53463, ~: 53463) +ERC721Test:testFailTransferFromUnOwned() (gas: 8000) +ERC721Test:testFailTransferFromUnOwned(address,address,uint256) (runs: 256, μ: 8311, ~: 8241) +ERC721Test:testFailTransferFromWrongFrom() (gas: 53361) +ERC721Test:testFailTransferFromWrongFrom(address,address,address,uint256) (runs: 256, μ: 53566, ~: 53752) +ERC721Test:testMetadata(string,string) (runs: 256, μ: 1341878, ~: 1332786) +ERC721Test:testMint() (gas: 54336) +ERC721Test:testMint(address,uint256) (runs: 256, μ: 54521, ~: 54521) +ERC721Test:testSafeMintToEOA() (gas: 56993) +ERC721Test:testSafeMintToEOA(uint256,address) (runs: 256, μ: 56976, ~: 57421) +ERC721Test:testSafeMintToERC721Recipient() (gas: 427035) +ERC721Test:testSafeMintToERC721Recipient(uint256) (runs: 256, μ: 426053, ~: 427142) +ERC721Test:testSafeMintToERC721RecipientWithData() (gas: 448149) +ERC721Test:testSafeMintToERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 480015, ~: 470905) +ERC721Test:testSafeTransferFromToEOA() (gas: 95666) +ERC721Test:testSafeTransferFromToEOA(uint256,address) (runs: 256, μ: 95352, ~: 96099) +ERC721Test:testSafeTransferFromToERC721Recipient() (gas: 485549) +ERC721Test:testSafeTransferFromToERC721Recipient(uint256) (runs: 256, μ: 484593, ~: 485682) +ERC721Test:testSafeTransferFromToERC721RecipientWithData() (gas: 506317) +ERC721Test:testSafeTransferFromToERC721RecipientWithData(uint256,bytes) (runs: 256, μ: 538126, ~: 529082) +ERC721Test:testTransferFrom() (gas: 86347) +ERC721Test:testTransferFrom(uint256,address) (runs: 256, μ: 86469, ~: 86477) +ERC721Test:testTransferFromApproveAll() (gas: 92898) +ERC721Test:testTransferFromApproveAll(uint256,address) (runs: 256, μ: 93182, ~: 93182) +ERC721Test:testTransferFromSelf() (gas: 64776) +ERC721Test:testTransferFromSelf(uint256,address) (runs: 256, μ: 65061, ~: 65061) +FixedPointMathLibTest:testDifferentiallyFuzzSqrt(uint256) (runs: 256, μ: 13809, ~: 4181) +FixedPointMathLibTest:testDivWadDown() (gas: 820) +FixedPointMathLibTest:testDivWadDown(uint256,uint256) (runs: 256, μ: 712, ~: 813) +FixedPointMathLibTest:testDivWadDownEdgeCases() (gas: 439) +FixedPointMathLibTest:testDivWadUp() (gas: 943) +FixedPointMathLibTest:testDivWadUp(uint256,uint256) (runs: 256, μ: 792, ~: 952) +FixedPointMathLibTest:testDivWadUpEdgeCases() (gas: 442) +FixedPointMathLibTest:testFailDivWadDownOverflow(uint256,uint256) (runs: 256, μ: 442, ~: 419) +FixedPointMathLibTest:testFailDivWadDownZeroDenominator() (gas: 332) +FixedPointMathLibTest:testFailDivWadDownZeroDenominator(uint256) (runs: 256, μ: 387, ~: 387) +FixedPointMathLibTest:testFailDivWadUpOverflow(uint256,uint256) (runs: 256, μ: 397, ~: 374) +FixedPointMathLibTest:testFailDivWadUpZeroDenominator() (gas: 332) +FixedPointMathLibTest:testFailDivWadUpZeroDenominator(uint256) (runs: 256, μ: 386, ~: 386) +FixedPointMathLibTest:testFailMulDivDownOverflow(uint256,uint256,uint256) (runs: 256, μ: 434, ~: 414) +FixedPointMathLibTest:testFailMulDivDownZeroDenominator() (gas: 328) +FixedPointMathLibTest:testFailMulDivDownZeroDenominator(uint256,uint256) (runs: 256, μ: 385, ~: 385) +FixedPointMathLibTest:testFailMulDivUpOverflow(uint256,uint256,uint256) (runs: 256, μ: 457, ~: 437) +FixedPointMathLibTest:testFailMulDivUpZeroDenominator() (gas: 329) +FixedPointMathLibTest:testFailMulDivUpZeroDenominator(uint256,uint256) (runs: 256, μ: 428, ~: 428) +FixedPointMathLibTest:testFailMulWadDownOverflow(uint256,uint256) (runs: 256, μ: 421, ~: 387) +FixedPointMathLibTest:testFailMulWadUpOverflow(uint256,uint256) (runs: 256, μ: 398, ~: 364) +FixedPointMathLibTest:testMulDivDown() (gas: 1813) +FixedPointMathLibTest:testMulDivDown(uint256,uint256,uint256) (runs: 256, μ: 686, ~: 786) +FixedPointMathLibTest:testMulDivDownEdgeCases() (gas: 686) +FixedPointMathLibTest:testMulDivUp() (gas: 2095) +FixedPointMathLibTest:testMulDivUp(uint256,uint256,uint256) (runs: 256, μ: 821, ~: 1034) +FixedPointMathLibTest:testMulDivUpEdgeCases() (gas: 785) +FixedPointMathLibTest:testMulWadDown() (gas: 823) +FixedPointMathLibTest:testMulWadDown(uint256,uint256) (runs: 256, μ: 681, ~: 803) +FixedPointMathLibTest:testMulWadDownEdgeCases() (gas: 822) +FixedPointMathLibTest:testMulWadUp() (gas: 921) +FixedPointMathLibTest:testMulWadUp(uint256,uint256) (runs: 256, μ: 821, ~: 1053) +FixedPointMathLibTest:testMulWadUpEdgeCases() (gas: 899) +FixedPointMathLibTest:testRPow() (gas: 2164) +FixedPointMathLibTest:testSqrt() (gas: 2580) +FixedPointMathLibTest:testSqrt(uint256) (runs: 256, μ: 997, ~: 1013) +FixedPointMathLibTest:testSqrtBack(uint256) (runs: 256, μ: 15210, ~: 340) +FixedPointMathLibTest:testSqrtBackHashed(uint256) (runs: 256, μ: 59066, ~: 59500) +FixedPointMathLibTest:testSqrtBackHashedSingle() (gas: 58937) +LibStringTest:testDifferentiallyFuzzToString(uint256,bytes) (runs: 256, μ: 20892, ~: 8988) +LibStringTest:testDifferentiallyFuzzToStringInt(int256,bytes) (runs: 256, μ: 20081, ~: 8356) +LibStringTest:testToString() (gas: 10069) +LibStringTest:testToStringDirty() (gas: 8145) +LibStringTest:testToStringIntNegative() (gas: 9634) +LibStringTest:testToStringIntPositive() (gas: 10481) +LibStringTest:testToStringOverwrite() (gas: 506) +MerkleProofLibTest:testValidProofSupplied() (gas: 2153) +MerkleProofLibTest:testVerifyEmptyMerkleProofSuppliedLeafAndRootDifferent() (gas: 1458) +MerkleProofLibTest:testVerifyEmptyMerkleProofSuppliedLeafAndRootSame() (gas: 1452) +MerkleProofLibTest:testVerifyInvalidProofSupplied() (gas: 2172) +MultiRolesAuthorityTest:testCanCallPublicCapability() (gas: 34204) +MultiRolesAuthorityTest:testCanCallPublicCapability(address,address,bytes4) (runs: 256, μ: 34390, ~: 34361) +MultiRolesAuthorityTest:testCanCallWithAuthorizedRole() (gas: 80416) +MultiRolesAuthorityTest:testCanCallWithAuthorizedRole(address,uint8,address,bytes4) (runs: 256, μ: 80705, ~: 80671) +MultiRolesAuthorityTest:testCanCallWithCustomAuthority() (gas: 422439) +MultiRolesAuthorityTest:testCanCallWithCustomAuthority(address,address,bytes4) (runs: 256, μ: 422858, ~: 422858) +MultiRolesAuthorityTest:testCanCallWithCustomAuthorityOverridesPublicCapability() (gas: 247388) +MultiRolesAuthorityTest:testCanCallWithCustomAuthorityOverridesPublicCapability(address,address,bytes4) (runs: 256, μ: 247841, ~: 247841) +MultiRolesAuthorityTest:testCanCallWithCustomAuthorityOverridesUserWithRole() (gas: 256546) +MultiRolesAuthorityTest:testCanCallWithCustomAuthorityOverridesUserWithRole(address,uint8,address,bytes4) (runs: 256, μ: 256885, ~: 256852) +MultiRolesAuthorityTest:testSetPublicCapabilities() (gas: 27727) +MultiRolesAuthorityTest:testSetPublicCapabilities(bytes4) (runs: 256, μ: 27836, ~: 27835) +MultiRolesAuthorityTest:testSetRoleCapabilities() (gas: 28932) +MultiRolesAuthorityTest:testSetRoleCapabilities(uint8,bytes4) (runs: 256, μ: 29073, ~: 29073) +MultiRolesAuthorityTest:testSetRoles() (gas: 28918) +MultiRolesAuthorityTest:testSetRoles(address,uint8) (runs: 256, μ: 29030, ~: 29016) +MultiRolesAuthorityTest:testSetTargetCustomAuthority() (gas: 28102) +MultiRolesAuthorityTest:testSetTargetCustomAuthority(address,address) (runs: 256, μ: 28176, ~: 28146) +OwnedTest:testCallFunctionAsNonOwner() (gas: 11344) +OwnedTest:testCallFunctionAsNonOwner(address) (runs: 256, μ: 16252, ~: 16290) +OwnedTest:testCallFunctionAsOwner() (gas: 10435) +OwnedTest:testTransferOwnership() (gas: 13123) +OwnedTest:testTransferOwnership(address) (runs: 256, μ: 13154, ~: 13192) +ReentrancyGuardTest:invariantReentrancyStatusAlways1() (runs: 256, calls: 3840, reverts: 266) +ReentrancyGuardTest:testFailUnprotectedCall() (gas: 46147) +ReentrancyGuardTest:testNoReentrancy() (gas: 7515) +ReentrancyGuardTest:testProtectedCall() (gas: 33467) +RolesAuthorityTest:testCanCallPublicCapability() (gas: 33409) +RolesAuthorityTest:testCanCallPublicCapability(address,address,bytes4) (runs: 256, μ: 33560, ~: 33532) +RolesAuthorityTest:testCanCallWithAuthorizedRole() (gas: 79995) +RolesAuthorityTest:testCanCallWithAuthorizedRole(address,uint8,address,bytes4) (runs: 256, μ: 80272, ~: 80238) +RolesAuthorityTest:testSetPublicCapabilities() (gas: 29095) +RolesAuthorityTest:testSetPublicCapabilities(address,bytes4) (runs: 256, μ: 29209, ~: 29192) +RolesAuthorityTest:testSetRoleCapabilities() (gas: 30276) +RolesAuthorityTest:testSetRoleCapabilities(uint8,address,bytes4) (runs: 256, μ: 30506, ~: 30489) +RolesAuthorityTest:testSetRoles() (gas: 29005) +RolesAuthorityTest:testSetRoles(address,uint8) (runs: 256, μ: 29122, ~: 29108) +SSTORE2Test:testFailReadInvalidPointer() (gas: 2927) +SSTORE2Test:testFailReadInvalidPointer(address,bytes) (runs: 256, μ: 3889, ~: 3892) +SSTORE2Test:testFailReadInvalidPointerCustomBounds() (gas: 3099) +SSTORE2Test:testFailReadInvalidPointerCustomBounds(address,uint256,uint256,bytes) (runs: 256, μ: 4107, ~: 4130) +SSTORE2Test:testFailReadInvalidPointerCustomStartBound() (gas: 3004) +SSTORE2Test:testFailReadInvalidPointerCustomStartBound(address,uint256,bytes) (runs: 256, μ: 3980, ~: 3988) +SSTORE2Test:testFailWriteReadCustomBoundsOutOfRange(bytes,uint256,uint256,bytes) (runs: 256, μ: 46236, ~: 43603) +SSTORE2Test:testFailWriteReadCustomStartBoundOutOfRange(bytes,uint256,bytes) (runs: 256, μ: 46017, ~: 43452) +SSTORE2Test:testFailWriteReadEmptyOutOfBounds() (gas: 34470) +SSTORE2Test:testFailWriteReadOutOfBounds() (gas: 34426) +SSTORE2Test:testFailWriteReadOutOfStartBound() (gas: 34362) +SSTORE2Test:testWriteRead() (gas: 53497) +SSTORE2Test:testWriteRead(bytes,bytes) (runs: 256, μ: 44019, ~: 41555) +SSTORE2Test:testWriteReadCustomBounds() (gas: 34869) +SSTORE2Test:testWriteReadCustomBounds(bytes,uint256,uint256,bytes) (runs: 256, μ: 29483, ~: 44592) +SSTORE2Test:testWriteReadCustomStartBound() (gas: 34740) +SSTORE2Test:testWriteReadCustomStartBound(bytes,uint256,bytes) (runs: 256, μ: 46484, ~: 44053) +SSTORE2Test:testWriteReadEmptyBound() (gas: 34677) +SSTORE2Test:testWriteReadFullBoundedRead() (gas: 53672) +SSTORE2Test:testWriteReadFullStartBound() (gas: 34764) +SafeCastLibTest:testFailSafeCastTo104() (gas: 387) +SafeCastLibTest:testFailSafeCastTo104(uint256) (runs: 256, μ: 468, ~: 468) +SafeCastLibTest:testFailSafeCastTo112() (gas: 388) +SafeCastLibTest:testFailSafeCastTo112(uint256) (runs: 256, μ: 445, ~: 445) +SafeCastLibTest:testFailSafeCastTo120() (gas: 409) +SafeCastLibTest:testFailSafeCastTo120(uint256) (runs: 256, μ: 490, ~: 490) +SafeCastLibTest:testFailSafeCastTo128() (gas: 365) +SafeCastLibTest:testFailSafeCastTo128(uint256) (runs: 256, μ: 487, ~: 487) +SafeCastLibTest:testFailSafeCastTo136() (gas: 409) +SafeCastLibTest:testFailSafeCastTo136(uint256) (runs: 256, μ: 489, ~: 489) +SafeCastLibTest:testFailSafeCastTo144() (gas: 365) +SafeCastLibTest:testFailSafeCastTo144(uint256) (runs: 256, μ: 423, ~: 423) +SafeCastLibTest:testFailSafeCastTo152() (gas: 368) +SafeCastLibTest:testFailSafeCastTo152(uint256) (runs: 256, μ: 468, ~: 468) +SafeCastLibTest:testFailSafeCastTo16() (gas: 388) +SafeCastLibTest:testFailSafeCastTo16(uint256) (runs: 256, μ: 468, ~: 468) +SafeCastLibTest:testFailSafeCastTo160() (gas: 409) +SafeCastLibTest:testFailSafeCastTo160(uint256) (runs: 256, μ: 444, ~: 444) +SafeCastLibTest:testFailSafeCastTo168() (gas: 341) +SafeCastLibTest:testFailSafeCastTo168(uint256) (runs: 256, μ: 488, ~: 488) +SafeCastLibTest:testFailSafeCastTo176() (gas: 363) +SafeCastLibTest:testFailSafeCastTo176(uint256) (runs: 256, μ: 489, ~: 489) +SafeCastLibTest:testFailSafeCastTo184() (gas: 343) +SafeCastLibTest:testFailSafeCastTo184(uint256) (runs: 256, μ: 490, ~: 490) +SafeCastLibTest:testFailSafeCastTo192() (gas: 367) +SafeCastLibTest:testFailSafeCastTo192(uint256) (runs: 256, μ: 446, ~: 446) +SafeCastLibTest:testFailSafeCastTo200() (gas: 343) +SafeCastLibTest:testFailSafeCastTo200(uint256) (runs: 256, μ: 490, ~: 490) +SafeCastLibTest:testFailSafeCastTo208() (gas: 386) +SafeCastLibTest:testFailSafeCastTo208(uint256) (runs: 256, μ: 446, ~: 446) +SafeCastLibTest:testFailSafeCastTo216() (gas: 365) +SafeCastLibTest:testFailSafeCastTo216(uint256) (runs: 256, μ: 424, ~: 424) +SafeCastLibTest:testFailSafeCastTo224() (gas: 409) +SafeCastLibTest:testFailSafeCastTo224(uint256) (runs: 256, μ: 423, ~: 423) +SafeCastLibTest:testFailSafeCastTo232() (gas: 410) +SafeCastLibTest:testFailSafeCastTo232(uint256) (runs: 256, μ: 467, ~: 467) +SafeCastLibTest:testFailSafeCastTo24() (gas: 387) +SafeCastLibTest:testFailSafeCastTo24(uint256) (runs: 256, μ: 424, ~: 424) +SafeCastLibTest:testFailSafeCastTo240() (gas: 364) +SafeCastLibTest:testFailSafeCastTo240(uint256) (runs: 256, μ: 467, ~: 467) +SafeCastLibTest:testFailSafeCastTo248() (gas: 365) +SafeCastLibTest:testFailSafeCastTo248(uint256) (runs: 256, μ: 466, ~: 466) +SafeCastLibTest:testFailSafeCastTo32() (gas: 364) +SafeCastLibTest:testFailSafeCastTo32(uint256) (runs: 256, μ: 468, ~: 468) +SafeCastLibTest:testFailSafeCastTo40() (gas: 366) +SafeCastLibTest:testFailSafeCastTo40(uint256) (runs: 256, μ: 422, ~: 422) +SafeCastLibTest:testFailSafeCastTo48() (gas: 366) +SafeCastLibTest:testFailSafeCastTo48(uint256) (runs: 256, μ: 488, ~: 488) +SafeCastLibTest:testFailSafeCastTo56() (gas: 388) +SafeCastLibTest:testFailSafeCastTo56(uint256) (runs: 256, μ: 445, ~: 445) +SafeCastLibTest:testFailSafeCastTo64() (gas: 410) +SafeCastLibTest:testFailSafeCastTo64(uint256) (runs: 256, μ: 446, ~: 446) +SafeCastLibTest:testFailSafeCastTo72() (gas: 410) +SafeCastLibTest:testFailSafeCastTo72(uint256) (runs: 256, μ: 467, ~: 467) +SafeCastLibTest:testFailSafeCastTo8() (gas: 341) +SafeCastLibTest:testFailSafeCastTo8(uint256) (runs: 256, μ: 421, ~: 421) +SafeCastLibTest:testFailSafeCastTo80() (gas: 343) +SafeCastLibTest:testFailSafeCastTo80(uint256) (runs: 256, μ: 424, ~: 424) +SafeCastLibTest:testFailSafeCastTo88() (gas: 344) +SafeCastLibTest:testFailSafeCastTo88(uint256) (runs: 256, μ: 489, ~: 489) +SafeCastLibTest:testFailSafeCastTo96() (gas: 366) +SafeCastLibTest:testFailSafeCastTo96(uint256) (runs: 256, μ: 469, ~: 469) +SafeCastLibTest:testSafeCastTo104() (gas: 515) +SafeCastLibTest:testSafeCastTo104(uint256) (runs: 256, μ: 2779, ~: 2779) +SafeCastLibTest:testSafeCastTo112() (gas: 469) +SafeCastLibTest:testSafeCastTo112(uint256) (runs: 256, μ: 2755, ~: 2755) +SafeCastLibTest:testSafeCastTo120() (gas: 491) +SafeCastLibTest:testSafeCastTo120(uint256) (runs: 256, μ: 2735, ~: 2735) +SafeCastLibTest:testSafeCastTo128() (gas: 516) +SafeCastLibTest:testSafeCastTo128(uint256) (runs: 256, μ: 2735, ~: 2735) +SafeCastLibTest:testSafeCastTo136() (gas: 470) +SafeCastLibTest:testSafeCastTo136(uint256) (runs: 256, μ: 2757, ~: 2757) +SafeCastLibTest:testSafeCastTo144() (gas: 514) +SafeCastLibTest:testSafeCastTo144(uint256) (runs: 256, μ: 2798, ~: 2798) +SafeCastLibTest:testSafeCastTo152() (gas: 494) +SafeCastLibTest:testSafeCastTo152(uint256) (runs: 256, μ: 2734, ~: 2734) +SafeCastLibTest:testSafeCastTo16() (gas: 469) +SafeCastLibTest:testSafeCastTo16(uint256) (runs: 256, μ: 2779, ~: 2779) +SafeCastLibTest:testSafeCastTo160() (gas: 491) +SafeCastLibTest:testSafeCastTo160(uint256) (runs: 256, μ: 2775, ~: 2775) +SafeCastLibTest:testSafeCastTo168() (gas: 494) +SafeCastLibTest:testSafeCastTo168(uint256) (runs: 256, μ: 2799, ~: 2799) +SafeCastLibTest:testSafeCastTo176() (gas: 493) +SafeCastLibTest:testSafeCastTo176(uint256) (runs: 256, μ: 2734, ~: 2734) +SafeCastLibTest:testSafeCastTo184() (gas: 513) +SafeCastLibTest:testSafeCastTo184(uint256) (runs: 256, μ: 2801, ~: 2801) +SafeCastLibTest:testSafeCastTo192() (gas: 494) +SafeCastLibTest:testSafeCastTo192(uint256) (runs: 256, μ: 2734, ~: 2734) +SafeCastLibTest:testSafeCastTo200() (gas: 470) +SafeCastLibTest:testSafeCastTo200(uint256) (runs: 256, μ: 2734, ~: 2734) +SafeCastLibTest:testSafeCastTo208() (gas: 472) +SafeCastLibTest:testSafeCastTo208(uint256) (runs: 256, μ: 2756, ~: 2756) +SafeCastLibTest:testSafeCastTo216() (gas: 493) +SafeCastLibTest:testSafeCastTo216(uint256) (runs: 256, μ: 2777, ~: 2777) +SafeCastLibTest:testSafeCastTo224() (gas: 469) +SafeCastLibTest:testSafeCastTo224(uint256) (runs: 256, μ: 2733, ~: 2733) +SafeCastLibTest:testSafeCastTo232() (gas: 492) +SafeCastLibTest:testSafeCastTo232(uint256) (runs: 256, μ: 2735, ~: 2735) +SafeCastLibTest:testSafeCastTo24() (gas: 515) +SafeCastLibTest:testSafeCastTo24(uint256) (runs: 256, μ: 2733, ~: 2733) +SafeCastLibTest:testSafeCastTo240() (gas: 513) +SafeCastLibTest:testSafeCastTo240(uint256) (runs: 256, μ: 2800, ~: 2800) +SafeCastLibTest:testSafeCastTo248() (gas: 472) +SafeCastLibTest:testSafeCastTo248(uint256) (runs: 256, μ: 2777, ~: 2777) +SafeCastLibTest:testSafeCastTo32() (gas: 516) +SafeCastLibTest:testSafeCastTo32(uint256) (runs: 256, μ: 2777, ~: 2777) +SafeCastLibTest:testSafeCastTo40() (gas: 517) +SafeCastLibTest:testSafeCastTo40(uint256) (runs: 256, μ: 2756, ~: 2756) +SafeCastLibTest:testSafeCastTo48() (gas: 469) +SafeCastLibTest:testSafeCastTo48(uint256) (runs: 256, μ: 2778, ~: 2778) +SafeCastLibTest:testSafeCastTo56() (gas: 470) +SafeCastLibTest:testSafeCastTo56(uint256) (runs: 256, μ: 2801, ~: 2801) +SafeCastLibTest:testSafeCastTo64() (gas: 537) +SafeCastLibTest:testSafeCastTo64(uint256) (runs: 256, μ: 2799, ~: 2799) +SafeCastLibTest:testSafeCastTo72(uint256) (runs: 256, μ: 2798, ~: 2798) +SafeCastLibTest:testSafeCastTo8() (gas: 513) +SafeCastLibTest:testSafeCastTo8(uint256) (runs: 256, μ: 2755, ~: 2755) +SafeCastLibTest:testSafeCastTo80(uint256) (runs: 256, μ: 2736, ~: 2736) +SafeCastLibTest:testSafeCastTo88(uint256) (runs: 256, μ: 2755, ~: 2755) +SafeCastLibTest:testSafeCastTo96() (gas: 536) +SafeCastLibTest:testSafeCastTo96(uint256) (runs: 256, μ: 2800, ~: 2800) +SafeTransferLibTest:testApproveWithGarbage(address,uint256,bytes,bytes) (runs: 256, μ: 2664, ~: 2231) +SafeTransferLibTest:testApproveWithMissingReturn() (gas: 30757) +SafeTransferLibTest:testApproveWithMissingReturn(address,uint256,bytes) (runs: 256, μ: 30334, ~: 31572) +SafeTransferLibTest:testApproveWithNonContract() (gas: 3041) +SafeTransferLibTest:testApproveWithNonContract(address,address,uint256,bytes) (runs: 256, μ: 4127, ~: 4123) +SafeTransferLibTest:testApproveWithReturnsTooMuch() (gas: 31140) +SafeTransferLibTest:testApproveWithReturnsTooMuch(address,uint256,bytes) (runs: 256, μ: 30802, ~: 32040) +SafeTransferLibTest:testApproveWithStandardERC20() (gas: 30888) +SafeTransferLibTest:testApproveWithStandardERC20(address,uint256,bytes) (runs: 256, μ: 30528, ~: 31766) +SafeTransferLibTest:testFailApproveWithGarbage(address,uint256,bytes,bytes) (runs: 256, μ: 84443, ~: 77915) +SafeTransferLibTest:testFailApproveWithReturnsFalse() (gas: 5633) +SafeTransferLibTest:testFailApproveWithReturnsFalse(address,uint256,bytes) (runs: 256, μ: 6486, ~: 6481) +SafeTransferLibTest:testFailApproveWithReturnsTooLittle() (gas: 5574) +SafeTransferLibTest:testFailApproveWithReturnsTooLittle(address,uint256,bytes) (runs: 256, μ: 6450, ~: 6445) +SafeTransferLibTest:testFailApproveWithReturnsTwo(address,uint256,bytes) (runs: 256, μ: 6458, ~: 6453) +SafeTransferLibTest:testFailApproveWithReverting() (gas: 5508) +SafeTransferLibTest:testFailApproveWithReverting(address,uint256,bytes) (runs: 256, μ: 6409, ~: 6404) +SafeTransferLibTest:testFailTransferETHToContractWithoutFallback() (gas: 7244) +SafeTransferLibTest:testFailTransferETHToContractWithoutFallback(uint256,bytes) (runs: 256, μ: 7758, ~: 8055) +SafeTransferLibTest:testFailTransferFromWithGarbage(address,address,uint256,bytes,bytes) (runs: 256, μ: 123254, ~: 117413) +SafeTransferLibTest:testFailTransferFromWithReturnsFalse() (gas: 13675) +SafeTransferLibTest:testFailTransferFromWithReturnsFalse(address,address,uint256,bytes) (runs: 256, μ: 14605, ~: 14600) +SafeTransferLibTest:testFailTransferFromWithReturnsTooLittle() (gas: 13556) +SafeTransferLibTest:testFailTransferFromWithReturnsTooLittle(address,address,uint256,bytes) (runs: 256, μ: 14464, ~: 14459) +SafeTransferLibTest:testFailTransferFromWithReturnsTwo(address,address,uint256,bytes) (runs: 256, μ: 14571, ~: 14566) +SafeTransferLibTest:testFailTransferFromWithReverting() (gas: 9757) +SafeTransferLibTest:testFailTransferFromWithReverting(address,address,uint256,bytes) (runs: 256, μ: 10685, ~: 10680) +SafeTransferLibTest:testFailTransferWithGarbage(address,uint256,bytes,bytes) (runs: 256, μ: 90366, ~: 83995) +SafeTransferLibTest:testFailTransferWithReturnsFalse() (gas: 8538) +SafeTransferLibTest:testFailTransferWithReturnsFalse(address,uint256,bytes) (runs: 256, μ: 9457, ~: 9452) +SafeTransferLibTest:testFailTransferWithReturnsTooLittle() (gas: 8544) +SafeTransferLibTest:testFailTransferWithReturnsTooLittle(address,uint256,bytes) (runs: 256, μ: 9397, ~: 9392) +SafeTransferLibTest:testFailTransferWithReturnsTwo(address,uint256,bytes) (runs: 256, μ: 9384, ~: 9379) +SafeTransferLibTest:testFailTransferWithReverting() (gas: 8500) +SafeTransferLibTest:testFailTransferWithReverting(address,uint256,bytes) (runs: 256, μ: 9356, ~: 9351) +SafeTransferLibTest:testTransferETH() (gas: 34592) +SafeTransferLibTest:testTransferETH(address,uint256,bytes) (runs: 256, μ: 35865, ~: 37975) +SafeTransferLibTest:testTransferFromWithGarbage(address,address,uint256,bytes,bytes) (runs: 256, μ: 2907, ~: 2247) +SafeTransferLibTest:testTransferFromWithMissingReturn() (gas: 49196) +SafeTransferLibTest:testTransferFromWithMissingReturn(address,address,uint256,bytes) (runs: 256, μ: 48365, ~: 49607) +SafeTransferLibTest:testTransferFromWithNonContract() (gas: 3047) +SafeTransferLibTest:testTransferFromWithNonContract(address,address,address,uint256,bytes) (runs: 256, μ: 4233, ~: 4240) +SafeTransferLibTest:testTransferFromWithReturnsTooMuch() (gas: 49820) +SafeTransferLibTest:testTransferFromWithReturnsTooMuch(address,address,uint256,bytes) (runs: 256, μ: 49012, ~: 50246) +SafeTransferLibTest:testTransferFromWithStandardERC20() (gas: 47612) +SafeTransferLibTest:testTransferFromWithStandardERC20(address,address,uint256,bytes) (runs: 256, μ: 46796, ~: 48058) +SafeTransferLibTest:testTransferWithGarbage(address,uint256,bytes,bytes) (runs: 256, μ: 2620, ~: 2187) +SafeTransferLibTest:testTransferWithMissingReturn() (gas: 36672) +SafeTransferLibTest:testTransferWithMissingReturn(address,uint256,bytes) (runs: 256, μ: 36007, ~: 37552) +SafeTransferLibTest:testTransferWithNonContract() (gas: 3018) +SafeTransferLibTest:testTransferWithNonContract(address,address,uint256,bytes) (runs: 256, μ: 4191, ~: 4187) +SafeTransferLibTest:testTransferWithReturnsTooMuch() (gas: 37118) +SafeTransferLibTest:testTransferWithReturnsTooMuch(address,uint256,bytes) (runs: 256, μ: 36410, ~: 37955) +SafeTransferLibTest:testTransferWithStandardERC20() (gas: 36702) +SafeTransferLibTest:testTransferWithStandardERC20(address,uint256,bytes) (runs: 256, μ: 36060, ~: 37605) +SignedWadMathTest:testFailWadDivOverflow(int256,int256) (runs: 256, μ: 348, ~: 329) +SignedWadMathTest:testFailWadDivZeroDenominator(int256) (runs: 256, μ: 296, ~: 296) +SignedWadMathTest:testFailWadMulEdgeCase() (gas: 286) +SignedWadMathTest:testFailWadMulEdgeCase2() (gas: 309) +SignedWadMathTest:testFailWadMulOverflow(int256,int256) (runs: 256, μ: 354, ~: 319) +SignedWadMathTest:testWadDiv(uint256,uint256,bool,bool) (runs: 256, μ: 5696, ~: 5664) +SignedWadMathTest:testWadMul(uint256,uint256,bool,bool) (runs: 256, μ: 5744, ~: 5712) +WETHInvariants:invariantTotalSupplyEqualsBalance() (runs: 256, calls: 3840, reverts: 1929) +WETHTest:testDeposit() (gas: 63535) +WETHTest:testDeposit(uint256) (runs: 256, μ: 62792, ~: 65880) +WETHTest:testFallbackDeposit() (gas: 63249) +WETHTest:testFallbackDeposit(uint256) (runs: 256, μ: 62516, ~: 65604) +WETHTest:testPartialWithdraw() (gas: 73281) +WETHTest:testWithdraw() (gas: 54360) +WETHTest:testWithdraw(uint256,uint256) (runs: 256, μ: 75443, ~: 78076) \ No newline at end of file diff --git a/lib/solmate/.gitattributes b/lib/solmate/.gitattributes new file mode 100644 index 0000000..7c5f3db --- /dev/null +++ b/lib/solmate/.gitattributes @@ -0,0 +1 @@ +.gas-snapshot linguist-language=Julia \ No newline at end of file diff --git a/lib/solmate/.github/pull_request_template.md b/lib/solmate/.github/pull_request_template.md new file mode 100644 index 0000000..5cca391 --- /dev/null +++ b/lib/solmate/.github/pull_request_template.md @@ -0,0 +1,13 @@ +## Description + +Describe the changes made in your pull request here. + +## Checklist + +Ensure you completed **all of the steps** below before submitting your pull request: + +- [ ] Ran `forge snapshot`? +- [ ] Ran `npm run lint`? +- [ ] Ran `forge test`? + +_Pull requests with an incomplete checklist will be thrown out._ diff --git a/lib/solmate/.github/workflows/tests.yml b/lib/solmate/.github/workflows/tests.yml new file mode 100644 index 0000000..2a29890 --- /dev/null +++ b/lib/solmate/.github/workflows/tests.yml @@ -0,0 +1,29 @@ +name: Tests + +on: [push, pull_request] + +jobs: + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Install dependencies + run: forge install + + - name: Check contract sizes + run: forge build --sizes + + - name: Check gas snapshots + run: forge snapshot --check + + - name: Run tests + run: forge test + env: + # Only fuzz intensely if we're running this action on a push to main or for a PR going into main: + FOUNDRY_PROFILE: ${{ (github.ref == 'refs/heads/main' || github.base_ref == 'main') && 'intense' }} diff --git a/lib/solmate/.gitignore b/lib/solmate/.gitignore new file mode 100644 index 0000000..5dfe93f --- /dev/null +++ b/lib/solmate/.gitignore @@ -0,0 +1,3 @@ +/cache +/node_modules +/out \ No newline at end of file diff --git a/lib/solmate/.gitmodules b/lib/solmate/.gitmodules new file mode 100644 index 0000000..e124719 --- /dev/null +++ b/lib/solmate/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ds-test"] + path = lib/ds-test + url = https://github.com/dapphub/ds-test diff --git a/lib/solmate/.prettierignore b/lib/solmate/.prettierignore new file mode 100644 index 0000000..7951405 --- /dev/null +++ b/lib/solmate/.prettierignore @@ -0,0 +1 @@ +lib \ No newline at end of file diff --git a/lib/solmate/.prettierrc b/lib/solmate/.prettierrc new file mode 100644 index 0000000..15ae8a7 --- /dev/null +++ b/lib/solmate/.prettierrc @@ -0,0 +1,14 @@ +{ + "tabWidth": 2, + "printWidth": 100, + + "overrides": [ + { + "files": "*.sol", + "options": { + "tabWidth": 4, + "printWidth": 120 + } + } + ] +} diff --git a/lib/solmate/LICENSE b/lib/solmate/LICENSE new file mode 100644 index 0000000..29ebfa5 --- /dev/null +++ b/lib/solmate/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/lib/solmate/README.md b/lib/solmate/README.md new file mode 100644 index 0000000..87fda96 --- /dev/null +++ b/lib/solmate/README.md @@ -0,0 +1,70 @@ +# solmate + +**Modern**, **opinionated**, and **gas optimized** building blocks for **smart contract development**. + +## Contracts + +```ml +auth +├─ Owned — "Simple single owner authorization" +├─ Auth — "Flexible and updatable auth pattern" +├─ authorities +│ ├─ RolesAuthority — "Role based Authority that supports up to 256 roles" +│ ├─ MultiRolesAuthority — "Flexible and target agnostic role based Authority" +mixins +├─ ERC4626 — "Minimal ERC4626 tokenized Vault implementation" +tokens +├─ WETH — "Minimalist and modern Wrapped Ether implementation" +├─ ERC20 — "Modern and gas efficient ERC20 + EIP-2612 implementation" +├─ ERC721 — "Modern, minimalist, and gas efficient ERC721 implementation" +├─ ERC1155 — "Minimalist and gas efficient standard ERC1155 implementation" +├─ ERC6909 — "Minimalist and gas efficient standard ERC6909 implementation" +utils +├─ SSTORE2 — "Library for cheaper reads and writes to persistent storage" +├─ CREATE3 — "Deploy to deterministic addresses without an initcode factor" +├─ LibString — "Library for creating string representations of uint values" +├─ SafeCastLib — "Safe unsigned integer casting lib that reverts on overflow" +├─ SignedWadMath — "Signed integer 18 decimal fixed point arithmetic library" +├─ MerkleProofLib — "Efficient merkle tree inclusion proof verification library" +├─ ReentrancyGuard — "Gas optimized reentrancy protection for smart contracts" +├─ FixedPointMathLib — "Arithmetic library with operations for fixed-point numbers" +├─ Bytes32AddressLib — "Library for converting between addresses and bytes32 values" +├─ SafeTransferLib — "Safe ERC20/ETH transfer lib that handles missing return values" +``` + +## Safety + +This is **experimental software** and is provided on an "as is" and "as available" basis. + +While each [major release has been audited](audits), these contracts are **not designed with user safety** in mind: + +- There are implicit invariants these contracts expect to hold. +- **You can easily shoot yourself in the foot if you're not careful.** +- You should thoroughly read each contract you plan to use top to bottom. + +We **do not give any warranties** and **will not be liable for any loss** incurred through any use of this codebase. + +## Installation + +To install with [**Foundry**](https://github.com/gakonst/foundry): + +```sh +forge install transmissions11/solmate +``` + +To install with [**Hardhat**](https://github.com/nomiclabs/hardhat) or [**Truffle**](https://github.com/trufflesuite/truffle): + +```sh +npm install solmate +``` + +## Acknowledgements + +These contracts were inspired by or directly modified from many sources, primarily: + +- [Gnosis](https://github.com/gnosis/gp-v2-contracts) +- [Uniswap](https://github.com/Uniswap/uniswap-lib) +- [Dappsys](https://github.com/dapphub/dappsys) +- [Dappsys V2](https://github.com/dapp-org/dappsys-v2) +- [0xSequence](https://github.com/0xSequence) +- [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts) diff --git a/lib/solmate/audits/v6-Fixed-Point-Solutions.pdf b/lib/solmate/audits/v6-Fixed-Point-Solutions.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5c4243425bf4fdaef1dcd87eceb2365ba97bd6f0 GIT binary patch literal 170456 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 ?uKH_LBG3w}|gz7C!T-OPS2=2wL82qXf;9 z-OHdUsT98T^w0O!Maa4)<%kF3f@jRi<9;^m%d)FsPf}g0U}uK)C@Z?rBgui3^IdJh76YQ@3#G`FDpUYl+;u)Kr?wF{~nb?4r9<&Ngvu8(~?}IUILEe0!H2 z8kz*OIm2hFFbp~w~r&JcPbEv8z01k)7qp*}*d}WOA(F{rT zvooBeNfEhLEiFMco!lSG#zv^{7VUcW?xoCngTM66wDO#xhvG6=`JO7AEBd6K&2RIo)@cV=2(#P;=EhEsU`(gsNBAPpB7LqRZmmc@)vMNj z%x&WkwwaE+E8E!5%4b`U>Z?KKA>X?BY4~DSkgI-s_yU zRqfQGzy_sU+27g~RS^P{p_x8m_;&2$fP?0jXWLRT&+qa@lp@Fbk7uDweL-KbFJW*& z$?C@j&&xi^WQwGxc=w`V{utT@+t{VqPK6Q$%*BJFEGUG`3s{GJY$4k=C5+sMIFPvR z8Gz3@ZhNmR9ueb0TO(KCJ^w=Vby`kv+s~O)7d!YHOi4TXn=%Z0EnP~78%tz#e$a@4 zD#{8@6HbYcX^c&v2mH_ z`rlJ$iDDTW{v?%(mW#r}-IR^RSKgp$16FIARxIZQVRAJ~#jAQGz&#IhAw2h9I}$tP zz3jKVpYaSfQeo1ViK%+Q=%3|SIgLvrPXSrxgQN1g`g&yRY2B?aX&q>$Mo`&(OhF}E zZQnw$oP&TYxcs#mIz?vGuO$n{MKMLk|nNfLBSlj^|p+ghz0KgN2P z5a_|L1kGC67uXA7pJ`<22|Vo0zoz_C`gx|N! z_JJhR0W1ZfvcH;K@i0;vNA_E2KVje>zrEDhg`BeJ1OGqj-a4$Rb#415r5gkU>F%5~ z0@A5;cPibjAl)6(-JQ}6lF}t1-7P8b4c6Z8R@eTX{qDV8@3GeN&p14Qsm^;|;~qEH z?>f)(Wv9g#a*GdgYpP-)Cu?nO0TLy0yUCbNR?q)v8%ly3; z?M{kp)|n7BPpg&%1$Sd-YI>Z-sO;BdpPrRSpvlY0WqrcEa3Mb1(!}Tu_sA`Y$i>Sm z!2Z-3(HU#nFyDJ_ly!g-ZP=kyvv8y136_l&H3r&9g?`Pwfub?Pc?&VrpkorJI@AT4 zM|$+!rVMp2;1Ir2WEYLL5ghG;HJrZj-cGRxbDULUKuDI)ruMOH1qnmWAg(kBTC3Z)H%0#^g@s44W6Q6`eDC zf=v{Elx#GFqQ<-E3VBwYsx@pwwApDx+!OAVKc11fte+WUihPr2nf|4!;9iFs#v?)V znJc_ca}ABKNlMI-r((B{D$TT~=E$l+CN*QDo0@ENwB5}WJGEAir>its?^n6*PU&v$ z=u$ryS82BO$u5S@iP6|E4L5}2ibYGlQ3CW@F zD{nqNtE)B9#hWjgkM#d}(u3^}A)_EbWXA7G;2C83-WJOu&@GA1<`}kJ!im z?cM)64gF4lfR;Z%fY_M-E;Icb7G?zq5C|Ar_*41E-~H|pq10v%G5(MJOge`h6rosNDl4HjVJ z3D6jFJ_H2(A2|4+!eruL`f~>-{zYZ{4weEVTz^1i0LpI$P9Sjw5HtRxGJxHZ0m#T; z`*V5uf3On2PD_8NjEA`}KveldVX!=mg>eA3kAKxY1E8EgKSO>Uo<0l`0Q{5#khucG zMZhc#Co3>m0AwRPOjiN-&HtLE_%~rH@UZ0g+4oW{Y^@&cc0^$fdhkmNn4eea&cRi! z7DqWBB+da!_#sL{zl@@!+=>Eo>~=*13_DUmmoA+l9inJ{*5I4_^po(2vtz4g$oKpK z%d&E1_ai8i6*o8WY2ll1zMb!W$x9nLp1#L#xOjP$6*Wxw=B5`&2}nB>g>ATD3@6T1 z=)Dso*gKGTRv4#j`a0*M0Vlcr*;HQER0q{Q5l)Wuok~D|avM3uV8yptL43YFFIP(W z5D7nC{V|ePCWZtP!CNVy$KI37j;E4=!t!dAnQRhHS!&ewQ550%-quy7bG+oSE3xz^ z{g1i2L_`W?{DWmX#7&Az+SWU$_Z>Lnp7HRCqPSUG5&EaKY#wJFaodE%1AY?jY0VvjWPT4{%};qW;VABG{zcd9!2oX!?@F zF9>B2d3$-i2Bva@_8DmhQ(LCu3~(*LgVvMq@M2keux>(Xbqf&T)WUq1h=x(%=#&b{ ztryWL6fNZ!9vNr4`E7I;`ozK&cbW)efhDTVId*$rb}+^UD@xm$o0`Oh^i3u4v66gd z?eN1?Vk%IPb4gQyqUU)U}(V>n`iuFs+7a6e^N58rj)Y2A?u9 z&RY@=7yR}(m3I;YI6``of>AjBQ#{%NmY(3D1^Hx`5QiWf?x-{@Udo8Z;SK~f zXhB^9hC@?Qs7N~GBk@=2qBV)BC3T)pT2COEK7m<-Lawn7mmyJ7TO;418H0cGgcup+ zMf(i9?7eA?&m_n8hVu^FG8L8~o6;5eF>Eqr2f}D?gl$v=5rkJKAyJ>WZ6uUeq7Wh- z7xD)dqD{2kPh);=SxKx8-sm59aB6GqBd{PW;Ol9hw}#eIm!G$s^!1x+7KBHH^;8LI z3RU?UOYvw?McTYM#So402D~THKq*LP=5Q|aW04IanWDKv5C{~oKH9~w;F?ZFk&IOz zG%$0H<}PuHnlq2_8B(*+Ui#57*fg<-B9p2cN|`6BXek}+%OB+tbkWDWIE(MDKJ~>#H77<2cy*rjf zjrM&ScyV9~ygtKNmTj@xrt|PgM6LbSx~($rqV&Bj{Gr=jdbV5S3W{ zr=O1#4^Bu=Uddg=%>ZKSVp=`?P!ozuH0P7_*_CA@9(IZ)Rl$ySDK@Q3Xzjyl=gzmQ ztPaq%nx=7OOmjqti&Gh$xxA1?AhATr%2v6mELlwW&KyZ}zx3B+86g4b>DcfaNUF>@ zuw8F;6;XN1^j|z37WZm`gnhT4uKPU2#Dw>S2>IB010Gb_>zD@2hZ>0-uVD6xxmu zO=L`iOXp|q@uG*Vx2`~%Vd@_psjlqa?0b0&V;kzG0ILqU(i%(wRFbVQn_aNK66(=QyI>D{5SoDNB zj~h}}Di^H_vE<|b)I=h5(~9+C17rVkl_Ot1y=3};&Km^7l%s3@e#B9=?{(S{hYCKt z(0pM0c3iJ{8u|{m4&HWn?@c3nm^Sn>76lZcQ~pc3H247a&iCPn;G$&}ZKzYlOza4o zx*TAMf>gd(eq7=eXH`fGiZ8~OohUJH%*4x55+_6I3UiY66I%^sxcR3HABB)##0fU~ z^!X`Ijp16msJyvWR?s;T3U+QNd6QF#$@~oYrB;D^&6Cs0=nPd@oxC(1%+bq>Ruu#s2TveUUvn53cQJ^h@ERyEw~%1&RgAMpeY`^XR% zIFoB~W7~WXIGwIRt0Ix?cC;<}7P;P`F|JeDllJ+5V(CpLqhI|9-K5higIEY4y&?jrev=_4ajofQ)h zkzVDqRGMQAM#kYS+GDunS0{Hw_U7{`u178|O-bS~PEQ_*EZ0I$;-dSrCFCh+Gwug1~Did@qj+X@cUf&Fld|`1;e8Fp6AM0#`|<9nPge!8E5% z0v#VSJftAXlR!GRJGfPxZ)jv4Pf}byWy+NiJ9h;RZ=$jvg&JMkBfNYU7C+qU|8{mQ z^hJur6pIMVD?dLo7TPi0R*;?l7NA6kgv5v(wp$7J1BpZTI#H-LLa^d5)TC&k62lUf zAcRwu=QK+7D$}So9cDf%>8m&46%gW$+s#KobojDWS`mPSyZ zm)MW%4H&N_FJsZ|1_lQ3Cl;isJuk8IS~zxxfxZs;V0nD8P6^XC!0r65&^9;ZU0al= zkxiE#;Gy>noC=w$44zQ8Uh-tv)@u62I=Bfuc4?at1FAgcx7$_*P#tE8gP^7Wnn+b# z;e=K{6{A?(mXIMf3f$4>hEk&H*J}FKWfLHSCB8=aBnOGLW)>@z{Xxf5B;Atq6ldB- zO$9-tR2CNlSq3Y7*RscTD#7zb-IG3b7q4vGYB(*wHLHLArd_KNtnq$3SUDI{S-!kO znDn+sWbrZ-mxj4k^K($4wYY*_PMa(|PsEGOc0*1dLY=~}G9xh3h%@sq*}CgogA{X7 zZm+=kFsYR70+T?-@lttl7wYA8kdWhzbyZChPF5xtj*dTG6s&q3wx`-Zlq5OrEe;>- z1DCUG-Qxr|s^&m4h~es)YqL?cK)4sz#olE+vfy)zEF8nT`{mm9*xm-a=^As}K4h+VpQ%i)#Wgf-#HIQYxoeNbP=hI*yErF00 z{=qo;&1PnTT}Q0da#^26yr!U5k@XJxQu9vk&TsqY{g#qF2(Ocmv0~*4gWmET%n{KS zG6g_k(P)ik=pl8g?5}iJMU*9YtrIYL1P86kML3ml+L)AHLrT$K@=lxYo7)B_Oq%ef z9IsCp2fYcF26v89M=jCUUFC(@x69^P{S7#n zJ9KWKlOSCCeM71C1+X=nVtJ7ziH4B5L#?3`qCQAZY2=3FRa(a_A7q5rBg6{mwY>Re zR=N0`Xr(qEwk%`p^+X%aR-5j*EaY8gV@)J1Zdh)^yGQYqkuBAXP##?qp@FZ^7MGj! zoPv0HUH5gbR#E&3Cgsc3@O{df2jWG#C1H$?M>SkzTt;XxP*0G}p6c=*lk3a|fcaRP zRknB49&xh-5EO?M2l9Isdbt*Per3xWxWh5J$($w8UR2eKilf(f+=Sb9DX4KHxWKj; zX))9Ae&pL`tYl*&5)zNn%2|w~gFE3`mx>5`EiAc`OOJzC2F^4!ED#y`VPKj z_-LY&$2riamgLD3W%}`Q4paHwBteB@W2acbo zv+nRq4jHoFgv>++-fT22wLu7?rCy47a46wAgq}oSw!0@EphBF_hQZx>1J{Fgzv;Ek!0XMh_rn6{1VFG4JLl{bwaf)Lk<|l(9S-;&v>m zxBUF1BASSot(DP+;Bn2$i{@>GYdn?n2jM_r8HUfJpH8Z(saslOs78^jroi^p2R(jQ zKa8+)L@9qG%0pkQGR|K!Vz{2;&DwRlcTA}ohDvdelFGCK3)PZLp}I7PI`z>@Dp*^P z9!<00jPeqSx-$LDt0Jb_nt07-E;eGNZVIc(C2+D*m4@a?>J4dWLpjUdtnVnTm5^+cIX&i`K*6s z2K$ite4022GQPh= zJZU9+VN~_cFoONpVFWWX&~XJli1COxfUf*+-e5#*AV9bUe1`}K;QbF;DTY=Cb`Nc0 zGea|b7jr#Jli$qFj4T-)fd&mQ?9OOrX>Vj}sRx9inCrP%IoRu%S?X9ASy;j19RA zxVS(DMn-@Yo1T#Y2yl<%WaTnu2N?jqdPaIb57vYJNVotbc|Nqyfnc5Q9b|T(W5xmk zki&oQk^aAu68{v2!~V0p1oVeM1$F?hFoC!L$OL2_Gcd8TvOmB!AYK~aO@FTD?C-7P zALD?2zXHDw6Ta6z8xz2k0I>}hU<1enD9xBSSOHNnaMyGEu|4$Pt4jbQO^|^htAQ~G zr!gBVVA#q80{qeD_hvaOz?A^uN*z@--@_{V@T1>9L!Upj_Ey>TOzkpZ3A5k8_ zvk*{wJ;*ZuQ63Lm36N#7|GD!Bf7>ko&9(R=)%y>8>7N9e0AKp^1)BeINw}DQVr_tz z$RAN2z;lxe1o#&GSRQP^=E@9Ux4*z?;(sWQ->n75ub(J?*gb#;2^-)=4p?>k1JOU2 z>oNhxKn8dRKwhw;=O8;-J#Sh2Meu~@*07|0+LSlXn$hUr+pg#fIG4cyYAFHxfQAOycf4BbO!G-xcyONq%Bu=BCj zI)azQn^y#N>o2I%y?X6EkdK<}TQ9xi$ECEuO&9?G?T z+d&3otp(d76a*p2$49-bsh)1vyF;)a38ZQIuXV##i|_}(T#G$D&CPk{%tEufx>b8e z-xY({Q87oOl}SzC-yovqBpNE1SX?4iGx>Pk-g=QxT9NC~E^pXDwL*6cNs8|UjmExE z>2sG7^U+dd(A{m2M(VYl z@*+3S*CgiToz&y@_l;CWH3jby@U51wu3H&Ym%im@VrvagjjYCm6~B3O_HBPVzU*t3 zvEc5r?IR$m&n}jtKQ9VM5#7%U1AZ>S+ZAy13Dn|wp!u8o1x7-4+ol6<^=6dUp6 z{yJVFmlVmpG=|h>;I^oMPj!0d=nH|M(-41BT-yDkK;7}6v1_7Azg+rt^82qdFI7kY zy=tRl(+ij(oSMXZlY~GhssPbt6osmBE`_@jxh-;{y+u2a?X)txs=D;{@o;QZK zrmyQRi$^k?D*AFuq9X8O)eurzTtKQfGeBuIXm0h2?bw){*?88ecf^X4e5%%S<(V#7tln0lH2jBP()L})zX;xVyr zQHa#@*Ma6<$-U#KRb(tUi5#?kLQ|w!!Fo{4B5_plDjko_0xBQnwPR94;Un=ds~kgN zZ#Nsgx2>5=GCtQYZFPD(uDsFixPd3@rKvr(DTEPZQO9;Ch%%bmF2F_-65t4%L5UED zie#=$N`l|Ks4rxbwN;XanQ4ka-eOJf--OIdr@y zq{Y=f?FhB#YAbqdFkc_3JLy|c)M8Q?@;w3JC`J}>$$ty3ePKn0o}qs#O<)uSW8XEt zoRHwmJUooGCz==gF+;tvu93NTDfFPaU$iKqS;o`L-+p5?GR)Cwf!h@u9*G;#0X3wk z>3z&|iJ}H=hht;7x5w&hkQ!iS#vLXZR@EKS*j8`%FWrR}E1{C$PAqNob!}_JXLf2Jr#i!I(UpbCLyhXek!fe6+|U+YHZH@ zDSW`6*gd|k?pu#j0T&RF^qMqb$oild7~YddLq z!bzg<`{F5XxQ<#Z?>E z{v$f|$yUH@cWg46v&jDoC8&;N!3}#%U?8>~6#gj{&haf{{!<%=NNWeEn?Vf&z7-cH zZIjBzeoG(_>k!bUU{g}PR5LJm;v)r3nlc$=7}UZikl#qG0%eI5l~_S@p?$061S0i@ z*EW%vDD-}%>w?J7rNL~FhWbJKv31I}PsnE%LJBO0FsXtWqXv=k^9-ueYLv2<~lP88ERr~8{4L@G9)}k<$gXk?yhZkz69!5itkzwSq zjxDWt5*w0|FjWGXmMm_zY`5PWWjCX?_5R>% ze}W9DH>}6lGI2{J#FHFPs{0x1 zsWYz$)U{}#5Lm=sLR7;Q%@v|HOcSt|Qut!^tk&y!VV4%Xxju6WZMI&4m67D+*n?v{ z)QI3u>1@!!XrZa)w*+j(8b34Vsaov6?wySV^>e(}WUP2PEVw|7$=~UGTSWT)b8PS? ztH7%bSjck$hJJGFZ*ir1B=Q3zlcN?IXlQMu*Zw@NYDK16gI7w!TY&Dw=JL6`WZghS zB!yH-J?YoCn$+4zF(mfISGfoS+hSDE3}}G6C~@l=Q48f|8+#fC%J5^OLRB?Xw{HN9 zKs)Kh&bEWwTLmsa>G?DX_}h zwd#}6;!2m{7VZIl9lDzlU2Q{xub|5D(|j!I_IT;W0kvgk+rb=Uf29u@@vrl;lo&wS z=5uJR$%0Cc#>}iy+&&#>FJGil_9oWQ6>ao^wxMTvR}9bUYAE{ZqbX4(IS5zDl-29C z);XZJ7nd3bi*Bt8RXlZ2kVcI*hlV-OyXlW$Rr2we<;*D|l*R3iO9rr1($_adobf4p zB`x&=24;|X!h)}Da4$MTD{84 z@W#?1dz0n|ZOQ$?SlvcXvq=ebcG*4sS=l-GnIDN7S}N)d*$HP`3Qzg2*vZfB%ngk}dmNg$W@ot;$_2YbIj#hZ!(J5Ex*lfwoJQ1Jw+&~vByrj7ZiIDO zcr=M%T-}!$M(j?SP&pMuw*sCuX)dTA+ymX4^2Wfks@IC6^7T5F3%ko9%b3s%>0m@M z-#)gy2Jy|v4o~jm?ba?HwY0L)P`4bmcHE#Q$=a^hWxfiZk#!EQh!^|ZC1$>z`Bkf8 z1G?!dL&)(W1;f4yr8^dBR2)@>26H!rT;3>wAEa1fDp?^>(IulJuP$oN*_6Wwa%uqkld-kXSi`(UEoR_X>e@> z{vw~6`gNyvpE;x9`Fl9*XGX-VP2gTnRqZ4-M-ar`f0$*$hkLE4w@z2RWKG3f``HVt ztsIiDwvEx+dxgWLYnP_9p+`qI)vJjnF^1?Hcq&Kx&@*IkxKM_sYS)*@V?xFsCN?k^ zQhW!m!}C4favR4hgl;#0Qp6UUXbKV%3R*&2F_{}m80_d**|x5P`AkyAUtVNg8fCeM zOwGEGTq%<-#EGCkmP^Vf^fRg}f0b-?x&))t8izT$6DwZT1*O?oqH<-X#>|pT;(3hQ z7vQj}tZQULN0$n6DV_F6vMzHzi&o@4d0A9A@>%=XR4My(Rf+ecAdJv^;bc3#d1cgF z;R|pDzV#B{z0A3qGuEKYnQbHW04qGMbAgs%NazlimVliYeV+TdTQ@1{K$*_*7QGzd zXS3&sDbr$#Sk@Yaa+SyB!sumty@h8!DEiWXMv^Died-G_0lIecEMKw`VmMSueY}s*FPM&m+p6PY;NPg8hH{ksmLv#r`q+2GW<6 zfBzpj;k-E{#m%D^n<-b%IIKLhwP)aMgo9mgZ3fNhOorOAkkshECDzq5loxdnzQjT&e5Tr+uv5C( zAdIl{XrE?7s|Y8l>ZDfxZc%A4t{)vVT5TP!9osJ#j&{JB7zXjBCBJ;PvNOHTy>TV= zwVgpxV$ey3P0~_(!Cq-m#9d^U5n zP&En*7mx4hSjFh~6%&kr_7#>*4}aH-Z*Y{`5i*7U#;9Qks>-r?TsEqmx6-))zu2LeNCvdO zS2hGzsZ#90?we8r0;MON(8?4Yf*`lF1$mf#70e7Hn{%w^rJ2^(_0-{~uY?avWU;ax zC`Ba~jKOA$B#BM3Rl|(*t#G$L13%-$%M-E|YI)hhG4z_%YfqaVLyq+_-vW0pzBW;} zAETyhy!btRE>nW>yfjhcRmO_hbpzoJY~8qd5?n6td}fNV;#}_54rjBOc9I;?J<7_9 zo4J2RiX6Y*fd7sjejtkM00QI!eslg0k>dZ2Km8s$Fadze(1_WX704U{vFic!jai?G zjf=|&#AV3E#=&gB%*AEM{5$f-@#`)2?~NfK`G|pwlL?qh|K1p42LY|-2jj=TK(Fj4 z^2YMBx{Kr2`|AK}czEA{wCy2n>N|O32O7)(`~1tVz^}K{e<%eOR=~uK^TE#dA3ef{ za6uql4)j;6gx?WJz@hRFXbiG5aRIdLw=A{qmGB^a^KmP#Z9=@k1dzXdu}D$G^W^C2;;k5IBFmYYyxQY=E;h3lJ*_@W+2t0^5V# zITt6}Ux7dVv@5dzZUuh5N&fwj$Oe4ufB`iyjPL`E2ehxuK)&K1xjFv+!T4X%cwl(q zSMPz}*z*HD;`}L3^*1yRsDJ+osN|>5p84k|BImD9Vmzz>2XL?drso9EG6N?I;DZeC z_`iyp^T$o__iz8#PlFF{|F<~|CN5wb06n<>KFs7i%wYh>f&cQ}XL7bPvT-o7G%#Yc zv$MCdHDY1>?HOR9X9rA}0Uq#{_O^Nk_I8XveYPw=o1An0`myi(ea-xUNZElSCNNyX z#>xOh6|(~_t`Cg#k3RPN{?0ZwU^3+3&}U|0Ghkt2;^Ja80OooOS&f0IJ{G|69*{$_ zau^#j|2%BQ`NK)?U&1cnyz)EPWeErm{SI#)ayQo>ayNTYkF_a}@yKSOfy^qW=n0e9B>m{2*&!jHSFU&G_p%8mNuCuHO)Q>Cwx zP?%rku9{<{j2~ot_D!G9uzhT6B5kh7He8!Ldrs&y;rlK<1axdFZBTP;1TV}*xvRU+!rv(O zU$^4x+ihvn5Ku(Rp$x23Ay!=t?jZ-Vl+l1I#F8|q!4+r^_MtkNrZyT>SpMK-5@n7`FkH(|YUi}u&W%5O7Hq4Gnu&b%+ z6JKcH0+(-3qpm{JLbeu`5h90~0!56$Q~_mzoL8^4#4fr!^i$iK=T4_bGHCABMlBpc zX_wh{*Q;{UV%;3Fxbe@|Bao0bBBV{uqu^$$grqK46~buhccHAyhhcMFwYgz%Eo`U4 z&Qol}>JCFFH_{GGH8d8wR`iE6OyFSp&lPWH57e@HUPH~`8FJ$p)>j1UJI`|EoOClu znkS4;qPpeG>Q_=U>WYrp%cv0yXS0Exq!cSTR-a3enGS?yX5sGconxFL0@LKo%*u8A ztWek(I!CGmJq=r`JSv%|S11e(t?OBJ2BXEMOqf|R*`jNxo4&%TZCXskiRC?TRc(rg zx=jk?`)VYsr^8R*XLd$8%I;1pr+SAJ8D|&!TC?je_2!Y=eYM$B8;+)Fta(8`RqwJ> zlY__;;!GF)Hk#oAXTC`USpu+Q#CRpfP)yE%I4Wv@Q~F6gfXZo#_@iODu>F*Ztn~id znv#IC3O8FpUz*c`=`Ww~yC{0&$S3=fo%J*j3&jhwwa@v^yD5NSWS51rT2n|>G$&1x z#Fh5UqRg}mg5A*SXI!{Ef||ivEO0DEa*yh`7q%y#W})q``Qkx@*IDxOiq0LHAIYX#_3zKm)_2hU2kni13_M zW-Y9Mm=!Ha%!iC}HNKT`Zn8z+FXNA_=IR$_s={abmTv-_-ID_~wOB@8!l?14A+|)U zMR2B0^U9{#4agKlt#&00+>xkSDZq1N>?uly50?d=prc$M)o)}WPRbqc!-S9%^tD_L zLQ{qun8{{rQHVXYw_e|l@f)tMiFD-TWk}}wl!60K?!6h{9FrH=<7hHV6~&`MRUdGB zE5aL>seA>$r?bo>Zy-Z|^qij8 zGH)PbR5;e01jTcxcMs;lY7ASF;#Jk&KNIX&DGuOwVt^dK)=p z#a?Sq4x43BK4KnK8joO}OY8l7`BG&B&&APzi2K`jJXfT@Y!5%7!mzNfH5=HBrO;0& zV@U0e*QH%l(SLf-xfDh|31#qH(u%RGCQqd!H%#H_3~Q;4`-i$~+{Cv%(a_rl+JU<# zAKPDuYw|_zbSo9$u<7PAqNL7h@k()Rnt>B?q90OAb>tg;U0{?iI??$A^OA-4BF3#l zyeqc(PTt>T`kCr39^rFU>ls1vkz^+f4%()+!KW1hI&{o56Y=lBi}~B%FF!Yr*xNV? zfm=q~SVV3r(}^h~5ONWqtZQ8KuU{0@<0hd0Tx3!?%r;8RN~7fb+_pMhQLiFcfLa`j z=vlRXod{W~Z^IJmoDX!s-Z4bfVP=A!WISZ5`pACo!1EX^aF}`eYt|F?6F#fZyc^|@ zT?JPL4dBPu)n?`9JIG?a!t(IJmQNS0AwCu}*UO2xF6(3aM!sWAXmF;2dPMB?X+#QT zVVwrLACj`>?K`Z(A_)9C7W)`jQTM zlFg2}A{pr}z0ya-`L(lP5PCL(bc1WFIkHe2d%Ue#SbGba^-ykYA+OOb!3$E+G@^Po z!BF$yHitljI8tlkTb{S-K3&z1GR>aj6e~3?4>G`7*AeM5^yh>yy|m-h^lhq}Qc1FQ zGGk|cJiIH5BE*8!>cWdZDG*OSmoPN|)--??E5fPUuQEs)HFgzD4_5Hl%Mhu)e8O%M zud7`DwiK+(R;LTz*rI}Nk2ztB+hp+M@M;wvI{Gp5kGhqx-xvnJVID5wvS?FJR z7oNYzUH){as?HNPH4>Ji zd+d~MLmxk10v8XR+UexMp|j|zWICNWRwKgk$S_7?1<=)~wW?e9M{OJ1M9jOpOgAFs z#T`-HebJh2;Hx~ws!7VpWLUu;vH`ce_0*N=j&BkByWY1pFEPWUp5K*55Lom>4vXVN^ZY!Pg{NA9)~$7Aiz0jVW@*k^H#Db=Wg+6U~LI>fGa zEyu*Nw*;+Uxu7kC%jq4__Is^7U%pDPf7qAz** zC<3le${-t>EMNXp=K`J-;k<>yw%EH*dmM4kc0+UO(=|1rwwc+4BrKFE8~6GxU((%r zF@p%tGBXS;b{lp0N~sbw$mYG|a_nHx=@&o2(+YKCxu1mM<@u1seKwgO1VZ`zO1U3R z<2p=~Z*d!_#%1^>XVFI=qgb*QqCASn9bmj)bHHD$o`D^vYqS2K(Tf&C|Ay5?Dg;{i zVmaP_#okzkkGHhgN*8M$94a6~q)TJj@dadkdlgG9&ler$7|teC%E^;=F))UGNsHw3 zmc=XL?_RpTzix{j^Av-d^e3i91$UJ@@v_FKAD@+eir+fzri;}^*NIWckHfj|#S6>* z_A!}g)R}0oxd5UuSa_)?kzu4>#2&>COfMfT<2;m<5KWku)3m2&p)F200>q+Xd6t5K zZLP)~%^HvRTib6>k3Ht);1SM1`Pn0$ytm48ul0!IA!9!hGVrc>bR=oNp=-cgettwQ z;picIw8-=v2QZ7R6nC)F1=pd43m07@CZM(poNcA{boRov2;3zP^PXW55G14yF9~rV zno+c!QDeOeN!K_em|=m|Ke*eDr0t0riI?J$o<<(8>9n_i9``-$DHnoR8YBt95;FRd zlZUez$e77QKylYqKJodO?jT|%n%NP@G2pn+Mc&q$4GIf`Htvv&`esFqIQhwNVJ34E zTBbhJi~w$1aA76Yqxxhqaj%9-MvbCCE9f0~L5|s;*GF2w@tCqNbP!I9G?nnrzimOAEC`p2>d2@`G8}Qcx_GX4cc#!_N%3Bmy?cO$T4u6xb*?#^ZvN2M$z#3QiXy7zn>dpt zR{TpCmGevuh8trN>U;Jh6^4@0VLXokqa|sw-K7S4!*PyTC=(f+N*4=?_a{qwE=CHQ z+5LWQ1I9~;WH2*_ud#zK+Fu>QZ$CaduT;M_CTfOQEZD52LokrKbfd0g17 zAA}H|*Nr~hl%!Y(#2ZE*(GDee!*wHJa~KYqnS69$jVK<0n=Yt^mEY|!-VN16cIZsp zxCfVy7)ShP`~%1WezoKCz3U13TbkdG1NMIp^JDpQ^%uX{yggj3Y|ZS=jO-ZYt$++X z!M}gOBkTXZCE@z@ z*6M0UWyih-!JTgk%Onl71`~K%l__Bpd#@5|#gI zO@6(b{6o1s_(gKC0`0aR$^~#w^~7& zK!fzFo5%MXh3z4!^`}%qK;;Bzg;}}&H=Iv?20TCp@2@TlaF?(GTL(J_Cm_%NzN@kU zTL%juApI}#mAsy<8U1rTYcqR2b4I{0!9vg8=x+e)KX)sB*gyW|G4^+B^6SUg@5KVl zu>i_?7Jz4de+aVzTM3AhnfZUg4#M{H37?ti*Uz&L^#W*V**MuB>`4D{#%JYVV_;@w z`;%jz|E)*OKP}3ypJZ8pnJ2)smJ4w41%N0!8#6Hc0K}hi0-g+jWh)1e49&#$NA51a z-&OTk4FRR5k+Fe3s~(3T;Ja>M%%sl_*w_ zTyxOI*tT?%BqE;K!gG7<_cxTCZ}e+#-nh@-I^|_Pt4+Nh2sK{1y{Xf=$h*HbOk}Q-Amjg1@x#Y5X~63;X(gQcI6PoCWPxOl`Tk=n6FZu3(x(t#zFc` z?|vvLRyDg{V@)Ax5j~l7cC6g!({1CRYQnpHak(dD6Yo?g%%mc329(Kn10@pE<&WaT zyaTwg70*XCs9B>`Mx7S|)sbn|B8KQ$KRQ3g)czURNW# zsI!>xRw3ht@?h!Bd}2{GEw&v?*pp!|824R|Xisx;>*2c#y2)9*^$InVLq#G83MaTfVBY)8P$^k@`})^-*XV~%p0Nm&i#`7-Y-IdOOl z@?y8A3$~ofsOixoWtRlNGZcx}r*RKS28x~(UAvD)9OBekt3;L}z|e**+v*2;kMN@Nij)B1bofbEBMS3s76$jx#7Yluw@R-HU)^g|SO1 zU%}u(g<%XKl%T+^laUHSLHO$k#6+%SS;7xN-2DY!I#Gq?p#SFmk9Y2Db$%UO&x7B|w=8vk4E zt2H^R@MR zDSM2PR5bnYXZoQojM%&r| zuV3~uv->)AVgK+0z^lpMO=vc=s}y{2rG4A_!S!{_8%Y($D9Jckr?mHZDhOR1a%C>A zY2I>6iFy8t`+5?-IoVW|_V)TXR|i8O1LD4Mm4-{fJ@dl zR&G~ijaV5|O4p&0*Phy^r~ES`c6=638-^|CjqaAHNb8k5jD3!rL^_P8kodM{50xe` z%}?s~bgV}yxT59cTBX&YrHFG@_6D|bu0xdMCB)(~ck|&WS~K}5MuNIS+@bLxuY0ZW zq-xM!^$X8mS$BV{od?r!xYQlyI1T)8K`Xa4GtmOA6{3{P?tkTZyKVVrJU zB!Xg-@rwf-rXCF?jhbeF-n|nl#KyqxB)~b=vaj=VcusRA&&dMa8|F-bqH0kiu z2DKG2)fM(&snljY<#rdXs-3z@f_Dm-)L4qi?QYT;}mk_=9$|SI?D7pb;So^K{vnuY@qjCQje^@(qLO#!={Ky9F8t>WwZ^4U$!Q&fF&~pW_$e>GgvA8SHGI z(){-X`f&)3;86y@fU|Iev=(EEdCp$Kl=pMqj=aycRx3)#7gwND-+Cz{TZ>#=^5_i@ z7RW3)H9dD6wKJ5yPSj|#VgB{)CkQtzGj;ALXJk;LwFs6yI&CUXSyq*qtyKYSzeKiK zhk6fm*L6qNYm?@Mgcg02WkD-%=r9Z;q!|VuF|=9t?df?DM?2{Dby9W`pN7F! z>GQfW*}Y(CRDgkYOzCIF11(@1MF~+_uz_ZHd3RkrOl^m34kUc!*xXOB_(qZWj_d0< zE`30Qn+Wa@y?$cL3*N2-$_%CJ&r)Lh_DjI__yw)2&>P~C?=qijzrp#)RO!!Om>QF= zd$1y}y~|&gmfxvHY;_D_r8i@+qLWF^C&hORk+3C!4p-)w$@hZvBL7ASN+WDnVNkA}7je4dk5FQ2yOY=5WaCWa{3}rK}TPTfrd@e6xTRRt6U0DFhTF-kSitv_(@1zl zQ7SZaKsD_8&!qJ%z?9u}OMb2%2R}Qdx#7!z;*J3e=n3}>N5A-Vco;2&UBdD)c5OeP zij#xtC9GaoA-WTJ=_)aD+45EUExgmEpL;5n2AHl~Iq&C#O!Mw+XB#k#jhw7(399Jw zJe0vqf1)dc;Qc-+{K6VWiEy2leQ#6+mS8K7ZU5^YBcMIw8YY6{eY2@|AQ(GxC# zQDMD!)3@0E11d+?ccz0PzamCclu?j1l+r$|C-76R9cj(K`~^-x!*j z%^s2Gb3bW4xDBl9bMq$|wNqt%+3o9Ks3M5R=XZc?_;8;bzltIC}bN%N}zsW zK8d0xO3oVgd~Nb-k}wS{n>)c{I`g)i3PpE(au^HL4*}rtkJMp~{P34MlzKbf88evp zUq*TH3ZaN-X@?xZT`-G|MtNm)?x2IwtPxoT2;DMi+xWu1L?|l`wnk{Qh!2ju;jiLT z`RoKwWNR~B2tT?JL^K3RUDmjZKRP8WU%yk{WXh?0Yghm|C z^4~)AT{-j4OIlidu9``>?}*ed4K>&3hlZ)vhYActAkM(FWl)|v>r(hMD@TJ@GdCSx zvjmv#H&&`0jBD7dg@ z>9i@3hpki>;!o~u;!g@Y;OA4TZHHs2f{pN(D@hLR5=0Tr!5pfxPGTH5DKTbB-&$XA zjULY()khmCZJ*MU1oksKBf6p|r0{c2^9&a|*EFBoGnn$_jMA=|scgO)XDy>kk+H!> zjOmj_?>Q(yBx$9C*bhI`_xW7^rYEZ)$Y~^Pxp}~m{5fcgGj z$k%jz;*Ng4pjTX_E92nKM$g?v9%(&px5H?>(8tEp!a-k3LX{K3H&hFt3n38_M0gSA?i}gYrSaB8Tn=~HFV&<HIEo2Hr834w;=-13|@Se0dN~ zXRM2sve=*5<4F3u#Z}Wwsr<^`Pm45T3(%m=GJQLbpV3!jGqBAEhrB#tfwrBms<|FQ z!Lw?wFJ7Zr^q3L9D=|O5GU%>ExyYee+?*j%xQ2VjEqA1owLCd1oGzFYS6OmZ$U7Qi z`;W)%3X)5GyN=Vrz7xEKSIN^h-2u59&DJi8Fc7THrvk~(sZ1<}@K&*Qr;sPJhL^eT zQcURE+&|LaugWzOXvc4|%3dFfd8D2B9GLJjsUx=9FPR(3R()h-WFX|$)azJu&W&}k zce%H~F6O%HM@+h}y1Aiyc_)!R0c~t3>@e-3|8+OS;C+)}FX0D0)=UZDFzWH%WL($* zo8KM@v>I<@ChW5W$dgV6`9MO((&2d=?{RqEu`0?D478?hHsXxe z&VRD%qO{@Jig&u;8fLQ+sx?%I+hR(Z`4#gSn1})O0RgM+Kzo`BT7Mi4CZ?^8ewo@B z+pup?VkaH--E}DYNGBgW}x zBfh_=*TsasrxnN{8A+0f8(wu5G{aZwI1+MXOFa?=F#fpt`_H`q=Ku3WcF>XsXm$-+ zEd?d-0!{Ea7`d4_LA*i$P;>_iGY9kk&N`5zi;;tgsktK%L)7+dLv<~&pbMv3kWc8?C*%jlCzT+)=zQi4)`(LsT=wp#X2_S^=iPImU zyRyuqnkX_ckyR|tBm0pug4~f%0~EM8jGoEY5l~Feh(XR8a3{O;IlYQC_v%6`paxU`d7} zNjiK}Nvx3p)mRFTQD^ffn(3oz6&??xgX*F{+QithzWAs{X0t-p0D2kaDrH25NiVE2w9>fT?vTcVt#DtS-?S5T8Z;z|h zvSkg{lFyFbm!CPjXW2fXzXvEbFV-&;1uuuYKU~!7Ir~h^7qlO?-ItBV4^8x}g|Kr7 z0LJ7+e#9!gRz^bRa~J154v%80fZX_cPC=*(i|Iv=ePw)?rV4N;$fmga-6O~^Sb7^Y zywvFF3Kp`%YDLK>_;zSYfS1?pH5@THG1x3%?xY*m4*VS$Vf!Owwm!H}>ME>np5Lnu z{&d(J#cq-3>>?{$pzW?CQgd9V|ZMtscUA8Xw%e|NZ=SWEHfSsCT3!PZtWCny*k z_mg8dQ(~qooi6xXUsN}1AlB7GAe7#k;XlkBISBt?D!S(=)-y@40?wy)+hC5P5lkfX zj~x$^xyQr1udVXxc2iYC6Gop^TF7U4F3Q}#u}DwP_%u4kBHvHhUmQ<&M|(S1B1BKI zwFen9yefV`djs=hH_eVdqFlD5gJfgfAX5O_X_zik_N_s+|5`)!0=zWO`xVxAEmFA` z>|*P~VpaX-l_2h)qB0lsot^qVC#U%`dwjHB0j3^^&96?}*Rgsd^{S1G`H3UiUmaiL zIT^wChkO0LEt#fjkCFDexm_>sH=B-PaH{N`iPp{V9+MksAV6^-yj0Q4{X*E|;x?pT ztbnF)+NX06Nt$brQ&%OOx3PlO>^sim*ImP;M@tK$M#-L?r8@32yO&#L#{Kra>^I@% zH2N9X2;CieR=a;9+)!+$dW)dYV(tvoG_XLW!M@>JRvHI%a!BJCh3*nwS24dT?A(mf zj{=u*jvSkAlc2Uh75`)k?It_Y)qx#~@GW@Ub|xX^+94wx($Z7RMx$iW3;ow~Ho|42 zM!ZS})c}EOYM4ViwUr{t{I+*;RD=y^czT>`=s3`=o3D%U@u#bq?r3KnC0cQp01||_)@XEw7rhe3hj2tbgR-?GiHwXO4!e= zu1%@Yr6XtKx&cUN(qzh4G=w=F3A}{Rd~c71;9GOst6Sd$zN?JtzYjozVF*#h;wxqo zaXW+A{7j;&iD$Py`@NcxhtOhVS`&i4qa%Qw@mPpe1(I{eTv$}dL$H<+>|sI#H&e$& z$g~9(N*~-GX=<`4U>pCTYN!b+BYz_t1-8@(yF};*%A}zx`-j{3nYz`%!d39AUtag` zaYXKc$J5Lq?;S;NT;tkmC!h3QF;x+*gb^$?65GOcC1+Oqa8v#gi z*RS&fI$q9glT_MWadO9t$Y|b0!>$+CZ-g?`C({&q9#?=N3@WANC^Y1q!)X2?*iLU(gy{7V=zpsX0hX@%akIc< z^To;~)iHtN!=-$VZ?~^MvO3pVgLjt*+S#Q>W6<2UPW)452|W;*ASLsyGL%- zeR*pxsyD{d_PecKUCdvQR>=U?NXrKWjN>$X41)ntr&IBE9qA90#mk1wtfm`#eyg(L z-afRmaOu(^*PC$*v^d&FEh!2%u2$K{nhSWb^PL-F39avpPIk%kiEon)pW4 zhp&+uW)WYXhR)4GWoQ13mx`2AIQ>P&Ql-m?bu*p%0OUc&`x3~11E;&9Q=U`i@+~`m z@=Y$OUkB}xGg?H$ck?TF9DS)l6zXO-Z-EM2ox=v2(q#08+ksy^9OE(iD-La30JUQ{YHax5$G*15S6{v zyNZR94J%eGWX&2bT!RV=6|H8Edy?l*0+mH085?Ytt^%F_qR%;FaEoTxq4s=BMjN$P zVrsf~W#-atRR8b%&cTTd|pI6~6lQpP%T=eHOaFq_<@ zyngs*`_pu)4)1QVUPBlj%b2C*s`Ob`V#XqU?C3znoA$edW0Qn@56+fvC=Tfm^ubF1 zH|?ts4Rk5`7+%lAS4v=Py?)tzkZ;EWIjv~a5S$^$cTDc=QwnW@tefqBma0#1<4p$6 zbA!#k68`lt6fQO+E~wz64PlT4&b+J!~6fgA^{-Z!)$k6P{d*ZQgxwCVd|2ABjcN6fhn z)@>h3yb^5gsDTAoo-;=|!Ybxt9Xg*;Zk?(XKN7BE zU=fTOKh#ND$)teXP-MOjo(+?Z-S|pTE9gXgI+x-SeE`w(tK~Pz>$jLNxRakntU8tn ze#R5nnP_xhtlbV@@$g`@P!ImJ#8@a=`AV)~-cPX){7Bt0B^|w*4EoVVOQYTaO!-R_ zPRN++JRKlhfY0W8`Ked|!&OdL`Nu8tS<+P6nB>3@+tF^=hBoe<38Q#Toqq4Ot>-y3 z<-9n<9Y=_-FG^%FZP$S`bUM3Gv;z|-HWt`*t~A}a3m1Hf07C9`y1&N$);;CLi3}cAiYJ!7!*Gn6xUc2_isRIRmA!$Mp1=ze(oqTm zQq)%z>vM0-Ya*E&rZ$lF!2LP>Tz2pzdkzsY;I zQj{4wMpAxYg+vn$hTlg1BY3v~5VvSyBY{raZr)xITZ@crb9%)#DGv}RSxOcuDbC2r4}`W^mw;y*UH1CN$(KXGO5^C5gX*@ zB=s1$qQCyO!*<<(XggQ2_0!qLD$ko*b8+oVpFp*oHG0$EGS4E@pP7eUu{;f?dOlR~ zxFe}zFw`vFr{^1~#GIp!tephrsR=A`V~K9yNoTwda+2p1S6xM|xNdj8z2tkJ>s6f( zYw|^-#*9RKceW8B%R5c4WC(sFxn5}voXXHtZP>_m?!6NHQq?S=wC<%%O>9m~;#ue> zO-vE0{c4n!(5DF)HQMKE`VqcL8VtJ|#gWr3bN(PocbK-}$H@%Fcd@TT?4>TgcLWGM zz)tEhv|cKb?_^$Thp7ylGYfCY*7nKUj+J+YhI!j9xmgGyx@RN^j1;O_=Zbr?R)0wA&V@5f4bJ z;Ix4E(S^bo@}V7MRDG2n z!F{LjO_NDDg;dfyR3r!{I&>qT$~fH<$}M5IIw~t}bF83dVul;?c*l%0y9nM%6fDo= zv*(G#?_C)yfPn=7FlFKgsP^IARqh z{cfkf!X|N6VLDLg+S2ZY7OIM-j?!C0W!6%umbyEN@NvHnj@Fvq{#kpK)>=`U^9v=7 zIT$Lm7_zW+B3|449ea}X1MIv#i4;r=6mD)sS%_3j`-eozlAq+gKYsp}ywC0G)2(md zRbU{{>2qn1XyYvhKbX;{dB3qcUHI^sTv@RHaE$8&s&stc|N15cwjr%jegUg)$2u5zF<7qSkJn! zrohW|PM8nqkEY6AO_1LnY#1GF%{R>#r`4BM<#0!1DtVO^ZqLb0X7}iBZ4{~7uT%k7 zNMYC4FAm%^g5JphB3jff^EM@vDILf~-kXmd<0bPzCE3F`;ovdg-1n#zIQP)IxnStQ z&;Ycu&z?QUL#u+O6t4r zG@>n^(?klPyD#xS&6l>^UiU9fFfIF_IWl+Le$7FK6!2}4hr#oN(!+Jr4TZM;=Cs4c z>~aI;1=njXS$n-|E})whI;8sJ?R6lgN>@H|P_+DS=8@pq=1TK{jPL+Ycn+vs-1UAN zM8BVA(LRD?pVW2{?pvVthP_QsuK>n_Ch5paeOSWO1n^Ia8>o<@Teu={m-!A%T?*A5RX! zuh=d3uz?!q8c^u1xaEYIQ!Y;ZwE}#*oT}YSxkxYQ_uDi`OIUNFxqQ*qwH>LQjQnVM zlB?g_om?DBF5DGAG?VYHcm#zcomhr>#pBnln8tgijZOu)tId!k+P2dq?w~RQmYu62 zEMfDyqZ{40a&-&rmslBO&T;msj!by^zM6Y)_ufg?CU%H+tz zIV+5(Kuv{~!bIa4wBwfsuG^qjhkMGE=jJ0CZV_Pg;qae+yX_uH3?UWrIW&?e z@=~z~5un&`n`L?r+a7O@F9i=C$l?QVpwo4#Ton{e*J&Fb?hOVu+&|!?KHMFJwEu{{ zJ3IE_xpss7A1!_UpKqId+C$3?N+|=1Q+Uc)&(6pV0MR`VbAb3RK%1PH|8MRN{MS8A zTr6yc##~&ipcFTtls=&SP3!=}rxYv3%-pOdoLsC%h8!kr+|2*HQ}ijz(?51Z{-NHlIQw}Er9)EhzH)jbqINow{=Hky zX30MV^(LU^*TUF0ySJY!+6CX=Q(@Tn_}Dy{YsY(^pFcK9Szq1`Z#iGBZ+M)pI-0dV z{sf-M&c|a}>$Pz#r!m>eNi8I;NwM6H6Kqr~@ZKwpdDgHHjOKEYs2mm;QGL_Yl$Lu{ zC1fKuVXsm|PS%XC1BY(pl2#I-TUb5!E7`p!%G8sOlPJq@_?O5f+RxMaU`jk*hSFG7 znT+goo6ijo`=>+)@=HoLjr@;uD2?R>6v0hK1q$-0YU*skEU4(#C*W4Ad{(8ZpAx%v zL||DI3U)`Uwt?7mdE*d?8pIT7K}g|&Nsx771L81>q-PyblTiE#`4(v%9!TA7ZwE$C zrj(jcMgW0)RZQKON6MB1)v{W@8RLx7to@c+?6K>LY(g(wmjWY9bX6WLFB6tFRb(lY zJ|*Fw(kjD9k*M-Uov>naG?SLgvc46FhI~Vs{aXvQ0yh6N?=(z0p5{$|4=p2wBGEN% zMN0xcckf%i=dMB}p}qcE`(VhO2#z7w5d5!FMXy*P`UysZ2&>Y2kVH29 z>9U13Q=)ij+m>SJp~C}k-@r6B7?Qq1!m)fSymtn}XV-GeDKo-WX#FuQl=u<6Jm9?} zV14P$8L(!`>LXJ4+HCS0CrNY?g;+lg{srx(e z6TU}}}XOurl4 z%9-zsX=sPn0dk9N!GGxZk<~FK-JmM}+i^%IR-IQ&-zIc*Yyvw{++$99CFl6D(P7Cd zw$t9Hu!aT&=@UAahRb?qRdoNoi=EC$M+H@neq>>oi{eUX4n5gU`bGi_x?O$^t;JBr zUv?#=?99l#d_tw)mO7LYFt~E`MviUdQa#*NN-i_p&Q{z-ycVE}-6nf-mPTeyZ*E8h zYUPm1zDBr6HIJByOoR9EtnzUn6I)ps*Vim<5( zh6N-HVg*7TIiNQRPx=bi zrIfg9umz%*$8*n*U6S`$6phz$TeyUnJmqr)dx)g44{^5Wey0RmKZaHMW?v>rUl%bi z6zeO;t}fhDC+2~P4c(E;IX!^URlZ2?!L27|zwFnoxxR35t?2``wTIl@;hD{PqWN}Y zKXwAb>iDVZj~08`Kes^RGuIAot%tJfuW-K$uaSG=;cEZh&HQB(=}S<8f`O?C9MgLf zM_VTcBNInrK0YP|2U{a06Ckk`lY*E8F_W^1E0CD!tu;tc(J_W}ZNOzQH67A8i(CjoU%;-`M@`LqOx7U}7n1RL?w z&wijUNq};qy?pxgwRa}Q<_03RuEbhT8=*n;LByQg&-8RQHnu=VVy&mG{(pc4;NN2b3LgDOAO8Q&rT(vC@!}pJLbzv0p4|hqS^nkd#mQJ-oQ(Au zwZFo}`V8Q|x(>^~hl}-Zp>_Y=TnCh^@(CxgKlo)!Kpu&ngw9z0XN!--9MO&yYN4Ed?FDpazOm ze!}TFizBFbL5<_ZW1lnCflj`7>~mtW_n@4!&tG`XL-kKx1ZZmYKLD2f-vbMZ1paRh z>@)Q?2$C1np1GJoM=$mKnU5EA^y0D4oUHGOxn4Z>nWYnS^nyJo?&#?eJd+##6Qa+Q ze}8jTj(?9R*VCn+dSB3x;lF1Ee`d1)Vex|6GhM-Z;^)wOQ1Rli&ym-lqZib;U$6&} zcRykH99Rh|UOW~QzVvkRB}(k6{9E7j5;F8Rh&lf~!~jtC$^U;~{J%MzdD%GjPyPj9 zeg^Mf+d{7Yy8D-r<6lN~Ad2w+rg#5bEC1SkzAUZ$?b&nxr@Mc0sK3=O$ER_!6KJ3g z0#3%<7&PpDan$D_FlYez;;7G~8c-Mi;+oH$3aEAXqXqcWxIahJFGKae;Qss|{{59% z{=D*wdp`O4pB>-7SNT*M{=G^7XmI~>H-C)nLGy>_reEi;W$P7vX_@`P|4ht7ELql5@D?8JFRm=9YF_MGz z=>a_JHD)ulVdrpU<8-wJP4`|N?4LIU0C9w~f|l|A)XQ#V?qh>mS0d2AnROEL;xu91g616J}#( z2Bnv0e;UR7yMU_DAC1JH)`Adt;gR`Y5(a>n zRoFqs{2}bb>BtOF&futo1y|dQbc(9PA+MIM_M=VYI!mt&2S~(3~BF-`|8;*jN}j zK>QSc)>RifM{{czBSUjTOM6hoejZ!=m+Jp=PY~^ZInauo#pnY!2#J4{W8q=}HHEDI zfPxj&))@nAIjoI=Y){fJW1~L}e$o2ZM*OK0`lpUS)Br?tU~Br+6Pkh+yZ|rV5ge14 ziR05+(8~(aUo|{6GJj~0HL)=TngNJGv^Jceq3VD7&4QJgo%5eId+)cxdMb-wFnNDE zZ1u7|s=t(TDZX{)StKzR5qSgSCzPhbY*kGuMLzH;l)m$|HVmzQsDJbt3vEMG4off! zv)BjySbIqVC*XpjeWvh)fgRc6qtcH>lE~4=kt46H?90^4RF6{I11EWvOvhd2#h>6X zU|c9-)ci)X$EYGv3UES9y;F0hkwly)L%o-+2sveawH-KURLFokU0q}$P3CssLQj0P zjBR=~>}d9@c9U~Brb{1LzhW%^o{ijB3NPcgk5Kz1}lNd zy=GMnlYVM1ys2)Jx+!PP?^!}KtWj;Q{>j-}9Wd}6l5R{U3(X|jSNlYbz8g%sJf`+% z=YU%dTWf{q4W zZVC?c2r8=~{od-izY{0F^t*+FyRR~gX!D$EkAGm$a|bs&1uad3&EIivF}^|IVe$}8F!dC zRE6U+kM#iQSgI3OqDb}LIgHCw&4tSTTSL`4F?d=MU27U&MB;FOl%+qS0-Pi%C4Z;H zo5m>q{=`y|&iGuFmHd+KbYIj{Sap)n5@BorkvnNp2Uw3EGYr6w(~raz4I2tEls6aA zo^vU%9>H@eGj+~>Ex}e&FlJH+l}sV@0MTDj0ov3Eo>l*~mES?vN6qM@VY5vW_mu?b zE`4moN!Qd=9g|nHRWaTdSs&A!9EMk$k(VzLH14it`s(7OQLl+cLpEhoR;=_gU~BBt zvSHz8PYF{iXFo?m3ebN<+Pi8%3NExGeD4V!>GyUZ#*uj`kS4;{{w>k3f+dCUYa`bo zQgx_d13=PuJ6TM_8$Nmul02y1ZMm;SosjhG$c$abva^Ums%L|`a(Gc2%m4om{Nm2?A#wYN~$e@ah6KA_Eq^evzxEB zcv76XG5HR1e-6ZS*T(@?$GG4|W=xq+1GjQh=s_h^LvhV?xo|gRRPw>@i4{8~SPK0G z^ZL@e*0WL3{_J1Dt+v(81cFlnO(vc5dz7$yheXiNQDxKseZL(hkn@K7r-O6x!d79o zDf7!jIr+~iQmXox%R4pkg4yRQCGe(GV%Rs0q7a$WX6Ajr&R449OjaEBInKM}U$oUrVNNMI?` z-=FtJRAu`n-)L-k#Ikzp=M^jG3O-C|@z7Uc{yMg(%lN2uPkc8j(v8BC)FvD07}d-- z(p9k9kL6d}-FDoLi$j8uC!O0am7rFErRj1)B|qJNH2E!FfDL6+7=5(KWo6SHcTCrN zU__0zw9@;`@94AS{D_Vdivg>*Ju&)aU*Iqe@4(CJEAXPyfymtlDc)F{V_nskIeH-{ z9soXqy^kNd+^?Yq3PgdZt-0q4H~-t56%QXxoQbWO}ngpbqGr^|ajz|{tM zF&8NK^#yHWrLHL9dHLY(3Kc<38(tJzvsXm z5G?tjJjPYsp!m!h7lIai;LC;GGJ+(D`{N5*`JKsyox}HY3@g z+3q^3!-PH>V9 z%Up!$>PP2SU5+sUZ~NaP7eosq&8y{C3R)kN&M}ems!>?l^^oHiicBr%SL(Hg6t9}R zA@RwHAWu-Hq$t2Bol%&)lo%1fAnZ!Zj;04&f1@}Ho^|-%IHf1<5}AE>klLW>#hDsbj0s!rK)FJ;Q8<5($q*lIo7M`KrJ~FY;*`2Jd8v!jt%>C%Feb z+A+2E?L58pN5VKHseT~kHSOy}EV-p+jj3zhH}RGU>G7WjIi~CxGen7^MPOV6O>^%# z(5z==?6Xgae_xmN1R8CTi5sKfM3J!uWXLDQ%Gi@vkhsJ{b04%*c-SW{5$lnRe862{ zyUg?2M&Us^a@@vm3bZNUoaDISxd$aH%-6@z7KyV99w+{Wnglx>^iCw=*#G#;aju;R zSD1@5TPO)YJ~GVy1i?PoHO@8Ws`RRqO~+mLM%{FrVM?dWa>k3{@+0)%`bNz!D7SzX zE$?^cVuzk@oL6q-;n-3MMzh9H7RrY zA`u&{reJqhd57B+QEh`6Ae2&|t$NP$E~bsrRI7Z_^n4Q??onmSWH_9>EBj0O=Hn>j z=fH~8Uoj%3*jQO1^?{dR^h@xz5m0L+k~^YZuD|@3!vYF;VBlRkZG$L&!OeM1GZ%8YAd? zP!nlp1fR?p+KeK!IRveZktNO`mH)3mOQ`_6;zPO{O3iDgFeq1fSM*Y!um@FaGQtGP z*lTKVwT`cqEWSrLMj0s_k;lz5oOBNZihI*K9=oHIjB{S>r3Y#I$JM;|@id^Fy zCCKz-B@peYmg@7fP~rkcMRBsjHTT8MCg0^9Fw0k?Oz|}231nyZVh-4@L{ITGFgvlL z=L@JOG~sJ4z!7yr%}T3MF^R$xhsK{0;xI(zFuf&v-wP!0N{}l^m&?|}KcGJ8!g77Y zBnz<1Zj$qapcHv$;k7$9u*k2_y#&71m1+m+aZMp$P*6!UlwhVabOMhIXg$uM@08_^c3cqA?R?OMa@-D_Vlj~W&4&+NJFYOP8)4)|pq-4(1ko19{^ZW78!yDbkvB3pH!jx^p_ktvq%%~QELf8-u9r8|6lE2B7iY-_`Vi@x zlyU?Ui?ijJ_ERVKGy_x5_i^gD1YFc3OnXs}N~t+)h&1bq zJih3ub1ryf_2unNf1c2+%TSr&=loXLM)dTi3OOmpa zINUwhJ(VUON78N$>Gf;P2muyy7N5oIC@%IkCkAE%w}u~EGW%}{pqA~d7YmxC8VdV} zO0&7?E4yL$DCw6|6UH6n#%K;3MZXq8JBRe9!KQp$gm7&7?HY<@nmZ4xLnebQ9;Y~f z!Z1&dNK+c2pM3*JnM9r**$wGE{zRo-X2LN#;Kp#18?`s}K%e=;HZIRXOzRR^2q_f* z{^t%2D=SS?$qll;a37UUdGPg|oeba7d*vQ=F~V@ia5kj16M+&X`c7Wsk=UD2nnfh^wq#D8W^|WseX*JwBKk&!~ z2CY5o*DVwcbsoz<{RDV=KVq&uJPu|hj8D>UcKn%zAG_O~V$9GH`D?D%6Z@n*B@qT$Y6Z zXI^QXlgBo=yZ++ZYLrHwxxAD1ku6SD8)3hNz)p;au)#nyjE2W_G^7Tvz2+hzhL9F- z>6edhcxvsX?xQ`wmHo^ICwHYaDW#7SXT$W<^v|>^gkw5dP5?98Y$TOmIng+PbWMwY zN5)*1Su{Cih1<&p$V^%>-#6s>uwBq}xX>+L-G)70kU@Sni*p*RyF`cHWdKyBwu;&c zzJPfxVzcL~kf#&6U)wxX9uV<5DznL93I!|I17T6XFEe)(W%jx}yy1-wYg7ODf#@X* z4*?kI@Q-l@k$Rj(gCw$FaDJ)`1xSo24wW`YygsOW#~4lMJm4as6x)5d>3%j4O(WaD z7JM0vKpToCukGlQjKCH1)<%5u%Ua#B*32zEg}!{&$%!3Az9vTtuX!Rz)p;TgTAgyA zCiSCmphE?Td3%oOe7)pwTBdQ26K|rU%WV(+!XpvbCR`xv%ZF;)#y5<4 z(#r-nVPx<#Ir(P0xu8c+menExuF3gp9v+z`>VtaT~TIj&R9#{{qUTgp(I8mp_*40lv7W5YFfa+5{ccwh$g;Ud;5h zFE|jYdBWERmvfTDJyf9k9&1}^!6)k>?shDXNbHgOM%j`XG9W4iSzS_GPrM!Sl;S2N z^ZG);qB82Ry9%BpDW^=B6KN3vh&R5oEs!?D!)x3xk>$IE-Vy)#nETQP;*utoOE57M zQ55 z0siV-xaQ?CLyB=fd-whGdb9|hO=-|?wNz`x^@kHCJvgWL%bosfNFT`XSq zM)&(2zWI_|TDp{DB%9=0M*;I`DU-a+U@ggyj<#Hv&PX3bLLNGVOT5b2BFS(ivXJxT zW<##tG@-{(RK_MHGiIO}doPXVr2$*i9;?LzB)?NtttD_F%6Hvvi)G|c#YJWHNMspH zW`weDf5`b6b4UlI0rJpih6LKKn2FO1s|DCVHGO!lG5NFSrWpyHWYNRi?mu5Q+m7TAl^1h-pJn5!|H*p_GJ%;cWr zdAzz8`I)^gu4d4e`8k&^wVoF!z7jd^4>p#PFv?X7YXoa)CSs*&MqbBBZ)Zb25ompg z^aFAfR;5_x+`!2>L^>|el}A0W2NUW_luUSO<=2oii{OOP68X&Fx?R04G-?iqg~d4=3R#MWBakp$XqIHM6%^{V)al5*Gb@dpsT)`y`|?wG zAnH72USwvCmcR5%W`X*53&EdQ``{v0Wwytx?ftuWyL+8`Z4G@|MnuMCxPX1r96-Q{ zQu1Z3oy~C3e3%mh^44^HVwDhWeOujzn$>z`h^J^YB2it4=Sa&<6Mq-+?~!9zdL3-G z^0v0ROxe{9Au>H9?q4YtZrrc2KBywGQKT@sm^Nvn?-@0EZW?g666UpND_3l7h; zf7R0;Ay0&=tUj9=NjC!-1`IW%-L(V|MUS!yZLuYhHe z)pSP1J7()kfA|sP)@`4_S8k3YWGyq%GoOT8`@v;^rHG@N@$1=G5l&S1M4dd}s(?k1ij%254R=>Ad!U~6DfDs(Bi}5WA zj5zBg-Tg=dQJd0xUs~pmko?<9nfhQ5f=8UBX&r%PP^@`D`55$}wCbqVp;QwHUrBg6 zqPHQT^WaY;?E=syAQ;7%){tW%2oY|Hp}W10Nuank{fPiDep8obH!M@cSb)gjgUkJ4 z_#T)wmsn(j9_n8teJJfguR@70d_8+aLP;>~BSnRGAfi4PPe~MT4fEUb&ox6p3UP0pU~2x#31W+W}m@M(k(e_%I(s19FHA5tR$u z{24S2%E(Mei18t zJrS#(Ju)bQ!7>KmYYyt64X+r*S|ZmsDq&9G)FWLf=-(3feZ)`Cg|)|^7j1!Kl&*5z zk3g+hZNO!G>jg8@RTyfi&%LIp?&nINopb{>-MJAu(~Xf*O?U#)0RBa+1yz;Q##bd2 z4;8ulogK#7h#mV{#Y)=LtsQ*7mI3=3rFwuXUU~1rPt@fQ-W8r6UIU$7{wsFv7+0)v z$(HnWemkP1J0^%+i?^4KqFj-crsRreBv~leS_B0dBS7|cJj{k%?Sfn=oLr5%Sue>QI}HaQRif7 z@~T&K$m-mb%rQ7$$Q21+%oS=s+3~Bjemj^GG*{FUC0FiqQqR5<$1AiotYhh2lsgPv z@jJZ!{A1j;^$LVSHEmRIm=oX3=F%c~4M>-dl0M+I3SXvd6e^~Z#3E}>(c zm&XEY$adH#l2>3Sa*rEMH#3i`Jogokb#jk)dfR7XK6#UZ zw^%&)liAy6@(+la-UTwnO#JVPea@JGH^ z0rwLn&;j&t{$KXqK#m(Ekq%eO6%U}p(^mV-O%H|(L#5usNIVZ-#T~cZCgV z^SL{RY2or0zjeLov(q)+z{(}qF|I9BMJv`>&UE&g`Ix(C#zxXeNj5#69!1#_<(`k) z{MocNAGK#zYKkr|hxkC9N#>S`^-zlH_HEe6hY!m*#pb4Y6g%WQ=m+XU`ds48K->e4 z0-dg*8#Z|Zb~#@7J@mN2fQMupmx6?eLpyb@gTBLByk^FNMKj~~230BVR9QFiK7VKd zeBj{yrf*n_*Qqa7^c@G0%Oo#cIDeEF=d2v79p->5GtxO(W&`ef;#&v;T2ZB$pjLoE z(ww2Vg9<#ISxpJ%4-0_CH^$nqIeEwlSqX=CJo}%_P*gbRST1_Z*s*;8^Qo^+-S@Qz zQ#5duXjpb_9A|A3)^KRzgZM#B4U<2;N1sk=ziN;L+fyu>KQeyoX9i#~p|z){mK z9zDTIIEy9q0ZaMrNJok)f04+}fx^hd+$tQSHBY^nk-l)PXZAp@cyZIA(w{J7c++7% z?!gz)s>G<0aWwn~t=4CrO!2J`=VzF`7S8%1-l+5E?rlk%P>UJP9}59h#!Oy6zQCK; z&!s3gXd^ZE2cZ?XYZHd_2hl_mA0}cS&|Zv%o2aNHF*qQVnO4$%nhP@g9WfpaWSM6l z8U7fV2~shIckb>n6T}bXN>O&@V>FEp!8r49(B_tE=`U>T2;&L1zP1`rhDz5-Qkk=@ zpRd zVe|DMPA z)0YX~_%&Il9dTrpeh!SwO$kvIqeEi9(S>W}&tOm0v9%rvhs7`1cSuK%13^HRjh|&| zfpk(tGDiDhbTM-?PN^d+mk@y>t9I0}L=y8}6L#LzL`JI$6)2Djf`&TTW9z3Ho&o`# zMxj;isxfn0utrqRC>Uc<(?x*aZUB7?0Ur&kH0b@lzmN4!TJm2`mrtG@WRSNJ?;X*XKZN0p-g$o-@_69liMODH5Ptf(kl&;VmTBOM+NA0Bs==l`G>nq$-7 zl$I1>!aib!l;%<69<8l1%z$tO0jfMwR9a`jNHpEdyLd@`%HiDyc48o>RZ##_(AL(} z)K*sTXWMOV`=uXUBeha*tuhMO=WOp22DJk4i`QMNVeDArA($#wT^R8W3h9g$k> z9kK}X1#qK5TU-Z=Hav?zRr%~dYr4!wPt{I;`N8D=HVNaBq3i&$Ra?Cg=BofK#Se3n>)q3|vC%p- ze2=jqrxxajpjrlV{`(^qG9x47gSeR_&z$_3>DZ?Yxaub_!-0W*b>GCeZ}9j)jUg%- zjn8AZFQsa?Hc%zn4>~aWHLfA5PrNHx{`0`OaHaBx%#G9iBd>&GX}?Vg00IGP)RId1DvGY4uRqZjD3U z6rz>1%8U!t|D=(g`M`w4HMady>B1S@C>1VK9~GdEkMuOCHhT^f#yg!aH3ihlRAAR|OV#e+&R5cObvHF0cXoB8adDGe@#6$G zqV2LP^R@NAEMTB^eW^sT4}2{-i<-sh^mEdbvYnJdiSr!=M9~t5)9wEUR6wi0^R>jC zd|~RQDaog%UPSuWCjXd29=??APGs)Z0%* z>|0rm8%$Z}QVDtg))&W2+q-Ic!N5qI#FJ<3CEpRtmv43c_;UTaO;7wT8A@uWJ%3KZ z)Pwd=sotOxukK3iv&Q&BH&l^~_U_rVZrUq9 zcE0sx@|z_4yBH5A-y>JUAv9aY?lK4L)Uv9+!l6S; zu8)n$nRzxocQ9$E=hKBCK+i=SkkriG+^*Dm(?Z3n^{q+Wn%!b=&k)oBtR191!HZxK0_CmI@XoQ|f6>Ns@h z5dU;H^(n2w`4M2^9uQLRwK}V4d+NP}=B&C+AXL~aJSI@#Vjw7PgtEUZWDq_B`WepK zHhj3aa|O1HvT#&Q&jI862IP1)7xB1@loPUTW3nzs`r8jqrZFa?#;{5IksorYHDR`z zOr{}|ttO*!$Yfo6>a&E6#U(F`%PK=ZOEt1kx)jEbC){T9kjViZL#v6QtTNm|*$;IR z247H=oI$hMqsPjemslW?!UE$LWG zpCDKAz?X>}qfy72R9OnBCKE%J*45;xHrsSsjv7EVZ>5^?_o>6+MrTK7O&v~*6?JRq zTH{*lvldA&8@+V6W3=ncoT2_nj_I!HITQQ~Oq)&t+6{UItdR0$($5;tIL;+Sp zzcFOv^J25G44c9dZB0xyCN!+70sEyCF98ZG0lWlk3_g85<1_3uDoR8aY*@mBnL!{8 zOP~Sx+D6cI`=A)&affQ}TVCdN+fi(Fk-UPKLv@#z^|h(7NS>^lyx`R>7q>1Oa{jCL zzP9|PJ=-q7eA~7wFF&(^zDh(g@X;ANlc~3o$>fvUZ-1QJoxJU<)l7}2irA{yctQheUw(xnHl0rHgQ}*S{@6D7)k(K~Sh7sK zY|!PQ-=6W@45YFeHIRv;K;xxs)1bAl$;+h99=B4MHik4FosHcGV+>c^7T z4lz6gC5%PlH4G1yG4Z2a4>Z~Bls_<`x7uj-IfoNQyMs;+I$0WPyA_*GcYrcp|678O z{Lej&NhEt7dm4XOqVE7{fbI!tpY93yY312~JjzsWnq*mEnr&HOU*WjUzSsV-?_>Wl zpJ|`*aR>FQ0X0_*s=D8&j^QXC1_gaR&af|NP!*l-xq#0Z2>6tM5A~U6!x5XE@e0BkORu;ERdae}f~*Yog9g&D zG$V;oS2$LQ9MrdOp9+*ZzH*^R;u^*dmSs^sSxG(7`|tc}>m8R}br;#=`0h`yo*4Pi zf%~Qhw{IU@J!}7!2S1*>;8%C8bG-EC7u)L|-uuAXnZ20=PDy$dq;0q0sjF7^J0apua&|oNZ1p{KRFd!A0BW9B~2dxQBWzwd} zG2SK?kCiaxd#HrnV6UpF!8Q3PPX5uS)TiuK>cMy!b8PZ^NM^TrxcOSMINUbXcClZW z;J!dT-#OcTk$JiETJt*Rb^Zs<21ye*(-}=>izpL(E@5-Zent8OVSio4O!{DFT%xyw zJ^(p%enO8_N=T;Jo}FTQc8cv?y4c<{LtCU#&C5hYYnHP`bR#=n1CrS-?X(-4 z+OIwTy!Fnu@E5hgP?_s~nPn03`P*J!(*p4U2i z#$COFzq@gN@*kftYXLWFqAGQu-ZqoR_kbz&L*h|3K4u+f9InE39QA2+&Qap(T*pzL zR_z>Rg)2OcGGDk9C7sR&Sm7vf)N#~vOfL)eI@5g9ou+N3XHC**VYK-cQLv+UgGndI zlEEm*xSp8J&j}*#LPWs~)MOTA;R*T#`^%POOTxh3P?}8eoIz}-b03!^Ln1d+VaP5V zhO|||17C9U!q84C6J|M)7pah&!+qq9R?39IXm(ZrRjEb=$||!u7&x+<)uFpA?PNWl z@4vA%n5`SfnOIk=pQwD_cWeDC|CY=7Y(5QI*}=xq#^jW*>&7-$0O@OgJ2TI_(^dTxoD4 z#mGXZlt{wELJn>n+Bpi|tU<$tC|!t!9Nbv6b2NJSe6vD)vQO7Sdw}3*o7wP^fW;7W zxdL{!gc+@(7z~Y|ER_T0GS0j{yw;=(izlPVOc&V#6Bn35^9^F`3gvDUXdcU|r# z$3u=MO|P5Y_A7da*HYvY^rcd%u>%(r0X2>4Fu3dv$8#2|)8cSitY%a<2?rx2VcCLv zAd5BOA{n9{w~FLdriyTRN!S>9wi)Uob)~vN71jTRQt@)7;w9i!z0{jkD&CEneJ|+) zR&py!UcXk$uAfsbq0^PiY3ikc?S)XG@NsCsJ#hnS;3I34UU3Oo4)_wpS0Azj_X$7w z0a15-gG$E1w#BGuz~z+DGK@|Bo$HPZu4>!9e(L%j+is+9c0NAtnw$0$W!VkKpXnsc z>bmO>-gjr~xEeS8`qAXY(~~Fu^z==whnYqhgZ$;fbto5#sIUjk?_+#yZ0(tVmK`l6 z8z{)KQKXBF!s-19M+;{rUYctTW~ms`TN2Z$H7#T%Au@vq#NQ*BFcY&Gtr)+Q7j&8p zK>|^g)#BR|HRw?pPkH!?=Hc5DPi8N1=(R)YAG5sGa8y0mz<8^8K@J%vCtSmFhH2C6 zle7iGYBCBJI&u2@7igk*Rk%b zcQn1I@x=^>DZ^*1C|l6FYbo4w5II)Bw--8@tz>p)=|u9trdG0bjX1lpq448QZ_iN+ zrVO5ZE*-pgUR&oSFJJRP^2puSeYXAG&dPB&j$Qh|eV46xSe$4%zjRFLpfBH<)tLPD zm32q2B(>ynvh5FB51f3r;oCR>g9Mjl{WlP;Mn1(%F&J=d7Padu9YuzJU_4n(_o&z>rq4?yeJQyDt{|6-%akR? zrKXF_D?Hc3I*9qmn#@=Q;R@^b~-QN%IBH+JTsqX<~O;r8*$B*a8cLB-cM)OHolsy!gY_DqIgUBqZjIQD9TEo&Mu%!NHjiU5LVzE9IncY>^cm_;yIJ@bb?h1&UzxaYr z_U->-!NN5+Bu~8gX7a>M=U%&D{_5-I&Rg4m)W(Ucwr;;_e!y!HN;xwjSe zJh*mm3JBT1;SXfe{A;eBF>B2=CsSiKj{8mXRS$2?p2soC4&r*aWe-?UR3dCRT;4SD z6_8^jE$MvV!d;^5R=Ew%;<+s3;<8!5F_K;;xk(o85^lGeJ?v{cmBAk7Rx=CeXWb4R z9yf;2IEmWOG&#Zf+nZi#dEi*02V-!rjdQq-AFkNEww`fgk03iL9%m6O7AK4+gl{Cx zs!cbUF#9Nv?ZMgP9gH`W@l~RX&mS^BlSY-TwD110>mZ^V5vMG^L=iXnY+R`S#Zymz z);~R}r2B&s75#mq-HFKA?x~Tv!UgVyzIl-qzAJ+3eb)!?bZ_(R^?l*~L_4852Dt+IG5`xUna*01_TF0XREExg156^ullJk|SHfMr|A8r^ykn)EODd zNKluNm|dx%VF_vY**`Uqwh9N)J{1LQl|~;>eC#%UTo@xwnfxgE zP4d&^&fo46Dt^8D;9cu+sYWT;gIkkp#Tfr6w_idNCD6%ws;d@-YN8Vjv>Hu*pzI{@ zUM2HJU5=+Gf-o4l@Xz z!bbI3=_%cQ^_Xf@q?RH7 z$ijs2;!EQDqOcL!xt)-NalC22{Ju%pXd)&SSFQ3(GF>S*%T)fA_4PN>?4E-T|9Nq0 zeL3pUqu{Nn_8qM`QqA7g9c6E-vae|4nPXALe{0l(2Q3E=u94C{vSV$Fabj&t@T_Td zZK73BuJCw8NI8iJ?0v2fE6~XTE&mg(d-svfU*G#C`TC9# zd4Y1NL#&ti|1R0>Y0?{QQ_h@304piV6!MkQ>C24h4fY zP;fm<@*3Xk^1#;HgqiKVyfK}L8Me4Ef0Br@)lX+CUePk|R!;E6mj^QMReosW z43-Y)(r;P}{Ow9Ze86;X*PD}u>Q2P!u{=H|eE^!iP92t`!)1uQ#AkLu+*ZX7L(^xW z>@7>VE!^#((?TO8T$Vm3k3~>jl~uBJiG?@O*w*Kp=FVHaVQTXq)+c{O2CnLNX6=Zp z?n%B)7M>FuI<5btTh}MIOC9xl=A84J@`An1^L8}$7ADx-bH|KYRQTf-+0<{rhzZO2 zx%u4Gr_#mJtH=jm?V3f;&!r?ir@XJ9C1$XY24&`1s2P{#Hp4Z!8{tmr5#d4e9-+~O@ys8n)-v!?U?DNYBU0-OyDWcKSeKG2xO-Vma3yp(u!Vk9pg2i2ZmUM70v z7+c<{%V}o|yx4YNVDib2k0#&v^VR@~fMkNPfO}w1VQva&Y(e zrzaA5nU3j6h`*uGbH>yg_#0*~PvH#BRjMzPtMc(s`A$aVmXi8!GxWDvhW;+g(7~T! z=uEWXG%oI4I&^uWui$6DhGM_|5Oq0TpO@;`PhHFgLFaNi-43^)^9!CZv0D(lN+3+! z23we&h{WUUv$IvCfpNUY?Qz>(PKx{<4VPtJ3>6@k-$TBCWZISW%bLcnxarX9Huwg8&k;$nn#o7?MM+CD&lJF zp&sr_4CFoBAd{|6Vh8WisAiUD_&-&7Td*@uHe-@(t*@OBgO2#I9ey86>8w5Y_^Dn#T4p#B1&#b&#u46AZlz>iYP`kgk6S6_ ztZllqxquYp@*&IRLzc^jEH|bZh=Hpb1K$H0a$>X2K26n(Q5#NV#zN(T!OjM|&Rf`5 zTlT8-yRRyCMuze;OpN#gzCcbu(3xUt)D;WGl&BbsM7`$RFu1LbFcx+?G#O)gQZ!5g zMieBc4I!uxhaq2JpY!p3ew=+FQ{80}FwsIAvrp7^nu2qCFRfs}RZ`fjZ*+2~v zrAGE!x9pTD*(p=lls#Q=+sFaoxh>eei%V_c8)NJ-=i??N1|yzH<SY;bwx#4R$`<_ld99cUy6WPOociMytG`e#z46&MvE$y;kHa zclKiAx$gioYjNb5C0m3eC&5(-6QRg$5-4m}+D;!zgk_o@Mu9Vjzz0S6x7GTIpDdBO zpIah7X-I2vrt6rt+jM}wg4F$eJCljq0d!WRPZc}~lTu_v0w~AqYd{4Dh4Y|dG26H{ z!qLKj#6ErL!9pfG%a*JrK@Wr~dZPstJvA70tOrJwQEf!3ce7GP71*2JOy9oC_U&Zb zX`i97qu`qT`_-3U-p{tA@pyWCA^TZcNahoy<0x3B< zsT0l?FE(FlSz}g=R8p$UeJ$f?tuRbZC}Ye+EQZ_Z9l|Dgld@HKNY>e@)nX}?s8f=t zVltacB?W_uX@YeEN#NE}QP|Ia+0QvuHcyTAW;?Za(5+x5y;~(sX(zoCZj;`?x7z8A zwLwdmRvL-113PRXMl40!(X$fB9+z?1;Rm9iSr@BBZKqQn*Q7?NSwhL9TX))+YRX|> ziZ)bxI~iN@Jt@X~-J(YtaF1G3o&K0ObNg`T%J!;juHai$^m>=VsV(X6z?AwCx%73Q zsn_|Aw6?{Bc|9yNWS2^BzB5k9%5J z(!dVkfQd7jhMvBaB#au8M2PKnl26Vqb?5XUGl=v=a>`@LI;rEwZ*Cen{@23EA4Z7J z|JX-7{G-OC>n>bzLd+5(doy4CAgg`0i@()3X4SvqHM#lg5_W`)A%&tYlNF~dD^wN) zMK4mSmlaXq3Y2M!?7GBKa9v_anocKWHJa45E=g(8#C0PPWnwUtNA21EIIzq>yVwjI;g5zBk~ze3po1{ z_weH;TZN(_;2hNVE@gHE&S9I97*U1&-oJZ9m69k+2g|DDyd3`B?(Q56mZgI%HIn|C z*BGgiElzX}7C*k*fx+B#Fc*U^7W{69D>MJu4+^<(rdgnzumzIX?s{6F9Z#Q3;)Jgf zSK?$h|Jcm_YCc+t?@F(M1^mRFsP$QiQ*}E19=~4{Rnckm82#cl&u+_87Qy53`l*(i zu#Iz!^CWzAQk{OPI@vbEG0ii>JH2j6)=xnBOjpcM-zfT?7EJ+V- zW>~Y^F>bw~CC#^~L5d?A4%;x?wL_(aH;=jC=K3#_&nDNB%l6*WFuM0O$?K#Ji+#@S zg-;|qJ0BIu`jykKcA43kKwaua=}Y8c7xW}g-bxoW2E-8C3^+s1h^|N~ z_QYcYq-sz9*l20AXH={~njEQ%Es`!1R!HlG_0p|yr| zNdqLYLAu$yDfZ`>7`-3uxQh$}`b$W}W{*p)qcMn1C5%anw(1ituPogXW zQhqRK6{wOQl=Z&swEMEt?&~_@^TixqHd&6W=s40Rh&*tNi;g2JIxLVF$R^HlCiQ7W z%|)~*%y}Wqc_GYsAsjaz`*;~`kemZl|3qqt#;73jL{pqOxBYTt}h*_en`#tOuLtXW!h&)xU`@#*B=$6Cnn zXPKm3*!juUg^!?sy_x)w_}`g7{p>k+H^kReU3T_pKip~eRiJ-tXI?>tjm2{dD%6Z`&G?xAmz}w>bUv0>Gd{~t zjKVuSSV>uu(3)^_V>mQSrJ+Jc(R>a^LcHmgZ*_tUV? zZP3}-_tuhEuXlTVIYAGjICJ)eyL&c^9uI``xEk>y!&sDHmZ`eGy3cGCgE7lpy6o>S zbXhgP_lOmIx2WT%#SL2i;{4`(AwSPcyS=dIT;%B%`czj(9UC zXXzhtam5mkvv*`wCH%YT^k>sj*DqSSU69!nB@9Z!T4h!H+wA?>f=QNeTg!s$t}my` zhAXojoh1>dQuCbXLg>1d+WKzC${x4J5fOS(R9+FT$oPBz@V#{1!53CM_v)A)lSikH zADDdM)Z%dM2jt$>o5tRDf3j5S828NbyI#+Y=8wH7xrFq-W_>@S+{f0bT^Qu@a|P>^}A8_T}n<=A5kz-sF$bbPVI4>!xCZ4!{#_Y8;E8D zv236q8;J1fPZv%HqS-(!8z^8*ID&zw0VZd_qrVZB1VD8DIst+38`oq3)026c7*)zO>Ho2;8$!OWJcI2^P4V?KSXki-BA zeRi>|cMRsB9xxX#_h09y{;1nr94v^EsN|NIj!eH&3l{5xLASt-fjH{3hV(%b^BVa3 z#*(Ay+n*?o=3C50DICZR`W0Cx3RFj;`FWV8lY;(YUxKmv23&iOx}lh#xN+-NB^nt| z8p&d^k?2S}X-Qa$*(2Gbk>WG;*;oJitc>crKCjWoppX+q&25^=IpIu%n_#3)yz?UR^eyP`_;~d_z?!j z*(ji#vDa_xbxS>a1H0sun33)gE_9B{AT2M;oJ8jr@Xu)YSLm5{1TLq?Eqb_6vE?B) z{c-b*XRcWE@Wk=c2P7{z>%4haesjzH-(M?rShsI$xwonxd9$v0#kD`){dDs0caS&K z3vZY@q-ogjc@fXdc;)?b7X4xNc`vN8Tz})Lv&WT}FX%B~*TomT)U@n#CRwFucXjah z!0#n;bX&90kd1{T8pPQL{vQ(R+iBBIE&bl}ah*nJ3HyeL zkX90 ztn1?M<6U7JbtH4ebxFTu-oE{Zzq9Wh(DG+zicVrm7-H5su}*nb5#8;X)5QvLfHFcn zQ@Pms8|gEvYyxUyKi1Ldo!OPcndM3hoY>8J?~KvxPL6i%^9S&Wj?e|FC&I5{~EfM5rddH-$*YbhOTAA(BNX*xl_wX z`i09F747=&mg&*-Z&2gVK+0_yL%$DhoYEh0*~G>Jvy(r*_G0pf#RtyVe#Ps%rH+$3 z-c6po|3+f|To`wFUY4-hAgsvd2N5$tylYn_2ewW6{_gXoX2*Z(Eh*!&}|#k zb!Pibn%UBaYt)hv{V&=wA1r^7{_M)YzoBEtQt4HIuWGgR6Mylc8oca^_B@!uu9zxVmVk$K?nyyo>({D8G zHytw>HPd(#6{%67nNPm-#AE~oo2;qfFXgeeL9f>o$*Cw3Am3BTNvWjAM}4jtK+(@p z$Q-Kh1I`{*;}z1ZY*a8#NWx4LJ*s9fZmJb9*n-%kIpU*)}T+>@3UR>Rt;? zqzR~$ji{hfR2C6YQL$o+67!52lYk}mgtipXJU5Z}p6!9LB$BA)i3SUizacyYcJ`g~ zyZ0`$n)mtq7v|hEcgnqU&hPyC_jlfL!ExHi)Y*+rUA)MQu#3)!_;_ZlJ>D4`KbJYj zKG!)XZapYHX!=v_wpu8e$VUo%K|7s4U7HY@&QI57N9OVKv_+9+{4(v@h{;E&8<#A@o;%ro&UJ!+0kkM699 zBxe~O<18Y)i|+a%NtKa!I1-6Fnk-jF9MW}c%`~%?9kwjnku@nE;Z55jOpM$T&&Dm& zlx0c6u9!=evrE&5^VmrEPqowD7iRFI4!3RP973(A2GKkhgnm)F z_CG$VO^#Gh?DIcNu1TNp>C2_dUMRg@FUG>9R|)6qeBk~sYS|C_lBF;IaaRxf>my^h zuDi4I#~yu*@j2jlLf;`a`#fX$URD#ltbj>|S<^I z7v#1cS6GQ!lR!}wH#&`>k*J*=DUFmz>Z6P{r#+-Np{!F?aA-rWws$i*>i$voj}jG1 zi%Ey0?_z0l6}n2rbzGy^pf(wG&IoRlG)kr4I8K_*bxCv7S;lndVl6NqXOS&-oj-U)pbc>NE?0GS+OO`$cK1 zO0*^X=bO#6<1Z~$VyaB`{bgtQuo*K2owGv+Av)E`in~MRXHnmZ%gV z)6jKfS-S0nLMoXNtgEaRQdA^ZI3z2fP}VEL!D3y{YHV23Si+`R7UPhv)7o1t5fmW{ zBCEL?*0!Vbwq=zyO0U8y+tKzd=lL9YyQ>I2t~JHlWw91{ldEKzL^$%hD$0@blMc~k z(iQ(CaiHr!7wN!C=^C_DR`Y{a1;rMTKhvZOp+nkPe()B;&Y8e%J@3%~NrTa*QfFzR zh^WC9PZb@S|B@<(yaPwm{ZmD$I#ncd-@7SIUFW@SCS42>qN-I?orIW*st#45JxqIAC`QhOV&oj{VbUAC$jVn8u`a)>5VxY^ zQX^P?GHx$ve?!W&nqjA*`nUV~aQ;8mgm_udiL_yBJExpg-Bv?ZP-TRvIU>iloW`H#aoK(2-iH5k_1o z5EAR_=iKLL45aTsjkQGL$A<8CO>oQM`)I`G;E)MNDV| zW&*~(4UK50sxcC)B8~W~DdUd)7neNt>P+^j9`@OJXZ-3{$Ha?iPRL!Q1vn0t!WcKt zv3Z0oUdS_|Lzasu{F>u)h!MO{H_cU{s{M1)&;8;vG(jP#HWQ@ygzTzFjoli#3;po@ z_e%@JsrP^T{{575)|VEb9=KAc8{_!AC|E4c69FplL^=C4$L2&D`*jt#+H>;5G$HoT zzq$mfYHPJ?+Nw}b>5BK?M?WkrxL>HJ*XaLiX#ueUzF=5}Sf!|wRx4o=+-awjCH4** z%93Hpa8H*O+;kK5mz~kSpG$KmGYw2Te#&i@b-5{_Cz~4erlz7kBGR53)il1TOYdr0 zs4r-mJM>Qdw#J`EA5K24M;d~Zw|c1JL3>Xmo@v;cc%fluVpqc-A|EtJr$-URkx=-N zFvD?eHH+_>hmrJ4DQqy_oq+G_1p?OXlZyxm?f5NEa2 z7GlGz!twJOFK@(+=@z5YxYt-~^c(zIW4-Z}!5RYzyN2dhs`)&qU318-qV*6AfFu|K zg)A6#RA(|E{$&_xHntr<*M!_(`h;({;e~k>y_bYR&6}rI=?)+_)VbZAET8G zXgC6lyIfT*wUvD5$(Nq3RLjw+t)(e76n0eW*#_W({0lV}Ne}L;HZToqx8vEaQSVY@ zdA4q7-TFGdNS%Mw&ad0v|6b5J1W|&zVMU0NRn`=S7JG|$T@e*&!4Y>6{puK`G{K5=Cw15iP0?ebO_9bDLfHOj;fQ2wvHDM2K4K}j@o=>#gj#3&@|_3z^836h5Cfm>_FOW>f%I?S zxiqbp>CRCP0{9o&;a^*!-b19GjKSd$jYPuHSWO)(hz9nc2jop`$Gqnku77dt7310# z?YS7Wj=uedt1C9dFWY^`?axfHDUE3FP}5~(gl}1T32!Nj4{vNI_btqVM9;W z=9J4$IB8~gy!);R?)hg7S#j{_ttX8{A2g(`hKViX=FXmc(p7Xd-9}aujjUQs1$x!J z7V(-{%eV2PdA>8VA%ioS>U3-R)bx_fnv5_i)Di7So*6we*(G)9=bBy7A0!t_i}g#) z%c7Shdo%BAdt!SM{~h`=_GRMZioKcsOd`v-m@VOi-O?pBedy6RkYmCAWJlPatjHSVWH91c9-UYJ1* z%Iv5Vj|w3JN?FtB+^frwjiD3`kc-{QfOKLwSPz^RkOc=vt7pBiUMZIx#=QuwLF>>4 zbP#bF)QKh|7Ev3Tt{X(xR0XAQ1f+++(|{aGdI(65YF0gzw&AT&dV44i$!?JFj1rY& z+Xs0EC|ND_GR@%JK0=v&gQ?XEb96$IF+dK;Cz$Rk!qM#!t-~vE#A0fy>)CLu4E}Y( zlRZl}Ua-E~Eq(o)7Z>5ej2|t3?w40Ce~#bL_s@GL-}~AXrLRiw{T%(|r5Sg<`TFix zpuW?T{{8F$!gZ7AAI~$f{)28cBs9PX%Fvq7THcsSWtM%xxWPoGifAg)62j^^C#{O{ zG^ZjXB1&|?L>Mp;5Ky#Q6KP>#z4^{7o{w*5*Kqov4uG+;hBE2XLZ`*1g{H;khUUf| z#t*YU)gQMWPim5$P!{3^>_YxZZHc~0e?r?LZ&kKvT2#AD`xvuE^?Byy<_#umBFa1K zhC+VRTyk4$n03rv<{+^bywdN%J*LU62Lx$u4>TFG){uZNSEs;tb|~Pge|K*LTB=p^ z8Db3*Tg^4{r_Mkwctl+AeT)ESo(mM=0y&HWB1i%ej88{^+#*1F5#V=`+Fc^bh@B!9 z4TwK0^kX7OC()~01@9Jzr3yO-+;JX(lqIn(^|zjfngkU{25J1^slLZwt4j&%x7` zv%=HT7vp*SeEGug+;nf|9sb?W2Z>KYpM<}PeUbPCcuO>s$tNj8nvkU2NgRS}^&!zw zxJ{pcN9$w4PF68lAt(#K?x6)R!=fZP)+ zy>$gN1B!&01e!@y7N(SO8fplD>v4d&z{w79xf71lvCsEP(#LUDL$iCT+NfY7lFg$G z!gf$O>~!S(oj1ID<-&Jvp8J!Q&3)PDu3Y}hr>ckr2$*;a!|rz75Jx76_i2{*dOd@{`>QvmA*pZzr2eKbZoz}>DCMH?%RW> zY9r6SW98H6?AT*HC_`kZh8jvAmcF&J>vvp&?!WD{OP-)ICq&3$75_F9Lyc}_SVm@| zB{4MNCYB@~)_$fxtxHM0LEn(*O>hZ1tZp(>sE~A4Gt&x+;Cwj5u>zy44Wn>>2*xnv zaz3;K1~aC4DkjIU_&x+VTbqZCEI{s7KAkD7VNk-Qt2g25Wc4y(h>tWte59JLXQtVY zjC}3KkHdca_;V2RkfI6Y+K8SHRV$ds;)xg04yKAZj1(rG&mS&da5SDw%}iKz2l5BH zXaJ=H>TeZoFPl7U*@7$z6484t*-0_BV5Sf;?3-@95#`BxTuKeC*0w@B4P+5MP1$sW zmdx3-c5Ntm^YSz2q(%-u>-1f_*q`3ry{Ite9OviCn7J3+ee5E#@=h&HWj`k?uaap( zzjx=VDj#lEbKx`9(P2TZNK`bdb>ZfkqBzN)ulQ6aJ&Z|rGE zheQy?R+bqGf_N3v%j_mb=XQLZYw_u{sf?~pYf3cInrkgDZuWJ6l>El6hY&+99^V~9 zR?Lmfjjf7t&16dOjAr1*G2q6r0d5=vZcNL7z}e3|ZcN`r%YyjaIOe6(Lgz@Z){nTC z0Oc$*QI4t305N5Nm@+_2ncA1kUFJt-zsY6HPIEHRG`z}`z^hGIqh^xQidhW>AJX*7 zUOgWZc(a+vH!rKA>^VQ__%iMGL!MSShXxi6%l9y?lC#gpK=1RSN8Ln($0+OuY>9dg z=S;bDj9B9k(X1=45OC3Yb@*w^uDd;MpyeC>eDJcje)!@wPt5=Gx_|%tp(n0e`P8qj zS@G1l$*H;F^JcYgxC?cB@E}5WKe+1H!f$r1c$RH?tM{chUVi0ex@uQ547(p9dG|lh zM9Gqh#0pUK3=FRv*T#-!cjz3Pio_Cym}F~qnB@^;rg<@}Dq0|OwP3md-q!?if}HHO zjwtlYs8>c&5V%nnz*7y-hUvu0)Pl7EMg`iuoTTrQeW$NL-bE)GqSsKlh61nP`QfdQ z+B^xuj*W#8g$>bzQM@F&F1jJwALXJr3{xG3DGkHqhjU)8r$z4SAgzO%W$4CP9HgcB z`6fr)7;p--a00sklz+iSvij18SFIU{U^8x;#JAY^}0R*^1&jz4=e&7>^ zV2C+G&{9a32!~*(@9#z?Pis83dZs}%8nJ6^n0g^%ukN|Ncloa;^jx`U$`3n;9q{#i zU622)?>zj->T9Rnb6wvHgge|$CbxrP7Z?#e=_aspJmBNQi4{LeeJpS`91F^3c^wWc zB#01srMI9JpcSDdAMOiO>AnE?+!p|!`@GT+7z{NQS^-)STI4O*Q-ef!|H`xjR~`kK z3M1(7PnOrn>*Nh`ul$jGP!<_EBQKFx$!q;nd*yyv$;d>17dgzz0!@x}Pk^glj~Ia$ zI7JY1Jj1Q!)^QuSUT!ZZ^l}F|%y3z5H+jZ!o~eiFmHp}GVEQ?QUY`R&!3BbX3qtB} zp9&=fZj$s}B3Rl1rPs(*d!BZ`P)OI(ayRbaKS1D<`M$lUr-%Du*RG=xuI}g_iadX` zG!>14*>uo}?ouyg=S6rmFZ6AAeyQW(JI@%_pw+$eo?#5F2CWV)$LIJHxmNx*o{vd9 zFLE5__z;716|-TDvw2m7A*~CBR29UuZLT4bIu;{bP|qpK8Wm;KPIa=%QqY6jPKVG3 zL4aYcf=@@S1Z!WTqo_(?=L0WQ6QS_0s>Xhoi&9&nRV6=RSMu zt#7Y=$QXYgH|OZOofGF#9!b^``wc}<;a9e@K|uX@yggVgU%SI#VU^V<3~CjEIwzbh z%#vAC{|A3qVC4W^?d1R}K}QZctY5!Km@$LBO2Lkh4MEW9;AW?u2B8l2kfX!H35ZG^ zbZ;SN1dii5pq*rIaj%gy;9l3ek_Pj2&hJ=6LV5g7%6w^ll7V0OyOK{rhFZD zHUE(Oitq>SJz<~lnfO1#w^GDW6rN={EC?dq@J-=mNy>>rSQG`8<8r(b=6OXSi;bfp zdyc1JSXE^dZaXqvndiV2TP@LNqqATOTVCSz8lp=3s4$>D)vNQDV?3hvh}0utoI{9c zb)C#)!qCW~bB6(A2C`y2$P%ni>JcK07z}I%EPW=S>3^*ndr>(-0X_N38cj{=K1@@S zh)F#VRwC9?tVrVmv_2v^#-VVkNC-^oV4?LR9{L0sW#n5}EXQ@4sZUIAua=^#$juc+ zS*ob$5NPzMqA1Yh-7Fk7R{0eZ0cO$7_`xTkzjsp=Wb|)}(!+ zxvMSoptU=`H{KuTvQpRxM;&6%AR($NbZ^0cXpLaS8Ge>5>D9);hKYkcqk<))f+eF4 zSTZWG5w#lL;isz*H3uvimF9y2aj1$P^Em8+>{7v4QW5#DPKr~u)l99L_`x_{5?>eJ z5buq1aTd2mqChuMprI&GPc-MD5^dWD%l=DaM){60W0x5-oX_2QUFW;T(WDqu?;7~? z%$q}C;0$^p?}0hIcrwLv3|Kf(!Il+C5fxUj>TJPCAyaXDf}zOxZYo59F#G^p8C9%) z^vVzBJ~G8pdYTrEyW&Z%?t%5AmrNXfUEdY>w#zO(e7yx&9!t}pjk~+MySqCCcXxM( z;O_43?gV$Y5FCOA*Wm83Pu_3ele5?U`*T6{bWK-Fbx*-F!}NX7%lT5!Id<~?+Tq1= z%abg`Xcs%|yYk&nbFJCDm^c3cgt-YyMUm9Rta== zD+a%}?>nb38$sY@d`KWASdYMcQI;(20~g~a*ZlR&P-N}~UltEUD#<^eV8a}nPhrq+ zK;)vTS9l2{Osqc2IH`T{#Pxp7>-TAa*7FeEB|wAk>9_EEox`rz?VbWpV0%nQt285uH1r9C6XL2jR_e@kQ5kL;#J^siAI->aM~`7 zOR5@7I{3HoPCvh!@;Vsm$!j75?glgnq*eV{)xzdq5FL|~iWTT>FTzlaZ`+|H&TzN& z#f8F1i!`u7+QC5u;eEJZp$U27($6hrdq1zUD+oitef#mXZr$@y5@D2KmK*w2BY$^Dg!$l6y{ly0)AuWE- z=?^7e$0Uy`@o(*w)3!QwxbcEhi0-G}Kw6EFA^q!0MB z4C+IU`S+@&{#{|wO;?`WR-@M85}Z#~I8U!&i!A52ccFc#twe6BwZ)CQ{+O+l-p;r4 zQ~#}ZOM@jB+B#3;_ZwP5TKfL^$mCfhvO3ydZ^QhO@+SWGhuMsuW4xE|kV`2J<7&K}ZsV+XTFBf~HpmxtkX?fh1{ z!M-_ZvCx>Q*Qeeh-BNxPJ6=89YV5@OGHN19$<~Ltr{W1Q`qQyw_(;lSpZhzWTO5a^ z0Tq1;CJpRT=$c4Rd0qKtNkZP*C~`|vO6KqG&ad#3)@e(1Rqu^AtmnO9kXe_6FYPzY z51Q|L@Y$z+2AFnGbP>M`R8U>5gX2EEL$@iR2I5hI@~IV3Pehk1>86u@yJQWLH@P9p z<0~hY5Xb!%V+D&q&5fLhyhS-h?LrC494BK?@JZQbiS$P0y2cd&Miz-j@^&4%JIA2s zFe>~7#X2scNNnZ8r5%t_VzvSv6857~Q#X)y9y#%rrMds~$!c5cZ4q9HWp`e5Q5J>V z2GyQQA4^_v6QZ%UeR+NuG5`M zd%dPbloK#BU5GE!d(75)fH;o=r^S>grmxh|_u4)Kuh(rm^>tPDnwx(v&sRmAfhY9e zD{0i=G`-oY>*4bInbWjpGmlPO+IpXo>SA8Yf5iP=$L6(fRPIew7S8Orj<&Rb;|l0^ z1=<q3e z%hmPl-lGBSpp2%wmcygby?ZTz?{D2JQvx(|2(E+EaR~RUqPZJFiBlupd@wk@E$c?< zs6yUGv|r7~z@xJrI?Qg<=nH*B4@hlllaBE5u-w$BM@}+nk$G!FO4l&?X<@Fkw7e_@63z1qK(qhJdO8@SaJli zyW|sY6YvusWa)Q0 z8aA87N6kFmcsMrG>)`Gsf}V8B6ZH`WY06B=Jvl3vD-vQUEoSWHtQ|E+z8;Oh#{TOV z82GIwmAltT*zsh%YvGOrz<+dr$DP7*a3uJ4#?KymCR6f`J z^1R*C6)|&;EVeiaTkQ&pFzTXZd|Vha4W#wE^R;pJFjZ1O2ylWP zy=te`M7qg2kab&atfXvun!g<^fSu9li1juhx6b zlhS;Gh4;oOZWvkyot12DqE*6a3durQjL9es;KSUt?1}C(i7T=`5q*LNlSX0n)zUo7 zGmRO$cC3TRC6Yt>MT-A4AJwPS*SN2$&+tuh8x`H(-}G09x~qLAd}{E_5U8j2kEom| zs@RyC=kHBN)l4_tioo;W-$?l#czBGvUhIxZsdEA4{p!*y^zMx?oN*P6j2Tjx6$#R zsiYvFvT7CRg$C&upRc{T6nURF&+}%wdRz3E1_Hj^y}6?x$fQhgeX)vJL-~@8Is&C% z-T6Z{Y1tTqM1D1H_wDy=)0)nGGmCqi>B(ZmkkS^un%k8G5xhc16g!4Crt}oX@f1e$ z!Ms`C{NN&J)Cm|s;S!W}KWl%ivE@~u1get(W%R^_paMRgtqz07@oM=T{2-b=bbvLs z=t=j5zB5Ad{BXRzCKr2r;og7V7i09$zp6d)FdXBWUY`#*d^Tgh4BaFciUxb^q;Iz9 zy3%db8nzTemJE`Xl2`_6D_n(gfw7?NZCgzi=lCVRCwJPzS?f_yk&UPeh5{w#7j@Oe zWW9@n?i0qp-aBS~UegAe(Wilk>3Yl{UYAozqj>_ucz0w!xro6foGdCLBhSS*<`_g% z9k#D28v!3}MO~_n)gmizn{*=)XoV^%O^H+9WCE^{LnWuEz&f^O!PPX?lq0^&cVc{G zy@TVFdDq=AwDJ2*g^Px>!X0#>U>O(Qyk`N0V4|5IX^$Y`zt~fA%Lug)IpaR{I(*hQMc99X%Xt(MKDc zZGExL?TMM|>k7xVHlN_x;Ie^vxh`H_#DB<%C8^bZfyxp|$KF|F}##h{3{+H(DlV+KT0*XtFy*Jb9 z<>PF;igZ>cfS79mAz#@I*%}7p5!`b5c^d!CbbGuI%TRaK3qy{or(y3zzV80yXt_1F z+0D1|D6|~+Q%du0==E&*%FGwB_k*JM_?V#Ed9qP2L?c^__Q^j)LkDY)#YdpN6~Y-x z_rQ}Robi^FLKz%k5(L9lWQ79D$NUR{CGK~#^43fQmTFWaa`$qwsHPwJj)I8_quz)cLg^Eo$wCJA1c06o^%d6Ik{8^sCi>+=4%QX%H)WX4A?ds}EcN zmv=~{^$=(%Pz3XD>US(`A)|w_CQkmO{8)=vG(y15-cJ`qSj z^H6y$0ja(cm~6SW(qff~cpBgFt(=-TthJn2R7GbMRo6+usDdAb7&{S!LcVgpd5p}H zJI+^&)5J)7YW}ciyw4uN|gp` zS>Hc$6_rsKNgiA`zS!O-KpG+n**NIBoIr4dD=RU?upr1W``R#=x_XiJgV5wM_>_AE8T6 zw_M*^4{d*eTtb$-)8WY> zJ%tSgg#FfS8#m}Z=$f2L6O;qxZ$lD1m;*d=*}M!KqfKr#=;|tzq687O0)zgNS~h#> zzLe3E^LCeL>Cr)Whp`2{mIWt#pS;_o;N0`$#afCgbBS`a7nGQ^?4>a4WOnzcpNO8v zDx7VK2{0FD(q z9YN#54dU;G@b(JXKEB7S^%17tjyisZ>#Rr1xOvYNjBt^PuQN)rCub?cDarcs(5ooi z7J4xfw%|8>^m@rWg4I>_68jjtjJ0Rzja8R^@qZNVQISu3QSVMt-{TeGf^ zqi3OQ59vlSD?mj;DuM>1TWRsbM525W9wOkeI`xOQ8JJ?H_WZM0$Dg>WxBXZ8R z{L|SCa8FP}o%=K5Q=$`GBY~s9FoCeQ}8cQNun75 z?8NZ}#gk7|8G6dC+vs`%PD*lj;r99X8S%GVO#S{Q>@eg?L@W}Ir57Gh<}jNd?CRK% z@C1un+Am3sF-mokmi)mKtm&-paFas0d=y67lT}o&Mbqw#DignpbA7)`v9!HZAXX2( zlr$AzqV~H!9fq2n-JOEH3Xrp`>fk8liuuNG9!tB@O*C!U6&Fi|&(kVy@}s%|TSl35H3!9j%KFKVHg4uvBY9b!wA2ovr@;hNx~T2Ngx|#Q!&%L z)d_ybz~zz94xe_NouVmkr!Slw!5#J%R~IWx+(8gs=81qg98Ch>lOc;s;bAi7(R|R4 zaU|J%FFDc+sS&MqAUvyr=PzrjE{?xYQ|)z1YV$z3hhhHG)zzic_8H!(SQ1ut*ER+w zTtjnOeC5z2*Oa{uOZU=NFm~>9n%?FnYlVlJ?K^!?B@Z@BFdRlw9{NdSVFVnJIS&%c4}{nljUEEtOeuIC-Ir9XCVV*TZ(d<( zY+6vo;@9_^o64>g4_dR7t}_s=LfS zFf}54-C@k^OBIWo8DDzW>YdRsHH{M#L!LVDAc`{+c*jIl4MH18}~8 zyu6Ve;EeEpzG#J=t&D8tQ~_sfjVxS<*kBliT};gEU5U5>d}bC-RyKgxf5C~D*=WoBhz=}N@;ha}Fz#L5iAC=K8cTbT&k zTiBWr0eJL(S{D&<@Fdcq=ip!i5X6}{xrpdlS=bmjnK%LPWELhSCL(4gK+9b0+^k#x z)bk$;0D{)Z#x}?k@A3>{%ZzMs<=5i+M3z@@gx&q7>pW3I!pj~H9Hfa zdrU+C+%f|fE5L34$pL8P49x5-tZaIK{u2R!&8)1f3;-%R7a#*bdjBo_SN~V{&k?|w zn}~&r=%3n%Sh$H;|J@erpPGr-{~+l9Od}C12N5eL5eEkc12;Dd!1#}fn~0Nzg@Kua zlbe%>4bbDiXE~Ue0DT5n5^?_1`@d!X>Bj##A|kGThVr-UU;Dqc|JD61_xJ3-+Wx0^ zf6sEWu`+P6adL3{Yb;Dee{KHVw||cH0ELM-xc}uYPQY*hfbf55{^iPlhWuCe_lV`6 zPW?UlQ`6tvKW@+?0?aDFhkuQ^08{*TV*g|I|J4|vx_>;QN5suc#0{9rKUWYZHxV-z z)4$gY7Yks~{I^SbfD21Z<3Ee=pUA-pn56%GE&cx@zgd_C1c?53*zwHKQ(m_ZW`grQ zqPLR}EYA%-~t_3s&|N8o& zm8&!CYTbKx&U;B#_9RcyPTneKv6P;KCgJh|V-nG16*;91d*Mi9G)VEPAQ`MsQOjKrjV_Hx~d@p7}pe zdB8$Ybx^an0@#=V0?nUAp#1L$%k_6v{Fe*Q!p+Y0CzM;+x|%rye!?HH>Syl{tts*Bvf0Qecc!nTw?E? z5nA=n3+Krppd#P}b%SQpi?fmBBmJOv?zkC$kL$A~yUs?w(FrXqM7lg*r)mqART|S# zd)e%{R@3JwG2l1oAL;&rIH!dF2Pc%$IB}_Mz-H${iSrgiX zL^+^3d@}n(W_z>nH364rhoBHHTK3D!MmAIank&fC7d|u0dZ))2o86KoN~3y^S%z-> zeA(|Mi6x?DF$&wBp`kstApy(U*(I(e62pO&)pL(Ko{r;PK&=i~t+sr!ArQ8!B$mOG z1-YrgGf~&8R9KMrPqr{W!lDhaz0;oVFfTg1#Nav*a!WP+25OJd_iZD|-R%ND@`E~D*j~`~lDqZMWL$lOW2O9V=~DT<*z&#Y^Hrxq<8r|R zTPEgUl)o%|YV|O6?LFfFXEOe$*-w+7Cav5E15RBk?(Us=Zh{vbvpQ8RazUB4u3s0? z9f3EJU{LoTMpZMe&Gl%0>}32b9prN^V?)PC(8yEO1S`9>c5KG9D%OwKYXy7%N=3e4 z2+_QoeDGuo-O#}pFMX6Q$dcw0E>z1xRCmI=4(`y@(`t^Nb z#xGdmOJm)DCu9RTY|D+G{*Yx1{Sed8YDS)|RigTgxHi5DlO6DUeZOCWChbd&Mmo{- zP|kSJ!k{eeC!x#)qi!?H+!$jx_A!B&MwtC>-&7Z<{~i^_ z$8G+g?=C|7^WrVG<16(GHq(y(JfiKRC!GiA%feiKm>+!Wa&f3&s7}L&j>03heJYC~ zeA!lvJxu2mUGC)U@t1_@cq>jrO-A*gm|oyq=yJO>ZC1Hj0`4N~r-tu^=%PhtrNLjK zqG2G#VQy}nhqzY@YYhAIGZXU;Z@o4c%7^Tmw0}?(3)heHNTYeip``Hd=@d_<9nd)jw;t-U9uXV$EYf0Pys1cUBOEh{&FZaR zW8}P-vDR$ZQ0b@`6O)IVg&I6tk-=SL7C5KP&g|qWJ6{D&XWSDw6{r{N#i6%l7RXJH zJk&kgy?Vqx+P*4RgJ1)8S{vKJ$h*&tKQd@njLVtx%oe-OHrhnhUzE*Z2Q}F zlExqq3X*wCJQdqLDSCkt$60c{X1+yp=z{RGV2J(mvofQR@ejiU_^U$(^g~0kR(od? z7J>k7EBpcs$t>gMQ2vt>|J|JFyqZ&g=csP-kfd&%h0N&;2A|(Ewoa>Kba)t~b)Q%5 z?9bhP))js?KSujA?;ANbkoy3qz!w4AYZ?RVUdmY%#q^lNgy>`Q%b;_cW2_`gkm}2+P@zIGc)o)I}e~j8U7l7iHv%4#bNVdgTucgM$;ByR-%0b)Yd~ID2r3b->bg$;l76XA`c0X2gEv*PX%*6Z*<6wC zhxcz7I|XlKb?pkMfWL+sp;(AvIp(Bxdxj~I!YDkU2*xG^`$VgVRr63t{AvKULD;4uI0U@$XAq^K-4@Em{rLu{et@uH_w-K*+x`n~$ z`a;+eV8>CMDLdlt=CR(h{Kih7s-N?p1c>o2V?R^4c&`y@KnGE$u@j95Tp!GkhMJkaZUL`7Otm ztSxaX33DQQ|H~P|M}e3`*#Nl$Nn^B5+8icd+GItmr@%Rjdu-qRIInT+eMiI}MDO83%rFRl zIO@XM;nFd(5{|xsW6$sWU~Uij2=U0_k@1?t8&rIF$oic6X7={$&E1dlv&=Egk$Dpl zW(JCXFndsXr$kCTKZ5}y8WX_9@J|)1)U{5iOWsWUD6}CxDFME-?_!3nSha*Q8aB!#}=lz8sO8wb)mBf;;eK-;iJ+ zo7`b`4uK=pNPzid(}EkmX31fld8)Ko4_tPi<&;-D@_Z}~@0|DqaYjL6|3WjI z_-5t^=NG^j(nFhBfL?KLFF%a(NKq%Ro23a-PkbJ4iu9b=yccsU5=HaGzsWi9YRWo2)cBdq z4<_V8aMzzcEb1&pJsnOuNIr;R6yBiolzY|5h1JnR;1`SXu90F6?#+a`8N#^3TQt;o zJxCN`>>X~rj=Mv$HhdmFHyqy8-PTBn-mWA2V9K55jP87?pEL97WREAx??mv1fPf;i zu~OWj*@rM$DJd{BxUudCR!@9&XHK?3jVX)SlXlD=kEayUod}Bd&*{a zc#$5(FXo0?TLauoh&EK=5Z_=W4G~p~%xe!m0^X)6FtEhGjSopJ2eB@KVJlMm$WXyW z<>z9_U^=}z#Y!7`@z&{EF$K|$sAn`1`figY8%p`WwC>mqUNhgM{fz3evM~m2qwz!T z4)fl*6*^!{v}Pau_U;v}U;mo!LJ||@SsGMHCQZq_FO-Dl?nNXGN+p()hr+nyvVDgl zfW|~YqZuR2_}T3v{k!}U0B&qFVaJE$QSU`??F2@P*~a{yE;eVWNc45rD+1966 z+NyN;kKmexVnpq`yV3<|9{hNJDI-HWWHEip6SpK&j^F{nM^Cz_F@1KgJ~=u#O+Evnpq`jC9kew>>o;vELX_A8 zf&oAm=M4LUz-Vov5lpY=PyO z$+qo##sl6)O~>E;R<|H)A@Z+4FwyW1BjyX=0f@hXv5Y0V#thIC0uBQR-EXmG*owWA z=jIilZKSceSY0`wRJQKj_wKyr8uRDwyjaZU_iHt2hGCC_sauR;_K37w^uc3+61}K= zb%6)GS3i02G!t?LJR=Wy&-Al@WueLn{`$UH%9T5<`uZ}$L{A@E2xnz4xZRm}h%dC` zx@YIurS%$Ye^w1`G7VQgq@IAv?5>e+ZHX~#zz~VqFu>3YA%HOG0~oE>wR`I1q~@*r z?#{L0>(t3+!ptcHKAONE3mFTo=E*FX@6*%fmLazO0zV;E2Y}H|{JLvDWa-A)s1`0E zy*t@i={fnQbo67Mr$8q;EhtuJJ!Qto?k#J(}g@iAFqJ*Fvys1LKwTcQAp*FB?F(Fu3 zB{WjMJ+o|oI|3M#g<;Fc$Y8A%lJ%h!Aj!Z$D(>&^oqwMh3p!JKetzB_(wt7nsi}FH z6V2p9Y|jCoI23V?HP`t1m0OfD1yc=l&G4WUlnN&5>H!1YNO*cqTwFXMu<@-b$kFq6 zNMgB8X6J@DU9|gsw2>ORw~6LKSQQJ~0!=}cF_5?t_U4J1nP!5wh?W*M7?V0*RYk*g zH?_%1b|G+jeT>;$ogXtEyEU39VGIrrvLhw8^)OJ>w?fa?aDzcBHVAzSGFcj zK(57E>yNU8#4Q3ni_CXS!S3vjJcht5g4~ECR9g2$^2I3&m7Pd3e5l|9%eEnJ+#h%14zBDhF^w92hOHbqc3t5ugg|$> znXns?%M7O}GNQOthFpwrcE2)_UZYAK@Pu+W>LRqZ!=}{gc=}j25|m z`3eHCN1TLa{_zO^CVPa=w)Su~dp9@-nLwb95$Ud71N61~u;AXNCF^dkBY)WjI4992 zJSWL!@lL%F>~2qc{TtXtunr30&^wNOs1EY_4#zO$Ho`FEjy&BFF+5>d7t;Z9JFXM% zMsPd+HR(pjX7&@32mhmyC*(%_6PB&G58k!t6MZwO05BraMMyZ32>`gv0MEOfI1Jft z^DC?!x0P};oRWP5v`^Rv#+}F=00{kc#kH$H9DK$0hT%lW7uZf{94WZNkhH_v0NV)3 zgOndCKYV1!xqAyhC&L2J%i^9e*W||{K3YRtq8__?p5PB8y)X)-y%4Xcm)p}xJEvE? z!-9jX5e`C#yTG0p00c9`HAgr23~4VsBiUw<$F}&e2m3G%(kB=rDM5$^(pI!d|(cweh`;LAMl%^d^I~q zSLMTmJFo!0GkJHuC%(sbLLxtSLK1?&c%)ARLQ;ZIK~jQX1*AUVH&7qg9>7xXBhwGw zyQ1C|Wak48N9qfnLFxzvA9ixB}mmenM$P>=lV2?G55RtVjN=UhtPL zCtP-Yagr-1{LGa93@=;wyk^b)s4ZLQTXKDA%aZ?;SUB0THB%&Kj->lz?QpNeR8KSSN;evK?PKFW03nHID7K?Ay~6u z@Q2#$uU4Kv>-qvM_wOX~^Y`87*2$d$pr8Nq?IEY5VX{vUo_kECi3EDQHs@5}9Pc4B zs@wwWn=N|FtD87~A%+MMmTGkp+Ll_kKE@yRy#Owm@HAsOiSSg_<_mkDt>-)=LCrIM z=f25=((n3fVl8GKm_t=dl+Nr~JMl+29%S4*ET15Tz_>kv1A?=PTNCJbL*YXl$VVt7 z+XK=oh)ysb1f5T)hXZ85L;jscHAJ`X5bE!uIBGbLNXnVW^v6F7*CQ|BT|wxCH=+R5 z49x~Voe39g1aE-iWAv3u>|BJm98-B9W!mxp&%FBDxLUdT7~sMa<*wuyrBz%bjB z+!YjSo=r))vnu}3-%{ezG%@lmH>PPZ{Fqufo?1zm(lp~GncJn|N%MCp|1}cT*EwXn zbj)x`6-fb_i=kiz>TJZ0RF|p~1Dl_(6YNLv;xacQfzj{Zvz3RC`dpi7-ZnE{;P)d!3nWVlj^@Atd(cHHTZc+v>Klw3f{L+v9g`6s8 zf0ObWi}UprBd4^Bqq-e3-L>}(o*xGf*^e$TaWzHvrrPDUbib5Mw#$q-%ZYW~RwROS z^=r_Z+d*Ng8l6qrUD=@CHbQkFvLOBH;wBg0&No2YkzP7pd4^6t^2$4O*sF9j3pL-z zODtp0*s^52txfI81Y(^ycY!u4)Ot%<`I^zJ2XzTj3W~?~TClXMq2DRs>;{$ALr7bo zC9P38tWmvDNAW276Hq2&6YlG;ITa7a!Q=34s*J{DP-O6-vGad<#YUW9(qsZR7 zeW&=zq7Xh+XLjp~BU`%k+HpX2G}$Pdsxx=;kizgai*~k?rD7p@6l#q}QTNg1VtYR^tSClBDJG(e-T04cMB^-ZAZTs zxEF#u?_-$72fr6G{2-2${0sSK##vw4;S&{CL~R|vwN)cyxd=C@AM2~cESHf8QlmIg z@2|(Gcg$=Q?{{tZMucSoYuM8d+4-Y4P`)8`$KzM))@Uz4R%Bz$D!h260xQSC_~+u8$z0JUHG}QxJKc`!zzD8c zT+@qR(K~6IQ_zpqi*!QQO5my25{dwVEsCSWQuL2lpjvBQ(znu)|= zl>s7JVqk3@pu-UdRc0glBP`M2rRDJl^6Ptzr7%Crqo=$AM$&p#cPXRv*k@R{Vk02h7!}RCwQ@?w$xb6Z9`S z*DrwJ*@pUy^_YzQ4x&?Gmi!orJ(}}Na!KvH{0X-73iZ9rBAq-+TNLkzg_u$K3hlg* z91gp+7n&OEM#+x$aPhGtvT)5$ktMdMdkLi(gaKZe;;MV8ZA;*<#Q}UOLhcv|*)USE zvSTRv3$DNw1uKs86*z;W?~rq9Auf_d=ABM6%l7_~?HgO-59B>Q>_H#P$L@veVHY&6 z=*Kd1=tYylN6YgtO#a1LsWi@now}~VuE6Tx?JLp#*=ptPDx|AFpNo)9)fMas=J|gm z>ICU)NM4ZL<^3Md-K$TWAQ(4ONB)W;dBJ?=;r@iUv$sXjGsgR-Q2b~aE*PcnB59B8 zb>zO^dr{Avbh3SfebSsFi2geDMvec0onhx3E=brTC25~=Fq+FdF;M3-{)6;G=iPwxSz}xiE&dTy zkI&0t-!&1tYIjS+Q_#Hb+GCN5POuKKOW7~xS>dJaK=9bVdkZfKS9_dh~kxC2)rD+?KlWb?35MT(_ekW+L{A-))5~W8!D{TWs9+a!K5iM6`b~(WxKhBK{FVF*C%X#ZDU7|f zvA&84=a$5jNm+wyZ*41d6aM_SLbhxs+1+Qtm@o7Q|a> z2`HQA!6>E4G1N4N<$?Z;HNC)qG)li9CZ@MMSXtOwJ z_2~PLCTSvlX`uyr<>>pA+GdTr3tG;~T46cgS;VTNNy~4alE318eFywxP~P-)YfFkt z0X~u11;%1)eWzrqF@bxqRh z>dr$rJ6b%bq)CHYVF#ezj2x(CVWNr81Q4PaeVdXFH5|@&DzQ7SJ=LrS>aBA zb$WZwHc{9yBJL~A0-mmf0Ulu?<9n-Ws%Q=o?C_by%bsBxR!Ziv4+UF!PZU>5V#v0J zNeBzt1e#UF!)NLe!pi5aj*F3(O@ACP>r6A8H$slmRgDP7)X(B=S{#NP^m*1kmD(J9 zPo2cBiJ^n6h)0*LjZak=O_M@VUs7HVu@Zl`!YeO5PdZ@MizM*D8jwgpui?RnN`P`! zRC8P=pL1{2E3&O_C|XEY>NFLs+qRk85s0h%P4%;N##PNi9bvt%=9rEk>CUO^`x}Bm z1Defojga!;5t;9jc0?dOw+>93YV%PuW~)X-MyCZX#Y+kBE+j3<*LMrFbgU|uMUbm!p9ara1Q~Eong!pG|zgbbjzb4Ou zQb6_BTEAPH6@SY;OK=}wms6PNOLt?fk*lNFg8KwH683&9~#L z6&LK~aCLqp-{wJWbCo!*d8?XRC4~pqq<+$TGwg(9tqc`xE=m8_y&uzU0iX?P1aM* z(NN@ft2nw(1Yp~P~eE=$9xYQAbXd-0rvm3X=!Qv(HRDPbuV8YxaYPdnb5y0VrN z!~)G`vLvsmHo~v@;QhD_;MgVFx%VX&@%6mtY9D4Zz%#&?!1?yBYsYtU*sR@shYpWt z+ij(%Vg^7r!!TQ1e$5um9?c5r=MxX+uUr}#`2!Aj8`S|yos zJmXS#u9~!3xI90y%CqQFyQh_@k86%~Xp>pCn!l73m$O%SaZhDSES!bB&ja40?mMKQ zz`jq$eH7I$!knKoBl8MJz+V$f<0$Ud3_fUuNr@$%bA$>dFX!v3Sv+tpSh*@1#+5(R zUhDhNGu5k^F2&8M=Q=q!$zC|&xZoUgA0x1@Zy37{JTj@DJ|N<3w|871 z!hz)jP@IJO=8P3PrCO~sOv$RQDM;CIBCDenm(JQS*DG@ymwV~uh{kUy>8UiR{Ks>Y zWe?j9a7@Ao@IZqnogHgGDL&Od57+;ycVqH6;IK}dMk&XqTx!;e^Y)qb(jbRDy%t+95&YF zc+OFqEK6B_O|P}b6SVIY*i3i7zD@6S8VPD!-oXA`*I^vbz4YMgNt=n4AqPD>~OoKheqw-<(@g!i5HMm|oNSr$Yj zQYbXHbD8i~jE*wP$yuvPz96qcfTexd9$wpNytW?6;f?9qS>iDN4N?@avm!pwAf6H9 ziqdz;0pS)eHDE1EZM`eb53rd@;c~h|c$mX>TfZYRN_wXYSLN~rQnixEy!njW$onK>@vOqJ#N+vftx;XHg*$gc<8N@-OYga@73k+%iMJ?cA;Iv z=?5O|9(SMn`*_?l2^K#*_Pf+!Xb)__b4}AX?7P-;6=2)(gukO+U|gga?C3ATE}5dx z98zOED7eKHIx?l{@GDJe#2hDQR;{aypUPHEV6ZREup~>H8>{E$QT?vwW1m#7a6Bw7 z!*)b#F7hEiA^VlN&VbyspDsftKR9H9E&SvUFkfL`u8(>_pdo4dQzZIG7n*wH;*8^Eh0{M@ms=n)WE4p9Ya3(Lv7_ zEQKjsQa38XCJ**A%Ir`hoA&6+WMFmZG2qHOKLnF8r=S%jrcA)g%-ON+Ri@E)X~WPS zDs+2I5BWMIcgOpyG25%FEs3j03Q(WPAqrv&zKv1V+vn>TY#-(Gau1tkU+>1@djoj8 zvJxx0bp3h1cZk^~55Yr=zaaE%RvfpxY zQb{VOlB$zRet&%{76}imh2gJ_X_H0G`HmB*%&Lb0UaNt%!Ic9X z+o7=%c`CFtSw*NQ2Yy;ejacU};uB->1@TNJvbe(-^4Ogxzie(OVMXI8bWFK@Cy!Bv zOMXs-+tUG6FYJs3l8Bj{!ew%z9YKM=?y1`^t215?HKDswa{0- zaM2A#Sd-O$<4PdU-$p+Zv~RP3kRC=D1AB8wIyM+%=GvDAPI5Zj$w&6L-PQEfBNNY$=NRM`3%R?TzoYb2q)PUraRgrThV$%6ti>>>Pio>d@T^ z&Fc3ZFx?yj%f$xueHSRvod|R`5E$4w?M;wKm{*{|?4?k5GaY7-A2~U7_BH5tT%Pz|;eG1+q7>>Wz-TU)7NtcIhV;gCihAOFj zb77wzb{`UYZyn#+o@D+uN$Zwt%T^v#CRVC9C=@GhNHc9>55gzN9D>?ZWKNzmn{|04 zU87cueh`8_BlPq>7V&Erb4uZJT;|f#$sO;k)c|WS-v+70u@K@^Xj2hDO|M$qCBG(d z@;qQPnPjOoc;|q4b8KDto~rQhhtBxI%AeN3Ve+Y(I!mZ5k}(^NprQK#oXn3CX#{on z>O`>0_&ud4S37+9yD+6;MFb`KAht^&uAS0Q+_)`i0i)rm@dt$&6F~`0h+|rOShs+) zrV4d}ibZ+U;eF*_#l=eGL&UmpBvtDoRFzRUT2p@|AvXT1Z)7v}i90gUVx);BomwSc zx-uKn9UxV~Xb=-xH`GWDXwfa4^Cm8yp=K)#n{yK&8ZAp!M{ugFxa}OeuJa7WmXcO4 zGeg~Eq%+(HL%~5)J)br-BSwO@ge`>j!ToOWI?=NpPk4Sq^m#DGN3$3I>-HISs2)gFGn|wCsuc#?we|8z9;c6VGimdXVjJ^_55;786{VfP2y@rCy z9W$_unuYW94Td>NJnc3HdG?BODS|mM*s^mzBL^i(^~Irq{XDBc3Wnif zMDbWtbj#0eMU5o$vrSGg9L|=57D+$F~cH zG?(|+66B5cY|H7U)3xBh_ITa)<5(dOa{GPtqn^~Ak!*K|XLD^Wo}?^y(wj&^*Pp(P zN82e)d@-a?qpVy9$Maejw=YlXP%M7(D75ZtxjS9oTtBA!1>QP5PAc%I;7CI@Cot%# z0lHh<9Ui89xQTNoD!UuYu!VMp$fRTW_)eV4OcqHX?anGhFSVZC$z(nur_=b2f?NU! zVdSFbQZ)SyagOe;f4OWb2R@=aMEy*+l3 zXj)ynzYEZjza|2wNQP`6jVw6sy=IUk{b1;+l)*$}FuE=xmZX84;!U3KG(lsK@Rs>r zIymw#Qjw_^h(*6th26~5BCC`VvH*t;6WQ^882mu*4bS0#*(BNi$2`jJj@!;*S<58n z9+$?~Dp~jGKm7IHqjTpZQ`gruU|H2L*irm2=Qvp&vB z`$3Mu#;OvIVF!9`zBj4SjO3>bFcI=z-gf;1iExS63H zwmCRUpn&p#h$YK>>eO=6JrXyzT$vhq)0tD=GxoebO(dd;9^1IS zxS%=#+Ux6_)grf9?HxnD$htbw(&aBTka}Zx@OesF!i=mpi=?SNJkkq4Z!SM-Dcsgs z&~sGt2vk>BU#PaMFBzFJVOaAc>)wTQM+ z8gQ3@X<;-|WF5pUnzEI;Wg-0`hZcO<8`*m%I^BPH*YEL?T(^?nYVucK1RcTa6h$)z z--`a!qa6psRpH>*2zg4P*Kpw2DMk73x^7<1V78L@S6xkxs~>uE8{_>6bj>yd-D%|- zGWIf|Fy%fS+$n5?#0P%85WT~WD&MVF-8$rYWM{c5S-Uy+RD^JZ zX=bg!(w^ROG_@2ixP{cp8$rvJ^W%my`yonMk(u04-|793)ZqyFziBvgUbP&St1@m1 zF=m{lges$7Y4-za7^n+9?JKSysW%hhWGIBGIcxk_xWAlH>ZM{hxp_x&6v_wNhZFMn zkoRyNjRlhq3GhBkjRo+_+6;3P(^jJN?Z&cXQ(p({=%wt-X*&H~hR56I3ng=Sy<^(e zLtThH5X{p{`lMuTqTU`dTk{`XCt{hmrq+j+#_I;zch^pVt5%Be*0P52)5bE=BRbT$ z8zT-{`z-+8h;ZB>p1k!h+T{lRwey~h^nC30Q*6b;@ye_zOPw&z2Wb%oJ>-9_U^Zj{ zF8;i>5=L{ygp2~Qz;9#yQkk|ECoIEZ_OVSrG(PJMUtGmNK$3EvR8u>a$U6flZkY}E zmMn4H6hF#e9q?9=t_y0}pPAHhRp>F>_O>5z#%gOP0s1`g>eH=O?B};734M-#moIMM zp4u`Fhe1vciLU8)yDJq|_7MQDkVf))T=p!UER2%m3ms$ZoyvX|0*1Y2naGw>*#d@>tf=&s7vfxmDviEL{Y5yn2UtI4lOs=Dk+G^Ryl!(&CCXz$k}@rt)(( z_?%xAh)bo&^6d}7kw<&hT*v$5Gaq?QbLes8@miZPl`$-yYH;FtD)*gO6ZW55wL=Lj zodUip+V7W*Qlx0HJpmjQ3US92joqa2Bw*5C@C|HB@Ci946wegd#^8$l1pw;5O7)zx z8rqhtP?LN6aRXAUXjI2uqu$GkOzSa~$-unyON}GX?bw*+Y3Ru6&1I`JJ;i68LM$dt z%RS=5v{|dAWy?Mjqth<&vgW4}q)mf)b7}ol?--=e9>o8kw%+b=cYS#nOBU32r}lc;?$xxle5YKiSEV9X@$tB; zyy|9sK0tNDkP58`7*{(e8(xeNwuUiU+58oG0&@fIug0Y=GHi}h7&qm_?po12GzDZM z^M(18KKC!mH&(2BBTXu{+)V-|SDoe#=8$+z4;|^awo}WwzTH8?7*!1IxnSWUnxnYa zEFrilrGckrr zgulKs$O@(*SUS0TvcUzw!lWKST5h8#tedz3zE|T{-x3__l|4r>$)x(eod}sn z&d^?Tbx-wixi|H?ppS0Z6#0f~l^ikLkPhUgLqFY+g@=hZ3^zk3wfe3R`P0%&O^<@R$yuuS4NFgxD7E$ zXOK|_QT+A@Ka!x*w-go4zPK6Vl z=y`n`v~)?O#3K7qd$x?aTdc)a>7+XJkn;xzE@d_}7k@61FBW>p2=8H{!&OP*)lUC9 zq~))P{c6CScZ0L`N`Kn3O+i581iq5zTD`Ykt*?^Y(gy-%^e?kSw6bHElnf=!1WQ$$ zm?K^u%7;PN-MpI3B(2?g2R=%;bn4$-j!j|3%S+_2W9I0g{?u1r6YR!jjaiZj_S#!i zI^`bnG}AH*k=5)S7{hNn8=5(umV-7#A0LOZC@;6N1iMgq*LsSVi%U``mZ{j`oH9_* zJ^n!UOzkQjYvvH3|JkLptLufkZG>ujozRRcX{Fb&J>GRf^mD@=ztv`K!@G`c!8s8b zv$P9i6a|JK=VqE0B}Pp}Ud;v}fLCz)maN8gGWz~{@7;E>NZXRSk`kr=`0iud@#Q-F z2Jf<)?I~+F{HcUVKr`~nd0ABW>vbGcKyeR}_*YBZ*d%(jUpAT^9^C4}E~yL#X{s4K z`G2Joi5*+aGc4~xfo#(()>6C{QdCFD4SZDi<0fiiu-_{hs)pxA)kmt=nv*%y%Z1eg z8Tq(UOOfzU8OFWI9^$pf(@!RJl17AWh#SedVn+@31K#UbZD5 z@8`6c?#dB%R8jkI*S55o8W_AX6Lmas%@oLIah|j-w?3yHmc4|R^jmk3$yuybnjw{F z`MPcl?eb7={4v`1FE5d-X+2|e{-o)#svH$u(5<^3rba4al`|3qxZ2X46w~- zFyUSf?mui=XrHUP`yPL>H>O>r>=vd(HzHa8+(3P}+46La)@^!s;8ZWnmUThCpAEr!%{XqF7&2IM zy}w9*9l3SY1>Rh zZM93;vuB0+v$>FWh|f;?2@VAc0i1kw~tn#)X2n z7|L32txg6Xk!KRw;G2U{fmE5w#$?$yPxfCOL&iv2^r=_n9}7CmePpWKF^Qr=D}@%% ziRA`XSuR0mW9yB)Dfyz7dHtgoGwthuz8WgVLrQj^n%1iVDek@syn~76}&h1Ig z(eMwRb!;J2-%cBk4Qy@K1EU9L8(%xRue&f{6(T1ud6w%L5V5kxCCqw1Y3%+sNX&>R zr$wq8*LK@xbK#)DXj&&5X9qF1NRK6v18t+iqzMPHn#FA5-Ip5Y8|Ea;mgbjTmXQ|S z(x7|(%sk5<@lHpjX;#*^q~(i#sNDg%v&`@10I6z&Ux4Ss)8urCBHp6{3Et`b>-C?$H_fz1M3-N4lR=gu(MoNTDuo^`K?+`sGEC88yi1?!o=hthz>#2{}gEXqk){(UlqwC zqB*FntSknY0YcKW`FYkf>n`;^>>oLP2mQcp%e0tL&u6SHY2%=G(cHSp1zjzi%Xg?0 zkW(Zh`ylzoc>N`{+N4EabX=B)UGmOY%+V{L&d6)F1u@{q5U~<}2*NNz;?EEeLSqfh zSh|;IxeC<+#Zt(LlCd+k(Ua6{!?FcHI>1~HnpwaLN=edMR7^x{n{=z}T3^Qw*TP|f zEPRzJL}V5C09|XIxn`d2-l4(2b#i@+D7al(D`O73L&P@ptaCHX?!x?tTT2?CBPArm z$313xwJzuD!g_vZVb6gGiH$4euBJ1u)4x)qJLo|rgJ6mi!G93|%=l_DYIx>^trkC9 zAQ5i1CstoOiJ<-BM=me=gjExTPlk^Y?!r0zi|34SR4RlQ)r~b=s9$*=Iw?%Nb$FFF z@kFg!p^-PA^w_k}+J=LQ2z-R2^=-Ku>mu`9SWa!Tc(en;`l(Do`VspjEn zByNhFP3a(INT)}sEj8XYuok_tsAgTwdR+9opjZ3APYb(mv>H{tU2;DC zXM=}oHr!lVd?&`G8!3_*r{Op*kE$YG4SyY(DhBPj2L_0QT*qLuyf5W+U-?eT z`Y9-W-!i*56kk0~J-qy|Hy*xiyWRGiF(@bE**TYev03GJ+okTL10DgggmT`OwbsMH zUqZJJZcVoYwb6CeZy^0vP$@R}N7=h)jT77CF6|hpnyg)5?N^Ed+_*KA$OD3_R}ju! zTt~<1vln*uSDVg`?a&HX`MPPOm)!$}nXu{p`tfCH6j3bp(@*pUt~DHuTMnoV$iXgb z|2$aS=HBGqN9i)Khr*{oTHm@Wx4Gb=JT}5Cq6*5(JcNQHuDL+EYeaSk<+u9xAg0n+Wbmfqg! zZNIWm7oVOHq^3^eH@!UDja+XeiqZ>yZ3eF&RS}H1?`|)7!9RgGA%LI?*R2jy(>Sqc zzhh2d|Fu4RqLa-{&_wcA$71mas(@IQaZLJ$jm}3v0`ZAl3M{V!K+@@By-1#s<-?GG zohsU{XK_fsW@T@WelSD8>LVB4HC?>zon~$)5fkNN{>X8B!yeW;+S5ZTSYFdT=hzI2OnNbNH8H(!nNxrVqiQf?37(qu|e(5Swt(b=F<|aobu0SecbX1HYQ(GB2 zvSoM>`&5Jcis+E=5UZVS-0T zYF3})=TEpl%rfts)i(%oKiWTJy1nq!TDp|ls1to;V@*mNo)d&KnlD@o6-$L!XYk1W zvXcca`6(GO=E?#;{9U;CJQ`rXxYG(o?!NmZYq4wSQgm}WR9;ldN7-XyO^=exo2()u zh-cys4jk+6mO+rJk_*d0Vvp^92HAMILo|Nj|dE znK26be@IU5&aGF$EImFH$sru7V$FmX1yW#ur$pki9V^>5$BQ<;@CYzLwVAr*S?xP_-=YUF06;<`G}yTRwzodT4sN;nnKqe?0yC{L9QV|5WcoM`R( z>iE95^<%e$GFezXwxPdxWp)T=HBQ9i|5dgv|Kx#xq3|hAqLgXU)gucfN%$R|ta;4+ z3|)Ke=p7W?dLm4y*X5`J8Woi_=Tp@@=z3tCoT;xB+pHGSv1Wz(`uyRmZ>Pvixid>MCv$4NZ(!1xCr_}gXuhMU{yM39e7k!1%D(9SSKmZ7)A2h2cj_P*hSzn>tQGdbxIy)j`(h z;WW9+nm_Glb?%GwLW@UEY@O=PxMhkxbZ8S2NCE_dyixXs@;(OaIo`KZrKvhgii`jg zSWpe|@m=x2!0jJsRW8B#U|~BjxLo4wz~Xol0XUu8ZKP^|g#6rzCKXO2u4iO=tkF;% zU?R?XAa0=cw44&Tyzt;c>FkF1qEDIVD`wWSLWp+-ipKKCUlG<>--g`^fHz(~ltPRK zEZ?NOH(p=I)Xx?t90LW3I(rH$6+~m}S5t@aj-r0o<;{ z*R{HjhtQu$_V39?yl6C?xFa{)lAyb;=x%+{4F2L=^%qwa&R@*w>sypp<>c45pC)BF zvFy|0#;7{KX1sfdnDO^K5!;kTg@^@Y)%}n#SP{#uW)<=mFZ~+&(ipH5Y_=P7f8)Sm z=j_G|+GxSd5M2)CCsV+gls}N+USG9Yo4ixRfyN@>n`G&uF zzsMpt-OdL*l2M!iHL0AC)SKMGB)6Z#QV@m zj+1retER;OhJVYv~fru|{L(h=TL&q3fHyeT*DCU;50%r+fkZZ+RO9gCyAD_`E) zrA{_5Ff&o3zyIADV)^vF{((OIQycmxo%SD;+JA6yBLBk0F^Je&8UKGa_otZlpLpHBRP%q%`zLnx zPonLgseb@%|K5dvK5=vNe6n=RES&!#sImP^bN?=={pag{8Ib>}p?`MmpW@s<^Zq5p z%=|ydX{;=tz53tCX)ON_Ic?-qPD5#Xp}S8eB#rnYg#<@K64{r7oUjksrK=?K_h&!P z=R8%DCm4_eG z7x7@XX)AbyQS*rb73mLHX4Yyy#xALo!>DB%fk*i5q*Qg`S&_uoKa9n9GY8E|hC=z3 zENaYvY*a6%qG&a?%A^zIIl7IXvBzr;oH8<+^!zk+3u@Zdjdrj1wUb@Ewz>CBx|TP0 zn5y!0v`5~-?L;y^{`(sCZ?xn8FrEJ~FaMjD_CHSJ|1FyK@2iK>e?`;&{rmryC5H8% zefkHQ#>~m`iDv#E(KHrr7OsCq)5bi%XancgKX@kCULe?*ndwQ{5W)vpyQ;XqvXX{tzA>5XmD|yC8i8teqbQsYPloP|;fFI3v;`7Mi{MW1bmB9NwD3`eAm10Vwxhzq8p)pDx?$ zMR144G$WB1U9_Zz9gkcbb^LxD-g5UMaHCeg@$SliJMU^4nlW9Ix^MkrFBFWT$6ee} zvb}J(ur2HhZ{Q+dkvx~3=@xG>0?BSdG&4{MJc%#v{+3u>Z1|n0`rd03t1Ch~Nt*#~c9*%fdOa6RPsB9` zWqAO0;cFIdlNiRg%UsR2uMQOGmDpOuG`_>HG%6z`De216yZBVwJg8q@^y7NJBET4n z!qlbg%WC%9(?7goRx=gjY#}OrZZ3$B)?spky^6M8+ZMNLR(d2 zILI^Q{4ThKB1_hsZ5hVd4L1Wi31d3|KYTa4bc(;QfJ2T0Hj)2tu{#DNPo5?e1K#

*`1Nbn;7m8?zgs_5u3-TXhez{v=!47fEk#<>76xM%Oqa{@@ zUD`L*!wYiWQSPS{`j}u0$?Fr4iz5TvhT@A4BR%Dxe?J>pu~!rq2{)Ggp>A`&WwZ|+?J=Y-;aL{?IWV*Av+c{Qd4A@%Uq;*7e703yFPg2h;5UxcdQDmSs zK!i#CzBOy&H{^#5Mnwcyd(tfdex1T{7D-{dPCw;tdiMTQJDK?G^o4nbBr+0G(J!Z$(l zju!K(kQ~sxzKQ0}4&tRj!1K!JD9 zd;0CFmd7zkdZJ&T8LjJIzhHSw|HvPl3A=%P{$%@|37&-Le&dp<*A`dCOK;EC!vpB^>sUzZtU(68c(T_KM5c%nLeF=8`cYh%Q zfA41Pzo~XdCtgH@$mAQ>Jm1asHXN8n@f0-qEXA$OnUj!BW*hCJ~Bo{Npx`bZd$RyH1jx1x&#pJ`GJ%oBZY zlS3Ry9=B3*MKsW3!y{Eb#sEp+V$w_g0i__r6V?y~Z>;2mEIWiMsWG04fXnD%jUt(h zOxRcWPyfy_2pKO`z}Rj+do<#AZF^@l7In+pKLA1&{9Tu~ykE6k zWza+^^qULuw?MOG))B<}O@~(MMPLG^@M^)=%Oba~yj2^p%F*E7MZ`T3=H6ZsYm}P% z*ceXSX%{B)`EO{7hGI=5y~b5p04|*6tHCz3NxErS5X_6JFfw`_^-sH^ZUgonydZ?i z7N-D$Bs|vB6t?43w&59)4lEGq7*H)Q1WuCSE5#2AYEL3%QTTH<6nOuW_^D3ldp*mz zvJB+mqN0X_{RHFu7u-mYKan*0c8$#RsS*ieuUnj1-RdNoPuYNzrwijIZx_PDO@`3 z*H!X?Gm>cePnf7uVQ!VFn>;gc*DySPu5lvCnMPKui_q}z3);|*IkTlV)Qs7J6PBAD zu6Lr8wkPGhB9QI|)ZA=km4A z)kfUY+IfZTUv(?eInUCv6da)Z1OTq*A@q-N>U`=pXcJFzc6fj^BVrtmG`C&{unx=Z z8|#*-wCo>PTyw^5DNS~cDFuITRCt(TZc&sw1^&&=fa#h+vdp&B#Jyki9Mcn>gK?E? z^4r9%r@x!nH|?3^*)u*^f3dR9cZ>2tkKG5o$P%kKpvYuy|{)!UZBhuJ1( z*$WV*{PS>DMKVjykNJhrzqN#btXsbSmAS<7peQTo$$pb6*N3w^+ABM-?Ks=Vplpm; zCB7j=U2{QOSK0&X`j5*WrUs*#@5ToJNG)b6#U;#wRF&3gp!92es4weX5{fU)Pw4wT z1s>z?mW*88#L)99{$4EgqM2eA<`+ja^emaT?V6TQd~}cz^wlH1`kUCWh`;Ru;D);L{C6QS6JlIJ!U3hy-KH9UP>ic|kXQyYSiXkAn}TmSMj}EAPz)60!EHJIXvaJ7azDy|YH=#i zJe927c_j{zvkh>nn0^^Ezg4zmye;+lF`yUV6drkrNR{XXe-x`N?!}^zc!jD-#Jy7^ z#U&$u|>%p(@{{U3%B102c8L3rkLUpJ&OHF8yx+Pfd1s- zXOK6&FDY=E*F)N468&5PeX(zv@;srJeMh0ZVYF>A=tl#I1%ip%pnK>MML5GBfHH;P zfj&3r=@#QccTH{@>$?D~8g6q@+OS^Hp?5N0$y556Zo{B2q&$X({sL&5Y=1=;V!cA9 z^wHn;q-12fB0x_{eoPDv2YB_0VWVRwKcbRwh5jg?6%BL8JScY~!P6vDqhv zvH{Xfx0wLxhTCkEf+pMOlya&^!RX z!L~Ie5}SQUXaE3TKQ|!Mg>v1{Pze1cd2vJx54{{v$82C`h>UK_S{)vm0XWs)Mx@j= z+vcEbV5^P{EeBW`Y-3V#vQ>wMCZ#NP^~nIr%(lfT=UJ{G(0`@4WriLk|LpCn1(cZ@ zVxrTfxCMn`0@&HEFwjSme-8J>1LzI5zffYaRfmKI0_gP(1<`MklSlfjC{0;d;zMx& z0HfU4&|<(W8%tp55CC9kNQ#c0{B1&v0DUL9$Rsx?)RM9!xyU%zKh%M;pOqyjbP51u zVF?RWqWrw}(JjV;E)Kw8jhzr9L~jP{GP9(I8UPRs44KhW0Qs!3J%1uYjVa@jzjggd z2=xJwGowz3;iFdrekO+)kfw%GQ;q_}8c<{7x&%T?nkkClNScgnSei1y7R>Ah1`!@S zx(LCLNeE#(PkPo69t6OU&cnObzMpHOx3#0Jj|Y09`-$Q=H;!L$u^9%4*WMG)}Oq z#6HJ$I57SG%tqpkxQe(6SaGtUmAk4uP<}16qj}#UI}Ym?pT(LJQ^8ghSHV*417fF) z#E&#rvlxZFN)qA>aYVE+$I(Sm(@Hb;1foKV4?#bggRhf&-H=^}IgmMo;W||Dz}gP? zAZk3CV^vJ_G|;Ex#3}*_W7UATu}a3j4hrgqb=dftq*nXpzxmq9W2_2DHZOBF)85nu zXp1!Ym|CsJ-QnSV0%mI=QzD zpm1P^#oZC?toRWGsFLO_W7=I>Pw_c!dV|_q_^1*%uK1ijts!kjondoF2zHAtT}bUM zailDrrNAq7WF$?b_#8703tTUB@}IVszEC{QzhwluQWNAk0jE)=ZIyWeM<}2GAdmvA=nZ(UxGYl~sYD0Dl6H~yq&_RSr3C2!U6huEj}WCRl|3S-U8Gm2twFc6 zAO@grPF>10r8FK*JHP@Gltf)#cuNX$2I^+lB~IS}GxO?#rfY#}%9`R96d*I|^6Xo7 z&>k>V>n^}AGq)~cT1i@7NmJzLi*z`RfSd&?h*BD!h9R3hYnor$k!I}kR`@i%G#kxW zHhac2yL2S5K*=LQ2@>QXtxPRjz#cj+CXG%VS*Rjufe+G@<^Yz^s4AA^s|XjTPyduQ zqK+(3k+8r3#R8>i66!p#z$3F&0L39nBp?XsC*U>pp3-m*d-^o9v?z^&Uq$hUMJgHcjaQixNI zQ;buJQ$SNjQ{1Mp2QpI_pMX=^fwh3Ug1dq>f_FmNfcrqMLcM-{guayTn()K(JMqf` zTL4oBR|gYGFXLGIgP_Y6Oc%Bd zW)W!-X7Q^VW)<}1SA8~pbbYc-lP;Jp89x`BlyXJuTfNGX2Vc}Gq)P~WhE4Y_M?Vff zGw@RIQZPF33F@>rb+Akrb1%C9`FP}o&9&XJl=irGhc-9gc8#pE1FoZoL!Pwt1)*Bu zh5Q$Qt1y+N!$2BGQ~QB=8YMq1`l9LdBdjrJ(>7U!8)$?wNr3T{Fo}$D6*Wm-r^98- znh{c&?Wy3aI8zwEnh)vS{uGxx7bKa?2ia?Rysl0jTrd$@zMQpgz$Rdm3@qtfre|0TL%+jF;fsM3)%7jCzf}^7THwrMGmcrr3^au z<{3yB6+8wF+XeQg#2&c|{19dpd==&usR{ZK(GLBRZWFsp2wVu#2CM?o2SOWC8(JIu z748vs6SnKYZ^Z8cED3A_f)Szv+zFf!tOMqiz>e?|b5o{k156L>{VO-@BfcG$9gH3B zC3Y80mzkeDcovu(gdmI;)Fa9z_@;N)moED*Pd~Y?RzFv;0We8$NibVTBuFH1BnTuh zUa&L2Mz9y~7cft7Yd^K`@LfoYkZ$Nz@Kxwlke4u<&RxI!&it(X%KaGp)WOog)4-S@ zIl*)x%3#~ze!{weS7BZ9Z}N2EcGddL`KkIP_?dyxfsOeUf{lR5fLDF#mjROp(}$11 z2FHTH0^5h&2gST-cUg7OcLBhxxUSg0lj+lD6EZ_H<1l|=Mr8(PCRBj^23rI@3swTI z>L>jjIvbxEiy4L)R{`c5G&M93Oad$nT-;COyC5<0C-4i70E+;L@QGv^LnwjMfZ-A2 z#6W!mtAcn2M+3X^YsmxkgvrosFw`q zzit?Zr_J#%k1bCa&TB_@ubYPd9XK%_eFbG?EDlX6N}${B$}Vn?-{jV~N;vCLpLCUX z0yBi7-|(^jcDU+oA-R~vZ2V5T(>`Dd>s4T4&mIG*+sfC7W4#m`m^5<@K)0F?Z7alv zAsM>DZAa>8HaP)T-=0*v4oiRDxF_v9{$TuJ$VzN|`h6U2r}zO5i4(fXj*yp22H*wZ zd$p$%MMQ9Lz3_H7q=;7oQ;w%`@1@fzFNaYeT!#26!IxHrKC&po{m zFWGqo?Cbz6+?C4@_0U``@~?5JNF&)_s-zth83(q*wZpd23XVkhV(KPbTQoSh)&r!2 z^99m3&(_vg_s*laKh7B$Ne{V|r|U2uD4i@9incL8Q5+X_jnupoW7U z#asx!RB6-1 z3D>PyOM}GRr7|fcVyp)p5WK3N`j_O!p5)NX(%D+=C0+w}*e|xZBgxL+Bgn*L<}2Dy zI&28~@DR^Xs9rx$J?AEXP~ zk9T=@bt20=s{v&Sgnhe`1%~D->Y==W>X%q==d6o?8$GIi~#OXO*Q(6t{ z)aZtw_Ujccuud!HG#^hk_^{-ce7?wQw-HPyILW(2{9bojuutTJnt@v^uRll~q>uW3 zP7MW3D8ftfcfHRX)4R>rPL{))Nv_kZ&a~Ts>LZMCjo%>aID*4ziRlE)6Nw(io@ zNS{eJs`gFxv`N154~(3I`Cl&H3U_92<6xkBzrgY$y{Z)7Z#YBDK$m+T(H4 zq1^>ZsvcY>S+DMaYob@Mf{GU2Z`&g6FbCg5IUimjIGUiWXus{_gFb|R>WpO5u2|t_ z(2G&rpSz4DU_+%RhUS1JmWr79m1P}GuX2GlQHtb`dV7OaWFo^mGpg-AW~U+ZTt;eK z)v$zg(bh|%aR_YzMCsTTDJTit&BUqkW4;%~-QdF8BvH+*$cXAs}7SNjJAw zs}Pw{2a=(^`oPQw+ZXRC$EUpFhx~X0MZ3;&^(v*_VVKUEkNSSD3%z$~H}cEV>i$h^ zl~_}w95)#~dUllJYTgNye2%6os1n~}Y>I7n2okY32@#-?n!xF3Y&9|xkcfbAebv8O zo^ru%=ILRJeAx)(ieBuT&?hd1GDK8x@z`l_&ADoBof>0lS%nt4 zDC^DooiK;Ah(9e@Qtu<4PW&hNF`nBnmAbbYMSJm3AsGygcc5h}xUzGSe)dnQSX^h3 za7s63Es$ss`})%Mt8>(e+6ftP zs_btQcPsg{>QB-cuKRIDj+FSi8p*t$c3R!@YRKhk5WCn1HmbzwoPH87aFsNO!m@O1 zLA+Q+Dz;B|d#;QDs;I2I)bKvkXm+QchDB1>VlC5D(qQXKwXLd9kmZ>)#|( ze!$*wgCUCVng1o(g~01lU`J?d!;A!OdEJ6_5Hv2%l0oE2{*j3OhDtDucL!@=lpck4 zCE1{F6xhEOo05?75lhd^mY(!C50FkX0#xlo=AIEMJk5Jt-BoT63)J9A!2l~ro%&O! zHl|u0NM92;1wT)3TB{+0Rd)xH@M2G6DFR}cs%A#x@ z`WcR+$Vgutw$?J@z0zwJt|QxD%biOl$>mv^UJ&H^YEA?5=- zN_wtB$ROv{H_Z_I_$(rJ%G9uVluX|SB;C6fnN8ts`$BAt{8UVw%dY1 zeWO5_)^`!DB@xfbnT(`N$?6iDGd~j`RP8C2Nkik@Wb$AmWiBV@^SE5TnrjhxzQ5Xc zu6czv&=fgk;k~wQ3Hw4$x2~+8Mu|!g14t5)BqFIn0VOL*k_{rDWCj~=G55Whp=#at-mh0bcb{{1`p(|F z*Q#%ou})!_`ehy2nn|nTxIT9Jq3vJQt{cilvsyaFy^R^Y^waCEv(KZ$ecdB`z-}(_ z2`E*mC8C~5*k1R#tEk+?uhlH?Ln}hgKQhqo3sMzQfZlk`HO^h7?VRwhsM#l5Ub!uB z{H9vl+1KJ4`cyEWqKDz%) z^?n|gg6w>g<^i%8=icoHX9ZI%@}o%F&daTyH9XPN`^U#p#^Q4A^4aJ&uShzPhYOYN zwMD!3KB@+_?+M0p9V2gd>%Fk1X=q%1djB39z$v!E*Kv?l=tN_ywype!B1VPYx!zGU(j{~=_Wn~&Aul(PTC%<8qE-SOQY*O3Iw$naQeXbEtY zrqmRR0$Byi`OC9SFI99I49b5~qmDyP9i7<7v@Xts+Gua)_o?SZee>wx8$x4 zvu2-2O!v!_rR%CY9bYS)39Vl!E6M1SlfU4!IGYsz5f>x>921^wWmq^ zES;a@(_aFtseX<}29@x{}{cjW$dD?iNU>EDH+0r0tTfz)isgdgPQ}vA^0p zJGxdfaIW!=mWxy*hNr}*=bBO7LT`O;yqLF-$;Ab28Y|hR?B$zy>X3|cMeC6KRP!rq zp@0C-#CP}?ueuvfmwpjVt8BAfUfRvRduhJNE-^Y*tPZot*cUc+!aPDvS4~hq^pr$r zWlL3d^6)8)CtF2U@8D=!#NoG^)~RyJQT8E5Hw%BVMje#gb1CR@`lz|@Rh*S#%LrrC z+djS1x`*_9VHG7QfNNAV!*g>gLt6_JWU=d+iPdT7fe?XXa=$)wXmg*X^6Y_jW~ySr z6JJYmjn{dSGR&*9-b;V`xCT$_Y_x)b?veb`IQ|5K!ckA{`=XtRd7qc}yloEY2vwSj zpY({(>=|09&M#}O=h5MQ>=UE)3~OHq89o*XqpA9E$1NXR(x~Zk!k-~Eo%@`UW?7t6 z$H6rB_2S80O540n%J+mwdroz|vy_;YQl)Dg#wSu$MdGpJqw2~rID$xy^>(4KO7R19 zAu-X|j>YW{4CHyWO!%!<&8Wtlz8_uderWHv7&ZApPPE=gJtuB4X%gZxV#&|)eT=QR zRE3d$B1qNefq9Aig_Qiq*>WfAGt4=o?$%Mqd2TJiz@YK6VGL} zi@QIy`#k&5{xQlTjqAV#2X2-tZBYOR?h;O+De7fY`hfXFXKz2TNA`)8Mn&z3zya&2 zUk9J}2jxb|>Wsgt~Z3%0W#0R*yE6SI>@ekmb7gx7SxuI^zbEpyXSh3}oSlbBp zsUP%Fy2Hfy+#h?R_a(O7T}T@@r*a=kb+I`ZI6n)?JXq)Vs$3_5{_uOnv*bB&y8NGiQqaq1D&K6 z(Hze)lSJ|x&WlU6zbpOR#mQU8@($HXwx&KtlS#Jix6V3m&33ZJ#oyjBr-wz~9gC4% zy-{|U>VGTLdO1e*(0;CH&XKWwF`QOfBB?i-S5?IBF+4i>I-YY%d33i|{EvjulNz@d z^DpqIUtP?P)>A7?60*NLZY#*rG{4I?ySsdyj(R541(^KeOL6w2TBdP zn$~o5en^Ovj*8>y>%Eu*F1LF4zq4;W`Wc>6*mVM}>5FwQ`-;Y>=58-;^Ot6tHR<+Q zSImw<8^-1$q$bS@5w7kbQ}#O-jcXS;OsdOw=2ocLswtaQF;MUHgcx<)0@8#rS5jUb z=4KkP0P>BmwMlZzxb~5IC2B5?^3sMe4n8DfvPV#n0$!rxV-T(WX9&zdg?`6Ek$!*`uA6Za=7-;3bjx3()G>xChKRkRohNC z&6bv3D}$DIWb^Qoi$t3rb~W9RUO6xsX8D{`j44}2en)8`=O2BdMSJsxKZ(_1CRbeg z<8d{IjbfkL;JHf2EG`vmK~6;hW|zryNd}1jp>9XF&&JF5{gGx4tPwp_%Zl~AZJw!x zBdyb}pSd<(N6}tYDPOgzQls3yb9{%b==uZY^{Ub#v*19vR}Lqwv()JNF|1QhD9Uon zmlR0?#aKx1;rqC@?wwQJj6M~{iPyF@mavH@@UBgJSvIUOdD1=Qe>8+Mz0I3Yjw0VS zF}0tG1IxZkfL@GktrT|raXl&@AREekY4hJ1<5YSrrXR?~#H+JC6r zzMHo6lZ8=&5S08SM?Q@Y=hSC#afkM;{zTh1{iabSF5o|f?r zZ;R<}$=544j79T)uU?TjJDU(qxBl#2q0;3+|L6)p0f(j~4Y@Zu-;n3@7qqo?m!mA@ z50^RGcBSW+z04XM))VNgsM_iBxNpE=tbyZ$TB(G$f$n^&uXEjzrmxpB6ADK&Sm znt{1H=S-7b$miP!K|TGqCTnH1r|g$po@tr%7F;oMbTCl)<@!{DL$V{tylS^|#84g! zdke36W8KvI{a3HKX-5B$P7h`Z+ZnS_YHZ#dBV)I>ZAi{qQAFpF7=izXf=8fdP{|ec z@!W8`VN;3ZYNp1Vd*dN{^AaPq934IhbukyH@N!56lCx0jSY)O_pg+~_ zRQCGggI6OX7WSww{)mV$R9~9g_xXcmJ{L26@!~#ajiTBHjo?zU3A17FF-LrfuE8jwB>Kw;tqwQj?DN}@&aMmq* z*5pz@gO-P`&BPXtH*UFhdV{HxNv21yKa~(TVa^}>sV2kH{M?GR;=QS<>y7cx^W^vP zoUlmW%QJ3UV)lr>bNr6f;UZn(A1dQs%`#u^UzuE)O)vT)DHCw#>2tI2kr0=J#T(hl z^wM4}-6zvJta5P^BEt6UdK%uV23!h-#`@PX7Zl=WJO>7j`7CEDFPyB6eUWIKpMOg; zt-QLzra#X^-M^-YC*Wsn%gJE3;?98Jl15ir6y@0q&Sw$%rpJ=G4F_A^oZ!pN?LU1r zf-!hUcaCU6E>nf~-lx0=^fqLI*5}VwfqfyIJ|8&^Eg~DrvVTfPzB5(`)69>fHza+# zy85j0%o>4VwwcT(4Gji9p&h9?9e<~uTJn2%{mg1E5Y<#DKNX^xQN<_HU~*@zG_LY( zd23u{jUX{J;!EbV0ASOe`*~(zafVH#v3FUK{ms#U%7vpQ;eHH_LaSXO&hB1oB5hR5 zyt$3%>z(4O+)9(besi*Bvp~NSk0%iSegpk~WqwZvF?~aAZ zIg0M*&O3WxK@vd*0AX&;e}6^X11n7+gEB+{i9mqAOzv_1(rK9WAwwa702zMAUD^7w z#(7732M;Vjq{zUZ0w+TlSxpaXC&zP&&h}2{v6~+chZ#CbN-o~mGtvZ{3jAQ|{qB4sPD2PU~7cs>8&!|9uv{w6eG{~ekwydG2l{^Ab& z|8sf>o4&&yQ*a~zf<0C-#=_rG-^}nP#{p0H2ixI)q7o2E!OJ~(&b$J#P2B%2FCVzP8dU6DnC|3L6b?X?9_@QZRZENOn3B6O2gQqlwCVKR$$j3zs_SeWqH=UXo zGy@I%RVmG$H>z(mDHF3yjiy&vI_rv?&=>DNk<0!<6pD?40^k3ciL!}zBok#59{*sX zc)Ojq!{A`d0~p+24;CPkiDaxD_AeP8-nRK*o&QS)fe;zy&25q4aCjU-h9{D7c$ob3 z&vke*2?P-`_;)-BsRM^25RvPM0Fel6Jr75u5D91*8G!HqKlQ@vKnP(UjtJq1sC5v5 zf;tZ(lVEP!*7G2kjf0SpaGPan>pBvSNJ8o*;Q$<5fw!CoQ3x~xRBwnApM0aB>@?GxN{Iu>&Qe@tYB6jOn%(zFPRL%w*Vo7 zd0Qy^0CWt<06;<60zfF-lR*L=r2{0vtVx7k7#qkOK@iM!MXUpeXiUP_h=kk=5Yd=~ z`!gy>00~b*VhD~D9vLeDHW_6L2_hqL0FVirRdMtAyS_kVR15%!2%>C;$PijaLETjl zu1&}sfjGFDAoPMT2@fr!P>`4e@pu#_K|BeCD-aK$Y7U$=5T%1aAR%iVNFd{p_X8w= z$QprzHZL{O4*2j0J}6`Ys=jQNXY@J{rn4h#25@B5Isn}VDF8efqxMoz{fz?S0O1=PKQgLs zL2xNS)*%RwNA_uWF9nB;9|RClc!A*m1Be{qH?JxJ_pl5PBJ{#C0uqz3j0p4Dx5NsM zBT#Ut^9U3WVIQ7IBqL`FSOy~R3?6R3Frj{{4k8(k?5lWqh9V=d0n0$-d;rfwL}Xup zWe~Ct;^Fpz?5ps6fCG@e0U!bTM=m|wtR0=syJ3zVl|AX`d;ZT^Pu9@I#RCiHZF3rg i|9UywxnN;a|C|inJ*?e4{+tWp(_uVfL`7Bg)&2$4o#Cti literal 0 HcmV?d00001 diff --git a/lib/solmate/foundry.toml b/lib/solmate/foundry.toml new file mode 100644 index 0000000..ebdfa11 --- /dev/null +++ b/lib/solmate/foundry.toml @@ -0,0 +1,7 @@ +[profile.default] +solc = "0.8.15" +bytecode_hash = "none" +optimizer_runs = 1000000 + +[profile.intense.fuzz] +runs = 10000 diff --git a/lib/solmate/lib/ds-test/.gitignore b/lib/solmate/lib/ds-test/.gitignore new file mode 100644 index 0000000..63f0b2c --- /dev/null +++ b/lib/solmate/lib/ds-test/.gitignore @@ -0,0 +1,3 @@ +/.dapple +/build +/out diff --git a/lib/solmate/lib/ds-test/LICENSE b/lib/solmate/lib/ds-test/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib/solmate/lib/ds-test/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/solmate/lib/ds-test/Makefile b/lib/solmate/lib/ds-test/Makefile new file mode 100644 index 0000000..661dac4 --- /dev/null +++ b/lib/solmate/lib/ds-test/Makefile @@ -0,0 +1,14 @@ +all:; dapp build + +test: + -dapp --use solc:0.4.23 build + -dapp --use solc:0.4.26 build + -dapp --use solc:0.5.17 build + -dapp --use solc:0.6.12 build + -dapp --use solc:0.7.5 build + +demo: + DAPP_SRC=demo dapp --use solc:0.7.5 build + -hevm dapp-test --verbose 3 + +.PHONY: test demo diff --git a/lib/solmate/lib/ds-test/default.nix b/lib/solmate/lib/ds-test/default.nix new file mode 100644 index 0000000..cf65419 --- /dev/null +++ b/lib/solmate/lib/ds-test/default.nix @@ -0,0 +1,4 @@ +{ solidityPackage, dappsys }: solidityPackage { + name = "ds-test"; + src = ./src; +} diff --git a/lib/solmate/lib/ds-test/demo/demo.sol b/lib/solmate/lib/ds-test/demo/demo.sol new file mode 100644 index 0000000..f3bb48e --- /dev/null +++ b/lib/solmate/lib/ds-test/demo/demo.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import "../src/test.sol"; + +contract DemoTest is DSTest { + function test_this() public pure { + require(true); + } + function test_logs() public { + emit log("-- log(string)"); + emit log("a string"); + + emit log("-- log_named_uint(string, uint)"); + emit log_named_uint("uint", 512); + + emit log("-- log_named_int(string, int)"); + emit log_named_int("int", -512); + + emit log("-- log_named_address(string, address)"); + emit log_named_address("address", address(this)); + + emit log("-- log_named_bytes32(string, bytes32)"); + emit log_named_bytes32("bytes32", "a string"); + + emit log("-- log_named_bytes(string, bytes)"); + emit log_named_bytes("bytes", hex"cafefe"); + + emit log("-- log_named_string(string, string)"); + emit log_named_string("string", "a string"); + + emit log("-- log_named_decimal_uint(string, uint, uint)"); + emit log_named_decimal_uint("decimal uint", 1.0e18, 18); + + emit log("-- log_named_decimal_int(string, int, uint)"); + emit log_named_decimal_int("decimal int", -1.0e18, 18); + } + event log_old_named_uint(bytes32,uint); + function test_old_logs() public { + emit log_old_named_uint("key", 500); + emit log_named_bytes32("bkey", "val"); + } + function test_trace() public view { + this.echo("string 1", "string 2"); + } + function test_multiline() public { + emit log("a multiline\\nstring"); + emit log("a multiline string"); + emit log_bytes("a string"); + emit log_bytes("a multiline\nstring"); + emit log_bytes("a multiline\\nstring"); + emit logs(hex"0000"); + emit log_named_bytes("0x0000", hex"0000"); + emit logs(hex"ff"); + } + function echo(string memory s1, string memory s2) public pure + returns (string memory, string memory) + { + return (s1, s2); + } + + function prove_this(uint x) public { + emit log_named_uint("sym x", x); + assertGt(x + 1, 0); + } + + function test_logn() public { + assembly { + log0(0x01, 0x02) + log1(0x01, 0x02, 0x03) + log2(0x01, 0x02, 0x03, 0x04) + log3(0x01, 0x02, 0x03, 0x04, 0x05) + } + } + + event MyEvent(uint, uint indexed, uint, uint indexed); + function test_events() public { + emit MyEvent(1, 2, 3, 4); + } + + function test_asserts() public { + string memory err = "this test has failed!"; + emit log("## assertTrue(bool)\n"); + assertTrue(false); + emit log("\n"); + assertTrue(false, err); + + emit log("\n## assertEq(address,address)\n"); + assertEq(address(this), msg.sender); + emit log("\n"); + assertEq(address(this), msg.sender, err); + + emit log("\n## assertEq32(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(uint,uint)\n"); + assertEq(uint(0), 1); + emit log("\n"); + assertEq(uint(0), 1, err); + + emit log("\n## assertEq(int,int)\n"); + assertEq(-1, -2); + emit log("\n"); + assertEq(-1, -2, err); + + emit log("\n## assertEqDecimal(int,int,uint)\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertEqDecimal(uint,uint,uint)\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGt(uint,uint)\n"); + assertGt(uint(0), 0); + emit log("\n"); + assertGt(uint(0), 0, err); + + emit log("\n## assertGt(int,int)\n"); + assertGt(-1, -1); + emit log("\n"); + assertGt(-1, -1, err); + + emit log("\n## assertGtDecimal(int,int,uint)\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGtDecimal(uint,uint,uint)\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGe(uint,uint)\n"); + assertGe(uint(0), 1); + emit log("\n"); + assertGe(uint(0), 1, err); + + emit log("\n## assertGe(int,int)\n"); + assertGe(-1, 0); + emit log("\n"); + assertGe(-1, 0, err); + + emit log("\n## assertGeDecimal(int,int,uint)\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGeDecimal(uint,uint,uint)\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertLt(uint,uint)\n"); + assertLt(uint(0), 0); + emit log("\n"); + assertLt(uint(0), 0, err); + + emit log("\n## assertLt(int,int)\n"); + assertLt(-1, -1); + emit log("\n"); + assertLt(-1, -1, err); + + emit log("\n## assertLtDecimal(int,int,uint)\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLtDecimal(uint,uint,uint)\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertLe(uint,uint)\n"); + assertLe(uint(1), 0); + emit log("\n"); + assertLe(uint(1), 0, err); + + emit log("\n## assertLe(int,int)\n"); + assertLe(0, -1); + emit log("\n"); + assertLe(0, -1, err); + + emit log("\n## assertLeDecimal(int,int,uint)\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLeDecimal(uint,uint,uint)\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertEq(string,string)\n"); + string memory s1 = "string 1"; + string memory s2 = "string 2"; + assertEq(s1, s2); + emit log("\n"); + assertEq(s1, s2, err); + + emit log("\n## assertEq0(bytes,bytes)\n"); + assertEq0(hex"abcdef01", hex"abcdef02"); + emit log("\n"); + assertEq0(hex"abcdef01", hex"abcdef02", err); + } +} + +contract DemoTestWithSetUp { + function setUp() public { + } + function test_pass() public pure { + } +} diff --git a/lib/solmate/lib/ds-test/package.json b/lib/solmate/lib/ds-test/package.json new file mode 100644 index 0000000..4802ada --- /dev/null +++ b/lib/solmate/lib/ds-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "ds-test", + "version": "1.0.0", + "description": "Assertions, equality checks and other test helpers ", + "bugs": "https://github.com/dapphub/ds-test/issues", + "license": "GPL-3.0", + "author": "Contributors to ds-test", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/dapphub/ds-test.git" + } +} diff --git a/lib/solmate/lib/ds-test/src/test.sol b/lib/solmate/lib/ds-test/src/test.sol new file mode 100644 index 0000000..515a3bd --- /dev/null +++ b/lib/solmate/lib/ds-test/src/test.sol @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.5.0; + +contract DSTest { + event log (string); + event logs (bytes); + + event log_address (address); + event log_bytes32 (bytes32); + event log_int (int); + event log_uint (uint); + event log_bytes (bytes); + event log_string (string); + + event log_named_address (string key, address val); + event log_named_bytes32 (string key, bytes32 val); + event log_named_decimal_int (string key, int val, uint decimals); + event log_named_decimal_uint (string key, uint val, uint decimals); + event log_named_int (string key, int val); + event log_named_uint (string key, uint val); + event log_named_bytes (string key, bytes val); + event log_named_string (string key, string val); + + bool public IS_TEST = true; + bool private _failed; + + address constant HEVM_ADDRESS = + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); + + modifier mayRevert() { _; } + modifier testopts(string memory) { _; } + + function failed() public returns (bool) { + if (_failed) { + return _failed; + } else { + bool globalFailed = false; + if (hasHEVMContext()) { + (, bytes memory retdata) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("load(address,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed")) + ) + ); + globalFailed = abi.decode(retdata, (bool)); + } + return globalFailed; + } + } + + function fail() internal { + if (hasHEVMContext()) { + (bool status, ) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("store(address,bytes32,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) + ) + ); + status; // Silence compiler warnings + } + _failed = true; + } + + function hasHEVMContext() internal view returns (bool) { + uint256 hevmCodeSize = 0; + assembly { + hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) + } + return hevmCodeSize > 0; + } + + modifier logs_gas() { + uint startGas = gasleft(); + _; + uint endGas = gasleft(); + emit log_named_uint("gas", startGas - endGas); + } + + function assertTrue(bool condition) internal { + if (!condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertTrue(bool condition, string memory err) internal { + if (!condition) { + emit log_named_string("Error", err); + assertTrue(condition); + } + } + + function assertEq(address a, address b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [address]"); + emit log_named_address(" Expected", b); + emit log_named_address(" Actual", a); + fail(); + } + } + function assertEq(address a, address b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes32 a, bytes32 b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [bytes32]"); + emit log_named_bytes32(" Expected", b); + emit log_named_bytes32(" Actual", a); + fail(); + } + } + function assertEq(bytes32 a, bytes32 b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + function assertEq32(bytes32 a, bytes32 b) internal { + assertEq(a, b); + } + function assertEq32(bytes32 a, bytes32 b, string memory err) internal { + assertEq(a, b, err); + } + + function assertEq(int a, int b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + function assertEq(int a, int b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEq(uint a, uint b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + function assertEq(uint a, uint b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEqDecimal(int a, int b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal int]"); + emit log_named_decimal_int(" Expected", b, decimals); + emit log_named_decimal_int(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + function assertEqDecimal(uint a, uint b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Expected", b, decimals); + emit log_named_decimal_uint(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + + function assertGt(uint a, uint b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGt(uint a, uint b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGt(int a, int b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGt(int a, int b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGtDecimal(int a, int b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + function assertGtDecimal(uint a, uint b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + + function assertGe(uint a, uint b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGe(uint a, uint b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGe(int a, int b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGe(int a, int b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGeDecimal(int a, int b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + function assertGeDecimal(uint a, uint b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertLt(uint a, uint b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLt(uint a, uint b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLt(int a, int b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLt(int a, int b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLtDecimal(int a, int b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + function assertLtDecimal(uint a, uint b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + + function assertLe(uint a, uint b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLe(uint a, uint b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLe(int a, int b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLe(int a, int b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLeDecimal(int a, int b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + function assertLeDecimal(uint a, uint b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log("Error: a == b not satisfied [string]"); + emit log_named_string(" Expected", b); + emit log_named_string(" Actual", a); + fail(); + } + } + function assertEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { + ok = true; + if (a.length == b.length) { + for (uint i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + ok = false; + } + } + } else { + ok = false; + } + } + function assertEq0(bytes memory a, bytes memory b) internal { + if (!checkEq0(a, b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + function assertEq0(bytes memory a, bytes memory b, string memory err) internal { + if (!checkEq0(a, b)) { + emit log_named_string("Error", err); + assertEq0(a, b); + } + } +} diff --git a/lib/solmate/package-lock.json b/lib/solmate/package-lock.json new file mode 100644 index 0000000..b99f283 --- /dev/null +++ b/lib/solmate/package-lock.json @@ -0,0 +1,125 @@ +{ + "name": "solmate", + "version": "6.2.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@solidity-parser/parser": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.13.2.tgz", + "integrity": "sha512-RwHnpRnfrnD2MSPveYoPh8nhofEvX7fgjHk1Oq+NNvCcLx4r1js91CO9o+F/F3fBzOCyvm8kKRTriFICX/odWw==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "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 + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, + "prettier-plugin-solidity": { + "version": "1.0.0-beta.16", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.16.tgz", + "integrity": "sha512-xVBcnoWpe52dNnCCbqPHC9ZrTWXcNfldf852ZD0DBcHDqVMwjHTAPEdfBVy6FczbFpVa8bmxQil+G5XkEz5WHA==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.13.2", + "emoji-regex": "^9.2.2", + "escape-string-regexp": "^4.0.0", + "semver": "^7.3.5", + "solidity-comments-extractor": "^0.0.7", + "string-width": "^4.2.2" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.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 + } + } +} diff --git a/lib/solmate/package.json b/lib/solmate/package.json new file mode 100644 index 0000000..e94cbdf --- /dev/null +++ b/lib/solmate/package.json @@ -0,0 +1,20 @@ +{ + "name": "solmate", + "license": "AGPL-3.0-only", + "version": "6.2.0", + "description": "Modern, opinionated and gas optimized building blocks for smart contract development.", + "files": [ + "src/**/*.sol" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/transmissions11/solmate.git" + }, + "devDependencies": { + "prettier": "^2.3.1", + "prettier-plugin-solidity": "^1.0.0-beta.13" + }, + "scripts": { + "lint": "prettier --write **.sol" + } +} diff --git a/lib/solmate/src/auth/Auth.sol b/lib/solmate/src/auth/Auth.sol new file mode 100644 index 0000000..3807ccd --- /dev/null +++ b/lib/solmate/src/auth/Auth.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol) +/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) +abstract contract Auth { + event OwnershipTransferred(address indexed user, address indexed newOwner); + + event AuthorityUpdated(address indexed user, Authority indexed newAuthority); + + address public owner; + + Authority public authority; + + constructor(address _owner, Authority _authority) { + owner = _owner; + authority = _authority; + + emit OwnershipTransferred(msg.sender, _owner); + emit AuthorityUpdated(msg.sender, _authority); + } + + modifier requiresAuth() virtual { + require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED"); + + _; + } + + function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) { + Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas. + + // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be + // aware that this makes protected functions uncallable even to the owner if the authority is out of order. + return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner; + } + + function setAuthority(Authority newAuthority) public virtual { + // We check if the caller is the owner first because we want to ensure they can + // always swap out the authority even if it's reverting or using up a lot of gas. + require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig)); + + authority = newAuthority; + + emit AuthorityUpdated(msg.sender, newAuthority); + } + + function transferOwnership(address newOwner) public virtual requiresAuth { + owner = newOwner; + + emit OwnershipTransferred(msg.sender, newOwner); + } +} + +/// @notice A generic interface for a contract which provides authorization data to an Auth instance. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol) +/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) +interface Authority { + function canCall( + address user, + address target, + bytes4 functionSig + ) external view returns (bool); +} diff --git a/lib/solmate/src/auth/Owned.sol b/lib/solmate/src/auth/Owned.sol new file mode 100644 index 0000000..e82b44d --- /dev/null +++ b/lib/solmate/src/auth/Owned.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Simple single owner authorization mixin. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) +abstract contract Owned { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event OwnershipTransferred(address indexed user, address indexed newOwner); + + /*////////////////////////////////////////////////////////////// + OWNERSHIP STORAGE + //////////////////////////////////////////////////////////////*/ + + address public owner; + + modifier onlyOwner() virtual { + require(msg.sender == owner, "UNAUTHORIZED"); + + _; + } + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(address _owner) { + owner = _owner; + + emit OwnershipTransferred(address(0), _owner); + } + + /*////////////////////////////////////////////////////////////// + OWNERSHIP LOGIC + //////////////////////////////////////////////////////////////*/ + + function transferOwnership(address newOwner) public virtual onlyOwner { + owner = newOwner; + + emit OwnershipTransferred(msg.sender, newOwner); + } +} diff --git a/lib/solmate/src/auth/authorities/MultiRolesAuthority.sol b/lib/solmate/src/auth/authorities/MultiRolesAuthority.sol new file mode 100644 index 0000000..3ff80bb --- /dev/null +++ b/lib/solmate/src/auth/authorities/MultiRolesAuthority.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Auth, Authority} from "../Auth.sol"; + +/// @notice Flexible and target agnostic role based Authority that supports up to 256 roles. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/authorities/MultiRolesAuthority.sol) +contract MultiRolesAuthority is Auth, Authority { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event UserRoleUpdated(address indexed user, uint8 indexed role, bool enabled); + + event PublicCapabilityUpdated(bytes4 indexed functionSig, bool enabled); + + event RoleCapabilityUpdated(uint8 indexed role, bytes4 indexed functionSig, bool enabled); + + event TargetCustomAuthorityUpdated(address indexed target, Authority indexed authority); + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(address _owner, Authority _authority) Auth(_owner, _authority) {} + + /*////////////////////////////////////////////////////////////// + CUSTOM TARGET AUTHORITY STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => Authority) public getTargetCustomAuthority; + + /*////////////////////////////////////////////////////////////// + ROLE/USER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => bytes32) public getUserRoles; + + mapping(bytes4 => bool) public isCapabilityPublic; + + mapping(bytes4 => bytes32) public getRolesWithCapability; + + function doesUserHaveRole(address user, uint8 role) public view virtual returns (bool) { + return (uint256(getUserRoles[user]) >> role) & 1 != 0; + } + + function doesRoleHaveCapability(uint8 role, bytes4 functionSig) public view virtual returns (bool) { + return (uint256(getRolesWithCapability[functionSig]) >> role) & 1 != 0; + } + + /*////////////////////////////////////////////////////////////// + AUTHORIZATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function canCall( + address user, + address target, + bytes4 functionSig + ) public view virtual override returns (bool) { + Authority customAuthority = getTargetCustomAuthority[target]; + + if (address(customAuthority) != address(0)) return customAuthority.canCall(user, target, functionSig); + + return + isCapabilityPublic[functionSig] || bytes32(0) != getUserRoles[user] & getRolesWithCapability[functionSig]; + } + + /*/////////////////////////////////////////////////////////////// + CUSTOM TARGET AUTHORITY CONFIGURATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function setTargetCustomAuthority(address target, Authority customAuthority) public virtual requiresAuth { + getTargetCustomAuthority[target] = customAuthority; + + emit TargetCustomAuthorityUpdated(target, customAuthority); + } + + /*////////////////////////////////////////////////////////////// + PUBLIC CAPABILITY CONFIGURATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function setPublicCapability(bytes4 functionSig, bool enabled) public virtual requiresAuth { + isCapabilityPublic[functionSig] = enabled; + + emit PublicCapabilityUpdated(functionSig, enabled); + } + + /*////////////////////////////////////////////////////////////// + USER ROLE ASSIGNMENT LOGIC + //////////////////////////////////////////////////////////////*/ + + function setUserRole( + address user, + uint8 role, + bool enabled + ) public virtual requiresAuth { + if (enabled) { + getUserRoles[user] |= bytes32(1 << role); + } else { + getUserRoles[user] &= ~bytes32(1 << role); + } + + emit UserRoleUpdated(user, role, enabled); + } + + /*////////////////////////////////////////////////////////////// + ROLE CAPABILITY CONFIGURATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function setRoleCapability( + uint8 role, + bytes4 functionSig, + bool enabled + ) public virtual requiresAuth { + if (enabled) { + getRolesWithCapability[functionSig] |= bytes32(1 << role); + } else { + getRolesWithCapability[functionSig] &= ~bytes32(1 << role); + } + + emit RoleCapabilityUpdated(role, functionSig, enabled); + } +} diff --git a/lib/solmate/src/auth/authorities/RolesAuthority.sol b/lib/solmate/src/auth/authorities/RolesAuthority.sol new file mode 100644 index 0000000..aa5cc71 --- /dev/null +++ b/lib/solmate/src/auth/authorities/RolesAuthority.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Auth, Authority} from "../Auth.sol"; + +/// @notice Role based Authority that supports up to 256 roles. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/authorities/RolesAuthority.sol) +/// @author Modified from Dappsys (https://github.com/dapphub/ds-roles/blob/master/src/roles.sol) +contract RolesAuthority is Auth, Authority { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event UserRoleUpdated(address indexed user, uint8 indexed role, bool enabled); + + event PublicCapabilityUpdated(address indexed target, bytes4 indexed functionSig, bool enabled); + + event RoleCapabilityUpdated(uint8 indexed role, address indexed target, bytes4 indexed functionSig, bool enabled); + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(address _owner, Authority _authority) Auth(_owner, _authority) {} + + /*////////////////////////////////////////////////////////////// + ROLE/USER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => bytes32) public getUserRoles; + + mapping(address => mapping(bytes4 => bool)) public isCapabilityPublic; + + mapping(address => mapping(bytes4 => bytes32)) public getRolesWithCapability; + + function doesUserHaveRole(address user, uint8 role) public view virtual returns (bool) { + return (uint256(getUserRoles[user]) >> role) & 1 != 0; + } + + function doesRoleHaveCapability( + uint8 role, + address target, + bytes4 functionSig + ) public view virtual returns (bool) { + return (uint256(getRolesWithCapability[target][functionSig]) >> role) & 1 != 0; + } + + /*////////////////////////////////////////////////////////////// + AUTHORIZATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function canCall( + address user, + address target, + bytes4 functionSig + ) public view virtual override returns (bool) { + return + isCapabilityPublic[target][functionSig] || + bytes32(0) != getUserRoles[user] & getRolesWithCapability[target][functionSig]; + } + + /*////////////////////////////////////////////////////////////// + ROLE CAPABILITY CONFIGURATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function setPublicCapability( + address target, + bytes4 functionSig, + bool enabled + ) public virtual requiresAuth { + isCapabilityPublic[target][functionSig] = enabled; + + emit PublicCapabilityUpdated(target, functionSig, enabled); + } + + function setRoleCapability( + uint8 role, + address target, + bytes4 functionSig, + bool enabled + ) public virtual requiresAuth { + if (enabled) { + getRolesWithCapability[target][functionSig] |= bytes32(1 << role); + } else { + getRolesWithCapability[target][functionSig] &= ~bytes32(1 << role); + } + + emit RoleCapabilityUpdated(role, target, functionSig, enabled); + } + + /*////////////////////////////////////////////////////////////// + USER ROLE ASSIGNMENT LOGIC + //////////////////////////////////////////////////////////////*/ + + function setUserRole( + address user, + uint8 role, + bool enabled + ) public virtual requiresAuth { + if (enabled) { + getUserRoles[user] |= bytes32(1 << role); + } else { + getUserRoles[user] &= ~bytes32(1 << role); + } + + emit UserRoleUpdated(user, role, enabled); + } +} diff --git a/lib/solmate/src/mixins/ERC4626.sol b/lib/solmate/src/mixins/ERC4626.sol new file mode 100644 index 0000000..af56c15 --- /dev/null +++ b/lib/solmate/src/mixins/ERC4626.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "../tokens/ERC20.sol"; +import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; +import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol"; + +/// @notice Minimal ERC4626 tokenized Vault implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol) +abstract contract ERC4626 is ERC20 { + using SafeTransferLib for ERC20; + using FixedPointMathLib for uint256; + + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed caller, + address indexed receiver, + address indexed owner, + uint256 assets, + uint256 shares + ); + + /*////////////////////////////////////////////////////////////// + IMMUTABLES + //////////////////////////////////////////////////////////////*/ + + ERC20 public immutable asset; + + constructor( + ERC20 _asset, + string memory _name, + string memory _symbol + ) ERC20(_name, _symbol, _asset.decimals()) { + asset = _asset; + } + + /*////////////////////////////////////////////////////////////// + DEPOSIT/WITHDRAWAL LOGIC + //////////////////////////////////////////////////////////////*/ + + function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) { + // Check for rounding error since we round down in previewDeposit. + require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES"); + + // Need to transfer before minting or ERC777s could reenter. + asset.safeTransferFrom(msg.sender, address(this), assets); + + _mint(receiver, shares); + + emit Deposit(msg.sender, receiver, assets, shares); + + afterDeposit(assets, shares); + } + + function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) { + assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up. + + // Need to transfer before minting or ERC777s could reenter. + asset.safeTransferFrom(msg.sender, address(this), assets); + + _mint(receiver, shares); + + emit Deposit(msg.sender, receiver, assets, shares); + + afterDeposit(assets, shares); + } + + function withdraw( + uint256 assets, + address receiver, + address owner + ) public virtual returns (uint256 shares) { + shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up. + + if (msg.sender != owner) { + uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; + } + + beforeWithdraw(assets, shares); + + _burn(owner, shares); + + emit Withdraw(msg.sender, receiver, owner, assets, shares); + + asset.safeTransfer(receiver, assets); + } + + function redeem( + uint256 shares, + address receiver, + address owner + ) public virtual returns (uint256 assets) { + if (msg.sender != owner) { + uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; + } + + // Check for rounding error since we round down in previewRedeem. + require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS"); + + beforeWithdraw(assets, shares); + + _burn(owner, shares); + + emit Withdraw(msg.sender, receiver, owner, assets, shares); + + asset.safeTransfer(receiver, assets); + } + + /*////////////////////////////////////////////////////////////// + ACCOUNTING LOGIC + //////////////////////////////////////////////////////////////*/ + + function totalAssets() public view virtual returns (uint256); + + function convertToShares(uint256 assets) public view virtual returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); + } + + function convertToAssets(uint256 shares) public view virtual returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply); + } + + function previewDeposit(uint256 assets) public view virtual returns (uint256) { + return convertToShares(assets); + } + + function previewMint(uint256 shares) public view virtual returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); + } + + function previewWithdraw(uint256 assets) public view virtual returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets()); + } + + function previewRedeem(uint256 shares) public view virtual returns (uint256) { + return convertToAssets(shares); + } + + /*////////////////////////////////////////////////////////////// + DEPOSIT/WITHDRAWAL LIMIT LOGIC + //////////////////////////////////////////////////////////////*/ + + function maxDeposit(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + function maxMint(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + function maxWithdraw(address owner) public view virtual returns (uint256) { + return convertToAssets(balanceOf[owner]); + } + + function maxRedeem(address owner) public view virtual returns (uint256) { + return balanceOf[owner]; + } + + /*////////////////////////////////////////////////////////////// + INTERNAL HOOKS LOGIC + //////////////////////////////////////////////////////////////*/ + + function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {} + + function afterDeposit(uint256 assets, uint256 shares) internal virtual {} +} diff --git a/lib/solmate/src/test/Auth.t.sol b/lib/solmate/src/test/Auth.t.sol new file mode 100644 index 0000000..9e31528 --- /dev/null +++ b/lib/solmate/src/test/Auth.t.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockAuthChild} from "./utils/mocks/MockAuthChild.sol"; +import {MockAuthority} from "./utils/mocks/MockAuthority.sol"; + +import {Authority} from "../auth/Auth.sol"; + +contract OutOfOrderAuthority is Authority { + function canCall( + address, + address, + bytes4 + ) public pure override returns (bool) { + revert("OUT_OF_ORDER"); + } +} + +contract AuthTest is DSTestPlus { + MockAuthChild mockAuthChild; + + function setUp() public { + mockAuthChild = new MockAuthChild(); + } + + function testTransferOwnershipAsOwner() public { + mockAuthChild.transferOwnership(address(0xBEEF)); + assertEq(mockAuthChild.owner(), address(0xBEEF)); + } + + function testSetAuthorityAsOwner() public { + mockAuthChild.setAuthority(Authority(address(0xBEEF))); + assertEq(address(mockAuthChild.authority()), address(0xBEEF)); + } + + function testCallFunctionAsOwner() public { + mockAuthChild.updateFlag(); + } + + function testTransferOwnershipWithPermissiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.transferOwnership(address(this)); + } + + function testSetAuthorityWithPermissiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.setAuthority(Authority(address(0xBEEF))); + } + + function testCallFunctionWithPermissiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.updateFlag(); + } + + function testSetAuthorityAsOwnerWithOutOfOrderAuthority() public { + mockAuthChild.setAuthority(new OutOfOrderAuthority()); + mockAuthChild.setAuthority(new MockAuthority(true)); + } + + function testFailTransferOwnershipAsNonOwner() public { + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.transferOwnership(address(0xBEEF)); + } + + function testFailSetAuthorityAsNonOwner() public { + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.setAuthority(Authority(address(0xBEEF))); + } + + function testFailCallFunctionAsNonOwner() public { + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipWithRestrictiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.transferOwnership(address(this)); + } + + function testFailSetAuthorityWithRestrictiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.setAuthority(Authority(address(0xBEEF))); + } + + function testFailCallFunctionWithRestrictiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipAsOwnerWithOutOfOrderAuthority() public { + mockAuthChild.setAuthority(new OutOfOrderAuthority()); + mockAuthChild.transferOwnership(address(0)); + } + + function testFailCallFunctionAsOwnerWithOutOfOrderAuthority() public { + mockAuthChild.setAuthority(new OutOfOrderAuthority()); + mockAuthChild.updateFlag(); + } + + function testTransferOwnershipAsOwner(address newOwner) public { + mockAuthChild.transferOwnership(newOwner); + assertEq(mockAuthChild.owner(), newOwner); + } + + function testSetAuthorityAsOwner(Authority newAuthority) public { + mockAuthChild.setAuthority(newAuthority); + assertEq(address(mockAuthChild.authority()), address(newAuthority)); + } + + function testTransferOwnershipWithPermissiveAuthority(address deadOwner, address newOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.transferOwnership(newOwner); + } + + function testSetAuthorityWithPermissiveAuthority(address deadOwner, Authority newAuthority) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.setAuthority(newAuthority); + } + + function testCallFunctionWithPermissiveAuthority(address deadOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipAsNonOwner(address deadOwner, address newOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.transferOwnership(newOwner); + } + + function testFailSetAuthorityAsNonOwner(address deadOwner, Authority newAuthority) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.setAuthority(newAuthority); + } + + function testFailCallFunctionAsNonOwner(address deadOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipWithRestrictiveAuthority(address deadOwner, address newOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.transferOwnership(newOwner); + } + + function testFailSetAuthorityWithRestrictiveAuthority(address deadOwner, Authority newAuthority) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.setAuthority(newAuthority); + } + + function testFailCallFunctionWithRestrictiveAuthority(address deadOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipAsOwnerWithOutOfOrderAuthority(address deadOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new OutOfOrderAuthority()); + mockAuthChild.transferOwnership(deadOwner); + } +} diff --git a/lib/solmate/src/test/Bytes32AddressLib.t.sol b/lib/solmate/src/test/Bytes32AddressLib.t.sol new file mode 100644 index 0000000..6c0a3d8 --- /dev/null +++ b/lib/solmate/src/test/Bytes32AddressLib.t.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {Bytes32AddressLib} from "../utils/Bytes32AddressLib.sol"; + +contract Bytes32AddressLibTest is DSTestPlus { + function testFillLast12Bytes() public { + assertEq( + Bytes32AddressLib.fillLast12Bytes(0xfEEDFaCEcaFeBEEFfEEDFACecaFEBeeFfeEdfAce), + 0xfeedfacecafebeeffeedfacecafebeeffeedface000000000000000000000000 + ); + } + + function testFromLast20Bytes() public { + assertEq( + Bytes32AddressLib.fromLast20Bytes(0xfeedfacecafebeeffeedfacecafebeeffeedfacecafebeeffeedfacecafebeef), + 0xCAfeBeefFeedfAceCAFeBEEffEEDfaCecafEBeeF + ); + } +} diff --git a/lib/solmate/src/test/CREATE3.t.sol b/lib/solmate/src/test/CREATE3.t.sol new file mode 100644 index 0000000..b279eeb --- /dev/null +++ b/lib/solmate/src/test/CREATE3.t.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {WETH} from "../tokens/WETH.sol"; +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockERC20} from "./utils/mocks/MockERC20.sol"; +import {MockAuthChild} from "./utils/mocks/MockAuthChild.sol"; + +import {CREATE3} from "../utils/CREATE3.sol"; + +contract CREATE3Test is DSTestPlus { + function testDeployERC20() public { + bytes32 salt = keccak256(bytes("A salt!")); + + MockERC20 deployed = MockERC20( + CREATE3.deploy( + salt, + abi.encodePacked(type(MockERC20).creationCode, abi.encode("Mock Token", "MOCK", 18)), + 0 + ) + ); + + assertEq(address(deployed), CREATE3.getDeployed(salt)); + + assertEq(deployed.name(), "Mock Token"); + assertEq(deployed.symbol(), "MOCK"); + assertEq(deployed.decimals(), 18); + } + + function testFailDoubleDeploySameBytecode() public { + bytes32 salt = keccak256(bytes("Salty...")); + + CREATE3.deploy(salt, type(MockAuthChild).creationCode, 0); + CREATE3.deploy(salt, type(MockAuthChild).creationCode, 0); + } + + function testFailDoubleDeployDifferentBytecode() public { + bytes32 salt = keccak256(bytes("and sweet!")); + + CREATE3.deploy(salt, type(WETH).creationCode, 0); + CREATE3.deploy(salt, type(MockAuthChild).creationCode, 0); + } + + function testDeployERC20( + bytes32 salt, + string calldata name, + string calldata symbol, + uint8 decimals + ) public { + MockERC20 deployed = MockERC20( + CREATE3.deploy(salt, abi.encodePacked(type(MockERC20).creationCode, abi.encode(name, symbol, decimals)), 0) + ); + + assertEq(address(deployed), CREATE3.getDeployed(salt)); + + assertEq(deployed.name(), name); + assertEq(deployed.symbol(), symbol); + assertEq(deployed.decimals(), decimals); + } + + function testFailDoubleDeploySameBytecode(bytes32 salt, bytes calldata bytecode) public { + CREATE3.deploy(salt, bytecode, 0); + CREATE3.deploy(salt, bytecode, 0); + } + + function testFailDoubleDeployDifferentBytecode( + bytes32 salt, + bytes calldata bytecode1, + bytes calldata bytecode2 + ) public { + CREATE3.deploy(salt, bytecode1, 0); + CREATE3.deploy(salt, bytecode2, 0); + } +} diff --git a/lib/solmate/src/test/DSTestPlus.t.sol b/lib/solmate/src/test/DSTestPlus.t.sol new file mode 100644 index 0000000..db10860 --- /dev/null +++ b/lib/solmate/src/test/DSTestPlus.t.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +contract DSTestPlusTest is DSTestPlus { + function testBound() public { + assertEq(bound(0, 69, 69), 69); + assertEq(bound(0, 68, 69), 68); + assertEq(bound(5, 0, 4), 0); + assertEq(bound(9999, 1337, 6666), 6006); + assertEq(bound(0, type(uint256).max - 6, type(uint256).max), type(uint256).max - 6); + assertEq(bound(6, type(uint256).max - 6, type(uint256).max), type(uint256).max); + } + + function testFailBoundMinBiggerThanMax() public { + bound(5, 100, 10); + } + + function testRelApproxEqBothZeroesPasses() public { + assertRelApproxEq(0, 0, 1e18); + assertRelApproxEq(0, 0, 0); + } + + function testBound( + uint256 num, + uint256 min, + uint256 max + ) public { + if (min > max) (min, max) = (max, min); + + uint256 bounded = bound(num, min, max); + + assertGe(bounded, min); + assertLe(bounded, max); + } + + function testFailBoundMinBiggerThanMax( + uint256 num, + uint256 min, + uint256 max + ) public { + if (max == min) { + unchecked { + min++; // Overflow is handled below. + } + } + + if (max > min) (min, max) = (max, min); + + bound(num, min, max); + } + + function testBrutalizeMemory() public brutalizeMemory("FEEDFACECAFEBEEFFEEDFACECAFEBEEF") { + bytes32 scratchSpace1; + bytes32 scratchSpace2; + bytes32 freeMem1; + bytes32 freeMem2; + + assembly { + scratchSpace1 := mload(0) + scratchSpace2 := mload(32) + freeMem1 := mload(mload(0x40)) + freeMem2 := mload(add(mload(0x40), 32)) + } + + assertGt(uint256(freeMem1), 0); + assertGt(uint256(freeMem2), 0); + assertGt(uint256(scratchSpace1), 0); + assertGt(uint256(scratchSpace2), 0); + } +} diff --git a/lib/solmate/src/test/ERC1155.t.sol b/lib/solmate/src/test/ERC1155.t.sol new file mode 100644 index 0000000..9e32d88 --- /dev/null +++ b/lib/solmate/src/test/ERC1155.t.sol @@ -0,0 +1,1777 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {MockERC1155} from "./utils/mocks/MockERC1155.sol"; + +import {ERC1155TokenReceiver} from "../tokens/ERC1155.sol"; + +contract ERC1155Recipient is ERC1155TokenReceiver { + address public operator; + address public from; + uint256 public id; + uint256 public amount; + bytes public mintData; + + function onERC1155Received( + address _operator, + address _from, + uint256 _id, + uint256 _amount, + bytes calldata _data + ) public override returns (bytes4) { + operator = _operator; + from = _from; + id = _id; + amount = _amount; + mintData = _data; + + return ERC1155TokenReceiver.onERC1155Received.selector; + } + + address public batchOperator; + address public batchFrom; + uint256[] internal _batchIds; + uint256[] internal _batchAmounts; + bytes public batchData; + + function batchIds() external view returns (uint256[] memory) { + return _batchIds; + } + + function batchAmounts() external view returns (uint256[] memory) { + return _batchAmounts; + } + + function onERC1155BatchReceived( + address _operator, + address _from, + uint256[] calldata _ids, + uint256[] calldata _amounts, + bytes calldata _data + ) external override returns (bytes4) { + batchOperator = _operator; + batchFrom = _from; + _batchIds = _ids; + _batchAmounts = _amounts; + batchData = _data; + + return ERC1155TokenReceiver.onERC1155BatchReceived.selector; + } +} + +contract RevertingERC1155Recipient is ERC1155TokenReceiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes calldata + ) public pure override returns (bytes4) { + revert(string(abi.encodePacked(ERC1155TokenReceiver.onERC1155Received.selector))); + } + + function onERC1155BatchReceived( + address, + address, + uint256[] calldata, + uint256[] calldata, + bytes calldata + ) external pure override returns (bytes4) { + revert(string(abi.encodePacked(ERC1155TokenReceiver.onERC1155BatchReceived.selector))); + } +} + +contract WrongReturnDataERC1155Recipient is ERC1155TokenReceiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes calldata + ) public pure override returns (bytes4) { + return 0xCAFEBEEF; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] calldata, + uint256[] calldata, + bytes calldata + ) external pure override returns (bytes4) { + return 0xCAFEBEEF; + } +} + +contract NonERC1155Recipient {} + +contract ERC1155Test is DSTestPlus, ERC1155TokenReceiver { + MockERC1155 token; + + mapping(address => mapping(uint256 => uint256)) public userMintAmounts; + mapping(address => mapping(uint256 => uint256)) public userTransferOrBurnAmounts; + + function setUp() public { + token = new MockERC1155(); + } + + function testMintToEOA() public { + token.mint(address(0xBEEF), 1337, 1, ""); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 1); + } + + function testMintToERC1155Recipient() public { + ERC1155Recipient to = new ERC1155Recipient(); + + token.mint(address(to), 1337, 1, "testing 123"); + + assertEq(token.balanceOf(address(to), 1337), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), 1337); + assertBytesEq(to.mintData(), "testing 123"); + } + + function testBatchMintToEOA() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory amounts = new uint256[](5); + amounts[0] = 100; + amounts[1] = 200; + amounts[2] = 300; + amounts[3] = 400; + amounts[4] = 500; + + token.batchMint(address(0xBEEF), ids, amounts, ""); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 100); + assertEq(token.balanceOf(address(0xBEEF), 1338), 200); + assertEq(token.balanceOf(address(0xBEEF), 1339), 300); + assertEq(token.balanceOf(address(0xBEEF), 1340), 400); + assertEq(token.balanceOf(address(0xBEEF), 1341), 500); + } + + function testBatchMintToERC1155Recipient() public { + ERC1155Recipient to = new ERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory amounts = new uint256[](5); + amounts[0] = 100; + amounts[1] = 200; + amounts[2] = 300; + amounts[3] = 400; + amounts[4] = 500; + + token.batchMint(address(to), ids, amounts, "testing 123"); + + assertEq(to.batchOperator(), address(this)); + assertEq(to.batchFrom(), address(0)); + assertUintArrayEq(to.batchIds(), ids); + assertUintArrayEq(to.batchAmounts(), amounts); + assertBytesEq(to.batchData(), "testing 123"); + + assertEq(token.balanceOf(address(to), 1337), 100); + assertEq(token.balanceOf(address(to), 1338), 200); + assertEq(token.balanceOf(address(to), 1339), 300); + assertEq(token.balanceOf(address(to), 1340), 400); + assertEq(token.balanceOf(address(to), 1341), 500); + } + + function testBurn() public { + token.mint(address(0xBEEF), 1337, 100, ""); + + token.burn(address(0xBEEF), 1337, 70); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 30); + } + + function testBatchBurn() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory burnAmounts = new uint256[](5); + burnAmounts[0] = 50; + burnAmounts[1] = 100; + burnAmounts[2] = 150; + burnAmounts[3] = 200; + burnAmounts[4] = 250; + + token.batchMint(address(0xBEEF), ids, mintAmounts, ""); + + token.batchBurn(address(0xBEEF), ids, burnAmounts); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 50); + assertEq(token.balanceOf(address(0xBEEF), 1338), 100); + assertEq(token.balanceOf(address(0xBEEF), 1339), 150); + assertEq(token.balanceOf(address(0xBEEF), 1340), 200); + assertEq(token.balanceOf(address(0xBEEF), 1341), 250); + } + + function testApproveAll() public { + token.setApprovalForAll(address(0xBEEF), true); + + assertTrue(token.isApprovedForAll(address(this), address(0xBEEF))); + } + + function testSafeTransferFromToEOA() public { + address from = address(0xABCD); + + token.mint(from, 1337, 100, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(0xBEEF), 1337, 70, ""); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 70); + assertEq(token.balanceOf(from, 1337), 30); + } + + function testSafeTransferFromToERC1155Recipient() public { + ERC1155Recipient to = new ERC1155Recipient(); + + address from = address(0xABCD); + + token.mint(from, 1337, 100, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(to), 1337, 70, "testing 123"); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), from); + assertEq(to.id(), 1337); + assertBytesEq(to.mintData(), "testing 123"); + + assertEq(token.balanceOf(address(to), 1337), 70); + assertEq(token.balanceOf(from, 1337), 30); + } + + function testSafeTransferFromSelf() public { + token.mint(address(this), 1337, 100, ""); + + token.safeTransferFrom(address(this), address(0xBEEF), 1337, 70, ""); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 70); + assertEq(token.balanceOf(address(this), 1337), 30); + } + + function testSafeBatchTransferFromToEOA() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); + + assertEq(token.balanceOf(from, 1337), 50); + assertEq(token.balanceOf(address(0xBEEF), 1337), 50); + + assertEq(token.balanceOf(from, 1338), 100); + assertEq(token.balanceOf(address(0xBEEF), 1338), 100); + + assertEq(token.balanceOf(from, 1339), 150); + assertEq(token.balanceOf(address(0xBEEF), 1339), 150); + + assertEq(token.balanceOf(from, 1340), 200); + assertEq(token.balanceOf(address(0xBEEF), 1340), 200); + + assertEq(token.balanceOf(from, 1341), 250); + assertEq(token.balanceOf(address(0xBEEF), 1341), 250); + } + + function testSafeBatchTransferFromToERC1155Recipient() public { + address from = address(0xABCD); + + ERC1155Recipient to = new ERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(to), ids, transferAmounts, "testing 123"); + + assertEq(to.batchOperator(), address(this)); + assertEq(to.batchFrom(), from); + assertUintArrayEq(to.batchIds(), ids); + assertUintArrayEq(to.batchAmounts(), transferAmounts); + assertBytesEq(to.batchData(), "testing 123"); + + assertEq(token.balanceOf(from, 1337), 50); + assertEq(token.balanceOf(address(to), 1337), 50); + + assertEq(token.balanceOf(from, 1338), 100); + assertEq(token.balanceOf(address(to), 1338), 100); + + assertEq(token.balanceOf(from, 1339), 150); + assertEq(token.balanceOf(address(to), 1339), 150); + + assertEq(token.balanceOf(from, 1340), 200); + assertEq(token.balanceOf(address(to), 1340), 200); + + assertEq(token.balanceOf(from, 1341), 250); + assertEq(token.balanceOf(address(to), 1341), 250); + } + + function testBatchBalanceOf() public { + address[] memory tos = new address[](5); + tos[0] = address(0xBEEF); + tos[1] = address(0xCAFE); + tos[2] = address(0xFACE); + tos[3] = address(0xDEAD); + tos[4] = address(0xFEED); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + token.mint(address(0xBEEF), 1337, 100, ""); + token.mint(address(0xCAFE), 1338, 200, ""); + token.mint(address(0xFACE), 1339, 300, ""); + token.mint(address(0xDEAD), 1340, 400, ""); + token.mint(address(0xFEED), 1341, 500, ""); + + uint256[] memory balances = token.balanceOfBatch(tos, ids); + + assertEq(balances[0], 100); + assertEq(balances[1], 200); + assertEq(balances[2], 300); + assertEq(balances[3], 400); + assertEq(balances[4], 500); + } + + function testFailMintToZero() public { + token.mint(address(0), 1337, 1, ""); + } + + function testFailMintToNonERC155Recipient() public { + token.mint(address(new NonERC1155Recipient()), 1337, 1, ""); + } + + function testFailMintToRevertingERC155Recipient() public { + token.mint(address(new RevertingERC1155Recipient()), 1337, 1, ""); + } + + function testFailMintToWrongReturnDataERC155Recipient() public { + token.mint(address(new RevertingERC1155Recipient()), 1337, 1, ""); + } + + function testFailBurnInsufficientBalance() public { + token.mint(address(0xBEEF), 1337, 70, ""); + token.burn(address(0xBEEF), 1337, 100); + } + + function testFailSafeTransferFromInsufficientBalance() public { + address from = address(0xABCD); + + token.mint(from, 1337, 70, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(0xBEEF), 1337, 100, ""); + } + + function testFailSafeTransferFromSelfInsufficientBalance() public { + token.mint(address(this), 1337, 70, ""); + token.safeTransferFrom(address(this), address(0xBEEF), 1337, 100, ""); + } + + function testFailSafeTransferFromToZero() public { + token.mint(address(this), 1337, 100, ""); + token.safeTransferFrom(address(this), address(0), 1337, 70, ""); + } + + function testFailSafeTransferFromToNonERC155Recipient() public { + token.mint(address(this), 1337, 100, ""); + token.safeTransferFrom(address(this), address(new NonERC1155Recipient()), 1337, 70, ""); + } + + function testFailSafeTransferFromToRevertingERC1155Recipient() public { + token.mint(address(this), 1337, 100, ""); + token.safeTransferFrom(address(this), address(new RevertingERC1155Recipient()), 1337, 70, ""); + } + + function testFailSafeTransferFromToWrongReturnDataERC1155Recipient() public { + token.mint(address(this), 1337, 100, ""); + token.safeTransferFrom(address(this), address(new WrongReturnDataERC1155Recipient()), 1337, 70, ""); + } + + function testFailSafeBatchTransferInsufficientBalance() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + + mintAmounts[0] = 50; + mintAmounts[1] = 100; + mintAmounts[2] = 150; + mintAmounts[3] = 200; + mintAmounts[4] = 250; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 100; + transferAmounts[1] = 200; + transferAmounts[2] = 300; + transferAmounts[3] = 400; + transferAmounts[4] = 500; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromToZero() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromToNonERC1155Recipient() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(new NonERC1155Recipient()), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromToRevertingERC1155Recipient() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(new RevertingERC1155Recipient()), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(new WrongReturnDataERC1155Recipient()), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromWithArrayLengthMismatch() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](4); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); + } + + function testFailBatchMintToZero() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + token.batchMint(address(0), ids, mintAmounts, ""); + } + + function testFailBatchMintToNonERC1155Recipient() public { + NonERC1155Recipient to = new NonERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + token.batchMint(address(to), ids, mintAmounts, ""); + } + + function testFailBatchMintToRevertingERC1155Recipient() public { + RevertingERC1155Recipient to = new RevertingERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + token.batchMint(address(to), ids, mintAmounts, ""); + } + + function testFailBatchMintToWrongReturnDataERC1155Recipient() public { + WrongReturnDataERC1155Recipient to = new WrongReturnDataERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + token.batchMint(address(to), ids, mintAmounts, ""); + } + + function testFailBatchMintWithArrayMismatch() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory amounts = new uint256[](4); + amounts[0] = 100; + amounts[1] = 200; + amounts[2] = 300; + amounts[3] = 400; + + token.batchMint(address(0xBEEF), ids, amounts, ""); + } + + function testFailBatchBurnInsufficientBalance() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 50; + mintAmounts[1] = 100; + mintAmounts[2] = 150; + mintAmounts[3] = 200; + mintAmounts[4] = 250; + + uint256[] memory burnAmounts = new uint256[](5); + burnAmounts[0] = 100; + burnAmounts[1] = 200; + burnAmounts[2] = 300; + burnAmounts[3] = 400; + burnAmounts[4] = 500; + + token.batchMint(address(0xBEEF), ids, mintAmounts, ""); + + token.batchBurn(address(0xBEEF), ids, burnAmounts); + } + + function testFailBatchBurnWithArrayLengthMismatch() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory burnAmounts = new uint256[](4); + burnAmounts[0] = 50; + burnAmounts[1] = 100; + burnAmounts[2] = 150; + burnAmounts[3] = 200; + + token.batchMint(address(0xBEEF), ids, mintAmounts, ""); + + token.batchBurn(address(0xBEEF), ids, burnAmounts); + } + + function testFailBalanceOfBatchWithArrayMismatch() public view { + address[] memory tos = new address[](5); + tos[0] = address(0xBEEF); + tos[1] = address(0xCAFE); + tos[2] = address(0xFACE); + tos[3] = address(0xDEAD); + tos[4] = address(0xFEED); + + uint256[] memory ids = new uint256[](4); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + + token.balanceOfBatch(tos, ids); + } + + function testMintToEOA( + address to, + uint256 id, + uint256 amount, + bytes memory mintData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + token.mint(to, id, amount, mintData); + + assertEq(token.balanceOf(to, id), amount); + } + + function testMintToERC1155Recipient( + uint256 id, + uint256 amount, + bytes memory mintData + ) public { + ERC1155Recipient to = new ERC1155Recipient(); + + token.mint(address(to), id, amount, mintData); + + assertEq(token.balanceOf(address(to), id), amount); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), id); + assertBytesEq(to.mintData(), mintData); + } + + function testBatchMintToEOA( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[to][id] += mintAmount; + } + + token.batchMint(to, normalizedIds, normalizedAmounts, mintData); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + + assertEq(token.balanceOf(to, id), userMintAmounts[to][id]); + } + } + + function testBatchMintToERC1155Recipient( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + ERC1155Recipient to = new ERC1155Recipient(); + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(to)][id] += mintAmount; + } + + token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); + + assertEq(to.batchOperator(), address(this)); + assertEq(to.batchFrom(), address(0)); + assertUintArrayEq(to.batchIds(), normalizedIds); + assertUintArrayEq(to.batchAmounts(), normalizedAmounts); + assertBytesEq(to.batchData(), mintData); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + + assertEq(token.balanceOf(address(to), id), userMintAmounts[address(to)][id]); + } + } + + function testBurn( + address to, + uint256 id, + uint256 mintAmount, + bytes memory mintData, + uint256 burnAmount + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + burnAmount = bound(burnAmount, 0, mintAmount); + + token.mint(to, id, mintAmount, mintData); + + token.burn(to, id, burnAmount); + + assertEq(token.balanceOf(address(to), id), mintAmount - burnAmount); + } + + function testBatchBurn( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory burnAmounts, + bytes memory mintData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + uint256 minLength = min3(ids.length, mintAmounts.length, burnAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedBurnAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + normalizedIds[i] = id; + normalizedMintAmounts[i] = bound(mintAmounts[i], 0, remainingMintAmountForId); + normalizedBurnAmounts[i] = bound(burnAmounts[i], 0, normalizedMintAmounts[i]); + + userMintAmounts[address(to)][id] += normalizedMintAmounts[i]; + userTransferOrBurnAmounts[address(to)][id] += normalizedBurnAmounts[i]; + } + + token.batchMint(to, normalizedIds, normalizedMintAmounts, mintData); + + token.batchBurn(to, normalizedIds, normalizedBurnAmounts); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + + assertEq(token.balanceOf(to, id), userMintAmounts[to][id] - userTransferOrBurnAmounts[to][id]); + } + } + + function testApproveAll(address to, bool approved) public { + token.setApprovalForAll(to, approved); + + assertBoolEq(token.isApprovedForAll(address(this), to), approved); + } + + function testSafeTransferFromToEOA( + uint256 id, + uint256 mintAmount, + bytes memory mintData, + uint256 transferAmount, + address to, + bytes memory transferData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + transferAmount = bound(transferAmount, 0, mintAmount); + + address from = address(0xABCD); + + token.mint(from, id, mintAmount, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, to, id, transferAmount, transferData); + + if (to == from) { + assertEq(token.balanceOf(to, id), mintAmount); + } else { + assertEq(token.balanceOf(to, id), transferAmount); + assertEq(token.balanceOf(from, id), mintAmount - transferAmount); + } + } + + function testSafeTransferFromToERC1155Recipient( + uint256 id, + uint256 mintAmount, + bytes memory mintData, + uint256 transferAmount, + bytes memory transferData + ) public { + ERC1155Recipient to = new ERC1155Recipient(); + + address from = address(0xABCD); + + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(from, id, mintAmount, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(to), id, transferAmount, transferData); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), from); + assertEq(to.id(), id); + assertBytesEq(to.mintData(), transferData); + + assertEq(token.balanceOf(address(to), id), transferAmount); + assertEq(token.balanceOf(from, id), mintAmount - transferAmount); + } + + function testSafeTransferFromSelf( + uint256 id, + uint256 mintAmount, + bytes memory mintData, + uint256 transferAmount, + address to, + bytes memory transferData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + + token.safeTransferFrom(address(this), to, id, transferAmount, transferData); + + assertEq(token.balanceOf(to, id), transferAmount); + assertEq(token.balanceOf(address(this), id), mintAmount - transferAmount); + } + + function testSafeBatchTransferFromToEOA( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + userTransferOrBurnAmounts[from][id] += transferAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, to, normalizedIds, normalizedTransferAmounts, transferData); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + + assertEq(token.balanceOf(address(to), id), userTransferOrBurnAmounts[from][id]); + assertEq(token.balanceOf(from, id), userMintAmounts[from][id] - userTransferOrBurnAmounts[from][id]); + } + } + + function testSafeBatchTransferFromToERC1155Recipient( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + ERC1155Recipient to = new ERC1155Recipient(); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + userTransferOrBurnAmounts[from][id] += transferAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(to), normalizedIds, normalizedTransferAmounts, transferData); + + assertEq(to.batchOperator(), address(this)); + assertEq(to.batchFrom(), from); + assertUintArrayEq(to.batchIds(), normalizedIds); + assertUintArrayEq(to.batchAmounts(), normalizedTransferAmounts); + assertBytesEq(to.batchData(), transferData); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + uint256 transferAmount = userTransferOrBurnAmounts[from][id]; + + assertEq(token.balanceOf(address(to), id), transferAmount); + assertEq(token.balanceOf(from, id), userMintAmounts[from][id] - transferAmount); + } + } + + function testBatchBalanceOf( + address[] memory tos, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + uint256 minLength = min3(tos.length, ids.length, amounts.length); + + address[] memory normalizedTos = new address[](minLength); + uint256[] memory normalizedIds = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + address to = tos[i] == address(0) || tos[i].code.length > 0 ? address(0xBEEF) : tos[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; + + normalizedTos[i] = to; + normalizedIds[i] = id; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + token.mint(to, id, mintAmount, mintData); + + userMintAmounts[to][id] += mintAmount; + } + + uint256[] memory balances = token.balanceOfBatch(normalizedTos, normalizedIds); + + for (uint256 i = 0; i < normalizedTos.length; i++) { + assertEq(balances[i], token.balanceOf(normalizedTos[i], normalizedIds[i])); + } + } + + function testFailMintToZero( + uint256 id, + uint256 amount, + bytes memory data + ) public { + token.mint(address(0), id, amount, data); + } + + function testFailMintToNonERC155Recipient( + uint256 id, + uint256 mintAmount, + bytes memory mintData + ) public { + token.mint(address(new NonERC1155Recipient()), id, mintAmount, mintData); + } + + function testFailMintToRevertingERC155Recipient( + uint256 id, + uint256 mintAmount, + bytes memory mintData + ) public { + token.mint(address(new RevertingERC1155Recipient()), id, mintAmount, mintData); + } + + function testFailMintToWrongReturnDataERC155Recipient( + uint256 id, + uint256 mintAmount, + bytes memory mintData + ) public { + token.mint(address(new RevertingERC1155Recipient()), id, mintAmount, mintData); + } + + function testFailBurnInsufficientBalance( + address to, + uint256 id, + uint256 mintAmount, + uint256 burnAmount, + bytes memory mintData + ) public { + burnAmount = bound(burnAmount, mintAmount + 1, type(uint256).max); + + token.mint(to, id, mintAmount, mintData); + token.burn(to, id, burnAmount); + } + + function testFailSafeTransferFromInsufficientBalance( + address to, + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + transferAmount = bound(transferAmount, mintAmount + 1, type(uint256).max); + + token.mint(from, id, mintAmount, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, to, id, transferAmount, transferData); + } + + function testFailSafeTransferFromSelfInsufficientBalance( + address to, + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, mintAmount + 1, type(uint256).max); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom(address(this), to, id, transferAmount, transferData); + } + + function testFailSafeTransferFromToZero( + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom(address(this), address(0), id, transferAmount, transferData); + } + + function testFailSafeTransferFromToNonERC155Recipient( + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom(address(this), address(new NonERC1155Recipient()), id, transferAmount, transferData); + } + + function testFailSafeTransferFromToRevertingERC1155Recipient( + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom( + address(this), + address(new RevertingERC1155Recipient()), + id, + transferAmount, + transferData + ); + } + + function testFailSafeTransferFromToWrongReturnDataERC1155Recipient( + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom( + address(this), + address(new WrongReturnDataERC1155Recipient()), + id, + transferAmount, + transferData + ); + } + + function testFailSafeBatchTransferInsufficientBalance( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + if (minLength == 0) revert(); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], mintAmount + 1, type(uint256).max); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, to, normalizedIds, normalizedTransferAmounts, transferData); + } + + function testFailSafeBatchTransferFromToZero( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0), normalizedIds, normalizedTransferAmounts, transferData); + } + + function testFailSafeBatchTransferFromToNonERC1155Recipient( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom( + from, + address(new NonERC1155Recipient()), + normalizedIds, + normalizedTransferAmounts, + transferData + ); + } + + function testFailSafeBatchTransferFromToRevertingERC1155Recipient( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom( + from, + address(new RevertingERC1155Recipient()), + normalizedIds, + normalizedTransferAmounts, + transferData + ); + } + + function testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom( + from, + address(new WrongReturnDataERC1155Recipient()), + normalizedIds, + normalizedTransferAmounts, + transferData + ); + } + + function testFailSafeBatchTransferFromWithArrayLengthMismatch( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + if (ids.length == transferAmounts.length) revert(); + + token.batchMint(from, ids, mintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, to, ids, transferAmounts, transferData); + } + + function testFailBatchMintToZero( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(0)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(0)][id] += mintAmount; + } + + token.batchMint(address(0), normalizedIds, normalizedAmounts, mintData); + } + + function testFailBatchMintToNonERC1155Recipient( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + NonERC1155Recipient to = new NonERC1155Recipient(); + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(to)][id] += mintAmount; + } + + token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); + } + + function testFailBatchMintToRevertingERC1155Recipient( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + RevertingERC1155Recipient to = new RevertingERC1155Recipient(); + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(to)][id] += mintAmount; + } + + token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); + } + + function testFailBatchMintToWrongReturnDataERC1155Recipient( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + WrongReturnDataERC1155Recipient to = new WrongReturnDataERC1155Recipient(); + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(to)][id] += mintAmount; + } + + token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); + } + + function testFailBatchMintWithArrayMismatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + if (ids.length == amounts.length) revert(); + + token.batchMint(address(to), ids, amounts, mintData); + } + + function testFailBatchBurnInsufficientBalance( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory burnAmounts, + bytes memory mintData + ) public { + uint256 minLength = min3(ids.length, mintAmounts.length, burnAmounts.length); + + if (minLength == 0) revert(); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedBurnAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; + + normalizedIds[i] = id; + normalizedMintAmounts[i] = bound(mintAmounts[i], 0, remainingMintAmountForId); + normalizedBurnAmounts[i] = bound(burnAmounts[i], normalizedMintAmounts[i] + 1, type(uint256).max); + + userMintAmounts[to][id] += normalizedMintAmounts[i]; + } + + token.batchMint(to, normalizedIds, normalizedMintAmounts, mintData); + + token.batchBurn(to, normalizedIds, normalizedBurnAmounts); + } + + function testFailBatchBurnWithArrayLengthMismatch( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory burnAmounts, + bytes memory mintData + ) public { + if (ids.length == burnAmounts.length) revert(); + + token.batchMint(to, ids, mintAmounts, mintData); + + token.batchBurn(to, ids, burnAmounts); + } + + function testFailBalanceOfBatchWithArrayMismatch(address[] memory tos, uint256[] memory ids) public view { + if (tos.length == ids.length) revert(); + + token.balanceOfBatch(tos, ids); + } +} diff --git a/lib/solmate/src/test/ERC20.t.sol b/lib/solmate/src/test/ERC20.t.sol new file mode 100644 index 0000000..1506d8c --- /dev/null +++ b/lib/solmate/src/test/ERC20.t.sol @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {MockERC20} from "./utils/mocks/MockERC20.sol"; + +contract ERC20Test is DSTestPlus { + MockERC20 token; + + bytes32 constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + function setUp() public { + token = new MockERC20("Token", "TKN", 18); + } + + function invariantMetadata() public { + assertEq(token.name(), "Token"); + assertEq(token.symbol(), "TKN"); + assertEq(token.decimals(), 18); + } + + function testMint() public { + token.mint(address(0xBEEF), 1e18); + + assertEq(token.totalSupply(), 1e18); + assertEq(token.balanceOf(address(0xBEEF)), 1e18); + } + + function testBurn() public { + token.mint(address(0xBEEF), 1e18); + token.burn(address(0xBEEF), 0.9e18); + + assertEq(token.totalSupply(), 1e18 - 0.9e18); + assertEq(token.balanceOf(address(0xBEEF)), 0.1e18); + } + + function testApprove() public { + assertTrue(token.approve(address(0xBEEF), 1e18)); + + assertEq(token.allowance(address(this), address(0xBEEF)), 1e18); + } + + function testTransfer() public { + token.mint(address(this), 1e18); + + assertTrue(token.transfer(address(0xBEEF), 1e18)); + assertEq(token.totalSupply(), 1e18); + + assertEq(token.balanceOf(address(this)), 0); + assertEq(token.balanceOf(address(0xBEEF)), 1e18); + } + + function testTransferFrom() public { + address from = address(0xABCD); + + token.mint(from, 1e18); + + hevm.prank(from); + token.approve(address(this), 1e18); + + assertTrue(token.transferFrom(from, address(0xBEEF), 1e18)); + assertEq(token.totalSupply(), 1e18); + + assertEq(token.allowance(from, address(this)), 0); + + assertEq(token.balanceOf(from), 0); + assertEq(token.balanceOf(address(0xBEEF)), 1e18); + } + + function testInfiniteApproveTransferFrom() public { + address from = address(0xABCD); + + token.mint(from, 1e18); + + hevm.prank(from); + token.approve(address(this), type(uint256).max); + + assertTrue(token.transferFrom(from, address(0xBEEF), 1e18)); + assertEq(token.totalSupply(), 1e18); + + assertEq(token.allowance(from, address(this)), type(uint256).max); + + assertEq(token.balanceOf(from), 0); + assertEq(token.balanceOf(address(0xBEEF)), 1e18); + } + + function testPermit() public { + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, block.timestamp)) + ) + ) + ); + + token.permit(owner, address(0xCAFE), 1e18, block.timestamp, v, r, s); + + assertEq(token.allowance(owner, address(0xCAFE)), 1e18); + assertEq(token.nonces(owner), 1); + } + + function testFailTransferInsufficientBalance() public { + token.mint(address(this), 0.9e18); + token.transfer(address(0xBEEF), 1e18); + } + + function testFailTransferFromInsufficientAllowance() public { + address from = address(0xABCD); + + token.mint(from, 1e18); + + hevm.prank(from); + token.approve(address(this), 0.9e18); + + token.transferFrom(from, address(0xBEEF), 1e18); + } + + function testFailTransferFromInsufficientBalance() public { + address from = address(0xABCD); + + token.mint(from, 0.9e18); + + hevm.prank(from); + token.approve(address(this), 1e18); + + token.transferFrom(from, address(0xBEEF), 1e18); + } + + function testFailPermitBadNonce() public { + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 1, block.timestamp)) + ) + ) + ); + + token.permit(owner, address(0xCAFE), 1e18, block.timestamp, v, r, s); + } + + function testFailPermitBadDeadline() public { + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, block.timestamp)) + ) + ) + ); + + token.permit(owner, address(0xCAFE), 1e18, block.timestamp + 1, v, r, s); + } + + function testFailPermitPastDeadline() public { + uint256 oldTimestamp = block.timestamp; + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, oldTimestamp)) + ) + ) + ); + + hevm.warp(block.timestamp + 1); + token.permit(owner, address(0xCAFE), 1e18, oldTimestamp, v, r, s); + } + + function testFailPermitReplay() public { + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, block.timestamp)) + ) + ) + ); + + token.permit(owner, address(0xCAFE), 1e18, block.timestamp, v, r, s); + token.permit(owner, address(0xCAFE), 1e18, block.timestamp, v, r, s); + } + + function testMetadata( + string calldata name, + string calldata symbol, + uint8 decimals + ) public { + MockERC20 tkn = new MockERC20(name, symbol, decimals); + assertEq(tkn.name(), name); + assertEq(tkn.symbol(), symbol); + assertEq(tkn.decimals(), decimals); + } + + function testMint(address from, uint256 amount) public { + token.mint(from, amount); + + assertEq(token.totalSupply(), amount); + assertEq(token.balanceOf(from), amount); + } + + function testBurn( + address from, + uint256 mintAmount, + uint256 burnAmount + ) public { + burnAmount = bound(burnAmount, 0, mintAmount); + + token.mint(from, mintAmount); + token.burn(from, burnAmount); + + assertEq(token.totalSupply(), mintAmount - burnAmount); + assertEq(token.balanceOf(from), mintAmount - burnAmount); + } + + function testApprove(address to, uint256 amount) public { + assertTrue(token.approve(to, amount)); + + assertEq(token.allowance(address(this), to), amount); + } + + function testTransfer(address from, uint256 amount) public { + token.mint(address(this), amount); + + assertTrue(token.transfer(from, amount)); + assertEq(token.totalSupply(), amount); + + if (address(this) == from) { + assertEq(token.balanceOf(address(this)), amount); + } else { + assertEq(token.balanceOf(address(this)), 0); + assertEq(token.balanceOf(from), amount); + } + } + + function testTransferFrom( + address to, + uint256 approval, + uint256 amount + ) public { + amount = bound(amount, 0, approval); + + address from = address(0xABCD); + + token.mint(from, amount); + + hevm.prank(from); + token.approve(address(this), approval); + + assertTrue(token.transferFrom(from, to, amount)); + assertEq(token.totalSupply(), amount); + + uint256 app = from == address(this) || approval == type(uint256).max ? approval : approval - amount; + assertEq(token.allowance(from, address(this)), app); + + if (from == to) { + assertEq(token.balanceOf(from), amount); + } else { + assertEq(token.balanceOf(from), 0); + assertEq(token.balanceOf(to), amount); + } + } + + function testPermit( + uint248 privKey, + address to, + uint256 amount, + uint256 deadline + ) public { + uint256 privateKey = privKey; + if (deadline < block.timestamp) deadline = block.timestamp; + if (privateKey == 0) privateKey = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, 0, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline, v, r, s); + + assertEq(token.allowance(owner, to), amount); + assertEq(token.nonces(owner), 1); + } + + function testFailBurnInsufficientBalance( + address to, + uint256 mintAmount, + uint256 burnAmount + ) public { + burnAmount = bound(burnAmount, mintAmount + 1, type(uint256).max); + + token.mint(to, mintAmount); + token.burn(to, burnAmount); + } + + function testFailTransferInsufficientBalance( + address to, + uint256 mintAmount, + uint256 sendAmount + ) public { + sendAmount = bound(sendAmount, mintAmount + 1, type(uint256).max); + + token.mint(address(this), mintAmount); + token.transfer(to, sendAmount); + } + + function testFailTransferFromInsufficientAllowance( + address to, + uint256 approval, + uint256 amount + ) public { + amount = bound(amount, approval + 1, type(uint256).max); + + address from = address(0xABCD); + + token.mint(from, amount); + + hevm.prank(from); + token.approve(address(this), approval); + + token.transferFrom(from, to, amount); + } + + function testFailTransferFromInsufficientBalance( + address to, + uint256 mintAmount, + uint256 sendAmount + ) public { + sendAmount = bound(sendAmount, mintAmount + 1, type(uint256).max); + + address from = address(0xABCD); + + token.mint(from, mintAmount); + + hevm.prank(from); + token.approve(address(this), sendAmount); + + token.transferFrom(from, to, sendAmount); + } + + function testFailPermitBadNonce( + uint256 privateKey, + address to, + uint256 amount, + uint256 deadline, + uint256 nonce + ) public { + if (deadline < block.timestamp) deadline = block.timestamp; + if (privateKey == 0) privateKey = 1; + if (nonce == 0) nonce = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, nonce, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline, v, r, s); + } + + function testFailPermitBadDeadline( + uint256 privateKey, + address to, + uint256 amount, + uint256 deadline + ) public { + if (deadline < block.timestamp) deadline = block.timestamp; + if (privateKey == 0) privateKey = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, 0, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline + 1, v, r, s); + } + + function testFailPermitPastDeadline( + uint256 privateKey, + address to, + uint256 amount, + uint256 deadline + ) public { + deadline = bound(deadline, 0, block.timestamp - 1); + if (privateKey == 0) privateKey = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, 0, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline, v, r, s); + } + + function testFailPermitReplay( + uint256 privateKey, + address to, + uint256 amount, + uint256 deadline + ) public { + if (deadline < block.timestamp) deadline = block.timestamp; + if (privateKey == 0) privateKey = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, 0, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline, v, r, s); + token.permit(owner, to, amount, deadline, v, r, s); + } +} + +contract ERC20Invariants is DSTestPlus, DSInvariantTest { + BalanceSum balanceSum; + MockERC20 token; + + function setUp() public { + token = new MockERC20("Token", "TKN", 18); + balanceSum = new BalanceSum(token); + + addTargetContract(address(balanceSum)); + } + + function invariantBalanceSum() public { + assertEq(token.totalSupply(), balanceSum.sum()); + } +} + +contract BalanceSum { + MockERC20 token; + uint256 public sum; + + constructor(MockERC20 _token) { + token = _token; + } + + function mint(address from, uint256 amount) public { + token.mint(from, amount); + sum += amount; + } + + function burn(address from, uint256 amount) public { + token.burn(from, amount); + sum -= amount; + } + + function approve(address to, uint256 amount) public { + token.approve(to, amount); + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public { + token.transferFrom(from, to, amount); + } + + function transfer(address to, uint256 amount) public { + token.transfer(to, amount); + } +} diff --git a/lib/solmate/src/test/ERC4626.t.sol b/lib/solmate/src/test/ERC4626.t.sol new file mode 100644 index 0000000..816c8e4 --- /dev/null +++ b/lib/solmate/src/test/ERC4626.t.sol @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {MockERC20} from "./utils/mocks/MockERC20.sol"; +import {MockERC4626} from "./utils/mocks/MockERC4626.sol"; + +contract ERC4626Test is DSTestPlus { + MockERC20 underlying; + MockERC4626 vault; + + function setUp() public { + underlying = new MockERC20("Mock Token", "TKN", 18); + vault = new MockERC4626(underlying, "Mock Token Vault", "vwTKN"); + } + + function invariantMetadata() public { + assertEq(vault.name(), "Mock Token Vault"); + assertEq(vault.symbol(), "vwTKN"); + assertEq(vault.decimals(), 18); + } + + function testMetadata(string calldata name, string calldata symbol) public { + MockERC4626 vlt = new MockERC4626(underlying, name, symbol); + assertEq(vlt.name(), name); + assertEq(vlt.symbol(), symbol); + assertEq(address(vlt.asset()), address(underlying)); + } + + function testSingleDepositWithdraw(uint128 amount) public { + if (amount == 0) amount = 1; + + uint256 aliceUnderlyingAmount = amount; + + address alice = address(0xABCD); + + underlying.mint(alice, aliceUnderlyingAmount); + + hevm.prank(alice); + underlying.approve(address(vault), aliceUnderlyingAmount); + assertEq(underlying.allowance(alice, address(vault)), aliceUnderlyingAmount); + + uint256 alicePreDepositBal = underlying.balanceOf(alice); + + hevm.prank(alice); + uint256 aliceShareAmount = vault.deposit(aliceUnderlyingAmount, alice); + + assertEq(vault.afterDepositHookCalledCounter(), 1); + + // Expect exchange rate to be 1:1 on initial deposit. + assertEq(aliceUnderlyingAmount, aliceShareAmount); + assertEq(vault.previewWithdraw(aliceShareAmount), aliceUnderlyingAmount); + assertEq(vault.previewDeposit(aliceUnderlyingAmount), aliceShareAmount); + assertEq(vault.totalSupply(), aliceShareAmount); + assertEq(vault.totalAssets(), aliceUnderlyingAmount); + assertEq(vault.balanceOf(alice), aliceShareAmount); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), aliceUnderlyingAmount); + assertEq(underlying.balanceOf(alice), alicePreDepositBal - aliceUnderlyingAmount); + + hevm.prank(alice); + vault.withdraw(aliceUnderlyingAmount, alice, alice); + + assertEq(vault.beforeWithdrawHookCalledCounter(), 1); + + assertEq(vault.totalAssets(), 0); + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 0); + assertEq(underlying.balanceOf(alice), alicePreDepositBal); + } + + function testSingleMintRedeem(uint128 amount) public { + if (amount == 0) amount = 1; + + uint256 aliceShareAmount = amount; + + address alice = address(0xABCD); + + underlying.mint(alice, aliceShareAmount); + + hevm.prank(alice); + underlying.approve(address(vault), aliceShareAmount); + assertEq(underlying.allowance(alice, address(vault)), aliceShareAmount); + + uint256 alicePreDepositBal = underlying.balanceOf(alice); + + hevm.prank(alice); + uint256 aliceUnderlyingAmount = vault.mint(aliceShareAmount, alice); + + assertEq(vault.afterDepositHookCalledCounter(), 1); + + // Expect exchange rate to be 1:1 on initial mint. + assertEq(aliceShareAmount, aliceUnderlyingAmount); + assertEq(vault.previewWithdraw(aliceShareAmount), aliceUnderlyingAmount); + assertEq(vault.previewDeposit(aliceUnderlyingAmount), aliceShareAmount); + assertEq(vault.totalSupply(), aliceShareAmount); + assertEq(vault.totalAssets(), aliceUnderlyingAmount); + assertEq(vault.balanceOf(alice), aliceUnderlyingAmount); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), aliceUnderlyingAmount); + assertEq(underlying.balanceOf(alice), alicePreDepositBal - aliceUnderlyingAmount); + + hevm.prank(alice); + vault.redeem(aliceShareAmount, alice, alice); + + assertEq(vault.beforeWithdrawHookCalledCounter(), 1); + + assertEq(vault.totalAssets(), 0); + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 0); + assertEq(underlying.balanceOf(alice), alicePreDepositBal); + } + + function testMultipleMintDepositRedeemWithdraw() public { + // Scenario: + // A = Alice, B = Bob + // ________________________________________________________ + // | Vault shares | A share | A assets | B share | B assets | + // |========================================================| + // | 1. Alice mints 2000 shares (costs 2000 tokens) | + // |--------------|---------|----------|---------|----------| + // | 2000 | 2000 | 2000 | 0 | 0 | + // |--------------|---------|----------|---------|----------| + // | 2. Bob deposits 4000 tokens (mints 4000 shares) | + // |--------------|---------|----------|---------|----------| + // | 6000 | 2000 | 2000 | 4000 | 4000 | + // |--------------|---------|----------|---------|----------| + // | 3. Vault mutates by +3000 tokens... | + // | (simulated yield returned from strategy)... | + // |--------------|---------|----------|---------|----------| + // | 6000 | 2000 | 3000 | 4000 | 6000 | + // |--------------|---------|----------|---------|----------| + // | 4. Alice deposits 2000 tokens (mints 1333 shares) | + // |--------------|---------|----------|---------|----------| + // | 7333 | 3333 | 4999 | 4000 | 6000 | + // |--------------|---------|----------|---------|----------| + // | 5. Bob mints 2000 shares (costs 3001 assets) | + // | NOTE: Bob's assets spent got rounded up | + // | NOTE: Alice's vault assets got rounded up | + // |--------------|---------|----------|---------|----------| + // | 9333 | 3333 | 5000 | 6000 | 9000 | + // |--------------|---------|----------|---------|----------| + // | 6. Vault mutates by +3000 tokens... | + // | (simulated yield returned from strategy) | + // | NOTE: Vault holds 17001 tokens, but sum of | + // | assetsOf() is 17000. | + // |--------------|---------|----------|---------|----------| + // | 9333 | 3333 | 6071 | 6000 | 10929 | + // |--------------|---------|----------|---------|----------| + // | 7. Alice redeem 1333 shares (2428 assets) | + // |--------------|---------|----------|---------|----------| + // | 8000 | 2000 | 3643 | 6000 | 10929 | + // |--------------|---------|----------|---------|----------| + // | 8. Bob withdraws 2928 assets (1608 shares) | + // |--------------|---------|----------|---------|----------| + // | 6392 | 2000 | 3643 | 4392 | 8000 | + // |--------------|---------|----------|---------|----------| + // | 9. Alice withdraws 3643 assets (2000 shares) | + // | NOTE: Bob's assets have been rounded back up | + // |--------------|---------|----------|---------|----------| + // | 4392 | 0 | 0 | 4392 | 8001 | + // |--------------|---------|----------|---------|----------| + // | 10. Bob redeem 4392 shares (8001 tokens) | + // |--------------|---------|----------|---------|----------| + // | 0 | 0 | 0 | 0 | 0 | + // |______________|_________|__________|_________|__________| + + address alice = address(0xABCD); + address bob = address(0xDCBA); + + uint256 mutationUnderlyingAmount = 3000; + + underlying.mint(alice, 4000); + + hevm.prank(alice); + underlying.approve(address(vault), 4000); + + assertEq(underlying.allowance(alice, address(vault)), 4000); + + underlying.mint(bob, 7001); + + hevm.prank(bob); + underlying.approve(address(vault), 7001); + + assertEq(underlying.allowance(bob, address(vault)), 7001); + + // 1. Alice mints 2000 shares (costs 2000 tokens) + hevm.prank(alice); + uint256 aliceUnderlyingAmount = vault.mint(2000, alice); + + uint256 aliceShareAmount = vault.previewDeposit(aliceUnderlyingAmount); + assertEq(vault.afterDepositHookCalledCounter(), 1); + + // Expect to have received the requested mint amount. + assertEq(aliceShareAmount, 2000); + assertEq(vault.balanceOf(alice), aliceShareAmount); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), aliceUnderlyingAmount); + assertEq(vault.convertToShares(aliceUnderlyingAmount), vault.balanceOf(alice)); + + // Expect a 1:1 ratio before mutation. + assertEq(aliceUnderlyingAmount, 2000); + + // Sanity check. + assertEq(vault.totalSupply(), aliceShareAmount); + assertEq(vault.totalAssets(), aliceUnderlyingAmount); + + // 2. Bob deposits 4000 tokens (mints 4000 shares) + hevm.prank(bob); + uint256 bobShareAmount = vault.deposit(4000, bob); + uint256 bobUnderlyingAmount = vault.previewWithdraw(bobShareAmount); + assertEq(vault.afterDepositHookCalledCounter(), 2); + + // Expect to have received the requested underlying amount. + assertEq(bobUnderlyingAmount, 4000); + assertEq(vault.balanceOf(bob), bobShareAmount); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), bobUnderlyingAmount); + assertEq(vault.convertToShares(bobUnderlyingAmount), vault.balanceOf(bob)); + + // Expect a 1:1 ratio before mutation. + assertEq(bobShareAmount, bobUnderlyingAmount); + + // Sanity check. + uint256 preMutationShareBal = aliceShareAmount + bobShareAmount; + uint256 preMutationBal = aliceUnderlyingAmount + bobUnderlyingAmount; + assertEq(vault.totalSupply(), preMutationShareBal); + assertEq(vault.totalAssets(), preMutationBal); + assertEq(vault.totalSupply(), 6000); + assertEq(vault.totalAssets(), 6000); + + // 3. Vault mutates by +3000 tokens... | + // (simulated yield returned from strategy)... + // The Vault now contains more tokens than deposited which causes the exchange rate to change. + // Alice share is 33.33% of the Vault, Bob 66.66% of the Vault. + // Alice's share count stays the same but the underlying amount changes from 2000 to 3000. + // Bob's share count stays the same but the underlying amount changes from 4000 to 6000. + underlying.mint(address(vault), mutationUnderlyingAmount); + assertEq(vault.totalSupply(), preMutationShareBal); + assertEq(vault.totalAssets(), preMutationBal + mutationUnderlyingAmount); + assertEq(vault.balanceOf(alice), aliceShareAmount); + assertEq( + vault.convertToAssets(vault.balanceOf(alice)), + aliceUnderlyingAmount + (mutationUnderlyingAmount / 3) * 1 + ); + assertEq(vault.balanceOf(bob), bobShareAmount); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), bobUnderlyingAmount + (mutationUnderlyingAmount / 3) * 2); + + // 4. Alice deposits 2000 tokens (mints 1333 shares) + hevm.prank(alice); + vault.deposit(2000, alice); + + assertEq(vault.totalSupply(), 7333); + assertEq(vault.balanceOf(alice), 3333); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 4999); + assertEq(vault.balanceOf(bob), 4000); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 6000); + + // 5. Bob mints 2000 shares (costs 3001 assets) + // NOTE: Bob's assets spent got rounded up + // NOTE: Alices's vault assets got rounded up + hevm.prank(bob); + vault.mint(2000, bob); + + assertEq(vault.totalSupply(), 9333); + assertEq(vault.balanceOf(alice), 3333); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 5000); + assertEq(vault.balanceOf(bob), 6000); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 9000); + + // Sanity checks: + // Alice and bob should have spent all their tokens now + assertEq(underlying.balanceOf(alice), 0); + assertEq(underlying.balanceOf(bob), 0); + // Assets in vault: 4k (alice) + 7k (bob) + 3k (yield) + 1 (round up) + assertEq(vault.totalAssets(), 14001); + + // 6. Vault mutates by +3000 tokens + // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000. + underlying.mint(address(vault), mutationUnderlyingAmount); + assertEq(vault.totalAssets(), 17001); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 6071); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 10929); + + // 7. Alice redeem 1333 shares (2428 assets) + hevm.prank(alice); + vault.redeem(1333, alice, alice); + + assertEq(underlying.balanceOf(alice), 2428); + assertEq(vault.totalSupply(), 8000); + assertEq(vault.totalAssets(), 14573); + assertEq(vault.balanceOf(alice), 2000); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 3643); + assertEq(vault.balanceOf(bob), 6000); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 10929); + + // 8. Bob withdraws 2929 assets (1608 shares) + hevm.prank(bob); + vault.withdraw(2929, bob, bob); + + assertEq(underlying.balanceOf(bob), 2929); + assertEq(vault.totalSupply(), 6392); + assertEq(vault.totalAssets(), 11644); + assertEq(vault.balanceOf(alice), 2000); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 3643); + assertEq(vault.balanceOf(bob), 4392); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 8000); + + // 9. Alice withdraws 3643 assets (2000 shares) + // NOTE: Bob's assets have been rounded back up + hevm.prank(alice); + vault.withdraw(3643, alice, alice); + + assertEq(underlying.balanceOf(alice), 6071); + assertEq(vault.totalSupply(), 4392); + assertEq(vault.totalAssets(), 8001); + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 0); + assertEq(vault.balanceOf(bob), 4392); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 8001); + + // 10. Bob redeem 4392 shares (8001 tokens) + hevm.prank(bob); + vault.redeem(4392, bob, bob); + assertEq(underlying.balanceOf(bob), 10930); + assertEq(vault.totalSupply(), 0); + assertEq(vault.totalAssets(), 0); + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 0); + assertEq(vault.balanceOf(bob), 0); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 0); + + // Sanity check + assertEq(underlying.balanceOf(address(vault)), 0); + } + + function testFailDepositWithNotEnoughApproval() public { + underlying.mint(address(this), 0.5e18); + underlying.approve(address(vault), 0.5e18); + assertEq(underlying.allowance(address(this), address(vault)), 0.5e18); + + vault.deposit(1e18, address(this)); + } + + function testFailWithdrawWithNotEnoughUnderlyingAmount() public { + underlying.mint(address(this), 0.5e18); + underlying.approve(address(vault), 0.5e18); + + vault.deposit(0.5e18, address(this)); + + vault.withdraw(1e18, address(this), address(this)); + } + + function testFailRedeemWithNotEnoughShareAmount() public { + underlying.mint(address(this), 0.5e18); + underlying.approve(address(vault), 0.5e18); + + vault.deposit(0.5e18, address(this)); + + vault.redeem(1e18, address(this), address(this)); + } + + function testFailWithdrawWithNoUnderlyingAmount() public { + vault.withdraw(1e18, address(this), address(this)); + } + + function testFailRedeemWithNoShareAmount() public { + vault.redeem(1e18, address(this), address(this)); + } + + function testFailDepositWithNoApproval() public { + vault.deposit(1e18, address(this)); + } + + function testFailMintWithNoApproval() public { + vault.mint(1e18, address(this)); + } + + function testFailDepositZero() public { + vault.deposit(0, address(this)); + } + + function testMintZero() public { + vault.mint(0, address(this)); + + assertEq(vault.balanceOf(address(this)), 0); + assertEq(vault.convertToAssets(vault.balanceOf(address(this))), 0); + assertEq(vault.totalSupply(), 0); + assertEq(vault.totalAssets(), 0); + } + + function testFailRedeemZero() public { + vault.redeem(0, address(this), address(this)); + } + + function testWithdrawZero() public { + vault.withdraw(0, address(this), address(this)); + + assertEq(vault.balanceOf(address(this)), 0); + assertEq(vault.convertToAssets(vault.balanceOf(address(this))), 0); + assertEq(vault.totalSupply(), 0); + assertEq(vault.totalAssets(), 0); + } + + function testVaultInteractionsForSomeoneElse() public { + // init 2 users with a 1e18 balance + address alice = address(0xABCD); + address bob = address(0xDCBA); + underlying.mint(alice, 1e18); + underlying.mint(bob, 1e18); + + hevm.prank(alice); + underlying.approve(address(vault), 1e18); + + hevm.prank(bob); + underlying.approve(address(vault), 1e18); + + // alice deposits 1e18 for bob + hevm.prank(alice); + vault.deposit(1e18, bob); + + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.balanceOf(bob), 1e18); + assertEq(underlying.balanceOf(alice), 0); + + // bob mint 1e18 for alice + hevm.prank(bob); + vault.mint(1e18, alice); + assertEq(vault.balanceOf(alice), 1e18); + assertEq(vault.balanceOf(bob), 1e18); + assertEq(underlying.balanceOf(bob), 0); + + // alice redeem 1e18 for bob + hevm.prank(alice); + vault.redeem(1e18, bob, alice); + + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.balanceOf(bob), 1e18); + assertEq(underlying.balanceOf(bob), 1e18); + + // bob withdraw 1e18 for alice + hevm.prank(bob); + vault.withdraw(1e18, alice, bob); + + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.balanceOf(bob), 0); + assertEq(underlying.balanceOf(alice), 1e18); + } +} diff --git a/lib/solmate/src/test/ERC6909.t.sol b/lib/solmate/src/test/ERC6909.t.sol new file mode 100644 index 0000000..309d164 --- /dev/null +++ b/lib/solmate/src/test/ERC6909.t.sol @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {MockERC6909} from "./utils/mocks/MockERC6909.sol"; + +contract ERC6909Test is DSTestPlus { + MockERC6909 token; + + mapping(address => mapping(uint256 => uint256)) public userMintAmounts; + mapping(address => mapping(uint256 => uint256)) public userTransferOrBurnAmounts; + + function setUp() public { + token = new MockERC6909(); + } + + function testMint() public { + token.mint(address(0xBEEF), 1337, 100); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 100); + assertEq(token.totalSupply(1337), 100); + } + + function testBurn() public { + token.mint(address(0xBEEF), 1337, 100); + token.burn(address(0xBEEF), 1337, 70); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 30); + assertEq(token.totalSupply(1337), 30); + } + + function testSetOperator() public { + token.setOperator(address(0xBEEF), true); + + assertTrue(token.isOperator(address(this), address(0xBEEF))); + } + + function testApprove() public { + token.approve(address(0xBEEF), 1337, 100); + + assertEq(token.allowance(address(this), address(0xBEEF), 1337), 100); + } + + function testTransfer() public { + address sender = address(0xABCD); + + token.mint(sender, 1337, 100); + + hevm.prank(sender); + token.transfer(address(0xBEEF), 1337, 70); + + assertEq(token.balanceOf(sender, 1337), 30); + assertEq(token.balanceOf(address(0xBEEF), 1337), 70); + } + + function testTransferFromWithApproval() public { + address sender = address(0xABCD); + address receiver = address(0xBEEF); + + token.mint(sender, 1337, 100); + + hevm.prank(sender); + token.approve(address(this), 1337, 100); + + token.transferFrom(sender, receiver, 1337, 70); + + assertEq(token.allowance(sender, address(this), 1337), 30); + assertEq(token.balanceOf(sender, 1337), 30); + assertEq(token.balanceOf(receiver, 1337), 70); + } + + function testTransferFromWithInfiniteApproval() public { + address sender = address(0xABCD); + address receiver = address(0xBEEF); + + token.mint(sender, 1337, 100); + + hevm.prank(sender); + token.approve(address(this), 1337, type(uint256).max); + + token.transferFrom(sender, receiver, 1337, 70); + + assertEq(token.allowance(sender, address(this), 1337), type(uint256).max); + assertEq(token.balanceOf(sender, 1337), 30); + assertEq(token.balanceOf(receiver, 1337), 70); + } + + function testTransferFromAsOperator() public { + address sender = address(0xABCD); + address receiver = address(0xBEEF); + + token.mint(sender, 1337, 100); + + hevm.prank(sender); + token.setOperator(address(this), true); + + token.transferFrom(sender, receiver, 1337, 70); + + assertEq(token.balanceOf(sender, 1337), 30); + assertEq(token.balanceOf(receiver, 1337), 70); + } + + function testFailMint() public { + token.mint(address(0xDEAD), 1337, type(uint256).max); + token.mint(address(0xBEEF), 1337, 1); + } + + function testFailTransfer() public { + address sender = address(0xABCD); + address receiver = address(0xBEEF); + + hevm.prank(sender); + token.transferFrom(sender, receiver, 1337, 1); + } + + function testFailTransferFrom() public { + address sender = address(0xABCD); + address receiver = address(0xBEEF); + + hevm.prank(sender); + token.transferFrom(sender, receiver, 1337, 1); + } + + function testFailTransferFromNotAuthorized() public { + address sender = address(0xABCD); + address receiver = address(0xBEEF); + + token.mint(sender, 1337, 100); + + token.transferFrom(sender, receiver, 1337, 100); + } + + function testMint( + address receiver, + uint256 id, + uint256 amount + ) public { + token.mint(receiver, id, amount); + + assertEq(token.balanceOf(receiver, id), amount); + assertEq(token.totalSupply(id), amount); + } + + function testBurn( + address sender, + uint256 id, + uint256 amount + ) public { + token.mint(sender, id, amount); + token.burn(sender, id, amount); + + assertEq(token.balanceOf(sender, id), 0); + assertEq(token.totalSupply(id), 0); + } + + function testSetOperator(address operator, bool approved) public { + token.setOperator(operator, approved); + + assertBoolEq(token.isOperator(address(this), operator), approved); + } + + function testApprove( + address spender, + uint256 id, + uint256 amount + ) public { + token.approve(spender, id, amount); + + assertEq(token.allowance(address(this), spender, id), amount); + } + + function testTransfer( + address sender, + address receiver, + uint256 id, + uint256 mintAmount, + uint256 transferAmount + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(sender, id, mintAmount); + + hevm.prank(sender); + token.transfer(receiver, id, transferAmount); + + if (sender == receiver) { + assertEq(token.balanceOf(sender, id), mintAmount); + } else { + assertEq(token.balanceOf(sender, id), mintAmount - transferAmount); + assertEq(token.balanceOf(receiver, id), transferAmount); + } + } + + function testTransferFromWithApproval( + address sender, + address receiver, + uint256 id, + uint256 mintAmount, + uint256 transferAmount + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(sender, id, mintAmount); + + hevm.prank(sender); + token.approve(address(this), id, mintAmount); + + token.transferFrom(sender, receiver, id, transferAmount); + + if (mintAmount == type(uint256).max) { + assertEq(token.allowance(sender, address(this), id), type(uint256).max); + } else { + assertEq(token.allowance(sender, address(this), id), mintAmount - transferAmount); + } + + if (sender == receiver) { + assertEq(token.balanceOf(sender, id), mintAmount); + } else { + assertEq(token.balanceOf(sender, id), mintAmount - transferAmount); + assertEq(token.balanceOf(receiver, id), transferAmount); + } + } + + function testTransferFromWithInfiniteApproval( + address sender, + address receiver, + uint256 id, + uint256 mintAmount, + uint256 transferAmount + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(sender, id, mintAmount); + + hevm.prank(sender); + token.approve(address(this), id, type(uint256).max); + + token.transferFrom(sender, receiver, id, transferAmount); + + assertEq(token.allowance(sender, address(this), id), type(uint256).max); + + if (sender == receiver) { + assertEq(token.balanceOf(sender, id), mintAmount); + } else { + assertEq(token.balanceOf(sender, id), mintAmount - transferAmount); + assertEq(token.balanceOf(receiver, id), transferAmount); + } + } + + function testTransferFromAsOperator( + address sender, + address receiver, + uint256 id, + uint256 mintAmount, + uint256 transferAmount + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(sender, id, mintAmount); + + hevm.prank(sender); + token.setOperator(address(this), true); + + token.transferFrom(sender, receiver, id, transferAmount); + + if (sender == receiver) { + assertEq(token.balanceOf(sender, id), mintAmount); + } else { + assertEq(token.balanceOf(sender, id), mintAmount - transferAmount); + assertEq(token.balanceOf(receiver, id), transferAmount); + } + } + + function testFailTransfer( + address sender, + address receiver, + uint256 id, + uint256 amount + ) public { + amount = bound(amount, 1, type(uint256).max); + + hevm.prank(sender); + token.transfer(receiver, id, amount); + } + + function testFailTransferFrom( + address sender, + address receiver, + uint256 id, + uint256 amount + ) public { + amount = bound(amount, 1, type(uint256).max); + + hevm.prank(sender); + token.transferFrom(sender, receiver, id, amount); + } + + function testFailTransferFromNotAuthorized( + address sender, + address receiver, + uint256 id, + uint256 amount + ) public { + amount = bound(amount, 1, type(uint256).max); + + token.mint(sender, id, amount); + + token.transferFrom(sender, receiver, id, amount); + } +} diff --git a/lib/solmate/src/test/ERC721.t.sol b/lib/solmate/src/test/ERC721.t.sol new file mode 100644 index 0000000..81de0ff --- /dev/null +++ b/lib/solmate/src/test/ERC721.t.sol @@ -0,0 +1,727 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {MockERC721} from "./utils/mocks/MockERC721.sol"; + +import {ERC721TokenReceiver} from "../tokens/ERC721.sol"; + +contract ERC721Recipient is ERC721TokenReceiver { + address public operator; + address public from; + uint256 public id; + bytes public data; + + function onERC721Received( + address _operator, + address _from, + uint256 _id, + bytes calldata _data + ) public virtual override returns (bytes4) { + operator = _operator; + from = _from; + id = _id; + data = _data; + + return ERC721TokenReceiver.onERC721Received.selector; + } +} + +contract RevertingERC721Recipient is ERC721TokenReceiver { + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) public virtual override returns (bytes4) { + revert(string(abi.encodePacked(ERC721TokenReceiver.onERC721Received.selector))); + } +} + +contract WrongReturnDataERC721Recipient is ERC721TokenReceiver { + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) public virtual override returns (bytes4) { + return 0xCAFEBEEF; + } +} + +contract NonERC721Recipient {} + +contract ERC721Test is DSTestPlus { + MockERC721 token; + + function setUp() public { + token = new MockERC721("Token", "TKN"); + } + + function invariantMetadata() public { + assertEq(token.name(), "Token"); + assertEq(token.symbol(), "TKN"); + } + + function testMint() public { + token.mint(address(0xBEEF), 1337); + + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.ownerOf(1337), address(0xBEEF)); + } + + function testBurn() public { + token.mint(address(0xBEEF), 1337); + token.burn(1337); + + assertEq(token.balanceOf(address(0xBEEF)), 0); + + hevm.expectRevert("NOT_MINTED"); + token.ownerOf(1337); + } + + function testApprove() public { + token.mint(address(this), 1337); + + token.approve(address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0xBEEF)); + } + + function testApproveBurn() public { + token.mint(address(this), 1337); + + token.approve(address(0xBEEF), 1337); + + token.burn(1337); + + assertEq(token.balanceOf(address(this)), 0); + assertEq(token.getApproved(1337), address(0)); + + hevm.expectRevert("NOT_MINTED"); + token.ownerOf(1337); + } + + function testApproveAll() public { + token.setApprovalForAll(address(0xBEEF), true); + + assertTrue(token.isApprovedForAll(address(this), address(0xBEEF))); + } + + function testTransferFrom() public { + address from = address(0xABCD); + + token.mint(from, 1337); + + hevm.prank(from); + token.approve(address(this), 1337); + + token.transferFrom(from, address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(0xBEEF)); + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.balanceOf(from), 0); + } + + function testTransferFromSelf() public { + token.mint(address(this), 1337); + + token.transferFrom(address(this), address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(0xBEEF)); + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.balanceOf(address(this)), 0); + } + + function testTransferFromApproveAll() public { + address from = address(0xABCD); + + token.mint(from, 1337); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.transferFrom(from, address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(0xBEEF)); + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.balanceOf(from), 0); + } + + function testSafeTransferFromToEOA() public { + address from = address(0xABCD); + + token.mint(from, 1337); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(0xBEEF)); + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.balanceOf(from), 0); + } + + function testSafeTransferFromToERC721Recipient() public { + address from = address(0xABCD); + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, 1337); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(recipient), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(recipient)); + assertEq(token.balanceOf(address(recipient)), 1); + assertEq(token.balanceOf(from), 0); + + assertEq(recipient.operator(), address(this)); + assertEq(recipient.from(), from); + assertEq(recipient.id(), 1337); + assertBytesEq(recipient.data(), ""); + } + + function testSafeTransferFromToERC721RecipientWithData() public { + address from = address(0xABCD); + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, 1337); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(recipient), 1337, "testing 123"); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(recipient)); + assertEq(token.balanceOf(address(recipient)), 1); + assertEq(token.balanceOf(from), 0); + + assertEq(recipient.operator(), address(this)); + assertEq(recipient.from(), from); + assertEq(recipient.id(), 1337); + assertBytesEq(recipient.data(), "testing 123"); + } + + function testSafeMintToEOA() public { + token.safeMint(address(0xBEEF), 1337); + + assertEq(token.ownerOf(1337), address(address(0xBEEF))); + assertEq(token.balanceOf(address(address(0xBEEF))), 1); + } + + function testSafeMintToERC721Recipient() public { + ERC721Recipient to = new ERC721Recipient(); + + token.safeMint(address(to), 1337); + + assertEq(token.ownerOf(1337), address(to)); + assertEq(token.balanceOf(address(to)), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), 1337); + assertBytesEq(to.data(), ""); + } + + function testSafeMintToERC721RecipientWithData() public { + ERC721Recipient to = new ERC721Recipient(); + + token.safeMint(address(to), 1337, "testing 123"); + + assertEq(token.ownerOf(1337), address(to)); + assertEq(token.balanceOf(address(to)), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), 1337); + assertBytesEq(to.data(), "testing 123"); + } + + function testFailMintToZero() public { + token.mint(address(0), 1337); + } + + function testFailDoubleMint() public { + token.mint(address(0xBEEF), 1337); + token.mint(address(0xBEEF), 1337); + } + + function testFailBurnUnMinted() public { + token.burn(1337); + } + + function testFailDoubleBurn() public { + token.mint(address(0xBEEF), 1337); + + token.burn(1337); + token.burn(1337); + } + + function testFailApproveUnMinted() public { + token.approve(address(0xBEEF), 1337); + } + + function testFailApproveUnAuthorized() public { + token.mint(address(0xCAFE), 1337); + + token.approve(address(0xBEEF), 1337); + } + + function testFailTransferFromUnOwned() public { + token.transferFrom(address(0xFEED), address(0xBEEF), 1337); + } + + function testFailTransferFromWrongFrom() public { + token.mint(address(0xCAFE), 1337); + + token.transferFrom(address(0xFEED), address(0xBEEF), 1337); + } + + function testFailTransferFromToZero() public { + token.mint(address(this), 1337); + + token.transferFrom(address(this), address(0), 1337); + } + + function testFailTransferFromNotOwner() public { + token.mint(address(0xFEED), 1337); + + token.transferFrom(address(0xFEED), address(0xBEEF), 1337); + } + + function testFailSafeTransferFromToNonERC721Recipient() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new NonERC721Recipient()), 1337); + } + + function testFailSafeTransferFromToNonERC721RecipientWithData() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new NonERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeTransferFromToRevertingERC721Recipient() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new RevertingERC721Recipient()), 1337); + } + + function testFailSafeTransferFromToRevertingERC721RecipientWithData() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new RevertingERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeTransferFromToERC721RecipientWithWrongReturnData() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new WrongReturnDataERC721Recipient()), 1337); + } + + function testFailSafeTransferFromToERC721RecipientWithWrongReturnDataWithData() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new WrongReturnDataERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeMintToNonERC721Recipient() public { + token.safeMint(address(new NonERC721Recipient()), 1337); + } + + function testFailSafeMintToNonERC721RecipientWithData() public { + token.safeMint(address(new NonERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeMintToRevertingERC721Recipient() public { + token.safeMint(address(new RevertingERC721Recipient()), 1337); + } + + function testFailSafeMintToRevertingERC721RecipientWithData() public { + token.safeMint(address(new RevertingERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeMintToERC721RecipientWithWrongReturnData() public { + token.safeMint(address(new WrongReturnDataERC721Recipient()), 1337); + } + + function testFailSafeMintToERC721RecipientWithWrongReturnDataWithData() public { + token.safeMint(address(new WrongReturnDataERC721Recipient()), 1337, "testing 123"); + } + + function testFailBalanceOfZeroAddress() public view { + token.balanceOf(address(0)); + } + + function testFailOwnerOfUnminted() public view { + token.ownerOf(1337); + } + + function testMetadata(string memory name, string memory symbol) public { + MockERC721 tkn = new MockERC721(name, symbol); + + assertEq(tkn.name(), name); + assertEq(tkn.symbol(), symbol); + } + + function testMint(address to, uint256 id) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(to, id); + + assertEq(token.balanceOf(to), 1); + assertEq(token.ownerOf(id), to); + } + + function testBurn(address to, uint256 id) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(to, id); + token.burn(id); + + assertEq(token.balanceOf(to), 0); + + hevm.expectRevert("NOT_MINTED"); + token.ownerOf(id); + } + + function testApprove(address to, uint256 id) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(address(this), id); + + token.approve(to, id); + + assertEq(token.getApproved(id), to); + } + + function testApproveBurn(address to, uint256 id) public { + token.mint(address(this), id); + + token.approve(address(to), id); + + token.burn(id); + + assertEq(token.balanceOf(address(this)), 0); + assertEq(token.getApproved(id), address(0)); + + hevm.expectRevert("NOT_MINTED"); + token.ownerOf(id); + } + + function testApproveAll(address to, bool approved) public { + token.setApprovalForAll(to, approved); + + assertBoolEq(token.isApprovedForAll(address(this), to), approved); + } + + function testTransferFrom(uint256 id, address to) public { + address from = address(0xABCD); + + if (to == address(0) || to == from) to = address(0xBEEF); + + token.mint(from, id); + + hevm.prank(from); + token.approve(address(this), id); + + token.transferFrom(from, to, id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), to); + assertEq(token.balanceOf(to), 1); + assertEq(token.balanceOf(from), 0); + } + + function testTransferFromSelf(uint256 id, address to) public { + if (to == address(0) || to == address(this)) to = address(0xBEEF); + + token.mint(address(this), id); + + token.transferFrom(address(this), to, id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), to); + assertEq(token.balanceOf(to), 1); + assertEq(token.balanceOf(address(this)), 0); + } + + function testTransferFromApproveAll(uint256 id, address to) public { + address from = address(0xABCD); + + if (to == address(0) || to == from) to = address(0xBEEF); + + token.mint(from, id); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.transferFrom(from, to, id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), to); + assertEq(token.balanceOf(to), 1); + assertEq(token.balanceOf(from), 0); + } + + function testSafeTransferFromToEOA(uint256 id, address to) public { + address from = address(0xABCD); + + if (to == address(0) || to == from) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + token.mint(from, id); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, to, id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), to); + assertEq(token.balanceOf(to), 1); + assertEq(token.balanceOf(from), 0); + } + + function testSafeTransferFromToERC721Recipient(uint256 id) public { + address from = address(0xABCD); + + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, id); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(recipient), id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), address(recipient)); + assertEq(token.balanceOf(address(recipient)), 1); + assertEq(token.balanceOf(from), 0); + + assertEq(recipient.operator(), address(this)); + assertEq(recipient.from(), from); + assertEq(recipient.id(), id); + assertBytesEq(recipient.data(), ""); + } + + function testSafeTransferFromToERC721RecipientWithData(uint256 id, bytes calldata data) public { + address from = address(0xABCD); + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, id); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(recipient), id, data); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), address(recipient)); + assertEq(token.balanceOf(address(recipient)), 1); + assertEq(token.balanceOf(from), 0); + + assertEq(recipient.operator(), address(this)); + assertEq(recipient.from(), from); + assertEq(recipient.id(), id); + assertBytesEq(recipient.data(), data); + } + + function testSafeMintToEOA(uint256 id, address to) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + token.safeMint(to, id); + + assertEq(token.ownerOf(id), address(to)); + assertEq(token.balanceOf(address(to)), 1); + } + + function testSafeMintToERC721Recipient(uint256 id) public { + ERC721Recipient to = new ERC721Recipient(); + + token.safeMint(address(to), id); + + assertEq(token.ownerOf(id), address(to)); + assertEq(token.balanceOf(address(to)), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), id); + assertBytesEq(to.data(), ""); + } + + function testSafeMintToERC721RecipientWithData(uint256 id, bytes calldata data) public { + ERC721Recipient to = new ERC721Recipient(); + + token.safeMint(address(to), id, data); + + assertEq(token.ownerOf(id), address(to)); + assertEq(token.balanceOf(address(to)), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), id); + assertBytesEq(to.data(), data); + } + + function testFailMintToZero(uint256 id) public { + token.mint(address(0), id); + } + + function testFailDoubleMint(uint256 id, address to) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(to, id); + token.mint(to, id); + } + + function testFailBurnUnMinted(uint256 id) public { + token.burn(id); + } + + function testFailDoubleBurn(uint256 id, address to) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(to, id); + + token.burn(id); + token.burn(id); + } + + function testFailApproveUnMinted(uint256 id, address to) public { + token.approve(to, id); + } + + function testFailApproveUnAuthorized( + address owner, + uint256 id, + address to + ) public { + if (owner == address(0) || owner == address(this)) owner = address(0xBEEF); + + token.mint(owner, id); + + token.approve(to, id); + } + + function testFailTransferFromUnOwned( + address from, + address to, + uint256 id + ) public { + token.transferFrom(from, to, id); + } + + function testFailTransferFromWrongFrom( + address owner, + address from, + address to, + uint256 id + ) public { + if (owner == address(0)) to = address(0xBEEF); + if (from == owner) revert(); + + token.mint(owner, id); + + token.transferFrom(from, to, id); + } + + function testFailTransferFromToZero(uint256 id) public { + token.mint(address(this), id); + + token.transferFrom(address(this), address(0), id); + } + + function testFailTransferFromNotOwner( + address from, + address to, + uint256 id + ) public { + if (from == address(this)) from = address(0xBEEF); + + token.mint(from, id); + + token.transferFrom(from, to, id); + } + + function testFailSafeTransferFromToNonERC721Recipient(uint256 id) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new NonERC721Recipient()), id); + } + + function testFailSafeTransferFromToNonERC721RecipientWithData(uint256 id, bytes calldata data) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new NonERC721Recipient()), id, data); + } + + function testFailSafeTransferFromToRevertingERC721Recipient(uint256 id) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new RevertingERC721Recipient()), id); + } + + function testFailSafeTransferFromToRevertingERC721RecipientWithData(uint256 id, bytes calldata data) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new RevertingERC721Recipient()), id, data); + } + + function testFailSafeTransferFromToERC721RecipientWithWrongReturnData(uint256 id) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new WrongReturnDataERC721Recipient()), id); + } + + function testFailSafeTransferFromToERC721RecipientWithWrongReturnDataWithData(uint256 id, bytes calldata data) + public + { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new WrongReturnDataERC721Recipient()), id, data); + } + + function testFailSafeMintToNonERC721Recipient(uint256 id) public { + token.safeMint(address(new NonERC721Recipient()), id); + } + + function testFailSafeMintToNonERC721RecipientWithData(uint256 id, bytes calldata data) public { + token.safeMint(address(new NonERC721Recipient()), id, data); + } + + function testFailSafeMintToRevertingERC721Recipient(uint256 id) public { + token.safeMint(address(new RevertingERC721Recipient()), id); + } + + function testFailSafeMintToRevertingERC721RecipientWithData(uint256 id, bytes calldata data) public { + token.safeMint(address(new RevertingERC721Recipient()), id, data); + } + + function testFailSafeMintToERC721RecipientWithWrongReturnData(uint256 id) public { + token.safeMint(address(new WrongReturnDataERC721Recipient()), id); + } + + function testFailSafeMintToERC721RecipientWithWrongReturnDataWithData(uint256 id, bytes calldata data) public { + token.safeMint(address(new WrongReturnDataERC721Recipient()), id, data); + } + + function testFailOwnerOfUnminted(uint256 id) public view { + token.ownerOf(id); + } +} diff --git a/lib/solmate/src/test/FixedPointMathLib.t.sol b/lib/solmate/src/test/FixedPointMathLib.t.sol new file mode 100644 index 0000000..789f957 --- /dev/null +++ b/lib/solmate/src/test/FixedPointMathLib.t.sol @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol"; + +contract FixedPointMathLibTest is DSTestPlus { + function testMulWadDown() public { + assertEq(FixedPointMathLib.mulWadDown(2.5e18, 0.5e18), 1.25e18); + assertEq(FixedPointMathLib.mulWadDown(3e18, 1e18), 3e18); + assertEq(FixedPointMathLib.mulWadDown(369, 271), 0); + } + + function testMulWadDownEdgeCases() public { + assertEq(FixedPointMathLib.mulWadDown(0, 1e18), 0); + assertEq(FixedPointMathLib.mulWadDown(1e18, 0), 0); + assertEq(FixedPointMathLib.mulWadDown(0, 0), 0); + } + + function testMulWadUp() public { + assertEq(FixedPointMathLib.mulWadUp(2.5e18, 0.5e18), 1.25e18); + assertEq(FixedPointMathLib.mulWadUp(3e18, 1e18), 3e18); + assertEq(FixedPointMathLib.mulWadUp(369, 271), 1); + } + + function testMulWadUpEdgeCases() public { + assertEq(FixedPointMathLib.mulWadUp(0, 1e18), 0); + assertEq(FixedPointMathLib.mulWadUp(1e18, 0), 0); + assertEq(FixedPointMathLib.mulWadUp(0, 0), 0); + } + + function testDivWadDown() public { + assertEq(FixedPointMathLib.divWadDown(1.25e18, 0.5e18), 2.5e18); + assertEq(FixedPointMathLib.divWadDown(3e18, 1e18), 3e18); + assertEq(FixedPointMathLib.divWadDown(2, 100000000000000e18), 0); + } + + function testDivWadDownEdgeCases() public { + assertEq(FixedPointMathLib.divWadDown(0, 1e18), 0); + } + + function testFailDivWadDownZeroDenominator() public pure { + FixedPointMathLib.divWadDown(1e18, 0); + } + + function testDivWadUp() public { + assertEq(FixedPointMathLib.divWadUp(1.25e18, 0.5e18), 2.5e18); + assertEq(FixedPointMathLib.divWadUp(3e18, 1e18), 3e18); + assertEq(FixedPointMathLib.divWadUp(2, 100000000000000e18), 1); + } + + function testDivWadUpEdgeCases() public { + assertEq(FixedPointMathLib.divWadUp(0, 1e18), 0); + } + + function testFailDivWadUpZeroDenominator() public pure { + FixedPointMathLib.divWadUp(1e18, 0); + } + + function testMulDivDown() public { + assertEq(FixedPointMathLib.mulDivDown(2.5e27, 0.5e27, 1e27), 1.25e27); + assertEq(FixedPointMathLib.mulDivDown(2.5e18, 0.5e18, 1e18), 1.25e18); + assertEq(FixedPointMathLib.mulDivDown(2.5e8, 0.5e8, 1e8), 1.25e8); + assertEq(FixedPointMathLib.mulDivDown(369, 271, 1e2), 999); + + assertEq(FixedPointMathLib.mulDivDown(1e27, 1e27, 2e27), 0.5e27); + assertEq(FixedPointMathLib.mulDivDown(1e18, 1e18, 2e18), 0.5e18); + assertEq(FixedPointMathLib.mulDivDown(1e8, 1e8, 2e8), 0.5e8); + + assertEq(FixedPointMathLib.mulDivDown(2e27, 3e27, 2e27), 3e27); + assertEq(FixedPointMathLib.mulDivDown(3e18, 2e18, 3e18), 2e18); + assertEq(FixedPointMathLib.mulDivDown(2e8, 3e8, 2e8), 3e8); + } + + function testMulDivDownEdgeCases() public { + assertEq(FixedPointMathLib.mulDivDown(0, 1e18, 1e18), 0); + assertEq(FixedPointMathLib.mulDivDown(1e18, 0, 1e18), 0); + assertEq(FixedPointMathLib.mulDivDown(0, 0, 1e18), 0); + } + + function testFailMulDivDownZeroDenominator() public pure { + FixedPointMathLib.mulDivDown(1e18, 1e18, 0); + } + + function testMulDivUp() public { + assertEq(FixedPointMathLib.mulDivUp(2.5e27, 0.5e27, 1e27), 1.25e27); + assertEq(FixedPointMathLib.mulDivUp(2.5e18, 0.5e18, 1e18), 1.25e18); + assertEq(FixedPointMathLib.mulDivUp(2.5e8, 0.5e8, 1e8), 1.25e8); + assertEq(FixedPointMathLib.mulDivUp(369, 271, 1e2), 1000); + + assertEq(FixedPointMathLib.mulDivUp(1e27, 1e27, 2e27), 0.5e27); + assertEq(FixedPointMathLib.mulDivUp(1e18, 1e18, 2e18), 0.5e18); + assertEq(FixedPointMathLib.mulDivUp(1e8, 1e8, 2e8), 0.5e8); + + assertEq(FixedPointMathLib.mulDivUp(2e27, 3e27, 2e27), 3e27); + assertEq(FixedPointMathLib.mulDivUp(3e18, 2e18, 3e18), 2e18); + assertEq(FixedPointMathLib.mulDivUp(2e8, 3e8, 2e8), 3e8); + } + + function testMulDivUpEdgeCases() public { + assertEq(FixedPointMathLib.mulDivUp(0, 1e18, 1e18), 0); + assertEq(FixedPointMathLib.mulDivUp(1e18, 0, 1e18), 0); + assertEq(FixedPointMathLib.mulDivUp(0, 0, 1e18), 0); + } + + function testFailMulDivUpZeroDenominator() public pure { + FixedPointMathLib.mulDivUp(1e18, 1e18, 0); + } + + function testRPow() public { + assertEq(FixedPointMathLib.rpow(2e27, 2, 1e27), 4e27); + assertEq(FixedPointMathLib.rpow(2e18, 2, 1e18), 4e18); + assertEq(FixedPointMathLib.rpow(2e8, 2, 1e8), 4e8); + assertEq(FixedPointMathLib.rpow(8, 3, 1), 512); + } + + function testSqrt() public { + assertEq(FixedPointMathLib.sqrt(0), 0); + assertEq(FixedPointMathLib.sqrt(1), 1); + assertEq(FixedPointMathLib.sqrt(2704), 52); + assertEq(FixedPointMathLib.sqrt(110889), 333); + assertEq(FixedPointMathLib.sqrt(32239684), 5678); + assertEq(FixedPointMathLib.sqrt(type(uint256).max), 340282366920938463463374607431768211455); + } + + function testSqrtBackHashedSingle() public { + testSqrtBackHashed(123); + } + + function testMulWadDown(uint256 x, uint256 y) public { + // Ignore cases where x * y overflows. + unchecked { + if (x != 0 && (x * y) / x != y) return; + } + + assertEq(FixedPointMathLib.mulWadDown(x, y), (x * y) / 1e18); + } + + function testFailMulWadDownOverflow(uint256 x, uint256 y) public pure { + // Ignore cases where x * y does not overflow. + unchecked { + if ((x * y) / x == y) revert(); + } + + FixedPointMathLib.mulWadDown(x, y); + } + + function testMulWadUp(uint256 x, uint256 y) public { + // Ignore cases where x * y overflows. + unchecked { + if (x != 0 && (x * y) / x != y) return; + } + + assertEq(FixedPointMathLib.mulWadUp(x, y), x * y == 0 ? 0 : (x * y - 1) / 1e18 + 1); + } + + function testFailMulWadUpOverflow(uint256 x, uint256 y) public pure { + // Ignore cases where x * y does not overflow. + unchecked { + if ((x * y) / x == y) revert(); + } + + FixedPointMathLib.mulWadUp(x, y); + } + + function testDivWadDown(uint256 x, uint256 y) public { + // Ignore cases where x * WAD overflows or y is 0. + unchecked { + if (y == 0 || (x != 0 && (x * 1e18) / 1e18 != x)) return; + } + + assertEq(FixedPointMathLib.divWadDown(x, y), (x * 1e18) / y); + } + + function testFailDivWadDownOverflow(uint256 x, uint256 y) public pure { + // Ignore cases where x * WAD does not overflow or y is 0. + unchecked { + if (y == 0 || (x * 1e18) / 1e18 == x) revert(); + } + + FixedPointMathLib.divWadDown(x, y); + } + + function testFailDivWadDownZeroDenominator(uint256 x) public pure { + FixedPointMathLib.divWadDown(x, 0); + } + + function testDivWadUp(uint256 x, uint256 y) public { + // Ignore cases where x * WAD overflows or y is 0. + unchecked { + if (y == 0 || (x != 0 && (x * 1e18) / 1e18 != x)) return; + } + + assertEq(FixedPointMathLib.divWadUp(x, y), x == 0 ? 0 : (x * 1e18 - 1) / y + 1); + } + + function testFailDivWadUpOverflow(uint256 x, uint256 y) public pure { + // Ignore cases where x * WAD does not overflow or y is 0. + unchecked { + if (y == 0 || (x * 1e18) / 1e18 == x) revert(); + } + + FixedPointMathLib.divWadUp(x, y); + } + + function testFailDivWadUpZeroDenominator(uint256 x) public pure { + FixedPointMathLib.divWadUp(x, 0); + } + + function testMulDivDown( + uint256 x, + uint256 y, + uint256 denominator + ) public { + // Ignore cases where x * y overflows or denominator is 0. + unchecked { + if (denominator == 0 || (x != 0 && (x * y) / x != y)) return; + } + + assertEq(FixedPointMathLib.mulDivDown(x, y, denominator), (x * y) / denominator); + } + + function testFailMulDivDownOverflow( + uint256 x, + uint256 y, + uint256 denominator + ) public pure { + // Ignore cases where x * y does not overflow or denominator is 0. + unchecked { + if (denominator == 0 || (x * y) / x == y) revert(); + } + + FixedPointMathLib.mulDivDown(x, y, denominator); + } + + function testFailMulDivDownZeroDenominator(uint256 x, uint256 y) public pure { + FixedPointMathLib.mulDivDown(x, y, 0); + } + + function testMulDivUp( + uint256 x, + uint256 y, + uint256 denominator + ) public { + // Ignore cases where x * y overflows or denominator is 0. + unchecked { + if (denominator == 0 || (x != 0 && (x * y) / x != y)) return; + } + + assertEq(FixedPointMathLib.mulDivUp(x, y, denominator), x * y == 0 ? 0 : (x * y - 1) / denominator + 1); + } + + function testFailMulDivUpOverflow( + uint256 x, + uint256 y, + uint256 denominator + ) public pure { + // Ignore cases where x * y does not overflow or denominator is 0. + unchecked { + if (denominator == 0 || (x * y) / x == y) revert(); + } + + FixedPointMathLib.mulDivUp(x, y, denominator); + } + + function testFailMulDivUpZeroDenominator(uint256 x, uint256 y) public pure { + FixedPointMathLib.mulDivUp(x, y, 0); + } + + function testDifferentiallyFuzzSqrt(uint256 x) public { + assertEq(FixedPointMathLib.sqrt(x), uniswapSqrt(x)); + assertEq(FixedPointMathLib.sqrt(x), abdkSqrt(x)); + } + + function testSqrt(uint256 x) public { + uint256 root = FixedPointMathLib.sqrt(x); + uint256 next = root + 1; + + // Ignore cases where next * next overflows. + unchecked { + if (next * next < next) return; + } + + assertTrue(root * root <= x && next * next > x); + } + + function testSqrtBack(uint256 x) public { + unchecked { + x >>= 128; + while (x != 0) { + assertEq(FixedPointMathLib.sqrt(x * x), x); + x >>= 1; + } + } + } + + function testSqrtBackHashed(uint256 x) public { + testSqrtBack(uint256(keccak256(abi.encode(x)))); + } + + function uniswapSqrt(uint256 y) internal pure returns (uint256 z) { + if (y > 3) { + z = y; + uint256 x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + } + } else if (y != 0) { + z = 1; + } + } + + function abdkSqrt(uint256 x) private pure returns (uint256) { + unchecked { + if (x == 0) return 0; + else { + uint256 xx = x; + uint256 r = 1; + if (xx >= 0x100000000000000000000000000000000) { + xx >>= 128; + r <<= 64; + } + if (xx >= 0x10000000000000000) { + xx >>= 64; + r <<= 32; + } + if (xx >= 0x100000000) { + xx >>= 32; + r <<= 16; + } + if (xx >= 0x10000) { + xx >>= 16; + r <<= 8; + } + if (xx >= 0x100) { + xx >>= 8; + r <<= 4; + } + if (xx >= 0x10) { + xx >>= 4; + r <<= 2; + } + if (xx >= 0x8) { + r <<= 1; + } + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; // Seven iterations should be enough + uint256 r1 = x / r; + return r < r1 ? r : r1; + } + } + } +} diff --git a/lib/solmate/src/test/LibString.t.sol b/lib/solmate/src/test/LibString.t.sol new file mode 100644 index 0000000..36ed435 --- /dev/null +++ b/lib/solmate/src/test/LibString.t.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {LibString} from "../utils/LibString.sol"; + +contract LibStringTest is DSTestPlus { + function testToString() public { + assertEq(LibString.toString(uint256(0)), "0"); + assertEq(LibString.toString(uint256(1)), "1"); + assertEq(LibString.toString(uint256(17)), "17"); + assertEq(LibString.toString(uint256(99999999)), "99999999"); + assertEq(LibString.toString(uint256(99999999999)), "99999999999"); + assertEq(LibString.toString(uint256(2342343923423)), "2342343923423"); + assertEq(LibString.toString(uint256(98765685434567)), "98765685434567"); + } + + function testToStringIntPositive() public { + assertEq(LibString.toString(int256(0)), "0"); + assertEq(LibString.toString(int256(1)), "1"); + assertEq(LibString.toString(int256(17)), "17"); + assertEq(LibString.toString(int256(99999999)), "99999999"); + assertEq(LibString.toString(int256(99999999999)), "99999999999"); + assertEq(LibString.toString(int256(2342343923423)), "2342343923423"); + assertEq(LibString.toString(int256(98765685434567)), "98765685434567"); + } + + function testToStringIntNegative() public { + assertEq(LibString.toString(int256(-0)), "0"); + assertEq(LibString.toString(int256(-17)), "-17"); + assertEq(LibString.toString(int256(-99999999)), "-99999999"); + assertEq(LibString.toString(int256(-99999999999)), "-99999999999"); + assertEq(LibString.toString(int256(-2342343923423)), "-2342343923423"); + assertEq(LibString.toString(int256(-98765685434567)), "-98765685434567"); + } + + function testDifferentiallyFuzzToString(uint256 value, bytes calldata brutalizeWith) + public + brutalizeMemory(brutalizeWith) + { + string memory libString = LibString.toString(value); + string memory oz = toStringOZ(value); + + assertEq(bytes(libString).length, bytes(oz).length); + assertEq(libString, oz); + } + + function testDifferentiallyFuzzToStringInt(int256 value, bytes calldata brutalizeWith) + public + brutalizeMemory(brutalizeWith) + { + string memory libString = LibString.toString(value); + string memory oz = toStringOZ(value); + + assertEq(bytes(libString).length, bytes(oz).length); + assertEq(libString, oz); + } + + function testToStringOverwrite() public { + string memory str = LibString.toString(uint256(1)); + + bytes32 data; + bytes32 expected; + + assembly { + // Imagine a high level allocation writing something to the current free memory. + // Should have sufficient higher order bits for this to be visible + mstore(mload(0x40), not(0)) + // Correctly allocate 32 more bytes, to avoid more interference + mstore(0x40, add(mload(0x40), 32)) + data := mload(add(str, 32)) + + // the expected value should be the uft-8 encoding of 1 (49), + // followed by clean bits. We achieve this by taking the value and + // shifting left to the end of the 32 byte word + expected := shl(248, 49) + } + + assertEq(data, expected); + } + + function testToStringDirty() public { + uint256 freememptr; + // Make the next 4 bytes of the free memory dirty + assembly { + let dirty := not(0) + freememptr := mload(0x40) + mstore(freememptr, dirty) + mstore(add(freememptr, 32), dirty) + mstore(add(freememptr, 64), dirty) + mstore(add(freememptr, 96), dirty) + mstore(add(freememptr, 128), dirty) + } + string memory str = LibString.toString(uint256(1)); + uint256 len; + bytes32 data; + bytes32 expected; + assembly { + freememptr := str + len := mload(str) + data := mload(add(str, 32)) + // the expected value should be the uft-8 encoding of 1 (49), + // followed by clean bits. We achieve this by taking the value and + // shifting left to the end of the 32 byte word + expected := shl(248, 49) + } + emit log_named_uint("str: ", freememptr); + emit log_named_uint("len: ", len); + emit log_named_bytes32("data: ", data); + assembly { + freememptr := mload(0x40) + } + emit log_named_uint("memptr: ", freememptr); + + assertEq(data, expected); + } +} + +function toStringOZ(int256 value) pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toStringOZ(absOZ(value)))); +} + +function toStringOZ(uint256 value) pure returns (string memory) { + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); +} + +function absOZ(int256 n) pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } +} diff --git a/lib/solmate/src/test/MerkleProofLib.t.sol b/lib/solmate/src/test/MerkleProofLib.t.sol new file mode 100644 index 0000000..5279679 --- /dev/null +++ b/lib/solmate/src/test/MerkleProofLib.t.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {MerkleProofLib} from "../utils/MerkleProofLib.sol"; + +contract MerkleProofLibTest is DSTestPlus { + function testVerifyEmptyMerkleProofSuppliedLeafAndRootSame() public { + bytes32[] memory proof; + assertBoolEq(this.verify(proof, 0x00, 0x00), true); + } + + function testVerifyEmptyMerkleProofSuppliedLeafAndRootDifferent() public { + bytes32[] memory proof; + bytes32 leaf = "a"; + assertBoolEq(this.verify(proof, 0x00, leaf), false); + } + + function testValidProofSupplied() public { + // Merkle tree created from leaves ['a', 'b', 'c']. + // Leaf is 'a'. + bytes32[] memory proof = new bytes32[](2); + proof[0] = 0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510; + proof[1] = 0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2; + bytes32 root = 0x5842148bc6ebeb52af882a317c765fccd3ae80589b21a9b8cbf21abb630e46a7; + bytes32 leaf = 0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb; + assertBoolEq(this.verify(proof, root, leaf), true); + } + + function testVerifyInvalidProofSupplied() public { + // Merkle tree created from leaves ['a', 'b', 'c']. + // Leaf is 'a'. + // Proof is same as testValidProofSupplied but last byte of first element is modified. + bytes32[] memory proof = new bytes32[](2); + proof[0] = 0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5511; + proof[1] = 0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2; + bytes32 root = 0x5842148bc6ebeb52af882a317c765fccd3ae80589b21a9b8cbf21abb630e46a7; + bytes32 leaf = 0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb; + assertBoolEq(this.verify(proof, root, leaf), false); + } + + function verify( + bytes32[] calldata proof, + bytes32 root, + bytes32 leaf + ) external pure returns (bool) { + return MerkleProofLib.verify(proof, root, leaf); + } +} diff --git a/lib/solmate/src/test/MultiRolesAuthority.t.sol b/lib/solmate/src/test/MultiRolesAuthority.t.sol new file mode 100644 index 0000000..eedf6a0 --- /dev/null +++ b/lib/solmate/src/test/MultiRolesAuthority.t.sol @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockAuthority} from "./utils/mocks/MockAuthority.sol"; + +import {Authority} from "../auth/Auth.sol"; + +import {MultiRolesAuthority} from "../auth/authorities/MultiRolesAuthority.sol"; + +contract MultiRolesAuthorityTest is DSTestPlus { + MultiRolesAuthority multiRolesAuthority; + + function setUp() public { + multiRolesAuthority = new MultiRolesAuthority(address(this), Authority(address(0))); + } + + function testSetRoles() public { + assertFalse(multiRolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertTrue(multiRolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(multiRolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + } + + function testSetRoleCapabilities() public { + assertFalse(multiRolesAuthority.doesRoleHaveCapability(0, 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.doesRoleHaveCapability(0, 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.doesRoleHaveCapability(0, 0xBEEFCAFE)); + } + + function testSetPublicCapabilities() public { + assertFalse(multiRolesAuthority.isCapabilityPublic(0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.isCapabilityPublic(0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.isCapabilityPublic(0xBEEFCAFE)); + } + + function testSetTargetCustomAuthority() public { + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(address(0xBEEF))), address(0)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xBEEF), Authority(address(0xCAFE))); + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(address(0xBEEF))), address(0xCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xBEEF), Authority(address(0))); + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(address(0xBEEF))), address(0)); + } + + function testCanCallWithAuthorizedRole() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallPublicCapability() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallWithCustomAuthority() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallWithCustomAuthorityOverridesPublicCapability() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, false); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallWithCustomAuthorityOverridesUserWithRole() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testSetRoles(address user, uint8 role) public { + assertFalse(multiRolesAuthority.doesUserHaveRole(user, role)); + + multiRolesAuthority.setUserRole(user, role, true); + assertTrue(multiRolesAuthority.doesUserHaveRole(user, role)); + + multiRolesAuthority.setUserRole(user, role, false); + assertFalse(multiRolesAuthority.doesUserHaveRole(user, role)); + } + + function testSetRoleCapabilities(uint8 role, bytes4 functionSig) public { + assertFalse(multiRolesAuthority.doesRoleHaveCapability(role, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, true); + assertTrue(multiRolesAuthority.doesRoleHaveCapability(role, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, false); + assertFalse(multiRolesAuthority.doesRoleHaveCapability(role, functionSig)); + } + + function testSetPublicCapabilities(bytes4 functionSig) public { + assertFalse(multiRolesAuthority.isCapabilityPublic(functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, true); + assertTrue(multiRolesAuthority.isCapabilityPublic(functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, false); + assertFalse(multiRolesAuthority.isCapabilityPublic(functionSig)); + } + + function testSetTargetCustomAuthority(address user, Authority customAuthority) public { + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(user)), address(0)); + + multiRolesAuthority.setTargetCustomAuthority(user, customAuthority); + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(user)), address(customAuthority)); + + multiRolesAuthority.setTargetCustomAuthority(user, Authority(address(0))); + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(user)), address(0)); + } + + function testCanCallWithAuthorizedRole( + address user, + uint8 role, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, true); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallPublicCapability( + address user, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallWithCustomAuthority( + address user, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallWithCustomAuthorityOverridesPublicCapability( + address user, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, false); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallWithCustomAuthorityOverridesUserWithRole( + address user, + uint8 role, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, true); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, false); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + } +} diff --git a/lib/solmate/src/test/Owned.t.sol b/lib/solmate/src/test/Owned.t.sol new file mode 100644 index 0000000..08a0239 --- /dev/null +++ b/lib/solmate/src/test/Owned.t.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockOwned} from "./utils/mocks/MockOwned.sol"; + +contract OwnedTest is DSTestPlus { + MockOwned mockOwned; + + function setUp() public { + mockOwned = new MockOwned(); + } + + function testTransferOwnership() public { + testTransferOwnership(address(0xBEEF)); + } + + function testCallFunctionAsNonOwner() public { + testCallFunctionAsNonOwner(address(0)); + } + + function testCallFunctionAsOwner() public { + mockOwned.updateFlag(); + } + + function testTransferOwnership(address newOwner) public { + mockOwned.transferOwnership(newOwner); + + assertEq(mockOwned.owner(), newOwner); + } + + function testCallFunctionAsNonOwner(address owner) public { + hevm.assume(owner != address(this)); + + mockOwned.transferOwnership(owner); + + hevm.expectRevert("UNAUTHORIZED"); + mockOwned.updateFlag(); + } +} diff --git a/lib/solmate/src/test/ReentrancyGuard.t.sol b/lib/solmate/src/test/ReentrancyGuard.t.sol new file mode 100644 index 0000000..842e367 --- /dev/null +++ b/lib/solmate/src/test/ReentrancyGuard.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {ReentrancyGuard} from "../utils/ReentrancyGuard.sol"; + +contract RiskyContract is ReentrancyGuard { + uint256 public enterTimes; + + function unprotectedCall() public { + enterTimes++; + + if (enterTimes > 1) return; + + this.protectedCall(); + } + + function protectedCall() public nonReentrant { + enterTimes++; + + if (enterTimes > 1) return; + + this.protectedCall(); + } + + function overprotectedCall() public nonReentrant {} +} + +contract ReentrancyGuardTest is DSTestPlus { + RiskyContract riskyContract; + + function setUp() public { + riskyContract = new RiskyContract(); + } + + function invariantReentrancyStatusAlways1() public { + assertEq(uint256(hevm.load(address(riskyContract), 0)), 1); + } + + function testFailUnprotectedCall() public { + riskyContract.unprotectedCall(); + + assertEq(riskyContract.enterTimes(), 1); + } + + function testProtectedCall() public { + try riskyContract.protectedCall() { + fail("Reentrancy Guard Failed To Stop Attacker"); + } catch {} + } + + function testNoReentrancy() public { + riskyContract.overprotectedCall(); + } +} diff --git a/lib/solmate/src/test/RolesAuthority.t.sol b/lib/solmate/src/test/RolesAuthority.t.sol new file mode 100644 index 0000000..e01db7e --- /dev/null +++ b/lib/solmate/src/test/RolesAuthority.t.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockAuthority} from "./utils/mocks/MockAuthority.sol"; + +import {Authority} from "../auth/Auth.sol"; + +import {RolesAuthority} from "../auth/authorities/RolesAuthority.sol"; + +contract RolesAuthorityTest is DSTestPlus { + RolesAuthority rolesAuthority; + + function setUp() public { + rolesAuthority = new RolesAuthority(address(this), Authority(address(0))); + } + + function testSetRoles() public { + assertFalse(rolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + + rolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertTrue(rolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + + rolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(rolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + } + + function testSetRoleCapabilities() public { + assertFalse(rolesAuthority.doesRoleHaveCapability(0, address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.doesRoleHaveCapability(0, address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, false); + assertFalse(rolesAuthority.doesRoleHaveCapability(0, address(0xCAFE), 0xBEEFCAFE)); + } + + function testSetPublicCapabilities() public { + assertFalse(rolesAuthority.isCapabilityPublic(address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setPublicCapability(address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.isCapabilityPublic(address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setPublicCapability(address(0xCAFE), 0xBEEFCAFE, false); + assertFalse(rolesAuthority.isCapabilityPublic(address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallWithAuthorizedRole() public { + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, false); + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallPublicCapability() public { + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setPublicCapability(address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setPublicCapability(address(0xCAFE), 0xBEEFCAFE, false); + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testSetRoles(address user, uint8 role) public { + assertFalse(rolesAuthority.doesUserHaveRole(user, role)); + + rolesAuthority.setUserRole(user, role, true); + assertTrue(rolesAuthority.doesUserHaveRole(user, role)); + + rolesAuthority.setUserRole(user, role, false); + assertFalse(rolesAuthority.doesUserHaveRole(user, role)); + } + + function testSetRoleCapabilities( + uint8 role, + address target, + bytes4 functionSig + ) public { + assertFalse(rolesAuthority.doesRoleHaveCapability(role, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, true); + assertTrue(rolesAuthority.doesRoleHaveCapability(role, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, false); + assertFalse(rolesAuthority.doesRoleHaveCapability(role, target, functionSig)); + } + + function testSetPublicCapabilities(address target, bytes4 functionSig) public { + assertFalse(rolesAuthority.isCapabilityPublic(target, functionSig)); + + rolesAuthority.setPublicCapability(target, functionSig, true); + assertTrue(rolesAuthority.isCapabilityPublic(target, functionSig)); + + rolesAuthority.setPublicCapability(target, functionSig, false); + assertFalse(rolesAuthority.isCapabilityPublic(target, functionSig)); + } + + function testCanCallWithAuthorizedRole( + address user, + uint8 role, + address target, + bytes4 functionSig + ) public { + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setUserRole(user, role, true); + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, true); + assertTrue(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, false); + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, true); + assertTrue(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setUserRole(user, role, false); + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallPublicCapability( + address user, + address target, + bytes4 functionSig + ) public { + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setPublicCapability(target, functionSig, true); + assertTrue(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setPublicCapability(target, functionSig, false); + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + } +} diff --git a/lib/solmate/src/test/SSTORE2.t.sol b/lib/solmate/src/test/SSTORE2.t.sol new file mode 100644 index 0000000..5d97ed7 --- /dev/null +++ b/lib/solmate/src/test/SSTORE2.t.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {SSTORE2} from "../utils/SSTORE2.sol"; + +contract SSTORE2Test is DSTestPlus { + function testWriteRead() public { + bytes memory testBytes = abi.encode("this is a test"); + + address pointer = SSTORE2.write(testBytes); + + assertBytesEq(SSTORE2.read(pointer), testBytes); + } + + function testWriteReadFullStartBound() public { + assertBytesEq(SSTORE2.read(SSTORE2.write(hex"11223344"), 0), hex"11223344"); + } + + function testWriteReadCustomStartBound() public { + assertBytesEq(SSTORE2.read(SSTORE2.write(hex"11223344"), 1), hex"223344"); + } + + function testWriteReadFullBoundedRead() public { + bytes memory testBytes = abi.encode("this is a test"); + + assertBytesEq(SSTORE2.read(SSTORE2.write(testBytes), 0, testBytes.length), testBytes); + } + + function testWriteReadCustomBounds() public { + assertBytesEq(SSTORE2.read(SSTORE2.write(hex"11223344"), 1, 3), hex"2233"); + } + + function testWriteReadEmptyBound() public { + SSTORE2.read(SSTORE2.write(hex"11223344"), 3, 3); + } + + function testFailReadInvalidPointer() public view { + SSTORE2.read(DEAD_ADDRESS); + } + + function testFailReadInvalidPointerCustomStartBound() public view { + SSTORE2.read(DEAD_ADDRESS, 1); + } + + function testFailReadInvalidPointerCustomBounds() public view { + SSTORE2.read(DEAD_ADDRESS, 2, 4); + } + + function testFailWriteReadOutOfStartBound() public { + SSTORE2.read(SSTORE2.write(hex"11223344"), 41000); + } + + function testFailWriteReadEmptyOutOfBounds() public { + SSTORE2.read(SSTORE2.write(hex"11223344"), 42000, 42000); + } + + function testFailWriteReadOutOfBounds() public { + SSTORE2.read(SSTORE2.write(hex"11223344"), 41000, 42000); + } + + function testWriteRead(bytes calldata testBytes, bytes calldata brutalizeWith) + public + brutalizeMemory(brutalizeWith) + { + assertBytesEq(SSTORE2.read(SSTORE2.write(testBytes)), testBytes); + } + + function testWriteReadCustomStartBound( + bytes calldata testBytes, + uint256 startIndex, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (testBytes.length == 0) return; + + startIndex = bound(startIndex, 0, testBytes.length); + + assertBytesEq(SSTORE2.read(SSTORE2.write(testBytes), startIndex), bytes(testBytes[startIndex:])); + } + + function testWriteReadCustomBounds( + bytes calldata testBytes, + uint256 startIndex, + uint256 endIndex, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (testBytes.length == 0) return; + + endIndex = bound(endIndex, 0, testBytes.length); + startIndex = bound(startIndex, 0, testBytes.length); + + if (startIndex > endIndex) return; + + assertBytesEq( + SSTORE2.read(SSTORE2.write(testBytes), startIndex, endIndex), + bytes(testBytes[startIndex:endIndex]) + ); + } + + function testFailReadInvalidPointer(address pointer, bytes calldata brutalizeWith) + public + view + brutalizeMemory(brutalizeWith) + { + if (pointer.code.length > 0) revert(); + + SSTORE2.read(pointer); + } + + function testFailReadInvalidPointerCustomStartBound( + address pointer, + uint256 startIndex, + bytes calldata brutalizeWith + ) public view brutalizeMemory(brutalizeWith) { + if (pointer.code.length > 0) revert(); + + SSTORE2.read(pointer, startIndex); + } + + function testFailReadInvalidPointerCustomBounds( + address pointer, + uint256 startIndex, + uint256 endIndex, + bytes calldata brutalizeWith + ) public view brutalizeMemory(brutalizeWith) { + if (pointer.code.length > 0) revert(); + + SSTORE2.read(pointer, startIndex, endIndex); + } + + function testFailWriteReadCustomStartBoundOutOfRange( + bytes calldata testBytes, + uint256 startIndex, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + startIndex = bound(startIndex, testBytes.length + 1, type(uint256).max); + + SSTORE2.read(SSTORE2.write(testBytes), startIndex); + } + + function testFailWriteReadCustomBoundsOutOfRange( + bytes calldata testBytes, + uint256 startIndex, + uint256 endIndex, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + endIndex = bound(endIndex, testBytes.length + 1, type(uint256).max); + + SSTORE2.read(SSTORE2.write(testBytes), startIndex, endIndex); + } +} diff --git a/lib/solmate/src/test/SafeCastLib.t.sol b/lib/solmate/src/test/SafeCastLib.t.sol new file mode 100644 index 0000000..52a6c07 --- /dev/null +++ b/lib/solmate/src/test/SafeCastLib.t.sol @@ -0,0 +1,644 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {SafeCastLib} from "../utils/SafeCastLib.sol"; + +contract SafeCastLibTest is DSTestPlus { + function testSafeCastTo248() public { + assertEq(SafeCastLib.safeCastTo248(2.5e45), 2.5e45); + assertEq(SafeCastLib.safeCastTo248(2.5e27), 2.5e27); + } + + function testSafeCastTo240() public { + assertEq(SafeCastLib.safeCastTo240(2.5e45), 2.5e45); + assertEq(SafeCastLib.safeCastTo240(2.5e27), 2.5e27); + } + + function testSafeCastTo232() public { + assertEq(SafeCastLib.safeCastTo232(2.5e45), 2.5e45); + assertEq(SafeCastLib.safeCastTo232(2.5e27), 2.5e27); + } + + function testSafeCastTo224() public { + assertEq(SafeCastLib.safeCastTo224(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo224(2.5e27), 2.5e27); + } + + function testSafeCastTo216() public { + assertEq(SafeCastLib.safeCastTo216(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo216(2.5e27), 2.5e27); + } + + function testSafeCastTo208() public { + assertEq(SafeCastLib.safeCastTo208(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo208(2.5e27), 2.5e27); + } + + function testSafeCastTo200() public { + assertEq(SafeCastLib.safeCastTo200(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo200(2.5e27), 2.5e27); + } + + function testSafeCastTo192() public { + assertEq(SafeCastLib.safeCastTo192(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo192(2.5e27), 2.5e27); + } + + function testSafeCastTo184() public { + assertEq(SafeCastLib.safeCastTo184(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo184(2.5e27), 2.5e27); + } + + function testSafeCastTo176() public { + assertEq(SafeCastLib.safeCastTo176(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo176(2.5e27), 2.5e27); + } + + function testSafeCastTo168() public { + assertEq(SafeCastLib.safeCastTo168(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo168(2.5e27), 2.5e27); + } + + function testSafeCastTo160() public { + assertEq(SafeCastLib.safeCastTo160(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo160(2.5e27), 2.5e27); + } + + function testSafeCastTo152() public { + assertEq(SafeCastLib.safeCastTo152(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo152(2.5e27), 2.5e27); + } + + function testSafeCastTo144() public { + assertEq(SafeCastLib.safeCastTo144(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo144(2.5e27), 2.5e27); + } + + function testSafeCastTo136() public { + assertEq(SafeCastLib.safeCastTo136(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo136(2.5e27), 2.5e27); + } + + function testSafeCastTo128() public { + assertEq(SafeCastLib.safeCastTo128(2.5e27), 2.5e27); + assertEq(SafeCastLib.safeCastTo128(2.5e18), 2.5e18); + } + + function testSafeCastTo120() public { + assertEq(SafeCastLib.safeCastTo120(2.5e27), 2.5e27); + assertEq(SafeCastLib.safeCastTo120(2.5e18), 2.5e18); + } + + function testSafeCastTo112() public { + assertEq(SafeCastLib.safeCastTo112(2.5e27), 2.5e27); + assertEq(SafeCastLib.safeCastTo112(2.5e18), 2.5e18); + } + + function testSafeCastTo104() public { + assertEq(SafeCastLib.safeCastTo104(2.5e27), 2.5e27); + assertEq(SafeCastLib.safeCastTo104(2.5e18), 2.5e18); + } + + function testSafeCastTo96() public { + assertEq(SafeCastLib.safeCastTo96(2.5e18), 2.5e18); + assertEq(SafeCastLib.safeCastTo96(2.5e17), 2.5e17); + } + + function testSafeCastTo64() public { + assertEq(SafeCastLib.safeCastTo64(2.5e18), 2.5e18); + assertEq(SafeCastLib.safeCastTo64(2.5e17), 2.5e17); + } + + function testSafeCastTo56() public { + assertEq(SafeCastLib.safeCastTo56(2.5e16), 2.5e16); + assertEq(SafeCastLib.safeCastTo56(2.5e15), 2.5e15); + } + + function testSafeCastTo48() public { + assertEq(SafeCastLib.safeCastTo48(2.5e12), 2.5e12); + assertEq(SafeCastLib.safeCastTo48(2.5e11), 2.5e11); + } + + function testSafeCastTo40() public { + assertEq(SafeCastLib.safeCastTo40(2.5e10), 2.5e10); + assertEq(SafeCastLib.safeCastTo40(2.5e9), 2.5e9); + } + + function testSafeCastTo32() public { + assertEq(SafeCastLib.safeCastTo32(2.5e8), 2.5e8); + assertEq(SafeCastLib.safeCastTo32(2.5e7), 2.5e7); + } + + function testSafeCastTo24() public { + assertEq(SafeCastLib.safeCastTo24(2.5e4), 2.5e4); + assertEq(SafeCastLib.safeCastTo24(2.5e3), 2.5e3); + } + + function testSafeCastTo16() public { + assertEq(SafeCastLib.safeCastTo16(2.5e3), 2.5e3); + assertEq(SafeCastLib.safeCastTo16(2.5e2), 2.5e2); + } + + function testSafeCastTo8() public { + assertEq(SafeCastLib.safeCastTo8(100), 100); + assertEq(SafeCastLib.safeCastTo8(250), 250); + } + + function testFailSafeCastTo248() public pure { + SafeCastLib.safeCastTo248(type(uint248).max + 1); + } + + function testFailSafeCastTo240() public pure { + SafeCastLib.safeCastTo240(type(uint240).max + 1); + } + + function testFailSafeCastTo232() public pure { + SafeCastLib.safeCastTo232(type(uint232).max + 1); + } + + function testFailSafeCastTo224() public pure { + SafeCastLib.safeCastTo224(type(uint224).max + 1); + } + + function testFailSafeCastTo216() public pure { + SafeCastLib.safeCastTo216(type(uint216).max + 1); + } + + function testFailSafeCastTo208() public pure { + SafeCastLib.safeCastTo208(type(uint208).max + 1); + } + + function testFailSafeCastTo200() public pure { + SafeCastLib.safeCastTo200(type(uint200).max + 1); + } + + function testFailSafeCastTo192() public pure { + SafeCastLib.safeCastTo192(type(uint192).max + 1); + } + + function testFailSafeCastTo184() public pure { + SafeCastLib.safeCastTo184(type(uint184).max + 1); + } + + function testFailSafeCastTo176() public pure { + SafeCastLib.safeCastTo176(type(uint176).max + 1); + } + + function testFailSafeCastTo168() public pure { + SafeCastLib.safeCastTo168(type(uint168).max + 1); + } + + function testFailSafeCastTo160() public pure { + SafeCastLib.safeCastTo160(type(uint160).max + 1); + } + + function testFailSafeCastTo152() public pure { + SafeCastLib.safeCastTo152(type(uint152).max + 1); + } + + function testFailSafeCastTo144() public pure { + SafeCastLib.safeCastTo144(type(uint144).max + 1); + } + + function testFailSafeCastTo136() public pure { + SafeCastLib.safeCastTo136(type(uint136).max + 1); + } + + function testFailSafeCastTo128() public pure { + SafeCastLib.safeCastTo128(type(uint128).max + 1); + } + + function testFailSafeCastTo120() public pure { + SafeCastLib.safeCastTo120(type(uint120).max + 1); + } + + function testFailSafeCastTo112() public pure { + SafeCastLib.safeCastTo112(type(uint112).max + 1); + } + + function testFailSafeCastTo104() public pure { + SafeCastLib.safeCastTo104(type(uint104).max + 1); + } + + function testFailSafeCastTo96() public pure { + SafeCastLib.safeCastTo96(type(uint96).max + 1); + } + + function testFailSafeCastTo88() public pure { + SafeCastLib.safeCastTo88(type(uint88).max + 1); + } + + function testFailSafeCastTo80() public pure { + SafeCastLib.safeCastTo80(type(uint80).max + 1); + } + + function testFailSafeCastTo72() public pure { + SafeCastLib.safeCastTo72(type(uint72).max + 1); + } + + function testFailSafeCastTo64() public pure { + SafeCastLib.safeCastTo64(type(uint64).max + 1); + } + + function testFailSafeCastTo56() public pure { + SafeCastLib.safeCastTo56(type(uint56).max + 1); + } + + function testFailSafeCastTo48() public pure { + SafeCastLib.safeCastTo48(type(uint48).max + 1); + } + + function testFailSafeCastTo40() public pure { + SafeCastLib.safeCastTo40(type(uint40).max + 1); + } + + function testFailSafeCastTo32() public pure { + SafeCastLib.safeCastTo32(type(uint32).max + 1); + } + + function testFailSafeCastTo24() public pure { + SafeCastLib.safeCastTo24(type(uint24).max + 1); + } + + function testFailSafeCastTo16() public pure { + SafeCastLib.safeCastTo16(type(uint16).max + 1); + } + + function testFailSafeCastTo8() public pure { + SafeCastLib.safeCastTo8(type(uint8).max + 1); + } + + function testSafeCastTo248(uint256 x) public { + x = bound(x, 0, type(uint248).max); + + assertEq(SafeCastLib.safeCastTo248(x), x); + } + + function testSafeCastTo240(uint256 x) public { + x = bound(x, 0, type(uint240).max); + + assertEq(SafeCastLib.safeCastTo240(x), x); + } + + function testSafeCastTo232(uint256 x) public { + x = bound(x, 0, type(uint232).max); + + assertEq(SafeCastLib.safeCastTo232(x), x); + } + + function testSafeCastTo224(uint256 x) public { + x = bound(x, 0, type(uint224).max); + + assertEq(SafeCastLib.safeCastTo224(x), x); + } + + function testSafeCastTo216(uint256 x) public { + x = bound(x, 0, type(uint216).max); + + assertEq(SafeCastLib.safeCastTo216(x), x); + } + + function testSafeCastTo208(uint256 x) public { + x = bound(x, 0, type(uint208).max); + + assertEq(SafeCastLib.safeCastTo208(x), x); + } + + function testSafeCastTo200(uint256 x) public { + x = bound(x, 0, type(uint200).max); + + assertEq(SafeCastLib.safeCastTo200(x), x); + } + + function testSafeCastTo192(uint256 x) public { + x = bound(x, 0, type(uint192).max); + + assertEq(SafeCastLib.safeCastTo192(x), x); + } + + function testSafeCastTo184(uint256 x) public { + x = bound(x, 0, type(uint184).max); + + assertEq(SafeCastLib.safeCastTo184(x), x); + } + + function testSafeCastTo176(uint256 x) public { + x = bound(x, 0, type(uint176).max); + + assertEq(SafeCastLib.safeCastTo176(x), x); + } + + function testSafeCastTo168(uint256 x) public { + x = bound(x, 0, type(uint168).max); + + assertEq(SafeCastLib.safeCastTo168(x), x); + } + + function testSafeCastTo160(uint256 x) public { + x = bound(x, 0, type(uint160).max); + + assertEq(SafeCastLib.safeCastTo160(x), x); + } + + function testSafeCastTo152(uint256 x) public { + x = bound(x, 0, type(uint152).max); + + assertEq(SafeCastLib.safeCastTo152(x), x); + } + + function testSafeCastTo144(uint256 x) public { + x = bound(x, 0, type(uint144).max); + + assertEq(SafeCastLib.safeCastTo144(x), x); + } + + function testSafeCastTo136(uint256 x) public { + x = bound(x, 0, type(uint136).max); + + assertEq(SafeCastLib.safeCastTo136(x), x); + } + + function testSafeCastTo128(uint256 x) public { + x = bound(x, 0, type(uint128).max); + + assertEq(SafeCastLib.safeCastTo128(x), x); + } + + function testSafeCastTo120(uint256 x) public { + x = bound(x, 0, type(uint120).max); + + assertEq(SafeCastLib.safeCastTo120(x), x); + } + + function testSafeCastTo112(uint256 x) public { + x = bound(x, 0, type(uint112).max); + + assertEq(SafeCastLib.safeCastTo112(x), x); + } + + function testSafeCastTo104(uint256 x) public { + x = bound(x, 0, type(uint104).max); + + assertEq(SafeCastLib.safeCastTo104(x), x); + } + + function testSafeCastTo96(uint256 x) public { + x = bound(x, 0, type(uint96).max); + + assertEq(SafeCastLib.safeCastTo96(x), x); + } + + function testSafeCastTo88(uint256 x) public { + x = bound(x, 0, type(uint88).max); + + assertEq(SafeCastLib.safeCastTo88(x), x); + } + + function testSafeCastTo80(uint256 x) public { + x = bound(x, 0, type(uint80).max); + + assertEq(SafeCastLib.safeCastTo80(x), x); + } + + function testSafeCastTo72(uint256 x) public { + x = bound(x, 0, type(uint72).max); + + assertEq(SafeCastLib.safeCastTo72(x), x); + } + + function testSafeCastTo64(uint256 x) public { + x = bound(x, 0, type(uint64).max); + + assertEq(SafeCastLib.safeCastTo64(x), x); + } + + function testSafeCastTo56(uint256 x) public { + x = bound(x, 0, type(uint56).max); + + assertEq(SafeCastLib.safeCastTo56(x), x); + } + + function testSafeCastTo48(uint256 x) public { + x = bound(x, 0, type(uint48).max); + + assertEq(SafeCastLib.safeCastTo48(x), x); + } + + function testSafeCastTo40(uint256 x) public { + x = bound(x, 0, type(uint40).max); + + assertEq(SafeCastLib.safeCastTo40(x), x); + } + + function testSafeCastTo32(uint256 x) public { + x = bound(x, 0, type(uint32).max); + + assertEq(SafeCastLib.safeCastTo32(x), x); + } + + function testSafeCastTo24(uint256 x) public { + x = bound(x, 0, type(uint24).max); + + assertEq(SafeCastLib.safeCastTo24(x), x); + } + + function testSafeCastTo16(uint256 x) public { + x = bound(x, 0, type(uint16).max); + + assertEq(SafeCastLib.safeCastTo16(x), x); + } + + function testSafeCastTo8(uint256 x) public { + x = bound(x, 0, type(uint8).max); + + assertEq(SafeCastLib.safeCastTo8(x), x); + } + + function testFailSafeCastTo248(uint256 x) public { + x = bound(x, type(uint248).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo248(x); + } + + function testFailSafeCastTo240(uint256 x) public { + x = bound(x, type(uint240).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo240(x); + } + + function testFailSafeCastTo232(uint256 x) public { + x = bound(x, type(uint232).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo232(x); + } + + function testFailSafeCastTo224(uint256 x) public { + x = bound(x, type(uint224).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo224(x); + } + + function testFailSafeCastTo216(uint256 x) public { + x = bound(x, type(uint216).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo216(x); + } + + function testFailSafeCastTo208(uint256 x) public { + x = bound(x, type(uint208).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo208(x); + } + + function testFailSafeCastTo200(uint256 x) public { + x = bound(x, type(uint200).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo200(x); + } + + function testFailSafeCastTo192(uint256 x) public { + x = bound(x, type(uint192).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo192(x); + } + + function testFailSafeCastTo184(uint256 x) public { + x = bound(x, type(uint184).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo184(x); + } + + function testFailSafeCastTo176(uint256 x) public { + x = bound(x, type(uint176).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo176(x); + } + + function testFailSafeCastTo168(uint256 x) public { + x = bound(x, type(uint168).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo168(x); + } + + function testFailSafeCastTo160(uint256 x) public { + x = bound(x, type(uint160).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo160(x); + } + + function testFailSafeCastTo152(uint256 x) public { + x = bound(x, type(uint152).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo152(x); + } + + function testFailSafeCastTo144(uint256 x) public { + x = bound(x, type(uint144).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo144(x); + } + + function testFailSafeCastTo136(uint256 x) public { + x = bound(x, type(uint136).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo136(x); + } + + function testFailSafeCastTo128(uint256 x) public { + x = bound(x, type(uint128).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo128(x); + } + + function testFailSafeCastTo120(uint256 x) public { + x = bound(x, type(uint120).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo120(x); + } + + function testFailSafeCastTo112(uint256 x) public { + x = bound(x, type(uint112).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo112(x); + } + + function testFailSafeCastTo104(uint256 x) public { + x = bound(x, type(uint104).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo104(x); + } + + function testFailSafeCastTo96(uint256 x) public { + x = bound(x, type(uint96).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo96(x); + } + + function testFailSafeCastTo88(uint256 x) public { + x = bound(x, type(uint88).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo88(x); + } + + function testFailSafeCastTo80(uint256 x) public { + x = bound(x, type(uint80).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo80(x); + } + + function testFailSafeCastTo72(uint256 x) public { + x = bound(x, type(uint72).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo72(x); + } + + function testFailSafeCastTo64(uint256 x) public { + x = bound(x, type(uint64).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo64(x); + } + + function testFailSafeCastTo56(uint256 x) public { + x = bound(x, type(uint56).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo56(x); + } + + function testFailSafeCastTo48(uint256 x) public { + x = bound(x, type(uint48).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo48(x); + } + + function testFailSafeCastTo40(uint256 x) public { + x = bound(x, type(uint40).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo40(x); + } + + function testFailSafeCastTo32(uint256 x) public { + x = bound(x, type(uint32).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo32(x); + } + + function testFailSafeCastTo24(uint256 x) public { + x = bound(x, type(uint24).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo24(x); + } + + function testFailSafeCastTo16(uint256 x) public { + x = bound(x, type(uint16).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo16(x); + } + + function testFailSafeCastTo8(uint256 x) public { + x = bound(x, type(uint8).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo8(x); + } +} diff --git a/lib/solmate/src/test/SafeTransferLib.t.sol b/lib/solmate/src/test/SafeTransferLib.t.sol new file mode 100644 index 0000000..b976e9f --- /dev/null +++ b/lib/solmate/src/test/SafeTransferLib.t.sol @@ -0,0 +1,610 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {MockERC20} from "./utils/mocks/MockERC20.sol"; +import {RevertingToken} from "./utils/weird-tokens/RevertingToken.sol"; +import {ReturnsTwoToken} from "./utils/weird-tokens/ReturnsTwoToken.sol"; +import {ReturnsFalseToken} from "./utils/weird-tokens/ReturnsFalseToken.sol"; +import {MissingReturnToken} from "./utils/weird-tokens/MissingReturnToken.sol"; +import {ReturnsTooMuchToken} from "./utils/weird-tokens/ReturnsTooMuchToken.sol"; +import {ReturnsGarbageToken} from "./utils/weird-tokens/ReturnsGarbageToken.sol"; +import {ReturnsTooLittleToken} from "./utils/weird-tokens/ReturnsTooLittleToken.sol"; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {ERC20} from "../tokens/ERC20.sol"; +import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; + +contract SafeTransferLibTest is DSTestPlus { + RevertingToken reverting; + ReturnsTwoToken returnsTwo; + ReturnsFalseToken returnsFalse; + MissingReturnToken missingReturn; + ReturnsTooMuchToken returnsTooMuch; + ReturnsGarbageToken returnsGarbage; + ReturnsTooLittleToken returnsTooLittle; + + MockERC20 erc20; + + function setUp() public { + reverting = new RevertingToken(); + returnsTwo = new ReturnsTwoToken(); + returnsFalse = new ReturnsFalseToken(); + missingReturn = new MissingReturnToken(); + returnsTooMuch = new ReturnsTooMuchToken(); + returnsGarbage = new ReturnsGarbageToken(); + returnsTooLittle = new ReturnsTooLittleToken(); + + erc20 = new MockERC20("StandardToken", "ST", 18); + erc20.mint(address(this), type(uint256).max); + } + + function testTransferWithMissingReturn() public { + verifySafeTransfer(address(missingReturn), address(0xBEEF), 1e18); + } + + function testTransferWithStandardERC20() public { + verifySafeTransfer(address(erc20), address(0xBEEF), 1e18); + } + + function testTransferWithReturnsTooMuch() public { + verifySafeTransfer(address(returnsTooMuch), address(0xBEEF), 1e18); + } + + function testTransferWithNonContract() public { + SafeTransferLib.safeTransfer(ERC20(address(0xBADBEEF)), address(0xBEEF), 1e18); + } + + function testTransferFromWithMissingReturn() public { + verifySafeTransferFrom(address(missingReturn), address(0xFEED), address(0xBEEF), 1e18); + } + + function testTransferFromWithStandardERC20() public { + verifySafeTransferFrom(address(erc20), address(0xFEED), address(0xBEEF), 1e18); + } + + function testTransferFromWithReturnsTooMuch() public { + verifySafeTransferFrom(address(returnsTooMuch), address(0xFEED), address(0xBEEF), 1e18); + } + + function testTransferFromWithNonContract() public { + SafeTransferLib.safeTransferFrom(ERC20(address(0xBADBEEF)), address(0xFEED), address(0xBEEF), 1e18); + } + + function testApproveWithMissingReturn() public { + verifySafeApprove(address(missingReturn), address(0xBEEF), 1e18); + } + + function testApproveWithStandardERC20() public { + verifySafeApprove(address(erc20), address(0xBEEF), 1e18); + } + + function testApproveWithReturnsTooMuch() public { + verifySafeApprove(address(returnsTooMuch), address(0xBEEF), 1e18); + } + + function testApproveWithNonContract() public { + SafeTransferLib.safeApprove(ERC20(address(0xBADBEEF)), address(0xBEEF), 1e18); + } + + function testTransferETH() public { + SafeTransferLib.safeTransferETH(address(0xBEEF), 1e18); + } + + function testFailTransferWithReturnsFalse() public { + verifySafeTransfer(address(returnsFalse), address(0xBEEF), 1e18); + } + + function testFailTransferWithReverting() public { + verifySafeTransfer(address(reverting), address(0xBEEF), 1e18); + } + + function testFailTransferWithReturnsTooLittle() public { + verifySafeTransfer(address(returnsTooLittle), address(0xBEEF), 1e18); + } + + function testFailTransferFromWithReturnsFalse() public { + verifySafeTransferFrom(address(returnsFalse), address(0xFEED), address(0xBEEF), 1e18); + } + + function testFailTransferFromWithReverting() public { + verifySafeTransferFrom(address(reverting), address(0xFEED), address(0xBEEF), 1e18); + } + + function testFailTransferFromWithReturnsTooLittle() public { + verifySafeTransferFrom(address(returnsTooLittle), address(0xFEED), address(0xBEEF), 1e18); + } + + function testFailApproveWithReturnsFalse() public { + verifySafeApprove(address(returnsFalse), address(0xBEEF), 1e18); + } + + function testFailApproveWithReverting() public { + verifySafeApprove(address(reverting), address(0xBEEF), 1e18); + } + + function testFailApproveWithReturnsTooLittle() public { + verifySafeApprove(address(returnsTooLittle), address(0xBEEF), 1e18); + } + + function testTransferWithMissingReturn( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(missingReturn), to, amount); + } + + function testTransferWithStandardERC20( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(erc20), to, amount); + } + + function testTransferWithReturnsTooMuch( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(returnsTooMuch), to, amount); + } + + function testTransferWithGarbage( + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if ( + (garbage.length < 32 || + (garbage[0] != 0 || + garbage[1] != 0 || + garbage[2] != 0 || + garbage[3] != 0 || + garbage[4] != 0 || + garbage[5] != 0 || + garbage[6] != 0 || + garbage[7] != 0 || + garbage[8] != 0 || + garbage[9] != 0 || + garbage[10] != 0 || + garbage[11] != 0 || + garbage[12] != 0 || + garbage[13] != 0 || + garbage[14] != 0 || + garbage[15] != 0 || + garbage[16] != 0 || + garbage[17] != 0 || + garbage[18] != 0 || + garbage[19] != 0 || + garbage[20] != 0 || + garbage[21] != 0 || + garbage[22] != 0 || + garbage[23] != 0 || + garbage[24] != 0 || + garbage[25] != 0 || + garbage[26] != 0 || + garbage[27] != 0 || + garbage[28] != 0 || + garbage[29] != 0 || + garbage[30] != 0 || + garbage[31] != bytes1(0x01))) && garbage.length != 0 + ) return; + + returnsGarbage.setGarbage(garbage); + + verifySafeTransfer(address(returnsGarbage), to, amount); + } + + function testTransferWithNonContract( + address nonContract, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (uint256(uint160(nonContract)) <= 18 || nonContract.code.length > 0) return; + + SafeTransferLib.safeTransfer(ERC20(nonContract), to, amount); + } + + function testFailTransferETHToContractWithoutFallback() public { + SafeTransferLib.safeTransferETH(address(this), 1e18); + } + + function testTransferFromWithMissingReturn( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(missingReturn), from, to, amount); + } + + function testTransferFromWithStandardERC20( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(erc20), from, to, amount); + } + + function testTransferFromWithReturnsTooMuch( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(returnsTooMuch), from, to, amount); + } + + function testTransferFromWithGarbage( + address from, + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if ( + (garbage.length < 32 || + (garbage[0] != 0 || + garbage[1] != 0 || + garbage[2] != 0 || + garbage[3] != 0 || + garbage[4] != 0 || + garbage[5] != 0 || + garbage[6] != 0 || + garbage[7] != 0 || + garbage[8] != 0 || + garbage[9] != 0 || + garbage[10] != 0 || + garbage[11] != 0 || + garbage[12] != 0 || + garbage[13] != 0 || + garbage[14] != 0 || + garbage[15] != 0 || + garbage[16] != 0 || + garbage[17] != 0 || + garbage[18] != 0 || + garbage[19] != 0 || + garbage[20] != 0 || + garbage[21] != 0 || + garbage[22] != 0 || + garbage[23] != 0 || + garbage[24] != 0 || + garbage[25] != 0 || + garbage[26] != 0 || + garbage[27] != 0 || + garbage[28] != 0 || + garbage[29] != 0 || + garbage[30] != 0 || + garbage[31] != bytes1(0x01))) && garbage.length != 0 + ) return; + + returnsGarbage.setGarbage(garbage); + + verifySafeTransferFrom(address(returnsGarbage), from, to, amount); + } + + function testTransferFromWithNonContract( + address nonContract, + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (uint256(uint160(nonContract)) <= 18 || nonContract.code.length > 0) return; + + SafeTransferLib.safeTransferFrom(ERC20(nonContract), from, to, amount); + } + + function testApproveWithMissingReturn( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(missingReturn), to, amount); + } + + function testApproveWithStandardERC20( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(erc20), to, amount); + } + + function testApproveWithReturnsTooMuch( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(returnsTooMuch), to, amount); + } + + function testApproveWithGarbage( + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if ( + (garbage.length < 32 || + (garbage[0] != 0 || + garbage[1] != 0 || + garbage[2] != 0 || + garbage[3] != 0 || + garbage[4] != 0 || + garbage[5] != 0 || + garbage[6] != 0 || + garbage[7] != 0 || + garbage[8] != 0 || + garbage[9] != 0 || + garbage[10] != 0 || + garbage[11] != 0 || + garbage[12] != 0 || + garbage[13] != 0 || + garbage[14] != 0 || + garbage[15] != 0 || + garbage[16] != 0 || + garbage[17] != 0 || + garbage[18] != 0 || + garbage[19] != 0 || + garbage[20] != 0 || + garbage[21] != 0 || + garbage[22] != 0 || + garbage[23] != 0 || + garbage[24] != 0 || + garbage[25] != 0 || + garbage[26] != 0 || + garbage[27] != 0 || + garbage[28] != 0 || + garbage[29] != 0 || + garbage[30] != 0 || + garbage[31] != bytes1(0x01))) && garbage.length != 0 + ) return; + + returnsGarbage.setGarbage(garbage); + + verifySafeApprove(address(returnsGarbage), to, amount); + } + + function testApproveWithNonContract( + address nonContract, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (uint256(uint160(nonContract)) <= 18 || nonContract.code.length > 0) return; + + SafeTransferLib.safeApprove(ERC20(nonContract), to, amount); + } + + function testTransferETH( + address recipient, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + // Transferring to msg.sender can fail because it's possible to overflow their ETH balance as it begins non-zero. + if (recipient.code.length > 0 || uint256(uint160(recipient)) <= 18 || recipient == msg.sender) return; + + amount = bound(amount, 0, address(this).balance); + + SafeTransferLib.safeTransferETH(recipient, amount); + } + + function testFailTransferWithReturnsFalse( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(returnsFalse), to, amount); + } + + function testFailTransferWithReverting( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(reverting), to, amount); + } + + function testFailTransferWithReturnsTooLittle( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(returnsTooLittle), to, amount); + } + + function testFailTransferWithReturnsTwo( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(returnsTwo), to, amount); + } + + function testFailTransferWithGarbage( + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + require(garbage.length != 0 && (garbage.length < 32 || garbage[31] != bytes1(0x01))); + + returnsGarbage.setGarbage(garbage); + + verifySafeTransfer(address(returnsGarbage), to, amount); + } + + function testFailTransferFromWithReturnsFalse( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(returnsFalse), from, to, amount); + } + + function testFailTransferFromWithReverting( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(reverting), from, to, amount); + } + + function testFailTransferFromWithReturnsTooLittle( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(returnsTooLittle), from, to, amount); + } + + function testFailTransferFromWithReturnsTwo( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(returnsTwo), from, to, amount); + } + + function testFailTransferFromWithGarbage( + address from, + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + require(garbage.length != 0 && (garbage.length < 32 || garbage[31] != bytes1(0x01))); + + returnsGarbage.setGarbage(garbage); + + verifySafeTransferFrom(address(returnsGarbage), from, to, amount); + } + + function testFailApproveWithReturnsFalse( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(returnsFalse), to, amount); + } + + function testFailApproveWithReverting( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(reverting), to, amount); + } + + function testFailApproveWithReturnsTooLittle( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(returnsTooLittle), to, amount); + } + + function testFailApproveWithReturnsTwo( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(returnsTwo), to, amount); + } + + function testFailApproveWithGarbage( + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + require(garbage.length != 0 && (garbage.length < 32 || garbage[31] != bytes1(0x01))); + + returnsGarbage.setGarbage(garbage); + + verifySafeApprove(address(returnsGarbage), to, amount); + } + + function testFailTransferETHToContractWithoutFallback(uint256 amount, bytes calldata brutalizeWith) + public + brutalizeMemory(brutalizeWith) + { + SafeTransferLib.safeTransferETH(address(this), amount); + } + + function verifySafeTransfer( + address token, + address to, + uint256 amount + ) internal { + uint256 preBal = ERC20(token).balanceOf(to); + SafeTransferLib.safeTransfer(ERC20(address(token)), to, amount); + uint256 postBal = ERC20(token).balanceOf(to); + + if (to == address(this)) { + assertEq(preBal, postBal); + } else { + assertEq(postBal - preBal, amount); + } + } + + function verifySafeTransferFrom( + address token, + address from, + address to, + uint256 amount + ) internal { + forceApprove(token, from, address(this), amount); + + // We cast to MissingReturnToken here because it won't check + // that there was return data, which accommodates all tokens. + MissingReturnToken(token).transfer(from, amount); + + uint256 preBal = ERC20(token).balanceOf(to); + SafeTransferLib.safeTransferFrom(ERC20(token), from, to, amount); + uint256 postBal = ERC20(token).balanceOf(to); + + if (from == to) { + assertEq(preBal, postBal); + } else { + assertEq(postBal - preBal, amount); + } + } + + function verifySafeApprove( + address token, + address to, + uint256 amount + ) internal { + SafeTransferLib.safeApprove(ERC20(address(token)), to, amount); + + assertEq(ERC20(token).allowance(address(this), to), amount); + } + + function forceApprove( + address token, + address from, + address to, + uint256 amount + ) internal { + uint256 slot = token == address(erc20) ? 4 : 2; // Standard ERC20 name and symbol aren't constant. + + hevm.store( + token, + keccak256(abi.encode(to, keccak256(abi.encode(from, uint256(slot))))), + bytes32(uint256(amount)) + ); + + assertEq(ERC20(token).allowance(from, to), amount, "wrong allowance"); + } +} diff --git a/lib/solmate/src/test/SignedWadMath.t.sol b/lib/solmate/src/test/SignedWadMath.t.sol new file mode 100644 index 0000000..4849448 --- /dev/null +++ b/lib/solmate/src/test/SignedWadMath.t.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {wadMul, wadDiv} from "../utils/SignedWadMath.sol"; + +contract SignedWadMathTest is DSTestPlus { + function testWadMul( + uint256 x, + uint256 y, + bool negX, + bool negY + ) public { + x = bound(x, 0, 99999999999999e18); + y = bound(x, 0, 99999999999999e18); + + int256 xPrime = negX ? -int256(x) : int256(x); + int256 yPrime = negY ? -int256(y) : int256(y); + + assertEq(wadMul(xPrime, yPrime), (xPrime * yPrime) / 1e18); + } + + function testFailWadMulEdgeCase() public pure { + int256 x = -1; + int256 y = type(int256).min; + + wadMul(x, y); + } + + function testFailWadMulEdgeCase2() public pure { + int256 x = type(int256).min; + int256 y = -1; + + wadMul(x, y); + } + + function testFailWadMulOverflow(int256 x, int256 y) public pure { + // Ignore cases where x * y does not overflow. + unchecked { + if ((x * y) / x == y) revert(); + } + + wadMul(x, y); + } + + function testWadDiv( + uint256 x, + uint256 y, + bool negX, + bool negY + ) public { + x = bound(x, 0, 99999999e18); + y = bound(x, 1, 99999999e18); + + int256 xPrime = negX ? -int256(x) : int256(x); + int256 yPrime = negY ? -int256(y) : int256(y); + + assertEq(wadDiv(xPrime, yPrime), (xPrime * 1e18) / yPrime); + } + + function testFailWadDivOverflow(int256 x, int256 y) public pure { + // Ignore cases where x * WAD does not overflow or y is 0. + unchecked { + if (y == 0 || (x * 1e18) / 1e18 == x) revert(); + } + + wadDiv(x, y); + } + + function testFailWadDivZeroDenominator(int256 x) public pure { + wadDiv(x, 0); + } +} diff --git a/lib/solmate/src/test/WETH.t.sol b/lib/solmate/src/test/WETH.t.sol new file mode 100644 index 0000000..a13761e --- /dev/null +++ b/lib/solmate/src/test/WETH.t.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; + +import {WETH} from "../tokens/WETH.sol"; + +contract WETHTest is DSTestPlus { + WETH weth; + + function setUp() public { + weth = new WETH(); + } + + function testFallbackDeposit() public { + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + + SafeTransferLib.safeTransferETH(address(weth), 1 ether); + + assertEq(weth.balanceOf(address(this)), 1 ether); + assertEq(weth.totalSupply(), 1 ether); + } + + function testDeposit() public { + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + + weth.deposit{value: 1 ether}(); + + assertEq(weth.balanceOf(address(this)), 1 ether); + assertEq(weth.totalSupply(), 1 ether); + } + + function testWithdraw() public { + uint256 startingBalance = address(this).balance; + + weth.deposit{value: 1 ether}(); + + weth.withdraw(1 ether); + + uint256 balanceAfterWithdraw = address(this).balance; + + assertEq(balanceAfterWithdraw, startingBalance); + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + } + + function testPartialWithdraw() public { + weth.deposit{value: 1 ether}(); + + uint256 balanceBeforeWithdraw = address(this).balance; + + weth.withdraw(0.5 ether); + + uint256 balanceAfterWithdraw = address(this).balance; + + assertEq(balanceAfterWithdraw, balanceBeforeWithdraw + 0.5 ether); + assertEq(weth.balanceOf(address(this)), 0.5 ether); + assertEq(weth.totalSupply(), 0.5 ether); + } + + function testFallbackDeposit(uint256 amount) public { + amount = bound(amount, 0, address(this).balance); + + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + + SafeTransferLib.safeTransferETH(address(weth), amount); + + assertEq(weth.balanceOf(address(this)), amount); + assertEq(weth.totalSupply(), amount); + } + + function testDeposit(uint256 amount) public { + amount = bound(amount, 0, address(this).balance); + + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + + weth.deposit{value: amount}(); + + assertEq(weth.balanceOf(address(this)), amount); + assertEq(weth.totalSupply(), amount); + } + + function testWithdraw(uint256 depositAmount, uint256 withdrawAmount) public { + depositAmount = bound(depositAmount, 0, address(this).balance); + withdrawAmount = bound(withdrawAmount, 0, depositAmount); + + weth.deposit{value: depositAmount}(); + + uint256 balanceBeforeWithdraw = address(this).balance; + + weth.withdraw(withdrawAmount); + + uint256 balanceAfterWithdraw = address(this).balance; + + assertEq(balanceAfterWithdraw, balanceBeforeWithdraw + withdrawAmount); + assertEq(weth.balanceOf(address(this)), depositAmount - withdrawAmount); + assertEq(weth.totalSupply(), depositAmount - withdrawAmount); + } + + receive() external payable {} +} + +contract WETHInvariants is DSTestPlus, DSInvariantTest { + WETHTester wethTester; + WETH weth; + + function setUp() public { + weth = new WETH(); + wethTester = new WETHTester{value: address(this).balance}(weth); + + addTargetContract(address(wethTester)); + } + + function invariantTotalSupplyEqualsBalance() public { + assertEq(address(weth).balance, weth.totalSupply()); + } +} + +contract WETHTester { + WETH weth; + + constructor(WETH _weth) payable { + weth = _weth; + } + + function deposit(uint256 amount) public { + weth.deposit{value: amount}(); + } + + function fallbackDeposit(uint256 amount) public { + SafeTransferLib.safeTransferETH(address(weth), amount); + } + + function withdraw(uint256 amount) public { + weth.withdraw(amount); + } + + receive() external payable {} +} diff --git a/lib/solmate/src/test/utils/DSInvariantTest.sol b/lib/solmate/src/test/utils/DSInvariantTest.sol new file mode 100644 index 0000000..820775c --- /dev/null +++ b/lib/solmate/src/test/utils/DSInvariantTest.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract DSInvariantTest { + address[] private targets; + + function targetContracts() public view virtual returns (address[] memory) { + require(targets.length > 0, "NO_TARGET_CONTRACTS"); + + return targets; + } + + function addTargetContract(address newTargetContract) internal virtual { + targets.push(newTargetContract); + } +} diff --git a/lib/solmate/src/test/utils/DSTestPlus.sol b/lib/solmate/src/test/utils/DSTestPlus.sol new file mode 100644 index 0000000..b56d4c9 --- /dev/null +++ b/lib/solmate/src/test/utils/DSTestPlus.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {DSTest} from "ds-test/test.sol"; + +import {Hevm} from "./Hevm.sol"; + +/// @notice Extended testing framework for DappTools projects. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/test/utils/DSTestPlus.sol) +contract DSTestPlus is DSTest { + Hevm internal constant hevm = Hevm(HEVM_ADDRESS); + + address internal constant DEAD_ADDRESS = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF; + + string private checkpointLabel; + uint256 private checkpointGasLeft = 1; // Start the slot warm. + + modifier brutalizeMemory(bytes memory brutalizeWith) { + /// @solidity memory-safe-assembly + assembly { + // Fill the 64 bytes of scratch space with the data. + pop( + staticcall( + gas(), // Pass along all the gas in the call. + 0x04, // Call the identity precompile address. + brutalizeWith, // Offset is the bytes' pointer. + 64, // Copy enough to only fill the scratch space. + 0, // Store the return value in the scratch space. + 64 // Scratch space is only 64 bytes in size, we don't want to write further. + ) + ) + + let size := add(mload(brutalizeWith), 32) // Add 32 to include the 32 byte length slot. + + // Fill the free memory pointer's destination with the data. + pop( + staticcall( + gas(), // Pass along all the gas in the call. + 0x04, // Call the identity precompile address. + brutalizeWith, // Offset is the bytes' pointer. + size, // We want to pass the length of the bytes. + mload(0x40), // Store the return value at the free memory pointer. + size // Since the precompile just returns its input, we reuse size. + ) + ) + } + + _; + } + + function startMeasuringGas(string memory label) internal virtual { + checkpointLabel = label; + + checkpointGasLeft = gasleft(); + } + + function stopMeasuringGas() internal virtual { + uint256 checkpointGasLeft2 = gasleft(); + + // Subtract 100 to account for the warm SLOAD in startMeasuringGas. + uint256 gasDelta = checkpointGasLeft - checkpointGasLeft2 - 100; + + emit log_named_uint(string(abi.encodePacked(checkpointLabel, " Gas")), gasDelta); + } + + function fail(string memory err) internal virtual { + emit log_named_string("Error", err); + fail(); + } + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertUint128Eq(uint128 a, uint128 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertUint64Eq(uint64 a, uint64 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertUint96Eq(uint96 a, uint96 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertUint32Eq(uint32 a, uint32 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertBoolEq(bool a, bool b) internal virtual { + b ? assertTrue(a) : assertFalse(a); + } + + function assertApproxEq( + uint256 a, + uint256 b, + uint256 maxDelta + ) internal virtual { + uint256 delta = a > b ? a - b : b - a; + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertRelApproxEq( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = ((a > b ? a - b : b - a) * 1e18) / b; + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertBytesEq(bytes memory a, bytes memory b) internal virtual { + if (keccak256(a) != keccak256(b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + + function assertUintArrayEq(uint256[] memory a, uint256[] memory b) internal virtual { + require(a.length == b.length, "LENGTH_MISMATCH"); + + for (uint256 i = 0; i < a.length; i++) { + assertEq(a[i], b[i]); + } + } + + function bound( + uint256 x, + uint256 min, + uint256 max + ) internal virtual returns (uint256 result) { + require(max >= min, "MAX_LESS_THAN_MIN"); + + uint256 size = max - min; + + if (size == 0) result = min; + else if (size == type(uint256).max) result = x; + else { + ++size; // Make max inclusive. + uint256 mod = x % size; + result = min + mod; + } + + emit log_named_uint("Bound Result", result); + } + + function min3( + uint256 a, + uint256 b, + uint256 c + ) internal pure returns (uint256) { + return a > b ? (b > c ? c : b) : (a > c ? c : a); + } + + function min2(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? b : a; + } +} diff --git a/lib/solmate/src/test/utils/Hevm.sol b/lib/solmate/src/test/utils/Hevm.sol new file mode 100644 index 0000000..8ca0eff --- /dev/null +++ b/lib/solmate/src/test/utils/Hevm.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +interface Hevm { + /// @notice Sets the block timestamp. + function warp(uint256) external; + + /// @notice Sets the block height. + function roll(uint256) external; + + /// @notice Sets the block base fee. + function fee(uint256) external; + + /// @notice Loads a storage slot from an address. + function load(address, bytes32) external returns (bytes32); + + /// @notice Stores a value to an address' storage slot. + function store( + address, + bytes32, + bytes32 + ) external; + + /// @notice Signs a digest with a private key, returns v r s. + function sign(uint256, bytes32) + external + returns ( + uint8, + bytes32, + bytes32 + ); + + /// @notice Gets address for a given private key. + function addr(uint256) external returns (address); + + /// @notice Performs a foreign function call via a terminal call. + function ffi(string[] calldata) external returns (bytes memory); + + /// @notice Sets the next call's msg.sender to be the input address. + function prank(address) external; + + /// @notice Sets all subsequent calls' msg.sender to be the input address until stopPrank is called. + function startPrank(address) external; + + /// @notice Sets the next call's msg.sender to be the input address and the tx.origin to be the second input. + function prank(address, address) external; + + /// @notice Sets all subsequent calls' msg.sender to be the input address and + /// sets tx.origin to be the second address inputted until stopPrank is called. + function startPrank(address, address) external; + + /// @notice Resets msg.sender to its original value before a prank. + function stopPrank() external; + + /// @notice Sets an address' balance. + function deal(address, uint256) external; + + /// @notice Sets an address' code. + function etch(address, bytes calldata) external; + + /// @notice Expects an error from the next call. + function expectRevert(bytes calldata) external; + + /// @notice Expects a revert from the next call. + function expectRevert(bytes4) external; + + /// @notice Record all storage reads and writes. + function record() external; + + /// @notice Gets all accessed reads and write slots from a recording session, for a given address. + function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes); + + /// @notice Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + /// @notice Call this function, then emit an event, then call a function. Internally after the call, we check + /// if logs were emitted in the expected order with the expected topics and data as specified by the booleans. + function expectEmit( + bool, + bool, + bool, + bool + ) external; + + /// @notice Mocks the behavior of a contract call, setting the input and output for a function. + /// @notice Calldata can either be strict or a partial match, e.g. if only passed + /// a selector to the expected calldata, then the entire function will be mocked. + function mockCall( + address, + bytes calldata, + bytes calldata + ) external; + + /// @notice Clears all mocked calls. + function clearMockedCalls() external; + + /// @notice Expect a call to an address with the specified calldata. + /// @notice Calldata can either be strict or a partial match. + function expectCall(address, bytes calldata) external; + + /// @notice Fetches the contract bytecode from its artifact file. + function getCode(string calldata) external returns (bytes memory); + + /// @notice Label an address in test traces. + function label(address addr, string calldata label) external; + + /// @notice When fuzzing, generate new inputs if the input conditional is not met. + function assume(bool) external; +} diff --git a/lib/solmate/src/test/utils/mocks/MockAuthChild.sol b/lib/solmate/src/test/utils/mocks/MockAuthChild.sol new file mode 100644 index 0000000..d2c3276 --- /dev/null +++ b/lib/solmate/src/test/utils/mocks/MockAuthChild.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Auth, Authority} from "../../../auth/Auth.sol"; + +contract MockAuthChild is Auth(msg.sender, Authority(address(0))) { + bool public flag; + + function updateFlag() public virtual requiresAuth { + flag = true; + } +} diff --git a/lib/solmate/src/test/utils/mocks/MockAuthority.sol b/lib/solmate/src/test/utils/mocks/MockAuthority.sol new file mode 100644 index 0000000..acb3689 --- /dev/null +++ b/lib/solmate/src/test/utils/mocks/MockAuthority.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Authority} from "../../../auth/Auth.sol"; + +contract MockAuthority is Authority { + bool immutable allowCalls; + + constructor(bool _allowCalls) { + allowCalls = _allowCalls; + } + + function canCall( + address, + address, + bytes4 + ) public view override returns (bool) { + return allowCalls; + } +} diff --git a/lib/solmate/src/test/utils/mocks/MockERC1155.sol b/lib/solmate/src/test/utils/mocks/MockERC1155.sol new file mode 100644 index 0000000..ede086d --- /dev/null +++ b/lib/solmate/src/test/utils/mocks/MockERC1155.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC1155} from "../../../tokens/ERC1155.sol"; + +contract MockERC1155 is ERC1155 { + function uri(uint256) public pure virtual override returns (string memory) {} + + function mint( + address to, + uint256 id, + uint256 amount, + bytes memory data + ) public virtual { + _mint(to, id, amount, data); + } + + function batchMint( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) public virtual { + _batchMint(to, ids, amounts, data); + } + + function burn( + address from, + uint256 id, + uint256 amount + ) public virtual { + _burn(from, id, amount); + } + + function batchBurn( + address from, + uint256[] memory ids, + uint256[] memory amounts + ) public virtual { + _batchBurn(from, ids, amounts); + } +} diff --git a/lib/solmate/src/test/utils/mocks/MockERC20.sol b/lib/solmate/src/test/utils/mocks/MockERC20.sol new file mode 100644 index 0000000..fbbaef5 --- /dev/null +++ b/lib/solmate/src/test/utils/mocks/MockERC20.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "../../../tokens/ERC20.sol"; + +contract MockERC20 is ERC20 { + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) ERC20(_name, _symbol, _decimals) {} + + function mint(address to, uint256 value) public virtual { + _mint(to, value); + } + + function burn(address from, uint256 value) public virtual { + _burn(from, value); + } +} diff --git a/lib/solmate/src/test/utils/mocks/MockERC4626.sol b/lib/solmate/src/test/utils/mocks/MockERC4626.sol new file mode 100644 index 0000000..edc7d5f --- /dev/null +++ b/lib/solmate/src/test/utils/mocks/MockERC4626.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "../../../tokens/ERC20.sol"; +import {ERC4626} from "../../../mixins/ERC4626.sol"; + +contract MockERC4626 is ERC4626 { + uint256 public beforeWithdrawHookCalledCounter = 0; + uint256 public afterDepositHookCalledCounter = 0; + + constructor( + ERC20 _underlying, + string memory _name, + string memory _symbol + ) ERC4626(_underlying, _name, _symbol) {} + + function totalAssets() public view override returns (uint256) { + return asset.balanceOf(address(this)); + } + + function beforeWithdraw(uint256, uint256) internal override { + beforeWithdrawHookCalledCounter++; + } + + function afterDeposit(uint256, uint256) internal override { + afterDepositHookCalledCounter++; + } +} diff --git a/lib/solmate/src/test/utils/mocks/MockERC6909.sol b/lib/solmate/src/test/utils/mocks/MockERC6909.sol new file mode 100644 index 0000000..5f7eabe --- /dev/null +++ b/lib/solmate/src/test/utils/mocks/MockERC6909.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import {ERC6909} from "../../../tokens/ERC6909.sol"; + +contract MockERC6909 is ERC6909 { + function mint( + address receiver, + uint256 id, + uint256 amount + ) public virtual { + _mint(receiver, id, amount); + } + + function burn( + address sender, + uint256 id, + uint256 amount + ) public virtual { + _burn(sender, id, amount); + } +} diff --git a/lib/solmate/src/test/utils/mocks/MockERC721.sol b/lib/solmate/src/test/utils/mocks/MockERC721.sol new file mode 100644 index 0000000..51227c0 --- /dev/null +++ b/lib/solmate/src/test/utils/mocks/MockERC721.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC721} from "../../../tokens/ERC721.sol"; + +contract MockERC721 is ERC721 { + constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) {} + + function tokenURI(uint256) public pure virtual override returns (string memory) {} + + function mint(address to, uint256 tokenId) public virtual { + _mint(to, tokenId); + } + + function burn(uint256 tokenId) public virtual { + _burn(tokenId); + } + + function safeMint(address to, uint256 tokenId) public virtual { + _safeMint(to, tokenId); + } + + function safeMint( + address to, + uint256 tokenId, + bytes memory data + ) public virtual { + _safeMint(to, tokenId, data); + } +} diff --git a/lib/solmate/src/test/utils/mocks/MockOwned.sol b/lib/solmate/src/test/utils/mocks/MockOwned.sol new file mode 100644 index 0000000..52ef918 --- /dev/null +++ b/lib/solmate/src/test/utils/mocks/MockOwned.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Owned} from "../../../auth/Owned.sol"; + +contract MockOwned is Owned(msg.sender) { + bool public flag; + + function updateFlag() public virtual onlyOwner { + flag = true; + } +} diff --git a/lib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sol b/lib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sol new file mode 100644 index 0000000..23f4633 --- /dev/null +++ b/lib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract MissingReturnToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "MissingReturnToken"; + + string public constant symbol = "MRT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + } + + function transfer(address to, uint256 amount) public virtual { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + } +} diff --git a/lib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sol b/lib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sol new file mode 100644 index 0000000..8139efe --- /dev/null +++ b/lib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsFalseToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsFalseToken"; + + string public constant symbol = "RFT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address, uint256) public virtual returns (bool) { + return false; + } + + function transfer(address, uint256) public virtual returns (bool) { + return false; + } + + function transferFrom( + address, + address, + uint256 + ) public virtual returns (bool) { + return false; + } +} diff --git a/lib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sol b/lib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sol new file mode 100644 index 0000000..77c9575 --- /dev/null +++ b/lib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsGarbageToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsGarbageToken"; + + string public constant symbol = "RGT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + MOCK STORAGE + //////////////////////////////////////////////////////////////*/ + + bytes garbage; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + bytes memory _garbage = garbage; + + assembly { + return(add(_garbage, 32), mload(_garbage)) + } + } + + function transfer(address to, uint256 amount) public virtual { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + + bytes memory _garbage = garbage; + + assembly { + return(add(_garbage, 32), mload(_garbage)) + } + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + + bytes memory _garbage = garbage; + + assembly { + return(add(_garbage, 32), mload(_garbage)) + } + } + + /*/////////////////////////////////////////////////////////////// + MOCK LOGIC + //////////////////////////////////////////////////////////////*/ + + function setGarbage(bytes memory _garbage) public virtual { + garbage = _garbage; + } +} diff --git a/lib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sol b/lib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sol new file mode 100644 index 0000000..69947c3 --- /dev/null +++ b/lib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsTooLittleToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsTooLittleToken"; + + string public constant symbol = "RTLT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address, uint256) public virtual { + assembly { + mstore(0, 0x0100000000000000000000000000000000000000000000000000000000000000) + return(0, 8) + } + } + + function transfer(address, uint256) public virtual { + assembly { + mstore(0, 0x0100000000000000000000000000000000000000000000000000000000000000) + return(0, 8) + } + } + + function transferFrom( + address, + address, + uint256 + ) public virtual { + assembly { + mstore(0, 0x0100000000000000000000000000000000000000000000000000000000000000) + return(0, 8) + } + } +} diff --git a/lib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sol b/lib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sol new file mode 100644 index 0000000..8774cbb --- /dev/null +++ b/lib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsTooMuchToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsTooMuchToken"; + + string public constant symbol = "RTMT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + assembly { + mstore(0, 1) + return(0, 4096) + } + } + + function transfer(address to, uint256 amount) public virtual { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + + assembly { + mstore(0, 1) + return(0, 4096) + } + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + + assembly { + mstore(0, 1) + return(0, 4096) + } + } +} diff --git a/lib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sol b/lib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sol new file mode 100644 index 0000000..ac980f8 --- /dev/null +++ b/lib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsTwoToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsFalseToken"; + + string public constant symbol = "RTT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address, uint256) public virtual returns (uint256) { + return 2; + } + + function transfer(address, uint256) public virtual returns (uint256) { + return 2; + } + + function transferFrom( + address, + address, + uint256 + ) public virtual returns (uint256) { + return 2; + } +} diff --git a/lib/solmate/src/test/utils/weird-tokens/RevertingToken.sol b/lib/solmate/src/test/utils/weird-tokens/RevertingToken.sol new file mode 100644 index 0000000..48ac1fa --- /dev/null +++ b/lib/solmate/src/test/utils/weird-tokens/RevertingToken.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract RevertingToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "RevertingToken"; + + string public constant symbol = "RT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address, uint256) public virtual { + revert(); + } + + function transfer(address, uint256) public virtual { + revert(); + } + + function transferFrom( + address, + address, + uint256 + ) public virtual { + revert(); + } +} diff --git a/lib/solmate/src/tokens/ERC1155.sol b/lib/solmate/src/tokens/ERC1155.sol new file mode 100644 index 0000000..cff0f02 --- /dev/null +++ b/lib/solmate/src/tokens/ERC1155.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Minimalist and gas efficient standard ERC1155 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) +abstract contract ERC1155 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event TransferSingle( + address indexed operator, + address indexed from, + address indexed to, + uint256 id, + uint256 amount + ); + + event TransferBatch( + address indexed operator, + address indexed from, + address indexed to, + uint256[] ids, + uint256[] amounts + ); + + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + event URI(string value, uint256 indexed id); + + /*////////////////////////////////////////////////////////////// + ERC1155 STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => mapping(uint256 => uint256)) public balanceOf; + + mapping(address => mapping(address => bool)) public isApprovedForAll; + + /*////////////////////////////////////////////////////////////// + METADATA LOGIC + //////////////////////////////////////////////////////////////*/ + + function uri(uint256 id) public view virtual returns (string memory); + + /*////////////////////////////////////////////////////////////// + ERC1155 LOGIC + //////////////////////////////////////////////////////////////*/ + + function setApprovalForAll(address operator, bool approved) public virtual { + isApprovedForAll[msg.sender][operator] = approved; + + emit ApprovalForAll(msg.sender, operator, approved); + } + + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes calldata data + ) public virtual { + require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); + + balanceOf[from][id] -= amount; + balanceOf[to][id] += amount; + + emit TransferSingle(msg.sender, from, to, id, amount); + + require( + to.code.length == 0 + ? to != address(0) + : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) == + ERC1155TokenReceiver.onERC1155Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function safeBatchTransferFrom( + address from, + address to, + uint256[] calldata ids, + uint256[] calldata amounts, + bytes calldata data + ) public virtual { + require(ids.length == amounts.length, "LENGTH_MISMATCH"); + + require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); + + // Storing these outside the loop saves ~15 gas per iteration. + uint256 id; + uint256 amount; + + for (uint256 i = 0; i < ids.length; ) { + id = ids[i]; + amount = amounts[i]; + + balanceOf[from][id] -= amount; + balanceOf[to][id] += amount; + + // An array can't have a total length + // larger than the max uint256 value. + unchecked { + ++i; + } + } + + emit TransferBatch(msg.sender, from, to, ids, amounts); + + require( + to.code.length == 0 + ? to != address(0) + : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) == + ERC1155TokenReceiver.onERC1155BatchReceived.selector, + "UNSAFE_RECIPIENT" + ); + } + + function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) + public + view + virtual + returns (uint256[] memory balances) + { + require(owners.length == ids.length, "LENGTH_MISMATCH"); + + balances = new uint256[](owners.length); + + // Unchecked because the only math done is incrementing + // the array index counter which cannot possibly overflow. + unchecked { + for (uint256 i = 0; i < owners.length; ++i) { + balances[i] = balanceOf[owners[i]][ids[i]]; + } + } + } + + /*////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return + interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 + interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155 + interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint( + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + balanceOf[to][id] += amount; + + emit TransferSingle(msg.sender, address(0), to, id, amount); + + require( + to.code.length == 0 + ? to != address(0) + : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) == + ERC1155TokenReceiver.onERC1155Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _batchMint( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + uint256 idsLength = ids.length; // Saves MLOADs. + + require(idsLength == amounts.length, "LENGTH_MISMATCH"); + + for (uint256 i = 0; i < idsLength; ) { + balanceOf[to][ids[i]] += amounts[i]; + + // An array can't have a total length + // larger than the max uint256 value. + unchecked { + ++i; + } + } + + emit TransferBatch(msg.sender, address(0), to, ids, amounts); + + require( + to.code.length == 0 + ? to != address(0) + : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) == + ERC1155TokenReceiver.onERC1155BatchReceived.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _batchBurn( + address from, + uint256[] memory ids, + uint256[] memory amounts + ) internal virtual { + uint256 idsLength = ids.length; // Saves MLOADs. + + require(idsLength == amounts.length, "LENGTH_MISMATCH"); + + for (uint256 i = 0; i < idsLength; ) { + balanceOf[from][ids[i]] -= amounts[i]; + + // An array can't have a total length + // larger than the max uint256 value. + unchecked { + ++i; + } + } + + emit TransferBatch(msg.sender, from, address(0), ids, amounts); + } + + function _burn( + address from, + uint256 id, + uint256 amount + ) internal virtual { + balanceOf[from][id] -= amount; + + emit TransferSingle(msg.sender, from, address(0), id, amount); + } +} + +/// @notice A generic interface for a contract which properly accepts ERC1155 tokens. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) +abstract contract ERC1155TokenReceiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes calldata + ) external virtual returns (bytes4) { + return ERC1155TokenReceiver.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] calldata, + uint256[] calldata, + bytes calldata + ) external virtual returns (bytes4) { + return ERC1155TokenReceiver.onERC1155BatchReceived.selector; + } +} diff --git a/lib/solmate/src/tokens/ERC20.sol b/lib/solmate/src/tokens/ERC20.sol new file mode 100644 index 0000000..9657044 --- /dev/null +++ b/lib/solmate/src/tokens/ERC20.sol @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) +/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) +/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. +abstract contract ERC20 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public name; + + string public symbol; + + uint8 public immutable decimals; + + /*////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*////////////////////////////////////////////////////////////// + EIP-2612 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 internal immutable INITIAL_CHAIN_ID; + + bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; + + mapping(address => uint256) public nonces; + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) { + name = _name; + symbol = _symbol; + decimals = _decimals; + + INITIAL_CHAIN_ID = block.chainid; + INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); + } + + /*////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual returns (bool) { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + return true; + } + + function transfer(address to, uint256 amount) public virtual returns (bool) { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + + return true; + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual returns (bool) { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + + return true; + } + + /*////////////////////////////////////////////////////////////// + EIP-2612 LOGIC + //////////////////////////////////////////////////////////////*/ + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); + + // Unchecked because the only math done is incrementing + // the owner's nonce which cannot realistically overflow. + unchecked { + address recoveredAddress = ecrecover( + keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR(), + keccak256( + abi.encode( + keccak256( + "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" + ), + owner, + spender, + value, + nonces[owner]++, + deadline + ) + ) + ) + ), + v, + r, + s + ); + + require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); + + allowance[recoveredAddress][spender] = value; + } + + emit Approval(owner, spender, value); + } + + function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { + return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); + } + + function computeDomainSeparator() internal view virtual returns (bytes32) { + return + keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes(name)), + keccak256("1"), + block.chainid, + address(this) + ) + ); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 amount) internal virtual { + totalSupply += amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(address(0), to, amount); + } + + function _burn(address from, uint256 amount) internal virtual { + balanceOf[from] -= amount; + + // Cannot underflow because a user's balance + // will never be larger than the total supply. + unchecked { + totalSupply -= amount; + } + + emit Transfer(from, address(0), amount); + } +} diff --git a/lib/solmate/src/tokens/ERC6909.sol b/lib/solmate/src/tokens/ERC6909.sol new file mode 100644 index 0000000..e963169 --- /dev/null +++ b/lib/solmate/src/tokens/ERC6909.sol @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/// @notice Minimalist and gas efficient standard ERC6909 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC6909.sol) +abstract contract ERC6909 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event OperatorSet(address indexed owner, address indexed operator, bool approved); + + event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount); + + event Transfer(address caller, address indexed from, address indexed to, uint256 indexed id, uint256 amount); + + /*////////////////////////////////////////////////////////////// + ERC6909 STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => uint256) public totalSupply; + + mapping(address => mapping(address => bool)) public isOperator; + + mapping(address => mapping(uint256 => uint256)) public balanceOf; + + mapping(address => mapping(address => mapping(uint256 => uint256))) public allowance; + + /*////////////////////////////////////////////////////////////// + ERC6909 LOGIC + //////////////////////////////////////////////////////////////*/ + + function transfer( + address receiver, + uint256 id, + uint256 amount + ) public virtual returns (bool) { + balanceOf[msg.sender][id] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[receiver][id] += amount; + } + + emit Transfer(msg.sender, msg.sender, receiver, id, amount); + + return true; + } + + function transferFrom( + address sender, + address receiver, + uint256 id, + uint256 amount + ) public virtual returns (bool) { + if (msg.sender != sender && !isOperator[sender][msg.sender]) { + uint256 allowed = allowance[sender][msg.sender][id]; + if (allowed != type(uint256).max) allowance[sender][msg.sender][id] = allowed - amount; + } + + balanceOf[sender][id] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[receiver][id] += amount; + } + + emit Transfer(msg.sender, sender, receiver, id, amount); + + return true; + } + + function approve( + address spender, + uint256 id, + uint256 amount + ) public virtual returns (bool) { + allowance[msg.sender][spender][id] = amount; + + emit Approval(msg.sender, spender, id, amount); + + return true; + } + + function setOperator(address operator, bool approved) public virtual returns (bool) { + isOperator[msg.sender][operator] = approved; + + emit OperatorSet(msg.sender, operator, approved); + + return true; + } + + /*////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return + interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 + interfaceId == 0xb2e69f8a; // ERC165 Interface ID for ERC6909 + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint( + address receiver, + uint256 id, + uint256 amount + ) internal virtual { + totalSupply[id] += amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[receiver][id] += amount; + } + + emit Transfer(msg.sender, address(0), receiver, id, amount); + } + + function _burn( + address sender, + uint256 id, + uint256 amount + ) internal virtual { + balanceOf[sender][id] -= amount; + + // Cannot underflow because a user's balance + // will never be larger than the total supply. + unchecked { + totalSupply[id] -= amount; + } + + emit Transfer(msg.sender, sender, address(0), id, amount); + } +} diff --git a/lib/solmate/src/tokens/ERC721.sol b/lib/solmate/src/tokens/ERC721.sol new file mode 100644 index 0000000..b47f271 --- /dev/null +++ b/lib/solmate/src/tokens/ERC721.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Modern, minimalist, and gas efficient ERC-721 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) +abstract contract ERC721 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 indexed id); + + event Approval(address indexed owner, address indexed spender, uint256 indexed id); + + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /*////////////////////////////////////////////////////////////// + METADATA STORAGE/LOGIC + //////////////////////////////////////////////////////////////*/ + + string public name; + + string public symbol; + + function tokenURI(uint256 id) public view virtual returns (string memory); + + /*////////////////////////////////////////////////////////////// + ERC721 BALANCE/OWNER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) internal _ownerOf; + + mapping(address => uint256) internal _balanceOf; + + function ownerOf(uint256 id) public view virtual returns (address owner) { + require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); + } + + function balanceOf(address owner) public view virtual returns (uint256) { + require(owner != address(0), "ZERO_ADDRESS"); + + return _balanceOf[owner]; + } + + /*////////////////////////////////////////////////////////////// + ERC721 APPROVAL STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) public getApproved; + + mapping(address => mapping(address => bool)) public isApprovedForAll; + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(string memory _name, string memory _symbol) { + name = _name; + symbol = _symbol; + } + + /*////////////////////////////////////////////////////////////// + ERC721 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 id) public virtual { + address owner = _ownerOf[id]; + + require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); + + getApproved[id] = spender; + + emit Approval(owner, spender, id); + } + + function setApprovalForAll(address operator, bool approved) public virtual { + isApprovedForAll[msg.sender][operator] = approved; + + emit ApprovalForAll(msg.sender, operator, approved); + } + + function transferFrom( + address from, + address to, + uint256 id + ) public virtual { + require(from == _ownerOf[id], "WRONG_FROM"); + + require(to != address(0), "INVALID_RECIPIENT"); + + require( + msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], + "NOT_AUTHORIZED" + ); + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + unchecked { + _balanceOf[from]--; + + _balanceOf[to]++; + } + + _ownerOf[id] = to; + + delete getApproved[id]; + + emit Transfer(from, to, id); + } + + function safeTransferFrom( + address from, + address to, + uint256 id + ) public virtual { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function safeTransferFrom( + address from, + address to, + uint256 id, + bytes calldata data + ) public virtual { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + /*////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return + interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 + interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 + interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 id) internal virtual { + require(to != address(0), "INVALID_RECIPIENT"); + + require(_ownerOf[id] == address(0), "ALREADY_MINTED"); + + // Counter overflow is incredibly unrealistic. + unchecked { + _balanceOf[to]++; + } + + _ownerOf[id] = to; + + emit Transfer(address(0), to, id); + } + + function _burn(uint256 id) internal virtual { + address owner = _ownerOf[id]; + + require(owner != address(0), "NOT_MINTED"); + + // Ownership check above ensures no underflow. + unchecked { + _balanceOf[owner]--; + } + + delete _ownerOf[id]; + + delete getApproved[id]; + + emit Transfer(owner, address(0), id); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL SAFE MINT LOGIC + //////////////////////////////////////////////////////////////*/ + + function _safeMint(address to, uint256 id) internal virtual { + _mint(to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _safeMint( + address to, + uint256 id, + bytes memory data + ) internal virtual { + _mint(to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } +} + +/// @notice A generic interface for a contract which properly accepts ERC721 tokens. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) +abstract contract ERC721TokenReceiver { + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) external virtual returns (bytes4) { + return ERC721TokenReceiver.onERC721Received.selector; + } +} diff --git a/lib/solmate/src/tokens/WETH.sol b/lib/solmate/src/tokens/WETH.sol new file mode 100644 index 0000000..ddf9647 --- /dev/null +++ b/lib/solmate/src/tokens/WETH.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "./ERC20.sol"; + +import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; + +/// @notice Minimalist and modern Wrapped Ether implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/WETH.sol) +/// @author Inspired by WETH9 (https://github.com/dapphub/ds-weth/blob/master/src/weth9.sol) +contract WETH is ERC20("Wrapped Ether", "WETH", 18) { + using SafeTransferLib for address; + + event Deposit(address indexed from, uint256 amount); + + event Withdrawal(address indexed to, uint256 amount); + + function deposit() public payable virtual { + _mint(msg.sender, msg.value); + + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 amount) public virtual { + _burn(msg.sender, amount); + + emit Withdrawal(msg.sender, amount); + + msg.sender.safeTransferETH(amount); + } + + receive() external payable virtual { + deposit(); + } +} diff --git a/lib/solmate/src/utils/Bytes32AddressLib.sol b/lib/solmate/src/utils/Bytes32AddressLib.sol new file mode 100644 index 0000000..448fb75 --- /dev/null +++ b/lib/solmate/src/utils/Bytes32AddressLib.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Library for converting between addresses and bytes32 values. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Bytes32AddressLib.sol) +library Bytes32AddressLib { + function fromLast20Bytes(bytes32 bytesValue) internal pure returns (address) { + return address(uint160(uint256(bytesValue))); + } + + function fillLast12Bytes(address addressValue) internal pure returns (bytes32) { + return bytes32(bytes20(addressValue)); + } +} diff --git a/lib/solmate/src/utils/CREATE3.sol b/lib/solmate/src/utils/CREATE3.sol new file mode 100644 index 0000000..0d5b341 --- /dev/null +++ b/lib/solmate/src/utils/CREATE3.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Bytes32AddressLib} from "./Bytes32AddressLib.sol"; + +/// @notice Deploy to deterministic addresses without an initcode factor. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/CREATE3.sol) +/// @author Modified from 0xSequence (https://github.com/0xSequence/create3/blob/master/contracts/Create3.sol) +library CREATE3 { + using Bytes32AddressLib for bytes32; + + //--------------------------------------------------------------------------------// + // Opcode | Opcode + Arguments | Description | Stack View // + //--------------------------------------------------------------------------------// + // 0x36 | 0x36 | CALLDATASIZE | size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 0 size // + // 0x37 | 0x37 | CALLDATACOPY | // + // 0x36 | 0x36 | CALLDATASIZE | size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 size // + // 0x34 | 0x34 | CALLVALUE | value 0 size // + // 0xf0 | 0xf0 | CREATE | newContract // + //--------------------------------------------------------------------------------// + // Opcode | Opcode + Arguments | Description | Stack View // + //--------------------------------------------------------------------------------// + // 0x67 | 0x67XXXXXXXXXXXXXXXX | PUSH8 bytecode | bytecode // + // 0x3d | 0x3d | RETURNDATASIZE | 0 bytecode // + // 0x52 | 0x52 | MSTORE | // + // 0x60 | 0x6008 | PUSH1 08 | 8 // + // 0x60 | 0x6018 | PUSH1 18 | 24 8 // + // 0xf3 | 0xf3 | RETURN | // + //--------------------------------------------------------------------------------// + bytes internal constant PROXY_BYTECODE = hex"67_36_3d_3d_37_36_3d_34_f0_3d_52_60_08_60_18_f3"; + + bytes32 internal constant PROXY_BYTECODE_HASH = keccak256(PROXY_BYTECODE); + + function deploy( + bytes32 salt, + bytes memory creationCode, + uint256 value + ) internal returns (address deployed) { + bytes memory proxyChildBytecode = PROXY_BYTECODE; + + address proxy; + /// @solidity memory-safe-assembly + assembly { + // Deploy a new contract with our pre-made bytecode via CREATE2. + // We start 32 bytes into the code to avoid copying the byte length. + proxy := create2(0, add(proxyChildBytecode, 32), mload(proxyChildBytecode), salt) + } + require(proxy != address(0), "DEPLOYMENT_FAILED"); + + deployed = getDeployed(salt); + (bool success, ) = proxy.call{value: value}(creationCode); + require(success && deployed.code.length != 0, "INITIALIZATION_FAILED"); + } + + function getDeployed(bytes32 salt) internal view returns (address) { + address proxy = keccak256( + abi.encodePacked( + // Prefix: + bytes1(0xFF), + // Creator: + address(this), + // Salt: + salt, + // Bytecode hash: + PROXY_BYTECODE_HASH + ) + ).fromLast20Bytes(); + + return + keccak256( + abi.encodePacked( + // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + hex"d6_94", + proxy, + hex"01" // Nonce of the proxy contract (1) + ) + ).fromLast20Bytes(); + } +} diff --git a/lib/solmate/src/utils/FixedPointMathLib.sol b/lib/solmate/src/utils/FixedPointMathLib.sol new file mode 100644 index 0000000..6887722 --- /dev/null +++ b/lib/solmate/src/utils/FixedPointMathLib.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Arithmetic library with operations for fixed-point numbers. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) +/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) +library FixedPointMathLib { + /*////////////////////////////////////////////////////////////// + SIMPLIFIED FIXED POINT OPERATIONS + //////////////////////////////////////////////////////////////*/ + + uint256 internal constant MAX_UINT256 = 2**256 - 1; + + uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. + + function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { + return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. + } + + function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { + return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. + } + + function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { + return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. + } + + function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { + return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. + } + + /*////////////////////////////////////////////////////////////// + LOW LEVEL FIXED POINT OPERATIONS + //////////////////////////////////////////////////////////////*/ + + function mulDivDown( + uint256 x, + uint256 y, + uint256 denominator + ) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) + if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { + revert(0, 0) + } + + // Divide x * y by the denominator. + z := div(mul(x, y), denominator) + } + } + + function mulDivUp( + uint256 x, + uint256 y, + uint256 denominator + ) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) + if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { + revert(0, 0) + } + + // If x * y modulo the denominator is strictly greater than 0, + // 1 is added to round up the division of x * y by the denominator. + z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) + } + } + + function rpow( + uint256 x, + uint256 n, + uint256 scalar + ) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + switch x + case 0 { + switch n + case 0 { + // 0 ** 0 = 1 + z := scalar + } + default { + // 0 ** n = 0 + z := 0 + } + } + default { + switch mod(n, 2) + case 0 { + // If n is even, store scalar in z for now. + z := scalar + } + default { + // If n is odd, store x in z for now. + z := x + } + + // Shifting right by 1 is like dividing by 2. + let half := shr(1, scalar) + + for { + // Shift n right by 1 before looping to halve it. + n := shr(1, n) + } n { + // Shift n right by 1 each iteration to halve it. + n := shr(1, n) + } { + // Revert immediately if x ** 2 would overflow. + // Equivalent to iszero(eq(div(xx, x), x)) here. + if shr(128, x) { + revert(0, 0) + } + + // Store x squared. + let xx := mul(x, x) + + // Round to the nearest number. + let xxRound := add(xx, half) + + // Revert if xx + half overflowed. + if lt(xxRound, xx) { + revert(0, 0) + } + + // Set x to scaled xxRound. + x := div(xxRound, scalar) + + // If n is even: + if mod(n, 2) { + // Compute z * x. + let zx := mul(z, x) + + // If z * x overflowed: + if iszero(eq(div(zx, x), z)) { + // Revert if x is non-zero. + if iszero(iszero(x)) { + revert(0, 0) + } + } + + // Round to the nearest number. + let zxRound := add(zx, half) + + // Revert if zx + half overflowed. + if lt(zxRound, zx) { + revert(0, 0) + } + + // Return properly scaled zxRound. + z := div(zxRound, scalar) + } + } + } + } + } + + /*////////////////////////////////////////////////////////////// + GENERAL NUMBER UTILITIES + //////////////////////////////////////////////////////////////*/ + + function sqrt(uint256 x) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + let y := x // We start y at x, which will help us make our initial estimate. + + z := 181 // The "correct" value is 1, but this saves a multiplication later. + + // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad + // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. + + // We check y >= 2^(k + 8) but shift right by k bits + // each branch to ensure that if x >= 256, then y >= 256. + if iszero(lt(y, 0x10000000000000000000000000000000000)) { + y := shr(128, y) + z := shl(64, z) + } + if iszero(lt(y, 0x1000000000000000000)) { + y := shr(64, y) + z := shl(32, z) + } + if iszero(lt(y, 0x10000000000)) { + y := shr(32, y) + z := shl(16, z) + } + if iszero(lt(y, 0x1000000)) { + y := shr(16, y) + z := shl(8, z) + } + + // Goal was to get z*z*y within a small factor of x. More iterations could + // get y in a tighter range. Currently, we will have y in [256, 256*2^16). + // We ensured y >= 256 so that the relative difference between y and y+1 is small. + // That's not possible if x < 256 but we can just verify those cases exhaustively. + + // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. + // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. + // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. + + // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range + // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. + + // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate + // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. + + // There is no overflow risk here since y < 2^136 after the first branch above. + z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. + + // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + + // If x+1 is a perfect square, the Babylonian method cycles between + // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. + // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division + // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. + // If you don't care whether the floor or ceil square root is returned, you can remove this statement. + z := sub(z, lt(div(x, z), z)) + } + } + + function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Mod x by y. Note this will return + // 0 instead of reverting if y is zero. + z := mod(x, y) + } + } + + function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + // Divide x by y. Note this will return + // 0 instead of reverting if y is zero. + r := div(x, y) + } + } + + function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Add 1 to x * y if x % y > 0. Note this will + // return 0 instead of reverting if y is zero. + z := add(gt(mod(x, y), 0), div(x, y)) + } + } +} diff --git a/lib/solmate/src/utils/LibString.sol b/lib/solmate/src/utils/LibString.sol new file mode 100644 index 0000000..97c89e0 --- /dev/null +++ b/lib/solmate/src/utils/LibString.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/// @notice Efficient library for creating string representations of integers. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) +/// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibString.sol) +library LibString { + function toString(int256 value) internal pure returns (string memory str) { + if (value >= 0) return toString(uint256(value)); + + unchecked { + str = toString(uint256(-value)); + + /// @solidity memory-safe-assembly + assembly { + // Note: This is only safe because we over-allocate memory + // and write the string from right to left in toString(uint256), + // and thus can be sure that sub(str, 1) is an unused memory location. + + let length := mload(str) // Load the string length. + // Put the - character at the start of the string contents. + mstore(str, 45) // 45 is the ASCII code for the - character. + str := sub(str, 1) // Move back the string pointer by a byte. + mstore(str, add(length, 1)) // Update the string length. + } + } + } + + function toString(uint256 value) internal pure returns (string memory str) { + /// @solidity memory-safe-assembly + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), but we allocate 160 bytes + // to keep the free memory pointer word aligned. We'll need 1 word for the length, 1 word for the + // trailing zeros padding, and 3 other words for a max of 78 digits. In total: 5 * 32 = 160 bytes. + let newFreeMemoryPointer := add(mload(0x40), 160) + + // Update the free memory pointer to avoid overriding our string. + mstore(0x40, newFreeMemoryPointer) + + // Assign str to the end of the zone of newly allocated memory. + str := sub(newFreeMemoryPointer, 32) + + // Clean the last word of memory it may not be overwritten. + mstore(str, 0) + + // Cache the end of the memory to calculate the length later. + let end := str + + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // prettier-ignore + for { let temp := value } 1 {} { + // Move the pointer 1 byte to the left. + str := sub(str, 1) + + // Write the character to the pointer. + // The ASCII index of the '0' character is 48. + mstore8(str, add(48, mod(temp, 10))) + + // Keep dividing temp until zero. + temp := div(temp, 10) + + // prettier-ignore + if iszero(temp) { break } + } + + // Compute and cache the final total length of the string. + let length := sub(end, str) + + // Move the pointer 32 bytes leftwards to make room for the length. + str := sub(str, 32) + + // Store the string's length at the start of memory allocated for our string. + mstore(str, length) + } + } +} diff --git a/lib/solmate/src/utils/MerkleProofLib.sol b/lib/solmate/src/utils/MerkleProofLib.sol new file mode 100644 index 0000000..8fd7cbd --- /dev/null +++ b/lib/solmate/src/utils/MerkleProofLib.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/// @notice Gas optimized merkle proof verification library. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) +/// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) +library MerkleProofLib { + function verify( + bytes32[] calldata proof, + bytes32 root, + bytes32 leaf + ) internal pure returns (bool isValid) { + /// @solidity memory-safe-assembly + assembly { + if proof.length { + // Left shifting by 5 is like multiplying by 32. + let end := add(proof.offset, shl(5, proof.length)) + + // Initialize offset to the offset of the proof in calldata. + let offset := proof.offset + + // Iterate over proof elements to compute root hash. + // prettier-ignore + for {} 1 {} { + // Slot where the leaf should be put in scratch space. If + // leaf > calldataload(offset): slot 32, otherwise: slot 0. + let leafSlot := shl(5, gt(leaf, calldataload(offset))) + + // Store elements to hash contiguously in scratch space. + // The xor puts calldataload(offset) in whichever slot leaf + // is not occupying, so 0 if leafSlot is 32, and 32 otherwise. + mstore(leafSlot, leaf) + mstore(xor(leafSlot, 32), calldataload(offset)) + + // Reuse leaf to store the hash to reduce stack operations. + leaf := keccak256(0, 64) // Hash both slots of scratch space. + + offset := add(offset, 32) // Shift 1 word per cycle. + + // prettier-ignore + if iszero(lt(offset, end)) { break } + } + } + + isValid := eq(leaf, root) // The proof is valid if the roots match. + } + } +} diff --git a/lib/solmate/src/utils/ReentrancyGuard.sol b/lib/solmate/src/utils/ReentrancyGuard.sol new file mode 100644 index 0000000..1453e24 --- /dev/null +++ b/lib/solmate/src/utils/ReentrancyGuard.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Gas optimized reentrancy protection for smart contracts. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol) +abstract contract ReentrancyGuard { + uint256 private locked = 1; + + modifier nonReentrant() virtual { + require(locked == 1, "REENTRANCY"); + + locked = 2; + + _; + + locked = 1; + } +} diff --git a/lib/solmate/src/utils/SSTORE2.sol b/lib/solmate/src/utils/SSTORE2.sol new file mode 100644 index 0000000..23d6980 --- /dev/null +++ b/lib/solmate/src/utils/SSTORE2.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Read and write to persistent storage at a fraction of the cost. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol) +/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol) +library SSTORE2 { + uint256 internal constant DATA_OFFSET = 1; // We skip the first byte as it's a STOP opcode to ensure the contract can't be called. + + /*////////////////////////////////////////////////////////////// + WRITE LOGIC + //////////////////////////////////////////////////////////////*/ + + function write(bytes memory data) internal returns (address pointer) { + // Prefix the bytecode with a STOP opcode to ensure it cannot be called. + bytes memory runtimeCode = abi.encodePacked(hex"00", data); + + bytes memory creationCode = abi.encodePacked( + //---------------------------------------------------------------------------------------------------------------// + // Opcode | Opcode + Arguments | Description | Stack View // + //---------------------------------------------------------------------------------------------------------------// + // 0x60 | 0x600B | PUSH1 11 | codeOffset // + // 0x59 | 0x59 | MSIZE | 0 codeOffset // + // 0x81 | 0x81 | DUP2 | codeOffset 0 codeOffset // + // 0x38 | 0x38 | CODESIZE | codeSize codeOffset 0 codeOffset // + // 0x03 | 0x03 | SUB | (codeSize - codeOffset) 0 codeOffset // + // 0x80 | 0x80 | DUP | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset // + // 0x92 | 0x92 | SWAP3 | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) // + // 0x59 | 0x59 | MSIZE | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) // + // 0x39 | 0x39 | CODECOPY | 0 (codeSize - codeOffset) // + // 0xf3 | 0xf3 | RETURN | // + //---------------------------------------------------------------------------------------------------------------// + hex"60_0B_59_81_38_03_80_92_59_39_F3", // Returns all code in the contract except for the first 11 (0B in hex) bytes. + runtimeCode // The bytecode we want the contract to have after deployment. Capped at 1 byte less than the code size limit. + ); + + /// @solidity memory-safe-assembly + assembly { + // Deploy a new contract with the generated creation code. + // We start 32 bytes into the code to avoid copying the byte length. + pointer := create(0, add(creationCode, 32), mload(creationCode)) + } + + require(pointer != address(0), "DEPLOYMENT_FAILED"); + } + + /*////////////////////////////////////////////////////////////// + READ LOGIC + //////////////////////////////////////////////////////////////*/ + + function read(address pointer) internal view returns (bytes memory) { + return readBytecode(pointer, DATA_OFFSET, pointer.code.length - DATA_OFFSET); + } + + function read(address pointer, uint256 start) internal view returns (bytes memory) { + start += DATA_OFFSET; + + return readBytecode(pointer, start, pointer.code.length - start); + } + + function read( + address pointer, + uint256 start, + uint256 end + ) internal view returns (bytes memory) { + start += DATA_OFFSET; + end += DATA_OFFSET; + + require(pointer.code.length >= end, "OUT_OF_BOUNDS"); + + return readBytecode(pointer, start, end - start); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL HELPER LOGIC + //////////////////////////////////////////////////////////////*/ + + function readBytecode( + address pointer, + uint256 start, + uint256 size + ) private view returns (bytes memory data) { + /// @solidity memory-safe-assembly + assembly { + // Get a pointer to some free memory. + data := mload(0x40) + + // Update the free memory pointer to prevent overriding our data. + // We use and(x, not(31)) as a cheaper equivalent to sub(x, mod(x, 32)). + // Adding 31 to size and running the result through the logic above ensures + // the memory pointer remains word-aligned, following the Solidity convention. + mstore(0x40, add(data, and(add(add(size, 32), 31), not(31)))) + + // Store the size of the data in the first 32 byte chunk of free memory. + mstore(data, size) + + // Copy the code into memory right after the 32 bytes we used to store the size. + extcodecopy(pointer, add(data, 32), start, size) + } + } +} diff --git a/lib/solmate/src/utils/SafeCastLib.sol b/lib/solmate/src/utils/SafeCastLib.sol new file mode 100644 index 0000000..9e8a2af --- /dev/null +++ b/lib/solmate/src/utils/SafeCastLib.sol @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Safe unsigned integer casting library that reverts on overflow. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) +library SafeCastLib { + function safeCastTo248(uint256 x) internal pure returns (uint248 y) { + require(x < 1 << 248); + + y = uint248(x); + } + + function safeCastTo240(uint256 x) internal pure returns (uint240 y) { + require(x < 1 << 240); + + y = uint240(x); + } + + function safeCastTo232(uint256 x) internal pure returns (uint232 y) { + require(x < 1 << 232); + + y = uint232(x); + } + + function safeCastTo224(uint256 x) internal pure returns (uint224 y) { + require(x < 1 << 224); + + y = uint224(x); + } + + function safeCastTo216(uint256 x) internal pure returns (uint216 y) { + require(x < 1 << 216); + + y = uint216(x); + } + + function safeCastTo208(uint256 x) internal pure returns (uint208 y) { + require(x < 1 << 208); + + y = uint208(x); + } + + function safeCastTo200(uint256 x) internal pure returns (uint200 y) { + require(x < 1 << 200); + + y = uint200(x); + } + + function safeCastTo192(uint256 x) internal pure returns (uint192 y) { + require(x < 1 << 192); + + y = uint192(x); + } + + function safeCastTo184(uint256 x) internal pure returns (uint184 y) { + require(x < 1 << 184); + + y = uint184(x); + } + + function safeCastTo176(uint256 x) internal pure returns (uint176 y) { + require(x < 1 << 176); + + y = uint176(x); + } + + function safeCastTo168(uint256 x) internal pure returns (uint168 y) { + require(x < 1 << 168); + + y = uint168(x); + } + + function safeCastTo160(uint256 x) internal pure returns (uint160 y) { + require(x < 1 << 160); + + y = uint160(x); + } + + function safeCastTo152(uint256 x) internal pure returns (uint152 y) { + require(x < 1 << 152); + + y = uint152(x); + } + + function safeCastTo144(uint256 x) internal pure returns (uint144 y) { + require(x < 1 << 144); + + y = uint144(x); + } + + function safeCastTo136(uint256 x) internal pure returns (uint136 y) { + require(x < 1 << 136); + + y = uint136(x); + } + + function safeCastTo128(uint256 x) internal pure returns (uint128 y) { + require(x < 1 << 128); + + y = uint128(x); + } + + function safeCastTo120(uint256 x) internal pure returns (uint120 y) { + require(x < 1 << 120); + + y = uint120(x); + } + + function safeCastTo112(uint256 x) internal pure returns (uint112 y) { + require(x < 1 << 112); + + y = uint112(x); + } + + function safeCastTo104(uint256 x) internal pure returns (uint104 y) { + require(x < 1 << 104); + + y = uint104(x); + } + + function safeCastTo96(uint256 x) internal pure returns (uint96 y) { + require(x < 1 << 96); + + y = uint96(x); + } + + function safeCastTo88(uint256 x) internal pure returns (uint88 y) { + require(x < 1 << 88); + + y = uint88(x); + } + + function safeCastTo80(uint256 x) internal pure returns (uint80 y) { + require(x < 1 << 80); + + y = uint80(x); + } + + function safeCastTo72(uint256 x) internal pure returns (uint72 y) { + require(x < 1 << 72); + + y = uint72(x); + } + + function safeCastTo64(uint256 x) internal pure returns (uint64 y) { + require(x < 1 << 64); + + y = uint64(x); + } + + function safeCastTo56(uint256 x) internal pure returns (uint56 y) { + require(x < 1 << 56); + + y = uint56(x); + } + + function safeCastTo48(uint256 x) internal pure returns (uint48 y) { + require(x < 1 << 48); + + y = uint48(x); + } + + function safeCastTo40(uint256 x) internal pure returns (uint40 y) { + require(x < 1 << 40); + + y = uint40(x); + } + + function safeCastTo32(uint256 x) internal pure returns (uint32 y) { + require(x < 1 << 32); + + y = uint32(x); + } + + function safeCastTo24(uint256 x) internal pure returns (uint24 y) { + require(x < 1 << 24); + + y = uint24(x); + } + + function safeCastTo16(uint256 x) internal pure returns (uint16 y) { + require(x < 1 << 16); + + y = uint16(x); + } + + function safeCastTo8(uint256 x) internal pure returns (uint8 y) { + require(x < 1 << 8); + + y = uint8(x); + } +} diff --git a/lib/solmate/src/utils/SafeTransferLib.sol b/lib/solmate/src/utils/SafeTransferLib.sol new file mode 100644 index 0000000..93ef5a9 --- /dev/null +++ b/lib/solmate/src/utils/SafeTransferLib.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "../tokens/ERC20.sol"; + +/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) +/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. +/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. +library SafeTransferLib { + /*////////////////////////////////////////////////////////////// + ETH OPERATIONS + //////////////////////////////////////////////////////////////*/ + + function safeTransferETH(address to, uint256 amount) internal { + bool success; + + /// @solidity memory-safe-assembly + assembly { + // Transfer the ETH and store if it succeeded or not. + success := call(gas(), to, amount, 0, 0, 0, 0) + } + + require(success, "ETH_TRANSFER_FAILED"); + } + + /*////////////////////////////////////////////////////////////// + ERC20 OPERATIONS + //////////////////////////////////////////////////////////////*/ + + function safeTransferFrom( + ERC20 token, + address from, + address to, + uint256 amount + ) internal { + bool success; + + /// @solidity memory-safe-assembly + assembly { + // Get a pointer to some free memory. + let freeMemoryPointer := mload(0x40) + + // Write the abi-encoded calldata into memory, beginning with the function selector. + mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) + mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument. + mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. + mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. + + success := and( + // Set success to whether the call reverted, if not we check it either + // returned exactly 1 (can't just be non-zero data), or had no return data. + or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), + // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. + // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. + // Counterintuitively, this call must be positioned second to the or() call in the + // surrounding and() call or else returndatasize() will be zero during the computation. + call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) + ) + } + + require(success, "TRANSFER_FROM_FAILED"); + } + + function safeTransfer( + ERC20 token, + address to, + uint256 amount + ) internal { + bool success; + + /// @solidity memory-safe-assembly + assembly { + // Get a pointer to some free memory. + let freeMemoryPointer := mload(0x40) + + // Write the abi-encoded calldata into memory, beginning with the function selector. + mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) + mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. + mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. + + success := and( + // Set success to whether the call reverted, if not we check it either + // returned exactly 1 (can't just be non-zero data), or had no return data. + or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), + // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. + // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. + // Counterintuitively, this call must be positioned second to the or() call in the + // surrounding and() call or else returndatasize() will be zero during the computation. + call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) + ) + } + + require(success, "TRANSFER_FAILED"); + } + + function safeApprove( + ERC20 token, + address to, + uint256 amount + ) internal { + bool success; + + /// @solidity memory-safe-assembly + assembly { + // Get a pointer to some free memory. + let freeMemoryPointer := mload(0x40) + + // Write the abi-encoded calldata into memory, beginning with the function selector. + mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) + mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument. + mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type. + + success := and( + // Set success to whether the call reverted, if not we check it either + // returned exactly 1 (can't just be non-zero data), or had no return data. + or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), + // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. + // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. + // Counterintuitively, this call must be positioned second to the or() call in the + // surrounding and() call or else returndatasize() will be zero during the computation. + call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) + ) + } + + require(success, "APPROVE_FAILED"); + } +} diff --git a/lib/solmate/src/utils/SignedWadMath.sol b/lib/solmate/src/utils/SignedWadMath.sol new file mode 100644 index 0000000..e7d30a4 --- /dev/null +++ b/lib/solmate/src/utils/SignedWadMath.sol @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/// @notice Signed 18 decimal fixed point (wad) arithmetic library. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SignedWadMath.sol) +/// @author Modified from Remco Bloemen (https://xn--2-umb.com/22/exp-ln/index.html) + +/// @dev Will not revert on overflow, only use where overflow is not possible. +function toWadUnsafe(uint256 x) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by 1e18. + r := mul(x, 1000000000000000000) + } +} + +/// @dev Takes an integer amount of seconds and converts it to a wad amount of days. +/// @dev Will not revert on overflow, only use where overflow is not possible. +/// @dev Not meant for negative second amounts, it assumes x is positive. +function toDaysWadUnsafe(uint256 x) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by 1e18 and then divide it by 86400. + r := div(mul(x, 1000000000000000000), 86400) + } +} + +/// @dev Takes a wad amount of days and converts it to an integer amount of seconds. +/// @dev Will not revert on overflow, only use where overflow is not possible. +/// @dev Not meant for negative day amounts, it assumes x is positive. +function fromDaysWadUnsafe(int256 x) pure returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by 86400 and then divide it by 1e18. + r := div(mul(x, 86400), 1000000000000000000) + } +} + +/// @dev Will not revert on overflow, only use where overflow is not possible. +function unsafeWadMul(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by y and divide by 1e18. + r := sdiv(mul(x, y), 1000000000000000000) + } +} + +/// @dev Will return 0 instead of reverting if y is zero and will +/// not revert on overflow, only use where overflow is not possible. +function unsafeWadDiv(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by 1e18 and divide it by y. + r := sdiv(mul(x, 1000000000000000000), y) + } +} + +function wadMul(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Store x * y in r for now. + r := mul(x, y) + + // Combined overflow check (`x == 0 || (x * y) / x == y`) and edge case check + // where x == -1 and y == type(int256).min, for y == -1 and x == min int256, + // the second overflow check will catch this. + // See: https://secure-contracts.com/learn_evm/arithmetic-checks.html#arithmetic-checks-for-int256-multiplication + // Combining into 1 expression saves gas as resulting bytecode will only have 1 `JUMPI` + // rather than 2. + if iszero( + and( + or(iszero(x), eq(sdiv(r, x), y)), + or(lt(x, not(0)), sgt(y, 0x8000000000000000000000000000000000000000000000000000000000000000)) + ) + ) { + revert(0, 0) + } + + // Scale the result down by 1e18. + r := sdiv(r, 1000000000000000000) + } +} + +function wadDiv(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Store x * 1e18 in r for now. + r := mul(x, 1000000000000000000) + + // Equivalent to require(y != 0 && ((x * 1e18) / 1e18 == x)) + if iszero(and(iszero(iszero(y)), eq(sdiv(r, 1000000000000000000), x))) { + revert(0, 0) + } + + // Divide r by y. + r := sdiv(r, y) + } +} + +/// @dev Will not work with negative bases, only use when x is positive. +function wadPow(int256 x, int256 y) pure returns (int256) { + // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y) + return wadExp((wadLn(x) * y) / 1e18); // Using ln(x) means x must be greater than 0. +} + +function wadExp(int256 x) pure returns (int256 r) { + unchecked { + // When the result is < 0.5 we return zero. This happens when + // x <= floor(log(0.5e18) * 1e18) ~ -42e18 + if (x <= -42139678854452767551) return 0; + + // When the result is > (2**255 - 1) / 1e18 we can not represent it as an + // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. + if (x >= 135305999368893231589) revert("EXP_OVERFLOW"); + + // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 + // for more intermediate precision and a binary basis. This base conversion + // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. + x = (x << 78) / 5**18; + + // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers + // of two such that exp(x) = exp(x') * 2**k, where k is an integer. + // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). + int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96; + x = x - k * 54916777467707473351141471128; + + // k is in the range [-61, 195]. + + // Evaluate using a (6, 7)-term rational approximation. + // p is made monic, we'll multiply by a scale factor later. + int256 y = x + 1346386616545796478920950773328; + y = ((y * x) >> 96) + 57155421227552351082224309758442; + int256 p = y + x - 94201549194550492254356042504812; + p = ((p * y) >> 96) + 28719021644029726153956944680412240; + p = p * x + (4385272521454847904659076985693276 << 96); + + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + int256 q = x - 2855989394907223263936484059900; + q = ((q * x) >> 96) + 50020603652535783019961831881945; + q = ((q * x) >> 96) - 533845033583426703283633433725380; + q = ((q * x) >> 96) + 3604857256930695427073651918091429; + q = ((q * x) >> 96) - 14423608567350463180887372962807573; + q = ((q * x) >> 96) + 26449188498355588339934803723976023; + + /// @solidity memory-safe-assembly + assembly { + // Div in assembly because solidity adds a zero check despite the unchecked. + // The q polynomial won't have zeros in the domain as all its roots are complex. + // No scaling is necessary because p is already 2**96 too large. + r := sdiv(p, q) + } + + // r should be in the range (0.09, 0.25) * 2**96. + + // We now need to multiply r by: + // * the scale factor s = ~6.031367120. + // * the 2**k factor from the range reduction. + // * the 1e18 / 2**96 factor for base conversion. + // We do this all at once, with an intermediate result in 2**213 + // basis, so the final right shift is always by a positive amount. + r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)); + } +} + +function wadLn(int256 x) pure returns (int256 r) { + unchecked { + require(x > 0, "UNDEFINED"); + + // We want to convert x from 10**18 fixed point to 2**96 fixed point. + // We do this by multiplying by 2**96 / 10**18. But since + // ln(x * C) = ln(x) + ln(C), we can simply do nothing here + // and add ln(2**96 / 10**18) at the end. + + /// @solidity memory-safe-assembly + assembly { + r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) + r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + r := or(r, shl(2, lt(0xf, shr(r, x)))) + r := or(r, shl(1, lt(0x3, shr(r, x)))) + r := or(r, lt(0x1, shr(r, x))) + } + + // Reduce range of x to (1, 2) * 2**96 + // ln(2^k * x) = k * ln(2) + ln(x) + int256 k = r - 96; + x <<= uint256(159 - k); + x = int256(uint256(x) >> 159); + + // Evaluate using a (8, 8)-term rational approximation. + // p is made monic, we will multiply by a scale factor later. + int256 p = x + 3273285459638523848632254066296; + p = ((p * x) >> 96) + 24828157081833163892658089445524; + p = ((p * x) >> 96) + 43456485725739037958740375743393; + p = ((p * x) >> 96) - 11111509109440967052023855526967; + p = ((p * x) >> 96) - 45023709667254063763336534515857; + p = ((p * x) >> 96) - 14706773417378608786704636184526; + p = p * x - (795164235651350426258249787498 << 96); + + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + // q is monic by convention. + int256 q = x + 5573035233440673466300451813936; + q = ((q * x) >> 96) + 71694874799317883764090561454958; + q = ((q * x) >> 96) + 283447036172924575727196451306956; + q = ((q * x) >> 96) + 401686690394027663651624208769553; + q = ((q * x) >> 96) + 204048457590392012362485061816622; + q = ((q * x) >> 96) + 31853899698501571402653359427138; + q = ((q * x) >> 96) + 909429971244387300277376558375; + /// @solidity memory-safe-assembly + assembly { + // Div in assembly because solidity adds a zero check despite the unchecked. + // The q polynomial is known not to have zeros in the domain. + // No scaling required because p is already 2**96 too large. + r := sdiv(p, q) + } + + // r is in the range (0, 0.125) * 2**96 + + // Finalization, we need to: + // * multiply by the scale factor s = 5.549… + // * add ln(2**96 / 10**18) + // * add k * ln(2) + // * multiply by 10**18 / 2**96 = 5**18 >> 78 + + // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 + r *= 1677202110996718588342820967067443963516166; + // add ln(2) * k * 5e18 * 2**192 + r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; + // add ln(2**96 / 10**18) * 5e18 * 2**192 + r += 600920179829731861736702779321621459595472258049074101567377883020018308; + // base conversion: mul 2**18 / 2**192 + r >>= 174; + } +} + +/// @dev Will return 0 instead of reverting if y is zero. +function unsafeDiv(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Divide x by y. + r := sdiv(x, y) + } +} diff --git a/remappings.txt b/remappings.txt new file mode 100644 index 0000000..0a60268 --- /dev/null +++ b/remappings.txt @@ -0,0 +1,12 @@ +ds-test/=lib/forge-std/lib/ds-test/src/ +erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/ +@forge-std/=lib/forge-std/src/ +@solmate/=lib/solmate/src/ +@openzeppelin/=lib/openzeppelin-contracts/ +@openzeppelin-v4.9.3/=lib/openzeppelin-contracts-v4.9.3/ +@openzeppelin-v5.0.0/=lib/openzeppelin-contracts-v5.0.0/ +@uniswap/v3-core/=lib/v3-core/ +@uniswap/v3-periphery/=lib/v3-periphery/ +@maverick-v1-interfaces/=lib/maverick-v1-interfaces/contracts/interfaces/ +@crytic/=lib/crytic/contracts +@src/=src/ diff --git a/script/GOERLI/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol b/script/GOERLI/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol new file mode 100644 index 0000000..bec042c --- /dev/null +++ b/script/GOERLI/GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {Script, console} from "forge-std/Script.sol"; +import { + AmphorSyntheticVaultWithPermit, + ERC20, + IERC20 +} from "../../src/AmphorSyntheticVaultWithPermit.sol"; + +contract GOERLI_aaveUSDC_DeployAmphorSyntheticVaultWithPermit is Script { + function run() external { + // if you want to deploy a vault with a seed phrase instead of a pk, uncomment the following line + // string memory seedPhrase = vm.readFile(".secret"); + // uint256 privateKey = vm.deriveKey(seedPhrase, 0); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address amphorlabsAddress = vm.envAddress("AMPHORLABS_ADDRESS_GOERLI"); + ERC20 underlying = ERC20(vm.envAddress("AAVE_USDC_GOERLI")); + uint8 decimalOffset = uint8(vm.envUint("DECIMALS_OFFSET_USDC")); + uint16 fees = uint16(vm.envUint("INITIAL_FEES_AMOUNT")); + uint256 bootstrapAmount = vm.envUint("BOOTSTRAP_AMOUNT_SYNTHETIC_USDC"); + string memory vaultName = vm.envString("SYNTHETIC_USDC_V0_NAME"); + string memory vaultSymbol = vm.envString("SYNTHETIC_USDC_V0_SYMBOL"); + + vm.startBroadcast(privateKey); + + AmphorSyntheticVaultWithPermit amphorSyntheticVault = + new AmphorSyntheticVaultWithPermit( + underlying, + vaultName, + vaultSymbol, + decimalOffset + ); + + amphorSyntheticVault.setFees(fees); + + IERC20(underlying).approve( + address(amphorSyntheticVault), bootstrapAmount + ); + amphorSyntheticVault.deposit(bootstrapAmount, amphorlabsAddress); + + amphorSyntheticVault.transferOwnership(amphorlabsAddress); + + console.log( + "Synthetic vault USDC contract address: ", + address(amphorSyntheticVault) + ); + + vm.stopBroadcast(); + } +} diff --git a/script/GOERLI/GOERLI_customUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol b/script/GOERLI/GOERLI_customUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol new file mode 100644 index 0000000..1ac023b --- /dev/null +++ b/script/GOERLI/GOERLI_customUSDC_DeployAmphorSyntheticVaultWithPermit.s.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {Script, console} from "forge-std/Script.sol"; +import { + AmphorSyntheticVaultWithPermit, + ERC20, + IERC20 +} from "../../src/AmphorSyntheticVaultWithPermit.sol"; + +contract GOERLI_customUSDC_DeployAmphorSyntheticVaultWithPermit is Script { + function run() external { + // if you want to deploy a vault with a seed phrase instead of a pk, uncomment the following line + // string memory seedPhrase = vm.readFile(".secret"); + // uint256 privateKey = vm.deriveKey(seedPhrase, 0); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address amphorlabsAddress = vm.envAddress("AMPHORLABS_ADDRESS_GOERLI"); + ERC20 underlying = ERC20(vm.envAddress("CUSTOM_USDC_GOERLI")); + uint8 decimalOffset = uint8(vm.envUint("DECIMALS_OFFSET_USDC")); + uint16 fees = uint16(vm.envUint("INITIAL_FEES_AMOUNT")); + uint256 bootstrapAmount = vm.envUint("BOOTSTRAP_AMOUNT_SYNTHETIC_USDC"); + string memory vaultName = vm.envString("SYNTHETIC_USDC_V0_NAME"); + string memory vaultSymbol = vm.envString("SYNTHETIC_USDC_V0_SYMBOL"); + + vm.startBroadcast(privateKey); + + AmphorSyntheticVaultWithPermit amphorSyntheticVault = + new AmphorSyntheticVaultWithPermit( + underlying, + vaultName, + vaultSymbol, + decimalOffset + ); + + amphorSyntheticVault.setFees(fees); + + IERC20(underlying).approve( + address(amphorSyntheticVault), bootstrapAmount + ); + amphorSyntheticVault.deposit(bootstrapAmount, amphorlabsAddress); + + amphorSyntheticVault.transferOwnership(amphorlabsAddress); + + console.log( + "Synthetic vault USDC contract address: ", + address(amphorSyntheticVault) + ); + + vm.stopBroadcast(); + } +} diff --git a/script/L1/AmphorSyntheticVault/USDC_DeployAmphorSyntheticVaultWithPermit.s.sol b/script/L1/AmphorSyntheticVault/USDC_DeployAmphorSyntheticVaultWithPermit.s.sol new file mode 100644 index 0000000..9fb36a2 --- /dev/null +++ b/script/L1/AmphorSyntheticVault/USDC_DeployAmphorSyntheticVaultWithPermit.s.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {Script, console} from "forge-std/Script.sol"; +import {AmphorSyntheticVaultWithPermit} from + "../../../src/AmphorSyntheticVaultWithPermit.sol"; +import "@openzeppelin-v4.9.3/contracts/token/ERC20/ERC20.sol"; + +contract L1_USDC_DeployAmphorSyntheticVaultWithPermit is Script { + function run() external { + // if you want to deploy a vault with a seed phrase instead of a pk, uncomment the following line + // string memory seedPhrase = vm.readFile(".secret"); + // uint256 privateKey = vm.deriveKey(seedPhrase, 0); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address amphorlabsAddress = vm.envAddress("AMPHORLABS_ADDRESS"); + ERC20 underlying = ERC20(vm.envAddress("USDC_MAINNET")); + uint8 decimalOffset = uint8(vm.envUint("DECIMALS_OFFSET_USDC")); + uint16 fees = uint16(vm.envUint("INITIAL_FEES_AMOUNT")); + uint256 bootstrapAmount = vm.envUint("BOOTSTRAP_AMOUNT_SYNTHETIC_USDC"); + string memory vaultName = vm.envString("SYNTHETIC_USDC_V0_NAME"); + string memory vaultSymbol = vm.envString("SYNTHETIC_USDC_V0_SYMBOL"); + + vm.startBroadcast(privateKey); + + AmphorSyntheticVaultWithPermit amphorSyntheticVault = + new AmphorSyntheticVaultWithPermit( + underlying, + vaultName, + vaultSymbol, + decimalOffset + ); + + amphorSyntheticVault.setFees(fees); + + IERC20(underlying).approve( + address(amphorSyntheticVault), bootstrapAmount + ); + amphorSyntheticVault.deposit(bootstrapAmount, amphorlabsAddress); + + amphorSyntheticVault.transferOwnership(amphorlabsAddress); + + console.log( + "Synthetic vault USDC contract address: ", + address(amphorSyntheticVault) + ); + + vm.stopBroadcast(); + } +} diff --git a/script/L1/AmphorSyntheticVault/WBTC_DeployAmphorSyntheticVault.s.sol b/script/L1/AmphorSyntheticVault/WBTC_DeployAmphorSyntheticVault.s.sol new file mode 100644 index 0000000..2831fa6 --- /dev/null +++ b/script/L1/AmphorSyntheticVault/WBTC_DeployAmphorSyntheticVault.s.sol @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {Script, console} from "forge-std/Script.sol"; +import {AmphorSyntheticVault} from "../../../src/AmphorSyntheticVault.sol"; +import "@openzeppelin-v4.9.3/contracts/token/ERC20/ERC20.sol"; + +contract L1_WBTC_DeployAmphorSyntheticVault is Script { + function run() external { + // if you want to deploy a vault with a seed phrase instead of a pk, uncomment the following line + // string memory seedPhrase = vm.readFile(".secret"); + // uint256 privateKey = vm.deriveKey(seedPhrase, 0); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address amphorlabsAddress = vm.envAddress("AMPHORLABS_ADDRESS"); + ERC20 underlying = ERC20(vm.envAddress("WBTC_MAINNET")); + uint8 decimalOffset = uint8(vm.envUint("DECIMALS_OFFSET_USDC")); + uint16 fees = uint16(vm.envUint("INITIAL_FEES_AMOUNT")); + uint256 bootstrapAmount = vm.envUint("BOOTSTRAP_AMOUNT_SYNTHETIC_USDC"); + string memory vaultName = vm.envString("SYNTHETIC_USDC_V0_NAME"); + string memory vaultSymbol = vm.envString("SYNTHETIC_USDC_V0_SYMBOL"); + + vm.startBroadcast(privateKey); + + AmphorSyntheticVault amphorSyntheticVault = new AmphorSyntheticVault( + underlying, + vaultName, + vaultSymbol, + decimalOffset + ); + + amphorSyntheticVault.setFees(fees); + + IERC20(underlying).approve( + address(amphorSyntheticVault), bootstrapAmount + ); + amphorSyntheticVault.deposit(bootstrapAmount, amphorlabsAddress); + + amphorSyntheticVault.transferOwnership(amphorlabsAddress); + + console.log( + "Synthetic vault WBTC contract address: ", + address(amphorSyntheticVault) + ); + + vm.stopBroadcast(); + } +} diff --git a/script/L1/AmphorSyntheticVault/WSTETH_DeployAmphorSyntheticVault.s.sol b/script/L1/AmphorSyntheticVault/WSTETH_DeployAmphorSyntheticVault.s.sol new file mode 100644 index 0000000..15b4a63 --- /dev/null +++ b/script/L1/AmphorSyntheticVault/WSTETH_DeployAmphorSyntheticVault.s.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {Script, console} from "forge-std/Script.sol"; +import {AmphorSyntheticVaultWithPermit} from + "../../../src/AmphorSyntheticVaultWithPermit.sol"; +import "@openzeppelin-v4.9.3/contracts/token/ERC20/ERC20.sol"; + +contract L1_WETH_DeployAmphorSyntheticVault is Script { + function run() external { + // if you want to deploy a vault with a seed phrase instead of a pk, uncomment the following line + // string memory seedPhrase = vm.readFile(".secret"); + // uint256 privateKey = vm.deriveKey(seedPhrase, 0); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address amphorlabsAddress = vm.envAddress("AMPHORLABS_ADDRESS"); + ERC20 underlying = ERC20(vm.envAddress("WSTETH_MAINNET")); + uint8 decimalOffset = uint8(vm.envUint("DECIMALS_OFFSET_WSTETH")); + uint16 fees = uint16(vm.envUint("INITIAL_FEES_AMOUNT")); + uint256 bootstrapAmount = + vm.envUint("BOOTSTRAP_AMOUNT_SYNTHETIC_WSTETH"); + + string memory vaultName = vm.envString("SYNTHETIC_WSTETH_V0_NAME"); + string memory vaultSymbol = vm.envString("SYNTHETIC_WSTETH_V0_SYMBOL"); + + vm.startBroadcast(privateKey); + AmphorSyntheticVaultWithPermit amphorSyntheticVault = + new AmphorSyntheticVaultWithPermit( + underlying, + vaultName, + vaultSymbol, + decimalOffset + ); + + amphorSyntheticVault.setFees(fees); + + IERC20(underlying).approve( + address(amphorSyntheticVault), bootstrapAmount + ); + amphorSyntheticVault.deposit(bootstrapAmount, amphorlabsAddress); + + amphorSyntheticVault.transferOwnership(amphorlabsAddress); + + console.log( + "Synthetic vault WSTETH contract address: ", + address(amphorSyntheticVault) + ); + + vm.stopBroadcast(); + } +} diff --git a/script/L1/DeployZapper.s.sol b/script/L1/DeployZapper.s.sol new file mode 100644 index 0000000..77a8d9d --- /dev/null +++ b/script/L1/DeployZapper.s.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {Script, console} from "forge-std/Script.sol"; +import {VaultZapper} from "../../src/VaultZapper.sol"; +import "@openzeppelin-v4.9.3/contracts/token/ERC20/ERC20.sol"; +import {AmphorSyntheticVaultWithPermit} from + "../../src/AmphorSyntheticVaultWithPermit.sol"; +import {IERC4626} from "@openzeppelin-v4.9.3/contracts/interfaces/IERC4626.sol"; + +contract L1_VaultZapper is Script { + function run() external { + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address amphorlabsAddress = vm.envAddress("AMPHORLABS_ADDRESS"); + IERC4626 vault = IERC4626(0x2791EB5807D69Fe10C02eED6B4DC12baC0701744); + address _router = 0x1111111254EEB25477B68fb85Ed929f73A960582; + ERC20 _DAI = ERC20(vm.envAddress("DAI_MAINNET")); + ERC20 _USDC = ERC20(vm.envAddress("USDC_MAINNET")); + ERC20 _USDT = ERC20(vm.envAddress("USDT_MAINNET")); + ERC20 _WETH = ERC20(vm.envAddress("WETH_MAINNET")); + ERC20 _STETH = ERC20(vm.envAddress("STETH_MAINNET")); + ERC20 _WBTC = ERC20(vm.envAddress("WBTC_MAINNET")); + + vm.startBroadcast(privateKey); + + VaultZapper zapper = + VaultZapper(0xd697D2af3ddfe4Ed24e92A230C4B93606B5d05fB); + zapper.toggleRouterAuthorization(_router); + + zapper.approveTokenForRouter(_DAI, _router); + zapper.approveTokenForRouter(_USDC, _router); + zapper.approveTokenForRouter(_USDT, _router); + zapper.approveTokenForRouter(_WETH, _router); + zapper.approveTokenForRouter(_STETH, _router); + zapper.approveTokenForRouter(_WBTC, _router); + + zapper.toggleVaultAuthorization(IERC4626(address(vault))); + + zapper.transferOwnership(amphorlabsAddress); + + console.log("Zapper contract address: ", address(zapper)); + + vm.stopBroadcast(); + } +} diff --git a/src/AmphorSyntheticVault.sol b/src/AmphorSyntheticVault.sol new file mode 100644 index 0000000..49305ce --- /dev/null +++ b/src/AmphorSyntheticVault.sol @@ -0,0 +1,802 @@ +//SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import { + Ownable, + Ownable2Step +} from "@openzeppelin-v4.9.3/contracts/access/Ownable2Step.sol"; +import { + ERC20, + IERC20, + IERC20Metadata +} from "@openzeppelin-v4.9.3/contracts/token/ERC20/ERC20.sol"; +import {Math} from "@openzeppelin-v4.9.3/contracts/utils/math/Math.sol"; +import {IERC4626} from "@openzeppelin-v4.9.3/contracts/interfaces/IERC4626.sol"; +import {SafeERC20} from + "@openzeppelin-v4.9.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Pausable} from "@openzeppelin-v4.9.3/contracts/security/Pausable.sol"; +import {ERC20Permit} from + "@openzeppelin-v4.9.3/contracts/token/ERC20/extensions/ERC20Permit.sol"; + +/* + _______ _______ _______ _______ _______ +( ___ )( )( ____ )|\ /|( ___ )( ____ ) +| ( ) || () () || ( )|| ) ( || ( ) || ( )| +| (___) || || || || (____)|| (___) || | | || (____)| +| ___ || |(_)| || _____)| ___ || | | || __) +| ( ) || | | || ( | ( ) || | | || (\ ( +| ) ( || ) ( || ) | ) ( || (___) || ) \ \__ +|/ \||/ \||/ |/ \|(_______)|/ \__/ + _______ _ _________ _______ __________________ _______ +( ____ \|\ /|( ( /|\__ __/|\ /|( ____ \\__ __/\__ __/( ____ \ +| ( \/( \ / )| \ ( | ) ( | ) ( || ( \/ ) ( ) ( | ( \/ +| (_____ \ (_) / | \ | | | | | (___) || (__ | | | | | | +(_____ ) \ / | (\ \) | | | | ___ || __) | | | | | | + ) | ) ( | | \ | | | | ( ) || ( | | | | | | +/\____) | | | | ) \ | | | | ) ( || (____/\ | | ___) (___| (____/\ +\_______) \_/ |/ )_) )_( |/ \|(_______/ )_( \_______/(_______/ +*/ + +contract AmphorSyntheticVault is + IERC4626, + ERC20, + ERC20Permit, + Ownable2Step, + Pausable +{ + /* + ###### + LIBS + ###### + */ + + /** + * @dev The `Math` lib is only used for `mulDiv` operations. + */ + using Math for uint256; + + /** + * @dev The `SafeERC20` lib is only used for `safeTransfer` and + * `safeTransferFrom` operations. + */ + using SafeERC20 for IERC20; + + /* + ##################################### + GENERAL ERC-4626 RELATED ATTRIBUTES + ##################################### + */ + + /** + * @dev The decimals amount of the share token. + */ + uint8 private immutable _decimalsShares; + + /** + * @dev The underlying asset of the vault. + */ + IERC20 internal immutable _asset; + + /** + * @dev The decimals offset of the shares token. This is to protect against + * inflation attacks. + * https://blog.openzeppelin.com/a-novel-defense-against-erc4626-inflation-attacks + * @return Amount of decimals offset of the shares. + */ + uint8 public immutable decimalsOffset; + + /* + ##################################### + AMPHOR SYNTHETIC RELATED ATTRIBUTES + ##################################### + */ + + /** + * @dev The total underlying assets amount just before the lock period. + * @return Amount of the total underlying assets just before the last vault + * locking. + */ + uint256 public lastSavedBalance; + + /** + * @dev The perf fees applied on the positive yield. + * @return Amount of the perf fees applied on the positive yield. + */ + uint16 public feesInBps; + + /** + * @dev The locking status of the vault. + * @return `true` if the vault is open for deposits, `false` otherwise. + */ + bool public vaultIsOpen; + + /* + ######## + EVENTS + ######## + */ + + /** + * @dev Emitted when an epoch starts. + * @param timestamp The block timestamp of the epoch start. + * @param lastSavedBalance The `lastSavedBalance` when the vault start. + * @param totalShares The total amount of shares when the vault start. + */ + event EpochStart( + uint256 indexed timestamp, uint256 lastSavedBalance, uint256 totalShares + ); + + /** + * @dev Emitted when an epoch ends. + * @param timestamp The block timestamp of the epoch end. + * @param lastSavedBalance The `lastSavedBalance` when the vault end. + * @param returnedAssets The total amount of underlying assets returned to + * the vault before collecting fees. + * @param fees The amount of fees collected. + * @param totalShares The total amount of shares when the vault end. + */ + event EpochEnd( + uint256 indexed timestamp, + uint256 lastSavedBalance, + uint256 returnedAssets, + uint256 fees, + uint256 totalShares + ); + + /** + * @dev Emitted when fees are changed. + * @param oldFees The old fees. + * @param newFees The new fees. + */ + event FeesChanged(uint16 oldFees, uint16 newFees); + + /* + ######## + ERRORS + ######## + */ + + /** + * @dev The vault is in locked state. Emitted if the tx cannot happen in + * this state. + */ + error VaultIsLocked(); + + /** + * @dev The vault is in open state. Emitted if the tx cannot happen in this + * state. + */ + error VaultIsOpen(); + + /** + * @dev The rules doesn't allow the perf fees to be higher than 30.00%. + */ + error FeesTooHigh(); + + /** + * @dev Claiming the underlying assets is not allowed. + */ + error CannotClaimAsset(); + + /** + * @dev Attempted to deposit more underlying assets than the max amount for + * `receiver`. + */ + error ERC4626ExceededMaxDeposit( + address receiver, uint256 assets, uint256 max + ); + + /** + * @dev Attempted to mint more shares than the max amount for `receiver`. + */ + error ERC4626ExceededMaxMint(address receiver, uint256 shares, uint256 max); + + /** + * @dev Attempted to withdraw more underlying assets than the max amount for + * `receiver`. + */ + error ERC4626ExceededMaxWithdraw(address owner, uint256 assets, uint256 max); + + /** + * @dev Attempted to redeem more shares than the max amount for `receiver`. + */ + error ERC4626ExceededMaxRedeem(address owner, uint256 shares, uint256 max); + + /** + * @dev Attempted to mint less shares than the min amount for `receiver`. + * This error is only thrown when the `depositMinShares` function is used. + * @notice The `depositMinShares` function is used to deposit underlying + * assets into the vault. It also checks that the amount of shares minted is + * greater or equal to the specified minimum amount. + * @param owner The address of the owner. + * @param shares The shares amount to be converted into underlying assets. + * @param minShares The minimum amount of shares to be minted. + */ + error ERC4626NotEnoughSharesMinted( + address owner, uint256 shares, uint256 minShares + ); + + /** + * @dev Attempted to withdraw more underlying assets than the max amount for + * `receiver`. + * This error is only thrown when the `mintMaxAssets` function is used. + * @notice The `mintMaxAssets` function is used to mint the specified amount + * of shares in exchange of the corresponding underlying assets amount from + * owner. It also checks that the amount of assets deposited is less or + * equal to the specified maximum amount. + * @param owner The address of the owner. + * @param assets The underlying assets amount to be converted into shares. + * @param maxAssets The maximum amount of assets to be deposited. + */ + error ERC4626TooMuchAssetsDeposited( + address owner, uint256 assets, uint256 maxAssets + ); + + /* + ############# + CONSTRUCTOR + ############# + */ + + /** + * @dev The `constructor` function is used to initialize the vault. + * @param underlying The underlying asset token. + * @param name The name of the vault. + * @param symbol The symbol of the vault. + * @param _decimalsOffset The decimal offset between the underlying asset + * token and the share token. + */ + constructor( + ERC20 underlying, + string memory name, + string memory symbol, + uint8 _decimalsOffset + ) ERC20(name, symbol) ERC20Permit(name) Ownable2Step() { + _asset = underlying; + decimalsOffset = _decimalsOffset; + unchecked { + _decimalsShares = underlying.decimals() + _decimalsOffset; + } + vaultIsOpen = true; + } + + /* + #################### + PAUSABLE OVERRIDES + #################### + */ + + /** + * @dev See {Pausable-_pause}. + * @notice The `pause` function is used to pause the vault. + * It can only be called by the owner of the contract (`onlyOwner` modifier) + * when the vault is not paused (`whenNotPaused`). + * It will disable further deposits but withdrawals will still be enabled. + */ + function pause() external onlyOwner { + _pause(); + } + + /** + * @dev See {Pausable-_unpause}. + * @notice The `unpause` function is used to unpause the vault. + * It can only be called by the owner of the contract (`onlyOwner` modifier) + * when the vault is paused (`whenPaused`). + * It will enable further deposits. + */ + + function unpause() external onlyOwner { + _unpause(); + } + + /* + ################## + ERC-20 OVERRIDES + ################## + */ + + /** + * @dev See {IERC20-decimals}. + * @notice The _decimalShares is equal to underlying asset decimals + + * decimalsOffset. See constructor for more details about this. + * @return Amount of decimals of the share token. + */ + function decimals() + public + view + override(ERC20, IERC20Metadata) + returns (uint8) + { + return _decimalsShares; + } + + /* + #################################### + GENERAL ERC-4626 RELATED FUNCTIONS + #################################### + */ + + /* + * @dev The `asset` function is used to return the address of the underlying + * @return address of the underlying asset. + */ + function asset() public view returns (address) { + return address(_asset); + } + + /** + * @dev The `totalAssets` function is used to calculate the theoretical + * total underlying assets owned by the vault. + * If the vault is locked, the last saved balance is added to the current + * balance. + * @notice The `totalAssets` function is used to know what is the + * theoretical TVL of the vault. + * @return Amount of the total underlying assets in the vault. + */ + function totalAssets() public view returns (uint256) { + if (vaultIsOpen) return _totalAssets(); + return _totalAssets() + lastSavedBalance; + } + + /** + * @dev See {IERC4626-convertToShares}. + * @notice The `convertToShares` function is used to calculate shares amount + * received in exchange of the specified underlying assets amount. + * @param assets The underlying assets amount to be converted into shares. + * @return Amount of shares received in exchange of the specified underlying + * assets amount. + */ + function convertToShares(uint256 assets) public view returns (uint256) { + return _convertToShares(assets, Math.Rounding.Down); + } + + /** + * @dev See {IERC4626-convertToAssets}. + * @notice The `convertToAssets` function is used to calculate underlying + * assets amount received in exchange of the specified amount of shares. + * @param shares The shares amount to be converted into underlying assets. + * @return Amount of assets received in exchange of the specified shares + * amount. + */ + function convertToAssets(uint256 shares) public view returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Down); + } + + /** + * @dev The `maxDeposit` function is used to calculate the maximum deposit. + * @notice If the vault is locked or paused, users are not allowed to mint, + * the maxMint is 0. + * @ param _ The address of the receiver. + * @return Amount of the maximum underlying assets deposit amount. + */ + function maxDeposit(address) public view returns (uint256) { + return !vaultIsOpen || paused() ? 0 : type(uint256).max; + } + + /** + * @dev The `maxMint` function is used to calculate the maximum amount of + * shares you can mint. + * @notice If the vault is locked or paused, the maxMint is 0. + * @ param _ The address of the receiver. + * @return Amount of the maximum shares mintable for the specified address. + */ + function maxMint(address) public view returns (uint256) { + return !vaultIsOpen || paused() ? 0 : type(uint256).max; + } + + /** + * @dev The `maxWithdraw` function is used to calculate the maximum amount + * of withdrawable underlying assets. + * @notice If the function is called during the lock period the maxWithdraw + * is `0`. + * @param owner The address of the owner. + * @return Amount of the maximum number of withdrawable underlying assets. + */ + function maxWithdraw(address owner) public view returns (uint256) { + return vaultIsOpen + ? _convertToAssets(balanceOf(owner), Math.Rounding.Down) + : 0; + } + + /** + * @dev The `maxRedemm` function is used to calculate the maximum amount of + * redeemable shares. + * @notice If the function is called during the lock period the maxRedeem is + * `0`. + * @param owner The address of the owner. + * @return Amount of the maximum number of redeemable shares. + */ + function maxRedeem(address owner) public view returns (uint256) { + return vaultIsOpen ? balanceOf(owner) : 0; + } + + /** + * @dev The `previewDeposit` function is used to calculate shares amount + * received in exchange of the specified underlying amount. + * @param assets The underlying assets amount to be converted into shares. + * @return Amount of shares received in exchange of the specified underlying + * assets amount. + */ + function previewDeposit(uint256 assets) public view returns (uint256) { + return _convertToShares(assets, Math.Rounding.Down); + } + + /** + * @dev The `previewMint` function is used to calculate the underlying asset + * amount received in exchange of the specified amount of shares. + * @param shares The shares amount to be converted into underlying assets. + * @return Amount of underlying assets received in exchange of the specified + * amount of shares. + */ + function previewMint(uint256 shares) public view returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Up); + } + + /** + * @dev The `previewWithdraw` function is used to calculate the shares + * amount received in exchange of the specified underlying amount. + * @param assets The underlying assets amount to be converted into shares. + * @return Amount of shares received in exchange of the specified underlying + * assets amount. + */ + function previewWithdraw(uint256 assets) public view returns (uint256) { + return _convertToShares(assets, Math.Rounding.Up); + } + + /** + * @dev The `previewRedeem` function is used to calculate the underlying + * assets amount received in exchange of the specified amount of shares. + * @param shares The shares amount to be converted into underlying assets. + * @return Amount of underlying assets received in exchange of the specified + * amount of shares. + */ + function previewRedeem(uint256 shares) public view returns (uint256) { + return _convertToAssets(shares, Math.Rounding.Down); + } + + /** + * @dev The `deposit` function is used to deposit underlying assets into the + * vault. + * @notice The `deposit` function is used to deposit underlying assets into + * the vault. + * @param assets The underlying assets amount to be converted into shares. + * @param receiver The address of the shares receiver. + * @return Amount of shares received in exchange of the + * specified underlying assets amount. + */ + function deposit(uint256 assets, address receiver) + public + returns (uint256) + { + uint256 maxAssets = maxDeposit(receiver); + if (assets > maxAssets) { + revert ERC4626ExceededMaxDeposit(receiver, assets, maxAssets); + } + + uint256 sharesAmount = previewDeposit(assets); + _deposit(_msgSender(), receiver, assets, sharesAmount); + + return sharesAmount; + } + + /** + * @dev The `depositMinShares` function is used to deposit underlying assets + * into the vault. It also checks that the amount of shares minted is greater + * or equal to the specified minimum amount. + * @param assets The underlying assets amount to be converted into shares. + * @param receiver The address of the shares receiver. + * @param minShares The minimum amount of shares to be minted. + * @return Amount of shares received in exchange of the specified underlying + * assets amount. + */ + function depositMinShares( + uint256 assets, + address receiver, + uint256 minShares + ) public returns (uint256) { + uint256 sharesAmount = deposit(assets, receiver); + if (sharesAmount < minShares) { + revert ERC4626NotEnoughSharesMinted( + receiver, sharesAmount, minShares + ); + } + return sharesAmount; + } + + /** + * @dev The `mint` function is used to mint the specified amount of shares in + * exchange of the corresponding assets amount from owner. + * @param shares The shares amount to be converted into underlying assets. + * @param receiver The address of the shares receiver. + * @return Amount of underlying assets deposited in exchange of the specified + * amount of shares. + */ + function mint(uint256 shares, address receiver) public returns (uint256) { + uint256 maxShares = maxMint(receiver); + if (shares > maxShares) { + revert ERC4626ExceededMaxMint(receiver, shares, maxShares); + } + + uint256 assetsAmount = previewMint(shares); + _deposit(_msgSender(), receiver, assetsAmount, shares); + + return assetsAmount; + } + + /** + * @dev The `mintMaxAssets` function is used to mint the specified amount of + * shares in exchange of the corresponding underlying assets amount from + * owner. It also checks that the amount of assets deposited is less or equal + * to the specified maximum amount. + * @param shares The shares amount to be converted into underlying assets. + * @param receiver The address of the shares receiver. + * @param maxAssets The maximum amount of assets to be deposited. + * @return Amount of underlying assets deposited in exchange of the specified + * amount of shares. + */ + function mintMaxAssets(uint256 shares, address receiver, uint256 maxAssets) + public + returns (uint256) + { + uint256 assetsAmount = mint(shares, receiver); + if (assetsAmount > maxAssets) { + revert ERC4626TooMuchAssetsDeposited( + receiver, assetsAmount, maxAssets + ); + } + + return assetsAmount; + } + + /** + * @dev The `withdraw` function is used to withdraw the specified underlying + * assets amount in exchange of a proportional amount of shares. + * @param assets The underlying assets amount to be converted into shares. + * @param receiver The address of the shares receiver. + * @param owner The address of the owner. + * @return Amount of shares received in exchange of the specified underlying + * assets amount. + */ + function withdraw(uint256 assets, address receiver, address owner) + external + returns (uint256) + { + uint256 maxAssets = maxWithdraw(owner); + if (assets > maxAssets) { + revert ERC4626ExceededMaxWithdraw(owner, assets, maxAssets); + } + + uint256 sharesAmount = previewWithdraw(assets); + _withdraw(receiver, owner, assets, sharesAmount); + + return sharesAmount; + } + + /** + * @dev The `redeem` function is used to redeem the specified amount of + * shares in exchange of the corresponding underlying assets amount from + * owner. + * @param shares The shares amount to be converted into underlying assets. + * @param receiver The address of the shares receiver. + * @param owner The address of the owner. + * @return Amount of underlying assets received in exchange of the specified + * amount of shares. + */ + function redeem(uint256 shares, address receiver, address owner) + external + returns (uint256) + { + uint256 maxShares = maxRedeem(owner); + if (shares > maxShares) { + revert ERC4626ExceededMaxRedeem(owner, shares, maxShares); + } + + uint256 assetsAmount = previewRedeem(shares); + _withdraw(receiver, owner, assetsAmount, shares); + + return assetsAmount; + } + + /** + * @dev The `_totalAssets` function is used to return the current assets + * balance of the vault contract. + * @notice The `_totalAssets` is used to know the balance of underlying of + * the vault contract without + * taking care of any theoretical external funds of the vault. + * @return Amount of underlying assets balance actually contained into the + * vault contract. + */ + function _totalAssets() internal view returns (uint256) { + return _asset.balanceOf(address(this)); + } + + /** + * @dev Internal conversion function (from assets to shares) with support + * for rounding direction. + * @param assets Theunderlying assets amount to be converted into shares. + * @param rounding The rounding direction. + * @return Amount of shares received in exchange of the specified underlying + * assets amount. + */ + function _convertToShares(uint256 assets, Math.Rounding rounding) + internal + view + returns (uint256) + { + return assets.mulDiv( + totalSupply() + 10 ** decimalsOffset, totalAssets() + 1, rounding + ); + } + + /** + * @dev Internal conversion function (from shares to assets) with support + * for rounding direction. + * @param shares The shares amount to be converted into underlying assets. + * @param rounding The rounding direction. + * @return Amount of underlying assets received in exchange of the + * specified amount of shares. + */ + function _convertToAssets(uint256 shares, Math.Rounding rounding) + internal + view + returns (uint256) + { + return shares.mulDiv( + totalAssets() + 1, totalSupply() + 10 ** decimalsOffset, rounding + ); + } + + /** + * @dev The `_deposit` function is used to deposit the specified underlying + * assets amount in exchange of a proportionnal amount of shares. + * @param caller The address of the caller. + * @param receiver The address of the shares receiver. + * @param assets The underlying assets amount to be converted into shares. + * @param shares The shares amount to be converted into underlying assets. + */ + function _deposit( + address caller, + address receiver, + uint256 assets, + uint256 shares + ) internal { + // 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. + // + // Conclusion: we need to do the transfer before we mint so that any + // reentrancy would happen before the assets are transferred and before + // the shares are minted, which is a valid state. + // slither-disable-next-line reentrancy-no-eth + SafeERC20.safeTransferFrom(_asset, caller, address(this), assets); + _mint(receiver, shares); + + emit Deposit(caller, receiver, assets, shares); + } + + /** + * @dev The function `_withdraw` is used to withdraw the specified + * underlying assets amount in exchange of a proportionnal amount of shares by + * specifying all the params. + * @notice The `withdraw` function is used to withdraw the specified + * underlying assets amount in exchange of a proportionnal amount of shares. + * @param receiver The address of the shares receiver. + * @param owner The address of the owner. + * @param assets The underlying assets amount to be converted into shares. + * @param shares The shares amount to be converted into underlying assets. + */ + function _withdraw( + address receiver, + address owner, + uint256 assets, + uint256 shares + ) internal { + if (_msgSender() != owner) { + _spendAllowance(owner, _msgSender(), shares); + } + + _burn(owner, shares); + SafeERC20.safeTransfer(_asset, receiver, assets); + + emit Withdraw(_msgSender(), receiver, owner, assets, shares); + } + + /* + #################################### + AMPHOR SYNTHETIC RELATED FUNCTIONS + #################################### + */ + + /** + * @dev The `start` function is used to start the lock period of the vault. + * It is the only way to lock the vault. It can only be called by the owner + * of the contract (`onlyOwner` modifier). + */ + function start() external onlyOwner { + if (!vaultIsOpen) revert VaultIsLocked(); + + lastSavedBalance = _totalAssets(); + vaultIsOpen = false; + _asset.safeTransfer(owner(), lastSavedBalance); + + emit EpochStart(block.timestamp, lastSavedBalance, totalSupply()); + } + + /** + * @dev The `end` function is used to end the lock period of the vault. + * @notice The `end` function is used to end the lock period of the vault. + * It can only be called by the owner of the contract (`onlyOwner` modifier) + * and only when the vault is locked. + * If there are profits, the performance fees are taken and sent to the + * owner of the contract. + * @param assetReturned The underlying assets amount to be deposited into + * the vault. + */ + function end(uint256 assetReturned) external onlyOwner { + if (vaultIsOpen) revert VaultIsOpen(); + + uint256 fees; + + if (assetReturned > lastSavedBalance && feesInBps > 0) { + uint256 profits; + unchecked { + profits = assetReturned - lastSavedBalance; + } + fees = (profits).mulDiv(feesInBps, 10000, Math.Rounding.Up); + } + + SafeERC20.safeTransferFrom( + _asset, _msgSender(), address(this), assetReturned - fees + ); + + vaultIsOpen = true; + + emit EpochEnd( + block.timestamp, + lastSavedBalance, + assetReturned, + fees, + totalSupply() + ); + + lastSavedBalance = 0; + } + + function restruct(uint256 virtualReturnedAsset) external onlyOwner { + emit EpochEnd( + block.timestamp, + lastSavedBalance, + virtualReturnedAsset, + 0, + totalSupply() + ); + emit EpochStart(block.timestamp, lastSavedBalance, totalSupply()); + } + + /** + * @dev The `setFees` function is used to modify the protocol fees. + * @notice The `setFees` function is used to modify the perf fees. + * It can only be called by the owner of the contract (`onlyOwner` modifier). + * It can't exceed 30% (3000 in BPS). + * @param newFees The new perf fees to be applied. + */ + function setFees(uint16 newFees) external onlyOwner { + if (newFees > 3000) revert FeesTooHigh(); + feesInBps = newFees; + emit FeesChanged(feesInBps, newFees); + } + + /** + * @dev The `claimToken` function is used to claim other tokens that have + * been sent to the vault. + * @notice The `claimToken` function is used to claim other tokens that have + * been sent to the vault. + * It can only be called by the owner of the contract (`onlyOwner` modifier). + * @param token The IERC20 token to be claimed. + */ + function claimToken(IERC20 token) external onlyOwner { + if (token == _asset) revert CannotClaimAsset(); + token.safeTransfer(_msgSender(), token.balanceOf(address(this))); + } +} diff --git a/src/AmphorSyntheticVaultWithPermit.sol b/src/AmphorSyntheticVaultWithPermit.sol new file mode 100644 index 0000000..a166816 --- /dev/null +++ b/src/AmphorSyntheticVaultWithPermit.sol @@ -0,0 +1,160 @@ +//SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +/* + _______ _______ _______ _______ _______ +( ___ )( )( ____ )|\ /|( ___ )( ____ ) +| ( ) || () () || ( )|| ) ( || ( ) || ( )| +| (___) || || || || (____)|| (___) || | | || (____)| +| ___ || |(_)| || _____)| ___ || | | || __) +| ( ) || | | || ( | ( ) || | | || (\ ( +| ) ( || ) ( || ) | ) ( || (___) || ) \ \__ +|/ \||/ \||/ |/ \|(_______)|/ \__/ + _______ _ _________ _______ __________________ _______ +( ____ \|\ /|( ( /|\__ __/|\ /|( ____ \\__ __/\__ __/( ____ \ +| ( \/( \ / )| \ ( | ) ( | ) ( || ( \/ ) ( ) ( | ( \/ +| (_____ \ (_) / | \ | | | | | (___) || (__ | | | | | | +(_____ ) \ / | (\ \) | | | | ___ || __) | | | | | | + ) | ) ( | | \ | | | | ( ) || ( | | | | | | +/\____) | | | | ) \ | | | | ) ( || (____/\ | | ___) (___| (____/\ +\_______) \_/ |/ )_) )_( |/ \|(_______/ )_( \_______/(_______/ +*/ + +import "./AmphorSyntheticVault.sol"; + +/* + * @dev The `PermitParams` struct is used to pass the permit signature and data. + * @param value The amount of tokens the spender is allowed to spend. + * @param deadline The timestamp after which the permit is no longer valid. + * @param v The recovery byte of the permit signature. + * @param r Half of the ECDSA signature pair of the permit. + * @param s Half of the ECDSA signature pair of the permit. + */ +struct PermitParams { + uint256 value; + uint256 deadline; + uint8 v; + bytes32 r; + bytes32 s; +} + +contract AmphorSyntheticVaultWithPermit is AmphorSyntheticVault { + /** + * @dev The `constructor` function is used to initialize the vault. + * @param underlying The underlying asset token. + * @param name The name of the vault. + * @param symbol The symbol of the vault. + * @param _decimalsOffset The decimal offset between the asset token and the + * share token. + */ + constructor( + ERC20 underlying, + string memory name, + string memory symbol, + uint8 _decimalsOffset + ) AmphorSyntheticVault(underlying, name, symbol, _decimalsOffset) {} + + /** + * @dev The `depositWithPermit` function is used to deposit underlying assets + * into the vault using a permit for approval. + * @param assets The underlying assets amount to be converted into + * shares. + * @param receiver The address of the shares receiver. + * @param permitParams The permit struct containing the permit signature and data. + * @return Amount of shares received in exchange of the specified underlying + * assets amount. + */ + function depositWithPermit( + uint256 assets, + address receiver, + PermitParams calldata permitParams + ) external returns (uint256) { + execPermit(_msgSender(), address(this), permitParams); + return deposit(assets, receiver); + } + + /* + * @dev The `depositWithPermitMinShares` function is used to deposit + * underlying assets into the vault using a permit for approval. + * @param assets The underlying assets amount to be converted into + * shares. + * @param receiver The address of the shares receiver. + * @param minShares The minimum amount of shares to be received in exchange of + * the specified underlying assets amount. + * @param permitParams The permit struct containing the permit signature and data. + * @return Amount of shares received in exchange of the specified underlying + * assets amount. + */ + function depositWithPermitMinShares( + uint256 assets, + address receiver, + uint256 minShares, + PermitParams calldata permitParams + ) external returns (uint256) { + execPermit(_msgSender(), address(this), permitParams); + return depositMinShares(assets, receiver, minShares); + } + + /** + * @dev The `mintWithPermit` function is used to mint the specified shares + * amount in exchange of the corresponding underlying assets amount from + * `_msgSender()` using a permit for approval. + * @param shares The amount of shares to be converted into underlying assets. + * @param receiver The address of the shares receiver. + * @param permitParams The permit struct containing the permit signature and data. + * @return Amount of underlying assets deposited in exchange of the specified + * shares amount. + */ + function mintWithPermit( + uint256 shares, + address receiver, + PermitParams calldata permitParams + ) external returns (uint256) { + execPermit(_msgSender(), address(this), permitParams); + return mint(shares, receiver); + } + + /** + * @dev The `mintWithPermit` function is used to mint the specified shares + * amount in exchange of the corresponding underlying assets amount from + * `_msgSender()` using a permit for approval. + * @param shares The amount of shares to be converted into underlying assets. + * @param receiver The address of the shares receiver. + * @param maxAssets The maximum amount of underlying assets to be deposited + * in exchange of the specified shares amount. + * @param permitParams The permit struct containing the permit signature and data. + * @return Amount of underlying assets deposited in exchange of the specified + * shares amount. + */ + function mintWithPermitMaxAssets( + uint256 shares, + address receiver, + uint256 maxAssets, + PermitParams calldata permitParams + ) external returns (uint256) { + execPermit(_msgSender(), address(this), permitParams); + return mintMaxAssets(shares, receiver, maxAssets); + } + + /* + * @dev The `execPermit` function is used to execute a permit for approval. + * @param owner The owner of the funds. + * @param spender The spender of the funds. + * @param permitParams The permit struct containing the permit signature and data. + */ + function execPermit( + address owner, + address spender, + PermitParams calldata permitParams + ) internal { + ERC20Permit(address(_asset)).permit( + owner, + spender, + permitParams.value, + permitParams.deadline, + permitParams.v, + permitParams.r, + permitParams.s + ); + } +} diff --git a/src/VaultZapper.sol b/src/VaultZapper.sol new file mode 100644 index 0000000..951b060 --- /dev/null +++ b/src/VaultZapper.sol @@ -0,0 +1,311 @@ +//SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import {Ownable2Step} from + "@openzeppelin-v4.9.3/contracts/access/Ownable2Step.sol"; +import {Pausable} from "@openzeppelin-v4.9.3/contracts/security/Pausable.sol"; +import {SafeERC20} from + "@openzeppelin-v4.9.3/contracts/token/ERC20/utils/SafeERC20.sol"; +import {IERC20} from "@openzeppelin-v4.9.3/contracts/token/ERC20/ERC20.sol"; +import {IERC4626} from "@openzeppelin-v4.9.3/contracts/interfaces/IERC4626.sol"; +import {PermitParams} from "./AmphorSyntheticVaultWithPermit.sol"; +import {ERC20Permit} from + "@openzeppelin-v4.9.3/contracts/token/ERC20/extensions/ERC20Permit.sol"; + +contract VaultZapper is Ownable2Step, Pausable { + /** + * @dev The `SafeERC20` lib is only used for `safeTransfer`, + * `safeTransferFrom` and `forceApprove` operations. + */ + using SafeERC20 for IERC20; + + mapping(IERC4626 => bool) public authorizedVaults; + mapping(address => bool) public authorizedRouters; + + error NotRouter(address router); + error NotVault(IERC4626 vault); + error SwapFailed(string reason); + error InconsistantSwapData( + uint256 expectedTokenInBalance, uint256 actualTokenInBalance + ); + error NotEnoughSharesMinted(uint256 sharesMinted, uint256 minSharesMinted); + error NotEnoughUnderlying( + uint256 previewedUnderlying, uint256 withdrawedUnderlying + ); + error NullMinShares(); + + event ZapAndDeposit( + IERC4626 indexed vault, + address indexed router, + IERC20 tokenIn, + uint256 amount, + uint256 shares + ); + + event RedeemAndZap( + IERC4626 indexed vault, address indexed router, uint256 shares + ); + + event WithdrawAndZap( + IERC4626 indexed vault, address indexed router, uint256 shares + ); + + event routerApproved(address indexed router, IERC20 indexed token); + event routerAuthorized(address indexed router, bool allowed); + event vaultAuthorized(IERC4626 indexed vault, bool allowed); + event vaultApproved(IERC4626 indexed vault, address indexed asset); + + modifier onlyAllowedRouter(address router) { + if (!authorizedRouters[router]) revert NotRouter(router); + _; + } + + modifier onlyAllowedVault(IERC4626 vault) { + if (!authorizedVaults[vault]) revert NotVault(vault); + _; + } + /** + * @dev The `claimToken` function is used to claim other tokens that have + * been sent to the vault. + * @notice The `claimToken` function is used to claim other tokens that have + * been sent to the vault. + * It can only be called by the owner of the contract (`onlyOwner` modifier). + * @param token The IERC20 token to be claimed. + */ + + function withdrawToken(IERC20 token) external onlyOwner { + token.safeTransfer(_msgSender(), token.balanceOf(address(this))); + } + + function withdrawNativeToken() external onlyOwner { + payable(_msgSender()).transfer(address(this).balance); + } + + function pause() external onlyOwner { + _pause(); + } + + function unpause() external onlyOwner { + _unpause(); + } + + function approveTokenForRouter(IERC20 token, address router) + public + onlyOwner + { + token.forceApprove(address(router), type(uint256).max); + emit routerApproved(address(router), token); + } + + function toggleRouterAuthorization(address router) public onlyOwner { + bool authorized = !authorizedRouters[router]; + authorizedRouters[router] = authorized; + emit routerAuthorized(router, authorized); + } + + function toggleVaultAuthorization(IERC4626 vault) public onlyOwner { + bool authorized = !authorizedVaults[vault]; + if (authorized) _approveVault(IERC4626(vault)); + else IERC20(vault.asset()).forceApprove(address(vault), 0); + authorizedVaults[vault] = authorized; + emit vaultAuthorized(vault, authorized); + } + + function _approveVault(IERC4626 vault) internal { + IERC20(vault.asset()).forceApprove(address(vault), type(uint256).max); + emit vaultApproved(vault, vault.asset()); + } + + function zapAndDeposit( + IERC20 tokenIn, + IERC4626 vault, + address router, + uint256 amount, + uint256 minShares, + bytes calldata data + ) + public + payable + onlyAllowedRouter(router) + onlyAllowedVault(vault) + whenNotPaused + returns (uint256) + { + if (minShares == 0) revert NullMinShares(); + + uint256 expectedBalance; + + if (msg.value == 0) { + expectedBalance = tokenIn.balanceOf(address(this)); + _transferTokenInAndApprove(router, tokenIn, amount); + } else { + expectedBalance = address(this).balance - msg.value; + } + + _execute(router, data); // zap + + uint256 balanceAfterZap = msg.value == 0 + ? tokenIn.balanceOf(address(this)) + : address(this).balance; + + if (balanceAfterZap > expectedBalance) { + // Our balance is higher than expected, we shouldn't have received any token + revert InconsistantSwapData({ + expectedTokenInBalance: expectedBalance, + actualTokenInBalance: balanceAfterZap + }); + } + + uint256 shares = _depositInVault(vault); + if (shares < minShares) { + revert NotEnoughSharesMinted({ + sharesMinted: shares, + minSharesMinted: minShares + }); + } + + emit ZapAndDeposit({ + vault: vault, + router: router, + tokenIn: tokenIn, + amount: amount, + shares: shares + }); + + return shares; + } + + function _transferTokenInAndApprove( + address router, + IERC20 tokenIn, + uint256 amount + ) private { + tokenIn.safeTransferFrom(_msgSender(), address(this), amount); + if (tokenIn.allowance(_msgSender(), address(router)) < amount) { + tokenIn.forceApprove(address(router), amount); + } + } + + function _depositInVault(IERC4626 vault) private returns (uint256) { + address asset = vault.asset(); + + uint256 amount = IERC20(asset).balanceOf(address(this)); + + return vault.deposit(amount, msg.sender); + } + + function redeemAndZap( + IERC4626 vault, + address router, + uint256 shares, // shares to redeem + bytes calldata data + ) public onlyAllowedRouter(router) onlyAllowedVault(vault) whenNotPaused { + // zapper balance in term of vault underlying + uint256 balanceBeforeRedeem = + IERC20(vault.asset()).balanceOf(address(this)); + IERC4626(vault).redeem(shares, address(this), _msgSender()); + + // Once the assets are out of the vault, we can zap them into the desired asset + _execute(router, data); + + uint256 balanceAfterSwap = + IERC20(vault.asset()).balanceOf(address(this)); + + if (balanceAfterSwap > balanceBeforeRedeem) { + revert InconsistantSwapData({ + expectedTokenInBalance: balanceBeforeRedeem, + actualTokenInBalance: balanceAfterSwap + }); + } + emit RedeemAndZap(vault, router, shares); + } + + function withdrawAndZap( + IERC4626 vault, + address router, + uint256 assets, // assets amount to withdraw + bytes calldata data + ) public onlyAllowedRouter(router) onlyAllowedVault(vault) whenNotPaused { + uint256 balanceBeforeWithdraw = + IERC20(vault.asset()).balanceOf(address(this)); + vault.withdraw(assets, address(this), _msgSender()); + + // Once the assets are out of the vault, we can zap them into the desired asset + _execute(router, data); + + uint256 balanceAfterSwap = + IERC20(vault.asset()).balanceOf(address(this)); + + if (balanceAfterSwap > balanceBeforeWithdraw) { + revert InconsistantSwapData({ + expectedTokenInBalance: balanceBeforeWithdraw, + actualTokenInBalance: balanceAfterSwap + }); + } + emit WithdrawAndZap(vault, router, assets); + } + + function zapAndDepositWithPermit( + IERC20 tokenIn, + IERC4626 vault, + address router, + uint256 amount, + uint256 minShares, + bytes calldata data, + PermitParams calldata permitParams + ) public payable returns (uint256) { + _executePermit(tokenIn, _msgSender(), address(this), permitParams); + return zapAndDeposit(tokenIn, vault, router, amount, minShares, data); + } + + function redeemAndZapWithPermit( + IERC4626 vault, + address router, + uint256 shares, // shares to redeem + bytes calldata data, + PermitParams calldata permitParams + ) public { + _executePermit(IERC20(vault), _msgSender(), address(this), permitParams); + redeemAndZap(vault, router, shares, data); + } + + function withdrawAndZapWithPermit( + IERC4626 vault, + address router, + uint256 assets, // assets amount to withdraw + bytes calldata data, + PermitParams calldata permitParams + ) public { + _executePermit(IERC20(vault), _msgSender(), address(this), permitParams); + withdrawAndZap(vault, router, assets, data); + } + + function _execute(address target, bytes memory data) + private + returns (bytes memory response) + { + (bool success, bytes memory _data) = target.call{value: msg.value}(data); + if (!success) { + if (data.length > 0) revert SwapFailed(string(_data)); + else revert SwapFailed("Unknown reason"); + } + return _data; + } + + function _executePermit( + IERC20 token, + address owner, + address spender, + PermitParams calldata permitParams + ) private { + ERC20Permit(address(token)).permit( + owner, + spender, + permitParams.value, + permitParams.deadline, + permitParams.v, + permitParams.r, + permitParams.s + ); + } +} diff --git a/src/utils/Constants.sol b/src/utils/Constants.sol new file mode 100644 index 0000000..53d3fba --- /dev/null +++ b/src/utils/Constants.sol @@ -0,0 +1,115 @@ +//SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +library Constants { + bytes32 internal constant USDC_TICKER = "usdc"; + bytes32 internal constant USDT_TICKER = "usdt"; + bytes32 internal constant DAI_TICKER = "dai"; + bytes32 internal constant CRV_TICKER = "a3CRV"; + + uint256 internal constant CVX_LUSD_PID = 33; + uint256 internal constant CVX_MIM_PID = 40; + uint256 internal constant CVX_FRAX_LUSD_PID = 102; + uint256 internal constant CVX_EURT_POLYGON_PID = 5; + uint256 internal constant CVX_USDR_POLYGON_PID = 11; + + uint256 internal constant TRADE_DEADLINE = 2000; + + address internal constant FRAX_USDC_ADDRESS = + 0xDcEF968d416a41Cdac0ED8702fAC8128A64241A2; + address internal constant FRAX_USDC_LP_ADDRESS = + 0x3175Df0976dFA876431C2E9eE6Bc45b65d3473CC; + address internal constant CRV_FRAX_LUSD_ADDRESS = + 0x497CE58F34605B9944E6b15EcafE6b001206fd25; + address internal constant CRV_FRAX_LUSD_LP_ADDRESS = + 0x497CE58F34605B9944E6b15EcafE6b001206fd25; + address internal constant CVX_FRAX_LUSD_REWARDS_ADDRESS = + 0x053e1dad223A206e6BCa24C77786bb69a10e427d; + address internal constant CVX_ADDRESS = + 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B; + address internal constant CRV_ADDRESS = + 0xD533a949740bb3306d119CC777fa900bA034cd52; + address internal constant USDC_ADDRESS = + 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address internal constant USDC_ADDRESS_POLYGON = + 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174; + address internal constant USDT_ADDRESS = + 0xdAC17F958D2ee523a2206206994597C13D831ec7; + address internal constant DAI_ADDRESS = + 0x6B175474E89094C44Da98b954EedeAC495271d0F; + address internal constant WETH_ADDRESS = + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + address internal constant WETH_ADDRESS_POLYGON = + 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619; + address internal constant LUSD_ADDRESS = + 0x5f98805A4E8be255a32880FDeC7F6728C6568bA0; + address internal constant MIM_ADDRESS = + 0x99D8a9C45b2ecA8864373A26D1459e3Dff1e17F3; + + address internal constant EURT_POLYGON_ADDRESS = + 0x7BDF330f423Ea880FF95fC41A280fD5eCFD3D09f; + address internal constant USDR_POLYGON_ADDRESS = + 0xb5DFABd7fF7F83BAB83995E72A52B97ABb7bcf63; + + address internal constant SUSHI_ROUTER_ADDRESS = + 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F; + address internal constant SUSHI_CRV_WETH_ADDRESS = + 0x58Dc5a51fE44589BEb22E8CE67720B5BC5378009; + address internal constant SUSHI_WETH_CVX_ADDRESS = + 0x05767d9EF41dC40689678fFca0608878fb3dE906; + address internal constant SUSHI_WETH_USDT_ADDRESS = + 0x06da0fd433C1A5d7a4faa01111c044910A184553; + + address internal constant CVX_BOOSTER_ADDRESS = + 0xF403C135812408BFbE8713b5A23a04b3D48AAE31; + address internal constant CRV_3POOL_ADDRESS = + 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7; + address internal constant CRV_3POOL_LP_ADDRESS = + 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490; + + address internal constant CVX_BOOSTER_POLYGON_ADDRESS = + 0xF403C135812408BFbE8713b5A23a04b3D48AAE31; + address internal constant CRV_3POOL_POLYGON_ADDRESS = + 0xa138341185a9D0429B0021A11FB717B225e13e1F; + address internal constant CRV_3POOL_LP_POLYGON_ADDRESS = + 0xE7a24EF0C5e95Ffb0f6684b813A78F2a3AD7D171; + + address internal constant CRV_LUSD_ADDRESS = + 0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA; + address internal constant CRV_LUSD_LP_ADDRESS = + 0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA; + address internal constant CVX_LUSD_REWARDS_ADDRESS = + 0x2ad92A7aE036a038ff02B96c88de868ddf3f8190; + + address internal constant CRV_EURT_POLYGON_ADDRESS = + 0x600743B1d8A96438bD46836fD34977a00293f6Aa; + address internal constant CRV_EURT_LP_POLYGON_ADDRESS = + 0x600743B1d8A96438bD46836fD34977a00293f6Aa; + address internal constant CRV_EURT_POLYGON_REWARDS_ADDRESS = + 0xc501491b0e4A73B2eFBaC564a412a927D2fc83dD; + + address internal constant CRV_USDR_POLYGON_ADDRESS = + 0xa138341185a9D0429B0021A11FB717B225e13e1F; + address internal constant CRV_USDR_LP_POLYGON_ADDRESS = + 0xa138341185a9D0429B0021A11FB717B225e13e1F; + address internal constant CRV_USDR_POLYGON_REWARDS_ADDRESS = + 0x3D17b2BcfcD7E0Dc4d6a0d6bA67c29FBc592B323; + + address internal constant CRV_MIM_ADDRESS = + 0x5a6A4D54456819380173272A5E8E9B9904BdF41B; + address internal constant CRV_MIM_LP_ADDRESS = + 0x5a6A4D54456819380173272A5E8E9B9904BdF41B; + address internal constant CVX_MIM_REWARDS_ADDRESS = + 0xFd5AbF66b003881b88567EB9Ed9c651F14Dc4771; + address internal constant CVX_MIM_EXTRA_ADDRESS = + 0x69a92f1656cd2e193797546cFe2EaF32EACcf6f7; + address internal constant MIM_EXTRA_ADDRESS = + 0x090185f2135308BaD17527004364eBcC2D37e5F6; + address internal constant MIM_EXTRA_PAIR_ADDRESS = + 0xb5De0C3753b6E1B4dBA616Db82767F17513E6d4E; + + address internal constant SDT_MIM_VAULT_ADDRESS = + 0x98dd95D0ac5b70B0F4ae5080a1C2EeA8c5c48387; + address internal constant SDT_MIM_SPELL_ADDRESS = + 0x090185f2135308BaD17527004364eBcC2D37e5F6; +} diff --git a/src/utils/ConstantsBSC.sol b/src/utils/ConstantsBSC.sol new file mode 100644 index 0000000..30307fd --- /dev/null +++ b/src/utils/ConstantsBSC.sol @@ -0,0 +1,11 @@ +//SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +library ConstantsBSC { + address internal constant BUSD_ADDRESS = + 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56; + address internal constant USDT_ADDRESS = + 0x55d398326f99059fF775485246999027B3197955; + address internal constant PANCAKESWAP_ROUTER_ADDRESS = + 0x10ED43C718714eb63d5aA57B78B54704E256024E; +} diff --git a/src/utils/MockERC20.sol.bak b/src/utils/MockERC20.sol.bak new file mode 100644 index 0000000..01ddd51 --- /dev/null +++ b/src/utils/MockERC20.sol.bak @@ -0,0 +1,8 @@ +//SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import '@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol'; + +contract MockERC20 is ERC20PresetFixedSupply { + constructor() ERC20PresetFixedSupply('Token', 'TKN', 1e27, msg.sender) {} +} diff --git a/src/utils/PermitERC20.sol b/src/utils/PermitERC20.sol new file mode 100644 index 0000000..6ddd076 --- /dev/null +++ b/src/utils/PermitERC20.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "@solmate/tokens/ERC20.sol"; + +contract PermitERC20 is ERC20 { + constructor(string memory _name, string memory _symbol, uint8 _decimals) + ERC20(_name, _symbol, _decimals) + { + _mint(msg.sender, 10000 * 10 ** 6); + } + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} diff --git a/test.txt b/test.txt new file mode 100644 index 0000000..5b632ee --- /dev/null +++ b/test.txt @@ -0,0 +1 @@ +"Amphor Synthetic LP-IL Hedged (WSTETH)" "ampr-LP-ETH" 12 \ No newline at end of file diff --git a/test/Zapper/OffChainCalls.t.sol b/test/Zapper/OffChainCalls.t.sol new file mode 100644 index 0000000..f617918 --- /dev/null +++ b/test/Zapper/OffChainCalls.t.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "../../src/VaultZapper.sol"; +import "../utils/SigUtils.sol"; +import "../v0/Core/Global.t.sol"; + +struct Swap { + address router; + IERC20 tokenIn; + IERC20 tokenOut; + uint256 amount; + uint256 minAmount; + address tokenInWhale; + uint256 slippage; +} + +contract OffChainCalls is GlobalTest { + address constant _router = 0x1111111254EEB25477B68fb85Ed929f73A960582; + mapping(IERC20 => mapping(IERC20 => bytes)) callData; + + constructor() { + callData[_DAI][_WSTETH] = + hex"0502b1c50000000000000000000000006b175474e89094c44da98b954eedeac495271d0f0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000001a2ee649ee2bf0000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000100000000000000003b6d0340c5578194d457dcce3f272538d1ad52c68d1ce8498b1ccac8"; + callData[_USDC][_WSTETH] = + hex"e449022e0000000000000000000000000000000000000000000000000000000059682f0000000000000000000000000000000000000000000000000009911d9882a2ad63000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000018000000000000000000000004622df6fb2d9bee0dcdacf545acdb6a2b2f4f8638b1ccac8"; + callData[_ETH][_WSTETH] = + hex"12aa3caf000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee0000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd090000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f0000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000c1d2ee6150b37cc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007c00000000000000000000000000000000000000000000005e00003000001640607f39c581f595b53c5cb19bd0b3f8da6c935e2ca00020d6bdbf787f39c581f595b53c5cb19bd0b3f8da6c935e2ca080a06c4eca277f39c581f595b53c5cb19bd0b3f8da6c935e2ca01111111254eeb25477b68fb85ed929f73a960582000000008b1ccac8"; + callData[_USDT][_WSTETH] = + hex"12aa3caf000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd090000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f000000000000000000000000000000000000000000000000000000000098968000000000000000000000000000000000000000000000000000103c4cfaf70b37000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000001570001290000df00a007e5c0d20000000000000000000000000000000000000000bb0000a100008b00004f02a0000000000000000000000000000000000000000000000000001269c19b68d8e1ee63c1e5109fcf8f5bd54db123470c96620441ca5c342a8bd4dac17f958d2ee523a2206206994597c13d831ec74101c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200042e1a7d4d000000000000000000000000000000000000000000000000000000000000000040607f39c581f595b53c5cb19bd0b3f8da6c935e2ca00020d6bdbf787f39c581f595b53c5cb19bd0b3f8da6c935e2ca000a0f2fa6b667f39c581f595b53c5cb19bd0b3f8da6c935e2ca000000000000000000000000000000000000000000000000000103c4f1bbda1d1000000000000000000082e941bcc487d80a06c4eca277f39c581f595b53c5cb19bd0b3f8da6c935e2ca01111111254eeb25477b68fb85ed929f73a96058200000000000000000000008b1ccac8"; + callData[_WBTC][_WSTETH] = + hex"e449022e0000000000000000000000000000000000000000000000000000000002faf0800000000000000000000000000000000000000000000000006fab3a94493005e1000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000020000000000000000000000004585fe77225b41b697c938b018e2ac67ac5a20c0800000000000000000000000109830a1aaad605bbf02a9dfa7b0b92ec2fb7daa8b1ccac8"; + callData[_STETH][_WSTETH] = + hex"12aa3caf000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09000000000000000000000000ae7ab96520de3a18e5e111b5eaab095312d7fe840000000000000000000000007f39c581f595b53c5cb19bd0b3f8da6c935e2ca0000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd090000000000000000000000005615deb798bb3e4dfa0139dfa1b3d433cc23b72f0000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000079246bd50806299c000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b600000000000000000000000000000000000000000000009800006a00005051207f39c581f595b53c5cb19bd0b3f8da6c935e2ca0ae7ab96520de3a18e5e111b5eaab095312d7fe840004ea598cb000000000000000000000000000000000000000000000000000000000000000000020d6bdbf787f39c581f595b53c5cb19bd0b3f8da6c935e2ca080a06c4eca277f39c581f595b53c5cb19bd0b3f8da6c935e2ca01111111254eeb25477b68fb85ed929f73a960582000000000000000000008b1ccac8"; + } + + // function _getSavedSwapData(Swap memory swap) + // public + // view + // returns (bytes memory) + // { + // return callData[swap.tokenIn][swap.tokenOut]; + // } + + function _getSwapData(address from, address to, Swap memory swap) + public + returns (bytes memory) + { + string[] memory inputs = new string[](8); + inputs[0] = "node"; + inputs[1] = "./test/scripts/getOneInchQuote.js"; + inputs[2] = vm.toString(from); + inputs[3] = vm.toString(to); + inputs[4] = vm.toString(address(swap.tokenIn)); + inputs[5] = vm.toString(address(swap.tokenOut)); + inputs[6] = vm.toString(swap.amount); + inputs[7] = vm.toString(swap.slippage); + + bytes memory res = vm.ffi(inputs); + + return res; + } +} diff --git a/test/Zapper/ZapperDeposit.t.sol b/test/Zapper/ZapperDeposit.t.sol new file mode 100644 index 0000000..bb75094 --- /dev/null +++ b/test/Zapper/ZapperDeposit.t.sol @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "../../src/VaultZapper.sol"; +import "./OffChainCalls.t.sol"; + +contract VaultZapperDeposit is OffChainCalls { + VaultZapper zapper; + SigUtils internal sigUtils; + uint256 userPrivateKey = _usersPk[0]; + address user = _users[0]; + + using SafeERC20 for IERC20; + + function setUp() public { + zapper = new VaultZapper(); + } + + function test_zapAndDepositUsdcWSTETH() public { + Swap memory usdcToWstEth = + Swap(_router, _USDC, _WSTETH, 1500 * 1e6, 1, address(0), 20); + _zapAndDeposit(usdcToWstEth); + } + + function test_failZapAndDepositUsdcWSTETHUnknownReason() public { + Swap memory usdcToWstEth = + Swap(_router, _USDC, _WSTETH, 150000000 * 1e6, 1, address(0), 0); + _failZapAndDeposit(usdcToWstEth, 150000000 * 1e6); + } + + function test_failZapAndDepositERC20PlusEth() public { + Swap memory usdcToWstEth = + Swap(_router, _USDC, _WSTETH, 1500 * 1e6, 1, address(0), 30); + _failZapAndDeposit_eth(usdcToWstEth, 1500 * 1e6); + } + + function test_inconsistantZapAndDepositUsdcWSTETH() public { + Swap memory usdcToWstEth = Swap( + _router, + IERC20(_USDC), + IERC20(_WSTETH), + 1000 * 1e6, + 1, + address(0), + 20 + ); + _failZapAndDeposit(usdcToWstEth, 1500 * 1e6); + } + + function test_failZapAndDepositUsdcWSTETH() public { + Swap memory usdcToWstEth = Swap( + _router, + IERC20(_USDC), + IERC20(_WSTETH), + 1000 * 1e6, + type(uint256).max, + address(0), + 20 + ); + _failZapAndDeposit(usdcToWstEth, 1500 * 1e6); + } + + function test_zapAndDepositEthWSTETH() public { + Swap memory ethToWstEth = + Swap(_router, _ETH, _WSTETH, 1e18, 1, address(0), 200); + _zapAndDeposit_eth(ethToWstEth); + } + + function test_inconsistantZapAndDepositEthWSTETH() public { + Swap memory ethToWstEth = Swap( + _router, IERC20(_ETH), IERC20(_WSTETH), 1e18, 1, address(0), 10000 + ); + _failZapAndDeposit_eth(ethToWstEth, 2e18); + } + + function test_inconsistantZapAndDepositEthWSTETHNullShares() public { + Swap memory ethToWstEth = Swap( + _router, IERC20(_ETH), IERC20(_WSTETH), 1e18, 0, address(0), 10000 + ); + _failZapAndDeposit_eth(ethToWstEth, 2e18); + } + + function test_inconsistantZapAndDepositUsdcWSTETHNullShares() public { + Swap memory usdcToWstEth = Swap( + _router, + IERC20(_USDC), + IERC20(_WSTETH), + 1000 * 1e6, + 0, + address(0), + 20 + ); + _failZapAndDeposit(usdcToWstEth, 1500 * 1e6); + } + + function _zapAndDeposit(Swap memory params) public { + bytes memory swapData = + _getSwapData(address(zapper), address(zapper), params); + _setUpVaultAndZapper(params.tokenOut); + _getTokenIn(params); + uint256 beforeDep = _vault.balanceOf(address(this)); + if (keccak256(swapData) == keccak256(hex"")) vm.expectRevert(); + zapper.zapAndDeposit( + params.tokenIn, + _vault, + params.router, + params.amount, + params.minAmount, + swapData + ); + uint256 afterDep = _vault.balanceOf(address(this)); + if (keccak256(swapData) != keccak256(hex"")) + assertTrue(afterDep > beforeDep, "Deposit failed"); + } + + function _failZapAndDeposit(Swap memory params, uint256 amount) public { + bytes memory swapData = + _getSwapData(address(zapper), address(zapper), params); + _setUpVaultAndZapper(params.tokenOut); + _getTokenIn(params); + vm.expectRevert(); + zapper.zapAndDeposit( + params.tokenIn, + _vault, + params.router, + amount, + params.minAmount, + swapData + ); + } + + function _zapAndDeposit_eth(Swap memory params) public { + bytes memory swapData = + _getSwapData(address(zapper), address(zapper), params); + _setUpVaultAndZapper(params.tokenOut); + _getTokenIn(params); + uint256 beforeDep = _vault.balanceOf(address(this)); + if (keccak256(swapData) == keccak256(hex"")) vm.expectRevert(); + zapper.zapAndDeposit{value: params.amount}( + params.tokenIn, _vault, params.router, params.amount, params.minAmount, swapData + ); + uint256 afterDep = _vault.balanceOf(address(this)); + if (keccak256(swapData) != keccak256(hex"")) + assertTrue(afterDep > beforeDep, "Deposit failed"); + } + + function _failZapAndDeposit_eth(Swap memory params, uint256 amount) + public + { + bytes memory swapData = _getSwapData(address(zapper), address(zapper), params); + _setUpVaultAndZapper(params.tokenOut); + _getTokenIn(params); + vm.expectRevert(); + zapper.zapAndDeposit{value: amount}( + params.tokenIn, _vault, params.router, params.amount, params.minAmount, swapData + ); + } + + function test_fail_zapAndDeposit_NotEnoughShares() public { + Swap memory params = Swap( + _router, + IERC20(_USDC), + IERC20(_WSTETH), + 1500 * 1e6, + type(uint256).max, + address(0), + 100 + ); + bytes memory swapData = _getSwapData(address(zapper), address(zapper), params); + _setUpVaultAndZapper(params.tokenOut); + _getTokenIn(params); + uint256 beforeDepTokenIn = + (IERC20(address(params.tokenIn)).balanceOf(address(this))); + + uint256 value = params.tokenIn == IERC20(_ETH) ? params.amount : 0; + vm.expectRevert(); + zapper.zapAndDeposit{value: value}( + params.tokenIn, + _vault, + params.router, + params.amount, + params.minAmount, + swapData + ); + uint256 afterDepTokenIn = + (IERC20(address(params.tokenIn)).balanceOf(address(this))); + assertTrue(afterDepTokenIn == beforeDepTokenIn, "Deposit failed"); + } + + function test_fail_zapAndDeposit_RouterFails() public { + Swap memory params = Swap( + _router, + IERC20(_USDC), + IERC20(_WSTETH), + 1500 * 1e6, + type(uint256).max, + address(0), + 100 + ); + bytes memory swapData = _getSwapData(address(zapper), address(zapper), params); + if (keccak256(swapData) != keccak256(hex"")) swapData[0] = hex"00"; + _setUpVaultAndZapper(params.tokenOut); + _getTokenIn(params); + uint256 beforeDepTokenIn = + (IERC20(address(params.tokenIn)).balanceOf(address(this))); + + uint256 value = params.tokenIn == IERC20(_ETH) ? params.amount : 0; + vm.expectRevert(); + zapper.zapAndDeposit{value: value}( + params.tokenIn, + _vault, + params.router, + params.amount, + params.minAmount, + swapData + ); + uint256 afterDepTokenIn = + (IERC20(address(params.tokenIn)).balanceOf(address(this))); + assertTrue(afterDepTokenIn == beforeDepTokenIn, "Deposit failed"); + } + + function _setUpVaultAndZapper(IERC20 asset) public { + _vault = new AmphorSyntheticVault(ERC20(address(asset)), "", "", 12); + if (!zapper.authorizedRouters(_router)) { + zapper.toggleRouterAuthorization(_router); + } + if (!zapper.authorizedVaults(_vault)) { + zapper.toggleVaultAuthorization(_vault); + } + zapper.approveTokenForRouter(IERC20(_vault.asset()), _router); + } + + function _getTokenIn(Swap memory params) public { + if (params.tokenIn != _ETH) { + if (params.tokenInWhale == address(0)) { + deal(address(params.tokenIn), address(this), 1000 * 1e18); + } else { + vm.prank(params.tokenInWhale); + SafeERC20.safeTransfer( + params.tokenIn, address(this), 1000 * 1e18 + ); + } + SafeERC20.forceApprove( + IERC20(params.tokenIn), address(zapper), type(uint256).max + ); + } + deal(address(this), 1000 * 1e18); + } +} diff --git a/test/Zapper/ZapperDepositPermit.t.sol b/test/Zapper/ZapperDepositPermit.t.sol new file mode 100644 index 0000000..cee7802 --- /dev/null +++ b/test/Zapper/ZapperDepositPermit.t.sol @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "../../src/VaultZapper.sol"; +import "../utils/SigUtils.sol"; +import "./OffChainCalls.t.sol"; + +contract SyntheticZapperPermitTest is OffChainCalls { + VaultZapper zapper; + SigUtils internal sigUtils; + uint256 userPrivateKey = 0xA11CE; + address user = vm.addr(userPrivateKey); + + function setUp() public { + zapper = new VaultZapper(); + } + + function test_zapAndDepositPermit_USDCWSTETH() public { + _zapAndDepositPermit( + Swap( + _router, + IERC20(_USDC), + IERC20(_WSTETH), + 15 * 1e6, + 0, + address(0), + 10000 + ) + ); + } + + function _zapAndDepositPermit(Swap memory params) public { + ERC20Permit token = ERC20Permit(address(params.tokenIn)); + sigUtils = new SigUtils(token.DOMAIN_SEPARATOR()); + bytes memory swapData = _getSwapData(address(zapper), address(zapper), params); + _setUpVaultAndZapper(params.tokenOut); + _getTokenIn(params, user); + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: user, + spender: address(zapper), + value: params.amount, + nonce: 0, + deadline: block.timestamp + 1 days + }); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(zapper), permit.value, permit.nonce, permit.deadline + ); + + PermitParams memory permitParams = PermitParams({ + value: permit.value, + deadline: block.timestamp + 1 days, + v: v, + r: r, + s: s + }); + + // execPermit(user, address(zapper), address(params.tokenIn), permitParams); + + uint256 beforeDep = (IERC20(address(_vault)).balanceOf(user)); + console.log("Shares balance before deposit", beforeDep); + + vm.prank(user); + + if (keccak256(swapData) == keccak256(hex"")) vm.expectRevert(); + zapper.zapAndDepositWithPermit( + params.tokenIn, + _vault, + params.router, + params.amount, + 1, + swapData, + permitParams + ); + + uint256 afterDep = (IERC20(address(_vault)).balanceOf(user)); + console.log("Shares balance after deposit", afterDep); + + if (keccak256(swapData) != keccak256(hex"")) + assertTrue(afterDep > beforeDep, "Deposit permit failed"); + } + + function execPermit( + address owner, + address spender, + address token, + PermitParams memory permitParams + ) internal { + ERC20Permit(address(token)).permit( + owner, + spender, + permitParams.value, + permitParams.deadline, + permitParams.v, + permitParams.r, + permitParams.s + ); + } + + function _signPermit( + address _spender, + uint256 _value, + uint256 _nonce, + uint256 deadline + ) internal view returns (uint8 v, bytes32 r, bytes32 s) { + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: user, + spender: _spender, + value: _value, + nonce: _nonce, + deadline: deadline + }); + bytes32 digest = sigUtils.getTypedDataHash(permit); + (v, r, s) = vm.sign(userPrivateKey, digest); + return (v, r, s); + } + + function _setUpVaultAndZapper(IERC20 tokenOut) public { + _vault = new AmphorSyntheticVault(ERC20(address(tokenOut)), "", "", 12); + if (!zapper.authorizedRouters(_router)) { + zapper.toggleRouterAuthorization(_router); + } + if (!zapper.authorizedVaults(_vault)) { + zapper.toggleVaultAuthorization(_vault); + } + } + + function _getTokenIn(Swap memory params, address receiver) public { + if (params.tokenIn != _ETH) { + if (params.tokenInWhale == address(0)) { + deal(address(params.tokenIn), receiver, 1000 * 1e18); + } else { + vm.prank(params.tokenInWhale); + SafeERC20.safeTransfer(params.tokenIn, receiver, 1000 * 1e18); + } + SafeERC20.forceApprove( + IERC20(params.tokenIn), address(zapper), type(uint256).max + ); + } + deal(receiver, 1000 * 1e18); + } +} diff --git a/test/Zapper/ZapperManagement.t.sol b/test/Zapper/ZapperManagement.t.sol new file mode 100644 index 0000000..031fc03 --- /dev/null +++ b/test/Zapper/ZapperManagement.t.sol @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "../../src/VaultZapper.sol"; +import "./OffChainCalls.t.sol"; + +contract VaultZapperManagement is OffChainCalls { + VaultZapper zapper; + SigUtils internal sigUtils; + uint256 userPrivateKey = _usersPk[0]; + address user = _users[0]; + + using SafeERC20 for IERC20; + + function setUp() public { + zapper = new VaultZapper(); + } + + function test_removeVaultAuthorization() public { + _setUpVaultAndZapper(_WSTETH); + uint256 allowanceBeforeDisabling = + _WSTETH.allowance(address(zapper), address(_vault)); + zapper.toggleVaultAuthorization(_vault); + uint256 allowanceAfterDisabling = + _WSTETH.allowance(address(zapper), address(_vault)); + assertTrue( + allowanceBeforeDisabling > 0 && allowanceAfterDisabling == 0, + "Router disabling failed" + ); + } + + function test_fail_removeVaultAuthorization_notOwner() public { + _setUpVaultAndZapper(_WSTETH); + vm.startPrank(user); + vm.expectRevert(); + zapper.toggleVaultAuthorization(_vault); + } + + function test_withdrawToken() public { + _setUpVaultAndZapper(_WSTETH); + uint256 amount = _USDT.balanceOf(address(this)); + deal(address(_USDT), address(zapper), 1000 * 1e6); + zapper.withdrawToken(_USDT); + uint256 amountAfter = _USDT.balanceOf(address(this)); + assertTrue(amount < amountAfter, "No dust collected"); + } + + function test_failWithdrawToken_notOwner() public { + _setUpVaultAndZapper(_WSTETH); + vm.startPrank(user); + vm.expectRevert(); + zapper.withdrawToken(_USDT); + } + + function test_withdrawNativeToken() public { + _setUpVaultAndZapper(_WSTETH); + uint256 amount = address(this).balance; + deal(address(zapper), 1000 * 1e6); + zapper.withdrawNativeToken(); + uint256 amountAfter = address(this).balance; + assertTrue(amount < amountAfter, "No dust collected"); + } + + function test_fail_withdrawNativeToken_notOwner() public { + _setUpVaultAndZapper(_WSTETH); + vm.startPrank(user); + vm.expectRevert(); + zapper.withdrawNativeToken(); + } + + function test_pauseZapper() public { + zapper.pause(); + assertTrue(zapper.paused(), "Zapper not paused"); + } + + function test_fail_pauseZapper_notOwner() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.pause(); + } + + function test_fail_unpauseZapper() public { + vm.expectRevert(); + zapper.unpause(); + } + + function test_fail_unpauseZapper_notOwner() public { + zapper.pause(); + vm.startPrank(user); + vm.expectRevert(); + zapper.unpause(); + } + + function test_unpauseZapper() public { + zapper.pause(); + zapper.unpause(); + assertTrue(!zapper.paused(), "Zapper not unpaused"); + } + + function test_fail_approveTokenForRouter_notOwner() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.approveTokenForRouter(_WSTETH, _router); + } + + function test_fail_toggleRouterAuthorization_notOwner() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.toggleRouterAuthorization(_router); + } + + function _setUpVaultAndZapper(IERC20 tokenOut) public { + _vault = new AmphorSyntheticVault(ERC20(address(tokenOut)), "", "", 12); + if (!zapper.authorizedRouters(_router)) { + zapper.toggleRouterAuthorization(_router); + } + if (!zapper.authorizedVaults(_vault)) { + zapper.toggleVaultAuthorization(_vault); + } + } + + function _getTokenIn(Swap memory params) public { + if (params.tokenIn != _ETH) { + if (params.tokenInWhale == address(0)) { + deal(address(params.tokenIn), address(this), 1000 * 1e18); + } else { + vm.prank(params.tokenInWhale); + SafeERC20.safeTransfer( + params.tokenIn, address(this), 1000 * 1e18 + ); + } + SafeERC20.forceApprove( + IERC20(params.tokenIn), address(zapper), type(uint256).max + ); + } + deal(address(this), 1000 * 1e18); + } + + receive() external payable {} + + +} diff --git a/test/Zapper/ZapperOnlyAllowedRouter.t.sol b/test/Zapper/ZapperOnlyAllowedRouter.t.sol new file mode 100644 index 0000000..1c4415e --- /dev/null +++ b/test/Zapper/ZapperOnlyAllowedRouter.t.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "../../src/VaultZapper.sol"; +import "./OffChainCalls.t.sol"; +import "../utils/SigUtils.sol"; + +contract VaultZapperOnlyAllowedRouter is OffChainCalls { + VaultZapper zapper; + SigUtils internal sigUtils; + uint256 userPrivateKey = _usersPk[0]; + address user = _users[0]; + + using SafeERC20 for IERC20; + + function setUp() public { + zapper = new VaultZapper(); + // _setUpVaultAndZapper(); + } + + function test_fail_withdrawAndZapNotAllowedRouter() public { + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + VaultZapper.NotRouter.selector, IERC4626(address(0)) + ) + ); + zapper.withdrawAndZap(IERC4626(address(0)), address(0), 1 * 1e18, ""); + } + + function test_fail_withdrawAndZapWithPermitNotAllowedRouter() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.withdrawAndZapWithPermit( + IERC4626(address(0)), + address(0), + 1 * 1e18, + "", + PermitParams({r: "", s: "", v: 0, value: 0, deadline: 0}) + ); + } + + function test_fail_zapAndDepositNotAllowedRouter() public { + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + VaultZapper.NotRouter.selector, IERC4626(address(0)) + ) + ); + zapper.zapAndDeposit( + IERC20(_USDC), IERC4626(address(0)), address(0), 1 * 1e18, 0, "" + ); + } + + function test_fail_zapAndDepositWithPermitNotAllowedRouter() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.zapAndDepositWithPermit( + IERC20(_USDC), + IERC4626(address(0)), + address(0), + 1 * 1e18, + 0, + "", + PermitParams({r: "", s: "", v: 0, value: 0, deadline: 0}) + ); + } + + function test_fail_redeemAndZapNotAllowedRouter() public { + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + VaultZapper.NotRouter.selector, IERC4626(address(0)) + ) + ); + zapper.redeemAndZap(IERC4626(address(0)), address(0), 1 * 1e18, ""); + } + + function test_fail_redeemAndZapWithPermitNotAllowedRouter() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.redeemAndZapWithPermit( + IERC4626(address(0)), + address(0), + 1 * 1e18, + "", + PermitParams({r: "", s: "", v: 0, value: 0, deadline: 0}) + ); + } + + // function _setUpVaultAndZapper() public { + // // IERC4626(address(0)) = new AmphorSyntheticVault(ERC20(address(asset)), "", "", 12); + // if (!zapper.authorizedRouters(address(0))) { + // zapper.toggleRouterAuthorization(address(0)); + // } + // } +} diff --git a/test/Zapper/ZapperOnlyAllowedVault.t.sol b/test/Zapper/ZapperOnlyAllowedVault.t.sol new file mode 100644 index 0000000..1fd9c19 --- /dev/null +++ b/test/Zapper/ZapperOnlyAllowedVault.t.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "../../src/VaultZapper.sol"; +import "./OffChainCalls.t.sol"; +import "../utils/SigUtils.sol"; + +contract VaultZapperOnlyAllowedVault is OffChainCalls { + VaultZapper zapper; + SigUtils internal sigUtils; + uint256 userPrivateKey = _usersPk[0]; + address user = _users[0]; + + using SafeERC20 for IERC20; + + function setUp() public { + zapper = new VaultZapper(); + _setUpVaultAndZapper(); + } + + function test_fail_withdrawAndZapNotAllowedVault() public { + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + VaultZapper.NotVault.selector, IERC4626(address(0)) + ) + ); + zapper.withdrawAndZap(IERC4626(address(0)), _router, 1 * 1e18, ""); + } + + function test_fail_withdrawAndZapWithPermitNotAllowedRouter() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.withdrawAndZapWithPermit( + IERC4626(address(0)), + _router, + 1 * 1e18, + "", + PermitParams({r: "", s: "", v: 0, value: 0, deadline: 0}) + ); + } + + function test_fail_zapAndDepositNotAllowedVault() public { + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + VaultZapper.NotVault.selector, IERC4626(address(0)) + ) + ); + zapper.zapAndDeposit( + IERC20(_USDC), IERC4626(address(0)), _router, 1 * 1e18, 0, "" + ); + } + + function test_fail_zapAndDepositWithPermitNotAllowedVault() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.zapAndDepositWithPermit( + IERC20(_USDC), + IERC4626(address(0)), + _router, + 1 * 1e18, + 0, + "", + PermitParams({r: "", s: "", v: 0, value: 0, deadline: 0}) + ); + } + + function test_fail_redeemAndZapNotAllowedVault() public { + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + VaultZapper.NotVault.selector, IERC4626(address(0)) + ) + ); + zapper.redeemAndZap(IERC4626(address(0)), _router, 1 * 1e18, ""); + } + + function test_fail_redeemAndZapWithPermitNotAllowedVault() public { + vm.startPrank(user); + vm.expectRevert(); + zapper.redeemAndZapWithPermit( + IERC4626(address(0)), + _router, + 1 * 1e18, + "", + PermitParams({r: "", s: "", v: 0, value: 0, deadline: 0}) + ); + } + + function _setUpVaultAndZapper() public { + // IERC4626(address(0)) = new AmphorSyntheticVault(ERC20(address(asset)), "", "", 12); + if (!zapper.authorizedRouters(_router)) { + zapper.toggleRouterAuthorization(_router); + } + } +} diff --git a/test/Zapper/ZapperWithdraw.t.sol b/test/Zapper/ZapperWithdraw.t.sol new file mode 100644 index 0000000..0a620e8 --- /dev/null +++ b/test/Zapper/ZapperWithdraw.t.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "./OffChainCalls.t.sol"; + +contract ZapperWithdrawTest is OffChainCalls { + VaultZapper zapper; + SigUtils internal sigUtils; + uint256 userPrivateKey = _usersPk[0]; + address user = _users[0]; + + function setUp() public { + zapper = new VaultZapper(); + _setUpVaultAndZapper(IERC20(vm.envAddress("WSTETH_MAINNET"))); + } + + function _setUpVaultAndZapper(IERC20 tokenIn) public { + _vault = new AmphorSyntheticVault(ERC20(address(tokenIn)), "", "", 12); + + if (!zapper.authorizedRouters(_router)) { + zapper.toggleRouterAuthorization(_router); + } + + if (!zapper.authorizedVaults(_vault)) { + zapper.toggleVaultAuthorization(_vault); + } + } + + function dealEverybody(uint256 assets) public { + deal(vm.envAddress("WSTETH_MAINNET"), address(this), assets); + IERC20(vm.envAddress("WSTETH_MAINNET")).approve( + address(_vault), type(uint256).max + ); + _vault.deposit(assets, address(this)); + deal(address(this), 1000 * 1e18); // get some eth + } + + function test_withdrawAndZapDAI() public { + _vault.approve(address(zapper), type(uint256).max); + + dealEverybody(1 * 1e18); + + Swap memory wstEthToDai = Swap( + _router, + ERC20(vm.envAddress("WSTETH_MAINNET")), + IERC20(vm.envAddress("DAI_MAINNET")), + 1 * 1e18, + 0, + address(0), + 30 + ); + + _withdrawAndZap(wstEthToDai); + } + + function test_inconsistantWithdrawAndZapDAI() public { + _vault.approve(address(zapper), type(uint256).max); + + dealEverybody(2 * 1e18); + + Swap memory wstEthToDai = Swap( + _router, + ERC20(vm.envAddress("WSTETH_MAINNET")), + IERC20(vm.envAddress("DAI_MAINNET")), + 1 * 1e18, + 0, + address(0), + 30 + ); + + _failWithdrawAndZap(wstEthToDai, 2 * 1e18); + } + + function test_redeemAndZapDAI() public { + _vault.approve(address(zapper), type(uint256).max); + + dealEverybody(1 * 1e18); + uint256 previewedRedeem = + _vault.previewRedeem(_vault.balanceOf(address(this))); + console.log("previewedRedeem_value", previewedRedeem); + + Swap memory wstEthToDai = Swap( + _router, + ERC20(vm.envAddress("WSTETH_MAINNET")), + IERC20(vm.envAddress("DAI_MAINNET")), + previewedRedeem, + 0, + address(0), + 30 + ); + + _redeemAndZap(wstEthToDai); + } + + function test_inconsistantRedeemAndZapDAI() public { + _vault.approve(address(zapper), type(uint256).max); + + dealEverybody(2 * 1e18); + uint256 previewedRedeem = + _vault.previewRedeem(_vault.balanceOf(address(this)) / 2); + console.log("previewedRedeem_value", previewedRedeem); + + Swap memory wstEthToDai = Swap( + _router, + ERC20(vm.envAddress("WSTETH_MAINNET")), + IERC20(vm.envAddress("DAI_MAINNET")), + previewedRedeem, + 0, + address(0), + 30 + ); + + _failRedeemAndZap(wstEthToDai); + } + + function _withdrawAndZap(Swap memory params) public { + bytes memory swapData = + _getSwapData(address(zapper), address(this), params); + + _vault.approve(address(zapper), type(uint256).max); + + uint256 beforeWith = (_vault.balanceOf(address(this))); + uint256 zappedBefore = IERC20(params.tokenOut).balanceOf(address(this)); + + zapper.approveTokenForRouter(params.tokenIn, params.router); + + if (keccak256(swapData) == keccak256(hex"")) vm.expectRevert(); + zapper.withdrawAndZap(_vault, _router, 1 * 1e18, swapData); + + uint256 afterWith = (_vault.balanceOf(address(this))); + uint256 zappedAfter = IERC20(params.tokenOut).balanceOf(address(this)); + console.log("beforeWith", beforeWith); + console.log("afterWith", afterWith); + console.log("zappedBefore", zappedBefore); + console.log("zappedAfter", zappedAfter); + + if (keccak256(swapData) != keccak256(hex"")) { + assertTrue(beforeWith > afterWith, "Withdraw failed"); + assertTrue( + zappedBefore < zappedAfter, + "Zap failed because no tokens were received" + ); + } + } + + function _failWithdrawAndZap(Swap memory params, uint256 amount) public { + bytes memory swapData = + _getSwapData(address(zapper), address(this), params); + + _vault.approve(address(zapper), type(uint256).max); + + zapper.approveTokenForRouter(params.tokenIn, params.router); + vm.expectRevert(); + zapper.withdrawAndZap(_vault, _router, amount, swapData); + } + + function _redeemAndZap(Swap memory params) public { + bytes memory swapData = + _getSwapData(address(zapper), address(this), params); + + _vault.approve(address(zapper), type(uint256).max); + + uint256 beforeRedeem = (_vault.balanceOf(address(this))); + uint256 zappedBefore = IERC20(params.tokenOut).balanceOf(address(this)); + + zapper.approveTokenForRouter(params.tokenIn, params.router); + + uint256 sharesBalance = _vault.balanceOf(address(this)); + if (keccak256(swapData) == keccak256(hex"")) vm.expectRevert(); + zapper.redeemAndZap(_vault, _router, sharesBalance, swapData); + uint256 afterRedeem = (_vault.balanceOf(address(this))); + uint256 zappedAfter = IERC20(params.tokenOut).balanceOf(address(this)); + console.log("beforeWith", beforeRedeem); + console.log("afterWith", afterRedeem); + console.log("zappedBefore", zappedBefore); + console.log("zappedAfter", zappedAfter); + + if (keccak256(swapData) != keccak256(hex"")) { + assertTrue(beforeRedeem > afterRedeem, "Redeem failed"); + assertTrue( + zappedBefore < zappedAfter, + "Zap failed because no tokens were received" + ); + } + } + + function _failRedeemAndZap(Swap memory params) public { + bytes memory swapData = + _getSwapData(address(zapper), address(this), params); + + _vault.approve(address(zapper), type(uint256).max); + + zapper.approveTokenForRouter(params.tokenIn, params.router); + + uint256 assets = _vault.balanceOf(address(this)); + + vm.expectRevert(); + zapper.redeemAndZap(_vault, _router, assets, swapData); + } +} diff --git a/test/Zapper/ZapperWithdrawPermit.sol b/test/Zapper/ZapperWithdrawPermit.sol new file mode 100644 index 0000000..8455eec --- /dev/null +++ b/test/Zapper/ZapperWithdrawPermit.sol @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "../../src/VaultZapper.sol"; +import "../utils/SigUtils.sol"; +import "./OffChainCalls.t.sol"; + +contract ZapperWithdrawPermitTest is OffChainCalls { + VaultZapper zapper; + SigUtils internal sigUtils; + uint256 userPrivateKey = 0xA11CE; + address user = vm.addr(userPrivateKey); + + function setUp() public { + zapper = new VaultZapper(); + _setUpVaultAndZapper(IERC20(vm.envAddress("WSTETH_MAINNET"))); + } + + function test_withdrawAndZapPermit_WSTETHUSDC() public { + zapper.approveTokenForRouter(_WSTETH, _router); + vm.startPrank(user); + _withdrawAndZapPermit( + Swap( + _router, + IERC20(_WSTETH), + IERC20(_USDC), + 1 * 1e18, + 0, + address(0), + 20 + ) + ); + vm.stopPrank(); + } + + function test_redeemAndZapPermit_WSTETHUSDC() public { + zapper.approveTokenForRouter(_WSTETH, _router); + vm.startPrank(user); + dealEverybody(1 * 1e18); + _redeemAndZapPermit( + Swap( + _router, + IERC20(_WSTETH), + IERC20(_USDC), + _vault.previewRedeem(_vault.balanceOf(user)), + 0, + address(0), + 20 + ) + ); + vm.stopPrank(); + } + + function dealEverybody(uint256 assets) public { + deal(vm.envAddress("WSTETH_MAINNET"), user, assets); + IERC20(vm.envAddress("WSTETH_MAINNET")).approve( + address(_vault), type(uint256).max + ); + _vault.deposit(assets, user); + deal(user, 1000 * 1e18); // get some eth + } + + function _withdrawAndZapPermit(Swap memory params) public { + ERC20Permit shareToken = ERC20Permit(address(_vault)); + sigUtils = new SigUtils(shareToken.DOMAIN_SEPARATOR()); + bytes memory swapData = _getSwapData(address(zapper), user, (params)); + dealEverybody(1 * 1e18); + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: user, + spender: address(zapper), + value: _vault.balanceOf(user), + nonce: 0, + deadline: block.timestamp + 1 days + }); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(zapper), permit.value, permit.nonce, permit.deadline + ); + + PermitParams memory permitParams = PermitParams({ + value: permit.value, + deadline: block.timestamp + 1 days, + v: v, + r: r, + s: s + }); + + //execPermit(user, address(zapper), address(_vault), permitParams); + + uint256 beforeWith = (IERC20(address(_vault)).balanceOf(user)); + uint256 beforeZap = (IERC20(address(params.tokenOut)).balanceOf(user)); + + if (keccak256(swapData) == keccak256(hex"")) vm.expectRevert(); + zapper.withdrawAndZapWithPermit( + _vault, params.router, params.amount, swapData, permitParams + ); + + uint256 afterWith = (IERC20(address(_vault)).balanceOf(user)); + uint256 afterZap = (IERC20(address(params.tokenOut)).balanceOf(user)); + + if (keccak256(swapData) != keccak256(hex"")) { + assertTrue(beforeWith > afterWith, "Deposit permit failed"); + assertTrue( + beforeZap < afterZap, + "Deposit permit failed because no token received" + ); + } + } + + function _redeemAndZapPermit(Swap memory params) public { + ERC20Permit shareToken = ERC20Permit(address(_vault)); + _vault.approve(address(zapper), type(uint256).max); + sigUtils = new SigUtils(shareToken.DOMAIN_SEPARATOR()); + bytes memory swapData = _getSwapData(address(zapper), user, params); + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: user, + spender: address(zapper), + value: _vault.balanceOf(user), + nonce: 0, + deadline: block.timestamp + 1 days + }); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(zapper), permit.value, permit.nonce, permit.deadline + ); + + PermitParams memory permitParams = PermitParams({ + value: permit.value, + deadline: block.timestamp + 1 days, + v: v, + r: r, + s: s + }); + + //execPermit(user, address(zapper), address(_vault), permitParams); + + uint256 beforeRedeem = (IERC20(address(_vault)).balanceOf(user)); + uint256 beforeZap = IERC20(address(params.tokenOut)).balanceOf(user); + console.log("Shares balance before redeem", beforeRedeem); + console.log("Zapped balance before redeem", beforeZap); + + uint256 sharesBalance = _vault.balanceOf(user); + + if (keccak256(swapData) == keccak256(hex"")) vm.expectRevert(); + zapper.redeemAndZapWithPermit( + _vault, + params.router, + sharesBalance, + swapData, + permitParams + ); + + uint256 afterRedeem = (IERC20(address(_vault)).balanceOf(user)); + uint256 afterZap = IERC20(address(params.tokenOut)).balanceOf(user); + console.log("Shares balance after redeem", afterRedeem); + console.log("Zapped balance after redeem", afterZap); + + if (keccak256(swapData) != keccak256(hex"")) { + assertTrue(beforeRedeem > afterRedeem, "Deposit permit failed"); + assertTrue( + beforeZap < afterZap, + "Deposit permit failed because no token received" + ); + } + } + + function execPermit( + address owner, + address spender, + address token, + PermitParams memory permitParams + ) internal { + ERC20Permit(address(token)).permit( + owner, + spender, + permitParams.value, + permitParams.deadline, + permitParams.v, + permitParams.r, + permitParams.s + ); + } + + function _signPermit( + address _spender, + uint256 _value, + uint256 _nonce, + uint256 deadline + ) internal view returns (uint8 v, bytes32 r, bytes32 s) { + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: user, + spender: _spender, + value: _value, + nonce: _nonce, + deadline: deadline + }); + bytes32 digest = sigUtils.getTypedDataHash(permit); + (v, r, s) = vm.sign(userPrivateKey, digest); + return (v, r, s); + } + + function _setUpVaultAndZapper(IERC20 tokenIn) public { + _vault = new AmphorSyntheticVault(ERC20(address(tokenIn)), "", "", 12); + if (!zapper.authorizedRouters(_router)) { + zapper.toggleRouterAuthorization(_router); + } + if (!zapper.authorizedVaults(_vault)) { + zapper.toggleVaultAuthorization(_vault); + } + } +} diff --git a/test/echidna.config.yaml b/test/echidna.config.yaml new file mode 100644 index 0000000..abe0b55 --- /dev/null +++ b/test/echidna.config.yaml @@ -0,0 +1,5 @@ +corpusDir: "tests/echidna-corpus" +testMode: assertion +testLimit: 10000 +deployer: "0x10000" +sender: ["0x10000"] diff --git a/test/scripts/getOneInchQuote.js b/test/scripts/getOneInchQuote.js new file mode 100644 index 0000000..81fc2ed --- /dev/null +++ b/test/scripts/getOneInchQuote.js @@ -0,0 +1,68 @@ +const tokens = [ + "CwAlZk3ouk1G9UFRgIoqGK9AP8lbJ7lV", + "RrfUwWopWKdTewyy01sh2hFYuGhGxnDB", + "OHoq1U02bPcytTgtUvPr5TbWHGaJn1f6", + "6DDN1W5OkyacoCUub1wwUVSIxKp3EtVp", + "kZ5eyyf1GpnDtY8YvjZ0JIwHx3etjWsF", + "XXRMlyVw4KY6Z1iIpzqEkXUikuv8UXia", + "kZ5eyyf1GpnDtY8YvjZ0JIwHx3etjWsF", + "RHHuitUwk826pRK5YR4PN5VuLHN6t2VN", + "AsEBF1NSqPEIM2HGDlg04jKwu8mHfbwj", + "Bo4A76aUnWIxWUhMedvU3kvo5pP7VHAR", +]; + +// "CwAlZk3ouk1G9UFRgIoqGK9AP8lbJ7lV,RrfUwWopWKdTewyy01sh2hFYuGhGxnDB,OHoq1U02bPcytTgtUvPr5TbWHGaJn1f6,6DDN1W5OkyacoCUub1wwUVSIxKp3EtVp,kZ5eyyf1GpnDtY8YvjZ0JIwHx3etjWsF,XXRMlyVw4KY6Z1iIpzqEkXUikuv8UXia,kZ5eyyf1GpnDtY8YvjZ0JIwHx3etjWsF,RHHuitUwk826pRK5YR4PN5VuLHN6t2VN,AsEBF1NSqPEIM2HGDlg04jKwu8mHfbwj,Bo4A76aUnWIxWUhMedvU3kvo5pP7VHAR" +function getSwapTx(from, to, inToken, out, amount, slippage) { + const headers = { + headers: { + Authorization: `Bearer ${tokens[getRandomInt(tokens.length)]}`, + accept: "application/json", + }, + }; + const swpParams = { + src: `0x${inToken}`, + dst: `0x${out}`, + amount: amount, + from: `0x${from}`, + receiver: `0x${to}`, + slippage: Number(slippage) / 10000, + disableEstimate: true, + allowPartialFill: false, + }; + + const url = apiRequestUrl("/swap", swpParams); + return fetch(url, headers); +} + +function apiRequestUrl(methodName, queryParams) { + const chainId = 1; + const apiBaseUrl = "https://api.1inch.dev/swap/v5.2/" + chainId; + + return ( + apiBaseUrl + methodName + "?" + new URLSearchParams(queryParams).toString() + ); +} + +function getRandomInt(max) { + return Math.floor(Math.random() * max); +} + +function sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +async function main() { + const from = BigInt(process.argv[2]).toString(16); + const to = BigInt(process.argv[3]).toString(16); + const inToken = BigInt(process.argv[4]).toString(16); + const outToken = BigInt(process.argv[5]).toString(16); + const amount = process.argv[6]; + const slippage = process.argv[7]; + await sleep(getRandomInt(10 * 1000)); + getSwapTx(from, to, inToken, outToken, amount, slippage).then(async (res) => { + const raw = await res.json(); + console.log(raw.tx.data); + }); +} + +main(); diff --git a/test/testsRules.md b/test/testsRules.md new file mode 100644 index 0000000..bc88835 --- /dev/null +++ b/test/testsRules.md @@ -0,0 +1,11 @@ +# This file contains the tests rules. +You can add new rules below. + +- Global vault values and specific vault global values should be in separate +contracts. +- Global `ERC20` assets should be as much as possible casted as `ERC20` (instead +of `address` or `IERC20`) in order to simplify the business logic and contain +some `IERC20` code extension like `IERC20Metadata`. +- Tests should contains a specific tests contract for each production contract, +specific(s) contract(s) for properties, and specific(s) contract(s) for basics +scenarios. diff --git a/test/utils/SigUtils.sol b/test/utils/SigUtils.sol new file mode 100644 index 0000000..680095d --- /dev/null +++ b/test/utils/SigUtils.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +contract SigUtils { + bytes32 internal DOMAIN_SEPARATOR; + + constructor(bytes32 _DOMAIN_SEPARATOR) { + DOMAIN_SEPARATOR = _DOMAIN_SEPARATOR; + } + + // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + bytes32 public constant PERMIT_TYPEHASH = + 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; + + struct Permit { + address owner; + address spender; + uint256 value; + uint256 nonce; + uint256 deadline; + } + + // computes the hash of a permit + function getStructHash(Permit memory _permit) + internal + pure + returns (bytes32) + { + return keccak256( + abi.encode( + PERMIT_TYPEHASH, + _permit.owner, + _permit.spender, + _permit.value, + _permit.nonce, + _permit.deadline + ) + ); + } + + // computes the hash of the fully encoded EIP-712 message for the domain, which can be used to recover the signer + function getTypedDataHash(Permit memory _permit) + public + view + returns (bytes32) + { + return keccak256( + abi.encodePacked( + "\x19\x01", DOMAIN_SEPARATOR, getStructHash(_permit) + ) + ); + } +} diff --git a/test/v0/BaseVault/BaseVault.t.sol b/test/v0/BaseVault/BaseVault.t.sol new file mode 100644 index 0000000..9d826ab --- /dev/null +++ b/test/v0/BaseVault/BaseVault.t.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "forge-std/console.sol"; +import "forge-std/Test.sol"; +import "@openzeppelin-v4.9.3/contracts/interfaces/IERC4626.sol"; +import "@openzeppelin-v4.9.3/contracts/token/ERC20/ERC20.sol"; +import "@openzeppelin-v4.9.3/contracts/utils/math/Math.sol"; + +abstract contract BaseVaultTest is Test {} diff --git a/test/v0/Core/BaseProperties.t.sol b/test/v0/Core/BaseProperties.t.sol new file mode 100644 index 0000000..9d2d1a1 --- /dev/null +++ b/test/v0/Core/BaseProperties.t.sol @@ -0,0 +1,290 @@ +//SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import "./Global.t.sol"; + +abstract contract BaseProperties is GlobalTest { + /** + * @dev The `Math` lib is only used for `mulDiv` operations. + */ + using Math for uint256; + + function test_decimals() public virtual { + console.log("Vault decimals: %s", _vault.decimals()); + assertEq(_vault.decimals(), _vaultDecimals); + } + + function test_asset() public virtual { + console.log("Vault asset: %s", _vault.asset()); + assertEq(_vault.asset(), address(_underlying)); + } + + function test_totalAsset() public virtual { + console.log("Vault total asset: %s", _vault.totalAssets()); + assertEq(_vault.totalAssets(), _bootstrapAmount); + } + + // TODO: redo this test for each vault + function test_convertToShares(uint256 assets) public virtual { + vm.assume( + assets + <= ( + type(uint256).max + / 10 ** (_vault.decimals() - _underlying.decimals()) + ) + ); + + uint256 shares = _vault.convertToShares(assets); + + console.log("%s assets = %s shares", assets, shares); + } + + // TODO: redo this test for each vault + function test_convertToAssets(uint256 shares) public virtual { + uint256 assets = _vault.convertToAssets(shares); + + console.log("%s shares = %s assets", shares, assets); + } + + // TODO: redo this test for each vault + function test_maxDeposit(address _address) public virtual { + uint256 maxDeposit = _vault.maxDeposit(_address); + + console.log( + "Max deposit of %s address is %s assets", _address, maxDeposit + ); + } + + // TODO: redo this test for each vault + function test_maxMint(address _address) public virtual { + uint256 maxMint = _vault.maxMint(_address); + + console.log("Max mint of %s address is %s assets", _address, maxMint); + } + + // TODO: redo this test for each vault + function test_maxWithdraw(address _address) public virtual { + uint256 maxWithdraw = _vault.maxWithdraw(_address); + + console.log( + "Max withdraw of %s address is %s assets", _address, maxWithdraw + ); + } + + // TODO: redo this test for each vault + function test_maxRedeem(address _address) public virtual { + uint256 maxRedeem = _vault.maxRedeem(_address); + + console.log( + "Max redeem of %s address is %s assets", _address, maxRedeem + ); + } + + // TODO: redo this test for each vault + function test_previewDeposit(uint256 assets) public virtual { + vm.assume( + assets + <= ( + type(uint256).max + / 10 ** (_vault.decimals() - _underlying.decimals()) + ) + ); + + uint256 shares = _vault.previewDeposit(assets); + + console.log("%s assets = %s shares", assets, shares); + } + + // TODO: redo this test for each vault + function test_previewMint(uint256 shares) public virtual { + uint256 assets = _vault.previewMint(shares); + + console.log("%s shares = %s assets", shares, assets); + } + + // TODO: redo this test for each vault + function test_previewWithdraw( + uint256 assets, + uint256 vaultAssets, + uint256 userSharesAmount + ) public virtual { + vm.assume(vaultAssets < _underlying.totalSupply()); + vm.assume(userSharesAmount <= vaultAssets); + vm.assume(assets <= vaultAssets); + vm.assume(assets <= _vault.maxWithdraw(address(this))); + + console.log("vaultAssets", vaultAssets); + + deal(address(_vault), address(this), userSharesAmount); + deal(address(_underlying), address(_vault), vaultAssets); + + _vault.approve(address(this), userSharesAmount); + _vault.approve(address(_vault), vaultAssets); + + console.log("maxWithdraw %s", _vault.maxWithdraw(address(this))); + console.log("vaultopen value %s", _vault.convertToAssets(_vault.balanceOf(address(this)))); + console.log("vault assets value %s", _underlying.balanceOf(address(_vault))); + console.log("vaultopen value %s", _vault.balanceOf(address(this))); + + uint256 shares = _vault.previewWithdraw(assets); + + console.log( + "%s assets = %s shares", + assets, + shares + ); + } + + // TODO: redo this test for each vault + function test_previewRedeem(uint256 shares) public virtual { + uint256 assets = _vault.previewRedeem(shares); + + console.log("%s shares = %s assets", shares, assets); + } + + // TODO: redo this test for each vault + function test_deposit(uint256 assets, address receiver) public virtual { + vm.assume(receiver != 0x0000000000000000000000000000000000000000); + vm.assume(assets <= _vault.maxDeposit(receiver)); + vm.assume( + assets + <= ( + type(uint256).max + / 10 ** (_vault.decimals() - _underlying.decimals()) + ) + ); + + deal(address(_underlying), address(this), assets); + _underlying.approve(address(_vault), assets); + + uint256 shares = _vault.deposit(assets, receiver); + + console.log("%s assets = %s shares", assets, shares); + } + + // TODO: redo this test for each vault + function test_mint( + uint256 shares, + address receiver, + uint256 vaultAssets, + uint256 sharesSupply + ) public { + vm.assume(shares <= sharesSupply); + vm.assume(shares <= _vault.maxMint(receiver)); + vm.assume(sharesSupply <= shares); + vm.assume(vaultAssets <= _underlying.totalSupply()); + + vm.assume(receiver != 0x0000000000000000000000000000000000000000); + + + deal(address(_underlying), address(_vault), vaultAssets); + deal(address(_vault), address(this), sharesSupply); + + console.log("balance", _underlying.balanceOf(address(this))); + + uint256 assets = _vault.previewMint(shares); + deal(address(_underlying), address(this), assets); + _underlying.approve(address(_vault), assets); + + assets = _vault.mint(0, receiver); + console.log("%s previewed shares = %s previewed assets", shares, assets); + + console.log( + "%s actual shares = %s actual assets", + shares, + assets + ); + } + + // TODO: redo this test for each vault + function test_withdraw( + uint256 userSharesAmount, + uint256 vaultAssets, + uint256 assets, + address receiver, + address owner + ) public virtual { + vm.assume(owner != 0x0000000000000000000000000000000000000000); + vm.assume(receiver != 0x0000000000000000000000000000000000000000); + vm.assume(vaultAssets < _underlying.totalSupply()); + vm.assume(userSharesAmount >= vaultAssets); + vm.assume(assets <= vaultAssets); + vm.assume(assets <= _vault.maxWithdraw(owner)); + + console.log("vaultAssets", vaultAssets); + + deal(address(_vault), address(owner), userSharesAmount); + deal(address(_underlying), address(_vault), vaultAssets); + + address sender = address(this); + + vm.prank(address(owner)); + _vault.approve(address(sender), userSharesAmount); + _vault.approve(address(_vault), vaultAssets); + + console.log("maxWithdraw %s", _vault.maxWithdraw(owner)); + console.log("vaultopen value %s", _vault.convertToAssets(_vault.balanceOf(owner))); + console.log("vault assets value %s", _underlying.balanceOf(address(_vault))); + console.log("vaultopen value %s", _vault.balanceOf(owner)); + + vm.prank(address(owner)); + uint256 shares = _vault.withdraw(assets, receiver, owner); + + console.log( + "%s assets = %s shares", + assets, + shares + ); + } + + // TODO: redo this test for each vault + function test_redeem( + uint256 shares, + uint256 vaultAssets, + address receiver, + address owner + ) public virtual { + vm.assume(owner != 0x0000000000000000000000000000000000000000); + vm.assume(receiver != 0x0000000000000000000000000000000000000000); + vm.assume(vaultAssets <= _underlying.totalSupply()); + vm.assume(shares <= _underlying.totalSupply()); + + deal(address(_vault), address(owner), shares); + deal(address(_underlying), address(_vault), vaultAssets); + + address sender = address(this); + + vm.prank(address(owner)); + _vault.approve(address(sender), shares); + _vault.approve(address(_vault), shares); + + console.log("VALUE %s", _vault.maxRedeem(address(this))); + + uint256 assets = _vault.previewRedeem(shares); + + console.log("%s shares = %s assets", shares, assets); + + assets = _vault.redeem(shares, receiver, owner); + } + + function test_name() public virtual { + console.log("Vault name: %s", _vault.name()); + assertEq(_vault.name(), _vaultName); + } + + function test_symbol() public virtual { + console.log("Vault symbol: %s", _vault.symbol()); + assertEq(_vault.symbol(), _vaultSymbol); + } + + function test_totalSupply() public virtual { + console.log("Vault totalSupply: %s", _vault.totalSupply()); + assertEq(_vault.totalSupply(), _initialMintAmount); + } + + function test_balanceOf() public virtual { + console.log("This balance: %s", _vault.balanceOf(address(this))); + console.log("_initialMintAmount : %s", _initialMintAmount); + assertEq(_vault.balanceOf(address(this)), _initialMintAmount); + } +} diff --git a/test/v0/Core/Global.t.sol b/test/v0/Core/Global.t.sol new file mode 100644 index 0000000..0733b7f --- /dev/null +++ b/test/v0/Core/Global.t.sol @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.19; + +import "../../../lib/forge-std/src/console.sol"; +import "../../../lib/forge-std/src/Test.sol"; + +import {ERC4626} from + "../../../lib/openzeppelin-contracts-v4.9.3/contracts/token/ERC20/extensions/ERC4626.sol"; + +import "../../../src/AmphorSyntheticVaultWithPermit.sol"; + +abstract contract GlobalTest is Test { + ERC20 internal immutable _DAI = ERC20(vm.envAddress("DAI_MAINNET")); + ERC20 internal immutable _USDC = ERC20(vm.envAddress("USDC_MAINNET")); + ERC20 internal immutable _USDT = ERC20(vm.envAddress("USDT_MAINNET")); + ERC20 internal immutable _WETH = ERC20(vm.envAddress("WETH_MAINNET")); + ERC20 internal immutable _ETH = ERC20(vm.envAddress("ETH_MAINNET")); + ERC20 internal immutable _WSTETH = ERC20(vm.envAddress("WSTETH_MAINNET")); + ERC20 internal immutable _STETH = ERC20(vm.envAddress("STETH_MAINNET")); + ERC20 internal immutable _WBTC = ERC20(vm.envAddress("WBTC_MAINNET")); + + ERC20 internal _underlying; + + IERC4626 internal _vault; + + uint256[] _usersPk = [ + 0xA11CE, + 0x1CEA11, + 0x1CEA12, + 0x1CEA13, + 0x1CEA14, + 0x1CEA15, + 0x1CEA16, + 0x1CEA17, + 0x1CEA18, + 0x1CEA19 + ]; + // address[] internal _users; + + address[] internal _users = [ + vm.addr(_usersPk[0]), + vm.addr(_usersPk[1]), + vm.addr(_usersPk[2]), + vm.addr(_usersPk[3]), + vm.addr(_usersPk[4]), + vm.addr(_usersPk[5]), + vm.addr(_usersPk[6]), + vm.addr(_usersPk[7]), + vm.addr(_usersPk[8]), + vm.addr(_usersPk[9]) + ]; + + uint256 internal _bootstrapAmount; + uint256 internal _initialMintAmount; + uint256 internal _vaultDecimals; + address internal _amphorLabs; + string internal _vaultName; + string internal _vaultSymbol; +} diff --git a/test/v0/SyntheticVault/SyntheticBase.t.sol b/test/v0/SyntheticVault/SyntheticBase.t.sol new file mode 100644 index 0000000..ceecf60 --- /dev/null +++ b/test/v0/SyntheticVault/SyntheticBase.t.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "../BaseVault/BaseVault.t.sol"; +import "@src/AmphorSyntheticVaultWithPermit.sol"; + +contract SyntheticBaseTests is BaseVaultTest { + /* + _ _ ____ _ _ _ _ _ _ + / \ _ __ ___ _ __ | |__ ___ _ __ / ___| _ _ _ __ | |_ | |__ ___ | |_ (_) ___ | |_ ___ ___ | |_ ___ + / _ \ | '_ ` _ \ | '_ \ | '_ \ / _ \ | '__| \___ \ | | | | | '_ \ | __| | '_ \ / _ \ | __| | | / __| | __| / _ \ / __| | __| / __| + / ___ \ | | | | | | | |_) | | | | | | (_) | | | ___) | | |_| | | | | | | |_ | | | | | __/ | |_ | | | (__ | |_ | __/ \__ \ | |_ \__ \ + /_/ \_\ |_| |_| |_| | .__/ |_| |_| \___/ |_| |____/ \__, | |_| |_| \__| |_| |_| \___| \__| |_| \___| \__| \___| |___/ \__| |___/ + |_| |___/ + */ + + // Declare global attributes here + AmphorSyntheticVaultWithPermit internal _synthVault; + ERC20 internal _underlying = ERC20(vm.envAddress("USDC_MAINNET")); // can also be vm.envAddress("WETH_MAINNET") or vm.envAddress("WBTC_MAINNET") + uint256 internal _underlyingDecimals = ERC20(_underlying).decimals(); + uint8 internal _decimalOffset = 12; + //_underlying == vm.envAddress("USDC_MAINNET") ? 24 : 35; // 24 for USDC, 35 for WETH, 35 for WBTC -> we should put less + address internal _usdt = vm.envAddress("USDT_MAINNET"); + // Declare AmphorLabs wallet address here + address internal _amphorLabs = 0xa51337F0B984B28E3363616563e11457a7498BB6; + + // Random signer address + address internal _signer = 0xfeFf51Dd22131c2CB32E62E8e6032620a5142aFf; + address internal _signer2 = 0xA9f6aE3502F75Ec8e0cd5463D96dC27E5e8F289a; + + function setUp() public virtual { + // Deploy the AmphorSyntheticVault contract + _synthVault = new AmphorSyntheticVaultWithPermit( + _underlying, + "Amphor Synthetic Vault", + "ASV", + _decimalOffset + ); + + _additionnalSetup(); + } + + function _additionnalSetup() internal virtual {} + + function _getUnderlyingBalance( + address user + ) internal view returns (uint256) { + return IERC20(_synthVault.asset()).balanceOf(user); + } + + function _getSharesBalance(address user) internal view returns (uint256) { + return _synthVault.balanceOf(user); + } + + function giveEthUnderlyingAndApprove( + address user + ) public returns (uint256) { + return + giveEthUnderlyingAndApprove( + user, + 10_000 * 10 ** _underlyingDecimals + ); + } + + function giveEthUnderlyingAndApprove( + address user, + uint256 amount + ) public returns (uint256) { + hoax(user); + deal(address(_underlying), user, amount); + vm.prank(user); + ERC20(_underlying).approve(address(_synthVault), UINT256_MAX); + return amount; + } + + function assertUnderlyingBalance( + address owner, + uint256 expectedBalance + ) public { + assertEq( + _getUnderlyingBalance(owner), + expectedBalance, + "underlying balance != expected balance" + ); + } + + function assertSharesBalance( + address owner, + uint256 expectedBalance + ) public { + assertEq( + _getSharesBalance(owner), + expectedBalance, + "shares balance != expected balance" + ); + } +} diff --git a/test/v0/SyntheticVault/SyntheticBasic.t.sol b/test/v0/SyntheticVault/SyntheticBasic.t.sol new file mode 100644 index 0000000..45e6f1c --- /dev/null +++ b/test/v0/SyntheticVault/SyntheticBasic.t.sol @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "./SyntheticBase.t.sol"; + +contract SyntheticBasicTests is SyntheticBaseTests { + function test_Name() public { + assertEq(_synthVault.name(), "Amphor Synthetic Vault"); + } + + function test_Owner() public { + assertEq(_synthVault.owner(), address(this)); + } + + function test_Symbol() public { + assertEq(_synthVault.symbol(), "ASV"); + } + + function test_Underlying() public { + assertEq(_synthVault.asset(), address(_underlying)); + } + + function test_AssetAddress() public { + assertEq(_synthVault.asset(), address(_underlying)); + } + + function test_DecimalOffset() public { + assertEq(_synthVault.decimalsOffset(), _decimalOffset); + } + + function test_TotalSupply() public { + assertEq(_synthVault.totalSupply(), 0); + } + + function test_BalanceOf() public { + assertEq(_synthVault.balanceOf(address(this)), 0); + } + + function test_Allowance() public { + assertEq(_synthVault.allowance(address(this), address(this)), 0); + } + + function test_Approve() public { + _synthVault.approve(address(this), 100); + assertEq(_synthVault.allowance(address(this), address(this)), 100); + } + + function test_perfFeesOver30() public { + vm.expectRevert(AmphorSyntheticVault.FeesTooHigh.selector); + _synthVault.setFees(31 * 100); + } + + function test_claimUnderlying() public { + giveEthUnderlyingAndApprove(_signer); + vm.prank(_signer); + _synthVault.deposit(100, _signer); + + vm.expectRevert(AmphorSyntheticVault.CannotClaimAsset.selector); + _synthVault.claimToken(IERC20(_underlying)); + } + + function test_claimOtherToken() public { + deal(address(_usdt), address(_synthVault), 10 * 10 ** 6); + + _synthVault.claimToken(IERC20(_usdt)); + } + + function test_totalAsset() public { + giveEthUnderlyingAndApprove(_signer); + vm.prank(_signer); + _synthVault.deposit(100, _signer); + + assertEq(_synthVault.totalAssets(), 100); + } + + function test_MaxDeposit() public { + assertEq( + _synthVault.maxDeposit(address(0)), + type(uint256).max, + "Max deposit should be equal to total supply of underlying" + ); + } + + function test_MaxDepositAfterStart() public { + _synthVault.start(); + assertEq( + _synthVault.maxDeposit(address(0)), + 0, + "Max deposit should be equal to zero after start" + ); + } + + function test_MaxMint() public { + assertEq( + _synthVault.maxMint(address(0)), + UINT256_MAX, + "Max mint should be equal to total supply of underlying " + ); + } + + function test_MaxMintAfterStart() public { + _synthVault.start(); + assertEq( + _synthVault.maxMint(address(0)), + 0, + "Max mint should be equal to total supply of underlying " + ); + } + + function test_maxWithdraw() public { + assertEq( + _synthVault.maxDeposit(address(0)), + type(uint256).max, + "Max deposit should be equal to total supply of underlying" + ); + } + + function test_maxWithdrawAfterStart() public { + _synthVault.start(); + assertEq( + _synthVault.maxWithdraw(address(0)), + 0, + "Max withdraw should be 0 after start" + ); + } + + function test_MaxRedeem() public { + assertEq( + _synthVault.maxRedeem(address(this)), + ERC20(_synthVault).balanceOf(address(this)), + "Max redeem should be equal to total supply of underlying" + ); + } + + function test_MaxRedeemAfterStart() public { + _synthVault.start(); + assertEq( + _synthVault.maxRedeem(address(this)), + 0, + "Max redeem should be equal to total supply of underlying" + ); + } + + function test_decimals() public { + assertEq( + _synthVault.decimals(), + ERC20(_underlying).decimals() + _decimalOffset, + "Max deposit should be equal to total supply of underlying after start" + ); + } + + function test_totalAssetsAfterStartWithoutDonation() public { + _synthVault.start(); + assertEq( + _synthVault.totalAssets(), + _synthVault.lastSavedBalance(), + "Total assets should be total supply of underlying after start" + ); + } + + function test_totalAssetsAfterStartWithDonation() public { + _synthVault.start(); + uint256 donationAmount = 100; + deal(address(_underlying), address(_synthVault), donationAmount); + assertEq( + _synthVault.totalAssets(), + _synthVault.lastSavedBalance() + donationAmount, + "Total assets should be total supply of underlying after start + donation" + ); + } +} diff --git a/test/v0/SyntheticVault/SyntheticDepositAndWithdraw.t.sol b/test/v0/SyntheticVault/SyntheticDepositAndWithdraw.t.sol new file mode 100644 index 0000000..88b6e89 --- /dev/null +++ b/test/v0/SyntheticVault/SyntheticDepositAndWithdraw.t.sol @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "./SyntheticBase.t.sol"; + +contract SyntheticDepositAndWithdrawTests is SyntheticBaseTests { + using Math for uint256; + + function test_SimpleDepositAndWithdraw() public { + uint256 depositAmount = 10 ** 16; // 1 ETH / 100 000 000 000.00000 USDC + uint256 vaultUnderlyingBalance = + IERC20(_underlying).balanceOf(address(_synthVault)); + + // Fund the vault with some underlying, and mint the corresponding shares tokens + deal(address(_underlying), _signer, depositAmount, false); + vm.startPrank(_signer); + IERC20(_underlying).approve(address(_synthVault), depositAmount); + uint256 sharesExpected = _synthVault.convertToShares(depositAmount); + _synthVault.deposit(depositAmount, _signer); + assertEq( + _getSharesBalance(_signer), + depositAmount * 10 ** _decimalOffset, + "Signer doesn't have the correct amount of ASV tokens after a deposit" + ); + assertEq( + sharesExpected, + _getSharesBalance(_signer), + "Shares expected should be equal to the shares balance" + ); + assertEq( + _getUnderlyingBalance(address(_synthVault)), + vaultUnderlyingBalance + depositAmount, + "synthVault should have 0 undelying token units after a deposit" + ); + assertEq( + IERC20(_underlying).balanceOf(_signer), + 0, + "Signer should have no undelying after a deposit" + ); + _synthVault.withdraw(depositAmount, _signer, _signer); + vm.stopPrank(); + + assertEq( + IERC20(_underlying).balanceOf(address(_synthVault)), + vaultUnderlyingBalance, + "synthVault should have 0 undelying token units after a withdraw" + ); + + assertEq( + IERC20(_underlying).balanceOf(_signer), + depositAmount, + "Signer should have his undelying back after a withdraw" + ); + assertEq( + IERC20(_synthVault).balanceOf(_signer), + 0, + "Signer doesn't have the correct amount of ASV tokens after a withdraw" + ); + } + + function test_depositZero() public { + giveEthUnderlyingAndApprove(_signer); + uint256 underlyingBefore = _getUnderlyingBalance(_signer); + uint256 shareBefore = _getSharesBalance(_signer); + uint256 vaultUnderlyingBalance = + _getUnderlyingBalance(address(_synthVault)); + vm.prank(_signer); + uint256 sharesExpected = _synthVault.previewDeposit(0); + + _synthVault.deposit(0, _signer); + assertEq( + _getUnderlyingBalance(_signer), + underlyingBefore, + "Signer should have the same amount of underlying after a deposit of 0" + ); + assertEq( + _getSharesBalance(_signer), + shareBefore, + "Signer should have the same amount of shares after a deposit of 0" + ); + assertEq( + shareBefore - _getSharesBalance(_signer), + sharesExpected, + "Signer should have the same amount of shares after a deposit of 0" + ); + assertEq( + _getUnderlyingBalance(address(_synthVault)), + vaultUnderlyingBalance, + "synthVault should have the same amount of underlying after a deposit of 0" + ); + } + + function test_depositMinSharesTooLow() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + uint256 toDeposit = 10 * 10 ** ERC20(_underlying).decimals(); + uint256 sharesPreview = _synthVault.previewDeposit(toDeposit); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626NotEnoughSharesMinted.selector, + _signer, + sharesPreview, + sharesPreview + 1 + ) + ); + _synthVault.depositMinShares(toDeposit, _signer, sharesPreview + 1); + } + + function test_depositMinSharesExact() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + uint256 toDeposit = 10 * 10 ** ERC20(_underlying).decimals(); + uint256 sharesPreview = _synthVault.previewDeposit(toDeposit); + uint256 sharesMinted = + _synthVault.depositMinShares(toDeposit, _signer, sharesPreview); + assertEq( + sharesMinted, + sharesPreview, + "Shares minted should be equal to the preview" + ); + } + + function test_depositMinShares1PercentSlippage() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + uint256 toDeposit = 1000 * 10 ** ERC20(_underlying).decimals(); + uint256 sharesPreview = _synthVault.previewDeposit(toDeposit); + + uint256 sharesMinted = _synthVault.depositMinShares( + toDeposit.mulDiv(9900, 10000), + _signer, + sharesPreview.mulDiv(9900, 10000) + ); + assertGe(sharesMinted, sharesPreview.mulDiv(9900, 10000)); + } + + function test_depositMinSharesNotEnough() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + uint256 toDeposit = 10 * 10 ** ERC20(_underlying).decimals(); + uint256 sharesPreview = _synthVault.previewDeposit(toDeposit); + uint256 actualShares = + _synthVault.previewDeposit(toDeposit.mulDiv(9899, 10000)); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626NotEnoughSharesMinted.selector, + _signer, + actualShares, + sharesPreview.mulDiv(9900, 10000) + ) + ); + _synthVault.depositMinShares( + toDeposit.mulDiv(9899, 10000), + _signer, + sharesPreview.mulDiv(9900, 10000) + ); + } + + function test_withdrawZero() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + _synthVault.deposit(100 * 10 ** 6, _signer); + + uint256 underlyingBefore = _getUnderlyingBalance(_signer); + uint256 shareBefore = _getSharesBalance(_signer); + uint256 vaultUnderlyingBalance = + _getUnderlyingBalance(address(_synthVault)); + _synthVault.withdraw(0, _signer, _signer); + vm.stopPrank(); + + assertEq( + _getUnderlyingBalance(_signer), + underlyingBefore, + "Signer should have the same amount of underlying after a withdraw of 0" + ); + assertEq( + _getSharesBalance(_signer), + shareBefore, + "Signer should have the same amount of shares after a withdraw of 0" + ); + assertEq( + _getUnderlyingBalance(address(_synthVault)), + vaultUnderlyingBalance, + "synthVault should have the same amount of underlying after a withdraw of 0" + ); + } + + function test_advancedDepositAndWithdraw() public { + // 10 ** 18 // 1 ETH / 10 000 000 000 000.00000 USDC + _testAdvancedDepositAndWithdraw( + 10 ** 18, type(uint256).max, 34545678908765, 9876546789 + ); // 34545678908765 is a random number + // _testAdvancedDepositAndWithdraw(3456789, 34545678908765); // 34545678908765 > 3456789 are both random numbers + // _testAdvancedDepositAndWithdraw(34545678908765, 3456789); // 34545678908765 > 3456789 are both random numbers + } + + function _testAdvancedDepositAndWithdraw( + uint256 balanceAmount, + uint256 approvalAmount, + uint256 depositAmount, + uint256 withdrawAmount + ) internal { + uint256 vaultUnderlyingBalance = + IERC20(_underlying).balanceOf(address(_synthVault)); + + // Fund the vault with some underlying, and mint the corresponding shares tokens + deal(address(_underlying), _signer, balanceAmount, false); + vm.startPrank(_signer); + IERC20(_underlying).approve(address(_synthVault), approvalAmount); // Max approval, just to test an eventual edge case + _synthVault.deposit(depositAmount, _signer); + assertEq( + IERC20(_synthVault).balanceOf(_signer), + depositAmount * 10 ** _decimalOffset, + "Signer doesn't have the correct amount of ASV tokens after a deposit" + ); + assertEq( + IERC20(_underlying).balanceOf(address(_synthVault)), + vaultUnderlyingBalance + depositAmount, + "synthVault should have 0 underlying token units after a deposit" + ); + assertEq( + IERC20(_underlying).balanceOf(_signer), + balanceAmount - depositAmount, + "Signer should have the randomUnderlyingBalanceOffset undelying after a deposit" + ); + _synthVault.withdraw(withdrawAmount, _signer, _signer); + vm.stopPrank(); + + // Verify balances + assertEq( + IERC20(_underlying).balanceOf(address(_synthVault)), + vaultUnderlyingBalance + depositAmount - withdrawAmount, + "synthVault should have 0 undelying token units after a withdraw" + ); + assertEq( + IERC20(_underlying).balanceOf(_signer), + balanceAmount - depositAmount + withdrawAmount, + "Signer should have his undelying back after a withdraw" + ); + assertEq( + IERC20(_synthVault).balanceOf(_signer), + (depositAmount - withdrawAmount) * 10 ** _decimalOffset, + "Signer doesn't have the correct amount of ASV tokens after a withdraw" + ); + } + + function test_withdrawForOtherUser() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + _synthVault.deposit(100 * 10 ** 6, _signer); + uint256 sharesBefore = _getSharesBalance(_signer); + ERC20(_synthVault).approve(_signer2, _getSharesBalance(_signer)); + vm.stopPrank(); + + vm.prank(_signer2); + uint256 shares = _synthVault.withdraw(100 * 10 ** 6, _signer2, _signer); + assertEq( + _getUnderlyingBalance(_signer2), + 100 * 10 ** 6, + "Signer2 should have the underlying after a withdraw for signer" + ); + assertEq( + sharesBefore, + shares, + "Shares return should be equal to the shares hold by signer" + ); + } + + function test_redeemForOtherUser() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + _synthVault.deposit(100 * 10 ** 6, _signer); + ERC20(_synthVault).approve(_signer2, _getSharesBalance(_signer)); + vm.stopPrank(); + + vm.startPrank(_signer2); + uint256 assets = + _synthVault.redeem(_getSharesBalance(_signer), _signer2, _signer); + assertEq( + assets, + 100 * 10 ** 6, + "Redeem return should be equal to the amount of underlying originally deposited" + ); + assertEq( + _getUnderlyingBalance(_signer2), + 100 * 10 ** 6, + "Signer2 should have the underlying after a withdraw for signer" + ); + } + + function test_redeemForOtherUserUintMax() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + _synthVault.deposit(100 * 10 ** 6, _signer); + ERC20(_synthVault).approve(_signer2, UINT256_MAX); + vm.stopPrank(); + + vm.startPrank(_signer2); + uint256 previewAssets = + _synthVault.previewRedeem(_getSharesBalance(_signer)); + uint256 _assets = + _synthVault.redeem(_getSharesBalance(_signer), _signer2, _signer); + + assertEq( + _getUnderlyingBalance(_signer2), + 100 * 10 ** 6, + "Signer2 should have the underlying after a withdraw for signer" + ); + assertEq( + _assets, + 100 * 10 ** 6, + "Assets return should be equal to the underlying balance of signer2" + ); + assertEq( + previewAssets, + 100 * 10 ** 6, + "Preview assets should be equal to the underlying balance of signer2" + ); + assertEq( + ERC20(_synthVault).allowance(_signer, _signer2), + UINT256_MAX, + "Signer2 allowance should remain unchanged after redeeming for signer" + ); + vm.stopPrank(); + } + + function test_withdrawForOtherUserUintMax() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + _synthVault.deposit(100 * 10 ** 6, _signer); + ERC20(_synthVault).approve(_signer2, UINT256_MAX); + vm.stopPrank(); + uint256 sharesBefore = _getSharesBalance(_signer); + uint256 sharesPreview = _synthVault.previewWithdraw(100 * 10 ** 6); + vm.startPrank(_signer2); + uint256 shares = _synthVault.withdraw(100 * 10 ** 6, _signer2, _signer); + assertEq( + _getUnderlyingBalance(_signer2), + 100 * 10 ** 6, + "Signer2 should have the underlying after a withdraw for signer" + ); + assertEq( + sharesBefore, + shares, + "Shares return should be equal to the shares hold by signer" + ); + assertEq( + sharesPreview, + shares, + "Shares return should be equal to the preview of the amount of shares" + ); + assertEq( + ERC20(_synthVault).allowance(_signer, _signer2), + UINT256_MAX, + "Signer2 allowance should remain unchanged after redeeming for signer" + ); + vm.stopPrank(); + } + + function test_redeem() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + uint256 underlyingBefore = _getUnderlyingBalance(_signer); + _synthVault.deposit(underlyingBefore, _signer); + + uint256 assets = + _synthVault.redeem(_getSharesBalance(_signer), _signer, _signer); + assertEq( + assets, + underlyingBefore, + "Redeem return should be equal to the amount of underlying originally deposited" + ); + assertEq( + _getUnderlyingBalance(_signer), + underlyingBefore, + "Signer should have the underlying after a withdraw for signer" + ); + } + + // function test_mint() public { + // giveEthUnderlyingAndApprove(_signer); + // vm.startPrank(_signer); + // uint256 underlyingBefore = _getUnderlyingBalance(_signer); + // uint256 toMint = 10 * 10 ** ERC20(_underlying).decimals(); + // uint256 underlyingPreview = _synthVault.previewMint(toMint); + // uint256 mintReturn = _synthVault.mint(toMint, _signer); + // uint256 underlyingAfter = _getUnderlyingBalance(_signer); + + // assertEq( + // mintReturn, + // underlyingPreview, + // "Mint return should be equal to the amount of underlying originally deposited" + // ); + // assertEq( + // underlyingAfter, + // underlyingBefore - mintReturn, + // "Mint return should be equal to the amount of underlying actually deposited" + // ); + // } + + function test_mintMaxAssets() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + uint256 toMint = 10 * 10 ** ERC20(_underlying).decimals(); + uint256 underlyingPreview = _synthVault.previewMint(toMint); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626TooMuchAssetsDeposited.selector, + _signer, + underlyingPreview, + underlyingPreview - 1 + ) + ); + _synthVault.mintMaxAssets(toMint, _signer, underlyingPreview - 1); + } + + function test_mintMaxAssetsTooHigh() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + uint256 toMint = 10 * 10 ** ERC20(_synthVault).decimals(); + uint256 underlyingPreview = _synthVault.previewMint(toMint); + uint256 underlyingPreviewExcess = _synthVault.previewMint(toMint + 1); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626TooMuchAssetsDeposited.selector, + _signer, + underlyingPreviewExcess, + underlyingPreview + ) + ); + _synthVault.mintMaxAssets(toMint + 1, _signer, underlyingPreview); + } + + function test_mintMaxAssetsSame() public { + giveEthUnderlyingAndApprove(_signer); + vm.startPrank(_signer); + uint256 toMint = 10 * 10 ** ERC20(_synthVault).decimals(); + uint256 underlyingPreview = _synthVault.previewMint(toMint); + + uint256 assetDeposited = + _synthVault.mintMaxAssets(toMint, _signer, underlyingPreview); + assertEq( + assetDeposited, + underlyingPreview, + "Asset deposited should be equal to the preview" + ); + } +} diff --git a/test/v0/SyntheticVault/SyntheticEndAndStart.t.sol b/test/v0/SyntheticVault/SyntheticEndAndStart.t.sol new file mode 100644 index 0000000..b0380fd --- /dev/null +++ b/test/v0/SyntheticVault/SyntheticEndAndStart.t.sol @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "./SyntheticBase.t.sol"; +import "@openzeppelin-v4.9.3/contracts/utils/math/Math.sol"; + +contract SyntheticEndAndStart is SyntheticBaseTests { + using Math for uint256; + + function _additionnalSetup() internal override { + giveEthUnderlyingAndApprove(_signer); + giveEthUnderlyingAndApprove(_signer2); + giveEthUnderlyingAndApprove(_amphorLabs); + giveEthUnderlyingAndApprove(address(this)); + _synthVault.setFees(20 * 100); + } + + function test_vaultIsOpen() public { + assertEq(_synthVault.vaultIsOpen(), true); + } + + function test_VaultIsClosedAfterStart() public { + _synthVault.start(); + assertEq(_synthVault.vaultIsOpen(), false); + } + + function test_VaultIsOpenAfterEnd() public { + _synthVault.start(); + _synthVault.end(0); + assertEq(_synthVault.vaultIsOpen(), true); + } + + function test_DoubleStart() public { + _synthVault.start(); + vm.expectRevert(AmphorSyntheticVault.VaultIsLocked.selector); + _synthVault.start(); + } + + function test_DoubleEnd() public { + _synthVault.start(); + _synthVault.end(0); + vm.expectRevert(AmphorSyntheticVault.VaultIsOpen.selector); + _synthVault.end(0); + } + + function test_surplusEnd() public { + _synthVault.start(); + _synthVault.setFees(20 * 100); + uint256 lastSavedBalance = _synthVault.lastSavedBalance(); + uint256 ownerUnderlyingBalance = 10_000 * 10 ** _underlyingDecimals; + uint256 amountToGiveBackToTheVault = ownerUnderlyingBalance / 2; + uint256 ownerUnderlyingBalanceAferEndWithoutFees = + ownerUnderlyingBalance - amountToGiveBackToTheVault; + + deal(address(_underlying), address(this), ownerUnderlyingBalance); + + IERC20(_underlying).approve( + address(_synthVault), ownerUnderlyingBalance + ); + uint16 perfFees = _synthVault.feesInBps(); + _synthVault.end(amountToGiveBackToTheVault); + + uint256 profits = amountToGiveBackToTheVault - lastSavedBalance; + uint256 afterEndOwnerUnderlyingBalance = + _getUnderlyingBalance(address(this)); + + assertEq( + afterEndOwnerUnderlyingBalance, + ownerUnderlyingBalanceAferEndWithoutFees + + profits.mulDiv(perfFees, 10000, Math.Rounding.Up) + ); + } + + function test_minusEnd() public { + vm.prank(_signer); + _synthVault.deposit(5_000 * 10 ** _underlyingDecimals, _signer); + _synthVault.start(); + uint256 lastSavedBalance = _synthVault.lastSavedBalance(); + uint256 ownerUnderlyingBalanceBeforeEnd = + _getUnderlyingBalance(address(this)); + + uint256 amountToGiveBackToTheVault = lastSavedBalance / 2; + _synthVault.end(amountToGiveBackToTheVault); + uint256 ownerUnderlyingBalacanceAfterEnd = + _getUnderlyingBalance(address(this)); + + assertEq( + ownerUnderlyingBalanceBeforeEnd - amountToGiveBackToTheVault, + ownerUnderlyingBalacanceAfterEnd + ); + } + + function test_EndWithZero() public { + vm.prank(_signer); + _synthVault.deposit(5_000 * 10 ** _underlyingDecimals, _signer); + _synthVault.start(); + uint256 ownerUnderlyingBalanceBeforeEnd = + _getUnderlyingBalance(address(this)); + + _synthVault.end(0); + uint256 ownerUnderlyingBalacanceAfterEnd = + _getUnderlyingBalance(address(this)); + + assertEq( + ownerUnderlyingBalanceBeforeEnd, ownerUnderlyingBalacanceAfterEnd + ); + } + + function test_startLastBalance() public { + address user = _signer; + address user2 = _signer2; + giveEthUnderlyingAndApprove(user); + giveEthUnderlyingAndApprove(user2); + vm.prank(user); + _synthVault.deposit(5_000 * 10 ** _underlyingDecimals, user); + vm.prank(user2); + _synthVault.deposit(3_000 * 10 ** _underlyingDecimals, user2); + + _synthVault.start(); + + assertEq( + _synthVault.lastSavedBalance(), + 5_000 * 10 ** _underlyingDecimals + + 3_000 * 10 ** _underlyingDecimals + ); + } + + function test_startOwnerUnderlyingBalance() public { + address user = _signer; + address user2 = _signer2; + uint256 ownerUnderlyingBeforeStart = + _getUnderlyingBalance(address(this)); + giveEthUnderlyingAndApprove(user); + giveEthUnderlyingAndApprove(user2); + vm.prank(user); + _synthVault.deposit(5_000 * 10 ** _underlyingDecimals, user); + vm.prank(user2); + _synthVault.deposit(3_000 * 10 ** _underlyingDecimals, user2); + + _synthVault.start(); + + assertEq( + _getUnderlyingBalance(address(this)) - ownerUnderlyingBeforeStart, + 5_000 * 10 ** _underlyingDecimals + + 3_000 * 10 ** _underlyingDecimals + ); + } + + function test_UserProfits() public { + address user = _signer; + address user2 = _signer2; + giveEthUnderlyingAndApprove(user); + giveEthUnderlyingAndApprove(user2); + uint256 userDeposit = 5_000 * 10 ** _underlyingDecimals; + uint256 user2Deposit = 3_000 * 10 ** _underlyingDecimals; + vm.prank(user); + _synthVault.deposit(userDeposit, user); + vm.prank(user2); + _synthVault.deposit(user2Deposit, user2); + + _synthVault.start(); + uint256 profitsInBips = 2000; + _synthVault.end( + (_synthVault.lastSavedBalance() * (10000 + profitsInBips)) / 10000 + ); + + _checkUserProfits(userDeposit, profitsInBips, 0, user); + _checkUserProfits(user2Deposit, profitsInBips, 0, user2); + } + + function test_UsersProfitsWithDonation() public { + address user = _signer; + address user2 = _signer2; + giveEthUnderlyingAndApprove(user); + giveEthUnderlyingAndApprove(user2); + uint256 userDeposit = 5_000 * 10 ** _underlyingDecimals; + uint256 user2Deposit = 3_000 * 10 ** _underlyingDecimals; + vm.prank(user); + _synthVault.deposit(userDeposit, user); + vm.prank(user2); + _synthVault.deposit(user2Deposit, user2); + + _synthVault.start(); + uint256 profitsInBips = 2000; + + deal( + address(_underlying), + address(_synthVault), + ERC20(_underlying).balanceOf(address(_synthVault)) + + 1000 * 10 ** _underlyingDecimals + ); + _synthVault.end( + (_synthVault.lastSavedBalance() * (10000 + profitsInBips)) / 10000 + ); + + _checkUserProfits(userDeposit, profitsInBips, 625000000, user); + _checkUserProfits(user2Deposit, profitsInBips, 375000000, user2); + } + + function test_UsersProfitsThankToDonation() public { + address user = _signer; + address user2 = _signer2; + giveEthUnderlyingAndApprove(user); + giveEthUnderlyingAndApprove(user2); + uint256 userDeposit = 5_000 * 10 ** _underlyingDecimals; + uint256 user2Deposit = 3_000 * 10 ** _underlyingDecimals; + vm.prank(user); + _synthVault.deposit(userDeposit, user); + vm.prank(user2); + _synthVault.deposit(user2Deposit, user2); + + _synthVault.start(); + uint256 lossesInBips = 2000; + + deal( + address(_underlying), + address(_synthVault), + ERC20(_underlying).balanceOf(address(_synthVault)) + + 1000 * 10 ** _underlyingDecimals + ); + _synthVault.end( + (_synthVault.lastSavedBalance() * (10000 - lossesInBips)) / 10000 + ); + + _checkUserProfitsThankToDonation( + userDeposit, lossesInBips, 625000000, user + ); + _checkUserProfitsThankToDonation( + user2Deposit, lossesInBips, 375000000, user2 + ); + } + + function test_UserLossesWithDonation() public { + address user = _signer; + address user2 = _signer2; + giveEthUnderlyingAndApprove(user); + giveEthUnderlyingAndApprove(user2); + uint256 userDeposit = 5_000 * 10 ** _underlyingDecimals; + uint256 user2Deposit = 3_000 * 10 ** _underlyingDecimals; + vm.prank(user); + _synthVault.deposit(userDeposit, user); + vm.prank(user2); + _synthVault.deposit(user2Deposit, user2); + + _synthVault.start(); + uint256 lossesInBips = 2000; + + deal( + address(_underlying), + address(_synthVault), + ERC20(_underlying).balanceOf(address(_synthVault)) + + 1000 * 10 ** _underlyingDecimals + ); + _synthVault.end( + (_synthVault.lastSavedBalance() * (10000 - lossesInBips)) / 10000 + ); + + _checkUserLosses(userDeposit, lossesInBips, 625000000, user); + _checkUserLosses(user2Deposit, lossesInBips, 375000000, user2); + } + + function test_UserProfitsWithFunkyFees() public { + _synthVault.setFees(1243); + test_UserProfits(); + } + + function test_UserProfitsWithFees0() public { + _synthVault.setFees(0); + test_UserProfits(); + } + + function _checkUserProfits( + uint256 userDeposit, + uint256 underlyingIncreaseInBips, + uint256 profitFromDonation, + address user + ) internal { + uint256 underlyingIncreaseAmountWithoutFees = userDeposit.mulDiv( + 10000 + underlyingIncreaseInBips, 10000, Math.Rounding.Up + ); + uint256 feesTaken = (underlyingIncreaseAmountWithoutFees - userDeposit) + .mulDiv(_synthVault.feesInBps(), 10000, Math.Rounding.Up); + uint256 amountToReceive = underlyingIncreaseAmountWithoutFees + - feesTaken - 1 + profitFromDonation; + uint256 userPotentialWithdraw = + _synthVault.previewRedeem(_getSharesBalance(user)); + assertEq( + amountToReceive, + userPotentialWithdraw, + "User won't withdraw the appropriate amount after end" + ); + } + + function _checkUserProfitsThankToDonation( + uint256 userDeposit, + uint256 underlyingDecreaseInBips, + uint256 profitFromDonation, + address user + ) internal { + uint256 underlyingIncreaseAmountWithoutFees = userDeposit.mulDiv( + 10000 - underlyingDecreaseInBips, 10000, Math.Rounding.Up + ); + uint256 amountToReceive = + underlyingIncreaseAmountWithoutFees + profitFromDonation; + uint256 userPotentialWithdraw = + _synthVault.previewRedeem(_getSharesBalance(user)); + assertEq( + amountToReceive, + userPotentialWithdraw, + "User won't withdraw the appropriate amount after end" + ); + } + + function test_UserLosses() public { + address user = _signer; + address user2 = _signer2; + giveEthUnderlyingAndApprove(user); + giveEthUnderlyingAndApprove(user2); + uint256 userDeposit = 5_000 * 10 ** _underlyingDecimals; + uint256 user2Deposit = 3_000 * 10 ** _underlyingDecimals; + vm.prank(user); + _synthVault.deposit(userDeposit, user); + vm.prank(user2); + _synthVault.deposit(user2Deposit, user2); + + _synthVault.start(); + uint256 lossesInBips = 2000; + _synthVault.end( + (_synthVault.lastSavedBalance() * (10000 - lossesInBips)) / 10000 + ); + + _checkUserLosses(userDeposit, lossesInBips, 0, user); + _checkUserLosses(user2Deposit, lossesInBips, 0, user2); + } + + function test_UserLossesWithoutFees() public { + _synthVault.setFees(0); + test_UserLosses(); + } + + function _checkUserLosses( + uint256 userDeposit, + uint256 underlyingDecreaseInBips, + uint256 profitFromDonation, + address user + ) internal { + uint256 underlyingDecreaseAmountWithoutFees = userDeposit.mulDiv( + 10000 - underlyingDecreaseInBips, 10000, Math.Rounding.Up + ); + uint256 feesTaken = 0; + uint256 amountToReceive = + underlyingDecreaseAmountWithoutFees - feesTaken + profitFromDonation; + uint256 userPotentialWithdraw = + _synthVault.previewRedeem(_getSharesBalance(user)); + assertEq( + amountToReceive, + userPotentialWithdraw, + "User won't withdraw the appropriate amount after end" + ); + } + + function test_MaxDepositAfterStart() public { + _synthVault.start(); + assertEq( + _synthVault.maxDeposit(address(0)), + 0, + "Max deposit should be 0 after start" + ); + } + + function test_MaxMintAfterStart() public { + _synthVault.start(); + assertEq( + _synthVault.maxMint(address(0)), + 0, + "Max mint should be 0 after start" + ); + } + + function test_MaxRedeemAfterStart() public { + _synthVault.start(); + assertEq( + _synthVault.maxRedeem(address(0)), + 0, + "Max redeem should be 0 after start" + ); + } + + function test_MaxWithdrawAfterStart() public { + _synthVault.start(); + assertEq( + _synthVault.maxWithdraw(address(0)), + 0, + "Max redeem should be 0 after start" + ); + } + + function test_userRedeemAfterStart() public { + address user = _signer; + giveEthUnderlyingAndApprove(user); + vm.prank(user); + _synthVault.deposit(100 * 10 ** 6, user); + _synthVault.start(); + + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxRedeem.selector, + user, + 1, + 0 + ) + ); + _synthVault.redeem(1, user, user); + } + + function test_userWithdrawAfterStart() public { + address user = _signer; + + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxWithdraw.selector, + user, + 1, + 0 + ) + ); + _synthVault.withdraw(1, user, user); + } + + function test_withdrawAfterEnd() public { + address user = _signer; + uint256 userBalance = giveEthUnderlyingAndApprove(user); + + vm.prank(user); + _synthVault.deposit(userBalance, user); + _synthVault.start(); + _synthVault.end(userBalance); + vm.startPrank(user); + _synthVault.withdraw(userBalance, user, user); + assertEq( + _getUnderlyingBalance(user), + userBalance, + "User should have its underlying back" + ); + } + + function test_redeemAfterStart() public { + address user = _signer; + giveEthUnderlyingAndApprove(user); + vm.prank(user); + _synthVault.deposit(100 * 10 ** 6, user); + _synthVault.start(); + + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxWithdraw.selector, + user, + 1, + 0 + ) + ); + _synthVault.withdraw(1, user, user); + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxRedeem.selector, + user, + 1, + 0 + ) + ); + _synthVault.redeem(1, user, user); + } + + function test_depositAfterStart() public { + address user = _signer; + giveEthUnderlyingAndApprove(user); + _synthVault.start(); + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxDeposit.selector, + user, + 100 * 10 ** 6, + 0 + ) + ); + _synthVault.deposit(100 * 10 ** 6, user); + } + + function test_mintAfterStart() public { + address user = _signer; + giveEthUnderlyingAndApprove(user); + _synthVault.start(); + vm.startPrank(user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxMint.selector, + user, + 100 * 10 ** 6, + 0 + ) + ); + _synthVault.mint(100 * 10 ** 6, user); + } + + function test_startMultipleEpochs() public { + address user = _signer; + address user2 = _signer2; + address user3 = address(0x123); + + giveEthUnderlyingAndApprove(user); + giveEthUnderlyingAndApprove(user2); + giveEthUnderlyingAndApprove(user3); + + vm.prank(user); + _synthVault.deposit(11 * 10 ** 6, user); + vm.prank(user2); + _synthVault.deposit(22 * 10 ** 6, user2); + vm.prank(user3); + _synthVault.deposit(33 * 10 ** 6, user3); + + assertEq( + _synthVault.lastSavedBalance(), + 0, + "Vault lastSavedBalance should be 0" + ); + + _synthVault.start(); + + assertEq( + _getUnderlyingBalance(address(_synthVault)), + 0, + "Vault should be empty" + ); + assertEq( + _synthVault.lastSavedBalance(), + 66 * 10 ** 6, + "Vault should have 66 * 10 ** 6 underlying" + ); + + giveEthUnderlyingAndApprove(address(this)); + + _synthVault.end(70 * 10 ** 6); + + assertEq( + _getUnderlyingBalance(address(_synthVault)), + 692 * 10 ** 5, + "Vault should have 70 * 10 ** 6 underlying" + ); + + assertEq( + _synthVault.lastSavedBalance(), + 0, + "Vault lastSavedBalance should be 0" + ); + + uint256 vaultBalance = 692 * 10 ** 5; + + vm.prank(user); + _synthVault.deposit(11 * 10 ** 6, user); + vm.prank(user2); + _synthVault.deposit(22 * 10 ** 6, user2); + vm.prank(user3); + _synthVault.deposit(33 * 10 ** 6, user3); + + _synthVault.start(); + + vaultBalance += 66 * 10 ** 6; + + assertEq( + _getUnderlyingBalance(address(_synthVault)), + 0, + "Vault should be empty" + ); + assertEq( + _synthVault.lastSavedBalance(), + vaultBalance, + "Vault should have 1352 * 10 ** 5 underlying (see {vaultBalance})" + ); + } +} diff --git a/test/v0/SyntheticVault/SyntheticInflation.t.sol b/test/v0/SyntheticVault/SyntheticInflation.t.sol new file mode 100644 index 0000000..c1c7896 --- /dev/null +++ b/test/v0/SyntheticVault/SyntheticInflation.t.sol @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "./SyntheticBase.t.sol"; + +contract SyntheticInflationTests is SyntheticBaseTests { + uint256 internal _underlyingBaseDepositPower = 10; + uint256 internal _underlyingBaseDeposit = 10 ** _underlyingBaseDepositPower; + uint256 internal _baseDepositDecimalsCount = _underlyingBaseDepositPower + 1; + uint256 internal _zeroBaseDeposit = 0; + + address internal _attacker; + address internal _victim; + + function _additionnalSetup() internal override { + // Bootstrap the AmphorSyntheticVault contract + + IERC20(_underlying).approve( + address(_synthVault), _underlyingBaseDeposit + ); + _attacker = _signer; + _victim = _signer2; + } + + function test_classicAttack() public { + // here donation is just victimDepositAmount + 1, so the attack should not work + + uint256 victimDepositAmount = 10; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = victimDepositAmount + 1; + + _testFailingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _zeroBaseDeposit + ); + } + + function test_attackWithPower2() public { + uint256 victimDepositAmount = 10_000 * 10 ** _underlyingDecimals; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = 10 ** 2 * victimDepositAmount; + + _testFailingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _zeroBaseDeposit + ); + } + + function test_attackWithPower3() public { + uint256 victimDepositAmount = 10_000 * 10 ** _underlyingDecimals; + + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = 10 ** 3 * victimDepositAmount; + + _testSucceeddingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _zeroBaseDeposit + ); + } + + function test_attackWithPower4() public { + uint256 victimDepositAmount = 10_000 * 10 ** _underlyingDecimals; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = 10 ** 4 * victimDepositAmount; + + _testSucceeddingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _zeroBaseDeposit + ); + } + + function test_attackWithPower5() public { + uint256 victimDepositAmount = 10_000 * 10 ** _underlyingDecimals; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = 10 ** 5 * victimDepositAmount; + + _testSucceeddingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _zeroBaseDeposit + ); + } + + function test_attackWithPower6() public { + uint256 victimDepositAmount = 10_000 * 10 ** _underlyingDecimals; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = 10 ** 6 * victimDepositAmount; + + _testSucceeddingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _zeroBaseDeposit + ); + } + + function test_attackWithPower7() public { + uint256 victimDepositAmount = 10_000 * 10 ** _underlyingDecimals; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = 10 ** 7 * victimDepositAmount; + + _testSucceeddingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _zeroBaseDeposit + ); + } + + function test_attackWithPower8() public { + uint256 victimDepositAmount = 10_000 * 10 ** _underlyingDecimals; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = 10 ** 8 * victimDepositAmount; + + _testSucceeddingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _zeroBaseDeposit + ); + } + + function test_attackWithExtremlyHighDonation() public { + // Testing inflation with an over big donation (so the attack should work) + uint256 victimDepositAmount = 10; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = victimDepositAmount + ** (_decimalOffset + _baseDepositDecimalsCount + 1); + _testSucceeddingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _underlyingBaseDeposit + ); + } + + function test_BaseFuzzInflation(uint8 donationPowerFactor) public { + vm.assume( + donationPowerFactor < _decimalOffset + _baseDepositDecimalsCount + 1 + ); + // Test inflation with only the base underlying amount in the vault + // This will try the attack with an amount up to vaults decimals + bootstrap decimal + 1 (+99%) + // For usdc, this means that with a 24 offset and a 10k USDC bootstrap we can go up to a 35 decimals amount + // up to 10 ** 29 . 000 000 USDC + + uint256 victimDepositAmount = 10; + uint256 attackDepositAmount = 1; + uint256 attackDonationAmount = + victimDepositAmount ** donationPowerFactor; + + _testFailingAttack( + victimDepositAmount, + attackDepositAmount, + attackDonationAmount, + _underlyingBaseDeposit + ); + } + + function _testSucceeddingAttack( + uint256 victimDepositAmount, + uint256 attackDepositAmount, + uint256 attackDonationAmount, + uint256 underlyingBaseDeposit + ) private { + // Fund the vault with some (vaultStartBalanceAddon) underlying, and mint the corresponding shares tokens + if (underlyingBaseDeposit > 0) { + deal( + address(_underlying), + address(this), + underlyingBaseDeposit, + false + ); + IERC20(_underlying).approve( + address(_synthVault), underlyingBaseDeposit + ); + _synthVault.deposit(underlyingBaseDeposit, address(this)); + } + + giveEthUnderlyingAndApprove( + _attacker, attackDepositAmount + attackDonationAmount + ); + + // Do the attack + vm.startPrank(_attacker); + _synthVault.deposit(attackDepositAmount, _attacker); + IERC20(_underlying).transfer(address(_synthVault), attackDonationAmount); + vm.stopPrank(); + + // Victim deposits some underlying + giveEthUnderlyingAndApprove(_victim, victimDepositAmount); + vm.prank(_victim); + _synthVault.deposit(victimDepositAmount, _victim); + + assertFalse( + victimDepositAmount - 1 // -1 because of the Math.Rounding.Floor + <= _synthVault.previewRedeem( + IERC20(address(_synthVault)).balanceOf(_victim) + ), + "victim should not have the appropriate underlying tokens amount" + ); + console.log('Attack "succeed":'); + console.log( + "Attacker's final balance", + _synthVault.previewRedeem(_getSharesBalance(_attacker)) + / 10 ** ERC20(_underlying).decimals() + ); + console.log( + "Victim's final balance", + _synthVault.previewRedeem(_getSharesBalance(_victim)) + / 10 ** ERC20(_underlying).decimals() + ); + console.log( + "Vault's final balance", + ERC20(_underlying).balanceOf(address(_synthVault)) + ); + + console.log( + "attacker loss:", + ( + attackDonationAmount + attackDepositAmount + - _synthVault.previewRedeem(_getSharesBalance(_attacker)) + ) / 10 ** ERC20(_underlying).decimals(), + " USDC" + ); + console.log( + "victim loss:", + ( + victimDepositAmount + - _synthVault.convertToAssets(_getSharesBalance(_victim)) + ), + // 10 ** ERC20(_underlying).decimals(), + "wei USDC" + ); + } + + function _testFailingAttack( + uint256 victimDepositAmount, + uint256 attackDepositAmount, + uint256 attackDonationAmount, + uint256 underlyingBaseDeposit + ) private { + if (underlyingBaseDeposit > 0) { + deal( + address(_underlying), + address(this), + underlyingBaseDeposit, + false + ); + IERC20(_underlying).approve( + address(_synthVault), underlyingBaseDeposit + ); + _synthVault.deposit(underlyingBaseDeposit, address(this)); + } + + giveEthUnderlyingAndApprove( + _attacker, attackDepositAmount + attackDonationAmount + ); + + // Do the attack + vm.startPrank(_attacker); + _synthVault.deposit(attackDepositAmount, _attacker); + IERC20(_underlying).transfer(address(_synthVault), attackDonationAmount); + vm.stopPrank(); + + // Victim deposits some underlying + giveEthUnderlyingAndApprove(_victim, victimDepositAmount); + vm.prank(_victim); + _synthVault.deposit(victimDepositAmount, _victim); + + assertEq( + victimDepositAmount - 1, // -1 because of the Math.Rounding.Floor + _synthVault.previewRedeem(_getSharesBalance(_victim)), + "Victim should have an appropriate underlying tokens amount" + ); + console.log("Attack failed:"); + console.log( + "attacker loss:", + ( + attackDonationAmount + attackDepositAmount + - _synthVault.previewRedeem(_getSharesBalance(_attacker)) + ) / 10 ** ERC20(_underlying).decimals(), + " USDC" + ); + console.log( + "victim loss:", + ( + victimDepositAmount + - _synthVault.previewRedeem(_getSharesBalance(_victim)) + ), + // 10 ** ERC20(_underlying).decimals(), + "wei USDC" + ); + } +} diff --git a/test/v0/SyntheticVault/SyntheticPausable.t.sol b/test/v0/SyntheticVault/SyntheticPausable.t.sol new file mode 100644 index 0000000..056a6f5 --- /dev/null +++ b/test/v0/SyntheticVault/SyntheticPausable.t.sol @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "./SyntheticPermit.t.sol"; +import "@src/AmphorSyntheticVault.sol"; +import "@openzeppelin-v4.9.3/contracts/access/Ownable.sol"; +import "@openzeppelin-v4.9.3/contracts/security/Pausable.sol"; +import "../../utils/SigUtils.sol"; +import "@openzeppelin-v4.9.3/contracts/security/Pausable.sol"; + +contract SyntheticPausableTests is SyntheticPermit { + function test_OwnerCanPause() public { + _synthVault.pause(); + assertEq(_synthVault.paused(), true); + } + + function test_notOwnerCantPause() public { + vm.prank(address(0x1234)); + + vm.expectRevert(); + _synthVault.pause(); + } + + function test_OwnerCanUnpause() public { + _synthVault.pause(); + _synthVault.unpause(); + assertEq(_synthVault.paused(), false); + } + + function test_notOwnerCantUnpause() public { + _synthVault.pause(); + vm.prank(address(0x1234)); + + vm.expectRevert(); + _synthVault.unpause(); + } + + function test_cantDoubleUnpause() public { + _synthVault.pause(); + _synthVault.unpause(); + vm.expectRevert(); + _synthVault.unpause(); + } + + function test_cantDoublepause() public { + _synthVault.pause(); + vm.expectRevert(); + _synthVault.pause(); + } + + function test_userCantDeposit() public { + _synthVault.pause(); + giveEthUnderlyingAndApprove(_user); + + vm.startPrank(_user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxDeposit.selector, + _user, + 1, + 0 + ) + ); + _synthVault.deposit(1, _user); + } + + function test_userCantMintWhenPaused() public { + _synthVault.pause(); + giveEthUnderlyingAndApprove(_user); + + vm.startPrank(_user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxMint.selector, + _user, + 1, + 0 + ) + ); + _synthVault.mint(1, _user); + } + + function test_userCantDepositWithPermit() public { + _synthVault.pause(); + giveEthUnderlyingAndApprove(_user); + + vm.startPrank(_user); + + (uint8 v, bytes32 r, bytes32 s) = + _signPermit(address(_synthVault), 1, _usdc.nonces(_user), _deadline); + vm.startPrank(_user); + + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxDeposit.selector, + _user, + 1, + 0 + ) + ); + PermitParams memory params = + PermitParams({value: 1, deadline: _deadline, v: v, r: r, s: s}); + _synthVault.depositWithPermit(1, _user, params); + } + + function test_userCantMintWithPermitWhenPaused() public { + _synthVault.pause(); + giveEthUnderlyingAndApprove(_user); + + (uint8 v, bytes32 r, bytes32 s) = + _signPermit(address(_synthVault), 1, _usdc.nonces(_user), _deadline); + vm.startPrank(_user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxMint.selector, + _user, + 1, + 0 + ) + ); + PermitParams memory params = + PermitParams({value: 1, deadline: _deadline, v: v, r: r, s: s}); + + _synthVault.mintWithPermit(1, _user, params); + } + + function test_userCanWithdraw() public { + uint256 amount = 1_000 * 10 ** 6; + giveEthUnderlyingAndApprove(_user); + uint256 underlyingBalance = _getUnderlyingBalance(_user); + vm.prank(_user); + _synthVault.deposit(amount, _user); + _synthVault.pause(); + vm.startPrank(_user); + _synthVault.withdraw(amount, _user, _user); + assertUnderlyingBalance(_user, underlyingBalance); + } + + function test_userCanRedeem() public { + uint256 amount = 1_000 * 10 ** 6; + giveEthUnderlyingAndApprove(_user); + uint256 underlyingBalance = _getUnderlyingBalance(_user); + vm.prank(_user); + _synthVault.deposit(amount, _user); + _synthVault.pause(); + vm.startPrank(_user); + _synthVault.redeem(_getSharesBalance(_user), _user, _user); + assertUnderlyingBalance(_user, underlyingBalance); + } + + function test_unPausingShouldGetBackToNormal() public { + _synthVault.pause(); + _synthVault.unpause(); + giveEthUnderlyingAndApprove(_user); + vm.startPrank(_user); + _synthVault.deposit(1, _user); + _synthVault.mint(1, _user); + (uint8 v, bytes32 r, bytes32 s) = + _signPermit(address(_synthVault), 1, _usdc.nonces(_user), _deadline); + vm.startPrank(_user); + PermitParams memory params = + PermitParams({value: 1, deadline: _deadline, v: v, r: r, s: s}); + _synthVault.mintWithPermit(1, _user, params); + (v, r, s) = + _signPermit(address(_synthVault), 1, _usdc.nonces(_user), _deadline); + vm.startPrank(_user); + params = PermitParams({value: 1, deadline: _deadline, v: v, r: r, s: s}); + _synthVault.depositWithPermit(1, _user, params); + _synthVault.withdraw(1, _user, _user); + _synthVault.redeem(1, _user, _user); + } +} diff --git a/test/v0/SyntheticVault/SyntheticPermit.t.sol b/test/v0/SyntheticVault/SyntheticPermit.t.sol new file mode 100644 index 0000000..123c918 --- /dev/null +++ b/test/v0/SyntheticVault/SyntheticPermit.t.sol @@ -0,0 +1,423 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import "./SyntheticBase.t.sol"; +import "../../utils/SigUtils.sol"; + +contract SyntheticPermit is SyntheticBaseTests { + SigUtils internal _sigUtils; + ERC20Permit internal _usdc = ERC20Permit(address(_underlying)); + uint256 internal _userPrivKey; + uint256 internal _deadline = block.timestamp + 1000; + address internal _user; + + function _additionnalSetup() internal override { + _sigUtils = new SigUtils(_usdc.DOMAIN_SEPARATOR()); + _userPrivKey = 0xA11CE; + _user = vm.addr(_userPrivKey); + giveEthUnderlyingAndApprove(_user); + } + + function test_BasicUsdcPermit() public { + address spender = address(_synthVault); + _execute_permit(spender, 10 * 1e6); + assertEq(_usdc.allowance(_user, spender), 10 * 1e6); + assertEq(_usdc.nonces(_user), 1); + } + + function test_depositWithPermit() public { + uint256 underlying = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + vm.prank(_user); + PermitParams memory params = PermitParams({ + value: underlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + _synthVault.depositWithPermit(underlying, _user, params); + assertSharesBalance(_user, underlying * 10 ** _decimalOffset); + assertUnderlyingBalance(_user, 0); + } + + function test_depositWithPermitUintMax() public { + uint256 underlying = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + UINT256_MAX, + _usdc.nonces(_user), + _deadline + ); + vm.prank(_user); + PermitParams memory params = PermitParams({ + value: UINT256_MAX, + deadline: _deadline, + v: v, + r: r, + s: s + }); + _synthVault.depositWithPermit(underlying, _user, params); + assertSharesBalance(_user, underlying * 10 ** _decimalOffset); + assertUnderlyingBalance(_user, 0); + } + + function test_depositWithPermitMinShares() public { + uint256 underlying = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + uint256 previewShares = _synthVault.previewMint(underlying); + vm.prank(_user); + PermitParams memory params = PermitParams({ + value: underlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + _synthVault.depositWithPermitMinShares( + underlying, + _user, + previewShares, + params + ); + } + + function test_depositWithPermitMinSharesUintMax() public { + uint256 underlying = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + UINT256_MAX, + _usdc.nonces(_user), + _deadline + ); + uint256 previewShares = _synthVault.previewMint(underlying); + vm.prank(_user); + PermitParams memory params = PermitParams({ + value: UINT256_MAX, + deadline: _deadline, + v: v, + r: r, + s: s + }); + _synthVault.depositWithPermitMinShares( + underlying, + _user, + previewShares, + params + ); + + assert( + ERC20(_underlying).allowance(_user, address(_synthVault)) == + UINT256_MAX - underlying + ); + } + + function test_depositWithPermitMinSharesTooLow() public { + uint256 underlying = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + uint256 previewShares = _synthVault.previewMint(underlying); + vm.prank(_user); + PermitParams memory params = PermitParams({ + value: underlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + _synthVault.depositWithPermitMinShares( + underlying, + _user, + previewShares + 1, + params + ); + } + + function test_MintWithPermit() public { + uint256 sharesExpected = 1_000_000 * 10 ** _decimalOffset; + uint256 underlying = _synthVault.previewMint(sharesExpected); + uint256 underlyingBefore = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + PermitParams memory params = PermitParams({ + value: underlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + vm.prank(_user); + _synthVault.mintWithPermit(sharesExpected, _user, params); + assertSharesBalance(_user, sharesExpected); + assertUnderlyingBalance(_user, underlyingBefore - underlying); + } + + function test_MintWithPermitAfterOtherUserDeposit() public { + address otherUser = address(0x012345); + giveEthUnderlyingAndApprove(otherUser); + vm.prank(otherUser); + _synthVault.deposit(1000 * 10 ** 6, otherUser); + uint256 sharesExpected = 1_000_000 * 10 ** _decimalOffset; + uint256 underlying = _synthVault.previewMint(sharesExpected); + uint256 underlyingBefore = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + PermitParams memory params = PermitParams({ + value: underlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + vm.prank(_user); + _synthVault.mintWithPermit(sharesExpected, _user, params); + assertSharesBalance(_user, sharesExpected); + assertUnderlyingBalance(_user, underlyingBefore - underlying); + } + + function test_MintWithPermitAfterVaultProfit() public { + // First deposit + address otherUser = address(0x012345); + giveEthUnderlyingAndApprove(otherUser); + vm.prank(otherUser); + _synthVault.deposit(1000 * 10 ** 6, otherUser); + + // Vault profit + deal( + address(_usdc), + address(_synthVault), + _usdc.balanceOf(address(_synthVault)) + 100 + ); + + // Mint with permit + uint256 sharesExpected = 1_000_000 * 10 ** _decimalOffset; + uint256 underlying = _synthVault.previewMint(sharesExpected); + uint256 underlyingBefore = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + PermitParams memory params = PermitParams({ + value: underlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + vm.prank(_user); + _synthVault.mintWithPermit(sharesExpected, _user, params); + assertSharesBalance(_user, sharesExpected); + assertUnderlyingBalance(_user, underlyingBefore - underlying); + } + + function test_MintWithPermitTooMuch() public { + uint256 sharesExpected = 1_000_000 * 10 ** _decimalOffset; + uint256 underlying = _synthVault.previewMint(sharesExpected); + uint256 tooMuchUnderlying = _synthVault.previewMint( + sharesExpected * 10 + ); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + + PermitParams memory params = PermitParams({ + value: tooMuchUnderlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + vm.prank(_user); + vm.expectRevert("EIP2612: invalid signature"); + _synthVault.mintWithPermit(sharesExpected * 10, _user, params); + } + + function test_TryingToScamPermit() public { + uint256 underlying = _getUnderlyingBalance(_user); + address _spender = address(_synthVault); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + _spender, + underlying, + _usdc.nonces(_user), + _deadline + ); + address randomSpender = vm.addr(0x1234); + vm.expectRevert("EIP2612: invalid signature"); + _usdc.permit(_user, randomSpender, underlying, _deadline, v, r, s); + } + + function test_mintWithPermitAfterStart() public { + giveEthUnderlyingAndApprove(_user); + _synthVault.start(); + uint256 sharesAmount = 100 * 10 ** 18; + uint256 assetAmount = _synthVault.previewMint(sharesAmount); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + assetAmount, + _usdc.nonces(_user), + _deadline + ); + PermitParams memory params = PermitParams({ + value: assetAmount, + deadline: _deadline, + v: v, + r: r, + s: s + }); + vm.prank(_user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxMint.selector, + _user, + sharesAmount, + 0 + ) + ); + _synthVault.mintWithPermit(sharesAmount, _user, params); + } + + function test_depositWithPermitAfterStart() public { + giveEthUnderlyingAndApprove(_user); + _synthVault.start(); + uint256 assetAmount = 100 * 10 ** 18; + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + assetAmount, + _usdc.nonces(_user), + _deadline + ); + PermitParams memory params = PermitParams({ + value: assetAmount, + deadline: _deadline, + v: v, + r: r, + s: s + }); + vm.prank(_user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626ExceededMaxDeposit.selector, + _user, + assetAmount, + 0 + ) + ); + _synthVault.depositWithPermit(assetAmount, _user, params); + } + + function test_MintWithPermitMaxAssets() public { + uint256 sharesExpected = 1_000 * 10 ** _synthVault.decimals(); + uint256 underlying = _synthVault.previewMint(sharesExpected); + uint256 underlyingBefore = _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + PermitParams memory params = PermitParams({ + value: underlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + vm.prank(_user); + _synthVault.mintWithPermitMaxAssets( + sharesExpected, + _user, + underlying, + params + ); + assertSharesBalance(_user, sharesExpected); + assertUnderlyingBalance(_user, underlyingBefore - underlying); + } + + function test_MintWithPermitMaxAssetsTooMuch() public { + uint256 sharesExpected = 1_000 * 10 ** _synthVault.decimals(); + uint256 underlying = _synthVault.previewMint(sharesExpected); + _getUnderlyingBalance(_user); + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + address(_synthVault), + underlying, + _usdc.nonces(_user), + _deadline + ); + PermitParams memory params = PermitParams({ + value: underlying, + deadline: _deadline, + v: v, + r: r, + s: s + }); + vm.prank(_user); + vm.expectRevert( + abi.encodeWithSelector( + AmphorSyntheticVault.ERC4626TooMuchAssetsDeposited.selector, + _user, + underlying, + underlying - 1 + ) + ); + _synthVault.mintWithPermitMaxAssets( + sharesExpected, + _user, + underlying - 1, + params + ); + } + + function _execute_permit(address _spender, uint256 _value) private { + (uint8 v, bytes32 r, bytes32 s) = _signPermit( + _spender, + _value, + _usdc.nonces(_user), + _deadline + ); + _usdc.permit(_user, _spender, _value, _deadline, v, r, s); + } + + function _signPermit( + address _spender, + uint256 _value, + uint256 _nonce, + uint256 deadline + ) internal view returns (uint8 v, bytes32 r, bytes32 s) { + SigUtils.Permit memory permit = SigUtils.Permit({ + owner: _user, + spender: _spender, + value: _value, + nonce: _nonce, + deadline: deadline + }); + bytes32 digest = _sigUtils.getTypedDataHash(permit); + return vm.sign(_userPrivKey, digest); + } +} diff --git a/test/v0/SyntheticVault/a16zCompliance.t.sol b/test/v0/SyntheticVault/a16zCompliance.t.sol new file mode 100644 index 0000000..d850d10 --- /dev/null +++ b/test/v0/SyntheticVault/a16zCompliance.t.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "erc4626-tests/ERC4626.test.sol"; + +import {PermitERC20 as ERC20Mock} from "@src/utils/PermitERC20.sol"; +import {AmphorSyntheticVaultWithPermit as ERC4626Mock} from "@src/AmphorSyntheticVaultWithPermit.sol"; + +contract A16zERC4626Tests { + // is ERC4626Test + // function setUp() public override { + // _underlying_ = address(new ERC20Mock("Mock ERC20", "MERC20", 6)); + // _underlying_ = vm.envAddress("USDC_MAINNET"); + // _vault_ = address( + // new ERC4626Mock(_underlying_, "Mock ERC4626", "MERC4626", 12) + // ); + // _delta_ = 0; + // _vaultMayBeEmpty = false; + // _unlimitedAmount = false; + // } +} diff --git a/test/v0/SyntheticVault/cryticCompliance.t.sol b/test/v0/SyntheticVault/cryticCompliance.t.sol new file mode 100644 index 0000000..e703ac1 --- /dev/null +++ b/test/v0/SyntheticVault/cryticCompliance.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.19; + +import {CryticERC4626PropertyTests} from + "@crytic/ERC4626/ERC4626PropertyTests.sol"; +// this token _must_ be the vault's underlying asset +import {TestERC20Token} from "@crytic/ERC4626/util/TestERC20Token.sol"; +// change to your vault implementation +import { + AmphorSyntheticVaultWithPermit, + ERC20 +} from "@src/AmphorSyntheticVaultWithPermit.sol"; + +contract CryticERC4626PropertyTestsSynth is CryticERC4626PropertyTests { + constructor() { + TestERC20Token _asset = new TestERC20Token("Test Token", "TT", 6); + AmphorSyntheticVaultWithPermit _vault = + new AmphorSyntheticVaultWithPermit( + ERC20(address(_asset)), + "Test Vault", + "TV", + 12 + ); + initialize(address(_vault), address(_asset), false); + } +}

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

{23QAMhgmDFwY9!) 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 literal 0 HcmV?d00001 diff --git a/lib/crytic/lib/solmate/foundry.toml b/lib/crytic/lib/solmate/foundry.toml new file mode 100644 index 0000000..ebdfa11 --- /dev/null +++ b/lib/crytic/lib/solmate/foundry.toml @@ -0,0 +1,7 @@ +[profile.default] +solc = "0.8.15" +bytecode_hash = "none" +optimizer_runs = 1000000 + +[profile.intense.fuzz] +runs = 10000 diff --git a/lib/crytic/lib/solmate/lib/ds-test/.gitignore b/lib/crytic/lib/solmate/lib/ds-test/.gitignore new file mode 100644 index 0000000..63f0b2c --- /dev/null +++ b/lib/crytic/lib/solmate/lib/ds-test/.gitignore @@ -0,0 +1,3 @@ +/.dapple +/build +/out diff --git a/lib/crytic/lib/solmate/lib/ds-test/LICENSE b/lib/crytic/lib/solmate/lib/ds-test/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib/crytic/lib/solmate/lib/ds-test/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/crytic/lib/solmate/lib/ds-test/Makefile b/lib/crytic/lib/solmate/lib/ds-test/Makefile new file mode 100644 index 0000000..661dac4 --- /dev/null +++ b/lib/crytic/lib/solmate/lib/ds-test/Makefile @@ -0,0 +1,14 @@ +all:; dapp build + +test: + -dapp --use solc:0.4.23 build + -dapp --use solc:0.4.26 build + -dapp --use solc:0.5.17 build + -dapp --use solc:0.6.12 build + -dapp --use solc:0.7.5 build + +demo: + DAPP_SRC=demo dapp --use solc:0.7.5 build + -hevm dapp-test --verbose 3 + +.PHONY: test demo diff --git a/lib/crytic/lib/solmate/lib/ds-test/default.nix b/lib/crytic/lib/solmate/lib/ds-test/default.nix new file mode 100644 index 0000000..cf65419 --- /dev/null +++ b/lib/crytic/lib/solmate/lib/ds-test/default.nix @@ -0,0 +1,4 @@ +{ solidityPackage, dappsys }: solidityPackage { + name = "ds-test"; + src = ./src; +} diff --git a/lib/crytic/lib/solmate/lib/ds-test/demo/demo.sol b/lib/crytic/lib/solmate/lib/ds-test/demo/demo.sol new file mode 100644 index 0000000..f3bb48e --- /dev/null +++ b/lib/crytic/lib/solmate/lib/ds-test/demo/demo.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import "../src/test.sol"; + +contract DemoTest is DSTest { + function test_this() public pure { + require(true); + } + function test_logs() public { + emit log("-- log(string)"); + emit log("a string"); + + emit log("-- log_named_uint(string, uint)"); + emit log_named_uint("uint", 512); + + emit log("-- log_named_int(string, int)"); + emit log_named_int("int", -512); + + emit log("-- log_named_address(string, address)"); + emit log_named_address("address", address(this)); + + emit log("-- log_named_bytes32(string, bytes32)"); + emit log_named_bytes32("bytes32", "a string"); + + emit log("-- log_named_bytes(string, bytes)"); + emit log_named_bytes("bytes", hex"cafefe"); + + emit log("-- log_named_string(string, string)"); + emit log_named_string("string", "a string"); + + emit log("-- log_named_decimal_uint(string, uint, uint)"); + emit log_named_decimal_uint("decimal uint", 1.0e18, 18); + + emit log("-- log_named_decimal_int(string, int, uint)"); + emit log_named_decimal_int("decimal int", -1.0e18, 18); + } + event log_old_named_uint(bytes32,uint); + function test_old_logs() public { + emit log_old_named_uint("key", 500); + emit log_named_bytes32("bkey", "val"); + } + function test_trace() public view { + this.echo("string 1", "string 2"); + } + function test_multiline() public { + emit log("a multiline\\nstring"); + emit log("a multiline string"); + emit log_bytes("a string"); + emit log_bytes("a multiline\nstring"); + emit log_bytes("a multiline\\nstring"); + emit logs(hex"0000"); + emit log_named_bytes("0x0000", hex"0000"); + emit logs(hex"ff"); + } + function echo(string memory s1, string memory s2) public pure + returns (string memory, string memory) + { + return (s1, s2); + } + + function prove_this(uint x) public { + emit log_named_uint("sym x", x); + assertGt(x + 1, 0); + } + + function test_logn() public { + assembly { + log0(0x01, 0x02) + log1(0x01, 0x02, 0x03) + log2(0x01, 0x02, 0x03, 0x04) + log3(0x01, 0x02, 0x03, 0x04, 0x05) + } + } + + event MyEvent(uint, uint indexed, uint, uint indexed); + function test_events() public { + emit MyEvent(1, 2, 3, 4); + } + + function test_asserts() public { + string memory err = "this test has failed!"; + emit log("## assertTrue(bool)\n"); + assertTrue(false); + emit log("\n"); + assertTrue(false, err); + + emit log("\n## assertEq(address,address)\n"); + assertEq(address(this), msg.sender); + emit log("\n"); + assertEq(address(this), msg.sender, err); + + emit log("\n## assertEq32(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(uint,uint)\n"); + assertEq(uint(0), 1); + emit log("\n"); + assertEq(uint(0), 1, err); + + emit log("\n## assertEq(int,int)\n"); + assertEq(-1, -2); + emit log("\n"); + assertEq(-1, -2, err); + + emit log("\n## assertEqDecimal(int,int,uint)\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertEqDecimal(uint,uint,uint)\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGt(uint,uint)\n"); + assertGt(uint(0), 0); + emit log("\n"); + assertGt(uint(0), 0, err); + + emit log("\n## assertGt(int,int)\n"); + assertGt(-1, -1); + emit log("\n"); + assertGt(-1, -1, err); + + emit log("\n## assertGtDecimal(int,int,uint)\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGtDecimal(uint,uint,uint)\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGe(uint,uint)\n"); + assertGe(uint(0), 1); + emit log("\n"); + assertGe(uint(0), 1, err); + + emit log("\n## assertGe(int,int)\n"); + assertGe(-1, 0); + emit log("\n"); + assertGe(-1, 0, err); + + emit log("\n## assertGeDecimal(int,int,uint)\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGeDecimal(uint,uint,uint)\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertLt(uint,uint)\n"); + assertLt(uint(0), 0); + emit log("\n"); + assertLt(uint(0), 0, err); + + emit log("\n## assertLt(int,int)\n"); + assertLt(-1, -1); + emit log("\n"); + assertLt(-1, -1, err); + + emit log("\n## assertLtDecimal(int,int,uint)\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLtDecimal(uint,uint,uint)\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertLe(uint,uint)\n"); + assertLe(uint(1), 0); + emit log("\n"); + assertLe(uint(1), 0, err); + + emit log("\n## assertLe(int,int)\n"); + assertLe(0, -1); + emit log("\n"); + assertLe(0, -1, err); + + emit log("\n## assertLeDecimal(int,int,uint)\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLeDecimal(uint,uint,uint)\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertEq(string,string)\n"); + string memory s1 = "string 1"; + string memory s2 = "string 2"; + assertEq(s1, s2); + emit log("\n"); + assertEq(s1, s2, err); + + emit log("\n## assertEq0(bytes,bytes)\n"); + assertEq0(hex"abcdef01", hex"abcdef02"); + emit log("\n"); + assertEq0(hex"abcdef01", hex"abcdef02", err); + } +} + +contract DemoTestWithSetUp { + function setUp() public { + } + function test_pass() public pure { + } +} diff --git a/lib/crytic/lib/solmate/lib/ds-test/package.json b/lib/crytic/lib/solmate/lib/ds-test/package.json new file mode 100644 index 0000000..4802ada --- /dev/null +++ b/lib/crytic/lib/solmate/lib/ds-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "ds-test", + "version": "1.0.0", + "description": "Assertions, equality checks and other test helpers ", + "bugs": "https://github.com/dapphub/ds-test/issues", + "license": "GPL-3.0", + "author": "Contributors to ds-test", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/dapphub/ds-test.git" + } +} diff --git a/lib/crytic/lib/solmate/lib/ds-test/src/test.sol b/lib/crytic/lib/solmate/lib/ds-test/src/test.sol new file mode 100644 index 0000000..515a3bd --- /dev/null +++ b/lib/crytic/lib/solmate/lib/ds-test/src/test.sol @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.5.0; + +contract DSTest { + event log (string); + event logs (bytes); + + event log_address (address); + event log_bytes32 (bytes32); + event log_int (int); + event log_uint (uint); + event log_bytes (bytes); + event log_string (string); + + event log_named_address (string key, address val); + event log_named_bytes32 (string key, bytes32 val); + event log_named_decimal_int (string key, int val, uint decimals); + event log_named_decimal_uint (string key, uint val, uint decimals); + event log_named_int (string key, int val); + event log_named_uint (string key, uint val); + event log_named_bytes (string key, bytes val); + event log_named_string (string key, string val); + + bool public IS_TEST = true; + bool private _failed; + + address constant HEVM_ADDRESS = + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); + + modifier mayRevert() { _; } + modifier testopts(string memory) { _; } + + function failed() public returns (bool) { + if (_failed) { + return _failed; + } else { + bool globalFailed = false; + if (hasHEVMContext()) { + (, bytes memory retdata) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("load(address,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed")) + ) + ); + globalFailed = abi.decode(retdata, (bool)); + } + return globalFailed; + } + } + + function fail() internal { + if (hasHEVMContext()) { + (bool status, ) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("store(address,bytes32,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) + ) + ); + status; // Silence compiler warnings + } + _failed = true; + } + + function hasHEVMContext() internal view returns (bool) { + uint256 hevmCodeSize = 0; + assembly { + hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) + } + return hevmCodeSize > 0; + } + + modifier logs_gas() { + uint startGas = gasleft(); + _; + uint endGas = gasleft(); + emit log_named_uint("gas", startGas - endGas); + } + + function assertTrue(bool condition) internal { + if (!condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertTrue(bool condition, string memory err) internal { + if (!condition) { + emit log_named_string("Error", err); + assertTrue(condition); + } + } + + function assertEq(address a, address b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [address]"); + emit log_named_address(" Expected", b); + emit log_named_address(" Actual", a); + fail(); + } + } + function assertEq(address a, address b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes32 a, bytes32 b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [bytes32]"); + emit log_named_bytes32(" Expected", b); + emit log_named_bytes32(" Actual", a); + fail(); + } + } + function assertEq(bytes32 a, bytes32 b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + function assertEq32(bytes32 a, bytes32 b) internal { + assertEq(a, b); + } + function assertEq32(bytes32 a, bytes32 b, string memory err) internal { + assertEq(a, b, err); + } + + function assertEq(int a, int b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [int]"); + emit log_named_int(" Expected", b); + emit log_named_int(" Actual", a); + fail(); + } + } + function assertEq(int a, int b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEq(uint a, uint b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + fail(); + } + } + function assertEq(uint a, uint b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEqDecimal(int a, int b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal int]"); + emit log_named_decimal_int(" Expected", b, decimals); + emit log_named_decimal_int(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + function assertEqDecimal(uint a, uint b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Expected", b, decimals); + emit log_named_decimal_uint(" Actual", a, decimals); + fail(); + } + } + function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + + function assertGt(uint a, uint b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGt(uint a, uint b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGt(int a, int b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGt(int a, int b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGtDecimal(int a, int b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + function assertGtDecimal(uint a, uint b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + + function assertGe(uint a, uint b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGe(uint a, uint b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGe(int a, int b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGe(int a, int b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGeDecimal(int a, int b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + function assertGeDecimal(uint a, uint b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertLt(uint a, uint b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLt(uint a, uint b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLt(int a, int b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLt(int a, int b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLtDecimal(int a, int b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + function assertLtDecimal(uint a, uint b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + + function assertLe(uint a, uint b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLe(uint a, uint b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLe(int a, int b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLe(int a, int b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLeDecimal(int a, int b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + function assertLeDecimal(uint a, uint b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log("Error: a == b not satisfied [string]"); + emit log_named_string(" Expected", b); + emit log_named_string(" Actual", a); + fail(); + } + } + function assertEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { + ok = true; + if (a.length == b.length) { + for (uint i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + ok = false; + } + } + } else { + ok = false; + } + } + function assertEq0(bytes memory a, bytes memory b) internal { + if (!checkEq0(a, b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + function assertEq0(bytes memory a, bytes memory b, string memory err) internal { + if (!checkEq0(a, b)) { + emit log_named_string("Error", err); + assertEq0(a, b); + } + } +} diff --git a/lib/crytic/lib/solmate/package-lock.json b/lib/crytic/lib/solmate/package-lock.json new file mode 100644 index 0000000..dd4d866 --- /dev/null +++ b/lib/crytic/lib/solmate/package-lock.json @@ -0,0 +1,125 @@ +{ + "name": "solmate", + "version": "6.7.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@solidity-parser/parser": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.13.2.tgz", + "integrity": "sha512-RwHnpRnfrnD2MSPveYoPh8nhofEvX7fgjHk1Oq+NNvCcLx4r1js91CO9o+F/F3fBzOCyvm8kKRTriFICX/odWw==", + "dev": true, + "requires": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "antlr4ts": { + "version": "0.5.0-alpha.4", + "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", + "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "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 + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, + "prettier-plugin-solidity": { + "version": "1.0.0-beta.16", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.16.tgz", + "integrity": "sha512-xVBcnoWpe52dNnCCbqPHC9ZrTWXcNfldf852ZD0DBcHDqVMwjHTAPEdfBVy6FczbFpVa8bmxQil+G5XkEz5WHA==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.13.2", + "emoji-regex": "^9.2.2", + "escape-string-regexp": "^4.0.0", + "semver": "^7.3.5", + "solidity-comments-extractor": "^0.0.7", + "string-width": "^4.2.2" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "solidity-comments-extractor": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz", + "integrity": "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.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 + } + } +} diff --git a/lib/crytic/lib/solmate/package.json b/lib/crytic/lib/solmate/package.json new file mode 100644 index 0000000..7cb23ec --- /dev/null +++ b/lib/crytic/lib/solmate/package.json @@ -0,0 +1,20 @@ +{ + "name": "solmate", + "license": "AGPL-3.0-only", + "version": "6.7.0", + "description": "Modern, opinionated and gas optimized building blocks for smart contract development.", + "files": [ + "src/**/*.sol" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/transmissions11/solmate.git" + }, + "devDependencies": { + "prettier": "^2.3.1", + "prettier-plugin-solidity": "^1.0.0-beta.13" + }, + "scripts": { + "lint": "prettier --write **.sol" + } +} diff --git a/lib/crytic/lib/solmate/src/auth/Auth.sol b/lib/crytic/lib/solmate/src/auth/Auth.sol new file mode 100644 index 0000000..3807ccd --- /dev/null +++ b/lib/crytic/lib/solmate/src/auth/Auth.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol) +/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) +abstract contract Auth { + event OwnershipTransferred(address indexed user, address indexed newOwner); + + event AuthorityUpdated(address indexed user, Authority indexed newAuthority); + + address public owner; + + Authority public authority; + + constructor(address _owner, Authority _authority) { + owner = _owner; + authority = _authority; + + emit OwnershipTransferred(msg.sender, _owner); + emit AuthorityUpdated(msg.sender, _authority); + } + + modifier requiresAuth() virtual { + require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED"); + + _; + } + + function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) { + Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas. + + // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be + // aware that this makes protected functions uncallable even to the owner if the authority is out of order. + return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner; + } + + function setAuthority(Authority newAuthority) public virtual { + // We check if the caller is the owner first because we want to ensure they can + // always swap out the authority even if it's reverting or using up a lot of gas. + require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig)); + + authority = newAuthority; + + emit AuthorityUpdated(msg.sender, newAuthority); + } + + function transferOwnership(address newOwner) public virtual requiresAuth { + owner = newOwner; + + emit OwnershipTransferred(msg.sender, newOwner); + } +} + +/// @notice A generic interface for a contract which provides authorization data to an Auth instance. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol) +/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol) +interface Authority { + function canCall( + address user, + address target, + bytes4 functionSig + ) external view returns (bool); +} diff --git a/lib/crytic/lib/solmate/src/auth/Owned.sol b/lib/crytic/lib/solmate/src/auth/Owned.sol new file mode 100644 index 0000000..e82b44d --- /dev/null +++ b/lib/crytic/lib/solmate/src/auth/Owned.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Simple single owner authorization mixin. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) +abstract contract Owned { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event OwnershipTransferred(address indexed user, address indexed newOwner); + + /*////////////////////////////////////////////////////////////// + OWNERSHIP STORAGE + //////////////////////////////////////////////////////////////*/ + + address public owner; + + modifier onlyOwner() virtual { + require(msg.sender == owner, "UNAUTHORIZED"); + + _; + } + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(address _owner) { + owner = _owner; + + emit OwnershipTransferred(address(0), _owner); + } + + /*////////////////////////////////////////////////////////////// + OWNERSHIP LOGIC + //////////////////////////////////////////////////////////////*/ + + function transferOwnership(address newOwner) public virtual onlyOwner { + owner = newOwner; + + emit OwnershipTransferred(msg.sender, newOwner); + } +} diff --git a/lib/crytic/lib/solmate/src/auth/authorities/MultiRolesAuthority.sol b/lib/crytic/lib/solmate/src/auth/authorities/MultiRolesAuthority.sol new file mode 100644 index 0000000..3ff80bb --- /dev/null +++ b/lib/crytic/lib/solmate/src/auth/authorities/MultiRolesAuthority.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Auth, Authority} from "../Auth.sol"; + +/// @notice Flexible and target agnostic role based Authority that supports up to 256 roles. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/authorities/MultiRolesAuthority.sol) +contract MultiRolesAuthority is Auth, Authority { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event UserRoleUpdated(address indexed user, uint8 indexed role, bool enabled); + + event PublicCapabilityUpdated(bytes4 indexed functionSig, bool enabled); + + event RoleCapabilityUpdated(uint8 indexed role, bytes4 indexed functionSig, bool enabled); + + event TargetCustomAuthorityUpdated(address indexed target, Authority indexed authority); + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(address _owner, Authority _authority) Auth(_owner, _authority) {} + + /*////////////////////////////////////////////////////////////// + CUSTOM TARGET AUTHORITY STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => Authority) public getTargetCustomAuthority; + + /*////////////////////////////////////////////////////////////// + ROLE/USER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => bytes32) public getUserRoles; + + mapping(bytes4 => bool) public isCapabilityPublic; + + mapping(bytes4 => bytes32) public getRolesWithCapability; + + function doesUserHaveRole(address user, uint8 role) public view virtual returns (bool) { + return (uint256(getUserRoles[user]) >> role) & 1 != 0; + } + + function doesRoleHaveCapability(uint8 role, bytes4 functionSig) public view virtual returns (bool) { + return (uint256(getRolesWithCapability[functionSig]) >> role) & 1 != 0; + } + + /*////////////////////////////////////////////////////////////// + AUTHORIZATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function canCall( + address user, + address target, + bytes4 functionSig + ) public view virtual override returns (bool) { + Authority customAuthority = getTargetCustomAuthority[target]; + + if (address(customAuthority) != address(0)) return customAuthority.canCall(user, target, functionSig); + + return + isCapabilityPublic[functionSig] || bytes32(0) != getUserRoles[user] & getRolesWithCapability[functionSig]; + } + + /*/////////////////////////////////////////////////////////////// + CUSTOM TARGET AUTHORITY CONFIGURATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function setTargetCustomAuthority(address target, Authority customAuthority) public virtual requiresAuth { + getTargetCustomAuthority[target] = customAuthority; + + emit TargetCustomAuthorityUpdated(target, customAuthority); + } + + /*////////////////////////////////////////////////////////////// + PUBLIC CAPABILITY CONFIGURATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function setPublicCapability(bytes4 functionSig, bool enabled) public virtual requiresAuth { + isCapabilityPublic[functionSig] = enabled; + + emit PublicCapabilityUpdated(functionSig, enabled); + } + + /*////////////////////////////////////////////////////////////// + USER ROLE ASSIGNMENT LOGIC + //////////////////////////////////////////////////////////////*/ + + function setUserRole( + address user, + uint8 role, + bool enabled + ) public virtual requiresAuth { + if (enabled) { + getUserRoles[user] |= bytes32(1 << role); + } else { + getUserRoles[user] &= ~bytes32(1 << role); + } + + emit UserRoleUpdated(user, role, enabled); + } + + /*////////////////////////////////////////////////////////////// + ROLE CAPABILITY CONFIGURATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function setRoleCapability( + uint8 role, + bytes4 functionSig, + bool enabled + ) public virtual requiresAuth { + if (enabled) { + getRolesWithCapability[functionSig] |= bytes32(1 << role); + } else { + getRolesWithCapability[functionSig] &= ~bytes32(1 << role); + } + + emit RoleCapabilityUpdated(role, functionSig, enabled); + } +} diff --git a/lib/crytic/lib/solmate/src/auth/authorities/RolesAuthority.sol b/lib/crytic/lib/solmate/src/auth/authorities/RolesAuthority.sol new file mode 100644 index 0000000..aa5cc71 --- /dev/null +++ b/lib/crytic/lib/solmate/src/auth/authorities/RolesAuthority.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Auth, Authority} from "../Auth.sol"; + +/// @notice Role based Authority that supports up to 256 roles. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/authorities/RolesAuthority.sol) +/// @author Modified from Dappsys (https://github.com/dapphub/ds-roles/blob/master/src/roles.sol) +contract RolesAuthority is Auth, Authority { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event UserRoleUpdated(address indexed user, uint8 indexed role, bool enabled); + + event PublicCapabilityUpdated(address indexed target, bytes4 indexed functionSig, bool enabled); + + event RoleCapabilityUpdated(uint8 indexed role, address indexed target, bytes4 indexed functionSig, bool enabled); + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(address _owner, Authority _authority) Auth(_owner, _authority) {} + + /*////////////////////////////////////////////////////////////// + ROLE/USER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => bytes32) public getUserRoles; + + mapping(address => mapping(bytes4 => bool)) public isCapabilityPublic; + + mapping(address => mapping(bytes4 => bytes32)) public getRolesWithCapability; + + function doesUserHaveRole(address user, uint8 role) public view virtual returns (bool) { + return (uint256(getUserRoles[user]) >> role) & 1 != 0; + } + + function doesRoleHaveCapability( + uint8 role, + address target, + bytes4 functionSig + ) public view virtual returns (bool) { + return (uint256(getRolesWithCapability[target][functionSig]) >> role) & 1 != 0; + } + + /*////////////////////////////////////////////////////////////// + AUTHORIZATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function canCall( + address user, + address target, + bytes4 functionSig + ) public view virtual override returns (bool) { + return + isCapabilityPublic[target][functionSig] || + bytes32(0) != getUserRoles[user] & getRolesWithCapability[target][functionSig]; + } + + /*////////////////////////////////////////////////////////////// + ROLE CAPABILITY CONFIGURATION LOGIC + //////////////////////////////////////////////////////////////*/ + + function setPublicCapability( + address target, + bytes4 functionSig, + bool enabled + ) public virtual requiresAuth { + isCapabilityPublic[target][functionSig] = enabled; + + emit PublicCapabilityUpdated(target, functionSig, enabled); + } + + function setRoleCapability( + uint8 role, + address target, + bytes4 functionSig, + bool enabled + ) public virtual requiresAuth { + if (enabled) { + getRolesWithCapability[target][functionSig] |= bytes32(1 << role); + } else { + getRolesWithCapability[target][functionSig] &= ~bytes32(1 << role); + } + + emit RoleCapabilityUpdated(role, target, functionSig, enabled); + } + + /*////////////////////////////////////////////////////////////// + USER ROLE ASSIGNMENT LOGIC + //////////////////////////////////////////////////////////////*/ + + function setUserRole( + address user, + uint8 role, + bool enabled + ) public virtual requiresAuth { + if (enabled) { + getUserRoles[user] |= bytes32(1 << role); + } else { + getUserRoles[user] &= ~bytes32(1 << role); + } + + emit UserRoleUpdated(user, role, enabled); + } +} diff --git a/lib/crytic/lib/solmate/src/mixins/ERC4626.sol b/lib/crytic/lib/solmate/src/mixins/ERC4626.sol new file mode 100644 index 0000000..af56c15 --- /dev/null +++ b/lib/crytic/lib/solmate/src/mixins/ERC4626.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "../tokens/ERC20.sol"; +import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; +import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol"; + +/// @notice Minimal ERC4626 tokenized Vault implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/mixins/ERC4626.sol) +abstract contract ERC4626 is ERC20 { + using SafeTransferLib for ERC20; + using FixedPointMathLib for uint256; + + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed caller, + address indexed receiver, + address indexed owner, + uint256 assets, + uint256 shares + ); + + /*////////////////////////////////////////////////////////////// + IMMUTABLES + //////////////////////////////////////////////////////////////*/ + + ERC20 public immutable asset; + + constructor( + ERC20 _asset, + string memory _name, + string memory _symbol + ) ERC20(_name, _symbol, _asset.decimals()) { + asset = _asset; + } + + /*////////////////////////////////////////////////////////////// + DEPOSIT/WITHDRAWAL LOGIC + //////////////////////////////////////////////////////////////*/ + + function deposit(uint256 assets, address receiver) public virtual returns (uint256 shares) { + // Check for rounding error since we round down in previewDeposit. + require((shares = previewDeposit(assets)) != 0, "ZERO_SHARES"); + + // Need to transfer before minting or ERC777s could reenter. + asset.safeTransferFrom(msg.sender, address(this), assets); + + _mint(receiver, shares); + + emit Deposit(msg.sender, receiver, assets, shares); + + afterDeposit(assets, shares); + } + + function mint(uint256 shares, address receiver) public virtual returns (uint256 assets) { + assets = previewMint(shares); // No need to check for rounding error, previewMint rounds up. + + // Need to transfer before minting or ERC777s could reenter. + asset.safeTransferFrom(msg.sender, address(this), assets); + + _mint(receiver, shares); + + emit Deposit(msg.sender, receiver, assets, shares); + + afterDeposit(assets, shares); + } + + function withdraw( + uint256 assets, + address receiver, + address owner + ) public virtual returns (uint256 shares) { + shares = previewWithdraw(assets); // No need to check for rounding error, previewWithdraw rounds up. + + if (msg.sender != owner) { + uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; + } + + beforeWithdraw(assets, shares); + + _burn(owner, shares); + + emit Withdraw(msg.sender, receiver, owner, assets, shares); + + asset.safeTransfer(receiver, assets); + } + + function redeem( + uint256 shares, + address receiver, + address owner + ) public virtual returns (uint256 assets) { + if (msg.sender != owner) { + uint256 allowed = allowance[owner][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[owner][msg.sender] = allowed - shares; + } + + // Check for rounding error since we round down in previewRedeem. + require((assets = previewRedeem(shares)) != 0, "ZERO_ASSETS"); + + beforeWithdraw(assets, shares); + + _burn(owner, shares); + + emit Withdraw(msg.sender, receiver, owner, assets, shares); + + asset.safeTransfer(receiver, assets); + } + + /*////////////////////////////////////////////////////////////// + ACCOUNTING LOGIC + //////////////////////////////////////////////////////////////*/ + + function totalAssets() public view virtual returns (uint256); + + function convertToShares(uint256 assets) public view virtual returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets()); + } + + function convertToAssets(uint256 shares) public view virtual returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? shares : shares.mulDivDown(totalAssets(), supply); + } + + function previewDeposit(uint256 assets) public view virtual returns (uint256) { + return convertToShares(assets); + } + + function previewMint(uint256 shares) public view virtual returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? shares : shares.mulDivUp(totalAssets(), supply); + } + + function previewWithdraw(uint256 assets) public view virtual returns (uint256) { + uint256 supply = totalSupply; // Saves an extra SLOAD if totalSupply is non-zero. + + return supply == 0 ? assets : assets.mulDivUp(supply, totalAssets()); + } + + function previewRedeem(uint256 shares) public view virtual returns (uint256) { + return convertToAssets(shares); + } + + /*////////////////////////////////////////////////////////////// + DEPOSIT/WITHDRAWAL LIMIT LOGIC + //////////////////////////////////////////////////////////////*/ + + function maxDeposit(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + function maxMint(address) public view virtual returns (uint256) { + return type(uint256).max; + } + + function maxWithdraw(address owner) public view virtual returns (uint256) { + return convertToAssets(balanceOf[owner]); + } + + function maxRedeem(address owner) public view virtual returns (uint256) { + return balanceOf[owner]; + } + + /*////////////////////////////////////////////////////////////// + INTERNAL HOOKS LOGIC + //////////////////////////////////////////////////////////////*/ + + function beforeWithdraw(uint256 assets, uint256 shares) internal virtual {} + + function afterDeposit(uint256 assets, uint256 shares) internal virtual {} +} diff --git a/lib/crytic/lib/solmate/src/test/Auth.t.sol b/lib/crytic/lib/solmate/src/test/Auth.t.sol new file mode 100644 index 0000000..9e31528 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/Auth.t.sol @@ -0,0 +1,192 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockAuthChild} from "./utils/mocks/MockAuthChild.sol"; +import {MockAuthority} from "./utils/mocks/MockAuthority.sol"; + +import {Authority} from "../auth/Auth.sol"; + +contract OutOfOrderAuthority is Authority { + function canCall( + address, + address, + bytes4 + ) public pure override returns (bool) { + revert("OUT_OF_ORDER"); + } +} + +contract AuthTest is DSTestPlus { + MockAuthChild mockAuthChild; + + function setUp() public { + mockAuthChild = new MockAuthChild(); + } + + function testTransferOwnershipAsOwner() public { + mockAuthChild.transferOwnership(address(0xBEEF)); + assertEq(mockAuthChild.owner(), address(0xBEEF)); + } + + function testSetAuthorityAsOwner() public { + mockAuthChild.setAuthority(Authority(address(0xBEEF))); + assertEq(address(mockAuthChild.authority()), address(0xBEEF)); + } + + function testCallFunctionAsOwner() public { + mockAuthChild.updateFlag(); + } + + function testTransferOwnershipWithPermissiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.transferOwnership(address(this)); + } + + function testSetAuthorityWithPermissiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.setAuthority(Authority(address(0xBEEF))); + } + + function testCallFunctionWithPermissiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.updateFlag(); + } + + function testSetAuthorityAsOwnerWithOutOfOrderAuthority() public { + mockAuthChild.setAuthority(new OutOfOrderAuthority()); + mockAuthChild.setAuthority(new MockAuthority(true)); + } + + function testFailTransferOwnershipAsNonOwner() public { + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.transferOwnership(address(0xBEEF)); + } + + function testFailSetAuthorityAsNonOwner() public { + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.setAuthority(Authority(address(0xBEEF))); + } + + function testFailCallFunctionAsNonOwner() public { + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipWithRestrictiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.transferOwnership(address(this)); + } + + function testFailSetAuthorityWithRestrictiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.setAuthority(Authority(address(0xBEEF))); + } + + function testFailCallFunctionWithRestrictiveAuthority() public { + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(address(0)); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipAsOwnerWithOutOfOrderAuthority() public { + mockAuthChild.setAuthority(new OutOfOrderAuthority()); + mockAuthChild.transferOwnership(address(0)); + } + + function testFailCallFunctionAsOwnerWithOutOfOrderAuthority() public { + mockAuthChild.setAuthority(new OutOfOrderAuthority()); + mockAuthChild.updateFlag(); + } + + function testTransferOwnershipAsOwner(address newOwner) public { + mockAuthChild.transferOwnership(newOwner); + assertEq(mockAuthChild.owner(), newOwner); + } + + function testSetAuthorityAsOwner(Authority newAuthority) public { + mockAuthChild.setAuthority(newAuthority); + assertEq(address(mockAuthChild.authority()), address(newAuthority)); + } + + function testTransferOwnershipWithPermissiveAuthority(address deadOwner, address newOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.transferOwnership(newOwner); + } + + function testSetAuthorityWithPermissiveAuthority(address deadOwner, Authority newAuthority) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.setAuthority(newAuthority); + } + + function testCallFunctionWithPermissiveAuthority(address deadOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(true)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipAsNonOwner(address deadOwner, address newOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.transferOwnership(newOwner); + } + + function testFailSetAuthorityAsNonOwner(address deadOwner, Authority newAuthority) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.setAuthority(newAuthority); + } + + function testFailCallFunctionAsNonOwner(address deadOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipWithRestrictiveAuthority(address deadOwner, address newOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.transferOwnership(newOwner); + } + + function testFailSetAuthorityWithRestrictiveAuthority(address deadOwner, Authority newAuthority) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.setAuthority(newAuthority); + } + + function testFailCallFunctionWithRestrictiveAuthority(address deadOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new MockAuthority(false)); + mockAuthChild.transferOwnership(deadOwner); + mockAuthChild.updateFlag(); + } + + function testFailTransferOwnershipAsOwnerWithOutOfOrderAuthority(address deadOwner) public { + if (deadOwner == address(this)) deadOwner = address(0); + + mockAuthChild.setAuthority(new OutOfOrderAuthority()); + mockAuthChild.transferOwnership(deadOwner); + } +} diff --git a/lib/crytic/lib/solmate/src/test/Bytes32AddressLib.t.sol b/lib/crytic/lib/solmate/src/test/Bytes32AddressLib.t.sol new file mode 100644 index 0000000..6c0a3d8 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/Bytes32AddressLib.t.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {Bytes32AddressLib} from "../utils/Bytes32AddressLib.sol"; + +contract Bytes32AddressLibTest is DSTestPlus { + function testFillLast12Bytes() public { + assertEq( + Bytes32AddressLib.fillLast12Bytes(0xfEEDFaCEcaFeBEEFfEEDFACecaFEBeeFfeEdfAce), + 0xfeedfacecafebeeffeedfacecafebeeffeedface000000000000000000000000 + ); + } + + function testFromLast20Bytes() public { + assertEq( + Bytes32AddressLib.fromLast20Bytes(0xfeedfacecafebeeffeedfacecafebeeffeedfacecafebeeffeedfacecafebeef), + 0xCAfeBeefFeedfAceCAFeBEEffEEDfaCecafEBeeF + ); + } +} diff --git a/lib/crytic/lib/solmate/src/test/CREATE3.t.sol b/lib/crytic/lib/solmate/src/test/CREATE3.t.sol new file mode 100644 index 0000000..b279eeb --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/CREATE3.t.sol @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {WETH} from "../tokens/WETH.sol"; +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockERC20} from "./utils/mocks/MockERC20.sol"; +import {MockAuthChild} from "./utils/mocks/MockAuthChild.sol"; + +import {CREATE3} from "../utils/CREATE3.sol"; + +contract CREATE3Test is DSTestPlus { + function testDeployERC20() public { + bytes32 salt = keccak256(bytes("A salt!")); + + MockERC20 deployed = MockERC20( + CREATE3.deploy( + salt, + abi.encodePacked(type(MockERC20).creationCode, abi.encode("Mock Token", "MOCK", 18)), + 0 + ) + ); + + assertEq(address(deployed), CREATE3.getDeployed(salt)); + + assertEq(deployed.name(), "Mock Token"); + assertEq(deployed.symbol(), "MOCK"); + assertEq(deployed.decimals(), 18); + } + + function testFailDoubleDeploySameBytecode() public { + bytes32 salt = keccak256(bytes("Salty...")); + + CREATE3.deploy(salt, type(MockAuthChild).creationCode, 0); + CREATE3.deploy(salt, type(MockAuthChild).creationCode, 0); + } + + function testFailDoubleDeployDifferentBytecode() public { + bytes32 salt = keccak256(bytes("and sweet!")); + + CREATE3.deploy(salt, type(WETH).creationCode, 0); + CREATE3.deploy(salt, type(MockAuthChild).creationCode, 0); + } + + function testDeployERC20( + bytes32 salt, + string calldata name, + string calldata symbol, + uint8 decimals + ) public { + MockERC20 deployed = MockERC20( + CREATE3.deploy(salt, abi.encodePacked(type(MockERC20).creationCode, abi.encode(name, symbol, decimals)), 0) + ); + + assertEq(address(deployed), CREATE3.getDeployed(salt)); + + assertEq(deployed.name(), name); + assertEq(deployed.symbol(), symbol); + assertEq(deployed.decimals(), decimals); + } + + function testFailDoubleDeploySameBytecode(bytes32 salt, bytes calldata bytecode) public { + CREATE3.deploy(salt, bytecode, 0); + CREATE3.deploy(salt, bytecode, 0); + } + + function testFailDoubleDeployDifferentBytecode( + bytes32 salt, + bytes calldata bytecode1, + bytes calldata bytecode2 + ) public { + CREATE3.deploy(salt, bytecode1, 0); + CREATE3.deploy(salt, bytecode2, 0); + } +} diff --git a/lib/crytic/lib/solmate/src/test/DSTestPlus.t.sol b/lib/crytic/lib/solmate/src/test/DSTestPlus.t.sol new file mode 100644 index 0000000..db10860 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/DSTestPlus.t.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +contract DSTestPlusTest is DSTestPlus { + function testBound() public { + assertEq(bound(0, 69, 69), 69); + assertEq(bound(0, 68, 69), 68); + assertEq(bound(5, 0, 4), 0); + assertEq(bound(9999, 1337, 6666), 6006); + assertEq(bound(0, type(uint256).max - 6, type(uint256).max), type(uint256).max - 6); + assertEq(bound(6, type(uint256).max - 6, type(uint256).max), type(uint256).max); + } + + function testFailBoundMinBiggerThanMax() public { + bound(5, 100, 10); + } + + function testRelApproxEqBothZeroesPasses() public { + assertRelApproxEq(0, 0, 1e18); + assertRelApproxEq(0, 0, 0); + } + + function testBound( + uint256 num, + uint256 min, + uint256 max + ) public { + if (min > max) (min, max) = (max, min); + + uint256 bounded = bound(num, min, max); + + assertGe(bounded, min); + assertLe(bounded, max); + } + + function testFailBoundMinBiggerThanMax( + uint256 num, + uint256 min, + uint256 max + ) public { + if (max == min) { + unchecked { + min++; // Overflow is handled below. + } + } + + if (max > min) (min, max) = (max, min); + + bound(num, min, max); + } + + function testBrutalizeMemory() public brutalizeMemory("FEEDFACECAFEBEEFFEEDFACECAFEBEEF") { + bytes32 scratchSpace1; + bytes32 scratchSpace2; + bytes32 freeMem1; + bytes32 freeMem2; + + assembly { + scratchSpace1 := mload(0) + scratchSpace2 := mload(32) + freeMem1 := mload(mload(0x40)) + freeMem2 := mload(add(mload(0x40), 32)) + } + + assertGt(uint256(freeMem1), 0); + assertGt(uint256(freeMem2), 0); + assertGt(uint256(scratchSpace1), 0); + assertGt(uint256(scratchSpace2), 0); + } +} diff --git a/lib/crytic/lib/solmate/src/test/ERC1155.t.sol b/lib/crytic/lib/solmate/src/test/ERC1155.t.sol new file mode 100644 index 0000000..9e32d88 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/ERC1155.t.sol @@ -0,0 +1,1777 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {MockERC1155} from "./utils/mocks/MockERC1155.sol"; + +import {ERC1155TokenReceiver} from "../tokens/ERC1155.sol"; + +contract ERC1155Recipient is ERC1155TokenReceiver { + address public operator; + address public from; + uint256 public id; + uint256 public amount; + bytes public mintData; + + function onERC1155Received( + address _operator, + address _from, + uint256 _id, + uint256 _amount, + bytes calldata _data + ) public override returns (bytes4) { + operator = _operator; + from = _from; + id = _id; + amount = _amount; + mintData = _data; + + return ERC1155TokenReceiver.onERC1155Received.selector; + } + + address public batchOperator; + address public batchFrom; + uint256[] internal _batchIds; + uint256[] internal _batchAmounts; + bytes public batchData; + + function batchIds() external view returns (uint256[] memory) { + return _batchIds; + } + + function batchAmounts() external view returns (uint256[] memory) { + return _batchAmounts; + } + + function onERC1155BatchReceived( + address _operator, + address _from, + uint256[] calldata _ids, + uint256[] calldata _amounts, + bytes calldata _data + ) external override returns (bytes4) { + batchOperator = _operator; + batchFrom = _from; + _batchIds = _ids; + _batchAmounts = _amounts; + batchData = _data; + + return ERC1155TokenReceiver.onERC1155BatchReceived.selector; + } +} + +contract RevertingERC1155Recipient is ERC1155TokenReceiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes calldata + ) public pure override returns (bytes4) { + revert(string(abi.encodePacked(ERC1155TokenReceiver.onERC1155Received.selector))); + } + + function onERC1155BatchReceived( + address, + address, + uint256[] calldata, + uint256[] calldata, + bytes calldata + ) external pure override returns (bytes4) { + revert(string(abi.encodePacked(ERC1155TokenReceiver.onERC1155BatchReceived.selector))); + } +} + +contract WrongReturnDataERC1155Recipient is ERC1155TokenReceiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes calldata + ) public pure override returns (bytes4) { + return 0xCAFEBEEF; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] calldata, + uint256[] calldata, + bytes calldata + ) external pure override returns (bytes4) { + return 0xCAFEBEEF; + } +} + +contract NonERC1155Recipient {} + +contract ERC1155Test is DSTestPlus, ERC1155TokenReceiver { + MockERC1155 token; + + mapping(address => mapping(uint256 => uint256)) public userMintAmounts; + mapping(address => mapping(uint256 => uint256)) public userTransferOrBurnAmounts; + + function setUp() public { + token = new MockERC1155(); + } + + function testMintToEOA() public { + token.mint(address(0xBEEF), 1337, 1, ""); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 1); + } + + function testMintToERC1155Recipient() public { + ERC1155Recipient to = new ERC1155Recipient(); + + token.mint(address(to), 1337, 1, "testing 123"); + + assertEq(token.balanceOf(address(to), 1337), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), 1337); + assertBytesEq(to.mintData(), "testing 123"); + } + + function testBatchMintToEOA() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory amounts = new uint256[](5); + amounts[0] = 100; + amounts[1] = 200; + amounts[2] = 300; + amounts[3] = 400; + amounts[4] = 500; + + token.batchMint(address(0xBEEF), ids, amounts, ""); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 100); + assertEq(token.balanceOf(address(0xBEEF), 1338), 200); + assertEq(token.balanceOf(address(0xBEEF), 1339), 300); + assertEq(token.balanceOf(address(0xBEEF), 1340), 400); + assertEq(token.balanceOf(address(0xBEEF), 1341), 500); + } + + function testBatchMintToERC1155Recipient() public { + ERC1155Recipient to = new ERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory amounts = new uint256[](5); + amounts[0] = 100; + amounts[1] = 200; + amounts[2] = 300; + amounts[3] = 400; + amounts[4] = 500; + + token.batchMint(address(to), ids, amounts, "testing 123"); + + assertEq(to.batchOperator(), address(this)); + assertEq(to.batchFrom(), address(0)); + assertUintArrayEq(to.batchIds(), ids); + assertUintArrayEq(to.batchAmounts(), amounts); + assertBytesEq(to.batchData(), "testing 123"); + + assertEq(token.balanceOf(address(to), 1337), 100); + assertEq(token.balanceOf(address(to), 1338), 200); + assertEq(token.balanceOf(address(to), 1339), 300); + assertEq(token.balanceOf(address(to), 1340), 400); + assertEq(token.balanceOf(address(to), 1341), 500); + } + + function testBurn() public { + token.mint(address(0xBEEF), 1337, 100, ""); + + token.burn(address(0xBEEF), 1337, 70); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 30); + } + + function testBatchBurn() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory burnAmounts = new uint256[](5); + burnAmounts[0] = 50; + burnAmounts[1] = 100; + burnAmounts[2] = 150; + burnAmounts[3] = 200; + burnAmounts[4] = 250; + + token.batchMint(address(0xBEEF), ids, mintAmounts, ""); + + token.batchBurn(address(0xBEEF), ids, burnAmounts); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 50); + assertEq(token.balanceOf(address(0xBEEF), 1338), 100); + assertEq(token.balanceOf(address(0xBEEF), 1339), 150); + assertEq(token.balanceOf(address(0xBEEF), 1340), 200); + assertEq(token.balanceOf(address(0xBEEF), 1341), 250); + } + + function testApproveAll() public { + token.setApprovalForAll(address(0xBEEF), true); + + assertTrue(token.isApprovedForAll(address(this), address(0xBEEF))); + } + + function testSafeTransferFromToEOA() public { + address from = address(0xABCD); + + token.mint(from, 1337, 100, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(0xBEEF), 1337, 70, ""); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 70); + assertEq(token.balanceOf(from, 1337), 30); + } + + function testSafeTransferFromToERC1155Recipient() public { + ERC1155Recipient to = new ERC1155Recipient(); + + address from = address(0xABCD); + + token.mint(from, 1337, 100, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(to), 1337, 70, "testing 123"); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), from); + assertEq(to.id(), 1337); + assertBytesEq(to.mintData(), "testing 123"); + + assertEq(token.balanceOf(address(to), 1337), 70); + assertEq(token.balanceOf(from, 1337), 30); + } + + function testSafeTransferFromSelf() public { + token.mint(address(this), 1337, 100, ""); + + token.safeTransferFrom(address(this), address(0xBEEF), 1337, 70, ""); + + assertEq(token.balanceOf(address(0xBEEF), 1337), 70); + assertEq(token.balanceOf(address(this), 1337), 30); + } + + function testSafeBatchTransferFromToEOA() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); + + assertEq(token.balanceOf(from, 1337), 50); + assertEq(token.balanceOf(address(0xBEEF), 1337), 50); + + assertEq(token.balanceOf(from, 1338), 100); + assertEq(token.balanceOf(address(0xBEEF), 1338), 100); + + assertEq(token.balanceOf(from, 1339), 150); + assertEq(token.balanceOf(address(0xBEEF), 1339), 150); + + assertEq(token.balanceOf(from, 1340), 200); + assertEq(token.balanceOf(address(0xBEEF), 1340), 200); + + assertEq(token.balanceOf(from, 1341), 250); + assertEq(token.balanceOf(address(0xBEEF), 1341), 250); + } + + function testSafeBatchTransferFromToERC1155Recipient() public { + address from = address(0xABCD); + + ERC1155Recipient to = new ERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(to), ids, transferAmounts, "testing 123"); + + assertEq(to.batchOperator(), address(this)); + assertEq(to.batchFrom(), from); + assertUintArrayEq(to.batchIds(), ids); + assertUintArrayEq(to.batchAmounts(), transferAmounts); + assertBytesEq(to.batchData(), "testing 123"); + + assertEq(token.balanceOf(from, 1337), 50); + assertEq(token.balanceOf(address(to), 1337), 50); + + assertEq(token.balanceOf(from, 1338), 100); + assertEq(token.balanceOf(address(to), 1338), 100); + + assertEq(token.balanceOf(from, 1339), 150); + assertEq(token.balanceOf(address(to), 1339), 150); + + assertEq(token.balanceOf(from, 1340), 200); + assertEq(token.balanceOf(address(to), 1340), 200); + + assertEq(token.balanceOf(from, 1341), 250); + assertEq(token.balanceOf(address(to), 1341), 250); + } + + function testBatchBalanceOf() public { + address[] memory tos = new address[](5); + tos[0] = address(0xBEEF); + tos[1] = address(0xCAFE); + tos[2] = address(0xFACE); + tos[3] = address(0xDEAD); + tos[4] = address(0xFEED); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + token.mint(address(0xBEEF), 1337, 100, ""); + token.mint(address(0xCAFE), 1338, 200, ""); + token.mint(address(0xFACE), 1339, 300, ""); + token.mint(address(0xDEAD), 1340, 400, ""); + token.mint(address(0xFEED), 1341, 500, ""); + + uint256[] memory balances = token.balanceOfBatch(tos, ids); + + assertEq(balances[0], 100); + assertEq(balances[1], 200); + assertEq(balances[2], 300); + assertEq(balances[3], 400); + assertEq(balances[4], 500); + } + + function testFailMintToZero() public { + token.mint(address(0), 1337, 1, ""); + } + + function testFailMintToNonERC155Recipient() public { + token.mint(address(new NonERC1155Recipient()), 1337, 1, ""); + } + + function testFailMintToRevertingERC155Recipient() public { + token.mint(address(new RevertingERC1155Recipient()), 1337, 1, ""); + } + + function testFailMintToWrongReturnDataERC155Recipient() public { + token.mint(address(new RevertingERC1155Recipient()), 1337, 1, ""); + } + + function testFailBurnInsufficientBalance() public { + token.mint(address(0xBEEF), 1337, 70, ""); + token.burn(address(0xBEEF), 1337, 100); + } + + function testFailSafeTransferFromInsufficientBalance() public { + address from = address(0xABCD); + + token.mint(from, 1337, 70, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(0xBEEF), 1337, 100, ""); + } + + function testFailSafeTransferFromSelfInsufficientBalance() public { + token.mint(address(this), 1337, 70, ""); + token.safeTransferFrom(address(this), address(0xBEEF), 1337, 100, ""); + } + + function testFailSafeTransferFromToZero() public { + token.mint(address(this), 1337, 100, ""); + token.safeTransferFrom(address(this), address(0), 1337, 70, ""); + } + + function testFailSafeTransferFromToNonERC155Recipient() public { + token.mint(address(this), 1337, 100, ""); + token.safeTransferFrom(address(this), address(new NonERC1155Recipient()), 1337, 70, ""); + } + + function testFailSafeTransferFromToRevertingERC1155Recipient() public { + token.mint(address(this), 1337, 100, ""); + token.safeTransferFrom(address(this), address(new RevertingERC1155Recipient()), 1337, 70, ""); + } + + function testFailSafeTransferFromToWrongReturnDataERC1155Recipient() public { + token.mint(address(this), 1337, 100, ""); + token.safeTransferFrom(address(this), address(new WrongReturnDataERC1155Recipient()), 1337, 70, ""); + } + + function testFailSafeBatchTransferInsufficientBalance() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + + mintAmounts[0] = 50; + mintAmounts[1] = 100; + mintAmounts[2] = 150; + mintAmounts[3] = 200; + mintAmounts[4] = 250; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 100; + transferAmounts[1] = 200; + transferAmounts[2] = 300; + transferAmounts[3] = 400; + transferAmounts[4] = 500; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromToZero() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromToNonERC1155Recipient() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(new NonERC1155Recipient()), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromToRevertingERC1155Recipient() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(new RevertingERC1155Recipient()), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](5); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + transferAmounts[4] = 250; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(new WrongReturnDataERC1155Recipient()), ids, transferAmounts, ""); + } + + function testFailSafeBatchTransferFromWithArrayLengthMismatch() public { + address from = address(0xABCD); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory transferAmounts = new uint256[](4); + transferAmounts[0] = 50; + transferAmounts[1] = 100; + transferAmounts[2] = 150; + transferAmounts[3] = 200; + + token.batchMint(from, ids, mintAmounts, ""); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0xBEEF), ids, transferAmounts, ""); + } + + function testFailBatchMintToZero() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + token.batchMint(address(0), ids, mintAmounts, ""); + } + + function testFailBatchMintToNonERC1155Recipient() public { + NonERC1155Recipient to = new NonERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + token.batchMint(address(to), ids, mintAmounts, ""); + } + + function testFailBatchMintToRevertingERC1155Recipient() public { + RevertingERC1155Recipient to = new RevertingERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + token.batchMint(address(to), ids, mintAmounts, ""); + } + + function testFailBatchMintToWrongReturnDataERC1155Recipient() public { + WrongReturnDataERC1155Recipient to = new WrongReturnDataERC1155Recipient(); + + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + token.batchMint(address(to), ids, mintAmounts, ""); + } + + function testFailBatchMintWithArrayMismatch() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory amounts = new uint256[](4); + amounts[0] = 100; + amounts[1] = 200; + amounts[2] = 300; + amounts[3] = 400; + + token.batchMint(address(0xBEEF), ids, amounts, ""); + } + + function testFailBatchBurnInsufficientBalance() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 50; + mintAmounts[1] = 100; + mintAmounts[2] = 150; + mintAmounts[3] = 200; + mintAmounts[4] = 250; + + uint256[] memory burnAmounts = new uint256[](5); + burnAmounts[0] = 100; + burnAmounts[1] = 200; + burnAmounts[2] = 300; + burnAmounts[3] = 400; + burnAmounts[4] = 500; + + token.batchMint(address(0xBEEF), ids, mintAmounts, ""); + + token.batchBurn(address(0xBEEF), ids, burnAmounts); + } + + function testFailBatchBurnWithArrayLengthMismatch() public { + uint256[] memory ids = new uint256[](5); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + ids[4] = 1341; + + uint256[] memory mintAmounts = new uint256[](5); + mintAmounts[0] = 100; + mintAmounts[1] = 200; + mintAmounts[2] = 300; + mintAmounts[3] = 400; + mintAmounts[4] = 500; + + uint256[] memory burnAmounts = new uint256[](4); + burnAmounts[0] = 50; + burnAmounts[1] = 100; + burnAmounts[2] = 150; + burnAmounts[3] = 200; + + token.batchMint(address(0xBEEF), ids, mintAmounts, ""); + + token.batchBurn(address(0xBEEF), ids, burnAmounts); + } + + function testFailBalanceOfBatchWithArrayMismatch() public view { + address[] memory tos = new address[](5); + tos[0] = address(0xBEEF); + tos[1] = address(0xCAFE); + tos[2] = address(0xFACE); + tos[3] = address(0xDEAD); + tos[4] = address(0xFEED); + + uint256[] memory ids = new uint256[](4); + ids[0] = 1337; + ids[1] = 1338; + ids[2] = 1339; + ids[3] = 1340; + + token.balanceOfBatch(tos, ids); + } + + function testMintToEOA( + address to, + uint256 id, + uint256 amount, + bytes memory mintData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + token.mint(to, id, amount, mintData); + + assertEq(token.balanceOf(to, id), amount); + } + + function testMintToERC1155Recipient( + uint256 id, + uint256 amount, + bytes memory mintData + ) public { + ERC1155Recipient to = new ERC1155Recipient(); + + token.mint(address(to), id, amount, mintData); + + assertEq(token.balanceOf(address(to), id), amount); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), id); + assertBytesEq(to.mintData(), mintData); + } + + function testBatchMintToEOA( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[to][id] += mintAmount; + } + + token.batchMint(to, normalizedIds, normalizedAmounts, mintData); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + + assertEq(token.balanceOf(to, id), userMintAmounts[to][id]); + } + } + + function testBatchMintToERC1155Recipient( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + ERC1155Recipient to = new ERC1155Recipient(); + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(to)][id] += mintAmount; + } + + token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); + + assertEq(to.batchOperator(), address(this)); + assertEq(to.batchFrom(), address(0)); + assertUintArrayEq(to.batchIds(), normalizedIds); + assertUintArrayEq(to.batchAmounts(), normalizedAmounts); + assertBytesEq(to.batchData(), mintData); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + + assertEq(token.balanceOf(address(to), id), userMintAmounts[address(to)][id]); + } + } + + function testBurn( + address to, + uint256 id, + uint256 mintAmount, + bytes memory mintData, + uint256 burnAmount + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + burnAmount = bound(burnAmount, 0, mintAmount); + + token.mint(to, id, mintAmount, mintData); + + token.burn(to, id, burnAmount); + + assertEq(token.balanceOf(address(to), id), mintAmount - burnAmount); + } + + function testBatchBurn( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory burnAmounts, + bytes memory mintData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + uint256 minLength = min3(ids.length, mintAmounts.length, burnAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedBurnAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + normalizedIds[i] = id; + normalizedMintAmounts[i] = bound(mintAmounts[i], 0, remainingMintAmountForId); + normalizedBurnAmounts[i] = bound(burnAmounts[i], 0, normalizedMintAmounts[i]); + + userMintAmounts[address(to)][id] += normalizedMintAmounts[i]; + userTransferOrBurnAmounts[address(to)][id] += normalizedBurnAmounts[i]; + } + + token.batchMint(to, normalizedIds, normalizedMintAmounts, mintData); + + token.batchBurn(to, normalizedIds, normalizedBurnAmounts); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + + assertEq(token.balanceOf(to, id), userMintAmounts[to][id] - userTransferOrBurnAmounts[to][id]); + } + } + + function testApproveAll(address to, bool approved) public { + token.setApprovalForAll(to, approved); + + assertBoolEq(token.isApprovedForAll(address(this), to), approved); + } + + function testSafeTransferFromToEOA( + uint256 id, + uint256 mintAmount, + bytes memory mintData, + uint256 transferAmount, + address to, + bytes memory transferData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + transferAmount = bound(transferAmount, 0, mintAmount); + + address from = address(0xABCD); + + token.mint(from, id, mintAmount, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, to, id, transferAmount, transferData); + + if (to == from) { + assertEq(token.balanceOf(to, id), mintAmount); + } else { + assertEq(token.balanceOf(to, id), transferAmount); + assertEq(token.balanceOf(from, id), mintAmount - transferAmount); + } + } + + function testSafeTransferFromToERC1155Recipient( + uint256 id, + uint256 mintAmount, + bytes memory mintData, + uint256 transferAmount, + bytes memory transferData + ) public { + ERC1155Recipient to = new ERC1155Recipient(); + + address from = address(0xABCD); + + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(from, id, mintAmount, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(to), id, transferAmount, transferData); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), from); + assertEq(to.id(), id); + assertBytesEq(to.mintData(), transferData); + + assertEq(token.balanceOf(address(to), id), transferAmount); + assertEq(token.balanceOf(from, id), mintAmount - transferAmount); + } + + function testSafeTransferFromSelf( + uint256 id, + uint256 mintAmount, + bytes memory mintData, + uint256 transferAmount, + address to, + bytes memory transferData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + + token.safeTransferFrom(address(this), to, id, transferAmount, transferData); + + assertEq(token.balanceOf(to, id), transferAmount); + assertEq(token.balanceOf(address(this), id), mintAmount - transferAmount); + } + + function testSafeBatchTransferFromToEOA( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + userTransferOrBurnAmounts[from][id] += transferAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, to, normalizedIds, normalizedTransferAmounts, transferData); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + + assertEq(token.balanceOf(address(to), id), userTransferOrBurnAmounts[from][id]); + assertEq(token.balanceOf(from, id), userMintAmounts[from][id] - userTransferOrBurnAmounts[from][id]); + } + } + + function testSafeBatchTransferFromToERC1155Recipient( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + ERC1155Recipient to = new ERC1155Recipient(); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + userTransferOrBurnAmounts[from][id] += transferAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(to), normalizedIds, normalizedTransferAmounts, transferData); + + assertEq(to.batchOperator(), address(this)); + assertEq(to.batchFrom(), from); + assertUintArrayEq(to.batchIds(), normalizedIds); + assertUintArrayEq(to.batchAmounts(), normalizedTransferAmounts); + assertBytesEq(to.batchData(), transferData); + + for (uint256 i = 0; i < normalizedIds.length; i++) { + uint256 id = normalizedIds[i]; + uint256 transferAmount = userTransferOrBurnAmounts[from][id]; + + assertEq(token.balanceOf(address(to), id), transferAmount); + assertEq(token.balanceOf(from, id), userMintAmounts[from][id] - transferAmount); + } + } + + function testBatchBalanceOf( + address[] memory tos, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + uint256 minLength = min3(tos.length, ids.length, amounts.length); + + address[] memory normalizedTos = new address[](minLength); + uint256[] memory normalizedIds = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + address to = tos[i] == address(0) || tos[i].code.length > 0 ? address(0xBEEF) : tos[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; + + normalizedTos[i] = to; + normalizedIds[i] = id; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + token.mint(to, id, mintAmount, mintData); + + userMintAmounts[to][id] += mintAmount; + } + + uint256[] memory balances = token.balanceOfBatch(normalizedTos, normalizedIds); + + for (uint256 i = 0; i < normalizedTos.length; i++) { + assertEq(balances[i], token.balanceOf(normalizedTos[i], normalizedIds[i])); + } + } + + function testFailMintToZero( + uint256 id, + uint256 amount, + bytes memory data + ) public { + token.mint(address(0), id, amount, data); + } + + function testFailMintToNonERC155Recipient( + uint256 id, + uint256 mintAmount, + bytes memory mintData + ) public { + token.mint(address(new NonERC1155Recipient()), id, mintAmount, mintData); + } + + function testFailMintToRevertingERC155Recipient( + uint256 id, + uint256 mintAmount, + bytes memory mintData + ) public { + token.mint(address(new RevertingERC1155Recipient()), id, mintAmount, mintData); + } + + function testFailMintToWrongReturnDataERC155Recipient( + uint256 id, + uint256 mintAmount, + bytes memory mintData + ) public { + token.mint(address(new RevertingERC1155Recipient()), id, mintAmount, mintData); + } + + function testFailBurnInsufficientBalance( + address to, + uint256 id, + uint256 mintAmount, + uint256 burnAmount, + bytes memory mintData + ) public { + burnAmount = bound(burnAmount, mintAmount + 1, type(uint256).max); + + token.mint(to, id, mintAmount, mintData); + token.burn(to, id, burnAmount); + } + + function testFailSafeTransferFromInsufficientBalance( + address to, + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + transferAmount = bound(transferAmount, mintAmount + 1, type(uint256).max); + + token.mint(from, id, mintAmount, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, to, id, transferAmount, transferData); + } + + function testFailSafeTransferFromSelfInsufficientBalance( + address to, + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, mintAmount + 1, type(uint256).max); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom(address(this), to, id, transferAmount, transferData); + } + + function testFailSafeTransferFromToZero( + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom(address(this), address(0), id, transferAmount, transferData); + } + + function testFailSafeTransferFromToNonERC155Recipient( + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom(address(this), address(new NonERC1155Recipient()), id, transferAmount, transferData); + } + + function testFailSafeTransferFromToRevertingERC1155Recipient( + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom( + address(this), + address(new RevertingERC1155Recipient()), + id, + transferAmount, + transferData + ); + } + + function testFailSafeTransferFromToWrongReturnDataERC1155Recipient( + uint256 id, + uint256 mintAmount, + uint256 transferAmount, + bytes memory mintData, + bytes memory transferData + ) public { + transferAmount = bound(transferAmount, 0, mintAmount); + + token.mint(address(this), id, mintAmount, mintData); + token.safeTransferFrom( + address(this), + address(new WrongReturnDataERC1155Recipient()), + id, + transferAmount, + transferData + ); + } + + function testFailSafeBatchTransferInsufficientBalance( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + if (minLength == 0) revert(); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], mintAmount + 1, type(uint256).max); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, to, normalizedIds, normalizedTransferAmounts, transferData); + } + + function testFailSafeBatchTransferFromToZero( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, address(0), normalizedIds, normalizedTransferAmounts, transferData); + } + + function testFailSafeBatchTransferFromToNonERC1155Recipient( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom( + from, + address(new NonERC1155Recipient()), + normalizedIds, + normalizedTransferAmounts, + transferData + ); + } + + function testFailSafeBatchTransferFromToRevertingERC1155Recipient( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom( + from, + address(new RevertingERC1155Recipient()), + normalizedIds, + normalizedTransferAmounts, + transferData + ); + } + + function testFailSafeBatchTransferFromToWrongReturnDataERC1155Recipient( + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + uint256 minLength = min3(ids.length, mintAmounts.length, transferAmounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedTransferAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[from][id]; + + uint256 mintAmount = bound(mintAmounts[i], 0, remainingMintAmountForId); + uint256 transferAmount = bound(transferAmounts[i], 0, mintAmount); + + normalizedIds[i] = id; + normalizedMintAmounts[i] = mintAmount; + normalizedTransferAmounts[i] = transferAmount; + + userMintAmounts[from][id] += mintAmount; + } + + token.batchMint(from, normalizedIds, normalizedMintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom( + from, + address(new WrongReturnDataERC1155Recipient()), + normalizedIds, + normalizedTransferAmounts, + transferData + ); + } + + function testFailSafeBatchTransferFromWithArrayLengthMismatch( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory transferAmounts, + bytes memory mintData, + bytes memory transferData + ) public { + address from = address(0xABCD); + + if (ids.length == transferAmounts.length) revert(); + + token.batchMint(from, ids, mintAmounts, mintData); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeBatchTransferFrom(from, to, ids, transferAmounts, transferData); + } + + function testFailBatchMintToZero( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(0)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(0)][id] += mintAmount; + } + + token.batchMint(address(0), normalizedIds, normalizedAmounts, mintData); + } + + function testFailBatchMintToNonERC1155Recipient( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + NonERC1155Recipient to = new NonERC1155Recipient(); + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(to)][id] += mintAmount; + } + + token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); + } + + function testFailBatchMintToRevertingERC1155Recipient( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + RevertingERC1155Recipient to = new RevertingERC1155Recipient(); + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(to)][id] += mintAmount; + } + + token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); + } + + function testFailBatchMintToWrongReturnDataERC1155Recipient( + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + WrongReturnDataERC1155Recipient to = new WrongReturnDataERC1155Recipient(); + + uint256 minLength = min2(ids.length, amounts.length); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[address(to)][id]; + + uint256 mintAmount = bound(amounts[i], 0, remainingMintAmountForId); + + normalizedIds[i] = id; + normalizedAmounts[i] = mintAmount; + + userMintAmounts[address(to)][id] += mintAmount; + } + + token.batchMint(address(to), normalizedIds, normalizedAmounts, mintData); + } + + function testFailBatchMintWithArrayMismatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory mintData + ) public { + if (ids.length == amounts.length) revert(); + + token.batchMint(address(to), ids, amounts, mintData); + } + + function testFailBatchBurnInsufficientBalance( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory burnAmounts, + bytes memory mintData + ) public { + uint256 minLength = min3(ids.length, mintAmounts.length, burnAmounts.length); + + if (minLength == 0) revert(); + + uint256[] memory normalizedIds = new uint256[](minLength); + uint256[] memory normalizedMintAmounts = new uint256[](minLength); + uint256[] memory normalizedBurnAmounts = new uint256[](minLength); + + for (uint256 i = 0; i < minLength; i++) { + uint256 id = ids[i]; + + uint256 remainingMintAmountForId = type(uint256).max - userMintAmounts[to][id]; + + normalizedIds[i] = id; + normalizedMintAmounts[i] = bound(mintAmounts[i], 0, remainingMintAmountForId); + normalizedBurnAmounts[i] = bound(burnAmounts[i], normalizedMintAmounts[i] + 1, type(uint256).max); + + userMintAmounts[to][id] += normalizedMintAmounts[i]; + } + + token.batchMint(to, normalizedIds, normalizedMintAmounts, mintData); + + token.batchBurn(to, normalizedIds, normalizedBurnAmounts); + } + + function testFailBatchBurnWithArrayLengthMismatch( + address to, + uint256[] memory ids, + uint256[] memory mintAmounts, + uint256[] memory burnAmounts, + bytes memory mintData + ) public { + if (ids.length == burnAmounts.length) revert(); + + token.batchMint(to, ids, mintAmounts, mintData); + + token.batchBurn(to, ids, burnAmounts); + } + + function testFailBalanceOfBatchWithArrayMismatch(address[] memory tos, uint256[] memory ids) public view { + if (tos.length == ids.length) revert(); + + token.balanceOfBatch(tos, ids); + } +} diff --git a/lib/crytic/lib/solmate/src/test/ERC20.t.sol b/lib/crytic/lib/solmate/src/test/ERC20.t.sol new file mode 100644 index 0000000..1506d8c --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/ERC20.t.sol @@ -0,0 +1,531 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {MockERC20} from "./utils/mocks/MockERC20.sol"; + +contract ERC20Test is DSTestPlus { + MockERC20 token; + + bytes32 constant PERMIT_TYPEHASH = + keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); + + function setUp() public { + token = new MockERC20("Token", "TKN", 18); + } + + function invariantMetadata() public { + assertEq(token.name(), "Token"); + assertEq(token.symbol(), "TKN"); + assertEq(token.decimals(), 18); + } + + function testMint() public { + token.mint(address(0xBEEF), 1e18); + + assertEq(token.totalSupply(), 1e18); + assertEq(token.balanceOf(address(0xBEEF)), 1e18); + } + + function testBurn() public { + token.mint(address(0xBEEF), 1e18); + token.burn(address(0xBEEF), 0.9e18); + + assertEq(token.totalSupply(), 1e18 - 0.9e18); + assertEq(token.balanceOf(address(0xBEEF)), 0.1e18); + } + + function testApprove() public { + assertTrue(token.approve(address(0xBEEF), 1e18)); + + assertEq(token.allowance(address(this), address(0xBEEF)), 1e18); + } + + function testTransfer() public { + token.mint(address(this), 1e18); + + assertTrue(token.transfer(address(0xBEEF), 1e18)); + assertEq(token.totalSupply(), 1e18); + + assertEq(token.balanceOf(address(this)), 0); + assertEq(token.balanceOf(address(0xBEEF)), 1e18); + } + + function testTransferFrom() public { + address from = address(0xABCD); + + token.mint(from, 1e18); + + hevm.prank(from); + token.approve(address(this), 1e18); + + assertTrue(token.transferFrom(from, address(0xBEEF), 1e18)); + assertEq(token.totalSupply(), 1e18); + + assertEq(token.allowance(from, address(this)), 0); + + assertEq(token.balanceOf(from), 0); + assertEq(token.balanceOf(address(0xBEEF)), 1e18); + } + + function testInfiniteApproveTransferFrom() public { + address from = address(0xABCD); + + token.mint(from, 1e18); + + hevm.prank(from); + token.approve(address(this), type(uint256).max); + + assertTrue(token.transferFrom(from, address(0xBEEF), 1e18)); + assertEq(token.totalSupply(), 1e18); + + assertEq(token.allowance(from, address(this)), type(uint256).max); + + assertEq(token.balanceOf(from), 0); + assertEq(token.balanceOf(address(0xBEEF)), 1e18); + } + + function testPermit() public { + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, block.timestamp)) + ) + ) + ); + + token.permit(owner, address(0xCAFE), 1e18, block.timestamp, v, r, s); + + assertEq(token.allowance(owner, address(0xCAFE)), 1e18); + assertEq(token.nonces(owner), 1); + } + + function testFailTransferInsufficientBalance() public { + token.mint(address(this), 0.9e18); + token.transfer(address(0xBEEF), 1e18); + } + + function testFailTransferFromInsufficientAllowance() public { + address from = address(0xABCD); + + token.mint(from, 1e18); + + hevm.prank(from); + token.approve(address(this), 0.9e18); + + token.transferFrom(from, address(0xBEEF), 1e18); + } + + function testFailTransferFromInsufficientBalance() public { + address from = address(0xABCD); + + token.mint(from, 0.9e18); + + hevm.prank(from); + token.approve(address(this), 1e18); + + token.transferFrom(from, address(0xBEEF), 1e18); + } + + function testFailPermitBadNonce() public { + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 1, block.timestamp)) + ) + ) + ); + + token.permit(owner, address(0xCAFE), 1e18, block.timestamp, v, r, s); + } + + function testFailPermitBadDeadline() public { + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, block.timestamp)) + ) + ) + ); + + token.permit(owner, address(0xCAFE), 1e18, block.timestamp + 1, v, r, s); + } + + function testFailPermitPastDeadline() public { + uint256 oldTimestamp = block.timestamp; + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, oldTimestamp)) + ) + ) + ); + + hevm.warp(block.timestamp + 1); + token.permit(owner, address(0xCAFE), 1e18, oldTimestamp, v, r, s); + } + + function testFailPermitReplay() public { + uint256 privateKey = 0xBEEF; + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, address(0xCAFE), 1e18, 0, block.timestamp)) + ) + ) + ); + + token.permit(owner, address(0xCAFE), 1e18, block.timestamp, v, r, s); + token.permit(owner, address(0xCAFE), 1e18, block.timestamp, v, r, s); + } + + function testMetadata( + string calldata name, + string calldata symbol, + uint8 decimals + ) public { + MockERC20 tkn = new MockERC20(name, symbol, decimals); + assertEq(tkn.name(), name); + assertEq(tkn.symbol(), symbol); + assertEq(tkn.decimals(), decimals); + } + + function testMint(address from, uint256 amount) public { + token.mint(from, amount); + + assertEq(token.totalSupply(), amount); + assertEq(token.balanceOf(from), amount); + } + + function testBurn( + address from, + uint256 mintAmount, + uint256 burnAmount + ) public { + burnAmount = bound(burnAmount, 0, mintAmount); + + token.mint(from, mintAmount); + token.burn(from, burnAmount); + + assertEq(token.totalSupply(), mintAmount - burnAmount); + assertEq(token.balanceOf(from), mintAmount - burnAmount); + } + + function testApprove(address to, uint256 amount) public { + assertTrue(token.approve(to, amount)); + + assertEq(token.allowance(address(this), to), amount); + } + + function testTransfer(address from, uint256 amount) public { + token.mint(address(this), amount); + + assertTrue(token.transfer(from, amount)); + assertEq(token.totalSupply(), amount); + + if (address(this) == from) { + assertEq(token.balanceOf(address(this)), amount); + } else { + assertEq(token.balanceOf(address(this)), 0); + assertEq(token.balanceOf(from), amount); + } + } + + function testTransferFrom( + address to, + uint256 approval, + uint256 amount + ) public { + amount = bound(amount, 0, approval); + + address from = address(0xABCD); + + token.mint(from, amount); + + hevm.prank(from); + token.approve(address(this), approval); + + assertTrue(token.transferFrom(from, to, amount)); + assertEq(token.totalSupply(), amount); + + uint256 app = from == address(this) || approval == type(uint256).max ? approval : approval - amount; + assertEq(token.allowance(from, address(this)), app); + + if (from == to) { + assertEq(token.balanceOf(from), amount); + } else { + assertEq(token.balanceOf(from), 0); + assertEq(token.balanceOf(to), amount); + } + } + + function testPermit( + uint248 privKey, + address to, + uint256 amount, + uint256 deadline + ) public { + uint256 privateKey = privKey; + if (deadline < block.timestamp) deadline = block.timestamp; + if (privateKey == 0) privateKey = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, 0, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline, v, r, s); + + assertEq(token.allowance(owner, to), amount); + assertEq(token.nonces(owner), 1); + } + + function testFailBurnInsufficientBalance( + address to, + uint256 mintAmount, + uint256 burnAmount + ) public { + burnAmount = bound(burnAmount, mintAmount + 1, type(uint256).max); + + token.mint(to, mintAmount); + token.burn(to, burnAmount); + } + + function testFailTransferInsufficientBalance( + address to, + uint256 mintAmount, + uint256 sendAmount + ) public { + sendAmount = bound(sendAmount, mintAmount + 1, type(uint256).max); + + token.mint(address(this), mintAmount); + token.transfer(to, sendAmount); + } + + function testFailTransferFromInsufficientAllowance( + address to, + uint256 approval, + uint256 amount + ) public { + amount = bound(amount, approval + 1, type(uint256).max); + + address from = address(0xABCD); + + token.mint(from, amount); + + hevm.prank(from); + token.approve(address(this), approval); + + token.transferFrom(from, to, amount); + } + + function testFailTransferFromInsufficientBalance( + address to, + uint256 mintAmount, + uint256 sendAmount + ) public { + sendAmount = bound(sendAmount, mintAmount + 1, type(uint256).max); + + address from = address(0xABCD); + + token.mint(from, mintAmount); + + hevm.prank(from); + token.approve(address(this), sendAmount); + + token.transferFrom(from, to, sendAmount); + } + + function testFailPermitBadNonce( + uint256 privateKey, + address to, + uint256 amount, + uint256 deadline, + uint256 nonce + ) public { + if (deadline < block.timestamp) deadline = block.timestamp; + if (privateKey == 0) privateKey = 1; + if (nonce == 0) nonce = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, nonce, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline, v, r, s); + } + + function testFailPermitBadDeadline( + uint256 privateKey, + address to, + uint256 amount, + uint256 deadline + ) public { + if (deadline < block.timestamp) deadline = block.timestamp; + if (privateKey == 0) privateKey = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, 0, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline + 1, v, r, s); + } + + function testFailPermitPastDeadline( + uint256 privateKey, + address to, + uint256 amount, + uint256 deadline + ) public { + deadline = bound(deadline, 0, block.timestamp - 1); + if (privateKey == 0) privateKey = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, 0, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline, v, r, s); + } + + function testFailPermitReplay( + uint256 privateKey, + address to, + uint256 amount, + uint256 deadline + ) public { + if (deadline < block.timestamp) deadline = block.timestamp; + if (privateKey == 0) privateKey = 1; + + address owner = hevm.addr(privateKey); + + (uint8 v, bytes32 r, bytes32 s) = hevm.sign( + privateKey, + keccak256( + abi.encodePacked( + "\x19\x01", + token.DOMAIN_SEPARATOR(), + keccak256(abi.encode(PERMIT_TYPEHASH, owner, to, amount, 0, deadline)) + ) + ) + ); + + token.permit(owner, to, amount, deadline, v, r, s); + token.permit(owner, to, amount, deadline, v, r, s); + } +} + +contract ERC20Invariants is DSTestPlus, DSInvariantTest { + BalanceSum balanceSum; + MockERC20 token; + + function setUp() public { + token = new MockERC20("Token", "TKN", 18); + balanceSum = new BalanceSum(token); + + addTargetContract(address(balanceSum)); + } + + function invariantBalanceSum() public { + assertEq(token.totalSupply(), balanceSum.sum()); + } +} + +contract BalanceSum { + MockERC20 token; + uint256 public sum; + + constructor(MockERC20 _token) { + token = _token; + } + + function mint(address from, uint256 amount) public { + token.mint(from, amount); + sum += amount; + } + + function burn(address from, uint256 amount) public { + token.burn(from, amount); + sum -= amount; + } + + function approve(address to, uint256 amount) public { + token.approve(to, amount); + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public { + token.transferFrom(from, to, amount); + } + + function transfer(address to, uint256 amount) public { + token.transfer(to, amount); + } +} diff --git a/lib/crytic/lib/solmate/src/test/ERC4626.t.sol b/lib/crytic/lib/solmate/src/test/ERC4626.t.sol new file mode 100644 index 0000000..816c8e4 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/ERC4626.t.sol @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {MockERC20} from "./utils/mocks/MockERC20.sol"; +import {MockERC4626} from "./utils/mocks/MockERC4626.sol"; + +contract ERC4626Test is DSTestPlus { + MockERC20 underlying; + MockERC4626 vault; + + function setUp() public { + underlying = new MockERC20("Mock Token", "TKN", 18); + vault = new MockERC4626(underlying, "Mock Token Vault", "vwTKN"); + } + + function invariantMetadata() public { + assertEq(vault.name(), "Mock Token Vault"); + assertEq(vault.symbol(), "vwTKN"); + assertEq(vault.decimals(), 18); + } + + function testMetadata(string calldata name, string calldata symbol) public { + MockERC4626 vlt = new MockERC4626(underlying, name, symbol); + assertEq(vlt.name(), name); + assertEq(vlt.symbol(), symbol); + assertEq(address(vlt.asset()), address(underlying)); + } + + function testSingleDepositWithdraw(uint128 amount) public { + if (amount == 0) amount = 1; + + uint256 aliceUnderlyingAmount = amount; + + address alice = address(0xABCD); + + underlying.mint(alice, aliceUnderlyingAmount); + + hevm.prank(alice); + underlying.approve(address(vault), aliceUnderlyingAmount); + assertEq(underlying.allowance(alice, address(vault)), aliceUnderlyingAmount); + + uint256 alicePreDepositBal = underlying.balanceOf(alice); + + hevm.prank(alice); + uint256 aliceShareAmount = vault.deposit(aliceUnderlyingAmount, alice); + + assertEq(vault.afterDepositHookCalledCounter(), 1); + + // Expect exchange rate to be 1:1 on initial deposit. + assertEq(aliceUnderlyingAmount, aliceShareAmount); + assertEq(vault.previewWithdraw(aliceShareAmount), aliceUnderlyingAmount); + assertEq(vault.previewDeposit(aliceUnderlyingAmount), aliceShareAmount); + assertEq(vault.totalSupply(), aliceShareAmount); + assertEq(vault.totalAssets(), aliceUnderlyingAmount); + assertEq(vault.balanceOf(alice), aliceShareAmount); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), aliceUnderlyingAmount); + assertEq(underlying.balanceOf(alice), alicePreDepositBal - aliceUnderlyingAmount); + + hevm.prank(alice); + vault.withdraw(aliceUnderlyingAmount, alice, alice); + + assertEq(vault.beforeWithdrawHookCalledCounter(), 1); + + assertEq(vault.totalAssets(), 0); + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 0); + assertEq(underlying.balanceOf(alice), alicePreDepositBal); + } + + function testSingleMintRedeem(uint128 amount) public { + if (amount == 0) amount = 1; + + uint256 aliceShareAmount = amount; + + address alice = address(0xABCD); + + underlying.mint(alice, aliceShareAmount); + + hevm.prank(alice); + underlying.approve(address(vault), aliceShareAmount); + assertEq(underlying.allowance(alice, address(vault)), aliceShareAmount); + + uint256 alicePreDepositBal = underlying.balanceOf(alice); + + hevm.prank(alice); + uint256 aliceUnderlyingAmount = vault.mint(aliceShareAmount, alice); + + assertEq(vault.afterDepositHookCalledCounter(), 1); + + // Expect exchange rate to be 1:1 on initial mint. + assertEq(aliceShareAmount, aliceUnderlyingAmount); + assertEq(vault.previewWithdraw(aliceShareAmount), aliceUnderlyingAmount); + assertEq(vault.previewDeposit(aliceUnderlyingAmount), aliceShareAmount); + assertEq(vault.totalSupply(), aliceShareAmount); + assertEq(vault.totalAssets(), aliceUnderlyingAmount); + assertEq(vault.balanceOf(alice), aliceUnderlyingAmount); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), aliceUnderlyingAmount); + assertEq(underlying.balanceOf(alice), alicePreDepositBal - aliceUnderlyingAmount); + + hevm.prank(alice); + vault.redeem(aliceShareAmount, alice, alice); + + assertEq(vault.beforeWithdrawHookCalledCounter(), 1); + + assertEq(vault.totalAssets(), 0); + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 0); + assertEq(underlying.balanceOf(alice), alicePreDepositBal); + } + + function testMultipleMintDepositRedeemWithdraw() public { + // Scenario: + // A = Alice, B = Bob + // ________________________________________________________ + // | Vault shares | A share | A assets | B share | B assets | + // |========================================================| + // | 1. Alice mints 2000 shares (costs 2000 tokens) | + // |--------------|---------|----------|---------|----------| + // | 2000 | 2000 | 2000 | 0 | 0 | + // |--------------|---------|----------|---------|----------| + // | 2. Bob deposits 4000 tokens (mints 4000 shares) | + // |--------------|---------|----------|---------|----------| + // | 6000 | 2000 | 2000 | 4000 | 4000 | + // |--------------|---------|----------|---------|----------| + // | 3. Vault mutates by +3000 tokens... | + // | (simulated yield returned from strategy)... | + // |--------------|---------|----------|---------|----------| + // | 6000 | 2000 | 3000 | 4000 | 6000 | + // |--------------|---------|----------|---------|----------| + // | 4. Alice deposits 2000 tokens (mints 1333 shares) | + // |--------------|---------|----------|---------|----------| + // | 7333 | 3333 | 4999 | 4000 | 6000 | + // |--------------|---------|----------|---------|----------| + // | 5. Bob mints 2000 shares (costs 3001 assets) | + // | NOTE: Bob's assets spent got rounded up | + // | NOTE: Alice's vault assets got rounded up | + // |--------------|---------|----------|---------|----------| + // | 9333 | 3333 | 5000 | 6000 | 9000 | + // |--------------|---------|----------|---------|----------| + // | 6. Vault mutates by +3000 tokens... | + // | (simulated yield returned from strategy) | + // | NOTE: Vault holds 17001 tokens, but sum of | + // | assetsOf() is 17000. | + // |--------------|---------|----------|---------|----------| + // | 9333 | 3333 | 6071 | 6000 | 10929 | + // |--------------|---------|----------|---------|----------| + // | 7. Alice redeem 1333 shares (2428 assets) | + // |--------------|---------|----------|---------|----------| + // | 8000 | 2000 | 3643 | 6000 | 10929 | + // |--------------|---------|----------|---------|----------| + // | 8. Bob withdraws 2928 assets (1608 shares) | + // |--------------|---------|----------|---------|----------| + // | 6392 | 2000 | 3643 | 4392 | 8000 | + // |--------------|---------|----------|---------|----------| + // | 9. Alice withdraws 3643 assets (2000 shares) | + // | NOTE: Bob's assets have been rounded back up | + // |--------------|---------|----------|---------|----------| + // | 4392 | 0 | 0 | 4392 | 8001 | + // |--------------|---------|----------|---------|----------| + // | 10. Bob redeem 4392 shares (8001 tokens) | + // |--------------|---------|----------|---------|----------| + // | 0 | 0 | 0 | 0 | 0 | + // |______________|_________|__________|_________|__________| + + address alice = address(0xABCD); + address bob = address(0xDCBA); + + uint256 mutationUnderlyingAmount = 3000; + + underlying.mint(alice, 4000); + + hevm.prank(alice); + underlying.approve(address(vault), 4000); + + assertEq(underlying.allowance(alice, address(vault)), 4000); + + underlying.mint(bob, 7001); + + hevm.prank(bob); + underlying.approve(address(vault), 7001); + + assertEq(underlying.allowance(bob, address(vault)), 7001); + + // 1. Alice mints 2000 shares (costs 2000 tokens) + hevm.prank(alice); + uint256 aliceUnderlyingAmount = vault.mint(2000, alice); + + uint256 aliceShareAmount = vault.previewDeposit(aliceUnderlyingAmount); + assertEq(vault.afterDepositHookCalledCounter(), 1); + + // Expect to have received the requested mint amount. + assertEq(aliceShareAmount, 2000); + assertEq(vault.balanceOf(alice), aliceShareAmount); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), aliceUnderlyingAmount); + assertEq(vault.convertToShares(aliceUnderlyingAmount), vault.balanceOf(alice)); + + // Expect a 1:1 ratio before mutation. + assertEq(aliceUnderlyingAmount, 2000); + + // Sanity check. + assertEq(vault.totalSupply(), aliceShareAmount); + assertEq(vault.totalAssets(), aliceUnderlyingAmount); + + // 2. Bob deposits 4000 tokens (mints 4000 shares) + hevm.prank(bob); + uint256 bobShareAmount = vault.deposit(4000, bob); + uint256 bobUnderlyingAmount = vault.previewWithdraw(bobShareAmount); + assertEq(vault.afterDepositHookCalledCounter(), 2); + + // Expect to have received the requested underlying amount. + assertEq(bobUnderlyingAmount, 4000); + assertEq(vault.balanceOf(bob), bobShareAmount); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), bobUnderlyingAmount); + assertEq(vault.convertToShares(bobUnderlyingAmount), vault.balanceOf(bob)); + + // Expect a 1:1 ratio before mutation. + assertEq(bobShareAmount, bobUnderlyingAmount); + + // Sanity check. + uint256 preMutationShareBal = aliceShareAmount + bobShareAmount; + uint256 preMutationBal = aliceUnderlyingAmount + bobUnderlyingAmount; + assertEq(vault.totalSupply(), preMutationShareBal); + assertEq(vault.totalAssets(), preMutationBal); + assertEq(vault.totalSupply(), 6000); + assertEq(vault.totalAssets(), 6000); + + // 3. Vault mutates by +3000 tokens... | + // (simulated yield returned from strategy)... + // The Vault now contains more tokens than deposited which causes the exchange rate to change. + // Alice share is 33.33% of the Vault, Bob 66.66% of the Vault. + // Alice's share count stays the same but the underlying amount changes from 2000 to 3000. + // Bob's share count stays the same but the underlying amount changes from 4000 to 6000. + underlying.mint(address(vault), mutationUnderlyingAmount); + assertEq(vault.totalSupply(), preMutationShareBal); + assertEq(vault.totalAssets(), preMutationBal + mutationUnderlyingAmount); + assertEq(vault.balanceOf(alice), aliceShareAmount); + assertEq( + vault.convertToAssets(vault.balanceOf(alice)), + aliceUnderlyingAmount + (mutationUnderlyingAmount / 3) * 1 + ); + assertEq(vault.balanceOf(bob), bobShareAmount); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), bobUnderlyingAmount + (mutationUnderlyingAmount / 3) * 2); + + // 4. Alice deposits 2000 tokens (mints 1333 shares) + hevm.prank(alice); + vault.deposit(2000, alice); + + assertEq(vault.totalSupply(), 7333); + assertEq(vault.balanceOf(alice), 3333); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 4999); + assertEq(vault.balanceOf(bob), 4000); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 6000); + + // 5. Bob mints 2000 shares (costs 3001 assets) + // NOTE: Bob's assets spent got rounded up + // NOTE: Alices's vault assets got rounded up + hevm.prank(bob); + vault.mint(2000, bob); + + assertEq(vault.totalSupply(), 9333); + assertEq(vault.balanceOf(alice), 3333); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 5000); + assertEq(vault.balanceOf(bob), 6000); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 9000); + + // Sanity checks: + // Alice and bob should have spent all their tokens now + assertEq(underlying.balanceOf(alice), 0); + assertEq(underlying.balanceOf(bob), 0); + // Assets in vault: 4k (alice) + 7k (bob) + 3k (yield) + 1 (round up) + assertEq(vault.totalAssets(), 14001); + + // 6. Vault mutates by +3000 tokens + // NOTE: Vault holds 17001 tokens, but sum of assetsOf() is 17000. + underlying.mint(address(vault), mutationUnderlyingAmount); + assertEq(vault.totalAssets(), 17001); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 6071); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 10929); + + // 7. Alice redeem 1333 shares (2428 assets) + hevm.prank(alice); + vault.redeem(1333, alice, alice); + + assertEq(underlying.balanceOf(alice), 2428); + assertEq(vault.totalSupply(), 8000); + assertEq(vault.totalAssets(), 14573); + assertEq(vault.balanceOf(alice), 2000); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 3643); + assertEq(vault.balanceOf(bob), 6000); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 10929); + + // 8. Bob withdraws 2929 assets (1608 shares) + hevm.prank(bob); + vault.withdraw(2929, bob, bob); + + assertEq(underlying.balanceOf(bob), 2929); + assertEq(vault.totalSupply(), 6392); + assertEq(vault.totalAssets(), 11644); + assertEq(vault.balanceOf(alice), 2000); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 3643); + assertEq(vault.balanceOf(bob), 4392); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 8000); + + // 9. Alice withdraws 3643 assets (2000 shares) + // NOTE: Bob's assets have been rounded back up + hevm.prank(alice); + vault.withdraw(3643, alice, alice); + + assertEq(underlying.balanceOf(alice), 6071); + assertEq(vault.totalSupply(), 4392); + assertEq(vault.totalAssets(), 8001); + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 0); + assertEq(vault.balanceOf(bob), 4392); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 8001); + + // 10. Bob redeem 4392 shares (8001 tokens) + hevm.prank(bob); + vault.redeem(4392, bob, bob); + assertEq(underlying.balanceOf(bob), 10930); + assertEq(vault.totalSupply(), 0); + assertEq(vault.totalAssets(), 0); + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.convertToAssets(vault.balanceOf(alice)), 0); + assertEq(vault.balanceOf(bob), 0); + assertEq(vault.convertToAssets(vault.balanceOf(bob)), 0); + + // Sanity check + assertEq(underlying.balanceOf(address(vault)), 0); + } + + function testFailDepositWithNotEnoughApproval() public { + underlying.mint(address(this), 0.5e18); + underlying.approve(address(vault), 0.5e18); + assertEq(underlying.allowance(address(this), address(vault)), 0.5e18); + + vault.deposit(1e18, address(this)); + } + + function testFailWithdrawWithNotEnoughUnderlyingAmount() public { + underlying.mint(address(this), 0.5e18); + underlying.approve(address(vault), 0.5e18); + + vault.deposit(0.5e18, address(this)); + + vault.withdraw(1e18, address(this), address(this)); + } + + function testFailRedeemWithNotEnoughShareAmount() public { + underlying.mint(address(this), 0.5e18); + underlying.approve(address(vault), 0.5e18); + + vault.deposit(0.5e18, address(this)); + + vault.redeem(1e18, address(this), address(this)); + } + + function testFailWithdrawWithNoUnderlyingAmount() public { + vault.withdraw(1e18, address(this), address(this)); + } + + function testFailRedeemWithNoShareAmount() public { + vault.redeem(1e18, address(this), address(this)); + } + + function testFailDepositWithNoApproval() public { + vault.deposit(1e18, address(this)); + } + + function testFailMintWithNoApproval() public { + vault.mint(1e18, address(this)); + } + + function testFailDepositZero() public { + vault.deposit(0, address(this)); + } + + function testMintZero() public { + vault.mint(0, address(this)); + + assertEq(vault.balanceOf(address(this)), 0); + assertEq(vault.convertToAssets(vault.balanceOf(address(this))), 0); + assertEq(vault.totalSupply(), 0); + assertEq(vault.totalAssets(), 0); + } + + function testFailRedeemZero() public { + vault.redeem(0, address(this), address(this)); + } + + function testWithdrawZero() public { + vault.withdraw(0, address(this), address(this)); + + assertEq(vault.balanceOf(address(this)), 0); + assertEq(vault.convertToAssets(vault.balanceOf(address(this))), 0); + assertEq(vault.totalSupply(), 0); + assertEq(vault.totalAssets(), 0); + } + + function testVaultInteractionsForSomeoneElse() public { + // init 2 users with a 1e18 balance + address alice = address(0xABCD); + address bob = address(0xDCBA); + underlying.mint(alice, 1e18); + underlying.mint(bob, 1e18); + + hevm.prank(alice); + underlying.approve(address(vault), 1e18); + + hevm.prank(bob); + underlying.approve(address(vault), 1e18); + + // alice deposits 1e18 for bob + hevm.prank(alice); + vault.deposit(1e18, bob); + + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.balanceOf(bob), 1e18); + assertEq(underlying.balanceOf(alice), 0); + + // bob mint 1e18 for alice + hevm.prank(bob); + vault.mint(1e18, alice); + assertEq(vault.balanceOf(alice), 1e18); + assertEq(vault.balanceOf(bob), 1e18); + assertEq(underlying.balanceOf(bob), 0); + + // alice redeem 1e18 for bob + hevm.prank(alice); + vault.redeem(1e18, bob, alice); + + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.balanceOf(bob), 1e18); + assertEq(underlying.balanceOf(bob), 1e18); + + // bob withdraw 1e18 for alice + hevm.prank(bob); + vault.withdraw(1e18, alice, bob); + + assertEq(vault.balanceOf(alice), 0); + assertEq(vault.balanceOf(bob), 0); + assertEq(underlying.balanceOf(alice), 1e18); + } +} diff --git a/lib/crytic/lib/solmate/src/test/ERC721.t.sol b/lib/crytic/lib/solmate/src/test/ERC721.t.sol new file mode 100644 index 0000000..81de0ff --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/ERC721.t.sol @@ -0,0 +1,727 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {MockERC721} from "./utils/mocks/MockERC721.sol"; + +import {ERC721TokenReceiver} from "../tokens/ERC721.sol"; + +contract ERC721Recipient is ERC721TokenReceiver { + address public operator; + address public from; + uint256 public id; + bytes public data; + + function onERC721Received( + address _operator, + address _from, + uint256 _id, + bytes calldata _data + ) public virtual override returns (bytes4) { + operator = _operator; + from = _from; + id = _id; + data = _data; + + return ERC721TokenReceiver.onERC721Received.selector; + } +} + +contract RevertingERC721Recipient is ERC721TokenReceiver { + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) public virtual override returns (bytes4) { + revert(string(abi.encodePacked(ERC721TokenReceiver.onERC721Received.selector))); + } +} + +contract WrongReturnDataERC721Recipient is ERC721TokenReceiver { + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) public virtual override returns (bytes4) { + return 0xCAFEBEEF; + } +} + +contract NonERC721Recipient {} + +contract ERC721Test is DSTestPlus { + MockERC721 token; + + function setUp() public { + token = new MockERC721("Token", "TKN"); + } + + function invariantMetadata() public { + assertEq(token.name(), "Token"); + assertEq(token.symbol(), "TKN"); + } + + function testMint() public { + token.mint(address(0xBEEF), 1337); + + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.ownerOf(1337), address(0xBEEF)); + } + + function testBurn() public { + token.mint(address(0xBEEF), 1337); + token.burn(1337); + + assertEq(token.balanceOf(address(0xBEEF)), 0); + + hevm.expectRevert("NOT_MINTED"); + token.ownerOf(1337); + } + + function testApprove() public { + token.mint(address(this), 1337); + + token.approve(address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0xBEEF)); + } + + function testApproveBurn() public { + token.mint(address(this), 1337); + + token.approve(address(0xBEEF), 1337); + + token.burn(1337); + + assertEq(token.balanceOf(address(this)), 0); + assertEq(token.getApproved(1337), address(0)); + + hevm.expectRevert("NOT_MINTED"); + token.ownerOf(1337); + } + + function testApproveAll() public { + token.setApprovalForAll(address(0xBEEF), true); + + assertTrue(token.isApprovedForAll(address(this), address(0xBEEF))); + } + + function testTransferFrom() public { + address from = address(0xABCD); + + token.mint(from, 1337); + + hevm.prank(from); + token.approve(address(this), 1337); + + token.transferFrom(from, address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(0xBEEF)); + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.balanceOf(from), 0); + } + + function testTransferFromSelf() public { + token.mint(address(this), 1337); + + token.transferFrom(address(this), address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(0xBEEF)); + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.balanceOf(address(this)), 0); + } + + function testTransferFromApproveAll() public { + address from = address(0xABCD); + + token.mint(from, 1337); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.transferFrom(from, address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(0xBEEF)); + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.balanceOf(from), 0); + } + + function testSafeTransferFromToEOA() public { + address from = address(0xABCD); + + token.mint(from, 1337); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(0xBEEF), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(0xBEEF)); + assertEq(token.balanceOf(address(0xBEEF)), 1); + assertEq(token.balanceOf(from), 0); + } + + function testSafeTransferFromToERC721Recipient() public { + address from = address(0xABCD); + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, 1337); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(recipient), 1337); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(recipient)); + assertEq(token.balanceOf(address(recipient)), 1); + assertEq(token.balanceOf(from), 0); + + assertEq(recipient.operator(), address(this)); + assertEq(recipient.from(), from); + assertEq(recipient.id(), 1337); + assertBytesEq(recipient.data(), ""); + } + + function testSafeTransferFromToERC721RecipientWithData() public { + address from = address(0xABCD); + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, 1337); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(recipient), 1337, "testing 123"); + + assertEq(token.getApproved(1337), address(0)); + assertEq(token.ownerOf(1337), address(recipient)); + assertEq(token.balanceOf(address(recipient)), 1); + assertEq(token.balanceOf(from), 0); + + assertEq(recipient.operator(), address(this)); + assertEq(recipient.from(), from); + assertEq(recipient.id(), 1337); + assertBytesEq(recipient.data(), "testing 123"); + } + + function testSafeMintToEOA() public { + token.safeMint(address(0xBEEF), 1337); + + assertEq(token.ownerOf(1337), address(address(0xBEEF))); + assertEq(token.balanceOf(address(address(0xBEEF))), 1); + } + + function testSafeMintToERC721Recipient() public { + ERC721Recipient to = new ERC721Recipient(); + + token.safeMint(address(to), 1337); + + assertEq(token.ownerOf(1337), address(to)); + assertEq(token.balanceOf(address(to)), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), 1337); + assertBytesEq(to.data(), ""); + } + + function testSafeMintToERC721RecipientWithData() public { + ERC721Recipient to = new ERC721Recipient(); + + token.safeMint(address(to), 1337, "testing 123"); + + assertEq(token.ownerOf(1337), address(to)); + assertEq(token.balanceOf(address(to)), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), 1337); + assertBytesEq(to.data(), "testing 123"); + } + + function testFailMintToZero() public { + token.mint(address(0), 1337); + } + + function testFailDoubleMint() public { + token.mint(address(0xBEEF), 1337); + token.mint(address(0xBEEF), 1337); + } + + function testFailBurnUnMinted() public { + token.burn(1337); + } + + function testFailDoubleBurn() public { + token.mint(address(0xBEEF), 1337); + + token.burn(1337); + token.burn(1337); + } + + function testFailApproveUnMinted() public { + token.approve(address(0xBEEF), 1337); + } + + function testFailApproveUnAuthorized() public { + token.mint(address(0xCAFE), 1337); + + token.approve(address(0xBEEF), 1337); + } + + function testFailTransferFromUnOwned() public { + token.transferFrom(address(0xFEED), address(0xBEEF), 1337); + } + + function testFailTransferFromWrongFrom() public { + token.mint(address(0xCAFE), 1337); + + token.transferFrom(address(0xFEED), address(0xBEEF), 1337); + } + + function testFailTransferFromToZero() public { + token.mint(address(this), 1337); + + token.transferFrom(address(this), address(0), 1337); + } + + function testFailTransferFromNotOwner() public { + token.mint(address(0xFEED), 1337); + + token.transferFrom(address(0xFEED), address(0xBEEF), 1337); + } + + function testFailSafeTransferFromToNonERC721Recipient() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new NonERC721Recipient()), 1337); + } + + function testFailSafeTransferFromToNonERC721RecipientWithData() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new NonERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeTransferFromToRevertingERC721Recipient() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new RevertingERC721Recipient()), 1337); + } + + function testFailSafeTransferFromToRevertingERC721RecipientWithData() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new RevertingERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeTransferFromToERC721RecipientWithWrongReturnData() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new WrongReturnDataERC721Recipient()), 1337); + } + + function testFailSafeTransferFromToERC721RecipientWithWrongReturnDataWithData() public { + token.mint(address(this), 1337); + + token.safeTransferFrom(address(this), address(new WrongReturnDataERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeMintToNonERC721Recipient() public { + token.safeMint(address(new NonERC721Recipient()), 1337); + } + + function testFailSafeMintToNonERC721RecipientWithData() public { + token.safeMint(address(new NonERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeMintToRevertingERC721Recipient() public { + token.safeMint(address(new RevertingERC721Recipient()), 1337); + } + + function testFailSafeMintToRevertingERC721RecipientWithData() public { + token.safeMint(address(new RevertingERC721Recipient()), 1337, "testing 123"); + } + + function testFailSafeMintToERC721RecipientWithWrongReturnData() public { + token.safeMint(address(new WrongReturnDataERC721Recipient()), 1337); + } + + function testFailSafeMintToERC721RecipientWithWrongReturnDataWithData() public { + token.safeMint(address(new WrongReturnDataERC721Recipient()), 1337, "testing 123"); + } + + function testFailBalanceOfZeroAddress() public view { + token.balanceOf(address(0)); + } + + function testFailOwnerOfUnminted() public view { + token.ownerOf(1337); + } + + function testMetadata(string memory name, string memory symbol) public { + MockERC721 tkn = new MockERC721(name, symbol); + + assertEq(tkn.name(), name); + assertEq(tkn.symbol(), symbol); + } + + function testMint(address to, uint256 id) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(to, id); + + assertEq(token.balanceOf(to), 1); + assertEq(token.ownerOf(id), to); + } + + function testBurn(address to, uint256 id) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(to, id); + token.burn(id); + + assertEq(token.balanceOf(to), 0); + + hevm.expectRevert("NOT_MINTED"); + token.ownerOf(id); + } + + function testApprove(address to, uint256 id) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(address(this), id); + + token.approve(to, id); + + assertEq(token.getApproved(id), to); + } + + function testApproveBurn(address to, uint256 id) public { + token.mint(address(this), id); + + token.approve(address(to), id); + + token.burn(id); + + assertEq(token.balanceOf(address(this)), 0); + assertEq(token.getApproved(id), address(0)); + + hevm.expectRevert("NOT_MINTED"); + token.ownerOf(id); + } + + function testApproveAll(address to, bool approved) public { + token.setApprovalForAll(to, approved); + + assertBoolEq(token.isApprovedForAll(address(this), to), approved); + } + + function testTransferFrom(uint256 id, address to) public { + address from = address(0xABCD); + + if (to == address(0) || to == from) to = address(0xBEEF); + + token.mint(from, id); + + hevm.prank(from); + token.approve(address(this), id); + + token.transferFrom(from, to, id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), to); + assertEq(token.balanceOf(to), 1); + assertEq(token.balanceOf(from), 0); + } + + function testTransferFromSelf(uint256 id, address to) public { + if (to == address(0) || to == address(this)) to = address(0xBEEF); + + token.mint(address(this), id); + + token.transferFrom(address(this), to, id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), to); + assertEq(token.balanceOf(to), 1); + assertEq(token.balanceOf(address(this)), 0); + } + + function testTransferFromApproveAll(uint256 id, address to) public { + address from = address(0xABCD); + + if (to == address(0) || to == from) to = address(0xBEEF); + + token.mint(from, id); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.transferFrom(from, to, id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), to); + assertEq(token.balanceOf(to), 1); + assertEq(token.balanceOf(from), 0); + } + + function testSafeTransferFromToEOA(uint256 id, address to) public { + address from = address(0xABCD); + + if (to == address(0) || to == from) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + token.mint(from, id); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, to, id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), to); + assertEq(token.balanceOf(to), 1); + assertEq(token.balanceOf(from), 0); + } + + function testSafeTransferFromToERC721Recipient(uint256 id) public { + address from = address(0xABCD); + + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, id); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(recipient), id); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), address(recipient)); + assertEq(token.balanceOf(address(recipient)), 1); + assertEq(token.balanceOf(from), 0); + + assertEq(recipient.operator(), address(this)); + assertEq(recipient.from(), from); + assertEq(recipient.id(), id); + assertBytesEq(recipient.data(), ""); + } + + function testSafeTransferFromToERC721RecipientWithData(uint256 id, bytes calldata data) public { + address from = address(0xABCD); + ERC721Recipient recipient = new ERC721Recipient(); + + token.mint(from, id); + + hevm.prank(from); + token.setApprovalForAll(address(this), true); + + token.safeTransferFrom(from, address(recipient), id, data); + + assertEq(token.getApproved(id), address(0)); + assertEq(token.ownerOf(id), address(recipient)); + assertEq(token.balanceOf(address(recipient)), 1); + assertEq(token.balanceOf(from), 0); + + assertEq(recipient.operator(), address(this)); + assertEq(recipient.from(), from); + assertEq(recipient.id(), id); + assertBytesEq(recipient.data(), data); + } + + function testSafeMintToEOA(uint256 id, address to) public { + if (to == address(0)) to = address(0xBEEF); + + if (uint256(uint160(to)) <= 18 || to.code.length > 0) return; + + token.safeMint(to, id); + + assertEq(token.ownerOf(id), address(to)); + assertEq(token.balanceOf(address(to)), 1); + } + + function testSafeMintToERC721Recipient(uint256 id) public { + ERC721Recipient to = new ERC721Recipient(); + + token.safeMint(address(to), id); + + assertEq(token.ownerOf(id), address(to)); + assertEq(token.balanceOf(address(to)), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), id); + assertBytesEq(to.data(), ""); + } + + function testSafeMintToERC721RecipientWithData(uint256 id, bytes calldata data) public { + ERC721Recipient to = new ERC721Recipient(); + + token.safeMint(address(to), id, data); + + assertEq(token.ownerOf(id), address(to)); + assertEq(token.balanceOf(address(to)), 1); + + assertEq(to.operator(), address(this)); + assertEq(to.from(), address(0)); + assertEq(to.id(), id); + assertBytesEq(to.data(), data); + } + + function testFailMintToZero(uint256 id) public { + token.mint(address(0), id); + } + + function testFailDoubleMint(uint256 id, address to) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(to, id); + token.mint(to, id); + } + + function testFailBurnUnMinted(uint256 id) public { + token.burn(id); + } + + function testFailDoubleBurn(uint256 id, address to) public { + if (to == address(0)) to = address(0xBEEF); + + token.mint(to, id); + + token.burn(id); + token.burn(id); + } + + function testFailApproveUnMinted(uint256 id, address to) public { + token.approve(to, id); + } + + function testFailApproveUnAuthorized( + address owner, + uint256 id, + address to + ) public { + if (owner == address(0) || owner == address(this)) owner = address(0xBEEF); + + token.mint(owner, id); + + token.approve(to, id); + } + + function testFailTransferFromUnOwned( + address from, + address to, + uint256 id + ) public { + token.transferFrom(from, to, id); + } + + function testFailTransferFromWrongFrom( + address owner, + address from, + address to, + uint256 id + ) public { + if (owner == address(0)) to = address(0xBEEF); + if (from == owner) revert(); + + token.mint(owner, id); + + token.transferFrom(from, to, id); + } + + function testFailTransferFromToZero(uint256 id) public { + token.mint(address(this), id); + + token.transferFrom(address(this), address(0), id); + } + + function testFailTransferFromNotOwner( + address from, + address to, + uint256 id + ) public { + if (from == address(this)) from = address(0xBEEF); + + token.mint(from, id); + + token.transferFrom(from, to, id); + } + + function testFailSafeTransferFromToNonERC721Recipient(uint256 id) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new NonERC721Recipient()), id); + } + + function testFailSafeTransferFromToNonERC721RecipientWithData(uint256 id, bytes calldata data) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new NonERC721Recipient()), id, data); + } + + function testFailSafeTransferFromToRevertingERC721Recipient(uint256 id) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new RevertingERC721Recipient()), id); + } + + function testFailSafeTransferFromToRevertingERC721RecipientWithData(uint256 id, bytes calldata data) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new RevertingERC721Recipient()), id, data); + } + + function testFailSafeTransferFromToERC721RecipientWithWrongReturnData(uint256 id) public { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new WrongReturnDataERC721Recipient()), id); + } + + function testFailSafeTransferFromToERC721RecipientWithWrongReturnDataWithData(uint256 id, bytes calldata data) + public + { + token.mint(address(this), id); + + token.safeTransferFrom(address(this), address(new WrongReturnDataERC721Recipient()), id, data); + } + + function testFailSafeMintToNonERC721Recipient(uint256 id) public { + token.safeMint(address(new NonERC721Recipient()), id); + } + + function testFailSafeMintToNonERC721RecipientWithData(uint256 id, bytes calldata data) public { + token.safeMint(address(new NonERC721Recipient()), id, data); + } + + function testFailSafeMintToRevertingERC721Recipient(uint256 id) public { + token.safeMint(address(new RevertingERC721Recipient()), id); + } + + function testFailSafeMintToRevertingERC721RecipientWithData(uint256 id, bytes calldata data) public { + token.safeMint(address(new RevertingERC721Recipient()), id, data); + } + + function testFailSafeMintToERC721RecipientWithWrongReturnData(uint256 id) public { + token.safeMint(address(new WrongReturnDataERC721Recipient()), id); + } + + function testFailSafeMintToERC721RecipientWithWrongReturnDataWithData(uint256 id, bytes calldata data) public { + token.safeMint(address(new WrongReturnDataERC721Recipient()), id, data); + } + + function testFailOwnerOfUnminted(uint256 id) public view { + token.ownerOf(id); + } +} diff --git a/lib/crytic/lib/solmate/src/test/FixedPointMathLib.t.sol b/lib/crytic/lib/solmate/src/test/FixedPointMathLib.t.sol new file mode 100644 index 0000000..789f957 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/FixedPointMathLib.t.sol @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {FixedPointMathLib} from "../utils/FixedPointMathLib.sol"; + +contract FixedPointMathLibTest is DSTestPlus { + function testMulWadDown() public { + assertEq(FixedPointMathLib.mulWadDown(2.5e18, 0.5e18), 1.25e18); + assertEq(FixedPointMathLib.mulWadDown(3e18, 1e18), 3e18); + assertEq(FixedPointMathLib.mulWadDown(369, 271), 0); + } + + function testMulWadDownEdgeCases() public { + assertEq(FixedPointMathLib.mulWadDown(0, 1e18), 0); + assertEq(FixedPointMathLib.mulWadDown(1e18, 0), 0); + assertEq(FixedPointMathLib.mulWadDown(0, 0), 0); + } + + function testMulWadUp() public { + assertEq(FixedPointMathLib.mulWadUp(2.5e18, 0.5e18), 1.25e18); + assertEq(FixedPointMathLib.mulWadUp(3e18, 1e18), 3e18); + assertEq(FixedPointMathLib.mulWadUp(369, 271), 1); + } + + function testMulWadUpEdgeCases() public { + assertEq(FixedPointMathLib.mulWadUp(0, 1e18), 0); + assertEq(FixedPointMathLib.mulWadUp(1e18, 0), 0); + assertEq(FixedPointMathLib.mulWadUp(0, 0), 0); + } + + function testDivWadDown() public { + assertEq(FixedPointMathLib.divWadDown(1.25e18, 0.5e18), 2.5e18); + assertEq(FixedPointMathLib.divWadDown(3e18, 1e18), 3e18); + assertEq(FixedPointMathLib.divWadDown(2, 100000000000000e18), 0); + } + + function testDivWadDownEdgeCases() public { + assertEq(FixedPointMathLib.divWadDown(0, 1e18), 0); + } + + function testFailDivWadDownZeroDenominator() public pure { + FixedPointMathLib.divWadDown(1e18, 0); + } + + function testDivWadUp() public { + assertEq(FixedPointMathLib.divWadUp(1.25e18, 0.5e18), 2.5e18); + assertEq(FixedPointMathLib.divWadUp(3e18, 1e18), 3e18); + assertEq(FixedPointMathLib.divWadUp(2, 100000000000000e18), 1); + } + + function testDivWadUpEdgeCases() public { + assertEq(FixedPointMathLib.divWadUp(0, 1e18), 0); + } + + function testFailDivWadUpZeroDenominator() public pure { + FixedPointMathLib.divWadUp(1e18, 0); + } + + function testMulDivDown() public { + assertEq(FixedPointMathLib.mulDivDown(2.5e27, 0.5e27, 1e27), 1.25e27); + assertEq(FixedPointMathLib.mulDivDown(2.5e18, 0.5e18, 1e18), 1.25e18); + assertEq(FixedPointMathLib.mulDivDown(2.5e8, 0.5e8, 1e8), 1.25e8); + assertEq(FixedPointMathLib.mulDivDown(369, 271, 1e2), 999); + + assertEq(FixedPointMathLib.mulDivDown(1e27, 1e27, 2e27), 0.5e27); + assertEq(FixedPointMathLib.mulDivDown(1e18, 1e18, 2e18), 0.5e18); + assertEq(FixedPointMathLib.mulDivDown(1e8, 1e8, 2e8), 0.5e8); + + assertEq(FixedPointMathLib.mulDivDown(2e27, 3e27, 2e27), 3e27); + assertEq(FixedPointMathLib.mulDivDown(3e18, 2e18, 3e18), 2e18); + assertEq(FixedPointMathLib.mulDivDown(2e8, 3e8, 2e8), 3e8); + } + + function testMulDivDownEdgeCases() public { + assertEq(FixedPointMathLib.mulDivDown(0, 1e18, 1e18), 0); + assertEq(FixedPointMathLib.mulDivDown(1e18, 0, 1e18), 0); + assertEq(FixedPointMathLib.mulDivDown(0, 0, 1e18), 0); + } + + function testFailMulDivDownZeroDenominator() public pure { + FixedPointMathLib.mulDivDown(1e18, 1e18, 0); + } + + function testMulDivUp() public { + assertEq(FixedPointMathLib.mulDivUp(2.5e27, 0.5e27, 1e27), 1.25e27); + assertEq(FixedPointMathLib.mulDivUp(2.5e18, 0.5e18, 1e18), 1.25e18); + assertEq(FixedPointMathLib.mulDivUp(2.5e8, 0.5e8, 1e8), 1.25e8); + assertEq(FixedPointMathLib.mulDivUp(369, 271, 1e2), 1000); + + assertEq(FixedPointMathLib.mulDivUp(1e27, 1e27, 2e27), 0.5e27); + assertEq(FixedPointMathLib.mulDivUp(1e18, 1e18, 2e18), 0.5e18); + assertEq(FixedPointMathLib.mulDivUp(1e8, 1e8, 2e8), 0.5e8); + + assertEq(FixedPointMathLib.mulDivUp(2e27, 3e27, 2e27), 3e27); + assertEq(FixedPointMathLib.mulDivUp(3e18, 2e18, 3e18), 2e18); + assertEq(FixedPointMathLib.mulDivUp(2e8, 3e8, 2e8), 3e8); + } + + function testMulDivUpEdgeCases() public { + assertEq(FixedPointMathLib.mulDivUp(0, 1e18, 1e18), 0); + assertEq(FixedPointMathLib.mulDivUp(1e18, 0, 1e18), 0); + assertEq(FixedPointMathLib.mulDivUp(0, 0, 1e18), 0); + } + + function testFailMulDivUpZeroDenominator() public pure { + FixedPointMathLib.mulDivUp(1e18, 1e18, 0); + } + + function testRPow() public { + assertEq(FixedPointMathLib.rpow(2e27, 2, 1e27), 4e27); + assertEq(FixedPointMathLib.rpow(2e18, 2, 1e18), 4e18); + assertEq(FixedPointMathLib.rpow(2e8, 2, 1e8), 4e8); + assertEq(FixedPointMathLib.rpow(8, 3, 1), 512); + } + + function testSqrt() public { + assertEq(FixedPointMathLib.sqrt(0), 0); + assertEq(FixedPointMathLib.sqrt(1), 1); + assertEq(FixedPointMathLib.sqrt(2704), 52); + assertEq(FixedPointMathLib.sqrt(110889), 333); + assertEq(FixedPointMathLib.sqrt(32239684), 5678); + assertEq(FixedPointMathLib.sqrt(type(uint256).max), 340282366920938463463374607431768211455); + } + + function testSqrtBackHashedSingle() public { + testSqrtBackHashed(123); + } + + function testMulWadDown(uint256 x, uint256 y) public { + // Ignore cases where x * y overflows. + unchecked { + if (x != 0 && (x * y) / x != y) return; + } + + assertEq(FixedPointMathLib.mulWadDown(x, y), (x * y) / 1e18); + } + + function testFailMulWadDownOverflow(uint256 x, uint256 y) public pure { + // Ignore cases where x * y does not overflow. + unchecked { + if ((x * y) / x == y) revert(); + } + + FixedPointMathLib.mulWadDown(x, y); + } + + function testMulWadUp(uint256 x, uint256 y) public { + // Ignore cases where x * y overflows. + unchecked { + if (x != 0 && (x * y) / x != y) return; + } + + assertEq(FixedPointMathLib.mulWadUp(x, y), x * y == 0 ? 0 : (x * y - 1) / 1e18 + 1); + } + + function testFailMulWadUpOverflow(uint256 x, uint256 y) public pure { + // Ignore cases where x * y does not overflow. + unchecked { + if ((x * y) / x == y) revert(); + } + + FixedPointMathLib.mulWadUp(x, y); + } + + function testDivWadDown(uint256 x, uint256 y) public { + // Ignore cases where x * WAD overflows or y is 0. + unchecked { + if (y == 0 || (x != 0 && (x * 1e18) / 1e18 != x)) return; + } + + assertEq(FixedPointMathLib.divWadDown(x, y), (x * 1e18) / y); + } + + function testFailDivWadDownOverflow(uint256 x, uint256 y) public pure { + // Ignore cases where x * WAD does not overflow or y is 0. + unchecked { + if (y == 0 || (x * 1e18) / 1e18 == x) revert(); + } + + FixedPointMathLib.divWadDown(x, y); + } + + function testFailDivWadDownZeroDenominator(uint256 x) public pure { + FixedPointMathLib.divWadDown(x, 0); + } + + function testDivWadUp(uint256 x, uint256 y) public { + // Ignore cases where x * WAD overflows or y is 0. + unchecked { + if (y == 0 || (x != 0 && (x * 1e18) / 1e18 != x)) return; + } + + assertEq(FixedPointMathLib.divWadUp(x, y), x == 0 ? 0 : (x * 1e18 - 1) / y + 1); + } + + function testFailDivWadUpOverflow(uint256 x, uint256 y) public pure { + // Ignore cases where x * WAD does not overflow or y is 0. + unchecked { + if (y == 0 || (x * 1e18) / 1e18 == x) revert(); + } + + FixedPointMathLib.divWadUp(x, y); + } + + function testFailDivWadUpZeroDenominator(uint256 x) public pure { + FixedPointMathLib.divWadUp(x, 0); + } + + function testMulDivDown( + uint256 x, + uint256 y, + uint256 denominator + ) public { + // Ignore cases where x * y overflows or denominator is 0. + unchecked { + if (denominator == 0 || (x != 0 && (x * y) / x != y)) return; + } + + assertEq(FixedPointMathLib.mulDivDown(x, y, denominator), (x * y) / denominator); + } + + function testFailMulDivDownOverflow( + uint256 x, + uint256 y, + uint256 denominator + ) public pure { + // Ignore cases where x * y does not overflow or denominator is 0. + unchecked { + if (denominator == 0 || (x * y) / x == y) revert(); + } + + FixedPointMathLib.mulDivDown(x, y, denominator); + } + + function testFailMulDivDownZeroDenominator(uint256 x, uint256 y) public pure { + FixedPointMathLib.mulDivDown(x, y, 0); + } + + function testMulDivUp( + uint256 x, + uint256 y, + uint256 denominator + ) public { + // Ignore cases where x * y overflows or denominator is 0. + unchecked { + if (denominator == 0 || (x != 0 && (x * y) / x != y)) return; + } + + assertEq(FixedPointMathLib.mulDivUp(x, y, denominator), x * y == 0 ? 0 : (x * y - 1) / denominator + 1); + } + + function testFailMulDivUpOverflow( + uint256 x, + uint256 y, + uint256 denominator + ) public pure { + // Ignore cases where x * y does not overflow or denominator is 0. + unchecked { + if (denominator == 0 || (x * y) / x == y) revert(); + } + + FixedPointMathLib.mulDivUp(x, y, denominator); + } + + function testFailMulDivUpZeroDenominator(uint256 x, uint256 y) public pure { + FixedPointMathLib.mulDivUp(x, y, 0); + } + + function testDifferentiallyFuzzSqrt(uint256 x) public { + assertEq(FixedPointMathLib.sqrt(x), uniswapSqrt(x)); + assertEq(FixedPointMathLib.sqrt(x), abdkSqrt(x)); + } + + function testSqrt(uint256 x) public { + uint256 root = FixedPointMathLib.sqrt(x); + uint256 next = root + 1; + + // Ignore cases where next * next overflows. + unchecked { + if (next * next < next) return; + } + + assertTrue(root * root <= x && next * next > x); + } + + function testSqrtBack(uint256 x) public { + unchecked { + x >>= 128; + while (x != 0) { + assertEq(FixedPointMathLib.sqrt(x * x), x); + x >>= 1; + } + } + } + + function testSqrtBackHashed(uint256 x) public { + testSqrtBack(uint256(keccak256(abi.encode(x)))); + } + + function uniswapSqrt(uint256 y) internal pure returns (uint256 z) { + if (y > 3) { + z = y; + uint256 x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + } + } else if (y != 0) { + z = 1; + } + } + + function abdkSqrt(uint256 x) private pure returns (uint256) { + unchecked { + if (x == 0) return 0; + else { + uint256 xx = x; + uint256 r = 1; + if (xx >= 0x100000000000000000000000000000000) { + xx >>= 128; + r <<= 64; + } + if (xx >= 0x10000000000000000) { + xx >>= 64; + r <<= 32; + } + if (xx >= 0x100000000) { + xx >>= 32; + r <<= 16; + } + if (xx >= 0x10000) { + xx >>= 16; + r <<= 8; + } + if (xx >= 0x100) { + xx >>= 8; + r <<= 4; + } + if (xx >= 0x10) { + xx >>= 4; + r <<= 2; + } + if (xx >= 0x8) { + r <<= 1; + } + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; + r = (r + x / r) >> 1; // Seven iterations should be enough + uint256 r1 = x / r; + return r < r1 ? r : r1; + } + } + } +} diff --git a/lib/crytic/lib/solmate/src/test/LibString.t.sol b/lib/crytic/lib/solmate/src/test/LibString.t.sol new file mode 100644 index 0000000..36ed435 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/LibString.t.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {LibString} from "../utils/LibString.sol"; + +contract LibStringTest is DSTestPlus { + function testToString() public { + assertEq(LibString.toString(uint256(0)), "0"); + assertEq(LibString.toString(uint256(1)), "1"); + assertEq(LibString.toString(uint256(17)), "17"); + assertEq(LibString.toString(uint256(99999999)), "99999999"); + assertEq(LibString.toString(uint256(99999999999)), "99999999999"); + assertEq(LibString.toString(uint256(2342343923423)), "2342343923423"); + assertEq(LibString.toString(uint256(98765685434567)), "98765685434567"); + } + + function testToStringIntPositive() public { + assertEq(LibString.toString(int256(0)), "0"); + assertEq(LibString.toString(int256(1)), "1"); + assertEq(LibString.toString(int256(17)), "17"); + assertEq(LibString.toString(int256(99999999)), "99999999"); + assertEq(LibString.toString(int256(99999999999)), "99999999999"); + assertEq(LibString.toString(int256(2342343923423)), "2342343923423"); + assertEq(LibString.toString(int256(98765685434567)), "98765685434567"); + } + + function testToStringIntNegative() public { + assertEq(LibString.toString(int256(-0)), "0"); + assertEq(LibString.toString(int256(-17)), "-17"); + assertEq(LibString.toString(int256(-99999999)), "-99999999"); + assertEq(LibString.toString(int256(-99999999999)), "-99999999999"); + assertEq(LibString.toString(int256(-2342343923423)), "-2342343923423"); + assertEq(LibString.toString(int256(-98765685434567)), "-98765685434567"); + } + + function testDifferentiallyFuzzToString(uint256 value, bytes calldata brutalizeWith) + public + brutalizeMemory(brutalizeWith) + { + string memory libString = LibString.toString(value); + string memory oz = toStringOZ(value); + + assertEq(bytes(libString).length, bytes(oz).length); + assertEq(libString, oz); + } + + function testDifferentiallyFuzzToStringInt(int256 value, bytes calldata brutalizeWith) + public + brutalizeMemory(brutalizeWith) + { + string memory libString = LibString.toString(value); + string memory oz = toStringOZ(value); + + assertEq(bytes(libString).length, bytes(oz).length); + assertEq(libString, oz); + } + + function testToStringOverwrite() public { + string memory str = LibString.toString(uint256(1)); + + bytes32 data; + bytes32 expected; + + assembly { + // Imagine a high level allocation writing something to the current free memory. + // Should have sufficient higher order bits for this to be visible + mstore(mload(0x40), not(0)) + // Correctly allocate 32 more bytes, to avoid more interference + mstore(0x40, add(mload(0x40), 32)) + data := mload(add(str, 32)) + + // the expected value should be the uft-8 encoding of 1 (49), + // followed by clean bits. We achieve this by taking the value and + // shifting left to the end of the 32 byte word + expected := shl(248, 49) + } + + assertEq(data, expected); + } + + function testToStringDirty() public { + uint256 freememptr; + // Make the next 4 bytes of the free memory dirty + assembly { + let dirty := not(0) + freememptr := mload(0x40) + mstore(freememptr, dirty) + mstore(add(freememptr, 32), dirty) + mstore(add(freememptr, 64), dirty) + mstore(add(freememptr, 96), dirty) + mstore(add(freememptr, 128), dirty) + } + string memory str = LibString.toString(uint256(1)); + uint256 len; + bytes32 data; + bytes32 expected; + assembly { + freememptr := str + len := mload(str) + data := mload(add(str, 32)) + // the expected value should be the uft-8 encoding of 1 (49), + // followed by clean bits. We achieve this by taking the value and + // shifting left to the end of the 32 byte word + expected := shl(248, 49) + } + emit log_named_uint("str: ", freememptr); + emit log_named_uint("len: ", len); + emit log_named_bytes32("data: ", data); + assembly { + freememptr := mload(0x40) + } + emit log_named_uint("memptr: ", freememptr); + + assertEq(data, expected); + } +} + +function toStringOZ(int256 value) pure returns (string memory) { + return string(abi.encodePacked(value < 0 ? "-" : "", toStringOZ(absOZ(value)))); +} + +function toStringOZ(uint256 value) pure returns (string memory) { + if (value == 0) { + return "0"; + } + uint256 temp = value; + uint256 digits; + while (temp != 0) { + digits++; + temp /= 10; + } + bytes memory buffer = new bytes(digits); + while (value != 0) { + digits -= 1; + buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); + value /= 10; + } + return string(buffer); +} + +function absOZ(int256 n) pure returns (uint256) { + unchecked { + // must be unchecked in order to support `n = type(int256).min` + return uint256(n >= 0 ? n : -n); + } +} diff --git a/lib/crytic/lib/solmate/src/test/MerkleProofLib.t.sol b/lib/crytic/lib/solmate/src/test/MerkleProofLib.t.sol new file mode 100644 index 0000000..5279679 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/MerkleProofLib.t.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {MerkleProofLib} from "../utils/MerkleProofLib.sol"; + +contract MerkleProofLibTest is DSTestPlus { + function testVerifyEmptyMerkleProofSuppliedLeafAndRootSame() public { + bytes32[] memory proof; + assertBoolEq(this.verify(proof, 0x00, 0x00), true); + } + + function testVerifyEmptyMerkleProofSuppliedLeafAndRootDifferent() public { + bytes32[] memory proof; + bytes32 leaf = "a"; + assertBoolEq(this.verify(proof, 0x00, leaf), false); + } + + function testValidProofSupplied() public { + // Merkle tree created from leaves ['a', 'b', 'c']. + // Leaf is 'a'. + bytes32[] memory proof = new bytes32[](2); + proof[0] = 0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5510; + proof[1] = 0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2; + bytes32 root = 0x5842148bc6ebeb52af882a317c765fccd3ae80589b21a9b8cbf21abb630e46a7; + bytes32 leaf = 0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb; + assertBoolEq(this.verify(proof, root, leaf), true); + } + + function testVerifyInvalidProofSupplied() public { + // Merkle tree created from leaves ['a', 'b', 'c']. + // Leaf is 'a'. + // Proof is same as testValidProofSupplied but last byte of first element is modified. + bytes32[] memory proof = new bytes32[](2); + proof[0] = 0xb5553de315e0edf504d9150af82dafa5c4667fa618ed0a6f19c69b41166c5511; + proof[1] = 0x0b42b6393c1f53060fe3ddbfcd7aadcca894465a5a438f69c87d790b2299b9b2; + bytes32 root = 0x5842148bc6ebeb52af882a317c765fccd3ae80589b21a9b8cbf21abb630e46a7; + bytes32 leaf = 0x3ac225168df54212a25c1c01fd35bebfea408fdac2e31ddd6f80a4bbf9a5f1cb; + assertBoolEq(this.verify(proof, root, leaf), false); + } + + function verify( + bytes32[] calldata proof, + bytes32 root, + bytes32 leaf + ) external pure returns (bool) { + return MerkleProofLib.verify(proof, root, leaf); + } +} diff --git a/lib/crytic/lib/solmate/src/test/MultiRolesAuthority.t.sol b/lib/crytic/lib/solmate/src/test/MultiRolesAuthority.t.sol new file mode 100644 index 0000000..eedf6a0 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/MultiRolesAuthority.t.sol @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockAuthority} from "./utils/mocks/MockAuthority.sol"; + +import {Authority} from "../auth/Auth.sol"; + +import {MultiRolesAuthority} from "../auth/authorities/MultiRolesAuthority.sol"; + +contract MultiRolesAuthorityTest is DSTestPlus { + MultiRolesAuthority multiRolesAuthority; + + function setUp() public { + multiRolesAuthority = new MultiRolesAuthority(address(this), Authority(address(0))); + } + + function testSetRoles() public { + assertFalse(multiRolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertTrue(multiRolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(multiRolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + } + + function testSetRoleCapabilities() public { + assertFalse(multiRolesAuthority.doesRoleHaveCapability(0, 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.doesRoleHaveCapability(0, 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.doesRoleHaveCapability(0, 0xBEEFCAFE)); + } + + function testSetPublicCapabilities() public { + assertFalse(multiRolesAuthority.isCapabilityPublic(0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.isCapabilityPublic(0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.isCapabilityPublic(0xBEEFCAFE)); + } + + function testSetTargetCustomAuthority() public { + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(address(0xBEEF))), address(0)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xBEEF), Authority(address(0xCAFE))); + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(address(0xBEEF))), address(0xCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xBEEF), Authority(address(0))); + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(address(0xBEEF))), address(0)); + } + + function testCanCallWithAuthorizedRole() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallPublicCapability() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallWithCustomAuthority() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallWithCustomAuthorityOverridesPublicCapability() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, false); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setPublicCapability(0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallWithCustomAuthorityOverridesUserWithRole() public { + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setTargetCustomAuthority(address(0xCAFE), Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertTrue(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setRoleCapability(0, 0xBEEFCAFE, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + multiRolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(multiRolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testSetRoles(address user, uint8 role) public { + assertFalse(multiRolesAuthority.doesUserHaveRole(user, role)); + + multiRolesAuthority.setUserRole(user, role, true); + assertTrue(multiRolesAuthority.doesUserHaveRole(user, role)); + + multiRolesAuthority.setUserRole(user, role, false); + assertFalse(multiRolesAuthority.doesUserHaveRole(user, role)); + } + + function testSetRoleCapabilities(uint8 role, bytes4 functionSig) public { + assertFalse(multiRolesAuthority.doesRoleHaveCapability(role, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, true); + assertTrue(multiRolesAuthority.doesRoleHaveCapability(role, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, false); + assertFalse(multiRolesAuthority.doesRoleHaveCapability(role, functionSig)); + } + + function testSetPublicCapabilities(bytes4 functionSig) public { + assertFalse(multiRolesAuthority.isCapabilityPublic(functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, true); + assertTrue(multiRolesAuthority.isCapabilityPublic(functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, false); + assertFalse(multiRolesAuthority.isCapabilityPublic(functionSig)); + } + + function testSetTargetCustomAuthority(address user, Authority customAuthority) public { + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(user)), address(0)); + + multiRolesAuthority.setTargetCustomAuthority(user, customAuthority); + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(user)), address(customAuthority)); + + multiRolesAuthority.setTargetCustomAuthority(user, Authority(address(0))); + assertEq(address(multiRolesAuthority.getTargetCustomAuthority(user)), address(0)); + } + + function testCanCallWithAuthorizedRole( + address user, + uint8 role, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, true); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallPublicCapability( + address user, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallWithCustomAuthority( + address user, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallWithCustomAuthorityOverridesPublicCapability( + address user, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, false); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setPublicCapability(functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallWithCustomAuthorityOverridesUserWithRole( + address user, + uint8 role, + address target, + bytes4 functionSig + ) public { + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, true); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(false)); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, new MockAuthority(true)); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, false); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setTargetCustomAuthority(target, Authority(address(0))); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, true); + assertTrue(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setRoleCapability(role, functionSig, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + + multiRolesAuthority.setUserRole(user, role, false); + assertFalse(multiRolesAuthority.canCall(user, target, functionSig)); + } +} diff --git a/lib/crytic/lib/solmate/src/test/Owned.t.sol b/lib/crytic/lib/solmate/src/test/Owned.t.sol new file mode 100644 index 0000000..08a0239 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/Owned.t.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockOwned} from "./utils/mocks/MockOwned.sol"; + +contract OwnedTest is DSTestPlus { + MockOwned mockOwned; + + function setUp() public { + mockOwned = new MockOwned(); + } + + function testTransferOwnership() public { + testTransferOwnership(address(0xBEEF)); + } + + function testCallFunctionAsNonOwner() public { + testCallFunctionAsNonOwner(address(0)); + } + + function testCallFunctionAsOwner() public { + mockOwned.updateFlag(); + } + + function testTransferOwnership(address newOwner) public { + mockOwned.transferOwnership(newOwner); + + assertEq(mockOwned.owner(), newOwner); + } + + function testCallFunctionAsNonOwner(address owner) public { + hevm.assume(owner != address(this)); + + mockOwned.transferOwnership(owner); + + hevm.expectRevert("UNAUTHORIZED"); + mockOwned.updateFlag(); + } +} diff --git a/lib/crytic/lib/solmate/src/test/ReentrancyGuard.t.sol b/lib/crytic/lib/solmate/src/test/ReentrancyGuard.t.sol new file mode 100644 index 0000000..842e367 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/ReentrancyGuard.t.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {ReentrancyGuard} from "../utils/ReentrancyGuard.sol"; + +contract RiskyContract is ReentrancyGuard { + uint256 public enterTimes; + + function unprotectedCall() public { + enterTimes++; + + if (enterTimes > 1) return; + + this.protectedCall(); + } + + function protectedCall() public nonReentrant { + enterTimes++; + + if (enterTimes > 1) return; + + this.protectedCall(); + } + + function overprotectedCall() public nonReentrant {} +} + +contract ReentrancyGuardTest is DSTestPlus { + RiskyContract riskyContract; + + function setUp() public { + riskyContract = new RiskyContract(); + } + + function invariantReentrancyStatusAlways1() public { + assertEq(uint256(hevm.load(address(riskyContract), 0)), 1); + } + + function testFailUnprotectedCall() public { + riskyContract.unprotectedCall(); + + assertEq(riskyContract.enterTimes(), 1); + } + + function testProtectedCall() public { + try riskyContract.protectedCall() { + fail("Reentrancy Guard Failed To Stop Attacker"); + } catch {} + } + + function testNoReentrancy() public { + riskyContract.overprotectedCall(); + } +} diff --git a/lib/crytic/lib/solmate/src/test/RolesAuthority.t.sol b/lib/crytic/lib/solmate/src/test/RolesAuthority.t.sol new file mode 100644 index 0000000..e01db7e --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/RolesAuthority.t.sol @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {MockAuthority} from "./utils/mocks/MockAuthority.sol"; + +import {Authority} from "../auth/Auth.sol"; + +import {RolesAuthority} from "../auth/authorities/RolesAuthority.sol"; + +contract RolesAuthorityTest is DSTestPlus { + RolesAuthority rolesAuthority; + + function setUp() public { + rolesAuthority = new RolesAuthority(address(this), Authority(address(0))); + } + + function testSetRoles() public { + assertFalse(rolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + + rolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertTrue(rolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + + rolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(rolesAuthority.doesUserHaveRole(address(0xBEEF), 0)); + } + + function testSetRoleCapabilities() public { + assertFalse(rolesAuthority.doesRoleHaveCapability(0, address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.doesRoleHaveCapability(0, address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, false); + assertFalse(rolesAuthority.doesRoleHaveCapability(0, address(0xCAFE), 0xBEEFCAFE)); + } + + function testSetPublicCapabilities() public { + assertFalse(rolesAuthority.isCapabilityPublic(address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setPublicCapability(address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.isCapabilityPublic(address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setPublicCapability(address(0xCAFE), 0xBEEFCAFE, false); + assertFalse(rolesAuthority.isCapabilityPublic(address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallWithAuthorizedRole() public { + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setUserRole(address(0xBEEF), 0, true); + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, false); + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setRoleCapability(0, address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setUserRole(address(0xBEEF), 0, false); + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testCanCallPublicCapability() public { + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setPublicCapability(address(0xCAFE), 0xBEEFCAFE, true); + assertTrue(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + + rolesAuthority.setPublicCapability(address(0xCAFE), 0xBEEFCAFE, false); + assertFalse(rolesAuthority.canCall(address(0xBEEF), address(0xCAFE), 0xBEEFCAFE)); + } + + function testSetRoles(address user, uint8 role) public { + assertFalse(rolesAuthority.doesUserHaveRole(user, role)); + + rolesAuthority.setUserRole(user, role, true); + assertTrue(rolesAuthority.doesUserHaveRole(user, role)); + + rolesAuthority.setUserRole(user, role, false); + assertFalse(rolesAuthority.doesUserHaveRole(user, role)); + } + + function testSetRoleCapabilities( + uint8 role, + address target, + bytes4 functionSig + ) public { + assertFalse(rolesAuthority.doesRoleHaveCapability(role, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, true); + assertTrue(rolesAuthority.doesRoleHaveCapability(role, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, false); + assertFalse(rolesAuthority.doesRoleHaveCapability(role, target, functionSig)); + } + + function testSetPublicCapabilities(address target, bytes4 functionSig) public { + assertFalse(rolesAuthority.isCapabilityPublic(target, functionSig)); + + rolesAuthority.setPublicCapability(target, functionSig, true); + assertTrue(rolesAuthority.isCapabilityPublic(target, functionSig)); + + rolesAuthority.setPublicCapability(target, functionSig, false); + assertFalse(rolesAuthority.isCapabilityPublic(target, functionSig)); + } + + function testCanCallWithAuthorizedRole( + address user, + uint8 role, + address target, + bytes4 functionSig + ) public { + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setUserRole(user, role, true); + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, true); + assertTrue(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, false); + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setRoleCapability(role, target, functionSig, true); + assertTrue(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setUserRole(user, role, false); + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + } + + function testCanCallPublicCapability( + address user, + address target, + bytes4 functionSig + ) public { + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setPublicCapability(target, functionSig, true); + assertTrue(rolesAuthority.canCall(user, target, functionSig)); + + rolesAuthority.setPublicCapability(target, functionSig, false); + assertFalse(rolesAuthority.canCall(user, target, functionSig)); + } +} diff --git a/lib/crytic/lib/solmate/src/test/SSTORE2.t.sol b/lib/crytic/lib/solmate/src/test/SSTORE2.t.sol new file mode 100644 index 0000000..5d97ed7 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/SSTORE2.t.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {SSTORE2} from "../utils/SSTORE2.sol"; + +contract SSTORE2Test is DSTestPlus { + function testWriteRead() public { + bytes memory testBytes = abi.encode("this is a test"); + + address pointer = SSTORE2.write(testBytes); + + assertBytesEq(SSTORE2.read(pointer), testBytes); + } + + function testWriteReadFullStartBound() public { + assertBytesEq(SSTORE2.read(SSTORE2.write(hex"11223344"), 0), hex"11223344"); + } + + function testWriteReadCustomStartBound() public { + assertBytesEq(SSTORE2.read(SSTORE2.write(hex"11223344"), 1), hex"223344"); + } + + function testWriteReadFullBoundedRead() public { + bytes memory testBytes = abi.encode("this is a test"); + + assertBytesEq(SSTORE2.read(SSTORE2.write(testBytes), 0, testBytes.length), testBytes); + } + + function testWriteReadCustomBounds() public { + assertBytesEq(SSTORE2.read(SSTORE2.write(hex"11223344"), 1, 3), hex"2233"); + } + + function testWriteReadEmptyBound() public { + SSTORE2.read(SSTORE2.write(hex"11223344"), 3, 3); + } + + function testFailReadInvalidPointer() public view { + SSTORE2.read(DEAD_ADDRESS); + } + + function testFailReadInvalidPointerCustomStartBound() public view { + SSTORE2.read(DEAD_ADDRESS, 1); + } + + function testFailReadInvalidPointerCustomBounds() public view { + SSTORE2.read(DEAD_ADDRESS, 2, 4); + } + + function testFailWriteReadOutOfStartBound() public { + SSTORE2.read(SSTORE2.write(hex"11223344"), 41000); + } + + function testFailWriteReadEmptyOutOfBounds() public { + SSTORE2.read(SSTORE2.write(hex"11223344"), 42000, 42000); + } + + function testFailWriteReadOutOfBounds() public { + SSTORE2.read(SSTORE2.write(hex"11223344"), 41000, 42000); + } + + function testWriteRead(bytes calldata testBytes, bytes calldata brutalizeWith) + public + brutalizeMemory(brutalizeWith) + { + assertBytesEq(SSTORE2.read(SSTORE2.write(testBytes)), testBytes); + } + + function testWriteReadCustomStartBound( + bytes calldata testBytes, + uint256 startIndex, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (testBytes.length == 0) return; + + startIndex = bound(startIndex, 0, testBytes.length); + + assertBytesEq(SSTORE2.read(SSTORE2.write(testBytes), startIndex), bytes(testBytes[startIndex:])); + } + + function testWriteReadCustomBounds( + bytes calldata testBytes, + uint256 startIndex, + uint256 endIndex, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (testBytes.length == 0) return; + + endIndex = bound(endIndex, 0, testBytes.length); + startIndex = bound(startIndex, 0, testBytes.length); + + if (startIndex > endIndex) return; + + assertBytesEq( + SSTORE2.read(SSTORE2.write(testBytes), startIndex, endIndex), + bytes(testBytes[startIndex:endIndex]) + ); + } + + function testFailReadInvalidPointer(address pointer, bytes calldata brutalizeWith) + public + view + brutalizeMemory(brutalizeWith) + { + if (pointer.code.length > 0) revert(); + + SSTORE2.read(pointer); + } + + function testFailReadInvalidPointerCustomStartBound( + address pointer, + uint256 startIndex, + bytes calldata brutalizeWith + ) public view brutalizeMemory(brutalizeWith) { + if (pointer.code.length > 0) revert(); + + SSTORE2.read(pointer, startIndex); + } + + function testFailReadInvalidPointerCustomBounds( + address pointer, + uint256 startIndex, + uint256 endIndex, + bytes calldata brutalizeWith + ) public view brutalizeMemory(brutalizeWith) { + if (pointer.code.length > 0) revert(); + + SSTORE2.read(pointer, startIndex, endIndex); + } + + function testFailWriteReadCustomStartBoundOutOfRange( + bytes calldata testBytes, + uint256 startIndex, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + startIndex = bound(startIndex, testBytes.length + 1, type(uint256).max); + + SSTORE2.read(SSTORE2.write(testBytes), startIndex); + } + + function testFailWriteReadCustomBoundsOutOfRange( + bytes calldata testBytes, + uint256 startIndex, + uint256 endIndex, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + endIndex = bound(endIndex, testBytes.length + 1, type(uint256).max); + + SSTORE2.read(SSTORE2.write(testBytes), startIndex, endIndex); + } +} diff --git a/lib/crytic/lib/solmate/src/test/SafeCastLib.t.sol b/lib/crytic/lib/solmate/src/test/SafeCastLib.t.sol new file mode 100644 index 0000000..0a56453 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/SafeCastLib.t.sol @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {SafeCastLib} from "../utils/SafeCastLib.sol"; + +contract SafeCastLibTest is DSTestPlus { + function testSafeCastTo248() public { + assertEq(SafeCastLib.safeCastTo248(2.5e45), 2.5e45); + assertEq(SafeCastLib.safeCastTo248(2.5e27), 2.5e27); + } + + function testSafeCastTo224() public { + assertEq(SafeCastLib.safeCastTo224(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo224(2.5e27), 2.5e27); + } + + function testSafeCastTo192() public { + assertEq(SafeCastLib.safeCastTo192(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo192(2.5e27), 2.5e27); + } + + function testSafeCastTo160() public { + assertEq(SafeCastLib.safeCastTo160(2.5e36), 2.5e36); + assertEq(SafeCastLib.safeCastTo160(2.5e27), 2.5e27); + } + + function testSafeCastTo128() public { + assertEq(SafeCastLib.safeCastTo128(2.5e27), 2.5e27); + assertEq(SafeCastLib.safeCastTo128(2.5e18), 2.5e18); + } + + function testSafeCastTo96() public { + assertEq(SafeCastLib.safeCastTo96(2.5e18), 2.5e18); + assertEq(SafeCastLib.safeCastTo96(2.5e17), 2.5e17); + } + + function testSafeCastTo64() public { + assertEq(SafeCastLib.safeCastTo64(2.5e18), 2.5e18); + assertEq(SafeCastLib.safeCastTo64(2.5e17), 2.5e17); + } + + function testSafeCastTo32() public { + assertEq(SafeCastLib.safeCastTo32(2.5e8), 2.5e8); + assertEq(SafeCastLib.safeCastTo32(2.5e7), 2.5e7); + } + + function testSafeCastTo24() public { + assertEq(SafeCastLib.safeCastTo24(2.5e4), 2.5e4); + assertEq(SafeCastLib.safeCastTo24(2.5e3), 2.5e3); + } + + function testSafeCastTo16() public { + assertEq(SafeCastLib.safeCastTo16(2.5e3), 2.5e3); + assertEq(SafeCastLib.safeCastTo16(2.5e2), 2.5e2); + } + + function testSafeCastTo8() public { + assertEq(SafeCastLib.safeCastTo8(100), 100); + assertEq(SafeCastLib.safeCastTo8(250), 250); + } + + function testFailSafeCastTo248() public pure { + SafeCastLib.safeCastTo248(type(uint248).max + 1); + } + + function testFailSafeCastTo224() public pure { + SafeCastLib.safeCastTo224(type(uint224).max + 1); + } + + function testFailSafeCastTo192() public pure { + SafeCastLib.safeCastTo192(type(uint192).max + 1); + } + + function testFailSafeCastTo160() public pure { + SafeCastLib.safeCastTo160(type(uint160).max + 1); + } + + function testFailSafeCastTo128() public pure { + SafeCastLib.safeCastTo128(type(uint128).max + 1); + } + + function testFailSafeCastTo96() public pure { + SafeCastLib.safeCastTo96(type(uint96).max + 1); + } + + function testFailSafeCastTo64() public pure { + SafeCastLib.safeCastTo64(type(uint64).max + 1); + } + + function testFailSafeCastTo32() public pure { + SafeCastLib.safeCastTo32(type(uint32).max + 1); + } + + function testFailSafeCastTo16() public pure { + SafeCastLib.safeCastTo16(type(uint16).max + 1); + } + + function testFailSafeCastTo8() public pure { + SafeCastLib.safeCastTo8(type(uint8).max + 1); + } + + function testSafeCastTo248(uint256 x) public { + x = bound(x, 0, type(uint248).max); + + assertEq(SafeCastLib.safeCastTo248(x), x); + } + + function testSafeCastTo224(uint256 x) public { + x = bound(x, 0, type(uint224).max); + + assertEq(SafeCastLib.safeCastTo224(x), x); + } + + function testSafeCastTo192(uint256 x) public { + x = bound(x, 0, type(uint192).max); + + assertEq(SafeCastLib.safeCastTo192(x), x); + } + + function testSafeCastTo160(uint256 x) public { + x = bound(x, 0, type(uint160).max); + + assertEq(SafeCastLib.safeCastTo160(x), x); + } + + function testSafeCastTo128(uint256 x) public { + x = bound(x, 0, type(uint128).max); + + assertEq(SafeCastLib.safeCastTo128(x), x); + } + + function testSafeCastTo96(uint256 x) public { + x = bound(x, 0, type(uint96).max); + + assertEq(SafeCastLib.safeCastTo96(x), x); + } + + function testSafeCastTo64(uint256 x) public { + x = bound(x, 0, type(uint64).max); + + assertEq(SafeCastLib.safeCastTo64(x), x); + } + + function testSafeCastTo32(uint256 x) public { + x = bound(x, 0, type(uint32).max); + + assertEq(SafeCastLib.safeCastTo32(x), x); + } + + function testSafeCastTo16(uint256 x) public { + x = bound(x, 0, type(uint16).max); + + assertEq(SafeCastLib.safeCastTo16(x), x); + } + + function testSafeCastTo8(uint256 x) public { + x = bound(x, 0, type(uint8).max); + + assertEq(SafeCastLib.safeCastTo8(x), x); + } + + function testFailSafeCastTo248(uint256 x) public { + x = bound(x, type(uint248).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo248(x); + } + + function testFailSafeCastTo224(uint256 x) public { + x = bound(x, type(uint224).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo224(x); + } + + function testFailSafeCastTo192(uint256 x) public { + x = bound(x, type(uint192).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo192(x); + } + + function testFailSafeCastTo160(uint256 x) public { + x = bound(x, type(uint160).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo160(x); + } + + function testFailSafeCastTo128(uint256 x) public { + x = bound(x, type(uint128).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo128(x); + } + + function testFailSafeCastTo96(uint256 x) public { + x = bound(x, type(uint96).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo96(x); + } + + function testFailSafeCastTo64(uint256 x) public { + x = bound(x, type(uint64).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo64(x); + } + + function testFailSafeCastTo32(uint256 x) public { + x = bound(x, type(uint32).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo32(x); + } + + function testFailSafeCastTo24(uint256 x) public { + x = bound(x, type(uint24).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo24(x); + } + + function testFailSafeCastTo16(uint256 x) public { + x = bound(x, type(uint16).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo16(x); + } + + function testFailSafeCastTo8(uint256 x) public { + x = bound(x, type(uint8).max + 1, type(uint256).max); + + SafeCastLib.safeCastTo8(x); + } +} diff --git a/lib/crytic/lib/solmate/src/test/SafeTransferLib.t.sol b/lib/crytic/lib/solmate/src/test/SafeTransferLib.t.sol new file mode 100644 index 0000000..b976e9f --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/SafeTransferLib.t.sol @@ -0,0 +1,610 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {MockERC20} from "./utils/mocks/MockERC20.sol"; +import {RevertingToken} from "./utils/weird-tokens/RevertingToken.sol"; +import {ReturnsTwoToken} from "./utils/weird-tokens/ReturnsTwoToken.sol"; +import {ReturnsFalseToken} from "./utils/weird-tokens/ReturnsFalseToken.sol"; +import {MissingReturnToken} from "./utils/weird-tokens/MissingReturnToken.sol"; +import {ReturnsTooMuchToken} from "./utils/weird-tokens/ReturnsTooMuchToken.sol"; +import {ReturnsGarbageToken} from "./utils/weird-tokens/ReturnsGarbageToken.sol"; +import {ReturnsTooLittleToken} from "./utils/weird-tokens/ReturnsTooLittleToken.sol"; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {ERC20} from "../tokens/ERC20.sol"; +import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; + +contract SafeTransferLibTest is DSTestPlus { + RevertingToken reverting; + ReturnsTwoToken returnsTwo; + ReturnsFalseToken returnsFalse; + MissingReturnToken missingReturn; + ReturnsTooMuchToken returnsTooMuch; + ReturnsGarbageToken returnsGarbage; + ReturnsTooLittleToken returnsTooLittle; + + MockERC20 erc20; + + function setUp() public { + reverting = new RevertingToken(); + returnsTwo = new ReturnsTwoToken(); + returnsFalse = new ReturnsFalseToken(); + missingReturn = new MissingReturnToken(); + returnsTooMuch = new ReturnsTooMuchToken(); + returnsGarbage = new ReturnsGarbageToken(); + returnsTooLittle = new ReturnsTooLittleToken(); + + erc20 = new MockERC20("StandardToken", "ST", 18); + erc20.mint(address(this), type(uint256).max); + } + + function testTransferWithMissingReturn() public { + verifySafeTransfer(address(missingReturn), address(0xBEEF), 1e18); + } + + function testTransferWithStandardERC20() public { + verifySafeTransfer(address(erc20), address(0xBEEF), 1e18); + } + + function testTransferWithReturnsTooMuch() public { + verifySafeTransfer(address(returnsTooMuch), address(0xBEEF), 1e18); + } + + function testTransferWithNonContract() public { + SafeTransferLib.safeTransfer(ERC20(address(0xBADBEEF)), address(0xBEEF), 1e18); + } + + function testTransferFromWithMissingReturn() public { + verifySafeTransferFrom(address(missingReturn), address(0xFEED), address(0xBEEF), 1e18); + } + + function testTransferFromWithStandardERC20() public { + verifySafeTransferFrom(address(erc20), address(0xFEED), address(0xBEEF), 1e18); + } + + function testTransferFromWithReturnsTooMuch() public { + verifySafeTransferFrom(address(returnsTooMuch), address(0xFEED), address(0xBEEF), 1e18); + } + + function testTransferFromWithNonContract() public { + SafeTransferLib.safeTransferFrom(ERC20(address(0xBADBEEF)), address(0xFEED), address(0xBEEF), 1e18); + } + + function testApproveWithMissingReturn() public { + verifySafeApprove(address(missingReturn), address(0xBEEF), 1e18); + } + + function testApproveWithStandardERC20() public { + verifySafeApprove(address(erc20), address(0xBEEF), 1e18); + } + + function testApproveWithReturnsTooMuch() public { + verifySafeApprove(address(returnsTooMuch), address(0xBEEF), 1e18); + } + + function testApproveWithNonContract() public { + SafeTransferLib.safeApprove(ERC20(address(0xBADBEEF)), address(0xBEEF), 1e18); + } + + function testTransferETH() public { + SafeTransferLib.safeTransferETH(address(0xBEEF), 1e18); + } + + function testFailTransferWithReturnsFalse() public { + verifySafeTransfer(address(returnsFalse), address(0xBEEF), 1e18); + } + + function testFailTransferWithReverting() public { + verifySafeTransfer(address(reverting), address(0xBEEF), 1e18); + } + + function testFailTransferWithReturnsTooLittle() public { + verifySafeTransfer(address(returnsTooLittle), address(0xBEEF), 1e18); + } + + function testFailTransferFromWithReturnsFalse() public { + verifySafeTransferFrom(address(returnsFalse), address(0xFEED), address(0xBEEF), 1e18); + } + + function testFailTransferFromWithReverting() public { + verifySafeTransferFrom(address(reverting), address(0xFEED), address(0xBEEF), 1e18); + } + + function testFailTransferFromWithReturnsTooLittle() public { + verifySafeTransferFrom(address(returnsTooLittle), address(0xFEED), address(0xBEEF), 1e18); + } + + function testFailApproveWithReturnsFalse() public { + verifySafeApprove(address(returnsFalse), address(0xBEEF), 1e18); + } + + function testFailApproveWithReverting() public { + verifySafeApprove(address(reverting), address(0xBEEF), 1e18); + } + + function testFailApproveWithReturnsTooLittle() public { + verifySafeApprove(address(returnsTooLittle), address(0xBEEF), 1e18); + } + + function testTransferWithMissingReturn( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(missingReturn), to, amount); + } + + function testTransferWithStandardERC20( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(erc20), to, amount); + } + + function testTransferWithReturnsTooMuch( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(returnsTooMuch), to, amount); + } + + function testTransferWithGarbage( + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if ( + (garbage.length < 32 || + (garbage[0] != 0 || + garbage[1] != 0 || + garbage[2] != 0 || + garbage[3] != 0 || + garbage[4] != 0 || + garbage[5] != 0 || + garbage[6] != 0 || + garbage[7] != 0 || + garbage[8] != 0 || + garbage[9] != 0 || + garbage[10] != 0 || + garbage[11] != 0 || + garbage[12] != 0 || + garbage[13] != 0 || + garbage[14] != 0 || + garbage[15] != 0 || + garbage[16] != 0 || + garbage[17] != 0 || + garbage[18] != 0 || + garbage[19] != 0 || + garbage[20] != 0 || + garbage[21] != 0 || + garbage[22] != 0 || + garbage[23] != 0 || + garbage[24] != 0 || + garbage[25] != 0 || + garbage[26] != 0 || + garbage[27] != 0 || + garbage[28] != 0 || + garbage[29] != 0 || + garbage[30] != 0 || + garbage[31] != bytes1(0x01))) && garbage.length != 0 + ) return; + + returnsGarbage.setGarbage(garbage); + + verifySafeTransfer(address(returnsGarbage), to, amount); + } + + function testTransferWithNonContract( + address nonContract, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (uint256(uint160(nonContract)) <= 18 || nonContract.code.length > 0) return; + + SafeTransferLib.safeTransfer(ERC20(nonContract), to, amount); + } + + function testFailTransferETHToContractWithoutFallback() public { + SafeTransferLib.safeTransferETH(address(this), 1e18); + } + + function testTransferFromWithMissingReturn( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(missingReturn), from, to, amount); + } + + function testTransferFromWithStandardERC20( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(erc20), from, to, amount); + } + + function testTransferFromWithReturnsTooMuch( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(returnsTooMuch), from, to, amount); + } + + function testTransferFromWithGarbage( + address from, + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if ( + (garbage.length < 32 || + (garbage[0] != 0 || + garbage[1] != 0 || + garbage[2] != 0 || + garbage[3] != 0 || + garbage[4] != 0 || + garbage[5] != 0 || + garbage[6] != 0 || + garbage[7] != 0 || + garbage[8] != 0 || + garbage[9] != 0 || + garbage[10] != 0 || + garbage[11] != 0 || + garbage[12] != 0 || + garbage[13] != 0 || + garbage[14] != 0 || + garbage[15] != 0 || + garbage[16] != 0 || + garbage[17] != 0 || + garbage[18] != 0 || + garbage[19] != 0 || + garbage[20] != 0 || + garbage[21] != 0 || + garbage[22] != 0 || + garbage[23] != 0 || + garbage[24] != 0 || + garbage[25] != 0 || + garbage[26] != 0 || + garbage[27] != 0 || + garbage[28] != 0 || + garbage[29] != 0 || + garbage[30] != 0 || + garbage[31] != bytes1(0x01))) && garbage.length != 0 + ) return; + + returnsGarbage.setGarbage(garbage); + + verifySafeTransferFrom(address(returnsGarbage), from, to, amount); + } + + function testTransferFromWithNonContract( + address nonContract, + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (uint256(uint160(nonContract)) <= 18 || nonContract.code.length > 0) return; + + SafeTransferLib.safeTransferFrom(ERC20(nonContract), from, to, amount); + } + + function testApproveWithMissingReturn( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(missingReturn), to, amount); + } + + function testApproveWithStandardERC20( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(erc20), to, amount); + } + + function testApproveWithReturnsTooMuch( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(returnsTooMuch), to, amount); + } + + function testApproveWithGarbage( + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if ( + (garbage.length < 32 || + (garbage[0] != 0 || + garbage[1] != 0 || + garbage[2] != 0 || + garbage[3] != 0 || + garbage[4] != 0 || + garbage[5] != 0 || + garbage[6] != 0 || + garbage[7] != 0 || + garbage[8] != 0 || + garbage[9] != 0 || + garbage[10] != 0 || + garbage[11] != 0 || + garbage[12] != 0 || + garbage[13] != 0 || + garbage[14] != 0 || + garbage[15] != 0 || + garbage[16] != 0 || + garbage[17] != 0 || + garbage[18] != 0 || + garbage[19] != 0 || + garbage[20] != 0 || + garbage[21] != 0 || + garbage[22] != 0 || + garbage[23] != 0 || + garbage[24] != 0 || + garbage[25] != 0 || + garbage[26] != 0 || + garbage[27] != 0 || + garbage[28] != 0 || + garbage[29] != 0 || + garbage[30] != 0 || + garbage[31] != bytes1(0x01))) && garbage.length != 0 + ) return; + + returnsGarbage.setGarbage(garbage); + + verifySafeApprove(address(returnsGarbage), to, amount); + } + + function testApproveWithNonContract( + address nonContract, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + if (uint256(uint160(nonContract)) <= 18 || nonContract.code.length > 0) return; + + SafeTransferLib.safeApprove(ERC20(nonContract), to, amount); + } + + function testTransferETH( + address recipient, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + // Transferring to msg.sender can fail because it's possible to overflow their ETH balance as it begins non-zero. + if (recipient.code.length > 0 || uint256(uint160(recipient)) <= 18 || recipient == msg.sender) return; + + amount = bound(amount, 0, address(this).balance); + + SafeTransferLib.safeTransferETH(recipient, amount); + } + + function testFailTransferWithReturnsFalse( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(returnsFalse), to, amount); + } + + function testFailTransferWithReverting( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(reverting), to, amount); + } + + function testFailTransferWithReturnsTooLittle( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(returnsTooLittle), to, amount); + } + + function testFailTransferWithReturnsTwo( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransfer(address(returnsTwo), to, amount); + } + + function testFailTransferWithGarbage( + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + require(garbage.length != 0 && (garbage.length < 32 || garbage[31] != bytes1(0x01))); + + returnsGarbage.setGarbage(garbage); + + verifySafeTransfer(address(returnsGarbage), to, amount); + } + + function testFailTransferFromWithReturnsFalse( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(returnsFalse), from, to, amount); + } + + function testFailTransferFromWithReverting( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(reverting), from, to, amount); + } + + function testFailTransferFromWithReturnsTooLittle( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(returnsTooLittle), from, to, amount); + } + + function testFailTransferFromWithReturnsTwo( + address from, + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeTransferFrom(address(returnsTwo), from, to, amount); + } + + function testFailTransferFromWithGarbage( + address from, + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + require(garbage.length != 0 && (garbage.length < 32 || garbage[31] != bytes1(0x01))); + + returnsGarbage.setGarbage(garbage); + + verifySafeTransferFrom(address(returnsGarbage), from, to, amount); + } + + function testFailApproveWithReturnsFalse( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(returnsFalse), to, amount); + } + + function testFailApproveWithReverting( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(reverting), to, amount); + } + + function testFailApproveWithReturnsTooLittle( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(returnsTooLittle), to, amount); + } + + function testFailApproveWithReturnsTwo( + address to, + uint256 amount, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + verifySafeApprove(address(returnsTwo), to, amount); + } + + function testFailApproveWithGarbage( + address to, + uint256 amount, + bytes memory garbage, + bytes calldata brutalizeWith + ) public brutalizeMemory(brutalizeWith) { + require(garbage.length != 0 && (garbage.length < 32 || garbage[31] != bytes1(0x01))); + + returnsGarbage.setGarbage(garbage); + + verifySafeApprove(address(returnsGarbage), to, amount); + } + + function testFailTransferETHToContractWithoutFallback(uint256 amount, bytes calldata brutalizeWith) + public + brutalizeMemory(brutalizeWith) + { + SafeTransferLib.safeTransferETH(address(this), amount); + } + + function verifySafeTransfer( + address token, + address to, + uint256 amount + ) internal { + uint256 preBal = ERC20(token).balanceOf(to); + SafeTransferLib.safeTransfer(ERC20(address(token)), to, amount); + uint256 postBal = ERC20(token).balanceOf(to); + + if (to == address(this)) { + assertEq(preBal, postBal); + } else { + assertEq(postBal - preBal, amount); + } + } + + function verifySafeTransferFrom( + address token, + address from, + address to, + uint256 amount + ) internal { + forceApprove(token, from, address(this), amount); + + // We cast to MissingReturnToken here because it won't check + // that there was return data, which accommodates all tokens. + MissingReturnToken(token).transfer(from, amount); + + uint256 preBal = ERC20(token).balanceOf(to); + SafeTransferLib.safeTransferFrom(ERC20(token), from, to, amount); + uint256 postBal = ERC20(token).balanceOf(to); + + if (from == to) { + assertEq(preBal, postBal); + } else { + assertEq(postBal - preBal, amount); + } + } + + function verifySafeApprove( + address token, + address to, + uint256 amount + ) internal { + SafeTransferLib.safeApprove(ERC20(address(token)), to, amount); + + assertEq(ERC20(token).allowance(address(this), to), amount); + } + + function forceApprove( + address token, + address from, + address to, + uint256 amount + ) internal { + uint256 slot = token == address(erc20) ? 4 : 2; // Standard ERC20 name and symbol aren't constant. + + hevm.store( + token, + keccak256(abi.encode(to, keccak256(abi.encode(from, uint256(slot))))), + bytes32(uint256(amount)) + ); + + assertEq(ERC20(token).allowance(from, to), amount, "wrong allowance"); + } +} diff --git a/lib/crytic/lib/solmate/src/test/SignedWadMath.t.sol b/lib/crytic/lib/solmate/src/test/SignedWadMath.t.sol new file mode 100644 index 0000000..ec5b6f3 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/SignedWadMath.t.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; + +import {wadMul, wadDiv} from "../utils/SignedWadMath.sol"; + +contract SignedWadMathTest is DSTestPlus { + function testWadMul( + uint256 x, + uint256 y, + bool negX, + bool negY + ) public { + x = bound(x, 0, 99999999999999e18); + y = bound(x, 0, 99999999999999e18); + + int256 xPrime = negX ? -int256(x) : int256(x); + int256 yPrime = negY ? -int256(y) : int256(y); + + assertEq(wadMul(xPrime, yPrime), (xPrime * yPrime) / 1e18); + } + + function testFailWadMulOverflow(int256 x, int256 y) public pure { + // Ignore cases where x * y does not overflow. + unchecked { + if ((x * y) / x == y) revert(); + } + + wadMul(x, y); + } + + function testWadDiv( + uint256 x, + uint256 y, + bool negX, + bool negY + ) public { + x = bound(x, 0, 99999999e18); + y = bound(x, 1, 99999999e18); + + int256 xPrime = negX ? -int256(x) : int256(x); + int256 yPrime = negY ? -int256(y) : int256(y); + + assertEq(wadDiv(xPrime, yPrime), (xPrime * 1e18) / yPrime); + } + + function testFailWadDivOverflow(int256 x, int256 y) public pure { + // Ignore cases where x * WAD does not overflow or y is 0. + unchecked { + if (y == 0 || (x * 1e18) / 1e18 == x) revert(); + } + + wadDiv(x, y); + } + + function testFailWadDivZeroDenominator(int256 x) public pure { + wadDiv(x, 0); + } +} diff --git a/lib/crytic/lib/solmate/src/test/WETH.t.sol b/lib/crytic/lib/solmate/src/test/WETH.t.sol new file mode 100644 index 0000000..a13761e --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/WETH.t.sol @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity 0.8.15; + +import {DSTestPlus} from "./utils/DSTestPlus.sol"; +import {DSInvariantTest} from "./utils/DSInvariantTest.sol"; + +import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; + +import {WETH} from "../tokens/WETH.sol"; + +contract WETHTest is DSTestPlus { + WETH weth; + + function setUp() public { + weth = new WETH(); + } + + function testFallbackDeposit() public { + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + + SafeTransferLib.safeTransferETH(address(weth), 1 ether); + + assertEq(weth.balanceOf(address(this)), 1 ether); + assertEq(weth.totalSupply(), 1 ether); + } + + function testDeposit() public { + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + + weth.deposit{value: 1 ether}(); + + assertEq(weth.balanceOf(address(this)), 1 ether); + assertEq(weth.totalSupply(), 1 ether); + } + + function testWithdraw() public { + uint256 startingBalance = address(this).balance; + + weth.deposit{value: 1 ether}(); + + weth.withdraw(1 ether); + + uint256 balanceAfterWithdraw = address(this).balance; + + assertEq(balanceAfterWithdraw, startingBalance); + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + } + + function testPartialWithdraw() public { + weth.deposit{value: 1 ether}(); + + uint256 balanceBeforeWithdraw = address(this).balance; + + weth.withdraw(0.5 ether); + + uint256 balanceAfterWithdraw = address(this).balance; + + assertEq(balanceAfterWithdraw, balanceBeforeWithdraw + 0.5 ether); + assertEq(weth.balanceOf(address(this)), 0.5 ether); + assertEq(weth.totalSupply(), 0.5 ether); + } + + function testFallbackDeposit(uint256 amount) public { + amount = bound(amount, 0, address(this).balance); + + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + + SafeTransferLib.safeTransferETH(address(weth), amount); + + assertEq(weth.balanceOf(address(this)), amount); + assertEq(weth.totalSupply(), amount); + } + + function testDeposit(uint256 amount) public { + amount = bound(amount, 0, address(this).balance); + + assertEq(weth.balanceOf(address(this)), 0); + assertEq(weth.totalSupply(), 0); + + weth.deposit{value: amount}(); + + assertEq(weth.balanceOf(address(this)), amount); + assertEq(weth.totalSupply(), amount); + } + + function testWithdraw(uint256 depositAmount, uint256 withdrawAmount) public { + depositAmount = bound(depositAmount, 0, address(this).balance); + withdrawAmount = bound(withdrawAmount, 0, depositAmount); + + weth.deposit{value: depositAmount}(); + + uint256 balanceBeforeWithdraw = address(this).balance; + + weth.withdraw(withdrawAmount); + + uint256 balanceAfterWithdraw = address(this).balance; + + assertEq(balanceAfterWithdraw, balanceBeforeWithdraw + withdrawAmount); + assertEq(weth.balanceOf(address(this)), depositAmount - withdrawAmount); + assertEq(weth.totalSupply(), depositAmount - withdrawAmount); + } + + receive() external payable {} +} + +contract WETHInvariants is DSTestPlus, DSInvariantTest { + WETHTester wethTester; + WETH weth; + + function setUp() public { + weth = new WETH(); + wethTester = new WETHTester{value: address(this).balance}(weth); + + addTargetContract(address(wethTester)); + } + + function invariantTotalSupplyEqualsBalance() public { + assertEq(address(weth).balance, weth.totalSupply()); + } +} + +contract WETHTester { + WETH weth; + + constructor(WETH _weth) payable { + weth = _weth; + } + + function deposit(uint256 amount) public { + weth.deposit{value: amount}(); + } + + function fallbackDeposit(uint256 amount) public { + SafeTransferLib.safeTransferETH(address(weth), amount); + } + + function withdraw(uint256 amount) public { + weth.withdraw(amount); + } + + receive() external payable {} +} diff --git a/lib/crytic/lib/solmate/src/test/utils/DSInvariantTest.sol b/lib/crytic/lib/solmate/src/test/utils/DSInvariantTest.sol new file mode 100644 index 0000000..820775c --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/DSInvariantTest.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract DSInvariantTest { + address[] private targets; + + function targetContracts() public view virtual returns (address[] memory) { + require(targets.length > 0, "NO_TARGET_CONTRACTS"); + + return targets; + } + + function addTargetContract(address newTargetContract) internal virtual { + targets.push(newTargetContract); + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/DSTestPlus.sol b/lib/crytic/lib/solmate/src/test/utils/DSTestPlus.sol new file mode 100644 index 0000000..b56d4c9 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/DSTestPlus.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {DSTest} from "ds-test/test.sol"; + +import {Hevm} from "./Hevm.sol"; + +/// @notice Extended testing framework for DappTools projects. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/test/utils/DSTestPlus.sol) +contract DSTestPlus is DSTest { + Hevm internal constant hevm = Hevm(HEVM_ADDRESS); + + address internal constant DEAD_ADDRESS = 0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF; + + string private checkpointLabel; + uint256 private checkpointGasLeft = 1; // Start the slot warm. + + modifier brutalizeMemory(bytes memory brutalizeWith) { + /// @solidity memory-safe-assembly + assembly { + // Fill the 64 bytes of scratch space with the data. + pop( + staticcall( + gas(), // Pass along all the gas in the call. + 0x04, // Call the identity precompile address. + brutalizeWith, // Offset is the bytes' pointer. + 64, // Copy enough to only fill the scratch space. + 0, // Store the return value in the scratch space. + 64 // Scratch space is only 64 bytes in size, we don't want to write further. + ) + ) + + let size := add(mload(brutalizeWith), 32) // Add 32 to include the 32 byte length slot. + + // Fill the free memory pointer's destination with the data. + pop( + staticcall( + gas(), // Pass along all the gas in the call. + 0x04, // Call the identity precompile address. + brutalizeWith, // Offset is the bytes' pointer. + size, // We want to pass the length of the bytes. + mload(0x40), // Store the return value at the free memory pointer. + size // Since the precompile just returns its input, we reuse size. + ) + ) + } + + _; + } + + function startMeasuringGas(string memory label) internal virtual { + checkpointLabel = label; + + checkpointGasLeft = gasleft(); + } + + function stopMeasuringGas() internal virtual { + uint256 checkpointGasLeft2 = gasleft(); + + // Subtract 100 to account for the warm SLOAD in startMeasuringGas. + uint256 gasDelta = checkpointGasLeft - checkpointGasLeft2 - 100; + + emit log_named_uint(string(abi.encodePacked(checkpointLabel, " Gas")), gasDelta); + } + + function fail(string memory err) internal virtual { + emit log_named_string("Error", err); + fail(); + } + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertUint128Eq(uint128 a, uint128 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertUint64Eq(uint64 a, uint64 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertUint96Eq(uint96 a, uint96 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertUint32Eq(uint32 a, uint32 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertBoolEq(bool a, bool b) internal virtual { + b ? assertTrue(a) : assertFalse(a); + } + + function assertApproxEq( + uint256 a, + uint256 b, + uint256 maxDelta + ) internal virtual { + uint256 delta = a > b ? a - b : b - a; + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertRelApproxEq( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the expected is 0, actual must be too. + + uint256 percentDelta = ((a > b ? a - b : b - a) * 1e18) / b; + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Expected", b); + emit log_named_uint(" Actual", a); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta, 18); + emit log_named_decimal_uint(" % Delta", percentDelta, 18); + fail(); + } + } + + function assertBytesEq(bytes memory a, bytes memory b) internal virtual { + if (keccak256(a) != keccak256(b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Expected", b); + emit log_named_bytes(" Actual", a); + fail(); + } + } + + function assertUintArrayEq(uint256[] memory a, uint256[] memory b) internal virtual { + require(a.length == b.length, "LENGTH_MISMATCH"); + + for (uint256 i = 0; i < a.length; i++) { + assertEq(a[i], b[i]); + } + } + + function bound( + uint256 x, + uint256 min, + uint256 max + ) internal virtual returns (uint256 result) { + require(max >= min, "MAX_LESS_THAN_MIN"); + + uint256 size = max - min; + + if (size == 0) result = min; + else if (size == type(uint256).max) result = x; + else { + ++size; // Make max inclusive. + uint256 mod = x % size; + result = min + mod; + } + + emit log_named_uint("Bound Result", result); + } + + function min3( + uint256 a, + uint256 b, + uint256 c + ) internal pure returns (uint256) { + return a > b ? (b > c ? c : b) : (a > c ? c : a); + } + + function min2(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? b : a; + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/Hevm.sol b/lib/crytic/lib/solmate/src/test/utils/Hevm.sol new file mode 100644 index 0000000..8ca0eff --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/Hevm.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +interface Hevm { + /// @notice Sets the block timestamp. + function warp(uint256) external; + + /// @notice Sets the block height. + function roll(uint256) external; + + /// @notice Sets the block base fee. + function fee(uint256) external; + + /// @notice Loads a storage slot from an address. + function load(address, bytes32) external returns (bytes32); + + /// @notice Stores a value to an address' storage slot. + function store( + address, + bytes32, + bytes32 + ) external; + + /// @notice Signs a digest with a private key, returns v r s. + function sign(uint256, bytes32) + external + returns ( + uint8, + bytes32, + bytes32 + ); + + /// @notice Gets address for a given private key. + function addr(uint256) external returns (address); + + /// @notice Performs a foreign function call via a terminal call. + function ffi(string[] calldata) external returns (bytes memory); + + /// @notice Sets the next call's msg.sender to be the input address. + function prank(address) external; + + /// @notice Sets all subsequent calls' msg.sender to be the input address until stopPrank is called. + function startPrank(address) external; + + /// @notice Sets the next call's msg.sender to be the input address and the tx.origin to be the second input. + function prank(address, address) external; + + /// @notice Sets all subsequent calls' msg.sender to be the input address and + /// sets tx.origin to be the second address inputted until stopPrank is called. + function startPrank(address, address) external; + + /// @notice Resets msg.sender to its original value before a prank. + function stopPrank() external; + + /// @notice Sets an address' balance. + function deal(address, uint256) external; + + /// @notice Sets an address' code. + function etch(address, bytes calldata) external; + + /// @notice Expects an error from the next call. + function expectRevert(bytes calldata) external; + + /// @notice Expects a revert from the next call. + function expectRevert(bytes4) external; + + /// @notice Record all storage reads and writes. + function record() external; + + /// @notice Gets all accessed reads and write slots from a recording session, for a given address. + function accesses(address) external returns (bytes32[] memory reads, bytes32[] memory writes); + + /// @notice Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + /// @notice Call this function, then emit an event, then call a function. Internally after the call, we check + /// if logs were emitted in the expected order with the expected topics and data as specified by the booleans. + function expectEmit( + bool, + bool, + bool, + bool + ) external; + + /// @notice Mocks the behavior of a contract call, setting the input and output for a function. + /// @notice Calldata can either be strict or a partial match, e.g. if only passed + /// a selector to the expected calldata, then the entire function will be mocked. + function mockCall( + address, + bytes calldata, + bytes calldata + ) external; + + /// @notice Clears all mocked calls. + function clearMockedCalls() external; + + /// @notice Expect a call to an address with the specified calldata. + /// @notice Calldata can either be strict or a partial match. + function expectCall(address, bytes calldata) external; + + /// @notice Fetches the contract bytecode from its artifact file. + function getCode(string calldata) external returns (bytes memory); + + /// @notice Label an address in test traces. + function label(address addr, string calldata label) external; + + /// @notice When fuzzing, generate new inputs if the input conditional is not met. + function assume(bool) external; +} diff --git a/lib/crytic/lib/solmate/src/test/utils/mocks/MockAuthChild.sol b/lib/crytic/lib/solmate/src/test/utils/mocks/MockAuthChild.sol new file mode 100644 index 0000000..d2c3276 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/mocks/MockAuthChild.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Auth, Authority} from "../../../auth/Auth.sol"; + +contract MockAuthChild is Auth(msg.sender, Authority(address(0))) { + bool public flag; + + function updateFlag() public virtual requiresAuth { + flag = true; + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/mocks/MockAuthority.sol b/lib/crytic/lib/solmate/src/test/utils/mocks/MockAuthority.sol new file mode 100644 index 0000000..acb3689 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/mocks/MockAuthority.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Authority} from "../../../auth/Auth.sol"; + +contract MockAuthority is Authority { + bool immutable allowCalls; + + constructor(bool _allowCalls) { + allowCalls = _allowCalls; + } + + function canCall( + address, + address, + bytes4 + ) public view override returns (bool) { + return allowCalls; + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC1155.sol b/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC1155.sol new file mode 100644 index 0000000..ede086d --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC1155.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC1155} from "../../../tokens/ERC1155.sol"; + +contract MockERC1155 is ERC1155 { + function uri(uint256) public pure virtual override returns (string memory) {} + + function mint( + address to, + uint256 id, + uint256 amount, + bytes memory data + ) public virtual { + _mint(to, id, amount, data); + } + + function batchMint( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) public virtual { + _batchMint(to, ids, amounts, data); + } + + function burn( + address from, + uint256 id, + uint256 amount + ) public virtual { + _burn(from, id, amount); + } + + function batchBurn( + address from, + uint256[] memory ids, + uint256[] memory amounts + ) public virtual { + _batchBurn(from, ids, amounts); + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC20.sol b/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC20.sol new file mode 100644 index 0000000..fbbaef5 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC20.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "../../../tokens/ERC20.sol"; + +contract MockERC20 is ERC20 { + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) ERC20(_name, _symbol, _decimals) {} + + function mint(address to, uint256 value) public virtual { + _mint(to, value); + } + + function burn(address from, uint256 value) public virtual { + _burn(from, value); + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC4626.sol b/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC4626.sol new file mode 100644 index 0000000..edc7d5f --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC4626.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "../../../tokens/ERC20.sol"; +import {ERC4626} from "../../../mixins/ERC4626.sol"; + +contract MockERC4626 is ERC4626 { + uint256 public beforeWithdrawHookCalledCounter = 0; + uint256 public afterDepositHookCalledCounter = 0; + + constructor( + ERC20 _underlying, + string memory _name, + string memory _symbol + ) ERC4626(_underlying, _name, _symbol) {} + + function totalAssets() public view override returns (uint256) { + return asset.balanceOf(address(this)); + } + + function beforeWithdraw(uint256, uint256) internal override { + beforeWithdrawHookCalledCounter++; + } + + function afterDeposit(uint256, uint256) internal override { + afterDepositHookCalledCounter++; + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC721.sol b/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC721.sol new file mode 100644 index 0000000..51227c0 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/mocks/MockERC721.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC721} from "../../../tokens/ERC721.sol"; + +contract MockERC721 is ERC721 { + constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) {} + + function tokenURI(uint256) public pure virtual override returns (string memory) {} + + function mint(address to, uint256 tokenId) public virtual { + _mint(to, tokenId); + } + + function burn(uint256 tokenId) public virtual { + _burn(tokenId); + } + + function safeMint(address to, uint256 tokenId) public virtual { + _safeMint(to, tokenId); + } + + function safeMint( + address to, + uint256 tokenId, + bytes memory data + ) public virtual { + _safeMint(to, tokenId, data); + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/mocks/MockOwned.sol b/lib/crytic/lib/solmate/src/test/utils/mocks/MockOwned.sol new file mode 100644 index 0000000..52ef918 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/mocks/MockOwned.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Owned} from "../../../auth/Owned.sol"; + +contract MockOwned is Owned(msg.sender) { + bool public flag; + + function updateFlag() public virtual onlyOwner { + flag = true; + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sol b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sol new file mode 100644 index 0000000..23f4633 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract MissingReturnToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "MissingReturnToken"; + + string public constant symbol = "MRT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + } + + function transfer(address to, uint256 amount) public virtual { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sol b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sol new file mode 100644 index 0000000..8139efe --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsFalseToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsFalseToken"; + + string public constant symbol = "RFT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address, uint256) public virtual returns (bool) { + return false; + } + + function transfer(address, uint256) public virtual returns (bool) { + return false; + } + + function transferFrom( + address, + address, + uint256 + ) public virtual returns (bool) { + return false; + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sol b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sol new file mode 100644 index 0000000..77c9575 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsGarbageToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsGarbageToken"; + + string public constant symbol = "RGT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + MOCK STORAGE + //////////////////////////////////////////////////////////////*/ + + bytes garbage; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + bytes memory _garbage = garbage; + + assembly { + return(add(_garbage, 32), mload(_garbage)) + } + } + + function transfer(address to, uint256 amount) public virtual { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + + bytes memory _garbage = garbage; + + assembly { + return(add(_garbage, 32), mload(_garbage)) + } + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + + bytes memory _garbage = garbage; + + assembly { + return(add(_garbage, 32), mload(_garbage)) + } + } + + /*/////////////////////////////////////////////////////////////// + MOCK LOGIC + //////////////////////////////////////////////////////////////*/ + + function setGarbage(bytes memory _garbage) public virtual { + garbage = _garbage; + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sol b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sol new file mode 100644 index 0000000..69947c3 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsTooLittleToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsTooLittleToken"; + + string public constant symbol = "RTLT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address, uint256) public virtual { + assembly { + mstore(0, 0x0100000000000000000000000000000000000000000000000000000000000000) + return(0, 8) + } + } + + function transfer(address, uint256) public virtual { + assembly { + mstore(0, 0x0100000000000000000000000000000000000000000000000000000000000000) + return(0, 8) + } + } + + function transferFrom( + address, + address, + uint256 + ) public virtual { + assembly { + mstore(0, 0x0100000000000000000000000000000000000000000000000000000000000000) + return(0, 8) + } + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sol b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sol new file mode 100644 index 0000000..8774cbb --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsTooMuchToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsTooMuchToken"; + + string public constant symbol = "RTMT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + assembly { + mstore(0, 1) + return(0, 4096) + } + } + + function transfer(address to, uint256 amount) public virtual { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + + assembly { + mstore(0, 1) + return(0, 4096) + } + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + + assembly { + mstore(0, 1) + return(0, 4096) + } + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sol b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sol new file mode 100644 index 0000000..ac980f8 --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract ReturnsTwoToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "ReturnsFalseToken"; + + string public constant symbol = "RTT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address, uint256) public virtual returns (uint256) { + return 2; + } + + function transfer(address, uint256) public virtual returns (uint256) { + return 2; + } + + function transferFrom( + address, + address, + uint256 + ) public virtual returns (uint256) { + return 2; + } +} diff --git a/lib/crytic/lib/solmate/src/test/utils/weird-tokens/RevertingToken.sol b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/RevertingToken.sol new file mode 100644 index 0000000..48ac1fa --- /dev/null +++ b/lib/crytic/lib/solmate/src/test/utils/weird-tokens/RevertingToken.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +contract RevertingToken { + /*/////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*/////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public constant name = "RevertingToken"; + + string public constant symbol = "RT"; + + uint8 public constant decimals = 18; + + /*/////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*/////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor() { + totalSupply = type(uint256).max; + balanceOf[msg.sender] = type(uint256).max; + } + + /*/////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address, uint256) public virtual { + revert(); + } + + function transfer(address, uint256) public virtual { + revert(); + } + + function transferFrom( + address, + address, + uint256 + ) public virtual { + revert(); + } +} diff --git a/lib/crytic/lib/solmate/src/tokens/ERC1155.sol b/lib/crytic/lib/solmate/src/tokens/ERC1155.sol new file mode 100644 index 0000000..cff0f02 --- /dev/null +++ b/lib/crytic/lib/solmate/src/tokens/ERC1155.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Minimalist and gas efficient standard ERC1155 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) +abstract contract ERC1155 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event TransferSingle( + address indexed operator, + address indexed from, + address indexed to, + uint256 id, + uint256 amount + ); + + event TransferBatch( + address indexed operator, + address indexed from, + address indexed to, + uint256[] ids, + uint256[] amounts + ); + + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + event URI(string value, uint256 indexed id); + + /*////////////////////////////////////////////////////////////// + ERC1155 STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(address => mapping(uint256 => uint256)) public balanceOf; + + mapping(address => mapping(address => bool)) public isApprovedForAll; + + /*////////////////////////////////////////////////////////////// + METADATA LOGIC + //////////////////////////////////////////////////////////////*/ + + function uri(uint256 id) public view virtual returns (string memory); + + /*////////////////////////////////////////////////////////////// + ERC1155 LOGIC + //////////////////////////////////////////////////////////////*/ + + function setApprovalForAll(address operator, bool approved) public virtual { + isApprovedForAll[msg.sender][operator] = approved; + + emit ApprovalForAll(msg.sender, operator, approved); + } + + function safeTransferFrom( + address from, + address to, + uint256 id, + uint256 amount, + bytes calldata data + ) public virtual { + require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); + + balanceOf[from][id] -= amount; + balanceOf[to][id] += amount; + + emit TransferSingle(msg.sender, from, to, id, amount); + + require( + to.code.length == 0 + ? to != address(0) + : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) == + ERC1155TokenReceiver.onERC1155Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function safeBatchTransferFrom( + address from, + address to, + uint256[] calldata ids, + uint256[] calldata amounts, + bytes calldata data + ) public virtual { + require(ids.length == amounts.length, "LENGTH_MISMATCH"); + + require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED"); + + // Storing these outside the loop saves ~15 gas per iteration. + uint256 id; + uint256 amount; + + for (uint256 i = 0; i < ids.length; ) { + id = ids[i]; + amount = amounts[i]; + + balanceOf[from][id] -= amount; + balanceOf[to][id] += amount; + + // An array can't have a total length + // larger than the max uint256 value. + unchecked { + ++i; + } + } + + emit TransferBatch(msg.sender, from, to, ids, amounts); + + require( + to.code.length == 0 + ? to != address(0) + : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) == + ERC1155TokenReceiver.onERC1155BatchReceived.selector, + "UNSAFE_RECIPIENT" + ); + } + + function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) + public + view + virtual + returns (uint256[] memory balances) + { + require(owners.length == ids.length, "LENGTH_MISMATCH"); + + balances = new uint256[](owners.length); + + // Unchecked because the only math done is incrementing + // the array index counter which cannot possibly overflow. + unchecked { + for (uint256 i = 0; i < owners.length; ++i) { + balances[i] = balanceOf[owners[i]][ids[i]]; + } + } + } + + /*////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return + interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 + interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155 + interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint( + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + balanceOf[to][id] += amount; + + emit TransferSingle(msg.sender, address(0), to, id, amount); + + require( + to.code.length == 0 + ? to != address(0) + : ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) == + ERC1155TokenReceiver.onERC1155Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _batchMint( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + uint256 idsLength = ids.length; // Saves MLOADs. + + require(idsLength == amounts.length, "LENGTH_MISMATCH"); + + for (uint256 i = 0; i < idsLength; ) { + balanceOf[to][ids[i]] += amounts[i]; + + // An array can't have a total length + // larger than the max uint256 value. + unchecked { + ++i; + } + } + + emit TransferBatch(msg.sender, address(0), to, ids, amounts); + + require( + to.code.length == 0 + ? to != address(0) + : ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) == + ERC1155TokenReceiver.onERC1155BatchReceived.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _batchBurn( + address from, + uint256[] memory ids, + uint256[] memory amounts + ) internal virtual { + uint256 idsLength = ids.length; // Saves MLOADs. + + require(idsLength == amounts.length, "LENGTH_MISMATCH"); + + for (uint256 i = 0; i < idsLength; ) { + balanceOf[from][ids[i]] -= amounts[i]; + + // An array can't have a total length + // larger than the max uint256 value. + unchecked { + ++i; + } + } + + emit TransferBatch(msg.sender, from, address(0), ids, amounts); + } + + function _burn( + address from, + uint256 id, + uint256 amount + ) internal virtual { + balanceOf[from][id] -= amount; + + emit TransferSingle(msg.sender, from, address(0), id, amount); + } +} + +/// @notice A generic interface for a contract which properly accepts ERC1155 tokens. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol) +abstract contract ERC1155TokenReceiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes calldata + ) external virtual returns (bytes4) { + return ERC1155TokenReceiver.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] calldata, + uint256[] calldata, + bytes calldata + ) external virtual returns (bytes4) { + return ERC1155TokenReceiver.onERC1155BatchReceived.selector; + } +} diff --git a/lib/crytic/lib/solmate/src/tokens/ERC20.sol b/lib/crytic/lib/solmate/src/tokens/ERC20.sol new file mode 100644 index 0000000..9657044 --- /dev/null +++ b/lib/crytic/lib/solmate/src/tokens/ERC20.sol @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol) +/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol) +/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it. +abstract contract ERC20 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 amount); + + event Approval(address indexed owner, address indexed spender, uint256 amount); + + /*////////////////////////////////////////////////////////////// + METADATA STORAGE + //////////////////////////////////////////////////////////////*/ + + string public name; + + string public symbol; + + uint8 public immutable decimals; + + /*////////////////////////////////////////////////////////////// + ERC20 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 public totalSupply; + + mapping(address => uint256) public balanceOf; + + mapping(address => mapping(address => uint256)) public allowance; + + /*////////////////////////////////////////////////////////////// + EIP-2612 STORAGE + //////////////////////////////////////////////////////////////*/ + + uint256 internal immutable INITIAL_CHAIN_ID; + + bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR; + + mapping(address => uint256) public nonces; + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals + ) { + name = _name; + symbol = _symbol; + decimals = _decimals; + + INITIAL_CHAIN_ID = block.chainid; + INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator(); + } + + /*////////////////////////////////////////////////////////////// + ERC20 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 amount) public virtual returns (bool) { + allowance[msg.sender][spender] = amount; + + emit Approval(msg.sender, spender, amount); + + return true; + } + + function transfer(address to, uint256 amount) public virtual returns (bool) { + balanceOf[msg.sender] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(msg.sender, to, amount); + + return true; + } + + function transferFrom( + address from, + address to, + uint256 amount + ) public virtual returns (bool) { + uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals. + + if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount; + + balanceOf[from] -= amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(from, to, amount); + + return true; + } + + /*////////////////////////////////////////////////////////////// + EIP-2612 LOGIC + //////////////////////////////////////////////////////////////*/ + + function permit( + address owner, + address spender, + uint256 value, + uint256 deadline, + uint8 v, + bytes32 r, + bytes32 s + ) public virtual { + require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED"); + + // Unchecked because the only math done is incrementing + // the owner's nonce which cannot realistically overflow. + unchecked { + address recoveredAddress = ecrecover( + keccak256( + abi.encodePacked( + "\x19\x01", + DOMAIN_SEPARATOR(), + keccak256( + abi.encode( + keccak256( + "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" + ), + owner, + spender, + value, + nonces[owner]++, + deadline + ) + ) + ) + ), + v, + r, + s + ); + + require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER"); + + allowance[recoveredAddress][spender] = value; + } + + emit Approval(owner, spender, value); + } + + function DOMAIN_SEPARATOR() public view virtual returns (bytes32) { + return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator(); + } + + function computeDomainSeparator() internal view virtual returns (bytes32) { + return + keccak256( + abi.encode( + keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), + keccak256(bytes(name)), + keccak256("1"), + block.chainid, + address(this) + ) + ); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 amount) internal virtual { + totalSupply += amount; + + // Cannot overflow because the sum of all user + // balances can't exceed the max uint256 value. + unchecked { + balanceOf[to] += amount; + } + + emit Transfer(address(0), to, amount); + } + + function _burn(address from, uint256 amount) internal virtual { + balanceOf[from] -= amount; + + // Cannot underflow because a user's balance + // will never be larger than the total supply. + unchecked { + totalSupply -= amount; + } + + emit Transfer(from, address(0), amount); + } +} diff --git a/lib/crytic/lib/solmate/src/tokens/ERC721.sol b/lib/crytic/lib/solmate/src/tokens/ERC721.sol new file mode 100644 index 0000000..b47f271 --- /dev/null +++ b/lib/crytic/lib/solmate/src/tokens/ERC721.sol @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Modern, minimalist, and gas efficient ERC-721 implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) +abstract contract ERC721 { + /*////////////////////////////////////////////////////////////// + EVENTS + //////////////////////////////////////////////////////////////*/ + + event Transfer(address indexed from, address indexed to, uint256 indexed id); + + event Approval(address indexed owner, address indexed spender, uint256 indexed id); + + event ApprovalForAll(address indexed owner, address indexed operator, bool approved); + + /*////////////////////////////////////////////////////////////// + METADATA STORAGE/LOGIC + //////////////////////////////////////////////////////////////*/ + + string public name; + + string public symbol; + + function tokenURI(uint256 id) public view virtual returns (string memory); + + /*////////////////////////////////////////////////////////////// + ERC721 BALANCE/OWNER STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) internal _ownerOf; + + mapping(address => uint256) internal _balanceOf; + + function ownerOf(uint256 id) public view virtual returns (address owner) { + require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); + } + + function balanceOf(address owner) public view virtual returns (uint256) { + require(owner != address(0), "ZERO_ADDRESS"); + + return _balanceOf[owner]; + } + + /*////////////////////////////////////////////////////////////// + ERC721 APPROVAL STORAGE + //////////////////////////////////////////////////////////////*/ + + mapping(uint256 => address) public getApproved; + + mapping(address => mapping(address => bool)) public isApprovedForAll; + + /*////////////////////////////////////////////////////////////// + CONSTRUCTOR + //////////////////////////////////////////////////////////////*/ + + constructor(string memory _name, string memory _symbol) { + name = _name; + symbol = _symbol; + } + + /*////////////////////////////////////////////////////////////// + ERC721 LOGIC + //////////////////////////////////////////////////////////////*/ + + function approve(address spender, uint256 id) public virtual { + address owner = _ownerOf[id]; + + require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); + + getApproved[id] = spender; + + emit Approval(owner, spender, id); + } + + function setApprovalForAll(address operator, bool approved) public virtual { + isApprovedForAll[msg.sender][operator] = approved; + + emit ApprovalForAll(msg.sender, operator, approved); + } + + function transferFrom( + address from, + address to, + uint256 id + ) public virtual { + require(from == _ownerOf[id], "WRONG_FROM"); + + require(to != address(0), "INVALID_RECIPIENT"); + + require( + msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], + "NOT_AUTHORIZED" + ); + + // Underflow of the sender's balance is impossible because we check for + // ownership above and the recipient's balance can't realistically overflow. + unchecked { + _balanceOf[from]--; + + _balanceOf[to]++; + } + + _ownerOf[id] = to; + + delete getApproved[id]; + + emit Transfer(from, to, id); + } + + function safeTransferFrom( + address from, + address to, + uint256 id + ) public virtual { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function safeTransferFrom( + address from, + address to, + uint256 id, + bytes calldata data + ) public virtual { + transferFrom(from, to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + /*////////////////////////////////////////////////////////////// + ERC165 LOGIC + //////////////////////////////////////////////////////////////*/ + + function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { + return + interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 + interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 + interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata + } + + /*////////////////////////////////////////////////////////////// + INTERNAL MINT/BURN LOGIC + //////////////////////////////////////////////////////////////*/ + + function _mint(address to, uint256 id) internal virtual { + require(to != address(0), "INVALID_RECIPIENT"); + + require(_ownerOf[id] == address(0), "ALREADY_MINTED"); + + // Counter overflow is incredibly unrealistic. + unchecked { + _balanceOf[to]++; + } + + _ownerOf[id] = to; + + emit Transfer(address(0), to, id); + } + + function _burn(uint256 id) internal virtual { + address owner = _ownerOf[id]; + + require(owner != address(0), "NOT_MINTED"); + + // Ownership check above ensures no underflow. + unchecked { + _balanceOf[owner]--; + } + + delete _ownerOf[id]; + + delete getApproved[id]; + + emit Transfer(owner, address(0), id); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL SAFE MINT LOGIC + //////////////////////////////////////////////////////////////*/ + + function _safeMint(address to, uint256 id) internal virtual { + _mint(to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } + + function _safeMint( + address to, + uint256 id, + bytes memory data + ) internal virtual { + _mint(to, id); + + require( + to.code.length == 0 || + ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == + ERC721TokenReceiver.onERC721Received.selector, + "UNSAFE_RECIPIENT" + ); + } +} + +/// @notice A generic interface for a contract which properly accepts ERC721 tokens. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) +abstract contract ERC721TokenReceiver { + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) external virtual returns (bytes4) { + return ERC721TokenReceiver.onERC721Received.selector; + } +} diff --git a/lib/crytic/lib/solmate/src/tokens/WETH.sol b/lib/crytic/lib/solmate/src/tokens/WETH.sol new file mode 100644 index 0000000..ddf9647 --- /dev/null +++ b/lib/crytic/lib/solmate/src/tokens/WETH.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "./ERC20.sol"; + +import {SafeTransferLib} from "../utils/SafeTransferLib.sol"; + +/// @notice Minimalist and modern Wrapped Ether implementation. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/WETH.sol) +/// @author Inspired by WETH9 (https://github.com/dapphub/ds-weth/blob/master/src/weth9.sol) +contract WETH is ERC20("Wrapped Ether", "WETH", 18) { + using SafeTransferLib for address; + + event Deposit(address indexed from, uint256 amount); + + event Withdrawal(address indexed to, uint256 amount); + + function deposit() public payable virtual { + _mint(msg.sender, msg.value); + + emit Deposit(msg.sender, msg.value); + } + + function withdraw(uint256 amount) public virtual { + _burn(msg.sender, amount); + + emit Withdrawal(msg.sender, amount); + + msg.sender.safeTransferETH(amount); + } + + receive() external payable virtual { + deposit(); + } +} diff --git a/lib/crytic/lib/solmate/src/utils/Bytes32AddressLib.sol b/lib/crytic/lib/solmate/src/utils/Bytes32AddressLib.sol new file mode 100644 index 0000000..448fb75 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/Bytes32AddressLib.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Library for converting between addresses and bytes32 values. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Bytes32AddressLib.sol) +library Bytes32AddressLib { + function fromLast20Bytes(bytes32 bytesValue) internal pure returns (address) { + return address(uint160(uint256(bytesValue))); + } + + function fillLast12Bytes(address addressValue) internal pure returns (bytes32) { + return bytes32(bytes20(addressValue)); + } +} diff --git a/lib/crytic/lib/solmate/src/utils/CREATE3.sol b/lib/crytic/lib/solmate/src/utils/CREATE3.sol new file mode 100644 index 0000000..0d5b341 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/CREATE3.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {Bytes32AddressLib} from "./Bytes32AddressLib.sol"; + +/// @notice Deploy to deterministic addresses without an initcode factor. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/CREATE3.sol) +/// @author Modified from 0xSequence (https://github.com/0xSequence/create3/blob/master/contracts/Create3.sol) +library CREATE3 { + using Bytes32AddressLib for bytes32; + + //--------------------------------------------------------------------------------// + // Opcode | Opcode + Arguments | Description | Stack View // + //--------------------------------------------------------------------------------// + // 0x36 | 0x36 | CALLDATASIZE | size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 0 size // + // 0x37 | 0x37 | CALLDATACOPY | // + // 0x36 | 0x36 | CALLDATASIZE | size // + // 0x3d | 0x3d | RETURNDATASIZE | 0 size // + // 0x34 | 0x34 | CALLVALUE | value 0 size // + // 0xf0 | 0xf0 | CREATE | newContract // + //--------------------------------------------------------------------------------// + // Opcode | Opcode + Arguments | Description | Stack View // + //--------------------------------------------------------------------------------// + // 0x67 | 0x67XXXXXXXXXXXXXXXX | PUSH8 bytecode | bytecode // + // 0x3d | 0x3d | RETURNDATASIZE | 0 bytecode // + // 0x52 | 0x52 | MSTORE | // + // 0x60 | 0x6008 | PUSH1 08 | 8 // + // 0x60 | 0x6018 | PUSH1 18 | 24 8 // + // 0xf3 | 0xf3 | RETURN | // + //--------------------------------------------------------------------------------// + bytes internal constant PROXY_BYTECODE = hex"67_36_3d_3d_37_36_3d_34_f0_3d_52_60_08_60_18_f3"; + + bytes32 internal constant PROXY_BYTECODE_HASH = keccak256(PROXY_BYTECODE); + + function deploy( + bytes32 salt, + bytes memory creationCode, + uint256 value + ) internal returns (address deployed) { + bytes memory proxyChildBytecode = PROXY_BYTECODE; + + address proxy; + /// @solidity memory-safe-assembly + assembly { + // Deploy a new contract with our pre-made bytecode via CREATE2. + // We start 32 bytes into the code to avoid copying the byte length. + proxy := create2(0, add(proxyChildBytecode, 32), mload(proxyChildBytecode), salt) + } + require(proxy != address(0), "DEPLOYMENT_FAILED"); + + deployed = getDeployed(salt); + (bool success, ) = proxy.call{value: value}(creationCode); + require(success && deployed.code.length != 0, "INITIALIZATION_FAILED"); + } + + function getDeployed(bytes32 salt) internal view returns (address) { + address proxy = keccak256( + abi.encodePacked( + // Prefix: + bytes1(0xFF), + // Creator: + address(this), + // Salt: + salt, + // Bytecode hash: + PROXY_BYTECODE_HASH + ) + ).fromLast20Bytes(); + + return + keccak256( + abi.encodePacked( + // 0xd6 = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x01) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + hex"d6_94", + proxy, + hex"01" // Nonce of the proxy contract (1) + ) + ).fromLast20Bytes(); + } +} diff --git a/lib/crytic/lib/solmate/src/utils/FixedPointMathLib.sol b/lib/crytic/lib/solmate/src/utils/FixedPointMathLib.sol new file mode 100644 index 0000000..6887722 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/FixedPointMathLib.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Arithmetic library with operations for fixed-point numbers. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol) +/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol) +library FixedPointMathLib { + /*////////////////////////////////////////////////////////////// + SIMPLIFIED FIXED POINT OPERATIONS + //////////////////////////////////////////////////////////////*/ + + uint256 internal constant MAX_UINT256 = 2**256 - 1; + + uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s. + + function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) { + return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down. + } + + function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) { + return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up. + } + + function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) { + return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down. + } + + function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) { + return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up. + } + + /*////////////////////////////////////////////////////////////// + LOW LEVEL FIXED POINT OPERATIONS + //////////////////////////////////////////////////////////////*/ + + function mulDivDown( + uint256 x, + uint256 y, + uint256 denominator + ) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) + if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { + revert(0, 0) + } + + // Divide x * y by the denominator. + z := div(mul(x, y), denominator) + } + } + + function mulDivUp( + uint256 x, + uint256 y, + uint256 denominator + ) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Equivalent to require(denominator != 0 && (y == 0 || x <= type(uint256).max / y)) + if iszero(mul(denominator, iszero(mul(y, gt(x, div(MAX_UINT256, y)))))) { + revert(0, 0) + } + + // If x * y modulo the denominator is strictly greater than 0, + // 1 is added to round up the division of x * y by the denominator. + z := add(gt(mod(mul(x, y), denominator), 0), div(mul(x, y), denominator)) + } + } + + function rpow( + uint256 x, + uint256 n, + uint256 scalar + ) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + switch x + case 0 { + switch n + case 0 { + // 0 ** 0 = 1 + z := scalar + } + default { + // 0 ** n = 0 + z := 0 + } + } + default { + switch mod(n, 2) + case 0 { + // If n is even, store scalar in z for now. + z := scalar + } + default { + // If n is odd, store x in z for now. + z := x + } + + // Shifting right by 1 is like dividing by 2. + let half := shr(1, scalar) + + for { + // Shift n right by 1 before looping to halve it. + n := shr(1, n) + } n { + // Shift n right by 1 each iteration to halve it. + n := shr(1, n) + } { + // Revert immediately if x ** 2 would overflow. + // Equivalent to iszero(eq(div(xx, x), x)) here. + if shr(128, x) { + revert(0, 0) + } + + // Store x squared. + let xx := mul(x, x) + + // Round to the nearest number. + let xxRound := add(xx, half) + + // Revert if xx + half overflowed. + if lt(xxRound, xx) { + revert(0, 0) + } + + // Set x to scaled xxRound. + x := div(xxRound, scalar) + + // If n is even: + if mod(n, 2) { + // Compute z * x. + let zx := mul(z, x) + + // If z * x overflowed: + if iszero(eq(div(zx, x), z)) { + // Revert if x is non-zero. + if iszero(iszero(x)) { + revert(0, 0) + } + } + + // Round to the nearest number. + let zxRound := add(zx, half) + + // Revert if zx + half overflowed. + if lt(zxRound, zx) { + revert(0, 0) + } + + // Return properly scaled zxRound. + z := div(zxRound, scalar) + } + } + } + } + } + + /*////////////////////////////////////////////////////////////// + GENERAL NUMBER UTILITIES + //////////////////////////////////////////////////////////////*/ + + function sqrt(uint256 x) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + let y := x // We start y at x, which will help us make our initial estimate. + + z := 181 // The "correct" value is 1, but this saves a multiplication later. + + // This segment is to get a reasonable initial estimate for the Babylonian method. With a bad + // start, the correct # of bits increases ~linearly each iteration instead of ~quadratically. + + // We check y >= 2^(k + 8) but shift right by k bits + // each branch to ensure that if x >= 256, then y >= 256. + if iszero(lt(y, 0x10000000000000000000000000000000000)) { + y := shr(128, y) + z := shl(64, z) + } + if iszero(lt(y, 0x1000000000000000000)) { + y := shr(64, y) + z := shl(32, z) + } + if iszero(lt(y, 0x10000000000)) { + y := shr(32, y) + z := shl(16, z) + } + if iszero(lt(y, 0x1000000)) { + y := shr(16, y) + z := shl(8, z) + } + + // Goal was to get z*z*y within a small factor of x. More iterations could + // get y in a tighter range. Currently, we will have y in [256, 256*2^16). + // We ensured y >= 256 so that the relative difference between y and y+1 is small. + // That's not possible if x < 256 but we can just verify those cases exhaustively. + + // Now, z*z*y <= x < z*z*(y+1), and y <= 2^(16+8), and either y >= 256, or x < 256. + // Correctness can be checked exhaustively for x < 256, so we assume y >= 256. + // Then z*sqrt(y) is within sqrt(257)/sqrt(256) of sqrt(x), or about 20bps. + + // For s in the range [1/256, 256], the estimate f(s) = (181/1024) * (s+1) is in the range + // (1/2.84 * sqrt(s), 2.84 * sqrt(s)), with largest error when s = 1 and when s = 256 or 1/256. + + // Since y is in [256, 256*2^16), let a = y/65536, so that a is in [1/256, 256). Then we can estimate + // sqrt(y) using sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2^18. + + // There is no overflow risk here since y < 2^136 after the first branch above. + z := shr(18, mul(z, add(y, 65536))) // A mul() is saved from starting z at 181. + + // Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough. + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + z := shr(1, add(z, div(x, z))) + + // If x+1 is a perfect square, the Babylonian method cycles between + // floor(sqrt(x)) and ceil(sqrt(x)). This statement ensures we return floor. + // See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division + // Since the ceil is rare, we save gas on the assignment and repeat division in the rare case. + // If you don't care whether the floor or ceil square root is returned, you can remove this statement. + z := sub(z, lt(div(x, z), z)) + } + } + + function unsafeMod(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Mod x by y. Note this will return + // 0 instead of reverting if y is zero. + z := mod(x, y) + } + } + + function unsafeDiv(uint256 x, uint256 y) internal pure returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + // Divide x by y. Note this will return + // 0 instead of reverting if y is zero. + r := div(x, y) + } + } + + function unsafeDivUp(uint256 x, uint256 y) internal pure returns (uint256 z) { + /// @solidity memory-safe-assembly + assembly { + // Add 1 to x * y if x % y > 0. Note this will + // return 0 instead of reverting if y is zero. + z := add(gt(mod(x, y), 0), div(x, y)) + } + } +} diff --git a/lib/crytic/lib/solmate/src/utils/LibString.sol b/lib/crytic/lib/solmate/src/utils/LibString.sol new file mode 100644 index 0000000..97c89e0 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/LibString.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/// @notice Efficient library for creating string representations of integers. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) +/// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibString.sol) +library LibString { + function toString(int256 value) internal pure returns (string memory str) { + if (value >= 0) return toString(uint256(value)); + + unchecked { + str = toString(uint256(-value)); + + /// @solidity memory-safe-assembly + assembly { + // Note: This is only safe because we over-allocate memory + // and write the string from right to left in toString(uint256), + // and thus can be sure that sub(str, 1) is an unused memory location. + + let length := mload(str) // Load the string length. + // Put the - character at the start of the string contents. + mstore(str, 45) // 45 is the ASCII code for the - character. + str := sub(str, 1) // Move back the string pointer by a byte. + mstore(str, add(length, 1)) // Update the string length. + } + } + } + + function toString(uint256 value) internal pure returns (string memory str) { + /// @solidity memory-safe-assembly + assembly { + // The maximum value of a uint256 contains 78 digits (1 byte per digit), but we allocate 160 bytes + // to keep the free memory pointer word aligned. We'll need 1 word for the length, 1 word for the + // trailing zeros padding, and 3 other words for a max of 78 digits. In total: 5 * 32 = 160 bytes. + let newFreeMemoryPointer := add(mload(0x40), 160) + + // Update the free memory pointer to avoid overriding our string. + mstore(0x40, newFreeMemoryPointer) + + // Assign str to the end of the zone of newly allocated memory. + str := sub(newFreeMemoryPointer, 32) + + // Clean the last word of memory it may not be overwritten. + mstore(str, 0) + + // Cache the end of the memory to calculate the length later. + let end := str + + // We write the string from rightmost digit to leftmost digit. + // The following is essentially a do-while loop that also handles the zero case. + // prettier-ignore + for { let temp := value } 1 {} { + // Move the pointer 1 byte to the left. + str := sub(str, 1) + + // Write the character to the pointer. + // The ASCII index of the '0' character is 48. + mstore8(str, add(48, mod(temp, 10))) + + // Keep dividing temp until zero. + temp := div(temp, 10) + + // prettier-ignore + if iszero(temp) { break } + } + + // Compute and cache the final total length of the string. + let length := sub(end, str) + + // Move the pointer 32 bytes leftwards to make room for the length. + str := sub(str, 32) + + // Store the string's length at the start of memory allocated for our string. + mstore(str, length) + } + } +} diff --git a/lib/crytic/lib/solmate/src/utils/MerkleProofLib.sol b/lib/crytic/lib/solmate/src/utils/MerkleProofLib.sol new file mode 100644 index 0000000..8fd7cbd --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/MerkleProofLib.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/// @notice Gas optimized merkle proof verification library. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) +/// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) +library MerkleProofLib { + function verify( + bytes32[] calldata proof, + bytes32 root, + bytes32 leaf + ) internal pure returns (bool isValid) { + /// @solidity memory-safe-assembly + assembly { + if proof.length { + // Left shifting by 5 is like multiplying by 32. + let end := add(proof.offset, shl(5, proof.length)) + + // Initialize offset to the offset of the proof in calldata. + let offset := proof.offset + + // Iterate over proof elements to compute root hash. + // prettier-ignore + for {} 1 {} { + // Slot where the leaf should be put in scratch space. If + // leaf > calldataload(offset): slot 32, otherwise: slot 0. + let leafSlot := shl(5, gt(leaf, calldataload(offset))) + + // Store elements to hash contiguously in scratch space. + // The xor puts calldataload(offset) in whichever slot leaf + // is not occupying, so 0 if leafSlot is 32, and 32 otherwise. + mstore(leafSlot, leaf) + mstore(xor(leafSlot, 32), calldataload(offset)) + + // Reuse leaf to store the hash to reduce stack operations. + leaf := keccak256(0, 64) // Hash both slots of scratch space. + + offset := add(offset, 32) // Shift 1 word per cycle. + + // prettier-ignore + if iszero(lt(offset, end)) { break } + } + } + + isValid := eq(leaf, root) // The proof is valid if the roots match. + } + } +} diff --git a/lib/crytic/lib/solmate/src/utils/ReentrancyGuard.sol b/lib/crytic/lib/solmate/src/utils/ReentrancyGuard.sol new file mode 100644 index 0000000..1453e24 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/ReentrancyGuard.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Gas optimized reentrancy protection for smart contracts. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ReentrancyGuard.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol) +abstract contract ReentrancyGuard { + uint256 private locked = 1; + + modifier nonReentrant() virtual { + require(locked == 1, "REENTRANCY"); + + locked = 2; + + _; + + locked = 1; + } +} diff --git a/lib/crytic/lib/solmate/src/utils/SSTORE2.sol b/lib/crytic/lib/solmate/src/utils/SSTORE2.sol new file mode 100644 index 0000000..23d6980 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/SSTORE2.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Read and write to persistent storage at a fraction of the cost. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol) +/// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol) +library SSTORE2 { + uint256 internal constant DATA_OFFSET = 1; // We skip the first byte as it's a STOP opcode to ensure the contract can't be called. + + /*////////////////////////////////////////////////////////////// + WRITE LOGIC + //////////////////////////////////////////////////////////////*/ + + function write(bytes memory data) internal returns (address pointer) { + // Prefix the bytecode with a STOP opcode to ensure it cannot be called. + bytes memory runtimeCode = abi.encodePacked(hex"00", data); + + bytes memory creationCode = abi.encodePacked( + //---------------------------------------------------------------------------------------------------------------// + // Opcode | Opcode + Arguments | Description | Stack View // + //---------------------------------------------------------------------------------------------------------------// + // 0x60 | 0x600B | PUSH1 11 | codeOffset // + // 0x59 | 0x59 | MSIZE | 0 codeOffset // + // 0x81 | 0x81 | DUP2 | codeOffset 0 codeOffset // + // 0x38 | 0x38 | CODESIZE | codeSize codeOffset 0 codeOffset // + // 0x03 | 0x03 | SUB | (codeSize - codeOffset) 0 codeOffset // + // 0x80 | 0x80 | DUP | (codeSize - codeOffset) (codeSize - codeOffset) 0 codeOffset // + // 0x92 | 0x92 | SWAP3 | codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) // + // 0x59 | 0x59 | MSIZE | 0 codeOffset (codeSize - codeOffset) 0 (codeSize - codeOffset) // + // 0x39 | 0x39 | CODECOPY | 0 (codeSize - codeOffset) // + // 0xf3 | 0xf3 | RETURN | // + //---------------------------------------------------------------------------------------------------------------// + hex"60_0B_59_81_38_03_80_92_59_39_F3", // Returns all code in the contract except for the first 11 (0B in hex) bytes. + runtimeCode // The bytecode we want the contract to have after deployment. Capped at 1 byte less than the code size limit. + ); + + /// @solidity memory-safe-assembly + assembly { + // Deploy a new contract with the generated creation code. + // We start 32 bytes into the code to avoid copying the byte length. + pointer := create(0, add(creationCode, 32), mload(creationCode)) + } + + require(pointer != address(0), "DEPLOYMENT_FAILED"); + } + + /*////////////////////////////////////////////////////////////// + READ LOGIC + //////////////////////////////////////////////////////////////*/ + + function read(address pointer) internal view returns (bytes memory) { + return readBytecode(pointer, DATA_OFFSET, pointer.code.length - DATA_OFFSET); + } + + function read(address pointer, uint256 start) internal view returns (bytes memory) { + start += DATA_OFFSET; + + return readBytecode(pointer, start, pointer.code.length - start); + } + + function read( + address pointer, + uint256 start, + uint256 end + ) internal view returns (bytes memory) { + start += DATA_OFFSET; + end += DATA_OFFSET; + + require(pointer.code.length >= end, "OUT_OF_BOUNDS"); + + return readBytecode(pointer, start, end - start); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL HELPER LOGIC + //////////////////////////////////////////////////////////////*/ + + function readBytecode( + address pointer, + uint256 start, + uint256 size + ) private view returns (bytes memory data) { + /// @solidity memory-safe-assembly + assembly { + // Get a pointer to some free memory. + data := mload(0x40) + + // Update the free memory pointer to prevent overriding our data. + // We use and(x, not(31)) as a cheaper equivalent to sub(x, mod(x, 32)). + // Adding 31 to size and running the result through the logic above ensures + // the memory pointer remains word-aligned, following the Solidity convention. + mstore(0x40, add(data, and(add(add(size, 32), 31), not(31)))) + + // Store the size of the data in the first 32 byte chunk of free memory. + mstore(data, size) + + // Copy the code into memory right after the 32 bytes we used to store the size. + extcodecopy(pointer, add(data, 32), start, size) + } + } +} diff --git a/lib/crytic/lib/solmate/src/utils/SafeCastLib.sol b/lib/crytic/lib/solmate/src/utils/SafeCastLib.sol new file mode 100644 index 0000000..ebbed22 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/SafeCastLib.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +/// @notice Safe unsigned integer casting library that reverts on overflow. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeCastLib.sol) +/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol) +library SafeCastLib { + function safeCastTo248(uint256 x) internal pure returns (uint248 y) { + require(x < 1 << 248); + + y = uint248(x); + } + + function safeCastTo224(uint256 x) internal pure returns (uint224 y) { + require(x < 1 << 224); + + y = uint224(x); + } + + function safeCastTo192(uint256 x) internal pure returns (uint192 y) { + require(x < 1 << 192); + + y = uint192(x); + } + + function safeCastTo160(uint256 x) internal pure returns (uint160 y) { + require(x < 1 << 160); + + y = uint160(x); + } + + function safeCastTo128(uint256 x) internal pure returns (uint128 y) { + require(x < 1 << 128); + + y = uint128(x); + } + + function safeCastTo96(uint256 x) internal pure returns (uint96 y) { + require(x < 1 << 96); + + y = uint96(x); + } + + function safeCastTo64(uint256 x) internal pure returns (uint64 y) { + require(x < 1 << 64); + + y = uint64(x); + } + + function safeCastTo32(uint256 x) internal pure returns (uint32 y) { + require(x < 1 << 32); + + y = uint32(x); + } + + function safeCastTo24(uint256 x) internal pure returns (uint24 y) { + require(x < 1 << 24); + + y = uint24(x); + } + + function safeCastTo16(uint256 x) internal pure returns (uint16 y) { + require(x < 1 << 16); + + y = uint16(x); + } + + function safeCastTo8(uint256 x) internal pure returns (uint8 y) { + require(x < 1 << 8); + + y = uint8(x); + } +} diff --git a/lib/crytic/lib/solmate/src/utils/SafeTransferLib.sol b/lib/crytic/lib/solmate/src/utils/SafeTransferLib.sol new file mode 100644 index 0000000..7080fd8 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/SafeTransferLib.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: AGPL-3.0-only +pragma solidity >=0.8.0; + +import {ERC20} from "../tokens/ERC20.sol"; + +/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) +/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. +/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. +library SafeTransferLib { + /*////////////////////////////////////////////////////////////// + ETH OPERATIONS + //////////////////////////////////////////////////////////////*/ + + function safeTransferETH(address to, uint256 amount) internal { + bool success; + + /// @solidity memory-safe-assembly + assembly { + // Transfer the ETH and store if it succeeded or not. + success := call(gas(), to, amount, 0, 0, 0, 0) + } + + require(success, "ETH_TRANSFER_FAILED"); + } + + /*////////////////////////////////////////////////////////////// + ERC20 OPERATIONS + //////////////////////////////////////////////////////////////*/ + + function safeTransferFrom( + ERC20 token, + address from, + address to, + uint256 amount + ) internal { + bool success; + + /// @solidity memory-safe-assembly + assembly { + // Get a pointer to some free memory. + let freeMemoryPointer := mload(0x40) + + // Write the abi-encoded calldata into memory, beginning with the function selector. + mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) + mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. + mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. + mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. + + success := and( + // Set success to whether the call reverted, if not we check it either + // returned exactly 1 (can't just be non-zero data), or had no return data. + or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), + // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. + // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. + // Counterintuitively, this call must be positioned second to the or() call in the + // surrounding and() call or else returndatasize() will be zero during the computation. + call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) + ) + } + + require(success, "TRANSFER_FROM_FAILED"); + } + + function safeTransfer( + ERC20 token, + address to, + uint256 amount + ) internal { + bool success; + + /// @solidity memory-safe-assembly + assembly { + // Get a pointer to some free memory. + let freeMemoryPointer := mload(0x40) + + // Write the abi-encoded calldata into memory, beginning with the function selector. + mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) + mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. + mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. + + success := and( + // Set success to whether the call reverted, if not we check it either + // returned exactly 1 (can't just be non-zero data), or had no return data. + or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), + // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. + // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. + // Counterintuitively, this call must be positioned second to the or() call in the + // surrounding and() call or else returndatasize() will be zero during the computation. + call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) + ) + } + + require(success, "TRANSFER_FAILED"); + } + + function safeApprove( + ERC20 token, + address to, + uint256 amount + ) internal { + bool success; + + /// @solidity memory-safe-assembly + assembly { + // Get a pointer to some free memory. + let freeMemoryPointer := mload(0x40) + + // Write the abi-encoded calldata into memory, beginning with the function selector. + mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) + mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. + mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. + + success := and( + // Set success to whether the call reverted, if not we check it either + // returned exactly 1 (can't just be non-zero data), or had no return data. + or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), + // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. + // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. + // Counterintuitively, this call must be positioned second to the or() call in the + // surrounding and() call or else returndatasize() will be zero during the computation. + call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) + ) + } + + require(success, "APPROVE_FAILED"); + } +} diff --git a/lib/crytic/lib/solmate/src/utils/SignedWadMath.sol b/lib/crytic/lib/solmate/src/utils/SignedWadMath.sol new file mode 100644 index 0000000..4344285 --- /dev/null +++ b/lib/crytic/lib/solmate/src/utils/SignedWadMath.sol @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/// @notice Signed 18 decimal fixed point (wad) arithmetic library. +/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SignedWadMath.sol) +/// @author Modified from Remco Bloemen (https://xn--2-umb.com/22/exp-ln/index.html) + +/// @dev Will not revert on overflow, only use where overflow is not possible. +function toWadUnsafe(uint256 x) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by 1e18. + r := mul(x, 1000000000000000000) + } +} + +/// @dev Takes an integer amount of seconds and converts it to a wad amount of days. +/// @dev Will not revert on overflow, only use where overflow is not possible. +/// @dev Not meant for negative second amounts, it assumes x is positive. +function toDaysWadUnsafe(uint256 x) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by 1e18 and then divide it by 86400. + r := div(mul(x, 1000000000000000000), 86400) + } +} + +/// @dev Takes a wad amount of days and converts it to an integer amount of seconds. +/// @dev Will not revert on overflow, only use where overflow is not possible. +/// @dev Not meant for negative day amounts, it assumes x is positive. +function fromDaysWadUnsafe(int256 x) pure returns (uint256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by 86400 and then divide it by 1e18. + r := div(mul(x, 86400), 1000000000000000000) + } +} + +/// @dev Will not revert on overflow, only use where overflow is not possible. +function unsafeWadMul(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by y and divide by 1e18. + r := sdiv(mul(x, y), 1000000000000000000) + } +} + +/// @dev Will return 0 instead of reverting if y is zero and will +/// not revert on overflow, only use where overflow is not possible. +function unsafeWadDiv(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Multiply x by 1e18 and divide it by y. + r := sdiv(mul(x, 1000000000000000000), y) + } +} + +function wadMul(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Store x * y in r for now. + r := mul(x, y) + + // Equivalent to require(x == 0 || (x * y) / x == y) + if iszero(or(iszero(x), eq(sdiv(r, x), y))) { + revert(0, 0) + } + + // Scale the result down by 1e18. + r := sdiv(r, 1000000000000000000) + } +} + +function wadDiv(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Store x * 1e18 in r for now. + r := mul(x, 1000000000000000000) + + // Equivalent to require(y != 0 && ((x * 1e18) / 1e18 == x)) + if iszero(and(iszero(iszero(y)), eq(sdiv(r, 1000000000000000000), x))) { + revert(0, 0) + } + + // Divide r by y. + r := sdiv(r, y) + } +} + +/// @dev Will not work with negative bases, only use when x is positive. +function wadPow(int256 x, int256 y) pure returns (int256) { + // Equivalent to x to the power of y because x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y) + return wadExp((wadLn(x) * y) / 1e18); // Using ln(x) means x must be greater than 0. +} + +function wadExp(int256 x) pure returns (int256 r) { + unchecked { + // When the result is < 0.5 we return zero. This happens when + // x <= floor(log(0.5e18) * 1e18) ~ -42e18 + if (x <= -42139678854452767551) return 0; + + // When the result is > (2**255 - 1) / 1e18 we can not represent it as an + // int. This happens when x >= floor(log((2**255 - 1) / 1e18) * 1e18) ~ 135. + if (x >= 135305999368893231589) revert("EXP_OVERFLOW"); + + // x is now in the range (-42, 136) * 1e18. Convert to (-42, 136) * 2**96 + // for more intermediate precision and a binary basis. This base conversion + // is a multiplication by 1e18 / 2**96 = 5**18 / 2**78. + x = (x << 78) / 5**18; + + // Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers + // of two such that exp(x) = exp(x') * 2**k, where k is an integer. + // Solving this gives k = round(x / log(2)) and x' = x - k * log(2). + int256 k = ((x << 96) / 54916777467707473351141471128 + 2**95) >> 96; + x = x - k * 54916777467707473351141471128; + + // k is in the range [-61, 195]. + + // Evaluate using a (6, 7)-term rational approximation. + // p is made monic, we'll multiply by a scale factor later. + int256 y = x + 1346386616545796478920950773328; + y = ((y * x) >> 96) + 57155421227552351082224309758442; + int256 p = y + x - 94201549194550492254356042504812; + p = ((p * y) >> 96) + 28719021644029726153956944680412240; + p = p * x + (4385272521454847904659076985693276 << 96); + + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + int256 q = x - 2855989394907223263936484059900; + q = ((q * x) >> 96) + 50020603652535783019961831881945; + q = ((q * x) >> 96) - 533845033583426703283633433725380; + q = ((q * x) >> 96) + 3604857256930695427073651918091429; + q = ((q * x) >> 96) - 14423608567350463180887372962807573; + q = ((q * x) >> 96) + 26449188498355588339934803723976023; + + /// @solidity memory-safe-assembly + assembly { + // Div in assembly because solidity adds a zero check despite the unchecked. + // The q polynomial won't have zeros in the domain as all its roots are complex. + // No scaling is necessary because p is already 2**96 too large. + r := sdiv(p, q) + } + + // r should be in the range (0.09, 0.25) * 2**96. + + // We now need to multiply r by: + // * the scale factor s = ~6.031367120. + // * the 2**k factor from the range reduction. + // * the 1e18 / 2**96 factor for base conversion. + // We do this all at once, with an intermediate result in 2**213 + // basis, so the final right shift is always by a positive amount. + r = int256((uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)); + } +} + +function wadLn(int256 x) pure returns (int256 r) { + unchecked { + require(x > 0, "UNDEFINED"); + + // We want to convert x from 10**18 fixed point to 2**96 fixed point. + // We do this by multiplying by 2**96 / 10**18. But since + // ln(x * C) = ln(x) + ln(C), we can simply do nothing here + // and add ln(2**96 / 10**18) at the end. + + /// @solidity memory-safe-assembly + assembly { + r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) + r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) + r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) + r := or(r, shl(4, lt(0xffff, shr(r, x)))) + r := or(r, shl(3, lt(0xff, shr(r, x)))) + r := or(r, shl(2, lt(0xf, shr(r, x)))) + r := or(r, shl(1, lt(0x3, shr(r, x)))) + r := or(r, lt(0x1, shr(r, x))) + } + + // Reduce range of x to (1, 2) * 2**96 + // ln(2^k * x) = k * ln(2) + ln(x) + int256 k = r - 96; + x <<= uint256(159 - k); + x = int256(uint256(x) >> 159); + + // Evaluate using a (8, 8)-term rational approximation. + // p is made monic, we will multiply by a scale factor later. + int256 p = x + 3273285459638523848632254066296; + p = ((p * x) >> 96) + 24828157081833163892658089445524; + p = ((p * x) >> 96) + 43456485725739037958740375743393; + p = ((p * x) >> 96) - 11111509109440967052023855526967; + p = ((p * x) >> 96) - 45023709667254063763336534515857; + p = ((p * x) >> 96) - 14706773417378608786704636184526; + p = p * x - (795164235651350426258249787498 << 96); + + // We leave p in 2**192 basis so we don't need to scale it back up for the division. + // q is monic by convention. + int256 q = x + 5573035233440673466300451813936; + q = ((q * x) >> 96) + 71694874799317883764090561454958; + q = ((q * x) >> 96) + 283447036172924575727196451306956; + q = ((q * x) >> 96) + 401686690394027663651624208769553; + q = ((q * x) >> 96) + 204048457590392012362485061816622; + q = ((q * x) >> 96) + 31853899698501571402653359427138; + q = ((q * x) >> 96) + 909429971244387300277376558375; + /// @solidity memory-safe-assembly + assembly { + // Div in assembly because solidity adds a zero check despite the unchecked. + // The q polynomial is known not to have zeros in the domain. + // No scaling required because p is already 2**96 too large. + r := sdiv(p, q) + } + + // r is in the range (0, 0.125) * 2**96 + + // Finalization, we need to: + // * multiply by the scale factor s = 5.549… + // * add ln(2**96 / 10**18) + // * add k * ln(2) + // * multiply by 10**18 / 2**96 = 5**18 >> 78 + + // mul s * 5e18 * 2**96, base is now 5**18 * 2**192 + r *= 1677202110996718588342820967067443963516166; + // add ln(2) * k * 5e18 * 2**192 + r += 16597577552685614221487285958193947469193820559219878177908093499208371 * k; + // add ln(2**96 / 10**18) * 5e18 * 2**192 + r += 600920179829731861736702779321621459595472258049074101567377883020018308; + // base conversion: mul 2**18 / 2**192 + r >>= 174; + } +} + +/// @dev Will return 0 instead of reverting if y is zero. +function unsafeDiv(int256 x, int256 y) pure returns (int256 r) { + /// @solidity memory-safe-assembly + assembly { + // Divide x by y. + r := sdiv(x, y) + } +} diff --git a/lib/crytic/package-lock.json b/lib/crytic/package-lock.json new file mode 100644 index 0000000..e8ffd93 --- /dev/null +++ b/lib/crytic/package-lock.json @@ -0,0 +1,6844 @@ +{ + "name": "@crytic/properties", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@crytic/properties", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "@openzeppelin/contracts": "^4.7.3", + "solmate": "^6.6.1" + }, + "devDependencies": { + "hardhat": "^2.9.3" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "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/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "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/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "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/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "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/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "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/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "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/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "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" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "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/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "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/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "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/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "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/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "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/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "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", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "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==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "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==", + "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" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-block/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "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", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-blockchain/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-block": "^4.0.0", + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-ethash/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "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", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-evm/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "dev": true, + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "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==", + "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", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "functional-red-black-tree": "^1.0.1" + } + }, + "node_modules/@nomicfoundation/ethereumjs-statemanager/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-trie/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-common": "^3.0.0", + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "dev": true, + "dependencies": { + "@nomicfoundation/ethereumjs-rlp": "^4.0.0-beta.2", + "ethereum-cryptography": "0.1.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "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", + "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" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@nomicfoundation/ethereumjs-vm/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "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==", + "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" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "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==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@openzeppelin/contracts": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.8.0.tgz", + "integrity": "sha512-AGuwhRRL+NaKx73WKRNzeCxOCOCxpaqF+kp8TJ89QzAipSwZy/NoflkWaL9bywXFRhIzXt8j38sfF7KBKCPWLw==" + }, + "node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/bip32": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", + "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.1.1", + "@noble/secp256k1": "~1.6.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==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "dependencies": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "dependencies": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "dependencies": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "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/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.11.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz", + "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w==", + "dev": true + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true, + "engines": { + "node": ">=0.3.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "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/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "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/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" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bigint-crypto-utils": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.1.7.tgz", + "integrity": "sha512-zpCQpIE2Oy5WIQpjC9iYZf8Uh9QqoS51ZCooAcNvzv1AQ3VWdT52D0ksr1+/faeK8HVIej1bxXcP75YcqH3KPA==", + "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==", + "dev": true, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true + }, + "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/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "node_modules/browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "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/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "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==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "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/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/command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "node_modules/commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "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/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/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/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/ethereum-cryptography": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz", + "integrity": "sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==", + "dev": true, + "dependencies": { + "@noble/hashes": "1.1.2", + "@noble/secp256k1": "1.6.3", + "@scure/bip32": "1.1.0", + "@scure/bip39": "1.1.0" + } + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/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/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-util/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/ethereumjs-util/node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "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": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "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==", + "dev": true + }, + "node_modules/hardhat": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.12.4.tgz", + "integrity": "sha512-rc9S2U/4M+77LxW1Kg7oqMMmjl81tzn5rNFARhbXKUA1am/nhfMJEujOjuKvt+ZGMiZ11PYSe8gyIpB/aRNDgw==", + "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/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.4.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + }, + "bin": { + "hardhat": "internal/cli/cli.js" + }, + "engines": { + "node": "^14.0.0 || ^16.0.0 || ^18.0.0" + }, + "peerDependencies": { + "ts-node": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "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/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "dependencies": { + "fp-ts": "^1.0.0" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "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/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "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": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.9" + } + }, + "node_modules/level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "dependencies": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/level" + } + }, + "node_modules/level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "dependencies": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "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", + "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/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/lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "dependencies": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "dependencies": { + "obliterator": "^2.0.0" + } + }, + "node_modules/mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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==", + "dev": true + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "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==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "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/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==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "dependencies": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "bin": { + "solcjs": "solcjs" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/solc/node_modules/fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "node_modules/solc/node_modules/jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/solc/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/solmate": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/solmate/-/solmate-6.6.1.tgz", + "integrity": "sha512-WHvRXQvGtgR6R9nmkDTz/d+oULMqf/D33rlzQyadTX2SbuTmaW7ToEjGjGtWUVCQwZsZ/JP3vbOEVv7fB50btg==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/undici": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "dev": true, + "dependencies": { + "busboy": "^1.6.0" + }, + "engines": { + "node": ">=12.18" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "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/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true + }, + "@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "dev": true, + "requires": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + } + }, + "@noble/hashes": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", + "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", + "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==", + "dev": true + }, + "@nomicfoundation/ethereumjs-block": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.0.0.tgz", + "integrity": "sha512-bk8uP8VuexLgyIZAHExH1QEovqx0Lzhc9Ntm63nCRKLHXIZkobaFaeCVwTESV7YkPKUk7NiK11s8ryed4CS9yA==", + "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" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "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", + "abstract-level": "^1.0.3", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "level": "^8.0.0", + "lru-cache": "^5.1.1", + "memory-level": "^1.0.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-block": "^4.0.0", + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "abstract-level": "^1.0.3", + "bigint-crypto-utils": "^3.0.23", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "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", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "mcl-wasm": "^0.7.1", + "rustbn.js": "~0.2.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "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==", + "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", + "debug": "^4.3.3", + "ethereum-cryptography": "0.1.3", + "functional-red-black-tree": "^1.0.1" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "ethereum-cryptography": "0.1.3", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-common": "^3.0.0", + "@nomicfoundation/ethereumjs-rlp": "^4.0.0", + "@nomicfoundation/ethereumjs-util": "^8.0.0", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "dev": true, + "requires": { + "@nomicfoundation/ethereumjs-rlp": "^4.0.0-beta.2", + "ethereum-cryptography": "0.1.3" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "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", + "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" + }, + "dependencies": { + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "@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==", + "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": { + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "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==", + "dev": true, + "optional": true + }, + "@openzeppelin/contracts": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.8.0.tgz", + "integrity": "sha512-AGuwhRRL+NaKx73WKRNzeCxOCOCxpaqF+kp8TJ89QzAipSwZy/NoflkWaL9bywXFRhIzXt8j38sfF7KBKCPWLw==" + }, + "@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "dev": true + }, + "@scure/bip32": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", + "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", + "dev": true, + "requires": { + "@noble/hashes": "~1.1.1", + "@noble/secp256k1": "~1.6.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==", + "dev": true, + "requires": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "@sentry/core": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz", + "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/hub": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz", + "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/minimal": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz", + "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/node": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-5.30.0.tgz", + "integrity": "sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg==", + "dev": true, + "requires": { + "@sentry/core": "5.30.0", + "@sentry/hub": "5.30.0", + "@sentry/tracing": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + } + }, + "@sentry/tracing": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-5.30.0.tgz", + "integrity": "sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw==", + "dev": true, + "requires": { + "@sentry/hub": "5.30.0", + "@sentry/minimal": "5.30.0", + "@sentry/types": "5.30.0", + "@sentry/utils": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@sentry/types": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz", + "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw==", + "dev": true + }, + "@sentry/utils": { + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz", + "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==", + "dev": true, + "requires": { + "@sentry/types": "5.30.0", + "tslib": "^1.9.3" + } + }, + "@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/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "@types/node": { + "version": "18.11.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.13.tgz", + "integrity": "sha512-IASpMGVcWpUsx5xBOrxMj7Bl8lqfuTY7FKAnPmu5cHkfQVWF8GulWS1jbRqA934qZL35xh5xN/+Xe/i26Bod4w==", + "dev": true + }, + "@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "abstract-level": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/abstract-level/-/abstract-level-1.0.3.tgz", + "integrity": "sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "catering": "^2.1.0", + "is-buffer": "^2.0.5", + "level-supports": "^4.0.0", + "level-transcoder": "^1.0.1", + "module-error": "^1.0.1", + "queue-microtask": "^1.2.3" + } + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "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-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "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==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "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 + }, + "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" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bigint-crypto-utils": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/bigint-crypto-utils/-/bigint-crypto-utils-3.1.7.tgz", + "integrity": "sha512-zpCQpIE2Oy5WIQpjC9iYZf8Uh9QqoS51ZCooAcNvzv1AQ3VWdT52D0ksr1+/faeK8HVIej1bxXcP75YcqH3KPA==", + "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==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "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 + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, + "browser-level": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-level/-/browser-level-1.0.1.tgz", + "integrity": "sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ==", + "dev": true, + "requires": { + "abstract-level": "^1.0.2", + "catering": "^2.1.1", + "module-error": "^1.0.2", + "run-parallel-limit": "^1.1.0" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, + "requires": { + "base-x": "^3.0.2" + } + }, + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dev": true, + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "catering": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.1.tgz", + "integrity": "sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w==", + "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.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "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 + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "classic-level": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/classic-level/-/classic-level-1.2.0.tgz", + "integrity": "sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg==", + "dev": true, + "requires": { + "abstract-level": "^1.0.2", + "catering": "^2.1.0", + "module-error": "^1.0.1", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.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 + }, + "command-exists": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", + "dev": true + }, + "commander": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "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 + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "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==", + "dev": true, + "requires": { + "@noble/hashes": "1.1.2", + "@noble/secp256k1": "1.6.3", + "@scure/bip32": "1.1.0", + "@scure/bip39": "1.1.0" + } + }, + "ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "dev": true, + "requires": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + }, + "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 + } + } + }, + "ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "dev": true, + "requires": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + }, + "dependencies": { + "@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "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 + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dev": true, + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + } + } + }, + "ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + } + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "fp-ts": { + "version": "1.19.3", + "resolved": "https://registry.npmjs.org/fp-ts/-/fp-ts-1.19.3.tgz", + "integrity": "sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg==", + "dev": true + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "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" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "hardhat": { + "version": "2.12.4", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.12.4.tgz", + "integrity": "sha512-rc9S2U/4M+77LxW1Kg7oqMMmjl81tzn5rNFARhbXKUA1am/nhfMJEujOjuKvt+ZGMiZ11PYSe8gyIpB/aRNDgw==", + "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/solidity-analyzer": "^0.1.0", + "@sentry/node": "^5.18.1", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "^5.1.0", + "abort-controller": "^3.0.0", + "adm-zip": "^0.4.16", + "aggregate-error": "^3.0.0", + "ansi-escapes": "^4.3.0", + "chalk": "^2.4.2", + "chokidar": "^3.4.0", + "ci-info": "^2.0.0", + "debug": "^4.1.1", + "enquirer": "^2.3.0", + "env-paths": "^2.2.0", + "ethereum-cryptography": "^1.0.3", + "ethereumjs-abi": "^0.6.8", + "find-up": "^2.1.0", + "fp-ts": "1.19.3", + "fs-extra": "^7.0.1", + "glob": "7.2.0", + "immutable": "^4.0.0-rc.12", + "io-ts": "1.10.4", + "keccak": "^3.0.2", + "lodash": "^4.17.11", + "mnemonist": "^0.38.0", + "mocha": "^10.0.0", + "p-map": "^4.0.0", + "qs": "^6.7.0", + "raw-body": "^2.4.1", + "resolve": "1.17.0", + "semver": "^6.3.0", + "solc": "0.7.3", + "source-map-support": "^0.5.13", + "stacktrace-parser": "^0.1.10", + "tsort": "0.0.1", + "undici": "^5.4.0", + "uuid": "^8.3.2", + "ws": "^7.4.6" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "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 + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "io-ts": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/io-ts/-/io-ts-1.10.4.tgz", + "integrity": "sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g==", + "dev": true, + "requires": { + "fp-ts": "^1.0.0" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "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 + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "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 + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "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": { + "argparse": "^2.0.1" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "dev": true, + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + } + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.9" + } + }, + "level": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/level/-/level-8.0.0.tgz", + "integrity": "sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ==", + "dev": true, + "requires": { + "browser-level": "^1.0.1", + "classic-level": "^1.2.0" + } + }, + "level-supports": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-4.0.1.tgz", + "integrity": "sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA==", + "dev": true + }, + "level-transcoder": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/level-transcoder/-/level-transcoder-1.0.1.tgz", + "integrity": "sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "module-error": "^1.0.1" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "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", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "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" + } + } + } + }, + "lru_map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "mcl-wasm": { + "version": "0.7.9", + "resolved": "https://registry.npmjs.org/mcl-wasm/-/mcl-wasm-0.7.9.tgz", + "integrity": "sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ==", + "dev": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "memory-level": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/memory-level/-/memory-level-1.0.0.tgz", + "integrity": "sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og==", + "dev": true, + "requires": { + "abstract-level": "^1.0.0", + "functional-red-black-tree": "^1.0.1", + "module-error": "^1.0.1" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mnemonist": { + "version": "0.38.5", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.5.tgz", + "integrity": "sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg==", + "dev": true, + "requires": { + "obliterator": "^2.0.0" + } + }, + "mocha": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", + "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.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", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "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 + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "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", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "module-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/module-error/-/module-error-1.0.2.tgz", + "integrity": "sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "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==", + "dev": true + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "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==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "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==", + "dev": true + }, + "obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "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" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "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" + } + }, + "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==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "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 + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, + "requires": { + "bn.js": "^5.2.0" + } + }, + "run-parallel-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz", + "integrity": "sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rustbn.js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/rustbn.js/-/rustbn.js-0.2.0.tgz", + "integrity": "sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, + "secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "requires": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "solc": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.3.tgz", + "integrity": "sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA==", + "dev": true, + "requires": { + "command-exists": "^1.2.8", + "commander": "3.0.2", + "follow-redirects": "^1.12.1", + "fs-extra": "^0.30.0", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "require-from-string": "^2.0.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "dependencies": { + "fs-extra": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", + "integrity": "sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "solmate": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/solmate/-/solmate-6.6.1.tgz", + "integrity": "sha512-WHvRXQvGtgR6R9nmkDTz/d+oULMqf/D33rlzQyadTX2SbuTmaW7ToEjGjGtWUVCQwZsZ/JP3vbOEVv7fB50btg==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "stacktrace-parser": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz", + "integrity": "sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==", + "dev": true, + "requires": { + "type-fest": "^0.7.1" + }, + "dependencies": { + "type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "string-width": { + "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": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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": { + "ansi-regex": "^5.0.1" + } + }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "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" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsort": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", + "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==", + "dev": true + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "dev": true + }, + "tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "undici": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.14.0.tgz", + "integrity": "sha512-yJlHYw6yXPPsuOH0x2Ib1Km61vu4hLiRRQoafs+WUgX1vO64vgnxiCEN9dpIrhZyHFsai3F0AEj4P9zy19enEQ==", + "dev": true, + "requires": { + "busboy": "^1.6.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.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" + } + }, + "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 + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "dev": true, + "requires": {} + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "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 + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/lib/crytic/package.json b/lib/crytic/package.json new file mode 100644 index 0000000..85a8626 --- /dev/null +++ b/lib/crytic/package.json @@ -0,0 +1,27 @@ +{ + "name": "@crytic/properties", + "version": "0.0.1", + "description": "Pre-made invariants for fuzz testing smart-contracts", + "main": "index.js", + "scripts": { + "compile": "hardhat compile", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/crytic/properties.git" + }, + "author": "Trail of Bits", + "license": "MIT", + "bugs": { + "url": "https://github.com/crytic/properties/issues" + }, + "homepage": "https://github.com/crytic/properties#readme", + "dependencies": { + "@openzeppelin/contracts": "^4.7.3", + "solmate": "^6.6.1" + }, + "devDependencies": { + "hardhat": "^2.9.3" + } +} diff --git a/lib/erc4626-tests/ERC4626.prop.sol b/lib/erc4626-tests/ERC4626.prop.sol new file mode 100644 index 0000000..c34512b --- /dev/null +++ b/lib/erc4626-tests/ERC4626.prop.sol @@ -0,0 +1,404 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "forge-std/Test.sol"; + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC20} from "forge-std/interfaces/IERC20.sol"; +interface IERC20 { + event Transfer(address indexed from, address indexed to, uint value); + event Approval(address indexed owner, address indexed spender, uint value); + function totalSupply() external view returns (uint); + function balanceOf(address account) external view returns (uint); + function transfer(address to, uint amount) external returns (bool); + function allowance(address owner, address spender) external view returns (uint); + function approve(address spender, uint amount) external returns (bool); + function transferFrom(address from, address to, uint amount) external returns (bool); +} + +// TODO: use interface provided by forge-std v1.0.0 or later +// import {IERC4626} from "forge-std/interfaces/IERC4626.sol"; +interface IERC4626 is IERC20 { + event Deposit(address indexed caller, address indexed owner, uint assets, uint shares); + event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint assets, uint shares); + function asset() external view returns (address assetTokenAddress); + function totalAssets() external view returns (uint totalManagedAssets); + function convertToShares(uint assets) external view returns (uint shares); + function convertToAssets(uint shares) external view returns (uint assets); + function maxDeposit(address receiver) external view returns (uint maxAssets); + function previewDeposit(uint assets) external view returns (uint shares); + function deposit(uint assets, address receiver) external returns (uint shares); + function maxMint(address receiver) external view returns (uint maxShares); + function previewMint(uint shares) external view returns (uint assets); + function mint(uint shares, address receiver) external returns (uint assets); + function maxWithdraw(address owner) external view returns (uint maxAssets); + function previewWithdraw(uint assets) external view returns (uint shares); + function withdraw(uint assets, address receiver, address owner) external returns (uint shares); + function maxRedeem(address owner) external view returns (uint maxShares); + function previewRedeem(uint shares) external view returns (uint assets); + function redeem(uint shares, address receiver, address owner) external returns (uint assets); +} + +abstract contract ERC4626Prop is Test { + uint internal _delta_; + + address internal _underlying_; + address internal _vault_; + + bool internal _vaultMayBeEmpty; + bool internal _unlimitedAmount; + + // + // asset + // + + // asset + // "MUST NOT revert." + function prop_asset(address caller) public { + vm.prank(caller); IERC4626(_vault_).asset(); + } + + // totalAssets + // "MUST NOT revert." + function prop_totalAssets(address caller) public { + vm.prank(caller); IERC4626(_vault_).totalAssets(); + } + + // + // convert + // + + // convertToShares + // "MUST NOT show any variations depending on the caller." + function prop_convertToShares(address caller1, address caller2, uint assets) public { + vm.prank(caller1); uint res1 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToShares(assets); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // convertToAssets + // "MUST NOT show any variations depending on the caller." + function prop_convertToAssets(address caller1, address caller2, uint shares) public { + vm.prank(caller1); uint res1 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + vm.prank(caller2); uint res2 = vault_convertToAssets(shares); // "MAY revert due to integer overflow caused by an unreasonably large input." + assertEq(res1, res2); + } + + // + // deposit + // + + // maxDeposit + // "MUST NOT revert." + function prop_maxDeposit(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxDeposit(receiver); + } + + // previewDeposit + // "MUST return as close to and no more than the exact amount of Vault + // shares that would be minted in a deposit call in the same transaction. + // I.e. deposit should return the same or more shares as previewDeposit if + // called in the same transaction." + function prop_previewDeposit(address caller, address receiver, address other, uint assets) public { + vm.prank(other); uint sharesPreview = vault_previewDeposit(assets); // "MAY revert due to other conditions that would also cause deposit to revert." + vm.prank(caller); uint sharesActual = vault_deposit(assets, receiver); + assertApproxGeAbs(sharesActual, sharesPreview, _delta_); + } + + // deposit + function prop_deposit(address caller, address receiver, uint assets) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint shares = vault_deposit(assets, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // mint + // + + // maxMint + // "MUST NOT revert." + function prop_maxMint(address caller, address receiver) public { + vm.prank(caller); IERC4626(_vault_).maxMint(receiver); + } + + // previewMint + // "MUST return as close to and no fewer than the exact amount of assets + // that would be deposited in a mint call in the same transaction. I.e. mint + // should return the same or fewer assets as previewMint if called in the + // same transaction." + function prop_previewMint(address caller, address receiver, address other, uint shares) public { + vm.prank(other); uint assetsPreview = vault_previewMint(shares); + vm.prank(caller); uint assetsActual = vault_mint(shares, receiver); + assertApproxLeAbs(assetsActual, assetsPreview, _delta_); + } + + // mint + function prop_mint(address caller, address receiver, uint shares) public { + uint oldCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint oldReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint oldAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + vm.prank(caller); uint assets = vault_mint(shares, receiver); + + uint newCallerAsset = IERC20(_underlying_).balanceOf(caller); + uint newReceiverShare = IERC20(_vault_).balanceOf(receiver); + uint newAllowance = IERC20(_underlying_).allowance(caller, _vault_); + + assertApproxEqAbs(newCallerAsset, oldCallerAsset - assets, _delta_, "asset"); // NOTE: this may fail if the caller is a contract in which the asset is stored + assertApproxEqAbs(newReceiverShare, oldReceiverShare + shares, _delta_, "share"); + if (oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - assets, _delta_, "allowance"); + } + + // + // withdraw + // + + // maxWithdraw + // "MUST NOT revert." + // NOTE: some implementations failed due to arithmetic overflow + function prop_maxWithdraw(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxWithdraw(owner); + } + + // previewWithdraw + // "MUST return as close to and no fewer than the exact amount of Vault + // shares that would be burned in a withdraw call in the same transaction. + // I.e. withdraw should return the same or fewer shares as previewWithdraw + // if called in the same transaction." + function prop_previewWithdraw(address caller, address receiver, address owner, address other, uint assets) public { + vm.prank(other); uint preview = vault_previewWithdraw(assets); + vm.prank(caller); uint actual = vault_withdraw(assets, receiver, owner); + assertApproxLeAbs(actual, preview, _delta_); + } + + // withdraw + function prop_withdraw(address caller, address receiver, address owner, uint assets) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint shares = vault_withdraw(assets, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // redeem + // + + // maxRedeem + // "MUST NOT revert." + function prop_maxRedeem(address caller, address owner) public { + vm.prank(caller); IERC4626(_vault_).maxRedeem(owner); + } + + // previewRedeem + // "MUST return as close to and no more than the exact amount of assets that + // would be withdrawn in a redeem call in the same transaction. I.e. redeem + // should return the same or more assets as previewRedeem if called in the + // same transaction." + function prop_previewRedeem(address caller, address receiver, address owner, address other, uint shares) public { + vm.prank(other); uint preview = vault_previewRedeem(shares); + vm.prank(caller); uint actual = vault_redeem(shares, receiver, owner); + assertApproxGeAbs(actual, preview, _delta_); + } + + // redeem + function prop_redeem(address caller, address receiver, address owner, uint shares) public { + uint oldReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint oldOwnerShare = IERC20(_vault_).balanceOf(owner); + uint oldAllowance = IERC20(_vault_).allowance(owner, caller); + + vm.prank(caller); uint assets = vault_redeem(shares, receiver, owner); + + uint newReceiverAsset = IERC20(_underlying_).balanceOf(receiver); + uint newOwnerShare = IERC20(_vault_).balanceOf(owner); + uint newAllowance = IERC20(_vault_).allowance(owner, caller); + + assertApproxEqAbs(newOwnerShare, oldOwnerShare - shares, _delta_, "share"); + assertApproxEqAbs(newReceiverAsset, oldReceiverAsset + assets, _delta_, "asset"); // NOTE: this may fail if the receiver is a contract in which the asset is stored + if (caller != owner && oldAllowance != type(uint).max) assertApproxEqAbs(newAllowance, oldAllowance - shares, _delta_, "allowance"); + + assertTrue(caller == owner || oldAllowance != 0 || (shares == 0 && assets == 0), "access control"); + } + + // + // round trip properties + // + + // redeem(deposit(a)) <= a + function prop_RT_deposit_redeem(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares = vault_deposit(assets, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets, _delta_); + } + + // s = deposit(a) + // s' = withdraw(a) + // s' >= s + function prop_RT_deposit_withdraw(address caller, uint assets) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares1 = vault_deposit(assets, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares1, _delta_); + } + + // deposit(redeem(s)) <= s + function prop_RT_redeem_deposit(address caller, uint shares) public { + vm.prank(caller); uint assets = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares, _delta_); + } + + // a = redeem(s) + // a' = mint(s) + // a' >= a + function prop_RT_redeem_mint(address caller, uint shares) public { + vm.prank(caller); uint assets1 = vault_redeem(shares, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets1, _delta_); + } + + // withdraw(mint(s)) >= s + function prop_RT_mint_withdraw(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets = vault_mint(shares, caller); + vm.prank(caller); uint shares2 = vault_withdraw(assets, caller, caller); + assertApproxGeAbs(shares2, shares, _delta_); + } + + // a = mint(s) + // a' = redeem(s) + // a' <= a + function prop_RT_mint_redeem(address caller, uint shares) public { + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets1 = vault_mint(shares, caller); + vm.prank(caller); uint assets2 = vault_redeem(shares, caller, caller); + assertApproxLeAbs(assets2, assets1, _delta_); + } + + // mint(withdraw(a)) >= a + function prop_RT_withdraw_mint(address caller, uint assets) public { + vm.prank(caller); uint shares = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint assets2 = vault_mint(shares, caller); + assertApproxGeAbs(assets2, assets, _delta_); + } + + // s = withdraw(a) + // s' = deposit(a) + // s' <= s + function prop_RT_withdraw_deposit(address caller, uint assets) public { + vm.prank(caller); uint shares1 = vault_withdraw(assets, caller, caller); + if (!_vaultMayBeEmpty) vm.assume(IERC20(_vault_).totalSupply() > 0); + vm.prank(caller); uint shares2 = vault_deposit(assets, caller); + assertApproxLeAbs(shares2, shares1, _delta_); + } + + // + // utils + // + + function vault_convertToShares(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToShares.selector, assets)); + } + function vault_convertToAssets(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.convertToAssets.selector, shares)); + } + + function vault_maxDeposit(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxDeposit.selector, receiver)); + } + function vault_maxMint(address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxMint.selector, receiver)); + } + function vault_maxWithdraw(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxWithdraw.selector, owner)); + } + function vault_maxRedeem(address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.maxRedeem.selector, owner)); + } + + function vault_previewDeposit(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewDeposit.selector, assets)); + } + function vault_previewMint(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewMint.selector, shares)); + } + function vault_previewWithdraw(uint assets) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewWithdraw.selector, assets)); + } + function vault_previewRedeem(uint shares) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.previewRedeem.selector, shares)); + } + + function vault_deposit(uint assets, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.deposit.selector, assets, receiver)); + } + function vault_mint(uint shares, address receiver) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.mint.selector, shares, receiver)); + } + function vault_withdraw(uint assets, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.withdraw.selector, assets, receiver, owner)); + } + function vault_redeem(uint shares, address receiver, address owner) internal returns (uint) { + return _call_vault(abi.encodeWithSelector(IERC4626.redeem.selector, shares, receiver, owner)); + } + + function _call_vault(bytes memory data) internal returns (uint) { + (bool success, bytes memory retdata) = _vault_.call(data); + if (success) return abi.decode(retdata, (uint)); + vm.assume(false); // if reverted, discard the current fuzz inputs, and let the fuzzer to start a new fuzz run + return 0; // silence warning + } + + function assertApproxGeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a >= b)) { + uint dt = b - a; + if (dt > maxDelta) { + emit log ("Error: a >=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } + + function assertApproxLeAbs(uint a, uint b, uint maxDelta) internal { + if (!(a <= b)) { + uint dt = a - b; + if (dt > maxDelta) { + emit log ("Error: a <=~ b not satisfied [uint]"); + emit log_named_uint (" Value a", a); + emit log_named_uint (" Value b", b); + emit log_named_uint (" Max Delta", maxDelta); + emit log_named_uint (" Delta", dt); + fail(); + } + } + } +} diff --git a/lib/erc4626-tests/ERC4626.test.sol b/lib/erc4626-tests/ERC4626.test.sol new file mode 100644 index 0000000..6254a05 --- /dev/null +++ b/lib/erc4626-tests/ERC4626.test.sol @@ -0,0 +1,349 @@ +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "./ERC4626.prop.sol"; + +interface IMockERC20 is IERC20 { + function mint(address to, uint value) external; + function burn(address from, uint value) external; +} + +abstract contract ERC4626Test is ERC4626Prop { + function setUp() public virtual; + + uint constant N = 4; + + struct Init { + address[N] user; + uint[N] share; + uint[N] asset; + int yield; + } + + // setup initial vault state as follows: + // + // totalAssets == sum(init.share) + init.yield + // totalShares == sum(init.share) + // + // init.user[i]'s assets == init.asset[i] + // init.user[i]'s shares == init.share[i] + function setUpVault(Init memory init) public virtual { + // setup initial shares and assets for individual users + for (uint i = 0; i < N; i++) { + address user = init.user[i]; + vm.assume(_isEOA(user)); + // shares + uint shares = init.share[i]; + try IMockERC20(_underlying_).mint(user, shares) {} catch { vm.assume(false); } + _approve(_underlying_, user, _vault_, shares); + vm.prank(user); try IERC4626(_vault_).deposit(shares, user) {} catch { vm.assume(false); } + // assets + uint assets = init.asset[i]; + try IMockERC20(_underlying_).mint(user, assets) {} catch { vm.assume(false); } + } + + // setup initial yield for vault + setUpYield(init); + } + + // setup initial yield + function setUpYield(Init memory init) public virtual { + if (init.yield >= 0) { // gain + uint gain = uint(init.yield); + try IMockERC20(_underlying_).mint(_vault_, gain) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } else { // loss + vm.assume(init.yield > type(int).min); // avoid overflow in conversion + uint loss = uint(-1 * init.yield); + try IMockERC20(_underlying_).burn(_vault_, loss) {} catch { vm.assume(false); } // this can be replaced by calling yield generating functions if provided by the vault + } + } + + // + // asset + // + + function test_asset(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_asset(caller); + } + + function test_totalAssets(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + prop_totalAssets(caller); + } + + // + // convert + // + + function test_convertToShares(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToShares(caller1, caller2, assets); + } + + function test_convertToAssets(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller1 = init.user[0]; + address caller2 = init.user[1]; + prop_convertToAssets(caller1, caller2, shares); + } + + // + // deposit + // + + function test_maxDeposit(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxDeposit(caller, receiver); + } + + function test_previewDeposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewDeposit(caller, receiver, other, assets); + } + + function test_deposit(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_deposit(caller, receiver, assets); + } + + // + // mint + // + + function test_maxMint(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + prop_maxMint(caller, receiver); + } + + function test_previewMint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address other = init.user[2]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_previewMint(caller, receiver, other, shares); + } + + function test_mint(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, allowance); + prop_mint(caller, receiver, shares); + } + + // + // withdraw + // + + function test_maxWithdraw(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxWithdraw(caller, owner); + } + + function test_previewWithdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewWithdraw(caller, receiver, owner, other, assets); + } + + function test_withdraw(Init memory init, uint assets, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + _approve(_vault_, owner, caller, allowance); + prop_withdraw(caller, receiver, owner, assets); + } + + function testFail_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + assets = bound(assets, 0, _max_withdraw(owner)); + vm.assume(caller != owner); + vm.assume(assets > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); uint shares = IERC4626(_vault_).withdraw(assets, receiver, owner); + assertGt(shares, 0); // this assert is expected to fail + } + + // + // redeem + // + + function test_maxRedeem(Init memory init) public virtual { + setUpVault(init); + address caller = init.user[0]; + address owner = init.user[1]; + prop_maxRedeem(caller, owner); + } + + function test_previewRedeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + address other = init.user[3]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, type(uint).max); + prop_previewRedeem(caller, receiver, owner, other, shares); + } + + function test_redeem(Init memory init, uint shares, uint allowance) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + _approve(_vault_, owner, caller, allowance); + prop_redeem(caller, receiver, owner, shares); + } + + function testFail_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + address receiver = init.user[1]; + address owner = init.user[2]; + shares = bound(shares, 0, _max_redeem(owner)); + vm.assume(caller != owner); + vm.assume(shares > 0); + _approve(_vault_, owner, caller, 0); + vm.prank(caller); IERC4626(_vault_).redeem(shares, receiver, owner); + } + + // + // round trip tests + // + + function test_RT_deposit_redeem(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_redeem(caller, assets); + } + + function test_RT_deposit_withdraw(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_deposit(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_deposit_withdraw(caller, assets); + } + + function test_RT_redeem_deposit(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_deposit(caller, shares); + } + + function test_RT_redeem_mint(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_redeem(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_redeem_mint(caller, shares); + } + + function test_RT_mint_withdraw(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_withdraw(caller, shares); + } + + function test_RT_mint_redeem(Init memory init, uint shares) public virtual { + setUpVault(init); + address caller = init.user[0]; + shares = bound(shares, 0, _max_mint(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_mint_redeem(caller, shares); + } + + function test_RT_withdraw_mint(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_mint(caller, assets); + } + + function test_RT_withdraw_deposit(Init memory init, uint assets) public virtual { + setUpVault(init); + address caller = init.user[0]; + assets = bound(assets, 0, _max_withdraw(caller)); + _approve(_underlying_, caller, _vault_, type(uint).max); + prop_RT_withdraw_deposit(caller, assets); + } + + // + // utils + // + + function _isContract(address account) internal view returns (bool) { return account.code.length > 0; } + function _isEOA (address account) internal view returns (bool) { return account.code.length == 0; } + + function _approve(address token, address owner, address spender, uint amount) internal { + vm.prank(owner); _safeApprove(token, spender, 0); + vm.prank(owner); _safeApprove(token, spender, amount); + } + + function _safeApprove(address token, address spender, uint amount) internal { + (bool success, bytes memory retdata) = token.call(abi.encodeWithSelector(IERC20.approve.selector, spender, amount)); + vm.assume(success); + if (retdata.length > 0) vm.assume(abi.decode(retdata, (bool))); + } + + function _max_deposit(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_underlying_).balanceOf(from); + } + + function _max_mint(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToShares(IERC20(_underlying_).balanceOf(from)); + } + + function _max_withdraw(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return vault_convertToAssets(IERC20(_vault_).balanceOf(from)); // may be different from maxWithdraw(from) + } + + function _max_redeem(address from) internal virtual returns (uint) { + if (_unlimitedAmount) return type(uint).max; + return IERC20(_vault_).balanceOf(from); // may be different from maxRedeem(from) + } +} diff --git a/lib/erc4626-tests/LICENSE b/lib/erc4626-tests/LICENSE new file mode 100644 index 0000000..0ad25db --- /dev/null +++ b/lib/erc4626-tests/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/lib/erc4626-tests/README.md b/lib/erc4626-tests/README.md new file mode 100644 index 0000000..651e443 --- /dev/null +++ b/lib/erc4626-tests/README.md @@ -0,0 +1,116 @@ +# ERC4626 Property Tests + +Foundry (dapptools-style) property-based tests for [ERC4626] standard conformance. + +[ERC4626]: + +You can read our post on "_[Generalized property tests for ERC4626 vaults][post]_." + +[post]: + +## Overview + +#### What is it? +- Test suites for checking if the given ERC4626 implementation satisfies the **standard requirements**. +- Dapptools-style **property-based tests** for fuzzing or symbolic execution testing. +- Tests that are **independent** from implementation details, thus applicable for any ERC4626 vaults. + +#### What isn’t it? +- It does NOT test implementation-specific details, e.g., how to generate and distribute yields, how to compute the share price, etc. + +#### Testing properties: + +- **Round-trip properties**: no one can make a free profit by depositing and immediately withdrawing back and forth. + +- **Functional correctness**: the `deposit()`, `mint()`, `withdraw()`, and `redeem()` functions update the balance and allowance properly. + +- The `preview{Deposit,Redeem}()` functions **MUST NOT over-estimate** the exact amount.[^1] + +[^1]: That is, the `deposit()` and `redeem()` functions “MUST return the same or more amounts as their preview function if called in the same transaction.” + +- The `preview{Mint,Withdraw}()` functions **MUST NOT under-estimate** the exact amount.[^2] + +[^2]: That is, the `mint()` and `withdraw()` functions “MUST return the same or fewer amounts as their preview function if called in the same transaction.” + +- The `convertTo{Shares,Assets}` functions “**MUST NOT show any variations** depending on the caller.” + +- The `asset()`, `totalAssets()`, and `max{Deposit,Mint,Withdraw,Redeem}()` functions “**MUST NOT revert**.” + +## Usage + +**Step 0**: Install [foundry] and add [forge-std] in your vault repo: +```bash +$ curl -L https://foundry.paradigm.xyz | bash + +$ cd /path/to/your-erc4626-vault +$ forge install foundry-rs/forge-std +``` + +[foundry]: +[forge-std]: + +**Step 1**: Add this [erc4626-tests] as a dependency to your vault: +```bash +$ cd /path/to/your-erc4626-vault +$ forge install a16z/erc4626-tests +``` + +[erc4626-tests]: + +**Step 2**: Extend the abstract test contract [`ERC4626Test`](ERC4626.test.sol) with your own custom vault setup method, for example: + +```solidity +// SPDX-License-Identifier: AGPL-3.0 +pragma solidity >=0.8.0 <0.9.0; + +import "erc4626-tests/ERC4626.test.sol"; + +import { ERC20Mock } from "/path/to/mocks/ERC20Mock.sol"; +import { ERC4626Mock } from "/path/to/mocks/ERC4626Mock.sol"; + +contract ERC4626StdTest is ERC4626Test { + function setUp() public override { + _underlying_ = address(new ERC20Mock("Mock ERC20", "MERC20", 18)); + _vault_ = address(new ERC4626Mock(ERC20Mock(__underlying__), "Mock ERC4626", "MERC4626")); + _delta_ = 0; + _vaultMayBeEmpty = false; + _unlimitedAmount = false; + } +} +``` + +Specifically, set the state variables as follows: +- `_vault_`: the address of your ERC4626 vault. +- `_underlying_`: the address of the underlying asset of your vault. Note that the default `setupVault()` and `setupYield()` methods of `ERC4626Test` assume that it implements `mint(address to, uint value)` and `burn(address from, uint value)`. You can override the setup methods with your own if such `mint()` and `burn()` are not implemented. +- `_delta_`: the maximum approximation error size to be passed to [`assertApproxEqAbs()`]. It must be given as an absolute value (not a percentage) in the smallest unit (e.g., Wei or Satoshi). Note that all the tests are expected to pass with `__delta__ == 0` as long as your vault follows the [preferred rounding direction] as specified in the standard. If your vault doesn't follow the preferred rounding direction, you can set `__delta__` to a reasonable size of rounding errors where the adversarial profit of exploiting such rounding errors stays sufficiently small compared to the gas cost. (You can read our [post] for more about the adversarial profit.) +- `_vaultMayBeEmpty`: when set to false, fuzz inputs that empties the vault are ignored. +- `_unlimitedAmount`: when set to false, fuzz inputs are restricted to the currently available amount from the caller. Limiting the amount can speed up fuzzing, but may miss some edge cases. + +[`assertApproxEqAbs()`]: + +[preferred rounding direction]: + +**Step 3**: Run `forge test` + +``` +$ forge test +``` + +## Examples + +Below are examples of adding these property tests to existing ERC4626 vaults: +- [OpenZeppelin ERC4626] [[diff](https://github.com/daejunpark/openzeppelin-contracts/pull/1/files)] +- [Solmate ERC4626] [[diff](https://github.com/daejunpark/solmate/pull/1/files)] +- [Revenue Distribution Token] [[diff](https://github.com/daejunpark/revenue-distribution-token/pull/1/files)] +- [Yield Daddy ERC4626 wrappers] [[diff](https://github.com/daejunpark/yield-daddy/pull/1/files)][^bug] + +[OpenZeppelin ERC4626]: +[Solmate ERC4626]: +[Revenue Distribution Token]: +[Yield Daddy ERC4626 wrappers]: + +[^bug]: Our property tests indeed revealed an [issue](https://github.com/timeless-fi/yield-daddy/issues/7) in their eToken testing mock contract. The tests passed after it is [fixed](https://github.com/daejunpark/yield-daddy/commit/721cf4bd766805fd409455434aa5fd1a9b2df25c). + +## Disclaimer + +_These smart contracts are being provided as is. No guarantee, representation or warranty is being made, express or implied, as to the safety or correctness of the user interface or the smart contracts. They have not been audited and as such there can be no assurance they will work as intended, and users may experience delays, failures, errors, omissions or loss of transmitted information. THE SMART CONTRACTS CONTAINED HEREIN ARE FURNISHED AS IS, WHERE IS, WITH ALL FAULTS AND WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF MERCHANTABILITY, NON-INFRINGEMENT OR FITNESS FOR ANY PARTICULAR PURPOSE. Further, use of any of these smart contracts may be restricted or prohibited under applicable law, including securities laws, and it is therefore strongly advised for you to contact a reputable attorney in any jurisdiction where these smart contracts may be accessible for any questions or concerns with respect thereto. Further, no information provided in this repo should be construed as investment advice or legal advice for any particular facts or circumstances, and is not meant to replace competent counsel. a16z is not liable for any use of the foregoing, and users should proceed with caution and use at their own risk. See a16z.com/disclosures for more info._ diff --git a/lib/forge-std/.github/workflows/ci.yml b/lib/forge-std/.github/workflows/ci.yml new file mode 100644 index 0000000..cb241ae --- /dev/null +++ b/lib/forge-std/.github/workflows/ci.yml @@ -0,0 +1,134 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + # Backwards compatibility checks: + # - the oldest and newest version of each supported minor version + # - versions with specific issues + - name: Check compatibility with latest + if: always() + run: | + output=$(forge build --skip test) + + if echo "$output" | grep -q "Warning"; then + echo "$output" + exit 1 + fi + + - name: Check compatibility with 0.8.0 + if: always() + run: | + output=$(forge build --skip test --use solc:0.8.0) + + if echo "$output" | grep -q "Warning"; then + echo "$output" + exit 1 + fi + + - name: Check compatibility with 0.7.6 + if: always() + run: | + output=$(forge build --skip test --use solc:0.7.6) + + if echo "$output" | grep -q "Warning"; then + echo "$output" + exit 1 + fi + + - name: Check compatibility with 0.7.0 + if: always() + run: | + output=$(forge build --skip test --use solc:0.7.0) + + if echo "$output" | grep -q "Warning"; then + echo "$output" + exit 1 + fi + + - name: Check compatibility with 0.6.12 + if: always() + run: | + output=$(forge build --skip test --use solc:0.6.12) + + if echo "$output" | grep -q "Warning"; then + echo "$output" + exit 1 + fi + + - name: Check compatibility with 0.6.2 + if: always() + run: | + output=$(forge build --skip test --use solc:0.6.2) + + if echo "$output" | grep -q "Warning"; then + echo "$output" + exit 1 + fi + + # via-ir compilation time checks. + - name: Measure compilation time of Test with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTest.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of TestBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationTestBase.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of Script with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScript.sol --use solc:0.8.17 --via-ir + + - name: Measure compilation time of ScriptBase with 0.8.17 --via-ir + if: always() + run: forge build --skip test --contracts test/compilation/CompilationScriptBase.sol --use solc:0.8.17 --via-ir + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Run tests + run: forge test -vvv + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Print forge version + run: forge --version + + - name: Check formatting + run: forge fmt --check diff --git a/lib/forge-std/.github/workflows/sync.yml b/lib/forge-std/.github/workflows/sync.yml new file mode 100644 index 0000000..5a9e9d5 --- /dev/null +++ b/lib/forge-std/.github/workflows/sync.yml @@ -0,0 +1,29 @@ +name: Sync Release Branch + +on: + release: + types: + - created + +jobs: + sync-release-branch: + runs-on: ubuntu-latest + if: startsWith(github.event.release.tag_name, 'v1') + steps: + - name: Check out the repo + uses: actions/checkout@v3 + with: + fetch-depth: 0 + ref: v1 + + - name: Configure Git + run: | + git config user.name github-actions[bot] + git config user.email 41898282+github-actions[bot]@users.noreply.github.com + + - name: Sync Release Branch + run: | + git fetch --tags + git checkout v1 + git reset --hard ${GITHUB_REF} + git push --force diff --git a/lib/forge-std/.gitignore b/lib/forge-std/.gitignore new file mode 100644 index 0000000..756106d --- /dev/null +++ b/lib/forge-std/.gitignore @@ -0,0 +1,4 @@ +cache/ +out/ +.vscode +.idea diff --git a/lib/forge-std/.gitmodules b/lib/forge-std/.gitmodules new file mode 100644 index 0000000..e124719 --- /dev/null +++ b/lib/forge-std/.gitmodules @@ -0,0 +1,3 @@ +[submodule "lib/ds-test"] + path = lib/ds-test + url = https://github.com/dapphub/ds-test diff --git a/lib/forge-std/LICENSE-APACHE b/lib/forge-std/LICENSE-APACHE new file mode 100644 index 0000000..cf01a49 --- /dev/null +++ b/lib/forge-std/LICENSE-APACHE @@ -0,0 +1,203 @@ +Copyright Contributors to Forge Standard Library + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/forge-std/LICENSE-MIT b/lib/forge-std/LICENSE-MIT new file mode 100644 index 0000000..28f9830 --- /dev/null +++ b/lib/forge-std/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright Contributors to Forge Standard Library + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE O THE USE OR OTHER +DEALINGS IN THE SOFTWARE.R diff --git a/lib/forge-std/README.md b/lib/forge-std/README.md new file mode 100644 index 0000000..8494a7d --- /dev/null +++ b/lib/forge-std/README.md @@ -0,0 +1,250 @@ +# Forge Standard Library • [![CI status](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml/badge.svg)](https://github.com/foundry-rs/forge-std/actions/workflows/ci.yml) + +Forge Standard Library is a collection of helpful contracts and libraries for use with [Forge and Foundry](https://github.com/foundry-rs/foundry). It leverages Forge's cheatcodes to make writing tests easier and faster, while improving the UX of cheatcodes. + +**Learn how to use Forge-Std with the [📖 Foundry Book (Forge-Std Guide)](https://book.getfoundry.sh/forge/forge-std.html).** + +## Install + +```bash +forge install foundry-rs/forge-std +``` + +## Contracts +### stdError + +This is a helper contract for errors and reverts. In Forge, this contract is particularly helpful for the `expectRevert` cheatcode, as it provides all compiler builtin errors. + +See the contract itself for all error codes. + +#### Example usage + +```solidity + +import "forge-std/Test.sol"; + +contract TestContract is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function testExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } +} + +contract ErrorsTest { + function arithmeticError(uint256 a) public { + uint256 a = a - 100; + } +} +``` + +### stdStorage + +This is a rather large contract due to all of the overloading to make the UX decent. Primarily, it is a wrapper around the `record` and `accesses` cheatcodes. It can *always* find and write the storage slot(s) associated with a particular variable without knowing the storage layout. The one _major_ caveat to this is while a slot can be found for packed storage variables, we can't write to that variable safely. If a user tries to write to a packed slot, the execution throws an error, unless it is uninitialized (`bytes32(0)`). + +This works by recording all `SLOAD`s and `SSTORE`s during a function call. If there is a single slot read or written to, it immediately returns the slot. Otherwise, behind the scenes, we iterate through and check each one (assuming the user passed in a `depth` parameter). If the variable is a struct, you can pass in a `depth` parameter which is basically the field depth. + +I.e.: +```solidity +struct T { + // depth 0 + uint256 a; + // depth 1 + uint256 b; +} +``` + +#### Example usage + +```solidity +import "forge-std/Test.sol"; + +contract TestContract is Test { + using stdStorage for StdStorage; + + Storage test; + + function setUp() public { + test = new Storage(); + } + + function testFindExists() public { + // Lets say we want to find the slot for the public + // variable `exists`. We just pass in the function selector + // to the `find` command + uint256 slot = stdstore.target(address(test)).sig("exists()").find(); + assertEq(slot, 0); + } + + function testWriteExists() public { + // Lets say we want to write to the slot for the public + // variable `exists`. We just pass in the function selector + // to the `checked_write` command + stdstore.target(address(test)).sig("exists()").checked_write(100); + assertEq(test.exists(), 100); + } + + // It supports arbitrary storage layouts, like assembly based storage locations + function testFindHidden() public { + // `hidden` is a random hash of a bytes, iteration through slots would + // not find it. Our mechanism does + // Also, you can use the selector instead of a string + uint256 slot = stdstore.target(address(test)).sig(test.hidden.selector).find(); + assertEq(slot, uint256(keccak256("my.random.var"))); + } + + // If targeting a mapping, you have to pass in the keys necessary to perform the find + // i.e.: + function testFindMapping() public { + uint256 slot = stdstore + .target(address(test)) + .sig(test.map_addr.selector) + .with_key(address(this)) + .find(); + // in the `Storage` constructor, we wrote that this address' value was 1 in the map + // so when we load the slot, we expect it to be 1 + assertEq(uint(vm.load(address(test), bytes32(slot))), 1); + } + + // If the target is a struct, you can specify the field depth: + function testFindStruct() public { + // NOTE: see the depth parameter - 0 means 0th field, 1 means 1st field, etc. + uint256 slot_for_a_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(0) + .find(); + + uint256 slot_for_b_field = stdstore + .target(address(test)) + .sig(test.basicStruct.selector) + .depth(1) + .find(); + + assertEq(uint(vm.load(address(test), bytes32(slot_for_a_field))), 1); + assertEq(uint(vm.load(address(test), bytes32(slot_for_b_field))), 2); + } +} + +// A complex storage contract +contract Storage { + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + constructor() { + map_addr[msg.sender] = 1; + } + + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + // mapping(address => Packed) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basicStruct = UnpackedStruct({ + a: 1, + b: 2 + }); + + function hidden() public view returns (bytes32 t) { + // an extremely hidden storage slot + bytes32 slot = keccak256("my.random.var"); + assembly { + t := sload(slot) + } + } +} +``` + +### stdCheats + +This is a wrapper over miscellaneous cheatcodes that need wrappers to be more dev friendly. Currently there are only functions related to `prank`. In general, users may expect ETH to be put into an address on `prank`, but this is not the case for safety reasons. Explicitly this `hoax` function should only be used for address that have expected balances as it will get overwritten. If an address already has ETH, you should just use `prank`. If you want to change that balance explicitly, just use `deal`. If you want to do both, `hoax` is also right for you. + + +#### Example usage: +```solidity + +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "forge-std/Test.sol"; + +// Inherit the stdCheats +contract StdCheatsTest is Test { + Bar test; + function setUp() public { + test = new Bar(); + } + + function testHoax() public { + // we call `hoax`, which gives the target address + // eth and then calls `prank` + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + + // overloaded to allow you to specify how much eth to + // initialize the address with + hoax(address(1337), 1); + test.bar{value: 1}(address(1337)); + } + + function testStartHoax() public { + // we call `startHoax`, which gives the target address + // eth and then calls `startPrank` + // + // it is also overloaded so that you can specify an eth amount + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } +} + +contract Bar { + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } +} +``` + +### Std Assertions + +Expand upon the assertion functions from the `DSTest` library. + +### `console.log` + +Usage follows the same format as [Hardhat](https://hardhat.org/hardhat-network/reference/#console-log). +It's recommended to use `console2.sol` as shown below, as this will show the decoded logs in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console2.sol"; +... +console2.log(someValue); +``` + +If you need compatibility with Hardhat, you must use the standard `console.sol` instead. +Due to a bug in `console.sol`, logs that use `uint256` or `int256` types will not be properly decoded in Forge traces. + +```solidity +// import it indirectly via Test.sol +import "forge-std/Test.sol"; +// or directly import it +import "forge-std/console.sol"; +... +console.log(someValue); +``` + +## License + +Forge Standard Library is offered under either [MIT](LICENSE-MIT) or [Apache 2.0](LICENSE-APACHE) license. diff --git a/lib/forge-std/foundry.toml b/lib/forge-std/foundry.toml new file mode 100644 index 0000000..f9679ee --- /dev/null +++ b/lib/forge-std/foundry.toml @@ -0,0 +1,21 @@ +[profile.default] +fs_permissions = [{ access = "read-write", path = "./"}] + +[rpc_endpoints] +# The RPC URLs are modified versions of the default for testing initialization. +mainnet = "https://mainnet.infura.io/v3/b1d3925804e74152b316ca7da97060d3" # Different API key. +optimism_goerli = "https://goerli.optimism.io/" # Adds a trailing slash. +arbitrum_one_goerli = "https://goerli-rollup.arbitrum.io/rpc/" # Adds a trailing slash. +needs_undefined_env_var = "${UNDEFINED_RPC_URL_PLACEHOLDER}" + +[fmt] +# These are all the `forge fmt` defaults. +line_length = 120 +tab_width = 4 +bracket_spacing = false +int_types = 'long' +multiline_func_header = 'attributes_first' +quote_style = 'double' +number_underscore = 'preserve' +single_line_statement_blocks = 'preserve' +ignore = ["src/console.sol", "src/console2.sol"] \ No newline at end of file diff --git a/lib/forge-std/lib/ds-test/.github/workflows/build.yml b/lib/forge-std/lib/ds-test/.github/workflows/build.yml new file mode 100644 index 0000000..d2ff97d --- /dev/null +++ b/lib/forge-std/lib/ds-test/.github/workflows/build.yml @@ -0,0 +1,41 @@ +name: "Build" +on: + pull_request: + push: +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: cachix/install-nix-action@v20 + with: + nix_path: nixpkgs=channel:nixos-unstable + extra_nix_config: | + access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} + + - name: setup dapp binary cache + uses: cachix/cachix-action@v12 + with: + name: dapp + + - name: install dapptools + run: nix profile install github:dapphub/dapptools#dapp --accept-flake-config + + - name: install foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: test with solc-0.5.17 + run: dapp --use solc-0.5.17 test -v + + - name: test with solc-0.6.11 + run: dapp --use solc-0.6.11 test -v + + - name: test with solc-0.7.6 + run: dapp --use solc-0.7.6 test -v + + - name: test with solc-0.8.18 + run: dapp --use solc-0.8.18 test -v + + - name: Run tests with foundry + run: forge test -vvv + diff --git a/lib/forge-std/lib/ds-test/.gitignore b/lib/forge-std/lib/ds-test/.gitignore new file mode 100644 index 0000000..462a994 --- /dev/null +++ b/lib/forge-std/lib/ds-test/.gitignore @@ -0,0 +1,4 @@ +/.dapple +/build +/out +/cache/ diff --git a/lib/forge-std/lib/ds-test/LICENSE b/lib/forge-std/lib/ds-test/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/lib/forge-std/lib/ds-test/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/forge-std/lib/ds-test/Makefile b/lib/forge-std/lib/ds-test/Makefile new file mode 100644 index 0000000..661dac4 --- /dev/null +++ b/lib/forge-std/lib/ds-test/Makefile @@ -0,0 +1,14 @@ +all:; dapp build + +test: + -dapp --use solc:0.4.23 build + -dapp --use solc:0.4.26 build + -dapp --use solc:0.5.17 build + -dapp --use solc:0.6.12 build + -dapp --use solc:0.7.5 build + +demo: + DAPP_SRC=demo dapp --use solc:0.7.5 build + -hevm dapp-test --verbose 3 + +.PHONY: test demo diff --git a/lib/forge-std/lib/ds-test/default.nix b/lib/forge-std/lib/ds-test/default.nix new file mode 100644 index 0000000..cf65419 --- /dev/null +++ b/lib/forge-std/lib/ds-test/default.nix @@ -0,0 +1,4 @@ +{ solidityPackage, dappsys }: solidityPackage { + name = "ds-test"; + src = ./src; +} diff --git a/lib/forge-std/lib/ds-test/demo/demo.sol b/lib/forge-std/lib/ds-test/demo/demo.sol new file mode 100644 index 0000000..f3bb48e --- /dev/null +++ b/lib/forge-std/lib/ds-test/demo/demo.sol @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import "../src/test.sol"; + +contract DemoTest is DSTest { + function test_this() public pure { + require(true); + } + function test_logs() public { + emit log("-- log(string)"); + emit log("a string"); + + emit log("-- log_named_uint(string, uint)"); + emit log_named_uint("uint", 512); + + emit log("-- log_named_int(string, int)"); + emit log_named_int("int", -512); + + emit log("-- log_named_address(string, address)"); + emit log_named_address("address", address(this)); + + emit log("-- log_named_bytes32(string, bytes32)"); + emit log_named_bytes32("bytes32", "a string"); + + emit log("-- log_named_bytes(string, bytes)"); + emit log_named_bytes("bytes", hex"cafefe"); + + emit log("-- log_named_string(string, string)"); + emit log_named_string("string", "a string"); + + emit log("-- log_named_decimal_uint(string, uint, uint)"); + emit log_named_decimal_uint("decimal uint", 1.0e18, 18); + + emit log("-- log_named_decimal_int(string, int, uint)"); + emit log_named_decimal_int("decimal int", -1.0e18, 18); + } + event log_old_named_uint(bytes32,uint); + function test_old_logs() public { + emit log_old_named_uint("key", 500); + emit log_named_bytes32("bkey", "val"); + } + function test_trace() public view { + this.echo("string 1", "string 2"); + } + function test_multiline() public { + emit log("a multiline\\nstring"); + emit log("a multiline string"); + emit log_bytes("a string"); + emit log_bytes("a multiline\nstring"); + emit log_bytes("a multiline\\nstring"); + emit logs(hex"0000"); + emit log_named_bytes("0x0000", hex"0000"); + emit logs(hex"ff"); + } + function echo(string memory s1, string memory s2) public pure + returns (string memory, string memory) + { + return (s1, s2); + } + + function prove_this(uint x) public { + emit log_named_uint("sym x", x); + assertGt(x + 1, 0); + } + + function test_logn() public { + assembly { + log0(0x01, 0x02) + log1(0x01, 0x02, 0x03) + log2(0x01, 0x02, 0x03, 0x04) + log3(0x01, 0x02, 0x03, 0x04, 0x05) + } + } + + event MyEvent(uint, uint indexed, uint, uint indexed); + function test_events() public { + emit MyEvent(1, 2, 3, 4); + } + + function test_asserts() public { + string memory err = "this test has failed!"; + emit log("## assertTrue(bool)\n"); + assertTrue(false); + emit log("\n"); + assertTrue(false, err); + + emit log("\n## assertEq(address,address)\n"); + assertEq(address(this), msg.sender); + emit log("\n"); + assertEq(address(this), msg.sender, err); + + emit log("\n## assertEq32(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(bytes32,bytes32)\n"); + assertEq32("bytes 1", "bytes 2"); + emit log("\n"); + assertEq32("bytes 1", "bytes 2", err); + + emit log("\n## assertEq(uint,uint)\n"); + assertEq(uint(0), 1); + emit log("\n"); + assertEq(uint(0), 1, err); + + emit log("\n## assertEq(int,int)\n"); + assertEq(-1, -2); + emit log("\n"); + assertEq(-1, -2, err); + + emit log("\n## assertEqDecimal(int,int,uint)\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertEqDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertEqDecimal(uint,uint,uint)\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertEqDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGt(uint,uint)\n"); + assertGt(uint(0), 0); + emit log("\n"); + assertGt(uint(0), 0, err); + + emit log("\n## assertGt(int,int)\n"); + assertGt(-1, -1); + emit log("\n"); + assertGt(-1, -1, err); + + emit log("\n## assertGtDecimal(int,int,uint)\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGtDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGtDecimal(uint,uint,uint)\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGtDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertGe(uint,uint)\n"); + assertGe(uint(0), 1); + emit log("\n"); + assertGe(uint(0), 1, err); + + emit log("\n## assertGe(int,int)\n"); + assertGe(-1, 0); + emit log("\n"); + assertGe(-1, 0, err); + + emit log("\n## assertGeDecimal(int,int,uint)\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18); + emit log("\n"); + assertGeDecimal(-2.0e18, -1.1e18, 18, err); + + emit log("\n## assertGeDecimal(uint,uint,uint)\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18); + emit log("\n"); + assertGeDecimal(uint(1.0e18), 1.1e18, 18, err); + + emit log("\n## assertLt(uint,uint)\n"); + assertLt(uint(0), 0); + emit log("\n"); + assertLt(uint(0), 0, err); + + emit log("\n## assertLt(int,int)\n"); + assertLt(-1, -1); + emit log("\n"); + assertLt(-1, -1, err); + + emit log("\n## assertLtDecimal(int,int,uint)\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLtDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLtDecimal(uint,uint,uint)\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLtDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertLe(uint,uint)\n"); + assertLe(uint(1), 0); + emit log("\n"); + assertLe(uint(1), 0, err); + + emit log("\n## assertLe(int,int)\n"); + assertLe(0, -1); + emit log("\n"); + assertLe(0, -1, err); + + emit log("\n## assertLeDecimal(int,int,uint)\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18); + emit log("\n"); + assertLeDecimal(-1.0e18, -1.1e18, 18, err); + + emit log("\n## assertLeDecimal(uint,uint,uint)\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18); + emit log("\n"); + assertLeDecimal(uint(2.0e18), 1.1e18, 18, err); + + emit log("\n## assertEq(string,string)\n"); + string memory s1 = "string 1"; + string memory s2 = "string 2"; + assertEq(s1, s2); + emit log("\n"); + assertEq(s1, s2, err); + + emit log("\n## assertEq0(bytes,bytes)\n"); + assertEq0(hex"abcdef01", hex"abcdef02"); + emit log("\n"); + assertEq0(hex"abcdef01", hex"abcdef02", err); + } +} + +contract DemoTestWithSetUp { + function setUp() public { + } + function test_pass() public pure { + } +} diff --git a/lib/forge-std/lib/ds-test/package.json b/lib/forge-std/lib/ds-test/package.json new file mode 100644 index 0000000..4802ada --- /dev/null +++ b/lib/forge-std/lib/ds-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "ds-test", + "version": "1.0.0", + "description": "Assertions, equality checks and other test helpers ", + "bugs": "https://github.com/dapphub/ds-test/issues", + "license": "GPL-3.0", + "author": "Contributors to ds-test", + "files": [ + "src/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/dapphub/ds-test.git" + } +} diff --git a/lib/forge-std/lib/ds-test/src/test.sol b/lib/forge-std/lib/ds-test/src/test.sol new file mode 100644 index 0000000..2bf3375 --- /dev/null +++ b/lib/forge-std/lib/ds-test/src/test.sol @@ -0,0 +1,592 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity >=0.5.0; + +contract DSTest { + event log (string); + event logs (bytes); + + event log_address (address); + event log_bytes32 (bytes32); + event log_int (int); + event log_uint (uint); + event log_bytes (bytes); + event log_string (string); + + event log_named_address (string key, address val); + event log_named_bytes32 (string key, bytes32 val); + event log_named_decimal_int (string key, int val, uint decimals); + event log_named_decimal_uint (string key, uint val, uint decimals); + event log_named_int (string key, int val); + event log_named_uint (string key, uint val); + event log_named_bytes (string key, bytes val); + event log_named_string (string key, string val); + + bool public IS_TEST = true; + bool private _failed; + + address constant HEVM_ADDRESS = + address(bytes20(uint160(uint256(keccak256('hevm cheat code'))))); + + modifier mayRevert() { _; } + modifier testopts(string memory) { _; } + + function failed() public returns (bool) { + if (_failed) { + return _failed; + } else { + bool globalFailed = false; + if (hasHEVMContext()) { + (, bytes memory retdata) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("load(address,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed")) + ) + ); + globalFailed = abi.decode(retdata, (bool)); + } + return globalFailed; + } + } + + function fail() internal virtual { + if (hasHEVMContext()) { + (bool status, ) = HEVM_ADDRESS.call( + abi.encodePacked( + bytes4(keccak256("store(address,bytes32,bytes32)")), + abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01))) + ) + ); + status; // Silence compiler warnings + } + _failed = true; + } + + function hasHEVMContext() internal view returns (bool) { + uint256 hevmCodeSize = 0; + assembly { + hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D) + } + return hevmCodeSize > 0; + } + + modifier logs_gas() { + uint startGas = gasleft(); + _; + uint endGas = gasleft(); + emit log_named_uint("gas", startGas - endGas); + } + + function assertTrue(bool condition) internal { + if (!condition) { + emit log("Error: Assertion Failed"); + fail(); + } + } + + function assertTrue(bool condition, string memory err) internal { + if (!condition) { + emit log_named_string("Error", err); + assertTrue(condition); + } + } + + function assertEq(address a, address b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [address]"); + emit log_named_address(" Left", a); + emit log_named_address(" Right", b); + fail(); + } + } + function assertEq(address a, address b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes32 a, bytes32 b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [bytes32]"); + emit log_named_bytes32(" Left", a); + emit log_named_bytes32(" Right", b); + fail(); + } + } + function assertEq(bytes32 a, bytes32 b, string memory err) internal { + if (a != b) { + emit log_named_string ("Error", err); + assertEq(a, b); + } + } + function assertEq32(bytes32 a, bytes32 b) internal { + assertEq(a, b); + } + function assertEq32(bytes32 a, bytes32 b, string memory err) internal { + assertEq(a, b, err); + } + + function assertEq(int a, int b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + fail(); + } + } + function assertEq(int a, int b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEq(uint a, uint b) internal { + if (a != b) { + emit log("Error: a == b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + fail(); + } + } + function assertEq(uint a, uint b, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + function assertEqDecimal(int a, int b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal int]"); + emit log_named_decimal_int(" Left", a, decimals); + emit log_named_decimal_int(" Right", b, decimals); + fail(); + } + } + function assertEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + function assertEqDecimal(uint a, uint b, uint decimals) internal { + if (a != b) { + emit log("Error: a == b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Left", a, decimals); + emit log_named_decimal_uint(" Right", b, decimals); + fail(); + } + } + function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a != b) { + emit log_named_string("Error", err); + assertEqDecimal(a, b, decimals); + } + } + + function assertNotEq(address a, address b) internal { + if (a == b) { + emit log("Error: a != b not satisfied [address]"); + emit log_named_address(" Left", a); + emit log_named_address(" Right", b); + fail(); + } + } + function assertNotEq(address a, address b, string memory err) internal { + if (a == b) { + emit log_named_string ("Error", err); + assertNotEq(a, b); + } + } + + function assertNotEq(bytes32 a, bytes32 b) internal { + if (a == b) { + emit log("Error: a != b not satisfied [bytes32]"); + emit log_named_bytes32(" Left", a); + emit log_named_bytes32(" Right", b); + fail(); + } + } + function assertNotEq(bytes32 a, bytes32 b, string memory err) internal { + if (a == b) { + emit log_named_string ("Error", err); + assertNotEq(a, b); + } + } + function assertNotEq32(bytes32 a, bytes32 b) internal { + assertNotEq(a, b); + } + function assertNotEq32(bytes32 a, bytes32 b, string memory err) internal { + assertNotEq(a, b, err); + } + + function assertNotEq(int a, int b) internal { + if (a == b) { + emit log("Error: a != b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + fail(); + } + } + function assertNotEq(int a, int b, string memory err) internal { + if (a == b) { + emit log_named_string("Error", err); + assertNotEq(a, b); + } + } + function assertNotEq(uint a, uint b) internal { + if (a == b) { + emit log("Error: a != b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + fail(); + } + } + function assertNotEq(uint a, uint b, string memory err) internal { + if (a == b) { + emit log_named_string("Error", err); + assertNotEq(a, b); + } + } + function assertNotEqDecimal(int a, int b, uint decimals) internal { + if (a == b) { + emit log("Error: a != b not satisfied [decimal int]"); + emit log_named_decimal_int(" Left", a, decimals); + emit log_named_decimal_int(" Right", b, decimals); + fail(); + } + } + function assertNotEqDecimal(int a, int b, uint decimals, string memory err) internal { + if (a == b) { + emit log_named_string("Error", err); + assertNotEqDecimal(a, b, decimals); + } + } + function assertNotEqDecimal(uint a, uint b, uint decimals) internal { + if (a == b) { + emit log("Error: a != b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Left", a, decimals); + emit log_named_decimal_uint(" Right", b, decimals); + fail(); + } + } + function assertNotEqDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a == b) { + emit log_named_string("Error", err); + assertNotEqDecimal(a, b, decimals); + } + } + + function assertGt(uint a, uint b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGt(uint a, uint b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGt(int a, int b) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGt(int a, int b, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGt(a, b); + } + } + function assertGtDecimal(int a, int b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + function assertGtDecimal(uint a, uint b, uint decimals) internal { + if (a <= b) { + emit log("Error: a > b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a <= b) { + emit log_named_string("Error", err); + assertGtDecimal(a, b, decimals); + } + } + + function assertGe(uint a, uint b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertGe(uint a, uint b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGe(int a, int b) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertGe(int a, int b, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGe(a, b); + } + } + function assertGeDecimal(int a, int b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + function assertGeDecimal(uint a, uint b, uint decimals) internal { + if (a < b) { + emit log("Error: a >= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a < b) { + emit log_named_string("Error", err); + assertGeDecimal(a, b, decimals); + } + } + + function assertLt(uint a, uint b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLt(uint a, uint b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLt(int a, int b) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLt(int a, int b, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLt(a, b); + } + } + function assertLtDecimal(int a, int b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(int a, int b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + function assertLtDecimal(uint a, uint b, uint decimals) internal { + if (a >= b) { + emit log("Error: a < b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a >= b) { + emit log_named_string("Error", err); + assertLtDecimal(a, b, decimals); + } + } + + function assertLe(uint a, uint b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [uint]"); + emit log_named_uint(" Value a", a); + emit log_named_uint(" Value b", b); + fail(); + } + } + function assertLe(uint a, uint b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLe(int a, int b) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [int]"); + emit log_named_int(" Value a", a); + emit log_named_int(" Value b", b); + fail(); + } + } + function assertLe(int a, int b, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLe(a, b); + } + } + function assertLeDecimal(int a, int b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal int]"); + emit log_named_decimal_int(" Value a", a, decimals); + emit log_named_decimal_int(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(int a, int b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + function assertLeDecimal(uint a, uint b, uint decimals) internal { + if (a > b) { + emit log("Error: a <= b not satisfied [decimal uint]"); + emit log_named_decimal_uint(" Value a", a, decimals); + emit log_named_decimal_uint(" Value b", b, decimals); + fail(); + } + } + function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal { + if (a > b) { + emit log_named_string("Error", err); + assertLeDecimal(a, b, decimals); + } + } + + function assertEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log("Error: a == b not satisfied [string]"); + emit log_named_string(" Left", a); + emit log_named_string(" Right", b); + fail(); + } + } + function assertEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertNotEq(string memory a, string memory b) internal { + if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) { + emit log("Error: a != b not satisfied [string]"); + emit log_named_string(" Left", a); + emit log_named_string(" Right", b); + fail(); + } + } + function assertNotEq(string memory a, string memory b, string memory err) internal { + if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) { + emit log_named_string("Error", err); + assertNotEq(a, b); + } + } + + function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) { + ok = true; + if (a.length == b.length) { + for (uint i = 0; i < a.length; i++) { + if (a[i] != b[i]) { + ok = false; + } + } + } else { + ok = false; + } + } + function assertEq0(bytes memory a, bytes memory b) internal { + if (!checkEq0(a, b)) { + emit log("Error: a == b not satisfied [bytes]"); + emit log_named_bytes(" Left", a); + emit log_named_bytes(" Right", b); + fail(); + } + } + function assertEq0(bytes memory a, bytes memory b, string memory err) internal { + if (!checkEq0(a, b)) { + emit log_named_string("Error", err); + assertEq0(a, b); + } + } + + function assertNotEq0(bytes memory a, bytes memory b) internal { + if (checkEq0(a, b)) { + emit log("Error: a != b not satisfied [bytes]"); + emit log_named_bytes(" Left", a); + emit log_named_bytes(" Right", b); + fail(); + } + } + function assertNotEq0(bytes memory a, bytes memory b, string memory err) internal { + if (checkEq0(a, b)) { + emit log_named_string("Error", err); + assertNotEq0(a, b); + } + } +} diff --git a/lib/forge-std/lib/ds-test/src/test.t.sol b/lib/forge-std/lib/ds-test/src/test.t.sol new file mode 100644 index 0000000..d277a30 --- /dev/null +++ b/lib/forge-std/lib/ds-test/src/test.t.sol @@ -0,0 +1,417 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.5.0; + +import {DSTest} from "./test.sol"; + +contract DemoTest is DSTest { + + // --- assertTrue --- + + function testAssertTrue() public { + assertTrue(true, "msg"); + assertTrue(true); + } + function testFailAssertTrue() public { + assertTrue(false); + } + function testFailAssertTrueWithMsg() public { + assertTrue(false, "msg"); + } + + // --- assertEq (Addr) --- + + function testAssertEqAddr() public { + assertEq(address(0x0), address(0x0), "msg"); + assertEq(address(0x0), address(0x0)); + } + function testFailAssertEqAddr() public { + assertEq(address(0x0), address(0x1)); + } + function testFailAssertEqAddrWithMsg() public { + assertEq(address(0x0), address(0x1), "msg"); + } + + // --- assertEq (Bytes32) --- + + function testAssertEqBytes32() public { + assertEq(bytes32("hi"), bytes32("hi"), "msg"); + assertEq(bytes32("hi"), bytes32("hi")); + } + function testFailAssertEqBytes32() public { + assertEq(bytes32("hi"), bytes32("ho")); + } + function testFailAssertEqBytes32WithMsg() public { + assertEq(bytes32("hi"), bytes32("ho"), "msg"); + } + + // --- assertEq (Int) --- + + function testAssertEqInt() public { + assertEq(-1, -1, "msg"); + assertEq(-1, -1); + } + function testFailAssertEqInt() public { + assertEq(-1, -2); + } + function testFailAssertEqIntWithMsg() public { + assertEq(-1, -2, "msg"); + } + + // --- assertEq (UInt) --- + + function testAssertEqUInt() public { + assertEq(uint(1), uint(1), "msg"); + assertEq(uint(1), uint(1)); + } + function testFailAssertEqUInt() public { + assertEq(uint(1), uint(2)); + } + function testFailAssertEqUIntWithMsg() public { + assertEq(uint(1), uint(2), "msg"); + } + + // --- assertEqDecimal (Int) --- + + function testAssertEqDecimalInt() public { + assertEqDecimal(-1, -1, 18, "msg"); + assertEqDecimal(-1, -1, 18); + } + function testFailAssertEqDecimalInt() public { + assertEqDecimal(-1, -2, 18); + } + function testFailAssertEqDecimalIntWithMsg() public { + assertEqDecimal(-1, -2, 18, "msg"); + } + + // --- assertEqDecimal (UInt) --- + + function testAssertEqDecimalUInt() public { + assertEqDecimal(uint(1), uint(1), 18, "msg"); + assertEqDecimal(uint(1), uint(1), 18); + } + function testFailAssertEqDecimalUInt() public { + assertEqDecimal(uint(1), uint(2), 18); + } + function testFailAssertEqDecimalUIntWithMsg() public { + assertEqDecimal(uint(1), uint(2), 18, "msg"); + } + + // --- assertNotEq (Addr) --- + + function testAssertNotEqAddr() public { + assertNotEq(address(0x0), address(0x1), "msg"); + assertNotEq(address(0x0), address(0x1)); + } + function testFailAssertNotEqAddr() public { + assertNotEq(address(0x0), address(0x0)); + } + function testFailAssertNotEqAddrWithMsg() public { + assertNotEq(address(0x0), address(0x0), "msg"); + } + + // --- assertNotEq (Bytes32) --- + + function testAssertNotEqBytes32() public { + assertNotEq(bytes32("hi"), bytes32("ho"), "msg"); + assertNotEq(bytes32("hi"), bytes32("ho")); + } + function testFailAssertNotEqBytes32() public { + assertNotEq(bytes32("hi"), bytes32("hi")); + } + function testFailAssertNotEqBytes32WithMsg() public { + assertNotEq(bytes32("hi"), bytes32("hi"), "msg"); + } + + // --- assertNotEq (Int) --- + + function testAssertNotEqInt() public { + assertNotEq(-1, -2, "msg"); + assertNotEq(-1, -2); + } + function testFailAssertNotEqInt() public { + assertNotEq(-1, -1); + } + function testFailAssertNotEqIntWithMsg() public { + assertNotEq(-1, -1, "msg"); + } + + // --- assertNotEq (UInt) --- + + function testAssertNotEqUInt() public { + assertNotEq(uint(1), uint(2), "msg"); + assertNotEq(uint(1), uint(2)); + } + function testFailAssertNotEqUInt() public { + assertNotEq(uint(1), uint(1)); + } + function testFailAssertNotEqUIntWithMsg() public { + assertNotEq(uint(1), uint(1), "msg"); + } + + // --- assertNotEqDecimal (Int) --- + + function testAssertNotEqDecimalInt() public { + assertNotEqDecimal(-1, -2, 18, "msg"); + assertNotEqDecimal(-1, -2, 18); + } + function testFailAssertNotEqDecimalInt() public { + assertNotEqDecimal(-1, -1, 18); + } + function testFailAssertNotEqDecimalIntWithMsg() public { + assertNotEqDecimal(-1, -1, 18, "msg"); + } + + // --- assertNotEqDecimal (UInt) --- + + function testAssertNotEqDecimalUInt() public { + assertNotEqDecimal(uint(1), uint(2), 18, "msg"); + assertNotEqDecimal(uint(1), uint(2), 18); + } + function testFailAssertNotEqDecimalUInt() public { + assertNotEqDecimal(uint(1), uint(1), 18); + } + function testFailAssertNotEqDecimalUIntWithMsg() public { + assertNotEqDecimal(uint(1), uint(1), 18, "msg"); + } + + // --- assertGt (UInt) --- + + function testAssertGtUInt() public { + assertGt(uint(2), uint(1), "msg"); + assertGt(uint(3), uint(2)); + } + function testFailAssertGtUInt() public { + assertGt(uint(1), uint(2)); + } + function testFailAssertGtUIntWithMsg() public { + assertGt(uint(1), uint(2), "msg"); + } + + // --- assertGt (Int) --- + + function testAssertGtInt() public { + assertGt(-1, -2, "msg"); + assertGt(-1, -3); + } + function testFailAssertGtInt() public { + assertGt(-2, -1); + } + function testFailAssertGtIntWithMsg() public { + assertGt(-2, -1, "msg"); + } + + // --- assertGtDecimal (UInt) --- + + function testAssertGtDecimalUInt() public { + assertGtDecimal(uint(2), uint(1), 18, "msg"); + assertGtDecimal(uint(3), uint(2), 18); + } + function testFailAssertGtDecimalUInt() public { + assertGtDecimal(uint(1), uint(2), 18); + } + function testFailAssertGtDecimalUIntWithMsg() public { + assertGtDecimal(uint(1), uint(2), 18, "msg"); + } + + // --- assertGtDecimal (Int) --- + + function testAssertGtDecimalInt() public { + assertGtDecimal(-1, -2, 18, "msg"); + assertGtDecimal(-1, -3, 18); + } + function testFailAssertGtDecimalInt() public { + assertGtDecimal(-2, -1, 18); + } + function testFailAssertGtDecimalIntWithMsg() public { + assertGtDecimal(-2, -1, 18, "msg"); + } + + // --- assertGe (UInt) --- + + function testAssertGeUInt() public { + assertGe(uint(2), uint(1), "msg"); + assertGe(uint(2), uint(2)); + } + function testFailAssertGeUInt() public { + assertGe(uint(1), uint(2)); + } + function testFailAssertGeUIntWithMsg() public { + assertGe(uint(1), uint(2), "msg"); + } + + // --- assertGe (Int) --- + + function testAssertGeInt() public { + assertGe(-1, -2, "msg"); + assertGe(-1, -1); + } + function testFailAssertGeInt() public { + assertGe(-2, -1); + } + function testFailAssertGeIntWithMsg() public { + assertGe(-2, -1, "msg"); + } + + // --- assertGeDecimal (UInt) --- + + function testAssertGeDecimalUInt() public { + assertGeDecimal(uint(2), uint(1), 18, "msg"); + assertGeDecimal(uint(2), uint(2), 18); + } + function testFailAssertGeDecimalUInt() public { + assertGeDecimal(uint(1), uint(2), 18); + } + function testFailAssertGeDecimalUIntWithMsg() public { + assertGeDecimal(uint(1), uint(2), 18, "msg"); + } + + // --- assertGeDecimal (Int) --- + + function testAssertGeDecimalInt() public { + assertGeDecimal(-1, -2, 18, "msg"); + assertGeDecimal(-1, -2, 18); + } + function testFailAssertGeDecimalInt() public { + assertGeDecimal(-2, -1, 18); + } + function testFailAssertGeDecimalIntWithMsg() public { + assertGeDecimal(-2, -1, 18, "msg"); + } + + // --- assertLt (UInt) --- + + function testAssertLtUInt() public { + assertLt(uint(1), uint(2), "msg"); + assertLt(uint(1), uint(3)); + } + function testFailAssertLtUInt() public { + assertLt(uint(2), uint(2)); + } + function testFailAssertLtUIntWithMsg() public { + assertLt(uint(3), uint(2), "msg"); + } + + // --- assertLt (Int) --- + + function testAssertLtInt() public { + assertLt(-2, -1, "msg"); + assertLt(-1, 0); + } + function testFailAssertLtInt() public { + assertLt(-1, -2); + } + function testFailAssertLtIntWithMsg() public { + assertLt(-1, -1, "msg"); + } + + // --- assertLtDecimal (UInt) --- + + function testAssertLtDecimalUInt() public { + assertLtDecimal(uint(1), uint(2), 18, "msg"); + assertLtDecimal(uint(2), uint(3), 18); + } + function testFailAssertLtDecimalUInt() public { + assertLtDecimal(uint(1), uint(1), 18); + } + function testFailAssertLtDecimalUIntWithMsg() public { + assertLtDecimal(uint(2), uint(1), 18, "msg"); + } + + // --- assertLtDecimal (Int) --- + + function testAssertLtDecimalInt() public { + assertLtDecimal(-2, -1, 18, "msg"); + assertLtDecimal(-2, -1, 18); + } + function testFailAssertLtDecimalInt() public { + assertLtDecimal(-2, -2, 18); + } + function testFailAssertLtDecimalIntWithMsg() public { + assertLtDecimal(-1, -2, 18, "msg"); + } + + // --- assertLe (UInt) --- + + function testAssertLeUInt() public { + assertLe(uint(1), uint(2), "msg"); + assertLe(uint(1), uint(1)); + } + function testFailAssertLeUInt() public { + assertLe(uint(4), uint(2)); + } + function testFailAssertLeUIntWithMsg() public { + assertLe(uint(3), uint(2), "msg"); + } + + // --- assertLe (Int) --- + + function testAssertLeInt() public { + assertLe(-2, -1, "msg"); + assertLe(-1, -1); + } + function testFailAssertLeInt() public { + assertLe(-1, -2); + } + function testFailAssertLeIntWithMsg() public { + assertLe(-1, -3, "msg"); + } + + // --- assertLeDecimal (UInt) --- + + function testAssertLeDecimalUInt() public { + assertLeDecimal(uint(1), uint(2), 18, "msg"); + assertLeDecimal(uint(2), uint(2), 18); + } + function testFailAssertLeDecimalUInt() public { + assertLeDecimal(uint(1), uint(0), 18); + } + function testFailAssertLeDecimalUIntWithMsg() public { + assertLeDecimal(uint(1), uint(0), 18, "msg"); + } + + // --- assertLeDecimal (Int) --- + + function testAssertLeDecimalInt() public { + assertLeDecimal(-2, -1, 18, "msg"); + assertLeDecimal(-2, -2, 18); + } + function testFailAssertLeDecimalInt() public { + assertLeDecimal(-2, -3, 18); + } + function testFailAssertLeDecimalIntWithMsg() public { + assertLeDecimal(-1, -2, 18, "msg"); + } + + // --- assertNotEq (String) --- + + function testAssertNotEqString() public { + assertNotEq(new string(1), new string(2), "msg"); + assertNotEq(new string(1), new string(2)); + } + function testFailAssertNotEqString() public { + assertNotEq(new string(1), new string(1)); + } + function testFailAssertNotEqStringWithMsg() public { + assertNotEq(new string(1), new string(1), "msg"); + } + + // --- assertNotEq0 (Bytes) --- + + function testAssertNotEq0Bytes() public { + assertNotEq0(bytes("hi"), bytes("ho"), "msg"); + assertNotEq0(bytes("hi"), bytes("ho")); + } + function testFailAssertNotEq0Bytes() public { + assertNotEq0(bytes("hi"), bytes("hi")); + } + function testFailAssertNotEq0BytesWithMsg() public { + assertNotEq0(bytes("hi"), bytes("hi"), "msg"); + } + + // --- fail override --- + + // ensure that fail can be overridden + function fail() internal override { + super.fail(); + } +} diff --git a/lib/forge-std/package.json b/lib/forge-std/package.json new file mode 100644 index 0000000..67bb85a --- /dev/null +++ b/lib/forge-std/package.json @@ -0,0 +1,16 @@ +{ + "name": "forge-std", + "version": "1.7.1", + "description": "Forge Standard Library is a collection of helpful contracts and libraries for use with Forge and Foundry.", + "homepage": "https://book.getfoundry.sh/forge/forge-std", + "bugs": "https://github.com/foundry-rs/forge-std/issues", + "license": "(Apache-2.0 OR MIT)", + "author": "Contributors to Forge Standard Library", + "files": [ + "src/**/*" + ], + "repository": { + "type": "git", + "url": "https://github.com/foundry-rs/forge-std.git" + } +} diff --git a/lib/forge-std/src/Base.sol b/lib/forge-std/src/Base.sol new file mode 100644 index 0000000..851ac0c --- /dev/null +++ b/lib/forge-std/src/Base.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {StdStorage} from "./StdStorage.sol"; +import {Vm, VmSafe} from "./Vm.sol"; + +abstract contract CommonBase { + // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D. + address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + // console.sol and console2.sol work by executing a staticcall to this address. + address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67; + // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38. + address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller")))); + // Address of the test contract, deployed by the DEFAULT_SENDER. + address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f; + // Deterministic deployment address of the Multicall3 contract. + address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11; + // The order of the secp256k1 curve. + uint256 internal constant SECP256K1_ORDER = + 115792089237316195423570985008687907852837564279074904382605163141518161494337; + + uint256 internal constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + Vm internal constant vm = Vm(VM_ADDRESS); + StdStorage internal stdstore; +} + +abstract contract TestBase is CommonBase {} + +abstract contract ScriptBase is CommonBase { + VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS); +} diff --git a/lib/forge-std/src/Script.sol b/lib/forge-std/src/Script.sol new file mode 100644 index 0000000..94e75f6 --- /dev/null +++ b/lib/forge-std/src/Script.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +// 💬 ABOUT +// Forge Std's default Script. + +// 🧩 MODULES +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {safeconsole} from "./safeconsole.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheatsSafe} from "./StdCheats.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorageSafe} from "./StdStorage.sol"; +import {StdStyle} from "./StdStyle.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {VmSafe} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {ScriptBase} from "./Base.sol"; + +// ⭐️ SCRIPT +abstract contract Script is ScriptBase, StdChains, StdCheatsSafe, StdUtils { + // Note: IS_SCRIPT() must return true. + bool public IS_SCRIPT = true; +} diff --git a/lib/forge-std/src/StdAssertions.sol b/lib/forge-std/src/StdAssertions.sol new file mode 100644 index 0000000..2778b3a --- /dev/null +++ b/lib/forge-std/src/StdAssertions.sol @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {DSTest} from "ds-test/test.sol"; +import {stdMath} from "./StdMath.sol"; + +abstract contract StdAssertions is DSTest { + event log_array(uint256[] val); + event log_array(int256[] val); + event log_array(address[] val); + event log_named_array(string key, uint256[] val); + event log_named_array(string key, int256[] val); + event log_named_array(string key, address[] val); + + function fail(string memory err) internal virtual { + emit log_named_string("Error", err); + fail(); + } + + function assertFalse(bool data) internal virtual { + assertTrue(!data); + } + + function assertFalse(bool data, string memory err) internal virtual { + assertTrue(!data, err); + } + + function assertEq(bool a, bool b) internal virtual { + if (a != b) { + emit log("Error: a == b not satisfied [bool]"); + emit log_named_string(" Left", a ? "true" : "false"); + emit log_named_string(" Right", b ? "true" : "false"); + fail(); + } + } + + function assertEq(bool a, bool b, string memory err) internal virtual { + if (a != b) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(bytes memory a, bytes memory b) internal virtual { + assertEq0(a, b); + } + + function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual { + assertEq0(a, b, err); + } + + function assertEq(uint256[] memory a, uint256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [uint[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(int256[] memory a, int256[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [int[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(address[] memory a, address[] memory b) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log("Error: a == b not satisfied [address[]]"); + emit log_named_array(" Left", a); + emit log_named_array(" Right", b); + fail(); + } + } + + function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual { + if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) { + emit log_named_string("Error", err); + assertEq(a, b); + } + } + + // Legacy helper + function assertEqUint(uint256 a, uint256 b) internal virtual { + assertEq(uint256(a), uint256(b)); + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_decimal_uint(" Left", a, decimals); + emit log_named_decimal_uint(" Right", b, decimals); + emit log_named_decimal_uint(" Max Delta", maxDelta, decimals); + emit log_named_decimal_uint(" Delta", delta, decimals); + fail(); + } + } + + function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, string memory err) + internal + virtual + { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + emit log_named_uint(" Max Delta", maxDelta); + emit log_named_uint(" Delta", delta); + fail(); + } + } + + function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbs(a, b, maxDelta); + } + } + + function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals) internal virtual { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_decimal_int(" Left", a, decimals); + emit log_named_decimal_int(" Right", b, decimals); + emit log_named_decimal_uint(" Max Delta", maxDelta, decimals); + emit log_named_decimal_uint(" Delta", delta, decimals); + fail(); + } + } + + function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, string memory err) + internal + virtual + { + uint256 delta = stdMath.delta(a, b); + + if (delta > maxDelta) { + emit log_named_string("Error", err); + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100% + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_uint(" Left", a); + emit log_named_uint(" Right", b); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18); + emit log_named_decimal_uint(" % Delta", percentDelta * 100, 18); + fail(); + } + } + + function assertApproxEqRel( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals + ) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [uint]"); + emit log_named_decimal_uint(" Left", a, decimals); + emit log_named_decimal_uint(" Right", b, decimals); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18); + emit log_named_decimal_uint(" % Delta", percentDelta * 100, 18); + fail(); + } + } + + function assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100% + uint256 decimals, + string memory err + ) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_int(" Left", a); + emit log_named_int(" Right", b); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18); + emit log_named_decimal_uint(" % Delta", percentDelta * 100, 18); + fail(); + } + } + + function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRel(a, b, maxPercentDelta); + } + } + + function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals) internal virtual { + if (b == 0) return assertEq(a, b); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log("Error: a ~= b not satisfied [int]"); + emit log_named_decimal_int(" Left", a, decimals); + emit log_named_decimal_int(" Right", b, decimals); + emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18); + emit log_named_decimal_uint(" % Delta", percentDelta * 100, 18); + fail(); + } + } + + function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, string memory err) + internal + virtual + { + if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too. + + uint256 percentDelta = stdMath.percentDelta(a, b); + + if (percentDelta > maxPercentDelta) { + emit log_named_string("Error", err); + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + } + + function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB) internal virtual { + assertEqCall(target, callDataA, target, callDataB, true); + } + + function assertEqCall(address targetA, bytes memory callDataA, address targetB, bytes memory callDataB) + internal + virtual + { + assertEqCall(targetA, callDataA, targetB, callDataB, true); + } + + function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB, bool strictRevertData) + internal + virtual + { + assertEqCall(target, callDataA, target, callDataB, strictRevertData); + } + + function assertEqCall( + address targetA, + bytes memory callDataA, + address targetB, + bytes memory callDataB, + bool strictRevertData + ) internal virtual { + (bool successA, bytes memory returnDataA) = address(targetA).call(callDataA); + (bool successB, bytes memory returnDataB) = address(targetB).call(callDataB); + + if (successA && successB) { + assertEq(returnDataA, returnDataB, "Call return data does not match"); + } + + if (!successA && !successB && strictRevertData) { + assertEq(returnDataA, returnDataB, "Call revert data does not match"); + } + + if (!successA && successB) { + emit log("Error: Calls were not equal"); + emit log_named_bytes(" Left call revert data", returnDataA); + emit log_named_bytes(" Right call return data", returnDataB); + fail(); + } + + if (successA && !successB) { + emit log("Error: Calls were not equal"); + emit log_named_bytes(" Left call return data", returnDataA); + emit log_named_bytes(" Right call revert data", returnDataB); + fail(); + } + } +} diff --git a/lib/forge-std/src/StdChains.sol b/lib/forge-std/src/StdChains.sol new file mode 100644 index 0000000..87e620a --- /dev/null +++ b/lib/forge-std/src/StdChains.sol @@ -0,0 +1,236 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {VmSafe} from "./Vm.sol"; + +/** + * StdChains provides information about EVM compatible chains that can be used in scripts/tests. + * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are + * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of + * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the + * alias used in this contract, which can be found as the first argument to the + * `setChainWithDefaultRpcUrl` call in the `initializeStdChains` function. + * + * There are two main ways to use this contract: + * 1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or + * `setChain(string memory chainAlias, Chain memory chain)` + * 2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`. + * + * The first time either of those are used, chains are initialized with the default set of RPC URLs. + * This is done in `initializeStdChains`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in + * `defaultRpcUrls`. + * + * The `setChain` function is straightforward, and it simply saves off the given chain data. + * + * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say + * we want to retrieve the RPC URL for `mainnet`: + * - If you have specified data with `setChain`, it will return that. + * - If you have configured a mainnet RPC URL in `foundry.toml`, it will return the URL, provided it + * is valid (e.g. a URL is specified, or an environment variable is given and exists). + * - If neither of the above conditions is met, the default data is returned. + * + * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults. + */ +abstract contract StdChains { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + bool private stdChainsInitialized; + + struct ChainData { + string name; + uint256 chainId; + string rpcUrl; + } + + struct Chain { + // The chain name. + string name; + // The chain's Chain ID. + uint256 chainId; + // The chain's alias. (i.e. what gets specified in `foundry.toml`). + string chainAlias; + // A default RPC endpoint for this chain. + // NOTE: This default RPC URL is included for convenience to facilitate quick tests and + // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy + // usage as you will be throttled and this is a disservice to others who need this endpoint. + string rpcUrl; + } + + // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data. + mapping(string => Chain) private chains; + // Maps from the chain's alias to it's default RPC URL. + mapping(string => string) private defaultRpcUrls; + // Maps from a chain ID to it's alias. + mapping(uint256 => string) private idToAlias; + + bool private fallbackToDefaultRpcUrls = true; + + // The RPC URL will be fetched from config or defaultRpcUrls if possible. + function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) { + require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string."); + + initializeStdChains(); + chain = chains[chainAlias]; + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(string): Chain with alias \"", chainAlias, "\" not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + function getChain(uint256 chainId) internal virtual returns (Chain memory chain) { + require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0."); + initializeStdChains(); + string memory chainAlias = idToAlias[chainId]; + + chain = chains[chainAlias]; + + require( + chain.chainId != 0, + string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found.")) + ); + + chain = getChainWithUpdatedRpcUrl(chainAlias, chain); + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, ChainData memory chain) internal virtual { + require( + bytes(chainAlias).length != 0, + "StdChains setChain(string,ChainData): Chain alias cannot be the empty string." + ); + + require(chain.chainId != 0, "StdChains setChain(string,ChainData): Chain ID cannot be 0."); + + initializeStdChains(); + string memory foundAlias = idToAlias[chain.chainId]; + + require( + bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)), + string( + abi.encodePacked( + "StdChains setChain(string,ChainData): Chain ID ", + vm.toString(chain.chainId), + " already used by \"", + foundAlias, + "\"." + ) + ) + ); + + uint256 oldChainId = chains[chainAlias].chainId; + delete idToAlias[oldChainId]; + + chains[chainAlias] = + Chain({name: chain.name, chainId: chain.chainId, chainAlias: chainAlias, rpcUrl: chain.rpcUrl}); + idToAlias[chain.chainId] = chainAlias; + } + + // set chain info, with priority to argument's rpcUrl field. + function setChain(string memory chainAlias, Chain memory chain) internal virtual { + setChain(chainAlias, ChainData({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl})); + } + + function _toUpper(string memory str) private pure returns (string memory) { + bytes memory strb = bytes(str); + bytes memory copy = new bytes(strb.length); + for (uint256 i = 0; i < strb.length; i++) { + bytes1 b = strb[i]; + if (b >= 0x61 && b <= 0x7A) { + copy[i] = bytes1(uint8(b) - 32); + } else { + copy[i] = b; + } + } + return string(copy); + } + + // lookup rpcUrl, in descending order of priority: + // current -> config (foundry.toml) -> environment variable -> default + function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) private returns (Chain memory) { + if (bytes(chain.rpcUrl).length == 0) { + try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) { + chain.rpcUrl = configRpcUrl; + } catch (bytes memory err) { + string memory envName = string(abi.encodePacked(_toUpper(chainAlias), "_RPC_URL")); + if (fallbackToDefaultRpcUrls) { + chain.rpcUrl = vm.envOr(envName, defaultRpcUrls[chainAlias]); + } else { + chain.rpcUrl = vm.envString(envName); + } + // distinguish 'not found' from 'cannot read' + bytes memory notFoundError = + abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias))); + if (keccak256(notFoundError) != keccak256(err) || bytes(chain.rpcUrl).length == 0) { + /// @solidity memory-safe-assembly + assembly { + revert(add(32, err), mload(err)) + } + } + } + } + return chain; + } + + function setFallbackToDefaultRpcUrls(bool useDefault) internal { + fallbackToDefaultRpcUrls = useDefault; + } + + function initializeStdChains() private { + if (stdChainsInitialized) return; + + stdChainsInitialized = true; + + // If adding an RPC here, make sure to test the default RPC URL in `testRpcs` + setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545")); + setChainWithDefaultRpcUrl( + "mainnet", ChainData("Mainnet", 1, "https://mainnet.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") + ); + setChainWithDefaultRpcUrl( + "goerli", ChainData("Goerli", 5, "https://goerli.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") + ); + setChainWithDefaultRpcUrl( + "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001") + ); + setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io")); + setChainWithDefaultRpcUrl("optimism_goerli", ChainData("Optimism Goerli", 420, "https://goerli.optimism.io")); + setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl( + "arbitrum_one_goerli", ChainData("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc") + ); + setChainWithDefaultRpcUrl("arbitrum_nova", ChainData("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc")); + setChainWithDefaultRpcUrl("polygon", ChainData("Polygon", 137, "https://polygon-rpc.com")); + setChainWithDefaultRpcUrl( + "polygon_mumbai", ChainData("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com") + ); + setChainWithDefaultRpcUrl("avalanche", ChainData("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc")); + setChainWithDefaultRpcUrl( + "avalanche_fuji", ChainData("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc") + ); + setChainWithDefaultRpcUrl( + "bnb_smart_chain", ChainData("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org") + ); + setChainWithDefaultRpcUrl( + "bnb_smart_chain_testnet", + ChainData("BNB Smart Chain Testnet", 97, "https://rpc.ankr.com/bsc_testnet_chapel") + ); + setChainWithDefaultRpcUrl("gnosis_chain", ChainData("Gnosis Chain", 100, "https://rpc.gnosischain.com")); + setChainWithDefaultRpcUrl("moonbeam", ChainData("Moonbeam", 1284, "https://rpc.api.moonbeam.network")); + setChainWithDefaultRpcUrl( + "moonriver", ChainData("Moonriver", 1285, "https://rpc.api.moonriver.moonbeam.network") + ); + setChainWithDefaultRpcUrl("moonbase", ChainData("Moonbase", 1287, "https://rpc.testnet.moonbeam.network")); + setChainWithDefaultRpcUrl("base_goerli", ChainData("Base Goerli", 84531, "https://goerli.base.org")); + setChainWithDefaultRpcUrl("base", ChainData("Base", 8453, "https://mainnet.base.org")); + } + + // set chain info, with priority to chainAlias' rpc url in foundry.toml + function setChainWithDefaultRpcUrl(string memory chainAlias, ChainData memory chain) private { + string memory rpcUrl = chain.rpcUrl; + defaultRpcUrls[chainAlias] = rpcUrl; + chain.rpcUrl = ""; + setChain(chainAlias, chain); + chain.rpcUrl = rpcUrl; // restore argument + } +} diff --git a/lib/forge-std/src/StdCheats.sol b/lib/forge-std/src/StdCheats.sol new file mode 100644 index 0000000..008b743 --- /dev/null +++ b/lib/forge-std/src/StdCheats.sol @@ -0,0 +1,817 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {console2} from "./console2.sol"; +import {Vm} from "./Vm.sol"; + +abstract contract StdCheatsSafe { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + bool private gasMeteringOff; + + // Data structures to parse Transaction objects from the broadcast artifact + // that conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawTx1559 { + string[] arguments; + address contractAddress; + string contractName; + // json value name = function + string functionSig; + bytes32 hash; + // json value name = tx + RawTx1559Detail txDetail; + // json value name = type + string opcode; + } + + struct RawTx1559Detail { + AccessList[] accessList; + bytes data; + address from; + bytes gas; + bytes nonce; + address to; + bytes txType; + bytes value; + } + + struct Tx1559 { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + bytes32 hash; + Tx1559Detail txDetail; + string opcode; + } + + struct Tx1559Detail { + AccessList[] accessList; + bytes data; + address from; + uint256 gas; + uint256 nonce; + address to; + uint256 txType; + uint256 value; + } + + // Data structures to parse Transaction objects from the broadcast artifact + // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct TxLegacy { + string[] arguments; + address contractAddress; + string contractName; + string functionSig; + string hash; + string opcode; + TxDetailLegacy transaction; + } + + struct TxDetailLegacy { + AccessList[] accessList; + uint256 chainId; + bytes data; + address from; + uint256 gas; + uint256 gasPrice; + bytes32 hash; + uint256 nonce; + bytes1 opcode; + bytes32 r; + bytes32 s; + uint256 txType; + address to; + uint8 v; + uint256 value; + } + + struct AccessList { + address accessAddress; + bytes32[] storageKeys; + } + + // Data structures to parse Receipt objects from the broadcast artifact. + // The Raw structs is what is parsed from the JSON + // and then converted to the one that is used by the user for better UX. + + struct RawReceipt { + bytes32 blockHash; + bytes blockNumber; + address contractAddress; + bytes cumulativeGasUsed; + bytes effectiveGasPrice; + address from; + bytes gasUsed; + RawReceiptLog[] logs; + bytes logsBloom; + bytes status; + address to; + bytes32 transactionHash; + bytes transactionIndex; + } + + struct Receipt { + bytes32 blockHash; + uint256 blockNumber; + address contractAddress; + uint256 cumulativeGasUsed; + uint256 effectiveGasPrice; + address from; + uint256 gasUsed; + ReceiptLog[] logs; + bytes logsBloom; + uint256 status; + address to; + bytes32 transactionHash; + uint256 transactionIndex; + } + + // Data structures to parse the entire broadcast artifact, assuming the + // transactions conform to EIP1559. + + struct EIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + Receipt[] receipts; + uint256 timestamp; + Tx1559[] transactions; + TxReturn[] txReturns; + } + + struct RawEIP1559ScriptArtifact { + string[] libraries; + string path; + string[] pending; + RawReceipt[] receipts; + TxReturn[] txReturns; + uint256 timestamp; + RawTx1559[] transactions; + } + + struct RawReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + bytes blockNumber; + bytes data; + bytes logIndex; + bool removed; + bytes32[] topics; + bytes32 transactionHash; + bytes transactionIndex; + bytes transactionLogIndex; + } + + struct ReceiptLog { + // json value = address + address logAddress; + bytes32 blockHash; + uint256 blockNumber; + bytes data; + uint256 logIndex; + bytes32[] topics; + uint256 transactionIndex; + uint256 transactionLogIndex; + bool removed; + } + + struct TxReturn { + string internalType; + string value; + } + + struct Account { + address addr; + uint256 key; + } + + enum AddressType { + Payable, + NonPayable, + ZeroAddress, + Precompile, + ForgeAddress + } + + // Checks that `addr` is not blacklisted by token contracts that have a blacklist. + function assumeNotBlacklisted(address token, address addr) internal view virtual { + // Nothing to check if `token` is not a contract. + uint256 tokenCodeSize; + assembly { + tokenCodeSize := extcodesize(token) + } + require(tokenCodeSize > 0, "StdCheats assumeNotBlacklisted(address,address): Token address is not a contract."); + + bool success; + bytes memory returnData; + + // 4-byte selector for `isBlacklisted(address)`, used by USDC. + (success, returnData) = token.staticcall(abi.encodeWithSelector(0xfe575a87, addr)); + vm.assume(!success || abi.decode(returnData, (bool)) == false); + + // 4-byte selector for `isBlackListed(address)`, used by USDT. + (success, returnData) = token.staticcall(abi.encodeWithSelector(0xe47d6060, addr)); + vm.assume(!success || abi.decode(returnData, (bool)) == false); + } + + // Checks that `addr` is not blacklisted by token contracts that have a blacklist. + // This is identical to `assumeNotBlacklisted(address,address)` but with a different name, for + // backwards compatibility, since this name was used in the original PR which has already has + // a release. This function can be removed in a future release once we want a breaking change. + function assumeNoBlacklisted(address token, address addr) internal view virtual { + assumeNotBlacklisted(token, addr); + } + + function assumeAddressIsNot(address addr, AddressType addressType) internal virtual { + if (addressType == AddressType.Payable) { + assumeNotPayable(addr); + } else if (addressType == AddressType.NonPayable) { + assumePayable(addr); + } else if (addressType == AddressType.ZeroAddress) { + assumeNotZeroAddress(addr); + } else if (addressType == AddressType.Precompile) { + assumeNotPrecompile(addr); + } else if (addressType == AddressType.ForgeAddress) { + assumeNotForgeAddress(addr); + } + } + + function assumeAddressIsNot(address addr, AddressType addressType1, AddressType addressType2) internal virtual { + assumeAddressIsNot(addr, addressType1); + assumeAddressIsNot(addr, addressType2); + } + + function assumeAddressIsNot( + address addr, + AddressType addressType1, + AddressType addressType2, + AddressType addressType3 + ) internal virtual { + assumeAddressIsNot(addr, addressType1); + assumeAddressIsNot(addr, addressType2); + assumeAddressIsNot(addr, addressType3); + } + + function assumeAddressIsNot( + address addr, + AddressType addressType1, + AddressType addressType2, + AddressType addressType3, + AddressType addressType4 + ) internal virtual { + assumeAddressIsNot(addr, addressType1); + assumeAddressIsNot(addr, addressType2); + assumeAddressIsNot(addr, addressType3); + assumeAddressIsNot(addr, addressType4); + } + + // This function checks whether an address, `addr`, is payable. It works by sending 1 wei to + // `addr` and checking the `success` return value. + // NOTE: This function may result in state changes depending on the fallback/receive logic + // implemented by `addr`, which should be taken into account when this function is used. + function _isPayable(address addr) private returns (bool) { + require( + addr.balance < UINT256_MAX, + "StdCheats _isPayable(address): Balance equals max uint256, so it cannot receive any more funds" + ); + uint256 origBalanceTest = address(this).balance; + uint256 origBalanceAddr = address(addr).balance; + + vm.deal(address(this), 1); + (bool success,) = payable(addr).call{value: 1}(""); + + // reset balances + vm.deal(address(this), origBalanceTest); + vm.deal(addr, origBalanceAddr); + + return success; + } + + // NOTE: This function may result in state changes depending on the fallback/receive logic + // implemented by `addr`, which should be taken into account when this function is used. See the + // `_isPayable` method for more information. + function assumePayable(address addr) internal virtual { + vm.assume(_isPayable(addr)); + } + + function assumeNotPayable(address addr) internal virtual { + vm.assume(!_isPayable(addr)); + } + + function assumeNotZeroAddress(address addr) internal pure virtual { + vm.assume(addr != address(0)); + } + + function assumeNotPrecompile(address addr) internal pure virtual { + assumeNotPrecompile(addr, _pureChainId()); + } + + function assumeNotPrecompile(address addr, uint256 chainId) internal pure virtual { + // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific + // address), but the same rationale for excluding them applies so we include those too. + + // These should be present on all EVM-compatible chains. + vm.assume(addr < address(0x1) || addr > address(0x9)); + + // forgefmt: disable-start + if (chainId == 10 || chainId == 420) { + // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21 + vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800)); + } else if (chainId == 42161 || chainId == 421613) { + // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains + vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068)); + } else if (chainId == 43114 || chainId == 43113) { + // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59 + vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff)); + vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF)); + vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff)); + } + // forgefmt: disable-end + } + + function assumeNotForgeAddress(address addr) internal pure virtual { + // vm, console, and Create2Deployer addresses + vm.assume( + addr != address(vm) && addr != 0x000000000000000000636F6e736F6c652e6c6f67 + && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C + ); + } + + function readEIP1559ScriptArtifact(string memory path) + internal + view + virtual + returns (EIP1559ScriptArtifact memory) + { + string memory data = vm.readFile(path); + bytes memory parsedData = vm.parseJson(data); + RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact)); + EIP1559ScriptArtifact memory artifact; + artifact.libraries = rawArtifact.libraries; + artifact.path = rawArtifact.path; + artifact.timestamp = rawArtifact.timestamp; + artifact.pending = rawArtifact.pending; + artifact.txReturns = rawArtifact.txReturns; + artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts); + artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions); + return artifact; + } + + function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) { + Tx1559[] memory txs = new Tx1559[](rawTxs.length); + for (uint256 i; i < rawTxs.length; i++) { + txs[i] = rawToConvertedEIPTx1559(rawTxs[i]); + } + return txs; + } + + function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) { + Tx1559 memory transaction; + transaction.arguments = rawTx.arguments; + transaction.contractName = rawTx.contractName; + transaction.functionSig = rawTx.functionSig; + transaction.hash = rawTx.hash; + transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail); + transaction.opcode = rawTx.opcode; + return transaction; + } + + function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail) + internal + pure + virtual + returns (Tx1559Detail memory) + { + Tx1559Detail memory txDetail; + txDetail.data = rawDetail.data; + txDetail.from = rawDetail.from; + txDetail.to = rawDetail.to; + txDetail.nonce = _bytesToUint(rawDetail.nonce); + txDetail.txType = _bytesToUint(rawDetail.txType); + txDetail.value = _bytesToUint(rawDetail.value); + txDetail.gas = _bytesToUint(rawDetail.gas); + txDetail.accessList = rawDetail.accessList; + return txDetail; + } + + function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions"); + RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[])); + return rawToConvertedEIPTx1559s(rawTxs); + } + + function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559)); + return rawToConvertedEIPTx1559(rawTx); + } + + // Analogous to readTransactions, but for receipts. + function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) { + string memory deployData = vm.readFile(path); + bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts"); + RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[])); + return rawToConvertedReceipts(rawReceipts); + } + + function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) { + string memory deployData = vm.readFile(path); + string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]")); + bytes memory parsedDeployData = vm.parseJson(deployData, key); + RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt)); + return rawToConvertedReceipt(rawReceipt); + } + + function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) { + Receipt[] memory receipts = new Receipt[](rawReceipts.length); + for (uint256 i; i < rawReceipts.length; i++) { + receipts[i] = rawToConvertedReceipt(rawReceipts[i]); + } + return receipts; + } + + function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) { + Receipt memory receipt; + receipt.blockHash = rawReceipt.blockHash; + receipt.to = rawReceipt.to; + receipt.from = rawReceipt.from; + receipt.contractAddress = rawReceipt.contractAddress; + receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice); + receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed); + receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed); + receipt.status = _bytesToUint(rawReceipt.status); + receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex); + receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber); + receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs); + receipt.logsBloom = rawReceipt.logsBloom; + receipt.transactionHash = rawReceipt.transactionHash; + return receipt; + } + + function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs) + internal + pure + virtual + returns (ReceiptLog[] memory) + { + ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length); + for (uint256 i; i < rawLogs.length; i++) { + logs[i].logAddress = rawLogs[i].logAddress; + logs[i].blockHash = rawLogs[i].blockHash; + logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber); + logs[i].data = rawLogs[i].data; + logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex); + logs[i].topics = rawLogs[i].topics; + logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex); + logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex); + logs[i].removed = rawLogs[i].removed; + } + return logs; + } + + // Deploy a contract by fetching the contract bytecode from + // the artifacts directory + // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))` + function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed."); + } + + function deployCode(string memory what) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(0, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string): Deployment failed."); + } + + /// @dev deploy contract with value on construction + function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = abi.encodePacked(vm.getCode(what), args); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed."); + } + + function deployCode(string memory what, uint256 val) internal virtual returns (address addr) { + bytes memory bytecode = vm.getCode(what); + /// @solidity memory-safe-assembly + assembly { + addr := create(val, add(bytecode, 0x20), mload(bytecode)) + } + + require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed."); + } + + // creates a labeled address and the corresponding private key + function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) { + privateKey = uint256(keccak256(abi.encodePacked(name))); + addr = vm.addr(privateKey); + vm.label(addr, name); + } + + // creates a labeled address + function makeAddr(string memory name) internal virtual returns (address addr) { + (addr,) = makeAddrAndKey(name); + } + + // Destroys an account immediately, sending the balance to beneficiary. + // Destroying means: balance will be zero, code will be empty, and nonce will be 0 + // This is similar to selfdestruct but not identical: selfdestruct destroys code and nonce + // only after tx ends, this will run immediately. + function destroyAccount(address who, address beneficiary) internal virtual { + uint256 currBalance = who.balance; + vm.etch(who, abi.encode()); + vm.deal(who, 0); + vm.resetNonce(who); + + uint256 beneficiaryBalance = beneficiary.balance; + vm.deal(beneficiary, currBalance + beneficiaryBalance); + } + + // creates a struct containing both a labeled address and the corresponding private key + function makeAccount(string memory name) internal virtual returns (Account memory account) { + (account.addr, account.key) = makeAddrAndKey(name); + } + + function deriveRememberKey(string memory mnemonic, uint32 index) + internal + virtual + returns (address who, uint256 privateKey) + { + privateKey = vm.deriveKey(mnemonic, index); + who = vm.rememberKey(privateKey); + } + + function _bytesToUint(bytes memory b) private pure returns (uint256) { + require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + function isFork() internal view virtual returns (bool status) { + try vm.activeFork() { + status = true; + } catch (bytes memory) {} + } + + modifier skipWhenForking() { + if (!isFork()) { + _; + } + } + + modifier skipWhenNotForking() { + if (isFork()) { + _; + } + } + + modifier noGasMetering() { + vm.pauseGasMetering(); + // To prevent turning gas monitoring back on with nested functions that use this modifier, + // we check if gasMetering started in the off position. If it did, we don't want to turn + // it back on until we exit the top level function that used the modifier + // + // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well. + // funcA will have `gasStartedOff` as false, funcB will have it as true, + // so we only turn metering back on at the end of the funcA + bool gasStartedOff = gasMeteringOff; + gasMeteringOff = true; + + _; + + // if gas metering was on when this modifier was called, turn it back on at the end + if (!gasStartedOff) { + gasMeteringOff = false; + vm.resumeGasMetering(); + } + } + + // We use this complex approach of `_viewChainId` and `_pureChainId` to ensure there are no + // compiler warnings when accessing chain ID in any solidity version supported by forge-std. We + // can't simply access the chain ID in a normal view or pure function because the solc View Pure + // Checker changed `chainid` from pure to view in 0.8.0. + function _viewChainId() private view returns (uint256 chainId) { + // Assembly required since `block.chainid` was introduced in 0.8.0. + assembly { + chainId := chainid() + } + + address(this); // Silence warnings in older Solc versions. + } + + function _pureChainId() private pure returns (uint256 chainId) { + function() internal view returns (uint256) fnIn = _viewChainId; + function() internal pure returns (uint256) pureChainId; + assembly { + pureChainId := fnIn + } + chainId = pureChainId(); + } +} + +// Wrappers around cheatcodes to avoid footguns +abstract contract StdCheats is StdCheatsSafe { + using stdStorage for StdStorage; + + StdStorage private stdstore; + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; + + // Skip forward or rewind time by the specified number of seconds + function skip(uint256 time) internal virtual { + vm.warp(block.timestamp + time); + } + + function rewind(uint256 time) internal virtual { + vm.warp(block.timestamp - time); + } + + // Setup a prank from an address that has some ether + function hoax(address msgSender) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.prank(msgSender); + } + + function hoax(address msgSender, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.prank(msgSender); + } + + function hoax(address msgSender, address origin) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.prank(msgSender, origin); + } + + function hoax(address msgSender, address origin, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.prank(msgSender, origin); + } + + // Start perpetual prank from an address that has some ether + function startHoax(address msgSender) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.startPrank(msgSender); + } + + function startHoax(address msgSender, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.startPrank(msgSender); + } + + // Start perpetual prank from an address that has some ether + // tx.origin is set to the origin parameter + function startHoax(address msgSender, address origin) internal virtual { + vm.deal(msgSender, 1 << 128); + vm.startPrank(msgSender, origin); + } + + function startHoax(address msgSender, address origin, uint256 give) internal virtual { + vm.deal(msgSender, give); + vm.startPrank(msgSender, origin); + } + + function changePrank(address msgSender) internal virtual { + console2_log("changePrank is deprecated. Please use vm.startPrank instead."); + vm.stopPrank(); + vm.startPrank(msgSender); + } + + function changePrank(address msgSender, address txOrigin) internal virtual { + vm.stopPrank(); + vm.startPrank(msgSender, txOrigin); + } + + // The same as Vm's `deal` + // Use the alternative signature for ERC20 tokens + function deal(address to, uint256 give) internal virtual { + vm.deal(to, give); + } + + // Set the balance of an account for any ERC20 token + // Use the alternative signature to update `totalSupply` + function deal(address token, address to, uint256 give) internal virtual { + deal(token, to, give, false); + } + + // Set the balance of an account for any ERC1155 token + // Use the alternative signature to update `totalSupply` + function dealERC1155(address token, address to, uint256 id, uint256 give) internal virtual { + dealERC1155(token, to, id, give, false); + } + + function deal(address token, address to, uint256 give, bool adjust) internal virtual { + // get current balance + (, bytes memory balData) = token.staticcall(abi.encodeWithSelector(0x70a08231, to)); + uint256 prevBal = abi.decode(balData, (uint256)); + + // update balance + stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give); + + // update total supply + if (adjust) { + (, bytes memory totSupData) = token.staticcall(abi.encodeWithSelector(0x18160ddd)); + uint256 totSup = abi.decode(totSupData, (uint256)); + if (give < prevBal) { + totSup -= (prevBal - give); + } else { + totSup += (give - prevBal); + } + stdstore.target(token).sig(0x18160ddd).checked_write(totSup); + } + } + + function dealERC1155(address token, address to, uint256 id, uint256 give, bool adjust) internal virtual { + // get current balance + (, bytes memory balData) = token.staticcall(abi.encodeWithSelector(0x00fdd58e, to, id)); + uint256 prevBal = abi.decode(balData, (uint256)); + + // update balance + stdstore.target(token).sig(0x00fdd58e).with_key(to).with_key(id).checked_write(give); + + // update total supply + if (adjust) { + (, bytes memory totSupData) = token.staticcall(abi.encodeWithSelector(0xbd85b039, id)); + require( + totSupData.length != 0, + "StdCheats deal(address,address,uint,uint,bool): target contract is not ERC1155Supply." + ); + uint256 totSup = abi.decode(totSupData, (uint256)); + if (give < prevBal) { + totSup -= (prevBal - give); + } else { + totSup += (give - prevBal); + } + stdstore.target(token).sig(0xbd85b039).with_key(id).checked_write(totSup); + } + } + + function dealERC721(address token, address to, uint256 id) internal virtual { + // check if token id is already minted and the actual owner. + (bool successMinted, bytes memory ownerData) = token.staticcall(abi.encodeWithSelector(0x6352211e, id)); + require(successMinted, "StdCheats deal(address,address,uint,bool): id not minted."); + + // get owner current balance + (, bytes memory fromBalData) = + token.staticcall(abi.encodeWithSelector(0x70a08231, abi.decode(ownerData, (address)))); + uint256 fromPrevBal = abi.decode(fromBalData, (uint256)); + + // get new user current balance + (, bytes memory toBalData) = token.staticcall(abi.encodeWithSelector(0x70a08231, to)); + uint256 toPrevBal = abi.decode(toBalData, (uint256)); + + // update balances + stdstore.target(token).sig(0x70a08231).with_key(abi.decode(ownerData, (address))).checked_write(--fromPrevBal); + stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(++toPrevBal); + + // update owner + stdstore.target(token).sig(0x6352211e).with_key(id).checked_write(to); + } + + function deployCodeTo(string memory what, address where) internal virtual { + deployCodeTo(what, "", 0, where); + } + + function deployCodeTo(string memory what, bytes memory args, address where) internal virtual { + deployCodeTo(what, args, 0, where); + } + + function deployCodeTo(string memory what, bytes memory args, uint256 value, address where) internal virtual { + bytes memory creationCode = vm.getCode(what); + vm.etch(where, abi.encodePacked(creationCode, args)); + (bool success, bytes memory runtimeBytecode) = where.call{value: value}(""); + require(success, "StdCheats deployCodeTo(string,bytes,uint256,address): Failed to create runtime bytecode."); + vm.etch(where, runtimeBytecode); + } + + // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere. + function console2_log(string memory p0) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string)", p0)); + status; + } +} diff --git a/lib/forge-std/src/StdError.sol b/lib/forge-std/src/StdError.sol new file mode 100644 index 0000000..a302191 --- /dev/null +++ b/lib/forge-std/src/StdError.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test +pragma solidity >=0.6.2 <0.9.0; + +library stdError { + bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01); + bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11); + bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12); + bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21); + bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22); + bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31); + bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32); + bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41); + bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51); +} diff --git a/lib/forge-std/src/StdInvariant.sol b/lib/forge-std/src/StdInvariant.sol new file mode 100644 index 0000000..bcd9ac0 --- /dev/null +++ b/lib/forge-std/src/StdInvariant.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +abstract contract StdInvariant { + struct FuzzSelector { + address addr; + bytes4[] selectors; + } + + struct FuzzInterface { + address addr; + string[] artifacts; + } + + address[] private _excludedContracts; + address[] private _excludedSenders; + address[] private _targetedContracts; + address[] private _targetedSenders; + + string[] private _excludedArtifacts; + string[] private _targetedArtifacts; + + FuzzSelector[] private _targetedArtifactSelectors; + FuzzSelector[] private _targetedSelectors; + + FuzzInterface[] private _targetedInterfaces; + + // Functions for users: + // These are intended to be called in tests. + + function excludeContract(address newExcludedContract_) internal { + _excludedContracts.push(newExcludedContract_); + } + + function excludeSender(address newExcludedSender_) internal { + _excludedSenders.push(newExcludedSender_); + } + + function excludeArtifact(string memory newExcludedArtifact_) internal { + _excludedArtifacts.push(newExcludedArtifact_); + } + + function targetArtifact(string memory newTargetedArtifact_) internal { + _targetedArtifacts.push(newTargetedArtifact_); + } + + function targetArtifactSelector(FuzzSelector memory newTargetedArtifactSelector_) internal { + _targetedArtifactSelectors.push(newTargetedArtifactSelector_); + } + + function targetContract(address newTargetedContract_) internal { + _targetedContracts.push(newTargetedContract_); + } + + function targetSelector(FuzzSelector memory newTargetedSelector_) internal { + _targetedSelectors.push(newTargetedSelector_); + } + + function targetSender(address newTargetedSender_) internal { + _targetedSenders.push(newTargetedSender_); + } + + function targetInterface(FuzzInterface memory newTargetedInterface_) internal { + _targetedInterfaces.push(newTargetedInterface_); + } + + // Functions for forge: + // These are called by forge to run invariant tests and don't need to be called in tests. + + function excludeArtifacts() public view returns (string[] memory excludedArtifacts_) { + excludedArtifacts_ = _excludedArtifacts; + } + + function excludeContracts() public view returns (address[] memory excludedContracts_) { + excludedContracts_ = _excludedContracts; + } + + function excludeSenders() public view returns (address[] memory excludedSenders_) { + excludedSenders_ = _excludedSenders; + } + + function targetArtifacts() public view returns (string[] memory targetedArtifacts_) { + targetedArtifacts_ = _targetedArtifacts; + } + + function targetArtifactSelectors() public view returns (FuzzSelector[] memory targetedArtifactSelectors_) { + targetedArtifactSelectors_ = _targetedArtifactSelectors; + } + + function targetContracts() public view returns (address[] memory targetedContracts_) { + targetedContracts_ = _targetedContracts; + } + + function targetSelectors() public view returns (FuzzSelector[] memory targetedSelectors_) { + targetedSelectors_ = _targetedSelectors; + } + + function targetSenders() public view returns (address[] memory targetedSenders_) { + targetedSenders_ = _targetedSenders; + } + + function targetInterfaces() public view returns (FuzzInterface[] memory targetedInterfaces_) { + targetedInterfaces_ = _targetedInterfaces; + } +} diff --git a/lib/forge-std/src/StdJson.sol b/lib/forge-std/src/StdJson.sol new file mode 100644 index 0000000..42d9bb7 --- /dev/null +++ b/lib/forge-std/src/StdJson.sol @@ -0,0 +1,183 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.0 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {VmSafe} from "./Vm.sol"; + +// Helpers for parsing and writing JSON files +// To parse: +// ``` +// using stdJson for string; +// string memory json = vm.readFile("some_peth"); +// json.parseUint(""); +// ``` +// To write: +// ``` +// using stdJson for string; +// string memory json = "deploymentArtifact"; +// Contract contract = new Contract(); +// json.serialize("contractAddress", address(contract)); +// json = json.serialize("deploymentTimes", uint(1)); +// // store the stringified JSON to the 'json' variable we have been using as a key +// // as we won't need it any longer +// string memory json2 = "finalArtifact"; +// string memory final = json2.serialize("depArtifact", json); +// final.write(""); +// ``` + +library stdJson { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) { + return vm.parseJson(json, key); + } + + function readUint(string memory json, string memory key) internal pure returns (uint256) { + return vm.parseJsonUint(json, key); + } + + function readUintArray(string memory json, string memory key) internal pure returns (uint256[] memory) { + return vm.parseJsonUintArray(json, key); + } + + function readInt(string memory json, string memory key) internal pure returns (int256) { + return vm.parseJsonInt(json, key); + } + + function readIntArray(string memory json, string memory key) internal pure returns (int256[] memory) { + return vm.parseJsonIntArray(json, key); + } + + function readBytes32(string memory json, string memory key) internal pure returns (bytes32) { + return vm.parseJsonBytes32(json, key); + } + + function readBytes32Array(string memory json, string memory key) internal pure returns (bytes32[] memory) { + return vm.parseJsonBytes32Array(json, key); + } + + function readString(string memory json, string memory key) internal pure returns (string memory) { + return vm.parseJsonString(json, key); + } + + function readStringArray(string memory json, string memory key) internal pure returns (string[] memory) { + return vm.parseJsonStringArray(json, key); + } + + function readAddress(string memory json, string memory key) internal pure returns (address) { + return vm.parseJsonAddress(json, key); + } + + function readAddressArray(string memory json, string memory key) internal pure returns (address[] memory) { + return vm.parseJsonAddressArray(json, key); + } + + function readBool(string memory json, string memory key) internal pure returns (bool) { + return vm.parseJsonBool(json, key); + } + + function readBoolArray(string memory json, string memory key) internal pure returns (bool[] memory) { + return vm.parseJsonBoolArray(json, key); + } + + function readBytes(string memory json, string memory key) internal pure returns (bytes memory) { + return vm.parseJsonBytes(json, key); + } + + function readBytesArray(string memory json, string memory key) internal pure returns (bytes[] memory) { + return vm.parseJsonBytesArray(json, key); + } + + function serialize(string memory jsonKey, string memory rootObject) internal returns (string memory) { + return vm.serializeJson(jsonKey, rootObject); + } + + function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bool[] memory value) + internal + returns (string memory) + { + return vm.serializeBool(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, uint256[] memory value) + internal + returns (string memory) + { + return vm.serializeUint(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, int256[] memory value) + internal + returns (string memory) + { + return vm.serializeInt(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, address[] memory value) + internal + returns (string memory) + { + return vm.serializeAddress(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes32[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes32(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, bytes[] memory value) + internal + returns (string memory) + { + return vm.serializeBytes(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function serialize(string memory jsonKey, string memory key, string[] memory value) + internal + returns (string memory) + { + return vm.serializeString(jsonKey, key, value); + } + + function write(string memory jsonKey, string memory path) internal { + vm.writeJson(jsonKey, path); + } + + function write(string memory jsonKey, string memory path, string memory valueKey) internal { + vm.writeJson(jsonKey, path, valueKey); + } +} diff --git a/lib/forge-std/src/StdMath.sol b/lib/forge-std/src/StdMath.sol new file mode 100644 index 0000000..459523b --- /dev/null +++ b/lib/forge-std/src/StdMath.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +library stdMath { + int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968; + + function abs(int256 a) internal pure returns (uint256) { + // Required or it will fail when `a = type(int256).min` + if (a == INT256_MIN) { + return 57896044618658097711785492504343953926634992332820282019728792003956564819968; + } + + return uint256(a > 0 ? a : -a); + } + + function delta(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a - b : b - a; + } + + function delta(int256 a, int256 b) internal pure returns (uint256) { + // a and b are of the same sign + // this works thanks to two's complement, the left-most bit is the sign bit + if ((a ^ b) > -1) { + return delta(abs(a), abs(b)); + } + + // a and b are of opposite signs + return abs(a) + abs(b); + } + + function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + + return absDelta * 1e18 / b; + } + + function percentDelta(int256 a, int256 b) internal pure returns (uint256) { + uint256 absDelta = delta(a, b); + uint256 absB = abs(b); + + return absDelta * 1e18 / absB; + } +} diff --git a/lib/forge-std/src/StdStorage.sol b/lib/forge-std/src/StdStorage.sol new file mode 100644 index 0000000..e5ded70 --- /dev/null +++ b/lib/forge-std/src/StdStorage.sol @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +import {Vm} from "./Vm.sol"; + +struct StdStorage { + mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots; + mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds; + bytes32[] _keys; + bytes4 _sig; + uint256 _depth; + address _target; + bytes32 _set; +} + +library stdStorageSafe { + event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot); + event WARNING_UninitedSlot(address who, uint256 slot); + + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return bytes4(keccak256(bytes(sigStr))); + } + + /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against + // slot complexity: + // if flat, will be bytes32(uint256(uint)); + // if map, will be keccak256(abi.encode(key, uint(slot))); + // if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot))))); + // if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth); + function find(StdStorage storage self) internal returns (uint256) { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + // calldata to test against + if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + vm.record(); + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + (bytes32[] memory reads,) = vm.accesses(address(who)); + if (reads.length == 1) { + bytes32 curr = vm.load(who, reads[0]); + if (curr == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[0])); + } + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + } else if (reads.length > 1) { + for (uint256 i = 0; i < reads.length; i++) { + bytes32 prev = vm.load(who, reads[i]); + if (prev == bytes32(0)) { + emit WARNING_UninitedSlot(who, uint256(reads[i])); + } + if (prev != fdat) { + continue; + } + bytes32 new_val = ~prev; + // store + vm.store(who, reads[i], new_val); + bool success; + { + bytes memory rdat; + (success, rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + + if (success && fdat == new_val) { + // we found which of the slots is the actual one + emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i])); + self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]); + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true; + vm.store(who, reads[i], prev); + break; + } + vm.store(who, reads[i], prev); + } + } else { + revert("stdStorage find(StdStorage): No storage use detected for target."); + } + + require( + self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))], + "stdStorage find(StdStorage): Slot(s) not found." + ); + + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + + return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]; + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + self._target = _target; + return self; + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + self._sig = _sig; + return self; + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + self._sig = sigs(_sig); + return self; + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + self._keys.push(bytes32(uint256(uint160(who)))); + return self; + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + self._keys.push(bytes32(amt)); + return self; + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + self._keys.push(key); + return self; + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + self._depth = _depth; + return self; + } + + function read(StdStorage storage self) private returns (bytes memory) { + address t = self._target; + uint256 s = find(self); + return abi.encode(vm.load(t, bytes32(s))); + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return abi.decode(read(self), (bytes32)); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + int256 v = read_int(self); + if (v == 0) return false; + if (v == 1) return true; + revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + } + + function read_address(StdStorage storage self) internal returns (address) { + return abi.decode(read(self), (address)); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return abi.decode(read(self), (uint256)); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return abi.decode(read(self), (int256)); + } + + function parent(StdStorage storage self) internal returns (uint256, bytes32) { + address who = self._target; + uint256 field_depth = self._depth; + vm.startMappingRecording(); + uint256 child = find(self) - field_depth; + (bool found, bytes32 key, bytes32 parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(child)); + if (!found) { + revert( + "stdStorage read_bool(StdStorage): Cannot find parent. Make sure you give a slot and startMappingRecording() has been called." + ); + } + return (uint256(parent_slot), key); + } + + function root(StdStorage storage self) internal returns (uint256) { + address who = self._target; + uint256 field_depth = self._depth; + vm.startMappingRecording(); + uint256 child = find(self) - field_depth; + bool found; + bytes32 root_slot; + bytes32 parent_slot; + (found,, parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(child)); + if (!found) { + revert( + "stdStorage read_bool(StdStorage): Cannot find parent. Make sure you give a slot and startMappingRecording() has been called." + ); + } + while (found) { + root_slot = parent_slot; + (found,, parent_slot) = vm.getMappingKeyAndParentOf(who, bytes32(root_slot)); + } + return uint256(root_slot); + } + + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} + +library stdStorage { + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function sigs(string memory sigStr) internal pure returns (bytes4) { + return stdStorageSafe.sigs(sigStr); + } + + function find(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.find(self); + } + + function target(StdStorage storage self, address _target) internal returns (StdStorage storage) { + return stdStorageSafe.target(self, _target); + } + + function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) { + return stdStorageSafe.sig(self, _sig); + } + + function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, who); + } + + function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, amt); + } + + function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) { + return stdStorageSafe.with_key(self, key); + } + + function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) { + return stdStorageSafe.depth(self, _depth); + } + + function checked_write(StdStorage storage self, address who) internal { + checked_write(self, bytes32(uint256(uint160(who)))); + } + + function checked_write(StdStorage storage self, uint256 amt) internal { + checked_write(self, bytes32(amt)); + } + + function checked_write_int(StdStorage storage self, int256 val) internal { + checked_write(self, bytes32(uint256(val))); + } + + function checked_write(StdStorage storage self, bool write) internal { + bytes32 t; + /// @solidity memory-safe-assembly + assembly { + t := write + } + checked_write(self, t); + } + + function checked_write(StdStorage storage self, bytes32 set) internal { + address who = self._target; + bytes4 fsig = self._sig; + uint256 field_depth = self._depth; + bytes32[] memory ins = self._keys; + + bytes memory cald = abi.encodePacked(fsig, flatten(ins)); + if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) { + find(self); + } + bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]); + + bytes32 fdat; + { + (, bytes memory rdat) = who.staticcall(cald); + fdat = bytesToBytes32(rdat, 32 * field_depth); + } + bytes32 curr = vm.load(who, slot); + + if (fdat != curr) { + require( + false, + "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported." + ); + } + vm.store(who, slot, set); + delete self._target; + delete self._sig; + delete self._keys; + delete self._depth; + } + + function read_bytes32(StdStorage storage self) internal returns (bytes32) { + return stdStorageSafe.read_bytes32(self); + } + + function read_bool(StdStorage storage self) internal returns (bool) { + return stdStorageSafe.read_bool(self); + } + + function read_address(StdStorage storage self) internal returns (address) { + return stdStorageSafe.read_address(self); + } + + function read_uint(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.read_uint(self); + } + + function read_int(StdStorage storage self) internal returns (int256) { + return stdStorageSafe.read_int(self); + } + + function parent(StdStorage storage self) internal returns (uint256, bytes32) { + return stdStorageSafe.parent(self); + } + + function root(StdStorage storage self) internal returns (uint256) { + return stdStorageSafe.root(self); + } + + // Private function so needs to be copied over + function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) { + bytes32 out; + + uint256 max = b.length > 32 ? 32 : b.length; + for (uint256 i = 0; i < max; i++) { + out |= bytes32(b[offset + i] & 0xFF) >> (i * 8); + } + return out; + } + + // Private function so needs to be copied over + function flatten(bytes32[] memory b) private pure returns (bytes memory) { + bytes memory result = new bytes(b.length * 32); + for (uint256 i = 0; i < b.length; i++) { + bytes32 k = b[i]; + /// @solidity memory-safe-assembly + assembly { + mstore(add(result, add(32, mul(32, i))), k) + } + } + + return result; + } +} diff --git a/lib/forge-std/src/StdStyle.sol b/lib/forge-std/src/StdStyle.sol new file mode 100644 index 0000000..d371e0c --- /dev/null +++ b/lib/forge-std/src/StdStyle.sol @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +import {VmSafe} from "./Vm.sol"; + +library StdStyle { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + string constant RED = "\u001b[91m"; + string constant GREEN = "\u001b[92m"; + string constant YELLOW = "\u001b[93m"; + string constant BLUE = "\u001b[94m"; + string constant MAGENTA = "\u001b[95m"; + string constant CYAN = "\u001b[96m"; + string constant BOLD = "\u001b[1m"; + string constant DIM = "\u001b[2m"; + string constant ITALIC = "\u001b[3m"; + string constant UNDERLINE = "\u001b[4m"; + string constant INVERSE = "\u001b[7m"; + string constant RESET = "\u001b[0m"; + + function styleConcat(string memory style, string memory self) private pure returns (string memory) { + return string(abi.encodePacked(style, self, RESET)); + } + + function red(string memory self) internal pure returns (string memory) { + return styleConcat(RED, self); + } + + function red(uint256 self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function red(int256 self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function red(address self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function red(bool self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function redBytes(bytes memory self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function redBytes32(bytes32 self) internal pure returns (string memory) { + return red(vm.toString(self)); + } + + function green(string memory self) internal pure returns (string memory) { + return styleConcat(GREEN, self); + } + + function green(uint256 self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function green(int256 self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function green(address self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function green(bool self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function greenBytes(bytes memory self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function greenBytes32(bytes32 self) internal pure returns (string memory) { + return green(vm.toString(self)); + } + + function yellow(string memory self) internal pure returns (string memory) { + return styleConcat(YELLOW, self); + } + + function yellow(uint256 self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellow(int256 self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellow(address self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellow(bool self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellowBytes(bytes memory self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function yellowBytes32(bytes32 self) internal pure returns (string memory) { + return yellow(vm.toString(self)); + } + + function blue(string memory self) internal pure returns (string memory) { + return styleConcat(BLUE, self); + } + + function blue(uint256 self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blue(int256 self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blue(address self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blue(bool self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blueBytes(bytes memory self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function blueBytes32(bytes32 self) internal pure returns (string memory) { + return blue(vm.toString(self)); + } + + function magenta(string memory self) internal pure returns (string memory) { + return styleConcat(MAGENTA, self); + } + + function magenta(uint256 self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magenta(int256 self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magenta(address self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magenta(bool self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magentaBytes(bytes memory self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function magentaBytes32(bytes32 self) internal pure returns (string memory) { + return magenta(vm.toString(self)); + } + + function cyan(string memory self) internal pure returns (string memory) { + return styleConcat(CYAN, self); + } + + function cyan(uint256 self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyan(int256 self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyan(address self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyan(bool self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyanBytes(bytes memory self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function cyanBytes32(bytes32 self) internal pure returns (string memory) { + return cyan(vm.toString(self)); + } + + function bold(string memory self) internal pure returns (string memory) { + return styleConcat(BOLD, self); + } + + function bold(uint256 self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function bold(int256 self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function bold(address self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function bold(bool self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function boldBytes(bytes memory self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function boldBytes32(bytes32 self) internal pure returns (string memory) { + return bold(vm.toString(self)); + } + + function dim(string memory self) internal pure returns (string memory) { + return styleConcat(DIM, self); + } + + function dim(uint256 self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dim(int256 self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dim(address self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dim(bool self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dimBytes(bytes memory self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function dimBytes32(bytes32 self) internal pure returns (string memory) { + return dim(vm.toString(self)); + } + + function italic(string memory self) internal pure returns (string memory) { + return styleConcat(ITALIC, self); + } + + function italic(uint256 self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italic(int256 self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italic(address self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italic(bool self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italicBytes(bytes memory self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function italicBytes32(bytes32 self) internal pure returns (string memory) { + return italic(vm.toString(self)); + } + + function underline(string memory self) internal pure returns (string memory) { + return styleConcat(UNDERLINE, self); + } + + function underline(uint256 self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underline(int256 self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underline(address self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underline(bool self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underlineBytes(bytes memory self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function underlineBytes32(bytes32 self) internal pure returns (string memory) { + return underline(vm.toString(self)); + } + + function inverse(string memory self) internal pure returns (string memory) { + return styleConcat(INVERSE, self); + } + + function inverse(uint256 self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverse(int256 self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverse(address self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverse(bool self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverseBytes(bytes memory self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } + + function inverseBytes32(bytes32 self) internal pure returns (string memory) { + return inverse(vm.toString(self)); + } +} diff --git a/lib/forge-std/src/StdUtils.sol b/lib/forge-std/src/StdUtils.sol new file mode 100644 index 0000000..ad9566e --- /dev/null +++ b/lib/forge-std/src/StdUtils.sol @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import {IMulticall3} from "./interfaces/IMulticall3.sol"; +import {VmSafe} from "./Vm.sol"; + +abstract contract StdUtils { + /*////////////////////////////////////////////////////////////////////////// + CONSTANTS + //////////////////////////////////////////////////////////////////////////*/ + + IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11); + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67; + uint256 private constant INT256_MIN_ABS = + 57896044618658097711785492504343953926634992332820282019728792003956564819968; + uint256 private constant SECP256K1_ORDER = + 115792089237316195423570985008687907852837564279074904382605163141518161494337; + uint256 private constant UINT256_MAX = + 115792089237316195423570985008687907853269984665640564039457584007913129639935; + + // Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy. + address private constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C; + + /*////////////////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) { + require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min."); + // If x is between min and max, return x directly. This is to ensure that dictionary values + // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188 + if (x >= min && x <= max) return x; + + uint256 size = max - min + 1; + + // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side. + // This helps ensure coverage of the min/max values. + if (x <= 3 && size > x) return min + x; + if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x); + + // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive. + if (x > max) { + uint256 diff = x - max; + uint256 rem = diff % size; + if (rem == 0) return max; + result = min + rem - 1; + } else if (x < min) { + uint256 diff = min - x; + uint256 rem = diff % size; + if (rem == 0) return min; + result = max - rem + 1; + } + } + + function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) { + result = _bound(x, min, max); + console2_log("Bound Result", result); + } + + function _bound(int256 x, int256 min, int256 max) internal pure virtual returns (int256 result) { + require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min."); + + // Shifting all int256 values to uint256 to use _bound function. The range of two types are: + // int256 : -(2**255) ~ (2**255 - 1) + // uint256: 0 ~ (2**256 - 1) + // So, add 2**255, INT256_MIN_ABS to the integer values. + // + // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow. + // So, use `~uint256(x) + 1` instead. + uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS); + uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS); + uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS); + + uint256 y = _bound(_x, _min, _max); + + // To move it back to int256 value, subtract INT256_MIN_ABS at here. + result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS); + } + + function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) { + result = _bound(x, min, max); + console2_log("Bound result", vm.toString(result)); + } + + function boundPrivateKey(uint256 privateKey) internal pure virtual returns (uint256 result) { + result = _bound(privateKey, 1, SECP256K1_ORDER - 1); + } + + function bytesToUint(bytes memory b) internal pure virtual returns (uint256) { + require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256)); + } + + /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce + /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol) + function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) { + // forgefmt: disable-start + // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0. + // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it. + if (nonce == 0x00) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80)))); + if (nonce <= 0x7f) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce)))); + + // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length. + if (nonce <= 2**8 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce)))); + if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce)))); + if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce)))); + // forgefmt: disable-end + + // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp + // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce) + // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex) + // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex) + // We assume nobody can have a nonce large enough to require more than 32 bytes. + return addressFromLast20Bytes( + keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce))) + ); + } + + function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer) + internal + pure + virtual + returns (address) + { + return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash))); + } + + /// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer + function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) { + return computeCreate2Address(salt, initCodeHash, CREATE2_FACTORY); + } + + /// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments + /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode + function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) { + return hashInitCode(creationCode, ""); + } + + /// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2 + /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode + /// @param args the ABI-encoded arguments to the constructor of C + function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(creationCode, args)); + } + + // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses. + function getTokenBalances(address token, address[] memory addresses) + internal + virtual + returns (uint256[] memory balances) + { + uint256 tokenCodeSize; + assembly { + tokenCodeSize := extcodesize(token) + } + require(tokenCodeSize > 0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract."); + + // ABI encode the aggregate call to Multicall3. + uint256 length = addresses.length; + IMulticall3.Call[] memory calls = new IMulticall3.Call[](length); + for (uint256 i = 0; i < length; ++i) { + // 0x70a08231 = bytes4("balanceOf(address)")) + calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))}); + } + + // Make the aggregate call. + (, bytes[] memory returnData) = multicall.aggregate(calls); + + // ABI decode the return data and return the balances. + balances = new uint256[](length); + for (uint256 i = 0; i < length; ++i) { + balances[i] = abi.decode(returnData[i], (uint256)); + } + } + + /*////////////////////////////////////////////////////////////////////////// + PRIVATE FUNCTIONS + //////////////////////////////////////////////////////////////////////////*/ + + function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) { + return address(uint160(uint256(bytesValue))); + } + + // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere. + + function console2_log(string memory p0, uint256 p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + status; + } + + function console2_log(string memory p0, string memory p1) private view { + (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1)); + status; + } +} diff --git a/lib/forge-std/src/Test.sol b/lib/forge-std/src/Test.sol new file mode 100644 index 0000000..743c183 --- /dev/null +++ b/lib/forge-std/src/Test.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// 💬 ABOUT +// Forge Std's default Test. + +// 🧩 MODULES +import {console} from "./console.sol"; +import {console2} from "./console2.sol"; +import {safeconsole} from "./safeconsole.sol"; +import {StdAssertions} from "./StdAssertions.sol"; +import {StdChains} from "./StdChains.sol"; +import {StdCheats} from "./StdCheats.sol"; +import {stdError} from "./StdError.sol"; +import {StdInvariant} from "./StdInvariant.sol"; +import {stdJson} from "./StdJson.sol"; +import {stdMath} from "./StdMath.sol"; +import {StdStorage, stdStorage} from "./StdStorage.sol"; +import {StdStyle} from "./StdStyle.sol"; +import {StdUtils} from "./StdUtils.sol"; +import {Vm} from "./Vm.sol"; + +// 📦 BOILERPLATE +import {TestBase} from "./Base.sol"; +import {DSTest} from "ds-test/test.sol"; + +// ⭐️ TEST +abstract contract Test is TestBase, DSTest, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils { +// Note: IS_TEST() must return true. +// Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76. +} diff --git a/lib/forge-std/src/Vm.sol b/lib/forge-std/src/Vm.sol new file mode 100644 index 0000000..c6aed00 --- /dev/null +++ b/lib/forge-std/src/Vm.sol @@ -0,0 +1,743 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +// Cheatcodes are marked as view/pure/none using the following rules: +// 0. A call's observable behaviour includes its return value, logs, reverts and state writes, +// 1. If you can influence a later call's observable behaviour, you're neither `view` nor `pure (you are modifying some state be it the EVM, interpreter, filesystem, etc), +// 2. Otherwise if you can be influenced by an earlier call, or if reading some state, you're `view`, +// 3. Otherwise you're `pure`. + +// The `VmSafe` interface does not allow manipulation of the EVM state or other actions that may +// result in Script simulations differing from on-chain execution. It is recommended to only use +// these cheats in scripts. +interface VmSafe { + // ======== Types ======== + enum CallerMode { + None, + Broadcast, + RecurrentBroadcast, + Prank, + RecurrentPrank + } + + struct Log { + bytes32[] topics; + bytes data; + address emitter; + } + + struct Rpc { + string key; + string url; + } + + struct DirEntry { + string errorMessage; + string path; + uint64 depth; + bool isDir; + bool isSymlink; + } + + struct FsMetadata { + bool isDir; + bool isSymlink; + uint256 length; + bool readOnly; + uint256 modified; + uint256 accessed; + uint256 created; + } + + struct Wallet { + address addr; + uint256 publicKeyX; + uint256 publicKeyY; + uint256 privateKey; + } + + struct FfiResult { + int32 exitCode; + bytes stdout; + bytes stderr; + } + + // ======== EVM ======== + + // Gets the address for a given private key + function addr(uint256 privateKey) external pure returns (address keyAddr); + + // Gets the nonce of an account. + // See `getNonce(Wallet memory wallet)` for an alternative way to manage users and get their nonces. + function getNonce(address account) external view returns (uint64 nonce); + + // Loads a storage slot from an address + function load(address target, bytes32 slot) external view returns (bytes32 data); + + // Signs data + function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s); + + // -------- Record Storage -------- + // Records all storage reads and writes + function record() external; + + // Gets all accessed reads and write slot from a `vm.record` session, for a given address + function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots); + + // -------- Recording Map Writes -------- + + // Starts recording all map SSTOREs for later retrieval. + function startMappingRecording() external; + + // Stops recording all map SSTOREs for later retrieval and clears the recorded data. + function stopMappingRecording() external; + + // Gets the number of elements in the mapping at the given slot, for a given address. + function getMappingLength(address target, bytes32 mappingSlot) external returns (uint256 length); + + // Gets the elements at index idx of the mapping at the given slot, for a given address. The + // index must be less than the length of the mapping (i.e. the number of keys in the mapping). + function getMappingSlotAt(address target, bytes32 mappingSlot, uint256 idx) external returns (bytes32 value); + + // Gets the map key and parent of a mapping at a given slot, for a given address. + function getMappingKeyAndParentOf(address target, bytes32 elementSlot) + external + returns (bool found, bytes32 key, bytes32 parent); + + // -------- Record Logs -------- + // Record all the transaction logs + function recordLogs() external; + + // Gets all the recorded logs + function getRecordedLogs() external returns (Log[] memory logs); + + // -------- Gas Metering -------- + // It's recommend to use the `noGasMetering` modifier included with forge-std, instead of + // using these functions directly. + + // Pauses gas metering (i.e. gas usage is not counted). Noop if already paused. + function pauseGasMetering() external; + + // Resumes gas metering (i.e. gas usage is counted again). Noop if already on. + function resumeGasMetering() external; + + // ======== Test Configuration ======== + + // If the condition is false, discard this run's fuzz inputs and generate new ones. + function assume(bool condition) external pure; + + // Writes a breakpoint to jump to in the debugger + function breakpoint(string calldata char) external; + + // Writes a conditional breakpoint to jump to in the debugger + function breakpoint(string calldata char, bool value) external; + + // Returns the RPC url for the given alias + function rpcUrl(string calldata rpcAlias) external view returns (string memory json); + + // Returns all rpc urls and their aliases `[alias, url][]` + function rpcUrls() external view returns (string[2][] memory urls); + + // Returns all rpc urls and their aliases as structs. + function rpcUrlStructs() external view returns (Rpc[] memory urls); + + // Suspends execution of the main thread for `duration` milliseconds + function sleep(uint256 duration) external; + + // ======== OS and Filesystem ======== + + // -------- Metadata -------- + + // Returns true if the given path points to an existing entity, else returns false + function exists(string calldata path) external returns (bool result); + + // Given a path, query the file system to get information about a file, directory, etc. + function fsMetadata(string calldata path) external view returns (FsMetadata memory metadata); + + // Returns true if the path exists on disk and is pointing at a directory, else returns false + function isDir(string calldata path) external returns (bool result); + + // Returns true if the path exists on disk and is pointing at a regular file, else returns false + function isFile(string calldata path) external returns (bool result); + + // Get the path of the current project root. + function projectRoot() external view returns (string memory path); + + // Returns the time since unix epoch in milliseconds + function unixTime() external returns (uint256 milliseconds); + + // -------- Reading and writing -------- + + // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine. + // `path` is relative to the project root. + function closeFile(string calldata path) external; + + // Copies the contents of one file to another. This function will **overwrite** the contents of `to`. + // On success, the total number of bytes copied is returned and it is equal to the length of the `to` file as reported by `metadata`. + // Both `from` and `to` are relative to the project root. + function copyFile(string calldata from, string calldata to) external returns (uint64 copied); + + // Creates a new, empty directory at the provided path. + // This cheatcode will revert in the following situations, but is not limited to just these cases: + // - User lacks permissions to modify `path`. + // - A parent of the given path doesn't exist and `recursive` is false. + // - `path` already exists and `recursive` is false. + // `path` is relative to the project root. + function createDir(string calldata path, bool recursive) external; + + // Reads the directory at the given path recursively, up to `max_depth`. + // `max_depth` defaults to 1, meaning only the direct children of the given directory will be returned. + // Follows symbolic links if `follow_links` is true. + function readDir(string calldata path) external view returns (DirEntry[] memory entries); + function readDir(string calldata path, uint64 maxDepth) external view returns (DirEntry[] memory entries); + function readDir(string calldata path, uint64 maxDepth, bool followLinks) + external + view + returns (DirEntry[] memory entries); + + // Reads the entire content of file to string. `path` is relative to the project root. + function readFile(string calldata path) external view returns (string memory data); + + // Reads the entire content of file as binary. `path` is relative to the project root. + function readFileBinary(string calldata path) external view returns (bytes memory data); + + // Reads next line of file to string. + function readLine(string calldata path) external view returns (string memory line); + + // Reads a symbolic link, returning the path that the link points to. + // This cheatcode will revert in the following situations, but is not limited to just these cases: + // - `path` is not a symbolic link. + // - `path` does not exist. + function readLink(string calldata linkPath) external view returns (string memory targetPath); + + // Removes a directory at the provided path. + // This cheatcode will revert in the following situations, but is not limited to just these cases: + // - `path` doesn't exist. + // - `path` isn't a directory. + // - User lacks permissions to modify `path`. + // - The directory is not empty and `recursive` is false. + // `path` is relative to the project root. + function removeDir(string calldata path, bool recursive) external; + + // Removes a file from the filesystem. + // This cheatcode will revert in the following situations, but is not limited to just these cases: + // - `path` points to a directory. + // - The file doesn't exist. + // - The user lacks permissions to remove the file. + // `path` is relative to the project root. + function removeFile(string calldata path) external; + + // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does. + // `path` is relative to the project root. + function writeFile(string calldata path, string calldata data) external; + + // Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does. + // `path` is relative to the project root. + function writeFileBinary(string calldata path, bytes calldata data) external; + + // Writes line to file, creating a file if it does not exist. + // `path` is relative to the project root. + function writeLine(string calldata path, string calldata data) external; + + // -------- Foreign Function Interface -------- + + // Performs a foreign function call via the terminal + function ffi(string[] calldata commandInput) external returns (bytes memory result); + + // Performs a foreign function call via terminal and returns the exit code, stdout, and stderr + function tryFfi(string[] calldata commandInput) external returns (FfiResult memory result); + + // ======== Environment Variables ======== + + // Sets environment variables + function setEnv(string calldata name, string calldata value) external; + + // Reads environment variables, (name) => (value) + function envBool(string calldata name) external view returns (bool value); + function envUint(string calldata name) external view returns (uint256 value); + function envInt(string calldata name) external view returns (int256 value); + function envAddress(string calldata name) external view returns (address value); + function envBytes32(string calldata name) external view returns (bytes32 value); + function envString(string calldata name) external view returns (string memory value); + function envBytes(string calldata name) external view returns (bytes memory value); + + // Reads environment variables as arrays + function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value); + function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value); + function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value); + function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value); + function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value); + function envString(string calldata name, string calldata delim) external view returns (string[] memory value); + function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value); + + // Read environment variables with default value + function envOr(string calldata name, bool defaultValue) external returns (bool value); + function envOr(string calldata name, uint256 defaultValue) external returns (uint256 value); + function envOr(string calldata name, int256 defaultValue) external returns (int256 value); + function envOr(string calldata name, address defaultValue) external returns (address value); + function envOr(string calldata name, bytes32 defaultValue) external returns (bytes32 value); + function envOr(string calldata name, string calldata defaultValue) external returns (string memory value); + function envOr(string calldata name, bytes calldata defaultValue) external returns (bytes memory value); + + // Read environment variables as arrays with default value + function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue) + external + returns (bool[] memory value); + function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue) + external + returns (uint256[] memory value); + function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue) + external + returns (int256[] memory value); + function envOr(string calldata name, string calldata delim, address[] calldata defaultValue) + external + returns (address[] memory value); + function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue) + external + returns (bytes32[] memory value); + function envOr(string calldata name, string calldata delim, string[] calldata defaultValue) + external + returns (string[] memory value); + function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue) + external + returns (bytes[] memory value); + + // ======== User Management ======== + + // Derives a private key from the name, labels the account with that name, and returns the wallet + function createWallet(string calldata walletLabel) external returns (Wallet memory wallet); + + // Generates a wallet from the private key and returns the wallet + function createWallet(uint256 privateKey) external returns (Wallet memory wallet); + + // Generates a wallet from the private key, labels the account with that name, and returns the wallet + function createWallet(uint256 privateKey, string calldata walletLabel) external returns (Wallet memory wallet); + + // Gets the label for the specified address + function getLabel(address account) external returns (string memory currentLabel); + + // Get nonce for a Wallet. + // See `getNonce(address account)` for an alternative way to get a nonce. + function getNonce(Wallet calldata wallet) external returns (uint64 nonce); + + // Labels an address in call traces + function label(address account, string calldata newLabel) external; + + // Signs data, (Wallet, digest) => (v, r, s) + function sign(Wallet calldata wallet, bytes32 digest) external returns (uint8 v, bytes32 r, bytes32 s); + + // ======== Scripts ======== + + // -------- Broadcasting Transactions -------- + + // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain + function broadcast() external; + + // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain + function broadcast(address signer) external; + + // Has the next call (at this call depth only) create a transaction with the private key provided as the sender that can later be signed and sent onchain + function broadcast(uint256 privateKey) external; + + // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain + function startBroadcast() external; + + // Has all subsequent calls (at this call depth only) create transactions with the address provided that can later be signed and sent onchain + function startBroadcast(address signer) external; + + // Has all subsequent calls (at this call depth only) create transactions with the private key provided that can later be signed and sent onchain + function startBroadcast(uint256 privateKey) external; + + // Stops collecting onchain transactions + function stopBroadcast() external; + + // -------- Key Management -------- + + // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index} + function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey); + + // Derive a private key from a provided mnenomic string (or mnenomic file path) at {derivationPath}{index} + function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index) + external + pure + returns (uint256 privateKey); + + // Adds a private key to the local forge wallet and returns the address + function rememberKey(uint256 privateKey) external returns (address keyAddr); + + // ======== Utilities ======== + + // Convert values to a string + function toString(address value) external pure returns (string memory stringifiedValue); + function toString(bytes calldata value) external pure returns (string memory stringifiedValue); + function toString(bytes32 value) external pure returns (string memory stringifiedValue); + function toString(bool value) external pure returns (string memory stringifiedValue); + function toString(uint256 value) external pure returns (string memory stringifiedValue); + function toString(int256 value) external pure returns (string memory stringifiedValue); + + // Convert values from a string + function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue); + function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); + function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue); + function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue); + function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue); + function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); + + // Gets the creation bytecode from an artifact file. Takes in the relative path to the json file + function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode); + + // Gets the deployed bytecode from an artifact file. Takes in the relative path to the json file + function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode); + + // ======== JSON Parsing and Manipulation ======== + + // -------- Reading -------- + + // NOTE: Please read https://book.getfoundry.sh/cheatcodes/parse-json to understand the + // limitations and caveats of the JSON parsing cheats. + + // Checks if a key exists in a JSON object. + function keyExists(string calldata json, string calldata key) external view returns (bool); + + // Given a string of JSON, return it as ABI-encoded + function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData); + function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData); + + // The following parseJson cheatcodes will do type coercion, for the type that they indicate. + // For example, parseJsonUint will coerce all values to a uint256. That includes stringified numbers '12' + // and hex numbers '0xEF'. + // Type coercion works ONLY for discrete values or arrays. That means that the key must return a value or array, not + // a JSON object. + function parseJsonUint(string calldata json, string calldata key) external pure returns (uint256); + function parseJsonUintArray(string calldata json, string calldata key) external pure returns (uint256[] memory); + function parseJsonInt(string calldata json, string calldata key) external pure returns (int256); + function parseJsonIntArray(string calldata json, string calldata key) external pure returns (int256[] memory); + function parseJsonBool(string calldata json, string calldata key) external pure returns (bool); + function parseJsonBoolArray(string calldata json, string calldata key) external pure returns (bool[] memory); + function parseJsonAddress(string calldata json, string calldata key) external pure returns (address); + function parseJsonAddressArray(string calldata json, string calldata key) + external + pure + returns (address[] memory); + function parseJsonString(string calldata json, string calldata key) external pure returns (string memory); + function parseJsonStringArray(string calldata json, string calldata key) external pure returns (string[] memory); + function parseJsonBytes(string calldata json, string calldata key) external pure returns (bytes memory); + function parseJsonBytesArray(string calldata json, string calldata key) external pure returns (bytes[] memory); + function parseJsonBytes32(string calldata json, string calldata key) external pure returns (bytes32); + function parseJsonBytes32Array(string calldata json, string calldata key) + external + pure + returns (bytes32[] memory); + + // Returns array of keys for a JSON object + function parseJsonKeys(string calldata json, string calldata key) external pure returns (string[] memory keys); + + // -------- Writing -------- + + // NOTE: Please read https://book.getfoundry.sh/cheatcodes/serialize-json to understand how + // to use the serialization cheats. + + // Serialize a key and value to a JSON object stored in-memory that can be later written to a file + // It returns the stringified version of the specific JSON file up to that moment. + function serializeJson(string calldata objectKey, string calldata value) external returns (string memory json); + function serializeBool(string calldata objectKey, string calldata valueKey, bool value) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256 value) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address value) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string calldata value) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value) + external + returns (string memory json); + + function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values) + external + returns (string memory json); + function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values) + external + returns (string memory json); + function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values) + external + returns (string memory json); + function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values) + external + returns (string memory json); + function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values) + external + returns (string memory json); + function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values) + external + returns (string memory json); + function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values) + external + returns (string memory json); + + // NOTE: Please read https://book.getfoundry.sh/cheatcodes/write-json to understand how + // to use the JSON writing cheats. + + // Write a serialized JSON object to a file. If the file exists, it will be overwritten. + function writeJson(string calldata json, string calldata path) external; + + // Write a serialized JSON object to an **existing** JSON file, replacing a value with key = + // This is useful to replace a specific value of a JSON file, without having to parse the entire thing + function writeJson(string calldata json, string calldata path, string calldata valueKey) external; +} + +// The `Vm` interface does allow manipulation of the EVM state. These are all intended to be used +// in tests, but it is not recommended to use these cheats in scripts. +interface Vm is VmSafe { + // ======== EVM ======== + + // -------- Block and Transaction Properties -------- + + // Sets block.chainid + function chainId(uint256 newChainId) external; + + // Sets block.coinbase + function coinbase(address newCoinbase) external; + + // Sets block.difficulty + // Not available on EVM versions from Paris onwards. Use `prevrandao` instead. + // If used on unsupported EVM versions it will revert. + function difficulty(uint256 newDifficulty) external; + + // Sets block.basefee + function fee(uint256 newBasefee) external; + + // Sets block.prevrandao + // Not available on EVM versions before Paris. Use `difficulty` instead. + // If used on unsupported EVM versions it will revert. + function prevrandao(bytes32 newPrevrandao) external; + + // Sets block.height + function roll(uint256 newHeight) external; + + // Sets tx.gasprice + function txGasPrice(uint256 newGasPrice) external; + + // Sets block.timestamp + function warp(uint256 newTimestamp) external; + + // -------- Account State -------- + + // Sets an address' balance + function deal(address account, uint256 newBalance) external; + + // Sets an address' code + function etch(address target, bytes calldata newRuntimeBytecode) external; + + // Resets the nonce of an account to 0 for EOAs and 1 for contract accounts + function resetNonce(address account) external; + + // Sets the nonce of an account; must be higher than the current nonce of the account + function setNonce(address account, uint64 newNonce) external; + + // Sets the nonce of an account to an arbitrary value + function setNonceUnsafe(address account, uint64 newNonce) external; + + // Stores a value to an address' storage slot. + function store(address target, bytes32 slot, bytes32 value) external; + + // -------- Call Manipulation -------- + // --- Mocks --- + + // Clears all mocked calls + function clearMockedCalls() external; + + // Mocks a call to an address, returning specified data. + // Calldata can either be strict or a partial match, e.g. if you only + // pass a Solidity selector to the expected calldata, then the entire Solidity + // function will be mocked. + function mockCall(address callee, bytes calldata data, bytes calldata returnData) external; + + // Mocks a call to an address with a specific msg.value, returning specified data. + // Calldata match takes precedence over msg.value in case of ambiguity. + function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external; + + // Reverts a call to an address with specified revert data. + function mockCallRevert(address callee, bytes calldata data, bytes calldata revertData) external; + + // Reverts a call to an address with a specific msg.value, with specified revert data. + function mockCallRevert(address callee, uint256 msgValue, bytes calldata data, bytes calldata revertData) + external; + + // --- Impersonation (pranks) --- + + // Sets the *next* call's msg.sender to be the input address + function prank(address msgSender) external; + + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called + function startPrank(address msgSender) external; + + // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input + function prank(address msgSender, address txOrigin) external; + + // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input + function startPrank(address msgSender, address txOrigin) external; + + // Resets subsequent calls' msg.sender to be `address(this)` + function stopPrank() external; + + // Reads the current `msg.sender` and `tx.origin` from state and reports if there is any active caller modification + function readCallers() external returns (CallerMode callerMode, address msgSender, address txOrigin); + + // -------- State Snapshots -------- + + // Snapshot the current state of the evm. + // Returns the id of the snapshot that was created. + // To revert a snapshot use `revertTo` + function snapshot() external returns (uint256 snapshotId); + + // Revert the state of the EVM to a previous snapshot + // Takes the snapshot id to revert to. + // This deletes the snapshot and all snapshots taken after the given snapshot id. + function revertTo(uint256 snapshotId) external returns (bool success); + + // -------- Forking -------- + // --- Creation and Selection --- + + // Returns the identifier of the currently active fork. Reverts if no fork is currently active. + function activeFork() external view returns (uint256 forkId); + + // Creates a new fork with the given endpoint and block and returns the identifier of the fork + function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + + // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork + function createFork(string calldata urlOrAlias) external returns (uint256 forkId); + + // Creates a new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before the transaction, + // and returns the identifier of the fork + function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + + // Creates and also selects a new fork with the given endpoint and block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId); + + // Creates and also selects new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before + // the transaction, returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId); + + // Creates and also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork + function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId); + + // Updates the currently active fork to given block number + // This is similar to `roll` but for the currently active fork + function rollFork(uint256 blockNumber) external; + + // Updates the currently active fork to given transaction + // this will `rollFork` with the number of the block the transaction was mined in and replays all transaction mined before it in the block + function rollFork(bytes32 txHash) external; + + // Updates the given fork to given block number + function rollFork(uint256 forkId, uint256 blockNumber) external; + + // Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block + function rollFork(uint256 forkId, bytes32 txHash) external; + + // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active. + function selectFork(uint256 forkId) external; + + // Fetches the given transaction from the active fork and executes it on the current state + function transact(bytes32 txHash) external; + + // Fetches the given transaction from the given fork and executes it on the current state + function transact(uint256 forkId, bytes32 txHash) external; + + // --- Behavior --- + + // In forking mode, explicitly grant the given address cheatcode access + function allowCheatcodes(address account) external; + + // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup + // Meaning, changes made to the state of this account will be kept when switching forks + function makePersistent(address account) external; + function makePersistent(address account0, address account1) external; + function makePersistent(address account0, address account1, address account2) external; + function makePersistent(address[] calldata accounts) external; + + // Revokes persistent status from the address, previously added via `makePersistent` + function revokePersistent(address account) external; + function revokePersistent(address[] calldata accounts) external; + + // Returns true if the account is marked as persistent + function isPersistent(address account) external view returns (bool persistent); + + // ======== Test Assertions and Utilities ======== + + // Expects a call to an address with the specified calldata. + // Calldata can either be a strict or a partial match + function expectCall(address callee, bytes calldata data) external; + + // Expects given number of calls to an address with the specified calldata. + function expectCall(address callee, bytes calldata data, uint64 count) external; + + // Expects a call to an address with the specified msg.value and calldata + function expectCall(address callee, uint256 msgValue, bytes calldata data) external; + + // Expects given number of calls to an address with the specified msg.value and calldata + function expectCall(address callee, uint256 msgValue, bytes calldata data, uint64 count) external; + + // Expect a call to an address with the specified msg.value, gas, and calldata. + function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data) external; + + // Expects given number of calls to an address with the specified msg.value, gas, and calldata. + function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data, uint64 count) external; + + // Expect a call to an address with the specified msg.value and calldata, and a *minimum* amount of gas. + function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data) external; + + // Expect given number of calls to an address with the specified msg.value and calldata, and a *minimum* amount of gas. + function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data, uint64 count) + external; + + // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData). + // Call this function, then emit an event, then call a function. Internally after the call, we check if + // logs were emitted in the expected order with the expected topics and data (as specified by the booleans). + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external; + + // Same as the previous method, but also checks supplied address against emitting contract. + function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter) + external; + + // Prepare an expected log with all topic and data checks enabled. + // Call this function, then emit an event, then call a function. Internally after the call, we check if + // logs were emitted in the expected order with the expected topics and data. + function expectEmit() external; + + // Same as the previous method, but also checks supplied address against emitting contract. + function expectEmit(address emitter) external; + + // Expects an error on next call that exactly matches the revert data. + function expectRevert(bytes calldata revertData) external; + + // Expects an error on next call that starts with the revert data. + function expectRevert(bytes4 revertData) external; + + // Expects an error on next call with any revert data. + function expectRevert() external; + + // Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the current subcontext. If any other + // memory is written to, the test will fail. Can be called multiple times to add more ranges to the set. + function expectSafeMemory(uint64 min, uint64 max) external; + + // Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the next created subcontext. + // If any other memory is written to, the test will fail. Can be called multiple times to add more ranges + // to the set. + function expectSafeMemoryCall(uint64 min, uint64 max) external; + + // Marks a test as skipped. Must be called at the top of the test. + function skip(bool skipTest) external; +} diff --git a/lib/forge-std/src/console.sol b/lib/forge-std/src/console.sol new file mode 100644 index 0000000..ad57e53 --- /dev/null +++ b/lib/forge-std/src/console.sol @@ -0,0 +1,1533 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +library console { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _sendLogPayload(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal view { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); + } + + function logUint(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function logString(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); + } + + function log(string memory p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); + } + + function log(uint p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); + } + + function log(uint p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); + } + + function log(uint p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); + } + + function log(string memory p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); + } + + function log(bool p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); + } + + function log(address p0, string memory p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); + } + + function log(uint p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); + } + + function log(uint p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); + } + + function log(uint p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); + } + + function log(uint p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); + } + + function log(uint p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); + } + + function log(uint p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); + } + + function log(uint p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); + } + + function log(uint p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); + } + + function log(uint p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); + } + + function log(uint p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); + } + + function log(uint p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); + } + + function log(uint p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); + } + + function log(bool p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); + } + + function log(bool p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); + } + + function log(bool p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); + } + + function log(address p0, uint p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); + } + + function log(address p0, uint p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); + } + + function log(address p0, uint p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal view { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/forge-std/src/console2.sol b/lib/forge-std/src/console2.sol new file mode 100644 index 0000000..c1e2cd7 --- /dev/null +++ b/lib/forge-std/src/console2.sol @@ -0,0 +1,1558 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +/// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should +/// use `int256` and `uint256`. This modified version fixes that. This version is recommended +/// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in +/// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`. +/// Reference: https://github.com/NomicFoundation/hardhat/issues/2178 +library console2 { + address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); + + function _castLogPayloadViewToPure( + function(bytes memory) internal view fnIn + ) internal pure returns (function(bytes memory) internal pure fnOut) { + assembly { + fnOut := fnIn + } + } + + function _sendLogPayload(bytes memory payload) internal pure { + _castLogPayloadViewToPure(_sendLogPayloadView)(payload); + } + + function _sendLogPayloadView(bytes memory payload) private view { + uint256 payloadLength = payload.length; + address consoleAddress = CONSOLE_ADDRESS; + /// @solidity memory-safe-assembly + assembly { + let payloadStart := add(payload, 32) + let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) + } + } + + function log() internal pure { + _sendLogPayload(abi.encodeWithSignature("log()")); + } + + function logInt(int256 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function logUint(uint256 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function logString(string memory p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function logBool(bool p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function logAddress(address p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function logBytes(bytes memory p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); + } + + function logBytes1(bytes1 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); + } + + function logBytes2(bytes2 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); + } + + function logBytes3(bytes3 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); + } + + function logBytes4(bytes4 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); + } + + function logBytes5(bytes5 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); + } + + function logBytes6(bytes6 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); + } + + function logBytes7(bytes7 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); + } + + function logBytes8(bytes8 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); + } + + function logBytes9(bytes9 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); + } + + function logBytes10(bytes10 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); + } + + function logBytes11(bytes11 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); + } + + function logBytes12(bytes12 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); + } + + function logBytes13(bytes13 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); + } + + function logBytes14(bytes14 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); + } + + function logBytes15(bytes15 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); + } + + function logBytes16(bytes16 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); + } + + function logBytes17(bytes17 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); + } + + function logBytes18(bytes18 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); + } + + function logBytes19(bytes19 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); + } + + function logBytes20(bytes20 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); + } + + function logBytes21(bytes21 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); + } + + function logBytes22(bytes22 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); + } + + function logBytes23(bytes23 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); + } + + function logBytes24(bytes24 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); + } + + function logBytes25(bytes25 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); + } + + function logBytes26(bytes26 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); + } + + function logBytes27(bytes27 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); + } + + function logBytes28(bytes28 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); + } + + function logBytes29(bytes29 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); + } + + function logBytes30(bytes30 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); + } + + function logBytes31(bytes31 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); + } + + function logBytes32(bytes32 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); + } + + function log(uint256 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0)); + } + + function log(int256 p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(int256)", p0)); + } + + function log(string memory p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); + } + + function log(bool p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); + } + + function log(address p0) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); + } + + function log(uint256 p0, uint256 p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1)); + } + + function log(uint256 p0, string memory p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1)); + } + + function log(uint256 p0, bool p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1)); + } + + function log(uint256 p0, address p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1)); + } + + function log(string memory p0, uint256 p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1)); + } + + function log(string memory p0, int256 p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1)); + } + + function log(string memory p0, string memory p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); + } + + function log(string memory p0, bool p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); + } + + function log(string memory p0, address p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); + } + + function log(bool p0, uint256 p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1)); + } + + function log(bool p0, string memory p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); + } + + function log(bool p0, bool p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); + } + + function log(bool p0, address p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); + } + + function log(address p0, uint256 p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1)); + } + + function log(address p0, string memory p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); + } + + function log(address p0, bool p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); + } + + function log(address p0, address p1) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); + } + + function log(uint256 p0, uint256 p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2)); + } + + function log(uint256 p0, string memory p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2)); + } + + function log(uint256 p0, bool p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2)); + } + + function log(uint256 p0, address p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2)); + } + + function log(string memory p0, uint256 p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); + } + + function log(string memory p0, string memory p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); + } + + function log(string memory p0, bool p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); + } + + function log(string memory p0, address p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2)); + } + + function log(string memory p0, address p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); + } + + function log(string memory p0, address p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); + } + + function log(string memory p0, address p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2)); + } + + function log(bool p0, uint256 p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); + } + + function log(bool p0, string memory p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); + } + + function log(bool p0, bool p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2)); + } + + function log(bool p0, bool p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); + } + + function log(bool p0, bool p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); + } + + function log(bool p0, bool p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); + } + + function log(bool p0, address p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2)); + } + + function log(bool p0, address p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); + } + + function log(bool p0, address p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); + } + + function log(bool p0, address p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2)); + } + + function log(address p0, uint256 p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2)); + } + + function log(address p0, string memory p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2)); + } + + function log(address p0, string memory p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); + } + + function log(address p0, string memory p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); + } + + function log(address p0, string memory p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); + } + + function log(address p0, bool p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2)); + } + + function log(address p0, bool p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); + } + + function log(address p0, bool p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); + } + + function log(address p0, bool p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); + } + + function log(address p0, address p1, uint256 p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2)); + } + + function log(address p0, address p1, string memory p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); + } + + function log(address p0, address p1, bool p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); + } + + function log(address p0, address p1, address p2) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, uint256 p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, string memory p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, bool p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3)); + } + + function log(uint256 p0, address p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, uint256 p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, string memory p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, bool p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); + } + + function log(string memory p0, address p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, uint256 p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, string memory p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, bool p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); + } + + function log(bool p0, address p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, uint256 p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, string memory p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, bool p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, uint256 p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, string memory p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, bool p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, uint256 p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, string memory p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, bool p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); + } + + function log(address p0, address p1, address p2, address p3) internal pure { + _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); + } + +} \ No newline at end of file diff --git a/lib/forge-std/src/interfaces/IERC1155.sol b/lib/forge-std/src/interfaces/IERC1155.sol new file mode 100644 index 0000000..f7dd2b4 --- /dev/null +++ b/lib/forge-std/src/interfaces/IERC1155.sol @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-1155 Multi Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-1155 +/// Note: The ERC-165 identifier for this interface is 0xd9b67a26. +interface IERC1155 is IERC165 { + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_id` argument MUST be the token type being transferred. + /// - The `_value` argument MUST be the number of tokens the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferSingle( + address indexed _operator, address indexed _from, address indexed _to, uint256 _id, uint256 _value + ); + + /// @dev + /// - Either `TransferSingle` or `TransferBatch` MUST emit when tokens are transferred, including zero value transfers as well as minting or burning (see "Safe Transfer Rules" section of the standard). + /// - The `_operator` argument MUST be the address of an account/contract that is approved to make the transfer (SHOULD be msg.sender). + /// - The `_from` argument MUST be the address of the holder whose balance is decreased. + /// - The `_to` argument MUST be the address of the recipient whose balance is increased. + /// - The `_ids` argument MUST be the list of tokens being transferred. + /// - The `_values` argument MUST be the list of number of tokens (matching the list and order of tokens specified in _ids) the holder balance is decreased by and match what the recipient balance is increased by. + /// - When minting/creating tokens, the `_from` argument MUST be set to `0x0` (i.e. zero address). + /// - When burning/destroying tokens, the `_to` argument MUST be set to `0x0` (i.e. zero address). + event TransferBatch( + address indexed _operator, address indexed _from, address indexed _to, uint256[] _ids, uint256[] _values + ); + + /// @dev MUST emit when approval for a second party/operator address to manage all tokens for an owner address is enabled or disabled (absence of an event assumes disabled). + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @dev MUST emit when the URI is updated for a token ID. URIs are defined in RFC 3986. + /// The URI MUST point to a JSON file that conforms to the "ERC-1155 Metadata URI JSON Schema". + event URI(string _value, uint256 indexed _id); + + /// @notice Transfers `_value` amount of an `_id` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if balance of holder for token `_id` is lower than the `_value` sent. + /// - MUST revert on any other error. + /// - MUST emit the `TransferSingle` event to reflect the balance change (see "Safe Transfer Rules" section of the standard). + /// - After the above conditions are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call `onERC1155Received` on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _id ID of the token type + /// @param _value Transfer amount + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to `onERC1155Received` on `_to` + function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data) external; + + /// @notice Transfers `_values` amount(s) of `_ids` from the `_from` address to the `_to` address specified (with safety call). + /// @dev Caller must be approved to manage the tokens being transferred out of the `_from` account (see "Approval" section of the standard). + /// - MUST revert if `_to` is the zero address. + /// - MUST revert if length of `_ids` is not the same as length of `_values`. + /// - MUST revert if any of the balance(s) of the holder(s) for token(s) in `_ids` is lower than the respective amount(s) in `_values` sent to the recipient. + /// - MUST revert on any other error. + /// - MUST emit `TransferSingle` or `TransferBatch` event(s) such that all the balance changes are reflected (see "Safe Transfer Rules" section of the standard). + /// - Balance changes and events MUST follow the ordering of the arrays (_ids[0]/_values[0] before _ids[1]/_values[1], etc). + /// - After the above conditions for the transfer(s) in the batch are met, this function MUST check if `_to` is a smart contract (e.g. code size > 0). If so, it MUST call the relevant `ERC1155TokenReceiver` hook(s) on `_to` and act appropriately (see "Safe Transfer Rules" section of the standard). + /// @param _from Source address + /// @param _to Target address + /// @param _ids IDs of each token type (order and length must match _values array) + /// @param _values Transfer amounts per token type (order and length must match _ids array) + /// @param _data Additional data with no specified format, MUST be sent unaltered in call to the `ERC1155TokenReceiver` hook(s) on `_to` + function safeBatchTransferFrom( + address _from, + address _to, + uint256[] calldata _ids, + uint256[] calldata _values, + bytes calldata _data + ) external; + + /// @notice Get the balance of an account's tokens. + /// @param _owner The address of the token holder + /// @param _id ID of the token + /// @return The _owner's balance of the token type requested + function balanceOf(address _owner, uint256 _id) external view returns (uint256); + + /// @notice Get the balance of multiple account/token pairs + /// @param _owners The addresses of the token holders + /// @param _ids ID of the tokens + /// @return The _owner's balance of the token types requested (i.e. balance for each (owner, id) pair) + function balanceOfBatch(address[] calldata _owners, uint256[] calldata _ids) + external + view + returns (uint256[] memory); + + /// @notice Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. + /// @dev MUST emit the ApprovalForAll event on success. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Queries the approval status of an operator for a given owner. + /// @param _owner The owner of the tokens + /// @param _operator Address of authorized operator + /// @return True if the operator is approved, false if not + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} diff --git a/lib/forge-std/src/interfaces/IERC165.sol b/lib/forge-std/src/interfaces/IERC165.sol new file mode 100644 index 0000000..9af4bf8 --- /dev/null +++ b/lib/forge-std/src/interfaces/IERC165.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +interface IERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} diff --git a/lib/forge-std/src/interfaces/IERC20.sol b/lib/forge-std/src/interfaces/IERC20.sol new file mode 100644 index 0000000..ba40806 --- /dev/null +++ b/lib/forge-std/src/interfaces/IERC20.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +/// @dev Interface of the ERC20 standard as defined in the EIP. +/// @dev This includes the optional name, symbol, and decimals metadata. +interface IERC20 { + /// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`). + event Transfer(address indexed from, address indexed to, uint256 value); + + /// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value` + /// is the new allowance. + event Approval(address indexed owner, address indexed spender, uint256 value); + + /// @notice Returns the amount of tokens in existence. + function totalSupply() external view returns (uint256); + + /// @notice Returns the amount of tokens owned by `account`. + function balanceOf(address account) external view returns (uint256); + + /// @notice Moves `amount` tokens from the caller's account to `to`. + function transfer(address to, uint256 amount) external returns (bool); + + /// @notice Returns the remaining number of tokens that `spender` is allowed + /// to spend on behalf of `owner` + function allowance(address owner, address spender) external view returns (uint256); + + /// @notice Sets `amount` as the allowance of `spender` over the caller's tokens. + /// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + function approve(address spender, uint256 amount) external returns (bool); + + /// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism. + /// `amount` is then deducted from the caller's allowance. + function transferFrom(address from, address to, uint256 amount) external returns (bool); + + /// @notice Returns the name of the token. + function name() external view returns (string memory); + + /// @notice Returns the symbol of the token. + function symbol() external view returns (string memory); + + /// @notice Returns the decimals places of the token. + function decimals() external view returns (uint8); +} diff --git a/lib/forge-std/src/interfaces/IERC4626.sol b/lib/forge-std/src/interfaces/IERC4626.sol new file mode 100644 index 0000000..bfe3a11 --- /dev/null +++ b/lib/forge-std/src/interfaces/IERC4626.sol @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC20.sol"; + +/// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in +/// https://eips.ethereum.org/EIPS/eip-4626 +interface IERC4626 is IERC20 { + event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares); + + event Withdraw( + address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares + ); + + /// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing. + /// @dev + /// - MUST be an ERC-20 token contract. + /// - MUST NOT revert. + function asset() external view returns (address assetTokenAddress); + + /// @notice Returns the total amount of the underlying asset that is “managed” by Vault. + /// @dev + /// - SHOULD include any compounding that occurs from yield. + /// - MUST be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT revert. + function totalAssets() external view returns (uint256 totalManagedAssets); + + /// @notice Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToShares(uint256 assets) external view returns (uint256 shares); + + /// @notice Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal + /// scenario where all the conditions are met. + /// @dev + /// - MUST NOT be inclusive of any fees that are charged against assets in the Vault. + /// - MUST NOT show any variations depending on the caller. + /// - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange. + /// - MUST NOT revert. + /// + /// NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the + /// “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and + /// from. + function convertToAssets(uint256 shares) external view returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver, + /// through a deposit call. + /// @dev + /// - MUST return a limited value if receiver is subject to some deposit limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited. + /// - MUST NOT revert. + function maxDeposit(address receiver) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit + /// call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called + /// in the same transaction. + /// - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the + /// deposit would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewDeposit(uint256 assets) external view returns (uint256 shares); + + /// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// deposit execution, and are accounted for during deposit. + /// - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function deposit(uint256 assets, address receiver) external returns (uint256 shares); + + /// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call. + /// @dev + /// - MUST return a limited value if receiver is subject to some mint limit. + /// - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted. + /// - MUST NOT revert. + function maxMint(address receiver) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given + /// current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call + /// in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the + /// same transaction. + /// - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint + /// would be accepted, regardless if the user has enough tokens approved, etc. + /// - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by minting. + function previewMint(uint256 shares) external view returns (uint256 assets); + + /// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens. + /// @dev + /// - MUST emit the Deposit event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint + /// execution, and are accounted for during mint. + /// - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not + /// approving enough underlying tokens to the Vault contract, etc). + /// + /// NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token. + function mint(uint256 shares, address receiver) external returns (uint256 assets); + + /// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the + /// Vault, through a withdraw call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST NOT revert. + function maxWithdraw(address owner) external view returns (uint256 maxAssets); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw + /// call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if + /// called + /// in the same transaction. + /// - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though + /// the withdrawal would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by depositing. + function previewWithdraw(uint256 assets) external view returns (uint256 shares); + + /// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// withdraw execution, and are accounted for during withdraw. + /// - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares); + + /// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault, + /// through a redeem call. + /// @dev + /// - MUST return a limited value if owner is subject to some withdrawal limit or timelock. + /// - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock. + /// - MUST NOT revert. + function maxRedeem(address owner) external view returns (uint256 maxShares); + + /// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block, + /// given current on-chain conditions. + /// @dev + /// - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call + /// in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the + /// same transaction. + /// - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the + /// redemption would be accepted, regardless if the user has enough shares, etc. + /// - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees. + /// - MUST NOT revert. + /// + /// NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in + /// share price or some other type of condition, meaning the depositor will lose assets by redeeming. + function previewRedeem(uint256 shares) external view returns (uint256 assets); + + /// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver. + /// @dev + /// - MUST emit the Withdraw event. + /// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the + /// redeem execution, and are accounted for during redeem. + /// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner + /// not having enough shares, etc). + /// + /// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed. + /// Those methods should be performed separately. + function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets); +} diff --git a/lib/forge-std/src/interfaces/IERC721.sol b/lib/forge-std/src/interfaces/IERC721.sol new file mode 100644 index 0000000..0a16f45 --- /dev/null +++ b/lib/forge-std/src/interfaces/IERC721.sol @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2; + +import "./IERC165.sol"; + +/// @title ERC-721 Non-Fungible Token Standard +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x80ac58cd. +interface IERC721 is IERC165 { + /// @dev This emits when ownership of any NFT changes by any mechanism. + /// This event emits when NFTs are created (`from` == 0) and destroyed + /// (`to` == 0). Exception: during contract creation, any number of NFTs + /// may be created and assigned without emitting Transfer. At the time of + /// any transfer, the approved address for that NFT (if any) is reset to none. + event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId); + + /// @dev This emits when the approved address for an NFT is changed or + /// reaffirmed. The zero address indicates there is no approved address. + /// When a Transfer event emits, this also indicates that the approved + /// address for that NFT (if any) is reset to none. + event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId); + + /// @dev This emits when an operator is enabled or disabled for an owner. + /// The operator can manage all NFTs of the owner. + event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved); + + /// @notice Count all NFTs assigned to an owner + /// @dev NFTs assigned to the zero address are considered invalid, and this + /// function throws for queries about the zero address. + /// @param _owner An address for whom to query the balance + /// @return The number of NFTs owned by `_owner`, possibly zero + function balanceOf(address _owner) external view returns (uint256); + + /// @notice Find the owner of an NFT + /// @dev NFTs assigned to zero address are considered invalid, and queries + /// about them do throw. + /// @param _tokenId The identifier for an NFT + /// @return The address of the owner of the NFT + function ownerOf(uint256 _tokenId) external view returns (address); + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. When transfer is complete, this function + /// checks if `_to` is a smart contract (code size > 0). If so, it calls + /// `onERC721Received` on `_to` and throws if the return value is not + /// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + /// @param data Additional data with no specified format, sent in call to `_to` + function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata data) external payable; + + /// @notice Transfers the ownership of an NFT from one address to another address + /// @dev This works identically to the other function with an extra data parameter, + /// except this function just sets data to "". + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE + /// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE + /// THEY MAY BE PERMANENTLY LOST + /// @dev Throws unless `msg.sender` is the current owner, an authorized + /// operator, or the approved address for this NFT. Throws if `_from` is + /// not the current owner. Throws if `_to` is the zero address. Throws if + /// `_tokenId` is not a valid NFT. + /// @param _from The current owner of the NFT + /// @param _to The new owner + /// @param _tokenId The NFT to transfer + function transferFrom(address _from, address _to, uint256 _tokenId) external payable; + + /// @notice Change or reaffirm the approved address for an NFT + /// @dev The zero address indicates there is no approved address. + /// Throws unless `msg.sender` is the current NFT owner, or an authorized + /// operator of the current owner. + /// @param _approved The new approved NFT controller + /// @param _tokenId The NFT to approve + function approve(address _approved, uint256 _tokenId) external payable; + + /// @notice Enable or disable approval for a third party ("operator") to manage + /// all of `msg.sender`'s assets + /// @dev Emits the ApprovalForAll event. The contract MUST allow + /// multiple operators per owner. + /// @param _operator Address to add to the set of authorized operators + /// @param _approved True if the operator is approved, false to revoke approval + function setApprovalForAll(address _operator, bool _approved) external; + + /// @notice Get the approved address for a single NFT + /// @dev Throws if `_tokenId` is not a valid NFT. + /// @param _tokenId The NFT to find the approved address for + /// @return The approved address for this NFT, or the zero address if there is none + function getApproved(uint256 _tokenId) external view returns (address); + + /// @notice Query if an address is an authorized operator for another address + /// @param _owner The address that owns the NFTs + /// @param _operator The address that acts on behalf of the owner + /// @return True if `_operator` is an approved operator for `_owner`, false otherwise + function isApprovedForAll(address _owner, address _operator) external view returns (bool); +} + +/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02. +interface IERC721TokenReceiver { + /// @notice Handle the receipt of an NFT + /// @dev The ERC721 smart contract calls this function on the recipient + /// after a `transfer`. This function MAY throw to revert and reject the + /// transfer. Return of other than the magic value MUST result in the + /// transaction being reverted. + /// Note: the contract address is always the message sender. + /// @param _operator The address which called `safeTransferFrom` function + /// @param _from The address which previously owned the token + /// @param _tokenId The NFT identifier which is being transferred + /// @param _data Additional data with no specified format + /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` + /// unless throwing + function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) + external + returns (bytes4); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional metadata extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x5b5e139f. +interface IERC721Metadata is IERC721 { + /// @notice A descriptive name for a collection of NFTs in this contract + function name() external view returns (string memory _name); + + /// @notice An abbreviated name for NFTs in this contract + function symbol() external view returns (string memory _symbol); + + /// @notice A distinct Uniform Resource Identifier (URI) for a given asset. + /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC + /// 3986. The URI may point to a JSON file that conforms to the "ERC721 + /// Metadata JSON Schema". + function tokenURI(uint256 _tokenId) external view returns (string memory); +} + +/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension +/// @dev See https://eips.ethereum.org/EIPS/eip-721 +/// Note: the ERC-165 identifier for this interface is 0x780e9d63. +interface IERC721Enumerable is IERC721 { + /// @notice Count NFTs tracked by this contract + /// @return A count of valid NFTs tracked by this contract, where each one of + /// them has an assigned and queryable owner not equal to the zero address + function totalSupply() external view returns (uint256); + + /// @notice Enumerate valid NFTs + /// @dev Throws if `_index` >= `totalSupply()`. + /// @param _index A counter less than `totalSupply()` + /// @return The token identifier for the `_index`th NFT, + /// (sort order not specified) + function tokenByIndex(uint256 _index) external view returns (uint256); + + /// @notice Enumerate NFTs assigned to an owner + /// @dev Throws if `_index` >= `balanceOf(_owner)` or if + /// `_owner` is the zero address, representing invalid NFTs. + /// @param _owner An address where we are interested in NFTs owned by them + /// @param _index A counter less than `balanceOf(_owner)` + /// @return The token identifier for the `_index`th NFT assigned to `_owner`, + /// (sort order not specified) + function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256); +} diff --git a/lib/forge-std/src/interfaces/IMulticall3.sol b/lib/forge-std/src/interfaces/IMulticall3.sol new file mode 100644 index 0000000..0d031b7 --- /dev/null +++ b/lib/forge-std/src/interfaces/IMulticall3.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +interface IMulticall3 { + struct Call { + address target; + bytes callData; + } + + struct Call3 { + address target; + bool allowFailure; + bytes callData; + } + + struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; + } + + struct Result { + bool success; + bytes returnData; + } + + function aggregate(Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes[] memory returnData); + + function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData); + + function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData); + + function blockAndAggregate(Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); + + function getBasefee() external view returns (uint256 basefee); + + function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash); + + function getBlockNumber() external view returns (uint256 blockNumber); + + function getChainId() external view returns (uint256 chainid); + + function getCurrentBlockCoinbase() external view returns (address coinbase); + + function getCurrentBlockDifficulty() external view returns (uint256 difficulty); + + function getCurrentBlockGasLimit() external view returns (uint256 gaslimit); + + function getCurrentBlockTimestamp() external view returns (uint256 timestamp); + + function getEthBalance(address addr) external view returns (uint256 balance); + + function getLastBlockHash() external view returns (bytes32 blockHash); + + function tryAggregate(bool requireSuccess, Call[] calldata calls) + external + payable + returns (Result[] memory returnData); + + function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls) + external + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData); +} diff --git a/lib/forge-std/src/safeconsole.sol b/lib/forge-std/src/safeconsole.sol new file mode 100644 index 0000000..5714d09 --- /dev/null +++ b/lib/forge-std/src/safeconsole.sol @@ -0,0 +1,13248 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +/// @author philogy +/// @dev Code generated automatically by script. +library safeconsole { + uint256 constant CONSOLE_ADDR = 0x000000000000000000000000000000000000000000636F6e736F6c652e6c6f67; + + // Credit to [0age](https://twitter.com/z0age/status/1654922202930888704) and [0xdapper](https://github.com/foundry-rs/forge-std/pull/374) + // for the view-to-pure log trick. + function _sendLogPayload(uint256 offset, uint256 size) private pure { + function(uint256, uint256) internal view fnIn = _sendLogPayloadView; + function(uint256, uint256) internal pure pureSendLogPayload; + assembly { + pureSendLogPayload := fnIn + } + pureSendLogPayload(offset, size); + } + + function _sendLogPayloadView(uint256 offset, uint256 size) private view { + assembly { + pop(staticcall(gas(), CONSOLE_ADDR, offset, size, 0x0, 0x0)) + } + } + + function _memcopy(uint256 fromOffset, uint256 toOffset, uint256 length) private pure { + function(uint256, uint256, uint256) internal view fnIn = _memcopyView; + function(uint256, uint256, uint256) internal pure pureMemcopy; + assembly { + pureMemcopy := fnIn + } + pureMemcopy(fromOffset, toOffset, length); + } + + function _memcopyView(uint256 fromOffset, uint256 toOffset, uint256 length) private view { + assembly { + pop(staticcall(gas(), 0x4, fromOffset, length, toOffset, length)) + } + } + + function logMemory(uint256 offset, uint256 length) internal pure { + if (offset >= 0x60) { + // Sufficient memory before slice to prepare call header. + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(sub(offset, 0x60)) + m1 := mload(sub(offset, 0x40)) + m2 := mload(sub(offset, 0x20)) + // Selector of `logBytes(bytes)`. + mstore(sub(offset, 0x60), 0xe17bf956) + mstore(sub(offset, 0x40), 0x20) + mstore(sub(offset, 0x20), length) + } + _sendLogPayload(offset - 0x44, length + 0x44); + assembly { + mstore(sub(offset, 0x60), m0) + mstore(sub(offset, 0x40), m1) + mstore(sub(offset, 0x20), m2) + } + } else { + // Insufficient space, so copy slice forward, add header and reverse. + bytes32 m0; + bytes32 m1; + bytes32 m2; + uint256 endOffset = offset + length; + assembly { + m0 := mload(add(endOffset, 0x00)) + m1 := mload(add(endOffset, 0x20)) + m2 := mload(add(endOffset, 0x40)) + } + _memcopy(offset, offset + 0x60, length); + assembly { + // Selector of `logBytes(bytes)`. + mstore(add(offset, 0x00), 0xe17bf956) + mstore(add(offset, 0x20), 0x20) + mstore(add(offset, 0x40), length) + } + _sendLogPayload(offset + 0x1c, length + 0x44); + _memcopy(offset + 0x60, offset, length); + assembly { + mstore(add(endOffset, 0x00), m0) + mstore(add(endOffset, 0x20), m1) + mstore(add(endOffset, 0x40), m2) + } + } + } + + function log(address p0) internal pure { + bytes32 m0; + bytes32 m1; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(address)`. + mstore(0x00, 0x2c2ecbc2) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(bool p0) internal pure { + bytes32 m0; + bytes32 m1; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(bool)`. + mstore(0x00, 0x32458eed) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(uint256 p0) internal pure { + bytes32 m0; + bytes32 m1; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + // Selector of `log(uint256)`. + mstore(0x00, 0xf82c50f1) + mstore(0x20, p0) + } + _sendLogPayload(0x1c, 0x24); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + } + } + + function log(bytes32 p0) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(string)`. + mstore(0x00, 0x41304fac) + mstore(0x20, 0x20) + writeString(0x40, p0) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, address p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(address,address)`. + mstore(0x00, 0xdaf0d4aa) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(address p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(address,bool)`. + mstore(0x00, 0x75b605d3) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(address p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(address,uint256)`. + mstore(0x00, 0x8309e8a8) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(address p0, bytes32 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,string)`. + mstore(0x00, 0x759f86bb) + mstore(0x20, p0) + mstore(0x40, 0x40) + writeString(0x60, p1) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(bool,address)`. + mstore(0x00, 0x853c4849) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(bool p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(bool,bool)`. + mstore(0x00, 0x2a110e83) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(bool p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(bool,uint256)`. + mstore(0x00, 0x399174d3) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(bool p0, bytes32 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,string)`. + mstore(0x00, 0x8feac525) + mstore(0x20, p0) + mstore(0x40, 0x40) + writeString(0x60, p1) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(uint256,address)`. + mstore(0x00, 0x69276c86) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(uint256 p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(uint256,bool)`. + mstore(0x00, 0x1c9d7eb3) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(uint256 p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + // Selector of `log(uint256,uint256)`. + mstore(0x00, 0xf666715a) + mstore(0x20, p0) + mstore(0x40, p1) + } + _sendLogPayload(0x1c, 0x44); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + } + } + + function log(uint256 p0, bytes32 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,string)`. + mstore(0x00, 0x643fd0df) + mstore(0x20, p0) + mstore(0x40, 0x40) + writeString(0x60, p1) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bytes32 p0, address p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(string,address)`. + mstore(0x00, 0x319af333) + mstore(0x20, 0x40) + mstore(0x40, p1) + writeString(0x60, p0) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bytes32 p0, bool p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(string,bool)`. + mstore(0x00, 0xc3b55635) + mstore(0x20, 0x40) + mstore(0x40, p1) + writeString(0x60, p0) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bytes32 p0, uint256 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(string,uint256)`. + mstore(0x00, 0xb60e72cc) + mstore(0x20, 0x40) + mstore(0x40, p1) + writeString(0x60, p0) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bytes32 p0, bytes32 p1) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,string)`. + mstore(0x00, 0x4b5c4277) + mstore(0x20, 0x40) + mstore(0x40, 0x80) + writeString(0x60, p0) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, address p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,address,address)`. + mstore(0x00, 0x018c84c2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, address p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,address,bool)`. + mstore(0x00, 0xf2a66286) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, address p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,address,uint256)`. + mstore(0x00, 0x17fe6185) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, address p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(address,address,string)`. + mstore(0x00, 0x007150be) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(address p0, bool p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,bool,address)`. + mstore(0x00, 0xf11699ed) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, bool p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,bool,bool)`. + mstore(0x00, 0xeb830c92) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, bool p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,bool,uint256)`. + mstore(0x00, 0x9c4f99fb) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, bool p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(address,bool,string)`. + mstore(0x00, 0x212255cc) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(address p0, uint256 p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,uint256,address)`. + mstore(0x00, 0x7bc0d848) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, uint256 p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,uint256,bool)`. + mstore(0x00, 0x678209a8) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, uint256 p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(address,uint256,uint256)`. + mstore(0x00, 0xb69bcaf6) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(address p0, uint256 p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(address,uint256,string)`. + mstore(0x00, 0xa1f2e8aa) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(address p0, bytes32 p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(address,string,address)`. + mstore(0x00, 0xf08744e8) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(address p0, bytes32 p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(address,string,bool)`. + mstore(0x00, 0xcf020fb1) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(address p0, bytes32 p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(address,string,uint256)`. + mstore(0x00, 0x67dd6ff1) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(address p0, bytes32 p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(address,string,string)`. + mstore(0x00, 0xfb772265) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, 0xa0) + writeString(0x80, p1) + writeString(0xc0, p2) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(bool p0, address p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,address,address)`. + mstore(0x00, 0xd2763667) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, address p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,address,bool)`. + mstore(0x00, 0x18c9c746) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, address p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,address,uint256)`. + mstore(0x00, 0x5f7b9afb) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, address p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(bool,address,string)`. + mstore(0x00, 0xde9a9270) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bool p0, bool p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,bool,address)`. + mstore(0x00, 0x1078f68d) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, bool p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,bool,bool)`. + mstore(0x00, 0x50709698) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, bool p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,bool,uint256)`. + mstore(0x00, 0x12f21602) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, bool p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(bool,bool,string)`. + mstore(0x00, 0x2555fa46) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bool p0, uint256 p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,uint256,address)`. + mstore(0x00, 0x088ef9d2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, uint256 p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,uint256,bool)`. + mstore(0x00, 0xe8defba9) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, uint256 p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(bool,uint256,uint256)`. + mstore(0x00, 0x37103367) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(bool p0, uint256 p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(bool,uint256,string)`. + mstore(0x00, 0xc3fc3970) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bool p0, bytes32 p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(bool,string,address)`. + mstore(0x00, 0x9591b953) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bool p0, bytes32 p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(bool,string,bool)`. + mstore(0x00, 0xdbb4c247) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bool p0, bytes32 p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(bool,string,uint256)`. + mstore(0x00, 0x1093ee11) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bool p0, bytes32 p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(bool,string,string)`. + mstore(0x00, 0xb076847f) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, 0xa0) + writeString(0x80, p1) + writeString(0xc0, p2) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(uint256 p0, address p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,address,address)`. + mstore(0x00, 0xbcfd9be0) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, address p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,address,bool)`. + mstore(0x00, 0x9b6ec042) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, address p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,address,uint256)`. + mstore(0x00, 0x5a9b5ed5) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, address p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(uint256,address,string)`. + mstore(0x00, 0x63cb41f9) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(uint256 p0, bool p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,bool,address)`. + mstore(0x00, 0x35085f7b) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, bool p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,bool,bool)`. + mstore(0x00, 0x20718650) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, bool p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,bool,uint256)`. + mstore(0x00, 0x20098014) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, bool p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(uint256,bool,string)`. + mstore(0x00, 0x85775021) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(uint256 p0, uint256 p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,uint256,address)`. + mstore(0x00, 0x5c96b331) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, uint256 p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,uint256,bool)`. + mstore(0x00, 0x4766da72) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, uint256 p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + // Selector of `log(uint256,uint256,uint256)`. + mstore(0x00, 0xd1ed7a3c) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + } + _sendLogPayload(0x1c, 0x64); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + } + } + + function log(uint256 p0, uint256 p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(uint256,uint256,string)`. + mstore(0x00, 0x71d04af2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x60) + writeString(0x80, p2) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(uint256 p0, bytes32 p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(uint256,string,address)`. + mstore(0x00, 0x7afac959) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(uint256 p0, bytes32 p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(uint256,string,bool)`. + mstore(0x00, 0x4ceda75a) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(uint256 p0, bytes32 p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(uint256,string,uint256)`. + mstore(0x00, 0x37aa7d4c) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, p2) + writeString(0x80, p1) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(uint256 p0, bytes32 p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(uint256,string,string)`. + mstore(0x00, 0xb115611f) + mstore(0x20, p0) + mstore(0x40, 0x60) + mstore(0x60, 0xa0) + writeString(0x80, p1) + writeString(0xc0, p2) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(bytes32 p0, address p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,address,address)`. + mstore(0x00, 0xfcec75e0) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, address p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,address,bool)`. + mstore(0x00, 0xc91d5ed4) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, address p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,address,uint256)`. + mstore(0x00, 0x0d26b925) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, address p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(string,address,string)`. + mstore(0x00, 0xe0e9ad4f) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, 0xa0) + writeString(0x80, p0) + writeString(0xc0, p2) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(bytes32 p0, bool p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,bool,address)`. + mstore(0x00, 0x932bbb38) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, bool p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,bool,bool)`. + mstore(0x00, 0x850b7ad6) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, bool p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,bool,uint256)`. + mstore(0x00, 0xc95958d6) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, bool p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(string,bool,string)`. + mstore(0x00, 0xe298f47d) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, 0xa0) + writeString(0x80, p0) + writeString(0xc0, p2) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(bytes32 p0, uint256 p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,uint256,address)`. + mstore(0x00, 0x1c7ec448) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, uint256 p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,uint256,bool)`. + mstore(0x00, 0xca7733b1) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, uint256 p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + // Selector of `log(string,uint256,uint256)`. + mstore(0x00, 0xca47c4eb) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, p2) + writeString(0x80, p0) + } + _sendLogPayload(0x1c, 0xa4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + } + } + + function log(bytes32 p0, uint256 p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(string,uint256,string)`. + mstore(0x00, 0x5970e089) + mstore(0x20, 0x60) + mstore(0x40, p1) + mstore(0x60, 0xa0) + writeString(0x80, p0) + writeString(0xc0, p2) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(bytes32 p0, bytes32 p1, address p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(string,string,address)`. + mstore(0x00, 0x95ed0195) + mstore(0x20, 0x60) + mstore(0x40, 0xa0) + mstore(0x60, p2) + writeString(0x80, p0) + writeString(0xc0, p1) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(bytes32 p0, bytes32 p1, bool p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(string,string,bool)`. + mstore(0x00, 0xb0e0f9b5) + mstore(0x20, 0x60) + mstore(0x40, 0xa0) + mstore(0x60, p2) + writeString(0x80, p0) + writeString(0xc0, p1) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(bytes32 p0, bytes32 p1, uint256 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + // Selector of `log(string,string,uint256)`. + mstore(0x00, 0x5821efa1) + mstore(0x20, 0x60) + mstore(0x40, 0xa0) + mstore(0x60, p2) + writeString(0x80, p0) + writeString(0xc0, p1) + } + _sendLogPayload(0x1c, 0xe4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + } + } + + function log(bytes32 p0, bytes32 p1, bytes32 p2) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + // Selector of `log(string,string,string)`. + mstore(0x00, 0x2ced7cef) + mstore(0x20, 0x60) + mstore(0x40, 0xa0) + mstore(0x60, 0xe0) + writeString(0x80, p0) + writeString(0xc0, p1) + writeString(0x100, p2) + } + _sendLogPayload(0x1c, 0x124); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + } + } + + function log(address p0, address p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,address,address)`. + mstore(0x00, 0x665bf134) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,address,bool)`. + mstore(0x00, 0x0e378994) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,address,uint256)`. + mstore(0x00, 0x94250d77) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,address,address,string)`. + mstore(0x00, 0xf808da20) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, address p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,bool,address)`. + mstore(0x00, 0x9f1bc36e) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,bool,bool)`. + mstore(0x00, 0x2cd4134a) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,bool,uint256)`. + mstore(0x00, 0x3971e78c) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,address,bool,string)`. + mstore(0x00, 0xaa6540c8) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, address p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,uint256,address)`. + mstore(0x00, 0x8da6def5) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,uint256,bool)`. + mstore(0x00, 0x9b4254e2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,address,uint256,uint256)`. + mstore(0x00, 0xbe553481) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, address p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,address,uint256,string)`. + mstore(0x00, 0xfdb4f990) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, address p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,address,string,address)`. + mstore(0x00, 0x8f736d16) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, address p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,address,string,bool)`. + mstore(0x00, 0x6f1a594e) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, address p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,address,string,uint256)`. + mstore(0x00, 0xef1cefe7) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, address p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,address,string,string)`. + mstore(0x00, 0x21bdaf25) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, bool p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,address,address)`. + mstore(0x00, 0x660375dd) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,address,bool)`. + mstore(0x00, 0xa6f50b0f) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,address,uint256)`. + mstore(0x00, 0xa75c59de) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,bool,address,string)`. + mstore(0x00, 0x2dd778e6) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bool p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,bool,address)`. + mstore(0x00, 0xcf394485) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,bool,bool)`. + mstore(0x00, 0xcac43479) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,bool,uint256)`. + mstore(0x00, 0x8c4e5de6) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,bool,bool,string)`. + mstore(0x00, 0xdfc4a2e8) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bool p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,uint256,address)`. + mstore(0x00, 0xccf790a1) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,uint256,bool)`. + mstore(0x00, 0xc4643e20) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,bool,uint256,uint256)`. + mstore(0x00, 0x386ff5f4) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, bool p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,bool,uint256,string)`. + mstore(0x00, 0x0aa6cfad) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bool p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,bool,string,address)`. + mstore(0x00, 0x19fd4956) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bool p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,bool,string,bool)`. + mstore(0x00, 0x50ad461d) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bool p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,bool,string,uint256)`. + mstore(0x00, 0x80e6a20b) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bool p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,bool,string,string)`. + mstore(0x00, 0x475c5c33) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, uint256 p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,address,address)`. + mstore(0x00, 0x478d1c62) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,address,bool)`. + mstore(0x00, 0xa1bcc9b3) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,address,uint256)`. + mstore(0x00, 0x100f650e) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,uint256,address,string)`. + mstore(0x00, 0x1da986ea) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, uint256 p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,bool,address)`. + mstore(0x00, 0xa31bfdcc) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,bool,bool)`. + mstore(0x00, 0x3bf5e537) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,bool,uint256)`. + mstore(0x00, 0x22f6b999) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,uint256,bool,string)`. + mstore(0x00, 0xc5ad85f9) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, uint256 p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,uint256,address)`. + mstore(0x00, 0x20e3984d) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,uint256,bool)`. + mstore(0x00, 0x66f1bc67) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(address,uint256,uint256,uint256)`. + mstore(0x00, 0x34f0e636) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(address p0, uint256 p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,uint256,uint256,string)`. + mstore(0x00, 0x4a28c017) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, uint256 p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,uint256,string,address)`. + mstore(0x00, 0x5c430d47) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, uint256 p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,uint256,string,bool)`. + mstore(0x00, 0xcf18105c) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, uint256 p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,uint256,string,uint256)`. + mstore(0x00, 0xbf01f891) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, uint256 p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,uint256,string,string)`. + mstore(0x00, 0x88a8c406) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, bytes32 p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,address,address)`. + mstore(0x00, 0x0d36fa20) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,address,bool)`. + mstore(0x00, 0x0df12b76) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,address,uint256)`. + mstore(0x00, 0x457fe3cf) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,string,address,string)`. + mstore(0x00, 0xf7e36245) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, bytes32 p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,bool,address)`. + mstore(0x00, 0x205871c2) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,bool,bool)`. + mstore(0x00, 0x5f1d5c9f) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,bool,uint256)`. + mstore(0x00, 0x515e38b6) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,string,bool,string)`. + mstore(0x00, 0xbc0b61fe) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, bytes32 p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,uint256,address)`. + mstore(0x00, 0x63183678) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,uint256,bool)`. + mstore(0x00, 0x0ef7e050) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(address,string,uint256,uint256)`. + mstore(0x00, 0x1dc8e1b8) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(address p0, bytes32 p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,string,uint256,string)`. + mstore(0x00, 0x448830a8) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, bytes32 p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,string,string,address)`. + mstore(0x00, 0xa04e2f87) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, bytes32 p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,string,string,bool)`. + mstore(0x00, 0x35a5071f) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, bytes32 p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(address,string,string,uint256)`. + mstore(0x00, 0x159f8927) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(address p0, bytes32 p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(address,string,string,string)`. + mstore(0x00, 0x5d02c50b) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, 0x100) + writeString(0xa0, p1) + writeString(0xe0, p2) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bool p0, address p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,address,address)`. + mstore(0x00, 0x1d14d001) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,address,bool)`. + mstore(0x00, 0x46600be0) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,address,uint256)`. + mstore(0x00, 0x0c66d1be) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,address,address,string)`. + mstore(0x00, 0xd812a167) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, address p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,bool,address)`. + mstore(0x00, 0x1c41a336) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,bool,bool)`. + mstore(0x00, 0x6a9c478b) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,bool,uint256)`. + mstore(0x00, 0x07831502) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,address,bool,string)`. + mstore(0x00, 0x4a66cb34) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, address p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,uint256,address)`. + mstore(0x00, 0x136b05dd) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,uint256,bool)`. + mstore(0x00, 0xd6019f1c) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,address,uint256,uint256)`. + mstore(0x00, 0x7bf181a1) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, address p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,address,uint256,string)`. + mstore(0x00, 0x51f09ff8) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, address p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,address,string,address)`. + mstore(0x00, 0x6f7c603e) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, address p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,address,string,bool)`. + mstore(0x00, 0xe2bfd60b) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, address p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,address,string,uint256)`. + mstore(0x00, 0xc21f64c7) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, address p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,address,string,string)`. + mstore(0x00, 0xa73c1db6) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, bool p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,address,address)`. + mstore(0x00, 0xf4880ea4) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,address,bool)`. + mstore(0x00, 0xc0a302d8) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,address,uint256)`. + mstore(0x00, 0x4c123d57) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,bool,address,string)`. + mstore(0x00, 0xa0a47963) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bool p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,bool,address)`. + mstore(0x00, 0x8c329b1a) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,bool,bool)`. + mstore(0x00, 0x3b2a5ce0) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,bool,uint256)`. + mstore(0x00, 0x6d7045c1) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,bool,bool,string)`. + mstore(0x00, 0x2ae408d4) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bool p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,uint256,address)`. + mstore(0x00, 0x54a7a9a0) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,uint256,bool)`. + mstore(0x00, 0x619e4d0e) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,bool,uint256,uint256)`. + mstore(0x00, 0x0bb00eab) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, bool p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,bool,uint256,string)`. + mstore(0x00, 0x7dd4d0e0) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bool p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,bool,string,address)`. + mstore(0x00, 0xf9ad2b89) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bool p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,bool,string,bool)`. + mstore(0x00, 0xb857163a) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bool p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,bool,string,uint256)`. + mstore(0x00, 0xe3a9ca2f) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bool p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,bool,string,string)`. + mstore(0x00, 0x6d1e8751) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, uint256 p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,address,address)`. + mstore(0x00, 0x26f560a8) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,address,bool)`. + mstore(0x00, 0xb4c314ff) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,address,uint256)`. + mstore(0x00, 0x1537dc87) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,uint256,address,string)`. + mstore(0x00, 0x1bb3b09a) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, uint256 p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,bool,address)`. + mstore(0x00, 0x9acd3616) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,bool,bool)`. + mstore(0x00, 0xceb5f4d7) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,bool,uint256)`. + mstore(0x00, 0x7f9bbca2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,uint256,bool,string)`. + mstore(0x00, 0x9143dbb1) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, uint256 p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,uint256,address)`. + mstore(0x00, 0x00dd87b9) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,uint256,bool)`. + mstore(0x00, 0xbe984353) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(bool,uint256,uint256,uint256)`. + mstore(0x00, 0x374bb4b2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(bool p0, uint256 p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,uint256,uint256,string)`. + mstore(0x00, 0x8e69fb5d) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, uint256 p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,uint256,string,address)`. + mstore(0x00, 0xfedd1fff) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, uint256 p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,uint256,string,bool)`. + mstore(0x00, 0xe5e70b2b) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, uint256 p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,uint256,string,uint256)`. + mstore(0x00, 0x6a1199e2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, uint256 p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,uint256,string,string)`. + mstore(0x00, 0xf5bc2249) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, bytes32 p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,address,address)`. + mstore(0x00, 0x2b2b18dc) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,address,bool)`. + mstore(0x00, 0x6dd434ca) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,address,uint256)`. + mstore(0x00, 0xa5cada94) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,string,address,string)`. + mstore(0x00, 0x12d6c788) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, bytes32 p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,bool,address)`. + mstore(0x00, 0x538e06ab) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,bool,bool)`. + mstore(0x00, 0xdc5e935b) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,bool,uint256)`. + mstore(0x00, 0x1606a393) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,string,bool,string)`. + mstore(0x00, 0x483d0416) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, bytes32 p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,uint256,address)`. + mstore(0x00, 0x1596a1ce) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,uint256,bool)`. + mstore(0x00, 0x6b0e5d53) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(bool,string,uint256,uint256)`. + mstore(0x00, 0x28863fcb) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bool p0, bytes32 p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,string,uint256,string)`. + mstore(0x00, 0x1ad96de6) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, bytes32 p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,string,string,address)`. + mstore(0x00, 0x97d394d8) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, bytes32 p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,string,string,bool)`. + mstore(0x00, 0x1e4b87e5) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, bytes32 p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(bool,string,string,uint256)`. + mstore(0x00, 0x7be0c3eb) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bool p0, bytes32 p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(bool,string,string,string)`. + mstore(0x00, 0x1762e32a) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, 0x100) + writeString(0xa0, p1) + writeString(0xe0, p2) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(uint256 p0, address p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,address,address)`. + mstore(0x00, 0x2488b414) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,address,bool)`. + mstore(0x00, 0x091ffaf5) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,address,uint256)`. + mstore(0x00, 0x736efbb6) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,address,address,string)`. + mstore(0x00, 0x031c6f73) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, address p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,bool,address)`. + mstore(0x00, 0xef72c513) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,bool,bool)`. + mstore(0x00, 0xe351140f) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,bool,uint256)`. + mstore(0x00, 0x5abd992a) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,address,bool,string)`. + mstore(0x00, 0x90fb06aa) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, address p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,uint256,address)`. + mstore(0x00, 0x15c127b5) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,uint256,bool)`. + mstore(0x00, 0x5f743a7c) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,address,uint256,uint256)`. + mstore(0x00, 0x0c9cd9c1) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, address p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,address,uint256,string)`. + mstore(0x00, 0xddb06521) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, address p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,address,string,address)`. + mstore(0x00, 0x9cba8fff) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, address p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,address,string,bool)`. + mstore(0x00, 0xcc32ab07) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, address p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,address,string,uint256)`. + mstore(0x00, 0x46826b5d) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, address p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,address,string,string)`. + mstore(0x00, 0x3e128ca3) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, bool p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,address,address)`. + mstore(0x00, 0xa1ef4cbb) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,address,bool)`. + mstore(0x00, 0x454d54a5) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,address,uint256)`. + mstore(0x00, 0x078287f5) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,bool,address,string)`. + mstore(0x00, 0xade052c7) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bool p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,bool,address)`. + mstore(0x00, 0x69640b59) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,bool,bool)`. + mstore(0x00, 0xb6f577a1) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,bool,uint256)`. + mstore(0x00, 0x7464ce23) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,bool,bool,string)`. + mstore(0x00, 0xdddb9561) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bool p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,uint256,address)`. + mstore(0x00, 0x88cb6041) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,uint256,bool)`. + mstore(0x00, 0x91a02e2a) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,bool,uint256,uint256)`. + mstore(0x00, 0xc6acc7a8) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, bool p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,bool,uint256,string)`. + mstore(0x00, 0xde03e774) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bool p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,bool,string,address)`. + mstore(0x00, 0xef529018) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bool p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,bool,string,bool)`. + mstore(0x00, 0xeb928d7f) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bool p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,bool,string,uint256)`. + mstore(0x00, 0x2c1d0746) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bool p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,bool,string,string)`. + mstore(0x00, 0x68c8b8bd) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, uint256 p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,address,address)`. + mstore(0x00, 0x56a5d1b1) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,address,bool)`. + mstore(0x00, 0x15cac476) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,address,uint256)`. + mstore(0x00, 0x88f6e4b2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,uint256,address,string)`. + mstore(0x00, 0x6cde40b8) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, uint256 p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,bool,address)`. + mstore(0x00, 0x9a816a83) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,bool,bool)`. + mstore(0x00, 0xab085ae6) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,bool,uint256)`. + mstore(0x00, 0xeb7f6fd2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,uint256,bool,string)`. + mstore(0x00, 0xa5b4fc99) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,uint256,address)`. + mstore(0x00, 0xfa8185af) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,uint256,bool)`. + mstore(0x00, 0xc598d185) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + assembly { + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + // Selector of `log(uint256,uint256,uint256,uint256)`. + mstore(0x00, 0x193fb800) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + } + _sendLogPayload(0x1c, 0x84); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + } + } + + function log(uint256 p0, uint256 p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,uint256,uint256,string)`. + mstore(0x00, 0x59cfcbe3) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0x80) + writeString(0xa0, p3) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, uint256 p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,uint256,string,address)`. + mstore(0x00, 0x42d21db7) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, uint256 p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,uint256,string,bool)`. + mstore(0x00, 0x7af6ab25) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, uint256 p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,uint256,string,uint256)`. + mstore(0x00, 0x5da297eb) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, p3) + writeString(0xa0, p2) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, uint256 p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,uint256,string,string)`. + mstore(0x00, 0x27d8afd2) + mstore(0x20, p0) + mstore(0x40, p1) + mstore(0x60, 0x80) + mstore(0x80, 0xc0) + writeString(0xa0, p2) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, bytes32 p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,address,address)`. + mstore(0x00, 0x6168ed61) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,address,bool)`. + mstore(0x00, 0x90c30a56) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,address,uint256)`. + mstore(0x00, 0xe8d3018d) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,string,address,string)`. + mstore(0x00, 0x9c3adfa1) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, bytes32 p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,bool,address)`. + mstore(0x00, 0xae2ec581) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,bool,bool)`. + mstore(0x00, 0xba535d9c) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,bool,uint256)`. + mstore(0x00, 0xcf009880) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,string,bool,string)`. + mstore(0x00, 0xd2d423cd) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, bytes32 p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,uint256,address)`. + mstore(0x00, 0x3b2279b4) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,uint256,bool)`. + mstore(0x00, 0x691a8f74) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(uint256,string,uint256,uint256)`. + mstore(0x00, 0x82c25b74) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p1) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(uint256 p0, bytes32 p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,string,uint256,string)`. + mstore(0x00, 0xb7b914ca) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p1) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, bytes32 p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,string,string,address)`. + mstore(0x00, 0xd583c602) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, bytes32 p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,string,string,bool)`. + mstore(0x00, 0xb3a6b6bd) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, bytes32 p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(uint256,string,string,uint256)`. + mstore(0x00, 0xb028c9bd) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p1) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(uint256 p0, bytes32 p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(uint256,string,string,string)`. + mstore(0x00, 0x21ad0683) + mstore(0x20, p0) + mstore(0x40, 0x80) + mstore(0x60, 0xc0) + mstore(0x80, 0x100) + writeString(0xa0, p1) + writeString(0xe0, p2) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, address p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,address,address)`. + mstore(0x00, 0xed8f28f6) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,address,bool)`. + mstore(0x00, 0xb59dbd60) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,address,uint256)`. + mstore(0x00, 0x8ef3f399) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,address,address,string)`. + mstore(0x00, 0x800a1c67) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, address p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,bool,address)`. + mstore(0x00, 0x223603bd) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,bool,bool)`. + mstore(0x00, 0x79884c2b) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,bool,uint256)`. + mstore(0x00, 0x3e9f866a) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,address,bool,string)`. + mstore(0x00, 0x0454c079) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, address p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,uint256,address)`. + mstore(0x00, 0x63fb8bc5) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,uint256,bool)`. + mstore(0x00, 0xfc4845f0) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,address,uint256,uint256)`. + mstore(0x00, 0xf8f51b1e) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, address p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,address,uint256,string)`. + mstore(0x00, 0x5a477632) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, address p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,address,string,address)`. + mstore(0x00, 0xaabc9a31) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, address p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,address,string,bool)`. + mstore(0x00, 0x5f15d28c) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, address p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,address,string,uint256)`. + mstore(0x00, 0x91d1112e) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, address p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,address,string,string)`. + mstore(0x00, 0x245986f2) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, 0x100) + writeString(0xa0, p0) + writeString(0xe0, p2) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, bool p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,address,address)`. + mstore(0x00, 0x33e9dd1d) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,address,bool)`. + mstore(0x00, 0x958c28c6) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,address,uint256)`. + mstore(0x00, 0x5d08bb05) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,bool,address,string)`. + mstore(0x00, 0x2d8e33a4) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bool p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,bool,address)`. + mstore(0x00, 0x7190a529) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,bool,bool)`. + mstore(0x00, 0x895af8c5) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,bool,uint256)`. + mstore(0x00, 0x8e3f78a9) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,bool,bool,string)`. + mstore(0x00, 0x9d22d5dd) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bool p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,uint256,address)`. + mstore(0x00, 0x935e09bf) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,uint256,bool)`. + mstore(0x00, 0x8af7cf8a) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,bool,uint256,uint256)`. + mstore(0x00, 0x64b5bb67) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, bool p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,bool,uint256,string)`. + mstore(0x00, 0x742d6ee7) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bool p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,bool,string,address)`. + mstore(0x00, 0xe0625b29) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bool p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,bool,string,bool)`. + mstore(0x00, 0x3f8a701d) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bool p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,bool,string,uint256)`. + mstore(0x00, 0x24f91465) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bool p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,bool,string,string)`. + mstore(0x00, 0xa826caeb) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, 0x100) + writeString(0xa0, p0) + writeString(0xe0, p2) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, uint256 p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,address,address)`. + mstore(0x00, 0x5ea2b7ae) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,address,bool)`. + mstore(0x00, 0x82112a42) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,address,uint256)`. + mstore(0x00, 0x4f04fdc6) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,uint256,address,string)`. + mstore(0x00, 0x9ffb2f93) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, uint256 p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,bool,address)`. + mstore(0x00, 0xe0e95b98) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,bool,bool)`. + mstore(0x00, 0x354c36d6) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,bool,uint256)`. + mstore(0x00, 0xe41b6f6f) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,uint256,bool,string)`. + mstore(0x00, 0xabf73a98) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, uint256 p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,uint256,address)`. + mstore(0x00, 0xe21de278) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,uint256,bool)`. + mstore(0x00, 0x7626db92) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + // Selector of `log(string,uint256,uint256,uint256)`. + mstore(0x00, 0xa7a87853) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + } + _sendLogPayload(0x1c, 0xc4); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + } + } + + function log(bytes32 p0, uint256 p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,uint256,uint256,string)`. + mstore(0x00, 0x854b3496) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, p2) + mstore(0x80, 0xc0) + writeString(0xa0, p0) + writeString(0xe0, p3) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, uint256 p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,uint256,string,address)`. + mstore(0x00, 0x7c4632a4) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, uint256 p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,uint256,string,bool)`. + mstore(0x00, 0x7d24491d) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, uint256 p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,uint256,string,uint256)`. + mstore(0x00, 0xc67ea9d1) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p2) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, uint256 p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,uint256,string,string)`. + mstore(0x00, 0x5ab84e1f) + mstore(0x20, 0x80) + mstore(0x40, p1) + mstore(0x60, 0xc0) + mstore(0x80, 0x100) + writeString(0xa0, p0) + writeString(0xe0, p2) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, bytes32 p1, address p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,address,address)`. + mstore(0x00, 0x439c7bef) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, address p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,address,bool)`. + mstore(0x00, 0x5ccd4e37) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, address p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,address,uint256)`. + mstore(0x00, 0x7cc3c607) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, address p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,string,address,string)`. + mstore(0x00, 0xeb1bff80) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, 0x100) + writeString(0xa0, p0) + writeString(0xe0, p1) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, bytes32 p1, bool p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,bool,address)`. + mstore(0x00, 0xc371c7db) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, bool p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,bool,bool)`. + mstore(0x00, 0x40785869) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, bool p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,bool,uint256)`. + mstore(0x00, 0xd6aefad2) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, bool p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,string,bool,string)`. + mstore(0x00, 0x5e84b0ea) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, 0x100) + writeString(0xa0, p0) + writeString(0xe0, p1) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, bytes32 p1, uint256 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,uint256,address)`. + mstore(0x00, 0x1023f7b2) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, uint256 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,uint256,bool)`. + mstore(0x00, 0xc3a8a654) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, uint256 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + // Selector of `log(string,string,uint256,uint256)`. + mstore(0x00, 0xf45d7d2c) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + } + _sendLogPayload(0x1c, 0x104); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + } + } + + function log(bytes32 p0, bytes32 p1, uint256 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,string,uint256,string)`. + mstore(0x00, 0x5d1a971a) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, p2) + mstore(0x80, 0x100) + writeString(0xa0, p0) + writeString(0xe0, p1) + writeString(0x120, p3) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, bytes32 p1, bytes32 p2, address p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,string,string,address)`. + mstore(0x00, 0x6d572f44) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, 0x100) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + writeString(0x120, p2) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, bytes32 p1, bytes32 p2, bool p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,string,string,bool)`. + mstore(0x00, 0x2c1754ed) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, 0x100) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + writeString(0x120, p2) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, bytes32 p1, bytes32 p2, uint256 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + // Selector of `log(string,string,string,uint256)`. + mstore(0x00, 0x8eafb02b) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, 0x100) + mstore(0x80, p3) + writeString(0xa0, p0) + writeString(0xe0, p1) + writeString(0x120, p2) + } + _sendLogPayload(0x1c, 0x144); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + } + } + + function log(bytes32 p0, bytes32 p1, bytes32 p2, bytes32 p3) internal pure { + bytes32 m0; + bytes32 m1; + bytes32 m2; + bytes32 m3; + bytes32 m4; + bytes32 m5; + bytes32 m6; + bytes32 m7; + bytes32 m8; + bytes32 m9; + bytes32 m10; + bytes32 m11; + bytes32 m12; + assembly { + function writeString(pos, w) { + let length := 0 + for {} lt(length, 0x20) { length := add(length, 1) } { if iszero(byte(length, w)) { break } } + mstore(pos, length) + let shift := sub(256, shl(3, length)) + mstore(add(pos, 0x20), shl(shift, shr(shift, w))) + } + m0 := mload(0x00) + m1 := mload(0x20) + m2 := mload(0x40) + m3 := mload(0x60) + m4 := mload(0x80) + m5 := mload(0xa0) + m6 := mload(0xc0) + m7 := mload(0xe0) + m8 := mload(0x100) + m9 := mload(0x120) + m10 := mload(0x140) + m11 := mload(0x160) + m12 := mload(0x180) + // Selector of `log(string,string,string,string)`. + mstore(0x00, 0xde68f20a) + mstore(0x20, 0x80) + mstore(0x40, 0xc0) + mstore(0x60, 0x100) + mstore(0x80, 0x140) + writeString(0xa0, p0) + writeString(0xe0, p1) + writeString(0x120, p2) + writeString(0x160, p3) + } + _sendLogPayload(0x1c, 0x184); + assembly { + mstore(0x00, m0) + mstore(0x20, m1) + mstore(0x40, m2) + mstore(0x60, m3) + mstore(0x80, m4) + mstore(0xa0, m5) + mstore(0xc0, m6) + mstore(0xe0, m7) + mstore(0x100, m8) + mstore(0x120, m9) + mstore(0x140, m10) + mstore(0x160, m11) + mstore(0x180, m12) + } + } +} diff --git a/lib/forge-std/test/StdAssertions.t.sol b/lib/forge-std/test/StdAssertions.t.sol new file mode 100644 index 0000000..ae998f1 --- /dev/null +++ b/lib/forge-std/test/StdAssertions.t.sol @@ -0,0 +1,1015 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdAssertionsTest is Test { + string constant CUSTOM_ERROR = "guh!"; + + bool constant EXPECT_PASS = false; + bool constant EXPECT_FAIL = true; + + bool constant SHOULD_REVERT = true; + bool constant SHOULD_RETURN = false; + + bool constant STRICT_REVERT_DATA = true; + bool constant NON_STRICT_REVERT_DATA = false; + + TestTest t = new TestTest(); + + /*////////////////////////////////////////////////////////////////////////// + FAIL(STRING) + //////////////////////////////////////////////////////////////////////////*/ + + function test_ShouldFail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._fail(CUSTOM_ERROR); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_FALSE + //////////////////////////////////////////////////////////////////////////*/ + + function test_AssertFalse_Pass() external { + t._assertFalse(false, EXPECT_PASS); + } + + function test_AssertFalse_Fail() external { + vm.expectEmit(false, false, false, true); + emit log("Error: Assertion Failed"); + t._assertFalse(true, EXPECT_FAIL); + } + + function test_AssertFalse_Err_Pass() external { + t._assertFalse(false, CUSTOM_ERROR, EXPECT_PASS); + } + + function test_AssertFalse_Err_Fail() external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertFalse(true, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BOOL) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertEq_Bool_Pass(bool a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testFuzz_AssertEq_Bool_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bool]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testFuzz_AssertEq_BoolErr_Pass(bool a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertEq_BoolErr_Fail(bool a, bool b) external { + vm.assume(a != b); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(BYTES) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertEq_Bytes_Pass(bytes calldata a) external { + t._assertEq(a, a, EXPECT_PASS); + } + + function testFuzz_AssertEq_Bytes_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [bytes]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testFuzz_AssertEq_BytesErr_Pass(bytes calldata a) external { + t._assertEq(a, a, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertEq_BytesErr_Fail(bytes calldata a, bytes calldata b) external { + vm.assume(keccak256(a) != keccak256(b)); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(ARRAY) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertEq_UintArr_Pass(uint256 e0, uint256 e1, uint256 e2) public { + uint256[] memory a = new uint256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + uint256[] memory b = new uint256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testFuzz_AssertEq_IntArr_Pass(int256 e0, int256 e1, int256 e2) public { + int256[] memory a = new int256[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + int256[] memory b = new int256[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testFuzz_AssertEq_AddressArr_Pass(address e0, address e1, address e2) public { + address[] memory a = new address[](3); + a[0] = e0; + a[1] = e1; + a[2] = e2; + address[] memory b = new address[](3); + b[0] = e0; + b[1] = e1; + b[2] = e2; + + t._assertEq(a, b, EXPECT_PASS); + } + + function testFuzz_AssertEq_UintArr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testFuzz_AssertEq_IntArr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testFuzz_AssertEq_AddressArr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testFuzz_AssertEq_UintArrErr_FailEl(uint256 e1) public { + vm.assume(e1 != 0); + uint256[] memory a = new uint256[](3); + uint256[] memory b = new uint256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testFuzz_AssertEq_IntArrErr_FailEl(int256 e1) public { + vm.assume(e1 != 0); + int256[] memory a = new int256[](3); + int256[] memory b = new int256[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testFuzz_AssertEq_AddressArrErr_FailEl(address e1) public { + vm.assume(e1 != address(0)); + address[] memory a = new address[](3); + address[] memory b = new address[](3); + b[1] = e1; + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testFuzz_AssertEq_UintArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testFuzz_AssertEq_IntArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testFuzz_AssertEq_AddressArr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, EXPECT_FAIL); + } + + function testFuzz_AssertEq_UintArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + uint256[] memory a = new uint256[](lenA); + uint256[] memory b = new uint256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [uint[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testFuzz_AssertEq_IntArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + int256[] memory a = new int256[](lenA); + int256[] memory b = new int256[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [int[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + function testFuzz_AssertEq_AddressArrErr_FailLen(uint256 lenA, uint256 lenB) public { + vm.assume(lenA != lenB); + vm.assume(lenA <= 10000); + vm.assume(lenB <= 10000); + address[] memory a = new address[](lenA); + address[] memory b = new address[](lenB); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + vm.expectEmit(false, false, false, true); + emit log("Error: a == b not satisfied [address[]]"); + t._assertEq(a, b, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function test_AssertEqUint() public { + assertEqUint(uint8(1), uint128(1)); + assertEqUint(uint64(2), uint64(2)); + } + + function testFail_AssertEqUint() public { + assertEqUint(uint64(1), uint96(2)); + assertEqUint(uint160(3), uint160(4)); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertApproxEqAbs_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqAbs_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testFuzz_AssertApproxEqAbs_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqAbs_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS_DECIMAL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertApproxEqAbsDecimal_Uint_Pass(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqAbsDecimal_Uint_Fail(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_FAIL); + } + + function testFuzz_AssertApproxEqAbsDecimal_UintErr_Pass(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqAbsDecimal_UintErr_Fail(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertApproxEqAbs_Int_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqAbs_Int_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbs(a, b, maxDelta, EXPECT_FAIL); + } + + function testFuzz_AssertApproxEqAbs_IntErr_Pass(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqAbs_IntErr_Fail(int256 a, int256 b, uint256 maxDelta) external { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbs(a, b, maxDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_ABS_DECIMAL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertApproxEqAbsDecimal_Int_Pass(int256 a, int256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqAbsDecimal_Int_Fail(int256 a, int256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, EXPECT_FAIL); + } + + function testFuzz_AssertApproxEqAbsDecimal_IntErr_Pass(int256 a, int256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) <= maxDelta); + + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqAbsDecimal_IntErr_Fail(int256 a, int256 b, uint256 maxDelta, uint256 decimals) + external + { + vm.assume(stdMath.delta(a, b) > maxDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqAbsDecimal(a, b, maxDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertApproxEqRel_Uint_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqRel_Uint_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testFuzz_AssertApproxEqRel_UintErr_Pass(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqRel_UintErr_Fail(uint256 a, uint256 b, uint256 maxPercentDelta) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL_DECIMAL(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertApproxEqRelDecimal_Uint_Pass( + uint256 a, + uint256 b, + uint256 maxPercentDelta, + uint256 decimals + ) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqRelDecimal_Uint_Fail( + uint256 a, + uint256 b, + uint256 maxPercentDelta, + uint256 decimals + ) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [uint]"); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_FAIL); + } + + function testFuzz_AssertApproxEqRelDecimal_UintErr_Pass( + uint256 a, + uint256 b, + uint256 maxPercentDelta, + uint256 decimals + ) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqRelDecimal_UintErr_Fail( + uint256 a, + uint256 b, + uint256 maxPercentDelta, + uint256 decimals + ) external { + vm.assume(a < type(uint128).max && b < type(uint128).max && b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertApproxEqRel_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqRel_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRel(a, b, maxPercentDelta, EXPECT_FAIL); + } + + function testFuzz_AssertApproxEqRel_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AssertApproxEqRel_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta) external { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRel(a, b, maxPercentDelta, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + APPROX_EQ_REL_DECIMAL(INT) + //////////////////////////////////////////////////////////////////////////*/ + + function testAssertApproxEqRelDecimal_Int_Pass(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_Int_Fail(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log("Error: a ~= b not satisfied [int]"); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, EXPECT_FAIL); + } + + function testAssertApproxEqRelDecimal_IntErr_Pass(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) <= maxPercentDelta); + + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_PASS); + } + + function testAssertApproxEqRelDecimal_IntErr_Fail(int128 a, int128 b, uint128 maxPercentDelta, uint128 decimals) + external + { + vm.assume(b != 0); + vm.assume(stdMath.percentDelta(a, b) > maxPercentDelta); + + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_EQ_CALL + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertEqCall_Return_Pass( + bytes memory callDataA, + bytes memory callDataB, + bytes memory returnData, + bool strictRevertData + ) external { + address targetA = address(new TestMockCall(returnData, SHOULD_RETURN)); + address targetB = address(new TestMockCall(returnData, SHOULD_RETURN)); + + t._assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData, EXPECT_PASS); + } + + function testFuzz_RevertWhenCalled_AssertEqCall_Return_Fail( + bytes memory callDataA, + bytes memory callDataB, + bytes memory returnDataA, + bytes memory returnDataB, + bool strictRevertData + ) external { + vm.assume(keccak256(returnDataA) != keccak256(returnDataB)); + + address targetA = address(new TestMockCall(returnDataA, SHOULD_RETURN)); + address targetB = address(new TestMockCall(returnDataB, SHOULD_RETURN)); + + vm.expectEmit(true, true, true, true); + emit log_named_string("Error", "Call return data does not match"); + t._assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData, EXPECT_FAIL); + } + + function testFuzz_AssertEqCall_Revert_Pass( + bytes memory callDataA, + bytes memory callDataB, + bytes memory revertDataA, + bytes memory revertDataB + ) external { + address targetA = address(new TestMockCall(revertDataA, SHOULD_REVERT)); + address targetB = address(new TestMockCall(revertDataB, SHOULD_REVERT)); + + t._assertEqCall(targetA, callDataA, targetB, callDataB, NON_STRICT_REVERT_DATA, EXPECT_PASS); + } + + function testFuzz_RevertWhenCalled_AssertEqCall_Revert_Fail( + bytes memory callDataA, + bytes memory callDataB, + bytes memory revertDataA, + bytes memory revertDataB + ) external { + vm.assume(keccak256(revertDataA) != keccak256(revertDataB)); + + address targetA = address(new TestMockCall(revertDataA, SHOULD_REVERT)); + address targetB = address(new TestMockCall(revertDataB, SHOULD_REVERT)); + + vm.expectEmit(true, true, true, true); + emit log_named_string("Error", "Call revert data does not match"); + t._assertEqCall(targetA, callDataA, targetB, callDataB, STRICT_REVERT_DATA, EXPECT_FAIL); + } + + function testFuzz_RevertWhenCalled_AssertEqCall_Fail( + bytes memory callDataA, + bytes memory callDataB, + bytes memory returnDataA, + bytes memory returnDataB, + bool strictRevertData + ) external { + address targetA = address(new TestMockCall(returnDataA, SHOULD_RETURN)); + address targetB = address(new TestMockCall(returnDataB, SHOULD_REVERT)); + + vm.expectEmit(true, true, true, true); + emit log_named_bytes(" Left call return data", returnDataA); + vm.expectEmit(true, true, true, true); + emit log_named_bytes(" Right call revert data", returnDataB); + t._assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData, EXPECT_FAIL); + + vm.expectEmit(true, true, true, true); + emit log_named_bytes(" Left call revert data", returnDataB); + vm.expectEmit(true, true, true, true); + emit log_named_bytes(" Right call return data", returnDataA); + t._assertEqCall(targetB, callDataB, targetA, callDataA, strictRevertData, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_NOT_EQ(BYTES) + //////////////////////////////////////////////////////////////////////////*/ + + function testFuzz_AssertNotEq_Bytes_Pass(bytes32 a, bytes32 b) external { + vm.assume(a != b); + t._assertNotEq(a, b, EXPECT_PASS); + } + + function testFuzz_AssertNotEq_Bytes_Fail(bytes32 a) external { + vm.expectEmit(false, false, false, true); + emit log("Error: a != b not satisfied [bytes32]"); + t._assertNotEq(a, a, EXPECT_FAIL); + } + + function testFuzz_AssertNotEq_BytesErr_Pass(bytes32 a, bytes32 b) external { + vm.assume(a != b); + t._assertNotEq(a, b, CUSTOM_ERROR, EXPECT_PASS); + } + + function testFuzz_AsserNottEq_BytesErr_Fail(bytes32 a) external { + vm.expectEmit(false, false, false, true); + emit log_named_string("Error", CUSTOM_ERROR); + t._assertNotEq(a, a, CUSTOM_ERROR, EXPECT_FAIL); + } + + /*////////////////////////////////////////////////////////////////////////// + ASSERT_NOT_EQ(UINT) + //////////////////////////////////////////////////////////////////////////*/ + + function test_AssertNotEqUint() public { + assertNotEq(uint8(1), uint128(2)); + assertNotEq(uint64(3), uint64(4)); + } + + function testFail_AssertNotEqUint() public { + assertNotEq(uint64(1), uint96(1)); + assertNotEq(uint160(2), uint160(2)); + } +} + +contract TestTest is Test { + modifier expectFailure(bool expectFail) { + bool preState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + _; + bool postState = vm.load(HEVM_ADDRESS, bytes32("failed")) != bytes32(0x00); + + if (preState == true) { + return; + } + + if (expectFail) { + require(postState == true, "expected failure not triggered"); + + // unwind the expected failure + vm.store(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x00))); + } else { + require(postState == false, "unexpected failure was triggered"); + } + } + + function _fail(string memory err) external expectFailure(true) { + fail(err); + } + + function _assertFalse(bool data, bool expectFail) external expectFailure(expectFail) { + assertFalse(data); + } + + function _assertFalse(bool data, string memory err, bool expectFail) external expectFailure(expectFail) { + assertFalse(data, err); + } + + function _assertEq(bool a, bool b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bool a, bool b, string memory err, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b, err); + } + + function _assertEq(bytes memory a, bytes memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(bytes memory a, bytes memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(int256[] memory a, int256[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(address[] memory a, address[] memory b, bool expectFail) external expectFailure(expectFail) { + assertEq(a, b); + } + + function _assertEq(uint256[] memory a, uint256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(int256[] memory a, int256[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertEq(address[] memory a, address[] memory b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertEq(a, b, err); + } + + function _assertNotEq(bytes32 a, bytes32 b, bool expectFail) external expectFailure(expectFail) { + assertNotEq32(a, b); + } + + function _assertNotEq(bytes32 a, bytes32 b, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertNotEq32(a, b, err); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + + function _assertApproxEqAbsDecimal( + uint256 a, + uint256 b, + uint256 maxDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals, err); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta); + } + + function _assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbs(a, b, maxDelta, err); + } + + function _assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals); + } + + function _assertApproxEqAbsDecimal( + int256 a, + int256 b, + uint256 maxDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqAbsDecimal(a, b, maxDelta, decimals, err); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(uint256 a, uint256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRelDecimal(uint256 a, uint256 b, uint256 maxPercentDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + + function _assertApproxEqRelDecimal( + uint256 a, + uint256 b, + uint256 maxPercentDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, err); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta); + } + + function _assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRel(a, b, maxPercentDelta, err); + } + + function _assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, bool expectFail) + external + expectFailure(expectFail) + { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals); + } + + function _assertApproxEqRelDecimal( + int256 a, + int256 b, + uint256 maxPercentDelta, + uint256 decimals, + string memory err, + bool expectFail + ) external expectFailure(expectFail) { + assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals, err); + } + + function _assertEqCall( + address targetA, + bytes memory callDataA, + address targetB, + bytes memory callDataB, + bool strictRevertData, + bool expectFail + ) external expectFailure(expectFail) { + assertEqCall(targetA, callDataA, targetB, callDataB, strictRevertData); + } +} + +contract TestMockCall { + bytes returnData; + bool shouldRevert; + + constructor(bytes memory returnData_, bool shouldRevert_) { + returnData = returnData_; + shouldRevert = shouldRevert_; + } + + fallback() external payable { + bytes memory returnData_ = returnData; + + if (shouldRevert) { + assembly { + revert(add(returnData_, 0x20), mload(returnData_)) + } + } else { + assembly { + return(add(returnData_, 0x20), mload(returnData_)) + } + } + } +} diff --git a/lib/forge-std/test/StdChains.t.sol b/lib/forge-std/test/StdChains.t.sol new file mode 100644 index 0000000..dab3751 --- /dev/null +++ b/lib/forge-std/test/StdChains.t.sol @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdChainsMock is Test { + function exposed_getChain(string memory chainAlias) public returns (Chain memory) { + return getChain(chainAlias); + } + + function exposed_getChain(uint256 chainId) public returns (Chain memory) { + return getChain(chainId); + } + + function exposed_setChain(string memory chainAlias, ChainData memory chainData) public { + setChain(chainAlias, chainData); + } + + function exposed_setFallbackToDefaultRpcUrls(bool useDefault) public { + setFallbackToDefaultRpcUrls(useDefault); + } +} + +contract StdChainsTest is Test { + function test_ChainRpcInitialization() public { + // RPCs specified in `foundry.toml` should be updated. + assertEq(getChain(1).rpcUrl, "https://mainnet.infura.io/v3/b1d3925804e74152b316ca7da97060d3"); + assertEq(getChain("optimism_goerli").rpcUrl, "https://goerli.optimism.io/"); + assertEq(getChain("arbitrum_one_goerli").rpcUrl, "https://goerli-rollup.arbitrum.io/rpc/"); + + // Environment variables should be the next fallback + assertEq(getChain("arbitrum_nova").rpcUrl, "https://nova.arbitrum.io/rpc"); + vm.setEnv("ARBITRUM_NOVA_RPC_URL", "myoverride"); + assertEq(getChain("arbitrum_nova").rpcUrl, "myoverride"); + vm.setEnv("ARBITRUM_NOVA_RPC_URL", "https://nova.arbitrum.io/rpc"); + + // Cannot override RPCs defined in `foundry.toml` + vm.setEnv("MAINNET_RPC_URL", "myoverride2"); + assertEq(getChain("mainnet").rpcUrl, "https://mainnet.infura.io/v3/b1d3925804e74152b316ca7da97060d3"); + + // Other RPCs should remain unchanged. + assertEq(getChain(31337).rpcUrl, "http://127.0.0.1:8545"); + assertEq(getChain("sepolia").rpcUrl, "https://sepolia.infura.io/v3/b9794ad1ddf84dfb8c34d6bb5dca2001"); + } + + function testFuzz_Rpc(string memory rpcAlias) internal { + string memory rpcUrl = getChain(rpcAlias).rpcUrl; + vm.createSelectFork(rpcUrl); + } + + // Ensure we can connect to the default RPC URL for each chain. + // function testRpcs() public { + // testRpc("mainnet"); + // testRpc("goerli"); + // testRpc("sepolia"); + // testRpc("optimism"); + // testRpc("optimism_goerli"); + // testRpc("arbitrum_one"); + // testRpc("arbitrum_one_goerli"); + // testRpc("arbitrum_nova"); + // testRpc("polygon"); + // testRpc("polygon_mumbai"); + // testRpc("avalanche"); + // testRpc("avalanche_fuji"); + // testRpc("bnb_smart_chain"); + // testRpc("bnb_smart_chain_testnet"); + // testRpc("gnosis_chain"); + // testRpc("moonbeam"); + // testRpc("moonriver"); + // testRpc("moonbase"); + // testRpc("base_goerli"); + // testRpc("base"); + // } + + function test_ChainNoDefault() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + vm.expectRevert("StdChains getChain(string): Chain with alias \"does_not_exist\" not found."); + stdChainsMock.exposed_getChain("does_not_exist"); + } + + function test_SetChainFirstFails() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + vm.expectRevert("StdChains setChain(string,ChainData): Chain ID 31337 already used by \"anvil\"."); + stdChainsMock.exposed_setChain("anvil2", ChainData("Anvil", 31337, "URL")); + } + + function test_ChainBubbleUp() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + stdChainsMock.exposed_setChain("needs_undefined_env_var", ChainData("", 123456789, "")); + vm.expectRevert( + "Failed to resolve env var `UNDEFINED_RPC_URL_PLACEHOLDER` in `${UNDEFINED_RPC_URL_PLACEHOLDER}`: environment variable not found" + ); + stdChainsMock.exposed_getChain("needs_undefined_env_var"); + } + + function test_CannotSetChain_ChainIdExists() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + stdChainsMock.exposed_setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + + vm.expectRevert('StdChains setChain(string,ChainData): Chain ID 123456789 already used by "custom_chain".'); + + stdChainsMock.exposed_setChain("another_custom_chain", ChainData("", 123456789, "")); + } + + function test_SetChain() public { + setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + Chain memory customChain = getChain("custom_chain"); + assertEq(customChain.name, "Custom Chain"); + assertEq(customChain.chainId, 123456789); + assertEq(customChain.chainAlias, "custom_chain"); + assertEq(customChain.rpcUrl, "https://custom.chain/"); + Chain memory chainById = getChain(123456789); + assertEq(chainById.name, customChain.name); + assertEq(chainById.chainId, customChain.chainId); + assertEq(chainById.chainAlias, customChain.chainAlias); + assertEq(chainById.rpcUrl, customChain.rpcUrl); + customChain.name = "Another Custom Chain"; + customChain.chainId = 987654321; + setChain("another_custom_chain", customChain); + Chain memory anotherCustomChain = getChain("another_custom_chain"); + assertEq(anotherCustomChain.name, "Another Custom Chain"); + assertEq(anotherCustomChain.chainId, 987654321); + assertEq(anotherCustomChain.chainAlias, "another_custom_chain"); + assertEq(anotherCustomChain.rpcUrl, "https://custom.chain/"); + // Verify the first chain data was not overwritten + chainById = getChain(123456789); + assertEq(chainById.name, "Custom Chain"); + assertEq(chainById.chainId, 123456789); + } + + function test_SetNoEmptyAlias() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + vm.expectRevert("StdChains setChain(string,ChainData): Chain alias cannot be the empty string."); + stdChainsMock.exposed_setChain("", ChainData("", 123456789, "")); + } + + function test_SetNoChainId0() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + vm.expectRevert("StdChains setChain(string,ChainData): Chain ID cannot be 0."); + stdChainsMock.exposed_setChain("alias", ChainData("", 0, "")); + } + + function test_GetNoChainId0() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + vm.expectRevert("StdChains getChain(uint256): Chain ID cannot be 0."); + stdChainsMock.exposed_getChain(0); + } + + function test_GetNoEmptyAlias() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + vm.expectRevert("StdChains getChain(string): Chain alias cannot be the empty string."); + stdChainsMock.exposed_getChain(""); + } + + function test_ChainIdNotFound() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + vm.expectRevert("StdChains getChain(string): Chain with alias \"no_such_alias\" not found."); + stdChainsMock.exposed_getChain("no_such_alias"); + } + + function test_ChainAliasNotFound() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + vm.expectRevert("StdChains getChain(uint256): Chain with ID 321 not found."); + + stdChainsMock.exposed_getChain(321); + } + + function test_SetChain_ExistingOne() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + setChain("custom_chain", ChainData("Custom Chain", 123456789, "https://custom.chain/")); + assertEq(getChain(123456789).chainId, 123456789); + + setChain("custom_chain", ChainData("Modified Chain", 999999999, "https://modified.chain/")); + vm.expectRevert("StdChains getChain(uint256): Chain with ID 123456789 not found."); + stdChainsMock.exposed_getChain(123456789); + + Chain memory modifiedChain = getChain(999999999); + assertEq(modifiedChain.name, "Modified Chain"); + assertEq(modifiedChain.chainId, 999999999); + assertEq(modifiedChain.rpcUrl, "https://modified.chain/"); + } + + function test_DontUseDefaultRpcUrl() public { + // We deploy a mock to properly test the revert. + StdChainsMock stdChainsMock = new StdChainsMock(); + + // Should error if default RPCs flag is set to false. + stdChainsMock.exposed_setFallbackToDefaultRpcUrls(false); + vm.expectRevert( + "Failed to get environment variable `ANVIL_RPC_URL` as type `string`: environment variable not found" + ); + stdChainsMock.exposed_getChain(31337); + vm.expectRevert( + "Failed to get environment variable `SEPOLIA_RPC_URL` as type `string`: environment variable not found" + ); + stdChainsMock.exposed_getChain("sepolia"); + } +} diff --git a/lib/forge-std/test/StdCheats.t.sol b/lib/forge-std/test/StdCheats.t.sol new file mode 100644 index 0000000..d7b3517 --- /dev/null +++ b/lib/forge-std/test/StdCheats.t.sol @@ -0,0 +1,610 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdCheats.sol"; +import "../src/Test.sol"; +import "../src/StdJson.sol"; + +contract StdCheatsTest is Test { + Bar test; + + using stdJson for string; + + function setUp() public { + test = new Bar(); + } + + function test_Skip() public { + vm.warp(100); + skip(25); + assertEq(block.timestamp, 125); + } + + function test_Rewind() public { + vm.warp(100); + rewind(25); + assertEq(block.timestamp, 75); + } + + function test_Hoax() public { + hoax(address(1337)); + test.bar{value: 100}(address(1337)); + } + + function test_HoaxOrigin() public { + hoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + } + + function test_HoaxDifferentAddresses() public { + hoax(address(1337), address(7331)); + test.origin{value: 100}(address(1337), address(7331)); + } + + function test_StartHoax() public { + startHoax(address(1337)); + test.bar{value: 100}(address(1337)); + test.bar{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function test_StartHoaxOrigin() public { + startHoax(address(1337), address(1337)); + test.origin{value: 100}(address(1337)); + test.origin{value: 100}(address(1337)); + vm.stopPrank(); + test.bar(address(this)); + } + + function test_ChangePrankMsgSender() public { + vm.startPrank(address(1337)); + test.bar(address(1337)); + changePrank(address(0xdead)); + test.bar(address(0xdead)); + changePrank(address(1337)); + test.bar(address(1337)); + vm.stopPrank(); + } + + function test_ChangePrankMsgSenderAndTxOrigin() public { + vm.startPrank(address(1337), address(1338)); + test.origin(address(1337), address(1338)); + changePrank(address(0xdead), address(0xbeef)); + test.origin(address(0xdead), address(0xbeef)); + changePrank(address(1337), address(1338)); + test.origin(address(1337), address(1338)); + vm.stopPrank(); + } + + function test_MakeAccountEquivalence() public { + Account memory account = makeAccount("1337"); + (address addr, uint256 key) = makeAddrAndKey("1337"); + assertEq(account.addr, addr); + assertEq(account.key, key); + } + + function test_MakeAddrEquivalence() public { + (address addr,) = makeAddrAndKey("1337"); + assertEq(makeAddr("1337"), addr); + } + + function test_MakeAddrSigning() public { + (address addr, uint256 key) = makeAddrAndKey("1337"); + bytes32 hash = keccak256("some_message"); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash); + assertEq(ecrecover(hash, v, r, s), addr); + } + + function test_Deal() public { + deal(address(this), 1 ether); + assertEq(address(this).balance, 1 ether); + } + + function tes_tDealToken() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18); + assertEq(barToken.balanceOf(address(this)), 10000e18); + } + + function test_DealTokenAdjustTotalSupply() public { + Bar barToken = new Bar(); + address bar = address(barToken); + deal(bar, address(this), 10000e18, true); + assertEq(barToken.balanceOf(address(this)), 10000e18); + assertEq(barToken.totalSupply(), 20000e18); + deal(bar, address(this), 0, true); + assertEq(barToken.balanceOf(address(this)), 0); + assertEq(barToken.totalSupply(), 10000e18); + } + + function test_DealERC1155Token() public { + BarERC1155 barToken = new BarERC1155(); + address bar = address(barToken); + dealERC1155(bar, address(this), 0, 10000e18, false); + assertEq(barToken.balanceOf(address(this), 0), 10000e18); + } + + function test_DealERC1155TokenAdjustTotalSupply() public { + BarERC1155 barToken = new BarERC1155(); + address bar = address(barToken); + dealERC1155(bar, address(this), 0, 10000e18, true); + assertEq(barToken.balanceOf(address(this), 0), 10000e18); + assertEq(barToken.totalSupply(0), 20000e18); + dealERC1155(bar, address(this), 0, 0, true); + assertEq(barToken.balanceOf(address(this), 0), 0); + assertEq(barToken.totalSupply(0), 10000e18); + } + + function test_DealERC721Token() public { + BarERC721 barToken = new BarERC721(); + address bar = address(barToken); + dealERC721(bar, address(2), 1); + assertEq(barToken.balanceOf(address(2)), 1); + assertEq(barToken.balanceOf(address(1)), 0); + dealERC721(bar, address(1), 2); + assertEq(barToken.balanceOf(address(1)), 1); + assertEq(barToken.balanceOf(bar), 1); + } + + function test_DeployCode() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes("")); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function test_DestroyAccount() public { + // deploy something to destroy it + BarERC721 barToken = new BarERC721(); + address bar = address(barToken); + vm.setNonce(bar, 10); + deal(bar, 100); + + uint256 prevThisBalance = address(this).balance; + uint256 size; + assembly { + size := extcodesize(bar) + } + + assertGt(size, 0); + assertEq(bar.balance, 100); + assertEq(vm.getNonce(bar), 10); + + destroyAccount(bar, address(this)); + assembly { + size := extcodesize(bar) + } + assertEq(address(this).balance, prevThisBalance + 100); + assertEq(vm.getNonce(bar), 0); + assertEq(size, 0); + assertEq(bar.balance, 0); + } + + function test_DeployCodeNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar"); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + } + + function test_DeployCodeVal() public { + address deployed = deployCode("StdCheats.t.sol:Bar", bytes(""), 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + function test_DeployCodeValNoArgs() public { + address deployed = deployCode("StdCheats.t.sol:Bar", 1 ether); + assertEq(string(getCode(deployed)), string(getCode(address(test)))); + assertEq(deployed.balance, 1 ether); + } + + // We need this so we can call "this.deployCode" rather than "deployCode" directly + function deployCodeHelper(string memory what) external { + deployCode(what); + } + + function test_DeployCodeFail() public { + vm.expectRevert(bytes("StdCheats deployCode(string): Deployment failed.")); + this.deployCodeHelper("StdCheats.t.sol:RevertingContract"); + } + + function getCode(address who) internal view returns (bytes memory o_code) { + /// @solidity memory-safe-assembly + assembly { + // retrieve the size of the code, this needs assembly + let size := extcodesize(who) + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + o_code := mload(0x40) + // new "memory end" including padding + mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f)))) + // store length in memory + mstore(o_code, size) + // actually retrieve the code, this needs assembly + extcodecopy(who, add(o_code, 0x20), 0, size) + } + } + + function test_DeriveRememberKey() public { + string memory mnemonic = "test test test test test test test test test test test junk"; + + (address deployer, uint256 privateKey) = deriveRememberKey(mnemonic, 0); + assertEq(deployer, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(privateKey, 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80); + } + + function test_BytesToUint() public { + assertEq(3, bytesToUint_test(hex"03")); + assertEq(2, bytesToUint_test(hex"02")); + assertEq(255, bytesToUint_test(hex"ff")); + assertEq(29625, bytesToUint_test(hex"73b9")); + } + + function test_ParseJsonTxDetail() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + string memory json = vm.readFile(path); + bytes memory transactionDetails = json.parseRaw(".transactions[0].tx"); + RawTx1559Detail memory rawTxDetail = abi.decode(transactionDetails, (RawTx1559Detail)); + Tx1559Detail memory txDetail = rawToConvertedEIP1559Detail(rawTxDetail); + assertEq(txDetail.from, 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266); + assertEq(txDetail.to, 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512); + assertEq( + txDetail.data, + hex"23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004" + ); + assertEq(txDetail.nonce, 3); + assertEq(txDetail.txType, 2); + assertEq(txDetail.gas, 29625); + assertEq(txDetail.value, 0); + } + + function test_ReadEIP1559Transaction() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 0; + Tx1559 memory transaction = readTx1559(path, index); + transaction; + } + + function test_ReadEIP1559Transactions() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Tx1559[] memory transactions = readTx1559s(path); + transactions; + } + + function test_ReadReceipt() public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + uint256 index = 5; + Receipt memory receipt = readReceipt(path, index); + assertEq( + receipt.logsBloom, + hex"00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100" + ); + } + + function test_ReadReceipts() public view { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/test/fixtures/broadcast.log.json"); + Receipt[] memory receipts = readReceipts(path); + receipts; + } + + function test_GasMeteringModifier() public { + uint256 gas_start_normal = gasleft(); + addInLoop(); + uint256 gas_used_normal = gas_start_normal - gasleft(); + + uint256 gas_start_single = gasleft(); + addInLoopNoGas(); + uint256 gas_used_single = gas_start_single - gasleft(); + + uint256 gas_start_double = gasleft(); + addInLoopNoGasNoGas(); + uint256 gas_used_double = gas_start_double - gasleft(); + + emit log_named_uint("Normal gas", gas_used_normal); + emit log_named_uint("Single modifier gas", gas_used_single); + emit log_named_uint("Double modifier gas", gas_used_double); + assertTrue(gas_used_double + gas_used_single < gas_used_normal); + } + + function addInLoop() internal pure returns (uint256) { + uint256 b; + for (uint256 i; i < 10000; i++) { + b += i; + } + return b; + } + + function addInLoopNoGas() internal noGasMetering returns (uint256) { + return addInLoop(); + } + + function addInLoopNoGasNoGas() internal noGasMetering returns (uint256) { + return addInLoopNoGas(); + } + + function bytesToUint_test(bytes memory b) private pure returns (uint256) { + uint256 number; + for (uint256 i = 0; i < b.length; i++) { + number = number + uint256(uint8(b[i])) * (2 ** (8 * (b.length - (i + 1)))); + } + return number; + } + + function testFuzz_AssumeAddressIsNot(address addr) external { + // skip over Payable and NonPayable enums + for (uint8 i = 2; i < uint8(type(AddressType).max); i++) { + assumeAddressIsNot(addr, AddressType(i)); + } + assertTrue(addr != address(0)); + assertTrue(addr < address(1) || addr > address(9)); + assertTrue(addr != address(vm) || addr != 0x000000000000000000636F6e736F6c652e6c6f67); + } + + function test_AssumePayable() external { + // We deploy a mock version so we can properly test the revert. + StdCheatsMock stdCheatsMock = new StdCheatsMock(); + + // all should revert since these addresses are not payable + + // VM address + vm.expectRevert(); + stdCheatsMock.exposed_assumePayable(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + // Console address + vm.expectRevert(); + stdCheatsMock.exposed_assumePayable(0x000000000000000000636F6e736F6c652e6c6f67); + + // Create2Deployer + vm.expectRevert(); + stdCheatsMock.exposed_assumePayable(0x4e59b44847b379578588920cA78FbF26c0B4956C); + + // all should pass since these addresses are payable + + // vitalik.eth + stdCheatsMock.exposed_assumePayable(0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045); + + // mock payable contract + MockContractPayable cp = new MockContractPayable(); + stdCheatsMock.exposed_assumePayable(address(cp)); + } + + function test_AssumeNotPayable() external { + // We deploy a mock version so we can properly test the revert. + StdCheatsMock stdCheatsMock = new StdCheatsMock(); + + // all should pass since these addresses are not payable + + // VM address + stdCheatsMock.exposed_assumeNotPayable(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + // Console address + stdCheatsMock.exposed_assumeNotPayable(0x000000000000000000636F6e736F6c652e6c6f67); + + // Create2Deployer + stdCheatsMock.exposed_assumeNotPayable(0x4e59b44847b379578588920cA78FbF26c0B4956C); + + // all should revert since these addresses are payable + + // vitalik.eth + vm.expectRevert(); + stdCheatsMock.exposed_assumeNotPayable(0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045); + + // mock payable contract + MockContractPayable cp = new MockContractPayable(); + vm.expectRevert(); + stdCheatsMock.exposed_assumeNotPayable(address(cp)); + } + + function testFuzz_AssumeNotPrecompile(address addr) external { + assumeNotPrecompile(addr, getChain("optimism_goerli").chainId); + assertTrue( + addr < address(1) || (addr > address(9) && addr < address(0x4200000000000000000000000000000000000000)) + || addr > address(0x4200000000000000000000000000000000000800) + ); + } + + function testFuzz_AssumeNotForgeAddress(address addr) external { + assumeNotForgeAddress(addr); + assertTrue( + addr != address(vm) && addr != 0x000000000000000000636F6e736F6c652e6c6f67 + && addr != 0x4e59b44847b379578588920cA78FbF26c0B4956C + ); + } + + function test_CannotDeployCodeTo() external { + vm.expectRevert("StdCheats deployCodeTo(string,bytes,uint256,address): Failed to create runtime bytecode."); + this._revertDeployCodeTo(); + } + + function _revertDeployCodeTo() external { + deployCodeTo("StdCheats.t.sol:RevertingContract", address(0)); + } + + function test_DeployCodeTo() external { + address arbitraryAddress = makeAddr("arbitraryAddress"); + + deployCodeTo( + "StdCheats.t.sol:MockContractWithConstructorArgs", + abi.encode(uint256(6), true, bytes20(arbitraryAddress)), + 1 ether, + arbitraryAddress + ); + + MockContractWithConstructorArgs ct = MockContractWithConstructorArgs(arbitraryAddress); + + assertEq(arbitraryAddress.balance, 1 ether); + assertEq(ct.x(), 6); + assertTrue(ct.y()); + assertEq(ct.z(), bytes20(arbitraryAddress)); + } +} + +contract StdCheatsMock is StdCheats { + function exposed_assumePayable(address addr) external { + assumePayable(addr); + } + + function exposed_assumeNotPayable(address addr) external { + assumeNotPayable(addr); + } + + // We deploy a mock version so we can properly test expected reverts. + function exposed_assumeNotBlacklisted(address token, address addr) external view { + return assumeNotBlacklisted(token, addr); + } +} + +contract StdCheatsForkTest is Test { + address internal constant SHIB = 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE; + address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address internal constant USDC_BLACKLISTED_USER = 0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD; + address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + address internal constant USDT_BLACKLISTED_USER = 0x8f8a8F4B54a2aAC7799d7bc81368aC27b852822A; + + function setUp() public { + // All tests of the `assumeNotBlacklisted` method are fork tests using live contracts. + vm.createSelectFork({urlOrAlias: "mainnet", blockNumber: 16_428_900}); + } + + function test_CannotAssumeNoBlacklisted_EOA() external { + // We deploy a mock version so we can properly test the revert. + StdCheatsMock stdCheatsMock = new StdCheatsMock(); + address eoa = vm.addr({privateKey: 1}); + vm.expectRevert("StdCheats assumeNotBlacklisted(address,address): Token address is not a contract."); + stdCheatsMock.exposed_assumeNotBlacklisted(eoa, address(0)); + } + + function testFuzz_AssumeNotBlacklisted_TokenWithoutBlacklist(address addr) external { + assumeNotBlacklisted(SHIB, addr); + assertTrue(true); + } + + function test_AssumeNoBlacklisted_USDC() external { + // We deploy a mock version so we can properly test the revert. + StdCheatsMock stdCheatsMock = new StdCheatsMock(); + vm.expectRevert(); + stdCheatsMock.exposed_assumeNotBlacklisted(USDC, USDC_BLACKLISTED_USER); + } + + function testFuzz_AssumeNotBlacklisted_USDC(address addr) external { + assumeNotBlacklisted(USDC, addr); + assertFalse(USDCLike(USDC).isBlacklisted(addr)); + } + + function test_AssumeNoBlacklisted_USDT() external { + // We deploy a mock version so we can properly test the revert. + StdCheatsMock stdCheatsMock = new StdCheatsMock(); + vm.expectRevert(); + stdCheatsMock.exposed_assumeNotBlacklisted(USDT, USDT_BLACKLISTED_USER); + } + + function testFuzz_AssumeNotBlacklisted_USDT(address addr) external { + assumeNotBlacklisted(USDT, addr); + assertFalse(USDTLike(USDT).isBlackListed(addr)); + } +} + +contract Bar { + constructor() payable { + /// `DEAL` STDCHEAT + totalSupply = 10000e18; + balanceOf[address(this)] = totalSupply; + } + + /// `HOAX` and `CHANGEPRANK` STDCHEATS + function bar(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + } + + function origin(address expectedSender) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedSender, "!prank"); + } + + function origin(address expectedSender, address expectedOrigin) public payable { + require(msg.sender == expectedSender, "!prank"); + require(tx.origin == expectedOrigin, "!prank"); + } + + /// `DEAL` STDCHEAT + mapping(address => uint256) public balanceOf; + uint256 public totalSupply; +} + +contract BarERC1155 { + constructor() payable { + /// `DEALERC1155` STDCHEAT + _totalSupply[0] = 10000e18; + _balances[0][address(this)] = _totalSupply[0]; + } + + function balanceOf(address account, uint256 id) public view virtual returns (uint256) { + return _balances[id][account]; + } + + function totalSupply(uint256 id) public view virtual returns (uint256) { + return _totalSupply[id]; + } + + /// `DEALERC1155` STDCHEAT + mapping(uint256 => mapping(address => uint256)) private _balances; + mapping(uint256 => uint256) private _totalSupply; +} + +contract BarERC721 { + constructor() payable { + /// `DEALERC721` STDCHEAT + _owners[1] = address(1); + _balances[address(1)] = 1; + _owners[2] = address(this); + _owners[3] = address(this); + _balances[address(this)] = 2; + } + + function balanceOf(address owner) public view virtual returns (uint256) { + return _balances[owner]; + } + + function ownerOf(uint256 tokenId) public view virtual returns (address) { + address owner = _owners[tokenId]; + return owner; + } + + mapping(uint256 => address) private _owners; + mapping(address => uint256) private _balances; +} + +interface USDCLike { + function isBlacklisted(address) external view returns (bool); +} + +interface USDTLike { + function isBlackListed(address) external view returns (bool); +} + +contract RevertingContract { + constructor() { + revert(); + } +} + +contract MockContractWithConstructorArgs { + uint256 public immutable x; + bool public y; + bytes20 public z; + + constructor(uint256 _x, bool _y, bytes20 _z) payable { + x = _x; + y = _y; + z = _z; + } +} + +contract MockContractPayable { + receive() external payable {} +} diff --git a/lib/forge-std/test/StdError.t.sol b/lib/forge-std/test/StdError.t.sol new file mode 100644 index 0000000..a6da60b --- /dev/null +++ b/lib/forge-std/test/StdError.t.sol @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdError.sol"; +import "../src/Test.sol"; + +contract StdErrorsTest is Test { + ErrorsTest test; + + function setUp() public { + test = new ErrorsTest(); + } + + function test_ExpectAssertion() public { + vm.expectRevert(stdError.assertionError); + test.assertionError(); + } + + function test_ExpectArithmetic() public { + vm.expectRevert(stdError.arithmeticError); + test.arithmeticError(10); + } + + function test_ExpectDiv() public { + vm.expectRevert(stdError.divisionError); + test.divError(0); + } + + function test_ExpectMod() public { + vm.expectRevert(stdError.divisionError); + test.modError(0); + } + + function test_ExpectEnum() public { + vm.expectRevert(stdError.enumConversionError); + test.enumConversion(1); + } + + function test_ExpectEncodeStg() public { + vm.expectRevert(stdError.encodeStorageError); + test.encodeStgError(); + } + + function test_ExpectPop() public { + vm.expectRevert(stdError.popError); + test.pop(); + } + + function test_ExpectOOB() public { + vm.expectRevert(stdError.indexOOBError); + test.indexOOBError(1); + } + + function test_ExpectMem() public { + vm.expectRevert(stdError.memOverflowError); + test.mem(); + } + + function test_ExpectIntern() public { + vm.expectRevert(stdError.zeroVarError); + test.intern(); + } +} + +contract ErrorsTest { + enum T {T1} + + uint256[] public someArr; + bytes someBytes; + + function assertionError() public pure { + assert(false); + } + + function arithmeticError(uint256 a) public pure { + a -= 100; + } + + function divError(uint256 a) public pure { + 100 / a; + } + + function modError(uint256 a) public pure { + 100 % a; + } + + function enumConversion(uint256 a) public pure { + T(a); + } + + function encodeStgError() public { + /// @solidity memory-safe-assembly + assembly { + sstore(someBytes.slot, 1) + } + keccak256(someBytes); + } + + function pop() public { + someArr.pop(); + } + + function indexOOBError(uint256 a) public pure { + uint256[] memory t = new uint256[](0); + t[a]; + } + + function mem() public pure { + uint256 l = 2 ** 256 / 32; + new uint256[](l); + } + + function intern() public returns (uint256) { + function(uint256) internal returns (uint256) x; + x(2); + return 7; + } +} diff --git a/lib/forge-std/test/StdMath.t.sol b/lib/forge-std/test/StdMath.t.sol new file mode 100644 index 0000000..6f50638 --- /dev/null +++ b/lib/forge-std/test/StdMath.t.sol @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import "../src/StdMath.sol"; +import "../src/Test.sol"; + +contract StdMathMock is Test { + function exposed_percentDelta(uint256 a, uint256 b) public pure returns (uint256) { + return stdMath.percentDelta(a, b); + } + + function exposed_percentDelta(int256 a, int256 b) public pure returns (uint256) { + return stdMath.percentDelta(a, b); + } +} + +contract StdMathTest is Test { + function test_GetAbs() external { + assertEq(stdMath.abs(-50), 50); + assertEq(stdMath.abs(50), 50); + assertEq(stdMath.abs(-1337), 1337); + assertEq(stdMath.abs(0), 0); + + assertEq(stdMath.abs(type(int256).min), (type(uint256).max >> 1) + 1); + assertEq(stdMath.abs(type(int256).max), (type(uint256).max >> 1)); + } + + function testFuzz_GetAbs(int256 a) external { + uint256 manualAbs = getAbs(a); + + uint256 abs = stdMath.abs(a); + + assertEq(abs, manualAbs); + } + + function test_GetDelta_Uint() external { + assertEq(stdMath.delta(uint256(0), uint256(0)), 0); + assertEq(stdMath.delta(uint256(0), uint256(1337)), 1337); + assertEq(stdMath.delta(uint256(0), type(uint64).max), type(uint64).max); + assertEq(stdMath.delta(uint256(0), type(uint128).max), type(uint128).max); + assertEq(stdMath.delta(uint256(0), type(uint256).max), type(uint256).max); + + assertEq(stdMath.delta(0, uint256(0)), 0); + assertEq(stdMath.delta(1337, uint256(0)), 1337); + assertEq(stdMath.delta(type(uint64).max, uint256(0)), type(uint64).max); + assertEq(stdMath.delta(type(uint128).max, uint256(0)), type(uint128).max); + assertEq(stdMath.delta(type(uint256).max, uint256(0)), type(uint256).max); + + assertEq(stdMath.delta(1337, uint256(1337)), 0); + assertEq(stdMath.delta(type(uint256).max, type(uint256).max), 0); + assertEq(stdMath.delta(5000, uint256(1250)), 3750); + } + + function testFuzz_GetDelta_Uint(uint256 a, uint256 b) external { + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function test_GetDelta_Int() external { + assertEq(stdMath.delta(int256(0), int256(0)), 0); + assertEq(stdMath.delta(int256(0), int256(1337)), 1337); + assertEq(stdMath.delta(int256(0), type(int64).max), type(uint64).max >> 1); + assertEq(stdMath.delta(int256(0), type(int128).max), type(uint128).max >> 1); + assertEq(stdMath.delta(int256(0), type(int256).max), type(uint256).max >> 1); + + assertEq(stdMath.delta(0, int256(0)), 0); + assertEq(stdMath.delta(1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).max, int256(0)), type(uint64).max >> 1); + assertEq(stdMath.delta(type(int128).max, int256(0)), type(uint128).max >> 1); + assertEq(stdMath.delta(type(int256).max, int256(0)), type(uint256).max >> 1); + + assertEq(stdMath.delta(-0, int256(0)), 0); + assertEq(stdMath.delta(-1337, int256(0)), 1337); + assertEq(stdMath.delta(type(int64).min, int256(0)), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(type(int128).min, int256(0)), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(type(int256).min, int256(0)), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(int256(0), -0), 0); + assertEq(stdMath.delta(int256(0), -1337), 1337); + assertEq(stdMath.delta(int256(0), type(int64).min), (type(uint64).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int128).min), (type(uint128).max >> 1) + 1); + assertEq(stdMath.delta(int256(0), type(int256).min), (type(uint256).max >> 1) + 1); + + assertEq(stdMath.delta(1337, int256(1337)), 0); + assertEq(stdMath.delta(type(int256).max, type(int256).max), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).min), 0); + assertEq(stdMath.delta(type(int256).min, type(int256).max), type(uint256).max); + assertEq(stdMath.delta(5000, int256(1250)), 3750); + } + + function testFuzz_GetDelta_Int(int256 a, int256 b) external { + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 delta = stdMath.delta(a, b); + + assertEq(delta, manualDelta); + } + + function test_GetPercentDelta_Uint() external { + StdMathMock stdMathMock = new StdMathMock(); + + assertEq(stdMath.percentDelta(uint256(0), uint256(1337)), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint64).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint128).max), 1e18); + assertEq(stdMath.percentDelta(uint256(0), type(uint192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, uint256(1337)), 0); + assertEq(stdMath.percentDelta(type(uint192).max, type(uint192).max), 0); + assertEq(stdMath.percentDelta(0, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, uint256(2500)), 0); + assertEq(stdMath.percentDelta(5000, uint256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, uint256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMathMock.exposed_percentDelta(uint256(1), 0); + } + + function testFuzz_GetPercentDelta_Uint(uint192 a, uint192 b) external { + vm.assume(b != 0); + uint256 manualDelta; + if (a > b) { + manualDelta = a - b; + } else { + manualDelta = b - a; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / b; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + function test_GetPercentDelta_Int() external { + // We deploy a mock version so we can properly test the revert. + StdMathMock stdMathMock = new StdMathMock(); + + assertEq(stdMath.percentDelta(int256(0), int256(1337)), 1e18); + assertEq(stdMath.percentDelta(int256(0), -1337), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).min), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int64).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int128).max), 1e18); + assertEq(stdMath.percentDelta(int256(0), type(int192).max), 1e18); + + assertEq(stdMath.percentDelta(1337, int256(1337)), 0); + assertEq(stdMath.percentDelta(type(int192).max, type(int192).max), 0); + assertEq(stdMath.percentDelta(type(int192).min, type(int192).min), 0); + + assertEq(stdMath.percentDelta(type(int192).min, type(int192).max), 2e18); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(type(int192).max, type(int192).min), 2e18 - 1); // rounds the 1 wei diff down + assertEq(stdMath.percentDelta(0, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(2500, int256(2500)), 0); + assertEq(stdMath.percentDelta(5000, int256(2500)), 1e18); + assertEq(stdMath.percentDelta(7500, int256(2500)), 2e18); + + vm.expectRevert(stdError.divisionError); + stdMathMock.exposed_percentDelta(int256(1), 0); + } + + function testFuzz_GetPercentDelta_Int(int192 a, int192 b) external { + vm.assume(b != 0); + uint256 absA = getAbs(a); + uint256 absB = getAbs(b); + uint256 absDelta = absA > absB ? absA - absB : absB - absA; + + uint256 manualDelta; + if ((a >= 0 && b >= 0) || (a < 0 && b < 0)) { + manualDelta = absDelta; + } + // (a < 0 && b >= 0) || (a >= 0 && b < 0) + else { + manualDelta = absA + absB; + } + + uint256 manualPercentDelta = manualDelta * 1e18 / absB; + uint256 percentDelta = stdMath.percentDelta(a, b); + + assertEq(percentDelta, manualPercentDelta); + } + + /*////////////////////////////////////////////////////////////////////////// + HELPERS + //////////////////////////////////////////////////////////////////////////*/ + + function getAbs(int256 a) private pure returns (uint256) { + if (a < 0) { + return a == type(int256).min ? uint256(type(int256).max) + 1 : uint256(-a); + } + + return uint256(a); + } +} diff --git a/lib/forge-std/test/StdStorage.t.sol b/lib/forge-std/test/StdStorage.t.sol new file mode 100644 index 0000000..0b3ca9b --- /dev/null +++ b/lib/forge-std/test/StdStorage.t.sol @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/StdStorage.sol"; +import "../src/Test.sol"; + +contract StdStorageTest is Test { + using stdStorage for StdStorage; + + StorageTest internal test; + + function setUp() public { + test = new StorageTest(); + } + + function test_StorageHidden() public { + assertEq(uint256(keccak256("my.random.var")), stdstore.target(address(test)).sig("hidden()").find()); + } + + function test_StorageObvious() public { + assertEq(uint256(0), stdstore.target(address(test)).sig("exists()").find()); + } + + function test_StorageExtraSload() public { + assertEq(16, stdstore.target(address(test)).sig(test.extra_sload.selector).find()); + } + + function test_StorageCheckedWriteHidden() public { + stdstore.target(address(test)).sig(test.hidden.selector).checked_write(100); + assertEq(uint256(test.hidden()), 100); + } + + function test_StorageCheckedWriteObvious() public { + stdstore.target(address(test)).sig(test.exists.selector).checked_write(100); + assertEq(test.exists(), 100); + } + + function test_StorageCheckedWriteSignedIntegerHidden() public { + stdstore.target(address(test)).sig(test.hidden.selector).checked_write_int(-100); + assertEq(int256(uint256(test.hidden())), -100); + } + + function test_StorageCheckedWriteSignedIntegerObvious() public { + stdstore.target(address(test)).sig(test.tG.selector).checked_write_int(-100); + assertEq(test.tG(), -100); + } + + function test_StorageMapStructA() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))), slot); + } + + function test_StorageMapStructB() public { + uint256 slot = + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).find(); + assertEq(uint256(keccak256(abi.encode(address(this), 4))) + 1, slot); + } + + function test_StorageDeepMap() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key( + address(this) + ).find(); + assertEq(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(5)))))), slot); + } + + function test_StorageCheckedWriteDeepMap() public { + stdstore.target(address(test)).sig(test.deep_map.selector).with_key(address(this)).with_key(address(this)) + .checked_write(100); + assertEq(100, test.deep_map(address(this), address(this))); + } + + function test_StorageDeepMapStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(0).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 0), + bytes32(slot) + ); + } + + function test_StorageDeepMapStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)) + .with_key(address(this)).depth(1).find(); + assertEq( + bytes32(uint256(keccak256(abi.encode(address(this), keccak256(abi.encode(address(this), uint256(6)))))) + 1), + bytes32(slot) + ); + } + + function test_StorageCheckedWriteDeepMapStructA() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(100, a); + assertEq(0, b); + } + + function test_StorageCheckedWriteDeepMapStructB() public { + stdstore.target(address(test)).sig(test.deep_map_struct.selector).with_key(address(this)).with_key( + address(this) + ).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.deep_map_struct(address(this), address(this)); + assertEq(0, a); + assertEq(100, b); + } + + function test_StorageCheckedWriteMapStructA() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 100); + assertEq(b, 0); + } + + function test_StorageCheckedWriteMapStructB() public { + stdstore.target(address(test)).sig(test.map_struct.selector).with_key(address(this)).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.map_struct(address(this)); + assertEq(a, 0); + assertEq(b, 100); + } + + function test_StorageStructA() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(0).find(); + assertEq(uint256(7), slot); + } + + function test_StorageStructB() public { + uint256 slot = stdstore.target(address(test)).sig(test.basic.selector).depth(1).find(); + assertEq(uint256(7) + 1, slot); + } + + function test_StorageCheckedWriteStructA() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(0).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 100); + assertEq(b, 1337); + } + + function test_StorageCheckedWriteStructB() public { + stdstore.target(address(test)).sig(test.basic.selector).depth(1).checked_write(100); + (uint256 a, uint256 b) = test.basic(); + assertEq(a, 1337); + assertEq(b, 100); + } + + function test_StorageMapAddrFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).find(); + assertEq(uint256(keccak256(abi.encode(address(this), uint256(1)))), slot); + } + + function test_StorageMapAddrRoot() public { + (uint256 slot, bytes32 key) = + stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).parent(); + assertEq(address(uint160(uint256(key))), address(this)); + assertEq(uint256(1), slot); + slot = stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).root(); + assertEq(uint256(1), slot); + } + + function test_StorageMapUintFound() public { + uint256 slot = stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).find(); + assertEq(uint256(keccak256(abi.encode(100, uint256(2)))), slot); + } + + function test_StorageCheckedWriteMapUint() public { + stdstore.target(address(test)).sig(test.map_uint.selector).with_key(100).checked_write(100); + assertEq(100, test.map_uint(100)); + } + + function test_StorageCheckedWriteMapAddr() public { + stdstore.target(address(test)).sig(test.map_addr.selector).with_key(address(this)).checked_write(100); + assertEq(100, test.map_addr(address(this))); + } + + function test_StorageCheckedWriteMapBool() public { + stdstore.target(address(test)).sig(test.map_bool.selector).with_key(address(this)).checked_write(true); + assertTrue(test.map_bool(address(this))); + } + + function testFail_StorageCheckedWriteMapPacked() public { + // expect PackedSlot error but not external call so cant expectRevert + stdstore.target(address(test)).sig(test.read_struct_lower.selector).with_key(address(uint160(1337))) + .checked_write(100); + } + + function test_StorageCheckedWriteMapPackedSuccess() public { + uint256 full = test.map_packed(address(1337)); + // keep upper 128, set lower 128 to 1337 + full = (full & (uint256((1 << 128) - 1) << 128)) | 1337; + stdstore.target(address(test)).sig(test.map_packed.selector).with_key(address(uint160(1337))).checked_write( + full + ); + assertEq(1337, test.read_struct_lower(address(1337))); + } + + function testFail_StorageConst() public { + // vm.expectRevert(abi.encodeWithSignature("NotStorage(bytes4)", bytes4(keccak256("const()")))); + stdstore.target(address(test)).sig("const()").find(); + } + + function testFail_StorageNativePack() public { + stdstore.target(address(test)).sig(test.tA.selector).find(); + stdstore.target(address(test)).sig(test.tB.selector).find(); + + // these both would fail + stdstore.target(address(test)).sig(test.tC.selector).find(); + stdstore.target(address(test)).sig(test.tD.selector).find(); + } + + function test_StorageReadBytes32() public { + bytes32 val = stdstore.target(address(test)).sig(test.tE.selector).read_bytes32(); + assertEq(val, hex"1337"); + } + + function test_StorageReadBool_False() public { + bool val = stdstore.target(address(test)).sig(test.tB.selector).read_bool(); + assertEq(val, false); + } + + function test_StorageReadBool_True() public { + bool val = stdstore.target(address(test)).sig(test.tH.selector).read_bool(); + assertEq(val, true); + } + + function test_StorageReadBool_Revert() public { + vm.expectRevert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool."); + this.readNonBoolValue(); + } + + function readNonBoolValue() public { + stdstore.target(address(test)).sig(test.tE.selector).read_bool(); + } + + function test_StorageReadAddress() public { + address val = stdstore.target(address(test)).sig(test.tF.selector).read_address(); + assertEq(val, address(1337)); + } + + function test_StorageReadUint() public { + uint256 val = stdstore.target(address(test)).sig(test.exists.selector).read_uint(); + assertEq(val, 1); + } + + function test_StorageReadInt() public { + int256 val = stdstore.target(address(test)).sig(test.tG.selector).read_int(); + assertEq(val, type(int256).min); + } +} + +contract StorageTest { + uint256 public exists = 1; + mapping(address => uint256) public map_addr; + mapping(uint256 => uint256) public map_uint; + mapping(address => uint256) public map_packed; + mapping(address => UnpackedStruct) public map_struct; + mapping(address => mapping(address => uint256)) public deep_map; + mapping(address => mapping(address => UnpackedStruct)) public deep_map_struct; + UnpackedStruct public basic; + + uint248 public tA; + bool public tB; + + bool public tC = false; + uint248 public tD = 1; + + struct UnpackedStruct { + uint256 a; + uint256 b; + } + + mapping(address => bool) public map_bool; + + bytes32 public tE = hex"1337"; + address public tF = address(1337); + int256 public tG = type(int256).min; + bool public tH = true; + bytes32 private tI = ~bytes32(hex"1337"); + + constructor() { + basic = UnpackedStruct({a: 1337, b: 1337}); + + uint256 two = (1 << 128) | 1; + map_packed[msg.sender] = two; + map_packed[address(uint160(1337))] = 1 << 128; + } + + function read_struct_upper(address who) public view returns (uint256) { + return map_packed[who] >> 128; + } + + function read_struct_lower(address who) public view returns (uint256) { + return map_packed[who] & ((1 << 128) - 1); + } + + function hidden() public view returns (bytes32 t) { + bytes32 slot = keccak256("my.random.var"); + /// @solidity memory-safe-assembly + assembly { + t := sload(slot) + } + } + + function const() public pure returns (bytes32 t) { + t = bytes32(hex"1337"); + } + + function extra_sload() public view returns (bytes32 t) { + // trigger read on slot `tE`, and make a staticcall to make sure compiler doesn't optimize this SLOAD away + assembly { + pop(staticcall(gas(), sload(tE.slot), 0, 0, 0, 0)) + } + t = tI; + } +} diff --git a/lib/forge-std/test/StdStyle.t.sol b/lib/forge-std/test/StdStyle.t.sol new file mode 100644 index 0000000..e12c005 --- /dev/null +++ b/lib/forge-std/test/StdStyle.t.sol @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdStyleTest is Test { + function test_StyleColor() public pure { + console2.log(StdStyle.red("StdStyle.red String Test")); + console2.log(StdStyle.red(uint256(10e18))); + console2.log(StdStyle.red(int256(-10e18))); + console2.log(StdStyle.red(true)); + console2.log(StdStyle.red(address(0))); + console2.log(StdStyle.redBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.redBytes32("StdStyle.redBytes32")); + console2.log(StdStyle.green("StdStyle.green String Test")); + console2.log(StdStyle.green(uint256(10e18))); + console2.log(StdStyle.green(int256(-10e18))); + console2.log(StdStyle.green(true)); + console2.log(StdStyle.green(address(0))); + console2.log(StdStyle.greenBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.greenBytes32("StdStyle.greenBytes32")); + console2.log(StdStyle.yellow("StdStyle.yellow String Test")); + console2.log(StdStyle.yellow(uint256(10e18))); + console2.log(StdStyle.yellow(int256(-10e18))); + console2.log(StdStyle.yellow(true)); + console2.log(StdStyle.yellow(address(0))); + console2.log(StdStyle.yellowBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.yellowBytes32("StdStyle.yellowBytes32")); + console2.log(StdStyle.blue("StdStyle.blue String Test")); + console2.log(StdStyle.blue(uint256(10e18))); + console2.log(StdStyle.blue(int256(-10e18))); + console2.log(StdStyle.blue(true)); + console2.log(StdStyle.blue(address(0))); + console2.log(StdStyle.blueBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.blueBytes32("StdStyle.blueBytes32")); + console2.log(StdStyle.magenta("StdStyle.magenta String Test")); + console2.log(StdStyle.magenta(uint256(10e18))); + console2.log(StdStyle.magenta(int256(-10e18))); + console2.log(StdStyle.magenta(true)); + console2.log(StdStyle.magenta(address(0))); + console2.log(StdStyle.magentaBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.magentaBytes32("StdStyle.magentaBytes32")); + console2.log(StdStyle.cyan("StdStyle.cyan String Test")); + console2.log(StdStyle.cyan(uint256(10e18))); + console2.log(StdStyle.cyan(int256(-10e18))); + console2.log(StdStyle.cyan(true)); + console2.log(StdStyle.cyan(address(0))); + console2.log(StdStyle.cyanBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.cyanBytes32("StdStyle.cyanBytes32")); + } + + function test_StyleFontWeight() public pure { + console2.log(StdStyle.bold("StdStyle.bold String Test")); + console2.log(StdStyle.bold(uint256(10e18))); + console2.log(StdStyle.bold(int256(-10e18))); + console2.log(StdStyle.bold(address(0))); + console2.log(StdStyle.bold(true)); + console2.log(StdStyle.boldBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.boldBytes32("StdStyle.boldBytes32")); + console2.log(StdStyle.dim("StdStyle.dim String Test")); + console2.log(StdStyle.dim(uint256(10e18))); + console2.log(StdStyle.dim(int256(-10e18))); + console2.log(StdStyle.dim(address(0))); + console2.log(StdStyle.dim(true)); + console2.log(StdStyle.dimBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.dimBytes32("StdStyle.dimBytes32")); + console2.log(StdStyle.italic("StdStyle.italic String Test")); + console2.log(StdStyle.italic(uint256(10e18))); + console2.log(StdStyle.italic(int256(-10e18))); + console2.log(StdStyle.italic(address(0))); + console2.log(StdStyle.italic(true)); + console2.log(StdStyle.italicBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.italicBytes32("StdStyle.italicBytes32")); + console2.log(StdStyle.underline("StdStyle.underline String Test")); + console2.log(StdStyle.underline(uint256(10e18))); + console2.log(StdStyle.underline(int256(-10e18))); + console2.log(StdStyle.underline(address(0))); + console2.log(StdStyle.underline(true)); + console2.log(StdStyle.underlineBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.underlineBytes32("StdStyle.underlineBytes32")); + console2.log(StdStyle.inverse("StdStyle.inverse String Test")); + console2.log(StdStyle.inverse(uint256(10e18))); + console2.log(StdStyle.inverse(int256(-10e18))); + console2.log(StdStyle.inverse(address(0))); + console2.log(StdStyle.inverse(true)); + console2.log(StdStyle.inverseBytes(hex"7109709ECfa91a80626fF3989D68f67F5b1DD12D")); + console2.log(StdStyle.inverseBytes32("StdStyle.inverseBytes32")); + } + + function test_StyleCombined() public pure { + console2.log(StdStyle.red(StdStyle.bold("Red Bold String Test"))); + console2.log(StdStyle.green(StdStyle.dim(uint256(10e18)))); + console2.log(StdStyle.yellow(StdStyle.italic(int256(-10e18)))); + console2.log(StdStyle.blue(StdStyle.underline(address(0)))); + console2.log(StdStyle.magenta(StdStyle.inverse(true))); + } + + function test_StyleCustom() public pure { + console2.log(h1("Custom Style 1")); + console2.log(h2("Custom Style 2")); + } + + function h1(string memory a) private pure returns (string memory) { + return StdStyle.cyan(StdStyle.inverse(StdStyle.bold(a))); + } + + function h2(string memory a) private pure returns (string memory) { + return StdStyle.magenta(StdStyle.bold(StdStyle.underline(a))); + } +} diff --git a/lib/forge-std/test/StdUtils.t.sol b/lib/forge-std/test/StdUtils.t.sol new file mode 100644 index 0000000..386e3a8 --- /dev/null +++ b/lib/forge-std/test/StdUtils.t.sol @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.7.0 <0.9.0; + +import "../src/Test.sol"; + +contract StdUtilsMock is StdUtils { + // We deploy a mock version so we can properly test expected reverts. + function exposed_getTokenBalances(address token, address[] memory addresses) + external + returns (uint256[] memory balances) + { + return getTokenBalances(token, addresses); + } + + function exposed_bound(int256 num, int256 min, int256 max) external view returns (int256) { + return bound(num, min, max); + } + + function exposed_bound(uint256 num, uint256 min, uint256 max) external view returns (uint256) { + return bound(num, min, max); + } + + function exposed_bytesToUint(bytes memory b) external pure returns (uint256) { + return bytesToUint(b); + } +} + +contract StdUtilsTest is Test { + /*////////////////////////////////////////////////////////////////////////// + BOUND UINT + //////////////////////////////////////////////////////////////////////////*/ + + function test_Bound() public { + assertEq(bound(uint256(5), 0, 4), 0); + assertEq(bound(uint256(0), 69, 69), 69); + assertEq(bound(uint256(0), 68, 69), 68); + assertEq(bound(uint256(10), 150, 190), 174); + assertEq(bound(uint256(300), 2800, 3200), 3107); + assertEq(bound(uint256(9999), 1337, 6666), 4669); + } + + function test_Bound_WithinRange() public { + assertEq(bound(uint256(51), 50, 150), 51); + assertEq(bound(uint256(51), 50, 150), bound(bound(uint256(51), 50, 150), 50, 150)); + assertEq(bound(uint256(149), 50, 150), 149); + assertEq(bound(uint256(149), 50, 150), bound(bound(uint256(149), 50, 150), 50, 150)); + } + + function test_Bound_EdgeCoverage() public { + assertEq(bound(uint256(0), 50, 150), 50); + assertEq(bound(uint256(1), 50, 150), 51); + assertEq(bound(uint256(2), 50, 150), 52); + assertEq(bound(uint256(3), 50, 150), 53); + assertEq(bound(type(uint256).max, 50, 150), 150); + assertEq(bound(type(uint256).max - 1, 50, 150), 149); + assertEq(bound(type(uint256).max - 2, 50, 150), 148); + assertEq(bound(type(uint256).max - 3, 50, 150), 147); + } + + function test_Bound_DistributionIsEven(uint256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, UINT256_MAX / 2, UINT256_MAX / 2 + size); + uint256 max = min + size - 1; + uint256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + i, min, max); + assertEq(result, min + (i - 1) % size); + // x < min + result = bound(min - i, min, max); + assertEq(result, max - (i - 1) % size); + } + } + + function test_Bound(uint256 num, uint256 min, uint256 max) public { + if (min > max) (min, max) = (max, min); + + uint256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function test_BoundUint256Max() public { + assertEq(bound(0, type(uint256).max - 1, type(uint256).max), type(uint256).max - 1); + assertEq(bound(1, type(uint256).max - 1, type(uint256).max), type(uint256).max); + } + + function test_CannotBoundMaxLessThanMin() public { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + stdUtils.exposed_bound(uint256(5), 100, 10); + } + + function test_CannotBoundMaxLessThanMin(uint256 num, uint256 min, uint256 max) public { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(uint256,uint256,uint256): Max is less than min.")); + stdUtils.exposed_bound(num, min, max); + } + + /*////////////////////////////////////////////////////////////////////////// + BOUND INT + //////////////////////////////////////////////////////////////////////////*/ + + function test_BoundInt() public { + assertEq(bound(-3, 0, 4), 2); + assertEq(bound(0, -69, -69), -69); + assertEq(bound(0, -69, -68), -68); + assertEq(bound(-10, 150, 190), 154); + assertEq(bound(-300, 2800, 3200), 2908); + assertEq(bound(9999, -1337, 6666), 1995); + } + + function test_BoundInt_WithinRange() public { + assertEq(bound(51, -50, 150), 51); + assertEq(bound(51, -50, 150), bound(bound(51, -50, 150), -50, 150)); + assertEq(bound(149, -50, 150), 149); + assertEq(bound(149, -50, 150), bound(bound(149, -50, 150), -50, 150)); + } + + function test_BoundInt_EdgeCoverage() public { + assertEq(bound(type(int256).min, -50, 150), -50); + assertEq(bound(type(int256).min + 1, -50, 150), -49); + assertEq(bound(type(int256).min + 2, -50, 150), -48); + assertEq(bound(type(int256).min + 3, -50, 150), -47); + assertEq(bound(type(int256).min, 10, 150), 10); + assertEq(bound(type(int256).min + 1, 10, 150), 11); + assertEq(bound(type(int256).min + 2, 10, 150), 12); + assertEq(bound(type(int256).min + 3, 10, 150), 13); + + assertEq(bound(type(int256).max, -50, 150), 150); + assertEq(bound(type(int256).max - 1, -50, 150), 149); + assertEq(bound(type(int256).max - 2, -50, 150), 148); + assertEq(bound(type(int256).max - 3, -50, 150), 147); + assertEq(bound(type(int256).max, -50, -10), -10); + assertEq(bound(type(int256).max - 1, -50, -10), -11); + assertEq(bound(type(int256).max - 2, -50, -10), -12); + assertEq(bound(type(int256).max - 3, -50, -10), -13); + } + + function test_BoundInt_DistributionIsEven(int256 min, uint256 size) public { + size = size % 100 + 1; + min = bound(min, -int256(size / 2), int256(size - size / 2)); + int256 max = min + int256(size) - 1; + int256 result; + + for (uint256 i = 1; i <= size * 4; ++i) { + // x > max + result = bound(max + int256(i), min, max); + assertEq(result, min + int256((i - 1) % size)); + // x < min + result = bound(min - int256(i), min, max); + assertEq(result, max - int256((i - 1) % size)); + } + } + + function test_BoundInt(int256 num, int256 min, int256 max) public { + if (min > max) (min, max) = (max, min); + + int256 result = bound(num, min, max); + + assertGe(result, min); + assertLe(result, max); + assertEq(result, bound(result, min, max)); + if (num >= min && num <= max) assertEq(result, num); + } + + function test_BoundIntInt256Max() public { + assertEq(bound(0, type(int256).max - 1, type(int256).max), type(int256).max - 1); + assertEq(bound(1, type(int256).max - 1, type(int256).max), type(int256).max); + } + + function test_BoundIntInt256Min() public { + assertEq(bound(0, type(int256).min, type(int256).min + 1), type(int256).min); + assertEq(bound(1, type(int256).min, type(int256).min + 1), type(int256).min + 1); + } + + function test_CannotBoundIntMaxLessThanMin() public { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + stdUtils.exposed_bound(-5, 100, 10); + } + + function test_CannotBoundIntMaxLessThanMin(int256 num, int256 min, int256 max) public { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + vm.assume(min > max); + vm.expectRevert(bytes("StdUtils bound(int256,int256,int256): Max is less than min.")); + stdUtils.exposed_bound(num, min, max); + } + + /*////////////////////////////////////////////////////////////////////////// + BOUND PRIVATE KEY + //////////////////////////////////////////////////////////////////////////*/ + + function test_BoundPrivateKey() public { + assertEq(boundPrivateKey(0), 1); + assertEq(boundPrivateKey(1), 1); + assertEq(boundPrivateKey(300), 300); + assertEq(boundPrivateKey(9999), 9999); + assertEq(boundPrivateKey(SECP256K1_ORDER - 1), SECP256K1_ORDER - 1); + assertEq(boundPrivateKey(SECP256K1_ORDER), 1); + assertEq(boundPrivateKey(SECP256K1_ORDER + 1), 2); + assertEq(boundPrivateKey(UINT256_MAX), UINT256_MAX & SECP256K1_ORDER - 1); // x&y is equivalent to x-x%y + } + + /*////////////////////////////////////////////////////////////////////////// + BYTES TO UINT + //////////////////////////////////////////////////////////////////////////*/ + + function test_BytesToUint() external { + bytes memory maxUint = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + bytes memory two = hex"02"; + bytes memory millionEther = hex"d3c21bcecceda1000000"; + + assertEq(bytesToUint(maxUint), type(uint256).max); + assertEq(bytesToUint(two), 2); + assertEq(bytesToUint(millionEther), 1_000_000 ether); + } + + function test_CannotConvertGT32Bytes() external { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + bytes memory thirty3Bytes = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + vm.expectRevert("StdUtils bytesToUint(bytes): Bytes length exceeds 32."); + stdUtils.exposed_bytesToUint(thirty3Bytes); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function test_ComputeCreateAddress() external { + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + uint256 nonce = 14; + address createAddress = computeCreateAddress(deployer, nonce); + assertEq(createAddress, 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + } + + /*////////////////////////////////////////////////////////////////////////// + COMPUTE CREATE2 ADDRESS + //////////////////////////////////////////////////////////////////////////*/ + + function test_ComputeCreate2Address() external { + bytes32 salt = bytes32(uint256(31415)); + bytes32 initcodeHash = keccak256(abi.encode(0x6080)); + address deployer = 0x6C9FC64A53c1b71FB3f9Af64d1ae3A4931A5f4E9; + address create2Address = computeCreate2Address(salt, initcodeHash, deployer); + assertEq(create2Address, 0xB147a5d25748fda14b463EB04B111027C290f4d3); + } + + function test_ComputeCreate2AddressWithDefaultDeployer() external { + bytes32 salt = 0xc290c670fde54e5ef686f9132cbc8711e76a98f0333a438a92daa442c71403c0; + bytes32 initcodeHash = hashInitCode(hex"6080", ""); + assertEq(initcodeHash, 0x1a578b7a4b0b5755db6d121b4118d4bc68fe170dca840c59bc922f14175a76b0); + address create2Address = computeCreate2Address(salt, initcodeHash); + assertEq(create2Address, 0xc0ffEe2198a06235aAbFffe5Db0CacF1717f5Ac6); + } +} + +contract StdUtilsForkTest is Test { + /*////////////////////////////////////////////////////////////////////////// + GET TOKEN BALANCES + //////////////////////////////////////////////////////////////////////////*/ + + address internal SHIB = 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE; + address internal SHIB_HOLDER_0 = 0x855F5981e831D83e6A4b4EBFCAdAa68D92333170; + address internal SHIB_HOLDER_1 = 0x8F509A90c2e47779cA408Fe00d7A72e359229AdA; + address internal SHIB_HOLDER_2 = 0x0e3bbc0D04fF62211F71f3e4C45d82ad76224385; + + address internal USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address internal USDC_HOLDER_0 = 0xDa9CE944a37d218c3302F6B82a094844C6ECEb17; + address internal USDC_HOLDER_1 = 0x3e67F4721E6d1c41a015f645eFa37BEd854fcf52; + + function setUp() public { + // All tests of the `getTokenBalances` method are fork tests using live contracts. + vm.createSelectFork({urlOrAlias: "mainnet", blockNumber: 16_428_900}); + } + + function test_CannotGetTokenBalances_NonTokenContract() external { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + // The UniswapV2Factory contract has neither a `balanceOf` function nor a fallback function, + // so the `balanceOf` call should revert. + address token = address(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f); + address[] memory addresses = new address[](1); + addresses[0] = USDC_HOLDER_0; + + vm.expectRevert("Multicall3: call failed"); + stdUtils.exposed_getTokenBalances(token, addresses); + } + + function test_CannotGetTokenBalances_EOA() external { + // We deploy a mock version so we can properly test the revert. + StdUtilsMock stdUtils = new StdUtilsMock(); + + address eoa = vm.addr({privateKey: 1}); + address[] memory addresses = new address[](1); + addresses[0] = USDC_HOLDER_0; + vm.expectRevert("StdUtils getTokenBalances(address,address[]): Token address is not a contract."); + stdUtils.exposed_getTokenBalances(eoa, addresses); + } + + function test_GetTokenBalances_Empty() external { + address[] memory addresses = new address[](0); + uint256[] memory balances = getTokenBalances(USDC, addresses); + assertEq(balances.length, 0); + } + + function test_GetTokenBalances_USDC() external { + address[] memory addresses = new address[](2); + addresses[0] = USDC_HOLDER_0; + addresses[1] = USDC_HOLDER_1; + uint256[] memory balances = getTokenBalances(USDC, addresses); + assertEq(balances[0], 159_000_000_000_000); + assertEq(balances[1], 131_350_000_000_000); + } + + function test_GetTokenBalances_SHIB() external { + address[] memory addresses = new address[](3); + addresses[0] = SHIB_HOLDER_0; + addresses[1] = SHIB_HOLDER_1; + addresses[2] = SHIB_HOLDER_2; + uint256[] memory balances = getTokenBalances(SHIB, addresses); + assertEq(balances[0], 3_323_256_285_484.42e18); + assertEq(balances[1], 1_271_702_771_149.99999928e18); + assertEq(balances[2], 606_357_106_247e18); + } +} diff --git a/lib/forge-std/test/Vm.t.sol b/lib/forge-std/test/Vm.t.sol new file mode 100644 index 0000000..3c1d73f --- /dev/null +++ b/lib/forge-std/test/Vm.t.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0 <0.9.0; + +import {Test} from "../src/Test.sol"; +import {Vm, VmSafe} from "../src/Vm.sol"; + +contract VmTest is Test { + // This test ensures that functions are never accidentally removed from a Vm interface, or + // inadvertently moved between Vm and VmSafe. This test must be updated each time a function is + // added to or removed from Vm or VmSafe. + function test_interfaceId() public { + assertEq(type(VmSafe).interfaceId, bytes4(0x329f5e71), "VmSafe"); + assertEq(type(Vm).interfaceId, bytes4(0x82ccbb14), "Vm"); + } +} diff --git a/lib/forge-std/test/compilation/CompilationScript.sol b/lib/forge-std/test/compilation/CompilationScript.sol new file mode 100644 index 0000000..e205cff --- /dev/null +++ b/lib/forge-std/test/compilation/CompilationScript.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScript is Script {} diff --git a/lib/forge-std/test/compilation/CompilationScriptBase.sol b/lib/forge-std/test/compilation/CompilationScriptBase.sol new file mode 100644 index 0000000..ce8e0e9 --- /dev/null +++ b/lib/forge-std/test/compilation/CompilationScriptBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Script.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationScriptBase is ScriptBase {} diff --git a/lib/forge-std/test/compilation/CompilationTest.sol b/lib/forge-std/test/compilation/CompilationTest.sol new file mode 100644 index 0000000..9beeafe --- /dev/null +++ b/lib/forge-std/test/compilation/CompilationTest.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTest is Test {} diff --git a/lib/forge-std/test/compilation/CompilationTestBase.sol b/lib/forge-std/test/compilation/CompilationTestBase.sol new file mode 100644 index 0000000..e993535 --- /dev/null +++ b/lib/forge-std/test/compilation/CompilationTestBase.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.2 <0.9.0; + +pragma experimental ABIEncoderV2; + +import "../../src/Test.sol"; + +// The purpose of this contract is to benchmark compilation time to avoid accidentally introducing +// a change that results in very long compilation times with via-ir. See https://github.com/foundry-rs/forge-std/issues/207 +contract CompilationTestBase is TestBase {} diff --git a/lib/forge-std/test/fixtures/broadcast.log.json b/lib/forge-std/test/fixtures/broadcast.log.json new file mode 100644 index 0000000..0a0200b --- /dev/null +++ b/lib/forge-std/test/fixtures/broadcast.log.json @@ -0,0 +1,187 @@ +{ + "transactions": [ + { + "hash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "function": "multiple_arguments(uint256,address,uint256[]):(uint256)", + "arguments": ["1", "0000000000000000000000000000000000001337", "[3,4]"], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "gas": "0x73b9", + "value": "0x0", + "data": "0x23e99187000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000013370000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004", + "nonce": "0x3", + "accessList": [] + } + }, + { + "hash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "function": "inc():(uint256)", + "arguments": [], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "gas": "0xdcb2", + "value": "0x0", + "data": "0x371303c0", + "nonce": "0x4", + "accessList": [] + } + }, + { + "hash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "type": "CALL", + "contractName": "Test", + "contractAddress": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "function": "t(uint256):(uint256)", + "arguments": ["1"], + "tx": { + "type": "0x02", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "gas": "0x8599", + "value": "0x0", + "data": "0xafe29f710000000000000000000000000000000000000000000000000000000000000001", + "nonce": "0x5", + "accessList": [] + } + } + ], + "receipts": [ + { + "transactionHash": "0x481dc86e40bba90403c76f8e144aa9ff04c1da2164299d0298573835f0991181", + "transactionIndex": "0x0", + "blockHash": "0xef0730448490304e5403be0fa8f8ce64f118e9adcca60c07a2ae1ab921d748af", + "blockNumber": "0x1", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": null, + "cumulativeGasUsed": "0x13f3a", + "gasUsed": "0x13f3a", + "contractAddress": "0x5fbdb2315678afecb367f032d93f642f64180aa3", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x6a187183545b8a9e7f1790e847139379bf5622baff2cb43acf3f5c79470af782", + "transactionIndex": "0x0", + "blockHash": "0xf3acb96a90071640c2a8c067ae4e16aad87e634ea8d8bbbb5b352fba86ba0148", + "blockNumber": "0x2", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": null, + "cumulativeGasUsed": "0x45d80", + "gasUsed": "0x45d80", + "contractAddress": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x064ad173b4867bdef2fb60060bbdaf01735fbf10414541ea857772974e74ea9d", + "transactionIndex": "0x0", + "blockHash": "0x8373d02109d3ee06a0225f23da4c161c656ccc48fe0fcee931d325508ae73e58", + "blockNumber": "0x3", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "cumulativeGasUsed": "0x45feb", + "gasUsed": "0x45feb", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xc6006863c267735a11476b7f15b15bc718e117e2da114a2be815dd651e1a509f", + "transactionIndex": "0x0", + "blockHash": "0x16712fae5c0e18f75045f84363fb6b4d9a9fe25e660c4ce286833a533c97f629", + "blockNumber": "0x4", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "cumulativeGasUsed": "0x5905", + "gasUsed": "0x5905", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xedf2b38d8d896519a947a1acf720f859bb35c0c5ecb8dd7511995b67b9853298", + "transactionIndex": "0x0", + "blockHash": "0x156b88c3eb9a1244ba00a1834f3f70de735b39e3e59006dd03af4fe7d5480c11", + "blockNumber": "0x5", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0xe7f1725e7734ce288f8367e1bb143e90bb3f0512", + "cumulativeGasUsed": "0xa9c4", + "gasUsed": "0xa9c4", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "transactionIndex": "0x0", + "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", + "blockNumber": "0x6", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "cumulativeGasUsed": "0x66c5", + "gasUsed": "0x66c5", + "contractAddress": null, + "logs": [ + { + "address": "0x7c6b4bbe207d642d98d5c537142d85209e585087", + "topics": [ + "0x0b2e13ff20ac7b474198655583edf70dedd2c1dc980e329c4fbb2fc0748b796b" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000046865726500000000000000000000000000000000000000000000000000000000", + "blockHash": "0xcf61faca67dbb2c28952b0b8a379e53b1505ae0821e84779679390cb8571cadb", + "blockNumber": "0x6", + "transactionHash": "0xa57e8e3981a6c861442e46c9471bd19cb3e21f9a8a6c63a72e7b5c47c6675a7c", + "transactionIndex": "0x1", + "logIndex": "0x0", + "transactionLogIndex": "0x0", + "removed": false + } + ], + "status": "0x1", + "logsBloom": "0x00000000000800000000000000000010000000000000000000000000000180000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100", + "effectiveGasPrice": "0xee6b2800" + }, + { + "transactionHash": "0x11fbb10230c168ca1e36a7e5c69a6dbcd04fd9e64ede39d10a83e36ee8065c16", + "transactionIndex": "0x0", + "blockHash": "0xf1e0ed2eda4e923626ec74621006ed50b3fc27580dc7b4cf68a07ca77420e29c", + "blockNumber": "0x7", + "from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "to": "0x0000000000000000000000000000000000001337", + "cumulativeGasUsed": "0x5208", + "gasUsed": "0x5208", + "contractAddress": null, + "logs": [], + "status": "0x1", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "effectiveGasPrice": "0xee6b2800" + } + ], + "libraries": [ + "src/Broadcast.t.sol:F:0x5fbdb2315678afecb367f032d93f642f64180aa3" + ], + "pending": [], + "path": "broadcast/Broadcast.t.sol/31337/run-latest.json", + "returns": {}, + "timestamp": 1655140035 +} diff --git a/lib/openzeppelin-contracts-v4.9.3/.changeset/config.json b/lib/openzeppelin-contracts-v4.9.3/.changeset/config.json new file mode 100644 index 0000000..66794fa --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.changeset/config.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", + "changelog": [ + "@changesets/changelog-github", + { + "repo": "OpenZeppelin/openzeppelin-contracts" + } + ], + "commit": false, + "access": "public", + "baseBranch": "master" +} diff --git a/lib/openzeppelin-contracts-v4.9.3/.codecov.yml b/lib/openzeppelin-contracts-v4.9.3/.codecov.yml new file mode 100644 index 0000000..9455306 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.codecov.yml @@ -0,0 +1,12 @@ +comment: off +github_checks: + annotations: false +coverage: + status: + patch: + default: + target: 95% + only_pulls: true + project: + default: + threshold: 1% diff --git a/lib/openzeppelin-contracts-v4.9.3/.editorconfig b/lib/openzeppelin-contracts-v4.9.3/.editorconfig new file mode 100644 index 0000000..f162e8d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = false +max_line_length = 120 + +[*.sol] +indent_size = 4 + +[*.js] +indent_size = 2 + +[*.{adoc,md}] +max_line_length = 0 diff --git a/lib/openzeppelin-contracts-v4.9.3/.eslintrc b/lib/openzeppelin-contracts-v4.9.3/.eslintrc new file mode 100644 index 0000000..a5418c5 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.eslintrc @@ -0,0 +1,20 @@ +{ + "root": true, + "extends" : [ + "eslint:recommended", + "prettier", + ], + "env": { + "es2022": true, + "browser": true, + "node": true, + "mocha": true, + }, + "globals" : { + "artifacts": "readonly", + "contract": "readonly", + "web3": "readonly", + "extendEnvironment": "readonly", + "expect": "readonly", + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/bug_report.md b/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..2797a08 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,21 @@ +--- +name: Bug report +about: Report a bug in OpenZeppelin Contracts + +--- + + + + + +**💻 Environment** + + + +**📝 Details** + + + +**🔢 Code to reproduce bug** + + diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/config.yml b/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..4018cef --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,4 @@ +contact_links: + - name: Questions & Support Requests + url: https://forum.openzeppelin.com/c/support/contracts/18 + about: Ask in the OpenZeppelin Forum diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/feature_request.md b/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..ff596b0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,14 @@ +--- +name: Feature request +about: Suggest an idea for OpenZeppelin Contracts + +--- + +**🧐 Motivation** + + +**📝 Details** + + + + diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/PULL_REQUEST_TEMPLATE.md b/lib/openzeppelin-contracts-v4.9.3/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..2394518 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,20 @@ + + + + + +Fixes #???? + + + + + +#### PR Checklist + + + + + +- [ ] Tests +- [ ] Documentation +- [ ] Changeset entry (run `npx changeset add`) diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/actions/gas-compare/action.yml b/lib/openzeppelin-contracts-v4.9.3/.github/actions/gas-compare/action.yml new file mode 100644 index 0000000..e38c48e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/actions/gas-compare/action.yml @@ -0,0 +1,49 @@ +name: Compare gas costs +inputs: + token: + description: github token + required: true + report: + description: report to read from + required: false + default: gasReporterOutput.json + out_report: + description: report to read + required: false + default: ${{ github.ref_name }}.gasreport.json + ref_report: + description: report to read from + required: false + default: ${{ github.base_ref }}.gasreport.json + +runs: + using: composite + steps: + - name: Download reference report + 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 gasreport + env: + GITHUB_TOKEN: ${{ inputs.token }} + shell: bash + continue-on-error: true + id: reference + - name: Compare reports + if: steps.reference.outcome == 'success' && github.event_name == 'pull_request' + run: | + node scripts/checks/compareGasReports.js ${{ inputs.report }} ${{ inputs.ref_report }} >> $GITHUB_STEP_SUMMARY + env: + STYLE: markdown + shell: bash + - name: Rename report for upload + if: github.event_name != 'pull_request' + run: | + mv ${{ inputs.report }} ${{ inputs.out_report }} + shell: bash + - name: Save report + if: github.event_name != 'pull_request' + uses: actions/upload-artifact@v3 + with: + name: gasreport + path: ${{ inputs.out_report }} diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/actions/setup/action.yml b/lib/openzeppelin-contracts-v4.9.3/.github/actions/setup/action.yml new file mode 100644 index 0000000..680fba0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/actions/setup/action.yml @@ -0,0 +1,19 @@ +name: Setup + +runs: + using: composite + steps: + - uses: actions/setup-node@v3 + with: + node-version: 14.x + - uses: actions/cache@v3 + id: cache + with: + path: '**/node_modules' + key: npm-v3-${{ hashFiles('**/package-lock.json') }} + - name: Install dependencies + run: npm ci + shell: bash + if: steps.cache.outputs.cache-hit != 'true' + env: + SKIP_COMPILE: true diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/actions/storage-layout/action.yml b/lib/openzeppelin-contracts-v4.9.3/.github/actions/storage-layout/action.yml new file mode 100644 index 0000000..fdfd5a2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.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 }} + 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/lib/openzeppelin-contracts-v4.9.3/.github/workflows/actionlint.yml b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/actionlint.yml new file mode 100644 index 0000000..8193109 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/actionlint.yml @@ -0,0 +1,18 @@ +name: lint workflows + +on: + pull_request: + paths: + - '.github/**/*.ya?ml' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Add problem matchers + run: | + # https://github.com/rhysd/actionlint/blob/3a2f2c7/docs/usage.md#problem-matchers + curl -LO https://raw.githubusercontent.com/rhysd/actionlint/main/.github/actionlint-matcher.json + echo "::add-matcher::actionlint-matcher.json" + - uses: docker://rhysd/actionlint:latest diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/workflows/changeset.yml b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/changeset.yml new file mode 100644 index 0000000..5fe70cf --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/changeset.yml @@ -0,0 +1,28 @@ +name: changeset + +on: + pull_request: + branches: + - master + types: + - opened + - synchronize + - labeled + - unlabeled + +concurrency: + group: changeset-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + if: ${{ !contains(github.event.pull_request.labels.*.name, 'ignore-changeset') }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # Include history so Changesets finds merge-base + - name: Set up environment + uses: ./.github/actions/setup + - name: Check changeset + run: npx changeset status --since=origin/${{ github.base_ref }} diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/workflows/checks.yml b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/checks.yml new file mode 100644 index 0000000..1292a52 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/checks.yml @@ -0,0 +1,111 @@ +name: checks + +on: + push: + branches: + - master + - release-v* + pull_request: {} + workflow_dispatch: {} + +concurrency: + group: checks-${{ github.ref }} + cancel-in-progress: true + +env: + NODE_OPTIONS: --max_old_space_size=5120 + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: npm run lint + + tests: + runs-on: ubuntu-latest + env: + FORCE_COLOR: 1 + GAS: true + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - name: Run tests and generate gas report + run: npm run test + - name: Check linearisation of the inheritance graph + run: npm run test:inheritance + - name: Check proceduraly generated contracts are up-to-date + 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 + - 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 }} + + tests-foundry: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + - name: Run tests + run: forge test -vv + + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: npm run coverage + - uses: codecov/codecov-action@v3 + with: + token: ${{ secrets.CODECOV_TOKEN }} + + slither: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: rm foundry.toml + - uses: crytic/slither-action@v0.3.0 + with: + node-version: 18.15 + + codespell: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Run CodeSpell + uses: codespell-project/actions-codespell@v1.0 + with: + check_filenames: true + skip: package-lock.json,*.pdf diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/workflows/docs.yml b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/docs.yml new file mode 100644 index 0000000..4b54ea6 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/docs.yml @@ -0,0 +1,19 @@ +name: Build Docs + +on: + push: + branches: [release-v*] + +permissions: + contents: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - run: node scripts/update-docs-branch.js + - run: git push --all origin diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/workflows/formal-verification.yml b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/formal-verification.yml new file mode 100644 index 0000000..ae5eba0 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/formal-verification.yml @@ -0,0 +1,68 @@ +name: formal verification + +on: + pull_request: + types: + - opened + - reopened + - synchronize + - labeled + workflow_dispatch: {} + +env: + PIP_VERSION: '3.10' + JAVA_VERSION: '11' + SOLC_VERSION: '0.8.19' + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +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 + 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: + 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 ${{ steps.arguments.outputs.result }} >> "$GITHUB_STEP_SUMMARY" + env: + CERTORAKEY: ${{ secrets.CERTORAKEY }} diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/workflows/release-cycle.yml b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/release-cycle.yml new file mode 100644 index 0000000..9d35022 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/release-cycle.yml @@ -0,0 +1,218 @@ +# 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: + push: + branches: + - release-v* + workflow_dispatch: {} + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + state: + name: Check state + permissions: + pull-requests: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - id: state + name: Get state + uses: actions/github-script@v6 + env: + TRIGGERING_ACTOR: ${{ github.triggering_actor }} + with: + result-encoding: string + script: await require('./scripts/release/workflow/state.js')({ github, context, core }) + outputs: + # Job Flags + start: ${{ steps.state.outputs.start }} + changesets: ${{ steps.state.outputs.changesets }} + promote: ${{ steps.state.outputs.promote }} + publish: ${{ steps.state.outputs.publish }} + merge: ${{ steps.state.outputs.merge }} + + # Global variables + is_prerelease: ${{ steps.state.outputs.is_prerelease }} + + start: + needs: state + name: Start new release candidate + permissions: + contents: write + actions: write + if: needs.state.outputs.start == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - id: start + name: Create branch with release candidate + run: bash scripts/release/workflow/start.sh + - name: Re-run workflow + uses: actions/github-script@v6 + env: + REF: ${{ steps.start.outputs.branch }} + with: + script: await require('./scripts/release/workflow/rerun.js')({ github, context }) + + promote: + needs: state + name: Promote to final release + permissions: + contents: write + actions: write + if: needs.state.outputs.promote == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Exit prerelease state + if: needs.state.outputs.is_prerelease == 'true' + run: bash scripts/release/workflow/exit-prerelease.sh + - name: Re-run workflow + uses: actions/github-script@v6 + with: + script: await require('./scripts/release/workflow/rerun.js')({ github, context }) + + changesets: + needs: state + name: Update PR to release + permissions: + contents: write + pull-requests: write + if: needs.state.outputs.changesets == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # To get all tags + - name: Set up environment + uses: ./.github/actions/setup + - name: Set release title + uses: actions/github-script@v6 + with: + result-encoding: string + script: await require('./scripts/release/workflow/set-changesets-pr-title.js')({ core }) + - name: Create PR + uses: changesets/action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PRERELEASE: ${{ needs.state.outputs.is_prerelease }} + with: + version: npm run version + title: ${{ env.TITLE }} + commit: ${{ env.TITLE }} + body: | # Wait for support on this https://github.com/changesets/action/pull/250 + This is an automated PR for releasing ${{ github.repository }} + Check [CHANGELOG.md](${{ github.repository }}/CHANGELOG.md) + + publish: + needs: state + name: Publish to npm + environment: npm + permissions: + contents: write + if: needs.state.outputs.publish == 'true' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Set up environment + uses: ./.github/actions/setup + - id: pack + name: Pack + 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 + run: bash scripts/release/workflow/publish.sh + env: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + TARBALL: ${{ steps.pack.outputs.tarball }} + TAG: ${{ steps.pack.outputs.tag }} + - name: Push tags + run: git push --tags + - name: Create Github Release + uses: actions/github-script@v6 + env: + 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 + name: Create PR back to master + permissions: + contents: write + pull-requests: write + if: needs.state.outputs.merge == 'true' + runs-on: ubuntu-latest + env: + MERGE_BRANCH: merge/${{ github.ref_name }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # All branches + - name: Set up environment + uses: ./.github/actions/setup + - run: bash scripts/git-user-config.sh + - name: Create branch to merge + run: | + git checkout -B "$MERGE_BRANCH" "$GITHUB_REF_NAME" + git push -f origin "$MERGE_BRANCH" + - name: Create PR back to master + uses: actions/github-script@v6 + with: + script: | + await github.rest.pulls.create({ + owner: context.repo.owner, + repo: context.repo.repo, + head: process.env.MERGE_BRANCH, + base: 'master', + title: '${{ format('Merge {0} branch', github.ref_name) }}' + }); diff --git a/lib/openzeppelin-contracts-v4.9.3/.github/workflows/upgradeable.yml b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/upgradeable.yml new file mode 100644 index 0000000..649596a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.github/workflows/upgradeable.yml @@ -0,0 +1,30 @@ +name: transpile upgradeable + +on: + push: + branches: + - master + - release-v* + +jobs: + transpile: + environment: push-upgradeable + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + repository: OpenZeppelin/openzeppelin-contracts-upgradeable + fetch-depth: 0 + token: ${{ secrets.GH_TOKEN_UPGRADEABLE }} + - name: Fetch current non-upgradeable branch + run: | + git fetch "https://github.com/${{ github.repository }}.git" "$REF" + git 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/lib/openzeppelin-contracts-v4.9.3/.gitignore b/lib/openzeppelin-contracts-v4.9.3/.gitignore new file mode 100644 index 0000000..2aac744 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.gitignore @@ -0,0 +1,71 @@ +*.swp +*.swo + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +allFiredEvents +scTopics + +# Coverage directory used by tools like istanbul +coverage +coverage.json +coverageEnv + +# node-waf configuration +.lock-wscript + +# Dependency directory +node_modules + +# Debug log from npm +npm-debug.log + +# local env variables +.env + +# truffle build directory +build/ + +# macOS +.DS_Store + +# truffle +.node-xmlhttprequest-* + +# IntelliJ IDE +.idea + +# docs artifacts +docs/modules/api + +# only used to package @openzeppelin/contracts +contracts/build/ +contracts/README.md + +# temporary artifact from solidity-coverage +allFiredEvents +.coverage_artifacts +.coverage_cache +.coverage_contracts + +# hardat-exposed +contracts-exposed + +# Hardhat +/cache +/artifacts + +# Foundry +/out + +# Certora +.certora* +.last_confs +certora_* +.zip-output-url.txt diff --git a/lib/openzeppelin-contracts-v4.9.3/.gitmodules b/lib/openzeppelin-contracts-v4.9.3/.gitmodules new file mode 100644 index 0000000..08a09bb --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.gitmodules @@ -0,0 +1,7 @@ +[submodule "lib/forge-std"] + branch = v1 + path = lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "lib/erc4626-tests"] + path = lib/erc4626-tests + url = https://github.com/a16z/erc4626-tests.git diff --git a/lib/openzeppelin-contracts-v4.9.3/.mocharc.js b/lib/openzeppelin-contracts-v4.9.3/.mocharc.js new file mode 100644 index 0000000..920662d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.mocharc.js @@ -0,0 +1,4 @@ +module.exports = { + require: 'hardhat/register', + timeout: 4000, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/.prettierrc b/lib/openzeppelin-contracts-v4.9.3/.prettierrc new file mode 100644 index 0000000..e08e242 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.prettierrc @@ -0,0 +1,14 @@ +{ + "printWidth": 120, + "singleQuote": true, + "trailingComma": "all", + "arrowParens": "avoid", + "overrides": [ + { + "files": "*.sol", + "options": { + "singleQuote": false + } + } + ] +} diff --git a/lib/openzeppelin-contracts-v4.9.3/.solcover.js b/lib/openzeppelin-contracts-v4.9.3/.solcover.js new file mode 100644 index 0000000..e0dea5e --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.solcover.js @@ -0,0 +1,13 @@ +module.exports = { + norpc: true, + testCommand: 'npm test', + compileCommand: 'npm run compile', + skipFiles: ['mocks'], + providerOptions: { + default_balance_ether: '10000000000000000000000000', + }, + mocha: { + fgrep: '[skip-on-coverage]', + invert: true, + }, +}; diff --git a/lib/openzeppelin-contracts-v4.9.3/.solhint.json b/lib/openzeppelin-contracts-v4.9.3/.solhint.json new file mode 100644 index 0000000..7729288 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/.solhint.json @@ -0,0 +1,14 @@ +{ + "rules": { + "no-unused-vars": "error", + "const-name-snakecase": "error", + "contract-name-camelcase": "error", + "event-name-camelcase": "error", + "func-name-mixedcase": "error", + "func-param-name-mixedcase": "error", + "modifier-name-mixedcase": "error", + "private-vars-leading-underscore": "error", + "var-name-mixedcase": "error", + "imports-on-top": "error" + } +} diff --git a/lib/openzeppelin-contracts-v4.9.3/CHANGELOG.md b/lib/openzeppelin-contracts-v4.9.3/CHANGELOG.md new file mode 100644 index 0000000..ec0209d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/CHANGELOG.md @@ -0,0 +1,730 @@ +# Changelog + + +## 4.9.3 (2023-07-28) + +- `ERC2771Context`: Return the forwarder address whenever the `msg.data` of a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes), as specified by ERC-2771. ([#4481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4481)) +- `ERC2771Context`: Prevent revert in `_msgData()` when a call originating from a trusted forwarder is not long enough to contain the request signer address (i.e. `msg.data.length` is less than 20 bytes). Return the full calldata in that case. ([#4484](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4484)) + +## 4.9.2 (2023-06-16) + +- `MerkleProof`: Fix a bug in `processMultiProof` and `processMultiProofCalldata` that allows proving arbitrary leaves if the tree contains a node with value 0 at depth 1. + +## 4.9.1 (2023-06-07) + +- `Governor`: Add a mechanism to restrict the address of the proposer using a suffix in the description. + +## 4.9.0 (2023-05-23) + +- `ReentrancyGuard`: Add a `_reentrancyGuardEntered` function to expose the guard status. ([#3714](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3714)) +- `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. ([#3863](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3863)) +- `EnumerableMap`: add a `keys()` function that returns an array containing all the keys. ([#3920](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3920)) +- `Governor`: add a public `cancel(uint256)` function. ([#3983](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3983)) +- `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. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934)) +- `Strings`: add `equal` method. ([#3774](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3774)) +- `IERC5313`: Add an interface for EIP-5313 that is now final. ([#4013](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4013)) +- `IERC4906`: Add an interface for ERC-4906 that is now Final. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012)) +- `StorageSlot`: Add support for `string` and `bytes`. ([#4008](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4008)) +- `Votes`, `ERC20Votes`, `ERC721Votes`: support timestamp checkpointing using EIP-6372. ([#3934](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3934)) +- `ERC4626`: Add mitigation to the inflation attack through virtual shares and assets. ([#3979](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3979)) +- `Strings`: add `toString` method for signed integers. ([#3773](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3773)) +- `ERC20Wrapper`: Make the `underlying` variable private and add a public accessor. ([#4029](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4029)) +- `EIP712`: add EIP-5267 support for better domain discovery. ([#3969](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3969)) +- `AccessControlDefaultAdminRules`: Add an extension of `AccessControl` with additional security rules for the `DEFAULT_ADMIN_ROLE`. ([#4009](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4009)) +- `SignatureChecker`: Add `isValidERC1271SignatureNow` for checking a signature directly against a smart contract using ERC-1271. ([#3932](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3932)) +- `SafeERC20`: Add a `forceApprove` function to improve compatibility with tokens behaving like USDT. ([#4067](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4067)) +- `ERC1967Upgrade`: removed contract-wide `oz-upgrades-unsafe-allow delegatecall` annotation, replaced by granular annotation in `UUPSUpgradeable`. ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971)) +- `ERC20Wrapper`: self wrapping and deposit by the wrapper itself are now explicitly forbidden. ([#4100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4100)) +- `ECDSA`: optimize bytes32 computation by using assembly instead of `abi.encodePacked`. ([#3853](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3853)) +- `ERC721URIStorage`: Emit ERC-4906 `MetadataUpdate` in `_setTokenURI`. ([#4012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4012)) +- `ShortStrings`: Added a library for handling short strings in a gas efficient way, with fallback to storage for longer strings. ([#4023](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4023)) +- `SignatureChecker`: Allow return data length greater than 32 from EIP-1271 signers. ([#4038](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4038)) +- `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`). ([#3971](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3971)) +- `Initializable`: optimize `_disableInitializers` by using `!=` instead of `<`. ([#3787](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3787)) +- `Ownable2Step`: make `acceptOwnership` public virtual to enable usecases that require overriding it. ([#3960](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3960)) +- `UUPSUpgradeable.sol`: Change visibility to the functions `upgradeTo ` and `upgradeToAndCall ` from `external` to `public`. ([#3959](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3959)) +- `TimelockController`: Add the `CallSalt` event to emit on operation schedule. ([#4001](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4001)) +- Reformatted codebase with latest version of Prettier Solidity. ([#3898](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3898)) +- `Math`: optimize `log256` rounding check. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) +- `ERC20Votes`: optimize by using unchecked arithmetic. ([#3748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3748)) +- `Multicall`: annotate `multicall` function as upgrade safe to not raise a flag for its delegatecall. ([#3961](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3961)) +- `ERC20Pausable`, `ERC721Pausable`, `ERC1155Pausable`: Add note regarding missing public pausing functionality ([#4007](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4007)) +- `ECDSA`: Add a function `toDataWithIntendedValidatorHash` that encodes data with version 0x00 following EIP-191. ([#4063](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/4063)) +- `MerkleProof`: optimize by using unchecked arithmetic. ([#3745](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3745)) + +### 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)) +- `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.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`. + +### 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)) + +## 4.8.0 (2022-11-08) + +- `TimelockController`: Added a new `admin` constructor parameter that is assigned the admin role instead of the deployer account. ([#3722](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3722)) +- `Initializable`: add internal functions `_getInitializedVersion` and `_isInitializing` ([#3598](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3598)) +- `ERC165Checker`: add `supportsERC165InterfaceUnchecked` for consulting individual interfaces without the full ERC165 protocol. ([#3339](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3339)) +- `Address`: optimize `functionCall` by calling `functionCallWithValue` directly. ([#3468](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3468)) +- `Address`: optimize `functionCall` functions by checking contract size only if there is no returned data. ([#3469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3469)) +- `Governor`: make the `relay` function payable, and add support for EOA payments. ([#3730](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3730)) +- `GovernorCompatibilityBravo`: remove unused `using` statements. ([#3506](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3506)) +- `ERC20`: optimize `_transfer`, `_mint` and `_burn` by using `unchecked` arithmetic when possible. ([#3513](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3513)) +- `ERC20Votes`, `ERC721Votes`: optimize `getPastVotes` for looking up recent checkpoints. ([#3673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3673)) +- `ERC20FlashMint`: add an internal `_flashFee` function for overriding. ([#3551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3551)) +- `ERC4626`: use the same `decimals()` as the underlying asset by default (if available). ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639)) +- `ERC4626`: add internal `_initialConvertToShares` and `_initialConvertToAssets` functions to customize empty vaults behavior. ([#3639](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3639)) +- `ERC721`: optimize transfers by making approval clearing implicit instead of emitting an event. ([#3481](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3481)) +- `ERC721`: optimize burn by making approval clearing implicit instead of emitting an event. ([#3538](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3538)) +- `ERC721`: Fix balance accounting when a custom `_beforeTokenTransfer` hook results in a transfer of the token under consideration. ([#3611](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3611)) +- `ERC721`: use unchecked arithmetic for balance updates. ([#3524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3524)) +- `ERC721Consecutive`: Implementation of EIP-2309 that allows batch minting of ERC721 tokens during construction. ([#3311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3311)) +- `ReentrancyGuard`: Reduce code size impact of the modifier by using internal functions. ([#3515](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3515)) +- `SafeCast`: optimize downcasting of signed integers. ([#3565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3565)) +- `ECDSA`: Remove redundant check on the `v` value. ([#3591](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3591)) +- `VestingWallet`: add `releasable` getters. ([#3580](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3580)) +- `VestingWallet`: remove unused library `Math.sol`. ([#3605](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3605)) +- `VestingWallet`: make constructor payable. ([#3665](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3665)) +- `Create2`: optimize address computation by using assembly instead of `abi.encodePacked`. ([#3600](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3600)) +- `Clones`: optimized the assembly to use only the scratch space during deployments, and optimized `predictDeterministicAddress` to use fewer operations. ([#3640](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3640)) +- `Checkpoints`: Use procedural generation to support multiple key/value lengths. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Checkpoints`: Add new lookup mechanisms. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Arrays`: Add `unsafeAccess` functions that allow reading and writing to an element in a storage array bypassing Solidity's "out-of-bounds" check. ([#3589](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3589)) +- `Strings`: optimize `toString`. ([#3573](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3573)) +- `Ownable2Step`: extension of `Ownable` that makes the ownership transfers a two step process. ([#3620](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3620)) +- `Math` and `SignedMath`: optimize function `max` by using `>` instead of `>=`. ([#3679](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3679)) +- `Math`: Add `log2`, `log10` and `log256`. ([#3670](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3670)) +- Arbitrum: Update the vendored arbitrum contracts to match the nitro upgrade. ([#3692](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3692)) + +### Breaking changes + +- `ERC721`: In order to add support for batch minting via `ERC721Consecutive` it was necessary to make a minor breaking change in the internal interface of `ERC721`. Namely, the hooks `_beforeTokenTransfer` and `_afterTokenTransfer` have one additional argument that may need to be added to overrides: + +```diff + function _beforeTokenTransfer( + address from, + address to, + uint256 tokenId, ++ uint256 batchSize + ) internal virtual override +``` + +- `ERC4626`: Conversion from shares to assets (and vice-versa) in an empty vault used to consider the possible mismatch between the underlying asset's and the vault's decimals. This initial conversion rate is now set to 1-to-1 irrespective of decimals, which are meant for usability purposes only. The vault now uses the assets decimals by default, so off-chain the numbers should appear the same. Developers overriding the vault decimals to a value that does not match the underlying asset may want to override the `_initialConvertToShares` and `_initialConvertToAssets` to replicate the previous behavior. + +- `TimelockController`: During deployment, the TimelockController used to grant the `TIMELOCK_ADMIN_ROLE` to the deployer and to the timelock itself. The deployer was then expected to renounce this role once configuration of the timelock is over. Failing to renounce that role allows the deployer to change the timelock permissions (but not to bypass the delay for any time-locked actions). The role is no longer given to the deployer by default. A new parameter `admin` can be set to a non-zero address to grant the admin role during construction (to the deployer or any other address). Just like previously, this admin role should be renounced after configuration. If this param is given `address(0)`, the role is not allocated and doesn't need to be revoked. In any case, the timelock itself continues to have this role. + +### Deprecations + +- `EIP712`: Added the file `EIP712.sol` and deprecated `draft-EIP712.sol` since the EIP is no longer a Draft. Developers are encouraged to update their imports. ([#3621](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3621)) + +```diff +-import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; ++import "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; +``` + +- `ERC721Votes`: Added the file `ERC721Votes.sol` and deprecated `draft-ERC721Votes.sol` since it no longer depends on a Draft EIP (EIP-712). Developers are encouraged to update their imports. ([#3699](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3699)) + +```diff +-import "@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol"; ++import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Votes.sol"; +``` + +### ERC-721 Compatibility Note + +ERC-721 integrators that interpret contract state from events should make sure that they implement the clearing of approval that is implicit in every transfer according to the EIP. Previous versions of OpenZeppelin Contracts emitted an explicit `Approval` event even though it was not required by the specification, and this is no longer the case. + +With the new `ERC721Consecutive` extension, the internal workings of `ERC721` are slightly changed. Custom extensions to ERC721 should be reviewed to ensure they remain correct. The internal functions that should be considered are `_ownerOf` (new), `_beforeTokenTransfer`, and `_afterTokenTransfer`. + +### ERC-4626 Upgrade Note + +Existing `ERC4626` contracts that are upgraded to 4.8 must initialize a new variable that holds the vault token decimals. The recommended way to do this is to use a [reinitializer]: + +[reinitializer]: https://docs.openzeppelin.com/contracts/4.x/api/proxy#Initializable-reinitializer-uint8- + +```solidity +function migrateToV48() public reinitializer(2) { + __ERC4626_init(IERC20Upgradeable(asset())); +} +``` + +## 4.7.3 (2022-08-10) + +### Breaking changes + +- `ECDSA`: `recover(bytes32,bytes)` and `tryRecover(bytes32,bytes)` no longer accept compact signatures to prevent malleability. Compact signature support remains available using `recover(bytes32,bytes32,bytes32)` and `tryRecover(bytes32,bytes32,bytes32)`. + +## 4.7.2 (2022-07-25) + +- `LibArbitrumL2`, `CrossChainEnabledArbitrumL2`: Fixed detection of cross-chain calls for EOAs. Previously, calls from EOAs would be classified as cross-chain calls. ([#3578](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3578)) +- `GovernorVotesQuorumFraction`: Fixed quorum updates so they do not affect past proposals that failed due to lack of quorum. ([#3561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3561)) +- `ERC165Checker`: Added protection against large returndata. ([#3587](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3587)) + +## 4.7.1 (2022-07-18) + +- `SignatureChecker`: Fix an issue that causes `isValidSignatureNow` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552)) +- `ERC165Checker`: Fix an issue that causes `supportsInterface` to revert when the target contract returns ill-encoded data. ([#3552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3552)) + +## 4.7.0 (2022-06-29) + +- `TimelockController`: Migrate `_call` to `_execute` and allow inheritance and overriding similar to `Governor`. ([#3317](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3317)) +- `CrossChainEnabledPolygonChild`: replace the `require` statement with the custom error `NotCrossChainCall`. ([#3380](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3380)) +- `ERC20FlashMint`: Add customizable flash fee receiver. ([#3327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3327)) +- `ERC4626`: add an extension of `ERC20` that implements the ERC4626 Tokenized Vault Standard. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171)) +- `SafeERC20`: add `safePermit` as mitigation against phantom permit functions. ([#3280](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3280)) +- `Math`: add a `mulDiv` function that can round the result either up or down. ([#3171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3171)) +- `Math`: Add a `sqrt` function to compute square roots of integers, rounding either up or down. ([#3242](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3242)) +- `Strings`: add a new overloaded function `toHexString` that converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. ([#3403](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3403)) +- `EnumerableMap`: add new `UintToUintMap` map type. ([#3338](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3338)) +- `EnumerableMap`: add new `Bytes32ToUintMap` map type. ([#3416](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3416)) +- `SafeCast`: add support for many more types, using procedural code generation. ([#3245](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3245)) +- `MerkleProof`: add `multiProofVerify` to prove multiple values are part of a Merkle tree. ([#3276](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3276)) +- `MerkleProof`: add calldata versions of the functions to avoid copying input arrays to memory and save gas. ([#3200](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3200)) +- `ERC721`, `ERC1155`: simplified revert reasons. ([#3254](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3254), ([#3438](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3438))) +- `ERC721`: removed redundant require statement. ([#3434](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3434)) +- `PaymentSplitter`: add `releasable` getters. ([#3350](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3350)) +- `Initializable`: refactored implementation of modifiers for easier understanding. ([#3450](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3450)) +- `Proxies`: remove runtime check of ERC1967 storage slots. ([#3455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3455)) + +### Breaking changes + +- `Initializable`: functions decorated with the modifier `reinitializer(1)` may no longer invoke each other. + +## 4.6.0 (2022-04-26) + +- `crosschain`: Add a new set of contracts for cross-chain applications. `CrossChainEnabled` is a base contract with instantiations for several chains and bridges, and `AccessControlCrossChain` is an extension of access control that allows cross-chain operation. ([#3183](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3183)) +- `AccessControl`: add a virtual `_checkRole(bytes32)` function that can be overridden to alter the `onlyRole` modifier behavior. ([#3137](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3137)) +- `EnumerableMap`: add new `AddressToUintMap` map type. ([#3150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3150)) +- `EnumerableMap`: add new `Bytes32ToBytes32Map` map type. ([#3192](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3192)) +- `ERC20FlashMint`: support infinite allowance when paying back a flash loan. ([#3226](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3226)) +- `ERC20Wrapper`: the `decimals()` function now tries to fetch the value from the underlying token instance. If that calls revert, then the default value is used. ([#3259](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3259)) +- `draft-ERC20Permit`: replace `immutable` with `constant` for `_PERMIT_TYPEHASH` since the `keccak256` of string literals is treated specially and the hash is evaluated at compile time. ([#3196](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3196)) +- `ERC1155`: Add a `_afterTokenTransfer` hook for improved extensibility. ([#3166](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3166)) +- `ERC1155URIStorage`: add a new extension that implements a `_setURI` behavior similar to ERC721's `_setTokenURI`. ([#3210](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3210)) +- `DoubleEndedQueue`: a new data structure that supports efficient push and pop to both front and back, useful for FIFO and LIFO queues. ([#3153](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3153)) +- `Governor`: improved security of `onlyGovernance` modifier when using an external executor contract (e.g. a timelock) that can operate without necessarily going through the governance protocol. ([#3147](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3147)) +- `Governor`: Add a way to parameterize votes. This can be used to implement voting systems such as fractionalized voting, ERC721 based voting, or any number of other systems. The `params` argument added to `_countVote` method, and included in the newly added `_getVotes` method, can be used by counting and voting modules respectively for such purposes. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: rewording of revert reason for consistency. ([#3275](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3275)) +- `Governor`: fix an inconsistency in data locations that could lead to invalid bytecode being produced. ([#3295](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3295)) +- `Governor`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by governors. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230)) +- `TimelockController`: Implement `IERC721Receiver` and `IERC1155Receiver` to improve token custody by timelocks. ([#3230](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3230)) +- `TimelockController`: Add a separate canceller role for the ability to cancel. ([#3165](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3165)) +- `Initializable`: add a reinitializer modifier that enables the initialization of new modules, added to already initialized contracts through upgradeability. ([#3232](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3232)) +- `Initializable`: add an Initialized event that tracks initialized version numbers. ([#3294](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3294)) +- `ERC2981`: make `royaltyInfo` public to allow super call in overrides. ([#3305](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3305)) + +### Upgradeability notice + +- `TimelockController`: **(Action needed)** The upgrade from <4.6 to >=4.6 introduces a new `CANCELLER_ROLE` that requires set up to be assignable. After the upgrade, only addresses with this role will have the ability to cancel. Proposers will no longer be able to cancel. Assigning cancellers can be done by an admin (including the timelock itself) once the role admin is set up. To do this, we recommend upgrading to the `TimelockControllerWith46MigrationUpgradeable` contract and then calling the `migrateTo46` function. + +### Breaking changes + +- `Governor`: Adds internal virtual `_getVotes` method that must be implemented; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing voting module extension, rename `getVotes` to `_getVotes` and add a `bytes memory` argument. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: Adds `params` parameter to internal virtual `_countVote` method; this is a breaking change for existing concrete extensions to `Governor`. To fix this on an existing counting module extension, add a `bytes memory` argument to `_countVote`. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Governor`: Does not emit `VoteCast` event when params data is non-empty; instead emits `VoteCastWithParams` event. To fix this on an integration that consumes the `VoteCast` event, also fetch/monitor `VoteCastWithParams` events. ([#3043](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3043)) +- `Votes`: The internal virtual function `_getVotingUnits` was made `view` (which was accidentally missing). Any overrides should now be updated so they are `view` as well. + +## 4.5.0 (2022-02-09) + +- `ERC2981`: add implementation of the royalty standard, and the respective extensions for `ERC721` and `ERC1155`. ([#3012](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3012)) +- `GovernorTimelockControl`: improve the `state()` function to have it reflect cases where a proposal has been canceled directly on the timelock. ([#2977](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2977)) +- Preset contracts are now deprecated in favor of [Contracts Wizard](https://wizard.openzeppelin.com). ([#2986](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2986)) +- `Governor`: add a relay function to help recover assets sent to a governor that is not its own executor (e.g. when using a timelock). ([#2926](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2926)) +- `GovernorPreventLateQuorum`: add new module to ensure a minimum voting duration is available after the quorum is reached. ([#2973](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2973)) +- `ERC721`: improved revert reason when transferring from wrong owner. ([#2975](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2975)) +- `Votes`: Added a base contract for vote tracking with delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944)) +- `ERC721Votes`: Added an extension of ERC721 enabled with vote tracking and delegation. ([#2944](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2944)) +- `ERC2771Context`: use immutable storage to store the forwarder address, no longer an issue since Solidity >=0.8.8 allows reading immutable variables in the constructor. ([#2917](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2917)) +- `Base64`: add a library to parse bytes into base64 strings using `encode(bytes memory)` function, and provide examples to show how to use to build URL-safe `tokenURIs`. ([#2884](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2884)) +- `ERC20`: reduce allowance before triggering transfer. ([#3056](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3056)) +- `ERC20`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085)) +- `ERC20`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `ERC20Burnable`: do not update allowance on `burnFrom` when allowance is `type(uint256).max`. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `ERC777`: do not update allowance on `transferFrom` when allowance is `type(uint256).max`. ([#3085](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3085)) +- `ERC777`: add a `_spendAllowance` internal function. ([#3170](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3170)) +- `SignedMath`: a new signed version of the Math library with `max`, `min`, and `average`. ([#2686](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2686)) +- `SignedMath`: add an `abs(int256)` method that returns the unsigned absolute value of a signed value. ([#2984](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2984)) +- `ERC1967Upgrade`: Refactor the secure upgrade to use `ERC1822` instead of the previous rollback mechanism. This reduces code complexity and attack surface with similar security guarantees. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021)) +- `UUPSUpgradeable`: Add `ERC1822` compliance to support the updated secure upgrade mechanism. ([#3021](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3021)) +- Some more functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. + +### Breaking changes + +- `ERC1967Upgrade`: The function `_upgradeToAndCallSecure` was renamed to `_upgradeToAndCallUUPS`, along with the change in security mechanism described above. +- `Address`: The Solidity pragma is increased from `^0.8.0` to `^0.8.1`. This is required by the `account.code.length` syntax that replaces inline assembly. This may require users to bump their compiler version from `0.8.0` to `0.8.1` or later. Note that other parts of the code already include stricter requirements. + +## 4.4.2 (2022-01-11) + +### Bugfixes + +- `GovernorCompatibilityBravo`: Fix error in the encoding of calldata for proposals submitted through the compatibility interface with explicit signatures. ([#3100](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3100)) + +## 4.4.1 (2021-12-14) + +- `Initializable`: change the existing `initializer` modifier and add a new `onlyInitializing` modifier to prevent reentrancy risk. ([#3006](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3006)) + +### Breaking change + +It is no longer possible to call an `initializer`-protected function from within another `initializer` function outside the context of a constructor. Projects using OpenZeppelin upgradeable proxies should continue to work as is, since in the common case the initializer is invoked in the constructor directly. If this is not the case for you, the suggested change is to use the new `onlyInitializing` modifier in the following way: + +```diff + contract A { +- function initialize() public initializer { ... } ++ function initialize() internal onlyInitializing { ... } + } + contract B is A { + function initialize() public initializer { + A.initialize(); + } + } +``` + +## 4.4.0 (2021-11-25) + +- `Ownable`: add an internal `_transferOwnership(address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControl`: add internal `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControl`: mark `_setupRole(bytes32,address)` as deprecated in favor of `_grantRole(bytes32,address)`. ([#2568](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2568)) +- `AccessControlEnumerable`: hook into `_grantRole(bytes32,address)` and `_revokeRole(bytes32,address)`. ([#2946](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2946)) +- `EIP712`: cache `address(this)` to immutable storage to avoid potential issues if a vanilla contract is used in a delegatecall context. ([#2852](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2852)) +- Add internal `_setApprovalForAll` to `ERC721` and `ERC1155`. ([#2834](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2834)) +- `Governor`: shift vote start and end by one block to better match Compound's GovernorBravo and prevent voting at the Governor level if the voting snapshot is not ready. ([#2892](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2892)) +- `GovernorCompatibilityBravo`: consider quorum an inclusive rather than exclusive minimum to match Compound's GovernorBravo. ([#2974](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2974)) +- `GovernorSettings`: a new governor module that manages voting settings updatable through governance actions. ([#2904](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2904)) +- `PaymentSplitter`: now supports ERC20 assets in addition to Ether. ([#2858](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2858)) +- `ECDSA`: add a variant of `toEthSignedMessageHash` for arbitrary length message hashing. ([#2865](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2865)) +- `MerkleProof`: add a `processProof` function that returns the rebuilt root hash given a leaf and a proof. ([#2841](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2841)) +- `VestingWallet`: new contract that handles the vesting of Ether and ERC20 tokens following a customizable vesting schedule. ([#2748](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2748)) +- `Governor`: enable receiving Ether when a Timelock contract is not used. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849)) +- `GovernorTimelockCompound`: fix ability to use Ether stored in the Timelock contract. ([#2849](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2849)) + +## 4.3.3 (2021-11-08) + +- `ERC1155Supply`: Handle `totalSupply` changes by hooking into `_beforeTokenTransfer` to ensure consistency of balances and supply during `IERC1155Receiver.onERC1155Received` calls. + +## 4.3.2 (2021-09-14) + +- `UUPSUpgradeable`: Add modifiers to prevent `upgradeTo` and `upgradeToAndCall` being executed on any contract that is not the active ERC1967 proxy. This prevents these functions being called on implementation contracts or minimal ERC1167 clones, in particular. + +## 4.3.1 (2021-08-26) + +- `TimelockController`: Add additional isOperationReady check. + +## 4.3.0 (2021-08-17) + +- `ERC2771Context`: use private variable from storage to store the forwarder address. Fixes issues where `_msgSender()` was not callable from constructors. ([#2754](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2754)) +- `EnumerableSet`: add `values()` functions that returns an array containing all values in a single call. ([#2768](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2768)) +- `Governor`: added a modular system of `Governor` contracts based on `GovernorAlpha` and `GovernorBravo`. ([#2672](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2672)) +- Add an `interfaces` folder containing solidity interfaces to final ERCs. ([#2517](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2517)) +- `ECDSA`: add `tryRecover` functions that will not throw if the signature is invalid, and will return an error flag instead. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661)) +- `SignatureChecker`: Reduce gas usage of the `isValidSignatureNow` function for the "signature by EOA" case. ([#2661](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2661)) + +## 4.2.0 (2021-06-30) + +- `ERC20Votes`: add a new extension of the `ERC20` token with support for voting snapshots and delegation. ([#2632](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2632)) +- `ERC20VotesComp`: Variant of `ERC20Votes` that is compatible with Compound's `Comp` token interface but restricts supply to `uint96`. ([#2706](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2706)) +- `ERC20Wrapper`: add a new extension of the `ERC20` token which wraps an underlying token. Deposit and withdraw guarantee that the total supply is backed by a corresponding amount of underlying token. ([#2633](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2633)) +- Enumerables: Improve gas cost of removal in `EnumerableSet` and `EnumerableMap`. +- Enumerables: Improve gas cost of lookup in `EnumerableSet` and `EnumerableMap`. +- `Counter`: add a reset method. ([#2678](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2678)) +- Tokens: Wrap definitely safe subtractions in `unchecked` blocks. +- `Math`: Add a `ceilDiv` method for performing ceiling division. +- `ERC1155Supply`: add a new `ERC1155` extension that keeps track of the totalSupply of each tokenId. ([#2593](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2593)) +- `BitMaps`: add a new `BitMaps` library that provides a storage efficient datastructure for `uint256` to `bool` mapping with contiguous keys. ([#2710](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2710)) + +### Breaking Changes + +- `ERC20FlashMint` is no longer a Draft ERC. ([#2673](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2673))) + +**How to update:** Change your import paths by removing the `draft-` prefix from `@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20FlashMint.sol`. + +> See [Releases and Stability: Drafts](https://docs.openzeppelin.com/contracts/4.x/releases-stability#drafts). + +## 4.1.0 (2021-04-29) + +- `IERC20Metadata`: add a new extended interface that includes the optional `name()`, `symbol()` and `decimals()` functions. ([#2561](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2561)) +- `ERC777`: make reception acquirement optional in `_mint`. ([#2552](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2552)) +- `ERC20Permit`: add a `_useNonce` to enable further usage of ERC712 signatures. ([#2565](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2565)) +- `ERC20FlashMint`: add an implementation of the ERC3156 extension for flash-minting ERC20 tokens. ([#2543](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2543)) +- `SignatureChecker`: add a signature verification library that supports both EOA and ERC1271 compliant contracts as signers. ([#2532](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2532)) +- `Multicall`: add abstract contract with `multicall(bytes[] calldata data)` function to bundle multiple calls together ([#2608](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2608)) +- `ECDSA`: add support for ERC2098 short-signatures. ([#2582](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2582)) +- `AccessControl`: add an `onlyRole` modifier to restrict specific function to callers bearing a specific role. ([#2609](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2609)) +- `StorageSlot`: add a library for reading and writing primitive types to specific storage slots. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542)) +- UUPS Proxies: add `UUPSUpgradeable` to implement the UUPS proxy pattern together with `EIP1967Proxy`. ([#2542](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2542)) + +### Breaking changes + +This release includes two small breaking changes in `TimelockController`. + +1. The `onlyRole` modifier in this contract was designed to let anyone through if the role was granted to `address(0)`, + allowing the possibility to to make a role "open", which can be used for `EXECUTOR_ROLE`. This modifier is now + replaced by `AccessControl.onlyRole`, which does not have this ability. The previous behavior was moved to the + modifier `TimelockController.onlyRoleOrOpenRole`. +2. It was possible to make `PROPOSER_ROLE` an open role (as described in the previous item) if it was granted to + `address(0)`. This would affect the `schedule`, `scheduleBatch`, and `cancel` operations in `TimelockController`. + This ability was removed as it does not make sense to open up the `PROPOSER_ROLE` in the same way that it does for + `EXECUTOR_ROLE`. + +## 4.0.0 (2021-03-23) + +- Now targeting the 0.8.x line of Solidity compilers. For 0.6.x (resp 0.7.x) support, use version 3.4.0 (resp 3.4.0-solc-0.7) of OpenZeppelin. +- `Context`: making `_msgData` return `bytes calldata` instead of `bytes memory` ([#2492](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2492)) +- `ERC20`: removed the `_setDecimals` function and the storage slot associated to decimals. ([#2502](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2502)) +- `Strings`: addition of a `toHexString` function. ([#2504](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2504)) +- `EnumerableMap`: change implementation to optimize for `key → value` lookups instead of enumeration. ([#2518](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2518)) +- `GSN`: deprecate GSNv1 support in favor of upcoming support for GSNv2. ([#2521](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2521)) +- `ERC165`: remove uses of storage in the base ERC165 implementation. ERC165 based contracts now use storage-less virtual functions. Old behavior remains available in the `ERC165Storage` extension. ([#2505](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2505)) +- `Initializable`: make initializer check stricter during construction. ([#2531](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2531)) +- `ERC721`: remove enumerability of tokens from the base implementation. This feature is now provided separately through the `ERC721Enumerable` extension. ([#2511](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2511)) +- `AccessControl`: removed enumerability by default for a more lightweight contract. It is now opt-in through `AccessControlEnumerable`. ([#2512](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2512)) +- Meta Transactions: add `ERC2771Context` and a `MinimalForwarder` for meta-transactions. ([#2508](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2508)) +- Overall reorganization of the contract folder to improve clarity and discoverability. ([#2503](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2503)) +- `ERC20Capped`: optimize gas usage by enforcing the check directly in `_mint`. ([#2524](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2524)) +- Rename `UpgradeableProxy` to `ERC1967Proxy`. ([#2547](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2547)) +- `ERC777`: optimize the gas costs of the constructor. ([#2551](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2551)) +- `ERC721URIStorage`: add a new extension that implements the `_setTokenURI` behavior as it was available in 3.4.0. ([#2555](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2555)) +- `AccessControl`: added ERC165 interface detection. ([#2562](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2562)) +- `ERC1155`: make `uri` public so overloading function can call it using super. ([#2576](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2576)) + +### Bug fixes for beta releases + +- `AccessControlEnumerable`: Fixed `renounceRole` not updating enumerable set of addresses for a role. ([#2572](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2572)) + +### How to upgrade from 3.x + +Since this version has moved a few contracts to different directories, users upgrading from a previous version will need to adjust their import statements. To make this easier, the package includes a script that will migrate import statements automatically. After upgrading to the latest version of the package, run: + +``` +npx openzeppelin-contracts-migrate-imports +``` + +Make sure you're using git or another version control system to be able to recover from any potential error in our script. + +### How to upgrade from 4.0-beta.x + +Some further changes have been done between the different beta iterations. Transitions made during this period are configured in the `migrate-imports` script. Consequently, you can upgrade from any previous 4.0-beta.x version using the same script as described in the _How to upgrade from 3.x_ section. + +## 3.4.2 (2021-07-24) + +- `TimelockController`: Add additional isOperationReady check. + +## 3.4.1 (2021-03-03) + +- `ERC721`: made `_approve` an internal function (was private). + +## 3.4.0 (2021-02-02) + +- `BeaconProxy`: added new kind of proxy that allows simultaneous atomic upgrades. ([#2411](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2411)) +- `EIP712`: added helpers to verify EIP712 typed data signatures on chain. ([#2418](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2418)) +- `ERC20Permit`: added an implementation of the ERC20 permit extension for gasless token approvals. ([#2237](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237)) +- Presets: added token presets with preminted fixed supply `ERC20PresetFixedSupply` and `ERC777PresetFixedSupply`. ([#2399](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2399)) +- `Address`: added `functionDelegateCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) +- `Clones`: added a library for deploying EIP 1167 minimal proxies. ([#2449](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2449)) +- `Context`: moved from `contracts/GSN` to `contracts/utils`. ([#2453](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2453)) +- `PaymentSplitter`: replace usage of `.transfer()` with `Address.sendValue` for improved compatibility with smart wallets. ([#2455](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2455)) +- `UpgradeableProxy`: bubble revert reasons from initialization calls. ([#2454](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2454)) +- `SafeMath`: fix a memory allocation issue by adding new `SafeMath.tryOp(uint,uint)→(bool,uint)` functions. `SafeMath.op(uint,uint,string)→uint` are now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462)) +- `EnumerableMap`: fix a memory allocation issue by adding new `EnumerableMap.tryGet(uint)→(bool,address)` functions. `EnumerableMap.get(uint)→string` is now deprecated. ([#2462](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2462)) +- `ERC165Checker`: added batch `getSupportedInterfaces`. ([#2469](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2469)) +- `RefundEscrow`: `beneficiaryWithdraw` will forward all available gas to the beneficiary. ([#2480](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2480)) +- Many view and pure functions have been made virtual to customize them via overrides. In many cases this will not imply that other functions in the contract will automatically adapt to the overridden definitions. People who wish to override should consult the source code to understand the impact and if they need to override any additional functions to achieve the desired behavior. + +### Security Fixes + +- `ERC777`: fix potential reentrancy issues for custom extensions to `ERC777`. ([#2483](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483)) + +If you're using our implementation of ERC777 from version 3.3.0 or earlier, and you define a custom `_beforeTokenTransfer` function that writes to a storage variable, you may be vulnerable to a reentrancy attack. If you're affected and would like assistance please write to security@openzeppelin.com. [Read more in the pull request.](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2483) + +## 3.3.0 (2020-11-26) + +- Now supports both Solidity 0.6 and 0.7. Compiling with solc 0.7 will result in warnings. Install the `solc-0.7` tag to compile without warnings. +- `Address`: added `functionStaticCall`, similar to the existing `functionCall`. ([#2333](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2333)) +- `TimelockController`: added a contract to augment access control schemes with a delay. ([#2354](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2354)) +- `EnumerableSet`: added `Bytes32Set`, for sets of `bytes32`. ([#2395](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2395)) + +## 3.2.2-solc-0.7 (2020-10-28) + +- Resolve warnings introduced by Solidity 0.7.4. ([#2396](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2396)) + +## 3.2.1-solc-0.7 (2020-09-15) + +- `ERC777`: Remove a warning about function state visibility in Solidity 0.7. ([#2327](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2327)) + +## 3.2.0 (2020-09-10) + +### New features + +- Proxies: added the proxy contracts from OpenZeppelin SDK. ([#2335](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2335)) + +#### Proxy changes with respect to OpenZeppelin SDK + +Aside from upgrading them from Solidity 0.5 to 0.6, we've changed a few minor things from the proxy contracts as they were found in OpenZeppelin SDK. + +- `UpgradeabilityProxy` was renamed to `UpgradeableProxy`. +- `AdminUpgradeabilityProxy` was renamed to `TransparentUpgradeableProxy`. +- `Proxy._willFallback` was renamed to `Proxy._beforeFallback`. +- `UpgradeabilityProxy._setImplementation` and `AdminUpgradeabilityProxy._setAdmin` were made private. + +### Improvements + +- `Address.isContract`: switched from `extcodehash` to `extcodesize` for less gas usage. ([#2311](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2311)) + +### Breaking changes + +- `ERC20Snapshot`: switched to using `_beforeTokenTransfer` hook instead of overriding ERC20 operations. ([#2312](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2312)) + +This small change in the way we implemented `ERC20Snapshot` may affect users who are combining this contract with +other ERC20 flavors, since it no longer overrides `_transfer`, `_mint`, and `_burn`. This can result in having to remove Solidity `override(...)` specifiers in derived contracts for these functions, and to instead have to add it for `_beforeTokenTransfer`. See [Using Hooks](https://docs.openzeppelin.com/contracts/3.x/extending-contracts#using-hooks) in the documentation. + +## 3.1.0 (2020-06-23) + +### New features + +- `SafeCast`: added functions to downcast signed integers (e.g. `toInt32`), improving usability of `SignedSafeMath`. ([#2243](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2243)) +- `functionCall`: new helpers that replicate Solidity's function call semantics, reducing the need to rely on `call`. ([#2264](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2264)) +- `ERC1155`: added support for a base implementation, non-standard extensions and a preset contract. ([#2014](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2014), [#2230](https://github.com/OpenZeppelin/openzeppelin-contracts/issues/2230)) + +### Improvements + +- `ReentrancyGuard`: reduced overhead of using the `nonReentrant` modifier. ([#2171](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2171)) +- `AccessControl`: added a `RoleAdminChanged` event to `_setAdminRole`. ([#2214](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2214)) +- Made all `public` functions in the token preset contracts `virtual`. ([#2257](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2257)) + +### Deprecations + +- `SafeERC20`: deprecated `safeApprove`. ([#2268](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2268)) + +## 3.0.2 (2020-06-08) + +### Improvements + +- Added SPX license identifier to all contracts. ([#2235](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2235)) + +## 3.0.1 (2020-04-27) + +### Bugfixes + +- `ERC777`: fixed the `_approve` internal function not validating some of their arguments for non-zero addresses. ([#2213](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2213)) + +## 3.0.0 (2020-04-20) + +### New features + +- `AccessControl`: new contract for managing permissions in a system, replacement for `Ownable` and `Roles`. ([#2112](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2112)) +- `SafeCast`: new functions to convert to and from signed and unsigned values: `toUint256` and `toInt256`. ([#2123](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2123)) +- `EnumerableMap`: a new data structure for key-value pairs (like `mapping`) that can be iterated over. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) + +### Breaking changes + +- `ERC721`: `burn(owner, tokenId)` was removed, use `burn(tokenId)` instead. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `ERC721`: `_checkOnERC721Received` was removed. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `ERC721`: `_transferFrom` and `_safeTransferFrom` were renamed to `_transfer` and `_safeTransfer`. ([#2162](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2162)) +- `Ownable`: removed `_transferOwnership`. ([#2162](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2162)) +- `PullPayment`, `Escrow`: `withdrawWithGas` was removed. The old `withdraw` function now forwards all gas. ([#2125](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2125)) +- `Roles` was removed, use `AccessControl` as a replacement. ([#2112](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2112)) +- `ECDSA`: when receiving an invalid signature, `recover` now reverts instead of returning the zero address. ([#2114](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2114)) +- `Create2`: added an `amount` argument to `deploy` for contracts with `payable` constructors. ([#2117](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2117)) +- `Pausable`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Strings`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Counters`: moved to the `utils` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `SignedSafeMath`: moved to the `math` directory. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `ERC20Snapshot`: moved to the `token/ERC20` directory. `snapshot` was changed into an `internal` function. ([#2122](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2122)) +- `Ownable`: moved to the `access` directory. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Ownable`: removed `isOwner`. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Secondary`: removed from the library, use `Ownable` instead. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `Escrow`, `ConditionalEscrow`, `RefundEscrow`: these now use `Ownable` instead of `Secondary`, their external API changed accordingly. ([#2120](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2120)) +- `ERC20`: removed `_burnFrom`. ([#2119](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2119)) +- `Address`: removed `toPayable`, use `payable(address)` instead. ([#2133](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2133)) +- `ERC777`: `_send`, `_mint` and `_burn` now use the caller as the operator. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134)) +- `ERC777`: removed `_callsTokensToSend` and `_callTokensReceived`. ([#2134](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2134)) +- `EnumerableSet`: renamed `get` to `at`. ([#2151](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2151)) +- `ERC165Checker`: functions no longer have a leading underscore. ([#2150](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2150)) +- `ERC721Metadata`, `ERC721Enumerable`: these contracts were removed, and their functionality merged into `ERC721`. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) +- `ERC721`: added a constructor for `name` and `symbol`. ([#2160](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2160)) +- `ERC20Detailed`: this contract was removed and its functionality merged into `ERC20`. ([#2161](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2161)) +- `ERC20`: added a constructor for `name` and `symbol`. `decimals` now defaults to 18. ([#2161](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2161)) +- `Strings`: renamed `fromUint256` to `toString` ([#2188](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2188)) + +## 2.5.1 (2020-04-24) + +### Bugfixes + +- `ERC777`: fixed the `_send` and `_approve` internal functions not validating some of their arguments for non-zero addresses. ([#2212](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2212)) + +## 2.5.0 (2020-02-04) + +### New features + +- `SafeCast.toUintXX`: new library for integer downcasting, which allows for safe operation on smaller types (e.g. `uint32`) when combined with `SafeMath`. ([#1926](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1926)) +- `ERC721Metadata`: added `baseURI`, which can be used for dramatic gas savings when all token URIs share a prefix (e.g. `http://api.myapp.com/tokens/`). ([#1970](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1970)) +- `EnumerableSet`: new library for storing enumerable sets of values. Only `AddressSet` is supported in this release. ([#2061](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/2061)) +- `Create2`: simple library to make usage of the `CREATE2` opcode easier. ([#1744](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1744)) + +### Improvements + +- `ERC777`: `_burn` is now internal, providing more flexibility and making it easier to create tokens that deflate. ([#1908](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1908)) +- `ReentrancyGuard`: greatly improved gas efficiency by using the net gas metering mechanism introduced in the Istanbul hardfork. ([#1992](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1992), [#1996](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1996)) +- `ERC777`: improve extensibility by making `_send` and related functions `internal`. ([#2027](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2027)) +- `ERC721`: improved revert reason when transferring tokens to a non-recipient contract. ([#2018](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2018)) + +### Breaking changes + +- `ERC165Checker` now requires a minimum Solidity compiler version of 0.5.10. ([#1829](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1829)) + +## 2.4.0 (2019-10-29) + +### New features + +- `Address.toPayable`: added a helper to convert between address types without having to resort to low-level casting. ([#1773](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1773)) +- Facilities to make metatransaction-enabled contracts through the Gas Station Network. ([#1844](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1844)) +- `Address.sendValue`: added a replacement to Solidity's `transfer`, removing the fixed gas stipend. ([#1962](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1962)) +- Added replacement for functions that don't forward all gas (which have been deprecated): ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976)) + - `PullPayment.withdrawPaymentsWithGas(address payable payee)` + - `Escrow.withdrawWithGas(address payable payee)` +- `SafeMath`: added support for custom error messages to `sub`, `div` and `mod` functions. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828)) + +### Improvements + +- `Address.isContract`: switched from `extcodesize` to `extcodehash` for less gas usage. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) +- `ERC20` and `ERC777` updated to throw custom errors on subtraction overflows. ([#1828](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1828)) + +### Deprecations + +- Deprecated functions that don't forward all gas: ([#1976](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1976)) + - `PullPayment.withdrawPayments(address payable payee)` + - `Escrow.withdraw(address payable payee)` + +### Breaking changes + +- `Address` now requires a minimum Solidity compiler version of 0.5.5. ([#1802](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1802)) +- `SignatureBouncer` has been removed from drafts, both to avoid confusions with the GSN and `GSNRecipientSignature` (previously called `GSNBouncerSignature`) and because the API was not very clear. ([#1879](https://github.com/OpenZeppelin/openzeppelin-contracts/pull/1879)) + +### How to upgrade from 2.4.0-beta + +The final 2.4.0 release includes a refactor of the GSN contracts that will be a breaking change for 2.4.0-beta users. + +- The default empty implementations of `_preRelayedCall` and `_postRelayedCall` were removed and must now be explicitly implemented always in custom recipients. If your custom recipient didn't include an implementation, you can provide an empty one. +- `GSNRecipient`, `GSNBouncerBase`, and `GSNContext` were all merged into `GSNRecipient`. +- `GSNBouncerSignature` and `GSNBouncerERC20Fee` were renamed to `GSNRecipientSignature` and `GSNRecipientERC20Fee`. +- It is no longer necessary to inherit from `GSNRecipient` when using `GSNRecipientSignature` and `GSNRecipientERC20Fee`. + +For example, a contract using `GSNBouncerSignature` would have to be changed in the following way. + +```diff +-contract MyDapp is GSNRecipient, GSNBouncerSignature { ++contract MyDapp is GSNRecipientSignature { +``` + +Refer to the table below to adjust your inheritance list. + +| 2.4.0-beta | 2.4.0 | +| ----------------------------------- | ----------------------- | +| `GSNRecipient, GSNBouncerSignature` | `GSNRecipientSignature` | +| `GSNRecipient, GSNBouncerERC20Fee` | `GSNRecipientERC20Fee` | +| `GSNBouncerBase` | `GSNRecipient` | + +## 2.3.0 (2019-05-27) + +### New features + +- `ERC1820`: added support for interacting with the [ERC1820](https://eips.ethereum.org/EIPS/eip-1820) registry contract (`IERC1820Registry`), as well as base contracts that can be registered as implementers there. ([#1677](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1677)) +- `ERC777`: support for the [ERC777 token](https://eips.ethereum.org/EIPS/eip-777), which has multiple improvements over `ERC20` (but is backwards compatible with it) such as built-in burning, a more straightforward permission system, and optional sender and receiver hooks on transfer (mandatory for contracts!). ([#1684](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1684)) +- All contracts now have revert reason strings, which give insight into error conditions, and help debug failing transactions. ([#1704](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1704)) + +### Improvements + +- Reverted the Solidity version bump done in v2.2.0, setting the minimum compiler version to v0.5.0, to prevent unexpected build breakage. Users are encouraged however to stay on top of new compiler releases, which usually include bugfixes. ([#1729](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1729)) + +### Bugfixes + +- `PostDeliveryCrowdsale`: some validations where skipped when paired with other crowdsale flavors, such as `AllowanceCrowdsale`, or `MintableCrowdsale` and `ERC20Capped`, which could cause buyers to not be able to claim their purchased tokens. ([#1721](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1721)) +- `ERC20._transfer`: the `from` argument was allowed to be the zero address, so it was possible to internally trigger a transfer of 0 tokens from the zero address. This address is not a valid destinatary of transfers, nor can it give or receive allowance, so this behavior was inconsistent. It now reverts. ([#1752](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1752)) + +## 2.2.0 (2019-03-14) + +### New features + +- `ERC20Snapshot`: create snapshots on demand of the token balances and total supply, to later retrieve and e.g. calculate dividends at a past time. ([#1617](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1617)) +- `SafeERC20`: `ERC20` contracts with no return value (i.e. that revert on failure) are now supported. ([#1655](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1655)) +- `ERC20`: added internal `_approve(address owner, address spender, uint256 value)`, allowing derived contracts to set the allowance of arbitrary accounts. ([#1609](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1609)) +- `ERC20Metadata`: added internal `_setTokenURI(string memory tokenURI)`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618)) +- `TimedCrowdsale`: added internal `_extendTime(uint256 newClosingTime)` as well as `TimedCrowdsaleExtended(uint256 prevClosingTime, uint256 newClosingTime)` event allowing to extend the crowdsale, as long as it hasn't already closed. + +### Improvements + +- Upgraded the minimum compiler version to v0.5.2: this removes many Solidity warnings that were false positives. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606)) +- `ECDSA`: `recover` no longer accepts malleable signatures (those using upper-range values for `s`, or 0/1 for `v`). ([#1622](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1622)) +- `ERC721`'s transfers are now more gas efficient due to removal of unnecessary `SafeMath` calls. ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610)) +- Fixed variable shadowing issues. ([#1606](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1606)) + +### Bugfixes + +- (minor) `SafeERC20`: `safeApprove` wasn't properly checking for a zero allowance when attempting to set a non-zero allowance. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647)) + +### Breaking changes in drafts + +- `TokenMetadata` has been renamed to `ERC20Metadata`. ([#1618](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1618)) +- The library `Counter` has been renamed to `Counters` and its API has been improved. See an example in `ERC721`, lines [17](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L17) and [204](https://github.com/OpenZeppelin/openzeppelin-solidity/blob/3cb4a00fce1da76196ac0ac3a0ae9702b99642b5/contracts/token/ERC721/ERC721.sol#L204). ([#1610](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1610)) + +## 2.1.3 (2019-02-26) + +- Backported `SafeERC20.safeApprove` bugfix. ([#1647](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1647)) + +## 2.1.2 (2019-01-17) + +- Removed most of the test suite from the npm package, except `PublicRole.behavior.js`, which may be useful to users testing their own `Roles`. + +## 2.1.1 (2019-01-04) + +- Version bump to avoid conflict in the npm registry. + +## 2.1.0 (2019-01-04) + +### New features + +- Now targeting the 0.5.x line of Solidity compilers. For 0.4.24 support, use version 2.0 of OpenZeppelin. +- `WhitelistCrowdsale`: a crowdsale where only whitelisted accounts (`WhitelistedRole`) can purchase tokens. Adding or removing accounts from the whitelist is done by whitelist admins (`WhitelistAdminRole`). Similar to the pre-2.0 `WhitelistedCrowdsale`. ([#1525](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1525), [#1589](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1589)) +- `RefundablePostDeliveryCrowdsale`: replacement for `RefundableCrowdsale` (deprecated, see below) where tokens are only granted once the crowdsale ends (if it meets its goal). ([#1543](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1543)) +- `PausableCrowdsale`: allows for pausers (`PauserRole`) to pause token purchases. Other crowdsale operations (e.g. withdrawals and refunds, if applicable) are not affected. ([#832](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/832)) +- `ERC20`: `transferFrom` and `_burnFrom ` now emit `Approval` events, to represent the token's state comprehensively through events. ([#1524](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1524)) +- `ERC721`: added `_burn(uint256 tokenId)`, replacing the similar deprecated function (see below). ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) +- `ERC721`: added `_tokensOfOwner(address owner)`, allowing to internally retrieve the array of an account's owned tokens. ([#1522](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1522)) +- Crowdsales: all constructors are now `public`, meaning it is not necessary to extend these contracts in order to deploy them. The exception is `FinalizableCrowdsale`, since it is meaningless unless extended. ([#1564](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1564)) +- `SignedSafeMath`: added overflow-safe operations for signed integers (`int256`). ([#1559](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1559), [#1588](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1588)) + +### Improvements + +- The compiler version required by `Array` was behind the rest of the library so it was updated to `v0.4.24`. ([#1553](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1553)) +- Now conforming to a 4-space indentation code style. ([1508](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1508)) +- `ERC20`: more gas efficient due to removed redundant `require`s. ([#1409](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1409)) +- `ERC721`: fixed a bug that prevented internal data structures from being properly cleaned, missing potential gas refunds. ([#1539](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1539) and [#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549)) +- `ERC721`: general gas savings on `transferFrom`, `_mint` and `_burn`, due to redundant `require`s and `SSTORE`s. ([#1549](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1549)) + +### Bugfixes + +### Breaking changes + +### Deprecations + +- `ERC721._burn(address owner, uint256 tokenId)`: due to the `owner` parameter being unnecessary. ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550)) +- `RefundableCrowdsale`: due to trading abuse potential on crowdsales that miss their goal. ([#1543](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1543)) diff --git a/lib/openzeppelin-contracts-v4.9.3/CODE_OF_CONDUCT.md b/lib/openzeppelin-contracts-v4.9.3/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..cd7770d --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at contact@openzeppelin.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org diff --git a/lib/openzeppelin-contracts-v4.9.3/CONTRIBUTING.md b/lib/openzeppelin-contracts-v4.9.3/CONTRIBUTING.md new file mode 100644 index 0000000..1a44cc2 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing Guidelines + +There are many ways to contribute to OpenZeppelin Contracts. + +## Troubleshooting + +You can help other users in the community to solve their smart contract issues in the [OpenZeppelin Forum]. + +[OpenZeppelin Forum]: https://forum.openzeppelin.com/ + +## Opening an issue + +You can [open an issue] to suggest a feature or report a minor bug. For serious bugs please do not open an issue, instead refer to our [security policy] for appropriate steps. + +If you believe your issue may be due to user error and not a problem in the library, consider instead posting a question on the [OpenZeppelin Forum]. + +Before opening an issue, be sure to search through the existing open and closed issues, and consider posting a comment in one of those instead. + +When requesting a new feature, include as many details as you can, especially around the use cases that motivate it. Features are prioritized according to the impact they may have on the ecosystem, so we appreciate information showing that the impact could be high. + +[security policy]: https://github.com/OpenZeppelin/openzeppelin-contracts/security +[open an issue]: https://github.com/OpenZeppelin/openzeppelin-contracts/issues/new/choose + +## Submitting a pull request + +If you would like to contribute code or documentation you may do so by forking the repository and submitting a pull request. + +Any non-trivial code contribution must be first discussed with the maintainers in an issue (see [Opening an issue](#opening-an-issue)). Only very minor changes are accepted without prior discussion. + +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/lib/openzeppelin-contracts-v4.9.3/GUIDELINES.md b/lib/openzeppelin-contracts-v4.9.3/GUIDELINES.md new file mode 100644 index 0000000..0f4c982 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/GUIDELINES.md @@ -0,0 +1,117 @@ +# Engineering Guidelines + +## Testing + +Code must be thoroughly tested with quality unit tests. + +We defer to the [Moloch Testing Guide](https://github.com/MolochVentures/moloch/tree/master/test#readme) for specific recommendations, though not all of it is relevant here. Note the introduction: + +> Tests should be written, not only to verify correctness of the target code, but to be comprehensively reviewed by other programmers. Therefore, for mission critical Solidity code, the quality of the tests are just as important (if not more so) than the code itself, and should be written with the highest standards of clarity and elegance. + +Every addition or change to the code must come with relevant and comprehensive tests. + +Refactors should avoid simultaneous changes to tests. + +Flaky tests are not acceptable. + +The test suite should run automatically for every change in the repository, and in pull requests tests must pass before merging. + +The test suite coverage must be kept as close to 100% as possible, enforced in pull requests. + +In some cases unit tests may be insufficient and complementary techniques should be used: + +1. Property-based tests (aka. fuzzing) for math-heavy code. +2. Formal verification for state machines. + +## Code style + +Solidity code should be written in a consistent format enforced by a linter, following the official [Solidity Style Guide](https://docs.soliditylang.org/en/latest/style-guide.html). See below for further [Solidity Conventions](#solidity-conventions). + +The code should be simple and straightforward, prioritizing readability and understandability. Consistency and predictability should be maintained across the codebase. In particular, this applies to naming, which should be systematic, clear, and concise. + +Sometimes these guidelines may be broken if doing so brings significant efficiency gains, but explanatory comments should be added. + +Modularity should be pursued, but not at the cost of the above priorities. + +## Documentation + +For contributors, project guidelines and processes must be documented publicly. + +For users, features must be abundantly documented. Documentation should include answers to common questions, solutions to common problems, and recommendations for critical decisions that the user may face. + +All changes to the core codebase (excluding tests, auxiliary scripts, etc.) must be documented in a changelog, except for purely cosmetic or documentation changes. + +## Peer review + +All changes must be submitted through pull requests and go through peer code review. + +The review must be approached by the reviewer in a similar way as if it was an audit of the code in question (but importantly it is not a substitute for and should not be considered an audit). + +Reviewers should enforce code and project guidelines. + +External contributions must be reviewed separately by multiple maintainers. + +## Automation + +Automation should be used as much as possible to reduce the possibility of human error and forgetfulness. + +Automations that make use of sensitive credentials must use secure secret management, and must be strengthened against attacks such as [those on GitHub Actions worklows](https://github.com/nikitastupin/pwnhub). + +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. + +* All state variables should be private. + + Changes to state should be accompanied by events, and in some cases it is not correct to arbitrarily set state. Encapsulating variables as private and only allowing modification via setters enables us to ensure that events and other rules are followed reliably and prevents this kind of user error. + +* Internal or private state variables or functions should have an underscore prefix. + + ```solidity + contract TestContract { + uint256 private _privateVar; + uint256 internal _internalVar; + function _testInternal() internal { ... } + function _testPrivate() private { ... } + } + ``` + +* 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); + } + ``` + + Some standards (e.g. ERC20) use present tense, and in those cases the + standard specification is used. + +* Interface names should have a capital I prefix. + + ```solidity + interface IERC777 { + ``` + +* Unchecked arithmetic blocks should contain comments explaining why overflow is guaranteed not to happen. If the reason is immediately apparent from the line above the unchecked block, the comment may be omitted. diff --git a/lib/openzeppelin-contracts-v4.9.3/LICENSE b/lib/openzeppelin-contracts-v4.9.3/LICENSE new file mode 100644 index 0000000..817249a --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016-2023 zOS Global Limited and contributors + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/lib/openzeppelin-contracts-v4.9.3/README.md b/lib/openzeppelin-contracts-v4.9.3/README.md new file mode 100644 index 0000000..9fc9551 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/README.md @@ -0,0 +1,90 @@ +# OpenZeppelin + +[![NPM Package](https://img.shields.io/npm/v/@openzeppelin/contracts.svg)](https://www.npmjs.org/package/@openzeppelin/contracts) +[![Coverage Status](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts/graph/badge.svg)](https://codecov.io/gh/OpenZeppelin/openzeppelin-contracts) +[![GitPOAPs](https://public-api.gitpoap.io/v1/repo/OpenZeppelin/openzeppelin-contracts/badge)](https://www.gitpoap.io/gh/OpenZeppelin/openzeppelin-contracts) +[![Docs](https://img.shields.io/badge/docs-%F0%9F%93%84-yellow)](https://docs.openzeppelin.com/contracts) +[![Forum](https://img.shields.io/badge/forum-%F0%9F%92%AC-yellow)](https://docs.openzeppelin.com/contracts) + +**A library for secure smart contract development.** Build on a solid foundation of community-vetted code. + + * Implementations of standards like [ERC20](https://docs.openzeppelin.com/contracts/erc20) and [ERC721](https://docs.openzeppelin.com/contracts/erc721). + * Flexible [role-based permissioning](https://docs.openzeppelin.com/contracts/access-control) scheme. + * Reusable [Solidity components](https://docs.openzeppelin.com/contracts/utilities) to build custom contracts and complex decentralized systems. + +:mage: **Not sure how to get started?** Check out [Contracts Wizard](https://wizard.openzeppelin.com/) — an interactive smart contract generator. + +:building_construction: **Want to scale your decentralized application?** Check out [OpenZeppelin Defender](https://openzeppelin.com/defender) — a secure platform for automating and monitoring your operations. + +## Overview + +### Installation + +``` +$ npm install @openzeppelin/contracts +``` + +OpenZeppelin Contracts features a [stable API](https://docs.openzeppelin.com/contracts/releases-stability#api-stability), which means that your contracts won't break unexpectedly when upgrading to a newer minor version. + +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. + +### Usage + +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"; + +contract MyCollectible is ERC721 { + constructor() ERC721("MyCollectible", "MCO") { + } +} +``` + +_If you're new to smart contract development, head to [Developing Smart Contracts](https://docs.openzeppelin.com/learn/developing-smart-contracts) to learn about creating a new project and compiling your contracts._ + +To keep your system secure, you should **always** use the installed code as-is, and neither copy-paste it from online sources nor modify it yourself. The library is designed so that only the contracts and functions you use are deployed, so you don't need to worry about it needlessly increasing gas costs. + +## Learn More + +The guides in the [documentation site](https://docs.openzeppelin.com/contracts) will teach about different concepts, and how to use the related contracts that OpenZeppelin Contracts provides: + +* [Access Control](https://docs.openzeppelin.com/contracts/access-control): decide who can perform each of the actions on your system. +* [Tokens](https://docs.openzeppelin.com/contracts/tokens): create tradeable assets or collectives, and distribute them via [Crowdsales](https://docs.openzeppelin.com/contracts/crowdsales). +* [Utilities](https://docs.openzeppelin.com/contracts/utilities): generic useful tools including non-overflowing math, signature verification, and trustless paying systems. + +The [full API](https://docs.openzeppelin.com/contracts/api/token/ERC20) is also thoroughly documented, and serves as a great reference when developing your smart contract application. You can also ask for help or follow Contracts's development in the [community forum](https://forum.openzeppelin.com). + +Finally, you may want to take a look at the [guides on our blog](https://blog.openzeppelin.com/guides), which cover several common use cases and good practices. The following articles provide great background reading, though please note that some of the referenced tools have changed, as the tooling in the ecosystem continues to rapidly evolve. + +* [The Hitchhiker’s Guide to Smart Contracts in Ethereum](https://blog.openzeppelin.com/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05) will help you get an overview of the various tools available for smart contract development, and help you set up your environment. +* [A Gentle Introduction to Ethereum Programming, Part 1](https://blog.openzeppelin.com/a-gentle-introduction-to-ethereum-programming-part-1-783cc7796094) provides very useful information on an introductory level, including many basic concepts from the Ethereum platform. +* For a more in-depth dive, you may read the guide [Designing the Architecture for Your Ethereum Application](https://blog.openzeppelin.com/designing-the-architecture-for-your-ethereum-application-9cec086f8317), which discusses how to better structure your application and its relationship to the real world. + +## Security + +This project is maintained by [OpenZeppelin](https://openzeppelin.com) with the goal of providing a secure and reliable library of smart contract components for the ecosystem. We address security through risk management in various areas such as engineering and open source best practices, scoping and API design, multi-layered review processes, and incident response preparedness. + +The security policy is detailed in [`SECURITY.md`](./SECURITY.md), and specifies how you can report security vulnerabilities, which versions will receive security patches, and how to stay informed about them. We run a [bug bounty program on Immunefi](https://immunefi.com/bounty/openzeppelin) to reward the responsible disclosure of vulnerabilities. + +The engineering guidelines we follow to promote project quality can be found in [`GUIDELINES.md`](./GUIDELINES.md). + +Past audits can be found in [`audits/`](./audits). + +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. + +## Contribute + +OpenZeppelin Contracts exists thanks to its contributors. There are many ways you can participate and help build high quality software. Check out the [contribution guide](CONTRIBUTING.md)! + +## License + +OpenZeppelin Contracts is released under the [MIT License](LICENSE). + +## Legal + +Your use of this Project is governed by the terms found at www.openzeppelin.com/tos (the "Terms"). diff --git a/lib/openzeppelin-contracts-v4.9.3/RELEASING.md b/lib/openzeppelin-contracts-v4.9.3/RELEASING.md new file mode 100644 index 0000000..0318f63 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/RELEASING.md @@ -0,0 +1,47 @@ +# Releasing + +> Visit the documentation for [details about release schedule](https://docs.openzeppelin.com/contracts/releases-stability). + +OpenZeppelin Contracts uses a fully automated release process that takes care of compiling, packaging, and publishing the library, all of which is carried out in a clean CI environment (GitHub Actions), implemented in the ([`release-cycle`](.github/workflows/release-cycle.yml)) workflow. This helps to reduce the potential for human error and inconsistencies, and ensures that the release process is ongoing and reliable. + +## Changesets + +[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. + +## Branching model + +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. + +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" + + checkout master + commit id: "Feature C" + commit id: "Fix A" + + checkout release-vX.Y + cherry-pick id: "Fix A" tag: "" + commit id: "Release vX.Y.0-rc.1" + commit id: "Release vX.Y.0" + + 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" +``` diff --git a/lib/openzeppelin-contracts-v4.9.3/SECURITY.md b/lib/openzeppelin-contracts-v4.9.3/SECURITY.md new file mode 100644 index 0000000..4d6ff96 --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/SECURITY.md @@ -0,0 +1,42 @@ +# Security Policy + +Security vulnerabilities should be disclosed to the project maintainers through [Immunefi], or alternatively by email to security@openzeppelin.com. + +[Immunefi]: https://immunefi.com/bounty/openzeppelin + +## Bug Bounty + +Responsible disclosure of security vulnerabilities is rewarded through a bug bounty program on [Immunefi]. + +There is a bonus reward for issues introduced in release candidates that are reported before making it into a stable release. + +## Security Patches + +Security vulnerabilities will be patched as soon as responsibly possible, and published as an advisory on this repository (see [advisories]) and on the affected npm packages. + +[advisories]: https://github.com/OpenZeppelin/openzeppelin-contracts/security/advisories + +Projects that build on OpenZeppelin Contracts are encouraged to clearly state, in their source code and websites, how to be contacted about security issues in the event that a direct notification is considered necessary. We recommend including it in the NatSpec for the contract as `/// @custom:security-contact security@example.com`. + +Additionally, we recommend installing the library through npm and setting up vulnerability alerts such as [Dependabot]. + +[Dependabot]: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-supply-chain-security#what-is-dependabot + +### Supported Versions + +Security patches will be released for the latest minor of a given major release. For example, if an issue is found in versions >=4.6.0 and the latest is 4.8.0, the patch will be released only in version 4.8.1. + +Only critical severity bug fixes will be backported to past major releases. + +| Version | Critical security fixes | Other security fixes | +| ------- | ----------------------- | -------------------- | +| 4.x | :white_check_mark: | :white_check_mark: | +| 3.4 | :white_check_mark: | :x: | +| 2.5 | :white_check_mark: | :x: | +| < 2.0 | :x: | :x: | + +Note as well that the Solidity language itself only guarantees security updates for the latest release. + +## Legal + +Smart contracts are a nascent techology and carry a high level of technical risk and uncertainty. OpenZeppelin Contracts is made available under the MIT License, which disclaims all warranties in relation to the project and which limits the liability of those that contribute and maintain the project, including OpenZeppelin. Your use of the project is also governed by the terms found at www.openzeppelin.com/tos (the "Terms"). As set out in the Terms, you are solely responsible for any use of OpenZeppelin Contracts and you assume all risks associated with any such use. This Security Policy in no way evidences or represents an on-going duty by any contributor, including OpenZeppelin, to correct any flaws or alert you to all or any of the potential risks of utilizing the project. diff --git a/lib/openzeppelin-contracts-v4.9.3/audits/2017-03.md b/lib/openzeppelin-contracts-v4.9.3/audits/2017-03.md new file mode 100644 index 0000000..4cd6dbf --- /dev/null +++ b/lib/openzeppelin-contracts-v4.9.3/audits/2017-03.md @@ -0,0 +1,292 @@ +# OpenZeppelin Audit + +NOTE ON 2021-07-19: This report makes reference to Zeppelin, OpenZeppelin, OpenZeppelin Contracts, the OpenZeppelin team, and OpenZeppelin library. Many of these things have since been renamed and know that this audit applies to what is currently called the OpenZeppelin Contracts which are maintained by the OpenZeppelin Contracts Community. + +March, 2017 +Authored by Dennis Peterson and Peter Vessenes + +# Introduction + +Zeppelin requested that New Alchemy perform an audit of the contracts in their OpenZeppelin library. The OpenZeppelin contracts are a set of contracts intended to be a safe building block for a variety of uses by parties that may not be as sophisticated as the OpenZeppelin team. It is a design goal that the contracts be deployable safely and "as-is". + +The contracts are hosted at: + +https://github.com/OpenZeppelin/zeppelin-solidity + +All the contracts in the "contracts" folder are in scope. + +The git commit hash we evaluated is: +9c5975a706b076b7000e8179f8101e0c61024c87 + +# Disclaimer + +The audit makes no statements or warrantees about utility of the code, safety of the code, suitability of the business model, regulatory regime for the business model, or any other statements about fitness of the contracts to purpose, or their bugfree status. The audit documentation is for discussion purposes only. + +# Executive Summary + +Overall the OpenZeppelin codebase is of reasonably high quality -- it is clean, modular and follows best practices throughout. + +It is still in flux as a codebase, and needs better documentation per file as to expected behavior and future plans. It probably needs more comprehensive and aggressive tests written by people less nice than the current OpenZeppelin team. + +We identified two critical errors and one moderate issue, and would not recommend this commit hash for public use until these bugs are remedied. + +The repository includes a set of Truffle unit tests, a requirement and best practice for smart contracts like these; we recommend these be bulked up. + +# Discussion + +## Big Picture: Is This A Worthwhile Project? + +As soon as a developer touches OpenZeppelin contracts, they will modify something, leaving them in an un-audited state. We do not recommend developers deploy any unaudited code to the Blockchain if it will handle money, information or other things of value. + +> "In accordance with Unix philosophy, Perl gives you enough rope to hang yourself" +> --Larry Wall + +We think this is an incredibly worthwhile project -- aided by the high code quality. Creating a framework that can be easily extended helps increase the average code quality on the Blockchain by charting a course for developers and encouraging containment of modifications to certain sections. + +> "Rust: The language that makes you take the safety off before shooting yourself in the foot" +> -- (@mbrubeck) + +We think much more could be done here, and recommend the OpenZeppelin team keep at this and keep focusing on the design goal of removing rope and adding safety. + +## Solidity Version Updates Recommended + +Most of the code uses Solidity 0.4.11, but some files under `Ownership` are marked 0.4.0. These should be updated. + +Solidity 0.4.10 will add several features which could be useful in these contracts: + +- `assert(condition)`, which throws if the condition is false + +- `revert()`, which rolls back without consuming all remaining gas. + +- `address.transfer(value)`, which is like `send` but automatically propagates exceptions, and supports `.gas()`. See https://github.com/ethereum/solidity/issues/610 for more on this. + +## Error Handling: Throw vs Return False +Solidity standards allow two ways to handle an error -- either calling `throw` or returning `false`. Both have benefits. In particular, a `throw` guarantees a complete wipe of the call stack (up to the preceding external call), whereas `false` allows a function to continue. + +In general we prefer `throw` in our code audits, because it is simpler -- it's less for an engineer to keep track of. Returning `false` and using logic to check results can quickly become a poorly-tracked state machine, and this sort of complexity can cause errors. + +In the OpenZeppelin contracts, both styles are used in different parts of the codebase. `SimpleToken` transfers throw upon failure, while the full ERC20 token returns `false`. Some modifiers `throw`, others just wrap the function body in a conditional, effectively allowing the function to return false if the condition is not met. + +We don't love this, and would usually recommend you stick with one style or the other throughout the codebase. + +In at least one case, these different techniques are combined cleverly (see the Multisig comments, line 65). As a set of contracts intended for general use, we recommend you either strive for more consistency or document explicit design criteria that govern which techniques are used where. + +Note that it may be impossible to use either one in all situations. For example, SafeMath functions pretty much have to throw upon failure, but ERC20 specifies returning booleans. Therefore we make no particular recommendations, but simply point out inconsistencies to consider. + +# Critical Issues + +## Stuck Ether in Crowdsale contract +CrowdsaleToken.sol has no provision for withdrawing the raised ether. We *strongly* recommend a standard `withdraw` function be added. There is no scenario in which someone should deploy this contract as is, whether for testing or live. + +## Recursive Call in MultisigWallet +Line 45 of `MultisigWallet.sol` checks if the amount being sent by `execute` is under a daily limit. + +This function can only be called by the "Owner". As a first angle of attack, it's worth asking what will happen if the multisig wallet owners reset the daily limit by approving a call to `resetSpentToday`. + +If a chain of calls can be constructed in which the owner confirms the `resetSpentToday` function and then withdraws through `execute` in a recursive call, the contract can be drained. In fact, this could be done without a recursive call, just through repeated `execute` calls alternating with the `confirm` calls. + +We are still working through the confirmation protocol in `Shareable.sol`, but we are not convinced that this is impossible, in fact it looks possible. The flexibility any shared owner has in being able to revoke confirmation later is another worrisome angle of approach even if some simple patches are included. + +This bug has a number of causes that need to be addressed: + +1. `resetSpentToday` and `confirm` together do not limit the days on which the function can be called or (it appears) the number of times it can be called. +1. Once a call has been confirmed and `execute`d it appears that it can be re-executed. This is not good. +3. `confirmandCheck` doesn't seem to have logic about whether or not the function in question has been called. +4. Even if it did, `revoke` would need updates and logic to deal with revocation requests after a function call had been completed. + +We do not recommend using the MultisigWallet until these issues are fixed. + +# Moderate to Minor Issues + +## PullPayment +PullPayment.sol needs some work. It has no explicit provision for cancelling a payment. This would be desirable in a number of scenarios; consider a payee losing their wallet, or giving a griefing address, or just an address that requires more than the default gas offered by `send`. + +`asyncSend` has no overflow checking. This is a bad plan. We recommend overflow and underflow checking at the layer closest to the data manipulation. + +`asyncSend` allows more balance to be queued up for sending than the contract holds. This is probably a bad idea, or at the very least should be called something different. If the intent is to allow this, it should have provisions for dealing with race conditions between competing `withdrawPayments` calls. + +It would be nice to see how many payments are pending. This would imply a bit of a rewrite; we recommend this contract get some design time, and that developers don't rely on it in its current state. + +## Shareable Contract + +We do not believe the `Shareable.sol` contract is ready for primetime. It is missing functions, and as written may be vulnerable to a reordering attack -- an attack in which a miner or other party "racing" with a smart contract participant inserts their own information into a list or mapping. + +The confirmation and revocation code needs to be looked over with a very careful eye imagining extraordinarily bad behavior by shared owners before this contract can be called safe. + +No sanity checks on the initial constructor's `required` argument are worrisome as well. + +# Line by Line Comments + +## Lifecycle + +### Killable + +Very simple, allows owner to call selfdestruct, sending funds to owner. No issues. However, note that `selfdestruct` should typically not be used; it is common that a developer may want to access data in a former contract, and they may not understand that `selfdestruct` limits access to the contract. We recommend better documentation about this dynamic, and an alternate function name for `kill` like `completelyDestroy` while `kill` would perhaps merely send funds to the owner. + +Also note that a killable function allows the owner to take funds regardless of other logic. This may be desirable or undesirable depending on the circumstances. Perhaps `Killable` should have a different name as well. + +### Migrations + +I presume that the goal of this contract is to allow and annotate a migration to a new smart contract address. We are not clear here how this would be accomplished by the code; we'd like to review with the OpenZeppelin team. + +### Pausable + +We like these pauses! Note that these allow significant griefing potential by owners, and that this might not be obvious to participants in smart contracts using the OpenZeppelin framework. We would recommend that additional sample logic be added to for instance the TokenContract showing safer use of the pause and resume functions. In particular, we would recommend a timelock after which anyone could unpause the contract. + +The modifiers use the pattern `if(bool){_;}`. This is fine for functions that return false upon failure, but could be problematic for functions expected to throw upon failure. See our comments above on standardizing on `throw` or `return(false)`. + +## Ownership + +### Ownable + +Line 19: Modifier throws if doesn't meet condition, in contrast to some other inheritable modifiers (e.g. in Pausable) that use `if(bool){_;}`. + +### Claimable + +Inherits from Ownable but the existing owner sets a pendingOwner who has to claim ownership. + +Line 17: Another modifier that throws. + +### DelayedClaimable + +Is there any reason to descend from Ownable directly, instead of just Claimable, which descends from Ownable? If not, descending from both just adds confusion. + +### Contactable + +Allows owner to set a public string of contract information. No issues. + +### Shareable + +This needs some work. Doesn't check if `_required <= len(_owners)` for instance, that would be a bummer. What if _required were like `MAX - 1`? + +I have a general concern about the difference between `owners`, `_owners`, and `owner` in `Ownable.sol`. I recommend "Owners" be renamed. In general we do not recomment single character differences in variable names, although a preceding underscore is not uncommon in Solidity code. + +Line 34: "this contract only has six types of events"...actually only two. + +Line 61: Why is `ownerIndex` keyed by addresses hashed to `uint`s? Why not use the addresses directly, so `ownerIndex` is less obscure, and so there's stronger typing? + +Line 62: Do not love `++i) ... owners[2+ i]`. Makes me do math, which is not what I want to do. I want to not have to do math. + +There should probably be a function for adding a new operation, so the developer doesn't have to work directly with the internal data. (This would make the multisig contract even shorter.) + +There's a `revoke` function but not a `propose` function that we can see. + +Beware reordering. If `propose` allows the user to choose a bytes string for their proposal, bad things(TM) will happen as currently written. + + +### Multisig + +Just an interface. Note it allows changing an owner address, but not changing the number of owners. This is somewhat limiting but also simplifies implementation. + +## Payment + +### PullPayment + +Safe from reentrance attack since ether send is at the end, plus it uses `.send()` rather than `.call.value()`. + +There's an argument to be made that `.call.value()` is a better option *if* you're sure that it will be done after all state updates, since `.send` will fail if the recipient has an expensive fallback function. However, in the context of a function meant to be embedded in other contracts, it's probably better to use `.send`. One possible compromise is to add a function which allows only the owner to send ether via `.call.value`. + +If you don't use `call.value` you should implement a `cancel` function in case some value is pending here. + +Line 14: +Doesn't use safeAdd. Although it appears that payout amounts can only be increased, in fact the payer could lower the payout as much as desired via overflow. Also, the payer could add a large non-overflowing amount, causing the payment to exceed the contract balance and therefore fail when withdraw is attempted. + +Recommendation: track the sum of non-withdrawn asyncSends, and don't allow a new one which exceeds the leftover balance. If it's ever desirable to make payments revocable, it should be done explicitly. + +## Tokens + +### ERC20 + +Standard ERC20 interface only. + +There's a security hole in the standard, reported at Edcon: `approve` does not protect against race conditions and simply replaces the current value. An approved spender could wait for the owner to call `approve` again, then attempt to spend the old limit before the new limit is applied. If successful, this attacker could successfully spend the sum of both limits. + +This could be fixed by either (1) including the old limit as a parameter, so the update will fail if some gets spent, or (2) using the value parameter as a delta instead of replacement value. + +This is not fixable while adhering to the current full ERC20 standard, though it would be possible to add a "secureApprove" function. The impact isn't extreme since at least you can only be attacked by addresses you approved. Also, users could mitigate this by always setting spending limits to zero and checking for spends, before setting the new limit. + +Edcon slides: +https://drive.google.com/file/d/0ByMtMw2hul0EN3NCaVFHSFdxRzA/view + +### ERC20Basic + +Simpler interface skipping the Approve function. Note this departs from ERC20 in another way: transfer throws instead of returning false. + +### BasicToken + +Uses `SafeSub` and `SafeMath`, so transfer `throw`s instead of returning false. This complies with ERC20Basic but not the actual ERC20 standard. + +### StandardToken + +Implementation of full ERC20 token. + +Transfer() and transferFrom() use SafeMath functions, which will cause them to throw instead of returning false. Not a security issue but departs from standard. + +### SimpleToken + +Sample instantiation of StandardToken. Note that in this sample, decimals is 18 and supply only 10,000, so the supply is a small fraction of a single nominal token. + +### CrowdsaleToken + +StandardToken which mints tokens at a fixed price when sent ether. + +There's no provision for owner withdrawing the ether. As a sample for crowdsales it should be Ownable and allow the owner to withdraw ether, rather than stranding the ether in the contract. + +Note: an alternative pattern is a mint() function which is only callable from a separate crowdsale contract, so any sort of rules can be added without modifying the token itself. + +### VestedToken + +Lines 23, 27: +Functions `transfer()` and `transferFrom()` have a modifier canTransfer which throws if not enough tokens are available. However, transfer() returns a boolean success. Inconsistent treatment of failure conditions may cause problems for other contracts using the token. (Note that transferableTokens() relies on safeSub(), so will also throw if there's insufficient balance.) + +Line 64: +Delete not actually necessary since the value is overwritten in the next line anyway. + +## Root level + +### Bounty + +Avoids potential race condition by having each researcher deploy a separate contract for attack; if a research manages to break his associated contract, other researchers can't immediately claim the reward, they have to reproduce the attack in their own contracts. + +A developer could subvert this intent by implementing `deployContract()` to always return the same address. However, this would break the `researchers` mapping, updating the researcher address associated with the contract. This could be prevented by blocking rewrites in `researchers`. + +### DayLimit + +The modifier `limitedDaily` calls `underLimit`, which both checks that the spend is below the daily limit, and adds the input value to the daily spend. This is fine if all functions throw upon failure. However, not all OpenZeppelin functions do this; there are functions that returns false, and modifiers that wrap the function body in `if (bool) {_;}`. In these cases, `_value` will be added to `spentToday`, but ether may not actually be sent because other preconditions were not met. (However in the OpenZeppelin multisig this is not a problem.) + +Lines 4, 11: +Comment claims that `DayLimit` is multiowned, and Shareable is imported, but DayLimit does not actually inherit from Shareable. The intent may be for child contracts to inherit from Shareable (as Multisig does); in this case the import should be removed and the comment altered. + +Line 46: +Manual overflow check instead of using safeAdd. Since this is called from a function that throws upon failure anyway, there's no real downside to using safeAdd. + +### LimitBalance + +No issues. + +### MultisigWallet + +Lines 28, 76, 80: +`kill`, `setDailyLimit`, and `resetSpentToday` only happen with multisig approval, and hashes for these actions are logged by Shareable. However, they should probably post their own events for easy reading. + +Line 45: +This call to underLimit will reduce the daily limit, and then either throw or return 0. So in this case there's no danger that the limit will be reduced without the operation going through. + +Line 65: +Shareable's onlyManyOwners will take the user's confirmation, and execute the function body if and only if enough users have confirmed. Whole thing throws if the send fails, which will roll back the confirmation. Confirm returns false if not enough have confirmed yet, true if the whole thing succeeds, and throws only in the exceptional circumstance that the designated transaction unexpectedly fails. Elegant design. + +Line 68: +Throw here is good but note this function can fail either by returning false or by throwing. + +Line 92: +A bit odd to split `clearPending()` between this contract and Shareable. However this does allow contracts inheriting from Shareable to use custom structs for pending transactions. + + +### SafeMath + +Another interesting comment from the same Edcon presentation was that the overflow behavior of Solidity is undocumented, so in theory, source code that relies on it could break with a future revision. + +However, compiled code should be fine, and in the unlikely event that the compiler is revised in this way, there should be plenty of warning. (But this is an argument for keeping overflow checks isolated in SafeMath.) + +Aside from that small caveat, these are fine. + diff --git a/lib/openzeppelin-contracts-v4.9.3/audits/2018-10.pdf b/lib/openzeppelin-contracts-v4.9.3/audits/2018-10.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d5bf12741c8a6d44ed597de7204fde72d91dec35 GIT binary patch literal 1000527 zcmcG#2UJr__XmogfLOtX4FL-vLV8G$;z{qM7f>*b^g3!*3@iUkxE6%o5w zC{`?}h$yJoP{CdieF5*iUs>Mof8Sf{oseYaoY}v#`Sx=(M3g>Ehf2GH^4*LtYu$Pp92s6zP8InC6Cm)N8Qw60(bb;6%NK2$9l5! zP_^i@E*LqdUp+ke>4x|=jWL3HyhzKJlv{%)3 zKFc-O_dnS%DL2uwN^$=!Wm@``tG75E*K_6fI7_pa=q*ig*sZ@mg%+< z{2y2e4gS+gVJM`-N)X83nd#L!T}%^r@cf_Yl`(;Hj~@*2n;>jhz>nuPSNKOQLZ*>c zZAH=~m2<7Rr8yW+uJrEqi1epc>@Q%SD&~Y z68gIIJ?qo17lYj7$s5|Ac6Gd&w6ADvy9r(z9sgwf6KxHrJUwY1xB2!t&#%uewCQhO z2=IT*PO({8EiJf7Cr zhnF;@$aWf*L4-Z-n2A%`Tty@Hj2UtwsJscul&fd@tm6#Ec5LM0n%cZQ$n@T8q~Ha{ zhkO%w&E-8Z^TNqzd*eHn6P|wj8Nj&e6A3q?4#lK|@7;^eU%z_msK>l3&{miM6?p%> zTV0APo|pTv>+YxVGe5Y1S6&%2ud}RS>g>k;V-+MhWW>g=m?CtHeRB7z`eas>LLCnGb z%8XDL%n@^lzYDqim2}M_@ZcpsDIFQKNiS;7mhJD*@7l2!-(Fa|XCQT2_SV&9T_10K zV1HZu(JTJ^iT4p{(@Xob_Fo-vp1EgE`i5oxnUV=Ee`m82f4r~y{Dzt(RS z91n||T<_Lr(^7u2am%Sm^?|KLy9)d&F=&4eRNh_W-F!dIc~pDonE^THF3gB`FM0cr z*%+{`*6-cks>4O&*7J3TH@DgIp5011^s-$2diQH?75H0pvbGwwbJkQ#-Z8h-IaAVZ zR$RI2iV1}bKKT06^UJ&V4VCV1@Xn~X2O!iE>I3gNi!1wqouVE!n0~KGs zB9BZs(0fA1z@cH#`IO#6p9HuSufx4`J94D@ZsUOAFem5!PN$rrUjLr$uz$if>`%5~ z2)Ki9=-)X&=IZ+t7s%kn2@?&gE==eg64)>He*E$sP5laoiW+>=@8{?iefz{HyHGl! zI&U|6&6*43sLLb4esB)Eta@R~hm*+xFXj{OHon=>zNu|au)wMC zxIlVs1AloPS$NEQI&Eq5=WnJtD>vl3IJn=9 zG@(0d57o%6yI+jJ&6!ouZAO!wDeH{viL-sQrVcPq~x@k8sXKDy7 zK?hK`LZbKKqJ7T?-#jO3IuHnh)P~_&CLThe5uk~XeZ42d_2=sK{cnuf{yHx=e{=SR z+|t(@vhxJlBKEGAh2y5@aoM6(CF7hY^#6c;hkXxSkj_4HY|5Eq)1cpcx4n90Y%F;x z%3i-_L*_Ztkg_RZ_`_p-Pdmk&V88sWz)(4tDp;zWnCZv#aBV z`EMpP#_864xcBq^XI*Ej^yG%1@FCfLlM}y0yA^(%YRvZ9enS5~*FCLrZeG{dn#?aU z|3?Hy%l!9CMGuMP>pDC4woQ#c?e>HnF>Yq&swoS$Wp-|gckAbTFLh*Y?$xDdJ<*}l z2j@=s0{(vSv2Ne`YHt@@Z=z4y?e~EdU*})l{T;g%o@Ew&`gr2vo44;>lQbCf(9N_v zYYGqF3p!{|sn783iV7){-KEyAKV7~!=H=Ck^32H(GPV#RGyD#g2V|y%L=Q9G^8TJV zYP{?PD)(~h^u0?i_GO|=ca00{cc%al^w~7IwBa2673fpaLb+#E#;W=b?n}kj`JDr% zE|xyIY91B!oDGGSU7PuEiL2qp5oYm2Aii;Syk=8D`%z2trrC?L2B+?8z2{ncwEt7c zq?2o~i}q1sCwclbn)7- zSJ*GCyrEMY^RINxMfVw03&GqRcqQPqhoJ)V>Qe<@osynRq#RlgEUxx(flT1Kc;rYzMr{x#uU1oRX0k&tJW)?G{g& zT76r;a^=B2CAGKF10HjIkt?T_C4Gu%1;*`Owtc|p7kJdY<~d3HZ?#kUyi{TjFKUc? z;|eA$J6VhFvvDbF!E7yTN}s(CLcR7QSEf%HaR#3-Ja^lRytsprXFom6r}gprskdgH zzV$A4o)c(Oa>*e#`6S7mizjEh612K&I!>N>*5ndG!o%`6FHPZuWx>MfExxGs0&<1_iskf=M&~;sXsH zcMANF4GT&#uP?;WL5f1ZLF&yfOV54reQ+pe$P3sqeKDP!8B@1r=jn;}UVj%|ntXHB z{Km_hlW*|mMP%q2hA0}wlwK*FmP7D8o?q}4M_p-2;m@1?gm!-;cS!UL*+ici@$F?z zSGttzJtkcKaMk7A9A{@${?9%+-%6*>?0b*gB^s8oKK9CY^2wbhyVu9HXvC_!;|Cw~ zTo#5MiMkhDP{!F@ybbwn_R`uR_4_oJz5VW19o>;X*Wxt$Tzh2Gra_+`P9M3B99Jk6e>`KFgj^w)Xdl zCl{x|c+u$JrzFTfNJ;<7!SMf`gR3}~7~M=skVQiAAVIleVsA zvM06`&b!)ClTz=D$w$$&`xLiZKN8eILx<4RL5MX_`I^4bSB{&SZ${3Wi?Zj<7`v&Q z_ao`xgM(#p>ylSDM0TY3QgqIb;^xMKHf}9x`6_4Ko^#8v67=Q%)4eUF)Kl|UKFD}_ zs&qa#o3h%&iYm%u)E3`Jf=qmKsG@4KK-aK&@4IzR6pzvn>T-}o5GVZWz9 zsgsiQ zBpd+?>z(cv*kW=z+~o> z$U}GP20G>#8)lE$_It+vN!11dhW@qk2?KXm*U;#{TSI8qQA@dy{lzbbNX?*KKSbt=J=VYImwq*g{*w3!# zieE2){3x6$B%{37d5y?yR1Ed5A2O(a$Wf0P)zN`98}9aLeT+MhIrqITdS`aTfVJ5b znH{XvOo7SlJuLfVX2IZ>sGDn{X&$?nftzy9c(aFjf8FlmeXxNKE-D_INj?nnUUN5m z@8mYOnmw&S-t}E$`d60i+UH^KTeD|&jP2Hu0+(f3?GWa=RA=w|OL`Lz7xv0CTJrpg zOI&aIY^o_!XS46`2AgK>_B(8?9EH|ZJUxtzd*2VOOK~wx**nHG>vLJW>~YDeiiW}E zC+$94+E?2bR#>Y?mk&S>R36_6zV>O$_-Rd!+F#sey7Wrm_bK!xRiLo+hgesx3n$VmN9kXxB5Ks@>GzH44u9eA4uFe=3#&LwfQIWk>xJb zi4}t?Do?au`gGyb1@chqt$-Q%g7^M;2MsIU9O#mE5l%B##j(ovT$<_k`yly8WfsT6?2igG6ym74I7-mSzYCI^8+93DYCUT!FV0SD zFPXb@GI$~Gz@ol>XP=Ge<(KIXs&Q>wsPA*}aLm=qb@PrHia#gb4)dIAwzRa@VY^C7 zcK^6fg!D}=-4;kbz9pYX=HwQ4y$-y(Y2dt1T`?n;7ADJ7Uv$@2xGav~z8kA~vDE9m zA>`-ted-aGa=Ci};!yzLoPHwL|L@rMm)7%(GZ-h6DX^2qws zmK~(7VeqQZ4WGi0>6`M$1+>IJ`qKD4QPQfYwq8u^V!mh2{)tf^fMx$!JmsnQk$8Q= zZP$K}UnXi$9$mLG-wUQ^b|Ef53$Q$0nsh$Ff85f2OTK$eXq8KTgsvG~bJC7d8sgS` z58=OTxn34|UV%+%nPdHOsW|3y@zTQ^(yC}rYYRw4kgVS0tIrp)2#75A@iphAL&2ju z-gdls_oKe;OWTKQtast}THmZ}1y!E>`Le6wa2K9~T;yFj^@RN=dS2+fwKcUw32|{@vA+V)mH$ zqRltJhg9JxnW_HfAWmM9c>TMtd4{N#c}J!eH2XAvZ@=}hxV54F;nJ0_=S7~HZT->^ z{j;m{Eq2~H!MOWx(p$UY=ZqMG4oBu zz~ROtZV!EMxy`95=ORz=>dOu{KT49i$M}RTdHXnN{HF`852WzUmW6`r#ZnZb8c;Tfz&Uc z>d)lfBS<$Ny}rJ*PIQnCfd>&}r`!uXBgWeZZ!-HuoNUTc7)O`gyIh~JchlpQOP(ML z3Md5y)Pm-H>E~=G^Imi=HlJLSOzpyPJ#$ATa}X2z{#gBB+@BxAzqe*u2K}5F_iWsO zPb-<7OSwNF0ZWCQ{E|&%wV=LnR>jv^VK(i@8Sb}QVIJ)*qx9jpT_Ybl>z(z_5A=>) zci#E%fzUbWaV5=jXzc0`JD}dhbnp`c*QeIisZC*FCJ|^N(xghc2z-FW!tiTG)3OyioEZd-c2c z%saPv73MP+5JMA&OpnDVWNoQe56qk!vYUImj3Un(kQUeU;Cbz}eZk+7@s*|0%6KfP zVs!5rg50|1lj~oXV)u{2>~WcRYr)ng7yQNK^c~ZSg~M;}GS9f!>Q#R8O0=JsDsSfG zbrAdyj(gbCM@3}>zmtL6M=buZbya-MgV6E^p-G3ItX>m^jo&oZ|K`90{`=}Y=V%%) z9hg1{z4oPFaq>$)#7CdS72B?*486Mo)5KCvz1U9`wue1u)`oeovw>Hc8|u6E3`1E3dYEip;hT*W@L3 z8nJU9v&SextCJFEjL^{KM3=z?-^^+5_lbp_ftGPu2jf?PkG&dX=Z;P3b@}1X=7!<{ z0O^2?xJyQ)$HweLEs5-Zt{}}XcogRPBzm&$sLL>7;iEwAn8oSaRE2iS+_0L*l>=JQ zuWz_ME>#biack1Co0#UIiQLc;=o`FYI|^FtYYxoV-OnNzJ@`}}yWW!sSwIkSh`xTmF==LdoWWl;s z^hkUXZrZTRLoe_Dy6@VIp~o`r-b2UpgL7`^$4u;6?lpEt+3D@v;p=nq`Xq8zvz~)p z$JT5)=Uqp4{H>2WJ>;C;R<~sCoUl`mj@@|IR~|m2-SsSwZ0_WPs>^%|g}28KmGiE> z9U{pr91g!ZaEV35nVGFCq4zJ#08$|5LkVvNF0@`-Xzg9O(Te*SKs#GFg&&wx?XkGL zZd~5o3_t;SKE-uYwQ)&}Z9z`LM9XMhOTX>=+0Rqr^3K}U-W;Huz00}=^ilurB|{EA zeBC#nAl`xeaV+c3#?057pFF6(1wQ(4N*~^=-Q4!Q>_dlNl)zR#TQiJWVVE5B^jXn> zU0yHJffkZ^J=zuCoNq60QVGBZZV*1GZV<)w*r$qc5^#j){ zbhLKglU{zs-R~>7n>oX$i03f2I1M;|<4M%AI4k4UqX8AUV;RpQn%x>pPaS)axqElr zkz?g$m~3RP3A6IeVZDZRzqH1@%eN4wVRdcZxPEIcxs-)I*N+kSteSB!b5H*aW=VAD zx)&=q*4g7RDz)2^P1180MmqlDQ0Uh6DKN#6_Q#jEG7SLYJ z2>K&!$O!Af;m7y>%-R2@rZo1^^g~rgZ+ku4UGZg}V;*xc)*$=+Jm#PL$l;jU|M^2Y zq^F<={<~RB{*C+UbG}2}-U#0ISvV@%t8nPLIm3^!ZoE>zIy))*0(i(KD8x3+x<=&K&bjqw8*XCV?{G!!0S4J-hyWDqc{h+n4-!$K> zxL&k)BVlCm{UH0o&bJR32_F3Vg)`*|Sp~=-@I2(Rz&UPpioFd#FDyQ^xtDi8PnTAe zcR!MWucWj;xC0Zq8i)6$E?{JxNcc+=%M{HhCs>pvb<8zFKA2Bvf%@( zM_k{(v=#Fx+Hanty8XOh`;kMoz7 zw+a2DhgTk3jo+1ZYs2{obMh`v)!(6|R)^#+AnL#NkBokbE6RVi?y^MYj7 zY;OLtK{l^d5Bw%%Jsr7gEfjmktNey6a8qm1mBC}iuL;FkPSd^iNS2ERkG!&p=&? zSZgDjE^2(T9`BM59eRwm?a|y}iLw3W(s$8DkKLHJbMO=D4E1X}eAIc;IdAvnzyrlD z>$ZsK-Mqy9@6V_=c}5DEHz!_L|BS%h?;a8MqIUAtNN@iQ;tt_9D5maew)^z#V~`El zbJw!2_x5?*~$Wu+ZiM2orh z)4k7kiEyUaf1-2kV)=`vY46?)KHT?MRbZ9xuKnPfDGx(bBQu5o(GdqP_qpt=)7I~s zKe=MpxNCdXg`QsGi&qaBHqo}~UQuP>h9Cwz+PmSpXCHF?`ll;UB(IreDE~s-p!B8> z6W(4hZk)^WKG269cx9mp7rJXoeN~^nfwfxe9xKKi?M=X)xnm0&x(21zGFM+4XsDi; zMC$Th^_?b+OIy)7=zNwKecYFPj=dGxMLBjsy0~&X`R&MW)JKn#5Fe#kGVPfh;iaNW zi$!r)!&{wSt8Tm$`j0<6RwOH17aD~ncy0Adsfu&D zG{@D&{Xw$!(oBx1eh&DMdsIc*-dmR=$7P1Zt}7fgeCXKG9m%}Tn3d`^ zG<9x)cR$L;I|B(#(Blz{tS6W0E)36qJJH&NHm>BIEZB~}l({KiL8x(V5K-9vfDy**$boYgD=eMh#VS+L0^oZeP zFD?8;fzACkY~I4IJ|ph04e)Ue;@=#2_9=Hv#vS*%cgJRByP}@8{*=BUv7#m&G0a@^ zoc@M;z1gj@S91;e?t|Tn(sd?;vuyT~*;&(`j%Ka98!j2I!+7Sim21pHR=D(zIe{N} ze^o%USD*C)VCwm50{R*a(ik3tTyxp03G#a3nh)1I*#?pX)|l`!JoV7@5l_CgEPOQN z?dI!)q$zT`i|^3B&4N)PaT{-8t~vh^Up& zfkS%X6ADt@9|6zf#9xB(KR&piI!1x_IJeCUgM_qiwY)qum^$N$F$uir_LNDzea@xp zO=_RC2~||j%V}*BCQUtlRMh;Uy68w{UBJ67KL?L_5jY_yrg_%>vcXd-+a_(y=$lh= zq+nCRv5nvRM|EtP4Z2j*`^=gVIh(4s>95@joiZG=Y<760H|E>b#eNaf7BE#XKK*qW`$ZE5omdX9YjC*6&Ug-D`RLqU+4yi+C6=DKyIdOeXe} zKc9Y7uZh^e$o(7^YzTX{@q0q_+i1_KJr?1;@KNAJ7n{?zf)k$yyWytdT#~2HfBWj<^xHo=^yW?2w{M*;c9uKErkLed z?jL_34g5AhU4$nZDrPhdY6$j7dwJacV-4CHlkqqJCNDVkdGPGj(M5f>EI1Z24N}=$ z=W%cS$K=(WZ_hY6-@!27?A_i`?tC!gkt8``)!Uz7YD!J7)uDs+mUvCgQ`J1zk1Jf7H;mT{F03CPk^f6Ihju} zk{96*4INQc1Ige0bRCI{LvQEi-Wr=3ppSd@K5ZJKWc{GPI?S;}o}(I!eMfj@G<~0w z7%7jMm4_3H95!jLOcVZ5Xb6Hz=PfG)h-_w1)cMA5Rb)#CE4 z>q(IK>rwN*c?Qn#7#V&Qd+_0N@S-2{j~)4BjCs$>eKWmg^}7qlQzmN zeM9x-zVPOur{0u0wFc-tQq;8{UTUWlr-tW+j@bCoc5D~1wXJ;5%j-=~PV6ziXrC8P zeg6n?CwkuJ`wP5%o{lavFMjpS1|sab?eu1s;`rUVXXAHGL!N#-U`*Mp6Ca?d>M+`t zFYa8tYh*Ng(zOAP{YQXq*N=&Maz5NB`_Q$%dAi%F3CEsKDhb?vC$QT4JbCY|lv~R* z)1oR=1Gv5!#oOqyO*E)(liV4?d`L$k2_0VhV;F02RZRv`G9SW$*Ugf z5LpS!Pd$(QsLcg~b6e|f4laD;b91M9j^yKB$rG0}r@I+`n5y28bkln8H1D;I(&94g zjHG*Mqwsg#ZkHBTSx%k^dGYqdm^qai{0Q+z3$#PJ==s!~>tm9jAJ?uUY~X+PrDr}| zld=DYZ0m{W>7#>AJM};+8Y|(E6b3paNVNbLSB^MD?1;nR6z+pLn-S<>z%c_Uff?aUmm1 z&Sv|)`8lY8EKbDVapycd5_qs|-`J^r+WqoB&JwTw^sYBz_lc4h;qz_i%^*WT#6M1&uq$uS?yaW6Cj*2N zk3!FVtPo7uk8lRgBzr=f9=cT33lB>o3$E7&dkg{1i@%rIaLabUe&}8(^794PZ^NIg z1SC5LzXIWU-zxbUes9Ulk2gG)x_eoDw>^!XdU0RPmYPjdN@uQ0a#g=^m{kkPD~~Q-)uNDtm1Wm^Tm@@T(RLP zUgTKUIj7idgO2(SC|`xIS?1sDv8t=ju=ch^6_OELl(#?W-U1p>ZQeH9M0I&o{j$dE zR8Dwc`?g)nM=n}>?q=)ysf(sw2{IdBRE;2wits;>raU?wbs=&S?A1H{>_Z-Fb6k zJ+#FgQMmUNb#$#;&bk>JygNKpU$2t~71WVq@LBSclUu(;pX!PqwTWLG;_F#TjH+B1qOPgAXAG(~-WK5Avsxs&&nUPj%0 z^rH^c>(s*uKg_gmKThPw*F>%}dVG0wXifX}^bwQR(nd_`G>zIBXFs$%kK5+H^YHX( z^Un1t*n8q#RdA#2``TqY&W@#kH?Y+^GbvL=LG!S%nS}N&MZFKY?U^wWu`lt-hq>V( zqM@cKJm0S<2kW(ZOXMY5{M8Eu*?Y?g?EK7D&64oJwTI0&?o8&d^1qOSIn`@n<~8T@ zfmam74IR-G3vqhns&8)>ZG=_FKbmET%bn4$bi}f+{>uR8tOx$raxP&Eob=BL=<$qa?O5<@H+Lxh-6u%q=QMPi&i8_69LHC3=ok#* zoPDzTRO#A@ADEKmH&N48dB!?z=(zu4$SyxerEPOW`^GD=c-W935qo(FH_v?PA7h`L zNnTvH)E&O$tEV!Zym?$(F8ld?b-b>*3UtAvZ)3_SFS_T#*6_La8}uu*`%tTu(#4Pj z7Uxu$rZL`HmX_CX?c=gT_scZ$akn_1c?FYJl17fdw!NUsPd8#0=BF=v#}gwyZ+=l$ zR`V*KHH)PuV58T}nA)B8ErRvRnCj(P%nT~(xRdA4jz@QjW-dCRCcVq|e>XGnM0ESn zV?~>ipUCod4?o|ijh@GMch^13@Obz)bX$? zXw9j8SLjW8m+gaBBBxQF?=IRoHmD(?D8nluex7Jbaq`@X=>^yGTz7t$b7{2-l3iIj z_u$vg`<;8g*IwF~(DmWu_hHSazBcT>V0ffH8X<`O{^M{)?$22VQr~|12-=pNczx&c za1Xwj$2~Gwia;u$ydV$J;l(!c|w-rXixBtgFH zIYGfbL-sB|soWd3J+>U$+~L`L>7nb3QTIaMv$l>KegD+bI$zH1_xA!T?^uMZ+FGRs zL(>5FJ4U+)%&6b_9Y~vX2wZXa{*YU9KkD5Ox~-p=esn*uumuG1I=R*xn58;BQ0=uF zwaIJS)t%2lwq2vNZBg0RA93rC-aPSWNp$}^y=EooK5jd7v+h$$`JK7L#BKBB9D5^f*`4^c`_u9;Rlv(rmNz>) zZ+zzSolc#+GajIS^odz?sQK}%`NfBy-I7#=TTr!MmEKt6he^s!Q?X*0=qIj^Z3-5G%>9GAf)DJ6NoTdiur2M7? z_OJg>z&f^rSX2f*&asaq5El*wLr{?JcNiQAMZ^YydafHxfq-LsgWQ*_)h0VOJcum@ zlP?zQ3x$S)eWwS~#Zr~tVlXSG2L*xX2HAgLK_O5m1ObMIfWrd7;D8_y(`1k(OXa3+ zGT#`Euh16)4uwENk-n^CvB{F^>)7~$HRvsJnz)2EZsX|gml`k zf*xIN5zE9D@xM05L`2(+VyQ-M@s-FGDt)B?>*JOFzA9OyzW_l8(~VfUQbkHN$vLSE zt~6C6Ma%r7qdX#P;WnL7=Rotd>9l%txGmCO+^x27N4xtp$lteTh(#0W|4W}jI@1?x zFv)!pp~w&^7=rLcLqZ`)7!(Db;@fQt5Eu!9LPH>sa2O;U4D{493w)^cD+Sx3(=d${{s0F2PZd6 zO)6uzFZg!jiY10*OQgSl_l^EK{*X&&{Od+~b7+r@p;ChmWD^@fkWet_Z-|Iwo#KBJ zDnKfo;_t}m^#4t))BTpxY+=j)rI_FHYwp=1#g>~5$tJ1XF?{^*Brsd>DGrVNq2Yf3 zgin#{Eq?<=Pc;7%D7sj$N|c)|WQV)|7RljpT;~6wRSU@Yw@M}cZ!UgMXSU!}y8li1 zOQnusa=qE%QVwtXjU$;Y1pPnKD8Z2rev2TJ{>6qd*`)1pc$pL=*UB9?wwN8>2>Gp3 z82>F+{=<@v3l1U}=&#^#_#$>EN?rb@JTr?#l>zzl(aL!b~Y6dDdeg!g2(a4QSP`-}YF2K^WLpNZ-}0RE1NKayI{*#E-$Bd2o> z25r>e=k+NB}wqZ!=1CC@kL5kq8iAsg^=wsW2h|-=M&t94sjS$}d1b z1khOkAQCWArFaOJt#x!92ZzVUkx2{=8~p2jJtzPCU`hnt9CaUHJA}-`I^Z0~AAsG> z|4#>71jE>6-K6{;`qUo4SRy}FWObYnb#sO>%V2D4&!EJfK|GPp@~f}t;hZPcDq{uR z{3v^v;>AM#=&P)MamW+>IY{#hB$fzCj_q#th>x*4`kJ1;xf>Kqmg)K0o<6vn6D(1t z(`sdo<}Z=aJ$KefNPLU9y9xSrXNiEXlsX1sfNml{BO~(FVn+jm>+S+{sg})QbzjGI zUsup$A#6?$;J=>~{nsD|2)svp2blzhK}a2saWRRdpc3guG7gW3;VKjyA|ECp^1(7J zgw+G+u&zlYq-e-^Mv6p;QA+d7mb(&JAQHjfUab2U(g3T&sTf4Rhe5&WOsUpoBvVFZW8RDYhprScrk-qT}C=mN)X z;@^0r=z=Wv?;0L7?u4ntYsJO`ax{2!oLPPg@#O2>!AjMl^o z8S1|P9p@Ybj#%c=6=D(_EX5g8XfPQ}W=9xf1@vSQw8!#2!~WOU9>Cuc{EPG-wf+o_ zf9Ei{Cw6fnTMSnOrE$s0bPfg|D~MIf1U4|4&|^5Y1Zqo>3CRj645Ji5c?uc_lgiV` zuz%k5|5w02Z}RK=zx@^VCXaeU`X{n9zy8J#J`9zbSz&4I6M&m2+~9Z z6rvRg{}q;wO#j#M??(CKB$e6I&@+s&_Ft!15DJe>WI&{P(Vv8W#3c{FDgY*cVF5%I zAP2DYUy(v}I68nM0}Lw=)}7VaEDROEqZ~;X6AKXFfXIq507Nh#RbXHM$qFb~SRz0+ z0~!F!2Pg(WZ^dc=ss=DAu=ZaZ(xgBNfWrWE5n#9CSO9|uK&?0h5W@qIR!6d9ihy9N z<3YueVsI=x7hr2JBr9GEaLgFG0uKkca15J8paXm|rUy{KA}9cX6eCd(Ab`+{QCNvI zAeM~LDTqoy?AT$%A|e1O9%E;b*nmuffwM?PAd!p-R*-Rk!ipsTWEr3mVQE$}{1=BB zJeFgn@Bl3s8*8Q50KEaL1gJ59QGqomsAj+;MdoQz>Eu0FsO|DPoWSN{RzpnF@!jxL_8G=y~Ff&@tVB2#Fq27Eg&m6*kp&86 zGL}pxYZa=b9zZM&P6jK~dMwjS!2=pCmTRDJty&FMsG+E>It^B0prl&$T5O`3if0-0 zST&f+2aHKr1D>h_l9I7z9u)?dQn6Mutp|{-Fe9)KJWb3>2CxVP%?zZFvB7v+Fw4rp zVGVSa)h5M}cyzVGuE)^1X(BbiPmWYiB##79! zWHwHSXY$xRfOwnZ#Y3?rY=`N@2DY6|GT;?b4n;{J;B_pH5<^wv&2$djM#tgpbS}&0 zc#y*BTqA}_zz6eq7$r+jz-xG7CFhsO1S*)9s^nS;Y%-sL;R^^tM~1Qq&;&UkaQK>z zpwS2<7%`JzA`2i&36fv~3t4PO@dvIEnv{tg0!S(%+LQp1$P@K&s8Xs@hzy=6SgBDE zdAwM$O~)omq_Hrz0Z&vJ#5}eUMl{03Hnz!3w6P>HHjA1FH%QFN6fp@POQ}j5heR?< z4YpKz4p|gjUlz*un-JQD6%BkVM>}(l+48)5s4F^P`f#6mK7h|SV zSypH&ol#2 zzz}7s5X(peLm8>Dc198$isVW)3@8B8;}V527#5s|Q_*AS3PcZw7_Jr@BSaxmaC$_H zT7;D0lI$_bs4yDWVv0c;!jL$to=N1PjJQ-alS4*}xKJfi4g`~N2n90<2!`WON+uK! zGN?hS9zYhB0mS05I#!GfL*)^YSYjI{OhdM^^c1XxM}x6ajkrV}6JP@jJR8iRvgrti zAM^R_SR(RmqlT4G*B*AW{aWl5XoGVj0xb;zt$;S1cM3V19~2bz)FVT zi99}rt%HzsJT-xnNT88;HU?J+iAmytVtFhrhskGH_*4QP!k1D6I7qCNpQII_Au>E4 zK@s+F2q!2~1SE*a4$+7O0&Q$E!9a3+iH%wlL;&VXwEPsU5XYA)wW$IjM<$aKU=*R! zD3=hBXrUFIDB=gFiU7WX55@kns+BxBAqg&uQR=Bg2wWPbLM^fl;U2G4aDiKMIC7YT`Z=U_&P9EVnSG@da_Q6MnE)r z8CA}rAd~erXrc-MLK=uV1(Zto<=6&^SVc*q3Jg}UT9(Ar83|&I4atKW#X21^NlY`Q zK=qQOL`4#TYOql?uq3fAi9}6eCRwQ_nK;F0BG}DfDg#ICS}1l1K1@KhD2PzGL}Il-RWLYB8Jo-?A~+^JHd&pF zv`Eaq0F#k&6j@@Iq_72Obr_tQV&DXW!qCVRkPwj4ab~L^5d%k260MdLoPf@B6b(rD zR5PDuld6eqvjk@YlSnBj1=>za{S|sKW*x$=R#Pn~Gt?d?p);g*NGeyzut?$1RFj0s zKn26WI6W)bf=7WRVH_r!h5>`QT$_bWfzVU0BiS~g#+MBJb;S9Vdz`}hQ-C(tP-NlEG5}c zi9I5BH+tSyeD_q2fdjxI#~nmOC67&D8-88;bIkwo{hxsUHW-9*lzCVRM~TR>EU@C) z06=B~EIJ!V1mS^S%Wx9VEg0+HSN<$Q41ONNb69E zl#FE=XpT`>#|<2lb{5ug&Y=+ph9iyr0#wl1jyeE=%qH7dd^`~k#jB(uJdbW9Dls;J zjiq8@cove9Zi`i+uxz^`1+QhLvbmZhs$B$QVi`P^UW1HDWhiC8@?k8AivuT<$rJ;f zf>kPFl@y2Sk~m<#g~6v{Om;YkiHF2+!Lh>b0)YTxlL@tGK`d112zHCvQC3S4!PpR) zUIv%{dZrk|5=oHYL|6=7DH4-ZWF1unw>um?7^^{W_*$b}q>D|G=qXUS9zj(bsREr5 zsWK)dC7VrRWQw6%zYg)qI1G!2?-AMICU~sFDrijJc z4HA--Kqs-`90r!ar>LYU_*4pxjZ-Ma9G+dE5;+nH2FCnVw_(UBc!f>I(^wTfB2(0{ z1foi&kr8+>R8mZ;)vhptgPEyH3P)q1b9o3RTPt&{RgDrM0U{Sd*p8*S%pevRO_E>B z3P`d9`lk;5R(zb6;&{X&RIxf^vQ!_7Ow=UBXpCa9K8dPJNOZ{k>R zLW5&fpaN4Uh#o+M8DbIYRbZ2V0%ZpS3L)2Iq!1ldAGS~k;i-ixzCbT9h?D|AA|Yxm zuwW*Gil=MTP(cz~i&b!_T&~GN(xBNG@~;&=2gg?HtO5&92)EhDaEJkmqC)io9a1ep zs>L*!0LeAt5o9ckj)#~iX0gO3#IiX!B;QIA+F+LdhrPD|lj7JKhH>{0To#vMcYLM? z*)Z zqV!Sa3V|o&K#XDwS4H=DHFUO(KrkfiS}Z6gm>6EZKaDm%uLg>eWxzFuYS?}blwcU+ zY`;;#v>H?qSjq9Y6apBdhoK!s6!T-+mR57^$yrTRca(6DT|VfS-c!K8x=*hMlwW) zm7WM2Q+Qn_6X`(W%lB#0oBkhojm6k%EPtK{V9?qr&9#ni8=vM8lGpm4b_D20Xn}7(han zCP*B$QzLZarl8VbgK#-lhw-rxQ6B?OHXl<(7TXC}RP1LE%q*EG83hd08ryF4CO zFsMkF2uzDDhB_E@lT08qshA0JB5sHB0fG!o&bZbFEbno#OC=7lv|2k1)>b9*#Hp&V zQ?9p$#c?N7<2A~u9wMEL`3wQ7Tc&eaj2bNiOug0+w(6NUH$ce;$cJbmE5U$Kq8=a= zvduPP(rF7u{EU!FDGb0KL}fFP$p|Ini6dGeE{_{c2oYEZDRF(&FB0%#c+!R&aihw| zH0A@;hs0)4gsav_!#YHh^uZ@xg*HP(6Ise1HKbu23a{(WpX@#G)cx5i+3EFj43Bp(IDxWQnL%3YSPA zO4wX_fq@oOh7~N2DFA4Ji5@U2qB5`FsTPwgVJbaM9AqL!kguomG{i6_<8tlJ7$gKk zg5kK;NRC?KMx~Eovuff2N!%HtnN)tIS{(zkhhtn#h(}?CObeTYbP`L_; zM8XdGeQ~WKO&m~Z(9V;F1y*a2=fuTw18Ts$K8a8P>t$vNSPmISNYaNwG`rhnRvLk! z4zdIwl?4l^bONIiwkS|Fh_%oXOyPIxt$-6V&;xA97YHXJ22|%$O4xvx`-2=)%x^Gi z30k^Dg2_DrpgS-OY)BiH123P4BN1>DLKj;mlg4FeC<@!DX<^A0Lkwtu7IZKpjF3NO zmN1=40o@=r7!h%tLkUXVB8kQ!X4(}<$gPGYY}7#Uxd~*q%Wcv}ReTx6ZX%HdQMuip z_L?aY9E;CwrA6%&m5CvjB!EiHj>SY`jzQ$+K~bHU z!1Os`3r-i1Fr7_8axl{rTNgH14Y*z#j(cE(#o&^#B`%X46;o9*24b*)#IBqu@F4ma zyimepr}!aRz{KJRJdz+EcHsPk8*|Zs4vXqya9TA(F_YO$fqaC3maY$T4Ut4ND6lJ4 z3aUi`sE$;j5($iISU^{jDN-FN3h^mABME}EQ3dLtTEr9y$IXq(<9fCzZPc}MOmSQ% zFohv0WY(LUd|Hqb;{*kMrCmwY2@Diz2=NeQ(S${XnG7t1VGAJz-Y+MW9tcg zfOAX|gBDCH;6|cblrUK%B0I@Q(l{bgjZDXk2I2-jLr2#^VOWJI5ZDw5M=i;a!wG8z zY+S%q$4%C-LE{Ws&44Wz3Dkr(AkjRrMGISf_Tutl(F<76k}0E;)I+S)bfIA zzsau*#Puqt$Y3*&fjdzXQE16h8p?>`fusa6@g2dW9HkTOX`VunNtj7MVVLwNNtd8n z;Gn|nB?Mz|7^8SRR;rAtk*OH^WDpNwAwU_V1cj95moYqXH6(_Z3=bVQCCNdz(nIy+ z69*EHCk{Hf5~{>ypt=1laWY9G3Uwhx#LGeqYP~UxqI|a-W%$Sx8&7KBBeJ9z)3GIV zDP8T1N_|X$)WBp3j0lznh~vVj0_T$hK?5G7a_L4Bi5}K^U?9U=BZi=#Cgm`~urol{ z3u!`WAW1-cUXf8Hi_&2R6*s!5BC<)3E5ybyJ#BN~Y7s3fE_7i$G4974W*1_yIGw%EFm#<02f2P7=go!nBsI6!whT*45Ak}4H*=2G#HX2T!U2O zjFBL_AuXRc!;-6b~6VwxoQ4Iv;KP zA%a4VC8FLa9Zy(z1e1y$GMWeq7B|F{X_*N?YnTK|h%Rvixxx?vL9oEW4hJ1Jg&h@% z%@P=P*g}4WH)&9%ZLl)AAz_fxoV<9%pjJo)s({Zd=jmY3Q3WKHsLl4M$Owcpxmyr( zfIhjUiD1BuDv4n=-OW;uQAdQ+;3ZIXolJOP!Lv|rlzARxxoLZt$fP>8;bcT3(uS4aEdKJDTK_pcn zCQ;HtV8@wGkBAOqJ`-IH5ffBFAOQBBF<=BHw|FGxOr*s*5iy!j*^>^tiV~p#YUK1{ zDFM)wPv^`*2*^hX733tqVE7)ZP9{pw%|sK}_R*-x>tY#&BA19E!xOk1N_#7mOr9Un zJ7^}qhzR`jA_8n<23cV%j0YI7E|8280}28wZq=b)J5|C*eLSW}B0-T^)Cb!Wg7M?YM0QWova1uq5#rCr~PP^1ZRH~?S zLRd(~=_-gq<;X447(){bIf4cWMN9SN&!L$WNhndDnrRbgMWm3}?+{zqPN&A9@%fb+ zHj_{Dr-$z|ff2X?;{x;vN??$grXu)*G8rNw1CouYP4To5gMqm1{G>*kKoUBMG-k0I zgJCUKsn9`YT+fPo6Py4!&Lz|A1`CaZ#Dh{#0z@Ln^m-r78!!c2FewmaaMXwvwWU`% z9`{Sh0Ww__jsng_39E1)(3j&JK(-_>!vjJpEkuIfNJ+BEDl*1N0%=Ya$CO06JHjAf zK(9>1)edtQAq%)^$$`U7dT_7FW3Z^{2+7Pw6dpfUqbDm3E;^5@l&QQJ>P9>+o=hQ; zGU8k@$7mE-6C@4MiMlX;kfYOkg20z5W-!xc7FY|LGAJWRT1}zj0LRwtz z=MjZMF^%cwQNTA`7LC@1dE)#aps#cj-^`7>j5ymLaBI~L40oH^X^kFN%Q3eK^>Q&1 z(1~flF@X|+&}wE%xKxkV;$;~u0Y62f<%ooIgOJIzW3dFsWr-x>a;t&@sj#GlPPIpU za)m3+=;a|;YjCl&Iz7;`Se&@bMbqh6!6+p6CUkHt3g}G47-l*tqzK&u`r?vFY*c3) zidZ;7S5o7aDrsUS%845onsg5}WL{E*!I(@!cK~yW4v$NW8nK^3=ePw@1uH;^T4^DJ zE-5hbFfUbxY8WC|NRA3Z78NcgVp@eXsHZ7Hn9krxYokO#7Oc>qEFvlpq3O0rEtRKCP4{76n2yqtY3Q5%@y2h=z$2Hj2aPk&49(U{O^&wH%WM zVo{@Xl)((Vv%xx(WD)Sb5e-&*!ogH?60TT+OtdJ3K`#-bi@@=vFq>~sc_Th@OdK>R zSbmC%9A$W{M3Yh+A?kFD7@v@2`1lARO>M%7B&>`9ONb35e^6jXw;VD=WzwKd=XGoO z%n-~c5!p1Jm}h3`oe~8wVPRZ{lj>uzydkDlXEEbJm|~`;q7~A@63xSRDfl$4Qf*{P zQ3>o&$*c_6%(Vw85!e;*`gAZb)>9Q^kzAXIhhZjLU%_g;0MGYj(Y#$XkR1zvP3e;Atqfcf)#U;0xP~BKE9R5kA`hgqrhCYYDm^|&QEYVrfmy8#`Q*5WVGJR(7%ue5i6&G+-~%6) z3W!?3LL^S}x;`B@6cV+1h_BFJw9j>3S4Du*DF+=r7vOiD=a(no;5hAnm)?L0oF zGfC+>IlvAVTSJ#?p%@XOg^3;}p7sSqfIG#I#9*9<0OOXHYKx0F3aeAD)hSJwU1Yb} zxk*tlo}eiGZjR0%)5RrWHZZh7G$+v$7c-TFAWULLv`IOMmCpi#TCFXi)mhDe3PdG< zO{%=%6fag|0Ka2g+=Hu#Y_2Md5fWArl$0e*P*{}IP#geN0JWrJunhP5;3V+#q^V7k zYV?}qKo@X_$RTr5!VyaZJcre$HAqaTL&#=0H3Esy=L7*tDyfh~kw)S`cgg<|(9zux z4yX)Jq?tN{IBj!q+g%u$ZxC5jPPUkdsRVkr2@0shi6qy=aL1()5m#tb$4MYqP$@uF z!YJ&O2Es5wtCA}G2^A-x0OqTRJB0YyY0FZ~?NaCwIa!wwpb=?6L$FZY;i#P8)KDNq zYvP0xaY9f9VkL|LlT)X4$>JQL*&B=}-5e>0r3a>Bqf~F_iM%3DnlBU7n93Fg?sl_6 z;T7OqlG;K5%DDkSf+3?s8KWi*aZ<#{6f+_bM3I#?Wflxll7=%C1>OAv!XoI(ku zH7SE%NY;|{nwZHchxB%r(IO#hT*3rI=DW=*LD0oiGvs8o23Es5E7!qc_<(fi2Sy%< z73VPYb~n#RO2*`5wkDnyML;lz3G*Wc6II|0kpQ>C#denfc(5fZUC_ugFf9Cd*r|a- z0-G3>`hac*OHB$O0uW)b2#bc@UL7n1Oq#6c#q-gI$0x>wz+)Fpip3&c2xby(I)YLf z_J(;ngk`sd4Eh*39^+U9bh1dIj*HnUz1^cB5rCU7VzFyt2BVND4#oBMcWgAE76}X< zG907YfCbY85L%-X>pc$4CgccdDGgWeNm-ImomayF2J-;KrUm`Laez3i zok?IY3xKnWpuvf3cH9s}qhTQOrtwf322vHw79|uIjVCaPJYhAPpwIymO57B6;*Qi0 z9TLR2Y#r0<1NtP4OOkAw%KOZ9O>1Sd1NzVxDyiJ`b5L}sQ0Orz5jgxPwg zFp4ol2BVl9Gb?pKTqE-cOgbM2TE9s|5K4iG*MTSXGMZkZV#MSIEAUpU)k@JjfK&p* z2O$Q8Dsw?%jy1%Ec}xbFS7#W}>%3088&EN`*B+n*{dg3x+_+E(LBM0E(NS2`pd3W& z2*ebp*Nfum03N+tZ*XczDw7i7LvevUL9p1^5{pyD@vwrSC?E_WaVY4;^m;mJ2frd#z8 z=Cemt)C7TyQK>8$Q!hXmRC+jUaq(;>7Lg+lEA>c-l#olAPJepHb~@K+mGMbBF~$!g zp@>@Ov|w;D3E?(#gc+oeH8=tCM08fKgh(a1v~nk36=BCEY?TO-Q!opOuH}T>kvNG@ zPrH!7Ujd4b?jooup}5Uu!o?b)SmzOX4Hk`1&(aJ0#(*@yQqh6}7+7#EkOUz*c|a)T z2_P3PLo~#ImjbltAZ85Y?-ac`DiE6W^n{cYw8tGDQ!pxxT5(s*gNl_dqTB^VLC}U% zmlS~`R7w@u0{D;C4+H;~A;?66GDv6FD+wyDfo4zS1C#{#8lE`GF@ufe0|APhh*oEp z1SC=l)#m{IKBiM(hvW%dBBU_{Mu8d&2)PoDz`+)aLo&eR-{~{?noT~y4?4~tKM^be zU}A{?3h5*paG1u|hO7#S*&&N*f`p*k8l1!0qgs~L>GqNE{2`mbafGm$z&FE6t$>ygz! zRnkXP>a?l^F=UZhbtGp*rLYmAQXv&MjpI6Jh!xi%cD7!li%=5@otQ%h;ZsC~HTlj_ z7zTy}#2BHf-3}JQ5dk+3U+LHL0|X}U4)eSLrZ&kp@I}-}n5j;<4SbcKnn)58F4TiT zFe@OdN^{IS>%PtLW?k_QeeOWp+&7xIZ5SVYF)Ol&|(P)SwO5~3KCq* zsWNll#oGwIF_BE_CF*EAw?`LC>ciToO&7JuC@i-;9GAjikx@1X3${6Y8Z!i(Qz8k2 zn_glDi2I4rh*UR3CPEfj+AvOZ$_ZKqFg7vxVTF_wNqT+05L3yecq6(*#9}s+G$1Gq z)#4#P$4aA{tXL$jLTCmJu$j0;K$eTKfj;aeDpbZafpr;}WK&qiV0j`W3pc4WTbvf) z5-<`HdY4#73530zpv_9NfNi9wp?Cs%>q0!AZjrmZOoDo zn?s-w?RJLShqLHOqZyGT+(|F&R9c840~s7BvB(1=YtTdr(-lU#F5&RQRGm}HFzJ|j zT_lnSi^T#u-=;{%&LLES+~p7;K^xPF+Xc1+Vo`+t(i#_3rbqI72rQRgkvSNPLZq;q zEYd4PVKFYGxFZ&RM5&YT17-)x;|2oW7*mzdxa4kc*ry~3wQ`FvX-p=gI-=O;buyzM znkK#VxJIfWsR_{CQn8)scGE+22GCJVwn)Mkgb& zVKdR{#+<~sh`?rA4E_))l%7L3h{jX8lOnN&A2rI8R0SA842Zi55m3WfOgcR(Ve)j$ z1TExZhyvPJT&oi4)qWw(&32i|Ni8GEQySH7;M{)40^(YELd|s&rBu3sYM|nXhl&Dg zKR3c*!I6MK?6GM`8l@>gP!pIO2Z>^|X*_1TFv<&9k_s)wDGDpX))=tI3an}M7LPd` z8Z*sJRS492y_FD4+B8nKlot_${V&jQJ%y#}5AyXVpYj*wy$BxlGL>4?43tt6BWg=f zf@-B3*nS_B@*k=917YHgfr5U@FL5cMQgN*oIlLslDu!?nPgpdgGe9JW}DL6R}FLXArTBWAnV zq)SBCk;69Fq&J0`ESgHoQZPj>sW`n; zU^j@)67y^kFGAzU>@*z@PvRI=rE>CvxPuTEs{ClkYw&`A3y(Re1F_6*iGUN0#;HLB zS4vGn2gHR1y%|;0F#5q7J z*Cog-ttPF}vn@e4pDYGig5UMt@>($eg$0*CDkBop=QsEIyTV_$Yfnrc(ERw|X1es_ z^PK6kp`SbenmY3;m$w!BLSfj4pkiKjB;vHSMXWTE6{XQKSug|3#27R<6QVGfnG}R& zW!k7#8ca?P?Bli{y7&$*uy03Fr+fii@S!Xl08Jv%z-f0F%_LL6`CJ+UVr9ZKI+lsR z5C+3G3W&b7=64u?F4X)tpfwHB z=o|T`~Gvb&fY(1q|!gO93(IRyqt(Gnp_2j1i_$ zGa(ieJW=RmGD@bvRua^n_?zaRg6{kk0zs+V6jUmliD67?CJbU@G9dZb18ISMSf!^)zn$zgfNXntr?`3-5cRcB}oW{L240@TEXWQ0Dhm%_gYaKCjoMrpn%RJXbM$7s_<)MO`&DF3SQ9WPqLH3 zyB~Zn#p?=~LjK16RoN##oc?yIUZF*N-?mWMAGXDu9#jPbsfq|ffbb9z@I|*H0ul=0 zApM!&?m;tnDNae`%D}N_ofhPg2HAzA#29J~fzTBqVE8D=9AZNeKo@b?1N&^0pYzs^}isq{j0^Xzh@9&U;5uaDA4{}&EQ{RDSuw7_^-ywzciF@9;6QyehWqm4g(<$A?}X^KE;*) zWi}l!JYidV>N5)1i)Qms432oh8R^ew~hHa*zcxAcx~Aq}Mu==$|yK0T~G-(rp{dhO+3S)W4L8DP8i> zg1xKf$R>j%%pX;Bd@LQls~GV)!`WgV;y^3Ki3o*z?$ ze@Y|(iGtf=;4}GXn%eZKhg7dWdhwy>ACUe-6#*~|=5HVo>WQLZCju+b2$~fRBZUFI zul2{kehVm5mh#FL29;mukHH9FuhWyre&3^vRF?|Fcvs=~p#TDw%CM{r11e_ECR4LW zz|To30P*qL--nW#TLFxq*}oY?e(CQw1bM#${*>V~J3s$=!FN9t|GMd?_tS?>{3kcX zJ8b%}y8nkUqhL}}llVEb$^@EgeeK0hEAAPnFG z+Wi%Bkp`23QW(OY$B07RC=B2)k_bbZU}OOIASqq|=P%QVe|MbtXL*Q9_YNEWVdjyB zkok#;{PP&0(&Zy%!78Sycs@t@HQ7xO*fiFDywvX)M!xeq#Y;ba`}CDC2%`C@L;hEw&TquFKTkvc4H4%zqy6urI8^9g zfi@h!CqH_r0D1qTvF6u<{qI8>8n_bbpJ!8Y;E0NN3-g)(Xteq5aR1*RPFhj^*oN}n zAS3vd$)&vw0rrvn0B>*`ng`f6QsIfj{FvnruRe%#srup6 zC(d}4@LYo6ojt(>|sX+M5PerFmM3n zx6Go0gKu;I^8G^wI1k5ws9DSmGKEQ@W&vO-82G$XCh-h1cn$-=zIT5W+`$;iAX8Jl z1b6U)(**YXx775Fx$hbfP1-OTDCj8BT<}+_yB{vojThA$+WG2}E8LBg>yq)kA-Cs( zwtQDETy$=7z@?YPFWCp4p)m$l+tWxm^6Z0GlQuox^&q#&g)i2OpSdZ|?|u@yp4+bX ztDJ3{zF5=c+7Bnj^{$WR(I2;4rN3SW7H=4Tg1ANR8!@Tj>Jx1r*RRpJdl8Bg4H_dkk-V>hYY? zg07a1!-{sCQoG259(nkQY?Yy{#XNWWT;|2Bp*2q#Uo5ZCyvX>SJqK8Bw>!ygQ)}Mv z9cMJ+dCMX{YAWZn4gaXPdw5`j*3VnfzFn}b|7KkoC%3y@+;j7zR?1_2u3JvdBK2ur zsaUDJw#Ab5A4XcVevp(L@ho7W@_FA)Jao27pTu{Xz4HlmW<8wKAhLc|&Vp;^t}pst zc&@*Cq~ylEr?2I;`T5}DyDjGreKpzFJv6CihigC18`380u(wfCTeHKsu-#kDnfWMe z%c@bcmid?5c;8EJd)(vK|JmKmzP04@=gjBVhK*^kXu_G3dm5LSImAn%JXCZ))4uKC zeG9(3_TB4Q?2F`PZ6&9xbm-e?daY!?HZzO6SS?krXYo5#tL zUN~%dZQ>E_(0YS7V+M>`+q6#qud&(8>2&tYquhqt~d zzj9)q4)aHJYAG^QEy`auw2gHrZ|L=E<21a$D@R@5>h+pQ%c@Q~?yJA0U6GY$L&I(6 zL02nynvCmr`o{dmBhW6odJC>kB=sX0_uf0$V%dnp6Sr52uHU@2^Jw`M>O9Zr)`OZ} zycpT}m15$yz0Yph#!`Zp`<2UPsG3zTl}TwErc6{6X;5}^i_dy~BR~9oi+%$ZQ=hlr zi3m4WD}QchUcF@-OLo&^SGwL@+30F1=77aD&rO5xj9gZ)Z5zw){)Y9Hp4;Zh>OPrU z&aBopV8ywc!nD#g#7nm~Z}empKX2u(%$K#xy{P;B8%LX-T`djoEW07ddb54^ipeV% zSD98}h7vnk-P|^=hl`{=pZm5*?vfG{eoIg&De{n_EbZHaM2m8;gHxN6 z2$CoXwc*qSwIA-lPSKfnHG#4PHaU1rLimhV?AWUf9VShhC)&CE$^ERaZ0mk%vq{xF zbmDFAoW@LU(^5ss@sBgw_iA4ATCuU(*#H?9?BAemBQdf6EZ8(-PJ#PekC zb;7zm6DKskI=znhVD0s^X~Wj3&QET3Y38sJ(>qUWcF{hwM`?6}PCU8DwWlqQ9)0$W ztO%+4q;C6fG@tGnOyO6reSh%J#fp>}yPdTjuQc>I%Q3A;e2)F0+TcNXC$^JQ*d|K3dlSx+bJyZ_SAZcfcF`ZN)L zPDT0G=FFWVAc@pPDmAaNP2`*a&RWH7SJ9t!; z(H);3Za%M8>we!&=c+p7H3`>QTc%6D7vGjXoIxw~x@gb-RVNlZ3RgT;WaU?}L>KfUVR&A|$sqVufZ3cAPI;Kp=-DQd&5tz!sK#Hz|ChpqeS&bEq|nm>xKZ+*V{gT9rwgdSRZG}>6McfH;XE{trrb5n~^Wi2J# zeJeK_pV8FQR9B@=nHyzZ_piE@rtULO8E!nVN@9CwYpZ1=PO;aE>or%5sV*Maw5FzM zt4S;R=)|tZU7B}jzM;{WJ#B45yq39RSLNcSxf$J>RUZ9?YHZ8q)s>QZe9mbFOR}b8 zqGN(PTT^kK@0jVkiEF1?lpARemCS5s;$srxgkruOV%V}`98Hu5p;`kF&m4*kSf;_Ui%eXDWLTl-q~7}t0lHm>Nn zk>APm{^Qk;PyNpOo$?sT)!YTUPP<+n&ss42(A-0@X@{nEqrJWQYS8VaYX>J+zi|Ds z?RJOTW9m$jXgle(C;KMvnS5>X4ce|14omqTN?5L0Zv4=dG;Y%U{W`4K z@}aEhix%ITn|UOA*0}{879sPNo9r_c%MX6mWpq|2CVN%qRoWOwDJ7bS-Ik~yOwU&5 zF3O#?Nw}#~@4cH3XPoIils#q3yy-)xZ-S@6GcO@czROu~r1eb8%yv5=WMy#3qwFi4 znlBwZRXkcee2-jv>ezW*_qB&s9ID{H?r2V1Kwr0O#?rH9^FqOiZ&};g@9r@(G37a- ze21Z?p;K#|tI@5^y*Ap+J8c@8TbWCmyen=meX;G#_Q~!pNY7mZU00Ch2j`r-{==gA znHQp)?)7Xpxy#aXHP$KC9ePsfN#mEzUy@6A7!)70q0-Y+;b_Zs{d*p-dgtb))dwF9 zyHdKvmo1hZ70Vcp_^>Bsaxjk{vG z^J2gJSbSWp9?7RYFk0P&&IjrEIm5 zkrLas6y36}Z$sjb-I{hjR-+i_6*oGdeOY>iE}y>$)yir^TiE<=VzoZrD;_J6Y31{{ z+t-Ok?*4JNaOm(F(i$$_7^YW{LVU}STb2`*$SoiZUn?~{Z zPk%fo9dzaH<#JcET`wlH0)oqJ8*t$X8hV?I0c{}*Ct@E$R7Uy+a z6T4R8ii?~4>ZM2yr?%KW1Soy`g&ye0{_1FIU~0dS=&8CpTU2_C8v4c<~*jvl~>ex4!r8rz-a% zws!}7_R_*_hwjX{y>^qmcemcWd!k1Tys!c zV>o;5imN|PUA%Ph`F(vREb01a4L<*;4KH8mCoHfpW_4-Tb862G_XfTmexkv;Y2&-y z?d81n!vpVzTY=@T$6r}AVq?jkH(qpkNj(2#ZO>~X-cGGsd}yf`_p>&B`L^rX4!3%q ze|@C%{K{Rw*q?-6J6?ZsuMF7K>dnfhX`J77eDT$~?N%`f9nW#mbP1lpS95$R~zaNa)Vj<_ktt@cTbth|CXq#ee7!X@!)m zf1OPxv#?Qy%A`}X=qZ~F3Cg1WIhzcPl8@tm+hqQ>$^31T`9EZnAyZPu(s!no|4@<$ zjL825V`Tm3kCB>UB874FpYS(iG00RFltO;+zu=Ed28%+=qSG^|REV6#_;aj{OwIR- z{Oxb}+u!iFzv2Iqzky6IL@(F~?oVk*85By2Qfh!VAruC_LNb|=QtdQEIU0s-a2U== zOR7pPh~5gIc-RR}8MY_#Qa%gZhT@&N5H+0i(b-O2fcB*XmzQ;-QquBmsv!Sla0WT$ z$V@pQQ<@nUfCZ_zKKM7t^g_B8JCw@U1=9DB$wYS4ZcJrX&7iPopjkkapD{H9VnM0? z=GV&vuF#Y-)gA)6Cs6u);e588Nd_uvCY3}5?oSF3&Pg;1&_Kc4)IlFm2#8v$KdF*b z)FTmGlA}`!2q1{Ma0ow940`HB*uGS{F%odj#?##))4&CHz)$KGWk8ht2SWynlpb9Q zWI^DWA6z^4uFni6t?+ltVJUK-mc$G!SQg|&6ZHE|CsHIDm;b5*vwq^`=S zZJpF(i}LF0+81j+<>aiL-Fne4-fz+S?wdK;k8dqr{Iu(a>SuOF{uBcvsdpltbMosoQ9JdFSTC!toWtgJ4x8h{VhtoewkgY&8{s^ z9$lnPzd2@bMNJN`&6~TScKh8k?2PBTJ=JRYE_LM)LiH5>(yrLXndqx&TedUOI1_N*SxBYb0qzHce}Xb>+3^md|i$=ym8Z& zHGUd$ZU^~tpQ?Ffc2(Wcq*OC^v$@TFD7B!1rlPO*E5)&#nIb!7(0ca9+08ZB*vg;F z&(&|$aE<$Fmuh@mvbEAS`$p~ij>!`n zVbPn^;g%95ZG$^q)RygqOx~^7-T3-w+7LmXP3^vZ5EI|$mg?8n_if3MvNboZa;hxp z*X&}e(ue9UomF@H*?Rb-TWwbqDY@tEjuHpEjK-_)Zr`F|#j{_PtkQJQw~?jYPZybU zPjI=eqwLRPn;eQb_HdeBci2h|xV)fy^EE^EPpmtuRJpQ*g&nIm4S#(H9yzN)wOXf+ z_IWaDMV(XlPROuq!3jdWRgdpSbBMi@GMec;|w>AvW_Akx%+i(5Q zVrHpjN4qzi7Rgm#=nf4YA#bvYMU!1Ewv>Z}-_p92I~rU!{iXBqz-Et6 zLYXVS-*j^4k=A#~&XKDnDpB`gN7_}pUF!A2a^WqHFO?MM?$Fw^OGH+!cywHnX>%Dj zj^5xeK`b@=OK(Z6`;)abcXoKRdQD!vLBro%H$;zIdx>XUZ_mb?<}NQ%mBH`iAApx` zdHUsS$w*?2-Kf8N!xALMljE!WOx+jp!xz^^7j0Njk@)4v{W%REKf}7%ZyY!vov=9c z=I-){u|X*B>8XZ0>a>hEUK}rJ>?+MTS!Vo}Rx{?zym|ezdRcRpj4C^sa=MtDvww3v z(yL_`A3maX-dptQu*qd>W!55{cyeH5@_yHQ@e?be*UFV{M`*y^Ri;v(ssl&nl-OT_ zJLlo6=Ucaqdi>^1qegGu+~AgbPCU{<@b>2$MMu=A@CD^{?WrYejqcsN?&Z0SO6~b> z^J-XI@ha`B;5gc*Qg86$Jvv={T<0_z$!<#7U3uYQPMII0xto66+e%tyWG16gdDGSY z&4EL{_yV}`#BDWBRnT~*=#R$Y-e~0mZn^kH*7GvCl{!tW_H`TnL$$xg@GjXUhhId` z-FBWlxqjaKwr0)d*`wm)za2K?uwdm|O-D&M0%Gxy)~H53k0~n=Qqg8Y)E1dXBDk znB20+^%-lv?ePp+KCjQqaX+70VOi6kPdFl~Rrzu7=odAASk)?a?B`9YHB$`sEPGBl z^S9{kL36j%X)*eCgJpA+rt>Y1)Y{UzTJ!Y>7kY1W>%8ez-C;TXj#X`%yE1T%@p#0c z?m2Z&KV|PNbDTI|c<;*%ou1wKiI_R1F*DL>#fhPhL!D<%+x6q#Sq((Dip}oYa(v4+ z57^3#lI7N^8nwIxkMtE43$4->kuCQ}(s~{)HLlCNYEiCoq_3oSn?`o{Xz_}zH(=j% zRW!^iQ}6bzx)ql4Dz>dur%jOJ-}ZI+!$)tHeON|p%pLZETW@|1^mU^*oXi&|M|Bs? zY06#V8@tgry?42t56evZ%u#)?Z|1?`drCOkv}y~@x2s;{a7`!sy(l%?lyMaq+~oQK ze($d-#~a^;4wS#7%3a7Y70s%!zfVifiD@zNs@AI{xocOp@I^=6X|pWLP`&L8YDZy- z;?^gFzN*=`+3AU<38tO1o8DM^ZSA!+${Aap&wN7cf2fS9-S4noW@~ z$N8p}Fh-7+xz~NOXX@9T$9Tr9pVn^FP3?m&54teRcKLix)e{YiEgksfz~VDjD_hQF zibGfC^t{O`eqrN``?~uhUkrXrzCCNxpdP|+IP))W?c4t8nPuUHFXjhc&R_lW=hZij zrs*jgGnF$QEbac{dews)&d!~!#h+$@HR`@M(pY4=-M$>ylEvQqio0Ko}7DJ zE@^a>F}EG+>6_EG_?2GO8ZX;kyJ?*TNLjNwuhj9i6Du~UJnG1zBl7PIG{v*+@rr|Y z-ZG7wx;G0eJ}qmGInrcp+2K2y92KqYX=3l*wR88bmOqXf)nsCoF=F1#<80rSY2_;K z|Ex#Qjs{BBDeWG1q)atDGNx>@^<>=qP1F98g%wwpn?9k{8Sc4d3+wOqZ);J$M?e4Gk&p4HPYJXnuda`TiqssGoetG=mXQtV034=;^`%bK{gOA@= z@l^8Iv>$>aMm)TBLvv$DmYu$QHmmHiNjKeupxv@D#-E8Pl4lcig0Eg4@wS;fcxOh{?|DZ%_T_cgYoBhLubFmG7hBCQD{Y%Mq|4m_ zltl|)G`o2rK%PUUUQmC-N?zQf$&0*LS9U37CF`jZZU< z_I~|{cgfZjb=^UaK^M#uEa^Lfu2jFm}T_|70} z|BDrM@7RWw(bDQp$ojE*n@)bzHX*cRe#b*{Nv9Lm=6@%TYv{kXgG zb=n?NXCJvgM!nTjF&=I{Z`LLUO6*PkvD|X@ckCZ8?B4gqScd)j{g=(hjQPRc^7Oub z%NmvDn*IJC8c(cT=Ij+~i`+GyM@@!+`%kBmUX$0~t780RtI|@oR))R#ceAqY*Lkx0 z&JEJInwRG%9`P)rl&u+;+DmD59_`Ls<;>XBIr2)EJyL!}dBF037J5AXvzlkugh-p$ z`x4I<&uE?fqSzn>@^syf#P>DsoH_p}kG$~FR-eZ~9`V&S%O0djren|E8FRJ@o@|}e zf43~V!;8a<58%3m1CqBdb?dF`da+#J4wO|(-S_&f@;4kZXzq#X!`Cj&_@SJgJAXx4 ze?6YX-23Ratj|W(x2Q%1Gg_4BigSA);XjjUilaUy&Bo<4rvsoZnB z&$KP|^4ZOMO%`m#7HQqBCY5?IZ}h8yTT3xso<0BdXFb;5UKg;lTJO@#J2vas_J*r3 zzuGw?`NVUutLN#kdE9cb=fctzl|4)Zcf;u69ev05U2u2J*$tOkJX>*-JH-1ox1a6v z19APDhVc9W6D;BZy&5`(u}i9IJ-_rn&%3o? z{FEt6lFvqLJ94W=$&Di~F%K-2%-#^UZ@3GM87yEzlLxfw_{$ZJll8mzucKRQGguRjsb-sakd4t5yNixbqd* z%~oo-gi>m3V4~a;b#B>tXhs`8M0nKebgPP7?ZVi}7>4}sXEcmc2WLLhFhbFE3+hj$ zgUUwmxk-}f3^6Myp4~>EJ=OqscWpSZB&go6>+-0WI20f|?R|J-+x^AM{jSeu-`e#< zlf##hI1R3gr>BKV7SG?}mSAW(s~thw z-+!L;grxZ?o{$3AH(gB+DN(Fyq0c}m?0K|cVa{~6y9t`Ts~XyU@bk0E z00tdPqi{IGS9A+QCQ&rh&wdnZMAd@h7^IW=5D?I~ggAga#mJ6Y#}Y`M=T}hI zlLdCy$%^+htg2GFu$D4i#^C&j+}4tcGwi$xJZ5ND&+>`sMIArE=MUmxtS!aG!~D*s z;H#DC5GP}BJ$x0;9INlY{vJ!J4EO!ja%$hFSIJIDma)X1-aSdJ(T*&U)lXeuWMv@a zl;{}W^rtTEF{x2PvUSo8vJHj?g`p?x_<~;yvMR_imc_(9=fxFAndH+x?h=_{vNN>b z&r))v`p`_LSU&pUwHb$>G2bjp?Y$b}x_Zu(t z^(w);d(acRCBWU9^z7y9{vI41sres@*Y7W$aeCf79Jg8cFkZ?p^5k6|)-wj(R~@q& zje3n>U9ZDr%j)Llq9V!2A%h(4@^PP*_up{XzaI}2l&PUQv9YLCshw^K!Pb?&xkm8b z+6?Ar^Ja<5LFGESLfTQb?f@bPE&pGw9C!u)Vgv9e^u{Cd7wCbzSIEy3BCPt3hlJyEzM>~{?s=BFX8ROSxm{?yzwuS$m+ zN7A1o^Q9h^Z$P(s_E`!uUJA?plkeB6m)M=SjS7v)Jd`$nP|p)Yp8Y)l*!2w8|PU}Td1l|p!;PVOfrlH`Pasa+~ zh?rrhj?58r)O)u7hXyuSs+JL$-ZKJDg9Cwy;s>R z^IMXSmBq`-jyog@+V7#gWcb>OLjLsyUOiNqo4W@^EDrZ*^+@#lNyg{4PmV-kxmuHf zO&_D1aJee?d&9()eQ+bx$%ZnOz6gj)a;Dg9SMEgsffpA*VE4CTjx1h9Nx1+^ie_KO48g1%})(l)ceJncR2O?u0#=Ww5|6&sg6%7 zRI-Md!uf#FDHh0XaZycUMJ(hwZ3Ddzv3)3upwvW~nyO;7@+cdUjmGeSqxv>?3V}Nd zlE;KL*mEtuZftguKfEvAHJEj<_eA^2Wx&5za5KxV4oWm=J$U>myj$5(s#Z{BJv2&VvCfuL;MV3U7#M(j9+piDxzMLuEg)8z=jv}= z0G=6iEA()FFibCfANekln^Enrxh>)g$1y$mnxbBCu|nuzlaO zS@q)uO9s|~*3}o;F=S|t$Ah7uL~Hxz2hK>y-*i2KKSI=<6|vk!HjgIh^MKTzPE$8% zYyoVfLaw=#();q?EDdlCsipn8E(r31^ zg1R(~DtEi}Uv37?P-{A^VBp!+cOgym?Yb(?+dRTw>0mykmRA5gsi?QewkO`F;v1*# zR^S>X7S=3%^?`R$D57Mh^9$BJGBn1Yz27|@{FV?su$8!HRDgVwT(1n7mb-k%$GS$7 zkVK;KppBmNZebNWRNKY3dA6E4?>U*N#RLJa?baA3gPamsNBU!00`RO=aFoxZ@*Gob zy>z0_CqvaUYm`b5X;LMKpU9ghVO)HSB!x_Z6=JD!Ed!(c<{=*sWTm3w+rDIZMR1x; zZu&3QSo6xh%>5yPfz8sL_qN)ZbgKr-Dst}ryp5(Ay$5%jaDwspQwt>Pz_0{@w z#SK4+_Y;P2suI9;*s9UP0_dLlYg1>d2%&qYFDfqYvxEkm+2HPE)uP#+YUHWDzqvsU zE8IWJe!xz2PMo6SO9WGU(h#DG&QX~u(>j_prTe)$;`p!(%+72T?y%Ro5QK;A32{(y zjxXoWVxd#d(IOP@D?iSty;)Tjg4#a}SvzC2LBf=IQ%_y9Y8u?aC~P{sxdb`;-_4~V+k9?N zHFEJKFW=nu<|rpQa8bWgBRV%Cste&!ymF3$>uxV79}SfdO7T(6lNUZCm3fd)12>#{)1miCu=uRs>gVIn~GmhfJS`! zBUq`#=b$4bMoY2ETbV(O`Xr^wJ)Dc(|Gv7M*V8PuQ2-ik3Pdi;Ar8u#l`Z*3$n*r) zwLQ}JE!ya(?Iz(A9o~ROsuff$n6Med4!h$#!bPgBrRG4PIC2w3_z)eBkjpGM9eoXD zd6KbP{1)u|dSW64Dj_dPc?P%Lu=Ex!lHZo&8Xiwu|DiC+F)oXhaq@ zL|xlY3$v;|7^4c0pqxl_!4g!0YL0H{Xh?kS9%|w)*L@~IwG}#;7fJ|Cp`P#2mcC!w z%i9PO^(g&R8ii(YOI*C-*8Dj0-saG|oo}&FvOS;f=wR$4;VJR)Qn)y>&l9|~s`UD9 z4RuWgT#Wt>|L}1=Jslm>Eq{8)6t(S_skh>|;4cibSdRok_$mSi_Q;pK0?`t<-DxDw zBwP00J$Q8;>^}oSsUal1ED97a-ZRMM^`02hr|Ekg@p@O#r0yb;r{Ze55sA(E<<>lq z(h_2HGCkZ4d0igUy6&A+`DV-WdkfVM!74AEw``i$GDQZgS)7^g=fy86CtL6NB+kAs zSe`qVA0uzM-e`MX9T`1g=14nxp@?rMD4z2Uu_67B`)KOqCd}WWLly|)n|zfO%dB`X z>m!b97C@t=GLkP_*8;X2tB)oF+x5H+vrE1pFSjJ+ybc&)wM=L2#$p;9Qo2J4jY@wk z1#w!gcuf#xTddIFe_0Vq;eVo)mE|-wUi_U_{^`2tKdZJvqQ5z1 z1b6*gw?%OF|Fd!{!t)p9_E+iul~v~F=RxSuzpbSIl~qpDa8oC8sX59mU?bvyp;(ZC> z!Pn7g8`Lq0TRZ7Q4{dZlu!bqj^{b~F&<(a3@ska$T=LTbgK*SZjVuHsJnG|x0 z#JlDwP^=?-Yj~kGbTtcV&)ew$l?YcMuqvcoCc_TIvN%Mv?n-2hgSfUdS=UJ5|1yQJ}wPl?-){Nb2zH zoUGcPBe`TAPAS?>PYg_UN|a3Ev20(*@FL7pS`<6=yXN>}{zZ{QjU$tzpP7}(O^I!b zm^zqmLzVhqg4KXV0@NmPU4LQ~+1z{@U>=S{S)TOe;QGyH`8yf@+kC&C$9-*f&*m`F z3zbAQzxsM%Gn2th-3B`oKe@3z4t`zmq?^oumu2QH z_l?Rj_ff~zoC$u0%i?%vvvWw(74+^Hdh5ozMu z^T@c}cP<)!k_u=vz&v6ik#yJe=OT}PUam(i;i!D_n0k7~rJ-55sPqU6dNot%|NVLU zEu*)+Q}+uB6B-;Yws$r66QTu3xHChaisK%jkx9J~esM;USP<~(ZBb#RGz*upG0Ka? zHWHX87S)?=t%bB3ibUT+Tl?wp2zd-TNa{eEl(3EmxM`fcYK*zxWz#bxYQ~?F0}aa# zO zU$sbVk)&5fp>oqa{&tlp-=6iZB)qP#@S)EH$^JGW(be+&RF85=^w&32DS#s@dP zlF>uCSKDwIa;%5RQm75v0dmQl!HGHFhG zM%_Wj6R>yCwJcR(qesa`DJ1V{T$9AdC0$UY;h+K}ZwI zOIWj0za;%!q2zRVVlz4}wqwNyI^AW13J-?lr_9cGEbNoGQ%l8Sw%~T~^<+u$rG<`# zzc4Fe2b=gv$N{gSK&%5Ysr%=I=sbsgQTiS?V28=K_evM-%Usx(WCj`K zS^}fVP)m0(>xJ($mmRd$4RY=8n%|uW+WFqdCS?0F^y*PBe&0t``95C%uG{IZKr5+< zRYaAN=G;3z?cKsF0)2ig+{eN?4V>R+?0VGn1$nye@&Xg8%@P(gvYw2Tdy>(`(p%|o zi8SmbS5rxMiz$Y6>HBv%ekOX6waoDln0!7KYy0CkRyr3?VYfgPLiI5Z{XuZw;FuV_ zTKgk*xh$-Km2WdLu6^-D&vAaF(S^=3FFcX->{(?Zx%zzAZg}4&1FOeY(DeJNU|i}; zxJ@r!xZUb0#R$IM+bo3^8=NmYz(~!GQZ_wM6GU5+NTA7@#m-fX=?SU-7d=^j`pI(P zP#YrMnRp_XlHSVrITCC6nth)Co|5n>hxGgglmiMs6Pb{k65`G&^hSXwMIaiBUcl zoN8yCYo#xr(Gq5A%_*C~G>*i)kvSH(k$%JW{?>tRII4=n(Vee=laU*p)bptu`B5`r zw_3tgz6TYGk)u@1xVJ9>R7^fLhT1e{z zWxnFIXd^4fM|}!=ajQ5-=CfOT5AoAR`*G7wXY_+GHATKAWt3{KU+wNvwmk?`C>I#F zVw8HCZBkZTLO3bP%Hv}EP)wgtL$fn3mx1aX(HIT6fQ*^^QrMR}v4^?mj`1@!=3!45 zH*%SGjJh`INNtvm>dsA!ynI_^*E`O6PPvt7{E{lQhBf*?57^@3h-cI-^f4-5uQR0j z-dgFrRpK$gALoQbebr0pO>zE zIPN=r|Bq-vkx^u<_+Ia>bg9W%-MOy|QH5}xB=NY^I$`<6^)Ci5;Y9eb{d&mf7EDfC zJ5RbJ!2WA}Od`J%N~3k9)#o9Py?ni&$@Xlf8sL-Mp5eSozuL4?`c5>&pV+@MI{pNo z`tSv^cq$gtu)cTUz^f(NvEWBZZ&oNO+DD2C`(9%Wm4kW*UU0l1Sy`I)`O@Dvax^7O zw4ovIiLWB;4{dZh*{x%Zr<|h6y{CEM^)PHp6fcG1TES!=gP4Wgjw2pM{H73oUm%dKW3>>$3LQXLV}29jD20xqC< zBqp9b0yiVyf9rfHO z^3-4F;vNyyV_IMW*VB}uh>sSU;^p`9PUSyP^=HTY=&_uH)0MG*E8w8Px7$u^qW6`3 z&M&rQJ}Z=!LH#O_X_9v9?qWuNX~DV9FPAHkrm6-joprjMZKYagF!sCP0j$SDFZTEny9$CYcP_fF*Sp_NzD=wUpeP-C z(z~!HpG}hZq#8#PKcsiE>l4aoRSZJxHeuoZ(TRzCvT{Gy;!a6zq~Ska5+6;R&|d9HWJ=E zM&Ql3u^)4$)>ZOtnkFPy&~lGxdbKm-Ii^3@#{8PGWu#e`9FmY7VZFCJ#_a4!-f!9C zUMI-LpB#ZIRHMtD-+*i~MEetwAwA-bq|#2Suyi9%W=8J?%|q6!fjrOy3!Ew~^tcNF>T*hZUz;~UF7bEg z&x9Jezvyhu0n114-}x(8HR-{EqPd8RD}qF=NN3eA<3F(OC+oGxqr%YC?>VjuP<+(X zG`&}4_I=DP*vICT9emHKH4^rC8OS$7)sdIMwMK=@i6cXsRdbI=wIiHe=~*tJ%5sZ%EJ9~I}e1N zuDU5AGNWbXmR3cu1~N7XpG^o)N{G`}(z4RFMt@wO6%hDkN{ujj{>g11?*B^9$M=(A zQRRjhNE;%ot$&dpQiy<{A55%_-~6!f$J3>!4wPgM+jE6@lCi5}U%@r$k;Bjyu)=ATj3c0#Wjvv!I|jqs*LPQk#)gs3|< zej#BIQL*RJGO}_nu>k~BxEFH)ccsPgnz#h5;Dp?d;&UN6<@+f`~pu6P>G1?`JNftXH@)p$-jyz_zz;L z{vqd|V!rt;r=S0CNuy)_F6-LKZ)q#5e#_hTr@&+XD)H%`BHzseun|pzgpZ65cnsM4 z_*?FOcZl+CE=o&DnaFUsh`{M!RoWJ7sOwvAY|*=>r(=&+_v6SYUyM*4#3KP$)P%7sZejb^ebhvd`}ug{GNT#cAH zOO@zo9*_w6P_t&eO^4V@@T`8r^5DmxW z1DeAtU4nK8Sxe2`_lL2~$0met0pW>1YY4ATUIw%p4Qg4|J(?QP)`k^ZogH3=y(@7S zUgA1#PgW~LVN!V1piL2CPH+Oi80K*gSW1nHkK3!oqeY%^Y?i$?&8bY z6iJ6)&G;QfTzBBdaV6Hpc2$#wdAI}a2Ymde=J@~j=R-m2Prje@ov8~Jt3-SkzEWPI z8O)~*@Ut0U@gP1OOa2e#12ff@dNHzt0MAK15qxK6=pjT`GHK>%(%?(LeeAdYB)`wy z_+CtmpLGLcrAk>sf@d`>>tLjvvlHU*eLLc)GB@c=l3KFT|$7IM%Esq$bhDoG&rav$RiC#jWFey$%Wpa`s5j+I}XFH1f< zpVyizV#)78C5l;;1b`BLWrMAe;^bWQ#(kijT;T_##oj}S3I1G}yUhu>Rv9sYFBb-_ z^jPS4ZE4946_uZ=>P53xDiZmbk|smgjFB-%tfYO;rA8x6WXRb#eRxepc<%m6aHXAB z^yNs~q~EK#1<@Hg&k^v9&|8$a%0C4EdF0jO25W${`s9=nD$1*eoO0jje%z^pT4xt5 zz=sxahVz4>Lc2j~RydDCGLKiPcDVa!4yxk!&3C?M*52Zi2nAo$6tfbPwu7wR>=bGt_&9c3185nmzY zTj(v2)cgB~r`|7Ood*)MM@-lBI!_MIowvYP<0lNR7F9|CCrIS9zj6cskg50Cmr4^A zpw&9`VIA5ylyJTX4b|tk4uZ^}#KgY~i$^H4^2u!UbqoXi5tzO$5j4~)=&aS}1TWE! z5WjX}vnoEMx2Q9RPs}Lgj}5-D$f$ZGctP@J6fn8?yCfuvFL9+;FPR0>yA!H1KuOY| zd;^^b`N^37u@KrNzNz`IF1W|>p~Hs$Zk|9W`dFRHg2 zL*KE?X=Iu|zm^^A$(78>dB`xQ(R8BO2PU)+t%fV4#?i*Ox;LnJXl5fhqCV`>?MshX zaK(PiA*p4j-RB&mVpkJt%~mHH+He$W69yHAGZ7}}Tk^>|Eb?8r&QJ5(mw zEiDq*xg7U+LaMKF3tCLtS*m^8an@lFQ^#POn*UY9{2+TlUYm>bS&6IhqUvU!*uHtb z5(H_ze_H5N&0jS<2AZcn(Iqe)H=_SX>AZTjU=0y*MJ-wU2zJ(LqQadDS16z#GhSsi zEylsK?nOViv_y)LA_rJ6lAB%?W?56LOzgtsE^NKZb6buv(8}s!gGJ7^Y{3VvfzHIF z5-Q?>`;{&44ah3>U%f1&p*gmsl#yP+VwhipgP_XL>{g~fiUyz%Z(W$Y@rPH(8IX-v zrl=^ChLHxvl*PF+8>fEYBH)7+6)A_v7O2@MvE~)8&mR_|!ijwTUbt&fJ^xsvEmH8N zpMj|BeSb!?VTA#Lh_tjywHTf73IC$ZHH#U{O$`O6{StNC*5Acm=O5nU+@O>nDs3ip z;;yu=l#Am|9%&`1p=-VU#~uoqMg{Q-(KIxtmXw0BGdK(>YmQ@3TPRa26LNyvYDG*j z(`RB!bC@X0Q-+fZ$IQ!$7d`8x8zZuZP4^$hV+3rj5_6=ri8E|s*u}&Zr>W{7?ED+; z9ppJ(m=bIiL9k-$^}PEzx zJS3bInD;i&_<#wu!%5jWrqtlfN>E0}+?kq@{R@T)|e$Y(X{&bM3=F_un7Q-Yo0AB4?p z?>Am^MPg6wii2=g8v+lt&n5vPSRa2q|1*L*bnAWA=q%3PfH$*RJKUHwAB*s1)wgN2 zjXTWDYVIGjT=1~v>7*+~)^a`%1+jt`w88az=e?2MuAyw0_N4g5hBZm@Fj}q9FD!$5ChLu&bgJxxXWsI6CI-i`h0%LX{ckzBt)*FNqJ^HkJ zQ66=gD{5+?)`j52QZ;(3$}|B+M?V-NE0{D)5ng95ObUlM$ZBgnf1gG#S%L?fT-r2u zC{;)YrVr8tFG)6k-{Fn*2Z{-nzx-+yK6l3OU|k9&SDVEVV0p%+y8mn-X8*KZQ!Vbw zWyn`=s|ci`C@V=bsSZF<(+7RYQkP3AxhC-|OQXn?7_#l%iO~rbs9C2s#?iv{$T7aH zNLcVxY8&I^gWQ&uJ-3xHGe1ZJcjyw!E%2I|9vWv+=_D&U?mIFeOnWp}t;_`DFx>NE z8DY!gr+Nfj>J#m`S7BU=y(BKK1&|!pX0uRjZMOW*i4AFBuwH{+}F#Akgn+mGs=o{ zi=(y9^0e)mk%^%a#sPE3ws@k-T=OeMWM@1*s5vEM7s5jZN8Q~nA^9?(W(<<>4=K|c zpbm(t!-6JX&`q7&?R3`Q$T!xH^4TY}1R!@{eopzhh!A8tn*dFP}r~XBnyYk2y zqNnkP?(q7NVE-&Gm%%h6AN5rGIZdg^qX<+pHe!>j9fG8@v+<3~ z0&Nt`ZO;DjJF&(@P0Ol`iLVg%qC z=|mrle|-w ztjz=DUbUSE)C3cZW&L~SLg)8VKiH?MRIl52=++j8>2@&8E)qb&y0_;?R?z9Cf}-?Z z3_g&sl}HRM6Ot|#C_B7qjTmj)fs#%nW9!r1&bYB*VGBUpgwI1csn!};49V_8Abf^u zvwVfhd&vb)gvpt?hWDn@vWf+)OAC)V{lMU%3puD^#rWsRJx3wT-OP`IXPP zj_7?rrZlzL$3QOY*J;%$m9a&EtQrwCHQO%F9W^=)EBXVoSwishR{;XTXhU-2Ic8nL zz24!TeU{h!EC#RE0f#?WTb`dAZ7II)iy~T~`^Ni)v23Gr-RK=k?bqCEys@YxP9G)- zHP7Ikp27G}v4kO!w79jY^;IczRgNxUijDCS9EK&F_OZYmJxWx6>jO>~>1(=J)CAv8 zM)3$;RZZNt-<8C4s=9j9gglQ@T#ykhD=1cp8`Fp=rKp2~5hBn~5yt8xaXL;ibH$T*TPUsRwdOO6QPYIViIm@v=nw$?Y?Ii{i;v~n6~Y`7>G7Ec|z;D zmLYHRa!Ozh56QR$oGJC3n}MFh~B5tk4HjSH9KcVOB@?(6ov zZB2^g%Hy219cs5B_rEw**ALCjcfX2*Y7U81gFya0PtQX_zc^L4JVjjQ4=>OhVr7;C z`FFfXed)RUnqR}uYkgZ}cI7ouv$jKvI2v8)m^%4MbMpY8_}*d^P?X#)jiliPCBg96ov@v=EejBJTT1X=o+lAVAO zYC!1A%Qs4>ZWG&D7MHp(`hmFh`JKWNm|jCxu4NQCdY^U$`g zolG?NQz@^e4fgNDxZ~69(?6A@xnWk&nBkPbd*vM9efurl9#MK`k$gyXU^a+Rhh>Si zgM%PzdUQHkBypp@D(z};_JijNj_F2f@p5n=kE0D&^1cB`Am2GWIH7c|%b@G%ux>iC zAUBN=I-?6RFPybn6E&mP<3nB7@NgYh8J!NQ&Q5Re#u&>DaVtoznXB@MDArzgfI{Se zMmlzd8}SnCg*{Ms8`1IGE~lpUYZFRKVa<6N1+EB?JV;E!k^Ch&0Dxoq=91j~vcz)y z#r63&EYTb6W)E=nE`#Sc6KvLLeh<;o>#`JQlIgmB9ndq3&&*xSql&uw)-|!)qAnt3 zNj(-N+=OLVdL*o>yuj%Y7n_po!X(C@d-x#MhlC3;bNE`9_@2`b(z8 z*cl0atZK4FwY(HDry#T#k~tBkZiH$+=NixVAzRxvDDRrE-ne)Lq4z2_hwJZ5sUq}V z^NoF`qRLAloOh{%Jwx#|s^zf(6XBWj&_aP}9D#EIle(3XN^7|Ff$^G%SZ?ENUMXDA zzx5j-%f>(pxYAkZBqCc64s%K_bXUuAw1}{zN|5?Opw-OmR<5MsCZ+A~K4QwPbtGZF zk@`}H|Ka1cggBepaBd1>!t9+CThtc~9AGRXAo1vRW&bpoK+WGi4g$@SO-3lpL6HlI zZWHUK^;cul^WC8n(V0$VSd1m1nmb(*1RvGWa}p7~2LOP%n5d6iEG;W)HFE8!5tbI zP`Hq($*4n+5yw+#HlXExl}a)^eJaeMtx~jR1Ti2kF4wk!SvLXQ^oKYGo6K}pFu$h7 ziCtuYK)Lt|g=J<`B-{$h<;D`Tbz28emnsGItdwqB8B6Bkoit)%M+Rm>DyacshlnQi zHRqZ*<5-{;FgKkwH=Z?-yPoeN7TR@?XVw8uRV9dk=E4-<1?T#NAyLU;G}dNIH$pL0 zVc>YynSk_ah)tA&yE91Jlilp;u+;qosuFUgBUoSw&zfD8EhaNjxh6D1V5-1eR7tCM zCfwH*w!AD5=O~y_0%b1!;O7YasDCU<$+2|yeOWjR1I#y`9(S=mU8RQu66ou}8005CUR&$WnjaHPrxdVOaiS7a4$o!zY;`3Y3SvGuB>G zQ-%z}Vy)a;^lR63P|B9`dg?bEy#5|32;yNiNCb*e#;A}5nCHc0m)YJfGcK)4Pw zn(PM;qKovP3QZKWQS$%PBGjt}3EQz{d;6>|{ih%~hL|*VlA_Yx_A%9JhLj{Yj;CgChulmc(=I8P;woL{$x#toOS&t+s6bnYeYUG>5hvo_0 zp)YkE4Rq%T6v|^q3PtF`&%`(nfJX6JoN}%oy!}@w!-{p!$(V0g(>%ws=oa z0xA&0iIjtmYjXl|Xg7tME{?UhLXPGRL1;3xFt75}F^P^Xlm*nJ_2W9P&lh*u(UpfzSOmD;vKd%;gZ_5N@SW~_fWtp(4 zH~~@&et>qCkvNpFicC!>YS7G9)*Bd&79@{FMXH_w*cJ5wfIsSApnLmw{i86>+7E3# z=qO{_&kQ47cr;8fghBE(KQc}Q#yub_Q^y|Rcf32+P$&V87%q@Nt{&E4D~vC;5X^rE zxR2wjG*Bz!*i=mv6Qe3`y?Wy~5b}C>M5z7_P?JWW!6uztKg4OlA-Yd77-HLfl`mnw zf)$Kdkl&1zB-=NiIg%{rMH&k=)Q$!+U|Feu0-(el{Q4IdHtQL@sf1N$Wm~OpGRy8{ z7A}#9Vdt^0en?w%5stNTKTM5<$HXTw&e%C-Yj@Y33_M%2N3Kr09+KE@5!aK~>cJA} zD<&a!HP8~&$kPI4hm%*QOwSE@Xm|)^1>>+vn&-wk&bVgB4@`qBwM-6cx=}hOp;?taPRl9vw19WM`&xBRq6ut7VRr?xdK$q|}b+?qQnkZtrG$;Fqb` z9Oizk=-Tvh713i0CJn?j^!80(1#%I$59_e!xG@LtWE~7aJInyMoay9HliM6iTarcg z_V$t%S+O`(Wb>?{C zY4lX+rH}Cuyi%q~HNt>~CAGRPWi1V%^s(j)ld1~semJ>JBq@XLPysfDO+(Ll$05&4NHoFAiK5o(<1ehY`rde1gSGUqa?r?9({5Qpr8noog2juvv$cf?I0^iMMpk7i2`*s!g*$=&5g9vcNe- zrdHP@UA^$$pS|Rx9v}|=#gm%FTId&!ZFm$C~gCTJ`I(hT-52Xb3B1@yb z_Rx}vGP!#z3~1>I59%koEmn?Fm2b z)tl(qys7WkfrY1LrjgP~*v&Y?ES4k5jf%_ih*r(wTszp?IlI`+`-kcca_ssOi*+(% z=1K(8idmijc#Nmb9vdW-Sxh%GM14^HSoH_3AUBfxsy&5csTW+|;~6+TG!ax3mp>m4 zj^7=H5L&Yprk#DZujs4cEw2a-pv{jtHe7BTU*;z8ZS`kp)6#ye$LFxFsD#1Nw?8&j zT@om;?x>#uK=2l>)s+!VI!tj{3==?*zzH-jhkq7ueFqRdqpEWL4s~`~Q!A#N3G3#9 zgWQKhVL(fQFL)fqAux_ZW-b!KlGJ6QY&fVvg_U8UG_dYSf{f46#K6cyT{V0urGq3p zHC`NlO_#JNJ;GbZc=DV20|y$FeaNPfYq2)GD*OXRR*+>3L@yYmFr^xv`g4vXs*KtM zFB47?kE6^9UCRs0!x6|YPyopho$e1Agvj?LiOsO<(YaKDVA*ltWTTu0rk!}siF<|e z!#X+BEh@E5takm*F>AW4y~T8aq$Y|=;v(@j_v(cs9m0=s1;HdXk?`z1zxKLm38DU_ zj99h&jc}MzG}maO=1f49I>^bjX2HX{=2D12y7d=Yo@b{x)VpaJ*3`}(x-^5M>w>Dm zGF^l^6Q72|)ie;YKHV>LYL~1U9t#vypFm6u<65Px#S>5t3M)(HD_!lT6+`41rbJ%S z=PBB+Y3CBV&yx~;THK61Jmg@SfW>X10g1z)Q3p z#LQ1l-}!sqVmUg|Iv7FP#-vh)XHEdc1g2SY;R0Udb}e!&npz8Of|Q!F77b8_l1AUe)TCQl&#hW?+`Eyj(; zCYK$#xi$M4_IZOvDPjwX1`?KObQHKzX9}t+>X%0? zl;`C8rq<`ay71;tCgz6W8;a_D1X!8>8fp;H_i&vw63(|ePf+dMe_vz2p4*yvd^z5# z@uh00)aNjJ+!7|?5!JCL|Oi-6n(@E(qkh4q46K#DO0QfB43INFT z$6HJvnt$*X9tG((Fp_bfgGpdx?TWG#Bk@*)@;I-7MUgByd4d-b^;ydyU{2Apg3TeC zbERwDZg6j@njL^W?8$#bXnD2{W8uxYjcl=Am@X!DMO!WT3H%5yD@mr*PkW~p=D9P4zh&tyCmn6K=^qb??WmOPrKqI3QWywP`r{r6JK7;D?xvq4g28uiO3DP5WZ zoGj!P>7D9L!OHvFontP?bLXTR!GCaz6gK7DY1d~v7jl}U!?)Lt?wMo0uOD%`0j+%N z|9jr~aD9#5Fg-PGTH^sX)e%;^)JK+qYegMudMP*u6jcVlMabVrzFzsj6{QY~4C+iG z78^&aWM7ibulgMJ4p7Y53PAn?9glb~Xe@dJi+S@m*c`v|esQqmcx6{Ds$a>KX+P-$ zBpnFi^C{alOVPOlEGQ!Vp$Wyxm#UvGKTtSgc0C3PDNT`hj*IU!#aX2la$IM-jJYw! z8@_l>+lfG;>E;m`;5h3IfJHw!rfrRt%199lD^aMov!jJ=im}!D=~K|4yDhE1Zal@} zW-s~7kPM?T${0X{Tpd-bIkiWH$DFl*Y6e`AmaPjq=EWM=I0)o9vtzWyIjejUwKCRC znnV{^?XkF;rZH99-XFvopDmo0H+U(c zk#jQZ_~2KsTX+I&YVV+jbSp)UgY6^nNOE(O0bLGka=sW+^Tuj|Abjz$I`I2===m_x%(2cO_N;z?;j6+_SdJ;-HiO= zmHJ7=Ezz|WSRr#tm=%HSEbt=vCSEr0KZ`)%zFh7I+&5vPi|%C!LJcD|h)M<7#KV|0f$_F4HeQ=ox_uX^$Iacyivk#u@~1q;?GH)@aIld zn!X9A3uK*3dIP&**Ucb_1y`htlX#}gbw@ich_7`Z3>ZWa1`J*Nb>y#p!oL6jF0jq} zP-Nx6I(fsys67vqOBidBY^SPASp1g^S*|N)(`M#}5|jyd__qgV50v%~O$YKq&dFiu z2qTB&!R-USi$lcTmC;{z&q@9Qy!Df*HJUOGYfweG1SDIxjo^gIi4*5)J11Z3uI)qmC2!S%rE)_aKVFCDIr}C1XKk#J6lGz^i%FU(NH~*M z6pTy!Nk6y!o%1C6dt>#4+9pVnUB?WZnX;1S>iyq8ZutKH;nPrut~1eR*VeZ8CatZ_ z1a$@CQb0NOoi!(q4wNS5;SC=ATI(sBBeGJ)mA6S2t8bFEM-_T-epkcuU44}MPXNeK zZ7$^lk1ct3IdP?(mj8k>u^1@lJo!aA7oWU1z+Hjg#G@wuc?zI<@(oK!9J}ELT)F$m z^P3lH3U!dKSCN)uG+*w6xwqKlkME|dwsBGdkARmZBn=q0SrFT*!uFWJT#-D|iXe8c zWP)*&yr4jd95}BIg1Dtc^mhO(@8^BDMn)Pld9pV-z`}DNm+d0;)*M8zw}X1gWa)U9 z(~PQ=izQy^8kTw zX;5=DzPpQ{7eI}M{xiX^z+n7UT+x+rrSF{A_>Ix~V%MBcI8l#MmRy~HdR2nz%UI^= zlb<+fQQkKEPC$XZA7(K$f!g7GzDM~*H{oc}-U%kq5win5OksSxNA@mTHE8Ua1JT)c zBa4zX@)831&ozaw6isdPzOEm)OA5IfMdHb++3m&)IcH9bY;Y&_&u>iv?BZzwfJY{l zAR{NZ?I%db)GX(jR_1Wn3Ksfo33rTVPF8|OlRPS1S^81rH*|{}t7_9u9h;%*T${9e zp#`pewKf8c?L)hY6bDUu5j9Q&)cpADsj4Ky7m!|g02S){KiIsmry9c%Dm13G8;$o3XlU&fn z?Nm)^JZpN9l6J)D3}X6*V_UhbQ3XB>KYR@b-yDTuP!&vc_7J>C5#VqIJfLP&6D^+P z7Sv6~XbIEq^^dKV`5+Maf4KV!sH&E??}I_30@5KM-E|IWkpj}45)y}!ZUiNi66r>| z58Wjop@1MDAl=d-3JBIW8{=~S@BQEZecx}bcdhSZt%tqO-g{=An3?DK&CK3&B;Y=5 zq}4WrOA#{GMby|mXNqQ#POHi+i`g@ha)z|HCcvXSEMw!PD3!aFUAIQTtqS72imX`} zF5r~>^S*9bt&Y7A;}qMAfz>G~k!HKM(>6rOCc-a=#MY9smC3LAVWu1$D{=<%>kP9ox;MAoFEeN@%2jfXz~|V9iS!LPs;4Jxn!@}e zGJ9_gJhqvN-lVIYA8@d3gcDh&rIu@H#1xJqS#?hN!=U~FrtZc#m3}t@Wy+vw&L$*H z;^(MbA|`KAuJcI9k;xh5P~9-dF|OUs_Hf`i{6*7w@k|tJz8czx)<4$YJ))BK{iYmR z#8Lb>SUIs$YyM4S$a7;+*1|o9fsz>RhZ4vA+HtTGOV;4xnq;|?pM7&E(57CQaoC_a z1*^#r?-BDi)~#C~Z6{ic4vnl|k|_uoZ{qY`W|kUIXOnE}jzJ1D?s#Yj=ER?Afx&(a zHkiu^<)YsfOhFxxiesx(XnfgqQEeE{XJ)XvIFWtv&L?e+T86fo$JJ3Qr{86++?wew z@;N>@xrrR{v+4@ddM z{@YnHmKoltM&X?rHvzR#gG7576o=qWKb}+Bh_~;59BN4ExxaZhQ+~xSIy(C-v#{zp z0(nVc3rkVXDdxQ%vR9wZFR3lqI5-tpjtC0Z5At?N5?z+}GDxv~VstAF2L6cdVQG|A zyoh~SnVgcS?o>D*;iStM)U0AoAS{iJTQFHP~@ zD26+*7iReK`{+uY$95Nqwvi^ej4jd|J9_s!j5$9ivA~mo`m4)=2vYlCy{&BNm|M{eKcJg{6wp}I%7VXkzyqAqSZ)R`;6cnyKQe*6*R1{k$( zxOuxbj~P8v6~`2jVMcKb*v3wMD&XVQo0yY2);)#+>P!-V91E;2(q{2?vV z3M}*X*5f4`HbkOKy{5hu-?ZE_=cm>veiRvSYz(>%eMPedKw_@v$L$SU}Tr zIA&FYKxH6(V*_Pex0BqF6Hp}B`zSiP`#f>=>r(aPXpIRuuc0N;g@70%lb53I9Hzt5 zOM&8!BX{@+*o?B)azmH8vDv~FvIlyk=C_V080@}ACr{W6H$}N7CGZ9JhrBeRZcz90 z6iND$*@Rz88xvd{E%AO(+&Qv1+0-?ZI)y9tC{X~*kf=}Hp&%Az3C9O3+i}V0mP9g| z-^yMr%+?5FlS+NaoJDm8Wlnu-UUmMxmRyOlVQSyjcNqIxq-27H#>e^C))eN!-TWkk zLx7cQY&Fl;sOx~h^0m-pa^wK&K}Xbw7#X|jPglRm;gPTBzm^&d5-u2^4Pwv7XV$xW zKd|l4#C<(drL9ttIxvboD=o=3$T~SV_@N~$tHQnbW4JSwRVi)w(5q+Ev!Hcn+nBSd z`SG>|Y6&;rD*874>czE;O3o6GXvP30$B`6znlM%?f;%}m6iZ7p9HthZ`F29=DcHvv z>~)`4jy%|$#;MLPC@V{ux5QV!D<(O_IH{pnrljN4Y*07E?7EB9<5o-*Ds>m>FXGONs$K+t0#Wc7t{g*=q#wL7mz9&{MpMa0YOJ?WtPEU~FF1S-amFra%7M56q zqR%8!D_C5KF(6mWDE_PXV0jYfgOmmrip{NZb>`v}cO>!^Dlp};W^iGyzWGh;3!r8H z#gct<+3Vg`QiovNsYaX!Az9J%8ni%t2^(~NX%OIwgE}-xEN73 z^0^G_5cXhh(q88TC-Xq!p|H|i7fayB)bz)NJK@x zuH!f-8$U{>(d1FM0Wn60NzALF9Y`7*z(44v)OTK6&r(u%o_ z2duWsh|wqJ!ebB@s%6yMm7RArr|`VxbX81HU4X&A%nGw9dff0FRzh#N{HrP2CDV5t zhNGA92yBF#Wi;6EVpEj6LJ!vWs#U6Enkti*1vF+n&s4?wmue9kVASP(c(9K`(R~UC zk*{YWli`2EGnkrSxYIfmcyU*pt;`J`8kL#(xWb}f(iSl$JB}dcaZH{f(BB{! z^&se&b!`NbfZBDAU=naN089c#MW;fOfI2d)^<+v=xCX}Z9M9p5k!dS*f5jYnh)N#M zP?s%zE@z{zNl6z={$+pNJ*961%(zBYL`LfqW`=+nSLD@)-R{CYZ2HTtRqA0`dIrG@ z=><6jsVqb21$MWZB5W$|9f(wAc!hYeStj#a`Nwi$^f);yUhGW|5DBz4eX&f`*|(ej z94?cMV(^b)U8x$@w-_2lLnMronU5q5A4XhRc`E zdQu2>ch4th4GU()&=uZN(<$_D%8JsVe{6N{nXV}tQg=e8&(YcDpj1xVLhkH+XhG}g z>K%cXiVTZM0<8JE0+vI_y*1{+#6DIoGt_RJ5CFKb4hCwQbf2bQ?bW3&Vu{6T>Qoju}ijHd+YSs1-(GN`t1Ri0~ zMRWv4kfNAr`n~HF7A!ZGQ0W^eGeZt#Wfg}6Wo0uZFa&(SmbE=n&?kIk&^Bs1-S z)N9u@*-+dyEEpf}9#>Ftwyr&O(;h$Wp{ToXM`H2|)f*0H;`zL8_D+UhW!I^i`96FV3vTGk_#!K$QzS>A-$IsU^lQ-ATKn=<(}&XpAN zGK1o8=)Dv?YaJD+Q&o>)8n(HtJN*8 zTYb*D9N5$9P(d0@%n7jhYt_wv zS@raD`t8*_?HAo&YO}Z#H}~s2&)aWW?EaWsn!n59QBKFIaXFHw#6Pd<8?9JP!?=ES z+bhAQ3bK1uWdZeB^I6q{o{OA6nU+stw|?__U=Tx5#$zz~UMHsweZh3A-TJ9zFvk_A z7Ufd=cJgRZWny$}D66}N0#2`r_vEUFW#B_bv&BuMh^?g2i}mIl03yq!Sh48yVq1^S zX+`Mco2yn|ByN*=0>gX>#JMNSiUfVo%Ofxbt0=%^s{M9Xj#^sZ+4ay2ymDp(m#S9q zHK}SCn`U|5A)6?8C-rdnoJL+02j64%pknQbo9U+(M$Yzw`9DrD`SydcI1DoFn|4wR zPVe8cv?rx1R6na16SQt5k#?1e95apBs)lDLc0H@(IEuo%#9owwY@nwQ@@PYseW~=a zbS!D`b9U9UCehOoeVXiRE@h9}6IcN_HH5*6&8bF4rl&bCM8{!PGVV>cUZT@O6_qGO zr_;ybg@nizmyci#s^oQ(m7Ft;%xKR{-M53$2w#W6EIuS|Bi-h`==JiSYX-<4Y_&F` z@623Zw9nFV$yCoq%-PihG$pw>$S4RK?`sS=z{c6tALZpdp`oW&lZ2h3GX(EAYjxj? zuxTcLx~Q1eLU`%wAB&9fPu^+;uc4lNSUSjrGN`Sp>j=o>KJaF+ zGNo{b)fOp>M#avt)~;sX>N7U+_dD@kglGAz zdj$KPoZ_`I)lfPL@N+o!q%4gIBuL`J~pwvwb-mrB82sywaZuMz0pm@E{U32 zKlFOxIPaPyq+OFyoBO~vQe7cNJ=5v+3#LJmBvj1qxxNveWK-Erq>Qj|5jD9yUdid+ zAR8tDSM{j7SmTl=rO}acNLE_G__?$buZ|>9#w3mj&^42{b@D{ogYkZknF*# zEF9(dI1lqN+L~Fct~OZ=Q?dE06lRQdk%YXCEcJx~C?L6F@>qpyU&u53sy5|9|G`eK z21R|VP5#75*g5=U_qcnn>SX#jU1a8vL|Q}G0}f~W!@>2Fv_Vi#EspF_yXF=&PgQJc1-p; zlYTnDtWz6N^2#}BQ2@14TwvnihMi^tA8kkj?|kULO!hW?F6m&`VHBcE>N1U+PX#Mp z`to?lHAGakQ^v|>&qK7hjva|AG@Of-S+2>B5>tFJb`6DNDOcP@GR3;Nt>#BsR~cF8 zdA6T^vbL@D#;RMh?vw{VVK?1t#8(A(b_(T>YqZ=jjo21Qz5lI0?B<`-KCgex2T>8o zJ$V;9`D?JGHhSa7s7Y-?tTFO2{K=$M_$ObOBbDKQtDL`j_}8oj*S&gy64RHf+so=?>Vo{YCA!2Wo7{%(@nHrvz9t& z^vtnIxpZOJ!#21dF8X+tpd#kpO9cBN=5&A|E)`|LvO_~#5?iuKRreJJ_L07|Iy#~vH$v2wIAQe`uSD0 zfATplX$K?szuKGSzkZQRKtKTT`-5CRKWP0AKf!e~Xd}+*K1%R{zqA-V4I0+X>!%2w z_@04IBfw$SH)S-1UbJDz-L7xsz-pUaUj2Y2apyhS-xzDw=f=>Y3wU6bx~fRt_B=SV zT^%L*Ob$NJp;%Y^b`%EN@%k9-jR%AE=Nf2kSixX!qLv0_C1|kOLnogJ5B=^*Gmt1* ziJfg94klQh+E*p0+g<~g9_MMq$t<~?0eSl(D~d;HYc7MUo{5{)2BVxcOyFGiP5JFn ztCR^M7|a*%YiqSZ99<0uxPGo<06fD|!v&omx#^d9+nRt=_BHStd$F^v70fr+i1^Iv zZr>P7L{rnX53BVC!IRU#JDpw^zC7jexXJQBU6^8csoFp@Wr7Aat8A!mZc?v3YLzrW3!9ZO)L+i1n;2QoaPT|>6U8iA zzm>P-qF*9z8wK;lxbK`2^zEK*iB-%518i0ZJe!_oz3$v?LkQcU1ZAelfFd0}gM{cs z>+EkTZJIb)YgAz^s%|CDQ>*k&#+iKf`Xvr5u$H79jrIC8&KtA=Z!BC(-uKXroPsrC znejZ~^x3bc7Ta8~63*{8P7lG`1#gT@pQ<2n5Q&Idv1?+^ABecD`DpnR%nhek=f$Rk zLdJ9F%X`{oi|B`jFxa-QHcnm2BN?aK5#vlk#nKBnr(n})6+{jq_#m~ujCb{|)*DyJ zVJ#Gf)nc|xDg;!;82O4-+(aY{sd%tiJZ@du8bTK2xzXLJu?o1zdocKR*H;_6E(O!* zlFrwatgCX(@92ilz#31Ru`IgKW#QFCa>aLCt$JvAS>r6M@v0dUxO(SYb!16i7Q*V% zu*_9zSWAzI3n+`XafF6~qbmQ)G;6lkb(pVaSCRju!ky6j#Jli-H)hMZA}=t`z}%dB zWr0)@_-0fyuY+tj@3n;xC}P5P*5YHHOawhb^j>}3#NYG`jr_eoSi$&s3=>EjFJ82; zB2uv%JF<(91~Z_nzz51wLf7iV(#V<3R(aHc2IG3H4W7KYvefe_Rd%hM=uyosEqIio z;sSV-MzA`PEQ@iNPU-2QI4}dkj21|dc5!>&lbFF-=+Q@<_tBuRurUmvhn0ZBcrhk8 zi&t*tE)U3pyy84iE_V-tHbC22r3d$x@oAXvXy=CCq{0{cR9zW0m8h^c_an~-`xVqH zb3Gdmp>AN!xnI7y_pwA3)lmP4?!(xdv{ya)>sM`cFPWMg1z&AXqo-ESfMrDo^W3O7 zCnosuM(T=2J=XTXAZN@coU{lXL#6$p`+oUcnR)Pqa*`y!5GsMae13k`(l_V#>|V#& zhAk~sUxKSx zlY1pqpN7hFXJ2a_Y7S(r)KVe{XH|x&$aW;9)yW9fsGVZa(GO$9O{rC{dnmbff5oZx zJ+##=-Vg5Oo@m~Sa@|qgasEkb@D?zw|t`Sp1L9ykn?C&?5&!-)ml_t zeUo-+bIzb*J4X4fH_8d~K2-y!o+w$0mzQ=FK1yB*5~jJ$UpK(_?gB!pER4b;;u~3z z@yygk&1*i)K`#x+WmJRrjD|2)3hA0ZuyWyFdPEl?Z7S;{5>5i7IfwO}xP;CjLx^xU zgI>TxjHJDjuFC%OSHm6CoW<$sHyShFZC8w&d{h}em|i7XJ+kzY@N(an~PA4ZR(A`H>+xu(O`!iVgPOas4x7<6AbyRTW zM|xUMrAa9LP4eUPRPR52vLG(rMaUg6y!@=&kD_nJ_=x#q z)UM^)C$ytsp^G|W;ZG(;IVVD{UZT}sd(Dzy9@_oJ8;{izMj%Tz7zivhDG~nA5mQ>u z_JhA+*LQ=p#Rq;iSE`q0zH?6a@tkKrtEx#Q;b~p?j7|N@M%$Gm{wg2e*mM>YPJvmx ztBuULu;Tei&F*+1(z&9(Ef3cD(>G{Z^ElC~(9c~L%fCkO@VJC+=?l>blS^d6(L@~8 z4&Ao8{bA#J8HrO_B9Hx93a>_gwoIKsy_K#=8E?63`8|0=T61rr$8APc;r9NcKnKs& zd;XVo+aG@ZoJ$(Rmsg8+lX)-vjZuguK77D3OiprZ*MF+Z|C$P0ZY4!}osg~R=LyQ& zE}>TjQ)x78+I7qnZ3nNC1y|tIc*|3gHE^w0@=zDrWLqXadN*$!FfqYIrrrire8k}X zc3xdV-lm2>U*dsm&!BsTgh;R`xv^YG5{H!X|y1`z$Zy8FyTTdB~Es zYqRTXtHHx4w^a@-N>sYc96g)JH`mSU zpQwM_z7|Mf<)W$lc=U=K%|IRjI*t8^1Jpj>NHpB0y`NALEpw(yKz539J{8witZ8DD zO8s4Fx(Lq!SwX(er6gA+@q9ajFI3tVGsAY8Du*l)`J10dYvP#5f2fX8{Ftqe<N3uH&&+ zKyM#yj8a^yAA?t1%&Je_?x*^4y~zGEot(`?L9OiNu}gRj2ibS@uRf6!g={EO5zAz) zMs`oKSE5UA^mJV-VRFgfg(v7;Vy~_qxaM3PvUGX%MuI2YD~UW6C_-;cF#pb0roRGvkdX4w>efyM)?9?$Fk;UQuTciepVi+R=$~? zYdQA$;isgx1NnKvw=Gl!2<0Y=U!<2AM8Uh}sQTji-F&?3l^JlacNdvrQ>gpj#^)Qr zA9a@7+V*a@M0<|Tal=ziu08Kf+UPQZ|cxMn$eUOZzz ziwz%DI?WtZN7L1cOO@fDhNma6v(qL-bHWW}<>YNj z!wJL}b#fyTa!oHS4Q~#I)$~1#s!LTftbud;7iFsVxVS&~n)HOaGCEV1#5Wp}EC!P7 zBYDtcqYqE!4gA7m>&Fd!U>6^tleFzAT*gx@G>g$Wuh%nlXg8jC^Q?<5T>2&MGxG+~ z93xK|p#mr1nPb?j)v%!YRAL`b)b$QuI1nYd*4?3yL+q?Ib9?J!dc00WK9wz3wSm}K z)#c}h2AAtTesk~r!ause6YzC^Q-*;>I))R*lI;)>R?t%NC}HLM+mbd18G9N*0y+Q> z9{EGC00Ii6$5_FxWy;fYMkRqet1yb+bEf%dDyD#6l4)!`Ez>%6Heuv7&8WsB7OO6| zxTL`)5lw1i(OTVtkxNxLg@m$K81_n0Bn(bYKJWBX(Y|@l^~vj+62s*3C)ya*XUX7% zO`5GtaG{aPN9beCr&?Ya7Akbvh-&8(zp%-05tNnISjMNU^vj}7-iyBQN$qVY+Ou!X zRYd{H=`X6f*}tx?9j!Y_UMqb5qRF3rNF(8Fi^^Jcsm$4n zw1sgN&oo=!3C8glz^%P$N8d8VC0U}qSYy-1ZCG*3SJjBkcRx4nOCGggO5}p@r}OPst#wU_fMGtjF%l{H7a3&O zFGfFD7VTUaBG*~e5ufGSS}(DSZsyn7vE1OonQP{?@ZUKf$(|O=CRjX$ecPCL=+7A# zXB^DC*%O=8a&Tlw77MgLdB$19{lY3L+nhA}i;(Kdcfn#K%Z(($zer{w7{b$88Ax6? zef5)Gv>baEfl0wWv$ti|>`UI;#BD}G7XI8$qq5KJ)DA4E0^}ril0CcKt5N0Hz?9xb zQP@9BiNsBQPHJN>=d0(4SxeR!E!TpwRT!quMoGygTdj}90@N3$md0cFXmADwA8xnbk0r7 zRHM2liv>Yttfu-xHoCnc=*N?qO+`DR=Zfj}Vy~NFcDOd%GF&BPgi{wrrwWVa>bJ>z zQ=8hdJ+g+YRmtkw;2#_FCd_D|hR*cOE&kqQf_Nbxo=Ke%B_mHvtx>kPmfGMY;*?mW zwGxU^s-w+lbatJ+28RKg=-1_uM`WXDgF&ew2e_1`3&H;)y2P`5bey8SzqZ+1k89S&S?4q{>PTN`-9^?y zTjp!%I&4+qne4umV{%isi!pB9w+p4ks+@C%cx97CLy4v;K4Z1i12%;S!-0aCm zL70~8k5uOwJ`X!?aembRUn#wSwysn3zQJw;%8^iXz*;fVr_;IkO@Hk%s%Advt_Zb)?=m_?#)} zu!}Y4m1Hv3iQE27DtwWJ&KJhi(%%CKJKooVRS;mwBF5WUnr&?bR#-cDTY~5pt zz~@u#zAyudONG-@4?{DCCw$wPn3NQ%Je{S(CTj8@4X{s}b4cm-b~6>#5ua|+O;hC@ zxFlztuj9VNk|=IjSMb@hvr5;fFvR$NL+4&jhTLgGmOZ}W)0hNJ8>XegeLA6aPonzc z9XampiZI8KV&0X`m+i*M-lP`7Y&R%D92L%@LMEW~bFHQlU0O$Px$ zO_mu?J@G3+`hdq_a-Z~~E>W??`4XYK+mu8+2=Q{&79>oSz5dm`ytB$L%HcNEvlf!y zU4=%tGJK$wLp&_#15qZ6@ny8QbzT_1ruzjYwmS&V2-((W`-7NeN&-AqdW!KOvCBTs zPcZIG*hB(4+uJ+_$O!AAI!5tXtf4}U6{E9ptXE}8!iaC`leA?TjbN^Zxj&BQD;DXM zR2=&5_q)4Y<5^=QpT2DQF&QP7xwq5pd>F{#iWJNoxx-`K{$Azv>{9(MmRRGtaPe1; z?V+AXv5gEZEuGI6Hn;vMZHfpxM&D3&Pa>(Kw^U1? zGe3nfM_sbHjVWF2Cn0i;M_shRY)kq;vGeFQ@r(KLqR^ zMRH&`-qKt+9J3P(m&Un+KgWEK9BHX1g6sM1`Rj6Z7f6+C)+$(%FIbs8Ciz}FJT}Hf zhS8Bagr(Bd7QipU-G(YpiPch+RIxm1Ti$3{@j`3k55erd!qNrTdxw2zwDQk+9M!G! z*asT(Bg1$t98*%!wk^4WgB(pFF0@VchK}5lZSC+eacYK9txEc5PCLpb+E1CBH~m&@ z^p^EGj8t}t2$Ankcc+T5sjy6_PbpN0L*fP}Qu&Md}i^SAs^Iyq!08q9cv<8qSi(`wV>w)Gx$6ZJ1D%)W$eGOEyeMHHlAF zl$=6XgpA;IGt<4&;Y;rKcqE8HJ$CMv13c+DpgRkDct=d@Y(0?3?&u`c&2T_zG{PJQ3?c-=7eRjtrtX!%8yWC}$;TfEGUcqI#gf+du;;$W_pa9F`66Fxbh=Br`@+I(oH(@W0$}E?e|ylAy4?^MR!5 z8>$+=kdprV!C`h&n$vwPu(Vw&eDdp3ap45_^$tGE1`6HYaLTk*m}{_ zg=!Dn5Q*oS_!&z@?W9NmQ$ZRQ^`nkoi+_lseoi-F%f#cLV9Z~XL7mhCPrCk{vDPKm zbm}w3yT%PljGk-YGt~QD4G#nz6we>LbJ>52{qVqburAYawwalGL3k1~WO0`fb@cG7 zFuR@F!!~ZwW8Cz|vyVY$2>=uWT#|nmLv4^mnV> zH0f7Y<|gFaPAPPSG|FAlS*P9nXd5=}C4n@u@zLhd<|;IxF0wBxF>`E`n|qe;AVOL* zVi#9FbFX)MY0dQZRfVpqngtyd%Hf_H9X7uHa$jYqtlt;k92_V)zofLT`KWkbm+L0J z&IZr(nyI(3;n(6e^Lz|%SKc5EoKEWnVLzcq4~wUcGALzs04XuU~YDdClPS zIqZqJhio0r!I>Uc^78PW*yTTLe?`0<%ultsS1s~+*vL@uP^)v+m@3{UrFZCd#rwM{ zGpE)AVoaMR`i-Ne_syAJ@QbY%Gs<=0-uUd`nqRA6r?bC4S!-3zxDpq;e>r`61+kM4Eqwm8lJ(chwohe2lbQ{?Q zohti3Z>?ws7Vr4*=E|pc2p4$oFU}0FR}K4opA!|YIM69<`_j`=j5i%u7}DYVF>~-7 ztHEh{y*2G_vk+Iwj9Rb_wE^}sUMK3?qpbz6jrECQFIl5U?KU?w({>#k4)~y$y4RJb zx&=0R28QQ__mx*Mh)`$*oO^Ue6&($9%6bjY3|#N2Z;TL4aa3xZM@``D4<^?hc)0I< zzRkJ)L5`xHCHyvCibqfLq#kGS=iYvRR2_MAxHE+6%doY~vrOJePLC0gf&)8u;lTrue=Pk6VNk}^5aUOhi# z!8`Vw`yN*ghtpKIuDP|Trw@Cu347|!)X#6&*yvgo6^6yUm&(m^an)GXXu69!PqLmz zfVe(wkU2&v)MOA>SJ>EG{#4#(Bo6JMGVJwNId^W+ntYB^#C$9wLpjaQ;>z3)RGxBn zD>GR8ZZt_%)a8Xre=O+NUo=-z7f^V1?Q$$~gO$id{4?fMjQq7LN1yRR#?&^!?AH}V zaZMt7jU%_a*9!dc?1Dgn=j0zEoAM^%*i|B8pT5hzg?$`1XFk7B|4KhYE%b?9JG}bH zuQJtlj<)!F|nlep5Nl|(BWcrRWCn&vNZ2wt*zrIJtf2$UXpFnh~rjpmWjXr zqN8nR2DgsLw)yxLW!>^#h6BlcuH#z|-%P&aMDsc3S1`wc#P`y%Qg>KLX#r!is@#yO zT5=5`rvGv#_(}UEG<4YG@K2L}F%QmjV&^O|BS%wclQ1rIZ8-%URkj-*cU6sS9XW0x z%`Kd`#APH@-5s4wZDefC?$Yq{KpSYOa7k!_{ieCOk2e>SFm*I>K-xLobpW@aeX>-z ze(ga85<@vd8#{CV*ox}7AWdCvT?9XZh7S-gKb!_3$WMa+n^{9g0kD-d9L@^}4$cuY z0{qatHukAX)wsAwW4N z<%MKECa64c4#|F!AU*sO5&}9xoFGVF|4NYlP7!D-;!@Z)nK=o~zU-~nl%=K=8nTk{LT zY4`+w{D$*^Is)$VgYi5RL1}v^A7QUf)HTC_v7?H z9!RFYB}mqj1o8b_c1ZqzPy7f_r+`j=>FAf9_;`NkiXog~PBzvwt0LB8X>d5;wfl!f?FQ4pY$ z;1~SgAzmRN8a{6B-z3P#5A-AWgFr>#`$_zO$6v$?84D0U&ky=_&IcLk1f7)qxB^2R z0%$<|LLeO=0nlI|;scci;^UYXUZDSz1R4R~NdlcF-wEOeIzxc&93rT*g+mn?vKi=P zj>`gN@*{X@cmzQ{{Jg+Epp!W!V0-Wk)Uf$LCFc|3KXwZUZqRXnJqY1oSH|P~KpF(p zkU<9s7X)R19Vw3+I*=d14H38o@`v+6M_^wesMCfzNJtK#4~SQ=H6%YbKj@I*prP>s z0-ZB(6g+%Tj|f$Qzaa#uj3)^WdVR=12m#Q00_NaAaZqo_2U>;zxDJPm2YDl4Fa&Ur z0s??x(DHb=!4G~upm8{`0^kU8RX}%tWTSs#-^?E#^5+sWMTa}44q$&yW|=!+zel8# zI}4YJsW}qty$C+`32nK^0$in?owcbAv>hb(iLEV<9qG?pZaA7iw?Qie8%7%0{akw{ zz{?NzjQnwngI9o;OUl~F+>wU=*e8pL-F4ID02+nv(D3kr&IC%Xe|%HQ$OdT*81T4D z137w{V@J>O;}+7|6lhi8hZ~2S_3<8)e;FA-cU7GnOr1*ce$KXQ62d#SM_6 zxMZA+tdS-+Y|X7rX}GymK@gz<%>G9p@JHmprS(%Pej(nITKKhlrY`?+#G;}P#WIju z_(7NUdq++wq_vYN_;{|hk(24qEi-@algY;mvir5w<;@_y$R5k*+!rJdz6EPDhRkXb zbQt0m4_znrR;sx)dvoE9QjeGm@wd<2^|S%l^n$&UbLIIaJ1r=O!)bj&zO8jkFj?}dW}i%!iK(>di4deyr;}06Jn;8 zzdVLG>b^l;r>b<%As17t(C59N-^O6~cIVN@_Ur}$R^nh2#R)=-Wn|m~R;4@KOrS2{Jg-_gDh#~!*SUh-+j4NSJIYb^o$WTt*jC;W>@ z5`-Q$XijjTj0`=~`WAp*emG!|J%gXuZJYL|EkeZMb{T7^EH)xfxtV$ZRdG`bSj)Uvkz7Ini#bNQZ~1O?6g z9JDa;F9UMh2A}b7sEp+d^VqhP2f=;Fo`#6Oc)@Z>N}k+&lzj+YykYmpKS2wW+F`>f^Kp%3cYc~ul_4cnmjj9hq%0AXGSxD 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%0Ds@WxhHVsCq?&%C$272odl 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

{23QAMhgmDFwY9!) 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

`pc zfEOEhR#lYEs>OWJY&!dLat^q#$sSh3%?Z{_7pNrgb>?-QH;;eSivAkNKu%bkbp30| z)~TNwcU|8{vB@@gpyzU8(HwO}(yD?VCZ9TK_v$$2P@B|n z2c3(4wJ(8Wz%UJXqq?b+NS62qF?n|d6cuCbYQvn%-o!J-h`V||LwBql`@o*LRf@lC zp>36xuxXg2{LbTajig?Cm3C9Rr{lpls$0{{8Q+h3=tns>zFTYU9iCdWjqfMeSd%?^ z&pSC?IvkV8s-6Z(qq{E@yGz+Nd&aV4o1x0_>cL%0n4EE< zt)p+>Hvb@-J(+4F*HSv|B=1Mm$zD{D&9ar)wQlhUS4Ai7^37^b?P!-N zyydi^_XOSXR8gDu1+^MJKTH3%*%#(H{~JPe+vcxBO}>XN&D9)s9*-2aevBo;V5kwW zWc|~!eBmnwT%XL`iGJz;v;17KGK$_8;*{re_mpJnqgv>)rELdH+27F`uBN(~rF7d`Zy^88bfxKk1;=IU}DbHXn!$gM8mS>uKJ^W$y0mLM%_SWsN&{N7Aa%aLH} zvm!gircVCr2QHl_RG=yy=c9X_+j-{Nsb1R=3#6OxqGjjb&}uesYglF#!6sus7Iug~ zd;C3}!jDUI23^`&w#KP_pgA|Z9eqgJG>L3JYk5{^N0LP+bO|igKVz9NNfkW2AKFh# zwzWL$pu86K=dnQb4=Sz>y?KeSIr^=JS5!8XONU~l0y9NCanANibdK9UEq1 zveVpt9{xx6v#9gkO^3Dn67FH#t6v|-_Nji57`Wn7xDZ*IX;_q4``$ssKO?l7=e5i5s39zgTRVcCLBKv-Mn|%5^`N{vzi(O=LeZDw?(b zT-mit6I4gM&-THAn&xp$kQTx%F(7f!!z)xeorTd)+G6QmBs^+bZo1^!3yo!5YWgqv zrza9Db$axgJ9HAzcFj%O9fRGrH(HS3K2CYtqvzj zY|lkRZv1%p_BZtEN9)_!nu0y=RH%!l{=Cqbzp`3P7Vw?S^yf9i7Rg)_!)t5uGY9@d zu6$R45HjNOSRv{luNdVoQa_nt*-Fxp_0LD%vC;S*)?uldQf$chkG3B+-9^NLxIz(6s?B)7&Ew)5M=$$< z&){WngJ0*OD_UeQi`|!6 zc8Ty~2k*BY6W#osk~`Y_er*&hGpmJ;UHS3C!p`Mk$(x63A=D#3Z+@nr0vRzHdhuWJ z=6e5LYet?8QM;m+-o&7(!|_0OGSf)laWSVa1qSLuNlv1ONIu)HVh&m}k9Gc)i(xO= z3`TH#`b5hDo?;+RvPy)!6V@-h5mh2GqvpE7-0CMEi%M}Nxk^qrRsp@?ec&L!el7R& z)0@%So3-!}AtkL?$dFL}PjyKq&)QiQyO1}Yg$2ir{Xr!12|-!z>@l?cUZt1uAv$2mvh-K1iP%`D59G-&qr=tf##ImPHDJQK3o*N`5e z-OGKZ-nl7?y;$0FNtzem$~}@sg5`52$wO#f4P8mxJ)qo)CA=|({*dv}v*->Z@^)p# zCURZS@l>n_GQJ=gZ2t@4AzL~qVZSEfu=V$JKCkx){*H}VVHUWr9c zJ-3+CiETaOmv7~2*Lv)Z?q1(%_|DSmDxQ~FE9Q!e3fztU{lS`F1~JK%XTSEDaxmoi ztf~cQv+UK~D|_M52=#`lFn%O&c#%MCOm7+;ruWunZFyra;iyB>W|YrzL^#1P;$EM> zCRtAATV$<0Cr>~cVeq61l*F%@+&`_&Z!Cky-jIM0>Tfsis95#Q>g z^{I?&s<4~2=dsxqT|=7n%h*Y>mA$8K!@dvq*Y1!%56vNdz{F>YPx^x5@;B*$@%Nrk zxrI#I1RP>KuZXa1^9Ou-*zjSV42|%hwE0wDHGiL3>vr8?Z1k_B&`2A-xvQ$Y0XG-y zjOoSo-mO%uVF^5jSVSp#2{_`zoSY@R9q3w^7Z(nk9|k={`E{t2O5im^imo1iKx_Y4p zy@Fh7&9w47Fk^>;RsQJ}DzIaEyN9Onlk8jY4XaL57&*B**HJ{f+m~;AbbIqcLl8G} zM~zR_-VAcTNTjMQ`WAF3M{DmefAd2Ne4(_y+nK=Bo;|5(O=h#higXavq&Z!qkP1?1 zEWeF|$f5TITVk-9w0Z*uBCDg%q;A93pCaPZMl&m@)>3zFD+e|DRL1gl! zbVH5<@pHM0mG;`?a~k%;sHX`S)}ELJ#}G!b$CQeQl`F)2Uy)`FePJvPUJ8WAy)0Jm zh0{}r*aDB!2>lvhR)h~fRr{bk+f73`*?mrmKZWKK6!EN2Vm2q04npscb$d6@9}cAv z&<2~!nkP?W=vJ^fPCIfAiju-A(CVGMaqTbTZaWUV+}Hc^=^D+wPHOf%i(Gd^ptkMx z|BJWx3~I9b;s9TzNf8x9L=Y?#rNq!e2OA>2_aLE{P!oC;RFEPFNC^D}q(kT>AWfR2 zP^AZuk^q8$2qJwS|N8Fk%zoOLot@!>z?kryd+zy_b8_#Qs=A%GWlXMCcV2FvIND&P zj0BCYVQ!>-JMY~q7)3_ZTT!EDDGJXO4YPooiX z8h&$~+HSe2rOb}+qc_vbcacG`FBX^MyB=~1+zTOGu3m99&n?$YHr!|UFqCtrBK76_ z_G@20j0>yCW{ujAgy2palj6NInxMw|>Nvx^izq|AD`t}I3G^e1ww-AAr}SCUjf9L>=Fgo2N5n@=Zto1eSM@O3MB8@?{RhmC``LMb%Q zOt2>BY4s;aeO;lbxfS^XH5>VJ0fGjZVgk89bEJHxgy{@OZM%F^F^ zPHB|F6Qt|zpQ)S9H{%PI@_c#ZTVZ0mvW$oO1`DtW^1Y1?e!JjIQfFoEO3+cI3ufGM zvTHH`Hk(^ZmYr6H zqDH&1#2HH_wff5y7Gk%tS$>65)3tE&`PN%WeTLlY-~5}^99uH^O$_%7Oa3(-o=(=~ z?UM~IefX0SAp3)t$4*CGlhp616umH9@Y&1xf+`Am^>TvV|I0&9zJe%s&0~t#yzvOC*E%g|aLeiQuhqOXt0`dQok~|y*Yrj` zaf9z%T8F;SgKKl+iN(H;jeF>s79OoOJzTw3i1@sFq0E=4){>D^9Sz50O}Vt(XiDx% zvEE}|Ng~4Qwn{2Jyq>j~mq6|e%$;QRcfoJ1M_jEtD;hk-`6J=d586LT_v%E^ zi|!~EsIP?=JP}OZ>J(@bi(*yGH*=J2zM>%O~~xFwUEd5$+IpK!!na z+$l2=lOOO3gTv3dqdVTk7K(cR>nNW5sGl>kNEo~v%Rb@B9w@y=_KOoA{GiWUboE-o z%d?xN3Cgxn&(d#<78=8=FY84-^D^CB`|(!&?S%JOd}^uwz2c9rK{LiH&&&Ft)Ytmb zsPQL3?v_gT$lPWX$I+fS#RYex_I)w^l&%Mjx2K9}U@V#mwy)fF!eoN$@++A@ry>{E}h|EbY6@-%x2Qx+Rkl@W4NYc9tBBz>vEIxv$h4s4R31{Z}gl| zP9bG77|v&Ug*THJ_(rv!Ik7eGiyVe~yPh?fR=qk+o()kxqjs%!i7py{g>`*+dK)NOLK_gIwc(lz20BI!GiPZ|o_PMr1z^gWE5!}FjtXBre+1#^tTY(Jlf z^^5E1tFUxc*1w@G{A^yG>2aD@c-#sJQL zsyBD=L8`fyo@$`oE1Uq2TyUtqneF>c)X#LVw{_}B+Rwdd*6+`@2Ma8NPe@qr4}}r@ zeNQ{{Ul+5yl#$$|8!L;L{(g^hq9OakwTTB?cZ2sH4en|W4zgVGn;F4#O}{-OA~~MZ^5>?Zw!@Qw&mJy!CLS zUodz1=)M-k=DjVB` z*OpUXM%1git_t3ey9o6J zi*uD|86He$h8&^sIQIOw8?JroV6F1|IQQ6;W%FL0MR3{qGP}ly@p9$ZZ3(rsxkd{U%}}Uvz=R@PhIcQQ;uf z2;uY+=hY_Ht8r|8*=qqsA^$B_&`sVg$;gX%Z_RO0E_0*{TNe>x=OKl^sF5jI`vS8r z;h(1_q-^r(NMoVkmfR)urO>O0!!ylm;?vwUtJz~Wp=%Esf1X^+8grABHMcRD_7Jhs zgt^A8EqRXY-h%Q#8n(xSB$dj$w`=VyQ8Dr4(@B{!r^d1QwCm%P+5%RS>6*H9t)C;S zRuCHs(g*uxOvtL{N`tvmTMEY$E7Ld2-ntUJeFm2;ze^CAMFu2he1|%(^86QQUpfsc zUacyTSuy5_rcrXfVE^S1UeDl!Rfa?63-IyzqtWy1%?jn*W$lZ=0p;S-H8N?qefXgj zGU;);`Mo5A{_&a%>E@I=tR#_AF!CDbDv&f|%Y`|1dea+O)BO@I5q^poDXuhmx>i>` z2N#B)yLE^AQzm@+j@N(TBmMLG<)hd0vL!a^_4Erp=&3Osqoxmo?^6Y}E?WuzxSh)R zRQM@$V6TzN51Kx=AH(SC#))A}4>ZO;(;%;eVI?)miB!n7_w5LFU5>Y6%97&iGcxQ2 z4{l$ie(=99nMl6}6kDD3f~NX)lU!E>s!FQvO^&daQ%UsgSDSq<=GJKoId|7PM;X}L z;ICMGa}dqc$u>5E>;qMVYOJSQdb0tRMwv{xl&oHlHI)am6RVicA{`*?y4c6*oFA`! zwAO}yxd$>iaun7o9JbCW8~^H7cxW$R0`rM>hNtCmVw_mE*3LaS=#&iTShSQp`yDb37q z{cncIOXV~dV??AW9m7%u_2A3k#wvbhiJZdi>#yLr*51*4sxn&P?~Ot6z=G7YlTISq zp~A%NhvaPXRsPw9tRI@{#}cu!bkGftkx{X$m`v8%Du7^JyQmS5%Pmw^|*1i zdVcXj!_d7(G|pmzgvIH)#t~EPu?0qiZx6_NBf_j_kugQY{JQGc0#i&JBxMRG#*LPn zB1y6#J=2?Crbin(j@g%a7O0hrgD5Q&9vpwX-sW-R&ip zLJ1T-DkPm54C7sZaB@O@@1WK&>Lw{}!opRZyMe_}b|Bc*R}*ZI3B}Yq5_pMp&Mp^F z0pchhr|W|8t(LJ|=|>H(79Zy*W^$Ci=?2H~VoR=2ta2xB{;3V0#;H_1q+bhRYJ6jh z^L>DiaWERbm45TWP|;XsSC9M--=5)Rg?!_eW;bjQ4nN3Vs+K9iS^QMWsjZHsq3F@E z@=7S>0I@$$2!3z+tc3J>_LNr$%nlFP2L6#_4Z4QTo5&z-2)fR#29>Y<9G$(NO(5)! zQD}@WJoNsrJYA0eb}3mp1Mcc#V_*D8iA6w?sjB3M-P=YFK4r3?gP=+kHiHdWEZ9pn zlsV|yV&env&EgP&$6Z?lBUFq*GG5dMWR2{zp=^^)`0J{<-qTV743go#o%tCeY(@VoF2Rm>H6IDC1<|8=GRK;6WMY*@ zIeJ=Okivo#ZrDq|s+B34GJ9%^f`cFEbwgX*NstbTqZ6t&YQB~W{~&@mWT>T~k9`Iu zzcVscz-TqrYRz4ZBa(57V2m)Ura%FC9!>SP^6g8UWJt%q?s_H@Fp#)bU;=qreaSDQ ztx+DL@+}mhFN8OW&v85#w^#3Kf8vs56pv@`HUi6gNoSs>Mfn-#e(CBtQ2`lj=HNKrqSzQFR<-)wrNLpB*t zlQrv16e=(gdnIK_j)Uy^I3ZPm(p{WvSB)FJBbXu%9^bbW!V{upnuz(kztcB!nq=Bd zTGuZZ7658WXDs$*JBe5>JR(SG`re+wU4z~7jWrry`AHo5Ji886<*z?p@umN}lY?&0 z3N2=o!?murz=gck1H_fzHl~Ot$52!5upzV05%LGnc~ejcaEhW0C_kA@43h!&Ze18w zo(-8)+d+N#e+ispjmfsL{>65z{rPiyh7Sg@ti|q_$y3M~TeeDi=6)S@yX1*WS;=3p zI(Zfz=9x8rDOEa_Cw|1d{w&L$HA8Q*J(45|VNVwoD5Rqlv3A-xq3FwnoBhp9d+Z6i zXOZ|kVsO2++m&LpIiC^1!U~BsHyuU_*YptbHJMJ&5xSAWa#a)o(=aSd*I>hiqjv`% z#Z$=2o68we#EiW6r$oPPyC6^$Z{BP_po>TC*hf{Y3OYb(DLe49$j?#pKtX(D55s7t zil$sc#}t@S&{wtS3A#vOc7KHMkNRpRm){}Ss6P>47nFM6Q2hZocE<_1T?bKNBy{s` zJR*N&i}-r*2;S=DABN`t4S%~P%ez5pKp7_T3NX9-+bIdA@*4+N#;6FKJ93;-av&=qB`lM(eN zKoKwykfZM1T){o0V_H@y@Qb@?&AG{ZGn6OaCGgXNlso0Zt8B=Wa$$X!4O}$#a=Ki( z(KuIJyn-H+_*J=+72j)rvxmecJ)g!ca}mDc%w`@^lb-_S^({bzA`A)N$EhhM0o~Az z6M+z*=#R$&yatb}iY+4TcWtR!3#mJwvQELm{fA?*pC#~RMyQi$ib-6Bi(Tq9G=3#? zIELxGHohu$S1D=$9ph6&s6Z@ZQ(jcH%r;doU^nvST>owv1kV@8Qh$&i>9eG49E0Fq zFDk^`x=~98dZ|7<`rRQwG;(>3sQ6?6~LUP-{`SHW9{jYy2MQJe&7>gRy z8-i+*?GCy;6w8zCd|(>~ze%6^O6Wt^kcW%}AkQAtvXUySL9RVeC>c>({l18cNO4QQ zI=f$4j~=vBC%qc13(A4l5{<^c#;=ppK1D|+{l%cS*;FzGMpOFMwa{H+LdRkVUkO(? zWt)JGF(4R~waima%70V4HS8-x@_Qd5ApAe5n-Ta(FdX<{~@PRg(#g%;p_ z8OPcS5MO*OKofx%!CY(tLzWpc+X&#NQs&Zh5qC;>-v7sT-I;)S%S)rk@vg6pQ!%$s z5kc{cMu|An+V+gMB%Gdl9TskGs+J;{q9~f74m^oXl0jUb4mK7*9ap!IN8MbK;1ow> zLe%^_4&=BYVaUwXegbONoq@0uQWxnp2p2*K-*eqq@!G8)<&jwvNnmSBWUc}IEg_rH ztCvs{7RIHGxNIFD)N$9)>Xld)VYN6r0>xSoSTb8})f&R+>B}q|Y`>DtMo9)Aa@w3Z*kTYbZ)pVaLi+2odbB= zSImEx*nWchl7fS(hK`I<-EhK5vksPv4QX#cezvQgjvvB_@qty+)!xFb{hq+$AU1B- zo$O?!^|7(hSdtUU*oZK51)XO|ATtuqCkjLq8WVu*S1(2b|FOD#0$O>^wPtenm0OFq zauj-EgXQmAUU~UqiF!ffwXWyr>DhS3aaHo2Fzibpi1vicNiGGVSj}k^S{8jnN5-rh zDrJq_6sH_i8KHJMr~z;{CZK`8asL(uk{$a8vrFmXN+F(AWkv&86-PcPXz!>$mWTW`DMu*wmeI)QGYfLV?a+w~ z&GQ640$Mz;T-bdr^r1f1?ESv#`(!@597%{*)e|(`gOKu z=bdF4eQOEmxA@Ww6*7XBGRz<0K=&IV0TtC{gnD-(P~H{&zx)~zE*4DTK+EZ4om!1h z^x~9Z!;P=)r1NY@9zpgREN^o2EwFE@Jx2_#cvVoP0V`yP$;?L-p0n7SxTc(_(EFh9 zZ<4nrdI(EDTE8h8(!3ptIjT_C$G&fec2O39thUi2W?jv)0(b$oj3PiEhP_W_ado?1 zg~c18B+{E(tlciHh9*7}RpDUguEX}755wLBes;e`=H@g-Opr3{3d*yN%d$_^CYw2= zqOdL-3Qxz8SA;@uWZLBo{$IFWdNxmaa2>=RxZ9DYD z2z5EW+1|)cUN8j;QekWI8Q|8mh!ZH-Uuls1gDcxh&wFLEdIS4o(cTLV#wVO5P+l;* zYE7-;_$hC24-^xP1wvjdP63@oHbcvWQ}NMQf&@MiAeg;E6l*8cPCH3am%KdzeHdr= znIdMWb@2E{k~}2Ec;!e(#g7Bao>T9ntRX;aNM6nyZjJsao2z2?N#^3 z!F$q{e`QfZRUkie(Or2RECahND}8jD4y zr)N)-#LBHVW+*Fyds#LdjD$C^zFgLWQsQe_QNYK{`P<|=a$eDEse7XQJ_$qY! zJ@x~HUAT0tn$E`8ck3|s-~SeY2IgnGIe9*}jb*p(Lb5s|As?u%`KI=OYN01&#;4+w zY$l%?U_SvMdLpp;zZ%-_>c(<`0Fcr?CIa7%QYwExT74~4Of~gtmKgemA$ePy?=>B8 zXeE8(u&`XM1fD<<7$=)NS&nExPC`Wly0?f0b>qNBBc*okLyJ zNz9#7mi^GX5EbA}CZP7+fPl<5B#dqYWaR??Ck0V?U)V&^A7=AP zDPg-Qj>p<8Bf@tD*{iTC043(a0}6ZH2$i?Pg$F|EXqTF4uUds|#C5xXj6{9o5i$o) ze;0mMSC9sFojHS?R&=cZ`j?q!tL%`99Z;`-3K_^eG{)lFNfj@nWz1k&PfO5vwVGJ6 ziJnWGY6<#K2S@?@2rez;G(=HTF8h( z2}%?HQz8vk_?lHCVGy) zH`OzY1Bko=xbO;Kb(o3z3M9+rLw`nu;POlSnV+oub(2axL|lrCK9vPXtWakgCVpzkpKd7iYJC27+Ig7bYW_lWe!l?1UQ1LN!QK0XlTi z`9M?m{)*Rix|rL4VqkoxSA|~(tMvFdr2v7^xIpNpWkvTveC>qrjxdlN_(7Ht>T^3+ zsErW*gE(d71^vRYcEOrFpdtht{w;x;!Q8H;i%Rtosx&}piy&9PWneECezjzTx@$vm z1Z3Qv5|&G2D>VzH%G&9Ej$n7rBG1*AZo_9&w0uuhc5rGYe@hAnM!8E{$&Lg7L)2?PY^g!c&^BP2Gn$(**<2I4s<;8~T_GKoMTZ1ypAZ;sZCRx&Ds#;V;D@e%|^i@vFPZL8wHxljD5u&i1MMkk9u>dE2L0<&00ssdQSQD7rg9fajGt4a$ zV0MZ2{(u(sgMn0p@BnnFohG3NXKsUi?XaZsFsw`Z;oHXeR2m{iJmaG7whPz8$Uilh z*CycQj|_~%2fyATXc{rUp}JOS1h?Hu!ErdD`XDI)##nSig~2IOL@^au+!zkH%wWDY z8oOhJ8sSaOqoF*JnuN|q%^RfS^ALa{1VHkZ%SOQ@webY>$GWeXPu`-i(c?tXxxX|g zipt@!B9L2Af+@4O;hZOAJ=YBdFuS3Q;@IiS{32)sk*tpeoRVe0ki%E4&j7648u=j3 zPVYw&9Kce5*Y7A{0dwgd9yEQ89Gu)mjqqTbsYD4Xp|HO#ra7ANA71eq z3Z)CHr_XWzQgjqY2>Z9tZ8goB56(R#QLwR``7RK10DGt3wUb=Sg;i2s(1RQZe3M*t z`+arC+89QHvOq*UQiG|Gn$pOWu3n19C)uY;pl{3>gn#y@&aT1+@|qM(kyKaGEF8f6 zA66!R<|#q`79jVq`Gl6`=eT1Y3v$2fhLY4CkVtWMB}6`I%I9|y>io_~tPmy5-vH#^ zO-g$PDBIuU3m|uZmav}$oCCoW9f<}_xScAe1~_-gq+my>&&7_z5c^a}T`kSdD30u( zMn0w`%y%?hEvkOA_+HCml|Z1qi^z8Eyj<1rq## zJ2_9ANgGhAI->072~mL1ZTuXK1=0<$yz;C;fYb$GCI(1HRT zXYFQNf(lROb|EQ{(Q^kop$@;Ue^papxur zVtwhpTg$nzVaxQ$VEdXGJZah!SVXJh^R)Gv6={BhmS z@oQtz<{f4TJYR#!FSz2ey|~G`*Vl@^m)Er?hS1mF6p2$3T|n+}b|lIauorE>4?yX7 zaO3AmYTxVZS)G)i97g^@`oy_Q|0z>*PX+hI$v6K(K{8+!J;Q!1P=mE=2x+2wSBzyu zfN(ja@!47XEyVtoDo0^h-O8RypOZ9dctE{<^KMX^DR;e)eS_6c^PiQ=XsQ9QJf49| zVEe8`$@) zx%t;T%*T@F#v*a#`rjoEaJ!^LkLm$l&&|%(#Cc%Sld%!R`@n#_euF3`=vAI2m&s}v zxTEqHxVNv~CriY8Y0IG4At@%JzIHGWyoY4h4PEHk;uNHa0lHgEG@}I3Cr)`1xw}-E zS#!wdJ8^DZYl%6r9e1nZX}F;JwL3`#*KWWf>{|m<>^_Pe+jUg0d$cTarLcB-cPhX7 zP;oVGO$X)Le9~qwV^pcZiaL)6$ElB7nWjYC?mxk_Pg9%h?R-x+ut586P zY38=v0EmvL4RX~2_LFM)Z`r$I5dN+m+8>R@rQ(7Ezz_O4kbN>JDtmG3dR8B)MP|k< z(`|woOzKuc@~;+N@E5ld;jAu^ElF1D^RWbD;cS(*6W_C0^zt`7+6NEYcZ0h1MNA>e zeHW=;EP6!@{S0)iF&yW#tJAxpZU;#z6!(`;R7aVa}f>y z_}5}z76VGOx6p{7o0h$k>RN=LvS)-7HYoBn34Tu!s4F2l5InUhGP`$V<2;mO+Q+NY z=(7IB^AV%Ifv$B%4vhX13AB%j$1kLiUMaiVO-ARNLh>LfAWvg$CU@S?IDk3C77a3j zh?a{dk{JlEl#%N`pS~3wS=~jLo5BoCB_t*#?$0qziygmvTq!+%bA$C2DSBSvEuGnN z8VY{(hHqSfOo_94bvGk_=hf-VR;bemR`#0E@q>?DTPAV9OUn)+ume35v+om7pdVPf z1rN03%o_>^nkHbnqXn4W9<{7q3CZwz#ycipbueME!D|( z@2x?AyGWvd1Stn3w=SN7vo&uU>x9?YqDC*jl^#7yRrSa-a0mYj`YS=McTa9^oi}EY z_`=<%$GQ9->c9*0rf>@O{wJ+-b4r6XK%X!fY$2t@{8!6&AStOf{@hu>{K$7?+R4iJ zg}?s9E$D!ppVqYaNt6+RkCu|_glb!1LxwH@T3Z8(DX?=BWy+_}2MOLA1#_+{gY^@QhI2C1lg=it3 ze8WA>&L`Y1pulc|x!Y;?^&P8LzW=S@4oL3T;;DCILMc0$QC%<88AwCZPxc;Ir%zrgu~2mUvQQ@-1!&Q?M7Y z-bJEuQ)5uGd-M&mT-<@tMqcvZcFV~4Z7tt)oNmu6%LKF3aY~v*IzAuKv7K(tFhTmm znwIuG@ z=t_b9iS3teDlBkOV2fnOs;olGXiHI6Go+*1^Q%p&3v%4aq8_I_B3z+|wb>=v@2#Yq z`Lot{xn^#g4}dahS#33#+8|&ReQc@Ah6VYvJV5uuWJG}}KJQn@I<`j9pRNk}k*Z4j z@+{exd|q2VQxRs&=r=SlewRUIQx2in+V9ZPqGy8nBN}SxSfNt(m{b_jm~4_IV6MfU z<<#Nrw-Xcg*9>^QguOiw6gA0JeyVB)+h9mncd_eR281*hy15J;1N2_b5xidpTiW)p zH0Zo+!8}D-HTCCNo`3((xtj$vX3HKQS|&|@_O&f-}sg~E;1w(v>n)G+M3sQJ4FWTBFI$ zJ>&TU3;iQr4O35Mr^6%$)_2_qh;Ocy5t4(jpC2G+h^na9d&yF989x7C^tQXC zvl_O`P600+=qB(5z(DRocy>S|#u)vUzi-4TX05$d`pOeut6kC|9f`SZoP%8Bd}$k7 z;n`s_=I9qyL#v#`e({NnIr&{j6dM{lmlGUwrv54bBc02XsgPBf}S%%+RihrKaro{YZKY%xVDREt$i@hb+xH z%Ke`Wdq2MAN{n4&8KK_$K5|b=4lZ^$*aUYV=*ngr|C0bHk$3|b z`$$Sf`P8g|#^PJw{jD!InG|X$tAK-#Fd`gd1A4epKI68TkG0K04B{--sxN!Vbv%?= zx)PLA6IFoy@TII_%+b0&&_53`X+ueKcsSnF*4rZW&{F`}c8Q@U|4+7O#l<-o$ct0~ z&ky+U?aOypWGlZaEx(@?W4r+pfoErIKFwP%HLxLsg?@T0 zGbp+x29{L*L7fVgpA@qVzOklY+A*~c=Qv^yp*yLdQjt!0Ef%J90Yw+e9=xG@ap6<6 zY=$EdqYHl~BP7r7)xBiG?TVT7j?f3>Q>*QN&$+Mp`LrlZCKY9qI(xdLM+W*1`e%^< zlw3k5F<*}|U9Db~ovZypFE5DyX)wde>prmG3YmMm8XcQrD=l!$v8t)+pfPpZWW%X0 zqSw-^$IW-)XW<6yEA#S(-@KObhV^31Y!+YH7xOIpAn%%($~SFREQUzsNiy|vyNq1V z?E1IS{%3CG-92Vm73FnP2dA5Ho+h)Gc#Vzbt&(^qye@Iq5M!o1at+eW>Q?1u*aVH2 z48lJ-dmRnSsD|v&{I%gXn2JbkJMB=QSGgmB=S>gHn}9~+$eW?V?~dBJY(i=l{{6SR zg(sLQij^(?lKk6>zGyFj_p<_I=DT$>dTYU%rw2ANcT0youLWD~M2P#=`$*AQuJO{4 zqE{mB#qXWhKk&~1nZ#DOr)gatm6CodHYnv$yNbKkPnexpXL@5lSLD0vtWr_C`*pIU zrALUSX6)!UR8g8<7)pUKI5U+m(Vluj<84PJS}W$lBR>PP-CI6+_2h;kL;!QyDAM8FNQnRoubK z1Lt0Nepo8^u?62I-YnjIny)UHIk>1Lq`QEagf`;7c}(8$9R>Z$9La8q5kY5WzxD4$ zr>seR-P?6-sS#kTkrP|9$Qy1$}rgG>&}C zA0aS+mZPOGC$vLVtYy?2`lNK8>nuE;oEDq)`WDt(r}BO*{wgqL#COgD`wb;`!f;aI zk|R{Nt~c`Ybh`S%nzKcrq}Ktf!v~KP^R_QqM(!Lp&mY*EZTVUlc|hm_TkBPjrBaY- zs+yr63YgClv)3xU4j7m)S&g56&>)QAYvrv&Je-SIENOyn%+SDky8DCHUYK-TcZ^>1 zJ%ejEybxGSo63sYr&?hgr9|_ihm!K!zc`<x+v0)cB!b(uhJ$oErxZ^AZ%XR0jkk7w`C%bOe*PhUUuM!sn^|3;~n zIb|;d+;@!BccJyG+#l9&Q;ECzJh+v=Ed2nKKVJxst`7W?(cQz{Pq3d8ZisEjYgINv z5&0N1)ht^lcb|+Q7CpjCzjht84#^rz)po17_%x0)oErJFH&MLjvEjqQ+7MsZhs|%@ zfA@7AH6$g$o&!*S*;liGZgswOTrMJ6Jh{}qu6n(Xq?h8o2j_g=f6Oh&9V+%NVzdXKYBhXdBw4KFgvVs&CSi^^Ks zk`*P;i$Xg*WdA8Xq^ZQhehnIG9oAteXP^HqFoP$e*^IoC5r*wDbS@$njIDEY7V{L2 zY@|sBD7{{ssJ^w=3qytt8s_VXTy8qzHf|(-<2Wt&oBdg@0gs*&U6W+Ep^f1{nnDWS z*H_1CGqE2_8vJ^ZlNw(q)444@#CflUa#6ltsIDbL(AX`B^87g!L-pLfZqK|#nl>t} zLdTaWM?aHe-pH9XwnR;H%Mio#*Y*LI6*68smv%+?S6j(-&J(qPfp)I~A%|9<`z*$C z4t3rX&QsqW#z5(sK$}v@%JxN^$d7U>ehz3zVcsM(dhqUYDM<(J+9D^x&j_#a<(-Tl z2^Kncv%Xwp{9%hX$jdB0f!E7&;*{DI#DiHgL*=hE<=)A?!w}y7LmpqP(LV119R9Us z`AhPMzt?k%?n}ICA}_wWq-2ZTb(()}yOb8#NlPjoQ&BJndf!_UZXYvOF1~GL<%kHA z8?waT%l*a5peIPFb_Kz$8v)1w7^qrSG?qF&y(rv~BVIV|MMM0JeL>^3SKPj4`z~%P z(_EkaEpdpw`aJY0<3sQC7js<*@Q<~{_MwIU4KC%^?EY+36Db|0h5ukbYWgfOw;+^) z%by~R&SNhm2bSM;pFdm9xZqWjOx(t}y?yHPeF)7Yu%|*Y-@W5i!G_Jan)4_~#Nm82pQBtCv5i z&jn&Gd}WK>Dw5{ROAEFj@Q&PsiIt^KhKc}_{Ozq1}z}c`nm4gK4%}u@-c*m&J91@wvj~ zddS2&Y@CYyg#vJC@CV>Z$dltkye&K?GHLD`QpVeF#vr=&~2!nSONS}#%Gy*6>Vy~ZyKxMnwR=p5I1pWKv`luuea z?y>T6myR+JSdt6m!QTCyFWE5DD+K0-oaKVY1{a$`2V6EHIFP_-Kpz{@ec#M93ot3s zS3%t4dP&?I7Cy&*sg@vLj%2($^1;1#?W<{2p=jyO!@DW;7HUVKcpiZUJ5n(Z`bUxo ze5NunF3n}%=Tc!a&+e@UigmGOBN(!O6e8xa)@7@*{kE)>2DwHTTFz3j98yZE0_!=mwMd$a+$hcGJBx2 za`k!`C)LKqMnmr7%ZzlGoIBB_*5~r5wyr50n1;}JaLgA$yX;=_FlJu`?&v+ZJIiB= z>fF-5^pgEspfjU9*l#1U(+UfX>s@?S!M^brxIy<{Sfww?S0Frl|KNbZjP8_r{qfd7 zhZ4i71T^Tu#df~$>7@dB4{OISr`G@(=U6Um*>A8R1_rFg6tJi~)>=un;b2k#&QEXMCWPF_tdBQhGAMahGmMXeu z2U*^$Ju+8pv650Uo4P9l9EWH7vi)Y~Gl>fNt|MgdY zd(=4)EME_Mh^M~B?7)q(<2k+@!xsc^&%qcl?FL+De&Z3TbP#og8LHYC>mhW-lcRJL zxb-@?b@R%X+_0kh>2J3{*ZxtG(TMchVO3yhosrN?;-!~xmdyxR2$pgda#u`LK$0M0h|9ti+L? zH%%I~&;h;LXmJC5Zfaj&(pgjU&L1`~4@TB`8-AOAxa`;@mYNxmQ@Q!jckB`$HrZ~- z3DrszE!*=AVyENO_oGBAFfuFOyLZn+=K|88)sISHPPOwL8jScIy6JfjFw^28mwX6y z_>K0vd%*49zM*fv(1eeCacc#Lb#SD9@^|3MxCyFeNBHgRv?o6hlI3D_Te!_AI z`d-PAGv8KS`O-#?xMnas$+S$j%I(LFE~uJT|8~+$Oz!M%GmNA08l_G@3~$e{fM1F` zW!^99z7)d9PfPQglJnMnlMU7GHC_$n_|DfVeFR_m*+==%DVW@#?$@m)hniEca`P> zrKk_eHj=?qKO%?u0!9rVB{#cS`y~>G4zhWf_!~=3`+8w#DMbhe$an&}{Ny|f%VnbZ z#*r%0;f;=49rk6im{f)}vOLBX&jnFoZ+cSc)_|Sn%z63Sh2Q90e5QobbNhN6RcFIJ zv5`0tC!!YOfEQ0@L}k0LMlP4o&tvcD$P`ZUh5y=RUxJ@gV19Y7_MALMulTa()V*^P zE9T`_xSpG$Uj4WkqM}Ci%udH!`a0VI0=WHo+3oxJ0k?+fj{Wj~8BIVb^UF%XGhEOo zjhyqD<|Mn9=HKV75tiYqiV$dR_y-D^oIkgzv^C2(^3c{aqT!z)y^fe)GfZ)`^8F1B z4O)d%T6Eme;=Uob9sy%iA{~@l<-)fiDer9d6Wf5PX=}e|-1S?mo!XG`WOU~D^DfN& zu0WO%w9EMw{nUQUAZ)7$ovw5)Tb*}~WYMMf@n6K?C z`GrG1miIcx|>?(0qt@+QKxcESKQVwsW!@V+Q-#(3xvt)nd_we~l&G=dv$MM1L z8eK6-$)QCbwia1fIk%a;e$MwES8u9TVZL7RV2X`2mtgdES1-EK5o1<<#p?{b?pg+I z`6h&AXSO}(`fSN=KuaUOamFoMBYIw>tOO`;cUE#cRPF>lmM`(vxSBZa0{P}6w_dSZ z<8#Zeb_*SPdSX#*a9`OJ6~|Px4#AMj%vLA%9f1QnJe<0-&rZ;H!a^Otkh3s|Ke>N2S^j?J|RhpHzp5%7aUqCVVC|!GV ze=DZw>#-V4fI<8T%x31Bj|t6|{=~&nm7Ukb%nSTmhuJ!2rYBLf6i3!heRI=iMO^8? z097#>9vx`n+UB+qIFVr&$l0@|6$ha+lY;u?y&BIvs99=X#dS}Sx<6z6?!D^*Mh}xj zlq_ZUqS{Htj5yO!d`vr(*TC4>@wmzxW}!*fanplFOR=|S9#L> z+lQZb#Gme|<}?!;f_QG9pyVdS>T2w=H1MBq((G~u=u%r#sr`di}<>JebwhMGG+$WZok}?Wt z!bV;ZXR}Q}2o^2AJF?)tfxzmqr0&Q4VXTr@;SY>iLWGMJ=5&71myE7@MaO(>w+m`* z{SH&8nJkm0iHM;+{Aer)4iZCh(fOX0FAg_rmVY~`1dKx`%1K@$;oZZU{qJGE@ zO}#GVLxDR1qY~fX7;_VKP&!=T9Sor?#nz4xno!n-_wdKf+yg*wmLT$8+90p;H z>)Mi9)FbcMCaW_O`hek*NAHt?bD3T)nw2Dyo4Nvb3N0tj*;Q`~QJPreFM&=hf4$Z9 z){zh0xQ~2V^2ICjaEc31{WgHn`|H`XkV_NyrP4K9o`t%_%h55 zJ-Mu08M`dEm`_z$@GubkFGL{u8A>mn67cO>1Gb5yZOG}pWp5Gk3aFM=kvNA*ZuK$ z`oc&b(44t#XkgA`i4)yiB{3MgliQ?Vl3XRwHzkT!xt{;P4E4l{@vkxRV47e5V29J? zp3NE>Rr60DjxW(+gYP$7UK{}RTb3Oq$9mO^v{C<0rhv>zzPFvh&#W-%DByeh6-?vR z4)jjJIqnSxyDg7bj)i6eN5(a}OE}!9uwwSqq56O)eDX6_p-$1VZwI9Heh zZWznSu2>*7J=L+mPCy~F@`yFczhW$r@y!zhK!${S@ ze(nd@@I`QJdeP@kYMz1F2uBC+4mlQ2dSQ8$#-fX#%D7_+$5`)od>Ei@Q0=PDbqp!r zcuh5gS4nZ6Xr|tmRN5?Hjbz04L1}GQ-XdDyP@pbSj+cYoai8 z1_zsEa6O{Z5W-yd{e~vtwMH^-<<2>(SjIJ_lAB$vE=`NTep~s)0lP^Ame#a*0Mwfg z!Zd^!Dqn;1a6EyX6m-iP<|GU>K@)`%z+^M9}d;G1BqkW zhjQ5nXRE44NzXBx_C~ z%$?%XOfv<=(#1=^{RYlJpmrKH(Jt50{YU#8INbqfi4B8Bcx^x=s~Vq~C;M*45vPL{ zD~GeAAGx%~)00v05 z_yiC~)QbCZ$plxv?l{LJtokkuSBCl}Xf7xN7Yze-h-!og&2eUCT`?mriu(yU^9?~fJm zq6ye^)xAyzP{>gPwyf*nKw}aB4%)>9=LiVXc7^QRyKjGzX`=i;Z207;jC1{I-ITWaa%SN^i?J`YvG-8m4 zJVk2@lW@d$rQ-SNQfSQ9vhS6M>t~s4&OSNjL8OE^wA)bjjw-vd38&{q@b6e}qmzEx zy5rewNy9j{&1BcQ@c!=yKhg5Nmg7G_ki#tVOm_o;%@@gAswH}%`0m}xW+|d|_~FD@ zohuOHq-CN$Li$St=qWz64`45g5({YNC^N}|e*}gM+8*nFf}uv1KRyI>G-plG57{y0 zFe<3&JKWcgi+QRH|BD;}yeUioVG(Z?G6eYC)a(MJ73xVrPVuXrA;&QDz-<38^i;Q* z3lE$?*_1)Z9ucqYxqm6U=Np4`J1FG{r$u7(y0g5Cj| zZCL*!QrlbiJ4Yhqi<0A~B!jjyGr*;A#Uu0Uzr`+iNccd4IMDtJ3gNSFkotLiZ4mJ| zOfv8>=wG+Mt>0PJ`ZYS2f3e2REgoK}`?Y7x=zN~r70|DOED?y(!noh&gCo%1gDG(GUEy%;)Efx3H4@aS>C%qQ%v zhqyVkX)I$?(|ULdAf|POX*Ys}YvBSNM>tp$ymY|%Oz2`s)O5qFR~kBlxeUq0i!|uc zo`7MEvjmcey{saA6@{{q$CBe4H#5R|QUGuI-nle^4Ec^w)ZE2CzhV2`@~a1@_mj4N z12J11z%a6km6EzZRV%kuksof#qtvoW00st-w>qj^^a8pUo^&ev>h}5iKCFFwhJ_}? zE%~>YD2AltTVeMs&_b@2za&1ypQ_HSSzsq_7VNyjtAm?#1aw*X)oJp~Ev>uSHZA_| zksIi$n;LZlsz_ZIzbV5lxh;K;YxJL#fxn&?zDXS3tRny5uX2|B-|#;a#~dhmUP1wo zkT}~RXC5503Lp+rx^XT^jyK-mSw7`Azbyy8&S&9UJ3}doOacU^l0>`?RRz+4^M3f^ z)c*l|9%(+J7Cu{n{lqC~DY*wRqt)ByYXjl9sUYU|i&XO@vsKn6MS|$-X@do8Ia3=X!XqrHzpoXgWnL1RLHy+ZO%Qv*qQzP|?9eY(sLl3}ZyM@Jukjx7Gey%WeqsLf zfqdic)Ufd9UBCV2$044R(~2BYtx;}H)vvxi%|mVjNM>Nbp!_0TslgmLip^lu_8%59 zz;ptv2b#5S;ATr7EJwVBJ)?hUS&lq*@DsXzsk@RIIbnOQtYW=8V3eY?&}rpvEeu9aJZrgp7@dL2MaevoJC=uiCF@LS|D95+vvA{D`S|Hhm*bLr~s z`|7@v-@WhH0t^uxsfdsD!??q&lorT>VBwQVWSCc0aSg<273skcWfhy3rJIHcV_8#n z&d4nwR%NWr5rwsKN@}Gu2*~e-OS{-+Qsp~jG@tKbjQAD0~WZLV_3(Ey$1aC z^rE6m8P`nXtKcbbIFVa?#my(U2Uo6zf=VO4Q}yrH7z6q1efZ`qRCDP)pz*+MTX^L) zP=i+KYzh&M{!0j0K70nd?aW_W!x~r^Xuk!@mTWPVmlR^e+S)Pf;1Eyt`(qp2=gcn@ z-8xpec97_-&J6}*o|NmC)P#{3aa1VNA!D7b38cZZR9b|_@f%D&VkGNT?9r0GG?OIH zY}y+f8t*L;dxrV}KIUE*Brk#4bm%k*A+BP>G&9)e_i#;dkR}c7Mv~ zmsrbdbX1%E!g3cdaQwIP1}~rs_wndBsa0605N>2A4;#kSQ{YJrl>*JEaY( z8EMlf8MV?H)0U(%Ft#@6Pp|oW&@N$^<=dZTX`U5;Sz<+>ZU=8M!z*ZC_*j*z?tCnj ztq4#r^Gotjpo*%Vf#_!E0RyN@b)jK$U5+Q^FyXYR-E%wZhtB#S2K|oJC&C_Y_Eg-R z!6_Qm_exT#>%H1bTOsvJQ+}22(LjZ-u>1TM)j{c9ucCL5C-3i%BseRZeYv#O?izzp zAAkXZUUN=lE#<8Fk4~PARTM82t&LIeW`XVKFXj4S4ZzZZnr08p3>Mx6gl;V!fR(Rh zdV$!fxWTaK4F$cWW4?iI(0M&Y$n6RRurXyU+s%)Ls2yhh#12x&*)c4X0ZpRTCwtv`3Zt>q$5`Fdt~e|zBow0fF7=t2oR z_?qCR&PtYzFW2waavH#(7zd;}P&e!NQQZ`yT%mn*b6XZ$;|(E|1VT_=G?sB57KG#a z4ft}!c6x}=UdM9o@JN!>ny8g(DkSAvGvDsc0s3kT=K~yjI7$JapMv3fSymdR@j5)Z zh}r*KptI{9XzR6Ky+;~xJ1V=QAXqDlP&#Ixmi6UAgg^0f{bDA=Nj}agCy>mJqDtWs zFIyLz;Ag#JwR!NuvlGB5(ZB}d{Gmm{PEfv(^3RD|==$B$t(ogKdtix`DO6T__~t?F zZ=Rsv40r5901=idM>+yMo)Q=wEp2BK2CRRmaM376)oq@(7gwpp$^Gpm26A?1Sc-Ff z7ElNJ=H_l>!a>#-C*>%RO*0^#N!nvWDptPHuJB9^Tr=yb933G_8Sv`ko5K&8K|>9T zPS-mDb=jAtJO9x{`ZAIzrxZban6{WTXw)JB!E_<;YXc8q-EH+8g5R2g*E0tj8RQhDXOu4uU84 zspG1R_jaZmjqQS$?27lSzsU1(jzyA!1xsI5ImcT=Z7Sbf(|P6$<$RVZhh6>riCYKX zG!3Em_)Ro`=x#q&Av}9RFOPlwB)WN?o#1cUU_hXnI#vX!-s{Hsx3#q;ijI850rAo- zXlwh&bHSu!0GY_`lZ)4O$dLFzgCff4P2ogY^E_pa>h_HscTZc>ykoS3EzZ>nE%SMo z_;4Ku#l{uRu>W>W*@SIp%pLzlpIYcgSbJe==xdBp2pj<6fT3FdZC)=^gpwfoe;{nm z)%2!^p|-}s#+b0#{6gC6WgNSN-?mZ$SZdSlx)IcV0t(TZN3x3s{UjU~PkcvVA&{x> zpTBqgF?ObnfXY(dC$dm|3dQJ9*V5Gh8@m&JZ(GPJgiq|>sCvrOZ4Ka`_(+#nDeth5 z;MU~;gjN3d+cI#;xa=GEzIm8vF0sl}W1=}#Ep2DXv5MlTS@P}GYT$ZT5V&)YVD$C$ zGoh7q#p2mnU7?pf^j^PJai456=22~mZ2mQ~L~odKUlZ0m;&@eg=LW`y;@V=vT5;`V zP>#X_I-btiu!8J^MM;_aTq*NvuCYN2jsone!RrNGr2|G1_&q34#MbG$_-C0lo=%3S zqYuY;*Lla;L`yt9QR^{%-Q2OvtrmIDQk&Ul%jQpWfYKT;``bWo*pVwv&Wl?fnu%7Q zFJhdz^e@s3Cux%8R%csoBKC!!vyA=x6$xwTo~_>vxe0KItYu)sj3LXNi|aru%KnuRXJsElf#;V<;lxhn%Is^`30x;9_koG8 z$1-b$4YPYM&()`Z3AjeNR^>DxfQ#YJMKL8SG?R4Apovac*9SXc2cSHW1du#(dEIV{ z68qWv2S-OtZLQ_?C!(*CAQ(`87&az3m_~^a4jd=y3Dz;bj@3esin?s=3OG zCCFlx`;yO?9l-;SE21i}MPRr)e3WPqp2kvM88=72d)LDwP)coyn45Oy7x2`8Cy(@n z$CKrTO3v>uP8B0!+J7tv8vQl3%%-nctVfzw%!Lt66d?trloxcO=Z9 zQl^9foWHaiS^=hPsBUj8z0R)tSoNWCUP3h80S3L~MWwrtv2zRw3Z7;$nxqaH`zc{pnQkW>n+bW7{4w(^ z@jpbAQUym@YEZ-rlxvt zP1EG2L1S*EW7(OD3~x@tlq9$ceWi9?HRUWZ5_lMeweLCySRHL#M`rilWf(OWa2Bwv z@f#gxdK57Coctc1s7!M=GzHBgA%N=>3wf$D>|aLnoj6eMW`tAa^xYZSnm_YL%a%(t zXllHs{Y~WpN-0zh&$9taIhu!C`p*@jGAjEk&Na57APe@*h{3mf=njKQmBwf6J}Voj;9&Mkio{j2^ocOy4sa8DP&2P6XN zuieW9baBw2lZM({f`>4Rd4LHG2NEbs{ad=@fpbs1hGuDyJ*32Qu>c+8+!VTe7QYJW ze#E;ge}(PZOq(!JE3eCz+G=SUku4!+E&D0A1U!l-@$5bS+7=6o?*U(@OvUWp@iCo$ zq68j{NQxx7^75a%h?;9EZ!n(#%rr)+9-TEptq5rK@9I~N@Ys%UC0`z0s7MRFE^c<_ zBsOLC@%P8@hN+ewU!vf(Zeoc#+MAY$jfGATM9N(2u6ZwS;mI{4fluJeDeKY_$9r;iTr)#Bk73~_|=Muf?ltix+&<`FL z-fG;u`s(MxpznMGj}I+JGZ={ZASkwY`Q)d!`k|VCbgd@nJMn-U!PJYlPCs6V`ZsD> zA>REE<(8djh>y~He0FluUF|-K*aEeD8!w3*&}0wYS8SDZyZUZI@3|VoTsZ@&oE0^I zXTEl?Y4|eUM*u1vD#oL&Dz&n1xAK81Nw8$`v0XL7*Tb+2Y#x50i_P_s#q`ZGHihAE zE<2NZ926wKe0Y>eLRTY*edRcPotZ-#FLPWg9M68v6Ubwx=OK_SUQw(pvaU}YFO$%& znul>HBg8|N{!f4cA6?1|5Y%AD$ra72yzASOfQp(Ed?hreBX#8L#aS`^udQ9-tCjbE zB4oD&Ge=^mAR)GH{$O<1r-|?;X20R?2Hb{QKCXd0$-wtSKfs4~XgaS+Z2s;10Nm3m zeKek1vH!)C6;VQ~KBR6o5@+w#FQ)b?_3KX8CcoNx5$5dgDrzx6UN$37`hBUcg0^y^ zX+fq^@JCmzj-kz1$P(P_>?@55wtr|nhx{kbctHWt&y8QPEPhOH?r~OwZH(C`O)Y6C zX6sZ@s32>w!#PkB2_GlPKcpgQe(1pJj&MvILg}%v?aGt4J+mUK%_epw1Hb{2n?0+1 z#gT>qy-4$S?pIkN>GeLKO1$VNo1c*7UzH;_BWgO-PwXM|*G80%{8c)8c)(6NV^Xe_ zhIqUG!6f+&YIoV52&{NrZ0hLB#Kgn}u^udMTsf_m=3kPCZtUuRc_;qsc2#}r(c8sI zByTM6R(IUhJZ!P1S=m}$R`$jl4OD|6A=tm^CS~V!Y$0Dbai+lIXBmu2{-2fw$zMFU zY-`^PA)4csY5ykg`&ipU>0SHIuS=CQ&8tThUGUhx;h#sVsby2RVh=0KHC;k;{gMQY z`J&1pP5I>AAabSpUtj?+kh2w-{X)oetquoV`!w%HCYyx&O)LUBG(R97x`l;~iGs(S zC_RNdv(O~jbnSCUcjunh{o${qt$)XTN8%vXgmmz2tM|mZ>s-LMsSjDbIPr4}>2sY4 z=JCX`Xq&cHvJy%Z@&7Tiq10gUXbcB=+}<9xfe#bM!)U>1-( z35mlTJp+cxvgvG{NDOKg7`vAC!)>=y5BJ({6yxz-cc4esUXAb0`>s>D?henZe!1NV zo#1!krXZco*#vc>JeHc=NJI74AHx_nlKscNV#6+dfl}G&?b_M;V3CkxiAbh$bhG&r zIwjs!Gzq-=4ub*G&Glt%1luJuGBzVPFvTom*Bw{m^77JSI+>spvFxcXs=@!uL6DO& z4Al0dfTMG38Uh4qbrn>ClScX=|FbW*jyRc)pv&FYd9W~p)4$Y-8r>A43_0x??Y!w( zI5%w*+;%A|jxeyZyQrS|*Q2qTKDnbfU7}YJlm6L|K3=^d`k4&+;F*T`5!{>P^DxX^U^WgCJGLL6j5(0&XGjjdhS`y?w_!(OBLl|SWY$-J}ZNMAK zDxEF?i6@Fi9s=Pp0+QuoSmz?B*upwgT4a~!*VU$+irB@_GRa*!WuQzHM?%%U*D!4YfL&i znPSgq@3+zD_07P|U)V7_OK*)xg=qK$vqx}!V9aac*m+*Z(vpoYEw5W*F zIdA<;*d)Yp-H`Fde8sVk%z(dIl>3S})glQ9!U23xL_i?W(w9Zf4>}F)jd(QohK-wJ zCZevRw$6gL+xju2*?2IFu<9lCp%K@?NBfVpitkQ1sVGE5q|4b7N-%p`jzOZU8nlrg zqeWqWIe~s1o>C4SY3I|wZU`_LPdj^+mx|&n-rQ)HN22s!f7e~4L2?njN`dkZ;621e7M2|@b90rfeEkTH{ z+UY+J17`3Tl#O{s)AqE4k@OFr-RDq?u^kBUK2b(^UyJVH1tBuF#eJ!d<$@5`mJcgE ze_}jZje1|At*opZ@)GmXc!^Np12^rp*`kIz{AgT~k;eX6o?~stUseMm8^vyIpKAvB zYSg7{=t1M#4!KE=i@%*8hd@~Jn5{kyUC|4qaL z@=X?zuqE7qMt*f*bVJ$gJh{eucJph(wuq*_=M-0HQ+!qM(iLN7?;XskeK8g; z)L`HQ2OCH_9S`6%FZ5kx-W+v2t+8CA%g~%YOaJkTm2i=|+on62Hq~f0yh+&a%ko2X zcxT&y+tT)G_OVb8>PiTm&2Iz(uZ*N@N$|!VbWan3CzPYQt_j+Td3W8hw$ZtGza4=8 z*zon6kF#l|i?!ktiG)CEP~p!y%R)A0%|eKLHc7Re6{Rx%Q>`#kW=lFd^c^{cswUl~ zl->M?q@3L$dxBvIg5{ z>mVHZL(=qc;6)l+&;)5qWVb%*W2y^zyW#h8*R2>M=z-V6Oxu6jYgp)t0T(<$J z2z8vCEQ+lRL9<*M}DS6MpZhi$B7KyuHto&*fiEp+NvGa z{a~aiDv$7g(KCQye-aJ4PQ|;J`g^eC@iQ9UC=LmiRE^if{QklEu;aPZ&WclYzHE;g zIUA6o&{U!4z*<=T!-huoLL2lLZmizCt=4)5xM)ApG?Z@b&Q8bk!EVq_`5DwoM+$;U zzwKUH*LX(QF>D)4_J5fw8C`aSdOC)6W7(zMwnaqDE~=KQ5pvuNexjZW-#+usKl3+r z3E`Xb{OuS;LgsKRCYhruML9|oz3zIpoed&K4Zy9rTOLz&MR~fvfnMbw97}id?4Qkp ziBO#Bns4wp!6Eb@#A#uk?T;`G{IQ?S{0N=O3rkM*Uu*wUn+ZhlsSTI6;wS?)QRus6 z#YO{Hvh#xGLInMLa#(1Rhw3=MVXhgYH?k4wM5Txa+chf^u&-m~EI!j0Ok^D<$%oPx zeq}H(MDH;W7DSXSdhO7CDDa{tE8?!xchW7&x%s>4*sQgUt(JkX;~|3pbDF(IL%Dn8 zf}fRJNVW!|ggPM0s==4%667x}HFsPz51{_t$HpiY*wswWMI7K0*$>>(KzhheWrWM* zj0QFk{WJa4yGyvVg$WwnG$~YjmW^GeZgs`cSBfx#D@k|#UNJ~nGDU2VGReACA=rywb4EgS$Azyw@nG{1UVmk&h)BRXZD z%ewJq!sbrMKv3xpNU=k^j?dspyz2rWcEzrNSKggX5eA- zadLl9noF>WzbQ}fD(6El`B75zv`VE-wfB`Cij3!5p&S%Db7%U=B_%7#zmpx`AqZlI2w&UPbA4j8`XNgsQ4r=*?4$9?0G!IjGviFZ>UZSI+wVeikNf|krCQ+i z4L8AjxAZ~AIEZuf*1iE3fpx9ULi%D5Yw(+CT}X}H&z*4M5YITu)axr0J@ZW(A|x^`eM9F;X4iMDz2AlY@get9j~+rwE)&$^JOwSK?{H&xI0IUPwyU z80>};<;KY|-0c=G#v(P!!zP}EZCqF}Z;8#$L)vsOtb0=Mp0)7NLW%jCOzs(frEG~6 z@pN&N@pJ|B)3^;g*~J@i!Q(7NN2ev;c{!!I`?m1gA8@ULZC7Aev}-BSvgJ(;UBC6J z9rfKtKGsl1{i7M#*FdZwGDKs4-WLd0s@G@5rn8im(Ff;e&n7#}$20DU&mi(eIc#t0 zNbD#_-6vFVZKuFV#T>zq(0ukUbVF9V?{Z$lh#L&zjA>)hTZt#qbO)!86b88Q550wG ztofL>At=qZ=MoHkk_0{9h9c3^umyrKi|~y-BI= zR|wBE>%OdJ!EKXbC&ks?4apK{xvNq9dL3I{huZA89;iC|d4Pk}F47&iQPJ^I>IN2W)G{$wz z(E7n0m(+1KmKv*K_2p;A|C|~|yl4bX7Lvx?lyWxDy@s2vmxYIzIWYjCRIA+ zx%r`8YfPi+Z(fA6V51)1kcmr8yy?ZQ#Qd9jtrW?F*|XW>f}7^$B$6ZyiLq0maE&nA z(0V1Q_UvrL8hVv?Xtt^`a@@xam|gI7>{~v(2PzdHHl5#g3nH9&s$*$VAfH3j4yA9M zB9NUl*TOInq%zChQ@@OCbvr0|Jz%Hosy=i|vL$Wn++pYSApverG1ONAza$@NAWuGo z3{{iY<(dl`|JMg&3=otW>m#HOd{q!*dwib{tA2UcRK&$gQ0Ol$e0q14qQO{Q;Y-`Y zeo#Y!_{Us#fU=ArA9`tT>|V@bQop7kX2$jM+4qg!n1E-J ziw6RZ*$zbOgQyYw*(y|SRUZIJz2@TZKz#poj%uWFDo~mR&->b_$HK7|3a;Mf8`m&T z<|k<378s1b2<6TjbD4nW?K%IworlUORqbrh4Pgi}3F!>+b_+JeKz`6bD=jFYSnnQz=L-CyGRdc(i}5e|FgfibHOJ53{yrjGF?NJkv&9~guE zfq{iB5$pNj`|MtNgYUmI(!xdZ;bm+r*GGR^M=gVW@3^b>BM-dA@t(O~T$ZTcr1LlF zPVx4Nlds6#53{jM9KwxKG)Y(kG^)L;wr09jewAkws6e^R0WTA0i`Jn=?O~^W6mvr& zF4`jIY8?mjO2XsS(P~pt5S%%qT+cj3LzCy!D<4R#qkk+yZPKV1!8W5f;>snUcIj9x z)%}Yb%A_#4#e;v1F)reirBsCQt_G)L-ys%wd`nJ!3G(z_k0R&7=!vaog$H&PDcj5PjE7t`#UZ_(J6T(7SyLtt!2OQ zdXRA3f4jLUi`;0Q&MOM??|^jbSo#en%T4il%W)dLhin zNu(_pv8oWXrSsE{aE2WJ?rv|xJ?72Gh3!wgNcfy{Q`5=Mmg)q#Ld&P#z^4Z+Uq_J~ zV^4gwmzPR+b@M;Jntqvczet#c43=uKr z610l|Pm+95=A*H8{{mUH8-3a~M|)D?vOYr6Ejip0E#rx_k)dX31z2 z)^kt($)smF`=y9Xax6WO;m*{*33t&wH^)=GJE>8=$7p}EMyxN{qaM(^euiGi_9$qv zrF!7GnQDw!*IS;Q9y`?j1)lonfn%*M<-Xb}X#7{j*x7&~{xF=z1G=Q|A8iJ^OkEG; zm5qyVS=y5NGJKgtmw5zK3mx@W0kD zb{C2G2I1dj;Mw^yq)U=eFppYBZ_#SiO<#$l3Y)tVJ7!XmtjTxMMiEp40L(Cq| zHnQ&gL(iEZk;=>`$=l}xp#GUWpMDs6xLV4qS(5u zO0#tw0N|dE0*iMsVq-nA%3`4EX?rJuZ0d@4iUxO|a6k8~S)7EB)jXv9!O#p8$h4a*sSaJ6rFTG%VtxYdeZ=HpB0;d^xkw|+463@3zv_M51Q{u~d)B|o8Q?lHrdbiyfBNtVeXGk)@p5e1zG2$_ zvkVE~Hk~ATGw=2)WEW5R3CC#g< z&Og+V^^9*@O=p@CxYd%`W^WA-u_$ocZ{ z)21?OUugGv>{FYH%&Mg%3m&@fHs0py9=@Anw@EipZ9P&Y19AD=w&*5pIsX-EWTD=- z)cpQ{){_1Z3%B6hj&=(ISrfT!q-t`V4b3;C_0%3lV^y#40LzGRwsDO-S54&3?k>)7 z#>aNQYRzz6{E}~7I<-4M+mEW0f~dnE|LA9&*x60}FNNSw!BvB06ML^e0LD5uDU~PT zm+%D81a2&-W!B>NJVTwL_<<$)y2ZFAG&ZTl5K$Lokkan!cyW6heRlX5osMjgwW}7d z|C!WJKDtXmhs-d|D5-l?^A= z>^m(29&tdUW1Xz*d+4>)!s^Swhg(^2w4~Ye-=TKP0sB1-{Vf@h2>Kdp?=|46BlI!z zm&AVa2*zw?I7CM3zer)w4V17Z*OW?B7ENyCxAWjOfz!^g3gk4koKb~AuG24o+(;ks zt|JjGB8byK8flK%!;AEMe)7rp_iqN4jElC4t<)5a3t+8lVC~i;-Nu)!@t@dI%X0IH zOcI5?g;UODiCEZDafgN3cM7p$i~GzIy&RbxKk8iwo~xJ&WWU74P^1XS>kGNXF|(lP zhrpHXDCp_wPwqUeS1hvM2AEMXT&|JdW1%wZ9j`VXbeRVAN$*B9q5eu9O}$Y_+55+9 z6xkG)26`#57o?FU#o}4?sGvS@EENA=7_E-bkUwn7h(OC)XqxskVVPZu>Qt0XpF<|U=#Q2rnLcXN4yq^zD( z-H3Pig{wzXEC-M0=cL5-=)EMeJSRF4z!aG+RZ;K{zdb+I#BsEQ-}Lm;YdO~cbuJoF z`1qSnZ!P+XDFT1!nRXQa_Zgeeb>zK5-HdSKS9eO6`7o5vpFPs~`~(c2BxQ}{6`0Oq zg6(D`ck>~`9yXYLDWP{}X(lY5z)HQuBlv{O5d8)x=A*r^DV%^{ep}ozAk&2vw8S)s zW;C}YE}FH)P{Q~BD8+Aj)m#KwtxER#r_)2qcZOXx?bvFzG=mP4>e7w^3Sg0t?ekQ2 zo%`{j##vS8E;#kYK-;?^6k%UfozBiz!63;l+_vfhju+fS45LJuBV93Q%A)pIG5e%%KJ1nHdes0GVc+F!AqC0 zi(&Mv8bb>E9FfNyE4lkwbvNQFEM1iP zCwvDT6) zJ|8ej5oB)vm6yk&TQOf%&1cx0h3x2ZAXB*d1tsOm6}7eX zDI4OxTjro_t9MR$kj{bm4eJz&{!~dOp~SXVSoc{P)7U%4Om*)l!-Ah1ZRR zS680;X*CaDaPXi+*vee5sX`+T-gXhd&|lzVqA3dcv3!4ZYInjUL9o?gky+i^7?;MB zCb-8ku=ILFHl+@~06yN24t^02KjLqag{x&{$48tEIyU@$D>ZfDH(_N`eIPW{599nJ zC+}U8OYBHVztibfr+Zf92>X}Hu6^LMxLZH!cSC7#6Ix0ZKhbB7lAY)A+4jwg*O)S- zSc0)-=pBd1g;cvNZY|T%w~q#ZHiTyA+-6K4m$l>38bw}ycXxHo zMY?T@FOj?$JL6}YlmF5ig|hPu!~4%$0)?brZv41~YcIEl0Qxe>Io)x*doJc><(cH>NWuoU|86x?=MRz0f$hP`O*a z0k@;0qZDUR^=rd$X_WVo(^>LH$d*5L~=pfNgSCv#?tF#e;W#t&mTXs&cwfL@{^20_Kw9vtO}oJ zZ~CRw2SeI|ThEnr79>GGc%5}?SOMxW=f4_1fsJZ4kwqyDTc4b zuS@Z#f3a|WB--*3Wf}032b#X-2#N8k@C&)+zY2o$=?(^s-!q`9dxWH83c4-hg7QMn zX9kl&5FR7o-16mpp@)3F9N*>6xAW71>VrcWAv~d>9O3`QBfGl@LOT`@HZUQ~MsK=T zuopr;p&u)x6@48163{`o;{FcXr_S09)>oLi!#X zuaS+@u8KAb+Kwul6)RoA(i;y}#F@`9Muh&MC{n`CxlRrGmuid&F|9GrqUR<&Wo6_g zUSf3;vO@2j>2BK6RCli-5{m3}3rGViBzO#Zucv%&o%u;kTeJIYT}UcS|EuU`_lNFG z0M`~Nhek5*0+s3T&Bj=ZQ@0BEx0O7qrdreQ!zyO>h@LF)vLP zX=1+r#BEeR4@g0s>$R8caL7dR;Q~|>W4!H%Tr$di_+SdW53DdOBeLJXUo1dk!>4## zj}uFCt#gB}*d^KV@OM}w{9JJmv;~18YE^*-vLF!pRabj zD501JMV3BhI;HfE@RyfqfEOU~g$&KWL)hCic1;La7rLKV{YUUVQyeM1mv_yRwg>1D z^0d%1H)gt_@NoUdLO4&1gAkpnb#fo13r{R#v<`B{wRoE29$#SK(3LU#&Uy#_ZwT<_ z;C;+VzL$fXI=G$bOyXkcLu6|@f-pQBJbqO$g%V?rWLpC@`HP`fWVse6vcd zynWWR3VQz#1vImMAK{P;&`4q|H>jFq9}kOi4_uA6)IYqsJAY0Q8UZ+#$3IfLQ5o@W z;u(_3)o7HT`?PIAG99@h!0>p*+Sp(w-4yNJJPXkGtSvj*9-@DFutXj~Lg+A0Vm!P{ zV&upE>^qv^-MJIXUNgL@f8jtywES)y1;AI1&*5!K9*b#h3k9`achy&Ma)v1RCrrChb?3YpF zp%0k`NAUNF|5$_+^wVCVqcHF0^hr&S%#aPZUHIh4_3ke&Qm=e;Pk@VeaRWIr{LYwT zU*L&W>9`#BirThxesvK!-au| zoD-}Lc#)Xv4kV_?L|1Vks8y?dlMY&*wICyEepepTLGz0_9L)I1TY0*6DWRKfx6BV- z@xn(`H~iZsg(t4OKo%>M+vu>U73Ib)p?b5qk)ZC3#^aYQNT=VjnuysTuNqO&Z+%JXiHU#Z^Yko4Q=qy69&uu(F9~eO+T|61WpcN8 zERS)csAnXIq0_x``XA%KxEjegrVhBlK!ql!@!GY&1h>pPFi>r&mN6r5UL(wloLin% zSpHZ9AQLQk;g^~k#9RwPUxX1MgVbv(3AZ|Ci*Z|O-RJ^!0y1%hqHvT;m~}l) z(w6t*sDZ)Xp>In>v#vQ&?RG2xZ4+~?qHp4I zRWBY)mRX?HKMy6!lGyBLROohBggKZZ8w{$3C&h2rq*)hZt`*FFnB1|J$NV+YVEY-9 z_m*x2cu=Q+`jp|zU*N}MJ7=ar!LPAYr%?`G7H?udy*}{BF8XW{fYiPQ7Tdd%{5i6q z>NilVVh$o+V>j$ z6OBk^PjeOP3MrWNz7%s(id*kDW!_|LyA-lg>Ri0=Ay5j9z`^<{*~&~#kt|oGwe-Ro zH9+hnQTc=ETtJ7~ZZh@^>b^qm_J6{NtbKvTkT^Qi*MG)3JejW z;s1>yD|ILbhgIrq->GCPGerrOFq=Wn zarcZ^zLD*&PaS@d_%4A+f+MG4p&GZ483Vg40t2wX-NWSde z+}yNi_jRL--dtQXEFJ)nB(=<{lX)~J(o5w*U@8Hk01q*`yc}j}D$1UHh5LS>+~8fj zqMUkxt-Nc2y>j~2DLKX*LClxWL( z+j6+ib=Y49KKM=2%8kHU#zUCyBqsa~ZbXT&_dk_t@asA!Y8|O69YmI|Gka13Q3-?a z2g$Bx0#bF=DgJMQ#RXU+)+8N)0vyRvTIE_VIs_@aOy?X+Mpa5R6?#kgfsxL4Pc6XzUjr=L%B-e+j z2qQCsQ!eTEsVVwJL(M1G6OH!{W@l$pBy$o8(6JQ~_DCiKGUKmzK{u#r?6dh``W>b$ z{BMre#SLZ=rY$-~`?@`5zPya3H)h4n9 zl|2qhj2s9s2@Pk67N)!y zMSWTfl}{J+hNcj(dXmLxl&6fmPp|q|&a+Y41FvBL98Y$^Z<8{V3A1Qe9MxsaBmztHz$b`R;FKdxd|;dmj@t*9^SP<_3S{SuhWJ{eDX< z9Hm&S(X?p9LFTXO97ch-iR%btLp#8hLOF6BN?%Qw|Q5k}u=>x2?017lR9rf3f9M_|W~S_^yw z%b2_UxK^B*Zu>hm%#nU4g8GN*610_NAW#PG!cV>c5^G7Z`ep$tx>hi4Jq8N2LLnf{ zuA9U2lXE}%I1I}jzvqI|dEBI)Ly~GRCY%Y|+8C2>R_*2Jt7pqTZ6&&%;`+pz^hhj6 zYS`nIXKZ)L3-n-(xGW$5pk~>5GmiN}+`HlbIJ)jYDE~ihW@m51{F|hFv!i4Wi+`=E?Ep68S`gMNTb;a&fwV!;NGa4 z1pAIKAmMRx2M^&Ckzw z3)^A5`M{lX4S9}1b@`?P=o}!Wa?O2A9-g4^;YrW!#p zjpBYza&|%6ljRofK|L@K>qn7)d1u!bZSWW=&?(=?2b906T49Qtq}f?#5y3fQDGhCH z?Q}I826jN`cd#xs}JJYa-)TL|6z%n0M~B~B_p zusno?8w09Q=#pd;ypF*ZOS4V87gvAfvNS@xB{cBOeKn@4-aA}B=zz5%y?-%>zQK^7 zy=kG?d)}3}zKs{lzU|glbVO}A`K7CC(sK7-=Dp)6gR;ZQz~J9(-cEE6I0;7*O==wI z`XFb+I{H-xin=wfx>MBb#QPSNeen62Q#+#g5SKOJ_n0iOszz;{#_#9*`TB*=O}laK zQapO>GpkkJ=K-}i6v$kccyxIqzWPUw7X5<(~I zlmRBs*;4(EVhw(s=t)0gi6=K}ei`6YM*4|zzECQ+a%uSJ+i2${rHD}tDHEFtm!h#k z%ZWLaT$J_M?JWa)5f8G3agSM*qLl8c))!KovYECh889VQ#xcA!tsX{uPL%R2>OO>(OQ2tmLqCJr-P)B-9ya2e zMI?`SCp7znCZwiu0pS-(Zeqx&oi-2M6wBQrQEk?r=GPE?lxPnlb*MZEP7mWF2)PaMekh`e&_ zCU1>hpvqn@6L@Xv!9!m36XVyDZ3BGw7b8TO1<}lb|D@HoX^-9)LE|Avj4Y!6-U%cT zHpXkhfLi{}!li5K0j&~af)#o<%+f_9(Mqgr6MYVWEf>2Judxm!zYizynXS$#DY=kI z)HR=VJEUb3XMyZE;Lu<;$uXb)&QV$|dWB>s`JpxP*T zhX)UTh7Ewo4)#r^6GuN~-U?#@q&XYh|1(0qN}oIJrkA#5!ahy&%aO=#%7)m{1W-ve za}?&F2fuHK=du9~s;MLH2LcCrkoevDjZf=C?eFu@SDu4e zqHNz_i)6L7e)6f`elBRMn){{44TS04 zi1gfnfqFz*&EwZkqB&=g_6rszf=4v)=q>;K-6m6j{kX2VFiM`&G|8D(>M+gxfu8msR*%scuFLQuv z0qK{BP=uT3!bz6Rd(9wm$Xe~#6OxDA6tF)A5@|=BxK6C!P(f!$$I|eUpeC%-qQ$h@ zWz}X-oB4!|1V)kl(`6v`XPZu}ldp@*{&rZl+&uqL_@-Dxh4!1mraV#W8Ce2=Gu{sv zN4_^L9>nKPAw55WfrR2mlFw6!%Nkojc#3SA%A}+o>{ebq-Jv?<(uTK1aINaUF z+qgseeN81Fl`y@K@Ds(Nk9^W*)EAm{&PenVSiw3ZA*lE*lRTqooTrY^$UHa9~t(#@~aX}kHE9WX9b^Mdu~wXblLypKpl zK?>d*benK!l8Tu`ibkeM8Ou4F%2ykaFL79#mV-vz57fM$93`sE-U~>=(7X3+#<8jY z*Bz+(qy5O!Kl&_FUFtELGDa}9j{`N9ngdavaqTSE!Dd1(m z1pMXCy5>98?p*7Gko3I#e233F8fvZe&kIAUc_g11dFrO$t~u6BHB7fPVa_~MeKQvH zHeee%EwB~)-TW8E@`PRn80$awl^}G6mLTuZ_lk=X5g~s#tfbLcy1YeyRWXLEyNZF% zc3?MxTLh&=tvP-cL0yzh>n@r%O-%&^bEbk>!nJM(qNatI+i+G|n?LFf1 z-)~o3TN>$)!yW|&24V-=HWED;tef4N*e250eFPzX(XJ*!&<~)SkVGCOZMp9$zv6Jh zr219Z$4rw;kFZ`yh8mk1`z2t(>lv0GQdyU8`ZLDG4Ms~}nKRUPfo@P?RZNU2D@Uue z2I%96&qdcyo=Ru#VVjT5aA!=m2oGqUluFjL^Ct`_?VdvIgyUWgpPYf0Qb=^A91%3M zv`wEzk>>;txUX2Xl@(|9+E?-<0|1+@!0y$7^$0DI(GoxnS>bP;>v&BjSYP z{v4EagV|{_CusAi%yOcgYxK-FuOTMn;EGQ;_9HHPN*y;J-`W3cdheW=u{guVgI<}7 zG?^+QBq$rJZ(ZA~eYrnB3}eR<(kc;|q{N~&J)vrT3!E$Gb{g_L$jSdQUf`(9usqPA zq^iI&tv2K$p|ikiE-}@K= zZ)x>W*O-;#PAZzQ-6f|yeq?kV;Y>Ij>(%BoK7VdyO2v3-{lFO|n%U}=2Vi(9^_-vZ zoc|k>Ex3xw0Y_m;;^@3u*&X~tC*sl7J&B5ZHb&5sdUqPXd8l1R!q2z!WpnW17Fwm&u z7_{OnQak5>#likps7$ESna?=yV^+o)j%0@3V|t%QkH>P^P(fFR*PyR*rJUcM?1IUB z_7_2@>OPxRk+Uu4hnnc{p2tnUoDnsgD@_5-7tU%fX6EAT2{yKK83iuv6hB_^^**9} ze-4+N83aY+$ zz4B&wJG)D3KDghAwtua;brIHR)WH%RtWmbRJE&~IAvkM*TSlo!-W*gu75XtNSK;0| zPEW$bC`%j*Mp&5x#FeWF5>A4Rp(?n+NcE~}+Wsv;tznhEB##1-8{y!S75()w#rL>a z(9XcA#P6=9Mp&D_etfw)UPRpyraEN71JmfU<|yiID>78tid3k(?S-(WFirU*A0AKL z{=IG2;lvR6HOQ9rRO8X?L-9XxTcyqLCW$&Igo4317F}6B4i#UWY%waf@uE#-@ON)9 z4K&^wdJ};8u{m`JoWvO+6m>_B67JD*OV($W&|gj$LoFRF-R;lp1CJPzA(MLSkM;WU zBRlnZs0qT$FL>G;T+C8f=^jYN)JgmS|FqTDJV<;ts!Xp!hfe9__xh+>!P_gQAt2e8 zis510pK&e=8*_+$gK0@%SBWK9ws(trZ)+j-e2tf$Qs~lA?U_@tpG$c~hsUC~{>xV` zB|VN4CXpEp`;n69#3mwABwW2Y&4v$nbo9B9|1rWa%?Wt_d$&FX#KszOTHBps=dCfw8(lL&N`mJy=ke7_vb_-eAIDiUE#@m1isp^`4Oz{UM9fC%3jGrYnYr( zKED}<4(OFNC;MG28DdDF1dL*Z(1;b!1rpDZ1A|7XQtK;Rp_V95c_H5se&6R@U^g?7 z&xkOo4sRX5Jn>Kt-73859ZPF5V_Rp{0wl|&abw_(X>p8n?xOmr$!Q{|zkB&kFw^^- zU!J8;CSf`K78cU$xLbY*=sgW{{$boQNu}^fu~p1aMo_`QO{y4*DA z4o~>}2+LNUb`Yd9frCAM&RB&e#YxsarI(QnAFGqQV6`9kKF{SMzAH3fsEi#~8Cm{4 z-O>iEuc=iHG)CR$psdqhbTf=g_*23MFAt>oTIRDMYJHo}76MD30%>g@wu4Ux7qWX0 zCmf*rWFg;exTN0j3GomV2gLw(Ct_}1?B(MWFI{#Zu%jh`13>LZt=jT`E#1B|?#^SG zKv44cVSPOH4O;+K`b2XIeJY+0WhSUP6(4COk&C|V|7BLWN6gUa%*9uRQ;;ogu_DtcyJf>Ec`-N+B#Ij9 z%%Y`GYu;ckB)~->H8?{Khk)z2+s(%jM=uP;<+J{TU!&9G@av=k(wpye*zTM$wkt{c zlD-Lkk!qH-RCs1FKNi< zjNN(nYXBCi=O9L}Dn03BBiVbzVjhzk^j|ey!aeGNWwY;(4I6%PkywLzFd%>}(X$5p z^DHD-jt5)r&NOd{!D}pPWo2Y6Hd+6iZjnXF^6Ocp{WV|N%XIpdFy=Na>dCP6dzW>D1kTP~J-8rGGqP5p&zdFgspV_AqJ z34cpudA1VWchwoQgs6OJEwwR8VKt~SQ1h1gv9dxNi7=#~=4{a69Csh#g?e0 zn+E)T6=$5b!R^cUhL<}P6A+;TTEGB!v#SId{Y4xbYU;-u5IzHRoz7puhl(mwLWvuY z`^FnPNM}FSj*sk+q)=+$N_6=eU=r*q(RksV~l+nps*EV^I!y zQ0OmHb0^3dy-yKNSvcly)aySUa9Q8kvGfl2_n|wMHDGKh&;Jtgg@{Pd=G3imejGLu zst59iVbW-os-~+VqlHbdG@x(oh`Rz-;06(3`!fg&?V5V`-&ur%YRp*-Fl)?+l3>|W z#VH1aEA0+0%@^cyOLaM9#SIi$)V^XXZ(lt4>t5F7w$>T8Olua1jrvIOx6#E#q~=9M z>t>7W?E~*`s#xtg{HLmqQ3Jjs_2is1sxXf4vhz-=WDB;3t=5N# z;ash$8&1NNP=BRA!mNMAXeHpxkg+3$7}|SRtfz3jDL&VaXp)c}R&T)# zqubvlU$DLG#L+P_Oz{+4oWU^j;d@&zs`bNAfRA6g9?YB2KIf+q;`X}1e zd9)h1a|CjXYDw6qEIlXoZ8d#2Wk%Y6^?Mq6Q6;1@v}51iJg?AZX58hD&g!Bc!W7dn zon1t)(VMKM>PK&-Bb*&K{-S1{ihD9daf>n!8kLfo(H zK-}?%-{Z^}hdrH9pEAOKvnmY&&n9mOI&$KlYC+SOwy8TrPoq05z&<>%PirB$ zO>2=rY3rY}u`YoQ6FZES<;7qB>#-zS;ADKBK@+tjzRx}y24nlZ(Y4TwRx_!y!0?JK z>gEm%3exO(5taJq;6Rh?J(Wys%Imyp!?={psP9VZb%gIZV<8Z*pGSSeb!=QDQ7E}Q zj!#ejgWfs?yMOyK+FxcfO6^shKIXug{e76V5S{roS1J{?09WX9>wd;AeCFHn&3&Z0 z@JZ->BH7&ct~W6tLfFVh+T3Bi!^C@ZFr8*WOfDC7w{KFps>274BEC-CslZ~Mh;u)2 zrjbFrY1!YAp6yl{QJgeu@I}60icB=~BTAfpW5ykRng_NfL}dt+Z`NYfI|`0&0YhP= z9_KiKLzr@xN&A(C)xcbp%^=`&95?NTnD`ZaeIz7YzT zw-h6AHl$L8VBHY0oZ!;`lHRMop;_ZLuobG5?Z9}Sb80)KwV{3se zIJ?74u=6jJmRVX2ZXc1{2iBO27d;TLHRTKn(%D4X$zRLO<7I;hZHY_GIu(Fg4b4H* zI77rL#$IfAV8mE{$RC%4zb*Raz}uxU)z65JE&>m)|BqeTUYX)bM~NqdeiJ-M?pV)* zs8L1T1}D*KRQqpLm|Nuc29a2&SGe2sKUB-@ch!C>pYC+ywdJmJ?6)w&Hoh{#)`Vzu z@7}beZNAP&YoXxR%7E=`VX}R=0Ds*2S5+<>(aO-*=Ws}sNQBCkoED|I?-3}sb^C~E zJIk=q`tr}H->y||WzZZVpLf=wm!Gfz!*1efw%pm)7!y7C_GRsEU}yoF_g`?ut>a45 z7z?bwsL;!xy#d7vfB)uPRa@|e7)T`7oAs;%?2{%lY8?O&Y`)HINUOMKRvedJVlk8# zgq~;!ar3rLq1E`wtMArx%gx;$cH{dE0XNQzts>58@5n@pdaCEJereHqZ{h0ojHm_% z<*D-~))6BlKb$unT_hRFbdF*uS}L^WeGfjWP&qE-O9xlc5j}|}>nrfb`zZ5RPjbyZ z%0k4j465^;g(11obY+WFS@wuj*-H_Br*J4o4Am(g0NjK+WIZ{N-`>kA{E}CRxi+j) z+#!d^plk)X9xn$cmPzc}5uI9zWS2fn!l?`L_b>dOhY^xQ<7<~ri>;`!o`Zf(DEPL? zv=hiiv^99|4z0MXO1EN6m2nHQ$F}s%*krC8;?DzaIZDR=zUjfY5I5{wka|}-`hd8? zaoA~Vn8~1HOgU@#xN6OLL`%upYv}01I>((3cpC4&=J{e@Lo>-Q6^2d(s_GtX@aHre zulP-?!6o*`)-`{VR!8INc@6}YgQt#+$!Ho0hr84dAB~#?($v)~e7^pKBoZIrlu(6; zSQbtQIxyb!m$tNs($AdbVO>yk`mB)#=SK{@F5C-X_Ko||Q){KcxqJ}8T-q^3Oxo9u zJvZ4+HX=Q8z;q(aIKJT6^zY`GWblveL}aDDu3SxXlHGQR?kAXv3kW*;@-(crBG_oe z+gqH8DQnM*$J-2lfX|gHG3av1JHdLf-n&odI|~a&ns4VW8?kEycGwpqk#rL1bpG8)|bAXJ? z!=&19C*n~uL@~hom#T|UK+@6G6@C>@&ujaCera#D2vI(o{Y6mOI`2&3KWC4qiPJss zl1QV)35W7#zWh2r5@uNSzyhiTv-V z(S;Joa?*L=6bA@=)MxoQ`Q(Mi{ zQ*!OEXHnm!SH)^3?0*W;D3|cFO)p#-D;V$i!)-MD6_;;|gw8rj3&iOu^@|leZ4?BD z{xccoMRh*X8(Vt zoyw0W6~Hq%xm0Mx8-^Y|DgLd zMJ|getkaIdYGYwBJ&^dyN-innbVP(s?JO)yk{j#(ZE*geoQtA>%e&{jwtBsclG!Mb z=qVL_j)wg0Z({J{jgu*h_yg|G;DNVOjmWv!9i8wzl%d zn#CYgY6xl^Z)2QL$YvC+at(SEly`_D{0Y7nP58p~OIZ@icWlfx*(v3enGGKXN7>9j zFZ^&-&0aM$Gz1K>&lyx`r!7B#QDaAb<;RcXKPhT{BdsdMcxo)Fh8}-%Hy!YiWQ~a{ z#^hG7^bCZ{5m&v&1YvTu@CWvXfbJ1T-QrZ#2ztb~xYU&8=`cBImieL4n{dg(v`rb5;u*Z%JWKMyrcbUH3KV;^ zhHX0rthh@V6%hAJj!1inkkMgGN@=RXRjXMeO67E|!@^sca#I;0uFx*4m!&#VIM$$M zU?=?&cPb^V3Yj zA1fJ!jX{u{Sx$Lsu=?HnwBon0`VP-c7X~Cof#f$f-w{z746iNNQgZ}mNX`5)w?)kr z>GD?%cKaF)eDpj}?|mb|LPybKZqBwEzDy*D@u+zdyN>}ENaH-~X8fvu*FQTCxLcNq z>+|vrF;af-Asqm7T9|lB;iA7)x2L`)M21?d(CaqN;}9;N`Ekc$SriyKZmd<+n&`>g zGO;Z-D;JZOUOs2uqKO*-$!jAzJ@crh^H{E5lk_!}Pe`7jT76o=AU(8=&(sY>i@IUR z-)|*8CPq^FxCaj%bwZFZbrZ&M=+iKCiG7x&0wO$dt?*o%q7b16LFG=QtkR+mL`lA+ zp__Fx(<7G;+L7s1j{fZCHPxVMVx56dB@)+J9YRyO$j-Kt;<*Pe6K72FX!-ce2Jv)> zb>~Um*G6T0dz}h>PIBH>@Q`9lyDnr>z0#MYA_I}s^MIiCF0Bz9h#LZ0wov+KbJIqQ zzHDk^WAuH6A|IMb$cU5boWpWHjIf9PX+&2|m3gymX)EGw&Q;H=4v8+apRQ%nzQ zoJ&OXIc98$q1T1jqo@99X<;3n|6Cf9Xf5J8sUsA_>97HIhv$T5-|K2Ni zB)=dcg#sK3^MqnAz`~laR|+26eeSsQx&lzuR1@QB)d&3Dzq%C)GZ~a#_&If2Bvl&4 zbqsxZcQ@&mbfvk@Tb zTDFA)vHJRrp{bpck55@l#gzIMI)X`?&(@y_7uvbv40*Yh$G+c_D6`@$YRwwM9|tPK zQaQqv4CQ^lmnX@Wm{cC21c=(Ce@CM6T}j!2`PKw<=SZT|&2MR#L!JcP)ytErj5siG z5DS_ym`>{Wa6(EQgI(eqDI+7pj;{)@NkRdvb<)-p;ANn9?^%nW;K= zZli5DeaD~CW0isYCFJXPODQ8Ta`K)L7Agds7@s8~DZ`%TTm1ehl-5pxdQfE%v{0(o_CWeDmV%8 z!b+{1w>0xFc4MqpaJk3nYNAg&33s{I=|d{^19!0!@Y4!Yc0Z{=Epk#^#`K);*Mg$N(YnzR)dHBi^{etM{liTz@ zKV$XsUij*>YMN2ihltV7x0o%uJbk@;79bt)s#-NJU%}JGvaLIXhdS%X^s#Wkn!#PBa|Xs#7l0T`5qPrhblBO?`Fcy< zH^nowPdi$b=`zrN^7wRybLzsPK<7df2G;W(k@}98<>(*vITaa|T^$^_fK1wWR5Ua* zPAIPmezJ&(>U4arOB0Az8hI<8rt>@BOGEReU$As8&%N7iy^McUrLOCP7|$Dzw73EU zy5b?sQ7SEt#@6Jv(i*YZnngaP>Z=O3ne^tdeh%x9dCqLyn1D&Y3}Og{4{T(-QY%m$KWPiLB`kGS+$8;%~#zF{ceBdxAT_U!2f<(TxtDc_Y2N8>Xl)&ot?lP zOEGkuN+3$h^AHUgIk5-hmUS2<156nN*9#FCX_Ab#{sG6S>Ors}&{1$eFj<0lJ?&%$ z$wOpI;Xlzg77!!KLZPRoD7gahUj#|yvd>vc1SNY>1UyiL=+wDWaGfW~4_0GIaV>N2 zzoWl|yi5(qu50a%Y%v)2G^*3$UpSL7u{`MZD^`GkC1WN$)V{0IvZ`S6-q#X}Oxu2U zcg@6puMZ-s+e|Jw_C}zGu7m_Z`q%Dhhyh{f+kf(|W7EPv`Q8bfwyWGCH8>l6Q#6Sa z6ZQ&x@AIfO+G13*pPH(;Q20Yj$BApei;-G_h&w?iilZxyULb1y)Z14)X_lh$0=L5y zyYZASW<+tS%JjKG#c$r$@m(jvoyL-AL^j7GZ9!D_%BH`&L+l0L7lU|6FySC~so4M@ z2W_^pjBt3QYfajwVTo?RWBjyzCLVfPx3mRH%XKT)J0T ztmQ9Wh*iQ2jsasO5%yM}_{~e?A%t;!dBNmEqGe~d-hv>prD#g9qnO2%YOuCitHBXD zvO#}JRVBO<`SL+`c-1uF7o{B;ek_p9E#hSNUZO0=IPl#5jJrYDr}a(j4Q-^}-6e1a zC-q-WwjS^hmHQS?6lD5;e()FPuTBQ`P2JXqb*;~o1To!)ArW2>N11%4fJgjW^;sAS ze!GjFlP-%Rx|+O$4--g!qq|zsZBS!^izvy@O};M{a3xYC@UjA@u3~u;pBZ=@+67>2 zJ3EJEl_493PfuPyi65#8zFX4ExK1E=e+BF(4u@o$%)9wyjzlLYhRY$)STJy??5;Hl z#UFl9s{jLV?UCOD-4l&91{cW&T)O-#(W^_01Q3lX3ztv7m2%R%0j>2fQ7`?Ds+PjT z_+($;$`@okCbj+q5~Jz-c$i`T1v_df19TASp;Bxnv~NKy)(KIEANzio38=JuV4bbD z_6W-Y)Pav|I2+>kR}C2wW9M0X@5!5V&aDz0Dw zTH@`X3YK2@Dj7n&_MbsrI8QKrmM<%CxlkO6tNGu~Wbb74qd)g4wDZbGn>D{UQoyz7 zll(KxFR!aC+@^O14{2AZ6M>I-7@isqk}A4~_^5%{8e+iuN+zJy08xq%0cipw7m5A3 z^mM6}lxThS{x$r?$A3B=a}jr1xYZl4vZ9>(iNxhVZTJB#EBq~O0x}hCnQD212|bfp z36nUUNeOsWV6+Yo_c+h)+9n|?9scm<9{4z`wcMVay=NM0*osc6+ZwSIT!`eK0IjV+ z=Kf1RO?_HUs80GTNQ@rTNmF@lGQN%MWqNIrAu^XTr+ZUa{OjKyXur3gpotq)ian;t zebo{NI{s=?vnW+hmkgmi$s<(qp5{hiB=cNZ5Z-Y{6f-%z`9RS! zwn!?UD7>d_kq9yf4}iZ6XCTvnGaMN z)JVqJtb`^;f38X-kooy0il0CtBsW#%JgHwXg$kowUt0O+i(@~jE_a--TOhEn$@e-o z=UkQTE2TECLrz*4=vC=Pq}{_yMNB(l-taMHm?xJ!|3prAd9ylOY)Q+W?aETwz!Uez zNsn$$+G-6jIvPpwS0O6Pe_dPR6qB_=Hp9Otfi;PM#5t(W`)t~sl5~0=nWNBJ4=5jF zo(2K|xQH0rvBGCr?sbK{v8{*nq0ow$@6WmDCih(P!x*vx4SvV6-;YP-vW`bYD_ELV z+J0>qJk8$J%hOQI*bMCS<`5bYSm5Vi1Y~%{yAu%5NaJsLdGRx4okN}%(HJO!sd<<=;KEY`tmEEK-`>VQ1=l=HQ_PWKGXPwo?Bx9pB{xc5qEk4+y&}3S= zj6;Iwg@6t=zVaIrJLdm;#{DAYv+}BoUVd$iAdQl6W~}?xS%ABBBnAlupK{W1=(&2W zmGpie@Y1u$32pQ)^#$}arzV>1_V|XUJnq{|6sbsgzqsusVfkA~opjCqF+-n&EQ=24 z)ybuD(UN)g`khmgDRAK}CFl-^B~Dal z#ajbPnv5F6>?;`EiaKZ^l4UXH zO+!0omLPLK2pQebSo+&!1=h|9^Q{Qfy2X48{xRQL~#JC-N% z#HuMrVq!}#>wGK~Lwb3MC)EoDSRELmjZ(ksl=F0$&~nqds0}=^dSrdU9ys5)zv&pMpdQ44sPUOPPco*l2mujwA46UJs$v?o?3 z$YBv=@-iWMxisNKNtb1QQ@wJi0d zS0;=pIbCKP41bJILnr<@n{4eM#04|n7uI!1?$65z+p_1KmHA#lW4``z_aAcnsD|_J5zyUy z_+rgv>aSH7aV-hL!8FTuIF=WmZpfuf@FRnow34%LuQiVu2Y4~g;6%H$TJ`2v^A-r& z0d1_T$X868(SbD!UXheWzdh1%qA6;d6npu8{PMdB~Lu>ZI zg06ZpBKOXootr&N!_EqPIr~6!`%&z=u`J1U^U00(V@bt{*$#>9r^WSBmNsR4-VZCL z9+(~EI%aUZ894xo#BHjnfKVp1_DHfoyf)vj_@HJ+Rxt2BwM?Qzfx3TJ`@+t)P z880=_&66Cj%F6Zep5%bS2eEhJ!8rFYoWZ7X66g07`J++e)$SI3<8A##EVxS$nX`qp zH9KIdg8!L81?&9|&BLRl6rS(brjS;z4FF2Sz{pSog_}-h)PdE3_4JgMG9lGpP6#G4 zL;qzzMc3OGEX)caE)QRlzj*({j+VWtH$943_iV1yp*_TdbJYs?BPf1!$F$u467TZC zW`5H%W+$p8^7jj^BBCz?zhC{)^rXO~J?2oE$`C5IX&8uwEw@1m%bP8Z9SiBxn)GG) z#_2KJ>MO9eYl4uolo@wMWbB3wB-jRIO#`0T4cJqd+eMEk`?vXNe!{En)H8{&+FCh{ zR(y!>?s*OBetLSZ-&m;($sh-vVSe__;FCn^d{oU{_r7?JQ{9IhVKElq`ed5>{8*A6 z_{K?ba463xTCghafkN~|t+~%2%OWOSae+rl6?xbTe`@RsS`L!rcJ6<>>f7!N-{;nV z1AVcUS9*@#J#AIa$|E-ylS=t&b13_P5-4}0xTf5@|BL98$AifyE}uZ+$x6jKD4FEo zL>#*n!@gT!NXCRay-x7u0m?(4)?!JO@OQIcI?6WH;?^pD?Sd6+eytia6}Sngci4EJ z>22YV&HlRdXiHAz+|)6?sqWyHuaQ1ZoNoFq`lVrWPyR{TGZZ*z%qh#u%G$ML0-Imi zIcxSQIlqP(SDz0&XV4Z2FPyabX=rwDKKD7SK4656(!u|=TbMB~;z$HG;B*0xYo-4; zA}b@dRGjbFxVFj(?da>*K|JOP*G|+PKkBjblblNWAr}Uc2A-!~N2DpNYd^Y=`eF!J z>;yip{_MRYyMx`}k8Tb*DKI4`b+#T5F~BS*f&5hq$990^J~uz6!YL-A3~`K68L26W zrKXrsL6{CybCH0;Sh+HVLPXS?lNn$*Bc=1o!^~m;C8{?WhByGMO1M z_6N4LJ4AOOca(P&cYHTAN3Rx_=OuErIxU7+hh#oByxY=g#axP45f_CmS|&PHp{l>) z@pcHuL;M~ZN73ND9$4L2KFCuL3s}!l0Q<)1eXCQWTVp7B40HBmN)V$XGe24m5oB3` zi+)CCnHd?bKjnNMlO7WHr97}k?VUzQ(7XNFFB{^_&70iiL^V&^bDi5Nz-{nRiUY=Z zi`lFFA}|k-B(pzUIOr|rYoGThJ0;!2vmtYPIr>s2$S0za^j;q*Egxm^tn7vN^bi(D zpGRz@SkdOd>*n#hz<@>HZ**gWVdw!@&C2xI)-(cGWAp zde{G@zgMb1wCb0$S#mF3rthQ__a~h+bgI`=i^E*A-n z1&+>fuPvonGV^w{=mg%QF9+M?&bRqIXc?>;K|FQvNDGl zo~UTi|0=mLVpl|H?~?CMANUd5oU$_KvK-n*jirCmpS9v?a#p#H(D4a^y^=H1``yKR z+Uzm(Y=AO3%A0X&r?~-h#-zj2^Qm#M{rj<-&m&7PjZfUZ>{N^OfejqI7N-WOpC>=MxQliH|ZN4xI=p~0)>n)#$B!o>*vLM?t7IJ zytT_3RcgYSU}@hWHZB(os-Bu!Ft47TpnF!m^1U+Q76|?>XuUFowKQ4)IwY{&u;=1C z@Q!w{$?l$aay%pbOw#wtgXJofQCwnOc{1L5m`alD&HZUJ5CQO;xD53)!%XJH6Gjyyg;n7kx#8YoXy)7hA3qUh8)!Z-HvjgtC5Hp5l6`e*SoEIDC=@MHH;ycyxNs`;L%jRSD;QTUus4LWm)m>s2A8 zHH@e4;+TKSoc_M))t>RgCAhefq!Qm7+Bm)qY94qo!D+4aUOpRT8$(+UdAWBUaOi=r zUvJzm_J|-zqR}OLqjhU*D<_w4R>b_i8NGqV;{k2ZDQgg*vDEhW=J!kP^uvN*8oZUg zKjHHM)5tuc?U!}Ru-4dYZ}SJ}vN8!-X0?Q(8(YB|D~U?<*Vt!j7g;SCIl^Y}jf!uH z#I}}R0RfHGvssMmx$&O5{;+bNEJ@*!lid!VpOr#6f5+2PzGZ#;WVwQ^1p3Emj=yjo+_FUQ5OR@!%1jM0Sm^FWf>G(k3b577_ zizi`oUh~PUvK1mMcsb6-D?2oZ`$M&%)70!VLOhE$Xl5It)Ltbj8Bkn3Yql!cxiJ3p zoYn$?W6w*mj%9!Nr_Se$dv@P&Z11J}7f*UTTkYbB)_~#P&tiY3tYUN?!TzhPgjjD+ z=VO+KOB{1hd{ZCJQhCL#WdDL@X8V8 z{247_o~>#I?K3BOTZcxhoAh?_u5a?56f8yDCdL4JUxj{ACiio~Tyw45d8&B1NGr|+ zMq*R4p4auQH!>cnh*COsp3*lix_VFWa5S5K3^5ReU!0xcq^aBez<{jV0IbNjr*GAN zlvPK9=FEJWm_ush`6=?rmq588JgVov53`?M8TmIJ{>N;GC3x~d{ZFsyMW2AV^Oxa4 za<(WMXIGoC%$YZ~Btxr`jfpskyaqAjp;# z!}1Bv^9-*1_t;kGTmF2dH*~U5W$p)@16iLzJ+g6z=J;_k*Z+%gxNs{#K>qCLnr4O7 z0>ofO`*^S;tU|@rupe5kzxJ>xWZHCzIg=YwU-QosVIe!rL)n()mt{H=eB6Zr~Sn{*-F4R_>Od zG@jk3O%Pcf{ZAx8t&ejy!Sh)msKQLnXwkWO^UHG!nG~3Vc+V33lI4y*AO-RoxEo~h zU*(mAu)r~dJKG14Y;2;xys@{m&f(5Zg<+Msak=PUNsw>;-I6HyJ{9oi7@H~FOlf;jV7$Qv1yaMR zLPj4DDIL2NINOJi(Jhg)hZ#Hj?``M~mAnhf|FmL_RH`x&^^3yna2?A)*lcQIzNx>qi&0=Q9sT_K;XV2x-6@SD=UfM;cPI4w3m zP%IqYZ+V)M&0Fe=M93WD z+rrK3Un2p?|Gp>a9VleAf2+a46cWvSx2n_LzDz-l4(J@LxCK?>^xLmv&sb;^fR~w1 zR<0+UerOGEXZ|DWeU4;iMw1LyRa&J0EAao%<=BC|DOJ@p*k$;#tuvdN{auBA*4WlJ zt(fX)YcFu(+`s^zZ%9^AELlln#^$vj&?7GhZDUjLeDfB8Wzjo91sVU%Ovr|&3F6wkm$ ztJysXJApob*gK&u8l@)cI9#6T4*r+)R?#8EAiq;V=vKrDrpbVGew9(0{Wl*}m_>6; z))GL`X#k5!g}z+BT{}1AZ(Tbe{kfJ`G>MRe8B#+Y;1@_I|5Phb>zarlU^%_GnA!2t zbCpf_Vnch68sE?)Z;kdJF$p3Vm!`#HMvi*W!2R~E*VNCS^klTIu+{L?{>frBjr8_y zJ~sbGg!Gbi-r5K>F1sG^6_Gr-s#&>!^MYX1BL&cfDR}q+Ez=cp-%b?S01-a@RW!k! ziG<+u9Z&2N%7$&wqS>VPaHC}Qf0nq4A;S!?dCO*@@n@bAk77Lnfo^zyo<4c7{28Kt zd}!aEr0PjMc|6p{I{2n0(mPN zWS}ejPLcX^1kJ=Hh?ZYnh_IiS=9(s?Zwru%)Jt%c9*r<>3*)j?_osHvbwe++8O(^C zylJcE`KvS=_1k|tX8f=}lwo<+(i?+OfNj!!@-84?ST=!i_xQM8ufj6gl8pUiItx6j zEsOfnxRxKlVsuKax9&4QS<4K-Cc{q5y=8;yru~~D@>ezY067^FO(l_qsaF?V&wR2F z)6N{@iGj24#ud1E{}q{!V#nhpjl&Wmsz}^$!Td2;Ewo0V1aaTmb+});<&i@LW4ZX) z3l0w!%?uuv(z<=<+0O_Y)0)b*ux%dkr2Rjirgu#fnhl&xrppW*j5oDg+pB?j&VIBi z%=7M|&LJ!8F<2!)TjQUOtXAofo{WFo<870l|W_ptL~fU0UcRbfgI(ROtZ}OaN)prN19NXYPA5cizmKd2?s(+zgXR zU|9byYklimYwx{w2mcc$J^9TbJ&H&D=1mX$!=e1XKs4<vNk4A zq+p)hE;WG}f8ySOG-{bsak^IgJdL+CMD;AV#4O2D`K#5VRKG(6lZWC!8H49jB)3W* z0h_<1p9rfT&&``u?MMRGNYBzuZC2JniqdxkFC%tD~?PC~siE#se&Euf9O;u*6Un1`kjHp1kP~bEG4x=7C(x z=mkNGqc2{ot9}P-eS788Q4stv-*=*+oiv?(OMZ4>d#sZ~`;PB;cD3{G*7IXo|5rMM zqkW4vBZfAMpWW&Nls5H%mHW3tWo{63bmB6A3_ck;M_dmg7N}OukC=C_o?F_AU0tOJ z@V>rkSgva_>xytmIs14_--y$6Pu2MFUQy1O>J32f6BB>zzIFNhg zJH|g9=VD2G@)X0Kbfs93UjKuqmxgqUs1g+A{9IV~{$#^i>B&+{ahvx7`?i-nufZDx zgV}%Tf5pugfYLQ_Dq6u<4mkg-r}zE*&TXm?xA5{)nr#OhD4RT z)?XT@_GVXsv|_<%q1CfmG}f@aGeEcAdy{$@++9xnbrom&?a{|o z@oW|2(V9ED6zfaj_ZNG`h(%Ol{d3MEv>H;ck3tFi%*hlqKtlaLc8rI7EhB*B5M0Kjy zRtGp|dQ(wzWL`VHn!|wufvNtPe`_teD8}Kb+^V9#;(WEP^r;wdWawd@)2*IqlQ{>P zsD(*yc@%UDx4QR%pfik2JsXj3Vo6G)A^5dSIk&X5oFNS&b_;Vd-UdB73TP)cKizd` zvrfy0<_y0d5e=vcQaZ#Fl%Kg#zunkGz9Vvn=b|CY-p%-rAj9YMI_2ULJtGWe!mlr< zHMn!H4V^wll`OBLejA7-6O1zBCS7Np+P_e(%OwlW5{-h5+!W&cnqEGk8ltd%t6WXU z%6*`GSK-Qj@tTq>QR|!gnQKvpKyg;8%cov-rt3qGo@rB>w9L6$X-57N5wW{*vMUUn z4b^w4n-S&gv@WxIGZtcFtdekjp>M}$wzz^W|ueRhFq z;HU-XQ<>69&cKv2NAuu?*Wi$=GCs>euf=N7Z^1>RWrwg4+CBXT#S73f~ITr!?!jS+WwR)SK&FP#YN90za7 z1GWJ9iqszO=(;+cA95Gv-d5t{o+Smg{v5N8@m=!>n@q`DmFUuMh}OLVoJ!uUI?p6k z+h@rJsmx0S{;)L$>gEOS_m960voy@yg*p ziayAYWq~sfiiYK|^fiNT9M_xz0a?xGv;M9zhBLII|N*? zVP>9x%cpFj(aQ>;=qrKe92ktGjnGtv`=N@j$V}~&3}bU(N!cdMV7KDox3vM__E1I9 z5FkB#VB6yn1bMI8MK@iZeW%ZBjr&r-UFq+pwWmSA4k*%DF{Z17mQ-OczZt}>qvJt_ z_59c|uaB2!Cr8xhZ(6SjpX+_xl&s7amNZmCmu_Qn|H(fyDBp%0z*D@e3Ycb!eJQ1E zBPZBphT`JWm5Pdh0+2vOOwCVnS-+%uG$%vDT3Ah_D=k7s=(b(+l$^mY>SmguHXR5A zO&^^ss!rA+s6=JU#8Nce7h*tz%=eCEF!$;m;S88#j|lX z|F+URo3v=K`W@~QukQiQicfn?6OA()C9o^j5XR*q>o~qE+06J*fc~j9;aX zyY)7{mfli@Pds7FoH|y`cPFqxg?TMzPI{A(skN%2RHB35L0f&5$)soG?kAwC4+i3& z3t&ZM$kPKq2c5*+SMsZ=fV)s->`MY>*D)+T-4`z9TuJ5h047=Om4!HUmHkR#U6`D3 zHg~N#9FZT>W&M^$W~dK!CLc?KYB9mefkaGV|C_$yTes6>CgV$Y;yAo zk$)?D&umr`(>I+U1}ss*3Njh$O0nF3O1m%vg}V&0A~?T-vfPS_8a+EM^(+S^?j?zv z@lJH|#T(nXjB%8$syBRgAu=;^Q;Iv3ybrgKSG6GZl^Pt~iN9~V%b&-3yHrsG!e0^; zp1?1Fkl~tYp)WRjxC>c{9NqDUackTrHo)$EvIwdid(ce&lV{juV{qKab*S;>=tQ#2 zbHo|vt8wSL{>-HQSWstu~L=Vg4~_#)?QxJVV#Pls>d zzs!OA$UL^(1K=ZIeX5_xNr4|-ec+>*O+S*Q<9li!_yXPHZBo3}_|s~6o0`mgWy zV!NHWe9tWsTf}(k)JAj9AD#NHw4VKvp!N^FD!TtGV~e(Ya7MTJ%dV2^5zncEtOo=m zV-rta>*fG3gTz&U`mA@1FotiaR>!t}>W*1oEDtcLFe=gGOqmrWjfp3jbcw$EPoCw` zm7wJtzi+RRtMSn_d+lBxp;!8@kqFuE)|SX;yVLBkrtGCn+Y7iSbh=B@NZfltX6bO^ zr$Zo@9hU7trWB7~KNh^3^KRFB_ps|^szRMOm{K013UbjAeWUvNhp30JTIdmqNg+6} zV*6w~dd;vYb3A3fMW8NFnXmW3Ye>rvYR*UPCT_-wMv%K zPhekq4{-i7`wkyha9OmTP)pPWTR%Y#7U2sfi2 zm)aQ1DNLQcZt%=n!${^i(?ii}5Ym1*H*OtBUIS&N9v(S=<+iZ2H7?;#EkCdOh-H>241y z`{!)SZ-d`7_>F`Wqh9>Mt}N6m`|Z85RHfF;3sIMRsmfM)4%-UF{kK9vY>;&2w?amK3+m*fO<}2C07@M>jd2v2$f{xO_I#Zgdv&*1|FbA4$ z+d8wi$j0XLZ=$zwr=3tewV8xQ`%KfA?5b_ZIoAvf>ndhp+0Ss%t`lR*Vw@QAg%5MG zfx8A0BPM}BOCNkB{Jc96Pb01WLv7aGFeyF2e)Xwjy6{rGzpfDzBH-H`!woNsH8~pBT+zG z)>QgEb*bj)+se@9WgVL3!Jdj1lqf}5P~iLaGN<1Yugu;m$KJS*8VugOeWi ze~RQvPa(XCgQ6Y}tS&S?P1Z2~rAkz)y}`WQl)$c>=Xe)y?t2#(l-X#5q_FVxN4-!- z7K1_!L`Qa&T2U9$F2&HWt!ssb+Z!5AS6E|o17OC{S~4TJo_+A$W#prYgv0R1k%?9T zuJ>%>HXbjqlQN2Olsi|yVNgJy%yr{zB6(`+LQPAKx^9>ni%5Qa&`o}Y;*VUG6R{Dw zvc)8bsr1IV$nX9>mJZvB5^NCFV0`lZqsy6>NfAu!s+krowNSJEJ-E zcd|PfA+HfCiig) z(2ZrXt&SX62Gn)#w%yI3ag(bJ;hd3}++Tuik7p;IwQLq41@84GOxwp}m^QG|&T{Pr zNFh&!I`^l@NX5}f{^7p67mc*MMIyoKE(zDJ_`0xNQkys*OPCy6SPBfcxQA@1O!e+j zbsjT|Ft4!0i^Y~4gz2Cg5*B63>{Vbu^c}#JDp`>E2N2@t1J8%~gf1ku33)DP?asa{ zJq66Z6l8BcehngvRqp)|+H8$cM>=umdkLeV7GQ2K;T3qOdV{J~d}L@F66V?5+sgQ( zUWjNma5VME-v?P-^ZC1&NU2h5|Ap8~nw^*bkzR`sGS&Ju;xk8&t={Kk34JqZIR7uv}K#zboPC!5rrwThu8}bWr->wzF%S>ZNC@Oo^x+IUk_W2ruDb0{r?5KE`3uM|&oAy6!w8jImi z^7ENB5E@C{eXGch(_oHY15KPfhb@weGXB~rWYNkO(h5K)I`>X-Ikh`Ahv=2EjU~7p z+VtQn4+#52v!|RqJ3o7Q+425bP70yB8-6iCy?+!b=-mT2c4$-5ZcGPWfabD)e}gTO z=R6Pn0~tM2zzrjjm#;Q zq`y_a@@7d)IUdwiorqdG-Pp#w2z)j`%@W8TOV5*KWX$pqZsr#RGrNbs|H2hMlA6qg z?&=58)CLU8y*MCBP5Lt*^^~Pq*dZoKRZ=g2pBCKd6NaMF(+K1dJW44~CeouM;;ein z==#}U9}(W(P*eEoQ3%s1Y6GEto0zL-%o`@6S^I-DPXSd990?r7^*%WOK{foariYaX zB%!Y+bL4$KSkQ8Vra9rFZun`KHpuM%6ttOfZXTv!U z@DVHPffB4gEJ{4RCv~LXgtITEfOQu(x9Bo|tvCPlMwXsLLX?!mZLIvOZP-Qw2r+eyb#)o6f}D|&Kvc^gA_(IluAt?|h8d_c z2mW*ov7m=sl~#1c3F=c{4o>;WGSJuJgvGBLa82;LJpFowxx(c5i^p1@1}t)C6lai$ zQG6w4x+(z-A)woQJ;T&%fdEND}_cU|;l zCC%b0Kt_UoclqZn|JPQ*Qund>aU`NNzu$6)Ba4#WRaCkR!g6|CCV@b5zLuktho(t} zjw=mi1(V0ZaPCI z{iL!|d~q!Fni?*Q7mm9;uo!XW%^tq`-Mheq22&@ZTu*FV7;yerwNO; zf$|pLQMtQZ%f$nrXzK(mi=l6Qi(>Oe{X`l$a3kZh1u=a}b^RLkQL|F^@viw7UXiij z+gk5o>Z5mA1EmsX%(6^WIXNToEIk$Mh+Om|Uyn?Tg-F4-OqxEkNFEDM%u8r%3Z#Y> zZlA>a2c6xSS3fTNvpKz}*S%&3i%0MK zOy{`Tr>z|AeE&cn{kzvFNh9wNod2?Cr-3E8vPn;0b(Gtz?xqa{IpDcsl4w7(=E>8* zjW|<^;~fV$m0q902mEZT7XtO zz-zWu=Xm2!XQRQmv1o`2?0l(MUW{;iPx6qu71ssZFZu!GNGP^Be}JT!I~P}o&h zx52%-5rDOIh?wy-DDpHQbL>2$Q?Sa7(wjc$pbRGRx5LjFV)A;XKwjlQh^9mnPxHm{%KcMC{VRt;9@!gDpi zg=aKoU_B2#poFB~$VY4E2-q2>p(M=W=*((<6piQi>ZcjRIw=~Ww>=X2U=0y#oTWM7 z73QI|I0A~y%P>8q(IPWI`Q5w5t|ANEGjve(?O1l2tnNS5=$i(>1&MqeR)yu~749Ds2-&Xz6HX*JLZPV2Gy-8hoiIW)y9eEnfsq13_mRtWppT@+0A$gr zx;mTz`C}2StmYY6ankmdD^o5!vIBr=NH#A_R=CJ~>eY<{uhLHCt$ICDMVXv>0+;g-% z4b$>WM)Q~hU=wO-iG9=hqe)NNTA#4Q43zvR#NBY|R(>qr#TK~H-mETCrphvH`gr?6o54|&OQVWc| zSt0>mU8AN9+hc~Jkcouan1M8X=piL^!<5KOFzK6ctM%*aoO_wF5w?578Q{O;z#9~E zDuygeUWoWy$-cdRFg5DNxe9ba;`!xS zYoC|T+qXb3tUS$+onnziBpISgj^4Q74;g*;tBqE}j%*#sZ}ml;2UVZDL(+ax7a+UBhqJCZ>FZ z84Al88=6$EW{HzeI zMW+NVh za12%BsXt9TUmp6@=wOcyGtrdDC9!AlWot9&75iUlKSISSF9%nD{mC=~14axmGB}^Z zo9(j6%EsAicrRq*$uh3Q)AMs~Mn-Yr4@oSX-sl{0*Q&X^ z@$?Mau+4+`WJ>z}#HrI~HU0Pj9(MM*43AmYA36N1RYC6`z`X`nXjSAXoL0q23Px}* z`LM#Z4VersPU!h-c*~#QpC3Xu=DwiY#iO;z!zjP{aPm|ECh~zmy`*PypR4wy-@`&y z!q+S_pf?;Hs_llxJ)%{-ZDsg3AYsd*YGP8z--N4`qPA-~{#i%?)m`^Gd1{I|ZASM3 zBH;tKHMwfnQk~z#PLEdx6_w)mQ$sQP1Q{+KzSXy$Pc<>7`M@1PdQR$w@ys+NiGS2o zR_EmYRgc_;;$9u6PoKZf;kI&MSir1k0JKy@9_uj2`*)LV0r7Q^hnuU@^L9iePwV|< zUR*-lHf!^&*>#=w~>fK@)hiBzMrP${(V0+p06;v zw)oS>CD|kSzd_hMb5Kl&*a+CZ;VY8VVxCyyBg!TK7QF@pwZqr&MWBf3se0@yY3XsP2|NGkH%2Q{NZQwdokw9(1=a)DULKk-_aU@{ zb^+l3LY}UTla-@@6Uta3yi*#*iAiGf7}8V$$avIO8enq&mKUw|23JDjL@s)wDV`5n zO0Iyu7kBN?gaiR=htlsKVGi=`D&-OWUZ{tulAfrV6oQ0gSE7AB`ZNc&0=NgFSpe+j zr?266=PsCMT^Qv{JPzj``Vh5 z#8H?bHicrI)U(hL{y5!A=7@;oPhSrxx+^HIG(qtsDP()&6Bt)eX36=C&skp30PdDCR<7WI82tl`O?&;VJ#iH9P7x`cA7W@fYE^TlI z1=j^?R%1grYjV3<*U=rIy63VI6Zu@y*gSx2yEskFIy#{<2;}rxYc!_!o!)pVnqtZd z&`}RbPV}K0B~K1wO>ZTvPU0SwyHrd6p%}lbn)oxHh zB}L?=xUgfo@BzR*6t1bIHRhM%3so@vey~R9#*0kJf*XC~EL*mpz|AYqJ(n9|&er~P zyp6fbV@)Zmp|Yo8gc1$pX_oTQE4=^|K7Tr$8oDzBtTWu6SG~v>Hah&oi67QHdKPrhwT?a~F15yBrcKg?y*FOu;d|2)3njgJ6T#Yr!r0-?vE46w_fLoa2ztfzN-%9>5{S!j z(h|Pr$i}s0@cA0Z*YN2#p6!6ZAxidDM*GbHlr!O$RlO z{XRLiJLIix_E$|25et+1(o=$LMPI4v$E_PnAtuc6z4n=sYOtIR(1aux)@)>a`vF#8 zv!+Ih8Jh-k-6)3g_Kc+dGWZZdRXST^mui2{<6idCUvXfb_t|-?YWnCps%3!EZ7`+L zS3H@RpH7#Y8utW7*A8iVwV}E;u?9fmv~@JsD2@i;mtReJ2WHY$v%!T$zW%)&;)B7v zGk<)|C0TQZ9xF=LW?lrrhv&}gf#`1?y0KvN-4z(NoaV?kXOWEPLHc`faEDre)r$K=3fEw@gjk)j~#0&t8TXFgeT8J*oxd46Q z*OfQ{lItzFb=$(N7n)|SV*=%szh%?@2N}L;d}gl%D~aqSbCdt}vzM7tfmtx=xC3j} zK}cX_%Fo>krI*ZRXi|Zn9RY9OA}Ivxn=-;c9=5FR49r1yfrp+2!?13uk9L(vfI{A{)@+SZhT%QG!YEvon_GBDlsSndzM15Up;<*Tvp*?NT>rEmd;six&*RWjl~fb?qV$5Fa99Yx6MVE1gyle!E-gDDh+NF$5@ zCl->IX|6vdzr9eU~EU;Rrrrc^TjHiODZ?v_hb#FZ!| zy9&um0lb0_^1S_HGde!!BB5Ut7Of=+1YC5?LH@6P+aniuSS!G~jm`Kdm_D{{?aPk9 z&A*5gL`=#TblZr_bhzd%iw4ckcV`^^Eg+*AWsPYczetzW$$D?BLO0ys{iYdVuwYjm zYZ!4}J}U$Uwc z?;v~Oor)Rnr=_^qy+>R)I}caaU^iY1%3|TXS>bL9)7xgV*VgoP^uka7iu-MrEw&vv zZ(=X;^lm+gXqvj>;;`l9=0SiGeOB%U)@AT^*(Q~##y+s0g=~w9K1=K6VkAVx-7_c8 zt6};<;iqbaULke0zXSA2_7U8s#{*=xND?GSTShdyw10ul9V!@tFw}LwY@||ZUQ*Qe zM<-6APkAq2guys;nFrx<@8MrFXk(&O%-TFgtxngvAoGhjL)&0GE4CoIy#Rn3rNX>; z0o#%S%rgjSN{NxH;jNo?bhC^qP=#CcMmQz4K*CUw;eV0`moBkHJR00_#t3?uB|wzF zaZGqrt-KUWkA64WZaK0V-I%7`m1Z+r(W$7vvR^p^iR!1{N(@vxhHQ-qe(ABZ?)Bte$x2H)oIJiG zxW_{-d1%iBxzw*4pH4$$(vx5ViMD;NSxZ)Oe@Cf}D)tG@yO7P}^d$*$V6!A-N_A8) zDi1{)k*ym0IHKsmC#f=CYSJE#9kf(R?`WY^@|VRu;biu>LW#7(s$`LrRhY(-m`w%0 zUwbTzsWzj!@68TjbvNi?En`XQ&|da~Cl)GyUDT!m2Ont%%R=eSY#+#_queX7&{0)E z05bJ~MgF$8IX`hbrGjp3Vx==jL}?M1x^L`S?e4mM<+0+&o5yZ{(cpj6_g^!ovJ-L^ zcSs?wwlFVGh?UF5CpT+HQW4Mt{s$Kyq@?)t{M;cA_>45I9U(Seq5kh)mrgn9ZG0ZBIRd~I_d8;X~ zn>wSFf%^P+ok70anTzVaf;L*0>{+2UR_vip##sL4yInrjzXT##ZGy?3$2l+o#c8_> zpJsub-Mffy8qW~(C>I+!u!U;eT1-rRT&SbHI6z(Q9g$C#I+pd$Pc;feK~Fl*@~-nr z2tkk3?P^}OoC3U1EP2LOPQ-&M;XBHp)(_VF8HdlksWYHI?LLyI+YOF7ZY#-`sL2)( zVbSM!>S9LRVXP{0SMSxkDrymzYP`5$@ycbcPjLILR6Su;OM^Z;sSy?0fe5vHNNU-} zc*%P^#!sb5Dm)PmNG)&4V|8`V>ZfW(`)4emw;6ER=uAvEkq4h!N=%tngKO=2>&klA zO@>r*Ih|~v_>H&x`A~0$_wV)1Q6|{Cqp{un(JN{+Xu%|{ZPe9T>G_tMb-y$sHGAav;o7*~d*g1w1DJeojbf&T#i32Nzl%18jl(M`Fr*9( zy#5t05nA`6DvsLtKL2@oZ=Yl(ujr3`4Wqtm;gJe*cigxVhk~qRTH4b7c?CE6nEGCa z=9=pq&y5{{_gr)NElnx&?nG%zT418x*$kz1|5>lu&^ks11S_&!J%BRNi~^Rnw>n+k zlotkFvU(J^?S#@_dU zKC*yL)RR-p`SbdtQ3|VGHqE^8fRB<--Z>#q!Z(|`?jgQ@W!34)-fG4lIsAmX=e-Q$ zqi4AyKm0`CxJ2twl1uf(Vpox0m1;=OeC4niG>;5AX(c!$H&Z@9WFv1 zlg4qrvNgGRluH1&a9!n&beifj&VXsCM;iu$s$6+&nb<<8V=%4-> z#**|%-y1f=v)an&SHvuf1}`TJzh2qP12z~v*Lh9PlAyUW@Ad|&}FO69_v+%qw6yhiPw(~OY_b2a;Dy#!x4(6d-y5WUUIYEXvb2)`T3i|zb>b#DR^Thb zXLYQ6ZTK$ONRy0E9d#PWcT0V89M%?jw^~mj!kohvypMxLz7Y88jS!L@H9qLYp7VK- zxSc-DHf3`6C|qJ^g3Dpw*can3odtz*HCTUL9X;@n4tSH`%&ixl8Y%q}OssIX@bJ?$ z{^Pw=nt$l0w49zjJ9zX{;10D&@nso`(K8WPuyZW;$upJt);`j&>mRU+&L0mWmUiTP zX2b=ubq+u4H+RfX-l%S&{x*H{Ow(L0;OKOoE6>hQ2#jE8w)m$zn^S2!q1^;g!(Dbd zoSO&}WG?#Xc;FvLN{VW&e)8y}Nrna5Wb=B50Q|0%LNqSLBkp(2*$XeTy@;PBH*Ed#pxaP=YrWS_4?oc!@dyxU37*1s5bAtfgWs#Y7qUK1j)oa9`^=csY1ZYPI&aJG zto(Q!8&3~{N(au!_>Kt5+Hmwq*#=pj!#4CKR%Xvr146{0AJ1Bjalv1QGM25+nYwZB zDgGziLiB%di~rv^t&Wl$K#A3@U``K2!~pp^|KAC&h=7o|=>MI}tflcKWrJthGJd_S zllp$0Uc@;`&?>auQs5rhmDgRC{P(!8yl%HFzxdW}&3})K`Z93#O$#{m79w|X_KoyA zaSOdW0||L1^I}xMISM8{(Q>>oz?r>t(sb^3KlH)1|Fu6~;+|ZqFq`mlo~_lxd{8$N z1Zf-kseji?)@N1xNM2cwc$3!Yrr^q4?v!rq5yskR!QZ$j;k;D7pJG|M)M)8qC}c!$ zgqflnzdVk!z$la_wwtt1myB;ZRT;a8uFm>2&%2N}@>Ivy3H(!&CL6*|qW{aVAtps$_rtY1GXL*S@ytqt)`QiTmTz7L5lr zW`QL)OCa@fF_NWz^#+k$$0jXhW5*^}ofgYjOL$85JeSJGWQ?u`mnKKIPOiUuT{E+N zHhuj#?Zsqd*y~PyK@6umlL&x{6~^^lI{fG^F02iaaCyMe$`6G z_(SmO)B620y7X~ZVF^8%rCrg!f2+dCPia^bj3=EWLV^ z7F!@JInN+y)_1t$9@BpV?R!;?h()7utStlT z6dK(VR@L>!2^4znIa*k5^nA6Za^8vC>DnXq`(M(WX4t*{8$R5n_iyCif0rn-QLVkc z(490ru4T~BG?bgnsX=MQy~CVL|D5|dc<`W}=mj`s{xI@}iz_|qMoNGo+FT949D){B z$Hx-ER&(1@`Mh@gDzUSfVG>QC`9&aN~sa8SnXoQ~!Cq!?j4HVSu%AQ1`z>`uQc zI^Mv^uUWg+l!`LOiY#4}wbwwuhkt1MHu2LxKjL98o)T=e*76%_*Nn1VJQFKKYofEb zy`V)A%x^b)olUKg3t1d%9b=?4txj+6`eu1H5+~T$aMBD`^jD%iTvHnL&?E|Y!kq-w zTC}kgKMl5m>@v(=ghm_vEQS6v-Dhh}r*C|`Mkfy38U-WPStS!cT?>xw*o-WFA{?EN zIrJ##-CvU2?ec#c^r7|c(4}8uT@}VNlSx1I5J#NziBs=7+Z>NpztQ7*8uY}Aup}Yk zB6pK!hMaj7@YxEmk06Zt90&tTki6B;6GsHA>TJUuso_PgbBcyvC6I@Uh@NPPBe9HW z8_w6;W4kH*WDF3yo zTc^I3p0PZlk}KR>^)F+938`wsoxN)Vb7QyV@Y^JWY!O7F9c>j_p%!aKlQg3qr_XDo z9D=s;w{&#}2L^B1tNxnMVt~IaNEwJflruwB?07?4wNL#DT1`7W(;lT%Z(IaQcKry2tawC;`qn zAht6Vx4C=G1A2@0dHL*l_=X*k-iCgW&Y6e|6nN7=3 zWydaHG8F9lA+?qLHn5L{#JeC2D22Y$nK$3_B(G1~8Rc6kZm~R&II>cBnkAD)TO8fR z4`)FaQ4_4Pryl;rhA$IDO73FsxlmQUQH6Ovz%G>=`X9uiU+c>litp**<1uZiURJQ^ z7f8s6UZ~Si#*a$zqCT^I*{tfyC=!CsRSFi6Y!)!~H~Rx~jm?X2@8`~0xcF(Dg0_JV zS=PLCNja0LxD8I1`IVQYtNUYfPcr)Z_r?h%hPULr|AQyWnDsjeVyR9p&Ng<1^0If? zgvlz3b|4?>-B}gzoc5eb73fqdSRrQ*USIsE^A{B>|G`|JXTWLauYQBXNWBD%fDNxT ztk;IHjW>E+Q^}Bfh2XE3;N;tpm&!wBP*-+KvD?@q^Hz5(1Al;o^$o(^~CP9@y0$pwnD8mX-1cma2Lj1caU;VBTWD?cW#^L#Q#*M z3*6F%6KN+nKohIOzgIJ0p1#8l>uad#qRqkhcmqReltz8E#{4}v7T+hskK(3KXUoTb zPa^sk`3^y6sbVqjJI%%Y2V+xoK%Y`w3Ghn<@Fp>gN0o`Cv zIDW0tnl}s!G3;EaaE8u+CcsHl%dy=M2=5(qGHs-U~f0$-_S8)Nf5Yag&(LFhiOeDK<;P~sigf99%_i9%1Y9cM%hauHn1(eVT}(aF?UC=9__AUe}C z=0LxmF3wc4;MM`fx?sl=q^lv zRQ8Rrb0UQJCk}17F#QqY4cNTB3-wK#!5Meq)^tm`*#J!Gh(f<z=%TWzWL ztI)rEqYNgN_p!rY=hnc=k84kteXsv($uF7bxE51OoirGmow&SJ{e=`h)FXrvB8ds? zRIrR|{dt2)In!VeKSIWaH!lH?4G{-ywsm*^@Zj6b{MT*WPMgKahGxN|8kM!?%lEtE!Vn$7CFW)_|ChbYE zgW-flXi@~&3a%19QFPcq6R($YH~N_vciZ)AUxs0Fuz|JKuGED|rmP12W>zq?sqqMm zyQ;fCPo3=iT7MUeTe5<{W*maH)YjW@rtR6qgfkUTuw>H*eIkeP{e|cct+&`d#h5nQ z4QgW&ckRNggh+mcNIOrk(+4?(A0E6t_T_8BPLwDfbE$3{lFh>%7qyfu>B6EH#*5fX7JdkO|$BJX`jq`&WB#RAS$e z_r-5JEjv<~236%D_*s1OJ%c^<`?n^D2}b^1;Egl3AOQ3yq5xil>8ptPggfl~rEJZm z>Ud5uZ5iq}5{3Q>!ju>!o<$Ih;APH`WV$5Ga_~qb*-cGMMbw^b_+V0`PgQ@J=Moz6 zx}tfmp>hGeku&e|ugQ2aeRC-G<9&hqDl7pfJSlZiW6Z4?0Q&5o_>@z6>EIWR8Uo-)VlK@Ap3m&s*)_`WbMPS zPQ@}{v7n3(>H#!#ggef}c*MRxPeittF)6aZ_;Gcmnig6pCC9Koq_32M2&T}VgfSIB z;LdGRC;J5T@pqkhn-8yNmkmPc)gMrMXwlG{Leyb+gy_xrNp8f1fp0*2T1d8-m2N1g66r3nxp%Z;N8(xh7%>5OM1M(AV@m?w6)9-L+d&xNBwPV_U+Ssmf`~6B3ZRLA5Y+7kevzdc zX|4VI&qYneuD)Y0V#@uG?YfZx%Sm^}U=y7`>!%}`&pltp+%SmkGp=q+{ebJ!QLRBc znHsAgI1w@esj5IvY~u9by;|rf!0WiU2FZ6Z2=gNxU?0Q3$J4?l^!tZRjO`}DCS9qX z5H3}o9=%X5Pi{V!jb*RB+A${aRi2Mjt+C`)y#GSTX2i;!#7Q&5;`+V}EnukObV;h^ z=)2r1a7aJFniH5ZTTSJv{;~5n={D#AS(}ZbcH+a!u!;!uVOU@3b}{bsGR)Z#&Z?=4 zesLZrC7!sR)Hi&EVn~|T&62lwan6PJ+DJ{nxckByE%4a4-b zBOlKiwa^SyFgrcG`JQSDX1Gs~m0u}E<%5&;3q?z~$p6LDSI0H^e($S*G)gEUWzaFw z(I6@!t#k|--8o=15~6^Df{f7u($YCPM1&0x5b1WKLqZyUx1YD)-#`ALFPOWZ^PF>C z*SXGpEL~Xbt)(P&FmIwTllCYBecaS_bhaK2Pl=|Aam?uIftTdS}$ruP$!X;Z`$g51kL>-VRZo_Hssy(0gUJY;W5*ugM&^oNF@ zo8oKl29Ks{P~$jpXtC^K0oT>w2RazzPlqa>5;(2DvJ4ZlPPOcy%Fi%{=ke~J&dC9s zPOeSBr)GKViXbAz2rew@_Z_X1MA08JuA-y0I6sb0Qi~Bb#L*w$Uqd$-Iu~6dUWUqK zG5;S0{g(ZrgJ)4n$3h&o9$S>EjQ6-q803nuCH-3=0gL*gkNR-NUHm2LfAKXWP{5bS zgqG34*f;B=$i)bQdK)XPlhoG`?0k%s7>Z- z=uM?Kxh}=Le?i_H=O!TeaP788P{Vd`$w{f24(3xU>_O@=Hov1FY$0s!P5SX zqNV|afa_;;Jb1&`C%~i4f{tLB(9vU)uaj+jMbNW9qrmsX8i*iG&gmUGVV=SlHSj!Q z1V51It6E`a`Y49j1{-}JS-wOVMEP31cR!nkX$*Jn;Zp6r|LV&2uNPfX>0SPPZ_r-z zwgzX+g)k0bMwQAc`H^#uz^|~9C=59A0x<&Q5~2ZCERcka!r;WQuK>X8;wMPPnKO2{=2o{Z1cZnhUuWIbWQiWsw3p9oY zXj5L_jdwR(9|i79n&HoK^l^9qu=W+Cv?|r}(b<|*u>hy%8rgt6c~4=CQxC_fL8Y}4 z95>i2dj1B3NJ+_CML#wR@i>f5uNEb!l z(!+0SalR%6cXE)&4GPFqiDPjD?h(A< z5^7xMaR!Hk0;ZE-cdA7@z2KV+VvygON7i+cTsUsvjZ0S4PTSsETCWenGR zQi#T?R=&X-YCFZK6rzuxf)KzC^~5FHB&Ay>jh}Pe?%n=d6>7iHqfK&hjdC?PpOE8n z#wHWQ2%=6K_3m>RKElSx35Rt0t=gW>6~gCl4pr-#Ge*uQ-6a19arjZnV4Tk1Cc*9; zs3@;{O{GL&I0f{JEDx9mznWC$xr$syFW%ldX$rg@e2TKdwY@9B6`JKzJ@C+9k#n_U zllMZTqI%s&J{f82#Q-2LC!BX3NFBx^NbUrg9N3?Tpq`vUUz*2D|J0-+ciAhtC7Vp8 zk4{^}5*nUVekuZwIY~Js8Ym^C1W5p@Hd-gk6YwFRwDWd>Z_A`7k{2M(KxJSo z7I^tfAH{1)umd!1Ujf6SzLk`YQlal~CBs>hnPxj9NjJPVmH!>dRSx!C<DSjE z;XlOp`nYT0jE4yx>Qw#A=0(Z}HgDasyen=GQ)29VKds1#8>H7aae|46Aq6A0MXHq~Gim~n!#{%RM z3Gl2DUbU8#KzEs*V_zXtlj@2tWCR{+*9m)s2c-zh?*yr~fN%=esyhEY@8bjbCBGPa zLKyjxQ5bpFHH3Y!z(TK<_E84IP|qMv$_C<^YrW%CojUMgE7aB~_RQ)2e~-WU-j^Nk z^r_!(W)ws5FMIJcxMzHXEIy=Ca!#@+`h~to*HeB1-6cfiH3SA=;xO`jfC@kz^uQRx zT@-6EdJb@xG=S{lY}Dl6Raoa>s}bMqxW^NMrBp z1p)m>aUwJSU``~F?IU>*TakQ;(>;TkkMY{h8*;*odQ$Q~&%<-_VG+G}9Sl%P7J(p# zEnk}gsN4df7-Oxy6YmIWDZur+3K+o7d(fDR#pmRDc)!GJh~F$&Ap3yy`q+3Uo+?vK zxGwtKH>`(q3?|mLT-bIg)6r`RKVIp?ApI}Fve3ODWA`VxYMo{vOFUGwdIl~bS_+B< z=(!`f$6=oVJQu#`j{ve+?=$X*#blAi(u;tufr_g4fFG-|tsD9T?h@n(4nA1;A`nKL zfzXp|4gP7ZjTnTexMfK^cvYSG6nPv+YVTvXdbjJ_h!Yj-S6+P|+d~bpV;YD=aLU2( ze=VjNl93(HSarFgd9c>7$5(=sUM-AY-xz&K%UsBm*O0mQO^YvjPT5WIea;&S68j*KVyp{$If)5BK8UMv zIUq3ngk)b`h->F$@^ip!|AH?7?f{pt83W1zU*c2oS`9~Q6=rqetY3z?y9(V-)=YYs zC;V!v$=3QYc;96F>1EuM7oVbb41TPlXtQYABhm2=f9%=lzt@263ORvRTy~*0?+lUa z0Ysd^7QiSF!isDO*;-UufT=zeVWh@I0-{^@BMJk;4M<+u77##nL79mL;iw{o+CAe2 zSlB%Q0H^3jcsf%0Pb36mCTN~*j?wflPj)W^LGNM5&Sg*`7$4&`DRCu3$Pt--_p%rN z!Tw*am-|8sm2J}ZGRz=(XES@yL}P>rViVj_x$bJr*r3?pE%9pHj8BW00;jG@r`(BbJIK0I^V>IOm&Cfq| zHFM(!j+Jw#)qh5A{){qdGxor8)*2o-$}if88LoM*ly--+YK;z{S>NW15#pR6t})h= zgmLgLS_&&dQn12xKgNiWtc>X$gn&#+uJ7b=GqnH5OikS7To=aPeuP1!gq5}R`Y<2| zYgOWsMfR^7NC|@DvQ6f+w(yyM^OvfegkYYPeJ%4oOD1;otFdX=3urN7tKqk)HUDGs zr)&{T)GsWHrC{OSZsZ}0<7toMR6$vhpg!kEtqAE2>-L%@)2NM5neHdL!*b2Ppj=kw z2Guph+H(rqw5d2@6%cGahkaH)MPrXU1(uKME<4Sj3%7Iapv~Qqk$DeZf$OpdQ&v51 zxhH*aZ{cs@zqe-QUbEAj-Xr_@ss~^5H^l+9OG4zN2H<)&#%uM=M}}WhHv%{mb@6Mr zdPVs>i_>M&==J<}mH!p)?Hl*;;<27uQYc1fqM-=V8V+&%I%(YroBy)K%tsIfyjxTx zwa}wmjPUr?-mkK>%HwOuQL;77Uo>&8J$FiZ2(K8>lfXob)5yz0&QWJI{3?q+=+4-i_(Zr!SffF;!6^eHA>&o$)x zd!kkIV732cD9~Y=x+~KUA??+IIBSCUNu~HN?OoCh{m=^Qi^B9I^#u9}EA}xVx}{J= zHewbv^xhH+G?eK^+c;ym#GTrNgC-8)S(ieA^e=*2_vneK-{1@cGL&1+keAZQWpBH+ zem`#A3+U7lG=eI1UnLG(@QfJv?Pd1lh{>K9AoMmqDLGvBXA* zjIN;#Y8camw`YewgU(gzh+(9^bG5!LrLXw=%MS}it|U&rRC2W*i^?&AW8YrNkuA(nv{NX7My z70utN2LYu;9q-YLmWl1fQ{Y}IA=bRVt>>PY^Lm&V!F7$q#mB_&&rnT>o_=^#COL9@ zgZ|}Y)STQqQsc#Bl;e$C$e3KILI<^qPD-wh8xv{GF#92l^iBR##r7{-hB4q*OAmNp z`o9v4e~-dIKd@>GCWf+S5=_Jzn#(Y#eEp61FPMX`aO9&?{C=L31Pa)nYMu4!iTo`H zB_0yvum^C>riujXPZkiME>034z^^vx@`XM3Qsuk4YJs(Dk;4q{B!@2%l|OX%-^Cul z4&KXj?aR!paYQflhPirwbto1>9eI|#%^Qb*`g7T#A+gp1z^9VbYe7Z5IWHG^povMA zzHI5MyQjYq$!AL=SN`b}cVPW8KAIC^XOa3i&dY=>dsNHPHAL_{;Mz)vNWQLT#zv1D zjGhB=L{7L%IhxQ1*kVabKms%6s{{eJ`ob};2ktbNrnTauQmp3)0j z!Bpv^3X)I;*LzLH5^lLBTYHCE`{i1X(sbJIz2-4*=KSB2`(_rp;7i{hK*{$P>&5<2 z=qAH)_M-g(G|THlH~7OL<>%c67BsRh9Kw`IGX-?6c2U+#HP)CI_6Yyo)jb1xF57Xa zh=#$4sUAsXrPTB|D{gok-M82F#BpC!6X+to87?TsF!Jp}*kd@P#EUTmgUiB*WjZ!Y z$PK(zZqfbk**uwhk#d90-v4Xx9Q;zxUl!V++&Kw)E;zIryZXBZi<0;G9-ux;pOkcM zD&G-{uS>YYCT=9`*<0fzUbm_KU88gOEuvV=meNx8-qGErp^>|q$dsOEUtgNNH%=NM zB#WnDb3EF%Q%opEC;vlDzYg7H@A$ghGq;cg==%}=jy>vUPH)qqp>`K;8Q`A*0(agu zzz}ihqCki+DWAmkq%$y5-R0aBiv|Q70Q+|2_w5`H@#WKkWF=B68 z)1x#bP^yiw+?%x7UrN0A-?QdrnYwGz4@tXBZ>3Jv0u@%)!4x@dnBsrP0=OR{C8CIj zd%Zk;YNa3b?FOIEWO-3{wi)9u@7HF}l?5nM`}A}TKBN*^7DEYEHoKQEqo)G7B5Es1 z>0uH!B}s6E0p2j3+eDKw-M-DsXE!?JpBV7^7v^q%K;#%p@wtjIe1jrI&B?lZ5fEt> zbi-$KH0ZsM;k?2F&8)uC)jkbxDtUr3ukXt?qyBV(>~=1R@uFK})0ojt4tv?^mABsg zcGGagfCz$#4rz*+OmhOO$1Yncj15+>1@8S*7B890g&-G|w4g5SJ^l|~QCKaG1=duT-M>Y-_&6^uJK}B{d)?y7L(* zw|@y`v4A~&hy69g-*S+m1}Lx%;-d%a@3KLTZqe7T1}J{f(N(os`8w7MD=tBdjkthh z;$7ePumdRa&FAwvPy^@sBI;*9l+9rO;qXsa!#|SrSi@sLhXe>2NZ`!Ss(eFC*!9_o ze+0Z5z}}KJC~!>I@KmYqhhA6vJC?XNt8_!e`@e^TBxD>#kH6PD+Txx`XZ*TWk4&j_ z6-+)Z!*r)^wP%+K{Fm*u$z=LBd>?!BtG!CLIh3hBR{`9Wm%f8PL$h*C6=ygnQ7>Q| z5q9_2JJ}aMm+P^=|2R0m&9gzmp$&@9e+0eo0Ys@#HDJOn?U)jYH!N$p#s zrY~9?lr2e5GEEYXy9I0?@kuD}%2mkE*ya!a^2=>1xk|z^Q1CtUaiBQb)61ezlUJjAI zlbIzh7P|6A&dm7q{n#4%t@mvx(ky{8Uhoxt3vJZ8?9rWn=YY&zUgpf20@BORlV9~w zQZW{Y4=mWxHyC5>7;7EbT`TWw{u^-*H>hrZ5l$sy)*bZ9=VN46e0a*>(xFL@aqPeVsmFheAoY5%FmzVgpsAMx8DKsPpR?EH~B6JwA)A`-C4L4l&V zxS>l3?i8W~ON}Yd;BSwlzKd*$3g1)OAx;vO9TT+*ytOK4)HZ(T$aKOOM0!?Aq%8UV zwP=XK6%=VOW8lWKtMlKYq*LvBOP)DCm*SV@^6dO&$mU!!<`tm>=u@-R|9#IxjUVUv zAyP>w%cSY^U)p%kchI?n0HuT$9Z$m=X|!CiEIm`TLoUmQ{i8cY&*9pC*bJR{w;c5* z(Mpp0lxbN*#a4a%uHlA#bwrn$=T{fx{GYrH_zKP9hR>X)!G^^`^mIDs=UJ0K-=NB$Y}svvfnMdVIF=*DKYJ7w z)q~#*9{h09%3>K*IsfrvXA^rMQ6&AfSX$Y4rQK1U+@Geo@ie^EQ`)P6Y3E0lQoKcj z?l%L?b|b`)HQo}WW~&?|lTk|%Lb3bQI!C^l5W_d6uF0AV!xED3M88Y8RW0}2?88lu zu2H?UnaM})IVhJ_?X8RzwyiAnre6%U5fK&K}3vBJ4q56UGT!-ip%YgnR`&Otn<}{}D`iAiO|u7~e1h3jMdWI)^e7A-20PkC z7VS3o^ez-uRXrYA()v97b56;^82RUWyPK|tne&0RMnDlC{>V3c<8n$vOHUIe>m1nX z#`jMo>3if9a~*vw6dZ#;<%;0$N6TC$(7bPjDO*UX)pkofeerbu(b$COwC8$ASGDq| zpRqT9&4`oC6tj+!Iiol$b;{(gUeg}>b3Rd_xaweP-nP*#(WGToQ{R>8HuaH> z@fOll-wjIY-&~`ND3X9q5LFKB$d&vMpT1e?hs49cakaR4fSq{(gP9y9 z{i&yGG11wmxgR1K(;2PZAf$WqmZt}%q(ynj1Y`l|}_hDDA4 z{Ed|HIX%?26K1Mu7c_`MXSOTI3o|mjKU7KhJnIj(x;&$TxF9}_bG{AP44f)AyFZd~ zI45g(S}?(S?1gySY_d+MkUD3~1L}K;#Bct!8*GhhcZtMYycO@{EJ`Xua^~_JqbmGo zQ#-%1_2F!01Zv;ZW;ZM8qk1_h(^Sox$Mzoo^jL5UEn4|<)I1<f~KFLUFF| z%UDnFn!|(+3TQ!*@W##c&VTQ9H8C{ty$us!e;GH@LAN@`A|}ftK`f!jrn+LSdr~{m zYu}Oi#TR#&LMfeWiO5#rlq??-mJl;@ZiU&o_jEv>i}t{hQsDc;mIS=VYVG|3&y!C* zRw<4^8oT9*N0}~uqS2Fd>Yfd7o-3-e^%Vp5D_v2+K^0t(NN8mK6s!zWCqNzLRkm&6xw`*3TKF;MI9&^0D-EeM`4IlQu0IXm|_Kz z!)jx19r78hzGOohA3C`#O|X3XSZMp^#*5%5ln=a8!e+jB2=A;ev<}Sw&$yIRx%a18 zRj_FAvf~cpN&OG;nR))io}BT?;W^Be1pi`Q*SSl@l=GgI3BB7TF7KW={T@J5aqlZn zn(Xm-mR`f8-pG8I;?GfL+8$(^%(aFtJAIkLJCOF1)noH|0`0 zv|KeEV%FjM=Q!|yXse4WzS{|EB5-|+(fk$3#c_hX__5r zc9mlw)meS@E1Glb=L$WQBQ1>FTHB$9^78E=DD^%8 zQ>msaFmX;@^FKw%_t?^8|VM zMCpJ$`0Ru?K@}`6{bO`6S9Z7KD}@Q4bo*2YqloPJB<(@SmgPV*Eiv!SQHIt^pLDQA z2<+)*q4v&7OicWyx$F8yR)+Q@)dMr>1XbL>zdM@&H@c3asm)x>eWZJ}KDgg$BZ3J5 ztO4EE5Uz*DM(IGLMBjk0jcCWSF`0Uw`Xre_kW2|!SA?R_ht}m}qF}US$1!grxvA<& zFqWOW)_Ssl9laAT=r~mt7nAIC=uMl~0Qz7hDS8_&&Vu&PecH^T!xo6dkH-e=n!S5{ zv>YwVc!>ja=qq#4)ThpD&Je=~!Zr6xp#{${#zQ67R^8d5`v%^M1q(_|PB?DV1Iatw+mw1Q6oqOQayH$i!z1Lv`%#9*85h}wen#+w)!c4 z6q%`m^{P}&64|$gF78*In8-JoODO2Ew~o=#oV&qDJL(r=e21qg8XU3*ZqU3cx&dIvL{1Vc5WG6%7Eq)q zoW{xJ)G&ooOptNnf7ksszXclTy^ z(j{jiXZ7-j9pbx*|EOM-o{S8V7R*Z2f+~ahuZsaA1A<}XJ)phe3~0CD?=s)dy}pVS z_>g^R`W8>n;XHobdq^2xvI>1=CCnYqnN-qkh5ut4^rU3aUA3E@VlYl{VHn|B9>X)1 zgkpMt?D&RZ;X_`}lrh;>S(cn%Y% z9EY~1nmW?PoYNfUchUw?QskYM(PfS~wYP1@M1I)6GpRLKe(xsrD4sEz#EzAvOoT{` z-Y0Ob^X0>VbBe17AJf_JO5@`6V@C(KtLcj}X?;^daI(qKokN)3u(HB{MM$=g;ltVq z!6ngl6=r#s^i9!rFR-(9>!RToCCZM~`Vxf`spMSpP0<745Jp=0#kt{t&tEt%#ghK% z(k>uobe3d+B&vOvuEPrx?YtV~^c&WDn9$&2;S<+8aFoG8#Z^~$-rWViM9BBBg^s*O z7oSnn(J}OzY@DbdY~Mb0sm6pSh)SedAc~`{uq;qz#`?!)F145m=FITFD*Q&r!gB?b zw#&+CWVI#R=tkUVjG$_eEmkan5|!b){A#g~d=4Y@R4Q+bGxT7O@s}f+98EY`6`5>_ zb^(L?xDeUsl1cG(mKR2-mpiwElvRnITR-)ZWW9Fe0hU`Wy8Nc@cd4CdJ1qW4X$VQ2 zTT}>~Vu3xbW1dShnY0c!`8{XhVHT<)4~12QHWKjooS999t!c`k2UbQAwHE@k+oBJq zsA4Y5_SM$bYUUAXlCnjKA%pHb1U4$cHo~1^fxFPe50-~czXg-eb2Q~JnO^bSye;MDRPu;PZwoawv@Pa^$bh6Ze6N4qWlFr9 zEEgz>w0bE!f6PhuNuMWs**Dj^tjD}L=ea!#Cxj>Q_)dzWXX^C3C$TYRj1PStyqKyS zSq))2J=$9(EtpiWZPJ0SzRD|`+00lYLkh8UC28j6Xcv4>w3KAwi`xFug)XxLs|&At zUUaO!nR>Z+6H2!`-I~cd4fftQ)nV(VTr$+7<^(?%g7n6-l+~up6Yxm3&`bSB+=LT! z-CJg@bg$C;j!)GVI{5s|6s&zzGC~DbOl&SE(N-!|0lOUNW!i;EL5#(ffvxRrl3FoZ z<}0B&toLHX^8N#RnpiecV}sR>?Yt|$N>dt!38F&+*}(f?qP9TOjmluwcDtSltadx+ zMh-lCG4kmqRLXS6q1U6#H0BD2d?yKp!JmA<8it&smmwI3A$xDo+5gs$sv@#W{wj>K z619h>fGneckN*Csb$OPzm7XcK%k5pf_2F{tm&1$Zi5vyP4sE{K-wiT{mfcwPzhEA_ z&4x37mgJ47ly2nDIJgwiswm+UqW#@Ey#Hd|m5ep|3mbAi+Ao9R%Z!Vg&$8NTuAnHq z6>h%0zZIRoa;ggFrVx7!x13t{HYC~78NFJhy!*O0?F!e{amG_)qqE4%1Uvc;9TTJH z`79~GKvjTtjPf^hZgJW0A5FFPXa2gX83QFXmVo(WzZ^+Bs{GZu+|xNe+4%$GBlO`5 zupY(>Dws*{N48EDQ1%!FW20MP9J&S$cBkcDa8nJ^rla|W`)NYp3PR-s|HCJk-J(Ul zxADD!Aw7rCk&TAvd(T?boDUYsO|G_Px>t_1{yrWlHB%U0xYIfmLe%dB4U5;3ytp3u zP)RDJW6+}9$KRj-Xg=&stH$1!JjS|gzozGkq?$g=?YFmFzYT<5VVA6DL_UmYVgeE3 zWjfx|E>_f4@~4+%aF*zjeIt`cCIy7Vj(XG`hFDxynxc z*8m7S{~s)q@+|tEq>CVdjdKjx@eQG9$hKLv8=pG zVxkG5ck55EGtT&S4IuZA`u2;>X{& zjPF)=u2@DKC_9x<8FM%5ReMbB*9j%5x>aE|TBlgQ(OYY@-d4UE9@KJ$G|Y8$@mG9m zE=kDH%iie>Lx=~RCMS=y@P5C4#n1T8M|~mm_ii{U8qfs^DMJs>X}UiOTNZf~^? zXm0)um#ZB6EJ+d(efhZEfKNC;6v0A@yd+x?YTO|EZb*|@lT?TW`s9%CBwg(GWowHA zJ!s-*4-5zUKyuO+10Kb*dYaY!3u}72ZT6sPerA=5gca&WQKVdCEDPgfP1M{-%8>DEC##^uS^2EWr`( z6w7{Rh@A^>q5~nZx`N8tMfguNA-$b!_T!D9HfH^9xtYs;nxk%1>C1jiD30aLNtF%( zF5%Cm1KyGu`^TqwspD%TjP&BfjdgWUhK1h;GESXJcd;JD`utC#<}5)yke{&*zarv; zXw%UCqIAs7<2Nk6?pR`CNJN%_%lvWvnGWN4xVLIxs7@-gS$lKwRcf}sl_st#N=l~0 z!=mTQmc)WKe%C5NjRw~Z%q0&$CEy1L;S0uvarpW#{=0c*qh!_<+x&!j`dC`Xnc2a+ zXI@WbgE#IYo)pe{rX7#70B^a!@$;#%3g4pM;XOy~T!zw)-j_(xXnG#(5-USWGd=8Z z&GRvXQrVkDnS~spyxa%=!jE4ZQ=Aps3ZB1;CPzMVZ+q{7kp-(TBTU2_-;ikZ9Go6Y zG|m8|w;6kjY>NG;bcs~|REAR`7hzkLRG0qu z1MNb&(Im@*iwrRObT!CFwHvq6kt?vfm9(lcw@ETmb>96Td&!o*Gh$*|B0jwFeUgm~ zb~5iuw+`@IvOSZ)TrnN0FYp;0$efI;i)e9fl|d({|Is@bi%&D)P9bTY)yB*9XZuds z=3Sf5OARK;g)gP%@F(D!l$XYy^uGFpS+%F zA%jz}PL94Uk9m;nQpy@NpZ2QMDf(5mNbfKC-9ONEH2JbhNNOxj7k5hkk2L zhf2^9U=Moutbf0#OhApH6Rcu{#f?gEr|udT4bR?bRoOPuxp=oVB*Yvobash_Ce>{% zpl1+MX8O>*z$HzS^m%EX!a`evYwZN6w?(fV$!eujQMD860B@d3vCxocybH-7M}kTU zIpPg>mI5SbAX~dxu#CPfnyhvyK>n4+A+G{=FodeyvE-=heZStu;}oomb$6!?a2ut5 zkVnrxz#F#*3G95%G@AJ}p{u_OhFRZoTkYADvub_lwovnn*BQcEILDyiNfNS&a(N%W zfh!)Fo%_u63Um!tSg(T1E6FGMNLZw1yQGs#sJKN^j+dOsTX;#+1Y5omCYR^)`l+uB zbx^F|+SehgEV~?bF*PYeepQr(ae8yVrEXz=b(Nom^4_|yUu*h14tvog2F9gu9Y~{9 zY!K=ty|RaN`~W`KChXTWj9th)9%o_gQk zlYEPw*T}Vc-^3`F$n|2^o?|k{@PzOucJU|O6#e)zOnh@1r%5xb4nzpdc`ilSJ0=Yd zi7G8+g&6 z+*HHwF3spbNe+VlhgYFSG5A4#A z?{1|4%QJ>K8r~9;9y@VAd0wan0t375-g!no?pZbAjIxgQKiN{DjH2cmuVt zDBh+L1AzHiQD;V|`biDSS{d^cv&tROVm$$?Iw!AA0RE#TKGGs?Q8A_Oshb1U{oVnY zmP+R>QWx`vsA8{ubJ!dis($QJt%j&~v_JqHoZpMzuun2u(vBuh`q<2D~&@%%gFJh^1Ccj z1Gn<37tE$`0f$A5b!ZQmbJMa9dZ1Ft0CA3)L56OnS_G#Ah7%{a|J?H?4_5ln?Xh}A z)NVI0j~{u*IME)#)GKKDzV5^xTK zKJ>Mk)3Z3^rX6!IrLZsZu<>uQ3+a(sm!}POczu!P!bgwFF)BR>?e|oL;IkJi?a-ru zo#eR#Vxhns?ZYEV$~?~lWOU!SAKBa*Ayk~$<;lTea7QG~2KBr7&`aWQgn4wNvI5qh z&PF55?b_cbKfk=?e(_j|_6nQJvhXlF_|-mlTN428?w8m+>oWHX=k%7dK-Bi57j$fJ zc;J}U$Fa_bNR?rrEt}+|1EOr;`e|a>IA%5+@4mKvclzD80cRv~?1#`;-+JvzDMX>wpR!k)lu~m5mGH#wW8N=un)r&xR&65nN|1_V(!t@aHjPV#_ci zg=FV~5>^VU9_Flui(*X>a(4~v=-MaE422Yp`;Ly}YP`cyY}&KC5mv~ppjl+2qV3Zb zo5BG*S-+H{jqu^6&Oo8ltGaq5?}On(%#x|N#hpc&XB~msutx~%+dK&02zVpeWVazUj6kw$-^W&c&~c6#AKN}ag&nN96Z*VH$&OpRl0jJO7Tl9``N+H)t@Z(4aBck-WNw&1_`rgo7*_qbH_4h%C56V#kehPV~Bg zxIuw#dMT0CfySkSAX>)t47gJut(VEiS6dj045b?hSdNoB7NSX$`<(YnI)8ura*r>_ z1S^n$eNu^|!0|F!60$<1eh(7DeUfuZJ)CC<-ghId-((~kpf0EK%&NPf)3azbIf~L` zQX2#nbQAAFm6u;WaJ5UindykG^;X0fEm`mx^nXqPBXH4MsV&nE+L+tJ6RNKHLO*M6 zg$(&(uDHh(9zMf(3#D7CXw*;aNoB!vb2PC7@;!Lb4pVdhFle#7#)Z_Q*38*i(ysBY<|6=GQe-u*-H@f#(~IVZg(CS+wrnY`a?`20x6BAF5r}!g zhUk7I)7&3snpY%mZ(bY@?Qd;}We6F$sY~-bW}eGWmVU07KT5%$Wsv@YZF99_&50Fu z)x;>s&%$Sq{u<~_hYi!yFzb1|KHljomHJ)XCoeq}LsGm$v8>^c7MTOE`pHQoCK` zGGt_ESKW=pwq>THV0Iw!PX?$@6YJ?6@0(`Z+Xt$KmKi)TsyTxJ^1(;HiQ$}ZYS54P zh&=$Zt@cSkBCU%;ogInNM8|L9{Zp!NR<`Fa$DAVY9=(^gJDzJ>~NLpNB z5p+PPh!KD#=R;q;5xAy8Br*i_XVub0xVcCPG0_u(R*IE^iJ){h3qd42#iffRP%*L47D}#+BPBC$=DoN5KWIx}EeHqe&l=e1h=k{6a z_UkF!G=6Sl{57%EYrR?CB-#Hf%E}@+=yI+#d!jw2-kdV4dHhLn`cs!J#S~TGdKsHk zMgSC5^3%g01uU#2{_|84$7mpMt{yIh8d~19w>fRCd~w&PW#*iw!XL6(S0IF_ARo`z=@}j#I{>eON8I|Pd4QRi|YJ^bZ3uiLN1+x27+N- z+N(0A5sUIxk@=a6J{NW8`(O)Mc72WNl{jrM(sBvqfJh3FS_VS5t_bkTmvPZymkJL_ zEWd<7IN7)l5%X+5=Mj&WC4>05&{OtfeeO)x(P=uXtQ`o~#5pNdE$rvVJQ-RwC+b2U zjKBWCyy-*z7)|v-`SYSywTn6LNqZFK?MAG?v)hv`1-PF=Fowz2+VB{C5d-YV-zm_M zId7u5vUk3{H54sH?U5d&(-R0bZom4uscdW@?Ny^3E|Wnq!69eJ!zERX>`76+Ha-b2 z!yK(K*!YFtU{Io(FIBKym!6-xVEn_1v#{jBz4Ie;w?+QoTx&Q&Ne_2;s`V>FBH*X+ zo712xq?!VWSmGEa&^Vf0Ori;zdsOJEopZ^cZrDLiql`TLn~yBS#q;juTek~A6_Aha zo~C93*E`=TIzdxdy5y1=I&2wa3+9_uE@;6@N091K5i(3cx1QYDc$D;_r+UKqU@52~ z%O5MW(>+{?e107AwZd{yI=KTgoOYrk$eYBz5> zeUG7+v3_%Z{ZVLd6R4e^7*!uLe%Pr&^`e`r-#T>VBYSQ7ovz^ezMHLw46HG~EqT7W zG+guCK4j89XVvDlvY251D+ZWE-mPMn7#oCb(VYV}WLi&}mtsNcepMAk1!e&r%I^K` zN*A`hc}s(4=bX6U&FyoUh250cKzOw=wPr&9Cy$cVcJdWG9xp>oI3tIMvW)BL1;z-a zDn0}~hp@^;#=6d5LIdNzmwv);}z@~#^?bHGZ7 z-*`Dsx=fMGwo!Gw;di`nnZ8wya^km}WWbLSV*fi%F=cAdlwOxw%2+E|wlI<2MZ{<^ z08U4&qf2whS+`5U7c^-B!#<+`E!@?Xpwpw!x7XPCP8z_wHFTMR+pz9OCuiBz>7Bt^>8-3 zdSvz5?$aUA0oN|jEgA*_xGdFZBv-sj9evwRBAEf3$`EI=po{19LG))rK1Yi(v;hu* zAyE-S_}PrF?}=yVv3D<(o7BWPT1Wy*qEwf5P7&CyK8PTz-F; zOh6@TepMU1QI}I=;(+N5kuf?l<*fdQ?&CD`u8LR$K8ND`%h)8A%`5FSPVHOX#mBeZ zT@#z0YInWXVa$i+I75&7EFN+ku5jN7AR&}BN+lmYK;oKkX3_>NOZG_;z1u)2U*=0R zmNxKp4WB>Ps)n@$!$I!OL$seaY8i}pQ92LYpNNI;hrhj2)ABg`A~XG3oNWK%8{e1l zdAfQpr`XT#oOm7F-pX!WK0Do?361I9il5_?(`e-(E`iovhBa+M zNxy!3>QfOnY;kZs6xaT;?@BiY#Zyr9c9ebjxI+Y*$83ci9d;3iBDFE`y`3*(uBV47 zjIB)!WgHUwwfD_$u>2R! zZfm5KVQ+mTS=xh)zc7BvTlVPRC6T`&QYXt2*YeO|NXqSDyED1%fU;R;zeO@(&W#5m zN%yl4$Z6MU0z_MFl@#?aNhmxKX>4FW71+FDc=_PjUxAI5R$gvn+n21gv}AQw$Lz3L zdvv;G%0=ip<)}QIKBSmM{U0JkLX3{X zVbS=-Jj7#4WHo}RFM}d)#mz&bPpR>(+negF$&3^HX??#U4 zI!FE_HIy_s_h+@Ar7gybqS<;Pve2)?VLInL0UMs zUtl1KZ>nbA)}M=%4GW|)P7d%~+5WI0>Q@gB3}$_&@RX112;ddiIb@O7dx~!sa}!&K zRXXys^C8vF>4Ay-XOHO31pitozfKn5oPKp$hGA=9b(3lPz9uAd*s4HW0W}KwE`_gI z*nbz`de_M15EBztKxEt%{YXM~;?H@2;mo5F@xIy87oTan+^NAbOy_bsnZO!dYwW#p z8DXV?>X=BwvkSj}x0iVKVeydqkKc1&b?NYjt*JIBxbJ^9V@J+Ja~J*eC>oJ5#w6YL zEUkY1y^|V}*ONoZTAXKX(`@aBP?P6L7USEm!OVq|W!auK63dQuUXSh^;iwHK7o2io z^j^=3zjk`|FpgM@`pqq;;e(_!hM0$2Wl}NxyCT6N=7!$T6uH72b?G@H+L(v2&6*h` z8xJK#t|zWQZ%`2{`T#*Kbt}HGPE&MlaS*7eX(9WPqxy=QEV!z)eAD(|d)|B8_9 z^4tRN!z5_P3^Kc;+MW%(tmO{CwO3PAABhQdWheySzfum{I407+O>euhR1T)6H9A?4 z_&0yADf`5PD1MZ%P(z!tS~-#MMeVD>a9R8@P7c%Ki%K|*KH=IYnqw7nqkH; z!_4GW)6KoQyJPz5W|+&ExVnw2O*eB*cTMc~{(K*g-+%DVb6(FpAxt+$G!CF@oqa-J zC!IB^&`w9PAG|S1VZrG6x-Xeix*^L{_iwvotS?n-z-(!|%*|_nN_xka>)ZY<8)*s6&yn=3AN|x*BvCxoY_0IF z^LA*HQ&jdeBpzq%91xQgGkCgC*mPVuFSI{B{Oxh<6ZI~53h+va{pZ4C9^&JG3Y<^Fs#rf_}hbJ+_B%g1~1?1xiJ#qs1YAJzh(lqmApa=)ZL6HE3K+91}FW=}i zbTksu-y1e=jhjfhjM+Ge{oT=zrN}1C!488jYYvaP3_aQ@*Q$z~zNDp=lzd&mlURn+ z+j7DuwWh@osT?Df1B4TpHV~;5(9sTI{hNjWlZo{6hpAit57c9SG&Z?2q7?{Ie|`yR zl6Hq8XbYF0X1}A7^dg;sJS0GSbJf>!YoaP2`sk5God_B9s~=##jWwSeQHm!bfFsdk z3WCT%#OIYEW!7xL+}g=0ZaK*QNbyv=*X`AD92`i*=^LtP z7Q=zvxcdJT@qj{;B`1>H+pLqRcwxL(t}9Wt*xVV#%3%q!v&mLa!9w5K(cmcu z+8U5h%JmHPXux(N89DSW{HV}H4cN%94~=eVdYq=#h0br=CT&XS>wC`##J6PD#I9Vh zXZJ;N96Ofc5aJC6jtH=UtmDZbe)D4gW#;X1=f8EX8!QF-GqjBF%-m0w=z6SsQW(;V z=E9pK{GwJKV#2%H2VIwU*0N8;dofl+7_EOIk%V8#zb=d2+VS1fM-YnVs&9Pc+m02v z>0ICJTDso}AbM>0QsCocTIFn|`j7mTXj)M5k2;HD9?p-&khj_7a9c|nHKKpD5-5f3 z*V&;WRMhGp8L#AR7v3c2?he}#k3f)Ix21p^n<_0S3LGS)ecM#2XRJ%W=D{HrIP}22JoG5+I)eNuSwr(k~ zurMfF%F(J^c`2Z4FA@4(*7RtQES)E4lAKP!gKZOb1pcPt5`#Dth=#EJ^hEL8fU*k2oaB#RW z;&37VXVnp2sMxDP#RIe`G*#-^a~D^9x29LT{KWSdZmik7qtSW}q-d4t8_KtL=VlUw zb8a!uK&%?&qeVgG1-n;PHJ%Z+tUJcC15wjuV=E3&PlvD`T-)@&?GX`kOX}qsPk3*K zKG4mF@0@!Vp8K0RhX~Jm{&a{Yr?fwjmd#a{rx_!O*>E}E$>yWN2q37rTNzh(LH~Du z3%xEpJbB$EcyPV|CP8;%Y`!IY2@YZ6L!K4q+k6kxA{zhE3_|KuU0S@WPG@04q_Q}Z{|@i{AN8*Kv# zha*-|&U8Dih6=aHML$c|kZdhv8C^h@WrMHa6`%iW`T3KQ1;Faxb7G8cjtA#>Drt|H z%zhAf4YY^+P(wOT&1&HR)ju=;`gWfzZ{zTdZJ88npk?EI)p31Eta0AcaW48>{0V)8 zS+VSR3sJp-neW3`;=Snlt!nZw2hrnI0VcR{(-Lvy@72@69wPvs16yr$jUsHC@Op}Y z|EEN$7QT~Fvv^`aQ9niosd|0*Y+&$Zm+a{uP9N*_mhN_4P2rgng)=^RXe|OTEP#pm zztXq$wXPgV1x9o!K2>xT%FL%m}cXaKFDcP7WMwy zl$<+%bu96OcXse$>v8H}=rzAs6R0U)>^k>NAJuVk%*^{LYq9~y3gBeMKP!8qvU*k8K_0wnH@CKmU1 zG-)^2=z5=Pp-z)3s*-=rp0P<;frO z3khudGPB4+DPEh~I&xc@F}KP01UA#)AFKR$0~yYL`UA@^j5+gI}r3{n~PVh{j$Wp1*ExO2wq@Va!i2G`_|M zndOY{c@o;Cj92_VNpD=o39TRcP0VRvY0&X`W8Et+_GHeCILcv zn*M2=eU3&PdK4p~QM7H4-cEUOBwDMZYErFJkyjYnz0NVF$wC&+g@O>UvoAe9%_SMRWL!eEYSHQ>U%hn?!^i z^>BX~;)-gtfhy$)G7P7x%lj;5{2va+9waU|)C4dj;;@DqxyM;|h`xfP8h&PH>{iNUQopVuZ3g27ZAXhIOv)G3;LpGA0?ikMB`HX zoH=QN^4n%#Yyg_<(xIqBwmr$l5Jm(j`#r5|^&5avuem%rlsR~ws~%~b28^b`3%=Hx zaR}VSqHFd-;~LJX!bEL?B7+ICP=Wk$=Sf8VzSHl&3s8l3)qge_hq1*t#C3*+dc>My zA>ZktRpvBM+ysf&(A@2krX2PDhLX~=h3?ZuGvD|&-8LD0y^)`LPewfQ!8q`vF4G8< zsY5~;$^qZ%JND2(U|?}e#6}_bKD&>};9HwkdbngE;wul=&GE0+F^gc|JAvwh$U|=# zLNvF_t1`{o3{aEqv{0W6)vD6{2oKlf5yB|-BRO|~7Tmjfd$#9&TLrA>JyhT`kY#$= zqJ5-Qd(@>L&DoGdfVqUTR>#Y^n)rBqyw;Q)gy4i#=zUJr`Y3qjRR}cJF+G-GG-*|i z;+at&^XC!MId`s=>;5JPR%J*1D{B^kNpcx>SN4?#(Pf5-19 zHT@Qa3-#&OXgO%S8G16|zth~5MP;el(8FD9$l*lxz=1uBilV>-?~NGD}5tcelUk7RxevY4d|H5;5=8)O7lz1)iu> zZ1Jxz@ZSTjuY+W+u_uwnv#WP{zo?p4l}I8$RmokRIM%O+Jp%a7tPI!0Tb` z^g1Gf`hx@T2t?ADU(7ZFJVhR*CQNVT76nk_n;h^NrkH?IntH(JMk{2_x5DE?@wB^?+NDbtWm40 z7ts$`-9JJv6?;{*dD1)xT}`z{t?Dh#&ra-Xe*6}uPnKRN&6g?mzUSF;`C@FI5&eGYXbR}P?!qZ zuo+n9996U&2?ufDxr~HQfz1<9PZ*$Jv|;~Z#BE6{>>^_t(F~a1oa1bk^0u4>Tsx+= zpV%C|@I7ijLj1PMdExvjp+Vy3SMc1zSCm_!P8J=8n^c45=eGuVnuP2%>K&T)!8708HG%S4m(&3|p(j>Lgh}O5*Q!l^6ay4V>AAmqa z%N{#4_l(FuE0**{IM3*Y(|0{5L2aqI2NloU(rPic-Iu)Pe2apf^DyQ`!NL3qLFp+$ zs;B0+iqI{1AaQy7&SXf|D?h^oQe2Lkurb@S5@ z%9@ANU)Uc5C3CeF%WAoXx6k}ubzXhs;FtcjwZ$6GWpa-?KR@5-ku@ygXKX)?X*MJ3 zw*mElhc$}8b7}j7hC&f%aA4r$MaX3>y+wTa%Q+~73far=gO0d&n5^(;_0E{6b4q)r zJkKa$l8-&n8PXQis8usc2;P(8b3wkSA*&vR9n4|s~8)#K<~yEB?AHnwscF9`VVhD zU~PB%sa}oG*fq@9xhs$ZY11hZmIYVlkX^#p|M1O5V5TsuRGTNVOEw^Z8u&vhK4IA} z3!y^6&m{C3dh4+|B_F@P zO^a^ww$pF%MlQMoi;v$PFk3Pn;t=L9cVb+F_^e1=H`6}ypARoIr1#by#o)qM1%YM6 zINP}9Eq_hqpWR*j5twp^AN*suE>T%Qw@&RJ0QO_NOGVZZO(^>rCw2AE?WGd`D!Oj4 zXnN7-4;W*en%-3;6O{=D&NdUU;NQBf-6@b6nrR{t4Cc=M*w*pmE&tZQE$h`f)jci-r{2k0<6*aHQ2*=Q zh$f7-l(Dp1mDK$`A*0Bq_;kK!qWeKw>GE8jC66kagD2t%|CQ0|h!6WiM;;Uqz(J34 zVsskK{izQ_z{`VW3Fm~oMV{ApZf;1g76y6LMg0e@u zo}PjcQxx2hLZUNS967tNlpbMJ*uy5LFAen0EZv056IiL21;zfMU{VDLQelQm>*7fW zPQlV214`YTqL$bODOhuR(vn$wEDhq|*Smx*ubRss%Qe|P{|qKb#h($EkG4ED+aH6D zlIzls1B!AYAv+goFLdrFh8yS9ow^ZpmxJvh!{`#e7&={D%)xxJ-30CMAZ>w zA0IE`T3zr6!xmyp+{HFRgJa9%T_E#0<79W;)psMV!!p!q3sLNRP$Q#c^STJgIt+-5 z3ajcLO@Y6fJNdVm^97+Wgiu#DW0;bOy94JUoK> zU$X>r99FA_-*MMcsy-bwN)_YmXv@#%(yd&mh6@`uXQ4W~?Mc=}ES5ya{C!FbuP=bq zkQNDjpqQ*uh3cnIdT&8mA0F?HJ11=@7*3-yfR)$g21_CV8L&ss$RwPz>X|$^`1V`z zUDXQdSM_p*ipA%R#n;!K`spvYdc9CG&3UVJ+AS=y~1^Sh-nxD73*OqlHd zjGmqE;cml1_8don0#_{VD^}+bYB9|=OF-LnjQ!C7;D#^_o!X6=;&I*R8Tv6o3|`N|Ezgz*oMR z8KEaMy_>2P+NQ8kW9nBq!=r*W@|j2v&cwRXU|lx*tM7AL!Uk!-Mo2F&|2T}0%aTUt zU*B8Af>`P~e8@$BA%15%t;-qojL!E_Mt1+Kvo5o~boR(u)&17@mnBODv}i3t?zYmK zjA}dPQ`J;0og)Ac2R^ziN4jpwER&OspM!Yj-$wOCqyIs}_Ws3AtdiU(Koq}t?lg{v^LK4GoVe*kss%5m<9pH7Bi zEd5-m7aFe=s`OWQ(DnHEIMqo?^TsgzHM(5nOx9Z?R7<)t#>#{yPqw?oX^LEyVVDH! ziH#HGl=)E*Djl7n_nIF1+$_ELe=`!v9}Wc%$vnQDWZq02A3`ouAxBOD;gCXs~trzcf7G?Rq3%;)71>%ZE3_cqF?$-XfBm<_E1&8#9 zE=2aUg^;(eZ}DjwU5(m@RPp>e6~r%#b{?28+bf=M!L~QG?m$+zz4D2GeEIZl?x)Yv z6cI@~w|&UngD0%WI#1C!HoK(Nf}~kCP!G?W4<$QVMC26{*sqNEGQ7Vj!|m~}zM9fu z8u2k&jf7Ll;+G=U6E@^Q8Byj=k0jeZQe1<6ZvoKP9Pw(RI{Z>;<+qC1LWaFT<2M*o zeg6r?xQcGegxFhgr*ng;Ac&w5B&}uTK>VRlIM;Wji+y1xP;+P)79toL${W5n5!usC z9NM{bxQPSdG-Byl#aj&dfOVphUZOk{70}5ftb}p=1AwKzB*2o|^CoxH>H_zSr8@_} zz0ub;^8{5^?Z#{V-g*c4UUS-!r;i;RX1HH0Ggk{XG9r7Q6Q4XE6_k%nJ(5n|7Q7 zIit0}rROR!ZE55sQ)YP@vdZM0>1Nu}RCli>8H(z14M+#8Bzg>aZ=|}n&i3^QI>guxm?JKqEPKfys2_ao3GUMJpiLn2WkAReZDa-(#M zQ%?>2_s9^hq&;{7*?8F{q$WM#R;5}>Hm%?@9pXJ+$J=hlIDdiG?}j0jFAp z;ccP#IK*0Kpaw_EjhSs%e7ETruLpvA)6TW=8zS_GF5WO#*g?HB_P0lT{oj2^HGVvL zy0Hg&LDZ_7Wa%|KdMJ)TiG`1uPC1hU;@MR?kOfF0Q=lJw2xCuw@eu;ng&riqe~H~^ z%Aj8F=idmX?*n|qTL$R4D<|V{c)0#!F+wobUYt?gDy1LNO(+c;tAm{LFP-JOB@`Lh zcf&?Rto|VOhJkDjp>l4@y%OZi-t}B(iU3z1qFB=zgzaJP(N@V3N{Tm@2{jfkfoAZ=ZGTqP|}w0nOasMtNlew368>463JIOoTyu$_RCL_&r%M$Ui#!J^&KoN(XA@G zB_d?H1%MtIkQ2^$6e7togMimg^^*;wUtL75Hvr8QypYsNs)|oeJp|&et%bjcE?+Dg z67^0XT?fWLk24YB%!|PT$ddBhfW{Psm}-6`ojTk%`LG481r<^Av+9HqT3E_!Zw8`j z73|)nfo`?`<$Ul;kT|Bj1?`v=pSlPEU93<6qoa~m^jp_N_*Qcxaost+N1F|w&VU7+ zgwr7K>m`msQ%w_1@q(a%O#O5d^(?LW!NO*JGQOJX^xs+sk~I&*rkxf!FV6kT7Hysn z5Uw0HY6Ecs z$ZdHmGjJyS-;yPrMHgV4LfQ&@AAV_9%oS0%l)jBh4}^nH-^3V( z-NB&t4k`Z{))oOjeCcrNt2t)<(@>JES6c&YDm`whIrgTg27~I6DVbZI*W637H!5b| zP42iWVt*TH@%)I*XJ=dmUep=DKEZrJMSg-d^JZGqAg$#(tqSmpOw)_An?sN65_j_e z)TbL@vAsJjoTm(evp{i6c}av&H)w-kuZI*{wBcM;XuWv?;)}pL(HxYL6iDn!Dn4}A zDuuKO_O8g(3w`xA2ATFE-9@@Pq-f6jO4{*V{KkMO=N4Q0mAK`*uBA&K;&-7D__#l0 zTREwyQFs*a}O`rngC< z$op(Hj%cwmPBX{_!M+h!0p;#$-oZ!be1@-F$g_t0Uci$0)2>poSKVK9?}$EE`uX4~N~|p4`Fo%W~TTY>e*lR@=t|lTLON6+~$mkPu z-r{%qc@r>Gl5MLUi;;ep5q|~5P=TzaE3uV=hXmtkY&Z)+M45#5-g`Lsd7UGjj(oKa zGRxQLMRFoZ8LPw_+3sdy3QhHCP=Q!!5$>oJd1s&~Z%VXwg*I8I7`2z_yhGX8`|^*f zE)VO|%b&mB;8zs?55q^J7@3%?>lbnl>GaCGn0y=+OpJ{ITUQq8Seb21QIzc$k!yNV zZXcCOcQbP1Y8~%pWj@*|dVAZij^0Ko&CG+#0WeF8M8vdI1b+|ktGf}A6e6PH5N1K< z@PF|roPY4$0$I8Xs^aHjxhJuRAI6SsljpN5M&}b?1YfGI-LFQoLqMu^XxWJh5~$sC zoxS#vfi+iFK7u$IMm}u9-uXGGfVKd_?@M00!e$_zFHv9a&0#m~@%3E=0$-gB=Wus7 z+StgSI$m~Tg!V}!EI9Rw>41)UKq~a})JBr={^8u*T&iqt5-}E@O5#5Gq-bWs%`V?9 zM*54nLNL=Gjx3^rs-s)fjj-*JFU-;_?!TM)5{JOdx^qwyAbO3U1~44gwf7|rxc-%} zHSV$(8y^+j2M}mfh-h$_RRFsEmosM(h&yq5l@Y{Z6L2_{YIPU#f0pLuJQT?u1@_aQ${bwM{JfIOjKo{yO02U$4(LCk8-P3Qd?bKn zEOWF~+A!$jK`;m-JDMOILo_F~H(RB9by;e16q%nkb`B>(hCYH^Rm8xYD-Nv{f&WV?a;re5&k`a-V zvJ$}Mt_V`i3Q7}g&p-U-d~16oHSCYU5LzX6EKHAt51PBa%FuoBi6VY<;Cy!5B4ghg z=}J$Ad|N4L@sBMWargN6MCwawVn@AlrA(3#DM*g)kj-I}HY;i?VIGb8twA}SnHe@e)508>{zTAyS6_ynWp8`jH8R>p++DcEEmXA?oT^v53wnT=pR z+g~SaJQM`5aZjD-Q%!26yq$NYWbI}a`d4ESNe5HZAXTR2pe~|ba0W{GL^fUTD)e7; zBR5*SlKHFrrN-RcQJy*X?VC9oh<^dO8iU;2)AR<%sb%BA6FtH7Nf{Ie{sk=i4e)N> z=?8d@Fd$*EatMurefNi|!Al=gNi*qmt9s%=^nD`zMmdl9>9bFn`-4%xD1kY+_B=m7 z-#KKL@%{@>&Yi$(G>U7BHbCb9QYv>mr=+3rZ@xV5o?uo<_GxD%-X|0#3y_vN{UL`u z^-?SD<09n{wmMsB;u+8a0I_x?X=k8yZ`3Ddq)@wjFF&CCRn>@)-6zh?Ifx3+>q)C= zXlSIVS_)8~NauSB{=}wXf}gs+dZPzt&GIopWiw7-_vy`EoAUw?!mkj#|AP_A=}DAW zfMBJ8hUx)SBj}oV8~7aqjF;yc_O5Oo<+9X*+$GiUj6Bt*tHNyWp0z=nk?zMV!4_ze z)b~wf`>#6^HvizpaQty@DLSDvo$Bo9m@?h_FZ14Zl1|=c_UY4q*u0ex2XGROB zu01k3W{)}b@?KZ4@sUu*rX=0yPsjIMp`%SgVFFBD4WRxS^p42`v4lZ)!YNtoD`xfS)^ zG@Thy$VHl8JUlRP6!9XP824FJ$VzE%N`BzQ#aj>?-2>^V;_kdYlP|f>D_u|ZV8G*! zmgWA?Zrs^fyP*)Qr$U5QYSt&!liw^1&H9}>c{1mWON^G5B+nY%n^m@=YDB>TAxl$b zU%pzg?nK3;Z!RX=XEW`PGoVYZPN2EHH=~JyOqTL4eV~DsOQJqcfPVnk-Q0;*9y;Qg zMJSI51kF9C3WC=!BD^9<^>r9EQWwD6;<-D-DvjDRf@)%P*~V}%C@dxFjZsH?`- z_7hysrG5yic}XPNb*XkCrk{lv6NmaW(TW8wZfAsG`J~Eo`)ytUx7wFxwd{AWH>QU= zRcWNqtV%YOqF;(hcux{*^=@Ty5(3; zJ?J@t-?}+Y;F0m46fVXhjAHTqPg?a$r3)(p#|a?OvIxHh3MCTM z$GwLFYI&fsW5@I}Y9+>aGt^#)siSCunRwYY>QVr@QtU#s!PcJ?7K-mNSDjN*a`h_V zgVCJx5jDF6tH7=;78QDf9LxD_j?#J&Gae}G-{;LwRWk>vS-25x?d=~72)*WwYdrsh zoUoSwtA)@ubQ9ZR* z=kxD;;@6xhL!%8I?1JzvYgz^3Up>Ah76xe0pqOZ1LsP`Yr{TJs8{+)uadZyCs$-;W zuDpWjmcWQ?YtvvbdGh;}p9lspY0d@o{SKF}(&kCM@1bs*v`Ky6c_O-(yd{1z38LFIwrL6LE-w0W5%W!R4Y_6Z8y%tbD>6ZD@;KLtudq6MmUncr?>!{8|8;KnAkJ z*oUA?=tsQ!y$JSqLb`B;B!i41uFY@GAX;E@Sr}It)K5&Ia6vCVija&m|0*~(W0y9t z<4J_KEBF@Q`I+ML2%Wm7c-`nVHuQHOr#rT!E3DK_%+nGt`IMpGiyA6MUTLxYAzJsM z-TweUJtCv(diQ-EXo-)p}W1^%YWm}K7TCeDLo=IAvhQjssF^o)~RL?>?VSQU223d zKyxvHQ8vy}VDz*)J*evTn9R_zV)`SFf}^Bxa~iu!W95cO%d9#G_1>ERvb`ANCb#b< zxzvS>3uNv;ByDx7Us&!FBrwGOp;!?tWekMAGuWc1MpJmgK?Fw|V`kP?g%4q6wlH-- z`XwX~<>9@umt}X~_>?ecu6ha)$U|-m*_;9rX-<^6;|oduY3HlR>rP zy5)cd%NaW{lq~zVV}H!=7R?xYPe;dtKOxz23xX%1+v0T<8Wx2Od1B_XviQK95!SC4 z5vI>r6(|&ACrkxsO9g|=NeLSOnDu?0fEa6vLj)!ut~y_QL3w;QI=6dQo$%{uxT}S) zewXCehI0OB{LEsq#am>tAatctxtWmnJK(e8E6BJ?E-)>XmX)pN&GuR$q1_aRFE~uq z&YolgM2NP1eDQkPS7#fqBW0xb1MJKPN*OyN798cQ)bUxO+5cE>m1-eD)+iy3M`wd-G0V zHrMA2lOLOtV9vHj6{1ur33EQS5h3OQ$Qj9YLYV%*7>uwOksF8bPqjZTT9(bS_cPWi z-ZgoNn7R6%Fr#GdFDXp)s{Q{zwZ;p5f^j;;oY}&Sb8tD9`;s1hh z7wN_ad~fKY&dXW5hQ8x} zK-C|0CU4)^%Zzu@%lww{@7JhZT|kcFsPbW>ZLB^L)ycJ9elcOrlkRWmPW;5+~3dV z4|qmsC+3&YG1|(cRyqLdGkZ%AnuE&%VJMv9;siv{UrsX_6vhX>qDK|9;p&cJKxaF& z9>FdGQ;%-g{SY0!Dx3MRWYjP{?c<-zK%0`;@Y_M&O|&utl&PyZl;$XrU`~xgRDSEX z>eN(Ee;PvP>+6f@YgJG9Y@l{-fASBZ+8&(%kwUAgD1IL>x`8C~$f?Uc&jl5SJQ%xfM@6Sr5;H`r3{Yrc1U~7@skHcpdz)uMhTP;WU4=(?q zPbG96@h=2_6F}k(f^7zJPTC)baMkFe+s?JQR7(D>al}l?id0yny*K`G}cduBVX_8Y^ zU>H>Ea1+xS<2Du;))XZ+6x-6SKDvl64;Wh=vax*PbM@6b@NU~CnVguEhqAvjZq=!~ zYo!WxG$d4{JppHDGfaUwSw@6(9#R1E$qYgRRTCdI()m{c)%?fCF^p|7f(_WS@==wq zM*WT5!FJpGm7+ha==`jo49@zY*Fh=zFX@=PDm=ui&tM~9nrX8G%d!w-Qvu9B6pBNs z-y`qPD<|xg-^X;7ob!4;rELpk!s6VlHlp(Q`|zq%oR8WISfj);n%(k%F}##=-b-ZO z+d{uXm}_8!DRB@mI}8-aqcN!@|4CC;)%UuCVHQu?(D`PHl(EM5pJTN!6(P(;zl~OL z$1@nUeoMJ2^ed?Mb`&PlVIcYQdN2PVt?qu+oX_bYuxrk4Hy{4W2 zs)K0Fye$SN$0Mi=)b7BqmzSB9et{*GuEk96LB~9v%RcIVb94vvRj!r`+C05tGMYQa z4^}x~S1)p~LjMAf3hicYICen5xmFu|8m}Bw9Sw~nIN~j>=F$b5*1*nzn?G3y&<`ka$gk46iNZROMJ{_EymHP%~6RSIZ za*Q>W6)mL9R=|n7K_HYE6HP^Ui;=>lYR1M7zecA@TZ;D$p)WEk(+dT{a+$X>xx>2Vvc)K(i`0DKp zTKJ%6Hl_>$D{*=dS?vj3JPtLF)c1@M`sn>uqhT@|?K7$9TFJk_MVtN16Nt+mEz_#dq*Xe*-5gUb@Vj9e1SI=Xaa^<~ zvkqk;*BBW3W4TK~}*t^D5OMbwkqs@){$_Pa_!sq)MxH%1ojc`(GtKDMo1KnV_Y3^HS zT8pvcpUZUMZ>dh0Jjz<>SYR^Ps%T%QH+GRV7dmG?1XmFB0ZfCsR>GEPP4dWvJyT)c z>4?C{jO^RkB0Sdk2=fH(nXaI6aBs@RT-in>d(DACTDxEztm{GmYaipAPat(2C(#yA zhnS|C8u49|tCrVye@6N$?2>SVpE5SJBQ%L0-%|s+FoMz5!vwIgvNy6|IFp0^4~q$K zzgAgelGoL;4w~eskZueJg;<3w5<^A~Kh;Z@n%`i9nj#_cAkPs&&)3|*+029#(Xo*5+cymiDSefh@=Rt$quG;%J%NrFUcc=LuZiF6FxcOkp|4kkaQ< z(40PFW0_6t9WMkJN6koZ7`seLDRfGF9X*&4sNmosQ4B>XKV50iD*6fia8~ph7XO0| z!%Cid07z#74)(ZtJ!Pt7ds&<09!7RNjCP)a^*+G&c_|nE>rEY+^7v_$uIc0Xjt0Q` z8koVs(eFGC%i6ugwnMl@zQuoWb440$WV{@t)VBO#EVTU1m)eS^71%nskzE5=p}=&X z1oHd?lhPVKBN_x_jWPgdC!%j(?dM|^FJHGIFr%aZ2Y~8Yjq1wRrY_G}7l-i-Kv44b zU}K&h!W4p*K7T)rI+sYO-Py5*JWNIc3#q zO0QnW4;2^&`eaF zgM5T0dDg!=1rKQ^nTvYpJ2tG`Ct_%K;N~yGD#(^FUVYUryJN{Ebu};nNEC3&jH2aW zbG`s>Brq2R!LbHyj{vUY-(EhJ1Zr_GHlOV`><*O{i&rb{lh*i8ll`9q+Mi0|-ozo0 zp;6)i^%@kn`Htu(2wH$t)L4qjSa86}=~nScGpFd2Z)rBRd|JB@@`Ov@rlc;PD`q$F zxE~sDhe#^DM-h zP6U|l%{K0c!{Ej>vaenlZ?pY9-yw+t_)a5VX~>7v(+vn*ze#kw?7|^R#;|lRkM(RZ zmac`$9fA6bv^^FWI0I!7I;%Zh5)_lzge?^!o(?Y4F!W;D9HnZdLx8s^j`~#$^3)32 zem~z(J4*Sa>1x@dZu70Vfj7vCkG4l8hLtFS;8rpV z(oFcoNpsv(K)JKI)KWj0?Nik!RrgnGtEECQonB{2GZdJTQ{k@3R|Cj{qoBfF#U2IBGaqEsRZnCk#S?jcU% zifJ?)*ir1M0Fw$TvR~tgEgz3LUy-?&Cd@Jij&<6@TWrI({K6A!U)3OIYx(DI9<;<@udKorHwKmgmm(3lq?hU@ahj z7$SpGu4=d`(p}sJ4h`ttIN_;)7B~wCvHu-_26s#ce!U2{Rf)cc2Fx0>V#F9W6tRjv zp-OuL%L@g$JklMuS+V^^#x*AF<*iGHk1k~$&KvC^E7XR*n4_6wkM)j@qHu+Z=Itig zhiC3XDj2Ofg6AsCqy3&E-$}WsRG^%{WEbpJo-SG)HJcwvjfT4sbq1k61JG^vz00zg z?xOq13~=wsyMB>I)wZIGl(q1sCV7u(M7=?4-C0uPXOyb?Z))}pJ|GaeeIE`q3g@a% z-*XYH274?06=8c6r5m}|A-sBF65&ywxu3jPmaJfj*;}45E#9;VU6> z6TeGGT0XKI8Jf$wJMHIXOHjlb9u2t~jZVzffsCLBkYOxQj;P8&h!!_8R{;5i5&D*v z97_a7ct9OMFzi1GR^~xfUU6mb^ zmAVIl?5Vm|^1+%7$aJ}E)-DJ1RkgkZ0kn@WsQO=bN!1c0t9CPwj;e4uNHhjP1YX&; z$xorgA71CmncsgbXW!-xDqcf>`N8Brvp&K5p5BK*u36TlfXByRc)N0uC z_;QS@iJ0fC-Dfr}@ZS3}U5!WW?z*1Q5|UTc<3kp&D>PUb_jsbRI_L+{#WfA)*of0D z7XZ;anPsh+I^sWzxk*~V*j&Xi5_Bh)YdxGXy ztRdqt#9?#-TQTojdgv{i(g5Ju;uXmYF6}c;Mz%dpAWxw6(SZqY8>em{hxy2N9@%$f0 zR~Z&%(}h()5D<`-RJvKZOS-!oq?@IYR9Zl3m+qHZI+jimmL;XTySu-~Z-4A{!H?OU zoq5ijIp+@lfB@w#$%w?e!$W19Z}_6o2^LuuIxz{U5r1VAtI)qOM1w$pKab+N^T;S~ z9QV)S7E+yN^;bf8t<~#9-=L7xH6*YDs6tTCVO!()s zgkAawP!9dJnH0MXcW*IIiC`dFO`B&A#7*6zBE>`Q)uY(uAR@5V$0&j!ydm>tLAdmt zoH{&k4Te!59eOE#9e+@&Qvrah(#ZvC!|rFdI{z@6Zwac-*hfApRUY+1UG)HCF4^hJ zP50ZUCzXL5R($k=90@9KjCsX=jYA=&t^5r;w4Qdev2q zeFzuqDNF$%8xrw@Up-(@XaBo?8ZKl1^51@w{+%Hj5IES}q(#XAe%nocHbm945hF$f z;jsaVCS6wwyJ;V*=6_+hK3vUq<+P`iqvYT8k8&5P@94WYQvCZ=ftpxgFUPbH>Sn0l z(CM+~q6;{|XN73H$ z$krxET+_Q$Z+8EY(ozd6faSvw|3MRVCD{c6TvINL0CqNp>d!yL#^1#P(XBBH4cnxE zZnaUy7Lg-}zhp#m-R(t`*^lf|p|me~19oifN)x>lXj^%}=Jj3PBkmT>FSQr^i0(7S z0%wYLKa3cbR+wLiB$e!b>C?qz{$XCtNc`?<6aO;7UT>98j9o*ug+{5T9my3iya5tf_3 z`1T_yR^TK9~IbHl>dxVkn~J*GVed) zic9N_vfeAe{-Q)9h4=vwR(N{Kx~VW>3)U9=S#8+02IM|TqQjPcKn9zw_88nG;0}pl z)QHPBVgpD|MCd44+vi3VXg^ni)-sEYUEX)1`Sb&59LeoGhDp!xIFoApPvBk=zG_dN zinWx88gki*%X*q2T{uS?+xM+Jp>WDe1bN;r% z5^_=ZI%U$k??9pmYc9qQi-B=Pf(JGj=jOcWh415$s{(v|bN^<&2#zQ6wn-*Nl2%&F z*s?(9`ciMu2DFWcp{PMe=8Wcr+ffFxC^_jP+ggUSqBnNmFZ~|r3r3$lccGaG==979 z2NezzV3ybqI&2S8YPXKaLIzLERvm{_WE?&EPkyY?KdS+|5zB(5!xl<3&LJGS6$f-x z_lX1RlB_(wZ<_yJp!;A6eTrWhj;Urj-Ti`Ydwy{iwWSmb)s=l^7Ne!>9^d zCor*lT99VOJ8_0Yh7Kvucqm5a?Cbw6o_-3)$Zi-U(V}!E$w6$#DYEy?M2ug+Ne6Ri zWl5m!kf)~rB_(9vgT>Pjt&iQAF)rYG!86u!zS^@#?eE((XU=T8qqLY=jxQ4YZ2Utt zcqW6Kd5}$M01!!n*9!ox^-*Y{me4PR2=bhTH#pauY4frI?#cGN!O%(1*VNwsF#gnH zQto{?jBffBI=f+{KS9!dp2zY|+u?;=pmRyjQrJzEmiZ+>`g!T?RV;96o6FP1 z3j3n_@CKm}SOcIaUN`8RFdGJ%G|zDIDbBk>jjcn;d`pYoBvh>sCeD85elPubDE1XO z*v)?kWm-%hInQY5jvkevA2p>$DaX=h9e`a>aeHUE9MuuSed1tk05W`D#6}oA-P-Sw zlH9WAE{$;|18_M>+>rDAIDe@%2f3ocYc9yZeHL!qB(%v7p9cRF&+=Ytb+v~nC#!rE z&2VUjPB6by{c{oVS7e1BI%d1UO(a{uK|48jqbH@e>zih!jZp|%2+cZ+zkdlN7 zU@q^$KGY-VZJR@(_IS3@}mq8LE*OGjl=gFVQXz#219sl1#d#0S4V5hb)u(Ix6F$JyrL8 zXmYxWN1oGs0?nj7kHSc3R2S%bX(^*Hd@?Ldt#TR+5n_6U^%$7_Tii*S(<$gvx3xw$ zg-|*IVDuF7ecA#&_105z6M3FOCu{4cD@9RqV7kWT>1Tr+vHQuAvjlGA?~AHu9evD2 z(p6>GS51B!3HKZ6eYet!hk^Qywt;ISXt2*?Xp-7*XtIYCkIZc#(-3i%?E)C<88t;5 ziExf{g05<&YJ|Q6&~T^zb1qulNV$7JM?rQMGtBqR-@GyJG_6AF*y3F)V`Vx#aak&z z_kj^sv!8N*+*Ht&_4oG!fY?vua>SEnKY**ouEf&v^66cIg3nNsTt2D-wY-koUFN18 z8XTuKZb|Q*xv7RWPciJKTklP%cx4)a?GaG!5kNd5mq5APzBf8m6~-wtkljfMLxg|98ANI`B$WS$w0KoVHCNUCX}1BDTb?CADhl~E*Jlxz_!~^F~u)eIIjwT7ife(Oyr!ozJJ~lPd zw2~YMq**2{DXM_QWM>MdOh```{|c;X6D@nXty+y(sRVWgzbrBwvROBV#2j%DeRBsY zPFl|!K8$dcNXw%-jTBk+BT|I+m7R)^qY}<5H#Y}^EPOlI+bUrda0~03PtCX)0k?sI zm4eY%)a~lqg4$K1MH7sLTuB-Qv|eKH8VG_;gg>+m=rbjhPFC8@eGx4-5anhJX*bs_ zR1-$F1Y`zwldl1+y-#%ZsN+#jv4Ai;V7dvwr1h})4qduU=;7|UYB|$$-#2VF>+wc@ z*g;s}8h-2r6uMb_*LdH^72FTQmu0>vf<;H)d@n?gOP0?8v%q_QF({5l8x9w(0}2kS z+>PlRM3ZSBWOPGEKyU_#LzV)#dM`UE{|mUf)qT^69R4ClXn@vxh>z%n$2NGOA?#%^ zboP|V1bTzL_(zG(7OI4{H4Aj_y~6=RN4`@ghGr;xDjcBkD0pJJjsPf-+F6>-?<>CT z|KL2pYMI5Y%}Ufn3Hy8lwE{V(iN3oq%GN+dOQHojJj7&)Oucp%8GZ4>hbj7%Nsg}l z`f6FFzJ}-{CGC8JZ2r5#>rYhML@|8;^IDfg!#JY;GMe#toD5p}@hvN&$*VCG)J0s& zs;JGE*9nH-ei8f?7mnxU8rXl*27-eX^(jV;m_xS;Y#~BYu&;5extFTAxiAe7B6BQZ zg&1+j_qHQxt3f?AIehW31)f}H?@MP4tpKDZ*2vN2!ciO*K}3b~bhNt(?)zy)0u=FX zjlWo}V9X0NyC1Xu)XJjSs+DLlyklzuHYt*b^IR&vsg@8v4nRr0^b2TdR~bSExxkEy z<_hmNH?8=|iYC_Ahrg9bvu{yy>oVYMvl$b0$bZQ);c2%ujWyNZ) zWBhb5mO%3c{8b}gTnRhe+*a(9SMRy-PBIfB*UbfKXArP8 zWk?v0B$C=~djUw>T2Q>amz0`|^nT=BoBzbH!L)0!to71ky1kz|G}H1|QBi3P12i?J z?=!bmJ{h=nCJxqPpR&!rwZ=^sIq|QT7TW6m52YcrrGi-{e1af9AJj%_bstmi8Bxi1 z@X8qL-8XfGb8x{DaDkvOi_R|z7}kWEO1bUyxT27$a~jDf>g!d=6L54McS_}^lFLZ? zIJB9>m+Ho}_ICt5kNd>mD6diFdOzzYGDKh8Rp9~rN=JM?18RKukEF)}K`A}{Sef;y zT8v66jr=qd&rJYxgR^}G1aV!3ZgjFazn=xeyU)Q#%0z?B+>M^+ggU!62b(hQZZGXQ z3{`%ge-yfZ)%@Rgm>vVs7(grls596eKy8x@9Kj8Qke5zd&RJWb7A%&0X+rOIO1%T_Y}-s!_b?X&&5BWFS7MwS)3thdW_}O@C}0JirkLf@{_fPB={9>jy;Fsx{YYoJ1xL9N5$+dAt?)Pvmj{deUSY*zS z*8~|s8wI)y3&k*J9E2xUH%q)XCbk4j1}N0V{|kwF&jm$?#@k~?yC;H$ECj|BiM;8`z@tFKhN80JD_SDXnAUC< zoz7qdD>kU0129-j`^3M1oAn!a4iVR9F(%p9b+6)b6u>m+XhA!3BYriYS?k*OZGJ+A zllz`S&4xD{*#hP+fY1rRHybbW1r;&c6#~Xq=*36^QAZ_zuubsjKy62f{5-DXg`+ZDx?Z1~j=DLPo>2^+%EHdJ zQYBZ(*!Ee2lJE7HX6=5F;R>OSwClHFqYk5XM}r z{HIYulgzPwjl=_JPp+@8D+4=2GgmFxO`5$tPU|p7>lF%MGq^{2NluaI1Z0ebFjO&D z5~TD`?A-<5>c5k>Oxl|lsgskHyOm!cpF2@YkvL(50``0-*xsW>8CoYj4tcsoH;0E# z04HrUBGM=|hC8b)?QH%fqRsx3I+6dD%+MEsB(>XY4<%(ypFojJme-Fv8Y%xumFms} zQSJ|JNijLFt&;a(d*P%QB5VD}QcKuo6Xe~5ytjOs)wm~%} z5U-{OB$bBmRFQ{Yb&uA9O-xPAm5rTU9GSDmTC^WHS+pOLr9{0g9p&o@6}%M<(>8Kg z{lcc?<o(*!h0SX?i1c4n|Op9t5)+{zk>-ZLcKoOvjL+%YK`D9d~ zBf)SJA+!@7jPz>Tu3E3)Iur#B)+g5N8Wm3#pRWz}XnU6QAph25QUpJ8Ak zwnvKjPI@d;G;aTC;u}6en6w( z@XdGu%wp2P5R?T=7e@Q2rN_yS0YPj{OyDv4qe%t`X41`=2?qT1!1W`L2B}rK;xb;w zOZ={QCCs?UbPz;#4bn{XORs9`3~$sPbl0s?;h4J+)i*or^vRb3114koEQH=GB4YBu z&HF%wJ3MJ8==q+K?sX4{Prc!t(8y=bE|P+`FzhEA=3s5~kT3t*yY}^S|JwHsK(t+9 z;)Now_e>DQjg8q#v46|LUvG|*PiNL&O=c&rb!NIR0aJ{gHqC{1&&vFsA0bbrw6(H_ z^n1VyL77n5{7JJ;4$M`r5deswZ?$!pQDUip=l`f zQ5oR>OdPK9d<`Ij<9n~in+{npioNs4a#DTk2%eCi)KZWhshn_Rvj_kjr}e;Y_K z?bQ3nlwYYCfn~bFD(Nc|Kn{Fp-BAavx2#_W6DiB&Z&%j1ol>y2q+hS4`RgnxpCusc zbxii*+2u!P$7c-WB*xqcD5367Tfu<|RQ>~~^JH-)PqRb(7jp%SP?Z1M9q%5mAicxF zRn00MZcy&9$4yfqi}y`2zP>LrahcrxeMG!O7zf~p2h$S20!$V4BQ!)`G!zr4`U=Hv zDFB617%#vk&~*|#m`P3+UP_46qU&8noBwdv`hgL%&BUczZ-oZo*oz?`4#|oMQ}7Z3WugPh^vX=f&uX*vA3%3;h({nS>ejhur+* ze?HJYU&@W**72pg4B!Xy1$HEino7r3t0?9X$RN6#YPM;Fyt`8hcb3oz;^)5dx_>y; zOi=*pX-WjuyR?QwX|w1&;cSerUCr|t;Gv3Z_2G_BYDaR9i9Nhv*}1TwVwhqxF7n?x z;f|*Pjz|pDW(VWGQf;VEjMY*|Tx4BY+#Au2&k-DN1cNgZs)1^C8m)5Yve0I6;o^O42Et{%xN0+(Vpm9P|`GF}x(`3?OJEaWraP zZ6vJGOR&Le{f9DtaOggG3>g2~0&p_FLRtvVkeji^Hpz;f8ZuJ*Si;b{JI(v;|%w@yuT)V=-H3sElKz`zvCfj zcFV1Zy=wb`yvI(AS`EVu)#arlwHS%0P+X^oKrI7C~) zOlo&4oq|)NMJ;q021HxQ7i~PE6ew)kl$!Amym8D^GC|9kR<(HCmImwfs|liJpl>f`C38zD`$AvmpCh3q6Pv7`X$di>&9$X zWf z`)E#Tc}3?xvXS^IMSG1;2^sHQc)- zJ>vc(yM>JD8I}>Bnd`$@N88H2NT%}7-!O(B>%LWrKj2=(q4li(5iXfKeNSlZtI&Tk zBeJ!|Lnrs)H)js51WUP4ZkLgG+NS46=YA30>U3jWoFI1r{FyiWMS#CJ?bgdTbN%Mg zT!ki;>u5bLMK0%Nh3;gs=urjdixj`Ven2B45vWVYSv?GPdih=dBqNJ;h{4Zm3?Rc0 zhs$4uo9l=0n?c5#R#C+;IJ?dY_=>q51aQq`0NfjmHw!{ld*1A;LgA;-x8q;-P=iu? zG$)ous)b&5k;MKEqkq?c#$vO;wd2p5&KR9=<}H1u{%%EeZcXhi)~qOxHC@(4k@t;J z)So+7-+udF3dsMqfcoZp$yKL`C-Zj9%C|5(1BmrtG#eU8zf%#{FLDJD8AtDKOBO?V z;K8^^!`LHMsW!fuHGvWLslI}Qn^JB@`a|bD!tr!(-I9?baVzVkyV;kQm(A?~9c6L! z6Ld0(`tTR>cZO`Kpg-m(ql#5?cv<+bd&0tMPCICC1AvO>i)fR|)DliC8?*-WQ-x7t zs-bxxh38aojdbm)&~a!q*Qx1VfIGg;!$*c^+h^J3$Qhfq>QvDjj!+lSRMN=b82V_W z?Tdd+%D(QRM>*IC{V?i39$%^P@kUZU;4jr`Dlzv50fm)MEFkbhM555i)dl}dB zH3@E|P>meXowLfmrQ8D!xamp>-@jnJG-OReg7|Ar6DaSHMz86Kz1?Xzd+_`qBt16W zDwxikUoC8ARmAT3zGQ;H@G#Rph5qx_^l*+IAXNI z)ud;%xi^m*WdS65F}J#E1Hh`%?xqld8n+=?sCalhv%RXgB8ruMKqsPasJ{l+MJ+Yr z(EQMHazaHG9sh{|^b($;rP+(y{za0SN-Egtz2-Z~Z_75sboJfI5mf3IGi`P)!EOvI z<^VndceyjF5v$|7(+{iJP4}qXh{o_+NtHZ|j=o#dJ7ss=m&B*^auX@s#a1P}CBd25x$G+P)qzDWw7Z#Y#4j88X+T6>)R7%*>bgvNxOk=>#%>xEt<0-aghbM!6fo z_(!L5fbnE5XBqJG?ctdKQqv3DPR@Q&eWv6pF3m%Pn-;Ojf;{?dgHJNTI??3O{QK$^ z&8ykfikFE1nt*VZmW@?o8yRQ%_}Z=cXClLgX71HQnG$0^0zfC z%ViJf30kEKjS=uAJB$3`yHexf5x{p9b%A!&BlTDS7jQK9VqjY z@hLuXJ_cT}eU#h~v>=)gcS;Us&{u(G_>vzj=CRu@iZu@qy^gVpJ^w&cMdtsGkkgCn z;6LCeXU0;EIK(Ito#Lk>u&&(2cn*HXd&Yfce;_(BonM?4%v5PJ>8I%z{Z$jRt=9B% z;k%pwA9&s@&b|y$@duTymFGLi=e=G85voPs%KGAAmK49=T80$hH%8`Nkr>$&g~y_k zu`gNx8y=ckZajkFK>X)@bPZEeQk*x$y+2?dVfG{tSR(e%!vx7(?hcCj88WlR_ZScj z3I!Xb9;(y{!54m0n)38^9#9J(@f0&S!6#bt^i@-bb~Vf?XgWC6G)iHk3a~LGd>zj48pT8`1U%pFgC9*;g9#%;`U744gKxW z#xXBm{Zm{)?=`&X7F&7l?da_m?hPqBb~OCiO_J(8F3eQ!&?@D3`o^v9aXb=+98639 zE{?(-_iaSaV&YEoO#}0T=YavAaXCK`ZOEbYbSd#!oPXRih2w4fRy5P{Uz#!Aiuvcg z^j5D=9L8{WZbSl&<-l%Y33`o#w@8i<>(CkhU|$~WLz0lmpu3`Lbud5-TJV287ba`E z**rn|@ZVqx=o|E2-`}6&CuWOjdtlJ+NNU4#_yf^+<+c}t#@x|aFQo*|3HnYLEP>a) zGx7e$QIYBXK*0o z!_>S2z^3B58n^9i=M8TCtbKStBRnZ4b{lG5PU*Lrxied~zgXBkkh6SkUtG*-yv*kK7JJ*o90L5#H06Xkq9jc%RN^d?!Y9aBhGia)pR zi&3YW-0E3=FD#GZH(zWZ!!q^AW7I9Xn0m!r0TmMybH){uV~&)#Kj5Oha>aVd(}Xj~2Rx7E=;_+Z1bW5;%y}6A zL-u@~i)6w}89w<|c6O%KY&i9|ZTa<`U+p=HhkV_yd!50vBqLbP60%#H`>glSJ4hK% z=D@-t%?XSjPE{=rDuhy;2gOj`ik{y-bgNGJpuD-d5yBVP?_WQC3~1<+9AmIl`6iK$ zu#O_G25IhJ`W?BUX;tg>@{_&^5Uh1dUvJvp-pUvRM(M2KhTY_HX8qm(=2X*4-u05VW+ zwuB@D=#K>kXEEt*twh3OqJPA77SO*dG^F*Fzur#!`sbifO1|@DiWMH?H_l8IbLUNN zB8Jv3P*p}Yn(a#SlE$x zs3k{=!DwI4Ck8;z7FE#d5?XFp+63a^x*nxv6YKwtvMgWIW?*<8CIBH0nA!o!w3P7) z`Q=wk8?Feo&5bf&5}Uw~ZP{?wUfCYqRe4=7O&{ot>}$GqxRaq;tLBe2`3>H(MsFmn zyl6WC|5sWHvfP=>ep&og@RS~RKyeTvXUe2tLfolaJn;^B_3ZweJZ2C7vo-F2er;GL za#iXr|B#qKpJqYCy8(2|VcD|ijLsnY3GwpMx9<5p)ueYw&-HaRo9^1Uv5g(6^yot1 z(!xswBL#vWNn2gNzFsw_u3Lv`J6O}sDDN4`o#XdW-g zbYsHYQGtU}FhznRr7_gKNkO}1>P%z%NS9`l%tpfbbJoY4g|NrCC;;A9qLr7*^a(xF zSS527|GRj&IYTT3rU6cuMRn7Is9Peekc5t<@UxS;#z$0S<@)7*a*VH67Z=D$iZ;tH zKxv?o`2DzCpGe^n>lg^?0 zqA?WuXkzy!U5x*gS74TVVClbYTcTyQVXD!8wq9oJ10V+=b$~pwUW)SQ=}*T03*#`N zlmGxeLx(`yE6PAZ>&NO!*r}WYc3##`7@8Q#Ea1$>-(*TBGY& zF2)6}I{>2BUi1JxE%;abWwLBSKatwe?rw=rnXz6m-;)r)Z@z7e5@SLfXW209rj)7vPUw>Xf0(M~zo>i-(o~Xw>5yIP21@Ar(Ik z17gWENNTIYd;@`W?%+Wqb3%qE?3znyX2&P1e`UK0N0z1&7tbVR(}VZzK?p!TV&3-e z?=A;^c<%`@Ze4q-3iR+4oxgpJ|J9@{hq6k5n@R^s#QP1!Bgu9+srxI7^7bjFnmCRD(dd+FB&ZRpHvk3DKzrLGJfX3_n*nI0r;l)Ws`uHp=NVi zIw4(9i56sJdq5?sBGS?Wh&T^mpq{UTQ&KE39x`E$yk-bcVtr#WZUE@FYPB9<^yaNU z!=x*?=9n*GKyWZ>l;iK5x)mAWoZ~BQv%UPThNYDZeuZuwoq+0{H4i`*J!5(Q443mD z?0d@pBHR%yed|qzuLW&5dwjt`+}lJl^@K4fER(Gqnq=mY!I%Jlrv%+4j{&$%`XzJ7 z4HF%F{vk)jm!ZEJ3kaS1QR|mziTB#HFoB+`T7aTItlb(fzJ~zq{($Dg?gIk6|J~3 z+cZ@5Yo?PMVmf#dm(6mNDc5SX+}fus+a8Hhvo>}|y~sh*?>r0g^BWY4rPw2zQ zLC8yus=#Whv$?1iswnpt$OkTr{+n2)I9}4N9~P933NY})QND6zkAN$Upi%`eEKBFX zUXeypyAq0Gfe}f1H)`b+7V5&P1EY(LFe?LSX>;ffi$MIrUHRmmL2QGzgZ^ZZww>Ol zYEw%E0G_iQE(>*kzN)f=gnj_51c;%&$?yufE|Kx?AG&;`dqCopT9U_sT6k1LCaoX* zqU=E4z-`)b@!Xl+C5G(d=mH=$!b(hR4XWBaJY;o&hq8tyRrWTFxRDX63s!zGm?70I zBS-@*erd&`8mQ<2=>*ftXcV8dE50(dyC ztKxb;+cz^aA3?5#y$@#gK;ft!eEaDw6Idwzp$M0GUZu?2FDj)hTm1}-Xm9AcUqZ|r zEY~nm{6=f(@(YNzqTy>Pb!WsL4-P0&$W-JPfAKr{3R= z#4f5c5Y|O@qN=7+I?uo?tiGVL+s2+{kKEtda$6L8XK!SNntr%T6KQ0E`F#{Zkn?`h zFBXV0MtJ5-e3|YsJ6(=ABd2Xi#!H8b<5U=c_5Wizw`x%{Az*T@-g`{?tPAa5bBf;< zBk)sdf-0_BasC=jo<+f~paQ^OBH}#C_e;wLwdX>Bjbx)?VbyZu1l1vF$Dxgk zq6hE(s!S#Qe0NR$e*!#j#}?p!^a1gHK%1jr zOmH+8z6qoPtc7zwme9u)O#+yAU~8PFcYi$g_kFJq1~04TzFTdMv9BVHo@Z(dnSmGp zc&vkM*SYspUY+Aj$Me0IU$Dm3-IeLLab3&xZkI+5*<&rBb00QZ>0$+oP1yk=gIBi3 z9rK6iHG+MUJL(J6XS2`zsQY;So^SSbt27N3ol~9CpMKtxw!qYr=D&YzdS(t1ZBQ*{ zP^g^FZ;WaO-#tD55t0_83t-t@h5KbKIGG_oNWdA=UYBu_YX5NeP!Vb8leL37%JFDY z%rqZVJZ!g@b$YHboOwvH>3mBiGhS0vQGm8SKy*zo<_x=rk`KPjvT8l7<<}b8L&_R0 z^#d--ZeEn1jJuKftpS=tKv`0CTvlxPD1?=LHf5o42zA+Cd)Hx{sF>*7%K_Kmg@<6K z3(MO_#+|QzEzK-CT8NR{pG0J1rh(0PtM?9%4lFQ-( zXO#P_?Do|}Mr-EQV6)y>;gUw8kx*p*%_IHd=M{dj_tw0L?tMwzjsDf2i#rIi878#T z&0UE1bsI!)tZZM3E6xsl)&O{>Z)H@+m({cC7;PC-;dOgO*axwt@wO75_GSEJmg_V{ z9{B;v(8odt?EX1}C0nBJYcrmbP`lHG{mUO)8e@=*r*V;1nzT%!E#LN8$M*L2Cx}k; zMM-{kSRmD%e;1a?=Pj(MLLH`OYEqMu-2`mR?TcjPs&H*B^qzPro=9ktU4v zT%;3yTfc}CjN(~@$=7Y=7JQJ$m41Cyb|5Q;)bWiX=ivJ-AkIqg>d~Xo@Nkq$N*&*z zeaYEeHRfe>^u^J`1rNXt)plx}=VR)%D1Ijp*K*O4*Z7t5)wmH;a|8gxu-R!EF3s89 zlKB-UDt&RiQ`})y4y~Ek9aWVQh+A9;ln^(oPmNoz%KI7EVak*ocy|+jSP~R&KAL{H zAxpBF8Z|u+t~Jy4x&W4evB9W_z>q{}9xR_TQ5aW(7H5Sj>a`R2mA?TNW>kt^c?%w2 z7#3Yr3D7JuwMle9 zzVK>M5MSCi3(3eaF|NH3fB<>(Hr$_UIy*eyvXmC!$g;C6q65&Md)i5MG`EPE^um3? zKJDgM&DQ`c`J(nY2VLokCXZWTSvX+hvp%4k7j*9Jc7mBS>fjGg$UpR!kQWlvRT2VL z(?}nW2{Ow2*}2{$A9NRcoh?QaM?Jz9kxw(&W`whe1!s>na;sk|ZUG-!&FuY#JUx+d zX=mf@Un-A$@Jk!N`sln{IO#6XyN=9AqAhvlNITR?f` zF<9rK`s2#MFyJ04!xsXShp#{Py9HWBD)y1gRpq@K^f+L7;g2h_YS{1?2q2))7x^hs zN6ZK!zO3jZ9>S8ib(=tlNsphe7H7tlm)}|(@H}h%JQk|S;}O!8g;kuv3tkpI=~SIr zUB{(+m={ydmwDq0e~y`E5FJfS%91TD1q2`gMNHNIKINVW_p8o?Mzqr!h}4*djFX%> z7s@&s`83YA*;)3arV}hWNTIQF^L>-VyEbrj~(?jq#*8+lkh|Jid-xrLJnuUHB@A9%!MWS{H)bPXB`I{-H z?0I;3E`774%AMR>7K?CXm+3|Lf|TE}Jb0}7JIYA(8>Z;zvF93hV;OlO}`-O5W!I%?i{9@k=7dSY7*wtSs+1VaFN*hYw(( zI*;7cM`y9WcorqUlAo5)+M-g6;`=NlC_Cl@6var|_(v!OcZ2}g&w;Ks5M%;68D^{B z=J*qSbR@Cba2IGUncDZfv)A^!R>l-Y(8*gf^AwFL$m> zX=#gl&x`(@z?9200b{o5UiKt?Yo|%Z%6;YLZYLyTJr~);TOo=#Q%OZrbZ_C2iSs0i z&ljLVTAT_QUMo;}U{o@QBUO}nww<)h_~V7uZp_5FADBf22U!Pk`JZWE&E$tRtUcB- zgQJltJ?GJuFB8+hMCDSSn1ZJq8}9=Hxs@jX6#NRhV^3VW?;sjJ&WuC_HDBHS)N{H& zNlV4!G4Q6&@Lxrcr({&{_@Ijj-gO%<{lSiOK1g~5h4AkQt7RzCokA_+wv`?R#RSAM61xNtWpz z2cXObw$@f-@1&}Uc;sF34#9hpsi5yuVsY!EH7TM*bu&8nVP}hwK+IV6lC$&fvvcxF2(>cvq0A;${$;O&zTOm%9XFr2Rj-s6dBW3zWXmJ57dT>Hp z`xg2U++cSHrIZc|s6Km`iapS6&6!GHZs%wWkY^wG@YSk)gOI6F4m@T{LQ02)2xvhR zAo&%HpC=K1s#D07-2-sx{Q&0dSUe>(gX zelB#Gc4If->`D#rfF?nSXFk}`1=xJbtE8nMZhSYZ+nt!R-cSAd zam5OSf#-m5>G!x;kZZeJ1k?z7|4>h7=`{UoM6{T6_RRDB&N0S|70w92xccqe#(MhH z%ikh*_ph1=?p%f3xUUYHEy)zY@R*5(I|FX~+)DVGJxr;TO+E0z&n@7pJdIOu+7h-lEd11tr8L}NY|AucFGATJVVHYf%CC0OEgT9%yLq>wx2a@7*RcX#^6b8khj7%L(pXneobiR&zi9@G4aQq$)=LVoBa$^_ zhYu+;4IQ0E+;|vaBxe>m1ErRh-8V>KaSrF9T1xZDEjBrZ@p-jpR?p1yV1zTjso4#&ikF}BiMJp=%Z=jQiYA*)KX{I^*Q_!ffXu(R=Oae+XU<&-xz9Ge%FU#sLw0( z^TThf*LeRQm*#1M-i7zp<*`^_~vZk}?OdBM7i37R;%Wlp*uT z&0N5MX_L45nrYWGS$v-J;4!jI(p&gv;*cNgr!Lv*amK2NTN~34oTl#V3gAmG{$JFC z|9==9W0uyfG+gYGXRa2c?T&UZPkZvg*>=uLIM#0irwmY=qnKjg1t*-Hbc@qc?Z>4M z4&s62Ih!On4~l zY|TurZ3je|5<}W+GCcbg9Vd;WO{&c{`4h^oBQ#*m$?Kw(HVRA^PA>N~wTs2@ibvqFui&;ZnL@J?L&y*O2yL@~D?=PuiadB=cBV!w9z45o zp~}sQYDqDnoe;2l+dv2TMiUp(V!%Ykou3z^tiF4dpSMD`W9Z+oFI1WQ;&s*e-BT}V zMy-kksJRf@8YHzu{KUbX){nhY|{tR0s{1fNOw&m$F~?7p9mRyENu`=|ih6mLx4y4fw7NhpL78lP{Fpkqkr>ay9hWA|3O%x-zm>F&3@RaMz;iZ~w4 z%-%{MQPh@ALi#r#e-t4C4odU&TGZhh&$tMaVOUV1PCDS8evkvNWATxnoR`q36>+Kg z!%`dvW|GopqKD8b|}LWxW&_rECRZ3 zf9F0-o7j~|rmNSwNd)YZBRxCVk)6IU5MnA^`J+;&?oH#5|9$xvL}=@2*E*TWPqS#! zDiw7s4)gP1n_}3A0=$iTdO;DqpaM~Z?*7L`{+5VKh0qgz@z7CkmBl@-GYVaTXKh`m7=t zs6Lc3_N55fK^wRV%mOzS7FNe#Z2;tH-8}XGR!QJjm3wo8Zh6b&j|mnfHf)Gp$Hl#Z zFF)3K?c$P+Oz?InQn%2{KGBLGv`HlL@f>z6|9_0Rw)rf+lfKG)8vG+F=q+QY$hg0= z@WsK!+28*tlzaL;_D-G>Uq&4Lg5xkdvb+{|vc->eK?!2vJMGp5n=(A`?~=B5Er$Z9 z0V~H5V+}_}GBI&)xS~I^TGDx~J&Uw}*Me-v+yBo-j1)zX4;{s2vg+^Wh@)oi)LAsz z{T(9($h@dvYMtb5>ef_)+zS!EgFj!|Hi#yH3$?{}uu z*<7^{#Hs~;iR{{hw-)YBc}6lt>(}E8n;~qE%~lXgRyB?EY^im9$F%>dk^gr#o&s?gKf;P4Q&AqAU*0C508}JMFLw5@{l1z92~!}75>fbwZo*ii zAf;*H)iq8d;QW548Q>zh+`!n&O4KS!!kh`!b2#a9_ltwiWLZXRwcE&b88fj?Hijm% zAIrk*xg4)8qyw%WBU;J-Ki3ZJi!8Dn(iwT#q_&0>e>-R%5Z3~bo4<1N4X6Ow33U4S z@_un+&l6STuF-Ge)RrS#{#7O8;CO+a4J>XQ20iu-IgXIPk=~EIZewJBhmb8bE&P{s1rb1wNmOcSCRRuSSa$hI>kG%H)YU&H)1udYWfG8j$ zU;{)ckrFzHg7l7bf;0n$DhX8t1r?+ikP<>@(tD83r3grq6nZC!fC(Uo(k+yC5&!$% z%HYX=0R=#19c`D!5%5Jj6tIQh(cYu~FiF4vBvGJ{WKygMUf!lr9d zr8{6|klFHXvc0Dm0xa#ZqmS`iD_xUXc z!8%gJ21$H^XiA1xaiX2DkiY2shE!_AJ}_Yy-936XYWhLd)+%K!Ql}JZ0fN#mF~987;EvAe zGEO58{({ZQ1h$lxzU=lKPZ@ATxycP&yXUQ7sO|tL#fP|y65#rBmtp}P34DnRudY(K z@9OW!8y^LguH_?p_xDru-fD~U)L$SYvRd$**4{otPF25CtcNU-hCW5caYe9ctpvW# zR8FdS4wb4tcPlUK>2j~NpVxBQJ}7=qun0}PbC#;$b?Yx%)rMV0zi#F#C57JjzC_L; z-T3()Dy^i0DsU4y9^fW25Z(PP2k2JEaV_TphFM~cW~q2N>$nTnRbL8+bGuAZO=Dfu z%z#zT1OloqVo9(h3%0=9n;J*MGkTe&CD+@$4bTh?t#2>1q1*+6Dp_K$b7XYrqXErM<+KB%ePP` z!O*=Ca_=V4SD8X>+O!w@(&2wAqKW^0dPbb0lkLKon}||3SekMO`Cd10N9b9b{mu`M z+Y9lJ4__d$v~f-Z-t#J1R~ms|Poild5X*xAFrYqHE^l?;*L_(Jb@G0!7;4jz1j-QR zPR)3gxxec5nfjwF1Eg7Mj^#iOZvbjUCv~=b+!BpPxBzjqx-d79iUEpG8C(rl1jZ`* zcH$cvdYPQcHDB)ZDxG5)f8PiVV zqGAq$Zw|0FZdnb+-Wo$gS61n0qBeLDcpQdS9o?O3g80RTShhN9Esp&x*<}BmL2%=( zQpAIezI50@93Vl_J2JRZjL5xPMy?hULe(T4RJx&i(;2PbAAwE!0F*pP;cQkx*+9J7 z^<=1T;TeKn4s~;rvQUkoRL#+Ra=Qa}D3qs761|4;`=Zt$HFUTAF0(3)JTz4?h4!zs}VGAFcO((ysC+|{@#~vv40kae#S6noZ2pPt7HTU zzv-q7!tnxSk<-^p%F zH|A}|PEc2?G0AUGW|GPlW|rlPnYRo(Tu_e`@g1Q2)UYCwpwcn|e}~sbZN#~W_@cY58>D?#4z2Wj14<0( zqxDcT+T~(3!tsr!(lhO&p6`VIV(O2|Oc|*_-`YW3UHtF~Dxn$!`lOCNVAtvGVxWr^ zvEx2&!sA6OXdWZL+feoHJm!eMnFH*YZ*5#4jx=C|g9ri40qQkOTL5EARW2qRW-h@Z}4v&(-G$I{KSQ|F46r3VL-J?bWlu zsinf|vM5WR*H3wJlPp*! zIb+LQ1w!Z>x3T9 z7hSV>UJiQ9-!xS++P-+)GrO*+%g81F!}KT0N*0O?mK6txmTI^^M!fNlI~Z3$e;wrM z;qIc*k{Bt{ba5U+Nr+qJZ=AGdFnY!OZy;_Vfcw1G8gFl4&KWIB+yqp4OdnMs(WVb# zi57ACK5x95PZ`w|mz+9uBF9g!j4Ib_eGlP(2Pc1VemB4lJn2XvbJ(?%PORhAfrd|y zPJlrIeO;ZIUQXSprew>m%s>;7UhdoeJld$nD7EX~A}?fcPbB|AL$@qEepNwz#R-iU zQw<(XZ>GfGEO=dAl>cT<>9@*(37g^#if)zZhdI>^;!fI3(aF8RI|QI!FM+1E?*z3F zI`Yx^1yVHoZNt>?Y6>{{dZvTExT@lnDYyagp(crCwqVL1&BC4ZW zs7|oUn%LhObN}r>Jst-_Pg1Y``UwPJqu|1(uDE`5E5Yu(Nse$#6>cRZ`<29GIAB*Hlld$>9 zqxw)Ia_vHfPBpswwZypPMQzlL*9N~i@&Jhm%WlvT&Cn-c^6K9{(Y7K^-u5*FCCHjq zjw5p?xZT77Qf$*3a!)Ms)Zw*)-Q~$-w6rq95v*FZ>rP;Qi_OaCbZ&QQBCX>FV)^qt z=;4IY(`o0Ns;jm!11K|cGV9byWPvmKTAJOh-$&{Hp6eECM;Ys}2Kc6NndkaE1&(lE zy-EJYVdY*`MS)avbLRqjYB=I8IcY@;nm$Ut-X ztmu>VyuY^P(6V6A)0#m2N^-DZRd##RH=q?-qoE`>k}IT0&H=@?o6FdwvkQ<;W9G_O z;;_2t@&c)5MJ&w&qOQFc@0brkIE*Dtn0-;dj&Ui}5+61`Hz%r%1-!ZIz z_?04?fU)s-ffVlzTq00&l*hQEVmA}gIMmMz9%S}+_wx_YiV}l(lJtvTWm)^G`?-V4 zNr>}{Sg=W@fva~7^}|2<)(1>Nx7xn}d$jB)h9#1i*&C{W%n8v;f7^qHq&~=0D1T#5b$fS7zAjLtm--rol|0hY(oJOwqQ5 z)b!>@9*nePpEYm#USNXwUbxcyt$Zv^N}_E~QkiqPvWoi>r%_CqqOWN7=O6Phum#eS zg*uMdXZBwqjlfN&8#3Q1Fw3_SXm6to*Yz-T@e6!dn!w+X#qdWsNdLIes|y8qk>tU@ zg;tqJ>*h9k2!d zm+qHn)~vd}%I{G3xw~(uKuE#q2h$I6^|l&!zKfDK^d*%M*1adFZ80J7U}-{cEAS3j ziz1i3^O}wD!{q7Fq4i#GL+gVyO^lcs-BcVC7bqNLuN}6pFM(U~#&gCcCi+!X3cTc0l>2fK0@B%^^20PHg1uz2$}z?1yyyAMxr59GButiKQ@d6qw9#XI$l>$ljZ>s#NQuCd^Tnn1sm4Kz6@11YX;S^Xn+}!KN(p&}- zCWluWpovo1pUbN;^%JPQeu{e;{Od=+Bk5j@siVI*nZbj;%)s=52uj9>Pu9G|!1CZM zYgpP>2q=1$#Z$1bs|R44eL#Q1qg}?84;Dw; zZl3m1#$P@swUOh4pW!fND^lL>F;!F zObcam$>*T?!6PZi~0@Tv_+#_c}10NPzZjT1eGc9YqY#+1md&y8~TM|uMNaO!*zi-=<&0kPPo}M{xaCT z`bKIL%7k3A^l?p$=>U;}=uX}YVlfx8>Z^Lmr^m52?MmS~4R$o6?1?SI`|YwCCGX`$ z#PXxipB(+%HrKU>>iS(5cQRy?<;!O#q-X~R)!ak<^}Y-$Yj~b~t+DT|^!QY=ytvA? zInKoqBsoT}0t6&Lqa}QiwfA47%|gkjzEQ)$2h1`Dpx?vM?#V)jUWB-54@ur< zyS9c%x1V&%m9HqFK2+Lgry`zC@lXD4z zHYE&Iq2?Z1L*i^f<_kjh?KP`6h zQ7yAqlKPyHponij4uDKhP8nRz-wD2zhDCK_9uV9!=IoRYqSVYDdz&LP`1_x< zIXPzVVoCUz_JDX)4xTe2Q#5s<& z8vJki`^UtN(ulInnUiq$2PiKj+|F(Pm506aNhz7jqL=qyC@9=C_J0JweA8Ut-Wl%T zb@JvtZ+ox5f6;WabAq3|X@+><_3*Nom^8RGg$5kq^w8_FgbeiLO%)GU59GZ^b`Ic& z@4|f$4sdm(o&U+3$_Ou%0UW8~;r7VG9q#UR8T_0Y!qp3oynIv5)y@lk7w+Kk0328c z?(PJR43!eUb?frK!}Ck|)*`mg1|Qx&ShOLYO}qV<8vZwp|Nnmv`v=rCk+=B&BJX7X zXWsqaC55<*wCw+y6_eK59((}P`>oP^)U&=Igg>N28Yzw+x%CR9{)XYKI%%_}KE+teTFDxVc>0=Jv)zbM%GHE?=h zwY5~~(yiT?-1NPGhg(2D-801RjqhRU%uff;T-Ro?YYFE+eziaSke}9B(VEWP)%pdS z->`bAo+gS+<29^u!8gfNh3=mDFT~S%T}r!EKh`&<}nZ7`Z0D#mG}(N5bu$g^PYmbQJ2xU*>nnRKEs|IPVk^@j@q@a98fR zUcB?G=A`zwVgA?DBaqB-l3gjpY2CKfASbfWQp%d zD{gx|i;KQ{!i1kuMiJVyp0V;ktR}2Uw<-Dz;ZkncQ|`;5*~gd(aX}a!1Bp$NB%OQ3(1IU{<$-~HR`L7 z5W=H)`SDKG7zy6R4-8fQmNG3pOSet*CIyOeE^)><4yVY(5DYU(z}>ojU51#$SJOS; zUi9CD9Vc;|yH+%jXbw$NbSjUHj|}p7jEAyaRWXrDcYosV@BZ^~!G&`wmh*8R1m__R zKk7GRA5Q-CDmb*&F8in8(5-^XV+If8x~3lv-+WTYfB7E6{D7#uNYz*|oqqG9Q!YAg zVTNgAn|5V;^R=Z+oz?lJp?zrW(UcEte6aC$sY-H0m~()eP0dIBZNaJs(VAGJO6Zj7 zmB=jtrlup_BLyF|bcTM+^7m%kfINrC<_{3%JqQm7y&4!B~!~vUjO1B(UMg=Ggp)hKeJt*@lk*hLR2OiOCXk zWpd%-BiiPz(-YZ=4#|$l95%Lcl_KKN3CE9wIRZ;aDYxmpOL)U814Y%)#(LI3GaK1aI z>#f9Ua_hQk6a4vDFbY!T3He>F!mi^tw4xJumF?5jXPw66kGRBV%(&3Ic4)JVS^8Ds zx`3bW|J-2^d-&k!akH=uwBKOEbt`Ed+lQRtlI?3Jz%x|3hYGV?Uqe~4jy1&h zIpk*{7c)+=CU17>nXHYm6&(**rrEp|IY%p;Zol%uuGZ<;*Pmme#XsA_6R#dKarG4K z8E#nlURE3sU2YY27$;(cwu+zAP*3c}Wy6~O zREtx&#!}--P5$nJ%&Ie9x1HTN^mwK@ri=BJ&u4?uJSTNm*I~Bh+Drx5;b&GGi;?fM zdCVM}%n3A-f))L7w)n=9bY0a_`{Jgm3&Cx@zw=?!fi7L|X{N-k_S5{_3ydxbVajRG z+{fQ0jU}m0m%xoLw_o}Cx+~*m?Z=;WFOt&E<>reRbi~PJB?cBR6=7?h)z{pNu}Ma4 zgActL^kdVej~+tTqf0hJa!Q&`$|_gic)=|9b->^b&)xO-@o$9ik+4D`v!M;P0FPS2 z%KhXO4f*16n*H-+=~(46E3fR7ZYzXYuCl#zfAUTzz(__!@(j^&k)OuYSdtmL8((_@z{ zI<1c^MSlHnOOn(k-gB{6{0@j5;qpf?&7Fx8D0n}0cH8d~`Q3AijFYn^WIgOub-i{2zB4^vr-C-JOx;RiRxfVobgFTxmnDo1gt(kUoF5+T za4@Z|**tPX=QP6!n=Jc^N=dVk_lG5v(cj-zsqEHf;9^lycuDS(QUWG4P97RuiJ!;3 z+f!QqVbD!Z^mi^U%`_1@SJ{x-B385GbMX&Q-^xAaS6@{x;dFvC%ZYQ@dqPk?EMe)y zyP7(1?-hNMofYn*Ka%HFNVrpT#;~#nCA>TZr~HLzRfkKlitW|`rLi>)5ntz#p5E-W z^1^2Y6-#1%7RnzQu0DtVPJajze5$VSM`^XeKv;?MyeeWs;Jmx~5FLs&DNj^^@}tJP z>>N;1e6FV>S-y@(P}_8_G=6FbcFYTi!^OoO{KyLCcXZ z4Zx0QA1UECScFl2`MuJQzDiboM~L{~;(qFmrqAKnEf~|%hWR&xKId@X4S5q!r2KyGzWt6o1X%I;DE- zaVif}k=WpMe0h-v5pNjOG z2)-6v)lD17c31fPzP(!7wP*`}3$rrI_1#A&zvR{Ix1}0%$Xi+&cC9-f)wFhsMOprK zA8V*t^DS1ssM2u!67!72J*Uv97Ef2+oGLM&{u zvQ|M(uAkx8R~J00eR^s2<4j`g$7I@*ppU1QkBqy$H9dCyLG zg+_LNV!dx~z-v^pJfN_QXh;^86%E($Wa&fv;ptLq_;Zn!{zH^t&Mp5f=VR7qU~a|L z)#_b3Pt`}iyH_Hx#i>k9mh=>B8o(*2I^R>};NJb!z@be9idB$i>Mw(i!hBNJ9pwQT zGbU5A3zw79Y@1t|sDyuEgAc~)NYU{}!p_Zetf{ARRy48&cc@C}wJ3ws*`-U>F^mHX zr9Ma2s0m44Z`J;Y9dc1#y#n5AkpE&A>BFhZjuc z%hrYzl&sMs=}bX&Ph@M$`Pz=Co*b-G@b!fI=YC#Epa$pJB-STDmT&FUQC|9=3eEm0 zvpx25^RC06y+dNj`SJf}87?jMKV|s;Yxd7bT^V$bx^^g+%hKZD_(uQFy`Yqsgsk-c zs{5BxZ(=iH6V2&AUe+i~GjK_{V#V!3T5QG6Gah^1ZYz3T_}KFn+jsl#TI@y7GoCvF z-X>}Q-X9vQynmbM$!WUxT#vZvncwoxMg{EQQHmq)|15V4X3lLl?D<~|xqRaP+n1 zoqM;LY+Eu{Z|i0zVa{bv9J?@lWSC+@RDFkOv1}PH9{%o9Vc{mdIO)?k<;GkuQZXeK zrby(Lp*2@THJ4rO(L8eVRLIrvLg9r7`-eEhd^Lmq2PDt&w7#sHg8!ZW$Je!=AGS%t z)GI{V#rX$V7*nO8re>VFviYle3Dps`n3q*;rF=m*klJsoPrSp*Uc$Gg$dhV!qL@b9 z3C-ib7vHUnTpS*^so$!y4lHIWhSw@b%a{1qnnt$&v3y@T^vCkJ%WNrsu}JX-a;|jf zmih6gB}uQFM!$tVubNoh9cTEH>Ngr0_PkA0oG7SJ8Xf}C3>8i;bY7@)JCA1fOJ97P zAN1d3J-Nd7Lo$qo=&d^<#%+aiWp5)(!5>KzS#(k*E1%<+p#E7}LaOE;w{>Q6ugagn zo_Ts6`R8!`qQu0-iiPyyE3m~owVS&a(uUn7<*XdcCmxB|>Ds!X7r%H8Y+Qw1lB!u9 zc_OJ)(!N^h_zn{pP2C%lEk@K1Pvdw-XqCCF<`WfF$$Fau3wBZtG?WkUd05D<;#`dt zqA8J6&CcTWoVOvAugjRtW(7)S7U_Xb`u4S+zw}?AeUIxL<FpsVj(WwCi^a{e;8ukaG8M8o!Y`LUcBr_!$yPVxjJroFPA6N@ zssKqcEqCA*!A&4;@&Pw~2l2WytfKve3p8X8IZ*JA;Q;8<^HL^kyds>ap1gukj{vX$Wh;dbVnh`oWT?enp;g zbLYaJN)9js?(0zJg8@lhYV1+eVs>-NO|Lcoa`I$0vI0xcy+gg_>dxUuLGW~Bwa(XK zqa_^$SRcs+NwLyUXGrcqys3+SqhYlbJ6p6JW12L7m#ImoXzwZu-JQQbvSEIAXb%jQ za_g#>%ro7Pm@?_A*BQcIh{6com*2Zwt?Y3#88?<%hfZ=dxx75?sc$@Rtny(*PW~Ar%57lM^P1R&6M9dR4E2Q z>G0z;=5Q(LZ39^xnJ0DGm7yiJgVq0**$CHjJ7GhlSE>y2NuGZhq9C17Uw{{pp|$i& z=T?idiPn}~V}@qrt@6BdA-wM#$~jtmOn9aCNi;Yi70s00&}Nu0c~zOZN>9s_O2jyF zRsgEiWNQxWgl?P(#9T8NuzPIl{s2f<3GKSu+$*dzEUZ+-S$RabBoGZ(B8CguVKjM4rjhty(O>dXxeX z4BgP=Bu60El=STm)o4JN^$035pPW-w9+hi>M@uD+6T~lK<;N+K>?qIV`d5U&QSM7s z!28}m<}-g{kEy`LO*pgzD-yEA4!-x}RWx;dqh zOuf@ug2MKs5=KIMNg=Cf?Z@*5; zSVw<wHYVR-Ww1e_d*nzn1}*}yB*CaSQM z`X4StccfqYOb^7jy@4frld5u}b#q)^Nxm-4hgrbwOl)s-Qj1_Dn$c0zaZ6jgcP6o@tZhf~6(R6MHCqvbV1g|b9IiTJY(5*v>&}6PQS4b{$JBMKCiuWy-wVCh6 z^e+_bWZX*SEPCB8isl0f&(Z8M$F3Y;!^e@M>W^ez3E?YzqY83-zze!gnZ(Gver|Hh zOm@SF8c%Fa@v=j`_QS#ZjYC|1r++DzEhJcPDrHobN72)ajRFuvNNHUfcuEAq!AMvYF1)T)d%YYPiRDob8)kOAp+Yfer(XCGeWWY|_ z50WV+(l~)A<^Zurbve*hspi+J%DJMa)|8%B>v-TuN*s1{ktpWv z3OakOW8uHN$H&~BVVn^R?ksT)e0W1wMR4&61EwQ&xSl{Im+6#XC+-Q-&Z2~Cwvx~5 zrHUnf+IxU;5xry74tw8Bk!qnmL|`hzrz^RMcS6a1CVD#efcr3Nys4QYUaz)NZ|Xdn zOeNeB#S63Q3gl9!u}A+Q-!JHHicIvYw)?V=dtw)J&81$HpYcm+s#TCu|MnDlPl#xW z<|cY26XnGe0ygZR z0g1;)QPuCZqKXPf8U9OhcaVGpAm7KiI5fSX4(Q?SyINgkuKe^gTS+C% zr=|0g!D1=T1}qj!THoP|S%@EG{=>8fXVqq)GZAf{Cu!}1S(N5PkN$r=pom)G+Az|qSvh}LHXUH47oN}|7Ful1FHE5PR_D5Rw&n8{H3%F z6)m;pgFtD5&|Q!KFDDFL7fh589r^V@h)9Z%tt01b?5A()1jVAAvUIORSOCP7)+pdb zGlg6tJRnG`TWLow(fESH5fh(0-}neEnYWCEb#(1GS`BJJ+H?= zGDHb;_#=has>>N&_d~E;y(_>WD4ktX-T>Z!i$JYbNvWSAweu~jP(QGTe*LZD^4`lo z7<=tMid;>6L@1(*=90A>FuhIPHJ`b3?Dgp#7F4P0o><~VY`rNpJHCKU_6RD;5XkSP*K_hYKJ4dQD#biIcmJ_W z-=PCm@V~DdeJ`ANHehC+$!dik0;A=SIj6OZK_a&{6yvCp74s*-khTyoM?KoP13M@? z$5>(DKW^aaGZXkHX=*D_;)EdWdWrA?J1Vh6_@3)BAp&4amM<|K;YLR*8Zk6%Fvd@P> ztt1&2dmrv^?0nreGn&+(PB26Jh2tzO`khEQQc7Js*vLGKYnA0X27p9zmKiCSP{Mi? zrAopQt;7;3dk<1Z3F0Qyv#yZFUkvG%Vu|3vUB_kVFn)h>O*D~6``U8y>%vm|xCi)< zLhxC5yz~dt{>wAQ_IESJ+}cb?eihtFvfr)y)uvLo9%GN0m>Gi!q#^_6L`t`0F+Y8sGyzH%d zlHpQGHXZpIy+p-*j0lVS$3ZdaM`d$O$M4x!!ZyfnT4saz3%T2At0ZisG08;SiDWIM z1c-9(CdYlvj0=N9*p41>zN_cNZZ%i@kri1R4W5ZZoH4q~0Ehxv$IU%RrJY++H1Q$oP55*?Cu+om)Msho zI100DPeHXKT-ZYQ>j>NS4 zI-~jZ?*V>$aSF1SZ&*U#G1gv1h=(ntYxa{HoXB3?@ zbqr*cs`}sT)*Ara>?lWL>irGvWMUsdoL^KuSu4iH-cQXIE#=_OgMiD*+ykN_015(Q zW=fhohs`n}QBRSWVg*9;%t&DNYZqX_50*EN!ronQs~FpO>E7tA8jc-ZKKt)0&%Jp5 zg>FXYm7(X*-jV22BbwCf!N3bJh>oPxF>Xb&c*R~gRt|gFK-RJyCT)-UElduw5CBhzy zPnGWhmf62FvlIB?9o$2-%pLuQQtF0)`Cgo7_8tQ$r*Sn2)Rau*x)>^4g67VxbK3=; zB#wQX&Vr59=YKm+VUnONL$Pn)uw(1Z-HO=h7Nq1ex&E`DAG4mdUZ0b_XAgyai!Mr0 zry`Hh`mcpL9p7h2&_%VGV&ZoNO4=g+=GTC5fnXvhR{kDjwSyix?R=UYs0)B%ngByEaGQG8&7G$VAev&J$@Pu)?q?RB z#@-iG=j6Cp1#~e516RPm-L8m;r1iT&vh2}mj!F7dOQ$3Z;JU1+F@icL^z?En zJgfJgy0%df)k6!15Alsh7SRa`>;>SFp2@^B`&rc3hZ6QE#>Rma{%r!B+DxetA}2O- zjPeTS=r4x-JRAX@C(%sI*J_W|xgF*udRUiwU4r%)1p3Nm*sdvtExO*()K5V$5e89b zuk-1-sB4WD$o(~6BYD6pt6!dV%BFP&bVp&mXPnG-xe8%?q8yqPmA6Lr_yRj%_y_31Pd@l+>B`2p(P{d2@mnUiSf?H`0 zoTo^y7Z4a;En9c2n3%#CEnm>r4s?Er_Nd7vC^1=p9C#kKnhi8aaR?U;mmhcV_5JZD z^X-3=KyT~!;QJU;X4Bb?rqc=9r${*_weR9rLZe404+vI%unpa0cyaQhmD*nVO8N+^*;6BwbI ztIdVhpvGV#f?l?${Ra_;E<38TZS;9~{d2Yjk3y7zDyORO-N@^EXMa7tA*Bv}$tcXR z9W;wa7 z|5&!Y-u5HF>sI(UB_S9T2hUABChW4bS>!tX*OM>)lQYL)J@*uSXU8NnceLa8+Krd5 zlKZ<&#I^)*4!^E=$sT8I6QtP(%l^9BDGu)div!O@YX6hYC#?ju(;n{VpB)gsA;?h% z%!87cn+Q7WB~wh+IyVsvh)%|h%S126@M1B6(d zV^W$!()b?V74qsnE7W{s#aiX$TIA~SYcP;<#wZCAG;!DEI?ri9khVOs%_o<3xrWgG zl~(-Gx$>Ldl!e=N7yW+{M+l=1-gz3}nDB59?4rCPTg!^UNJ`jenMfE?NLw~zPg60S zOhv$xCc)|uyrUpmL;m`-T(3-)U>ou!e7a_gA{i_jLG~QUwlFe5gF;?WH18bP>aY~^ z6-bcJfo+Bc5poLsnbqe1b(4xb6;2!DzjKz}-D#3YsMn~-E&``HNj*6d?35g*$$+A2 zxtUT1_VPh$ztIVvEvJdBvn^UK;qov6dAF;Kq*I|_253kVAL6Lnm3U`(l0B+&SHOZD zrMaX36NE}XG<*gN2EQsRSXMG40Y1l!!1SeIYM^DH51n=Xt!sFD-izmWB=12C%no;| zUo!xd?(QV!BJnz>N$tm2v0YNWa3SJDTL@hAPMRrZu$lX*gAlPnf;Ru0VP;1^cToX! z5rQ>u3t^VF?iZ59q`OFEIuP6}#0~5+aFhtY{9=l^;Xr!`+PEzxfLrHBQW{2+wbkPU z34X#l%gy)rvd?$*e<5MvyOgUwdYk&`)w#RW_&7q&CC74Im2&@=M0(bC`5_yELq>^cRJeup`Rq{ z2=T~;uenyG^u_-Oak7Zsb-jHs{qH5))_l??SE8owgiv3SsmvrpL0YDuuPQDFCysq) zD%NQrL_2!~70!+VKu!FdAs|!1LK`-iO3sDy$g4Ct8 z7l-YguBfWdqYk6)~%;GG)$I`d&Ta!yTo zrP2UlwUtKTL}0q45B2F z8hN#@g)Z?<-Pf?*u?@_?C7}MO7)kx9?Y||aDf*E$uV@{`q8acBpag&EZ;n&$Dbmp3WP?ZbQtsK zXtj*V+C^AmoMRFcdwI$@WYC{3y$lH8GtV8TXwKuTokXuS%#UqmDM|eUAdlebH;r@8 z2s@XosoieNO43_kBB9}hWPUo@U_4a&nllOzqT&3FAs+1%+HJhGh$tjiRlw^7}7-_2o<_J}GFPjU;aHe5dud;LQ!zb57ZJ*GH6 z;_FS5A!D))j#+zz(RwS<6P9b&hH?Ko-LIo7@gb+M#fXs~Rt_Q7@gXwvPc{%dPZ9+g zc`q^dy9>D0^gHt6M`n;WgwHAboP0odEkN-jy|#UAyYgdd`qd@o9mx~JVFYURKE#3D zE@`ptYEai-Et0YZ6mDMC*UHu<%ub#h6g+_bn%VIdB z63xYY;kFQ$4hp;-Hq-WlOOPfG`fhQtltN^e1Whe$Kf7LjP>T?b+^uT$w$xDOZ^u}Dj3~AjL&K}d@)_*a5J&c@_Z9zM) z^9a5d2P!oDdhH@o*g?u{#{hU?;t|~Y=IEl`Q|-S91+Fkn^2+x>j+6BvZhBxnX_oBU z-g)DY_-0sl1VBh41U?qM)6I$MlEoZ#l(4U6^^u-sK9y#%O0u+-zFL#;vyo5qvwNX% zTARoZNme?hD3Y0Qx_Z;D?~ybHg)5Jmd;c_VJZZltVj-p4#X|Rd)+@AcGr+CFWP}S| zWpqv(E|r)k;jfUO?tl=D{rwyilVS;xx{PMYpw5&F zTR!rr<0%)?GEJf4ji1^Zx_43rQbalnRC?#YG82q*!pE!Clk& z+wKO^%EH#z0ty|2-kxHd5Z{Tv`%Y%$$};OqO2o8c%yG*(9LDARWnXlzY@xGudHbnr zt>-6F-@_0CfZPS4ojV`eewd@dq2>CJKu-tFa%B_-t_N2BfJtBwoFa)tb31u9&5jk+ zK{7u*&6kf&emuNKA1I92(cdMTi0u;s9w|KzQ?}J>EKh)E+e5(aB83JKr2VG2w_VCT zQV~;ICA`EQKExIyGj!x=nTlt?I`Jp$=NtLXE%~V>zQ|efa}S>m=aQS4-(L9FdE>U( zo5!5%6Km{2`Gikl4=N((yqvo(m6+tMk;QpY`;c{#qho%j?G02iQW&_PPq}nHAjmL{BA6 z6`b{W7y+NJh6CtJp#kfQ8)mH6oW`ZZbj?PrP3S8sWIv7bkcP&w-5V_$E?atfU|+;P z-5ta6oME*Pre+JldvgQ>q)b2}!=-*gvG28dlkvgaXiPs#K7SDr(D8KI_6T9$h1RRL zQ@}MB5?1??PE5T${!Km-fD@?L)6oB@#}j z926vf^EM8Q@ap*{6AU|E+Ptw$8lmB!$;2FF%WAUK$x+IIYWniaQ{k$=yQH1H45+^E zQm-N~!#U)}Idh{<(gLV|`e*`q?4Uy=VT%GGqQ?cL&n2Z^6FQfBZ}-9H_M-s!$dE?K zmIXP*#-Yaiw0fzQa?h_0Nv^07gmpDRbwIe(2yob-IBv}+9zK}s8{Ct;Ry~l^W2_H! z7@MR-)$ajCuFKZcK?P9m2g{1xq1t-C+%b4y8u9VGpdY2Is4L5c*|^f=NGE#7|Xk-`6(0k6IQ zygg6C$GA)OG%anHPbO=-!n@``Bh8JiFUCfKYcD5A-Y)`e9(0_oF?i94*TC4-b!XWy zWgj|mC70fE?omVIn8jMorFV;`U;Fet{A7#j6GL&H^|b~lsjlEt`i?m$jrEsb4BYtF zSv+E=n76#p6f#Da6b!_NPu~EO`8rwu;oqj47N`LSXkZs@`SFY${zOUvCxm(KcjRRZ zRV%h}43`z&x0K5;*;)JpbT!g^=8oPKPxjJ>^b1lvP~YCm+nfP;X+!NmUY&d}H}+KF z+tYnwJ?dJVbDR-T_@HKR#rY3Ll`o(FysUWq&mv zA?+}n<1hKDJx$QN-e7GNO4qAc(ju8pOVkz)_hq+XRu945pP@z}_03xZ*C z7Spvu2`<_s9d`bS%11%mNRhYygQoM2XDe>oc-7ujT2(=pP0ZS(D2f`jN9?^v5L@lq zwO3Hou2DN?tSYh9o}pIlnlazg=Xu_L{28B|b8>$7ecj*dx^Ej~EO6n&yQGxmo8w}Y zIT?l-{E5#1>?0{7)w6a7JQd%b{J;0ha}x2|jcq`|chercLHPUtrTrTCOLn8GAD|g$ zxKl&rF4`$A{QI$AUTtI%qIKn4*M`xEW1KpVPIIYQ<>LxNg z&jnz{Da1*f5tJPiQF~&SFaCEOU`5;8jQNXz^fGn*yE#fY&J3Ci zLe0b=^wr}mHN;LVJPX*LB+BfQJn!L#W7BGmdz7$I)4u;KI8mej&TDv^l(5?;9J7V` zUpKmtky#9=Z_?}PSGg8A8zsW2|Jn4pyXSwe<tP!G)5@Os}{d=B|teYux~n^*VRm@H^wXK>ZwB46fQCGaY{2efB*1Pu;{! z1cvNe9(q?x0@HsG6Sykb|5cB@C5%2@vRgrcX>9iF-P`vx)B(28NT8b>=O{-fPTYqw zXJMz9D=)eS{(LJu%5%ue{aW@ICxcsTme<1n*^ang=N!hK=9)SH|F#NSUMS%cZ;&K; zDt;if|Ne&ut3RVe;5I{*AMA~U*~OULdw=WFJ66tmglhopQ@h3ge@~3^ue*{U;fz%C zjHSEZ>g&MVLE}CYI7%qelgQ{I^|ouaMV9N13B}k@XPS$Yubf9P?E=f6x1(axEQFYE zXttFVtl!VQ)ZMqO5AQQ}|KS8%JuBWf`9rq3?}b*;**9B@UdmzowqlTD<>yfwT^-wD z`cMlhJG+jvi4+$7v9!B4Ic(%q(fdO`r>dfU?(*&+&Q*7b;+2jz+BAt_#+`z`b|`wz zC0{d3zkXYE@e!NOZ_VJJcJ9~X!U_Q=xc`&k_en|?I!=%fU{-m;k9w8mTQCEO8dyIF z98bPRg3JSISHFDeZDa7qj--4PPa*cXsz1t|`Rfw%IvH#IqWX@1_T8nqFl+g^>r;Q@ zlW;y*gQpfHpoI=Z*>BG)OyIeGtjU6x4mHo=u)-Sz7_wlk?ItJQ^>CnIeM7IBl zB*SkV;vT18aRtV$-!O$UkEDy@ZIC4(A@XLzN{#)3Y9G~B-_FkSF1hao_0`LNor-?~ zU`C7thKRjX(OaV1Du+Dw`d#&jv%C2ksU17R;@9q%l-8{-X$BoDD%#F8&q*(>^bcW% z+Aae4zU>Y2&~ib6dF) z-%$!!_d*O+Yy!qp)APC{CAg`n5-LA*S02#Vc7wf*8sR(YVnBVb6g*hu$vVBZMN3gC}(ZRE6n&?j3o4R?! z1C0nC=TH@ZnY144_5Sa7U5_J>mS9B#bbq-|a)4=dp;=tMTMA!FxmA75ZvTRMn#Z|4 z?Z+Nhh-B46u}Yr9vPCgA7$hZb`OX4y{90{Hf{Eh7oS0)&rXywDZKv@~sr&WU0gEhq zKpK1IzMg8hJ#(6aZ6;()nabRknr+eG=9i0x}(uV&*X{MiYfH&k#=OSgG|-SrC-Ub!33+~GKa87g=5Qww*R^I7s) zh=PF?yr`P@NVE$O18``3@%oyn&-D<0C0-%%6{@DJ?2y`Vo@x1SIUev!`YrD=7inTm z2zxQ()Rn#U;Bz}AO?Z&#m@$eg|ALZ8oo%DW5o~YP1RNPa1*(`6g}}+mDhalsiRZ`+ zX^ek{Vbj?Oqlf8Z9Gtf1K|jBgS;sv282FA@+9NAuxyOzBcxMecw)!7%sj&9+tX+|_ zd>qgInEJZ;7yt4qd)h$Z+`=RpL7w7U!Rm~@UqQU;UYj!Xx66pcnJnK|)rMUG)|pJZ>D4!3SxgSm)k?sAb&Q_`eSAbW+Jt-S)MwGDabmk} zDag3n`RvO70{gI!DXHH1)E>@`FBR}pF(HUJ+V^6p|Gl|&C!xtjB_aq;a zOA`cBDUXuRFGreWjq;OvlFo>#h>qFS2WK-bM4Ge^!ty;^=$vE@qkpRKXRCB)+tki} z+zMKi^?Y#=v2dVY61)&C`4;103RPD$0h^k6r4F?HDZNom%*^$xtI^Eo1C&$2iMNaO z3<6eQ2j7}G-;{k;KudS1{N*XN#by|2)#)zl#abX7sGE&1(tY^MJ#Q#GWf*|jpw@V> zZTGa)Gz%!h4ql29bu%D*GS(Pj=dt6eO#h*skbUs=O3ug4!AY+&LZGiLxtk!{6;85L zBT)x_-uKXPpZKFVRfE9HuE{hub%;2yKCBg34s&~RrGpGSxc2S8yFKstd2kKGyOzBm z47|N&O;H4P{GRDupsQbY{~$786X{wEqUI61TcEfIIy4_^r@&!-Izxr5^~wPjZUHOp zL8PAfX=!OcRZg5^#6&5s;ckcp2LY+`HzzB(CVGzt$r|%Ei{5HJXbv24*bk?H0%$=0 zBd9Y*UoQs`Dbt^T>8I6`=xGc+Z@e;$!7!Q>lrvO{D;c?+i5-|O)P2R8Mrf#b9f)FJ zZnRt|Wk^3x;LsS7?_4;8qb@O{&R&BZ*z!R~%m{~L%xL)qU zwL*n6{5p4}yLy{0h!%VQL6a8!4HYqdWgbgZxfwwL_Tf|UOT7SG7aDX4q{lLpfjIXG zu&wKob%{YQwfj(mB9wa1*N#|>+iO3f+Y|wb>svFbqTYWC?9%#TQVm;xF$d>jE-#7n z@$YbU-yV*1N)p}iL;R#3AQ_Lc%9#tK>!zu)YJn%trh>zGSaYA38;}~)xOv17W-3vq zlHNLqA}`(Tzc0D+cP=ZG{IYiZw6_#F8>fza^@B&Z!x=(|vs9b=yx>5OZqQO;YDb+s z71p_4i%^?Yhwn!xagKymdOAV>+A9Z$g6n5rGZAM|8#eJSKTANSKKeenj;dE%pMm9R zpgd|7GkDG|1vby?t_>vGOa&#i7?86M$?jYr_}$HGao&?lL@jm&V^7E;%Ac9w#}m=h zigg`$|G5}OMiPKc3e^!;D4eHc*7T{C3^!EKjDGgWyh=@yQy)6ASeFRN%gD!M5QU}~ z7xu@lH06`P{yYEngU2iRK_w0IdoRFG?@0>3kMKI76o1&h$giCAijdzsQu<3 z@UG>GSy!Z*^gox*Zy;8#fZGIrnh2I(oTpOv@Iw-FxG?}=iSk^hm_b=J2+agwh9+bV zPB*$)#C)98^Z(Iyr)L(fz9JO+7__(zuJqC}(S6(QA=URYoP$juT;D6!!v+{%OMj=F z;27cMmZZrlm|vJQR0D_Yw>g1-H6wR_tL-Ry6pm{e_(SVGwD!=_n>Nk78QDI0)d$kB zDGEkJishJXYWon+w{w^uH9oC|*G7amF_|nE7nh3~IaIUV3tN0yp*uO9+wI?_n@78F zldN5V!~$@FpCMV#fjxh)z}OYs;E5HdM&A=)DN)n%3V|Sq>`sTo1rq9ewe3hIVFBu6 z-RJEp#`)BLY$(^{^z5pts!A5Z??v1#&t5W7kh`A1opA4!6ZezQ$Yit%kPX0+BeWd3 zqE#|!m(-7QruaZ)Au>ROGe1pLKpr^%H4%VifHQ<}02psL0&O?vQMLECA#bUg^`LVR z$_{s6!g=*+2tyoNxg!u^!Ofh+m{Hkpv3_P9@UC*)Rk5FvXgrZ~Z4&DIJ&t8IBb7!P z*8LL!VuL--6E*m&u(i^$9{yBwe3oPrf1BQmI=$%oywcun%TP*pZ--VKuKOfT)>SYP zZfH*tcSnXP>7@uDCMv$Eewa7w(AD`jE;9N2#eypO`|GEqGwamRxHfd4Y94GpN-uwO zZSEg~EbBni2 zfmQ;PbHLl>0jxJZ#M14NCGOs7u9UnM&MYE4;Jx4uqNb48L{IvC>tVbfkAK#uUW!BQ zCLywHCt{C@YEkz}g6)1RBj zdUN`j{lu9#PQ?Ig6kiH)YOeEk#AX>G8o{L|Ts+Gdd~r(s+nzw2ER>**K&(=|l*)CE zi(qEUpyDy;qh4y*@$&$AMQkHWH4h=WN0)BE9=J`XBhnG4#`#W6#TQ~-a2k43(ti;I zk!zwwXB#Y7h8i59&D@NG6(j^8b-}G0>+6Nf2a<O`CZ|4bZ)y>{b<+PD#%`B6T1e zHmUh@T9j}Iktnt|d}Xlo$Nk{Bu#ZFKTN+tTaCXaR^QS&Tob60;e_ohH znAqwS)DbM2fR;znEZEDR?FlD?*vByz&;o#t&#Po=F+OWJkA49yW=}OJC@Tp zi5vqG`G;4*kE4v0(Pb0f3mdwDU%h~hC54w^K?u7ETTfuJ|8pd@4%;U42lt=_udP59 z@RpHWj~;!C++JZtQqsitxqMEt#B9g+V6aTnUX@PTb$Sf}vqyMWGn5OOXnp|szG zSi@^YTG?|i?uR3#1Ra9ZM=e7~u$stocPa1fi+ibu1teALSG3>ecQ%lx5_w8KjeT<% zUGnEf(S(_ZPtL@AanDm1_fTWzLAm_Nr=e_ero*dTHGRF?NW2Xj%5DtN<8f?fcHaEq!T!?5M;E;Oh%Qyb8jmvoC9ZBew^7=N5W@A-uSfdjRw>iBr;8 zzON?NQ4;%Be~=(+B^tn$d^@OvaO=yeh^J$foi*5NJ!9c} zcdn4vGT7+H@bWfQbe6Zi)-vZk>eqAJQ(B+AS2!C+=4ix)h?Svd?D||n$J|MM?;rE< z3wei15`E@&t$Me`^CqqgMVC6nK5~)nC#9t_^11wj(0~qd{1E4v&EHAzBHW;fu%V?~ zU9j6j6-E{j?(-4fnyIATx5Gh{ubapc49aQ&J#lb{cIF9Z`)e0SeA=}Ms03oZ;+SDx#Gsp#kI5HYzNr0e*VglF@kTQ) z(-si;6T5_Gow(1UH*&fNR=zw5=%m%|7hlHnQJHZe$=UX4OMSI{u%OV*!NmQoYRpq8 z_x$Rn7(Ta)OHIj-)7sP|K(%&sA?na8`x50=q0Rm-3T+OY2NKJcq2xSX&`xFb9@#5q z7N1G}J^M-nU2KBf!MtC0-yS0DF{e8^y6^Et4;r6tM!*YvEmQ{UqJ%{&-OL7h4h7fL z*H0``l*k7A0k}lwYs&iAM(CP;S>k$gkMBvb@eF}w&0qG7X3BU9@U8L1=MNrgVuAZ_ zpzq37+_SIdKmc3rt8cV8TjO0mG0r+86(vZYD8NA7Y|vehx0 zqHBfN#YNJ-+;ShUh;A#aIqxE(31J^xI}_XxV!+nea0C9<7+mFni<>LK)@7j5JBWWq zaJUg{4Lgs1e4l#HzQzv?q@Oc*Qu_S+=p5GF)$(8Bt!_d#1$pGr=gANN>%`^`;aQ!`5rq4~scx{HxUE5Or;&uQF0P_z-0ksA zDhOqc68MYKlV>@wKaiKT6pC@radY7spMMdA(dQgb8yHsdPwtN{&=WweSDhd30rgv^ zEe!{{;$iBr{|6I5=A_=)Oy_4-7UY{%OVv-AfFjWYv*rnbQL#m}xp*jWD z5I3{ScU`}sHhg^%`gk-ShHD|x$jGRx5n=j7^-kqZ4;lUa3^3-n&DN z1;!vOuiWtUwC+98h{7TMn=PN0&^D-61rm)b^fj%1*QQ!Nan-H zd3iO55>+p-wG@&#BghOt(J!A|d4W{;tEYkW5*ZX^n$C55A4CRs+4UP3M^qcixRyF) ztKb_|6-%ylwm3J=1Ltk|CwqcM5qN6j{2owm-Ux%paFss?g}A>l%3H8jaz;a5y}`=N#;N>$#?t8%f5sWt$n#Hl#^wDuN6QW!ILG@SESeVy8<|l zzvbyI|DM;>J^{?EvCI~yR^RDVll#q-e3CRKP-c#CsU{hMVrk;VUw#5sZce|zJK*O_kL@fX@Y~0{2Bt5 z&w!%}uPkpfngbN)o5(WwXMP@dab3-C00u}h{{Rq2w2HfONu=k#?u3Vwta{G%=LUL3 z*v?per}mkzCg-`oGVs6aCmLC=MkKXoGa9thX@I!^pXXMTt$oJ$1h4E?eh^~XPn?s| zalhg*QMQC36~7T&x1s;9y0cdeg1A_eJ$nLm%2k6nO|_BqefoOj*hMk)<<_!B-e>8H zNgLgc!v(!GlOq!?<7Lx(x3WToA1}l%?=LWTu?NvnQ)yl@vq0`oc%RgAfId*6$yh6K z2WJYa$zo{q`l9c-h>M3z z7H6*LAv%6_Gws%L*)J1PcK9{dwA1b9=J0Ky{9 zGI#*+xvAO)NGsG*fgR(PVZn!Rv%oC>P@ELksZ&qFK-uJew;gg`n-l+HcGwI3G+QXm z5T|)U)3t4?cPLn%I(cLUa#QvkmmvrdZ;aCco~}p#5~=Q~`I#*d{7K2-L!y4$u_@qE zIOmaR{r9p98W7%-pa``4ghh7mi(Bn1i58e*6fPNf`|(egz@^`DCi()0%fC<^b4g5G z?0x}@9-i|dK<{n@^W!+ZyTAl?N0RN6eqIf}&u;=XjgFL;MEO3nQVwx>^zY8EZXdd0 zUCC0A(>rZ*Pci@>?e!9w0@U3jf(N&KraqyJp5kWE#*y?j4XeR*fSA@Eq+1OVu0{xS z91!A<@zMiH?KonIwDg0l=jz)1IWLn6=Rr8qFu<_JS>%>Lu&6A39*MP@%aZLIJ2k|5 zl#giqhFloi2>ymr)Yv9D!La>oZtW)Q`Jm-rPr()oFpR8X#Z=BvmGVuMjklQ6NY%_D zfPn$zt&R$3-GHvSJMHq`nq9u$w=3`N;bRMNOa3k-kEZPSQqVOGw2&*Mk0|y@CMt8P z=GZBk1d->&H3;L5fKE%l8V#PA1+viyy|@^R9?;eQCB8Bp>(f&w5RMV5W`EF^jvKpdoWVx1EmFy4@9zV|PF zTJ(LM%_OmMfwqsytLRV!Djrj#JP=a>vb-PIr^9 z4NT~&jGEc~s*)?2rToU;o=}N(GKyY(#!;tvk~*jy4(+)-0Jn` zx_O|fg_{s)GC?Z@AKX0N6#dZcuMT-z3IR)6`q+V*1Xq-GLa8F0t#dYWIew9;;!BL| zoL(+g=@R&9Q;kIkz(3dMa+FQlNyT5=ek6bF^+>yX(%<<0Z+(tyCfp6qKE=cwzWq zvz2t{zF&+`o6SDoBoxM={svW-tl=0pH~aU7diCnBK|$Ts54*K@13X86%d)97hq*ab zKKphz4Y>AgFaraI_Yc#Q>dkY!ZV#J}n zpU}l4ou!nBF`JY3%2q3p$ay<4dTMt>R{%j^x8Si0BbxWI4!=&RW=<8h>V@+CivSAh zy<8Iqe+mzSFA;|bqFmW0DX3T1FU)u|7S0*pRQ4YI?0L-=V1VLCLA|RTBpPI;G2h4! z5<0Jh^hr z6_guD94mi5$L-5Q_mY^gJe^7F29E}A+91j=fEu(ydrgRJ_)mPm;{HAOB{FYi1;1~u zul*7zTe8HIA3YJH(9()#hXljeuMe$>9xy*tbnRH?+S`{`wpmEB3*6sE74c8W^9Rs}pA2Y90%16L#I%JZP zj8@C-)79~CmGDvhu!P8B9B#!iw&z+Q7c3-WKDW88^lsUu^MJ%k#d??j(lt*hm;P2E z3&ob*0$%2QoYgYBQ3luph{kav)8=gKzBN4V7Oq)+D(7~|=r?L0;05n@oAYCY;rW&R z(9nzn95r2u!3oe_Mgx&H8zq!YnfYugH=i%@)yYN}S(5_pTyG&FN4oOA(-6W*6k4KowOv<))Jb>~_UDQxh7b z*5SB&A1a(Wv3+7|b%U(^_)@Q9`HrmHn>~eStA7Hd@K{yupV5yFyUAJ1{+-P zjG)(lUJabq`7CN{Zhc=ns18_K?x)&8GlGP-0ij!y2Vmu^nI59H$}qU*Jt1I5dS(oCmEP+vTy9$^ zfQ>1A(ROy&mF97Jw#E)!H`F-|Ev%@D`XL~Aubi-eo zhtf0qG@};_Q2rDT^a_~_#`!oW9KkYMipm8GylkCpf*!hss!B)MT9%cRwgMLvf`hPY$U6oE+el z&s;|gOpXJ!uJ&NqznTC{Ko|Hx`G!4_)3NWoX*=qqcq!+UYKXe|;C%0G@K76Yc7CN+ zl%q~QZb%(UZ?BKF>nni`S&cZ54-StS?*)zR(#BRA?QBgp7}*9b*cR?seUj(n9EqTU z2o^u9aEh~nT9?1Lpoe7-WP3=J!q4mKh-wgPCczAzKgs)0UG0a;WXE?nr7_R%MAuHT z;{8qP^+{DyM!vdL0wJw`*4NiXaW-xV!Mvb3EiL~zF1VBoAQQQMaQ4~^9uV)VSHv2| z6pWQL&C+D6Y+~fNyW1LP9ir@Q2+x=3m`^&z2WvQ0P zSDkFv38(cFP>9kvke%26LCIl$$9E7K>^AYu<6Gx1BPY6Ws4UHO0?X46A-ElCnmXzb zBX_cIZF89gh_PLa3QVSEy^rL`N4m)J{T2%)QB5{LSmli}mOzR|WnZ}W&ca1=D3tFS z63m`f(;c>Po%y0b~2y>I>1 z`cD%})T#;h1zFWCp;v`>PGDRJkqrU7g~(0@>mV$k3+B3r%j-1p#=@ zL4aK)2%Xt5#2?_SeO)cb2MqW1I;jQk^q393yk5oaoRfdx zkD%TgTFL~+F6mamLWB%&#}R=3-H^Tz$0STZTi*ASiOh`*8*l_lyzS}8sMt@>V5Poco8{|23k?} z&#wrVc5xMWT15)RwlbEcpSz3^IXb%cjeS0pSt+QW-g$JQHUUh))k`(YCjkLmjASN~ zDM_J;vU3Vsbj+$Y$dMob>y9#j@|Mf%a#NJT&(1$6DtuynCHF@H&N3zH<^Asl4T<(< zLI9E|+^1ex4w1V{0{qf-KmbiO!ZCin;?Wph0w!}KHB;q>()g36!Uh97#88l^-lZX9 z{g?D%Mq|&q@J)bos3^fhWq=OIyBZw24m~Tbp1V4ywW+E1ebS&VffPClTn(Gayu$op ze&UC_QQaz>iIIj4whbDK=yYt^W(W@b1%&c#wlsYa9dGB*)jQRCNJpRv@a`^#cHOnA z>P&kOJC41Xk2g6FjU{jBkSoBVrQA&v8`+HU4ofQ5)CyZ_nGS#=PwQ}#p}R-U+i9a znQW<7-P&n#kC&hf*TBFPn6$fiDR)lfa8#IwEPPH!SXPPKe~}?)*d{D!TpqoS@-v6N@Z{viaH# zld@?Mgs*-({OWO|9zZYcJXUNV!ebwT><(%)L)CY-9}Du zC7$p!iGdP3Wb7t{U1Yi(39ZNEjq^s#GB?mJEMTFBQ^SCq_L$6%7ildkrF~ye@*PiW z3&Rb^0l6;T#fN_a8wG`g`2JsSf~u;@ofQpZOuhQdQpchb*JI)t2@}eo3Y?{Cv`X@E zLIiL#3aVct`&b>UU52K2UZ)$@>vQI_tneG|XL#l_cOU&694k+CH!uOuZny!iPyCI) z+JpWjpl=j`x|ktO<-f0wu~+<=-&r)DVM9~mH0&_tb6CYtIbv8nlx8@WsQ8bIoAR)1 zYphF5eSRkVi}U$k3p_UF*y5sRi7N#kf3iI(G~9btvOp?;A6PV1?_+L_@WAaqZ&Gbf zyP?pK`s~#F%fP?lS5w!bLc@Rriemrf zuDEAWFT4h(K^xsv6f-dZ9pls(vUnV~4DPxmzAAl2;L=1F-&ZZK!gVfOL&$MuG*6d#^p5x1=2i#phu6p4+5 zOpr#%T&@(-_6ef&nz=Sm9fjdlF~P}ILc(-QUiyC}EpSbbci?(My!qpnK#VbnUf`O9cg zM4twG$gX0Gr0e-NV+PoAG;{fsTluu8J|g3}dsY3X(Oyz;@jxLlT}82_RlB7RR7rv* zlaKAZ0f7!B$hW>}#Sxq7eH`68{i-pPkaN+A+H)^I>Cw%tOd^gdY0NW+$%~9^syLa$ zYT-Ec6P`dGQ(aGiEb+3!_abOLia440c9mS*eHkI1$7z2Ao{->3c>#hN{4lAkNre}^ zIS#0(*+J(*Gul!IPF|d4lYiRU6+T;f{}Um*B$zo8LIlYObn^P6IzNnsH8T4RcGVNr zU-EJFpS3{R_+DC)?@y~lzpXvR=iDFYoN&5shv;hQTm}X zS)KH3{b8t+zl*4OA9cx;Jk_^_nlifbvBo)>a>4JN)!GKuBf$#@)8o$|Wdi?@S`PUS zoN>s(6iKV~0hbd;-C5VUEw+{q zVTM$-Y46yB87>TI9QZ4=cZh+Lbjr9?GZn?S`_?$=#r>|59T9jTT5RIr+}POI8HEm# zH!7dhP4zEIz%g?1Kf4ldyJm|{08+$Bvy1ARt`&3sy6pZfmjb^pdv<)6TOU?68BF#U;)=|T+w zxb{J>hsGO)e;AtwbZERq-E;{H9g+u)I?}*|V42vGY&v$?RNFHTYJTyT)78G_zM`}j zYuvE+ZL5XhUm@p6tZRdpPmlaugL_@3f_Px~=53Q!N|r(iBL3f}R+Z|_Z;cRO&&$jG zHpu=>XVZ>9cg`~rk?R+;yo(zvurj)q9c!J-Hj!vw>Xv}1!Zz^>X+TO+0%!ZSeak{w zLUZ9Fu-YN5u6*Hw@g{2-r4CI0Dzkv(QE)8Y@G&q zVi}EYy8}J4)^c1|?lztF{e)^ddku`lx-B-wNJI6|x1ldrll(_M z6Tr`Wfl}F#apf4@|5eDLNF?KZRFl~q4h`{n6eXha3iqX37uTniAp+-&h?w-Cz+}_( zZFeH|v$HeL$t2QZ)FMnxRGq)oUXYU}6x?>FK&X9b5)1@sb>^2t5{G)-{$pQm8FDlk z!jZeK@nm6!q5?9@xjhSuNw9mr2ej(DFz$58LP|zzpEs0MI!(eYjy!5(9|(^TkVFTV#T8P2J@0PUcDG@A zpMm|{$7@mmBxb@qwER|t<2Yh%v`yb7kYVK=0Dd;@os$e^Z=GKyzPj1c@7?n>DAgpo z?7}f>UvxSzs8Ur~vF#FW{W5V|W!!;eiaDmc-o$3mGlevLV#h-kUm8*gf%pWohKPLN z%q!vqxn76Tk`0e6E}CQH3a&#m&?89BOFv^a32`FVjW{E|!kAlTz+WxOeNK^Lo(Kft z06r*kAP{Kb(>&)}?fUixV$iig!`g_ksLQa8li=m1UNlt}F&sCvazSli$ff_*?p?Lw z>m$ymPeeqdOWER!@Vc81!J^CRbP?~OMB#urfdP$3E`<)Y^XXmG2N;j09^Z^({69Py z-cns2?=NIQ_Zk>G6S`ur=5R^?} z(Xi+=Q3D1vFwnDHXKd2GFzOrSi#7lip^cT3tOIj6eB`E&CvFx(kN)WR+DW&7hwG1d zAYhaDYI{ueXc#F(A%KupWW&6yk3Knkra??oi$ES&+;Y9~1%ptT3-!}EK zEj)aBUZq%-j04mEfp#Wr^VmD@*x$rCm~RI5(;<@bvHhW#WVVVF%`kZs+U0mN3ru}K zfT-$faYV%h>+Tu@J+ly>>4 z1*cl;%74^mQV|kbgT?h&nt(MdhAvsL;lQP=+>bNCg8tpvETE);8V*RPOZqTIHav~I z7K-xYXXzT8rH(414al^t_vJYQ`%6pB9DbbzQ2(w& zBP?@*N~Q-Q_K2~p8*XVJJ*4hE%6WWBodAgbnY`=SCRR3O6l~9BC%0l`-|b8IHdeSivYJ{&EmFSmI`=G-{kDjrhHE)YoMQ^yk1) z8(AfrK0$mwPRI3AxKN$Y$*@T%J|MsMej0^JZP-*`&?!>#Xp7m$dZoFuO-GGy@=)e4 zSPEK=0DuJuDOU-owWnoqUoXyl{W)k12*L&>ZtT?2d#9F&c8J1^WqC_yy$V^ z1XA2+`KW>XI5^Ka#Xk~sF$~B`hAbfg566yF^%Gg2H&})w`L~k3*2G0@jb}%M%wm=i zbe`$e-N}TMOz*4T1L^m8(VZsTxr&FA4?nvlW|P--K^b?@AgY`2{!UK<_ex?zwMzuNQ|0PF1N1qKG(&P zfiVhYW7(QHF^n%LSxWvM@A&41vXV1Wh~+?FgY$9W%*hULK@#JQRB zGc)N9)M!Fy5;jv%EtNk=?wS*avgNEjWgsz#9D|BPfEP@a!hsi zZRWSz<64H;EWz>VR+6P@M=hb!MPur&^M%XRYBOWf zSc*#+g7UJalk8{XUhRlaq4GpIY%n#Hwlu@;W6DG}6OhD0jv%*?JoZoY1D4ybv!BB$ z>h)ud=wfhMD8^EC`X>(*`nXB#UN6s7;EUib!`i^3_}O-$z7S^@^Q% z;|J%?FP_mvkZmhOn3v4&1@BfaO)=}dP&f27vwtKb(qVo<7>9V4xrS{6t}*v|HgHpb z7VMpemHj>jGOA&Q*7k2Xr;M_(R9P0PE#5Qw<5)lB1rju#OB`{P z$4#cREEd0rbE7y))f!=(rV)bfN4-|fU)N7!rpxL>hrQf@*@Z;guKDd7 zpi%*1)A?=I-GmeVYFilR%V(3fLm65oNM*;(G;xgupPJ_EsGUW$xb77_@3VdHqBiiC za$VZSsl(RmZ9Ky6$v|%r;*5Hzo;qpYZJ?66CdW+B=wBa<+ecb#q=%B;^HoNT?C^Q) zSG0OpmBq$MJkeX2`|$caS^ZUInJ-;8`(D)()F0-WJ*-6(^}r)LBlkiU<_L z7nHqgXG17Xj>e_>`Ll%4$KO_aq66+p&hH60WZ9FW`|pSIXDL5*t#}Ja>Q$%vd*Zv# zvsEIDQh?GlXx7(SEe3%;Jo)@o4l&?SfFoZjI#CZ&nyW{lxauzD1RI#;6 zKY%O9B&0pS+a=f-?e-l6EjOou;>QU~L$lYvHo{eU>%SKMo$WlDGxd#a)oB&i(;fWz zhiuR@7lK#0k2DG2FmZ@0+HfGW`i|TGBQUU_IUJn_xz6fg(Erw|o*E{ShbUoVxj6XM zGHem#d&OO`8?omtPJGY(^sGn?lg8huGr`*V2eMBy)WN5%xUZat#ObQvB`t!E$5bM+9?vsjgYFx(3f* zuRI{Jj^Xy}{YLe&Ap+AU2V6O%w9XyN#X7%c834m`QCoOYarw_Ggc3;!yep36yvG zX|^+cvpF467qAAsdYzFUKUu>lI;{Y1=qS<_gj!bkxUOAiOEyJKa&@({>K^@K=+vf; zI07-_)Yy1b*IXGdS73416L@!n@9Q9vZ3H7xeRQUz`|Al*ah?DD(+vAgnak>6 zgMPvO+8lf9m--?Kd`<5R%+Te7IoFDYBk>==_{S6PW$zZFGN|!&MFx>6zvHi>x-o|n zJzFV}zK7VqGl#6s*duRnI_pACWxEwL*-|`-T}{-7tZFTe{~p>`{|4^5N8h1l=lkC3 z325AB#hB@U0sc_JhCTYkZ||)8J55~n`nKL>?ulYX3#v|$jQlRUUa%O ztIT*&zMBp+QHV!e5-yoxdLhcRt7a%ZSThdR`CJ;>k z{N@~EGoQ2O%Nrq!!7!2Wk?e|QS zPgP#b%zRbEoIP3t$fyv~jNRof4$CJS4Q@Ro-GHeeIdOyg+57d&TdKp40&YqNj|}{nL*~^wpy&*u&U{&`#fVop>}wr*9Ns*@YE??%SLk=HNLV z*i8DfIi9}UQ68~z9_k0?7+L6AWguy4EuvbRbg_ueO+m&;@;>U31xyI4Sn;M0lqcLW zb6E2`Jz<(gEPwAp`De7dPHd-cMMLs*Hcqp{DCo9hoLH^W0y3WX1yY+uN51|Fqm8&q zf9I^{Lr3JY)s44ves!+DcgGakTgIZ;vZw-DKMVkHPX~edt7x&2?wI#t;L1rmM}aKb zve%0GS09Kxx>wAPf*)7iB>%$I2o%XypDU_n8Cd`8C(&`H!Neu@Yi;diEQ|5=#_{nn zx=YgFD;Is+K~$3|Nv{om7i2&+A2OY?(`UdN{IxiY&aja8V%U`fx@zA{Kfcz6!v;6R+Uiu;@RhLu{I5!NKhYt5NX)oWEa%`dgo zq}4ZvKh-TnHqoE^x$A1m|8aEP zfl&T`9N8lo*`s794rlLVZ`qE>$c{UEXK&eOZ$gg9ID7l%TvqldbZ75bqTkc+Uw?V- z`8@B>`~6z)mqKS_i!IrMjfV+Dh&5rLj9BMeH>e3U#BT5Gkc`9Cdx8-!qfN=HO8QM2 zw}G)APb(AEL_Vn=Y@OCOz`UDD@vZEt#lG$7PzWH5^=Q+oNhhxo4rK}3SklXFBp<}V zn_>7wr0}@Ix*;+ty~7gK6mF5(6XbUB`**_G;ax%wwnN1kA=msleT4q&4g(t&Zb>M{ zO*{@?_8V83Q^*~vMy`!_5+;7}Mr-VjG&XgtKzg57dHA!m(XFn3a|V62L`y}rUv*eH z%jk?SYOi2^D~ozmd1CmW&z7_8yCoJf_wcvxW)-Axq)EY7J*m(J`Vz<|m#jVC!BoW0 z=uRMt>M{IxWPiA|o;62$u1N938Q#=RBK{5T2b$E^fdK*UoN3Lt?}vFyvT(~c97mE5 z_G#;cF-*)rkpP01$uGPS4cHZnC!Z&7wyTya#bf)HuI5#uXdAByjV8)hr< z`c>R%=#L&tru++|HIW<(fsNlPBdG)l6(yMU+J`l%!3~0%BPq2FRZu}u-?3-a#~QFT zg-i?G`n}IYf-)zbsW~gjzIugK%9sm*MmHr9!p-FQ))HEow}(;tNYA{pyWI1vGyOx^ z1_;uzE$FK~mb8rCD!_WMpP80VftW1!l2LQ4^qY&=La_ubpWn;?N{qbx`_T;V!QJ^e zEmbrA5RHoPiAfB=BJ*cyN_+#mfSIO_6Xb(uXa7D{<@^8SVi-?OzUj_oH$ue__Q}kq zxANa-{EDr&_z~V_j2BqnJxBS)SSdIk-S^-Gf}E!1ixm-{&EqcEfoBYeVxw+1c!C&V zH@4ZYc>RD%y&^2}7YmmuK~jmbUc4!vf)bW2Z(Gor7L;`)w#dNSyVI6!yAv6a``@%u zHvJne!X3UV429&dLuu?W^*wqgsL)T^jR-day#$=28%I>WVxe?c$U}zOhJ<2$Jc6=wm5u&lgNccWGTyaC-zWkRw$vR0D;xxY67e~zm?ueL z$47T3<|-;jm#GxXB?z;!O1Eo@f&PF4c2QAH^TTP#2Ro0D4m-hcES?DV(&_6x>C~N( zGclezW*%1*noCz2DpmB9=x=;jb9ZQ!XViy0;R3g{x-l)jMmo(0qgI&`JUv~-#k{7q zi}eUm%l15MZ@(+$4>9{?@vk9)m8DnbfNRK*k|j(+LA6HH*w{=BY-n(IbJRQKM9X>- zmjhH@r)zwv6jbOg3mdy=!J1$C=&0Jq@|(Ix=$~8-mTg$Jm{LHf(ZsSPEV3fq# zLXVjuV-C3bDGKnZ$qDaiN(A$Me01u3!YxmM>9EU1bhajEb7xEJ@s6%MMyq5tk(VJS zNAMxkDaa#mn+j4dFFz&b?2B8=PcEgIi{L4TSBL}2v5|sj-&EBC8j7gg7}>Y`yqZkU zD%=Wovz{6s1TOD1e+~Y{Xz?qunl5E(_%&{Rv9FI42lZn@Wm+PMq!0MLhuEbo=RA;+ z%~!5F3jiCsXX(*x&7PdM?b{hoUvqPFb>uJmHMFtv$^liqW6vJ;)R5=$4rH$vO51CC z@P2xWoBG-N+a2%PMsZ-Ys8o$zFa%EdMsAFm$jnZrVPu!`dV@`H?JU0r&iHF`GX(pS z)s{C^bKizuccrXT4eLb=3J6WW$#@+YP5ut4Ar~bw&k$ccL9EGJGg*Ca!4H{(?tnG5 zr@c+N&6RV9Z#8{>1$}eisDYJzk5T+p8$eBuNieRPZe(@`2E>t2cq*T6)vKPx)kxLfqN83%M@N|+GWyq+(a&)e zV`uZ!tgs!~>UgV@`uzDm_9q#Nd6rR9*!xZ%bklZ+;n-|k*1;J1Cf3i_>3+79Wt`us^Ub9^YztP1#|}-TKpn~-*zw12LGFeg( z{3QImNdT}bTCoP|{k{4A*E1autt`4_-}WK%XY54+f`ZCVvX~pR4KgK*n>3K$?7R8l zqMY*l(ZXFX8hrq-Zg=f{kW%%`PNDH@S=yMitzSc^o&EbyP)&Z~Nt`ZeYb9xOoZtce z7X}quhU7FglLYcsf;j;n)e){Fmmh4H?^y}5IgUruE09zof26D{fpg;QJnkqlfik?K z!D_(J*B&E3Ss#6&y82T?Vll_nqV*#jrn`5ac0$9nV^Ts*(&NlxIvgr&1p>UtPw9o7~mgkWLKzvi3{yz z7gfbO`V5SvL6ksA9e7cQc04CK<>)T}=HB=#rv=hF$8PKIApvIlB>wY8u_t#u+_psT z9dg%7)^lP9A5$DZMhhz?W**9FFO&nleqS&7AaLcbXyokii&(vJ-_bGVy|=B)@4&}a zw!-1dhdK)!Cx|gWl)=h7do=06elksPqh<{kdCk0}W*n^i<*FP`BG%Xga=mRj+M50t zN=IV*yh5`f8mYct0@gEqI_Ew!vo`GDtV=3InZK9W9C$I13&^#lYhbZFJ3wbTez)Vz zuVEOPZq3Wkmnpf?`}c0pHQ|V!1|M*Ra_VM={k>yNRy7(uhOR&B6VaBP^sdvaq@Ga@ zoQVjSXcFjlVOu!I8TP}b_0y4ZmP$CmgA{F;V5#2XxUZ`-q}zD@7=Wyr7Xc`!Z@uyI zDH1xBakvC~Nif-cM6VFarR>ndgjq`DSaP~?S+;j2cmuO zH$`t#%U*z{G;{;Yr_2QCehCM*f;<|P$1ozvNyzWLVS3yd*S5}m$^AC({clPC*z|s% zxF*Mq=@W?Zg6}uKCHQzpV*Yaor7c9v!u<7CNf^84EnRuVg&Rp|QDGlwYf{bbhJ1LL z4R`_4sFhhpZ=<-fpT2}bOkw+Jh;I^qa^IhUVvgI$-7&zML#AGs@kbSU>gsi7GEGWk z4pnLB4JYt*_3f(Vj-(>~nhUd*tmF+~dBb4+!a@G&2FVc-5qN*1uAp=|gLc%Z#t0}L zfZD>ur00X)LlWZw5ci!|z7YptLG5|?hJnx{X5@|ULQr0nLqOmUqq3oIl%ef>AJGB| zp@!+4H5T>LPbZ_|y~Dnz*qa|--JCyQh>QUo%aiKNUQAXZn`D-BsttxU=YicAXs(-3 z3+ceX7r`S&LV;;ttb&ztmxFAhf;y!F#I4uR)FOUATKQG4eZfD`de#lG9 zJlorXN_sZCSIW(uj#|CCdf+iN80au8fx7;!|zTo@0yc zY@SKC!@E@rtIpMCnIts1o9{k>A=FjqvF^<668C&)U;e}R$;jJWizB3B+Ago8hI#fw zd|aNL!eON;nmM{ruZzG!)uH|6W#%x6uf}3Ir z1Ax(7*&oHAs;P4S#21uw^+xo)_{#Z;CHdea%4=le^#nUP;erGrlsc`*8%Ru1PN)|` zG3z3N(hoXtIVckbbW*2_J&s8bCvy@H)b zmg4B~nsq+%m;nWhWUQkrf@li0$f-Dj$!A#6&~8J37s{qrM^dbFEvC5Ur66Q#9iK8= znz(66!SDUPT`#+=xiD*zX=aZN2?ncS(IDCXR#7(|CZ>GQ6e-Q^se z)T5asG=a2O=&%&FUVDyIk$wmW3)5R^)Q+VAWrDp3^75r2J(f8p zt;p_v5X$QQ6Q##Y@?K3mc9TxbrU_;G6m)VL716kt1&+-m>6n1KuND?R$4XWx=RFJK zdz^V)@w`to&0`$LXRk!C&z%LCFdQ;5qkIm(D3KiP2x{0L;lZ+#awJ_z>7Ks&?k5hxGY%M zX~EWz0c^O^WLN`Pm1}!?dVS!VU*TgHiZ#9litWuw=>lCif&)fWDL^TLy~Y`Z_}^wY z}6rL4PF z^7@Dk&n9R0rKE#a-||Hug;rz?3DIYTP9A!O4Apw06>3MkP}!3-?H4u+p}l%L8N_pV z`x-@C|9}w{momdKIehN-OaD-?C`^Z-uev7V8-~w7U`4Om7cM>A62Mb(-hnOTfl|vU zD45n6?$|wdO-@rXc%3DCN9mvSyah za;fjBTeqoI~sI0vYHk_Lb1kzTOw~#2C`Tpl4zt&t@RLj#I z5$7hiXqopBDbi2``v(U{t#Tx61iUI0)5+K7j+dz7v4x(K?pg7c(Cw@h?Z13m%=&>B zb=p##-l5+6ToW8SJiT`T`UE_m##o)OBLi^p0i)v)q2dqk9?tiUPvN^@>bF9)8he6t ziDuY^?~POr;;|C*^(ZK7|F@f3v#j>^N`ZNUN&)6H*1;!E2xe{Ar=W4x81tC&m2EQ2 zh#UL-&%M0ln7UuubpBSx&l*Ati`2dI{ zY2?wJE@nA-zETqoVG^ed^_68SF64R6#5lOG@n-~RH$;}N7-y)7wRh}@*G{?K{)`#& zVp(`MO^2Tc{QiDe3=!^ne53F*0B(d$;lA^duDFzZq{dXbq!Isf23JbhRO1)ME%eox zPbc)2+q3 z_LX8gNsQ(ojj56f*wsNm9yhr&n<&+rpz?w|o~EZ#Ry~n=q0rw>L94Gj11^!MEF(fY z()5Oj3uMF_)fiFtN-+4_EVxyD)v11|>3REOX65y#Ym%Ds|IhI8ST=U{H_eNM2h3*G zee8km%CD@g0a;fb)z>QLgt9p2_hMHpRD6LNwLZ2q*7YU{F35GBH8}z^Cp_PFaeKOG4U)+adlYV+sEvc1jeO&*{q_OB5a_B0pQZb55Pj zty-N;LXd))rY_%FZ4Usd)~#bJE*#Xj>os>3CFDaF21%kzO?a@g6K`!5!jP=6KF)MM7XB{tl6{|ZSFkslDflR*lSVe!yveWf6~8) zd7p&5mv`f)4I+PzWB_J3-m8EMMo6=~=o_LHe@;PqW&}KI#|=CJfEVG)+zGyL`76i})~$(F3u3G;p8(r_RkQ zDqu zR}Ssa)w&f*)7GRfJd@8-qs_lQk&cO_Q;-7w-Bn@wIbm6H%);$&9yRAfnXwQ&*2p@E zBT*INw>Gkf zNu5LM;PB!=iS1tb&&i>?)R#Xj0&Ew)d@8o%`QrZ{7nM}JW~E`)d@+w_j`>w=UU1w%Ly>1@hB|^>qJ(=c`7Wvq@s{5{ny^7-7X=38@mK;^+!J`l59n z&$OX!U$kyr|J2H-qs(6nq(fttLu3mqki(k22dhPqX!N$Ga ztDDTz=7ix5Z)u$|=sj~lt89Oi5qxiy*nStYQE4+a^&br6Zj$J2D+g>;x;WHEcSMfd;Ky5=gTf5b!hb7{Q+`Ao3<3ykPX0 zeAO(V!1N_Cnw!|snox9J@8Q=+IIDr(Ri=J&=2S1)u|#gn1$S3|Ndr~X`0osp^MC+= zhEn3JED6h7f+5`Uu4pjx!0RY~1#Yj1w} zH70F;ngOiIz7pO?J_yOdsvj$4n_Wi!jc?_{NmjL!FJ5jfEJX9q`(Uo;8KEI1G}^3+ z^AECH+^1KpM~}^fv!~>++$87l{1?Ex(J~M98)rqq6BUtqC3`-%b)y%7Hqy4T*^bQ= zqquwI=Bcn5We2ABdTh#G%wT*wo5EzJ!VySw=-VDYW zKSGIgD-8+(%wJuD81ULFZmZ{h$nf0 zudw-SlLSL%b60i(zz7js3fcS22IKJ~Pc1<{VT47R0Z=3OiUI?Cj-l2o^DVoV*LR9} z+TlLZ+Qe3V+B0=g&NmOcVC^WMBaV0WIMNJ%+Nk%Q_oQrW6D4qOzwIbHrn8yu?dh4e z+5P8v?>f$=>9RF8{x_RsAkXL97o&ayF!yul`8=_^rs3 z`&*xCwe({;sX z;-qAI3adYWd#b#@Xz11Z!ndn^56s}e&mFJ8XV7ik+uOLV{LV~+9H-KDNM@k8T@;r0 zGjr;A{w)y&PF9-IllZ~Bs#Q%ZS`H|6mL}KAA`_n%}sNiTsv_q1g6iv3RfL#>IqT4vKq(4A03| z?TLtbV}z@xG#FVw_upskaux{}CH*&(C0V5}sx4#Ve;L6I90zWyEFQMiE$s@Om z#TC(KC~6g|#(1fF`W;yrao)`RmMA0EYDmqO-=6QFAIo1+zx}lyv`suo;n1_*xs_gm ze9POmEG#QMBGPJiSn~hIpEYy28X2H(7Xfe;&(H_Z6~VEz#J7IONJVS_pwiW z#Ai%hUuGA|(u&T9kPtn1NA{jdcN*wE@`?Q(e-f0u;>q}eZt>+3M)bX5Ql|Je5L97r zfddOqh!3)~L9QE*H5FV_6hBU4b`#b7O4a2hAe`+0w8+j*Ef!P9KjnkP@PJNpK6L13 zv{IcBf99V7hPElEOr73i@!j-I$>S-2CDkc-vCygR_w843QK8uhq=uwgzzN}8cRfL- z2e}#~m^|qqEpa_b9FcAsU9lZK{x1o6l!Ek9w2OFem>oHpge)1s2Ot+BUi$CCe&Ntn zV|;W=SK@ahKI95q?7DE2!EY*$r{=6BPZSwRwH@)P~~xqNmE<0Y5aFiTrIH2 z4QJXVe&)u#lL~*Oj4wZz^favevl53R4F8Dt{{;r>aXC$|qn~68ZsMJnPgF^m>EUr( z0sFfx7C`UEcf*HM@tnTZd)k*Xzp)^(sL#tdXs|z~Ltr7DSdoWuNztMW*IRA3_=OMG z!jZ6_?6}CJ@Muh|`F&q!kA_i*w-^e3p%=jlE4&A^vPljg^hteoc-^lfYD@Q;nU{ph z?$V;|SzH>ewd-OXbGl%xP5>zsvy|YixaTds+=ogEdo+AN)#=f^xH2S6YDw@}rRJTC zHDLPA;f$X~XYfaZNe|b*+P-lty^X4JhU)^>U2$~rL220cze zer-!ahNU1cd!N3?`WhUbxoFj=d^;TL>kw?-q5QV4UW`tjT}roCLzN4|R%_MU$pk(D zIxE4FoXhkQn@U*)g=T?#|5Zw+4N1hJ+jQgHaXtWq7`e92>^&lkq<9M=>(8zrC+Mc; z1xD(vU;myo%?+YSCn?S)z_D-eZ;*{XAS2dxo&;6C>uVEnVj$hOtN0@6JeC{6!&=4V zYtz-APj)xq6Azxxl~kRWJ1&mz^6CB5zEzsf`#R^<=Zz@{PuHCWd8Uk%ognA9$fFVH zDJ3Q)%6#N2oU9yKn1l?;bUi9tQOI)*wl*x^dG!oAd-*A4R@E*shW8O@ z4b{Sa4z|_yoKUPVsf*SrGBi>)+!9I$b-*yz0pXm->GW;=PG@ z7@HAO{)d`AkB?K-=LrK-aSREc&AGG;9sLEO{upuvhQ2<_(UN_{rG^tq=j%*|r|C>K zXx1>#$GDc7nhJt9zr+`#vYj`itpsoxU;^&_y`dAP(N}195S~?3TXczNFxKY|Rv`69S3pr% z!t(MIWcY6$TRAMAfneF42F_T0PdUJ|9lRMQD1$Jd*Ihn~qc5vw4VJB1W@Z9I3R#&l za$A17DS3<6=74ie^}l4fOQqN`5RzB_3SRSQYi2o#U=9ijx)CQU=i} zoII?$dj@$UmiTh)^c?so!4hlL$dJ*MZI(^Y^t?M)hl(R`c5FcH(lM#3Pc&zz zG^}m`<;ukyZ6yKJ^oML^d@cDW5A|tiYw#@UP53C7tchAnEE~#FTgsi8*6utdS4ONI z4>&oD1-*jI_5->wlv9&aN-!=h>rRuVn@;*jcS|xArejEcKI=4uhhtpCj5D_T4pkA>HlTakv?^aRKgHhQ)=s*r>m>A5oC)|pVCsrw$LHCox1#s` zeJfunDahat)F_FZcJCsf4X>nI@E2PMus81!IP4nf+ga+G=KeSE zd*xG3%t5(gRZo(K&+t3g%aC^BAJKJu$*fkLA2Y5?gG-tN+(oHPSSh!k?-uW8HT_w$ z6ZE*vI0?0jc#?wrZv;P04m;o^SZ3vKW*6bBJ_314h;E56K(KAVZ#LRP^6I{c;aJtz zNLWZWB4%foNbpLd-_RLJ)YKE;um3hH19qOEy)ccKQ0yd#<>JPb`tqJYY ztxNAj!MWPJ1V!(t0AzsSu~^`6v%X8nnwxmTf-@cu_Z_$j-0dc0R+O8UeU2}aZTN`A zm-*2|As0I2`tSzGt6ZxVc6xBhZZ&^I@=jx)OSjC;5%)bJF0%ho%aI!r!MoNH*m~)v z>27Hy#hvWnxR71q&Q1OOmCyh)P1FTkW?Hz5-Q+JP3r6)FFMYM0Kke8*(pxt#u>x6= zg#7O}k0JipY)=5DtL`)zD_c_ct>={wYw-LogVo4>GuG*~&eml_vuW3pxKQn?-Q5v2 zYaY>gV}dFg6{^;d>X~=Bd4(?sH}LzDr@lT(e1a2Eyu^lU(yWcJa|whOWp$Y zC&!v>^^P)ix;`f`-VCmVa17(g%%^_|XVg-cxPnc}A(um*UxSp=DFjoJs|=C)>x0+l#BoVxLtIhl}wU*=Oz1GE3kF?#vRy`tY`$~-2!X+K5=o6g zt`&*khp>$qfNVriF*xp&LvEQzqiqV+U|Aj3?%NmHz}HfrGIf}@+Ox=Rv02mogT>lY z!A|7t(E+4}bO=BibPZEBZ5qCyAP9Ch^UwB^kYU5B)-?ai6%!n3w1{Z}7>itkE>S?o4~&~- zEA6fcz-_TmC9vPPu-|h&U^g?F@38=V+=>u$B#CYBO zB|nA$-RFg3^tTsHIO-E8b*46VXIpvz>T6+(fW&M09#nM)NMIuP#6Bj!_x3_rt>-)& zr89E)Y%Q|#F^IvDu@ksD_)vW#_>n+&p9c2ZhRYa^osy42@X@Tm?nGS7tv&eLro2OyLJd^sP@e7PqAt9-08gFTZ&mczGN*7{phmI_3_sChh-S~v6 z@JsTgtk>kb6}B9BWiCf10g3`ams7U#&Q36t4+Zo^;RyUu=R*MN_`6$-FNIwiO)Td8 z3BSQ+B@#Ev24=PX)#v)_hO=EuF_`)VY-yFc&+r{a)P6($9~f4GQqfzE%UN_IEa=w= z%(9~$QtD{8c6iXZ7;&H1+^M3em^Wc3>}VMF&d^zsMMG}d)j?+9_=#0~M#zVHres38 z;Z@6Tk4&0=@=@3U@n8S}w!*?0_)oKtY%>{Zvpd(iB?(7ZHz>%0FmDr|s5*Cxle4VcEqZdgl*rsc?}NntMmZmWMoz(bWN)<}EDK9WZNQgH zkq<^!7+DAJIUQyiW-7^*DXKnFz~Sw_^LAdy&0(XdW_0IESXY z-*&m;+q9u(XAuB)6l5CENO(dXL;6cP586(4-$Q@G2BhBGUg=<-&S_j{tmz~FeQk{) z25CY~$J?aOJLx&mzk(O?iYrCeAQRC0)tvJ>hIXzJj;(g9BqQGq>jDD6Kf9`+uSetw z?=1WU10&}EUZ?vg^iV~82Ar}9x^K3*Q;qXuVjTmBB4y6_ww8d_uNG+ijGx0EzGO3a z>Vf2$Y2|VkT}R%%UXn@00(~6-$lWGMU9zL2fg8n@9uTQuV~6$bI}7sL36|OU>%$!i z5cnqp0_9GED^LCK_cSdt>)6T)s6yTySy;J(&RKlR@T($mcVl1w_JS+;%}-=?c}Bh4 zu|WW1OLcK?crO{5sKeRY=EX_a_&Ym zVDEZn!akfwJ8Q(B#{*)GISC3pC)z}nz)02Ik(I@gLVnpE=e)$>GV6v{T-BY+2X~%T zJ#W{$BUTwKgYKbosqdQI-Ng~gHSL%-h1-WdUo`MK3xv-!9-)W*#y?T<(rdtYz9}ra zYCKqSJZ!f+ltD*(llO*WUjw7tj*jPwgz1vc_$=`3={v!(R`t%}OLUEh}#y1?oS4;bwR)oiTM)^BnlVm&ivseU3(Xx`df_iPLe?y&H?VThMR@3sOoANODDc*^mLVPZQH09)(qTt>I`MC*Z!X#AUI zM!BB8iPxLmqHnPQ1D|ncHPgXN$)180jnaI$@dP|~rGDTq2BN)(vPui!HxO0YZQ zKV9R7=#Su!j-$I52kQ&D&kDqjG@I&N*d29!k<<@#4b%6(JArLhs^(k@z#lZ5E093? z2&-nuRi8{FX}V_rBQ#or*G;N5914#dDyneC^P3@H4#b#=PeO4_bO|UAM=>rAtL816u z`oVFZ8ga4WKJ1 zWGskk&paEN5 z3x^djzFouo<{(ezi#X@m7M2o^@`DH_8NVf3vW-FA(31ozMIW;xe{rgg0Gds~aBR%f zKh}c2ITK?r%0h22Cc-^7yw6}Qv&~?gOyd|(u(=_PjgUNyQxGKHxbs?(C~-Br$fl3o zk=p0}8Uf?_wb`@Oiq$l4w8rsHDC^@73JKBaSB}m2eQ==jAc|H#A^mkxy-8wvPV6^T ztwz!)-UJW`*w3T2=`k@Wo&rv*P82dUdT+Qv%^lFWiVcv*#A?23G{PM|ce)R=12b9O z@MX}_iSWI9Za2i%L(FkIiP=YKiJiW?Po_{9*Sf|;Olf#?f=DfaP^H?s=AVxXP2*|EIz>+ofvQ0g2k2Qv-+kQv*K zF#SVEbFwNV+AnXpE{vL|PsBtFWym`Tv_rUxSE>88CiQ^0DxX!VIr?T1+xOp7TdcI+ zf=k@3cEjNi!qW^`%%wJefr0+IyVLzr@{E?WqC|j9Wp=#cQd3=t+GaQx)EfiAHk5^D{|6xn$I&9A;-g`GdOJ9exzEt`kHEN|2q zaq1KB*DcG%q~3v2^)SIt1K-j5p6L7z2g%MqQ(8`CJ@ER-6yI~kUn=*5fUPO#5Wt;H zrkD0#wN;WrD5)cPrDgXEfUSlUVCmgJk~I^`n_f8aHt&lkW#GYOUz`Pdv}cCch_PkB z;SKn{%P=5cUh5+LnACqt0L7mGJ&66PV$kF&QIGEYr2%^z^Q}od!SxlvHp_R7YNuVz zpK512eMB9F8$A1MY_QG$*kJ2mdV|0AZJC(Y#aLZ5{6-BxJKNYD8JFOX+V3Q-vD}_ zO!=>Nfj|datbZHcE(Og?&JgHSov#XsZM$mChhdDRN96-5q9aLS;Hz+a_C;KQ3GKQar#l62cQt zdnN=l+@$&s`U_&dL@B&DQc{naZTV~~x8g0-2ukuNwu~&f6EB5+n=Gzwl)ctx$`2tOX_alb;{7<=;7C; zdx0E&iQoGhY_)k;5286LyJpBK2RrXAO!qw)mm5D|KNVw}Tykmo_wvlMg(r5R^DXGy*mjQ_BAH1H3_0$78qrV_YC7)YBgM|1x92V3V@W(L8fVnEMc(xF{T~Bq=C4-b7i zeKeybgy{E|fymZHH|l@|CnO@#;J{ltlL0>xBAD~?zs2zgle&l25M7vX^!h-R(u6{a zPAb^4_cC%VrZE{9+Lp>p??(rl{vknYhBg5z3c^;Cx^HxCi-C{cEkc8Q(;CLp`u0Q(iaJ^ajo z@=rl_1IqAaxi_+~`L0p#?5xgRs0!JoD&Xa0^1?3<6v@@^2=gRDHJ!7-hF^PunYgn4 zJRke7dQtq!sJ|y#CrkISe1U5RV&*B8-hbz@-{gKsBBq>vg6Y*Ngt=yyuFYPU?F7Ib zv;$ODZ_B{vU6mzLEHp;tFQ5)DL`OfEj|rl?nGGkF;PX|;`mW{)(A=Lu>HPg^h&~@m zJ(H{q`ODTWqT4XL`(CC@1@bK;3@Dvy%rq~6GdR6cYAP6k{dy>THNoW<*l_%8DC-3_&{gXw)v5VOrK^9}L@B}h}NkNKx# z!pVDC%8L)ZrWva~ExP&J%H`{+ZLV97Kx9WDW=RfasYuW$WD6J@L1V+-nFVGNCRSbSdk{<@yKZgg}M5X3%bRcDyBc@K;lJ4$Qczn}b0 z*YqE6S1%{he4=6E^}7(`OpJQaoU&#{W&6s|Sgaa(Jzz!>q1XU_=yV9cJyPgf{2GL) zS5ljMV`YjKFB7$$d&Rf>c(p|Q59;avd7&2Fq;vaBUY7&zz%e+P>OYVUmzRE37!rqp z%amqf?9m>v?Gm`=DQj9nJ_zh-%lxVz2v)nX6fCJ)^%(3^ z|LI|?93f|`>do2yBi zykz3t_Xia49IxIXZrj^9yO{Q+;C7j7TDmX=wS|f~Yvz;HZ&K^V^xu8F)*U7sbVK{X zajPuH-)vgtB_0aXM?nF^$>{G-e?F9MoZaDP!)!H!LuRz`rL(S#oAv`dFE3Y%B3fr8 zMWd`Ptn(Sk^A75QkYAzF4blmhPkIctq>URVt7iBrMKcX6xO^2*O?hZ;Imw7_fM-gt zoo#Sl3YM?7kO%X<>#==VsV|Ff2gD5QWL*JTd;f&uNw>qnYAIPEVCg0xlQz3AaqxD) zng<0f)i0S}O8WT*(?T=x-Z@VIWf&+_!Dd<{aYYlwstG-a`K}tQ1(Tm7Nvb4G$PM&pJf7Ek!C5!aNf|7mkOA+(9HivWA?7XvJGlsMt%?LY|Spa2_> zrVqL21fT+GUgX3i{Rrs!C+7j)mQBjWqEb`5tbY`!3+Oqm&7rac*e~^+8LvrE@2uBY z44N15NmtMP`4jN0OH5rh*XtV04drjyxt3ei%Bd=^o^x!`Ck_M7Yf~metJs!{1iqtb z7DVl1if8C{-?j))KST2~En|tYJ{am(uyk%p42`d6=;(1b2nEwJXPbmPjlfno<;lE2 zMy9NnUg%MmA`L<4!m0Eh4Cn(1ir!3Yt3ggy%<4fWDyz;VfZGaD4@6CDu#&3B5V&c9 z=qs1GxpvZ_d+;hLwp6dS+-DBRrz@O0kBk0mRwH)OuQB4K5^M(!={-4*r5xH( zFI>&CQRsuRV{{Wflb0gj(mnde4{$vF*ZA0FnPvhD$-JhL^iy4#;h=Olqe8kQ?+Q^wdjDLnTbI+NYb;zz%WY<&L~Oqn+1 zNJ)5a>6H;sDn6~f_0B}_rccMwzu4)<0itbRv*F$-zgUX%yA|J9e$M-of9LggBV6zK zp3x@}g?71BRkcmLh@8Y>d$2<}3#@q|1v%)Fy(Nj=0CUI9{NvIhx}g758Zua2@*(!PL;+D^HZLC^DTIC<=?DlFGosnuu2~ytW5D30Mq7AQ~Cw zX7w5mh5L^BUX`nkIIQ_J;kP_D{Xm+2APk`)i)Tn{fWSkp}Qry3tBl zJfTIs&%CXWeqkn=thzbZOxD0*SPr-L!2p_@2V18=5jWKwAZ1w!Osn|1^EdoZhkmRB z+~#veXR`BVAEQe3>%v9YQg`I+vCIu#$A=`O887`5U@QQvGnC!{w#fpE1p_4n*B$Fo zgpGJDU?%~Wq1vwXZP`hxMpXQGk1F(5Fkg5|t5RyJLH@?6+gfjzd^Oajnn>+OqDNc4 z(V*DEdj>!StSQ!>7}JNU(l}`!42ts6sfj}a0R^T4bQ#G<=ypzx2rli1#(+W*^c1Yq zdD&bfFzVGv4miz#i}MBW+HXVuR=p%^;95G6{PbyabY`a__vsT0N!7unu29O>^NnX> zrEfg&N4-6&6QcH{t8978+VdueCjpjWr5fq+0PS;sKp@qRoKgv?3IMgK|4O3S--@aO ztF0->&argmTmO|Y9wiEF&wxON8uGx{Su$kKcs8}`{V63~{Jjdl766pR6kgrkXgZJ1Zqh10Fwf4hZ)3e3358)=h8jP zAfSCn5d4&#w+Q8Z2fba;Ql2p~PoJy1aO+@bItvrd?zhcG9fAE^ZfWF2#!sWzVDG?y z663RU3{Aw-V(VW&!I_=Z=!bRIv0gDg0VkV|G|MmPQk+?&HCi&hMjSutqX=Xz@QP^? z$j>BD*PNcZ>Fc?W=e!7=-}7m)K!>Ixm2EZq1S@my?lmWPhgN%?{Ydfcq~NdiK4YZi zKJb*R03NM0efOg}#JV8eePRo?G^`f~sst8WkyhW6ia)IRkJ6fk8`OQ6At~lLT{)>L zYU*p>emEe!_Lso&t}gl%o1?tWDujbsY71y;ywAu+)G91V~Wv1i4h(F zux49CM71QbcFwxkRvECeeDwNwj(_I<1h#w$=`bY0smY(eTrNJ52is z*hN9^E090YD@mlIyWdv<7~=KKfTq%tN)P`l-oRut%=*fVPD6uKvw$p*Id!xRzV6ei{wqY&yX#?SuMz*MKAEGy z8|_Wn*FZoKkdVXb2da4vsW(yLy^fXHjtReqx8?lFtl}yHD4G0ZiWey5N}1?XbT$?A(NdAPIw3Dwzp;k$$EM3MA#-o2TK% zr0;_N(Yr1!OaJJ5SD@Pd;1@^WZw}7Tr%X*by%35jqTTF>*T{crzMdt-+U&u9Qv+k0 zJZWEw8CX;uS)O3cVRv$H$s6@XRe}l;YUQ&weZu4?=nyp|z6dr75GbIDM^{c#)&VU> zMg=nQ6q_Q2tu<9fHu!6Gu0iQnVvB;dBUJi`)Gp^F@aw9K_<@MuqOFs^-AGS*8?teQ z04C% z#y$QfapjW+PVIX#ncuPC0$@$qZ`=emq4E%)Wq-jq?3x&^Vs*zQ#cUgS)*i}Bz-pdT z!(x1X@bOmX)_sG+fh4K*rX*y0GRbp1fla*CUT@?N(rlh#GgWc!cHbn-73vVgHo3ZF z{yxQ~yU%b*l-x!lJ=8_gdPXBuPqW?lm-~oAXBv|DK9lfhZ;*?8F?%4h@Ybh1oEQGP%g|}}<#7WY!4bw}ieK2Cc5Da4jN~#_ z=5vdm@)Ch`x-?N<(9Cs$V9GONufsQiINNS+5qVXprm?fr*N>A%>q7so7-rujlSEwu z@)PI72N;gs;s-8dr)buzQ6RBk_$HGd4Cj!fC z$s97&m#FVq19ad&S6q#8zm@kHKf0f7{i`c`6s-ByNFnf>gWZE{#nUB+dEwm|$ z$3w~%!cX}K6I{yJoxVtf5UaW^P#4M;NSWk;1E_*&OX2t)#vnAlAt)8En+* zbS6&Mrb!4$wL1M2E0GkxA>e zNw$}FEsvz@Ta4San00C3LgO;<-p@1G6TZbTY0a#msYwl~Baq`0wJPpFVU{M-?PMXwvjqXik_cMF5RN<+_DZR_Qg1y^0(68TA zSVC7wmAcH4+iHbiDmDYnJAykz8v~cdi7-#-$U`YSxKtL3Ez|wN$->xN~x?W?7x=m@WlGD z0W|Du@z}>^9;-3`AkpClXC{XOyeeN2$q#Un5aZ5wFL|D&T74>%uXsXrdbv1RU`zQT z!=16LmNV|9i$2wql-&}L(a}u!aQ0Sp?%KU6PU(~O+qHL{%D|XJAc?b6nO$%GH8J7v zI5JbQxdur2m~z%Wmkv7zUw1)g~WQ5MK}GNsu%$ZWudfK&yAx%Plw1m zkBNCy686K6HLC2SwtIkDdPZ5nm2PxTU{_-j)Z%xS|GPx`o-L?wY2y1?jE}hOxu6E& z(kpt}9I_A`hfji0! zgccKOrwLz%(TY2H-8rogne|c7b^z^7xs+w9zI>zjRAD+sr80Dc#h2pW9J8 zoV*AcT1~o_YP2k(iAC}xGWcZ7gzcfHT-DK5UbS#nLZN)fMWJkmZkP{mf$GThuQqQ& zo2B9@lhQzzhlL4!4xHZ)MQQh<>wk5z+O^&ZqKfoNA^gBJ0BfrP@-p2{I5b_GKF}X2 zUST7q7Uh%&c4kPf;r8-33TdLVXKaysCXY1}wgu;in0;$LMk?e@{v~$|Q1AOQCAGdR z^g@;XJAW>-9A||@UYDh8`kL=^_dY3;nhYxwqEK%!(y51{#lU=V=JmS|XZq}71&XYz zR&aYfiaic(i@a%6@L~!N=jgt_qsOJ7606T3TH1N*cK3tXpUiBopR9p?BS13@Wu)3k zq@7uqs4Z-?c?m}bpTFy%P^3iAMU2=k4yb!$^5;b97|q(gQ!kPae?0o;H%@3;kHOgd zP>sahE~@zN5iCy{aXFpP0+=A-47S+B1AnChy(f!0Gt0V<38tlm9A9J~75krA#{9VO z4Cr(Itd4bi1oYOPDlEB;UE6g$s(Oq7o5LIjV!3gt`rL{IKGUj8DZBc2J8)XC0E%&x zj{lodyTun?v;WSOgT{lTM= zYlys~c45Jt#{0wW&#*@I3`sWWgPw?p+Wk)E^I#z3c_-GoDy@{CzzMezZ(n_wlHunp z0O9%7J)=E)Dve#5?2K!>(MZ?F`J`CL9OrCsuBw$yn{hSM&JbfEQx%iinZ;}U^ex$U z$vLN8EZEzt;q=2nqX|{|&(9Rpf`2hArBMpfllgT53bm}9XtffQ@b)x9<}S47T{04+ zUV|0Yox8-duGIqxKI=-2+&bbqw%|&>4+}DwB-6rB$1a=7JjOI0T>8>WD2+_EiDz&W z)JWQbig|pWmX48G>|{Bovb_Ac1KdblC7JUJrdd|~k;oOR%6VO|1D}u)2qGYthJtey zm$?a-EAOi;@?vvwljC1L&-5uPTORKE6qrXAdm|Qt_27;xFlqd;>-*B2!KmR%PwSrH zmT&ot*l1qqqnV{8C!nk<{bB+YqJJKijYC2rH2qD7SW2TR5V(ox{n=Mb?4g?$wPUyA zFg~WOf=7DI%6k`?YH09{xZ{liBZJ~wx2FbA6y7g5QNC#CPKjdBJDO?-x4!jaU9rCcaC#&!Re(Dp&%l?Tv-ZweaSZ zG+OUF=g}lL7|QSr)7)*TDZPh*2O}p*Qg2L%UKrOtzHda-(CdA__WsyiOg=TqHw+)e zYI^yNMjHOTmS$FydA~eLkD2rc$DNut<)Go9>l900_~c+EevFFN>&D=?M-YY2>J~_D5K6Jd{mq=&r+Lqk&WG)n7 zXsk#|ii=ydrGpx6oLseflwIv1rj^IN^0Yd_@A5`LtHu@&rnBTBHGw~wNx%X29^t0k zh(E%RUYC>fxMrH$5LpGWq3U|W%(hX2=R{Mp47A6bVLOSu!i}PLeV$oH)8|I}xR#Tn z;}2mX)6&A%KRq!I8J+k)FRpgq5Zyp7aR=A>Toj*uN@#E1!Ka1Tjsn+TRq6M^yjk*A z`=nR}_#|(gV^n{_3uDQNCsYyUy_L8YcSUjIuDZc7T=@X$bsQ-Eke;cUCg=${zn{SN z7huad2y~)$@QbA3OR&C_cr1)bqJ2x$!rQL4b$J8hNxi)k|xA`vm zgQ}PaWY!kyT#l;zfy3P<^nv&FQ`0C49Q)qImARd4MbW_JOhsVc7>$2rQgm|+38!)9 zmUJOv@aM!r(=LJt7Bu_X#3C&<)qPdgpPq2{QBNY718VCqLY&6qV!ODHH7k4cH!G@f z^cCB&qhdM;7p2r|nmwDb_)Qq%1$2_V+MU_yF5qdM_9{Lk+`<77c^C{DNC*2x)Db@D z0Z7XS8NJK8)4RIx3ZjoARub(fGt;Z5aXWwji{_ijrKuLyb$9Uco6c3Tukd$vvJGHT zw(-}`9v9o`cf;~0JK~$4CsJ{Y?((9j4n&w9;gcUkAU9SxBngEB$Ui<;LCVm{%Gna&EIcwy&^xZZWv8oWIU=G_+nk=I{fCfQt=v>be)??Wheld**SI*x2 z&S>+K=d(h33!)O49QrqtO7Uu4{H1awxPBgp4)o?D=#wR^2fQ^rYu*BlLFk|dGZ88_ zYb|5cmtO`_dEdkTngs>XeR|Yt(-9K7Ih59T6M0E7TD9TFsz0-P@a>r#(H}fa1R_z` z`D@bOGgl4vzjuGLJ*Ke6(%tWNB(eC!@LmjsjpxW)af;N^CAR(OxPo}K;|7}5+U6bh z@ef4~4mOfKH~3Rr436Q9iWd1&#(pPuUYPRc)6F5->qnqNCWb7=UB{@QlnTR1JI)4I z)xQzCe!&nMSrh&94(`K7uRg9`l21{-bYq*1wRb1X+HAc!96IixH@8(C9yphj2%Be^ zD>{UK1G_JX_$!kok9Bj_X+nC-=6(mJaD^&|*`x!-PRmzUQjEsKZks@IgqPAX(M?XA zqid!FcKq(|Hb8jd4D{v`kIwJ-v7PfoJ1CL%D(;dSs>aR^H;-FP9v(t~d#yqda!2gk z0$o-xnA2dQ;_%RYWg?UtK=Zz$#W2B!zUpFYshOeFj&+nFm@9mIa5Cr89x15r(oxg;33 z09pWEkDP{iTipG`iY>Y%vX4|-qdbsY*!1y+;gfFKq$V%m#69_t6Y``mXdJkCDj#Qm z!Mii6HuWG42?9zqt)@z1MRlG=egd5j`kh&-^?MjCo^TxtH4_bp0Qy*gmtmwuW@^>X zk)H{4$R4f;P>uO%A;%x9Oi#7h4yJv7RdIR|Sa*o+qgMaGSe67gVi;Kl&7}VqQFC7KocH(90 zKVrGmPhd@{nL-xnE2aI=M~=2Wfq`|ElQ6pFtPkFL0gw_un1s;JgWqj_t7U?j*TX4^ z{jmND+xh#-0RLFX+iZ5z^~GppTR ztK3>HA`w_nIcc#d(LOWGaZG8AzeiHBO-ja|U@aZ|eXsVYNA$*# z_)B0rfwgM2Uh8coCU8%Kmhx}pJ?C?1opZ-yRgp*CJr1b9dCD;EAJ%hvTElI!JZj|x zrdAq8hs>kzqS)wAWXVQ)W(^HGxveKV3t1iZ{4$MvpCdPaw`_E-V7t`Re>Wg`Gr1d} zNrCHgm&PP6!W##0l;Wv!e5p<0-p%SptrG|O8@nb_mZ9CZKd|b@>#S)U&`d%T?~2Ihok6mFIHdCDyBQp3CINN3Ul^S3 z2^@UXxac-N>EX9>?Hu_2ggJ`B)g3gHHu2K&ao?gu-K>bYRl)p)V%uSCPA08w00&>{ zD!cKH_nZ|Req{}Qm?0y2&o3m~JEZLP*p?dFuG;AL9jugFy#^`=VD$h!vT3T;@ct*Z zf5bR!*rh;&{L!Dk6!T2hKpV_p59j>|yD%~J`%i6`?Y%&G&(_>xj%52ZmIAVc8HskY zQI19WZ2pDW>}|z??H%ToyFAauDWo>xJ?7@)AH(tU-jo3S;z?43RwhZt#UU(8H6D7< zmFM%0E4caXtCF=2DqqD(OeeP~x_pnaJdvoOhRG6Pqn{+QF7;k6-6M5}{>IUf?o9x23jOllT+FN^(%*-NtzW0T-NE}rAcOpjKwPP_fuM()` z!PA_v?47wQ%LXstnDC>c0^*j@xf9%+}9D6oqw6a?^ycDQL-8(~a z&ENZ}9mr=+sgMp!Yjc@xBvZ;8*lyxT%=AT^3TRGYUT60$Zd4PgFnuK^u})p{5q`WK z1~eaWYy|anR{$IDKPDq+;>=Kq7ny4OtGDS(ZR$cemmH+IY=BC(&q6ku2E)(TS5=(9 zMK_^V+Y?97)VQHBi;v7Sy~B4GK%KxdZ9q(-S6Xa_w1RHhTqZ%SG| z4$Lw%Xlc(Ne-T=02pihy*N&--cJKi#&LsrM=Nl81mdK5UjoD!>TL3Mw0dbjUK^G-YcHZmiRv_umHaD+@kHkxr?DGOv zAoXcgJy*SBB;q0C;mOIwrjNe6OnfJZ@&P%nv03&K&|MT6Zgii!c+&F2 zk+(Q?tXB|lZ+Lv1GP*NY&#SS&`>HiT&6|9}qhkacua!vo0Zv#kcr#6d;o3lt^l9W> zJ?kLeTDW;-4yVTIK7$Nei$^ZLl;zWW@0E3$J#i8M&IeWA5bMH~V@J8W=br z6HoVhf4@e*)Hd3d=*7V}3^=PzvxZXGwjY7P=p@>2JSTvgwY0$dME9XtSIm}r$+uBN z&Z5>9keqxQO)3t%t6v>b!*DPY)5;LzeFtmXgDq%{z=p_Asf`}3xm$=&8j1Z*AZG|t zWeHa-L=ZT*4}6nqq6U}Jm52=~uy`?QrE)SBRc~7!tww;%;bkr17*4T-?Td=>-{$d+ zMlNRK#YSM$HJ#?xN}zb|)nIwJ_svN)7#2kmZJu5*X(JRWg0&xg?f)d&|Qr6X_k+RhG_2Qr*1Jh|#y^r1)xr_shSMHMgkzndoIPH@ey+yk-BW*TIzZ%u}O-_ zeIY_b8-B15-)S}U+e_yb4vt;esign*)NkHM93PRbjMgy%?4WRz$E>hs*7+OlGS2lr zRyN#+FS_r-Y+W3dA7KX$*RiOzvbGHb?eI0RNEWlkR^MTZXNkU#iI>^GIoTbT2ynN! ze|C)n6~17@jEV%-b-3XD|2y7vzFS2U#}@X@^ep{R+)z;KV`$?b>a z$%sIYa{z(~ZO-kMv+zT7MIz{pM<@B~q+=hH(1!0qHhhcpS@pBz*y~umVV=-7-$41fk23Q5?4Ia;{_=B9Gzvr(6?MwV~RF=coJ8@72bL8$ODhy28)ymOi& zLMsBGA)x6qOFe$yd1$wy%eD?=4;yt(o$z@!C-ln4F)=^oPYV{Fo<$T6yEJc&L1w|+ z!9lz9sHgo#e1#+8!+FRx019vw&3v548`ZE5=D;A9`E4$K_-t(joNf;sSI>L^t&Q+3 z-5);8(*J48%LPNY?ZR<^0q}AH99F zr8-1Zz;IVpAp^RpmhH;RjgIoKzRRo!J__8%@6%|kmNm51;cb^N6Knh#i>{w3+i#}1 z3@?`p>MWdL9@z?n5E=rTCUex(V`^w1*2S_WHjFs9^hW>FRI8}Vc zBXnTUxS_p`>YoLc743`XV@!<6{DXtGSY-ILC6>=brrsS2`8z3&)~j%!_9NY@cry)* zU7KrRQS(btp8DPUnmkw3v<*&Fd#wN<L{G#-J2}f z6jbxFq?0U%b<8Nk&VzExq*3||^y;px#&rKneW1_uv9iwSf?jq#+bgy-Wc}}A!tMC7 zgjaI%TgrjT3-tz4SE4}6(DNb}!oC^v`BxMlmZy9b;NX4q*73)6{SjE^^{7-EQ+gJ~ zdO*jtYez@NHOx5nsI(v_B81^0sEfe*>gd&1`>bMc!ASI|NKjpf%K6&5nxY4J#O@v} z^1dgu5COvYwy%8>G*PA2uND*U8>O)ldUr3Y#glV;`053`06RaKbbXmgR1)D}RPcD;=F;N;*Lm@Y=D>VI4&==o~skPS&;|4Z2dD|0$%?hCLgDC5j*o z%)U-OCd`;K;3NlsmZFMR)T?*cc)$iYEL zTG*U+$=LbHV9i3r^~~t0@@MU_dH_l+{3ZdGhZ1e60|@z0S@FBykJzpZiUN~ju&LpqQqY&|6}zNeCp=>g2(S78XD88GBektMk66mMHF=_@|6y>8I^%Z2ywo1; zv(CDjO7R}vS9)4o&&>NqiN64>K1fhtAz&+N!{kl_Ug@V6zE#-D1l)xN?La#4cAcZL zv;CoxuC-(?^bm=9pS-jycbQ)#_NAXwuIF*vW73KfdhO+&b%dGSHRb+Ei(Z`YB`5h=aM8 z{F|qLN%yC!G{Gsg=T@g;I-@%_24gFU#-c~x3VBp*QaePsnl#4>Zy2upH#@KYh?56~ z0QA}E8KsTc)u>PG{PI0v zXQevGyvDS`kUe8g1TP^Od&(`I_->Ky#e)zG{u$9WfhG@CyU)?RQEHVX?NrdocRlf9 zmM86A+iE^~Px}G)gvfSFA5DtpXOxP;k{cFuJ7hWtewN|&XLZ@Py@;sUw~tjnR|D+A z_AKK$yrd8jJ1}NsbPj(GX#`)upDBd~*Bo3<#BZCld`0CUV{;1M2~7Xgh2o9ojfQ{x zHEp2%XeTf_Qw&tVWj=PPYBiG`~VKGz%@{V-MbuBwkse!A@Gm-g1_ z`N#2dW5B}a#xOcHK~zJB8CWV$S4Zz>c%tW%qUW1;Se`Irc34JEsG9;NPqG!0n>Q2c zSe}61sC()Jy&zo_6~I&Ou<`o6+m1)fWxP?L|w)! zNa_VT$HX0clkYQwmZ%qn90J6pAE5EPo*iCMa7)6i9aH1^{fu`}u`)_IQ#XGxd-!)2 z`J;fr)sG)HHL#=|f0w%Wd#{=7!c)Ra@MOEifkp#@j2lB=m%>1&)7jLoC-$E%tBj&M)irhw zF=!`P`9K`3?F+}HPw7+myV3U>#C`Dm-*X*j#%C03yD6Kd{cER3GGL$l2+FEVmCoE- zQFr{wsi^+E(bhMh)gd`yP?sNX zOvn&LcFj zI}?qyIY(HH!oQUoYI#J5A7)?%R%>6AgK=bMtiMkJ!(R+;Ew{;i*0%nmalcY;m+_!2 zg;lM{nRw0GpBNpI+v)%#vGERszt)143x*quj2@|U!f&PBNuXfa(G8DrGBKH{u}2yN zLCoTHrAN_yCziw*7{g@BdCZHrRJ$N|N{6J~7t5@8v?6TPuJ!L}ln|Hm-_Z_nTn$a( z78Mu0_!efu5})Y56FeaKCzt6`bX2}-B^_iTH9m2GevYj&YH6hkPyKNWva@q;aggXp z=tl05VTW~EnxmI(l7pnk)^@F35$uNC)JD3cQSElF)0ohEx3a3AeB1w7N6it;gCZjw zL)$SXYr$r*S_A-r>Eq{S2I;3v*&@EPkP(_S>T~2v%CL_-`yM%ZP%E9J_0`Esej9Hd zb;z-w=x4@(f6Cw*H@^bX_W-9%ouHM#yO>A&Jq3^)u=_lbI3)PRYn;yC^AF`7UFafVWbUryML!d2EVzWPtegA#Dk<#hE=Npn5gG zmJcc#Qx_7~r^c5zf@5qbVI8%ZzI__5<5scOHMVP_i4~_&`iPd473nG`bqElB2XSOd zl;r+12+0e1McDF~1_)i~NZ5ZsDe#5ML1^Zc1ul&no|F%N_RVt!hI-EY|AYQgCovr0Rl zNYO{{0FVNQlj4D-O+?Ap2qH-(c~LPuY8J@4QOkB(t#!5J9-LcQcNV|=ks=Q+aV}*x z_6QgpLG(1HsvBD%cVwGV*3UMJrxJ@0i`=>cvx?I}B3@cg2Q#{Tc`qpYs*H7-xU9oc={_f{yT?^E8Q3^lW4M+&- z|96l=BI%*1;XMh*aeZhBg2O2qpCyj#rU8IG$y8PYZSma*);_tcEM(nfQhN}6pcxn_-m7}cl+>nC~#NOPmQxu zuBUO8v@7d5U1nz?P9=yTb!5BXBw7Q4)`n@oH@^tbKBf@RCig`iU3NBrk_6#L!7g1K zmD=8lP9u%k_CI~Q{fv|y9dbE!HR?AOu@W~ z)LeO{W=zkaRskUpE6O#x*Y42K%+DN%-k*XLjX@*wuTSr1rvG~%&7_risNrW48hAbc zJ}r4NAOwbIXRQ;&a;apxcTk_lPQnaVsuIGvAi2kj|( z(;5&U`%uQ#n<@c@HwqNmhODB|OCyMOpyX-AF74l_B*?w0-!lVV`3s|0iT0&V+^9|0 zx!;9vKCTFZp(&QuBpAB1b-Z$UW+{{rm0SUd3&!D}8}n>`J@-WEBzp~2#Qe}Iosa*mMur+&Tm%o>W4!v;%c$KJ!L(^y z<}Hk+I&4;2Jgr{gJZ*g<%v})k!XyWN{fakRTQuZ3N39)Id5YHbkJBsOM>z=GBq6bf z#vGHpZgRgKFxHs={o%Depbd#T977xDA~hi*1U^90ER>^I1)(ef8+4cqzTu*-`1j=r zpop%Y4OAM(FJZG~^{Yd#Tmk?^Qgep6l$6|_k&~dUa+z&HwrMS8$Pc2J7~#&bUd# zQuAcYKOYx)PfgTj3KhyCL{T8REDbeCK}EZmI*^f|KEnJa418x7DoKYbPQn(UIE&zn zft964*3`NUK??fZrhq_lp^@zy7e$*i6-O4_)a6gFcOVowmF*C<-r=O$WyQ`l-V~m~ zv!{Y^7H~baR|-D8ifW_%x7JRhqimX7>M1pqZD-?o=%Gi7_58{N zBjaQSx0_0I9TcmSN&bye%1eH_tW9QdkTC|a(SbBc3!Wwlc;i5NkjK?2ADF&+iQPWU zTMJe3{MXvSrG|r?jmcxs!JVcCv<@WR0nAbbM7q%stubQeV9AtOt2}cJcJ{b6roI~1v_b@f zzgI5OMz~}#mtw#wj?2ay`3BsX0cv;(bxP;{XPrG6w>~Z3-J97dGViC;*HwF}@A)#w z-D%Zw-~>Glh9_mM2U>u+ANtG*uwO= zw$0E;V~o?P>9GR{Ht4-+p6WEa?akG~nRcy`#68CMDC$~EseuXHkH4Nd#$wFC_>s>LmeUD zG;PWL6s!&8Jy1ic5U|RIb`b(K0vy;acaNdtrcnU3^$1&WwJ3A7zzQ6_<1)CT1Q8>uGzmrhhS{iJ=aws?!Ch5V5rbYcnPZL+H}SC-2ELMdDh>#lk2AD+BdZ)j zaMN|xRt$h8)ofQ$rKGOfZRdWqI`tiQ`WIh7k0rB`a+FL$7aDJPUNaO|pv2$BGz(Ad{L|E44G`P&n8Hk+j|t z<;GPvhW4ugDZ|Qvy-JWx`?L<-MP*TAYMr8UC@|iqIpQoGt3NIKK`iUew=Vthp%gCN z)sqLePk+{$$!jWV+-F!`K{4Q8ggBfrZv^(%N-=L`mIc5aIVX5nl34>Wi;B!*& zuEl*T{`5tmPWyKc*^hH&VqYGQeywkQ_bt&L`>@ zKM*I_K@bVRg_Bx@6e5z9Su+Iv%bpBq7px-r@*jY@-3*< z&12mVnfVkO@Xr$8(Rm&cYV$z4$z1qRX>p9JYFDQicB#q+_e{ntt^V+gn79ZU{NCHo z0@?l?``y()hs1@V6_i&44u8BZoKCXuWPOlU-}B?TyQwQeny-o7uuY!}^N2wWYPC0# zV|KfWJ7*ss<>6n}xYa*Gl1pB znrrzKKO+jDUQml9-QGjFJ!Zq$OyjN{G^S>Jf|v-&o0*u`Zsp6SZJcTkN%g!BKmH)r zs=Hr~Qq`ZA+Ws$YkSxGR3BU1o%<$E!DD75?*QHX4dg}1kASB-4b z)MZbvRFcytUM^Bmj8<-Ps|XQQUudvEWk-Iqlmzg!9b-)JrBytdU<%Mn+< zd(ea(qtWyKPE|-WJ=AAt^QpQ5iOZH4cF8FE4G&7Fu_c$r%>}W5yJq{_^7qH^-T5Dg zF0puBf+*5oe(YRzfQo!vC*LqMr{ie6{OM&QBkpgN8`K|z2-ovKpc$Sj6WN*k7m%>z zk+nTjD&B)?R>BV&dhRY~2sSJ`O>{KkKQkUpa8X^ z0Ia1l?5{p!a^Uwz`#^jh;^pD)qS}=f$JI%P;YOz<9Wb}gSv}N`CiovgG#m&TO7%m= z;ozbt>gKRnLHTJNNU6X#9l(~TBbTfhla>8y){J2pS>w1xueEE|#D}d6zyWeF2|CPm zkR7n-I7I%0YZVsX_vrsHd`?1&C3mpDtMlWC1-3?Xq1gViV4Am&`(*&F2BiIiGV4wp zRUXZ3#$Tx5shP)lgP=eEKs#NQuIJK8W-?D{d}H~SPa8593jYOR3ydKNJ))zQPA$J+ zcs2`I;-BCSL6G=uAgCR|T`Lou{NeoGo3}8xZDHad6L|UBkhDi^udj;Lk!hKRteaWc zNtr2!|NDF+b#n!z{9mzhDNU(E`T*T4Lafh!4DWfm4B&qOZ}--z+A+WhK+jGN&W-d8)U|k&-%Dh?s0k<^fj{C?P15aR0rK5a8}mDw+X#TI^V> zkQV3zf1WAf4R6R;7nkTwbt*<&6+kut_i%p>Fm?+wxNArAx5%?8iuBDI8XXX(&24<7 zy)bt4LnVy)R^HdD-Uo5i*#b7dX_a27#vM}SX*NO!;{|5S=`P!V~sBcQd) ztWH3Fi`2r8uy`;lZT&kNcy|#4#BdxrIqT$3jSZKnV-OQm2FU`Rcd0YTCI7;fJG<;5p-sU$^{6oRhQi*?9Yl{{ld6pP zWHE;nst5qvZZ6Yv&Mt_Ybpq{3&NDGDKta1 zTfNjjh;dfe#+xfE@~g1;8!f3twkiZiWdmA-a94&&2rEc(pvDcLgMfP|-PX)%Ev{TE zRY(2|fV6^lU*}4c;15hN?Z5nD*}kdjjcG}^-u}1nuZ+E3+bVf2wS6t4qzE8Svr&xL z><3Jts@zOw_~9&Y&p@=Gahox0ef1kHmXd1Y@!p$%ICy(ttw?^F=0oC1N;ZWGCHsFT zd(WNn6;w*#7yPHl`}3NDTh#r|K>?53`F$dgq*8^ox<UpK zg;H18ln|o0ywCon2k!`Xi#AH82{b_KU%B72nt8OJu!8_>vNf9>S!4%iy=ksQ;<~WFw;Lh( zr@QqHG|!&uf2@)6=Pg|PgRulsAVUQZ9Pq7YKM!w5@H}P{-9uZN=gvZX_48bhqM#M; z;ZfNv|F-NSbF72NAGTpFK?I{W>eoL-t4~`Wq|x_ujXV=6LR8u#ku&DmLcY7Ni`M$H zQ%fa$`cp0SN`+7(-^P!A9MfHm{1f!{*<1ds-6_@bQ7kt=mUK2lTt$!DM!)Q_%U}eQq@d*=^1CxguJ~yU5nf98a_JSU)mBw* zj~8{UBP0*D8pd7w_AxveP)$KuNyafNUhiGslCS#k3DnZm_|dShp4ETHG%a>{>O^Xq zpQY>F}dF6VD7%r%s<8- zW63J#8XPm7D7`52H~tf6$rYVnw54f;Xd=S^kZ$)`7Ils6n>L zfl8qECj(Cv@EXS~Peu@#Y3q2GnwAGqW9TZ#M~M%|lK{Ue63Rz2 z-G=$B@d)dmL3+EfdXa5UMH03(^nETtwkc=5#R3dZ%UT}=z(eXfKcJ<0;BzzA0BzXH zq@Ffw@;7~>XCG*k;=}Je|L^=|n~|zmFV4aXK7W@_RYq5+e0CR5kOXiA4@kA^Q#&HL z;5MOO78S3{4+LCPj3I$<&zxW@hs-sW2CeODA0S4krtKexe2@RLNFi8wJRwA;92O%D z5lq??hfA(#YC<5R`N1C9HF29RYm)KZ-2(4=MxIfO(%7(SjJJ%sZe8VxWk}R6&kC>q z_fTJl*3LU>1jY0yQ7_s@az$nqG9>sFE=^%Bj)0SUF}IjHk=->k%e)IGfmihNpT=u5xUEA_-wQjqF62!KYJ5Fc(pwHbSAO4g5))h!p%Pm$IYxE4iG+PhIPMq^>Ch+;JvZ2q;{I&b# zDoi>%9Wt2ua=<-r!%qIcUHVFvC`%C;w)Z!CL!1C8mIO^}jPZXcf4_*(`a^>ONfS_AXwNG%VvxX8MX!;|Q0+FvZFIE?+ zl0jl>tt(q>Wf_N-f8uuI(T-8=U*%7a|9bpq4gN3v`DgY@W>Vhf2_DG(CB(-YWaoDK zn}@wKo(MlZFa7N=l9D`z0iGaw9#b8AXOM#r9*=>qz0be@QFF6%0^#wPfM5E&qUYli z0jMcdL13p>KJ)^jf_OX%9qx$JRW(l4@4K_t>EG2>ERA? z_n`;=P8sa#1M;TlQFgWS0V#qUJYE8VH9_u9fMh{oeraj?|9QOEnLAy4x89&T_vMxi zk~mxTpKJKPbpQYV``CX3jnfz_{$I|W!2daS|6hkfKv+ch|8Xj;%n}%zo`mGs5f zsN<%SC9?Gw-g08W7u}0-qmQP2d3X~>Y61IXtRK_s-r!hISGDomILVc~{CD{~r76X$ zQ-UK4JM<+G+ucaN=Nua^$q9TSyt7~vI^`OAez4VZDl@!3c_UT-7jf|54)}0wBg%#@ z}8fBQ)n%T^;l z2v_E#SDNIv{V4mf^eCfOQM^iBNT=@0n+(dNca~rVxr0CVIQ|!J?-|w9_Qe4{1*M}j z0YR`(BtQr)5Q+$jNSEG%gf7w(qzVWsND&kSLVxt$Yd{2~NeWeZ04WJoK%_{Y>tEl@ ze3&n@)~s2J4}>gobNAV2|H?V{?0Cuhjl^~DK@bDzU)tKB8cs2d!b?Dx^fSuJ!MUJQ z(z(6QP`5h`Ju@pR8FB+hXT)Qn2bWLIpJ)WnJU<=lu)1TR?Lq$?268a?#gX&G0KO}@ znglI7QyU$*ZWerJqr7A9YVfL81W3m)V~sV%a@4Y>toQlWQNYQ;@dMYZlJzu({*+pU zagSFF1lit&evNy>Slel0kTF$oeYFSSujAM%{az+~Hi5Z-J+>%&QS^rP*)=9Aqt4an ze>NW1h`uzRgm1q2P+$_maa;4ECB=^w#^;LR#=M2cUmhNUT0U)^)QgR>U+mV;II^jK zaHCg-)}HtFYooB;2RDF+#m^h%=@MgAzI?1n=TC6dC`#L32udq2$ra7bCVvZQbk%UO zpf!5XbBnitOIqq6WjfB}@RN#%W$>fHwIJNn^Sr0^umseRvZX^0?1-bI3 zL3lHL1$e`hANbq{KifOL{c_V^1lLBN-_7SL{Us~V)!Q?y%g}z_L@u8_9GwLc-Iw9% z-)G=$ecU(ts_^R@dzCxW5$$Tu^oWmwCTld@>B)kg*>40A(-tBY6^0X~9rr|1J0xZY zR-ab{H#qY;XEgj0nin-ux)VjO$08vqn(XL&vS~MwoZmgxHME;NyUu4ix)3T;q%zXPx`+t#Dk-fJ|b5Eyg{K^n@yp zwe+%f#_YkBcd&^29brWJHCx}0Yj09fp46}2vC+ldn;hSe%+vdc>@*k2G!Dwm8`Z(TBS?g@<%kQA_uqEA+jxQyGU#qVge!naaqyU3FIW znazBtd@*S~WOy@kXDTB2`(AYl?dwuIRP@xMAL{FZjXiOH?t?J?Q0`4}{8Fpq(z8R` zFXDzDmN{QyUbM(Hs)^@ykOU-Z#AToY#2M(+Xvok|hGh5yWk-n2t#eN9B*rk{4*T3m@WRI3YDu zo6z1IE<%g?ikt2+?M0U2%9>;4jP1e7hA~_Y`NIARmt7})b$+5B>B&%coc}7S zvmp=@vRj-}v8&~&K^(GlcZ)PnQ$swnLB(-OL#`dJ;es|p7t%r>ff-Lf$z%kKUYRuf z8M--=X|UJeN>gY215dE8o!!*ndvl+iOXOSE4D@aCyMDH$z=fGLl-NTC8h-zw8=D^j zj|$K6u`Vuq(t1OlwuQLp`3|IA2p)~bK-{@~Yu7`3JBwSe(%TO+5V}4f{SKm1L zW&Yg@#M20tMJ8m&nr9e@dq%QK(8Zl)E#==5-k4=R0gtv~FCX7&?F-i6=GW&!CZUfb z1n)@8@OY%KEI+dr)_GIcR9`fHu4%m`nl?hy|3CypPH*@mn#w7DVH5gZD#5Q>Hhr!NqCr{5FSwL zFGjksvsyq@zdzYm&7pfv%G1K}>^`qz&s}v1|In$~ZaI|WF0GKS7+9nK?)*Y;<73Cl z&r2MZbCD*=X^Z>8`B#L0*o6|#F>A&fR;_|A?xFE({Ka}xniRck>>NE8qC$#2t|MaK zN~c*qV>ja`x;(H7+LYlBaFjPR7m~TTQ;Oz1Kxn2ffuapuu8?98os0(Y@caKu(QOz<@cdm9V+%z9FNe`AICUn9fd*XxY1I;qoB=kc@wwiE@3Up4er_z-5wK-`|cz=RN`WKag z4^yGOj)qva;tcu%SXK8AL}kPEe>4$uwJs(vmILI?-3S@EFmteF(t#CW|ryOmrrPJGxKFRqf7+**8h1U^fj0HhpLY`LYQ)*&+HeJ z0jd_6L(6eWCe!1X~jQQTZwwCbKqgiLRDIi!Z)3EBM%e9KjwnzVHCCj?JZb|qge{FNy zB_^8=Tj%!+oc3uvGWg!%f(kXBpE?xhiSez_`w6NSbrqw%Y7K&akASu$s9w9g>~62O zsVO77N1JrnIaFE$OW5jT2oRK48Ew-H5BDgGK#yY4eay)F=VKMDQp7FeP5O;rR(iD1 zZsW@=is$Y3kVw;JW^;HyOM1<#uaGR)P;j4qFNYzo|MQ_SEgEn48_~*N5}2iK1y-=X zM^fs_8VXIsH`{|xb!e`twU-ye=QN-A9&Gmnwy@kNl<e7u`v7Ja#ZJVG8=cqR0rTjN08_!hEQ5P?br;io(+0w)LK|5l_h6)JaOuBth-;p@|o#z|4-sISh9#Ka3 zpl6Odtfc7`^!KEn$B0|^gjTMQzNZRhc%2Jq>-hEf;K$HF&YiZd4Bpbht9KQ4Pm)Ze zjXrC5sfu*VRFpax#oc}Q4jz)%)x0V3$~?z;X)~IIVqJb=@G>edrsqz}zaP}a*!RY7 zjLBmP7an=J#5(6~kK1QNrxY)Q2U}&jIDYF^g?zX=uQgw!ZJo(iK+ie#zU7xxf*Mut z;GQdD@j8aCr)xs6{<|!w&P%`8@n%VZ518AY%2-L>DQJT+wQPDBAy*E&>!S9qWx#2E zYzpj9L-2k4Za6*xV)tDXJV|4HwXEZx&d84yE48j`Z#xZ)>|5+26QLC@DVF9zbwmFQ zFqYXy^E8lg{*W*q`suIKo9rv1kKjjv;fgxsNp!%?iIPd(0KK{>Br?vJ$H{0UBjZZm zymGJL%JqUnH`99?g#kKD`I?(z;&-10ZIAh>lyqG2;w_fsaoqg=eBD`t##M`_qODPI z+9Fw9^j$s7KjB2DqNtXKIy@~(Slw2&thAoxWzZ?%Ef-O4_p{o z&F_TXtOvQ~T4P-UPV?{GX_9z*t&t%pT-IRvqk*E1J{yx;kbEP(P*|r?59VOMW0uF9 z+;JsG;K@|Gt;5N$)2FVmdX{8IZw_Z0W%+YW`UCcd4r^$Glvo>kV=5v@Ip1^i2G;=M0mL_#eDytZqzt zmEP&D>UOKrIm65|oWI!$(!3z&vQ)X3iYQxZM!1?tnsS-qCa#X2A0=AhR4WtP&D$qS zM>m~o%v@#GroCHcT^XB2Yi7m66>;3MgUDiLT^SCi>yT2JV|j{uBXxc zjJ!sbF_K^$2XotGmN=m+a?d!Du0aej80lL@7GxdmNJyuH>$+Sm-#gsM|B;U zf2tTcGN*E0sNgRZE!{;fRgBy*r3x-fe%m_!J?v%O)b{Bl%~87VcvSeyPKX2!q)-tN z3RVvjNiBZ5(&Wk!!{(d0=3f}}-(Wqz!M7zHei`>ndrX|$0_DQiNr2jW$lxw(rAybo zEMJ%M%h3>4HT`m|HJ^V|o(atq%z->Q*Ssb<#Z$AAIeG)Wrrfx9dNpIzOrj~(6-zpsfR#Emj?SfA8za}|vzSiR)TQd| z4X;>3ZOJHa%(qct>zXSK7EY~6oDZzc-Yz}Ulj7?&WVQMsMPL-|mzwq&?BL-2FVH?z zS`>UbRiZNzjA2b9q&!d`YY?Aj;QJNYBgRY4V{^wN4D8K{Wjv*A3&1&^lCm|h6zqZX zku@s*eyW97ykXy1&81WeavesRK+Ye2gLM^*pSI&JKXH276JFEx%2_J(3^`m>Y5H)j zu6ov4#F_f$ZJsab&QrI&{tF-RpEs}Wy_u6Mw$-esneRqVjy^JO`Z$oA4ANn>7WsKA znd_m*LwNswBZV(Kb@m{N&ee^poGvxM1oK#nv>bww)+WVKpw@ER(!{)e`c)IAbCES@ zthO@gj*A<+FVX2*cTUH0BRW>vL6F5mE(pp(Mls>tFdvMa{aW!y zz18_OvriVXnKHrF7R26Pg|EhVx}`Q7VlJqX$V>^E^%ye+2s@#Q{yfSN%C3jGpUU<5 z>Sr5W=Wk+Q)8i*1It4>ES*2sEZUsjUf~E-X$fwRJIb7vV%v@}0n2d3~v=-4rdZo)U z(q8+UAqp~C%|+#+vgGz5nf!VPE2ObXfKe)|VEfu@XY8k*kvxjhiy}W7pT`0NQqx8} z4Qqpo5VloF+ZV{$(4<5M&KitrJ;9P4J*6FQ1U6L1c z?fY<`Vp(3h`(XAvLl|&WnKA1aWMK2}SS%LYQ?OyNVKzZs>#9@jksI%xG%N^H80f6W zjC~cmg7VWR?jttknDiTH^zTgCg~50u$)Il6%z95s-yGG%448OlUNBJ zwEQGdnhoWd+WZC^IL^&mhxs&cWIBHock!ORgb}-DV2w0mG(UBHscgzdYPvlORgE~) zpR8C6w`MZ&{@&t>*UqbmVi=G~C<$qQy@p?yG1|Dde1{1=rFtGUeLuk#Y_!41hUx|R zxS`(PNgUf(Qh$VbcorY1K#-U`=2PrJz8faTfW{QTMf+8YGj};->LxyqZ-_khsJqU^ z@+Se6-)++VP)NNz^31n~IMF>cl%Fplm74*sm(I#U8ods*(lXjJi6gZ1kUI@i7Yv3) zCb*$KMu-i4QaL?d&vj#!6BQAHsVRhq65cY~qF^pyJ(9l5Mx(!ej}@|_Vkdm{Nw&7* zp^a0i4EYq{`SF%;Cq!XA{lB^p+np)!?E>aQ=X-eSGkjfMtahIB8|k+dg>W-_Ya@hE z52*x>C+kz7sLT=N&+?H@PKiI-DYcBdh<7#-q3Tb&fWc68#M{?b<84vzizs)ba8jvU zoi5;faA~z{g7d(^I_&TOECY ztWU+lC#94H#GU~km}~a9nD}Pqj87QC?i{oY{E}q@zKYHnPa|%CTxVCFm#yuM%-qey z<9A2N7fddxJo~RavBrL9N{~%+c6G6JD7vS_EGSK1Rs7TbU84uTDhcEWQmewGv7w4U zJtQO8VdoYbKV*LfiwrpF+`=0tMj0mH#BISgs9sz0Hpx_=u9`ddBH7P5mqs>?n zp-QU^J!JqQGowTr_ER}@(#4Zz&g>GMA6gFg8&v*J-TPndOKfkg#_kqj5Chm#(AaU&T~c-o6$v$e90%JS07xX-fx)igWi2lG<%k)1Pg-Q%Mv ziS!rupKi^`8DQvA<%Lsh-D@yEPX#|1Cpv+~vSgH2_@PSb*s9!d?z{y4XOQ+Z32}v< zXv~D*QD$_%FxjmV^MNcVGoBXbgh~Px$V~N&JmLDD0pqqPdE4r`KiblGYA{@lxN!7{9-%N{ra^n&AS}Aq{IFs9kAu2OIL`G-LECyDt_Qn zTKpHRP9KMccxKEoCCf(h#tvK5pJ(2;q3ua@W(5Lj>HcBKey!EcPWv_@ep%!W`RHQo3;ZTd56d>2YYzKSep7J@57R?U*dbq?Lhlq+5kR$vedB^!Y>TARtP!R7q zAj-9q#gne0qw>wjXbv43ydFw~-47}9v%Z?%<#z}+>Q4pPK{B}w)gOVU)16S;bx<`r zd>7xwJH85!EkaOfpbp75CC#ZJ#qFr zn7AJvjzoZg9Ch#F4(ukLTx5X*ZwRF{XD9GalOF)fSyLeL?J|)SHdIoXh=I!nHWI^{ zDqm(i#vK!@s827+A%D8;bMku&T1cgi4nzdb4O1N#!cO3TI2 zg7$k7gDh+sbzq53A+TG1-EfUA_-;2RDm=H1yXB0As{w-pUX-2+$_HC=qAeT%{24ss zvj(-BA;32XaaYjta3HxZk{@tFlLn6YQXJINfkToUl3CGf0~DwUP?9yUdu}b|6d*fJIhlqw#Lvk*@rp4p|1V8TqThTj z07=4;SKDbZ87ybxX8xAKSYpZh$xd~*q zRF0X0%6jyGy(aPXK;82!=URgC*lO%LDdkIKc>G@sdY4H7%Qv1hu&IUb65h8j1o0Ph zcagX8=qN+Hk%S}O5~_p|g(S&|E94`SPjta35fmjExCFiw-TWzml6;O%Ui3U3x1X@=(S?mMZLaF>mgFY}cJ0*p|RFf*R{wZJdm{ zb%uN%OJ^L1HLGn)dq>3TYt~_$EzC5MKuLGR(=>rQv5hy3>3xKW22jV{s+y_q7m=S)^+{|GdZr+uKv=`PC?J*1$Mv92JZY+E4){pSQ)2?U_6%a%ReEI~pB0-|&ECMZuzWxYi z-UXMjL2XKs537t5ciJfda5urDf$w;5vmE)pos#B6SHj%v@g(sLK(A{sg;-J@1|Knp zEN`dmg|fTatMjsF^pnk*QYDpwJgZ8L`!gzzy_3+-BK}w&3Rh*Gz%e(ChesY;k{WIW zkEdxf;Q8@r$(%9~_qAXZ1B`j@fqHHNzkN6N2s!&i_X$)@4`X^3@0oi>1JLP|h6GYt zHgZQC6(LD>{<`x?_rj_8h$Kq<7>^yatUWO3N4d8EgYhX8~$Pys(kSjRHCMLrnS(jw) zn4E}l*-(5qhPomgd_CPhXW%cpwz>z=i4lny;hT&qp#%w@1(YK_Q*lhcv#4bdCE{L+ zjt6G=_bFg#v!P=+PIS}+@lA?@pE&y4Xe4l-I1_Oni!+v|U2reRIc?HyNwPms=xf{H zr^bn_vCR&~z6ziuI9QFX$-AFN+cHKl|6sX6`VX#bFTUu3W%LB}MWdh1JDQww6~p-; z?CLeOcgD{60=wbmkr*K4MUrIjc~mpJOe7f>iNQ_Z7Jlp@s7j& ze&D{W73nn37*7HS*1i%2+6wbQKHOdW174S+Rw1%q{F{maZ0?Ufp9~Miz`f!3qd~CfbvVSK~1kq;Zg+&fgJGd zT+Bx(yGY4sHI=Q8&(=})zyA%w1%$8N<^)4_EAwvar36hnd>&9+^UNFo)k1?$k4?tK z+fF<*#C!oj^i*)=e>Jqv)s6WQ9w4Q?^mzUqrDTCVwB}l{gnBYZh6MV$5oueO{|yyz zwi8Xh>A)L9h^14Y1Mbp1*YFBD~)~ z(Pv>oI{QTP!&#T%#!bRdpON^!V2bU*4KElKODBkI69PN9*&|`!4NQ)527K31CZCKF zri=XKM3;G3L}sxs2-#*sfJ_>6fRq-*slqT#tJ%{6}$w6V-snvI86vo}2+L${T_uOdO6^ zLchpH!jZz7u>6#Y_Up$v$}+m>nQx1xN#7HMm-*3Wi05E=J5XOc13*V37pRv0O8K zqZok5D?$pc09J>&xQ}3hd>(u+EC`!d?8o?E`LCN);;C@SuzZuV;{HjiWJ2@9n%oj# zn3L5~qX4IbiYyC|s*N^cRRSplfOerC;BGmMU{4V-atYT*vB>+qRd}r$1ry9e8QhZ; z(s6D1Q~P8aRPCvt85>IdME4g^Dt%+@=g~m$>vBS1(pd@iON>s5gBghpQdNKsU3hw^ zt#^0X>l#(mtv@j^IoG2m@Cc)H|0F3NS*~>n-*u4%-3#@x7sfq7fbAj58ODiU+qi>m zg>fGx$;&Tk=1+9<*AxI10c!ZS7;cVmyP7I4(~Gat0;ep1T>+PYy-eiwqH&^-E%^x` z+*(`78HwsF9q!b4duq!ZS0Abk?@hJ8A-T-Qo3A#0mo)R{%6-y@cx>J{P}Y=V z01^0`CoV>EqJU(y%QFKce6BH`4T$jw8L36z&xOt*pfyuCG90_%F~4~YvcSxtp&Bo3 zyCIO!d}mm~$G1-xxHeI7A^FPx8GkMAeu@NVDm@rr3&q&?N#OwI5&`g8Gm=IF6`A=W z3*Wv{mJaHAzv70!|i)p41$EyV+{w^`iUKso76|1FK zG7q%J#rnxmk)J@>zXxw?XxDsv+D#OPn8;h~0x<`$cj`kM(X~uOE$Jl<*b&b^!CiOI zTX&*cPKQ?&42wl+(HBsX8|hOuOVGG@hh!=A^;yHvuYQ!7RhR%i)BH)I`f`e;BShfi z^2A<_67+8Yau1n%-?H=qd%|l;>T}&tlGz6mDaO8-z)wm3`aw!l;3*0tOiuAL1iN<; zQyv4#_BZ(g$Q__193}wg0F?AdszKY?UY$z|lD%k}zoXRaV$W%Wc_^%@kz#KgL-I=@ zom|9EKLaW2$B-tfOEybpkV(!rg=0_0|4sv*OEhFADTRfGf>TsJ5-@RwS^-6Yf++JO z}Fbl3r=Tup-Iq$>u#tbHq-|xTp?CZn7k+~Os1TS#^g$AhM7yr{0o3^A^PXo(^tn=mZ96;%1rtQ>GT4itY;&Z~ujZVGuQaqdp8!gLP~0DdPKAOkkow zxExdX?QMMLqkl`4;}DEqWp}0bX$qyYf4xKV?(xgjlW$tsv1C{}%BU@ndUt z?hP;Fi8S?SIF?lZyTk!*myGyvJ;3XE*x8!64o$n$HlFh-8UEt(#<(`@&5DPiAkC|{_to6(a6(?L8JR=N!~QHDU})t#jcZ5|Td2v&Bg`u!_mF}26l>POn*Xa%zzWm! zE%|;h6+sv5ssqd?^|IfxciAxXLmRv=5`#^~2Kqyk`#4d(utW+6Nt=2WZ$y9`9lpsKx> zDPJylg$?cnxYihraoN}DU(vLOCKX8fDI}=bIzi$NUjk%OJRwS(-Xs;^`hnTVhDrDg zH_nv(gI6luw&?WA=S}y&;_*0;I)e*OI~McXi;r#Nwj>4pru0Q=@6&9P?}&elL)-e* zVqO&iO0=iI7_XO-xs&W#h@^0!bH;Cw6>8r5K6p=A34H{`QJSGLdxkd{;G9$5ULD4) z2A3JaMtlNX>x>=g{G{GryjL`KDT(-6)!lv~GS3W}15E;Zn&{HI^L@nvj6$ScVuZYW zufqw%E>bY^%!F(G^YzG6!GcD@3RIkDgr!6mdGyJtY{4{|1C|q|78-1)sDzOBdg(SaDcRPKCu42rIdJ14ae+yw}I8NoMPRy(aTj#t#M*ea-zuRCo0+_Z zADKk=?Y2L3-q+Cqd=bA)w?y`rG~31S2MBQaGxiV+J{u#M<=i}_IQUkr)$q^QJe+%x z%E99l&>cL7IFJ3ULYvjPh`^c)9<9l%^{&~b{Cy!3z-PJR@}5n#o09R32{(D9%phKb zdKan2O|1d#u93H>GD$}|TLtOETP?$5w{(0`v3lLFt=^j_kC9WPQgM06_U%*)+Hv9^ z*0gxwsc_TJP1@Q<7GU4^NjIGmNAn0ROQ!lg_!WTv43Y&4*Z_ryN0$VGAygolE6M2s z!dLPQPVK&RQDA_6IxW)eD{_i0BQ1p)&CvF0&sE!G7u1-OWj$7PSfoN9W4lXq*k4XM z_h+nyxTkMf^n=qcve;?Sw?ZLm2AC3;4NKBj1%U2{z{HhFh-a@)9@!a3e&GQ5601sj zbFA1Gz28_pRuiF1>oYPm`H)6oTLvZDIqY1#h@K7<2y3XJVu8yzlqVxlCM44gK?@!B z45#*IzB^GNf6ah5ih3~+;vX}h=x;Y6V^9sgtgCX0Bbt*5)cE|4gc8YT9~jrl%1iUlqRmGS??uB!EN;7f6?3S zl+9?^EX7sjyz8ZpZFxBPu8NjCq~Q)Qq!zFO^)3T=Ij5&9&@(`IRER2fSht(Q6fmkNupK}Ct5rGRt$TTqsXII(m%v7vs$ zL8>MofgMo)BCq|Z9OCPhcoRNIyU5I3+ivIQ+yqfx2Ai7+0G5e&)5m)qfFu9uY~BEB z;@VWgp!ZeH3jT+O=U#sG?**(qA_iC?0gMbEU}uJIO*AEW$MVS3?V(Adh)Tvq5z?;s=G>Mppy}Y&fPT|GqN)ztK z-c#4N1r9z4X!DYaPZ=TIVu}rF((;l3J9*zMuW%Up*P?h0`B{2p{CAzmvjMAZ5VxGQy<`$gPgD>r#PyNHMRD%$f$S$H658np=N`Bn$8lx|6(o|$qenk({MmA@be1}O85UzhcO!ZFw8)cc;rD#Pf^ON@z z>*%-MH=sUN33TzI;Vi98k>3>#Z~l#gPyWgZfA%zBy^J0&Hbuf>Y)~J#apTb#bNv{5 z1BD$s?;K%{xO*G)H##9{6kLWw&k8~8Tw3pBhO5mV`u43b&~*5R9W3Mis!?KcN&(=$ zsgU%KGVLhIg|Nim@&a0rb|wA^aCj+hzl~_VpM$)O{Bq)Hd0Ecna@oq~hy6_-Z9wfU zJ$O}@--O;GdnNXh_n%mPNf!#3%*-K71EkluEA734ZTSa1@t(y}G%z|3=lG|*f;2+& zl-g2!W7Y&eC)Ycg2GNshy-dT-tj>bXGn@`CJlYbxMpb)WIE&{^2b}=5rSS4Iv!fa4 z*eYiDf=>D$_t@{w<2Q%G4k%zXHhtpkz7{8YkP|8bP?JLf`C`oqA8DS`NXp@13*4~vit8o5469Y6^6i)6K#`c&KC7az`BFM zc@zL8Oz3#VYY}EE)hlwdwLfVTK)5}_X%;^B{)11@*>@|E(Mfi)f+w6S+Uky4lebJa zoa(}Qth~D2eCGEGHV~_fOB=p(Iwl)73sEx}{H5P4G8~>itBI<7+iJ~hgi@U#Q7*N? zw$kK#B+!wpb>GcNM*nUV^zZf+R+vx@rBj!1S|2TbNMEkmuDvtDP`OpL%Z@DyucV z3&hCfFtONu27^PtEU;;Gg?ow)>xhi(JBa}qkJ=UN)js^p_&WVthuK1(-KT05wY#em z#qF!hgp6~+4iIrcI_IkTyBi#RO#CK;Zn)MhMY;fBgzR_ z*C<6A1wRZKUS(GH-`Q390{|QN*94$2pXN;crtYZJoFe!rBGfJ+YBFtkDsA?-vx+BB zwV(Q>=f}k|Z#&2>!i}Qchk2Ty^nnE(VZC|e1iTUZ-DBdq&j|Qe`fz4blqfnq^POK0 zI%!R2b${2jrACmhMqXmgGG_=163wA6q0tOCqBXe}?EEC6Wakr>uuxoE`(SKYw{&E5 zPSwWTXK&!MhoQEW>o0xn=OrN0q2H^Gi>b}6*cQ5Lb3k`c&|j0J@4idS74(rJ+ zC~5|ODwcnhnz>r(bx2EJp3(UA=LMvR^IF-bL0+x}42C#PHELvNGu8D`XFo(XrYlOn zSBBqBiZnzw z@A^Bh>nNc~?;SV+^_R(!0jyT%*~DZc6C@K#9O|mqdx`o<&-R_UUUYiGl`5DO%Eh;e zrxidx@PwGzGds*r=|_Wi1eku=(uoY*YfT^_*Bb5?c^&6s?NXfqYwWrgDbaFed^dx_ zM%IcYQLrZw?Wn@OCpoCC#LRvb9&8iRZY1xJ_dOtuH>}y5w38Ns=`?y;NXj2w=jawX-Q#M1HjvU*kH}=JNq_mDA1o8SFP1H=K-9N zv1Rp3`dFaHbBpR*ta=P%mS4{$8yWH*FLzf?eXnMhYHKN7tZLbP8Od3blz0?4{ zO3Tkdjwu4`=*pAVsRAxhm73*aYX{Ho@Wh69%poAlyZ+N|4Z|z7Ga*(T?t4dpzbLkP z1mb&LpcW!mw%D!1FPwX2$@UzwBR_6xZRMS&CP=SvYwM=mg@2T;TvDM9Wz`)qN4mI~m4`!nT0V48r+cQ+&s5*31>fjlcHN+R zp~zYf9bZR`QLw*M1bXXz1Ue_3o*bF91#cb)^q!sWw|?0?_PKbh`imy`^jIiC189J~ zXZCBZ@>WMTtp!N#^K=NixWXBc=~u{>?cgUSN};RctZg;E89+C>oIz@C2Jh^oq@*u8 zJMPg6@=V8RNDR>hs=R-9=UXPi>jM*B9l~xO6JP5JN#++iG~8Mu z?U5^wE7(*8Qh&DsTBL_DA1-HG^W=r@n|Lc%iO?~wUN`>NYmjf9`RkL~sqdd1T1-WNj98ye$)5-&m3WAKW2Nkq&g}1~ zT)7s)MX_vm*`4RsF1)>Xwrv!DweoO6ZnPWxB9beSALE4xFX8D6u* zjx7VGSM1*dp3*5md^f^7tTFJIo`uI1>>KxiMsxonDt(APf}xoQhljN0RA-dy_qY1n zm1xhT;LnvWxAFf-EfLI7sU2fYtpPIbNtuXMpW%iC1h5*DAmR!b8=c5qB|j5PzOU)Z z_ARmOwZk&a=c#MYjh8h<8%BQyn1>Fmgz>(lOVw@a@l69Xxe z`e_?c@uK~&%DvrC+s@iS^5D7&X#u)acFRVI+3WAy64|OoNVvL3q;a1t1KhJ3jb!nC zd+5@B?Xkt37Hb(LBi^u-KW$$5mK{=9KlS}4`077OFs*Rk9Tr9APt#J`@q9E=Pvz1>+e1E`YzCh-9|@Yu zRWkf9bkDJGALKv~RAaP0*#%iTwaj|)f?-y`1}u5;;{+R&kO7Si)W;IR=;C%_no1`r z%0Bf!Z+C2*c$ACL=;1YjSR9!prOfrLc)hGVpX?rrfQwa?kzQl@rB$j}hDG`%AWEF6 zIa9LdCpG7W#CH=SEOT96%!NlcytM6_{o<-aaO(K0~&(-9lEJG4+#Cj5w}7R zW$5)bp?#nUrcdzOZx=#`zqvI8>;N6R8fU*z%WyNEnb3Q{Uj-bkxH8_cqiw86{>J4U%C!8;lkmZOwxPE`+xY{ARMnEKFsOt?9SfKke!YAW>h%x zG`^Q|Pvf#2F(OD#G&@Nbss`Y{AqIG4K=dUI7FgbJ1!TAAk4nE%f}e6VDP&)crPT{q z;XHanIG}q~z6K4qg9yg+Cztoyk@g&e9+nSzYV@+u4#kNsjG)}BVs1|)CvvLzbbP^Z zgM6-J$y;ozFMn$#g|zR{qb)e8WX_s!`P{x86Y*jHCQ)~;O8P3pIEg*#!jo&(MWwWOtS2 z1}A9_$TgB66hFg<`29zW?j!&w6_h=gEagN9fplblE8bGczl} zV&hmH<@olITOHDGXm;>vpU+lAlgSa__IsPDFV5>aQ% zGrkcw9wVv|Lg=aGD$b zppk1X-GXTU%HqeI4bm!9{SFjf8~TwcTEDOXYy10{Uy zUMtKW@iXTd-_BX_%eSw@T7SxW?8MCvzMXV*Gu7EEZRXv>*cdDJd%h|!rfbI5LO4$j zch{(jh)Rwv28gxrg38&=%ynuXG47sZoq|05qJbn^S#D6|c4rT|@(Iua_lnm!=enzD z7t1!G%sVq}S=VNYcl}!$agEb%nOc!^qNT+^dAq%w-L7`~`F(}rXIlRUO=lSv<@`!bqzt4Px=TPn8tE9i8)lFWX=&*O>5`Bha%f>_q#I-a>27%L-~T<{FMJ%1nS18i zd#`=2bx|ZNI`AL3i|kil)VaU)tUpc*czQGht`C;cOYy5+Jlahsu9K+;a5-R?X%i>} z(&v=}u(p_V#mY31eq=}R2uj%Qm6R=E94(f<&R)-H3DMu`%+_fn_Y_+Jz&;o#ZW0cr z5&)vPfg)_3|mNC8TaZp(k*iPtk2?Ak1#c)*aaF z{~k-JN3+T3=Nz`+w&l+RP8o@CrIIGb*Ld1OTeCH2X*&UB^zRL!Y@UOCPHKJ(XB~EPVm6XF=#}_HEr?`0h~O z!cyNKm?uY4FMu8au7sFMjrY#8UM-=AO%DT(-kbrX2X*G z1{uh#jH6+enKw9SyJX_|bS0nHI^5(-_wF%8WS+aB&N4>{@#hW31(kOmJv!3Jd>wWz zY-Q*kv$YW4xp3al_s=}+TF#*gU!So{WmeI7$a~hbYvx07X*2s@}5bU^J>heb|$g!<7glWABDZ7&I^CG(v4NMYn<}w zUAM@nZn&jyN5_eYSl#?jL5#2{%)4$K7EWJoC^eP`s%Tk|eyiyBDHU`TEDmb^PdCU< zIXrJLEzPdA_)~vE0EyI`2l=9ZSVjw&iGw<|GtSvN_*}qosrM$-rC{?l$8_^zI^CT7 zn|y)Q>$<;o?Y*y;A2ee#Yyp8^o;g*IUyiSpYC+$~5gKpA^y_^)2Tb$I$8a=-pYge1 zj^8vvKKm?Vrump7$i|5|)ef23P>b*A#CaKo%<0Bn`$6H~MWsC`wuoB;Uiv!1=R!!d)=;>h7T=YhfRQoP-y>t+|<>bo1m|#Gy~-9RgCR&H5>F-5jU~ z;;WV+L|mTGE@kyznL9=%?`hrx`zixnH0<2rygyGrU%>2dF7|YEm9RvPnqF;(XBGHZ zs0`Of3W-!f%!Yc81vb^U&MlG^35N#(xJ0@zd20e0vZ-I5u+`G*b6#RRhizGV%8G0u zi6aI*8ef0^{6$SP;P3y8!gY*dR2@}UznR5CJv@poA-`E*;W(& zBc2;l_|vYXto`H1ZKD)3eVFNV#_?o)D_$9kWWv*jMLiDz^qwXclb?9*gFvQoyHS8s zoCp@-%Cy}}H(64dn&@qj%_6jtVksX^*{^rFkCoQ!PvKEG9-m#i;vq0m;7a8%1Kzf1 z4CSHghdY6`RiM*5ihGTHj102&xQZe}B|osQ^<4+92B32%@&50nbC~zrjxmYsTb{z2 zZpOM#+W3B*0=P|w83>@y(nsEJ=>p`ox(VS7_~n-YcRGKME;P1vrOi2;H88B= zojx32qQwT^Z#cg=0Q$EKTS~U|$`>i4exFSMnUj2PJB^o7e$s*8=k`08+Oq?godUDn z8uWKt9#Wmec17S2W^LHRl?UXBz}qvxS_JBC#W#EGCgH4c0aQ}ZEpv#Y5HJKy6sUKw*N}8YVK?pgiia!TFiS87fbf6WSKSW8k7*ssW+I#{ z2m7o5+9)eYJZ(*COTXKn?d)fs-s;~)P3?2Q%o@XJabfj~Mm1^BOwl`0V+vvB7@J~} zE+CpJR`TOF5EV@2IBKj_rm6Ff<~b08jI+doK`pd4Ae>Q!&&ZW|x8s1*$&8iF-r0{_ z+TAD_BOsdU!993=rGZ^ngBgsHm7XiU$4yPXa&*<%ym_^^$4ZUIci`m>&-qSo%biY2 zz7wJWYO{#*PYES)*JUrYA?z&#Mn|gqiLuks<|@2M{c#W1r^h?z2L0uut5EUKnr->& zS=Ph5@42XLv8M43f^wTMk9<0GRUq!H-Dm+&oF5{}v%d3kWtG&|{smxwMDx!8aYUuC zFPlhk<>Q8POv0?^+;C-}SB&P2GH_v^K|j67SxCqGX%Kg8s|J?Xk^SDFgGK|y0r)(3 zB5m!{C#Se&cJc#Zv%X^NB#wubWVqSlhNQekS-Opbr|Qn0wJ^LA5!UP}#05t!>>|ZR z!siv=*qMt$$h)0YjlAzt*V8t-oySXhsU{~TTE?rU&mLt2i@siq-l8tid9nu5kdtcO zGBSZtr@YSV*r-2~t`jm>VGP;udW$pjD??#mGS|LGoCUY~MaLA&D4+XddAvvh79BOu zlK~WR6#gx%IvCKHKUVbR1}WV)rdZ0s)L?szVV#zX;QA+=hGc+0+F`+}VC3eJ8P7VJ zXc%+%%`=yI>J&mLnZl2I`P=SjcB(A0WtKmT{)Lfx!Bk#OFfP-HK*OqIKBe#8|Bh{MDMK zvDye}n=mj_eC`;)UKSzd*T`04kOBV+2pY6G*87}=8eaDJ;NRJtF-13I%aBbkuc~K% zUpFr5p*;LAd<5{OFaU%_tYy#;;B!;8^_P;bBLz9eu6hI=XPE_L`h}n;yUtv=;{?bg z4MO&axNXk;N?1MK>ZjU5DM#4NU;z8dO9X==Mx1X5;E`=*D>9+q4yTBo#199R2yKg9j&wfDa=JB;a#N$~K0gqq* zb@Si)o@K0GqjUHbso&h<;gz^udqj;ccw?{cBZGL+ojzUP1oT7@9uj=t2twsGftp4| z$Vni4URWsyyS)7G$#3i)yQ1955EIcl?Q%}j0Wayy<**-BdBg`lHu%@5zr3qxvPlSTTF8=uq%kP%99-Q9KT7C`0EHMDX z$Shhy>I_w>*j7P)yeW%N%_s&K7(m|YtaR4(?_PM)uIQ`X=jr>n_URcGnjojd-y)(Y zlFlCm-Lt?5xmNa)_z-`pDyMpZmAF{|euY;HGw$^7vh=Oh;F?=ncd=<&{NE$j*HJSu z>wyuh z&lvTuK3kld;eo0RbY{AeZHyrdtCH=a_mS}gKOrUe0a2f%;TXFxfBHbaad&D^ zP=D8NxA|#^>*TaNn^bd@lU?PzPfzoZ>j07wSTHEPNL6ew18ywQAGP_1h4eR>0PBKg z?HV{)QU}Wr@3WrKJ+v%`AKUv1Ucb~?Ne-W|IagA)T8n@$+KJMVyTQ8su>*Pp&RpKF zbCc=t>Xd2bRHLb0E2Ccf6O$k0nmG6oe=+zGehkCSm7z#R(BHo`<4#|?djFxS@8owc zAB(>Mf-M>Gscsl|n3>WXnI9;0GKmcF%qXgcIIbey-$htP=Vs`nU}iC`DLJL(*J13S~NI4Bi??8aVq(lh7!3gTY&rWWAC#Qo@INlH{3nM}vLi zy#->=K+oUX%=3ceC9s=uI~%PQI%yac7haCVs60b+-z?(r2u@$jZD}ui zT6O6hRf%>#~kkb?2zSiA6Q9rdy>IPFNn)DS9xIIBPd2d1h z>?3|4t^wIr{oXf~*h!+<2191C=LG%g0Y8L>)+lt|A#4lc^;Hp_E^YCEEIdMjdiG4v zjEI`u4l2)s1dyDh(H1=*rh+RX5ZKQu=5R4GU?F3p7TGN%>)5yPHi%6V69@Xm*K!*j zRHwf&-T4n3|ApV+`FG(y9vvsN3JDg#3~l9ro2?vT6P)GKg=ev6Vt9I|v_RD(?drv& zmYQQ)60h`)tn~X+tG^s{h#O@1^ru*uW%y$jThgW4!dgu6@;eqjRpzKU9ZO~^0MyI; zk{lH1qN-*fI+?)5$LN=8g2UuGY)?udLMc^g36c2z$I(lW}(jr>Ipv zC`ziV_i8O|1=TH0`Br>D0~Nf+?(e7HXnXRm1X;m};WYYaqv02T8UOe4EiWrMh8tz|w-6Vh2qR6xs!ZZcQ$Lm9JrVf!Ha( z!7%R)2EC_cyn$}edOn58?h5*|Fr+Qp&X2lMlBH#9?9uc){0ruZv5}I$2y}g1sm?BzHNZ{q z3Z{*3*B{oh8^E9_d!!oBH*5R8x+y}rLi^0%5utmg*+4+FUw_+5cRi zv+M3?>owoKMjCNDE4m{fSSyQAT1M}d_2mMDAMta&A_jv=9`-3mko1m%a={WeOBaj4 z7u_P&dGNxs6Tm3Zz>>xOOOu3^pll)OpChN>HQ&>%smnHNK(VC>R7Pv~=0Wvuu7K|h zXY_+V5ta&DDgr&05?CB9ZKo6ZuYW9eRxd);X`Z$dQ?9|u`RyqRa&mjO6yx&DzZUev z)y>eDjjS(5(t$sddO$3lw8xrMv}~h8{+TMcde%cJGE9Wh|MjQ0hac0w4mB(~UhnwV zW?q)`Jg+cAaHJ$n52^p29^#hE*n$mBPXfKJ_HgKbJpl-tCg8d918V}iKZ^~fH|{vrva5ZBk^*1|STg6Q0T z6Ad7`JC2nJ&z{iBqTf7;Y@TPv`I$866R0GQ6+)`^x^ez(ZEcC5BOh@<+|&zNT7Iz{ zS(4I#Oyv66*>gK+NNk`%0cG^2V4}2no-$iy`$m?tr@d+3A=2Ik=W2z9@w`iHxR#A# z;|gckZ#%nm!Ui67$9vJI8vH4%qaZo>4MqtB27qwDQmy|sx0fMIQ2_lv5H|a2dehxN zOZ{MDOvrS8A?3|7j&0m;8%cgF)#(nMFe+bu`ACf;nMM765;pTEo}-W;$kfj-KfC@I zInjhcWhn3CnO=Pk#^_Yj)KLc;xe@+sU&ttcP3+&Ocu3c74d9=6OBGux?J$wx)@B2Q zRo?jfQgHFO%v-m<`7DtfV&$jCc(YeEH1OhMWrb1G#M`UYfc37gVE7=x=$q+hf-9*C zMYFRyf-igMJb$a;KG~$rqgoeQ|7&K7+%Vz1CaiwM@vQX935X5GwZYD6#kG@0ISTdf zd^%^r`f3*_Ldw|ZLYZ5AjSX6G;Ad3{T+i<+888&b??Hhgwocc@zDTce!QVw3eLTjy z&OOc~TH@-7SdZ%K=8R@+HP3yP+{`*#I)9oCwAO&x-x_+uid=DYTHJEih`0Q55#_|8 zcadT+Nu40OI@@v+wlDOYX{^32JgcF50uhG7`m_99kj3l^htXmJ=HIr^W2_kz*F`Syq{nFJ=}8~EcSZD>H=O)nWF-R>v!Yw=5iDr2&W9T707|%Z z7`lPAi>HN}Tt`Q@fr;G-foK!``Y;h zMutsot>yN|qpy-6-l6_7XiTs-69kY%p#k-x3b5=`BH)*<2LfnnV2*K%l`khS<8LyM zDH$sLijx%0MU4h_u#rF!y<5Zg4L{OG-y6HvhiwC#LuDx@BAxn(sJqdj``Eqm?v1N+ zYP*{Hz&8!@QgD$Y|J|sWH2uv#MhagHWKEk;#*LK6aQm>auukWWZMwk7DIk>ZvZU$@ z>v%bbY&@wpfI961 zrdH@O-Q(N)FV}C53*ftt4_B)}u_MQc>nvi*a3=IB{$@;Y`w@TQ+vq^?uH$OXa~uI{ zN%C?qsHf}nzfbu&Its{~_~@`k<^a%)&NbR3j=eDQKZ9|_!1X?sH{D}_O}?&MMG+w) z#17QJ+V{2V59c2aE+t#Qe_!rddzWOXSJT#I@{Ak19K*oC71*@9cq(^I<+8C}+kU<4 zKmN3;ZJcNZ)%njF1qaKrB7nap%&=oDlV2Fi+Q&~mK9Nq3+4;Oz4l?7sM+KHFnLmiel(ia*_mJ=*7 zzrQ$Dgox_+wIE>l*Tf=|u6(f$X;MBb4D-?Nz}hu3Z&#~g%C4|npqAMYH-$=?5c;#X zX*IM0OxaNF-dNh5ZQt*8t3P`e9knWNL`Ay%(HT*~Oigqq0q#PzhF;*R>4PZ+_5b@i zyX<4t1;=;_Qg{37_mUTu>_W!QF~ljjnnkG-I;HKVgj}S%9dWED;Nkod&a)=Kxlc0{C$dHwl6fsL40T3pp>JzxF!EwAj+dMZ80v<4fz>aKb)^lEihRaV@ir&C#)5G{mnvAWOzVd zxd5_RvH(PuJL^iksG)KdM&?R;JDCM(8?^+Lq2QPUE^_e+FR zW}+cBLih36$w_yW+bCiS)beAzID9~ZHF#g4Rl@b^r!k$!Y7}F|45VUKL?4#^#;v;H z+jt)VsAQ-JkEXK3(yGJK8>%SIl)=Mt)d*V;!OpjSXhRpB>m!Tmo273G!C_x^B6mN? zPkj0CD4l?=N)Y|pVfs2fn>1GXxJD?J^_(k!%T(8$KU1u{NJ)5Ik2qF3u0tgk<4{_V zi!AjYKLtLzq$eP#WgRD$H>+^3Z%+a$YIfk2;GDMPk&`ET`Sic`4*BnvUjK=Z-QtXF z@xcOw*gAQGkzJoBLYo+Uhr1ha8*X_x2680=J`nu^AKsy9zag>yxAO~dPb>FPdu&Dj z7gJV939bB?yxB;cxmUNC+^g8HGhLJTdh11qlb?%-`2cz8j2!9DrP^|uiixHL=?Z~g zT{YSU)?-0SFw?W|)XLa?!F6nMpV?yt_(i@ne#bKZHNCmVUIn%`Vx2Uxpr)9uRY7?L zS<5<{12vKGu#@~lDv;&{53KG8Ma3W#9}C*AJh(g3%QM=oqgT=Z93ZjTqtZtVY2e?B zG~;u-$`DSi^9EJmMLt>ALzderMs7w_wW*$1gXpdeDIIt#wfFFVN;+d)rkR3xzyHxV z@hxh1>7H;_(Yol=(Uq~Wu`^;lP|m1gS~tb7I3C@|#qaV?tnGGHZR^p?*-v?Q0S1@rV&*f_oh)VvSmIcXMJh*J{*bE|? zz=jFZM$%k z4|%KqOi{bowG<#FDT1cI@F?`;B5WzUv0e$Xcth-MK%tE7sj$xm7Q>;m`?QM@|aT z+3Zaa9ObdZ_(lq^pYWr4P_5JHB5#TOTYGbSM^1SBh*ldqStgyNV=% zRo!8{gLHFzTN}Z4P7jYx3k*myP1|+DRlmHvbe~QnC_yZHsEMfaw%H4?Q-*-rpX710 zZ%u-LAg!+a3UI4* zrA1--wzd~lGyi(jS5qf<6sC)H%cD}i7|_M4l}8?Q&?TcKixA^uxLDhlP$PXY_t>T; zRj7G9E=A;$E9wspe=l=+lqMihxY)zj&#fdtZi8Q-)xU%=W=ofn(^Ce#pv+RK;*eOP zNaP_99>XuO?r#=bL|%B+)1mEV!=RLo_Qu>sroIvVk)?+qF^$Bac>Ms1t~ zZnyQKNHg)WFhZ)9)P_b}1|RJ{)hO_tu)m@Z7M3bwi7UqJX*mXotg6$5e~J{z0?Y|? z>#(FU=tu{T-gSe&@p#JF!{m+MXNu7s)eYv<2x;7;-`|6pM87~`ukx0jXDX5ldlFAW z9%7+A*($5q)!)h=dZ`iloiH(!%X%R9$G;@aY2rRPtSd#hpZ zOSF}hl|yb~ZfZ|q3Vh&0dt^_QYQ4E z@qMT4B-_PbI2bTV0?{Ndpfzn#j0IzNL<^%R9m;Bbb zg$L%ecr9D&xh0=9X3c~|w=6_oxL}fUvm4h(N7yPYQ2xX*6dCTt3+>v~Rc1vkZ31uk7MX7>2996J`HVS)|%jxeyk zgyZo5PV++FMf%NA=hGU~HM%tQ>9f>dubBxKsk*JZ6KRqSXG5EWe7`L}M25oK2V9r7 zS2K?Vdr((`Xsv%E5O}2|rAq=gcA$IeFg(F*m30l!RutcL=h_B*@qXJM|FPlw4{s-v z3TG>YClYb~gCJqoI3VG!M`L- z4hLSOuzZ~$Z3*wzLw!tkrZ5Q1Cbno?cABaM0U8+f>s)6vf`L%-2j%N_02QH%k(HaOC5nLbd?=0-1S;EBdyLrxUlR&>ap?We37oidFirl*)B0m6;7<{lJi;@94 z&mGq=xSW{arofH*33U%AK%hGG)*tzr5E)i#uO7$0^KucZg+!+?f7VjzwCV>VO;EXn z{)?Ug4EvL4(Dhf`i^;zSiyyzB;f>;ua7b2rPR#EgtPeY!OYW>VR^`d`sFJe)DGE*H zy7tTkWxuScWiGTpkD*3t&D*N2XMl_L6Lmw$*6!?dEKk-A+9~fl)sm6?uO&ZrFRiLQ z!ffAd8%gwkn<^e%c7S>~gmh!srrfrNh0QLil&BK2-3)%FnhV`N^U6E(GjR^$ne+JV z5J5s_e=I7Its+S|N));7a<-ibB1iSdt-f0xQ*l9gy1#*5UF`|0W7uw~Xj$z)EKB z*SR18zn*L+>cpX1HgJeb+USi;SSnEo;=yLkk_7DIP%(?o@C_4Li%Iga^*zQJoQX2lttDjc{uIX)-ozWo@IWFXV9ej-N5bPQ9VbEquY((lsbk z9Z^i>pJCbH!*vPrlaib}E}REY|L$WW6m#qkOTQ~SzK4d|B;}}p+HtLcm)o4IQArK zC}g}ppcvxkKT7ym;}x?sU7p}Didu%#xTn?hB;k-SDAgzd>GzmXT_&8mKo)+W3D@)g zACQk89Qfe}kcE#H`r-9+Y*JLyQM#Gv#m^r!$?|)iHiT!-#E*ms*=7bFHXkSV2c7qz`ycf(yu{Cp|n_N<~l=wT@`4fV$k~NZ#VS}Mj z>v4sXT(rMh&l3@w`ulMT^l$^|FwOXCWIGmW*4Xv-6O4Z49fPB)n%WJTy>Z-X`OF`nIGk(L$~+wo&T~S z%7}l|Bm3%z6-1gybp3t4P=#7uMszAuNhw`mUgm6~{d_F_p4bc`PlV0prk2E(a@1`? z8P{eCoKVCT2no(({YE=vxyzURCX2X1KgNhA8oiZxB1LC#`bd6&6aUalklKoeVH<+d zY;!LDu1|uX=Lc~Q&Luj@^4mI-53&Ws?IEw9pR1O}d^OD)+xFB|=)vBkRP!x>rJHtN zRx#nWOR|#U>h4F-e>DGlg1gh8(1kg9bmjc^HDx&Au6($8>Ec1qe$~nhqt07(LmxBy zm(s$W=GQo}u-6%zXf~i)bI;d94+XGMi13Dx{9>A|zaw1#>p_gnuL)|ST1IHy;Er?h zI15v?Ws%zQGoycw4I`e^0>%poW3F--NhFpfV%M<{;*%7uvG=o-g3!ZAKGpm!{gigH z^TQ8*)sFeLAni?9Gy8Ua>u4Xk@Ct{2KI3{?U4?S%qQ`6yIhM~|x2tibc3DndaMv2c zsM^~Xp-kAQhc{$mk`r%xaVs$YCSNOtb7A&u_Bi9FcsdFv2tlH3l_^}pOgA)NOQ=3O z8?l03vEmeZOADX*u9DR0tIB<7dRPytDG>h{ zYY$MC5#&QJ?Tp-tn2hVzt#L8v~gU<+I=mD4<33>J|Q;rLe+35=AoLAxug~D z&TF_$3vp{|g50HK^}hc8v~dF-xqqOn-FryESXoM!nm4cG$H{(f^hWtVlUO|9cgVCS zS|3CWkkqR$4iCik-(;(V8zlp+Y2dt%wOTX`Ya##YeV$P@<78f(CT_m| z_={l9+%e|~Sni(F-`jbpv|{DX2JH}r0E3|R5O=pgQxxPEHMGK<5{eZoBn8dhDs0M9 z>1!w~I-T!2Supj9Y13&F)6*UP{f}_iJr|5wbqF^JLz+0m79$;StbSn(_6GzMw1lna zf$uYW>GXfLsi%Yr=fO%@n68ihw2oQ?`rL6=?uQ?EiQzqSySOY?yGiA3(wXA!6(e7f zy&q;_nmB|RCTWl``>R)ZRc_66E4P)UXYGdyD3wdd(qRFM_cl9v5v9bG4R@ zaV75Y>S(no;VX1`_w)Ak8I zMBcsRuxq>Q$_E~KSBybD9Jp}!rsI*m&l8M{`u>i?S7b^Ki3RoUQ*GIAydESR_uFo6 z${;tKr}d10{5v3>I+l8i59OYHmF-O1VornGZF}fhv-O@AD@nsBDzzZX&{4QO5V0!% zbxXV6mT-m~|L$&Y!!7FV$c0TkUN~&dsj2CtzNIQow!q@4H{j_3%f~@D+sFf7_2s3a z?jH)M!WKoQwxdtmW@t~!99Bn2+9msYbF`g5>dOewJ*_jaLzfF;-z*-Dz<5ADfQJ%L1VuwM9=yU@rK|u9?&NI{A4}YW#V!mr({%!%haCG zm*x}ETb$5Br+J3V$;oM1c6v1Anw`doGKTz&%}e54x9MME9Fegc4&`OQb{P(x1e?bp z32C6IY-+p=4?81x^_%%5!xKG`W&_&!v0!iu{w*#HVFML z1<%fxBHi+|GpJDAL>ko04U$m-zbXQN*mFEFvy`Iw2iMBKqug|2x^ycWlV-EgTO7uzA3G=U z)T%7NlLDu)DNR&U)T7xGpfq=8{Tg4kZL}7HhFKrfIIB83TXJ) zU>`CT4qove3+_BFGop@)3SBmaoqwn!>uEo( z4C71Z9e_GVbxWPJXM~ZNP!|&mqVpKWU>sqWriNnidce$MqxRC?k@Mu@r%a{SywK`% z-={JWo>fgs6gYI-ZM@CVIpmvTwNBMnX+2UQ19AA-wCE&kIsFxEWTM))(D?a)){^=V z4Kruoj&%JBvLbTbNY>yu8=7xO>8Ux4#Hw210*(=*OrvT!j_UB8-CdmFv`-zrRT`l> z_{BfEv}<;Nu^&}22~mqb{>j%U9^Os$FNxq!{#AoT6Kk&@0LD5sDV8PR7jyYj2W%{; zrq|&2JVTwL_=P3$rp2f_I69%l08#r@KdHmV;o|l-^6c<2G8Ne(V_PLwSD(;NKDtXm zi%c`X-95omb z3TeJ-F|-v??x$2*+PanIaVmD%Vur9UrdYHK%q8ui?>tUR2t5F3rg!GL9GW5=uIk zA!1@l#vK-7-6_C|F6uLj_jF)%_@sLwaIS2^pZO9OLxCbFw=d`x$JCsn9|BXdrJ$pu zJGt|)S~1Uj?{E6*-Q^njJr*jX?(u5lL6^zbKB?WXCe*gX(c~NXq`iOKhT%;yDWI49 zdtcR4B$+%4ALZ2sjs;`?3!~K*9P)z>KS;xfL6{!|s8pN#6khOFgB1E>%d3kaARhN2 z_L5_H=!!&=zDng@Jr+ph#3e3uDaKtjyI6Ybg003uk{fd~X14JMsfhDo$Ue*^k5@GD~3NrC(Ai4CVc?PGP47pxvl zFpOX^Tq4$!=aGhv}0b692WCejgymq{=CXOS;eW$0N-pDflZ*ozOz{lTod~e=Q zOcC%)*QB%Pzn`%&ZD;Ol)XgwgUNy&5>5oHsyqP2L=Ow*ag=8wf4eKMV_{FbN&k+kOa_(jw9 zC`#D=AH~>B&+3b>ma7uIeyMbjvYlZU4O^D#Esd{-3AHIl{`pzqknQtiR_*)op~hJi zr!E-P#XvjX5Q>lwsx}<{IuIn$h1*{BRg+T#aE@*q5xevGlOe%#xnYiBI$77b{i}X{ ze#!K^4Akmr>%m>m&=t_6kLxHRbJb8W^3P>9x^h2{jg93qt<1ZJU~tpM?P3@{tHO}P zK1bv-Moa8|QP~Z<3Q1LYm4|!}f*KkonAe6u*3tmGD35~P;Uu`!+{v%S9P|~5%8k6V z8ATJ0+wDK&W2~TJv`37*R}qE?<*;HsMFiBf`xm=}lxA>cIjmF+DKgiPDLfxAOcG%1 zXv@uI(kY*>tl}|f&Oml{*%PhtSuFC8`gs@SU7Z82A$20^009ZvG6gLyT{&L$&yROU zof9^sG$-Fufs@zf8eJ$B;s1}CmX0TD#Uo*0K<;P3UBxnSsY;1-*}|K~f~zYJy_D*Q zZ#Z~RB5Wm&H?M-j4&HYWWTC&n$3#;Q@MZe>`qcJ>L7ZT##XP;LwJ|1zAw^)1X<+Hi zh)hx~em-oxA07N67IwtjBm+~;$czm;8+2&+`(ASD!gs>bxavS~s6UJSkF1&>`zzGON~s_u_8dsP7G>{!MTRS?olg8A@iZ`xl$HFWz8ElVS-(m!fwb zA{UZvGdML(M&Cc`1KJRpfm6E?T};M~dus%F+1=gMk*DaWe@)SqC8A{4f-Znno$>OK z(?Zpsv{UEc`{Xvm3-<31yKdz*{J>~YBpW`b4t&cu(!+GQr*@OngWIInt4(~%r&;8m z4V&TXR?)p%Zm=$%`O|CG7Q0T|ryA75#xa(L$7D&V{nRT5n-@qrs~U9Sq>0&{N`^c0 zzNGSb6qDFH?W|3&E1EfUR`_z`^T+aS88m-2?88mD*9-EkNUe&=8Y)L%K3g*EW(`C;QuwpLqWGiFqdWWs|Q&1hRK57GhcOJaf}GsV)%G z9@u)WsJ$Qo`o$$x%LdpL4QaeppYB$lToM3iW!@p>0S?QYvf%de@hLb-rm9x@oFtfA zD-Zi)(aw^_Lodz}%GLI<<_qA}Z7(O}lq{Lr&DJs#B@K(;zUf8m?i0R4)Ozqo)7!5*v5TZC!AR}L8Zn#07$D?=}2m;cHO%%|GxH~vh6s_YSxj>+q^j0?yKI-TiHeuZ!u zLXumS_XQvFc(Q$#;qT|C1JnkG(t@~xgV{p=jfZ!45d?QG9&BJj7!BWcuV60(eMUc) zPbvH~_|3nQjz<>ts2&(geTaY~wfkfCh}AjP>D#U>VD62$vYErJuxdA2_4Cr*$MKxi z3_p47U@*n{ZkfLFV?8yz=MBN}n-MO_sH8(trMUv2*N1oF_W&h#Nj`Oth1<~DaaUQ3 z32jG(#gdsef9b6|Gvds97$Z#YPy{J%>r|@>{rhT+0WqyU&!p=rG-YY%DOPNG60}0+ zmF{NJ(o}n|E*y-6yZWbq<>TB3z1EYyw9eF1(Nym~TNjiJ(fcm4+5NFQ9l*7P%b?+m zyFh0;{J87JBCqbBV8lcLPZHede0uD$k31qLK?hu+^eRaKPmeS)vYG?Okac!Ax02|% zTZKZ=iz#XEsUWYhTDEpO+PU**eICg8E;3yDJOP_DpAROlpmA>eC}t&z!cC0#pE(Wd z<^d@PzFu?53WH1}9xgyNFvi=D$R#4&h7YE|`@jjqG$Qi@{LLIBI(&+^^*FIK*E%=o zf?b>$3**Bg;pK>dpe^thQmODakbMQAZ$+B&%1N=}49L76dRgJ#VCzA_!S2*>DNLA# z?1U7+x6?QC~;s@Q;j}Iav@jTgp01;qXc8>7g~6m zYM0PCz+PUa0A7Ij7t+)N4W)v=nFEz&XOg;@uys$jVzx zBpt9R(*zC=fVR-q?kH7#iKErc$?)i!sreSLpmw~proeOx>$i5F^T{Z-^zvTQ%yH9e0WQJ_O^};(_ws(JVk!t0WTO3TRixbF^;dR0s`v!}*OvPoh zQ_!-Z^{oxd_5wz8X-@=&tbz>Ti92WXl{L?I{-yIJ1N@$Gglqqp*%%!@=A1y4|BLt> zHy|-ZI!GISmgBTTyOYJo626sB%#9Eeuk4Vt!FK6o325Yl&Kf=_XGo&BRDQfIF zgq+Irl1rF7C4U$=UNOpq9aA8Hk&I?w2{b|=7d-I|W1JnyOIHoqZL0_3VyYbqkzZkdFDf}hOu=pHvLLY=7;XBDUuf$zz8O_ISsB|Lp)d9!K@{ z{|^0FBARu{j_9yuvPX40QP2ys8lJx5MoQU&UTwV<2^(Oxyb%floe08U*FkuH`J+8Q1};*HG>LfaW$a$13_JE=Sek!DOj9 zTHW(tq73oPetP+CH-#*F6J&#aV$`*~=`Z6u=CY{2hUzT!QMvDFSAYj~ z3aC$MKD_z9TsCv2>J+@{OSS4{;AOEU*3;_)_sqgC=Ke^nYv8cGJIR|P`&#uDidDo$ z#ErauHURc~NVI)6l&t`*GmnLR=Tzj+LduHp3S5fB1n*iU5;vtO=9_q;tlUH*l37z+ zM7x6WXT2^(9Tj8N`%M@(>Dw;_EfwL57v2Pl!C^R9^%AX& zJSFEX$ZST)3o!`^oeHh}$nx?@+DNd3Udo@r5=tgxxe$P?fdk!G)C4@(fqd!;7yn-mzrhD8tH5R=(1 zss5W4y9U{U_}AF!F%61(aI6m`1iqfWz9GwRBR9N^^Z1lAl^7xfiWyBI=eT=@Oh3qW zS910>oO5YPnGmN9xd|s}yA^BN zKi(J49HjDlAhIZ3ysdr*y4k;b88KlMH%erlhFa{^+s$GC|Ub*k8~2S~o{-rU@@X!UiY zi`-mXG%Owfkt8*YDwDa?CsIpgU%{{ViTvF~X>+p~|Bs`q3}~wF;&dYt(xEhnFko~` zcSti3M7kM`v~)>Nx_JO;iBZxhW27`F;YK43O1;ptz?`;T*ebzaib4IZf9jsWF` z(8?9vECqqqt}VfjQx1<`F+*OAixD%_IJv<4_eZ1fF*o8H1!n+oBWxNo!b`IJQv9hZ zeaW(V{I6L|2|*L}KPcDG*JHk2-glfn`6Yg0FO^xj+evus;NqU+$Vaw(WtwJ%Q!r~X zl>PSG@nO&L5JmX6VmUi6QhP-|3Fec;XjY<_N{PTd?Rvg4`5eTUi0Ju3YkoN~eU8cs1zKiwJRMyPh1tDLh0jXG2n+yQ-G_v%1Rj?Jw+Xkce@I5-J=E_O z%Q2kOlsywGI8KCrwsK>iKAT^&Jez{R`7=$Nzqi>O0#vPQ=XP8;sBzD0{whcY)=^V) z59VST*WZL`zH?OvZvlYchr%Ak%`k#slA(g@!+!eTS2xvgLLCac!`_^X2m zFjihXQ8bole&%4FdjF4U$M+`LOQvacz^Zg^rJv9quP=g9pfnUx_UTh(=6+QU8Id{i z|9AgQ7I`SjDLxL9D$C@cl!p!;Z*ny`rO14RNtH{mpa_tG@(aHO@a{Me-eo1AB9DL{ zdUMiP!Y2HzjAek;lRD9$Iuj|MQ>RufxLGv_Z{P+TPfii69op5F;&_w|vS|mQ^!5@~ zVwHCDyyKKre(ft2G%Rs+h1#iaH-Rv!%uoJ}q93*=($TW-ash03J%m0A&t}S#wfsvf zMe(2&e*SoK?2%2?t#_;WFzIW%4)3+vRWg&dq;FhPFH)n;CfFonVyWdMfWNyYNHZ@e zO@dmy`^%;3bR;zvg2fb7EB0HM5m7&C>m{3G^4y3j898z`k9wQ4?||@Pq(G?FNWOhw zkA~me-#?Q2keS-sqE;i5CPWUFXE-)$Sjh0U3U8n!`#AVYPEIa$bPM4jpx`!3OZjfb zvR`8;^(RZrK|IxeRVG-tvt7ouc5Q>hO9RC=`(?kThVD~et(ynhEPiV$vgP^~@RfsH zB3`4ypnb)Xk2-MOuD<+NNBx_R2P&?Am^<&Bvx9B2pH=YXr48%qe1+wyM4K^-qp=c; z8WrfEMPMsX_|v?0}PPEngVW`I`t?eC0t*rNn*_fVS^)??FO zDcJ#u@i5!ZkeufvYe-GUF@#|r% z`LM;mYU>pra~!{By?15ViD78cS%r3SkA^A2J-{@}{L-D7cEz^*<=5)gUB^IyRwfRl z*$wdd>${KOOy%SIkPKeXxlg@r;gh5PmKe=RU~h#dyrBDJ;wi>jP*0_azl<6AD;6}q zD?|SMm4DJeB?V4|L2@n-0MM}JzLm^%ArshYE&}kJ?L>LfuRf=IY=iJSeLrUBr6Ph& z`Wwfe=+UYaZfjOh^w_*LyPSwgJD8ybYp|?__mK=ja?onWa@nSrQ4jHLJQ&F;wz5Sl zZ3P8L-UVOO^#YxDNHL`rll;Qt>{hp#RjbisQ^D+M88j#1IV?{J_%@nmq5k7c2w0*# zT(@}N_pWyIBFI|OMmpQRg>)2ipTw+9-fwaC)ac{>Xxw*dpbl<4D=I4Th}>nq{lJ@l z1A2);b@jFz;5h)7$_?)cc~r8}hiCm$Pu0_ddYDP~iA5;f(0Koj!Hi%H%rYSk%!foPAV zi~I$@;?l9ypLoeCnbx!A2E9h-F;C$Rna*F?@&PTxyAsI$XJ#muKS^paoQ)0|WePxz z;44xTupL9KRu@|LF0b$9bG5>KCAA1F{k3Lm-#gtr>4tV7e1Ee>yv2~Dy=|x1f7zR| zxr3j;x#Q7UdQ5FS^QE_U#(M9c=e_$lo3h)+$mm~h-bIWDC<(_?%<7%!2SMj!dWN+| z%KG*0`m@xWBnMVCgRrIfGY8_NaJLOW?=e$sQ-|C>OFAeD@DGSuob%w`qhNUIx1dus z=moJl63W?>WVpJOSpO@}_3^JB`Ce~uJu?bMe1R;;5nM>5vk&x6h3n;>F+ml$+v~z8 zHefd?-i-6s`0@*uS3xe7WS=OPN~8;FR>zLNP4rw*ikj4uv2dvID4Qy^pITDM$J(CX z-7#^N@*&!p_gU2`D(J7vKNBP+za_Q21>93*{e?rXKNNVZ^*uI)0k1n=jz_=8>dTkL z4aEpkbrOsUn<1%zq7Gqb?yt=0;{^|VQjDxL1-AIX+{!f#ODa}xiYyI|)yp-9FX)8q z&E<5LJeF-rCQQj6Qy4zlHgs{`(-nLx`gG7LN%Wg3$Y-E;w{@pifR6j;5-Y&Nzzff4 z!s}a>;Q=w^X2#6AnM)9qc)>QQdYj>#pq3azo>e^r{5~U2$+EYnXHDZf$1%SD%CI-O zV?`w1Yo&21VVIQ^8;|xS$=X|d{4X(rRnzLvTu^)HCF?`u+AMNtZVkJ7 z>38Kc0w~(gKOFR}S!;|{pB{XWPj^cd^F+0jzv;>9*n;w@6S)AfPrk#Sm^MSm4o0v>2-}nl<3(>mP3LK zwCjXJgV`$2diEz@Wxez%0XX;J&8AW9+(Bk8eoS{ykG?r^z@k-y|G$70C4hf&SUM#H&zd%qZlQ+goVC!{eWyJX~^jjbdnW`Yw-~M_=cz-H; zP2urpBY1~kiqx)mqiZ|881BK{z9J|sIU>|%dsO`Y!k;N~r3xOXXB!D{6)%v7-mCm$ zX^9^GI3UY*u1nf#xeu{yzM``xF0Zl+q^X1#LJ096M-YD?*O>vTk30hZXHER#S6mt2 zkga|kg7tk4^ope42ZGDrnqxr26XJs{tl=9*W6k;3q(#q?7+i%lCdj+J_yn`$=gPLFvyOY zN`e=U-~f;dJ~z!zLH}^?H6t8kYj@&LI1c16<-6@$zYaRx?@N%^-XpnU9N(ZTm`8m3 zgK!Q_A(MK=H1nKN?#)jgV0xf(S(;QIHA~H)^297VijhpR{ZDXW&N*vj+n-R6>MOV?TOEwik1{zr0cHqHYt2t2n@!arWl)t2D^O^Bu&uh$2EbQ|#3Lfl_>Ev5X zCy?i&Tb4I($MjL%D^l|1So|&MFFh_aB{&)rYxc;`$-Q9|;v<59UFb$KK?|^fQZ~sB zggmLs4zK<5o5I4adiE8bqMM{}M;3>ATg`?@=e!OWtsO|@jap9dk>B@`TSy~+uB(lK$tXv%-Wd)eNbJ*i&kQuzuV4|aq2^$CdlDqenPB0yS`Xwe3<>k9{ zk>l{)FiIJ<)j0766(UeVjwb*`+TAFjmk=;o+|%8?I<_jT4ehaNH?MPBw;R!AJ>?*U zQsn(|8&3Gush8m5@8))}6PYK!BzPQ!5^t{7eOuC6C}uk^M+npz?}tre-kUMkh6yD& z3)2AHQt{|&TFM5{%mzP8flst2!NXGEmtUTLK>O(*ojGgPrF=gc>+9ri*(LkFp;m-U zo?A|TtBNQSgs#=7brAD40Xi%G;+)I$V(SWNIk^_Tynr<_`c3irCD)n8`QtnQ2r+bN zo85nk7e(p;BJR&FC&BHZ;09Xi?LYsXG|d&FK`k!I!N+=_|F4maJ|rg4a+(5FMD(=_ zInojx*p`12cN+T`!o^g{;b-05pGSN@=^GDT_$aP2Ie%Of-|hRQsbjk&kNZu|>(86h z5U%cfb&^ae30r>laiOOp-lt@!l=o&M6ENa3ctH|8B-7=0>8f0=%R4KBvfbA&;B%Kv zDRU~eA(Fz>nv`$3;@bG6YW8+wT$bR2{0pStz}o8Rm9tJ&vq0uAoxlgIn^+%yV7-~e z%@b2K=~{0N2$k40Vmc`h8Ga$LH4ay@rsNDg1HBiDl<2@;CG1&df?=428!xl+hXz@v z2S^RqCgRY&p)C7H`J%X=f_@-cSvIEo^J>~ev zLtizhO$DD6aHYim<15TD!B=FcuXCAuMLFG29%S3H?dOfJFrt~ziI$JU4>D1p&hP(^ffy@bQCw#a3 zjj=XukPWo;9|z0fdZVkL_h`JbvJ`muUoIONG?qSp>AgC}SY2-!z_T4XjN_I(lmaVh1K_LZ9^cf#pf4M67h}PtQKbq)$%W{)Qv8BZ$srvKohkJVq<4Gh# zaBwhouzd^hlaa=S{plTItvv=1iDH+ADB%!Lx`8DNDQTG&rvS6ugOPjgHE;3Khtlm^czAb8X4g)C**Til}2^%-T5HWHv*dMt?57dG=f; zXCK>ga-KJPrd?!M`?Nx;zDqE9SY_`F;vkavYV7nJ*py(gA64*>(bXNsOk%I`kP^rz z5Q1P7;y99j+;jg;Aqge>Pq|57kH>F!RU<0e8nf)^bXfoB69Y-|$xuF0rrF}GjT=bw zsL6GqU2O3#vaBZ|;^Ik4J_#VHd`_LXl+-iyVs8I}gt;u+&Wll%hb)aMIy@u~Yj9K7 zr)zDfC=z4W8q^^fld8g|F*mJlc?T$0E*!KJ_z*MyWh>%n%CbGtqok_FGOsh{A*Hv% zZ!5NFC{1lGbE5xo?NGC*o`8ao|;yGa%ft088_c_(L}jf5G&Ik zL-O*NW*}Uw<3h%F836cX<4p(E5=UAZKa@lD9@sg@aNmyO0`jaPbd4-B#L5@qjM}de z{cO+h&f(GM{5#BMDAn)<14}@)pLpFVY#c&2Yja>%8EIt=!rq}${+8JkdxKds<)WsY z&{uxO7x0+AJBkH|YqQRh#_#W)Y=t;KZ2)jaiREoHQBqfFpmYWq_$|q@UUde+f$6zJfphjm#dX$X7Y9mboG6y7Zla0 z#(qh0&}hnM9qLeb#NlLxXPa(SaxV=2sKt$27(oso1GLXXf`(i4oI`%NiZ(1dVR3QZ zgDb&3t^%foA9J(Maip>ho-+C|Je@4yK!#i&-2i!&KdJ;BA78RqF8n5pP(R?%DRs5S z{7@ek)&I2hw=2A!`$ua~+oh|9n}wwWXR@9BVs^0`C&ka#0s{<`?=N6dGlJbL#t-a_ zD3u6qnkw4>s6>_B0tSU0nOU_q8w6yM;Yk%aMZ? zwBsA??aRm(lWw-SP_4?ny%AL_F5v|u+)7Gi^0ttw*@%z11xk3EIQ_}f6KsiW7?G7u zAa|ZtP!uUPhPv<;Gu7+bImdT|4aT*GQhZ9p9z-M0ei&{}D!<3Yg7gH>rhIp=Fu_9o z{`uwlWCi&^l;M;M3(jQBU8HETug+HMELEfKa|C0}Vwwxa(4EZQ-QRWTabt-79^uG+ zuEnrGC-FCtCyVc6t8Z+|)v%YP*@8XA&n^1`lus)9k_oy|!55O77~vfY7Q5AfZgA72 zfoXPOQguj(50B=C6!NeH0yM@6=$fi2h{XC#yGfay4{Zihpl7>zu<7>b+aS!3Z5gA$ zNt_){(Rj>|j7Q5W)s$1tcr{lBv39cdbUb$qK4wY-%@}Y#H5e?4=`rM^CXA}O7lVK}mVYN`q=WdX>{Zn-dzv@2*)!0m{BY93SJ+ylZ9Tq*L5m zOlv}i8Z6<;{X1N|?d6P%4Sq&S@RhU13zxD0x2o!HuN7azSFhd5`< zx74LfALXv~F0q(zRrjnjT6xOZ3Y|SYgj5p^0Z4<6LCThOL;Co+3rk7i$v9|yPEIwk zlz=Tc#x})pt}na_GMI6`P`MGy(Qsg%)gzb$>pKVG>|=cj3Zrf2BH04s5VJHgW1951 z8~K9w=cF&+Ul5NAP$y>gMx_Z5`s+fM#B*r2j4E#Pw1 z7()^%WRd_z!+&@$lX{OI8nsAQ*k0p;+he^I!2aWc{x5le+04X#<052w{EdPNB%}HC z>#*7|wvIC9&Ys$3P_A3c*6>^NvUr(-70n5=vlQ+?&#K)}miPI;y(^y0K=X&JtYkKE zw*%l1JS|JXG2BWim8coqCI<^FluQyHYcT+T=;CiS_;2wl0ABn%mSv;x+va zD|-UPP?0<$pOQcLcp)q|a$by58`^!g5?cKfOlwcq1za6Gh`te=D4@De1N-m5qzuMR zNk$={lJM5K4i5>`!OEVGBVk zo@vjb&m>YBx3?W&cMC+_?}CB=sMTcL(7a*c{Is!87GyHxz_Q3LuclE)jqz&1*)vIf z<@eRD*>@lYHP!Em4h;M7Pg5sCc8a?Npf#>AaIQXu%@F`H7AZn4Y(#Z9DaYy3=R@i; z2oN@s1?an>-xf9dBuqW7JOY(C#d#7|KV*C4w(Yp3E=Q&SilUx6r*t*KmOqpS0n|m| z^*EzWM*!CGuvdg5fnFX>EMor!yFq6q5;RH&Wwkx%aXh$U?9`ABrhWrkSf(D({)FOp z+>m?)LyHm0x+`%xORjkN{pvwkwp2q3ogG$oj~kaFA90&GmNyr1C+vp(9)?C3IEgc= z%gnggNevvcS;l9C{8vYxj7L4ZX7T;0aq}-8Qd=M%3?RT(8QFvWX%>>Lr$Vjw=G(T# zVf9uGaIAsg;$aHJB3S)h80|kg8 zrOtS^mx0o+1}OcEUP7O|V%C4|4(FO}<8Tw+fZxAamP$nfbsYf6-6cs}vLK^@8^whN z5UHSJhjkx0@$=g9m)ZvC!R+$uaZU#K${hJupZnwNYglB~GMDC)heZ4~w{!uWGy0X{ zR7PR$#lHFL1(Wk%n9S<-d>^rET@SP^RYhOIzYr4(+nsr|EKNbjBMbolVWbRNt+w^L z)MOb23=J6EIOeT}7JGn%IR1`6BYJ1U{yUF$Qjb562gDllVx(A(REf$#Q7U^Qt4qZN zywbf+xrxK2Rt>K?s=8JV?>#GfJvMqG*Jv$*v5_As?pxg4MC%o+J5cR%cTar3sbh8J z3!bSzMGpIqH<5GGs6)BF%PqO6KVG&!>aabMLPqIPlV#uWIpEpT zci+WY);WnTQ#aPHv@7_{!duL{norYW-=H;ge$jGl@B@ZO)NM47C|sa3d&^DqBO*}c zuL%3SIISd%6*PIQ6iVk=_U9eF#W`=zn<4A7^-%t>`d9c7+kqO-`meP;Ww=F9 zv7HHkt#xibqsMBp?NCZM-l2s~rnhhM%~p@F2Rd-zGv=H|I+#A$lfRtANBkxmVRz4Z zWMM1k>%L!@Cqb2HarDj05;?Wd47P+Gc#q+Ta>mt!c^mK`3P6Yt%urQ&N*oaw@d0fp z(OAedM2!a_40PsKuvsAm=)KWx_qYM_6Zn(;=-$QQ#^T2p`69nHnrod|>~;L$6pwWb z(hq(*f~{98=biJx|7o<8!-4b>CXJA*KB-2cbdCO}NTfQqt3+G4H%Qj0TVVz*e)qCK z-u6~sqr@GCH~fa2D*sfmLg14Zur!r@-9^$E!Zjec(935FyqZXv%)|*8_88L?8aNM_A4Z7jib$5H4pAws5c&b}hNUMdrNGQ*&k&1oB z)_>~QSwDDNX`*{?*xx*WEGLtto&5IpWwkCV^B!+pZZG2~rnsK@0y}B8-4Z~0r?dX- zppE$_F@K#^eEOFmmbDrQ*y>tYErIs!8tOj}VOuCUz^rCnPXIWI1bT31gUk4$F9IZ3#z!3H{lsH4C%)5d#PwdTzE8$50+?Coe3a&mOV-bV__Y_bLVai{n9@H4u z0phAWCW)5ln-~xI3+eqoI0FQ(!Qc>cR!e`_KKo&bQ(hR7B;)3atLb zD-44#MG(6r8}>jP+8Bz(MjyLlXPU9{Z|mQk3Ld_u4NoH9H3AfxW&M`MTzqx8y_G%#Ie-B&2e9G_Gb&c9)9uazi5g8 z;ZCPd949POOz+K(N>-cxa`g*l2M_B4m{{nL;DQuBDl%yN(r=kw{ ze8ln}*yAr1`$53elyeB+&L-AP`&wn0Bo|6#Pf}sgqXe+kkbE?aD@eS0QgO=*Bi{N$ z(UcVIUFkO`{$8!wA!Y(}DX@40f9}x^$d=VOOFknCnC3(9CU_slPAKa)yNJ~xyZ)#{ zJz~B$izc|d#@%83sb1x{r}0bmY_|`;vtX0!pq&}I^_3aA0jAM^c-x+ddQ*hfLBeiS z0kpH7#hz{%_O#<(T|N)q!8ADNbVQXxjLego6Qg-p*&!(Uz zWD#D(zu+_=NK}mBF#SAF{(O6qg%P;>a`(0{bO4z5pK-;b`&!!+3mAVdnM zJ#4d}%F=_bk04+aP~#|WmvYbf#-vy^QN4r?$%r-iiqvgp$2K#m&R(>#kDDL_Vf;zx zQmGi03nWwNYKblXd*D)q$nzjxIk}6C8%Va=UIRZqLRuzxlWPxBmcYkkkv(Bn#^fe* zHSN-sdE?TRuS5e~q99!HRA&M}!A+$1xIaJU+j}{s-wJB+H^#NfyW}8Qq`ffD)3wl) zO34EU;xil3yb8KhoW_vAz>@EU7~!cj{tj8R*veX)`RF%9!tYwmdjQ&qwjMw1$cD$J zVmsbk6}LEVa@){?L-yJ!=_2Tkt9>(xABm@*5dX{=xVeDeuGEHQhbk8K`meZ8^?coXw(m^>t}H z(zy1C6+{Or7`-u2sW2&*qMZu1_;MNbBc?GKXxf%bO&&$RGr1*1YJ@feDhj+d(m)bZ^3lRZ^x6dn4n(4sF?*WwID>4q!(1q?%pX{uzJ#S^=OBKM&N$-VI79{jh zuQSXOAJKfy2pxXo1*Yf7x_vqJwQ5Q9%CNsTT02YUnQXpGXZ`GRa^0`zvEOCZ#p|aX ze}QRK%LO^+mak2fOm_oec3OeTYj>sK^X`gb2}Vl8G9_<2CE?Nk%*ObUJq!ku%dmw? zcwKkPBxwFNNHXtW2BOD>*Lw?}XU&;);3hIFPsgX!Z6%$3&RIlbGBUm& zlvGp0BaN7gj@D~ffaXf^Vm-PGEgF$`Qxq3JpZZX`%@>AaFm|*gLmg3SAuNk_^rX|+^8<{*^)vXPy5s36C#5BpyG!+gS zg=_?-{D`Sav&x<j6{3 zNcjfX6UQR}?vX&=;Z)ZPdnL8IHCCi(a??}Tx|M&=i&ss=`A;qVs~2L)Rq|t>@tZQh z9XJLfR{00gVRF-~2}0sfFsYJElq^#D9M)x-EA<5BSKxyLf;~DScbtQMcuJcTlMDiL z+A=5fg21Xb7W~DPYwm-6YQNlV6eDG96zzeEs6I|W1UH9TM{tU|M~Ac=wnxT8{>7B< zKMJBGn;08+8K1{r!_8DBjbG7o9|Qmjc-Geu^>-cZ?A`PS5-{7$ADTK)In~ATc`JsK zweJ!eMl?Tty*BJ7?Q}x>!Z9l?#vQgSa}$pQY2JGSh?C*NuK*r|PMq!0XM=22{UZjX z(WR4)l&jWbEH5t?^Fk^oIBBD_4z%k9;mb~n{E$DPk`0mxmu$WI+mc3&Qv+NzTsoNXn#)QBqmiorwKQ2at;j;~0ZHvYXuU|UhwW_}+Tl=cT=~%BtfL;RF zd;b_{*Y@U^T{HkTBdr$$mQ}Hd^VUXfgPDQs9Sg@wn`#+(#nnsJ zZJNYkzR+zI z$GM3w;eAPP$6TOB_73;n76WIWJFZs2M;h=+K@dN9`^EUL*S@r`r+Y|SMz z88`cnON;FG{-@HALhFz;N*^Pc&c=+eyS=Bi2PbvPT>SEb3SJ zYl;7ZSq68)`QJuLz+dS~C1%b>h4_$pS1ze!DxR#eHQz$qz-mwiv+_j&nw!Vlr@$d@ zqA@_kxEz#LKC$}{exyw^)(LL+J)<_>bvQt&kpH=G7PQbAIeR8`gVp(865N!VW*RUS z0M;2Y9{}5AgvNq_BLve8?OuqEe8Xoe29qM+sqt&wO{%IdU;lt8@R2iHd`_iYVxmss z;MilOyGODXYF&k|x}NCXo@Y2HviN}(PyuU*bR@>~Au82RItGK^`)XImA%TDb6F%yU zh#NST55=3Bwnk@n z%RfG6GZ$AGT<#7fYdhb3AyVStjx*}xUX}2EU$WAMyR;*Bl3)s88CI*{?vIhaj|TWs z{Yl6a;3@!6oBHoaG<_(qJha@NhU^|oR(J%gj&UiFqI(DUGF0J*Mo!`(^G0*2-5*ZL zsN=EA{bOWhWjP5{K^dZX+Q3$z;m6ha6)0OR&jahVPRQf7gIAf?aRM4F-hJASKxa+p zEhyvpAjhkU_ZcgtSOdy_Mi92MJQ>ssTC#7U>j{#wnA`Uq@3gr7RU~2K0R)`@ezTd{ zKmaBM+zzw#cg66Tj9<&x7QsOIkig%Rox9}C9pQbqsHr$>XqG--d*Rwi+k6%#nB8xa zjra}rcfO;P6&gQ%&kT(K14@j~k};H#&x@@7`~qioQ6QhxTE%+B_y(SA*;B5(qE2yQ zlvHocn20=n+D971lK``JB;FaUOb#mjjPhlD_vz4Pup_?l!p%T^`nr162Tnt%$0yCE|~& zzmi!|a)Nq}GQ>qZXDX&tgiZY3b{q`|{&>K(xUY>qMdv7PFbQCwmfHiH8?Uu3e_m^k z_WP_lezwN%O3OacG*g+AQx~x1mmC*@`)#0F-tY-j!H0y=FK2cb{eC4F6e{`~vTIvV zHHC{aF11^%xIKTfcOE1Y^tw(xu}I0=&APKMosT;4eEmOzYW6I_?JH~%AbWCaYfBqg z8Lvw8!o8FQKBX8Q78_#W0%HdEST2~DGu(iRu>y`S=Sh#9_flY>{C#T@Q`elcO{G2) z<0r3A=Qw9>Y)bTQ#F4;wzGE`~smgrA<3X2FlgjJELpQ*aHWeEO$w>qk*1}F#Fp)jZ zFZF4H(JJHbBr^5>6!~arzX}MIDd5Aq+cC)g2UY63KZ*Cg^~y{vhNG+Lpw7~ni8S_R zcQv+fR7WoPth&EC%x=b)&-Oj!ksJw|ZgC3$OW#gKPRkJz5iL2HZZ4G>TSB;+vpgQ{Ob>Wme*uVbZlV#2Ypww;s1w%N%`=1rg&J;@*xqvfMR zgT_xCfp*I_l9CCk3K-W*;24=w%=UpnCmEU{&`}_x;E-^p9R6m`#R60a&yyy2W@suT zPMnKG&(2cv1QRHRNEUD|T1$qc`A`HsQ3mNXdQ$LQq$-TmVM+6>@g9URUV&a^1m!h$ z^u@Frjd`0i>Ig2M%bHmq_63wFL4hG-W_;BC>oRicK<9m+1CGhu346F<;lvvRiRrhI zOHIBN>ZdO!g_GSoJP$V_ig@>r-gRzW{zu=t0H^IbuV_8a*5E8n%Jj6OlEC{ys;$m= z^}Oe18(9KOE$+NG)llZClaA$>fhCoZl}V-?7Dqeh+)*Dy1*o82wQSD1PmtsU8KMfu z5kkKQ1PVxk(bbcb4M2;LQ4UW$MW;xhYfKd34FQ^6KfGyHV+(_KB9;5_RWIkoaB3?J zd4Y)E!tIlX9=IosHSxGyzE|e5nB2A9P+zyWqQDoUBv2^P2ycbOumBfro~o=!RE&Fl zCd#;6zxXLZ<^c;IBdtf~GNtvVjr#)_K`M~w%y?=H$gH+H_y&c%P`XvKKJ!nhiT|9Z z4Zye)u#T55MBlV+HAHa;Vjh1NyYfu~r}nW;<#jGP16WhGgDby=w=BeWC4fH;{X+y( zzN+(*bgrEwYaijoXSu+xZa%&+_-wmt`;q?9K$65pa}vBGneZhR-xk)|7a#aKQ8w4G zsfs9PhhGxv3ULHto?2Tr`;cPY(`T?OOkypT9_lP^HLD(~tI=U}Opa(aoK;tgszJPZ z(ic@bNAyKyS5^=U@aC3sbNa4QR$&}^?|jDHA{x~BCjOQ-#^B)!PzI+CUCneH@)1}0 zmrWPv1b%*Uk8`h=jeXm={b5t*GbLespK*A!56D@zh$V&PJpW5?AsGPe@ZJa%^a z=2_BcZRo?QLH12D;rnYqe&TfW7{$6*^w^pB6v=co3M3W`AE|ok%s>dno-`;yfpU!@ z;EDdJ)&`TCR5LDp(Y4t16-F{(jjD`N$hwnuF}MX%>t7*X1svC|Mnww9DdH*==RPH~ z{RB8hvjp)mBmWC^)=>qjgBUNhG7Ip56^VEcNE3GA|6x9;#`=kEp2h|PmK6{OKECB@ zOfXbCYD|J%X!X6naK=e1+(xq~`-3_K&=HTpGNJ&divAG+ayX%$1VDYIlF=FfPzo0X+yo|Wk_U@fS<*k!;|w{6 zHV9Up{_TFsL(*gA(PX;Lj&vO&mXHTx!w+fMVee>@5gBOf4C`A=$hqu~NXe7=^q|+p zCY!J*uZz6i9a7?ou@7(YfXi8<{qFqyJN(%LW%p9V65BwYP#}SQjfp@K3U1S;=8-hsxForP4*jQT?4O z#L)4&EB%QtFZGVp?lJ~Np{mQ#VO4O=P70jwpQXRte-n%&#_x2o9Ii2{mrAtz5s?!2 zxi*DR_Sf53K|;y!f(*5b)FI_`DvT;a8P#8kCjrvEo;Y8(0mHtwz?+2p3w4gKl)C&* z`I(VGu1X&~6AwQFKIe>iE5MR%nO6St6FL3W?fOEQH7#eJJ6laNU*cOA1Nuc7n+*Wb z(MnCa4p&>dcW+NrPSXiTMSW2L#v}qD&S72QXY;=F)U%72e5H;i0P->AYbF$eiHdWa zD1DaW-Bc=^+@@oUfKlvMmjXY$C3w8xgP_T+&o|4DXh0|P zF`|q56sMC+4#ik`ua2Vke0O_y({9SQ$!=$sz15NQ8He?b0GOiCYF@F1LyGSMhm5qm z4ww`_5xhU=RZRb^y6$FB)DSOBqau=%;JJMsK>DlDL zTLY_uLH%tRDHePE{!!^q2lrD%tJB}F?D$Ap{{d@~Z8$z<8g!Cl(*tsK3aH$4WM8}q zb7?gPRCue&`eTtrDO7PIFVeD)45t|Y9ipRT0h_m-arp^k&5%fi8`)F+&WMsGyB@yq znvLfxqJ7#|G2PIeL$_+ik^K=K)+|k@W$&7LCBRYU!L`|uhwa32Y?l0)Xy=@AM8OBJ z$t{g_pj~co!=i}551|H+_-~=#MiozeKTkWZFGl_$0=-8@{nUD3d!|65o_;JYzWS=s z&ssTrfS+VWvqXs9i7Cz`P7f~%G9Rszju3+z22x?G^q~aA}miGwdET*6KDDz z_xXE2w@nvDFnx?y7FiPeSZ;R%fXfUx;4}8``lNi#@`{)?wWy^%wJ}4ynChv0r2YRV;mxQ@6kmR}#yk@B zlz@g_;&a~Pjl*y^%p|kp{K6OG+(CZRfEk81M*T9z#wi?>OWx1XTb$*jB^vpf3o0(S ze%U96(&Ud<7ET;RL#y(Dz|WsQZJdD|WqG1wB1VPQ7!38l7W_G&uQtb1nvKhpg;aQh z(b3H(UpW4R0Ej0>f>lFKwa_C6f;OTPjVW5z@fDzi7t-*I^Bk-*c4@aUZXQ@gxRRDq z;UJ2f3!RG9EMIpUH?kj2vX!$pu&ZBN1Q@{f<)bo-uKKxf4}L{HoeG{wZ7_Itt*9RI zopmFJ7X0*y-xpv*ZK|YOZUv`?Uq#DdrVK`9BJ4DpaAF6FHw4hygV2!c{_L3j^A{Hu zFEX)ngI_H?(cWQ5*ff0|_o=Db zoa#>tDtVIdAQ6g#hv5oL8YgvqUtKg2J5}dtH8|BdRLX|C3X(lv-q>&eWL2=g^T<$x zKM{ral$0V%L%I|)nhik!6EQqK+Dzf0mlJzvb7(s^tD{Opbt z6z)d%id^yiPX}7g)`6^8R{itE9;dEwFYa|4Kp#QzvoF5=(U&B*4|Yo^@A%!=_Lx74 zI;F&4hX1_&tL;sJNqfSjHk%EuvTGhrfUb3dN~+qdPMk{^Gg}Si1g01a9=8sAV>e^ZV(yeOP!8<~()@zeK4|6;V|8|LoBZ%2dBF1-(f{-u zZ^%@o62T-7nP+|R&FGV4#!_tkL*Ic!zDwhWT@i6MK=sM8`1z?6BcK~6!@;3Er)bBj z#sdP;Q*;(T16~$!nd(b?GOC!P0oZd>cOc~;Retx;x9h>3o~Q#}Ef~NrHt@?VGJ0mN z%iDMr6kt-RUZY0yo~QufZWK3^`;UGTfAV@V^UUoN;CQl8vkgfjJv^1b?!a*D6B?B@ z7LbLs&#=0)N!qw%$6DH`!^{BG1k}46{4Wf)aUL)HzVhl! z%iu=oncmiQ3o6vhoTSXPei!@FjM`UtmiYn+95j}cRh5-pIq2UT3(Kuzl| zhF>!2ibj>p*!?oLz*{PK32h1*=b&^7eB%*m$`3ylg$}!1!V)_e|Fy`f@NG5M2M(U? zDk2BQrcJ;ebB*gD=136x)b&|@4dbXA6KONw^WI~!boPy(eaD0GglrB%AJ=~kJUo7Y z-V#ipMqQLx(o%am4vCqd)-wS8)d0hG0u{WpJfXrVBc=>@j#nG6FHfMRm{)_F57!Y` zV2TqY-VHd#zbFMluM_Q(&z`b3G6s`V3;78j{0F@9=Z|z_4~Z*f=fydn*f;DFKZHL} zK2SUe+|nGsURhg`EYRt(8f71q{n#9~t=ECMnxrNn23@gEajr$yeZ}YR7D)mH(3!^4 z;J+DO-?R1y!`%vS>DjWPPyWyE#FQ}P+-@5`3MC&uT0wjaSC=LW9?m{{awXS@HB z_kT)uL^7EE#1^@K7A?u>@%Nx|l)IpCW{(@$Hsi>1VXp+UBS0z-n-;F*tq+Mpy#Obf z2{!MV0a$-OQCZwY^j5kJZ9c4V ziJ%u~uo#C-ZcVju?gv6P-+lS@q^~~8M!waFif1l>g|yPfU?8`2p*OkXSvvjmnIjOA z{#1;egqZp?8nM0gT$)TYkop7NmAo_WK-*|up)W%N(nAro zzg;cT2IzDAXQX*QxpXT9oe+9`zMF}I;rXx+-gUS7A~OF>J7HyD}DZu@OFqnfDM#b2ga z>c#k}_}FkM{As3?)tI-YXHz&}3|bAwTaH$Jjq03bxczS|8}z>Z#w<9PIgO<2b#G|c z?qp8eL(DDBOvAPxx54t!=@5&;<71+oXn4A)b6>{IwW}uY4dxyXDUB75-pPPHr9~R+ zdkG{ikv-_s6+&B&!uo^#7TodB&2B~e05s*}ABLEiXnXSP)p2E|Q#@a6oY;Rgych{T zL}?$=9?qTwkl3BEvlg%&*~d<1eKK6I;cInOyNTBG3xU3tH!=9r%YWA9HTq(hGA-7Z zd3Lw08FSvO+uHlNZ7;^^?tz*uo^w@|sCk~bl5OOWllxCGf0ZYhvjcoBTF~K|wY{LM z7hx(9uVH}LY4h$*hRt}&Z5IGXK(vr_HwDS({mWIk7g09{K;Vfp;LWF)`ElsS^G6`g zR+(y8>4@4;En#JK6&ztfbz!)-PXNh;%$269e|+C!#zf?I)&|-=3G|0}k1Y$2x=CiOw)<3dm ze{KhK=L2vFFR!JjB=$$QPVPe5h83r|ZFSx&wZ|xHl)Ka&Q z%e+~T-PIq1J1vn%1Zy1`|XqU4{Q}6e=Ib-kk=Hw9*0Ow_>j_9 z&P85f!4ar_wGE5digo7H82CxwIkkJ0O*=S~01hvbqI}b*Y}^spl88R&X3geu_;j z$D_ZEe&@Uk2gZ~8uROnaGveFpmQ8mAjs1C%@GE^Cqvsg)0_9|B!l7)_7wjG^*pjtYt--hr^Ez!npGM9HqakI+paZt zB5u`}NX(1C&kuC0bN&&7S65B^CYv*s4o(cpQ>&prRxy!0%*ZF1M*3#0t-8fsmxn(K zdfy1iwF!QV+1=~h{<4MZ()4-c73I5yqd+Yh0v}99lf-CmeBh##%vKQ0Zjbct&@k$n zKQ-7sGGRwCIw-imEqqqI8hw`%56Jtf4NG%)UlJ8q>J%(dCCSIwa3?d9m_P1+)6{V* z>y-hopy%YPcojY7@OtHo;+{b3(rWU zwe;cSPgvy8--OPXA(7|ikUJ?dqBpz((xCxGS8Q9TYq@Bl-Mza|Z1x(+96(e9?U4-= zGzND*v;S?3!;W7F6v*%YJ|&-JHV4XJ`rEniK3D~bsp3&u&Re^Kv*?$cKkmzRtNrpx z7iJ>fO2^pdX|sFhrgJpq`!=^2mu~Ss5hs^gMYbCok46XI&3aP+)QiVTJuowf)z1%L zRj6>)f-gLowOzQK-MlDSX`}R2{ITKq21TUs&;BpMk*e)%Fde2#8s8W`YaqKpI>RD8_bpS>HKFFlPBaUP$hIe*u*PE><(|zCL+_ez zGS)8=sbpmVy+#*^T+MRbR)CCN2k8yMq_@dY2k}ZV-Q+K~R#yx4i_HuRL@p$N`sU+0 zxZwL(Abx&rDTaeSZaoxmZ}5QzQoSl5gJ@Jt(^}!pl`X#hW#N6wgw>7rV5%)e&*wd` zS&ik4Hv|Ag9dh9_Xp+w9Y)ze<=P~Jb*6D}EN$62j1KH|X20;DTfqpUm^vB`SZ?eIK zKsM_3A2j#ujXq6Zeq##xBt&A9<8&>lLRRla9cN6cC+bL0ePZQxdiT%ea$+Usua6#^ zCoFjg-`@xVijO##{kp%E00-|qA_FpTU@RpJNznh%S@)$fVJ?_k4pv{(OC{TFA{$1t zBEZyLmY=;&H>OhA9zj%ByR0^S7oBQ&p0#wk-RFz`@*`4v^Esli2YK^4NF*)r=gY>% znMY(e-{!8ubD)(t&5CvSJ`+VGkju;~Bir_lru!Gc>SQuA5$k70I->+;6$(XPD`5Q- zsdhlUDM|4tFw0PI6u8vTj{8lCzw85QcvcGxv?@LiNQ0zrTFnOTjy zXu<@^Zg*e@QlA%9GgVuLKHOp2J3Jg)_0V>aiEIT^+#de`ol_1r~!$T%%8_!;J(c6tj-?EXQ{9wzYs zg;CVcfnJz`ThTb_mbXN9BIrs!p}pCifgYDT*igi#4ir8;>0l=IpnmnYin|eY}>5 zXY_S9(AT$DCX#M#XQx8D&@#-D`04H_0^rrUXjv7)(S0FYZ&+5*kk-){2SH5AozxV-cj4WyhUf~jp z+Bhj0T{DiX)pIl&&DVn%F1@I4ECrJ1?E8y@p_hl{5JWHoFiL;|=@XAGRc@0S{>0Gs zTA`g!mR?tWJ3#j_W1o2wgYQQOpEux5JI(C5@VZ9OJQ>6Stwy*hC~W!4mo_)KUD3hZ z!Et3BwFB-nWLn~748{}G2F0XFz=&TKnUA%MtU&7oi?VSad^7-ppfm9{wf9(>h*f2C zmlAN{j|}1s@Prcsk*%rMZA(-gpZ2}-k%EsxafQsH-`fUFiYiD5HL%H;^vK@ufRx^n>XG8zlBje2VUw|Z_m|l zGBVzH{P61a_~DRXyMqsk8EeeroH6%ZbV0)JjcY5}>(~PijL@>@Tsm@{gua|UF8m@~ zE3ST;ApYV|3@#ri#Ab21Z8ot-nT z+LHjrNYSg{+8KFZcvi55;aKwe0f55A2De0UgClL zs|>P3$KuvW@(&sxfHnj)-9`xq?_2k*7GARBfaqcEizBX}vs^@qMd}J2|v?KWt#L@XfW3 zUujzxcyj+?u*?;VicDAmG=o=$_6a9L_&n*l`3ciL!KLLZQG)fyex7&M4a#+lXIv7U zQ!YNAQa7Ts;-)`6slVh5l&*bIz@}O@o>TX+1$J_A`CURm=BYo|>Myi!I@a0p=9wIt zE$LRV0JUB;)I(FMMMMdLbW#@5p_^#fC_P(lDgNp?&$jC!&!hi7k;ZIZO;Z)wbcQf6 zzdL2p))&9=W|CX?Y(A&T!~s!UXJh2QU;O7<$?suz8sB-K=MWHOWPHs-Jk6Es{yF=~JKx3zt`o~X+bT}PgO~X@QJ^G*wAlj4 znkIrvK|38|lee(1a`BK_ifeGlTP@i|lqNwnul2X)xt$pS5LPT0 zDYT*p{B28g^qihoXji9pS#tx^GYxDj%#+YV|Ite7Zvw2zPsY#dV%f~3s^0=(r{m&S ztr8n*FOv0=H3iM7r(-i)RZL3sNmh)8>gI1P-Ha&6g z>^J>$5M(EaO0JRJgM69W)C&6q85jFHBi09sq(=K-f_H7CO3Q3TFZ<4_JgvK%o0~lw zXS#(~axNQ~RpQ)Nc>Bw^!tyf0TwFZXU22T0CO25qo2{Adt<N-4TeK`v)Zwy5@9)i&RJ(( z{S=j1*w3249jp(IVxl*hf)Jp#W+h3Peo9ua|4b++5S9~!%rJ}r|@EiEk<2>tN=!kml`0gNYpZA9kh`}SY0)AAuXLt(=repLZV z$4fYs=dNTQwzd%=cy91q6nMq6dFeCAK$%**Tui)sn8r-#-Ho&cH?EDr^QXv?l}+Ry zebHo`VP@=v%Zy{&chb#g$pSNYBc_I~3b8&-Z)8aaA6tJ=sm5jHGN?RKxOG^(p(KOX z`kpRxnJ?FY<5snV)f`?-8 z#{I_Zx_1IMhD|vdLV+|4yOsL>qRdsCVlrG>VgG2QpcPz#tQ=V#eDPciK7$RAleMf# zgfEn5e-3E1;D`@6`4hES7#LzTm~ybFMD;82Ive${0rq52_nHb`|&(tq)l5zsd; zaL?QQ_r175M?Z8-&Zf7ViiEgA`Xx>Ou_nO&)M%X5JVyz2taX}-fm+^T0Kx2TxH);6fNg{eEc0cg)DDZMQ@M8H+ zqU=8Rkci^klhVO0>|Qb%oru)vLB_$iw`3V}(l34yWPKO}25gv_=Rfc&8*lWm0wDUT z|0O#bEny=#nc;S<>McB7J1I@u>|av04b$JRc=B_jADAAhC=vvOhmT%$y9a>7)H&F*7l&F?Zj3 zL+DcX^R`4~wvdE@5~_3;oqIk1Lce?$d<0MNuqvRRF7_sod=)XyCOsG%m#$P)1T=sI zI%2-~@+|AOWcQ1S;LsKpW2s7upkbo!R+%4`(JtXhL*_d z{nccsnnefb#aASNw4V(FJwVC$e`TAjxS#1q_QZ(_ya*L*C>&e&Jh5F7R_g)7?ELnN z4@f5T(~#@gY})qLFBpAM6R~0GcfC(FnEW0MRYj#g|2x^_{w+M;R<`b$tS0)O+5t2e zyn@rZXvH`LFg?xFtQg%_iCRnkA=8YQ5eiu67Vsek3UhGbFziH*zCzZ zcr{{V&lkp}NqkcubMVC?pmLOeSvV*64W=qdm4?QpNF)Z?ROVb+Zm zg&aPG0erHq?LB7e?)k0-eg(A#HJQsY-k-b?vo@TBis|P=cbC4;n)cpv-*NMU51ZVcX`wT+5Th@;-;v9!Y?06+%3Y^E zl6%Q`?!DT2@mrkCH<&==@OQ=zW%j3oG zY#*lmxTRJd)B2?=YIC97&$z;{M3*CFMuadb4u8Tq^3nA?%adCHD|i18ZxE^TQZ;+* z-x#J=`lXowKJ3yG&u4wu?7pGmp+(sPm?u=abJB2Zm;jU1$D4A4Am=^iU4Qx%_uq^2 zp3Qm0^`6~q+L>w)M|S#@C&+?aRCw=*p58I?39J@!f}~dn^sm@G8;jg9Xv!Q*nQP&% z^H<^RVR#2_StR4AQ-%%MQ&B%9!uU60a`Aj~hxg*ho>i-6DXjr{>D@s6XZCZ&0exd~ z&#{%BiIeA->X&NXkr%YS*2As9=u9zq4(~II@D>Jtqi|Ql#cN+_%O9IKdEDimVP_bm zO5alUu*go5J^IqzI5~Sia%KeB_{_-4iwZxgfxVQQN|cMkcqwk!+1Rkz`c2k{EGwI= zLxqpDaRg5RjRz3_WV@>5ihP_f0#9k5-A{vOCU1Wq_e^H(w9+>ef| zLaOvCI$ojyPNJNzwUM(wbK+SV0oize@H8!%lVy{qRSM%SNraIiG+`LZNg(6fm-Ubt zx{R<;!uvY#&BfkhdkQ;9)17sxcG-j~u$sJl510J764()YJAhLLUNh**JPj-COi*2$ z#eU9#Ik^JNr}2xrhz~^K4nAIq*zI`MZ3Hh+%?sEA8kc^8NAkI~xQ8N5AFOX0>d)?^ zybBGNQOKCMJYCtod+nz{C@{GC{{6Zd*2IG@sgu(i^`s|m67HbGjRqSUH5fW#1bbo( zBFQR4&pV*hi+HpG&ODxt!GrXoOsFs&iy34w!NoK-XQr2D~m}eoIZJ zQ@ffYKGjVbra2H}nQSDl1_7vIJeEWm<0q(dL ztgAj9-)NU<5|v%G3%=x>hGASpEiC(JuGV#CL{f|uMZET6O4fJNM4&~*6H!t}pK)uC z#^cDP^cK};+zgV^{p{A|B+`YJ<9u}t=@b2a&eGiVu-I^=jI>ipW|3C9BJ?}7!i!CQ zoMXyihi}kKI`?P!L=1id;`^uqGUv9A{3wmzlHZe%w^)1ylx0n&kDPNgd+$z$77xqd z3^(Rnq@YA8+~V<4??L8N*v-|M2j!T%S5yN{_v!8i=@>y&nwR7doargJ_puP<)Bg4O zCb?uy^WSQCrCM7|yG`+IDtQi%mdw2$VFNN7Z4i$wpuWi08i-<0u)fIfzEUglirTd( za@Nh4!5{4m45liq(K>!GqsW)i!`SXa(?=@^#_{;$k53~Kto&RkY+|>b&a)BHim;bE zRllcEK%LEYVQnI~YwChcN=`cOnivU7d}in(y7l-kUFI{<;b&zFNnjJH(Xn0Z6MUs% zQ!`~`!uJEPm6bz-jYLb-H}p0seo(8aF?QY}&QFSTY0KOR#i7eXt@pApwAspOawYJ_ z6|M4z9Xowh)SUjj7}5tLSSzMD4aD@#20?&e(&({~PSO!`x`^jAY=~xw`WXF+A}E@7 z$2CI>ZuTM;w>W+#U;*V-g&lZ_CNuT^6$Yn>*#)q+Dp%H<)n3J=z3PhE2E5KtL0x3R_DXqAPMgZ|l2?x%I{5#c7h6%mQwJ zn3sm{w>KOSm5?OPX@yO2i0Hj{07yY1NeIEx2BKt3L?I-Se3*~CDkkWvVbf+>4V+3` zJHZvLYd^pImLl^na42NaclGHXLbcZ>sOp=bH)ZSMaer3xCt~tYWM+GdRD^fs3=DW2 zcpr3BxK83co*Jw--hZLFTpzkUn3jQyp;FURio?4iDEg5MgXT-}@tV;W98TT;pvZ>R zWQyAWjh`vQ7KlV>fA1ACzswhW>4!>i>Y3zpY;$Z5(k*2jjdwk^>0YWl!X4txoO5vR zt@ZG*E&0B5R0!VR@`(!Q`O8QFAq;TL;I@SAs5ZO+#c3CImoG7q(gh@7r+59Ckj z33gh+^?FH;KL}>KfHiu$(}W_|9ZsPAEU|5|GzNxEOXL8bY#BmOTM#2jK*f~0iGEBR zJGF?~zFPb>^4kkZNBU{;7n8RYG)t?w9H*yYb_J*bRdh3G9IFPyY9iE-t6v0Z?~@B^ zl6j){&suB1u^{BWzhfI`sV4L}99j1b4B7fKBt}-V^=N%@yeYt8)^viFS&Qduz1!7S zyuI78yO0@quUIUJU6Dqy)q z-W-3mw`)fvT@|#qn&Y)5)nGvMp@_XRK>~uT70k5^Sj1v~4WXKWl&1x&#J{7GU^mLv zrh478=Z4Q?tPAaUFsn{8Yq@Wt7la}3cvJJoD|CrC!s2HvQW!ldxtzz2D>i@4m|OGf znTHC8X&1fUrNzA!P1M-eSFmp!U0wYAwt_+9ln++2)kRX_tXQXh-kU1Apm^)(1#vkF z$rHUMtX=VASXW_li>_m?a}U^Qz)ahTokm918?ENY`7&;=%7IHk%nPg3djIckWT^4Q zMF{a-N6UY_3f*b|B~IRESzj?#MNCVJCsxZJC*sC}TtF*N4Kk1y_I&A@q5)4hE3K%C z<25F~AD#2v%Rt?Z6%xCn&pFQLEcfFUQ-$&AclV86O<2U<2v$E6tqv0*@&JNnft>kD zC`AcGzse`xEgp;9||g_tg?UL3G@^Z^7(#R1`1P;kW~hkonDG8+%r zCp8o$TL*z%ni1a|pj;W#;&Ic(P`t?XjpfxNJGO>8XPYYKFB}bHmx6fC8^8z~?w8sr z8P6AtoRYp&+`Rg#KRhHs30X46$p?ARiLuI5pMPXLbOTrGPCH+hpZ6=xdK(D8RC)EADP zNVf^awb&`QnQ?HB)&U>9b?D;cPZj`b24(A%$q2LQBzsS-5fNib{4xxtG4hDTUow8$ zEX!DpgCk;zxx0cbF&D+??VgFY5H9$cN#1J~!EFIWzk#%-fNLn>c1b*cwX+-3`sexU z+f$o)#yxb}FI6bD-Cp^**e#m&9%3gU$k;TTuL*?bj>pVE@d%yQRE~>X+Um*PuW0JX zKRt#?nt8{j`ER=S8kmzSn{@TmM!3xC?%RM7{m@n81iR@CD0c%_;)PNy&j|m$&#Ob)6AB>zn&F^I#fNOTuW_jYyXChIH z^{Ma$=-)dOA?d83{vc>KY05zf(FEcim;q%NL}^(w4}}>57N_G7(i|9!e-nJ zirfu|99w8)3Pz<-YTFAHkU>xMVMv)KDz8U39rNSZbV1a=t*q=rzx!0`h%L-neB`N) zr=*sW4N4|@iZ*L#ky8k1h+}Ic4e#+x`q}>p+C7YohY@b2;&Kz44)rJ4t4f61HD!`{ z$lpg@c>Gm`XV4u#rwiP?ferf_(5YO9wT}XbGR{Qrk1eyF9cQ|dF?(cD> zA^S98LJ2qr2n1P~hQrOJko(CvRS0D3 z2MRT!v|K4+V(#s-r3oW6kKudVQr+8&^+T zsGKr}BO#8cSX@J>Gk4Vp)~f=nh$sfmDoQr-GY-CmNuyq=v8DVu^}9P92bnVAuMUPXO#ht&Pe9bUD55NZTSr>k$!MCh zwoe_Fq2<#0Q1#?H>JZ-#CIOgm5|e;jRGcDP3dp7M zJvb#ME`o);hkBWyo1fsnJO68txG}V#XDR^mN4`YTNp>IN`f0V@qH!*UPAF;qIu6|? zZSIwOj4E)m?V${#t6g0C6MZl1?pcL%^*vP4rbgOyF3Ki8;qu0ewbvWvwjEGis}unK zeCIynhC@hbK+o7^xG+0*E(0_Cm{Jp?gcvHczDTkXvBJumzs|yM-EX2^*_PJS_symX ztJS5%>tu2*8%vj*iYEk^FhJ`Cl@OARZH)7M_7#iC+e^E(2`Qgp213t_42&z+vt<*P zk2D9Q+TRBsd=hJXxl@c$)}EEx_~$oB=B!8wzwx$B@zf|O{H753l1eFp+j|82N7)43 z2NDrw{YzdAb`a~#?G5iYYZCF^xwbQ~i7M5?kJ5zAt5x#Xam6+3i_CXUxR-PO)v3R$ zvqgpdz3YD<8sf%oFZI?Y0De-}5bDA%bKT$31l?thn09?112~W2KpCp0oG*DCZyxI0 z@aTXFJ>HbSDSn{;eP=u1E!#h8i@~CmHv+4FtkF-yfD;3R49;u+ez$C*vT^42k_V#k zYz12ag(|mI$kt7qwfCr^7o@m(CB<2>Pcen4`J$=YH`%>RpZ_yF%j9JPgOGGV^EHwc z2f*ri5wEOq4VwKJgSIq^c)#}GVZj^>k6=GO!MAXHuYJN*tM2?B3Ju+Ql?V39l<;1| zYEWl2EiRf4IeFcHM{Vj2AOGX3fG`HQ$G|G3s{CWebus*cVeA`Tj8JVuCXKTrYVP)u z<(lbQbnw>fcT}5LxMB~Vob&csbYtQ=JEo8*K%`*LZKB9uPTv1p? zN=0HTgMSVQYZhq}y+ZyrT)h;zTho4hJ_S^F$Ky=S1byC&>H$c?`-xw0)^4Oay^on1 zs|+YAT{=t+Mjzs&Ik|b)KS1SPpiT0D89};^8U}Gp2wZoGDJxt71tXk&-rgJMXn-#gh1- znGVE94k1Cea^YtMY&rs!J?2z)lfNtMABN9}iZ|u)_jYo)|6z{37Mm-!GY?9HdbphV z(5k_jKPj?pMo?wZOsAZ}K}SZe$2A~tf!=1iw3lwb4pZZJ3nOcbzkFVnIg$V8gv~Jp zM74_!o7y$}KoDBY-4y?fwDE&QZU9d0(Cwun(D-+U_fWpv%%-`q-BjT6HDQVO*k7OL ztD+NAb=g+a(qmKO_x{V@=$Dy-Qr`A#+zJz_ux>#1@=&w3E zsW3+LQNC@Ze4?)h@=2-$6j_sk6PM^ru**lC=fGA0^ME%4D7(3-+e`biSIDz2l;q74 z7V8tF$)mroIXANZT`7p=ir&|<&RY@G>4Fw(vb3CxNWm#%IyD%36f|bOQ8Pi$$a-r55M)m^&z7hgXgBdsQ=H*z(M+$?HXv1lTqH0U zxX3ezEg-duY<56=i^Rn1L4JQ)BCd-avh{NX@ZmT!GH_&ewKZo6BQOI@%HuggXrTlA zX}Xp42_F96y&gU8s(5^>34Ewq;l96u1w&kRc`=*hCN4EKSe{xMntYU|A_6TfE+UnH ztEA3K#bz}^U3mhHnwNG!iBv1*P={s+2KBXaf$zSrF zCaN7&rz|5rp3fG5%CF@ny=2{K(Dkpd~R$SB4QNEyMFrE{X^VVR=bT%%~2$A21Jv z8|rC|`K3#Rs^~r+SR-WXb*4nY-QF?gomXE>n^%>gD-BT>8-F+cm8sKxLn*7Fvb$lJ z1O>!tmh(}oJ%B1ymYYfq-kS!VGZ4?IT}2EV?bonk@d*~L@1X*N{u{kZdCw+kKE)iy zr;{sDaQx%!Z5IlAxRl@zWS_|UkO|>uBCb`a=Y;`(W{-JC-Hh~%M4tvId~!T3}QBTd#NKjI1Ug^kgO!rh#4Pr%d_CCHgXK}YhrYN&{NCoADbqI z&rcjmO$x9U{UEI$vu-Q}8#BfA*kwwn!*bd|;}V=0v*EE_28`Z|ni@$aOd8B(s~E!5 zJ)HVmKRTSWbf(5O)sDiQB76BCIaBVi?7Ve#Jyad(3IOT0=+mexWXI>G(j_Lxpup+c zB1{Mxs%sN!08N~>iQ*i=k^}hihY3&rbh=u$X*mcwf&| zGRl0F`)g|fr+3G1<4=nN?=nJ?nB3W=VKUuuBz|UWw+WOeocpt~HlcAEb~%i7sQ|Bi zN4X~JMC;r72w?8G;#a)Xr{ac*dNGR`mcBIpx63->&YfNuzWn-K)6kS!_Q48J9n52E zB{~?;;Xo!(^TS?BdBWNe)59UuaFg4`y`67HcpbbCJf0yL$T%H}s~&X>wi*64E!XNx z+2Gi(BD8*4?D9d50|49sH9qVeb>=>b>IV?F;?#GPAXS!A0qV@BGhrO`tf$}sv4v|7 zB+Xpg7{Vj}z^3i5X85W3jjhsDN%$a{i|CJ!o%EzC%z|Fq4R~f9fB>FM`M7x?b(2{Q zj4PIAhD~=L;1`^Y^`AzG^cieoxKMU6SJ|8sc%QNKM$xJAhI%P@h^2s%w-=1QzA33VQ=bX6qKR zm%{mJCYx50)$ZN=tB~F`N)3s!FX z+>DCLxeDkPg+{&<030qVrU2i!f9wzodn^^EI*rXspI~~Jx{dF9{P+K9q=1`*yaB|9 zoF+pxADA`C_kKBHsUH9l%}>_owy~>lS)GjM);eU%E#wdRFpUM9+GxYD)B1UqSc*jD z{IoFc-=e+_EFHI0fW)*YFi)F@GDW85QX~ZA&kPZcwt$hl=TQjZ@l$U5xXx6QM`}WL z{7j`t=+n@I){j?2qW_fs0C}f7@lE(TkF(mSkU7cIJxGT2j9tD&Rq2ww%$0R2rlm_u zakdRhyfSv~E-rztJQgIyLU}VnU5`zO&1PSx9N5VnJwT42vC;c%`6{YY3FuTG)@TOa#%K8DLE%0;=R~`74KC!$QPzD z3SQw(bf z{j7$kZpy*c@>78t+@dGkF{uR{ij4U9H+XRE8gn?~z@8IYz{4yatn!n6+`Ve`jX-*2 z$Vi*z@OorpnpR^PfYyGlmjVU<<$jjvtF;flGQ#UGIlwtDvOl)jS2$dZQyZJ(wuixUCKlHf_T5rI#6NXqbRwV0>j zMGRjg%Xr8LyV>_pk|{kSg_6nN7Y>Ay*M*` z+l4e-A;-0}C8>i4*$lE4s{c&XwgNjZVLS7D>E28)$hp1T!@tl$O@SXg8O}k$- zvyDVSCnllNi9Niuh*QHmW}|k0Q?K$=@$>yt*MHjJf7AEh)8{hd&nzAif?Zz0JfL7J z=c`Yy)((Us!VG*2S05xLd3AlGFRUHFHXek$I-b@ZfB#3t*~$(~$ZG(3g?v~ z0(S9W0RB!9;^YB_GVm%oS$Tk;gKb=20fg1TE_MKAkg$NXG{b+E_d0d6jsMCTe9L^b zZh?N3F8kLs{BL^x|K~3IH%LE`spS8G??nFx-~GQag#f>p$p6F@Cev_gk$e6}27Ry~ zwt0o@nlV2O@FwrC`v~*^-LcYkj z%E}Nf{2nR5SfnsOni|ea$*syWwp(cPWuybKP3H+AQGu={W*iT$DYq|M2)DXOf4Qm2 z632*7z|PLcI$R)oi{pCi%wfAhJH2m)8TG-7`={N6+TTa%be7zkl;U3mZp62qYjM9h zDkuWw8Fq5rLSE-^>%(JAF^tDIP3nENR~bbz``k@dA5SfKZ+G+h^E(gOmUU1C+W2@6i=?;<6=r0GuG6dC*Q>rnzleA9 z)ymsc=m=s6F?0}nNFYCmmj536WSaLxG^i^XL_F0=^QFrvp!ElZH4&xJh%gbA``)vt z*6>+IAVqVu%;}d>7<=vzl!#w}T^1=E&hmpp%Y_QYNcd6cSBkcr4z;#I5c<3+I!h~x zq@FP~_YC!=fMKY~Bd6RZtmYHl&20oC?s~2$( z{bFyar?c7f=tWB1_9!g;md}}pq|wC&$HQk|`X0Ky7T6E8IUIlZH6wto1^%#Cqzo*xgUuQ7`V(QoQ4fAq@@T>5b+2F(s>FU%)Z+BePy-6kM@kJRuY{7sbsk z`-E0GFXvYqMEPe?>-wG?cMzJQJ>kI_Q68w)UVAYNbqLC|tGiU5^;&5c@HQAf7W014 z+l1zRI+t~Sf5;OWmlKpnMqFf)p~YvB&a8Q#kzJ{4VSi8?Axkj)?YgJe+xcWG_0ymp zo0431Tb38yMmbOON&<|TOZ#3t4=Sp_ibzV9QP0voja`nu7hY-va?t4h`OXec^n7tm zD#%ePcHT>r6BNM}df%^7GUM3X3j_6AVb2J%N<6J&LGdP@C)GuNF8Ru5wqVD5X_xD# z_~WFhUii|xDwxxB0fCtpij&@BuuUtp-&H1X+ab#`I;CH*u15vg=WeeOqbRcA#cv1I z*KBXd_X;_(Pq5w4_GsXPwUL)xuS6G_!qzBn^5puVwhRacVoy`0eZAPR05y9)?gfqRyo$`4%;ix5NG?;wT_+m zwIk}OyKU3fd;C6Dy8Cz4_&1jb^y2yCCy8XlyI8y%wqiZGcF&I=-%BKf z_3bRYl-5jJOBZVwTs@q9h~MM*TJ-Y0pmZV{D_4-baOs`}xd;TQl5#r9+4QI|>k5bt z10_m#YCC%#aWHiBRz2~Skf%|(cm4L~FYIg5Q~RSUDPrTpa!0wRnB1`1s@L~Oj z^tv>ljv&U*6JhW3n}*ca__XXkKbe~Ha_LnUkIE!yXGrPeTF+uNsb(Y#r^OX19apd* z^*`8h6F9pI;5**a7Uo@<<97V4^Sv;iXeWVS+jt&In97$|TYvh&g1&C7%MdEx>B5>% zi7H+6rlpj-b0a$;vG!LKEM{giHha~!C>u7Mt5?S!AhKx8MCobz14{?S>FptX-o%}W z7MSb2Ta2z=@w^G6du@^^^6rZhi|kY2;dYcI%x;4*ED~?)P=Q9RH?_h+Bkrz$Q4PbL z>8H9nGuOrK4RktIZC-hwmQ4vg_*nD%RggBKcdLdzFMa2Co6Aqmo;NJXWz2i3G0Dxh zc&FbEL=G&qoP1!`Q4_hgd%zqE>gO-`fh$goRZnB)obRp;*NiD_s(=33Bu4#Fr*Gy7 zBeM=jCih*JcT69RLpbd)&q7jeED`=WwU+ulQrN1cL!wUKW<}IARDH}{OVE390!%Z~ z+sl0?U)ws($Mcm!@?Obdm`3foo#`g7MEjwU0u=RL&-XcLPQUOYZ{j0-srU8Yp7aO@ zGpJGb5_Ln@GY5ToUvpEt2zD(!$tIusqP-Wxh{u(r@NNqv;#xk1OZ3UqFxjrX+dD&@ zBb^g3z2}jCUmUhQi42FByLWw|HGV{!cwCD6m7be)(ttOV4ptxBifYAAk%)g1as%;` zwzogE(LTw2O=`PAqRmhv`23bZT%A1qoHsm{0#6se2mTf1G$&;~EJj7FMjVZ`dQbl0 zt}Sf6ePo(eB}+AnXv502rh$GLn)!Y;;zrL&tW~pY_H#kv?%`PY)-^BI@!8wvfj7QO zy`GO$60N&qzxd)&V!Ffnc6-P@{)jNYT#xX!BIgOgl+ufUu;> z@Ih+$^fzQRZ*{4ko9W4%=vM6oSEj_o%u;sODjzxB)W+?1Uux5DY?m6DxskXENkBcz zWKgU6gN@Qr*X6Dya7nT34-0kGlCpo$?U`L^cvJC5ZLp9$;$7O8tdh|Kw6=~&wo96? zsmWw>-boeP_eV*b^XM_5BfUEhHVhI&lb=W#;P0X?s2}#d9B9@2Ba^H!2Y;T|kB1Qd zD4gP3pS^y2Jfy$JJ}>&NV}RFdd(R-$3|aS@x1{f~c(igx-pvCA!humoe3p+0(?qD)JPLqtJfR;|UPf<1v3Ap%HXg)I(sQ`>b30{Qgk<4|EwccB z)~(%<`J#p&Tl(8mGd?W=TmgaS%1x#1h?n};7n~!ub^P=TI*Y!@)NQxE*c76zz4|Br z_s@_{{KkcL9KB)Q`H%lQxDn<1AK>QyH&Csu^bEk{8dfkz22p;1zV`ojge}Z3_&=km zjWph*Y}4tl8NWZ&N&dP+E$oyeU=`eE$xm_b*1JwiJ_@c|@7gTOuYPN@=A*brb^|EB zdkIwC1wFeez9al~vxVA?2A?RCY2lOKB@!kz-g3It&yl@+)^zDZ7tC<`f9=orSlQbZ zX5$`CGqt+tXbm#~kd}du#xLDuJr>2!M3wc4@6$S56aDkEo+^%<|`IcK6q?y5QdP$@Kx zDDG?3r>_-^11dLo?*=n|EaF-Xx3)(>R%-9O_y(mVNFU1K<@oRZzem>pwC@lyRjT6d z6kr)4zLzEf(l?;g5c{&L8DAS-pYWlkql`I#9jf-(>~?vQ7(KE*Ridx{{L}q$m)@^a zC+p=q<8)(F7L7+WX8tAjOThKdq9jUv>h&W!PmNp3Mo*0i92d%1O1Mi7pvz^W(uM?q zrOA=46PqFLYNmHDrtX}ky`G2&eb>P!faZ`a`xwll62g^I*^Mo6Z# zbGO>IJRu@#>2gx61X4ft3qd=MtImIHI9*kfqIo#7Y9(xggL$ETj&WL5k=2<%S`#T1 zt&AdU{4A3ciGn6qXw*uh&%0IdVDPW@MxLp5{2s=JDU-!(Iz} zFCX?xyvRna_Rf4)($v^X{f4H&+++?-5-YAfretbmE@jh!qk6p8rYUpB5qF(ksF8P5 z{0va$>Pss@C?Sod7(Cc|?$=aak3FAC%uFt{DydgPZb{n7h5R)ZLfe(ozEYnQC1lI` z*iAe@_%ROlu+Ie*r|;;~tW|45N)lytFI|MCM_;d-Z*Z6Rrrh5jvC!9YxK}SX@*8S5 z46~h~2^AtWky%_GkfLy=58FLXCf11gEcT7|Q9|-o#}ALZv!IPP<85p>$OkI=DpBq( zDUG@)e1#?4!+5n?l#wJKIi}*?4VaxUxfbeq3iUUtZ`LmyfAaDep4oG077SZwm5i^s z6r9?!8d`dVJ2)b8sF9FIza_ZZLx5E>RQ@t}`877td{@fCZbz9f8yL*yd? zj_9MX$k|IV1co+k%jr&AOxI%{X@ha(cGB0}2#aEPQxR%0QOTNKweERtW# zN5WTM@stRZRj^C@!Lhfcdo&NPZy z3bhzB@}y~vSUny?l^~RruceEdsej;(o!am5mo)G<1u6Y;$Ir}=)dz}moA*P29yj_V z<9vhL|GA6B0(nX6$JUPwV6>ez3f6^o%(4-LFFo1ObK^2#Fa z4~oPW2eo}z?^~GF+mc_AewZ|^a052;Jl=*!Z;OZ&*2CfL0{bkTFn%PX@)D(d8S5{J z5tuq-mgu&61 z*YI$Dz5pmUou^hPD+{Xk!QVn%@6aFy)7*{g&`nv;8R43w5%$)z+|ph`-s{tH-ddxC zeGEcXeK8HjL_V^Ci8=9TEonP#)%$99TR_Xo_Cwd~vo-8atRW>LxC=}7CMM1fKFN)= z|LTRPu8gNY@lkOdpG{Ld`)cx{H1Zt7gd)qnm>Pkt^eoxCmx@jMaN2k<0%J?0XFe1H zN!V$-sjlCNmEN`tR&nSAEX9N3Ocyk|w2BlDUIPv5|&+>Y;oRHp?Viqg? z3B#*}=ULKel*N&qd~jw|5gE=Zd-BOY-SB-JPsvR*j1yVq{i!g|3rLf>s~0UA`A$#T zK_v zylASUvy+W&p}fo^R-t?RbSX~XKnkf@U#&Su z0mm%$O7kJP9&51XFa1iw`;X>323@3zMul~li}?=3tmhjFzps4wI<>W4Qdns-5URt8 z)`!!eJyOsT{E~iMrcn6OMx`}RC;m&siK~1s`WA zB$F_^K`|4=pZa#hXuY((99cq){wDfgo%ZUH;yh?Rykl0pYhnzMaPQWU!|z|>I;guT z5}XJd*DBQB1#6ss0)%5cOGIXsMOa3qw<33fCNG}FldmmRfM2rv6Kaz6G~?3%C(flD z6^COLnMjR+z!EtMM5en(?Ws5aFP^SD9t!{ef65*yD~V_rS!Z@;X-W3pCx`6qaAZZL zP=uVrA!N_&BRj<15t4OwcgW1h=J)RN>HGV$dgR>u{d&J%&*$^?e7|4m^4u0hZ`yx_ zi}s~P7ZG2LC(yo4sqbbSP*%2AE_?$j;_83e? zBI%YbBqxzX2$KhAw>k`~#EwX)YNcfRH-Iy3N;7P2cG-_~zI|)K_?3FkYjZfJ@#b;8 zE?y))^0W?@*kp5dx1XV(@kk~fc)FN-TAp9vxUUy6R)d{!_&)}q0_PY;LMvX3lV6n217 zleb(>Bfdq>fP{F@9$u=IESYo>9i3}NMqkjT!|NeLIRd;zH)|>wUH>crpn-xM!m=M~ zD?Wj1jZTP-YN#p$zJqV|9;uBz;^+Q7mnNTpFtot`O5{e8XHOAjESJ3bpz&?evFR+Y z!7f4{dp31WngT(pBiI!Xx5KcXN<tXZ1QfWK*(R}xJE`u`7%|Ch~*Z3n(u{ZS@r7tKRFCZ`ejUFPq+)N6O{5h8eXLgH_%A6z# zK4h+UsJ9XR*Dxj7^hpP7^;j?jB>myn0N3DpKEBQ;?tNZYvk}p7K4Be$hX)M2#(tB* z6&s_DqsXQ)Wv+I~7ty$d(1B>iGdj4BueX&W`_R#TmH0C6d2G_NkByV{6|>mY>?yau zN5-3X+Oa4A;!pf`Lm`GR~K zABv9!6+?aaFR8!T`Z*>#oe@!Yk0<+S6Qsuy!pR`?AP{9Jz37h#*cf2ov+twR*e+W1tN4n zG{M|#zyY5FRqnooj?Oa^sH)J^#Y(4Uo8ZHGN?0inDtI)`LNbYX@)$GHBV|NlafLMQ z(PfxRCV^k>dP=q?<64k_L=uktvz7km;&R8B2N?YZCX8L9`fuC!yxzk1TTrH!CL)R( z;C;RUx87I3l_Rwo`%ENF=!_thiFW&+J#UpH+WEm(_y2%CjfK#=ZXtIW@F33aQ?nAw zY#?r(Fc`_Zs^UXFH-YS)dSP;}yaxT%PJ{U3YjsejOBKO*_-E`gDdkJl%Y?r*=xqjt ze6I1BflU=`n-JGJ7s6l2-9g^KqoWP+Mp6!VOQNmXWdxzwG;24SO(+x9#6WavC zm~LI{YfyFE+(YhlaNm$fazw;M&b;G93>)G5&CTpbVCEedZ#xkUu`a`K5pPj(x77uo z?V2H8`6aP9_U3q|O32?7vKF<-j2f{tDXQzq&;?5!a}ljkj%5*5kFmp(ZG^#=J=RgH z#1EZ3Pq)SPD%-9Wwo>k$MtqFI?!D|O*(f3&okqAi$MEYIVEs=Ll;lw>=$?LR)~`1q z9&kwa+@u?XcAz@&yXWjOC-~SGOn+g}`mrzYrf9qo7{{S8XwROMbWG63YfPEc>B|4!@jPVoa(b-0L5(EBBykJD02_8hh zMgbc9$BLE_SouY_%F*o??v1`Gk?4_CmcJi){`s>Xl(U+z^t^^nPRB9~tC6mUVV{FV zw8y87a^ECKRh~qm70{P;<;^=_vNnh{Y4ZL@W7JkFB`EGDcr^GO_pX+D$F)+@9qCA! zn>`vMz5?*N5}V&cs>b3Y!O-Vc%5Er!o1GdjM|vOGoHkOVBkCx6Z5%pLKy=#Cq|FEa_A(7v%lY5Aqb)@46 zRn^0qo+NmEIH3b@I;A#|gvs*Wl0-yGlij&BZ@btfOQGLqoI^+J@V_4;o{=W6%AnuJ zv7;MI-HO;L7omz-T>qn>U$URJU!RvZu#thS#1>&xN#4}t0f7hynm-j1u&B?*sCUPL zC7+}Ijjut`0^uZ1w4wplsmT~cCrutOTK(BVJj0IQ73QeK@+CH0l|Uxjb4K?REDEdE zVnvKf({jA?Xf1a}E~>=e?7EZpH^`gfJw@g2EnkrgY1jxYJuK5OzsJ7K6 zq+dw42DkuQOctaI!`>#bxVc~Yh{YMBWKtU%ZQPj`L*pMws&aDhRAal(gki6Mzq?&2 ze`TC3B}^W0gJj#pq}wO!kjx#DQCQd2n-7N(=S4yWFL=tIn z!s^@s^N~2EMY=9cegYDGRSWFc7{wObU~lZNB%B0;sIu4l_3>y~#t7!_E!5uludZzT zc-keO-WAyU8tpslU~mGc&emp(1vov|%pT;) z8_J{nMtFWLMxCFb@dE^@lh;^8YHG$fQL4mdb%MMgypwLr$$)>e=!Cka4tGaON-B+# z^M#StfcYiaASRY&aH)cX;0v&g57sOaQcJ#&E``2qMB32de?t|uI zO_==N)h;Q!PH;F%&)_=_GWcYbu^nW`BOR7OQ6XWDkJtqOiMerrVJ{n_vbVT#U@0B# zlGE(fK4R;7I$R;flE_$Z`Td7~5^6Ky*pF;ZO+MbS|~};+PflR~(}RV- zYEqGx(pkgOHO{j8N6pfS4G$|n6oG9{R!xltN(l{F4uGoF7UIW5QWz-hLS5k7avI4y z!($W@FMsdxzTf>3uUV;Nf_*59b4(!}R+T#2CEFmXjs?xw5o$*|yC7Bi$JouH!QxkE zhsoc_OthP4azgc|qiSV70vQm%KY=2?6P zH7mLsinJ5KIl>`!5_i&#QQum)Lv2NHpQOnP&*)~4baI!J0E-Z=eP0MOhr3@)m6Ywq zf7FDe%t73M%D_<~`r?N%O30S%2x#1nGL~C&Jvkkv#@g;di?^e-%yvW4top5~{#}xD ze7w1;BezMDug>2my-VoH83AeSP7EM{e{kZDC{6?j#>Y8kfWm(;#C%8 zc_0hL*!9Zb0CI^0c-D-hUQ0t}p=RaVQO?w6JZlIUhKDb{1Ub5 zZhzMMU>AP+Nen6R8Qs3wGrBBxgj0#=96?8aKZ9+sX8?mw9a>g(fm+cK0At;hpT~~8Q zDNROTo6AUZzw9|t(MV|yb>){`TNw+Q*ww}&(@tq)zRl2e%{7tajEU#&K1IZpbM;XXc zZ}qI6{?mx&f)Y_y!3e=ISTTU-5~l(YKsF=j2}aDPNY0m?0(1>jRHM5hIIRuC@P}~s z5EroUp%SNnFyaP;o)kOqPs^>8AVg(sOB29RbrZgG-DSA;HdcVJQQu0Lbf^C3%dex` zs6k$A1BE1BH5C50#WY1Vyy+9Gd9!F1%vJ0Okfk9zLOE7KH`KK%KRI_2B_&K0Ew;g$ zgW5a(u7&7UBC4A7j1J;}=O5*+-s`SD(kW%Ys|ZHKA~YHED9Lq0cQILd;xF=xP<*EP!5EXbY*I_THH1|JECZr!&iEC@Fsd1c!`0M!L$ zCK`mJnmlUjSP)=guS5WxqVJPfXjnf`k=!wXgI)3-CMAbH1A+t4Iv;$?S40XyQI3@*P%PlWtKM1)K^ z_8R*^MkB&pM)o}@!ujaUVdr{FLQT=0dn4`l0jt!Zkjh)7D*~qD@D=zazk?lLISV|= zW``r1VVLRr@4A|qv0azSnWO68!xz6tS+tsa$LIL+v54vP>-ol#raV`#f^px305gg8pDj1 zJ4s%!T; z(@xB45Z@g`((+}3l(0`px?&ouQQ(&9-@?6d;WkMo)<;Jk#Q{w+l|>Tk;mQ zg_<1c0#k@b*w;9UCF@X)e=`*5Fil)j?1Rt{bRcfp;5@07{Gq)IhT-p8V7*b;p5&h3 zClYshIT79RC<=RNn;KR>**PYLbh8b-Ib8N?ZQ^btpTx9#p=kPNvGp6QlxJS!O++(P zn~#yF)9IA1c(!~!XxR?xFc33?s&t>Dd^YD3(f>Qpt(idRjFt*9JBtONYZ3C*X&kFz(?aDL8>!oCDCA;N&Q`j@O;8)2?m2v(L z;wa0Zx=(VZOdR#Sg5k4C#1|?acB4@_ zX3%VC62!|yhtY%YTMs}KqODRxVm%$wI z*PMt&AO7!$I|jQ8*KVvxwEJKK0qP==3=t;p6Wu@a=AN#6TURZ*%pN(!_Ev7_ zG{whzUV&Sj@*>!QjI3}0=8J%9F)k#@G?= z*3z~KtAN88R8q@i*wToqvQmC>>=J%x4Bflk`p{)ZTN~&i0U7Qnj%Rcmg|G*3NU1MJ z7#5#}mCkf&7{A&7Mzz`SzrA@l^ECAWk5gc0=nVXH&mR`rpxQwMJr_J$gIDuygH35% zzBj1P3Wud#YpPeJ6Y3JL^2nG;_z-GbW$M;6ziM?1y+M>nJ22QP-Ppg@I5>Pw8=2ap z*ZIOK&OCXToFbEo%kggANVT9JA^wM&e(ZTET@7%*VQnJ^(D!}PRVUQ<975x~seTuJ z5#XPGvS1!NV2F5hQ7}Y;Mp*WIa+-k1`CNnJ$I~4YSTKm8@kZ;S!p+8^#{BdKXlsSn zPupZy#ITcPO^?c;Xqi6NcAIFwvygP^zr7aXp15Yw2T7x5eXPmY43$tdz!tf#T9Upg z0k|I~FL{Rq_kD4s``9?@%LQS7;>V)yY%7i*ey^+^sfsdSdW{TC-eD+gOQ7V(_FL4{ z=!sx~h}udTR+y}PX)+vPLNZMkw9w{AcWU+Z---_VD+av!fxXrj6gkRWa-wDqU!_mg zaJB262Sl11-B65<2E7+ryzld1tH+%zwYtw6OCO@F>wB}U&V2ZX_DU|5`Ml?+#!<7) z9NzM!vv2(R94Fz3en|u;3(^uxOmhXZ&!}ycM+Yi+g17%Fi>Iw`=B+L^hmTSwhhg7E z&Io~EzE03_{8w~S2N-aW3{8Puii2miq<`p5I5p-L;Ef53^knLa2(9-WwYNy$&? zQ1tXwiQ)51!I5SKEdCg0i`=C;(9*A5i2NZ`!S zseDaI-tyl}xDUJ*7@J;mx1HNahkSldN1v@4g@ z@uoAf^`hnx&#wJ=tMv5yVm! zD^a|V*epIj@+VK^*g(`sSD{JYd*X4W=;#k-J$k9xX9WI9bkV?Tvh$Bud4_O%i@iUt zx%Zd~)4P0zwP=1osWd&=GFc}6GO&FlB%}N)mmuF`o8JA+FIO0ER+1Nig70mNKf*rg zqs!!`&a+212T7Ukw0q! zNH5k`Ue@0DarZrs6X@qnuj@`;0Rv5!|k*X&3CfB zuX}$v^0GXqU~;ZxvF%}B{U;mY*2XTpit8UhZ;`ba+vNA(T7F3r3LMMGCQJa(Yutf} zQ?f06rzhF7AC)I8m3k4kr4 z@DfecX^~8xSM3Y}w3Z?ZzGerL(BYrhK`QOE|J37vTaRAti`XMTH#Tkb)4(P=OIT3 z&2brps$ASFsW9cUD4I}?;8neIvtObVFph*$J(oxFB1!^29Y0KY+)77%BMbn2YI^*? z@42V-?Ib@;J{e`3JbCg%p9K022B#6AlrWM!imYEGKxxxu~V)pgDHUbk(UkqRYys(;YecJ8u>KlWBg{e@5G6)n+bwGM&G8 z+9KUP$hR`O{7thpixEO)ltek-BCpsvxx6ye`^dedqtiUStfYEu|70!3%XE^N&%}7f zI)Qh@hnc665IyFZWteJSy{I_BE^P9{F#L?y!a1Hl%X){riqa-e8JIR`ytCrMG3>Q9gnnCIv}MLe&%cOTlR; z`?m5zMFU(j#vNTppd{o4!g$VK3oihge0htif*JU0l+H6Cza&M)+%6e8U z_FU}6PmU}zzOkRmM{YZ-mQ`*494&19xj;xi6>2XbDahdRvF7&bgMC45N7~TQl1o|4q-bSGh!v=q{+;b5-ST5!TTMNLxx%Wd2g3_G#Y5j`RBX(VzrVJ58fsa&?dod<6$z8}1D>x^r#3YA zG%{S80b}Ka|B58N_g!PoqYuPGV@O8=5rTbaMQSorTnkLqMqZ<~TUPg}?(F^1aj8k4 zm9VaA)eqleF94enKdmKp1*LdQe_ZC8DN?%MJLd7HQ_l{EG9 za?N3}#1WeBMus-y9iOy!!sKE)qV*fZ4KH5y@y3=mt1h^IsS@oW7izV6DyzKxTjw!9 zs<5xQHAGHc%bTCDLLE9_mfDUX11NN6oANCQ4z{>GwZ!7-KrmKDj}hXI_%O!*CTuNu z;-l5=;f%c*CDWsV@kdC${*zf^S9Vin1X>FzB@42p~geJw=a{~64aUmUat8;8(vb+a7*9#|(3B!Iia?U5^eqZKnFW}7^Tur(0METX+NX6BiE;u6Wt5J@=7+d`zk4YV2 zh4Uo$Z}g|X0vbIRx-!9NRi~5_VFu0nP*d?*hmqsxhT-nB%;eZ=`SuODelGDw@;Rkm zk?KZ_u!(yD`RP*%`id#>4zKKZs%8r9Jjdrrhrbh}-zb{bHAar}$P>a0miBsY<7uf-=<#G%RWHj9a(L$xoN>jc@!5GYp}Xj^onyk)LOY_r5#fD;yy zmpuxL`YJSEMAUV0YgCjGU~s8K@{Pt028+;MsVNZ~zT4;v@iEVdq^PEi<0ra`n2^?u|o%F0XZ(=~%URK3qj%;W~%gxWLp#5j8kT zKU6)(BH<2n$g3mnZD|YV-ZrsvMuaK$Tj9jBc3J85g~=6e5Eq*|P%;1lRZow?Ql_Tn zhdXk{il#iPjlH}lY_jx%2Wh_N>b@|}{pEe3!|MxALmx8S^-X;?_1Rlub7`)nfA(MF zQcmUe?b;;_Jh3m^XW$YG z+fOFkYX=vrCc~`SJ$@eq?^3LH2_$s8LM=qkuX9+xq&oH7l08UbOL4^1+R6{3D#)mG zZT+eO)j!JT&)%gCXVdz6c6=%lp88ehjNh3NMQz1?=j!k@eqtoNfexAF*Ko=G-g@*G zZJ9Lf_B6-J(WeVxvnqa9cV80M%=5#E(aQJte611s>Trm)jX$cV@n^x2PJBv6P*sIt zmNZaKWe4w1RP#dZA+CWHV}XgQLO@G*E&b+qXF=F9)V|e6#a}2}KGZagMxlNEvQH)< zEwLAv*$@uY$VHzdRMKMv?-F&Q21h**KKUyiQDllxX%GM88dN#=;o!j&Z&!D-(wES# z#&_+sXGz{ri`qXUzc(6z(B?vvx4 z<}Yi9Na{nCUAoZYL!m@)c&f+{f_*TtsqFwM4SiWj`+Kl#T1HAv|Rgv zP!gS``e7)JSFqNOSip|3y9`>OhczE8Wnc2*h3=U6-T5fW!1VL7 z@q3fYX63D|-_44KT0XTj!)Xq|l%3|#)l-MuBNo=mF9>WQ{?+C$j;h92+Uy%mML|R? zPo(6IhLVar#i!XQdv9d)wU;km3gep^mn_~Uq&3&^FDo@Ut zeAs8Z=e!IV7r+dpeW6KSGgSM!0rPW?l|W|(B?WwFT)w~F*Q!i^A_EJ$bFPK|S89=9_T8#sw$w@xagHUTR=tL+QW8LF zOp=gP!rEv@Z7Ti`9PL3^Wh_x){Oxj3HI0zRMp2 zIJ!kciM2DwyYDYrNtIaLQGLv6bb?sl^HM)|#DYF zy)3#6r-`NK;ZkZ_3;4O)+Y(6&f#>LB4{($hnH+dfcDzSy(fmO!Et#c;jN4BxF}?A8 zsk|R~o(ZN__u5nByccKD5SS_!+_ZLnIx8%{W_;x;58CGgS7 zI4h)uw}v$xt%aU690-~!l%M%`>4JLRJjj-S(+txiv+^>vt620B1S70~0ZUQxFwq7f zWI$&FMOwm{T-}dMQyHYiIL80gc85oZ2OqHNUA#sT76)cYDKlM*KF`WeCwqj$Vd5W4 zNH2Q$Z`}RJIw;yFC85ljnmtY&vebpVSZ#ENe5-F+{-L|1?wd1UXc3I4_BC3WxjXMz zFO{73B(r?&F7i7wKQ_^>-wD-3kSyLo2651E8TgZ5-eh1>5f>Nt)IEzZZ1ShLIi=SA z4lUvRXX(agJS7P~gl@{;>gN=Qks%6VSxGujRZ#y8vEa&p*fY8w(B5zZv|H>~ zc|b8C;7$c8Y)65$*#~qu4_*=W7@n6dL0>+W5KQ1tF719y`t1<%uynvny_=POAYN>4 z2;uQD=K5$dit{eA{R@^`7F!uB#vk* z$4lJhk`&Uc{=qXHFYfi9(4Ry2TTVZ(G%ra%aB=oLmp-qU);l2%rzMVT?!kjYWj_C- z!mqZ^JyJ&LyZ=0jthVJDS&biw5mOIwz)2@EpfWrbU(OfO&0xiK7e~#paa|RdtF-cDlZDm)Q5c!E~*8_g`oF+-t{M z_e$O~m_m|f=9PmdxM2_KxMtEUh<48{e$Ci;TZOCLg2Jl8KaokKoT)YC^+|@oyN}Hx zYX1q+Z;jraV2q(w>aDG<)y|{Prs0W_MuuFy2W(Vgt>mjEqSv5F?`-$tn}KWE#y_g( z(pA=W9q4c(I_=jPSEgQg#n0{BxOLdAJQqtoi^-opYggo-xR&1MG+IYZ3~osKA~GOp z4PWbDby-p_rrZpcLOy<>G<(3$^1=9e_F_P;U3rgnQ_dqNZhpx1q=T!eE(iDO|q5a7LMBZ z+=VW81hW&*`h+-e zN`=0f7vjfVp(}oh%Vpb@epmgg*3qFS$ChC3q>33TxMF;5F`2nir3%>PKrhoVOdet` zqY7+oZ;~}i(2AYpre}mx5sN!_otR>IXv|HP+Bfpf{wPar7$Qpzie>}vgN4Q%Q#UGu zOW*T+Ca~IVo|rjb-;TMJZo#O^au9w#%1Udda4>*KHVysY59UDR?7s-ZIuAPefzJMy zK2#NjV@jt4{;`x3G!M5V$fk&NBb5iNIQUBmRh+CA?(Rd+UHnf0I5oBsMQLK4c& zOPY?eT5Hat=>3#0zPY^~o&WPl9WF>O{Qzz|vEpY+wQewSu1Iz36(Q}c!1_UkuDRK9 zBsJNQwcWtN>`^{0N$}2A{seCg!o!cx!01svG1d)cP3{%cY9<#(440;wBd24dT6aj8Ytxs;;z4*Tj9hLbc8HB$JPl{K$3& zyQ^St>Gy^-7S}wsRo(H^Hey%RwUp6Zu*s;}dt#?fJXzhd3cK1eap?=IomR^g)pO57 zn$OZa^B9@`k$}mi3LAVun9MMRc(Z8pUssUW=?kp*p3rf>H;nbh1(!P}EFq%#vs1de zbcI8UK2gzaEp|aoO~2qbD@Tjvs3M}N586zGC4!_7+%(A3N(JHO4N7kZwJEh}#JQml z_s9>^rLR!i+3XrYlZw58L~1KdX6eMM7y(Wk-fWz*CDwGq6Be6v2fb7NoG*h8x34z=8xPEagVNlno4 z_@oiVx41@BYZn!eC@$;wlgrpSILgC}EmLu@%20l)tAn!5{n}M@?NGUf^DZ$Kc^EZg z3+lnGDZA%qCH)btTKb<=4g{}18IoCXDYY=Apv}N%emf~G`}aJEu?DdYq`igzpCCl6xN#N&V#KbLNHdr25Z+TX|L^w00F6 zBIJ73SZ2tv)$Ut8UtOip)!T@Nh0{K12V>m8TOMfsXkxS?polQEZ3|yb=teo%e(pnv zPR0LmJXfQj=-s;xA#q=wqBT+jg?LTAGN=ROo4M-AI|h0#_rqY#~XrdrI2_gIXjdtiwVTA z9Z|STIB;X!`{MfB#B-ym76<0pV65pHkoOuFE~g`Z!md>^tH)fS%D@=B{YLwOCw+6+ z!m?CmX!R?RhZc4?>%p=D@LP%#r|3)x3#vC*4-RBbj-`3DjG)?pD>QKbEsWd032>*d zG@oko#roqN*KF&qwMS(pL^_Gnm>iMBp30CDMvhHSxfaFz_eC7Wmu?*$(d|%oc~MOy zc+!NkJrh#eH=E=|*=gkHGoKRw1&;im9|Yq@#a#iDa9RLU&iE}pC%+9`2_ z!EcAXPWs@hr-KYl#ksl!G(WhG8rAgnXwoY?<;mI{bBf_YpWrpfbV2ptd z&ObLN!*%b;vg@7-bQsu!?&SwYN}dC}1H)fTl4GlNstTEfDt z(c;IaxtTDY%RxN@*mBEzUIp%H+BA>K@|5RV8$4>qLA@<{JxB+t!6 zrS&!}gANHQDP&*hxtly7LH*hKO=9J&tn*6+U4!oX8M--;wmY?oYNGW9$luSKXaHVS&qDd2L z?j#czXY=~boE>bZU%9+vKwDW({p=JbIpfxn6gS7@+D>!b+|JUH2sguxm4GKL>2LX* zq>|Y<7M>eGK0S^NLA_x0GZo8sWcvI8P)DxA{=SXgx>ANH^RGy+lj8%AYV(P;ofo%W zl+UY`4U4QEyv;cMDaJa^RZevdi_GGs)WMV%H9i^xit|xqA?B@&Bqpz_;s-DTB-rW! z#}SwM@`HpkJApoQ>#Ra%9@RS*X1Np|r@FRXQuv0(B|h-VJnW|LBb8$ln$q|!nl2eY z#KAq!g(xSN~PRcF;=(LlJoRww=CIY9$`#tx;OMa{41~wd5R)wgSc(+ z3hXw@Q91D9jlNA!_2<_XrVKLQ-rXH?G;LldnkB)1!Huk@tp7Pyk;{3ytF(Wb$m=f> zc8P<{a9{8`?DSy3R;4Jn9@`9)P$^Z9qs)_ALQpLP7IxmN0Q2Lbj*M{4!y1&GDpnV}BpA_bHx8>hp{q^={-Xt9nj%3d zX_c>-wf^cpzo1N8m6K-qQ+b1ovFu-**MUHhKwkG{_}Zf2+% z*UjPF>aVm81FbXi%U_Oy6bqK>*S~>>9EJtIw^g5Uc%{65k;p3-)3#VtcjxR3cD28+ z!n5V#w4s$Qf$ft5;1qgIU9=O5%us_gO#v0y$I$R@$8|G3%;}c}$44Q}bt!|qJx&5? zd}=yoE{Bz0m5^HapDzjEZi)bKSj5q$Qd+*9oMk5IG zSB!G#@zbAe(EXszl$l*h@!%Z&y?q9TJfB@;bnn;`+L>i?xD2KH!`;2m_DH7HGjC_Z zPs_j&*3prw%D6xld#z`l?0&cGf|0*+~8{H572`Eo3@d5w;yUy293e@&?r&&7im+R-=ePQR9rGtNzU z7YQz`iRF67(N1XH-HALkn{hoY@XdFE(620PZE*{+pB!F{Q#V*-+}acVQva!)?z5gz za5b~=8{lCSQp#iVKxh}uYm@Kq6-4T!JMK?E{D+1@ zPD1%d&e>?z=J(lc!+=6g7qBz0G7gremyL-q*U7f*FjQcznnPOcf+`FoM~E|?jaKBmOp4`D5q-Oc5$K85E_c&(VyOm zc#K>RnMQuP7i z&z|>ZH!d0qwmSX8Tr}3laz)1x@qMU7v`-*{rbKl6^ReJBV6g*EUt6_G?4@F+W~+j% z$48$kU8wI22v}2jD%8q)Ed|$pM~Ga?Blfb?+uwb@8uVJO(Q#FJ2!Z6)zm2PUXW$ky zHo9@dF?+CKkzIAr={)zaNAlN3VH%rZuY{QP+raj^9xjvw<6?@|54%XOC^xm|XX$;6jnlD(#u{d8o@xU&)uhYz+b zgf_HYcGHu8M(VtYj7foEdKrbzuGZ<@5N3{*47h7Bv#-Vbm+M&i43!IsIKIQHHd4vN z9sb*;9lySOz9Af9ffG%{J*>pjL$d_`%Bm{PLsY+Vx7nGQdjG{$g;Yg9gbqD%$ zf-LG@%~RqFWJ)10qPh>sIrE!~=_S>hi>HRd`&t@e*}{e|8ZteKnH6}V#5z+V5~Uo- zJ;3^pLsPX&&EaF*l7(5w6C3|+R(8;vem2C)#AW3D>R_|CO#WAO?=6Li7^;#@3ctA= zapbe)@r?S$f|DuF)-^_ZZHHxE?+Tw@qza~f6!M8s6VFLdn||_NgY(sX8$Bphhf~F z=(9B3wr~imoPL`mHDq{jOVg9vp?RvkV7fo)cLu0W<16XyagEb$ZT(e)i)=nv^_+pA zTcP{EDB=9@GoT;w9=8i*Tm8eJBxZNzI!7v%@%CSoJ4cMqFY!EjG3pvY@(y^aLCK3A zUpfCWQki>rQ_kirx0o|RO_~fWIq!Pw&A>Ail96GcKdX^0DJVcgj)@)@dwi!-Y@T73 z**YPitMk@$Mvbe^(5veQAzkY~TJ{)1TIrA1*5e!G<+8DsPO4xeifc@~hg!12Fzxp@ z(w_&7AZ3I`{oGzV!#*SBi{_8)%{!CId{>%oS)>GZq8{6%giz<&@g_N8>#Z5Gn#LZM zr0cq`-$_*mu9s1wDgvOW((m3TsbFFz8)ZpTlll@Uk<F^ySJy)s$r057qTwE&Bj3&_i|3{P(1YVnoydS3TIOWkD##B zKj`{^bjw|nDc-`aCtBsA9! zj!-ee?;Yv<$dC>CF7f&(Pe=viy_b)rmFW47H+Nj2soY&RliAuG*pv!po7Dc%ft3v-HKQUFIYTZ# zyt;Zn`Dst}xZCbRNJZ-Jy!LZNHaKzAyP+QNG-!{MY6=P4Gc*9Ot}*__A4~wDy%c&* z>qsPC%&lvuZZT>rZ!&$GjlfaAwzG0SoX`kr=LZh;2ORGu@NizgFK4@OZB6T1Oq(Z^1+TB1D9&xA#sa!U23EINg|OH zDaprl5Gn34BctFLam<~2Kqm6i^YEV!@44Akt$wO^FS|d#Zj>`kdw%bMM0;cHsB4sq zBi+vACBd!MoA?UR3$r_P_~7|8Fc7;X`aov8L+9B;OjCB^vny12-dJFS15LHg{fy57 z5gM|Te~hqcJ417R7DoCjvwiZ`qhqKm6Le0oUmWj1X>^8~Od_~~plVSDYbxXBovfm^ zC(>)r!@UQKeT!SaJ#xPkfl%Q*jJtkO?-^CIuAzxO?2!*sapPD@Hnx9xPaAo!g4D(M z>&e|*JI#gbtn?LWz+sj7l|LVr`&H$tPsb=mF`ZfKq$bYhV)><(+;uJWUh9PYovF~7 z)~B$R?lZkthW?S8Oj6Go9yXC|pmbVz&Pa$xm zjhUOi_ogLVu0^ihUuW3OSWi7mlx&ZjiSB5VcrDmqoAFO#oyc(h=tdfV*5IPVzH|v-91Kb{99>Mp+DS$3K`FuHTDTmOppBujpORvoN9IhdnnZMn%X{>xJ?=vyge;8oX{at&xI z!M&Ct_OTMrGfBccVx$BBr~OMK3p2=R&(op*Xfp$beM}EpxJ%6;NBiM#*m;Bx8^GBb zq^1`%t^3x&Up_&NF#tZo|Izf7aZP^z-*h8iLb{|un$a!NDI(=4>4pvI zPHE|uZV5qRbR&#Ly1|WZDG~Tz{_fZPgs1GPb3X4p;8JIi`-u+V5=`VR5z zyH{RgonvMa2Hku1S)$_?08zfrm0>Jl;Nu#;{iNLl?hY~s*6wm>-&2RS!NNy;=V`f> zMDv^Qc%tTRrD9YX(xYUl$=x`gh?H`@cM)q0k4%3*-o7|1?%98QxY-Cz7(Ywd;*!?v z;lQXBX~hC}o{FR}#f8Z9p4IXH#uc@dr>Fw+_V-@=yUYJ!pz>N0pPtk!9s``w@3$SY zXFixkZ@_rc;O~CccYTu~E&lF^(&%tWVkcTa_GNT0a4m3hD@OqTeXW0!In~;zzN6P1 zMG&V7^Zk2wKxudL*6f|l=YDx>AACP_rm~@Lmhu5=@GlzG16Fzo2mT5HNkBcITgNbH z{Ixzm=ny~qJz9ZN12D~1U#&t`YCKkbC+!Iz1l-^?L2V*qeGwBxBd~Oi%If$DvSsZ-05S8csatGFj)0hKp@7Rb}_uBjdHl#MnVPG;WQ5B}J)`FVKN)u8o4O0qW) zgB>-}!rWj6@Lg!vvxwfb$XQU*{=e7R?FhRuEZ$p;wlC0lfTE;)A2RtHQ-)HYRf;yb zTft#g+)bg+8P|4N*{pE#LpE~Dje}Q=WPSpm)5xFs3-;J5%Il+v%Bl!-v@<+#pAs2j z-M;xpun`l>NS|Ez;MCRC9&WxhyKB;2T<>0U;UmXilrbj_sliyU-_lCGOo{>?MsdAx z&oHNxt=ss*p>U>2lQB;b$0o?+B+Ijiz5o2j*mQNe$9r?$B_sq$ePSao^v41!XulE% z8QzWaXkG|kqHhMUt5~&NqeIgY-a6b>FQb-2mGHfqpi~q2c;yFf5X}k2j(E4YrlRcJ z0@s@hD=aSd`0_Hw>Hrv$YSot$=s23_d0m$#~&WDPn+&4xM@bj!*O?*K!H)ghl`j6y*VJeF=;)Ox~jl zw8(xk;>9??9plmxwsx7Y!Q1zUe_zRnQSg#I6OO}4@i>1&n1#4jj6sq@Q~1UOA`zc63I1>Rd2-LjMOdxp#FX1 z#wkA6DW2@}(<{waVlPTtU3iGi*?j{7Fnw~h%FnJ*@!NN>C7m41%cLg5W(lJdZVfhl z))4qgtw`V#xV)p4d8dQu5^@td1~)psWZ?2re*j(sgEwQ~LBZ@BTg7BsP0 z7yOlY*qsnKjnnxXiDW>to;6(fnC^3hU!x|(upn=Wf#sJaYCwh-4%Gi)my zr^xo914C+YkUVy9fu$uJmuJm|!t=N&<@v*-LNbOnVH~5=+-+7KS%Sh@y?DaQ-vU7b z7KWZ8Inq_78WLMZ#0d(CU0V5=CkkQ$#hkl$B6HYhI`AG!y3>Hm;-%s1F&;)u%8bNWxtL z+$1fBDJtfb$-b^ORMAyWw=64Ei+<~^*MDz28M+Fyxcp43i4zdk$gTW_CqYz1@?-O7 zY|C$RJBK{AU|Z9dGv-#blnV`7sML_n+>=G#7E&P|(gUO#Sz*}l#-4a=JY4;;xbwzK zuq&%7yVEvqJrl44q_ld~_(>z*2M!=V2z%UQOJp?q@>b)=JlTGStaVh6-;HbQ(>%Ql zWwAYE`UOJrh=(Sl26Ix%zp+s)!melO&jhUI5D|{6w z3B%Ma;QC&=gMv9Yw`EA9UV2Oc~Lk9d~(q?=wr~ z;^|9O0e`CyG>U&*7Nl_H_`0)eCzNQBU!ki&+3&HwpUS6R*uPhcEZw_b3q$nGq3OW0 z-Q21rLam=O*DXWl?bbCZI{Q_PW4gw<@Cb6f_8_PT5ajGc7Ct>=yVZdKseM}E@tGF! zAv4Rs?zgYu4}IcdXG9@W&QxAvUfJlfTm}w#Wc!Q%HT(os(=`h7-;+8@wICh+Ivc&P z?|YUBY#T#2uFn14LkHdFLj=6AEj#CI)UCymBm%z8Z>u+1KAOUKJ^%bU=>(rV^tK)b z@PA>Hkoe2AB)Ep$^s1t3KeRRY(2HH4 z2Rk_9Q-h?*T`}sY^P$NeQ~&aB^G?xS*NW0eV|)9n+WCWi-HnWyJ+-+q!>ZVfkM9{0 zbgE*GyBN~Y(I;;#?RK{8-lUCy_@@FmWMs#!DG+&m3nx8`Y=qp z)?99i>$J5t?fb+#3T7Yc%({En;x6g_?xHgoS%6zVy~OG%|6@WXMk^$mGmht*%f2a% zlka`@O1AmA)oojxQt{ugw_B4vJb(PnxMZa9+>r^ULZxw!>_EO+lK+M{%`zD%!U1wn zL_i_X>ZcW+*ZNIe&G@u`-#70}nn}7%*tv-Q*)@tK%fZjZ46j|)869^Ud2~>zR}((x zp{A6OcvZ=jSccW#cE&5Yp-UH~5+j)lgcBIHV5ybR@h%~w+onLXsr1W-nY(~DloNZ} z+ngEE3V5kMK8LnQeT2fO3s?WkQKyjbCZ2;lBtZM~v^MhUK2<#o(87zlVbZAA-@&|F z8@{(9WY2^FN22Ep1eObn|565*-mo|NFC5U|F{zsKOXeKto<%V{eDqjEE5&hqhW~~t z(&tw45I-26xhw5QbEXswzqNW;@BbO=*={oM9DRL#{X~#hkk(s*k^s1AFDzDcbzrAc zvMjU?DEUtH-M=`EiEP#S-ud1#E7zi}=0J~|S-X{HxUYWofPs)CP)+h2`q9_?L<4dC zvj-^FaPFJ46;bdUu4u3b^4axlJ?4pZD{5a{e&EbZdS`FDxazmbsh6DMkqaM;5=(V> z)manA#s-I-zowXFdOx%u*Z5Bn4=glWaUsgP%RZZl7s8QoU;AW_$(d2C5}q(WpKJpa zDD9g%ip-VGah-eY_|FrfH6VcN-?7q6Yk#i>2kG394Z~Frd$FCr*SQWi<;QdP* zi7%F?we^-45i5M#y}8}9@^?3o;IZj*fv<~swX2QV6RC_yT5$3A2CHH&_P50leYkB*n*U5SNqYi{)5IDzODd5JYNK5(z4i?nAYpK$4 ztW3!&c3|1hR0FNi@#OkGF^^x6mH4S=>$vd(-t)Di_8jy#-BnQajD{05HVVc%rUPlid-xq_$3+M@c5&>quVDc^_W5nDB{ zxy&~30vs4EW4SCakC%k31*PoIe2Cbl&-)Lqg`w~B=saQB~x zT{6r5wD$Q#k0hN;Z_MEx5ydet>3cZ`@>oS+^4xQe>`|5$+Y!CfJ*VyG2OOwQ1K&^m z&52BE^f%6un0?%&8z6D%oNwM~b=wSqk>+Ru;{U2=fWZC?I&_O#a3$@>NZI2@bo>ci zQa<@Q@9CwZY<^=U}3h%?VPyf>y z8M&~cRj&Pv`)=e7&0@svrBC5yfVpd^(4yB5r)W}g$1^F}JS};u38I)Sx69oeUJA58 zyt@0fNi8?jr@wd5o5JI>S3LqpmrGzGR2TZzJA58+C<8D2qB!5~TevR4; zQ&dZwTDJcr9AVQr5B#ry_K@!yaMzi6T^ykLXYOfW|Jf=6i+5tjtXLZ*2d6^corh5S zvajn>S$PS^PvYE4^K2%~p6{{y+HSV>b{gmi&7CP+ z@XAB$VSr%)OvqP3+cD6-b|M)R*`xTMqPt*LZUe7{5MFn!PZ#ZGH{lBN`(baP@Rr*F zHy)tHjYfz9=#R@4xFP=M1YL^&x{|@`JwS%zP`;j0(N_-DgrMkA*3TBdjH~7P9G6|n zI*QISv%WtSmy}JTUIS>q$BOMW=Qjkp@I%Z6{`>z0`50j#as@yaK6->4<9|40XciL; z^KmP0rCI8Bb3)2z0w^|>)b zRq$dJ%R{yQ;KDGos%|a&Yo_}v1a6~bsv6G?L#H(oh$6k}q~0o&l%5eJpNc5V{VxGx z0b*w}9Bt5pE+*}!!Dk#L6vPhQBWE1LBFwOaS6?fb2J=k(acIJWW8dm`=TZqjb9Xe_~0RB(ksSjQ7KczQijr-|v^M#36Mn!>3Wgx38?(5mF0F zkWPI}oBmXMlr|wcC^4wT>@Q14DnhD6pqINspf_-c)_u&`KEZ?!7H=gvF()JJ?VRr6 z*9LMp=Gy?d*WLAu7&XfCHz zOxzjH_}_2siuhoQ+{s;UL$!XK9V#9FVpx_%-*qhqUZ?y^GCaehXqMNOzs~XYn$&u+ zW=?NhnHZ^}p6#nfSyrqZhaT0g&$Ama>6-X`aD1*H(QSE)n*d|X-a)tHZLsua9DOK; zO+X~J#Z^}_?E{^AjDwHk6~9f>nl`XQ8%OqB)26sM>a0t3)=*3joSVkIX+_PJlPBGk zF;hvc%cXAwr_PqK#uvVVkqV|bF42gBV zz#{go%*JZX_7$&%Pzr3n`#yKG8vV*Ig<-v$Y!f<6BoQ1qXeW2%((=eLU>WS1V!VkW?kSZ-Z$tSD!blt>jSx(&45fiK+|Lz|cNS`?DmH!j^ zvhNTnmY_uCR{w%AX^Q;o_CRbPitNgLHODyCYEwtK_3W}W|{tB9hC~3*n8f+>ly;$l!U$*dz?=a|)HZmOhaqw)+ zGarmqd(vYbi8OagC__5o+I+(t843z2Zj0P11pmz$U@-pLp_?8dQ3$Kx;y7ebLM$zm|NqFchSQ`!8?CXh-H>Vpd$-yx8%u2%#sk(0kF1!nY z#yW<_60{cGs&O0(%2U2Cgfy<*8|4PS@WR+sXAlAex0q8B&e`fEaGzRm2F^WvS-`LC z!q<5C3_UfL0I00X+?nLGrjmm`&h6T~wdkA{h8O;oA9L?iT9*@2b;ler!tIfW+HpQL z_IrYn)Be5Z^Ou}eMq)#K2esRdnr}y*O$F?>wq#S7EYW*MLk^C~X3t(R5kLhOsPkOu z+brqu`hdfw>k+IV?9{iWu^Gj=Ce9L_A@B{=V1)j6`)BhM1o!uc+a9q@<5zay@uOgi zE-fwR-`i>vm5QyN27;a*u>G7Q@=U!5w4YzA8~&t(sv+p=yL>y>oALz-ql*kV$T;R~ z23C6c*QrJWZo{xPi=uicL1)v5o%B%GXMSWNrBZ4v3v<@6lfL;4Pdi>pL}(v(zYZ_k zcm%nuQP9mOW_kkwUgOabcnl(8$|q_c37#SSq#;CW=^6ZpNL}UNw1)51l$vY~CXHj4qN{scS{Yt!#>AyRh9oS2Y z_B%uWl|62A{WAIiqxXB*m14iD9#@(tzPq{ZxJ{$g<;9s}{V(9De;hv3>(v;npM@rT zR*PE*90i5rHXqX`e^s#^={0vdR@N{r!Q<#m9?bNM9w5v#jv}Q_RQZIv#?gc{N@^G zxAJAjmEXN<2Jy`9_s9~Iz*r3$1+p?)?EnulbQ&Ie`VFFN?F zeWDb|Fa1HN9Oa!Rk&wYE6KAobMT8=s!AV)U-Df)kdBD0#K`;^Lb$5r0rmw+9O0C7T zxLBfgcl~?^a7Kj@W*u$xaa&U&n;`=P{XnQ7H5tjzxH2kq!{hYUN@X-xNP?76r9 zak+*m<##|JqGpX9S$IxhtQ$-GGJ^o(9!8tf6zya848BgS6?i7O0Nj{EM}%Ox(}&$>s<;~Y z(&4%7^(=yu7^J>XUt6 z!bjhE8q;b)FlYzr1CMGKffv#ahu;fEUep2uA2&=cdqo-c`49WBATsnIe*il6vCC|Y zFS~!vOp9I0E9FH-34?spN6*nO7+}|T^6Y3ppFk6DuowjV3`kgwAHs*IauXJ}O zK7C(}Z6PQSAGsV&9|CtiDhHiVfS7NNmM7FA(f(}(P6^mP|yq2%x1`mAJ( z=fsk3P1N}2^&1RCufN*$2OWcGH3A8(~0DR?w?ozX!m6H1$+?1HqJvziCoW zAI(83;m@L*Caad00|9_B)}=+gGMS)EAdog_ds#cHo}eEEZI<#Iw(N^G)4H&@lZPlK_9^L+neVZL*>J`(SG>j)=Vh}7%3dwLl`g=4qgD59wAuxc!OXU*S zjsW6{`BSfAcUqN-<)e{3%Qp*(5oB)%FG_$%9N6sCpr|MZy_H|ycpmidM-dz&Yccn0 zw99JP;ZWBIp&${-P-o+_30!rg5mw=<)DHpC*quzrs3;?nRAz%985@eX@<|$!Da{~z zPku8P-8`pAUQ630bvWcU;|l1F^p);CmCz%CI1i_jJ(AWE&Z z)l7?W+c&}Q+D{FDW7rbjaHUmzDI_vW688~L{jEsE!Ig$LCjN4-7(1?X@I#Wf6T6d& z;g#rbO>>c)=XjWEl%e^9p?`2KEGdT|Fb#W31_p-ndoP=H%N*7~3u@-;O^UzRXzYe( z8_mbP=D~xn_9I)+I#MRm?o?9`4+Kr3TH@1rpNkv@>!!I|QWCHyO+)fXEL zfQ~&Vz=(OVq+<#%q{!!G3$5QrOt^|9T;ZQ;x}Q1#4DmO@iFc1 zr6J>##lg?IrcxU%{OKUPm@i7k={4I27bYm)IGyDV&FH)H8PRqk-9b9e z849mQ3qd*KJ^!79VKZc$QGz0K*=)J{nJIlj$nb}4c0VfUy+yhihZnF?uL_7hAu}Zl zV8lXnSGL8|5UhfgJ!5i%+@iMFCdtg!&ZHHK&R8ng(NFb+9q+oUVCxOpfq)DKNafy` z+gp3CI>g)HljMf<)4-zKD9G;bw3qsSr$(C>v|M^&G*`o&!lS6-erWnVJ&Yl|vb}hn zwZVG)Z-M0K_9?Naa3DDnyqF*99BGhyn?JM>5D<{Yvd>1Vo4FO%i-Mtsu5i{!8I!Mr zhFSDmal1GF&E(`{5y$$HXE>%Hed0c*2}&)dJkD=;K6{+({zt9-$eZvCE$TufD=*Z< zB-yed60(^I#6^YFj81026_zdmZI-;jNHjs@wcP}|MB@I?r7(Ln4Z9|GuC`5XpSOEtAZ?_0Bx-Mx-Po5EHr zA`=0=rG+=Yfz*&L5p9sDtWu@gyLX1lAl)~Q_ov;{c4TztpE7`z*X|ZWJOLhfKugac zl)LVgJUp!YwfMezjkrRqT%mILMRW1Zjh9h+-NPqbd?*o)2Hy+nu*hT9Ucy`q5&|rA zHBo<#uZ$P==WH^Bh&Ict+VU#|gC9_H@;yJ=F_FB$QXsO}x( zQK}TRs0+O1+gXu@g0uUnx?vp(TXp9CRdZabC}ST83~L#f*P3k0=6?=+=t$Ti9@Gx) z=jNNt#OJW4(tjFIhAoMvUe=Dd@zcfc&ZhOaf}Yd(Jxa?SUUWBPHI~kwxT<};^ZRMd zR0%EGh?Kjl@*$x>#JsDXsi$!U0OHVFx78^39qCn4lF3UD*P`;LfoRk{6ilC=tc0q` z1N;Q>%eUU{4}lC7kl*xYf#+sg*L9ZZ>#wDKD5F9d0rC9bop<(ya)6-NJNuAsG5wB3?qUN%dO^|KrDrjp{I$Sv) ztAvfqb`BcIv1kk4421S8W?>H2SIp)V}bi~lzx5$&-lcuIWX-A(4s(l>pzMgFU) zDCPH~3g>*n^A>;EXym|T0>rxbznmTa)W#4o-fsf08n}VDq6wX^_S5~w zlUp)iT3K>Rf9Qeb%vuTh`1uu|r_t1Dyh#ULH= zgbzJK(L8Q$O}6360@v|f-j&jRY>di|zkSC@daatc$%gg3+I zt4ggS?sbJZ4Y~<0z0Ftzg)D9PG}DseP~W z#%+FMUoiFN0=PH&#%>X>+NRTVBf!V-2-kZ-FY5fUi_HT2vvt;b!B$38{|myi7vlo* zv8g9g8jHoitl!g3&<||6tEw4?T!JRH&ik70IMDaBxU4zpi&mLDIpLSSW0;XfCz41R zdzS`n=r8I?Hu#+G5{IF?_^h>ww{)5HdFVQWPnL&yTT8=VU5PMck9%M`ST)ge#Ahq@ zWBdGf8oIiDlr1s&aHG$XJAJSFvH-ibL?tweeIJ-i#~$}RxKwomlTA4&ds4-=yPqEW z9b--@NHKs^D2rBV(9e;HlehGt2r<^Q9-(pU6o>It0 zdyE~=f{%a|hGSf@0Q||4S8D76AMrT7y4b!r;)YX}lK>OOCI#`uL(rE+N@%o1n#hBB zF%U5pAmvvtafcOIN1s=FHrabo^6|JdT}wR6M0P`pVSN!FF?NI=5{q8*PpfMA7Ec>; zlivyWHuJmGD~uupUO{+f4hOx_ZpM)q)ryJsFXx?+BP z#5MXg0N3Edp{1F4kQYF%dq|Ytu%d=x8JAf3TIiQEIKiG@rvq7lBoYPM;fHY6^p|fT zU<2q;QteOCzgg1ASBLqx0_leUAE8VKy>w@%AB~7GdMt(s#5#)6YuTg>LVEF~GA9}! zmwYQ1c^(Nx#*V$2W5PCju!B(`n}e^Cm-1H$a^dKHsXv2kh{BboA_~Vhbb2 znaF~gij{Ks(ArX(zP6Tmxs7{@jSV`Qtj;Z5Ng*4ytJDJ)55R4quisUn{T%mQA3xip zdyXCx5JByFZcB;f5;34^Nz3tH1vMnX+AgP= zB?qcyJM56N^m9e6sZ@`eel^Vj@{OxIrMifW%lKPW#-UA<#ay<2r*+7hu}S+{qh#DT zfs^MErY^*h?}gUv!!p}KU{B8T=&7)WEaOv{T+#uDn5t3wa|~4W{k%c>Y0`P}VfQQF zJf(r7l@*$G6^}%ibT2>9BLi~5n*0Pyvd+Ncc2Ij~NAKSdndbvQa|LfWrIMQBvvW`W zxEouc&myb8SKkx#Pr==XCO=Fv5MV8e)&`O!eenPqQxsxq_~0~JwSLLRZ76NX$hsfZ zXY|m*Qf@~J5JkH{?>-fDr}Gc{gLi`XDfJy_*R1&5O%Ui}h4P!6l(eJXxhK}{v^Enq zT+(`W*zxKQS=AD;8wXWfVHvm7wNMo=2^dQ^&bCm_Q)?Y9Z8s+4YN*ZrsdpmU@O}=oEgT3Zjs;bV-vNK3g}30AEsSJ=4f$PV6%d)+FP+S1*)HiH4`%N1sGd7u8J^N6ox;)wHyLZv<~85C z4VB?l_yh%Muhz3<<}c}ndsFZ$bBZgUNdV3SD?!-xTU`nyO=Qv+%V&OYlV{BGFQ{eQ z8`v$U>}U*PigXCcrBzEJP_J`s8gY{mK93W|#=k}jR*4qe@}j%!IULbE&ee<}ZN}zq z1d*@od8rXhl99ul)_2lF7efD*EU9doK+_cB_Ds!)D~Do^$ikI$1TsCS7JU9X=6&dw zhRrW44(}ZR)@!ukXjpHTm~R7P2am6I<#?vT620-iFrsXkogo(0J`c5AM{{J8an0C_ z^c~kL&Xw3(Rf}(C_neinzf5$wzQ^XX(ys##>H=V&GW|eB{sMN37P^!m-PH!&O7NO= z%gc+~W6zwDkCuVRcelV|dw*WINFH3v1jR1pCK5#6q6~w*A5!d5M)TC5jg|?p&;05l zxkx2Rkm$8!eAvEC3UN!OdXc#|>iS&_Jndz=n^bRT(Spyll(TyL){r^-4ol~?n6-M( z%9SsndRQbb_IKHKb_&WAr5e3e5*xHYsq-X_*XE0X-P-#pIP+*ns$X{h5hIEYMY^NX z7;K-H|FK}hkMt0!6v^K)ErwG&^K2v>Z$_d{|fc5ah6|z_G8)*ZJ#Wxan9}>%ow;&Qm zd=$w&)iEEal}^gxX@?c&EIX8#5+kdsy#Yv1fS@BKkMm^Yaq=f$7 z{{G=>OflO&W`)9wYHXWFT5$`rb(jfXSS=Q(SUyQ8>5RfiY#8;!$%A`F)aK#%#M$&zSAK0 zHhITWx7*4Pn58PjXi&?IGfetv|L*Rt?cHD>hUDGVRny8bP)SnHt~HZSd;V&*G8jxP zLKNsJMW3I?{)(Ea|48-k5HM~CuG~<~lHh3UTjH!=u)6+=9B`*y44EOv$Oi7e7ZQPu zx)oh7FawYqLDQ%q?h+-}VvNevh0ChZzh+Uz1q@X05Ke(+qaWKL4{RQ}g`T3X6qz_$ z2)L|aVs2yO&n&r%)s4PPWttNqY<8{22HnO26ksC-vexc|HVU5N^yje=On8xH;ywqO zwcr;G&NTY+HTv*uKbM!ui9}`0;;&_UTM5Z@v}QpCqNPRH<2Iz-K_c8K(R!77B;BHv z-sX!=WfPj^Z`Ir$HfL8qe7nW1EdC#ck4DlnFxWOOO^ataLNO*L@%*=%tP zNVQIFyPtyj>kr)LZ+xXQTdS%bLF{y6Z?-el{hd@nI{@ML`Aet5b`Xvq!9d>aaWD1h z&3z>dSBnJecz-|I)Fgm1UUqAY`dL(FNa{7i5e?;#WY~w9tt8XKe)>a&jYEo$TVj=-aEDZhc^=3C z{Uf>oxYNl?1X#wh#@nUd2fsZE0ioqY<3*r}0@;2n`2Z^h$?%=obgo7h;UWN|7hsT{QbY@7X?eS-9lOvw^) z1_aKykKDp3AJzja98z4!pYQ6ut}`cvCS<_NL|Y6*J;`HrD^thiGHO&R1-8rkVRalp z;>kXQsa3PmL=20xPA2InklIGvRJ6=`o@